diff options
author | Brian Norris <computersforpeace@gmail.com> | 2011-06-23 19:45:24 -0400 |
---|---|---|
committer | Artem Bityutskiy <artem.bityutskiy@intel.com> | 2011-09-11 08:02:14 -0400 |
commit | 041e4575f03400e045f00a823fcbbbb337de8409 (patch) | |
tree | 3fa062bee497a7ff13d908bf2204de4ec04888da | |
parent | d6137badeff1ef64b4e0092ec249ebdeaeb3ff37 (diff) |
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>
-rw-r--r-- | drivers/mtd/mtdchar.c | 15 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 9 |
2 files changed, 23 insertions, 1 deletions
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index c60067b1f07a..d5924635ead5 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c | |||
@@ -473,6 +473,21 @@ static int mtd_do_readoob(struct mtd_info *mtd, uint64_t start, | |||
473 | ret = -EFAULT; | 473 | ret = -EFAULT; |
474 | 474 | ||
475 | kfree(ops.oobbuf); | 475 | kfree(ops.oobbuf); |
476 | |||
477 | /* | ||
478 | * NAND returns -EBADMSG on ECC errors, but it returns the OOB | ||
479 | * data. For our userspace tools it is important to dump areas | ||
480 | * with ECC errors! | ||
481 | * For kernel internal usage it also might return -EUCLEAN | ||
482 | * to signal the caller that a bitflip has occured and has | ||
483 | * been corrected by the ECC algorithm. | ||
484 | * | ||
485 | * Note: most NAND ECC algorithms do not calculate ECC | ||
486 | * for the OOB area. | ||
487 | */ | ||
488 | if (ret == -EUCLEAN || ret == -EBADMSG) | ||
489 | return 0; | ||
490 | |||
476 | return ret; | 491 | return ret; |
477 | } | 492 | } |
478 | 493 | ||
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 237d7daa189c..5418d27122c4 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c | |||
@@ -1750,6 +1750,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, | |||
1750 | { | 1750 | { |
1751 | int page, realpage, chipnr, sndcmd = 1; | 1751 | int page, realpage, chipnr, sndcmd = 1; |
1752 | struct nand_chip *chip = mtd->priv; | 1752 | struct nand_chip *chip = mtd->priv; |
1753 | struct mtd_ecc_stats stats; | ||
1753 | int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; | 1754 | int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; |
1754 | int readlen = ops->ooblen; | 1755 | int readlen = ops->ooblen; |
1755 | int len; | 1756 | int len; |
@@ -1758,6 +1759,8 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, | |||
1758 | DEBUG(MTD_DEBUG_LEVEL3, "%s: from = 0x%08Lx, len = %i\n", | 1759 | DEBUG(MTD_DEBUG_LEVEL3, "%s: from = 0x%08Lx, len = %i\n", |
1759 | __func__, (unsigned long long)from, readlen); | 1760 | __func__, (unsigned long long)from, readlen); |
1760 | 1761 | ||
1762 | stats = mtd->ecc_stats; | ||
1763 | |||
1761 | if (ops->mode == MTD_OOB_AUTO) | 1764 | if (ops->mode == MTD_OOB_AUTO) |
1762 | len = chip->ecc.layout->oobavail; | 1765 | len = chip->ecc.layout->oobavail; |
1763 | else | 1766 | else |
@@ -1828,7 +1831,11 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, | |||
1828 | } | 1831 | } |
1829 | 1832 | ||
1830 | ops->oobretlen = ops->ooblen; | 1833 | ops->oobretlen = ops->ooblen; |
1831 | return 0; | 1834 | |
1835 | if (mtd->ecc_stats.failed - stats.failed) | ||
1836 | return -EBADMSG; | ||
1837 | |||
1838 | return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; | ||
1832 | } | 1839 | } |
1833 | 1840 | ||
1834 | /** | 1841 | /** |