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
10int 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.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	return 0;
27}
28
29static int is_block_bad(struct mtd_info *mtd, unsigned int ebnum)
30{
31	int ret;
32	loff_t addr = (loff_t)ebnum * mtd->erasesize;
33
34	ret = mtd_block_isbad(mtd, addr);
35	if (ret)
36		pr_info("block %d is bad\n", ebnum);
37
38	return ret;
39}
40
41int mtdtest_scan_for_bad_eraseblocks(struct mtd_info *mtd, unsigned char *bbt,
42					unsigned int eb, int ebcnt)
43{
44	int i, bad = 0;
45
46	if (!mtd_can_have_bb(mtd))
47		return 0;
48
49	pr_info("scanning for bad eraseblocks\n");
50	for (i = 0; i < ebcnt; ++i) {
51		bbt[i] = is_block_bad(mtd, eb + i) ? 1 : 0;
52		if (bbt[i])
53			bad += 1;
54		cond_resched();
55	}
56	pr_info("scanned %d eraseblocks, %d are bad\n", i, bad);
57
58	return 0;
59}
60
61int mtdtest_erase_good_eraseblocks(struct mtd_info *mtd, unsigned char *bbt,
62				unsigned int eb, int ebcnt)
63{
64	int err;
65	unsigned int i;
66
67	for (i = 0; i < ebcnt; ++i) {
68		if (bbt[i])
69			continue;
70		err = mtdtest_erase_eraseblock(mtd, eb + i);
71		if (err)
72			return err;
73		cond_resched();
74	}
75
76	return 0;
77}
78
79int mtdtest_read(struct mtd_info *mtd, loff_t addr, size_t size, void *buf)
80{
81	size_t read;
82	int err;
83
84	err = mtd_read(mtd, addr, size, &read, buf);
85	/* Ignore corrected ECC errors */
86	if (mtd_is_bitflip(err))
87		err = 0;
88	if (!err && read != size)
89		err = -EIO;
90	if (err)
91		pr_err("error: read failed at %#llx\n", addr);
92
93	return err;
94}
95
96int mtdtest_write(struct mtd_info *mtd, loff_t addr, size_t size,
97		const void *buf)
98{
99	size_t written;
100	int err;
101
102	err = mtd_write(mtd, addr, size, &written, buf);
103	if (!err && written != size)
104		err = -EIO;
105	if (err)
106		pr_err("error: write failed at %#llx\n", addr);
107
108	return err;
109}
110