2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
4 * Copyright (C) 2002-2007 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
7 * Created by Charles Manning <charles@aleph1.co.uk>
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.
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.
22 const char *yaffs_flashif_c_version = "$Id: yaffs_fileem2k.c,v 1.12 2007/02/14 01:09:06 wookey Exp $";
27 #include "yaffs_flashif.h"
28 #include "yaffs_guts.h"
29 #include "devextras.h"
31 #include <sys/types.h>
36 #include "yaffs_fileem2k.h"
37 #include "yaffs_packedtags2.h"
39 //#define SIMULATE_FAILURES
43 __u8 data[PAGE_SIZE]; // Data + spare
48 yflash_Page page[PAGES_PER_BLOCK]; // The pages in the block
54 #define MAX_HANDLES 20
55 #define BLOCKS_PER_HANDLE 8000
59 int handle[MAX_HANDLES];
63 static yflash_Device filedisk;
65 int yaffs_testPartialWrite = 0;
70 static __u8 localBuffer[PAGE_SIZE];
72 static char *NToName(char *buf,int n)
74 sprintf(buf,"emfile%d",n);
78 static char dummyBuffer[BLOCK_SIZE];
80 static int GetBlockFileHandle(int n)
90 h = open(name, O_RDWR | O_CREAT, S_IREAD | S_IWRITE);
92 fSize = lseek(h,0,SEEK_END);
93 requiredSize = BLOCKS_PER_HANDLE * BLOCK_SIZE;
94 if(fSize < requiredSize){
95 for(i = 0; i < BLOCKS_PER_HANDLE; i++)
96 if(write(h,dummyBuffer,BLOCK_SIZE) != BLOCK_SIZE)
106 static int CheckInit(void)
108 static int initialised = 0;
127 memset(dummyBuffer,0xff,sizeof(dummyBuffer));
130 filedisk.nBlocks = SIZE_IN_MB * BLOCKS_PER_MB;
132 for(i = 0; i < MAX_HANDLES; i++)
133 filedisk.handle[i] = -1;
135 for(i = 0,blk = 0; blk < filedisk.nBlocks; blk+=BLOCKS_PER_HANDLE,i++)
136 filedisk.handle[i] = GetBlockFileHandle(i);
143 int yflash_GetNumberOfBlocks(void)
147 return filedisk.nBlocks;
150 int yflash_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, yaffs_ExtendedTags *tags)
159 T(YAFFS_TRACE_MTD,(TSTR("write chunk %d data %x tags %x" TENDSTR),chunkInNAND,(unsigned)data, (unsigned)tags));
167 pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE;
168 h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
170 lseek(h,pos,SEEK_SET);
171 nRead = read(h, localBuffer,dev->nDataBytesPerChunk);
172 for(i = error = 0; i < dev->nDataBytesPerChunk && !error; i++){
173 if(localBuffer[i] != 0xFF){
174 printf("nand simulation: chunk %d data byte %d was %0x2\n",
175 chunkInNAND,i,localBuffer[i]);
180 for(i = 0; i < dev->nDataBytesPerChunk; i++)
181 localBuffer[i] &= data[i];
183 if(memcmp(localBuffer,data,dev->nDataBytesPerChunk))
184 printf("nand simulator: data does not match\n");
186 lseek(h,pos,SEEK_SET);
187 written = write(h,localBuffer,dev->nDataBytesPerChunk);
189 if(yaffs_testPartialWrite){
194 #ifdef SIMULATE_FAILURES
195 if((chunkInNAND >> 6) == 100)
198 if((chunkInNAND >> 6) == 110)
203 if(written != dev->nDataBytesPerChunk) return YAFFS_FAIL;
208 pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE + PAGE_DATA_SIZE ;
209 h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
211 lseek(h,pos,SEEK_SET);
213 if( 0 && dev->isYaffs2)
216 written = write(h,tags,sizeof(yaffs_ExtendedTags));
217 if(written != sizeof(yaffs_ExtendedTags)) return YAFFS_FAIL;
221 yaffs_PackedTags2 pt;
222 yaffs_PackTags2(&pt,tags);
223 __u8 * ptab = (__u8 *)&pt;
225 nRead = read(h,localBuffer,sizeof(pt));
226 for(i = error = 0; i < sizeof(pt) && !error; i++){
227 if(localBuffer[i] != 0xFF){
228 printf("nand simulation: chunk %d oob byte %d was %0x2\n",
229 chunkInNAND,i,localBuffer[i]);
234 for(i = 0; i < sizeof(pt); i++)
235 localBuffer[i] &= ptab[i];
237 if(memcmp(localBuffer,&pt,sizeof(pt)))
238 printf("nand sim: tags corruption\n");
240 lseek(h,pos,SEEK_SET);
242 written = write(h,localBuffer,sizeof(pt));
243 if(written != sizeof(pt)) return YAFFS_FAIL;
252 int yaffs_CheckAllFF(const __u8 *ptr, int n)
257 if(*ptr!=0xFF) return 0;
264 static int fail300 = 1;
265 static int fail320 = 1;
267 static int failRead10 = 2;
269 int yflash_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags)
275 T(YAFFS_TRACE_MTD,(TSTR("read chunk %d data %x tags %x" TENDSTR),chunkInNAND,(unsigned)data, (unsigned)tags));
284 pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE;
285 h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
286 lseek(h,pos,SEEK_SET);
287 nread = read(h,data,dev->nDataBytesPerChunk);
290 if(nread != dev->nDataBytesPerChunk) return YAFFS_FAIL;
295 pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE + PAGE_DATA_SIZE;
296 h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
297 lseek(h,pos,SEEK_SET);
299 if(0 && dev->isYaffs2)
301 nread= read(h,tags,sizeof(yaffs_ExtendedTags));
302 if(nread != sizeof(yaffs_ExtendedTags)) return YAFFS_FAIL;
303 if(yaffs_CheckAllFF((__u8 *)tags,sizeof(yaffs_ExtendedTags)))
305 yaffs_InitialiseTags(tags);
314 yaffs_PackedTags2 pt;
315 nread= read(h,&pt,sizeof(pt));
316 yaffs_UnpackTags2(tags,&pt);
317 #ifdef SIMULATE_FAILURES
318 if((chunkInNAND >> 6) == 100) {
319 if(fail300 && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR){
320 tags->eccResult = YAFFS_ECC_RESULT_FIXED;
325 if((chunkInNAND >> 6) == 110) {
326 if(fail320 && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR){
327 tags->eccResult = YAFFS_ECC_RESULT_FIXED;
332 if(failRead10>0 && chunkInNAND == 10){
337 if(nread != sizeof(pt)) return YAFFS_FAIL;
347 int yflash_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
352 yaffs_PackedTags2 pt;
356 memset(&pt,0,sizeof(pt));
357 h = filedisk.handle[(blockNo / ( BLOCKS_PER_HANDLE))];
358 lseek(h,((blockNo % BLOCKS_PER_HANDLE) * dev->nChunksPerBlock) * PAGE_SIZE + PAGE_DATA_SIZE,SEEK_SET);
359 written = write(h,&pt,sizeof(pt));
361 if(written != sizeof(pt)) return YAFFS_FAIL;
368 int yflash_EraseBlockInNAND(yaffs_Device *dev, int blockNumber)
376 printf("erase block %d\n",blockNumber);
378 if(blockNumber == 320)
381 if(blockNumber < 0 || blockNumber >= filedisk.nBlocks)
383 T(YAFFS_TRACE_ALWAYS,("Attempt to erase non-existant block %d\n",blockNumber));
396 h = filedisk.handle[(blockNumber / ( BLOCKS_PER_HANDLE))];
397 lseek(h,((blockNumber % BLOCKS_PER_HANDLE) * dev->nChunksPerBlock) * PAGE_SIZE,SEEK_SET);
398 for(i = 0; i < dev->nChunksPerBlock; i++)
400 write(h,pg,PAGE_SIZE);
402 pos = lseek(h, 0,SEEK_CUR);
409 int yflash_InitialiseNAND(yaffs_Device *dev)
419 int yflash_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber)
421 yaffs_ExtendedTags tags;
426 chunkNo = blockNo * dev->nChunksPerBlock;
428 yflash_ReadChunkWithTagsFromNAND(dev,chunkNo,NULL,&tags);
431 *state = YAFFS_BLOCK_STATE_DEAD;
433 else if(!tags.chunkUsed)
435 *state = YAFFS_BLOCK_STATE_EMPTY;
437 else if(tags.chunkUsed)
439 *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
440 *sequenceNumber = tags.sequenceNumber;