yaffs_fileem2k.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. /*
  2. * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
  3. *
  4. * Copyright (C) 2002-2007 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. * This provides a YAFFS nand emulation on a file for emulating 2kB pages.
  15. * This is only intended as test code to test persistence etc.
  16. */
  17. const char *yaffs_flashif_c_version = "$Id: yaffs_fileem2k.c,v 1.12 2007/02/14 01:09:06 wookey Exp $";
  18. #include "yportenv.h"
  19. #include "yaffs_flashif.h"
  20. #include "yaffs_guts.h"
  21. #include "devextras.h"
  22. #include <sys/types.h>
  23. #include <sys/stat.h>
  24. #include <fcntl.h>
  25. #include <unistd.h>
  26. #include "yaffs_fileem2k.h"
  27. #include "yaffs_packedtags2.h"
  28. //#define SIMULATE_FAILURES
  29. typedef struct
  30. {
  31. __u8 data[PAGE_SIZE]; // Data + spare
  32. } yflash_Page;
  33. typedef struct
  34. {
  35. yflash_Page page[PAGES_PER_BLOCK]; // The pages in the block
  36. } yflash_Block;
  37. #define MAX_HANDLES 20
  38. #define BLOCKS_PER_HANDLE 8000
  39. typedef struct
  40. {
  41. int handle[MAX_HANDLES];
  42. int nBlocks;
  43. } yflash_Device;
  44. static yflash_Device filedisk;
  45. int yaffs_testPartialWrite = 0;
  46. static __u8 localBuffer[PAGE_SIZE];
  47. static char *NToName(char *buf,int n)
  48. {
  49. sprintf(buf,"emfile%d",n);
  50. return buf;
  51. }
  52. static char dummyBuffer[BLOCK_SIZE];
  53. static int GetBlockFileHandle(int n)
  54. {
  55. int h;
  56. int requiredSize;
  57. char name[40];
  58. NToName(name,n);
  59. int fSize;
  60. int i;
  61. h = open(name, O_RDWR | O_CREAT, S_IREAD | S_IWRITE);
  62. if(h >= 0){
  63. fSize = lseek(h,0,SEEK_END);
  64. requiredSize = BLOCKS_PER_HANDLE * BLOCK_SIZE;
  65. if(fSize < requiredSize){
  66. for(i = 0; i < BLOCKS_PER_HANDLE; i++)
  67. if(write(h,dummyBuffer,BLOCK_SIZE) != BLOCK_SIZE)
  68. return -1;
  69. }
  70. }
  71. return h;
  72. }
  73. static int CheckInit(void)
  74. {
  75. static int initialised = 0;
  76. int h;
  77. int i;
  78. off_t fSize;
  79. off_t requiredSize;
  80. int written;
  81. int blk;
  82. yflash_Page p;
  83. if(initialised)
  84. {
  85. return YAFFS_OK;
  86. }
  87. initialised = 1;
  88. memset(dummyBuffer,0xff,sizeof(dummyBuffer));
  89. filedisk.nBlocks = SIZE_IN_MB * BLOCKS_PER_MB;
  90. for(i = 0; i < MAX_HANDLES; i++)
  91. filedisk.handle[i] = -1;
  92. for(i = 0,blk = 0; blk < filedisk.nBlocks; blk+=BLOCKS_PER_HANDLE,i++)
  93. filedisk.handle[i] = GetBlockFileHandle(i);
  94. return 1;
  95. }
  96. int yflash_GetNumberOfBlocks(void)
  97. {
  98. CheckInit();
  99. return filedisk.nBlocks;
  100. }
  101. int yflash_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, yaffs_ExtendedTags *tags)
  102. {
  103. int written;
  104. int pos;
  105. int h;
  106. int i;
  107. int nRead;
  108. int error;
  109. T(YAFFS_TRACE_MTD,(TSTR("write chunk %d data %x tags %x" TENDSTR),chunkInNAND,(unsigned)data, (unsigned)tags));
  110. CheckInit();
  111. if(data)
  112. {
  113. pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE;
  114. h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
  115. lseek(h,pos,SEEK_SET);
  116. nRead = read(h, localBuffer,dev->nDataBytesPerChunk);
  117. for(i = error = 0; i < dev->nDataBytesPerChunk && !error; i++){
  118. if(localBuffer[i] != 0xFF){
  119. printf("nand simulation: chunk %d data byte %d was %0x2\n",
  120. chunkInNAND,i,localBuffer[i]);
  121. error = 1;
  122. }
  123. }
  124. for(i = 0; i < dev->nDataBytesPerChunk; i++)
  125. localBuffer[i] &= data[i];
  126. if(memcmp(localBuffer,data,dev->nDataBytesPerChunk))
  127. printf("nand simulator: data does not match\n");
  128. lseek(h,pos,SEEK_SET);
  129. written = write(h,localBuffer,dev->nDataBytesPerChunk);
  130. if(yaffs_testPartialWrite){
  131. close(h);
  132. exit(1);
  133. }
  134. #ifdef SIMULATE_FAILURES
  135. if((chunkInNAND >> 6) == 100)
  136. written = 0;
  137. if((chunkInNAND >> 6) == 110)
  138. written = 0;
  139. #endif
  140. if(written != dev->nDataBytesPerChunk) return YAFFS_FAIL;
  141. }
  142. if(tags)
  143. {
  144. pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE + PAGE_DATA_SIZE ;
  145. h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
  146. lseek(h,pos,SEEK_SET);
  147. if( 0 && dev->isYaffs2)
  148. {
  149. written = write(h,tags,sizeof(yaffs_ExtendedTags));
  150. if(written != sizeof(yaffs_ExtendedTags)) return YAFFS_FAIL;
  151. }
  152. else
  153. {
  154. yaffs_PackedTags2 pt;
  155. yaffs_PackTags2(&pt,tags);
  156. __u8 * ptab = (__u8 *)&pt;
  157. nRead = read(h,localBuffer,sizeof(pt));
  158. for(i = error = 0; i < sizeof(pt) && !error; i++){
  159. if(localBuffer[i] != 0xFF){
  160. printf("nand simulation: chunk %d oob byte %d was %0x2\n",
  161. chunkInNAND,i,localBuffer[i]);
  162. error = 1;
  163. }
  164. }
  165. for(i = 0; i < sizeof(pt); i++)
  166. localBuffer[i] &= ptab[i];
  167. if(memcmp(localBuffer,&pt,sizeof(pt)))
  168. printf("nand sim: tags corruption\n");
  169. lseek(h,pos,SEEK_SET);
  170. written = write(h,localBuffer,sizeof(pt));
  171. if(written != sizeof(pt)) return YAFFS_FAIL;
  172. }
  173. }
  174. return YAFFS_OK;
  175. }
  176. int yaffs_CheckAllFF(const __u8 *ptr, int n)
  177. {
  178. while(n)
  179. {
  180. n--;
  181. if(*ptr!=0xFF) return 0;
  182. ptr++;
  183. }
  184. return 1;
  185. }
  186. static int fail300 = 1;
  187. static int fail320 = 1;
  188. static int failRead10 = 2;
  189. int yflash_ReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *tags)
  190. {
  191. int nread;
  192. int pos;
  193. int h;
  194. T(YAFFS_TRACE_MTD,(TSTR("read chunk %d data %x tags %x" TENDSTR),chunkInNAND,(unsigned)data, (unsigned)tags));
  195. CheckInit();
  196. if(data)
  197. {
  198. pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE;
  199. h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
  200. lseek(h,pos,SEEK_SET);
  201. nread = read(h,data,dev->nDataBytesPerChunk);
  202. if(nread != dev->nDataBytesPerChunk) return YAFFS_FAIL;
  203. }
  204. if(tags)
  205. {
  206. pos = (chunkInNAND % (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE)) * PAGE_SIZE + PAGE_DATA_SIZE;
  207. h = filedisk.handle[(chunkInNAND / (PAGES_PER_BLOCK * BLOCKS_PER_HANDLE))];
  208. lseek(h,pos,SEEK_SET);
  209. if(0 && dev->isYaffs2)
  210. {
  211. nread= read(h,tags,sizeof(yaffs_ExtendedTags));
  212. if(nread != sizeof(yaffs_ExtendedTags)) return YAFFS_FAIL;
  213. if(yaffs_CheckAllFF((__u8 *)tags,sizeof(yaffs_ExtendedTags)))
  214. {
  215. yaffs_InitialiseTags(tags);
  216. }
  217. else
  218. {
  219. tags->chunkUsed = 1;
  220. }
  221. }
  222. else
  223. {
  224. yaffs_PackedTags2 pt;
  225. nread= read(h,&pt,sizeof(pt));
  226. yaffs_UnpackTags2(tags,&pt);
  227. #ifdef SIMULATE_FAILURES
  228. if((chunkInNAND >> 6) == 100) {
  229. if(fail300 && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR){
  230. tags->eccResult = YAFFS_ECC_RESULT_FIXED;
  231. fail300 = 0;
  232. }
  233. }
  234. if((chunkInNAND >> 6) == 110) {
  235. if(fail320 && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR){
  236. tags->eccResult = YAFFS_ECC_RESULT_FIXED;
  237. fail320 = 0;
  238. }
  239. }
  240. #endif
  241. if(failRead10>0 && chunkInNAND == 10){
  242. failRead10--;
  243. nread = 0;
  244. }
  245. if(nread != sizeof(pt)) return YAFFS_FAIL;
  246. }
  247. }
  248. return YAFFS_OK;
  249. }
  250. int yflash_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
  251. {
  252. int written;
  253. int h;
  254. yaffs_PackedTags2 pt;
  255. CheckInit();
  256. memset(&pt,0,sizeof(pt));
  257. h = filedisk.handle[(blockNo / ( BLOCKS_PER_HANDLE))];
  258. lseek(h,((blockNo % BLOCKS_PER_HANDLE) * dev->nChunksPerBlock) * PAGE_SIZE + PAGE_DATA_SIZE,SEEK_SET);
  259. written = write(h,&pt,sizeof(pt));
  260. if(written != sizeof(pt)) return YAFFS_FAIL;
  261. return YAFFS_OK;
  262. }
  263. int yflash_EraseBlockInNAND(yaffs_Device *dev, int blockNumber)
  264. {
  265. int i;
  266. int h;
  267. CheckInit();
  268. printf("erase block %d\n",blockNumber);
  269. if(blockNumber == 320)
  270. fail320 = 1;
  271. if(blockNumber < 0 || blockNumber >= filedisk.nBlocks)
  272. {
  273. T(YAFFS_TRACE_ALWAYS,("Attempt to erase non-existant block %d\n",blockNumber));
  274. return YAFFS_FAIL;
  275. }
  276. else
  277. {
  278. __u8 pg[PAGE_SIZE];
  279. int syz = PAGE_SIZE;
  280. int pos;
  281. memset(pg,0xff,syz);
  282. h = filedisk.handle[(blockNumber / ( BLOCKS_PER_HANDLE))];
  283. lseek(h,((blockNumber % BLOCKS_PER_HANDLE) * dev->nChunksPerBlock) * PAGE_SIZE,SEEK_SET);
  284. for(i = 0; i < dev->nChunksPerBlock; i++)
  285. {
  286. write(h,pg,PAGE_SIZE);
  287. }
  288. pos = lseek(h, 0,SEEK_CUR);
  289. return YAFFS_OK;
  290. }
  291. }
  292. int yflash_InitialiseNAND(yaffs_Device *dev)
  293. {
  294. CheckInit();
  295. return YAFFS_OK;
  296. }
  297. int yflash_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber)
  298. {
  299. yaffs_ExtendedTags tags;
  300. int chunkNo;
  301. *sequenceNumber = 0;
  302. chunkNo = blockNo * dev->nChunksPerBlock;
  303. yflash_ReadChunkWithTagsFromNAND(dev,chunkNo,NULL,&tags);
  304. if(tags.blockBad)
  305. {
  306. *state = YAFFS_BLOCK_STATE_DEAD;
  307. }
  308. else if(!tags.chunkUsed)
  309. {
  310. *state = YAFFS_BLOCK_STATE_EMPTY;
  311. }
  312. else if(tags.chunkUsed)
  313. {
  314. *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
  315. *sequenceNumber = tags.sequenceNumber;
  316. }
  317. return YAFFS_OK;
  318. }