1 From ian@brightstareng
.com Fri May
18 15:06:49 2007
2 From ian@brightstareng
.com Fri May
18 15:08:21 2007
3 Received
: from
206.173.66.57.ptr
.us
.xo
.net ([206.173.66.57] helo
=zebra
.brightstareng
.com
)
4 by apollo
.linkchoose
.co
.uk with
esmtp (Exim
4.60)
5 (envelope
-from
<ian@brightstareng
.com
>)
7 for david
.goodenough@linkchoose
.co
.uk
; Fri
, 18 May
2007 15:08:21 +0100
8 Received
: from
localhost (localhost
.localdomain
[127.0.0.1])
9 by zebra
.brightstareng
.com (Postfix
) with ESMTP
10 id
4819F28C004
; Fri
, 18 May
2007 10:07:49 -0400 (EDT
)
11 Received
: from zebra
.brightstareng
.com ([127.0.0.1])
12 by
localhost (zebra
[127.0.0.1]) (amavisd
-new, port
10024) with ESMTP
13 id
05328-06; Fri
, 18 May
2007 10:07:16 -0400 (EDT
)
14 Received
: from
pippin (unknown
[192.168.1.25])
15 by zebra
.brightstareng
.com (Postfix
) with ESMTP
16 id
8BEF528C1BC
; Fri
, 18 May
2007 10:06:53 -0400 (EDT
)
17 From
: Ian McDonnell
<ian@brightstareng
.com
>
18 To
: David Goodenough
<david
.goodenough@linkchoose
.co
.uk
>
19 Subject
: Re
: something tested
this time
-- yaffs_mtdif1
-compat
.c
20 Date
: Fri
, 18 May
2007 10:06:49 -0400
21 User
-Agent
: KMail
/1.9.1
22 References
: <200705142207.06909.ian@brightstareng
.com
> <200705171131.53536.ian@brightstareng
.com
> <200705181334.32166.david
.goodenough@linkchoose
.co
.uk
>
23 In
-Reply
-To
: <200705181334.32166.david
.goodenough@linkchoose
.co
.uk
>
24 Cc
: Andrea Conti
<alyf@alyf
.net
>,
25 Charles Manning
<manningc2@actrix
.gen
.nz
>
27 Content
-Type
: Multipart
/Mixed
;
28 boundary
="Boundary-00=_5LbTGmt62YoutxM"
29 Message
-Id
: <200705181006.49860.ian@brightstareng
.com
>
30 X
-Virus
-Scanned
: by amavisd
-new at brightstareng
.com
33 X
-KMail
-EncryptionState
:
34 X
-KMail
-SignatureState
:
37 --Boundary
-00=_5LbTGmt62YoutxM
38 Content
-Type
: text
/plain
;
40 Content
-Transfer
-Encoding
: 7bit
41 Content
-Disposition
: inline
45 On Friday
18 May
2007 08:34, you wrote
:
46 > Yea team
. With
this fix in
place (I put it in the wrong place
47 > at first
) I can now mount
and ls the Yaffs partition without
52 Attached is a newer yaffs_mtdif1
.c with a bandaid to help the
53 2.6.18 and 2.6.19 versions of MTD
not trip on the oob read
.
54 See the LINUX_VERSION_CODE conditional in
55 nandmtd1_ReadChunkWithTagsFromNAND
.
59 --Boundary
-00=_5LbTGmt62YoutxM
60 Content
-Type
: text
/x
-csrc
;
61 charset
="iso-8859-15";
63 Content
-Transfer
-Encoding
: 7bit
64 Content
-Disposition
: attachment
;
65 filename
="yaffs_mtdif1.c"
68 * YAFFS: Yet another FFS. A NAND-flash specific file system.
69 * yaffs_mtdif1.c NAND mtd interface functions for small-page NAND.
71 * Copyright (C) 2002 Aleph One Ltd.
72 * for Toby Churchill Ltd and Brightstar Engineering
74 * This program is free software; you can redistribute it and/or modify
75 * it under the terms of the GNU General Public License version 2 as
76 * published by the Free Software Foundation.
80 * This module provides the interface between yaffs_nand.c and the
81 * MTD API. This version is used when the MTD interface supports the
82 * 'mtd_oob_ops' style calls to read_oob and write_oob, circa 2.6.17,
83 * and we have small-page NAND device.
85 * These functions are invoked via function pointers in yaffs_nand.c.
86 * This replaces functionality provided by functions in yaffs_mtdif.c
87 * and the yaffs_TagsCompatability functions in yaffs_tagscompat.c that are
88 * called in yaffs_mtdif.c when the function pointers are NULL.
89 * We assume the MTD layer is performing ECC (useNANDECC is true).
93 #include "yaffs_guts.h"
94 #include "yaffs_packedtags1.h"
95 #include "yaffs_tagscompat.h" // for yaffs_CalcTagsECC
97 #include "linux/kernel.h"
98 #include "linux/version.h"
99 #include "linux/types.h"
100 #include "linux/mtd/mtd.h"
102 /* Don't compile this module if we don't have MTD's mtd_oob_ops interface */
103 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
105 const char *yaffs_mtdif1_c_version
= "$Id: yaffs_mtdif1.c,v 1.3 2007/05/15 20:16:11 ian Exp $";
107 #ifndef CONFIG_YAFFS_9BYTE_TAGS
108 # define YTAG1_SIZE 8
110 # define YTAG1_SIZE 9
114 /* Use the following nand_ecclayout with MTD when using
115 * CONFIG_YAFFS_9BYTE_TAGS and the older on-NAND tags layout.
116 * If you have existing Yaffs images and the byte order differs from this,
117 * adjust 'oobfree' to match your existing Yaffs data.
119 * This nand_ecclayout scatters/gathers to/from the old-yaffs layout with the
120 * pageStatus byte (at NAND spare offset 4) scattered/gathered from/to
123 * Old-style on-NAND format: T0,T1,T2,T3,P,B,T4,T5,E0,E1,E2,T6,T7,E3,E4,E5
124 * We have/need PackedTags1 plus pageStatus: T0,T1,T2,T3,T4,T5,T6,T7,P
125 * where Tn are the tag bytes, En are MTD's ECC bytes, P is the pageStatus
126 * byte and B is the small-page bad-block indicator byte.
128 static struct nand_ecclayout nand_oob_16
= {
130 .eccpos
= { 8, 9, 10, 13, 14, 15 },
132 .oobfree
= { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } }
136 /* Write a chunk (page) of data to NAND.
138 * Caller always provides ExtendedTags data which are converted to a more
139 * compact (packed) form for storage in NAND. A mini-ECC runs over the
140 * contents of the tags meta-data; used to valid the tags when read.
142 * - Pack ExtendedTags to PackedTags1 form
143 * - Compute mini-ECC for PackedTags1
144 * - Write data and packed tags to NAND.
146 * Note: Due to the use of the PackedTags1 meta-data which does not include
147 * a full sequence number (as found in the larger PackedTags2 form) it is
148 * necessary for Yaffs to re-write a chunk/page (just once) to mark it as
149 * discarded and dirty. This is not ideal: newer NAND parts are supposed
150 * to be written just once. When Yaffs performs this operation, this
151 * function is called with a NULL data pointer -- calling MTD write_oob
152 * without data is valid usage (2.6.17).
154 * Any underlying MTD error results in YAFFS_FAIL.
155 * Returns YAFFS_OK or YAFFS_FAIL.
157 int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device
*dev
,
158 int chunkInNAND
, const __u8
* data
, const yaffs_ExtendedTags
* etags
)
160 struct mtd_info
* mtd
= dev
->genericDevice
;
161 int chunkBytes
= dev
->nDataBytesPerChunk
;
162 loff_t addr
= ((loff_t
)chunkInNAND
) * chunkBytes
;
163 struct mtd_oob_ops ops
;
164 yaffs_PackedTags1 pt1
;
167 /* we assume that PackedTags1 and yaffs_Tags are compatible */
168 compile_time_assertion(sizeof(yaffs_PackedTags1
) == 12);
169 compile_time_assertion(sizeof(yaffs_Tags
) == 8);
171 yaffs_PackTags1(&pt1
, etags
);
172 yaffs_CalcTagsECC((yaffs_Tags
*)&pt1
);
174 /* When deleting a chunk, the upper layer provides only skeletal
175 * etags, one with chunkDeleted set. However, we need to update the
176 * tags, not erase them completely. So we use the NAND write property
177 * that only zeroed-bits stick and set tag bytes to all-ones and
178 * zero just the (not) deleted bit.
180 #ifndef CONFIG_YAFFS_9BYTE_TAGS
181 if (etags
->chunkDeleted
) {
182 memset(&pt1
, 0xff, 8);
183 /* clear delete status bit to indicate deleted */
187 ((__u8
*)&pt1
)[8] = 0xff;
188 if (etags
->chunkDeleted
) {
189 memset(&pt1
, 0xff, 8);
190 /* zero pageStatus byte to indicate deleted */
191 ((__u8
*)&pt1
)[8] = 0;
195 memset(&ops
, 0, sizeof(ops
));
196 ops
.mode
= MTD_OOB_AUTO
;
197 ops
.len
= (data
) ? chunkBytes
: 0;
198 ops
.ooblen
= YTAG1_SIZE
;
199 ops
.datbuf
= (__u8
*)data
;
200 ops
.oobbuf
= (__u8
*)&pt1
;
202 retval
= mtd
->write_oob(mtd
, addr
, &ops
);
204 yaffs_trace(YAFFS_TRACE_MTD
,
205 "write_oob failed, chunk %d, mtd error %d\n",
206 chunkInNAND
, retval
);
208 return retval
? YAFFS_FAIL
: YAFFS_OK
;
211 /* Return with empty ExtendedTags but add eccResult.
213 static int rettags(yaffs_ExtendedTags
* etags
, int eccResult
, int retval
)
216 memset(etags
, 0, sizeof(*etags
));
217 etags
->eccResult
= eccResult
;
222 /* Read a chunk (page) from NAND.
224 * Caller expects ExtendedTags data to be usable even on error; that is,
225 * all members except eccResult and blockBad are zeroed.
227 * - Check ECC results for data (if applicable)
228 * - Check for blank/erased block (return empty ExtendedTags if blank)
229 * - Check the PackedTags1 mini-ECC (correct if necessary/possible)
230 * - Convert PackedTags1 to ExtendedTags
231 * - Update eccResult and blockBad members to refect state.
233 * Returns YAFFS_OK or YAFFS_FAIL.
235 int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device
*dev
,
236 int chunkInNAND
, __u8
* data
, yaffs_ExtendedTags
* etags
)
238 struct mtd_info
* mtd
= dev
->genericDevice
;
239 int chunkBytes
= dev
->nDataBytesPerChunk
;
240 loff_t addr
= ((loff_t
)chunkInNAND
) * chunkBytes
;
241 int eccres
= YAFFS_ECC_RESULT_NO_ERROR
;
242 struct mtd_oob_ops ops
;
243 yaffs_PackedTags1 pt1
;
247 memset(&ops
, 0, sizeof(ops
));
248 ops
.mode
= MTD_OOB_AUTO
;
249 ops
.len
= (data
) ? chunkBytes
: 0;
250 ops
.ooblen
= YTAG1_SIZE
;
252 ops
.oobbuf
= (__u8
*)&pt1
;
254 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
255 /* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug;
256 * help it out with ops.len = ops.ooblen when ops.datbuf == NULL.
258 ops
.len
= (ops
.datbuf
) ? ops
.len
: ops
.ooblen
;
260 /* Read page and oob using MTD.
261 * Check status and determine ECC result.
263 retval
= mtd
->read_oob(mtd
, addr
, &ops
);
265 yaffs_trace(YAFFS_TRACE_MTD
,
266 "read_oob failed, chunk %d, mtd error %d\n",
267 chunkInNAND
, retval
);
276 /* MTD's ECC fixed the data */
277 eccres
= YAFFS_ECC_RESULT_FIXED
;
282 /* MTD's ECC could not fix the data */
286 rettags(etags
, YAFFS_ECC_RESULT_UNFIXED
, 0);
287 etags
->blockBad
= (mtd
->block_isbad
)(mtd
, addr
);
291 /* Check for a blank/erased chunk.
293 if (yaffs_CheckFF((__u8
*)&pt1
, 8)) {
294 /* when blank, upper layers want eccResult to be <= NO_ERROR */
295 return rettags(etags
, YAFFS_ECC_RESULT_NO_ERROR
, YAFFS_OK
);
298 #ifndef CONFIG_YAFFS_9BYTE_TAGS
299 /* Read deleted status (bit) then return it to it's non-deleted
300 * state before performing tags mini-ECC check. pt1.deleted is
303 deleted
= !pt1
.deleted
;
306 (void) deleted
; /* not used */
309 /* Check the packed tags mini-ECC and correct if necessary/possible.
311 retval
= yaffs_CheckECCOnTags((yaffs_Tags
*)&pt1
);
314 /* no tags error, use MTD result */
317 /* recovered tags-ECC error */
319 eccres
= YAFFS_ECC_RESULT_FIXED
;
322 /* unrecovered tags-ECC error */
323 dev
->tagsEccUnfixed
++;
324 return rettags(etags
, YAFFS_ECC_RESULT_UNFIXED
, YAFFS_FAIL
);
327 /* Unpack the tags to extended form and set ECC result.
328 * [set shouldBeFF just to keep yaffs_UnpackTags1 happy]
330 pt1
.shouldBeFF
= 0xFFFFFFFF;
331 yaffs_UnpackTags1(etags
, &pt1
);
332 etags
->eccResult
= eccres
;
334 /* Set deleted state.
336 #ifndef CONFIG_YAFFS_9BYTE_TAGS
337 etags
->chunkDeleted
= deleted
;
339 etags
->chunkDeleted
= (yaffs_CountBits(((__u8
*)&pt1
)[8]) < 7);
346 * This is a persistant state.
347 * Use of this function should be rare.
349 * Returns YAFFS_OK or YAFFS_FAIL.
351 int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct
*dev
, int blockNo
)
353 struct mtd_info
* mtd
= dev
->genericDevice
;
354 int blocksize
= dev
->nChunksPerBlock
* dev
->nDataBytesPerChunk
;
357 yaffs_trace(YAFFS_TRACE_BAD_BLOCKS
, "marking block %d bad", blockNo
);
359 retval
= mtd
->block_markbad(mtd
, (loff_t
)blocksize
* blockNo
);
360 return (retval
) ? YAFFS_FAIL
: YAFFS_OK
;
363 /* Check any MTD prerequists.
365 * Returns YAFFS_OK or YAFFS_FAIL.
367 static int nandmtd1_TestPrerequists(struct mtd_info
* mtd
)
369 /* 2.6.18 has mtd->ecclayout->oobavail */
370 /* 2.6.21 has mtd->ecclayout->oobavail and mtd->oobavail */
371 int oobavail
= mtd
->ecclayout
->oobavail
;
373 if (oobavail
< YTAG1_SIZE
) {
374 yaffs_trace(YAFFS_TRACE_ERROR
,
375 "mtd device has only %d bytes for tags, need %d",
376 oobavail
, YTAG1_SIZE
);
382 /* Query for the current state of a specific block.
384 * Examine the tags of the first chunk of the block and return the state:
385 * - YAFFS_BLOCK_STATE_DEAD, the block is marked bad
386 * - YAFFS_BLOCK_STATE_NEEDS_SCANNING, the block is in use
387 * - YAFFS_BLOCK_STATE_EMPTY, the block is clean
389 * Always returns YAFFS_OK.
391 int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct
*dev
, int blockNo
,
392 yaffs_BlockState
* pState
, int *pSequenceNumber
)
394 struct mtd_info
* mtd
= dev
->genericDevice
;
395 int chunkNo
= blockNo
* dev
->nChunksPerBlock
;
396 yaffs_ExtendedTags etags
;
397 int state
= YAFFS_BLOCK_STATE_DEAD
;
401 /* We don't yet have a good place to test for MTD config prerequists.
402 * Do it here as we are called during the initial scan.
404 if (nandmtd1_TestPrerequists(mtd
) != YAFFS_OK
) {
408 retval
= nandmtd1_ReadChunkWithTagsFromNAND(dev
, chunkNo
, NULL
, &etags
);
409 if (etags
.blockBad
) {
410 yaffs_trace(YAFFS_TRACE_BAD_BLOCKS
,
411 "block %d is marked bad", blockNo
);
412 state
= YAFFS_BLOCK_STATE_DEAD
;
414 else if (etags
.chunkUsed
) {
415 state
= YAFFS_BLOCK_STATE_NEEDS_SCANNING
;
416 seqnum
= etags
.sequenceNumber
;
419 state
= YAFFS_BLOCK_STATE_EMPTY
;
423 *pSequenceNumber
= seqnum
;
425 /* query always succeeds */
429 #endif /*KERNEL_VERSION*/
431 --Boundary
-00=_5LbTGmt62YoutxM
--