aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/ubi/io.c
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 /drivers/mtd/ubi/io.c
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>
Diffstat (limited to 'drivers/mtd/ubi/io.c')
-rw-r--r--drivers/mtd/ubi/io.c58
1 files changed, 56 insertions, 2 deletions
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)