More test clean ups
[yaffs2.git] / direct / yaffs_fileem2k.c
1 /*
2  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3  *
4  * Copyright (C) 2002-2007 Aleph One Ltd.
5  *   for Toby Churchill Ltd and Brightstar Engineering
6  *
7  * Created by Charles Manning <charles@aleph1.co.uk>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License version 2 as
11  * published by the Free Software Foundation.
12  */
13
14 /*
15  * This provides a YAFFS nand emulation on a file for emulating 2kB pages.
16  * This is only intended as test code to test persistence etc.
17  */
18
19 const char *yaffs_flashif2_c_version = "$Id: yaffs_fileem2k.c,v 1.16 2009-01-12 00:49:01 charles Exp $";
20
21
22 #include "yportenv.h"
23
24 #include "yaffs_flashif2.h"
25 #include "yaffs_guts.h"
26 #include "devextras.h"
27
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 #include <unistd.h> 
32
33 #include "yaffs_fileem2k.h"
34 #include "yaffs_packedtags2.h"
35
36 //#define SIMULATE_FAILURES
37
38
39 #define REPORT_ERROR 0
40
41 typedef struct 
42 {
43         __u8 data[PAGE_SIZE]; // Data + spare
44 } yflash_Page;
45
46 typedef struct
47 {
48         yflash_Page page[PAGES_PER_BLOCK]; // The pages in the block
49         
50 } yflash_Block;
51
52
53
54 #define MAX_HANDLES 20
55 #define BLOCKS_PER_HANDLE 8000
56
57 typedef struct
58 {
59         int handle[MAX_HANDLES];
60         int nBlocks;
61 } yflash_Device;
62
63 static yflash_Device filedisk;
64
65 int yaffs_testPartialWrite = 0;
66
67
68
69
70 static __u8 localBuffer[PAGE_SIZE];
71
72 static char *NToName(char *buf,int n)
73 {
74         sprintf(buf,"emfile-2k-%d",n);
75         return buf;
76 }
77
78 static char dummyBuffer[BLOCK_SIZE];
79
80 static int GetBlockFileHandle(int n)
81 {
82         int h;
83         int requiredSize;
84         
85         char name[40];
86         NToName(name,n);
87         int fSize;
88         int i;
89         
90         h =  open(name, O_RDWR | O_CREAT, S_IREAD | S_IWRITE);
91         if(h >= 0){
92                 fSize = lseek(h,0,SEEK_END);
93                 requiredSize = BLOCKS_PER_HANDLE * BLOCK_SIZE;
94                 if(fSize < requiredSize){
95                    for(i = 0; i < BLOCKS_PER_HANDLE; i++)
96                         if(write(h,dummyBuffer,BLOCK_SIZE) != BLOCK_SIZE)
97                                 return -1;
98                         
99                 }
100         }
101         
102         return h;
103
104 }
105
106 static int  CheckInit(void)
107 {
108         static int initialised = 0;
109         int i;
110
111         int blk;
112
113         
114         if(initialised) 
115         {
116                 return YAFFS_OK;
117         }
118
119         initialised = 1;
120         
121         memset(dummyBuffer,0xff,sizeof(dummyBuffer));
122         
123         
124         filedisk.nBlocks = SIZE_IN_MB * BLOCKS_PER_MB;
125
126         for(i = 0; i <  MAX_HANDLES; i++)
127                 filedisk.handle[i] = -1;
128         
129         for(i = 0,blk = 0; blk < filedisk.nBlocks; blk+=BLOCKS_PER_HANDLE,i++)
130                 filedisk.handle[i] = GetBlockFileHandle(i);
131         
132         
133         return 1;
134 }
135
136
137 int yflash2_GetNumberOfBlocks(void)
138 {
139         CheckInit();
140         
141         return filedisk.nBlocks;
142 }
143
144 int yflash2_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_ExtendedTags *tags)
145 {
146         int written;
147         int pos;
148         int h;
149         int i;
150         int nRead;
151         int error;
152         
153         T(YAFFS_TRACE_MTD,(TSTR("write chunk %d data %x tags %x" TENDSTR),chunkInNAND,(unsigned)data, (unsigned)tags));
154
155         CheckInit();
156         
157         
158         if(dev->inbandTags){
159                 
160                 yaffs_PackedTags2TagsPart * pt2tp;
161                 pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->nDataBytesPerChunk];
162                 yaffs_PackTags2TagsPart(pt2tp,tags);
163                 
164                 pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE;
165                 h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
166                                                         
167                 lseek(h,pos,SEEK_SET);
168                 written = write(h,data,dev->totalBytesPerChunk);
169
170                 
171                 if(yaffs_testPartialWrite){
172                         close(h);
173                         exit(1);
174                 }
175                 
176                 if(written != dev->totalBytesPerChunk) return YAFFS_FAIL;
177
178
179         }
180         
181         else {
182         
183                 if(data)
184                 {
185                         pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE;
186                         h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
187                 
188                         lseek(h,pos,SEEK_SET);
189                         nRead =  read(h, localBuffer,dev->nDataBytesPerChunk);
190                         for(i = error = 0; i < dev->nDataBytesPerChunk && !error; i++){
191                                 if(REPORT_ERROR && localBuffer[i] != 0xFF){
192                                         printf("nand simulation: chunk %d data byte %d was %0x2\n",
193                                                 chunkInNAND,i,localBuffer[i]);
194                                         error = 1;
195                                 }
196                         }
197                 
198                         for(i = 0; i < dev->nDataBytesPerChunk; i++)
199                         localBuffer[i] &= data[i];
200                   
201                         if(REPORT_ERROR && memcmp(localBuffer,data,dev->nDataBytesPerChunk))
202                                 printf("nand simulator: data does not match\n");
203                         
204                         lseek(h,pos,SEEK_SET);
205                         written = write(h,localBuffer,dev->nDataBytesPerChunk);
206                 
207                         if(yaffs_testPartialWrite){
208                                 close(h);
209                                 exit(1);
210                         }
211                 
212 #ifdef SIMULATE_FAILURES
213                                 if((chunkInNAND >> 6) == 100) 
214                                 written = 0;
215
216                                 if((chunkInNAND >> 6) == 110) 
217                                 written = 0;
218 #endif
219
220
221                         if(written != dev->nDataBytesPerChunk) return YAFFS_FAIL;
222                 }
223         
224                 if(tags)
225                 {
226                         pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE + PAGE_DATA_SIZE ;
227                         h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
228                 
229                         lseek(h,pos,SEEK_SET);
230
231                         if( 0 && dev->isYaffs2)
232                         {
233                         
234                                 written = write(h,tags,sizeof(yaffs_ExtendedTags));
235                                 if(written != sizeof(yaffs_ExtendedTags)) return YAFFS_FAIL;
236                         }
237                         else
238                         {
239                                 yaffs_PackedTags2 pt;
240                                 yaffs_PackTags2(&pt,tags);
241                                 __u8 * ptab = (__u8 *)&pt;
242
243                                 nRead = read(h,localBuffer,sizeof(pt));
244                                 for(i = error = 0; REPORT_ERROR && i < sizeof(pt) && !error; i++){
245                                         if(localBuffer[i] != 0xFF){
246                                                 printf("nand simulation: chunk %d oob byte %d was %0x2\n",
247                                                         chunkInNAND,i,localBuffer[i]);
248                                                         error = 1;
249                                         }
250                                 }
251                 
252                                 for(i = 0; i < sizeof(pt); i++)
253                                 localBuffer[i] &= ptab[i];
254                          
255                                 if(REPORT_ERROR && memcmp(localBuffer,&pt,sizeof(pt)))
256                                         printf("nand sim: tags corruption\n");
257                                 
258                                 lseek(h,pos,SEEK_SET);
259                         
260                                 written = write(h,localBuffer,sizeof(pt));
261                                 if(written != sizeof(pt)) return YAFFS_FAIL;
262                         }
263                 }
264         
265         }
266         return YAFFS_OK;        
267
268 }
269
270 int yaffs_CheckAllFF(const __u8 *ptr, int n)
271 {
272         while(n)
273         {
274                 n--;
275                 if(*ptr!=0xFF) return 0;
276                 ptr++;
277         }
278         return 1;
279 }
280
281
282 static int fail300 = 1;
283 static int fail320 = 1;
284
285 static int failRead10 = 2;
286
287 int yflash2_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags)
288 {
289         int nread;
290         int pos;
291         int h;
292         int localData = 0;
293         int retval = YAFFS_OK;
294         int nRead;
295         
296         T(YAFFS_TRACE_MTD,(TSTR("read chunk %d data %x tags %x" TENDSTR),chunkInNAND,(unsigned)data, (unsigned)tags));
297         
298         CheckInit();
299         
300         
301         
302         
303         if(dev->inbandTags){
304                 /* Got to suck the tags out of the data area */
305                 if(!data) {
306                         localData=1;
307                         data = yaffs_GetTempBuffer(dev,__LINE__);
308                 }
309
310                 
311                 yaffs_PackedTags2TagsPart * pt2tp;
312                 pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->nDataBytesPerChunk];
313
314                 
315                 pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE;
316                 h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
317                 
318                 lseek(h,pos,SEEK_SET);
319
320                 nRead = read(h, data,dev->totalBytesPerChunk);
321
322                 yaffs_UnpackTags2TagsPart(tags,pt2tp);
323                 
324                 if(nread != dev->totalBytesPerChunk)
325                         retval = YAFFS_FAIL;
326                         
327                 if(localData)
328                         yaffs_ReleaseTempBuffer(dev,data,__LINE__);
329
330
331
332         }
333         
334         else {
335         
336                 if(data)
337                 {
338
339                         pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE;
340                         h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];             
341                         lseek(h,pos,SEEK_SET);
342                         nread = read(h,data,dev->nDataBytesPerChunk);
343                 
344                 
345                         if(nread != dev->nDataBytesPerChunk) 
346                                 retval = YAFFS_FAIL;
347                 }
348         
349                 if(tags)
350                 {
351                         pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE + PAGE_DATA_SIZE;
352                         h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];             
353                         lseek(h,pos,SEEK_SET);
354
355                         if(0 && dev->isYaffs2)
356                         {
357                                 nread= read(h,tags,sizeof(yaffs_ExtendedTags));
358                                 if(nread != sizeof(yaffs_ExtendedTags))
359                                          retval =  YAFFS_FAIL;
360                                 if(yaffs_CheckAllFF((__u8 *)tags,sizeof(yaffs_ExtendedTags)))
361                                 {
362                                         yaffs_InitialiseTags(tags);
363                                 }
364                                 else
365                                 {
366                                         tags->chunkUsed = 1;
367                                 }
368                         }
369                         else
370                         {
371                                 yaffs_PackedTags2 pt;
372                                 nread= read(h,&pt,sizeof(pt));
373                                 yaffs_UnpackTags2(tags,&pt);
374 #ifdef SIMULATE_FAILURES
375                                 if((chunkInNAND >> 6) == 100) {
376                                         if(fail300 && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR){
377                                                 tags->eccResult = YAFFS_ECC_RESULT_FIXED;
378                                                 fail300 = 0;
379                                         }
380                                 }
381                                 
382                                 if((chunkInNAND >> 6) == 110) {
383                                         if(fail320 && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR){
384                                                 tags->eccResult = YAFFS_ECC_RESULT_FIXED;
385                                                 fail320 = 0;
386                                         }
387                                 }
388 #endif
389                                 if(failRead10>0 && chunkInNAND == 10){
390                                         failRead10--;
391                                         nread = 0;
392                                 }
393                         
394                                 if(nread != sizeof(pt))
395                                         retval = YAFFS_FAIL;
396                         }
397                 }
398         }
399         
400
401
402         return retval;  
403
404 }
405
406
407 int yflash2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
408 {
409         int written;
410         int h;
411         
412         yaffs_PackedTags2 pt;
413
414         CheckInit();
415         
416         memset(&pt,0,sizeof(pt));
417         h = filedisk.handle[(blockNo / ( BLOCKS_PER_HANDLE))];
418         lseek(h,((blockNo % BLOCKS_PER_HANDLE) * dev->nChunksPerBlock) * PAGE_SIZE + PAGE_DATA_SIZE,SEEK_SET);
419         written = write(h,&pt,sizeof(pt));
420                 
421         if(written != sizeof(pt)) return YAFFS_FAIL;
422         
423         
424         return YAFFS_OK;
425         
426 }
427
428 int yflash2_EraseBlockInNAND(yaffs_Device *dev, int blockNumber)
429 {
430
431         int i;
432         int h;
433                 
434         CheckInit();
435         
436         printf("erase block %d\n",blockNumber);
437         
438         if(blockNumber == 320)
439                 fail320 = 1;
440         
441         if(blockNumber < 0 || blockNumber >= filedisk.nBlocks)
442         {
443                 T(YAFFS_TRACE_ALWAYS,("Attempt to erase non-existant block %d\n",blockNumber));
444                 return YAFFS_FAIL;
445         }
446         else
447         {
448         
449                 __u8 pg[PAGE_SIZE];
450                 int syz = PAGE_SIZE;
451                 int pos;
452                 
453                 memset(pg,0xff,syz);
454                 
455
456                 h = filedisk.handle[(blockNumber / ( BLOCKS_PER_HANDLE))];
457                 lseek(h,((blockNumber % BLOCKS_PER_HANDLE) * dev->nChunksPerBlock) * PAGE_SIZE,SEEK_SET);               
458                 for(i = 0; i < dev->nChunksPerBlock; i++)
459                 {
460                         write(h,pg,PAGE_SIZE);
461                 }
462                 pos = lseek(h, 0,SEEK_CUR);
463                 
464                 return YAFFS_OK;
465         }
466         
467 }
468
469 int yflash2_InitialiseNAND(yaffs_Device *dev)
470 {
471         CheckInit();
472         
473         return YAFFS_OK;
474 }
475
476
477
478
479 int yflash2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, __u32 *sequenceNumber)
480 {
481         yaffs_ExtendedTags tags;
482         int chunkNo;
483
484         *sequenceNumber = 0;
485         
486         chunkNo = blockNo * dev->nChunksPerBlock;
487         
488         yflash2_ReadChunkWithTagsFromNAND(dev,chunkNo,NULL,&tags);
489         if(tags.blockBad)
490         {
491                 *state = YAFFS_BLOCK_STATE_DEAD;
492         }
493         else if(!tags.chunkUsed)
494         {
495                 *state = YAFFS_BLOCK_STATE_EMPTY;
496         }
497         else if(tags.chunkUsed)
498         {
499                 *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
500                 *sequenceNumber = tags.sequenceNumber;
501         }
502         return YAFFS_OK;
503 }
504