All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/14] mtd: nand: improve flash-based BBT robustness
@ 2011-09-07 20:13 Brian Norris
  2011-09-07 20:13 ` [PATCH 01/14] mtd: nand: refactor scanning code Brian Norris
                   ` (13 more replies)
  0 siblings, 14 replies; 31+ messages in thread
From: Brian Norris @ 2011-09-07 20:13 UTC (permalink / raw)
  To: Artem Bityutskiy
  Cc: Kevin Cernekee, Matthieu Castet, Jim Quinlan, linux-mtd,
	Brian Norris, David Woodhouse, Matthew Creech

Hello,

This patch series aims to improve the robustness of flash-based bad
block tables, especially their ECC handling. In fact, most of the
patches simply build up to the changes in patch 9 and 10, with some
following bugfixes and improvements that were discovered as a result of
the optimizations.

It's worth noting here the intended block scrubbing policy so that it
can be checked for soundness and for implementation:

*) a BBT page with uncorrected ECC errors is invalid
*) a BBT page with corrected ECC errors is valid but needs scrubbing
   (erased and rewritten with corrected data)

Upon discovering invalid table page(s), we retry our table versioning in
this order:

(1) Mirrored table of same version
(2) Mirrored table of lesser version
(3) Rescan flash for bad blocks

After yielding the most up-to-date table (from table in flash or from
scanning the device), then if the flash-BBT is out of date or needs
scrubbing, the table should be rewritten.

Let me know how any of this works and if there are particular areas
where documentation or explanation is lacking.

Brian

Brian Norris (14):
  mtd: nand: refactor scanning code
  mtd: nand: do not ignore all ECC errors
  mtd: define `is_ecc_error()' macros
  mtd: utilize `is_ecc_error()' macros
  mtd: nand: remove unnecessary variable
  mtd: nand: fix style
  mtd: nand: begin restructuring check_create
  mtd: nand: remove gotos in `check_create()'
  mtd: nand: report ECC errors properly when reading BBT
  mtd: nand: scrub BBT on ECC errors
  mtd: nand: wait to set BBT version
  mtd: nand: do not scan bad blocks with NAND_BBT_NO_OOB set
  mtd: nand: invalidate cache on unaligned reads
  mtd: nand: switch `check_pattern()' to standard `memcmp()'

 drivers/mtd/inftlcore.c             |    4 +-
 drivers/mtd/mtdchar.c               |    4 +-
 drivers/mtd/mtdconcat.c             |    8 +-
 drivers/mtd/mtdoops.c               |    2 +-
 drivers/mtd/mtdpart.c               |    8 +-
 drivers/mtd/mtdswap.c               |   20 ++--
 drivers/mtd/nand/diskonchip.c       |    2 +-
 drivers/mtd/nand/nand_base.c        |   12 ++-
 drivers/mtd/nand/nand_bbt.c         |  198 ++++++++++++++++++-----------------
 drivers/mtd/nftlcore.c              |    4 +-
 drivers/mtd/onenand/onenand_base.c  |   11 +-
 drivers/mtd/sm_ftl.c                |    4 +-
 drivers/mtd/tests/mtd_pagetest.c    |   28 +++---
 drivers/mtd/tests/mtd_readtest.c    |    2 +-
 drivers/mtd/tests/mtd_speedtest.c   |    8 +-
 drivers/mtd/tests/mtd_stresstest.c  |    2 +-
 drivers/mtd/tests/mtd_subpagetest.c |    9 +-
 drivers/mtd/tests/mtd_torturetest.c |    2 +-
 drivers/mtd/ubi/eba.c               |    2 +-
 drivers/mtd/ubi/io.c                |   27 +++--
 drivers/mtd/ubi/kapi.c              |    3 +-
 drivers/mtd/ubi/misc.c              |    2 +-
 drivers/mtd/ubi/scan.c              |    4 +-
 drivers/mtd/ubi/vtbl.c              |    2 +-
 include/linux/mtd/mtd.h             |    5 +
 25 files changed, 198 insertions(+), 175 deletions(-)

-- 
1.7.5.4

^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH 01/14] mtd: nand: refactor scanning code
  2011-09-07 20:13 [PATCH 00/14] mtd: nand: improve flash-based BBT robustness Brian Norris
@ 2011-09-07 20:13 ` Brian Norris
  2011-09-11 13:58   ` Artem Bityutskiy
  2011-09-07 20:13 ` [PATCH 02/14] mtd: nand: do not ignore all ECC errors Brian Norris
                   ` (12 subsequent siblings)
  13 siblings, 1 reply; 31+ messages in thread
From: Brian Norris @ 2011-09-07 20:13 UTC (permalink / raw)
  To: Artem Bityutskiy
  Cc: Kevin Cernekee, Matthieu Castet, Jim Quinlan, linux-mtd,
	Brian Norris, David Woodhouse, Matthew Creech

A few pieces of code are unnecessarily duplicated. For easier
maintenance, we should fix this.

This should have no functional effect.

Signed-off-by: Brian Norris <computersforpeace@gmail.com>
---
 drivers/mtd/nand/nand_bbt.c |   26 +++++++-------------------
 1 files changed, 7 insertions(+), 19 deletions(-)

diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index c488bcb..cbf9b69 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -306,28 +306,16 @@ static int scan_read_raw_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
 	ops.ooboffs = 0;
 	ops.ooblen = mtd->oobsize;
 
-
 	while (len > 0) {
-		if (len <= mtd->writesize) {
-			ops.oobbuf = buf + len;
-			ops.datbuf = buf;
-			ops.len = len;
-			res = mtd->read_oob(mtd, offs, &ops);
-
-			/* Ignore ECC errors when checking for BBM */
-			if (res != -EUCLEAN && res != -EBADMSG)
-				return res;
-			return 0;
-		} else {
-			ops.oobbuf = buf + mtd->writesize;
-			ops.datbuf = buf;
-			ops.len = mtd->writesize;
-			res = mtd->read_oob(mtd, offs, &ops);
+		ops.datbuf = buf;
+		ops.len = min(len, (size_t)mtd->writesize);
+		ops.oobbuf = buf + ops.len;
 
-			/* Ignore ECC errors when checking for BBM */
-			if (res && res != -EUCLEAN && res != -EBADMSG)
-				return res;
-		}
+		res = mtd->read_oob(mtd, offs, &ops);
+
+		/* Ignore ECC errors when checking for BBM */
+		if (res && res != -EUCLEAN && res != -EBADMSG)
+			return res;
 
 		buf += mtd->oobsize + mtd->writesize;
 		len -= mtd->writesize;
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 02/14] mtd: nand: do not ignore all ECC errors
  2011-09-07 20:13 [PATCH 00/14] mtd: nand: improve flash-based BBT robustness Brian Norris
  2011-09-07 20:13 ` [PATCH 01/14] mtd: nand: refactor scanning code Brian Norris
@ 2011-09-07 20:13 ` Brian Norris
  2011-09-11 13:58   ` Artem Bityutskiy
  2011-09-07 20:13 ` [PATCH 03/14] mtd: define `is_ecc_error()' macros Brian Norris
                   ` (11 subsequent siblings)
  13 siblings, 1 reply; 31+ messages in thread
From: Brian Norris @ 2011-09-07 20:13 UTC (permalink / raw)
  To: Artem Bityutskiy
  Cc: Kevin Cernekee, Matthieu Castet, Jim Quinlan, linux-mtd,
	Brian Norris, David Woodhouse, Matthew Creech

There are a few reasons not to ignore ECC errors here.

First, mtd->read_oob is being called in raw mode, so there should be no
error correction in the first place.

Second, if we change this such that there *is* error correction in this
function, then we will want to pass the error message upward.

In fact, the code I introduced to "ignore ECC errors" would have been
better if it had just placed this test down in `scan_block_full()' in
the first place. We would like to ignore ECC errors when we are simply
checking for bad block markers (e.g., factory marked), but we may not
want to ignore ECC errors when scanning OOB for a flash-based BBT
pattern (in `scan_read_raw()'; note that the return codes from
`scan_read_raw()' are not actually handled yet).

Signed-off-by: Brian Norris <computersforpeace@gmail.com>
---
 drivers/mtd/nand/nand_bbt.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index cbf9b69..fcfaf06 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -313,8 +313,7 @@ static int scan_read_raw_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
 
 		res = mtd->read_oob(mtd, offs, &ops);
 
-		/* Ignore ECC errors when checking for BBM */
-		if (res && res != -EUCLEAN && res != -EBADMSG)
+		if (res)
 			return res;
 
 		buf += mtd->oobsize + mtd->writesize;
@@ -400,7 +399,8 @@ static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd,
 	int ret, j;
 
 	ret = scan_read_raw_oob(mtd, buf, offs, readlen);
-	if (ret)
+	/* Ignore ECC errors when checking for BBM */
+	if (ret && ret != -EUCLEAN && ret != -EBADMSG)
 		return ret;
 
 	for (j = 0; j < len; j++, buf += scanlen) {
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 03/14] mtd: define `is_ecc_error()' macros
  2011-09-07 20:13 [PATCH 00/14] mtd: nand: improve flash-based BBT robustness Brian Norris
  2011-09-07 20:13 ` [PATCH 01/14] mtd: nand: refactor scanning code Brian Norris
  2011-09-07 20:13 ` [PATCH 02/14] mtd: nand: do not ignore all ECC errors Brian Norris
@ 2011-09-07 20:13 ` Brian Norris
  2011-09-11 13:57   ` Artem Bityutskiy
  2011-09-07 20:13 ` [PATCH 04/14] mtd: utilize " Brian Norris
                   ` (10 subsequent siblings)
  13 siblings, 1 reply; 31+ messages in thread
From: Brian Norris @ 2011-09-07 20:13 UTC (permalink / raw)
  To: Artem Bityutskiy
  Cc: Kevin Cernekee, Matthieu Castet, Jim Quinlan, linux-mtd,
	Brian Norris, David Woodhouse, Matthew Creech

These macros can be used instead of including -EUCLEAN and -EBADMSG all
over the place. They should help make code a little bit more readable.

Signed-off-by: Brian Norris <computersforpeace@gmail.com>
---
 include/linux/mtd/mtd.h |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index ead70ed..1dd74f4 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -348,4 +348,9 @@ void *mtd_kmalloc_up_to(const struct mtd_info *mtd, size_t *size);
 
 void mtd_erase_callback(struct erase_info *instr);
 
+#define is_corrected_ecc_error(error) (error == -EUCLEAN)
+#define is_uncorrected_ecc_error(error) (error == -EBADMSG)
+#define is_ecc_error(error) ((is_corrected_ecc_error(error) || \
+			      is_uncorrected_ecc_error(error)))
+
 #endif /* __MTD_MTD_H__ */
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 04/14] mtd: utilize `is_ecc_error()' macros
  2011-09-07 20:13 [PATCH 00/14] mtd: nand: improve flash-based BBT robustness Brian Norris
                   ` (2 preceding siblings ...)
  2011-09-07 20:13 ` [PATCH 03/14] mtd: define `is_ecc_error()' macros Brian Norris
