yaffs_mtdif1.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. /*
  2. * YAFFS: Yet another FFS. A NAND-flash specific file system.
  3. * yaffs_mtdif1.c NAND mtd interface functions for small-page NAND.
  4. *
  5. * Copyright (C) 2002 Aleph One Ltd.
  6. * for Toby Churchill Ltd and Brightstar Engineering
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License version 2 as
  10. * published by the Free Software Foundation.
  11. */
  12. /*
  13. * This module provides the interface between yaffs_nand.c and the
  14. * MTD API. This version is used when the MTD interface supports the
  15. * 'mtd_oob_ops' style calls to read_oob and write_oob, circa 2.6.17,
  16. * and we have small-page NAND device.
  17. *
  18. * These functions are invoked via function pointers in yaffs_nand.c.
  19. * This replaces functionality provided by functions in yaffs_mtdif.c
  20. * and the yaffs_TagsCompatability functions in yaffs_tagscompat.c that are
  21. * called in yaffs_mtdif.c when the function pointers are NULL.
  22. * We assume the MTD layer is performing ECC (useNANDECC is true).
  23. */
  24. #include "yportenv.h"
  25. #include "yaffs_guts.h"
  26. #include "yaffs_packedtags1.h"
  27. #include "yaffs_tagscompat.h" // for yaffs_CalcTagsECC
  28. #include "linux/kernel.h"
  29. #include "linux/version.h"
  30. #include "linux/types.h"
  31. #include "linux/mtd/mtd.h"
  32. /* Don't compile this module if we don't have MTD's mtd_oob_ops interface */
  33. #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
  34. const char *yaffs_mtdif1_c_version = "$Id: yaffs_mtdif1.c,v 1.5 2007/10/29 14:59:57 imcd Exp $";
  35. #ifndef CONFIG_YAFFS_9BYTE_TAGS
  36. # define YTAG1_SIZE 8
  37. #else
  38. # define YTAG1_SIZE 9
  39. #endif
  40. #if 0
  41. /* Use the following nand_ecclayout with MTD when using
  42. * CONFIG_YAFFS_9BYTE_TAGS and the older on-NAND tags layout.
  43. * If you have existing Yaffs images and the byte order differs from this,
  44. * adjust 'oobfree' to match your existing Yaffs data.
  45. *
  46. * This nand_ecclayout scatters/gathers to/from the old-yaffs layout with the
  47. * pageStatus byte (at NAND spare offset 4) scattered/gathered from/to
  48. * the 9th byte.
  49. *
  50. * Old-style on-NAND format: T0,T1,T2,T3,P,B,T4,T5,E0,E1,E2,T6,T7,E3,E4,E5
  51. * We have/need PackedTags1 plus pageStatus: T0,T1,T2,T3,T4,T5,T6,T7,P
  52. * where Tn are the tag bytes, En are MTD's ECC bytes, P is the pageStatus
  53. * byte and B is the small-page bad-block indicator byte.
  54. */
  55. static struct nand_ecclayout nand_oob_16 = {
  56. .eccbytes = 6,
  57. .eccpos = { 8, 9, 10, 13, 14, 15 },
  58. .oobavail = 9,
  59. .oobfree = { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } }
  60. };
  61. #endif
  62. /* Write a chunk (page) of data to NAND.
  63. *
  64. * Caller always provides ExtendedTags data which are converted to a more
  65. * compact (packed) form for storage in NAND. A mini-ECC runs over the
  66. * contents of the tags meta-data; used to valid the tags when read.
  67. *
  68. * - Pack ExtendedTags to PackedTags1 form
  69. * - Compute mini-ECC for PackedTags1
  70. * - Write data and packed tags to NAND.
  71. *
  72. * Note: Due to the use of the PackedTags1 meta-data which does not include
  73. * a full sequence number (as found in the larger PackedTags2 form) it is
  74. * necessary for Yaffs to re-write a chunk/page (just once) to mark it as
  75. * discarded and dirty. This is not ideal: newer NAND parts are supposed
  76. * to be written just once. When Yaffs performs this operation, this
  77. * function is called with a NULL data pointer -- calling MTD write_oob
  78. * without data is valid usage (2.6.17).
  79. *
  80. * Any underlying MTD error results in YAFFS_FAIL.
  81. * Returns YAFFS_OK or YAFFS_FAIL.
  82. */
  83. int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev,
  84. int chunkInNAND, const __u8 * data, const yaffs_ExtendedTags * etags)
  85. {
  86. struct mtd_info * mtd = dev->genericDevice;
  87. int chunkBytes = dev->nDataBytesPerChunk;
  88. loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
  89. struct mtd_oob_ops ops;
  90. yaffs_PackedTags1 pt1;
  91. int retval;
  92. /* we assume that PackedTags1 and yaffs_Tags are compatible */
  93. compile_time_assertion(sizeof(yaffs_PackedTags1) == 12);
  94. compile_time_assertion(sizeof(yaffs_Tags) == 8);
  95. dev->nPageWrites++;
  96. yaffs_PackTags1(&pt1, etags);
  97. yaffs_CalcTagsECC((yaffs_Tags *)&pt1);
  98. /* When deleting a chunk, the upper layer provides only skeletal
  99. * etags, one with chunkDeleted set. However, we need to update the
  100. * tags, not erase them completely. So we use the NAND write property
  101. * that only zeroed-bits stick and set tag bytes to all-ones and
  102. * zero just the (not) deleted bit.
  103. */
  104. #ifndef CONFIG_YAFFS_9BYTE_TAGS
  105. if (etags->chunkDeleted) {
  106. memset(&pt1, 0xff, 8);
  107. /* clear delete status bit to indicate deleted */
  108. pt1.deleted = 0;
  109. }
  110. #else
  111. ((__u8 *)&pt1)[8] = 0xff;
  112. if (etags->chunkDeleted) {
  113. memset(&pt1, 0xff, 8);
  114. /* zero pageStatus byte to indicate deleted */
  115. ((__u8 *)&pt1)[8] = 0;
  116. }
  117. #endif
  118. memset(&ops, 0, sizeof(ops));
  119. ops.mode = MTD_OOB_AUTO;
  120. ops.len = (data) ? chunkBytes : 0;
  121. ops.ooblen = YTAG1_SIZE;
  122. ops.datbuf = (__u8 *)data;
  123. ops.oobbuf = (__u8 *)&pt1;
  124. retval = mtd->write_oob(mtd, addr, &ops);
  125. if (retval) {
  126. yaffs_trace(YAFFS_TRACE_MTD,
  127. "write_oob failed, chunk %d, mtd error %d\n",
  128. chunkInNAND, retval);
  129. }
  130. return retval ? YAFFS_FAIL : YAFFS_OK;
  131. }
  132. /* Return with empty ExtendedTags but add eccResult.
  133. */
  134. static int rettags(yaffs_ExtendedTags * etags, int eccResult, int retval)
  135. {
  136. if (etags) {
  137. memset(etags, 0, sizeof(*etags));
  138. etags->eccResult = eccResult;
  139. }
  140. return retval;
  141. }
  142. /* Read a chunk (page) from NAND.
  143. *
  144. * Caller expects ExtendedTags data to be usable even on error; that is,
  145. * all members except eccResult and blockBad are zeroed.
  146. *
  147. * - Check ECC results for data (if applicable)
  148. * - Check for blank/erased block (return empty ExtendedTags if blank)
  149. * - Check the PackedTags1 mini-ECC (correct if necessary/possible)
  150. * - Convert PackedTags1 to ExtendedTags
  151. * - Update eccResult and blockBad members to refect state.
  152. *
  153. * Returns YAFFS_OK or YAFFS_FAIL.
  154. */
  155. int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
  156. int chunkInNAND, __u8 * data, yaffs_ExtendedTags * etags)
  157. {
  158. struct mtd_info * mtd = dev->genericDevice;
  159. int chunkBytes = dev->nDataBytesPerChunk;
  160. loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
  161. int eccres = YAFFS_ECC_RESULT_NO_ERROR;
  162. struct mtd_oob_ops ops;
  163. yaffs_PackedTags1 pt1;
  164. int retval;
  165. int deleted;
  166. dev->nPageReads++;
  167. memset(&ops, 0, sizeof(ops));
  168. ops.mode = MTD_OOB_AUTO;
  169. ops.len = (data) ? chunkBytes : 0;
  170. ops.ooblen = YTAG1_SIZE;
  171. ops.datbuf = data;
  172. ops.oobbuf = (__u8 *)&pt1;
  173. #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
  174. /* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug;
  175. * help it out with ops.len = ops.ooblen when ops.datbuf == NULL.
  176. */
  177. ops.len = (ops.datbuf) ? ops.len : ops.ooblen;
  178. #endif
  179. /* Read page and oob using MTD.
  180. * Check status and determine ECC result.
  181. */
  182. retval = mtd->read_oob(mtd, addr, &ops);
  183. if (retval) {
  184. yaffs_trace(YAFFS_TRACE_MTD,
  185. "read_oob failed, chunk %d, mtd error %d\n",
  186. chunkInNAND, retval);
  187. }
  188. switch (retval) {
  189. case 0:
  190. /* no error */
  191. break;
  192. case -EUCLEAN:
  193. /* MTD's ECC fixed the data */
  194. eccres = YAFFS_ECC_RESULT_FIXED;
  195. dev->eccFixed++;
  196. break;
  197. case -EBADMSG:
  198. /* MTD's ECC could not fix the data */
  199. dev->eccUnfixed++;
  200. /* fall into... */
  201. default:
  202. rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0);
  203. etags->blockBad = (mtd->block_isbad)(mtd, addr);
  204. return YAFFS_FAIL;
  205. }
  206. /* Check for a blank/erased chunk.
  207. */
  208. if (yaffs_CheckFF((__u8 *)&pt1, 8)) {
  209. /* when blank, upper layers want eccResult to be <= NO_ERROR */
  210. return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK);
  211. }
  212. #ifndef CONFIG_YAFFS_9BYTE_TAGS
  213. /* Read deleted status (bit) then return it to it's non-deleted
  214. * state before performing tags mini-ECC check. pt1.deleted is
  215. * inverted.
  216. */
  217. deleted = !pt1.deleted;
  218. pt1.deleted = 1;
  219. #else
  220. deleted = (yaffs_CountBits(((__u8 *)&pt1)[8]) < 7);
  221. #endif
  222. /* Check the packed tags mini-ECC and correct if necessary/possible.
  223. */
  224. retval = yaffs_CheckECCOnTags((yaffs_Tags *)&pt1);
  225. switch (retval) {
  226. case 0:
  227. /* no tags error, use MTD result */
  228. break;
  229. case 1:
  230. /* recovered tags-ECC error */
  231. dev->tagsEccFixed++;
  232. if (eccres == YAFFS_ECC_RESULT_NO_ERROR)
  233. eccres = YAFFS_ECC_RESULT_FIXED;
  234. break;
  235. default:
  236. /* unrecovered tags-ECC error */
  237. dev->tagsEccUnfixed++;
  238. return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL);
  239. }
  240. /* Unpack the tags to extended form and set ECC result.
  241. * [set shouldBeFF just to keep yaffs_UnpackTags1 happy]
  242. */
  243. pt1.shouldBeFF = 0xFFFFFFFF;
  244. yaffs_UnpackTags1(etags, &pt1);
  245. etags->eccResult = eccres;
  246. /* Set deleted state */
  247. etags->chunkDeleted = deleted;
  248. return YAFFS_OK;
  249. }
  250. /* Mark a block bad.
  251. *
  252. * This is a persistant state.
  253. * Use of this function should be rare.
  254. *
  255. * Returns YAFFS_OK or YAFFS_FAIL.
  256. */
  257. int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
  258. {
  259. struct mtd_info * mtd = dev->genericDevice;
  260. int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk;
  261. int retval;
  262. yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad\n", blockNo);
  263. retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo);
  264. return (retval) ? YAFFS_FAIL : YAFFS_OK;
  265. }
  266. /* Check any MTD prerequists.
  267. *
  268. * Returns YAFFS_OK or YAFFS_FAIL.
  269. */
  270. static int nandmtd1_TestPrerequists(struct mtd_info * mtd)
  271. {
  272. /* 2.6.18 has mtd->ecclayout->oobavail */
  273. /* 2.6.21 has mtd->ecclayout->oobavail and mtd->oobavail */
  274. int oobavail = mtd->ecclayout->oobavail;
  275. if (oobavail < YTAG1_SIZE) {
  276. yaffs_trace(YAFFS_TRACE_ERROR,
  277. "mtd device has only %d bytes for tags, need %d\n",
  278. oobavail, YTAG1_SIZE);
  279. return YAFFS_FAIL;
  280. }
  281. return YAFFS_OK;
  282. }
  283. /* Query for the current state of a specific block.
  284. *
  285. * Examine the tags of the first chunk of the block and return the state:
  286. * - YAFFS_BLOCK_STATE_DEAD, the block is marked bad
  287. * - YAFFS_BLOCK_STATE_NEEDS_SCANNING, the block is in use
  288. * - YAFFS_BLOCK_STATE_EMPTY, the block is clean
  289. *
  290. * Always returns YAFFS_OK.
  291. */
  292. int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
  293. yaffs_BlockState * pState, int *pSequenceNumber)
  294. {
  295. struct mtd_info * mtd = dev->genericDevice;
  296. int chunkNo = blockNo * dev->nChunksPerBlock;
  297. loff_t addr = (loff_t)chunkNo * dev->nDataBytesPerChunk;
  298. yaffs_ExtendedTags etags;
  299. int state = YAFFS_BLOCK_STATE_DEAD;
  300. int seqnum = 0;
  301. int retval;
  302. /* We don't yet have a good place to test for MTD config prerequists.
  303. * Do it here as we are called during the initial scan.
  304. */
  305. if (nandmtd1_TestPrerequists(mtd) != YAFFS_OK) {
  306. return YAFFS_FAIL;
  307. }
  308. retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags);
  309. etags.blockBad = (mtd->block_isbad)(mtd, addr);
  310. if (etags.blockBad) {
  311. yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
  312. "block %d is marked bad\n", blockNo);
  313. state = YAFFS_BLOCK_STATE_DEAD;
  314. }
  315. else if (etags.eccResult != YAFFS_ECC_RESULT_NO_ERROR) {
  316. /* bad tags, need to look more closely */
  317. state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
  318. }
  319. else if (etags.chunkUsed) {
  320. state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
  321. seqnum = etags.sequenceNumber;
  322. }
  323. else {
  324. state = YAFFS_BLOCK_STATE_EMPTY;
  325. }
  326. *pState = state;
  327. *pSequenceNumber = seqnum;
  328. /* query always succeeds */
  329. return YAFFS_OK;
  330. }
  331. #endif /*KERNEL_VERSION*/