1*a995c792SAkinobu Mita /* 2*a995c792SAkinobu Mita * Copyright (C) 2006-2008 Nokia Corporation 3*a995c792SAkinobu Mita * 4*a995c792SAkinobu Mita * This program is free software; you can redistribute it and/or modify it 5*a995c792SAkinobu Mita * under the terms of the GNU General Public License version 2 as published by 6*a995c792SAkinobu Mita * the Free Software Foundation. 7*a995c792SAkinobu Mita * 8*a995c792SAkinobu Mita * This program is distributed in the hope that it will be useful, but WITHOUT 9*a995c792SAkinobu Mita * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10*a995c792SAkinobu Mita * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11*a995c792SAkinobu Mita * more details. 12*a995c792SAkinobu Mita * 13*a995c792SAkinobu Mita * You should have received a copy of the GNU General Public License along with 14*a995c792SAkinobu Mita * this program; see the file COPYING. If not, write to the Free Software 15*a995c792SAkinobu Mita * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 16*a995c792SAkinobu Mita * 17*a995c792SAkinobu Mita * Check MTD device read. 18*a995c792SAkinobu Mita * 19*a995c792SAkinobu Mita * Author: Adrian Hunter <ext-adrian.hunter@nokia.com> 20*a995c792SAkinobu Mita */ 21*a995c792SAkinobu Mita 22*a995c792SAkinobu Mita #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 23*a995c792SAkinobu Mita 24*a995c792SAkinobu Mita #include <linux/init.h> 25*a995c792SAkinobu Mita #include <linux/module.h> 26*a995c792SAkinobu Mita #include <linux/moduleparam.h> 27*a995c792SAkinobu Mita #include <linux/err.h> 28*a995c792SAkinobu Mita #include <linux/mtd/mtd.h> 29*a995c792SAkinobu Mita #include <linux/slab.h> 30*a995c792SAkinobu Mita #include <linux/sched.h> 31*a995c792SAkinobu Mita 32*a995c792SAkinobu Mita static int dev = -EINVAL; 33*a995c792SAkinobu Mita module_param(dev, int, S_IRUGO); 34*a995c792SAkinobu Mita MODULE_PARM_DESC(dev, "MTD device number to use"); 35*a995c792SAkinobu Mita 36*a995c792SAkinobu Mita static struct mtd_info *mtd; 37*a995c792SAkinobu Mita static unsigned char *iobuf; 38*a995c792SAkinobu Mita static unsigned char *iobuf1; 39*a995c792SAkinobu Mita static unsigned char *bbt; 40*a995c792SAkinobu Mita 41*a995c792SAkinobu Mita static int pgsize; 42*a995c792SAkinobu Mita static int ebcnt; 43*a995c792SAkinobu Mita static int pgcnt; 44*a995c792SAkinobu Mita 45*a995c792SAkinobu Mita static int read_eraseblock_by_page(int ebnum) 46*a995c792SAkinobu Mita { 47*a995c792SAkinobu Mita size_t read; 48*a995c792SAkinobu Mita int i, ret, err = 0; 49*a995c792SAkinobu Mita loff_t addr = ebnum * mtd->erasesize; 50*a995c792SAkinobu Mita void *buf = iobuf; 51*a995c792SAkinobu Mita void *oobbuf = iobuf1; 52*a995c792SAkinobu Mita 53*a995c792SAkinobu Mita for (i = 0; i < pgcnt; i++) { 54*a995c792SAkinobu Mita memset(buf, 0 , pgsize); 55*a995c792SAkinobu Mita ret = mtd_read(mtd, addr, pgsize, &read, buf); 56*a995c792SAkinobu Mita if (ret == -EUCLEAN) 57*a995c792SAkinobu Mita ret = 0; 58*a995c792SAkinobu Mita if (ret || read != pgsize) { 59*a995c792SAkinobu Mita pr_err("error: read failed at %#llx\n", 60*a995c792SAkinobu Mita (long long)addr); 61*a995c792SAkinobu Mita if (!err) 62*a995c792SAkinobu Mita err = ret; 63*a995c792SAkinobu Mita if (!err) 64*a995c792SAkinobu Mita err = -EINVAL; 65*a995c792SAkinobu Mita } 66*a995c792SAkinobu Mita if (mtd->oobsize) { 67*a995c792SAkinobu Mita struct mtd_oob_ops ops; 68*a995c792SAkinobu Mita 69*a995c792SAkinobu Mita ops.mode = MTD_OPS_PLACE_OOB; 70*a995c792SAkinobu Mita ops.len = 0; 71*a995c792SAkinobu Mita ops.retlen = 0; 72*a995c792SAkinobu Mita ops.ooblen = mtd->oobsize; 73*a995c792SAkinobu Mita ops.oobretlen = 0; 74*a995c792SAkinobu Mita ops.ooboffs = 0; 75*a995c792SAkinobu Mita ops.datbuf = NULL; 76*a995c792SAkinobu Mita ops.oobbuf = oobbuf; 77*a995c792SAkinobu Mita ret = mtd_read_oob(mtd, addr, &ops); 78*a995c792SAkinobu Mita if ((ret && !mtd_is_bitflip(ret)) || 79*a995c792SAkinobu Mita ops.oobretlen != mtd->oobsize) { 80*a995c792SAkinobu Mita pr_err("error: read oob failed at " 81*a995c792SAkinobu Mita "%#llx\n", (long long)addr); 82*a995c792SAkinobu Mita if (!err) 83*a995c792SAkinobu Mita err = ret; 84*a995c792SAkinobu Mita if (!err) 85*a995c792SAkinobu Mita err = -EINVAL; 86*a995c792SAkinobu Mita } 87*a995c792SAkinobu Mita oobbuf += mtd->oobsize; 88*a995c792SAkinobu Mita } 89*a995c792SAkinobu Mita addr += pgsize; 90*a995c792SAkinobu Mita buf += pgsize; 91*a995c792SAkinobu Mita } 92*a995c792SAkinobu Mita 93*a995c792SAkinobu Mita return err; 94*a995c792SAkinobu Mita } 95*a995c792SAkinobu Mita 96*a995c792SAkinobu Mita static void dump_eraseblock(int ebnum) 97*a995c792SAkinobu Mita { 98*a995c792SAkinobu Mita int i, j, n; 99*a995c792SAkinobu Mita char line[128]; 100*a995c792SAkinobu Mita int pg, oob; 101*a995c792SAkinobu Mita 102*a995c792SAkinobu Mita pr_info("dumping eraseblock %d\n", ebnum); 103*a995c792SAkinobu Mita n = mtd->erasesize; 104*a995c792SAkinobu Mita for (i = 0; i < n;) { 105*a995c792SAkinobu Mita char *p = line; 106*a995c792SAkinobu Mita 107*a995c792SAkinobu Mita p += sprintf(p, "%05x: ", i); 108*a995c792SAkinobu Mita for (j = 0; j < 32 && i < n; j++, i++) 109*a995c792SAkinobu Mita p += sprintf(p, "%02x", (unsigned int)iobuf[i]); 110*a995c792SAkinobu Mita printk(KERN_CRIT "%s\n", line); 111*a995c792SAkinobu Mita cond_resched(); 112*a995c792SAkinobu Mita } 113*a995c792SAkinobu Mita if (!mtd->oobsize) 114*a995c792SAkinobu Mita return; 115*a995c792SAkinobu Mita pr_info("dumping oob from eraseblock %d\n", ebnum); 116*a995c792SAkinobu Mita n = mtd->oobsize; 117*a995c792SAkinobu Mita for (pg = 0, i = 0; pg < pgcnt; pg++) 118*a995c792SAkinobu Mita for (oob = 0; oob < n;) { 119*a995c792SAkinobu Mita char *p = line; 120*a995c792SAkinobu Mita 121*a995c792SAkinobu Mita p += sprintf(p, "%05x: ", i); 122*a995c792SAkinobu Mita for (j = 0; j < 32 && oob < n; j++, oob++, i++) 123*a995c792SAkinobu Mita p += sprintf(p, "%02x", 124*a995c792SAkinobu Mita (unsigned int)iobuf1[i]); 125*a995c792SAkinobu Mita printk(KERN_CRIT "%s\n", line); 126*a995c792SAkinobu Mita cond_resched(); 127*a995c792SAkinobu Mita } 128*a995c792SAkinobu Mita } 129*a995c792SAkinobu Mita 130*a995c792SAkinobu Mita static int is_block_bad(int ebnum) 131*a995c792SAkinobu Mita { 132*a995c792SAkinobu Mita loff_t addr = ebnum * mtd->erasesize; 133*a995c792SAkinobu Mita int ret; 134*a995c792SAkinobu Mita 135*a995c792SAkinobu Mita ret = mtd_block_isbad(mtd, addr); 136*a995c792SAkinobu Mita if (ret) 137*a995c792SAkinobu Mita pr_info("block %d is bad\n", ebnum); 138*a995c792SAkinobu Mita return ret; 139*a995c792SAkinobu Mita } 140*a995c792SAkinobu Mita 141*a995c792SAkinobu Mita static int scan_for_bad_eraseblocks(void) 142*a995c792SAkinobu Mita { 143*a995c792SAkinobu Mita int i, bad = 0; 144*a995c792SAkinobu Mita 145*a995c792SAkinobu Mita bbt = kzalloc(ebcnt, GFP_KERNEL); 146*a995c792SAkinobu Mita if (!bbt) 147*a995c792SAkinobu Mita return -ENOMEM; 148*a995c792SAkinobu Mita 149*a995c792SAkinobu Mita if (!mtd_can_have_bb(mtd)) 150*a995c792SAkinobu Mita return 0; 151*a995c792SAkinobu Mita 152*a995c792SAkinobu Mita pr_info("scanning for bad eraseblocks\n"); 153*a995c792SAkinobu Mita for (i = 0; i < ebcnt; ++i) { 154*a995c792SAkinobu Mita bbt[i] = is_block_bad(i) ? 1 : 0; 155*a995c792SAkinobu Mita if (bbt[i]) 156*a995c792SAkinobu Mita bad += 1; 157*a995c792SAkinobu Mita cond_resched(); 158*a995c792SAkinobu Mita } 159*a995c792SAkinobu Mita pr_info("scanned %d eraseblocks, %d are bad\n", i, bad); 160*a995c792SAkinobu Mita return 0; 161*a995c792SAkinobu Mita } 162*a995c792SAkinobu Mita 163*a995c792SAkinobu Mita static int __init mtd_readtest_init(void) 164*a995c792SAkinobu Mita { 165*a995c792SAkinobu Mita uint64_t tmp; 166*a995c792SAkinobu Mita int err, i; 167*a995c792SAkinobu Mita 168*a995c792SAkinobu Mita printk(KERN_INFO "\n"); 169*a995c792SAkinobu Mita printk(KERN_INFO "=================================================\n"); 170*a995c792SAkinobu Mita 171*a995c792SAkinobu Mita if (dev < 0) { 172*a995c792SAkinobu Mita pr_info("Please specify a valid mtd-device via module parameter\n"); 173*a995c792SAkinobu Mita return -EINVAL; 174*a995c792SAkinobu Mita } 175*a995c792SAkinobu Mita 176*a995c792SAkinobu Mita pr_info("MTD device: %d\n", dev); 177*a995c792SAkinobu Mita 178*a995c792SAkinobu Mita mtd = get_mtd_device(NULL, dev); 179*a995c792SAkinobu Mita if (IS_ERR(mtd)) { 180*a995c792SAkinobu Mita err = PTR_ERR(mtd); 181*a995c792SAkinobu Mita pr_err("error: Cannot get MTD device\n"); 182*a995c792SAkinobu Mita return err; 183*a995c792SAkinobu Mita } 184*a995c792SAkinobu Mita 185*a995c792SAkinobu Mita if (mtd->writesize == 1) { 186*a995c792SAkinobu Mita pr_info("not NAND flash, assume page size is 512 " 187*a995c792SAkinobu Mita "bytes.\n"); 188*a995c792SAkinobu Mita pgsize = 512; 189*a995c792SAkinobu Mita } else 190*a995c792SAkinobu Mita pgsize = mtd->writesize; 191*a995c792SAkinobu Mita 192*a995c792SAkinobu Mita tmp = mtd->size; 193*a995c792SAkinobu Mita do_div(tmp, mtd->erasesize); 194*a995c792SAkinobu Mita ebcnt = tmp; 195*a995c792SAkinobu Mita pgcnt = mtd->erasesize / pgsize; 196*a995c792SAkinobu Mita 197*a995c792SAkinobu Mita pr_info("MTD device size %llu, eraseblock size %u, " 198*a995c792SAkinobu Mita "page size %u, count of eraseblocks %u, pages per " 199*a995c792SAkinobu Mita "eraseblock %u, OOB size %u\n", 200*a995c792SAkinobu Mita (unsigned long long)mtd->size, mtd->erasesize, 201*a995c792SAkinobu Mita pgsize, ebcnt, pgcnt, mtd->oobsize); 202*a995c792SAkinobu Mita 203*a995c792SAkinobu Mita err = -ENOMEM; 204*a995c792SAkinobu Mita iobuf = kmalloc(mtd->erasesize, GFP_KERNEL); 205*a995c792SAkinobu Mita if (!iobuf) 206*a995c792SAkinobu Mita goto out; 207*a995c792SAkinobu Mita iobuf1 = kmalloc(mtd->erasesize, GFP_KERNEL); 208*a995c792SAkinobu Mita if (!iobuf1) 209*a995c792SAkinobu Mita goto out; 210*a995c792SAkinobu Mita 211*a995c792SAkinobu Mita err = scan_for_bad_eraseblocks(); 212*a995c792SAkinobu Mita if (err) 213*a995c792SAkinobu Mita goto out; 214*a995c792SAkinobu Mita 215*a995c792SAkinobu Mita /* Read all eraseblocks 1 page at a time */ 216*a995c792SAkinobu Mita pr_info("testing page read\n"); 217*a995c792SAkinobu Mita for (i = 0; i < ebcnt; ++i) { 218*a995c792SAkinobu Mita int ret; 219*a995c792SAkinobu Mita 220*a995c792SAkinobu Mita if (bbt[i]) 221*a995c792SAkinobu Mita continue; 222*a995c792SAkinobu Mita ret = read_eraseblock_by_page(i); 223*a995c792SAkinobu Mita if (ret) { 224*a995c792SAkinobu Mita dump_eraseblock(i); 225*a995c792SAkinobu Mita if (!err) 226*a995c792SAkinobu Mita err = ret; 227*a995c792SAkinobu Mita } 228*a995c792SAkinobu Mita cond_resched(); 229*a995c792SAkinobu Mita } 230*a995c792SAkinobu Mita 231*a995c792SAkinobu Mita if (err) 232*a995c792SAkinobu Mita pr_info("finished with errors\n"); 233*a995c792SAkinobu Mita else 234*a995c792SAkinobu Mita pr_info("finished\n"); 235*a995c792SAkinobu Mita 236*a995c792SAkinobu Mita out: 237*a995c792SAkinobu Mita 238*a995c792SAkinobu Mita kfree(iobuf); 239*a995c792SAkinobu Mita kfree(iobuf1); 240*a995c792SAkinobu Mita kfree(bbt); 241*a995c792SAkinobu Mita put_mtd_device(mtd); 242*a995c792SAkinobu Mita if (err) 243*a995c792SAkinobu Mita pr_info("error %d occurred\n", err); 244*a995c792SAkinobu Mita printk(KERN_INFO "=================================================\n"); 245*a995c792SAkinobu Mita return err; 246*a995c792SAkinobu Mita } 247*a995c792SAkinobu Mita module_init(mtd_readtest_init); 248*a995c792SAkinobu Mita 249*a995c792SAkinobu Mita static void __exit mtd_readtest_exit(void) 250*a995c792SAkinobu Mita { 251*a995c792SAkinobu Mita return; 252*a995c792SAkinobu Mita } 253*a995c792SAkinobu Mita module_exit(mtd_readtest_exit); 254*a995c792SAkinobu Mita 255*a995c792SAkinobu Mita MODULE_DESCRIPTION("Read test module"); 256*a995c792SAkinobu Mita MODULE_AUTHOR("Adrian Hunter"); 257*a995c792SAkinobu Mita MODULE_LICENSE("GPL"); 258