Merge branch 'fixes' of http://ftp.arm.linux.org.uk/pub/linux/arm/kernel/git-cur...
[pandora-kernel.git] / drivers / mtd / tests / mtd_subpagetest.c
1 /*
2  * Copyright (C) 2006-2007 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 sub-page read and write on MTD device.
18  * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
19  *
20  */
21
22 #include <linux/init.h>
23 #include <linux/module.h>
24 #include <linux/moduleparam.h>
25 #include <linux/err.h>
26 #include <linux/mtd/mtd.h>
27 #include <linux/slab.h>
28 #include <linux/sched.h>
29
30 #define PRINT_PREF KERN_INFO "mtd_subpagetest: "
31
32 static int dev = -EINVAL;
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 *writebuf;
38 static unsigned char *readbuf;
39 static unsigned char *bbt;
40
41 static int subpgsize;
42 static int bufsize;
43 static int ebcnt;
44 static int pgcnt;
45 static int errcnt;
46 static unsigned long next = 1;
47
48 static inline unsigned int simple_rand(void)
49 {
50         next = next * 1103515245 + 12345;
51         return (unsigned int)((next / 65536) % 32768);
52 }
53
54 static inline void simple_srand(unsigned long seed)
55 {
56         next = seed;
57 }
58
59 static void set_random_data(unsigned char *buf, size_t len)
60 {
61         size_t i;
62
63         for (i = 0; i < len; ++i)
64                 buf[i] = simple_rand();
65 }
66
67 static inline void clear_data(unsigned char *buf, size_t len)
68 {
69         memset(buf, 0, len);
70 }
71
72 static int erase_eraseblock(int ebnum)
73 {
74         int err;
75         struct erase_info ei;
76         loff_t addr = ebnum * mtd->erasesize;
77
78         memset(&ei, 0, sizeof(struct erase_info));
79         ei.mtd  = mtd;
80         ei.addr = addr;
81         ei.len  = mtd->erasesize;
82
83         err = mtd->erase(mtd, &ei);
84         if (err) {
85                 printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum);
86                 return err;
87         }
88
89         if (ei.state == MTD_ERASE_FAILED) {
90                 printk(PRINT_PREF "some erase error occurred at EB %d\n",
91                        ebnum);
92                 return -EIO;
93         }
94
95         return 0;
96 }
97
98 static int erase_whole_device(void)
99 {
100         int err;
101         unsigned int i;
102
103         printk(PRINT_PREF "erasing whole device\n");
104         for (i = 0; i < ebcnt; ++i) {
105                 if (bbt[i])
106                         continue;
107                 err = erase_eraseblock(i);
108                 if (err)
109                         return err;
110                 cond_resched();
111         }
112         printk(PRINT_PREF "erased %u eraseblocks\n", i);
113         return 0;
114 }
115
116 static int write_eraseblock(int ebnum)
117 {
118         size_t written = 0;
119         int err = 0;
120         loff_t addr = ebnum * mtd->erasesize;
121
122         set_random_data(writebuf, subpgsize);
123         err = mtd->write(mtd, addr, subpgsize, &written, writebuf);
124         if (unlikely(err || written != subpgsize)) {
125                 printk(PRINT_PREF "error: write failed at %#llx\n",
126                        (long long)addr);
127                 if (written != subpgsize) {
128                         printk(PRINT_PREF "  write size: %#x\n", subpgsize);
129                         printk(PRINT_PREF "  written: %#zx\n", written);
130                 }
131                 return err ? err : -1;
132         }
133
134         addr += subpgsize;
135
136         set_random_data(writebuf, subpgsize);
137         err = mtd->write(mtd, addr, subpgsize, &written, writebuf);
138         if (unlikely(err || written != subpgsize)) {
139                 printk(PRINT_PREF "error: write failed at %#llx\n",
140                        (long long)addr);
141                 if (written != subpgsize) {
142                         printk(PRINT_PREF "  write size: %#x\n", subpgsize);
143                         printk(PRINT_PREF "  written: %#zx\n", written);
144                 }
145                 return err ? err : -1;
146         }
147
148         return err;
149 }
150
151 static int write_eraseblock2(int ebnum)
152 {
153         size_t written = 0;
154         int err = 0, k;
155         loff_t addr = ebnum * mtd->erasesize;
156
157         for (k = 1; k < 33; ++k) {
158                 if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize)
159                         break;
160                 set_random_data(writebuf, subpgsize * k);
161                 err = mtd->write(mtd, addr, subpgsize * k, &written, writebuf);
162                 if (unlikely(err || written != subpgsize * k)) {
163                         printk(PRINT_PREF "error: write failed at %#llx\n",
164                                (long long)addr);
165                         if (written != subpgsize) {
166                                 printk(PRINT_PREF "  write size: %#x\n",
167                                        subpgsize * k);
168                                 printk(PRINT_PREF "  written: %#08zx\n",
169                                        written);
170                         }
171                         return err ? err : -1;
172                 }
173                 addr += subpgsize * k;
174         }
175
176         return err;
177 }
178
179 static void print_subpage(unsigned char *p)
180 {
181         int i, j;
182
183         for (i = 0; i < subpgsize; ) {
184                 for (j = 0; i < subpgsize && j < 32; ++i, ++j)
185                         printk("%02x", *p++);
186                 printk("\n");
187         }
188 }
189
190 static int verify_eraseblock(int ebnum)
191 {
192         size_t read = 0;
193         int err = 0;
194         loff_t addr = ebnum * mtd->erasesize;
195
196         set_random_data(writebuf, subpgsize);
197         clear_data(readbuf, subpgsize);
198         read = 0;
199         err = mtd->read(mtd, addr, subpgsize, &read, readbuf);
200         if (unlikely(err || read != subpgsize)) {
201                 if (mtd_is_bitflip(err) && read == subpgsize) {
202                         printk(PRINT_PREF "ECC correction at %#llx\n",
203                                (long long)addr);
204                         err = 0;
205                 } else {
206                         printk(PRINT_PREF "error: read failed at %#llx\n",
207                                (long long)addr);
208                         return err ? err : -1;
209                 }
210         }
211         if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
212                 printk(PRINT_PREF "error: verify failed at %#llx\n",
213                        (long long)addr);
214                 printk(PRINT_PREF "------------- written----------------\n");
215                 print_subpage(writebuf);
216                 printk(PRINT_PREF "------------- read ------------------\n");
217                 print_subpage(readbuf);
218                 printk(PRINT_PREF "-------------------------------------\n");
219                 errcnt += 1;
220         }
221
222         addr += subpgsize;
223
224         set_random_data(writebuf, subpgsize);
225         clear_data(readbuf, subpgsize);
226         read = 0;
227         err = mtd->read(mtd, addr, subpgsize, &read, readbuf);
228         if (unlikely(err || read != subpgsize)) {
229                 if (mtd_is_bitflip(err) && read == subpgsize) {
230                         printk(PRINT_PREF "ECC correction at %#llx\n",
231                                (long long)addr);
232                         err = 0;
233                 } else {
234                         printk(PRINT_PREF "error: read failed at %#llx\n",
235                                (long long)addr);
236                         return err ? err : -1;
237                 }
238         }
239         if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
240                 printk(PRINT_PREF "error: verify failed at %#llx\n",
241                        (long long)addr);
242                 printk(PRINT_PREF "------------- written----------------\n");
243                 print_subpage(writebuf);
244                 printk(PRINT_PREF "------------- read ------------------\n");
245                 print_subpage(readbuf);
246                 printk(PRINT_PREF "-------------------------------------\n");
247                 errcnt += 1;
248         }
249
250         return err;
251 }
252
253 static int verify_eraseblock2(int ebnum)
254 {
255         size_t read = 0;
256         int err = 0, k;
257         loff_t addr = ebnum * mtd->erasesize;
258
259         for (k = 1; k < 33; ++k) {
260                 if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize)
261                         break;
262                 set_random_data(writebuf, subpgsize * k);
263                 clear_data(readbuf, subpgsize * k);
264                 read = 0;
265                 err = mtd->read(mtd, addr, subpgsize * k, &read, readbuf);
266                 if (unlikely(err || read != subpgsize * k)) {
267                         if (mtd_is_bitflip(err) && read == subpgsize * k) {
268                                 printk(PRINT_PREF "ECC correction at %#llx\n",
269                                        (long long)addr);
270                                 err = 0;
271                         } else {
272                                 printk(PRINT_PREF "error: read failed at "
273                                        "%#llx\n", (long long)addr);
274                                 return err ? err : -1;
275                         }
276                 }
277                 if (unlikely(memcmp(readbuf, writebuf, subpgsize * k))) {
278                         printk(PRINT_PREF "error: verify failed at %#llx\n",
279                                (long long)addr);
280                         errcnt += 1;
281                 }
282                 addr += subpgsize * k;
283         }
284
285         return err;
286 }
287
288 static int verify_eraseblock_ff(int ebnum)
289 {
290         uint32_t j;
291         size_t read = 0;
292         int err = 0;
293         loff_t addr = ebnum * mtd->erasesize;
294
295         memset(writebuf, 0xff, subpgsize);
296         for (j = 0; j < mtd->erasesize / subpgsize; ++j) {
297                 clear_data(readbuf, subpgsize);
298                 read = 0;
299                 err = mtd->read(mtd, addr, subpgsize, &read, readbuf);
300                 if (unlikely(err || read != subpgsize)) {
301                         if (mtd_is_bitflip(err) && read == subpgsize) {
302                                 printk(PRINT_PREF "ECC correction at %#llx\n",
303                                        (long long)addr);
304                                 err = 0;
305                         } else {
306                                 printk(PRINT_PREF "error: read failed at "
307                                        "%#llx\n", (long long)addr);
308                                 return err ? err : -1;
309                         }
310                 }
311                 if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
312                         printk(PRINT_PREF "error: verify 0xff failed at "
313                                "%#llx\n", (long long)addr);
314                         errcnt += 1;
315                 }
316                 addr += subpgsize;
317         }
318
319         return err;
320 }
321
322 static int verify_all_eraseblocks_ff(void)
323 {
324         int err;
325         unsigned int i;
326
327         printk(PRINT_PREF "verifying all eraseblocks for 0xff\n");
328         for (i = 0; i < ebcnt; ++i) {
329                 if (bbt[i])
330                         continue;
331                 err = verify_eraseblock_ff(i);
332                 if (err)
333                         return err;
334                 if (i % 256 == 0)
335                         printk(PRINT_PREF "verified up to eraseblock %u\n", i);
336                 cond_resched();
337         }
338         printk(PRINT_PREF "verified %u eraseblocks\n", i);
339         return 0;
340 }
341
342 static int is_block_bad(int ebnum)
343 {
344         loff_t addr = ebnum * mtd->erasesize;
345         int ret;
346
347         ret = mtd->block_isbad(mtd, addr);
348         if (ret)
349                 printk(PRINT_PREF "block %d is bad\n", ebnum);
350         return ret;
351 }
352
353 static int scan_for_bad_eraseblocks(void)
354 {
355         int i, bad = 0;
356
357         bbt = kzalloc(ebcnt, GFP_KERNEL);
358         if (!bbt) {
359                 printk(PRINT_PREF "error: cannot allocate memory\n");
360                 return -ENOMEM;
361         }
362
363         printk(PRINT_PREF "scanning for bad eraseblocks\n");
364         for (i = 0; i < ebcnt; ++i) {
365                 bbt[i] = is_block_bad(i) ? 1 : 0;
366                 if (bbt[i])
367                         bad += 1;
368                 cond_resched();
369         }
370         printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad);
371         return 0;
372 }
373
374 static int __init mtd_subpagetest_init(void)
375 {
376         int err = 0;
377         uint32_t i;
378         uint64_t tmp;
379
380         printk(KERN_INFO "\n");
381         printk(KERN_INFO "=================================================\n");
382
383         if (dev < 0) {
384                 printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n");
385                 printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n");
386                 return -EINVAL;
387         }
388
389         printk(PRINT_PREF "MTD device: %d\n", dev);
390
391         mtd = get_mtd_device(NULL, dev);
392         if (IS_ERR(mtd)) {
393                 err = PTR_ERR(mtd);
394                 printk(PRINT_PREF "error: cannot get MTD device\n");
395                 return err;
396         }
397
398         if (mtd->type != MTD_NANDFLASH) {
399                 printk(PRINT_PREF "this test requires NAND flash\n");
400                 goto out;
401         }
402
403         subpgsize = mtd->writesize >> mtd->subpage_sft;
404         tmp = mtd->size;
405         do_div(tmp, mtd->erasesize);
406         ebcnt = tmp;
407         pgcnt = mtd->erasesize / mtd->writesize;
408
409         printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
410                "page size %u, subpage size %u, count of eraseblocks %u, "
411                "pages per eraseblock %u, OOB size %u\n",
412                (unsigned long long)mtd->size, mtd->erasesize,
413                mtd->writesize, subpgsize, ebcnt, pgcnt, mtd->oobsize);
414
415         err = -ENOMEM;
416         bufsize = subpgsize * 32;
417         writebuf = kmalloc(bufsize, GFP_KERNEL);
418         if (!writebuf) {
419                 printk(PRINT_PREF "error: cannot allocate memory\n");
420                 goto out;
421         }
422         readbuf = kmalloc(bufsize, GFP_KERNEL);
423         if (!readbuf) {
424                 printk(PRINT_PREF "error: cannot allocate memory\n");
425                 goto out;
426         }
427
428         err = scan_for_bad_eraseblocks();
429         if (err)
430                 goto out;
431
432         err = erase_whole_device();
433         if (err)
434                 goto out;
435
436         printk(PRINT_PREF "writing whole device\n");
437         simple_srand(1);
438         for (i = 0; i < ebcnt; ++i) {
439                 if (bbt[i])
440                         continue;
441                 err = write_eraseblock(i);
442                 if (unlikely(err))
443                         goto out;
444                 if (i % 256 == 0)
445                         printk(PRINT_PREF "written up to eraseblock %u\n", i);
446                 cond_resched();
447         }
448         printk(PRINT_PREF "written %u eraseblocks\n", i);
449
450         simple_srand(1);
451         printk(PRINT_PREF "verifying all eraseblocks\n");
452         for (i = 0; i < ebcnt; ++i) {
453                 if (bbt[i])
454                         continue;
455                 err = verify_eraseblock(i);
456                 if (unlikely(err))
457                         goto out;
458                 if (i % 256 == 0)
459                         printk(PRINT_PREF "verified up to eraseblock %u\n", i);
460                 cond_resched();
461         }
462         printk(PRINT_PREF "verified %u eraseblocks\n", i);
463
464         err = erase_whole_device();
465         if (err)
466                 goto out;
467
468         err = verify_all_eraseblocks_ff();
469         if (err)
470                 goto out;
471
472         /* Write all eraseblocks */
473         simple_srand(3);
474         printk(PRINT_PREF "writing whole device\n");
475         for (i = 0; i < ebcnt; ++i) {
476                 if (bbt[i])
477                         continue;
478                 err = write_eraseblock2(i);
479                 if (unlikely(err))
480                         goto out;
481                 if (i % 256 == 0)
482                         printk(PRINT_PREF "written up to eraseblock %u\n", i);
483                 cond_resched();
484         }
485         printk(PRINT_PREF "written %u eraseblocks\n", i);
486
487         /* Check all eraseblocks */
488         simple_srand(3);
489         printk(PRINT_PREF "verifying all eraseblocks\n");
490         for (i = 0; i < ebcnt; ++i) {
491                 if (bbt[i])
492                         continue;
493                 err = verify_eraseblock2(i);
494                 if (unlikely(err))
495                         goto out;
496                 if (i % 256 == 0)
497                         printk(PRINT_PREF "verified up to eraseblock %u\n", i);
498                 cond_resched();
499         }
500         printk(PRINT_PREF "verified %u eraseblocks\n", i);
501
502         err = erase_whole_device();
503         if (err)
504                 goto out;
505
506         err = verify_all_eraseblocks_ff();
507         if (err)
508                 goto out;
509
510         printk(PRINT_PREF "finished with %d errors\n", errcnt);
511
512 out:
513         kfree(bbt);
514         kfree(readbuf);
515         kfree(writebuf);
516         put_mtd_device(mtd);
517         if (err)
518                 printk(PRINT_PREF "error %d occurred\n", err);
519         printk(KERN_INFO "=================================================\n");
520         return err;
521 }
522 module_init(mtd_subpagetest_init);
523
524 static void __exit mtd_subpagetest_exit(void)
525 {
526         return;
527 }
528 module_exit(mtd_subpagetest_exit);
529
530 MODULE_DESCRIPTION("Subpage test module");
531 MODULE_AUTHOR("Adrian Hunter");
532 MODULE_LICENSE("GPL");