@ 2011-09-07 20:13 ` Brian Norris
  2011-09-21  1:34   ` [PATCH v2 04/14] mtd: utilize `mtd_is_*()' functions Brian Norris
  2011-09-07 20:13 ` [PATCH 05/14] mtd: nand: remove unnecessary variable Brian Norris
                   ` (9 subsequent siblings)
  13 siblings, 1 reply; 31+ messages in thread
From: Brian Norris @ 2011-09-07 20:13 UTC (permalink / raw)
  To: Artem Bityutskiy
  Cc: Kevin Cernekee, Matthieu Castet, Jim Quinlan, linux-mtd,
	Brian Norris, David Woodhouse, Matthew Creech

Signed-off-by: Brian Norris <computersforpeace@gmail.com>
---
 drivers/mtd/inftlcore.c             |    4 ++--
 drivers/mtd/mtdchar.c               |    4 ++--
 drivers/mtd/mtdconcat.c             |    8 ++++----
 drivers/mtd/mtdoops.c               |    2 +-
 drivers/mtd/mtdpart.c               |    8 ++++----
 drivers/mtd/mtdswap.c               |   20 ++++++++++----------
 drivers/mtd/nand/diskonchip.c       |    2 +-
 drivers/mtd/nand/nand_bbt.c         |    4 ++--
 drivers/mtd/nftlcore.c              |    4 ++--
 drivers/mtd/onenand/onenand_base.c  |   11 ++++++-----
 drivers/mtd/sm_ftl.c                |    4 ++--
 drivers/mtd/tests/mtd_pagetest.c    |   28 ++++++++++++++--------------
 drivers/mtd/tests/mtd_readtest.c    |    2 +-
 drivers/mtd/tests/mtd_speedtest.c   |    8 ++++----
 drivers/mtd/tests/mtd_stresstest.c  |    2 +-
 drivers/mtd/tests/mtd_subpagetest.c |    9 +++++----
 drivers/mtd/tests/mtd_torturetest.c |    2 +-
 drivers/mtd/ubi/eba.c               |    2 +-
 drivers/mtd/ubi/io.c                |   27 +++++++++++++++------------
 drivers/mtd/ubi/kapi.c              |    3 ++-
 drivers/mtd/ubi/misc.c              |    2 +-
 drivers/mtd/ubi/scan.c              |    4 ++--
 drivers/mtd/ubi/vtbl.c              |    2 +-
 23 files changed, 84 insertions(+), 78 deletions(-)

diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c
index 652065e..ead9913 100644
--- a/drivers/mtd/inftlcore.c
+++ b/drivers/mtd/inftlcore.c
@@ -346,7 +346,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 && ret != -EUCLEAN) {
+		if (ret < 0 && !is_corrected_ecc_error(ret)) {
 			ret = mtd->read(mtd,
 					(inftl->EraseSize * BlockMap[block]) +
 					(block * SECTORSIZE), SECTORSIZE,
@@ -917,7 +917,7 @@ foundit:
 		int ret = mtd->read(mtd, ptr, SECTORSIZE, &retlen, buffer);
 
 		/* Handle corrected bit flips gracefully */
-		if (ret < 0 && ret != -EUCLEAN)
+		if (ret < 0 && !is_corrected_ecc_error(ret))
 			return -EIO;
 	}
 	return 0;
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index 8feb5fd..5960665 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -242,7 +242,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t
 		 * Userspace software which accesses NAND this way
 		 * must be aware of the fact that it deals with NAND
 		 */
-		if (!ret || (ret == -EUCLEAN) || (ret == -EBADMSG)) {
+		if (!ret || is_ecc_error(ret)) {
 			*ppos += retlen;
 			if (copy_to_user(buf, kbuf, retlen)) {
 				kfree(kbuf);
@@ -491,7 +491,7 @@ static int mtd_do_readoob(struct file *file, struct mtd_info *mtd,
 	 * does not calculate ECC for the OOB area, so do not rely on
 	 * this behavior unless you have replaced it with your own.
 	 */
-	if (ret == -EUCLEAN || ret == -EBADMSG)
+	if (is_ecc_error(ret))
 		return 0;
 
 	return ret;
diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c
index d3fabd1..9a730be 100644
--- a/drivers/mtd/mtdconcat.c
+++ b/drivers/mtd/mtdconcat.c
@@ -95,10 +95,10 @@ concat_read(struct mtd_info *mtd, loff_t from, size_t len,
 
 		/* Save information about bitflips! */
 		if (unlikely(err)) {
-			if (err == -EBADMSG) {
+			if (is_uncorrected_ecc_error(err)) {
 				mtd->ecc_stats.failed++;
 				ret = err;
-			} else if (err == -EUCLEAN) {
+			} else if (is_corrected_ecc_error(err)) {
 				mtd->ecc_stats.corrected++;
 				/* Do not overwrite -EBADMSG !! */
 				if (!ret)
@@ -279,10 +279,10 @@ concat_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
 
 		/* Save information about bitflips! */
 		if (unlikely(err)) {
-			if (err == -EBADMSG) {
+			if (is_uncorrected_ecc_error(err)) {
 				mtd->ecc_stats.failed++;
 				ret = err;
-			} else if (err == -EUCLEAN) {
+			} else if (is_corrected_ecc_error(err)) {
 				mtd->ecc_stats.corrected++;
 				/* Do not overwrite -EBADMSG !! */
 				if (!ret)
diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c
index e3e40f4..8243720 100644
--- a/drivers/mtd/mtdoops.c
+++ b/drivers/mtd/mtdoops.c
@@ -258,7 +258,7 @@ static void find_next_position(struct mtdoops_context *cxt)
 		ret = mtd->read(mtd, page * record_size, MTDOOPS_HEADER_SIZE,
 				&retlen, (u_char *) &count[0]);
 		if (retlen != MTDOOPS_HEADER_SIZE ||
-				(ret < 0 && ret != -EUCLEAN)) {
+				(ret < 0 && !is_corrected_ecc_error(ret))) {
 			printk(KERN_ERR "mtdoops: read failure at %ld (%td of %d read), err %d\n",
 			       page * record_size, retlen,
 			       MTDOOPS_HEADER_SIZE, ret);
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index cd7785a..82fecfa 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -73,9 +73,9 @@ static int part_read(struct mtd_info *mtd, loff_t from, size_t len,
 	res = part->master->read(part->master, from + part->offset,
 				   len, retlen, buf);
 	if (unlikely(res)) {
-		if (res == -EUCLEAN)
+		if (is_corrected_ecc_error(res))
 			mtd->ecc_stats.corrected += part->master->ecc_stats.corrected - stats.corrected;
-		if (res == -EBADMSG)
+		if (is_uncorrected_ecc_error(res))
 			mtd->ecc_stats.failed += part->master->ecc_stats.failed - stats.failed;
 	}
 	return res;
@@ -142,9 +142,9 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from,
 
 	res = part->master->read_oob(part->master, from + part->offset, ops);
 	if (unlikely(res)) {
-		if (res == -EUCLEAN)
+		if (is_corrected_ecc_error(res))
 			mtd->ecc_stats.corrected++;
-		if (res == -EBADMSG)
+		if (is_uncorrected_ecc_error(res))
 			mtd->ecc_stats.failed++;
 	}
 	return res;
diff --git a/drivers/mtd/mtdswap.c b/drivers/mtd/mtdswap.c
index 910309f..e72ff61 100644
--- a/drivers/mtd/mtdswap.c
+++ b/drivers/mtd/mtdswap.c
@@ -314,7 +314,7 @@ static int mtdswap_read_oob(struct mtdswap_dev *d, loff_t from,
 {
 	int ret = d->mtd->read_oob(d->mtd, from, ops);
 
-	if (ret == -EUCLEAN)
+	if (is_corrected_ecc_error(ret))
 		return ret;
 
 	if (ret) {
@@ -354,7 +354,7 @@ static int mtdswap_read_markers(struct mtdswap_dev *d, struct swap_eb *eb)
 
 	ret = mtdswap_read_oob(d, offset, &ops);
 
-	if (ret && ret != -EUCLEAN)
+	if (ret && !is_corrected_ecc_error(ret))
 		return ret;
 
 	data = (struct mtdswap_oobdata *)d->oob_buf;
@@ -363,7 +363,7 @@ static int mtdswap_read_markers(struct mtdswap_dev *d, struct swap_eb *eb)
 
 	if (le16_to_cpu(data->magic) == MTDSWAP_MAGIC_CLEAN) {
 		eb->erase_count = le32_to_cpu(data->count);
-		if (ret == -EUCLEAN)
+		if (is_corrected_ecc_error(ret))
 			ret = MTDSWAP_SCANNED_BITFLIP;
 		else {
 			if (le16_to_cpu(data2->magic) == MTDSWAP_MAGIC_DIRTY)
@@ -408,7 +408,7 @@ static int mtdswap_write_marker(struct mtdswap_dev *d, struct swap_eb *eb,
 	if (ret) {
 		dev_warn(d->dev, "Write OOB failed for block at %08llx "
 			"error %d\n", offset, ret);
-		if (ret == -EIO || ret == -EBADMSG)
+		if (ret == -EIO || is_uncorrected_ecc_error(ret))
 			mtdswap_handle_write_error(d, eb);
 		return ret;
 	}
@@ -628,7 +628,7 @@ static int mtdswap_map_free_block(struct mtdswap_dev *d, unsigned int page,
 			TREE_COUNT(d, CLEAN)--;
 
 			ret = mtdswap_write_marker(d, eb, MTDSWAP_TYPE_DIRTY);
-		} while (ret == -EIO || ret == -EBADMSG);
+		} while (ret == -EIO || is_uncorrected_ecc_error(ret));
 
 		if (ret)
 			return ret;
@@ -678,7 +678,7 @@ retry:
 	ret = mtdswap_map_free_block(d, page, bp);
 	eb = d->eb_data + (*bp / d->pages_per_eblk);
 
-	if (ret == -EIO || ret == -EBADMSG) {
+	if (ret == -EIO || is_uncorrected_ecc_error(ret)) {
 		d->curr_write = NULL;
 		eb->active_count--;
 		d->revmap[*bp] = PAGE_UNDEF;
@@ -690,7 +690,7 @@ retry:
 
 	writepos = (loff_t)*bp << PAGE_SHIFT;
 	ret =  mtd->write(mtd, writepos, PAGE_SIZE, &retlen, buf);
-	if (ret == -EIO || ret == -EBADMSG) {
+	if (ret == -EIO || is_uncorrected_ecc_error(ret)) {
 		d->curr_write_pos--;
 		eb->active_count--;
 		d->revmap[*bp] = PAGE_UNDEF;
@@ -738,7 +738,7 @@ static int mtdswap_move_block(struct mtdswap_dev *d, unsigned int oldblock,
 retry:
 	ret = mtd->read(mtd, readpos, PAGE_SIZE, &retlen, d->page_buf);
 
-	if (ret < 0 && ret != -EUCLEAN) {
+	if (ret < 0 && !is_corrected_ecc_error(ret)) {
 		oldeb = d->eb_data + oldblock / d->pages_per_eblk;
 		oldeb->flags |= EBLOCK_READERR;
 
@@ -1016,7 +1016,7 @@ static int mtdswap_gc(struct mtdswap_dev *d, unsigned int background)
 
 	if (ret == 0)
 		mtdswap_rb_add(d, eb, MTDSWAP_CLEAN);
-	else if (ret != -EIO && ret != -EBADMSG)
+	else if (ret != -EIO && !is_uncorrected_ecc_error(ret))
 		mtdswap_rb_add(d, eb, MTDSWAP_DIRTY);
 
 	return 0;
@@ -1164,7 +1164,7 @@ retry:
 	ret = mtd->read(mtd, readpos, PAGE_SIZE, &retlen, buf);
 
 	d->mtd_read_count++;
-	if (ret == -EUCLEAN) {
+	if (is_corrected_ecc_error(ret)) {
 		eb->flags |= EBLOCK_BITFLIP;
 		mtdswap_rb_add(d, eb, MTDSWAP_BITFLIP);
 		ret = 0;
diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c
index de93a98..7e39c10 100644
--- a/drivers/mtd/nand/diskonchip.c
+++ b/drivers/mtd/nand/diskonchip.c
@@ -1031,7 +1031,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat,
 		WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
 	else
 		WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
-	if (no_ecc_failures && (ret == -EBADMSG)) {
+	if (no_ecc_failures && is_uncorrected_ecc_error(ret)) {
 		printk(KERN_ERR "suppressing ECC failure\n");
 		ret = 0;
 	}
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index fcfaf06..03d76c5 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -400,7 +400,7 @@ static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd,
 
 	ret = scan_read_raw_oob(mtd, buf, offs, readlen);
 	/* Ignore ECC errors when checking for BBM */
-	if (ret && ret != -EUCLEAN && ret != -EBADMSG)
+	if (ret && !is_ecc_error(ret))
 		return ret;
 
 	for (j = 0; j < len; j++, buf += scanlen) {
@@ -430,7 +430,7 @@ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,
 		 */
 		ret = mtd->read_oob(mtd, offs, &ops);
 		/* Ignore ECC errors when checking for BBM */
-		if (ret && ret != -EUCLEAN && ret != -EBADMSG)
+		if (ret && !is_ecc_error(ret))
 			return ret;
 
 		if (check_short_pattern(buf, bd))
diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c
index 272e3c0..a22be2d 100644
--- a/drivers/mtd/nftlcore.c
+++ b/drivers/mtd/nftlcore.c
@@ -425,7 +425,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 && ret != -EUCLEAN) {
+		if (ret < 0 && !is_corrected_ecc_error(ret)) {
 			ret = mtd->read(mtd, (nftl->EraseSize * BlockMap[block])
 					+ (block * 512), 512, &retlen,
 					movebuf);
@@ -773,7 +773,7 @@ static int nftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,
 		size_t retlen;
 		int res = mtd->read(mtd, ptr, 512, &retlen, buffer);
 
-		if (res < 0 && res != -EUCLEAN)
+		if (res < 0 && !is_corrected_ecc_error(res))
 			return -EIO;
 	}
 	return 0;
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index 65a8e18..0906b63 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -1079,7 +1079,8 @@ static int onenand_recover_lsb(struct mtd_info *mtd, loff_t addr, int status)
 		return status;
 
 	/* check if we failed due to uncorrectable error */
-	if (status != -EBADMSG && status != ONENAND_BBT_READ_ECC_ERROR)
+	if (!is_uncorrected_ecc_error(status) &&
+			status != ONENAND_BBT_READ_ECC_ERROR)
 		return status;
 
 	/* check if address lies in MLC region */
@@ -1159,7 +1160,7 @@ static int onenand_mlc_read_ops_nolock(struct mtd_info *mtd, loff_t from,
 			if (unlikely(ret))
 				ret = onenand_recover_lsb(mtd, from, ret);
 			onenand_update_bufferram(mtd, from, !ret);
-			if (ret == -EBADMSG)
+			if (is_uncorrected_ecc_error(ret))
 				ret = 0;
 			if (ret)
 				break;
@@ -1255,7 +1256,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
 			this->command(mtd, ONENAND_CMD_READ, from, writesize);
  			ret = this->wait(mtd, FL_READING);
  			onenand_update_bufferram(mtd, from, !ret);
-			if (ret == -EBADMSG)
+			if (is_uncorrected_ecc_error(ret))
 				ret = 0;
  		}
  	}
@@ -1315,7 +1316,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
  		/* Now wait for load */
  		ret = this->wait(mtd, FL_READING);
  		onenand_update_bufferram(mtd, from, !ret);
-		if (ret == -EBADMSG)
+		if (is_uncorrected_ecc_error(ret))
 			ret = 0;
  	}
 
@@ -1403,7 +1404,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
 		if (unlikely(ret))
 			ret = onenand_recover_lsb(mtd, from, ret);
 
-		if (ret && ret != -EBADMSG) {
+		if (ret && !is_uncorrected_ecc_error(ret)) {
 			printk(KERN_ERR "%s: read failed = 0x%x\n",
 				__func__, ret);
 			break;
diff --git a/drivers/mtd/sm_ftl.c b/drivers/mtd/sm_ftl.c
index d927641..63d8946 100644
--- a/drivers/mtd/sm_ftl.c
+++ b/drivers/mtd/sm_ftl.c
@@ -281,7 +281,7 @@ again:
 	ret = mtd->read_oob(mtd, sm_mkoffset(ftl, zone, block, boffset), &ops);
 
 	/* Test for unknown errors */
-	if (ret != 0 && ret != -EUCLEAN && ret != -EBADMSG) {
+	if (ret != 0 && !is_ecc_error(ret)) {
 		dbg("read of block %d at zone %d, failed due to error (%d)",
 			block, zone, ret);
 		goto again;
@@ -306,7 +306,7 @@ again:
 	}
 
 	/* Test ECC*/
-	if (ret == -EBADMSG ||
+	if (is_uncorrected_ecc_error(ret) ||
 		(ftl->smallpagenand && sm_correct_sector(buffer, oob))) {
 
 		dbg("read of block %d at zone %d, failed due to ECC error",
diff --git a/drivers/mtd/tests/mtd_pagetest.c b/drivers/mtd/tests/mtd_pagetest.c
index 00b937e..7518dbd 100644
--- a/drivers/mtd/tests/mtd_pagetest.c
+++ b/drivers/mtd/tests/mtd_pagetest.c
@@ -128,7 +128,7 @@ static int verify_eraseblock(int ebnum)
 	for (j = 0; j < pgcnt - 1; ++j, addr += pgsize) {
 		/* Do a read to set the internal dataRAMs to different data */
 		err = mtd->read(mtd, addr0, bufsize, &read, twopages);
-		if (err == -EUCLEAN)
+		if (is_corrected_ecc_error(err))
 			err = 0;
 		if (err || read != bufsize) {
 			printk(PRINT_PREF "error: read failed at %#llx\n",
@@ -136,7 +136,7 @@ static int verify_eraseblock(int ebnum)
 			return err;
 		}
 		err = mtd->read(mtd, addrn - bufsize, bufsize, &read, twopages);
-		if (err == -EUCLEAN)
+		if (is_corrected_ecc_error(err))
 			err = 0;
 		if (err || read != bufsize) {
 			printk(PRINT_PREF "error: read failed at %#llx\n",
@@ -146,7 +146,7 @@ static int verify_eraseblock(int ebnum)
 		memset(twopages, 0, bufsize);
 		read = 0;
 		err = mtd->read(mtd, addr, bufsize, &read, twopages);
-		if (err == -EUCLEAN)
+		if (is_corrected_ecc_error(err))
 			err = 0;
 		if (err || read != bufsize) {
 			printk(PRINT_PREF "error: read failed at %#llx\n",
@@ -164,7 +164,7 @@ static int verify_eraseblock(int ebnum)
 		unsigned long oldnext = next;
 		/* Do a read to set the internal dataRAMs to different data */
 		err = mtd->read(mtd, addr0, bufsize, &read, twopages);
-		if (err == -EUCLEAN)
+		if (is_corrected_ecc_error(err))
 			err = 0;
 		if (err || read != bufsize) {
 			printk(PRINT_PREF "error: read failed at %#llx\n",
@@ -172,7 +172,7 @@ static int verify_eraseblock(int ebnum)
 			return err;
 		}
 		err = mtd->read(mtd, addrn - bufsize, bufsize, &read, twopages);
-		if (err == -EUCLEAN)
+		if (is_corrected_ecc_error(err))
 			err = 0;
 		if (err || read != bufsize) {
 			printk(PRINT_PREF "error: read failed at %#llx\n",
@@ -182,7 +182,7 @@ static int verify_eraseblock(int ebnum)
 		memset(twopages, 0, bufsize);
 		read = 0;
 		err = mtd->read(mtd, addr, bufsize, &read, twopages);
-		if (err == -EUCLEAN)
+		if (is_corrected_ecc_error(err))
 			err = 0;
 		if (err || read != bufsize) {
 			printk(PRINT_PREF "error: read failed at %#llx\n",
@@ -231,7 +231,7 @@ static int crosstest(void)
 	read = 0;
 	addr = addrn - pgsize - pgsize;
 	err = mtd->read(mtd, addr, pgsize, &read, pp1);
-	if (err == -EUCLEAN)
+	if (is_corrected_ecc_error(err))
 		err = 0;
 	if (err || read != pgsize) {
 		printk(PRINT_PREF "error: read failed at %#llx\n",
@@ -244,7 +244,7 @@ static int crosstest(void)
 	read = 0;
 	addr = addrn - pgsize - pgsize - pgsize;
 	err = mtd->read(mtd, addr, pgsize, &read, pp1);
-	if (err == -EUCLEAN)
+	if (is_corrected_ecc_error(err))
 		err = 0;
 	if (err || read != pgsize) {
 		printk(PRINT_PREF "error: read failed at %#llx\n",
@@ -258,7 +258,7 @@ static int crosstest(void)
 	addr = addr0;
 	printk(PRINT_PREF "reading page at %#llx\n", (long long)addr);
 	err = mtd->read(mtd, addr, pgsize, &read, pp2);
-	if (err == -EUCLEAN)
+	if (is_corrected_ecc_error(err))
 		err = 0;
 	if (err || read != pgsize) {
 		printk(PRINT_PREF "error: read failed at %#llx\n",
@@ -272,7 +272,7 @@ static int crosstest(void)
 	addr = addrn - pgsize;
 	printk(PRINT_PREF "reading page at %#llx\n", (long long)addr);
 	err = mtd->read(mtd, addr, pgsize, &read, pp3);
-	if (err == -EUCLEAN)
+	if (is_corrected_ecc_error(err))
 		err = 0;
 	if (err || read != pgsize) {
 		printk(PRINT_PREF "error: read failed at %#llx\n",
@@ -286,7 +286,7 @@ static int crosstest(void)
 	addr = addr0;
 	printk(PRINT_PREF "reading page at %#llx\n", (long long)addr);
 	err = mtd->read(mtd, addr, pgsize, &read, pp4);
-	if (err == -EUCLEAN)
+	if (is_corrected_ecc_error(err))
 		err = 0;
 	if (err || read != pgsize) {
 		printk(PRINT_PREF "error: read failed at %#llx\n",
@@ -345,7 +345,7 @@ static int erasecrosstest(void)
 	printk(PRINT_PREF "reading 1st page of block %d\n", ebnum);
 	memset(readbuf, 0, pgsize);
 	err = mtd->read(mtd, addr0, pgsize, &read, readbuf);
-	if (err == -EUCLEAN)
+	if (is_corrected_ecc_error(err))
 		err = 0;
 	if (err || read != pgsize) {
 		printk(PRINT_PREF "error: read failed at %#llx\n",
@@ -383,7 +383,7 @@ static int erasecrosstest(void)
 	printk(PRINT_PREF "reading 1st page of block %d\n", ebnum);
 	memset(readbuf, 0, pgsize);
 	err = mtd->read(mtd, addr0, pgsize, &read, readbuf);
-	if (err == -EUCLEAN)
+	if (is_corrected_ecc_error(err))
 		err = 0;
 	if (err || read != pgsize) {
 		printk(PRINT_PREF "error: read failed at %#llx\n",
@@ -439,7 +439,7 @@ static int erasetest(void)
 
 	printk(PRINT_PREF "reading 1st page of block %d\n", ebnum);
 	err = mtd->read(mtd, addr0, pgsize, &read, twopages);
-	if (err == -EUCLEAN)
+	if (is_corrected_ecc_error(err))
 		err = 0;
 	if (err || read != pgsize) {
 		printk(PRINT_PREF "error: read failed at %#llx\n",
diff --git a/drivers/mtd/tests/mtd_readtest.c b/drivers/mtd/tests/mtd_readtest.c
index 587e1e3..60b20ff 100644
--- a/drivers/mtd/tests/mtd_readtest.c
+++ b/drivers/mtd/tests/mtd_readtest.c
@@ -75,7 +75,7 @@ static int read_eraseblock_by_page(int ebnum)
 			ops.datbuf    = NULL;
 			ops.oobbuf    = oobbuf;
 			ret = mtd->read_oob(mtd, addr, &ops);
-			if ((ret && ret != -EUCLEAN) ||
+			if ((ret && !is_corrected_ecc_error(ret)) ||
 					ops.oobretlen != mtd->oobsize) {
 				printk(PRINT_PREF "error: read oob failed at "
 						  "%#llx\n", (long long)addr);
diff --git a/drivers/mtd/tests/mtd_speedtest.c b/drivers/mtd/tests/mtd_speedtest.c
index 627d4e2..2de2c5f 100644
--- a/drivers/mtd/tests/mtd_speedtest.c
+++ b/drivers/mtd/tests/mtd_speedtest.c
@@ -216,7 +216,7 @@ static int read_eraseblock(int ebnum)
 
 	err = mtd->read(mtd, addr, mtd->erasesize, &read, iobuf);
 	/* Ignore corrected ECC errors */
-	if (err == -EUCLEAN)
+	if (is_corrected_ecc_error(err))
 		err = 0;
 	if (err || read != mtd->erasesize) {
 		printk(PRINT_PREF "error: read failed at %#llx\n", addr);
@@ -237,7 +237,7 @@ static int read_eraseblock_by_page(int ebnum)
 	for (i = 0; i < pgcnt; i++) {
 		err = mtd->read(mtd, addr, pgsize, &read, buf);
 		/* Ignore corrected ECC errors */
-		if (err == -EUCLEAN)
+		if (is_corrected_ecc_error(err))
 			err = 0;
 		if (err || read != pgsize) {
 			printk(PRINT_PREF "error: read failed at %#llx\n",
@@ -263,7 +263,7 @@ static int read_eraseblock_by_2pages(int ebnum)
 	for (i = 0; i < n; i++) {
 		err = mtd->read(mtd, addr, sz, &read, buf);
 		/* Ignore corrected ECC errors */
-		if (err == -EUCLEAN)
+		if (is_corrected_ecc_error(err))
 			err = 0;
 		if (err || read != sz) {
 			printk(PRINT_PREF "error: read failed at %#llx\n",
@@ -278,7 +278,7 @@ static int read_eraseblock_by_2pages(int ebnum)
 	if (pgcnt % 2) {
 		err = mtd->read(mtd, addr, pgsize, &read, buf);
 		/* Ignore corrected ECC errors */
-		if (err == -EUCLEAN)
+		if (is_corrected_ecc_error(err))
 			err = 0;
 		if (err || read != pgsize) {
 			printk(PRINT_PREF "error: read failed at %#llx\n",
diff --git a/drivers/mtd/tests/mtd_stresstest.c b/drivers/mtd/tests/mtd_stresstest.c
index 531625f..a2378a1 100644
--- a/drivers/mtd/tests/mtd_stresstest.c
+++ b/drivers/mtd/tests/mtd_stresstest.c
@@ -154,7 +154,7 @@ static int do_read(void)
 	}
 	addr = eb * mtd->erasesize + offs;
 	err = mtd->read(mtd, addr, len, &read, readbuf);
-	if (err == -EUCLEAN)
+	if (is_corrected_ecc_error(err))
 		err = 0;
 	if (unlikely(err || read != len)) {
 		printk(PRINT_PREF "error: read failed at 0x%llx\n",
diff --git a/drivers/mtd/tests/mtd_subpagetest.c b/drivers/mtd/tests/mtd_subpagetest.c
index 334eae5..c36a3a4 100644
--- a/drivers/mtd/tests/mtd_subpagetest.c
+++ b/drivers/mtd/tests/mtd_subpagetest.c
@@ -198,7 +198,7 @@ static int verify_eraseblock(int ebnum)
 	read = 0;
 	err = mtd->read(mtd, addr, subpgsize, &read, readbuf);
 	if (unlikely(err || read != subpgsize)) {
-		if (err == -EUCLEAN && read == subpgsize) {
+		if (is_corrected_ecc_error(err) && read == subpgsize) {
 			printk(PRINT_PREF "ECC correction at %#llx\n",
 			       (long long)addr);
 			err = 0;
@@ -226,7 +226,7 @@ static int verify_eraseblock(int ebnum)
 	read = 0;
 	err = mtd->read(mtd, addr, subpgsize, &read, readbuf);
 	if (unlikely(err || read != subpgsize)) {
-		if (err == -EUCLEAN && read == subpgsize) {
+		if (is_corrected_ecc_error(err) && read == subpgsize) {
 			printk(PRINT_PREF "ECC correction at %#llx\n",
 			       (long long)addr);
 			err = 0;
@@ -264,7 +264,8 @@ static int verify_eraseblock2(int ebnum)
 		read = 0;
 		err = mtd->read(mtd, addr, subpgsize * k, &read, readbuf);
 		if (unlikely(err || read != subpgsize * k)) {
-			if (err == -EUCLEAN && read == subpgsize * k) {
+			if (is_corrected_ecc_error(err) &&
+					read == subpgsize * k) {
 				printk(PRINT_PREF "ECC correction at %#llx\n",
 				       (long long)addr);
 				err = 0;
@@ -298,7 +299,7 @@ static int verify_eraseblock_ff(int ebnum)
 		read = 0;
 		err = mtd->read(mtd, addr, subpgsize, &read, readbuf);
 		if (unlikely(err || read != subpgsize)) {
-			if (err == -EUCLEAN && read == subpgsize) {
+			if (is_corrected_ecc_error(err) && read == subpgsize) {
 				printk(PRINT_PREF "ECC correction at %#llx\n",
 				       (long long)addr);
 				err = 0;
diff --git a/drivers/mtd/tests/mtd_torturetest.c b/drivers/mtd/tests/mtd_torturetest.c
index 5c6c3d2..b9fc132 100644
--- a/drivers/mtd/tests/mtd_torturetest.c
+++ b/drivers/mtd/tests/mtd_torturetest.c
@@ -138,7 +138,7 @@ static inline int check_eraseblock(int ebnum, unsigned char *buf)
 
 retry:
 	err = mtd->read(mtd, addr, len, &read, check_buf);
-	if (err == -EUCLEAN)
+	if (is_corrected_ecc_error(err))
 		printk(PRINT_PREF "single bit flip occurred at EB %d "
 		       "MTD reported that it was fixed.\n", ebnum);
 	else if (err) {
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
index 4be6718..93ee028 100644
--- a/drivers/mtd/ubi/eba.c
+++ b/drivers/mtd/ubi/eba.c
@@ -443,7 +443,7 @@ retry:
 		if (err == UBI_IO_BITFLIPS) {
 			scrub = 1;
 			err = 0;
-		} else if (err == -EBADMSG) {
+		} else if (is_uncorrected_ecc_error(err)) {
 			if (vol->vol_type == UBI_DYNAMIC_VOLUME)
 				goto out_unlock;
 			scrub = 1;
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index 6ba55c2..c01ac06 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -172,9 +172,10 @@ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset,
 retry:
 	err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf);
 	if (err) {
-		const char *errstr = (err == -EBADMSG) ? " (ECC error)" : "";
+		const char *errstr =
+			is_uncorrected_ecc_error(err) ? " (ECC error)" : "";
 
-		if (err == -EUCLEAN) {
+		if (is_corrected_ecc_error(err)) {
 			/*
 			 * -EUCLEAN is reported if there was a bit-flip which
 			 * was corrected, so this is harmless.
@@ -205,7 +206,7 @@ retry:
 		 * all the requested data. But some buggy drivers might do
 		 * this, so we change it to -EIO.
 		 */
-		if (read != len && err == -EBADMSG) {
+		if (read != len && is_uncorrected_ecc_error(err)) {
 			ubi_assert(0);
 			err = -EIO;
 		}
@@ -469,7 +470,7 @@ static int torture_peb(struct ubi_device *ubi, int pnum)
 
 out:
 	mutex_unlock(&ubi->buf_mutex);
-	if (err == UBI_IO_BITFLIPS || err == -EBADMSG) {
+	if (err == UBI_IO_BITFLIPS || is_uncorrected_ecc_error(err)) {
 		/*
 		 * If a bit-flip or data integrity error was detected, the test
 		 * has not passed because it happened on a freshly erased
@@ -760,7 +761,8 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
 
 	read_err = ubi_io_read(ubi, ec_hdr, pnum, 0, UBI_EC_HDR_SIZE);
 	if (read_err) {
-		if (read_err != UBI_IO_BITFLIPS && read_err != -EBADMSG)
+		if (read_err != UBI_IO_BITFLIPS &&
+				!is_uncorrected_ecc_error(read_err))
 			return read_err;
 
 		/*
@@ -776,7 +778,7 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
 
 	magic = be32_to_cpu(ec_hdr->magic);
 	if (magic != UBI_EC_HDR_MAGIC) {
-		if (read_err == -EBADMSG)
+		if (is_uncorrected_ecc_error(read_err))
 			return UBI_IO_BAD_HDR_EBADMSG;
 
 		/*
@@ -1032,12 +1034,13 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
 	p = (char *)vid_hdr - ubi->vid_hdr_shift;
 	read_err = ubi_io_read(ubi, p, pnum, ubi->vid_hdr_aloffset,
 			  ubi->vid_hdr_alsize);
-	if (read_err && read_err != UBI_IO_BITFLIPS && read_err != -EBADMSG)
+	if (read_err && read_err != UBI_IO_BITFLIPS &&
+			!is_uncorrected_ecc_error(read_err))
 		return read_err;
 
 	magic = be32_to_cpu(vid_hdr->magic);
 	if (magic != UBI_VID_HDR_MAGIC) {
-		if (read_err == -EBADMSG)
+		if (is_uncorrected_ecc_error(read_err))
 			return UBI_IO_BAD_HDR_EBADMSG;
 
 		if (ubi_check_pattern(vid_hdr, 0xFF, UBI_VID_HDR_SIZE)) {
@@ -1219,7 +1222,7 @@ static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum)
 		return -ENOMEM;
 
 	err = ubi_io_read(ubi, ec_hdr, pnum, 0, UBI_EC_HDR_SIZE);
-	if (err && err != UBI_IO_BITFLIPS && err != -EBADMSG)
+	if (err && err != UBI_IO_BITFLIPS && !is_uncorrected_ecc_error(err))
 		goto exit;
 
 	crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC);
@@ -1306,7 +1309,7 @@ static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum)
 	p = (char *)vid_hdr - ubi->vid_hdr_shift;
 	err = ubi_io_read(ubi, p, pnum, ubi->vid_hdr_aloffset,
 			  ubi->vid_hdr_alsize);
-	if (err && err != UBI_IO_BITFLIPS && err != -EBADMSG)
+	if (err && err != UBI_IO_BITFLIPS && !is_uncorrected_ecc_error(err))
 		goto exit;
 
 	crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_EC_HDR_SIZE_CRC);
@@ -1358,7 +1361,7 @@ int ubi_dbg_check_write(struct ubi_device *ubi, const void *buf, int pnum,
 	}
 
 	err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf1);
-	if (err && err != -EUCLEAN)
+	if (err && !is_corrected_ecc_error(err))
 		goto out_free;
 
 	for (i = 0; i < len; i++) {
@@ -1422,7 +1425,7 @@ int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len)
 	}
 
 	err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf);
-	if (err && err != -EUCLEAN) {
+	if (err && !is_corrected_ecc_error(err)) {
 		ubi_err("error %d while reading %d bytes from PEB %d:%d, "
 			"read %zd bytes", err, len, pnum, offset, read);
 		goto error;
diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c
index d39716e..9df3c83 100644
--- a/drivers/mtd/ubi/kapi.c
+++ b/drivers/mtd/ubi/kapi.c
@@ -410,7 +410,8 @@ int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
 		return 0;
 
 	err = ubi_eba_read_leb(ubi, vol, lnum, buf, offset, len, check);
-	if (err && err == -EBADMSG && vol->vol_type == UBI_STATIC_VOLUME) {
+	if (err && is_uncorrected_ecc_error(err)
+			&& vol->vol_type == UBI_STATIC_VOLUME) {
 		ubi_warn("mark volume %d as corrupted", vol_id);
 		vol->corrupted = 1;
 	}
diff --git a/drivers/mtd/ubi/misc.c b/drivers/mtd/ubi/misc.c
index ff2a65c..5ec209a 100644
--- a/drivers/mtd/ubi/misc.c
+++ b/drivers/mtd/ubi/misc.c
@@ -81,7 +81,7 @@ int ubi_check_volume(struct ubi_device *ubi, int vol_id)
 
 		err = ubi_eba_read_leb(ubi, vol, i, buf, 0, size, 1);
 		if (err) {
-			if (err == -EBADMSG)
+			if (is_uncorrected_ecc_error(err))
 				err = 1;
 			break;
 		}
diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c
index a3a198f..20d6820 100644
--- a/drivers/mtd/ubi/scan.c
+++ b/drivers/mtd/ubi/scan.c
@@ -395,7 +395,7 @@ static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb,
 	}
 
 	err = ubi_io_read_data(ubi, buf, pnum, 0, len);
-	if (err && err != UBI_IO_BITFLIPS && err != -EBADMSG)
+	if (err && err != UBI_IO_BITFLIPS && !is_uncorrected_ecc_error(err))
 		goto out_free_buf;
 
 	data_crc = be32_to_cpu(vid_hdr->data_crc);
@@ -793,7 +793,7 @@ static int check_corruption(struct ubi_device *ubi, struct ubi_vid_hdr *vid_hdr,
 
 	err = ubi_io_read(ubi, ubi->peb_buf1, pnum, ubi->leb_start,
 			  ubi->leb_size);
-	if (err == UBI_IO_BITFLIPS || err == -EBADMSG) {
+	if (err == UBI_IO_BITFLIPS || is_uncorrected_ecc_error(err)) {
 		/*
 		 * Bit-flips or integrity errors while reading the data area.
 		 * It is difficult to say for sure what type of corruption is
diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c
index 4b50a30..d9a91af 100644
--- a/drivers/mtd/ubi/vtbl.c
+++ b/drivers/mtd/ubi/vtbl.c
@@ -423,7 +423,7 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi,
 
 		err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0,
 				       ubi->vtbl_size);
-		if (err == UBI_IO_BITFLIPS || err == -EBADMSG)
+		if (err == UBI_IO_BITFLIPS || is_uncorrected_ecc_error(err))
 			/*
 			 * Scrub the PEB later. Note, -EBADMSG indicates an
 			 * uncorrectable ECC error, but we have our own CRC and
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 05/14] mtd: nand: remove unnecessary variable
  2011-09-07 20:13 [PATCH 00/14] mtd: nand: improve flash-based BBT robustness Brian Norris
                   ` (3 preceding siblings ...)
  2011-09-07 20:13 ` [PATCH 04/14] mtd: utilize " Brian Norris
@ 2011-09-07 20:13 ` Brian Norris
  2011-09-11 13:58   ` Artem Bityutskiy
  2011-09-07 20:13 ` [PATCH 06/14] mtd: nand: fix style Brian Norris
                   ` (8 subsequent siblings)
  13 siblings, 1 reply; 31+ messages in thread
From: Brian Norris @ 2011-09-07 20:13 UTC (permalink / raw)
  To: Artem Bityutskiy
  Cc: Kevin Cernekee, Matthieu Castet, Jim Quinlan, linux-mtd,
	Brian Norris, David Woodhouse, Matthew Creech

`writeops' is unnecessary in the function `nand_update_bbt()'

