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.


Thanks,
Matt



--- a/package/system/mtd/src/jffs2.c
+++ b/package/system/mtd/src/jffs2.c
@@ -58,7 +58,18 @@
                ofs += (size - (ofs % size));
        }
        ofs = ofs % erasesize;
-       if (ofs == 0) {
+       if (ofs == 0)
+       {
+               while (mtd_block_is_bad(outfd, mtdofs) && (mtdofs < mtdsize))
+               {
+                       if (!quiet)
+                               fprintf(stderr, "\nSkipping bad block at 0x%08x 
  ", mtdofs);
+                       
+                       mtdofs += erasesize;
+                       
+                       // Move the file pointer along over the bad block.
+                       lseek(outfd, erasesize, SEEK_CUR);
+               }
                mtd_erase_block(outfd, mtdofs);
                write(outfd, buf, erasesize);
                mtdofs += erasesize;
--- a/package/system/mtd/src/mtd.c
+++ b/package/system/mtd/src/mtd.c
@@ -58,6 +58,7 @@
 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 @@
        }
        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,17 @@
        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 +350,7 @@
        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];
@@ -428,7 +455,14 @@
 
                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,11 +500,24 @@
                /* 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;
+                               }
 
+                               //fprintf(stderr, "erase at offset 0x%08x\n", 
e);
                                if (mtd_erase_block(fd, e) < 0) {
                                        if (next) {
                                                if (w < e) {
@@ -497,6 +544,7 @@
                if (!quiet)
                        fprintf(stderr, "\b\b\b[w]");
 
+        //fprintf(stderr, "write 0x%x bytes at offset 0x%08x\n", buflen, 
lseek(fd, 0, SEEK_CUR));
                if ((result = write(fd, buf + offset, buflen)) < buflen) {
                        if (result < 0) {
                                fprintf(stderr, "Error writing image.\n");
--- a/package/system/mtd/src/mtd.h
+++ b/package/system/mtd/src/mtd.h
@@ -15,6 +15,7 @@
 
 extern int mtd_open(const char *mtd, bool block);
 extern int mtd_check_open(const char *mtd);
+extern int mtd_block_is_bad(int fd, int offset);
 extern int mtd_erase_block(int fd, int offset);
 extern int mtd_write_buffer(int fd, const char *buf, int offset, int length);
 extern int mtd_write_jffs2(const char *mtd, const char *filename, const char 
*dir);
--- a/package/system/mtd/src/jffs2.c
+++ b/package/system/mtd/src/jffs2.c
@@ -58,7 +58,18 @@
 		ofs += (size - (ofs % size));
 	}
 	ofs = ofs % erasesize;
-	if (ofs == 0) {
+	if (ofs == 0)
+	{
+		while (mtd_block_is_bad(outfd, mtdofs) && (mtdofs < mtdsize))
+		{
+			if (!quiet)
+				fprintf(stderr, "\nSkipping bad block at 0x%08x   ", mtdofs);
+			
+			mtdofs += erasesize;
+			
+			// Move the file pointer along over the bad block.
+			lseek(outfd, erasesize, SEEK_CUR);
+		}
 		mtd_erase_block(outfd, mtdofs);
 		write(outfd, buf, erasesize);
 		mtdofs += erasesize;
--- a/package/system/mtd/src/mtd.c
+++ b/package/system/mtd/src/mtd.c
@@ -58,6 +58,7 @@
 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 @@
 	}
 	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,17 @@
 	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 +350,7 @@
 	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];
@@ -428,7 +455,14 @@
 
 		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,11 +500,24 @@
 		/* 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;
+				}
 
+				//fprintf(stderr, "erase at offset 0x%08x\n", e);
 				if (mtd_erase_block(fd, e) < 0) {
 					if (next) {
 						if (w < e) {
@@ -497,6 +544,7 @@
 		if (!quiet)
 			fprintf(stderr, "\b\b\b[w]");
 
+        //fprintf(stderr, "write 0x%x bytes at offset 0x%08x\n", buflen, lseek(fd, 0, SEEK_CUR));
 		if ((result = write(fd, buf + offset, buflen)) < buflen) {
 			if (result < 0) {
 				fprintf(stderr, "Error writing image.\n");
--- a/package/system/mtd/src/mtd.h
+++ b/package/system/mtd/src/mtd.h
@@ -15,6 +15,7 @@
 
 extern int mtd_open(const char *mtd, bool block);
 extern int mtd_check_open(const char *mtd);
+extern int mtd_block_is_bad(int fd, int offset);
 extern int mtd_erase_block(int fd, int offset);
 extern int mtd_write_buffer(int fd, const char *buf, int offset, int length);
 extern int mtd_write_jffs2(const char *mtd, const char *filename, const char *dir);
_______________________________________________
openwrt-devel mailing list
openwrt-devel@lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel

Reply via email to