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 v2.6.33-rc3 253 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#include <linux/init.h> 23#include <linux/module.h> 24#include <linux/moduleparam.h> 25#include <linux/err.h> 26#include <linux/mtd/mtd.h> 27#include <linux/sched.h> 28 29#define PRINT_PREF KERN_INFO "mtd_readtest: " 30 31static int dev; 32module_param(dev, int, S_IRUGO); 33MODULE_PARM_DESC(dev, "MTD device number to use"); 34 35static struct mtd_info *mtd; 36static unsigned char *iobuf; 37static unsigned char *iobuf1; 38static unsigned char *bbt; 39 40static int pgsize; 41static int ebcnt; 42static int pgcnt; 43 44static int read_eraseblock_by_page(int ebnum) 45{ 46 size_t read = 0; 47 int i, ret, err = 0; 48 loff_t addr = ebnum * mtd->erasesize; 49 void *buf = iobuf; 50 void *oobbuf = iobuf1; 51 52 for (i = 0; i < pgcnt; i++) { 53 memset(buf, 0 , pgcnt); 54 ret = mtd->read(mtd, addr, pgsize, &read, buf); 55 if (ret == -EUCLEAN) 56 ret = 0; 57 if (ret || read != pgsize) { 58 printk(PRINT_PREF "error: read failed at %#llx\n", 59 (long long)addr); 60 if (!err) 61 err = ret; 62 if (!err) 63 err = -EINVAL; 64 } 65 if (mtd->oobsize) { 66 struct mtd_oob_ops ops; 67 68 ops.mode = MTD_OOB_PLACE; 69 ops.len = 0; 70 ops.retlen = 0; 71 ops.ooblen = mtd->oobsize; 72 ops.oobretlen = 0; 73 ops.ooboffs = 0; 74 ops.datbuf = NULL; 75 ops.oobbuf = oobbuf; 76 ret = mtd->read_oob(mtd, addr, &ops); 77 if (ret || ops.oobretlen != mtd->oobsize) { 78 printk(PRINT_PREF "error: read oob failed at " 79 "%#llx\n", (long long)addr); 80 if (!err) 81 err = ret; 82 if (!err) 83 err = -EINVAL; 84 } 85 oobbuf += mtd->oobsize; 86 } 87 addr += pgsize; 88 buf += pgsize; 89 } 90 91 return err; 92} 93 94static void dump_eraseblock(int ebnum) 95{ 96 int i, j, n; 97 char line[128]; 98 int pg, oob; 99 100 printk(PRINT_PREF "dumping eraseblock %d\n", ebnum); 101 n = mtd->erasesize; 102 for (i = 0; i < n;) { 103 char *p = line; 104 105 p += sprintf(p, "%05x: ", i); 106 for (j = 0; j < 32 && i < n; j++, i++) 107 p += sprintf(p, "%02x", (unsigned int)iobuf[i]); 108 printk(KERN_CRIT "%s\n", line); 109 cond_resched(); 110 } 111 if (!mtd->oobsize) 112 return; 113 printk(PRINT_PREF "dumping oob from eraseblock %d\n", ebnum); 114 n = mtd->oobsize; 115 for (pg = 0, i = 0; pg < pgcnt; pg++) 116 for (oob = 0; oob < n;) { 117 char *p = line; 118 119 p += sprintf(p, "%05x: ", i); 120 for (j = 0; j < 32 && oob < n; j++, oob++, i++) 121 p += sprintf(p, "%02x", 122 (unsigned int)iobuf1[i]); 123 printk(KERN_CRIT "%s\n", line); 124 cond_resched(); 125 } 126} 127 128static int is_block_bad(int ebnum) 129{ 130 loff_t addr = ebnum * mtd->erasesize; 131 int ret; 132 133 ret = mtd->block_isbad(mtd, addr); 134 if (ret) 135 printk(PRINT_PREF "block %d is bad\n", ebnum); 136 return ret; 137} 138 139static int scan_for_bad_eraseblocks(void) 140{ 141 int i, bad = 0; 142 143 bbt = kmalloc(ebcnt, GFP_KERNEL); 144 if (!bbt) { 145 printk(PRINT_PREF "error: cannot allocate memory\n"); 146 return -ENOMEM; 147 } 148 memset(bbt, 0 , ebcnt); 149 150 printk(PRINT_PREF "scanning for bad eraseblocks\n"); 151 for (i = 0; i < ebcnt; ++i) { 152 bbt[i] = is_block_bad(i) ? 1 : 0; 153 if (bbt[i]) 154 bad += 1; 155 cond_resched(); 156 } 157 printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad); 158 return 0; 159} 160 161static int __init mtd_readtest_init(void) 162{ 163 uint64_t tmp; 164 int err, i; 165 166 printk(KERN_INFO "\n"); 167 printk(KERN_INFO "=================================================\n"); 168 printk(PRINT_PREF "MTD device: %d\n", dev); 169 170 mtd = get_mtd_device(NULL, dev); 171 if (IS_ERR(mtd)) { 172 err = PTR_ERR(mtd); 173 printk(PRINT_PREF "error: Cannot get MTD device\n"); 174 return err; 175 } 176 177 if (mtd->writesize == 1) { 178 printk(PRINT_PREF "not NAND flash, assume page size is 512 " 179 "bytes.\n"); 180 pgsize = 512; 181 } else 182 pgsize = mtd->writesize; 183 184 tmp = mtd->size; 185 do_div(tmp, mtd->erasesize); 186 ebcnt = tmp; 187 pgcnt = mtd->erasesize / mtd->writesize; 188 189 printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, " 190 "page size %u, count of eraseblocks %u, pages per " 191 "eraseblock %u, OOB size %u\n", 192 (unsigned long long)mtd->size, mtd->erasesize, 193 pgsize, ebcnt, pgcnt, mtd->oobsize); 194 195 err = -ENOMEM; 196 iobuf = kmalloc(mtd->erasesize, GFP_KERNEL); 197 if (!iobuf) { 198 printk(PRINT_PREF "error: cannot allocate memory\n"); 199 goto out; 200 } 201 iobuf1 = kmalloc(mtd->erasesize, GFP_KERNEL); 202 if (!iobuf1) { 203 printk(PRINT_PREF "error: cannot allocate memory\n"); 204 goto out; 205 } 206 207 err = scan_for_bad_eraseblocks(); 208 if (err) 209 goto out; 210 211 /* Read all eraseblocks 1 page at a time */ 212 printk(PRINT_PREF "testing page read\n"); 213 for (i = 0; i < ebcnt; ++i) { 214 int ret; 215 216 if (bbt[i]) 217 continue; 218 ret = read_eraseblock_by_page(i); 219 if (ret) { 220 dump_eraseblock(i); 221 if (!err) 222 err = ret; 223 } 224 cond_resched(); 225 } 226 227 if (err) 228 printk(PRINT_PREF "finished with errors\n"); 229 else 230 printk(PRINT_PREF "finished\n"); 231 232out: 233 234 kfree(iobuf); 235 kfree(iobuf1); 236 kfree(bbt); 237 put_mtd_device(mtd); 238 if (err) 239 printk(PRINT_PREF "error %d occurred\n", err); 240 printk(KERN_INFO "=================================================\n"); 241 return err; 242} 243module_init(mtd_readtest_init); 244 245static void __exit mtd_readtest_exit(void) 246{ 247 return; 248} 249module_exit(mtd_readtest_exit); 250 251MODULE_DESCRIPTION("Read test module"); 252MODULE_AUTHOR("Adrian Hunter"); 253MODULE_LICENSE("GPL");