linux-mtd.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/5] mtd: nand/UBI: add power-cut emulation
@ 2015-09-25 15:09 Boris Brezillon
  2015-09-25 15:09 ` [PATCH 1/5] mtd: nand: add basic stuff to support " Boris Brezillon
                   ` (4 more replies)
  0 siblings, 5 replies; 9+ messages in thread
From: Boris Brezillon @ 2015-09-25 15:09 UTC (permalink / raw)
  To: David Woodhouse, Brian Norris, linux-mtd, Artem Bityutskiy,
	Richard Weinberger
  Cc: Andrea Scian, Bean Huo 霍斌斌 (beanhuo),
	Karl Zhang 张双锣 (karlzhang), Iwo Mergler,
	Jeff Lauruhn (jlauruhn), Stefan Roese, linux-kernel,
	Boris Brezillon

Hello,

This series aims at adding a power-cut emulation layer at the nandsim
level.
The final goal is to support MLC NAND emulation in nandsim in order to
validate the work done in the NAND, UBI and UBIFS layers to reliably
support those chips.

Even though the UBI layer already provides a power-cut emulation
infrastructure, I decided to add one at the nandsim layer for the
following reasons:
- IMO it is cleaner to isolate MLC NAND emulation in the NAND layer
- emulating unstable bits in UBI is not so easy: the unstable bits
  issue happens when a program or erase operation is interrupted (by a
  power-cut) while it is almost finished. In this case the next read
  operation will succeed (return the expected data), but not the following
  ones.
  Emulating this problem requires knowing which block/page was being
  accessed when the power-cut occurred, and if we want to validate that
  UBI (not UBIFS) is robust to such errors, we have to reattach the mtd
  partition to the UBI layer, and by doing that we loose the information
  of which page/block was being programmed/erased when the power-cut
  occurred.
  By implementing the power-cut emulation at the nandsim level, we can
  easily detach/attach the emulated device, and check still keep those
  information.
- emulating paired pages in UBI is a bit easier but still requires some
  knowledge about the pairing scheme (which differs from one chip to
  another), and I'm not sure yet how this will be exposed by the MTD/NAND
  layers.

This being said, I might be wrong in my assumptions, so feel free to
comment on that decision.

Regarding the code itself, this series adds a simple power-cut emulation
layer, and modifies the intermediate layers (NAND and UBI) to forward
emulated power-cut errors and let the UBIFS layer switch into read-only
mode.

Paired pages and unstable bits emulation is not part of the series, but
can be added on top of those changes by tweaking the actions taken in
nandsim when a power-cut is emulated.

Also, I'm not sure about the method used to inform NAND core when a
power-cut was emulated: I'm currently adding a virtual NAND status flag,
but adding a new field in the nand_chip struct might be a better approach.
This would also allow us to compile out code sections that are only useful
when doing NAND emulation.

Best Regards,

Boris

Boris Brezillon (5):
  mtd: nand: add basic stuff to support power-cut emulation
  mtd: nand: return -EROFS in case of power-cut emulation
  UBI: switch the UBI device in read-only mode when mtd returns -EROFS
  mtd: nand: nandsim: implement ->get_status()
  mtd: nand: nandsim: add support for power-cut emulation

 drivers/mtd/nand/nand_base.c |  34 ++++++--
 drivers/mtd/nand/nandsim.c   | 182 ++++++++++++++++++++++++++++++++++++++++---
 drivers/mtd/ubi/io.c         |   4 +-
 include/linux/mtd/nand.h     |   4 +
 4 files changed, 207 insertions(+), 17 deletions(-)

-- 
1.9.1

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 1/5] mtd: nand: add basic stuff to support power-cut emulation
  2015-09-25 15:09 [PATCH 0/5] mtd: nand/UBI: add power-cut emulation Boris Brezillon
