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