Merge branch 'siocghwtstamp' of git://git.kernel.org/pub/scm/linux/kernel/git/bwh...
[cascardo/linux.git] / drivers / mtd / tests / oobtest.c
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
36 static int dev = -EINVAL;
37 module_param(dev, int, S_IRUGO);
38 MODULE_PARM_DESC(dev, "MTD device number to use");
39
40 static struct mtd_info *mtd;
41 static unsigned char *readbuf;
42 static unsigned char *writebuf;
43 static unsigned char *bbt;
44
45 static int ebcnt;
46 static int pgcnt;
47 static int errcnt;
48 static int use_offset;
49 static int use_len;
50 static int use_len_max;
51 static int vary_offset;
52 static struct rnd_state rnd_state;
53
54 static void do_vary_offset(void)
55 {
56         use_len -= 1;
57         if (use_len < 1) {
58                 use_offset += 1;
59                 if (use_offset >= use_len_max)
60                         use_offset = 0;
61                 use_len = use_len_max - use_offset;
62         }
63 }
64
65 static int write_eraseblock(int ebnum)
66 {
67         int i;
68         struct mtd_oob_ops ops;
69         int err = 0;
70         loff_t addr = ebnum * mtd->erasesize;
71
72         for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) {
73                 prandom_bytes_state(&rnd_state, writebuf, use_len);
74                 ops.mode      = MTD_OPS_AUTO_OOB;
75                 ops.len       = 0;
76                 ops.retlen    = 0;
77                 ops.ooblen    = use_len;
78                 ops.oobretlen = 0;
79                 ops.ooboffs   = use_offset;
80                 ops.datbuf    = NULL;
81                 ops.oobbuf    = writebuf;
82                 err = mtd_write_oob(mtd, addr, &ops);
83                 if (err || ops.oobretlen != use_len) {
84                         pr_err("error: writeoob failed at %#llx\n",
85                                (long long)addr);
86                         pr_err("error: use_len %d, use_offset %d\n",
87                                use_len, use_offset);
88                         errcnt += 1;
89                         return err ? err : -1;
90                 }
91                 if (vary_offset)
92                         do_vary_offset();
93         }
94
95         return err;
96 }
97
98 static int write_whole_device(void)
99 {
100         int err;
101         unsigned int i;
102
103         pr_info("writing OOBs of whole device\n");
104         for (i = 0; i < ebcnt; ++i) {
105                 if (bbt[i])
106                         continue;
107                 err = write_eraseblock(i);
108                 if (err)
109                         return err;
110                 if (i % 256 == 0)
111                         pr_info("written up to eraseblock %u\n", i);
112                 cond_resched();
113         }
114         pr_info("written %u eraseblocks\n", i);
115         return 0;
116 }
117
118 static int verify_eraseblock(int ebnum)
119 {
120         int i;
121         struct mtd_oob_ops ops;
122         int err = 0;
123         loff_t addr = ebnum * mtd->erasesize;
124
125         for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) {
126                 prandom_bytes_state(&rnd_state, writebuf, use_len);
127                 ops.mode      = MTD_OPS_AUTO_OOB;
128                 ops.len       = 0;
129                 ops.retlen    = 0;
130                 ops.ooblen    = use_len;
131                 ops.oobretlen = 0;
132                 ops.ooboffs   = use_offset;
133                 ops.datbuf    = NULL;
134                 ops.oobbuf    = readbuf;
135                 err = mtd_read_oob(mtd, addr, &ops);
136                 if (err || ops.oobretlen != use_len) {
137                         pr_err("error: readoob failed at %#llx\n",
138                                (long long)addr);
139                         errcnt += 1;
140                         return err ? err : -1;
141                 }
142                 if (memcmp(readbuf, writebuf, use_len)) {
143                         pr_err("error: verify failed at %#llx\n",
144                                (long long)addr);
145                         errcnt += 1;
146                         if (errcnt > 1000) {
147                                 pr_err("error: too many errors\n");
148                                 return -1;
149                         }
150                 }
151                 if (use_offset != 0 || use_len < mtd->ecclayout->oobavail) {
152                         int k;
153
154                         ops.mode      = MTD_OPS_AUTO_OOB;
155                         ops.len       = 0;
156                         ops.retlen    = 0;
157                         ops.ooblen    = mtd->ecclayout->oobavail;
158                         ops.oobretlen = 0;
159                         ops.ooboffs   = 0;
160                         ops.datbuf    = NULL;
161                         ops.oobbuf    = readbuf;
162                         err = mtd_read_oob(mtd, addr, &ops);
163                         if (err || ops.oobretlen != mtd->ecclayout->oobavail) {
164                                 pr_err("error: readoob failed at %#llx\n",
165                                                 (long long)addr);
166                                 errcnt += 1;
167                                 return err ? err : -1;
168                         }
169                         if (memcmp(readbuf + use_offset, writebuf, use_len)) {
170                                 pr_err("error: verify failed at %#llx\n",
171                                                 (long long)addr);
172                                 errcnt += 1;
173                                 if (errcnt > 1000) {
174                                         pr_err("error: too many errors\n");
175                                         return -1;
176                                 }
177                         }
178                         for (k = 0; k < use_offset; ++k)
179                                 if (readbuf[k] != 0xff) {
180                                         pr_err("error: verify 0xff "
181                                                "failed at %#llx\n",
182                                                (long long)addr);
183                                         errcnt += 1;
184                                         if (errcnt > 1000) {
185                                                 pr_err("error: too "
186                                                        "many errors\n");
187                                                 return -1;
188                                         }
189                                 }
190                         for (k = use_offset + use_len;
191                              k < mtd->ecclayout->oobavail; ++k)
192                                 if (readbuf[k] != 0xff) {
193                                         pr_err("error: verify 0xff "
194                                                "failed at %#llx\n",
195                                                (long long)addr);
196                                         errcnt += 1;
197                                         if (errcnt > 1000) {
198                                                 pr_err("error: too "
199                                                        "many errors\n");
200                                                 return -1;
201                                         }
202                                 }
203                 }
204                 if (vary_offset)
205                         do_vary_offset();
206         }
207         return err;
208 }
209
210 static int verify_eraseblock_in_one_go(int ebnum)
211 {
212         struct mtd_oob_ops ops;
213         int err = 0;
214         loff_t addr = ebnum * mtd->erasesize;
215         size_t len = mtd->ecclayout->oobavail * pgcnt;
216
217         prandom_bytes_state(&rnd_state, writebuf, len);
218         ops.mode      = MTD_OPS_AUTO_OOB;
219         ops.len       = 0;
220         ops.retlen    = 0;
221         ops.ooblen    = len;
222         ops.oobretlen = 0;
223         ops.ooboffs   = 0;
224         ops.datbuf    = NULL;
225         ops.oobbuf    = readbuf;
226         err = mtd_read_oob(mtd, addr, &ops);
227         if (err || ops.oobretlen != len) {
228                 pr_err("error: readoob failed at %#llx\n",
229                        (long long)addr);
230                 errcnt += 1;
231                 return err ? err : -1;
232         }
233         if (memcmp(readbuf, writebuf, len)) {
234                 pr_err("error: verify failed at %#llx\n",
235                        (long long)addr);
236                 errcnt += 1;
237                 if (errcnt > 1000) {
238                         pr_err("error: too many errors\n");
239                         return -1;
240                 }
241         }
242
243         return err;
244 }
245
246 static int verify_all_eraseblocks(void)
247 {
248         int err;
249         unsigned int i;
250
251         pr_info("verifying all eraseblocks\n");
252         for (i = 0; i < ebcnt; ++i) {
253                 if (bbt[i])
254                         continue;
255                 err = verify_eraseblock(i);
256                 if (err)
257                         return err;
258                 if (i % 256 == 0)
259                         pr_info("verified up to eraseblock %u\n", i);
260                 cond_resched();
261         }
262         pr_info("verified %u eraseblocks\n", i);
263         return 0;
264 }
265
266 static int __init mtd_oobtest_init(void)
267 {
268         int err = 0;
269         unsigned int i;
270         uint64_t tmp;
271         struct mtd_oob_ops ops;
272         loff_t addr = 0, addr0;
273
274         printk(KERN_INFO "\n");
275         printk(KERN_INFO "=================================================\n");
276
277         if (dev < 0) {
278                 pr_info("Please specify a valid mtd-device via module parameter\n");
279                 pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
280                 return -EINVAL;
281         }
282
283         pr_info("MTD device: %d\n", dev);
284
285         mtd = get_mtd_device(NULL, dev);
286         if (IS_ERR(mtd)) {
287                 err = PTR_ERR(mtd);
288                 pr_err("error: cannot get MTD device\n");
289                 return err;
290         }
291
292         if (!mtd_type_is_nand(mtd)) {
293                 pr_info("this test requires NAND flash\n");
294                 goto out;
295         }
296
297         tmp = mtd->size;
298         do_div(tmp, mtd->erasesize);
299         ebcnt = tmp;
300         pgcnt = mtd->erasesize / mtd->writesize;
301
302         pr_info("MTD device size %llu, eraseblock size %u, "
303                "page size %u, count of eraseblocks %u, pages per "
304                "eraseblock %u, OOB size %u\n",
305                (unsigned long long)mtd->size, mtd->erasesize,
306                mtd->writesize, ebcnt, pgcnt, mtd->oobsize);
307
308         err = -ENOMEM;
309         readbuf = kmalloc(mtd->erasesize, GFP_KERNEL);
310         if (!readbuf)
311                 goto out;
312         writebuf = kmalloc(mtd->erasesize, GFP_KERNEL);
313         if (!writebuf)
314                 goto out;
315         bbt = kzalloc(ebcnt, GFP_KERNEL);
316         if (!bbt)
317                 goto out;
318
319         err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt);
320         if (err)
321                 goto out;
322
323         use_offset = 0;
324         use_len = mtd->ecclayout->oobavail;
325         use_len_max = mtd->ecclayout->oobavail;
326         vary_offset = 0;
327
328         /* First test: write all OOB, read it back and verify */
329         pr_info("test 1 of 5\n");
330
331         err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
332         if (err)
333                 goto out;
334
335         prandom_seed_state(&rnd_state, 1);
336         err = write_whole_device();
337         if (err)
338                 goto out;
339
340         prandom_seed_state(&rnd_state, 1);
341         err = verify_all_eraseblocks();
342         if (err)
343                 goto out;
344
345         /*
346          * Second test: write all OOB, a block at a time, read it back and
347          * verify.
348          */
349         pr_info("test 2 of 5\n");
350
351         err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
352         if (err)
353                 goto out;
354
355         prandom_seed_state(&rnd_state, 3);
356         err = write_whole_device();
357         if (err)
358                 goto out;
359
360         /* Check all eraseblocks */
361         prandom_seed_state(&rnd_state, 3);
362         pr_info("verifying all eraseblocks\n");
363         for (i = 0; i < ebcnt; ++i) {
364                 if (bbt[i])
365                         continue;
366                 err = verify_eraseblock_in_one_go(i);
367                 if (err)
368                         goto out;
369                 if (i % 256 == 0)
370                         pr_info("verified up to eraseblock %u\n", i);
371                 cond_resched();
372         }
373         pr_info("verified %u eraseblocks\n", i);
374
375         /*
376          * Third test: write OOB at varying offsets and lengths, read it back
377          * and verify.
378          */
379         pr_info("test 3 of 5\n");
380
381         err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
382         if (err)
383                 goto out;
384
385         /* Write all eraseblocks */
386         use_offset = 0;
387         use_len = mtd->ecclayout->oobavail;
388         use_len_max = mtd->ecclayout->oobavail;
389         vary_offset = 1;
390         prandom_seed_state(&rnd_state, 5);
391
392         err = write_whole_device();
393         if (err)
394                 goto out;
395
396         /* Check all eraseblocks */
397         use_offset = 0;
398         use_len = mtd->ecclayout->oobavail;
399         use_len_max = mtd->ecclayout->oobavail;
400         vary_offset = 1;
401         prandom_seed_state(&rnd_state, 5);
402         err = verify_all_eraseblocks();
403         if (err)
404                 goto out;
405
406         use_offset = 0;
407         use_len = mtd->ecclayout->oobavail;
408         use_len_max = mtd->ecclayout->oobavail;
409         vary_offset = 0;
410
411         /* Fourth test: try to write off end of device */
412         pr_info("test 4 of 5\n");
413
414         err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
415         if (err)
416                 goto out;
417
418         addr0 = 0;
419         for (i = 0; i < ebcnt && bbt[i]; ++i)
420                 addr0 += mtd->erasesize;
421
422         /* Attempt to write off end of OOB */
423         ops.mode      = MTD_OPS_AUTO_OOB;
424         ops.len       = 0;
425         ops.retlen    = 0;
426         ops.ooblen    = 1;
427         ops.oobretlen = 0;
428         ops.ooboffs   = mtd->ecclayout->oobavail;
429         ops.datbuf    = NULL;
430         ops.oobbuf    = writebuf;
431         pr_info("attempting to start write past end of OOB\n");
432         pr_info("an error is expected...\n");
433         err = mtd_write_oob(mtd, addr0, &ops);
434         if (err) {
435                 pr_info("error occurred as expected\n");
436                 err = 0;
437         } else {
438                 pr_err("error: can write past end of OOB\n");
439                 errcnt += 1;
440         }
441
442         /* Attempt to read off end of OOB */
443         ops.mode      = MTD_OPS_AUTO_OOB;
444         ops.len       = 0;
445         ops.retlen    = 0;
446         ops.ooblen    = 1;
447         ops.oobretlen = 0;
448         ops.ooboffs   = mtd->ecclayout->oobavail;
449         ops.datbuf    = NULL;
450         ops.oobbuf    = readbuf;
451         pr_info("attempting to start read past end of OOB\n");
452         pr_info("an error is expected...\n");
453         err = mtd_read_oob(mtd, addr0, &ops);
454         if (err) {
455                 pr_info("error occurred as expected\n");
456                 err = 0;
457         } else {
458                 pr_err("error: can read past end of OOB\n");
459                 errcnt += 1;
460         }
461
462         if (bbt[ebcnt - 1])
463                 pr_info("skipping end of device tests because last "
464                        "block is bad\n");
465         else {
466                 /* Attempt to write off end of device */
467                 ops.mode      = MTD_OPS_AUTO_OOB;
468                 ops.len       = 0;
469                 ops.retlen    = 0;
470                 ops.ooblen    = mtd->ecclayout->oobavail + 1;
471                 ops.oobretlen = 0;
472                 ops.ooboffs   = 0;
473                 ops.datbuf    = NULL;
474                 ops.oobbuf    = writebuf;
475                 pr_info("attempting to write past end of device\n");
476                 pr_info("an error is expected...\n");
477                 err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops);
478                 if (err) {
479                         pr_info("error occurred as expected\n");
480                         err = 0;
481                 } else {
482                         pr_err("error: wrote past end of device\n");
483                         errcnt += 1;
484                 }
485
486                 /* Attempt to read off end of device */
487                 ops.mode      = MTD_OPS_AUTO_OOB;
488                 ops.len       = 0;
489                 ops.retlen    = 0;
490                 ops.ooblen    = mtd->ecclayout->oobavail + 1;
491                 ops.oobretlen = 0;
492                 ops.ooboffs   = 0;
493                 ops.datbuf    = NULL;
494                 ops.oobbuf    = readbuf;
495                 pr_info("attempting to read past end of device\n");
496                 pr_info("an error is expected...\n");
497                 err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops);
498                 if (err) {
499                         pr_info("error occurred as expected\n");
500                         err = 0;
501                 } else {
502                         pr_err("error: read past end of device\n");
503                         errcnt += 1;
504                 }
505
506                 err = mtdtest_erase_eraseblock(mtd, ebcnt - 1);
507                 if (err)
508                         goto out;
509
510                 /* Attempt to write off end of device */
511                 ops.mode      = MTD_OPS_AUTO_OOB;
512                 ops.len       = 0;
513                 ops.retlen    = 0;
514                 ops.ooblen    = mtd->ecclayout->oobavail;
515                 ops.oobretlen = 0;
516                 ops.ooboffs   = 1;
517                 ops.datbuf    = NULL;
518                 ops.oobbuf    = writebuf;
519                 pr_info("attempting to write past end of device\n");
520                 pr_info("an error is expected...\n");
521                 err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops);
522                 if (err) {
523                         pr_info("error occurred as expected\n");
524                         err = 0;
525                 } else {
526                         pr_err("error: wrote past end of device\n");
527                         errcnt += 1;
528                 }
529
530                 /* Attempt to read off end of device */
531                 ops.mode      = MTD_OPS_AUTO_OOB;
532                 ops.len       = 0;
533                 ops.retlen    = 0;
534                 ops.ooblen    = mtd->ecclayout->oobavail;
535                 ops.oobretlen = 0;
536                 ops.ooboffs   = 1;
537                 ops.datbuf    = NULL;
538                 ops.oobbuf    = readbuf;
539                 pr_info("attempting to read past end of device\n");
540                 pr_info("an error is expected...\n");
541                 err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops);
542                 if (err) {
543                         pr_info("error occurred as expected\n");
544                         err = 0;
545                 } else {
546                         pr_err("error: read past end of device\n");
547                         errcnt += 1;
548                 }
549         }
550
551         /* Fifth test: write / read across block boundaries */
552         pr_info("test 5 of 5\n");
553
554         /* Erase all eraseblocks */
555         err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
556         if (err)
557                 goto out;
558
559         /* Write all eraseblocks */
560         prandom_seed_state(&rnd_state, 11);
561         pr_info("writing OOBs of whole device\n");
562         for (i = 0; i < ebcnt - 1; ++i) {
563                 int cnt = 2;
564                 int pg;
565                 size_t sz = mtd->ecclayout->oobavail;
566                 if (bbt[i] || bbt[i + 1])
567                         continue;
568                 addr = (i + 1) * mtd->erasesize - mtd->writesize;
569                 for (pg = 0; pg < cnt; ++pg) {
570                         prandom_bytes_state(&rnd_state, writebuf, sz);
571                         ops.mode      = MTD_OPS_AUTO_OOB;
572                         ops.len       = 0;
573                         ops.retlen    = 0;
574                         ops.ooblen    = sz;
575                         ops.oobretlen = 0;
576                         ops.ooboffs   = 0;
577                         ops.datbuf    = NULL;
578                         ops.oobbuf    = writebuf;
579                         err = mtd_write_oob(mtd, addr, &ops);
580                         if (err)
581                                 goto out;
582                         if (i % 256 == 0)
583                                 pr_info("written up to eraseblock %u\n", i);
584                         cond_resched();
585                         addr += mtd->writesize;
586                 }
587         }
588         pr_info("written %u eraseblocks\n", i);
589
590         /* Check all eraseblocks */
591         prandom_seed_state(&rnd_state, 11);
592         pr_info("verifying all eraseblocks\n");
593         for (i = 0; i < ebcnt - 1; ++i) {
594                 if (bbt[i] || bbt[i + 1])
595                         continue;
596                 prandom_bytes_state(&rnd_state, writebuf,
597                                         mtd->ecclayout->oobavail * 2);
598                 addr = (i + 1) * mtd->erasesize - mtd->writesize;
599                 ops.mode      = MTD_OPS_AUTO_OOB;
600                 ops.len       = 0;
601                 ops.retlen    = 0;
602                 ops.ooblen    = mtd->ecclayout->oobavail * 2;
603                 ops.oobretlen = 0;
604                 ops.ooboffs   = 0;
605                 ops.datbuf    = NULL;
606                 ops.oobbuf    = readbuf;
607                 err = mtd_read_oob(mtd, addr, &ops);
608                 if (err)
609                         goto out;
610                 if (memcmp(readbuf, writebuf, mtd->ecclayout->oobavail * 2)) {
611                         pr_err("error: verify failed at %#llx\n",
612                                (long long)addr);
613                         errcnt += 1;
614                         if (errcnt > 1000) {
615                                 pr_err("error: too many errors\n");
616                                 goto out;
617                         }
618                 }
619                 if (i % 256 == 0)
620                         pr_info("verified up to eraseblock %u\n", i);
621                 cond_resched();
622         }
623         pr_info("verified %u eraseblocks\n", i);
624
625         pr_info("finished with %d errors\n", errcnt);
626 out:
627         kfree(bbt);
628         kfree(writebuf);
629         kfree(readbuf);
630         put_mtd_device(mtd);
631         if (err)
632                 pr_info("error %d occurred\n", err);
633         printk(KERN_INFO "=================================================\n");
634         return err;
635 }
636 module_init(mtd_oobtest_init);
637
638 static void __exit mtd_oobtest_exit(void)
639 {
640         return;
641 }
642 module_exit(mtd_oobtest_exit);
643
644 MODULE_DESCRIPTION("Out-of-band test module");
645 MODULE_AUTHOR("Adrian Hunter");
646 MODULE_LICENSE("GPL");