Merge branch 'tracing-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6] / 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/sched.h>
29
30 #define PRINT_PREF KERN_INFO "mtd_oobtest: "
31
32 static int dev;
33 module_param(dev, int, S_IRUGO);
34 MODULE_PARM_DESC(dev, "MTD device number to use");
35
36 static struct mtd_info *mtd;
37 static unsigned char *readbuf;
38 static unsigned char *writebuf;
39 static unsigned char *bbt;
40
41 static int ebcnt;
42 static int pgcnt;
43 static int errcnt;
44 static int use_offset;
45 static int use_len;
46 static int use_len_max;
47 static int vary_offset;
48 static unsigned long next = 1;
49
50 static inline unsigned int simple_rand(void)
51 {
52         next = next * 1103515245 + 12345;
53         return (unsigned int)((next / 65536) % 32768);
54 }
55
56 static inline void simple_srand(unsigned long seed)
57 {
58         next = seed;
59 }
60
61 static void set_random_data(unsigned char *buf, size_t len)
62 {
63         size_t i;
64
65         for (i = 0; i < len; ++i)
66                 buf[i] = simple_rand();
67 }
68
69 static int erase_eraseblock(int ebnum)
70 {
71         int err;
72         struct erase_info ei;
73         loff_t addr = ebnum * mtd->erasesize;
74
75         memset(&ei, 0, sizeof(struct erase_info));
76         ei.mtd  = mtd;
77         ei.addr = addr;
78         ei.len  = mtd->erasesize;
79
80         err = mtd->erase(mtd, &ei);
81         if (err) {
82                 printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum);
83                 return err;
84         }
85
86         if (ei.state == MTD_ERASE_FAILED) {
87                 printk(PRINT_PREF "some erase error occurred at EB %d\n",
88                        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         printk(PRINT_PREF "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         printk(PRINT_PREF "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_OOB_AUTO;
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                         printk(PRINT_PREF "error: writeoob failed at %#llx\n",
144                                (long long)addr);
145                         printk(PRINT_PREF "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         printk(PRINT_PREF "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                         printk(PRINT_PREF "written up to eraseblock %u\n", i);
171                 cond_resched();
172         }
173         printk(PRINT_PREF "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_OOB_AUTO;
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                         printk(PRINT_PREF "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                         printk(PRINT_PREF "error: verify failed at %#llx\n",
203                                (long long)addr);
204                         errcnt += 1;
205                         if (errcnt > 1000) {
206                                 printk(PRINT_PREF "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_OOB_AUTO;
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                                 printk(PRINT_PREF "error: readoob failed at "
224                                        "%#llx\n", (long long)addr);
225                                 errcnt += 1;
226                                 return err ? err : -1;
227                         }
228                         if (memcmp(readbuf + use_offset, writebuf, use_len)) {
229                                 printk(PRINT_PREF "error: verify failed at "
230                                        "%#llx\n", (long long)addr);
231                                 errcnt += 1;
232                                 if (errcnt > 1000) {
233                                         printk(PRINT_PREF "error: too many "
234                                                "errors\n");
235                                         return -1;
236                                 }
237                         }
238                         for (k = 0; k < use_offset; ++k)
239                                 if (readbuf[k] != 0xff) {
240                                         printk(PRINT_PREF "error: verify 0xff "
241                                                "failed at %#llx\n",
242                                                (long long)addr);
243                                         errcnt += 1;
244                                         if (errcnt > 1000) {
245                                                 printk(PRINT_PREF "error: too "
246                                                        "many errors\n");
247                                                 return -1;
248                                         }
249                                 }
250                         for (k = use_offset + use_len;
251                              k < mtd->ecclayout->oobavail; ++k)
252                                 if (readbuf[k] != 0xff) {
253                                         printk(PRINT_PREF "error: verify 0xff "
254                                                "failed at %#llx\n",
255                                                (long long)addr);
256                                         errcnt += 1;
257                                         if (errcnt > 1000) {
258                                                 printk(PRINT_PREF "error: too "
259                                                        "many errors\n");
260                                                 return -1;
261                                         }
262                                 }
263                 }
264                 if (vary_offset)
265                         do_vary_offset();
266         }
267         return err;
268 }
269
270 static int verify_eraseblock_in_one_go(int ebnum)
271 {
272         struct mtd_oob_ops ops;
273         int err = 0;
274         loff_t addr = ebnum * mtd->erasesize;
275         size_t len = mtd->ecclayout->oobavail * pgcnt;
276
277         set_random_data(writebuf, len);
278         ops.mode      = MTD_OOB_AUTO;
279         ops.len       = 0;
280         ops.retlen    = 0;
281         ops.ooblen    = len;
282         ops.oobretlen = 0;
283         ops.ooboffs   = 0;
284         ops.datbuf    = NULL;
285         ops.oobbuf    = readbuf;
286         err = mtd->read_oob(mtd, addr, &ops);
287         if (err || ops.oobretlen != len) {
288                 printk(PRINT_PREF "error: readoob failed at %#llx\n",
289                        (long long)addr);
290                 errcnt += 1;
291                 return err ? err : -1;
292         }
293         if (memcmp(readbuf, writebuf, len)) {
294                 printk(PRINT_PREF "error: verify failed at %#llx\n",
295                        (long long)addr);
296                 errcnt += 1;
297                 if (errcnt > 1000) {
298                         printk(PRINT_PREF "error: too many errors\n");
299                         return -1;
300                 }
301         }
302
303         return err;
304 }
305
306 static int verify_all_eraseblocks(void)
307 {
308         int err;
309         unsigned int i;
310
311         printk(PRINT_PREF "verifying all eraseblocks\n");
312         for (i = 0; i < ebcnt; ++i) {
313                 if (bbt[i])
314                         continue;
315                 err = verify_eraseblock(i);
316                 if (err)
317                         return err;
318                 if (i % 256 == 0)
319                         printk(PRINT_PREF "verified up to eraseblock %u\n", i);
320                 cond_resched();
321         }
322         printk(PRINT_PREF "verified %u eraseblocks\n", i);
323         return 0;
324 }
325
326 static int is_block_bad(int ebnum)
327 {
328         int ret;
329         loff_t addr = ebnum * mtd->erasesize;
330
331         ret = mtd->block_isbad(mtd, addr);
332         if (ret)
333                 printk(PRINT_PREF "block %d is bad\n", ebnum);
334         return ret;
335 }
336
337 static int scan_for_bad_eraseblocks(void)
338 {
339         int i, bad = 0;
340
341         bbt = kmalloc(ebcnt, GFP_KERNEL);
342         if (!bbt) {
343                 printk(PRINT_PREF "error: cannot allocate memory\n");
344                 return -ENOMEM;
345         }
346         memset(bbt, 0 , ebcnt);
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         mtd->erasesize = mtd->erasesize;
396         readbuf = kmalloc(mtd->erasesize, GFP_KERNEL);
397         if (!readbuf) {
398                 printk(PRINT_PREF "error: cannot allocate memory\n");
399                 goto out;
400         }
401         writebuf = kmalloc(mtd->erasesize, GFP_KERNEL);
402         if (!writebuf) {
403                 printk(PRINT_PREF "error: cannot allocate memory\n");
404                 goto out;
405         }
406
407         err = scan_for_bad_eraseblocks();
408         if (err)
409                 goto out;
410
411         use_offset = 0;
412         use_len = mtd->ecclayout->oobavail;
413         use_len_max = mtd->ecclayout->oobavail;
414         vary_offset = 0;
415
416         /* First test: write all OOB, read it back and verify */
417         printk(PRINT_PREF "test 1 of 5\n");
418
419         err = erase_whole_device();
420         if (err)
421                 goto out;
422
423         simple_srand(1);
424         err = write_whole_device();
425         if (err)
426                 goto out;
427
428         simple_srand(1);
429         err = verify_all_eraseblocks();
430         if (err)
431                 goto out;
432
433         /*
434          * Second test: write all OOB, a block at a time, read it back and
435          * verify.
436          */
437         printk(PRINT_PREF "test 2 of 5\n");
438
439         err = erase_whole_device();
440         if (err)
441                 goto out;
442
443         simple_srand(3);
444         err = write_whole_device();
445         if (err)
446                 goto out;
447
448         /* Check all eraseblocks */
449         simple_srand(3);
450         printk(PRINT_PREF "verifying all eraseblocks\n");
451         for (i = 0; i < ebcnt; ++i) {
452                 if (bbt[i])
453                         continue;
454                 err = verify_eraseblock_in_one_go(i);
455                 if (err)
456                         goto out;
457                 if (i % 256 == 0)
458                         printk(PRINT_PREF "verified up to eraseblock %u\n", i);
459                 cond_resched();
460         }
461         printk(PRINT_PREF "verified %u eraseblocks\n", i);
462
463         /*
464          * Third test: write OOB at varying offsets and lengths, read it back
465          * and verify.
466          */
467         printk(PRINT_PREF "test 3 of 5\n");
468
469         err = erase_whole_device();
470         if (err)
471                 goto out;
472
473         /* Write all eraseblocks */
474         use_offset = 0;
475         use_len = mtd->ecclayout->oobavail;
476         use_len_max = mtd->ecclayout->oobavail;
477         vary_offset = 1;
478         simple_srand(5);
479         printk(PRINT_PREF "writing OOBs of whole device\n");
480         for (i = 0; i < ebcnt; ++i) {
481                 if (bbt[i])
482                         continue;
483                 err = write_eraseblock(i);
484                 if (err)
485                         goto out;
486                 if (i % 256 == 0)
487                         printk(PRINT_PREF "written up to eraseblock %u\n", i);
488                 cond_resched();
489         }
490         printk(PRINT_PREF "written %u eraseblocks\n", i);
491
492         /* Check all eraseblocks */
493         use_offset = 0;
494         use_len = mtd->ecclayout->oobavail;
495         use_len_max = mtd->ecclayout->oobavail;
496         vary_offset = 1;
497         simple_srand(5);
498         err = verify_all_eraseblocks();
499         if (err)
500                 goto out;
501
502         use_offset = 0;
503         use_len = mtd->ecclayout->oobavail;
504         use_len_max = mtd->ecclayout->oobavail;
505         vary_offset = 0;
506
507         /* Fourth test: try to write off end of device */
508         printk(PRINT_PREF "test 4 of 5\n");
509
510         err = erase_whole_device();
511         if (err)
512                 goto out;
513
514         addr0 = 0;
515         for (i = 0; bbt[i] && i < ebcnt; ++i)
516                 addr0 += mtd->erasesize;
517
518         /* Attempt to write off end of OOB */
519         ops.mode      = MTD_OOB_AUTO;
520         ops.len       = 0;
521         ops.retlen    = 0;
522         ops.ooblen    = 1;
523         ops.oobretlen = 0;
524         ops.ooboffs   = mtd->ecclayout->oobavail;
525         ops.datbuf    = NULL;
526         ops.oobbuf    = writebuf;
527         printk(PRINT_PREF "attempting to start write past end of OOB\n");
528         printk(PRINT_PREF "an error is expected...\n");
529         err = mtd->write_oob(mtd, addr0, &ops);
530         if (err) {
531                 printk(PRINT_PREF "error occurred as expected\n");
532                 err = 0;
533         } else {
534                 printk(PRINT_PREF "error: can write past end of OOB\n");
535                 errcnt += 1;
536         }
537
538         /* Attempt to read off end of OOB */
539         ops.mode      = MTD_OOB_AUTO;
540         ops.len       = 0;
541         ops.retlen    = 0;
542         ops.ooblen    = 1;
543         ops.oobretlen = 0;
544         ops.ooboffs   = mtd->ecclayout->oobavail;
545         ops.datbuf    = NULL;
546         ops.oobbuf    = readbuf;
547         printk(PRINT_PREF "attempting to start read past end of OOB\n");
548         printk(PRINT_PREF "an error is expected...\n");
549         err = mtd->read_oob(mtd, addr0, &ops);
550         if (err) {
551                 printk(PRINT_PREF "error occurred as expected\n");
552                 err = 0;
553         } else {
554                 printk(PRINT_PREF "error: can read past end of OOB\n");
555                 errcnt += 1;
556         }
557
558         if (bbt[ebcnt - 1])
559                 printk(PRINT_PREF "skipping end of device tests because last "
560                        "block is bad\n");
561         else {
562                 /* Attempt to write off end of device */
563                 ops.mode      = MTD_OOB_AUTO;
564                 ops.len       = 0;
565                 ops.retlen    = 0;
566                 ops.ooblen    = mtd->ecclayout->oobavail + 1;
567                 ops.oobretlen = 0;
568                 ops.ooboffs   = 0;
569                 ops.datbuf    = NULL;
570                 ops.oobbuf    = writebuf;
571                 printk(PRINT_PREF "attempting to write past end of device\n");
572                 printk(PRINT_PREF "an error is expected...\n");
573                 err = mtd->write_oob(mtd, mtd->size - mtd->writesize, &ops);
574                 if (err) {
575                         printk(PRINT_PREF "error occurred as expected\n");
576                         err = 0;
577                 } else {
578                         printk(PRINT_PREF "error: wrote past end of device\n");
579                         errcnt += 1;
580                 }
581
582                 /* Attempt to read off end of device */
583                 ops.mode      = MTD_OOB_AUTO;
584                 ops.len       = 0;
585                 ops.retlen    = 0;
586                 ops.ooblen    = mtd->ecclayout->oobavail + 1;
587                 ops.oobretlen = 0;
588                 ops.ooboffs   = 0;
589                 ops.datbuf    = NULL;
590                 ops.oobbuf    = readbuf;
591                 printk(PRINT_PREF "attempting to read past end of device\n");
592                 printk(PRINT_PREF "an error is expected...\n");
593                 err = mtd->read_oob(mtd, mtd->size - mtd->writesize, &ops);
594                 if (err) {
595                         printk(PRINT_PREF "error occurred as expected\n");
596                         err = 0;
597                 } else {
598                         printk(PRINT_PREF "error: read past end of device\n");
599                         errcnt += 1;
600                 }
601
602                 err = erase_eraseblock(ebcnt - 1);
603                 if (err)
604                         goto out;
605
606                 /* Attempt to write off end of device */
607                 ops.mode      = MTD_OOB_AUTO;
608                 ops.len       = 0;
609                 ops.retlen    = 0;
610                 ops.ooblen    = mtd->ecclayout->oobavail;
611                 ops.oobretlen = 0;
612                 ops.ooboffs   = 1;
613                 ops.datbuf    = NULL;
614                 ops.oobbuf    = writebuf;
615                 printk(PRINT_PREF "attempting to write past end of device\n");
616                 printk(PRINT_PREF "an error is expected...\n");
617                 err = mtd->write_oob(mtd, mtd->size - mtd->writesize, &ops);
618                 if (err) {
619                         printk(PRINT_PREF "error occurred as expected\n");
620                         err = 0;
621                 } else {
622                         printk(PRINT_PREF "error: wrote past end of device\n");
623                         errcnt += 1;
624                 }
625
626                 /* Attempt to read off end of device */
627                 ops.mode      = MTD_OOB_AUTO;
628                 ops.len       = 0;
629                 ops.retlen    = 0;
630                 ops.ooblen    = mtd->ecclayout->oobavail;
631                 ops.oobretlen = 0;
632                 ops.ooboffs   = 1;
633                 ops.datbuf    = NULL;
634                 ops.oobbuf    = readbuf;
635                 printk(PRINT_PREF "attempting to read past end of device\n");
636                 printk(PRINT_PREF "an error is expected...\n");
637                 err = mtd->read_oob(mtd, mtd->size - mtd->writesize, &ops);
638                 if (err) {
639                         printk(PRINT_PREF "error occurred as expected\n");
640                         err = 0;
641                 } else {
642                         printk(PRINT_PREF "error: read past end of device\n");
643                         errcnt += 1;
644                 }
645         }
646
647         /* Fifth test: write / read across block boundaries */
648         printk(PRINT_PREF "test 5 of 5\n");
649
650         /* Erase all eraseblocks */
651         err = erase_whole_device();
652         if (err)
653                 goto out;
654
655         /* Write all eraseblocks */
656         simple_srand(11);
657         printk(PRINT_PREF "writing OOBs of whole device\n");
658         for (i = 0; i < ebcnt - 1; ++i) {
659                 int cnt = 2;
660                 int pg;
661                 size_t sz = mtd->ecclayout->oobavail;
662                 if (bbt[i] || bbt[i + 1])
663                         continue;
664                 addr = (i + 1) * mtd->erasesize - mtd->writesize;
665                 for (pg = 0; pg < cnt; ++pg) {
666                         set_random_data(writebuf, sz);
667                         ops.mode      = MTD_OOB_AUTO;
668                         ops.len       = 0;
669                         ops.retlen    = 0;
670                         ops.ooblen    = sz;
671                         ops.oobretlen = 0;
672                         ops.ooboffs   = 0;
673                         ops.datbuf    = NULL;
674                         ops.oobbuf    = writebuf;
675                         err = mtd->write_oob(mtd, addr, &ops);
676                         if (err)
677                                 goto out;
678                         if (i % 256 == 0)
679                                 printk(PRINT_PREF "written up to eraseblock "
680                                        "%u\n", i);
681                         cond_resched();
682                         addr += mtd->writesize;
683                 }
684         }
685         printk(PRINT_PREF "written %u eraseblocks\n", i);
686
687         /* Check all eraseblocks */
688         simple_srand(11);
689         printk(PRINT_PREF "verifying all eraseblocks\n");
690         for (i = 0; i < ebcnt - 1; ++i) {
691                 if (bbt[i] || bbt[i + 1])
692                         continue;
693                 set_random_data(writebuf, mtd->ecclayout->oobavail * 2);
694                 addr = (i + 1) * mtd->erasesize - mtd->writesize;
695                 ops.mode      = MTD_OOB_AUTO;
696                 ops.len       = 0;
697                 ops.retlen    = 0;
698                 ops.ooblen    = mtd->ecclayout->oobavail * 2;
699                 ops.oobretlen = 0;
700                 ops.ooboffs   = 0;
701                 ops.datbuf    = NULL;
702                 ops.oobbuf    = readbuf;
703                 err = mtd->read_oob(mtd, addr, &ops);
704                 if (err)
705                         goto out;
706                 if (memcmp(readbuf, writebuf, mtd->ecclayout->oobavail * 2)) {
707                         printk(PRINT_PREF "error: verify failed at %#llx\n",
708                                (long long)addr);
709                         errcnt += 1;
710                         if (errcnt > 1000) {
711                                 printk(PRINT_PREF "error: too many errors\n");
712                                 goto out;
713                         }
714                 }
715                 if (i % 256 == 0)
716                         printk(PRINT_PREF "verified up to eraseblock %u\n", i);
717                 cond_resched();
718         }
719         printk(PRINT_PREF "verified %u eraseblocks\n", i);
720
721         printk(PRINT_PREF "finished with %d errors\n", errcnt);
722 out:
723         kfree(bbt);
724         kfree(writebuf);
725         kfree(readbuf);
726         put_mtd_device(mtd);
727         if (err)
728                 printk(PRINT_PREF "error %d occurred\n", err);
729         printk(KERN_INFO "=================================================\n");
730         return err;
731 }
732 module_init(mtd_oobtest_init);
733
734 static void __exit mtd_oobtest_exit(void)
735 {
736         return;
737 }
738 module_exit(mtd_oobtest_exit);
739
740 MODULE_DESCRIPTION("Out-of-band test module");
741 MODULE_AUTHOR("Adrian Hunter");
742 MODULE_LICENSE("GPL");