Signed-off-by: Brian Norris <computersforpeace@gmail.com>
---
 drivers/mtd/nand/nand_bbt.c |    8 +++-----
 1 files changed, 3 insertions(+), 5 deletions(-)

diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index 03d76c5..b493f51 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -1171,7 +1171,7 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
 int nand_update_bbt(struct mtd_info *mtd, loff_t offs)
 {
 	struct nand_chip *this = mtd->priv;
-	int len, res = 0, writeops = 0;
+	int len, res = 0;
 	int chip, chipsel;
 	uint8_t *buf;
 	struct nand_bbt_descr *td = this->bbt_td;
@@ -1187,8 +1187,6 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs)
 	if (!buf)
 		return -ENOMEM;
 
-	writeops = md != NULL ? 0x03 : 0x01;
-
 	/* Do we have a bbt per chip? */
 	if (td->options & NAND_BBT_PERCHIP) {
 		chip = (int)(offs >> this->chip_shift);
@@ -1203,13 +1201,13 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs)
 		md->version[chip]++;
 
 	/* Write the bad block table to the device? */
-	if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {
+	if (td->options & NAND_BBT_WRITE) {
 		res = write_bbt(mtd, buf, td, md, chipsel);
 		if (res < 0)
 			goto out;
 	}
 	/* Write the mirror bad block table to the device? */
-	if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) {
+	if (md && (md->options & NAND_BBT_WRITE)) {
 		res = write_bbt(mtd, buf, md, td, chipsel);
 	}
 
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 06/14] mtd: nand: fix style
  2011-09-07 20:13 [PATCH 00/14] mtd: nand: improve flash-based BBT robustness Brian Norris
                   ` (4 preceding siblings ...)
  2011-09-07 20:13 ` [PATCH 05/14] mtd: nand: remove unnecessary variable Brian Norris
@ 2011-09-07 20:13 ` Brian Norris
  2011-09-11 14:00   ` Artem Bityutskiy
  2011-09-07 20:13 ` [PATCH 07/14] mtd: nand: begin restructuring check_create Brian Norris
                   ` (7 subsequent siblings)
  13 siblings, 1 reply; 31+ messages in thread
From: Brian Norris @ 2011-09-07 20:13 UTC (permalink / raw)
  To: Artem Bityutskiy
  Cc: Kevin Cernekee, Matthieu Castet, Jim Quinlan, linux-mtd,
	Brian Norris, David Woodhouse, Matthew Creech

Remove some extra spaces
Consistently use '0x' prefix for bitfield-like constants
Spelling: "aplies" -> "applies"

Signed-off-by: Brian Norris <computersforpeace@gmail.com>
---
 drivers/mtd/nand/nand_bbt.c |   28 ++++++++++++++--------------
 1 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index b493f51..cba4c44 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -183,16 +183,16 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
 	size_t retlen, len, totlen;
 	loff_t from;
 	int bits = td->options & NAND_BBT_NRBITS_MSK;
-	uint8_t msk = (uint8_t) ((1 << bits) - 1);
+	uint8_t msk = (uint8_t)((1 << bits) - 1);
 	u32 marker_len;
 	int reserved_block_code = td->reserved_block_code;
 
 	totlen = (num * bits) >> 3;
 	marker_len = add_marker_len(td);
