[Patch] Support large devices for flash_eraseaal

Jörn Engel
2009-07-07T16:22:50Z

The mtd-abi.h bits may be wrong, not sure. Otherwise it allows me to
erase a large device. No guarantees beyond that.

Signed-off-by: Joern Engel <joern@logfs.org>

Jörn

--
Happiness isn't having what you want, it's wanting what you have.
-- unknown

flash_eraseall.c | 88 +++++++++++++++++++++++++++++++++++++++++--------
include/mtd/mtd-abi.h | 89 +++++++++++++++++++++++++++++---------------------
2 files changed, 126 insertions(+), 51 deletions(-)

diff --git a/flash_eraseall.c b/flash_eraseall.c
index a22fc49..d865cbc 100644
--- a/flash_eraseall.c
+++ b/flash_eraseall.c
@@ -48,33 +48,93 @@ static const char *mtd_device;
static int quiet; /* true -- don't output progress */
static int jffs2; // format for jffs2 usage

+struct mtd_info_user64 {
+ uint8_t type;
+ uint32_t flags;
+ uint64_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;
+};
+
static void process_options (int argc, char *argv[]);
-void show_progress (mtd_info_t *meminfo, erase_info_t *erase);
+void show_progress(struct mtd_info_user64 *meminfo, struct erase_info_user64 *erase);
static void display_help (void);
static void display_version (void);
static struct jffs2_unknown_node cleanmarker;
int target_endian = __BYTE_ORDER;

+static int get_info(const char *devname, struct mtd_info_user64 *mtd64)
+{
+ struct mtd_info_user mtd;
+ char buf[256];
+ int fd;
+
+ if ((fd = open(devname, O_RDWR)) < 0) {
+ fprintf(stderr, "%s: %s: %s\n", exe_name, devname, strerror(errno));
+ return 1;
+ }
+
+
+ if (ioctl(fd, MEMGETINFO, &mtd) != 0) {
+ fprintf(stderr, "%s: %s: unable to get MTD device info\n", exe_name, devname);
+ return 1;
+ }
+ close(fd);
+
+ mtd64->type = mtd.type;
+ mtd64->flags = mtd.flags;
+ mtd64->size = mtd.size;
+ mtd64->erasesize = mtd.erasesize;
+ mtd64->writesize = mtd.writesize;
+ mtd64->oobsize = mtd.oobsize;
+ mtd64->ecctype = mtd.ecctype;
+ mtd64->eccsize = mtd.eccsize;
+
+ /* I'm glad I only have to do this for one parameter. */
+ sprintf(buf, "/sys/class/mtd/%s/size", basename((char *)devname));
+ fd = open(buf, O_RDONLY);
+ if (fd < 0)
+ return 0;
+ read(fd, buf, 256);
+ mtd64->size = strtoull(buf, NULL, 0);
+ close(fd);
+ return 0;
+}
+
+static int do_erase(int fd, struct erase_info_user64 *ei64, struct mtd_info_user64 *mtd64)
+{
+ struct erase_info_user ei;
+
+ if (mtd64->size >= 0x100000000ull)
+ return ioctl(fd, MEMERASE64, ei64);
+ else {
+ ei.start = ei64->start;
+ ei.length = ei64->length;
+ return ioctl(fd, MEMERASE, &ei);
+ }
+}
+
int main (int argc, char *argv[])
{
- mtd_info_t meminfo;
+ struct mtd_info_user64 meminfo;
int fd, clmpos = 0, clmlen = 8;
- erase_info_t erase;
+ struct erase_info_user64 erase;
int isNAND, bbtest = 1;

process_options(argc, argv);

+ if (get_info(mtd_device, &meminfo))
+ return 1;
if ((fd = open(mtd_device, O_RDWR)) < 0) {
fprintf(stderr, "%s: %s: %s\n", exe_name, mtd_device, strerror(errno));
return 1;
}

-
- if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
- fprintf(stderr, "%s: %s: unable to get MTD device info\n", exe_name, mtd_device);
- return 1;
- }
-
erase.length = meminfo.erasesize;
isNAND = meminfo.type == MTD_NANDFLASH ? 1 : 0;

@@ -130,7 +190,7 @@ int main (int argc, char *argv[])
int ret = ioctl(fd, MEMGETBADBLOCK, &offset);
if (ret > 0) {
if (!quiet)
- printf ("\nSkipping bad block at 0x%08x\n", erase.start);
+ printf ("\nSkipping bad block at 0x%08llx\n", erase.start);
continue;
} else if (ret < 0) {
if (errno == EOPNOTSUPP) {
@@ -149,7 +209,7 @@ int main (int argc, char *argv[])
if (!quiet)
show_progress(&meminfo, &erase);

- if (ioctl(fd, MEMERASE, &erase) != 0) {
+ if (do_erase(fd, &erase, &meminfo) != 0) {
fprintf(stderr, "\n%s: %s: MTD Erase failure: %s\n", exe_name, mtd_device, strerror(errno));
continue;
}
@@ -179,7 +239,7 @@ int main (int argc, char *argv[])
}
}
if (!quiet)
- printf (" Cleanmarker written at %x.", erase.start);
+ printf (" Cleanmarker written at %llx.", erase.start);
}
if (!quiet) {
show_progress(&meminfo, &erase);
@@ -250,9 +310,9 @@ void process_options (int argc, char *argv[])
mtd_device = argv[optind];
}

