14cd10358SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2a995c792SAkinobu Mita /* 3a995c792SAkinobu Mita * Copyright (C) 2006-2008 Nokia Corporation 4a995c792SAkinobu Mita * 5a995c792SAkinobu Mita * Test OOB read and write on MTD device. 6a995c792SAkinobu Mita * 7a995c792SAkinobu Mita * Author: Adrian Hunter <ext-adrian.hunter@nokia.com> 8a995c792SAkinobu Mita */ 9a995c792SAkinobu Mita 10a995c792SAkinobu Mita #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 11a995c792SAkinobu Mita 12a995c792SAkinobu Mita #include <asm/div64.h> 13a995c792SAkinobu Mita #include <linux/init.h> 14a995c792SAkinobu Mita #include <linux/module.h> 15a995c792SAkinobu Mita #include <linux/moduleparam.h> 16a995c792SAkinobu Mita #include <linux/err.h> 17a995c792SAkinobu Mita #include <linux/mtd/mtd.h> 18a995c792SAkinobu Mita #include <linux/slab.h> 19a995c792SAkinobu Mita #include <linux/sched.h> 20a995c792SAkinobu Mita #include <linux/random.h> 21a995c792SAkinobu Mita 224bf527aaSAkinobu Mita #include "mtd_test.h" 234bf527aaSAkinobu Mita 24a995c792SAkinobu Mita static int dev = -EINVAL; 25afc0ea1bSRoger Quadros static int bitflip_limit; 26a995c792SAkinobu Mita module_param(dev, int, S_IRUGO); 27a995c792SAkinobu Mita MODULE_PARM_DESC(dev, "MTD device number to use"); 28afc0ea1bSRoger Quadros module_param(bitflip_limit, int, S_IRUGO); 29afc0ea1bSRoger Quadros MODULE_PARM_DESC(bitflip_limit, "Max. allowed bitflips per page"); 30a995c792SAkinobu Mita 31a995c792SAkinobu Mita static struct mtd_info *mtd; 32a995c792SAkinobu Mita static unsigned char *readbuf; 33a995c792SAkinobu Mita static unsigned char *writebuf; 34a995c792SAkinobu Mita static unsigned char *bbt; 35a995c792SAkinobu Mita 36a995c792SAkinobu Mita static int ebcnt; 37a995c792SAkinobu Mita static int pgcnt; 38a995c792SAkinobu Mita static int errcnt; 39a995c792SAkinobu Mita static int use_offset; 40a995c792SAkinobu Mita static int use_len; 41a995c792SAkinobu Mita static int use_len_max; 42a995c792SAkinobu Mita static int vary_offset; 43a995c792SAkinobu Mita static struct rnd_state rnd_state; 44a995c792SAkinobu Mita 45a995c792SAkinobu Mita static void do_vary_offset(void) 46a995c792SAkinobu Mita { 47a995c792SAkinobu Mita use_len -= 1; 48a995c792SAkinobu Mita if (use_len < 1) { 49a995c792SAkinobu Mita use_offset += 1; 50a995c792SAkinobu Mita if (use_offset >= use_len_max) 51a995c792SAkinobu Mita use_offset = 0; 52a995c792SAkinobu Mita use_len = use_len_max - use_offset; 53a995c792SAkinobu Mita } 54a995c792SAkinobu Mita } 55a995c792SAkinobu Mita 56a995c792SAkinobu Mita static int write_eraseblock(int ebnum) 57a995c792SAkinobu Mita { 58a995c792SAkinobu Mita int i; 59a995c792SAkinobu Mita struct mtd_oob_ops ops; 60a995c792SAkinobu Mita int err = 0; 61b9da8baeSBrian Norris loff_t addr = (loff_t)ebnum * mtd->erasesize; 62a995c792SAkinobu Mita 63be54f8f1SAkinobu Mita prandom_bytes_state(&rnd_state, writebuf, use_len_max * pgcnt); 64a995c792SAkinobu Mita for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) { 65a995c792SAkinobu Mita ops.mode = MTD_OPS_AUTO_OOB; 66a995c792SAkinobu Mita ops.len = 0; 67a995c792SAkinobu Mita ops.retlen = 0; 68a995c792SAkinobu Mita ops.ooblen = use_len; 69a995c792SAkinobu Mita ops.oobretlen = 0; 70a995c792SAkinobu Mita ops.ooboffs = use_offset; 71a995c792SAkinobu Mita ops.datbuf = NULL; 72be54f8f1SAkinobu Mita ops.oobbuf = writebuf + (use_len_max * i) + use_offset; 73a995c792SAkinobu Mita err = mtd_write_oob(mtd, addr, &ops); 74a995c792SAkinobu Mita if (err || ops.oobretlen != use_len) { 75a995c792SAkinobu Mita pr_err("error: writeoob failed at %#llx\n", 76a995c792SAkinobu Mita (long long)addr); 77a995c792SAkinobu Mita pr_err("error: use_len %d, use_offset %d\n", 78a995c792SAkinobu Mita use_len, use_offset); 79a995c792SAkinobu Mita errcnt += 1; 80a995c792SAkinobu Mita return err ? err : -1; 81a995c792SAkinobu Mita } 82a995c792SAkinobu Mita if (vary_offset) 83a995c792SAkinobu Mita do_vary_offset(); 84a995c792SAkinobu Mita } 85a995c792SAkinobu Mita 86a995c792SAkinobu Mita return err; 87a995c792SAkinobu Mita } 88a995c792SAkinobu Mita 89a995c792SAkinobu Mita static int write_whole_device(void) 90a995c792SAkinobu Mita { 91a995c792SAkinobu Mita int err; 92a995c792SAkinobu Mita unsigned int i; 93a995c792SAkinobu Mita 94a995c792SAkinobu Mita pr_info("writing OOBs of whole device\n"); 95a995c792SAkinobu Mita for (i = 0; i < ebcnt; ++i) { 96a995c792SAkinobu Mita if (bbt[i]) 97a995c792SAkinobu Mita continue; 98a995c792SAkinobu Mita err = write_eraseblock(i); 99a995c792SAkinobu Mita if (err) 100a995c792SAkinobu Mita return err; 101a995c792SAkinobu Mita if (i % 256 == 0) 102a995c792SAkinobu Mita pr_info("written up to eraseblock %u\n", i); 1032a6a28e7SRichard Weinberger 1042a6a28e7SRichard Weinberger err = mtdtest_relax(); 1052a6a28e7SRichard Weinberger if (err) 1062a6a28e7SRichard Weinberger return err; 107a995c792SAkinobu Mita } 108a995c792SAkinobu Mita pr_info("written %u eraseblocks\n", i); 109a995c792SAkinobu Mita return 0; 110a995c792SAkinobu Mita } 111a995c792SAkinobu Mita 112afc0ea1bSRoger Quadros /* 113afc0ea1bSRoger Quadros * Display the address, offset and data bytes at comparison failure. 114afc0ea1bSRoger Quadros * Return number of bitflips encountered. 115afc0ea1bSRoger Quadros */ 116718e38b4SRoger Quadros static size_t memcmpshowoffset(loff_t addr, loff_t offset, const void *cs, 117718e38b4SRoger Quadros const void *ct, size_t count) 1185a66088bSRoger Quadros { 1195a66088bSRoger Quadros const unsigned char *su1, *su2; 1205a66088bSRoger Quadros int res; 1215a66088bSRoger Quadros size_t i = 0; 122afc0ea1bSRoger Quadros size_t bitflips = 0; 1235a66088bSRoger Quadros 1245a66088bSRoger Quadros for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--, i++) { 1255a66088bSRoger Quadros res = *su1 ^ *su2; 1265a66088bSRoger Quadros if (res) { 127718e38b4SRoger Quadros pr_info("error @addr[0x%lx:0x%lx] 0x%x -> 0x%x diff 0x%x\n", 128718e38b4SRoger Quadros (unsigned long)addr, (unsigned long)offset + i, 129718e38b4SRoger Quadros *su1, *su2, res); 130afc0ea1bSRoger Quadros bitflips += hweight8(res); 1315a66088bSRoger Quadros } 1325a66088bSRoger Quadros } 1335a66088bSRoger Quadros 134afc0ea1bSRoger Quadros return bitflips; 1355a66088bSRoger Quadros } 1365a66088bSRoger Quadros 137718e38b4SRoger Quadros #define memcmpshow(addr, cs, ct, count) memcmpshowoffset((addr), 0, (cs), (ct),\ 138718e38b4SRoger Quadros (count)) 139718e38b4SRoger Quadros 140d2b51c80SRoger Quadros /* 141d2b51c80SRoger Quadros * Compare with 0xff and show the address, offset and data bytes at 142d2b51c80SRoger Quadros * comparison failure. Return number of bitflips encountered. 143d2b51c80SRoger Quadros */ 144d2b51c80SRoger Quadros static size_t memffshow(loff_t addr, loff_t offset, const void *cs, 145d2b51c80SRoger Quadros size_t count) 146d2b51c80SRoger Quadros { 147d2b51c80SRoger Quadros const unsigned char *su1; 148d2b51c80SRoger Quadros int res; 149d2b51c80SRoger Quadros size_t i = 0; 150d2b51c80SRoger Quadros size_t bitflips = 0; 151d2b51c80SRoger Quadros 152d2b51c80SRoger Quadros for (su1 = cs; 0 < count; ++su1, count--, i++) { 153d2b51c80SRoger Quadros res = *su1 ^ 0xff; 154d2b51c80SRoger Quadros if (res) { 155d2b51c80SRoger Quadros pr_info("error @addr[0x%lx:0x%lx] 0x%x -> 0xff diff 0x%x\n", 156d2b51c80SRoger Quadros (unsigned long)addr, (unsigned long)offset + i, 157d2b51c80SRoger Quadros *su1, res); 158d2b51c80SRoger Quadros bitflips += hweight8(res); 159d2b51c80SRoger Quadros } 160d2b51c80SRoger Quadros } 161d2b51c80SRoger Quadros 162d2b51c80SRoger Quadros return bitflips; 163d2b51c80SRoger Quadros } 164d2b51c80SRoger Quadros 165a995c792SAkinobu Mita static int verify_eraseblock(int ebnum) 166a995c792SAkinobu Mita { 167a995c792SAkinobu Mita int i; 168a995c792SAkinobu Mita struct mtd_oob_ops ops; 169a995c792SAkinobu Mita int err = 0; 1701001ff7aSBrian Norris loff_t addr = (loff_t)ebnum * mtd->erasesize; 171afc0ea1bSRoger Quadros size_t bitflips; 172a995c792SAkinobu Mita 173be54f8f1SAkinobu Mita prandom_bytes_state(&rnd_state, writebuf, use_len_max * pgcnt); 174a995c792SAkinobu Mita for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) { 175a995c792SAkinobu Mita ops.mode = MTD_OPS_AUTO_OOB; 176a995c792SAkinobu Mita ops.len = 0; 177a995c792SAkinobu Mita ops.retlen = 0; 178a995c792SAkinobu Mita ops.ooblen = use_len; 179a995c792SAkinobu Mita ops.oobretlen = 0; 180a995c792SAkinobu Mita ops.ooboffs = use_offset; 181a995c792SAkinobu Mita ops.datbuf = NULL; 182a995c792SAkinobu Mita ops.oobbuf = readbuf; 183a995c792SAkinobu Mita err = mtd_read_oob(mtd, addr, &ops); 18412663b44SMiquel Raynal if (mtd_is_bitflip(err)) 18512663b44SMiquel Raynal err = 0; 18612663b44SMiquel Raynal 187a995c792SAkinobu Mita if (err || ops.oobretlen != use_len) { 188a995c792SAkinobu Mita pr_err("error: readoob failed at %#llx\n", 189a995c792SAkinobu Mita (long long)addr); 190a995c792SAkinobu Mita errcnt += 1; 191a995c792SAkinobu Mita return err ? err : -1; 192a995c792SAkinobu Mita } 193afc0ea1bSRoger Quadros 194afc0ea1bSRoger Quadros bitflips = memcmpshow(addr, readbuf, 1955a66088bSRoger Quadros writebuf + (use_len_max * i) + use_offset, 196afc0ea1bSRoger Quadros use_len); 197afc0ea1bSRoger Quadros if (bitflips > bitflip_limit) { 198a995c792SAkinobu Mita pr_err("error: verify failed at %#llx\n", 199a995c792SAkinobu Mita (long long)addr); 200a995c792SAkinobu Mita errcnt += 1; 201a995c792SAkinobu Mita if (errcnt > 1000) { 202a995c792SAkinobu Mita pr_err("error: too many errors\n"); 203a995c792SAkinobu Mita return -1; 204a995c792SAkinobu Mita } 205afc0ea1bSRoger Quadros } else if (bitflips) { 206afc0ea1bSRoger Quadros pr_info("ignoring error as within bitflip_limit\n"); 207a995c792SAkinobu Mita } 208afc0ea1bSRoger Quadros 209f5b8aa78SBoris BREZILLON if (use_offset != 0 || use_len < mtd->oobavail) { 210a995c792SAkinobu Mita int k; 211a995c792SAkinobu Mita 212a995c792SAkinobu Mita ops.mode = MTD_OPS_AUTO_OOB; 213a995c792SAkinobu Mita ops.len = 0; 214a995c792SAkinobu Mita ops.retlen = 0; 215f5b8aa78SBoris BREZILLON ops.ooblen = mtd->oobavail; 216a995c792SAkinobu Mita ops.oobretlen = 0; 217a995c792SAkinobu Mita ops.ooboffs = 0; 218a995c792SAkinobu Mita ops.datbuf = NULL; 219a995c792SAkinobu Mita ops.oobbuf = readbuf; 220a995c792SAkinobu Mita err = mtd_read_oob(mtd, addr, &ops); 22112663b44SMiquel Raynal if (mtd_is_bitflip(err)) 22212663b44SMiquel Raynal err = 0; 22312663b44SMiquel Raynal 224f5b8aa78SBoris BREZILLON if (err || ops.oobretlen != mtd->oobavail) { 225a995c792SAkinobu Mita pr_err("error: readoob failed at %#llx\n", 226a995c792SAkinobu Mita (long long)addr); 227a995c792SAkinobu Mita errcnt += 1; 228a995c792SAkinobu Mita return err ? err : -1; 229a995c792SAkinobu Mita } 230718e38b4SRoger Quadros bitflips = memcmpshowoffset(addr, use_offset, 231718e38b4SRoger Quadros readbuf + use_offset, 232be54f8f1SAkinobu Mita writebuf + (use_len_max * i) + use_offset, 233afc0ea1bSRoger Quadros use_len); 234d2b51c80SRoger Quadros 235d2b51c80SRoger Quadros /* verify pre-offset area for 0xff */ 236d2b51c80SRoger Quadros bitflips += memffshow(addr, 0, readbuf, use_offset); 237d2b51c80SRoger Quadros 238d2b51c80SRoger Quadros /* verify post-(use_offset + use_len) area for 0xff */ 239d2b51c80SRoger Quadros k = use_offset + use_len; 240d2b51c80SRoger Quadros bitflips += memffshow(addr, k, readbuf + k, 241f5b8aa78SBoris BREZILLON mtd->oobavail - k); 242d2b51c80SRoger Quadros 243afc0ea1bSRoger Quadros if (bitflips > bitflip_limit) { 244a995c792SAkinobu Mita pr_err("error: verify failed at %#llx\n", 245a995c792SAkinobu Mita (long long)addr); 246a995c792SAkinobu Mita errcnt += 1; 247a995c792SAkinobu Mita if (errcnt > 1000) { 248a995c792SAkinobu Mita pr_err("error: too many errors\n"); 249a995c792SAkinobu Mita return -1; 250a995c792SAkinobu Mita } 251afc0ea1bSRoger Quadros } else if (bitflips) { 252d2b51c80SRoger Quadros pr_info("ignoring errors as within bitflip limit\n"); 253a995c792SAkinobu Mita } 254a995c792SAkinobu Mita } 255a995c792SAkinobu Mita if (vary_offset) 256a995c792SAkinobu Mita do_vary_offset(); 257a995c792SAkinobu Mita } 258a995c792SAkinobu Mita return err; 259a995c792SAkinobu Mita } 260a995c792SAkinobu Mita 261a995c792SAkinobu Mita static int verify_eraseblock_in_one_go(int ebnum) 262a995c792SAkinobu Mita { 263a995c792SAkinobu Mita struct mtd_oob_ops ops; 264a995c792SAkinobu Mita int err = 0; 2651001ff7aSBrian Norris loff_t addr = (loff_t)ebnum * mtd->erasesize; 266f5b8aa78SBoris BREZILLON size_t len = mtd->oobavail * pgcnt; 267f5b8aa78SBoris BREZILLON size_t oobavail = mtd->oobavail; 268afc0ea1bSRoger Quadros size_t bitflips; 269afc0ea1bSRoger Quadros int i; 270a995c792SAkinobu Mita 271a995c792SAkinobu Mita prandom_bytes_state(&rnd_state, writebuf, len); 272a995c792SAkinobu Mita ops.mode = MTD_OPS_AUTO_OOB; 273a995c792SAkinobu Mita ops.len = 0; 274a995c792SAkinobu Mita ops.retlen = 0; 275a995c792SAkinobu Mita ops.ooblen = len; 276a995c792SAkinobu Mita ops.oobretlen = 0; 277a995c792SAkinobu Mita ops.ooboffs = 0; 278a995c792SAkinobu Mita ops.datbuf = NULL; 279a995c792SAkinobu Mita ops.oobbuf = readbuf; 280afc0ea1bSRoger Quadros 281afc0ea1bSRoger Quadros /* read entire block's OOB at one go */ 282a995c792SAkinobu Mita err = mtd_read_oob(mtd, addr, &ops); 28312663b44SMiquel Raynal if (mtd_is_bitflip(err)) 28412663b44SMiquel Raynal err = 0; 28512663b44SMiquel Raynal 286a995c792SAkinobu Mita if (err || ops.oobretlen != len) { 287a995c792SAkinobu Mita pr_err("error: readoob failed at %#llx\n", 288a995c792SAkinobu Mita (long long)addr); 289a995c792SAkinobu Mita errcnt += 1; 290a995c792SAkinobu Mita return err ? err : -1; 291a995c792SAkinobu Mita } 292afc0ea1bSRoger Quadros 293afc0ea1bSRoger Quadros /* verify one page OOB at a time for bitflip per page limit check */ 294afc0ea1bSRoger Quadros for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) { 295afc0ea1bSRoger Quadros bitflips = memcmpshow(addr, readbuf + (i * oobavail), 296afc0ea1bSRoger Quadros writebuf + (i * oobavail), oobavail); 297afc0ea1bSRoger Quadros if (bitflips > bitflip_limit) { 298a995c792SAkinobu Mita pr_err("error: verify failed at %#llx\n", 299a995c792SAkinobu Mita (long long)addr); 300a995c792SAkinobu Mita errcnt += 1; 301a995c792SAkinobu Mita if (errcnt > 1000) { 302a995c792SAkinobu Mita pr_err("error: too many errors\n"); 303a995c792SAkinobu Mita return -1; 304a995c792SAkinobu Mita } 305afc0ea1bSRoger Quadros } else if (bitflips) { 306afc0ea1bSRoger Quadros pr_info("ignoring error as within bitflip_limit\n"); 307afc0ea1bSRoger Quadros } 308a995c792SAkinobu Mita } 309a995c792SAkinobu Mita 310a995c792SAkinobu Mita return err; 311a995c792SAkinobu Mita } 312a995c792SAkinobu Mita 313a995c792SAkinobu Mita static int verify_all_eraseblocks(void) 314a995c792SAkinobu Mita { 315a995c792SAkinobu Mita int err; 316a995c792SAkinobu Mita unsigned int i; 317a995c792SAkinobu Mita 318a995c792SAkinobu Mita pr_info("verifying all eraseblocks\n"); 319a995c792SAkinobu Mita for (i = 0; i < ebcnt; ++i) { 320a995c792SAkinobu Mita if (bbt[i]) 321a995c792SAkinobu Mita continue; 322a995c792SAkinobu Mita err = verify_eraseblock(i); 323a995c792SAkinobu Mita if (err) 324a995c792SAkinobu Mita return err; 325a995c792SAkinobu Mita if (i % 256 == 0) 326a995c792SAkinobu Mita pr_info("verified up to eraseblock %u\n", i); 3272a6a28e7SRichard Weinberger 3282a6a28e7SRichard Weinberger err = mtdtest_relax(); 3292a6a28e7SRichard Weinberger if (err) 3302a6a28e7SRichard Weinberger return err; 331a995c792SAkinobu Mita } 332a995c792SAkinobu Mita pr_info("verified %u eraseblocks\n", i); 333a995c792SAkinobu Mita return 0; 334a995c792SAkinobu Mita } 335a995c792SAkinobu Mita 336a995c792SAkinobu Mita static int __init mtd_oobtest_init(void) 337a995c792SAkinobu Mita { 338a995c792SAkinobu Mita int err = 0; 339a995c792SAkinobu Mita unsigned int i; 340a995c792SAkinobu Mita uint64_t tmp; 341a995c792SAkinobu Mita struct mtd_oob_ops ops; 342a995c792SAkinobu Mita loff_t addr = 0, addr0; 343a995c792SAkinobu Mita 344a995c792SAkinobu Mita printk(KERN_INFO "\n"); 345a995c792SAkinobu Mita printk(KERN_INFO "=================================================\n"); 346a995c792SAkinobu Mita 347a995c792SAkinobu Mita if (dev < 0) { 348a995c792SAkinobu Mita pr_info("Please specify a valid mtd-device via module parameter\n"); 349a995c792SAkinobu Mita pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n"); 350a995c792SAkinobu Mita return -EINVAL; 351a995c792SAkinobu Mita } 352a995c792SAkinobu Mita 353a995c792SAkinobu Mita pr_info("MTD device: %d\n", dev); 354a995c792SAkinobu Mita 355a995c792SAkinobu Mita mtd = get_mtd_device(NULL, dev); 356a995c792SAkinobu Mita if (IS_ERR(mtd)) { 357a995c792SAkinobu Mita err = PTR_ERR(mtd); 358a995c792SAkinobu Mita pr_err("error: cannot get MTD device\n"); 359a995c792SAkinobu Mita return err; 360a995c792SAkinobu Mita } 361a995c792SAkinobu Mita 362818b9739SHuang Shijie if (!mtd_type_is_nand(mtd)) { 363a995c792SAkinobu Mita pr_info("this test requires NAND flash\n"); 364a995c792SAkinobu Mita goto out; 365a995c792SAkinobu Mita } 366a995c792SAkinobu Mita 367a995c792SAkinobu Mita tmp = mtd->size; 368a995c792SAkinobu Mita do_div(tmp, mtd->erasesize); 369a995c792SAkinobu Mita ebcnt = tmp; 370a995c792SAkinobu Mita pgcnt = mtd->erasesize / mtd->writesize; 371a995c792SAkinobu Mita 372a995c792SAkinobu Mita pr_info("MTD device size %llu, eraseblock size %u, " 373a995c792SAkinobu Mita "page size %u, count of eraseblocks %u, pages per " 374a995c792SAkinobu Mita "eraseblock %u, OOB size %u\n", 375a995c792SAkinobu Mita (unsigned long long)mtd->size, mtd->erasesize, 376a995c792SAkinobu Mita mtd->writesize, ebcnt, pgcnt, mtd->oobsize); 377a995c792SAkinobu Mita 378a995c792SAkinobu Mita err = -ENOMEM; 379a995c792SAkinobu Mita readbuf = kmalloc(mtd->erasesize, GFP_KERNEL); 380a995c792SAkinobu Mita if (!readbuf) 381a995c792SAkinobu Mita goto out; 382a995c792SAkinobu Mita writebuf = kmalloc(mtd->erasesize, GFP_KERNEL); 383a995c792SAkinobu Mita if (!writebuf) 384a995c792SAkinobu Mita goto out; 3854bf527aaSAkinobu Mita bbt = kzalloc(ebcnt, GFP_KERNEL); 3864bf527aaSAkinobu Mita if (!bbt) 3874bf527aaSAkinobu Mita goto out; 388a995c792SAkinobu Mita 3894bf527aaSAkinobu Mita err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt); 390a995c792SAkinobu Mita if (err) 391a995c792SAkinobu Mita goto out; 392a995c792SAkinobu Mita 393a995c792SAkinobu Mita use_offset = 0; 394f5b8aa78SBoris BREZILLON use_len = mtd->oobavail; 395f5b8aa78SBoris BREZILLON use_len_max = mtd->oobavail; 396a995c792SAkinobu Mita vary_offset = 0; 397a995c792SAkinobu Mita 398a995c792SAkinobu Mita /* First test: write all OOB, read it back and verify */ 399a995c792SAkinobu Mita pr_info("test 1 of 5\n"); 400a995c792SAkinobu Mita 4014bf527aaSAkinobu Mita err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); 402a995c792SAkinobu Mita if (err) 403a995c792SAkinobu Mita goto out; 404a995c792SAkinobu Mita 405a995c792SAkinobu Mita prandom_seed_state(&rnd_state, 1); 406a995c792SAkinobu Mita err = write_whole_device(); 407a995c792SAkinobu Mita if (err) 408a995c792SAkinobu Mita goto out; 409a995c792SAkinobu Mita 410a995c792SAkinobu Mita prandom_seed_state(&rnd_state, 1); 411a995c792SAkinobu Mita err = verify_all_eraseblocks(); 412a995c792SAkinobu Mita if (err) 413a995c792SAkinobu Mita goto out; 414a995c792SAkinobu Mita 415a995c792SAkinobu Mita /* 416a995c792SAkinobu Mita * Second test: write all OOB, a block at a time, read it back and 417a995c792SAkinobu Mita * verify. 418a995c792SAkinobu Mita */ 419a995c792SAkinobu Mita pr_info("test 2 of 5\n"); 420a995c792SAkinobu Mita 4214bf527aaSAkinobu Mita err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); 422a995c792SAkinobu Mita if (err) 423a995c792SAkinobu Mita goto out; 424a995c792SAkinobu Mita 425a995c792SAkinobu Mita prandom_seed_state(&rnd_state, 3); 426a995c792SAkinobu Mita err = write_whole_device(); 427a995c792SAkinobu Mita if (err) 428a995c792SAkinobu Mita goto out; 429a995c792SAkinobu Mita 430a995c792SAkinobu Mita /* Check all eraseblocks */ 431a995c792SAkinobu Mita prandom_seed_state(&rnd_state, 3); 432a995c792SAkinobu Mita pr_info("verifying all eraseblocks\n"); 433a995c792SAkinobu Mita for (i = 0; i < ebcnt; ++i) { 434a995c792SAkinobu Mita if (bbt[i]) 435a995c792SAkinobu Mita continue; 436a995c792SAkinobu Mita err = verify_eraseblock_in_one_go(i); 437a995c792SAkinobu Mita if (err) 438a995c792SAkinobu Mita goto out; 439a995c792SAkinobu Mita if (i % 256 == 0) 440a995c792SAkinobu Mita pr_info("verified up to eraseblock %u\n", i); 4412a6a28e7SRichard Weinberger 4422a6a28e7SRichard Weinberger err = mtdtest_relax(); 4432a6a28e7SRichard Weinberger if (err) 4442a6a28e7SRichard Weinberger goto out; 445a995c792SAkinobu Mita } 446a995c792SAkinobu Mita pr_info("verified %u eraseblocks\n", i); 447a995c792SAkinobu Mita 448a995c792SAkinobu Mita /* 449a995c792SAkinobu Mita * Third test: write OOB at varying offsets and lengths, read it back 450a995c792SAkinobu Mita * and verify. 451a995c792SAkinobu Mita */ 452a995c792SAkinobu Mita pr_info("test 3 of 5\n"); 453a995c792SAkinobu Mita 4544bf527aaSAkinobu Mita err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); 455a995c792SAkinobu Mita if (err) 456a995c792SAkinobu Mita goto out; 457a995c792SAkinobu Mita 458a995c792SAkinobu Mita /* Write all eraseblocks */ 459a995c792SAkinobu Mita use_offset = 0; 460f5b8aa78SBoris BREZILLON use_len = mtd->oobavail; 461f5b8aa78SBoris BREZILLON use_len_max = mtd->oobavail; 462a995c792SAkinobu Mita vary_offset = 1; 463a995c792SAkinobu Mita prandom_seed_state(&rnd_state, 5); 464a995c792SAkinobu Mita 465a995c792SAkinobu Mita err = write_whole_device(); 466a995c792SAkinobu Mita if (err) 467a995c792SAkinobu Mita goto out; 468a995c792SAkinobu Mita 469a995c792SAkinobu Mita /* Check all eraseblocks */ 470a995c792SAkinobu Mita use_offset = 0; 471f5b8aa78SBoris BREZILLON use_len = mtd->oobavail; 472f5b8aa78SBoris BREZILLON use_len_max = mtd->oobavail; 473a995c792SAkinobu Mita vary_offset = 1; 474a995c792SAkinobu Mita prandom_seed_state(&rnd_state, 5); 475a995c792SAkinobu Mita err = verify_all_eraseblocks(); 476a995c792SAkinobu Mita if (err) 477a995c792SAkinobu Mita goto out; 478a995c792SAkinobu Mita 479a995c792SAkinobu Mita use_offset = 0; 480f5b8aa78SBoris BREZILLON use_len = mtd->oobavail; 481f5b8aa78SBoris BREZILLON use_len_max = mtd->oobavail; 482a995c792SAkinobu Mita vary_offset = 0; 483a995c792SAkinobu Mita 484a995c792SAkinobu Mita /* Fourth test: try to write off end of device */ 485a995c792SAkinobu Mita pr_info("test 4 of 5\n"); 486a995c792SAkinobu Mita 4874bf527aaSAkinobu Mita err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); 488a995c792SAkinobu Mita if (err) 489a995c792SAkinobu Mita goto out; 490a995c792SAkinobu Mita 491a995c792SAkinobu Mita addr0 = 0; 492a995c792SAkinobu Mita for (i = 0; i < ebcnt && bbt[i]; ++i) 493a995c792SAkinobu Mita addr0 += mtd->erasesize; 494a995c792SAkinobu Mita 495a995c792SAkinobu Mita /* Attempt to write off end of OOB */ 496a995c792SAkinobu Mita ops.mode = MTD_OPS_AUTO_OOB; 497a995c792SAkinobu Mita ops.len = 0; 498a995c792SAkinobu Mita ops.retlen = 0; 499a995c792SAkinobu Mita ops.ooblen = 1; 500a995c792SAkinobu Mita ops.oobretlen = 0; 501f5b8aa78SBoris BREZILLON ops.ooboffs = mtd->oobavail; 502a995c792SAkinobu Mita ops.datbuf = NULL; 503a995c792SAkinobu Mita ops.oobbuf = writebuf; 504a995c792SAkinobu Mita pr_info("attempting to start write past end of OOB\n"); 505a995c792SAkinobu Mita pr_info("an error is expected...\n"); 506a995c792SAkinobu Mita err = mtd_write_oob(mtd, addr0, &ops); 507a995c792SAkinobu Mita if (err) { 508a995c792SAkinobu Mita pr_info("error occurred as expected\n"); 509a995c792SAkinobu Mita err = 0; 510a995c792SAkinobu Mita } else { 511a995c792SAkinobu Mita pr_err("error: can write past end of OOB\n"); 512a995c792SAkinobu Mita errcnt += 1; 513a995c792SAkinobu Mita } 514a995c792SAkinobu Mita 515a995c792SAkinobu Mita /* Attempt to read off end of OOB */ 516a995c792SAkinobu Mita ops.mode = MTD_OPS_AUTO_OOB; 517a995c792SAkinobu Mita ops.len = 0; 518a995c792SAkinobu Mita ops.retlen = 0; 519a995c792SAkinobu Mita ops.ooblen = 1; 520a995c792SAkinobu Mita ops.oobretlen = 0; 521f5b8aa78SBoris BREZILLON ops.ooboffs = mtd->oobavail; 522a995c792SAkinobu Mita ops.datbuf = NULL; 523a995c792SAkinobu Mita ops.oobbuf = readbuf; 524a995c792SAkinobu Mita pr_info("attempting to start read past end of OOB\n"); 525a995c792SAkinobu Mita pr_info("an error is expected...\n"); 526a995c792SAkinobu Mita err = mtd_read_oob(mtd, addr0, &ops); 52712663b44SMiquel Raynal if (mtd_is_bitflip(err)) 52812663b44SMiquel Raynal err = 0; 52912663b44SMiquel Raynal 530a995c792SAkinobu Mita if (err) { 531a995c792SAkinobu Mita pr_info("error occurred as expected\n"); 532a995c792SAkinobu Mita err = 0; 533a995c792SAkinobu Mita } else { 534a995c792SAkinobu Mita pr_err("error: can read past end of OOB\n"); 535a995c792SAkinobu Mita errcnt += 1; 536a995c792SAkinobu Mita } 537a995c792SAkinobu Mita 538a995c792SAkinobu Mita if (bbt[ebcnt - 1]) 539a995c792SAkinobu Mita pr_info("skipping end of device tests because last " 540a995c792SAkinobu Mita "block is bad\n"); 541a995c792SAkinobu Mita else { 542a995c792SAkinobu Mita /* Attempt to write off end of device */ 543a995c792SAkinobu Mita ops.mode = MTD_OPS_AUTO_OOB; 544a995c792SAkinobu Mita ops.len = 0; 545a995c792SAkinobu Mita ops.retlen = 0; 546f5b8aa78SBoris BREZILLON ops.ooblen = mtd->oobavail + 1; 547a995c792SAkinobu Mita ops.oobretlen = 0; 548a995c792SAkinobu Mita ops.ooboffs = 0; 549a995c792SAkinobu Mita ops.datbuf = NULL; 550a995c792SAkinobu Mita ops.oobbuf = writebuf; 551a995c792SAkinobu Mita pr_info("attempting to write past end of device\n"); 552a995c792SAkinobu Mita pr_info("an error is expected...\n"); 553a995c792SAkinobu Mita err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops); 554a995c792SAkinobu Mita if (err) { 555a995c792SAkinobu Mita pr_info("error occurred as expected\n"); 556a995c792SAkinobu Mita err = 0; 557a995c792SAkinobu Mita } else { 558a995c792SAkinobu Mita pr_err("error: wrote past end of device\n"); 559a995c792SAkinobu Mita errcnt += 1; 560a995c792SAkinobu Mita } 561a995c792SAkinobu Mita 562a995c792SAkinobu Mita /* Attempt to read off end of device */ 563a995c792SAkinobu Mita ops.mode = MTD_OPS_AUTO_OOB; 564a995c792SAkinobu Mita ops.len = 0; 565a995c792SAkinobu Mita ops.retlen = 0; 566f5b8aa78SBoris BREZILLON ops.ooblen = mtd->oobavail + 1; 567a995c792SAkinobu Mita ops.oobretlen = 0; 568a995c792SAkinobu Mita ops.ooboffs = 0; 569a995c792SAkinobu Mita ops.datbuf = NULL; 570a995c792SAkinobu Mita ops.oobbuf = readbuf; 571a995c792SAkinobu Mita pr_info("attempting to read past end of device\n"); 572a995c792SAkinobu Mita pr_info("an error is expected...\n"); 573a995c792SAkinobu Mita err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops); 57412663b44SMiquel Raynal if (mtd_is_bitflip(err)) 57512663b44SMiquel Raynal err = 0; 57612663b44SMiquel Raynal 577a995c792SAkinobu Mita if (err) { 578a995c792SAkinobu Mita pr_info("error occurred as expected\n"); 579a995c792SAkinobu Mita err = 0; 580a995c792SAkinobu Mita } else { 581a995c792SAkinobu Mita pr_err("error: read past end of device\n"); 582a995c792SAkinobu Mita errcnt += 1; 583a995c792SAkinobu Mita } 584a995c792SAkinobu Mita 5854bf527aaSAkinobu Mita err = mtdtest_erase_eraseblock(mtd, ebcnt - 1); 586a995c792SAkinobu Mita if (err) 587a995c792SAkinobu Mita goto out; 588a995c792SAkinobu Mita 589a995c792SAkinobu Mita /* Attempt to write off end of device */ 590a995c792SAkinobu Mita ops.mode = MTD_OPS_AUTO_OOB; 591a995c792SAkinobu Mita ops.len = 0; 592a995c792SAkinobu Mita ops.retlen = 0; 593f5b8aa78SBoris BREZILLON ops.ooblen = mtd->oobavail; 594a995c792SAkinobu Mita ops.oobretlen = 0; 595a995c792SAkinobu Mita ops.ooboffs = 1; 596a995c792SAkinobu Mita ops.datbuf = NULL; 597a995c792SAkinobu Mita ops.oobbuf = writebuf; 598a995c792SAkinobu Mita pr_info("attempting to write past end of device\n"); 599a995c792SAkinobu Mita pr_info("an error is expected...\n"); 600a995c792SAkinobu Mita err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops); 601a995c792SAkinobu Mita if (err) { 602a995c792SAkinobu Mita pr_info("error occurred as expected\n"); 603a995c792SAkinobu Mita err = 0; 604a995c792SAkinobu Mita } else { 605a995c792SAkinobu Mita pr_err("error: wrote past end of device\n"); 606a995c792SAkinobu Mita errcnt += 1; 607a995c792SAkinobu Mita } 608a995c792SAkinobu Mita 609a995c792SAkinobu Mita /* Attempt to read off end of device */ 610a995c792SAkinobu Mita ops.mode = MTD_OPS_AUTO_OOB; 611a995c792SAkinobu Mita ops.len = 0; 612a995c792SAkinobu Mita ops.retlen = 0; 613f5b8aa78SBoris BREZILLON ops.ooblen = mtd->oobavail; 614a995c792SAkinobu Mita ops.oobretlen = 0; 615a995c792SAkinobu Mita ops.ooboffs = 1; 616a995c792SAkinobu Mita ops.datbuf = NULL; 617a995c792SAkinobu Mita ops.oobbuf = readbuf; 618a995c792SAkinobu Mita pr_info("attempting to read past end of device\n"); 619a995c792SAkinobu Mita pr_info("an error is expected...\n"); 620a995c792SAkinobu Mita err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops); 62112663b44SMiquel Raynal if (mtd_is_bitflip(err)) 62212663b44SMiquel Raynal err = 0; 62312663b44SMiquel Raynal 624a995c792SAkinobu Mita if (err) { 625a995c792SAkinobu Mita pr_info("error occurred as expected\n"); 626a995c792SAkinobu Mita err = 0; 627a995c792SAkinobu Mita } else { 628a995c792SAkinobu Mita pr_err("error: read past end of device\n"); 629a995c792SAkinobu Mita errcnt += 1; 630a995c792SAkinobu Mita } 631a995c792SAkinobu Mita } 632a995c792SAkinobu Mita 633a995c792SAkinobu Mita /* Fifth test: write / read across block boundaries */ 634a995c792SAkinobu Mita pr_info("test 5 of 5\n"); 635a995c792SAkinobu Mita 636a995c792SAkinobu Mita /* Erase all eraseblocks */ 6374bf527aaSAkinobu Mita err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); 638a995c792SAkinobu Mita if (err) 639a995c792SAkinobu Mita goto out; 640a995c792SAkinobu Mita 641a995c792SAkinobu Mita /* Write all eraseblocks */ 642a995c792SAkinobu Mita prandom_seed_state(&rnd_state, 11); 643a995c792SAkinobu Mita pr_info("writing OOBs of whole device\n"); 644a995c792SAkinobu Mita for (i = 0; i < ebcnt - 1; ++i) { 645a995c792SAkinobu Mita int cnt = 2; 646a995c792SAkinobu Mita int pg; 647f5b8aa78SBoris BREZILLON size_t sz = mtd->oobavail; 648a995c792SAkinobu Mita if (bbt[i] || bbt[i + 1]) 649a995c792SAkinobu Mita continue; 6501001ff7aSBrian Norris addr = (loff_t)(i + 1) * mtd->erasesize - mtd->writesize; 651be54f8f1SAkinobu Mita prandom_bytes_state(&rnd_state, writebuf, sz * cnt); 652a995c792SAkinobu Mita for (pg = 0; pg < cnt; ++pg) { 653a995c792SAkinobu Mita ops.mode = MTD_OPS_AUTO_OOB; 654a995c792SAkinobu Mita ops.len = 0; 655a995c792SAkinobu Mita ops.retlen = 0; 656a995c792SAkinobu Mita ops.ooblen = sz; 657a995c792SAkinobu Mita ops.oobretlen = 0; 658a995c792SAkinobu Mita ops.ooboffs = 0; 659a995c792SAkinobu Mita ops.datbuf = NULL; 660be54f8f1SAkinobu Mita ops.oobbuf = writebuf + pg * sz; 661a995c792SAkinobu Mita err = mtd_write_oob(mtd, addr, &ops); 662a995c792SAkinobu Mita if (err) 663a995c792SAkinobu Mita goto out; 664a995c792SAkinobu Mita if (i % 256 == 0) 665a995c792SAkinobu Mita pr_info("written up to eraseblock %u\n", i); 6662a6a28e7SRichard Weinberger 6672a6a28e7SRichard Weinberger err = mtdtest_relax(); 6682a6a28e7SRichard Weinberger if (err) 6692a6a28e7SRichard Weinberger goto out; 6702a6a28e7SRichard Weinberger 671a995c792SAkinobu Mita addr += mtd->writesize; 672a995c792SAkinobu Mita } 673a995c792SAkinobu Mita } 674a995c792SAkinobu Mita pr_info("written %u eraseblocks\n", i); 675a995c792SAkinobu Mita 676a995c792SAkinobu Mita /* Check all eraseblocks */ 677a995c792SAkinobu Mita prandom_seed_state(&rnd_state, 11); 678a995c792SAkinobu Mita pr_info("verifying all eraseblocks\n"); 679a995c792SAkinobu Mita for (i = 0; i < ebcnt - 1; ++i) { 680a995c792SAkinobu Mita if (bbt[i] || bbt[i + 1]) 681a995c792SAkinobu Mita continue; 682f5b8aa78SBoris BREZILLON prandom_bytes_state(&rnd_state, writebuf, mtd->oobavail * 2); 6831001ff7aSBrian Norris addr = (loff_t)(i + 1) * mtd->erasesize - mtd->writesize; 684a995c792SAkinobu Mita ops.mode = MTD_OPS_AUTO_OOB; 685a995c792SAkinobu Mita ops.len = 0; 686a995c792SAkinobu Mita ops.retlen = 0; 687f5b8aa78SBoris BREZILLON ops.ooblen = mtd->oobavail * 2; 688a995c792SAkinobu Mita ops.oobretlen = 0; 689a995c792SAkinobu Mita ops.ooboffs = 0; 690a995c792SAkinobu Mita ops.datbuf = NULL; 691a995c792SAkinobu Mita ops.oobbuf = readbuf; 692a995c792SAkinobu Mita err = mtd_read_oob(mtd, addr, &ops); 69312663b44SMiquel Raynal if (mtd_is_bitflip(err)) 69412663b44SMiquel Raynal err = 0; 69512663b44SMiquel Raynal 696a995c792SAkinobu Mita if (err) 697a995c792SAkinobu Mita goto out; 6985a66088bSRoger Quadros if (memcmpshow(addr, readbuf, writebuf, 699f5b8aa78SBoris BREZILLON mtd->oobavail * 2)) { 700a995c792SAkinobu Mita pr_err("error: verify failed at %#llx\n", 701a995c792SAkinobu Mita (long long)addr); 702a995c792SAkinobu Mita errcnt += 1; 703a995c792SAkinobu Mita if (errcnt > 1000) { 704a995c792SAkinobu Mita pr_err("error: too many errors\n"); 705a995c792SAkinobu Mita goto out; 706a995c792SAkinobu Mita } 707a995c792SAkinobu Mita } 708a995c792SAkinobu Mita if (i % 256 == 0) 709a995c792SAkinobu Mita pr_info("verified up to eraseblock %u\n", i); 7102a6a28e7SRichard Weinberger 7112a6a28e7SRichard Weinberger err = mtdtest_relax(); 7122a6a28e7SRichard Weinberger if (err) 7132a6a28e7SRichard Weinberger goto out; 714a995c792SAkinobu Mita } 715a995c792SAkinobu Mita pr_info("verified %u eraseblocks\n", i); 716a995c792SAkinobu Mita 717a995c792SAkinobu Mita pr_info("finished with %d errors\n", errcnt); 718a995c792SAkinobu Mita out: 719a995c792SAkinobu Mita kfree(bbt); 720a995c792SAkinobu Mita kfree(writebuf); 721a995c792SAkinobu Mita kfree(readbuf); 722a995c792SAkinobu Mita put_mtd_device(mtd); 723a995c792SAkinobu Mita if (err) 724a995c792SAkinobu Mita pr_info("error %d occurred\n", err); 725a995c792SAkinobu Mita printk(KERN_INFO "=================================================\n"); 726a995c792SAkinobu Mita return err; 727a995c792SAkinobu Mita } 728a995c792SAkinobu Mita module_init(mtd_oobtest_init); 729a995c792SAkinobu Mita 730a995c792SAkinobu Mita static void __exit mtd_oobtest_exit(void) 731a995c792SAkinobu Mita { 732a995c792SAkinobu Mita return; 733a995c792SAkinobu Mita } 734a995c792SAkinobu Mita module_exit(mtd_oobtest_exit); 735a995c792SAkinobu Mita 736a995c792SAkinobu Mita MODULE_DESCRIPTION("Out-of-band test module"); 737a995c792SAkinobu Mita MODULE_AUTHOR("Adrian Hunter"); 738a995c792SAkinobu Mita MODULE_LICENSE("GPL"); 739