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