]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
dfu: mtd: mark bad the MTD block on erase error
authorPatrick Delaunay <patrick.delaunay@foss.st.com>
Mon, 5 Jun 2023 07:52:08 +0000 (09:52 +0200)
committerDario Binacchi <dario.binacchi@amarulasolutions.com>
Fri, 13 Oct 2023 08:49:07 +0000 (10:49 +0200)
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>
drivers/dfu/dfu_mtd.c

index 50d6b17cefa6bbbcfa8ab94f5d34ad742ea49a00..485586989c8a60007c1dff7963b685f7edc21457 100644 (file)
@@ -90,22 +90,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;
                }
        }