summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Woodhouse <dwmw2@infradead.org>2007-08-09 16:23:19 +0800
committerDavid Woodhouse <dwmw2@infradead.org>2007-08-09 16:23:19 +0800
commit2c629e07b87746d49e267db286f096541ef01d90 (patch)
tree1c16c288e563b108bc2f6145306817f7d4c142f9
parentb431ea844a1770f46eeac738df7595c549a3deac (diff)
Add nand integrity testing utility.
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
-rw-r--r--Makefile8
-rw-r--r--nandtest.c172
2 files changed, 179 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index ae45261..4f74158 100644
--- 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
index 0000000..254d41f
--- /dev/null
+++ b/nandtest.c
@@ -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;
+}