summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@cruncher.tec.linutronix.de>2006-05-29 14:56:39 +0200
committerThomas Gleixner <tglx@cruncher.tec.linutronix.de>2006-05-29 15:06:51 +0200
commit9a1fcdfd4bee27c418424cac47abf7c049541297 (patch)
tree5baa5f1e1d1a296a319bf6a5a4b636668c107e00 /drivers
parent[MTD] Rework the out of band handling completely (diff)
downloadlinux-9a1fcdfd4bee27c418424cac47abf7c049541297.tar.xz
linux-9a1fcdfd4bee27c418424cac47abf7c049541297.zip
[MTD] NAND Signal that a bitflip was corrected by ECC
Return -EUCLEAN on read when a bitflip was detected and corrected, so the clients can react and eventually copy the affected block to a spare one. Make all in kernel users aware of the change. Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mtd/inftlcore.c7
-rw-r--r--drivers/mtd/mtdchar.c5
-rw-r--r--drivers/mtd/mtdconcat.c15
-rw-r--r--drivers/mtd/nand/nand_base.c5
-rw-r--r--drivers/mtd/nftlcore.c6
5 files changed, 29 insertions, 9 deletions
diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c
index efb1a95aa0a0..1e21a2c3dd29 100644
--- a/drivers/mtd/inftlcore.c
+++ b/drivers/mtd/inftlcore.c
@@ -355,7 +355,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
ret = mtd->read(mtd, (inftl->EraseSize * BlockMap[block]) +
(block * SECTORSIZE), SECTORSIZE, &retlen,
movebuf);
- if (ret < 0) {
+ if (ret < 0 && ret != -EUCLEAN) {
ret = mtd->read(mtd,
(inftl->EraseSize * BlockMap[block]) +
(block * SECTORSIZE), SECTORSIZE,
@@ -922,7 +922,10 @@ foundit:
} else {
size_t retlen;
loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs;
- if (mtd->read(mtd, ptr, SECTORSIZE, &retlen, buffer))
+ int ret = mtd->read(mtd, ptr, SECTORSIZE, &retlen, buffer);
+
+ /* Handle corrected bit flips gracefully */
+ if (ret < 0 && ret != -EUCLEAN)
return -EIO;
}
return 0;
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index 7522fc3a2827..a48210d58b92 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -199,10 +199,13 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t
/* Nand returns -EBADMSG on ecc errors, but it returns
* the 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.
* Userspace software which accesses NAND this way
* must be aware of the fact that it deals with NAND
*/
- if (!ret || (ret == -EBADMSG)) {
+ if (!ret || (ret == -EUCLEAN) || (ret == -EBADMSG)) {
*ppos += retlen;
if (copy_to_user(buf, kbuf, retlen)) {
kfree(kbuf);
diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c
index 38151b8e6631..3c8d5e6fa010 100644
--- a/drivers/mtd/mtdconcat.c
+++ b/drivers/mtd/mtdconcat.c
@@ -56,7 +56,7 @@ concat_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t * retlen, u_char * buf)
{
struct mtd_concat *concat = CONCAT(mtd);
- int err = -EINVAL;
+ int ret = 0, err = -EINVAL;
int i;
*retlen = 0;
@@ -80,9 +80,18 @@ concat_read(struct mtd_info *mtd, loff_t from, size_t len,
err = subdev->read(subdev, from, size, &retsize, buf);
- if (err)
+ if (err && (err != -EBADMSG) && (err != -EUCLEAN))
break;
+ /* Save information about bitflips! */
+ if (err) {
+ if (err == -EBADMSG)
+ ret = err;
+ else if (!ret)
+ ret = err;
+ err = 0;
+ }
+
*retlen += retsize;
len -= size;
if (len == 0)
@@ -92,7 +101,7 @@ concat_read(struct mtd_info *mtd, loff_t from, size_t len,
buf += size;
from = 0;
}
- return err;
+ return err ? err : ret;
}
static int
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index b8e6e1579cf1..7a3a44907715 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1035,7 +1035,10 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
if (ret)
return ret;
- return mtd->ecc_stats.failed - stats.failed ? -EBADMSG : 0;
+ if (mtd->ecc_stats.failed - stats.failed)
+ return -EBADMSG;
+
+ return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
}
/**
diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c
index f6ffe7949b26..dc7573501d8c 100644
--- a/drivers/mtd/nftlcore.c
+++ b/drivers/mtd/nftlcore.c
@@ -422,7 +422,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
ret = mtd->read(mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512),
512, &retlen, movebuf);
- if (ret < 0) {
+ if (ret < 0 && ret != -EUCLEAN) {
ret = mtd->read(mtd, (nftl->EraseSize * BlockMap[block])
+ (block * 512), 512, &retlen,
movebuf);
@@ -768,7 +768,9 @@ static int nftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,
} else {
loff_t ptr = (lastgoodEUN * nftl->EraseSize) + blockofs;
size_t retlen;
- if (mtd->read(mtd, ptr, 512, &retlen, buffer))
+ int res = mtd->read(mtd, ptr, 512, &retlen, buffer);
+
+ if (res < 0 && res != -EUCLEAN)
return -EIO;
}
return 0;