Patchwork [U-Boot] U-boot nand bug, read.part should fail

login
register
mail settings
Submitter Harvey Chapman
Date Feb. 8, 2013, 3:48 p.m.
Message ID <41DD0060-5CA2-4643-A5A7-B35BF2775981@3gfp.com>
Download mbox | patch
Permalink /patch/219209/
State RFC
Delegated to: Scott Wood
Headers show

Comments

Harvey Chapman - Feb. 8, 2013, 3:48 p.m.
On Feb 7, 2013, at 5:22 PM, Scott Wood <scottwood@freescale.com> wrote:

> It's fine until you get a bad block in the partition, and you end up accessing the first block of the next partition (or getting "Attempt to read/write outside the flash area" if it's the last partition).
> 
> Of course, fixing partition/chip accesses to account for this when determining size would be even better. :-)

Something like this?

Patch

diff --git a/common/cmd_nand.c b/common/cmd_nand.c
--- a/common/cmd_nand.c
+++ b/common/cmd_nand.c
@@ -621,60 +621,78 @@  int do_nand(cmd_tbl_t * cmdtp, int flag,
 
 		nand = &nand_info[dev];
 
 		s = strchr(cmd, '.');
 
 		if (s && !strcmp(s, ".raw")) {
 			raw = 1;
 
 			if (arg_off(argv[3], &dev, &off, &size))
 				return 1;
 
 			if (argc > 4 && !str2long(argv[4], &pagecount)) {
 				printf("'%s' is not a number\n", argv[4]);
 				return 1;
 			}
 
 			if (pagecount * nand->writesize > size) {
 				puts("Size exceeds partition or device limit\n");
 				return -1;
 			}
 
 			rwsize = pagecount * (nand->writesize + nand->oobsize);
 		} else {
 			if (arg_off_size(argc - 3, argv + 3, &dev,
 						&off, &size) != 0)
 				return 1;
 
 			rwsize = size;
 		}
 
+                /* If no size was given, it has been calculated for us as
+                 * the remainder of the chip or partition from offset. Adjust
+                 * down for bad blocks, if necessary.
+                 */
+                if (argc < 4) {
+                        nand_info_t *nand = &nand_info[dev];
+                        int maxsize = rwsize;
+                        int offset = off;
+                        for (; offset < maxsize; offset += nand->erasesize)
+                                if (nand_block_isbad(nand, offset))
+                                        rwsize -= nand->erasesize;
+
+                        if (rwsize != maxsize)
+                                printf("\nsize adjusted to %d (%d bad blocks)\n",
+                                       rwsize,
+                                       (maxsize - rwsize) / nand->erasesize);
+                }
+
 		if (!s || !strcmp(s, ".jffs2") ||
 		    !strcmp(s, ".e") || !strcmp(s, ".i") || !strcmp(s, ".part")) {
 			if (read)
 				ret = nand_read_skip_bad(nand, off, &rwsize,
 							 (u_char *)addr);
 			else
 				ret = nand_write_skip_bad(nand, off, &rwsize,
 							  (u_char *)addr, 0);
 #ifdef CONFIG_CMD_NAND_TRIMFFS
 		} else if (!strcmp(s, ".trimffs")) {
 			if (read) {
 				printf("Unknown nand command suffix '%s'\n", s);
 				return 1;
 			}
 			ret = nand_write_skip_bad(nand, off, &rwsize,
 						(u_char *)addr,
 						WITH_DROP_FFS);
 #endif
 #ifdef CONFIG_CMD_NAND_YAFFS
 		} else if (!strcmp(s, ".yaffs")) {
 			if (read) {
 				printf("Unknown nand command suffix '%s'.\n", s);
 				return 1;
 			}
 			ret = nand_write_skip_bad(nand, off, &rwsize,
 						(u_char *)addr,
 						WITH_INLINE_OOB);
 #endif
 		} else if (!strcmp(s, ".oob")) {
 			/* out-of-band data */