r4912 - in developers/werner: . badnand

werner at docs.openmoko.org werner at docs.openmoko.org
Thu Feb 5 05:38:43 CET 2009


Author: werner
Date: 2009-02-05 05:38:42 +0100 (Thu, 05 Feb 2009)
New Revision: 4912

Added:
   developers/werner/badnand/
   developers/werner/badnand/Makefile
   developers/werner/badnand/README
   developers/werner/badnand/badnand.c
   developers/werner/badnand/mtd-abi.h
   developers/werner/badnand/nbad.c
Log:
Somewhat crude BBT dumping tool.



Added: developers/werner/badnand/Makefile
===================================================================
--- developers/werner/badnand/Makefile	                        (rev 0)
+++ developers/werner/badnand/Makefile	2009-02-05 04:38:42 UTC (rev 4912)
@@ -0,0 +1,35 @@
+CC=arm-angstrom-linux-gnueabi-gcc
+
+CFLAGS=-Wall -Wshadow -g -O
+LDFLAGS=
+
+PREFIX=/usr
+
+NAME=badnand
+OBJS=badnand.o
+
+.PHONY:		all install uninstall clean depend spotless
+
+all:		$(NAME)
+
+$(NAME):	$(OBJS)
+
+install:	$(NAME)
+		install -D $(NAME) $(PREFIX)/bin/$(NAME)
+
+uninstall:
+		rm -f $(PREFIX)/bin/$(NAME)
+
+depend:
+		$(CPP) $(CFLAGS) -MM -MG *.c >.depend || \
+		  { rm -f .depend; exit 1; }
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
+
+clean:
+		rm -f $(OBJS) .depend
+
+spotless:	clean
+		rm -f $(NAME)

Added: developers/werner/badnand/README
===================================================================
--- developers/werner/badnand/README	                        (rev 0)
+++ developers/werner/badnand/README	2009-02-05 04:38:42 UTC (rev 4912)
@@ -0,0 +1,15 @@
+mtd-abi.h is from mtd-utils:
+
+git://git.infradead.org/mtd-utils.git
+mtd-utils/include/mtd/mtd-abi.h
+
+
+badnand shows the bad block table. Invoke with the last NAND device,
+e.g.,
+
+# badnand /dev/mtd6
+
+nbad counts the number of blocks the kernel considers as "bad" (for
+whatever reason) on an MTD device. With -v, it prints their position
+relative to the start of the partition. Note that "nbad" also
+considers the blocks occupised by the BBT as "bad".

Added: developers/werner/badnand/badnand.c
===================================================================
--- developers/werner/badnand/badnand.c	                        (rev 0)
+++ developers/werner/badnand/badnand.c	2009-02-05 04:38:42 UTC (rev 4912)
@@ -0,0 +1,130 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+#include "mtd-abi.h"
+
+
+#define	NUM_BLOCKS	2048
+
+
+/*
+ * OOB layout:
+ *
+ * Offset  Size  Description
+ *      0     1  Factory-bad marker (0xff = okay)
+ *      8     5	 BBT marker, "1tbB" and "Bbt0"
+ *     12     1	 Version
+ *     40    24  8x3 ECC bytes
+ */
+
+
+static void usage(const char *name)
+{
+	fprintf(stderr, "usage: %s last_mtd_partition\n", name);
+	exit(1);
+}
+
+
+int main(int argc, char **argv)
+{
+	const char *dev;
+	int fd;
+	uint32_t pos;
+	struct mtd_info_user meminfo;
+	struct mtd_oob_buf oob;
+	uint8_t *buf;
+	int i;
+	ssize_t got;
+	int factory = 0, worn = 0, good = 0;
+
+	if (argc != 2)
+		usage(*argv);
+	dev = argv[1];
+	fd = open(dev, O_RDONLY);
+	if (fd < 0) {
+		perror(dev);
+		exit(1);
+	}
+
+	if (ioctl(fd, MEMGETINFO, &meminfo) < 0) {
+		perror("ioctl(MEMGETINFO)");
+		exit (1);
+	}
+
+	buf = malloc(meminfo.erasesize);
+	if (!buf) {
+		perror("malloc");
+		exit(1);
+	}
+
+	pos = 0;
+	while (1) {
+		oob.start = pos;
+		oob.length = meminfo.oobsize;
+		oob.ptr = buf;
+		if (ioctl(fd, MEMREADOOB, &oob) < 0) {
+			perror("MEMREADOOB");
+			exit(1);
+		}
+		if (!memcmp(buf+8, "Bbt0", 4))
+			break;
+#if 0
+		printf("%6u:", pos >> 10);
+		for (i = 0; i != meminfo.oobsize; i++)
+			printf(" %02x", oob_buf[i]);
+		printf("\n");
+#endif
+		pos += meminfo.erasesize;
+	}
+
+	if (lseek(fd, pos, SEEK_SET) != pos) {
+		perror("lseek");
+		exit(1);
+	}
+	for (i = 0; i != meminfo.erasesize; i += meminfo.writesize) {
+		got = read(fd, buf+i, meminfo.writesize);
+		if (got < 0) {
+			perror("read");
+			exit(1);
+		}
+		if (got != meminfo.writesize) {
+			fprintf(stderr, "bad read: wanted %u got %u\n",
+			    meminfo.writesize, (unsigned) got);
+			exit(1);
+		}
+	}
+
+	for (i = 0; i != meminfo.erasesize*4 && i != NUM_BLOCKS; i++) {
+		if (!(i & 63)) {
+			if (i)
+				putchar('\n');
+			printf("%6d ", i*(meminfo.erasesize >> 10));
+		} else {
+			if (i && !(i & 15))
+				putchar(' ');
+		}
+		switch ((buf[i >> 2] >> ((i & 3) << 1)) & 3) {
+		case 0:
+			putchar('F');
+			factory++;
+			break;
+		case 3:
+			putchar('.');
+			good++;
+			break;
+		default:
+			putchar('w');
+			worn++;
+			break;
+		}
+	}
+	printf("\nFactory %d, worn %d, good %d\n", factory, worn, good);
+
+	return 0;
+}

