@@ -2761,6 +2761,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
pr_debug("%s: device is write protected!\n",
__func__);
instr->state = MTD_ERASE_FAILED;
+ instr->priv = NAND_ERASE_WRITE_PROTECTED;
goto erase_exit;
}
@@ -2776,6 +2777,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
pr_warn("%s: attempt to erase a bad block at page 0x%08x\n",
__func__, page);
instr->state = MTD_ERASE_FAILED;
+ instr->priv = NAND_ERASE_BAD_BLOCK;
goto erase_exit;
}
@@ -2802,6 +2804,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
pr_debug("%s: failed erase, page 0x%08x\n",
__func__, page);
instr->state = MTD_ERASE_FAILED;
+ instr->priv = NAND_ERASE_BLOCK_ERASE_FAILED;
instr->fail_addr =
((loff_t)page << chip->page_shift);
goto erase_exit;
@@ -2819,6 +2822,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
}
}
instr->state = MTD_ERASE_DONE;
+ instr->priv = NAND_ERASE_OK;
erase_exit:
@@ -662,6 +662,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
page = td->pages[chip];
goto write;
}
+next:
/*
* Automatic placement of the bad block table. Search direction
@@ -787,13 +788,42 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
einfo.addr = to;
einfo.len = 1 << this->bbt_erase_shift;
res = nand_erase_nand(mtd, &einfo, 1);
- if (res < 0)
+ if (res == -EIO && einfo.state == MTD_ERASE_FAILED
+ && einfo.priv == NAND_ERASE_BLOCK_ERASE_FAILED) {
+ /* This block is bad. Mark it as such and see if
+ * there's another block available in the BBT area. */
+ int block = page >>
+ (this->bbt_erase_shift - this->page_shift);
+ pr_info("nand_bbt: failed to erase block %d when writing BBT\n",
+ block);
+ bbt_mark_entry(this, block, BBT_BLOCK_WORN);
+
+ res = this->block_markbad(mtd, block);
+ if (res)
+ pr_warn("nand_bbt: error %d while marking block %d bad\n",
+ res, block);
+ goto next;
+ } else if (res < 0)
goto outerr;
res = scan_write_bbt(mtd, to, len, buf,
td->options & NAND_BBT_NO_OOB ? NULL :
&buf[len]);
- if (res < 0)
+ if (res == -EIO) {
+ /* This block is bad. Mark it as such and see if
+ * there's another block available in the BBT area. */
+ int block = page >>
+ (this->bbt_erase_shift - this->page_shift);
+ pr_info("nand_bbt: failed to erase block %d when writing BBT\n",
+ block);
+ bbt_mark_entry(this, block, BBT_BLOCK_WORN);
+
+ res = this->block_markbad(mtd, block);
+ if (res)
+ pr_warn("nand_bbt: error %d while marking block %d bad\n",
+ res, block);
+ goto next;
+ } else if (res < 0)
goto outerr;
pr_info("Bad block table written to 0x%012llx, version 0x%02X\n",
@@ -1030,4 +1030,11 @@ struct nand_sdr_timings {
/* get timing characteristics from ONFI timing mode. */
const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode);
+
+/* reasons for erase failures */
+#define NAND_ERASE_OK 0
+#define NAND_ERASE_WRITE_PROTECTED 1
+#define NAND_ERASE_BAD_BLOCK 2
+#define NAND_ERASE_BLOCK_ERASE_FAILED 3
+
#endif /* __LINUX_MTD_NAND_H */