[Yaffs] Fixes for working with MTD
Artis Kugevics
artis at mikrotik.com
Wed Jul 27 10:58:13 BST 2005
As Yaffs2 does not specify its own nand_oobinfo structure, MTD uses default
one. That structure has field oobfree, which specifies, at which offset to
put oob info from yaffs. For example, following structure
static struct nand_oobinfo nand_oob_64 = {
.useecc = MTD_NANDECC_AUTOPLACE,
.eccbytes = 24,
.eccpos = {
40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63},
.oobfree = { {2, 38} }
};
which is by default in MTD, leaves first 2 bytes unused (for marking block as
bad) and places oob info from yaffs starting at offset 2. mtd->write_ecc()
and mtd->read_ecc() does that correctly.
But mtd->read_oob() and mtd->write_oob() reads and writes whole oob space,
without use of nand_oobinfo structure. It works as expected in yaffs_mtdif.c,
where such behaviour is needed. But it fails in yaffs_mtdif2.c, where
mtd->read_oob() expects to read only yaffs oob info, and not whole oob area
of nand. So, this oobfree offset has to be applied somewhere, to read yaffs
oob info from correct offset. Fixing this in yaffs may not seem the right
solution, but it is required, to don't break yaffs1 support at the same time.
Here is my patch:
=== Cut ===
--- orig/yaffs_mtdif2.c 2005-07-27 12:41:59.000000000 +0300
+++ yaffs_mtdif2.c 2005-07-26 12:04:37.000000000 +0300
@@ -100,20 +100,29 @@
{
retval =
mtd->read_ecc(mtd,addr,dev->nBytesPerChunk,&dummy,data,dev->spareBuffer,NULL);
}
+ memcpy(&pt,dev->spareBuffer,sizeof(pt));
}
else
{
#endif
if(data)
retval = mtd->read(mtd,addr,dev->nBytesPerChunk,&dummy,data);
- if(tags)
- retval = mtd->read_oob(mtd,addr,mtd->oobsize,&dummy,dev->spareBuffer);
+ if(tags) {
+ int i, j;
+ retval = mtd->read_oob(mtd,addr,mtd->oobsize,&dummy,
+ dev->spareBuffer);
+ for (i = 0, j = 0; mtd->oobinfo.oobfree[i][1] ; i++) {
+ int from = mtd->oobinfo.oobfree[i][0];
+ int num = mtd->oobinfo.oobfree[i][1];
+ memcpy(&((char *) &pt)[j],
+ &((char *) dev->spareBuffer)[from], num);
+ j+= num;
+ }
+ }
#ifndef CONFIG_YAFFS_USE_OLD_MTD
}
#endif
- memcpy(&pt,dev->spareBuffer,sizeof(pt));
-
if(tags)
yaffs_UnpackTags2(tags,&pt);
=== Cut ===
Another problem - yaffs_mtdif.c does not use return value from
mtd->write_ecc():
=== Cut ===
--- orig/yaffs_mtdif.c 2005-07-27 12:41:59.000000000 +0300
+++ yaffs_mtdif.c 2005-07-26 17:26:04.000000000 +0300
@@ -53,9 +54,9 @@
if(data && spare)
{
if(dev->useNANDECC)
-
mtd->write_ecc(mtd,addr,dev->nBytesPerChunk,&dummy,data,spareAsBytes,&yaffs_oobinfo);
+ retval =
mtd->write_ecc(mtd,addr,dev->nBytesPerChunk,&dummy,data,spareAsBytes,&yaffs_oobinfo);
else
-
mtd->write_ecc(mtd,addr,dev->nBytesPerChunk,&dummy,data,spareAsBytes,&yaffs_noeccinfo);
+ retval =
mtd->write_ecc(mtd,addr,dev->nBytesPerChunk,&dummy,data,spareAsBytes,&yaffs_noeccinfo);
}
else
{
=== Cut ===
And maybe it is better to initialize unused oob tag bits to something, before
writing them to nand? Those ar 2 bits in yaffs1 fs:
=== Cut ===
--- orig/yaffs_tagscompat.c 2005-07-27 12:41:59.000000000 +0300
+++ yaffs_tagscompat.c 2005-07-26 12:39:01.000000000 +0300
@@ -586,6 +586,7 @@
tags.chunkId = eTags->chunkId;
tags.byteCount = eTags->byteCount;
tags.serialNumber = eTags->serialNumber;
+ tags.unusedStuff = 0xffffffff;
// NCB
if (!dev->useNANDECC && data)
=== Cut ===
Artis
On Wednesday 27 July 2005 11:36, Chris Williams wrote:
> Hello,
>
> I wrote earlier trying to figure out why I was losing data with YAFFS2,
> thinking I had the settings wrong. Instead it appears that there are a
> couple bugs in the code that interfaces to MTD (assuming that I
> understand everything correctly of course ;) .)
>
> Anyhow, the two issues I was experiencing were that data would be lost
> because all blocks written to would become bad blocks if I reset the
> system (i.e. updated the bad block table), and after solving that, my
> data would be minorly corrupted. Number one was caused by the code in
> nandmtd2_WriteChunkWithTagsToNAND() and
> nandmtd2_ReadChunkWithTagsToNAND() which write and read the tags struct
> from position 0 in the OOB--thus overwriting the bad block marker. The
> second issue (data corruption) was being caused by these same two
> functions which when writing out the tag, write it out as oobsize, so it
> overwrites the MTD ECC with random data that's past the end of the tag
> in memory.
>
> In nandmtd2_WriteChunkWithTagsToNAND()
> - if(tags)
> - retval = mtd->write_oob(mtd,addr, mtd->oobsize,&dummy,(__u8
> *)&pt); + if(tags)
> + retval = mtd->write_oob(mtd,addr + 2, sizeof(pt),&dummy,(__u8
> *)&pt); /* skip two bytes so we don't have to worry about the bad
> block marker */
>
> In nandmtd2_ReadChunkWithTagsToNAND()
> - if(tags)
> - retval =
> mtd->read_oob(mtd,addr,mtd->oobsize,&dummy,dev->spareBuffer);
> + if(tags)
> + retval = mtd->read_oob(mtd,addr +
> 2,sizeof(pt),&dummy,dev->spareBuffer); /* tag data begins two bytes
> into the OOB */
>
> Also, I noticed that the tag ecc is, according to the reference
> material, only supposed to be three bytes, however the structure is
> defined as:
>
> typedef struct
> {
> unsigned char colParity;
> unsigned lineParity; //int
> unsigned lineParityPrime; //int
> } yaffs_ECCOther;
>
> So it is actually being written out as 9 bytes in the OOB, I believe.
>
> -Chris
>
> _______________________________________________
> yaffs mailing list
> yaffs at stoneboat.aleph1.co.uk
> http://stoneboat.aleph1.co.uk/cgi-bin/mailman/listinfo/yaffs
More information about the yaffs
mailing list