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