Add more test harness stuff
[yaffs2.git] / direct / yaffs_fileem2k.c
1 /*
2  * YAFFS: Yet another FFS. A NAND-flash specific file system. 
3  * yaffs_ramdisk.c: yaffs ram disk component
4  *
5  * Copyright (C) 2002 Aleph One Ltd.
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 const char *yaffs_flashif_c_version = "$Id: yaffs_fileem2k.c,v 1.10 2006-11-13 07:16:37 charles Exp $";
19
20
21 #include "yportenv.h"
22
23 #include "yaffs_flashif.h"
24 #include "yaffs_guts.h"
25 #include "devextras.h"
26
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <unistd.h> 
31
32 #include "yaffs_fileem2k.h"
33 #include "yaffs_packedtags2.h"
34
35 //#define SIMULATE_FAILURES
36
37 typedef struct 
38 {
39         __u8 data[PAGE_SIZE]; // Data + spare
40 } yflash_Page;
41
42 typedef struct
43 {
44         yflash_Page page[PAGES_PER_BLOCK]; // The pages in the block
45         
46 } yflash_Block;
47
48
49
50 #define MAX_HANDLES 20
51 #define BLOCKS_PER_HANDLE 8000
52
53 typedef struct
54 {
55         int handle[MAX_HANDLES];
56         int nBlocks;
57 } yflash_Device;
58
59 static yflash_Device filedisk;
60
61 int yaffs_testPartialWrite = 0;
62
63
64
65
66 static __u8 localBuffer[PAGE_SIZE];
67
68 static char *NToName(char *buf,int n)
69 {
70         sprintf(buf,"emfile%d",n);
71         return buf;
72 }
73
74 static char dummyBuffer[BLOCK_SIZE];
75
76 static int GetBlockFileHandle(int n)
77 {
78         int h;
79         int requiredSize;
80         
81         char name[40];
82         NToName(name,n);
83         int fSize;
84         int i;
85         
86         h =  open(name, O_RDWR | O_CREAT, S_IREAD | S_IWRITE);
87         if(h >= 0){
88                 fSize = lseek(h,0,SEEK_END);
89                 requiredSize = BLOCKS_PER_HANDLE * BLOCK_SIZE;
90                 if(fSize < requiredSize){
91                    for(i = 0; i < BLOCKS_PER_HANDLE; i++)
92                         if(write(h,dummyBuffer,BLOCK_SIZE) != BLOCK_SIZE)
93                                 return -1;
94                         
95                 }
96         }
97         
98         return h;
99
100 }
101
102 static int  CheckInit(void)
103 {
104         static int initialised = 0;
105         int h;
106         int i;
107
108         
109         off_t fSize;
110         off_t requiredSize;
111         int written;
112         int blk;
113         
114         yflash_Page p;
115         
116         if(initialised) 
117         {
118                 return YAFFS_OK;
119         }
120
121         initialised = 1;
122         
123         memset(dummyBuffer,0xff,sizeof(dummyBuffer));
124         
125         
126         filedisk.nBlocks = SIZE_IN_MB * BLOCKS_PER_MB;
127
128         for(i = 0; i <  MAX_HANDLES; i++)
129                 filedisk.handle[i] = -1;
130         
131         for(i = 0,blk = 0; blk < filedisk.nBlocks; blk+=BLOCKS_PER_HANDLE,i++)
132                 filedisk.handle[i] = GetBlockFileHandle(i);
133         
134         
135         return 1;
136 }
137
138
139 int yflash_GetNumberOfBlocks(void)
140 {
141         CheckInit();
142         
143         return filedisk.nBlocks;
144 }
145
146 int yflash_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, yaffs_ExtendedTags *tags)
147 {
148         int written;
149         int pos;
150         int h;
151         int i;
152         int nRead;
153         int error;
154         
155         T(YAFFS_TRACE_MTD,(TSTR("write chunk %d data %x tags %x" TENDSTR),chunkInNAND,(unsigned)data, (unsigned)tags));
156
157         CheckInit();
158         
159         
160         
161         if(data)
162         {
163                 pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE;
164                 h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
165                 
166                 lseek(h,pos,SEEK_SET);
167                 nRead =  read(h, localBuffer,dev->nDataBytesPerChunk);
168                 for(i = error = 0; i < dev->nDataBytesPerChunk && !error; i++){
169                         if(localBuffer[i] != 0xFF){
170                                 printf("nand simulation: chunk %d data byte %d was %0x2\n",
171                                         chunkInNAND,i,localBuffer[i]);
172                                 error = 1;
173                         }
174                 }
175                 
176                 for(i = 0; i < dev->nDataBytesPerChunk; i++)
177                   localBuffer[i] &= data[i];
178                   
179                 if(memcmp(localBuffer,data,dev->nDataBytesPerChunk))
180                         printf("nand simulator: data does not match\n");
181                         
182                 lseek(h,pos,SEEK_SET);
183                 written = write(h,localBuffer,dev->nDataBytesPerChunk);
184                 
185                 if(yaffs_testPartialWrite){
186                         close(h);
187                         exit(1);
188                 }
189                 
190 #ifdef SIMULATE_FAILURES
191                         if((chunkInNAND >> 6) == 100) 
192                           written = 0;
193
194                         if((chunkInNAND >> 6) == 110) 
195                           written = 0;
196 #endif
197
198
199                 if(written != dev->nDataBytesPerChunk) return YAFFS_FAIL;
200         }
201         
202         if(tags)
203         {
204                 pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE + PAGE_DATA_SIZE ;
205                 h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
206                 
207                 lseek(h,pos,SEEK_SET);
208
209                 if( 0 && dev->isYaffs2)
210                 {
211                         
212                         written = write(h,tags,sizeof(yaffs_ExtendedTags));
213                         if(written != sizeof(yaffs_ExtendedTags)) return YAFFS_FAIL;
214                 }
215                 else
216                 {
217                         yaffs_PackedTags2 pt;
218                         yaffs_PackTags2(&pt,tags);
219                         __u8 * ptab = (__u8 *)&pt;
220
221                         nRead = read(h,localBuffer,sizeof(pt));
222                         for(i = error = 0; i < sizeof(pt) && !error; i++){
223                                 if(localBuffer[i] != 0xFF){
224                                         printf("nand simulation: chunk %d oob byte %d was %0x2\n",
225                                                 chunkInNAND,i,localBuffer[i]);
226                                                 error = 1;
227                                 }
228                         }
229                 
230                         for(i = 0; i < sizeof(pt); i++)
231                           localBuffer[i] &= ptab[i];
232                          
233                         if(memcmp(localBuffer,&pt,sizeof(pt)))
234                                 printf("nand sim: tags corruption\n");
235                                 
236                         lseek(h,pos,SEEK_SET);
237                         
238                         written = write(h,localBuffer,sizeof(pt));
239                         if(written != sizeof(pt)) return YAFFS_FAIL;
240                 }
241         }
242         
243
244         return YAFFS_OK;        
245
246 }
247
248 int yaffs_CheckAllFF(const __u8 *ptr, int n)
249 {
250         while(n)
251         {
252                 n--;
253                 if(*ptr!=0xFF) return 0;
254                 ptr++;
255         }
256         return 1;
257 }
258
259
260 static int fail300 = 1;
261 static int fail320 = 1;
262
263 static int failRead10 = 2;
264
265 int yflash_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags)
266 {
267         int nread;
268         int pos;
269         int h;
270         
271         T(YAFFS_TRACE_MTD,(TSTR("read chunk %d data %x tags %x" TENDSTR),chunkInNAND,(unsigned)data, (unsigned)tags));
272         
273         CheckInit();
274         
275         
276         
277         if(data)
278         {
279
280                 pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE;
281                 h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];             
282                 lseek(h,pos,SEEK_SET);
283                 nread = read(h,data,dev->nDataBytesPerChunk);
284                 
285                 
286                 if(nread != dev->nDataBytesPerChunk) return YAFFS_FAIL;
287         }
288         
289         if(tags)
290         {
291                 pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE + PAGE_DATA_SIZE;
292                 h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];             
293                 lseek(h,pos,SEEK_SET);
294
295                 if(0 && dev->isYaffs2)
296                 {
297                         nread= read(h,tags,sizeof(yaffs_ExtendedTags));
298                         if(nread != sizeof(yaffs_ExtendedTags)) return YAFFS_FAIL;
299                         if(yaffs_CheckAllFF((__u8 *)tags,sizeof(yaffs_ExtendedTags)))
300                         {
301                                 yaffs_InitialiseTags(tags);
302                         }
303                         else
304                         {
305                                 tags->chunkUsed = 1;
306                         }
307                 }
308                 else
309                 {
310                         yaffs_PackedTags2 pt;
311                         nread= read(h,&pt,sizeof(pt));
312                         yaffs_UnpackTags2(tags,&pt);
313 #ifdef SIMULATE_FAILURES
314                         if((chunkInNAND >> 6) == 100) {
315                             if(fail300 && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR){
316                                tags->eccResult = YAFFS_ECC_RESULT_FIXED;
317                                fail300 = 0;
318                             }
319                             
320                         }
321                         if((chunkInNAND >> 6) == 110) {
322                             if(fail320 && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR){
323                                tags->eccResult = YAFFS_ECC_RESULT_FIXED;
324                                fail320 = 0;
325                             }
326                         }
327 #endif
328                         if(failRead10>0 && chunkInNAND == 10){
329                                 failRead10--;
330                                 nread = 0;
331                         }
332                         
333                         if(nread != sizeof(pt)) return YAFFS_FAIL;
334                 }
335         }
336         
337
338         return YAFFS_OK;        
339
340 }
341
342
343 int yflash_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
344 {
345         int written;
346         int h;
347         
348         yaffs_PackedTags2 pt;
349
350         CheckInit();
351         
352         memset(&pt,0,sizeof(pt));
353         h = filedisk.handle[(blockNo / ( BLOCKS_PER_HANDLE))];
354         lseek(h,((blockNo % BLOCKS_PER_HANDLE) * dev->nChunksPerBlock) * PAGE_SIZE + PAGE_DATA_SIZE,SEEK_SET);
355         written = write(h,&pt,sizeof(pt));
356                 
357         if(written != sizeof(pt)) return YAFFS_FAIL;
358         
359         
360         return YAFFS_OK;
361         
362 }
363
364 int yflash_EraseBlockInNAND(yaffs_Device *dev, int blockNumber)
365 {
366
367         int i;
368         int h;
369                 
370         CheckInit();
371         
372         printf("erase block %d\n",blockNumber);
373         
374         if(blockNumber == 320)
375                 fail320 = 1;
376         
377         if(blockNumber < 0 || blockNumber >= filedisk.nBlocks)
378         {
379                 T(YAFFS_TRACE_ALWAYS,("Attempt to erase non-existant block %d\n",blockNumber));
380                 return YAFFS_FAIL;
381         }
382         else
383         {
384         
385                 __u8 pg[PAGE_SIZE];
386                 int syz = PAGE_SIZE;
387                 int pos;
388                 
389                 memset(pg,0xff,syz);
390                 
391
392                 h = filedisk.handle[(blockNumber / ( BLOCKS_PER_HANDLE))];
393                 lseek(h,((blockNumber % BLOCKS_PER_HANDLE) * dev->nChunksPerBlock) * PAGE_SIZE,SEEK_SET);               
394                 for(i = 0; i < dev->nChunksPerBlock; i++)
395                 {
396                         write(h,pg,PAGE_SIZE);
397                 }
398                 pos = lseek(h, 0,SEEK_CUR);
399                 
400                 return YAFFS_OK;
401         }
402         
403 }
404
405 int yflash_InitialiseNAND(yaffs_Device *dev)
406 {
407         CheckInit();
408         
409         return YAFFS_OK;
410 }
411
412
413
414
415 int yflash_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber)
416 {
417         yaffs_ExtendedTags tags;
418         int chunkNo;
419
420         *sequenceNumber = 0;
421         
422         chunkNo = blockNo * dev->nChunksPerBlock;
423         
424         yflash_ReadChunkWithTagsFromNAND(dev,chunkNo,NULL,&tags);
425         if(tags.blockBad)
426         {
427                 *state = YAFFS_BLOCK_STATE_DEAD;
428         }
429         else if(!tags.chunkUsed)
430         {
431                 *state = YAFFS_BLOCK_STATE_EMPTY;
432         }
433         else if(tags.chunkUsed)
434         {
435                 *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
436                 *sequenceNumber = tags.sequenceNumber;
437         }
438         return YAFFS_OK;
439 }
440