@ 2015-09-25 15:09 ` Boris Brezillon
  2015-09-28  5:41   ` kbuild test robot
  2015-09-25 15:09 ` [PATCH 2/5] mtd: nand: return -EROFS in case of " Boris Brezillon
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 9+ messages in thread
From: Boris Brezillon @ 2015-09-25 15:09 UTC (permalink / raw)
  To: David Woodhouse, Brian Norris, linux-mtd, Artem Bityutskiy,
	Richard Weinberger
  Cc: Andrea Scian, Bean Huo 霍斌斌 (beanhuo),
	Karl Zhang 张双锣 (karlzhang), Iwo Mergler,
	Jeff Lauruhn (jlauruhn), Stefan Roese, linux-kernel,
	Boris Brezillon

Add a new status flag to support power-cut emulation. Since real NAND
status is limited to 8bits, we can safely use higher bits for something
else. The NAND_STATUS_POWER_CUT is assigned bit 30 to avoid integer
overflow (not sure this is necessary).

The NAND status is currently retrieved using ->read_byte() after sending
a NAND_CMD_STATUS command, which prevents the nandsim (or any other
implementation that wants to support power-cut emulation) to return a
value with the NAND_STATUS_POWER_CUT flag set.
Add a ->get_status() method returning an int, and provide a default
implementation.

Also note that ->get_status() could be used for other cases than power-cut
emulation. For example, some NAND controllers are able to retrieve the
NAND status by their own after launching a specific command, and this
status is then stored in a specific register, thus preventing the extra
->cmdfunc() + ->read_byte() calls.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 drivers/mtd/nand/nand_base.c | 17 ++++++++++++++---
 include/linux/mtd/nand.h     |  4 ++++
 2 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 37c0d9d..a621814 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -478,8 +478,7 @@ static int nand_check_wp(struct mtd_info *mtd)
 		return 0;
 
 	/* Check the WP bit */
-	chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
-	return (chip->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1;
+	return (chip->get_status(mtd) & NAND_STATUS_WP) ? 0 : 1;
 }
 
 /**
@@ -880,6 +879,15 @@ static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip,
 	}
 }
 
+static int nand_get_status(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+
+	chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
+
+	return (int)chip->read_byte(mtd);
+}
+
 /**
  * nand_wait - [DEFAULT] wait until the command is done
  * @mtd: MTD device structure
@@ -922,7 +930,7 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
 	}
 	led_trigger_event(nand_led_trigger, LED_OFF);
 
-	status = (int)chip->read_byte(mtd);
+	status = chip->get_status(mtd);
 	/* This can happen if in case of timeout or buggy dev_ready */
 	WARN_ON(!(status & NAND_STATUS_READY));
 	return status;
@@ -3106,6 +3114,9 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)
 	if (chip->cmdfunc == NULL)
 		chip->cmdfunc = nand_command;
 
+	if (!chip->get_status)
+		chip->get_status = nand_get_status;
+
 	/* check, if a user supplied wait function given */
 	if (chip->waitfunc == NULL)
 		chip->waitfunc = nand_wait;
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index c4d8e30..075d7b8 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -107,6 +107,9 @@ extern int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
 #define NAND_STATUS_READY	0x40
 #define NAND_STATUS_WP		0x80
 
+/* Status bits reserved for NAND emulation */
+#define NAND_STATUS_POWER_CUT	0x40000000
+
 /*
  * Constants for ECC_MODES
  */
@@ -661,6 +664,7 @@ struct nand_chip {
 	int (*init_size)(struct mtd_info *mtd, struct nand_chip *this,
 			u8 *id_data);
 	int (*dev_ready)(struct mtd_info *mtd);
+	int (*get_status)(struct mtd_info *mtd);
 	void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column,
 			int page_addr);
 	int(*waitfunc)(struct mtd_info *mtd, struct nand_chip *this);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 2/5] mtd: nand: return -EROFS in case of power-cut emulation
  2015-09-25 15:09 [PATCH 0/5] mtd: nand/UBI: add power-cut emulation Boris Brezillon
  2015-09-25 15:09 ` [PATCH 1/5] mtd: nand: add basic stuff to support " Boris Brezillon
@ 2015-09-25 15:09 ` Boris Brezillon
  2015-09-25 15:09 ` [PATCH 3/5] UBI: switch the UBI device in read-only mode when mtd returns -EROFS Boris Brezillon
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 9+ messages in thread
From: Boris Brezillon @ 2015-09-25 15:09 UTC (permalink / raw)
  To: David Woodhouse, Brian Norris, linux-mtd, Artem Bityutskiy,
	Richard Weinberger
  Cc: Andrea Scian, Bean Huo 霍斌斌 (beanhuo),
	Karl Zhang 张双锣 (karlzhang), Iwo Mergler,
	Jeff Lauruhn (jlauruhn), Stefan Roese, linux-kernel,
	Boris Brezillon

Now that we are able to emulate power-cuts, we should differentiate the
power-cut emulation and input/output error cases to let the MTD user
decide what it should do.
EROFS was chosen to mimic what's done in UBI when a power-cut emulation
occurs.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 drivers/mtd/nand/nand_base.c | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index a621814..223aabdb 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1951,6 +1951,9 @@ static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
 
 	status = chip->waitfunc(mtd, chip);
 
