[PATCH v3 0/2] dfu: mtd: mark bad the MTD block on erase error

V3 for http://patchwork.ozlabs.org/project/uboot/list/?series=357878 after remarks and missing impact after comts d9fa61f54e7f9a ("mtd: nand: Show reserved block in chip.erase") and cfb82f7c123e4 ("mtd: nand: Mark reserved blocks")
Patrick
Changes in v3: - Split serie with trace fix and support of bad block in MTD erase - Fix trace for "bbt reserved" when mtd_block_isbad return 2
Changes in v2: - fix mtd_block_isbad offset parameter for erase check - Add trace when bad block are skipped in erase loop - Add remaining byte in trace "Limit reached"
Patrick Delaunay (2): dfu: mtd: fix the trace when limit is reached dfu: mtd: mark bad the MTD block on erase error
drivers/dfu/dfu_mtd.c | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-)

The offset variable = 'off' used in the error trace when limit is reach on erase operation is incorect as 'erase_op.addr' is used in the loop. This patch corrects the copy paste issue between the erase loop and the write loop.
This patch also adds the 'remaining' information to allow to debug of limit issues.
Fixes: 6015af28ee6d ("dfu: add backend for MTD device") Signed-off-by: Patrick Delaunay patrick.delaunay@foss.st.com ---
(no changes since v1)
drivers/dfu/dfu_mtd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/dfu/dfu_mtd.c b/drivers/dfu/dfu_mtd.c index c7075f12eca9..b764f091786d 100644 --- a/drivers/dfu/dfu_mtd.c +++ b/drivers/dfu/dfu_mtd.c @@ -86,8 +86,8 @@ static int mtd_block_op(enum dfu_op op, struct dfu_entity *dfu,
while (remaining) { if (erase_op.addr + remaining > lim) { - printf("Limit reached 0x%llx while erasing at offset 0x%llx\n", - lim, off); + printf("Limit reached 0x%llx while erasing at offset 0x%llx, remaining 0x%llx\n", + lim, erase_op.addr, remaining); return -EIO; }

On 6/5/23 09:52, Patrick Delaunay wrote:
The offset variable = 'off' used in the error trace when limit is reach on erase operation is incorect as 'erase_op.addr' is used in the loop. This patch corrects the copy paste issue between the erase loop and the write loop.
This patch also adds the 'remaining' information to allow to debug of limit issues.
Fixes: 6015af28ee6d ("dfu: add backend for MTD device") Signed-off-by: Patrick Delaunay patrick.delaunay@foss.st.com
(no changes since v1)
drivers/dfu/dfu_mtd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/dfu/dfu_mtd.c b/drivers/dfu/dfu_mtd.c index c7075f12eca9..b764f091786d 100644 --- a/drivers/dfu/dfu_mtd.c +++ b/drivers/dfu/dfu_mtd.c @@ -86,8 +86,8 @@ static int mtd_block_op(enum dfu_op op, struct dfu_entity *dfu,
while (remaining) { if (erase_op.addr + remaining > lim) {
printf("Limit reached 0x%llx while erasing at offset 0x%llx\n",
lim, off);
printf("Limit reached 0x%llx while erasing at offset 0x%llx, remaining 0x%llx\n",
lim, erase_op.addr, remaining); return -EIO; }
Reviewed-by: Patrice Chotard patrice.chotard@foss.st.com
Thanks Patrice

Hello Patrick,
On Mon, Jun 05, 2023 at 09:52:07AM +0200, Patrick Delaunay wrote:
The offset variable = 'off' used in the error trace when limit is reach on erase operation is incorect as 'erase_op.addr' is used in the loop. This patch corrects the copy paste issue between the erase loop and the write loop.
This patch also adds the 'remaining' information to allow to debug of limit issues.
Fixes: 6015af28ee6d ("dfu: add backend for MTD device") Signed-off-by: Patrick Delaunay patrick.delaunay@foss.st.com Reviewed-by: Patrice Chotard patrice.chotard@foss.st.com
Applied to nand-next, thanks and regards
Dario
(no changes since v1)
drivers/dfu/dfu_mtd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/dfu/dfu_mtd.c b/drivers/dfu/dfu_mtd.c index c7075f12eca9..b764f091786d 100644 --- a/drivers/dfu/dfu_mtd.c +++ b/drivers/dfu/dfu_mtd.c @@ -86,8 +86,8 @@ static int mtd_block_op(enum dfu_op op, struct dfu_entity *dfu,
while (remaining) { if (erase_op.addr + remaining > lim) {
printf("Limit reached 0x%llx while erasing at offset 0x%llx\n",
lim, off);
printf("Limit reached 0x%llx while erasing at offset 0x%llx, remaining 0x%llx\n",
lim, erase_op.addr, remaining); return -EIO; }

In the MTD DFU backend, it is needed to mark the NAND block bad when the erase failed with the -EIO error, as it is done in UBI and JFFS2 code.
This operation is not done in the MTD framework, but the bad block tag (in BBM or in BBT) is required to avoid to write data on this block in the next DFU_OP_WRITE loop in mtd_block_op(): the code skip the bad blocks, tested by mtd_block_isbad().
Without this patch, when the NAND block become bad on DFU write operation - low probability on new NAND - the DFU write operation will always failed because the failing block is never marked bad.
This patch also adds a test to avoid to request an erase operation on a block already marked bad; this test is not performed in MTD framework in mtd_erase().
Reviewed-by: Michael Trimarchi michael@amarulasolutions.com Signed-off-by: Patrick Delaunay patrick.delaunay@foss.st.com ---
Changes in v3: - Split serie with trace fix and support of bad block in MTD erase - Fix trace for "bbt reserved" when mtd_block_isbad return 2
Changes in v2: - fix mtd_block_isbad offset parameter for erase check - Add trace when bad block are skipped in erase loop - Add remaining byte in trace "Limit reached"
drivers/dfu/dfu_mtd.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-)
diff --git a/drivers/dfu/dfu_mtd.c b/drivers/dfu/dfu_mtd.c index b764f091786d..271d485d1c9a 100644 --- a/drivers/dfu/dfu_mtd.c +++ b/drivers/dfu/dfu_mtd.c @@ -91,22 +91,36 @@ static int mtd_block_op(enum dfu_op op, struct dfu_entity *dfu, return -EIO; }
+ /* Skip the block if it is bad, don't erase it again */ + ret = mtd_block_isbad(mtd, erase_op.addr); + if (ret) { + printf("Skipping %s at 0x%08llx\n", + ret == 1 ? "bad block" : "bbt reserved", + erase_op.addr); + erase_op.addr += mtd->erasesize; + continue; + } + ret = mtd_erase(mtd, &erase_op);
if (ret) { - /* Abort if its not a bad block error */ - if (ret != -EIO) { - printf("Failure while erasing at offset 0x%llx\n", - erase_op.fail_addr); - return 0; + /* If this is not -EIO, we have no idea what to do. */ + if (ret == -EIO) { + printf("Marking bad block at 0x%08llx (%d)\n", + erase_op.fail_addr, ret); + ret = mtd_block_markbad(mtd, erase_op.addr); + } + /* Abort if it is not -EIO or can't mark bad */ + if (ret) { + printf("Failure while erasing at offset 0x%llx (%d)\n", + erase_op.fail_addr, ret); + return ret; } - printf("Skipping bad block at 0x%08llx\n", - erase_op.addr); } else { remaining -= mtd->erasesize; }
- /* Continue erase behind bad block */ + /* Continue erase behind the current block */ erase_op.addr += mtd->erasesize; } }

Hello Patrick,
On Mon, Jun 05, 2023 at 09:52:08AM +0200, Patrick Delaunay wrote:
In the MTD DFU backend, it is needed to mark the NAND block bad when the erase failed with the -EIO error, as it is done in UBI and JFFS2 code.
This operation is not done in the MTD framework, but the bad block tag (in BBM or in BBT) is required to avoid to write data on this block in the next DFU_OP_WRITE loop in mtd_block_op(): the code skip the bad blocks, tested by mtd_block_isbad().
Without this patch, when the NAND block become bad on DFU write operation
- low probability on new NAND - the DFU write operation will always failed
because the failing block is never marked bad.
This patch also adds a test to avoid to request an erase operation on a block already marked bad; this test is not performed in MTD framework in mtd_erase().
Reviewed-by: Michael Trimarchi michael@amarulasolutions.com Signed-off-by: Patrick Delaunay patrick.delaunay@foss.st.com
Applied to nand-next, thanks and regards,
Dario
Changes in v3:
- Split serie with trace fix and support of bad block in MTD erase
- Fix trace for "bbt reserved" when mtd_block_isbad return 2
Changes in v2:
- fix mtd_block_isbad offset parameter for erase check
- Add trace when bad block are skipped in erase loop
- Add remaining byte in trace "Limit reached"
drivers/dfu/dfu_mtd.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-)
diff --git a/drivers/dfu/dfu_mtd.c b/drivers/dfu/dfu_mtd.c index b764f091786d..271d485d1c9a 100644 --- a/drivers/dfu/dfu_mtd.c +++ b/drivers/dfu/dfu_mtd.c @@ -91,22 +91,36 @@ static int mtd_block_op(enum dfu_op op, struct dfu_entity *dfu, return -EIO; }
/* Skip the block if it is bad, don't erase it again */
ret = mtd_block_isbad(mtd, erase_op.addr);
if (ret) {
printf("Skipping %s at 0x%08llx\n",
ret == 1 ? "bad block" : "bbt reserved",
erase_op.addr);
erase_op.addr += mtd->erasesize;
continue;
}
ret = mtd_erase(mtd, &erase_op); if (ret) {
/* Abort if its not a bad block error */
if (ret != -EIO) {
printf("Failure while erasing at offset 0x%llx\n",
erase_op.fail_addr);
return 0;
/* If this is not -EIO, we have no idea what to do. */
if (ret == -EIO) {
printf("Marking bad block at 0x%08llx (%d)\n",
erase_op.fail_addr, ret);
ret = mtd_block_markbad(mtd, erase_op.addr);
}
/* Abort if it is not -EIO or can't mark bad */
if (ret) {
printf("Failure while erasing at offset 0x%llx (%d)\n",
erase_op.fail_addr, ret);
return ret; }
printf("Skipping bad block at 0x%08llx\n",
erase_op.addr); } else { remaining -= mtd->erasesize; }
/* Continue erase behind bad block */
} }/* Continue erase behind the current block */ erase_op.addr += mtd->erasesize;
participants (3)
-
Dario Binacchi
-
Patrice CHOTARD
-
Patrick Delaunay