xref: /rk3399_rockchip-uboot/fs/yaffs2/yaffs_mtdif2.c (revision 0e8cc8bd92257da2e1df88cbc985e166e472ce61)
1*0e8cc8bdSWilliam Juul /*
2*0e8cc8bdSWilliam Juul  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3*0e8cc8bdSWilliam Juul  *
4*0e8cc8bdSWilliam Juul  * Copyright (C) 2002-2007 Aleph One Ltd.
5*0e8cc8bdSWilliam Juul  *   for Toby Churchill Ltd and Brightstar Engineering
6*0e8cc8bdSWilliam Juul  *
7*0e8cc8bdSWilliam Juul  * Created by Charles Manning <charles@aleph1.co.uk>
8*0e8cc8bdSWilliam Juul  *
9*0e8cc8bdSWilliam Juul  * This program is free software; you can redistribute it and/or modify
10*0e8cc8bdSWilliam Juul  * it under the terms of the GNU General Public License version 2 as
11*0e8cc8bdSWilliam Juul  * published by the Free Software Foundation.
12*0e8cc8bdSWilliam Juul  */
13*0e8cc8bdSWilliam Juul 
14*0e8cc8bdSWilliam Juul /* mtd interface for YAFFS2 */
15*0e8cc8bdSWilliam Juul 
16*0e8cc8bdSWilliam Juul const char *yaffs_mtdif2_c_version =
17*0e8cc8bdSWilliam Juul     "$Id: yaffs_mtdif2.c,v 1.17 2007/02/14 01:09:06 wookey Exp $";
18*0e8cc8bdSWilliam Juul 
19*0e8cc8bdSWilliam Juul #include "yportenv.h"
20*0e8cc8bdSWilliam Juul 
21*0e8cc8bdSWilliam Juul 
22*0e8cc8bdSWilliam Juul #include "yaffs_mtdif2.h"
23*0e8cc8bdSWilliam Juul 
24*0e8cc8bdSWilliam Juul #include "linux/mtd/mtd.h"
25*0e8cc8bdSWilliam Juul #include "linux/types.h"
26*0e8cc8bdSWilliam Juul #include "linux/time.h"
27*0e8cc8bdSWilliam Juul 
28*0e8cc8bdSWilliam Juul #include "yaffs_packedtags2.h"
29*0e8cc8bdSWilliam Juul 
30*0e8cc8bdSWilliam Juul int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
31*0e8cc8bdSWilliam Juul 				      const __u8 * data,
32*0e8cc8bdSWilliam Juul 				      const yaffs_ExtendedTags * tags)
33*0e8cc8bdSWilliam Juul {
34*0e8cc8bdSWilliam Juul 	struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
35*0e8cc8bdSWilliam Juul #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
36*0e8cc8bdSWilliam Juul 	struct mtd_oob_ops ops;
37*0e8cc8bdSWilliam Juul #else
38*0e8cc8bdSWilliam Juul 	size_t dummy;
39*0e8cc8bdSWilliam Juul #endif
40*0e8cc8bdSWilliam Juul 	int retval = 0;
41*0e8cc8bdSWilliam Juul 
42*0e8cc8bdSWilliam Juul 	loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
43*0e8cc8bdSWilliam Juul 
44*0e8cc8bdSWilliam Juul 	yaffs_PackedTags2 pt;
45*0e8cc8bdSWilliam Juul 
46*0e8cc8bdSWilliam Juul 	T(YAFFS_TRACE_MTD,
47*0e8cc8bdSWilliam Juul 	  (TSTR
48*0e8cc8bdSWilliam Juul 	   ("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"
49*0e8cc8bdSWilliam Juul 	    TENDSTR), chunkInNAND, data, tags));
50*0e8cc8bdSWilliam Juul 
51*0e8cc8bdSWilliam Juul #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
52*0e8cc8bdSWilliam Juul 	if (tags)
53*0e8cc8bdSWilliam Juul 		yaffs_PackTags2(&pt, tags);
54*0e8cc8bdSWilliam Juul 	else
55*0e8cc8bdSWilliam Juul 		BUG(); /* both tags and data should always be present */
56*0e8cc8bdSWilliam Juul 
57*0e8cc8bdSWilliam Juul 	if (data) {
58*0e8cc8bdSWilliam Juul 		ops.mode = MTD_OOB_AUTO;
59*0e8cc8bdSWilliam Juul 		ops.ooblen = sizeof(pt);
60*0e8cc8bdSWilliam Juul 		ops.len = dev->nDataBytesPerChunk;
61*0e8cc8bdSWilliam Juul 		ops.ooboffs = 0;
62*0e8cc8bdSWilliam Juul 		ops.datbuf = (__u8 *)data;
63*0e8cc8bdSWilliam Juul 		ops.oobbuf = (void *)&pt;
64*0e8cc8bdSWilliam Juul 		retval = mtd->write_oob(mtd, addr, &ops);
65*0e8cc8bdSWilliam Juul 	} else
66*0e8cc8bdSWilliam Juul 		BUG(); /* both tags and data should always be present */
67*0e8cc8bdSWilliam Juul #else
68*0e8cc8bdSWilliam Juul 	if (tags) {
69*0e8cc8bdSWilliam Juul 		yaffs_PackTags2(&pt, tags);
70*0e8cc8bdSWilliam Juul 	}
71*0e8cc8bdSWilliam Juul 
72*0e8cc8bdSWilliam Juul 	if (data && tags) {
73*0e8cc8bdSWilliam Juul 		if (dev->useNANDECC)
74*0e8cc8bdSWilliam Juul 			retval =
75*0e8cc8bdSWilliam Juul 			    mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
76*0e8cc8bdSWilliam Juul 					   &dummy, data, (__u8 *) & pt, NULL);
77*0e8cc8bdSWilliam Juul 		else
78*0e8cc8bdSWilliam Juul 			retval =
79*0e8cc8bdSWilliam Juul 			    mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
80*0e8cc8bdSWilliam Juul 					   &dummy, data, (__u8 *) & pt, NULL);
81*0e8cc8bdSWilliam Juul 	} else {
82*0e8cc8bdSWilliam Juul 		if (data)
83*0e8cc8bdSWilliam Juul 			retval =
84*0e8cc8bdSWilliam Juul 			    mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy,
85*0e8cc8bdSWilliam Juul 				       data);
86*0e8cc8bdSWilliam Juul 		if (tags)
87*0e8cc8bdSWilliam Juul 			retval =
88*0e8cc8bdSWilliam Juul 			    mtd->write_oob(mtd, addr, mtd->oobsize, &dummy,
89*0e8cc8bdSWilliam Juul 					   (__u8 *) & pt);
90*0e8cc8bdSWilliam Juul 
91*0e8cc8bdSWilliam Juul 	}
92*0e8cc8bdSWilliam Juul #endif
93*0e8cc8bdSWilliam Juul 
94*0e8cc8bdSWilliam Juul 	if (retval == 0)
95*0e8cc8bdSWilliam Juul 		return YAFFS_OK;
96*0e8cc8bdSWilliam Juul 	else
97*0e8cc8bdSWilliam Juul 		return YAFFS_FAIL;
98*0e8cc8bdSWilliam Juul }
99*0e8cc8bdSWilliam Juul 
100*0e8cc8bdSWilliam Juul int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
101*0e8cc8bdSWilliam Juul 				       __u8 * data, yaffs_ExtendedTags * tags)
102*0e8cc8bdSWilliam Juul {
103*0e8cc8bdSWilliam Juul 	struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
104*0e8cc8bdSWilliam Juul #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
105*0e8cc8bdSWilliam Juul 	struct mtd_oob_ops ops;
106*0e8cc8bdSWilliam Juul #endif
107*0e8cc8bdSWilliam Juul 	size_t dummy;
108*0e8cc8bdSWilliam Juul 	int retval = 0;
109*0e8cc8bdSWilliam Juul 
110*0e8cc8bdSWilliam Juul 	loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
111*0e8cc8bdSWilliam Juul 
112*0e8cc8bdSWilliam Juul 	yaffs_PackedTags2 pt;
113*0e8cc8bdSWilliam Juul 
114*0e8cc8bdSWilliam Juul 	T(YAFFS_TRACE_MTD,
115*0e8cc8bdSWilliam Juul 	  (TSTR
116*0e8cc8bdSWilliam Juul 	   ("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p"
117*0e8cc8bdSWilliam Juul 	    TENDSTR), chunkInNAND, data, tags));
118*0e8cc8bdSWilliam Juul 
119*0e8cc8bdSWilliam Juul #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
120*0e8cc8bdSWilliam Juul 	if (data && !tags)
121*0e8cc8bdSWilliam Juul 		retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk,
122*0e8cc8bdSWilliam Juul 				&dummy, data);
123*0e8cc8bdSWilliam Juul 	else if (tags) {
124*0e8cc8bdSWilliam Juul 		ops.mode = MTD_OOB_AUTO;
125*0e8cc8bdSWilliam Juul 		ops.ooblen = sizeof(pt);
126*0e8cc8bdSWilliam Juul 		ops.len = data ? dev->nDataBytesPerChunk : sizeof(pt);
127*0e8cc8bdSWilliam Juul 		ops.ooboffs = 0;
128*0e8cc8bdSWilliam Juul 		ops.datbuf = data;
129*0e8cc8bdSWilliam Juul 		ops.oobbuf = dev->spareBuffer;
130*0e8cc8bdSWilliam Juul 		retval = mtd->read_oob(mtd, addr, &ops);
131*0e8cc8bdSWilliam Juul 	}
132*0e8cc8bdSWilliam Juul #else
133*0e8cc8bdSWilliam Juul 	if (data && tags) {
134*0e8cc8bdSWilliam Juul 		if (dev->useNANDECC) {
135*0e8cc8bdSWilliam Juul 			retval =
136*0e8cc8bdSWilliam Juul 			    mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
137*0e8cc8bdSWilliam Juul 					  &dummy, data, dev->spareBuffer,
138*0e8cc8bdSWilliam Juul 					  NULL);
139*0e8cc8bdSWilliam Juul 		} else {
140*0e8cc8bdSWilliam Juul 			retval =
141*0e8cc8bdSWilliam Juul 			    mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
142*0e8cc8bdSWilliam Juul 					  &dummy, data, dev->spareBuffer,
143*0e8cc8bdSWilliam Juul 					  NULL);
144*0e8cc8bdSWilliam Juul 		}
145*0e8cc8bdSWilliam Juul 	} else {
146*0e8cc8bdSWilliam Juul 		if (data)
147*0e8cc8bdSWilliam Juul 			retval =
148*0e8cc8bdSWilliam Juul 			    mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
149*0e8cc8bdSWilliam Juul 				      data);
150*0e8cc8bdSWilliam Juul 		if (tags)
151*0e8cc8bdSWilliam Juul 			retval =
152*0e8cc8bdSWilliam Juul 			    mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
153*0e8cc8bdSWilliam Juul 					  dev->spareBuffer);
154*0e8cc8bdSWilliam Juul 	}
155*0e8cc8bdSWilliam Juul #endif
156*0e8cc8bdSWilliam Juul 
157*0e8cc8bdSWilliam Juul 	memcpy(&pt, dev->spareBuffer, sizeof(pt));
158*0e8cc8bdSWilliam Juul 
159*0e8cc8bdSWilliam Juul 	if (tags)
160*0e8cc8bdSWilliam Juul 		yaffs_UnpackTags2(tags, &pt);
161*0e8cc8bdSWilliam Juul 
162*0e8cc8bdSWilliam Juul 	if(tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR)
163*0e8cc8bdSWilliam Juul 		tags->eccResult = YAFFS_ECC_RESULT_UNFIXED;
164*0e8cc8bdSWilliam Juul 
165*0e8cc8bdSWilliam Juul 	if (retval == 0)
166*0e8cc8bdSWilliam Juul 		return YAFFS_OK;
167*0e8cc8bdSWilliam Juul 	else
168*0e8cc8bdSWilliam Juul 		return YAFFS_FAIL;
169*0e8cc8bdSWilliam Juul }
170*0e8cc8bdSWilliam Juul 
171*0e8cc8bdSWilliam Juul int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
172*0e8cc8bdSWilliam Juul {
173*0e8cc8bdSWilliam Juul 	struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
174*0e8cc8bdSWilliam Juul 	int retval;
175*0e8cc8bdSWilliam Juul 	T(YAFFS_TRACE_MTD,
176*0e8cc8bdSWilliam Juul 	  (TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), blockNo));
177*0e8cc8bdSWilliam Juul 
178*0e8cc8bdSWilliam Juul 	retval =
179*0e8cc8bdSWilliam Juul 	    mtd->block_markbad(mtd,
180*0e8cc8bdSWilliam Juul 			       blockNo * dev->nChunksPerBlock *
181*0e8cc8bdSWilliam Juul 			       dev->nDataBytesPerChunk);
182*0e8cc8bdSWilliam Juul 
183*0e8cc8bdSWilliam Juul 	if (retval == 0)
184*0e8cc8bdSWilliam Juul 		return YAFFS_OK;
185*0e8cc8bdSWilliam Juul 	else
186*0e8cc8bdSWilliam Juul 		return YAFFS_FAIL;
187*0e8cc8bdSWilliam Juul 
188*0e8cc8bdSWilliam Juul }
189*0e8cc8bdSWilliam Juul 
190*0e8cc8bdSWilliam Juul int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
191*0e8cc8bdSWilliam Juul 			    yaffs_BlockState * state, int *sequenceNumber)
192*0e8cc8bdSWilliam Juul {
193*0e8cc8bdSWilliam Juul 	struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
194*0e8cc8bdSWilliam Juul 	int retval;
195*0e8cc8bdSWilliam Juul 
196*0e8cc8bdSWilliam Juul 	T(YAFFS_TRACE_MTD,
197*0e8cc8bdSWilliam Juul 	  (TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo));
198*0e8cc8bdSWilliam Juul 	retval =
199*0e8cc8bdSWilliam Juul 	    mtd->block_isbad(mtd,
200*0e8cc8bdSWilliam Juul 			     blockNo * dev->nChunksPerBlock *
201*0e8cc8bdSWilliam Juul 			     dev->nDataBytesPerChunk);
202*0e8cc8bdSWilliam Juul 
203*0e8cc8bdSWilliam Juul 	if (retval) {
204*0e8cc8bdSWilliam Juul 		T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR)));
205*0e8cc8bdSWilliam Juul 
206*0e8cc8bdSWilliam Juul 		*state = YAFFS_BLOCK_STATE_DEAD;
207*0e8cc8bdSWilliam Juul 		*sequenceNumber = 0;
208*0e8cc8bdSWilliam Juul 	} else {
209*0e8cc8bdSWilliam Juul 		yaffs_ExtendedTags t;
210*0e8cc8bdSWilliam Juul 		nandmtd2_ReadChunkWithTagsFromNAND(dev,
211*0e8cc8bdSWilliam Juul 						   blockNo *
212*0e8cc8bdSWilliam Juul 						   dev->nChunksPerBlock, NULL,
213*0e8cc8bdSWilliam Juul 						   &t);
214*0e8cc8bdSWilliam Juul 
215*0e8cc8bdSWilliam Juul 		if (t.chunkUsed) {
216*0e8cc8bdSWilliam Juul 			*sequenceNumber = t.sequenceNumber;
217*0e8cc8bdSWilliam Juul 			*state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
218*0e8cc8bdSWilliam Juul 		} else {
219*0e8cc8bdSWilliam Juul 			*sequenceNumber = 0;
220*0e8cc8bdSWilliam Juul 			*state = YAFFS_BLOCK_STATE_EMPTY;
221*0e8cc8bdSWilliam Juul 		}
222*0e8cc8bdSWilliam Juul 	}
223*0e8cc8bdSWilliam Juul 	T(YAFFS_TRACE_MTD,
224*0e8cc8bdSWilliam Juul 	  (TSTR("block is bad seq %d state %d" TENDSTR), *sequenceNumber,
225*0e8cc8bdSWilliam Juul 	   *state));
226*0e8cc8bdSWilliam Juul 
227*0e8cc8bdSWilliam Juul 	if (retval == 0)
228*0e8cc8bdSWilliam Juul 		return YAFFS_OK;
229*0e8cc8bdSWilliam Juul 	else
230*0e8cc8bdSWilliam Juul 		return YAFFS_FAIL;
231*0e8cc8bdSWilliam Juul }
232*0e8cc8bdSWilliam Juul 
233