yaffs_mtdif2.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  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. /* mtd interface for YAFFS2 */
  14. const char *yaffs_mtdif2_c_version =
  15. "$Id: yaffs_mtdif2.c,v 1.17 2007/02/14 01:09:06 wookey Exp $";
  16. #include "yportenv.h"
  17. #include "yaffs_mtdif2.h"
  18. #include "linux/mtd/mtd.h"
  19. #include "linux/types.h"
  20. #include "linux/time.h"
  21. #include "yaffs_packedtags2.h"
  22. int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
  23. const __u8 * data,
  24. const yaffs_ExtendedTags * tags)
  25. {
  26. struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
  27. #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
  28. struct mtd_oob_ops ops;
  29. #else
  30. size_t dummy;
  31. #endif
  32. int retval = 0;
  33. loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
  34. yaffs_PackedTags2 pt;
  35. T(YAFFS_TRACE_MTD,
  36. (TSTR
  37. ("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"
  38. TENDSTR), chunkInNAND, data, tags));
  39. #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
  40. if (tags)
  41. yaffs_PackTags2(&pt, tags);
  42. else
  43. BUG(); /* both tags and data should always be present */
  44. if (data) {
  45. ops.mode = MTD_OOB_AUTO;
  46. ops.ooblen = sizeof(pt);
  47. ops.len = dev->nDataBytesPerChunk;
  48. ops.ooboffs = 0;
  49. ops.datbuf = (__u8 *)data;
  50. ops.oobbuf = (void *)&pt;
  51. retval = mtd->write_oob(mtd, addr, &ops);
  52. } else
  53. BUG(); /* both tags and data should always be present */
  54. #else
  55. if (tags) {
  56. yaffs_PackTags2(&pt, tags);
  57. }
  58. if (data && tags) {
  59. if (dev->useNANDECC)
  60. retval =
  61. mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
  62. &dummy, data, (__u8 *) & pt, NULL);
  63. else
  64. retval =
  65. mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
  66. &dummy, data, (__u8 *) & pt, NULL);
  67. } else {
  68. if (data)
  69. retval =
  70. mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy,
  71. data);
  72. if (tags)
  73. retval =
  74. mtd->write_oob(mtd, addr, mtd->oobsize, &dummy,
  75. (__u8 *) & pt);
  76. }
  77. #endif
  78. if (retval == 0)
  79. return YAFFS_OK;
  80. else
  81. return YAFFS_FAIL;
  82. }
  83. int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
  84. __u8 * data, yaffs_ExtendedTags * tags)
  85. {
  86. struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
  87. #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
  88. struct mtd_oob_ops ops;
  89. #endif
  90. size_t dummy;
  91. int retval = 0;
  92. loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
  93. yaffs_PackedTags2 pt;
  94. T(YAFFS_TRACE_MTD,
  95. (TSTR
  96. ("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p"
  97. TENDSTR), chunkInNAND, data, tags));
  98. #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
  99. if (data && !tags)
  100. retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk,
  101. &dummy, data);
  102. else if (tags) {
  103. ops.mode = MTD_OOB_AUTO;
  104. ops.ooblen = sizeof(pt);
  105. ops.len = data ? dev->nDataBytesPerChunk : sizeof(pt);
  106. ops.ooboffs = 0;
  107. ops.datbuf = data;
  108. ops.oobbuf = dev->spareBuffer;
  109. retval = mtd->read_oob(mtd, addr, &ops);
  110. }
  111. #else
  112. if (data && tags) {
  113. if (dev->useNANDECC) {
  114. retval =
  115. mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
  116. &dummy, data, dev->spareBuffer,
  117. NULL);
  118. } else {
  119. retval =
  120. mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
  121. &dummy, data, dev->spareBuffer,
  122. NULL);
  123. }
  124. } else {
  125. if (data)
  126. retval =
  127. mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
  128. data);
  129. if (tags)
  130. retval =
  131. mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
  132. dev->spareBuffer);
  133. }
  134. #endif
  135. memcpy(&pt, dev->spareBuffer, sizeof(pt));
  136. if (tags)
  137. yaffs_UnpackTags2(tags, &pt);
  138. if(tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR)
  139. tags->eccResult = YAFFS_ECC_RESULT_UNFIXED;
  140. if (retval == 0)
  141. return YAFFS_OK;
  142. else
  143. return YAFFS_FAIL;
  144. }
  145. int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
  146. {
  147. struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
  148. int retval;
  149. T(YAFFS_TRACE_MTD,
  150. (TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), blockNo));
  151. retval =
  152. mtd->block_markbad(mtd,
  153. blockNo * dev->nChunksPerBlock *
  154. dev->nDataBytesPerChunk);
  155. if (retval == 0)
  156. return YAFFS_OK;
  157. else
  158. return YAFFS_FAIL;
  159. }
  160. int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
  161. yaffs_BlockState * state, int *sequenceNumber)
  162. {
  163. struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
  164. int retval;
  165. T(YAFFS_TRACE_MTD,
  166. (TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo));
  167. retval =
  168. mtd->block_isbad(mtd,
  169. blockNo * dev->nChunksPerBlock *
  170. dev->nDataBytesPerChunk);
  171. if (retval) {
  172. T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR)));
  173. *state = YAFFS_BLOCK_STATE_DEAD;
  174. *sequenceNumber = 0;
  175. } else {
  176. yaffs_ExtendedTags t;
  177. nandmtd2_ReadChunkWithTagsFromNAND(dev,
  178. blockNo *
  179. dev->nChunksPerBlock, NULL,
  180. &t);
  181. if (t.chunkUsed) {
  182. *sequenceNumber = t.sequenceNumber;
  183. *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
  184. } else {
  185. *sequenceNumber = 0;
  186. *state = YAFFS_BLOCK_STATE_EMPTY;
  187. }
  188. }
  189. T(YAFFS_TRACE_MTD,
  190. (TSTR("block is bad seq %d state %d" TENDSTR), *sequenceNumber,
  191. *state));
  192. if (retval == 0)
  193. return YAFFS_OK;
  194. else
  195. return YAFFS_FAIL;
  196. }