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