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