-	from = ((loff_t) page) << this->page_shift;
+	from = ((loff_t)page) << this->page_shift;
 
 	while (totlen) {
-		len = min(totlen, (size_t) (1 << this->bbt_erase_shift));
+		len = min(totlen, (size_t)(1 << this->bbt_erase_shift));
 		if (marker_len) {
 			/*
 			 * In case the BBT marker is not in the OOB area it
@@ -250,7 +250,7 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
  * @mtd: MTD device structure
  * @buf: temporary buffer
  * @td: descriptor for the bad block table
- * @chip: read the table for a specific chip, -1 read all chips; aplies only if
+ * @chip: read the table for a specific chip, -1 read all chips; applies only if
  *        NAND_BBT_PERCHIP option is set
  *
  * Read the bad block table for all chips starting at a given page. We assume
@@ -743,12 +743,12 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
 
 		bbtoffs = chip * (numblocks >> 2);
 
-		to = ((loff_t) page) << this->page_shift;
+		to = ((loff_t)page) << this->page_shift;
 
 		/* Must we save the block contents? */
 		if (td->options & NAND_BBT_SAVECONTENT) {
 			/* Make it block aligned */
-			to &= ~((loff_t) ((1 << this->bbt_erase_shift) - 1));
+			to &= ~((loff_t)((1 << this->bbt_erase_shift) - 1));
 			len = 1 << this->bbt_erase_shift;
 			res = mtd->read(mtd, to, len, &retlen, buf);
 			if (res < 0) {
@@ -771,7 +771,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
 			pageoffs = page - (int)(to >> this->page_shift);
 			offs = pageoffs << this->page_shift;
 			/* Preset the bbt area with 0xff */
-			memset(&buf[offs], 0xff, (size_t) (numblocks >> sft));
+			memset(&buf[offs], 0xff, (size_t)(numblocks >> sft));
 			ooboffs = len + (pageoffs * mtd->oobsize);
 
 		} else if (td->options & NAND_BBT_NO_OOB) {
@@ -781,7 +781,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
 			if (td->options & NAND_BBT_VERSION)
 				offs++;
 			/* Calc length */
-			len = (size_t) (numblocks >> sft);
+			len = (size_t)(numblocks >> sft);
 			len += offs;
 			/* Make it page aligned! */
 			len = ALIGN(len, mtd->writesize);
@@ -791,7 +791,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
 			memcpy(buf, td->pattern, td->len);
 		} else {
 			/* Calc length */
-			len = (size_t) (numblocks >> sft);
+			len = (size_t)(numblocks >> sft);
 			/* Make it page aligned! */
 			len = ALIGN(len, mtd->writesize);
 			/* Preset the buffer with 0xff */
@@ -903,14 +903,14 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
 			if (td->pages[i] == -1) {
 				rd = md;
 				td->version[i] = md->version[i];
-				writeops = 1;
+				writeops = 0x01;
 				goto writecheck;
 			}
 
 			if (md->pages[i] == -1) {
 				rd = td;
 				md->version[i] = td->version[i];
-				writeops = 2;
+				writeops = 0x02;
 				goto writecheck;
 			}
 
@@ -921,14 +921,14 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
 				goto writecheck;
 			}
 
-			if (((int8_t) (td->version[i] - md->version[i])) > 0) {
+			if (((int8_t)(td->version[i] - md->version[i])) > 0) {
 				rd = td;
 				md->version[i] = td->version[i];
-				writeops = 2;
+				writeops = 0x02;
 			} else {
 				rd = md;
 				td->version[i] = md->version[i];
-				writeops = 1;
+				writeops = 0x01;
 			}
 
 			goto writecheck;
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 07/14] mtd: nand: begin restructuring check_create
  2011-09-07 20:13 [PATCH 00/14] mtd: nand: improve flash-based BBT robustness Brian Norris
                   ` (5 preceding siblings ...)
  2011-09-07 20:13 ` [PATCH 06/14] mtd: nand: fix style Brian Norris
@ 2011-09-07 20:13 ` Brian Norris
  2011-09-07 20:13 ` [PATCH 08/14] mtd: nand: remove gotos in `check_create()' Brian Norris
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 31+ messages in thread
From: Brian Norris @ 2011-09-07 20:13 UTC (permalink / raw)
  To: Artem Bityutskiy
  Cc: Kevin Cernekee, Matthieu Castet, Jim Quinlan, linux-mtd,
	Brian Norris, David Woodhouse, Matthew Creech

We will begin restructuring the code for check_create so that we can
make some important changes. For now, we should just begin to get rid of
some goto statements to make things cleaner. This is the first step of a
few, which are separated to make them easier to follow.

This step should just be a code refactor.

Signed-off-by: Brian Norris <computersforpeace@gmail.com>
---
 drivers/mtd/nand/nand_bbt.c |   24 +++++-------------------
 1 files changed, 5 insertions(+), 19 deletions(-)

diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index cba4c44..6b5b2c0 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -898,30 +898,19 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
 			if (td->pages[i] == -1 && md->pages[i] == -1) {
 				writeops = 0x03;
 				goto create;
-			}
-
-			if (td->pages[i] == -1) {
+			} else if (td->pages[i] == -1) {
 				rd = md;
 				td->version[i] = md->version[i];
 				writeops = 0x01;
-				goto writecheck;
-			}
-
-			if (md->pages[i] == -1) {
+			} else if (md->pages[i] == -1) {
 				rd = td;
 				md->version[i] = td->version[i];
 				writeops = 0x02;
-				goto writecheck;
-			}
-
-			if (td->version[i] == md->version[i]) {
+			} else if (td->version[i] == md->version[i]) {
 				rd = td;
 				if (!(td->options & NAND_BBT_VERSION))
 					rd2 = md;
-				goto writecheck;
-			}
-
-			if (((int8_t)(td->version[i] - md->version[i])) > 0) {
+			} else if (((int8_t)(td->version[i] - md->version[i])) > 0) {
 				rd = td;
 				md->version[i] = td->version[i];
 				writeops = 0x02;
@@ -930,17 +919,14 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
 				td->version[i] = md->version[i];
 				writeops = 0x01;
 			}
-
-			goto writecheck;
-
 		} else {
 			if (td->pages[i] == -1) {
 				writeops = 0x01;
 				goto create;
 			}
 			rd = td;
-			goto writecheck;
 		}
+		goto writecheck;
 	create:
 		/* Create the bad block table by scanning the device? */
 		if (!(td->options & NAND_BBT_CREATE))
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 08/14] mtd: nand: remove gotos in `check_create()'
  2011-09-07 20:13 [PATCH 00/14] mtd: nand: improve flash-based BBT robustness Brian Norris
                   ` (6 preceding siblings ...)
  2011-09-07 20:13 ` [PATCH 07/14] mtd: nand: begin restructuring check_create Brian Norris
@ 2011-09-07 20:13 ` Brian Norris
  2011-09-07 20:13 ` [PATCH 09/14] mtd: nand: report ECC errors properly when reading BBT Brian Norris
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 31+ messages in thread
From: Brian Norris @ 2011-09-07 20:13 UTC (permalink / raw)
  To: Artem Bityutskiy
  Cc: Kevin Cernekee, Matthieu Castet, Jim Quinlan, linux-mtd,
	Brian Norris, David Woodhouse, Matthew Creech

This is a second step in restructuring `check_create()'. When we don't
rely on goto statements for our main functionality, the code will become
a little easier to manipulate.

Signed-off-by: Brian Norris <computersforpeace@gmail.com>
---
 drivers/mtd/nand/nand_bbt.c |   39 +++++++++++++++++++++------------------
 1 files changed, 21 insertions(+), 18 deletions(-)

diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index 6b5b2c0..9d4f889 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -875,7 +875,7 @@ static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *b
  */
 static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd)
 {
-	int i, chips, writeops, chipsel, res;
+	int i, chips, writeops, create, chipsel, res;
 	struct nand_chip *this = mtd->priv;
 	struct nand_bbt_descr *td = this->bbt_td;
 	struct nand_bbt_descr *md = this->bbt_md;
@@ -889,6 +889,7 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
 
 	for (i = 0; i < chips; i++) {
 		writeops = 0;
+		create = 0;
 		rd = NULL;
 		rd2 = NULL;
 		/* Per chip or per device? */
@@ -896,8 +897,8 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
 		/* Mirrored table available? */
 		if (md) {
 			if (td->pages[i] == -1 && md->pages[i] == -1) {
+				create = 1;
 				writeops = 0x03;
-				goto create;
 			} else if (td->pages[i] == -1) {
 				rd = md;
 				td->version[i] = md->version[i];
@@ -921,25 +922,27 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
 			}
 		} else {
 			if (td->pages[i] == -1) {
+				create = 1;
 				writeops = 0x01;
-				goto create;
+			} else {
+				rd = td;
 			}
-			rd = td;
 		}
-		goto writecheck;
-	create:
-		/* Create the bad block table by scanning the device? */
-		if (!(td->options & NAND_BBT_CREATE))
-			continue;
 
-		/* Create the table in memory by scanning the chip(s) */
-		if (!(this->bbt_options & NAND_BBT_CREATE_EMPTY))
-			create_bbt(mtd, buf, bd, chipsel);
+		if (create) {
+			/* Create the bad block table by scanning the device? */
+			if (!(td->options & NAND_BBT_CREATE))
+				continue;
+
+			/* Create the table in memory by scanning the chip(s) */
+			if (!(this->bbt_options & NAND_BBT_CREATE_EMPTY))
+				create_bbt(mtd, buf, bd, chipsel);
+
+			td->version[i] = 1;
+			if (md)
+				md->version[i] = 1;
+		}
 
-		td->version[i] = 1;
-		if (md)
-			md->version[i] = 1;
-	writecheck:
 		/* Read back first? */
 		if (rd)
 			read_abs_bbt(mtd, buf, rd, chipsel);
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 09/14] mtd: nand: report ECC errors properly when reading BBT
  2011-09-07 20:13 [PATCH 00/14] mtd: nand: improve flash-based BBT robustness Brian Norris
                   ` (7 preceding siblings ...)
  2011-09-07 20:13 ` [PATCH 08/14] mtd: nand: remove gotos in `check_create()' Brian Norris
@ 2011-09-07 20:13 ` Brian Norris
  2011-09-21  1:35   ` [PATCH v2 " Brian Norris
  2011-09-07 20:13 ` [PATCH 10/14] mtd: nand: scrub BBT on ECC errors Brian Norris
                   ` (4 subsequent siblings)
  13 siblings, 1 reply; 31+ messages in thread
From: Brian Norris @ 2011-09-07 20:13 UTC (permalink / raw)
  To: Artem Bityutskiy
  Cc: Kevin Cernekee, Matthieu Castet, Jim Quinlan, linux-mtd,
	Brian Norris, David Woodhouse, Matthew Creech

Instead of just printing a warning when encountering ECC errors, we
should return a proper error status and print a more informative
warning. Later, we will handle these error messages in the upper layers
of the BBT scan.

Note that this patch makes our check for ECC error codes a little bit
more restrictive, leaving all unrecognized errors to the generic "else"
clause. This shouldn't cause problems and could even be a benefit.

This code is based on some findings reported by Matthieu Castet.

Reported-by: Matthieu CASTET <matthieu.castet@parrot.com>
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
---
 drivers/mtd/nand/nand_bbt.c |   17 ++++++++++++-----
 1 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index 9d4f889..37df614 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -178,7 +178,7 @@ static u32 add_marker_len(struct nand_bbt_descr *td)
 static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
 		struct nand_bbt_descr *td, int offs)
 {
-	int res, i, j, act = 0;
+	int res, ret = 0, i, j, act = 0;
 	struct nand_chip *this = mtd->priv;
 	size_t retlen, len, totlen;
 	loff_t from;
@@ -204,11 +204,18 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
 		}
 		res = mtd->read(mtd, from, len, &retlen, buf);
 		if (res < 0) {
-			if (retlen != len) {
-				pr_info("nand_bbt: error reading bad block table\n");
+			if (is_uncorrected_ecc_error(res)) {
+				pr_info("nand_bbt: ECC error in BBT at "
+					"0x%012llx\n", from & ~mtd->writesize);
+				return res;
+			} else if (is_corrected_ecc_error(res)) {
+				pr_info("nand_bbt: corrected error in BBT at "
+					"0x%012llx\n", from & ~mtd->writesize);
+				ret = res;
+			} else {
+				pr_info("nand_bbt: error reading BBT\n");
 				return res;
 			}
-			pr_warn("nand_bbt: ECC error while reading bad block table\n");
 		}
 
 		/* Analyse data */
@@ -242,7 +249,7 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
 		totlen -= len;
 		from += len;
 	}
-	return 0;
+	return ret;
 }
 
 /**
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 10/14] mtd: nand: scrub BBT on ECC errors
  2011-09-07 20:13 [PATCH 00/14] mtd: nand: improve flash-based BBT robustness Brian Norris
                   ` (8 preceding siblings ...)
  2011-09-07 20:13 ` [PATCH 09/14] mtd: nand: report ECC errors properly when reading BBT Brian Norris
@ 2011-09-07 20:13 ` Brian Norris
  2011-09-21  1:35   ` [PATCH v2 " Brian Norris
  2011-09-07 20:13 ` [PATCH 11/14] mtd: nand: wait to set BBT version Brian Norris
                   ` (3 subsequent siblings)
  13 siblings, 1 reply; 31+ messages in thread
From: Brian Norris @ 2011-09-07 20:13 UTC (permalink / raw)
  To: Artem Bityutskiy
  Cc: Kevin Cernekee, Matthieu Castet, Jim Quinlan, linux-mtd,
	Brian Norris, David Woodhouse, Matthew Creech

Now that `read_bbt()' returns ECC error codes properly, we handle those
codes when checking the integrity of our flash-based BBT.

The modifications can be described by this new policy:

*) On any uncorrected ECC error, we invalidate the corresponding table
   and retry our version-checking integrity logic.
*) On corrected ECC errors, we mark both tables for re-writing to flash
   (a.k.a. scrubbing).

Current integrity checks (i.e., comparing version numbers, etc.) should
take care of all the cases that result in rescanning the device for bad
blocks or falling back to the BBT as found in the mirror descriptor.

Signed-off-by: Brian Norris <computersforpeace@gmail.com>
---
 drivers/mtd/nand/nand_bbt.c |   29 ++++++++++++++++++++++++-----
 1 files changed, 24 insertions(+), 5 deletions(-)

diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index 37df614..cc24119 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -882,7 +882,7 @@ static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *b
  */
 static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd)
 {
-	int i, chips, writeops, create, chipsel, res;
+	int i, chips, writeops, create, chipsel, res, res2;
 	struct nand_chip *this = mtd->priv;
 	struct nand_bbt_descr *td = this->bbt_td;
 	struct nand_bbt_descr *md = this->bbt_md;
@@ -899,6 +899,7 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
 		create = 0;
 		rd = NULL;
 		rd2 = NULL;
+		res = res2 = 0;
 		/* Per chip or per device? */
 		chipsel = (td->options & NAND_BBT_PERCHIP) ? i : -1;
 		/* Mirrored table available? */
@@ -951,11 +952,29 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
 		}
 
 		/* Read back first? */
-		if (rd)
-			read_abs_bbt(mtd, buf, rd, chipsel);
+		if (rd) {
+			res = read_abs_bbt(mtd, buf, rd, chipsel);
+			if (is_uncorrected_ecc_error(res)) {
+				/* Mark table as invalid */
+				rd->pages[i] = -1;
+				i--;
+				continue;
+			}
+		}
 		/* If they weren't versioned, read both */
-		if (rd2)
-			read_abs_bbt(mtd, buf, rd2, chipsel);
+		if (rd2) {
+			res2 = read_abs_bbt(mtd, buf, rd2, chipsel);
+			if (is_uncorrected_ecc_error(res2)) {
+				/* Mark table as invalid */
+				rd2->pages[i] = -1;
+				i--;
+				continue;
+			}
+		}
+
+		/* Scrub the flash table(s)? */
+		if (is_corrected_ecc_error(res) || is_corrected_ecc_error(res2))
+			writeops = 0x03;
 
 		/* Write the bad block table to the device? */
 		if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 11/14] mtd: nand: wait to set BBT version
  2011-09-07 20:13 [PATCH 00/14] mtd: nand: improve flash-based BBT robustness Brian Norris
                   ` (9 preceding siblings ...)
  2011-09-07 20:13 ` [PATCH 10/14] mtd: nand: scrub BBT on ECC errors Brian Norris
@ 2011-09-07 20:13 ` Brian Norris
  2011-09-21  1:35   ` [PATCH v2 " Brian Norris
  2011-09-07 20:13 ` [PATCH 12/14] mtd: nand: do not scan bad blocks with NAND_BBT_NO_OOB set Brian Norris
                   ` (2 subsequent siblings)
  13 siblings, 1 reply; 31+ messages in thread
From: Brian Norris @ 2011-09-07 20:13 UTC (permalink / raw)
  To: Artem Bityutskiy
  Cc: Kevin Cernekee, Matthieu Castet, Jim Quinlan, linux-mtd,
	Brian Norris, David Woodhouse, Matthew Creech

Because there are so many cases of checking, writing, and re-writing of
the bad block table(s), we might as well wait until the we've settled on
a valid, clean copy of the table. This also prevents us from falsely
incrementing the table version. For example, we may have the following:

  Primary table, with version 0x02
  Mirror table, with version 0x01
  Primary table has uncorrectable ECC errors

If we don't have this fix applied, then we will:

  Choose to read the primary table (higher version)
  Set mirror table version to 0x02
  Read back primary table
  Invalidate table because of ECC errors
  Retry readback operation with mirror table, now version 0x02
  Mirrored table reads cleanly
  Writeback BBT to primary table location (with "version 0x02")

However, the mirrored table shouldn't have a new version number.
Instead, we actually want:

  Choose to read the primary table (higher version)
  Read back primary table
  Invalidate table because of ECC errors
  Retry readback with mirror table (version 0x01)
  Mirrored table reads cleanly
  Set both tables to version 0x01
  Writeback BBT to primary table location (version 0x01)

Signed-off-by: Brian Norris <computersforpeace@gmail.com>
---
 drivers/mtd/nand/nand_bbt.c |   12 ++++++++----
 1 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index cc24119..2009fbb 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -909,11 +909,9 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
 				writeops = 0x03;
 			} else if (td->pages[i] == -1) {
 				rd = md;
-				td->version[i] = md->version[i];
 				writeops = 0x01;
 			} else if (md->pages[i] == -1) {
 				rd = td;
-				md->version[i] = td->version[i];
 				writeops = 0x02;
 			} else if (td->version[i] == md->version[i]) {
 				rd = td;
@@ -921,11 +919,9 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
 					rd2 = md;
 			} else if (((int8_t)(td->version[i] - md->version[i])) > 0) {
 				rd = td;
-				md->version[i] = td->version[i];
 				writeops = 0x02;
 			} else {
 				rd = md;
-				td->version[i] = md->version[i];
 				writeops = 0x01;
 			}
 		} else {
@@ -957,6 +953,7 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
 			if (is_uncorrected_ecc_error(res)) {
 				/* Mark table as invalid */
 				rd->pages[i] = -1;
+				rd->version[i] = 0;
 				i--;
 				continue;
 			}
@@ -967,6 +964,7 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
 			if (is_uncorrected_ecc_error(res2)) {
 				/* Mark table as invalid */
 				rd2->pages[i] = -1;
+				rd2->version[i] = 0;
 				i--;
 				continue;
 			}
@@ -976,6 +974,12 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
 		if (is_corrected_ecc_error(res) || is_corrected_ecc_error(res2))
 			writeops = 0x03;
 
+		/* Update version numbers before writing */
+		if (md) {
+			td->version[i] = max(td->version[i], md->version[i]);
+			md->version[i] = td->version[i];
+		}
+
 		/* Write the bad block table to the device? */
 		if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {
 			res = write_bbt(mtd, buf, td, md, chipsel);
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 12/14] mtd: nand: do not scan bad blocks with NAND_BBT_NO_OOB set
  2011-09-07 20:13 [PATCH 00/14] mtd: nand: improve flash-based BBT robustness Brian Norris
                   ` (10 preceding siblings ...)
  2011-09-07 20:13 ` [PATCH 11/14] mtd: nand: wait to set BBT version Brian Norris
@ 2011-09-07 20:13 ` Brian Norris
  2011-09-21  1:36   ` [PATCH v2 " Brian Norris
  2011-09-07 20:13 ` [PATCH 13/14] mtd: nand: invalidate cache on unaligned reads Brian Norris
  2011-09-07 20:13 ` [PATCH 14/14] mtd: nand: switch `check_pattern()' to standard `memcmp()' Brian Norris
  13 siblings, 1 reply; 31+ messages in thread
From: Brian Norris @ 2011-09-07 20:13 UTC (permalink / raw)
  To: Artem Bityutskiy
  Cc: Kevin Cernekee, Matthieu Castet, Jim Quinlan, linux-mtd,
	Brian Norris, David Woodhouse, Matthew Creech

Updates to our default function for creating bad block patterns have
broken the "no OOB" feature. The NAND_BBT_NO_OOB option should not be
set while scanning for bad blocks, but we've been passing all BBT
options from nand_chip.bbt_options to the bad block scan. This causes us
to hit the:

	BUG_ON(bd->options & NAND_BBT_NO_OOB);

in create_bbt() when we scan the flash for bad blocks.

Thus, while it can be legal to set NAND_BBT_NO_OOB in a custom badblock
pattern descriptor (presumably with NAND_BBT_CREATE disabled?), we
should not pass it through in our default function.

Also, to help clarify and emphasize that the function creates bad block
patterns only (not, for example, table descriptors for locating
flash-based BBT), I renamed `nand_create_default_bbt_descr' to
`nand_create_badblock_pattern'.

Signed-off-by: Brian Norris <computersforpeace@gmail.com>
---
 drivers/mtd/nand/nand_bbt.c |   13 +++++++------
 1 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index 2009fbb..26d6a51 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -1294,26 +1294,27 @@ static struct nand_bbt_descr bbt_mirror_no_bbt_descr = {
 	.pattern = mirror_pattern
 };
 
+#define BADBLOCK_SCAN_MASK (~NAND_BBT_NO_OOB)
 /**
- * nand_create_default_bbt_descr - [INTERN] Creates a BBT descriptor structure
+ * nand_create_badblock_pattern - [INTERN] Creates a BBT descriptor structure
  * @this: NAND chip to create descriptor for
  *
  * This function allocates and initializes a nand_bbt_descr for BBM detection
- * based on the properties of "this". The new descriptor is stored in
+ * based on the properties of @this. The new descriptor is stored in
  * this->badblock_pattern. Thus, this->badblock_pattern should be NULL when
  * passed to this function.
  */
-static int nand_create_default_bbt_descr(struct nand_chip *this)
+static int nand_create_badblock_pattern(struct nand_chip *this)
 {
 	struct nand_bbt_descr *bd;
 	if (this->badblock_pattern) {
-		pr_warn("BBT descr already allocated; not replacing\n");
+		pr_warn("Bad block pattern already allocated; not replacing\n");
 		return -EINVAL;
 	}
 	bd = kzalloc(sizeof(*bd), GFP_KERNEL);
 	if (!bd)
 		return -ENOMEM;
-	bd->options = this->bbt_options;
+	bd->options = this->bbt_options & BADBLOCK_SCAN_MASK;
 	bd->offs = this->badblockpos;
 	bd->len = (this->options & NAND_BUSWIDTH_16) ? 2 : 1;
 	bd->pattern = scan_ff_pattern;
@@ -1367,7 +1368,7 @@ int nand_default_bbt(struct mtd_info *mtd)
 	}
 
 	if (!this->badblock_pattern)
-		nand_create_default_bbt_descr(this);
+		nand_create_badblock_pattern(this);
 
 	return nand_scan_bbt(mtd, this->badblock_pattern);
 }
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 13/14] mtd: nand: invalidate cache on unaligned reads
  2011-09-07 20:13 [PATCH 00/14] mtd: nand: improve flash-based BBT robustness Brian Norris
                   ` (11 preceding siblings ...)
  2011-09-07 20:13 ` [PATCH 12/14] mtd: nand: do not scan bad blocks with NAND_BBT_NO_OOB set Brian Norris
