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.8-rc2 538 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[ebcnt]; 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 pr_err("error: cannot allocate memory\n"); 255 goto out_mtd; 256 } 257 258 patt_A5A = kmalloc(mtd->erasesize, GFP_KERNEL); 259 if (!patt_A5A) { 260 pr_err("error: cannot allocate memory\n"); 261 goto out_patt_5A5; 262 } 263 264 patt_FF = kmalloc(mtd->erasesize, GFP_KERNEL); 265 if (!patt_FF) { 266 pr_err("error: cannot allocate memory\n"); 267 goto out_patt_A5A; 268 } 269 270 check_buf = kmalloc(mtd->erasesize, GFP_KERNEL); 271 if (!check_buf) { 272 pr_err("error: cannot allocate memory\n"); 273 goto out_patt_FF; 274 } 275 276 err = 0; 277 278 /* Initialize patterns */ 279 memset(patt_FF, 0xFF, mtd->erasesize); 280 for (i = 0; i < mtd->erasesize / pgsize; i++) { 281 if (!(i & 1)) { 282 memset(patt_5A5 + i * pgsize, 0x55, pgsize); 283 memset(patt_A5A + i * pgsize, 0xAA, pgsize); 284 } else { 285 memset(patt_5A5 + i * pgsize, 0xAA, pgsize); 286 memset(patt_A5A + i * pgsize, 0x55, pgsize); 287 } 288 } 289 290 /* 291 * Check if there is a bad eraseblock among those we are going to test. 292 */ 293 memset(&bad_ebs[0], 0, sizeof(int) * ebcnt); 294 if (mtd_can_have_bb(mtd)) { 295 for (i = eb; i < eb + ebcnt; i++) { 296 err = mtd_block_isbad(mtd, (loff_t)i * mtd->erasesize); 297 298 if (err < 0) { 299 pr_info("block_isbad() returned %d " 300 "for EB %d\n", err, i); 301 goto out; 302 } 303 304 if (err) { 305 pr_err("EB %d is bad. Skip it.\n", i); 306 bad_ebs[i - eb] = 1; 307 } 308 } 309 } 310 311 start_timing(); 312 while (1) { 313 int i; 314 void *patt; 315 316 /* Erase all eraseblocks */ 317 for (i = eb; i < eb + ebcnt; i++) { 318 if (bad_ebs[i - eb]) 319 continue; 320 err = erase_eraseblock(i); 321 if (err) 322 goto out; 323 cond_resched(); 324 } 325 326 /* Check if the eraseblocks contain only 0xFF bytes */ 327 if (check) { 328 for (i = eb; i < eb + ebcnt; i++) { 329 if (bad_ebs[i - eb]) 330 continue; 331 err = check_eraseblock(i, patt_FF); 332 if (err) { 333 pr_info("verify failed" 334 " for 0xFF... pattern\n"); 335 goto out; 336 } 337 cond_resched(); 338 } 339 } 340 341 /* Write the pattern */ 342 for (i = eb; i < eb + ebcnt; i++) { 343 if (bad_ebs[i - eb]) 344 continue; 345 if ((eb + erase_cycles) & 1) 346 patt = patt_5A5; 347 else 348 patt = patt_A5A; 349 err = write_pattern(i, patt); 350 if (err) 351 goto out; 352 cond_resched(); 353 } 354 355 /* Verify what we wrote */ 356 if (check) { 357 for (i = eb; i < eb + ebcnt; i++) { 358 if (bad_ebs[i - eb]) 359 continue; 360 if ((eb + erase_cycles) & 1) 361 patt = patt_5A5; 362 else 363 patt = patt_A5A; 364 err = check_eraseblock(i, patt); 365 if (err) { 366 pr_info("verify failed for %s" 367 " pattern\n", 368 ((eb + erase_cycles) & 1) ? 369 "0x55AA55..." : "0xAA55AA..."); 370 goto out; 371 } 372 cond_resched(); 373 } 374 } 375 376 erase_cycles += 1; 377 378 if (erase_cycles % gran == 0) { 379 long ms; 380 381 stop_timing(); 382 ms = (finish.tv_sec - start.tv_sec) * 1000 + 383 (finish.tv_usec - start.tv_usec) / 1000; 384 pr_info("%08u erase cycles done, took %lu " 385 "milliseconds (%lu seconds)\n", 386 erase_cycles, ms, ms / 1000); 387 start_timing(); 388 } 389 390 if (!infinite && --cycles_count == 0) 391 break; 392 } 393out: 394 395 pr_info("finished after %u erase cycles\n", 396 erase_cycles); 397 kfree(check_buf); 398out_patt_FF: 399 kfree(patt_FF); 400out_patt_A5A: 401 kfree(patt_A5A); 402out_patt_5A5: 403 kfree(patt_5A5); 404out_mtd: 405 put_mtd_device(mtd); 406 if (err) 407 pr_info("error %d occurred during torturing\n", err); 408 printk(KERN_INFO "=================================================\n"); 409 return err; 410} 411module_init(tort_init); 412 413static void __exit tort_exit(void) 414{ 415 return; 416} 417module_exit(tort_exit); 418 419static int countdiffs(unsigned char *buf, unsigned char *check_buf, 420 unsigned offset, unsigned len, unsigned *bytesp, 421 unsigned *bitsp); 422static void print_bufs(unsigned char *read, unsigned char *written, int start, 423 int len); 424 425/* 426 * Report the detailed information about how the read EB differs from what was 427 * written. 428 */ 429static void report_corrupt(unsigned char *read, unsigned char *written) 430{ 431 int i; 432 int bytes, bits, pages, first; 433 int offset, len; 434 size_t check_len = mtd->erasesize; 435 436 if (pgcnt) 437 check_len = pgcnt * pgsize; 438 439 bytes = bits = pages = 0; 440 for (i = 0; i < check_len; i += pgsize) 441 if (countdiffs(written, read, i, pgsize, &bytes, 442 &bits) >= 0) 443 pages++; 444 445 pr_info("verify fails on %d pages, %d bytes/%d bits\n", 446 pages, bytes, bits); 447 pr_info("The following is a list of all differences between" 448 " what was read from flash and what was expected\n"); 449 450 for (i = 0; i < check_len; i += pgsize) { 451 cond_resched(); 452 bytes = bits = 0; 453 first = countdiffs(written, read, i, pgsize, &bytes, 454 &bits); 455 if (first < 0) 456 continue; 457 458 printk("-------------------------------------------------------" 459 "----------------------------------\n"); 460 461 pr_info("Page %zd has %d bytes/%d bits failing verify," 462 " starting at offset 0x%x\n", 463 (mtd->erasesize - check_len + i) / pgsize, 464 bytes, bits, first); 465 466 offset = first & ~0x7; 467 len = ((first + bytes) | 0x7) + 1 - offset; 468 469 print_bufs(read, written, offset, len); 470 } 471} 472 473static void print_bufs(unsigned char *read, unsigned char *written, int start, 474 int len) 475{ 476 int i = 0, j1, j2; 477 char *diff; 478 479 printk("Offset Read Written\n"); 480 while (i < len) { 481 printk("0x%08x: ", start + i); 482 diff = " "; 483 for (j1 = 0; j1 < 8 && i + j1 < len; j1++) { 484 printk(" %02x", read[start + i + j1]); 485 if (read[start + i + j1] != written[start + i + j1]) 486 diff = "***"; 487 } 488 489 while (j1 < 8) { 490 printk(" "); 491 j1 += 1; 492 } 493 494 printk(" %s ", diff); 495 496 for (j2 = 0; j2 < 8 && i + j2 < len; j2++) 497 printk(" %02x", written[start + i + j2]); 498 printk("\n"); 499 i += 8; 500 } 501} 502 503/* 504 * Count the number of differing bytes and bits and return the first differing 505 * offset. 506 */ 507static int countdiffs(unsigned char *buf, unsigned char *check_buf, 508 unsigned offset, unsigned len, unsigned *bytesp, 509 unsigned *bitsp) 510{ 511 unsigned i, bit; 512 int first = -1; 513 514 for (i = offset; i < offset + len; i++) 515 if (buf[i] != check_buf[i]) { 516 first = i; 517 break; 518 } 519 520 while (i < offset + len) { 521 if (buf[i] != check_buf[i]) { 522 (*bytesp)++; 523 bit = 1; 524 while (bit < 256) { 525 if ((buf[i] & bit) != (check_buf[i] & bit)) 526 (*bitsp)++; 527 bit <<= 1; 528 } 529 } 530 i++; 531 } 532 533 return first; 534} 535 536MODULE_DESCRIPTION("Eraseblock torturing module"); 537MODULE_AUTHOR("Artem Bityutskiy, Jarkko Lavinen, Adrian Hunter"); 538MODULE_LICENSE("GPL");