···11+/*22+ * Copyright (C) 2006-2008 Artem Bityutskiy33+ * Copyright (C) 2006-2008 Jarkko Lavinen44+ * Copyright (C) 2006-2008 Adrian Hunter55+ *66+ * This program is free software; you can redistribute it and/or modify it77+ * under the terms of the GNU General Public License version 2 as published by88+ * the Free Software Foundation.99+ *1010+ * This program is distributed in the hope that it will be useful, but WITHOUT1111+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or1212+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for1313+ * more details.1414+ *1515+ * You should have received a copy of the GNU General Public License along with1616+ * this program; see the file COPYING. If not, write to the Free Software1717+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.1818+ *1919+ * Authors: Artem Bityutskiy, Jarkko Lavinen, Adria Hunter2020+ *2121+ * WARNING: this test program may kill your flash and your device. Do not2222+ * use it unless you know what you do. Authors are not responsible for any2323+ * damage caused by this program.2424+ */2525+2626+#include <linux/init.h>2727+#include <linux/module.h>2828+#include <linux/moduleparam.h>2929+#include <linux/err.h>3030+#include <linux/mtd/mtd.h>3131+#include <linux/sched.h>3232+3333+#define PRINT_PREF KERN_INFO "mtd_torturetest: "3434+#define RETRIES 33535+3636+static int eb = 8;3737+module_param(eb, int, S_IRUGO);3838+MODULE_PARM_DESC(eb, "eraseblock number within the selected MTD device");3939+4040+static int ebcnt = 32;4141+module_param(ebcnt, int, S_IRUGO);4242+MODULE_PARM_DESC(ebcnt, "number of consecutive eraseblocks to torture");4343+4444+static int pgcnt;4545+module_param(pgcnt, int, S_IRUGO);4646+MODULE_PARM_DESC(pgcnt, "number of pages per eraseblock to torture (0 => all)");4747+4848+static int dev;4949+module_param(dev, int, S_IRUGO);5050+MODULE_PARM_DESC(dev, "MTD device number to use");5151+5252+static int gran = 512;5353+module_param(gran, int, S_IRUGO);5454+MODULE_PARM_DESC(gran, "how often the status information should be printed");5555+5656+static int check = 1;5757+module_param(check, int, S_IRUGO);5858+MODULE_PARM_DESC(check, "if the written data should be checked");5959+6060+static unsigned int cycles_count;6161+module_param(cycles_count, uint, S_IRUGO);6262+MODULE_PARM_DESC(cycles_count, "how many erase cycles to do "6363+ "(infinite by default)");6464+6565+static struct mtd_info *mtd;6666+6767+/* This buffer contains 0x555555...0xAAAAAA... pattern */6868+static unsigned char *patt_5A5;6969+/* This buffer contains 0xAAAAAA...0x555555... pattern */7070+static unsigned char *patt_A5A;7171+/* This buffer contains all 0xFF bytes */7272+static unsigned char *patt_FF;7373+/* This a temporary buffer is use when checking data */7474+static unsigned char *check_buf;7575+/* How many erase cycles were done */7676+static unsigned int erase_cycles;7777+7878+static int pgsize;7979+static struct timeval start, finish;8080+8181+static void report_corrupt(unsigned char *read, unsigned char *written);8282+8383+static inline void start_timing(void)8484+{8585+ do_gettimeofday(&start);8686+}8787+8888+static inline void stop_timing(void)8989+{9090+ do_gettimeofday(&finish);9191+}9292+9393+/*9494+ * Erase eraseblock number @ebnum.9595+ */9696+static inline int erase_eraseblock(int ebnum)9797+{9898+ int err;9999+ struct erase_info ei;100100+ loff_t addr = ebnum * mtd->erasesize;101101+102102+ memset(&ei, 0, sizeof(struct erase_info));103103+ ei.mtd = mtd;104104+ ei.addr = addr;105105+ ei.len = mtd->erasesize;106106+107107+ err = mtd->erase(mtd, &ei);108108+ if (err) {109109+ printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum);110110+ return err;111111+ }112112+113113+ if (ei.state == MTD_ERASE_FAILED) {114114+ printk(PRINT_PREF "some erase error occurred at EB %d\n",115115+ ebnum);116116+ return -EIO;117117+ }118118+119119+ return 0;120120+}121121+122122+/*123123+ * Check that the contents of eraseblock number @enbum is equivalent to the124124+ * @buf buffer.125125+ */126126+static inline int check_eraseblock(int ebnum, unsigned char *buf)127127+{128128+ int err, retries = 0;129129+ size_t read = 0;130130+ loff_t addr = ebnum * mtd->erasesize;131131+ size_t len = mtd->erasesize;132132+133133+ if (pgcnt) {134134+ addr = (ebnum + 1) * mtd->erasesize - pgcnt * pgsize;135135+ len = pgcnt * pgsize;136136+ }137137+138138+retry:139139+ err = mtd->read(mtd, addr, len, &read, check_buf);140140+ if (err == -EUCLEAN)141141+ printk(PRINT_PREF "single bit flip occurred at EB %d "142142+ "MTD reported that it was fixed.\n", ebnum);143143+ else if (err) {144144+ printk(PRINT_PREF "error %d while reading EB %d, "145145+ "read %zd\n", err, ebnum, read);146146+ return err;147147+ }148148+149149+ if (read != len) {150150+ printk(PRINT_PREF "failed to read %zd bytes from EB %d, "151151+ "read only %zd, but no error reported\n",152152+ len, ebnum, read);153153+ return -EIO;154154+ }155155+156156+ if (memcmp(buf, check_buf, len)) {157157+ printk(PRINT_PREF "read wrong data from EB %d\n", ebnum);158158+ report_corrupt(check_buf, buf);159159+160160+ if (retries++ < RETRIES) {161161+ /* Try read again */162162+ yield();163163+ printk(PRINT_PREF "re-try reading data from EB %d\n",164164+ ebnum);165165+ goto retry;166166+ } else {167167+ printk(PRINT_PREF "retried %d times, still errors, "168168+ "give-up\n", RETRIES);169169+ return -EINVAL;170170+ }171171+ }172172+173173+ if (retries != 0)174174+ printk(PRINT_PREF "only attempt number %d was OK (!!!)\n",175175+ retries);176176+177177+ return 0;178178+}179179+180180+static inline int write_pattern(int ebnum, void *buf)181181+{182182+ int err;183183+ size_t written = 0;184184+ loff_t addr = ebnum * mtd->erasesize;185185+ size_t len = mtd->erasesize;186186+187187+ if (pgcnt) {188188+ addr = (ebnum + 1) * mtd->erasesize - pgcnt * pgsize;189189+ len = pgcnt * pgsize;190190+ }191191+ err = mtd->write(mtd, addr, len, &written, buf);192192+ if (err) {193193+ printk(PRINT_PREF "error %d while writing EB %d, written %zd"194194+ " bytes\n", err, ebnum, written);195195+ return err;196196+ }197197+ if (written != len) {198198+ printk(PRINT_PREF "written only %zd bytes of %zd, but no error"199199+ " reported\n", written, len);200200+ return -EIO;201201+ }202202+203203+ return 0;204204+}205205+206206+static int __init tort_init(void)207207+{208208+ int err = 0, i, infinite = !cycles_count;209209+ int bad_ebs[ebcnt];210210+211211+ printk(KERN_INFO "\n");212212+ printk(KERN_INFO "=================================================\n");213213+ printk(PRINT_PREF "Warning: this program is trying to wear out your "214214+ "flash, stop it if this is not wanted.\n");215215+ printk(PRINT_PREF "MTD device: %d\n", dev);216216+ printk(PRINT_PREF "torture %d eraseblocks (%d-%d) of mtd%d\n",217217+ ebcnt, eb, eb + ebcnt - 1, dev);218218+ if (pgcnt)219219+ printk(PRINT_PREF "torturing just %d pages per eraseblock\n",220220+ pgcnt);221221+ printk(PRINT_PREF "write verify %s\n", check ? "enabled" : "disabled");222222+223223+ mtd = get_mtd_device(NULL, dev);224224+ if (IS_ERR(mtd)) {225225+ err = PTR_ERR(mtd);226226+ printk(PRINT_PREF "error: cannot get MTD device\n");227227+ return err;228228+ }229229+230230+ if (mtd->writesize == 1) {231231+ printk(PRINT_PREF "not NAND flash, assume page size is 512 "232232+ "bytes.\n");233233+ pgsize = 512;234234+ } else235235+ pgsize = mtd->writesize;236236+237237+ if (pgcnt && (pgcnt > mtd->erasesize / pgsize || pgcnt < 0)) {238238+ printk(PRINT_PREF "error: invalid pgcnt value %d\n", pgcnt);239239+ goto out_mtd;240240+ }241241+242242+ err = -ENOMEM;243243+ patt_5A5 = kmalloc(mtd->erasesize, GFP_KERNEL);244244+ if (!patt_5A5) {245245+ printk(PRINT_PREF "error: cannot allocate memory\n");246246+ goto out_mtd;247247+ }248248+249249+ patt_A5A = kmalloc(mtd->erasesize, GFP_KERNEL);250250+ if (!patt_A5A) {251251+ printk(PRINT_PREF "error: cannot allocate memory\n");252252+ goto out_patt_5A5;253253+ }254254+255255+ patt_FF = kmalloc(mtd->erasesize, GFP_KERNEL);256256+ if (!patt_FF) {257257+ printk(PRINT_PREF "error: cannot allocate memory\n");258258+ goto out_patt_A5A;259259+ }260260+261261+ check_buf = kmalloc(mtd->erasesize, GFP_KERNEL);262262+ if (!check_buf) {263263+ printk(PRINT_PREF "error: cannot allocate memory\n");264264+ goto out_patt_FF;265265+ }266266+267267+ err = 0;268268+269269+ /* Initialize patterns */270270+ memset(patt_FF, 0xFF, mtd->erasesize);271271+ for (i = 0; i < mtd->erasesize / pgsize; i++) {272272+ if (!(i & 1)) {273273+ memset(patt_5A5 + i * pgsize, 0x55, pgsize);274274+ memset(patt_A5A + i * pgsize, 0xAA, pgsize);275275+ } else {276276+ memset(patt_5A5 + i * pgsize, 0xAA, pgsize);277277+ memset(patt_A5A + i * pgsize, 0x55, pgsize);278278+ }279279+ }280280+281281+ /*282282+ * Check if there is a bad eraseblock among those we are going to test.283283+ */284284+ memset(&bad_ebs[0], 0, sizeof(int) * ebcnt);285285+ if (mtd->block_isbad) {286286+ for (i = eb; i < eb + ebcnt; i++) {287287+ err = mtd->block_isbad(mtd,288288+ (loff_t)i * mtd->erasesize);289289+290290+ if (err < 0) {291291+ printk(PRINT_PREF "block_isbad() returned %d "292292+ "for EB %d\n", err, i);293293+ goto out;294294+ }295295+296296+ if (err) {297297+ printk("EB %d is bad. Skip it.\n", i);298298+ bad_ebs[i - eb] = 1;299299+ }300300+ }301301+ }302302+303303+ start_timing();304304+ while (1) {305305+ int i;306306+ void *patt;307307+308308+ /* Erase all eraseblocks */309309+ for (i = eb; i < eb + ebcnt; i++) {310310+ if (bad_ebs[i - eb])311311+ continue;312312+ err = erase_eraseblock(i);313313+ if (err)314314+ goto out;315315+ cond_resched();316316+ }317317+318318+ /* Check if the eraseblocks contain only 0xFF bytes */319319+ if (check) {320320+ for (i = eb; i < eb + ebcnt; i++) {321321+ if (bad_ebs[i - eb])322322+ continue;323323+ err = check_eraseblock(i, patt_FF);324324+ if (err) {325325+ printk(PRINT_PREF "verify failed"326326+ " for 0xFF... pattern\n");327327+ goto out;328328+ }329329+ cond_resched();330330+ }331331+ }332332+333333+ /* Write the pattern */334334+ for (i = eb; i < eb + ebcnt; i++) {335335+ if (bad_ebs[i - eb])336336+ continue;337337+ if ((eb + erase_cycles) & 1)338338+ patt = patt_5A5;339339+ else340340+ patt = patt_A5A;341341+ err = write_pattern(i, patt);342342+ if (err)343343+ goto out;344344+ cond_resched();345345+ }346346+347347+ /* Verify what we wrote */348348+ if (check) {349349+ for (i = eb; i < eb + ebcnt; i++) {350350+ if (bad_ebs[i - eb])351351+ continue;352352+ if ((eb + erase_cycles) & 1)353353+ patt = patt_5A5;354354+ else355355+ patt = patt_A5A;356356+ err = check_eraseblock(i, patt);357357+ if (err) {358358+ printk(PRINT_PREF "verify failed for %s"359359+ " pattern\n",360360+ ((eb + erase_cycles) & 1) ?361361+ "0x55AA55..." : "0xAA55AA...");362362+ goto out;363363+ }364364+ cond_resched();365365+ }366366+ }367367+368368+ erase_cycles += 1;369369+370370+ if (erase_cycles % gran == 0) {371371+ long ms;372372+373373+ stop_timing();374374+ ms = (finish.tv_sec - start.tv_sec) * 1000 +375375+ (finish.tv_usec - start.tv_usec) / 1000;376376+ printk(PRINT_PREF "%08u erase cycles done, took %lu "377377+ "milliseconds (%lu seconds)\n",378378+ erase_cycles, ms, ms / 1000);379379+ start_timing();380380+ }381381+382382+ if (!infinite && --cycles_count == 0)383383+ break;384384+ }385385+out:386386+387387+ printk(PRINT_PREF "finished after %u erase cycles\n",388388+ erase_cycles);389389+ kfree(check_buf);390390+out_patt_FF:391391+ kfree(patt_FF);392392+out_patt_A5A:393393+ kfree(patt_A5A);394394+out_patt_5A5:395395+ kfree(patt_5A5);396396+out_mtd:397397+ put_mtd_device(mtd);398398+ if (err)399399+ printk(PRINT_PREF "error %d occurred during torturing\n", err);400400+ printk(KERN_INFO "=================================================\n");401401+ return err;402402+}403403+module_init(tort_init);404404+405405+static void __exit tort_exit(void)406406+{407407+ return;408408+}409409+module_exit(tort_exit);410410+411411+static int countdiffs(unsigned char *buf, unsigned char *check_buf,412412+ unsigned offset, unsigned len, unsigned *bytesp,413413+ unsigned *bitsp);414414+static void print_bufs(unsigned char *read, unsigned char *written, int start,415415+ int len);416416+417417+/*418418+ * Report the detailed information about how the read EB differs from what was419419+ * written.420420+ */421421+static void report_corrupt(unsigned char *read, unsigned char *written)422422+{423423+ int i;424424+ int bytes, bits, pages, first;425425+ int offset, len;426426+ size_t check_len = mtd->erasesize;427427+428428+ if (pgcnt)429429+ check_len = pgcnt * pgsize;430430+431431+ bytes = bits = pages = 0;432432+ for (i = 0; i < check_len; i += pgsize)433433+ if (countdiffs(written, read, i, pgsize, &bytes,434434+ &bits) >= 0)435435+ pages++;436436+437437+ printk(PRINT_PREF "verify fails on %d pages, %d bytes/%d bits\n",438438+ pages, bytes, bits);439439+ printk(PRINT_PREF "The following is a list of all differences between"440440+ " what was read from flash and what was expected\n");441441+442442+ for (i = 0; i < check_len; i += pgsize) {443443+ cond_resched();444444+ bytes = bits = 0;445445+ first = countdiffs(written, read, i, pgsize, &bytes,446446+ &bits);447447+ if (first < 0)448448+ continue;449449+450450+ printk("-------------------------------------------------------"451451+ "----------------------------------\n");452452+453453+ printk(PRINT_PREF "Page %d has %d bytes/%d bits failing verify,"454454+ " starting at offset 0x%x\n",455455+ (mtd->erasesize - check_len + i) / pgsize,456456+ bytes, bits, first);457457+458458+ offset = first & ~0x7;459459+ len = ((first + bytes) | 0x7) + 1 - offset;460460+461461+ print_bufs(read, written, offset, len);462462+ }463463+}464464+465465+static void print_bufs(unsigned char *read, unsigned char *written, int start,466466+ int len)467467+{468468+ int i = 0, j1, j2;469469+ char *diff;470470+471471+ printk("Offset Read Written\n");472472+ while (i < len) {473473+ printk("0x%08x: ", start + i);474474+ diff = " ";475475+ for (j1 = 0; j1 < 8 && i + j1 < len; j1++) {476476+ printk(" %02x", read[start + i + j1]);477477+ if (read[start + i + j1] != written[start + i + j1])478478+ diff = "***";479479+ }480480+481481+ while (j1 < 8) {482482+ printk(" ");483483+ j1 += 1;484484+ }485485+486486+ printk(" %s ", diff);487487+488488+ for (j2 = 0; j2 < 8 && i + j2 < len; j2++)489489+ printk(" %02x", written[start + i + j2]);490490+ printk("\n");491491+ i += 8;492492+ }493493+}494494+495495+/*496496+ * Count the number of differing bytes and bits and return the first differing497497+ * offset.498498+ */499499+static int countdiffs(unsigned char *buf, unsigned char *check_buf,500500+ unsigned offset, unsigned len, unsigned *bytesp,501501+ unsigned *bitsp)502502+{503503+ unsigned i, bit;504504+ int first = -1;505505+506506+ for (i = offset; i < offset + len; i++)507507+ if (buf[i] != check_buf[i]) {508508+ first = i;509509+ break;510510+ }511511+512512+ while (i < offset + len) {513513+ if (buf[i] != check_buf[i]) {514514+ (*bytesp)++;515515+ bit = 1;516516+ while (bit < 256) {517517+ if ((buf[i] & bit) != (check_buf[i] & bit))518518+ (*bitsp)++;519519+ bit <<= 1;520520+ }521521+ }522522+ i++;523523+ }524524+525525+ return first;526526+}527527+528528+MODULE_DESCRIPTION("Eraseblock torturing module");529529+MODULE_AUTHOR("Artem Bityutskiy, Jarkko Lavinen, Adrian Hunter");530530+MODULE_LICENSE("GPL");