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