All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Benoît Thébaudeau" <benoit.thebaudeau@advansee.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH v2] nand: Add torture feature
Date: Fri, 16 Nov 2012 20:20:54 +0100 (CET)	[thread overview]
Message-ID: <1752254295.1495778.1353093654020.JavaMail.root@advansee.com> (raw)
In-Reply-To: <1330941635.587470.1352146590666.JavaMail.root@advansee.com>

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

  parent reply	other threads:[~2012-11-16 19:20 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-11-05 20:15 [U-Boot] [PATCH 1/3] nand: Clean up nand_util Benoît Thébaudeau
2012-11-05 20:16 ` [U-Boot] [PATCH 2/3] nand: Fix nand_erase_opts() offset check Benoît Thébaudeau
2012-11-16  0:23   ` [U-Boot] [U-Boot,2/3] " Scott Wood
2012-11-19 20:40     ` Benoît Thébaudeau
2012-11-19 20:51       ` Scott Wood
2012-11-05 20:16 ` [U-Boot] [PATCH 3/3] nand: Add torture feature Benoît Thébaudeau
2012-11-06  0:03   ` Scott Wood
2012-11-16 19:20   ` Benoît Thébaudeau [this message]
2012-11-16 23:54     ` [U-Boot] [PATCH v2] " Scott Wood
2012-11-16  0:22 ` [U-Boot] [U-Boot,1/3] nand: Clean up nand_util Scott Wood
2012-11-16  0:29   ` Scott Wood
2012-11-16  7:20     ` Andreas Bießmann
2012-11-19 20:54       ` Tom Rini

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1752254295.1495778.1353093654020.JavaMail.root@advansee.com \
    --to=benoit.thebaudeau@advansee.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.