1. yaffs文件系统中yaffs自身的ECC与MTD的ECC之间联系分析:
从yaffs_mtdif.c文件中的这个函数,可以很容易看出它们的联系:
int nandmtd_ReadChunkFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
size_t dummy;
int retval = 0;
loff_t addr = ((loff_t)chunkInNAND) * dev->nBytesPerChunk;
__u8 *spareAsBytes = (__u8 *)spare;
#ifndef CONFIG_YAFFS_USE_OLD_MTD
if(data && spare)
{
if(dev->useNANDECC) /* 如果配置CONFIG_YAFFS_USE_NANDECC的话,此值为1,否则为0 */
{ // Careful, this call adds 2 ints to the end of the spare data. Calling function should
// allocate enough memory for spare, i.e. [YAFFS_BYTES_PER_SPARE+2*sizeof(int)].
retval = mtd->read_ecc(mtd,addr,dev->nBytesPerChunk,&dummy,data,spareAsBytes,&yaffs_oobinfo);
}
else
{
retval = mtd->read_ecc(mtd,addr,dev->nBytesPerChunk,&dummy,data,spareAsBytes,&yaffs_noeccinfo);
}
}
else
{
#endif
if(data)
retval = mtd->read(mtd,addr,dev->nBytesPerChunk,&dummy,data);
if(spare)
retval = mtd->read_oob(mtd,addr,YAFFS_BYTES_PER_SPARE,&dummy,spareAsBytes);
#ifndef CONFIG_YAFFS_USE_OLD_MTD
}
#endif
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}
上面mtd->read_ecc、mtd->write_ecc在drivers/mtd/nand/nand.c中定义,与ECC有关的代码摘录如下:
// use chip default if zero
if (oobsel == NULL) /* oobsel来自上面mtd->read_ecc调用的最后一个参数 */
oobsel = &mtd->oobinfo;
/* 如果配置CONFIG_YAFFS_USE_NANDECC的话,
* 从mtd->read_ecc传入的oobsel->useecc为1,否则为0
* this->eccmode的值是在nand.c中自己指定的,它确定所指mtd设备使用的ECC类型
*/
eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;
......
switch (eccmode) {
case NAND_ECC_NONE:
this->read_buf(mtd, data_poi, end);
......
break;
case NAND_ECC_SOFT: /* Software ECC 3/256: Read in a page + oob data */
this->read_buf(mtd, data_poi, end);
/* 计算出ECC码 */
this->calculate_ecc(mtd, &data_poi[0], &ecc_calc[0]);
......
break;
case NAND_ECC_HW3_256:
..........
通过硬件机制得到ECC码
..........
}
......
/* OOB里面包含ECC,如果eccmode != NAND_ECC_NONE的话,
* 这些ECC码将和上面计算得到的ECC码进行校验
*/
读OOB
......
/* Skip ECC, if not active */
if (eccmode == NAND_ECC_NONE)
goto readdata;
......
根据ECC进行校验
......
yaffs中的ECC代码有两部分,一是512字节的数据的ECC码,一是OOB里面8字节的tags的ECC码。
1. 对于512字节的数据的ECC码:
以flash上的一个chunk为例,前面512字节存放数据,后面16字节的OOB中,有根据这512字节
数据计算出来的ECC码。当yaffs文件系统需要读出一个chunk数据时,对于不同版本的MTD驱动,有
如下两种方法:
1.1 当在yaffs中配置CONFIG_YAFFS_USE_OLD_MTD时,使用如下语句读出数据,没有MTD的ECC校验。
至于是否作ECC校验,取决于yaffs是否配置CONFIG_YAFFS_USE_NANDECC:
配置了CONFIG_YAFFS_USE_NANDECC,则yaffs自身的ECC功能未使用,所以没有任何ECC校验
未配置CONFIG_YAFFS_USE_NANDECC,则使用yaffs自身的ECC功能
retval = mtd->read(mtd,addr,dev->nBytesPerChunk,&dummy,data);
if(spare)
retval = mtd->read_oob(mtd,addr,YAFFS_BYTES_PER_SPARE,&dummy,spareAsBytes);
1.2 在yaffs中未配置CONFIG_YAFFS_USE_OLD_MTD时,使用如下语句读出数据,要么使用MTD的ECC功能,
要么使用yaffs自身的ECC功能,取决与是否配置CONFIG_YAFFS_USE_NANDECC:
if(dev->useNANDECC)
{ // Careful, this call adds 2 ints to the end of the spare data. Calling function should
// allocate enough memory for spare, i.e. [YAFFS_BYTES_PER_SPARE+2*sizeof(int)].
retval = mtd->read_ecc(mtd,addr,dev->nBytesPerChunk,&dummy,data,spareAsBytes,&yaffs_oobinfo);
}
else
{
retval = mtd->read_ecc(mtd,addr,dev->nBytesPerChunk,&dummy,data,spareAsBytes,&yaffs_noeccinfo);
}
2. 对于OOB里面8字节的tags的ECC码:
使用yaffs自身的ECC功能
ECC总结如下:
1. 使用谁的ECC功能:
CONFIG_YAFFS_USE_OLD_MTD CONFIG_YAFFS_USE_NANDECC 512字节的ECC TAGS的ECC
y y none yaffs
y n yaffs yaffs
n y mtd yaffs
n n yaffs yaffs
2. MTD的ECC功能类型,可以在nand.c中指定某个nand flash使用何种类型的mtd ECC功能:
2.1 NAND_ECC_NONE /* 不使用ECC */
2.2 NAND_ECC_SOFT
2.3 NAND_ECC_HW3_256
2.4 NAND_ECC_HW3_512
2.5 NAND_ECC_HW6_512
2.6 NAND_ECC_DISKONCHIP