]> www.infradead.org Git - mtd-utils.git/commitdiff
ubiformat: mark faulty blocks as bad
authorRoger Quadros <ext-roger.quadros@nokia.com>
Thu, 26 Mar 2009 12:14:27 +0000 (14:14 +0200)
committerArtem Bityutskiy <Artem.Bityutskiy@nokia.com>
Thu, 26 Mar 2009 14:31:05 +0000 (16:31 +0200)
Few minor amendments by Artem. And increase the utility
version number.

Signed-off-by: Roger Quadros <ext-roger.quadros@nokia.com>
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
ubi-utils/include/libmtd.h
ubi-utils/src/libmtd.c
ubi-utils/src/ubiformat.c

index d3c6a6320f3f864420757652f3c3bfa5365886b6..032dafbb8fa7590ba9bb10fcc5e73a0b064468d3 100644 (file)
@@ -63,6 +63,7 @@ struct mtd_info
 int mtd_get_info(const char *node, struct mtd_info *mtd);
 int mtd_erase(const struct mtd_info *mtd, int eb);
 int mtd_is_bad(const struct mtd_info *mtd, int eb);
+int mtd_mark_bad(const struct mtd_info *mtd, int eb);
 int mtd_read(const struct mtd_info *mtd, int eb, int offs, void *buf, int len);
 int mtd_write(const struct mtd_info *mtd, int eb, int offs, void *buf, int len);
 
index b60ddbdfd08c031aad8cf3c632abdb4b5979e832..b2f386aa5e8f75e07e9fd12c49c9bc1822c877f1 100644 (file)
@@ -191,13 +191,43 @@ int mtd_is_bad(const struct mtd_info *mtd, int eb)
 
        seek = (loff_t)eb * mtd->eb_size;
        ret = ioctl(mtd->fd, MEMGETBADBLOCK, &seek);
-       if (ret == -1) {
-               sys_errmsg("MEMGETBADBLOCK ioctl failed for "
-                          "eraseblock %d (mtd%d)", eb, mtd->num);
+       if (ret == -1)
+               return sys_errmsg("MEMGETBADBLOCK ioctl failed for "
+                                 "eraseblock %d (mtd%d)", eb, mtd->num);
+       return 0;
+}
+
+/**
+ * mtd_mark_bad - marks the block as bad.
+ * @mtd: MTD device description object
+ * @eb: eraseblock to mark bad
+ *
+ * This function marks the eraseblock @eb as bad. Returns %0 if success
+ * %-1 if failure
+ */
+int mtd_mark_bad(const struct mtd_info *mtd, int eb)
+{
+       int ret;
+       loff_t seek;
+
+       if (!mtd->allows_bb) {
+               errno = EINVAL;
                return -1;
        }
 
-       return ret;
+       if (eb < 0 || eb >= mtd->eb_cnt) {
+               errmsg("bad eraseblock number %d, mtd%d has %d eraseblocks",
+                      eb, mtd->num, mtd->eb_cnt);
+               errno = EINVAL;
+               return -1;
+       }
+
+       seek = (loff_t)eb * mtd->eb_size;
+       ret = ioctl(mtd->fd, MEMSETBADBLOCK, &seek);
+       if (ret == -1)
+               return sys_errmsg("MEMSETBADBLOCK ioctl failed for "
+                                 "eraseblock %d (mtd%d)", eb, mtd->num);
+       return 0;
 }
 
 /**
@@ -232,19 +262,15 @@ int mtd_read(const struct mtd_info *mtd, int eb, int offs, void *buf, int len)
 
        /* Seek to the beginning of the eraseblock */
        seek = (off_t)eb * mtd->eb_size + offs;
