• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * YAFFS: Yet another FFS. A NAND-flash specific file system.
3  * yaffs_mtdif.c  NAND mtd wrapper functions.
4  *
5  * Copyright (C) 2002 Aleph One Ltd.
6  *   for Toby Churchill Ltd and Brightstar Engineering
7  *
8  * Created by Charles Manning <charles@aleph1.co.uk>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as
12  * published by the Free Software Foundation.
13  *
14  */
15 
16 /* mtd interface for YAFFS2 */
17 
18 const char *yaffs_mtdif2_c_version =
19     "$Id: yaffs_mtdif2.c,v 1.14 2006/10/03 10:13:03 charles Exp $";
20 
21 #include "yportenv.h"
22 
23 
24 #include "yaffs_mtdif2.h"
25 
26 #include "linux/mtd/mtd.h"
27 #include "linux/types.h"
28 #include "linux/time.h"
29 
30 #include "yaffs_packedtags2.h"
31 
32 
nandmtd2_pt2buf(yaffs_Device * dev,yaffs_PackedTags2 * pt,int is_raw)33 void nandmtd2_pt2buf(yaffs_Device *dev, yaffs_PackedTags2 *pt, int is_raw)
34 {
35 	struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
36 	__u8 *ptab = (__u8 *)pt; /* packed tags as bytes */
37 
38 	int	i, j = 0, k, n;
39 #ifdef CONFIG_YAFFS_DOES_ECC
40 	size_t packed_size = sizeof(yaffs_PackedTags2);
41 #else
42 	size_t packed_size = sizeof(yaffs_PackedTags2TagsPart);
43 #endif
44 
45 	/* Pack buffer with 0xff */
46 	for (i = 0; i < mtd->oobsize; i++)
47 		dev->spareBuffer[i] = 0xff;
48 
49 	if(!is_raw){
50 		memcpy(dev->spareBuffer,pt,packed_size);
51 	} else {
52 		j = 0;
53 		k = mtd->ecclayout->oobfree[j].offset;
54 		n = mtd->ecclayout->oobfree[j].length;
55 
56 		//printk("nandmtd2_pt2buf: writing %d bytes of extra data into %d\n", packed_size, mtd->oobsize);
57 
58 		if (n == 0) {
59 			T(YAFFS_TRACE_ERROR, (TSTR("No OOB space for tags" TENDSTR)));
60 			YBUG();
61 		}
62 
63 		for (i = 0; i < packed_size; i++) {
64 			if (n == 0) {
65 				j++;
66 				k = mtd->ecclayout->oobfree[j].offset;
67 				n = mtd->ecclayout->oobfree[j].length;
68 				if (n == 0 || j >= (sizeof(mtd->ecclayout->oobfree) / sizeof(mtd->ecclayout->oobfree[0]))) {
69 					T(YAFFS_TRACE_ERROR, (TSTR("No OOB space for tags" TENDSTR)));
70 					YBUG();
71 				}
72 			}
73 			dev->spareBuffer[k] = ptab[i];
74 			k++;
75 			n--;
76 		}
77 	}
78 
79 }
80 
nandmtd2_buf2pt(yaffs_Device * dev,yaffs_PackedTags2 * pt,int is_raw)81 void nandmtd2_buf2pt(yaffs_Device *dev, yaffs_PackedTags2 *pt, int is_raw)
82 {
83 	struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
84 	int	i, j = 0, k, n;
85 	__u8 *ptab = (__u8 *)pt; /* packed tags as bytes */
86 	size_t packed_size = dev->useNANDECC ? sizeof(yaffs_PackedTags2TagsPart) : sizeof(yaffs_PackedTags2);
87 
88 	if (!is_raw) {
89 
90 		memcpy(pt,dev->spareBuffer,packed_size);
91 	} else {
92 		j = 0;
93 		k = mtd->ecclayout->oobfree[j].offset;
94 		n = mtd->ecclayout->oobfree[j].length;
95 
96 		if (n == 0) {
97 			T(YAFFS_TRACE_ERROR, (TSTR("No space in OOB for tags" TENDSTR)));
98 			YBUG();
99 		}
100 
101 		for (i = 0; i < packed_size; i++) {
102 			if (n == 0) {
103 				j++;
104 				k = mtd->ecclayout->oobfree[j].offset;
105 				n = mtd->ecclayout->oobfree[j].length;
106 				if (n == 0 || j >= (sizeof(mtd->ecclayout->oobfree) / sizeof(mtd->ecclayout->oobfree[0]))) {
107 					T(YAFFS_TRACE_ERROR, (TSTR("No space in OOB for tags" TENDSTR)));
108 					YBUG();
109 				}
110 			}
111 			ptab[i] = dev->spareBuffer[k];
112 			k++;
113 			n--;
114 		}
115 	}
116 
117 }
118 
nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev,int chunkInNAND,const __u8 * data,const yaffs_ExtendedTags * tags)119 int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
120 				      const __u8 * data,
121 				      const yaffs_ExtendedTags * tags)
122 {
123 	struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
124 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
125 	struct mtd_oob_ops ops;
126 #else
127 	size_t dummy;
128 #endif
129 	int retval = 0;
130 
131 	loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
132 
133 	yaffs_PackedTags2 pt;
134 
135 	T(YAFFS_TRACE_MTD,
136 	  (TSTR
137 	   ("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"
138 	    TENDSTR), chunkInNAND, data, tags));
139 
140 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
141 	if (tags)
142 		yaffs_PackTags2(&pt, tags);
143 	else
144 		BUG(); /* both tags and data should always be present */
145 
146 	nandmtd2_pt2buf(dev, &pt, 1);
147 	if (data) {
148 		ops.mode = MTD_OOB_AUTO;
149 		ops.ooblen = mtd->oobsize;
150 		ops.len = dev->nDataBytesPerChunk;
151 		ops.ooboffs = 0;
152 		ops.datbuf = (__u8 *)data;
153 		ops.oobbuf = dev->spareBuffer;
154 		retval = mtd->write_oob(mtd, addr, &ops);
155 	} else
156 		BUG(); /* both tags and data should always be present */
157 #else
158 	if (tags) {
159 		yaffs_PackTags2(&pt, tags);
160 	}
161 
162 	if (tags) {
163 		nandmtd2_pt2buf(dev, &pt, 1);
164 		retval =
165 		    mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
166 				   &dummy, data, dev->spareBuffer, NULL);
167 	} else if (data) {
168 			retval =
169 			    mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy,
170 				       data);
171 	}
172 #endif
173 
174 	if (retval == 0)
175 		return YAFFS_OK;
176 	else
177 		return YAFFS_FAIL;
178 }
179 
nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev,int chunkInNAND,__u8 * data,yaffs_ExtendedTags * tags)180 int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
181 				       __u8 * data, yaffs_ExtendedTags * tags)
182 {
183 	struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
184 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
185 	struct mtd_oob_ops ops;
186 #endif
187 	size_t dummy;
188 	int retval = 0;
189 
190 	loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
191 
192 	yaffs_PackedTags2 pt;
193 
194 	T(YAFFS_TRACE_MTD,
195 	  (TSTR
196 	   ("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p"
197 	    TENDSTR), chunkInNAND, data, tags));
198 
199 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
200 	if (data && !tags)
201 		retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk,
202 				&dummy, data);
203 	else if (tags) {
204 		ops.mode = MTD_OOB_AUTO;
205 		ops.ooblen = mtd->oobsize;
206 		ops.len = data ? dev->nDataBytesPerChunk : mtd->oobsize;
207 		ops.ooboffs = 0;
208 		ops.datbuf = data;
209 		ops.oobbuf = dev->spareBuffer;
210 		retval = mtd->read_oob(mtd, addr, &ops);
211 		nandmtd2_buf2pt(dev, &pt, 1);
212 	}
213 #else
214 	if (data && tags) {
215 			retval =
216 			    mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
217 					  &dummy, data, dev->spareBuffer,
218 					  NULL);
219 		} else {
220 			retval =
221 			    mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
222 					  &dummy, data, dev->spareBuffer,
223 					  NULL);
224 		}
225 	} else {
226 		if (data)
227 			retval =
228 			    mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
229 				      data);
230 		if (tags) {
231 			retval =
232 			    mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
233 					  dev->spareBuffer);
234 			nandmtd2_buf2pt(dev, &pt, 1);
235 		}
236 	}
237 #endif
238 
239 	if (tags)
240 		yaffs_UnpackTags2(tags, &pt);
241 
242 	if(tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR)
243 		tags->eccResult = YAFFS_ECC_RESULT_UNFIXED;
244 
245 	if (retval == 0)
246 		return YAFFS_OK;
247 	else
248 		return YAFFS_FAIL;
249 }
250 
251 int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
252 {
253 	struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
254 	int retval;
255 	T(YAFFS_TRACE_MTD,
256 	  (TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), blockNo));
257 
258 	retval =
259 	    mtd->block_markbad(mtd,
260 			       blockNo * dev->nChunksPerBlock *
261 			       dev->nDataBytesPerChunk);
262 
263 	if (retval == 0)
264 		return YAFFS_OK;
265 	else
266 		return YAFFS_FAIL;
267 
268 }
269 
270 int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
271 			    yaffs_BlockState * state, int *sequenceNumber)
272 {
273 	struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
274 	int retval;
275 
276 	T(YAFFS_TRACE_MTD,
277 	  (TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo));
278 	retval =
279 	    mtd->block_isbad(mtd,
280 			     blockNo * dev->nChunksPerBlock *
281 			     dev->nDataBytesPerChunk);
282 
283 	if (retval) {
284 		T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR)));
285 
286 		*state = YAFFS_BLOCK_STATE_DEAD;
287 		*sequenceNumber = 0;
288 	} else {
289 		yaffs_ExtendedTags t;
290 		nandmtd2_ReadChunkWithTagsFromNAND(dev,
291 						   blockNo *
292 						   dev->nChunksPerBlock, NULL,
293 						   &t);
294 
295 		if (t.chunkUsed) {
296 			*sequenceNumber = t.sequenceNumber;
297 			*state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
298 		} else {
299 			*sequenceNumber = 0;
300 			*state = YAFFS_BLOCK_STATE_EMPTY;
301 		}
302 
303 		T(YAFFS_TRACE_MTD,
304 		  (TSTR("block is OK seq %d state %d" TENDSTR), *sequenceNumber,
305 		   *state));
306 	}
307 
308 	if (retval == 0)
309 		return YAFFS_OK;
310 	else
311 		return YAFFS_FAIL;
312 }
313 
314