@ 2011-09-07 20:13 ` Brian Norris
  2011-09-07 20:13 ` [PATCH 14/14] mtd: nand: switch `check_pattern()' to standard `memcmp()' Brian Norris
  13 siblings, 0 replies; 31+ messages in thread
From: Brian Norris @ 2011-09-07 20:13 UTC (permalink / raw)
  To: Artem Bityutskiy
  Cc: Kevin Cernekee, Matthieu Castet, Jim Quinlan, linux-mtd,
	Brian Norris, David Woodhouse, Matthew Creech

In rare cases, we are given an unaligned parameter `from' in
`nand_do_read_ops()'. In such cases, we use the page cache
(chip->buffers->databuf) as an intermediate buffer before dumping to the
client buffer. However, there are also cases where this buffer is not
cleanly reusable. In those cases, we need to make sure that we
explicitly invalidate the cache.

This patch prevents accidental reusage of the page cache, and for me,
this solves some problems I come across when reading a corrupted BBT
from flash (NAND_BBT_USE_FLASH and NAND_BBT_NO_OOB).

Note: the rare "unaligned" case is a result of the extra BBT pattern +
version located in the data area instead of OOB.

Also, this patch disables caching on raw reads, since we are reading
without error correction. This is, obviously, prone to errors and should
not be cached.

Signed-off-by: Brian Norris <computersforpeace@gmail.com>
---
 drivers/mtd/nand/nand_base.c |   12 ++++++++++--
 1 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index c9767b5..51653d9 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1479,14 +1479,22 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
 			else
 				ret = chip->ecc.read_page(mtd, chip, bufpoi,
 							  page);
-			if (ret < 0)
+			if (ret < 0) {
+				if (!aligned)
+					/* Invalidate page cache */
+					chip->pagebuf = -1;
 				break;
+			}
 
 			/* Transfer not aligned data */
 			if (!aligned) {
 				if (!NAND_SUBPAGE_READ(chip) && !oob &&
-				    !(mtd->ecc_stats.failed - stats.failed))
+				    !(mtd->ecc_stats.failed - stats.failed) &&
+				    (ops->mode != MTD_OPS_RAW))
 					chip->pagebuf = realpage;
+				else
+					/* Invalidate page cache */
+					chip->pagebuf = -1;
 				memcpy(buf, chip->buffers->databuf + col, bytes);
 			}
 
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 14/14] mtd: nand: switch `check_pattern()' to standard `memcmp()'
  2011-09-07 20:13 [PATCH 00/14] mtd: nand: improve flash-based BBT robustness Brian Norris
                   ` (12 preceding siblings ...)
  2011-09-07 20:13 ` [PATCH 13/14] mtd: nand: invalidate cache on unaligned reads Brian Norris
@ 2011-09-07 20:13 ` Brian Norris
  13 siblings, 0 replies; 31+ messages in thread
From: Brian Norris @ 2011-09-07 20:13 UTC (permalink / raw)
  To: Artem Bityutskiy
  Cc: Kevin Cernekee, Matthieu Castet, Jim Quinlan, linux-mtd,
	Brian Norris, David Woodhouse, Matthew Creech

A portion of the `check_pattern()' function is basically a `memcmp()'.
Since it's possible for `memcmp()' to be optimized for a particular
architecture, we should use it instead.

Signed-off-by: Brian Norris <computersforpeace@gmail.com>
---
 drivers/mtd/nand/nand_bbt.c |    6 ++----
 1 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index 26d6a51..6576afb 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -107,10 +107,8 @@ static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_desc
 	p += end;
 
 	/* Compare the pattern */
-	for (i = 0; i < td->len; i++) {
-		if (p[i] != td->pattern[i])
-			return -1;
-	}
+	if (memcmp(p, td->pattern, td->len))
+		return -1;
 
 	if (td->options & NAND_BBT_SCANEMPTY) {
 		p += td->len;
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* Re: [PATCH 03/14] mtd: define `is_ecc_error()' macros
  2011-09-07 20:13 ` [PATCH 03/14] mtd: define `is_ecc_error()' macros Brian Norris
@ 2011-09-11 13:57   ` Artem Bityutskiy
  2011-09-19  4:14     ` Artem Bityutskiy
  0 siblings, 1 reply; 31+ messages in thread
From: Artem Bityutskiy @ 2011-09-11 13:57 UTC (permalink / raw)
  To: Brian Norris
  Cc: Kevin Cernekee, Matthieu Castet, Jim Quinlan, linux-mtd,
	David Woodhouse, Matthew Creech

On Wed, 2011-09-07 at 13:13 -0700, Brian Norris wrote:
> These macros can be used instead of including -EUCLEAN and -EBADMSG all
> over the place. They should help make code a little bit more readable.
> 
> Signed-off-by: Brian Norris <computersforpeace@gmail.com>
> ---
>  include/linux/mtd/mtd.h |    5 +++++
>  1 files changed, 5 insertions(+), 0 deletions(-)
> 
> diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
> index ead70ed..1dd74f4 100644
> --- a/include/linux/mtd/mtd.h
> +++ b/include/linux/mtd/mtd.h
> @@ -348,4 +348,9 @@ void *mtd_kmalloc_up_to(const struct mtd_info *mtd, size_t *size);
>  
>  void mtd_erase_callback(struct erase_info *instr);
>  
> +#define is_corrected_ecc_error(error) (error == -EUCLEAN)

This is not really an error...

> +#define is_uncorrected_ecc_error(error) (error == -EBADMSG)
> +#define is_ecc_error(error) ((is_corrected_ecc_error(error) || \
> +			      is_uncorrected_ecc_error(error)))

Could we please have static inline functions instead of macros?

I think it is nicer to have mtd_ prefixes, how about these names
instead:

mtd_is_bitflip()
mtd_is_eccerr()
mtd_is_bitflip_or_eccerr()

-- 
Best Regards,
Artem Bityutskiy

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 01/14] mtd: nand: refactor scanning code
  2011-09-07 20:13 ` [PATCH 01/14] mtd: nand: refactor scanning code Brian Norris
@ 2011-09-11 13:58   ` Artem Bityutskiy
  0 siblings, 0 replies; 31+ messages in thread
From: Artem Bityutskiy @ 2011-09-11 13:58 UTC (permalink / raw)
  To: Brian Norris
  Cc: Kevin Cernekee, Matthieu Castet, Jim Quinlan, linux-mtd,
	David Woodhouse, Matthew Creech

On Wed, 2011-09-07 at 13:13 -0700, Brian Norris wrote:
> A few pieces of code are unnecessarily duplicated. For easier
> maintenance, we should fix this.
> 
> This should have no functional effect.
> 
> Signed-off-by: Brian Norris <computersforpeace@gmail.com>

Pushed to my tree, thanks!

-- 
Best Regards,
Artem Bityutskiy

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 02/14] mtd: nand: do not ignore all ECC errors
  2011-09-07 20:13 ` [PATCH 02/14] mtd: nand: do not ignore all ECC errors Brian Norris
@ 2011-09-11 13:58   ` Artem Bityutskiy
  0 siblings, 0 replies; 31+ messages in thread
From: Artem Bityutskiy @ 2011-09-11 13:58 UTC (permalink / raw)
  To: Brian Norris
  Cc: Kevin Cernekee, Matthieu Castet, Jim Quinlan, linux-mtd,
	David Woodhouse, Matthew Creech

On Wed, 2011-09-07 at 13:13 -0700, Brian Norris wrote:
> There are a few reasons not to ignore ECC errors here.
> 
> First, mtd->read_oob is being called in raw mode, so there should be no
> error correction in the first place.
> 
> Second, if we change this such that there *is* error correction in this
> function, then we will want to pass the error message upward.
> 
> In fact, the code I introduced to "ignore ECC errors" would have been
> better if it had just placed this test down in `scan_block_full()' in
> the first place. We would like to ignore ECC errors when we are simply
> checking for bad block markers (e.g., factory marked), but we may not
> want to ignore ECC errors when scanning OOB for a flash-based BBT
> pattern (in `scan_read_raw()'; note that the return codes from
> `scan_read_raw()' are not actually handled yet).
> 
> Signed-off-by: Brian Norris <computersforpeace@gmail.com>

Pushed to my tree, thanks!

-- 
Best Regards,
Artem Bityutskiy

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 05/14] mtd: nand: remove unnecessary variable
  2011-09-07 20:13 ` [PATCH 05/14] mtd: nand: remove unnecessary variable Brian Norris
@ 2011-09-11 13:58   ` Artem Bityutskiy
  0 siblings, 0 replies; 31+ messages in thread
From: Artem Bityutskiy @ 2011-09-11 13:58 UTC (permalink / raw)
  To: Brian Norris
  Cc: Kevin Cernekee, Matthieu Castet, Jim Quinlan, linux-mtd,
	David Woodhouse, Matthew Creech

On Wed, 2011-09-07 at 13:13 -0700, Brian Norris wrote:
> `writeops' is unnecessary in the function `nand_update_bbt()'
> 
> Signed-off-by: Brian Norris <computersforpeace@gmail.com>

Pushed to my tree, thanks!

-- 
Best Regards,
Artem Bityutskiy

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 06/14] mtd: nand: fix style
  2011-09-07 20:13 ` [PATCH 06/14] mtd: nand: fix style Brian Norris
@ 2011-09-11 14:00   ` Artem Bityutskiy
  0 siblings, 0 replies; 31+ messages in thread
From: Artem Bityutskiy @ 2011-09-11 14:00 UTC (permalink / raw)
  To: Brian Norris
  Cc: Kevin Cernekee, Matthieu Castet, Jim Quinlan, linux-mtd,
	David Woodhouse, Matthew Creech

On Wed, 2011-09-07 at 13:13 -0700, Brian Norris wrote:
> Remove some extra spaces
> Consistently use '0x' prefix for bitfield-like constants
> Spelling: "aplies" -> "applies"
> 
> Signed-off-by: Brian Norris <computersforpeace@gmail.com>

Pushed this one to my tree as well, thanks!

-- 
Best Regards,
Artem Bityutskiy

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 03/14] mtd: define `is_ecc_error()' macros
  2011-09-11 13:57   ` Artem Bityutskiy
@ 2011-09-19  4:14     ` Artem Bityutskiy
  2011-09-19 18:43       ` Brian Norris
  0 siblings, 1 reply; 31+ messages in thread
From: Artem Bityutskiy @ 2011-09-19  4:14 UTC (permalink / raw)
  To: Brian Norris
  Cc: Kevin Cernekee, Matthieu Castet, Jim Quinlan, linux-mtd,
	David Woodhouse, Matthew Creech

On Sun, 2011-09-11 at 16:57 +0300, Artem Bityutskiy wrote:
> > +#define is_corrected_ecc_error(error) (error == -EUCLEAN)
> 
> This is not really an error...
> 
> > +#define is_uncorrected_ecc_error(error) (error == -EBADMSG)
> > +#define is_ecc_error(error) ((is_corrected_ecc_error(error) || \
> > +			      is_uncorrected_ecc_error(error)))
> 
> Could we please have static inline functions instead of macros?
> 
> I think it is nicer to have mtd_ prefixes, how about these names
> instead:
> 
> mtd_is_bitflip()
> mtd_is_eccerr()
> mtd_is_bitflip_or_eccerr()

Brian, I was actually waiting for v2 of the patches: 3/14, and
9/14-14/14.

-- 
Best Regards,
Artem Bityutskiy

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 03/14] mtd: define `is_ecc_error()' macros
  2011-09-19  4:14     ` Artem Bityutskiy
@ 2011-09-19 18:43       ` Brian Norris
  2011-09-20  7:19         ` Artem Bityutskiy
  0 siblings, 1 reply; 31+ messages in thread
From: Brian Norris @ 2011-09-19 18:43 UTC (permalink / raw)
  To: dedekind1
  Cc: Kevin Cernekee, Matthieu Castet, Jim Quinlan, linux-mtd,
	David Woodhouse, Matthew Creech

On Sun, Sep 18, 2011 at 9:14 PM, Artem Bityutskiy <dedekind1@gmail.com> wrote:
> On Sun, 2011-09-11 at 16:57 +0300, Artem Bityutskiy wrote:
>> > +#define is_corrected_ecc_error(error) (error == -EUCLEAN)
>>
>> This is not really an error...

I suppose I was just considering the names as describing the error
code, even if it's not fully an error.

>> > +#define is_uncorrected_ecc_error(error) (error == -EBADMSG)
>> > +#define is_ecc_error(error) ((is_corrected_ecc_error(error) || \
>> > +                         is_uncorrected_ecc_error(error)))
>>
>> Could we please have static inline functions instead of macros?

Of course we can! Is there a particular reason? Better type checking?
Or just kernel style? I don't think I see a code-size benefit...

>> I think it is nicer to have mtd_ prefixes, how about these names
>> instead:
>>
>> mtd_is_bitflip()
>> mtd_is_eccerr()
>> mtd_is_bitflip_or_eccerr()
>
> Brian, I was actually waiting for v2 of the patches: 3/14, and
> 9/14-14/14.

Right, I hadn't settled on a name yet and so I haven't rewritten the patches.

I like the fact that your names are shorter. I'm not sure about
`mtd_is_bitflip_or_eccerr()', though; the compound name seems a little
out of place. But maybe it's just better to be clear on exactly what
is covered by the function. Is there a broad category name for
bitflips/ECC errors? I just consider them corrected/uncorrected errors
in flash, thus the naming I gave.

I'll either repost with a better naming scheme or update my patches
with the suggested names.

Brian

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 03/14] mtd: define `is_ecc_error()' macros
  2011-09-19 18:43       ` Brian Norris
@ 2011-09-20  7:19         ` Artem Bityutskiy
  2011-09-21  1:30           ` [PATCH v2 03/14] mtd: define `mtd_is_*()' functions Brian Norris
  2011-09-21  1:40           ` [PATCH 03/14] mtd: define `is_ecc_error()' macros Brian Norris
  0 siblings, 2 replies; 31+ messages in thread
From: Artem Bityutskiy @ 2011-09-20  7:19 UTC (permalink / raw)
  To: Brian Norris
  Cc: Kevin Cernekee, Matthieu Castet, Jim Quinlan, linux-mtd,
	David Woodhouse, Matthew Creech

On Mon, 2011-09-19 at 11:43 -0700, Brian Norris wrote:
> Right, I hadn't settled on a name yet and so I haven't rewritten the patches.
> 
> I like the fact that your names are shorter. I'm not sure about
> `mtd_is_bitflip_or_eccerr()', though; the compound name seems a little
> out of place. But maybe it's just better to be clear on exactly what
> is covered by the function. Is there a broad category name for
> bitflips/ECC errors? I just consider them corrected/uncorrected errors
> in flash, thus the naming I gave.
> 
> I'll either repost with a better naming scheme or update my patches
> with the suggested names.

OK, let's do this sooner than later please, to make sure I have all your
work in my tree, which is safer (consider the situation when dwmw2 picks
what I have now and upstreams before we put everything in).

-- 
Best Regards,
Artem Bityutskiy

^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH v2 03/14] mtd: define `mtd_is_*()' functions
  2011-09-20  7:19         ` Artem Bityutskiy
@ 2011-09-21  1:30           ` Brian Norris
  2011-09-21  1:40           ` [PATCH 03/14] mtd: define `is_ecc_error()' macros Brian Norris
  1 sibling, 0 replies; 31+ messages in thread
From: Brian Norris @ 2011-09-21  1:30 UTC (permalink / raw)
  To: Artem Bityutskiy
  Cc: Kevin Cernekee, Brian Norris, linux-mtd, David Woodhouse,
	Matthieu Castet

These functions can be used instead of referencing -EUCLEAN and -EBADMSG
all over the place. They should help make code a little bit more
readable.

Signed-off-by: Brian Norris <computersforpeace@gmail.com>
---
v2: use static inline functions, change names to `mtd_is_*' prefix,
    don't call bitflips "errors"

 include/linux/mtd/mtd.h |   12 ++++++++++++
 1 files changed, 12 insertions(+), 0 deletions(-)

diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 37d0827..4bce1eb 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -348,4 +348,16 @@ void *mtd_kmalloc_up_to(const struct mtd_info *mtd, size_t *size);
 
 void mtd_erase_callback(struct erase_info *instr);
 
+static inline int mtd_is_bitflip(int err) {
+	return err == -EUCLEAN;
+}
+
+static inline int mtd_is_eccerr(int err) {
+	return err == -EBADMSG;
+}
+
+static inline int mtd_is_bitflip_or_eccerr(int err) {
+	return mtd_is_bitflip(err) || mtd_is_eccerr(err);
+}
+
 #endif /* __MTD_MTD_H__ */
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v2 04/14] mtd: utilize `mtd_is_*()' functions
  2011-09-07 20:13 ` [PATCH 04/14] mtd: utilize " Brian Norris
@ 2011-09-21  1:34   ` Brian Norris
  0 siblings, 0 replies; 31+ messages in thread
