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 * Test OOB read and write on MTD device. 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 <asm/div64.h> 25a995c792SAkinobu Mita #include <linux/init.h> 26a995c792SAkinobu Mita #include <linux/module.h> 27a995c792SAkinobu Mita #include <linux/moduleparam.h> 28a995c792SAkinobu Mita #include <linux/err.h> 29a995c792SAkinobu Mita #include <linux/mtd/mtd.h> 30a995c792SAkinobu Mita #include <linux/slab.h> 31a995c792SAkinobu Mita #include <linux/sched.h> 32a995c792SAkinobu Mita #include <linux/random.h> 33a995c792SAkinobu Mita 344bf527aaSAkinobu Mita #include "mtd_test.h" 354bf527aaSAkinobu Mita 36a995c792SAkinobu Mita static int dev = -EINVAL; 37a995c792SAkinobu Mita module_param(dev, int, S_IRUGO); 38a995c792SAkinobu Mita MODULE_PARM_DESC(dev, "MTD device number to use"); 39a995c792SAkinobu Mita 40a995c792SAkinobu Mita static struct mtd_info *mtd; 41a995c792SAkinobu Mita static unsigned char *readbuf; 42a995c792SAkinobu Mita static unsigned char *writebuf; 43a995c792SAkinobu Mita static unsigned char *bbt; 44a995c792SAkinobu Mita 45a995c792SAkinobu Mita static int ebcnt; 46a995c792SAkinobu Mita static int pgcnt; 47a995c792SAkinobu Mita static int errcnt; 48a995c792SAkinobu Mita static int use_offset; 49a995c792SAkinobu Mita static int use_len; 50a995c792SAkinobu Mita static int use_len_max; 51a995c792SAkinobu Mita static int vary_offset; 52a995c792SAkinobu Mita static struct rnd_state rnd_state; 53a995c792SAkinobu Mita 54a995c792SAkinobu Mita static void do_vary_offset(void) 55a995c792SAkinobu Mita { 56a995c792SAkinobu Mita use_len -= 1; 57a995c792SAkinobu Mita if (use_len < 1) { 58a995c792SAkinobu Mita use_offset += 1; 59a995c792SAkinobu Mita if (use_offset >= use_len_max) 60a995c792SAkinobu Mita use_offset = 0; 61a995c792SAkinobu Mita use_len = use_len_max - use_offset; 62a995c792SAkinobu Mita } 63a995c792SAkinobu Mita } 64a995c792SAkinobu Mita 65a995c792SAkinobu Mita static int write_eraseblock(int ebnum) 66a995c792SAkinobu Mita { 67a995c792SAkinobu Mita int i; 68a995c792SAkinobu Mita struct mtd_oob_ops ops; 69a995c792SAkinobu Mita int err = 0; 70a995c792SAkinobu Mita loff_t addr = ebnum * mtd->erasesize; 71a995c792SAkinobu Mita 72be54f8f1SAkinobu Mita prandom_bytes_state(&rnd_state, writebuf, use_len_max * pgcnt); 73a995c792SAkinobu Mita for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) { 74a995c792SAkinobu Mita ops.mode = MTD_OPS_AUTO_OOB; 75a995c792SAkinobu Mita ops.len = 0; 76a995c792SAkinobu Mita ops.retlen = 0; 77a995c792SAkinobu Mita ops.ooblen = use_len; 78a995c792SAkinobu Mita ops.oobretlen = 0; 79a995c792SAkinobu Mita ops.ooboffs = use_offset; 80a995c792SAkinobu Mita ops.datbuf = NULL; 81be54f8f1SAkinobu Mita ops.oobbuf = writebuf + (use_len_max * i) + use_offset; 82a995c792SAkinobu Mita err = mtd_write_oob(mtd, addr, &ops); 83a995c792SAkinobu Mita if (err || ops.oobretlen != use_len) { 84a995c792SAkinobu Mita pr_err("error: writeoob failed at %#llx\n", 85a995c792SAkinobu Mita (long long)addr); 86a995c792SAkinobu Mita pr_err("error: use_len %d, use_offset %d\n", 87a995c792SAkinobu Mita use_len, use_offset); 88a995c792SAkinobu Mita errcnt += 1; 89a995c792SAkinobu Mita return err ? err : -1; 90a995c792SAkinobu Mita } 91a995c792SAkinobu Mita if (vary_offset) 92a995c792SAkinobu Mita do_vary_offset(); 93a995c792SAkinobu Mita } 94a995c792SAkinobu Mita 95a995c792SAkinobu Mita return err; 96a995c792SAkinobu Mita } 97a995c792SAkinobu Mita 98a995c792SAkinobu Mita static int write_whole_device(void) 99a995c792SAkinobu Mita { 100a995c792SAkinobu Mita int err; 101a995c792SAkinobu Mita unsigned int i; 102a995c792SAkinobu Mita 103a995c792SAkinobu Mita pr_info("writing OOBs of whole device\n"); 104a995c792SAkinobu Mita for (i = 0; i < ebcnt; ++i) { 105a995c792SAkinobu Mita if (bbt[i]) 106a995c792SAkinobu Mita continue; 107a995c792SAkinobu Mita err = write_eraseblock(i); 108a995c792SAkinobu Mita if (err) 109a995c792SAkinobu Mita return err; 110a995c792SAkinobu Mita if (i % 256 == 0) 111a995c792SAkinobu Mita pr_info("written up to eraseblock %u\n", i); 112a995c792SAkinobu Mita cond_resched(); 113a995c792SAkinobu Mita } 114a995c792SAkinobu Mita pr_info("written %u eraseblocks\n", i); 115a995c792SAkinobu Mita return 0; 116a995c792SAkinobu Mita } 117a995c792SAkinobu Mita 118a995c792SAkinobu Mita static int verify_eraseblock(int ebnum) 119a995c792SAkinobu Mita { 120a995c792SAkinobu Mita int i; 121a995c792SAkinobu Mita struct mtd_oob_ops ops; 122a995c792SAkinobu Mita int err = 0; 123a995c792SAkinobu Mita loff_t addr = ebnum * mtd->erasesize; 124a995c792SAkinobu Mita 125be54f8f1SAkinobu Mita prandom_bytes_state(&rnd_state, writebuf, use_len_max * pgcnt); 126a995c792SAkinobu Mita for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) { 127a995c792SAkinobu Mita ops.mode = MTD_OPS_AUTO_OOB; 128a995c792SAkinobu Mita ops.len = 0; 129a995c792SAkinobu Mita ops.retlen = 0; 130a995c792SAkinobu Mita ops.ooblen = use_len; 131a995c792SAkinobu Mita ops.oobretlen = 0; 132a995c792SAkinobu Mita ops.ooboffs = use_offset; 133a995c792SAkinobu Mita ops.datbuf = NULL; 134a995c792SAkinobu Mita ops.oobbuf = readbuf; 135a995c792SAkinobu Mita err = mtd_read_oob(mtd, addr, &ops); 136a995c792SAkinobu Mita if (err || ops.oobretlen != use_len) { 137a995c792SAkinobu Mita pr_err("error: readoob failed at %#llx\n", 138a995c792SAkinobu Mita (long long)addr); 139a995c792SAkinobu Mita errcnt += 1; 140a995c792SAkinobu Mita return err ? err : -1; 141a995c792SAkinobu Mita } 142be54f8f1SAkinobu Mita if (memcmp(readbuf, writebuf + (use_len_max * i) + use_offset, 143be54f8f1SAkinobu Mita use_len)) { 144a995c792SAkinobu Mita pr_err("error: verify failed at %#llx\n", 145a995c792SAkinobu Mita (long long)addr); 146a995c792SAkinobu Mita errcnt += 1; 147a995c792SAkinobu Mita if (errcnt > 1000) { 148a995c792SAkinobu Mita pr_err("error: too many errors\n"); 149a995c792SAkinobu Mita return -1; 150a995c792SAkinobu Mita } 151a995c792SAkinobu Mita } 152a995c792SAkinobu Mita if (use_offset != 0 || use_len < mtd->ecclayout->oobavail) { 153a995c792SAkinobu Mita int k; 154a995c792SAkinobu Mita 155a995c792SAkinobu Mita ops.mode = MTD_OPS_AUTO_OOB; 156a995c792SAkinobu Mita ops.len = 0; 157a995c792SAkinobu Mita ops.retlen = 0; 158a995c792SAkinobu Mita ops.ooblen = mtd->ecclayout->oobavail; 159a995c792SAkinobu Mita ops.oobretlen = 0; 160a995c792SAkinobu Mita ops.ooboffs = 0; 161a995c792SAkinobu Mita ops.datbuf = NULL; 162a995c792SAkinobu Mita ops.oobbuf = readbuf; 163a995c792SAkinobu Mita err = mtd_read_oob(mtd, addr, &ops); 164a995c792SAkinobu Mita if (err || ops.oobretlen != mtd->ecclayout->oobavail) { 165a995c792SAkinobu Mita pr_err("error: readoob failed at %#llx\n", 166a995c792SAkinobu Mita (long long)addr); 167a995c792SAkinobu Mita errcnt += 1; 168a995c792SAkinobu Mita return err ? err : -1; 169a995c792SAkinobu Mita } 170be54f8f1SAkinobu Mita if (memcmp(readbuf + use_offset, 171be54f8f1SAkinobu Mita writebuf + (use_len_max * i) + use_offset, 172be54f8f1SAkinobu Mita use_len)) { 173a995c792SAkinobu Mita pr_err("error: verify failed at %#llx\n", 174a995c792SAkinobu Mita (long long)addr); 175a995c792SAkinobu Mita errcnt += 1; 176a995c792SAkinobu Mita if (errcnt > 1000) { 177a995c792SAkinobu Mita pr_err("error: too many errors\n"); 178a995c792SAkinobu Mita return -1; 179a995c792SAkinobu Mita } 180a995c792SAkinobu Mita } 181a995c792SAkinobu Mita for (k = 0; k < use_offset; ++k) 182a995c792SAkinobu Mita if (readbuf[k] != 0xff) { 183a995c792SAkinobu Mita pr_err("error: verify 0xff " 184a995c792SAkinobu Mita "failed at %#llx\n", 185a995c792SAkinobu Mita (long long)addr); 186a995c792SAkinobu Mita errcnt += 1; 187a995c792SAkinobu Mita if (errcnt > 1000) { 188a995c792SAkinobu Mita pr_err("error: too " 189a995c792SAkinobu Mita "many errors\n"); 190a995c792SAkinobu Mita return -1; 191a995c792SAkinobu Mita } 192a995c792SAkinobu Mita } 193a995c792SAkinobu Mita for (k = use_offset + use_len; 194a995c792SAkinobu Mita k < mtd->ecclayout->oobavail; ++k) 195a995c792SAkinobu Mita if (readbuf[k] != 0xff) { 196a995c792SAkinobu Mita pr_err("error: verify 0xff " 197a995c792SAkinobu Mita "failed at %#llx\n", 198a995c792SAkinobu Mita (long long)addr); 199a995c792SAkinobu Mita errcnt += 1; 200a995c792SAkinobu Mita if (errcnt > 1000) { 201a995c792SAkinobu Mita pr_err("error: too " 202a995c792SAkinobu Mita "many errors\n"); 203a995c792SAkinobu Mita return -1; 204a995c792SAkinobu Mita } 205a995c792SAkinobu Mita } 206a995c792SAkinobu Mita } 207a995c792SAkinobu Mita if (vary_offset) 208a995c792SAkinobu Mita do_vary_offset(); 209a995c792SAkinobu Mita } 210a995c792SAkinobu Mita return err; 211a995c792SAkinobu Mita } 212a995c792SAkinobu Mita 213a995c792SAkinobu Mita static int verify_eraseblock_in_one_go(int ebnum) 214a995c792SAkinobu Mita { 215a995c792SAkinobu Mita struct mtd_oob_ops ops; 216a995c792SAkinobu Mita int err = 0; 217a995c792SAkinobu Mita loff_t addr = ebnum * mtd->erasesize; 218a995c792SAkinobu Mita size_t len = mtd->ecclayout->oobavail * pgcnt; 219a995c792SAkinobu Mita 220a995c792SAkinobu Mita prandom_bytes_state(&rnd_state, writebuf, len); 221a995c792SAkinobu Mita ops.mode = MTD_OPS_AUTO_OOB; 222a995c792SAkinobu Mita ops.len = 0; 223a995c792SAkinobu Mita ops.retlen = 0; 224a995c792SAkinobu Mita ops.ooblen = len; 225a995c792SAkinobu Mita ops.oobretlen = 0; 226a995c792SAkinobu Mita ops.ooboffs = 0; 227a995c792SAkinobu Mita ops.datbuf = NULL; 228a995c792SAkinobu Mita ops.oobbuf = readbuf; 229a995c792SAkinobu Mita err = mtd_read_oob(mtd, addr, &ops); 230a995c792SAkinobu Mita if (err || ops.oobretlen != len) { 231a995c792SAkinobu Mita pr_err("error: readoob failed at %#llx\n", 232a995c792SAkinobu Mita (long long)addr); 233a995c792SAkinobu Mita errcnt += 1; 234a995c792SAkinobu Mita return err ? err : -1; 235a995c792SAkinobu Mita } 236a995c792SAkinobu Mita if (memcmp(readbuf, writebuf, len)) { 237a995c792SAkinobu Mita pr_err("error: verify failed at %#llx\n", 238a995c792SAkinobu Mita (long long)addr); 239a995c792SAkinobu Mita errcnt += 1; 240a995c792SAkinobu Mita if (errcnt > 1000) { 241a995c792SAkinobu Mita pr_err("error: too many errors\n"); 242a995c792SAkinobu Mita return -1; 243a995c792SAkinobu Mita } 244a995c792SAkinobu Mita } 245a995c792SAkinobu Mita 246a995c792SAkinobu Mita return err; 247a995c792SAkinobu Mita } 248a995c792SAkinobu Mita 249a995c792SAkinobu Mita static int verify_all_eraseblocks(void) 250a995c792SAkinobu Mita { 251a995c792SAkinobu Mita int err; 252a995c792SAkinobu Mita unsigned int i; 253a995c792SAkinobu Mita 254a995c792SAkinobu Mita pr_info("verifying all eraseblocks\n"); 255a995c792SAkinobu Mita for (i = 0; i < ebcnt; ++i) { 256a995c792SAkinobu Mita if (bbt[i]) 257a995c792SAkinobu Mita continue; 258a995c792SAkinobu Mita err = verify_eraseblock(i); 259a995c792SAkinobu Mita if (err) 260a995c792SAkinobu Mita return err; 261a995c792SAkinobu Mita if (i % 256 == 0) 262a995c792SAkinobu Mita pr_info("verified up to eraseblock %u\n", i); 263a995c792SAkinobu Mita cond_resched(); 264a995c792SAkinobu Mita } 265a995c792SAkinobu Mita pr_info("verified %u eraseblocks\n", i); 266a995c792SAkinobu Mita return 0; 267a995c792SAkinobu Mita } 268a995c792SAkinobu Mita 269a995c792SAkinobu Mita static int __init mtd_oobtest_init(void) 270a995c792SAkinobu Mita { 271a995c792SAkinobu Mita int err = 0; 272a995c792SAkinobu Mita unsigned int i; 273a995c792SAkinobu Mita uint64_t tmp; 274a995c792SAkinobu Mita struct mtd_oob_ops ops; 275a995c792SAkinobu Mita loff_t addr = 0, addr0; 276a995c792SAkinobu Mita 277a995c792SAkinobu Mita printk(KERN_INFO "\n"); 278a995c792SAkinobu Mita printk(KERN_INFO "=================================================\n"); 279a995c792SAkinobu Mita 280a995c792SAkinobu Mita if (dev < 0) { 281a995c792SAkinobu Mita pr_info("Please specify a valid mtd-device via module parameter\n"); 282a995c792SAkinobu Mita pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n"); 283a995c792SAkinobu Mita return -EINVAL; 284a995c792SAkinobu Mita } 285a995c792SAkinobu Mita 286a995c792SAkinobu Mita pr_info("MTD device: %d\n", dev); 287a995c792SAkinobu Mita 288a995c792SAkinobu Mita mtd = get_mtd_device(NULL, dev); 289a995c792SAkinobu Mita if (IS_ERR(mtd)) { 290a995c792SAkinobu Mita err = PTR_ERR(mtd); 291a995c792SAkinobu Mita pr_err("error: cannot get MTD device\n"); 292a995c792SAkinobu Mita return err; 293a995c792SAkinobu Mita } 294a995c792SAkinobu Mita 295818b9739SHuang Shijie if (!mtd_type_is_nand(mtd)) { 296a995c792SAkinobu Mita pr_info("this test requires NAND flash\n"); 297a995c792SAkinobu Mita goto out; 298a995c792SAkinobu Mita } 299a995c792SAkinobu Mita 300a995c792SAkinobu Mita tmp = mtd->size; 301a995c792SAkinobu Mita do_div(tmp, mtd->erasesize); 302a995c792SAkinobu Mita ebcnt = tmp; 303a995c792SAkinobu Mita pgcnt = mtd->erasesize / mtd->writesize; 304a995c792SAkinobu Mita 305a995c792SAkinobu Mita pr_info("MTD device size %llu, eraseblock size %u, " 306a995c792SAkinobu Mita "page size %u, count of eraseblocks %u, pages per " 307a995c792SAkinobu Mita "eraseblock %u, OOB size %u\n", 308a995c792SAkinobu Mita (unsigned long long)mtd->size, mtd->erasesize, 309a995c792SAkinobu Mita mtd->writesize, ebcnt, pgcnt, mtd->oobsize); 310a995c792SAkinobu Mita 311a995c792SAkinobu Mita err = -ENOMEM; 312a995c792SAkinobu Mita readbuf = kmalloc(mtd->erasesize, GFP_KERNEL); 313a995c792SAkinobu Mita if (!readbuf) 314a995c792SAkinobu Mita goto out; 315a995c792SAkinobu Mita writebuf = kmalloc(mtd->erasesize, GFP_KERNEL); 316a995c792SAkinobu Mita if (!writebuf) 317a995c792SAkinobu Mita goto out; 3184bf527aaSAkinobu Mita bbt = kzalloc(ebcnt, GFP_KERNEL); 3194bf527aaSAkinobu Mita if (!bbt) 3204bf527aaSAkinobu Mita goto out; 321a995c792SAkinobu Mita 3224bf527aaSAkinobu Mita err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt); 323a995c792SAkinobu Mita if (err) 324a995c792SAkinobu Mita goto out; 325a995c792SAkinobu Mita 326a995c792SAkinobu Mita use_offset = 0; 327a995c792SAkinobu Mita use_len = mtd->ecclayout->oobavail; 328a995c792SAkinobu Mita use_len_max = mtd->ecclayout->oobavail; 329a995c792SAkinobu Mita vary_offset = 0; 330a995c792SAkinobu Mita 331a995c792SAkinobu Mita /* First test: write all OOB, read it back and verify */ 332a995c792SAkinobu Mita pr_info("test 1 of 5\n"); 333a995c792SAkinobu Mita 3344bf527aaSAkinobu Mita err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); 335a995c792SAkinobu Mita if (err) 336a995c792SAkinobu Mita goto out; 337a995c792SAkinobu Mita 338a995c792SAkinobu Mita prandom_seed_state(&rnd_state, 1); 339a995c792SAkinobu Mita err = write_whole_device(); 340a995c792SAkinobu Mita if (err) 341a995c792SAkinobu Mita goto out; 342a995c792SAkinobu Mita 343a995c792SAkinobu Mita prandom_seed_state(&rnd_state, 1); 344a995c792SAkinobu Mita err = verify_all_eraseblocks(); 345a995c792SAkinobu Mita if (err) 346a995c792SAkinobu Mita goto out; 347a995c792SAkinobu Mita 348a995c792SAkinobu Mita /* 349a995c792SAkinobu Mita * Second test: write all OOB, a block at a time, read it back and 350a995c792SAkinobu Mita * verify. 351a995c792SAkinobu Mita */ 352a995c792SAkinobu Mita pr_info("test 2 of 5\n"); 353a995c792SAkinobu Mita 3544bf527aaSAkinobu Mita err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); 355a995c792SAkinobu Mita if (err) 356a995c792SAkinobu Mita goto out; 357a995c792SAkinobu Mita 358a995c792SAkinobu Mita prandom_seed_state(&rnd_state, 3); 359a995c792SAkinobu Mita err = write_whole_device(); 360a995c792SAkinobu Mita if (err) 361a995c792SAkinobu Mita goto out; 362a995c792SAkinobu Mita 363a995c792SAkinobu Mita /* Check all eraseblocks */ 364a995c792SAkinobu Mita prandom_seed_state(&rnd_state, 3); 365a995c792SAkinobu Mita pr_info("verifying all eraseblocks\n"); 366a995c792SAkinobu Mita for (i = 0; i < ebcnt; ++i) { 367a995c792SAkinobu Mita if (bbt[i]) 368a995c792SAkinobu Mita continue; 369a995c792SAkinobu Mita err = verify_eraseblock_in_one_go(i); 370a995c792SAkinobu Mita if (err) 371a995c792SAkinobu Mita goto out; 372a995c792SAkinobu Mita if (i % 256 == 0) 373a995c792SAkinobu Mita pr_info("verified up to eraseblock %u\n", i); 374a995c792SAkinobu Mita cond_resched(); 375a995c792SAkinobu Mita } 376a995c792SAkinobu Mita pr_info("verified %u eraseblocks\n", i); 377a995c792SAkinobu Mita 378a995c792SAkinobu Mita /* 379a995c792SAkinobu Mita * Third test: write OOB at varying offsets and lengths, read it back 380a995c792SAkinobu Mita * and verify. 381a995c792SAkinobu Mita */ 382a995c792SAkinobu Mita pr_info("test 3 of 5\n"); 383a995c792SAkinobu Mita 3844bf527aaSAkinobu Mita err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); 385a995c792SAkinobu Mita if (err) 386a995c792SAkinobu Mita goto out; 387a995c792SAkinobu Mita 388a995c792SAkinobu Mita /* Write all eraseblocks */ 389a995c792SAkinobu Mita use_offset = 0; 390a995c792SAkinobu Mita use_len = mtd->ecclayout->oobavail; 391a995c792SAkinobu Mita use_len_max = mtd->ecclayout->oobavail; 392a995c792SAkinobu Mita vary_offset = 1; 393a995c792SAkinobu Mita prandom_seed_state(&rnd_state, 5); 394a995c792SAkinobu Mita 395a995c792SAkinobu Mita err = write_whole_device(); 396a995c792SAkinobu Mita if (err) 397a995c792SAkinobu Mita goto out; 398a995c792SAkinobu Mita 399a995c792SAkinobu Mita /* Check all eraseblocks */ 400a995c792SAkinobu Mita use_offset = 0; 401a995c792SAkinobu Mita use_len = mtd->ecclayout->oobavail; 402a995c792SAkinobu Mita use_len_max = mtd->ecclayout->oobavail; 403a995c792SAkinobu Mita vary_offset = 1; 404a995c792SAkinobu Mita prandom_seed_state(&rnd_state, 5); 405a995c792SAkinobu Mita err = verify_all_eraseblocks(); 406a995c792SAkinobu Mita if (err) 407a995c792SAkinobu Mita goto out; 408a995c792SAkinobu Mita 409a995c792SAkinobu Mita use_offset = 0; 410a995c792SAkinobu Mita use_len = mtd->ecclayout->oobavail; 411a995c792SAkinobu Mita use_len_max = mtd->ecclayout->oobavail; 412a995c792SAkinobu Mita vary_offset = 0; 413a995c792SAkinobu Mita 414a995c792SAkinobu Mita /* Fourth test: try to write off end of device */ 415a995c792SAkinobu Mita pr_info("test 4 of 5\n"); 416a995c792SAkinobu Mita 4174bf527aaSAkinobu Mita err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); 418a995c792SAkinobu Mita if (err) 419a995c792SAkinobu Mita goto out; 420a995c792SAkinobu Mita 421a995c792SAkinobu Mita addr0 = 0; 422a995c792SAkinobu Mita for (i = 0; i < ebcnt && bbt[i]; ++i) 423a995c792SAkinobu Mita addr0 += mtd->erasesize; 424a995c792SAkinobu Mita 425a995c792SAkinobu Mita /* Attempt to write off end of OOB */ 426a995c792SAkinobu Mita ops.mode = MTD_OPS_AUTO_OOB; 427a995c792SAkinobu Mita ops.len = 0; 428a995c792SAkinobu Mita ops.retlen = 0; 429a995c792SAkinobu Mita ops.ooblen = 1; 430a995c792SAkinobu Mita ops.oobretlen = 0; 431a995c792SAkinobu Mita ops.ooboffs = mtd->ecclayout->oobavail; 432a995c792SAkinobu Mita ops.datbuf = NULL; 433a995c792SAkinobu Mita ops.oobbuf = writebuf; 434a995c792SAkinobu Mita pr_info("attempting to start write past end of OOB\n"); 435a995c792SAkinobu Mita pr_info("an error is expected...\n"); 436a995c792SAkinobu Mita err = mtd_write_oob(mtd, addr0, &ops); 437a995c792SAkinobu Mita if (err) { 438a995c792SAkinobu Mita pr_info("error occurred as expected\n"); 439a995c792SAkinobu Mita err = 0; 440a995c792SAkinobu Mita } else { 441a995c792SAkinobu Mita pr_err("error: can write past end of OOB\n"); 442a995c792SAkinobu Mita errcnt += 1; 443a995c792SAkinobu Mita } 444a995c792SAkinobu Mita 445a995c792SAkinobu Mita /* Attempt to read off end of OOB */ 446a995c792SAkinobu Mita ops.mode = MTD_OPS_AUTO_OOB; 447a995c792SAkinobu Mita ops.len = 0; 448a995c792SAkinobu Mita ops.retlen = 0; 449a995c792SAkinobu Mita ops.ooblen = 1; 450a995c792SAkinobu Mita ops.oobretlen = 0; 451a995c792SAkinobu Mita ops.ooboffs = mtd->ecclayout->oobavail; 452a995c792SAkinobu Mita ops.datbuf = NULL; 453a995c792SAkinobu Mita ops.oobbuf = readbuf; 454a995c792SAkinobu Mita pr_info("attempting to start read past end of OOB\n"); 455a995c792SAkinobu Mita pr_info("an error is expected...\n"); 456a995c792SAkinobu Mita err = mtd_read_oob(mtd, addr0, &ops); 457a995c792SAkinobu Mita if (err) { 458a995c792SAkinobu Mita pr_info("error occurred as expected\n"); 459a995c792SAkinobu Mita err = 0; 460a995c792SAkinobu Mita } else { 461a995c792SAkinobu Mita pr_err("error: can read past end of OOB\n"); 462a995c792SAkinobu Mita errcnt += 1; 463a995c792SAkinobu Mita } 464a995c792SAkinobu Mita 465a995c792SAkinobu Mita if (bbt[ebcnt - 1]) 466a995c792SAkinobu Mita pr_info("skipping end of device tests because last " 467a995c792SAkinobu Mita "block is bad\n"); 468a995c792SAkinobu Mita else { 469a995c792SAkinobu Mita /* Attempt to write off end of device */ 470a995c792SAkinobu Mita ops.mode = MTD_OPS_AUTO_OOB; 471a995c792SAkinobu Mita ops.len = 0; 472a995c792SAkinobu Mita ops.retlen = 0; 473a995c792SAkinobu Mita ops.ooblen = mtd->ecclayout->oobavail + 1; 474a995c792SAkinobu Mita ops.oobretlen = 0; 475a995c792SAkinobu Mita ops.ooboffs = 0; 476a995c792SAkinobu Mita ops.datbuf = NULL; 477a995c792SAkinobu Mita ops.oobbuf = writebuf; 478a995c792SAkinobu Mita pr_info("attempting to write past end of device\n"); 479a995c792SAkinobu Mita pr_info("an error is expected...\n"); 480a995c792SAkinobu Mita err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops); 481a995c792SAkinobu Mita if (err) { 482a995c792SAkinobu Mita pr_info("error occurred as expected\n"); 483a995c792SAkinobu Mita err = 0; 484a995c792SAkinobu Mita } else { 485a995c792SAkinobu Mita pr_err("error: wrote past end of device\n"); 486a995c792SAkinobu Mita errcnt += 1; 487a995c792SAkinobu Mita } 488a995c792SAkinobu Mita 489a995c792SAkinobu Mita /* Attempt to read off end of device */ 490a995c792SAkinobu Mita ops.mode = MTD_OPS_AUTO_OOB; 491a995c792SAkinobu Mita ops.len = 0; 492a995c792SAkinobu Mita ops.retlen = 0; 493a995c792SAkinobu Mita ops.ooblen = mtd->ecclayout->oobavail + 1; 494a995c792SAkinobu Mita ops.oobretlen = 0; 495a995c792SAkinobu Mita ops.ooboffs = 0; 496a995c792SAkinobu Mita ops.datbuf = NULL; 497a995c792SAkinobu Mita ops.oobbuf = readbuf; 498a995c792SAkinobu Mita pr_info("attempting to read past end of device\n"); 499a995c792SAkinobu Mita pr_info("an error is expected...\n"); 500a995c792SAkinobu Mita err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops); 501a995c792SAkinobu Mita if (err) { 502a995c792SAkinobu Mita pr_info("error occurred as expected\n"); 503a995c792SAkinobu Mita err = 0; 504a995c792SAkinobu Mita } else { 505a995c792SAkinobu Mita pr_err("error: read past end of device\n"); 506a995c792SAkinobu Mita errcnt += 1; 507a995c792SAkinobu Mita } 508a995c792SAkinobu Mita 5094bf527aaSAkinobu Mita err = mtdtest_erase_eraseblock(mtd, ebcnt - 1); 510a995c792SAkinobu Mita if (err) 511a995c792SAkinobu Mita goto out; 512a995c792SAkinobu Mita 513a995c792SAkinobu Mita /* Attempt to write off end of device */ 514a995c792SAkinobu Mita ops.mode = MTD_OPS_AUTO_OOB; 515a995c792SAkinobu Mita ops.len = 0; 516a995c792SAkinobu Mita ops.retlen = 0; 517a995c792SAkinobu Mita ops.ooblen = mtd->ecclayout->oobavail; 518a995c792SAkinobu Mita ops.oobretlen = 0; 519a995c792SAkinobu Mita ops.ooboffs = 1; 520a995c792SAkinobu Mita ops.datbuf = NULL; 521a995c792SAkinobu Mita ops.oobbuf = writebuf; 522a995c792SAkinobu Mita pr_info("attempting to write past end of device\n"); 523a995c792SAkinobu Mita pr_info("an error is expected...\n"); 524a995c792SAkinobu Mita err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops); 525a995c792SAkinobu Mita if (err) { 526a995c792SAkinobu Mita pr_info("error occurred as expected\n"); 527a995c792SAkinobu Mita err = 0; 528a995c792SAkinobu Mita } else { 529a995c792SAkinobu Mita pr_err("error: wrote past end of device\n"); 530a995c792SAkinobu Mita errcnt += 1; 531a995c792SAkinobu Mita } 532a995c792SAkinobu Mita 533a995c792SAkinobu Mita /* Attempt to read off end of device */ 534a995c792SAkinobu Mita ops.mode = MTD_OPS_AUTO_OOB; 535a995c792SAkinobu Mita ops.len = 0; 536a995c792SAkinobu Mita ops.retlen = 0; 537a995c792SAkinobu Mita ops.ooblen = mtd->ecclayout->oobavail; 538a995c792SAkinobu Mita ops.oobretlen = 0; 539a995c792SAkinobu Mita ops.ooboffs = 1; 540a995c792SAkinobu Mita ops.datbuf = NULL; 541a995c792SAkinobu Mita ops.oobbuf = readbuf; 542a995c792SAkinobu Mita pr_info("attempting to read past end of device\n"); 543a995c792SAkinobu Mita pr_info("an error is expected...\n"); 544a995c792SAkinobu Mita err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops); 545a995c792SAkinobu Mita if (err) { 546a995c792SAkinobu Mita pr_info("error occurred as expected\n"); 547a995c792SAkinobu Mita err = 0; 548a995c792SAkinobu Mita } else { 549a995c792SAkinobu Mita pr_err("error: read past end of device\n"); 550a995c792SAkinobu Mita errcnt += 1; 551a995c792SAkinobu Mita } 552a995c792SAkinobu Mita } 553a995c792SAkinobu Mita 554a995c792SAkinobu Mita /* Fifth test: write / read across block boundaries */ 555a995c792SAkinobu Mita pr_info("test 5 of 5\n"); 556a995c792SAkinobu Mita 557a995c792SAkinobu Mita /* Erase all eraseblocks */ 5584bf527aaSAkinobu Mita err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); 559a995c792SAkinobu Mita if (err) 560a995c792SAkinobu Mita goto out; 561a995c792SAkinobu Mita 562a995c792SAkinobu Mita /* Write all eraseblocks */ 563a995c792SAkinobu Mita prandom_seed_state(&rnd_state, 11); 564a995c792SAkinobu Mita pr_info("writing OOBs of whole device\n"); 565a995c792SAkinobu Mita for (i = 0; i < ebcnt - 1; ++i) { 566a995c792SAkinobu Mita int cnt = 2; 567a995c792SAkinobu Mita int pg; 568a995c792SAkinobu Mita size_t sz = mtd->ecclayout->oobavail; 569a995c792SAkinobu Mita if (bbt[i] || bbt[i + 1]) 570a995c792SAkinobu Mita continue; 571a995c792SAkinobu Mita addr = (i + 1) * mtd->erasesize - mtd->writesize; 572be54f8f1SAkinobu Mita prandom_bytes_state(&rnd_state, writebuf, sz * cnt); 573a995c792SAkinobu Mita for (pg = 0; pg < cnt; ++pg) { 574a995c792SAkinobu Mita ops.mode = MTD_OPS_AUTO_OOB; 575a995c792SAkinobu Mita ops.len = 0; 576a995c792SAkinobu Mita ops.retlen = 0; 577a995c792SAkinobu Mita ops.ooblen = sz; 578a995c792SAkinobu Mita ops.oobretlen = 0; 579a995c792SAkinobu Mita ops.ooboffs = 0; 580a995c792SAkinobu Mita ops.datbuf = NULL; 581be54f8f1SAkinobu Mita ops.oobbuf = writebuf + pg * sz; 582a995c792SAkinobu Mita err = mtd_write_oob(mtd, addr, &ops); 583a995c792SAkinobu Mita if (err) 584a995c792SAkinobu Mita goto out; 585a995c792SAkinobu Mita if (i % 256 == 0) 586a995c792SAkinobu Mita pr_info("written up to eraseblock %u\n", i); 587a995c792SAkinobu Mita cond_resched(); 588a995c792SAkinobu Mita addr += mtd->writesize; 589a995c792SAkinobu Mita } 590a995c792SAkinobu Mita } 591a995c792SAkinobu Mita pr_info("written %u eraseblocks\n", i); 592a995c792SAkinobu Mita 593a995c792SAkinobu Mita /* Check all eraseblocks */ 594a995c792SAkinobu Mita prandom_seed_state(&rnd_state, 11); 595a995c792SAkinobu Mita pr_info("verifying all eraseblocks\n"); 596a995c792SAkinobu Mita for (i = 0; i < ebcnt - 1; ++i) { 597a995c792SAkinobu Mita if (bbt[i] || bbt[i + 1]) 598a995c792SAkinobu Mita continue; 599a995c792SAkinobu Mita prandom_bytes_state(&rnd_state, writebuf, 600a995c792SAkinobu Mita mtd->ecclayout->oobavail * 2); 601a995c792SAkinobu Mita addr = (i + 1) * mtd->erasesize - mtd->writesize; 602a995c792SAkinobu Mita ops.mode = MTD_OPS_AUTO_OOB; 603a995c792SAkinobu Mita ops.len = 0; 604a995c792SAkinobu Mita ops.retlen = 0; 605a995c792SAkinobu Mita ops.ooblen = mtd->ecclayout->oobavail * 2; 606a995c792SAkinobu Mita ops.oobretlen = 0; 607a995c792SAkinobu Mita ops.ooboffs = 0; 608a995c792SAkinobu Mita ops.datbuf = NULL; 609a995c792SAkinobu Mita ops.oobbuf = readbuf; 610a995c792SAkinobu Mita err = mtd_read_oob(mtd, addr, &ops); 611a995c792SAkinobu Mita if (err) 612a995c792SAkinobu Mita goto out; 613a995c792SAkinobu Mita if (memcmp(readbuf, writebuf, mtd->ecclayout->oobavail * 2)) { 614a995c792SAkinobu Mita pr_err("error: verify failed at %#llx\n", 615a995c792SAkinobu Mita (long long)addr); 616a995c792SAkinobu Mita errcnt += 1; 617a995c792SAkinobu Mita if (errcnt > 1000) { 618a995c792SAkinobu Mita pr_err("error: too many errors\n"); 619a995c792SAkinobu Mita goto out; 620a995c792SAkinobu Mita } 621a995c792SAkinobu Mita } 622a995c792SAkinobu Mita if (i % 256 == 0) 623a995c792SAkinobu Mita pr_info("verified up to eraseblock %u\n", i); 624a995c792SAkinobu Mita cond_resched(); 625a995c792SAkinobu Mita } 626a995c792SAkinobu Mita pr_info("verified %u eraseblocks\n", i); 627a995c792SAkinobu Mita 628a995c792SAkinobu Mita pr_info("finished with %d errors\n", errcnt); 629a995c792SAkinobu Mita out: 630a995c792SAkinobu Mita kfree(bbt); 631a995c792SAkinobu Mita kfree(writebuf); 632a995c792SAkinobu Mita kfree(readbuf); 633a995c792SAkinobu Mita put_mtd_device(mtd); 634a995c792SAkinobu Mita if (err) 635a995c792SAkinobu Mita pr_info("error %d occurred\n", err); 636a995c792SAkinobu Mita printk(KERN_INFO "=================================================\n"); 637a995c792SAkinobu Mita return err; 638a995c792SAkinobu Mita } 639a995c792SAkinobu Mita module_init(mtd_oobtest_init); 640a995c792SAkinobu Mita 641a995c792SAkinobu Mita static void __exit mtd_oobtest_exit(void) 642a995c792SAkinobu Mita { 643a995c792SAkinobu Mita return; 644a995c792SAkinobu Mita } 645a995c792SAkinobu Mita module_exit(mtd_oobtest_exit); 646a995c792SAkinobu Mita 647a995c792SAkinobu Mita MODULE_DESCRIPTION("Out-of-band test module"); 648a995c792SAkinobu Mita MODULE_AUTHOR("Adrian Hunter"); 649a995c792SAkinobu Mita MODULE_LICENSE("GPL"); 650