1 // SPDX-License-Identifier: GPL-2.0 2 #define pr_fmt(fmt) "mtd_test: " fmt 3 4 #include <linux/module.h> 5 #include <linux/sched.h> 6 #include <linux/printk.h> 7 8 #include "mtd_test.h" 9 10 int mtdtest_erase_eraseblock(struct mtd_info *mtd, unsigned int ebnum) 11 { 12 int err; 13 struct erase_info ei; 14 loff_t addr = (loff_t)ebnum * mtd->erasesize; 15 16 memset(&ei, 0, sizeof(struct erase_info)); 17 ei.mtd = mtd; 18 ei.addr = addr; 19 ei.len = mtd->erasesize; 20 21 err = mtd_erase(mtd, &ei); 22 if (err) { 23 pr_info("error %d while erasing EB %d\n", err, ebnum); 24 return err; 25 } 26 27 if (ei.state == MTD_ERASE_FAILED) { 28 pr_info("some erase error occurred at EB %d\n", ebnum); 29 return -EIO; 30 } 31 return 0; 32 } 33 34 static int is_block_bad(struct mtd_info *mtd, unsigned int ebnum) 35 { 36 int ret; 37 loff_t addr = (loff_t)ebnum * mtd->erasesize; 38 39 ret = mtd_block_isbad(mtd, addr); 40 if (ret) 41 pr_info("block %d is bad\n", ebnum); 42 43 return ret; 44 } 45 46 int mtdtest_scan_for_bad_eraseblocks(struct mtd_info *mtd, unsigned char *bbt, 47 unsigned int eb, int ebcnt) 48 { 49 int i, bad = 0; 50 51 if (!mtd_can_have_bb(mtd)) 52 return 0; 53 54 pr_info("scanning for bad eraseblocks\n"); 55 for (i = 0; i < ebcnt; ++i) { 56 bbt[i] = is_block_bad(mtd, eb + i) ? 1 : 0; 57 if (bbt[i]) 58 bad += 1; 59 cond_resched(); 60 } 61 pr_info("scanned %d eraseblocks, %d are bad\n", i, bad); 62 63 return 0; 64 } 65 66 int mtdtest_erase_good_eraseblocks(struct mtd_info *mtd, unsigned char *bbt, 67 unsigned int eb, int ebcnt) 68 { 69 int err; 70 unsigned int i; 71 72 for (i = 0; i < ebcnt; ++i) { 73 if (bbt[i]) 74 continue; 75 err = mtdtest_erase_eraseblock(mtd, eb + i); 76 if (err) 77 return err; 78 cond_resched(); 79 } 80 81 return 0; 82 } 83 84 int mtdtest_read(struct mtd_info *mtd, loff_t addr, size_t size, void *buf) 85 { 86 size_t read; 87 int err; 88 89 err = mtd_read(mtd, addr, size, &read, buf); 90 /* Ignore corrected ECC errors */ 91 if (mtd_is_bitflip(err)) 92 err = 0; 93 if (!err && read != size) 94 err = -EIO; 95 if (err) 96 pr_err("error: read failed at %#llx\n", addr); 97 98 return err; 99 } 100 101 int mtdtest_write(struct mtd_info *mtd, loff_t addr, size_t size, 102 const void *buf) 103 { 104 size_t written; 105 int err; 106 107 err = mtd_write(mtd, addr, size, &written, buf); 108 if (!err && written != size) 109 err = -EIO; 110 if (err) 111 pr_err("error: write failed at %#llx\n", addr); 112 113 return err; 114 } 115