* [PATCH 01/16] mtd: Add support for marking blocks as good
2016-03-15 11:15 Introduce mtd-peb API Sascha Hauer
@ 2016-03-15 11:15 ` Sascha Hauer
2016-03-15 11:15 ` [PATCH 02/16] mtd: nand: Add option to print bbt in nand command Sascha Hauer
` (14 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Sascha Hauer @ 2016-03-15 11:15 UTC (permalink / raw)
To: Barebox List
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
commands/nand.c | 34 +++++++++++++++++++++----
drivers/mtd/core.c | 16 ++++++++++++
drivers/mtd/mtdconcat.c | 24 ++++++++++++++++++
drivers/mtd/nand/nand_base.c | 59 ++++++++++++++++++++++++++++++++++++++++++++
drivers/mtd/partition.c | 16 ++++++++++++
fs/devfs-core.c | 1 +
include/linux/mtd/mtd-abi.h | 1 +
include/linux/mtd/mtd.h | 2 ++
include/linux/mtd/nand.h | 2 ++
9 files changed, 150 insertions(+), 5 deletions(-)
diff --git a/commands/nand.c b/commands/nand.c
index c330ad1..1807c92 100644
--- a/commands/nand.c
+++ b/commands/nand.c
@@ -32,6 +32,7 @@
#define NAND_ADD 1
#define NAND_DEL 2
#define NAND_MARKBAD 3
+#define NAND_MARKGOOD 4
static int do_nand(int argc, char *argv[])
{
@@ -39,7 +40,7 @@ static int do_nand(int argc, char *argv[])
int command = 0;
loff_t badblock = 0;
- while((opt = getopt(argc, argv, "adb:")) > 0) {
+ while((opt = getopt(argc, argv, "adb:g:")) > 0) {
if (command) {
printf("only one command may be given\n");
return 1;
@@ -55,12 +56,24 @@ static int do_nand(int argc, char *argv[])
case 'b':
command = NAND_MARKBAD;
badblock = strtoull_suffix(optarg, NULL, 0);
+ break;
+ case 'g':
+ command = NAND_MARKGOOD;
+ badblock = strtoull_suffix(optarg, NULL, 0);
+ break;
+ default:
+ return COMMAND_ERROR_USAGE;
}
}
if (optind >= argc)
return COMMAND_ERROR_USAGE;
+ if (!command) {
+ printf("No action given\n");
+ return COMMAND_ERROR_USAGE;
+ }
+
if (command == NAND_ADD) {
while (optind < argc) {
if (dev_add_bb_dev(basename(argv[optind]), NULL))
@@ -77,11 +90,21 @@ static int do_nand(int argc, char *argv[])
}
}
- if (command == NAND_MARKBAD) {
+ if (command == NAND_MARKBAD || command == NAND_MARKGOOD) {
int ret = 0, fd;
+ const char *str;
+ int ctl;
+
+ if (command == NAND_MARKBAD) {
+ str = "bad";
+ ctl = MEMSETBADBLOCK;
+ } else {
+ str = "good";
+ ctl = MEMSETGOODBLOCK;
+ }
- printf("marking block at 0x%08llx on %s as bad\n",
- badblock, argv[optind]);
+ printf("marking block at 0x%08llx on %s as %s\n",
+ badblock, argv[optind], str);
fd = open(argv[optind], O_RDWR);
if (fd < 0) {
@@ -89,7 +112,7 @@ static int do_nand(int argc, char *argv[])
return 1;
}
- ret = ioctl(fd, MEMSETBADBLOCK, &badblock);
+ ret = ioctl(fd, ctl, &badblock);
if (ret) {
if (ret == -EINVAL)
printf("Maybe offset %lld is out of range.\n",
@@ -110,6 +133,7 @@ BAREBOX_CMD_HELP_TEXT("Options:")
BAREBOX_CMD_HELP_OPT ("-a", "register a bad block aware device ontop of a normal NAND device")
BAREBOX_CMD_HELP_OPT ("-d", "deregister a bad block aware device")
BAREBOX_CMD_HELP_OPT ("-b OFFS", "mark block at OFFSet as bad")
+BAREBOX_CMD_HELP_OPT ("-g OFFS", "mark block at OFFSet as good")
BAREBOX_CMD_HELP_END
BAREBOX_CMD_START(nand)
diff --git a/drivers/mtd/core.c b/drivers/mtd/core.c
index 161c6ad..3143b07 100644
--- a/drivers/mtd/core.c
+++ b/drivers/mtd/core.c
@@ -231,6 +231,10 @@ int mtd_ioctl(struct cdev *cdev, int request, void *buf)
dev_dbg(cdev->dev, "MEMSETBADBLOCK: 0x%08llx\n", *offset);
ret = mtd_block_markbad(mtd, *offset);
break;
+ case MEMSETGOODBLOCK:
+ dev_dbg(cdev->dev, "MEMSETGOODBLOCK: 0x%08llx\n", *offset);
+ ret = mtd_block_markgood(mtd, *offset);
+ break;
case MEMERASE:
ret = mtd_op_erase(cdev, ei->length, ei->start + cdev->offset);
break;
@@ -320,6 +324,18 @@ int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs)
return ret;
}
+int mtd_block_markgood(struct mtd_info *mtd, loff_t ofs)
+{
+ int ret;
+
+ if (mtd->block_markgood)
+ ret = mtd->block_markgood(mtd, ofs);
+ else
+ ret = -ENOSYS;
+
+ return ret;
+}
+
int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
u_char *buf)
{
diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c
index 6395b2f..fa43071 100644
--- a/drivers/mtd/mtdconcat.c
+++ b/drivers/mtd/mtdconcat.c
@@ -506,6 +506,28 @@ static int concat_block_markbad(struct mtd_info *mtd, loff_t ofs)
return err;
}
+static int concat_block_markgood(struct mtd_info *mtd, loff_t ofs)
+{
+ struct mtd_concat *concat = CONCAT(mtd);
+ int i, err = -EINVAL;
+
+ for (i = 0; i < concat->num_subdev; i++) {
+ struct mtd_info *subdev = concat->subdev[i];
+
+ if (ofs >= subdev->size) {
+ ofs -= subdev->size;
+ continue;
+ }
+
+ err = mtd_block_markgood(subdev, ofs);
+ if (!err)
+ mtd->ecc_stats.badblocks--;
+ break;
+ }
+
+ return err;
+}
+
/*
* This function constructs a virtual MTD device by concatenating
* num_devs MTD devices. A pointer to the new device object is
@@ -565,6 +587,8 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
concat->mtd.block_isbad = concat_block_isbad;
if (subdev[0]->block_markbad)
concat->mtd.block_markbad = concat_block_markbad;
+ if (subdev[0]->block_markgood)
+ concat->mtd.block_markgood = concat_block_markgood;
concat->mtd.ecc_stats.badblocks = subdev[0]->ecc_stats.badblocks;
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index ec5a8b7..ffbf829 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -456,6 +456,38 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
return chip->block_bad(mtd, ofs, getchip);
}
+/**
+ * nand_default_block_markgood - [DEFAULT] mark a block good
+ * @mtd: MTD device structure
+ * @ofs: offset from device start
+ *
+ * This is the default implementation, which can be overridden by
+ * a hardware specific driver.
+*/
+static __maybe_unused int nand_default_block_markgood(struct mtd_info *mtd, loff_t ofs)
+{
+ struct nand_chip *chip = mtd->priv;
+ int block, res, ret = 0;
+
+ /* Get block number */
+ block = (int)(ofs >> chip->bbt_erase_shift);
+ /* Mark block good in memory-based BBT */
+ if (chip->bbt)
+ chip->bbt[block >> 2] &= ~(0x01 << ((block & 0x03) << 1));
+
+ /* Update flash-based bad block table */
+ if (IS_ENABLED(CONFIG_NAND_BBT) && chip->bbt_options & NAND_BBT_USE_FLASH) {
+ res = nand_update_bbt(mtd, ofs);
+ if (!ret)
+ ret = res;
+ }
+
+ if (!ret)
+ mtd->ecc_stats.badblocks++;
+
+ return ret;
+}
+
/* Wait for the ready pin, after a command. The timeout is caught later. */
void nand_wait_ready(struct mtd_info *mtd)
{
@@ -2775,6 +2807,30 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
}
/**
+ * nand_block_markgood - [MTD Interface] Mark block at the given offset as bad
+ * @mtd: MTD device structure
+ * @ofs: offset relative to mtd start
+ */
+static int nand_block_markgood(struct mtd_info *mtd, loff_t ofs)
+{
+ struct nand_chip *chip = mtd->priv;
+ int ret;
+
+ if (!IS_ENABLED(CONFIG_MTD_WRITE))
+ return -ENOTSUPP;
+
+ ret = nand_block_isbad(mtd, ofs);
+ if (ret < 0)
+ return ret;
+
+ /* If it was good already, return success and do nothing */
+ if (!ret)
+ return 0;
+
+ return chip->block_markgood(mtd, ofs);
+}
+
+/**
* nand_onfi_set_features- [REPLACEABLE] set features for ONFI nand
* @mtd: MTD device structure
* @chip: nand chip info structure
@@ -2844,6 +2900,8 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)
#ifdef CONFIG_MTD_WRITE
if (!chip->block_markbad)
chip->block_markbad = nand_default_block_markbad;
+ if (!chip->block_markgood)
+ chip->block_markgood = nand_default_block_markgood;
if (!chip->write_buf)
chip->write_buf = busw ? nand_write_buf16 : nand_write_buf;
#endif
@@ -3707,6 +3765,7 @@ int nand_scan_tail(struct mtd_info *mtd)
mtd->unlock = NULL;
mtd->block_isbad = nand_block_isbad;
mtd->block_markbad = nand_block_markbad;
+ mtd->block_markgood = nand_block_markgood;
mtd->writebufsize = mtd->writesize;
/* propagate ecc info to mtd_info */
diff --git a/drivers/mtd/partition.c b/drivers/mtd/partition.c
index c11a3db..261e35c 100644
--- a/drivers/mtd/partition.c
+++ b/drivers/mtd/partition.c
@@ -114,6 +114,21 @@ static int mtd_part_block_markbad(struct mtd_info *mtd, loff_t ofs)
return res;
}
+static int mtd_part_block_markgood(struct mtd_info *mtd, loff_t ofs)
+{
+ int res;
+
+ if (!(mtd->flags & MTD_WRITEABLE))
+ return -EROFS;
+ if (ofs >= mtd->size)
+ return -EINVAL;
+ ofs += mtd->master_offset;
+ res = mtd->master->block_markgood(mtd->master, ofs);
+ if (!res)
+ mtd->ecc_stats.badblocks--;
+ return res;
+}
+
struct mtd_info *mtd_add_partition(struct mtd_info *mtd, off_t offset,
uint64_t size, unsigned long flags, const char *name)
{
@@ -168,6 +183,7 @@ struct mtd_info *mtd_add_partition(struct mtd_info *mtd, off_t offset,
part->lock = mtd_part_lock;
part->unlock = mtd_part_unlock;
part->block_markbad = mtd->block_markbad ? mtd_part_block_markbad : NULL;
+ part->block_markgood = mtd->block_markgood ? mtd_part_block_markgood : NULL;
}
if (mtd->write_oob)
diff --git a/fs/devfs-core.c b/fs/devfs-core.c
index deacaaa..75ed3b0 100644
--- a/fs/devfs-core.c
+++ b/fs/devfs-core.c
@@ -192,6 +192,7 @@ static int partition_ioctl(struct cdev *cdev, int request, void *buf)
switch (request) {
case MEMSETBADBLOCK:
+ case MEMSETGOODBLOCK:
case MEMGETBADBLOCK:
offset = *_buf;
offset += cdev->offset;
diff --git a/include/linux/mtd/mtd-abi.h b/include/linux/mtd/mtd-abi.h
index 8e778df..9bca9b5 100644
--- a/include/linux/mtd/mtd-abi.h
+++ b/include/linux/mtd/mtd-abi.h
@@ -118,6 +118,7 @@ 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 MEMSETGOODBLOCK _IOW('M', 20, loff_t)
/*
* Obsolete legacy interface. Keep it in order not to break userspace
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 421a941..efb08b1 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -189,6 +189,7 @@ struct mtd_info {
/* Bad block management functions */
int (*block_isbad) (struct mtd_info *mtd, loff_t ofs);
int (*block_markbad) (struct mtd_info *mtd, loff_t ofs);
+ int (*block_markgood) (struct mtd_info *mtd, loff_t ofs);
/* ECC status information */
struct mtd_ecc_stats ecc_stats;
@@ -308,6 +309,7 @@ int mtd_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
int mtd_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
int mtd_block_isbad(struct mtd_info *mtd, loff_t ofs);
int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs);
+int mtd_block_markgood(struct mtd_info *mtd, loff_t ofs);
int mtd_all_ff(const void *buf, unsigned int len);
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 83d664e..b787842 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -394,6 +394,7 @@ struct nand_buffers {
* @select_chip: [REPLACEABLE] select chip nr
* @block_bad: [REPLACEABLE] check, if the block is bad
* @block_markbad: [REPLACEABLE] mark the block bad
+ * @block_markgood: [REPLACEABLE] mark the block good
* @cmd_ctrl: [BOARDSPECIFIC] hardwarespecific function for controlling
* ALE/CLE/nCE. Also used to write command and address
* @init_size: [BOARDSPECIFIC] hardwarespecific function for setting
@@ -479,6 +480,7 @@ struct nand_chip {
void (*select_chip)(struct mtd_info *mtd, int chip);
int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);
int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
+ int (*block_markgood)(struct mtd_info *mtd, loff_t ofs);
void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl);
int (*init_size)(struct mtd_info *mtd, struct nand_chip *this,
u8 *id_data);
--
2.7.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 02/16] mtd: nand: Add option to print bbt in nand command
2016-03-15 11:15 Introduce mtd-peb API Sascha Hauer
2016-03-15 11:15 ` [PATCH 01/16] mtd: Add support for marking blocks as good Sascha Hauer
@ 2016-03-15 11:15 ` Sascha Hauer
2016-03-15 11:15 ` [PATCH 03/16] mtd: mtdpart: Add oob_read function Sascha Hauer
` (13 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Sascha Hauer @ 2016-03-15 11:15 UTC (permalink / raw)
To: Barebox List
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
commands/nand.c | 51 ++++++++++++++++++++++++++++++++++++++++-----------
1 file changed, 40 insertions(+), 11 deletions(-)
diff --git a/commands/nand.c b/commands/nand.c
index 1807c92..b065a66 100644
--- a/commands/nand.c
+++ b/commands/nand.c
@@ -33,14 +33,18 @@
#define NAND_DEL 2
#define NAND_MARKBAD 3
#define NAND_MARKGOOD 4
+#define NAND_INFO 5
static int do_nand(int argc, char *argv[])
{
int opt;
int command = 0;
loff_t badblock = 0;
+ int fd;
+ int ret;
+ struct mtd_info_user mtdinfo;
- while((opt = getopt(argc, argv, "adb:g:")) > 0) {
+ while((opt = getopt(argc, argv, "adb:g:i")) > 0) {
if (command) {
printf("only one command may be given\n");
return 1;
@@ -61,6 +65,9 @@ static int do_nand(int argc, char *argv[])
command = NAND_MARKGOOD;
badblock = strtoull_suffix(optarg, NULL, 0);
break;
+ case 'i':
+ command = NAND_INFO;
+ break;
default:
return COMMAND_ERROR_USAGE;
}
@@ -90,8 +97,17 @@ static int do_nand(int argc, char *argv[])
}
}
+ fd = open(argv[optind], O_RDWR);
+ if (fd < 0) {
+ perror("open");
+ return 1;
+ }
+
+ ret = ioctl(fd, MEMGETINFO, &mtdinfo);
+ if (ret)
+ goto out;
+
if (command == NAND_MARKBAD || command == NAND_MARKGOOD) {
- int ret = 0, fd;
const char *str;
int ctl;
@@ -106,12 +122,6 @@ static int do_nand(int argc, char *argv[])
printf("marking block at 0x%08llx on %s as %s\n",
badblock, argv[optind], str);
- fd = open(argv[optind], O_RDWR);
- if (fd < 0) {
- perror("open");
- return 1;
- }
-
ret = ioctl(fd, ctl, &badblock);
if (ret) {
if (ret == -EINVAL)
@@ -121,11 +131,29 @@ static int do_nand(int argc, char *argv[])
perror("ioctl");
}
- close(fd);
- return ret;
+ goto out;
}
- return 0;
+ if (command == NAND_INFO) {
+ loff_t ofs;
+ int bad = 0;
+
+ for (ofs = 0; ofs < mtdinfo.size; ofs += mtdinfo.erasesize) {
+ if (ioctl(fd, MEMGETBADBLOCK, &ofs)) {
+ printf("Block at 0x%08llx is bad\n", ofs);
+ bad = 1;
+ }
+ }
+
+ if (!bad)
+ printf("No bad blocks\n");
+ }
+
+ ret = 0;
+out:
+ close(fd);
+
+ return ret;
}
BAREBOX_CMD_HELP_START(nand)
@@ -134,6 +162,7 @@ BAREBOX_CMD_HELP_OPT ("-a", "register a bad block aware device ontop of a norma
BAREBOX_CMD_HELP_OPT ("-d", "deregister a bad block aware device")
BAREBOX_CMD_HELP_OPT ("-b OFFS", "mark block at OFFSet as bad")
BAREBOX_CMD_HELP_OPT ("-g OFFS", "mark block at OFFSet as good")
+BAREBOX_CMD_HELP_OPT ("-i", "info. Show information about bad blocks")
BAREBOX_CMD_HELP_END
BAREBOX_CMD_START(nand)
--
2.7.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 03/16] mtd: mtdpart: Add oob_read function
2016-03-15 11:15 Introduce mtd-peb API Sascha Hauer
2016-03-15 11:15 ` [PATCH 01/16] mtd: Add support for marking blocks as good Sascha Hauer
2016-03-15 11:15 ` [PATCH 02/16] mtd: nand: Add option to print bbt in nand command Sascha Hauer
@ 2016-03-15 11:15 ` Sascha Hauer
2016-03-15 11:15 ` [PATCH 04/16] mtd: Introduce function to get mtd type string Sascha Hauer
` (12 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Sascha Hauer @ 2016-03-15 11:15 UTC (permalink / raw)
To: Barebox List
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/mtd/partition.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/drivers/mtd/partition.c b/drivers/mtd/partition.c
index 261e35c..777cb75 100644
--- a/drivers/mtd/partition.c
+++ b/drivers/mtd/partition.c
@@ -18,6 +18,26 @@ static int mtd_part_read(struct mtd_info *mtd, loff_t from, size_t len,
return res;
}
+static int mtd_part_read_oob(struct mtd_info *mtd, loff_t from,
+ struct mtd_oob_ops *ops)
+{
+ int res;
+
+ if (from >= mtd->size)
+ return -EINVAL;
+ if (ops->datbuf && from + ops->len > mtd->size)
+ return -EINVAL;
+
+ res = mtd->master->read_oob(mtd->master, from + mtd->master_offset, ops);
+ if (unlikely(res)) {
+ if (mtd_is_bitflip(res))
+ mtd->ecc_stats.corrected++;
+ if (mtd_is_eccerr(res))
+ mtd->ecc_stats.failed++;
+ }
+ return res;
+}
+
static int mtd_part_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf)
{
@@ -188,6 +208,8 @@ struct mtd_info *mtd_add_partition(struct mtd_info *mtd, off_t offset,
if (mtd->write_oob)
part->write_oob = mtd_part_write_oob;
+ if (mtd->read_oob)
+ part->read_oob = mtd_part_read_oob;
part->block_isbad = mtd->block_isbad ? mtd_part_block_isbad : NULL;
part->size = size;
--
2.7.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 04/16] mtd: Introduce function to get mtd type string
2016-03-15 11:15 Introduce mtd-peb API Sascha Hauer
` (2 preceding siblings ...)
2016-03-15 11:15 ` [PATCH 03/16] mtd: mtdpart: Add oob_read function Sascha Hauer
@ 2016-03-15 11:15 ` Sascha Hauer
2016-03-15 11:15 ` [PATCH 05/16] mtd: rename mtd_all_ff -> mtd_buf_all_ff Sascha Hauer
` (11 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Sascha Hauer @ 2016-03-15 11:15 UTC (permalink / raw)
To: Barebox List
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/mtd/core.c | 22 ++++++++++++++++++++++
include/linux/mtd/mtd.h | 1 +
2 files changed, 23 insertions(+)
diff --git a/drivers/mtd/core.c b/drivers/mtd/core.c
index 3143b07..0a3f7ed 100644
--- a/drivers/mtd/core.c
+++ b/drivers/mtd/core.c
@@ -733,3 +733,25 @@ void mtdcore_add_hook(struct mtddev_hook *hook)
{
list_add(&hook->hook, &mtd_register_hooks);
}
+
+const char *mtd_type_str(struct mtd_info *mtd)
+{
+ switch (mtd->type) {
+ case MTD_ABSENT:
+ return "absent";
+ case MTD_RAM:
+ return "ram";
+ case MTD_ROM:
+ return "rom";
+ case MTD_NORFLASH:
+ return "nor";
+ case MTD_NANDFLASH:
+ return "nand";
+ case MTD_DATAFLASH:
+ return"dataflash";
+ case MTD_UBIVOLUME:
+ return "ubi";
+ default:
+ return "unknown";
+ }
+}
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index efb08b1..98dd82c 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -281,6 +281,7 @@ extern struct mtd_info *get_mtd_device_nm(const char *name);
extern void put_mtd_device(struct mtd_info *mtd);
+const char *mtd_type_str(struct mtd_info *mtd);
struct mtd_notifier {
void (*add)(struct mtd_info *mtd);
--
2.7.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 05/16] mtd: rename mtd_all_ff -> mtd_buf_all_ff
2016-03-15 11:15 Introduce mtd-peb API Sascha Hauer
` (3 preceding siblings ...)
2016-03-15 11:15 ` [PATCH 04/16] mtd: Introduce function to get mtd type string Sascha Hauer
@ 2016-03-15 11:15 ` Sascha Hauer
2016-03-15 11:15 ` [PATCH 06/16] mtd: Introduce mtd_check_pattern Sascha Hauer
` (10 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Sascha Hauer @ 2016-03-15 11:15 UTC (permalink / raw)
To: Barebox List
To make clear this function checks a given buffer and not data on a mtd
device.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/mtd/core.c | 10 +++++++++-
drivers/mtd/nand/nand_base.c | 2 +-
include/linux/mtd/mtd.h | 2 +-
lib/libscan.c | 2 +-
4 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/drivers/mtd/core.c b/drivers/mtd/core.c
index 0a3f7ed..ff53a4a 100644
--- a/drivers/mtd/core.c
+++ b/drivers/mtd/core.c
@@ -34,7 +34,15 @@
static LIST_HEAD(mtd_register_hooks);
-int mtd_all_ff(const void *buf, unsigned int len)
+/**
+ * mtd_buf_all_ff - check if buffer contains only 0xff
+ * @buf: buffer to check
+ * @size: buffer size in bytes
+ *
+ * This function returns %1 if there are only 0xff bytes in @buf, and %0 if
+ * something else was also found.
+ */
+int mtd_buf_all_ff(const void *buf, unsigned int len)
{
while ((unsigned long)buf & 0x3) {
if (*(const uint8_t *)buf != 0xff)
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index ffbf829..7eef287 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -2403,7 +2403,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
memset(chip->oob_poi, 0xff, mtd->oobsize);
}
- if (oob || !mtd_all_ff(wbuf, mtd->writesize)) {
+ if (oob || !mtd_buf_all_ff(wbuf, mtd->writesize)) {
ret = chip->write_page(mtd, chip, column, bytes, wbuf,
oob_required, page, cached,
(ops->mode == MTD_OPS_RAW));
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 98dd82c..4374882 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -312,7 +312,7 @@ int mtd_block_isbad(struct mtd_info *mtd, loff_t ofs);
int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs);
int mtd_block_markgood(struct mtd_info *mtd, loff_t ofs);
-int mtd_all_ff(const void *buf, unsigned int len);
+int mtd_buf_all_ff(const void *buf, unsigned int len);
/*
* Debugging macro and defines
diff --git a/lib/libscan.c b/lib/libscan.c
index 0c850ae..29d1cdb 100644
--- a/lib/libscan.c
+++ b/lib/libscan.c
@@ -84,7 +84,7 @@ int libscan_ubi_scan(struct mtd_dev_info *mtd, int fd, struct ubi_scan_info **in
goto out_ec;
if (be32_to_cpu(ech.magic) != UBI_EC_HDR_MAGIC) {
- if (mtd_all_ff(&ech, sizeof(struct ubi_ec_hdr))) {
+ if (mtd_buf_all_ff(&ech, sizeof(struct ubi_ec_hdr))) {
si->empty_cnt += 1;
si->ec[eb] = EB_EMPTY;
if (v)
--
2.7.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 06/16] mtd: Introduce mtd_check_pattern
2016-03-15 11:15 Introduce mtd-peb API Sascha Hauer
` (4 preceding siblings ...)
2016-03-15 11:15 ` [PATCH 05/16] mtd: rename mtd_all_ff -> mtd_buf_all_ff Sascha Hauer
@ 2016-03-15 11:15 ` Sascha Hauer
2016-03-15 11:15 ` [PATCH 07/16] mtd: Introduce mtd-peb API Sascha Hauer
` (9 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Sascha Hauer @ 2016-03-15 11:15 UTC (permalink / raw)
To: Barebox List
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/mtd/core.c | 19 +++++++++++++++++++
include/linux/mtd/mtd.h | 1 +
2 files changed, 20 insertions(+)
diff --git a/drivers/mtd/core.c b/drivers/mtd/core.c
index ff53a4a..dcf94bf 100644
--- a/drivers/mtd/core.c
+++ b/drivers/mtd/core.c
@@ -74,6 +74,25 @@ int mtd_buf_all_ff(const void *buf, unsigned int len)
return 1;
}
+/**
+ * mtd_buf_check_pattern - check if buffer contains only a certain byte pattern.
+ * @buf: buffer to check
+ * @patt: the pattern to check
+ * @size: buffer size in bytes
+ *
+ * This function returns %1 in there are only @patt bytes in @buf, and %0 if
+ * something else was also found.
+ */
+int mtd_buf_check_pattern(const void *buf, uint8_t patt, int size)
+{
+ int i;
+
+ for (i = 0; i < size; i++)
+ if (((const uint8_t *)buf)[i] != patt)
+ return 0;
+ return 1;
+}
+
static ssize_t mtd_op_read(struct cdev *cdev, void* buf, size_t count,
loff_t offset, ulong flags)
{
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 4374882..18d8866 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -313,6 +313,7 @@ int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs);
int mtd_block_markgood(struct mtd_info *mtd, loff_t ofs);
int mtd_buf_all_ff(const void *buf, unsigned int len);
+int mtd_buf_check_pattern(const void *buf, uint8_t patt, int size);
/*
* Debugging macro and defines
--
2.7.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 07/16] mtd: Introduce mtd-peb API
2016-03-15 11:15 Introduce mtd-peb API Sascha Hauer
` (5 preceding siblings ...)
2016-03-15 11:15 ` [PATCH 06/16] mtd: Introduce mtd_check_pattern Sascha Hauer
@ 2016-03-15 11:15 ` Sascha Hauer
2016-03-15 11:15 ` [PATCH 08/16] ubiformat: Use " Sascha Hauer
` (8 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Sascha Hauer @ 2016-03-15 11:15 UTC (permalink / raw)
To: Barebox List
Code which properly wants to handle Nand flash has to work
in a block based way since blocks are the entities that are erased or
may become bad. The regular mtd API works based on offsets in the device
which introduces unhandy 64bit arithmetics and the requirement to align
buffers to blocks.
This introduces the mtd peb API (PEB for physical Erase Block) which
allows the users to work in a block oriented way. The API is heavily
inspired by the UBI IO layer and in fact can replace parts thereof
later.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/mtd/Kconfig | 9 +
drivers/mtd/Makefile | 2 +-
drivers/mtd/peb.c | 537 ++++++++++++++++++++++++++++++++++++++++++++++++++
include/mtd/mtd-peb.h | 21 ++
4 files changed, 568 insertions(+), 1 deletion(-)
create mode 100644 drivers/mtd/peb.c
create mode 100644 include/mtd/mtd-peb.h
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index ea1be55..db9c287 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -30,6 +30,15 @@ config MTD_CONCAT
needs driver support, currently only the cfi-flash driver supports
concatenating MTD devices.
+comment "MTD debug options"
+
+config MTD_PEB_DEBUG
+ bool "MTD PEB debug"
+ help
+ When enabled the MTD PEB API will emulate bitflips. Random read
+ operations will return that bits are flipped. The MTD PEB API
+ is used by UBI and ubiformat
+
source "drivers/mtd/devices/Kconfig"
source "drivers/mtd/nor/Kconfig"
source "drivers/mtd/nand/Kconfig"
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index d3ae7fc..bfac8eb 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -3,7 +3,7 @@ obj-$(CONFIG_DRIVER_CFI) += nor/
obj-$(CONFIG_MTD_SPI_NOR) += spi-nor/
obj-$(CONFIG_MTD_UBI) += ubi/
obj-y += devices/
-obj-$(CONFIG_MTD) += core.o partition.o
+obj-$(CONFIG_MTD) += core.o partition.o peb.o
obj-$(CONFIG_MTD_OOB_DEVICE) += mtdoob.o
obj-$(CONFIG_MTD_RAW_DEVICE) += mtdraw.o
obj-$(CONFIG_MTD_CONCAT) += mtdconcat.o
diff --git a/drivers/mtd/peb.c b/drivers/mtd/peb.c
new file mode 100644
index 0000000..15420a8
--- /dev/null
+++ b/drivers/mtd/peb.c
@@ -0,0 +1,537 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <init.h>
+#include <magicvar.h>
+#include <globalvar.h>
+#include <linux/mtd/mtd.h>
+#include <mtd/mtd-peb.h>
+#include <linux/err.h>
+
+#define MTD_IO_RETRIES 3
+
+static int __mtd_peb_chk_io;
+
+static int mtd_peb_chk_io(void)
+{
+ if (!IS_ENABLED(CONFIG_MTD_PEB_DEBUG))
+ return 0;
+
+ if (!__mtd_peb_chk_io)
+ return 0;
+
+ return 1;
+}
+
+static u32 __mtd_peb_emulate_bitflip;
+
+static int mtd_peb_emulate_bitflip(void)
+{
+ if (!IS_ENABLED(CONFIG_MTD_PEB_DEBUG))
+ return 0;
+
+ if (!__mtd_peb_emulate_bitflip)
+ return 0;
+
+ return !(random32() % __mtd_peb_emulate_bitflip);
+}
+
+static u32 __mtd_peb_emulate_write_failure;
+
+static int mtd_peb_emulate_write_failure(void)
+{
+ if (!IS_ENABLED(CONFIG_MTD_PEB_DEBUG))
+ return 0;
+
+ if (!__mtd_peb_emulate_write_failure)
+ return 0;
+
+ return !(random32() % __mtd_peb_emulate_write_failure);
+}
+
+static u32 __mtd_peb_emulate_erase_failures;
+
+static int mtd_peb_emulate_erase_failure(void)
+{
+ if (!IS_ENABLED(CONFIG_MTD_PEB_DEBUG))
+ return 0;
+
+ if (!__mtd_peb_emulate_erase_failures)
+ return 0;
+
+ return !(random32() % __mtd_peb_emulate_erase_failures);
+}
+
+#ifdef CONFIG_MTD_PEB_DEBUG
+static int mtd_peb_debug_init(void)
+{
+ globalvar_add_simple_int("mtd_peb.mtd_peb_emulate_bitflip",
+ &__mtd_peb_emulate_bitflip, "%u");
+ globalvar_add_simple_int("mtd_peb.mtd_peb_emulate_write_failure",
+ &__mtd_peb_emulate_write_failure, "%u");
+ globalvar_add_simple_int("mtd_peb.mtd_peb_emulate_erase_failures",
+ &__mtd_peb_emulate_erase_failures, "%u");
+ globalvar_add_simple_bool("mtd_peb.mtd_peb_chk_io",
+ &__mtd_peb_chk_io);
+ return 0;
+}
+device_initcall(mtd_peb_debug_init);
+
+BAREBOX_MAGICVAR_NAMED(global_mtd_peb_emulate_bitflip,
+ global.mtd_peb.emulate_bitflip,
+ "random bitflips, on average every #nth access returns -EUCLEAN");
+BAREBOX_MAGICVAR_NAMED(global_mtd_peb_emulate_write_failure,
+ global.mtd_peb.emulate_write_failure,
+ "random write failures, on average every #nth access returns write failure");
+BAREBOX_MAGICVAR_NAMED(global_mtd_peb_emulate_erase_failures,
+ global.mtd_peb.emulate_erase_failures,
+ "random erase failures, on average every #nth access returns erase failure");
+BAREBOX_MAGICVAR_NAMED(global_mtd_peb_chk_io,
+ global.mtd_peb.chk_io,
+ "If true, written data will be verified");
+
+#endif
+
+static int mtd_peb_valid(struct mtd_info *mtd, int pnum)
+{
+ if (pnum < 0)
+ return false;
+
+ if ((uint64_t)pnum * mtd->erasesize >= mtd->size)
+ return false;
+
+ if (mtd->numeraseregions)
+ return false;
+
+ return true;
+}
+
+/**
+ * mtd_num_pebs - return number of PEBs for this device
+ * @mtd: mtd device
+ *
+ * This function returns the number of physical erase blocks this device
+ * has.
+ */
+int mtd_num_pebs(struct mtd_info *mtd)
+{
+ return mtd_div_by_eb(mtd->size, mtd);
+}
+
+/**
+ * mtd_peb_mark_bad - mark a physical eraseblock as bad
+ * @mtd: mtd device
+ * @pnum: The number of the block
+ *
+ * This function marks a physical eraseblock as bad.
+ */
+int mtd_peb_mark_bad(struct mtd_info *mtd, int pnum)
+{
+ return mtd_block_markbad(mtd, (loff_t)pnum * mtd->erasesize);
+}
+
+/**
+ * mtd_peb_is_bad - test if a physical eraseblock is bad
+ * @mtd: mtd device
+ * @pnum: The number of the block
+ *
+ * This function tests if a physical eraseblock is bad. Returns
+ * 0 if it is good, 1 if it is bad or a negative error value if the
+ * block is invalid
+ */
+int mtd_peb_is_bad(struct mtd_info *mtd, int pnum)
+{
+ if (!mtd_peb_valid(mtd, pnum))
+ return -EINVAL;
+
+ return mtd_block_isbad(mtd, (loff_t)pnum * mtd->erasesize);
+}
+
+/**
+ * mtd_peb_read - read data from a physical eraseblock.
+ * @mtd: mtd device
+ * @buf: buffer where to store the read data
+ * @pnum: physical eraseblock number to read from
+ * @offset: offset within the physical eraseblock from where to read
+ * @len: how many bytes to read
+ *
+ * This function reads data from offset @offset of physical eraseblock @pnum
+ * and stores the read data in the @buf buffer. The following return codes are
+ * possible:
+ *
+ * o %0 if all the requested data were successfully read;
+ * o %-EUCLEAN if all the requested data were successfully read, but
+ * correctable bit-flips were detected; this is harmless but may indicate
+ * that this eraseblock may become bad soon (but do not have to);
+ * o %-EBADMSG if the MTD subsystem reported about data integrity problems, for
+ * example it can be an ECC error in case of NAND; this most probably means
+ * that the data is corrupted;
+ * o %-EIO if some I/O error occurred;
+ * o other negative error codes in case of other errors.
+ */
+int mtd_peb_read(struct mtd_info *mtd, void *buf, int pnum, int offset,
+ int len)
+{
+ int err, retries = 0;
+ size_t read;
+ loff_t addr;
+
+ if (!mtd_peb_valid(mtd, pnum))
+ return -EINVAL;
+ if (offset < 0 || offset + len > mtd->erasesize)
+ return -EINVAL;
+ if (len <= 0)
+ return -EINVAL;
+ if (mtd_peb_is_bad(mtd, pnum))
+ return -EINVAL;
+
+ /* Deliberately corrupt the buffer */
+ *((uint8_t *)buf) ^= 0xFF;
+
+ addr = (loff_t)pnum * mtd->erasesize + offset;
+retry:
+ err = mtd_read(mtd, addr, len, &read, buf);
+ if (err) {
+ const char *errstr = mtd_is_eccerr(err) ? " (ECC error)" : "";
+
+ if (mtd_is_bitflip(err)) {
+ /*
+ * -EUCLEAN is reported if there was a bit-flip which
+ * was corrected, so this is harmless.
+ *
+ * We do not report about it here unless debugging is
+ * enabled. A corresponding message will be printed
+ * later, when it is has been scrubbed.
+ */
+ dev_dbg(&mtd->class_dev, "fixable bit-flip detected at PEB %d\n", pnum);
+ if (len != read)
+ return -EIO;
+ return -EUCLEAN;
+ }
+
+ if (mtd_is_eccerr(err) && retries++ < MTD_IO_RETRIES)
+ goto retry;
+
+ dev_err(&mtd->class_dev, "error %d%s while reading %d bytes from PEB %d:%d\n",
+ err, errstr, len, pnum, offset);
+ return err;
+ }
+
+ if (len != read)
+ return -EIO;
+
+ if (mtd_peb_emulate_bitflip())
+ return -EUCLEAN;
+
+ return 0;
+}
+
+/**
+ * mtd_peb_check_all_ff - check that a region of flash is empty.
+ * @mtd: mtd device
+ * @pnum: the physical eraseblock number to check
+ * @offset: the starting offset within the physical eraseblock to check
+ * @len: the length of the region to check
+ *
+ * This function returns zero if only 0xFF bytes are present at offset
+ * @offset of the physical eraseblock @pnum, -EBADMSG if the buffer does
+ * not contain all 0xFF or other negative error codes when other errors
+ * occured
+ */
+int mtd_peb_check_all_ff(struct mtd_info *mtd, int pnum, int offset, int len,
+ int warn)
+{
+ size_t read;
+ int err;
+ void *buf;
+
+ buf = malloc(len);
+ if (!buf)
+ return -ENOMEM;
+
+ err = mtd_peb_read(mtd, buf, pnum, offset, len);
+ if (err && !mtd_is_bitflip(err)) {
+ dev_err(&mtd->class_dev,
+ "error %d while reading %d bytes from PEB %d:%d, read %zd bytes\n",
+ err, len, pnum, offset, read);
+ goto out;
+ }
+
+ err = mtd_buf_all_ff(buf, len);
+ if (err == 0) {
+ if (warn)
+ dev_err(&mtd->class_dev, "all-ff check failed for PEB %d\n",
+ pnum);
+ err = -EBADMSG;
+ goto out;
+ }
+
+ err = 0;
+
+out:
+ free(buf);
+
+ return err;
+}
+
+/**
+ * mtd_peb_verify - make sure write succeeded.
+ * @mtd: mtd device
+ * @buf: buffer with data which were written
+ * @pnum: physical eraseblock number the data were written to
+ * @offset: offset within the physical eraseblock the data were written to
+ * @len: how many bytes were written
+ *
+ * This functions reads data which were recently written and compares it with
+ * the original data buffer - the data have to match. Returns zero if the data
+ * match and a negative error code if not or in case of failure.
+ */
+int mtd_peb_verify(struct mtd_info *mtd, const void *buf, int pnum,
+ int offset, int len)
+{
+ int err, i;
+ size_t read;
+ void *buf1;
+ loff_t addr = (loff_t)pnum * mtd->erasesize + offset;
+
+ buf1 = malloc(len);
+ if (!buf1)
+ return 0;
+
+ err = mtd_read(mtd, addr, len, &read, buf1);
+ if (err && !mtd_is_bitflip(err))
+ goto out_free;
+
+ for (i = 0; i < len; i++) {
+ uint8_t c = ((uint8_t *)buf)[i];
+ uint8_t c1 = ((uint8_t *)buf1)[i];
+ int dump_len;
+
+ if (c == c1)
+ continue;
+
+ dev_err(&mtd->class_dev, "self-check failed for PEB %d:%d, len %d\n",
+ pnum, offset, len);
+ dev_info(&mtd->class_dev, "data differs at position %d\n", i);
+ dump_len = max_t(int, 128, len - i);
+#ifdef DEBUG
+ dev_info(&mtd->class_dev, "hex dump of the original buffer from %d to %d\n",
+ i, i + dump_len);
+ memory_display(buf + i, i, dump_len, 4, 0);
+ dev_info(&mtd->class_dev, "hex dump of the read buffer from %d to %d\n",
+ i, i + dump_len);
+ memory_display(buf1 + i, i, dump_len, 4, 0);
+ dump_stack();
+#endif
+ err = -EBADMSG;
+ goto out_free;
+ }
+
+ err = 0;
+
+out_free:
+ free(buf1);
+ return err;
+}
+
+/**
+ * mtd_peb_write - write data to a physical eraseblock.
+ * @mtd: mtd device
+ * @buf: buffer with the data to write
+ * @pnum: physical eraseblock number to write to
+ * @offset: offset within the physical eraseblock where to write
+ * @len: how many bytes to write
+ *
+ * This function writes @len bytes of data from buffer @buf to offset @offset
+ * of physical eraseblock @pnum. If all the data was successfully written,
+ * zero is returned. If an error occurred, this function returns a negative
+ * error code. If %-EBADMSG is returned, the physical eraseblock most probably
+ * went bad.
+ *
+ * Note, in case of an error, it is possible that something was still written
+ * to the flash media, but may be some garbage.
+ */
+int mtd_peb_write(struct mtd_info *mtd, const void *buf, int pnum, int offset,
+ int len)
+{
+ int err;
+ size_t written;
+ loff_t addr;
+
+ dev_dbg(&mtd->class_dev, "write %d bytes to PEB %d:%d\n", len, pnum, offset);
+
+ if (!mtd_peb_valid(mtd, pnum))
+ return -EINVAL;
+ if (offset < 0 || offset + len > mtd->erasesize)
+ return -EINVAL;
+ if (len <= 0)
+ return -EINVAL;
+ if (len % mtd->writesize)
+ return -EINVAL;
+ if (mtd_peb_is_bad(mtd, pnum))
+ return -EINVAL;
+
+ if (mtd_peb_emulate_write_failure()) {
+ dev_err(&mtd->class_dev, "Cannot write %d bytes to PEB %d:%d (emulated)\n",
+ len, pnum, offset);
+ return -EIO;
+ }
+
+ if (mtd_peb_chk_io()) {
+ /* The area we are writing to has to contain all 0xFF bytes */
+ err = mtd_peb_check_all_ff(mtd, pnum, offset, len, 1);
+ if (err)
+ return err;
+ }
+
+ addr = (loff_t)pnum * mtd->erasesize + offset;
+ err = mtd_write(mtd, addr, len, &written, buf);
+ if (err) {
+ dev_err(&mtd->class_dev, "error %d while writing %d bytes to PEB %d:%d, written %zd bytes\n",
+ err, len, pnum, offset, written);
+ } else {
+ if (written != len)
+ err = -EIO;
+ }
+
+ if (!err && mtd_peb_chk_io())
+ err = mtd_peb_verify(mtd, buf, pnum, offset, len);
+
+ return err;
+}
+
+/**
+ * mtd_peb_erase - erase a physical eraseblock.
+ * @mtd: mtd device
+ * @pnum: physical eraseblock number to erase
+ *
+ * This function erases physical eraseblock @pnum.
+ *
+ * This function returns 0 in case of success, %-EIO if the erasure failed,
+ * and other negative error codes in case of other errors. Note, %-EIO means
+ * that the physical eraseblock is bad.
+ */
+int mtd_peb_erase(struct mtd_info *mtd, int pnum)
+{
+ int ret;
+ struct erase_info ei = {};
+
+ dev_dbg(&mtd->class_dev, "erase PEB %d\n", pnum);
+
+ if (!mtd_peb_valid(mtd, pnum))
+ return -EINVAL;
+
+ ei.mtd = mtd;
+ ei.addr = (loff_t)pnum * mtd->erasesize;
+ ei.len = mtd->erasesize;
+
+ ret = mtd_erase(mtd, &ei);
+ if (ret)
+ return ret;
+
+ if (mtd_peb_chk_io()) {
+ ret = mtd_peb_check_all_ff(mtd, pnum, 0, mtd->erasesize, 1);
+ if (ret == -EBADMSG)
+ ret = -EIO;
+ }
+
+ if (mtd_peb_emulate_erase_failure()) {
+ dev_err(&mtd->class_dev, "cannot erase PEB %d (emulated)", pnum);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/* Patterns to write to a physical eraseblock when torturing it */
+static uint8_t patterns[] = {0xa5, 0x5a, 0x0};
+
+/**
+ * mtd_peb_torture - test a supposedly bad physical eraseblock.
+ * @mtd: mtd device
+ * @pnum: the physical eraseblock number to test
+ *
+ * This function is a last resort when an eraseblock is assumed to be
+ * bad. It will write and check some patterns to the block. If the test
+ * is passed then this function will with the block freshly erased and
+ * the positive number returned indicaties how often the block has been
+ * erased during this test.
+ * If the block does not pass the test the block is marked as bad and
+ * -EIO is returned.
+ * Other negative errors are returned in case of other errors.
+ */
+int mtd_peb_torture(struct mtd_info *mtd, int pnum)
+{
+ int err, i, patt_count;
+ void *peb_buf;
+
+ if (!mtd_peb_valid(mtd, pnum))
+ return -EINVAL;
+
+ peb_buf = malloc(mtd->erasesize);
+ if (!peb_buf)
+ return -ENOMEM;
+
+ dev_dbg(&mtd->class_dev, "run torture test for PEB %d\n", pnum);
+
+ patt_count = ARRAY_SIZE(patterns);
+
+ for (i = 0; i < patt_count; i++) {
+ err = mtd_peb_erase(mtd, pnum);
+ if (err)
+ goto out;
+
+ /* Make sure the PEB contains only 0xFF bytes after erasing */
+ err = mtd_peb_check_all_ff(mtd, pnum, 0, mtd->writesize, 0);
+ if (err)
+ goto out;
+
+ /* Write a pattern and check it */
+ memset(peb_buf, patterns[i], mtd->erasesize);
+ err = mtd_peb_write(mtd, peb_buf, pnum, 0, mtd->erasesize);
+ if (err)
+ goto out;
+
+ err = mtd_peb_verify(mtd, peb_buf, pnum, 0, mtd->erasesize);
+ if (err)
+ goto out;
+ }
+
+ err = mtd_peb_erase(mtd, pnum);
+ if (err)
+ goto out;
+
+ err = patt_count + 1;
+ dev_dbg(&mtd->class_dev, "PEB %d passed torture test, do not mark it as bad\n",
+ pnum);
+
+out:
+ if (err == -EUCLEAN || mtd_is_eccerr(err)) {
+ /*
+ * If a bit-flip or data integrity error was detected, the test
+ * has not passed because it happened on a freshly erased
+ * physical eraseblock which means something is wrong with it.
+ */
+ dev_err(&mtd->class_dev, "read problems on freshly erased PEB %d, marking it bad\n",
+ pnum);
+
+ mtd_peb_mark_bad(mtd, pnum);
+
+ err = -EIO;
+ }
+
+ free(peb_buf);
+
+ return err;
+}
diff --git a/include/mtd/mtd-peb.h b/include/mtd/mtd-peb.h
new file mode 100644
index 0000000..50ac9a5
--- /dev/null
+++ b/include/mtd/mtd-peb.h
@@ -0,0 +1,21 @@
+#ifndef __LINUX_MTD_MTDPEB_H
+#define __LINUX_MTD_MTDPEB_H
+
+#include <linux/mtd/mtd.h>
+
+int mtd_peb_read(struct mtd_info *mtd, void *buf, int pnum, int offset,
+ int len);
+int mtd_peb_write(struct mtd_info *mtd, const void *buf, int pnum, int offset,
+ int len);
+
+int mtd_peb_torture(struct mtd_info *mtd, int pnum);
+int mtd_peb_erase(struct mtd_info *mtd, int pnum);
+int mtd_peb_mark_bad(struct mtd_info *mtd, int pnum);
+int mtd_peb_is_bad(struct mtd_info *mtd, int pnum);
+int mtd_peb_check_all_ff(struct mtd_info *mtd, int pnum, int offset, int len,
+ int warn);
+int mtd_peb_verify(struct mtd_info *mtd, const void *buf, int pnum,
+ int offset, int len);
+int mtd_num_pebs(struct mtd_info *mtd);
+
+#endif /* __LINUX_MTD_MTDPEB_H */
--
2.7.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 08/16] ubiformat: Use mtd-peb API
2016-03-15 11:15 Introduce mtd-peb API Sascha Hauer
` (6 preceding siblings ...)
2016-03-15 11:15 ` [PATCH 07/16] mtd: Introduce mtd-peb API Sascha Hauer
@ 2016-03-15 11:15 ` Sascha Hauer
2016-03-15 11:15 ` [PATCH 09/16] remove now unused libmtd Sascha Hauer
` (7 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Sascha Hauer @ 2016-03-15 11:15 UTC (permalink / raw)
To: Barebox List
This changes ubiformat from the libmtd API to the mtd-peb API. This
makes the libmtd API unnecessary and it can be removed in the next
step.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
commands/ubiformat.c | 191 +++++++++++++++++++++++++-----------------------
include/mtd/libscan.h | 3 +-
include/mtd/libubigen.h | 4 +-
lib/libscan.c | 28 +++----
lib/libubigen.c | 23 ++----
5 files changed, 124 insertions(+), 125 deletions(-)
diff --git a/commands/ubiformat.c b/commands/ubiformat.c
index f9c50b7..0172654 100644
--- a/commands/ubiformat.c
+++ b/commands/ubiformat.c
@@ -46,12 +46,12 @@
#include <linux/stat.h>
#include <linux/log2.h>
#include <linux/mtd/mtd-abi.h>
-#include <mtd/libmtd.h>
#include <mtd/libscan.h>
#include <mtd/libubigen.h>
#include <mtd/ubi-user.h>
#include <mtd/utils.h>
#include <mtd/ubi-media.h>
+#include <mtd/mtd-peb.h>
/* The variables below are set by command line arguments */
struct args {
@@ -68,7 +68,6 @@ struct args {
long long ec;
const char *image;
const char *node;
- int node_fd;
};
static struct args args;
@@ -166,16 +165,18 @@ static int parse_opt(int argc, char *argv[])
return 0;
}
-static void print_bad_eraseblocks(const struct mtd_dev_info *mtd,
+static void print_bad_eraseblocks(struct mtd_info *mtd,
const struct ubi_scan_info *si)
{
- int first = 1, eb;
+ int first = 1, eb, eb_cnt;
+
+ eb_cnt = mtd_div_by_eb(mtd->size, mtd);
if (si->bad_cnt == 0)
return;
normsg_cont("%d bad eraseblocks found, numbers: ", si->bad_cnt);
- for (eb = 0; eb < mtd->eb_cnt; eb++) {
+ for (eb = 0; eb < eb_cnt; eb++) {
if (si->ec[eb] != EB_BAD)
continue;
if (first) {
@@ -210,7 +211,7 @@ static int change_ech(struct ubi_ec_hdr *hdr, uint32_t image_seq,
return 0;
}
-static int drop_ffs(const struct mtd_dev_info *mtd, const void *buf, int len)
+static int drop_ffs(struct mtd_info *mtd, const void *buf, int len)
{
int i;
@@ -220,8 +221,8 @@ static int drop_ffs(const struct mtd_dev_info *mtd, const void *buf, int len)
/* The resulting length must be aligned to the minimum flash I/O size */
len = i + 1;
- len = (len + mtd->min_io_size - 1) / mtd->min_io_size;
- len *= mtd->min_io_size;
+ len = (len + mtd->writesize - 1) / mtd->writesize;
+ len *= mtd->writesize;
return len;
}
@@ -271,20 +272,20 @@ static int consecutive_bad_check(int eb)
}
/* TODO: we should actually torture the PEB before marking it as bad */
-static int mark_bad(const struct mtd_dev_info *mtd, struct ubi_scan_info *si, int eb)
+static int mark_bad(struct mtd_info *mtd, struct ubi_scan_info *si, int eb)
{
int err;
if (!args.quiet)
normsg_cont("marking block %d bad\n", eb);
- if (!mtd->bb_allowed) {
+ if (!mtd_can_have_bb(mtd)) {
if (!args.quiet)
printf("\n");
return errmsg("bad blocks not supported by this flash");
}
- err = mtd_mark_bad(mtd, args.node_fd, eb);
+ err = mtd_peb_mark_bad(mtd, eb);
if (err)
return err;
@@ -294,24 +295,26 @@ static int mark_bad(const struct mtd_dev_info *mtd, struct ubi_scan_info *si, in
return consecutive_bad_check(eb);
}
-static int flash_image(const struct mtd_dev_info *mtd,
+static int flash_image(struct mtd_info *mtd,
const struct ubigen_info *ui, struct ubi_scan_info *si)
{
- int fd, img_ebs, eb, written_ebs = 0, ret = -1;
+ int fd, img_ebs, eb, written_ebs = 0, ret = -1, eb_cnt;
off_t st_size;
char *buf = NULL;
+ eb_cnt = mtd_num_pebs(mtd);
+
fd = open_file(&st_size);
if (fd < 0)
return fd;
- buf = malloc(mtd->eb_size);
+ buf = malloc(mtd->erasesize);
if (!buf) {
- sys_errmsg("cannot allocate %d bytes of memory", mtd->eb_size);
+ sys_errmsg("cannot allocate %d bytes of memory", mtd->erasesize);
goto out_close;
}
- img_ebs = st_size / mtd->eb_size;
+ img_ebs = st_size / mtd->erasesize;
if (img_ebs > si->good_cnt) {
sys_errmsg("file \"%s\" is too large (%lld bytes)",
@@ -319,10 +322,10 @@ static int flash_image(const struct mtd_dev_info *mtd,
goto out_close;
}
- if (st_size % mtd->eb_size) {
+ if (st_size % mtd->erasesize) {
sys_errmsg("file \"%s\" (size %lld bytes) is not multiple of "
"eraseblock size (%d bytes)",
- args.image, (long long)st_size, mtd->eb_size);
+ args.image, (long long)st_size, mtd->erasesize);
goto out_close;
}
@@ -332,13 +335,13 @@ static int flash_image(const struct mtd_dev_info *mtd,
}
verbose(args.verbose, "will write %d eraseblocks", img_ebs);
- for (eb = 0; eb < mtd->eb_cnt; eb++) {
+ for (eb = 0; eb < eb_cnt; eb++) {
int err, new_len;
long long ec;
if (!args.quiet && !args.verbose) {
printf("\rubiformat: flashing eraseblock %d -- %2u %% complete ",
- eb, (eb + 1) * 100 / mtd->eb_cnt);
+ eb, (eb + 1) * 100 / eb_cnt);
}
if (si->ec[eb] == EB_BAD)
@@ -348,13 +351,13 @@ static int flash_image(const struct mtd_dev_info *mtd,
normsg_cont("eraseblock %d: erase", eb);
}
- err = libmtd_erase(mtd, args.node_fd, eb);
+ err = mtd_peb_erase(mtd, eb);
if (err) {
if (!args.quiet)
printf("\n");
sys_errmsg("failed to erase eraseblock %d", eb);
- if (errno != EIO)
+ if (err != EIO)
goto out_close;
if (mark_bad(mtd, si, eb))
@@ -363,7 +366,7 @@ static int flash_image(const struct mtd_dev_info *mtd,
continue;
}
- err = read_full(fd, buf, mtd->eb_size);
+ err = read_full(fd, buf, mtd->erasesize);
if (err < 0) {
sys_errmsg("failed to read eraseblock %d from \"%s\"",
written_ebs, args.image);
@@ -392,20 +395,21 @@ static int flash_image(const struct mtd_dev_info *mtd,
printf(", write data\n");
}
- new_len = drop_ffs(mtd, buf, mtd->eb_size);
+ new_len = drop_ffs(mtd, buf, mtd->erasesize);
- err = libmtd_write(mtd, args.node_fd, eb, 0, buf, new_len);
+ err = mtd_peb_write(mtd, buf, eb, 0, new_len);
if (err) {
sys_errmsg("cannot write eraseblock %d", eb);
- if (errno != EIO)
+ if (err != EIO)
+ goto out_close;
+
+ err = mtd_peb_torture(mtd, eb);
+ if (err < 0 && err != -EIO)
+ goto out_close;
+ if (err == -EIO && consecutive_bad_check(eb))
goto out_close;
- err = mtd_torture(mtd, args.node_fd, eb);
- if (err) {
- if (mark_bad(mtd, si, eb))
- goto out_close;
- }
continue;
}
if (++written_ebs >= img_ebs)
@@ -423,30 +427,32 @@ out_close:
return ret;
}
-static int format(const struct mtd_dev_info *mtd,
+static int format(struct mtd_info *mtd,
const struct ubigen_info *ui, struct ubi_scan_info *si,
- int start_eb, int novtbl)
+ int start_eb, int novtbl, int subpage_size)
{
- int eb, err, write_size;
+ int eb, err, write_size, eb_cnt;
struct ubi_ec_hdr *hdr;
struct ubi_vtbl_record *vtbl;
int eb1 = -1, eb2 = -1;
long long ec1 = -1, ec2 = -1;
- write_size = UBI_EC_HDR_SIZE + mtd->subpage_size - 1;
- write_size /= mtd->subpage_size;
- write_size *= mtd->subpage_size;
+ eb_cnt = mtd_num_pebs(mtd);
+
+ write_size = UBI_EC_HDR_SIZE + subpage_size - 1;
+ write_size /= subpage_size;
+ write_size *= subpage_size;
hdr = malloc(write_size);
if (!hdr)
return sys_errmsg("cannot allocate %d bytes of memory", write_size);
memset(hdr, 0xFF, write_size);
- for (eb = start_eb; eb < mtd->eb_cnt; eb++) {
+ for (eb = start_eb; eb < eb_cnt; eb++) {
long long ec;
if (!args.quiet && !args.verbose) {
printf("\rubiformat: formatting eraseblock %d -- %2u %% complete ",
- eb, (eb + 1 - start_eb) * 100 / (mtd->eb_cnt - start_eb));
+ eb, (eb + 1 - start_eb) * 100 / (eb_cnt - start_eb));
}
if (si->ec[eb] == EB_BAD)
@@ -464,13 +470,13 @@ static int format(const struct mtd_dev_info *mtd,
normsg_cont("eraseblock %d: erase", eb);
}
- err = libmtd_erase(mtd, args.node_fd, eb);
+ err = mtd_peb_erase(mtd, eb);
if (err) {
if (!args.quiet)
printf("\n");
sys_errmsg("failed to erase eraseblock %d", eb);
- if (errno != EIO)
+ if (err != EIO)
goto out_free;
if (mark_bad(mtd, si, eb))
@@ -495,7 +501,7 @@ static int format(const struct mtd_dev_info *mtd,
printf(", write EC %lld\n", ec);
}
- err = libmtd_write(mtd, args.node_fd, eb, 0, hdr, write_size);
+ err = mtd_peb_write(mtd, hdr, eb, 0, write_size);
if (err) {
if (!args.quiet && !args.verbose)
printf("\n");
@@ -503,16 +509,17 @@ static int format(const struct mtd_dev_info *mtd,
write_size, eb);
if (errno != EIO) {
- if (args.subpage_size != mtd->min_io_size)
+ if (args.subpage_size != mtd->writesize)
normsg("may be sub-page size is incorrect?");
goto out_free;
}
- err = mtd_torture(mtd, args.node_fd, eb);
- if (err) {
- if (mark_bad(mtd, si, eb))
- goto out_free;
- }
+ err = mtd_peb_torture(mtd, eb);
+ if (err < 0 && err != -EIO)
+ goto out_free;
+ if (err == -EIO && consecutive_bad_check(eb))
+ goto out_free;
+
continue;
}
@@ -532,8 +539,7 @@ static int format(const struct mtd_dev_info *mtd,
if (!vtbl)
goto out_free;
- err = ubigen_write_layout_vol(ui, eb1, eb2, ec1, ec2, vtbl,
- args.node_fd);
+ err = ubigen_write_layout_vol(ui, eb1, eb2, ec1, ec2, vtbl, mtd);
free(vtbl);
if (err) {
errmsg("cannot write layout volume");
@@ -551,78 +557,82 @@ out_free:
int do_ubiformat(int argc, char *argv[])
{
- int err, verbose;
- struct mtd_dev_info mtd;
+ int err, verbose, fd, eb_cnt;
+ struct mtd_info *mtd;
struct ubigen_info ui;
struct ubi_scan_info *si;
+ struct mtd_info_user mtd_user;
err = parse_opt(argc, argv);
if (err)
return err;
- err = mtd_get_dev_info(args.node, &mtd);
- if (err) {
- sys_errmsg("cannot get information about \"%s\"", args.node);
- goto out_close_mtd;
+ fd = open(args.node, O_RDWR);
+ if (fd < 0)
+ return sys_errmsg("cannot open \"%s\"", args.node);
+
+ if (ioctl(fd, MEMGETINFO, &mtd_user)) {
+ sys_errmsg("MEMGETINFO ioctl request failed");
+ goto out_close;
}
- if (!is_power_of_2(mtd.min_io_size)) {
+ mtd = mtd_user.mtd;
+
+ if (!is_power_of_2(mtd->writesize)) {
errmsg("min. I/O size is %d, but should be power of 2",
- mtd.min_io_size);
- goto out_close_mtd;
+ mtd->writesize);
+ goto out_close;
}
- if (args.subpage_size && args.subpage_size != mtd.subpage_size) {
- mtd.subpage_size = args.subpage_size;
- args.manual_subpage = 1;
+ if (args.subpage_size) {
+ if (args.subpage_size != mtd->writesize >> mtd->subpage_sft)
+ args.manual_subpage = 1;
+ } else {
+ args.subpage_size = mtd->writesize >> mtd->subpage_sft;
}
if (args.manual_subpage) {
/* Do some sanity check */
- if (args.subpage_size > mtd.min_io_size) {
+ if (args.subpage_size > mtd->writesize) {
errmsg("sub-page cannot be larger than min. I/O unit");
- goto out_close_mtd;
+ goto out_close;
}
- if (mtd.min_io_size % args.subpage_size) {
+ if (mtd->writesize % args.subpage_size) {
errmsg("min. I/O unit size should be multiple of "
"sub-page size");
- goto out_close_mtd;
+ goto out_close;
}
}
- args.node_fd = open(args.node, O_RDWR);
- if (args.node_fd < 0) {
- sys_errmsg("cannot open \"%s\"", args.node);
- goto out_close_mtd;
- }
-
/* Validate VID header offset if it was specified */
if (args.vid_hdr_offs != 0) {
if (args.vid_hdr_offs % 8) {
errmsg("VID header offset has to be multiple of min. I/O unit size");
goto out_close;
}
- if (args.vid_hdr_offs + (int)UBI_VID_HDR_SIZE > mtd.eb_size) {
+ if (args.vid_hdr_offs + (int)UBI_VID_HDR_SIZE > mtd->erasesize) {
errmsg("bad VID header offset");
goto out_close;
}
}
- if (!mtd.writable) {
- errmsg("%s (%s) is a read-only device", mtd.node, args.node);
+ if (!(mtd->flags & MTD_WRITEABLE)) {
+ errmsg("%s is a read-only device", args.node);
goto out_close;
}
/* Make sure this MTD device is not attached to UBI */
/* FIXME! Find a proper way to do this in barebox! */
+ eb_cnt = mtd_div_by_eb(mtd->size, mtd);
+
if (!args.quiet) {
- normsg_cont("%s (%s), size %lld bytes (%s)", mtd.node, mtd.type_str,
- mtd.size, size_human_readable(mtd.size));
- printf(", %d eraseblocks of %d bytes (%s)", mtd.eb_cnt,
- mtd.eb_size, size_human_readable(mtd.eb_size));
- printf(", min. I/O size %d bytes\n", mtd.min_io_size);
+ normsg_cont("%s (%s), size %lld bytes (%s)", args.node, mtd_type_str(mtd),
+ mtd->size, size_human_readable(mtd->size));
+ printf(", %d eraseblocks of %d bytes (%s)", eb_cnt,
+ mtd->erasesize, size_human_readable(mtd->erasesize));
+ printf(", min. I/O size %d bytes\n", mtd->writesize);
}
if (args.quiet)
@@ -631,9 +641,9 @@ int do_ubiformat(int argc, char *argv[])
verbose = 2;
else
verbose = 1;
- err = libscan_ubi_scan(&mtd, args.node_fd, &si, verbose);
+ err = libscan_ubi_scan(mtd, &si, verbose);
if (err) {
- errmsg("failed to scan %s (%s)", mtd.node, args.node);
+ errmsg("failed to scan %s", args.node);
goto out_close;
}
@@ -644,7 +654,7 @@ int do_ubiformat(int argc, char *argv[])
if (si->good_cnt < 2 && (!args.novtbl || args.image)) {
errmsg("too few non-bad eraseblocks (%d) on %s",
- si->good_cnt, mtd.node);
+ si->good_cnt, args.node);
goto out_free;
}
@@ -656,7 +666,7 @@ int do_ubiformat(int argc, char *argv[])
normsg("%d eraseblocks are supposedly empty", si->empty_cnt);
if (si->corrupted_cnt)
normsg("%d corrupted erase counters", si->corrupted_cnt);
- print_bad_eraseblocks(&mtd, si);
+ print_bad_eraseblocks(mtd, si);
}
if (si->alien_cnt) {
@@ -717,7 +727,7 @@ int do_ubiformat(int argc, char *argv[])
if (!args.quiet && args.override_ec)
normsg("use erase counter %lld for all eraseblocks", args.ec);
- ubigen_info_init(&ui, mtd.eb_size, mtd.min_io_size, mtd.subpage_size,
+ ubigen_info_init(&ui, mtd->erasesize, mtd->writesize, args.subpage_size,
args.vid_hdr_offs, args.ubi_ver, args.image_seq);
if (si->vid_hdr_offs != -1 && ui.vid_hdr_offs != si->vid_hdr_offs) {
@@ -735,28 +745,27 @@ int do_ubiformat(int argc, char *argv[])
}
if (args.image) {
- err = flash_image(&mtd, &ui, si);
+ err = flash_image(mtd, &ui, si);
if (err < 0)
goto out_free;
- err = format(&mtd, &ui, si, err, 1);
+ err = format(mtd, &ui, si, err, 1, args.subpage_size);
if (err)
goto out_free;
} else {
- err = format(&mtd, &ui, si, 0, args.novtbl);
+ err = format(mtd, &ui, si, 0, args.novtbl, args.subpage_size);
if (err)
goto out_free;
}
libscan_ubi_scan_free(si);
- close(args.node_fd);
return 0;
out_free:
libscan_ubi_scan_free(si);
out_close:
- close(args.node_fd);
-out_close_mtd:
+ close(fd);
+
return 1;
}
diff --git a/include/mtd/libscan.h b/include/mtd/libscan.h
index bb01482..e925a26 100644
--- a/include/mtd/libscan.h
+++ b/include/mtd/libscan.h
@@ -84,12 +84,11 @@ struct mtd_dev_info;
/**
* ubi_scan - scan an MTD device.
* @mtd: information about the MTD device to scan
- * @fd: MTD device node file descriptor
* @info: the result of the scanning is returned here
* @verbose: verbose mode: %0 - be silent, %1 - output progress information,
* 2 - debugging output mode
*/
-int libscan_ubi_scan(struct mtd_dev_info *mtd, int fd, struct ubi_scan_info **info,
+int libscan_ubi_scan(struct mtd_info *mtd, struct ubi_scan_info **info,
int verbose);
/**
diff --git a/include/mtd/libubigen.h b/include/mtd/libubigen.h
index f05978b..266f393 100644
--- a/include/mtd/libubigen.h
+++ b/include/mtd/libubigen.h
@@ -170,13 +170,13 @@ int ubigen_write_volume(const struct ubigen_info *ui,
* @ec1: erase counter value for @peb1
* @ec2: erase counter value for @peb1
* @vtbl: volume table
- * @fd: output file descriptor seeked to the proper position
+ * @mtd: The mtd device
*
* This function creates the UBI layout volume which contains 2 copies of the
* volume table. Returns zero in case of success and %-1 in case of failure.
*/
int ubigen_write_layout_vol(const struct ubigen_info *ui, int peb1, int peb2,
long long ec1, long long ec2,
- struct ubi_vtbl_record *vtbl, int fd);
+ struct ubi_vtbl_record *vtbl, struct mtd_info *mtd);
#endif /* !__LIBUBIGEN_H__ */
diff --git a/lib/libscan.c b/lib/libscan.c
index 29d1cdb..bf298a7 100644
--- a/lib/libscan.c
+++ b/lib/libscan.c
@@ -26,26 +26,28 @@
#include <linux/mtd/mtd.h>
#include <linux/stat.h>
#include <linux/mtd/mtd-abi.h>
-#include <mtd/libmtd.h>
+#include <mtd/mtd-peb.h>
#include <mtd/libscan.h>
#include <mtd/ubi-user.h>
#include <mtd/utils.h>
#include <mtd/ubi-media.h>
#include <asm-generic/div64.h>
-int libscan_ubi_scan(struct mtd_dev_info *mtd, int fd, struct ubi_scan_info **info,
+int libscan_ubi_scan(struct mtd_info *mtd, struct ubi_scan_info **info,
int verbose)
{
- int eb, v = (verbose == 2), pr = (verbose == 1);
+ int eb, v = (verbose == 2), pr = (verbose == 1), eb_cnt;
struct ubi_scan_info *si;
unsigned long long sum = 0;
+ eb_cnt = mtd_div_by_eb(mtd->size, mtd);
+
si = calloc(1, sizeof(struct ubi_scan_info));
if (!si)
return sys_errmsg("cannot allocate %zd bytes of memory",
sizeof(struct ubi_scan_info));
- si->ec = calloc(mtd->eb_cnt, sizeof(uint32_t));
+ si->ec = calloc(eb_cnt, sizeof(uint32_t));
if (!si->ec) {
sys_errmsg("cannot allocate %zd bytes of memory",
sizeof(struct ubi_scan_info));
@@ -54,8 +56,8 @@ int libscan_ubi_scan(struct mtd_dev_info *mtd, int fd, struct ubi_scan_info **in
si->vid_hdr_offs = si->data_offs = -1;
- verbose(v, "start scanning eraseblocks 0-%d", mtd->eb_cnt);
- for (eb = 0; eb < mtd->eb_cnt; eb++) {
+ verbose(v, "start scanning eraseblocks 0-%d", eb_cnt);
+ for (eb = 0; eb < eb_cnt; eb++) {
int ret;
uint32_t crc;
struct ubi_ec_hdr ech;
@@ -65,10 +67,10 @@ int libscan_ubi_scan(struct mtd_dev_info *mtd, int fd, struct ubi_scan_info **in
normsg_cont("scanning eraseblock %d", eb);
if (pr) {
printf("\r" PROGRAM_NAME ": scanning eraseblock %d -- %2u %% complete ",
- eb, (eb + 1) * 100 / mtd->eb_cnt);
+ eb, (eb + 1) * 100 / eb_cnt);
}
- ret = mtd_is_bad(mtd, fd, eb);
+ ret = mtd_peb_is_bad(mtd, eb);
if (ret == -1)
goto out_ec;
if (ret) {
@@ -79,7 +81,7 @@ int libscan_ubi_scan(struct mtd_dev_info *mtd, int fd, struct ubi_scan_info **in
continue;
}
- ret = libmtd_read(mtd, fd, eb, 0, &ech, sizeof(struct ubi_ec_hdr));
+ ret = mtd_peb_read(mtd, &ech, eb, 0, sizeof(struct ubi_ec_hdr));
if (ret < 0)
goto out_ec;
@@ -121,14 +123,14 @@ int libscan_ubi_scan(struct mtd_dev_info *mtd, int fd, struct ubi_scan_info **in
if (si->vid_hdr_offs == -1) {
si->vid_hdr_offs = be32_to_cpu(ech.vid_hdr_offset);
si->data_offs = be32_to_cpu(ech.data_offset);
- if (si->data_offs % mtd->min_io_size) {
+ if (si->data_offs % mtd->writesize) {
if (pr)
printf("\n");
if (v)
printf(": corrupted because of the below\n");
warnmsg("bad data offset %d at eraseblock %d (n"
"of multiple of min. I/O unit size %d)",
- si->data_offs, eb, mtd->min_io_size);
+ si->data_offs, eb, mtd->writesize);
warnmsg("treat eraseblock %d as corrupted", eb);
si->corrupted_cnt += 1;
si->ec[eb] = EB_CORRUPTED;
@@ -174,7 +176,7 @@ int libscan_ubi_scan(struct mtd_dev_info *mtd, int fd, struct ubi_scan_info **in
if (si->ok_cnt != 0) {
/* Calculate mean erase counter */
- for (eb = 0; eb < mtd->eb_cnt; eb++) {
+ for (eb = 0; eb < eb_cnt; eb++) {
if (si->ec[eb] > EC_MAX)
continue;
sum += si->ec[eb];
@@ -183,7 +185,7 @@ int libscan_ubi_scan(struct mtd_dev_info *mtd, int fd, struct ubi_scan_info **in
si->mean_ec = sum;
}
- si->good_cnt = mtd->eb_cnt - si->bad_cnt;
+ si->good_cnt = eb_cnt - si->bad_cnt;
verbose(v, "finished, mean EC %lld, %d OK, %d corrupted, %d empty, %d "
"alien, bad %d", si->mean_ec, si->ok_cnt, si->corrupted_cnt,
si->empty_cnt, si->alien_cnt, si->bad_cnt);
diff --git a/lib/libubigen.c b/lib/libubigen.c
index 9006329..77ebb05 100644
--- a/lib/libubigen.c
+++ b/lib/libubigen.c
@@ -34,6 +34,7 @@
#include <mtd/utils.h>
#include <mtd/ubi-media.h>
#include <mtd/libubigen.h>
+#include <mtd/mtd-peb.h>
void ubigen_info_init(struct ubigen_info *ui, int peb_size, int min_io_size,
int subpage_size, int vid_hdr_offs, int ubi_ver,
@@ -247,13 +248,12 @@ out_free:
int ubigen_write_layout_vol(const struct ubigen_info *ui, int peb1, int peb2,
long long ec1, long long ec2,
- struct ubi_vtbl_record *vtbl, int fd)
+ struct ubi_vtbl_record *vtbl, struct mtd_info *mtd)
{
int ret;
struct ubigen_vol_info vi;
char *outbuf;
struct ubi_vid_hdr *vid_hdr;
- off_t seek;
vi.bytes = ui->leb_size * UBI_LAYOUT_VOLUME_EBS;
vi.id = UBI_LAYOUT_VOLUME_ID;
@@ -277,29 +277,18 @@ int ubigen_write_layout_vol(const struct ubigen_info *ui, int peb1, int peb2,
memset(outbuf + ui->data_offs + ui->vtbl_size, 0xFF,
ui->peb_size - ui->data_offs - ui->vtbl_size);
- seek = (off_t) peb1 * ui->peb_size;
- if (lseek(fd, seek, SEEK_SET) != seek) {
- sys_errmsg("cannot seek output file");
- goto out_free;
- }
-
ubigen_init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf, ec1);
ubigen_init_vid_hdr(ui, &vi, vid_hdr, 0, NULL, 0);
- ret = write(fd, outbuf, ui->peb_size);
- if (ret != ui->peb_size) {
+ ret = mtd_peb_write(mtd, outbuf, peb1, 0, ui->peb_size);
+ if (ret < 0) {
sys_errmsg("cannot write %d bytes", ui->peb_size);
goto out_free;
}
- seek = (off_t) peb2 * ui->peb_size;
- if (lseek(fd, seek, SEEK_SET) != seek) {
- sys_errmsg("cannot seek output file");
- goto out_free;
- }
ubigen_init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf, ec2);
ubigen_init_vid_hdr(ui, &vi, vid_hdr, 1, NULL, 0);
- ret = write(fd, outbuf, ui->peb_size);
- if (ret != ui->peb_size) {
+ ret = mtd_peb_write(mtd, outbuf, peb2, 0, ui->peb_size);
+ if (ret < 0) {
sys_errmsg("cannot write %d bytes", ui->peb_size);
goto out_free;
}
--
2.7.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 09/16] remove now unused libmtd
2016-03-15 11:15 Introduce mtd-peb API Sascha Hauer
` (7 preceding siblings ...)
2016-03-15 11:15 ` [PATCH 08/16] ubiformat: Use " Sascha Hauer
@ 2016-03-15 11:15 ` Sascha Hauer
2016-03-15 11:15 ` [PATCH 10/16] mtd: ubi: Use mtd_all_ff/mtd_check_pattern Sascha Hauer
` (6 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Sascha Hauer @ 2016-03-15 11:15 UTC (permalink / raw)
To: Barebox List
The only user of libmtd was ubiformat which now uses the mtd-peb API,
so remove the now unused libmtd.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
commands/Kconfig | 1 -
include/mtd/libmtd.h | 149 ---------------------
lib/Kconfig | 3 -
lib/Makefile | 1 -
lib/libmtd.c | 368 ---------------------------------------------------
5 files changed, 522 deletions(-)
delete mode 100644 include/mtd/libmtd.h
delete mode 100644 lib/libmtd.c
diff --git a/commands/Kconfig b/commands/Kconfig
index 9519a44..1724391 100644
--- a/commands/Kconfig
+++ b/commands/Kconfig
@@ -694,7 +694,6 @@ config CMD_UBI
config CMD_UBIFORMAT
tristate
depends on MTD_UBI
- select LIBMTD
select LIBSCAN
select LIBUBIGEN
prompt "ubiformat"
diff --git a/include/mtd/libmtd.h b/include/mtd/libmtd.h
deleted file mode 100644
index 65c390a..0000000
--- a/include/mtd/libmtd.h
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright (C) 2008, 2009 Nokia Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
- * the GNU General Public License for more details.
- * Author: Artem Bityutskiy
- *
- * MTD library.
- */
-
-#ifndef __LIBMTD_H__
-#define __LIBMTD_H__
-
-/* Maximum MTD device name length */
-#define MTD_NAME_MAX 127
-/* Maximum MTD device type string length */
-#define MTD_TYPE_MAX 64
-
-/**
- * struct mtd_dev_info - information about an MTD device.
- * @node: node pointing to device
- * @type: flash type (constants like %MTD_NANDFLASH defined in mtd-abi.h)
- * @type_str: static R/O flash type string
- * @name: device name
- * @size: device size in bytes
- * @eb_cnt: count of eraseblocks
- * @eb_size: eraseblock size
- * @min_io_size: minimum input/output unit size
- * @subpage_size: sub-page size
- * @oob_size: OOB size (zero if the device does not have OOB area)
- * @region_cnt: count of additional erase regions
- * @writable: zero if the device is read-only
- * @bb_allowed: non-zero if the MTD device may have bad eraseblocks
- */
-struct mtd_dev_info
-{
- const char *node;
- int type;
- const char type_str[MTD_TYPE_MAX + 1];
- long long size;
- int eb_cnt;
- int eb_size;
- int min_io_size;
- int subpage_size;
- int oob_size;
- int region_cnt;
- unsigned int writable:1;
- unsigned int bb_allowed:1;
-};
-
-/**
- * mtd_get_dev_info - get information about an MTD device.
- * @desc: MTD library descriptor
- * @node: name of the MTD device node
- * @mtd: the MTD device information is returned here
- *
- * This function gets information about MTD device defined by the @node device
- * node file and saves this information in the @mtd object. Returns %0 in case
- * of success and %-1 in case of failure. If MTD subsystem is not present in the
- * system, or the MTD device does not exist, errno is set to @ENODEV.
- */
-int mtd_get_dev_info(const char *node, struct mtd_dev_info *mtd);
-
-/**
- * libmtd_erase - erase an eraseblock.
- * @desc: MTD library descriptor
- * @mtd: MTD device description object
- * @fd: MTD device node file descriptor
- * @eb: eraseblock to erase
- *
- * This function erases eraseblock @eb of MTD device described by @fd. Returns
- * %0 in case of success and %-1 in case of failure.
- */
-int libmtd_erase(const struct mtd_dev_info *mtd, int fd, int eb);
-
-/**
- * mtd_torture - torture an eraseblock.
- * @desc: MTD library descriptor
- * @mtd: MTD device description object
- * @fd: MTD device node file descriptor
- * @eb: eraseblock to torture
- *
- * This function tortures eraseblock @eb. Returns %0 in case of success and %-1
- * in case of failure.
- */
-int mtd_torture(const struct mtd_dev_info *mtd, int fd, int eb);
-
-/**
- * mtd_is_bad - check if eraseblock is bad.
- * @mtd: MTD device description object
- * @fd: MTD device node file descriptor
- * @eb: eraseblock to check
- *
- * This function checks if eraseblock @eb is bad. Returns %0 if not, %1 if yes,
- * and %-1 in case of failure.
- */
-int mtd_is_bad(const struct mtd_dev_info *mtd, int fd, int eb);
-
-/**
- * mtd_mark_bad - mark an eraseblock as bad.
- * @mtd: MTD device description object
- * @fd: MTD device node file descriptor
- * @eb: eraseblock to mark as bad
- *
- * This function marks eraseblock @eb as bad. Returns %0 in case of success and
- * %-1 in case of failure.
- */
-int mtd_mark_bad(const struct mtd_dev_info *mtd, int fd, int eb);
-
-/**
- * mtd_read - read data from an MTD device.
- * @mtd: MTD device description object
- * @fd: MTD device node file descriptor
- * @eb: eraseblock to read from
- * @offs: offset withing the eraseblock to read from
- * @buf: buffer to read data to
- * @len: how many bytes to read
- *
- * This function reads @len bytes of data from eraseblock @eb and offset @offs
- * of the MTD device defined by @mtd and stores the read data at buffer @buf.
- * Returns %0 in case of success and %-1 in case of failure.
- */
-int libmtd_read(const struct mtd_dev_info *mtd, int fd, int eb, int offs,
- void *buf, int len);
-
-/**
- * mtd_write - write data to an MTD device.
- * @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
- *
- * 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.
- */
-int libmtd_write(const struct mtd_dev_info *mtd, int fd, int eb, int offs,
- void *buf, int len);
-
-#endif /* __LIBMTD_H__ */
diff --git a/lib/Kconfig b/lib/Kconfig
index f051751..d5f99ae 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -52,9 +52,6 @@ config LIBSCAN
config LIBUBIGEN
bool
-config LIBMTD
- bool
-
config STMP_DEVICE
bool
diff --git a/lib/Makefile b/lib/Makefile
index 44ba25b..b6da848 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -44,7 +44,6 @@ obj-$(CONFIG_BITREV) += bitrev.o
obj-$(CONFIG_QSORT) += qsort.o
obj-$(CONFIG_LIBSCAN) += libscan.o
obj-$(CONFIG_LIBUBIGEN) += libubigen.o
-obj-$(CONFIG_LIBMTD) += libmtd.o
obj-y += gui/
obj-$(CONFIG_XYMODEM) += xymodem.o
obj-y += unlink-recursive.o
diff --git a/lib/libmtd.c b/lib/libmtd.c
deleted file mode 100644
index 56672bd..0000000
--- a/lib/libmtd.c
+++ /dev/null
@@ -1,368 +0,0 @@
-/*
- * Copyright (C) 2009 Nokia Corporation
- * Copyright (C) 2012 Wolfram Sang, Pengutronix e.K. <w.sang@pengutronix.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
- * the GNU General Public License for more details.
- *
- * Author: Artem Bityutskiy
- * Author: Wolfram Sang
- *
- * This file is part of the MTD library. Based on pre-2.6.30 kernels support,
- * now adapted to barebox.
- *
- * NOTE: No support for 64 bit sizes yet!
- */
-
-#include <common.h>
-#include <stdlib.h>
-#include <string.h>
-#include <malloc.h>
-#include <errno.h>
-#include <crc.h>
-#include <fs.h>
-#include <fcntl.h>
-#include <ioctl.h>
-#include <linux/stat.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/mtd-abi.h>
-#include <mtd/libmtd.h>
-#include <mtd/utils.h>
-
-#define PROGRAM_NAME "libmtd"
-
-static inline int mtd_ioctl_error(const struct mtd_dev_info *mtd, int eb,
- const char *sreq)
-{
- return sys_errmsg("%s ioctl failed for eraseblock %d (%s)",
- sreq, eb, mtd->node);
-}
-
-static int mtd_valid_erase_block(const struct mtd_dev_info *mtd, int eb)
-{
- if (eb < 0 || eb >= mtd->eb_cnt) {
- errmsg("bad eraseblock number %d, %s has %d eraseblocks",
- eb, mtd->node, mtd->eb_cnt);
- errno = EINVAL;
- return -1;
- }
- return 0;
-}
-
-int libmtd_erase(const struct mtd_dev_info *mtd, int fd, int eb)
-{
- int ret;
- struct erase_info_user ei;
-
- ret = mtd_valid_erase_block(mtd, eb);
- if (ret)
- return ret;
-
- ei.start = (__u64)eb * mtd->eb_size;
- ei.length = mtd->eb_size;
-
- ret = ioctl(fd, MEMERASE, &ei);
- if (ret < 0)
- return mtd_ioctl_error(mtd, eb, "MEMERASE");
- return 0;
-}
-
-/* Patterns to write to a physical eraseblock when torturing it */
-static uint8_t patterns[] = {0xa5, 0x5a, 0x0};
-
-/**
- * check_pattern - check if buffer contains only a certain byte pattern.
- * @buf: buffer to check
- * @patt: the pattern to check
- * @size: buffer size in bytes
- *
- * This function returns %1 in there are only @patt bytes in @buf, and %0 if
- * something else was also found.
- */
-static int check_pattern(const void *buf, uint8_t patt, int size)
-{
- int i;
-
- for (i = 0; i < size; i++)
- if (((const uint8_t *)buf)[i] != patt)
- return 0;
- return 1;
-}
-
-int mtd_torture(const struct mtd_dev_info *mtd, int fd, int eb)
-{
- int err, i, patt_count;
- void *buf;
-
- normsg("run torture test for PEB %d", eb);
- patt_count = ARRAY_SIZE(patterns);
-
- buf = xmalloc(mtd->eb_size);
-
- for (i = 0; i < patt_count; i++) {
- err = libmtd_erase(mtd, fd, eb);
- if (err)
- goto out;
-
- /* Make sure the PEB contains only 0xFF bytes */
- err = libmtd_read(mtd, fd, eb, 0, buf, mtd->eb_size);
- if (err)
- goto out;
-
- err = check_pattern(buf, 0xFF, mtd->eb_size);
- if (err == 0) {
- errmsg("erased PEB %d, but a non-0xFF byte found", eb);
- errno = EIO;
- goto out;
- }
-
- /* Write a pattern and check it */
- memset(buf, patterns[i], mtd->eb_size);
- err = libmtd_write(mtd, fd, eb, 0, buf, mtd->eb_size);
- if (err)
- goto out;
-
- memset(buf, ~patterns[i], mtd->eb_size);
- err = libmtd_read(mtd, fd, eb, 0, buf, mtd->eb_size);
- if (err)
- goto out;
-
- err = check_pattern(buf, patterns[i], mtd->eb_size);
- if (err == 0) {
- errmsg("pattern %x checking failed for PEB %d",
- patterns[i], eb);
- errno = EIO;
- goto out;
- }
- }
-
- err = 0;
- normsg("PEB %d passed torture test, do not mark it a bad", eb);
-
-out:
- free(buf);
- return -1;
-}
-
-int mtd_is_bad(const struct mtd_dev_info *mtd, int fd, int eb)
-{
- int ret;
- loff_t seek;
-
- ret = mtd_valid_erase_block(mtd, eb);
- if (ret)
- return ret;
-
- if (!mtd->bb_allowed)
- return 0;
-
- seek = (loff_t)eb * mtd->eb_size;
- ret = ioctl(fd, MEMGETBADBLOCK, &seek);
- if (ret == -1)
- return mtd_ioctl_error(mtd, eb, "MEMGETBADBLOCK");
- return ret;
-}
-
-int mtd_mark_bad(const struct mtd_dev_info *mtd, int fd, int eb)
-{
- int ret;
- loff_t seek;
-
- if (!mtd->bb_allowed) {
- errno = EINVAL;
- return -1;
- }
-
- ret = mtd_valid_erase_block(mtd, eb);
- if (ret)
- return ret;
-
- seek = (loff_t)eb * mtd->eb_size;
- ret = ioctl(fd, MEMSETBADBLOCK, &seek);
- if (ret == -1)
- return mtd_ioctl_error(mtd, eb, "MEMSETBADBLOCK");
- return 0;
-}
-
-int libmtd_read(const struct mtd_dev_info *mtd, int fd, int eb, int offs,
- void *buf, int len)
-{
- int ret, rd = 0;
- loff_t seek;
-
- ret = mtd_valid_erase_block(mtd, eb);
- if (ret)
- return ret;
-
- if (offs < 0 || offs + len > mtd->eb_size) {
- errmsg("bad offset %d or length %d, %s eraseblock size is %d",
- offs, len, mtd->node, mtd->eb_size);
- errno = EINVAL;
- return -1;
- }
-
- /* Seek to the beginning of the eraseblock */
- seek = (loff_t)eb * mtd->eb_size + offs;
- if (lseek(fd, seek, SEEK_SET) != seek)
- return sys_errmsg("cannot seek %s to offset %llu",
- mtd->node, (unsigned long long)seek);
-
- while (rd < len) {
- ret = read(fd, buf, len);
- if (ret < 0)
- return sys_errmsg("cannot read %d bytes from %s (eraseblock %d, offset %d)",
- len, mtd->node, eb, offs);
- rd += ret;
- }
-
- return 0;
-}
-
-int libmtd_write(const struct mtd_dev_info *mtd, int fd, int eb, int offs,
- void *buf, int len)
-{
- int ret;
- loff_t seek;
-
- ret = mtd_valid_erase_block(mtd, eb);
- if (ret)
- return ret;
-
- if (offs < 0 || offs + len > mtd->eb_size) {
- errmsg("bad offset %d or length %d, %s eraseblock size is %d",
- offs, len, mtd->node, mtd->eb_size);
- errno = EINVAL;
- return -1;
- }
- if (offs % mtd->subpage_size) {
- errmsg("write offset %d is not aligned to %s min. I/O size %d",
- offs, mtd->node, mtd->subpage_size);
- errno = EINVAL;
- return -1;
- }
- if (len % mtd->subpage_size) {
- errmsg("write length %d is not aligned to %s min. I/O size %d",
- len, mtd->node, mtd->subpage_size);
- errno = EINVAL;
- return -1;
- }
-
- /* Seek to the beginning of the eraseblock */
- seek = (loff_t)eb * mtd->eb_size + offs;
- if (lseek(fd, seek, SEEK_SET) != seek)
- return sys_errmsg("cannot seek %s to offset %llu",
- mtd->node, (unsigned long long)seek);
-
- ret = write(fd, buf, len);
- if (ret != len)
- return sys_errmsg("cannot write %d bytes to %s (eraseblock %d, offset %d)",
- len, mtd->node, eb, offs);
-
- return 0;
-}
-
-/**
- * mtd_get_dev_info - fill the mtd_dev_info structure
- * @node: name of the MTD device node
- * @mtd: the MTD device information is returned here
- */
-int mtd_get_dev_info(const char *node, struct mtd_dev_info *mtd)
-{
- struct mtd_info_user ui;
- int fd, ret;
- loff_t offs = 0;
-
- memset(mtd, '\0', sizeof(struct mtd_dev_info));
-
- mtd->node = node;
-
- fd = open(node, O_RDWR);
- if (fd < 0)
- return sys_errmsg("cannot open \"%s\"", node);
-
- if (ioctl(fd, MEMGETINFO, &ui)) {
- sys_errmsg("MEMGETINFO ioctl request failed");
- goto out_close;
- }
-
- ret = ioctl(fd, MEMGETBADBLOCK, &offs);
- if (ret == -1) {
- if (errno != EOPNOTSUPP) {
- sys_errmsg("MEMGETBADBLOCK ioctl failed");
- goto out_close;
- }
- errno = 0;
- mtd->bb_allowed = 0;
- } else
- mtd->bb_allowed = 1;
-
- mtd->type = ui.type;
- mtd->size = ui.size;
- mtd->eb_size = ui.erasesize;
- mtd->min_io_size = ui.writesize;
- mtd->oob_size = ui.oobsize;
- mtd->subpage_size = ui.subpagesize;
-
- if (mtd->min_io_size <= 0) {
- errmsg("%s has insane min. I/O unit size %d",
- node, mtd->min_io_size);
- goto out_close;
- }
- if (mtd->eb_size <= 0 || mtd->eb_size < mtd->min_io_size) {
- errmsg("%s has insane eraseblock size %d",
- node, mtd->eb_size);
- goto out_close;
- }
- if (mtd->size <= 0 || mtd->size < mtd->eb_size) {
- errmsg("%s has insane size %lld",
- node, mtd->size);
- goto out_close;
- }
-
- mtd->eb_cnt = mtd_user_div_by_eb(ui.size, &ui);
-
- switch(mtd->type) {
- case MTD_ABSENT:
- errmsg("%s (%s) is removable and is not present",
- mtd->node, node);
- goto out_close;
- case MTD_RAM:
- strcpy((char *)mtd->type_str, "ram");
- break;
- case MTD_ROM:
- strcpy((char *)mtd->type_str, "rom");
- break;
- case MTD_NORFLASH:
- strcpy((char *)mtd->type_str, "nor");
- break;
- case MTD_NANDFLASH:
- strcpy((char *)mtd->type_str, "nand");
- break;
- case MTD_DATAFLASH:
- strcpy((char *)mtd->type_str, "dataflash");
- break;
- case MTD_UBIVOLUME:
- strcpy((char *)mtd->type_str, "ubi");
- break;
- default:
- goto out_close;
- }
-
- if (ui.flags & MTD_WRITEABLE)
- mtd->writable = 1;
-
- close(fd);
-
- return 0;
-
-out_close:
- close(fd);
- return -1;
-}
--
2.7.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 10/16] mtd: ubi: Use mtd_all_ff/mtd_check_pattern
2016-03-15 11:15 Introduce mtd-peb API Sascha Hauer
` (8 preceding siblings ...)
2016-03-15 11:15 ` [PATCH 09/16] remove now unused libmtd Sascha Hauer
@ 2016-03-15 11:15 ` Sascha Hauer
2016-03-15 11:15 ` [PATCH 11/16] mtd: ubi: Use mtd_peb_check_all_ff Sascha Hauer
` (5 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Sascha Hauer @ 2016-03-15 11:15 UTC (permalink / raw)
To: Barebox List
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/mtd/ubi/attach.c | 2 +-
drivers/mtd/ubi/io.c | 10 +++++-----
drivers/mtd/ubi/misc.c | 19 -------------------
drivers/mtd/ubi/ubi.h | 1 -
4 files changed, 6 insertions(+), 26 deletions(-)
diff --git a/drivers/mtd/ubi/attach.c b/drivers/mtd/ubi/attach.c
index d6fe43b..88370f4 100644
--- a/drivers/mtd/ubi/attach.c
+++ b/drivers/mtd/ubi/attach.c
@@ -772,7 +772,7 @@ static int check_corruption(struct ubi_device *ubi, struct ubi_vid_hdr *vid_hdr,
if (err)
goto out_unlock;
- if (ubi_check_pattern(ubi->peb_buf, 0xFF, ubi->leb_size))
+ if (mtd_buf_all_ff(ubi->peb_buf, ubi->leb_size))
goto out_unlock;
ubi_err("PEB %d contains corrupted VID header, and the data does not contain all 0xFF",
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index e55dfc5..801c0eb 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -405,7 +405,7 @@ static int torture_peb(struct ubi_device *ubi, int pnum)
if (err)
goto out;
- err = ubi_check_pattern(ubi->peb_buf, 0xFF, ubi->peb_size);
+ err = mtd_buf_all_ff(ubi->peb_buf, ubi->peb_size);
if (err == 0) {
ubi_err("erased PEB %d, but a non-0xFF byte found",
pnum);
@@ -424,7 +424,7 @@ static int torture_peb(struct ubi_device *ubi, int pnum)
if (err)
goto out;
- err = ubi_check_pattern(ubi->peb_buf, patterns[i],
+ err = mtd_buf_check_pattern(ubi->peb_buf, patterns[i],
ubi->peb_size);
if (err == 0) {
ubi_err("pattern %x checking failed for PEB %d",
@@ -740,7 +740,7 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
* 0xFF. If yes, this physical eraseblock is assumed to be
* empty.
*/
- if (ubi_check_pattern(ec_hdr, 0xFF, UBI_EC_HDR_SIZE)) {
+ if (mtd_buf_all_ff(ec_hdr, UBI_EC_HDR_SIZE)) {
/* The physical eraseblock is supposedly empty */
if (verbose)
ubi_warn("no EC header found at PEB %d, only 0xFF bytes",
@@ -996,7 +996,7 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
if (mtd_is_eccerr(read_err))
return UBI_IO_BAD_HDR_EBADMSG;
- if (ubi_check_pattern(vid_hdr, 0xFF, UBI_VID_HDR_SIZE)) {
+ if (mtd_buf_all_ff(vid_hdr, UBI_VID_HDR_SIZE)) {
if (verbose)
ubi_warn("no VID header found at PEB %d, only 0xFF bytes",
pnum);
@@ -1382,7 +1382,7 @@ int ubi_self_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len)
goto error;
}
- err = ubi_check_pattern(buf, 0xFF, len);
+ err = mtd_buf_all_ff(buf, len);
if (err == 0) {
ubi_err("flash region at PEB %d:%d, length %d does not contain all 0xFF bytes",
pnum, offset, len);
diff --git a/drivers/mtd/ubi/misc.c b/drivers/mtd/ubi/misc.c
index b5c6efe..9633466 100644
--- a/drivers/mtd/ubi/misc.c
+++ b/drivers/mtd/ubi/misc.c
@@ -128,22 +128,3 @@ void ubi_calculate_reserved(struct ubi_device *ubi)
ubi->bad_peb_count, ubi->bad_peb_limit);
}
}
-
-/**
- * ubi_check_pattern - check if buffer contains only a certain byte pattern.
- * @buf: buffer to check
- * @patt: the pattern to check
- * @size: buffer size in bytes
- *
- * This function returns %1 in there are only @patt bytes in @buf, and %0 if
- * something else was also found.
- */
-int ubi_check_pattern(const void *buf, uint8_t patt, int size)
-{
- int i;
-
- for (i = 0; i < size; i++)
- if (((const uint8_t *)buf)[i] != patt)
- return 0;
- return 1;
-}
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index 61ae738..577b35d 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -757,7 +757,6 @@ int ubi_calc_data_len(const struct ubi_device *ubi, const void *buf,
int ubi_check_volume(struct ubi_device *ubi, int vol_id);
void ubi_update_reserved(struct ubi_device *ubi);
void ubi_calculate_reserved(struct ubi_device *ubi);
-int ubi_check_pattern(const void *buf, uint8_t patt, int size);
/* eba.c */
int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol,
--
2.7.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 11/16] mtd: ubi: Use mtd_peb_check_all_ff
2016-03-15 11:15 Introduce mtd-peb API Sascha Hauer
` (9 preceding siblings ...)
2016-03-15 11:15 ` [PATCH 10/16] mtd: ubi: Use mtd_all_ff/mtd_check_pattern Sascha Hauer
@ 2016-03-15 11:15 ` Sascha Hauer
2016-03-15 11:15 ` [PATCH 12/16] mtd: ubi: Use mtd_peb_torture Sascha Hauer
` (4 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Sascha Hauer @ 2016-03-15 11:15 UTC (permalink / raw)
To: Barebox List
Use mtd-peb function for checking for a all-ff buffer.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/mtd/ubi/io.c | 39 ++-------------------------------------
1 file changed, 2 insertions(+), 37 deletions(-)
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index 801c0eb..4495996 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -83,6 +83,7 @@
*/
#include <linux/err.h>
+#include <mtd/mtd-peb.h>
#include "ubi.h"
static int self_check_not_bad(const struct ubi_device *ubi, int pnum);
@@ -1361,44 +1362,8 @@ out_free:
*/
int ubi_self_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len)
{
- size_t read;
- int err;
- void *buf;
- loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
-
if (!ubi_dbg_chk_io(ubi))
return 0;
- buf = kmalloc(len, GFP_KERNEL);
- if (!buf) {
- ubi_err("cannot allocate memory to check for 0xFFs");
- return 0;
- }
-
- err = mtd_read(ubi->mtd, addr, len, &read, buf);
- if (err && !mtd_is_bitflip(err)) {
- ubi_err("error %d while reading %d bytes from PEB %d:%d, read %zd bytes",
- err, len, pnum, offset, read);
- goto error;
- }
-
- err = mtd_buf_all_ff(buf, len);
- if (err == 0) {
- ubi_err("flash region at PEB %d:%d, length %d does not contain all 0xFF bytes",
- pnum, offset, len);
- goto fail;
- }
-
- vfree(buf);
- return 0;
-
-fail:
- ubi_err("self-check failed for PEB %d", pnum);
- ubi_msg("hex dump of the %d-%d region", offset, offset + len);
- print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf, len, 1);
- err = -EINVAL;
-error:
- dump_stack();
- vfree(buf);
- return err;
+ return mtd_peb_check_all_ff(ubi->mtd, pnum, offset, len, 1);
}
--
2.7.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 12/16] mtd: ubi: Use mtd_peb_torture
2016-03-15 11:15 Introduce mtd-peb API Sascha Hauer
` (10 preceding siblings ...)
2016-03-15 11:15 ` [PATCH 11/16] mtd: ubi: Use mtd_peb_check_all_ff Sascha Hauer
@ 2016-03-15 11:15 ` Sascha Hauer
2016-03-15 11:15 ` [PATCH 13/16] mtd: ubi: Use mtd_peb_read Sascha Hauer
` (3 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Sascha Hauer @ 2016-03-15 11:15 UTC (permalink / raw)
To: Barebox List
The mtd-peb API provides a torture test derived from the UBI torture
test. Use it. Since the mtd-peb variant of the torture test will also
mark a block as bad when the test fails this also makes a separate
ubi_io_mark_bad unnecessary.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/mtd/ubi/io.c | 115 +++-----------------------------------------------
drivers/mtd/ubi/ubi.h | 1 -
drivers/mtd/ubi/wl.c | 5 ---
3 files changed, 5 insertions(+), 116 deletions(-)
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index 4495996..4031253 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -376,82 +376,6 @@ retry:
return 0;
}
-/* Patterns to write to a physical eraseblock when torturing it */
-static uint8_t patterns[] = {0xa5, 0x5a, 0x0};
-
-/**
- * torture_peb - test a supposedly bad physical eraseblock.
- * @ubi: UBI device description object
- * @pnum: the physical eraseblock number to test
- *
- * This function returns %-EIO if the physical eraseblock did not pass the
- * test, a positive number of erase operations done if the test was
- * successfully passed, and other negative error codes in case of other errors.
- */
-static int torture_peb(struct ubi_device *ubi, int pnum)
-{
- int err, i, patt_count;
-
- ubi_msg("run torture test for PEB %d", pnum);
- patt_count = ARRAY_SIZE(patterns);
- ubi_assert(patt_count > 0);
-
- for (i = 0; i < patt_count; i++) {
- err = do_sync_erase(ubi, pnum);
- if (err)
- goto out;
-
- /* Make sure the PEB contains only 0xFF bytes */
- err = ubi_io_read(ubi, ubi->peb_buf, pnum, 0, ubi->peb_size);
- if (err)
- goto out;
-
- err = mtd_buf_all_ff(ubi->peb_buf, ubi->peb_size);
- if (err == 0) {
- ubi_err("erased PEB %d, but a non-0xFF byte found",
- pnum);
- err = -EIO;
- goto out;
- }
-
- /* Write a pattern and check it */
- memset(ubi->peb_buf, patterns[i], ubi->peb_size);
- err = ubi_io_write(ubi, ubi->peb_buf, pnum, 0, ubi->peb_size);
- if (err)
- goto out;
-
- memset(ubi->peb_buf, ~patterns[i], ubi->peb_size);
- err = ubi_io_read(ubi, ubi->peb_buf, pnum, 0, ubi->peb_size);
- if (err)
- goto out;
-
- err = mtd_buf_check_pattern(ubi->peb_buf, patterns[i],
- ubi->peb_size);
- if (err == 0) {
- ubi_err("pattern %x checking failed for PEB %d",
- patterns[i], pnum);
- err = -EIO;
- goto out;
- }
- }
-
- err = patt_count;
- ubi_msg("PEB %d passed torture test, do not mark it as bad", pnum);
-
-out:
- if (err == UBI_IO_BITFLIPS || mtd_is_eccerr(err)) {
- /*
- * If a bit-flip or data integrity error was detected, the test
- * has not passed because it happened on a freshly erased
- * physical eraseblock which means something is wrong with it.
- */
- ubi_err("read problems on freshly erased PEB %d, must be bad",
- pnum);
- err = -EIO;
- }
- return err;
-}
-
/**
* nor_erase_prepare - prepare a NOR flash PEB for erasure.
* @ubi: UBI device description object
@@ -564,15 +488,15 @@ int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int torture)
}
if (torture) {
- ret = torture_peb(ubi, pnum);
+ ret = mtd_peb_torture(ubi->mtd, pnum);
if (ret < 0)
return ret;
+ } else {
+ err = do_sync_erase(ubi, pnum);
+ if (err)
+ return err;
}
- err = do_sync_erase(ubi, pnum);
- if (err)
- return err;
-
return ret + 1;
}
@@ -606,35 +530,6 @@ int ubi_io_is_bad(const struct ubi_device *ubi, int pnum)
}
/**
- * ubi_io_mark_bad - mark a physical eraseblock as bad.
- * @ubi: UBI device description object
- * @pnum: the physical eraseblock number to mark
- *
- * This function returns zero in case of success and a negative error code in
- * case of failure.
- */
-int ubi_io_mark_bad(const struct ubi_device *ubi, int pnum)
-{
- int err;
- struct mtd_info *mtd = ubi->mtd;
-
- ubi_assert(pnum >= 0 && pnum < ubi->peb_count);
-
- if (ubi->ro_mode) {
- ubi_err("read-only mode");
- return -EROFS;
- }
-
- if (!ubi->bad_allowed)
- return 0;
-
- err = mtd_block_markbad(mtd, (loff_t)pnum * ubi->peb_size);
- if (err)
- ubi_err("cannot mark PEB %d bad, error %d", pnum, err);
- return err;
-}
-
-/**
* validate_ec_hdr - validate an erase counter header.
* @ubi: UBI device description object
* @ec_hdr: the erase counter header to check
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index 577b35d..03a36d2 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -799,7 +799,6 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
int len);
int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int torture);
int ubi_io_is_bad(const struct ubi_device *ubi, int pnum);
-int ubi_io_mark_bad(const struct ubi_device *ubi, int pnum);
int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
struct ubi_ec_hdr *ec_hdr, int verbose);
int ubi_io_write_ec_hdr(struct ubi_device *ubi, int pnum,
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index 4c20e90..cb2f9d7 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -1421,11 +1421,6 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
available_consumed = 1;
}
- ubi_msg("mark PEB %d as bad", pnum);
- err = ubi_io_mark_bad(ubi, pnum);
- if (err)
- goto out_ro;
-
if (ubi->beb_rsvd_pebs > 0) {
if (available_consumed) {
/*
--
2.7.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 13/16] mtd: ubi: Use mtd_peb_read
2016-03-15 11:15 Introduce mtd-peb API Sascha Hauer
` (11 preceding siblings ...)
2016-03-15 11:15 ` [PATCH 12/16] mtd: ubi: Use mtd_peb_torture Sascha Hauer
@ 2016-03-15 11:15 ` Sascha Hauer
2016-03-15 11:15 ` [PATCH 14/16] mtd: ubi: Use mtd_peb_write Sascha Hauer
` (2 subsequent siblings)
15 siblings, 0 replies; 17+ messages in thread
From: Sascha Hauer @ 2016-03-15 11:15 UTC (permalink / raw)
To: Barebox List
mtd_peb_read provides the same functionality as ubi_io_read. Use
it.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/mtd/ubi/debug.h | 13 --------
drivers/mtd/ubi/io.c | 89 +++----------------------------------------------
2 files changed, 5 insertions(+), 97 deletions(-)
diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h
index ebf961b..f177e6b 100644
--- a/drivers/mtd/ubi/debug.h
+++ b/drivers/mtd/ubi/debug.h
@@ -73,19 +73,6 @@ static inline int ubi_dbg_is_bgt_disabled(const struct ubi_device *ubi)
}
/**
- * ubi_dbg_is_bitflip - if it is time to emulate a bit-flip.
- * @ubi: UBI device description object
- *
- * Returns non-zero if a bit-flip should be emulated, otherwise returns zero.
- */
-static inline int ubi_dbg_is_bitflip(const struct ubi_device *ubi)
-{
- if (ubi->dbg.emulate_bitflips)
- return !(random32() % 200);
- return 0;
-}
-
-/**
* ubi_dbg_is_write_failure - if it is time to emulate a write failure.
* @ubi: UBI device description object
*
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index 4031253..4fa8e5d 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -121,91 +121,12 @@ static int self_check_write(struct ubi_device *ubi, const void *buf, int pnum,
int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset,
int len)
{
- int err, retries = 0;
- size_t read;
- loff_t addr;
-
- dbg_io("read %d bytes from PEB %d:%d", len, pnum, offset);
-
- ubi_assert(pnum >= 0 && pnum < ubi->peb_count);
- ubi_assert(offset >= 0 && offset + len <= ubi->peb_size);
- ubi_assert(len > 0);
-
- err = self_check_not_bad(ubi, pnum);
- if (err)
- return err;
-
- /*
- * Deliberately corrupt the buffer to improve robustness. Indeed, if we
- * do not do this, the following may happen:
- * 1. The buffer contains data from previous operation, e.g., read from
- * another PEB previously. The data looks like expected, e.g., if we
- * just do not read anything and return - the caller would not
- * notice this. E.g., if we are reading a VID header, the buffer may
- * contain a valid VID header from another PEB.
- * 2. The driver is buggy and returns us success or -EBADMSG or
- * -EUCLEAN, but it does not actually put any data to the buffer.
- *
- * This may confuse UBI or upper layers - they may think the buffer
- * contains valid data while in fact it is just old data. This is
- * especially possible because UBI (and UBIFS) relies on CRC, and
- * treats data as correct even in case of ECC errors if the CRC is
- * correct.
- *
- * Try to prevent this situation by changing the first byte of the
- * buffer.
- */
- *((uint8_t *)buf) ^= 0xFF;
-
- addr = (loff_t)pnum * ubi->peb_size + offset;
-retry:
- err = mtd_read(ubi->mtd, addr, len, &read, buf);
- if (err) {
- const char *errstr = mtd_is_eccerr(err) ? " (ECC error)" : "";
-
- if (mtd_is_bitflip(err)) {
- /*
- * -EUCLEAN is reported if there was a bit-flip which
- * was corrected, so this is harmless.
- *
- * We do not report about it here unless debugging is
- * enabled. A corresponding message will be printed
- * later, when it is has been scrubbed.
- */
- ubi_msg("fixable bit-flip detected at PEB %d", pnum);
- ubi_assert(len == read);
- return UBI_IO_BITFLIPS;
- }
+ int ret;
- if (retries++ < UBI_IO_RETRIES) {
- ubi_warn("error %d%s while reading %d bytes from PEB %d:%d, read only %zd bytes, retry",
- err, errstr, len, pnum, offset, read);
- goto retry;
- }
-
- ubi_err("error %d%s while reading %d bytes from PEB %d:%d, read %zd bytes",
- err, errstr, len, pnum, offset, read);
- dump_stack();
-
- /*
- * The driver should never return -EBADMSG if it failed to read
- * all the requested data. But some buggy drivers might do
- * this, so we change it to -EIO.
- */
- if (read != len && mtd_is_eccerr(err)) {
- ubi_assert(0);
- err = -EIO;
- }
- } else {
- ubi_assert(len == read);
-
- if (ubi_dbg_is_bitflip(ubi)) {
- dbg_gen("bit-flip (emulated)");
- err = UBI_IO_BITFLIPS;
- }
- }
-
- return err;
+ ret = mtd_peb_read(ubi->mtd, buf, pnum, offset, len);
+ if (mtd_is_bitflip(ret))
+ return UBI_IO_BITFLIPS;
+ return ret;
}
/**
--
2.7.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 14/16] mtd: ubi: Use mtd_peb_write
2016-03-15 11:15 Introduce mtd-peb API Sascha Hauer
` (12 preceding siblings ...)
2016-03-15 11:15 ` [PATCH 13/16] mtd: ubi: Use mtd_peb_read Sascha Hauer
@ 2016-03-15 11:15 ` Sascha Hauer
2016-03-15 11:15 ` [PATCH 15/16] mtd: ubi: Use mtd_peb_erase Sascha Hauer
2016-03-15 11:15 ` [PATCH 16/16] mtd: ubi: Make debug options configurable Sascha Hauer
15 siblings, 0 replies; 17+ messages in thread
From: Sascha Hauer @ 2016-03-15 11:15 UTC (permalink / raw)
To: Barebox List
mtd_peb_write provides the same functionality as ubi_io_write. Use it.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/mtd/ubi/debug.h | 14 ------
drivers/mtd/ubi/io.c | 113 +-----------------------------------------------
2 files changed, 1 insertion(+), 126 deletions(-)
diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h
index f177e6b..9d0542c 100644
--- a/drivers/mtd/ubi/debug.h
+++ b/drivers/mtd/ubi/debug.h
@@ -73,20 +73,6 @@ static inline int ubi_dbg_is_bgt_disabled(const struct ubi_device *ubi)
}
/**
- * ubi_dbg_is_write_failure - if it is time to emulate a write failure.
- * @ubi: UBI device description object
- *
- * Returns non-zero if a write failure should be emulated, otherwise returns
- * zero.
- */
-static inline int ubi_dbg_is_write_failure(const struct ubi_device *ubi)
-{
- if (ubi->dbg.emulate_io_failures)
- return !(random32() % 500);
- return 0;
-}
-
-/**
* ubi_dbg_is_erase_failure - if its time to emulate an erase failure.
* @ubi: UBI device description object
*
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index 4fa8e5d..ed0cd1c 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -93,8 +93,6 @@ static int self_check_ec_hdr(const struct ubi_device *ubi, int pnum,
static int self_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum);
static int self_check_vid_hdr(const struct ubi_device *ubi, int pnum,
const struct ubi_vid_hdr *vid_hdr);
-static int self_check_write(struct ubi_device *ubi, const void *buf, int pnum,
- int offset, int len);
/**
* ubi_io_read - read data from a physical eraseblock.
@@ -150,8 +148,6 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
int len)
{
int err;
- size_t written;
- loff_t addr;
dbg_io("write %d bytes to PEB %d:%d", len, pnum, offset);
@@ -165,15 +161,6 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
return -EROFS;
}
- err = self_check_not_bad(ubi, pnum);
- if (err)
- return err;
-
- /* The area we are writing to has to contain all 0xFF bytes */
- err = ubi_self_check_all_ff(ubi, pnum, offset, len);
- if (err)
- return err;
-
if (offset >= ubi->leb_start) {
/*
* We write to the data area of the physical eraseblock. Make
@@ -187,39 +174,7 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
return err;
}
- if (ubi_dbg_is_write_failure(ubi)) {
- ubi_err("cannot write %d bytes to PEB %d:%d (emulated)",
- len, pnum, offset);
- dump_stack();
- return -EIO;
- }
-
- addr = (loff_t)pnum * ubi->peb_size + offset;
- err = mtd_write(ubi->mtd, addr, len, &written, buf);
- if (err) {
- ubi_err("error %d while writing %d bytes to PEB %d:%d, written %zd bytes",
- err, len, pnum, offset, written);
- dump_stack();
- ubi_dump_flash(ubi, pnum, offset, len);
- } else
- ubi_assert(written == len);
-
- if (!err) {
- err = self_check_write(ubi, buf, pnum, offset, len);
- if (err)
- return err;
-
- /*
- * Since we always write sequentially, the rest of the PEB has
- * to contain only 0xFF bytes.
- */
- offset += len;
- len = ubi->peb_size - offset;
- if (len)
- err = ubi_self_check_all_ff(ubi, pnum, offset, len);
- }
-
- return err;
+ return mtd_peb_write(ubi->mtd, buf, pnum, offset, len);
}
/**
@@ -1100,72 +1055,6 @@ exit:
}
/**
- * self_check_write - make sure write succeeded.
- * @ubi: UBI device description object
- * @buf: buffer with data which were written
- * @pnum: physical eraseblock number the data were written to
- * @offset: offset within the physical eraseblock the data were written to
- * @len: how many bytes were written
- *
- * This functions reads data which were recently written and compares it with
- * the original data buffer - the data have to match. Returns zero if the data
- * match and a negative error code if not or in case of failure.
- */
-static int self_check_write(struct ubi_device *ubi, const void *buf, int pnum,
- int offset, int len)
-{
- int err, i;
- size_t read;
- void *buf1;
- loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
-
- if (!ubi_dbg_chk_io(ubi))
- return 0;
-
- buf1 = kmalloc(len, GFP_KERNEL);
- if (!buf1) {
- ubi_err("cannot allocate memory to check writes");
- return 0;
- }
-
- err = mtd_read(ubi->mtd, addr, len, &read, buf1);
- if (err && !mtd_is_bitflip(err))
- goto out_free;
-
- for (i = 0; i < len; i++) {
- uint8_t c = ((uint8_t *)buf)[i];
- uint8_t c1 = ((uint8_t *)buf1)[i];
- int dump_len;
-
- if (c == c1)
- continue;
-
- ubi_err("self-check failed for PEB %d:%d, len %d",
- pnum, offset, len);
- ubi_msg("data differ at position %d", i);
- dump_len = max_t(int, 128, len - i);
- ubi_msg("hex dump of the original buffer from %d to %d",
- i, i + dump_len);
- print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
- buf + i, dump_len, 1);
- ubi_msg("hex dump of the read buffer from %d to %d",
- i, i + dump_len);
- print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
- buf1 + i, dump_len, 1);
- dump_stack();
- err = -EINVAL;
- goto out_free;
- }
-
- vfree(buf1);
- return 0;
-
-out_free:
- vfree(buf1);
- return err;
-}
-
-/**
* ubi_self_check_all_ff - check that a region of flash is empty.
* @ubi: UBI device description object
* @pnum: the physical eraseblock number to check
--
2.7.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 15/16] mtd: ubi: Use mtd_peb_erase
2016-03-15 11:15 Introduce mtd-peb API Sascha Hauer
` (13 preceding siblings ...)
2016-03-15 11:15 ` [PATCH 14/16] mtd: ubi: Use mtd_peb_write Sascha Hauer
@ 2016-03-15 11:15 ` Sascha Hauer
2016-03-15 11:15 ` [PATCH 16/16] mtd: ubi: Make debug options configurable Sascha Hauer
15 siblings, 0 replies; 17+ messages in thread
From: Sascha Hauer @ 2016-03-15 11:15 UTC (permalink / raw)
To: Barebox List
mtd_peb_erase provides the same functionality as do_sync_erase. Use it.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/mtd/ubi/debug.h | 14 -------------
drivers/mtd/ubi/io.c | 55 +------------------------------------------------
2 files changed, 1 insertion(+), 68 deletions(-)
diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h
index 9d0542c..c1b41b4 100644
--- a/drivers/mtd/ubi/debug.h
+++ b/drivers/mtd/ubi/debug.h
@@ -72,20 +72,6 @@ static inline int ubi_dbg_is_bgt_disabled(const struct ubi_device *ubi)
return ubi->dbg.disable_bgt;
}
-/**
- * ubi_dbg_is_erase_failure - if its time to emulate an erase failure.
- * @ubi: UBI device description object
- *
- * Returns non-zero if an erase failure should be emulated, otherwise returns
- * zero.
- */
-static inline int ubi_dbg_is_erase_failure(const struct ubi_device *ubi)
-{
- if (ubi->dbg.emulate_io_failures)
- return !(random32() % 400);
- return 0;
-}
-
static inline int ubi_dbg_chk_io(const struct ubi_device *ubi)
{
return ubi->dbg.chk_io;
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index ed0cd1c..b3cb4f2 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -178,17 +178,6 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
}
/**
- * erase_callback - MTD erasure call-back.
- * @ei: MTD erase information object.
- *
- * Note, even though MTD erase interface is asynchronous, all the current
- * implementations are synchronous anyway.
- */
-static void erase_callback(struct erase_info *ei)
-{
-}
-
-/**
* do_sync_erase - synchronously erase a physical eraseblock.
* @ubi: UBI device description object
* @pnum: the physical eraseblock number to erase
@@ -199,9 +188,6 @@ static void erase_callback(struct erase_info *ei)
*/
static int do_sync_erase(struct ubi_device *ubi, int pnum)
{
- int err, retries = 0;
- struct erase_info ei;
-
dbg_io("erase PEB %d", pnum);
ubi_assert(pnum >= 0 && pnum < ubi->peb_count);
@@ -210,46 +196,7 @@ static int do_sync_erase(struct ubi_device *ubi, int pnum)
return -EROFS;
}
-retry:
- memset(&ei, 0, sizeof(struct erase_info));
-
- ei.mtd = ubi->mtd;
- ei.addr = (loff_t)pnum * ubi->peb_size;
- ei.len = ubi->peb_size;
- ei.callback = erase_callback;
-
- err = mtd_erase(ubi->mtd, &ei);
- if (err) {
- if (retries++ < UBI_IO_RETRIES) {
- ubi_warn("error %d while erasing PEB %d, retry",
- err, pnum);
- goto retry;
- }
- ubi_err("cannot erase PEB %d, error %d", pnum, err);
- dump_stack();
- return err;
- }
-
- if (ei.state == MTD_ERASE_FAILED) {
- if (retries++ < UBI_IO_RETRIES) {
- ubi_warn("error while erasing PEB %d, retry", pnum);
- goto retry;
- }
- ubi_err("cannot erase PEB %d", pnum);
- dump_stack();
- return -EIO;
- }
-
- err = ubi_self_check_all_ff(ubi, pnum, 0, ubi->peb_size);
- if (err)
- return err;
-
- if (ubi_dbg_is_erase_failure(ubi)) {
- ubi_err("cannot erase PEB %d (emulated)", pnum);
- return -EIO;
- }
-
- return 0;
+ return mtd_peb_erase(ubi->mtd, pnum);
}
/**
--
2.7.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 16/16] mtd: ubi: Make debug options configurable
2016-03-15 11:15 Introduce mtd-peb API Sascha Hauer
` (14 preceding siblings ...)
2016-03-15 11:15 ` [PATCH 15/16] mtd: ubi: Use mtd_peb_erase Sascha Hauer
@ 2016-03-15 11:15 ` Sascha Hauer
15 siblings, 0 replies; 17+ messages in thread
From: Sascha Hauer @ 2016-03-15 11:15 UTC (permalink / raw)
To: Barebox List
This makes the UBI debug options configurable. This make the debug
options actually available to the user and also allows the compiler
to optimize away the debug code when the options are disabled.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/mtd/ubi/Kconfig | 13 +++++++++++++
drivers/mtd/ubi/debug.h | 10 ++++++++--
2 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/drivers/mtd/ubi/Kconfig b/drivers/mtd/ubi/Kconfig
index ccd547d..4c49793 100644
--- a/drivers/mtd/ubi/Kconfig
+++ b/drivers/mtd/ubi/Kconfig
@@ -77,4 +77,17 @@ config MTD_UBI_FASTMAP
If in doubt, say "N".
+comment "UBI debugging options"
+
+config MTD_UBI_CHECK_IO
+ bool "Check IO operations"
+ help
+ When enabled UBI will check if erased blocks are really erased and if areas
+ written to are empty before writing.
+
+config MTD_UBI_GENERAL_EXTRA_CHECKS
+ bool "general extra checks"
+ help
+ This enables some general extra checks in UBI
+
endif # MTD_UBI
diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h
index c1b41b4..511e454 100644
--- a/drivers/mtd/ubi/debug.h
+++ b/drivers/mtd/ubi/debug.h
@@ -74,11 +74,17 @@ static inline int ubi_dbg_is_bgt_disabled(const struct ubi_device *ubi)
static inline int ubi_dbg_chk_io(const struct ubi_device *ubi)
{
- return ubi->dbg.chk_io;
+ if (IS_ENABLED(CONFIG_MTD_UBI_CHECK_IO))
+ return 1;
+ else
+ return 0;
}
static inline int ubi_dbg_chk_gen(const struct ubi_device *ubi)
{
- return ubi->dbg.chk_gen;
+ if (IS_ENABLED(CONFIG_MTD_UBI_GENERAL_EXTRA_CHECKS))
+ return 1;
+ else
+ return 0;
}
#endif /* !__UBI_DEBUG_H__ */
--
2.7.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 17+ messages in thread