staticint write_whole_device(void)
{ int err; unsignedint i;
pr_info("writing OOBs of whole device\n"); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue;
err = write_eraseblock(i); if (err) return err; if (i % 256 == 0)
pr_info("written up to eraseblock %u\n", i);
/* * Compare with 0xff and show the address, offset and data bytes at * comparison failure. Return number of bitflips encountered.
*/ static size_t memffshow(loff_t addr, loff_t offset, constvoid *cs,
size_t count)
{ constunsignedchar *su1; int res;
size_t i = 0;
size_t bitflips = 0;
for (su1 = cs; 0 < count; ++su1, count--, i++) {
res = *su1 ^ 0xff; if (res) {
pr_info("error @addr[0x%lx:0x%lx] 0x%x -> 0xff diff 0x%x\n",
(unsignedlong)addr, (unsignedlong)offset + i,
*su1, res);
bitflips += hweight8(res);
}
}
/* verify one page OOB at a time for bitflip per page limit check */ for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) {
bitflips = memcmpshow(addr, readbuf + (i * oobavail),
writebuf + (i * oobavail), oobavail); if (bitflips > bitflip_limit) {
pr_err("error: verify failed at %#llx\n",
(longlong)addr);
errcnt += 1; if (errcnt > 1000) {
pr_err("error: too many errors\n"); return -1;
}
} elseif (bitflips) {
pr_info("ignoring error as within bitflip_limit\n");
}
}
return err;
}
staticint verify_all_eraseblocks(void)
{ int err; unsignedint i;
pr_info("verifying all eraseblocks\n"); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue;
err = verify_eraseblock(i); if (err) return err; if (i % 256 == 0)
pr_info("verified up to eraseblock %u\n", i);
if (dev < 0) {
pr_info("Please specify a valid mtd-device via module parameter\n");
pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n"); return -EINVAL;
}
pr_info("MTD device: %d\n", dev);
mtd = get_mtd_device(NULL, dev); if (IS_ERR(mtd)) {
err = PTR_ERR(mtd);
pr_err("error: cannot get MTD device\n"); return err;
}
if (!mtd_type_is_nand(mtd)) {
pr_info("this test requires NAND flash\n"); goto out;
}
/* First test: write all OOB, read it back and verify */
pr_info("test 1 of 5\n");
err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); if (err) goto out;
prandom_seed_state(&rnd_state, 1);
err = write_whole_device(); if (err) goto out;
prandom_seed_state(&rnd_state, 1);
err = verify_all_eraseblocks(); if (err) goto out;
/* * Second test: write all OOB, a block at a time, read it back and * verify.
*/
pr_info("test 2 of 5\n");
err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); if (err) goto out;
prandom_seed_state(&rnd_state, 3);
err = write_whole_device(); if (err) goto out;
/* Check all eraseblocks */
prandom_seed_state(&rnd_state, 3);
pr_info("verifying all eraseblocks\n"); for (i = 0; i < ebcnt; ++i) { if (bbt[i]) continue;
err = verify_eraseblock_in_one_go(i); if (err) goto out; if (i % 256 == 0)
pr_info("verified up to eraseblock %u\n", i);
/* Fourth test: try to write off end of device */
pr_info("test 4 of 5\n");
err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); if (err) goto out;
addr0 = 0; for (i = 0; i < ebcnt && bbt[i]; ++i)
addr0 += mtd->erasesize;
/* Attempt to write off end of OOB */
ops.mode = MTD_OPS_AUTO_OOB;
ops.len = 0;
ops.retlen = 0;
ops.ooblen = 1;
ops.oobretlen = 0;
ops.ooboffs = mtd->oobavail;
ops.datbuf = NULL;
ops.oobbuf = writebuf;
pr_info("attempting to start write past end of OOB\n");
pr_info("an error is expected...\n");
err = mtd_write_oob(mtd, addr0, &ops); if (err) {
pr_info("error occurred as expected\n");
} else {
pr_err("error: can write past end of OOB\n");
errcnt += 1;
}
/* Attempt to read off end of OOB */
ops.mode = MTD_OPS_AUTO_OOB;
ops.len = 0;
ops.retlen = 0;
ops.ooblen = 1;
ops.oobretlen = 0;
ops.ooboffs = mtd->oobavail;
ops.datbuf = NULL;
ops.oobbuf = readbuf;
pr_info("attempting to start read past end of OOB\n");
pr_info("an error is expected...\n");
err = mtd_read_oob(mtd, addr0, &ops); if (mtd_is_bitflip(err))
err = 0;
if (err) {
pr_info("error occurred as expected\n");
} else {
pr_err("error: can read past end of OOB\n");
errcnt += 1;
}
if (bbt[ebcnt - 1])
pr_info("skipping end of device tests because last " "block is bad\n"); else { /* Attempt to write off end of device */
ops.mode = MTD_OPS_AUTO_OOB;
ops.len = 0;
ops.retlen = 0;
ops.ooblen = mtd->oobavail + 1;
ops.oobretlen = 0;
ops.ooboffs = 0;
ops.datbuf = NULL;
ops.oobbuf = writebuf;
pr_info("attempting to write past end of device\n");
pr_info("an error is expected...\n");
err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops); if (err) {
pr_info("error occurred as expected\n");
} else {
pr_err("error: wrote past end of device\n");
errcnt += 1;
}
/* Attempt to read off end of device */
ops.mode = MTD_OPS_AUTO_OOB;
ops.len = 0;
ops.retlen = 0;
ops.ooblen = mtd->oobavail + 1;
ops.oobretlen = 0;
ops.ooboffs = 0;
ops.datbuf = NULL;
ops.oobbuf = readbuf;
pr_info("attempting to read past end of device\n");
pr_info("an error is expected...\n");
err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops); if (mtd_is_bitflip(err))
err = 0;
if (err) {
pr_info("error occurred as expected\n");
} else {
pr_err("error: read past end of device\n");
errcnt += 1;
}
err = mtdtest_erase_eraseblock(mtd, ebcnt - 1); if (err) goto out;
/* Attempt to write off end of device */
ops.mode = MTD_OPS_AUTO_OOB;
ops.len = 0;
ops.retlen = 0;
ops.ooblen = mtd->oobavail;
ops.oobretlen = 0;
ops.ooboffs = 1;
ops.datbuf = NULL;
ops.oobbuf = writebuf;
pr_info("attempting to write past end of device\n");
pr_info("an error is expected...\n");
err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops); if (err) {
pr_info("error occurred as expected\n");
} else {
pr_err("error: wrote past end of device\n");
errcnt += 1;
}
/* Attempt to read off end of device */
ops.mode = MTD_OPS_AUTO_OOB;
ops.len = 0;
ops.retlen = 0;
ops.ooblen = mtd->oobavail;
ops.oobretlen = 0;
ops.ooboffs = 1;
ops.datbuf = NULL;
ops.oobbuf = readbuf;
pr_info("attempting to read past end of device\n");
pr_info("an error is expected...\n");
err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops); if (mtd_is_bitflip(err))
err = 0;
if (err) {
pr_info("error occurred as expected\n");
} else {
pr_err("error: read past end of device\n");
errcnt += 1;
}
}
/* Fifth test: write / read across block boundaries */
pr_info("test 5 of 5\n");
/* Erase all eraseblocks */
err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt); if (err) goto out;
/* Write all eraseblocks */
prandom_seed_state(&rnd_state, 11);
pr_info("writing OOBs of whole device\n"); for (i = 0; i < ebcnt - 1; ++i) { int cnt = 2; int pg;
size_t sz = mtd->oobavail; if (bbt[i] || bbt[i + 1]) continue;
addr = (loff_t)(i + 1) * mtd->erasesize - mtd->writesize;
prandom_bytes_state(&rnd_state, writebuf, sz * cnt); for (pg = 0; pg < cnt; ++pg) {
ops.mode = MTD_OPS_AUTO_OOB;
ops.len = 0;
ops.retlen = 0;
ops.ooblen = sz;
ops.oobretlen = 0;
ops.ooboffs = 0;
ops.datbuf = NULL;
ops.oobbuf = writebuf + pg * sz;
err = mtd_write_oob(mtd, addr, &ops); if (err) goto out; if (i % 256 == 0)
pr_info("written up to eraseblock %u\n", i);
if (err) goto out; if (memcmpshow(addr, readbuf, writebuf,
mtd->oobavail * 2)) {
pr_err("error: verify failed at %#llx\n",
(longlong)addr);
errcnt += 1; if (errcnt > 1000) {
err = -EINVAL;
pr_err("error: too many errors\n"); goto out;
}
} if (i % 256 == 0)
pr_info("verified up to eraseblock %u\n", i);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.