aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd
diff options
context:
space:
mode:
authorBrian Norris <computersforpeace@gmail.com>2012-02-06 16:44:00 -0500
committerDavid Woodhouse <David.Woodhouse@intel.com>2012-03-26 19:27:02 -0400
commite2414f4c20bd4dc62186fbfd7bdec50bce6d2ead (patch)
treeaf6385dee456265eb6773955ec092d6320317364 /drivers/mtd
parent050c0c1bb2604a62bb250ff6181e9c00727da510 (diff)
mtd: nand: write BBM to OOB even with flash-based BBT
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 incomplete and the flash-based table becomes the only source of current bad block information. This becomes an obvious problem when, for example: * 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 So 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. Comments are updated, expanded, and/or relocated as necessary. The new flash-based BBT procedure for marking bad blocks: (1) erase the affected block, to allow OOB marker to be written cleanly (2) update in-memory BBT (3) write bad block marker to OOB area of affected block (4) update flash-based BBT Note that we retain the first error encountered in (3) or (4), finish the procedures, and dump the error in the end. This should handle power cuts gracefully enough. (1) and (2) are mostly harmless (note that (1) will not erase an already-recognized bad block). The OOB and BBT may be "out of sync" if we experience power loss bewteen (3) and (4), but we can reasonably expect that on next boot, subsequent I/O operations will discover that the block should be marked bad again, thus re-syncing the OOB and BBT. Note that this is a change from the previous default flash-based BBT behavior. If your system cannot support writing bad block markers to OOB, use the new NAND_BBT_NO_OOB_BBM option (in combination with NAND_BBT_USE_FLASH and NAND_BBT_NO_OOB). Signed-off-by: Brian Norris <computersforpeace@gmail.com> Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/nand/nand_base.c46
1 files changed, 31 insertions, 15 deletions
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 05f8243ed1d..13a56d3e8ae 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -392,15 +392,23 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
392 * @ofs: offset from device start 392 * @ofs: offset from device start
393 * 393 *
394 * This is the default implementation, which can be overridden by a hardware 394 * This is the default implementation, which can be overridden by a hardware
395 * specific driver. 395 * specific driver. We try operations in the following order, according to our
396 * bbt_options (NAND_BBT_NO_OOB_BBM and NAND_BBT_USE_FLASH):
397 * (1) erase the affected block, to allow OOB marker to be written cleanly
398 * (2) update in-memory BBT
399 * (3) write bad block marker to OOB area of affected block
400 * (4) update flash-based BBT
401 * Note that we retain the first error encountered in (3) or (4), finish the
402 * procedures, and dump the error in the end.
396*/ 403*/
397static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) 404static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
398{ 405{
399 struct nand_chip *chip = mtd->priv; 406 struct nand_chip *chip = mtd->priv;
400 uint8_t buf[2] = { 0, 0 }; 407 uint8_t buf[2] = { 0, 0 };
401 int block, ret, i = 0; 408 int block, res, ret = 0, i = 0;
409 int write_oob = !(chip->bbt_options & NAND_BBT_NO_OOB_BBM);
402 410
403 if (!(chip->bbt_options & NAND_BBT_USE_FLASH)) { 411 if (write_oob) {
404 struct erase_info einfo; 412 struct erase_info einfo;
405 413
406 /* Attempt erase before marking OOB */ 414 /* Attempt erase before marking OOB */
@@ -413,23 +421,17 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
413 421
414 /* Get block number */ 422 /* Get block number */
415 block = (int)(ofs >> chip->bbt_erase_shift); 423 block = (int)(ofs >> chip->bbt_erase_shift);
424 /* Mark block bad in memory-based BBT */
416 if (chip->bbt) 425 if (chip->bbt)
417 chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); 426 chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
418 427
419 /* Do we have a flash based bad block table? */ 428 /* Write bad block marker to OOB */
420 if (chip->bbt_options & NAND_BBT_USE_FLASH) 429 if (write_oob) {
421 ret = nand_update_bbt(mtd, ofs);
422 else {
423 struct mtd_oob_ops ops; 430 struct mtd_oob_ops ops;
424 loff_t wr_ofs = ofs; 431 loff_t wr_ofs = ofs;
425 432
426 nand_get_device(chip, mtd, FL_WRITING); 433 nand_get_device(chip, mtd, FL_WRITING);
427 434
428 /*
429 * Write to first/last page(s) if necessary. If we write to more
430 * than one location, the first error encountered quits the
431 * procedure.
432 */
433 ops.datbuf = NULL; 435 ops.datbuf = NULL;
434 ops.oobbuf = buf; 436 ops.oobbuf = buf;
435 ops.ooboffs = chip->badblockpos; 437 ops.ooboffs = chip->badblockpos;
@@ -441,18 +443,28 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
441 } 443 }
442 ops.mode = MTD_OPS_PLACE_OOB; 444 ops.mode = MTD_OPS_PLACE_OOB;
443 445
446 /* Write to first/last page(s) if necessary */
444 if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) 447 if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
445 wr_ofs += mtd->erasesize - mtd->writesize; 448 wr_ofs += mtd->erasesize - mtd->writesize;
446 do { 449 do {
447 ret = nand_do_write_oob(mtd, wr_ofs, &ops); 450 res = nand_do_write_oob(mtd, wr_ofs, &ops);
451 if (!ret)
452 ret = res;
448 453
449 i++; 454 i++;
450 wr_ofs += mtd->writesize; 455 wr_ofs += mtd->writesize;
451 } while (!ret && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && 456 } while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2);
452 i < 2);
453 457
454 nand_release_device(mtd); 458 nand_release_device(mtd);
455 } 459 }
460
461 /* Update flash-based bad block table */
462 if (chip->bbt_options & NAND_BBT_USE_FLASH) {
463 res = nand_update_bbt(mtd, ofs);
464 if (!ret)
465 ret = res;
466 }
467
456 if (!ret) 468 if (!ret)
457 mtd->ecc_stats.badblocks++; 469 mtd->ecc_stats.badblocks++;
458 470
@@ -3260,6 +3272,10 @@ int nand_scan_tail(struct mtd_info *mtd)
3260 int i; 3272 int i;
3261 struct nand_chip *chip = mtd->priv; 3273 struct nand_chip *chip = mtd->priv;
3262 3274
3275 /* New bad blocks should be marked in OOB, flash-based BBT, or both */
3276 BUG_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) &&
3277 !(chip->bbt_options & NAND_BBT_USE_FLASH));
3278
3263 if (!(chip->options & NAND_OWN_BUFFERS)) 3279 if (!(chip->options & NAND_OWN_BUFFERS))
3264 chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL); 3280 chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL);
3265 if (!chip->buffers) 3281 if (!chip->buffers)