]> www.infradead.org Git - mtd-utils.git/commitdiff
Add nand integrity testing utility.
authorDavid Woodhouse <dwmw2@infradead.org>
Thu, 9 Aug 2007 08:23:19 +0000 (16:23 +0800)
committerDavid Woodhouse <dwmw2@infradead.org>
Thu, 9 Aug 2007 08:23:19 +0000 (16:23 +0800)
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
Makefile
nandtest.c [new file with mode: 0644]

index ae452614e4d501f56b7976543afc4a5178598e7a..4f741583b3b9b1c3f9621a027aadb3d744710a32 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -21,7 +21,7 @@ endif
 
 RAWTARGETS = ftl_format flash_erase flash_eraseall nanddump doc_loadbios \
        mkfs.jffs ftl_check mkfs.jffs2 flash_lock flash_unlock flash_info \
-       flash_otp_info flash_otp_dump mtd_debug flashcp nandwrite \
+       flash_otp_info flash_otp_dump mtd_debug flashcp nandwrite nandtest \
        jffs2dump \
        nftldump nftl_format docfdisk \
        rfddump rfdformat \
@@ -72,6 +72,12 @@ $(BUILDDIR)/jffs2dump: $(BUILDDIR)/jffs2dump.o $(BUILDDIR)/crc32.o
 $(BUILDDIR)/sumtool: $(BUILDDIR)/sumtool.o $(BUILDDIR)/crc32.o
        $(CC) $(LDFLAGS) -o $@ $^
 
+$(BUILDDIR)/serve_image: $(BUILDDIR)/serve_image.o $(BUILDDIR)/crc32.o
+       $(CC) $(LDFLAGS) -o $@ $^
+
+$(BUILDDIR)/recv_image: $(BUILDDIR)/recv_image.o $(BUILDDIR)/crc32.o
+       $(CC) $(LDFLAGS) -o $@ $^
+
 install: ${TARGETS}
        mkdir -p ${DESTDIR}/${SBINDIR}
        install -m0755 ${TARGETS} ${DESTDIR}/${SBINDIR}/
diff --git a/nandtest.c b/nandtest.c
new file mode 100644 (file)
index 0000000..254d41f
--- /dev/null
@@ -0,0 +1,172 @@
+#define _GNU_SOURCE
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <getopt.h>
+
+#include <asm/types.h>
+#include "mtd/mtd-user.h"
+
+
+
+/*
+ * Main program
+ */
+int main(int argc, char **argv)
+{
+       int fd;
+       int block, i;
+       unsigned char *wbuf, *rbuf;
+       struct mtd_info_user meminfo;
+       struct mtd_ecc_stats oldstats, newstats;
+       int seed;
+       int pass;
+       int nr_passes = 1;
+
+       if (argc == 4) {
+               seed = atol(argv[3]);
+               argc = 3;
+       }
+       if (argc == 3) {
+               nr_passes = atol(argv[2]);
+               argc = 2;
+       }
+       if (argc != 2) {
+               fprintf(stderr, "usage: %s <device> [<passes>] [<random seed>]\n",
+                       (strrchr(argv[0],',')?:argv[0]-1)+1);
+               exit(1);
+       }
+
+       fd = open(argv[1], O_RDWR);
+       if (fd < 0) {
+               perror("open");
+               exit(1);
+       }
+       
+       if (ioctl(fd, MEMGETINFO, &meminfo)) {
+               perror("MEMGETINFO");
+               close(fd);
+               exit(1);
+       }
+
+       wbuf = malloc(meminfo.erasesize * 2);
+       if (!wbuf) {
+               fprintf(stderr, "Could not allocate %d bytes for buffer\n",
+                       meminfo.erasesize * 2);
+               exit(1);
+       }
+       rbuf = wbuf + meminfo.erasesize;
+
+       if (ioctl(fd, ECCGETSTATS, &oldstats)) {
+               perror("ECCGETSTATS");
+               close(fd);
+               exit(1);
+       }
+
+       printf("ECC corrections: %d\n", oldstats.corrected);
+       printf("ECC failures   : %d\n", oldstats.failed);
+       printf("Bad blocks     : %d\n", oldstats.badblocks);
+       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;
+                       ssize_t len;
+
+                       seed = rand();
+                       srand(seed);
+
+                       if (ioctl(fd, MEMGETBADBLOCK, &ofs)) {
+                               printf("\rBad block at 0x%08x\n", (unsigned)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<meminfo.erasesize; i++)
+                               wbuf[i] = rand();
+
+                       len = pwrite(fd, wbuf, meminfo.erasesize, ofs);
+                       if (len < 0) {
+                               printf("\n");
+                               perror("write");
+                               exit(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);
+                               newstats.corrected = oldstats.corrected;
+                       }
+                       if (newstats.failed > oldstats.failed) {
+                               printf("\nECC failed at %08x\n", (unsigned) ofs);
+                               newstats.corrected = oldstats.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<meminfo.erasesize; i++) {
+                                       if (wbuf[i] != rbuf[i])
+                                               printf("Byte 0x%x is %02x should be %02x\n",
+                                                      i, rbuf[i], wbuf[i]);
+                               }
+                               exit(1);
+                       }
+               }
+               printf("\nFinished pass %d successfully\n", pass+1);
+       }
+       /* Return happy */
+       return 0;
+}