8813b0e86637a1f0418259e5eedc5c8fac3ca962
[linux-3.10.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 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
23
24 #include <linux/init.h>
25 #include <linux/module.h>
26 #include <linux/moduleparam.h>
27 #include <linux/err.h>
28 #include <linux/mtd/mtd.h>
29 #include <linux/slab.h>
30 #include <linux/sched.h>
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                 pr_err("error %d while erasing EB %d\n", err, ebnum);
86                 return err;
87         }
88
89         if (ei.state == MTD_ERASE_FAILED) {
90                 pr_err("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         pr_info("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         pr_info("erased %u eraseblocks\n", i);
113         return 0;
114 }
115
116 static int write_eraseblock(int ebnum)
117 {
118         size_t written;
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                 pr_err("error: write failed at %#llx\n",
126                        (long long)addr);
127                 if (written != subpgsize) {
128                         pr_err("  write size: %#x\n", subpgsize);
129                         pr_err("  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                 pr_err("error: write failed at %#llx\n",
140                        (long long)addr);
141                 if (written != subpgsize) {
142                         pr_err("  write size: %#x\n", subpgsize);
143                         pr_err("  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;
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                         pr_err("error: write failed at %#llx\n",
164                                (long long)addr);
165                         if (written != subpgsize) {
166                                 pr_err("  write size: %#x\n",
167                                        subpgsize * k);
168                                 pr_err("  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;
193         int err = 0;
194         loff_t addr = ebnum * mtd->erasesize;
195
196         set_random_data(writebuf, subpgsize);
197         clear_data(readbuf, subpgsize);
198         err = mtd_read(mtd, addr, subpgsize, &read, readbuf);
199         if (unlikely(err || read != subpgsize)) {
200                 if (mtd_is_bitflip(err) && read == subpgsize) {
201                         pr_info("ECC correction at %#llx\n",
202                                (long long)addr);
203                         err = 0;
204                 } else {
205                         pr_err("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                 pr_err("error: verify failed at %#llx\n",
212                        (long long)addr);
213                 pr_info("------------- written----------------\n");
214                 print_subpage(writebuf);
215                 pr_info("------------- read ------------------\n");
216                 print_subpage(readbuf);
217                 pr_info("-------------------------------------\n");
218                 errcnt += 1;
219         }
220
221         addr += subpgsize;
222
223         set_random_data(writebuf, subpgsize);
224         clear_data(readbuf, subpgsize);
225         err = mtd_read(mtd, addr, subpgsize, &read, readbuf);
226         if (unlikely(err || read != subpgsize)) {
227                 if (mtd_is_bitflip(err) && read == subpgsize) {
228                         pr_info("ECC correction at %#llx\n",
229                                (long long)addr);
230                         err = 0;
231                 } else {
232                         pr_err("error: read failed at %#llx\n",
233                                (long long)addr);
234                         return err ? err : -1;
235                 }
236         }
237         if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
238                 pr_info("error: verify failed at %#llx\n",
239                        (long long)addr);
240                 pr_info("------------- written----------------\n");
241                 print_subpage(writebuf);
242                 pr_info("------------- read ------------------\n");
243                 print_subpage(readbuf);
244                 pr_info("-------------------------------------\n");
245                 errcnt += 1;
246         }
247
248         return err;
249 }
250
251 static int verify_eraseblock2(int ebnum)
252 {
253         size_t read;
254         int err = 0, k;
255         loff_t addr = ebnum * mtd->erasesize;
256
257         for (k = 1; k < 33; ++k) {
258                 if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize)
259                         break;
260                 set_random_data(writebuf, subpgsize * k);
261                 clear_data(readbuf, subpgsize * k);
262                 err = mtd_read(mtd, addr, subpgsize * k, &read, readbuf);
263                 if (unlikely(err || read != subpgsize * k)) {
264                         if (mtd_is_bitflip(err) && read == subpgsize * k) {
265                                 pr_info("ECC correction at %#llx\n",
266                                        (long long)addr);
267                                 err = 0;
268                         } else {
269                                 pr_err("error: read failed at "
270                                        "%#llx\n", (long long)addr);
271                                 return err ? err : -1;
272                         }
273                 }
274                 if (unlikely(memcmp(readbuf, writebuf, subpgsize * k))) {
275                         pr_err("error: verify failed at %#llx\n",
276                                (long long)addr);
277                         errcnt += 1;
278                 }
279                 addr += subpgsize * k;
280         }
281
282         return err;
283 }
284
285 static int verify_eraseblock_ff(int ebnum)
286 {
287         uint32_t j;
288         size_t read;
289         int err = 0;
290         loff_t addr = ebnum * mtd->erasesize;
291
292         memset(writebuf, 0xff, subpgsize);
293         for (j = 0; j < mtd->erasesize / subpgsize; ++j) {
294                 clear_data(readbuf, subpgsize);
295                 err = mtd_read(mtd, addr, subpgsize, &read, readbuf);
296                 if (unlikely(err || read != subpgsize)) {
297                         if (mtd_is_bitflip(err) && read == subpgsize) {
298                                 pr_info("ECC correction at %#llx\n",
299                                        (long long)addr);
300                                 err = 0;
301                         } else {
302                                 pr_err("error: read failed at "
303                                        "%#llx\n", (long long)addr);
304                                 return err ? err : -1;
305                         }
306                 }
307                 if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
308                         pr_err("error: verify 0xff failed at "
309                                "%#llx\n", (long long)addr);
310                         errcnt += 1;
311                 }
312                 addr += subpgsize;
313         }
314
315         return err;
316 }
317
318 static int verify_all_eraseblocks_ff(void)
319 {
320         int err;
321         unsigned int i;
322
323         pr_info("verifying all eraseblocks for 0xff\n");
324         for (i = 0; i < ebcnt; ++i) {
325                 if (bbt[i])
326                         continue;
327                 err = verify_eraseblock_ff(i);
328                 if (err)
329                         return err;
330                 if (i % 256 == 0)
331                         pr_info("verified up to eraseblock %u\n", i);
332                 cond_resched();
333         }
334         pr_info("verified %u eraseblocks\n", i);
335         return 0;
336 }
337
338 static int is_block_bad(int ebnum)
339 {
340         loff_t addr = ebnum * mtd->erasesize;
341         int ret;
342
343         ret = mtd_block_isbad(mtd, addr);
344         if (ret)
345                 pr_info("block %d is bad\n", ebnum);
346         return ret;
347 }
348
349 static int scan_for_bad_eraseblocks(void)
350 {
351         int i, bad = 0;
352
353         bbt = kzalloc(ebcnt, GFP_KERNEL);
354         if (!bbt) {
355                 pr_err("error: cannot allocate memory\n");
356                 return -ENOMEM;
357         }
358
359         pr_info("scanning for bad eraseblocks\n");
360         for (i = 0; i < ebcnt; ++i) {
361                 bbt[i] = is_block_bad(i) ? 1 : 0;
362                 if (bbt[i])
363                         bad += 1;
364                 cond_resched();
365         }
366         pr_info("scanned %d eraseblocks, %d are bad\n", i, bad);
367         return 0;
368 }
369
370 static int __init mtd_subpagetest_init(void)
371 {
372         int err = 0;
373         uint32_t i;
374         uint64_t tmp;
375
376         printk(KERN_INFO "\n");
377         printk(KERN_INFO "=================================================\n");
378
379         if (dev < 0) {
380                 pr_info("Please specify a valid mtd-device via module paramter\n");
381                 pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
382                 return -EINVAL;
383         }
384
385         pr_info("MTD device: %d\n", dev);
386
387         mtd = get_mtd_device(NULL, dev);
388         if (IS_ERR(mtd)) {
389                 err = PTR_ERR(mtd);
390                 pr_err("error: cannot get MTD device\n");
391                 return err;
392         }
393
394         if (mtd->type != MTD_NANDFLASH) {
395                 pr_info("this test requires NAND flash\n");
396                 goto out;
397         }
398
399         subpgsize = mtd->writesize >> mtd->subpage_sft;
400         tmp = mtd->size;
401         do_div(tmp, mtd->erasesize);
402         ebcnt = tmp;
403         pgcnt = mtd->erasesize / mtd->writesize;
404
405         pr_info("MTD device size %llu, eraseblock size %u, "
406                "page size %u, subpage size %u, count of eraseblocks %u, "
407                "pages per eraseblock %u, OOB size %u\n",
408                (unsigned long long)mtd->size, mtd->erasesize,
409                mtd->writesize, subpgsize, ebcnt, pgcnt, mtd->oobsize);
410
411         err = -ENOMEM;
412         bufsize = subpgsize * 32;
413         writebuf = kmalloc(bufsize, GFP_KERNEL);
414         if (!writebuf) {
415                 pr_info("error: cannot allocate memory\n");
416                 goto out;
417         }
418         readbuf = kmalloc(bufsize, GFP_KERNEL);
419         if (!readbuf) {
420                 pr_info("error: cannot allocate memory\n");
421                 goto out;
422         }
423
424         err = scan_for_bad_eraseblocks();
425         if (err)
426                 goto out;
427
428         err = erase_whole_device();
429         if (err)
430                 goto out;
431
432         pr_info("writing whole device\n");
433         simple_srand(1);
434         for (i = 0; i < ebcnt; ++i) {
435                 if (bbt[i])
436                         continue;
437                 err = write_eraseblock(i);
438                 if (unlikely(err))
439                         goto out;
440                 if (i % 256 == 0)
441                         pr_info("written up to eraseblock %u\n", i);
442                 cond_resched();
443         }
444         pr_info("written %u eraseblocks\n", i);
445
446         simple_srand(1);
447         pr_info("verifying all eraseblocks\n");
448         for (i = 0; i < ebcnt; ++i) {
449                 if (bbt[i])
450                         continue;
451                 err = verify_eraseblock(i);
452                 if (unlikely(err))
453                         goto out;
454                 if (i % 256 == 0)
455                         pr_info("verified up to eraseblock %u\n", i);
456                 cond_resched();
457         }
458         pr_info("verified %u eraseblocks\n", i);
459
460         err = erase_whole_device();
461         if (err)
462                 goto out;
463
464         err = verify_all_eraseblocks_ff();
465         if (err)
466                 goto out;
467
468         /* Write all eraseblocks */
469         simple_srand(3);
470         pr_info("writing whole device\n");
471         for (i = 0; i < ebcnt; ++i) {
472                 if (bbt[i])
473                         continue;
474                 err = write_eraseblock2(i);
475                 if (unlikely(err))
476                         goto out;
477                 if (i % 256 == 0)
478                         pr_info("written up to eraseblock %u\n", i);
479                 cond_resched();
480         }
481         pr_info("written %u eraseblocks\n", i);
482
483         /* Check all eraseblocks */
484         simple_srand(3);
485         pr_info("verifying all eraseblocks\n");
486         for (i = 0; i < ebcnt; ++i) {
487                 if (bbt[i])
488                         continue;
489                 err = verify_eraseblock2(i);
490                 if (unlikely(err))
491                         goto out;
492                 if (i % 256 == 0)
493                         pr_info("verified up to eraseblock %u\n", i);
494                 cond_resched();
495         }
496         pr_info("verified %u eraseblocks\n", i);
497
498         err = erase_whole_device();
499         if (err)
500                 goto out;
501
502         err = verify_all_eraseblocks_ff();
503         if (err)
504                 goto out;
505
506         pr_info("finished with %d errors\n", errcnt);
507
508 out:
509         kfree(bbt);
510         kfree(readbuf);
511         kfree(writebuf);
512         put_mtd_device(mtd);
513         if (err)
514                 pr_info("error %d occurred\n", err);
515         printk(KERN_INFO "=================================================\n");
516         return err;
517 }
518 module_init(mtd_subpagetest_init);
519
520 static void __exit mtd_subpagetest_exit(void)
521 {
522         return;
523 }
524 module_exit(mtd_subpagetest_exit);
525
526 MODULE_DESCRIPTION("Subpage test module");
527 MODULE_AUTHOR("Adrian Hunter");
528 MODULE_LICENSE("GPL");