Added: developers/werner/badnand/mtd-abi.h
===================================================================
--- developers/werner/badnand/mtd-abi.h	                        (rev 0)
+++ developers/werner/badnand/mtd-abi.h	2009-02-05 04:38:42 UTC (rev 4912)
@@ -0,0 +1,152 @@
+/*
+ * $Id: mtd-abi.h,v 1.13 2005/11/07 11:14:56 gleixner Exp $
+ *
+ * Portions of MTD ABI definition which are shared by kernel and user space
+ */
+
+#ifndef __MTD_ABI_H__
+#define __MTD_ABI_H__
+
+struct erase_info_user {
+	uint32_t start;
+	uint32_t length;
+};
+
+struct mtd_oob_buf {
+	uint32_t start;
+	uint32_t length;
+	unsigned char *ptr;
+};
+
+#define MTD_ABSENT		0
+#define MTD_RAM			1
+#define MTD_ROM			2
+#define MTD_NORFLASH		3
+#define MTD_NANDFLASH		4
+#define MTD_DATAFLASH		6
+#define MTD_UBIVOLUME		7
+
+#define MTD_WRITEABLE		0x400	/* Device is writeable */
+#define MTD_BIT_WRITEABLE	0x800	/* Single bits can be flipped */
+#define MTD_NO_ERASE		0x1000	/* No erase necessary */
+#define MTD_STUPID_LOCK		0x2000	/* Always locked after reset */
+
+// Some common devices / combinations of capabilities
+#define MTD_CAP_ROM		0
+#define MTD_CAP_RAM		(MTD_WRITEABLE | MTD_BIT_WRITEABLE | MTD_NO_ERASE)
+#define MTD_CAP_NORFLASH	(MTD_WRITEABLE | MTD_BIT_WRITEABLE)
+#define MTD_CAP_NANDFLASH	(MTD_WRITEABLE)
+
+/* ECC byte placement */
+#define MTD_NANDECC_OFF		0	// Switch off ECC (Not recommended)
+#define MTD_NANDECC_PLACE	1	// Use the given placement in the structure (YAFFS1 legacy mode)
+#define MTD_NANDECC_AUTOPLACE	2	// Use the default placement scheme
+#define MTD_NANDECC_PLACEONLY	3	// Use the given placement in the structure (Do not store ecc result on read)
+#define MTD_NANDECC_AUTOPL_USR 	4	// Use the given autoplacement scheme rather than using the default
+
+/* OTP mode selection */
+#define MTD_OTP_OFF		0
+#define MTD_OTP_FACTORY		1
+#define MTD_OTP_USER		2
+
+struct mtd_info_user {
+	uint8_t type;
+	uint32_t flags;
+	uint32_t size;	 // Total size of the MTD
+	uint32_t erasesize;
+	uint32_t writesize;
+	uint32_t oobsize;   // Amount of OOB data per block (e.g. 16)
+	/* The below two fields are obsolete and broken, do not use them
+	 * (TODO: remove at some point) */
+	uint32_t ecctype;
+	uint32_t eccsize;
+};
+
+struct region_info_user {
+	uint32_t offset;		/* At which this region starts,
+					 * from the beginning of the MTD */
+	uint32_t erasesize;		/* For this region */
+	uint32_t numblocks;		/* Number of blocks in this region */
+	uint32_t regionindex;
+};
+
+struct otp_info {
+	uint32_t start;
+	uint32_t length;
+	uint32_t locked;
+};
+
+#define MEMGETINFO		_IOR('M', 1, struct mtd_info_user)
+#define MEMERASE		_IOW('M', 2, struct erase_info_user)
+#define MEMWRITEOOB		_IOWR('M', 3, struct mtd_oob_buf)
+#define MEMREADOOB		_IOWR('M', 4, struct mtd_oob_buf)
+#define MEMLOCK			_IOW('M', 5, struct erase_info_user)
+#define MEMUNLOCK		_IOW('M', 6, struct erase_info_user)
+#define MEMGETREGIONCOUNT	_IOR('M', 7, int)
+#define MEMGETREGIONINFO	_IOWR('M', 8, struct region_info_user)
+#define MEMSETOOBSEL		_IOW('M', 9, struct nand_oobinfo)
+#define MEMGETOOBSEL		_IOR('M', 10, struct nand_oobinfo)
+#define MEMGETBADBLOCK		_IOW('M', 11, loff_t)
+#define MEMSETBADBLOCK		_IOW('M', 12, loff_t)
+#define OTPSELECT		_IOR('M', 13, int)
+#define OTPGETREGIONCOUNT	_IOW('M', 14, int)
+#define OTPGETREGIONINFO	_IOW('M', 15, struct otp_info)
+#define OTPLOCK			_IOR('M', 16, struct otp_info)
+#define ECCGETLAYOUT		_IOR('M', 17, struct nand_ecclayout)
+#define ECCGETSTATS		_IOR('M', 18, struct mtd_ecc_stats)
+#define MTDFILEMODE		_IO('M', 19)
+
+/*
+ * Obsolete legacy interface. Keep it in order not to break userspace
+ * interfaces
+ */
+struct nand_oobinfo {
+	uint32_t useecc;
+	uint32_t eccbytes;
+	uint32_t oobfree[8][2];
+	uint32_t eccpos[32];
+};
+
+struct nand_oobfree {
+	uint32_t offset;
+	uint32_t length;
+};
+
+#define MTD_MAX_OOBFREE_ENTRIES	8
+/*
+ * ECC layout control structure. Exported to userspace for
+ * diagnosis and to allow creation of raw images
+ */
+struct nand_ecclayout {
+	uint32_t eccbytes;
+	uint32_t eccpos[64];
+	uint32_t oobavail;
+	struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES];
+};
+
+/**
+ * struct mtd_ecc_stats - error correction stats
+ *
+ * @corrected:	number of corrected bits
+ * @failed:	number of uncorrectable errors
+ * @badblocks:	number of bad blocks in this partition
+ * @bbtblocks:	number of blocks reserved for bad block tables
+ */
+struct mtd_ecc_stats {
+	uint32_t corrected;
+	uint32_t failed;
+	uint32_t badblocks;
+	uint32_t bbtblocks;
+};
+
+/*
+ * Read/write file modes for access to MTD
+ */
+enum mtd_file_modes {
+	MTD_MODE_NORMAL = MTD_OTP_OFF,
+	MTD_MODE_OTP_FACTORY = MTD_OTP_FACTORY,
+	MTD_MODE_OTP_USER = MTD_OTP_USER,
+	MTD_MODE_RAW,
+};
+
+#endif /* __MTD_ABI_H__ */

