]> bbs.cooldavid.org Git - net-next-2.6.git/blob - drivers/mtd/tests/mtd_pagetest.c
ce17cbe918c5a1e4fe411a51eb7d92eafa22308e
[net-next-2.6.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/sched.h>
29
30 #define PRINT_PREF KERN_INFO "mtd_pagetest: "
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 *twopages;
38 static unsigned char *writebuf;
39 static unsigned char *boundary;
40 static unsigned char *bbt;
41
42 static int pgsize;
43 static int bufsize;
44 static int ebcnt;
45 static int pgcnt;
46 static int errcnt;
47 static unsigned long next = 1;
48
49 static inline unsigned int simple_rand(void)
50 {
51         next = next * 1103515245 + 12345;
52         return (unsigned int)((next / 65536) % 32768);
53 }
54
55 static inline void simple_srand(unsigned long seed)
56 {
57         next = seed;
58 }
59
60 static void set_random_data(unsigned char *buf, size_t len)
61 {
62         size_t i;
63
64         for (i = 0; i < len; ++i)
65                 buf[i] = simple_rand();
66 }
67
68 static int erase_eraseblock(int ebnum)
69 {
70         int err;
71         struct erase_info ei;
72         loff_t addr = ebnum * mtd->erasesize;
73
74         memset(&ei, 0, sizeof(struct erase_info));
75         ei.mtd  = mtd;
76         ei.addr = addr;
77         ei.len  = mtd->erasesize;
78
79         err = mtd->erase(mtd, &ei);
80         if (err) {
81                 printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum);
82                 return err;
83         }
84
85         if (ei.state == MTD_ERASE_FAILED) {
86                 printk(PRINT_PREF "some erase error occurred at EB %d\n",
87                        ebnum);
88                 return -EIO;
89         }
90
91         return 0;
92 }
93
94 static int write_eraseblock(int ebnum)
95 {
96         int err = 0;
97         size_t written = 0;
98         loff_t addr = ebnum * mtd->erasesize;
99
100         set_random_data(writebuf, mtd->erasesize);
101         cond_resched();
102         err = mtd->write(mtd, addr, mtd->erasesize, &written, writebuf);
103         if (err || written != mtd->erasesize)
104                 printk(PRINT_PREF "error: write failed at %#llx\n",
105                        (long long)addr);
106
107         return err;
108 }
109
110 static int verify_eraseblock(int ebnum)
111 {
112         uint32_t j;
113         size_t read = 0;
114         int err = 0, i;
115         loff_t addr0, addrn;
116         loff_t addr = ebnum * mtd->erasesize;
117
118         addr0 = 0;
119         for (i = 0; i < ebcnt && bbt[i]; ++i)
120                 addr0 += mtd->erasesize;
121
122         addrn = mtd->size;
123         for (i = 0; i < ebcnt && bbt[ebcnt - i - 1]; ++i)
124                 addrn -= mtd->erasesize;
125
126         set_random_data(writebuf, mtd->erasesize);
127         for (j = 0; j < pgcnt - 1; ++j, addr += pgsize) {
128                 /* Do a read to set the internal dataRAMs to different data */
129                 err = mtd->read(mtd, addr0, bufsize, &read, twopages);
130                 if (err == -EUCLEAN)
131                         err = 0;
132                 if (err || read != bufsize) {
133                         printk(PRINT_PREF "error: read failed at %#llx\n",
134                                (long long)addr0);
135                         return err;
136                 }
137                 err = mtd->read(mtd, addrn - bufsize, bufsize, &read, twopages);
138                 if (err == -EUCLEAN)
139                         err = 0;
140                 if (err || read != bufsize) {
141                         printk(PRINT_PREF "error: read failed at %#llx\n",
142                                (long long)(addrn - bufsize));
143                         return err;
144                 }
145                 memset(twopages, 0, bufsize);
146                 read = 0;
147                 err = mtd->read(mtd, addr, bufsize, &read, twopages);
148                 if (err == -EUCLEAN)
149                         err = 0;
150                 if (err || read != bufsize) {
151                         printk(PRINT_PREF "error: read failed at %#llx\n",
152                                (long long)addr);
153                         break;
154                 }
155                 if (memcmp(twopages, writebuf + (j * pgsize), bufsize)) {
156                         printk(PRINT_PREF "error: verify failed at %#llx\n",
157                                (long long)addr);
158                         errcnt += 1;
159                 }
160         }
161         /* Check boundary between eraseblocks */
162         if (addr <= addrn - pgsize - pgsize && !bbt[ebnum + 1]) {
163                 unsigned long oldnext = next;
164                 /* Do a read to set the internal dataRAMs to different data */
165                 err = mtd->read(mtd, addr0, bufsize, &read, twopages);
166                 if (err == -EUCLEAN)
167                         err = 0;
168                 if (err || read != bufsize) {
169                         printk(PRINT_PREF "error: read failed at %#llx\n",
170                                (long long)addr0);
171                         return err;
172                 }
173                 err = mtd->read(mtd, addrn - bufsize, bufsize, &read, twopages);
174                 if (err == -EUCLEAN)
175                         err = 0;
176                 if (err || read != bufsize) {
177                         printk(PRINT_PREF "error: read failed at %#llx\n",
178                                (long long)(addrn - bufsize));
179                         return err;
180                 }
181                 memset(twopages, 0, bufsize);
182                 read = 0;
183                 err = mtd->read(mtd, addr, bufsize, &read, twopages);
184                 if (err == -EUCLEAN)
185                         err = 0;
186                 if (err || read != bufsize) {
187                         printk(PRINT_PREF "error: read failed at %#llx\n",
188                                (long long)addr);
189                         return err;
190                 }
191                 memcpy(boundary, writebuf + mtd->erasesize - pgsize, pgsize);
192                 set_random_data(boundary + pgsize, pgsize);
193                 if (memcmp(twopages, boundary, bufsize)) {
194                         printk(PRINT_PREF "error: verify failed at %#llx\n",
195                                (long long)addr);
196                         errcnt += 1;
197                 }
198                 next = oldnext;
199         }
200         return err;
201 }
202
203 static int crosstest(void)
204 {
205         size_t read = 0;
206         int err = 0, i;
207         loff_t addr, addr0, addrn;
208         unsigned char *pp1, *pp2, *pp3, *pp4;
209
210         printk(PRINT_PREF "crosstest\n");
211         pp1 = kmalloc(pgsize * 4, GFP_KERNEL);
212         if (!pp1) {
213                 printk(PRINT_PREF "error: cannot allocate memory\n");
214                 return -ENOMEM;
215         }
216         pp2 = pp1 + pgsize;
217         pp3 = pp2 + pgsize;
218         pp4 = pp3 + pgsize;
219         memset(pp1, 0, pgsize * 4);
220
221         addr0 = 0;
222         for (i = 0; i < ebcnt && bbt[i]; ++i)
223                 addr0 += mtd->erasesize;
224
225         addrn = mtd->size;
226         for (i = 0; i < ebcnt && bbt[ebcnt - i - 1]; ++i)
227                 addrn -= mtd->erasesize;
228
229         /* Read 2nd-to-last page to pp1 */
230         read = 0;
231         addr = addrn - pgsize - pgsize;
232         err = mtd->read(mtd, addr, pgsize, &read, pp1);
233         if (err == -EUCLEAN)
234                 err = 0;
235         if (err || read != pgsize) {
236                 printk(PRINT_PREF "error: read failed at %#llx\n",
237                        (long long)addr);
238                 kfree(pp1);
239                 return err;
240         }
241
242         /* Read 3rd-to-last page to pp1 */
243         read = 0;
244         addr = addrn - pgsize - pgsize - pgsize;
245         err = mtd->read(mtd, addr, pgsize, &read, pp1);
246         if (err == -EUCLEAN)
247                 err = 0;
248         if (err || read != pgsize) {
249                 printk(PRINT_PREF "error: read failed at %#llx\n",
250                        (long long)addr);
251                 kfree(pp1);
252                 return err;
253         }
254
255         /* Read first page to pp2 */
256         read = 0;
257         addr = addr0;
258         printk(PRINT_PREF "reading page at %#llx\n", (long long)addr);
259         err = mtd->read(mtd, addr, pgsize, &read, pp2);
260         if (err == -EUCLEAN)
261                 err = 0;
262         if (err || read != pgsize) {
263                 printk(PRINT_PREF "error: read failed at %#llx\n",
264                        (long long)addr);
265                 kfree(pp1);
266                 return err;
267         }
268
269         /* Read last page to pp3 */
270         read = 0;
271         addr = addrn - pgsize;
272         printk(PRINT_PREF "reading page at %#llx\n", (long long)addr);
273         err = mtd->read(mtd, addr, pgsize, &read, pp3);
274         if (err == -EUCLEAN)
275                 err = 0;
276         if (err || read != pgsize) {
277                 printk(PRINT_PREF "error: read failed at %#llx\n",
278                        (long long)addr);
279                 kfree(pp1);
280                 return err;
281         }
282
283         /* Read first page again to pp4 */
284         read = 0;
285         addr = addr0;
286         printk(PRINT_PREF "reading page at %#llx\n", (long long)addr);
287         err = mtd->read(mtd, addr, pgsize, &read, pp4);
288         if (err == -EUCLEAN)
289                 err = 0;
290         if (err || read != pgsize) {
291                 printk(PRINT_PREF "error: read failed at %#llx\n",
292                        (long long)addr);
293                 kfree(pp1);
294                 return err;
295         }
296
297         /* pp2 and pp4 should be the same */
298         printk(PRINT_PREF "verifying pages read at %#llx match\n",
299                (long long)addr0);
300         if (memcmp(pp2, pp4, pgsize)) {
301                 printk(PRINT_PREF "verify failed!\n");
302                 errcnt += 1;
303         } else if (!err)
304                 printk(PRINT_PREF "crosstest ok\n");
305         kfree(pp1);
306         return err;
307 }
308
309 static int erasecrosstest(void)
310 {
311         size_t read = 0, written = 0;
312         int err = 0, i, ebnum, ok = 1, ebnum2;
313         loff_t addr0;
314         char *readbuf = twopages;
315
316         printk(PRINT_PREF "erasecrosstest\n");
317
318         ebnum = 0;
319         addr0 = 0;
320         for (i = 0; i < ebcnt && bbt[i]; ++i) {
321                 addr0 += mtd->erasesize;
322                 ebnum += 1;
323         }
324
325         ebnum2 = ebcnt - 1;
326         while (ebnum2 && bbt[ebnum2])
327                 ebnum2 -= 1;
328
329         printk(PRINT_PREF "erasing block %d\n", ebnum);
330         err = erase_eraseblock(ebnum);
331         if (err)
332                 return err;
333
334         printk(PRINT_PREF "writing 1st page of block %d\n", ebnum);
335         set_random_data(writebuf, pgsize);
336         strcpy(writebuf, "There is no data like this!");
337         err = mtd->write(mtd, addr0, pgsize, &written, writebuf);
338         if (err || written != pgsize) {
339                 printk(PRINT_PREF "error: write failed at %#llx\n",
340                        (long long)addr0);
341                 return err ? err : -1;
342         }
343
344         printk(PRINT_PREF "reading 1st page of block %d\n", ebnum);
345         memset(readbuf, 0, pgsize);
346         err = mtd->read(mtd, addr0, pgsize, &read, readbuf);
347         if (err == -EUCLEAN)
348                 err = 0;
349         if (err || read != pgsize) {
350                 printk(PRINT_PREF "error: read failed at %#llx\n",
351                        (long long)addr0);
352                 return err ? err : -1;
353         }
354
355         printk(PRINT_PREF "verifying 1st page of block %d\n", ebnum);
356         if (memcmp(writebuf, readbuf, pgsize)) {
357                 printk(PRINT_PREF "verify failed!\n");
358                 errcnt += 1;
359                 ok = 0;
360                 return err;
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                 ok = 0;
399         }
400
401         if (ok && !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 = kmalloc(ebcnt, GFP_KERNEL);
483         if (!bbt) {
484                 printk(PRINT_PREF "error: cannot allocate memory\n");
485                 return -ENOMEM;
486         }
487         memset(bbt, 0 , ebcnt);
488
489         printk(PRINT_PREF "scanning for bad eraseblocks\n");
490         for (i = 0; i < ebcnt; ++i) {
491                 bbt[i] = is_block_bad(i) ? 1 : 0;
492                 if (bbt[i])
493                         bad += 1;
494                 cond_resched();
495         }
496         printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad);
497         return 0;
498 }
499
500 static int __init mtd_pagetest_init(void)
501 {
502         int err = 0;
503         uint64_t tmp;
504         uint32_t i;
505
506         printk(KERN_INFO "\n");
507         printk(KERN_INFO "=================================================\n");
508         printk(PRINT_PREF "MTD device: %d\n", dev);
509
510         mtd = get_mtd_device(NULL, dev);
511         if (IS_ERR(mtd)) {
512                 err = PTR_ERR(mtd);
513                 printk(PRINT_PREF "error: cannot get MTD device\n");
514                 return err;
515         }
516
517         if (mtd->type != MTD_NANDFLASH) {
518                 printk(PRINT_PREF "this test requires NAND flash\n");
519                 goto out;
520         }
521
522         tmp = mtd->size;
523         do_div(tmp, mtd->erasesize);
524         ebcnt = tmp;
525         pgcnt = mtd->erasesize / mtd->writesize;
526         pgsize = mtd->writesize;
527
528         printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
529                "page size %u, count of eraseblocks %u, pages per "
530                "eraseblock %u, OOB size %u\n",
531                (unsigned long long)mtd->size, mtd->erasesize,
532                pgsize, ebcnt, pgcnt, mtd->oobsize);
533
534         err = -ENOMEM;
535         bufsize = pgsize * 2;
536         writebuf = kmalloc(mtd->erasesize, GFP_KERNEL);
537         if (!writebuf) {
538                 printk(PRINT_PREF "error: cannot allocate memory\n");
539                 goto out;
540         }
541         twopages = kmalloc(bufsize, GFP_KERNEL);
542         if (!twopages) {
543                 printk(PRINT_PREF "error: cannot allocate memory\n");
544                 goto out;
545         }
546         boundary = kmalloc(bufsize, GFP_KERNEL);
547         if (!boundary) {
548                 printk(PRINT_PREF "error: cannot allocate memory\n");
549                 goto out;
550         }
551
552         err = scan_for_bad_eraseblocks();
553         if (err)
554                 goto out;
555
556         /* Erase all eraseblocks */
557         printk(PRINT_PREF "erasing whole device\n");
558         for (i = 0; i < ebcnt; ++i) {
559                 if (bbt[i])
560                         continue;
561                 err = erase_eraseblock(i);
562                 if (err)
563                         goto out;
564                 cond_resched();
565         }
566         printk(PRINT_PREF "erased %u eraseblocks\n", i);
567
568         /* Write all eraseblocks */
569         simple_srand(1);
570         printk(PRINT_PREF "writing whole device\n");
571         for (i = 0; i < ebcnt; ++i) {
572                 if (bbt[i])
573                         continue;
574                 err = write_eraseblock(i);
575                 if (err)
576                         goto out;
577                 if (i % 256 == 0)
578                         printk(PRINT_PREF "written up to eraseblock %u\n", i);
579                 cond_resched();
580         }
581         printk(PRINT_PREF "written %u eraseblocks\n", i);
582
583         /* Check all eraseblocks */
584         simple_srand(1);
585         printk(PRINT_PREF "verifying all eraseblocks\n");
586         for (i = 0; i < ebcnt; ++i) {
587                 if (bbt[i])
588                         continue;
589                 err = verify_eraseblock(i);
590                 if (err)
591                         goto out;
592                 if (i % 256 == 0)
593                         printk(PRINT_PREF "verified up to eraseblock %u\n", i);
594                 cond_resched();
595         }
596         printk(PRINT_PREF "verified %u eraseblocks\n", i);
597
598         err = crosstest();
599         if (err)
600                 goto out;
601
602         err = erasecrosstest();
603         if (err)
604                 goto out;
605
606         err = erasetest();
607         if (err)
608                 goto out;
609
610         printk(PRINT_PREF "finished with %d errors\n", errcnt);
611 out:
612
613         kfree(bbt);
614         kfree(boundary);
615         kfree(twopages);
616         kfree(writebuf);
617         put_mtd_device(mtd);
618         if (err)
619                 printk(PRINT_PREF "error %d occurred\n", err);
620         printk(KERN_INFO "=================================================\n");
621         return err;
622 }
623 module_init(mtd_pagetest_init);
624
625 static void __exit mtd_pagetest_exit(void)
626 {
627         return;
628 }
629 module_exit(mtd_pagetest_exit);
630
631 MODULE_DESCRIPTION("NAND page test");
632 MODULE_AUTHOR("Adrian Hunter");
633 MODULE_LICENSE("GPL");