linux/drivers/mtd/tests/mtd_subpagetest.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2006-2007 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 sub-page read and write on MTD device.
  18 * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
  19 *
  20 */
  21
  22#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  23
  24#include <linux/init.h>
  25#include <linux/module.h>
  26#include <linux/moduleparam.h>
  27#include <linux/err.h>
  28#include <linux/mtd/mtd.h>
  29#include <linux/slab.h>
  30#include <linux/sched.h>
  31#include <linux/random.h>
  32
  33static int dev = -EINVAL;
  34module_param(dev, int, S_IRUGO);
  35MODULE_PARM_DESC(dev, "MTD device number to use");
  36
  37static struct mtd_info *mtd;
  38static unsigned char *writebuf;
  39static unsigned char *readbuf;
  40static unsigned char *bbt;
  41
  42static int subpgsize;
  43static int bufsize;
  44static int ebcnt;
  45static int pgcnt;
  46static int errcnt;
  47static struct rnd_state rnd_state;
  48
  49static inline void clear_data(unsigned char *buf, size_t len)
  50{
  51        memset(buf, 0, len);
  52}
  53
  54static int erase_eraseblock(int ebnum)
  55{
  56        int err;
  57        struct erase_info ei;
  58        loff_t addr = ebnum * mtd->erasesize;
  59
  60        memset(&ei, 0, sizeof(struct erase_info));
  61        ei.mtd  = mtd;
  62        ei.addr = addr;
  63        ei.len  = mtd->erasesize;
  64
  65        err = mtd_erase(mtd, &ei);
  66        if (err) {
  67                pr_err("error %d while erasing EB %d\n", err, ebnum);
  68                return err;
  69        }
  70
  71        if (ei.state == MTD_ERASE_FAILED) {
  72                pr_err("some erase error occurred at EB %d\n",
  73                       ebnum);
  74                return -EIO;
  75        }
  76
  77        return 0;
  78}
  79
  80static int erase_whole_device(void)
  81{
  82        int err;
  83        unsigned int i;
  84
  85        pr_info("erasing whole device\n");
  86        for (i = 0; i < ebcnt; ++i) {
  87                if (bbt[i])
  88                        continue;
  89                err = erase_eraseblock(i);
  90                if (err)
  91                        return err;
  92                cond_resched();
  93        }
  94        pr_info("erased %u eraseblocks\n", i);
  95        return 0;
  96}
  97
  98static int write_eraseblock(int ebnum)
  99{
 100        size_t written;
 101        int err = 0;
 102        loff_t addr = ebnum * mtd->erasesize;
 103
 104        prandom_bytes_state(&rnd_state, writebuf, subpgsize);
 105        err = mtd_write(mtd, addr, subpgsize, &written, writebuf);
 106        if (unlikely(err || written != subpgsize)) {
 107                pr_err("error: write failed at %#llx\n",
 108                       (long long)addr);
 109                if (written != subpgsize) {
 110                        pr_err("  write size: %#x\n", subpgsize);
 111                        pr_err("  written: %#zx\n", written);
 112                }
 113                return err ? err : -1;
 114        }
 115
 116        addr += subpgsize;
 117
 118        prandom_bytes_state(&rnd_state, writebuf, subpgsize);
 119        err = mtd_write(mtd, addr, subpgsize, &written, writebuf);
 120        if (unlikely(err || written != subpgsize)) {
 121                pr_err("error: write failed at %#llx\n",
 122                       (long long)addr);
 123                if (written != subpgsize) {
 124                        pr_err("  write size: %#x\n", subpgsize);
 125                        pr_err("  written: %#zx\n", written);
 126                }
 127                return err ? err : -1;
 128        }
 129
 130        return err;
 131}
 132
 133static int write_eraseblock2(int ebnum)
 134{
 135        size_t written;
 136        int err = 0, k;
 137        loff_t addr = ebnum * mtd->erasesize;
 138
 139        for (k = 1; k < 33; ++k) {
 140                if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize)
 141                        break;
 142                prandom_bytes_state(&rnd_state, writebuf, subpgsize * k);
 143                err = mtd_write(mtd, addr, subpgsize * k, &written, writebuf);
 144                if (unlikely(err || written != subpgsize * k)) {
 145                        pr_err("error: write failed at %#llx\n",
 146                               (long long)addr);
 147                        if (written != subpgsize) {
 148                                pr_err("  write size: %#x\n",
 149                                       subpgsize * k);
 150                                pr_err("  written: %#08zx\n",
 151                                       written);
 152                        }
 153                        return err ? err : -1;
 154                }
 155                addr += subpgsize * k;
 156        }
 157
 158        return err;
 159}
 160
 161static void print_subpage(unsigned char *p)
 162{
 163        int i, j;
 164
 165        for (i = 0; i < subpgsize; ) {
 166                for (j = 0; i < subpgsize && j < 32; ++i, ++j)
 167                        printk("%02x", *p++);
 168                printk("\n");
 169        }
 170}
 171
 172static int verify_eraseblock(int ebnum)
 173{
 174        size_t read;
 175        int err = 0;
 176        loff_t addr = ebnum * mtd->erasesize;
 177
 178        prandom_bytes_state(&rnd_state, writebuf, subpgsize);
 179        clear_data(readbuf, subpgsize);
 180        err = mtd_read(mtd, addr, subpgsize, &read, readbuf);
 181        if (unlikely(err || read != subpgsize)) {
 182                if (mtd_is_bitflip(err) && read == subpgsize) {
 183                        pr_info("ECC correction at %#llx\n",
 184                               (long long)addr);
 185                        err = 0;
 186                } else {
 187                        pr_err("error: read failed at %#llx\n",
 188                               (long long)addr);
 189                        return err ? err : -1;
 190                }
 191        }
 192        if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
 193                pr_err("error: verify failed at %#llx\n",
 194                       (long long)addr);
 195                pr_info("------------- written----------------\n");
 196                print_subpage(writebuf);
 197                pr_info("------------- read ------------------\n");
 198                print_subpage(readbuf);
 199                pr_info("-------------------------------------\n");
 200                errcnt += 1;
 201        }
 202
 203        addr += subpgsize;
 204
 205        prandom_bytes_state(&rnd_state, writebuf, subpgsize);
 206        clear_data(readbuf, subpgsize);
 207        err = mtd_read(mtd, addr, subpgsize, &read, readbuf);
 208        if (unlikely(err || read != subpgsize)) {
 209                if (mtd_is_bitflip(err) && read == subpgsize) {
 210                        pr_info("ECC correction at %#llx\n",
 211                               (long long)addr);
 212                        err = 0;
 213                } else {
 214                        pr_err("error: read failed at %#llx\n",
 215                               (long long)addr);
 216                        return err ? err : -1;
 217                }
 218        }
 219        if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
 220                pr_info("error: verify failed at %#llx\n",
 221                       (long long)addr);
 222                pr_info("------------- written----------------\n");
 223                print_subpage(writebuf);
 224                pr_info("------------- read ------------------\n");
 225                print_subpage(readbuf);
 226                pr_info("-------------------------------------\n");
 227                errcnt += 1;
 228        }
 229
 230        return err;
 231}
 232
 233static int verify_eraseblock2(int ebnum)
 234{
 235        size_t read;
 236        int err = 0, k;
 237        loff_t addr = ebnum * mtd->erasesize;
 238
 239        for (k = 1; k < 33; ++k) {
 240                if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize)
 241                        break;
 242                prandom_bytes_state(&rnd_state, writebuf, subpgsize * k);
 243                clear_data(readbuf, subpgsize * k);
 244                err = mtd_read(mtd, addr, subpgsize * k, &read, readbuf);
 245                if (unlikely(err || read != subpgsize * k)) {
 246                        if (mtd_is_bitflip(err) && read == subpgsize * k) {
 247                                pr_info("ECC correction at %#llx\n",
 248                                       (long long)addr);
 249                                err = 0;
 250                        } else {
 251                                pr_err("error: read failed at "
 252                                       "%#llx\n", (long long)addr);
 253                                return err ? err : -1;
 254                        }
 255                }
 256                if (unlikely(memcmp(readbuf, writebuf, subpgsize * k))) {
 257                        pr_err("error: verify failed at %#llx\n",
 258                               (long long)addr);
 259                        errcnt += 1;
 260                }
 261                addr += subpgsize * k;
 262        }
 263
 264        return err;
 265}
 266
 267static int verify_eraseblock_ff(int ebnum)
 268{
 269        uint32_t j;
 270        size_t read;
 271        int err = 0;
 272        loff_t addr = ebnum * mtd->erasesize;
 273
 274        memset(writebuf, 0xff, subpgsize);
 275        for (j = 0; j < mtd->erasesize / subpgsize; ++j) {
 276                clear_data(readbuf, subpgsize);
 277                err = mtd_read(mtd, addr, subpgsize, &read, readbuf);
 278                if (unlikely(err || read != subpgsize)) {
 279                        if (mtd_is_bitflip(err) && read == subpgsize) {
 280                                pr_info("ECC correction at %#llx\n",
 281                                       (long long)addr);
 282                                err = 0;
 283                        } else {
 284                                pr_err("error: read failed at "
 285                                       "%#llx\n", (long long)addr);
 286                                return err ? err : -1;
 287                        }
 288                }
 289                if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
 290                        pr_err("error: verify 0xff failed at "
 291                               "%#llx\n", (long long)addr);
 292                        errcnt += 1;
 293                }
 294                addr += subpgsize;
 295        }
 296
 297        return err;
 298}
 299
 300static int verify_all_eraseblocks_ff(void)
 301{
 302        int err;
 303        unsigned int i;
 304
 305        pr_info("verifying all eraseblocks for 0xff\n");
 306        for (i = 0; i < ebcnt; ++i) {
 307                if (bbt[i])
 308                        continue;
 309                err = verify_eraseblock_ff(i);
 310                if (err)
 311                        return err;
 312                if (i % 256 == 0)
 313                        pr_info("verified up to eraseblock %u\n", i);
 314                cond_resched();
 315        }
 316        pr_info("verified %u eraseblocks\n", i);
 317        return 0;
 318}
 319
 320static int is_block_bad(int ebnum)
 321{
 322        loff_t addr = ebnum * mtd->erasesize;
 323        int ret;
 324
 325        ret = mtd_block_isbad(mtd, addr);
 326        if (ret)
 327                pr_info("block %d is bad\n", ebnum);
 328        return ret;
 329}
 330
 331static int scan_for_bad_eraseblocks(void)
 332{
 333        int i, bad = 0;
 334
 335        bbt = kzalloc(ebcnt, GFP_KERNEL);
 336        if (!bbt) {
 337                pr_err("error: cannot allocate memory\n");
 338                return -ENOMEM;
 339        }
 340
 341        pr_info("scanning for bad eraseblocks\n");
 342        for (i = 0; i < ebcnt; ++i) {
 343                bbt[i] = is_block_bad(i) ? 1 : 0;
 344                if (bbt[i])
 345                        bad += 1;
 346                cond_resched();
 347        }
 348        pr_info("scanned %d eraseblocks, %d are bad\n", i, bad);
 349        return 0;
 350}
 351
 352static int __init mtd_subpagetest_init(void)
 353{
 354        int err = 0;
 355        uint32_t i;
 356        uint64_t tmp;
 357
 358        printk(KERN_INFO "\n");
 359        printk(KERN_INFO "=================================================\n");
 360
 361        if (dev < 0) {
 362                pr_info("Please specify a valid mtd-device via module parameter\n");
 363                pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
 364                return -EINVAL;
 365        }
 366
 367        pr_info("MTD device: %d\n", dev);
 368
 369        mtd = get_mtd_device(NULL, dev);
 370        if (IS_ERR(mtd)) {
 371                err = PTR_ERR(mtd);
 372                pr_err("error: cannot get MTD device\n");
 373                return err;
 374        }
 375
 376        if (mtd->type != MTD_NANDFLASH) {
 377                pr_info("this test requires NAND flash\n");
 378                goto out;
 379        }
 380
 381        subpgsize = mtd->writesize >> mtd->subpage_sft;
 382        tmp = mtd->size;
 383        do_div(tmp, mtd->erasesize);
 384        ebcnt = tmp;
 385        pgcnt = mtd->erasesize / mtd->writesize;
 386
 387        pr_info("MTD device size %llu, eraseblock size %u, "
 388               "page size %u, subpage size %u, count of eraseblocks %u, "
 389               "pages per eraseblock %u, OOB size %u\n",
 390               (unsigned long long)mtd->size, mtd->erasesize,
 391               mtd->writesize, subpgsize, ebcnt, pgcnt, mtd->oobsize);
 392
 393        err = -ENOMEM;
 394        bufsize = subpgsize * 32;
 395        writebuf = kmalloc(bufsize, GFP_KERNEL);
 396        if (!writebuf) {
 397                pr_info("error: cannot allocate memory\n");
 398                goto out;
 399        }
 400        readbuf = kmalloc(bufsize, GFP_KERNEL);
 401        if (!readbuf) {
 402                pr_info("error: cannot allocate memory\n");
 403                goto out;
 404        }
 405
 406        err = scan_for_bad_eraseblocks();
 407        if (err)
 408                goto out;
 409
 410        err = erase_whole_device();
 411        if (err)
 412                goto out;
 413
 414        pr_info("writing whole device\n");
 415        prandom_seed_state(&rnd_state, 1);
 416        for (i = 0; i < ebcnt; ++i) {
 417                if (bbt[i])
 418                        continue;
 419                err = write_eraseblock(i);
 420                if (unlikely(err))
 421                        goto out;
 422                if (i % 256 == 0)
 423                        pr_info("written up to eraseblock %u\n", i);
 424                cond_resched();
 425        }
 426        pr_info("written %u eraseblocks\n", i);
 427
 428        prandom_seed_state(&rnd_state, 1);
 429        pr_info("verifying all eraseblocks\n");
 430        for (i = 0; i < ebcnt; ++i) {
 431                if (bbt[i])
 432                        continue;
 433                err = verify_eraseblock(i);
 434                if (unlikely(err))
 435                        goto out;
 436                if (i % 256 == 0)
 437                        pr_info("verified up to eraseblock %u\n", i);
 438                cond_resched();
 439        }
 440        pr_info("verified %u eraseblocks\n", i);
 441
 442        err = erase_whole_device();
 443        if (err)
 444                goto out;
 445
 446        err = verify_all_eraseblocks_ff();
 447        if (err)
 448                goto out;
 449
 450        /* Write all eraseblocks */
 451        prandom_seed_state(&rnd_state, 3);
 452        pr_info("writing whole device\n");
 453        for (i = 0; i < ebcnt; ++i) {
 454                if (bbt[i])
 455                        continue;
 456                err = write_eraseblock2(i);
 457                if (unlikely(err))
 458                        goto out;
 459                if (i % 256 == 0)
 460                        pr_info("written up to eraseblock %u\n", i);
 461                cond_resched();
 462        }
 463        pr_info("written %u eraseblocks\n", i);
 464
 465        /* Check all eraseblocks */
 466        prandom_seed_state(&rnd_state, 3);
 467        pr_info("verifying all eraseblocks\n");
 468        for (i = 0; i < ebcnt; ++i) {
 469                if (bbt[i])
 470                        continue;
 471                err = verify_eraseblock2(i);
 472                if (unlikely(err))
 473                        goto out;
 474                if (i % 256 == 0)
 475                        pr_info("verified up to eraseblock %u\n", i);
 476                cond_resched();
 477        }
 478        pr_info("verified %u eraseblocks\n", i);
 479
 480        err = erase_whole_device();
 481        if (err)
 482                goto out;
 483
 484        err = verify_all_eraseblocks_ff();
 485        if (err)
 486                goto out;
 487
 488        pr_info("finished with %d errors\n", errcnt);
 489
 490out:
 491        kfree(bbt);
 492        kfree(readbuf);
 493        kfree(writebuf);
 494        put_mtd_device(mtd);
 495        if (err)
 496                pr_info("error %d occurred\n", err);
 497        printk(KERN_INFO "=================================================\n");
 498        return err;
 499}
 500module_init(mtd_subpagetest_init);
 501
 502static void __exit mtd_subpagetest_exit(void)
 503{
 504        return;
 505}
 506module_exit(mtd_subpagetest_exit);
 507
 508MODULE_DESCRIPTION("Subpage test module");
 509MODULE_AUTHOR("Adrian Hunter");
 510MODULE_LICENSE("GPL");
 511