#define pr_fmt(fmt) "mtd_test: " fmt #include #include #include #include "mtd_test.h" int mtdtest_erase_eraseblock(struct mtd_info *mtd, unsigned int ebnum) { int err; struct erase_info ei; loff_t addr = (loff_t)ebnum * mtd->erasesize; memset(&ei, 0, sizeof(struct erase_info)); ei.mtd = mtd; ei.addr = addr; ei.len = mtd->erasesize; err = mtd_erase(mtd, &ei); if (err) { pr_info("error %d while erasing EB %d\n", err, ebnum); return err; } if (ei.state == MTD_ERASE_FAILED) { pr_info("some erase error occurred at EB %d\n", ebnum); return -EIO; } return 0; } static int is_block_bad(struct mtd_info *mtd, unsigned int ebnum) { int ret; loff_t addr = (loff_t)ebnum * mtd->erasesize; ret = mtd_block_isbad(mtd, addr); if (ret) pr_info("block %d is bad\n", ebnum); return ret; } int mtdtest_scan_for_bad_eraseblocks(struct mtd_info *mtd, unsigned char *bbt, unsigned int eb, int ebcnt) { int i, bad = 0; if (!mtd_can_have_bb(mtd)) return 0; pr_info("scanning for bad eraseblocks\n"); for (i = 0; i < ebcnt; ++i) { bbt[i] = is_block_bad(mtd, eb + i) ? 1 : 0; if (bbt[i]) bad += 1; cond_resched(); } pr_info("scanned %d eraseblocks, %d are bad\n", i, bad); return 0; } int mtdtest_erase_good_eraseblocks(struct mtd_info *mtd, unsigned char *bbt, unsigned int eb, int ebcnt) { int err; unsigned int i; for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue; err = mtdtest_erase_eraseblock(mtd, eb + i); if (err) return err; cond_resched(); } return 0; } int mtdtest_read(struct mtd_info *mtd, loff_t addr, size_t size, void *buf) { size_t read; int err; err = mtd_read(mtd, addr, size, &read, buf); /* Ignore corrected ECC errors */ if (mtd_is_bitflip(err)) err = 0; if (!err && read != size) err = -EIO; if (err) pr_err("error: read failed at %#llx\n", addr); return err; } int mtdtest_write(struct mtd_info *mtd, loff_t addr, size_t size, const void *buf) { size_t written; int err; err = mtd_write(mtd, addr, size, &written, buf); if (!err && written != size) err = -EIO; if (err) pr_err("error: write failed at %#llx\n", addr); return err; }