Have updated yaffs direct tests and added README files to the tests.
[yaffs2.git] / yaffs_mtdif1_multi.c
1 /*
2  * YAFFS: Yet another FFS. 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 /*
15  * This module provides the interface between yaffs_nand.c and the
16  * MTD API.  This version is used when the MTD interface supports the
17  * 'mtd_oob_ops' style calls to read_oob and write_oob, circa 2.6.17,
18  * and we have small-page NAND device.
19  *
20  * These functions are invoked via function pointers in yaffs_nand.c.
21  * This replaces functionality provided by functions in yaffs_mtdif.c
22  * and the yaffs_tags compatability functions in yaffs_tagscompat.c that are
23  * called in yaffs_mtdif.c when the function pointers are NULL.
24  * We assume the MTD layer is performing ECC (use_nand_ecc is true).
25  */
26
27 #include "yportenv.h"
28 #include "yaffs_trace.h"
29 #include "yaffs_guts.h"
30 #include "yaffs_packedtags1.h"
31 #include "yaffs_tagscompat.h"   /* for yaffs_calc_tags_ecc */
32 #include "yaffs_linux.h"
33
34 #include "linux/kernel.h"
35 #include "linux/version.h"
36 #include "linux/types.h"
37 #include "linux/mtd/mtd.h"
38
39 /* Don't compile this module if we don't have MTD's mtd_oob_ops interface */
40 #if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
41
42
43 #if 0
44 /* Use the following nand_ecclayout with MTD when using
45  * 9 byte tags and the older on-NAND tags layout.
46  * If you have existing Yaffs images and the byte order differs from this,
47  * adjust 'oobfree' to match your existing Yaffs data.
48  *
49  * This nand_ecclayout scatters/gathers to/from the old-yaffs layout with the
50  * page_status byte (at NAND spare offset 4) scattered/gathered from/to
51  * the 9th byte.
52  *
53  * Old-style on-NAND format: T0,T1,T2,T3,P,B,T4,T5,E0,E1,E2,T6,T7,E3,E4,E5
54  * We have/need packed_tags1 plus page_status: T0,T1,T2,T3,T4,T5,T6,T7,P
55  * where Tn are the tag bytes, En are MTD's ECC bytes, P is the page_status
56  * byte and B is the small-page bad-block indicator byte.
57  */
58 static struct nand_ecclayout nand_oob_16 = {
59         .eccbytes = 6,
60         .eccpos = {8, 9, 10, 13, 14, 15},
61         .oobavail = 9,
62         .oobfree = {{0, 4}, {6, 2}, {11, 2}, {4, 1} }
63 };
64 #endif
65
66 /* Write a chunk (page) of data to NAND.
67  *
68  * Caller always provides ExtendedTags data which are converted to a more
69  * compact (packed) form for storage in NAND.  A mini-ECC runs over the
70  * contents of the tags meta-data; used to valid the tags when read.
71  *
72  *  - Pack ExtendedTags to packed_tags1 form
73  *  - Compute mini-ECC for packed_tags1
74  *  - Write data and packed tags to NAND.
75  *
76  * Note: Due to the use of the packed_tags1 meta-data which does not include
77  * a full sequence number (as found in the larger packed_tags2 form) it is
78  * necessary for Yaffs to re-write a chunk/page (just once) to mark it as
79  * discarded and dirty.  This is not ideal: newer NAND parts are supposed
80  * to be written just once.  When Yaffs performs this operation, this
81  * function is called with a NULL data pointer -- calling MTD write_oob
82  * without data is valid usage (2.6.17).
83  *
84  * Any underlying MTD error results in YAFFS_FAIL.
85  * Returns YAFFS_OK or YAFFS_FAIL.
86  */
87 int nandmtd1_write_chunk_tags(struct yaffs_dev *dev,
88                               int nand_chunk, const u8 *data,
89                               const struct yaffs_ext_tags *etags)
90 {
91         struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
92         int chunk_bytes = dev->data_bytes_per_chunk;
93         loff_t addr = ((loff_t) nand_chunk) * chunk_bytes;
94         struct mtd_oob_ops ops;
95         struct yaffs_packed_tags1 pt1;
96         int retval;
97
98         /* we assume that packed_tags1 and struct yaffs_tags are compatible */
99         compile_time_assertion(sizeof(struct yaffs_packed_tags1) == 12);
100         compile_time_assertion(sizeof(struct yaffs_tags) == 8);
101
102         yaffs_pack_tags1(&pt1, etags);
103         yaffs_calc_tags_ecc((struct yaffs_tags *)&pt1);
104
105         /* When deleting a chunk, the upper layer provides only skeletal
106          * etags, one with is_deleted set.  However, we need to update the
107          * tags, not erase them completely.  So we use the NAND write property
108          * that only zeroed-bits stick and set tag bytes to all-ones and
109          * zero just the (not) deleted bit.
110          */
111         if(dev->param.tags_9bytes) {
112                 ((u8 *) &pt1)[8] = 0xff;
113                 if (etags->is_deleted) {
114                         memset(&pt1, 0xff, 8);
115                         /* zero page_status byte to indicate deleted */
116                         ((u8 *) &pt1)[8] = 0;
117                 }
118         } else {
119                 if (etags->is_deleted) {
120                         memset(&pt1, 0xff, 8);
121                         /* clear delete status bit to indicate deleted */
122                         pt1.deleted = 0;
123                 }
124         }
125
126         memset(&ops, 0, sizeof(ops));
127         ops.mode = MTD_OOB_AUTO;
128         ops.len = (data) ? chunk_bytes : 0;
129         ops.ooblen = dev->param.tags_9bytes ? 9 : 8;
130         ops.datbuf = (u8 *) data;
131         ops.oobbuf = (u8 *) &pt1;
132
133         retval = mtd->write_oob(mtd, addr, &ops);
134         if (retval) {
135                 yaffs_trace(YAFFS_TRACE_MTD,
136                         "write_oob failed, chunk %d, mtd error %d",
137                         nand_chunk, retval);
138         }
139         return retval ? YAFFS_FAIL : YAFFS_OK;
140 }
141
142 /* Return with empty ExtendedTags but add ecc_result.
143  */
144 static int rettags(struct yaffs_ext_tags *etags, int ecc_result, int retval)
145 {
146         if (etags) {
147                 memset(etags, 0, sizeof(*etags));
148                 etags->ecc_result = ecc_result;
149         }
150         return retval;
151 }
152
153 /* Read a chunk (page) from NAND.
154  *
155  * Caller expects ExtendedTags data to be usable even on error; that is,
156  * all members except ecc_result and block_bad are zeroed.
157  *
158  *  - Check ECC results for data (if applicable)
159  *  - Check for blank/erased block (return empty ExtendedTags if blank)
160  *  - Check the packed_tags1 mini-ECC (correct if necessary/possible)
161  *  - Convert packed_tags1 to ExtendedTags
162  *  - Update ecc_result and block_bad members to refect state.
163  *
164  * Returns YAFFS_OK or YAFFS_FAIL.
165  */
166 int nandmtd1_read_chunk_tags(struct yaffs_dev *dev,
167                              int nand_chunk, u8 *data,
168                              struct yaffs_ext_tags *etags)
169 {
170         struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
171         int chunk_bytes = dev->data_bytes_per_chunk;
172         loff_t addr = ((loff_t) nand_chunk) * chunk_bytes;
173         int eccres = YAFFS_ECC_RESULT_NO_ERROR;
174         struct mtd_oob_ops ops;
175         struct yaffs_packed_tags1 pt1;
176         int retval;
177         int deleted;
178
179         memset(&ops, 0, sizeof(ops));
180         ops.mode = MTD_OOB_AUTO;
181         ops.len = (data) ? chunk_bytes : 0;
182         ops.ooblen = dev->param.tags_9bytes ? 9 : 8;
183         ops.datbuf = data;
184         ops.oobbuf = (u8 *) &pt1;
185
186 #if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 20))
187         /* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug;
188          * help it out with ops.len = ops.ooblen when ops.datbuf == NULL.
189          */
190         ops.len = (ops.datbuf) ? ops.len : ops.ooblen;
191 #endif
192         /* Read page and oob using MTD.
193          * Check status and determine ECC result.
194          */
195         retval = mtd->read_oob(mtd, addr, &ops);
196         if (retval)
197                 yaffs_trace(YAFFS_TRACE_MTD,
198                         "read_oob failed, chunk %d, mtd error %d",
199                         nand_chunk, retval);
200
201         switch (retval) {
202         case 0:
203                 /* no error */
204                 break;
205
206         case -EUCLEAN:
207                 /* MTD's ECC fixed the data */
208                 eccres = YAFFS_ECC_RESULT_FIXED;
209                 dev->n_ecc_fixed++;
210                 break;
211
212         case -EBADMSG:
213                 /* MTD's ECC could not fix the data */
214                 dev->n_ecc_unfixed++;
215                 /* fall into... */
216         default:
217                 rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0);
218                 etags->block_bad = (mtd->block_isbad) (mtd, addr);
219                 return YAFFS_FAIL;
220         }
221
222         /* Check for a blank/erased chunk.
223          */
224         if (yaffs_check_ff((u8 *) &pt1, 8)) {
225                 /* when blank, upper layers want ecc_result to be <= NO_ERROR */
226                 return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK);
227         }
228
229         if(dev->param.tags_9bytes) {
230                 deleted = (hweight8(((u8 *) &pt1)[8]) < 7);
231         } else {
232                 /* Read deleted status (bit) then return it to it's non-deleted
233                  * state before performing tags mini-ECC check. pt1.deleted is
234                  * inverted.
235                  */
236                 deleted = !pt1.deleted;
237                 pt1.deleted = 1;
238         }
239
240         /* Check the packed tags mini-ECC and correct if necessary/possible.
241          */
242         retval = yaffs_check_tags_ecc((struct yaffs_tags *)&pt1);
243         switch (retval) {
244         case 0:
245                 /* no tags error, use MTD result */
246                 break;
247         case 1:
248                 /* recovered tags-ECC error */
249                 dev->n_tags_ecc_fixed++;
250                 if (eccres == YAFFS_ECC_RESULT_NO_ERROR)
251                         eccres = YAFFS_ECC_RESULT_FIXED;
252                 break;
253         default:
254                 /* unrecovered tags-ECC error */
255                 dev->n_tags_ecc_unfixed++;
256                 return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL);
257         }
258
259         /* Unpack the tags to extended form and set ECC result.
260          * [set should_be_ff just to keep yaffs_unpack_tags1 happy]
261          */
262         pt1.should_be_ff = 0xffffffff;
263         yaffs_unpack_tags1(etags, &pt1);
264         etags->ecc_result = eccres;
265
266         /* Set deleted state */
267         etags->is_deleted = deleted;
268         return YAFFS_OK;
269 }
270
271 /* Mark a block bad.
272  *
273  * This is a persistant state.
274  * Use of this function should be rare.
275  *
276  * Returns YAFFS_OK or YAFFS_FAIL.
277  */
278 int nandmtd1_mark_block_bad(struct yaffs_dev *dev, int block_no)
279 {
280         struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
281         int blocksize = dev->param.chunks_per_block * dev->data_bytes_per_chunk;
282         int retval;
283
284         yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", block_no);
285
286         retval = mtd->block_markbad(mtd, (loff_t) blocksize * block_no);
287         return (retval) ? YAFFS_FAIL : YAFFS_OK;
288 }
289
290 /* Check any MTD prerequists.
291  *
292  * Returns YAFFS_OK or YAFFS_FAIL.
293  */
294 static int nandmtd1_test_prerequists(struct yaffs_dev *dev, struct mtd_info *mtd)
295 {
296         /* 2.6.18 has mtd->ecclayout->oobavail */
297         /* 2.6.21 has mtd->ecclayout->oobavail and mtd->oobavail */
298         int oobavail = mtd->ecclayout->oobavail;
299
300         if (oobavail < (dev->param.tags_9bytes ? 9 : 8)) {
301                 yaffs_trace(YAFFS_TRACE_ERROR,
302                         "mtd device has only %d bytes for tags, need %d",
303                         oobavail, dev->param.tags_9bytes ? 9 : 8);
304                 return YAFFS_FAIL;
305         }
306         return YAFFS_OK;
307 }
308
309 /* Query for the current state of a specific block.
310  *
311  * Examine the tags of the first chunk of the block and return the state:
312  *  - YAFFS_BLOCK_STATE_DEAD, the block is marked bad
313  *  - YAFFS_BLOCK_STATE_NEEDS_SCAN, the block is in use
314  *  - YAFFS_BLOCK_STATE_EMPTY, the block is clean
315  *
316  * Always returns YAFFS_OK.
317  */
318 int nandmtd1_query_block(struct yaffs_dev *dev, int block_no,
319                          enum yaffs_block_state *state_ptr, u32 * seq_ptr)
320 {
321         struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
322         int chunk_num = block_no * dev->param.chunks_per_block;
323         loff_t addr = (loff_t) chunk_num * dev->data_bytes_per_chunk;
324         struct yaffs_ext_tags etags;
325         int state = YAFFS_BLOCK_STATE_DEAD;
326         int seqnum = 0;
327         int retval;
328
329         /* We don't yet have a good place to test for MTD config prerequists.
330          * Do it here as we are called during the initial scan.
331          */
332         if (nandmtd1_test_prerequists(dev, mtd) != YAFFS_OK)
333                 return YAFFS_FAIL;
334
335         retval = nandmtd1_read_chunk_tags(dev, chunk_num, NULL, &etags);
336         etags.block_bad = (mtd->block_isbad) (mtd, addr);
337         if (etags.block_bad) {
338                 yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
339                         "block %d is marked bad",
340                         block_no);
341                 state = YAFFS_BLOCK_STATE_DEAD;
342         } else if (etags.ecc_result != YAFFS_ECC_RESULT_NO_ERROR) {
343                 /* bad tags, need to look more closely */
344                 state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
345         } else if (etags.chunk_used) {
346                 state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
347                 seqnum = etags.seq_number;
348         } else {
349                 state = YAFFS_BLOCK_STATE_EMPTY;
350         }
351
352         *state_ptr = state;
353         *seq_ptr = seqnum;
354
355         /* query always succeeds */
356         return YAFFS_OK;
357 }
358
359 #endif /*MTD_VERSION */