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 --- lib/libmtd.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'lib/libmtd.c') 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); -- cgit v1.2.3 From 6a8889fbc0ea7a198628c9e3901fd88038e12d09 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 31 Aug 2011 13:00:34 -0700 Subject: libmtd: support MEMWRITE ioctl `mtd_write()' now will first attempt to use MEMWRITE. Then, if that doesn't exist, it will attempt to fall back to old methods for writing OOB and/or page data. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- lib/libmtd.c | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) (limited to 'lib/libmtd.c') diff --git a/lib/libmtd.c b/lib/libmtd.c index 746ea69..d47b307 100644 --- a/lib/libmtd.c +++ b/lib/libmtd.c @@ -1077,6 +1077,7 @@ int mtd_write(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb, { int ret; off_t seek; + struct mtd_write_req ops; ret = mtd_valid_erase_block(mtd, eb); if (ret) @@ -1101,16 +1102,38 @@ int mtd_write(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb, return -1; } - /* Seek to the beginning of the eraseblock */ + /* Calculate seek address */ seek = (off_t)eb * mtd->eb_size + offs; - if (lseek(fd, seek, SEEK_SET) != seek) - return sys_errmsg("cannot seek mtd%d to offset %llu", - mtd->mtd_num, (unsigned long long)seek); - 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); + ops.start = seek; + ops.len = len; + ops.ooblen = ooblen; + ops.usr_data = (uint64_t)(unsigned long)data; + ops.usr_oob = (uint64_t)(unsigned long)oob; + ops.mode = mode; + + ret = ioctl(fd, MEMWRITE, &ops); + if (ret == 0) + return 0; + else if (errno != ENOTTY) + return mtd_ioctl_error(mtd, eb, "MEMWRITE"); + + /* Fall back to old methods if necessary */ + if (oob) { + if (mtd_write_oob(desc, mtd, fd, seek, ooblen, oob) < 0) + return sys_errmsg("cannot write to OOB"); + } + if (data) { + /* Seek to the beginning of the eraseblock */ + if (lseek(fd, seek, SEEK_SET) != seek) + return sys_errmsg("cannot seek mtd%d to offset %llu", + mtd->mtd_num, (unsigned long long)seek); + 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); + } return 0; } -- cgit v1.2.3 From c4c8cdf621a5d1ea4f0f01ff004c6f1c33be9daa Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 31 Aug 2011 13:00:36 -0700 Subject: mtdutils: move OOB auto-layout into libmtd's mtd_write With the addition of the the new ioctl(MEMWRITE), we can use the kernel's internal OOB autoplacement option. It's a cleaner interface and avoids too much duplication of coding effort. This patch moves any legacy code (using MEMGETOOBSEL) into a legacy function in libmtd.c. It's not exactly a "pre-2.6.30" feature, so I'm not moving it to libmtd_legacy.c. Now, autoplacement features are only activated if we call mtd_write with mode == MTD_OPS_AUTO_OOB. This should fix some discrepancies for nandwrite, where we weren't handling OOB consistently (i.e., we had different functionality when the kernel did/didn't support MEMWRITE). But that also means that we now default to using MTD_OPS_PLACE_OOB instead of AUTO layout. To re-enable autoplacement, we can re-implement the `--autoplace' option that had previously rotted. This patch also cleans up a need for an extra OOB buffer in nandwrite. This has been tested a little in nandsim as well as on SLC NAND flash. Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy --- lib/libmtd.c | 39 +++++++++++++++++++++++++++++++++++++++ nandwrite.c | 53 ++++------------------------------------------------- 2 files changed, 43 insertions(+), 49 deletions(-) (limited to 'lib/libmtd.c') diff --git a/lib/libmtd.c b/lib/libmtd.c index d47b307..1b16de5 100644 --- a/lib/libmtd.c +++ b/lib/libmtd.c @@ -1071,6 +1071,42 @@ int mtd_read(const struct mtd_dev_info *mtd, int fd, int eb, int offs, return 0; } +static int legacy_auto_oob_layout(const struct mtd_dev_info *mtd, int fd, + int ooblen, void *oob) { + struct nand_oobinfo old_oobinfo; + int start, len; + uint8_t *tmp_buf; + + /* Read the current oob info */ + if (ioctl(fd, MEMGETOOBSEL, &old_oobinfo)) + return sys_errmsg("MEMGETOOBSEL failed"); + + tmp_buf = malloc(ooblen); + memcpy(tmp_buf, oob, ooblen); + + /* + * We use autoplacement and have the oobinfo with the autoplacement + * information from the kernel available + */ + if (old_oobinfo.useecc == MTD_NANDECC_AUTOPLACE) { + int i, tags_pos = 0; + for (i = 0; old_oobinfo.oobfree[i][1]; i++) { + /* Set the reserved bytes to 0xff */ + start = old_oobinfo.oobfree[i][0]; + len = old_oobinfo.oobfree[i][1]; + memcpy(oob + start, tmp_buf + tags_pos, len); + tags_pos += len; + } + } else { + /* Set at least the ecc byte positions to 0xff */ + start = old_oobinfo.eccbytes; + len = mtd->oob_size - start; + memcpy(oob + start, tmp_buf + start, len); + } + + return 0; +} + 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) @@ -1120,6 +1156,9 @@ int mtd_write(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb, /* Fall back to old methods if necessary */ if (oob) { + if (mode == MTD_OPS_AUTO_OOB) + if (legacy_auto_oob_layout(mtd, fd, ooblen, oob)) + return -1; if (mtd_write_oob(desc, mtd, fd, seek, ooblen, oob) < 0) return sys_errmsg("cannot write to OOB"); } diff --git a/nandwrite.c b/nandwrite.c index a78b0b6..920863f 100644 --- a/nandwrite.c +++ b/nandwrite.c @@ -233,7 +233,6 @@ int main(int argc, char * const argv[]) /* points to the current page inside filebuf */ unsigned char *writebuf = NULL; /* points to the OOB for the current page in filebuf */ - unsigned char *oobreadbuf = NULL; unsigned char *oobbuf = NULL; libmtd_t mtd_desc; int ebsize_aligned; @@ -345,9 +344,6 @@ int main(int argc, char * const argv[]) filebuf = xmalloc(filebuf_max); erase_buffer(filebuf, filebuf_max); - oobbuf = xmalloc(mtd.oob_size); - erase_buffer(oobbuf, mtd.oob_size); - /* * Get data from input and write to the device while there is * still input to read and we are still within the device @@ -460,16 +456,16 @@ int main(int argc, char * const argv[]) } if (writeoob) { - oobreadbuf = writebuf + mtd.min_io_size; + oobbuf = writebuf + mtd.min_io_size; /* Read more data for the OOB from the input if there isn't enough in the buffer */ - if ((oobreadbuf + mtd.oob_size) > (filebuf + filebuf_len)) { + if ((oobbuf + mtd.oob_size) > (filebuf + filebuf_len)) { int readlen = mtd.oob_size; - int alreadyread = (filebuf + filebuf_len) - oobreadbuf; + int alreadyread = (filebuf + filebuf_len) - oobbuf; int tinycnt = alreadyread; while (tinycnt < readlen) { - cnt = read(ifd, oobreadbuf + tinycnt, readlen - tinycnt); + cnt = read(ifd, oobbuf + tinycnt, readlen - tinycnt); if (cnt == 0) { /* EOF */ break; } else if (cnt < 0) { @@ -494,46 +490,6 @@ int main(int argc, char * const argv[]) imglen = 0; } } - - if (!noecc) { - int start, len; - struct nand_oobinfo old_oobinfo; - - /* Read the current oob info */ - if (ioctl(fd, MEMGETOOBSEL, &old_oobinfo) != 0) { - perror("MEMGETOOBSEL"); - close(fd); - exit(EXIT_FAILURE); - } - - /* - * We use autoplacement and have the oobinfo with the autoplacement - * information from the kernel available - * - * Modified to support out of order oobfree segments, - * such as the layout used by diskonchip.c - */ - if (old_oobinfo.useecc == MTD_NANDECC_AUTOPLACE) { - int i, tags_pos = 0, tmp_ofs; - for (i = 0; old_oobinfo.oobfree[i][1]; i++) { - /* Set the reserved bytes to 0xff */ - start = old_oobinfo.oobfree[i][0]; - len = old_oobinfo.oobfree[i][1]; - tmp_ofs = rawoob ? start : tags_pos; - memcpy(oobbuf + start, oobreadbuf + tmp_ofs, len); - tags_pos += len; - } - } else { - /* Set at least the ecc byte positions to 0xff */ - start = old_oobinfo.eccbytes; - len = mtd.oob_size - start; - memcpy(oobbuf + start, - oobreadbuf + start, - len); - } - } else { - memcpy(oobbuf, oobreadbuf, mtd.oob_size); - } } /* Write out data */ @@ -588,7 +544,6 @@ closeall: close(ifd); libmtd_close(mtd_desc); free(filebuf); - free(oobbuf); close(fd); if (failed -- cgit v1.2.3