+	if (unlikely(status & NAND_STATUS_POWER_CUT))
+		return -EROFS;
+
 	return status & NAND_STATUS_FAIL ? -EIO : 0;
 }
 
@@ -2009,6 +2012,8 @@ static int nand_write_oob_syndrome(struct mtd_info *mtd,
 
 	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
 	status = chip->waitfunc(mtd, chip);
+	if (unlikely(status & NAND_STATUS_POWER_CUT))
+		return -EROFS;
 
 	return status & NAND_STATUS_FAIL ? -EIO : 0;
 }
@@ -2442,6 +2447,9 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
 			status = chip->errstat(mtd, chip, FL_WRITING, status,
 					       page);
 
+		if (unlikely(status & NAND_STATUS_POWER_CUT))
+			return -EROFS;
+
 		if (status & NAND_STATUS_FAIL)
 			return -EIO;
 	} else {
@@ -2868,7 +2876,7 @@ static int nand_erase(struct mtd_info *mtd, struct erase_info *instr)
 int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
 		    int allowbbt)
 {
-	int page, status, pages_per_block, ret, chipnr;
+	int page, status = 0, pages_per_block, ret, chipnr;
 	struct nand_chip *chip = mtd->priv;
 	loff_t len;
 
@@ -2958,7 +2966,12 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
 
 erase_exit:
 
-	ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
+	if (instr->state == MTD_ERASE_DONE)
+		ret = 0;
+	else if (unlikely(status & NAND_STATUS_POWER_CUT))
+		ret = -EROFS;
+	else
+		ret = -EIO;
 
 	/* Deselect and wake up anyone waiting on the device */
 	chip->select_chip(mtd, -1);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 3/5] UBI: switch the UBI device in read-only mode when mtd returns -EROFS
  2015-09-25 15:09 [PATCH 0/5] mtd: nand/UBI: add power-cut emulation Boris Brezillon
  2015-09-25 15:09 ` [PATCH 1/5] mtd: nand: add basic stuff to support " Boris Brezillon
  2015-09-25 15:09 ` [PATCH 2/5] mtd: nand: return -EROFS in case of " Boris Brezillon
@ 2015-09-25 15:09 ` Boris Brezillon
  2015-09-25 17:34   ` Richard Weinberger
  2015-09-25 15:09 ` [PATCH 4/5] mtd: nand: nandsim: implement ->get_status() Boris Brezillon
  2015-09-25 15:09 ` [PATCH 5/5] mtd: nand: nandsim: add support for power-cut emulation Boris Brezillon
  4 siblings, 1 reply; 9+ messages in thread
From: Boris Brezillon @ 2015-09-25 15:09 UTC (permalink / raw)
  To: David Woodhouse, Brian Norris, linux-mtd, Artem Bityutskiy,
	Richard Weinberger
  Cc: Andrea Scian, Bean Huo 霍斌斌 (beanhuo),
	Karl Zhang 张双锣 (karlzhang), Iwo Mergler,
	Jeff Lauruhn (jlauruhn), Stefan Roese, linux-kernel,
	Boris Brezillon

The NAND layer is now able to forward power-cut emulation errors from
a NAND driver to the MTD user.
Check for this kind of errors in UBI and switch the UBI device in read-only
mode if such an error occurs.
The error will also be forwarded to the UBI user requesting the operation
if any, thus allowing UBIFS to act accordingly.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 drivers/mtd/ubi/io.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index 5bbd1f0..c5ebef7 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -303,6 +303,8 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
 		len = ubi->peb_size - offset;
 		if (len)
 			err = ubi_self_check_all_ff(ubi, pnum, offset, len);
+	} else if (err == -EROFS) {
+		ubi_ro_mode(ubi);
 	}
 
 	return err;
