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