Added: developers/werner/badnand/nbad.c
===================================================================
--- developers/werner/badnand/nbad.c	                        (rev 0)
+++ developers/werner/badnand/nbad.c	2009-02-05 04:38:42 UTC (rev 4912)
@@ -0,0 +1,78 @@
+/*
+ *  nbad.c
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#include <stdint.h>
+#include "mtd-abi.h"
+
+
+static int verbose = 0;
+
+
+static void check_device(const char *file)
+{
+    int n_bad = 0;
+    int fd;
+    struct mtd_info_user meminfo;
+    loff_t pos;
+    int n = 0, is_bad;
+
+    fd = open(file, O_RDONLY);
+    if (fd < 0) {
+	perror(file);
+	exit(1);
+    }
+    if (ioctl(fd, MEMGETINFO, &meminfo) < 0) {
+	perror("ioctl(MEMGETINFO)");
+	exit (1);
+    }
+    for (pos = 0; pos < meminfo.size; pos += meminfo.erasesize) {
+	is_bad = ioctl(fd, MEMGETBADBLOCK, &pos);
+	if (is_bad < 0) {
+	    perror("ioctl(MEMGETBADBLOCK)");
+	    exit(1);
+	}
+	if (is_bad) {
+	    if (verbose)
+		printf("%d %ld\n", n, (long) pos);
+	    n_bad++;
+	}
+	n++;
+    }
+    printf("%s %d\n", file, n_bad);
+    if (close(fd) < 0) {
+	perror("close");
+	exit(1);
+    }
+}
+
+
+static void usage(const char *name)
+{
+    fprintf(stderr, "usage; %s [-v] mtd_device ...\n", name);
+    exit(1);
+}
+
+
+int main(int argc, char *const *argv)
+{
+    int c;
+
+    while ((c = getopt(argc, argv, "v")) != EOF)
+	switch (c) {
+	    case 'v':
+		verbose++;
+		break;
+	    default:
+		usage(*argv);
+	}
+    while (optind != argc)
+	check_device(argv[optind++]);
+    return 0;
+}




More information about the commitlog mailing list