linux/drivers/mtd/tests/mtd_torturetest.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2006-2008 Artem Bityutskiy
   3 * Copyright (C) 2006-2008 Jarkko Lavinen
   4 * Copyright (C) 2006-2008 Adrian Hunter
   5 *
   6 * This program is free software; you can redistribute it and/or modify it
   7 * under the terms of the GNU General Public License version 2 as published by
   8 * the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope that it will be useful, but WITHOUT
  11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  13 * more details.
  14 *
  15 * You should have received a copy of the GNU General Public License along with
  16 * this program; see the file COPYING. If not, write to the Free Software
  17 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  18 *
  19 * Authors: Artem Bityutskiy, Jarkko Lavinen, Adria Hunter
  20 *
  21 * WARNING: this test program may kill your flash and your device. Do not
  22 * use it unless you know what you do. Authors are not responsible for any
  23 * damage caused by this program.
  24 */
  25
  26#include <linux/init.h>
  27#include <linux/module.h>
  28#include <linux/moduleparam.h>
  29#include <linux/err.h>
  30#include <linux/mtd/mtd.h>
  31#include <linux/sched.h>
  32
  33#define PRINT_PREF KERN_INFO "mtd_torturetest: "
  34#define RETRIES 3
  35
  36static int eb = 8;
  37module_param(eb, int, S_IRUGO);
  38MODULE_PARM_DESC(eb, "eraseblock number within the selected MTD device");
  39
  40static int ebcnt = 32;
  41module_param(ebcnt, int, S_IRUGO);
  42MODULE_PARM_DESC(ebcnt, "number of consecutive eraseblocks to torture");
  43
  44static int pgcnt;
  45module_param(pgcnt, int, S_IRUGO);
  46MODULE_PARM_DESC(pgcnt, "number of pages per eraseblock to torture (0 => all)");
  47
  48static int dev;
  49module_param(dev, int, S_IRUGO);
  50MODULE_PARM_DESC(dev, "MTD device number to use");
  51
  52static int gran = 512;
  53module_param(gran, int, S_IRUGO);
  54MODULE_PARM_DESC(gran, "how often the status information should be printed");
  55
  56static int check = 1;
  57module_param(check, int, S_IRUGO);
  58MODULE_PARM_DESC(check, "if the written data should be checked");
  59
  60static unsigned int cycles_count;
  61module_param(cycles_count, uint, S_IRUGO);
  62MODULE_PARM_DESC(cycles_count, "how many erase cycles to do "
  63                               "(infinite by default)");
  64
  65static struct mtd_info *mtd;
  66
  67/* This buffer contains 0x555555...0xAAAAAA... pattern */
  68static unsigned char *patt_5A5;
  69/* This buffer contains 0xAAAAAA...0x555555... pattern */
  70static unsigned char *patt_A5A;
  71/* This buffer contains all 0xFF bytes */
  72static unsigned char *patt_FF;
  73/* This a temporary buffer is use when checking data */
  74static unsigned char *check_buf;
  75/* How many erase cycles were done */
  76static unsigned int erase_cycles;
  77
  78static int pgsize;
  79static struct timeval start, finish;
  80
  81static void report_corrupt(unsigned char *read, unsigned char *written);
  82
  83static inline void start_timing(void)
  84{
  85        do_gettimeofday(&start);
  86}
  87
  88static inline void stop_timing(void)
  89{
  90        do_gettimeofday(&finish);
  91}
  92
  93/*
  94 * Erase eraseblock number @ebnum.
  95 */
  96static inline int erase_eraseblock(int ebnum)
  97{
  98        int err;
  99        struct erase_info ei;
 100        loff_t addr = ebnum * mtd->erasesize;
 101
 102        memset(&ei, 0, sizeof(struct erase_info));
 103        ei.mtd  = mtd;
 104        ei.addr = addr;
 105        ei.len  = mtd->erasesize;
 106
 107        err = mtd->erase(mtd, &ei);
 108        if (err) {
 109                printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum);
 110                return err;
 111        }
 112
 113        if (ei.state == MTD_ERASE_FAILED) {
 114                printk(PRINT_PREF "some erase error occurred at EB %d\n",
 115                       ebnum);
 116                return -EIO;
 117        }
 118
 119        return 0;
 120}
 121
 122/*
 123 * Check that the contents of eraseblock number @enbum is equivalent to the
 124 * @buf buffer.
 125 */
 126static inline int check_eraseblock(int ebnum, unsigned char *buf)
 127{
 128        int err, retries = 0;
 129        size_t read = 0;
 130        loff_t addr = ebnum * mtd->erasesize;
 131        size_t len = mtd->erasesize;
 132
 133        if (pgcnt) {
 134                addr = (ebnum + 1) * mtd->erasesize - pgcnt * pgsize;
 135                len = pgcnt * pgsize;
 136        }
 137
 138retry:
 139        err = mtd->read(mtd, addr, len, &read, check_buf);
 140        if (err == -EUCLEAN)
 141                printk(PRINT_PREF "single bit flip occurred at EB %d "
 142                       "MTD reported that it was fixed.\n", ebnum);
 143        else if (err) {
 144                printk(PRINT_PREF "error %d while reading EB %d, "
 145                       "read %zd\n", err, ebnum, read);
 146                return err;
 147        }
 148
 149        if (read != len) {
 150                printk(PRINT_PREF "failed to read %zd bytes from EB %d, "
 151                       "read only %zd, but no error reported\n",
 152                       len, ebnum, read);
 153                return -EIO;
 154        }
 155
 156        if (memcmp(buf, check_buf, len)) {
 157                printk(PRINT_PREF "read wrong data from EB %d\n", ebnum);
 158                report_corrupt(check_buf, buf);
 159
 160                if (retries++ < RETRIES) {
 161                        /* Try read again */
 162                        yield();
 163                        printk(PRINT_PREF "re-try reading data from EB %d\n",
 164                               ebnum);
 165                        goto retry;
 166                } else {
 167                        printk(PRINT_PREF "retried %d times, still errors, "
 168                               "give-up\n", RETRIES);
 169                        return -EINVAL;
 170                }
 171        }
 172
 173        if (retries != 0)
 174                printk(PRINT_PREF "only attempt number %d was OK (!!!)\n",
 175                       retries);
 176
 177        return 0;
 178}
 179
 180static inline int write_pattern(int ebnum, void *buf)
 181{
 182        int err;
 183        size_t written = 0;
 184        loff_t addr = ebnum * mtd->erasesize;
 185        size_t len = mtd->erasesize;
 186
 187        if (pgcnt) {
 188                addr = (ebnum + 1) * mtd->erasesize - pgcnt * pgsize;
 189                len = pgcnt * pgsize;
 190        }
 191        err = mtd->write(mtd, addr, len, &written, buf);
 192        if (err) {
 193                printk(PRINT_PREF "error %d while writing EB %d, written %zd"
 194                      " bytes\n", err, ebnum, written);
 195                return err;
 196        }
 197        if (written != len) {
 198                printk(PRINT_PREF "written only %zd bytes of %zd, but no error"
 199                       " reported\n", written, len);
 200                return -EIO;
 201        }
 202
 203        return 0;
 204}
 205
 206static int __init tort_init(void)
 207{
 208        int err = 0, i, infinite = !cycles_count;
 209        int bad_ebs[ebcnt];
 210
 211        printk(KERN_INFO "\n");
 212        printk(KERN_INFO "=================================================\n");
 213        printk(PRINT_PREF "Warning: this program is trying to wear out your "
 214               "flash, stop it if this is not wanted.\n");
 215        printk(PRINT_PREF "MTD device: %d\n", dev);
 216        printk(PRINT_PREF "torture %d eraseblocks (%d-%d) of mtd%d\n",
 217               ebcnt, eb, eb + ebcnt - 1, dev);
 218        if (pgcnt)
 219                printk(PRINT_PREF "torturing just %d pages per eraseblock\n",
 220                        pgcnt);
 221        printk(PRINT_PREF "write verify %s\n", check ? "enabled" : "disabled");
 222
 223        mtd = get_mtd_device(NULL, dev);
 224        if (IS_ERR(mtd)) {
 225                err = PTR_ERR(mtd);
 226                printk(PRINT_PREF "error: cannot get MTD device\n");
 227                return err;
 228        }
 229
 230        if (mtd->writesize == 1) {
 231                printk(PRINT_PREF "not NAND flash, assume page size is 512 "
 232                       "bytes.\n");
 233                pgsize = 512;
 234        } else
 235                pgsize = mtd->writesize;
 236
 237        if (pgcnt && (pgcnt > mtd->erasesize / pgsize || pgcnt < 0)) {
 238                printk(PRINT_PREF "error: invalid pgcnt value %d\n", pgcnt);
 239                goto out_mtd;
 240        }
 241
 242        err = -ENOMEM;
 243        patt_5A5 = kmalloc(mtd->erasesize, GFP_KERNEL);
 244        if (!patt_5A5) {
 245                printk(PRINT_PREF "error: cannot allocate memory\n");
 246                goto out_mtd;
 247        }
 248
 249        patt_A5A = kmalloc(mtd->erasesize, GFP_KERNEL);
 250        if (!patt_A5A) {
 251                printk(PRINT_PREF "error: cannot allocate memory\n");
 252                goto out_patt_5A5;
 253        }
 254
 255        patt_FF = kmalloc(mtd->erasesize, GFP_KERNEL);
 256        if (!patt_FF) {
 257                printk(PRINT_PREF "error: cannot allocate memory\n");
 258                goto out_patt_A5A;
 259        }
 260
 261        check_buf = kmalloc(mtd->erasesize, GFP_KERNEL);
 262        if (!check_buf) {
 263                printk(PRINT_PREF "error: cannot allocate memory\n");
 264                goto out_patt_FF;
 265        }
 266
 267        err = 0;
 268
 269        /* Initialize patterns */
 270        memset(patt_FF, 0xFF, mtd->erasesize);
 271        for (i = 0; i < mtd->erasesize / pgsize; i++) {
 272                if (!(i & 1)) {
 273                        memset(patt_5A5 + i * pgsize, 0x55, pgsize);
 274                        memset(patt_A5A + i * pgsize, 0xAA, pgsize);
 275                } else {
 276                        memset(patt_5A5 + i * pgsize, 0xAA, pgsize);
 277                        memset(patt_A5A + i * pgsize, 0x55, pgsize);
 278                }
 279        }
 280
 281        /*
 282         * Check if there is a bad eraseblock among those we are going to test.
 283         */
 284        memset(&bad_ebs[0], 0, sizeof(int) * ebcnt);
 285        if (mtd->block_isbad) {
 286                for (i = eb; i < eb + ebcnt; i++) {
 287                        err = mtd->block_isbad(mtd,
 288                                               (loff_t)i * mtd->erasesize);
 289
 290                        if (err < 0) {
 291                                printk(PRINT_PREF "block_isbad() returned %d "
 292                                       "for EB %d\n", err, i);
 293                                goto out;
 294                        }
 295
 296                        if (err) {
 297                                printk("EB %d is bad. Skip it.\n", i);
 298                                bad_ebs[i - eb] = 1;
 299                        }
 300                }
 301        }
 302
 303        start_timing();
 304        while (1) {
 305                int i;
 306                void *patt;
 307
 308                /* Erase all eraseblocks */
 309                for (i = eb; i < eb + ebcnt; i++) {
 310                        if (bad_ebs[i - eb])
 311                                continue;
 312                        err = erase_eraseblock(i);
 313                        if (err)
 314                                goto out;
 315                        cond_resched();
 316                }
 317
 318                /* Check if the eraseblocks contain only 0xFF bytes */
 319                if (check) {
 320                        for (i = eb; i < eb + ebcnt; i++) {
 321                                if (bad_ebs[i - eb])
 322                                        continue;
 323                                err = check_eraseblock(i, patt_FF);
 324                                if (err) {
 325                                        printk(PRINT_PREF "verify failed"
 326                                               " for 0xFF... pattern\n");
 327                                        goto out;
 328                                }
 329                                cond_resched();
 330                        }
 331                }
 332
 333                /* Write the pattern */
 334                for (i = eb; i < eb + ebcnt; i++) {
 335                        if (bad_ebs[i - eb])
 336                                continue;
 337                        if ((eb + erase_cycles) & 1)
 338                                patt = patt_5A5;
 339                        else
 340                                patt = patt_A5A;
 341                        err = write_pattern(i, patt);
 342                        if (err)
 343                                goto out;
 344                        cond_resched();
 345                }
 346
 347                /* Verify what we wrote */
 348                if (check) {
 349                        for (i = eb; i < eb + ebcnt; i++) {
 350                                if (bad_ebs[i - eb])
 351                                        continue;
 352                                if ((eb + erase_cycles) & 1)
 353                                        patt = patt_5A5;
 354                                else
 355                                        patt = patt_A5A;
 356                                err = check_eraseblock(i, patt);
 357                                if (err) {
 358                                        printk(PRINT_PREF "verify failed for %s"
 359                                               " pattern\n",
 360                                               ((eb + erase_cycles) & 1) ?
 361                                               "0x55AA55..." : "0xAA55AA...");
 362                                        goto out;
 363                                }
 364                                cond_resched();
 365                        }
 366                }
 367
 368                erase_cycles += 1;
 369
 370                if (erase_cycles % gran == 0) {
 371                        long ms;
 372
 373                        stop_timing();
 374                        ms = (finish.tv_sec - start.tv_sec) * 1000 +
 375                             (finish.tv_usec - start.tv_usec) / 1000;
 376                        printk(PRINT_PREF "%08u erase cycles done, took %lu "
 377                               "milliseconds (%lu seconds)\n",
 378                               erase_cycles, ms, ms / 1000);
 379                        start_timing();
 380                }
 381
 382                if (!infinite && --cycles_count == 0)
 383                        break;
 384        }
 385out:
 386
 387        printk(PRINT_PREF "finished after %u erase cycles\n",
 388               erase_cycles);
 389        kfree(check_buf);
 390out_patt_FF:
 391        kfree(patt_FF);
 392out_patt_A5A:
 393        kfree(patt_A5A);
 394out_patt_5A5:
 395        kfree(patt_5A5);
 396out_mtd:
 397        put_mtd_device(mtd);
 398        if (err)
 399                printk(PRINT_PREF "error %d occurred during torturing\n", err);
 400        printk(KERN_INFO "=================================================\n");
 401        return err;
 402}
 403module_init(tort_init);
 404
 405static void __exit tort_exit(void)
 406{
 407        return;
 408}
 409module_exit(tort_exit);
 410
 411static int countdiffs(unsigned char *buf, unsigned char *check_buf,
 412                      unsigned offset, unsigned len, unsigned *bytesp,
 413                      unsigned *bitsp);
 414static void print_bufs(unsigned char *read, unsigned char *written, int start,
 415                       int len);
 416
 417/*
 418 * Report the detailed information about how the read EB differs from what was
 419 * written.
 420 */
 421static void report_corrupt(unsigned char *read, unsigned char *written)
 422{
 423        int i;
 424        int bytes, bits, pages, first;
 425        int offset, len;
 426        size_t check_len = mtd->erasesize;
 427
 428        if (pgcnt)
 429                check_len = pgcnt * pgsize;
 430
 431        bytes = bits = pages = 0;
 432        for (i = 0; i < check_len; i += pgsize)
 433                if (countdiffs(written, read, i, pgsize, &bytes,
 434                               &bits) >= 0)
 435                        pages++;
 436
 437        printk(PRINT_PREF "verify fails on %d pages, %d bytes/%d bits\n",
 438               pages, bytes, bits);
 439        printk(PRINT_PREF "The following is a list of all differences between"
 440               " what was read from flash and what was expected\n");
 441
 442        for (i = 0; i < check_len; i += pgsize) {
 443                cond_resched();
 444                bytes = bits = 0;
 445                first = countdiffs(written, read, i, pgsize, &bytes,
 446                                   &bits);
 447                if (first < 0)
 448                        continue;
 449
 450                printk("-------------------------------------------------------"
 451                       "----------------------------------\n");
 452
 453                printk(PRINT_PREF "Page %zd has %d bytes/%d bits failing verify,"
 454                       " starting at offset 0x%x\n",
 455                       (mtd->erasesize - check_len + i) / pgsize,
 456                       bytes, bits, first);
 457
 458                offset = first & ~0x7;
 459                len = ((first + bytes) | 0x7) + 1 - offset;
 460
 461                print_bufs(read, written, offset, len);
 462        }
 463}
 464
 465static void print_bufs(unsigned char *read, unsigned char *written, int start,
 466                       int len)
 467{
 468        int i = 0, j1, j2;
 469        char *diff;
 470
 471        printk("Offset       Read                          Written\n");
 472        while (i < len) {
 473                printk("0x%08x: ", start + i);
 474                diff = "   ";
 475                for (j1 = 0; j1 < 8 && i + j1 < len; j1++) {
 476                        printk(" %02x", read[start + i + j1]);
 477                        if (read[start + i + j1] != written[start + i + j1])
 478                                diff = "***";
 479                }
 480
 481                while (j1 < 8) {
 482                        printk(" ");
 483                        j1 += 1;
 484                }
 485
 486                printk("  %s ", diff);
 487
 488                for (j2 = 0; j2 < 8 && i + j2 < len; j2++)
 489                        printk(" %02x", written[start + i + j2]);
 490                printk("\n");
 491                i += 8;
 492        }
 493}
 494
 495/*
 496 * Count the number of differing bytes and bits and return the first differing
 497 * offset.
 498 */
 499static int countdiffs(unsigned char *buf, unsigned char *check_buf,
 500                      unsigned offset, unsigned len, unsigned *bytesp,
 501                      unsigned *bitsp)
 502{
 503        unsigned i, bit;
 504        int first = -1;
 505
 506        for (i = offset; i < offset + len; i++)
 507                if (buf[i] != check_buf[i]) {
 508                        first = i;
 509                        break;
 510                }
 511
 512        while (i < offset + len) {
 513                if (buf[i] != check_buf[i]) {
 514                        (*bytesp)++;
 515                        bit = 1;
 516                        while (bit < 256) {
 517                                if ((buf[i] & bit) != (check_buf[i] & bit))
 518                                        (*bitsp)++;
 519                                bit <<= 1;
 520                        }
 521                }
 522                i++;
 523        }
 524
 525        return first;
 526}
 527
 528MODULE_DESCRIPTION("Eraseblock torturing module");
 529MODULE_AUTHOR("Artem Bityutskiy, Jarkko Lavinen, Adrian Hunter");
 530MODULE_LICENSE("GPL");
 531
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.