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