@@ -355,7 +357,7 @@ retry:
 
 	err = mtd_erase(ubi->mtd, &ei);
 	if (err) {
-		if (retries++ < UBI_IO_RETRIES) {
+		if (err != -EROFS && retries++ < UBI_IO_RETRIES) {
 			ubi_warn(ubi, "error %d while erasing PEB %d, retry",
 				 err, pnum);
 			yield();
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 4/5] mtd: nand: nandsim: implement ->get_status()
  2015-09-25 15:09 [PATCH 0/5] mtd: nand/UBI: add power-cut emulation Boris Brezillon
                   ` (2 preceding siblings ...)
  2015-09-25 15:09 ` [PATCH 3/5] UBI: switch the UBI device in read-only mode when mtd returns -EROFS Boris Brezillon
@ 2015-09-25 15:09 ` Boris Brezillon
  2015-09-25 15:09 ` [PATCH 5/5] mtd: nand: nandsim: add support for power-cut emulation Boris Brezillon
  4 siblings, 0 replies; 9+ messages in thread
From: Boris Brezillon @ 2015-09-25 15:09 UTC (permalink / raw)
  To: David Woodhouse, Brian Norris, linux-mtd, Artem Bityutskiy,
	Richard Weinberger
  Cc: Andrea Scian, Bean Huo 霍斌斌 (beanhuo),
	Karl Zhang 张双锣 (karlzhang), Iwo Mergler,
	Jeff Lauruhn (jlauruhn), Stefan Roese, linux-kernel,
	Boris Brezillon

We need to implement a specific ->get_status() function to support
power-cut emulation.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 drivers/mtd/nand/nandsim.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index b16d70a..efd8763 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -347,7 +347,7 @@ struct nandsim {
 	/* NAND flash internal registers */
 	struct {
 		unsigned command; /* the command register */
-		u_char   status;  /* the status register */
+		int      status;  /* the status register */
 		uint     row;     /* the page number */
 		uint     column;  /* the offset within page */
 		uint     count;   /* internal counter */
@@ -2221,6 +2221,13 @@ static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
 	return;
 }
 
+static int ns_nand_get_status(struct mtd_info *mtd)
+{
+	struct nandsim *ns = ((struct nand_chip *)mtd->priv)->priv;
+
+	return ns->regs.status;
+}
+
 /*
  * Module initialization function
  */
@@ -2256,6 +2263,7 @@ static int __init ns_init_module(void)
 	chip->write_buf  = ns_nand_write_buf;
 	chip->read_buf   = ns_nand_read_buf;
 	chip->read_word  = ns_nand_read_word;
+	chip->get_status = ns_nand_get_status;
 	chip->ecc.mode   = NAND_ECC_SOFT;
 	/* The NAND_SKIP_BBTSCAN option is necessary for 'overridesize' */
 	/* and 'badblocks' parameters to work */
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 5/5] mtd: nand: nandsim: add support for power-cut emulation
  2015-09-25 15:09 [PATCH 0/5] mtd: nand/UBI: add power-cut emulation Boris Brezillon
                   ` (3 preceding siblings ...)
  2015-09-25 15:09 ` [PATCH 4/5] mtd: nand: nandsim: implement ->get_status() Boris Brezillon
@ 2015-09-25 15:09 ` Boris Brezillon
  4 siblings, 0 replies; 9+ messages in thread
From: Boris Brezillon @ 2015-09-25 15:09 UTC (permalink / raw)
  To: David Woodhouse, Brian Norris, linux-mtd, Artem Bityutskiy,
	Richard Weinberger
  Cc: Andrea Scian, Bean Huo 霍斌斌 (beanhuo),
	Karl Zhang 张双锣 (karlzhang), Iwo Mergler,
	Jeff Lauruhn (jlauruhn), Stefan Roese, linux-kernel,
	Boris Brezillon

Add support for power-cut emulation on program and erase operations.

This power-cut emulation is configurable through the nandsim/powercut file
exposed in debugfs and can be triggered on erase or program operations.
The user can also specify a specific block and/or page (relative to a
block) at which he wants the power-cut to occur.

Here are some configuration examples:

disabled => the power-cut emulation is disabled
on-erase => power-cut emulation is active and triggered on all erase
            operations
on-erase:12 => power-cut emulation is active and triggered each time block
               12 is accessed
on-program => power-cut emulation is active and triggered each time a page
              is programmed
on-program::5 => power-cut emulation is active and triggered each time page
                 5 of any block is programmed
on-program:12:5 => power-cut emulation is active and triggered each time
                    page 5 of block 12 is programmed

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 drivers/mtd/nand/nandsim.c | 172 ++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 162 insertions(+), 10 deletions(-)

diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index efd8763..2f3f674 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -289,6 +289,7 @@ MODULE_PARM_DESC(bch,		 "Enable BCH ecc and set how many bits should "
 struct nandsim_debug_info {
 	struct dentry *dfs_root;
 	struct dentry *dfs_wear_report;
+	struct dentry *dfs_powercut;
 };
 
 /*
@@ -299,6 +300,24 @@ union ns_mem {
 	uint16_t *word;  /* for 16-bit word access */
 };
 
+enum ns_powercut_status {
+	NS_POWER_CUT_DISABLED,
+	NS_POWER_CUT_ON_ERASE,
+	NS_POWER_CUT_ON_PROGRAM,
+};
+
+struct ns_powercut {
+	enum ns_powercut_status status;
+	int block;
+	int page;
+};
+
+static struct ns_powercut powercut_info = {
+	.status = NS_POWER_CUT_DISABLED,
+	.block = -1,
+	.page = -1,
+};
+
 /*
  * The structure which describes all the internal simulator data.
  */
@@ -369,6 +388,7 @@ struct nandsim {
 	void *file_buf;
 	struct page *held_pages[NS_MAX_HELD_PAGES];
 	int held_cnt;
+	bool powercut;
 
 	struct nandsim_debug_info dbg;
 };
@@ -514,6 +534,78 @@ static const struct file_operations dfs_fops = {
 	.release	= single_release,
 };
 
+static ssize_t read_file_powercut(struct file *file, char __user *user_buf,
+				  size_t count, loff_t *ppos)
+{
+	char buf[32];
+	int size = 0;
+
+	switch (powercut_info.status) {
+	case NS_POWER_CUT_DISABLED:
+		size = snprintf(buf, sizeof(buf), "disabled\n");
+		break;
+	case NS_POWER_CUT_ON_ERASE:
+		size = snprintf(buf, sizeof(buf), "on-erase:%d\n",
+				powercut_info.block);
+		break;
+	case NS_POWER_CUT_ON_PROGRAM:
+		size = snprintf(buf, sizeof(buf), "on-program:%d:%d\n",
+				powercut_info.block, powercut_info.page);
+		break;
+	default:
+		break;
+	}
+
+	return simple_read_from_buffer(user_buf, size, ppos, buf, size);
+}
+
+static ssize_t write_file_powercut(struct file *file,
+				   const char __user *user_buf,
+				   size_t count, loff_t *ppos)
+{
+	char buf[32];
+	size_t buf_size;
+	char *ptr = buf;
+	long block = -1, page = -1;
+	int ret;
+
+	buf_size = min(count, (sizeof(buf) - 1));
+	if (copy_from_user(buf, user_buf, buf_size))
+		return -EFAULT;
+
+	buf[buf_size] = '\0';
+
+	if (!strncmp(buf, "disabled", sizeof("disabled") - 1)) {
+		powercut_info.status = NS_POWER_CUT_DISABLED;
+	} else if (!strncmp(buf, "on-erase", sizeof("on-erase") - 1)) {
+		strsep(&ptr, ":");
+		if (ptr)
+			ret = kstrtol(ptr, 0, &block);
+		powercut_info.status = NS_POWER_CUT_ON_ERASE;
+	} else if (!strncmp(buf, "on-program", sizeof("on-program") - 1)) {
+		strsep(&ptr, ":");
+		if (ptr) {
+			ret = kstrtol(ptr, 0, &block);
+			strsep(&ptr, ":");
+			if (ptr)
+				ret = kstrtol(ptr, 0, &page);
+		}
+		powercut_info.status = NS_POWER_CUT_ON_PROGRAM;
+	}
+
+	powercut_info.block = block;
+	powercut_info.page = page;
+
+	return count;
+}
+
+static const struct file_operations powercut_fops = {
+	.read =		read_file_powercut,
+	.write =	write_file_powercut,
+	.open =		simple_open,
+	.llseek =	default_llseek,
+};
+
 /**
  * nandsim_debugfs_create - initialize debugfs
  * @dev: nandsim device description object
@@ -546,6 +638,12 @@ static int nandsim_debugfs_create(struct nandsim *dev)
 		goto out_remove;
 	dbg->dfs_wear_report = dent;
 
+	dent = debugfs_create_file("powercut", S_IWUSR | S_IRUSR,
+				   dbg->dfs_root, dev, &powercut_fops);
+	if (IS_ERR_OR_NULL(dent))
+		goto out_remove;
+	dbg->dfs_powercut = dent;
+
 	return 0;
 
 out_remove:
@@ -1206,6 +1304,10 @@ static inline void switch_to_ready_state(struct nandsim *ns, u_char status)
 	ns->regs.row    = 0;
 	ns->regs.column = 0;
 	ns->regs.status = status;
+	if (ns->powercut) {
+		ns->powercut = false;
+		ns->regs.status |= NAND_STATUS_POWER_CUT;
+	}
 }
 
 /*
@@ -1509,29 +1611,60 @@ static void read_page(struct nandsim *ns, int num)
 /*
  * Erase all pages in the specified sector.
  */
-static void erase_sector(struct nandsim *ns)
+static int erase_sector(struct nandsim *ns)
 {
 	union ns_mem *mypage;
 	int i;
 
+	if (powercut_info.status == NS_POWER_CUT_ON_ERASE) {
+		long block = ns->regs.row / ns->geom.pgsec;
+
+		if (powercut_info.block < 0 ||
+		    powercut_info.block == block)
+			ns->powercut = true;
+	}
+
 	if (ns->cfile) {
-		for (i = 0; i < ns->geom.pgsec; i++)
-			if (__test_and_clear_bit(ns->regs.row + i,
-						 ns->pages_written)) {
-				NS_DBG("erase_sector: freeing page %d\n", ns->regs.row + i);
+		for (i = 0; i < ns->geom.pgsec; i++) {
+			if (ns->powercut) {
+				loff_t pos = (loff_t)(ns->regs.row + i) *
+					     ns->geom.pgszoob;
+
+				/*
+				 * Corrupt all pages of the block if a
+				 * power-cut occurs in the middle of a
+				 * program operation.
+				 */
+				prandom_bytes(ns->file_buf, ns->geom.pgszoob);
+				write_file(ns, ns->cfile, ns->file_buf,
+					   ns->geom.pgszoob, pos);
+				set_bit(ns->regs.row + i, ns->pages_written);
+				NS_DBG("erase_sector (power-cut emulation): corrupting page %d\n",
+				       ns->regs.row + i);
+			} else if (__test_and_clear_bit(ns->regs.row + i,
+							ns->pages_written)) {
+				NS_DBG("erase_sector: freeing page %d\n",
+				       ns->regs.row + i);
 			}
-		return;
+		}
+
+		return ns->powercut ? -1 : 0;
 	}
 
 	mypage = NS_GET_PAGE(ns);
 	for (i = 0; i < ns->geom.pgsec; i++) {
-		if (mypage->byte != NULL) {
+		if (ns->powercut) {
+			if (mypage->byte)
+				prandom_bytes(mypage->byte, ns->geom.pgszoob);
+		} else if (mypage->byte != NULL) {
 			NS_DBG("erase_sector: freeing page %d\n", ns->regs.row+i);
 			kmem_cache_free(ns->nand_pages_slab, mypage->byte);
 			mypage->byte = NULL;
 		}
 		mypage++;
 	}
+
+	return ns->powercut ? -1 : 0;
 }
 
 /*
@@ -1543,6 +1676,24 @@ static int prog_page(struct nandsim *ns, int num)
 	union ns_mem *mypage;
 	u_char *pg_off;
 
+	if (powercut_info.status == NS_POWER_CUT_ON_PROGRAM) {
+		long block = ns->regs.row / ns->geom.pgsec;
+		long page = ns->regs.row % ns->geom.pgsec;
+
+		if (powercut_info.block < 0 ||
+		    powercut_info.block == block) {
+			if (powercut_info.page < 0 ||
+			    powercut_info.page == page) {
+				/*
+				 * Corrupt the page if a power-cut occurs in
+				 * the middle of a program operation.
+				 */
+				prandom_bytes(ns->buf.byte, ns->geom.pgszoob);
+				ns->powercut = true;
+			}
+		}
+	}
+
 	if (ns->cfile) {
 		loff_t off;
 		ssize_t tx;
@@ -1579,7 +1730,7 @@ static int prog_page(struct nandsim *ns, int num)
 				return -1;
 			}
 		}
-		return 0;
+		return ns->powercut ? -1 : 0;
 	}
 
 	mypage = NS_GET_PAGE(ns);
@@ -1603,7 +1754,7 @@ static int prog_page(struct nandsim *ns, int num)
 	for (i = 0; i < num; i++)
 		pg_off[i] &= ns->buf.byte[i];
 
-	return 0;
+	return ns->powercut ? -1 : 0;
 }
 
 /*
@@ -1681,7 +1832,8 @@ static int do_state_action(struct nandsim *ns, uint32_t action)
 				ns->regs.row, NS_RAW_OFFSET(ns));
 		NS_LOG("erase sector %u\n", erase_block_no);
 
-		erase_sector(ns);
+		if (erase_sector(ns) == -1)
+			return -1;
 
 		NS_MDELAY(erase_delay);
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH 3/5] UBI: switch the UBI device in read-only mode when mtd returns -EROFS
  2015-09-25 15:09 ` [PATCH 3/5] UBI: switch the UBI device in read-only mode when mtd returns -EROFS Boris Brezillon
@ 2015-09-25 17:34   ` Richard Weinberger
  2015-09-26  8:40     ` Boris Brezillon
  0 siblings, 1 reply; 9+ messages in thread
From: Richard Weinberger @ 2015-09-25 17:34 UTC (permalink / raw)
  To: Boris Brezillon, David Woodhouse, Brian Norris, linux-mtd,
	Artem Bityutskiy
  Cc: Andrea Scian, Bean Huo 霍斌斌 (beanhuo),
	Karl Zhang 张双锣 (karlzhang), Iwo Mergler,
	Jeff Lauruhn (jlauruhn), Stefan Roese, linux-kernel

Am 25.09.2015 um 17:09 schrieb Boris Brezillon:
> The NAND layer is now able to forward power-cut emulation errors from
> a NAND driver to the MTD user.
> Check for this kind of errors in UBI and switch the UBI device in read-only
> mode if such an error occurs.
> The error will also be forwarded to the UBI user requesting the operation
> if any, thus allowing UBIFS to act accordingly.
> 
> Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
> ---
>  drivers/mtd/ubi/io.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
> index 5bbd1f0..c5ebef7 100644
> --- a/drivers/mtd/ubi/io.c
> +++ b/drivers/mtd/ubi/io.c
> @@ -303,6 +303,8 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
>  		len = ubi->peb_size - offset;
>  		if (len)
>  			err = ubi_self_check_all_ff(ubi, pnum, offset, len);
> +	} else if (err == -EROFS) {
> +		ubi_ro_mode(ubi);
>  	}
>  
>  	return err;
> @@ -355,7 +357,7 @@ retry:
>  
>  	err = mtd_erase(ubi->mtd, &ei);
>  	if (err) {
> -		if (retries++ < UBI_IO_RETRIES) {
> +		if (err != -EROFS && retries++ < UBI_IO_RETRIES) {

Looks good! :)
One small nit, can you please add a comment above both lines that the EROFS checks are
here because of emulators.

Thanks,
//richard

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 3/5] UBI: switch the UBI device in read-only mode when mtd returns -EROFS
  2015-09-25 17:34   ` Richard Weinberger
@ 2015-09-26  8:40     ` Boris Brezillon
  0 siblings, 0 replies; 9+ messages in thread
From: Boris Brezillon @ 2015-09-26  8:40 UTC (permalink / raw)
  To: Richard Weinberger
  Cc: David Woodhouse, Brian Norris, linux-mtd, Artem Bityutskiy,
	Andrea Scian, Bean Huo 霍斌斌 (beanhuo),
	Karl Zhang 张双锣 (karlzhang), Iwo Mergler,
	Jeff Lauruhn (jlauruhn), Stefan Roese, linux-kernel

Hi Richard,

On Fri, 25 Sep 2015 19:34:42 +0200
Richard Weinberger <richard@nod.at> wrote:

> Am 25.09.2015 um 17:09 schrieb Boris Brezillon:
> > The NAND layer is now able to forward power-cut emulation errors from
> > a NAND driver to the MTD user.
> > Check for this kind of errors in UBI and switch the UBI device in read-only
> > mode if such an error occurs.
> > The error will also be forwarded to the UBI user requesting the operation
> > if any, thus allowing UBIFS to act accordingly.
> > 
> > Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
> > ---
> >  drivers/mtd/ubi/io.c | 4 +++-
> >  1 file changed, 3 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
> > index 5bbd1f0..c5ebef7 100644
> > --- a/drivers/mtd/ubi/io.c
> > +++ b/drivers/mtd/ubi/io.c
> > @@ -303,6 +303,8 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
> >  		len = ubi->peb_size - offset;
> >  		if (len)
> >  			err = ubi_self_check_all_ff(ubi, pnum, offset, len);
> > +	} else if (err == -EROFS) {
> > +		ubi_ro_mode(ubi);
> >  	}
> >  
> >  	return err;
> > @@ -355,7 +357,7 @@ retry:
> >  
> >  	err = mtd_erase(ubi->mtd, &ei);
> >  	if (err) {
> > -		if (retries++ < UBI_IO_RETRIES) {
> > +		if (err != -EROFS && retries++ < UBI_IO_RETRIES) {
> 
> Looks good! :)
> One small nit, can you please add a comment above both lines that the EROFS checks are
> here because of emulators.

Sure, I'll add a comment.

Thanks,

Boris

-- 
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/5] mtd: nand: add basic stuff to support power-cut emulation
  2015-09-25 15:09 ` [PATCH 1/5] mtd: nand: add basic stuff to support " Boris Brezillon
@ 2015-09-28  5:41   ` kbuild test robot
  0 siblings, 0 replies; 9+ messages in thread
From: kbuild test robot @ 2015-09-28  5:41 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: kbuild-all, David Woodhouse, Brian Norris, linux-mtd,
	Artem Bityutskiy, Richard Weinberger, Andrea Scian,
	Bean Huo 霍斌斌 (beanhuo),
	Karl Zhang 张双锣 (karlzhang), Iwo Mergler,
	Jeff Lauruhn (jlauruhn), Stefan Roese, linux-kernel,
	Boris Brezillon

[-- Attachment #1: Type: text/plain, Size: 2425 bytes --]

Hi Boris,

[auto build test results on v4.3-rc2 -- if it's inappropriate base, please ignore]

config: i386-allnoconfig (attached as .config)
reproduce:
  git checkout f3924c26b426d59134751b046f403f3f66e16ed7
  # save the attached .config to linux build tree
  make ARCH=i386 

All warnings (new ones prefixed by >>):

>> include/linux/mtd/nand.h:730: warning: No description found for parameter 'get_status'

vim +/get_status +730 include/linux/mtd/nand.h

30631cb8 Alessandro Rubini 2009-09-20  714  	flstate_t state;
f75e5097 Thomas Gleixner   2006-05-26  715  
f75e5097 Thomas Gleixner   2006-05-26  716  	uint8_t *oob_poi;
f75e5097 Thomas Gleixner   2006-05-26  717  	struct nand_hw_control *controller;
f75e5097 Thomas Gleixner   2006-05-26  718  
f75e5097 Thomas Gleixner   2006-05-26  719  	struct nand_ecc_ctrl ecc;
4bf63fcb David Woodhouse   2006-09-25  720  	struct nand_buffers *buffers;
f75e5097 Thomas Gleixner   2006-05-26  721  	struct nand_hw_control hwcontrol;
f75e5097 Thomas Gleixner   2006-05-26  722  
^1da177e Linus Torvalds    2005-04-16  723  	uint8_t *bbt;
^1da177e Linus Torvalds    2005-04-16  724  	struct nand_bbt_descr *bbt_td;
^1da177e Linus Torvalds    2005-04-16  725  	struct nand_bbt_descr *bbt_md;
f75e5097 Thomas Gleixner   2006-05-26  726  
^1da177e Linus Torvalds    2005-04-16  727  	struct nand_bbt_descr *badblock_pattern;
f75e5097 Thomas Gleixner   2006-05-26  728  
^1da177e Linus Torvalds    2005-04-16  729  	void *priv;
^1da177e Linus Torvalds    2005-04-16 @730  };
^1da177e Linus Torvalds    2005-04-16  731  
^1da177e Linus Torvalds    2005-04-16  732  /*
^1da177e Linus Torvalds    2005-04-16  733   * NAND Flash Manufacturer ID Codes
^1da177e Linus Torvalds    2005-04-16  734   */
^1da177e Linus Torvalds    2005-04-16  735  #define NAND_MFR_TOSHIBA	0x98
^1da177e Linus Torvalds    2005-04-16  736  #define NAND_MFR_SAMSUNG	0xec
^1da177e Linus Torvalds    2005-04-16  737  #define NAND_MFR_FUJITSU	0x04
^1da177e Linus Torvalds    2005-04-16  738  #define NAND_MFR_NATIONAL	0x8f

:::::: The code at line 730 was first introduced by commit
:::::: 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 Linux-2.6.12-rc2

:::::: TO: Linus Torvalds <torvalds@ppc970.osdl.org>
:::::: CC: Linus Torvalds <torvalds@ppc970.osdl.org>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/octet-stream, Size: 6062 bytes --]

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2015-09-28  5:40 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-09-25 15:09 [PATCH 0/5] mtd: nand/UBI: add power-cut emulation Boris Brezillon
2015-09-25 15:09 ` [PATCH 1/5] mtd: nand: add basic stuff to support " Boris Brezillon
2015-09-28  5:41   ` kbuild test robot
2015-09-25 15:09 ` [PATCH 2/5] mtd: nand: return -EROFS in case of " Boris Brezillon
2015-09-25 15:09 ` [PATCH 3/5] UBI: switch the UBI device in read-only mode when mtd returns -EROFS Boris Brezillon
2015-09-25 17:34   ` Richard Weinberger
2015-09-26  8:40     ` Boris Brezillon
2015-09-25 15:09 ` [PATCH 4/5] mtd: nand: nandsim: implement ->get_status() Boris Brezillon
2015-09-25 15:09 ` [PATCH 5/5] mtd: nand: nandsim: add support for power-cut emulation Boris Brezillon

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).