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

Configure Feed

Select the types of activity you want to include in your feed.

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