Patchwork [5/7] NAND: make ->check_bad more user friendly

login
register
mail settings
Submitter Maxim Levitsky
Date Feb. 5, 2010, 11:18 p.m.
Message ID <1265411890-9156-6-git-send-email-maximlevitsky@gmail.com>
Download mbox | patch
Permalink /patch/44694/
State New
Headers show

Comments

Maxim Levitsky - Feb. 5, 2010, 11:18 p.m.
Currently to implement a custom ->check_bad one need to call
nand_get_device, nand_release_device.
Also it not possible to use mtd->read_oob because they call
nand_get_device too.
Refactor the code, so check_bad now always has to do nand_get_device
Thus it can use plain mtd->read_oob

Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
---
 drivers/mtd/nand/cafe_nand.c  |    2 +-
 drivers/mtd/nand/diskonchip.c |    2 +-
 drivers/mtd/nand/nand_base.c  |   74 ++++++++++++++++++++++++++---------------
 include/linux/mtd/nand.h      |    2 +-
 4 files changed, 50 insertions(+), 30 deletions(-)

Patch

diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c
index c828d9a..8211197 100644
--- a/drivers/mtd/nand/cafe_nand.c
+++ b/drivers/mtd/nand/cafe_nand.c
@@ -577,7 +577,7 @@  static int cafe_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
 	return 0;
 }
 
-static int cafe_nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
+static int cafe_nand_block_bad(struct mtd_info *mtd, loff_t ofs)
 {
 	return 0;
 }
diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c
index b126cf8..ea3a3c9 100644
--- a/drivers/mtd/nand/diskonchip.c
+++ b/drivers/mtd/nand/diskonchip.c
@@ -854,7 +854,7 @@  static int doc200x_dev_ready(struct mtd_info *mtd)
 	}
 }
 
-static int doc200x_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
+static int doc200x_block_bad(struct mtd_info *mtd, loff_t ofs)
 {
 	/* This is our last resort if we couldn't find or create a BBT.  Just
 	   pretend all blocks are good. */
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index c393df3..86fa40a 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -312,22 +312,18 @@  static int nand_verify_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
  *
  * Check, if the block is bad.
  */
-static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
+static int nand_block_bad(struct mtd_info *mtd, loff_t ofs)
 {
 	int page, chipnr, res = 0;
 	struct nand_chip *chip = mtd->priv;
 	u16 bad;
 
 	page = (int)(ofs >> chip->page_shift) & chip->pagemask;
+	chipnr = (int)(ofs >> chip->chip_shift);
+	nand_get_device(chip, mtd, FL_READING);
 
-	if (getchip) {
-		chipnr = (int)(ofs >> chip->chip_shift);
-
-		nand_get_device(chip, mtd, FL_READING);
-
-		/* Select the NAND device */
-		chip->select_chip(mtd, chipnr);
-	}
+	/* Select the NAND device */
+	chip->select_chip(mtd, chipnr);
 
 	if (chip->options & NAND_BUSWIDTH_16) {
 		chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos & 0xFE,
@@ -343,9 +339,7 @@  static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
 			res = 1;
 	}
 
-	if (getchip)
-		nand_release_device(mtd);
-
+	nand_release_device(mtd);
 	return res;
 }
 
@@ -410,19 +404,17 @@  static int nand_check_wp(struct mtd_info *mtd)
  * nand_block_checkbad - [GENERIC] Check if a block is marked bad
  * @mtd:	MTD device structure
  * @ofs:	offset from device start
- * @getchip:	0, if the chip is already selected
  * @allowbbt:	1, if its allowed to access the bbt area
  *
  * Check, if the block is bad. Either by reading the bad block table or
  * calling of the scan function.
  */
-static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
-			       int allowbbt)
+static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int allowbbt)
 {
 	struct nand_chip *chip = mtd->priv;
 
 	if (!chip->bbt)
-		return chip->block_bad(mtd, ofs, getchip);
+		return chip->block_bad(mtd, ofs);
 
 	/* Return info from the table */
 	return nand_isbad_bbt(mtd, ofs, allowbbt);
@@ -2277,6 +2269,40 @@  static int nand_erase(struct mtd_info *mtd, struct erase_info *instr)
 	return nand_erase_nand(mtd, instr, 0);
 }
 
+/**
+ * nand_erase_nand - [Internal] check to see if range contains bad blocks
+ * @mtd:	MTD device structure
+ * @offs:	start offset
+ * @len:	length of the range
+ * @allowbbt:	allow access to bbt
+ *
+ * Sanity check before doing the erase
+ */
+static int nand_check_range(struct mtd_info *mtd, loff_t offs, loff_t len,
+			int allow_bbt)
+{
+	struct nand_chip *chip = mtd->priv;
+	int page = offs >> chip->page_shift;
+	int mask = (1 << chip->page_shift) - 1;
+
+	if (len & mask || offs & mask) {
+		DEBUG(MTD_DEBUG_LEVEL0, "%s Unaligned access\n", __func__);
+		return -EINVAL;
+	}
+
+	while (offs < len) {
+		if (nand_block_checkbad(mtd, offs, allow_bbt)) {
+			printk(KERN_WARNING "%s: attempt to erase a bad block "
+					"at page 0x%08x\n", __func__, page);
+				return -EIO;
+		}
+
+		offs += (1 < chip->page_shift);
+		page++;
+	}
+	return 0;
+}
+
 #define BBT_PAGE_MASK	0xffffff3f
 /**
  * nand_erase_nand - [Internal] erase block(s)
@@ -2321,6 +2347,10 @@  int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
 
 	instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
 
+	/* See if we were asked to erase bad blocks */
+	if (nand_check_range(mtd, instr->addr, instr->len, allowbbt))
+		return -EINVAL;
+
 	/* Grab the lock and see if the device is available */
 	nand_get_device(chip, mtd, FL_ERASING);
 
@@ -2357,16 +2387,6 @@  int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
 	instr->state = MTD_ERASING;
 
 	while (len) {
-		/*
-		 * heck if we have a bad block, we do not erase bad blocks !
-		 */
-		if (nand_block_checkbad(mtd, ((loff_t) page) <<
-					chip->page_shift, 0, allowbbt)) {
-			printk(KERN_WARNING "%s: attempt to erase a bad block "
-					"at page 0x%08x\n", __func__, page);
-			instr->state = MTD_ERASE_FAILED;
-			goto erase_exit;
-		}
 
 		/*
 		 * Invalidate the page cache, if we erase the block which
@@ -2490,7 +2510,7 @@  static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
 	if (offs > mtd->size)
 		return -EINVAL;
 
-	return nand_block_checkbad(mtd, offs, 1, 0);
+	return nand_block_checkbad(mtd, offs, 0);
 }
 
 /**
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index ccab9df..921f24b 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -364,7 +364,7 @@  struct nand_chip {
 	void		(*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);
 	int		(*verify_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
 	void		(*select_chip)(struct mtd_info *mtd, int chip);
-	int		(*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);
+	int		(*block_bad)(struct mtd_info *mtd, loff_t ofs);
 	int		(*block_markbad)(struct mtd_info *mtd, loff_t ofs);
 	void		(*cmd_ctrl)(struct mtd_info *mtd, int dat,
 				    unsigned int ctrl);