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