linux/drivers/mtd/tests/oobtest.c
<<
>>
Prefs
   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                err = 0;
 510        } else {
 511                pr_err("error: can write past end of OOB\n");
 512                errcnt += 1;
 513        }
 514
 515        /* Attempt to read off end of OOB */
 516        ops.mode      = MTD_OPS_AUTO_OOB;
 517        ops.len       = 0;
 518        ops.retlen    = 0;
 519        ops.ooblen    = 1;
 520        ops.oobretlen = 0;
 521        ops.ooboffs   = mtd->oobavail;
 522        ops.datbuf    = NULL;
 523        ops.oobbuf    = readbuf;
 524        pr_info("attempting to start read past end of OOB\n");
 525        pr_info("an error is expected...\n");
 526        err = mtd_read_oob(mtd, addr0, &ops);
 527        if (mtd_is_bitflip(err))
 528                err = 0;
 529
 530        if (err) {
 531                pr_info("error occurred as expected\n");
 532                err = 0;
 533        } else {
 534                pr_err("error: can read past end of OOB\n");
 535                errcnt += 1;
 536        }
 537
 538        if (bbt[ebcnt - 1])
 539                pr_info("skipping end of device tests because last "
 540                       "block is bad\n");
 541        else {
 542                /* Attempt to write off end of device */
 543                ops.mode      = MTD_OPS_AUTO_OOB;
 544                ops.len       = 0;
 545                ops.retlen    = 0;
 546                ops.ooblen    = mtd->oobavail + 1;
 547                ops.oobretlen = 0;
 548                ops.ooboffs   = 0;
 549                ops.datbuf    = NULL;
 550                ops.oobbuf    = writebuf;
 551                pr_info("attempting to write past end of device\n");
 552                pr_info("an error is expected...\n");
 553                err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops);
 554                if (err) {
 555                        pr_info("error occurred as expected\n");
 556                        err = 0;
 557                } else {
 558                        pr_err("error: wrote past end of device\n");
 559                        errcnt += 1;
 560                }
 561
 562                /* Attempt to read off end of device */
 563                ops.mode      = MTD_OPS_AUTO_OOB;
 564                ops.len       = 0;
 565                ops.retlen    = 0;
 566                ops.ooblen    = mtd->oobavail + 1;
 567                ops.oobretlen = 0;
 568                ops.ooboffs   = 0;
 569                ops.datbuf    = NULL;
 570                ops.oobbuf    = readbuf;
 571                pr_info("attempting to read past end of device\n");
 572                pr_info("an error is expected...\n");
 573                err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops);
 574                if (mtd_is_bitflip(err))
 575                        err = 0;
 576
 577                if (err) {
 578                        pr_info("error occurred as expected\n");
 579                        err = 0;
 580                } else {
 581                        pr_err("error: read past end of device\n");
 582                        errcnt += 1;
 583                }
 584
 585                err = mtdtest_erase_eraseblock(mtd, ebcnt - 1);
 586                if (err)
 587                        goto out;
 588
 589                /* Attempt to write off end of device */
 590                ops.mode      = MTD_OPS_AUTO_OOB;
 591                ops.len       = 0;
 592                ops.retlen    = 0;
 593                ops.ooblen    = mtd->oobavail;
 594                ops.oobretlen = 0;
 595                ops.ooboffs   = 1;
 596                ops.datbuf    = NULL;
 597                ops.oobbuf    = writebuf;
 598                pr_info("attempting to write past end of device\n");
 599                pr_info("an error is expected...\n");
 600                err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops);
 601                if (err) {
 602                        pr_info("error occurred as expected\n");
 603                        err = 0;
 604                } else {
 605                        pr_err("error: wrote past end of device\n");
 606                        errcnt += 1;
 607                }
 608
 609                /* Attempt to read off end of device */
 610                ops.mode      = MTD_OPS_AUTO_OOB;
 611                ops.len       = 0;
 612                ops.retlen    = 0;
 613                ops.ooblen    = mtd->oobavail;
 614                ops.oobretlen = 0;
 615                ops.ooboffs   = 1;
 616                ops.datbuf    = NULL;
 617                ops.oobbuf    = readbuf;
 618                pr_info("attempting to read past end of device\n");
 619                pr_info("an error is expected...\n");
 620                err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops);
 621                if (mtd_is_bitflip(err))
 622                        err = 0;
 623
 624                if (err) {
 625                        pr_info("error occurred as expected\n");
 626                        err = 0;
 627                } else {
 628                        pr_err("error: read past end of device\n");
 629                        errcnt += 1;
 630                }
 631        }
 632
 633        /* Fifth test: write / read across block boundaries */
 634        pr_info("test 5 of 5\n");
 635
 636        /* Erase all eraseblocks */
 637        err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
 638        if (err)
 639                goto out;
 640
 641        /* Write all eraseblocks */
 642        prandom_seed_state(&rnd_state, 11);
 643        pr_info("writing OOBs of whole device\n");
 644        for (i = 0; i < ebcnt - 1; ++i) {
 645                int cnt = 2;
 646                int pg;
 647                size_t sz = mtd->oobavail;
 648                if (bbt[i] || bbt[i + 1])
 649                        continue;
 650                addr = (loff_t)(i + 1) * mtd->erasesize - mtd->writesize;
 651                prandom_bytes_state(&rnd_state, writebuf, sz * cnt);
 652                for (pg = 0; pg < cnt; ++pg) {
 653                        ops.mode      = MTD_OPS_AUTO_OOB;
 654                        ops.len       = 0;
 655                        ops.retlen    = 0;
 656                        ops.ooblen    = sz;
 657                        ops.oobretlen = 0;
 658                        ops.ooboffs   = 0;
 659                        ops.datbuf    = NULL;
 660                        ops.oobbuf    = writebuf + pg * sz;
 661                        err = mtd_write_oob(mtd, addr, &ops);
 662                        if (err)
 663                                goto out;
 664                        if (i % 256 == 0)
 665                                pr_info("written up to eraseblock %u\n", i);
 666
 667                        err = mtdtest_relax();
 668                        if (err)
 669                                goto out;
 670
 671                        addr += mtd->writesize;
 672                }
 673        }
 674        pr_info("written %u eraseblocks\n", i);
 675
 676        /* Check all eraseblocks */
 677        prandom_seed_state(&rnd_state, 11);
 678        pr_info("verifying all eraseblocks\n");
 679        for (i = 0; i < ebcnt - 1; ++i) {
 680                if (bbt[i] || bbt[i + 1])
 681                        continue;
 682                prandom_bytes_state(&rnd_state, writebuf, mtd->oobavail * 2);
 683                addr = (loff_t)(i + 1) * mtd->erasesize - mtd->writesize;
 684                ops.mode      = MTD_OPS_AUTO_OOB;
 685                ops.len       = 0;
 686                ops.retlen    = 0;
 687                ops.ooblen    = mtd->oobavail * 2;
 688                ops.oobretlen = 0;
 689                ops.ooboffs   = 0;
 690                ops.datbuf    = NULL;
 691                ops.oobbuf    = readbuf;
 692                err = mtd_read_oob(mtd, addr, &ops);
 693                if (mtd_is_bitflip(err))
 694                        err = 0;
 695
 696                if (err)
 697                        goto out;
 698                if (memcmpshow(addr, readbuf, writebuf,
 699                               mtd->oobavail * 2)) {
 700                        pr_err("error: verify failed at %#llx\n",
 701                               (long long)addr);
 702                        errcnt += 1;
 703                        if (errcnt > 1000) {
 704                                pr_err("error: too many errors\n");
 705                                goto out;
 706                        }
 707                }
 708                if (i % 256 == 0)
 709                        pr_info("verified up to eraseblock %u\n", i);
 710
 711                err = mtdtest_relax();
 712                if (err)
 713                        goto out;
 714        }
 715        pr_info("verified %u eraseblocks\n", i);
 716
 717        pr_info("finished with %d errors\n", errcnt);
 718out:
 719        kfree(bbt);
 720        kfree(writebuf);
 721        kfree(readbuf);
 722        put_mtd_device(mtd);
 723        if (err)
 724                pr_info("error %d occurred\n", err);
 725        printk(KERN_INFO "=================================================\n");
 726        return err;
 727}
 728module_init(mtd_oobtest_init);
 729
 730static void __exit mtd_oobtest_exit(void)
 731{
 732        return;
 733}
 734module_exit(mtd_oobtest_exit);
 735
 736MODULE_DESCRIPTION("Out-of-band test module");
 737MODULE_AUTHOR("Adrian Hunter");
 738MODULE_LICENSE("GPL");
 739