From: Brian Norris @ 2011-09-21  1:34 UTC (permalink / raw)
  To: Artem Bityutskiy
  Cc: Kevin Cernekee, Brian Norris, linux-mtd, David Woodhouse,
	Matthieu Castet

Signed-off-by: Brian Norris <computersforpeace@gmail.com>
---
v2: change to `mtd_is_*' prefix

 drivers/mtd/inftlcore.c             |    4 ++--
 drivers/mtd/mtdchar.c               |    4 ++--
 drivers/mtd/mtdconcat.c             |    8 ++++----
 drivers/mtd/mtdoops.c               |    2 +-
 drivers/mtd/mtdpart.c               |    8 ++++----
 drivers/mtd/mtdswap.c               |   20 ++++++++++----------
 drivers/mtd/nand/diskonchip.c       |    2 +-
 drivers/mtd/nand/nand_bbt.c         |    4 ++--
 drivers/mtd/nftlcore.c              |    4 ++--
 drivers/mtd/onenand/onenand_base.c  |   10 +++++-----
 drivers/mtd/sm_ftl.c                |    4 ++--
 drivers/mtd/tests/mtd_pagetest.c    |   28 ++++++++++++++--------------
 drivers/mtd/tests/mtd_readtest.c    |    2 +-
 drivers/mtd/tests/mtd_speedtest.c   |    8 ++++----
 drivers/mtd/tests/mtd_stresstest.c  |    2 +-
 drivers/mtd/tests/mtd_subpagetest.c |    8 ++++----
 drivers/mtd/tests/mtd_torturetest.c |    2 +-
 drivers/mtd/ubi/eba.c               |    2 +-
 drivers/mtd/ubi/io.c                |   24 ++++++++++++------------
 drivers/mtd/ubi/kapi.c              |    2 +-
 drivers/mtd/ubi/misc.c              |    2 +-
 drivers/mtd/ubi/scan.c              |    4 ++--
 drivers/mtd/ubi/vtbl.c              |    2 +-
 23 files changed, 78 insertions(+), 78 deletions(-)

diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c
index 652065e..dd034ef 100644
--- a/drivers/mtd/inftlcore.c
+++ b/drivers/mtd/inftlcore.c
@@ -346,7 +346,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 && ret != -EUCLEAN) {
+		if (ret < 0 && !mtd_is_bitflip(ret)) {
 			ret = mtd->read(mtd,
 					(inftl->EraseSize * BlockMap[block]) +
 					(block * SECTORSIZE), SECTORSIZE,
@@ -917,7 +917,7 @@ foundit:
 		int ret = mtd->read(mtd, ptr, SECTORSIZE, &retlen, buffer);
 
 		/* Handle corrected bit flips gracefully */
-		if (ret < 0 && ret != -EUCLEAN)
+		if (ret < 0 && !mtd_is_bitflip(ret))
 			return -EIO;
 	}
 	return 0;
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index 8feb5fd..47be6e5 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -242,7 +242,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t
 		 * Userspace software which accesses NAND this way
 		 * must be aware of the fact that it deals with NAND
 		 */
-		if (!ret || (ret == -EUCLEAN) || (ret == -EBADMSG)) {
+		if (!ret || mtd_is_bitflip_or_eccerr(ret)) {
 			*ppos += retlen;
 			if (copy_to_user(buf, kbuf, retlen)) {
 				kfree(kbuf);
@@ -491,7 +491,7 @@ static int mtd_do_readoob(struct file *file, struct mtd_info *mtd,
 	 * does not calculate ECC for the OOB area, so do not rely on
 	 * this behavior unless you have replaced it with your own.
 	 */
-	if (ret == -EUCLEAN || ret == -EBADMSG)
+	if (mtd_is_bitflip_or_eccerr(ret))
 		return 0;
 
 	return ret;
diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c
index d3fabd1..6df4d4d 100644
--- a/drivers/mtd/mtdconcat.c
+++ b/drivers/mtd/mtdconcat.c
@@ -95,10 +95,10 @@ concat_read(struct mtd_info *mtd, loff_t from, size_t len,
 
 		/* Save information about bitflips! */
 		if (unlikely(err)) {
-			if (err == -EBADMSG) {
+			if (mtd_is_eccerr(err)) {
 				mtd->ecc_stats.failed++;
 				ret = err;
-			} else if (err == -EUCLEAN) {
+			} else if (mtd_is_bitflip(err)) {
 				mtd->ecc_stats.corrected++;
 				/* Do not overwrite -EBADMSG !! */
 				if (!ret)
@@ -279,10 +279,10 @@ concat_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
 
 		/* Save information about bitflips! */
 		if (unlikely(err)) {
-			if (err == -EBADMSG) {
+			if (mtd_is_eccerr(err)) {
 				mtd->ecc_stats.failed++;
 				ret = err;
-			} else if (err == -EUCLEAN) {
+			} else if (mtd_is_bitflip(err)) {
 				mtd->ecc_stats.corrected++;
 				/* Do not overwrite -EBADMSG !! */
 				if (!ret)
diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c
index e3e40f4..1e2fa62 100644
--- a/drivers/mtd/mtdoops.c
+++ b/drivers/mtd/mtdoops.c
@@ -258,7 +258,7 @@ static void find_next_position(struct mtdoops_context *cxt)
 		ret = mtd->read(mtd, page * record_size, MTDOOPS_HEADER_SIZE,
 				&retlen, (u_char *) &count[0]);
 		if (retlen != MTDOOPS_HEADER_SIZE ||
-				(ret < 0 && ret != -EUCLEAN)) {
+				(ret < 0 && !mtd_is_bitflip(ret))) {
 			printk(KERN_ERR "mtdoops: read failure at %ld (%td of %d read), err %d\n",
 			       page * record_size, retlen,
 			       MTDOOPS_HEADER_SIZE, ret);
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index cd7785a..a0bd2de 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -73,9 +73,9 @@ static int part_read(struct mtd_info *mtd, loff_t from, size_t len,
 	res = part->master->read(part->master, from + part->offset,
 				   len, retlen, buf);
 	if (unlikely(res)) {
-		if (res == -EUCLEAN)
+		if (mtd_is_bitflip(res))
 			mtd->ecc_stats.corrected += part->master->ecc_stats.corrected - stats.corrected;
-		if (res == -EBADMSG)
+		if (mtd_is_eccerr(res))
 			mtd->ecc_stats.failed += part->master->ecc_stats.failed - stats.failed;
 	}
 	return res;
@@ -142,9 +142,9 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from,
 
 	res = part->master->read_oob(part->master, from + part->offset, ops);
 	if (unlikely(res)) {
-		if (res == -EUCLEAN)
+		if (mtd_is_bitflip(res))
 			mtd->ecc_stats.corrected++;
-		if (res == -EBADMSG)
+		if (mtd_is_eccerr(res))
 			mtd->ecc_stats.failed++;
 	}
 	return res;
diff --git a/drivers/mtd/mtdswap.c b/drivers/mtd/mtdswap.c
index 910309f..bd9590c 100644
--- a/drivers/mtd/mtdswap.c
+++ b/drivers/mtd/mtdswap.c
@@ -314,7 +314,7 @@ static int mtdswap_read_oob(struct mtdswap_dev *d, loff_t from,
 {
 	int ret = d->mtd->read_oob(d->mtd, from, ops);
 
-	if (ret == -EUCLEAN)
+	if (mtd_is_bitflip(ret))
 		return ret;
 
 	if (ret) {
@@ -354,7 +354,7 @@ static int mtdswap_read_markers(struct mtdswap_dev *d, struct swap_eb *eb)
 
 	ret = mtdswap_read_oob(d, offset, &ops);
 
-	if (ret && ret != -EUCLEAN)
+	if (ret && !mtd_is_bitflip(ret))
 		return ret;
 
 	data = (struct mtdswap_oobdata *)d->oob_buf;
@@ -363,7 +363,7 @@ static int mtdswap_read_markers(struct mtdswap_dev *d, struct swap_eb *eb)
 
 	if (le16_to_cpu(data->magic) == MTDSWAP_MAGIC_CLEAN) {
 		eb->erase_count = le32_to_cpu(data->count);
-		if (ret == -EUCLEAN)
+		if (mtd_is_bitflip(ret))
 			ret = MTDSWAP_SCANNED_BITFLIP;
 		else {
 			if (le16_to_cpu(data2->magic) == MTDSWAP_MAGIC_DIRTY)
@@ -408,7 +408,7 @@ static int mtdswap_write_marker(struct mtdswap_dev *d, struct swap_eb *eb,
 	if (ret) {
 		dev_warn(d->dev, "Write OOB failed for block at %08llx "
 			"error %d\n", offset, ret);
-		if (ret == -EIO || ret == -EBADMSG)
+		if (ret == -EIO || mtd_is_eccerr(ret))
 			mtdswap_handle_write_error(d, eb);
 		return ret;
 	}
@@ -628,7 +628,7 @@ static int mtdswap_map_free_block(struct mtdswap_dev *d, unsigned int page,
 			TREE_COUNT(d, CLEAN)--;
 
 			ret = mtdswap_write_marker(d, eb, MTDSWAP_TYPE_DIRTY);
-		} while (ret == -EIO || ret == -EBADMSG);
+		} while (ret == -EIO || mtd_is_eccerr(ret));
 
 		if (ret)
 			return ret;
@@ -678,7 +678,7 @@ retry:
 	ret = mtdswap_map_free_block(d, page, bp);
 	eb = d->eb_data + (*bp / d->pages_per_eblk);
 
-	if (ret == -EIO || ret == -EBADMSG) {
+	if (ret == -EIO || mtd_is_eccerr(ret)) {
 		d->curr_write = NULL;
 		eb->active_count--;
 		d->revmap[*bp] = PAGE_UNDEF;
@@ -690,7 +690,7 @@ retry:
 
 	writepos = (loff_t)*bp << PAGE_SHIFT;
 	ret =  mtd->write(mtd, writepos, PAGE_SIZE, &retlen, buf);
-	if (ret == -EIO || ret == -EBADMSG) {
+	if (ret == -EIO || mtd_is_eccerr(ret)) {
 		d->curr_write_pos--;
 		eb->active_count--;
 		d->revmap[*bp] = PAGE_UNDEF;
@@ -738,7 +738,7 @@ static int mtdswap_move_block(struct mtdswap_dev *d, unsigned int oldblock,
 retry:
 	ret = mtd->read(mtd, readpos, PAGE_SIZE, &retlen, d->page_buf);
 
-	if (ret < 0 && ret != -EUCLEAN) {
+	if (ret < 0 && !mtd_is_bitflip(ret)) {
 		oldeb = d->eb_data + oldblock / d->pages_per_eblk;
 		oldeb->flags |= EBLOCK_READERR;
 
@@ -1016,7 +1016,7 @@ static int mtdswap_gc(struct mtdswap_dev *d, unsigned int background)
 
 	if (ret == 0)
 		mtdswap_rb_add(d, eb, MTDSWAP_CLEAN);
-	else if (ret != -EIO && ret != -EBADMSG)
+	else if (ret != -EIO && !mtd_is_eccerr(ret))
 		mtdswap_rb_add(d, eb, MTDSWAP_DIRTY);
 
 	return 0;
@@ -1164,7 +1164,7 @@ retry:
 	ret = mtd->read(mtd, readpos, PAGE_SIZE, &retlen, buf);
 
 	d->mtd_read_count++;
-	if (ret == -EUCLEAN) {
+	if (mtd_is_bitflip(ret)) {
 		eb->flags |= EBLOCK_BITFLIP;
 		mtdswap_rb_add(d, eb, MTDSWAP_BITFLIP);
 		ret = 0;
diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c
index de93a98..ae8c60d 100644
--- a/drivers/mtd/nand/diskonchip.c
+++ b/drivers/mtd/nand/diskonchip.c
@@ -1031,7 +1031,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat,
 		WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
 	else
 		WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
-	if (no_ecc_failures && (ret == -EBADMSG)) {
+	if (no_ecc_failures && mtd_is_eccerr(ret)) {
 		printk(KERN_ERR "suppressing ECC failure\n");
 		ret = 0;
 	}
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index 7dbfce4..584bdcb 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -400,7 +400,7 @@ static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd,
 
 	ret = scan_read_raw_oob(mtd, buf, offs, readlen);
 	/* Ignore ECC errors when checking for BBM */
-	if (ret && ret != -EUCLEAN && ret != -EBADMSG)
+	if (ret && !mtd_is_bitflip_or_eccerr(ret))
 		return ret;
 
 	for (j = 0; j < len; j++, buf += scanlen) {
@@ -430,7 +430,7 @@ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,
 		 */
 		ret = mtd->read_oob(mtd, offs, &ops);
 		/* Ignore ECC errors when checking for BBM */
-		if (ret && ret != -EUCLEAN && ret != -EBADMSG)
+		if (ret && !mtd_is_bitflip_or_eccerr(ret))
 			return ret;
 
 		if (check_short_pattern(buf, bd))
diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c
index 272e3c0..cda77b5 100644
--- a/drivers/mtd/nftlcore.c
+++ b/drivers/mtd/nftlcore.c
@@ -425,7 +425,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 && ret != -EUCLEAN) {
+		if (ret < 0 && !mtd_is_bitflip(ret)) {
 			ret = mtd->read(mtd, (nftl->EraseSize * BlockMap[block])
 					+ (block * 512), 512, &retlen,
 					movebuf);
@@ -773,7 +773,7 @@ static int nftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,
 		size_t retlen;
 		int res = mtd->read(mtd, ptr, 512, &retlen, buffer);
 
-		if (res < 0 && res != -EUCLEAN)
+		if (res < 0 && !mtd_is_bitflip(res))
 			return -EIO;
 	}
 	return 0;
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index a52aa0f..a839473 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -1079,7 +1079,7 @@ static int onenand_recover_lsb(struct mtd_info *mtd, loff_t addr, int status)
 		return status;
 
 	/* check if we failed due to uncorrectable error */
-	if (status != -EBADMSG && status != ONENAND_BBT_READ_ECC_ERROR)
+	if (!mtd_is_eccerr(status) && status != ONENAND_BBT_READ_ECC_ERROR)
 		return status;
 
 	/* check if address lies in MLC region */
@@ -1159,7 +1159,7 @@ static int onenand_mlc_read_ops_nolock(struct mtd_info *mtd, loff_t from,
 			if (unlikely(ret))
 				ret = onenand_recover_lsb(mtd, from, ret);
 			onenand_update_bufferram(mtd, from, !ret);
-			if (ret == -EBADMSG)
+			if (mtd_is_eccerr(ret))
 				ret = 0;
 			if (ret)
 				break;
@@ -1255,7 +1255,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
 			this->command(mtd, ONENAND_CMD_READ, from, writesize);
  			ret = this->wait(mtd, FL_READING);
  			onenand_update_bufferram(mtd, from, !ret);
-			if (ret == -EBADMSG)
+			if (mtd_is_eccerr(ret))
 				ret = 0;
  		}
  	}
@@ -1315,7 +1315,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
  		/* Now wait for load */
  		ret = this->wait(mtd, FL_READING);
  		onenand_update_bufferram(mtd, from, !ret);
-		if (ret == -EBADMSG)
+		if (mtd_is_eccerr(ret))
 			ret = 0;
  	}
 
@@ -1403,7 +1403,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
 		if (unlikely(ret))
 			ret = onenand_recover_lsb(mtd, from, ret);
 
-		if (ret && ret != -EBADMSG) {
+		if (ret && !mtd_is_eccerr(ret)) {
 			printk(KERN_ERR "%s: read failed = 0x%x\n",
 				__func__, ret);
 			break;
diff --git a/drivers/mtd/sm_ftl.c b/drivers/mtd/sm_ftl.c
index d927641..fddb714 100644
--- a/drivers/mtd/sm_ftl.c
+++ b/drivers/mtd/sm_ftl.c
@@ -281,7 +281,7 @@ again:
 	ret = mtd->read_oob(mtd, sm_mkoffset(ftl, zone, block, boffset), &ops);
 
 	/* Test for unknown errors */
-	if (ret != 0 && ret != -EUCLEAN && ret != -EBADMSG) {
+	if (ret != 0 && !mtd_is_bitflip_or_eccerr(ret)) {
 		dbg("read of block %d at zone %d, failed due to error (%d)",
 			block, zone, ret);
 		goto again;
@@ -306,7 +306,7 @@ again:
 	}
 
 	/* Test ECC*/
-	if (ret == -EBADMSG ||
+	if (mtd_is_eccerr(ret) ||
 		(ftl->smallpagenand && sm_correct_sector(buffer, oob))) {
 
 		dbg("read of block %d at zone %d, failed due to ECC error",
diff --git a/drivers/mtd/tests/mtd_pagetest.c b/drivers/mtd/tests/mtd_pagetest.c
index 00b937e..186b14c 100644
--- a/drivers/mtd/tests/mtd_pagetest.c
+++ b/drivers/mtd/tests/mtd_pagetest.c
@@ -128,7 +128,7 @@ static int verify_eraseblock(int ebnum)
 	for (j = 0; j < pgcnt - 1; ++j, addr += pgsize) {
 		/* Do a read to set the internal dataRAMs to different data */
 		err = mtd->read(mtd, addr0, bufsize, &read, twopages);
-		if (err == -EUCLEAN)
+		if (mtd_is_bitflip(err))
 			err = 0;
 		if (err || read != bufsize) {
 			printk(PRINT_PREF "error: read failed at %#llx\n",
@@ -136,7 +136,7 @@ static int verify_eraseblock(int ebnum)
 			return err;
 		}
 		err = mtd->read(mtd, addrn - bufsize, bufsize, &read, twopages);
-		if (err == -EUCLEAN)
+		if (mtd_is_bitflip(err))
 			err = 0;
 		if (err || read != bufsize) {
 			printk(PRINT_PREF "error: read failed at %#llx\n",
@@ -146,7 +146,7 @@ static int verify_eraseblock(int ebnum)
 		memset(twopages, 0, bufsize);
 		read = 0;
 		err = mtd->read(mtd, addr, bufsize, &read, twopages);
-		if (err == -EUCLEAN)
+		if (mtd_is_bitflip(err))
 			err = 0;
 		if (err || read != bufsize) {
 			printk(PRINT_PREF "error: read failed at %#llx\n",
@@ -164,7 +164,7 @@ static int verify_eraseblock(int ebnum)
 		unsigned long oldnext = next;
 		/* Do a read to set the internal dataRAMs to different data */
 		err = mtd->read(mtd, addr0, bufsize, &read, twopages);
-		if (err == -EUCLEAN)
+		if (mtd_is_bitflip(err))
 			err = 0;
 		if (err || read != bufsize) {
 			printk(PRINT_PREF "error: read failed at %#llx\n",
@@ -172,7 +172,7 @@ static int verify_eraseblock(int ebnum)
 			return err;
 		}
 		err = mtd->read(mtd, addrn - bufsize, bufsize, &read, twopages);
-		if (err == -EUCLEAN)
+		if (mtd_is_bitflip(err))
 			err = 0;
 		if (err || read != bufsize) {
 			printk(PRINT_PREF "error: read failed at %#llx\n",
@@ -182,7 +182,7 @@ static int verify_eraseblock(int ebnum)
 		memset(twopages, 0, bufsize);
 		read = 0;
 		err = mtd->read(mtd, addr, bufsize, &read, twopages);
-		if (err == -EUCLEAN)
+		if (mtd_is_bitflip(err))
 			err = 0;
 		if (err || read != bufsize) {
 			printk(PRINT_PREF "error: read failed at %#llx\n",
@@ -231,7 +231,7 @@ static int crosstest(void)
 	read = 0;
 	addr = addrn - pgsize - pgsize;
 	err = mtd->read(mtd, addr, pgsize, &read, pp1);
-	if (err == -EUCLEAN)
+	if (mtd_is_bitflip(err))
 		err = 0;
 	if (err || read != pgsize) {
 		printk(PRINT_PREF "error: read failed at %#llx\n",
@@ -244,7 +244,7 @@ static int crosstest(void)
 	read = 0;
 	addr = addrn - pgsize - pgsize - pgsize;
 	err = mtd->read(mtd, addr, pgsize, &read, pp1);
-	if (err == -EUCLEAN)
+	if (mtd_is_bitflip(err))
 		err = 0;
 	if (err || read != pgsize) {
 		printk(PRINT_PREF "error: read failed at %#llx\n",
@@ -258,7 +258,7 @@ static int crosstest(void)
 	addr = addr0;
 	printk(PRINT_PREF "reading page at %#llx\n", (long long)addr);
 	err = mtd->read(mtd, addr, pgsize, &read, pp2);
-	if (err == -EUCLEAN)
+	if (mtd_is_bitflip(err))
 		err = 0;
 	if (err || read != pgsize) {
 		printk(PRINT_PREF "error: read failed at %#llx\n",
@@ -272,7 +272,7 @@ static int crosstest(void)
 	addr = addrn - pgsize;
 	printk(PRINT_PREF "reading page at %#llx\n", (long long)addr);
 	err = mtd->read(mtd, addr, pgsize, &read, pp3);
-	if (err == -EUCLEAN)
+	if (mtd_is_bitflip(err))
 		err = 0;
 	if (err || read != pgsize) {
 		printk(PRINT_PREF "error: read failed at %#llx\n",
@@ -286,7 +286,7 @@ static int crosstest(void)
 	addr = addr0;
 	printk(PRINT_PREF "reading page at %#llx\n", (long long)addr);
 	err = mtd->read(mtd, addr, pgsize, &read, pp4);
-	if (err == -EUCLEAN)
+	if (mtd_is_bitflip(err))
 		err = 0;
 	if (err || read != pgsize) {
 		printk(PRINT_PREF "error: read failed at %#llx\n",
@@ -345,7 +345,7 @@ static int erasecrosstest(void)
 	printk(PRINT_PREF "reading 1st page of block %d\n", ebnum);
 	memset(readbuf, 0, pgsize);
 	err = mtd->read(mtd, addr0, pgsize, &read, readbuf);
-	if (err == -EUCLEAN)
+	if (mtd_is_bitflip(err))
 		err = 0;
 	if (err || read != pgsize) {
 		printk(PRINT_PREF "error: read failed at %#llx\n",
@@ -383,7 +383,7 @@ static int erasecrosstest(void)
 	printk(PRINT_PREF "reading 1st page of block %d\n", ebnum);
 	memset(readbuf, 0, pgsize);
 	err = mtd->read(mtd, addr0, pgsize, &read, readbuf);
-	if (err == -EUCLEAN)
+	if (mtd_is_bitflip(err))
 		err = 0;
 	if (err || read != pgsize) {
 		printk(PRINT_PREF "error: read failed at %#llx\n",
@@ -439,7 +439,7 @@ static int erasetest(void)
 
 	printk(PRINT_PREF "reading 1st page of block %d\n", ebnum);
 	err = mtd->read(mtd, addr0, pgsize, &read, twopages);
-	if (err == -EUCLEAN)
+	if (mtd_is_bitflip(err))
 		err = 0;
 	if (err || read != pgsize) {
 		printk(PRINT_PREF "error: read failed at %#llx\n",
diff --git a/drivers/mtd/tests/mtd_readtest.c b/drivers/mtd/tests/mtd_readtest.c
index 587e1e3..7560453 100644
--- a/drivers/mtd/tests/mtd_readtest.c
+++ b/drivers/mtd/tests/mtd_readtest.c
@@ -75,7 +75,7 @@ static int read_eraseblock_by_page(int ebnum)
 			ops.datbuf    = NULL;
 			ops.oobbuf    = oobbuf;
 			ret = mtd->read_oob(mtd, addr, &ops);
-			if ((ret && ret != -EUCLEAN) ||
+			if ((ret && !mtd_is_bitflip(ret)) ||
 					ops.oobretlen != mtd->oobsize) {
 				printk(PRINT_PREF "error: read oob failed at "
 						  "%#llx\n", (long long)addr);
diff --git a/drivers/mtd/tests/mtd_speedtest.c b/drivers/mtd/tests/mtd_speedtest.c
index 627d4e2..79d53ee 100644
--- a/drivers/mtd/tests/mtd_speedtest.c
+++ b/drivers/mtd/tests/mtd_speedtest.c
@@ -216,7 +216,7 @@ static int read_eraseblock(int ebnum)
 
 	err = mtd->read(mtd, addr, mtd->erasesize, &read, iobuf);
 	/* Ignore corrected ECC errors */
-	if (err == -EUCLEAN)
+	if (mtd_is_bitflip(err))
 		err = 0;
 	if (err || read != mtd->erasesize) {
 		printk(PRINT_PREF "error: read failed at %#llx\n", addr);
@@ -237,7 +237,7 @@ static int read_eraseblock_by_page(int ebnum)
 	for (i = 0; i < pgcnt; i++) {
 		err = mtd->read(mtd, addr, pgsize, &read, buf);
 		/* Ignore corrected ECC errors */
-		if (err == -EUCLEAN)
+		if (mtd_is_bitflip(err))
 			err = 0;
 		if (err || read != pgsize) {
 			printk(PRINT_PREF "error: read failed at %#llx\n",
@@ -263,7 +263,7 @@ static int read_eraseblock_by_2pages(int ebnum)
 	for (i = 0; i < n; i++) {
 		err = mtd->read(mtd, addr, sz, &read, buf);
 		/* Ignore corrected ECC errors */
-		if (err == -EUCLEAN)
+		if (mtd_is_bitflip(err))
 			err = 0;
 		if (err || read != sz) {
 			printk(PRINT_PREF "error: read failed at %#llx\n",
@@ -278,7 +278,7 @@ static int read_eraseblock_by_2pages(int ebnum)
 	if (pgcnt % 2) {
 		err = mtd->read(mtd, addr, pgsize, &read, buf);
 		/* Ignore corrected ECC errors */
-		if (err == -EUCLEAN)
+		if (mtd_is_bitflip(err))
 			err = 0;
 		if (err || read != pgsize) {
 			printk(PRINT_PREF "error: read failed at %#llx\n",
diff --git a/drivers/mtd/tests/mtd_stresstest.c b/drivers/mtd/tests/mtd_stresstest.c
index 531625f..3c9008a 100644
--- a/drivers/mtd/tests/mtd_stresstest.c
+++ b/drivers/mtd/tests/mtd_stresstest.c
@@ -154,7 +154,7 @@ static int do_read(void)
 	}
 	addr = eb * mtd->erasesize + offs;
 	err = mtd->read(mtd, addr, len, &read, readbuf);
-	if (err == -EUCLEAN)
+	if (mtd_is_bitflip(err))
 		err = 0;
 	if (unlikely(err || read != len)) {
 		printk(PRINT_PREF "error: read failed at 0x%llx\n",
diff --git a/drivers/mtd/tests/mtd_subpagetest.c b/drivers/mtd/tests/mtd_subpagetest.c
index 334eae5..2b51842 100644
--- a/drivers/mtd/tests/mtd_subpagetest.c
+++ b/drivers/mtd/tests/mtd_subpagetest.c
@@ -198,7 +198,7 @@ static int verify_eraseblock(int ebnum)
 	read = 0;
 	err = mtd->read(mtd, addr, subpgsize, &read, readbuf);
 	if (unlikely(err || read != subpgsize)) {
-		if (err == -EUCLEAN && read == subpgsize) {
+		if (mtd_is_bitflip(err) && read == subpgsize) {
 			printk(PRINT_PREF "ECC correction at %#llx\n",
 			       (long long)addr);
 			err = 0;
@@ -226,7 +226,7 @@ static int verify_eraseblock(int ebnum)
 	read = 0;
 	err = mtd->read(mtd, addr, subpgsize, &read, readbuf);
 	if (unlikely(err || read != subpgsize)) {
-		if (err == -EUCLEAN && read == subpgsize) {
+		if (mtd_is_bitflip(err) && read == subpgsize) {
 			printk(PRINT_PREF "ECC correction at %#llx\n",
 			       (long long)addr);
 			err = 0;
@@ -264,7 +264,7 @@ static int verify_eraseblock2(int ebnum)
 		read = 0;
 		err = mtd->read(mtd, addr, subpgsize * k, &read, readbuf);
 		if (unlikely(err || read != subpgsize * k)) {
-			if (err == -EUCLEAN && read == subpgsize * k) {
+			if (mtd_is_bitflip(err) && read == subpgsize * k) {
 				printk(PRINT_PREF "ECC correction at %#llx\n",
 				       (long long)addr);
 				err = 0;
@@ -298,7 +298,7 @@ static int verify_eraseblock_ff(int ebnum)
 		read = 0;
 		err = mtd->read(mtd, addr, subpgsize, &read, readbuf);
 		if (unlikely(err || read != subpgsize)) {
-			if (err == -EUCLEAN && read == subpgsize) {
+			if (mtd_is_bitflip(err) && read == subpgsize) {
 				printk(PRINT_PREF "ECC correction at %#llx\n",
 				       (long long)addr);
 				err = 0;
diff --git a/drivers/mtd/tests/mtd_torturetest.c b/drivers/mtd/tests/mtd_torturetest.c
index 5c6c3d2..25786ce 100644
--- a/drivers/mtd/tests/mtd_torturetest.c
+++ b/drivers/mtd/tests/mtd_torturetest.c
@@ -138,7 +138,7 @@ static inline int check_eraseblock(int ebnum, unsigned char *buf)
 
 retry:
 	err = mtd->read(mtd, addr, len, &read, check_buf);
-	if (err == -EUCLEAN)
+	if (mtd_is_bitflip(err))
 		printk(PRINT_PREF "single bit flip occurred at EB %d "
 		       "MTD reported that it was fixed.\n", ebnum);
 	else if (err) {
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
index 4be6718..fb7f19b 100644
--- a/drivers/mtd/ubi/eba.c
+++ b/drivers/mtd/ubi/eba.c
@@ -443,7 +443,7 @@ retry:
 		if (err == UBI_IO_BITFLIPS) {
 			scrub = 1;
 			err = 0;
-		} else if (err == -EBADMSG) {
+		} else if (mtd_is_eccerr(err)) {
 			if (vol->vol_type == UBI_DYNAMIC_VOLUME)
 				goto out_unlock;
 			scrub = 1;
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index 6ba55c2..f20b6f2 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -172,9 +172,9 @@ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset,
 retry:
 	err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf);
 	if (err) {
-		const char *errstr = (err == -EBADMSG) ? " (ECC error)" : "";
+		const char *errstr = mtd_is_eccerr(err) ? " (ECC error)" : "";
 
-		if (err == -EUCLEAN) {
+		if (mtd_is_bitflip(err)) {
 			/*
 			 * -EUCLEAN is reported if there was a bit-flip which
 			 * was corrected, so this is harmless.
@@ -205,7 +205,7 @@ retry:
 		 * all the requested data. But some buggy drivers might do
 		 * this, so we change it to -EIO.
 		 */
-		if (read != len && err == -EBADMSG) {
+		if (read != len && mtd_is_eccerr(err)) {
 			ubi_assert(0);
 			err = -EIO;
 		}
@@ -469,7 +469,7 @@ static int torture_peb(struct ubi_device *ubi, int pnum)
 
 out:
 	mutex_unlock(&ubi->buf_mutex);
-	if (err == UBI_IO_BITFLIPS || err == -EBADMSG) {
+	if (err == UBI_IO_BITFLIPS || mtd_is_eccerr(err)) {
 		/*
 		 * If a bit-flip or data integrity error was detected, the test
 		 * has not passed because it happened on a freshly erased
@@ -760,7 +760,7 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
 
 	read_err = ubi_io_read(ubi, ec_hdr, pnum, 0, UBI_EC_HDR_SIZE);
 	if (read_err) {
-		if (read_err != UBI_IO_BITFLIPS && read_err != -EBADMSG)
+		if (read_err != UBI_IO_BITFLIPS && !mtd_is_eccerr(read_err))
 			return read_err;
 
 		/*
@@ -776,7 +776,7 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
 
 	magic = be32_to_cpu(ec_hdr->magic);
 	if (magic != UBI_EC_HDR_MAGIC) {
-		if (read_err == -EBADMSG)
+		if (mtd_is_eccerr(read_err))
 			return UBI_IO_BAD_HDR_EBADMSG;
 
 		/*
@@ -1032,12 +1032,12 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
 	p = (char *)vid_hdr - ubi->vid_hdr_shift;
 	read_err = ubi_io_read(ubi, p, pnum, ubi->vid_hdr_aloffset,
 			  ubi->vid_hdr_alsize);
-	if (read_err && read_err != UBI_IO_BITFLIPS && read_err != -EBADMSG)
+	if (read_err && read_err != UBI_IO_BITFLIPS && !mtd_is_eccerr(read_err))
 		return read_err;
 
 	magic = be32_to_cpu(vid_hdr->magic);
 	if (magic != UBI_VID_HDR_MAGIC) {
-		if (read_err == -EBADMSG)
+		if (mtd_is_eccerr(read_err))
 			return UBI_IO_BAD_HDR_EBADMSG;
 
 		if (ubi_check_pattern(vid_hdr, 0xFF, UBI_VID_HDR_SIZE)) {
@@ -1219,7 +1219,7 @@ static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum)
 		return -ENOMEM;
 
 	err = ubi_io_read(ubi, ec_hdr, pnum, 0, UBI_EC_HDR_SIZE);
-	if (err && err != UBI_IO_BITFLIPS && err != -EBADMSG)
+	if (err && err != UBI_IO_BITFLIPS && !mtd_is_eccerr(err))
 		goto exit;
 
 	crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC);
@@ -1306,7 +1306,7 @@ static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum)
 	p = (char *)vid_hdr - ubi->vid_hdr_shift;
 	err = ubi_io_read(ubi, p, pnum, ubi->vid_hdr_aloffset,
 			  ubi->vid_hdr_alsize);
-	if (err && err != UBI_IO_BITFLIPS && err != -EBADMSG)
+	if (err && err != UBI_IO_BITFLIPS && !mtd_is_eccerr(err))
 		goto exit;
 
 	crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_EC_HDR_SIZE_CRC);
@@ -1358,7 +1358,7 @@ int ubi_dbg_check_write(struct ubi_device *ubi, const void *buf, int pnum,
 	}
 
 	err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf1);
-	if (err && err != -EUCLEAN)
+	if (err && !mtd_is_bitflip(err))
 		goto out_free;
 
 	for (i = 0; i < len; i++) {
@@ -1422,7 +1422,7 @@ int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len)
 	}
 
 	err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf);
-	if (err && err != -EUCLEAN) {
+	if (err && !mtd_is_bitflip(err)) {
 		ubi_err("error %d while reading %d bytes from PEB %d:%d, "
 			"read %zd bytes", err, len, pnum, offset, read);
 		goto error;
diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c
index d39716e..1a35fc5 100644
--- a/drivers/mtd/ubi/kapi.c
+++ b/drivers/mtd/ubi/kapi.c
@@ -410,7 +410,7 @@ int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
 		return 0;
 
 	err = ubi_eba_read_leb(ubi, vol, lnum, buf, offset, len, check);
-	if (err && err == -EBADMSG && vol->vol_type == UBI_STATIC_VOLUME) {
+	if (err && mtd_is_eccerr(err) && vol->vol_type == UBI_STATIC_VOLUME) {
 		ubi_warn("mark volume %d as corrupted", vol_id);
 		vol->corrupted = 1;
 	}
diff --git a/drivers/mtd/ubi/misc.c b/drivers/mtd/ubi/misc.c
index ff2a65c..f6a7d7a 100644
--- a/drivers/mtd/ubi/misc.c
+++ b/drivers/mtd/ubi/misc.c
@@ -81,7 +81,7 @@ int ubi_check_volume(struct ubi_device *ubi, int vol_id)
 
 		err = ubi_eba_read_leb(ubi, vol, i, buf, 0, size, 1);
 		if (err) {
-			if (err == -EBADMSG)
+			if (mtd_is_eccerr(err))
 				err = 1;
 			break;
 		}
diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c
index a3a198f..0cb17d9 100644
--- a/drivers/mtd/ubi/scan.c
+++ b/drivers/mtd/ubi/scan.c
@@ -395,7 +395,7 @@ static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb,
 	}
 
 	err = ubi_io_read_data(ubi, buf, pnum, 0, len);
-	if (err && err != UBI_IO_BITFLIPS && err != -EBADMSG)
+	if (err && err != UBI_IO_BITFLIPS && !mtd_is_eccerr(err))
 		goto out_free_buf;
 
 	data_crc = be32_to_cpu(vid_hdr->data_crc);
@@ -793,7 +793,7 @@ static int check_corruption(struct ubi_device *ubi, struct ubi_vid_hdr *vid_hdr,
 
 	err = ubi_io_read(ubi, ubi->peb_buf1, pnum, ubi->leb_start,
 			  ubi->leb_size);
-	if (err == UBI_IO_BITFLIPS || err == -EBADMSG) {
+	if (err == UBI_IO_BITFLIPS || mtd_is_eccerr(err)) {
 		/*
 		 * Bit-flips or integrity errors while reading the data area.
 		 * It is difficult to say for sure what type of corruption is
diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c
index 4b50a30..9ad18da 100644
--- a/drivers/mtd/ubi/vtbl.c
+++ b/drivers/mtd/ubi/vtbl.c
@@ -423,7 +423,7 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi,
 
 		err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0,
 				       ubi->vtbl_size);
-		if (err == UBI_IO_BITFLIPS || err == -EBADMSG)
+		if (err == UBI_IO_BITFLIPS || mtd_is_eccerr(err))
 			/*
 			 * Scrub the PEB later. Note, -EBADMSG indicates an
 			 * uncorrectable ECC error, but we have our own CRC and
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v2 09/14] mtd: nand: report ECC errors properly when reading BBT
  2011-09-07 20:13 ` [PATCH 09/14] mtd: nand: report ECC errors properly when reading BBT Brian Norris
