yaffs_nandif.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. /*
  2. * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
  3. *
  4. * Copyright (C) 2002-2011 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 "yportenv.h"
  14. #include "yaffs_guts.h"
  15. #include "yaffs_nandif.h"
  16. #include "yaffs_packedtags2.h"
  17. #include "yramsim.h"
  18. #include "yaffs_trace.h"
  19. #include "yaffsfs.h"
  20. /* NB For use with inband tags....
  21. * We assume that the data buffer is of size totalBytersPerChunk so that
  22. * we can also use it to load the tags.
  23. */
  24. int ynandif_WriteChunkWithTagsToNAND(struct yaffs_dev *dev, int nand_chunk,
  25. const u8 *data,
  26. const struct yaffs_ext_tags *tags)
  27. {
  28. int retval = 0;
  29. struct yaffs_packed_tags2 pt;
  30. void *spare;
  31. unsigned spareSize = 0;
  32. struct ynandif_Geometry *geometry = (struct ynandif_Geometry *)(dev->driver_context);
  33. yaffs_trace(YAFFS_TRACE_MTD,
  34. "nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p",
  35. nand_chunk, data, tags);
  36. /* For yaffs2 writing there must be both data and tags.
  37. * If we're using inband tags, then the tags are stuffed into
  38. * the end of the data buffer.
  39. */
  40. if (dev->param.inband_tags) {
  41. struct yaffs_packed_tags2_tags_only *pt2tp;
  42. pt2tp = (struct yaffs_packed_tags2_tags_only *)
  43. (data + dev->data_bytes_per_chunk);
  44. yaffs_pack_tags2_tags_only(pt2tp, tags);
  45. spare = NULL;
  46. spareSize = 0;
  47. } else {
  48. yaffs_pack_tags2(&pt, tags, !dev->param.no_tags_ecc);
  49. spare = &pt;
  50. spareSize = sizeof(struct yaffs_packed_tags2);
  51. }
  52. retval = geometry->writeChunk(dev, nand_chunk,
  53. data, dev->param.total_bytes_per_chunk,
  54. spare, spareSize);
  55. return retval;
  56. }
  57. int ynandif_ReadChunkWithTagsFromNAND(struct yaffs_dev *dev, int nand_chunk,
  58. u8 *data, struct yaffs_ext_tags *tags)
  59. {
  60. struct yaffs_packed_tags2 pt;
  61. int localData = 0;
  62. void *spare = NULL;
  63. unsigned spareSize;
  64. int retval = 0;
  65. int eccStatus; /* 0 = ok, 1 = fixed, -1 = unfixed */
  66. struct ynandif_Geometry *geometry = (struct ynandif_Geometry *)(dev->driver_context);
  67. yaffs_trace(YAFFS_TRACE_MTD,
  68. "nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p",
  69. nand_chunk, data, tags);
  70. if (!tags) {
  71. spare = NULL;
  72. spareSize = 0;
  73. } else if (dev->param.inband_tags) {
  74. if (!data) {
  75. localData = 1;
  76. data = yaffs_get_temp_buffer(dev);
  77. }
  78. spare = NULL;
  79. spareSize = 0;
  80. } else {
  81. spare = &pt;
  82. spareSize = sizeof(struct yaffs_packed_tags2);
  83. }
  84. retval = geometry->readChunk(dev, nand_chunk,
  85. data,
  86. data ? dev->param.total_bytes_per_chunk : 0,
  87. spare, spareSize,
  88. &eccStatus);
  89. if (dev->param.inband_tags) {
  90. if (tags) {
  91. struct yaffs_packed_tags2_tags_only *pt2tp;
  92. pt2tp = (struct yaffs_packed_tags2_tags_only *)
  93. &data[dev->data_bytes_per_chunk];
  94. yaffs_unpack_tags2_tags_only(tags, pt2tp);
  95. }
  96. } else {
  97. if (tags)
  98. yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc);
  99. }
  100. if (tags && tags->chunk_used) {
  101. if (eccStatus < 0 ||
  102. tags->ecc_result == YAFFS_ECC_RESULT_UNFIXED)
  103. tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED;
  104. else if (eccStatus > 0 ||
  105. tags->ecc_result == YAFFS_ECC_RESULT_FIXED)
  106. tags->ecc_result = YAFFS_ECC_RESULT_FIXED;
  107. else
  108. tags->ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
  109. }
  110. if (localData)
  111. yaffs_release_temp_buffer(dev, data);
  112. return retval;
  113. }
  114. int ynandif_MarkNANDBlockBad(struct yaffs_dev *dev, int blockId)
  115. {
  116. struct ynandif_Geometry *geometry = (struct ynandif_Geometry *)(dev->driver_context);
  117. return geometry->markBlockBad(dev, blockId);
  118. }
  119. int ynandif_EraseBlockInNAND(struct yaffs_dev *dev, int blockId)
  120. {
  121. struct ynandif_Geometry *geometry = (struct ynandif_Geometry *)(dev->driver_context);
  122. return geometry->eraseBlock(dev, blockId);
  123. }
  124. static int ynandif_IsBlockOk(struct yaffs_dev *dev, int blockId)
  125. {
  126. struct ynandif_Geometry *geometry = (struct ynandif_Geometry *)(dev->driver_context);
  127. return geometry->checkBlockOk(dev, blockId);
  128. }
  129. int ynandif_QueryNANDBlock(struct yaffs_dev *dev, int blockId,
  130. enum yaffs_block_state *state, u32 *seq_number)
  131. {
  132. unsigned chunkNo;
  133. struct yaffs_ext_tags tags;
  134. *seq_number = 0;
  135. chunkNo = blockId * dev->param.chunks_per_block;
  136. if (!ynandif_IsBlockOk(dev, blockId)) {
  137. *state = YAFFS_BLOCK_STATE_DEAD;
  138. } else {
  139. ynandif_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &tags);
  140. if (!tags.chunk_used) {
  141. *state = YAFFS_BLOCK_STATE_EMPTY;
  142. } else {
  143. *state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
  144. *seq_number = tags.seq_number;
  145. }
  146. }
  147. return YAFFS_OK;
  148. }
  149. int ynandif_InitialiseNAND(struct yaffs_dev *dev)
  150. {
  151. struct ynandif_Geometry *geometry = (struct ynandif_Geometry *)(dev->driver_context);
  152. geometry->initialise(dev);
  153. return YAFFS_OK;
  154. }
  155. int ynandif_Deinitialise_flash_fn(struct yaffs_dev *dev)
  156. {
  157. struct ynandif_Geometry *geometry = (struct ynandif_Geometry *)(dev->driver_context);
  158. geometry->deinitialise(dev);
  159. return YAFFS_OK;
  160. }
  161. struct yaffs_dev *
  162. yaffs_add_dev_from_geometry(const YCHAR *name,
  163. const struct ynandif_Geometry *geometry)
  164. {
  165. YCHAR *clonedName = malloc(sizeof(YCHAR) *
  166. (strnlen(name, YAFFS_MAX_NAME_LENGTH)+1));
  167. struct yaffs_dev *dev = malloc(sizeof(struct yaffs_dev));
  168. struct yaffs_param *param;
  169. if (dev && clonedName) {
  170. memset(dev, 0, sizeof(struct yaffs_dev));
  171. strcpy(clonedName, name);
  172. param = &dev->param;
  173. param->name = clonedName;
  174. param->write_chunk_tags_fn = ynandif_WriteChunkWithTagsToNAND;
  175. param->read_chunk_tags_fn = ynandif_ReadChunkWithTagsFromNAND;
  176. param->erase_fn = ynandif_EraseBlockInNAND;
  177. param->initialise_flash_fn = ynandif_InitialiseNAND;
  178. param->query_block_fn = ynandif_QueryNANDBlock;
  179. param->bad_block_fn = ynandif_MarkNANDBlockBad;
  180. param->n_caches = 20;
  181. param->start_block = geometry->start_block;
  182. param->end_block = geometry->end_block;
  183. param->total_bytes_per_chunk = geometry->dataSize;
  184. param->spare_bytes_per_chunk = geometry->spareSize;
  185. param->inband_tags = geometry->inband_tags;
  186. param->chunks_per_block = geometry->pagesPerBlock;
  187. param->use_nand_ecc = geometry->hasECC;
  188. param->is_yaffs2 = geometry->useYaffs2;
  189. param->n_reserved_blocks = 5;
  190. dev->driver_context = (void *)geometry;
  191. yaffs_add_device(dev);
  192. return dev;
  193. }
  194. free(dev);
  195. free(clonedName);
  196. return NULL;
  197. }