[U-Boot] [PATCH 1/3] nand: Clean up nand_util

This patch cleans up nand_util.c: - Fix tabs. - Fix typos. - Remove space character before opening parenthesis in function calls. - Fix comments.
Signed-off-by: Benoît Thébaudeau benoit.thebaudeau@advansee.com Cc: Scott Wood scottwood@freescale.com --- .../drivers/mtd/nand/nand_util.c | 64 ++++++++++---------- 1 file changed, 32 insertions(+), 32 deletions(-)
diff --git u-boot-nand-flash-9c60e75.orig/drivers/mtd/nand/nand_util.c u-boot-nand-flash-9c60e75/drivers/mtd/nand/nand_util.c index c4752a7..3f11103 100644 --- u-boot-nand-flash-9c60e75.orig/drivers/mtd/nand/nand_util.c +++ u-boot-nand-flash-9c60e75/drivers/mtd/nand/nand_util.c @@ -50,8 +50,8 @@ #include <nand.h> #include <jffs2/jffs2.h>
-typedef struct erase_info erase_info_t; -typedef struct mtd_info mtd_info_t; +typedef struct erase_info erase_info_t; +typedef struct mtd_info mtd_info_t;
/* support only for native endian JFFS2 */ #define cpu_to_je16(x) (x) @@ -59,7 +59,7 @@ typedef struct mtd_info mtd_info_t;
/** * nand_erase_opts: - erase NAND flash with support for various options - * (jffs2 formating) + * (jffs2 formatting) * * @param meminfo NAND device to erase * @param opts options, @see struct nand_erase_options @@ -81,7 +81,7 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts) struct nand_chip *chip = meminfo->priv;
if ((opts->offset & (meminfo->writesize - 1)) != 0) { - printf("Attempt to erase non page aligned data\n"); + printf("Attempt to erase non page-aligned data\n"); return -1; }
@@ -94,8 +94,8 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts) erase_length = lldiv(opts->length + meminfo->erasesize - 1, meminfo->erasesize);
- cleanmarker.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK); - cleanmarker.nodetype = cpu_to_je16 (JFFS2_NODETYPE_CLEANMARKER); + cleanmarker.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); + cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER); cleanmarker.totlen = cpu_to_je32(8);
/* scrub option allows to erase badblock. To prevent internal @@ -118,7 +118,7 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts) erased_length < erase_length; erase.addr += meminfo->erasesize) {
- WATCHDOG_RESET (); + WATCHDOG_RESET();
if (!opts->scrub && bbtest) { int ret = meminfo->block_isbad(meminfo, erase.addr); @@ -259,7 +259,7 @@ int nand_lock(struct mtd_info *mtd, int tight) * flash * * @param mtd nand mtd instance - * @param offset page address to query (muss be page aligned!) + * @param offset page address to query (must be page-aligned!) * * @return -1 in case of error * >0 lock status: @@ -281,7 +281,7 @@ int nand_get_lock_status(struct mtd_info *mtd, loff_t offset)
if ((offset & (mtd->writesize - 1)) != 0) { - printf ("nand_get_lock_status: " + printf("nand_get_lock_status: " "Start address must be beginning of " "nand page!\n"); ret = -1; @@ -332,20 +332,20 @@ int nand_unlock(struct mtd_info *mtd, loff_t start, size_t length, /* check the WP bit */ chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); if (!(chip->read_byte(mtd) & NAND_STATUS_WP)) { - printf ("nand_unlock: Device is write protected!\n"); + printf("nand_unlock: Device is write protected!\n"); ret = -1; goto out; }
if ((start & (mtd->erasesize - 1)) != 0) { - printf ("nand_unlock: Start address must be beginning of " + printf("nand_unlock: Start address must be beginning of " "nand block!\n"); ret = -1; goto out; }
if (length == 0 || (length & (mtd->erasesize - 1)) != 0) { - printf ("nand_unlock: Length must be a multiple of nand block " + printf("nand_unlock: Length must be a multiple of nand block " "size %08x!\n", mtd->erasesize); ret = -1; goto out; @@ -485,7 +485,7 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, pages = nand->erasesize / nand->writesize; blocksize = (pages * nand->oobsize) + nand->erasesize; if (*length % (nand->writesize + nand->oobsize)) { - printf ("Attempt to write incomplete page" + printf("Attempt to write incomplete page" " in yaffs mode\n"); return -EINVAL; } @@ -507,25 +507,25 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, * partition boundary). So don't try to handle that. */ if ((offset & (nand->writesize - 1)) != 0) { - printf ("Attempt to write non page aligned data\n"); + printf("Attempt to write non page-aligned data\n"); *length = 0; return -EINVAL; }
need_skip = check_skip_len(nand, offset, *length); if (need_skip < 0) { - printf ("Attempt to write outside the flash area\n"); + printf("Attempt to write outside the flash area\n"); *length = 0; return -EINVAL; }
if (!need_skip && !(flags & WITH_DROP_FFS)) { - rval = nand_write (nand, offset, length, buffer); + rval = nand_write(nand, offset, length, buffer); if (rval == 0) return 0;
*length = 0; - printf ("NAND write to offset %llx failed %d\n", + printf("NAND write to offset %llx failed %d\n", offset, rval); return rval; } @@ -534,10 +534,10 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, size_t block_offset = offset & (nand->erasesize - 1); size_t write_size, truncated_write_size;
- WATCHDOG_RESET (); + WATCHDOG_RESET();
- if (nand_block_isbad (nand, offset & ~(nand->erasesize - 1))) { - printf ("Skip bad block 0x%08llx\n", + if (nand_block_isbad(nand, offset & ~(nand->erasesize - 1))) { + printf("Skip bad block 0x%08llx\n", offset & ~(nand->erasesize - 1)); offset += nand->erasesize - block_offset; continue; @@ -592,7 +592,7 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, }
if (rval != 0) { - printf ("NAND write to offset %llx failed %d\n", + printf("NAND write to offset %llx failed %d\n", offset, rval); *length -= left_to_write; return rval; @@ -608,13 +608,13 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, * nand_read_skip_bad: * * Read image from NAND flash. - * Blocks that are marked bad are skipped and the next block is readen + * Blocks that are marked bad are skipped and the next block is read * instead as long as the image is short enough to fit even after skipping the * bad blocks. * * @param nand NAND device * @param offset offset in flash - * @param length buffer length, on return holds remaining bytes to read + * @param length buffer length, on return holds number of read bytes * @param buffer buffer to write to * @return 0 in case of success */ @@ -627,25 +627,25 @@ int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, int need_skip;
if ((offset & (nand->writesize - 1)) != 0) { - printf ("Attempt to read non page aligned data\n"); + printf("Attempt to read non page-aligned data\n"); *length = 0; return -EINVAL; }
need_skip = check_skip_len(nand, offset, *length); if (need_skip < 0) { - printf ("Attempt to read outside the flash area\n"); + printf("Attempt to read outside the flash area\n"); *length = 0; return -EINVAL; }
if (!need_skip) { - rval = nand_read (nand, offset, length, buffer); + rval = nand_read(nand, offset, length, buffer); if (!rval || rval == -EUCLEAN) return 0;
*length = 0; - printf ("NAND read from offset %llx failed %d\n", + printf("NAND read from offset %llx failed %d\n", offset, rval); return rval; } @@ -654,10 +654,10 @@ int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, size_t block_offset = offset & (nand->erasesize - 1); size_t read_length;
- WATCHDOG_RESET (); + WATCHDOG_RESET();
- if (nand_block_isbad (nand, offset & ~(nand->erasesize - 1))) { - printf ("Skipping bad block 0x%08llx\n", + if (nand_block_isbad(nand, offset & ~(nand->erasesize - 1))) { + printf("Skipping bad block 0x%08llx\n", offset & ~(nand->erasesize - 1)); offset += nand->erasesize - block_offset; continue; @@ -668,9 +668,9 @@ int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, else read_length = nand->erasesize - block_offset;
- rval = nand_read (nand, offset, &read_length, p_buffer); + rval = nand_read(nand, offset, &read_length, p_buffer); if (rval && rval != -EUCLEAN) { - printf ("NAND read from offset %llx failed %d\n", + printf("NAND read from offset %llx failed %d\n", offset, rval); *length -= left_to_read; return rval;

NAND Flash is erased by blocks, not by pages.
Signed-off-by: Benoît Thébaudeau benoit.thebaudeau@advansee.com Cc: Scott Wood scottwood@freescale.com --- .../drivers/mtd/nand/nand_util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git u-boot-nand-flash-9c60e75.orig/drivers/mtd/nand/nand_util.c u-boot-nand-flash-9c60e75/drivers/mtd/nand/nand_util.c index 3f11103..2855683 100644 --- u-boot-nand-flash-9c60e75.orig/drivers/mtd/nand/nand_util.c +++ u-boot-nand-flash-9c60e75/drivers/mtd/nand/nand_util.c @@ -80,8 +80,8 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts) struct mtd_oob_ops oob_opts; struct nand_chip *chip = meminfo->priv;
- if ((opts->offset & (meminfo->writesize - 1)) != 0) { - printf("Attempt to erase non page-aligned data\n"); + if ((opts->offset & (meminfo->erasesize - 1)) != 0) { + printf("Attempt to erase non block-aligned data\n"); return -1; }

On Mon, Nov 05, 2012 at 10:16:15AM -0000, =?utf-8?q?Beno=C3=AEt_Th=C3=A9baudeau_=3Cbenoit=2Ethebaudeau=40advans?==?utf-8?q?ee=2Ecom=3E?= wrote:
NAND Flash is erased by blocks, not by pages.
Signed-off-by: Benoît Thébaudeau benoit.thebaudeau@advansee.com Cc: Scott Wood scottwood@freescale.com
Applied to u-boot-nand-flash
-Scott

Dear Scott Wood,
On Friday, November 16, 2012 1:23:20 AM, Scott Wood wrote:
On Mon, Nov 05, 2012 at 10:16:15AM -0000, =?utf-8?q?Beno=C3=AEt_Th=C3=A9baudeau_=3Cbenoit=2Ethebaudeau=40advans?==?utf-8?q?ee=2Ecom=3E?= wrote:
NAND Flash is erased by blocks, not by pages.
Signed-off-by: Benoît Thébaudeau benoit.thebaudeau@advansee.com Cc: Scott Wood scottwood@freescale.com
Applied to u-boot-nand-flash
Thanks.
I still don't see it on gitweb. Usually, this takes at most a few hours. Is there a mirror sync issue or something? Unless this is a manual operation for you?
Best regards, Benoît

On 11/19/2012 02:40:31 PM, Benoît Thébaudeau wrote:
Dear Scott Wood,
On Friday, November 16, 2012 1:23:20 AM, Scott Wood wrote:
On Mon, Nov 05, 2012 at 10:16:15AM -0000,
=?utf-8?q?Beno=C3=AEt_Th=C3=A9baudeau_=3Cbenoit=2Ethebaudeau=40advans?==?utf-8?q?ee=2Ecom=3E?=
wrote:
NAND Flash is erased by blocks, not by pages.
Signed-off-by: Benoît Thébaudeau benoit.thebaudeau@advansee.com Cc: Scott Wood scottwood@freescale.com
Applied to u-boot-nand-flash
Thanks.
I still don't see it on gitweb. Usually, this takes at most a few hours. Is there a mirror sync issue or something? Unless this is a manual operation for you?
I'm waiting to get an ack from Andy for the mpc85xx bits before I push my tree, lest I have history that needs changing.
-Scott

This patch adds a NAND Flash torture feature, which is useful as a block stress test to determine if a block is still good and reliable (or should be marked as bad), e.g. after a write error.
This code is ported from mtd-utils' lib/libmtd.c.
Signed-off-by: Benoît Thébaudeau benoit.thebaudeau@advansee.com Cc: Scott Wood scottwood@freescale.com --- .../common/cmd_nand.c | 18 ++++ .../doc/README.nand | 3 + .../drivers/mtd/nand/nand_util.c | 107 ++++++++++++++++++++ .../include/nand.h | 1 + 4 files changed, 129 insertions(+)
diff --git u-boot-nand-flash-9c60e75.orig/common/cmd_nand.c u-boot-nand-flash-9c60e75/common/cmd_nand.c index 9c6dabe..fe5c28c 100644 --- u-boot-nand-flash-9c60e75.orig/common/cmd_nand.c +++ u-boot-nand-flash-9c60e75/common/cmd_nand.c @@ -701,6 +701,23 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) return ret == 0 ? 0 : 1; }
+ if (strcmp(cmd, "torture") == 0) { + if (argc < 3) + goto usage; + + if (!str2off(argv[2], &off)) { + puts("Offset is not a valid number\n"); + return 1; + } + + printf("\nNAND torture: device %d offset 0x%llx size 0x%x\n", + dev, off, nand->erasesize); + ret = nand_torture(nand, off); + printf(" %s\n", ret ? "Failed" : "Passed"); + + return ret == 0 ? 0 : 1; + } + if (strcmp(cmd, "markbad") == 0) { argc -= 2; argv += 2; @@ -812,6 +829,7 @@ U_BOOT_CMD( "nand erase.chip [clean] - erase entire chip'\n" "nand bad - show bad blocks\n" "nand dump[.oob] off - dump page\n" + "nand torture off - torture block at offset\n" "nand scrub [-y] off size | scrub.part partition | scrub.chip\n" " really clean NAND erasing bad blocks (UNSAFE)\n" "nand markbad off [...] - mark bad block(s) at offset (UNSAFE)\n" diff --git u-boot-nand-flash-9c60e75.orig/doc/README.nand u-boot-nand-flash-9c60e75/doc/README.nand index c130189..8a17d11 100644 --- u-boot-nand-flash-9c60e75.orig/doc/README.nand +++ u-boot-nand-flash-9c60e75/doc/README.nand @@ -213,6 +213,9 @@ Miscellaneous and testing commands: DANGEROUS!!! Factory set bad blocks will be lost. Use only to remove artificial bad blocks created with the "markbad" command.
+ "torture offset" + torture block to determine if it is still reliable +
NAND locking command (for chips with active LOCKPRE pin)
diff --git u-boot-nand-flash-9c60e75.orig/drivers/mtd/nand/nand_util.c u-boot-nand-flash-9c60e75/drivers/mtd/nand/nand_util.c index 2855683..ddcb31c 100644 --- u-boot-nand-flash-9c60e75.orig/drivers/mtd/nand/nand_util.c +++ u-boot-nand-flash-9c60e75/drivers/mtd/nand/nand_util.c @@ -683,3 +683,110 @@ int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
return 0; } + +/** + * check_pattern: + * + * Check if buffer contains only a certain byte pattern. + * + * @param buf buffer to check + * @param patt the pattern to check + * @param size buffer size in bytes + * @return 1 if there are only patt bytes in buf + * 0 if something else was found + */ +static int check_pattern(const u_char *buf, u_char patt, int size) +{ + int i; + + for (i = 0; i < size; i++) + if (buf[i] != patt) + return 0; + return 1; +} + +/** + * nand_torture: + * + * Torture a block of NAND flash. + * This is useful to determine if a block that caused a write error is still + * good or should be marked as bad. + * + * @param nand NAND device + * @param offset offset in flash + * @return 0 if the block is still good + */ +int nand_torture(nand_info_t *nand, loff_t offset) +{ + u_char patterns[] = {0xa5, 0x5a, 0x00}; + struct erase_info instr = { + .mtd = nand, + .addr = offset, + .len = nand->erasesize, + }; + size_t retlen; + int res, ret = -1, i, patt_count; + u_char *buf; + + if ((offset & (nand->erasesize - 1)) != 0) { + puts("Attempt to torture a block at a non block-aligned " + "offset\n"); + return -EINVAL; + } + + if (offset + nand->erasesize > nand->size) { + puts("Attempt to torture a block outside the flash area\n"); + return -EINVAL; + } + + patt_count = ARRAY_SIZE(patterns); + + buf = malloc(nand->erasesize); + if (buf == NULL) { + puts("Out of memory for erase block buffer\n"); + return -ENOMEM; + } + + for (i = 0; i < patt_count; i++) { + res = nand->erase(nand, &instr); + if (res) + goto out; + + /* Make sure the block contains only 0xff bytes */ + res = nand->read(nand, offset, nand->erasesize, &retlen, buf); + if ((res && res != -EUCLEAN) || retlen != nand->erasesize) + goto out; + + res = check_pattern(buf, 0xff, nand->erasesize); + if (!res) { + printf("Erased block at 0x%llx, but a non-0xff byte " + "was found\n", offset); + ret = -EIO; + goto out; + } + + /* Write a pattern and check it */ + memset(buf, patterns[i], nand->erasesize); + ret = nand->write(nand, offset, nand->erasesize, &retlen, buf); + if (ret || retlen != nand->erasesize) + goto out; + + res = nand->read(nand, offset, nand->erasesize, &retlen, buf); + if ((res && res != -EUCLEAN) || retlen != nand->erasesize) + goto out; + + res = check_pattern(buf, patterns[i], nand->erasesize); + if (!res) { + printf("Pattern 0x%.2x checking failed for block at " + "0x%llx\n", patterns[i], offset); + ret = -EIO; + goto out; + } + } + + ret = 0; + +out: + free(buf); + return ret; +} diff --git u-boot-nand-flash-9c60e75.orig/include/nand.h u-boot-nand-flash-9c60e75/include/nand.h index bbe28b2..dded4e2 100644 --- u-boot-nand-flash-9c60e75.orig/include/nand.h +++ u-boot-nand-flash-9c60e75/include/nand.h @@ -139,6 +139,7 @@ int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, u_char *buffer, int flags); int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts); +int nand_torture(nand_info_t *nand, loff_t offset);
#define NAND_LOCK_STATUS_TIGHT 0x01 #define NAND_LOCK_STATUS_UNLOCK 0x04

On 11/05/2012 02:16:30 PM, Benoît Thébaudeau wrote:
This patch adds a NAND Flash torture feature, which is useful as a block stress test to determine if a block is still good and reliable (or should be marked as bad), e.g. after a write error.
This code is ported from mtd-utils' lib/libmtd.c.
Signed-off-by: Benoît Thébaudeau benoit.thebaudeau@advansee.com Cc: Scott Wood scottwood@freescale.com
.../common/cmd_nand.c | 18 ++++ .../doc/README.nand | 3 + .../drivers/mtd/nand/nand_util.c | 107 ++++++++++++++++++++ .../include/nand.h | 1 + 4 files changed, 129 insertions(+)
Please define and document a CONFIG symbol to selectively enable this feature.
diff --git u-boot-nand-flash-9c60e75.orig/common/cmd_nand.c u-boot-nand-flash-9c60e75/common/cmd_nand.c index 9c6dabe..fe5c28c 100644 --- u-boot-nand-flash-9c60e75.orig/common/cmd_nand.c +++ u-boot-nand-flash-9c60e75/common/cmd_nand.c @@ -701,6 +701,23 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) return ret == 0 ? 0 : 1; }
- if (strcmp(cmd, "torture") == 0) {
if (argc < 3)
goto usage;
if (!str2off(argv[2], &off)) {
puts("Offset is not a valid number\n");
return 1;
}
printf("\nNAND torture: device %d offset 0x%llx size
0x%x\n",
dev, off, nand->erasesize);
ret = nand_torture(nand, off);
printf(" %s\n", ret ? "Failed" : "Passed");
return ret == 0 ? 0 : 1;
- }
- if (strcmp(cmd, "markbad") == 0) { argc -= 2; argv += 2;
@@ -812,6 +829,7 @@ U_BOOT_CMD( "nand erase.chip [clean] - erase entire chip'\n" "nand bad - show bad blocks\n" "nand dump[.oob] off - dump page\n"
- "nand torture off - torture block at offset\n" "nand scrub [-y] off size | scrub.part partition | scrub.chip\n" " really clean NAND erasing bad blocks (UNSAFE)\n" "nand markbad off [...] - mark bad block(s) at offset
(UNSAFE)\n" diff --git u-boot-nand-flash-9c60e75.orig/doc/README.nand u-boot-nand-flash-9c60e75/doc/README.nand index c130189..8a17d11 100644 --- u-boot-nand-flash-9c60e75.orig/doc/README.nand +++ u-boot-nand-flash-9c60e75/doc/README.nand @@ -213,6 +213,9 @@ Miscellaneous and testing commands: DANGEROUS!!! Factory set bad blocks will be lost. Use only to remove artificial bad blocks created with the "markbad" command.
- "torture offset"
- torture block to determine if it is still reliable
Please elaborate -- for example, what is the return code in the case where it is reliable versus when it is not? Does the block automatically get marked bad if it is unreliable? How many erase cycles does this put the block through?
What's the intended use of this? Manual inquiries by a curious user, or something automated?
/* Make sure the block contains only 0xff bytes */
res = nand->read(nand, offset, nand->erasesize,
&retlen, buf);
if ((res && res != -EUCLEAN) || retlen !=
nand->erasesize)
goto out;
res = check_pattern(buf, 0xff, nand->erasesize);
if (!res) {
printf("Erased block at 0x%llx, but a non-0xff
byte "
"was found\n", offset);
ret = -EIO;
goto out;
}
/* Write a pattern and check it */
memset(buf, patterns[i], nand->erasesize);
ret = nand->write(nand, offset, nand->erasesize,
&retlen, buf);
if (ret || retlen != nand->erasesize)
goto out;
res = nand->read(nand, offset, nand->erasesize,
&retlen, buf);
if ((res && res != -EUCLEAN) || retlen !=
nand->erasesize)
goto out;
Shouldn't you print an error message if the read, write, or erase fails?
-Scott

This patch adds a NAND Flash torture feature, which is useful as a block stress test to determine if a block is still good and reliable (or should be marked as bad), e.g. after a write error.
This code is ported from mtd-utils' lib/libmtd.c.
Signed-off-by: Benoît Thébaudeau benoit.thebaudeau@advansee.com Cc: Scott Wood scottwood@freescale.com --- Changes for v2: - Define and document CONFIG_CMD_NAND_TORTURE to selectively enable this feature. - Elaborate the documentation of the torture command. - Print an error message if the erase, read or write fails. - Rename the res variable to err in order to remove confusion with ret.
.../common/cmd_nand.c | 22 ++++ .../doc/README.nand | 21 ++++ .../drivers/mtd/nand/nand_util.c | 123 ++++++++++++++++++++ .../include/nand.h | 3 + 4 files changed, 169 insertions(+)
diff --git u-boot-nand-flash-9c60e75.orig/common/cmd_nand.c u-boot-nand-flash-9c60e75/common/cmd_nand.c index 9c6dabe..639db81 100644 --- u-boot-nand-flash-9c60e75.orig/common/cmd_nand.c +++ u-boot-nand-flash-9c60e75/common/cmd_nand.c @@ -701,6 +701,25 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) return ret == 0 ? 0 : 1; }
+#ifdef CONFIG_CMD_NAND_TORTURE + if (strcmp(cmd, "torture") == 0) { + if (argc < 3) + goto usage; + + if (!str2off(argv[2], &off)) { + puts("Offset is not a valid number\n"); + return 1; + } + + printf("\nNAND torture: device %d offset 0x%llx size 0x%x\n", + dev, off, nand->erasesize); + ret = nand_torture(nand, off); + printf(" %s\n", ret ? "Failed" : "Passed"); + + return ret == 0 ? 0 : 1; + } +#endif + if (strcmp(cmd, "markbad") == 0) { argc -= 2; argv += 2; @@ -812,6 +831,9 @@ U_BOOT_CMD( "nand erase.chip [clean] - erase entire chip'\n" "nand bad - show bad blocks\n" "nand dump[.oob] off - dump page\n" +#ifdef CONFIG_CMD_NAND_TORTURE + "nand torture off - torture block at offset\n" +#endif "nand scrub [-y] off size | scrub.part partition | scrub.chip\n" " really clean NAND erasing bad blocks (UNSAFE)\n" "nand markbad off [...] - mark bad block(s) at offset (UNSAFE)\n" diff --git u-boot-nand-flash-9c60e75.orig/doc/README.nand u-boot-nand-flash-9c60e75/doc/README.nand index c130189..a1a511c 100644 --- u-boot-nand-flash-9c60e75.orig/doc/README.nand +++ u-boot-nand-flash-9c60e75/doc/README.nand @@ -108,6 +108,9 @@ Configuration Options: CONFIG_CMD_NAND Enables NAND support and commmands.
+ CONFIG_CMD_NAND_TORTURE + Enables the torture command (see description of this command below). + CONFIG_MTD_NAND_ECC_JFFS2 Define this if you want the Error Correction Code information in the out-of-band data to be formatted to match the JFFS2 file system. @@ -213,6 +216,24 @@ Miscellaneous and testing commands: DANGEROUS!!! Factory set bad blocks will be lost. Use only to remove artificial bad blocks created with the "markbad" command.
+ "torture offset" + Torture block to determine if it is still reliable. + Enabled by the CONFIG_CMD_NAND_TORTURE configuration option. + This command returns 0 if the block is still reliable, else 1. + If the block is detected as unreliable, it is up to the user to decide to + mark this block as bad. + The analyzed block is put through 3 erase / write cycles (or less if the block + is detected as unreliable earlier). + This command can be used in scripts, e.g. together with the markbad command to + automate retries and handling of possibly newly detected bad blocks if the + nand write command fails. + It can also be used manually by users having seen some NAND errors in logs to + search the root cause of these errors. + The underlying nand_torture() function is also useful for code willing to + automate actions following a nand->write() error. This would e.g. be required + in order to program or update safely firmware to NAND, especially for the UBI + part of such firmware. +
NAND locking command (for chips with active LOCKPRE pin)
diff --git u-boot-nand-flash-9c60e75.orig/drivers/mtd/nand/nand_util.c u-boot-nand-flash-9c60e75/drivers/mtd/nand/nand_util.c index 2855683..a162964 100644 --- u-boot-nand-flash-9c60e75.orig/drivers/mtd/nand/nand_util.c +++ u-boot-nand-flash-9c60e75/drivers/mtd/nand/nand_util.c @@ -683,3 +683,126 @@ int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
return 0; } + +#ifdef CONFIG_CMD_NAND_TORTURE + +/** + * check_pattern: + * + * Check if buffer contains only a certain byte pattern. + * + * @param buf buffer to check + * @param patt the pattern to check + * @param size buffer size in bytes + * @return 1 if there are only patt bytes in buf + * 0 if something else was found + */ +static int check_pattern(const u_char *buf, u_char patt, int size) +{ + int i; + + for (i = 0; i < size; i++) + if (buf[i] != patt) + return 0; + return 1; +} + +/** + * nand_torture: + * + * Torture a block of NAND flash. + * This is useful to determine if a block that caused a write error is still + * good or should be marked as bad. + * + * @param nand NAND device + * @param offset offset in flash + * @return 0 if the block is still good + */ +int nand_torture(nand_info_t *nand, loff_t offset) +{ + u_char patterns[] = {0xa5, 0x5a, 0x00}; + struct erase_info instr = { + .mtd = nand, + .addr = offset, + .len = nand->erasesize, + }; + size_t retlen; + int err, ret = -1, i, patt_count; + u_char *buf; + + if ((offset & (nand->erasesize - 1)) != 0) { + puts("Attempt to torture a block at a non block-aligned " + "offset\n"); + return -EINVAL; + } + + if (offset + nand->erasesize > nand->size) { + puts("Attempt to torture a block outside the flash area\n"); + return -EINVAL; + } + + patt_count = ARRAY_SIZE(patterns); + + buf = malloc(nand->erasesize); + if (buf == NULL) { + puts("Out of memory for erase block buffer\n"); + return -ENOMEM; + } + + for (i = 0; i < patt_count; i++) { + err = nand->erase(nand, &instr); + if (err) { + printf("%s: erase() failed for block at 0x%llx: %d\n", + nand->name, instr.addr, err); + goto out; + } + + /* Make sure the block contains only 0xff bytes */ + err = nand->read(nand, offset, nand->erasesize, &retlen, buf); + if ((err && err != -EUCLEAN) || retlen != nand->erasesize) { + printf("%s: read() failed for block at 0x%llx: %d\n", + nand->name, instr.addr, err); + goto out; + } + + err = check_pattern(buf, 0xff, nand->erasesize); + if (!err) { + printf("Erased block at 0x%llx, but a non-0xff byte " + "was found\n", offset); + ret = -EIO; + goto out; + } + + /* Write a pattern and check it */ + memset(buf, patterns[i], nand->erasesize); + err = nand->write(nand, offset, nand->erasesize, &retlen, buf); + if (err || retlen != nand->erasesize) { + printf("%s: write() failed for block at 0x%llx: %d\n", + nand->name, instr.addr, err); + goto out; + } + + err = nand->read(nand, offset, nand->erasesize, &retlen, buf); + if ((err && err != -EUCLEAN) || retlen != nand->erasesize) { + printf("%s: read() failed for block at 0x%llx: %d\n", + nand->name, instr.addr, err); + goto out; + } + + err = check_pattern(buf, patterns[i], nand->erasesize); + if (!err) { + printf("Pattern 0x%.2x checking failed for block at " + "0x%llx\n", patterns[i], offset); + ret = -EIO; + goto out; + } + } + + ret = 0; + +out: + free(buf); + return ret; +} + +#endif diff --git u-boot-nand-flash-9c60e75.orig/include/nand.h u-boot-nand-flash-9c60e75/include/nand.h index bbe28b2..c4530b0 100644 --- u-boot-nand-flash-9c60e75.orig/include/nand.h +++ u-boot-nand-flash-9c60e75/include/nand.h @@ -139,6 +139,9 @@ int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, u_char *buffer, int flags); int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts); +#ifdef CONFIG_CMD_NAND_TORTURE +int nand_torture(nand_info_t *nand, loff_t offset); +#endif
#define NAND_LOCK_STATUS_TIGHT 0x01 #define NAND_LOCK_STATUS_UNLOCK 0x04

On 11/16/2012 01:20:54 PM, Benoît Thébaudeau wrote:
+int nand_torture(nand_info_t *nand, loff_t offset) +{
- u_char patterns[] = {0xa5, 0x5a, 0x00};
- struct erase_info instr = {
.mtd = nand,
.addr = offset,
.len = nand->erasesize,
- };
- size_t retlen;
- int err, ret = -1, i, patt_count;
- u_char *buf;
- if ((offset & (nand->erasesize - 1)) != 0) {
puts("Attempt to torture a block at a non block-aligned
"
"offset\n");
return -EINVAL;
- }
- if (offset + nand->erasesize > nand->size) {
puts("Attempt to torture a block outside the flash
area\n");
return -EINVAL;
- }
I won't hold up the patch for this, since I think it works out OK due to type promotion rules (and in any case there are easier ways for a hostile user to do bad things in U-Boot) with nand->size being uint64_t, but loff_t is signed. An explicit cast would be nice.
- patt_count = ARRAY_SIZE(patterns);
- buf = malloc(nand->erasesize);
- if (buf == NULL) {
puts("Out of memory for erase block buffer\n");
return -ENOMEM;
- }
- for (i = 0; i < patt_count; i++) {
err = nand->erase(nand, &instr);
if (err) {
printf("%s: erase() failed for block at 0x%llx:
%d\n",
nand->name, instr.addr, err);
goto out;
}
/* Make sure the block contains only 0xff bytes */
err = nand->read(nand, offset, nand->erasesize,
&retlen, buf);
if ((err && err != -EUCLEAN) || retlen !=
nand->erasesize) {
printf("%s: read() failed for block at 0x%llx:
%d\n",
nand->name, instr.addr, err);
goto out;
}
err = check_pattern(buf, 0xff, nand->erasesize);
if (!err) {
printf("Erased block at 0x%llx, but a non-0xff
byte "
"was found\n", offset);
ret = -EIO;
goto out;
}
Strings should not be wrapped (to improve greppability of errors), even if it would put the line over 80 columns. I'll fix this when applying.
diff --git u-boot-nand-flash-9c60e75.orig/include/nand.h u-boot-nand-flash-9c60e75/include/nand.h index bbe28b2..c4530b0 100644 --- u-boot-nand-flash-9c60e75.orig/include/nand.h +++ u-boot-nand-flash-9c60e75/include/nand.h @@ -139,6 +139,9 @@ int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, u_char *buffer, int flags); int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts); +#ifdef CONFIG_CMD_NAND_TORTURE +int nand_torture(nand_info_t *nand, loff_t offset); +#endif
Prototypes should not be ifdeffed. Will fix when applying.
Applied to u-boot-nand-flash.
-Scott

On Mon, Nov 05, 2012 at 10:15:46AM -0000, =?utf-8?q?Beno=C3=AEt_Th=C3=A9baudeau_=3Cbenoit=2Ethebaudeau=40advans?==?utf-8?q?ee=2Ecom=3E?= wrote:
This patch cleans up nand_util.c:
- Fix tabs.
- Fix typos.
- Remove space character before opening parenthesis in function calls.
- Fix comments.
Signed-off-by: Benoît Thébaudeau benoit.thebaudeau@advansee.com Cc: Scott Wood scottwood@freescale.com
.../drivers/mtd/nand/nand_util.c | 64 ++++++++++---------- 1 file changed, 32 insertions(+), 32 deletions(-)
Applied to u-boot-nand-flash
-Scott

On 11/15/2012 06:22:11 PM, Scott Wood wrote:
On Mon, Nov 05, 2012 at 10:15:46AM -0000, =?utf-8?q?Beno=C3=AEt_Th=C3=A9baudeau_=3Cbenoit=2Ethebaudeau=40advans?==?utf-8?q?ee=2Ecom=3E?= wrote:
Sigh, it looks like either patchwork is mangling the From address or mutt is failing to understand something valid (I assume the latter since "git am" didn't seem to have a problem with it)... I don't see this encoding in the original e-mail.
-Scott

Dear Scott Wood,
On 16.11.12 01:29, Scott Wood wrote:
On 11/15/2012 06:22:11 PM, Scott Wood wrote:
On Mon, Nov 05, 2012 at 10:15:46AM -0000, =?utf-8?q?Beno=C3=AEt_Th=C3=A9baudeau_=3Cbenoit=2Ethebaudeau=40advans?==?utf-8?q?ee=2Ecom=3E?= wrote:
Sigh, it looks like either patchwork is mangling the From address or mutt is failing to understand something valid (I assume the latter since "git am" didn't seem to have a problem with it)... I don't see this encoding in the original e-mail.
patchwork has no influence her. AFAIK the mail header should only contain ASCII, therefore the 'From:' header content is itself encoded. This snippet manage to decode Benoîts name correctly:
---8<--- perl -MEncode -e 'binmode(STDOUT, ":utf8"); print Encode::decode("MIME-Header", "=?utf-8?Q?Beno=C3=AEt_Th=C3=A9baudeau?= benoit.thebaudeau@advansee.com");' --->8---
git and even patchwork [1] can decode it, but it seems your mutt rule to setup the rely mail is broken. Maybe [2] can help here?
Best regards
Andreas Bießmann
[1] http://patchwork.ozlabs.org/project/uboot/list/?submitter=14629&state=* [2] http://www.michnet.de/mutt/#purgemail

On Fri, Nov 16, 2012 at 08:20:50AM +0100, Andreas Bießmann wrote:
Dear Scott Wood,
On 16.11.12 01:29, Scott Wood wrote:
On 11/15/2012 06:22:11 PM, Scott Wood wrote:
On Mon, Nov 05, 2012 at 10:15:46AM -0000, =?utf-8?q?Beno=C3=AEt_Th=C3=A9baudeau_=3Cbenoit=2Ethebaudeau=40advans?==?utf-8?q?ee=2Ecom=3E?= wrote:
Sigh, it looks like either patchwork is mangling the From address or mutt is failing to understand something valid (I assume the latter since "git am" didn't seem to have a problem with it)... I don't see this encoding in the original e-mail.
patchwork has no influence her. AFAIK the mail header should only contain ASCII, therefore the 'From:' header content is itself encoded. This snippet manage to decode Benoîts name correctly:
---8<--- perl -MEncode -e 'binmode(STDOUT, ":utf8"); print Encode::decode("MIME-Header", "=?utf-8?Q?Beno=C3=AEt_Th=C3=A9baudeau?= benoit.thebaudeau@advansee.com");' --->8---
git and even patchwork [1] can decode it, but it seems your mutt rule to setup the rely mail is broken. Maybe [2] can help here?
I don't quite know what's going on here, but I also have this problem when replying to bundles from patchwork (which of course 'git am' fine) but not when replying to emails via IMAP. I've just been fixing this up by hand however (since it's correct in the email body).
participants (4)
-
Andreas Bießmann
-
Benoît Thébaudeau
-
Scott Wood
-
Tom Rini