Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

MTD: tests: add mtd_torturetest

This test is designed to work for very long time and it tries to
wear few eraseblocks.

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>

+530
+530
drivers/mtd/tests/mtd_torturetest.c
··· 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 + 36 + static int eb = 8; 37 + module_param(eb, int, S_IRUGO); 38 + MODULE_PARM_DESC(eb, "eraseblock number within the selected MTD device"); 39 + 40 + static int ebcnt = 32; 41 + module_param(ebcnt, int, S_IRUGO); 42 + MODULE_PARM_DESC(ebcnt, "number of consecutive eraseblocks to torture"); 43 + 44 + static int pgcnt; 45 + module_param(pgcnt, int, S_IRUGO); 46 + MODULE_PARM_DESC(pgcnt, "number of pages per eraseblock to torture (0 => all)"); 47 + 48 + static int dev; 49 + module_param(dev, int, S_IRUGO); 50 + MODULE_PARM_DESC(dev, "MTD device number to use"); 51 + 52 + static int gran = 512; 53 + module_param(gran, int, S_IRUGO); 54 + MODULE_PARM_DESC(gran, "how often the status information should be printed"); 55 + 56 + static int check = 1; 57 + module_param(check, int, S_IRUGO); 58 + MODULE_PARM_DESC(check, "if the written data should be checked"); 59 + 60 + static unsigned int cycles_count; 61 + module_param(cycles_count, uint, S_IRUGO); 62 + MODULE_PARM_DESC(cycles_count, "how many erase cycles to do " 63 + "(infinite by default)"); 64 + 65 + static struct mtd_info *mtd; 66 + 67 + /* This buffer contains 0x555555...0xAAAAAA... pattern */ 68 + static unsigned char *patt_5A5; 69 + /* This buffer contains 0xAAAAAA...0x555555... pattern */ 70 + static unsigned char *patt_A5A; 71 + /* This buffer contains all 0xFF bytes */ 72 + static unsigned char *patt_FF; 73 + /* This a temporary buffer is use when checking data */ 74 + static unsigned char *check_buf; 75 + /* How many erase cycles were done */ 76 + static unsigned int erase_cycles; 77 + 78 + static int pgsize; 79 + static struct timeval start, finish; 80 + 81 + static void report_corrupt(unsigned char *read, unsigned char *written); 82 + 83 + static inline void start_timing(void) 84 + { 85 + do_gettimeofday(&start); 86 + } 87 + 88 + static inline void stop_timing(void) 89 + { 90 + do_gettimeofday(&finish); 91 + } 92 + 93 + /* 94 + * Erase eraseblock number @ebnum. 95 + */ 96 + static 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 + */ 126 + static 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 + 138 + retry: 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 + 180 + static 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 + 206 + static 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 + } 385 + out: 386 + 387 + printk(PRINT_PREF "finished after %u erase cycles\n", 388 + erase_cycles); 389 + kfree(check_buf); 390 + out_patt_FF: 391 + kfree(patt_FF); 392 + out_patt_A5A: 393 + kfree(patt_A5A); 394 + out_patt_5A5: 395 + kfree(patt_5A5); 396 + out_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 + } 403 + module_init(tort_init); 404 + 405 + static void __exit tort_exit(void) 406 + { 407 + return; 408 + } 409 + module_exit(tort_exit); 410 + 411 + static int countdiffs(unsigned char *buf, unsigned char *check_buf, 412 + unsigned offset, unsigned len, unsigned *bytesp, 413 + unsigned *bitsp); 414 + static 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 + */ 421 + static 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 %d 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 + 465 + static 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 + */ 499 + static 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 + 528 + MODULE_DESCRIPTION("Eraseblock torturing module"); 529 + MODULE_AUTHOR("Artem Bityutskiy, Jarkko Lavinen, Adrian Hunter"); 530 + MODULE_LICENSE("GPL");