Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1/*
2 * Copyright (C) 2006-2008 Nokia Corporation
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; see the file COPYING. If not, write to the Free Software
15 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16 *
17 * Test OOB read and write on MTD device.
18 *
19 * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
20 */
21
22#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
23
24#include <asm/div64.h>
25#include <linux/init.h>
26#include <linux/module.h>
27#include <linux/moduleparam.h>
28#include <linux/err.h>
29#include <linux/mtd/mtd.h>
30#include <linux/slab.h>
31#include <linux/sched.h>
32#include <linux/random.h>
33
34#include "mtd_test.h"
35
36static int dev = -EINVAL;
37static int bitflip_limit;
38module_param(dev, int, S_IRUGO);
39MODULE_PARM_DESC(dev, "MTD device number to use");
40module_param(bitflip_limit, int, S_IRUGO);
41MODULE_PARM_DESC(bitflip_limit, "Max. allowed bitflips per page");
42
43static struct mtd_info *mtd;
44static unsigned char *readbuf;
45static unsigned char *writebuf;
46static unsigned char *bbt;
47
48static int ebcnt;
49static int pgcnt;
50static int errcnt;
51static int use_offset;
52static int use_len;
53static int use_len_max;
54static int vary_offset;
55static struct rnd_state rnd_state;
56
57static void do_vary_offset(void)
58{
59 use_len -= 1;
60 if (use_len < 1) {
61 use_offset += 1;
62 if (use_offset >= use_len_max)
63 use_offset = 0;
64 use_len = use_len_max - use_offset;
65 }
66}
67
68static int write_eraseblock(int ebnum)
69{
70 int i;
71 struct mtd_oob_ops ops;
72 int err = 0;
73 loff_t addr = ebnum * mtd->erasesize;
74
75 prandom_bytes_state(&rnd_state, writebuf, use_len_max * pgcnt);
76 for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) {
77 ops.mode = MTD_OPS_AUTO_OOB;
78 ops.len = 0;
79 ops.retlen = 0;
80 ops.ooblen = use_len;
81 ops.oobretlen = 0;
82 ops.ooboffs = use_offset;
83 ops.datbuf = NULL;
84 ops.oobbuf = writebuf + (use_len_max * i) + use_offset;
85 err = mtd_write_oob(mtd, addr, &ops);
86 if (err || ops.oobretlen != use_len) {
87 pr_err("error: writeoob failed at %#llx\n",
88 (long long)addr);
89 pr_err("error: use_len %d, use_offset %d\n",
90 use_len, use_offset);
91 errcnt += 1;
92 return err ? err : -1;
93 }
94 if (vary_offset)
95 do_vary_offset();
96 }
97
98 return err;
99}
100
101static int write_whole_device(void)
102{
103 int err;
104 unsigned int i;
105
106 pr_info("writing OOBs of whole device\n");
107 for (i = 0; i < ebcnt; ++i) {
108 if (bbt[i])
109 continue;
110 err = write_eraseblock(i);
111 if (err)
112 return err;
113 if (i % 256 == 0)
114 pr_info("written up to eraseblock %u\n", i);
115 cond_resched();
116 }
117 pr_info("written %u eraseblocks\n", i);
118 return 0;
119}
120
121/*
122 * Display the address, offset and data bytes at comparison failure.
123 * Return number of bitflips encountered.
124 */
125static size_t memcmpshow(loff_t addr, const void *cs, const void *ct, size_t count)
126{
127 const unsigned char *su1, *su2;
128 int res;
129 size_t i = 0;
130 size_t bitflips = 0;
131
132 for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--, i++) {
133 res = *su1 ^ *su2;
134 if (res) {
135 pr_info("error @addr[0x%lx:0x%zx] 0x%x -> 0x%x diff 0x%x\n",
136 (unsigned long)addr, i, *su1, *su2, res);
137 bitflips += hweight8(res);
138 }
139 }
140
141 return bitflips;
142}
143
144static int verify_eraseblock(int ebnum)
145{
146 int i;
147 struct mtd_oob_ops ops;
148 int err = 0;
149 loff_t addr = (loff_t)ebnum * mtd->erasesize;
150 size_t bitflips;
151
152 prandom_bytes_state(&rnd_state, writebuf, use_len_max * pgcnt);
153 for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) {
154 ops.mode = MTD_OPS_AUTO_OOB;
155 ops.len = 0;
156 ops.retlen = 0;
157 ops.ooblen = use_len;
158 ops.oobretlen = 0;
159 ops.ooboffs = use_offset;
160 ops.datbuf = NULL;
161 ops.oobbuf = readbuf;
162 err = mtd_read_oob(mtd, addr, &ops);
163 if (err || ops.oobretlen != use_len) {
164 pr_err("error: readoob failed at %#llx\n",
165 (long long)addr);
166 errcnt += 1;
167 return err ? err : -1;
168 }
169
170 bitflips = memcmpshow(addr, readbuf,
171 writebuf + (use_len_max * i) + use_offset,
172 use_len);
173 if (bitflips > bitflip_limit) {
174 pr_err("error: verify failed at %#llx\n",
175 (long long)addr);
176 errcnt += 1;
177 if (errcnt > 1000) {
178 pr_err("error: too many errors\n");
179 return -1;
180 }
181 } else if (bitflips) {
182 pr_info("ignoring error as within bitflip_limit\n");
183 }
184
185 if (use_offset != 0 || use_len < mtd->ecclayout->oobavail) {
186 int k;
187
188 ops.mode = MTD_OPS_AUTO_OOB;
189 ops.len = 0;
190 ops.retlen = 0;
191 ops.ooblen = mtd->ecclayout->oobavail;
192 ops.oobretlen = 0;
193 ops.ooboffs = 0;
194 ops.datbuf = NULL;
195 ops.oobbuf = readbuf;
196 err = mtd_read_oob(mtd, addr, &ops);
197 if (err || ops.oobretlen != mtd->ecclayout->oobavail) {
198 pr_err("error: readoob failed at %#llx\n",
199 (long long)addr);
200 errcnt += 1;
201 return err ? err : -1;
202 }
203 bitflips = memcmpshow(addr, readbuf + use_offset,
204 writebuf + (use_len_max * i) + use_offset,
205 use_len);
206 if (bitflips > bitflip_limit) {
207 pr_err("error: verify failed at %#llx\n",
208 (long long)addr);
209 errcnt += 1;
210 if (errcnt > 1000) {
211 pr_err("error: too many errors\n");
212 return -1;
213 }
214 } else if (bitflips) {
215 pr_info("ignoring error as within bitflip_limit\n");
216 }
217
218 for (k = 0; k < use_offset; ++k)
219 if (readbuf[k] != 0xff) {
220 pr_err("error: verify 0xff "
221 "failed at %#llx\n",
222 (long long)addr);
223 errcnt += 1;
224 if (errcnt > 1000) {
225 pr_err("error: too "
226 "many errors\n");
227 return -1;
228 }
229 }
230 for (k = use_offset + use_len;
231 k < mtd->ecclayout->oobavail; ++k)
232 if (readbuf[k] != 0xff) {
233 pr_err("error: verify 0xff "
234 "failed at %#llx\n",
235 (long long)addr);
236 errcnt += 1;
237 if (errcnt > 1000) {
238 pr_err("error: too "
239 "many errors\n");
240 return -1;
241 }
242 }
243 }
244 if (vary_offset)
245 do_vary_offset();
246 }
247 return err;
248}
249
250static int verify_eraseblock_in_one_go(int ebnum)
251{
252 struct mtd_oob_ops ops;
253 int err = 0;
254 loff_t addr = (loff_t)ebnum * mtd->erasesize;
255 size_t len = mtd->ecclayout->oobavail * pgcnt;
256 size_t oobavail = mtd->ecclayout->oobavail;
257 size_t bitflips;
258 int i;
259
260 prandom_bytes_state(&rnd_state, writebuf, len);
261 ops.mode = MTD_OPS_AUTO_OOB;
262 ops.len = 0;
263 ops.retlen = 0;
264 ops.ooblen = len;
265 ops.oobretlen = 0;
266 ops.ooboffs = 0;
267 ops.datbuf = NULL;
268 ops.oobbuf = readbuf;
269
270 /* read entire block's OOB at one go */
271 err = mtd_read_oob(mtd, addr, &ops);
272 if (err || ops.oobretlen != len) {
273 pr_err("error: readoob failed at %#llx\n",
274 (long long)addr);
275 errcnt += 1;
276 return err ? err : -1;
277 }
278
279 /* verify one page OOB at a time for bitflip per page limit check */
280 for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) {
281 bitflips = memcmpshow(addr, readbuf + (i * oobavail),
282 writebuf + (i * oobavail), oobavail);
283 if (bitflips > bitflip_limit) {
284 pr_err("error: verify failed at %#llx\n",
285 (long long)addr);
286 errcnt += 1;
287 if (errcnt > 1000) {
288 pr_err("error: too many errors\n");
289 return -1;
290 }
291 } else if (bitflips) {
292 pr_info("ignoring error as within bitflip_limit\n");
293 }
294 }
295
296 return err;
297}
298
299static int verify_all_eraseblocks(void)
300{
301 int err;
302 unsigned int i;
303
304 pr_info("verifying all eraseblocks\n");
305 for (i = 0; i < ebcnt; ++i) {
306 if (bbt[i])
307 continue;
308 err = verify_eraseblock(i);
309 if (err)
310 return err;
311 if (i % 256 == 0)
312 pr_info("verified up to eraseblock %u\n", i);
313 cond_resched();
314 }
315 pr_info("verified %u eraseblocks\n", i);
316 return 0;
317}
318
319static int __init mtd_oobtest_init(void)
320{
321 int err = 0;
322 unsigned int i;
323 uint64_t tmp;
324 struct mtd_oob_ops ops;
325 loff_t addr = 0, addr0;
326
327 printk(KERN_INFO "\n");
328 printk(KERN_INFO "=================================================\n");
329
330 if (dev < 0) {
331 pr_info("Please specify a valid mtd-device via module parameter\n");
332 pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
333 return -EINVAL;
334 }
335
336 pr_info("MTD device: %d\n", dev);
337
338 mtd = get_mtd_device(NULL, dev);
339 if (IS_ERR(mtd)) {
340 err = PTR_ERR(mtd);
341 pr_err("error: cannot get MTD device\n");
342 return err;
343 }
344
345 if (!mtd_type_is_nand(mtd)) {
346 pr_info("this test requires NAND flash\n");
347 goto out;
348 }
349
350 tmp = mtd->size;
351 do_div(tmp, mtd->erasesize);
352 ebcnt = tmp;
353 pgcnt = mtd->erasesize / mtd->writesize;
354
355 pr_info("MTD device size %llu, eraseblock size %u, "
356 "page size %u, count of eraseblocks %u, pages per "
357 "eraseblock %u, OOB size %u\n",
358 (unsigned long long)mtd->size, mtd->erasesize,
359 mtd->writesize, ebcnt, pgcnt, mtd->oobsize);
360
361 err = -ENOMEM;
362 readbuf = kmalloc(mtd->erasesize, GFP_KERNEL);
363 if (!readbuf)
364 goto out;
365 writebuf = kmalloc(mtd->erasesize, GFP_KERNEL);
366 if (!writebuf)
367 goto out;
368 bbt = kzalloc(ebcnt, GFP_KERNEL);
369 if (!bbt)
370 goto out;
371
372 err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt);
373 if (err)
374 goto out;
375
376 use_offset = 0;
377 use_len = mtd->ecclayout->oobavail;
378 use_len_max = mtd->ecclayout->oobavail;
379 vary_offset = 0;
380
381 /* First test: write all OOB, read it back and verify */
382 pr_info("test 1 of 5\n");
383
384 err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
385 if (err)
386 goto out;
387
388 prandom_seed_state(&rnd_state, 1);
389 err = write_whole_device();
390 if (err)
391 goto out;
392
393 prandom_seed_state(&rnd_state, 1);
394 err = verify_all_eraseblocks();
395 if (err)
396 goto out;
397
398 /*
399 * Second test: write all OOB, a block at a time, read it back and
400 * verify.
401 */
402 pr_info("test 2 of 5\n");
403
404 err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
405 if (err)
406 goto out;
407
408 prandom_seed_state(&rnd_state, 3);
409 err = write_whole_device();
410 if (err)
411 goto out;
412
413 /* Check all eraseblocks */
414 prandom_seed_state(&rnd_state, 3);
415 pr_info("verifying all eraseblocks\n");
416 for (i = 0; i < ebcnt; ++i) {
417 if (bbt[i])
418 continue;
419 err = verify_eraseblock_in_one_go(i);
420 if (err)
421 goto out;
422 if (i % 256 == 0)
423 pr_info("verified up to eraseblock %u\n", i);
424 cond_resched();
425 }
426 pr_info("verified %u eraseblocks\n", i);
427
428 /*
429 * Third test: write OOB at varying offsets and lengths, read it back
430 * and verify.
431 */
432 pr_info("test 3 of 5\n");
433
434 err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
435 if (err)
436 goto out;
437
438 /* Write all eraseblocks */
439 use_offset = 0;
440 use_len = mtd->ecclayout->oobavail;
441 use_len_max = mtd->ecclayout->oobavail;
442 vary_offset = 1;
443 prandom_seed_state(&rnd_state, 5);
444
445 err = write_whole_device();
446 if (err)
447 goto out;
448
449 /* Check all eraseblocks */
450 use_offset = 0;
451 use_len = mtd->ecclayout->oobavail;
452 use_len_max = mtd->ecclayout->oobavail;
453 vary_offset = 1;
454 prandom_seed_state(&rnd_state, 5);
455 err = verify_all_eraseblocks();
456 if (err)
457 goto out;
458
459 use_offset = 0;
460 use_len = mtd->ecclayout->oobavail;
461 use_len_max = mtd->ecclayout->oobavail;
462 vary_offset = 0;
463
464 /* Fourth test: try to write off end of device */
465 pr_info("test 4 of 5\n");
466
467 err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
468 if (err)
469 goto out;
470
471 addr0 = 0;
472 for (i = 0; i < ebcnt && bbt[i]; ++i)
473 addr0 += mtd->erasesize;
474
475 /* Attempt to write off end of OOB */
476 ops.mode = MTD_OPS_AUTO_OOB;
477 ops.len = 0;
478 ops.retlen = 0;
479 ops.ooblen = 1;
480 ops.oobretlen = 0;
481 ops.ooboffs = mtd->ecclayout->oobavail;
482 ops.datbuf = NULL;
483 ops.oobbuf = writebuf;
484 pr_info("attempting to start write past end of OOB\n");
485 pr_info("an error is expected...\n");
486 err = mtd_write_oob(mtd, addr0, &ops);
487 if (err) {
488 pr_info("error occurred as expected\n");
489 err = 0;
490 } else {
491 pr_err("error: can write past end of OOB\n");
492 errcnt += 1;
493 }
494
495 /* Attempt to read off end of OOB */
496 ops.mode = MTD_OPS_AUTO_OOB;
497 ops.len = 0;
498 ops.retlen = 0;
499 ops.ooblen = 1;
500 ops.oobretlen = 0;
501 ops.ooboffs = mtd->ecclayout->oobavail;
502 ops.datbuf = NULL;
503 ops.oobbuf = readbuf;
504 pr_info("attempting to start read past end of OOB\n");
505 pr_info("an error is expected...\n");
506 err = mtd_read_oob(mtd, addr0, &ops);
507 if (err) {
508 pr_info("error occurred as expected\n");
509 err = 0;
510 } else {
511 pr_err("error: can read past end of OOB\n");
512 errcnt += 1;
513 }
514
515 if (bbt[ebcnt - 1])
516 pr_info("skipping end of device tests because last "
517 "block is bad\n");
518 else {
519 /* Attempt to write off end of device */
520 ops.mode = MTD_OPS_AUTO_OOB;
521 ops.len = 0;
522 ops.retlen = 0;
523 ops.ooblen = mtd->ecclayout->oobavail + 1;
524 ops.oobretlen = 0;
525 ops.ooboffs = 0;
526 ops.datbuf = NULL;
527 ops.oobbuf = writebuf;
528 pr_info("attempting to write past end of device\n");
529 pr_info("an error is expected...\n");
530 err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops);
531 if (err) {
532 pr_info("error occurred as expected\n");
533 err = 0;
534 } else {
535 pr_err("error: wrote past end of device\n");
536 errcnt += 1;
537 }
538
539 /* Attempt to read off end of device */
540 ops.mode = MTD_OPS_AUTO_OOB;
541 ops.len = 0;
542 ops.retlen = 0;
543 ops.ooblen = mtd->ecclayout->oobavail + 1;
544 ops.oobretlen = 0;
545 ops.ooboffs = 0;
546 ops.datbuf = NULL;
547 ops.oobbuf = readbuf;
548 pr_info("attempting to read past end of device\n");
549 pr_info("an error is expected...\n");
550 err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops);
551 if (err) {
552 pr_info("error occurred as expected\n");
553 err = 0;
554 } else {
555 pr_err("error: read past end of device\n");
556 errcnt += 1;
557 }
558
559 err = mtdtest_erase_eraseblock(mtd, ebcnt - 1);
560 if (err)
561 goto out;
562
563 /* Attempt to write off end of device */
564 ops.mode = MTD_OPS_AUTO_OOB;
565 ops.len = 0;
566 ops.retlen = 0;
567 ops.ooblen = mtd->ecclayout->oobavail;
568 ops.oobretlen = 0;
569 ops.ooboffs = 1;
570 ops.datbuf = NULL;
571 ops.oobbuf = writebuf;
572 pr_info("attempting to write past end of device\n");
573 pr_info("an error is expected...\n");
574 err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops);
575 if (err) {
576 pr_info("error occurred as expected\n");
577 err = 0;
578 } else {
579 pr_err("error: wrote past end of device\n");
580 errcnt += 1;
581 }
582
583 /* Attempt to read off end of device */
584 ops.mode = MTD_OPS_AUTO_OOB;
585 ops.len = 0;
586 ops.retlen = 0;
587 ops.ooblen = mtd->ecclayout->oobavail;
588 ops.oobretlen = 0;
589 ops.ooboffs = 1;
590 ops.datbuf = NULL;
591 ops.oobbuf = readbuf;
592 pr_info("attempting to read past end of device\n");
593 pr_info("an error is expected...\n");
594 err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops);
595 if (err) {
596 pr_info("error occurred as expected\n");
597 err = 0;
598 } else {
599 pr_err("error: read past end of device\n");
600 errcnt += 1;
601 }
602 }
603
604 /* Fifth test: write / read across block boundaries */
605 pr_info("test 5 of 5\n");
606
607 /* Erase all eraseblocks */
608 err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
609 if (err)
610 goto out;
611
612 /* Write all eraseblocks */
613 prandom_seed_state(&rnd_state, 11);
614 pr_info("writing OOBs of whole device\n");
615 for (i = 0; i < ebcnt - 1; ++i) {
616 int cnt = 2;
617 int pg;
618 size_t sz = mtd->ecclayout->oobavail;
619 if (bbt[i] || bbt[i + 1])
620 continue;
621 addr = (loff_t)(i + 1) * mtd->erasesize - mtd->writesize;
622 prandom_bytes_state(&rnd_state, writebuf, sz * cnt);
623 for (pg = 0; pg < cnt; ++pg) {
624 ops.mode = MTD_OPS_AUTO_OOB;
625 ops.len = 0;
626 ops.retlen = 0;
627 ops.ooblen = sz;
628 ops.oobretlen = 0;
629 ops.ooboffs = 0;
630 ops.datbuf = NULL;
631 ops.oobbuf = writebuf + pg * sz;
632 err = mtd_write_oob(mtd, addr, &ops);
633 if (err)
634 goto out;
635 if (i % 256 == 0)
636 pr_info("written up to eraseblock %u\n", i);
637 cond_resched();
638 addr += mtd->writesize;
639 }
640 }
641 pr_info("written %u eraseblocks\n", i);
642
643 /* Check all eraseblocks */
644 prandom_seed_state(&rnd_state, 11);
645 pr_info("verifying all eraseblocks\n");
646 for (i = 0; i < ebcnt - 1; ++i) {
647 if (bbt[i] || bbt[i + 1])
648 continue;
649 prandom_bytes_state(&rnd_state, writebuf,
650 mtd->ecclayout->oobavail * 2);
651 addr = (loff_t)(i + 1) * mtd->erasesize - mtd->writesize;
652 ops.mode = MTD_OPS_AUTO_OOB;
653 ops.len = 0;
654 ops.retlen = 0;
655 ops.ooblen = mtd->ecclayout->oobavail * 2;
656 ops.oobretlen = 0;
657 ops.ooboffs = 0;
658 ops.datbuf = NULL;
659 ops.oobbuf = readbuf;
660 err = mtd_read_oob(mtd, addr, &ops);
661 if (err)
662 goto out;
663 if (memcmpshow(addr, readbuf, writebuf,
664 mtd->ecclayout->oobavail * 2)) {
665 pr_err("error: verify failed at %#llx\n",
666 (long long)addr);
667 errcnt += 1;
668 if (errcnt > 1000) {
669 pr_err("error: too many errors\n");
670 goto out;
671 }
672 }
673 if (i % 256 == 0)
674 pr_info("verified up to eraseblock %u\n", i);
675 cond_resched();
676 }
677 pr_info("verified %u eraseblocks\n", i);
678
679 pr_info("finished with %d errors\n", errcnt);
680out:
681 kfree(bbt);
682 kfree(writebuf);
683 kfree(readbuf);
684 put_mtd_device(mtd);
685 if (err)
686 pr_info("error %d occurred\n", err);
687 printk(KERN_INFO "=================================================\n");
688 return err;
689}
690module_init(mtd_oobtest_init);
691
692static void __exit mtd_oobtest_exit(void)
693{
694 return;
695}
696module_exit(mtd_oobtest_exit);
697
698MODULE_DESCRIPTION("Out-of-band test module");
699MODULE_AUTHOR("Adrian Hunter");
700MODULE_LICENSE("GPL");