From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail.sigma-star.at ([95.130.255.111]) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1auolo-0004wP-DS for linux-mtd@lists.infradead.org; Mon, 25 Apr 2016 22:14:22 +0000 From: Richard Weinberger To: linux-mtd@lists.infradead.org Cc: david.oberhollenzer@sigma-star.at, Richard Weinberger Subject: [PATCH 7/8] mtd-utils: Add flash read test utility Date: Tue, 26 Apr 2016 00:13:28 +0200 Message-Id: <1461622409-14970-8-git-send-email-richard@nod.at> In-Reply-To: <1461622409-14970-1-git-send-email-richard@nod.at> References: <1461622409-14970-1-git-send-email-richard@nod.at> List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: David Oberhollenzer Basically a user space port of the mtd read test kernel module. In addition to the module parameters, the utility can scan only a sub-range of the flash erase block with a configurable stride. Signed-off-by: David Oberhollenzer Signed-off-by: Richard Weinberger --- .gitignore | 1 + Makefile | 3 +- misc-utils/flash_readtest.c | 263 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 266 insertions(+), 1 deletion(-) create mode 100644 misc-utils/flash_readtest.c diff --git a/.gitignore b/.gitignore index 5f948e7..8e240d5 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,7 @@ /misc-utils/flashcp /misc-utils/ftl_check /misc-utils/ftl_format +/misc-utils/flash_readtest /jffsX-utils/jffs2dump /jffsX-utils/jffs2reader /jffsX-utils/mkfs.jffs2 diff --git a/Makefile b/Makefile index 2813f3a..add8864 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,8 @@ MISC_BINS = \ ftl_format doc_loadbios ftl_check mtd_debug docfdisk \ serve_image recv_image mtdpart flash_erase flash_lock \ flash_unlock flash_otp_info flash_otp_dump flash_otp_lock \ - flash_otp_write flashcp flash_torture flash_stress flash_speed + flash_otp_write flashcp flash_torture flash_stress flash_speed \ + flash_readtest UBI_BINS = \ ubiupdatevol ubimkvol ubirmvol ubicrc32 ubinfo ubiattach \ ubidetach ubinize ubiformat ubirename mtdinfo ubirsvol ubiblock diff --git a/misc-utils/flash_readtest.c b/misc-utils/flash_readtest.c new file mode 100644 index 0000000..9c15f67 --- /dev/null +++ b/misc-utils/flash_readtest.c @@ -0,0 +1,263 @@ +/* + * Copyright (C) 2006-2008 Nokia Corporation + * Copyright (C) 2015 sigma star gmbh + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; see the file COPYING. If not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Check MTD device read. + * + * Author: David Oberhollenzer + * + * Based on linux readtest.c + * Author: Adrian Hunter + */ +#define PROGRAM_NAME "flash_readtest" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +#define FLAG_VERBOSE 1 + +static int peb=-1, skip=-1, count=-1, flags=0, pgcnt, pgsize, fd; +static unsigned char *iobuf, *iobuf1; +static struct mtd_dev_info mtd; +static const char *mtddev; +static libmtd_t mtd_desc; + +static void usage(int status) +{ + fputs( + "Usage: "PROGRAM_NAME" [OPTIONS] \n\n" + "Common options:\n" + " -h, --help Display this help output\n" + " -b, --peb Start from this physical erase block\n" + " -c, --count Number of erase blocks to process (default: all)\n" + " -s, --skip Number of blocks to skip\n" + " -v, --verbose Generate more verbose output\n\n", + status==EXIT_SUCCESS ? stdout : stderr); + exit(status); +} + +static long read_num(int idx, int argidx, int argc, char **argv) +{ + char *end; + long num; + + if (argidx >= argc) { + fprintf(stderr, "%s: missing argument\n", argv[idx]); + exit(EXIT_FAILURE); + } + + num = strtol(argv[argidx], &end, 0); + + if (!end || *end!='\0') { + fprintf(stderr, "%s: expected integer argument\n", argv[idx]); + exit(EXIT_FAILURE); + } + return num; +} + +static void process_options(int argc, char **argv) +{ + int i; + + for (i=1; i= 0) + goto failmulti; + peb = read_num(i, i+1, argc, argv); + if (peb < 0) + goto failarg; + ++i; + } else if (!strcmp(argv[i], "--count") || !strcmp(argv[i], "-c")) { + if (count >= 0) + goto failmulti; + count = read_num(i, i+1, argc, argv); + if (count < 0) + goto failarg; + ++i; + } else if (!strcmp(argv[i], "--skip") || !strcmp(argv[i], "-s")) { + if (skip >= 0) + goto failmulti; + skip = read_num(i, i+1, argc, argv); + if (skip < 0) + goto failarg; + ++i; + } else { + if (mtddev) + usage(EXIT_FAILURE); + mtddev = argv[i]; + } + } + + if (!mtddev) + errmsg_die("No device specified!"); + + if (peb < 0) + peb = 0; + if (skip < 0) + skip = 0; + return; +failmulti: + errmsg_die("'%s' specified more than once!", argv[i]); +failarg: + errmsg_die("Invalid argument for '%s'!", argv[i]); +} + +static int read_eraseblock_by_page(int ebnum) +{ + unsigned char *buf = iobuf, *oobbuf = iobuf1; + uint64_t addr = ((uint64_t)ebnum) * ((uint64_t)mtd.eb_size); + int i, ret; + + for (i = 0; i < pgcnt; ++i) { + memset(buf, 0, pgsize); + ret = mtd_read(&mtd, fd, ebnum, i*pgsize, buf, pgsize); + if (ret) { + fprintf(stderr, "Error reading block %d, page %d\n", ebnum, i); + return -1; + } + if (mtd.oob_size) { + ret = mtd_read_oob(mtd_desc, &mtd, fd, + addr, mtd.oob_size, oobbuf); + + if (ret) { + fprintf(stderr, "Error reading OOB in block %d, page %d\n", + ebnum, i); + return -1; + } + oobbuf += mtd.oob_size; + } + buf += pgsize; + addr += pgsize; + } + + if (flags & FLAG_VERBOSE) + printf("Successfully read erase block %d\n", ebnum); + + return 0; +} + +static void dump_eraseblock(int ebnum) +{ + char line[128]; + int i, j, n; + int pg, oob; + + printf("dumping eraseblock %d\n", ebnum); + n = mtd.eb_size; + for (i = 0; i < n;) { + char *p = line; + + p += sprintf(p, "%05x: ", i); + for (j = 0; j < 32 && i < n; j++, i++) + p += sprintf(p, "%02x", (unsigned int)iobuf[i]); + printf("%s\n", line); + } + if (!mtd.oob_size) + return; + printf("dumping oob from eraseblock %d\n", ebnum); + n = mtd.oob_size; + for (pg = 0, i = 0; pg < pgcnt; ++pg) { + for (oob = 0; oob < n;) { + char *p = line; + + p += sprintf(p, "%05x: ", i); + for (j = 0; j < 32 && oob < n; ++j, ++oob, ++i) + p += sprintf(p, "%02x", (unsigned int)iobuf1[i]); + printf("%s\n", line); + } + } + putchar('\n'); +} + +int main(int argc, char **argv) +{ + int status = EXIT_SUCCESS, i, ret, blk; + + process_options(argc, argv); + + mtd_desc = libmtd_open(); + if (!mtd_desc) + return errmsg("can't initialize libmtd"); + + if (mtd_get_dev_info(mtd_desc, mtddev, &mtd) < 0) + return errmsg("mtd_get_dev_info failed"); + + if (mtd.subpage_size == 1) { + puts("not NAND flash, assume page size is 512 bytes."); + pgsize = 512; + } else { + pgsize = mtd.subpage_size; + } + + pgcnt = mtd.eb_size / pgsize; + + if (count < 0) + count = mtd.eb_cnt; + + if (peb >= mtd.eb_cnt) + return errmsg("Physical erase block %d is out of range!\n", peb); + + if ((peb + (count - 1)*(skip + 1)) >= mtd.eb_cnt) { + return errmsg("Given block range exceeds block count of %d!\n", + mtd.eb_cnt); + } + + iobuf = xmalloc(mtd.eb_size); + iobuf1 = xmalloc(mtd.eb_size); + + if ((fd = open(mtddev, O_RDWR)) == -1) { + perror(mtddev); + status = EXIT_FAILURE; + goto out; + } + + /* Read all eraseblocks 1 page at a time */ + puts("testing page read"); + + for (i = 0; i < count; ++i) { + blk = peb + i*(skip+1); + + if (mtd_is_bad(&mtd, fd, blk)) { + printf("Skipping bad block %d\n", blk); + continue; + } + ret = read_eraseblock_by_page(blk); + if (ret && (flags & FLAG_VERBOSE)) { + dump_eraseblock(blk); + status = EXIT_FAILURE; + } + } +out: + free(iobuf); + free(iobuf1); + return status; +} + -- 2.7.3