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 v2.6.29-rc4 530 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/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");