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