1/* 2 * Copyright (C) 2006-2008 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 OOB read and write on MTD device. 18 * 19 * Author: Adrian Hunter <ext-adrian.hunter@nokia.com> 20 */ 21 22#include <asm/div64.h> 23#include <linux/init.h> 24#include <linux/module.h> 25#include <linux/moduleparam.h> 26#include <linux/err.h> 27#include <linux/mtd/mtd.h> 28#include <linux/slab.h> 29#include <linux/sched.h> 30 31#define PRINT_PREF KERN_INFO "mtd_oobtest: " 32 33static int dev; 34module_param(dev, int, S_IRUGO); 35MODULE_PARM_DESC(dev, "MTD device number to use"); 36 37static struct mtd_info *mtd; 38static unsigned char *readbuf; 39static unsigned char *writebuf; 40static unsigned char *bbt; 41 42static int ebcnt; 43static int pgcnt; 44static int errcnt; 45static int use_offset; 46static int use_len; 47static int use_len_max; 48static int vary_offset; 49static unsigned long next = 1; 50 51static inline unsigned int simple_rand(void) 52{ 53 next = next * 1103515245 + 12345; 54 return (unsigned int)((next / 65536) % 32768); 55} 56 57static inline void simple_srand(unsigned long seed) 58{ 59 next = seed; 60} 61 62static void set_random_data(unsigned char *buf, size_t len) 63{ 64 size_t i; 65 66 for (i = 0; i < len; ++i) 67 buf[i] = simple_rand(); 68} 69 70static int erase_eraseblock(int ebnum) 71{ 72 int err; 73 struct erase_info ei; 74 loff_t addr = ebnum * mtd->erasesize; 75 76 memset(&ei, 0, sizeof(struct erase_info)); 77 ei.mtd = mtd; 78 ei.addr = addr; 79 ei.len = mtd->erasesize; 80 81 err = mtd->erase(mtd, &ei); 82 if (err) { 83 printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum); 84 return err; 85 } 86 87 if (ei.state == MTD_ERASE_FAILED) { 88 printk(PRINT_PREF "some erase error occurred at EB %d\n", 89 ebnum); 90 return -EIO; 91 } 92 93 return 0; 94} 95 96static int erase_whole_device(void) 97{ 98 int err; 99 unsigned int i; 100 101 printk(PRINT_PREF "erasing whole device\n"); 102 for (i = 0; i < ebcnt; ++i) { 103 if (bbt[i]) 104 continue; 105 err = erase_eraseblock(i); 106 if (err) 107 return err; 108 cond_resched(); 109 } 110 printk(PRINT_PREF "erased %u eraseblocks\n", i); 111 return 0; 112} 113 114static void do_vary_offset(void) 115{ 116 use_len -= 1; 117 if (use_len < 1) { 118 use_offset += 1; 119 if (use_offset >= use_len_max) 120 use_offset = 0; 121 use_len = use_len_max - use_offset; 122 } 123} 124 125static int write_eraseblock(int ebnum) 126{ 127 int i; 128 struct mtd_oob_ops ops; 129 int err = 0; 130 loff_t addr = ebnum * mtd->erasesize; 131 132 for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) { 133 set_random_data(writebuf, use_len); 134 ops.mode = MTD_OOB_AUTO; 135 ops.len = 0; 136 ops.retlen = 0; 137 ops.ooblen = use_len; 138 ops.oobretlen = 0; 139 ops.ooboffs = use_offset; 140 ops.datbuf = NULL; 141 ops.oobbuf = writebuf; 142 err = mtd->write_oob(mtd, addr, &ops); 143 if (err || ops.oobretlen != use_len) { 144 printk(PRINT_PREF "error: writeoob failed at %#llx\n", 145 (long long)addr); 146 printk(PRINT_PREF "error: use_len %d, use_offset %d\n", 147 use_len, use_offset); 148 errcnt += 1; 149 return err ? err : -1; 150 } 151 if (vary_offset) 152 do_vary_offset(); 153 } 154 155 return err; 156} 157 158static int write_whole_device(void) 159{ 160 int err; 161 unsigned int i; 162 163 printk(PRINT_PREF "writing OOBs of whole device\n"); 164 for (i = 0; i < ebcnt; ++i) { 165 if (bbt[i]) 166 continue; 167 err = write_eraseblock(i); 168 if (err) 169 return err; 170 if (i % 256 == 0) 171 printk(PRINT_PREF "written up to eraseblock %u\n", i); 172 cond_resched(); 173 } 174 printk(PRINT_PREF "written %u eraseblocks\n", i); 175 return 0; 176} 177 178static int verify_eraseblock(int ebnum) 179{ 180 int i; 181 struct mtd_oob_ops ops; 182 int err = 0; 183 loff_t addr = ebnum * mtd->erasesize; 184 185 for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) { 186 set_random_data(writebuf, use_len); 187 ops.mode = MTD_OOB_AUTO; 188 ops.len = 0; 189 ops.retlen = 0; 190 ops.ooblen = use_len; 191 ops.oobretlen = 0; 192 ops.ooboffs = use_offset; 193 ops.datbuf = NULL; 194 ops.oobbuf = readbuf; 195 err = mtd->read_oob(mtd, addr, &ops); 196 if (err || ops.oobretlen != use_len) { 197 printk(PRINT_PREF "error: readoob failed at %#llx\n", 198 (long long)addr); 199 errcnt += 1; 200 return err ? err : -1; 201 } 202 if (memcmp(readbuf, writebuf, use_len)) { 203 printk(PRINT_PREF "error: verify failed at %#llx\n", 204 (long long)addr); 205 errcnt += 1; 206 if (errcnt > 1000) { 207 printk(PRINT_PREF "error: too many errors\n"); 208 return -1; 209 } 210 } 211 if (use_offset != 0 || use_len < mtd->ecclayout->oobavail) { 212 int k; 213 214 ops.mode = MTD_OOB_AUTO; 215 ops.len = 0; 216 ops.retlen = 0; 217 ops.ooblen = mtd->ecclayout->oobavail; 218 ops.oobretlen = 0; 219 ops.ooboffs = 0; 220 ops.datbuf = NULL; 221 ops.oobbuf = readbuf; 222 err = mtd->read_oob(mtd, addr, &ops); 223 if (err || ops.oobretlen != mtd->ecclayout->oobavail) { 224 printk(PRINT_PREF "error: readoob failed at " 225 "%#llx\n", (long long)addr); 226 errcnt += 1; 227 return err ? err : -1; 228 } 229 if (memcmp(readbuf + use_offset, writebuf, use_len)) { 230 printk(PRINT_PREF "error: verify failed at " 231 "%#llx\n", (long long)addr); 232 errcnt += 1; 233 if (errcnt > 1000) { 234 printk(PRINT_PREF "error: too many " 235 "errors\n"); 236 return -1; 237 } 238 } 239 for (k = 0; k < use_offset; ++k) 240 if (readbuf[k] != 0xff) { 241 printk(PRINT_PREF "error: verify 0xff " 242 "failed at %#llx\n", 243 (long long)addr); 244 errcnt += 1; 245 if (errcnt > 1000) { 246 printk(PRINT_PREF "error: too " 247 "many errors\n"); 248 return -1; 249 } 250 } 251 for (k = use_offset + use_len; 252 k < mtd->ecclayout->oobavail; ++k) 253 if (readbuf[k] != 0xff) { 254 printk(PRINT_PREF "error: verify 0xff " 255 "failed at %#llx\n", 256 (long long)addr); 257 errcnt += 1; 258 if (errcnt > 1000) { 259 printk(PRINT_PREF "error: too " 260 "many errors\n"); 261 return -1; 262 } 263 } 264 } 265 if (vary_offset) 266 do_vary_offset(); 267 } 268 return err; 269} 270 271static int verify_eraseblock_in_one_go(int ebnum) 272{ 273 struct mtd_oob_ops ops; 274 int err = 0; 275 loff_t addr = ebnum * mtd->erasesize; 276 size_t len = mtd->ecclayout->oobavail * pgcnt; 277 278 set_random_data(writebuf, len); 279 ops.mode = MTD_OOB_AUTO; 280 ops.len = 0; 281 ops.retlen = 0; 282 ops.ooblen = len; 283 ops.oobretlen = 0; 284 ops.ooboffs = 0; 285 ops.datbuf = NULL; 286 ops.oobbuf = readbuf; 287 err = mtd->read_oob(mtd, addr, &ops); 288 if (err || ops.oobretlen != len) { 289 printk(PRINT_PREF "error: readoob failed at %#llx\n", 290 (long long)addr); 291 errcnt += 1; 292 return err ? err : -1; 293 } 294 if (memcmp(readbuf, writebuf, len)) { 295 printk(PRINT_PREF "error: verify failed at %#llx\n", 296 (long long)addr); 297 errcnt += 1; 298 if (errcnt > 1000) { 299 printk(PRINT_PREF "error: too many errors\n"); 300 return -1; 301 } 302 } 303 304 return err; 305} 306 307static int verify_all_eraseblocks(void) 308{ 309 int err; 310 unsigned int i; 311 312 printk(PRINT_PREF "verifying all eraseblocks\n"); 313 for (i = 0; i < ebcnt; ++i) { 314 if (bbt[i]) 315 continue; 316 err = verify_eraseblock(i); 317 if (err) 318 return err; 319 if (i % 256 == 0) 320 printk(PRINT_PREF "verified up to eraseblock %u\n", i); 321 cond_resched(); 322 } 323 printk(PRINT_PREF "verified %u eraseblocks\n", i); 324 return 0; 325} 326 327static int is_block_bad(int ebnum) 328{ 329 int ret; 330 loff_t addr = ebnum * mtd->erasesize; 331 332 ret = mtd->block_isbad(mtd, addr); 333 if (ret) 334 printk(PRINT_PREF "block %d is bad\n", ebnum); 335 return ret; 336} 337 338static int scan_for_bad_eraseblocks(void) 339{ 340 int i, bad = 0; 341 342 bbt = kmalloc(ebcnt, GFP_KERNEL); 343 if (!bbt) { 344 printk(PRINT_PREF "error: cannot allocate memory\n"); 345 return -ENOMEM; 346 } 347 348 printk(PRINT_PREF "scanning for bad eraseblocks\n"); 349 for (i = 0; i < ebcnt; ++i) { 350 bbt[i] = is_block_bad(i) ? 1 : 0; 351 if (bbt[i]) 352 bad += 1; 353 cond_resched(); 354 } 355 printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad); 356 return 0; 357} 358 359static int __init mtd_oobtest_init(void) 360{ 361 int err = 0; 362 unsigned int i; 363 uint64_t tmp; 364 struct mtd_oob_ops ops; 365 loff_t addr = 0, addr0; 366 367 printk(KERN_INFO "\n"); 368 printk(KERN_INFO "=================================================\n"); 369 printk(PRINT_PREF "MTD device: %d\n", dev); 370 371 mtd = get_mtd_device(NULL, dev); 372 if (IS_ERR(mtd)) { 373 err = PTR_ERR(mtd); 374 printk(PRINT_PREF "error: cannot get MTD device\n"); 375 return err; 376 } 377 378 if (mtd->type != MTD_NANDFLASH) { 379 printk(PRINT_PREF "this test requires NAND flash\n"); 380 goto out; 381 } 382 383 tmp = mtd->size; 384 do_div(tmp, mtd->erasesize); 385 ebcnt = tmp; 386 pgcnt = mtd->erasesize / mtd->writesize; 387 388 printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, " 389 "page size %u, count of eraseblocks %u, pages per " 390 "eraseblock %u, OOB size %u\n", 391 (unsigned long long)mtd->size, mtd->erasesize, 392 mtd->writesize, ebcnt, pgcnt, mtd->oobsize); 393 394 err = -ENOMEM; 395 readbuf = kmalloc(mtd->erasesize, GFP_KERNEL); 396 if (!readbuf) { 397 printk(PRINT_PREF "error: cannot allocate memory\n"); 398 goto out; 399 } 400 writebuf = kmalloc(mtd->erasesize, GFP_KERNEL); 401 if (!writebuf) { 402 printk(PRINT_PREF "error: cannot allocate memory\n"); 403 goto out; 404 } 405 406 err = scan_for_bad_eraseblocks(); 407 if (err) 408 goto out; 409 410 use_offset = 0; 411 use_len = mtd->ecclayout->oobavail; 412 use_len_max = mtd->ecclayout->oobavail; 413 vary_offset = 0; 414 415 /* First test: write all OOB, read it back and verify */ 416 printk(PRINT_PREF "test 1 of 5\n"); 417 418 err = erase_whole_device(); 419 if (err) 420 goto out; 421 422 simple_srand(1); 423 err = write_whole_device(); 424 if (err) 425 goto out; 426 427 simple_srand(1); 428 err = verify_all_eraseblocks(); 429 if (err) 430 goto out; 431 432 /* 433 * Second test: write all OOB, a block at a time, read it back and 434 * verify. 435 */ 436 printk(PRINT_PREF "test 2 of 5\n"); 437 438 err = erase_whole_device(); 439 if (err) 440 goto out; 441 442 simple_srand(3); 443 err = write_whole_device(); 444 if (err) 445 goto out; 446 447 /* Check all eraseblocks */ 448 simple_srand(3); 449 printk(PRINT_PREF "verifying all eraseblocks\n"); 450 for (i = 0; i < ebcnt; ++i) { 451 if (bbt[i]) 452 continue; 453 err = verify_eraseblock_in_one_go(i); 454 if (err) 455 goto out; 456 if (i % 256 == 0) 457 printk(PRINT_PREF "verified up to eraseblock %u\n", i); 458 cond_resched(); 459 } 460 printk(PRINT_PREF "verified %u eraseblocks\n", i); 461 462 /* 463 * Third test: write OOB at varying offsets and lengths, read it back 464 * and verify. 465 */ 466 printk(PRINT_PREF "test 3 of 5\n"); 467 468 err = erase_whole_device(); 469 if (err) 470 goto out; 471 472 /* Write all eraseblocks */ 473 use_offset = 0; 474 use_len = mtd->ecclayout->oobavail; 475 use_len_max = mtd->ecclayout->oobavail; 476 vary_offset = 1; 477 simple_srand(5); 478 479 err = write_whole_device(); 480 if (err) 481 goto out; 482 483 /* Check all eraseblocks */ 484 use_offset = 0; 485 use_len = mtd->ecclayout->oobavail; 486 use_len_max = mtd->ecclayout->oobavail; 487 vary_offset = 1; 488 simple_srand(5); 489 err = verify_all_eraseblocks(); 490 if (err) 491 goto out; 492 493 use_offset = 0; 494 use_len = mtd->ecclayout->oobavail; 495 use_len_max = mtd->ecclayout->oobavail; 496 vary_offset = 0; 497 498 /* Fourth test: try to write off end of device */ 499 printk(PRINT_PREF "test 4 of 5\n"); 500 501 err = erase_whole_device(); 502 if (err) 503 goto out; 504 505 addr0 = 0; 506 for (i = 0; i < ebcnt && bbt[i]; ++i) 507 addr0 += mtd->erasesize; 508 509 /* Attempt to write off end of OOB */ 510 ops.mode = MTD_OOB_AUTO; 511 ops.len = 0; 512 ops.retlen = 0; 513 ops.ooblen = 1; 514 ops.oobretlen = 0; 515 ops.ooboffs = mtd->ecclayout->oobavail; 516 ops.datbuf = NULL; 517 ops.oobbuf = writebuf; 518 printk(PRINT_PREF "attempting to start write past end of OOB\n"); 519 printk(PRINT_PREF "an error is expected...\n"); 520 err = mtd->write_oob(mtd, addr0, &ops); 521 if (err) { 522 printk(PRINT_PREF "error occurred as expected\n"); 523 err = 0; 524 } else { 525 printk(PRINT_PREF "error: can write past end of OOB\n"); 526 errcnt += 1; 527 } 528 529 /* Attempt to read off end of OOB */ 530 ops.mode = MTD_OOB_AUTO; 531 ops.len = 0; 532 ops.retlen = 0; 533 ops.ooblen = 1; 534 ops.oobretlen = 0; 535 ops.ooboffs = mtd->ecclayout->oobavail; 536 ops.datbuf = NULL; 537 ops.oobbuf = readbuf; 538 printk(PRINT_PREF "attempting to start read past end of OOB\n"); 539 printk(PRINT_PREF "an error is expected...\n"); 540 err = mtd->read_oob(mtd, addr0, &ops); 541 if (err) { 542 printk(PRINT_PREF "error occurred as expected\n"); 543 err = 0; 544 } else { 545 printk(PRINT_PREF "error: can read past end of OOB\n"); 546 errcnt += 1; 547 } 548 549 if (bbt[ebcnt - 1]) 550 printk(PRINT_PREF "skipping end of device tests because last " 551 "block is bad\n"); 552 else { 553 /* Attempt to write off end of device */ 554 ops.mode = MTD_OOB_AUTO; 555 ops.len = 0; 556 ops.retlen = 0; 557 ops.ooblen = mtd->ecclayout->oobavail + 1; 558 ops.oobretlen = 0; 559 ops.ooboffs = 0; 560 ops.datbuf = NULL; 561 ops.oobbuf = writebuf; 562 printk(PRINT_PREF "attempting to write past end of device\n"); 563 printk(PRINT_PREF "an error is expected...\n"); 564 err = mtd->write_oob(mtd, mtd->size - mtd->writesize, &ops); 565 if (err) { 566 printk(PRINT_PREF "error occurred as expected\n"); 567 err = 0; 568 } else { 569 printk(PRINT_PREF "error: wrote past end of device\n"); 570 errcnt += 1; 571 } 572 573 /* Attempt to read off end of device */ 574 ops.mode = MTD_OOB_AUTO; 575 ops.len = 0; 576 ops.retlen = 0; 577 ops.ooblen = mtd->ecclayout->oobavail + 1; 578 ops.oobretlen = 0; 579 ops.ooboffs = 0; 580 ops.datbuf = NULL; 581 ops.oobbuf = readbuf; 582 printk(PRINT_PREF "attempting to read past end of device\n"); 583 printk(PRINT_PREF "an error is expected...\n"); 584 err = mtd->read_oob(mtd, mtd->size - mtd->writesize, &ops); 585 if (err) { 586 printk(PRINT_PREF "error occurred as expected\n"); 587 err = 0; 588 } else { 589 printk(PRINT_PREF "error: read past end of device\n"); 590 errcnt += 1; 591 } 592 593 err = erase_eraseblock(ebcnt - 1); 594 if (err) 595 goto out; 596 597 /* Attempt to write off end of device */ 598 ops.mode = MTD_OOB_AUTO; 599 ops.len = 0; 600 ops.retlen = 0; 601 ops.ooblen = mtd->ecclayout->oobavail; 602 ops.oobretlen = 0; 603 ops.ooboffs = 1; 604 ops.datbuf = NULL; 605 ops.oobbuf = writebuf; 606 printk(PRINT_PREF "attempting to write past end of device\n"); 607 printk(PRINT_PREF "an error is expected...\n"); 608 err = mtd->write_oob(mtd, mtd->size - mtd->writesize, &ops); 609 if (err) { 610 printk(PRINT_PREF "error occurred as expected\n"); 611 err = 0; 612 } else { 613 printk(PRINT_PREF "error: wrote past end of device\n"); 614 errcnt += 1; 615 } 616 617 /* Attempt to read off end of device */ 618 ops.mode = MTD_OOB_AUTO; 619 ops.len = 0; 620 ops.retlen = 0; 621 ops.ooblen = mtd->ecclayout->oobavail; 622 ops.oobretlen = 0; 623 ops.ooboffs = 1; 624 ops.datbuf = NULL; 625 ops.oobbuf = readbuf; 626 printk(PRINT_PREF "attempting to read past end of device\n"); 627 printk(PRINT_PREF "an error is expected...\n"); 628 err = mtd->read_oob(mtd, mtd->size - mtd->writesize, &ops); 629 if (err) { 630 printk(PRINT_PREF "error occurred as expected\n"); 631 err = 0; 632 } else { 633 printk(PRINT_PREF "error: read past end of device\n"); 634 errcnt += 1; 635 } 636 } 637 638 /* Fifth test: write / read across block boundaries */ 639 printk(PRINT_PREF "test 5 of 5\n"); 640 641 /* Erase all eraseblocks */ 642 err = erase_whole_device(); 643 if (err) 644 goto out; 645 646 /* Write all eraseblocks */ 647 simple_srand(11); 648 printk(PRINT_PREF "writing OOBs of whole device\n"); 649 for (i = 0; i < ebcnt - 1; ++i) { 650 int cnt = 2; 651 int pg; 652 size_t sz = mtd->ecclayout->oobavail; 653 if (bbt[i] || bbt[i + 1]) 654 continue; 655 addr = (i + 1) * mtd->erasesize - mtd->writesize; 656 for (pg = 0; pg < cnt; ++pg) { 657 set_random_data(writebuf, sz); 658 ops.mode = MTD_OOB_AUTO; 659 ops.len = 0; 660 ops.retlen = 0; 661 ops.ooblen = sz; 662 ops.oobretlen = 0; 663 ops.ooboffs = 0; 664 ops.datbuf = NULL; 665 ops.oobbuf = writebuf; 666 err = mtd->write_oob(mtd, addr, &ops); 667 if (err) 668 goto out; 669 if (i % 256 == 0) 670 printk(PRINT_PREF "written up to eraseblock " 671 "%u\n", i); 672 cond_resched(); 673 addr += mtd->writesize; 674 } 675 } 676 printk(PRINT_PREF "written %u eraseblocks\n", i); 677 678 /* Check all eraseblocks */ 679 simple_srand(11); 680 printk(PRINT_PREF "verifying all eraseblocks\n"); 681 for (i = 0; i < ebcnt - 1; ++i) { 682 if (bbt[i] || bbt[i + 1]) 683 continue; 684 set_random_data(writebuf, mtd->ecclayout->oobavail * 2); 685 addr = (i + 1) * mtd->erasesize - mtd->writesize; 686 ops.mode = MTD_OOB_AUTO; 687 ops.len = 0; 688 ops.retlen = 0; 689 ops.ooblen = mtd->ecclayout->oobavail * 2; 690 ops.oobretlen = 0; 691 ops.ooboffs = 0; 692 ops.datbuf = NULL; 693 ops.oobbuf = readbuf; 694 err = mtd->read_oob(mtd, addr, &ops); 695 if (err) 696 goto out; 697 if (memcmp(readbuf, writebuf, mtd->ecclayout->oobavail * 2)) { 698 printk(PRINT_PREF "error: verify failed at %#llx\n", 699 (long long)addr); 700 errcnt += 1; 701 if (errcnt > 1000) { 702 printk(PRINT_PREF "error: too many errors\n"); 703 goto out; 704 } 705 } 706 if (i % 256 == 0) 707 printk(PRINT_PREF "verified up to eraseblock %u\n", i); 708 cond_resched(); 709 } 710 printk(PRINT_PREF "verified %u eraseblocks\n", i); 711 712 printk(PRINT_PREF "finished with %d errors\n", errcnt); 713out: 714 kfree(bbt); 715 kfree(writebuf); 716 kfree(readbuf); 717 put_mtd_device(mtd); 718 if (err) 719 printk(PRINT_PREF "error %d occurred\n", err); 720 printk(KERN_INFO "=================================================\n"); 721 return err; 722} 723module_init(mtd_oobtest_init); 724 725static void __exit mtd_oobtest_exit(void) 726{ 727 return; 728} 729module_exit(mtd_oobtest_exit); 730 731MODULE_DESCRIPTION("Out-of-band test module"); 732MODULE_AUTHOR("Adrian Hunter"); 733MODULE_LICENSE("GPL"); 734