Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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.

+31 -15
+31 -15
drivers/mtd/ubi/io.c
··· 476 476 */ 477 477 static int nor_erase_prepare(struct ubi_device *ubi, int pnum) 478 478 { 479 - int err; 479 + int err, err1; 480 480 size_t written; 481 481 loff_t addr; 482 482 uint32_t data = 0; 483 + struct ubi_vid_hdr vid_hdr; 483 484 484 485 addr = (loff_t)pnum * ubi->peb_size + ubi->vid_hdr_aloffset; 485 486 err = ubi->mtd->write(ubi->mtd, addr, 4, &written, (void *)&data); 486 - if (err) { 487 - ubi_err("error %d while writing 4 bytes to PEB %d:%d, written " 488 - "%zd bytes", err, pnum, ubi->vid_hdr_aloffset, written); 489 - ubi_dbg_dump_stack(); 490 - return err; 487 + if (!err) { 488 + addr -= ubi->vid_hdr_aloffset; 489 + err = ubi->mtd->write(ubi->mtd, addr, 4, &written, 490 + (void *)&data); 491 + if (!err) 492 + return 0; 491 493 } 492 494 493 - addr -= ubi->vid_hdr_aloffset; 494 - err = ubi->mtd->write(ubi->mtd, addr, 4, &written, (void *)&data); 495 - if (err) { 496 - ubi_err("error %d while writing 4 bytes to PEB %d:%d, written " 497 - "%zd bytes", err, pnum, 0, written); 498 - ubi_dbg_dump_stack(); 499 - return err; 500 - } 495 + /* 496 + * We failed to write to the media. This was observed with Spansion 497 + * S29GL512N NOR flash. Most probably the eraseblock erasure was 498 + * interrupted at a very inappropriate moment, so it became unwritable. 499 + * In this case we probably anyway have garbage in this PEB. 500 + */ 501 + err1 = ubi_io_read_vid_hdr(ubi, pnum, &vid_hdr, 0); 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 /**