-       if (lseek(mtd->fd, seek, SEEK_SET) != seek) {
-               sys_errmsg("cannot seek mtd%d to offset %llu",
-                          mtd->num, (unsigned long long)seek);
-               return -1;
-       }
+       if (lseek(mtd->fd, seek, SEEK_SET) != seek)
+               return sys_errmsg("cannot seek mtd%d to offset %llu",
+                                 mtd->num, (unsigned long long)seek);
 
        while (rd < len) {
                ret = read(mtd->fd, buf, len);
-               if (ret < 0) {
-                       sys_errmsg("cannot read %d bytes from mtd%d (eraseblock %d, offset %d)",
-                                  len, mtd->num, eb, offs);
-                       return -1;
-               }
+               if (ret < 0)
+                       return sys_errmsg("cannot read %d bytes from mtd%d (eraseblock %d, offset %d)",
+                                         len, mtd->num, eb, offs);
                rd += ret;
        }
 
@@ -297,18 +323,14 @@ int mtd_write(const struct mtd_info *mtd, int eb, int offs, void *buf, int len)
 
        /* Seek to the beginning of the eraseblock */
        seek = (off_t)eb * mtd->eb_size + offs;
-       if (lseek(mtd->fd, seek, SEEK_SET) != seek) {
-               sys_errmsg("cannot seek mtd%d to offset %llu",
-                          mtd->num, (unsigned long long)seek);
-               return -1;
-       }
+       if (lseek(mtd->fd, seek, SEEK_SET) != seek)
+               return sys_errmsg("cannot seek mtd%d to offset %llu",
+                                 mtd->num, (unsigned long long)seek);
 
        ret = write(mtd->fd, buf, len);
-       if (ret != len) {
-               sys_errmsg("cannot write %d bytes to mtd%d (eraseblock %d, offset %d)",
-                          len, mtd->num, eb, offs);
-               return -1;
-       }
+       if (ret != len)
+               return sys_errmsg("cannot write %d bytes to mtd%d (eraseblock %d, offset %d)",
+                                 len, mtd->num, eb, offs);
 
        return 0;
 }
index 0074c7a7f651335d43348928357baa699623d198..3a1b19887aa6020cc5bdc95d6033c90659bfd498 100644 (file)
  * Author: Artem Bityutskiy
  */
 
+/*
+ * Maximum amount of consequtive eraseblocks which are considered as normal by
+ * this utility. Otherwise it is assume that something is wrong with the flash
+ * or the driver, and eraseblocks are stopped being marked as bad.
+ */
+#define MAX_CONSECUTIVE_BAD_BLOCKS 4
+
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
@@ -38,7 +45,7 @@
 #include "crc32.h"
 #include "common.h"
 
-#define PROGRAM_VERSION "1.0"
+#define PROGRAM_VERSION "1.1"
 #define PROGRAM_NAME    "ubiformat"
 
 /* The variables below are set by command line arguments */
@@ -354,6 +361,67 @@ static int read_all(int fd, void *buf, size_t len)
        return 0;
 }
 
