|
134
|
1 /* |
|
|
2 * YAFFS: Yet another FFS. A NAND-flash specific file system. |
|
|
3 * |
|
|
4 * Copyright (C) 2002 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 /* mtd interface for YAFFS2 */ |
|
|
15 |
|
|
16 const char *yaffs_mtdif2_c_version = |
|
172
|
17 "$Id: yaffs_mtdif2.c,v 1.2 2007-03-07 08:05:58 colin Exp $"; |
|
134
|
18 |
|
|
19 #include "yportenv.h" |
|
|
20 |
|
|
21 |
|
|
22 #include "yaffs_mtdif2.h" |
|
|
23 |
|
|
24 #include "linux/mtd/mtd.h" |
|
|
25 #include "linux/types.h" |
|
|
26 #include "linux/time.h" |
|
|
27 |
|
|
28 #include "yaffs_packedtags2.h" |
|
|
29 |
|
|
30 |
|
|
31 void nandmtd2_pt2buf(yaffs_Device *dev, yaffs_PackedTags2 *pt, int is_raw) |
|
|
32 { |
|
|
33 struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); |
|
|
34 __u8 *ptab = (__u8 *)pt; /* packed tags as bytes */ |
|
|
35 |
|
|
36 int i, j = 0, k, n; |
|
|
37 |
|
|
38 /* Pack buffer with 0xff */ |
|
|
39 for (i = 0; i < mtd->oobsize; i++) |
|
|
40 dev->spareBuffer[i] = 0xff; |
|
|
41 |
|
|
42 if(!is_raw){ |
|
|
43 memcpy(dev->spareBuffer,pt,sizeof(yaffs_PackedTags2)); |
|
|
44 } else { |
|
|
45 j = 0; |
|
|
46 k = mtd->oobinfo.oobfree[j][0]; |
|
|
47 n = mtd->oobinfo.oobfree[j][1]; |
|
|
48 |
|
|
49 if (n == 0) { |
|
|
50 T(YAFFS_TRACE_ERROR, (TSTR("No OOB space for tags" TENDSTR))); |
|
|
51 YBUG(); |
|
|
52 } |
|
|
53 |
|
|
54 for (i = 0; i < sizeof(yaffs_PackedTags2); i++) { |
|
|
55 if (n == 0) { |
|
|
56 j++; |
|
|
57 k = mtd->oobinfo.oobfree[j][0]; |
|
|
58 n = mtd->oobinfo.oobfree[j][1]; |
|
|
59 if (n == 0) { |
|
|
60 T(YAFFS_TRACE_ERROR, (TSTR("No OOB space for tags" TENDSTR))); |
|
|
61 YBUG(); |
|
|
62 } |
|
|
63 } |
|
|
64 dev->spareBuffer[k] = ptab[i]; |
|
|
65 k++; |
|
|
66 n--; |
|
|
67 } |
|
|
68 } |
|
|
69 |
|
|
70 } |
|
|
71 |
|
|
72 void nandmtd2_buf2pt(yaffs_Device *dev, yaffs_PackedTags2 *pt, int is_raw) |
|
|
73 { |
|
|
74 struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); |
|
|
75 int i, j = 0, k, n; |
|
|
76 __u8 *ptab = (__u8 *)pt; /* packed tags as bytes */ |
|
|
77 |
|
|
78 |
|
|
79 if (!is_raw) { |
|
|
80 |
|
|
81 memcpy(pt,dev->spareBuffer,sizeof(yaffs_PackedTags2)); |
|
|
82 } else { |
|
|
83 j = 0; |
|
|
84 k = mtd->oobinfo.oobfree[j][0]; |
|
|
85 n = mtd->oobinfo.oobfree[j][1]; |
|
|
86 |
|
|
87 if (n == 0) { |
|
|
88 T(YAFFS_TRACE_ERROR, (TSTR("No space in OOB for tags" TENDSTR))); |
|
|
89 YBUG(); |
|
|
90 } |
|
|
91 |
|
|
92 for (i = 0; i < sizeof(yaffs_PackedTags2); i++) { |
|
|
93 if (n == 0) { |
|
|
94 j++; |
|
|
95 k = mtd->oobinfo.oobfree[j][0]; |
|
|
96 n = mtd->oobinfo.oobfree[j][1]; |
|
|
97 if (n == 0) { |
|
|
98 T(YAFFS_TRACE_ERROR, (TSTR("No space in OOB for tags" TENDSTR))); |
|
|
99 YBUG(); |
|
|
100 } |
|
|
101 } |
|
|
102 ptab[i] = dev->spareBuffer[k]; |
|
|
103 k++; |
|
|
104 n--; |
|
|
105 } |
|
|
106 } |
|
|
107 |
|
|
108 } |
|
|
109 |
|
|
110 int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND, |
|
|
111 const __u8 * data, |
|
|
112 const yaffs_ExtendedTags * tags) |
|
|
113 { |
|
|
114 struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); |
|
|
115 size_t dummy; |
|
|
116 int retval = 0; |
|
|
117 |
|
|
118 loff_t addr = ((loff_t) chunkInNAND) * dev->nBytesPerChunk; |
|
|
119 |
|
|
120 yaffs_PackedTags2 pt; |
|
|
121 |
|
|
122 T(YAFFS_TRACE_MTD, |
|
|
123 (TSTR |
|
|
124 ("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p" |
|
|
125 TENDSTR), chunkInNAND, data, tags)); |
|
|
126 |
|
|
127 if (tags) { |
|
|
128 yaffs_PackTags2(&pt, tags); |
|
|
129 } |
|
|
130 |
|
|
131 if (data && tags) { |
|
|
132 nandmtd2_pt2buf(dev, &pt, 0); |
|
|
133 retval = |
|
|
134 mtd->write_ecc(mtd, addr, dev->nBytesPerChunk, |
|
|
135 &dummy, data, dev->spareBuffer, |
|
|
136 NULL); |
|
|
137 |
|
|
138 } else { |
|
|
139 |
|
|
140 T(YAFFS_TRACE_ALWAYS, |
|
|
141 (TSTR |
|
|
142 ("Write chunk with null tags or data!" TENDSTR))); |
|
|
143 YBUG(); |
|
|
144 } |
|
|
145 |
|
|
146 if (retval == 0) |
|
|
147 return YAFFS_OK; |
|
|
148 else |
|
|
149 return YAFFS_FAIL; |
|
|
150 } |
|
|
151 |
|
|
152 int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND, |
|
|
153 __u8 * data, yaffs_ExtendedTags * tags) |
|
|
154 { |
|
|
155 struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); |
|
|
156 size_t dummy; |
|
|
157 int retval = 0; |
|
|
158 |
|
|
159 loff_t addr = ((loff_t) chunkInNAND) * dev->nBytesPerChunk; |
|
|
160 |
|
|
161 yaffs_PackedTags2 pt; |
|
|
162 |
|
|
163 T(YAFFS_TRACE_MTD, |
|
|
164 (TSTR |
|
|
165 ("nandmtd2_ReadChunkWithTagsToNAND chunk %d data %p tags %p" |
|
|
166 TENDSTR), chunkInNAND, data, tags)); |
|
|
167 |
|
|
168 if (0 && data && tags) { |
|
|
169 retval = |
|
|
170 mtd->read_ecc(mtd, addr, dev->nBytesPerChunk, |
|
|
171 &dummy, data, dev->spareBuffer, |
|
|
172 NULL); |
|
|
173 nandmtd2_buf2pt(dev, &pt, 0); |
|
|
174 } else { |
|
|
175 if (data) |
|
|
176 retval = |
|
|
177 mtd->read(mtd, addr, dev->nBytesPerChunk, &dummy, |
|
|
178 data); |
|
|
179 if (tags) { |
|
|
180 retval = |
|
|
181 mtd->read_oob(mtd, addr, mtd->oobsize, &dummy, |
|
|
182 dev->spareBuffer); |
|
|
183 nandmtd2_buf2pt(dev, &pt, 1); |
|
|
184 } |
|
|
185 } |
|
|
186 |
|
|
187 if (tags) |
|
|
188 yaffs_UnpackTags2(tags, &pt); |
|
|
189 |
|
|
190 if (retval == 0) |
|
|
191 return YAFFS_OK; |
|
|
192 else |
|
|
193 return YAFFS_FAIL; |
|
|
194 } |
|
|
195 |
|
|
196 int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo) |
|
|
197 { |
|
|
198 struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); |
|
|
199 int retval; |
|
|
200 T(YAFFS_TRACE_MTD, |
|
|
201 (TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), blockNo)); |
|
|
202 |
|
|
203 retval = |
|
|
204 mtd->block_markbad(mtd, |
|
|
205 blockNo * dev->nChunksPerBlock * |
|
|
206 dev->nBytesPerChunk); |
|
|
207 |
|
|
208 if (retval == 0) |
|
|
209 return YAFFS_OK; |
|
|
210 else |
|
|
211 return YAFFS_FAIL; |
|
|
212 |
|
|
213 } |
|
|
214 |
|
|
215 int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, |
|
|
216 yaffs_BlockState * state, int *sequenceNumber) |
|
|
217 { |
|
|
218 struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice); |
|
|
219 int retval; |
|
|
220 |
|
|
221 T(YAFFS_TRACE_MTD, |
|
|
222 (TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo)); |
|
|
223 retval = |
|
|
224 mtd->block_isbad(mtd, |
|
|
225 blockNo * dev->nChunksPerBlock * |
|
|
226 dev->nBytesPerChunk); |
|
|
227 |
|
|
228 if (retval) { |
|
|
229 T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR))); |
|
|
230 |
|
|
231 *state = YAFFS_BLOCK_STATE_DEAD; |
|
|
232 *sequenceNumber = 0; |
|
|
233 } else { |
|
|
234 yaffs_ExtendedTags t; |
|
|
235 nandmtd2_ReadChunkWithTagsFromNAND(dev, |
|
|
236 blockNo * |
|
|
237 dev->nChunksPerBlock, NULL, |
|
|
238 &t); |
|
|
239 |
|
|
240 if (t.chunkUsed) { |
|
|
241 *sequenceNumber = t.sequenceNumber; |
|
|
242 *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; |
|
|
243 } else { |
|
|
244 *sequenceNumber = 0; |
|
|
245 *state = YAFFS_BLOCK_STATE_EMPTY; |
|
|
246 } |
|
|
247 |
|
|
248 T(YAFFS_TRACE_MTD, |
|
|
249 (TSTR("block is OK seq %d state %d" TENDSTR), *sequenceNumber, |
|
|
250 *state)); |
|
|
251 } |
|
|
252 |
|
|
253 if (retval == 0) |
|
|
254 return YAFFS_OK; |
|
|
255 else |
|
|
256 return YAFFS_FAIL; |
|
|
257 } |
|
|
258 |