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#include <linux/init.h> 23#include <linux/module.h> 24#include <linux/moduleparam.h> 25#include <linux/err.h> 26#include <linux/mtd/mtd.h> 27#include <linux/slab.h> 28#include <linux/sched.h> 29 30#define PRINT_PREF KERN_INFO "mtd_subpagetest: " 31 32static int dev; 33module_param(dev, int, S_IRUGO); 34MODULE_PARM_DESC(dev, "MTD device number to use"); 35 36static struct mtd_info *mtd; 37static unsigned char *writebuf; 38static unsigned char *readbuf; 39static unsigned char *bbt; 40 41static int subpgsize; 42static int bufsize; 43static int ebcnt; 44static int pgcnt; 45static int errcnt; 46static unsigned long next = 1; 47 48static inline unsigned int simple_rand(void) 49{ 50 next = next * 1103515245 + 12345; 51 return (unsigned int)((next / 65536) % 32768); 52} 53 54static inline void simple_srand(unsigned long seed) 55{ 56 next = seed; 57} 58 59static void set_random_data(unsigned char *buf, size_t len) 60{ 61 size_t i; 62 63 for (i = 0; i < len; ++i) 64 buf[i] = simple_rand(); 65} 66 67static inline void clear_data(unsigned char *buf, size_t len) 68{ 69 memset(buf, 0, len); 70} 71 72static int erase_eraseblock(int ebnum) 73{ 74 int err; 75 struct erase_info ei; 76 loff_t addr = ebnum * mtd->erasesize; 77 78 memset(&ei, 0, sizeof(struct erase_info)); 79 ei.mtd = mtd; 80 ei.addr = addr; 81 ei.len = mtd->erasesize; 82 83 err = mtd->erase(mtd, &ei); 84 if (err) { 85 printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum); 86 return err; 87 } 88 89 if (ei.state == MTD_ERASE_FAILED) { 90 printk(PRINT_PREF "some erase error occurred at EB %d\n", 91 ebnum); 92 return -EIO; 93 } 94 95 return 0; 96} 97 98static int erase_whole_device(void) 99{ 100 int err; 101 unsigned int i; 102 103 printk(PRINT_PREF "erasing whole device\n"); 104 for (i = 0; i < ebcnt; ++i) { 105 if (bbt[i]) 106 continue; 107 err = erase_eraseblock(i); 108 if (err) 109 return err; 110 cond_resched(); 111 } 112 printk(PRINT_PREF "erased %u eraseblocks\n", i); 113 return 0; 114} 115 116static int write_eraseblock(int ebnum) 117{ 118 size_t written = 0; 119 int err = 0; 120 loff_t addr = ebnum * mtd->erasesize; 121 122 set_random_data(writebuf, subpgsize); 123 err = mtd->write(mtd, addr, subpgsize, &written, writebuf); 124 if (unlikely(err || written != subpgsize)) { 125 printk(PRINT_PREF "error: write failed at %#llx\n", 126 (long long)addr); 127 if (written != subpgsize) { 128 printk(PRINT_PREF " write size: %#x\n", subpgsize); 129 printk(PRINT_PREF " written: %#zx\n", written); 130 } 131 return err ? err : -1; 132 } 133 134 addr += subpgsize; 135 136 set_random_data(writebuf, subpgsize); 137 err = mtd->write(mtd, addr, subpgsize, &written, writebuf); 138 if (unlikely(err || written != subpgsize)) { 139 printk(PRINT_PREF "error: write failed at %#llx\n", 140 (long long)addr); 141 if (written != subpgsize) { 142 printk(PRINT_PREF " write size: %#x\n", subpgsize); 143 printk(PRINT_PREF " written: %#zx\n", written); 144 } 145 return err ? err : -1; 146 } 147 148 return err; 149} 150 151static int write_eraseblock2(int ebnum) 152{ 153 size_t written = 0; 154 int err = 0, k; 155 loff_t addr = ebnum * mtd->erasesize; 156 157 for (k = 1; k < 33; ++k) { 158 if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize) 159 break; 160 set_random_data(writebuf, subpgsize * k); 161 err = mtd->write(mtd, addr, subpgsize * k, &written, writebuf); 162 if (unlikely(err || written != subpgsize * k)) { 163 printk(PRINT_PREF "error: write failed at %#llx\n", 164 (long long)addr); 165 if (written != subpgsize) { 166 printk(PRINT_PREF " write size: %#x\n", 167 subpgsize * k); 168 printk(PRINT_PREF " written: %#08zx\n", 169 written); 170 } 171 return err ? err : -1; 172 } 173 addr += subpgsize * k; 174 } 175 176 return err; 177} 178 179static void print_subpage(unsigned char *p) 180{ 181 int i, j; 182 183 for (i = 0; i < subpgsize; ) { 184 for (j = 0; i < subpgsize && j < 32; ++i, ++j) 185 printk("%02x", *p++); 186 printk("\n"); 187 } 188} 189 190static int verify_eraseblock(int ebnum) 191{ 192 size_t read = 0; 193 int err = 0; 194 loff_t addr = ebnum * mtd->erasesize; 195 196 set_random_data(writebuf, subpgsize); 197 clear_data(readbuf, subpgsize); 198 read = 0; 199 err = mtd->read(mtd, addr, subpgsize, &read, readbuf); 200 if (unlikely(err || read != subpgsize)) { 201 if (err == -EUCLEAN && read == subpgsize) { 202 printk(PRINT_PREF "ECC correction at %#llx\n", 203 (long long)addr); 204 err = 0; 205 } else { 206 printk(PRINT_PREF "error: read failed at %#llx\n", 207 (long long)addr); 208 return err ? err : -1; 209 } 210 } 211 if (unlikely(memcmp(readbuf, writebuf, subpgsize))) { 212 printk(PRINT_PREF "error: verify failed at %#llx\n", 213 (long long)addr); 214 printk(PRINT_PREF "------------- written----------------\n"); 215 print_subpage(writebuf); 216 printk(PRINT_PREF "------------- read ------------------\n"); 217 print_subpage(readbuf); 218 printk(PRINT_PREF "-------------------------------------\n"); 219 errcnt += 1; 220 } 221 222 addr += subpgsize; 223 224 set_random_data(writebuf, subpgsize); 225 clear_data(readbuf, subpgsize); 226 read = 0; 227 err = mtd->read(mtd, addr, subpgsize, &read, readbuf); 228 if (unlikely(err || read != subpgsize)) { 229 if (err == -EUCLEAN && read == subpgsize) { 230 printk(PRINT_PREF "ECC correction at %#llx\n", 231 (long long)addr); 232 err = 0; 233 } else { 234 printk(PRINT_PREF "error: read failed at %#llx\n", 235 (long long)addr); 236 return err ? err : -1; 237 } 238 } 239 if (unlikely(memcmp(readbuf, writebuf, subpgsize))) { 240 printk(PRINT_PREF "error: verify failed at %#llx\n", 241 (long long)addr); 242 printk(PRINT_PREF "------------- written----------------\n"); 243 print_subpage(writebuf); 244 printk(PRINT_PREF "------------- read ------------------\n"); 245 print_subpage(readbuf); 246 printk(PRINT_PREF "-------------------------------------\n"); 247 errcnt += 1; 248 } 249 250 return err; 251} 252 253static int verify_eraseblock2(int ebnum) 254{ 255 size_t read = 0; 256 int err = 0, k; 257 loff_t addr = ebnum * mtd->erasesize; 258 259 for (k = 1; k < 33; ++k) { 260 if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize) 261 break; 262 set_random_data(writebuf, subpgsize * k); 263 clear_data(readbuf, subpgsize * k); 264 read = 0; 265 err = mtd->read(mtd, addr, subpgsize * k, &read, readbuf); 266 if (unlikely(err || read != subpgsize * k)) { 267 if (err == -EUCLEAN && read == subpgsize * k) { 268 printk(PRINT_PREF "ECC correction at %#llx\n", 269 (long long)addr); 270 err = 0; 271 } else { 272 printk(PRINT_PREF "error: read failed at " 273 "%#llx\n", (long long)addr); 274 return err ? err : -1; 275 } 276 } 277 if (unlikely(memcmp(readbuf, writebuf, subpgsize * k))) { 278 printk(PRINT_PREF "error: verify failed at %#llx\n", 279 (long long)addr); 280 errcnt += 1; 281 } 282 addr += subpgsize * k; 283 } 284 285 return err; 286} 287 288static int verify_eraseblock_ff(int ebnum) 289{ 290 uint32_t j; 291 size_t read = 0; 292 int err = 0; 293 loff_t addr = ebnum * mtd->erasesize; 294 295 memset(writebuf, 0xff, subpgsize); 296 for (j = 0; j < mtd->erasesize / subpgsize; ++j) { 297 clear_data(readbuf, subpgsize); 298 read = 0; 299 err = mtd->read(mtd, addr, subpgsize, &read, readbuf); 300 if (unlikely(err || read != subpgsize)) { 301 if (err == -EUCLEAN && read == subpgsize) { 302 printk(PRINT_PREF "ECC correction at %#llx\n", 303 (long long)addr); 304 err = 0; 305 } else { 306 printk(PRINT_PREF "error: read failed at " 307 "%#llx\n", (long long)addr); 308 return err ? err : -1; 309 } 310 } 311 if (unlikely(memcmp(readbuf, writebuf, subpgsize))) { 312 printk(PRINT_PREF "error: verify 0xff failed at " 313 "%#llx\n", (long long)addr); 314 errcnt += 1; 315 } 316 addr += subpgsize; 317 } 318 319 return err; 320} 321 322static int verify_all_eraseblocks_ff(void) 323{ 324 int err; 325 unsigned int i; 326 327 printk(PRINT_PREF "verifying all eraseblocks for 0xff\n"); 328 for (i = 0; i < ebcnt; ++i) { 329 if (bbt[i]) 330 continue; 331 err = verify_eraseblock_ff(i); 332 if (err) 333 return err; 334 if (i % 256 == 0) 335 printk(PRINT_PREF "verified up to eraseblock %u\n", i); 336 cond_resched(); 337 } 338 printk(PRINT_PREF "verified %u eraseblocks\n", i); 339 return 0; 340} 341 342static int is_block_bad(int ebnum) 343{ 344 loff_t addr = ebnum * mtd->erasesize; 345 int ret; 346 347 ret = mtd->block_isbad(mtd, addr); 348 if (ret) 349 printk(PRINT_PREF "block %d is bad\n", ebnum); 350 return ret; 351} 352 353static int scan_for_bad_eraseblocks(void) 354{ 355 int i, bad = 0; 356 357 bbt = kzalloc(ebcnt, GFP_KERNEL); 358 if (!bbt) { 359 printk(PRINT_PREF "error: cannot allocate memory\n"); 360 return -ENOMEM; 361 } 362 363 printk(PRINT_PREF "scanning for bad eraseblocks\n"); 364 for (i = 0; i < ebcnt; ++i) { 365 bbt[i] = is_block_bad(i) ? 1 : 0; 366 if (bbt[i]) 367 bad += 1; 368 cond_resched(); 369 } 370 printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad); 371 return 0; 372} 373 374static int __init mtd_subpagetest_init(void) 375{ 376 int err = 0; 377 uint32_t i; 378 uint64_t tmp; 379 380 printk(KERN_INFO "\n"); 381 printk(KERN_INFO "=================================================\n"); 382 printk(PRINT_PREF "MTD device: %d\n", dev); 383 384 mtd = get_mtd_device(NULL, dev); 385 if (IS_ERR(mtd)) { 386 err = PTR_ERR(mtd); 387 printk(PRINT_PREF "error: cannot get MTD device\n"); 388 return err; 389 } 390 391 if (mtd->type != MTD_NANDFLASH) { 392 printk(PRINT_PREF "this test requires NAND flash\n"); 393 goto out; 394 } 395 396 subpgsize = mtd->writesize >> mtd->subpage_sft; 397 printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, " 398 "page size %u, subpage size %u, count of eraseblocks %u, " 399 "pages per eraseblock %u, OOB size %u\n", 400 (unsigned long long)mtd->size, mtd->erasesize, 401 mtd->writesize, subpgsize, ebcnt, pgcnt, mtd->oobsize); 402 403 err = -ENOMEM; 404 bufsize = subpgsize * 32; 405 writebuf = kmalloc(bufsize, GFP_KERNEL); 406 if (!writebuf) { 407 printk(PRINT_PREF "error: cannot allocate memory\n"); 408 goto out; 409 } 410 readbuf = kmalloc(bufsize, GFP_KERNEL); 411 if (!readbuf) { 412 printk(PRINT_PREF "error: cannot allocate memory\n"); 413 goto out; 414 } 415 416 tmp = mtd->size; 417 do_div(tmp, mtd->erasesize); 418 ebcnt = tmp; 419 pgcnt = mtd->erasesize / mtd->writesize; 420 421 err = scan_for_bad_eraseblocks(); 422 if (err) 423 goto out; 424 425 err = erase_whole_device(); 426 if (err) 427 goto out; 428 429 printk(PRINT_PREF "writing whole device\n"); 430 simple_srand(1); 431 for (i = 0; i < ebcnt; ++i) { 432 if (bbt[i]) 433 continue; 434 err = write_eraseblock(i); 435 if (unlikely(err)) 436 goto out; 437 if (i % 256 == 0) 438 printk(PRINT_PREF "written up to eraseblock %u\n", i); 439 cond_resched(); 440 } 441 printk(PRINT_PREF "written %u eraseblocks\n", i); 442 443 simple_srand(1); 444 printk(PRINT_PREF "verifying all eraseblocks\n"); 445 for (i = 0; i < ebcnt; ++i) { 446 if (bbt[i]) 447 continue; 448 err = verify_eraseblock(i); 449 if (unlikely(err)) 450 goto out; 451 if (i % 256 == 0) 452 printk(PRINT_PREF "verified up to eraseblock %u\n", i); 453 cond_resched(); 454 } 455 printk(PRINT_PREF "verified %u eraseblocks\n", i); 456 457 err = erase_whole_device(); 458 if (err) 459 goto out; 460 461 err = verify_all_eraseblocks_ff(); 462 if (err) 463 goto out; 464 465 /* Write all eraseblocks */ 466 simple_srand(3); 467 printk(PRINT_PREF "writing whole device\n"); 468 for (i = 0; i < ebcnt; ++i) { 469 if (bbt[i]) 470 continue; 471 err = write_eraseblock2(i); 472 if (unlikely(err)) 473 goto out; 474 if (i % 256 == 0) 475 printk(PRINT_PREF "written up to eraseblock %u\n", i); 476 cond_resched(); 477 } 478 printk(PRINT_PREF "written %u eraseblocks\n", i); 479 480 /* Check all eraseblocks */ 481 simple_srand(3); 482 printk(PRINT_PREF "verifying all eraseblocks\n"); 483 for (i = 0; i < ebcnt; ++i) { 484 if (bbt[i]) 485 continue; 486 err = verify_eraseblock2(i); 487 if (unlikely(err)) 488 goto out; 489 if (i % 256 == 0) 490 printk(PRINT_PREF "verified up to eraseblock %u\n", i); 491 cond_resched(); 492 } 493 printk(PRINT_PREF "verified %u eraseblocks\n", i); 494 495 err = erase_whole_device(); 496 if (err) 497 goto out; 498 499 err = verify_all_eraseblocks_ff(); 500 if (err) 501 goto out; 502 503 printk(PRINT_PREF "finished with %d errors\n", errcnt); 504 505out: 506 kfree(bbt); 507 kfree(readbuf); 508 kfree(writebuf); 509 put_mtd_device(mtd); 510 if (err) 511 printk(PRINT_PREF "error %d occurred\n", err); 512 printk(KERN_INFO "=================================================\n"); 513 return err; 514} 515module_init(mtd_subpagetest_init); 516 517static void __exit mtd_subpagetest_exit(void) 518{ 519 return; 520} 521module_exit(mtd_subpagetest_exit); 522 523MODULE_DESCRIPTION("Subpage test module"); 524MODULE_AUTHOR("Adrian Hunter"); 525MODULE_LICENSE("GPL"); 526