@ 2011-09-21  1:35   ` Brian Norris
  0 siblings, 0 replies; 31+ messages in thread
From: Brian Norris @ 2011-09-21  1:35 UTC (permalink / raw)
  To: Artem Bityutskiy
  Cc: Kevin Cernekee, Brian Norris, linux-mtd, David Woodhouse,
	Matthieu Castet

Instead of just printing a warning when encountering ECC errors, we
should return a proper error status and print a more informative
warning. Later, we will handle these error messages in the upper layers
of the BBT scan.

Note that this patch makes our check for ECC error codes a little bit
more restrictive, leaving all unrecognized errors to the generic "else"
clause. This shouldn't cause problems and could even be a benefit.

This code is based on some findings reported by Matthieu Castet.

Reported-by: Matthieu CASTET <matthieu.castet@parrot.com>
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
---
v2: change to `mtd_is_*' prefix

 drivers/mtd/nand/nand_bbt.c |   17 ++++++++++++-----
 1 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index 584bdcb..0ed8591 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -178,7 +178,7 @@ static u32 add_marker_len(struct nand_bbt_descr *td)
 static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
 		struct nand_bbt_descr *td, int offs)
 {
-	int res, i, j, act = 0;
+	int res, ret = 0, i, j, act = 0;
 	struct nand_chip *this = mtd->priv;
 	size_t retlen, len, totlen;
 	loff_t from;
@@ -204,11 +204,18 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
 		}
 		res = mtd->read(mtd, from, len, &retlen, buf);
 		if (res < 0) {
-			if (retlen != len) {
-				pr_info("nand_bbt: error reading bad block table\n");
+			if (mtd_is_eccerr(res)) {
+				pr_info("nand_bbt: ECC error in BBT at "
+					"0x%012llx\n", from & ~mtd->writesize);
+				return res;
+			} else if (mtd_is_bitflip(res)) {
+				pr_info("nand_bbt: corrected error in BBT at "
+					"0x%012llx\n", from & ~mtd->writesize);
+				ret = res;
+			} else {
+				pr_info("nand_bbt: error reading BBT\n");
 				return res;
 			}
-			pr_warn("nand_bbt: ECC error while reading bad block table\n");
 		}
 
 		/* Analyse data */
@@ -242,7 +249,7 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
 		totlen -= len;
 		from += len;
 	}
