[U-Boot] [PATCH 3/3] nand: Add torture feature
Benoît Thébaudeau
benoit.thebaudeau at advansee.com
Mon Nov 5 21:16:30 CET 2012
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 at advansee.com>
Cc: Scott Wood <scottwood at 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
More information about the U-Boot
mailing list