From patchwork Fri Feb 5 23:18:08 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maxim Levitsky X-Patchwork-Id: 44694 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from bombadil.infradead.org (bombadil.infradead.org [18.85.46.34]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id C27BBB7CEF for ; Sat, 6 Feb 2010 10:21:11 +1100 (EST) Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.69 #1 (Red Hat Linux)) id 1NdXRj-0004BK-QF; Fri, 05 Feb 2010 23:18:43 +0000 Received: from mail-bw0-f221.google.com ([209.85.218.221]) by bombadil.infradead.org with esmtp (Exim 4.69 #1 (Red Hat Linux)) id 1NdXRa-00041V-Gk for linux-mtd@lists.infradead.org; Fri, 05 Feb 2010 23:18:41 +0000 Received: by mail-bw0-f221.google.com with SMTP id 21so3708866bwz.4 for ; Fri, 05 Feb 2010 15:18:34 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:from:to:cc:subject:date :message-id:x-mailer:in-reply-to:references; bh=R+LrehgGaMYejDSc3/K7qnO3i81rqY6eO3GJwdIWL80=; b=j7aEsqPYMZAnAw84qQ0Oy1xRYHhEJpL9K8MxJ0XOP2hVuRbFNynTmTwUXSVkHGQHlJ szIMZk6Pjsr5UUNBU4zzTHG1qKBJy1sTJ02Lhd1ubBKDV7W52yggWAdvRsFCAX2vWJhJ O69p9/dSK182YipJ9/Cx4kaEh1tF/CbzCRbhE= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references; b=apVKhW1US4BjjHEywat2ZphAlgCrvLDOOLv2vXYfa2TJ/Q+SqocVfvS7/qp+LvZaHV jAkEV6etuEB0mhnB7K9yjaUxZVyxVupLWXMUytpvM8XP50vE17UaU6SVz0aJbYs91t/0 VAWWDUjy+VVbz5A3K204FHEfXNjzyaO6A8rh0= Received: by 10.204.24.84 with SMTP id u20mr2139793bkb.164.1265411914100; Fri, 05 Feb 2010 15:18:34 -0800 (PST) Received: from localhost.localdomain (IGLD-84-229-248-49.inter.net.il [84.229.248.49]) by mx.google.com with ESMTPS id 13sm892197bwz.6.2010.02.05.15.18.32 (version=SSLv3 cipher=RC4-MD5); Fri, 05 Feb 2010 15:18:33 -0800 (PST) From: Maxim Levitsky To: David Woodhouse Subject: [PATCH 5/7] NAND: make ->check_bad more user friendly Date: Sat, 6 Feb 2010 01:18:08 +0200 Message-Id: <1265411890-9156-6-git-send-email-maximlevitsky@gmail.com> X-Mailer: git-send-email 1.6.3.3 In-Reply-To: <1265411890-9156-1-git-send-email-maximlevitsky@gmail.com> References: <1265411890-9156-1-git-send-email-maximlevitsky@gmail.com> X-CRM114-Version: 20090807-BlameThorstenAndJenny ( TRE 0.7.6 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20100205_181834_814761_8443F320 X-CRM114-Status: GOOD ( 24.89 ) X-Spam-Score: 0.0 (/) X-Spam-Report: SpamAssassin version 3.2.5 on bombadil.infradead.org summary: Content analysis details: (0.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- _SUMMARY_ Cc: Maxim Levitsky , Artem Bityutskiy , Vitaly Wool , linux-kernel , "stanley.miao" , linux-mtd X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: linux-mtd-bounces@lists.infradead.org Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org 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 --- 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(-) 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);