yaffs_tagscompat.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  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. #include "yaffs_guts.h"
  14. #include "yaffs_tagscompat.h"
  15. #include "yaffs_ecc.h"
  16. static void yaffs_HandleReadDataError(yaffs_Device * dev, int chunkInNAND);
  17. #ifdef NOTYET
  18. static void yaffs_CheckWrittenBlock(yaffs_Device * dev, int chunkInNAND);
  19. static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND,
  20. const __u8 * data,
  21. const yaffs_Spare * spare);
  22. static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND,
  23. const yaffs_Spare * spare);
  24. static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND);
  25. #endif
  26. static const char yaffs_countBitsTable[256] = {
  27. 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
  28. 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
  29. 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
  30. 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
  31. 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
  32. 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
  33. 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
  34. 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
  35. 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
  36. 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
  37. 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
  38. 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
  39. 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
  40. 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
  41. 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
  42. 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
  43. };
  44. static int yaffs_CountBits(__u8 x)
  45. {
  46. int retVal;
  47. retVal = yaffs_countBitsTable[x];
  48. return retVal;
  49. }
  50. /********** Tags ECC calculations *********/
  51. void yaffs_CalcECC(const __u8 * data, yaffs_Spare * spare)
  52. {
  53. yaffs_ECCCalculate(data, spare->ecc1);
  54. yaffs_ECCCalculate(&data[256], spare->ecc2);
  55. }
  56. void yaffs_CalcTagsECC(yaffs_Tags * tags)
  57. {
  58. /* Calculate an ecc */
  59. unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes;
  60. unsigned i, j;
  61. unsigned ecc = 0;
  62. unsigned bit = 0;
  63. tags->ecc = 0;
  64. for (i = 0; i < 8; i++) {
  65. for (j = 1; j & 0xff; j <<= 1) {
  66. bit++;
  67. if (b[i] & j) {
  68. ecc ^= bit;
  69. }
  70. }
  71. }
  72. tags->ecc = ecc;
  73. }
  74. int yaffs_CheckECCOnTags(yaffs_Tags * tags)
  75. {
  76. unsigned ecc = tags->ecc;
  77. yaffs_CalcTagsECC(tags);
  78. ecc ^= tags->ecc;
  79. if (ecc && ecc <= 64) {
  80. /* TODO: Handle the failure better. Retire? */
  81. unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes;
  82. ecc--;
  83. b[ecc / 8] ^= (1 << (ecc & 7));
  84. /* Now recvalc the ecc */
  85. yaffs_CalcTagsECC(tags);
  86. return 1; /* recovered error */
  87. } else if (ecc) {
  88. /* Wierd ecc failure value */
  89. /* TODO Need to do somethiong here */
  90. return -1; /* unrecovered error */
  91. }
  92. return 0;
  93. }
  94. /********** Tags **********/
  95. static void yaffs_LoadTagsIntoSpare(yaffs_Spare * sparePtr,
  96. yaffs_Tags * tagsPtr)
  97. {
  98. yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr;
  99. yaffs_CalcTagsECC(tagsPtr);
  100. sparePtr->tagByte0 = tu->asBytes[0];
  101. sparePtr->tagByte1 = tu->asBytes[1];
  102. sparePtr->tagByte2 = tu->asBytes[2];
  103. sparePtr->tagByte3 = tu->asBytes[3];
  104. sparePtr->tagByte4 = tu->asBytes[4];
  105. sparePtr->tagByte5 = tu->asBytes[5];
  106. sparePtr->tagByte6 = tu->asBytes[6];
  107. sparePtr->tagByte7 = tu->asBytes[7];
  108. }
  109. static void yaffs_GetTagsFromSpare(yaffs_Device * dev, yaffs_Spare * sparePtr,
  110. yaffs_Tags * tagsPtr)
  111. {
  112. yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr;
  113. int result;
  114. tu->asBytes[0] = sparePtr->tagByte0;
  115. tu->asBytes[1] = sparePtr->tagByte1;
  116. tu->asBytes[2] = sparePtr->tagByte2;
  117. tu->asBytes[3] = sparePtr->tagByte3;
  118. tu->asBytes[4] = sparePtr->tagByte4;
  119. tu->asBytes[5] = sparePtr->tagByte5;
  120. tu->asBytes[6] = sparePtr->tagByte6;
  121. tu->asBytes[7] = sparePtr->tagByte7;
  122. result = yaffs_CheckECCOnTags(tagsPtr);
  123. if (result > 0) {
  124. dev->tagsEccFixed++;
  125. } else if (result < 0) {
  126. dev->tagsEccUnfixed++;
  127. }
  128. }
  129. static void yaffs_SpareInitialise(yaffs_Spare * spare)
  130. {
  131. memset(spare, 0xFF, sizeof(yaffs_Spare));
  132. }
  133. static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev,
  134. int chunkInNAND, const __u8 * data,
  135. yaffs_Spare * spare)
  136. {
  137. if (chunkInNAND < dev->startBlock * dev->nChunksPerBlock) {
  138. T(YAFFS_TRACE_ERROR,
  139. (TSTR("**>> yaffs chunk %d is not valid" TENDSTR),
  140. chunkInNAND));
  141. return YAFFS_FAIL;
  142. }
  143. dev->nPageWrites++;
  144. return dev->writeChunkToNAND(dev, chunkInNAND, data, spare);
  145. }
  146. static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,
  147. int chunkInNAND,
  148. __u8 * data,
  149. yaffs_Spare * spare,
  150. yaffs_ECCResult * eccResult,
  151. int doErrorCorrection)
  152. {
  153. int retVal;
  154. yaffs_Spare localSpare;
  155. dev->nPageReads++;
  156. if (!spare && data) {
  157. /* If we don't have a real spare, then we use a local one. */
  158. /* Need this for the calculation of the ecc */
  159. spare = &localSpare;
  160. }
  161. if (!dev->useNANDECC) {
  162. retVal = dev->readChunkFromNAND(dev, chunkInNAND, data, spare);
  163. if (data && doErrorCorrection) {
  164. /* Do ECC correction */
  165. /* Todo handle any errors */
  166. int eccResult1, eccResult2;
  167. __u8 calcEcc[3];
  168. yaffs_ECCCalculate(data, calcEcc);
  169. eccResult1 =
  170. yaffs_ECCCorrect(data, spare->ecc1, calcEcc);
  171. yaffs_ECCCalculate(&data[256], calcEcc);
  172. eccResult2 =
  173. yaffs_ECCCorrect(&data[256], spare->ecc2, calcEcc);
  174. if (eccResult1 > 0) {
  175. T(YAFFS_TRACE_ERROR,
  176. (TSTR
  177. ("**>>yaffs ecc error fix performed on chunk %d:0"
  178. TENDSTR), chunkInNAND));
  179. dev->eccFixed++;
  180. } else if (eccResult1 < 0) {
  181. T(YAFFS_TRACE_ERROR,
  182. (TSTR
  183. ("**>>yaffs ecc error unfixed on chunk %d:0"
  184. TENDSTR), chunkInNAND));
  185. dev->eccUnfixed++;
  186. }
  187. if (eccResult2 > 0) {
  188. T(YAFFS_TRACE_ERROR,
  189. (TSTR
  190. ("**>>yaffs ecc error fix performed on chunk %d:1"
  191. TENDSTR), chunkInNAND));
  192. dev->eccFixed++;
  193. } else if (eccResult2 < 0) {
  194. T(YAFFS_TRACE_ERROR,
  195. (TSTR
  196. ("**>>yaffs ecc error unfixed on chunk %d:1"
  197. TENDSTR), chunkInNAND));
  198. dev->eccUnfixed++;
  199. }
  200. if (eccResult1 || eccResult2) {
  201. /* We had a data problem on this page */
  202. yaffs_HandleReadDataError(dev, chunkInNAND);
  203. }
  204. if (eccResult1 < 0 || eccResult2 < 0)
  205. *eccResult = YAFFS_ECC_RESULT_UNFIXED;
  206. else if (eccResult1 > 0 || eccResult2 > 0)
  207. *eccResult = YAFFS_ECC_RESULT_FIXED;
  208. else
  209. *eccResult = YAFFS_ECC_RESULT_NO_ERROR;
  210. }
  211. } else {
  212. /* Must allocate enough memory for spare+2*sizeof(int) */
  213. /* for ecc results from device. */
  214. struct yaffs_NANDSpare nspare;
  215. retVal =
  216. dev->readChunkFromNAND(dev, chunkInNAND, data,
  217. (yaffs_Spare *) & nspare);
  218. memcpy(spare, &nspare, sizeof(yaffs_Spare));
  219. if (data && doErrorCorrection) {
  220. if (nspare.eccres1 > 0) {
  221. T(YAFFS_TRACE_ERROR,
  222. (TSTR
  223. ("**>>mtd ecc error fix performed on chunk %d:0"
  224. TENDSTR), chunkInNAND));
  225. } else if (nspare.eccres1 < 0) {
  226. T(YAFFS_TRACE_ERROR,
  227. (TSTR
  228. ("**>>mtd ecc error unfixed on chunk %d:0"
  229. TENDSTR), chunkInNAND));
  230. }
  231. if (nspare.eccres2 > 0) {
  232. T(YAFFS_TRACE_ERROR,
  233. (TSTR
  234. ("**>>mtd ecc error fix performed on chunk %d:1"
  235. TENDSTR), chunkInNAND));
  236. } else if (nspare.eccres2 < 0) {
  237. T(YAFFS_TRACE_ERROR,
  238. (TSTR
  239. ("**>>mtd ecc error unfixed on chunk %d:1"
  240. TENDSTR), chunkInNAND));
  241. }
  242. if (nspare.eccres1 || nspare.eccres2) {
  243. /* We had a data problem on this page */
  244. yaffs_HandleReadDataError(dev, chunkInNAND);
  245. }
  246. if (nspare.eccres1 < 0 || nspare.eccres2 < 0)
  247. *eccResult = YAFFS_ECC_RESULT_UNFIXED;
  248. else if (nspare.eccres1 > 0 || nspare.eccres2 > 0)
  249. *eccResult = YAFFS_ECC_RESULT_FIXED;
  250. else
  251. *eccResult = YAFFS_ECC_RESULT_NO_ERROR;
  252. }
  253. }
  254. return retVal;
  255. }
  256. #ifdef NOTYET
  257. static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
  258. int chunkInNAND)
  259. {
  260. static int init = 0;
  261. static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK];
  262. static __u8 data[YAFFS_BYTES_PER_CHUNK];
  263. /* Might as well always allocate the larger size for */
  264. /* dev->useNANDECC == true; */
  265. static __u8 spare[sizeof(struct yaffs_NANDSpare)];
  266. dev->readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) spare);
  267. if (!init) {
  268. memset(cmpbuf, 0xff, YAFFS_BYTES_PER_CHUNK);
  269. init = 1;
  270. }
  271. if (memcmp(cmpbuf, data, YAFFS_BYTES_PER_CHUNK))
  272. return YAFFS_FAIL;
  273. if (memcmp(cmpbuf, spare, 16))
  274. return YAFFS_FAIL;
  275. return YAFFS_OK;
  276. }
  277. #endif
  278. /*
  279. * Functions for robustisizing
  280. */
  281. static void yaffs_HandleReadDataError(yaffs_Device * dev, int chunkInNAND)
  282. {
  283. int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
  284. /* Mark the block for retirement */
  285. yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1;
  286. T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
  287. (TSTR("**>>Block %d marked for retirement" TENDSTR), blockInNAND));
  288. /* TODO:
  289. * Just do a garbage collection on the affected block
  290. * then retire the block
  291. * NB recursion
  292. */
  293. }
  294. #ifdef NOTYET
  295. static void yaffs_CheckWrittenBlock(yaffs_Device * dev, int chunkInNAND)
  296. {
  297. }
  298. static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND,
  299. const __u8 * data,
  300. const yaffs_Spare * spare)
  301. {
  302. }
  303. static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND,
  304. const yaffs_Spare * spare)
  305. {
  306. }
  307. static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND)
  308. {
  309. int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
  310. /* Mark the block for retirement */
  311. yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1;
  312. /* Delete the chunk */
  313. yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
  314. }
  315. static int yaffs_VerifyCompare(const __u8 * d0, const __u8 * d1,
  316. const yaffs_Spare * s0, const yaffs_Spare * s1)
  317. {
  318. if (memcmp(d0, d1, YAFFS_BYTES_PER_CHUNK) != 0 ||
  319. s0->tagByte0 != s1->tagByte0 ||
  320. s0->tagByte1 != s1->tagByte1 ||
  321. s0->tagByte2 != s1->tagByte2 ||
  322. s0->tagByte3 != s1->tagByte3 ||
  323. s0->tagByte4 != s1->tagByte4 ||
  324. s0->tagByte5 != s1->tagByte5 ||
  325. s0->tagByte6 != s1->tagByte6 ||
  326. s0->tagByte7 != s1->tagByte7 ||
  327. s0->ecc1[0] != s1->ecc1[0] ||
  328. s0->ecc1[1] != s1->ecc1[1] ||
  329. s0->ecc1[2] != s1->ecc1[2] ||
  330. s0->ecc2[0] != s1->ecc2[0] ||
  331. s0->ecc2[1] != s1->ecc2[1] || s0->ecc2[2] != s1->ecc2[2]) {
  332. return 0;
  333. }
  334. return 1;
  335. }
  336. #endif /* NOTYET */
  337. int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device * dev,
  338. int chunkInNAND,
  339. const __u8 * data,
  340. const yaffs_ExtendedTags *
  341. eTags)
  342. {
  343. yaffs_Spare spare;
  344. yaffs_Tags tags;
  345. yaffs_SpareInitialise(&spare);
  346. if (eTags->chunkDeleted) {
  347. spare.pageStatus = 0;
  348. } else {
  349. tags.objectId = eTags->objectId;
  350. tags.chunkId = eTags->chunkId;
  351. tags.byteCount = eTags->byteCount;
  352. tags.serialNumber = eTags->serialNumber;
  353. if (!dev->useNANDECC && data) {
  354. yaffs_CalcECC(data, &spare);
  355. }
  356. yaffs_LoadTagsIntoSpare(&spare, &tags);
  357. }
  358. return yaffs_WriteChunkToNAND(dev, chunkInNAND, data, &spare);
  359. }
  360. int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device * dev,
  361. int chunkInNAND,
  362. __u8 * data,
  363. yaffs_ExtendedTags * eTags)
  364. {
  365. yaffs_Spare spare;
  366. yaffs_Tags tags;
  367. yaffs_ECCResult eccResult;
  368. static yaffs_Spare spareFF;
  369. static int init;
  370. if (!init) {
  371. memset(&spareFF, 0xFF, sizeof(spareFF));
  372. init = 1;
  373. }
  374. if (yaffs_ReadChunkFromNAND
  375. (dev, chunkInNAND, data, &spare, &eccResult, 1)) {
  376. /* eTags may be NULL */
  377. if (eTags) {
  378. int deleted =
  379. (yaffs_CountBits(spare.pageStatus) < 7) ? 1 : 0;
  380. eTags->chunkDeleted = deleted;
  381. eTags->eccResult = eccResult;
  382. eTags->blockBad = 0; /* We're reading it */
  383. /* therefore it is not a bad block */
  384. eTags->chunkUsed =
  385. (memcmp(&spareFF, &spare, sizeof(spareFF)) !=
  386. 0) ? 1 : 0;
  387. if (eTags->chunkUsed) {
  388. yaffs_GetTagsFromSpare(dev, &spare, &tags);
  389. eTags->objectId = tags.objectId;
  390. eTags->chunkId = tags.chunkId;
  391. eTags->byteCount = tags.byteCount;
  392. eTags->serialNumber = tags.serialNumber;
  393. }
  394. }
  395. return YAFFS_OK;
  396. } else {
  397. return YAFFS_FAIL;
  398. }
  399. }
  400. int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
  401. int blockInNAND)
  402. {
  403. yaffs_Spare spare;
  404. memset(&spare, 0xff, sizeof(yaffs_Spare));
  405. spare.blockStatus = 'Y';
  406. yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock, NULL,
  407. &spare);
  408. yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock + 1,
  409. NULL, &spare);
  410. return YAFFS_OK;
  411. }
  412. int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
  413. int blockNo, yaffs_BlockState *
  414. state,
  415. int *sequenceNumber)
  416. {
  417. yaffs_Spare spare0, spare1;
  418. static yaffs_Spare spareFF;
  419. static int init;
  420. yaffs_ECCResult dummy;
  421. if (!init) {
  422. memset(&spareFF, 0xFF, sizeof(spareFF));
  423. init = 1;
  424. }
  425. *sequenceNumber = 0;
  426. yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock, NULL,
  427. &spare0, &dummy, 1);
  428. yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock + 1, NULL,
  429. &spare1, &dummy, 1);
  430. if (yaffs_CountBits(spare0.blockStatus & spare1.blockStatus) < 7)
  431. *state = YAFFS_BLOCK_STATE_DEAD;
  432. else if (memcmp(&spareFF, &spare0, sizeof(spareFF)) == 0)
  433. *state = YAFFS_BLOCK_STATE_EMPTY;
  434. else
  435. *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
  436. return YAFFS_OK;
  437. }