1 /* 2 * Copyright (C) 2006-2007 Nokia Corporation 3 * 4 * This program is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 as published by 6 * the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it will be useful, but WITHOUT 9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 * more details. 12 * 13 * You should have received a copy of the GNU General Public License along with 14 * this program; see the file COPYING. If not, write to the Free Software 15 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 16 * 17 * Test sub-page read and write on MTD device. 18 * Author: Adrian Hunter <ext-adrian.hunter@nokia.com> 19 * 20 */ 21 22 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 23 24 #include <linux/init.h> 25 #include <linux/module.h> 26 #include <linux/moduleparam.h> 27 #include <linux/err.h> 28 #include <linux/mtd/mtd.h> 29 #include <linux/slab.h> 30 #include <linux/sched.h> 31 #include <linux/random.h> 32 33 #include "mtd_test.h" 34 35 static int dev = -EINVAL; 36 module_param(dev, int, S_IRUGO); 37 MODULE_PARM_DESC(dev, "MTD device number to use"); 38 39 static struct mtd_info *mtd; 40 static unsigned char *writebuf; 41 static unsigned char *readbuf; 42 static unsigned char *bbt; 43 44 static int subpgsize; 45 static int bufsize; 46 static int ebcnt; 47 static int pgcnt; 48 static int errcnt; 49 static struct rnd_state rnd_state; 50 51 static inline void clear_data(unsigned char *buf, size_t len) 52 { 53 memset(buf, 0, len); 54 } 55 56 static int write_eraseblock(int ebnum) 57 { 58 size_t written; 59 int err = 0; 60 loff_t addr = ebnum * mtd->erasesize; 61 62 prandom_bytes_state(&rnd_state, writebuf, subpgsize); 63 err = mtd_write(mtd, addr, subpgsize, &written, writebuf); 64 if (unlikely(err || written != subpgsize)) { 65 pr_err("error: write failed at %#llx\n", 66 (long long)addr); 67 if (written != subpgsize) { 68 pr_err(" write size: %#x\n", subpgsize); 69 pr_err(" written: %#zx\n", written); 70 } 71 return err ? err : -1; 72 } 73 74 addr += subpgsize; 75 76 prandom_bytes_state(&rnd_state, writebuf, subpgsize); 77 err = mtd_write(mtd, addr, subpgsize, &written, writebuf); 78 if (unlikely(err || written != subpgsize)) { 79 pr_err("error: write failed at %#llx\n", 80 (long long)addr); 81 if (written != subpgsize) { 82 pr_err(" write size: %#x\n", subpgsize); 83 pr_err(" written: %#zx\n", written); 84 } 85 return err ? err : -1; 86 } 87 88 return err; 89 } 90 91 static int write_eraseblock2(int ebnum) 92 { 93 size_t written; 94 int err = 0, k; 95 loff_t addr = ebnum * mtd->erasesize; 96 97 for (k = 1; k < 33; ++k) { 98 if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize) 99 break; 100 prandom_bytes_state(&rnd_state, writebuf, subpgsize * k); 101 err = mtd_write(mtd, addr, subpgsize * k, &written, writebuf); 102 if (unlikely(err || written != subpgsize * k)) { 103 pr_err("error: write failed at %#llx\n", 104 (long long)addr); 105 if (written != subpgsize) { 106 pr_err(" write size: %#x\n", 107 subpgsize * k); 108 pr_err(" written: %#08zx\n", 109 written); 110 } 111 return err ? err : -1; 112 } 113 addr += subpgsize * k; 114 } 115 116 return err; 117 } 118 119 static void print_subpage(unsigned char *p) 120 { 121 int i, j; 122 123 for (i = 0; i < subpgsize; ) { 124 for (j = 0; i < subpgsize && j < 32; ++i, ++j) 125 printk("%02x", *p++); 126 printk("\n"); 127 } 128 } 129 130 static int verify_eraseblock(int ebnum) 131 { 132 size_t read; 133 int err = 0; 134 loff_t addr = ebnum * mtd->erasesize; 135 136 prandom_bytes_state(&rnd_state, writebuf, subpgsize); 137 clear_data(readbuf, subpgsize); 138 err = mtd_read(mtd, addr, subpgsize, &read, readbuf); 139 if (unlikely(err || read != subpgsize)) { 140 if (mtd_is_bitflip(err) && read == subpgsize) { 141 pr_info("ECC correction at %#llx\n", 142 (long long)addr); 143 err = 0; 144 } else { 145 pr_err("error: read failed at %#llx\n", 146 (long long)addr); 147 return err ? err : -1; 148 } 149 } 150 if (unlikely(memcmp(readbuf, writebuf, subpgsize))) { 151 pr_err("error: verify failed at %#llx\n", 152 (long long)addr); 153 pr_info("------------- written----------------\n"); 154 print_subpage(writebuf); 155 pr_info("------------- read ------------------\n"); 156 print_subpage(readbuf); 157 pr_info("-------------------------------------\n"); 158 errcnt += 1; 159 } 160 161 addr += subpgsize; 162 163 prandom_bytes_state(&rnd_state, writebuf, subpgsize); 164 clear_data(readbuf, subpgsize); 165 err = mtd_read(mtd, addr, subpgsize, &read, readbuf); 166 if (unlikely(err || read != subpgsize)) { 167 if (mtd_is_bitflip(err) && read == subpgsize) { 168 pr_info("ECC correction at %#llx\n", 169 (long long)addr); 170 err = 0; 171 } else { 172 pr_err("error: read failed at %#llx\n", 173 (long long)addr); 174 return err ? err : -1; 175 } 176 } 177 if (unlikely(memcmp(readbuf, writebuf, subpgsize))) { 178 pr_info("error: verify failed at %#llx\n", 179 (long long)addr); 180 pr_info("------------- written----------------\n"); 181 print_subpage(writebuf); 182 pr_info("------------- read ------------------\n"); 183 print_subpage(readbuf); 184 pr_info("-------------------------------------\n"); 185 errcnt += 1; 186 } 187 188 return err; 189 } 190 191 static int verify_eraseblock2(int ebnum) 192 { 193 size_t read; 194 int err = 0, k; 195 loff_t addr = ebnum * mtd->erasesize; 196 197 for (k = 1; k < 33; ++k) { 198 if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize) 199 break; 200 prandom_bytes_state(&rnd_state, writebuf, subpgsize * k); 201 clear_data(readbuf, subpgsize * k); 202 err = mtd_read(mtd, addr, subpgsize * k, &read, readbuf); 203 if (unlikely(err || read != subpgsize * k)) { 204 if (mtd_is_bitflip(err) && read == subpgsize * k) { 205 pr_info("ECC correction at %#llx\n", 206 (long long)addr); 207 err = 0; 208 } else { 209 pr_err("error: read failed at " 210 "%#llx\n", (long long)addr); 211 return err ? err : -1; 212 } 213 } 214 if (unlikely(memcmp(readbuf, writebuf, subpgsize * k))) { 215 pr_err("error: verify failed at %#llx\n", 216 (long long)addr); 217 errcnt += 1; 218 } 219 addr += subpgsize * k; 220 } 221 222 return err; 223 } 224 225 static int verify_eraseblock_ff(int ebnum) 226 { 227 uint32_t j; 228 size_t read; 229 int err = 0; 230 loff_t addr = ebnum * mtd->erasesize; 231 232 memset(writebuf, 0xff, subpgsize); 233 for (j = 0; j < mtd->erasesize / subpgsize; ++j) { 234 clear_data(readbuf, subpgsize); 235 err = mtd_read(mtd, addr, subpgsize, &read, readbuf); 236 if (unlikely(err || read != subpgsize)) { 237 if (mtd_is_bitflip(err) && read == subpgsize) { 238 pr_info("ECC correction at %#llx\n", 239 (long long)addr); 240 err = 0; 241 } else { 242 pr_err("error: read failed at " 243 "%#llx\n", (long long)addr); 244 return err ? err : -1; 245 } 246 } 247 if (unlikely(memcmp(readbuf, writebuf, subpgsize))) { 248 pr_err("error: verify 0xff failed at " 249 "%#llx\n", (long long)addr); 250 errcnt += 1; 251 } 252 addr += subpgsize; 253 } 254 255 return err; 256 } 257 258 static int verify_all_eraseblocks_ff(void) 259 { 260 int err; 261 unsigned int i; 262 263 pr_info("verifying all eraseblocks for 0xff\n"); 264 for (i = 0; i < ebcnt; ++i) { 265 if (bbt[i]) 266 continue; 267 err = verify_eraseblock_ff(i); 268 if (err) 269 return err; 270 if (i % 256 == 0) 271 pr_info("verified up to eraseblock %u\n", i); 272 cond_resched(); 273 } 274 pr_info("verified %u eraseblocks\n", i); 275 return 0; 276 } 277 278 static int __init mtd_subpagetest_init(void) 279 { 280 int err = 0; 281 uint32_t i; 282 uint64_t tmp; 283 284 printk(KERN_INFO "\n"); 285 printk(KERN_INFO "=================================================\n"); 286 287 if (dev < 0) { 288 pr_info("Please specify a valid mtd-device via module parameter\n"); 289 pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n"); 290 return -EINVAL; 291 } 292 293 pr_info("MTD device: %d\n", dev); 294 295 mtd = get_mtd_device(NULL, dev); 296 if (IS_ERR(mtd)) { 297 err = PTR_ERR(mtd); 298 pr_err("error: cannot get MTD device\n"); 299 return err; 300 } 301 302 if (!mtd_type_is_nand(mtd)) { 303 pr_info("this test requires NAND flash\n"); 304 goto out; 305 } 306 307 subpgsize = mtd->writesize >> mtd->subpage_sft; 308 tmp = mtd->size; 309 do_div(tmp, mtd->erasesize); 310 ebcnt = tmp; 311 pgcnt = mtd->erasesize / mtd->writesize; 312 313 pr_info("MTD device size %llu, eraseblock size %u, " 314 "page size %u, subpage size %u, count of eraseblocks %u, " 315 "pages per eraseblock %u, OOB size %u\n", 316 (unsigned long long)mtd->size, mtd->erasesize, 317 mtd->writesize, subpgsize, ebcnt, pgcnt, mtd->oobsize); 318 319 err = -ENOMEM; 320 bufsize = subpgsize * 32; 321 writebuf = kmalloc(bufsize, GFP_KERNEL); 322 if (!writebuf) 323 goto out; 324 readbuf = kmalloc(bufsize, GFP_KERNEL); 325 if (!readbuf) 326 goto out; 327 bbt = kzalloc(ebcnt, GFP_KERNEL); 328 if (!bbt) 329 goto out; 330 331 err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt); 332 if (err) 333 goto out; 334 335 err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); 336 if (err) 337 goto out; 338 339 pr_info("writing whole device\n"); 340 prandom_seed_state(&rnd_state, 1); 341 for (i = 0; i < ebcnt; ++i) { 342 if (bbt[i]) 343 continue; 344 err = write_eraseblock(i); 345 if (unlikely(err)) 346 goto out; 347 if (i % 256 == 0) 348 pr_info("written up to eraseblock %u\n", i); 349 cond_resched(); 350 } 351 pr_info("written %u eraseblocks\n", i); 352 353 prandom_seed_state(&rnd_state, 1); 354 pr_info("verifying all eraseblocks\n"); 355 for (i = 0; i < ebcnt; ++i) { 356 if (bbt[i]) 357 continue; 358 err = verify_eraseblock(i); 359 if (unlikely(err)) 360 goto out; 361 if (i % 256 == 0) 362 pr_info("verified up to eraseblock %u\n", i); 363 cond_resched(); 364 } 365 pr_info("verified %u eraseblocks\n", i); 366 367 err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); 368 if (err) 369 goto out; 370 371 err = verify_all_eraseblocks_ff(); 372 if (err) 373 goto out; 374 375 /* Write all eraseblocks */ 376 prandom_seed_state(&rnd_state, 3); 377 pr_info("writing whole device\n"); 378 for (i = 0; i < ebcnt; ++i) { 379 if (bbt[i]) 380 continue; 381 err = write_eraseblock2(i); 382 if (unlikely(err)) 383 goto out; 384 if (i % 256 == 0) 385 pr_info("written up to eraseblock %u\n", i); 386 cond_resched(); 387 } 388 pr_info("written %u eraseblocks\n", i); 389 390 /* Check all eraseblocks */ 391 prandom_seed_state(&rnd_state, 3); 392 pr_info("verifying all eraseblocks\n"); 393 for (i = 0; i < ebcnt; ++i) { 394 if (bbt[i]) 395 continue; 396 err = verify_eraseblock2(i); 397 if (unlikely(err)) 398 goto out; 399 if (i % 256 == 0) 400 pr_info("verified up to eraseblock %u\n", i); 401 cond_resched(); 402 } 403 pr_info("verified %u eraseblocks\n", i); 404 405 err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); 406 if (err) 407 goto out; 408 409 err = verify_all_eraseblocks_ff(); 410 if (err) 411 goto out; 412 413 pr_info("finished with %d errors\n", errcnt); 414 415 out: 416 kfree(bbt); 417 kfree(readbuf); 418 kfree(writebuf); 419 put_mtd_device(mtd); 420 if (err) 421 pr_info("error %d occurred\n", err); 422 printk(KERN_INFO "=================================================\n"); 423 return err; 424 } 425 module_init(mtd_subpagetest_init); 426 427 static void __exit mtd_subpagetest_exit(void) 428 { 429 return; 430 } 431 module_exit(mtd_subpagetest_exit); 432 433 MODULE_DESCRIPTION("Subpage test module"); 434 MODULE_AUTHOR("Adrian Hunter"); 435 MODULE_LICENSE("GPL"); 436