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