-void show_progress (mtd_info_t *meminfo, erase_info_t *erase)
+void show_progress(struct mtd_info_user64 *meminfo, struct erase_info_user64 *erase)
{
- printf("\rErasing %d Kibyte @ %x -- %2llu %% complete.",
+ printf("\rErasing %d Kibyte @ %llx -- %2llu %% complete.",
meminfo->erasesize / 1024, erase->start,
(unsigned long long) erase->start * 100 / meminfo->size);
fflush(stdout);
diff --git a/include/mtd/mtd-abi.h b/include/mtd/mtd-abi.h
index 86defe1..c6954ed 100644
--- a/include/mtd/mtd-abi.h
+++ b/include/mtd/mtd-abi.h
@@ -1,23 +1,35 @@
/*
- * $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__

+#include <linux/types.h>
+
struct erase_info_user {
- uint32_t start;
- uint32_t length;
+ __u32 start;
+ __u32 length;
+};
+
+struct erase_info_user64 {
+ __u64 start;
+ __u64 length;
};

struct mtd_oob_buf {
- uint32_t start;
- uint32_t length;
+ __u32 start;
+ __u32 length;
unsigned char *ptr;
};

+struct mtd_oob_buf64 {
+ __u64 start;
+ __u32 pad;
+ __u32 length;
+ __u64 usr_ptr;
+};
+
#define MTD_ABSENT 0
#define MTD_RAM 1
#define MTD_ROM 2
@@ -29,7 +41,7 @@ struct mtd_oob_buf {
#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 */
+#define MTD_POWERUP_LOCK 0x2000 /* Always locked after reset */

// Some common devices / combinations of capabilities
#define MTD_CAP_ROM 0
@@ -50,30 +62,30 @@ struct mtd_oob_buf {
#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)
+ __u8 type;
+ __u32 flags;
+ __u32 size; // Total size of the MTD
+ __u32 erasesize;
+ __u32 writesize;
+ __u32 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;
+ __u32 ecctype;
+ __u32 eccsize;
};

struct region_info_user {
- uint32_t offset; /* At which this region starts,
+ __u32 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;
+ __u32 erasesize; /* For this region */
+ __u32 numblocks; /* Number of blocks in this region */
+ __u32 regionindex;
};

struct otp_info {
- uint32_t start;
- uint32_t length;
- uint32_t locked;
+ __u32 start;
+ __u32 length;
+ __u32 locked;
};

#define MEMGETINFO _IOR('M', 1, struct mtd_info_user)
@@ -86,8 +98,8 @@ struct otp_info {
#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 MEMGETBADBLOCK _IOW('M', 11, __kernel_loff_t)
+#define MEMSETBADBLOCK _IOW('M', 12, __kernel_loff_t)
#define OTPSELECT _IOR('M', 13, int)
#define OTPGETREGIONCOUNT _IOW('M', 14, int)
#define OTPGETREGIONINFO _IOW('M', 15, struct otp_info)
@@ -95,21 +107,24 @@ 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)
+#define MEMERASE64 _IOW('M', 20, struct erase_info_user64)
+#define MEMWRITEOOB64 _IOWR('M', 21, struct mtd_oob_buf64)
+#define MEMREADOOB64 _IOWR('M', 22, struct mtd_oob_buf64)

/*
* 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];
+ __u32 useecc;
+ __u32 eccbytes;
+ __u32 oobfree[8][2];
+ __u32 eccpos[32];
};

struct nand_oobfree {
- uint32_t offset;
- uint32_t length;
+ __u32 offset;
+ __u32 length;
};

#define MTD_MAX_OOBFREE_ENTRIES 8
@@ -118,9 +133,9 @@ struct nand_oobfree {
* diagnosis and to allow creation of raw images
*/
struct nand_ecclayout {
- uint32_t eccbytes;
- uint32_t eccpos[64];
- uint32_t oobavail;
+ __u32 eccbytes;
+ __u32 eccpos[64];
+ __u32 oobavail;
struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES];
};

@@ -133,10 +148,10 @@ struct nand_ecclayout {
* @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;
+ __u32 corrected;
+ __u32 failed;
+ __u32 badblocks;
+ __u32 bbtblocks;
};

/*