+/*
+ * Returns %-1 if consecutive bad blocks exceeds the
+ * MAX_CONSECUTIVE_BAD_BLOCKS and returns %0 otherwise.
+ */
+static int consecutive_bad_check(int eb)
+{
+       static int consecutive_bad_blocks = 1;
+       static int prev_bb = -1;
+
+       if (prev_bb == -1)
+               prev_bb = eb;
+
+       if (eb == prev_bb + 1)
+               consecutive_bad_blocks += 1;
+       else
+               consecutive_bad_blocks = 1;
+
+       prev_bb = eb;
+
+       if (consecutive_bad_blocks >= MAX_CONSECUTIVE_BAD_BLOCKS) {
+               if (!args.quiet)
+                       printf("\n");
+               return errmsg("consecutive bad blocks exceed limit: %d, bad flash?",
+                             MAX_CONSECUTIVE_BAD_BLOCKS);
+       }
+
+       return 0;
+}
+
+static int mark_bad(const struct mtd_info *mtd, struct ubi_scan_info *si, int eb)
+{
+       int err;
+
+       if (!args.yes) {
+               normsg_cont("mark it as bad? Continue (yes/no) ");
+               if (!answer_is_yes())
+                       return -1;
+       }
+
+       if (!args.quiet)
+               normsg_cont("marking block %d bad", eb);
+
+       if (!args.quiet)
+               printf("\n");
+
+       if (!mtd->allows_bb) {
+               if (!args.quiet)
+                       printf("\n");
+               return errmsg("bad blocks not supported by this flash");
+       }
+
+       err = mtd_mark_bad(mtd, eb);
+       if (err)
+               return err;
+
+       si->bad_cnt += 1;
+       si->ec[eb] = EB_BAD;
+
+       return consecutive_bad_check(eb);
+}
+
 static int flash_image(const struct mtd_info *mtd, struct ubi_scan_info *si)
 {
        int fd, img_ebs, eb, written_ebs = 0, divisor;
@@ -372,7 +440,7 @@ static int flash_image(const struct mtd_info *mtd, struct ubi_scan_info *si)
        }
 
        if (st_size % mtd->eb_size) {
-               return sys_errmsg("file \"%s\" (size %lld bytes) is not multiple of eraseblock size (%d bytes)",
+               return sys_errmsg("file \"%s\" (size %lld bytes) is not multiple of ""eraseblock size (%d bytes)",
                                  args.image, (long long)st_size, mtd->eb_size);
                goto out_close;
        }
@@ -402,8 +470,18 @@ static int flash_image(const struct mtd_info *mtd, struct ubi_scan_info *si)
 
                err = mtd_erase(mtd, eb);
                if (err) {
+                       if (!args.quiet)
+                               printf("\n");
                        sys_errmsg("failed to erase eraseblock %d", eb);
-                       goto out_close;
+
+                       if (errno != EIO)
+                               goto out_close;
+
+                       if (mark_bad(mtd, si, eb))
+                               goto out_close;
+
+                       divisor += 1;
+                       continue;
                }
 
                err = read_all(fd, buf, mtd->eb_size);
@@ -442,8 +520,21 @@ static int flash_image(const struct mtd_info *mtd, struct ubi_scan_info *si)
 
                err = mtd_write(mtd, eb, 0, buf, new_len);
                if (err) {
+                       if (!args.quiet)
+                               printf("\n");
                        sys_errmsg("cannot write eraseblock %d", eb);
-                       goto out_close;
+
+                       if (errno != EIO)
+                               goto out_close;
+
+
+                       if (mark_bad(mtd, si, eb)) {
+                               normsg("operation incomplete");
+                               goto out_close;
+                       }
+
+                       divisor += 1;
+                       continue;
                }
                if (++written_ebs >= img_ebs)
                        break;
@@ -460,7 +551,7 @@ out_close:
 }
 
 static int format(const struct mtd_info *mtd, const struct ubigen_info *ui,
-                 const struct ubi_scan_info *si, int start_eb, int novtbl)
+                 struct ubi_scan_info *si, int start_eb, int novtbl)
 {
        int eb, err, write_size;
        struct ubi_ec_hdr *hdr;
@@ -506,8 +597,14 @@ static int format(const struct mtd_info *mtd, const struct ubigen_info *ui,
                if (err) {
                        if (!args.quiet)
                                printf("\n");
+
                        sys_errmsg("failed to erase eraseblock %d", eb);
-                       goto out_free;
+                       if (errno != EIO)
+                               goto out_free;
+
+                       if (mark_bad(mtd, si, eb))
+                               goto out_free;
+                       continue;
                }
 
                if ((eb1 == -1 || eb2 == -1) && !novtbl) {
@@ -534,9 +631,20 @@ static int format(const struct mtd_info *mtd, const struct ubigen_info *ui,
                                printf("\n");
                        sys_errmsg("cannot write EC header (%d bytes buffer) to eraseblock %d",
                                   write_size, eb);
-                       if (args.subpage_size != mtd->min_io_size)
-                               normsg("may be %d is incorrect?", args.subpage_size);
-                       goto out_free;
+
+                       if (errno != EIO) {
+                               if (args.subpage_size != mtd->min_io_size)
+                                       normsg("may be %d is incorrect?",
+                                                       args.subpage_size);
+                               goto out_free;
+                       }
+
+                       if (mark_bad(mtd, si, eb)) {
+                               normsg("operation incomplete");
+                               goto out_free;
+                       }
+                       continue;
+
                }
        }