summaryrefslogtreecommitdiffstats
path: root/drivers/mtd
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/devices/m25p80.c4
-rw-r--r--drivers/mtd/devices/mtd_dataflash.c1
-rw-r--r--drivers/mtd/devices/slram.c2
-rw-r--r--drivers/mtd/ftl.c2
-rw-r--r--drivers/mtd/maps/ixp2000.c2
-rw-r--r--drivers/mtd/mtd_blkdevs.c2
-rw-r--r--drivers/mtd/nand/cafe_nand.c4
-rw-r--r--drivers/mtd/nand/cmx270_nand.c4
-rw-r--r--drivers/mtd/ubi/debug.c32
-rw-r--r--drivers/mtd/ubi/debug.h2
-rw-r--r--drivers/mtd/ubi/eba.c2
-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.h5
15 files changed, 103 insertions, 32 deletions
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 00355862eba9..379c316f329e 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -909,13 +909,13 @@ static struct spi_driver m25p80_driver = {
};
-static int m25p80_init(void)
+static int __init m25p80_init(void)
{
return spi_register_driver(&m25p80_driver);
}
-static void m25p80_exit(void)
+static void __exit m25p80_exit(void)
{
spi_unregister_driver(&m25p80_driver);
}
diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c
index 70a7369d3211..93e3627be74c 100644
--- a/drivers/mtd/devices/mtd_dataflash.c
+++ b/drivers/mtd/devices/mtd_dataflash.c
@@ -966,3 +966,4 @@ module_exit(dataflash_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Andrew Victor, David Brownell");
MODULE_DESCRIPTION("MTD DataFlash driver");
+MODULE_ALIAS("spi:mtd_dataflash");
diff --git a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c
index 239500b0b751..3aa05cd18ea1 100644
--- a/drivers/mtd/devices/slram.c
+++ b/drivers/mtd/devices/slram.c
@@ -303,7 +303,7 @@ __setup("slram=", mtd_slram_setup);
#endif
-static int init_slram(void)
+static int __init init_slram(void)
{
char *devname;
int i;
diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c
index a790c062af1f..e56d6b42f020 100644
--- a/drivers/mtd/ftl.c
+++ b/drivers/mtd/ftl.c
@@ -1099,7 +1099,7 @@ static struct mtd_blktrans_ops ftl_tr = {
.owner = THIS_MODULE,
};
-static int init_ftl(void)
+static int __init init_ftl(void)
{
return register_mtd_blktrans(&ftl_tr);
}
diff --git a/drivers/mtd/maps/ixp2000.c b/drivers/mtd/maps/ixp2000.c
index d4fb9a3ab4df..1bdf0ee6d0b6 100644
--- a/drivers/mtd/maps/ixp2000.c
+++ b/drivers/mtd/maps/ixp2000.c
@@ -184,7 +184,7 @@ static int ixp2000_flash_probe(struct platform_device *dev)
info->map.bankwidth = 1;
/*
- * map_priv_2 is used to store a ptr to to the bank_setup routine
+ * map_priv_2 is used to store a ptr to the bank_setup routine
*/
info->map.map_priv_2 = (unsigned long) ixp_data->bank_setup;
diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c
index 7baba40c1ed2..0acbf4f5be50 100644
--- a/drivers/mtd/mtd_blkdevs.c
+++ b/drivers/mtd/mtd_blkdevs.c
@@ -210,7 +210,7 @@ static int blktrans_ioctl(struct block_device *bdev, fmode_t mode,
}
}
-static struct block_device_operations mtd_blktrans_ops = {
+static const struct block_device_operations mtd_blktrans_ops = {
.owner = THIS_MODULE,
.open = blktrans_open,
.release = blktrans_release,
diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c
index a70f40e161d7..c828d9ac7bd7 100644
--- a/drivers/mtd/nand/cafe_nand.c
+++ b/drivers/mtd/nand/cafe_nand.c
@@ -903,12 +903,12 @@ static struct pci_driver cafe_nand_pci_driver = {
.resume = cafe_nand_resume,
};
-static int cafe_nand_init(void)
+static int __init cafe_nand_init(void)
{
return pci_register_driver(&cafe_nand_pci_driver);
}
-static void cafe_nand_exit(void)
+static void __exit cafe_nand_exit(void)
{
pci_unregister_driver(&cafe_nand_pci_driver);
}
diff --git a/drivers/mtd/nand/cmx270_nand.c b/drivers/mtd/nand/cmx270_nand.c
index 10081e656a6f..826cacffcefc 100644
--- a/drivers/mtd/nand/cmx270_nand.c
+++ b/drivers/mtd/nand/cmx270_nand.c
@@ -147,7 +147,7 @@ static int cmx270_device_ready(struct mtd_info *mtd)
/*
* Main initialization routine
*/
-static int cmx270_init(void)
+static int __init cmx270_init(void)
{
struct nand_chip *this;
const char *part_type;
@@ -261,7 +261,7 @@ module_init(cmx270_init);
/*
* Clean up routine
*/
-static void cmx270_cleanup(void)
+static void __exit cmx270_cleanup(void)
{
/* Release resources, unregister device */
nand_release(cmx270_nand_mtd);
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)
printk(KERN_DEBUG "\t1st 16 characters of name: %s\n", nm);
}
+/**
+ * ubi_dbg_dump_flash - dump a region of flash.
+ * @ubi: UBI device description object
+ * @pnum: the physical eraseblock number to dump
+ * @offset: the starting offset within the physical eraseblock to dump
+ * @len: the length of the region to dump
+ */
+void ubi_dbg_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len)
+{
+ int err;
+ size_t read;
+ void *buf;
+ loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
+
+ buf = vmalloc(len);
+ if (!buf)
+ return;
+ err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf);
+ if (err && err != -EUCLEAN) {
+ ubi_err("error %d while reading %d bytes from PEB %d:%d, "
+ "read %zd bytes", err, len, pnum, offset, read);
+ goto out;
+ }
+
+ dbg_msg("dumping %d bytes of data from PEB %d, offset %d",
+ len, pnum, offset);
+ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf, len, 1);
+out:
+ vfree(buf);
+ return;
+}
+
#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);
void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv);
void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type);
void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req);
+void ubi_dbg_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len);
#ifdef CONFIG_MTD_UBI_DEBUG_MSG
/* General debugging messages */
@@ -167,6 +168,7 @@ static inline int ubi_dbg_is_erase_failure(void)
#define ubi_dbg_dump_sv(sv) ({})
#define ubi_dbg_dump_seb(seb, type) ({})
#define ubi_dbg_dump_mkvol_req(req) ({})
+#define ubi_dbg_dump_flash(ubi, pnum, offset, len) ({})
#define UBI_IO_DEBUG 0
#define DBG_DISABLE_BGT 0
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
index e4d9ef0c965a..9f87c99189a9 100644
--- a/drivers/mtd/ubi/eba.c
+++ b/drivers/mtd/ubi/eba.c
@@ -1065,7 +1065,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
}
/*
- * Now we have got to calculate how much data we have to to copy. In
+ * Now we have got to calculate how much data we have to copy. In
* case of a static volume it is fairly easy - the VID header contains
* the data size. In case of a dynamic volume it is more difficult - we
* have to read the contents, cut 0xFF bytes from the end and copy only
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,
ubi_err("error %d while writing %d bytes to PEB %d:%d, written "
"%zd bytes", err, len, pnum, offset, written);
ubi_dbg_dump_stack();
+ ubi_dbg_dump_flash(ubi, pnum, offset, len);
} else
ubi_assert(written == len);
@@ -475,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;
+ 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, 0, 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, ubi->vid_hdr_aloffset, 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;
}
/**
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,
dbg_bld("add to free: PEB %d, EC %d", pnum, ec);
else if (list == &si->erase)
dbg_bld("add to erase: PEB %d, EC %d", pnum, ec);
- else if (list == &si->corr)
+ else if (list == &si->corr) {
dbg_bld("add to corrupted: PEB %d, EC %d", pnum, ec);
- else if (list == &si->alien)
+ si->corr_count += 1;
+ } else if (list == &si->alien)
dbg_bld("add to alien: PEB %d, EC %d", pnum, ec);
else
BUG();
@@ -864,7 +865,9 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
}
}
- /* Both UBI headers seem to be fine */
+ if (ec_corr)
+ ubi_warn("valid VID header but corrupted EC header at PEB %d",
+ pnum);
err = ubi_scan_add_used(ubi, si, pnum, ec, vidh, bitflips);
if (err)
return err;
@@ -936,6 +939,19 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
ubi_msg("empty MTD device detected");
/*
+ * Few corrupted PEBs are not a problem and may be just a result of
+ * unclean reboots. However, many of them may indicate some problems
+ * with the flash HW or driver. Print a warning in this case.
+ */
+ if (si->corr_count >= 8 || si->corr_count >= ubi->peb_count / 4) {
+ ubi_warn("%d PEBs are corrupted", si->corr_count);
+ printk(KERN_WARNING "corrupted PEBs are:");
+ list_for_each_entry(seb, &si->corr, u.list)
+ printk(KERN_CONT " %d", seb->pnum);
+ printk(KERN_CONT "\n");
+ }
+
+ /*
* In case of unknown erase counter we use the mean erase counter
* value.
*/
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 {
* @mean_ec: mean erase counter value
* @ec_sum: a temporary variable used when calculating @mean_ec
* @ec_count: a temporary variable used when calculating @mean_ec
+ * @corr_count: count of corrupted PEBs
* @image_seq_set: indicates @ubi->image_seq is known
*
* This data structure contains the result of scanning and may be used by other
@@ -125,6 +126,7 @@ struct ubi_scan_info {
int mean_ec;
uint64_t ec_sum;
int ec_count;
+ int corr_count;
int image_seq_set;
};
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index 6a5fe9633783..1af08178defd 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -570,7 +570,7 @@ void ubi_do_get_volume_info(struct ubi_device *ubi, struct ubi_volume *vol,
/*
* ubi_rb_for_each_entry - walk an RB-tree.
- * @rb: a pointer to type 'struct rb_node' to to use as a loop counter
+ * @rb: a pointer to type 'struct rb_node' to use as a loop counter
* @pos: a pointer to RB-tree entry type to use as a loop counter
* @root: RB-tree's root
* @member: the name of the 'struct rb_node' within the RB-tree entry
@@ -579,7 +579,8 @@ void ubi_do_get_volume_info(struct ubi_device *ubi, struct ubi_volume *vol,
for (rb = rb_first(root), \
pos = (rb ? container_of(rb, typeof(*pos), member) : NULL); \
rb; \
- rb = rb_next(rb), pos = container_of(rb, typeof(*pos), member))
+ rb = rb_next(rb), \
+ pos = (rb ? container_of(rb, typeof(*pos), member) : NULL))
/**
* ubi_zalloc_vid_hdr - allocate a volume identifier header object.