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