[PATCH v2] mtd: nand: write bad block marker even with BBT
Brian Norris
computersforpeace at gmail.com
Mon Dec 19 17:03:51 EST 2011
Currently, the flash-based BBT implementation writes bad block data only
to its flash-based table and not to the OOB marker area. Then, as new
bad blocks are marked over time, the OOB markers become out of date and
the flash-based table becomes the only source of current bad block
information. This can be a problem when:
* bootloader cannot read the flash-based BBT format
* BBT is corrupted and the flash must be rescanned for bad
blocks; we want to remember bad blocks that were marked from Linux
In an attempt to keep the bad block markers in sync with the flash-based
BBT, this patch changes the default so that we write bad block markers
to the proper OOB area on each block in addition to flash-based BBT.
Theoretically, the bad block table and the OOB markers can still get out
of sync if the system experiences a power cut between writing the BBT to
flash and writing the OOB marker to a newly-marked bad block. However,
this is a relatively unlikely event, as new bad blocks shouldn't appear
frequently.
Note that this is a change from the previous default flash-based BBT
behavior. If any contributors rely on the old behavior, they are welcome
to introduce an option flag for it.
Adapted from code by Matthieu Castet.
Signed-off-by: Brian Norris <computersforpeace at gmail.com>
---
v2: Explain potential power cut issues and remove option for retaining
old behavior. I CC'd various MTD contributors; speak up if the new
default is unacceptable!
drivers/mtd/nand/nand_base.c | 59 +++++++++++++++++++++++------------------
1 files changed, 33 insertions(+), 26 deletions(-)
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 35b4565..dfa017e 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -393,6 +393,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
struct nand_chip *chip = mtd->priv;
uint8_t buf[2] = { 0, 0 };
int block, ret, i = 0;
+ struct mtd_oob_ops ops;
if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
ofs += mtd->erasesize - mtd->writesize;
@@ -403,34 +404,40 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
/* Do we have a flash based bad block table? */
- if (chip->bbt_options & NAND_BBT_USE_FLASH)
+ if (chip->bbt_options & NAND_BBT_USE_FLASH) {
ret = nand_update_bbt(mtd, ofs);
- else {
- struct mtd_oob_ops ops;
+ if (ret)
+ return ret;
+ }
- nand_get_device(chip, mtd, FL_WRITING);
+ /*
+ * Write bad block marker to OOB
+ * Note that a flash-based BBT (when used) can become out of sync with
+ * OOB markers if a power cut occurs here. See:
+ * http://lists.infradead.org/pipermail/linux-mtd/2011-December/038851.html
+ */
- /*
- * 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.
- */
- ops.len = ops.ooblen = 2;
- ops.datbuf = NULL;
- ops.oobbuf = buf;
- ops.ooboffs = chip->badblockpos & ~0x01;
- ops.mode = MTD_OPS_PLACE_OOB;
- do {
- ret = nand_do_write_oob(mtd, ofs, &ops);
-
- i++;
- ofs += mtd->writesize;
- } while (!ret && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE) &&
- i < 2);
+ nand_get_device(chip, mtd, FL_WRITING);
+
+ /*
+ * 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.
+ */
+ ops.len = ops.ooblen = 2;
+ ops.datbuf = NULL;
+ ops.oobbuf = buf;
+ ops.ooboffs = chip->badblockpos & ~0x01;
+ ops.mode = MTD_OPS_PLACE_OOB;
+ do {
+ ret = nand_do_write_oob(mtd, ofs, &ops);
+
+ i++;
+ ofs += mtd->writesize;
+ } while (!ret && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2);
+
+ nand_release_device(mtd);
- nand_release_device(mtd);
- }
if (!ret)
mtd->ecc_stats.badblocks++;
--
1.7.5.4
More information about the linux-mtd
mailing list