502-yaffs-fix-compat-tags-handling.patch 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. Subject: yaffs: fix compat tags handling
  2. Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
  3. ---
  4. --- a/fs/yaffs2/yaffs_tagscompat.c
  5. +++ b/fs/yaffs2/yaffs_tagscompat.c
  6. @@ -17,7 +17,9 @@
  7. #include "yaffs_getblockinfo.h"
  8. #include "yaffs_trace.h"
  9. +#if 0
  10. static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk);
  11. +#endif
  12. /********** Tags ECC calculations *********/
  13. @@ -71,6 +73,7 @@ int yaffs_check_tags_ecc(struct yaffs_ta
  14. return 0;
  15. }
  16. +#if 0
  17. /********** Tags **********/
  18. static void yaffs_load_tags_to_spare(struct yaffs_spare *spare_ptr,
  19. @@ -379,3 +382,214 @@ void yaffs_tags_compat_install(struct ya
  20. if(!dev->tagger.mark_bad_fn)
  21. dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad;
  22. }
  23. +#else
  24. +
  25. +#include "yaffs_packedtags1.h"
  26. +
  27. +static int yaffs_tags_compat_write(struct yaffs_dev *dev,
  28. + int nand_chunk,
  29. + const u8 *data,
  30. + const struct yaffs_ext_tags *tags)
  31. +{
  32. + struct yaffs_packed_tags1 pt1;
  33. + u8 tag_buf[9];
  34. + int retval;
  35. +
  36. + /* we assume that yaffs_packed_tags1 and yaffs_tags are compatible */
  37. + compile_time_assertion(sizeof(struct yaffs_packed_tags1) == 12);
  38. + compile_time_assertion(sizeof(struct yaffs_tags) == 8);
  39. +
  40. + yaffs_pack_tags1(&pt1, tags);
  41. + yaffs_calc_tags_ecc((struct yaffs_tags *)&pt1);
  42. +
  43. + /* When deleting a chunk, the upper layer provides only skeletal
  44. + * tags, one with is_deleted set. However, we need to update the
  45. + * tags, not erase them completely. So we use the NAND write property
  46. + * that only zeroed-bits stick and set tag bytes to all-ones and
  47. + * zero just the (not) deleted bit.
  48. + */
  49. + if (!dev->param.tags_9bytes) {
  50. + if (tags->is_deleted) {
  51. + memset(&pt1, 0xff, 8);
  52. + /* clear delete status bit to indicate deleted */
  53. + pt1.deleted = 0;
  54. + }
  55. + memcpy(tag_buf, &pt1, 8);
  56. + } else {
  57. + if (tags->is_deleted) {
  58. + memset(tag_buf, 0xff, 8);
  59. + tag_buf[8] = 0;
  60. + } else {
  61. + memcpy(tag_buf, &pt1, 8);
  62. + tag_buf[8] = 0xff;
  63. + }
  64. + }
  65. +
  66. + retval = dev->drv.drv_write_chunk_fn(dev, nand_chunk,
  67. + data,
  68. + (data) ? dev->data_bytes_per_chunk : 0,
  69. + tag_buf,
  70. + (dev->param.tags_9bytes) ? 9 : 8);
  71. +
  72. + return retval;
  73. +}
  74. +
  75. +/* Return with empty extended tags but add ecc_result.
  76. + */
  77. +static int return_empty_tags(struct yaffs_ext_tags *tags,
  78. + enum yaffs_ecc_result ecc_result,
  79. + int retval)
  80. +{
  81. + if (tags) {
  82. + memset(tags, 0, sizeof(*tags));
  83. + tags->ecc_result = ecc_result;
  84. + }
  85. +
  86. + return retval;
  87. +}
  88. +
  89. +static int yaffs_tags_compat_read(struct yaffs_dev *dev,
  90. + int nand_chunk,
  91. + u8 *data,
  92. + struct yaffs_ext_tags *tags)
  93. +{
  94. + struct yaffs_packed_tags1 pt1;
  95. + enum yaffs_ecc_result ecc_result;
  96. + int retval;
  97. + int deleted;
  98. + u8 tag_buf[9];
  99. +
  100. + retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk,
  101. + data, dev->param.total_bytes_per_chunk,
  102. + tag_buf,
  103. + (dev->param.tags_9bytes) ? 9 : 8,
  104. + &ecc_result);
  105. +
  106. + switch (ecc_result) {
  107. + case YAFFS_ECC_RESULT_NO_ERROR:
  108. + case YAFFS_ECC_RESULT_FIXED:
  109. + break;
  110. +
  111. + case YAFFS_ECC_RESULT_UNFIXED:
  112. + default:
  113. + return_empty_tags(tags, YAFFS_ECC_RESULT_UNFIXED, 0);
  114. + tags->block_bad = dev->drv.drv_check_bad_fn(dev, nand_chunk);
  115. + return YAFFS_FAIL;
  116. + }
  117. +
  118. + /* Check for a blank/erased chunk. */
  119. + if (yaffs_check_ff(tag_buf, 8)) {
  120. + /* when blank, upper layers want ecc_result to be <= NO_ERROR */
  121. + return return_empty_tags(tags, YAFFS_ECC_RESULT_NO_ERROR,
  122. + YAFFS_OK);
  123. + }
  124. +
  125. + memcpy(&pt1, tag_buf, 8);
  126. +
  127. + if (!dev->param.tags_9bytes) {
  128. + /* Read deleted status (bit) then return it to it's non-deleted
  129. + * state before performing tags mini-ECC check. pt1.deleted is
  130. + * inverted.
  131. + */
  132. + deleted = !pt1.deleted;
  133. + pt1.deleted = 1;
  134. + } else {
  135. + deleted = (hweight8(tag_buf[8]) < 7) ? 1 : 0;
  136. + }
  137. +
  138. + /* Check the packed tags mini-ECC and correct if necessary/possible. */
  139. + retval = yaffs_check_tags_ecc((struct yaffs_tags *)&pt1);
  140. + switch (retval) {
  141. + case 0:
  142. + /* no tags error, use MTD result */
  143. + break;
  144. + case 1:
  145. + /* recovered tags-ECC error */
  146. + dev->n_tags_ecc_fixed++;
  147. + if (ecc_result == YAFFS_ECC_RESULT_NO_ERROR)
  148. + ecc_result = YAFFS_ECC_RESULT_FIXED;
  149. + break;
  150. + default:
  151. + /* unrecovered tags-ECC error */
  152. + dev->n_tags_ecc_unfixed++;
  153. + return return_empty_tags(tags, YAFFS_ECC_RESULT_UNFIXED,
  154. + YAFFS_FAIL);
  155. + }
  156. +
  157. + /* Unpack the tags to extended form and set ECC result.
  158. + * [set should_be_ff just to keep yaffs_unpack_tags1 happy]
  159. + */
  160. + pt1.should_be_ff = 0xffffffff;
  161. + yaffs_unpack_tags1(tags, &pt1);
  162. + tags->ecc_result = ecc_result;
  163. +
  164. + /* Set deleted state */
  165. + tags->is_deleted = deleted;
  166. + return YAFFS_OK;
  167. +}
  168. +
  169. +static int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int block_no)
  170. +{
  171. + return dev->drv.drv_mark_bad_fn(dev, block_no);
  172. +}
  173. +
  174. +static int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
  175. + int block_no,
  176. + enum yaffs_block_state *state,
  177. + u32 *seq_number)
  178. +{
  179. + struct yaffs_ext_tags tags;
  180. + int retval;
  181. +
  182. + yaffs_trace(YAFFS_TRACE_MTD, "%s %d", __func__, block_no);
  183. +
  184. + *seq_number = 0;
  185. +
  186. + retval = dev->drv.drv_check_bad_fn(dev, block_no);
  187. + if (retval == YAFFS_FAIL) {
  188. + *state = YAFFS_BLOCK_STATE_DEAD;
  189. + goto out;
  190. + }
  191. +
  192. + yaffs_tags_compat_read(dev, block_no * dev->param.chunks_per_block,
  193. + NULL, &tags);
  194. +
  195. + if (tags.ecc_result != YAFFS_ECC_RESULT_NO_ERROR) {
  196. + yaffs_trace(YAFFS_TRACE_MTD, "block %d is marked bad",
  197. + block_no);
  198. + *state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
  199. + } else if (tags.chunk_used) {
  200. + *seq_number = tags.seq_number;
  201. + *state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
  202. + } else {
  203. + *state = YAFFS_BLOCK_STATE_EMPTY;
  204. + }
  205. +
  206. + retval = YAFFS_OK;
  207. +
  208. +out:
  209. + yaffs_trace(YAFFS_TRACE_MTD,
  210. + "block query returns seq %u state %d",
  211. + *seq_number, *state);
  212. +
  213. + return retval;
  214. +}
  215. +
  216. +void yaffs_tags_compat_install(struct yaffs_dev *dev)
  217. +{
  218. + if (dev->param.is_yaffs2)
  219. + return;
  220. +
  221. + if (!dev->tagger.write_chunk_tags_fn)
  222. + dev->tagger.write_chunk_tags_fn = yaffs_tags_compat_write;
  223. +
  224. + if (!dev->tagger.read_chunk_tags_fn)
  225. + dev->tagger.read_chunk_tags_fn = yaffs_tags_compat_read;
  226. +
  227. + if (!dev->tagger.query_block_fn)
  228. + dev->tagger.query_block_fn = yaffs_tags_compat_query_block;
  229. +
  230. + if (!dev->tagger.mark_bad_fn)
  231. + dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad;
  232. +}
  233. +#endif