-	return 0;
+	return ret;
 }
 
 /**
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v2 10/14] mtd: nand: scrub BBT on ECC errors
  2011-09-07 20:13 ` [PATCH 10/14] mtd: nand: scrub BBT on ECC errors Brian Norris
@ 2011-09-21  1:35   ` Brian Norris
  0 siblings, 0 replies; 31+ messages in thread
From: Brian Norris @ 2011-09-21  1:35 UTC (permalink / raw)
  To: Artem Bityutskiy
  Cc: Kevin Cernekee, Brian Norris, linux-mtd, David Woodhouse,
	Matthieu Castet

Now that `read_bbt()' returns ECC error codes properly, we handle those
codes when checking the integrity of our flash-based BBT.

The modifications can be described by this new policy:

*) On any uncorrected ECC error, we invalidate the corresponding table
   and retry our version-checking integrity logic.
*) On corrected bitflips, we mark both tables for re-writing to flash
   (a.k.a. scrubbing).

Current integrity checks (i.e., comparing version numbers, etc.) should
take care of all the cases that result in rescanning the device for bad
blocks or falling back to the BBT as found in the mirror descriptor.

Signed-off-by: Brian Norris <computersforpeace@gmail.com>
---
v2: change to `mtd_is_*' prefix

 drivers/mtd/nand/nand_bbt.c |   29 ++++++++++++++++++++++++-----
 1 files changed, 24 insertions(+), 5 deletions(-)

diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index 0ed8591..11185aa 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -882,7 +882,7 @@ static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *b
  */
 static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd)
 {
-	int i, chips, writeops, create, chipsel, res;
+	int i, chips, writeops, create, chipsel, res, res2;
 	struct nand_chip *this = mtd->priv;
 	struct nand_bbt_descr *td = this->bbt_td;
 	struct nand_bbt_descr *md = this->bbt_md;
@@ -899,6 +899,7 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
 		create = 0;
 		rd = NULL;
 		rd2 = NULL;
+		res = res2 = 0;
 		/* Per chip or per device? */
 		chipsel = (td->options & NAND_BBT_PERCHIP) ? i : -1;
 		/* Mirrored table available? */
@@ -951,11 +952,29 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
 		}
 
 		/* Read back first? */
-		if (rd)
-			read_abs_bbt(mtd, buf, rd, chipsel);
+		if (rd) {
+			res = read_abs_bbt(mtd, buf, rd, chipsel);
+			if (mtd_is_eccerr(res)) {
+				/* Mark table as invalid */
+				rd->pages[i] = -1;
+				i--;
+				continue;
+			}
+		}
 		/* If they weren't versioned, read both */
-		if (rd2)
-			read_abs_bbt(mtd, buf, rd2, chipsel);
+		if (rd2) {
+			res2 = read_abs_bbt(mtd, buf, rd2, chipsel);
+			if (mtd_is_eccerr(res2)) {
+				/* Mark table as invalid */
+				rd2->pages[i] = -1;
+				i--;
+				continue;
+			}
+		}
+
+		/* Scrub the flash table(s)? */
+		if (mtd_is_bitflip(res) || mtd_is_bitflip(res2))
+			writeops = 0x03;
 
 		/* Write the bad block table to the device? */
 		if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v2 11/14] mtd: nand: wait to set BBT version
  2011-09-07 20:13 ` [PATCH 11/14] mtd: nand: wait to set BBT version Brian Norris
@ 2011-09-21  1:35   ` Brian Norris
  0 siblings, 0 replies; 31+ messages in thread
From: Brian Norris @ 2011-09-21  1:35 UTC (permalink / raw)
  To: Artem Bityutskiy
  Cc: Kevin Cernekee, Brian Norris, linux-mtd, David Woodhouse,
	Matthieu Castet

Because there are so many cases of checking, writing, and re-writing of
the bad block table(s), we might as well wait until the we've settled on
a valid, clean copy of the table. This also prevents us from falsely
incrementing the table version. For example, we may have the following:

  Primary table, with version 0x02
  Mirror table, with version 0x01
  Primary table has uncorrectable ECC errors

If we don't have this fix applied, then we will:

  Choose to read the primary table (higher version)
  Set mirror table version to 0x02
  Read back primary table
  Invalidate table because of ECC errors
  Retry readback operation with mirror table, now version 0x02
  Mirrored table reads cleanly
  Writeback BBT to primary table location (with "version 0x02")

However, the mirrored table shouldn't have a new version number.
Instead, we actually want:

  Choose to read the primary table (higher version)
  Read back primary table
  Invalidate table because of ECC errors
  Retry readback with mirror table (version 0x01)
  Mirrored table reads cleanly
  Set both tables to version 0x01
  Writeback BBT to primary table location (version 0x01)

Signed-off-by: Brian Norris <computersforpeace@gmail.com>
---
v2: change to `mtd_is_*' prefix

 drivers/mtd/nand/nand_bbt.c |   12 ++++++++----
 1 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index 11185aa..e7976c7 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -909,11 +909,9 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
 				writeops = 0x03;
 			} else if (td->pages[i] == -1) {
 				rd = md;
-				td->version[i] = md->version[i];
 				writeops = 0x01;
 			} else if (md->pages[i] == -1) {
 				rd = td;
-				md->version[i] = td->version[i];
 				writeops = 0x02;
 			} else if (td->version[i] == md->version[i]) {
 				rd = td;
@@ -921,11 +919,9 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
 					rd2 = md;
 			} else if (((int8_t)(td->version[i] - md->version[i])) > 0) {
 				rd = td;
-				md->version[i] = td->version[i];
 				writeops = 0x02;
 			} else {
 				rd = md;
-				td->version[i] = md->version[i];
 				writeops = 0x01;
 			}
 		} else {
@@ -957,6 +953,7 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
 			if (mtd_is_eccerr(res)) {
 				/* Mark table as invalid */
 				rd->pages[i] = -1;
+				rd->version[i] = 0;
 				i--;
 				continue;
 			}
@@ -967,6 +964,7 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
 			if (mtd_is_eccerr(res2)) {
 				/* Mark table as invalid */
 				rd2->pages[i] = -1;
+				rd2->version[i] = 0;
 				i--;
 				continue;
 			}
@@ -976,6 +974,12 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
 		if (mtd_is_bitflip(res) || mtd_is_bitflip(res2))
 			writeops = 0x03;
 
+		/* Update version numbers before writing */
+		if (md) {
+			td->version[i] = max(td->version[i], md->version[i]);
+			md->version[i] = td->version[i];
+		}
+
 		/* Write the bad block table to the device? */
 		if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {
 			res = write_bbt(mtd, buf, td, md, chipsel);
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v2 12/14] mtd: nand: do not scan bad blocks with NAND_BBT_NO_OOB set
  2011-09-07 20:13 ` [PATCH 12/14] mtd: nand: do not scan bad blocks with NAND_BBT_NO_OOB set Brian Norris
@ 2011-09-21  1:36   ` Brian Norris
  0 siblings, 0 replies; 31+ messages in thread
From: Brian Norris @ 2011-09-21  1:36 UTC (permalink / raw)
  To: Artem Bityutskiy
  Cc: Kevin Cernekee, Brian Norris, linux-mtd, David Woodhouse,
	Matthieu Castet

Updates to our default function for creating bad block patterns have
broken the "no OOB" feature. The NAND_BBT_NO_OOB option should not be
set while scanning for bad blocks, but we've been passing all BBT
options from nand_chip.bbt_options to the bad block scan. This causes us
to hit the:

	BUG_ON(bd->options & NAND_BBT_NO_OOB);

in create_bbt() when we scan the flash for bad blocks.

Thus, while it can be legal to set NAND_BBT_NO_OOB in a custom badblock
pattern descriptor (presumably with NAND_BBT_CREATE disabled?), we
should not pass it through in our default function.

Also, to help clarify and emphasize that the function creates bad block
patterns only (not, for example, table descriptors for locating
flash-based BBT), I renamed `nand_create_default_bbt_descr' to
`nand_create_badblock_pattern'.

Signed-off-by: Brian Norris <computersforpeace@gmail.com>
---
v2: change to `mtd_is_*' prefix

 drivers/mtd/nand/nand_bbt.c |   13 +++++++------
 1 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index e7976c7..783093d 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -1294,26 +1294,27 @@ static struct nand_bbt_descr bbt_mirror_no_bbt_descr = {
 	.pattern = mirror_pattern
 };
 
+#define BADBLOCK_SCAN_MASK (~NAND_BBT_NO_OOB)
 /**
- * nand_create_default_bbt_descr - [INTERN] Creates a BBT descriptor structure
+ * nand_create_badblock_pattern - [INTERN] Creates a BBT descriptor structure
  * @this: NAND chip to create descriptor for
  *
  * This function allocates and initializes a nand_bbt_descr for BBM detection
- * based on the properties of "this". The new descriptor is stored in
+ * based on the properties of @this. The new descriptor is stored in
  * this->badblock_pattern. Thus, this->badblock_pattern should be NULL when
  * passed to this function.
  */
-static int nand_create_default_bbt_descr(struct nand_chip *this)
+static int nand_create_badblock_pattern(struct nand_chip *this)
 {
 	struct nand_bbt_descr *bd;
 	if (this->badblock_pattern) {
-		pr_warn("BBT descr already allocated; not replacing\n");
+		pr_warn("Bad block pattern already allocated; not replacing\n");
 		return -EINVAL;
 	}
 	bd = kzalloc(sizeof(*bd), GFP_KERNEL);
 	if (!bd)
 		return -ENOMEM;
-	bd->options = this->bbt_options;
+	bd->options = this->bbt_options & BADBLOCK_SCAN_MASK;
 	bd->offs = this->badblockpos;
 	bd->len = (this->options & NAND_BUSWIDTH_16) ? 2 : 1;
 	bd->pattern = scan_ff_pattern;
@@ -1367,7 +1368,7 @@ int nand_default_bbt(struct mtd_info *mtd)
 	}
 
 	if (!this->badblock_pattern)
-		nand_create_default_bbt_descr(this);
+		nand_create_badblock_pattern(this);
 
 	return nand_scan_bbt(mtd, this->badblock_pattern);
 }
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* Re: [PATCH 03/14] mtd: define `is_ecc_error()' macros
  2011-09-20  7:19         ` Artem Bityutskiy
  2011-09-21  1:30           ` [PATCH v2 03/14] mtd: define `mtd_is_*()' functions Brian Norris
@ 2011-09-21  1:40           ` Brian Norris
  2011-09-21  6:24             ` Artem Bityutskiy
  1 sibling, 1 reply; 31+ messages in thread
From: Brian Norris @ 2011-09-21  1:40 UTC (permalink / raw)
  To: dedekind1
  Cc: David Woodhouse, Kevin Cernekee, linux-mtd, Matthew Creech,
	Matthieu Castet

On Tue, Sep 20, 2011 at 12:19 AM, Artem Bityutskiy <dedekind1@gmail.com> wrote:
>> I'll either repost with a better naming scheme or update my patches
>> with the suggested names.
>
> OK, let's do this sooner than later please, to make sure I have all your
> work in my tree, which is safer (consider the situation when dwmw2 picks
> what I have now and upstreams before we put everything in).

OK, I sent the necessary v2 patches. I just went with your names for
lack of a better idea.

I didn't send v2 of patches 13/14 and 14/14, since there was no
dependency. Let me know if I need to resend anything else.

Brian

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 03/14] mtd: define `is_ecc_error()' macros
  2011-09-21  1:40           ` [PATCH 03/14] mtd: define `is_ecc_error()' macros Brian Norris
@ 2011-09-21  6:24             ` Artem Bityutskiy
  0 siblings, 0 replies; 31+ messages in thread
From: Artem Bityutskiy @ 2011-09-21  6:24 UTC (permalink / raw)
  To: Brian Norris
  Cc: David Woodhouse, Kevin Cernekee, linux-mtd, Matthew Creech,
	Matthieu Castet

On Tue, 2011-09-20 at 18:40 -0700, Brian Norris wrote:
> On Tue, Sep 20, 2011 at 12:19 AM, Artem Bityutskiy <dedekind1@gmail.com> wrote:
> >> I'll either repost with a better naming scheme or update my patches
> >> with the suggested names.
> >
> > OK, let's do this sooner than later please, to make sure I have all your
> > work in my tree, which is safer (consider the situation when dwmw2 picks
> > what I have now and upstreams before we put everything in).
> 
> OK, I sent the necessary v2 patches. I just went with your names for
> lack of a better idea.
> 
> I didn't send v2 of patches 13/14 and 14/14, since there was no
> dependency. Let me know if I need to resend anything else.

Pushed, thanks for great job!

-- 
Best Regards,
Artem Bityutskiy

^ permalink raw reply	[flat|nested] 31+ messages in thread

end of thread, other threads:[~2011-09-21  6:21 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-09-07 20:13 [PATCH 00/14] mtd: nand: improve flash-based BBT robustness Brian Norris
2011-09-07 20:13 ` [PATCH 01/14] mtd: nand: refactor scanning code Brian Norris
2011-09-11 13:58   ` Artem Bityutskiy
2011-09-07 20:13 ` [PATCH 02/14] mtd: nand: do not ignore all ECC errors Brian Norris
2011-09-11 13:58   ` Artem Bityutskiy
2011-09-07 20:13 ` [PATCH 03/14] mtd: define `is_ecc_error()' macros Brian Norris
2011-09-11 13:57   ` Artem Bityutskiy
2011-09-19  4:14     ` Artem Bityutskiy
2011-09-19 18:43       ` Brian Norris
2011-09-20  7:19         ` Artem Bityutskiy
2011-09-21  1:30           ` [PATCH v2 03/14] mtd: define `mtd_is_*()' functions Brian Norris
2011-09-21  1:40           ` [PATCH 03/14] mtd: define `is_ecc_error()' macros Brian Norris
2011-09-21  6:24             ` Artem Bityutskiy
2011-09-07 20:13 ` [PATCH 04/14] mtd: utilize " Brian Norris
2011-09-21  1:34   ` [PATCH v2 04/14] mtd: utilize `mtd_is_*()' functions Brian Norris
2011-09-07 20:13 ` [PATCH 05/14] mtd: nand: remove unnecessary variable Brian Norris
2011-09-11 13:58   ` Artem Bityutskiy
2011-09-07 20:13 ` [PATCH 06/14] mtd: nand: fix style Brian Norris
2011-09-11 14:00   ` Artem Bityutskiy
2011-09-07 20:13 ` [PATCH 07/14] mtd: nand: begin restructuring check_create Brian Norris
2011-09-07 20:13 ` [PATCH 08/14] mtd: nand: remove gotos in `check_create()' Brian Norris
2011-09-07 20:13 ` [PATCH 09/14] mtd: nand: report ECC errors properly when reading BBT Brian Norris
2011-09-21  1:35   ` [PATCH v2 " Brian Norris
2011-09-07 20:13 ` [PATCH 10/14] mtd: nand: scrub BBT on ECC errors Brian Norris
2011-09-21  1:35   ` [PATCH v2 " Brian Norris
2011-09-07 20:13 ` [PATCH 11/14] mtd: nand: wait to set BBT version Brian Norris
2011-09-21  1:35   ` [PATCH v2 " Brian Norris
2011-09-07 20:13 ` [PATCH 12/14] mtd: nand: do not scan bad blocks with NAND_BBT_NO_OOB set Brian Norris
2011-09-21  1:36   ` [PATCH v2 " Brian Norris
2011-09-07 20:13 ` [PATCH 13/14] mtd: nand: invalidate cache on unaligned reads Brian Norris
2011-09-07 20:13 ` [PATCH 14/14] mtd: nand: switch `check_pattern()' to standard `memcmp()' Brian Norris

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.