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(state: &rnd_state, buf: writebuf, nbytes: mtd->erasesize);
46 cond_resched();
47 return mtdtest_write(mtd, addr, size: mtd->erasesize, buf: 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(state: &rnd_state, buf: writebuf, nbytes: 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, addr: addr0, size: bufsize, buf: twopages);
69 if (err)
70 return err;
71 err = mtdtest_read(mtd, addr: addrn - bufsize, size: bufsize, buf: twopages);
72 if (err)
73 return err;
74 memset(twopages, 0, bufsize);
75 err = mtdtest_read(mtd, addr, size: bufsize, buf: twopages);
76 if (err)
77 break;
78 if (memcmp(p: twopages, q: writebuf + (j * pgsize), size: 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, addr: addr0, size: bufsize, buf: twopages);
90 if (err)
91 return err;
92 err = mtdtest_read(mtd, addr: addrn - bufsize, size: bufsize, buf: twopages);
93 if (err)
94 return err;
95 memset(twopages, 0, bufsize);
96 err = mtdtest_read(mtd, addr, size: bufsize, buf: twopages);
97 if (err)
98 return err;
99 memcpy(boundary, writebuf + mtd->erasesize - pgsize, pgsize);
100 prandom_bytes_state(state: &rnd_state, buf: boundary + pgsize, nbytes: pgsize);
101 if (memcmp(p: twopages, q: boundary, size: 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(n: pgsize, size: 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, size: pgsize, buf: pp1);
136 if (err) {
137 kfree(objp: 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, size: pgsize, buf: pp1);
144 if (err) {
145 kfree(objp: 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, size: pgsize, buf: pp2);
153 if (err) {
154 kfree(objp: 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, size: pgsize, buf: pp3);
162 if (err) {
163 kfree(objp: 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, size: pgsize, buf: pp4);
171 if (err) {
172 kfree(objp: 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(p: pp2, q: pp4, size: pgsize)) {
180 pr_err("verify failed!\n");
181 errcnt += 1;
182 } else if (!err)
183 pr_info("crosstest ok\n");
184 kfree(objp: 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(state: &rnd_state, buf: writebuf, nbytes: pgsize);
214 strcpy(p: writebuf, q: "There is no data like this!");
215 err = mtdtest_write(mtd, addr: addr0, size: pgsize, buf: 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, addr: addr0, size: pgsize, buf: readbuf);
222 if (err)
223 return err;
224
225 pr_info("verifying 1st page of block %d\n", ebnum);
226 if (memcmp(p: writebuf, q: readbuf, size: 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(state: &rnd_state, buf: writebuf, nbytes: pgsize);
239 strcpy(p: writebuf, q: "There is no data like this!");
240 err = mtdtest_write(mtd, addr: addr0, size: pgsize, buf: writebuf);
241 if (err)
242 return err;
243
244 pr_info("erasing block %d\n", ebnum2);
245 err = mtdtest_erase_eraseblock(mtd, ebnum: 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, addr: addr0, size: pgsize, buf: readbuf);
252 if (err)
253 return err;
254
255 pr_info("verifying 1st page of block %d\n", ebnum);
256 if (memcmp(p: writebuf, q: readbuf, size: 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(state: &rnd_state, buf: writebuf, nbytes: pgsize);
288 err = mtdtest_write(mtd, addr: addr0, size: pgsize, buf: 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, addr: addr0, size: pgsize, buf: 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, num: dev);
337 if (IS_ERR(ptr: mtd)) {
338 err = PTR_ERR(ptr: 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(size: mtd->erasesize, GFP_KERNEL);
363 if (!writebuf)
364 goto out;
365 twopages = kmalloc(size: bufsize, GFP_KERNEL);
366 if (!twopages)
367 goto out;
368 boundary = kmalloc(size: bufsize, GFP_KERNEL);
369 if (!boundary)
370 goto out;
371
372 bbt = kzalloc(size: ebcnt, GFP_KERNEL);
373 if (!bbt)
374 goto out;
375 err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, eb: 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, eb: 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(state: &rnd_state, seed: 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(ebnum: 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(state: &rnd_state, seed: 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(ebnum: 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(objp: bbt);
442 kfree(objp: boundary);
443 kfree(objp: twopages);
444 kfree(objp: 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

source code of linux/drivers/mtd/tests/pagetest.c