From d7a9700570eb6d3e55777cda1ae1503000692bb9 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 26 Mar 2014 10:50:09 +0000 Subject: mtd: add support for bad blocks in NAND flash NAND flash is very likely to contain bad blocks. Currently, mtd and therefore sysupgrade fails when it encounters a single bad block, potentially leaving an unbootable system. This patch allows the mtd utility to skip bad blocks in NAND flash and complete sysupgrade successfully. Patch by: Matthew Redfearn Signed-off-by: Felix Fietkau git-svn-id: svn://svn.openwrt.org/openwrt/trunk@40021 3c298f89-4303-0410-b956-a3cf2f4a3e73 --- package/system/mtd/src/mtd.c | 51 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 5 deletions(-) (limited to 'package/system/mtd/src/mtd.c') diff --git a/package/system/mtd/src/mtd.c b/package/system/mtd/src/mtd.c index 73335f3fbe..604ca28ae2 100644 --- a/package/system/mtd/src/mtd.c +++ b/package/system/mtd/src/mtd.c @@ -58,6 +58,7 @@ int no_erase; int mtdsize = 0; int erasesize = 0; int jffs2_skip_bytes=0; +int mtdtype = 0; int mtd_open(const char *mtd, bool block) { @@ -103,10 +104,28 @@ int mtd_check_open(const char *mtd) } mtdsize = mtdInfo.size; erasesize = mtdInfo.erasesize; + mtdtype = mtdInfo.type; return fd; } +int mtd_block_is_bad(int fd, int offset) +{ + int r = 0; + loff_t o = offset; + + if (mtdtype == MTD_NANDFLASH) + { + r = ioctl(fd, MEMGETBADBLOCK, &o); + if (r < 0) + { + fprintf(stderr, "Failed to get erase block status\n"); + exit(1); + } + } + return r; +} + int mtd_erase_block(int fd, int offset) { struct erase_info_user mtdEraseInfo; @@ -236,10 +255,14 @@ mtd_erase(const char *mtd) for (mtdEraseInfo.start = 0; mtdEraseInfo.start < mtdsize; mtdEraseInfo.start += erasesize) { - - ioctl(fd, MEMUNLOCK, &mtdEraseInfo); - if(ioctl(fd, MEMERASE, &mtdEraseInfo)) - fprintf(stderr, "Failed to erase block on %s at 0x%x\n", mtd, mtdEraseInfo.start); + if (mtd_block_is_bad(fd, mtdEraseInfo.start)) { + if (!quiet) + fprintf(stderr, "\nSkipping bad block at 0x%x ", mtdEraseInfo.start); + } else { + ioctl(fd, MEMUNLOCK, &mtdEraseInfo); + if(ioctl(fd, MEMERASE, &mtdEraseInfo)) + fprintf(stderr, "Failed to erase block on %s at 0x%x\n", mtd, mtdEraseInfo.start); + } } close(fd); @@ -324,6 +347,7 @@ mtd_write(int imagefd, const char *mtd, char *fis_layout, size_t part_offset) ssize_t skip = 0; uint32_t offset = 0; int jffs2_replaced = 0; + int skip_bad_blocks = 0; #ifdef FIS_SUPPORT static struct fis_part new_parts[MAX_ARGS]; @@ -429,6 +453,12 @@ resume: if (buflen == 0) break; + if (buflen < erasesize) { + /* Pad block to eraseblock size */ + memset(&buf[buflen], 0xff, erasesize - buflen); + buflen = erasesize; + } + if (skip > 0) { skip -= buflen; buflen = 0; @@ -466,10 +496,21 @@ resume: /* need to erase the next block before writing data to it */ if(!no_erase) { - while (w + buflen > e) { + while (w + buflen > e - skip_bad_blocks) { if (!quiet) fprintf(stderr, "\b\b\b[e]"); + if (mtd_block_is_bad(fd, e)) { + if (!quiet) + fprintf(stderr, "\nSkipping bad block at 0x%08x ", e); + + skip_bad_blocks += erasesize; + e += erasesize; + + // Move the file pointer along over the bad block. + lseek(fd, erasesize, SEEK_CUR); + continue; + } if (mtd_erase_block(fd, e) < 0) { if (next) { -- cgit v1.2.3