Merge branch 'fix/hda' into for-linus
[pandora-kernel.git] / drivers / mtd / tests / mtd_pagetest.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 page 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_pagetest: "
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 *twopages;
39 static unsigned char *writebuf;
40 static unsigned char *boundary;
41 static unsigned char *bbt;
42
43 static int pgsize;
44 static int bufsize;
45 static int ebcnt;
46 static int pgcnt;
47 static int errcnt;
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 write_eraseblock(int ebnum)
96 {
97         int err = 0;
98         size_t written = 0;
99         loff_t addr = ebnum * mtd->erasesize;
100
101         set_random_data(writebuf, mtd->erasesize);
102         cond_resched();
103         err = mtd->write(mtd, addr, mtd->erasesize, &written, writebuf);
104         if (err || written != mtd->erasesize)
105                 printk(PRINT_PREF "error: write failed at %#llx\n",
106                        (long long)addr);
107
108         return err;
109 }
110
111 static int verify_eraseblock(int ebnum)
112 {
113         uint32_t j;
114         size_t read = 0;
115         int err = 0, i;
116         loff_t addr0, addrn;
117         loff_t addr = ebnum * mtd->erasesize;
118
119         addr0 = 0;
120         for (i = 0; i < ebcnt && bbt[i]; ++i)
121                 addr0 += mtd->erasesize;
122
123         addrn = mtd->size;
124         for (i = 0; i < ebcnt && bbt[ebcnt - i - 1]; ++i)
125                 addrn -= mtd->erasesize;
126
127         set_random_data(writebuf, mtd->erasesize);
128         for (j = 0; j < pgcnt - 1; ++j, addr += pgsize) {
129                 /* Do a read to set the internal dataRAMs to different data */
130                 err = mtd->read(mtd, addr0, bufsize, &read, twopages);
131                 if (err == -EUCLEAN)
132                         err = 0;
133                 if (err || read != bufsize) {
134                         printk(PRINT_PREF "error: read failed at %#llx\n",
135                                (long long)addr0);
136                         return err;
137                 }
138                 err = mtd->read(mtd, addrn - bufsize, bufsize, &read, twopages);
139                 if (err == -EUCLEAN)
140                         err = 0;
141                 if (err || read != bufsize) {
142                         printk(PRINT_PREF "error: read failed at %#llx\n",
143                                (long long)(addrn - bufsize));
144                         return err;
145                 }
146                 memset(twopages, 0, bufsize);
147                 read = 0;
148                 err = mtd->read(mtd, addr, bufsize, &read, twopages);
149                 if (err == -EUCLEAN)
150                         err = 0;
151                 if (err || read != bufsize) {
152                         printk(PRINT_PREF "error: read failed at %#llx\n",
153                                (long long)addr);
154                         break;
155                 }
156                 if (memcmp(twopages, writebuf + (j * pgsize), bufsize)) {
157                         printk(PRINT_PREF "error: verify failed at %#llx\n",
158                                (long long)addr);
159                         errcnt += 1;
160                 }
161         }
162         /* Check boundary between eraseblocks */
163         if (addr <= addrn - pgsize - pgsize && !bbt[ebnum + 1]) {
164                 unsigned long oldnext = next;
165                 /* Do a read to set the internal dataRAMs to different data */
166                 err = mtd->read(mtd, addr0, bufsize, &read, twopages);
167                 if (err == -EUCLEAN)
168                         err = 0;
169                 if (err || read != bufsize) {
170                         printk(PRINT_PREF "error: read failed at %#llx\n",
171                                (long long)addr0);
172                         return err;
173                 }
174                 err = mtd->read(mtd, addrn - bufsize, bufsize, &read, twopages);
175                 if (err == -EUCLEAN)
176                         err = 0;
177                 if (err || read != bufsize) {
178                         printk(PRINT_PREF "error: read failed at %#llx\n",
179                                (long long)(addrn - bufsize));
180                         return err;
181                 }
182                 memset(twopages, 0, bufsize);
183                 read = 0;
184                 err = mtd->read(mtd, addr, bufsize, &read, twopages);
185                 if (err == -EUCLEAN)
186                         err = 0;
187                 if (err || read != bufsize) {
188                         printk(PRINT_PREF "error: read failed at %#llx\n",
189                                (long long)addr);
190                         return err;
191                 }
192                 memcpy(boundary, writebuf + mtd->erasesize - pgsize, pgsize);
193                 set_random_data(boundary + pgsize, pgsize);
194                 if (memcmp(twopages, boundary, bufsize)) {
195                         printk(PRINT_PREF "error: verify failed at %#llx\n",
196                                (long long)addr);
197                         errcnt += 1;
198                 }
199                 next = oldnext;
200         }
201         return err;
202 }
203
204 static int crosstest(void)
205 {
206         size_t read = 0;
207         int err = 0, i;
208         loff_t addr, addr0, addrn;
209         unsigned char *pp1, *pp2, *pp3, *pp4;
210
211         printk(PRINT_PREF "crosstest\n");
212         pp1 = kmalloc(pgsize * 4, GFP_KERNEL);
213         if (!pp1) {
214                 printk(PRINT_PREF "error: cannot allocate memory\n");
215                 return -ENOMEM;
216         }
217         pp2 = pp1 + pgsize;
218         pp3 = pp2 + pgsize;
219         pp4 = pp3 + pgsize;
220         memset(pp1, 0, pgsize * 4);
221
222         addr0 = 0;
223         for (i = 0; i < ebcnt && bbt[i]; ++i)
224                 addr0 += mtd->erasesize;
225
226         addrn = mtd->size;
227         for (i = 0; i < ebcnt && bbt[ebcnt - i - 1]; ++i)
228                 addrn -= mtd->erasesize;
229
230         /* Read 2nd-to-last page to pp1 */
231         read = 0;
232         addr = addrn - pgsize - pgsize;
233         err = mtd->read(mtd, addr, pgsize, &read, pp1);
234         if (err == -EUCLEAN)
235                 err = 0;
236         if (err || read != pgsize) {
237                 printk(PRINT_PREF "error: read failed at %#llx\n",
238                        (long long)addr);
239                 kfree(pp1);
240                 return err;
241         }
242
243         /* Read 3rd-to-last page to pp1 */
244         read = 0;
245         addr = addrn - pgsize - pgsize - pgsize;
246         err = mtd->read(mtd, addr, pgsize, &read, pp1);
247         if (err == -EUCLEAN)
248                 err = 0;
249         if (err || read != pgsize) {
250                 printk(PRINT_PREF "error: read failed at %#llx\n",
251                        (long long)addr);
252                 kfree(pp1);
253                 return err;
254         }
255
256         /* Read first page to pp2 */
257         read = 0;
258         addr = addr0;
259         printk(PRINT_PREF "reading page at %#llx\n", (long long)addr);
260         err = mtd->read(mtd, addr, pgsize, &read, pp2);
261         if (err == -EUCLEAN)
262                 err = 0;
263         if (err || read != pgsize) {
264                 printk(PRINT_PREF "error: read failed at %#llx\n",
265                        (long long)addr);
266                 kfree(pp1);
267                 return err;
268         }
269
270         /* Read last page to pp3 */
271         read = 0;
272         addr = addrn - pgsize;
273         printk(PRINT_PREF "reading page at %#llx\n", (long long)addr);
274         err = mtd->read(mtd, addr, pgsize, &read, pp3);
275         if (err == -EUCLEAN)
276                 err = 0;
277         if (err || read != pgsize) {
278                 printk(PRINT_PREF "error: read failed at %#llx\n",
279                        (long long)addr);
280                 kfree(pp1);
281                 return err;
282         }
283
284         /* Read first page again to pp4 */
285         read = 0;
286         addr = addr0;
287         printk(PRINT_PREF "reading page at %#llx\n", (long long)addr);
288         err = mtd->read(mtd, addr, pgsize, &read, pp4);
289         if (err == -EUCLEAN)
290                 err = 0;
291         if (err || read != pgsize) {
292                 printk(PRINT_PREF "error: read failed at %#llx\n",
293                        (long long)addr);
294                 kfree(pp1);
295                 return err;
296         }
297
298         /* pp2 and pp4 should be the same */
299         printk(PRINT_PREF "verifying pages read at %#llx match\n",
300                (long long)addr0);
301         if (memcmp(pp2, pp4, pgsize)) {
302                 printk(PRINT_PREF "verify failed!\n");
303                 errcnt += 1;
304         } else if (!err)
305                 printk(PRINT_PREF "crosstest ok\n");
306         kfree(pp1);
307         return err;
308 }
309
310 static int erasecrosstest(void)
311 {
312         size_t read = 0, written = 0;
313         int err = 0, i, ebnum, ok = 1, ebnum2;
314         loff_t addr0;
315         char *readbuf = twopages;
316
317         printk(PRINT_PREF "erasecrosstest\n");
318
319         ebnum = 0;
320         addr0 = 0;
321         for (i = 0; i < ebcnt && bbt[i]; ++i) {
322                 addr0 += mtd->erasesize;
323                 ebnum += 1;
324         }
325
326         ebnum2 = ebcnt - 1;
327         while (ebnum2 && bbt[ebnum2])
328                 ebnum2 -= 1;
329
330         printk(PRINT_PREF "erasing block %d\n", ebnum);
331         err = erase_eraseblock(ebnum);
332         if (err)
333                 return err;
334
335         printk(PRINT_PREF "writing 1st page of block %d\n", ebnum);
336         set_random_data(writebuf, pgsize);
337         strcpy(writebuf, "There is no data like this!");
338         err = mtd->write(mtd, addr0, pgsize, &written, writebuf);
339         if (err || written != pgsize) {
340                 printk(PRINT_PREF "error: write failed at %#llx\n",
341                        (long long)addr0);
342                 return err ? err : -1;
343         }
344
345         printk(PRINT_PREF "reading 1st page of block %d\n", ebnum);
346         memset(readbuf, 0, pgsize);
347         err = mtd->read(mtd, addr0, pgsize, &read, readbuf);
348         if (err == -EUCLEAN)
349                 err = 0;
350         if (err || read != pgsize) {
351                 printk(PRINT_PREF "error: read failed at %#llx\n",
352                        (long long)addr0);
353                 return err ? err : -1;
354         }
355
356         printk(PRINT_PREF "verifying 1st page of block %d\n", ebnum);
357         if (memcmp(writebuf, readbuf, pgsize)) {
358                 printk(PRINT_PREF "verify failed!\n");
359                 errcnt += 1;
360                 ok = 0;
361                 return err;
362         }
363
364         printk(PRINT_PREF "erasing block %d\n", ebnum);
365         err = erase_eraseblock(ebnum);
366         if (err)
367                 return err;
368
369         printk(PRINT_PREF "writing 1st page of block %d\n", ebnum);
370         set_random_data(writebuf, pgsize);
371         strcpy(writebuf, "There is no data like this!");
372         err = mtd->write(mtd, addr0, pgsize, &written, writebuf);
373         if (err || written != pgsize) {
374                 printk(PRINT_PREF "error: write failed at %#llx\n",
375                        (long long)addr0);
376                 return err ? err : -1;
377         }
378
379         printk(PRINT_PREF "erasing block %d\n", ebnum2);
380         err = erase_eraseblock(ebnum2);
381         if (err)
382                 return err;
383
384         printk(PRINT_PREF "reading 1st page of block %d\n", ebnum);
385         memset(readbuf, 0, pgsize);
386         err = mtd->read(mtd, addr0, pgsize, &read, readbuf);
387         if (err == -EUCLEAN)
388                 err = 0;
389         if (err || read != pgsize) {
390                 printk(PRINT_PREF "error: read failed at %#llx\n",
391                        (long long)addr0);
392                 return err ? err : -1;
393         }
394
395         printk(PRINT_PREF "verifying 1st page of block %d\n", ebnum);
396         if (memcmp(writebuf, readbuf, pgsize)) {
397                 printk(PRINT_PREF "verify failed!\n");
398                 errcnt += 1;
399                 ok = 0;
400         }
401
402         if (ok && !err)
403                 printk(PRINT_PREF "erasecrosstest ok\n");
404         return err;
405 }
406
407 static int erasetest(void)
408 {
409         size_t read = 0, written = 0;
410         int err = 0, i, ebnum, ok = 1;
411         loff_t addr0;
412
413         printk(PRINT_PREF "erasetest\n");
414
415         ebnum = 0;
416         addr0 = 0;
417         for (i = 0; i < ebcnt && bbt[i]; ++i) {
418                 addr0 += mtd->erasesize;
419                 ebnum += 1;
420         }
421
422         printk(PRINT_PREF "erasing block %d\n", ebnum);
423         err = erase_eraseblock(ebnum);
424         if (err)
425                 return err;
426
427         printk(PRINT_PREF "writing 1st page of block %d\n", ebnum);
428         set_random_data(writebuf, pgsize);
429         err = mtd->write(mtd, addr0, pgsize, &written, writebuf);
430         if (err || written != pgsize) {
431                 printk(PRINT_PREF "error: write failed at %#llx\n",
432                        (long long)addr0);
433                 return err ? err : -1;
434         }
435
436         printk(PRINT_PREF "erasing block %d\n", ebnum);
437         err = erase_eraseblock(ebnum);
438         if (err)
439                 return err;
440
441         printk(PRINT_PREF "reading 1st page of block %d\n", ebnum);
442         err = mtd->read(mtd, addr0, pgsize, &read, twopages);
443         if (err == -EUCLEAN)
444                 err = 0;
445         if (err || read != pgsize) {
446                 printk(PRINT_PREF "error: read failed at %#llx\n",
447                        (long long)addr0);
448                 return err ? err : -1;
449         }
450
451         printk(PRINT_PREF "verifying 1st page of block %d is all 0xff\n",
452                ebnum);
453         for (i = 0; i < pgsize; ++i)
454                 if (twopages[i] != 0xff) {
455                         printk(PRINT_PREF "verifying all 0xff failed at %d\n",
456                                i);
457                         errcnt += 1;
458                         ok = 0;
459                         break;
460                 }
461
462         if (ok && !err)
463                 printk(PRINT_PREF "erasetest ok\n");
464
465         return err;
466 }
467
468 static int is_block_bad(int ebnum)
469 {
470         loff_t addr = ebnum * mtd->erasesize;
471         int ret;
472
473         ret = mtd->block_isbad(mtd, addr);
474         if (ret)
475                 printk(PRINT_PREF "block %d is bad\n", ebnum);
476         return ret;
477 }
478
479 static int scan_for_bad_eraseblocks(void)
480 {
481         int i, bad = 0;
482
483         bbt = kmalloc(ebcnt, GFP_KERNEL);
484         if (!bbt) {
485                 printk(PRINT_PREF "error: cannot allocate memory\n");
486                 return -ENOMEM;
487         }
488         memset(bbt, 0 , ebcnt);
489
490         printk(PRINT_PREF "scanning for bad eraseblocks\n");
491         for (i = 0; i < ebcnt; ++i) {
492                 bbt[i] = is_block_bad(i) ? 1 : 0;
493                 if (bbt[i])
494                         bad += 1;
495                 cond_resched();
496         }
497         printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad);
498         return 0;
499 }
500
501 static int __init mtd_pagetest_init(void)
502 {
503         int err = 0;
504         uint64_t tmp;
505         uint32_t i;
506
507         printk(KERN_INFO "\n");
508         printk(KERN_INFO "=================================================\n");
509         printk(PRINT_PREF "MTD device: %d\n", dev);
510
511         mtd = get_mtd_device(NULL, dev);
512         if (IS_ERR(mtd)) {
513                 err = PTR_ERR(mtd);
514                 printk(PRINT_PREF "error: cannot get MTD device\n");
515                 return err;
516         }
517
518         if (mtd->type != MTD_NANDFLASH) {
519                 printk(PRINT_PREF "this test requires NAND flash\n");
520                 goto out;
521         }
522
523         tmp = mtd->size;
524         do_div(tmp, mtd->erasesize);
525         ebcnt = tmp;
526         pgcnt = mtd->erasesize / mtd->writesize;
527         pgsize = mtd->writesize;
528
529         printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
530                "page size %u, count of eraseblocks %u, pages per "
531                "eraseblock %u, OOB size %u\n",
532                (unsigned long long)mtd->size, mtd->erasesize,
533                pgsize, ebcnt, pgcnt, mtd->oobsize);
534
535         err = -ENOMEM;
536         bufsize = pgsize * 2;
537         writebuf = kmalloc(mtd->erasesize, GFP_KERNEL);
538         if (!writebuf) {
539                 printk(PRINT_PREF "error: cannot allocate memory\n");
540                 goto out;
541         }
542         twopages = kmalloc(bufsize, GFP_KERNEL);
543         if (!twopages) {
544                 printk(PRINT_PREF "error: cannot allocate memory\n");
545                 goto out;
546         }
547         boundary = kmalloc(bufsize, GFP_KERNEL);
548         if (!boundary) {
549                 printk(PRINT_PREF "error: cannot allocate memory\n");
550                 goto out;
551         }
552
553         err = scan_for_bad_eraseblocks();
554         if (err)
555                 goto out;
556
557         /* Erase all eraseblocks */
558         printk(PRINT_PREF "erasing whole device\n");
559         for (i = 0; i < ebcnt; ++i) {
560                 if (bbt[i])
561                         continue;
562                 err = erase_eraseblock(i);
563                 if (err)
564                         goto out;
565                 cond_resched();
566         }
567         printk(PRINT_PREF "erased %u eraseblocks\n", i);
568
569         /* Write all eraseblocks */
570         simple_srand(1);
571         printk(PRINT_PREF "writing whole device\n");
572         for (i = 0; i < ebcnt; ++i) {
573                 if (bbt[i])
574                         continue;
575                 err = write_eraseblock(i);
576                 if (err)
577                         goto out;
578                 if (i % 256 == 0)
579                         printk(PRINT_PREF "written up to eraseblock %u\n", i);
580                 cond_resched();
581         }
582         printk(PRINT_PREF "written %u eraseblocks\n", i);
583
584         /* Check all eraseblocks */
585         simple_srand(1);
586         printk(PRINT_PREF "verifying all eraseblocks\n");
587         for (i = 0; i < ebcnt; ++i) {
588                 if (bbt[i])
589                         continue;
590                 err = verify_eraseblock(i);
591                 if (err)
592                         goto out;
593                 if (i % 256 == 0)
594                         printk(PRINT_PREF "verified up to eraseblock %u\n", i);
595                 cond_resched();
596         }
597         printk(PRINT_PREF "verified %u eraseblocks\n", i);
598
599         err = crosstest();
600         if (err)
601                 goto out;
602
603         err = erasecrosstest();
604         if (err)
605                 goto out;
606
607         err = erasetest();
608         if (err)
609                 goto out;
610
611         printk(PRINT_PREF "finished with %d errors\n", errcnt);
612 out:
613
614         kfree(bbt);
615         kfree(boundary);
616         kfree(twopages);
617         kfree(writebuf);
618         put_mtd_device(mtd);
619         if (err)
620                 printk(PRINT_PREF "error %d occurred\n", err);
621         printk(KERN_INFO "=================================================\n");
622         return err;
623 }
624 module_init(mtd_pagetest_init);
625
626 static void __exit mtd_pagetest_exit(void)
627 {
628         return;
629 }
630 module_exit(mtd_pagetest_exit);
631
632 MODULE_DESCRIPTION("NAND page test");
633 MODULE_AUTHOR("Adrian Hunter");
634 MODULE_LICENSE("GPL");