398cc0868a65ed5f041523b6700de52ec5ffb183
[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.20 2009-10-15 00:45:46 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
37
38 #define REPORT_ERROR 0
39
40 typedef struct 
41 {
42         __u8 data[PAGE_SIZE]; // Data + spare
43 } yflash_Page;
44
45 typedef struct
46 {
47         yflash_Page page[PAGES_PER_BLOCK]; // The pages in the block
48         
49 } yflash_Block;
50
51
52
53 #define MAX_HANDLES 20
54 #define BLOCKS_PER_HANDLE (32*8)
55
56 typedef struct
57 {
58         int handle[MAX_HANDLES];
59         int nBlocks;
60 } yflash_Device;
61
62 static yflash_Device filedisk;
63
64 int yaffs_testPartialWrite = 0;
65
66 extern int random_seed;
67 extern int simulate_power_failure;
68 static int initialised = 0;
69 static int remaining_ops;
70 static int nops_so_far;
71
72 int ops_multiplier;
73
74
75 static void yflash2_MaybePowerFail(unsigned int chunkInNAND, int failPoint)
76 {
77
78    nops_so_far++;
79    
80    
81    remaining_ops--;
82    if(simulate_power_failure &&
83       remaining_ops < 1){
84        printf("Simulated power failure after %d operations\n",nops_so_far);
85        printf("  Fail simulated on chunkInNAND %d, at fail point %d\n",
86                         chunkInNAND, failPoint);
87         exit(0);
88   }
89 }
90
91
92
93
94
95 static __u8 localBuffer[PAGE_SIZE];
96
97 static char *NToName(char *buf,int n)
98 {
99         sprintf(buf,"emfile-2k-%d",n);
100         return buf;
101 }
102
103 static char dummyBuffer[BLOCK_SIZE];
104
105 static int GetBlockFileHandle(int n)
106 {
107         int h;
108         int requiredSize;
109         
110         char name[40];
111         NToName(name,n);
112         int fSize;
113         int i;
114         
115         h =  open(name, O_RDWR | O_CREAT, S_IREAD | S_IWRITE);
116         if(h >= 0){
117                 fSize = lseek(h,0,SEEK_END);
118                 requiredSize = BLOCKS_PER_HANDLE * BLOCK_SIZE;
119                 if(fSize < requiredSize){
120                    for(i = 0; i < BLOCKS_PER_HANDLE; i++)
121                         if(write(h,dummyBuffer,BLOCK_SIZE) != BLOCK_SIZE)
122                                 return -1;
123                         
124                 }
125         }
126         
127         return h;
128
129 }
130
131 static int  CheckInit(void)
132 {
133         static int initialised = 0;
134         int i;
135
136         int blk;
137
138         
139         if(initialised) 
140         {
141                 return YAFFS_OK;
142         }
143
144         initialised = 1;
145         
146
147         srand(random_seed);
148         remaining_ops = (rand() % 1000) * 5;
149         memset(dummyBuffer,0xff,sizeof(dummyBuffer));
150
151         
152         
153         filedisk.nBlocks = SIZE_IN_MB * BLOCKS_PER_MB;
154
155         for(i = 0; i <  MAX_HANDLES; i++)
156                 filedisk.handle[i] = -1;
157         
158         for(i = 0,blk = 0; blk < filedisk.nBlocks; blk+=BLOCKS_PER_HANDLE,i++)
159                 filedisk.handle[i] = GetBlockFileHandle(i);
160         
161         
162         return 1;
163 }
164
165
166 int yflash2_GetNumberOfBlocks(void)
167 {
168         CheckInit();
169         
170         return filedisk.nBlocks;
171 }
172
173 int yflash2_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_ExtendedTags *tags)
174 {
175         int written;
176         int pos;
177         int h;
178         int i;
179         int nRead;
180         int error;
181         
182         T(YAFFS_TRACE_MTD,(TSTR("write chunk %d data %x tags %x" TENDSTR),chunkInNAND,(unsigned)data, (unsigned)tags));
183
184         CheckInit();
185         
186         
187         if(dev->inbandTags){
188                 
189                 yaffs_PackedTags2TagsPart * pt2tp;
190                 pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->nDataBytesPerChunk];
191                 yaffs_PackTags2TagsPart(pt2tp,tags);
192                 
193                 pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE;
194                 h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
195                                                         
196                 lseek(h,pos,SEEK_SET);
197                 written = write(h,data,dev->totalBytesPerChunk);
198
199                 
200                 if(yaffs_testPartialWrite){
201                         close(h);
202                         exit(1);
203                 }
204                 
205                 if(written != dev->totalBytesPerChunk) return YAFFS_FAIL;
206
207
208         }
209         
210         else {
211                 /* First do a write of a partial page */
212                 int n_partials;
213                 int bpos;
214
215                 if(data)
216                 {
217                         pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE;
218                         h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
219                 
220                         
221                         memcpy(localBuffer,data, dev->nDataBytesPerChunk);
222                         
223                         n_partials = rand()%20;
224                         
225                         for(i = 0; i < n_partials; i++){
226                                 bpos = rand() % dev->nDataBytesPerChunk;
227                                 
228                                 localBuffer[bpos] |= (1 << (rand() & 7));
229                         }
230                   
231                         if(REPORT_ERROR && memcmp(localBuffer,data,dev->nDataBytesPerChunk))
232                                 printf("nand simulator: data does not match\n");
233                         
234                         lseek(h,pos,SEEK_SET);
235                         written = write(h,localBuffer,dev->nDataBytesPerChunk);
236                 
237                         if(yaffs_testPartialWrite){
238                                 close(h);
239                                 exit(1);
240                         }
241
242
243                         if(written != dev->nDataBytesPerChunk) return YAFFS_FAIL;
244                 }
245                 // yflash2_MaybePowerFail(chunkInNAND,1);
246         
247                 if(tags)
248                 {
249                         pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE + PAGE_DATA_SIZE ;
250                         h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
251                 
252                         lseek(h,pos,SEEK_SET);
253
254                         if( 0 && dev->isYaffs2)
255                         {
256                         
257                                 written = write(h,tags,sizeof(yaffs_ExtendedTags));
258                                 if(written != sizeof(yaffs_ExtendedTags)) return YAFFS_FAIL;
259                         }
260                         else
261                         {
262                                 yaffs_PackedTags2 pt;
263                                 yaffs_PackTags2(dev,&pt,tags);
264                                 __u8 * ptab = (__u8 *)&pt;
265
266                                 nRead = read(h,localBuffer,sizeof(pt));
267                                 for(i = error = 0; REPORT_ERROR && i < sizeof(pt) && !error; i++){
268                                         if(localBuffer[i] != 0xFF){
269                                                 printf("nand simulation: chunk %d oob byte %d was %0x2\n",
270                                                         chunkInNAND,i,localBuffer[i]);
271                                                         error = 1;
272                                         }
273                                 }
274                 
275                                 for(i = 0; i < sizeof(pt); i++)
276                                 localBuffer[i] &= ptab[i];
277                                 
278                                 n_partials = rand()% sizeof(pt);
279                         
280                                 for(i = 0; i < n_partials; i++){
281                                         bpos = rand() % sizeof(pt);
282                                 
283                                         localBuffer[bpos] |= (1 << (rand() & 7));
284                                 }                       
285                          
286                                 if(REPORT_ERROR && memcmp(localBuffer,&pt,sizeof(pt)))
287                                         printf("nand sim: tags corruption\n");
288                                 
289                                 lseek(h,pos,SEEK_SET);
290                         
291                                 written = write(h,localBuffer,sizeof(pt));
292                                 if(written != sizeof(pt)) return YAFFS_FAIL;
293                         }
294                 }
295                 
296                 //yflash2_MaybePowerFail(chunkInNAND,2);
297                 
298                 /* Next do the whole write */
299                 if(data)
300                 {
301                         pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE;
302                         h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
303                 
304                         
305                         memset(localBuffer,0xFF, PAGE_SIZE);            
306                         for(i = 0; i < dev->nDataBytesPerChunk; i++){
307                                 localBuffer[i] &= data[i];
308                         }
309                   
310                         if(REPORT_ERROR && memcmp(localBuffer,data,dev->nDataBytesPerChunk))
311                                 printf("nand simulator: data does not match\n");
312                         
313                         lseek(h,pos,SEEK_SET);
314                         written = write(h,localBuffer,dev->nDataBytesPerChunk);
315                 
316                         if(yaffs_testPartialWrite){
317                                 close(h);
318                                 exit(1);
319                         }
320
321
322                         if(written != dev->nDataBytesPerChunk) return YAFFS_FAIL;
323                 }
324         
325                 if(tags)
326                 {
327                         pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE + PAGE_DATA_SIZE ;
328                         h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
329                 
330                         lseek(h,pos,SEEK_SET);
331
332                         if( 0 && dev->isYaffs2)
333                         {
334                         
335                                 written = write(h,tags,sizeof(yaffs_ExtendedTags));
336                                 if(written != sizeof(yaffs_ExtendedTags)) return YAFFS_FAIL;
337                         }
338                         else
339                         {
340                                 yaffs_PackedTags2 pt;
341                                 yaffs_PackTags2(dev,&pt,tags);
342                                 __u8 * ptab = (__u8 *)&pt;
343
344                                 nRead = read(h,localBuffer,sizeof(pt));
345                                 for(i = error = 0; REPORT_ERROR && i < sizeof(pt) && !error; i++){
346                                         if(localBuffer[i] != 0xFF){
347                                                 printf("nand simulation: chunk %d oob byte %d was %0x2\n",
348                                                         chunkInNAND,i,localBuffer[i]);
349                                                         error = 1;
350                                         }
351                                 }
352                 
353                                 for(i = 0; i < sizeof(pt); i++)
354                                 localBuffer[i] &= ptab[i];
355                          
356                                 if(REPORT_ERROR && memcmp(localBuffer,&pt,sizeof(pt)))
357                                         printf("nand sim: tags corruption\n");
358                                 
359                                 lseek(h,pos,SEEK_SET);
360                         
361                                 written = write(h,localBuffer,sizeof(pt));
362                                 if(written != sizeof(pt)) return YAFFS_FAIL;
363                         }
364                 }
365                 
366                 yflash2_MaybePowerFail(chunkInNAND,3);
367         
368         }
369         return YAFFS_OK;        
370
371 }
372
373 int yaffs_CheckAllFF(const __u8 *ptr, int n)
374 {
375         while(n)
376         {
377                 n--;
378                 if(*ptr!=0xFF) return 0;
379                 ptr++;
380         }
381         return 1;
382 }
383
384
385 static int fail300 = 1;
386 static int fail320 = 1;
387
388 static int failRead10 = 2;
389
390 int yflash2_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags)
391 {
392         int nread;
393         int pos;
394         int h;
395         int localData = 0;
396         int retval = YAFFS_OK;
397         int nRead;
398         
399         T(YAFFS_TRACE_MTD,(TSTR("read chunk %d data %x tags %x" TENDSTR),chunkInNAND,(unsigned)data, (unsigned)tags));
400         
401         CheckInit();
402         
403         
404         
405         
406         if(dev->inbandTags){
407                 /* Got to suck the tags out of the data area */
408                 if(!data) {
409                         localData=1;
410                         data = yaffs_GetTempBuffer(dev,__LINE__);
411                 }
412
413                 
414                 yaffs_PackedTags2TagsPart * pt2tp;
415                 pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->nDataBytesPerChunk];
416
417                 
418                 pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE;
419                 h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
420                 
421                 lseek(h,pos,SEEK_SET);
422
423                 nRead = read(h, data,dev->totalBytesPerChunk);
424
425                 yaffs_UnpackTags2TagsPart(tags,pt2tp);
426                 
427                 if(nread != dev->totalBytesPerChunk)
428                         retval = YAFFS_FAIL;
429                         
430                 if(localData)
431                         yaffs_ReleaseTempBuffer(dev,data,__LINE__);
432
433
434
435         }
436         
437         else {
438         
439                 if(data)
440                 {
441
442                         pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE;
443                         h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];             
444                         lseek(h,pos,SEEK_SET);
445                         nread = read(h,data,dev->nDataBytesPerChunk);
446                 
447                 
448                         if(nread != dev->nDataBytesPerChunk) 
449                                 retval = YAFFS_FAIL;
450                 }
451         
452                 if(tags)
453                 {
454                         pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE + PAGE_DATA_SIZE;
455                         h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];             
456                         lseek(h,pos,SEEK_SET);
457
458                         if(0 && dev->isYaffs2)
459                         {
460                                 nread= read(h,tags,sizeof(yaffs_ExtendedTags));
461                                 if(nread != sizeof(yaffs_ExtendedTags))
462                                          retval =  YAFFS_FAIL;
463                                 if(yaffs_CheckAllFF((__u8 *)tags,sizeof(yaffs_ExtendedTags)))
464                                 {
465                                         yaffs_InitialiseTags(tags);
466                                 }
467                                 else
468                                 {
469                                         tags->chunkUsed = 1;
470                                 }
471                         }
472                         else
473                         {
474                                 yaffs_PackedTags2 pt;
475                                 nread= read(h,&pt,sizeof(pt));
476                                 yaffs_UnpackTags2(dev,tags,&pt);
477 #ifdef SIMULATE_FAILURES
478                                 if((chunkInNAND >> 6) == 100) {
479                                         if(fail300 && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR){
480                                                 tags->eccResult = YAFFS_ECC_RESULT_FIXED;
481                                                 fail300 = 0;
482                                         }
483                                 }
484                                 
485                                 if((chunkInNAND >> 6) == 110) {
486                                         if(fail320 && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR){
487                                                 tags->eccResult = YAFFS_ECC_RESULT_FIXED;
488                                                 fail320 = 0;
489                                         }
490                                 }
491 #endif
492                                 if(failRead10>0 && chunkInNAND == 10){
493                                         failRead10--;
494                                         nread = 0;
495                                 }
496                         
497                                 if(nread != sizeof(pt))
498                                         retval = YAFFS_FAIL;
499                         }
500                 }
501         }
502         
503
504
505         return retval;  
506
507 }
508
509
510 int yflash2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
511 {
512         int written;
513         int h;
514         
515         yaffs_PackedTags2 pt;
516
517         CheckInit();
518         
519         memset(&pt,0,sizeof(pt));
520         h = filedisk.handle[(blockNo / ( BLOCKS_PER_HANDLE))];
521         lseek(h,((blockNo % BLOCKS_PER_HANDLE) * dev->nChunksPerBlock) * PAGE_SIZE + PAGE_DATA_SIZE,SEEK_SET);
522         written = write(h,&pt,sizeof(pt));
523                 
524         if(written != sizeof(pt)) return YAFFS_FAIL;
525         
526         
527         return YAFFS_OK;
528         
529 }
530
531 int yflash2_EraseBlockInNAND(yaffs_Device *dev, int blockNumber)
532 {
533
534         int i;
535         int h;
536                 
537         CheckInit();
538         
539         printf("erase block %d\n",blockNumber);
540         
541         if(blockNumber == 320)
542                 fail320 = 1;
543         
544         if(blockNumber < 0 || blockNumber >= filedisk.nBlocks)
545         {
546                 T(YAFFS_TRACE_ALWAYS,("Attempt to erase non-existant block %d\n",blockNumber));
547                 return YAFFS_FAIL;
548         }
549         else
550         {
551         
552                 __u8 pg[PAGE_SIZE];
553                 int syz = PAGE_SIZE;
554                 int pos;
555                 
556                 memset(pg,0xff,syz);
557                 
558
559                 h = filedisk.handle[(blockNumber / ( BLOCKS_PER_HANDLE))];
560                 lseek(h,((blockNumber % BLOCKS_PER_HANDLE) * dev->nChunksPerBlock) * PAGE_SIZE,SEEK_SET);               
561                 for(i = 0; i < dev->nChunksPerBlock; i++)
562                 {
563                         write(h,pg,PAGE_SIZE);
564                 }
565                 pos = lseek(h, 0,SEEK_CUR);
566                 
567                 return YAFFS_OK;
568         }
569         
570 }
571
572 int yflash2_InitialiseNAND(yaffs_Device *dev)
573 {
574         CheckInit();
575         
576         return YAFFS_OK;
577 }
578
579
580
581
582 int yflash2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, __u32 *sequenceNumber)
583 {
584         yaffs_ExtendedTags tags;
585         int chunkNo;
586
587         *sequenceNumber = 0;
588         
589         chunkNo = blockNo * dev->nChunksPerBlock;
590         
591         yflash2_ReadChunkWithTagsFromNAND(dev,chunkNo,NULL,&tags);
592         if(tags.blockBad)
593         {
594                 *state = YAFFS_BLOCK_STATE_DEAD;
595         }
596         else if(!tags.chunkUsed)
597         {
598                 *state = YAFFS_BLOCK_STATE_EMPTY;
599         }
600         else if(tags.chunkUsed)
601         {
602                 *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
603                 *sequenceNumber = tags.sequenceNumber;
604         }
605         return YAFFS_OK;
606 }
607