linux-mtd.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/4] mtd: nand: erase block before marking bad
@ 2012-01-14  2:11 Brian Norris
  2012-01-14  2:11 ` [PATCH 2/4] mtd: nand: fix SCAN2NDPAGE check for BBM Brian Norris
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: Brian Norris @ 2012-01-14  2:11 UTC (permalink / raw)
  To: linux-mtd; +Cc: Brian Norris, David Woodhouse, Artem Bityutskiy

Many NAND flash systems (especially those with MLC NAND) cannot be
reliably written twice in a row. For instance, when marking a bad block,
the block may already have data written to it, and so we should attempt
to erase the block before writing a bad block marker to its OOB region.

We can ignore erase failures, since the block may be bad such that it
cannot be erased properly; we still attempt to write zeros to its spare
area.

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

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 8a393f9..f0e768f 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -407,6 +407,14 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
 		ret = nand_update_bbt(mtd, ofs);
 	else {
 		struct mtd_oob_ops ops;
+		struct erase_info einfo;
+
+		/* Attempt erase before marking OOB */
+		memset(&einfo, 0, sizeof(einfo));
+		einfo.mtd = mtd;
+		einfo.addr = ofs;
+		einfo.len = 1 << chip->phys_erase_shift;
+		nand_erase_nand(mtd, &einfo, 0);
 
 		nand_get_device(chip, mtd, FL_WRITING);
 
-- 
1.7.5.4

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

* [PATCH 2/4] mtd: nand: fix SCAN2NDPAGE check for BBM
  2012-01-14  2:11 [PATCH 1/4] mtd: nand: erase block before marking bad Brian Norris
@ 2012-01-14  2:11 ` Brian Norris
  2012-01-14  2:11 ` [PATCH 3/4] mtd: nand: differentiate 1- vs. 2-byte writes when marking bad blocks Brian Norris
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 6+ messages in thread
From: Brian Norris @ 2012-01-14  2:11 UTC (permalink / raw)
  To: linux-mtd; +Cc: Brian Norris, David Woodhouse, Artem Bityutskiy

nand_block_bad() doesn't check the correct pages when
NAND_BBT_SCAN2NDPAGE is enabled. It should scan both the OOB region of
both the 1st and 2nd page of each block.

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

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index f0e768f..c1ec4fb 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -338,7 +338,7 @@ static int nand_verify_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
  */
 static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
 {
-	int page, chipnr, res = 0;
+	int page, chipnr, res = 0, i = 0;
 	struct nand_chip *chip = mtd->priv;
 	u16 bad;
 
@@ -356,23 +356,29 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
 		chip->select_chip(mtd, chipnr);
 	}
 
-	if (chip->options & NAND_BUSWIDTH_16) {
-		chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos & 0xFE,
-			      page);
-		bad = cpu_to_le16(chip->read_word(mtd));
-		if (chip->badblockpos & 0x1)
-			bad >>= 8;
-		else
-			bad &= 0xFF;
-	} else {
-		chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos, page);
-		bad = chip->read_byte(mtd);
-	}
+	do {
+		if (chip->options & NAND_BUSWIDTH_16) {
+			chip->cmdfunc(mtd, NAND_CMD_READOOB,
+					chip->badblockpos & 0xFE, page);
+			bad = cpu_to_le16(chip->read_word(mtd));
+			if (chip->badblockpos & 0x1)
+				bad >>= 8;
+			else
+				bad &= 0xFF;
+		} else {
+			chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos,
+					page);
+			bad = chip->read_byte(mtd);
+		}
 
-	if (likely(chip->badblockbits == 8))
-		res = bad != 0xFF;
-	else
-		res = hweight8(bad) < chip->badblockbits;
+		if (likely(chip->badblockbits == 8))
+			res = bad != 0xFF;
+		else
+			res = hweight8(bad) < chip->badblockbits;
+		ofs += mtd->writesize;
+		page = (int)(ofs >> chip->page_shift) & chip->pagemask;
+		i++;
+	} while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE));
 
 	if (getchip)
 		nand_release_device(mtd);
-- 
1.7.5.4

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

* [PATCH 3/4] mtd: nand: differentiate 1- vs. 2-byte writes when marking bad blocks
  2012-01-14  2:11 [PATCH 1/4] mtd: nand: erase block before marking bad Brian Norris
  2012-01-14  2:11 ` [PATCH 2/4] mtd: nand: fix SCAN2NDPAGE check for BBM Brian Norris
