00b937e38c1d509abcda5cbd6cfc429c06b0807b
[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, 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                 return -1;
361         }
362
363         printk(PRINT_PREF "erasing block %d\n", ebnum);
364         err = erase_eraseblock(ebnum);
365         if (err)
366                 return err;
367
368         printk(PRINT_PREF "writing 1st page of block %d\n", ebnum);
369         set_random_data(writebuf, pgsize);
370         strcpy(writebuf, "There is no data like this!");
371         err = mtd->write(mtd, addr0, pgsize, &written, writebuf);
372         if (err || written != pgsize) {
373                 printk(PRINT_PREF "error: write failed at %#llx\n",
374                        (long long)addr0);
375                 return err ? err : -1;
376         }
377
378         printk(PRINT_PREF "erasing block %d\n", ebnum2);
379         err = erase_eraseblock(ebnum2);
380         if (err)
381                 return err;
382
383         printk(PRINT_PREF "reading 1st page of block %d\n", ebnum);
384         memset(readbuf, 0, pgsize);
385         err = mtd->read(mtd, addr0, pgsize, &read, readbuf);
386         if (err == -EUCLEAN)
387                 err = 0;
388         if (err || read != pgsize) {
389                 printk(PRINT_PREF "error: read failed at %#llx\n",
390                        (long long)addr0);
391                 return err ? err : -1;
392         }
393
394         printk(PRINT_PREF "verifying 1st page of block %d\n", ebnum);
395         if (memcmp(writebuf, readbuf, pgsize)) {
396                 printk(PRINT_PREF "verify failed!\n");
397                 errcnt += 1;
398                 return -1;
399         }
400
401         if (!err)
402                 printk(PRINT_PREF "erasecrosstest ok\n");
403         return err;
404 }
405
406 static int erasetest(void)
407 {
408         size_t read = 0, written = 0;
409         int err = 0, i, ebnum, ok = 1;
410         loff_t addr0;
411
412         printk(PRINT_PREF "erasetest\n");
413
414         ebnum = 0;
415         addr0 = 0;
416         for (i = 0; i < ebcnt && bbt[i]; ++i) {
417                 addr0 += mtd->erasesize;
418                 ebnum += 1;
419         }
420
421         printk(PRINT_PREF "erasing block %d\n", ebnum);
422         err = erase_eraseblock(ebnum);
423         if (err)
424                 return err;
425
426         printk(PRINT_PREF "writing 1st page of block %d\n", ebnum);
427         set_random_data(writebuf, pgsize);
428         err = mtd->write(mtd, addr0, pgsize, &written, writebuf);
429         if (err || written != pgsize) {
430                 printk(PRINT_PREF "error: write failed at %#llx\n",
431                        (long long)addr0);
432                 return err ? err : -1;
433         }
434
435         printk(PRINT_PREF "erasing block %d\n", ebnum);
436         err = erase_eraseblock(ebnum);
437         if (err)
438                 return err;
439
440         printk(PRINT_PREF "reading 1st page of block %d\n", ebnum);
441         err = mtd->read(mtd, addr0, pgsize, &read, twopages);
442         if (err == -EUCLEAN)
443                 err = 0;
444         if (err || read != pgsize) {
445                 printk(PRINT_PREF "error: read failed at %#llx\n",
446                        (long long)addr0);
447                 return err ? err : -1;
448         }
449
450         printk(PRINT_PREF "verifying 1st page of block %d is all 0xff\n",
451                ebnum);
452         for (i = 0; i < pgsize; ++i)
453                 if (twopages[i] != 0xff) {
454                         printk(PRINT_PREF "verifying all 0xff failed at %d\n",
455                                i);
456                         errcnt += 1;
457                         ok = 0;
458                         break;
459                 }
460
461         if (ok && !err)
462                 printk(PRINT_PREF "erasetest ok\n");
463
464         return err;
465 }
466
467 static int is_block_bad(int ebnum)
468 {
469         loff_t addr = ebnum * mtd->erasesize;
470         int ret;
471
472         ret = mtd->block_isbad(mtd, addr);
473         if (ret)
474                 printk(PRINT_PREF "block %d is bad\n", ebnum);
475         return ret;
476 }
477
478 static int scan_for_bad_eraseblocks(void)
479 {
480         int i, bad = 0;
481
482         bbt = kzalloc(ebcnt, GFP_KERNEL);
483         if (!bbt) {
484                 printk(PRINT_PREF "error: cannot allocate memory\n");
485                 return -ENOMEM;
486         }
487
488         printk(PRINT_PREF "scanning for bad eraseblocks\n");
489         for (i = 0; i < ebcnt; ++i) {
490                 bbt[i] = is_block_bad(i) ? 1 : 0;
491                 if (bbt[i])
492                         bad += 1;
493                 cond_resched();
494         }
495         printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad);
496         return 0;
497 }
498
499 static int __init mtd_pagetest_init(void)
500 {
501         int err = 0;
502         uint64_t tmp;
503         uint32_t i;
504
505         printk(KERN_INFO "\n");
506         printk(KERN_INFO "=================================================\n");
507         printk(PRINT_PREF "MTD device: %d\n", dev);
508
509         mtd = get_mtd_device(NULL, dev);
510         if (IS_ERR(mtd)) {
511                 err = PTR_ERR(mtd);
512                 printk(PRINT_PREF "error: cannot get MTD device\n");
513                 return err;
514         }
515
516         if (mtd->type != MTD_NANDFLASH) {
517                 printk(PRINT_PREF "this test requires NAND flash\n");
518                 goto out;
519         }
520
521         tmp = mtd->size;
522         do_div(tmp, mtd->erasesize);
523         ebcnt = tmp;
524         pgcnt = mtd->erasesize / mtd->writesize;
525         pgsize = mtd->writesize;
526
527         printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
528                "page size %u, count of eraseblocks %u, pages per "
529                "eraseblock %u, OOB size %u\n",
530                (unsigned long long)mtd->size, mtd->erasesize,
531                pgsize, ebcnt, pgcnt, mtd->oobsize);
532
533         err = -ENOMEM;
534         bufsize = pgsize * 2;
535         writebuf = kmalloc(mtd->erasesize, GFP_KERNEL);
536         if (!writebuf) {
537                 printk(PRINT_PREF "error: cannot allocate memory\n");
538                 goto out;
539         }
540         twopages = kmalloc(bufsize, GFP_KERNEL);
541         if (!twopages) {
542                 printk(PRINT_PREF "error: cannot allocate memory\n");
543                 goto out;
544         }
545         boundary = kmalloc(bufsize, GFP_KERNEL);
546         if (!boundary) {
547                 printk(PRINT_PREF "error: cannot allocate memory\n");
548                 goto out;
549         }
550
551         err = scan_for_bad_eraseblocks();
552         if (err)
553                 goto out;
554
555         /* Erase all eraseblocks */
556         printk(PRINT_PREF "erasing whole device\n");
557         for (i = 0; i < ebcnt; ++i) {
558                 if (bbt[i])
559                         continue;
560                 err = erase_eraseblock(i);
561                 if (err)
562                         goto out;
563                 cond_resched();
564         }
565         printk(PRINT_PREF "erased %u eraseblocks\n", i);
566
567         /* Write all eraseblocks */
568         simple_srand(1);
569         printk(PRINT_PREF "writing whole device\n");
570         for (i = 0; i < ebcnt; ++i) {
571                 if (bbt[i])
572                         continue;
573                 err = write_eraseblock(i);
574                 if (err)
575                         goto out;
576                 if (i % 256 == 0)
577                         printk(PRINT_PREF "written up to eraseblock %u\n", i);
578                 cond_resched();
579         }
580         printk(PRINT_PREF "written %u eraseblocks\n", i);
581
582         /* Check all eraseblocks */
583         simple_srand(1);
584         printk(PRINT_PREF "verifying all eraseblocks\n");
585         for (i = 0; i < ebcnt; ++i) {
586                 if (bbt[i])
587                         continue;
588                 err = verify_eraseblock(i);
589                 if (err)
590                         goto out;
591                 if (i % 256 == 0)
592                         printk(PRINT_PREF "verified up to eraseblock %u\n", i);
593                 cond_resched();
594         }
595         printk(PRINT_PREF "verified %u eraseblocks\n", i);
596
597         err = crosstest();
598         if (err)
599                 goto out;
600
601         err = erasecrosstest();
602         if (err)
603                 goto out;
604
605         err = erasetest();
606         if (err)
607                 goto out;
608
609         printk(PRINT_PREF "finished with %d errors\n", errcnt);
610 out:
611
612         kfree(bbt);
613         kfree(boundary);
614         kfree(twopages);
615         kfree(writebuf);
616         put_mtd_device(mtd);
617         if (err)
618                 printk(PRINT_PREF "error %d occurred\n", err);
619         printk(KERN_INFO "=================================================\n");
620         return err;
621 }
622 module_init(mtd_pagetest_init);
623
624 static void __exit mtd_pagetest_exit(void)
625 {
626         return;
627 }
628 module_exit(mtd_pagetest_exit);
629
630 MODULE_DESCRIPTION("NAND page test");
631 MODULE_AUTHOR("Adrian Hunter");
632 MODULE_LICENSE("GPL");