diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-21 11:13:55 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-21 11:13:55 -0400 |
commit | 0b887ef19d7319263f31babc2a7855bc92865c0e (patch) | |
tree | eb9aaed5f530a5ad3c9cd28cbec1fade63a993a9 /drivers | |
parent | 44040f107e64d689ccd3211ac62c6bc44f3f0775 (diff) | |
parent | de75c771b4cc4da963164a538a8448128301bc35 (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.c | 32 | ||||
-rw-r--r-- | drivers/mtd/ubi/debug.h | 2 | ||||
-rw-r--r-- | drivers/mtd/ubi/io.c | 49 | ||||
-rw-r--r-- | drivers/mtd/ubi/scan.c | 22 | ||||
-rw-r--r-- | drivers/mtd/ubi/scan.h | 2 | ||||
-rw-r--r-- | drivers/mtd/ubi/ubi.h | 3 |
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 | */ | ||
206 | void 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); | ||
226 | out: | ||
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); | |||
55 | void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv); | 55 | void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv); |
56 | void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type); | 56 | void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type); |
57 | void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req); | 57 | void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req); |
58 | void 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 | */ |
476 | static int nor_erase_prepare(struct ubi_device *ubi, int pnum) | 477 | static 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. |