From patchwork Mon Nov 5 20:16:30 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Beno=C3=AEt_Th=C3=A9baudeau?= X-Patchwork-Id: 197293 X-Patchwork-Delegate: scottwood@freescale.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 5AEEF2C00B4 for ; Tue, 6 Nov 2012 07:10:11 +1100 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 183954A415; Mon, 5 Nov 2012 21:10:10 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id OPJmE0M4-OQx; Mon, 5 Nov 2012 21:10:09 +0100 (CET) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 6AAD34A41C; Mon, 5 Nov 2012 21:10:08 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id E84914A415 for ; Mon, 5 Nov 2012 21:10:06 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 2wl-EMK-rGjT for ; Mon, 5 Nov 2012 21:10:06 +0100 (CET) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from zose-mta13.web4all.fr (zose-mta-13.w4a.fr [178.33.204.90]) by theia.denx.de (Postfix) with ESMTP id 111E84A42F for ; Mon, 5 Nov 2012 21:10:04 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by zose-mta13.web4all.fr (Postfix) with ESMTP id 8D18A58058; Mon, 5 Nov 2012 21:08:25 +0100 (CET) X-Virus-Scanned: amavisd-new at zose1.web4all.fr Received: from zose-mta13.web4all.fr ([127.0.0.1]) by localhost (zose-mta13.web4all.fr [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id eouNGHeBViiv; Mon, 5 Nov 2012 21:08:24 +0100 (CET) Received: from zose-store12.web4all.fr (zose-store12.web4all.fr [178.33.204.49]) by zose-mta13.web4all.fr (Postfix) with ESMTP id 7712F58049; Mon, 5 Nov 2012 21:08:24 +0100 (CET) Date: Mon, 5 Nov 2012 21:16:30 +0100 (CET) From: =?utf-8?Q?Beno=C3=AEt_Th=C3=A9baudeau?= To: U-Boot-Users ML Message-ID: <1330941635.587470.1352146590666.JavaMail.root@advansee.com> In-Reply-To: <1708288193.587453.1352146546966.JavaMail.root@advansee.com> MIME-Version: 1.0 X-Originating-IP: [88.188.188.98] X-Mailer: Zimbra 7.2.0_GA_2669 (ZimbraWebClient - FF3.0 (Win)/7.2.0_GA_2669) Cc: Scott Wood Subject: [U-Boot] [PATCH 3/3] nand: Add torture feature X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.11 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de 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 Cc: Scott Wood --- .../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