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