diff options
-rw-r--r-- | ubi-utils/include/libmtd.h | 1 | ||||
-rw-r--r-- | ubi-utils/src/libmtd.c | 70 | ||||
-rw-r--r-- | ubi-utils/src/ubiformat.c | 126 |
3 files changed, 164 insertions, 33 deletions
diff --git a/ubi-utils/include/libmtd.h b/ubi-utils/include/libmtd.h index d3c6a63..032dafb 100644 --- a/ubi-utils/include/libmtd.h +++ b/ubi-utils/include/libmtd.h @@ -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); diff --git a/ubi-utils/src/libmtd.c b/ubi-utils/src/libmtd.c index b60ddbd..b2f386a 100644 --- a/ubi-utils/src/libmtd.c +++ b/ubi-utils/src/libmtd.c @@ -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; } diff --git a/ubi-utils/src/ubiformat.c b/ubi-utils/src/ubiformat.c index 0074c7a..3a1b198 100644 --- a/ubi-utils/src/ubiformat.c +++ b/ubi-utils/src/ubiformat.c @@ -22,6 +22,13 @@ * 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; + } } |