diff options
author | Artem B. Bityuckiy <dedekind@infradead.org> | 2005-02-16 12:09:39 -0500 |
---|---|---|
committer | Thomas Gleixner <tglx@mtd.linutronix.de> | 2005-05-23 06:38:33 -0400 |
commit | 171650af9cd847964cf69b6bab9009631283293f (patch) | |
tree | c995b772d0f88d83a5c89a5daa7b4c01c97e2f99 | |
parent | f16407d73effc59e1e9f88e45a3dc53cacbb8264 (diff) |
[MTD] NAND: Fix bad block table scan for small page devices
Scan 1st and 2nd pages of SP devices for BB marker by default.
Fix more then one page scanning in create_bbt.c.
Signed-off-by: Artem B. Bityuckiy <dedekind@infradead.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r-- | drivers/mtd/nand/nand_bbt.c | 59 |
1 files changed, 30 insertions, 29 deletions
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 5ff6eba8bec6..c85c69dec540 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.30 2005/02/11 10:14:12 dedekind Exp $ | 9 | * $Id: nand_bbt.c,v 1.31 2005/02/16 17:09:36 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 |
@@ -77,17 +77,17 @@ | |||
77 | */ | 77 | */ |
78 | static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td) | 78 | static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td) |
79 | { | 79 | { |
80 | int i, end; | 80 | int i, end = 0; |
81 | uint8_t *p = buf; | 81 | uint8_t *p = buf; |
82 | 82 | ||
83 | end = paglen + td->offs; | ||
84 | if (td->options & NAND_BBT_SCANEMPTY) { | 83 | if (td->options & NAND_BBT_SCANEMPTY) { |
84 | end = paglen + td->offs; | ||
85 | for (i = 0; i < end; i++) { | 85 | for (i = 0; i < end; i++) { |
86 | if (p[i] != 0xff) | 86 | if (p[i] != 0xff) |
87 | return -1; | 87 | return -1; |
88 | } | 88 | } |
89 | p += end; | ||
89 | } | 90 | } |
90 | p += end; | ||
91 | 91 | ||
92 | /* Compare the pattern */ | 92 | /* Compare the pattern */ |
93 | for (i = 0; i < td->len; i++) { | 93 | for (i = 0; i < td->len; i++) { |
@@ -95,9 +95,9 @@ static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_des | |||
95 | return -1; | 95 | return -1; |
96 | } | 96 | } |
97 | 97 | ||
98 | p += td->len; | ||
99 | end += td->len; | ||
100 | if (td->options & NAND_BBT_SCANEMPTY) { | 98 | if (td->options & NAND_BBT_SCANEMPTY) { |
99 | p += td->len; | ||
100 | end += td->len; | ||
101 | for (i = end; i < len; i++) { | 101 | for (i = end; i < len; i++) { |
102 | if (*p++ != 0xff) | 102 | if (*p++ != 0xff) |
103 | return -1; | 103 | return -1; |
@@ -255,7 +255,7 @@ static int read_abs_bbts (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_de | |||
255 | static int 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, pagelen; | 258 | int i, j, numblocks, len, scanlen; |
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,17 +270,16 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr | |||
270 | else | 270 | else |
271 | len = 1; | 271 | len = 1; |
272 | } | 272 | } |
273 | 273 | ||
274 | if (bd->options == 0) { | 274 | if (!(bd->options & NAND_BBT_SCANEMPTY)) { |
275 | /* Memory-based BBT. We may read only needed bytes from the OOB area to | 275 | /* We need only read few bytes from the OOB area */ |
276 | * test if block is bad, no need to read the whole page content. */ | 276 | scanlen = ooblen = 0; |
277 | scanlen = ooblen = pagelen = 0; | ||
278 | readlen = bd->len; | 277 | readlen = bd->len; |
279 | } else { | 278 | } else { |
279 | /* Full page content should be read */ | ||
280 | scanlen = mtd->oobblock + mtd->oobsize; | 280 | scanlen = mtd->oobblock + mtd->oobsize; |
281 | readlen = len * mtd->oobblock; | 281 | readlen = len * mtd->oobblock; |
282 | ooblen = len * mtd->oobsize; | 282 | ooblen = len * mtd->oobsize; |
283 | pagelen = mtd->oobblock; | ||
284 | } | 283 | } |
285 | 284 | ||
286 | if (chip == -1) { | 285 | if (chip == -1) { |
@@ -293,7 +292,7 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr | |||
293 | if (chip >= this->numchips) { | 292 | if (chip >= this->numchips) { |
294 | printk (KERN_WARNING "create_bbt(): chipnr (%d) > available chips (%d)\n", | 293 | printk (KERN_WARNING "create_bbt(): chipnr (%d) > available chips (%d)\n", |
295 | chip + 1, this->numchips); | 294 | chip + 1, this->numchips); |
296 | return -EINVAL; | 295 | return -EINVAL; |
297 | } | 296 | } |
298 | numblocks = this->chipsize >> (this->bbt_erase_shift - 1); | 297 | numblocks = this->chipsize >> (this->bbt_erase_shift - 1); |
299 | startblock = chip * numblocks; | 298 | startblock = chip * numblocks; |
@@ -304,16 +303,21 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr | |||
304 | for (i = startblock; i < numblocks;) { | 303 | for (i = startblock; i < numblocks;) { |
305 | int ret; | 304 | int ret; |
306 | 305 | ||
307 | if (bd->options == 0) { | 306 | if (bd->options & NAND_BBT_SCANEMPTY) |
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))) | 307 | if ((ret = nand_read_raw (mtd, buf, from, readlen, ooblen))) |
313 | return ret; | 308 | return ret; |
314 | } | 309 | |
315 | for (j = 0; j < len; j++) { | 310 | for (j = 0; j < len; j++) { |
316 | if (check_pattern (&buf[j * scanlen], scanlen, pagelen, bd)) { | 311 | if (!(bd->options & NAND_BBT_SCANEMPTY)) { |
312 | size_t retlen; | ||
313 | |||
314 | /* No need to read pages fully, just read required OOB bytes */ | ||
315 | ret = mtd->read_oob(mtd, from + j * mtd->oobblock + bd->offs, | ||
316 | readlen, &retlen, &buf[0]); | ||
317 | if (ret) | ||
318 | return ret; | ||
319 | } | ||
320 | if (check_pattern (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) { | ||
317 | this->bbt[i >> 3] |= 0x03 << (i & 0x6); | 321 | this->bbt[i >> 3] |= 0x03 << (i & 0x6); |
318 | printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n", | 322 | printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n", |
319 | i >> 1, (unsigned int) from); | 323 | i >> 1, (unsigned int) from); |
@@ -323,6 +327,7 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr | |||
323 | i += 2; | 327 | i += 2; |
324 | from += (1 << this->bbt_erase_shift); | 328 | from += (1 << this->bbt_erase_shift); |
325 | } | 329 | } |
330 | |||
326 | return 0; | 331 | return 0; |
327 | } | 332 | } |
328 | 333 | ||
@@ -608,12 +613,11 @@ write: | |||
608 | * The function creates a memory based bbt by scanning the device | 613 | * The function creates a memory based bbt by scanning the device |
609 | * for manufacturer / software marked good / bad blocks | 614 | * for manufacturer / software marked good / bad blocks |
610 | */ | 615 | */ |
611 | static int nand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) | 616 | static inline int nand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) |
612 | { | 617 | { |
613 | struct nand_chip *this = mtd->priv; | 618 | struct nand_chip *this = mtd->priv; |
614 | 619 | ||
615 | /* Ensure that we only scan for the pattern and nothing else */ | 620 | bd->options &= ~NAND_BBT_SCANEMPTY; |
616 | bd->options = 0; | ||
617 | return create_bbt (mtd, this->data_buf, bd, -1); | 621 | return create_bbt (mtd, this->data_buf, bd, -1); |
618 | } | 622 | } |
619 | 623 | ||
@@ -928,14 +932,11 @@ out: | |||
928 | } | 932 | } |
929 | 933 | ||
930 | /* Define some generic bad / good block scan pattern which are used | 934 | /* Define some generic bad / good block scan pattern which are used |
931 | * while scanning a device for factory marked good / bad blocks | 935 | * while scanning a device for factory marked good / bad blocks. */ |
932 | * | ||
933 | * The memory based patterns just | ||
934 | */ | ||
935 | static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; | 936 | static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; |
936 | 937 | ||
937 | static struct nand_bbt_descr smallpage_memorybased = { | 938 | static struct nand_bbt_descr smallpage_memorybased = { |
938 | .options = 0, | 939 | .options = NAND_BBT_SCAN2NDPAGE, |
939 | .offs = 5, | 940 | .offs = 5, |
940 | .len = 1, | 941 | .len = 1, |
941 | .pattern = scan_ff_pattern | 942 | .pattern = scan_ff_pattern |