On Sunday 24 November 2002 20:00, Nick Bane wrote:
> Well I might offer one more instance - and that relates to yaffs too. That
> is when the fs uses other parts of the oob data and is running on chips
> that only accept two writes to the oob area. Under those circumstances we
> want the fs and not the mtd layer to do the writing assuming that a second
> write to the oob is part of the fs's bad block strategy.
If I understand YAFFS correctly, then the OOB data are written in one go
together with data. So the fs supplies all oob data except ECC and the driver
fills in either SW or HW generated ECC at the appropriate place for the
calling fs. So fs supplied OOB data and ECC are written in one cycle. It's
not a two step procedure.
> Also, if I am being picky, I believe that hardware assisted ecc can be
> implemented where the hardware just does the arithmetic. It is then up to
> the driver to read that data and write it out to the oob. If it *really*
> wanted to, an fs could ignore the results and write something else. This
> would make it reasonable for fs's on different partitions to use/ignore the
> Hardware ECC.
Yep, but I assume, that somebody, who has HW ECC is willing to use it. And all
NAND aware filesystems will use ECC.
I was curious and modified YAFFS to use nand ecc. It works. The modifications
are really small. I copied files around with nandecc enabled and verified it
afterwards with nandecc disabled. Enable/disable is in YAFFS only, not in
nand.c, where NAND_SW_ECC is selected for the hole chip, as I have a JFFS2
root partition on the same chip. This runs on top of current MTD-CVS without
any modification. The NAND driver HW-ECC support is therefore available for
YAFFS out of the box.
A penalty is that I have to copy oob data around on read, because NAND driver
returns 16Byte OOB data and 2 x 4 Byte ECC correction result. This was a
request of Charles, when we discussed some YAFFS issues before I did the big
nand.c overhaul. This behaviour is a subject, which could be changed, as the
only user would be YAFFS at the moment, AFAIK.
A further improvement would be to use the NAND driver write verify function
and skip this function in YAFFS. Therefor the return value from
mtd->write_ecc has to be evaluated inside YAFFS. This would be recommended,
if you intend to use JFFS2 and YAFFS together and want to have the write
verify for both filesystems. At the moment a double checking is done for
YAFFS, if it is enabled in the nand driver. JFFS2 does not support write
verify in the fs layer. It relies on the write verify of the nand driver and
handles the results.
Patch attached.
Jeffrey: Forgive me, that I did not change the if statements. I was to lazy :)
I have added a section about this issue to
http://www.linux-mtd.infradead.org/tech/nand.html.
--
Thomas
____________________________________________________
linutronix - competence in embedded & realtime linux
http://www.linutronix.de
mail:
tglx@linutronix.de
? cvs.diff
Index: Makefile
===================================================================
RCS file: /home/aleph1/cvs/yaffs/Makefile,v
retrieving revision 1.5
diff -u -r1.5 Makefile
--- Makefile 27 Aug 2002 03:31:38 -0000 1.5
+++ Makefile 24 Nov 2002 18:53:27 -0000
@@ -15,7 +15,7 @@
## Change or override KERNELDIR to your kernel
## comment out USE_xxxx if you don't want these features.
-KERNELDIR = /usr/src/kernel-headers-2.4.18
+KERNELDIR = /home/thomas/work/linux
# Configurations...
# Comment out the stuff you don't want.
@@ -25,7 +25,7 @@
# This adds the yaffsram file system support. Nice for testing on x86, but uses 2MB of RAM.
# Don't enable for NAND-based targets.
-USE_RAM_FOR_TEST = -DCONFIG_YAFFS_RAM_ENABLED
+#USE_RAM_FOR_TEST = -DCONFIG_YAFFS_RAM_ENABLED
# CONFIG_YAFFS_MTD_ENABLED.
@@ -33,6 +33,11 @@
USE_MTD = -DCONFIG_YAFFS_MTD_ENABLED
+# CONFIG_YAFFS_USE_NANDECC.
+# This enables the ECC functions of the generic MTD-NAND driver
+
+USE_NANDECC = -DCONFIG_YAFFS_USE_NANDECC
+
# CONFIG_YAFFS_USE_GENERIC_RW
# Use generic_read/generic_write for reading/writing files. This enables the use of the Linux
# file caching layer.
@@ -55,7 +60,7 @@
# this is safe, since the write verification will fail.
# Suggest enabling the test (ie. keep the following line commented) during development to help debug things.
-#IGNORE_CHUNK_ERASED = -DCONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK
+IGNORE_CHUNK_ERASED = -DCONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK
#CONFIG_YAFFS_DISABLE_WRITE_VERIFY
# I am severely reluctant to provide this config. Disabling the verification is not a good thing to do
@@ -67,7 +72,7 @@
# End of configuration options.
-YAFFS_CONFIGS = $(USE_RAM_FOR_TEST) $(USE_MTD) $(USE_GENERIC_RW) $(USE_HEADER_FILE_SIZE) $(IGNORE_CHUNK_ERASED) $(IGNORE_WRITE_VERIFY)
+YAFFS_CONFIGS = $(USE_RAM_FOR_TEST) $(USE_MTD) $(USE_GENERIC_RW) $(USE_HEADER_FILE_SIZE) $(IGNORE_CHUNK_ERASED) $(IGNORE_WRITE_VERIFY) $(USE_NANDECC)
CFLAGS = -D__KERNEL__ -DMODULE $(YAFFS_CONFIGS) -I$(KERNELDIR)/include -O2 -Wall
@@ -78,10 +83,10 @@
all: yaffs.o
$(OBJS): %.o: %.c Makefile
- gcc -c $(CFLAGS) $< -o $@
+ arm-linux-gcc -c $(CFLAGS) $< -o $@
yaffs.o: $(OBJS)
- ld -r $(OBJS) -o $@
+ arm-linux-ld -r $(OBJS) -o $@
clean:
rm -f $(OBJS) core
Index: yaffs_guts.c
===================================================================
RCS file: /home/aleph1/cvs/yaffs/yaffs_guts.c,v
retrieving revision 1.7
diff -u -r1.7 yaffs_guts.c
--- yaffs_guts.c 27 Aug 2002 03:31:38 -0000 1.7
+++ yaffs_guts.c 24 Nov 2002 18:53:32 -0000
@@ -131,14 +131,22 @@
return dev->writeChunkToNAND(dev,chunkInNAND,data,spare);
}
+struct nandspare {
+ yaffs_Spare spare;
+ int eccres1;
+ int eccres2;
+};
int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare,int doErrorCorrection)
{
int retVal;
- __u8 calcEcc[3];
yaffs_Spare localSpare;
+#ifndef CONFIG_YAFFS_USE_NANDECC
+ __u8 calcEcc[3];
int eccResult1,eccResult2;
-
+#else
+ struct nandspare nspare;
+#endif
dev->nPageReads++;
if(!spare && data)
@@ -148,6 +156,8 @@
spare = &localSpare;
}
+
+#ifndef CONFIG_YAFFS_USE_NANDECC
retVal = dev->readChunkFromNAND(dev,chunkInNAND,data,spare);
if(data && doErrorCorrection)
{
@@ -181,7 +191,38 @@
// Hoosterman, we had a data problem on this page
yaffs_HandleReadDataError(dev,chunkInNAND);
}
- }
+ }
+#else
+ retVal = dev->readChunkFromNAND(dev,chunkInNAND,data,(yaffs_Spare*)&nspare);
+ memcpy (spare, &nspare, sizeof(yaffs_Spare));
+ if(data && doErrorCorrection)
+ {
+ if(nspare.eccres1>0)
+ {
+ T((TSTR("**>>ecc error fix performed on chunk %d:0" TENDSTR),chunkInNAND));
+ }
+ else if(nspare.eccres1<0)
+ {
+ T((TSTR("**>>ecc error unfixed on chunk %d:0" TENDSTR),chunkInNAND));
+ }
+
+ if(nspare.eccres2>0)
+ {
+ T((TSTR("**>>ecc error fix performed on chunk %d:1" TENDSTR),chunkInNAND));
+ }
+ else if(nspare.eccres2<0)
+ {
+ T((TSTR("**>>ecc error unfixed on chunk %d:1" TENDSTR),chunkInNAND));
+ }
+
+ if(nspare.eccres2 || nspare.eccres2)
+ {
+ // Hoosterman, we had a data problem on this page
+ yaffs_HandleReadDataError(dev,chunkInNAND);
+ }
+
+ }
+#endif
return retVal;
}
@@ -1956,11 +1997,12 @@
yaffs_SpareInitialise(&spare);
+#ifndef CONFIG_YAFFS_USE_NANDECC
if(buffer)
{
yaffs_CalcECC(buffer,&spare);
}
-
+#endif
yaffs_LoadTagsIntoSpare(&spare,tags);
return yaffs_WriteChunkToNAND(dev,chunkInNAND,buffer,&spare);
@@ -1984,11 +2026,12 @@
yaffs_SpareInitialise(&spare);
+#ifndef CONFIG_YAFFS_USE_NANDECC
if(buffer)
{
yaffs_CalcECC(buffer,&spare);
}
-
+#endif
yaffs_LoadTagsIntoSpare(&spare,tags);
return yaffs_WriteNewChunkToNAND(dev,buffer,&spare,useReserve);
@@ -3731,10 +3774,10 @@
/////////////////// YAFFS test code //////////////////////////////////
-#define yaffs_CheckStruct(structure,syze, name) \
- if(sizeof(structure) != syze) \
- { YPRINTF(("%s should be %d but is %d\n",name,syze,sizeof(structure))); \
- return YAFFS_FAIL; \
+#define yaffs_CheckStruct(structure,syze, name) \
+ if(sizeof(structure) != syze) \
+ { YPRINTF(("%s should be %d but is %d\n",name,syze,sizeof(structure))); \
+ return YAFFS_FAIL; \
}
Index: yaffs_mtdif.c
===================================================================
RCS file: /home/aleph1/cvs/yaffs/yaffs_mtdif.c,v
retrieving revision 1.2
diff -u -r1.2 yaffs_mtdif.c
--- yaffs_mtdif.c 27 Aug 2002 03:31:38 -0000 1.2
+++ yaffs_mtdif.c 24 Nov 2002 18:53:33 -0000
@@ -20,7 +20,7 @@
#include "linux/mtd/mtd.h"
#include "linux/types.h"
-
+#include "linux/mtd/nand.h"
int nandmtd_WriteChunkToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, yaffs_Spare *spare)
{
@@ -32,11 +32,16 @@
__u8 *spareAsBytes = (__u8 *)spare;
- if(data)
+ if(data && !spare)
mtd->write(mtd,addr,YAFFS_BYTES_PER_CHUNK,&dummy,data);
- if(spare)
+ if(!data && spare)
mtd->write_oob(mtd,addr,YAFFS_BYTES_PER_SPARE,&dummy,spareAsBytes);
-
+ if(data && spare)
+#ifdef CONFIG_YAFFS_USE_NANDECC
+ mtd->write_ecc(mtd,addr,YAFFS_BYTES_PER_CHUNK,&dummy,data,spareAsBytes,NAND_YAFFS_OOB);
+#else
+ mtd->write_ecc(mtd,addr,YAFFS_BYTES_PER_CHUNK,&dummy,data,spareAsBytes,NAND_NONE_OOB);
+#endif
return YAFFS_OK;
}
@@ -50,10 +55,16 @@
__u8 *spareAsBytes = (__u8 *)spare;
- if(data)
+ if(data && !spare)
mtd->read(mtd,addr,YAFFS_BYTES_PER_CHUNK,&dummy,data);
- if(spare)
+ if(!data && spare)
mtd->read_oob(mtd,addr,YAFFS_BYTES_PER_SPARE,&dummy,spareAsBytes);
+ if(data && spare)
+#ifdef CONFIG_YAFFS_USE_NANDECC
+ mtd->read_ecc(mtd,addr,YAFFS_BYTES_PER_CHUNK,&dummy,data,spareAsBytes,NAND_YAFFS_OOB);
+#else
+ mtd->read_ecc(mtd,addr,YAFFS_BYTES_PER_CHUNK,&dummy,data,spareAsBytes,NAND_NONE_OOB);
+#endif
return YAFFS_OK;
}