subpagetest.c (10373B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Copyright (C) 2006-2007 Nokia Corporation 4 * 5 * Test sub-page read and write on MTD device. 6 * Author: Adrian Hunter <ext-adrian.hunter@nokia.com> 7 */ 8 9#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 10 11#include <linux/init.h> 12#include <linux/module.h> 13#include <linux/moduleparam.h> 14#include <linux/err.h> 15#include <linux/mtd/mtd.h> 16#include <linux/slab.h> 17#include <linux/sched.h> 18#include <linux/random.h> 19 20#include "mtd_test.h" 21 22static int dev = -EINVAL; 23module_param(dev, int, S_IRUGO); 24MODULE_PARM_DESC(dev, "MTD device number to use"); 25 26static struct mtd_info *mtd; 27static unsigned char *writebuf; 28static unsigned char *readbuf; 29static unsigned char *bbt; 30 31static int subpgsize; 32static int bufsize; 33static int ebcnt; 34static int pgcnt; 35static int errcnt; 36static struct rnd_state rnd_state; 37 38static inline void clear_data(unsigned char *buf, size_t len) 39{ 40 memset(buf, 0, len); 41} 42 43static int write_eraseblock(int ebnum) 44{ 45 size_t written; 46 int err = 0; 47 loff_t addr = (loff_t)ebnum * mtd->erasesize; 48 49 prandom_bytes_state(&rnd_state, writebuf, subpgsize); 50 err = mtd_write(mtd, addr, subpgsize, &written, writebuf); 51 if (unlikely(err || written != subpgsize)) { 52 pr_err("error: write failed at %#llx\n", 53 (long long)addr); 54 if (written != subpgsize) { 55 pr_err(" write size: %#x\n", subpgsize); 56 pr_err(" written: %#zx\n", written); 57 } 58 return err ? err : -1; 59 } 60 61 addr += subpgsize; 62 63 prandom_bytes_state(&rnd_state, writebuf, subpgsize); 64 err = mtd_write(mtd, addr, subpgsize, &written, writebuf); 65 if (unlikely(err || written != subpgsize)) { 66 pr_err("error: write failed at %#llx\n", 67 (long long)addr); 68 if (written != subpgsize) { 69 pr_err(" write size: %#x\n", subpgsize); 70 pr_err(" written: %#zx\n", written); 71 } 72 return err ? err : -1; 73 } 74 75 return err; 76} 77 78static int write_eraseblock2(int ebnum) 79{ 80 size_t written; 81 int err = 0, k; 82 loff_t addr = (loff_t)ebnum * mtd->erasesize; 83 84 for (k = 1; k < 33; ++k) { 85 if (addr + (subpgsize * k) > (loff_t)(ebnum + 1) * mtd->erasesize) 86 break; 87 prandom_bytes_state(&rnd_state, writebuf, subpgsize * k); 88 err = mtd_write(mtd, addr, subpgsize * k, &written, writebuf); 89 if (unlikely(err || written != subpgsize * k)) { 90 pr_err("error: write failed at %#llx\n", 91 (long long)addr); 92 if (written != subpgsize * k) { 93 pr_err(" write size: %#x\n", 94 subpgsize * k); 95 pr_err(" written: %#08zx\n", 96 written); 97 } 98 return err ? err : -1; 99 } 100 addr += subpgsize * k; 101 } 102 103 return err; 104} 105 106static void print_subpage(unsigned char *p) 107{ 108 int i, j; 109 110 for (i = 0; i < subpgsize; ) { 111 for (j = 0; i < subpgsize && j < 32; ++i, ++j) 112 printk("%02x", *p++); 113 printk("\n"); 114 } 115} 116 117static int verify_eraseblock(int ebnum) 118{ 119 size_t read; 120 int err = 0; 121 loff_t addr = (loff_t)ebnum * mtd->erasesize; 122 123 prandom_bytes_state(&rnd_state, writebuf, subpgsize); 124 clear_data(readbuf, subpgsize); 125 err = mtd_read(mtd, addr, subpgsize, &read, readbuf); 126 if (unlikely(err || read != subpgsize)) { 127 if (mtd_is_bitflip(err) && read == subpgsize) { 128 pr_info("ECC correction at %#llx\n", 129 (long long)addr); 130 err = 0; 131 } else { 132 pr_err("error: read failed at %#llx\n", 133 (long long)addr); 134 return err ? err : -1; 135 } 136 } 137 if (unlikely(memcmp(readbuf, writebuf, subpgsize))) { 138 pr_err("error: verify failed at %#llx\n", 139 (long long)addr); 140 pr_info("------------- written----------------\n"); 141 print_subpage(writebuf); 142 pr_info("------------- read ------------------\n"); 143 print_subpage(readbuf); 144 pr_info("-------------------------------------\n"); 145 errcnt += 1; 146 } 147 148 addr += subpgsize; 149 150 prandom_bytes_state(&rnd_state, writebuf, subpgsize); 151 clear_data(readbuf, subpgsize); 152 err = mtd_read(mtd, addr, subpgsize, &read, readbuf); 153 if (unlikely(err || read != subpgsize)) { 154 if (mtd_is_bitflip(err) && read == subpgsize) { 155 pr_info("ECC correction at %#llx\n", 156 (long long)addr); 157 err = 0; 158 } else { 159 pr_err("error: read failed at %#llx\n", 160 (long long)addr); 161 return err ? err : -1; 162 } 163 } 164 if (unlikely(memcmp(readbuf, writebuf, subpgsize))) { 165 pr_info("error: verify failed at %#llx\n", 166 (long long)addr); 167 pr_info("------------- written----------------\n"); 168 print_subpage(writebuf); 169 pr_info("------------- read ------------------\n"); 170 print_subpage(readbuf); 171 pr_info("-------------------------------------\n"); 172 errcnt += 1; 173 } 174 175 return err; 176} 177 178static int verify_eraseblock2(int ebnum) 179{ 180 size_t read; 181 int err = 0, k; 182 loff_t addr = (loff_t)ebnum * mtd->erasesize; 183 184 for (k = 1; k < 33; ++k) { 185 if (addr + (subpgsize * k) > (loff_t)(ebnum + 1) * mtd->erasesize) 186 break; 187 prandom_bytes_state(&rnd_state, writebuf, subpgsize * k); 188 clear_data(readbuf, subpgsize * k); 189 err = mtd_read(mtd, addr, subpgsize * k, &read, readbuf); 190 if (unlikely(err || read != subpgsize * k)) { 191 if (mtd_is_bitflip(err) && read == subpgsize * k) { 192 pr_info("ECC correction at %#llx\n", 193 (long long)addr); 194 err = 0; 195 } else { 196 pr_err("error: read failed at " 197 "%#llx\n", (long long)addr); 198 return err ? err : -1; 199 } 200 } 201 if (unlikely(memcmp(readbuf, writebuf, subpgsize * k))) { 202 pr_err("error: verify failed at %#llx\n", 203 (long long)addr); 204 errcnt += 1; 205 } 206 addr += subpgsize * k; 207 } 208 209 return err; 210} 211 212static int verify_eraseblock_ff(int ebnum) 213{ 214 uint32_t j; 215 size_t read; 216 int err = 0; 217 loff_t addr = (loff_t)ebnum * mtd->erasesize; 218 219 memset(writebuf, 0xff, subpgsize); 220 for (j = 0; j < mtd->erasesize / subpgsize; ++j) { 221 clear_data(readbuf, subpgsize); 222 err = mtd_read(mtd, addr, subpgsize, &read, readbuf); 223 if (unlikely(err || read != subpgsize)) { 224 if (mtd_is_bitflip(err) && read == subpgsize) { 225 pr_info("ECC correction at %#llx\n", 226 (long long)addr); 227 err = 0; 228 } else { 229 pr_err("error: read failed at " 230 "%#llx\n", (long long)addr); 231 return err ? err : -1; 232 } 233 } 234 if (unlikely(memcmp(readbuf, writebuf, subpgsize))) { 235 pr_err("error: verify 0xff failed at " 236 "%#llx\n", (long long)addr); 237 errcnt += 1; 238 } 239 addr += subpgsize; 240 } 241 242 return err; 243} 244 245static int verify_all_eraseblocks_ff(void) 246{ 247 int err; 248 unsigned int i; 249 250 pr_info("verifying all eraseblocks for 0xff\n"); 251 for (i = 0; i < ebcnt; ++i) { 252 if (bbt[i]) 253 continue; 254 err = verify_eraseblock_ff(i); 255 if (err) 256 return err; 257 if (i % 256 == 0) 258 pr_info("verified up to eraseblock %u\n", i); 259 260 err = mtdtest_relax(); 261 if (err) 262 return err; 263 } 264 pr_info("verified %u eraseblocks\n", i); 265 return 0; 266} 267 268static int __init mtd_subpagetest_init(void) 269{ 270 int err = 0; 271 uint32_t i; 272 uint64_t tmp; 273 274 printk(KERN_INFO "\n"); 275 printk(KERN_INFO "=================================================\n"); 276 277 if (dev < 0) { 278 pr_info("Please specify a valid mtd-device via module parameter\n"); 279 pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n"); 280 return -EINVAL; 281 } 282 283 pr_info("MTD device: %d\n", dev); 284 285 mtd = get_mtd_device(NULL, dev); 286 if (IS_ERR(mtd)) { 287 err = PTR_ERR(mtd); 288 pr_err("error: cannot get MTD device\n"); 289 return err; 290 } 291 292 if (!mtd_type_is_nand(mtd)) { 293 pr_info("this test requires NAND flash\n"); 294 goto out; 295 } 296 297 subpgsize = mtd->writesize >> mtd->subpage_sft; 298 tmp = mtd->size; 299 do_div(tmp, mtd->erasesize); 300 ebcnt = tmp; 301 pgcnt = mtd->erasesize / mtd->writesize; 302 303 pr_info("MTD device size %llu, eraseblock size %u, " 304 "page size %u, subpage size %u, count of eraseblocks %u, " 305 "pages per eraseblock %u, OOB size %u\n", 306 (unsigned long long)mtd->size, mtd->erasesize, 307 mtd->writesize, subpgsize, ebcnt, pgcnt, mtd->oobsize); 308 309 err = -ENOMEM; 310 bufsize = subpgsize * 32; 311 writebuf = kmalloc(bufsize, GFP_KERNEL); 312 if (!writebuf) 313 goto out; 314 readbuf = kmalloc(bufsize, GFP_KERNEL); 315 if (!readbuf) 316 goto out; 317 bbt = kzalloc(ebcnt, GFP_KERNEL); 318 if (!bbt) 319 goto out; 320 321 err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt); 322 if (err) 323 goto out; 324 325 err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); 326 if (err) 327 goto out; 328 329 pr_info("writing whole device\n"); 330 prandom_seed_state(&rnd_state, 1); 331 for (i = 0; i < ebcnt; ++i) { 332 if (bbt[i]) 333 continue; 334 err = write_eraseblock(i); 335 if (unlikely(err)) 336 goto out; 337 if (i % 256 == 0) 338 pr_info("written up to eraseblock %u\n", i); 339 340 err = mtdtest_relax(); 341 if (err) 342 goto out; 343 } 344 pr_info("written %u eraseblocks\n", i); 345 346 prandom_seed_state(&rnd_state, 1); 347 pr_info("verifying all eraseblocks\n"); 348 for (i = 0; i < ebcnt; ++i) { 349 if (bbt[i]) 350 continue; 351 err = verify_eraseblock(i); 352 if (unlikely(err)) 353 goto out; 354 if (i % 256 == 0) 355 pr_info("verified up to eraseblock %u\n", i); 356 357 err = mtdtest_relax(); 358 if (err) 359 goto out; 360 } 361 pr_info("verified %u eraseblocks\n", i); 362 363 err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); 364 if (err) 365 goto out; 366 367 err = verify_all_eraseblocks_ff(); 368 if (err) 369 goto out; 370 371 /* Write all eraseblocks */ 372 prandom_seed_state(&rnd_state, 3); 373 pr_info("writing whole device\n"); 374 for (i = 0; i < ebcnt; ++i) { 375 if (bbt[i]) 376 continue; 377 err = write_eraseblock2(i); 378 if (unlikely(err)) 379 goto out; 380 if (i % 256 == 0) 381 pr_info("written up to eraseblock %u\n", i); 382 383 err = mtdtest_relax(); 384 if (err) 385 goto out; 386 } 387 pr_info("written %u eraseblocks\n", i); 388 389 /* Check all eraseblocks */ 390 prandom_seed_state(&rnd_state, 3); 391 pr_info("verifying all eraseblocks\n"); 392 for (i = 0; i < ebcnt; ++i) { 393 if (bbt[i]) 394 continue; 395 err = verify_eraseblock2(i); 396 if (unlikely(err)) 397 goto out; 398 if (i % 256 == 0) 399 pr_info("verified up to eraseblock %u\n", i); 400 401 err = mtdtest_relax(); 402 if (err) 403 goto out; 404 } 405 pr_info("verified %u eraseblocks\n", i); 406 407 err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); 408 if (err) 409 goto out; 410 411 err = verify_all_eraseblocks_ff(); 412 if (err) 413 goto out; 414 415 pr_info("finished with %d errors\n", errcnt); 416 417out: 418 kfree(bbt); 419 kfree(readbuf); 420 kfree(writebuf); 421 put_mtd_device(mtd); 422 if (err) 423 pr_info("error %d occurred\n", err); 424 printk(KERN_INFO "=================================================\n"); 425 return err; 426} 427module_init(mtd_subpagetest_init); 428 429static void __exit mtd_subpagetest_exit(void) 430{ 431 return; 432} 433module_exit(mtd_subpagetest_exit); 434 435MODULE_DESCRIPTION("Subpage test module"); 436MODULE_AUTHOR("Adrian Hunter"); 437MODULE_LICENSE("GPL");