xref: /openbmc/linux/drivers/mtd/tests/oobtest.c (revision be54f8f1)
1a995c792SAkinobu Mita /*
2a995c792SAkinobu Mita  * Copyright (C) 2006-2008 Nokia Corporation
3a995c792SAkinobu Mita  *
4a995c792SAkinobu Mita  * This program is free software; you can redistribute it and/or modify it
5a995c792SAkinobu Mita  * under the terms of the GNU General Public License version 2 as published by
6a995c792SAkinobu Mita  * the Free Software Foundation.
7a995c792SAkinobu Mita  *
8a995c792SAkinobu Mita  * This program is distributed in the hope that it will be useful, but WITHOUT
9a995c792SAkinobu Mita  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10a995c792SAkinobu Mita  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11a995c792SAkinobu Mita  * more details.
12a995c792SAkinobu Mita  *
13a995c792SAkinobu Mita  * You should have received a copy of the GNU General Public License along with
14a995c792SAkinobu Mita  * this program; see the file COPYING. If not, write to the Free Software
15a995c792SAkinobu Mita  * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16a995c792SAkinobu Mita  *
17a995c792SAkinobu Mita  * Test OOB read and write on MTD device.
18a995c792SAkinobu Mita  *
19a995c792SAkinobu Mita  * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
20a995c792SAkinobu Mita  */
21a995c792SAkinobu Mita 
22a995c792SAkinobu Mita #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
23a995c792SAkinobu Mita 
24a995c792SAkinobu Mita #include <asm/div64.h>
25a995c792SAkinobu Mita #include <linux/init.h>
26a995c792SAkinobu Mita #include <linux/module.h>
27a995c792SAkinobu Mita #include <linux/moduleparam.h>
28a995c792SAkinobu Mita #include <linux/err.h>
29a995c792SAkinobu Mita #include <linux/mtd/mtd.h>
30a995c792SAkinobu Mita #include <linux/slab.h>
31a995c792SAkinobu Mita #include <linux/sched.h>
32a995c792SAkinobu Mita #include <linux/random.h>
33a995c792SAkinobu Mita 
344bf527aaSAkinobu Mita #include "mtd_test.h"
354bf527aaSAkinobu Mita 
36a995c792SAkinobu Mita static int dev = -EINVAL;
37a995c792SAkinobu Mita module_param(dev, int, S_IRUGO);
38a995c792SAkinobu Mita MODULE_PARM_DESC(dev, "MTD device number to use");
39a995c792SAkinobu Mita 
40a995c792SAkinobu Mita static struct mtd_info *mtd;
41a995c792SAkinobu Mita static unsigned char *readbuf;
42a995c792SAkinobu Mita static unsigned char *writebuf;
43a995c792SAkinobu Mita static unsigned char *bbt;
44a995c792SAkinobu Mita 
45a995c792SAkinobu Mita static int ebcnt;
46a995c792SAkinobu Mita static int pgcnt;
47a995c792SAkinobu Mita static int errcnt;
48a995c792SAkinobu Mita static int use_offset;
49a995c792SAkinobu Mita static int use_len;
50a995c792SAkinobu Mita static int use_len_max;
51a995c792SAkinobu Mita static int vary_offset;
52a995c792SAkinobu Mita static struct rnd_state rnd_state;
53a995c792SAkinobu Mita 
54a995c792SAkinobu Mita static void do_vary_offset(void)
55a995c792SAkinobu Mita {
56a995c792SAkinobu Mita 	use_len -= 1;
57a995c792SAkinobu Mita 	if (use_len < 1) {
58a995c792SAkinobu Mita 		use_offset += 1;
59a995c792SAkinobu Mita 		if (use_offset >= use_len_max)
60a995c792SAkinobu Mita 			use_offset = 0;
61a995c792SAkinobu Mita 		use_len = use_len_max - use_offset;
62a995c792SAkinobu Mita 	}
63a995c792SAkinobu Mita }
64a995c792SAkinobu Mita 
65a995c792SAkinobu Mita static int write_eraseblock(int ebnum)
66a995c792SAkinobu Mita {
67a995c792SAkinobu Mita 	int i;
68a995c792SAkinobu Mita 	struct mtd_oob_ops ops;
69a995c792SAkinobu Mita 	int err = 0;
70a995c792SAkinobu Mita 	loff_t addr = ebnum * mtd->erasesize;
71a995c792SAkinobu Mita 
72be54f8f1SAkinobu Mita 	prandom_bytes_state(&rnd_state, writebuf, use_len_max * pgcnt);
73a995c792SAkinobu Mita 	for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) {
74a995c792SAkinobu Mita 		ops.mode      = MTD_OPS_AUTO_OOB;
75a995c792SAkinobu Mita 		ops.len       = 0;
76a995c792SAkinobu Mita 		ops.retlen    = 0;
77a995c792SAkinobu Mita 		ops.ooblen    = use_len;
78a995c792SAkinobu Mita 		ops.oobretlen = 0;
79a995c792SAkinobu Mita 		ops.ooboffs   = use_offset;
80a995c792SAkinobu Mita 		ops.datbuf    = NULL;
81be54f8f1SAkinobu Mita 		ops.oobbuf    = writebuf + (use_len_max * i) + use_offset;
82a995c792SAkinobu Mita 		err = mtd_write_oob(mtd, addr, &ops);
83a995c792SAkinobu Mita 		if (err || ops.oobretlen != use_len) {
84a995c792SAkinobu Mita 			pr_err("error: writeoob failed at %#llx\n",
85a995c792SAkinobu Mita 			       (long long)addr);
86a995c792SAkinobu Mita 			pr_err("error: use_len %d, use_offset %d\n",
87a995c792SAkinobu Mita 			       use_len, use_offset);
88a995c792SAkinobu Mita 			errcnt += 1;
89a995c792SAkinobu Mita 			return err ? err : -1;
90a995c792SAkinobu Mita 		}
91a995c792SAkinobu Mita 		if (vary_offset)
92a995c792SAkinobu Mita 			do_vary_offset();
93a995c792SAkinobu Mita 	}
94a995c792SAkinobu Mita 
95a995c792SAkinobu Mita 	return err;
96a995c792SAkinobu Mita }
97a995c792SAkinobu Mita 
98a995c792SAkinobu Mita static int write_whole_device(void)
99a995c792SAkinobu Mita {
100a995c792SAkinobu Mita 	int err;
101a995c792SAkinobu Mita 	unsigned int i;
102a995c792SAkinobu Mita 
103a995c792SAkinobu Mita 	pr_info("writing OOBs of whole device\n");
104a995c792SAkinobu Mita 	for (i = 0; i < ebcnt; ++i) {
105a995c792SAkinobu Mita 		if (bbt[i])
106a995c792SAkinobu Mita 			continue;
107a995c792SAkinobu Mita 		err = write_eraseblock(i);
108a995c792SAkinobu Mita 		if (err)
109a995c792SAkinobu Mita 			return err;
110a995c792SAkinobu Mita 		if (i % 256 == 0)
111a995c792SAkinobu Mita 			pr_info("written up to eraseblock %u\n", i);
112a995c792SAkinobu Mita 		cond_resched();
113a995c792SAkinobu Mita 	}
114a995c792SAkinobu Mita 	pr_info("written %u eraseblocks\n", i);
115a995c792SAkinobu Mita 	return 0;
116a995c792SAkinobu Mita }
117a995c792SAkinobu Mita 
118a995c792SAkinobu Mita static int verify_eraseblock(int ebnum)
119a995c792SAkinobu Mita {
120a995c792SAkinobu Mita 	int i;
121a995c792SAkinobu Mita 	struct mtd_oob_ops ops;
122a995c792SAkinobu Mita 	int err = 0;
123a995c792SAkinobu Mita 	loff_t addr = ebnum * mtd->erasesize;
124a995c792SAkinobu Mita 
125be54f8f1SAkinobu Mita 	prandom_bytes_state(&rnd_state, writebuf, use_len_max * pgcnt);
126a995c792SAkinobu Mita 	for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) {
127a995c792SAkinobu Mita 		ops.mode      = MTD_OPS_AUTO_OOB;
128a995c792SAkinobu Mita 		ops.len       = 0;
129a995c792SAkinobu Mita 		ops.retlen    = 0;
130a995c792SAkinobu Mita 		ops.ooblen    = use_len;
131a995c792SAkinobu Mita 		ops.oobretlen = 0;
132a995c792SAkinobu Mita 		ops.ooboffs   = use_offset;
133a995c792SAkinobu Mita 		ops.datbuf    = NULL;
134a995c792SAkinobu Mita 		ops.oobbuf    = readbuf;
135a995c792SAkinobu Mita 		err = mtd_read_oob(mtd, addr, &ops);
136a995c792SAkinobu Mita 		if (err || ops.oobretlen != use_len) {
137a995c792SAkinobu Mita 			pr_err("error: readoob failed at %#llx\n",
138a995c792SAkinobu Mita 			       (long long)addr);
139a995c792SAkinobu Mita 			errcnt += 1;
140a995c792SAkinobu Mita 			return err ? err : -1;
141a995c792SAkinobu Mita 		}
142be54f8f1SAkinobu Mita 		if (memcmp(readbuf, writebuf + (use_len_max * i) + use_offset,
143be54f8f1SAkinobu Mita 			   use_len)) {
144a995c792SAkinobu Mita 			pr_err("error: verify failed at %#llx\n",
145a995c792SAkinobu Mita 			       (long long)addr);
146a995c792SAkinobu Mita 			errcnt += 1;
147a995c792SAkinobu Mita 			if (errcnt > 1000) {
148a995c792SAkinobu Mita 				pr_err("error: too many errors\n");
149a995c792SAkinobu Mita 				return -1;
150a995c792SAkinobu Mita 			}
151a995c792SAkinobu Mita 		}
152a995c792SAkinobu Mita 		if (use_offset != 0 || use_len < mtd->ecclayout->oobavail) {
153a995c792SAkinobu Mita 			int k;
154a995c792SAkinobu Mita 
155a995c792SAkinobu Mita 			ops.mode      = MTD_OPS_AUTO_OOB;
156a995c792SAkinobu Mita 			ops.len       = 0;
157a995c792SAkinobu Mita 			ops.retlen    = 0;
158a995c792SAkinobu Mita 			ops.ooblen    = mtd->ecclayout->oobavail;
159a995c792SAkinobu Mita 			ops.oobretlen = 0;
160a995c792SAkinobu Mita 			ops.ooboffs   = 0;
161a995c792SAkinobu Mita 			ops.datbuf    = NULL;
162a995c792SAkinobu Mita 			ops.oobbuf    = readbuf;
163a995c792SAkinobu Mita 			err = mtd_read_oob(mtd, addr, &ops);
164a995c792SAkinobu Mita 			if (err || ops.oobretlen != mtd->ecclayout->oobavail) {
165a995c792SAkinobu Mita 				pr_err("error: readoob failed at %#llx\n",
166a995c792SAkinobu Mita 						(long long)addr);
167a995c792SAkinobu Mita 				errcnt += 1;
168a995c792SAkinobu Mita 				return err ? err : -1;
169a995c792SAkinobu Mita 			}
170be54f8f1SAkinobu Mita 			if (memcmp(readbuf + use_offset,
171be54f8f1SAkinobu Mita 				   writebuf + (use_len_max * i) + use_offset,
172be54f8f1SAkinobu Mita 				   use_len)) {
173a995c792SAkinobu Mita 				pr_err("error: verify failed at %#llx\n",
174a995c792SAkinobu Mita 						(long long)addr);
175a995c792SAkinobu Mita 				errcnt += 1;
176a995c792SAkinobu Mita 				if (errcnt > 1000) {
177a995c792SAkinobu Mita 					pr_err("error: too many errors\n");
178a995c792SAkinobu Mita 					return -1;
179a995c792SAkinobu Mita 				}
180a995c792SAkinobu Mita 			}
181a995c792SAkinobu Mita 			for (k = 0; k < use_offset; ++k)
182a995c792SAkinobu Mita 				if (readbuf[k] != 0xff) {
183a995c792SAkinobu Mita 					pr_err("error: verify 0xff "
184a995c792SAkinobu Mita 					       "failed at %#llx\n",
185a995c792SAkinobu Mita 					       (long long)addr);
186a995c792SAkinobu Mita 					errcnt += 1;
187a995c792SAkinobu Mita 					if (errcnt > 1000) {
188a995c792SAkinobu Mita 						pr_err("error: too "
189a995c792SAkinobu Mita 						       "many errors\n");
190a995c792SAkinobu Mita 						return -1;
191a995c792SAkinobu Mita 					}
192a995c792SAkinobu Mita 				}
193a995c792SAkinobu Mita 			for (k = use_offset + use_len;
194a995c792SAkinobu Mita 			     k < mtd->ecclayout->oobavail; ++k)
195a995c792SAkinobu Mita 				if (readbuf[k] != 0xff) {
196a995c792SAkinobu Mita 					pr_err("error: verify 0xff "
197a995c792SAkinobu Mita 					       "failed at %#llx\n",
198a995c792SAkinobu Mita 					       (long long)addr);
199a995c792SAkinobu Mita 					errcnt += 1;
200a995c792SAkinobu Mita 					if (errcnt > 1000) {
201a995c792SAkinobu Mita 						pr_err("error: too "
202a995c792SAkinobu Mita 						       "many errors\n");
203a995c792SAkinobu Mita 						return -1;
204a995c792SAkinobu Mita 					}
205a995c792SAkinobu Mita 				}
206a995c792SAkinobu Mita 		}
207a995c792SAkinobu Mita 		if (vary_offset)
208a995c792SAkinobu Mita 			do_vary_offset();
209a995c792SAkinobu Mita 	}
210a995c792SAkinobu Mita 	return err;
211a995c792SAkinobu Mita }
212a995c792SAkinobu Mita 
213a995c792SAkinobu Mita static int verify_eraseblock_in_one_go(int ebnum)
214a995c792SAkinobu Mita {
215a995c792SAkinobu Mita 	struct mtd_oob_ops ops;
216a995c792SAkinobu Mita 	int err = 0;
217a995c792SAkinobu Mita 	loff_t addr = ebnum * mtd->erasesize;
218a995c792SAkinobu Mita 	size_t len = mtd->ecclayout->oobavail * pgcnt;
219a995c792SAkinobu Mita 
220a995c792SAkinobu Mita 	prandom_bytes_state(&rnd_state, writebuf, len);
221a995c792SAkinobu Mita 	ops.mode      = MTD_OPS_AUTO_OOB;
222a995c792SAkinobu Mita 	ops.len       = 0;
223a995c792SAkinobu Mita 	ops.retlen    = 0;
224a995c792SAkinobu Mita 	ops.ooblen    = len;
225a995c792SAkinobu Mita 	ops.oobretlen = 0;
226a995c792SAkinobu Mita 	ops.ooboffs   = 0;
227a995c792SAkinobu Mita 	ops.datbuf    = NULL;
228a995c792SAkinobu Mita 	ops.oobbuf    = readbuf;
229a995c792SAkinobu Mita 	err = mtd_read_oob(mtd, addr, &ops);
230a995c792SAkinobu Mita 	if (err || ops.oobretlen != len) {
231a995c792SAkinobu Mita 		pr_err("error: readoob failed at %#llx\n",
232a995c792SAkinobu Mita 		       (long long)addr);
233a995c792SAkinobu Mita 		errcnt += 1;
234a995c792SAkinobu Mita 		return err ? err : -1;
235a995c792SAkinobu Mita 	}
236a995c792SAkinobu Mita 	if (memcmp(readbuf, writebuf, len)) {
237a995c792SAkinobu Mita 		pr_err("error: verify failed at %#llx\n",
238a995c792SAkinobu Mita 		       (long long)addr);
239a995c792SAkinobu Mita 		errcnt += 1;
240a995c792SAkinobu Mita 		if (errcnt > 1000) {
241a995c792SAkinobu Mita 			pr_err("error: too many errors\n");
242a995c792SAkinobu Mita 			return -1;
243a995c792SAkinobu Mita 		}
244a995c792SAkinobu Mita 	}
245a995c792SAkinobu Mita 
246a995c792SAkinobu Mita 	return err;
247a995c792SAkinobu Mita }
248a995c792SAkinobu Mita 
249a995c792SAkinobu Mita static int verify_all_eraseblocks(void)
250a995c792SAkinobu Mita {
251a995c792SAkinobu Mita 	int err;
252a995c792SAkinobu Mita 	unsigned int i;
253a995c792SAkinobu Mita 
254a995c792SAkinobu Mita 	pr_info("verifying all eraseblocks\n");
255a995c792SAkinobu Mita 	for (i = 0; i < ebcnt; ++i) {
256a995c792SAkinobu Mita 		if (bbt[i])
257a995c792SAkinobu Mita 			continue;
258a995c792SAkinobu Mita 		err = verify_eraseblock(i);
259a995c792SAkinobu Mita 		if (err)
260a995c792SAkinobu Mita 			return err;
261a995c792SAkinobu Mita 		if (i % 256 == 0)
262a995c792SAkinobu Mita 			pr_info("verified up to eraseblock %u\n", i);
263a995c792SAkinobu Mita 		cond_resched();
264a995c792SAkinobu Mita 	}
265a995c792SAkinobu Mita 	pr_info("verified %u eraseblocks\n", i);
266a995c792SAkinobu Mita 	return 0;
267a995c792SAkinobu Mita }
268a995c792SAkinobu Mita 
269a995c792SAkinobu Mita static int __init mtd_oobtest_init(void)
270a995c792SAkinobu Mita {
271a995c792SAkinobu Mita 	int err = 0;
272a995c792SAkinobu Mita 	unsigned int i;
273a995c792SAkinobu Mita 	uint64_t tmp;
274a995c792SAkinobu Mita 	struct mtd_oob_ops ops;
275a995c792SAkinobu Mita 	loff_t addr = 0, addr0;
276a995c792SAkinobu Mita 
277a995c792SAkinobu Mita 	printk(KERN_INFO "\n");
278a995c792SAkinobu Mita 	printk(KERN_INFO "=================================================\n");
279a995c792SAkinobu Mita 
280a995c792SAkinobu Mita 	if (dev < 0) {
281a995c792SAkinobu Mita 		pr_info("Please specify a valid mtd-device via module parameter\n");
282a995c792SAkinobu Mita 		pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
283a995c792SAkinobu Mita 		return -EINVAL;
284a995c792SAkinobu Mita 	}
285a995c792SAkinobu Mita 
286a995c792SAkinobu Mita 	pr_info("MTD device: %d\n", dev);
287a995c792SAkinobu Mita 
288a995c792SAkinobu Mita 	mtd = get_mtd_device(NULL, dev);
289a995c792SAkinobu Mita 	if (IS_ERR(mtd)) {
290a995c792SAkinobu Mita 		err = PTR_ERR(mtd);
291a995c792SAkinobu Mita 		pr_err("error: cannot get MTD device\n");
292a995c792SAkinobu Mita 		return err;
293a995c792SAkinobu Mita 	}
294a995c792SAkinobu Mita 
295818b9739SHuang Shijie 	if (!mtd_type_is_nand(mtd)) {
296a995c792SAkinobu Mita 		pr_info("this test requires NAND flash\n");
297a995c792SAkinobu Mita 		goto out;
298a995c792SAkinobu Mita 	}
299a995c792SAkinobu Mita 
300a995c792SAkinobu Mita 	tmp = mtd->size;
301a995c792SAkinobu Mita 	do_div(tmp, mtd->erasesize);
302a995c792SAkinobu Mita 	ebcnt = tmp;
303a995c792SAkinobu Mita 	pgcnt = mtd->erasesize / mtd->writesize;
304a995c792SAkinobu Mita 
305a995c792SAkinobu Mita 	pr_info("MTD device size %llu, eraseblock size %u, "
306a995c792SAkinobu Mita 	       "page size %u, count of eraseblocks %u, pages per "
307a995c792SAkinobu Mita 	       "eraseblock %u, OOB size %u\n",
308a995c792SAkinobu Mita 	       (unsigned long long)mtd->size, mtd->erasesize,
309a995c792SAkinobu Mita 	       mtd->writesize, ebcnt, pgcnt, mtd->oobsize);
310a995c792SAkinobu Mita 
311a995c792SAkinobu Mita 	err = -ENOMEM;
312a995c792SAkinobu Mita 	readbuf = kmalloc(mtd->erasesize, GFP_KERNEL);
313a995c792SAkinobu Mita 	if (!readbuf)
314a995c792SAkinobu Mita 		goto out;
315a995c792SAkinobu Mita 	writebuf = kmalloc(mtd->erasesize, GFP_KERNEL);
316a995c792SAkinobu Mita 	if (!writebuf)
317a995c792SAkinobu Mita 		goto out;
3184bf527aaSAkinobu Mita 	bbt = kzalloc(ebcnt, GFP_KERNEL);
3194bf527aaSAkinobu Mita 	if (!bbt)
3204bf527aaSAkinobu Mita 		goto out;
321a995c792SAkinobu Mita 
3224bf527aaSAkinobu Mita 	err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt);
323a995c792SAkinobu Mita 	if (err)
324a995c792SAkinobu Mita 		goto out;
325a995c792SAkinobu Mita 
326a995c792SAkinobu Mita 	use_offset = 0;
327a995c792SAkinobu Mita 	use_len = mtd->ecclayout->oobavail;
328a995c792SAkinobu Mita 	use_len_max = mtd->ecclayout->oobavail;
329a995c792SAkinobu Mita 	vary_offset = 0;
330a995c792SAkinobu Mita 
331a995c792SAkinobu Mita 	/* First test: write all OOB, read it back and verify */
332a995c792SAkinobu Mita 	pr_info("test 1 of 5\n");
333a995c792SAkinobu Mita 
3344bf527aaSAkinobu Mita 	err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
335a995c792SAkinobu Mita 	if (err)
336a995c792SAkinobu Mita 		goto out;
337a995c792SAkinobu Mita 
338a995c792SAkinobu Mita 	prandom_seed_state(&rnd_state, 1);
339a995c792SAkinobu Mita 	err = write_whole_device();
340a995c792SAkinobu Mita 	if (err)
341a995c792SAkinobu Mita 		goto out;
342a995c792SAkinobu Mita 
343a995c792SAkinobu Mita 	prandom_seed_state(&rnd_state, 1);
344a995c792SAkinobu Mita 	err = verify_all_eraseblocks();
345a995c792SAkinobu Mita 	if (err)
346a995c792SAkinobu Mita 		goto out;
347a995c792SAkinobu Mita 
348a995c792SAkinobu Mita 	/*
349a995c792SAkinobu Mita 	 * Second test: write all OOB, a block at a time, read it back and
350a995c792SAkinobu Mita 	 * verify.
351a995c792SAkinobu Mita 	 */
352a995c792SAkinobu Mita 	pr_info("test 2 of 5\n");
353a995c792SAkinobu Mita 
3544bf527aaSAkinobu Mita 	err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
355a995c792SAkinobu Mita 	if (err)
356a995c792SAkinobu Mita 		goto out;
357a995c792SAkinobu Mita 
358a995c792SAkinobu Mita 	prandom_seed_state(&rnd_state, 3);
359a995c792SAkinobu Mita 	err = write_whole_device();
360a995c792SAkinobu Mita 	if (err)
361a995c792SAkinobu Mita 		goto out;
362a995c792SAkinobu Mita 
363a995c792SAkinobu Mita 	/* Check all eraseblocks */
364a995c792SAkinobu Mita 	prandom_seed_state(&rnd_state, 3);
365a995c792SAkinobu Mita 	pr_info("verifying all eraseblocks\n");
366a995c792SAkinobu Mita 	for (i = 0; i < ebcnt; ++i) {
367a995c792SAkinobu Mita 		if (bbt[i])
368a995c792SAkinobu Mita 			continue;
369a995c792SAkinobu Mita 		err = verify_eraseblock_in_one_go(i);
370a995c792SAkinobu Mita 		if (err)
371a995c792SAkinobu Mita 			goto out;
372a995c792SAkinobu Mita 		if (i % 256 == 0)
373a995c792SAkinobu Mita 			pr_info("verified up to eraseblock %u\n", i);
374a995c792SAkinobu Mita 		cond_resched();
375a995c792SAkinobu Mita 	}
376a995c792SAkinobu Mita 	pr_info("verified %u eraseblocks\n", i);
377a995c792SAkinobu Mita 
378a995c792SAkinobu Mita 	/*
379a995c792SAkinobu Mita 	 * Third test: write OOB at varying offsets and lengths, read it back
380a995c792SAkinobu Mita 	 * and verify.
381a995c792SAkinobu Mita 	 */
382a995c792SAkinobu Mita 	pr_info("test 3 of 5\n");
383a995c792SAkinobu Mita 
3844bf527aaSAkinobu Mita 	err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
385a995c792SAkinobu Mita 	if (err)
386a995c792SAkinobu Mita 		goto out;
387a995c792SAkinobu Mita 
388a995c792SAkinobu Mita 	/* Write all eraseblocks */
389a995c792SAkinobu Mita 	use_offset = 0;
390a995c792SAkinobu Mita 	use_len = mtd->ecclayout->oobavail;
391a995c792SAkinobu Mita 	use_len_max = mtd->ecclayout->oobavail;
392a995c792SAkinobu Mita 	vary_offset = 1;
393a995c792SAkinobu Mita 	prandom_seed_state(&rnd_state, 5);
394a995c792SAkinobu Mita 
395a995c792SAkinobu Mita 	err = write_whole_device();
396a995c792SAkinobu Mita 	if (err)
397a995c792SAkinobu Mita 		goto out;
398a995c792SAkinobu Mita 
399a995c792SAkinobu Mita 	/* Check all eraseblocks */
400a995c792SAkinobu Mita 	use_offset = 0;
401a995c792SAkinobu Mita 	use_len = mtd->ecclayout->oobavail;
402a995c792SAkinobu Mita 	use_len_max = mtd->ecclayout->oobavail;
403a995c792SAkinobu Mita 	vary_offset = 1;
404a995c792SAkinobu Mita 	prandom_seed_state(&rnd_state, 5);
405a995c792SAkinobu Mita 	err = verify_all_eraseblocks();
406a995c792SAkinobu Mita 	if (err)
407a995c792SAkinobu Mita 		goto out;
408a995c792SAkinobu Mita 
409a995c792SAkinobu Mita 	use_offset = 0;
410a995c792SAkinobu Mita 	use_len = mtd->ecclayout->oobavail;
411a995c792SAkinobu Mita 	use_len_max = mtd->ecclayout->oobavail;
412a995c792SAkinobu Mita 	vary_offset = 0;
413a995c792SAkinobu Mita 
414a995c792SAkinobu Mita 	/* Fourth test: try to write off end of device */
415a995c792SAkinobu Mita 	pr_info("test 4 of 5\n");
416a995c792SAkinobu Mita 
4174bf527aaSAkinobu Mita 	err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
418a995c792SAkinobu Mita 	if (err)
419a995c792SAkinobu Mita 		goto out;
420a995c792SAkinobu Mita 
421a995c792SAkinobu Mita 	addr0 = 0;
422a995c792SAkinobu Mita 	for (i = 0; i < ebcnt && bbt[i]; ++i)
423a995c792SAkinobu Mita 		addr0 += mtd->erasesize;
424a995c792SAkinobu Mita 
425a995c792SAkinobu Mita 	/* Attempt to write off end of OOB */
426a995c792SAkinobu Mita 	ops.mode      = MTD_OPS_AUTO_OOB;
427a995c792SAkinobu Mita 	ops.len       = 0;
428a995c792SAkinobu Mita 	ops.retlen    = 0;
429a995c792SAkinobu Mita 	ops.ooblen    = 1;
430a995c792SAkinobu Mita 	ops.oobretlen = 0;
431a995c792SAkinobu Mita 	ops.ooboffs   = mtd->ecclayout->oobavail;
432a995c792SAkinobu Mita 	ops.datbuf    = NULL;
433a995c792SAkinobu Mita 	ops.oobbuf    = writebuf;
434a995c792SAkinobu Mita 	pr_info("attempting to start write past end of OOB\n");
435a995c792SAkinobu Mita 	pr_info("an error is expected...\n");
436a995c792SAkinobu Mita 	err = mtd_write_oob(mtd, addr0, &ops);
437a995c792SAkinobu Mita 	if (err) {
438a995c792SAkinobu Mita 		pr_info("error occurred as expected\n");
439a995c792SAkinobu Mita 		err = 0;
440a995c792SAkinobu Mita 	} else {
441a995c792SAkinobu Mita 		pr_err("error: can write past end of OOB\n");
442a995c792SAkinobu Mita 		errcnt += 1;
443a995c792SAkinobu Mita 	}
444a995c792SAkinobu Mita 
445a995c792SAkinobu Mita 	/* Attempt to read off end of OOB */
446a995c792SAkinobu Mita 	ops.mode      = MTD_OPS_AUTO_OOB;
447a995c792SAkinobu Mita 	ops.len       = 0;
448a995c792SAkinobu Mita 	ops.retlen    = 0;
449a995c792SAkinobu Mita 	ops.ooblen    = 1;
450a995c792SAkinobu Mita 	ops.oobretlen = 0;
451a995c792SAkinobu Mita 	ops.ooboffs   = mtd->ecclayout->oobavail;
452a995c792SAkinobu Mita 	ops.datbuf    = NULL;
453a995c792SAkinobu Mita 	ops.oobbuf    = readbuf;
454a995c792SAkinobu Mita 	pr_info("attempting to start read past end of OOB\n");
455a995c792SAkinobu Mita 	pr_info("an error is expected...\n");
456a995c792SAkinobu Mita 	err = mtd_read_oob(mtd, addr0, &ops);
457a995c792SAkinobu Mita 	if (err) {
458a995c792SAkinobu Mita 		pr_info("error occurred as expected\n");
459a995c792SAkinobu Mita 		err = 0;
460a995c792SAkinobu Mita 	} else {
461a995c792SAkinobu Mita 		pr_err("error: can read past end of OOB\n");
462a995c792SAkinobu Mita 		errcnt += 1;
463a995c792SAkinobu Mita 	}
464a995c792SAkinobu Mita 
465a995c792SAkinobu Mita 	if (bbt[ebcnt - 1])
466a995c792SAkinobu Mita 		pr_info("skipping end of device tests because last "
467a995c792SAkinobu Mita 		       "block is bad\n");
468a995c792SAkinobu Mita 	else {
469a995c792SAkinobu Mita 		/* Attempt to write off end of device */
470a995c792SAkinobu Mita 		ops.mode      = MTD_OPS_AUTO_OOB;
471a995c792SAkinobu Mita 		ops.len       = 0;
472a995c792SAkinobu Mita 		ops.retlen    = 0;
473a995c792SAkinobu Mita 		ops.ooblen    = mtd->ecclayout->oobavail + 1;
474a995c792SAkinobu Mita 		ops.oobretlen = 0;
475a995c792SAkinobu Mita 		ops.ooboffs   = 0;
476a995c792SAkinobu Mita 		ops.datbuf    = NULL;
477a995c792SAkinobu Mita 		ops.oobbuf    = writebuf;
478a995c792SAkinobu Mita 		pr_info("attempting to write past end of device\n");
479a995c792SAkinobu Mita 		pr_info("an error is expected...\n");
480a995c792SAkinobu Mita 		err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops);
481a995c792SAkinobu Mita 		if (err) {
482a995c792SAkinobu Mita 			pr_info("error occurred as expected\n");
483a995c792SAkinobu Mita 			err = 0;
484a995c792SAkinobu Mita 		} else {
485a995c792SAkinobu Mita 			pr_err("error: wrote past end of device\n");
486a995c792SAkinobu Mita 			errcnt += 1;
487a995c792SAkinobu Mita 		}
488a995c792SAkinobu Mita 
489a995c792SAkinobu Mita 		/* Attempt to read off end of device */
490a995c792SAkinobu Mita 		ops.mode      = MTD_OPS_AUTO_OOB;
491a995c792SAkinobu Mita 		ops.len       = 0;
492a995c792SAkinobu Mita 		ops.retlen    = 0;
493a995c792SAkinobu Mita 		ops.ooblen    = mtd->ecclayout->oobavail + 1;
494a995c792SAkinobu Mita 		ops.oobretlen = 0;
495a995c792SAkinobu Mita 		ops.ooboffs   = 0;
496a995c792SAkinobu Mita 		ops.datbuf    = NULL;
497a995c792SAkinobu Mita 		ops.oobbuf    = readbuf;
498a995c792SAkinobu Mita 		pr_info("attempting to read past end of device\n");
499a995c792SAkinobu Mita 		pr_info("an error is expected...\n");
500a995c792SAkinobu Mita 		err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops);
501a995c792SAkinobu Mita 		if (err) {
502a995c792SAkinobu Mita 			pr_info("error occurred as expected\n");
503a995c792SAkinobu Mita 			err = 0;
504a995c792SAkinobu Mita 		} else {
505a995c792SAkinobu Mita 			pr_err("error: read past end of device\n");
506a995c792SAkinobu Mita 			errcnt += 1;
507a995c792SAkinobu Mita 		}
508a995c792SAkinobu Mita 
5094bf527aaSAkinobu Mita 		err = mtdtest_erase_eraseblock(mtd, ebcnt - 1);
510a995c792SAkinobu Mita 		if (err)
511a995c792SAkinobu Mita 			goto out;
512a995c792SAkinobu Mita 
513a995c792SAkinobu Mita 		/* Attempt to write off end of device */
514a995c792SAkinobu Mita 		ops.mode      = MTD_OPS_AUTO_OOB;
515a995c792SAkinobu Mita 		ops.len       = 0;
516a995c792SAkinobu Mita 		ops.retlen    = 0;
517a995c792SAkinobu Mita 		ops.ooblen    = mtd->ecclayout->oobavail;
518a995c792SAkinobu Mita 		ops.oobretlen = 0;
519a995c792SAkinobu Mita 		ops.ooboffs   = 1;
520a995c792SAkinobu Mita 		ops.datbuf    = NULL;
521a995c792SAkinobu Mita 		ops.oobbuf    = writebuf;
522a995c792SAkinobu Mita 		pr_info("attempting to write past end of device\n");
523a995c792SAkinobu Mita 		pr_info("an error is expected...\n");
524a995c792SAkinobu Mita 		err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops);
525a995c792SAkinobu Mita 		if (err) {
526a995c792SAkinobu Mita 			pr_info("error occurred as expected\n");
527a995c792SAkinobu Mita 			err = 0;
528a995c792SAkinobu Mita 		} else {
529a995c792SAkinobu Mita 			pr_err("error: wrote past end of device\n");
530a995c792SAkinobu Mita 			errcnt += 1;
531a995c792SAkinobu Mita 		}
532a995c792SAkinobu Mita 
533a995c792SAkinobu Mita 		/* Attempt to read off end of device */
534a995c792SAkinobu Mita 		ops.mode      = MTD_OPS_AUTO_OOB;
535a995c792SAkinobu Mita 		ops.len       = 0;
536a995c792SAkinobu Mita 		ops.retlen    = 0;
537a995c792SAkinobu Mita 		ops.ooblen    = mtd->ecclayout->oobavail;
538a995c792SAkinobu Mita 		ops.oobretlen = 0;
539a995c792SAkinobu Mita 		ops.ooboffs   = 1;
540a995c792SAkinobu Mita 		ops.datbuf    = NULL;
541a995c792SAkinobu Mita 		ops.oobbuf    = readbuf;
542a995c792SAkinobu Mita 		pr_info("attempting to read past end of device\n");
543a995c792SAkinobu Mita 		pr_info("an error is expected...\n");
544a995c792SAkinobu Mita 		err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops);
545a995c792SAkinobu Mita 		if (err) {
546a995c792SAkinobu Mita 			pr_info("error occurred as expected\n");
547a995c792SAkinobu Mita 			err = 0;
548a995c792SAkinobu Mita 		} else {
549a995c792SAkinobu Mita 			pr_err("error: read past end of device\n");
550a995c792SAkinobu Mita 			errcnt += 1;
551a995c792SAkinobu Mita 		}
552a995c792SAkinobu Mita 	}
553a995c792SAkinobu Mita 
554a995c792SAkinobu Mita 	/* Fifth test: write / read across block boundaries */
555a995c792SAkinobu Mita 	pr_info("test 5 of 5\n");
556a995c792SAkinobu Mita 
557a995c792SAkinobu Mita 	/* Erase all eraseblocks */
5584bf527aaSAkinobu Mita 	err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
559a995c792SAkinobu Mita 	if (err)
560a995c792SAkinobu Mita 		goto out;
561a995c792SAkinobu Mita 
562a995c792SAkinobu Mita 	/* Write all eraseblocks */
563a995c792SAkinobu Mita 	prandom_seed_state(&rnd_state, 11);
564a995c792SAkinobu Mita 	pr_info("writing OOBs of whole device\n");
565a995c792SAkinobu Mita 	for (i = 0; i < ebcnt - 1; ++i) {
566a995c792SAkinobu Mita 		int cnt = 2;
567a995c792SAkinobu Mita 		int pg;
568a995c792SAkinobu Mita 		size_t sz = mtd->ecclayout->oobavail;
569a995c792SAkinobu Mita 		if (bbt[i] || bbt[i + 1])
570a995c792SAkinobu Mita 			continue;
571a995c792SAkinobu Mita 		addr = (i + 1) * mtd->erasesize - mtd->writesize;
572be54f8f1SAkinobu Mita 		prandom_bytes_state(&rnd_state, writebuf, sz * cnt);
573a995c792SAkinobu Mita 		for (pg = 0; pg < cnt; ++pg) {
574a995c792SAkinobu Mita 			ops.mode      = MTD_OPS_AUTO_OOB;
575a995c792SAkinobu Mita 			ops.len       = 0;
576a995c792SAkinobu Mita 			ops.retlen    = 0;
577a995c792SAkinobu Mita 			ops.ooblen    = sz;
578a995c792SAkinobu Mita 			ops.oobretlen = 0;
579a995c792SAkinobu Mita 			ops.ooboffs   = 0;
580a995c792SAkinobu Mita 			ops.datbuf    = NULL;
581be54f8f1SAkinobu Mita 			ops.oobbuf    = writebuf + pg * sz;
582a995c792SAkinobu Mita 			err = mtd_write_oob(mtd, addr, &ops);
583a995c792SAkinobu Mita 			if (err)
584a995c792SAkinobu Mita 				goto out;
585a995c792SAkinobu Mita 			if (i % 256 == 0)
586a995c792SAkinobu Mita 				pr_info("written up to eraseblock %u\n", i);
587a995c792SAkinobu Mita 			cond_resched();
588a995c792SAkinobu Mita 			addr += mtd->writesize;
589a995c792SAkinobu Mita 		}
590a995c792SAkinobu Mita 	}
591a995c792SAkinobu Mita 	pr_info("written %u eraseblocks\n", i);
592a995c792SAkinobu Mita 
593a995c792SAkinobu Mita 	/* Check all eraseblocks */
594a995c792SAkinobu Mita 	prandom_seed_state(&rnd_state, 11);
595a995c792SAkinobu Mita 	pr_info("verifying all eraseblocks\n");
596a995c792SAkinobu Mita 	for (i = 0; i < ebcnt - 1; ++i) {
597a995c792SAkinobu Mita 		if (bbt[i] || bbt[i + 1])
598a995c792SAkinobu Mita 			continue;
599a995c792SAkinobu Mita 		prandom_bytes_state(&rnd_state, writebuf,
600a995c792SAkinobu Mita 					mtd->ecclayout->oobavail * 2);
601a995c792SAkinobu Mita 		addr = (i + 1) * mtd->erasesize - mtd->writesize;
602a995c792SAkinobu Mita 		ops.mode      = MTD_OPS_AUTO_OOB;
603a995c792SAkinobu Mita 		ops.len       = 0;
604a995c792SAkinobu Mita 		ops.retlen    = 0;
605a995c792SAkinobu Mita 		ops.ooblen    = mtd->ecclayout->oobavail * 2;
606a995c792SAkinobu Mita 		ops.oobretlen = 0;
607a995c792SAkinobu Mita 		ops.ooboffs   = 0;
608a995c792SAkinobu Mita 		ops.datbuf    = NULL;
609a995c792SAkinobu Mita 		ops.oobbuf    = readbuf;
610a995c792SAkinobu Mita 		err = mtd_read_oob(mtd, addr, &ops);
611a995c792SAkinobu Mita 		if (err)
612a995c792SAkinobu Mita 			goto out;
613a995c792SAkinobu Mita 		if (memcmp(readbuf, writebuf, mtd->ecclayout->oobavail * 2)) {
614a995c792SAkinobu Mita 			pr_err("error: verify failed at %#llx\n",
615a995c792SAkinobu Mita 			       (long long)addr);
616a995c792SAkinobu Mita 			errcnt += 1;
617a995c792SAkinobu Mita 			if (errcnt > 1000) {
618a995c792SAkinobu Mita 				pr_err("error: too many errors\n");
619a995c792SAkinobu Mita 				goto out;
620a995c792SAkinobu Mita 			}
621a995c792SAkinobu Mita 		}
622a995c792SAkinobu Mita 		if (i % 256 == 0)
623a995c792SAkinobu Mita 			pr_info("verified up to eraseblock %u\n", i);
624a995c792SAkinobu Mita 		cond_resched();
625a995c792SAkinobu Mita 	}
626a995c792SAkinobu Mita 	pr_info("verified %u eraseblocks\n", i);
627a995c792SAkinobu Mita 
628a995c792SAkinobu Mita 	pr_info("finished with %d errors\n", errcnt);
629a995c792SAkinobu Mita out:
630a995c792SAkinobu Mita 	kfree(bbt);
631a995c792SAkinobu Mita 	kfree(writebuf);
632a995c792SAkinobu Mita 	kfree(readbuf);
633a995c792SAkinobu Mita 	put_mtd_device(mtd);
634a995c792SAkinobu Mita 	if (err)
635a995c792SAkinobu Mita 		pr_info("error %d occurred\n", err);
636a995c792SAkinobu Mita 	printk(KERN_INFO "=================================================\n");
637a995c792SAkinobu Mita 	return err;
638a995c792SAkinobu Mita }
639a995c792SAkinobu Mita module_init(mtd_oobtest_init);
640a995c792SAkinobu Mita 
641a995c792SAkinobu Mita static void __exit mtd_oobtest_exit(void)
642a995c792SAkinobu Mita {
643a995c792SAkinobu Mita 	return;
644a995c792SAkinobu Mita }
645a995c792SAkinobu Mita module_exit(mtd_oobtest_exit);
646a995c792SAkinobu Mita 
647a995c792SAkinobu Mita MODULE_DESCRIPTION("Out-of-band test module");
648a995c792SAkinobu Mita MODULE_AUTHOR("Adrian Hunter");
649a995c792SAkinobu Mita MODULE_LICENSE("GPL");
650