@ 2012-01-14  2:11 ` Brian Norris
  2012-01-14  2:11 ` [PATCH 4/4] mtd: nand: correct comment on nand_chip badblockbits Brian Norris
  2012-01-16 12:07 ` [PATCH 1/4] mtd: nand: erase block before marking bad Artem Bityutskiy
  3 siblings, 0 replies; 6+ messages in thread
From: Brian Norris @ 2012-01-14  2:11 UTC (permalink / raw)
  To: linux-mtd; +Cc: Brian Norris, David Woodhouse, Artem Bityutskiy

It seems that we have developed a bad-block-marking "feature" out of
pure laziness:

  "We write two bytes per location, so we dont have to mess with 16 bit
  access."

It's relatively simple to write a 1 byte at a time on x8 devices and 2
bytes at a time on x16 devices, so let's do it.

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

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index c1ec4fb..ecc3f52 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -427,13 +427,17 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
 		/*
 		 * Write to first two pages if necessary. If we write to more
 		 * than one location, the first error encountered quits the
-		 * procedure. We write two bytes per location, so we dont have
-		 * to mess with 16 bit access.
+		 * procedure.
 		 */
-		ops.len = ops.ooblen = 2;
 		ops.datbuf = NULL;
 		ops.oobbuf = buf;
-		ops.ooboffs = chip->badblockpos & ~0x01;
+		ops.ooboffs = chip->badblockpos;
+		if (chip->options & NAND_BUSWIDTH_16) {
+			ops.ooboffs &= ~0x01;
+			ops.len = ops.ooblen = 2;
+		} else {
+			ops.len = ops.ooblen = 1;
+		}
 		ops.mode = MTD_OPS_PLACE_OOB;
 		do {
 			ret = nand_do_write_oob(mtd, ofs, &ops);
-- 
1.7.5.4

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

* [PATCH 4/4] mtd: nand: correct comment on nand_chip badblockbits
  2012-01-14  2:11 [PATCH 1/4] mtd: nand: erase block before marking bad Brian Norris
  2012-01-14  2:11 ` [PATCH 2/4] mtd: nand: fix SCAN2NDPAGE check for BBM Brian Norris
  2012-01-14  2:11 ` [PATCH 3/4] mtd: nand: differentiate 1- vs. 2-byte writes when marking bad blocks Brian Norris
@ 2012-01-14  2:11 ` Brian Norris
  2012-01-16 12:07 ` [PATCH 1/4] mtd: nand: erase block before marking bad Artem Bityutskiy
  3 siblings, 0 replies; 6+ messages in thread
From: Brian Norris @ 2012-01-14  2:11 UTC (permalink / raw)
  To: linux-mtd; +Cc: Brian Norris, David Woodhouse, Artem Bityutskiy

The description for badblockbits is incorrect. I think someone just made
up a false description on the spot to satisfy some kerneldoc warning.

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

diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 63b5a8b..609868f 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -448,8 +448,9 @@ struct nand_buffers {
  *			will be copied to the appropriate nand_bbt_descr's.
  * @badblockpos:	[INTERN] position of the bad block marker in the oob
  *			area.
- * @badblockbits:	[INTERN] number of bits to left-shift the bad block
- *			number
+ * @badblockbits:	[INTERN] minimum number of set bits in a good block's
+ *			bad block marker position; i.e., BBM == 11110111b is
+ *			not bad when badblockbits == 7
  * @cellinfo:		[INTERN] MLC/multichip data from chip ident
  * @numchips:		[INTERN] number of physical chips
  * @chipsize:		[INTERN] the size of one chip for multichip arrays
-- 
1.7.5.4

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

* Re: [PATCH 1/4] mtd: nand: erase block before marking bad
  2012-01-14  2:11 [PATCH 1/4] mtd: nand: erase block before marking bad Brian Norris
                   ` (2 preceding siblings ...)
  2012-01-14  2:11 ` [PATCH 4/4] mtd: nand: correct comment on nand_chip badblockbits Brian Norris
@ 2012-01-16 12:07 ` Artem Bityutskiy
  2012-01-16 19:18   ` Brian Norris
  3 siblings, 1 reply; 6+ messages in thread
From: Artem Bityutskiy @ 2012-01-16 12:07 UTC (permalink / raw)
  To: Brian Norris; +Cc: David Woodhouse, linux-mtd

[-- Attachment #1: Type: text/plain, Size: 752 bytes --]

On Fri, 2012-01-13 at 18:11 -0800, Brian Norris wrote:
> Many NAND flash systems (especially those with MLC NAND) cannot be
> reliably written twice in a row. For instance, when marking a bad block,
> the block may already have data written to it, and so we should attempt
> to erase the block before writing a bad block marker to its OOB region.
> 
> We can ignore erase failures, since the block may be bad such that it
> cannot be erased properly; we still attempt to write zeros to its spare
> area.
> 
> Signed-off-by: Brian Norris <computersforpeace@gmail.com>

All four look good, pushed to l2-mtd.git, thanks.

What are your plans WRT marking blocks as bad both in the OOB and the
table?

-- 
Best Regards,
Artem Bityutskiy

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [PATCH 1/4] mtd: nand: erase block before marking bad
  2012-01-16 12:07 ` [PATCH 1/4] mtd: nand: erase block before marking bad Artem Bityutskiy
