diff options
author | Artem B. Bityuckiy <dedekind@infradead.org> | 2005-02-11 05:14:15 -0500 |
---|---|---|
committer | Thomas Gleixner <tglx@mtd.linutronix.de> | 2005-05-23 06:32:18 -0400 |
commit | eeada24da8bd23fcf6acd2729be054ea99b301bb (patch) | |
tree | c5d3cdffbfc11ec2ee82d64aef4177e92dfdffc7 /drivers/mtd | |
parent | 41ce921440bd14d9b69b19fbf47d9278582739fe (diff) |
[MTD] NAND: Read only OOB bytes during bad block scan
When scanning NAND for bad blocks, don't read the whole page, read
only needed OOB bytes instead. Also check the return code of the
nand_read_raw() function. Correctly free the this->bbt array in
case of failure. Tested with Large page NAND.
Fix debugging message.
Signed-off-by: Artem B. Bityuckiy <dedekind@infradead.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/nand/nand_bbt.c | 52 |
1 files changed, 38 insertions, 14 deletions
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 9a1949751c1f..5ff6eba8bec6 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c | |||
@@ -6,7 +6,7 @@ | |||
6 | * | 6 | * |
7 | * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de) | 7 | * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de) |
8 | * | 8 | * |
9 | * $Id: nand_bbt.c,v 1.28 2004/11/13 10:19:09 gleixner Exp $ | 9 | * $Id: nand_bbt.c,v 1.30 2005/02/11 10:14:12 dedekind Exp $ |
10 | * | 10 | * |
11 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License version 2 as | 12 | * it under the terms of the GNU General Public License version 2 as |
@@ -252,10 +252,10 @@ static int read_abs_bbts (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_de | |||
252 | * Create a bad block table by scanning the device | 252 | * Create a bad block table by scanning the device |
253 | * for the given good/bad block identify pattern | 253 | * for the given good/bad block identify pattern |
254 | */ | 254 | */ |
255 | static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip) | 255 | static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip) |
256 | { | 256 | { |
257 | struct nand_chip *this = mtd->priv; | 257 | struct nand_chip *this = mtd->priv; |
258 | int i, j, numblocks, len, scanlen; | 258 | int i, j, numblocks, len, scanlen, pagelen; |
259 | int startblock; | 259 | int startblock; |
260 | loff_t from; | 260 | loff_t from; |
261 | size_t readlen, ooblen; | 261 | size_t readlen, ooblen; |
@@ -270,9 +270,18 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc | |||
270 | else | 270 | else |
271 | len = 1; | 271 | len = 1; |
272 | } | 272 | } |
273 | scanlen = mtd->oobblock + mtd->oobsize; | 273 | |
274 | readlen = len * mtd->oobblock; | 274 | if (bd->options == 0) { |
275 | ooblen = len * mtd->oobsize; | 275 | /* Memory-based BBT. We may read only needed bytes from the OOB area to |
276 | * test if block is bad, no need to read the whole page content. */ | ||
277 | scanlen = ooblen = pagelen = 0; | ||
278 | readlen = bd->len; | ||
279 | } else { | ||
280 | scanlen = mtd->oobblock + mtd->oobsize; | ||
281 | readlen = len * mtd->oobblock; | ||
282 | ooblen = len * mtd->oobsize; | ||
283 | pagelen = mtd->oobblock; | ||
284 | } | ||
276 | 285 | ||
277 | if (chip == -1) { | 286 | if (chip == -1) { |
278 | /* Note that numblocks is 2 * (real numblocks) here, see i+=2 below as it | 287 | /* Note that numblocks is 2 * (real numblocks) here, see i+=2 below as it |
@@ -284,7 +293,7 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc | |||
284 | if (chip >= this->numchips) { | 293 | if (chip >= this->numchips) { |
285 | printk (KERN_WARNING "create_bbt(): chipnr (%d) > available chips (%d)\n", | 294 | printk (KERN_WARNING "create_bbt(): chipnr (%d) > available chips (%d)\n", |
286 | chip + 1, this->numchips); | 295 | chip + 1, this->numchips); |
287 | return; | 296 | return -EINVAL; |
288 | } | 297 | } |
289 | numblocks = this->chipsize >> (this->bbt_erase_shift - 1); | 298 | numblocks = this->chipsize >> (this->bbt_erase_shift - 1); |
290 | startblock = chip * numblocks; | 299 | startblock = chip * numblocks; |
@@ -293,9 +302,18 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc | |||
293 | } | 302 | } |
294 | 303 | ||
295 | for (i = startblock; i < numblocks;) { | 304 | for (i = startblock; i < numblocks;) { |
296 | nand_read_raw (mtd, buf, from, readlen, ooblen); | 305 | int ret; |
306 | |||
307 | if (bd->options == 0) { | ||
308 | size_t retlen; | ||
309 | if ((ret = mtd->read_oob(mtd, from + bd->offs, bd->len, &retlen, &buf[bd->offs]))) | ||
310 | return ret; | ||
311 | } else { | ||
312 | if ((ret = nand_read_raw (mtd, buf, from, readlen, ooblen))) | ||
313 | return ret; | ||
314 | } | ||
297 | for (j = 0; j < len; j++) { | 315 | for (j = 0; j < len; j++) { |
298 | if (check_pattern (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) { | 316 | if (check_pattern (&buf[j * scanlen], scanlen, pagelen, bd)) { |
299 | this->bbt[i >> 3] |= 0x03 << (i & 0x6); | 317 | this->bbt[i >> 3] |= 0x03 << (i & 0x6); |
300 | printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n", | 318 | printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n", |
301 | i >> 1, (unsigned int) from); | 319 | i >> 1, (unsigned int) from); |
@@ -305,6 +323,7 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc | |||
305 | i += 2; | 323 | i += 2; |
306 | from += (1 << this->bbt_erase_shift); | 324 | from += (1 << this->bbt_erase_shift); |
307 | } | 325 | } |
326 | return 0; | ||
308 | } | 327 | } |
309 | 328 | ||
310 | /** | 329 | /** |
@@ -595,8 +614,7 @@ static int nand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) | |||
595 | 614 | ||
596 | /* Ensure that we only scan for the pattern and nothing else */ | 615 | /* Ensure that we only scan for the pattern and nothing else */ |
597 | bd->options = 0; | 616 | bd->options = 0; |
598 | create_bbt (mtd, this->data_buf, bd, -1); | 617 | return create_bbt (mtd, this->data_buf, bd, -1); |
599 | return 0; | ||
600 | } | 618 | } |
601 | 619 | ||
602 | /** | 620 | /** |
@@ -808,8 +826,14 @@ int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) | |||
808 | /* If no primary table decriptor is given, scan the device | 826 | /* If no primary table decriptor is given, scan the device |
809 | * to build a memory based bad block table | 827 | * to build a memory based bad block table |
810 | */ | 828 | */ |
811 | if (!td) | 829 | if (!td) { |
812 | return nand_memory_bbt(mtd, bd); | 830 | if ((res = nand_memory_bbt(mtd, bd))) { |
831 | printk (KERN_ERR "nand_bbt: Can't scan flash and build the RAM-based BBT\n"); | ||
832 | kfree (this->bbt); | ||
833 | this->bbt = NULL; | ||
834 | } | ||
835 | return res; | ||
836 | } | ||
813 | 837 | ||
814 | /* Allocate a temporary buffer for one eraseblock incl. oob */ | 838 | /* Allocate a temporary buffer for one eraseblock incl. oob */ |
815 | len = (1 << this->bbt_erase_shift); | 839 | len = (1 << this->bbt_erase_shift); |
@@ -1042,7 +1066,7 @@ int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt) | |||
1042 | res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03; | 1066 | res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03; |
1043 | 1067 | ||
1044 | DEBUG (MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n", | 1068 | DEBUG (MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n", |
1045 | (unsigned int)offs, res, block >> 1); | 1069 | (unsigned int)offs, block >> 1, res); |
1046 | 1070 | ||
1047 | switch ((int)res) { | 1071 | switch ((int)res) { |
1048 | case 0x00: return 0; | 1072 | case 0x00: return 0; |