diff options
author | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2009-07-24 09:18:04 -0400 |
---|---|---|
committer | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2009-08-14 13:02:20 -0400 |
commit | de75c771b4cc4da963164a538a8448128301bc35 (patch) | |
tree | a8fea3a1a6c68324b0b425c482f3c2ef5c7d1b22 /drivers/mtd/ubi | |
parent | 867996b15c1f0a98d2c405bada907e97499ba8c2 (diff) |
UBI: improve NOR flash erasure quirk
More testing of NOR flash against power cuts showed that sometimes
eraseblocks may be unwritable, and we cannot really invalidate
them before erasure. But in this case the eraseblock probably
contains garbage anyway, and we do not have to invalidate the
headers. This assumption might be not true, but this is at least
what I have observed. So if we cannot invalidate the headers,
we make sure that the PEB does not contain valid VID header.
If this is true, everything is fine, otherwise we panic.
Diffstat (limited to 'drivers/mtd/ubi')
-rw-r--r-- | drivers/mtd/ubi/io.c | 46 |
1 files changed, 31 insertions, 15 deletions
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c index b693138fc519..8aa51e7a6a7d 100644 --- a/drivers/mtd/ubi/io.c +++ b/drivers/mtd/ubi/io.c | |||
@@ -476,30 +476,46 @@ out: | |||
476 | */ | 476 | */ |
477 | static int nor_erase_prepare(struct ubi_device *ubi, int pnum) | 477 | static int nor_erase_prepare(struct ubi_device *ubi, int pnum) |
478 | { | 478 | { |
479 | int err; | 479 | int err, err1; |
480 | size_t written; | 480 | size_t written; |
481 | loff_t addr; | 481 | loff_t addr; |
482 | uint32_t data = 0; | 482 | uint32_t data = 0; |
483 | struct ubi_vid_hdr vid_hdr; | ||
483 | 484 | ||
484 | addr = (loff_t)pnum * ubi->peb_size + ubi->vid_hdr_aloffset; | 485 | addr = (loff_t)pnum * ubi->peb_size + ubi->vid_hdr_aloffset; |
485 | err = ubi->mtd->write(ubi->mtd, addr, 4, &written, (void *)&data); | 486 | err = ubi->mtd->write(ubi->mtd, addr, 4, &written, (void *)&data); |
486 | if (err) { | 487 | if (!err) { |
487 | ubi_err("error %d while writing 4 bytes to PEB %d:%d, written " | 488 | addr -= ubi->vid_hdr_aloffset; |
488 | "%zd bytes", err, pnum, ubi->vid_hdr_aloffset, written); | 489 | err = ubi->mtd->write(ubi->mtd, addr, 4, &written, |
489 | ubi_dbg_dump_stack(); | 490 | (void *)&data); |
490 | return err; | 491 | if (!err) |
492 | return 0; | ||
491 | } | 493 | } |
492 | 494 | ||
493 | addr -= ubi->vid_hdr_aloffset; | 495 | /* |
494 | err = ubi->mtd->write(ubi->mtd, addr, 4, &written, (void *)&data); | 496 | * We failed to write to the media. This was observed with Spansion |
495 | if (err) { | 497 | * S29GL512N NOR flash. Most probably the eraseblock erasure was |
496 | ubi_err("error %d while writing 4 bytes to PEB %d:%d, written " | 498 | * interrupted at a very inappropriate moment, so it became unwritable. |
497 | "%zd bytes", err, pnum, 0, written); | 499 | * In this case we probably anyway have garbage in this PEB. |
498 | ubi_dbg_dump_stack(); | 500 | */ |
499 | return err; | 501 | err1 = ubi_io_read_vid_hdr(ubi, pnum, &vid_hdr, 0); |
500 | } | 502 | if (err1 == UBI_IO_BAD_VID_HDR) |
503 | /* | ||
504 | * The VID header is corrupted, so we can safely erase this | ||
505 | * PEB and not afraid that it will be treated as a valid PEB in | ||
506 | * case of an unclean reboot. | ||
507 | */ | ||
508 | return 0; | ||
501 | 509 | ||
502 | return 0; | 510 | /* |
511 | * The PEB contains a valid VID header, but we cannot invalidate it. | ||
512 | * Supposedly the flash media or the driver is screwed up, so return an | ||
513 | * error. | ||
514 | */ | ||
515 | ubi_err("cannot invalidate PEB %d, write returned %d read returned %d", | ||
516 | pnum, err, err1); | ||
517 | ubi_dbg_dump_flash(ubi, pnum, 0, ubi->peb_size); | ||
518 | return -EIO; | ||
503 | } | 519 | } |
504 | 520 | ||
505 | /** | 521 | /** |