blob: 1cb3f7758fb60d8b084c27cc74d2098d5b7a691f [file] [log] [blame]
Artem Bityutskiye3644da2008-12-08 13:33:29 +02001/*
2 * Copyright (C) 2006-2008 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 OOB read and write on MTD device.
18 *
19 * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
20 */
21
Vikram Narayanan04810272012-10-10 23:12:02 +053022#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
23
Artem Bityutskiye3644da2008-12-08 13:33:29 +020024#include <asm/div64.h>
25#include <linux/init.h>
26#include <linux/module.h>
27#include <linux/moduleparam.h>
28#include <linux/err.h>
29#include <linux/mtd/mtd.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090030#include <linux/slab.h>
Artem Bityutskiye3644da2008-12-08 13:33:29 +020031#include <linux/sched.h>
Akinobu Mita8dad0492013-02-27 17:05:33 -080032#include <linux/random.h>
Artem Bityutskiye3644da2008-12-08 13:33:29 +020033
Akinobu Mita4bf527a2013-08-03 18:52:09 +090034#include "mtd_test.h"
35
Wolfram Sang74060602011-10-30 00:11:53 +020036static int dev = -EINVAL;
Roger Quadrosafc0ea12014-10-21 16:53:28 +030037static int bitflip_limit;
Artem Bityutskiye3644da2008-12-08 13:33:29 +020038module_param(dev, int, S_IRUGO);
39MODULE_PARM_DESC(dev, "MTD device number to use");
Roger Quadrosafc0ea12014-10-21 16:53:28 +030040module_param(bitflip_limit, int, S_IRUGO);
41MODULE_PARM_DESC(bitflip_limit, "Max. allowed bitflips per page");
Artem Bityutskiye3644da2008-12-08 13:33:29 +020042
43static struct mtd_info *mtd;
44static unsigned char *readbuf;
45static unsigned char *writebuf;
46static unsigned char *bbt;
47
48static int ebcnt;
49static int pgcnt;
50static int errcnt;
51static int use_offset;
52static int use_len;
53static int use_len_max;
54static int vary_offset;
Akinobu Mita8dad0492013-02-27 17:05:33 -080055static struct rnd_state rnd_state;
Artem Bityutskiye3644da2008-12-08 13:33:29 +020056
Artem Bityutskiye3644da2008-12-08 13:33:29 +020057static void do_vary_offset(void)
58{
59 use_len -= 1;
60 if (use_len < 1) {
61 use_offset += 1;
62 if (use_offset >= use_len_max)
63 use_offset = 0;
64 use_len = use_len_max - use_offset;
65 }
66}
67
68static int write_eraseblock(int ebnum)
69{
70 int i;
71 struct mtd_oob_ops ops;
72 int err = 0;
Brian Norrisb9da8ba2015-02-28 02:02:26 -080073 loff_t addr = (loff_t)ebnum * mtd->erasesize;
Artem Bityutskiye3644da2008-12-08 13:33:29 +020074
Akinobu Mitabe54f8f2014-03-08 00:24:10 +090075 prandom_bytes_state(&rnd_state, writebuf, use_len_max * pgcnt);
Artem Bityutskiye3644da2008-12-08 13:33:29 +020076 for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) {
Brian Norris0612b9d2011-08-30 18:45:40 -070077 ops.mode = MTD_OPS_AUTO_OOB;
Artem Bityutskiye3644da2008-12-08 13:33:29 +020078 ops.len = 0;
79 ops.retlen = 0;
80 ops.ooblen = use_len;
81 ops.oobretlen = 0;
82 ops.ooboffs = use_offset;
Hannes Eder23d42492009-03-05 20:15:01 +010083 ops.datbuf = NULL;
Akinobu Mitabe54f8f2014-03-08 00:24:10 +090084 ops.oobbuf = writebuf + (use_len_max * i) + use_offset;
Artem Bityutskiya2cc5ba2011-12-23 18:29:55 +020085 err = mtd_write_oob(mtd, addr, &ops);
Artem Bityutskiye3644da2008-12-08 13:33:29 +020086 if (err || ops.oobretlen != use_len) {
Vikram Narayanan04810272012-10-10 23:12:02 +053087 pr_err("error: writeoob failed at %#llx\n",
Artem Bityutskiye3644da2008-12-08 13:33:29 +020088 (long long)addr);
Vikram Narayanan04810272012-10-10 23:12:02 +053089 pr_err("error: use_len %d, use_offset %d\n",
Artem Bityutskiye3644da2008-12-08 13:33:29 +020090 use_len, use_offset);
91 errcnt += 1;
92 return err ? err : -1;
93 }
94 if (vary_offset)
95 do_vary_offset();
96 }
97
98 return err;
99}
100
101static int write_whole_device(void)
102{
103 int err;
104 unsigned int i;
105
Vikram Narayanan04810272012-10-10 23:12:02 +0530106 pr_info("writing OOBs of whole device\n");
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200107 for (i = 0; i < ebcnt; ++i) {
108 if (bbt[i])
109 continue;
110 err = write_eraseblock(i);
111 if (err)
112 return err;
113 if (i % 256 == 0)
Vikram Narayanan04810272012-10-10 23:12:02 +0530114 pr_info("written up to eraseblock %u\n", i);
Richard Weinberger2a6a28e72015-03-29 21:52:06 +0200115
116 err = mtdtest_relax();
117 if (err)
118 return err;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200119 }
Vikram Narayanan04810272012-10-10 23:12:02 +0530120 pr_info("written %u eraseblocks\n", i);
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200121 return 0;
122}
123
Roger Quadrosafc0ea12014-10-21 16:53:28 +0300124/*
125 * Display the address, offset and data bytes at comparison failure.
126 * Return number of bitflips encountered.
127 */
Roger Quadros718e38b2015-07-08 14:50:19 +0300128static size_t memcmpshowoffset(loff_t addr, loff_t offset, const void *cs,
129 const void *ct, size_t count)
Roger Quadros5a660882014-10-21 16:53:27 +0300130{
131 const unsigned char *su1, *su2;
132 int res;
Roger Quadros5a660882014-10-21 16:53:27 +0300133 size_t i = 0;
Roger Quadrosafc0ea12014-10-21 16:53:28 +0300134 size_t bitflips = 0;
Roger Quadros5a660882014-10-21 16:53:27 +0300135
136 for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--, i++) {
137 res = *su1 ^ *su2;
138 if (res) {
Roger Quadros718e38b2015-07-08 14:50:19 +0300139 pr_info("error @addr[0x%lx:0x%lx] 0x%x -> 0x%x diff 0x%x\n",
140 (unsigned long)addr, (unsigned long)offset + i,
141 *su1, *su2, res);
Roger Quadrosafc0ea12014-10-21 16:53:28 +0300142 bitflips += hweight8(res);
Roger Quadros5a660882014-10-21 16:53:27 +0300143 }
144 }
145
Roger Quadrosafc0ea12014-10-21 16:53:28 +0300146 return bitflips;
Roger Quadros5a660882014-10-21 16:53:27 +0300147}
148
Roger Quadros718e38b2015-07-08 14:50:19 +0300149#define memcmpshow(addr, cs, ct, count) memcmpshowoffset((addr), 0, (cs), (ct),\
150 (count))
151
Roger Quadrosd2b51c82014-12-05 17:18:39 +0200152/*
153 * Compare with 0xff and show the address, offset and data bytes at
154 * comparison failure. Return number of bitflips encountered.
155 */
156static size_t memffshow(loff_t addr, loff_t offset, const void *cs,
157 size_t count)
158{
159 const unsigned char *su1;
160 int res;
161 size_t i = 0;
162 size_t bitflips = 0;
163
164 for (su1 = cs; 0 < count; ++su1, count--, i++) {
165 res = *su1 ^ 0xff;
166 if (res) {
167 pr_info("error @addr[0x%lx:0x%lx] 0x%x -> 0xff diff 0x%x\n",
168 (unsigned long)addr, (unsigned long)offset + i,
169 *su1, res);
170 bitflips += hweight8(res);
171 }
172 }
173
174 return bitflips;
175}
176
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200177static int verify_eraseblock(int ebnum)
178{
179 int i;
180 struct mtd_oob_ops ops;
181 int err = 0;
Brian Norris1001ff72014-07-21 19:07:12 -0700182 loff_t addr = (loff_t)ebnum * mtd->erasesize;
Roger Quadrosafc0ea12014-10-21 16:53:28 +0300183 size_t bitflips;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200184
Akinobu Mitabe54f8f2014-03-08 00:24:10 +0900185 prandom_bytes_state(&rnd_state, writebuf, use_len_max * pgcnt);
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200186 for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) {
Brian Norris0612b9d2011-08-30 18:45:40 -0700187 ops.mode = MTD_OPS_AUTO_OOB;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200188 ops.len = 0;
189 ops.retlen = 0;
190 ops.ooblen = use_len;
191 ops.oobretlen = 0;
192 ops.ooboffs = use_offset;
Hannes Eder23d42492009-03-05 20:15:01 +0100193 ops.datbuf = NULL;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200194 ops.oobbuf = readbuf;
Artem Bityutskiyfd2819b2011-12-23 18:27:05 +0200195 err = mtd_read_oob(mtd, addr, &ops);
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200196 if (err || ops.oobretlen != use_len) {
Vikram Narayanan04810272012-10-10 23:12:02 +0530197 pr_err("error: readoob failed at %#llx\n",
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200198 (long long)addr);
199 errcnt += 1;
200 return err ? err : -1;
201 }
Roger Quadrosafc0ea12014-10-21 16:53:28 +0300202
203 bitflips = memcmpshow(addr, readbuf,
204 writebuf + (use_len_max * i) + use_offset,
205 use_len);
206 if (bitflips > bitflip_limit) {
Vikram Narayanan04810272012-10-10 23:12:02 +0530207 pr_err("error: verify failed at %#llx\n",
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200208 (long long)addr);
209 errcnt += 1;
210 if (errcnt > 1000) {
Vikram Narayanan04810272012-10-10 23:12:02 +0530211 pr_err("error: too many errors\n");
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200212 return -1;
213 }
Roger Quadrosafc0ea12014-10-21 16:53:28 +0300214 } else if (bitflips) {
215 pr_info("ignoring error as within bitflip_limit\n");
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200216 }
Roger Quadrosafc0ea12014-10-21 16:53:28 +0300217
Boris BREZILLONf5b8aa72016-03-07 10:46:51 +0100218 if (use_offset != 0 || use_len < mtd->oobavail) {
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200219 int k;
220
Brian Norris0612b9d2011-08-30 18:45:40 -0700221 ops.mode = MTD_OPS_AUTO_OOB;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200222 ops.len = 0;
223 ops.retlen = 0;
Boris BREZILLONf5b8aa72016-03-07 10:46:51 +0100224 ops.ooblen = mtd->oobavail;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200225 ops.oobretlen = 0;
226 ops.ooboffs = 0;
Hannes Eder23d42492009-03-05 20:15:01 +0100227 ops.datbuf = NULL;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200228 ops.oobbuf = readbuf;
Artem Bityutskiyfd2819b2011-12-23 18:27:05 +0200229 err = mtd_read_oob(mtd, addr, &ops);
Boris BREZILLONf5b8aa72016-03-07 10:46:51 +0100230 if (err || ops.oobretlen != mtd->oobavail) {
Vikram Narayanan04810272012-10-10 23:12:02 +0530231 pr_err("error: readoob failed at %#llx\n",
232 (long long)addr);
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200233 errcnt += 1;
234 return err ? err : -1;
235 }
Roger Quadros718e38b2015-07-08 14:50:19 +0300236 bitflips = memcmpshowoffset(addr, use_offset,
237 readbuf + use_offset,
238 writebuf + (use_len_max * i) + use_offset,
239 use_len);
Roger Quadrosd2b51c82014-12-05 17:18:39 +0200240
241 /* verify pre-offset area for 0xff */
242 bitflips += memffshow(addr, 0, readbuf, use_offset);
243
244 /* verify post-(use_offset + use_len) area for 0xff */
245 k = use_offset + use_len;
246 bitflips += memffshow(addr, k, readbuf + k,
Boris BREZILLONf5b8aa72016-03-07 10:46:51 +0100247 mtd->oobavail - k);
Roger Quadrosd2b51c82014-12-05 17:18:39 +0200248
Roger Quadrosafc0ea12014-10-21 16:53:28 +0300249 if (bitflips > bitflip_limit) {
Vikram Narayanan04810272012-10-10 23:12:02 +0530250 pr_err("error: verify failed at %#llx\n",
251 (long long)addr);
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200252 errcnt += 1;
253 if (errcnt > 1000) {
Vikram Narayanan04810272012-10-10 23:12:02 +0530254 pr_err("error: too many errors\n");
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200255 return -1;
256 }
Roger Quadrosafc0ea12014-10-21 16:53:28 +0300257 } else if (bitflips) {
Roger Quadrosd2b51c82014-12-05 17:18:39 +0200258 pr_info("ignoring errors as within bitflip limit\n");
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200259 }
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200260 }
261 if (vary_offset)
262 do_vary_offset();
263 }
264 return err;
265}
266
267static int verify_eraseblock_in_one_go(int ebnum)
268{
269 struct mtd_oob_ops ops;
270 int err = 0;
Brian Norris1001ff72014-07-21 19:07:12 -0700271 loff_t addr = (loff_t)ebnum * mtd->erasesize;
Boris BREZILLONf5b8aa72016-03-07 10:46:51 +0100272 size_t len = mtd->oobavail * pgcnt;
273 size_t oobavail = mtd->oobavail;
Roger Quadrosafc0ea12014-10-21 16:53:28 +0300274 size_t bitflips;
275 int i;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200276
Akinobu Mita8dad0492013-02-27 17:05:33 -0800277 prandom_bytes_state(&rnd_state, writebuf, len);
Brian Norris0612b9d2011-08-30 18:45:40 -0700278 ops.mode = MTD_OPS_AUTO_OOB;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200279 ops.len = 0;
280 ops.retlen = 0;
281 ops.ooblen = len;
282 ops.oobretlen = 0;
283 ops.ooboffs = 0;
Hannes Eder23d42492009-03-05 20:15:01 +0100284 ops.datbuf = NULL;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200285 ops.oobbuf = readbuf;
Roger Quadrosafc0ea12014-10-21 16:53:28 +0300286
287 /* read entire block's OOB at one go */
Artem Bityutskiyfd2819b2011-12-23 18:27:05 +0200288 err = mtd_read_oob(mtd, addr, &ops);
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200289 if (err || ops.oobretlen != len) {
Vikram Narayanan04810272012-10-10 23:12:02 +0530290 pr_err("error: readoob failed at %#llx\n",
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200291 (long long)addr);
292 errcnt += 1;
293 return err ? err : -1;
294 }
Roger Quadrosafc0ea12014-10-21 16:53:28 +0300295
296 /* verify one page OOB at a time for bitflip per page limit check */
297 for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) {
298 bitflips = memcmpshow(addr, readbuf + (i * oobavail),
299 writebuf + (i * oobavail), oobavail);
300 if (bitflips > bitflip_limit) {
301 pr_err("error: verify failed at %#llx\n",
302 (long long)addr);
303 errcnt += 1;
304 if (errcnt > 1000) {
305 pr_err("error: too many errors\n");
306 return -1;
307 }
308 } else if (bitflips) {
309 pr_info("ignoring error as within bitflip_limit\n");
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200310 }
311 }
312
313 return err;
314}
315
316static int verify_all_eraseblocks(void)
317{
318 int err;
319 unsigned int i;
320
Vikram Narayanan04810272012-10-10 23:12:02 +0530321 pr_info("verifying all eraseblocks\n");
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200322 for (i = 0; i < ebcnt; ++i) {
323 if (bbt[i])
324 continue;
325 err = verify_eraseblock(i);
326 if (err)
327 return err;
328 if (i % 256 == 0)
Vikram Narayanan04810272012-10-10 23:12:02 +0530329 pr_info("verified up to eraseblock %u\n", i);
Richard Weinberger2a6a28e72015-03-29 21:52:06 +0200330
331 err = mtdtest_relax();
332 if (err)
333 return err;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200334 }
Vikram Narayanan04810272012-10-10 23:12:02 +0530335 pr_info("verified %u eraseblocks\n", i);
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200336 return 0;
337}
338
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200339static int __init mtd_oobtest_init(void)
340{
341 int err = 0;
342 unsigned int i;
343 uint64_t tmp;
344 struct mtd_oob_ops ops;
345 loff_t addr = 0, addr0;
346
347 printk(KERN_INFO "\n");
348 printk(KERN_INFO "=================================================\n");
Wolfram Sang74060602011-10-30 00:11:53 +0200349
350 if (dev < 0) {
Masanari Iida064a7692012-11-09 23:20:58 +0900351 pr_info("Please specify a valid mtd-device via module parameter\n");
352 pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
Wolfram Sang74060602011-10-30 00:11:53 +0200353 return -EINVAL;
354 }
355
Vikram Narayanan04810272012-10-10 23:12:02 +0530356 pr_info("MTD device: %d\n", dev);
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200357
358 mtd = get_mtd_device(NULL, dev);
359 if (IS_ERR(mtd)) {
360 err = PTR_ERR(mtd);
Vikram Narayanan04810272012-10-10 23:12:02 +0530361 pr_err("error: cannot get MTD device\n");
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200362 return err;
363 }
364
Huang Shijie818b9732013-09-25 14:58:17 +0800365 if (!mtd_type_is_nand(mtd)) {
Vikram Narayanan04810272012-10-10 23:12:02 +0530366 pr_info("this test requires NAND flash\n");
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200367 goto out;
368 }
369
370 tmp = mtd->size;
371 do_div(tmp, mtd->erasesize);
372 ebcnt = tmp;
373 pgcnt = mtd->erasesize / mtd->writesize;
374
Vikram Narayanan04810272012-10-10 23:12:02 +0530375 pr_info("MTD device size %llu, eraseblock size %u, "
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200376 "page size %u, count of eraseblocks %u, pages per "
377 "eraseblock %u, OOB size %u\n",
378 (unsigned long long)mtd->size, mtd->erasesize,
379 mtd->writesize, ebcnt, pgcnt, mtd->oobsize);
380
381 err = -ENOMEM;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200382 readbuf = kmalloc(mtd->erasesize, GFP_KERNEL);
Brian Norris33777e62013-05-02 14:18:51 -0700383 if (!readbuf)
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200384 goto out;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200385 writebuf = kmalloc(mtd->erasesize, GFP_KERNEL);
Brian Norris33777e62013-05-02 14:18:51 -0700386 if (!writebuf)
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200387 goto out;
Akinobu Mita4bf527a2013-08-03 18:52:09 +0900388 bbt = kzalloc(ebcnt, GFP_KERNEL);
389 if (!bbt)
390 goto out;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200391
Akinobu Mita4bf527a2013-08-03 18:52:09 +0900392 err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt);
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200393 if (err)
394 goto out;
395
396 use_offset = 0;
Boris BREZILLONf5b8aa72016-03-07 10:46:51 +0100397 use_len = mtd->oobavail;
398 use_len_max = mtd->oobavail;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200399 vary_offset = 0;
400
401 /* First test: write all OOB, read it back and verify */
Vikram Narayanan04810272012-10-10 23:12:02 +0530402 pr_info("test 1 of 5\n");
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200403
Akinobu Mita4bf527a2013-08-03 18:52:09 +0900404 err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200405 if (err)
406 goto out;
407
Akinobu Mita8dad0492013-02-27 17:05:33 -0800408 prandom_seed_state(&rnd_state, 1);
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200409 err = write_whole_device();
410 if (err)
411 goto out;
412
Akinobu Mita8dad0492013-02-27 17:05:33 -0800413 prandom_seed_state(&rnd_state, 1);
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200414 err = verify_all_eraseblocks();
415 if (err)
416 goto out;
417
418 /*
419 * Second test: write all OOB, a block at a time, read it back and
420 * verify.
421 */
Vikram Narayanan04810272012-10-10 23:12:02 +0530422 pr_info("test 2 of 5\n");
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200423
Akinobu Mita4bf527a2013-08-03 18:52:09 +0900424 err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200425 if (err)
426 goto out;
427
Akinobu Mita8dad0492013-02-27 17:05:33 -0800428 prandom_seed_state(&rnd_state, 3);
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200429 err = write_whole_device();
430 if (err)
431 goto out;
432
433 /* Check all eraseblocks */
Akinobu Mita8dad0492013-02-27 17:05:33 -0800434 prandom_seed_state(&rnd_state, 3);
Vikram Narayanan04810272012-10-10 23:12:02 +0530435 pr_info("verifying all eraseblocks\n");
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200436 for (i = 0; i < ebcnt; ++i) {
437 if (bbt[i])
438 continue;
439 err = verify_eraseblock_in_one_go(i);
440 if (err)
441 goto out;
442 if (i % 256 == 0)
Vikram Narayanan04810272012-10-10 23:12:02 +0530443 pr_info("verified up to eraseblock %u\n", i);
Richard Weinberger2a6a28e72015-03-29 21:52:06 +0200444
445 err = mtdtest_relax();
446 if (err)
447 goto out;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200448 }
Vikram Narayanan04810272012-10-10 23:12:02 +0530449 pr_info("verified %u eraseblocks\n", i);
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200450
451 /*
452 * Third test: write OOB at varying offsets and lengths, read it back
453 * and verify.
454 */
Vikram Narayanan04810272012-10-10 23:12:02 +0530455 pr_info("test 3 of 5\n");
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200456
Akinobu Mita4bf527a2013-08-03 18:52:09 +0900457 err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200458 if (err)
459 goto out;
460
461 /* Write all eraseblocks */
462 use_offset = 0;
Boris BREZILLONf5b8aa72016-03-07 10:46:51 +0100463 use_len = mtd->oobavail;
464 use_len_max = mtd->oobavail;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200465 vary_offset = 1;
Akinobu Mita8dad0492013-02-27 17:05:33 -0800466 prandom_seed_state(&rnd_state, 5);
Akinobu Mitaf54d6332009-10-09 18:43:52 +0900467
468 err = write_whole_device();
469 if (err)
470 goto out;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200471
472 /* Check all eraseblocks */
473 use_offset = 0;
Boris BREZILLONf5b8aa72016-03-07 10:46:51 +0100474 use_len = mtd->oobavail;
475 use_len_max = mtd->oobavail;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200476 vary_offset = 1;
Akinobu Mita8dad0492013-02-27 17:05:33 -0800477 prandom_seed_state(&rnd_state, 5);
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200478 err = verify_all_eraseblocks();
479 if (err)
480 goto out;
481
482 use_offset = 0;
Boris BREZILLONf5b8aa72016-03-07 10:46:51 +0100483 use_len = mtd->oobavail;
484 use_len_max = mtd->oobavail;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200485 vary_offset = 0;
486
487 /* Fourth test: try to write off end of device */
Vikram Narayanan04810272012-10-10 23:12:02 +0530488 pr_info("test 4 of 5\n");
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200489
Akinobu Mita4bf527a2013-08-03 18:52:09 +0900490 err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200491 if (err)
492 goto out;
493
494 addr0 = 0;
Roel Kluinc6f7e7b2009-07-31 16:21:01 +0200495 for (i = 0; i < ebcnt && bbt[i]; ++i)
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200496 addr0 += mtd->erasesize;
497
498 /* Attempt to write off end of OOB */
Brian Norris0612b9d2011-08-30 18:45:40 -0700499 ops.mode = MTD_OPS_AUTO_OOB;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200500 ops.len = 0;
501 ops.retlen = 0;
502 ops.ooblen = 1;
503 ops.oobretlen = 0;
Boris BREZILLONf5b8aa72016-03-07 10:46:51 +0100504 ops.ooboffs = mtd->oobavail;
Hannes Eder23d42492009-03-05 20:15:01 +0100505 ops.datbuf = NULL;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200506 ops.oobbuf = writebuf;
Vikram Narayanan04810272012-10-10 23:12:02 +0530507 pr_info("attempting to start write past end of OOB\n");
508 pr_info("an error is expected...\n");
Artem Bityutskiya2cc5ba2011-12-23 18:29:55 +0200509 err = mtd_write_oob(mtd, addr0, &ops);
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200510 if (err) {
Vikram Narayanan04810272012-10-10 23:12:02 +0530511 pr_info("error occurred as expected\n");
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200512 err = 0;
513 } else {
Vikram Narayanan04810272012-10-10 23:12:02 +0530514 pr_err("error: can write past end of OOB\n");
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200515 errcnt += 1;
516 }
517
518 /* Attempt to read off end of OOB */
Brian Norris0612b9d2011-08-30 18:45:40 -0700519 ops.mode = MTD_OPS_AUTO_OOB;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200520 ops.len = 0;
521 ops.retlen = 0;
522 ops.ooblen = 1;
523 ops.oobretlen = 0;
Boris BREZILLONf5b8aa72016-03-07 10:46:51 +0100524 ops.ooboffs = mtd->oobavail;
Hannes Eder23d42492009-03-05 20:15:01 +0100525 ops.datbuf = NULL;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200526 ops.oobbuf = readbuf;
Vikram Narayanan04810272012-10-10 23:12:02 +0530527 pr_info("attempting to start read past end of OOB\n");
528 pr_info("an error is expected...\n");
Artem Bityutskiyfd2819b2011-12-23 18:27:05 +0200529 err = mtd_read_oob(mtd, addr0, &ops);
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200530 if (err) {
Vikram Narayanan04810272012-10-10 23:12:02 +0530531 pr_info("error occurred as expected\n");
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200532 err = 0;
533 } else {
Vikram Narayanan04810272012-10-10 23:12:02 +0530534 pr_err("error: can read past end of OOB\n");
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200535 errcnt += 1;
536 }
537
538 if (bbt[ebcnt - 1])
Vikram Narayanan04810272012-10-10 23:12:02 +0530539 pr_info("skipping end of device tests because last "
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200540 "block is bad\n");
541 else {
542 /* Attempt to write off end of device */
Brian Norris0612b9d2011-08-30 18:45:40 -0700543 ops.mode = MTD_OPS_AUTO_OOB;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200544 ops.len = 0;
545 ops.retlen = 0;
Boris BREZILLONf5b8aa72016-03-07 10:46:51 +0100546 ops.ooblen = mtd->oobavail + 1;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200547 ops.oobretlen = 0;
548 ops.ooboffs = 0;
Hannes Eder23d42492009-03-05 20:15:01 +0100549 ops.datbuf = NULL;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200550 ops.oobbuf = writebuf;
Vikram Narayanan04810272012-10-10 23:12:02 +0530551 pr_info("attempting to write past end of device\n");
552 pr_info("an error is expected...\n");
Artem Bityutskiya2cc5ba2011-12-23 18:29:55 +0200553 err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops);
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200554 if (err) {
Vikram Narayanan04810272012-10-10 23:12:02 +0530555 pr_info("error occurred as expected\n");
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200556 err = 0;
557 } else {
Vikram Narayanan04810272012-10-10 23:12:02 +0530558 pr_err("error: wrote past end of device\n");
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200559 errcnt += 1;
560 }
561
562 /* Attempt to read off end of device */
Brian Norris0612b9d2011-08-30 18:45:40 -0700563 ops.mode = MTD_OPS_AUTO_OOB;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200564 ops.len = 0;
565 ops.retlen = 0;
Boris BREZILLONf5b8aa72016-03-07 10:46:51 +0100566 ops.ooblen = mtd->oobavail + 1;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200567 ops.oobretlen = 0;
568 ops.ooboffs = 0;
Hannes Eder23d42492009-03-05 20:15:01 +0100569 ops.datbuf = NULL;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200570 ops.oobbuf = readbuf;
Vikram Narayanan04810272012-10-10 23:12:02 +0530571 pr_info("attempting to read past end of device\n");
572 pr_info("an error is expected...\n");
Artem Bityutskiyfd2819b2011-12-23 18:27:05 +0200573 err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops);
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200574 if (err) {
Vikram Narayanan04810272012-10-10 23:12:02 +0530575 pr_info("error occurred as expected\n");
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200576 err = 0;
577 } else {
Vikram Narayanan04810272012-10-10 23:12:02 +0530578 pr_err("error: read past end of device\n");
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200579 errcnt += 1;
580 }
581
Akinobu Mita4bf527a2013-08-03 18:52:09 +0900582 err = mtdtest_erase_eraseblock(mtd, ebcnt - 1);
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200583 if (err)
584 goto out;
585
586 /* Attempt to write off end of device */
Brian Norris0612b9d2011-08-30 18:45:40 -0700587 ops.mode = MTD_OPS_AUTO_OOB;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200588 ops.len = 0;
589 ops.retlen = 0;
Boris BREZILLONf5b8aa72016-03-07 10:46:51 +0100590 ops.ooblen = mtd->oobavail;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200591 ops.oobretlen = 0;
592 ops.ooboffs = 1;
Hannes Eder23d42492009-03-05 20:15:01 +0100593 ops.datbuf = NULL;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200594 ops.oobbuf = writebuf;
Vikram Narayanan04810272012-10-10 23:12:02 +0530595 pr_info("attempting to write past end of device\n");
596 pr_info("an error is expected...\n");
Artem Bityutskiya2cc5ba2011-12-23 18:29:55 +0200597 err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops);
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200598 if (err) {
Vikram Narayanan04810272012-10-10 23:12:02 +0530599 pr_info("error occurred as expected\n");
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200600 err = 0;
601 } else {
Vikram Narayanan04810272012-10-10 23:12:02 +0530602 pr_err("error: wrote past end of device\n");
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200603 errcnt += 1;
604 }
605
606 /* Attempt to read off end of device */
Brian Norris0612b9d2011-08-30 18:45:40 -0700607 ops.mode = MTD_OPS_AUTO_OOB;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200608 ops.len = 0;
609 ops.retlen = 0;
Boris BREZILLONf5b8aa72016-03-07 10:46:51 +0100610 ops.ooblen = mtd->oobavail;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200611 ops.oobretlen = 0;
612 ops.ooboffs = 1;
Hannes Eder23d42492009-03-05 20:15:01 +0100613 ops.datbuf = NULL;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200614 ops.oobbuf = readbuf;
Vikram Narayanan04810272012-10-10 23:12:02 +0530615 pr_info("attempting to read past end of device\n");
616 pr_info("an error is expected...\n");
Artem Bityutskiyfd2819b2011-12-23 18:27:05 +0200617 err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops);
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200618 if (err) {
Vikram Narayanan04810272012-10-10 23:12:02 +0530619 pr_info("error occurred as expected\n");
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200620 err = 0;
621 } else {
Vikram Narayanan04810272012-10-10 23:12:02 +0530622 pr_err("error: read past end of device\n");
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200623 errcnt += 1;
624 }
625 }
626
627 /* Fifth test: write / read across block boundaries */
Vikram Narayanan04810272012-10-10 23:12:02 +0530628 pr_info("test 5 of 5\n");
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200629
630 /* Erase all eraseblocks */
Akinobu Mita4bf527a2013-08-03 18:52:09 +0900631 err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200632 if (err)
633 goto out;
634
635 /* Write all eraseblocks */
Akinobu Mita8dad0492013-02-27 17:05:33 -0800636 prandom_seed_state(&rnd_state, 11);
Vikram Narayanan04810272012-10-10 23:12:02 +0530637 pr_info("writing OOBs of whole device\n");
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200638 for (i = 0; i < ebcnt - 1; ++i) {
639 int cnt = 2;
640 int pg;
Boris BREZILLONf5b8aa72016-03-07 10:46:51 +0100641 size_t sz = mtd->oobavail;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200642 if (bbt[i] || bbt[i + 1])
643 continue;
Brian Norris1001ff72014-07-21 19:07:12 -0700644 addr = (loff_t)(i + 1) * mtd->erasesize - mtd->writesize;
Akinobu Mitabe54f8f2014-03-08 00:24:10 +0900645 prandom_bytes_state(&rnd_state, writebuf, sz * cnt);
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200646 for (pg = 0; pg < cnt; ++pg) {
Brian Norris0612b9d2011-08-30 18:45:40 -0700647 ops.mode = MTD_OPS_AUTO_OOB;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200648 ops.len = 0;
649 ops.retlen = 0;
650 ops.ooblen = sz;
651 ops.oobretlen = 0;
652 ops.ooboffs = 0;
Hannes Eder23d42492009-03-05 20:15:01 +0100653 ops.datbuf = NULL;
Akinobu Mitabe54f8f2014-03-08 00:24:10 +0900654 ops.oobbuf = writebuf + pg * sz;
Artem Bityutskiya2cc5ba2011-12-23 18:29:55 +0200655 err = mtd_write_oob(mtd, addr, &ops);
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200656 if (err)
657 goto out;
658 if (i % 256 == 0)
Vikram Narayanan04810272012-10-10 23:12:02 +0530659 pr_info("written up to eraseblock %u\n", i);
Richard Weinberger2a6a28e72015-03-29 21:52:06 +0200660
661 err = mtdtest_relax();
662 if (err)
663 goto out;
664
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200665 addr += mtd->writesize;
666 }
667 }
Vikram Narayanan04810272012-10-10 23:12:02 +0530668 pr_info("written %u eraseblocks\n", i);
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200669
670 /* Check all eraseblocks */
Akinobu Mita8dad0492013-02-27 17:05:33 -0800671 prandom_seed_state(&rnd_state, 11);
Vikram Narayanan04810272012-10-10 23:12:02 +0530672 pr_info("verifying all eraseblocks\n");
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200673 for (i = 0; i < ebcnt - 1; ++i) {
674 if (bbt[i] || bbt[i + 1])
675 continue;
Boris BREZILLONf5b8aa72016-03-07 10:46:51 +0100676 prandom_bytes_state(&rnd_state, writebuf, mtd->oobavail * 2);
Brian Norris1001ff72014-07-21 19:07:12 -0700677 addr = (loff_t)(i + 1) * mtd->erasesize - mtd->writesize;
Brian Norris0612b9d2011-08-30 18:45:40 -0700678 ops.mode = MTD_OPS_AUTO_OOB;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200679 ops.len = 0;
680 ops.retlen = 0;
Boris BREZILLONf5b8aa72016-03-07 10:46:51 +0100681 ops.ooblen = mtd->oobavail * 2;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200682 ops.oobretlen = 0;
683 ops.ooboffs = 0;
Hannes Eder23d42492009-03-05 20:15:01 +0100684 ops.datbuf = NULL;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200685 ops.oobbuf = readbuf;
Artem Bityutskiyfd2819b2011-12-23 18:27:05 +0200686 err = mtd_read_oob(mtd, addr, &ops);
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200687 if (err)
688 goto out;
Roger Quadros5a660882014-10-21 16:53:27 +0300689 if (memcmpshow(addr, readbuf, writebuf,
Boris BREZILLONf5b8aa72016-03-07 10:46:51 +0100690 mtd->oobavail * 2)) {
Vikram Narayanan04810272012-10-10 23:12:02 +0530691 pr_err("error: verify failed at %#llx\n",
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200692 (long long)addr);
693 errcnt += 1;
694 if (errcnt > 1000) {
Vikram Narayanan04810272012-10-10 23:12:02 +0530695 pr_err("error: too many errors\n");
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200696 goto out;
697 }
698 }
699 if (i % 256 == 0)
Vikram Narayanan04810272012-10-10 23:12:02 +0530700 pr_info("verified up to eraseblock %u\n", i);
Richard Weinberger2a6a28e72015-03-29 21:52:06 +0200701
702 err = mtdtest_relax();
703 if (err)
704 goto out;
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200705 }
Vikram Narayanan04810272012-10-10 23:12:02 +0530706 pr_info("verified %u eraseblocks\n", i);
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200707
Vikram Narayanan04810272012-10-10 23:12:02 +0530708 pr_info("finished with %d errors\n", errcnt);
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200709out:
710 kfree(bbt);
711 kfree(writebuf);
712 kfree(readbuf);
713 put_mtd_device(mtd);
714 if (err)
Vikram Narayanan04810272012-10-10 23:12:02 +0530715 pr_info("error %d occurred\n", err);
Artem Bityutskiye3644da2008-12-08 13:33:29 +0200716 printk(KERN_INFO "=================================================\n");
717 return err;
718}
719module_init(mtd_oobtest_init);
720
721static void __exit mtd_oobtest_exit(void)
722{
723 return;
724}
725module_exit(mtd_oobtest_exit);
726
727MODULE_DESCRIPTION("Out-of-band test module");
728MODULE_AUTHOR("Adrian Hunter");
729MODULE_LICENSE("GPL");