@ 2012-01-16 19:18   ` Brian Norris
  0 siblings, 0 replies; 6+ messages in thread
From: Brian Norris @ 2012-01-16 19:18 UTC (permalink / raw)
  To: dedekind1; +Cc: David Woodhouse, linux-mtd

On Mon, Jan 16, 2012 at 4:07 AM, Artem Bityutskiy <dedekind1@gmail.com> wrote:
> On Fri, 2012-01-13 at 18:11 -0800, Brian Norris wrote:
>> Many NAND flash systems (especially those with MLC NAND) cannot be
>> reliably written twice in a row. For instance, when marking a bad block,
>> the block may already have data written to it, and so we should attempt
>> to erase the block before writing a bad block marker to its OOB region.
>
> All four look good, pushed to l2-mtd.git, thanks.

Sorry, but actually this "erase block before marking bad" patch is
incorrect. I didn't test this particular revision, and so I forgot
that the erase fails because the block is already marked as bad:

  nand_erase_nand: attempt to erase a bad block at page 0x...

I'll send a fixup patch on top of l2-mtd-2.6.

> What are your plans WRT marking blocks as bad both in the OOB and the
> table?

I don't have a 100% definite plan, but I've been trying to track the
comments/suggestions in the other thread. I'll reply to that thread so
we have the right reply-chain and CC list for discussion.

Brian

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

end of thread, other threads:[~2012-01-16 19:18 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-01-14  2:11 [PATCH 1/4] mtd: nand: erase block before marking bad Brian Norris
2012-01-14  2:11 ` [PATCH 2/4] mtd: nand: fix SCAN2NDPAGE check for BBM Brian Norris
2012-01-14  2:11 ` [PATCH 3/4] mtd: nand: differentiate 1- vs. 2-byte writes when marking bad blocks Brian Norris
2012-01-14  2:11 ` [PATCH 4/4] mtd: nand: correct comment on nand_chip badblockbits Brian Norris
2012-01-16 12:07 ` [PATCH 1/4] mtd: nand: erase block before marking bad Artem Bityutskiy
2012-01-16 19:18   ` Brian Norris

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).