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