aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-09-21 11:13:55 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-09-21 11:13:55 -0400
commit0b887ef19d7319263f31babc2a7855bc92865c0e (patch)
treeeb9aaed5f530a5ad3c9cd28cbec1fade63a993a9 /drivers
parent44040f107e64d689ccd3211ac62c6bc44f3f0775 (diff)
parentde75c771b4cc4da963164a538a8448128301bc35 (diff)
Merge branch 'linux-next' of git://git.infradead.org/ubi-2.6
* 'linux-next' of git://git.infradead.org/ubi-2.6: UBI: improve NOR flash erasure quirk UBI: introduce flash dump helper UBI: eliminate possible undefined behaviour UBI: print a warning if too many PEBs are corrupted UBI: amend NOR flash pre-erase quirk UBI: print a message if ECH is corrupted and VIDH is ok
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mtd/ubi/debug.c32
-rw-r--r--drivers/mtd/ubi/debug.h2
-rw-r--r--drivers/mtd/ubi/io.c49
-rw-r--r--drivers/mtd/ubi/scan.c22
-rw-r--r--drivers/mtd/ubi/scan.h2
-rw-r--r--drivers/mtd/ubi/ubi.h3
6 files changed, 90 insertions, 20 deletions
diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c
index 54b0186915fb..4876977e52cb 100644
--- a/drivers/mtd/ubi/debug.c
+++ b/drivers/mtd/ubi/debug.c
@@ -196,4 +196,36 @@ void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req)
196 printk(KERN_DEBUG "\t1st 16 characters of name: %s\n", nm); 196 printk(KERN_DEBUG "\t1st 16 characters of name: %s\n", nm);
197} 197}
198 198
199/**
200 * ubi_dbg_dump_flash - dump a region of flash.
201 * @ubi: UBI device description object
202 * @pnum: the physical eraseblock number to dump
203 * @offset: the starting offset within the physical eraseblock to dump
204 * @len: the length of the region to dump
205 */
206void ubi_dbg_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len)
207{
208 int err;
209 size_t read;
210 void *buf;
211 loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
212
213 buf = vmalloc(len);
214 if (!buf)
215 return;
216 err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf);
217 if (err && err != -EUCLEAN) {
218 ubi_err("error %d while reading %d bytes from PEB %d:%d, "
219 "read %zd bytes", err, len, pnum, offset, read);
220 goto out;
221 }
222
223 dbg_msg("dumping %d bytes of data from PEB %d, offset %d",
224 len, pnum, offset);
225 print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf, len, 1);
226out:
227 vfree(buf);
228 return;
229}
230
199#endif /* CONFIG_MTD_UBI_DEBUG */ 231#endif /* CONFIG_MTD_UBI_DEBUG */
diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h
index a4da7a09b949..f30bcb372c05 100644
--- a/drivers/mtd/ubi/debug.h
+++ b/drivers/mtd/ubi/debug.h
@@ -55,6 +55,7 @@ void ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx);
55void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv); 55void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv);
56void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type); 56void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type);
57void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req); 57void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req);
58void ubi_dbg_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len);
58 59
59#ifdef CONFIG_MTD_UBI_DEBUG_MSG 60#ifdef CONFIG_MTD_UBI_DEBUG_MSG
60/* General debugging messages */ 61/* General debugging messages */
@@ -167,6 +168,7 @@ static inline int ubi_dbg_is_erase_failure(void)
167#define ubi_dbg_dump_sv(sv) ({}) 168#define ubi_dbg_dump_sv(sv) ({})
168#define ubi_dbg_dump_seb(seb, type) ({}) 169#define ubi_dbg_dump_seb(seb, type) ({})
169#define ubi_dbg_dump_mkvol_req(req) ({}) 170#define ubi_dbg_dump_mkvol_req(req) ({})
171#define ubi_dbg_dump_flash(ubi, pnum, offset, len) ({})
170 172
171#define UBI_IO_DEBUG 0 173#define UBI_IO_DEBUG 0
172#define DBG_DISABLE_BGT 0 174#define DBG_DISABLE_BGT 0
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index 4cb69925d8d9..8aa51e7a6a7d 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -269,6 +269,7 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
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 ubi_dbg_dump_flash(ubi, pnum, offset, len);
272 } else 273 } else
273 ubi_assert(written == len); 274 ubi_assert(written == len);
274 275
@@ -475,30 +476,46 @@ out:
475 */ 476 */
476static int nor_erase_prepare(struct ubi_device *ubi, int pnum) 477static int nor_erase_prepare(struct ubi_device *ubi, int pnum)
477{ 478{
478 int err; 479 int err, err1;
479 size_t written; 480 size_t written;
480 loff_t addr; 481 loff_t addr;
481 uint32_t data = 0; 482 uint32_t data = 0;
483 struct ubi_vid_hdr vid_hdr;
482 484
483 addr = (loff_t)pnum * ubi->peb_size; 485 addr = (loff_t)pnum * ubi->peb_size + ubi->vid_hdr_aloffset;
484 err = ubi->mtd->write(ubi->mtd, addr, 4, &written, (void *)&data); 486 err = ubi->mtd->write(ubi->mtd, addr, 4, &written, (void *)&data);
485 if (err) { 487 if (!err) {
486 ubi_err("error %d while writing 4 bytes to PEB %d:%d, written " 488 addr -= ubi->vid_hdr_aloffset;
487 "%zd bytes", err, pnum, 0, written); 489 err = ubi->mtd->write(ubi->mtd, addr, 4, &written,
488 ubi_dbg_dump_stack(); 490 (void *)&data);
489 return err; 491 if (!err)
492 return 0;
490 } 493 }
491 494
492 addr += ubi->vid_hdr_aloffset; 495 /*
493 err = ubi->mtd->write(ubi->mtd, addr, 4, &written, (void *)&data); 496 * We failed to write to the media. This was observed with Spansion
494 if (err) { 497 * S29GL512N NOR flash. Most probably the eraseblock erasure was
495 ubi_err("error %d while writing 4 bytes to PEB %d:%d, written " 498 * interrupted at a very inappropriate moment, so it became unwritable.
496 "%zd bytes", err, pnum, ubi->vid_hdr_aloffset, written); 499 * In this case we probably anyway have garbage in this PEB.
497 ubi_dbg_dump_stack(); 500 */
498 return err; 501 err1 = ubi_io_read_vid_hdr(ubi, pnum, &vid_hdr, 0);
499 } 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;
500 509
501 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;
502} 519}
503 520
504/** 521/**
diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c
index b847745394b4..e7161adc419d 100644
--- a/drivers/mtd/ubi/scan.c
+++ b/drivers/mtd/ubi/scan.c
@@ -75,9 +75,10 @@ static int add_to_list(struct ubi_scan_info *si, int pnum, int ec,
75 dbg_bld("add to free: PEB %d, EC %d", pnum, ec); 75 dbg_bld("add to free: PEB %d, EC %d", pnum, ec);
76 else if (list == &si->erase) 76 else if (list == &si->erase)
77 dbg_bld("add to erase: PEB %d, EC %d", pnum, ec); 77 dbg_bld("add to erase: PEB %d, EC %d", pnum, ec);
78 else if (list == &si->corr) 78 else if (list == &si->corr) {
79 dbg_bld("add to corrupted: PEB %d, EC %d", pnum, ec); 79 dbg_bld("add to corrupted: PEB %d, EC %d", pnum, ec);
80 else if (list == &si->alien) 80 si->corr_count += 1;
81 } else if (list == &si->alien)
81 dbg_bld("add to alien: PEB %d, EC %d", pnum, ec); 82 dbg_bld("add to alien: PEB %d, EC %d", pnum, ec);
82 else 83 else
83 BUG(); 84 BUG();
@@ -864,7 +865,9 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
864 } 865 }
865 } 866 }
866 867
867 /* Both UBI headers seem to be fine */ 868 if (ec_corr)
869 ubi_warn("valid VID header but corrupted EC header at PEB %d",
870 pnum);
868 err = ubi_scan_add_used(ubi, si, pnum, ec, vidh, bitflips); 871 err = ubi_scan_add_used(ubi, si, pnum, ec, vidh, bitflips);
869 if (err) 872 if (err)
870 return err; 873 return err;
@@ -936,6 +939,19 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
936 ubi_msg("empty MTD device detected"); 939 ubi_msg("empty MTD device detected");
937 940
938 /* 941 /*
942 * Few corrupted PEBs are not a problem and may be just a result of
943 * unclean reboots. However, many of them may indicate some problems
944 * with the flash HW or driver. Print a warning in this case.
945 */
946 if (si->corr_count >= 8 || si->corr_count >= ubi->peb_count / 4) {
947 ubi_warn("%d PEBs are corrupted", si->corr_count);
948 printk(KERN_WARNING "corrupted PEBs are:");
949 list_for_each_entry(seb, &si->corr, u.list)
950 printk(KERN_CONT " %d", seb->pnum);
951 printk(KERN_CONT "\n");
952 }
953
954 /*
939 * In case of unknown erase counter we use the mean erase counter 955 * In case of unknown erase counter we use the mean erase counter
940 * value. 956 * value.
941 */ 957 */
diff --git a/drivers/mtd/ubi/scan.h b/drivers/mtd/ubi/scan.h
index 1017cf12def5..bab31695dace 100644
--- a/drivers/mtd/ubi/scan.h
+++ b/drivers/mtd/ubi/scan.h
@@ -102,6 +102,7 @@ struct ubi_scan_volume {
102 * @mean_ec: mean erase counter value 102 * @mean_ec: mean erase counter value
103 * @ec_sum: a temporary variable used when calculating @mean_ec 103 * @ec_sum: a temporary variable used when calculating @mean_ec
104 * @ec_count: a temporary variable used when calculating @mean_ec 104 * @ec_count: a temporary variable used when calculating @mean_ec
105 * @corr_count: count of corrupted PEBs
105 * @image_seq_set: indicates @ubi->image_seq is known 106 * @image_seq_set: indicates @ubi->image_seq is known
106 * 107 *
107 * This data structure contains the result of scanning and may be used by other 108 * This data structure contains the result of scanning and may be used by other
@@ -125,6 +126,7 @@ struct ubi_scan_info {
125 int mean_ec; 126 int mean_ec;
126 uint64_t ec_sum; 127 uint64_t ec_sum;
127 int ec_count; 128 int ec_count;
129 int corr_count;
128 int image_seq_set; 130 int image_seq_set;
129}; 131};
130 132
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index 6a5fe9633783..c290f51dd178 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -579,7 +579,8 @@ void ubi_do_get_volume_info(struct ubi_device *ubi, struct ubi_volume *vol,
579 for (rb = rb_first(root), \ 579 for (rb = rb_first(root), \
580 pos = (rb ? container_of(rb, typeof(*pos), member) : NULL); \ 580 pos = (rb ? container_of(rb, typeof(*pos), member) : NULL); \
581 rb; \ 581 rb; \
582 rb = rb_next(rb), pos = container_of(rb, typeof(*pos), member)) 582 rb = rb_next(rb), \
583 pos = (rb ? container_of(rb, typeof(*pos), member) : NULL))
583 584
584/** 585/**
585 * ubi_zalloc_vid_hdr - allocate a volume identifier header object. 586 * ubi_zalloc_vid_hdr - allocate a volume identifier header object.