blob: aade56f2794541f9d0545be12a0110f9ffe18ea1 [file] [log] [blame]
Artem Bityutskiybf608622008-12-08 13:37:48 +02001/*
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
Vikram Narayanancd66a2d2012-10-10 23:11:06 +053022#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
23
Artem Bityutskiybf608622008-12-08 13:37:48 +020024#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>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090029#include <linux/slab.h>
Artem Bityutskiybf608622008-12-08 13:37:48 +020030#include <linux/sched.h>
Akinobu Mitaa312b782013-02-27 17:05:39 -080031#include <linux/random.h>
Artem Bityutskiybf608622008-12-08 13:37:48 +020032
Wolfram Sang74060602011-10-30 00:11:53 +020033static int dev = -EINVAL;
Artem Bityutskiybf608622008-12-08 13:37:48 +020034module_param(dev, int, S_IRUGO);
35MODULE_PARM_DESC(dev, "MTD device number to use");
36
37static struct mtd_info *mtd;
38static unsigned char *writebuf;
39static unsigned char *readbuf;
40static unsigned char *bbt;
41
42static int subpgsize;
43static int bufsize;
44static int ebcnt;
45static int pgcnt;
46static int errcnt;
Akinobu Mitaa312b782013-02-27 17:05:39 -080047static struct rnd_state rnd_state;
Artem Bityutskiybf608622008-12-08 13:37:48 +020048
49static inline void clear_data(unsigned char *buf, size_t len)
50{
51 memset(buf, 0, len);
52}
53
54static 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
Artem Bityutskiy7e1f0dc2011-12-23 15:25:39 +020065 err = mtd_erase(mtd, &ei);
Artem Bityutskiybf608622008-12-08 13:37:48 +020066 if (err) {
Vikram Narayanancd66a2d2012-10-10 23:11:06 +053067 pr_err("error %d while erasing EB %d\n", err, ebnum);
Artem Bityutskiybf608622008-12-08 13:37:48 +020068 return err;
69 }
70
71 if (ei.state == MTD_ERASE_FAILED) {
Vikram Narayanancd66a2d2012-10-10 23:11:06 +053072 pr_err("some erase error occurred at EB %d\n",
Artem Bityutskiybf608622008-12-08 13:37:48 +020073 ebnum);
74 return -EIO;
75 }
76
77 return 0;
78}
79
80static int erase_whole_device(void)
81{
82 int err;
83 unsigned int i;
84
Vikram Narayanancd66a2d2012-10-10 23:11:06 +053085 pr_info("erasing whole device\n");
Artem Bityutskiybf608622008-12-08 13:37:48 +020086 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 }
Vikram Narayanancd66a2d2012-10-10 23:11:06 +053094 pr_info("erased %u eraseblocks\n", i);
Artem Bityutskiybf608622008-12-08 13:37:48 +020095 return 0;
96}
97
98static int write_eraseblock(int ebnum)
99{
Artem Bityutskiy30fa9842011-12-29 15:16:28 +0200100 size_t written;
Artem Bityutskiybf608622008-12-08 13:37:48 +0200101 int err = 0;
102 loff_t addr = ebnum * mtd->erasesize;
103
Akinobu Mitaa312b782013-02-27 17:05:39 -0800104 prandom_bytes_state(&rnd_state, writebuf, subpgsize);
Artem Bityutskiyeda95cb2011-12-23 17:35:41 +0200105 err = mtd_write(mtd, addr, subpgsize, &written, writebuf);
Artem Bityutskiybf608622008-12-08 13:37:48 +0200106 if (unlikely(err || written != subpgsize)) {
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530107 pr_err("error: write failed at %#llx\n",
Artem Bityutskiybf608622008-12-08 13:37:48 +0200108 (long long)addr);
109 if (written != subpgsize) {
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530110 pr_err(" write size: %#x\n", subpgsize);
111 pr_err(" written: %#zx\n", written);
Artem Bityutskiybf608622008-12-08 13:37:48 +0200112 }
113 return err ? err : -1;
114 }
115
116 addr += subpgsize;
117
Akinobu Mitaa312b782013-02-27 17:05:39 -0800118 prandom_bytes_state(&rnd_state, writebuf, subpgsize);
Artem Bityutskiyeda95cb2011-12-23 17:35:41 +0200119 err = mtd_write(mtd, addr, subpgsize, &written, writebuf);
Artem Bityutskiybf608622008-12-08 13:37:48 +0200120 if (unlikely(err || written != subpgsize)) {
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530121 pr_err("error: write failed at %#llx\n",
Artem Bityutskiybf608622008-12-08 13:37:48 +0200122 (long long)addr);
123 if (written != subpgsize) {
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530124 pr_err(" write size: %#x\n", subpgsize);
125 pr_err(" written: %#zx\n", written);
Artem Bityutskiybf608622008-12-08 13:37:48 +0200126 }
127 return err ? err : -1;
128 }
129
130 return err;
131}
132
133static int write_eraseblock2(int ebnum)
134{
Artem Bityutskiy30fa9842011-12-29 15:16:28 +0200135 size_t written;
Artem Bityutskiybf608622008-12-08 13:37:48 +0200136 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;
Akinobu Mitaa312b782013-02-27 17:05:39 -0800142 prandom_bytes_state(&rnd_state, writebuf, subpgsize * k);
Artem Bityutskiyeda95cb2011-12-23 17:35:41 +0200143 err = mtd_write(mtd, addr, subpgsize * k, &written, writebuf);
Artem Bityutskiybf608622008-12-08 13:37:48 +0200144 if (unlikely(err || written != subpgsize * k)) {
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530145 pr_err("error: write failed at %#llx\n",
Artem Bityutskiybf608622008-12-08 13:37:48 +0200146 (long long)addr);
147 if (written != subpgsize) {
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530148 pr_err(" write size: %#x\n",
Artem Bityutskiybf608622008-12-08 13:37:48 +0200149 subpgsize * k);
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530150 pr_err(" written: %#08zx\n",
Artem Bityutskiybf608622008-12-08 13:37:48 +0200151 written);
152 }
153 return err ? err : -1;
154 }
155 addr += subpgsize * k;
156 }
157
158 return err;
159}
160
161static 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
172static int verify_eraseblock(int ebnum)
173{
Artem Bityutskiy30fa9842011-12-29 15:16:28 +0200174 size_t read;
Artem Bityutskiybf608622008-12-08 13:37:48 +0200175 int err = 0;
176 loff_t addr = ebnum * mtd->erasesize;
177
Akinobu Mitaa312b782013-02-27 17:05:39 -0800178 prandom_bytes_state(&rnd_state, writebuf, subpgsize);
Artem Bityutskiybf608622008-12-08 13:37:48 +0200179 clear_data(readbuf, subpgsize);
Artem Bityutskiy329ad392011-12-23 17:30:16 +0200180 err = mtd_read(mtd, addr, subpgsize, &read, readbuf);
Artem Bityutskiybf608622008-12-08 13:37:48 +0200181 if (unlikely(err || read != subpgsize)) {
Brian Norrisd57f40542011-09-20 18:34:25 -0700182 if (mtd_is_bitflip(err) && read == subpgsize) {
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530183 pr_info("ECC correction at %#llx\n",
Artem Bityutskiybf608622008-12-08 13:37:48 +0200184 (long long)addr);
185 err = 0;
186 } else {
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530187 pr_err("error: read failed at %#llx\n",
Artem Bityutskiybf608622008-12-08 13:37:48 +0200188 (long long)addr);
189 return err ? err : -1;
190 }
191 }
192 if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530193 pr_err("error: verify failed at %#llx\n",
Artem Bityutskiybf608622008-12-08 13:37:48 +0200194 (long long)addr);
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530195 pr_info("------------- written----------------\n");
Artem Bityutskiybf608622008-12-08 13:37:48 +0200196 print_subpage(writebuf);
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530197 pr_info("------------- read ------------------\n");
Artem Bityutskiybf608622008-12-08 13:37:48 +0200198 print_subpage(readbuf);
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530199 pr_info("-------------------------------------\n");
Artem Bityutskiybf608622008-12-08 13:37:48 +0200200 errcnt += 1;
201 }
202
203 addr += subpgsize;
204
Akinobu Mitaa312b782013-02-27 17:05:39 -0800205 prandom_bytes_state(&rnd_state, writebuf, subpgsize);
Artem Bityutskiybf608622008-12-08 13:37:48 +0200206 clear_data(readbuf, subpgsize);
Artem Bityutskiy329ad392011-12-23 17:30:16 +0200207 err = mtd_read(mtd, addr, subpgsize, &read, readbuf);
Artem Bityutskiybf608622008-12-08 13:37:48 +0200208 if (unlikely(err || read != subpgsize)) {
Brian Norrisd57f40542011-09-20 18:34:25 -0700209 if (mtd_is_bitflip(err) && read == subpgsize) {
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530210 pr_info("ECC correction at %#llx\n",
Artem Bityutskiybf608622008-12-08 13:37:48 +0200211 (long long)addr);
212 err = 0;
213 } else {
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530214 pr_err("error: read failed at %#llx\n",
Artem Bityutskiybf608622008-12-08 13:37:48 +0200215 (long long)addr);
216 return err ? err : -1;
217 }
218 }
219 if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530220 pr_info("error: verify failed at %#llx\n",
Artem Bityutskiybf608622008-12-08 13:37:48 +0200221 (long long)addr);
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530222 pr_info("------------- written----------------\n");
Artem Bityutskiybf608622008-12-08 13:37:48 +0200223 print_subpage(writebuf);
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530224 pr_info("------------- read ------------------\n");
Artem Bityutskiybf608622008-12-08 13:37:48 +0200225 print_subpage(readbuf);
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530226 pr_info("-------------------------------------\n");
Artem Bityutskiybf608622008-12-08 13:37:48 +0200227 errcnt += 1;
228 }
229
230 return err;
231}
232
233static int verify_eraseblock2(int ebnum)
234{
Artem Bityutskiy30fa9842011-12-29 15:16:28 +0200235 size_t read;
Artem Bityutskiybf608622008-12-08 13:37:48 +0200236 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;
Akinobu Mitaa312b782013-02-27 17:05:39 -0800242 prandom_bytes_state(&rnd_state, writebuf, subpgsize * k);
Artem Bityutskiybf608622008-12-08 13:37:48 +0200243 clear_data(readbuf, subpgsize * k);
Artem Bityutskiy329ad392011-12-23 17:30:16 +0200244 err = mtd_read(mtd, addr, subpgsize * k, &read, readbuf);
Artem Bityutskiybf608622008-12-08 13:37:48 +0200245 if (unlikely(err || read != subpgsize * k)) {
Brian Norrisd57f40542011-09-20 18:34:25 -0700246 if (mtd_is_bitflip(err) && read == subpgsize * k) {
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530247 pr_info("ECC correction at %#llx\n",
Artem Bityutskiybf608622008-12-08 13:37:48 +0200248 (long long)addr);
249 err = 0;
250 } else {
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530251 pr_err("error: read failed at "
Artem Bityutskiybf608622008-12-08 13:37:48 +0200252 "%#llx\n", (long long)addr);
253 return err ? err : -1;
254 }
255 }
256 if (unlikely(memcmp(readbuf, writebuf, subpgsize * k))) {
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530257 pr_err("error: verify failed at %#llx\n",
Artem Bityutskiybf608622008-12-08 13:37:48 +0200258 (long long)addr);
259 errcnt += 1;
260 }
261 addr += subpgsize * k;
262 }
263
264 return err;
265}
266
267static int verify_eraseblock_ff(int ebnum)
268{
269 uint32_t j;
Artem Bityutskiy30fa9842011-12-29 15:16:28 +0200270 size_t read;
Artem Bityutskiybf608622008-12-08 13:37:48 +0200271 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);
Artem Bityutskiy329ad392011-12-23 17:30:16 +0200277 err = mtd_read(mtd, addr, subpgsize, &read, readbuf);
Artem Bityutskiybf608622008-12-08 13:37:48 +0200278 if (unlikely(err || read != subpgsize)) {
Brian Norrisd57f40542011-09-20 18:34:25 -0700279 if (mtd_is_bitflip(err) && read == subpgsize) {
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530280 pr_info("ECC correction at %#llx\n",
Artem Bityutskiybf608622008-12-08 13:37:48 +0200281 (long long)addr);
282 err = 0;
283 } else {
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530284 pr_err("error: read failed at "
Artem Bityutskiybf608622008-12-08 13:37:48 +0200285 "%#llx\n", (long long)addr);
286 return err ? err : -1;
287 }
288 }
289 if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530290 pr_err("error: verify 0xff failed at "
Artem Bityutskiybf608622008-12-08 13:37:48 +0200291 "%#llx\n", (long long)addr);
292 errcnt += 1;
293 }
294 addr += subpgsize;
295 }
296
297 return err;
298}
299
300static int verify_all_eraseblocks_ff(void)
301{
302 int err;
303 unsigned int i;
304
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530305 pr_info("verifying all eraseblocks for 0xff\n");
Artem Bityutskiybf608622008-12-08 13:37:48 +0200306 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)
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530313 pr_info("verified up to eraseblock %u\n", i);
Artem Bityutskiybf608622008-12-08 13:37:48 +0200314 cond_resched();
315 }
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530316 pr_info("verified %u eraseblocks\n", i);
Artem Bityutskiybf608622008-12-08 13:37:48 +0200317 return 0;
318}
319
320static int is_block_bad(int ebnum)
321{
322 loff_t addr = ebnum * mtd->erasesize;
323 int ret;
324
Artem Bityutskiy7086c192011-12-23 19:35:30 +0200325 ret = mtd_block_isbad(mtd, addr);
Artem Bityutskiybf608622008-12-08 13:37:48 +0200326 if (ret)
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530327 pr_info("block %d is bad\n", ebnum);
Artem Bityutskiybf608622008-12-08 13:37:48 +0200328 return ret;
329}
330
331static int scan_for_bad_eraseblocks(void)
332{
333 int i, bad = 0;
334
Julia Lawall2bfefa42010-05-13 22:03:15 +0200335 bbt = kzalloc(ebcnt, GFP_KERNEL);
Artem Bityutskiybf608622008-12-08 13:37:48 +0200336 if (!bbt) {
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530337 pr_err("error: cannot allocate memory\n");
Artem Bityutskiybf608622008-12-08 13:37:48 +0200338 return -ENOMEM;
339 }
Artem Bityutskiybf608622008-12-08 13:37:48 +0200340
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530341 pr_info("scanning for bad eraseblocks\n");
Artem Bityutskiybf608622008-12-08 13:37:48 +0200342 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 }
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530348 pr_info("scanned %d eraseblocks, %d are bad\n", i, bad);
Artem Bityutskiybf608622008-12-08 13:37:48 +0200349 return 0;
350}
351
352static 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");
Wolfram Sang74060602011-10-30 00:11:53 +0200360
361 if (dev < 0) {
Masanari Iida064a7692012-11-09 23:20:58 +0900362 pr_info("Please specify a valid mtd-device via module parameter\n");
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530363 pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
Wolfram Sang74060602011-10-30 00:11:53 +0200364 return -EINVAL;
365 }
366
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530367 pr_info("MTD device: %d\n", dev);
Artem Bityutskiybf608622008-12-08 13:37:48 +0200368
369 mtd = get_mtd_device(NULL, dev);
370 if (IS_ERR(mtd)) {
371 err = PTR_ERR(mtd);
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530372 pr_err("error: cannot get MTD device\n");
Artem Bityutskiybf608622008-12-08 13:37:48 +0200373 return err;
374 }
375
376 if (mtd->type != MTD_NANDFLASH) {
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530377 pr_info("this test requires NAND flash\n");
Artem Bityutskiybf608622008-12-08 13:37:48 +0200378 goto out;
379 }
380
381 subpgsize = mtd->writesize >> mtd->subpage_sft;
Roman Tereshonkov7b7e9052011-02-03 13:45:56 +0200382 tmp = mtd->size;
383 do_div(tmp, mtd->erasesize);
384 ebcnt = tmp;
385 pgcnt = mtd->erasesize / mtd->writesize;
386
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530387 pr_info("MTD device size %llu, eraseblock size %u, "
Artem Bityutskiybf608622008-12-08 13:37:48 +0200388 "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) {
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530397 pr_info("error: cannot allocate memory\n");
Artem Bityutskiybf608622008-12-08 13:37:48 +0200398 goto out;
399 }
400 readbuf = kmalloc(bufsize, GFP_KERNEL);
401 if (!readbuf) {
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530402 pr_info("error: cannot allocate memory\n");
Artem Bityutskiybf608622008-12-08 13:37:48 +0200403 goto out;
404 }
405
Artem Bityutskiybf608622008-12-08 13:37:48 +0200406 err = scan_for_bad_eraseblocks();
407 if (err)
408 goto out;
409
410 err = erase_whole_device();
411 if (err)
412 goto out;
413
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530414 pr_info("writing whole device\n");
Akinobu Mitaa312b782013-02-27 17:05:39 -0800415 prandom_seed_state(&rnd_state, 1);
Artem Bityutskiybf608622008-12-08 13:37:48 +0200416 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)
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530423 pr_info("written up to eraseblock %u\n", i);
Artem Bityutskiybf608622008-12-08 13:37:48 +0200424 cond_resched();
425 }
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530426 pr_info("written %u eraseblocks\n", i);
Artem Bityutskiybf608622008-12-08 13:37:48 +0200427
Akinobu Mitaa312b782013-02-27 17:05:39 -0800428 prandom_seed_state(&rnd_state, 1);
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530429 pr_info("verifying all eraseblocks\n");
Artem Bityutskiybf608622008-12-08 13:37:48 +0200430 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)
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530437 pr_info("verified up to eraseblock %u\n", i);
Artem Bityutskiybf608622008-12-08 13:37:48 +0200438 cond_resched();
439 }
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530440 pr_info("verified %u eraseblocks\n", i);
Artem Bityutskiybf608622008-12-08 13:37:48 +0200441
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 */
Akinobu Mitaa312b782013-02-27 17:05:39 -0800451 prandom_seed_state(&rnd_state, 3);
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530452 pr_info("writing whole device\n");
Artem Bityutskiybf608622008-12-08 13:37:48 +0200453 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)
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530460 pr_info("written up to eraseblock %u\n", i);
Artem Bityutskiybf608622008-12-08 13:37:48 +0200461 cond_resched();
462 }
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530463 pr_info("written %u eraseblocks\n", i);
Artem Bityutskiybf608622008-12-08 13:37:48 +0200464
465 /* Check all eraseblocks */
Akinobu Mitaa312b782013-02-27 17:05:39 -0800466 prandom_seed_state(&rnd_state, 3);
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530467 pr_info("verifying all eraseblocks\n");
Artem Bityutskiybf608622008-12-08 13:37:48 +0200468 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)
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530475 pr_info("verified up to eraseblock %u\n", i);
Artem Bityutskiybf608622008-12-08 13:37:48 +0200476 cond_resched();
477 }
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530478 pr_info("verified %u eraseblocks\n", i);
Artem Bityutskiybf608622008-12-08 13:37:48 +0200479
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
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530488 pr_info("finished with %d errors\n", errcnt);
Artem Bityutskiybf608622008-12-08 13:37:48 +0200489
490out:
491 kfree(bbt);
492 kfree(readbuf);
493 kfree(writebuf);
494 put_mtd_device(mtd);
495 if (err)
Vikram Narayanancd66a2d2012-10-10 23:11:06 +0530496 pr_info("error %d occurred\n", err);
Artem Bityutskiybf608622008-12-08 13:37:48 +0200497 printk(KERN_INFO "=================================================\n");
498 return err;
499}
500module_init(mtd_subpagetest_init);
501
502static void __exit mtd_subpagetest_exit(void)
503{
504 return;
505}
506module_exit(mtd_subpagetest_exit);
507
508MODULE_DESCRIPTION("Subpage test module");
509MODULE_AUTHOR("Adrian Hunter");
510MODULE_LICENSE("GPL");