mtd: nand: handle ECC errors in OOB
While the standard NAND OOB functions do not do ECC on the spare area, it is possible for a driver to supply its own OOB ECC functions (e.g., HW ECC). nand_do_read_oob should act like nand_do_read_ops in checking the ECC stats and returning -EBADMSG or -EUCLEAN on uncorrectable errors or correctable bitflips, respectively. These error codes could be used in flash-based BBT code or in YAFFS, for example. Doing this, however, messes with the behavior of mtd_do_readoob. Now, mtd_do_readoob should check whether we had -EUCLEAN or -EBADMSG errors and discard those as "non-fatal" so that the ioctls can still succeed with (possibly uncorrected) data. Signed-off-by: Brian Norris <computersforpeace@gmail.com> Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
This commit is contained in:
parent
d6137badef
commit
041e4575f0
|
@ -473,6 +473,21 @@ static int mtd_do_readoob(struct mtd_info *mtd, uint64_t start,
|
||||||
ret = -EFAULT;
|
ret = -EFAULT;
|
||||||
|
|
||||||
kfree(ops.oobbuf);
|
kfree(ops.oobbuf);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NAND returns -EBADMSG on ECC errors, but it returns the OOB
|
||||||
|
* data. For our userspace tools it is important to dump areas
|
||||||
|
* with ECC errors!
|
||||||
|
* For kernel internal usage it also might return -EUCLEAN
|
||||||
|
* to signal the caller that a bitflip has occured and has
|
||||||
|
* been corrected by the ECC algorithm.
|
||||||
|
*
|
||||||
|
* Note: most NAND ECC algorithms do not calculate ECC
|
||||||
|
* for the OOB area.
|
||||||
|
*/
|
||||||
|
if (ret == -EUCLEAN || ret == -EBADMSG)
|
||||||
|
return 0;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1750,6 +1750,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
|
||||||
{
|
{
|
||||||
int page, realpage, chipnr, sndcmd = 1;
|
int page, realpage, chipnr, sndcmd = 1;
|
||||||
struct nand_chip *chip = mtd->priv;
|
struct nand_chip *chip = mtd->priv;
|
||||||
|
struct mtd_ecc_stats stats;
|
||||||
int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
|
int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
|
||||||
int readlen = ops->ooblen;
|
int readlen = ops->ooblen;
|
||||||
int len;
|
int len;
|
||||||
|
@ -1758,6 +1759,8 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
|
||||||
DEBUG(MTD_DEBUG_LEVEL3, "%s: from = 0x%08Lx, len = %i\n",
|
DEBUG(MTD_DEBUG_LEVEL3, "%s: from = 0x%08Lx, len = %i\n",
|
||||||
__func__, (unsigned long long)from, readlen);
|
__func__, (unsigned long long)from, readlen);
|
||||||
|
|
||||||
|
stats = mtd->ecc_stats;
|
||||||
|
|
||||||
if (ops->mode == MTD_OOB_AUTO)
|
if (ops->mode == MTD_OOB_AUTO)
|
||||||
len = chip->ecc.layout->oobavail;
|
len = chip->ecc.layout->oobavail;
|
||||||
else
|
else
|
||||||
|
@ -1828,7 +1831,11 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
|
||||||
}
|
}
|
||||||
|
|
||||||
ops->oobretlen = ops->ooblen;
|
ops->oobretlen = ops->ooblen;
|
||||||
return 0;
|
|
||||||
|
if (mtd->ecc_stats.failed - stats.failed)
|
||||||
|
return -EBADMSG;
|
||||||
|
|
||||||
|
return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue