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