0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0011
0012 #include <asm/div64.h>
0013 #include <linux/init.h>
0014 #include <linux/module.h>
0015 #include <linux/moduleparam.h>
0016 #include <linux/err.h>
0017 #include <linux/mtd/mtd.h>
0018 #include <linux/slab.h>
0019 #include <linux/sched.h>
0020 #include <linux/random.h>
0021
0022 #include "mtd_test.h"
0023
0024 static int dev = -EINVAL;
0025 module_param(dev, int, S_IRUGO);
0026 MODULE_PARM_DESC(dev, "MTD device number to use");
0027
0028 static struct mtd_info *mtd;
0029 static unsigned char *twopages;
0030 static unsigned char *writebuf;
0031 static unsigned char *boundary;
0032 static unsigned char *bbt;
0033
0034 static int pgsize;
0035 static int bufsize;
0036 static int ebcnt;
0037 static int pgcnt;
0038 static int errcnt;
0039 static struct rnd_state rnd_state;
0040
0041 static int write_eraseblock(int ebnum)
0042 {
0043 loff_t addr = (loff_t)ebnum * mtd->erasesize;
0044
0045 prandom_bytes_state(&rnd_state, writebuf, mtd->erasesize);
0046 cond_resched();
0047 return mtdtest_write(mtd, addr, mtd->erasesize, writebuf);
0048 }
0049
0050 static int verify_eraseblock(int ebnum)
0051 {
0052 uint32_t j;
0053 int err = 0, i;
0054 loff_t addr0, addrn;
0055 loff_t addr = (loff_t)ebnum * mtd->erasesize;
0056
0057 addr0 = 0;
0058 for (i = 0; i < ebcnt && bbt[i]; ++i)
0059 addr0 += mtd->erasesize;
0060
0061 addrn = mtd->size;
0062 for (i = 0; i < ebcnt && bbt[ebcnt - i - 1]; ++i)
0063 addrn -= mtd->erasesize;
0064
0065 prandom_bytes_state(&rnd_state, writebuf, mtd->erasesize);
0066 for (j = 0; j < pgcnt - 1; ++j, addr += pgsize) {
0067
0068 err = mtdtest_read(mtd, addr0, bufsize, twopages);
0069 if (err)
0070 return err;
0071 err = mtdtest_read(mtd, addrn - bufsize, bufsize, twopages);
0072 if (err)
0073 return err;
0074 memset(twopages, 0, bufsize);
0075 err = mtdtest_read(mtd, addr, bufsize, twopages);
0076 if (err)
0077 break;
0078 if (memcmp(twopages, writebuf + (j * pgsize), bufsize)) {
0079 pr_err("error: verify failed at %#llx\n",
0080 (long long)addr);
0081 errcnt += 1;
0082 }
0083 }
0084
0085 if (addr <= addrn - pgsize - pgsize && !bbt[ebnum + 1]) {
0086 struct rnd_state old_state = rnd_state;
0087
0088
0089 err = mtdtest_read(mtd, addr0, bufsize, twopages);
0090 if (err)
0091 return err;
0092 err = mtdtest_read(mtd, addrn - bufsize, bufsize, twopages);
0093 if (err)
0094 return err;
0095 memset(twopages, 0, bufsize);
0096 err = mtdtest_read(mtd, addr, bufsize, twopages);
0097 if (err)
0098 return err;
0099 memcpy(boundary, writebuf + mtd->erasesize - pgsize, pgsize);
0100 prandom_bytes_state(&rnd_state, boundary + pgsize, pgsize);
0101 if (memcmp(twopages, boundary, bufsize)) {
0102 pr_err("error: verify failed at %#llx\n",
0103 (long long)addr);
0104 errcnt += 1;
0105 }
0106 rnd_state = old_state;
0107 }
0108 return err;
0109 }
0110
0111 static int crosstest(void)
0112 {
0113 int err = 0, i;
0114 loff_t addr, addr0, addrn;
0115 unsigned char *pp1, *pp2, *pp3, *pp4;
0116
0117 pr_info("crosstest\n");
0118 pp1 = kcalloc(pgsize, 4, GFP_KERNEL);
0119 if (!pp1)
0120 return -ENOMEM;
0121 pp2 = pp1 + pgsize;
0122 pp3 = pp2 + pgsize;
0123 pp4 = pp3 + pgsize;
0124
0125 addr0 = 0;
0126 for (i = 0; i < ebcnt && bbt[i]; ++i)
0127 addr0 += mtd->erasesize;
0128
0129 addrn = mtd->size;
0130 for (i = 0; i < ebcnt && bbt[ebcnt - i - 1]; ++i)
0131 addrn -= mtd->erasesize;
0132
0133
0134 addr = addrn - pgsize - pgsize;
0135 err = mtdtest_read(mtd, addr, pgsize, pp1);
0136 if (err) {
0137 kfree(pp1);
0138 return err;
0139 }
0140
0141
0142 addr = addrn - pgsize - pgsize - pgsize;
0143 err = mtdtest_read(mtd, addr, pgsize, pp1);
0144 if (err) {
0145 kfree(pp1);
0146 return err;
0147 }
0148
0149
0150 addr = addr0;
0151 pr_info("reading page at %#llx\n", (long long)addr);
0152 err = mtdtest_read(mtd, addr, pgsize, pp2);
0153 if (err) {
0154 kfree(pp1);
0155 return err;
0156 }
0157
0158
0159 addr = addrn - pgsize;
0160 pr_info("reading page at %#llx\n", (long long)addr);
0161 err = mtdtest_read(mtd, addr, pgsize, pp3);
0162 if (err) {
0163 kfree(pp1);
0164 return err;
0165 }
0166
0167
0168 addr = addr0;
0169 pr_info("reading page at %#llx\n", (long long)addr);
0170 err = mtdtest_read(mtd, addr, pgsize, pp4);
0171 if (err) {
0172 kfree(pp1);
0173 return err;
0174 }
0175
0176
0177 pr_info("verifying pages read at %#llx match\n",
0178 (long long)addr0);
0179 if (memcmp(pp2, pp4, pgsize)) {
0180 pr_err("verify failed!\n");
0181 errcnt += 1;
0182 } else if (!err)
0183 pr_info("crosstest ok\n");
0184 kfree(pp1);
0185 return err;
0186 }
0187
0188 static int erasecrosstest(void)
0189 {
0190 int err = 0, i, ebnum, ebnum2;
0191 loff_t addr0;
0192 char *readbuf = twopages;
0193
0194 pr_info("erasecrosstest\n");
0195
0196 ebnum = 0;
0197 addr0 = 0;
0198 for (i = 0; i < ebcnt && bbt[i]; ++i) {
0199 addr0 += mtd->erasesize;
0200 ebnum += 1;
0201 }
0202
0203 ebnum2 = ebcnt - 1;
0204 while (ebnum2 && bbt[ebnum2])
0205 ebnum2 -= 1;
0206
0207 pr_info("erasing block %d\n", ebnum);
0208 err = mtdtest_erase_eraseblock(mtd, ebnum);
0209 if (err)
0210 return err;
0211
0212 pr_info("writing 1st page of block %d\n", ebnum);
0213 prandom_bytes_state(&rnd_state, writebuf, pgsize);
0214 strcpy(writebuf, "There is no data like this!");
0215 err = mtdtest_write(mtd, addr0, pgsize, writebuf);
0216 if (err)
0217 return err;
0218
0219 pr_info("reading 1st page of block %d\n", ebnum);
0220 memset(readbuf, 0, pgsize);
0221 err = mtdtest_read(mtd, addr0, pgsize, readbuf);
0222 if (err)
0223 return err;
0224
0225 pr_info("verifying 1st page of block %d\n", ebnum);
0226 if (memcmp(writebuf, readbuf, pgsize)) {
0227 pr_err("verify failed!\n");
0228 errcnt += 1;
0229 return -1;
0230 }
0231
0232 pr_info("erasing block %d\n", ebnum);
0233 err = mtdtest_erase_eraseblock(mtd, ebnum);
0234 if (err)
0235 return err;
0236
0237 pr_info("writing 1st page of block %d\n", ebnum);
0238 prandom_bytes_state(&rnd_state, writebuf, pgsize);
0239 strcpy(writebuf, "There is no data like this!");
0240 err = mtdtest_write(mtd, addr0, pgsize, writebuf);
0241 if (err)
0242 return err;
0243
0244 pr_info("erasing block %d\n", ebnum2);
0245 err = mtdtest_erase_eraseblock(mtd, ebnum2);
0246 if (err)
0247 return err;
0248
0249 pr_info("reading 1st page of block %d\n", ebnum);
0250 memset(readbuf, 0, pgsize);
0251 err = mtdtest_read(mtd, addr0, pgsize, readbuf);
0252 if (err)
0253 return err;
0254
0255 pr_info("verifying 1st page of block %d\n", ebnum);
0256 if (memcmp(writebuf, readbuf, pgsize)) {
0257 pr_err("verify failed!\n");
0258 errcnt += 1;
0259 return -1;
0260 }
0261
0262 if (!err)
0263 pr_info("erasecrosstest ok\n");
0264 return err;
0265 }
0266
0267 static int erasetest(void)
0268 {
0269 int err = 0, i, ebnum, ok = 1;
0270 loff_t addr0;
0271
0272 pr_info("erasetest\n");
0273
0274 ebnum = 0;
0275 addr0 = 0;
0276 for (i = 0; i < ebcnt && bbt[i]; ++i) {
0277 addr0 += mtd->erasesize;
0278 ebnum += 1;
0279 }
0280
0281 pr_info("erasing block %d\n", ebnum);
0282 err = mtdtest_erase_eraseblock(mtd, ebnum);
0283 if (err)
0284 return err;
0285
0286 pr_info("writing 1st page of block %d\n", ebnum);
0287 prandom_bytes_state(&rnd_state, writebuf, pgsize);
0288 err = mtdtest_write(mtd, addr0, pgsize, writebuf);
0289 if (err)
0290 return err;
0291
0292 pr_info("erasing block %d\n", ebnum);
0293 err = mtdtest_erase_eraseblock(mtd, ebnum);
0294 if (err)
0295 return err;
0296
0297 pr_info("reading 1st page of block %d\n", ebnum);
0298 err = mtdtest_read(mtd, addr0, pgsize, twopages);
0299 if (err)
0300 return err;
0301
0302 pr_info("verifying 1st page of block %d is all 0xff\n",
0303 ebnum);
0304 for (i = 0; i < pgsize; ++i)
0305 if (twopages[i] != 0xff) {
0306 pr_err("verifying all 0xff failed at %d\n",
0307 i);
0308 errcnt += 1;
0309 ok = 0;
0310 break;
0311 }
0312
0313 if (ok && !err)
0314 pr_info("erasetest ok\n");
0315
0316 return err;
0317 }
0318
0319 static int __init mtd_pagetest_init(void)
0320 {
0321 int err = 0;
0322 uint64_t tmp;
0323 uint32_t i;
0324
0325 printk(KERN_INFO "\n");
0326 printk(KERN_INFO "=================================================\n");
0327
0328 if (dev < 0) {
0329 pr_info("Please specify a valid mtd-device via module parameter\n");
0330 pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
0331 return -EINVAL;
0332 }
0333
0334 pr_info("MTD device: %d\n", dev);
0335
0336 mtd = get_mtd_device(NULL, dev);
0337 if (IS_ERR(mtd)) {
0338 err = PTR_ERR(mtd);
0339 pr_err("error: cannot get MTD device\n");
0340 return err;
0341 }
0342
0343 if (!mtd_type_is_nand(mtd)) {
0344 pr_info("this test requires NAND flash\n");
0345 goto out;
0346 }
0347
0348 tmp = mtd->size;
0349 do_div(tmp, mtd->erasesize);
0350 ebcnt = tmp;
0351 pgcnt = mtd->erasesize / mtd->writesize;
0352 pgsize = mtd->writesize;
0353
0354 pr_info("MTD device size %llu, eraseblock size %u, "
0355 "page size %u, count of eraseblocks %u, pages per "
0356 "eraseblock %u, OOB size %u\n",
0357 (unsigned long long)mtd->size, mtd->erasesize,
0358 pgsize, ebcnt, pgcnt, mtd->oobsize);
0359
0360 err = -ENOMEM;
0361 bufsize = pgsize * 2;
0362 writebuf = kmalloc(mtd->erasesize, GFP_KERNEL);
0363 if (!writebuf)
0364 goto out;
0365 twopages = kmalloc(bufsize, GFP_KERNEL);
0366 if (!twopages)
0367 goto out;
0368 boundary = kmalloc(bufsize, GFP_KERNEL);
0369 if (!boundary)
0370 goto out;
0371
0372 bbt = kzalloc(ebcnt, GFP_KERNEL);
0373 if (!bbt)
0374 goto out;
0375 err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt);
0376 if (err)
0377 goto out;
0378
0379
0380 pr_info("erasing whole device\n");
0381 err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
0382 if (err)
0383 goto out;
0384 pr_info("erased %u eraseblocks\n", ebcnt);
0385
0386
0387 prandom_seed_state(&rnd_state, 1);
0388 pr_info("writing whole device\n");
0389 for (i = 0; i < ebcnt; ++i) {
0390 if (bbt[i])
0391 continue;
0392 err = write_eraseblock(i);
0393 if (err)
0394 goto out;
0395 if (i % 256 == 0)
0396 pr_info("written up to eraseblock %u\n", i);
0397
0398 err = mtdtest_relax();
0399 if (err)
0400 goto out;
0401 }
0402 pr_info("written %u eraseblocks\n", i);
0403
0404
0405 prandom_seed_state(&rnd_state, 1);
0406 pr_info("verifying all eraseblocks\n");
0407 for (i = 0; i < ebcnt; ++i) {
0408 if (bbt[i])
0409 continue;
0410 err = verify_eraseblock(i);
0411 if (err)
0412 goto out;
0413 if (i % 256 == 0)
0414 pr_info("verified up to eraseblock %u\n", i);
0415
0416 err = mtdtest_relax();
0417 if (err)
0418 goto out;
0419 }
0420 pr_info("verified %u eraseblocks\n", i);
0421
0422 err = crosstest();
0423 if (err)
0424 goto out;
0425
0426 if (ebcnt > 1) {
0427 err = erasecrosstest();
0428 if (err)
0429 goto out;
0430 } else {
0431 pr_info("skipping erasecrosstest, 2 erase blocks needed\n");
0432 }
0433
0434 err = erasetest();
0435 if (err)
0436 goto out;
0437
0438 pr_info("finished with %d errors\n", errcnt);
0439 out:
0440
0441 kfree(bbt);
0442 kfree(boundary);
0443 kfree(twopages);
0444 kfree(writebuf);
0445 put_mtd_device(mtd);
0446 if (err)
0447 pr_info("error %d occurred\n", err);
0448 printk(KERN_INFO "=================================================\n");
0449 return err;
0450 }
0451 module_init(mtd_pagetest_init);
0452
0453 static void __exit mtd_pagetest_exit(void)
0454 {
0455 return;
0456 }
0457 module_exit(mtd_pagetest_exit);
0458
0459 MODULE_DESCRIPTION("NAND page test");
0460 MODULE_AUTHOR("Adrian Hunter");
0461 MODULE_LICENSE("GPL");