0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0011
0012 #include <linux/init.h>
0013 #include <linux/module.h>
0014 #include <linux/moduleparam.h>
0015 #include <linux/err.h>
0016 #include <linux/mtd/mtd.h>
0017 #include <linux/slab.h>
0018 #include <linux/sched.h>
0019
0020 #include "mtd_test.h"
0021
0022 static int dev = -EINVAL;
0023 module_param(dev, int, S_IRUGO);
0024 MODULE_PARM_DESC(dev, "MTD device number to use");
0025
0026 static struct mtd_info *mtd;
0027 static unsigned char *iobuf;
0028 static unsigned char *iobuf1;
0029 static unsigned char *bbt;
0030
0031 static int pgsize;
0032 static int ebcnt;
0033 static int pgcnt;
0034
0035 static int read_eraseblock_by_page(int ebnum)
0036 {
0037 int i, ret, err = 0;
0038 loff_t addr = (loff_t)ebnum * mtd->erasesize;
0039 void *buf = iobuf;
0040 void *oobbuf = iobuf1;
0041
0042 for (i = 0; i < pgcnt; i++) {
0043 memset(buf, 0 , pgsize);
0044 ret = mtdtest_read(mtd, addr, pgsize, buf);
0045 if (ret) {
0046 if (!err)
0047 err = ret;
0048 }
0049 if (mtd->oobsize) {
0050 struct mtd_oob_ops ops;
0051
0052 ops.mode = MTD_OPS_PLACE_OOB;
0053 ops.len = 0;
0054 ops.retlen = 0;
0055 ops.ooblen = mtd->oobsize;
0056 ops.oobretlen = 0;
0057 ops.ooboffs = 0;
0058 ops.datbuf = NULL;
0059 ops.oobbuf = oobbuf;
0060 ret = mtd_read_oob(mtd, addr, &ops);
0061 if ((ret && !mtd_is_bitflip(ret)) ||
0062 ops.oobretlen != mtd->oobsize) {
0063 pr_err("error: read oob failed at "
0064 "%#llx\n", (long long)addr);
0065 if (!err)
0066 err = ret;
0067 if (!err)
0068 err = -EINVAL;
0069 }
0070 oobbuf += mtd->oobsize;
0071 }
0072 addr += pgsize;
0073 buf += pgsize;
0074 }
0075
0076 return err;
0077 }
0078
0079 static void dump_eraseblock(int ebnum)
0080 {
0081 int i, j, n;
0082 char line[128];
0083 int pg, oob;
0084
0085 pr_info("dumping eraseblock %d\n", ebnum);
0086 n = mtd->erasesize;
0087 for (i = 0; i < n;) {
0088 char *p = line;
0089
0090 p += sprintf(p, "%05x: ", i);
0091 for (j = 0; j < 32 && i < n; j++, i++)
0092 p += sprintf(p, "%02x", (unsigned int)iobuf[i]);
0093 printk(KERN_CRIT "%s\n", line);
0094 cond_resched();
0095 }
0096 if (!mtd->oobsize)
0097 return;
0098 pr_info("dumping oob from eraseblock %d\n", ebnum);
0099 n = mtd->oobsize;
0100 for (pg = 0, i = 0; pg < pgcnt; pg++)
0101 for (oob = 0; oob < n;) {
0102 char *p = line;
0103
0104 p += sprintf(p, "%05x: ", i);
0105 for (j = 0; j < 32 && oob < n; j++, oob++, i++)
0106 p += sprintf(p, "%02x",
0107 (unsigned int)iobuf1[i]);
0108 printk(KERN_CRIT "%s\n", line);
0109 cond_resched();
0110 }
0111 }
0112
0113 static int __init mtd_readtest_init(void)
0114 {
0115 uint64_t tmp;
0116 int err, i;
0117
0118 printk(KERN_INFO "\n");
0119 printk(KERN_INFO "=================================================\n");
0120
0121 if (dev < 0) {
0122 pr_info("Please specify a valid mtd-device via module parameter\n");
0123 return -EINVAL;
0124 }
0125
0126 pr_info("MTD device: %d\n", dev);
0127
0128 mtd = get_mtd_device(NULL, dev);
0129 if (IS_ERR(mtd)) {
0130 err = PTR_ERR(mtd);
0131 pr_err("error: Cannot get MTD device\n");
0132 return err;
0133 }
0134
0135 if (mtd->writesize == 1) {
0136 pr_info("not NAND flash, assume page size is 512 "
0137 "bytes.\n");
0138 pgsize = 512;
0139 } else
0140 pgsize = mtd->writesize;
0141
0142 tmp = mtd->size;
0143 do_div(tmp, mtd->erasesize);
0144 ebcnt = tmp;
0145 pgcnt = mtd->erasesize / pgsize;
0146
0147 pr_info("MTD device size %llu, eraseblock size %u, "
0148 "page size %u, count of eraseblocks %u, pages per "
0149 "eraseblock %u, OOB size %u\n",
0150 (unsigned long long)mtd->size, mtd->erasesize,
0151 pgsize, ebcnt, pgcnt, mtd->oobsize);
0152
0153 err = -ENOMEM;
0154 iobuf = kmalloc(mtd->erasesize, GFP_KERNEL);
0155 if (!iobuf)
0156 goto out;
0157 iobuf1 = kmalloc(mtd->erasesize, GFP_KERNEL);
0158 if (!iobuf1)
0159 goto out;
0160
0161 bbt = kzalloc(ebcnt, GFP_KERNEL);
0162 if (!bbt)
0163 goto out;
0164 err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt);
0165 if (err)
0166 goto out;
0167
0168
0169 pr_info("testing page read\n");
0170 for (i = 0; i < ebcnt; ++i) {
0171 int ret;
0172
0173 if (bbt[i])
0174 continue;
0175 ret = read_eraseblock_by_page(i);
0176 if (ret) {
0177 dump_eraseblock(i);
0178 if (!err)
0179 err = ret;
0180 }
0181
0182 ret = mtdtest_relax();
0183 if (ret) {
0184 err = ret;
0185 goto out;
0186 }
0187 }
0188
0189 if (err)
0190 pr_info("finished with errors\n");
0191 else
0192 pr_info("finished\n");
0193
0194 out:
0195
0196 kfree(iobuf);
0197 kfree(iobuf1);
0198 kfree(bbt);
0199 put_mtd_device(mtd);
0200 if (err)
0201 pr_info("error %d occurred\n", err);
0202 printk(KERN_INFO "=================================================\n");
0203 return err;
0204 }
0205 module_init(mtd_readtest_init);
0206
0207 static void __exit mtd_readtest_exit(void)
0208 {
0209 return;
0210 }
0211 module_exit(mtd_readtest_exit);
0212
0213 MODULE_DESCRIPTION("Read test module");
0214 MODULE_AUTHOR("Adrian Hunter");
0215 MODULE_LICENSE("GPL");