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