Skip to content

Commit

Permalink
mtd: nand: handle ECC errors in OOB
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Brian Norris authored and Artem Bityutskiy committed Sep 11, 2011
1 parent d6137ba commit 041e457
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 1 deletion.
15 changes: 15 additions & 0 deletions drivers/mtd/mtdchar.c
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,21 @@ static int mtd_do_readoob(struct mtd_info *mtd, uint64_t start,
ret = -EFAULT;

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;
}

Expand Down
9 changes: 8 additions & 1 deletion drivers/mtd/nand/nand_base.c
Original file line number Diff line number Diff line change
Expand Up @@ -1750,6 +1750,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
{
int page, realpage, chipnr, sndcmd = 1;
struct nand_chip *chip = mtd->priv;
struct mtd_ecc_stats stats;
int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
int readlen = ops->ooblen;
int len;
Expand All @@ -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",
__func__, (unsigned long long)from, readlen);

stats = mtd->ecc_stats;

if (ops->mode == MTD_OOB_AUTO)
len = chip->ecc.layout->oobavail;
else
Expand Down Expand Up @@ -1828,7 +1831,11 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
}

ops->oobretlen = ops->ooblen;
return 0;

if (mtd->ecc_stats.failed - stats.failed)
return -EBADMSG;

return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
}

/**
Expand Down

0 comments on commit 041e457

Please sign in to comment.