aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@cruncher.tec.linutronix.de>2006-05-29 08:56:39 -0400
committerThomas Gleixner <tglx@cruncher.tec.linutronix.de>2006-05-29 09:06:51 -0400
commit9a1fcdfd4bee27c418424cac47abf7c049541297 (patch)
tree5baa5f1e1d1a296a319bf6a5a4b636668c107e00
parent8593fbc68b0df1168995de76d1af38eb62fd6b62 (diff)
[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>
-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
-rw-r--r--fs/jffs2/wbuf.c32
6 files changed, 46 insertions, 24 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
355 ret = mtd->read(mtd, (inftl->EraseSize * BlockMap[block]) + 355 ret = mtd->read(mtd, (inftl->EraseSize * BlockMap[block]) +
356 (block * SECTORSIZE), SECTORSIZE, &retlen, 356 (block * SECTORSIZE), SECTORSIZE, &retlen,
357 movebuf); 357 movebuf);
358 if (ret < 0) { 358 if (ret < 0 && ret != -EUCLEAN) {
359 ret = mtd->read(mtd, 359 ret = mtd->read(mtd,
360 (inftl->EraseSize * BlockMap[block]) + 360 (inftl->EraseSize * BlockMap[block]) +
361 (block * SECTORSIZE), SECTORSIZE, 361 (block * SECTORSIZE), SECTORSIZE,
@@ -922,7 +922,10 @@ foundit:
922 } else { 922 } else {
923 size_t retlen; 923 size_t retlen;
924 loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs; 924 loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs;
925 if (mtd->read(mtd, ptr, SECTORSIZE, &retlen, buffer)) 925 int ret = mtd->read(mtd, ptr, SECTORSIZE, &retlen, buffer);
926
927 /* Handle corrected bit flips gracefully */
928 if (ret < 0 && ret != -EUCLEAN)
926 return -EIO; 929 return -EIO;
927 } 930 }
928 return 0; 931 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
199 /* Nand returns -EBADMSG on ecc errors, but it returns 199 /* Nand returns -EBADMSG on ecc errors, but it returns
200 * the data. For our userspace tools it is important 200 * the data. For our userspace tools it is important
201 * to dump areas with ecc errors ! 201 * to dump areas with ecc errors !
202 * For kernel internal usage it also might return -EUCLEAN
203 * to signal the caller that a bitflip has occured and has
204 * been corrected by the ECC algorithm.
202 * Userspace software which accesses NAND this way 205 * Userspace software which accesses NAND this way
203 * must be aware of the fact that it deals with NAND 206 * must be aware of the fact that it deals with NAND
204 */ 207 */
205 if (!ret || (ret == -EBADMSG)) { 208 if (!ret || (ret == -EUCLEAN) || (ret == -EBADMSG)) {
206 *ppos += retlen; 209 *ppos += retlen;
207 if (copy_to_user(buf, kbuf, retlen)) { 210 if (copy_to_user(buf, kbuf, retlen)) {
208 kfree(kbuf); 211 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,
56 size_t * retlen, u_char * buf) 56 size_t * retlen, u_char * buf)
57{ 57{
58 struct mtd_concat *concat = CONCAT(mtd); 58 struct mtd_concat *concat = CONCAT(mtd);
59 int err = -EINVAL; 59 int ret = 0, err = -EINVAL;
60 int i; 60 int i;
61 61
62 *retlen = 0; 62 *retlen = 0;
@@ -80,9 +80,18 @@ concat_read(struct mtd_info *mtd, loff_t from, size_t len,
80 80
81 err = subdev->read(subdev, from, size, &retsize, buf); 81 err = subdev->read(subdev, from, size, &retsize, buf);
82 82
83 if (err) 83 if (err && (err != -EBADMSG) && (err != -EUCLEAN))
84 break; 84 break;
85 85
86 /* Save information about bitflips! */
87 if (err) {
88 if (err == -EBADMSG)
89 ret = err;
90 else if (!ret)
91 ret = err;
92 err = 0;
93 }
94
86 *retlen += retsize; 95 *retlen += retsize;
87 len -= size; 96 len -= size;
88 if (len == 0) 97 if (len == 0)
@@ -92,7 +101,7 @@ concat_read(struct mtd_info *mtd, loff_t from, size_t len,
92 buf += size; 101 buf += size;
93 from = 0; 102 from = 0;
94 } 103 }
95 return err; 104 return err ? err : ret;
96} 105}
97 106
98static int 107static 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,
1035 if (ret) 1035 if (ret)
1036 return ret; 1036 return ret;
1037 1037
1038 return mtd->ecc_stats.failed - stats.failed ? -EBADMSG : 0; 1038 if (mtd->ecc_stats.failed - stats.failed)
1039 return -EBADMSG;
1040
1041 return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
1039} 1042}
1040 1043
1041/** 1044/**
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
422 422
423 ret = mtd->read(mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512), 423 ret = mtd->read(mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512),
424 512, &retlen, movebuf); 424 512, &retlen, movebuf);
425 if (ret < 0) { 425 if (ret < 0 && ret != -EUCLEAN) {
426 ret = mtd->read(mtd, (nftl->EraseSize * BlockMap[block]) 426 ret = mtd->read(mtd, (nftl->EraseSize * BlockMap[block])
427 + (block * 512), 512, &retlen, 427 + (block * 512), 512, &retlen,
428 movebuf); 428 movebuf);
@@ -768,7 +768,9 @@ static int nftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,
768 } else { 768 } else {
769 loff_t ptr = (lastgoodEUN * nftl->EraseSize) + blockofs; 769 loff_t ptr = (lastgoodEUN * nftl->EraseSize) + blockofs;
770 size_t retlen; 770 size_t retlen;
771 if (mtd->read(mtd, ptr, 512, &retlen, buffer)) 771 int res = mtd->read(mtd, ptr, 512, &retlen, buffer);
772
773 if (res < 0 && res != -EUCLEAN)
772 return -EIO; 774 return -EIO;
773 } 775 }
774 return 0; 776 return 0;
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c
index 1195d06d4373..a7f153f79ecb 100644
--- a/fs/jffs2/wbuf.c
+++ b/fs/jffs2/wbuf.c
@@ -296,10 +296,11 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
296 /* Do the read... */ 296 /* Do the read... */
297 ret = c->mtd->read(c->mtd, start, c->wbuf_ofs - start, &retlen, buf); 297 ret = c->mtd->read(c->mtd, start, c->wbuf_ofs - start, &retlen, buf);
298 298
299 if (ret == -EBADMSG && retlen == c->wbuf_ofs - start) { 299 /* ECC recovered ? */
300 /* ECC recovered */ 300 if ((ret == -EUCLEAN || ret == -EBADMSG) &&
301 (retlen == c->wbuf_ofs - start))
301 ret = 0; 302 ret = 0;
302 } 303
303 if (ret || retlen != c->wbuf_ofs - start) { 304 if (ret || retlen != c->wbuf_ofs - start) {
304 printk(KERN_CRIT "Old data are already lost in wbuf recovery. Data loss ensues.\n"); 305 printk(KERN_CRIT "Old data are already lost in wbuf recovery. Data loss ensues.\n");
305 306
@@ -908,20 +909,21 @@ int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *re
908 down_read(&c->wbuf_sem); 909 down_read(&c->wbuf_sem);
909 ret = c->mtd->read(c->mtd, ofs, len, retlen, buf); 910 ret = c->mtd->read(c->mtd, ofs, len, retlen, buf);
910 911
911 if ( (ret == -EBADMSG) && (*retlen == len) ) { 912 if ( (ret == -EBADMSG || ret == -EUCLEAN) && (*retlen == len) ) {
912 printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n", 913 if (ret == -EBADMSG)
913 len, ofs); 914 printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx)"
915 " returned ECC error\n", len, ofs);
914 /* 916 /*
915 * We have the raw data without ECC correction in the buffer, maybe 917 * We have the raw data without ECC correction in the buffer,
916 * we are lucky and all data or parts are correct. We check the node. 918 * maybe we are lucky and all data or parts are correct. We
917 * If data are corrupted node check will sort it out. 919 * check the node. If data are corrupted node check will sort
918 * We keep this block, it will fail on write or erase and the we 920 * it out. We keep this block, it will fail on write or erase
919 * mark it bad. Or should we do that now? But we should give him a chance. 921 * and the we mark it bad. Or should we do that now? But we
920 * Maybe we had a system crash or power loss before the ecc write or 922 * should give him a chance. Maybe we had a system crash or
921 * a erase was completed. 923 * power loss before the ecc write or a erase was completed.
922 * So we return success. :) 924 * So we return success. :)
923 */ 925 */
924 ret = 0; 926 ret = 0;
925 } 927 }
926 928
927 /* if no writebuffer available or write buffer empty, return */ 929 /* if no writebuffer available or write buffer empty, return */
@@ -943,7 +945,7 @@ int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *re
943 orbf = (c->wbuf_ofs - ofs); /* offset in read buffer */ 945 orbf = (c->wbuf_ofs - ofs); /* offset in read buffer */
944 if (orbf > len) /* is write beyond write buffer ? */ 946 if (orbf > len) /* is write beyond write buffer ? */
945 goto exit; 947 goto exit;
946 lwbf = len - orbf; /* number of bytes to copy */ 948 lwbf = len - orbf; /* number of bytes to copy */
947 if (lwbf > c->wbuf_len) 949 if (lwbf > c->wbuf_len)
948 lwbf = c->wbuf_len; 950 lwbf = c->wbuf_len;
949 } 951 }