From e413d17f8bd6c680a4f792006932a070ce504120 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 9 Sep 2011 10:11:49 -0700 Subject: mtd-utils: update mtd-abi.h Kernel ABI header added a new ioctl, killed an old one, and exposed OOB modes to user-space. Plus, it added a lot of documentation. We have some trivial name changes for some MTD mode constants as well. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- include/mtd/mtd-abi.h | 122 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 105 insertions(+), 17 deletions(-) (limited to 'include') diff --git a/include/mtd/mtd-abi.h b/include/mtd/mtd-abi.h index a86364a..4de167b 100644 --- a/include/mtd/mtd-abi.h +++ b/include/mtd/mtd-abi.h @@ -45,6 +45,51 @@ struct mtd_oob_buf64 { __u64 usr_ptr; }; +/** + * MTD operation modes + * + * @MTD_OPS_PLACE_OOB: OOB data are placed at the given offset (default) + * @MTD_OPS_AUTO_OOB: OOB data are automatically placed at the free areas + * which are defined by the internal ecclayout + * @MTD_OPS_RAW: data are transferred as-is, with no error correction; + * this mode implies %MTD_OPS_PLACE_OOB + * + * These modes can be passed to ioctl(MEMWRITE) and are also used internally. + * See notes on "MTD file modes" for discussion on %MTD_OPS_RAW vs. + * %MTD_FILE_MODE_RAW. + */ +enum { + MTD_OPS_PLACE_OOB = 0, + MTD_OPS_AUTO_OOB = 1, + MTD_OPS_RAW = 2, +}; + +/** + * struct mtd_write_req - data structure for requesting a write operation + * + * @start: start address + * @len: length of data buffer + * @ooblen: length of OOB buffer + * @usr_data: user-provided data buffer + * @usr_oob: user-provided OOB buffer + * @mode: MTD mode (see "MTD operation modes") + * @padding: reserved, must be set to 0 + * + * This structure supports ioctl(MEMWRITE) operations, allowing data and/or OOB + * writes in various modes. To write to OOB-only, set @usr_data == NULL, and to + * write data-only, set @usr_oob == NULL. However, setting both @usr_data and + * @usr_oob to NULL is not allowed. + */ +struct mtd_write_req { + __u64 start; + __u64 len; + __u64 ooblen; + __u64 usr_data; + __u64 usr_oob; + __u8 mode; + __u8 padding[7]; +}; + #define MTD_ABSENT 0 #define MTD_RAM 1 #define MTD_ROM 2 @@ -59,13 +104,13 @@ struct mtd_oob_buf64 { #define MTD_NO_ERASE 0x1000 /* No erase necessary */ #define MTD_POWERUP_LOCK 0x2000 /* Always locked after reset */ -// Some common devices / combinations of capabilities +/* 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 */ +/* Obsolete ECC byte placement modes (used with obsolete MEMGETOOBSEL) */ #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 @@ -80,21 +125,18 @@ struct mtd_oob_buf64 { struct mtd_info_user { __u8 type; __u32 flags; - __u32 size; // Total size of the MTD + __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) */ - __u32 ecctype; - __u32 eccsize; + __u32 oobsize; /* Amount of OOB data per block (e.g. 16) */ + __u64 padding; /* Old obsolete field; do not use */ }; struct region_info_user { __u32 offset; /* At which this region starts, - * from the beginning of the MTD */ - __u32 erasesize; /* For this region */ - __u32 numblocks; /* Number of blocks in this region */ + * from the beginning of the MTD */ + __u32 erasesize; /* For this region */ + __u32 numblocks; /* Number of blocks in this region */ __u32 regionindex; }; @@ -104,29 +146,61 @@ struct otp_info { __u32 locked; }; +/* + * Note, the following ioctl existed in the past and was removed: + * #define MEMSETOOBSEL _IOW('M', 9, struct nand_oobinfo) + * Try to avoid adding a new ioctl with the same ioctl number. + */ + +/* Get basic MTD characteristics info (better to use sysfs) */ #define MEMGETINFO _IOR('M', 1, struct mtd_info_user) +/* Erase segment of MTD */ #define MEMERASE _IOW('M', 2, struct erase_info_user) +/* Write out-of-band data from MTD */ #define MEMWRITEOOB _IOWR('M', 3, struct mtd_oob_buf) +/* Read out-of-band data from MTD */ #define MEMREADOOB _IOWR('M', 4, struct mtd_oob_buf) +/* Lock a chip (for MTD that supports it) */ #define MEMLOCK _IOW('M', 5, struct erase_info_user) +/* Unlock a chip (for MTD that supports it) */ #define MEMUNLOCK _IOW('M', 6, struct erase_info_user) +/* Get the number of different erase regions */ #define MEMGETREGIONCOUNT _IOR('M', 7, int) +/* Get information about the erase region for a specific index */ #define MEMGETREGIONINFO _IOWR('M', 8, struct region_info_user) -#define MEMSETOOBSEL _IOW('M', 9, struct nand_oobinfo) +/* Get info about OOB modes (e.g., RAW, PLACE, AUTO) - legacy interface */ #define MEMGETOOBSEL _IOR('M', 10, struct nand_oobinfo) +/* Check if an eraseblock is bad */ #define MEMGETBADBLOCK _IOW('M', 11, __kernel_loff_t) +/* Mark an eraseblock as bad */ #define MEMSETBADBLOCK _IOW('M', 12, __kernel_loff_t) +/* Set OTP (One-Time Programmable) mode (factory vs. user) */ #define OTPSELECT _IOR('M', 13, int) +/* Get number of OTP (One-Time Programmable) regions */ #define OTPGETREGIONCOUNT _IOW('M', 14, int) +/* Get all OTP (One-Time Programmable) info about MTD */ #define OTPGETREGIONINFO _IOW('M', 15, struct otp_info) +/* Lock a given range of user data (must be in mode %MTD_FILE_MODE_OTP_USER) */ #define OTPLOCK _IOR('M', 16, struct otp_info) +/* Get ECC layout (deprecated) */ #define ECCGETLAYOUT _IOR('M', 17, struct nand_ecclayout_user) +/* Get statistics about corrected/uncorrected errors */ #define ECCGETSTATS _IOR('M', 18, struct mtd_ecc_stats) +/* Set MTD mode on a per-file-descriptor basis (see "MTD file modes") */ #define MTDFILEMODE _IO('M', 19) +/* Erase segment of MTD (supports 64-bit address) */ #define MEMERASE64 _IOW('M', 20, struct erase_info_user64) +/* Write data to OOB (64-bit version) */ #define MEMWRITEOOB64 _IOWR('M', 21, struct mtd_oob_buf64) +/* Read data from OOB (64-bit version) */ #define MEMREADOOB64 _IOWR('M', 22, struct mtd_oob_buf64) +/* Check if chip is locked (for MTD that supports it) */ #define MEMISLOCKED _IOR('M', 23, struct erase_info_user) +/* + * Most generic write interface; can write in-band and/or out-of-band in various + * modes (see "struct mtd_write_req") + */ +#define MEMWRITE _IOWR('M', 24, struct mtd_write_req) /* * Obsolete legacy interface. Keep it in order not to break userspace @@ -177,13 +251,27 @@ struct mtd_ecc_stats { }; /* - * Read/write file modes for access to MTD + * MTD file modes - for read/write access to MTD + * + * @MTD_FILE_MODE_NORMAL: OTP disabled, ECC enabled + * @MTD_FILE_MODE_OTP_FACTORY: OTP enabled in factory mode + * @MTD_FILE_MODE_OTP_USER: OTP enabled in user mode + * @MTD_FILE_MODE_RAW: OTP disabled, ECC disabled + * + * These modes can be set via ioctl(MTDFILEMODE). The mode mode will be retained + * separately for each open file descriptor. + * + * Note: %MTD_FILE_MODE_RAW provides the same functionality as %MTD_OPS_RAW - + * raw access to the flash, without error correction or autoplacement schemes. + * Wherever possible, the MTD_OPS_* mode will override the MTD_FILE_MODE_* mode + * (e.g., when using ioctl(MEMWRITE)), but in some cases, the MTD_FILE_MODE is + * used out of necessity (e.g., `write()', ioctl(MEMWRITEOOB64)). */ 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, + MTD_FILE_MODE_NORMAL = MTD_OTP_OFF, + MTD_FILE_MODE_OTP_FACTORY = MTD_OTP_FACTORY, + MTD_FILE_MODE_OTP_USER = MTD_OTP_USER, + MTD_FILE_MODE_RAW, }; #endif /* __MTD_ABI_H__ */ -- cgit v1.2.3 From cd42aea270e84884e6bbac845414568f0febbedf Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 31 Aug 2011 13:00:33 -0700 Subject: libmtd: modify `mtd_write' to cover OOB writes To support the MEMWRITE ioctl, we will need a different sort of libmtd interface for writing to flash. We will expand mtd_write to include more functionality; for now, we just change the function definition and description as we begin to add the actual functionality. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- include/libmtd.h | 15 +++++++++++---- lib/libmtd.c | 10 ++++++---- nandwrite.c | 4 ++-- ubi-utils/ubiformat.c | 6 ++++-- 4 files changed, 23 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/include/libmtd.h b/include/libmtd.h index 9efccbc..07c304a 100644 --- a/include/libmtd.h +++ b/include/libmtd.h @@ -255,19 +255,26 @@ int mtd_read(const struct mtd_dev_info *mtd, int fd, int eb, int offs, /** * mtd_write - write data to an MTD device. + * @desc: MTD library descriptor * @mtd: MTD device description object * @fd: MTD device node file descriptor * @eb: eraseblock to write to * @offs: offset withing the eraseblock to write to - * @buf: buffer to write - * @len: how many bytes to write + * @data: data buffer to write + * @len: how many data bytes to write + * @oob: OOB buffer to write + * @ooblen: how many OOB bytes to write + * @mode: write mode (e.g., %MTD_OOB_PLACE, %MTD_OOB_RAW) * * This function writes @len bytes of data to eraseblock @eb and offset @offs * of the MTD device defined by @mtd. Returns %0 in case of success and %-1 in * case of failure. + * + * Can only write to a single page at a time if writing to OOB. */ -int mtd_write(const struct mtd_dev_info *mtd, int fd, int eb, int offs, - void *buf, int len); +int mtd_write(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb, + int offs, void *data, int len, void *oob, int ooblen, + uint8_t mode); /** * mtd_read_oob - read out-of-band area. diff --git a/lib/libmtd.c b/lib/libmtd.c index c34874e..746ea69 100644 --- a/lib/libmtd.c +++ b/lib/libmtd.c @@ -970,7 +970,8 @@ int mtd_torture(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb) /* Write a pattern and check it */ memset(buf, patterns[i], mtd->eb_size); - err = mtd_write(mtd, fd, eb, 0, buf, mtd->eb_size); + err = mtd_write(desc, mtd, fd, eb, 0, buf, mtd->eb_size, NULL, + 0, 0); if (err) goto out; @@ -1070,8 +1071,9 @@ int mtd_read(const struct mtd_dev_info *mtd, int fd, int eb, int offs, return 0; } -int mtd_write(const struct mtd_dev_info *mtd, int fd, int eb, int offs, - void *buf, int len) +int mtd_write(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb, + int offs, void *data, int len, void *oob, int ooblen, + uint8_t mode) { int ret; off_t seek; @@ -1105,7 +1107,7 @@ int mtd_write(const struct mtd_dev_info *mtd, int fd, int eb, int offs, return sys_errmsg("cannot seek mtd%d to offset %llu", mtd->mtd_num, (unsigned long long)seek); - ret = write(fd, buf, len); + ret = write(fd, data, len); if (ret != len) return sys_errmsg("cannot write %d bytes to mtd%d (eraseblock %d, offset %d)", len, mtd->mtd_num, eb, offs); diff --git a/nandwrite.c b/nandwrite.c index 3eea6e2..33a3b8f 100644 --- a/nandwrite.c +++ b/nandwrite.c @@ -543,8 +543,8 @@ int main(int argc, char * const argv[]) } /* Write out the Page data */ - if (!onlyoob && mtd_write(&mtd, fd, mtdoffset / mtd.eb_size, mtdoffset % mtd.eb_size, - writebuf, mtd.min_io_size)) { + if (!onlyoob && mtd_write(mtd_desc, &mtd, fd, mtdoffset / mtd.eb_size, mtdoffset % mtd.eb_size, + writebuf, mtd.min_io_size, NULL, 0, 0)) { int i; if (errno != EIO) { sys_errmsg("%s: MTD write failure", mtd_device); diff --git a/ubi-utils/ubiformat.c b/ubi-utils/ubiformat.c index bfa1730..ed2b8d0 100644 --- a/ubi-utils/ubiformat.c +++ b/ubi-utils/ubiformat.c @@ -534,7 +534,8 @@ static int flash_image(libmtd_t libmtd, const struct mtd_dev_info *mtd, new_len = drop_ffs(mtd, buf, mtd->eb_size); - err = mtd_write(mtd, args.node_fd, eb, 0, buf, new_len); + err = mtd_write(libmtd, mtd, args.node_fd, eb, 0, buf, new_len, + NULL, 0, 0); if (err) { sys_errmsg("cannot write eraseblock %d", eb); @@ -637,7 +638,8 @@ static int format(libmtd_t libmtd, const struct mtd_dev_info *mtd, fflush(stdout); } - err = mtd_write(mtd, args.node_fd, eb, 0, hdr, write_size); + err = mtd_write(libmtd, mtd, args.node_fd, eb, 0, hdr, + write_size, NULL, 0, 0); if (err) { if (!args.quiet && !args.verbose) printf("\n"); -- cgit v1.2.3