|
@@ -392,15 +392,23 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
|
|
* @ofs: offset from device start
|
|
* @ofs: offset from device start
|
|
*
|
|
*
|
|
* This is the default implementation, which can be overridden by a hardware
|
|
* This is the default implementation, which can be overridden by a hardware
|
|
- * specific driver.
|
|
|
|
|
|
+ * specific driver. We try operations in the following order, according to our
|
|
|
|
+ * bbt_options (NAND_BBT_NO_OOB_BBM and NAND_BBT_USE_FLASH):
|
|
|
|
+ * (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.
|
|
*/
|
|
*/
|
|
static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
|
static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
|
{
|
|
{
|
|
struct nand_chip *chip = mtd->priv;
|
|
struct nand_chip *chip = mtd->priv;
|
|
uint8_t buf[2] = { 0, 0 };
|
|
uint8_t buf[2] = { 0, 0 };
|
|
- int block, ret, i = 0;
|
|
|
|
|
|
+ int block, res, ret = 0, i = 0;
|
|
|
|
+ int write_oob = !(chip->bbt_options & NAND_BBT_NO_OOB_BBM);
|
|
|
|
|
|
- if (!(chip->bbt_options & NAND_BBT_USE_FLASH)) {
|
|
|
|
|
|
+ if (write_oob) {
|
|
struct erase_info einfo;
|
|
struct erase_info einfo;
|
|
|
|
|
|
/* Attempt erase before marking OOB */
|
|
/* Attempt erase before marking OOB */
|
|
@@ -413,23 +421,17 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
|
|
|
|
|
/* Get block number */
|
|
/* Get block number */
|
|
block = (int)(ofs >> chip->bbt_erase_shift);
|
|
block = (int)(ofs >> chip->bbt_erase_shift);
|
|
|
|
+ /* Mark block bad in memory-based BBT */
|
|
if (chip->bbt)
|
|
if (chip->bbt)
|
|
chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
|
|
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)
|
|
|
|
- ret = nand_update_bbt(mtd, ofs);
|
|
|
|
- else {
|
|
|
|
|
|
+ /* Write bad block marker to OOB */
|
|
|
|
+ if (write_oob) {
|
|
struct mtd_oob_ops ops;
|
|
struct mtd_oob_ops ops;
|
|
loff_t wr_ofs = ofs;
|
|
loff_t wr_ofs = ofs;
|
|
|
|
|
|
nand_get_device(chip, mtd, FL_WRITING);
|
|
nand_get_device(chip, mtd, FL_WRITING);
|
|
|
|
|
|
- /*
|
|
|
|
- * Write to first/last page(s) if necessary. If we write to more
|
|
|
|
- * than one location, the first error encountered quits the
|
|
|
|
- * procedure.
|
|
|
|
- */
|
|
|
|
ops.datbuf = NULL;
|
|
ops.datbuf = NULL;
|
|
ops.oobbuf = buf;
|
|
ops.oobbuf = buf;
|
|
ops.ooboffs = chip->badblockpos;
|
|
ops.ooboffs = chip->badblockpos;
|
|
@@ -441,18 +443,28 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
|
}
|
|
}
|
|
ops.mode = MTD_OPS_PLACE_OOB;
|
|
ops.mode = MTD_OPS_PLACE_OOB;
|
|
|
|
|
|
|
|
+ /* Write to first/last page(s) if necessary */
|
|
if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
|
|
if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
|
|
wr_ofs += mtd->erasesize - mtd->writesize;
|
|
wr_ofs += mtd->erasesize - mtd->writesize;
|
|
do {
|
|
do {
|
|
- ret = nand_do_write_oob(mtd, wr_ofs, &ops);
|
|
|
|
|
|
+ res = nand_do_write_oob(mtd, wr_ofs, &ops);
|
|
|
|
+ if (!ret)
|
|
|
|
+ ret = res;
|
|
|
|
|
|
i++;
|
|
i++;
|
|
wr_ofs += mtd->writesize;
|
|
wr_ofs += mtd->writesize;
|
|
- } while (!ret && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE) &&
|
|
|
|
- i < 2);
|
|
|
|
|
|
+ } while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2);
|
|
|
|
|
|
nand_release_device(mtd);
|
|
nand_release_device(mtd);
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ /* Update flash-based bad block table */
|
|
|
|
+ if (chip->bbt_options & NAND_BBT_USE_FLASH) {
|
|
|
|
+ res = nand_update_bbt(mtd, ofs);
|
|
|
|
+ if (!ret)
|
|
|
|
+ ret = res;
|
|
|
|
+ }
|
|
|
|
+
|
|
if (!ret)
|
|
if (!ret)
|
|
mtd->ecc_stats.badblocks++;
|
|
mtd->ecc_stats.badblocks++;
|
|
|
|
|
|
@@ -3260,6 +3272,10 @@ int nand_scan_tail(struct mtd_info *mtd)
|
|
int i;
|
|
int i;
|
|
struct nand_chip *chip = mtd->priv;
|
|
struct nand_chip *chip = mtd->priv;
|
|
|
|
|
|
|
|
+ /* New bad blocks should be marked in OOB, flash-based BBT, or both */
|
|
|
|
+ BUG_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) &&
|
|
|
|
+ !(chip->bbt_options & NAND_BBT_USE_FLASH));
|
|
|
|
+
|
|
if (!(chip->options & NAND_OWN_BUFFERS))
|
|
if (!(chip->options & NAND_OWN_BUFFERS))
|
|
chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL);
|
|
chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL);
|
|
if (!chip->buffers)
|
|
if (!chip->buffers)
|