[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