yaffs: Change NEEDS_SCANNING to NEEDS_SCAN
[yaffs2.git] / direct / basic-test / yaffs_fileem2k.c
1 /*
2  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3  *
4  * Copyright (C) 2002-2011 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.24 2010-02-18 01:18:04 charles Exp $";
20
21
22 #include "yportenv.h"
23 #include "yaffs_trace.h"
24
25 #include "yaffs_flashif2.h"
26 #include "yaffs_guts.h"
27 #include "yaffs_fileem2k.h"
28 #include "yaffs_packedtags2.h"
29 #include "yaffs_tagsvalidity.h"
30
31
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35 #include <unistd.h> 
36
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 (32*8)
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_test_partial_write = 0;
66
67 extern int random_seed;
68 extern int simulate_power_failure;
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 nand_chunk, 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("  power failed on nand_chunk %d, at fail point %d\n",
86                         nand_chunk, 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(struct yaffs_dev *dev,int nand_chunk,const u8 *data, const struct yaffs_ext_tags *tags)
174 {
175         int written;
176         int pos;
177         int h;
178         int i;
179         int nRead;
180         int error;
181         
182         yaffs_trace(YAFFS_TRACE_MTD, "write chunk %d data %p tags %p",nand_chunk, data, tags);
183
184         CheckInit();
185         
186         
187         if(dev->param.inband_tags){
188                 
189                 struct yaffs_packed_tags2_tags_only * pt2tp;
190                 pt2tp = (struct yaffs_packed_tags2_tags_only *)&data[dev->data_bytes_per_chunk];
191                 yaffs_pack_tags2_tags_only(pt2tp,tags);
192                 
193                 pos = (nand_chunk % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE;
194                 h = filedisk.handle[(nand_chunk / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
195                                                         
196                 lseek(h,pos,SEEK_SET);
197                 written = write(h,data,dev->param.total_bytes_per_chunk);
198
199                 
200                 if(yaffs_test_partial_write){
201                         close(h);
202                         exit(1);
203                 }
204                 
205                 if(written != dev->param.total_bytes_per_chunk) 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 = (nand_chunk % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE;
218                         h = filedisk.handle[(nand_chunk / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
219                 
220                         
221                         memcpy(localBuffer,data, dev->data_bytes_per_chunk);
222                         
223                         n_partials = rand()%20;
224                         
225                         for(i = 0; i < n_partials; i++){
226                                 bpos = rand() % dev->data_bytes_per_chunk;
227                                 
228                                 localBuffer[bpos] |= (1 << (rand() & 7));
229                         }
230                   
231                         if(REPORT_ERROR && memcmp(localBuffer,data,dev->data_bytes_per_chunk))
232                                 printf("nand simulator: data does not match\n");
233                         
234                         lseek(h,pos,SEEK_SET);
235                         written = write(h,localBuffer,dev->data_bytes_per_chunk);
236                 
237                         if(yaffs_test_partial_write){
238                                 close(h);
239                                 exit(1);
240                         }
241
242
243                         if(written != dev->data_bytes_per_chunk) return YAFFS_FAIL;
244                 }
245                 // yflash2_MaybePowerFail(nand_chunk,1);
246         
247                 if(tags)
248                 {
249                         pos = (nand_chunk % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE + PAGE_DATA_SIZE ;
250                         h = filedisk.handle[(nand_chunk / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
251                 
252                         lseek(h,pos,SEEK_SET);
253
254                         if( 0 && dev->param.is_yaffs2)
255                         {
256                         
257                                 written = write(h,tags,sizeof(struct yaffs_ext_tags));
258                                 if(written != sizeof(struct yaffs_ext_tags)) return YAFFS_FAIL;
259                         }
260                         else
261                         {
262                                 struct yaffs_packed_tags2 pt;
263                                 yaffs_pack_tags2(&pt,tags, !dev->param.no_tags_ecc);
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                                                         nand_chunk,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(nand_chunk,2);
297                 
298                 /* Next do the whole write */
299                 if(data)
300                 {
301                         pos = (nand_chunk % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE;
302                         h = filedisk.handle[(nand_chunk / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
303                 
304                         
305                         memset(localBuffer,0xFF, PAGE_SIZE);            
306                         for(i = 0; i < dev->data_bytes_per_chunk; i++){
307                                 localBuffer[i] &= data[i];
308                         }
309                   
310                         if(REPORT_ERROR && memcmp(localBuffer,data,dev->data_bytes_per_chunk))
311                                 printf("nand simulator: data does not match\n");
312                         
313                         lseek(h,pos,SEEK_SET);
314                         written = write(h,localBuffer,dev->data_bytes_per_chunk);
315                 
316                         if(yaffs_test_partial_write){
317                                 close(h);
318                                 exit(1);
319                         }
320
321
322                         if(written != dev->data_bytes_per_chunk) return YAFFS_FAIL;
323                 }
324         
325                 if(tags)
326                 {
327                         pos = (nand_chunk % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE + PAGE_DATA_SIZE ;
328                         h = filedisk.handle[(nand_chunk / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
329                 
330                         lseek(h,pos,SEEK_SET);
331
332                         if( 0 && dev->param.is_yaffs2)
333                         {
334                         
335                                 written = write(h,tags,sizeof(struct yaffs_ext_tags));
336                                 if(written != sizeof(struct yaffs_ext_tags)) return YAFFS_FAIL;
337                         }
338                         else
339                         {
340                                 struct yaffs_packed_tags2 pt;
341                                 yaffs_pack_tags2(&pt,tags,!dev->param.no_tags_ecc);
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                                                         nand_chunk,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(nand_chunk,3);
367         
368         }
369         return YAFFS_OK;        
370
371 }
372
373 int yaffs_check_all_ff(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(struct yaffs_dev *dev,int nand_chunk, u8 *data, struct yaffs_ext_tags *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         yaffs_trace(YAFFS_TRACE_MTD,"read chunk %d data %p tags %p",nand_chunk, data, tags);
400         
401         CheckInit();
402         
403         
404         
405         
406         if(dev->param.inband_tags){
407                 /* Got to suck the tags out of the data area */
408                 if(!data) {
409                         localData=1;
410                         data = yaffs_get_temp_buffer(dev,__LINE__);
411                 }
412
413                 
414                 struct yaffs_packed_tags2_tags_only * pt2tp;
415                 pt2tp = (struct yaffs_packed_tags2_tags_only *)&data[dev->data_bytes_per_chunk];
416
417                 
418                 pos = (nand_chunk % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE;
419                 h = filedisk.handle[(nand_chunk / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
420                 
421                 lseek(h,pos,SEEK_SET);
422
423                 nRead = read(h, data,dev->param.total_bytes_per_chunk);
424
425                 yaffs_unpack_tags2_tags_only(tags,pt2tp);
426                 
427                 if(nread != dev->param.total_bytes_per_chunk)
428                         retval = YAFFS_FAIL;
429                         
430                 if(localData)
431                         yaffs_release_temp_buffer(dev,data,__LINE__);
432
433
434
435         }
436         
437         else {
438         
439                 if(data)
440                 {
441
442                         pos = (nand_chunk % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE;
443                         h = filedisk.handle[(nand_chunk / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];              
444                         lseek(h,pos,SEEK_SET);
445                         nread = read(h,data,dev->data_bytes_per_chunk);
446                 
447                 
448                         if(nread != dev->data_bytes_per_chunk) 
449                                 retval = YAFFS_FAIL;
450                 }
451         
452                 if(tags)
453                 {
454                         pos = (nand_chunk % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE + PAGE_DATA_SIZE;
455                         h = filedisk.handle[(nand_chunk / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];              
456                         lseek(h,pos,SEEK_SET);
457
458                         if(0 && dev->param.is_yaffs2)
459                         {
460                                 nread= read(h,tags,sizeof(struct yaffs_ext_tags));
461                                 if(nread != sizeof(struct yaffs_ext_tags))
462                                          retval =  YAFFS_FAIL;
463                                 if(yaffs_check_all_ff((u8 *)tags,sizeof(struct yaffs_ext_tags)))
464                                 {
465                                         yaffs_init_tags(tags);
466                                 }
467                                 else
468                                 {
469                                         tags->chunk_used = 1;
470                                 }
471                         }
472                         else
473                         {
474                                 struct yaffs_packed_tags2 pt;
475                                 nread= read(h,&pt,sizeof(pt));
476                                 yaffs_unpack_tags2(tags,&pt, !dev->param.no_tags_ecc);
477 #ifdef SIMULATE_FAILURES
478                                 if((nand_chunk >> 6) == 100) {
479                                         if(fail300 && tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR){
480                                                 tags->ecc_result = YAFFS_ECC_RESULT_FIXED;
481                                                 fail300 = 0;
482                                         }
483                                 }
484                                 
485                                 if((nand_chunk >> 6) == 110) {
486                                         if(fail320 && tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR){
487                                                 tags->ecc_result = YAFFS_ECC_RESULT_FIXED;
488                                                 fail320 = 0;
489                                         }
490                                 }
491 #endif
492                                 if(failRead10>0 && nand_chunk == 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_dev *dev, int block_no)
511 {
512         int written;
513         int h;
514         
515         struct yaffs_packed_tags2 pt;
516
517         CheckInit();
518         
519         memset(&pt,0,sizeof(pt));
520         h = filedisk.handle[(block_no / ( BLOCKS_PER_HANDLE))];
521         lseek(h,((block_no % BLOCKS_PER_HANDLE) * dev->param.chunks_per_block) * 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(struct yaffs_dev *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                 yaffs_trace(YAFFS_TRACE_ALWAYS,"Attempt to erase non-existant block %d",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->param.chunks_per_block) * PAGE_SIZE,SEEK_SET);                
561                 for(i = 0; i < dev->param.chunks_per_block; 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(struct yaffs_dev *dev)
573 {
574         CheckInit();
575         
576         return YAFFS_OK;
577 }
578
579
580
581
582 int yflash2_QueryNANDBlock(struct yaffs_dev *dev, int block_no, enum yaffs_block_state *state, u32 *seq_number)
583 {
584         struct yaffs_ext_tags tags;
585         int chunkNo;
586
587         *seq_number = 0;
588         
589         chunkNo = block_no * dev->param.chunks_per_block;
590         
591         yflash2_ReadChunkWithTagsFromNAND(dev,chunkNo,NULL,&tags);
592         if(tags.block_bad)
593         {
594                 *state = YAFFS_BLOCK_STATE_DEAD;
595         }
596         else if(!tags.chunk_used)
597         {
598                 *state = YAFFS_BLOCK_STATE_EMPTY;
599         }
600         else if(tags.chunk_used)
601         {
602                 *state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
603                 *seq_number = tags.seq_number;
604         }
605         return YAFFS_OK;
606 }
607