UBI: improve NOR flash erasure quirk
authorArtem Bityutskiy <Artem.Bityutskiy@nokia.com>
Fri, 24 Jul 2009 13:18:04 +0000 (16:18 +0300)
committerArtem Bityutskiy <Artem.Bityutskiy@nokia.com>
Fri, 14 Aug 2009 17:02:20 +0000 (20:02 +0300)
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.

drivers/mtd/ubi/io.c

index b693138fc51939dd3ceffdbaf0aaa67d975f362f..8aa51e7a6a7df515e25c628b767b18a2e3838c50 100644 (file)
@@ -476,30 +476,46 @@ out:
  */
 static int nor_erase_prepare(struct ubi_device *ubi, int pnum)
 {
-       int err;
+       int err, err1;
        size_t written;
        loff_t addr;
        uint32_t data = 0;
+       struct ubi_vid_hdr vid_hdr;
 
        addr = (loff_t)pnum * ubi->peb_size + ubi->vid_hdr_aloffset;
        err = ubi->mtd->write(ubi->mtd, addr, 4, &written, (void *)&data);
-       if (err) {
-               ubi_err("error %d while writing 4 bytes to PEB %d:%d, written "
-                       "%zd bytes", err, pnum, ubi->vid_hdr_aloffset, written);
-               ubi_dbg_dump_stack();
-               return err;
+       if (!err) {
+               addr -= ubi->vid_hdr_aloffset;
+               err = ubi->mtd->write(ubi->mtd, addr, 4, &written,
+                                     (void *)&data);
+               if (!err)
+                       return 0;
        }
 
-       addr -= ubi->vid_hdr_aloffset;
-       err = ubi->mtd->write(ubi->mtd, addr, 4, &written, (void *)&data);
-       if (err) {
-               ubi_err("error %d while writing 4 bytes to PEB %d:%d, written "
-                       "%zd bytes", err, pnum, 0, written);
-               ubi_dbg_dump_stack();
-               return err;
-       }
+       /*
+        * We failed to write to the media. This was observed with Spansion
+        * S29GL512N NOR flash. Most probably the eraseblock erasure was
+        * interrupted at a very inappropriate moment, so it became unwritable.
+        * In this case we probably anyway have garbage in this PEB.
+        */
+       err1 = ubi_io_read_vid_hdr(ubi, pnum, &vid_hdr, 0);
+       if (err1 == UBI_IO_BAD_VID_HDR)
+               /*
+                * The VID header is corrupted, so we can safely erase this
+                * PEB and not afraid that it will be treated as a valid PEB in
+                * case of an unclean reboot.
+                */
+               return 0;
 
-       return 0;
+       /*
+        * The PEB contains a valid VID header, but we cannot invalidate it.
+        * Supposedly the flash media or the driver is screwed up, so return an
+        * error.
+        */
+       ubi_err("cannot invalidate PEB %d, write returned %d read returned %d",
+               pnum, err, err1);
+       ubi_dbg_dump_flash(ubi, pnum, 0, ubi->peb_size);
+       return -EIO;
 }
 
 /**