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