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