From edcd5dafa3f8529467fbafbb8f37b44e90d77c41 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 11 Sep 2007 11:48:43 +0200 Subject: Improve option handling in nandtest, add markbad and offset/length options. Signed-off-by: David Woodhouse --- nandtest.c | 296 +++++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 202 insertions(+), 94 deletions(-) (limited to 'nandtest.c') diff --git a/nandtest.c b/nandtest.c index 35766d8..7613a52 100644 --- a/nandtest.c +++ b/nandtest.c @@ -15,6 +15,111 @@ #include #include "mtd/mtd-user.h" +void usage(void) +{ + fprintf(stderr, "usage: nandtest [OPTIONS] \n\n" + " -h, --help Display this help output\n" + " -m, --markbad Mark blocks bad if they appear so\n" + " -s, --seed Supply random seed\n" + " -p, --passes Number of passes\n" + " -o, --offset Start offset on flash\n" + " -l, --length Length of flash to test\n" + " -k, --keep Restore existing contents after test\n"); + exit(1); +} + +struct mtd_info_user meminfo; +struct mtd_ecc_stats oldstats, newstats; +int fd; +int markbad=0; +int seed; + +int erase_and_write(loff_t ofs, unsigned char *data, unsigned char *rbuf) +{ + struct erase_info_user er; + ssize_t len; + int i; + + printf("\r%08x: erasing... ", (unsigned)ofs); + fflush(stdout); + + er.start = ofs; + er.length = meminfo.erasesize; + + if (ioctl(fd, MEMERASE, &er)) { + perror("MEMERASE"); + if (markbad) { + printf("Mark block bad at %08lx\n", (long)ofs); + ioctl(fd, MEMSETBADBLOCK, &ofs); + } + return 1; + } + + printf("\r%08x: writing...", (unsigned)ofs); + fflush(stdout); + + len = pwrite(fd, data, meminfo.erasesize, ofs); + if (len < 0) { + printf("\n"); + perror("write"); + if (markbad) { + printf("Mark block bad at %08lx\n", (long)ofs); + ioctl(fd, MEMSETBADBLOCK, &ofs); + } + return 1; + } + if (len < meminfo.erasesize) { + printf("\n"); + fprintf(stderr, "Short write (%d bytes)\n", len); + exit(1); + } + + printf("\r%08x: reading...", (unsigned)ofs); + fflush(stdout); + + len = pread(fd, rbuf, meminfo.erasesize, ofs); + if (len < meminfo.erasesize) { + printf("\n"); + if (len) + fprintf(stderr, "Short read (%d bytes)\n", len); + else + perror("read"); + exit(1); + } + + if (ioctl(fd, ECCGETSTATS, &newstats)) { + printf("\n"); + perror("ECCGETSTATS"); + close(fd); + exit(1); + } + + if (newstats.corrected > oldstats.corrected) { + printf("\nECC corrected at %08x\n", (unsigned) ofs); + oldstats.corrected = newstats.corrected; + } + if (newstats.failed > oldstats.failed) { + printf("\nECC failed at %08x\n", (unsigned) ofs); + oldstats.corrected = newstats.corrected; + } + if (len < meminfo.erasesize) + exit(1); + + printf("\r%08x: checking...", (unsigned)ofs); + fflush(stdout); + + if (memcmp(data, rbuf, meminfo.erasesize)) { + printf("\n"); + fprintf(stderr, "compare failed. seed %d\n", seed); + for (i=0; i [] []\n", - (strrchr(argv[0],',')?:argv[0]-1)+1); - exit(1); + for (;;) { + static const char *short_options="hkl:mo:p:s:"; + static const struct option long_options[] = { + { "help", no_argument, 0, 'h' }, + { "markbad", no_argument, 0, 'm' }, + { "seed", required_argument, 0, 's' }, + { "passes", required_argument, 0, 'p' }, + { "offset", required_argument, 0, 'o' }, + { "length", required_argument, 0, 'l' }, + { "keep", no_argument, 0, 'k' }, + {0, 0, 0, 0}, + }; + int option_index = 0; + int c = getopt_long(argc, argv, short_options, long_options, &option_index); + if (c == EOF) + break; + + switch (c) { + case 'h': + case '?': + usage(); + break; + + case 'm': + markbad = 1; + break; + + case 'k': + keep_contents = 1; + break; + + case 's': + seed = atol(optarg); + break; + + case 'p': + nr_passes = atol(optarg); + break; + + case 'o': + offset = atol(optarg); + break; + + case 'l': + length = strtol(optarg, NULL, 0); + break; + + } } + if (argc - optind != 1) + usage(); - fd = open(argv[1], O_RDWR); + fd = open(argv[optind], O_RDWR); if (fd < 0) { perror("open"); exit(1); @@ -57,13 +199,33 @@ int main(int argc, char **argv) exit(1); } - wbuf = malloc(meminfo.erasesize * 2); + if (length == -1) + length = meminfo.size; + + if (offset % meminfo.erasesize) { + fprintf(stderr, "Offset %x not multiple of erase size %x\n", + offset, meminfo.erasesize); + exit(1); + } + if (length % meminfo.erasesize) { + fprintf(stderr, "Length %x not multiple of erase size %x\n", + length, meminfo.erasesize); + exit(1); + } + if (length + offset > meminfo.size) { + fprintf(stderr, "Length %x + offset %x exceeds device size %x\n", + length, offset, meminfo.size); + exit(1); + } + + wbuf = malloc(meminfo.erasesize * 3); if (!wbuf) { fprintf(stderr, "Could not allocate %d bytes for buffer\n", meminfo.erasesize * 2); exit(1); } rbuf = wbuf + meminfo.erasesize; + kbuf = rbuf + meminfo.erasesize; if (ioctl(fd, ECCGETSTATS, &oldstats)) { perror("ECCGETSTATS"); @@ -77,94 +239,40 @@ int main(int argc, char **argv) printf("BBT blocks : %d\n", oldstats.bbtblocks); for (pass = 0; pass < nr_passes; pass++) { - - for (block = 0; block < meminfo.size / meminfo.erasesize ; block++) { - loff_t ofs = block * meminfo.erasesize; - struct erase_info_user er; + loff_t test_ofs; + + for (test_ofs = offset; test_ofs < offset+length; test_ofs += meminfo.erasesize) { ssize_t len; seed = rand(); srand(seed); - if (ioctl(fd, MEMGETBADBLOCK, &ofs)) { - printf("\rBad block at 0x%08x\n", (unsigned)ofs); + if (ioctl(fd, MEMGETBADBLOCK, &test_ofs)) { + printf("\rBad block at 0x%08x\n", (unsigned)test_ofs); continue; } - printf("\r%08x: erasing... ", (unsigned)ofs); - fflush(stdout); - - er.start = ofs; - er.length = meminfo.erasesize; - - if (ioctl(fd, MEMERASE, &er)) { - perror("MEMERASE"); - exit(1); - } - - printf("\r%08x: writing...", (unsigned)ofs); - fflush(stdout); - for (i=0; i oldstats.corrected) { - printf("\nECC corrected at %08x\n", (unsigned) ofs); - oldstats.corrected = newstats.corrected; - } - if (newstats.failed > oldstats.failed) { - printf("\nECC failed at %08x\n", (unsigned) ofs); - oldstats.corrected = newstats.corrected; - } - if (len < meminfo.erasesize) - exit(1); - - printf("\r%08x: checking...", (unsigned)ofs); - fflush(stdout); - - if (memcmp(wbuf, rbuf, meminfo.erasesize)) { - printf("\n"); - fprintf(stderr, "compare failed. seed %d\n", seed); - for (i=0; i