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