]>
Commit | Line | Data |
---|---|---|
753ac610 CM |
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 | } |