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