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; 37afc0ea1bSRoger Quadros static int bitflip_limit; 38a995c792SAkinobu Mita module_param(dev, int, S_IRUGO); 39a995c792SAkinobu Mita MODULE_PARM_DESC(dev, "MTD device number to use"); 40afc0ea1bSRoger Quadros module_param(bitflip_limit, int, S_IRUGO); 41afc0ea1bSRoger Quadros MODULE_PARM_DESC(bitflip_limit, "Max. allowed bitflips per page"); 42a995c792SAkinobu Mita 43a995c792SAkinobu Mita static struct mtd_info *mtd; 44a995c792SAkinobu Mita static unsigned char *readbuf; 45a995c792SAkinobu Mita static unsigned char *writebuf; 46a995c792SAkinobu Mita static unsigned char *bbt; 47a995c792SAkinobu Mita 48a995c792SAkinobu Mita static int ebcnt; 49a995c792SAkinobu Mita static int pgcnt; 50a995c792SAkinobu Mita static int errcnt; 51a995c792SAkinobu Mita static int use_offset; 52a995c792SAkinobu Mita static int use_len; 53a995c792SAkinobu Mita static int use_len_max; 54a995c792SAkinobu Mita static int vary_offset; 55a995c792SAkinobu Mita static struct rnd_state rnd_state; 56a995c792SAkinobu Mita 57a995c792SAkinobu Mita static void do_vary_offset(void) 58a995c792SAkinobu Mita { 59a995c792SAkinobu Mita use_len -= 1; 60a995c792SAkinobu Mita if (use_len < 1) { 61a995c792SAkinobu Mita use_offset += 1; 62a995c792SAkinobu Mita if (use_offset >= use_len_max) 63a995c792SAkinobu Mita use_offset = 0; 64a995c792SAkinobu Mita use_len = use_len_max - use_offset; 65a995c792SAkinobu Mita } 66a995c792SAkinobu Mita } 67a995c792SAkinobu Mita 68a995c792SAkinobu Mita static int write_eraseblock(int ebnum) 69a995c792SAkinobu Mita { 70a995c792SAkinobu Mita int i; 71a995c792SAkinobu Mita struct mtd_oob_ops ops; 72a995c792SAkinobu Mita int err = 0; 73b9da8baeSBrian Norris loff_t addr = (loff_t)ebnum * mtd->erasesize; 74a995c792SAkinobu Mita 75be54f8f1SAkinobu Mita prandom_bytes_state(&rnd_state, writebuf, use_len_max * pgcnt); 76a995c792SAkinobu Mita for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) { 77a995c792SAkinobu Mita ops.mode = MTD_OPS_AUTO_OOB; 78a995c792SAkinobu Mita ops.len = 0; 79a995c792SAkinobu Mita ops.retlen = 0; 80a995c792SAkinobu Mita ops.ooblen = use_len; 81a995c792SAkinobu Mita ops.oobretlen = 0; 82a995c792SAkinobu Mita ops.ooboffs = use_offset; 83a995c792SAkinobu Mita ops.datbuf = NULL; 84be54f8f1SAkinobu Mita ops.oobbuf = writebuf + (use_len_max * i) + use_offset; 85a995c792SAkinobu Mita err = mtd_write_oob(mtd, addr, &ops); 86a995c792SAkinobu Mita if (err || ops.oobretlen != use_len) { 87a995c792SAkinobu Mita pr_err("error: writeoob failed at %#llx\n", 88a995c792SAkinobu Mita (long long)addr); 89a995c792SAkinobu Mita pr_err("error: use_len %d, use_offset %d\n", 90a995c792SAkinobu Mita use_len, use_offset); 91a995c792SAkinobu Mita errcnt += 1; 92a995c792SAkinobu Mita return err ? err : -1; 93a995c792SAkinobu Mita } 94a995c792SAkinobu Mita if (vary_offset) 95a995c792SAkinobu Mita do_vary_offset(); 96a995c792SAkinobu Mita } 97a995c792SAkinobu Mita 98a995c792SAkinobu Mita return err; 99a995c792SAkinobu Mita } 100a995c792SAkinobu Mita 101a995c792SAkinobu Mita static int write_whole_device(void) 102a995c792SAkinobu Mita { 103a995c792SAkinobu Mita int err; 104a995c792SAkinobu Mita unsigned int i; 105a995c792SAkinobu Mita 106a995c792SAkinobu Mita pr_info("writing OOBs of whole device\n"); 107a995c792SAkinobu Mita for (i = 0; i < ebcnt; ++i) { 108a995c792SAkinobu Mita if (bbt[i]) 109a995c792SAkinobu Mita continue; 110a995c792SAkinobu Mita err = write_eraseblock(i); 111a995c792SAkinobu Mita if (err) 112a995c792SAkinobu Mita return err; 113a995c792SAkinobu Mita if (i % 256 == 0) 114a995c792SAkinobu Mita pr_info("written up to eraseblock %u\n", i); 1152a6a28e7SRichard Weinberger 1162a6a28e7SRichard Weinberger err = mtdtest_relax(); 1172a6a28e7SRichard Weinberger if (err) 1182a6a28e7SRichard Weinberger return err; 119a995c792SAkinobu Mita } 120a995c792SAkinobu Mita pr_info("written %u eraseblocks\n", i); 121a995c792SAkinobu Mita return 0; 122a995c792SAkinobu Mita } 123a995c792SAkinobu Mita 124afc0ea1bSRoger Quadros /* 125afc0ea1bSRoger Quadros * Display the address, offset and data bytes at comparison failure. 126afc0ea1bSRoger Quadros * Return number of bitflips encountered. 127afc0ea1bSRoger Quadros */ 128718e38b4SRoger Quadros static size_t memcmpshowoffset(loff_t addr, loff_t offset, const void *cs, 129718e38b4SRoger Quadros const void *ct, size_t count) 1305a66088bSRoger Quadros { 1315a66088bSRoger Quadros const unsigned char *su1, *su2; 1325a66088bSRoger Quadros int res; 1335a66088bSRoger Quadros size_t i = 0; 134afc0ea1bSRoger Quadros size_t bitflips = 0; 1355a66088bSRoger Quadros 1365a66088bSRoger Quadros for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--, i++) { 1375a66088bSRoger Quadros res = *su1 ^ *su2; 1385a66088bSRoger Quadros if (res) { 139718e38b4SRoger Quadros pr_info("error @addr[0x%lx:0x%lx] 0x%x -> 0x%x diff 0x%x\n", 140718e38b4SRoger Quadros (unsigned long)addr, (unsigned long)offset + i, 141718e38b4SRoger Quadros *su1, *su2, res); 142afc0ea1bSRoger Quadros bitflips += hweight8(res); 1435a66088bSRoger Quadros } 1445a66088bSRoger Quadros } 1455a66088bSRoger Quadros 146afc0ea1bSRoger Quadros return bitflips; 1475a66088bSRoger Quadros } 1485a66088bSRoger Quadros 149718e38b4SRoger Quadros #define memcmpshow(addr, cs, ct, count) memcmpshowoffset((addr), 0, (cs), (ct),\ 150718e38b4SRoger Quadros (count)) 151718e38b4SRoger Quadros 152d2b51c80SRoger Quadros /* 153d2b51c80SRoger Quadros * Compare with 0xff and show the address, offset and data bytes at 154d2b51c80SRoger Quadros * comparison failure. Return number of bitflips encountered. 155d2b51c80SRoger Quadros */ 156d2b51c80SRoger Quadros static size_t memffshow(loff_t addr, loff_t offset, const void *cs, 157d2b51c80SRoger Quadros size_t count) 158d2b51c80SRoger Quadros { 159d2b51c80SRoger Quadros const unsigned char *su1; 160d2b51c80SRoger Quadros int res; 161d2b51c80SRoger Quadros size_t i = 0; 162d2b51c80SRoger Quadros size_t bitflips = 0; 163d2b51c80SRoger Quadros 164d2b51c80SRoger Quadros for (su1 = cs; 0 < count; ++su1, count--, i++) { 165d2b51c80SRoger Quadros res = *su1 ^ 0xff; 166d2b51c80SRoger Quadros if (res) { 167d2b51c80SRoger Quadros pr_info("error @addr[0x%lx:0x%lx] 0x%x -> 0xff diff 0x%x\n", 168d2b51c80SRoger Quadros (unsigned long)addr, (unsigned long)offset + i, 169d2b51c80SRoger Quadros *su1, res); 170d2b51c80SRoger Quadros bitflips += hweight8(res); 171d2b51c80SRoger Quadros } 172d2b51c80SRoger Quadros } 173d2b51c80SRoger Quadros 174d2b51c80SRoger Quadros return bitflips; 175d2b51c80SRoger Quadros } 176d2b51c80SRoger Quadros 177a995c792SAkinobu Mita static int verify_eraseblock(int ebnum) 178a995c792SAkinobu Mita { 179a995c792SAkinobu Mita int i; 180a995c792SAkinobu Mita struct mtd_oob_ops ops; 181a995c792SAkinobu Mita int err = 0; 1821001ff7aSBrian Norris loff_t addr = (loff_t)ebnum * mtd->erasesize; 183afc0ea1bSRoger Quadros size_t bitflips; 184a995c792SAkinobu Mita 185be54f8f1SAkinobu Mita prandom_bytes_state(&rnd_state, writebuf, use_len_max * pgcnt); 186a995c792SAkinobu Mita for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) { 187a995c792SAkinobu Mita ops.mode = MTD_OPS_AUTO_OOB; 188a995c792SAkinobu Mita ops.len = 0; 189a995c792SAkinobu Mita ops.retlen = 0; 190a995c792SAkinobu Mita ops.ooblen = use_len; 191a995c792SAkinobu Mita ops.oobretlen = 0; 192a995c792SAkinobu Mita ops.ooboffs = use_offset; 193a995c792SAkinobu Mita ops.datbuf = NULL; 194a995c792SAkinobu Mita ops.oobbuf = readbuf; 195a995c792SAkinobu Mita err = mtd_read_oob(mtd, addr, &ops); 19612663b44SMiquel Raynal if (mtd_is_bitflip(err)) 19712663b44SMiquel Raynal err = 0; 19812663b44SMiquel Raynal 199a995c792SAkinobu Mita if (err || ops.oobretlen != use_len) { 200a995c792SAkinobu Mita pr_err("error: readoob failed at %#llx\n", 201a995c792SAkinobu Mita (long long)addr); 202a995c792SAkinobu Mita errcnt += 1; 203a995c792SAkinobu Mita return err ? err : -1; 204a995c792SAkinobu Mita } 205afc0ea1bSRoger Quadros 206afc0ea1bSRoger Quadros bitflips = memcmpshow(addr, readbuf, 2075a66088bSRoger Quadros writebuf + (use_len_max * i) + use_offset, 208afc0ea1bSRoger Quadros use_len); 209afc0ea1bSRoger Quadros if (bitflips > bitflip_limit) { 210a995c792SAkinobu Mita pr_err("error: verify failed at %#llx\n", 211a995c792SAkinobu Mita (long long)addr); 212a995c792SAkinobu Mita errcnt += 1; 213a995c792SAkinobu Mita if (errcnt > 1000) { 214a995c792SAkinobu Mita pr_err("error: too many errors\n"); 215a995c792SAkinobu Mita return -1; 216a995c792SAkinobu Mita } 217afc0ea1bSRoger Quadros } else if (bitflips) { 218afc0ea1bSRoger Quadros pr_info("ignoring error as within bitflip_limit\n"); 219a995c792SAkinobu Mita } 220afc0ea1bSRoger Quadros 221f5b8aa78SBoris BREZILLON if (use_offset != 0 || use_len < mtd->oobavail) { 222a995c792SAkinobu Mita int k; 223a995c792SAkinobu Mita 224a995c792SAkinobu Mita ops.mode = MTD_OPS_AUTO_OOB; 225a995c792SAkinobu Mita ops.len = 0; 226a995c792SAkinobu Mita ops.retlen = 0; 227f5b8aa78SBoris BREZILLON ops.ooblen = mtd->oobavail; 228a995c792SAkinobu Mita ops.oobretlen = 0; 229a995c792SAkinobu Mita ops.ooboffs = 0; 230a995c792SAkinobu Mita ops.datbuf = NULL; 231a995c792SAkinobu Mita ops.oobbuf = readbuf; 232a995c792SAkinobu Mita err = mtd_read_oob(mtd, addr, &ops); 23312663b44SMiquel Raynal if (mtd_is_bitflip(err)) 23412663b44SMiquel Raynal err = 0; 23512663b44SMiquel Raynal 236f5b8aa78SBoris BREZILLON if (err || ops.oobretlen != mtd->oobavail) { 237a995c792SAkinobu Mita pr_err("error: readoob failed at %#llx\n", 238a995c792SAkinobu Mita (long long)addr); 239a995c792SAkinobu Mita errcnt += 1; 240a995c792SAkinobu Mita return err ? err : -1; 241a995c792SAkinobu Mita } 242718e38b4SRoger Quadros bitflips = memcmpshowoffset(addr, use_offset, 243718e38b4SRoger Quadros readbuf + use_offset, 244be54f8f1SAkinobu Mita writebuf + (use_len_max * i) + use_offset, 245afc0ea1bSRoger Quadros use_len); 246d2b51c80SRoger Quadros 247d2b51c80SRoger Quadros /* verify pre-offset area for 0xff */ 248d2b51c80SRoger Quadros bitflips += memffshow(addr, 0, readbuf, use_offset); 249d2b51c80SRoger Quadros 250d2b51c80SRoger Quadros /* verify post-(use_offset + use_len) area for 0xff */ 251d2b51c80SRoger Quadros k = use_offset + use_len; 252d2b51c80SRoger Quadros bitflips += memffshow(addr, k, readbuf + k, 253f5b8aa78SBoris BREZILLON mtd->oobavail - k); 254d2b51c80SRoger Quadros 255afc0ea1bSRoger Quadros if (bitflips > bitflip_limit) { 256a995c792SAkinobu Mita pr_err("error: verify failed at %#llx\n", 257a995c792SAkinobu Mita (long long)addr); 258a995c792SAkinobu Mita errcnt += 1; 259a995c792SAkinobu Mita if (errcnt > 1000) { 260a995c792SAkinobu Mita pr_err("error: too many errors\n"); 261a995c792SAkinobu Mita return -1; 262a995c792SAkinobu Mita } 263afc0ea1bSRoger Quadros } else if (bitflips) { 264d2b51c80SRoger Quadros pr_info("ignoring errors as within bitflip limit\n"); 265a995c792SAkinobu Mita } 266a995c792SAkinobu Mita } 267a995c792SAkinobu Mita if (vary_offset) 268a995c792SAkinobu Mita do_vary_offset(); 269a995c792SAkinobu Mita } 270a995c792SAkinobu Mita return err; 271a995c792SAkinobu Mita } 272a995c792SAkinobu Mita 273a995c792SAkinobu Mita static int verify_eraseblock_in_one_go(int ebnum) 274a995c792SAkinobu Mita { 275a995c792SAkinobu Mita struct mtd_oob_ops ops; 276a995c792SAkinobu Mita int err = 0; 2771001ff7aSBrian Norris loff_t addr = (loff_t)ebnum * mtd->erasesize; 278f5b8aa78SBoris BREZILLON size_t len = mtd->oobavail * pgcnt; 279f5b8aa78SBoris BREZILLON size_t oobavail = mtd->oobavail; 280afc0ea1bSRoger Quadros size_t bitflips; 281afc0ea1bSRoger Quadros int i; 282a995c792SAkinobu Mita 283a995c792SAkinobu Mita prandom_bytes_state(&rnd_state, writebuf, len); 284a995c792SAkinobu Mita ops.mode = MTD_OPS_AUTO_OOB; 285a995c792SAkinobu Mita ops.len = 0; 286a995c792SAkinobu Mita ops.retlen = 0; 287a995c792SAkinobu Mita ops.ooblen = len; 288a995c792SAkinobu Mita ops.oobretlen = 0; 289a995c792SAkinobu Mita ops.ooboffs = 0; 290a995c792SAkinobu Mita ops.datbuf = NULL; 291a995c792SAkinobu Mita ops.oobbuf = readbuf; 292afc0ea1bSRoger Quadros 293afc0ea1bSRoger Quadros /* read entire block's OOB at one go */ 294a995c792SAkinobu Mita err = mtd_read_oob(mtd, addr, &ops); 29512663b44SMiquel Raynal if (mtd_is_bitflip(err)) 29612663b44SMiquel Raynal err = 0; 29712663b44SMiquel Raynal 298a995c792SAkinobu Mita if (err || ops.oobretlen != len) { 299a995c792SAkinobu Mita pr_err("error: readoob failed at %#llx\n", 300a995c792SAkinobu Mita (long long)addr); 301a995c792SAkinobu Mita errcnt += 1; 302a995c792SAkinobu Mita return err ? err : -1; 303a995c792SAkinobu Mita } 304afc0ea1bSRoger Quadros 305afc0ea1bSRoger Quadros /* verify one page OOB at a time for bitflip per page limit check */ 306afc0ea1bSRoger Quadros for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) { 307afc0ea1bSRoger Quadros bitflips = memcmpshow(addr, readbuf + (i * oobavail), 308afc0ea1bSRoger Quadros writebuf + (i * oobavail), oobavail); 309afc0ea1bSRoger Quadros if (bitflips > bitflip_limit) { 310a995c792SAkinobu Mita pr_err("error: verify failed at %#llx\n", 311a995c792SAkinobu Mita (long long)addr); 312a995c792SAkinobu Mita errcnt += 1; 313a995c792SAkinobu Mita if (errcnt > 1000) { 314a995c792SAkinobu Mita pr_err("error: too many errors\n"); 315a995c792SAkinobu Mita return -1; 316a995c792SAkinobu Mita } 317afc0ea1bSRoger Quadros } else if (bitflips) { 318afc0ea1bSRoger Quadros pr_info("ignoring error as within bitflip_limit\n"); 319afc0ea1bSRoger Quadros } 320a995c792SAkinobu Mita } 321a995c792SAkinobu Mita 322a995c792SAkinobu Mita return err; 323a995c792SAkinobu Mita } 324a995c792SAkinobu Mita 325a995c792SAkinobu Mita static int verify_all_eraseblocks(void) 326a995c792SAkinobu Mita { 327a995c792SAkinobu Mita int err; 328a995c792SAkinobu Mita unsigned int i; 329a995c792SAkinobu Mita 330a995c792SAkinobu Mita pr_info("verifying all eraseblocks\n"); 331a995c792SAkinobu Mita for (i = 0; i < ebcnt; ++i) { 332a995c792SAkinobu Mita if (bbt[i]) 333a995c792SAkinobu Mita continue; 334a995c792SAkinobu Mita err = verify_eraseblock(i); 335a995c792SAkinobu Mita if (err) 336a995c792SAkinobu Mita return err; 337a995c792SAkinobu Mita if (i % 256 == 0) 338a995c792SAkinobu Mita pr_info("verified up to eraseblock %u\n", i); 3392a6a28e7SRichard Weinberger 3402a6a28e7SRichard Weinberger err = mtdtest_relax(); 3412a6a28e7SRichard Weinberger if (err) 3422a6a28e7SRichard Weinberger return err; 343a995c792SAkinobu Mita } 344a995c792SAkinobu Mita pr_info("verified %u eraseblocks\n", i); 345a995c792SAkinobu Mita return 0; 346a995c792SAkinobu Mita } 347a995c792SAkinobu Mita 348a995c792SAkinobu Mita static int __init mtd_oobtest_init(void) 349a995c792SAkinobu Mita { 350a995c792SAkinobu Mita int err = 0; 351a995c792SAkinobu Mita unsigned int i; 352a995c792SAkinobu Mita uint64_t tmp; 353a995c792SAkinobu Mita struct mtd_oob_ops ops; 354a995c792SAkinobu Mita loff_t addr = 0, addr0; 355a995c792SAkinobu Mita 356a995c792SAkinobu Mita printk(KERN_INFO "\n"); 357a995c792SAkinobu Mita printk(KERN_INFO "=================================================\n"); 358a995c792SAkinobu Mita 359a995c792SAkinobu Mita if (dev < 0) { 360a995c792SAkinobu Mita pr_info("Please specify a valid mtd-device via module parameter\n"); 361a995c792SAkinobu Mita pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n"); 362a995c792SAkinobu Mita return -EINVAL; 363a995c792SAkinobu Mita } 364a995c792SAkinobu Mita 365a995c792SAkinobu Mita pr_info("MTD device: %d\n", dev); 366a995c792SAkinobu Mita 367a995c792SAkinobu Mita mtd = get_mtd_device(NULL, dev); 368a995c792SAkinobu Mita if (IS_ERR(mtd)) { 369a995c792SAkinobu Mita err = PTR_ERR(mtd); 370a995c792SAkinobu Mita pr_err("error: cannot get MTD device\n"); 371a995c792SAkinobu Mita return err; 372a995c792SAkinobu Mita } 373a995c792SAkinobu Mita 374818b9739SHuang Shijie if (!mtd_type_is_nand(mtd)) { 375a995c792SAkinobu Mita pr_info("this test requires NAND flash\n"); 376a995c792SAkinobu Mita goto out; 377a995c792SAkinobu Mita } 378a995c792SAkinobu Mita 379a995c792SAkinobu Mita tmp = mtd->size; 380a995c792SAkinobu Mita do_div(tmp, mtd->erasesize); 381a995c792SAkinobu Mita ebcnt = tmp; 382a995c792SAkinobu Mita pgcnt = mtd->erasesize / mtd->writesize; 383a995c792SAkinobu Mita 384a995c792SAkinobu Mita pr_info("MTD device size %llu, eraseblock size %u, " 385a995c792SAkinobu Mita "page size %u, count of eraseblocks %u, pages per " 386a995c792SAkinobu Mita "eraseblock %u, OOB size %u\n", 387a995c792SAkinobu Mita (unsigned long long)mtd->size, mtd->erasesize, 388a995c792SAkinobu Mita mtd->writesize, ebcnt, pgcnt, mtd->oobsize); 389a995c792SAkinobu Mita 390a995c792SAkinobu Mita err = -ENOMEM; 391a995c792SAkinobu Mita readbuf = kmalloc(mtd->erasesize, GFP_KERNEL); 392a995c792SAkinobu Mita if (!readbuf) 393a995c792SAkinobu Mita goto out; 394a995c792SAkinobu Mita writebuf = kmalloc(mtd->erasesize, GFP_KERNEL); 395a995c792SAkinobu Mita if (!writebuf) 396a995c792SAkinobu Mita goto out; 3974bf527aaSAkinobu Mita bbt = kzalloc(ebcnt, GFP_KERNEL); 3984bf527aaSAkinobu Mita if (!bbt) 3994bf527aaSAkinobu Mita goto out; 400a995c792SAkinobu Mita 4014bf527aaSAkinobu Mita err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt); 402a995c792SAkinobu Mita if (err) 403a995c792SAkinobu Mita goto out; 404a995c792SAkinobu Mita 405a995c792SAkinobu Mita use_offset = 0; 406f5b8aa78SBoris BREZILLON use_len = mtd->oobavail; 407f5b8aa78SBoris BREZILLON use_len_max = mtd->oobavail; 408a995c792SAkinobu Mita vary_offset = 0; 409a995c792SAkinobu Mita 410a995c792SAkinobu Mita /* First test: write all OOB, read it back and verify */ 411a995c792SAkinobu Mita pr_info("test 1 of 5\n"); 412a995c792SAkinobu Mita 4134bf527aaSAkinobu Mita err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); 414a995c792SAkinobu Mita if (err) 415a995c792SAkinobu Mita goto out; 416a995c792SAkinobu Mita 417a995c792SAkinobu Mita prandom_seed_state(&rnd_state, 1); 418a995c792SAkinobu Mita err = write_whole_device(); 419a995c792SAkinobu Mita if (err) 420a995c792SAkinobu Mita goto out; 421a995c792SAkinobu Mita 422a995c792SAkinobu Mita prandom_seed_state(&rnd_state, 1); 423a995c792SAkinobu Mita err = verify_all_eraseblocks(); 424a995c792SAkinobu Mita if (err) 425a995c792SAkinobu Mita goto out; 426a995c792SAkinobu Mita 427a995c792SAkinobu Mita /* 428a995c792SAkinobu Mita * Second test: write all OOB, a block at a time, read it back and 429a995c792SAkinobu Mita * verify. 430a995c792SAkinobu Mita */ 431a995c792SAkinobu Mita pr_info("test 2 of 5\n"); 432a995c792SAkinobu Mita 4334bf527aaSAkinobu Mita err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); 434a995c792SAkinobu Mita if (err) 435a995c792SAkinobu Mita goto out; 436a995c792SAkinobu Mita 437a995c792SAkinobu Mita prandom_seed_state(&rnd_state, 3); 438a995c792SAkinobu Mita err = write_whole_device(); 439a995c792SAkinobu Mita if (err) 440a995c792SAkinobu Mita goto out; 441a995c792SAkinobu Mita 442a995c792SAkinobu Mita /* Check all eraseblocks */ 443a995c792SAkinobu Mita prandom_seed_state(&rnd_state, 3); 444a995c792SAkinobu Mita pr_info("verifying all eraseblocks\n"); 445a995c792SAkinobu Mita for (i = 0; i < ebcnt; ++i) { 446a995c792SAkinobu Mita if (bbt[i]) 447a995c792SAkinobu Mita continue; 448a995c792SAkinobu Mita err = verify_eraseblock_in_one_go(i); 449a995c792SAkinobu Mita if (err) 450a995c792SAkinobu Mita goto out; 451a995c792SAkinobu Mita if (i % 256 == 0) 452a995c792SAkinobu Mita pr_info("verified up to eraseblock %u\n", i); 4532a6a28e7SRichard Weinberger 4542a6a28e7SRichard Weinberger err = mtdtest_relax(); 4552a6a28e7SRichard Weinberger if (err) 4562a6a28e7SRichard Weinberger goto out; 457a995c792SAkinobu Mita } 458a995c792SAkinobu Mita pr_info("verified %u eraseblocks\n", i); 459a995c792SAkinobu Mita 460a995c792SAkinobu Mita /* 461a995c792SAkinobu Mita * Third test: write OOB at varying offsets and lengths, read it back 462a995c792SAkinobu Mita * and verify. 463a995c792SAkinobu Mita */ 464a995c792SAkinobu Mita pr_info("test 3 of 5\n"); 465a995c792SAkinobu Mita 4664bf527aaSAkinobu Mita err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); 467a995c792SAkinobu Mita if (err) 468a995c792SAkinobu Mita goto out; 469a995c792SAkinobu Mita 470a995c792SAkinobu Mita /* Write all eraseblocks */ 471a995c792SAkinobu Mita use_offset = 0; 472f5b8aa78SBoris BREZILLON use_len = mtd->oobavail; 473f5b8aa78SBoris BREZILLON use_len_max = mtd->oobavail; 474a995c792SAkinobu Mita vary_offset = 1; 475a995c792SAkinobu Mita prandom_seed_state(&rnd_state, 5); 476a995c792SAkinobu Mita 477a995c792SAkinobu Mita err = write_whole_device(); 478a995c792SAkinobu Mita if (err) 479a995c792SAkinobu Mita goto out; 480a995c792SAkinobu Mita 481a995c792SAkinobu Mita /* Check all eraseblocks */ 482a995c792SAkinobu Mita use_offset = 0; 483f5b8aa78SBoris BREZILLON use_len = mtd->oobavail; 484f5b8aa78SBoris BREZILLON use_len_max = mtd->oobavail; 485a995c792SAkinobu Mita vary_offset = 1; 486a995c792SAkinobu Mita prandom_seed_state(&rnd_state, 5); 487a995c792SAkinobu Mita err = verify_all_eraseblocks(); 488a995c792SAkinobu Mita if (err) 489a995c792SAkinobu Mita goto out; 490a995c792SAkinobu Mita 491a995c792SAkinobu Mita use_offset = 0; 492f5b8aa78SBoris BREZILLON use_len = mtd->oobavail; 493f5b8aa78SBoris BREZILLON use_len_max = mtd->oobavail; 494a995c792SAkinobu Mita vary_offset = 0; 495a995c792SAkinobu Mita 496a995c792SAkinobu Mita /* Fourth test: try to write off end of device */ 497a995c792SAkinobu Mita pr_info("test 4 of 5\n"); 498a995c792SAkinobu Mita 4994bf527aaSAkinobu Mita err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); 500a995c792SAkinobu Mita if (err) 501a995c792SAkinobu Mita goto out; 502a995c792SAkinobu Mita 503a995c792SAkinobu Mita addr0 = 0; 504a995c792SAkinobu Mita for (i = 0; i < ebcnt && bbt[i]; ++i) 505a995c792SAkinobu Mita addr0 += mtd->erasesize; 506a995c792SAkinobu Mita 507a995c792SAkinobu Mita /* Attempt to write off end of OOB */ 508a995c792SAkinobu Mita ops.mode = MTD_OPS_AUTO_OOB; 509a995c792SAkinobu Mita ops.len = 0; 510a995c792SAkinobu Mita ops.retlen = 0; 511a995c792SAkinobu Mita ops.ooblen = 1; 512a995c792SAkinobu Mita ops.oobretlen = 0; 513f5b8aa78SBoris BREZILLON ops.ooboffs = mtd->oobavail; 514a995c792SAkinobu Mita ops.datbuf = NULL; 515a995c792SAkinobu Mita ops.oobbuf = writebuf; 516a995c792SAkinobu Mita pr_info("attempting to start write past end of OOB\n"); 517a995c792SAkinobu Mita pr_info("an error is expected...\n"); 518a995c792SAkinobu Mita err = mtd_write_oob(mtd, addr0, &ops); 519a995c792SAkinobu Mita if (err) { 520a995c792SAkinobu Mita pr_info("error occurred as expected\n"); 521a995c792SAkinobu Mita err = 0; 522a995c792SAkinobu Mita } else { 523a995c792SAkinobu Mita pr_err("error: can write past end of OOB\n"); 524a995c792SAkinobu Mita errcnt += 1; 525a995c792SAkinobu Mita } 526a995c792SAkinobu Mita 527a995c792SAkinobu Mita /* Attempt to read off end of OOB */ 528a995c792SAkinobu Mita ops.mode = MTD_OPS_AUTO_OOB; 529a995c792SAkinobu Mita ops.len = 0; 530a995c792SAkinobu Mita ops.retlen = 0; 531a995c792SAkinobu Mita ops.ooblen = 1; 532a995c792SAkinobu Mita ops.oobretlen = 0; 533f5b8aa78SBoris BREZILLON ops.ooboffs = mtd->oobavail; 534a995c792SAkinobu Mita ops.datbuf = NULL; 535a995c792SAkinobu Mita ops.oobbuf = readbuf; 536a995c792SAkinobu Mita pr_info("attempting to start read past end of OOB\n"); 537a995c792SAkinobu Mita pr_info("an error is expected...\n"); 538a995c792SAkinobu Mita err = mtd_read_oob(mtd, addr0, &ops); 53912663b44SMiquel Raynal if (mtd_is_bitflip(err)) 54012663b44SMiquel Raynal err = 0; 54112663b44SMiquel Raynal 542a995c792SAkinobu Mita if (err) { 543a995c792SAkinobu Mita pr_info("error occurred as expected\n"); 544a995c792SAkinobu Mita err = 0; 545a995c792SAkinobu Mita } else { 546a995c792SAkinobu Mita pr_err("error: can read past end of OOB\n"); 547a995c792SAkinobu Mita errcnt += 1; 548a995c792SAkinobu Mita } 549a995c792SAkinobu Mita 550a995c792SAkinobu Mita if (bbt[ebcnt - 1]) 551a995c792SAkinobu Mita pr_info("skipping end of device tests because last " 552a995c792SAkinobu Mita "block is bad\n"); 553a995c792SAkinobu Mita else { 554a995c792SAkinobu Mita /* Attempt to write off end of device */ 555a995c792SAkinobu Mita ops.mode = MTD_OPS_AUTO_OOB; 556a995c792SAkinobu Mita ops.len = 0; 557a995c792SAkinobu Mita ops.retlen = 0; 558f5b8aa78SBoris BREZILLON ops.ooblen = mtd->oobavail + 1; 559a995c792SAkinobu Mita ops.oobretlen = 0; 560a995c792SAkinobu Mita ops.ooboffs = 0; 561a995c792SAkinobu Mita ops.datbuf = NULL; 562a995c792SAkinobu Mita ops.oobbuf = writebuf; 563a995c792SAkinobu Mita pr_info("attempting to write past end of device\n"); 564a995c792SAkinobu Mita pr_info("an error is expected...\n"); 565a995c792SAkinobu Mita err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops); 566a995c792SAkinobu Mita if (err) { 567a995c792SAkinobu Mita pr_info("error occurred as expected\n"); 568a995c792SAkinobu Mita err = 0; 569a995c792SAkinobu Mita } else { 570a995c792SAkinobu Mita pr_err("error: wrote past end of device\n"); 571a995c792SAkinobu Mita errcnt += 1; 572a995c792SAkinobu Mita } 573a995c792SAkinobu Mita 574a995c792SAkinobu Mita /* Attempt to read off end of device */ 575a995c792SAkinobu Mita ops.mode = MTD_OPS_AUTO_OOB; 576a995c792SAkinobu Mita ops.len = 0; 577a995c792SAkinobu Mita ops.retlen = 0; 578f5b8aa78SBoris BREZILLON ops.ooblen = mtd->oobavail + 1; 579a995c792SAkinobu Mita ops.oobretlen = 0; 580a995c792SAkinobu Mita ops.ooboffs = 0; 581a995c792SAkinobu Mita ops.datbuf = NULL; 582a995c792SAkinobu Mita ops.oobbuf = readbuf; 583a995c792SAkinobu Mita pr_info("attempting to read past end of device\n"); 584a995c792SAkinobu Mita pr_info("an error is expected...\n"); 585a995c792SAkinobu Mita err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops); 58612663b44SMiquel Raynal if (mtd_is_bitflip(err)) 58712663b44SMiquel Raynal err = 0; 58812663b44SMiquel Raynal 589a995c792SAkinobu Mita if (err) { 590a995c792SAkinobu Mita pr_info("error occurred as expected\n"); 591a995c792SAkinobu Mita err = 0; 592a995c792SAkinobu Mita } else { 593a995c792SAkinobu Mita pr_err("error: read past end of device\n"); 594a995c792SAkinobu Mita errcnt += 1; 595a995c792SAkinobu Mita } 596a995c792SAkinobu Mita 5974bf527aaSAkinobu Mita err = mtdtest_erase_eraseblock(mtd, ebcnt - 1); 598a995c792SAkinobu Mita if (err) 599a995c792SAkinobu Mita goto out; 600a995c792SAkinobu Mita 601a995c792SAkinobu Mita /* Attempt to write off end of device */ 602a995c792SAkinobu Mita ops.mode = MTD_OPS_AUTO_OOB; 603a995c792SAkinobu Mita ops.len = 0; 604a995c792SAkinobu Mita ops.retlen = 0; 605f5b8aa78SBoris BREZILLON ops.ooblen = mtd->oobavail; 606a995c792SAkinobu Mita ops.oobretlen = 0; 607a995c792SAkinobu Mita ops.ooboffs = 1; 608a995c792SAkinobu Mita ops.datbuf = NULL; 609a995c792SAkinobu Mita ops.oobbuf = writebuf; 610a995c792SAkinobu Mita pr_info("attempting to write past end of device\n"); 611a995c792SAkinobu Mita pr_info("an error is expected...\n"); 612a995c792SAkinobu Mita err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops); 613a995c792SAkinobu Mita if (err) { 614a995c792SAkinobu Mita pr_info("error occurred as expected\n"); 615a995c792SAkinobu Mita err = 0; 616a995c792SAkinobu Mita } else { 617a995c792SAkinobu Mita pr_err("error: wrote past end of device\n"); 618a995c792SAkinobu Mita errcnt += 1; 619a995c792SAkinobu Mita } 620a995c792SAkinobu Mita 621a995c792SAkinobu Mita /* Attempt to read off end of device */ 622a995c792SAkinobu Mita ops.mode = MTD_OPS_AUTO_OOB; 623a995c792SAkinobu Mita ops.len = 0; 624a995c792SAkinobu Mita ops.retlen = 0; 625f5b8aa78SBoris BREZILLON ops.ooblen = mtd->oobavail; 626a995c792SAkinobu Mita ops.oobretlen = 0; 627a995c792SAkinobu Mita ops.ooboffs = 1; 628a995c792SAkinobu Mita ops.datbuf = NULL; 629a995c792SAkinobu Mita ops.oobbuf = readbuf; 630a995c792SAkinobu Mita pr_info("attempting to read past end of device\n"); 631a995c792SAkinobu Mita pr_info("an error is expected...\n"); 632a995c792SAkinobu Mita err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops); 63312663b44SMiquel Raynal if (mtd_is_bitflip(err)) 63412663b44SMiquel Raynal err = 0; 63512663b44SMiquel Raynal 636a995c792SAkinobu Mita if (err) { 637a995c792SAkinobu Mita pr_info("error occurred as expected\n"); 638a995c792SAkinobu Mita err = 0; 639a995c792SAkinobu Mita } else { 640a995c792SAkinobu Mita pr_err("error: read past end of device\n"); 641a995c792SAkinobu Mita errcnt += 1; 642a995c792SAkinobu Mita } 643a995c792SAkinobu Mita } 644a995c792SAkinobu Mita 645a995c792SAkinobu Mita /* Fifth test: write / read across block boundaries */ 646a995c792SAkinobu Mita pr_info("test 5 of 5\n"); 647a995c792SAkinobu Mita 648a995c792SAkinobu Mita /* Erase all eraseblocks */ 6494bf527aaSAkinobu Mita err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); 650a995c792SAkinobu Mita if (err) 651a995c792SAkinobu Mita goto out; 652a995c792SAkinobu Mita 653a995c792SAkinobu Mita /* Write all eraseblocks */ 654a995c792SAkinobu Mita prandom_seed_state(&rnd_state, 11); 655a995c792SAkinobu Mita pr_info("writing OOBs of whole device\n"); 656a995c792SAkinobu Mita for (i = 0; i < ebcnt - 1; ++i) { 657a995c792SAkinobu Mita int cnt = 2; 658a995c792SAkinobu Mita int pg; 659f5b8aa78SBoris BREZILLON size_t sz = mtd->oobavail; 660a995c792SAkinobu Mita if (bbt[i] || bbt[i + 1]) 661a995c792SAkinobu Mita continue; 6621001ff7aSBrian Norris addr = (loff_t)(i + 1) * mtd->erasesize - mtd->writesize; 663be54f8f1SAkinobu Mita prandom_bytes_state(&rnd_state, writebuf, sz * cnt); 664a995c792SAkinobu Mita for (pg = 0; pg < cnt; ++pg) { 665a995c792SAkinobu Mita ops.mode = MTD_OPS_AUTO_OOB; 666a995c792SAkinobu Mita ops.len = 0; 667a995c792SAkinobu Mita ops.retlen = 0; 668a995c792SAkinobu Mita ops.ooblen = sz; 669a995c792SAkinobu Mita ops.oobretlen = 0; 670a995c792SAkinobu Mita ops.ooboffs = 0; 671a995c792SAkinobu Mita ops.datbuf = NULL; 672be54f8f1SAkinobu Mita ops.oobbuf = writebuf + pg * sz; 673a995c792SAkinobu Mita err = mtd_write_oob(mtd, addr, &ops); 674a995c792SAkinobu Mita if (err) 675a995c792SAkinobu Mita goto out; 676a995c792SAkinobu Mita if (i % 256 == 0) 677a995c792SAkinobu Mita pr_info("written up to eraseblock %u\n", i); 6782a6a28e7SRichard Weinberger 6792a6a28e7SRichard Weinberger err = mtdtest_relax(); 6802a6a28e7SRichard Weinberger if (err) 6812a6a28e7SRichard Weinberger goto out; 6822a6a28e7SRichard Weinberger 683a995c792SAkinobu Mita addr += mtd->writesize; 684a995c792SAkinobu Mita } 685a995c792SAkinobu Mita } 686a995c792SAkinobu Mita pr_info("written %u eraseblocks\n", i); 687a995c792SAkinobu Mita 688a995c792SAkinobu Mita /* Check all eraseblocks */ 689a995c792SAkinobu Mita prandom_seed_state(&rnd_state, 11); 690a995c792SAkinobu Mita pr_info("verifying all eraseblocks\n"); 691a995c792SAkinobu Mita for (i = 0; i < ebcnt - 1; ++i) { 692a995c792SAkinobu Mita if (bbt[i] || bbt[i + 1]) 693a995c792SAkinobu Mita continue; 694f5b8aa78SBoris BREZILLON prandom_bytes_state(&rnd_state, writebuf, mtd->oobavail * 2); 6951001ff7aSBrian Norris addr = (loff_t)(i + 1) * mtd->erasesize - mtd->writesize; 696a995c792SAkinobu Mita ops.mode = MTD_OPS_AUTO_OOB; 697a995c792SAkinobu Mita ops.len = 0; 698a995c792SAkinobu Mita ops.retlen = 0; 699f5b8aa78SBoris BREZILLON ops.ooblen = mtd->oobavail * 2; 700a995c792SAkinobu Mita ops.oobretlen = 0; 701a995c792SAkinobu Mita ops.ooboffs = 0; 702a995c792SAkinobu Mita ops.datbuf = NULL; 703a995c792SAkinobu Mita ops.oobbuf = readbuf; 704a995c792SAkinobu Mita err = mtd_read_oob(mtd, addr, &ops); 70512663b44SMiquel Raynal if (mtd_is_bitflip(err)) 70612663b44SMiquel Raynal err = 0; 70712663b44SMiquel Raynal 708a995c792SAkinobu Mita if (err) 709a995c792SAkinobu Mita goto out; 7105a66088bSRoger Quadros if (memcmpshow(addr, readbuf, writebuf, 711f5b8aa78SBoris BREZILLON mtd->oobavail * 2)) { 712a995c792SAkinobu Mita pr_err("error: verify failed at %#llx\n", 713a995c792SAkinobu Mita (long long)addr); 714a995c792SAkinobu Mita errcnt += 1; 715a995c792SAkinobu Mita if (errcnt > 1000) { 716a995c792SAkinobu Mita pr_err("error: too many errors\n"); 717a995c792SAkinobu Mita goto out; 718a995c792SAkinobu Mita } 719a995c792SAkinobu Mita } 720a995c792SAkinobu Mita if (i % 256 == 0) 721a995c792SAkinobu Mita pr_info("verified up to eraseblock %u\n", i); 7222a6a28e7SRichard Weinberger 7232a6a28e7SRichard Weinberger err = mtdtest_relax(); 7242a6a28e7SRichard Weinberger if (err) 7252a6a28e7SRichard Weinberger goto out; 726a995c792SAkinobu Mita } 727a995c792SAkinobu Mita pr_info("verified %u eraseblocks\n", i); 728a995c792SAkinobu Mita 729a995c792SAkinobu Mita pr_info("finished with %d errors\n", errcnt); 730a995c792SAkinobu Mita out: 731a995c792SAkinobu Mita kfree(bbt); 732a995c792SAkinobu Mita kfree(writebuf); 733a995c792SAkinobu Mita kfree(readbuf); 734a995c792SAkinobu Mita put_mtd_device(mtd); 735a995c792SAkinobu Mita if (err) 736a995c792SAkinobu Mita pr_info("error %d occurred\n", err); 737a995c792SAkinobu Mita printk(KERN_INFO "=================================================\n"); 738a995c792SAkinobu Mita return err; 739a995c792SAkinobu Mita } 740a995c792SAkinobu Mita module_init(mtd_oobtest_init); 741a995c792SAkinobu Mita 742a995c792SAkinobu Mita static void __exit mtd_oobtest_exit(void) 743a995c792SAkinobu Mita { 744a995c792SAkinobu Mita return; 745a995c792SAkinobu Mita } 746a995c792SAkinobu Mita module_exit(mtd_oobtest_exit); 747a995c792SAkinobu Mita 748a995c792SAkinobu Mita MODULE_DESCRIPTION("Out-of-band test module"); 749a995c792SAkinobu Mita MODULE_AUTHOR("Adrian Hunter"); 750a995c792SAkinobu Mita MODULE_LICENSE("GPL"); 751