yaffs_nandif.c 6.3 KB

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