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.thebaud...@advansee.com>
Cc: Scott Wood <scottw...@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
_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to