aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArtem Bityutskiy <Artem.Bityutskiy@nokia.com>2009-07-06 01:57:53 -0400
committerArtem Bityutskiy <Artem.Bityutskiy@nokia.com>2009-07-07 04:37:45 -0400
commitebf53f421308c2f59c9bcbad4c5c297a0d00199a (patch)
tree1ec5084484bcaea259a210147cb278af4286f7e6
parentfe96efc1a3c049f0a1bcd9b65e0faeb751ce5ec6 (diff)
UBI: fix NOR flash recovery
This commit fixes NOR flash recovery issues observed with Spansion S29GL512N NOR. When NOR erases, it first fills PEBs with zeroes, then sets all bytes to 0xFF. Filling with zeroes starts from the end of the PEB. And when power is cut, this results in PEBs containing correct EC and VID headers but corrupted with zeros at the end. This confuses UBI and it mistakinly accepts these PEBs and associate them with LEBs. Fis this issue by zeroing EC and VID magics before erasing PEBs, to make UBI later refuse zem. Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
-rw-r--r--drivers/mtd/ubi/build.c5
-rw-r--r--drivers/mtd/ubi/io.c58
-rw-r--r--drivers/mtd/ubi/ubi.h4
3 files changed, 64 insertions, 3 deletions
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index db0b9cb64c6c..e1f7d0a78b9d 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -657,6 +657,11 @@ static int io_init(struct ubi_device *ubi)
657 if (ubi->mtd->block_isbad && ubi->mtd->block_markbad) 657 if (ubi->mtd->block_isbad && ubi->mtd->block_markbad)
658 ubi->bad_allowed = 1; 658 ubi->bad_allowed = 1;
659 659
660 if (ubi->mtd->type == MTD_NORFLASH) {
661 ubi_assert(ubi->mtd->writesize == 1);
662 ubi->nor_flash = 1;
663 }
664
660 ubi->min_io_size = ubi->mtd->writesize; 665 ubi->min_io_size = ubi->mtd->writesize;
661 ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft; 666 ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft;
662 667
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index 1ea14218de02..c3bd2e34c642 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -266,8 +266,8 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
266 addr = (loff_t)pnum * ubi->peb_size + offset; 266 addr = (loff_t)pnum * ubi->peb_size + offset;
267 err = ubi->mtd->write(ubi->mtd, addr, len, &written, buf); 267 err = ubi->mtd->write(ubi->mtd, addr, len, &written, buf);
268 if (err) { 268 if (err) {
269 ubi_err("error %d while writing %d bytes to PEB %d:%d, written" 269 ubi_err("error %d while writing %d bytes to PEB %d:%d, written "
270 " %zd bytes", err, len, pnum, offset, written); 270 "%zd bytes", err, len, pnum, offset, written);
271 ubi_dbg_dump_stack(); 271 ubi_dbg_dump_stack();
272 } else 272 } else
273 ubi_assert(written == len); 273 ubi_assert(written == len);
@@ -454,6 +454,54 @@ out:
454} 454}
455 455
456/** 456/**
457 * nor_erase_prepare - prepare a NOR flash PEB for erasure.
458 * @ubi: UBI device description object
459 * @pnum: physical eraseblock number to prepare
460 *
461 * NOR flash, or at least some of them, have peculiar embedded PEB erasure
462 * algorithm: the PEB is first filled with zeroes, then it is erased. And
463 * filling with zeroes starts from the end of the PEB. This was observed with
464 * Spansion S29GL512N NOR flash.
465 *
466 * This means that in case of a power cut we may end up with intact data at the
467 * beginning of the PEB, and all zeroes at the end of PEB. In other words, the
468 * EC and VID headers are OK, but a large chunk of data at the end of PEB is
469 * zeroed. This makes UBI mistakenly treat this PEB as used and associate it
470 * with an LEB, which leads to subsequent failures (e.g., UBIFS fails).
471 *
472 * This function is called before erasing NOR PEBs and it zeroes out EC and VID
473 * magic numbers in order to invalidate them and prevent the failures. Returns
474 * zero in case of success and a negative error code in case of failure.
475 */
476static int nor_erase_prepare(struct ubi_device *ubi, int pnum)
477{
478 int err;
479 size_t written;
480 loff_t addr;
481 uint32_t data = 0;
482
483 addr = (loff_t)pnum * ubi->peb_size;
484 err = ubi->mtd->write(ubi->mtd, addr, 4, &written, &data);
485 if (err) {
486 ubi_err("error %d while writing 4 bytes to PEB %d:0, written "
487 "%zd bytes", err, pnum, 0, written);
488 ubi_dbg_dump_stack();
489 return err;
490 }
491
492 addr += ubi->vid_hdr_aloffset;
493 err = ubi->mtd->write(ubi->mtd, addr, 4, &written, &data);
494 if (err) {
495 ubi_err("error %d while writing 4 bytes to PEB %d:%d, written "
496 "%zd bytes", err, pnum, ubi->vid_hdr_aloffset, written);
497 ubi_dbg_dump_stack();
498 return err;
499 }
500
501 return 0;
502}
503
504/**
457 * ubi_io_sync_erase - synchronously erase a physical eraseblock. 505 * ubi_io_sync_erase - synchronously erase a physical eraseblock.
458 * @ubi: UBI device description object 506 * @ubi: UBI device description object
459 * @pnum: physical eraseblock number to erase 507 * @pnum: physical eraseblock number to erase
@@ -484,6 +532,12 @@ int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int torture)
484 return -EROFS; 532 return -EROFS;
485 } 533 }
486 534
535 if (ubi->nor_flash) {
536 err = nor_erase_prepare(ubi, pnum);
537 if (err)
538 return err;
539 }
540
487 if (torture) { 541 if (torture) {
488 ret = torture_peb(ubi, pnum); 542 ret = torture_peb(ubi, pnum);
489 if (ret < 0) 543 if (ret < 0)
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index 64604e8809ec..6a5fe9633783 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -373,6 +373,7 @@ struct ubi_wl_entry;
373 * @vid_hdr_shift: contains @vid_hdr_offset - @vid_hdr_aloffset 373 * @vid_hdr_shift: contains @vid_hdr_offset - @vid_hdr_aloffset
374 * @bad_allowed: whether the MTD device admits of bad physical eraseblocks or 374 * @bad_allowed: whether the MTD device admits of bad physical eraseblocks or
375 * not 375 * not
376 * @nor_flash: non-zero if working on top of NOR flash
376 * @mtd: MTD device descriptor 377 * @mtd: MTD device descriptor
377 * 378 *
378 * @peb_buf1: a buffer of PEB size used for different purposes 379 * @peb_buf1: a buffer of PEB size used for different purposes
@@ -454,7 +455,8 @@ struct ubi_device {
454 int vid_hdr_offset; 455 int vid_hdr_offset;
455 int vid_hdr_aloffset; 456 int vid_hdr_aloffset;
456 int vid_hdr_shift; 457 int vid_hdr_shift;
457 int bad_allowed; 458 unsigned int bad_allowed:1;
459 unsigned int nor_flash:1;
458 struct mtd_info *mtd; 460 struct mtd_info *mtd;
459 461
460 void *peb_buf1; 462 void *peb_buf1;