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