Exemplo n.º 1
0
static int read_eraseblock_by_page(int ebnum)
{
	unsigned char *buf = iobuf, *oobbuf = iobuf1;
	uint64_t addr = ((uint64_t)ebnum) * ((uint64_t)mtd.eb_size);
	int i, ret;

	for (i = 0; i < pgcnt; ++i) {
		memset(buf, 0, pgsize);
		ret = mtd_read(&mtd, fd, ebnum, i*pgsize, buf, pgsize);
		if (ret) {
			fprintf(stderr, "Error reading block %d, page %d\n", ebnum, i);
			return -1;
		}
		if (mtd.oob_size) {
			ret = mtd_read_oob(mtd_desc, &mtd, fd,
							addr, mtd.oob_size, oobbuf);

			if (ret) {
				fprintf(stderr, "Error reading OOB in block %d, page %d\n",
						ebnum, i);
				return -1;
			}
			oobbuf += mtd.oob_size;
		}
		buf += pgsize;
		addr += pgsize;
	}

	if (flags & FLAG_VERBOSE)
		printf("Successfully read erase block %d\n", ebnum);

	return 0;
}
Exemplo n.º 2
0
static ssize_t mtd_op_read_oob(struct cdev *cdev, void *buf, size_t count,
			     loff_t _offset, ulong flags)
{
	struct mtd_info *mtd = to_mtd(cdev);
	struct mtd_oob_ops ops;
	int ret;
	unsigned long offset = _offset;

	if (count < mtd->oobsize)
		return -EINVAL;

	ops.mode = MTD_OPS_RAW;
	ops.ooboffs = 0;
	ops.ooblen = mtd->oobsize;
	ops.oobbuf = buf;
	ops.datbuf = NULL;
	ops.len = mtd->oobsize;

	offset /= mtd->oobsize;
	ret = mtd_read_oob(mtd, offset * mtd->writesize, &ops);
	if (ret)
		return ret;

	return mtd->oobsize;
}
Exemplo n.º 3
0
static ssize_t mtdraw_read_unaligned(struct mtd_info *mtd, void *dst,
				     size_t count, int skip, ulong offset)
{
	struct mtd_oob_ops ops;
	ssize_t ret;
	int partial = 0;
	void *tmp = dst;

	if (skip || count < mtd->writesize + mtd->oobsize)
		partial = 1;
	if (partial)
		tmp = malloc(mtd->writesize + mtd->oobsize);
	if (!tmp)
		return -ENOMEM;
	ops.mode = MTD_OPS_RAW;
	ops.ooboffs = 0;
	ops.datbuf = tmp;
	ops.len = mtd->writesize;
	ops.oobbuf = tmp + mtd->writesize;
	ops.ooblen = mtd->oobsize;
	ret = mtd_read_oob(mtd, offset, &ops);
	if (ret)
		goto err;
	if (partial)
		memcpy(dst, tmp + skip, count);
	ret = count;
err:
	if (partial)
		free(tmp);

	return ret;
}
static int verify_eraseblock_in_one_go(int ebnum)
{
    struct mtd_oob_ops ops;
    int err = 0;
    loff_t addr = ebnum * mtd->erasesize;
    size_t len = mtd->ecclayout->oobavail * pgcnt;

    set_random_data(writebuf, len);
    ops.mode      = MTD_OPS_AUTO_OOB;
    ops.len       = 0;
    ops.retlen    = 0;
    ops.ooblen    = len;
    ops.oobretlen = 0;
    ops.ooboffs   = 0;
    ops.datbuf    = NULL;
    ops.oobbuf    = readbuf;
    err = mtd_read_oob(mtd, addr, &ops);
    if (err || ops.oobretlen != len) {
        printk(PRINT_PREF "error: readoob failed at %#llx\n",
               (long long)addr);
        errcnt += 1;
        return err ? err : -1;
    }
    if (memcmp(readbuf, writebuf, len)) {
        printk(PRINT_PREF "error: verify failed at %#llx\n",
               (long long)addr);
        errcnt += 1;
        if (errcnt > 1000) {
            printk(PRINT_PREF "error: too many errors\n");
            return -1;
        }
    }

    return err;
}
static int yaffs_mtd_read(struct yaffs_dev *dev, int nand_chunk,
				   u8 *data, int data_len,
				   u8 *oob, int oob_len,
				   enum yaffs_ecc_result *ecc_result)
{
	struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
	loff_t addr;
	struct mtd_oob_ops ops;
	int retval;

	addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
	memset(&ops, 0, sizeof(ops));
	ops.mode = MTD_OPS_AUTO_OOB;
	ops.len = (data) ? data_len : 0;
	ops.ooblen = oob_len;
	ops.datbuf = data;
	ops.oobbuf = oob;

#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 20))
	/* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug;
	 * help it out with ops.len = ops.ooblen when ops.datbuf == NULL.
	 */
	ops.len = (ops.datbuf) ? ops.len : ops.ooblen;
#endif
	/* Read page and oob using MTD.
	 * Check status and determine ECC result.
	 */
	retval = mtd_read_oob(mtd, addr, &ops);
	if (retval)
		yaffs_trace(YAFFS_TRACE_MTD,
			"read_oob failed, chunk %d, mtd error %d",
			nand_chunk, retval);

	switch (retval) {
	case 0:
		/* no error */
		if(ecc_result)
			*ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
		break;

	case -EUCLEAN:
		/* MTD's ECC fixed the data */
		if(ecc_result)
			*ecc_result = YAFFS_ECC_RESULT_FIXED;
		dev->n_ecc_fixed++;
		break;

	case -EBADMSG:
	default:
		/* MTD's ECC could not fix the data */
		dev->n_ecc_unfixed++;
		if(ecc_result)
			*ecc_result = YAFFS_ECC_RESULT_UNFIXED;
		return YAFFS_FAIL;
	}

	return YAFFS_OK;
}
Exemplo n.º 6
0
static int
concat_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
{
	struct mtd_concat *concat = CONCAT(mtd);
	struct mtd_oob_ops devops = *ops;
	int i, err, ret = 0;

	ops->retlen = ops->oobretlen = 0;

	for (i = 0; i < concat->num_subdev; i++) {
		struct mtd_info *subdev = concat->subdev[i];

		if (from >= subdev->size) {
			from -= subdev->size;
			continue;
		}

		/* partial read ? */
		if (from + devops.len > subdev->size)
			devops.len = subdev->size - from;

		err = mtd_read_oob(subdev, from, &devops);
		ops->retlen += devops.retlen;
		ops->oobretlen += devops.oobretlen;

		/* Save information about bitflips! */
		if (unlikely(err)) {
			if (mtd_is_eccerr(err)) {
				mtd->ecc_stats.failed++;
				ret = err;
			} else if (mtd_is_bitflip(err)) {
				mtd->ecc_stats.corrected++;
				/* Do not overwrite -EBADMSG !! */
				if (!ret)
					ret = err;
			} else
				return err;
		}

		if (devops.datbuf) {
			devops.len = ops->len - ops->retlen;
			if (!devops.len)
				return ret;
			devops.datbuf += devops.retlen;
		}
		if (devops.oobbuf) {
			devops.ooblen = ops->ooblen - ops->oobretlen;
			if (!devops.ooblen)
				return ret;
			devops.oobbuf += ops->oobretlen;
		}

		from = 0;
	}
	return -EINVAL;
}
Exemplo n.º 7
0
static int nand_dump(nand_info_t *nand, ulong off, int only_oob, int repeat)
{
	int i;
	u_char *datbuf, *oobbuf, *p;
	static loff_t last;
	int ret = 0;

	if (repeat)
		off = last + nand->writesize;

	last = off;

	datbuf = memalign(ARCH_DMA_MINALIGN, nand->writesize);
	if (!datbuf) {
		puts("No memory for page buffer\n");
		return 1;
	}

	oobbuf = memalign(ARCH_DMA_MINALIGN, nand->oobsize);
	if (!oobbuf) {
		puts("No memory for page buffer\n");
		ret = 1;
		goto free_dat;
	}
	off &= ~(nand->writesize - 1);
	loff_t addr = (loff_t) off;
	struct mtd_oob_ops ops;
	memset(&ops, 0, sizeof(ops));
	ops.datbuf = datbuf;
	ops.oobbuf = oobbuf;
	ops.len = nand->writesize;
	ops.ooblen = nand->oobsize;
	ops.mode = MTD_OPS_RAW;
	i = mtd_read_oob(nand, addr, &ops);
	if (i < 0) {
		printf("Error (%d) reading page %08lx\n", i, off);
		ret = 1;
		goto free_all;
	}
	printf("Page %08lx dump:\n", off);

	if (!only_oob) {
		i = nand->writesize >> 4;
		p = datbuf;

		while (i--) {
			printf("\t%02x %02x %02x %02x %02x %02x %02x %02x"
			       "  %02x %02x %02x %02x %02x %02x %02x %02x\n",
			       p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
			       p[8], p[9], p[10], p[11], p[12], p[13], p[14],
			       p[15]);
			p += 16;
		}
	}
Exemplo n.º 8
0
static void test_mtd_read_oob(void **state)
{
	struct libmtd *lib = mock_libmtd_open();
	struct mtd_dev_info mtd;
	struct mtd_oob_buf64 oob64;
	struct mtd_oob_buf oob;
	int mock_fd = 4;
	uint64_t start = 0, length = 64;
	char buf[64];
	memset(buf, 0xCD, 64);
	memset(&oob, 0, sizeof(oob));
	memset(&oob64, 0, sizeof(oob64));
	memset(&mtd, 0, sizeof(mtd));
	mtd.bb_allowed = 1;
	mtd.eb_cnt = 1024;
	mtd.eb_size = 128;
	mtd.subpage_size = 64;
	mtd.oob_size = 128;
	oob64.start = start;
	oob64.length = length;
	oob64.usr_ptr = (uint64_t)(unsigned long)buf;
	oob.start = oob64.start;
	oob.length = oob64.length;
	oob.ptr = buf;

	lib->offs64_ioctls = OFFS64_IOCTLS_NOT_SUPPORTED;
	expect_ioctl(MEMREADOOB, 0, &oob);
	int r = mtd_read_oob(lib, &mtd, mock_fd, start, length, buf);
	assert_int_equal(r, 0);

	lib->offs64_ioctls = OFFS64_IOCTLS_SUPPORTED;
	expect_ioctl(MEMREADOOB64, 0, &oob64);
	r = mtd_read_oob(lib, &mtd, mock_fd, start, length, buf);
	assert_int_equal(r, 0);

	libmtd_close(lib);
	(void) state;
}
static int read_eraseblock_by_page(int ebnum)
{
	size_t read;
	int i, ret, err = 0;
	loff_t addr = ebnum * mtd->erasesize;
	void *buf = iobuf;
	void *oobbuf = iobuf1;

	for (i = 0; i < pgcnt; i++) {
		memset(buf, 0 , pgcnt);
		ret = mtd_read(mtd, addr, pgsize, &read, buf);
		if (ret == -EUCLEAN)
			ret = 0;
		if (ret || read != pgsize) {
			printk(PRINT_PREF "error: read failed at %#llx\n",
			       (long long)addr);
			if (!err)
				err = ret;
			if (!err)
				err = -EINVAL;
		}
		if (mtd->oobsize) {
			struct mtd_oob_ops ops;

			ops.mode      = MTD_OPS_PLACE_OOB;
			ops.len       = 0;
			ops.retlen    = 0;
			ops.ooblen    = mtd->oobsize;
			ops.oobretlen = 0;
			ops.ooboffs   = 0;
			ops.datbuf    = NULL;
			ops.oobbuf    = oobbuf;
			ret = mtd_read_oob(mtd, addr, &ops);
			if ((ret && !mtd_is_bitflip(ret)) ||
					ops.oobretlen != mtd->oobsize) {
				printk(PRINT_PREF "error: read oob failed at "
						  "%#llx\n", (long long)addr);
				if (!err)
					err = ret;
				if (!err)
					err = -EINVAL;
			}
			oobbuf += mtd->oobsize;
		}
		addr += pgsize;
		buf += pgsize;
	}

	return err;
}
Exemplo n.º 10
0
static int sharpsl_nand_read_oob(struct mtd_info *mtd, loff_t offs, u8 *buf)
{
	struct mtd_oob_ops ops = { };
	int ret;

	ops.mode = MTD_OPS_PLACE_OOB;
	ops.ooblen = mtd->oobsize;
	ops.oobbuf = buf;

	ret = mtd_read_oob(mtd, offs, &ops);
	if (ret != 0 || mtd->oobsize != ops.oobretlen)
		return -1;

	return 0;
}
Exemplo n.º 11
0
static __maybe_unused ssize_t raw_read_page(struct mtd_info *mtd, void *dst, loff_t offset)
{
	struct mtd_oob_ops ops;
	ssize_t ret;

	ops.mode = MTD_OPS_RAW;
	ops.ooboffs = 0;
	ops.datbuf = dst;
	ops.len = mtd->writesize;
	ops.oobbuf = dst + mtd->writesize;
	ops.ooblen = mtd->oobsize;
	ret = mtd_read_oob(mtd, offset, &ops);

        return ret;
}
Exemplo n.º 12
0
/* Read one page with oob one time */
int ubi_io_read_oob(const struct ubi_device *ubi, void *databuf, void *oobbuf,
                int pnum, int offset)
{
        int err;
        loff_t addr;
        struct mtd_oob_ops ops;

        dbg_io("read from PEB %d:%d", pnum, offset);

        ubi_assert(pnum >= 0 && pnum < ubi->peb_count);
        ubi_assert(offset >= 0 && offset + ubi->mtd->writesize <= ubi->peb_size);

        addr = (loff_t)pnum * ubi->peb_size + offset;

        ops.mode = MTD_OPS_AUTO_OOB;
        ops.ooblen = ubi->mtd->oobavail;
        ops.oobbuf = oobbuf;
        ops.ooboffs = 0;
        ops.len = ubi->mtd->writesize;
        ops.datbuf = databuf;
        ops.retlen = ops.oobretlen = 0;

        err = mtd_read_oob(ubi->mtd, addr, &ops);
        if (err) {
                if (err == -EUCLEAN) {
                        /*
                         * -EUCLEAN is reported if there was a bit-flip which
                         * was corrected, so this is harmless.
                         *
                         * We do not report about it here unless debugging is
                         * enabled. A corresponding message will be printed
                         * later, when it is has been scrubbed.
                         */
                        ubi_msg("fixable bit-flip detected at addr %lld", addr);
                        if(oobbuf)
                                ubi_assert(ops.oobretlen == ops.ooblen);
                        return UBI_IO_BITFLIPS;
                }
                if (ops.retlen != ops.len && err == -EBADMSG) {
                        ubi_err("err(%d), retlen(%zu), len(%zu)", err, ops.retlen, ops.len);
			dump_stack();
                        err = -EIO;
                }
		ubi_msg("mtd_read_oob err %d\n", err);
        }

        return err;
}
Exemplo n.º 13
0
static int verify_eraseblock_in_one_go(int ebnum)
{
	struct mtd_oob_ops ops;
	int err = 0;
	loff_t addr = (loff_t)ebnum * mtd->erasesize;
	size_t len = mtd->ecclayout->oobavail * pgcnt;
	size_t oobavail = mtd->ecclayout->oobavail;
	size_t bitflips;
	int i;

	prandom_bytes_state(&rnd_state, writebuf, len);
	ops.mode      = MTD_OPS_AUTO_OOB;
	ops.len       = 0;
	ops.retlen    = 0;
	ops.ooblen    = len;
	ops.oobretlen = 0;
	ops.ooboffs   = 0;
	ops.datbuf    = NULL;
	ops.oobbuf    = readbuf;

	/* read entire block's OOB at one go */
	err = mtd_read_oob(mtd, addr, &ops);
	if (err || ops.oobretlen != len) {
		pr_err("error: readoob failed at %#llx\n",
		       (long long)addr);
		errcnt += 1;
		return err ? err : -1;
	}

	/* 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",
			       (long long)addr);
			errcnt += 1;
			if (errcnt > 1000) {
				pr_err("error: too many errors\n");
				return -1;
			}
		} else if (bitflips) {
			pr_info("ignoring error as within bitflip_limit\n");
		}
	}

	return err;
}
Exemplo n.º 14
0
/*
 * Read oob data from flash
 */
int inftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len,
		   size_t *retlen, uint8_t *buf)
{
	struct mtd_oob_ops ops;
	int res;

	ops.mode = MTD_OPS_PLACE_OOB;
	ops.ooboffs = offs & (mtd->writesize - 1);
	ops.ooblen = len;
	ops.oobbuf = buf;
	ops.datbuf = NULL;

	res = mtd_read_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
	*retlen = ops.oobretlen;
	return res;
}
Exemplo n.º 15
0
Arquivo: mtdpart.c Projeto: DFE/u-boot
static int part_read_oob(struct mtd_info *mtd, loff_t from,
		struct mtd_oob_ops *ops)
{
	struct mtd_part *part = PART(mtd);
	int res;

	if (from >= mtd->size)
		return -EINVAL;
	if (ops->datbuf && from + ops->len > mtd->size)
		return -EINVAL;
	res = mtd_read_oob(part->master, from + part->offset, ops);

	if (unlikely(res)) {
		if (mtd_is_bitflip(res))
			mtd->ecc_stats.corrected++;
		if (mtd_is_eccerr(res))
			mtd->ecc_stats.failed++;
	}
	return res;
}
Exemplo n.º 16
0
int nandmtd_ReadChunkFromNAND(struct yaffs_dev *dev, int chunkInNAND, u8 *data,
			      struct yaffs_spare *spare)
{
	struct mtd_info *mtd = (struct mtd_info *)(dev->driver_context);
	struct mtd_oob_ops ops;
	size_t dummy;
	int retval = 0;

	loff_t addr = ((loff_t) chunkInNAND) * dev->data_bytes_per_chunk;
	u8 spareAsBytes[8]; /* OOB */

	if (data && !spare)
		retval = mtd_read(mtd, addr, dev->data_bytes_per_chunk,
				&dummy, data);
	else if (spare) {
		if (dev->param.use_nand_ecc) {
			ops.mode = MTD_OPS_AUTO_OOB;
			ops.ooblen = 8; /* temp hack */
		} else {
			ops.mode = MTD_OPS_RAW;
			ops.ooblen = YAFFS_BYTES_PER_SPARE;
		}
		ops.len = data ? dev->data_bytes_per_chunk : ops.ooblen;
		ops.datbuf = data;
		ops.ooboffs = 0;
		ops.oobbuf = spareAsBytes;
		retval = mtd_read_oob(mtd, addr, &ops);
		if (dev->param.use_nand_ecc)
			translate_oob2spare(spare, spareAsBytes);
	}

	if (retval == 0)
		return YAFFS_OK;
	else
		return YAFFS_FAIL;
}
int nandmtd2_read_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
			     u8 * data, struct yaffs_ext_tags *tags)
{
	struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
	struct mtd_oob_ops ops;

	size_t dummy;
	int retval = 0;
	int local_data = 0;

	loff_t addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;

	struct yaffs_packed_tags2 pt;

	int packed_tags_size =
	    dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
	void *packed_tags_ptr =
	    dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;

	yaffs_trace(YAFFS_TRACE_MTD,
		"nandmtd2_read_chunk_tags chunk %d data %p tags %p",
		nand_chunk, data, tags);

	if (dev->param.inband_tags) {

		if (!data) {
			local_data = 1;
			data = yaffs_get_temp_buffer(dev, __LINE__);
		}

	}

	if (dev->param.inband_tags || (data && !tags))
		retval = mtd_read(mtd, addr, dev->param.total_bytes_per_chunk,
				   &dummy, data);
	else if (tags) {

#if 1
    	if(!data )
    	{
			local_data = 1;
			data = yaffs_get_temp_buffer(dev, __LINE__);

    	}
		ops.mode = MTD_OPS_AUTO_OOB;
		ops.ooblen = packed_tags_size;
		ops.ooboffs = 0;
		ops.len = dev->data_bytes_per_chunk;
		ops.datbuf = data;
		ops.oobbuf = yaffs_dev_to_lc(dev)->spare_buffer;
		retval = mtd_read_oob(mtd, addr, &ops);
		if(retval)
		{
			printk(KERN_ERR"yaffsdebug mtdiferror %s retval:%d unfixed:%d fixed:%d chunk:%d addr:0x%llx\n",\
				(retval == -EUCLEAN)?"fix ecc":"unfix ecc",retval,dev->n_ecc_unfixed,dev->n_ecc_fixed,nand_chunk,addr);
#ifdef YAFFS_MVG_TEST_DEBUG_LOG
			if(retval != -EUCLEAN)
			{
				printk(KERN_ERR"dump checksum_BCH chunk:%d addr:0x%x\n",nand_chunk,addr);
				mtk_dump_byte(ops.datbuf,ops.len,0);		
				printk(KERN_ERR"dump BCH oob\n");
				mtk_dump_byte(ops.oobbuf,ops.ooblen,0);			
			}
#endif	
		}

#else
		ops.mode = MTD_OOB_AUTO;
		ops.ooblen = packed_tags_size;
		ops.len = data ? dev->data_bytes_per_chunk : packed_tags_size;
		ops.ooboffs = 0;
		ops.datbuf = data;
		ops.oobbuf = yaffs_dev_to_lc(dev)->spare_buffer;
		retval = mtd->read_oob(mtd, addr, &ops);
#endif	
	}

	if (dev->param.inband_tags) {
		if (tags) {
			struct yaffs_packed_tags2_tags_only *pt2tp;
			pt2tp =
			    (struct yaffs_packed_tags2_tags_only *)&data[dev->
									 data_bytes_per_chunk];
			yaffs_unpack_tags2_tags_only(tags, pt2tp);
		}
	} else {
		if (tags) {
			memcpy(packed_tags_ptr,
			       yaffs_dev_to_lc(dev)->spare_buffer,
			       packed_tags_size);
			yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc);
		}
	}

	if (local_data)
		yaffs_release_temp_buffer(dev, data, __LINE__);

	if (tags && retval == -EBADMSG
	    && tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) {
		tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED;
		dev->n_ecc_unfixed++;
	}
	if (tags && retval == -EUCLEAN
	    && tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) {
		tags->ecc_result = YAFFS_ECC_RESULT_FIXED;
		dev->n_ecc_fixed++;
	}
	if (retval == 0)
		return YAFFS_OK;
	else
		return YAFFS_FAIL;
}
int nandmtd2_read_chunk_tags(struct yaffs_dev *dev, int nand_chunk,
			     u8 * data, struct yaffs_ext_tags *tags)
{
	struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
	struct mtd_oob_ops ops;

	size_t dummy;
	int retval = 0;
	int local_data = 0;

	loff_t addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;

	struct yaffs_packed_tags2 pt;

	int packed_tags_size =
	    dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
	void *packed_tags_ptr =
	    dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;

	yaffs_trace(YAFFS_TRACE_MTD,
		"nandmtd2_read_chunk_tags chunk %d data %p tags %p",
		nand_chunk, data, tags);

	if (dev->param.inband_tags) {

		if (!data) {
			local_data = 1;
			data = yaffs_get_temp_buffer(dev, __LINE__);
		}

	}

	if (dev->param.inband_tags || (data && !tags))
		retval = mtd_read(mtd, addr, dev->param.total_bytes_per_chunk,
				   &dummy, data);
	else if (tags) {
		ops.mode = MTD_OPS_AUTO_OOB;
		ops.ooblen = packed_tags_size;
		ops.len = data ? dev->data_bytes_per_chunk : packed_tags_size;
		ops.ooboffs = 0;
		ops.datbuf = data;
		ops.oobbuf = yaffs_dev_to_lc(dev)->spare_buffer;
		retval = mtd_read_oob(mtd, addr, &ops);
	}

	if (dev->param.inband_tags) {
		if (tags) {
			struct yaffs_packed_tags2_tags_only *pt2tp;
			pt2tp =
			    (struct yaffs_packed_tags2_tags_only *)&data[dev->
									 data_bytes_per_chunk];
			yaffs_unpack_tags2_tags_only(tags, pt2tp);
		}
	} else {
		if (tags) {
			memcpy(packed_tags_ptr,
			       yaffs_dev_to_lc(dev)->spare_buffer,
			       packed_tags_size);
			yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc);
		}
	}

	if (local_data)
		yaffs_release_temp_buffer(dev, data, __LINE__);

	if (tags && retval == -EBADMSG
	    && tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) {
		tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED;
		dev->n_ecc_unfixed++;
	}
	if (tags && retval == -EUCLEAN
	    && tags->ecc_result == YAFFS_ECC_RESULT_NO_ERROR) {
		tags->ecc_result = YAFFS_ECC_RESULT_FIXED;
		dev->n_ecc_fixed++;
	}
	if (retval == 0)
		return YAFFS_OK;
	else
		return YAFFS_FAIL;
}
Exemplo n.º 19
0
/*
 * Main program
 */
int main(int argc, char * const argv[])
{
	long long ofs, end_addr = 0;
	long long blockstart = 1;
	int ret, i, fd, ofd = 0, bs, badblock = 0;
	struct mtd_dev_info mtd;
	char pretty_buf[PRETTY_BUF_LEN];
	int oobinfochanged = 0, firstblock = 1;
	struct nand_oobinfo old_oobinfo;
	struct mtd_ecc_stats stat1, stat2;
	bool eccstats = false;
	unsigned char *readbuf = NULL, *oobbuf = NULL;
	libmtd_t mtd_desc;

	process_options(argc, argv);

	/* Initialize libmtd */
	mtd_desc = libmtd_open();
	if (!mtd_desc)
		return errmsg("can't initialize libmtd");

	/* Open MTD device */
	if ((fd = open(mtddev, O_RDONLY)) == -1) {
		perror(mtddev);
		exit(EXIT_FAILURE);
	}

	/* Fill in MTD device capability structure */
	if (mtd_get_dev_info(mtd_desc, mtddev, &mtd) < 0)
		return errmsg("mtd_get_dev_info failed");

	/* Allocate buffers */
	oobbuf = xmalloc(sizeof(oobbuf) * mtd.oob_size);
	readbuf = xmalloc(sizeof(readbuf) * mtd.min_io_size);

	if (noecc)  {
		ret = ioctl(fd, MTDFILEMODE, MTD_MODE_RAW);
		if (ret == 0) {
			oobinfochanged = 2;
		} else {
			switch (errno) {
			case ENOTTY:
				if (ioctl(fd, MEMGETOOBSEL, &old_oobinfo) != 0) {
					perror("MEMGETOOBSEL");
					goto closeall;
				}
				if (ioctl(fd, MEMSETOOBSEL, &none_oobinfo) != 0) {
					perror("MEMSETOOBSEL");
					goto closeall;
				}
				oobinfochanged = 1;
				break;
			default:
				perror("MTDFILEMODE");
				goto closeall;
			}
		}
	} else {
		/* check if we can read ecc stats */
		if (!ioctl(fd, ECCGETSTATS, &stat1)) {
			eccstats = true;
			if (!quiet) {
				fprintf(stderr, "ECC failed: %d\n", stat1.failed);
				fprintf(stderr, "ECC corrected: %d\n", stat1.corrected);
				fprintf(stderr, "Number of bad blocks: %d\n", stat1.badblocks);
				fprintf(stderr, "Number of bbt blocks: %d\n", stat1.bbtblocks);
			}
		} else
			perror("No ECC status information available");
	}

	/* Open output file for writing. If file name is "-", write to standard
	 * output. */
	if (!dumpfile) {
		ofd = STDOUT_FILENO;
	} else if ((ofd = open(dumpfile, O_WRONLY | O_TRUNC | O_CREAT, 0644))== -1) {
		perror(dumpfile);
		goto closeall;
	}

	if (!pretty_print && !forcebinary && isatty(ofd)) {
		fprintf(stderr, "Not printing binary garbage to tty. Use '-a'\n"
				"or '--forcebinary' to override.\n");
		goto closeall;
	}

	/* Initialize start/end addresses and block size */
	if (start_addr & (mtd.min_io_size - 1)) {
		fprintf(stderr, "WARNING: The start address is not page-aligned !\n"
				"The pagesize of this NAND Flash is 0x%x.\n"
				"nandwrite doesn't allow writes starting at this location.\n"
				"Future versions of nanddump will fail here.\n",
				mtd.min_io_size);
	}
	if (length)
		end_addr = start_addr + length;
	if (!length || end_addr > mtd.size)
		end_addr = mtd.size;

	bs = mtd.min_io_size;

	/* Print informative message */
	if (!quiet) {
		fprintf(stderr, "Block size %d, page size %d, OOB size %d\n",
				mtd.eb_size, mtd.min_io_size, mtd.oob_size);
		fprintf(stderr,
				"Dumping data starting at 0x%08llx and ending at 0x%08llx...\n",
				start_addr, end_addr);
	}

	/* Dump the flash contents */
	for (ofs = start_addr; ofs < end_addr; ofs += bs) {
		/* Check for bad block */
		if (noskipbad) {
			badblock = 0;
		} else if (blockstart != (ofs & (~mtd.eb_size + 1)) ||
				firstblock) {
			blockstart = ofs & (~mtd.eb_size + 1);
			firstblock = 0;
			if ((badblock = mtd_is_bad(&mtd, fd, ofs / mtd.eb_size)) < 0) {
				errmsg("libmtd: mtd_is_bad");
				goto closeall;
			}
		}

		if (badblock) {
			if (omitbad)
				continue;
			memset(readbuf, 0xff, bs);
		} else {
			/* Read page data and exit on failure */
			if (mtd_read(&mtd, fd, ofs / mtd.eb_size, ofs % mtd.eb_size, readbuf, bs)) {
				errmsg("mtd_read");
				goto closeall;
			}
		}

		/* ECC stats available ? */
		if (eccstats) {
			if (ioctl(fd, ECCGETSTATS, &stat2)) {
				perror("ioctl(ECCGETSTATS)");
				goto closeall;
			}
			if (stat1.failed != stat2.failed)
				fprintf(stderr, "ECC: %d uncorrectable bitflip(s)"
						" at offset 0x%08llx\n",
						stat2.failed - stat1.failed, ofs);
			if (stat1.corrected != stat2.corrected)
				fprintf(stderr, "ECC: %d corrected bitflip(s) at"
						" offset 0x%08llx\n",
						stat2.corrected - stat1.corrected, ofs);
			stat1 = stat2;
		}

		/* Write out page data */
		if (pretty_print) {
			for (i = 0; i < bs; i += PRETTY_ROW_SIZE) {
				pretty_dump_to_buffer(readbuf + i, PRETTY_ROW_SIZE,
						pretty_buf, PRETTY_BUF_LEN, true, canonical, ofs + i);
				write(ofd, pretty_buf, strlen(pretty_buf));
			}
		} else
			write(ofd, readbuf, bs);

		if (omitoob)
			continue;

		if (badblock) {
			memset(oobbuf, 0xff, mtd.oob_size);
		} else {
			/* Read OOB data and exit on failure */
			if (mtd_read_oob(mtd_desc, &mtd, fd, ofs, mtd.oob_size, oobbuf)) {
				errmsg("libmtd: mtd_read_oob");
				goto closeall;
			}
		}

		/* Write out OOB data */
		if (pretty_print) {
			for (i = 0; i < mtd.oob_size; i += PRETTY_ROW_SIZE) {
				pretty_dump_to_buffer(oobbuf + i, mtd.oob_size - i,
						pretty_buf, PRETTY_BUF_LEN, false, canonical, 0);
				write(ofd, pretty_buf, strlen(pretty_buf));
			}
		} else
			write(ofd, oobbuf, mtd.oob_size);
	}

	/* reset oobinfo */
	if (oobinfochanged == 1) {
		if (ioctl(fd, MEMSETOOBSEL, &old_oobinfo) != 0) {
			perror("MEMSETOOBSEL");
			close(fd);
			close(ofd);
			return EXIT_FAILURE;
		}
	}
	/* Close the output file and MTD device, free memory */
	close(fd);
	close(ofd);
	free(oobbuf);
	free(readbuf);

	/* Exit happy */
	return EXIT_SUCCESS;

closeall:
	/* The new mode change is per file descriptor ! */
	if (oobinfochanged == 1) {
		if (ioctl(fd, MEMSETOOBSEL, &old_oobinfo) != 0)  {
			perror("MEMSETOOBSEL");
		}
	}
	close(fd);
	close(ofd);
	free(oobbuf);
	free(readbuf);
	exit(EXIT_FAILURE);
}
/* Read a chunk (page) from NAND.
 *
 * Caller expects ExtendedTags data to be usable even on error; that is,
 * all members except ecc_result and block_bad are zeroed.
 *
 *  - Check ECC results for data (if applicable)
 *  - Check for blank/erased block (return empty ExtendedTags if blank)
 *  - Check the packed_tags1 mini-ECC (correct if necessary/possible)
 *  - Convert packed_tags1 to ExtendedTags
 *  - Update ecc_result and block_bad members to refect state.
 *
 * Returns YAFFS_OK or YAFFS_FAIL.
 */
int nandmtd1_read_chunk_tags(struct yaffs_dev *dev,
			     int nand_chunk, u8 * data,
			     struct yaffs_ext_tags *etags)
{
	struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
	int chunk_bytes = dev->data_bytes_per_chunk;
	loff_t addr = ((loff_t) nand_chunk) * chunk_bytes;
	int eccres = YAFFS_ECC_RESULT_NO_ERROR;
	struct mtd_oob_ops ops;
	struct yaffs_packed_tags1 pt1;
	int retval;
	int deleted;

	memset(&ops, 0, sizeof(ops));
	ops.mode =  MTD_OPS_AUTO_OOB;
	ops.len = (data) ? chunk_bytes : 0;
	ops.ooblen = YTAG1_SIZE;
	ops.datbuf = data;
	ops.oobbuf = (u8 *) & pt1;

	/* Read page and oob using MTD.
	 * Check status and determine ECC result.
	 */
	retval = mtd_read_oob(mtd, addr, &ops);
	if (retval) {
		yaffs_trace(YAFFS_TRACE_MTD,
			"read_oob failed, chunk %d, mtd error %d",
			nand_chunk, retval);
	}

	switch (retval) {
	case 0:
		/* no error */
		break;

	case -EUCLEAN:
		/* MTD's ECC fixed the data */
		eccres = YAFFS_ECC_RESULT_FIXED;
		dev->n_ecc_fixed++;
		break;

	case -EBADMSG:
		/* MTD's ECC could not fix the data */
		dev->n_ecc_unfixed++;
		/* fall into... */
	default:
		rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0);
		etags->block_bad = (mtd_block_isbad) (mtd, addr);
		return YAFFS_FAIL;
	}

	/* Check for a blank/erased chunk.
	 */
	if (yaffs_check_ff((u8 *) & pt1, 8)) {
		/* when blank, upper layers want ecc_result to be <= NO_ERROR */
		return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK);
	}
#ifndef CONFIG_YAFFS_9BYTE_TAGS
	/* Read deleted status (bit) then return it to it's non-deleted
	 * state before performing tags mini-ECC check. pt1.deleted is
	 * inverted.
	 */
	deleted = !pt1.deleted;
	pt1.deleted = 1;
#else
	deleted = (yaffs_count_bits(((u8 *) & pt1)[8]) < 7);
#endif

	/* Check the packed tags mini-ECC and correct if necessary/possible.
	 */
	retval = yaffs_check_tags_ecc((struct yaffs_tags *)&pt1);
	switch (retval) {
	case 0:
		/* no tags error, use MTD result */
		break;
	case 1:
		/* recovered tags-ECC error */
		dev->n_tags_ecc_fixed++;
		if (eccres == YAFFS_ECC_RESULT_NO_ERROR)
			eccres = YAFFS_ECC_RESULT_FIXED;
		break;
	default:
		/* unrecovered tags-ECC error */
		dev->n_tags_ecc_unfixed++;
		return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL);
	}

	/* Unpack the tags to extended form and set ECC result.
	 * [set should_be_ff just to keep yaffs_unpack_tags1 happy]
	 */
	pt1.should_be_ff = 0xFFFFFFFF;
	yaffs_unpack_tags1(etags, &pt1);
	etags->ecc_result = eccres;

	/* Set deleted state */
	etags->is_deleted = deleted;
	return YAFFS_OK;
}
Exemplo n.º 21
0
static int verify_eraseblock(int ebnum)
{
	int i;
	struct mtd_oob_ops ops;
	int err = 0;
	loff_t addr = (loff_t)ebnum * mtd->erasesize;
	size_t bitflips;

	prandom_bytes_state(&rnd_state, writebuf, use_len_max * pgcnt);
	for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) {
		ops.mode      = MTD_OPS_AUTO_OOB;
		ops.len       = 0;
		ops.retlen    = 0;
		ops.ooblen    = use_len;
		ops.oobretlen = 0;
		ops.ooboffs   = use_offset;
		ops.datbuf    = NULL;
		ops.oobbuf    = readbuf;
		err = mtd_read_oob(mtd, addr, &ops);
		if (err || ops.oobretlen != use_len) {
			pr_err("error: readoob failed at %#llx\n",
			       (long long)addr);
			errcnt += 1;
			return err ? err : -1;
		}

		bitflips = memcmpshow(addr, readbuf,
				      writebuf + (use_len_max * i) + use_offset,
				      use_len);
		if (bitflips > bitflip_limit) {
			pr_err("error: verify failed at %#llx\n",
			       (long long)addr);
			errcnt += 1;
			if (errcnt > 1000) {
				pr_err("error: too many errors\n");
				return -1;
			}
		} else if (bitflips) {
			pr_info("ignoring error as within bitflip_limit\n");
		}

		if (use_offset != 0 || use_len < mtd->ecclayout->oobavail) {
			int k;

			ops.mode      = MTD_OPS_AUTO_OOB;
			ops.len       = 0;
			ops.retlen    = 0;
			ops.ooblen    = mtd->ecclayout->oobavail;
			ops.oobretlen = 0;
			ops.ooboffs   = 0;
			ops.datbuf    = NULL;
			ops.oobbuf    = readbuf;
			err = mtd_read_oob(mtd, addr, &ops);
			if (err || ops.oobretlen != mtd->ecclayout->oobavail) {
				pr_err("error: readoob failed at %#llx\n",
						(long long)addr);
				errcnt += 1;
				return err ? err : -1;
			}
			bitflips = memcmpshow(addr, readbuf + use_offset,
					      writebuf + (use_len_max * i) + use_offset,
					      use_len);

			/* verify pre-offset area for 0xff */
			bitflips += memffshow(addr, 0, readbuf, use_offset);

			/* verify post-(use_offset + use_len) area for 0xff */
			k = use_offset + use_len;
			bitflips += memffshow(addr, k, readbuf + k,
					      mtd->ecclayout->oobavail - k);

			if (bitflips > bitflip_limit) {
				pr_err("error: verify failed at %#llx\n",
						(long long)addr);
				errcnt += 1;
				if (errcnt > 1000) {
					pr_err("error: too many errors\n");
					return -1;
				}
			} else if (bitflips) {
				pr_info("ignoring errors as within bitflip limit\n");
			}
		}
		if (vary_offset)
			do_vary_offset();
	}
	return err;
}
Exemplo n.º 22
0
static int __init mtd_oobtest_init(void)
{
    int err = 0;
    unsigned int i;
    uint64_t tmp;
    struct mtd_oob_ops ops;
    loff_t addr = 0, addr0;

    printk(KERN_INFO "\n");
    printk(KERN_INFO "=================================================\n");

    if (dev < 0) {
        printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n");
        printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n");
        return -EINVAL;
    }

    printk(PRINT_PREF "MTD device: %d\n", dev);

    mtd = get_mtd_device(NULL, dev);
    if (IS_ERR(mtd)) {
        err = PTR_ERR(mtd);
        printk(PRINT_PREF "error: cannot get MTD device\n");
        return err;
    }

    if (mtd->type != MTD_NANDFLASH) {
        printk(PRINT_PREF "this test requires NAND flash\n");
        goto out;
    }

    tmp = mtd->size;
    do_div(tmp, mtd->erasesize);
    ebcnt = tmp;
    pgcnt = mtd->erasesize / mtd->writesize;

    printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
           "page size %u, count of eraseblocks %u, pages per "
           "eraseblock %u, OOB size %u\n",
           (unsigned long long)mtd->size, mtd->erasesize,
           mtd->writesize, ebcnt, pgcnt, mtd->oobsize);

    err = -ENOMEM;
    readbuf = kmalloc(mtd->erasesize, GFP_KERNEL);
    if (!readbuf) {
        printk(PRINT_PREF "error: cannot allocate memory\n");
        goto out;
    }
    writebuf = kmalloc(mtd->erasesize, GFP_KERNEL);
    if (!writebuf) {
        printk(PRINT_PREF "error: cannot allocate memory\n");
        goto out;
    }

    err = scan_for_bad_eraseblocks();
    if (err)
        goto out;

    use_offset = 0;
    use_len = mtd->ecclayout->oobavail;
    use_len_max = mtd->ecclayout->oobavail;
    vary_offset = 0;

    /* First test: write all OOB, read it back and verify */
    printk(PRINT_PREF "test 1 of 5\n");

    err = erase_whole_device();
    if (err)
        goto out;

    simple_srand(1);
    err = write_whole_device();
    if (err)
        goto out;

    simple_srand(1);
    err = verify_all_eraseblocks();
    if (err)
        goto out;

    /*
     * Second test: write all OOB, a block at a time, read it back and
     * verify.
     */
    printk(PRINT_PREF "test 2 of 5\n");

    err = erase_whole_device();
    if (err)
        goto out;

    simple_srand(3);
    err = write_whole_device();
    if (err)
        goto out;

    /* Check all eraseblocks */
    simple_srand(3);
    printk(PRINT_PREF "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)
            printk(PRINT_PREF "verified up to eraseblock %u\n", i);
        cond_resched();
    }
    printk(PRINT_PREF "verified %u eraseblocks\n", i);

    /*
     * Third test: write OOB at varying offsets and lengths, read it back
     * and verify.
     */
    printk(PRINT_PREF "test 3 of 5\n");

    err = erase_whole_device();
    if (err)
        goto out;

    /* Write all eraseblocks */
    use_offset = 0;
    use_len = mtd->ecclayout->oobavail;
    use_len_max = mtd->ecclayout->oobavail;
    vary_offset = 1;
    simple_srand(5);

    err = write_whole_device();
    if (err)
        goto out;

    /* Check all eraseblocks */
    use_offset = 0;
    use_len = mtd->ecclayout->oobavail;
    use_len_max = mtd->ecclayout->oobavail;
    vary_offset = 1;
    simple_srand(5);
    err = verify_all_eraseblocks();
    if (err)
        goto out;

    use_offset = 0;
    use_len = mtd->ecclayout->oobavail;
    use_len_max = mtd->ecclayout->oobavail;
    vary_offset = 0;

    /* Fourth test: try to write off end of device */
    printk(PRINT_PREF "test 4 of 5\n");

    err = erase_whole_device();
    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->ecclayout->oobavail;
    ops.datbuf    = NULL;
    ops.oobbuf    = writebuf;
    printk(PRINT_PREF "attempting to start write past end of OOB\n");
    printk(PRINT_PREF "an error is expected...\n");
    err = mtd_write_oob(mtd, addr0, &ops);
    if (err) {
        printk(PRINT_PREF "error occurred as expected\n");
        err = 0;
    } else {
        printk(PRINT_PREF "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->ecclayout->oobavail;
    ops.datbuf    = NULL;
    ops.oobbuf    = readbuf;
    printk(PRINT_PREF "attempting to start read past end of OOB\n");
    printk(PRINT_PREF "an error is expected...\n");
    err = mtd_read_oob(mtd, addr0, &ops);
    if (err) {
        printk(PRINT_PREF "error occurred as expected\n");
        err = 0;
    } else {
        printk(PRINT_PREF "error: can read past end of OOB\n");
        errcnt += 1;
    }

    if (bbt[ebcnt - 1])
        printk(PRINT_PREF "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->ecclayout->oobavail + 1;
        ops.oobretlen = 0;
        ops.ooboffs   = 0;
        ops.datbuf    = NULL;
        ops.oobbuf    = writebuf;
        printk(PRINT_PREF "attempting to write past end of device\n");
        printk(PRINT_PREF "an error is expected...\n");
        err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops);
        if (err) {
            printk(PRINT_PREF "error occurred as expected\n");
            err = 0;
        } else {
            printk(PRINT_PREF "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->ecclayout->oobavail + 1;
        ops.oobretlen = 0;
        ops.ooboffs   = 0;
        ops.datbuf    = NULL;
        ops.oobbuf    = readbuf;
        printk(PRINT_PREF "attempting to read past end of device\n");
        printk(PRINT_PREF "an error is expected...\n");
        err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops);
        if (err) {
            printk(PRINT_PREF "error occurred as expected\n");
            err = 0;
        } else {
            printk(PRINT_PREF "error: read past end of device\n");
            errcnt += 1;
        }

        err = erase_eraseblock(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->ecclayout->oobavail;
        ops.oobretlen = 0;
        ops.ooboffs   = 1;
        ops.datbuf    = NULL;
        ops.oobbuf    = writebuf;
        printk(PRINT_PREF "attempting to write past end of device\n");
        printk(PRINT_PREF "an error is expected...\n");
        err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops);
        if (err) {
            printk(PRINT_PREF "error occurred as expected\n");
            err = 0;
        } else {
            printk(PRINT_PREF "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->ecclayout->oobavail;
        ops.oobretlen = 0;
        ops.ooboffs   = 1;
        ops.datbuf    = NULL;
        ops.oobbuf    = readbuf;
        printk(PRINT_PREF "attempting to read past end of device\n");
        printk(PRINT_PREF "an error is expected...\n");
        err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops);
        if (err) {
            printk(PRINT_PREF "error occurred as expected\n");
            err = 0;
        } else {
            printk(PRINT_PREF "error: read past end of device\n");
            errcnt += 1;
        }
    }

    /* Fifth test: write / read across block boundaries */
    printk(PRINT_PREF "test 5 of 5\n");

    /* Erase all eraseblocks */
    err = erase_whole_device();
    if (err)
        goto out;

    /* Write all eraseblocks */
    simple_srand(11);
    printk(PRINT_PREF "writing OOBs of whole device\n");
    for (i = 0; i < ebcnt - 1; ++i) {
        int cnt = 2;
        int pg;
        size_t sz = mtd->ecclayout->oobavail;
        if (bbt[i] || bbt[i + 1])
            continue;
        addr = (i + 1) * mtd->erasesize - mtd->writesize;
        for (pg = 0; pg < cnt; ++pg) {
            set_random_data(writebuf, sz);
            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;
            err = mtd_write_oob(mtd, addr, &ops);
            if (err)
                goto out;
            if (i % 256 == 0)
                printk(PRINT_PREF "written up to eraseblock "
                       "%u\n", i);
            cond_resched();
            addr += mtd->writesize;
        }
    }
    printk(PRINT_PREF "written %u eraseblocks\n", i);

    /* Check all eraseblocks */
    simple_srand(11);
    printk(PRINT_PREF "verifying all eraseblocks\n");
    for (i = 0; i < ebcnt - 1; ++i) {
        if (bbt[i] || bbt[i + 1])
            continue;
        set_random_data(writebuf, mtd->ecclayout->oobavail * 2);
        addr = (i + 1) * mtd->erasesize - mtd->writesize;
        ops.mode      = MTD_OPS_AUTO_OOB;
        ops.len       = 0;
        ops.retlen    = 0;
        ops.ooblen    = mtd->ecclayout->oobavail * 2;
        ops.oobretlen = 0;
        ops.ooboffs   = 0;
        ops.datbuf    = NULL;
        ops.oobbuf    = readbuf;
        err = mtd_read_oob(mtd, addr, &ops);
        if (err)
            goto out;
        if (memcmp(readbuf, writebuf, mtd->ecclayout->oobavail * 2)) {
            printk(PRINT_PREF "error: verify failed at %#llx\n",
                   (long long)addr);
            errcnt += 1;
            if (errcnt > 1000) {
                printk(PRINT_PREF "error: too many errors\n");
                goto out;
            }
        }
        if (i % 256 == 0)
            printk(PRINT_PREF "verified up to eraseblock %u\n", i);
        cond_resched();
    }
    printk(PRINT_PREF "verified %u eraseblocks\n", i);

    printk(PRINT_PREF "finished with %d errors\n", errcnt);
out:
    kfree(bbt);
    kfree(writebuf);
    kfree(readbuf);
    put_mtd_device(mtd);
    if (err)
        printk(PRINT_PREF "error %d occurred\n", err);
    printk(KERN_INFO "=================================================\n");
    return err;
}
Exemplo n.º 23
0
static int verify_eraseblock(int ebnum)
{
    int i;
    struct mtd_oob_ops ops;
    int err = 0;
    loff_t addr = ebnum * mtd->erasesize;

    for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) {
        set_random_data(writebuf, use_len);
        ops.mode      = MTD_OPS_AUTO_OOB;
        ops.len       = 0;
        ops.retlen    = 0;
        ops.ooblen    = use_len;
        ops.oobretlen = 0;
        ops.ooboffs   = use_offset;
        ops.datbuf    = NULL;
        ops.oobbuf    = readbuf;
        err = mtd_read_oob(mtd, addr, &ops);
        if (err || ops.oobretlen != use_len) {
            printk(PRINT_PREF "error: readoob failed at %#llx\n",
                   (long long)addr);
            errcnt += 1;
            return err ? err : -1;
        }
        if (memcmp(readbuf, writebuf, use_len)) {
            printk(PRINT_PREF "error: verify failed at %#llx\n",
                   (long long)addr);
            errcnt += 1;
            if (errcnt > 1000) {
                printk(PRINT_PREF "error: too many errors\n");
                return -1;
            }
        }
        if (use_offset != 0 || use_len < mtd->ecclayout->oobavail) {
            int k;

            ops.mode      = MTD_OPS_AUTO_OOB;
            ops.len       = 0;
            ops.retlen    = 0;
            ops.ooblen    = mtd->ecclayout->oobavail;
            ops.oobretlen = 0;
            ops.ooboffs   = 0;
            ops.datbuf    = NULL;
            ops.oobbuf    = readbuf;
            err = mtd_read_oob(mtd, addr, &ops);
            if (err || ops.oobretlen != mtd->ecclayout->oobavail) {
                printk(PRINT_PREF "error: readoob failed at "
                       "%#llx\n", (long long)addr);
                errcnt += 1;
                return err ? err : -1;
            }
            if (memcmp(readbuf + use_offset, writebuf, use_len)) {
                printk(PRINT_PREF "error: verify failed at "
                       "%#llx\n", (long long)addr);
                errcnt += 1;
                if (errcnt > 1000) {
                    printk(PRINT_PREF "error: too many "
                           "errors\n");
                    return -1;
                }
            }
            for (k = 0; k < use_offset; ++k)
                if (readbuf[k] != 0xff) {
                    printk(PRINT_PREF "error: verify 0xff "
                           "failed at %#llx\n",
                           (long long)addr);
                    errcnt += 1;
                    if (errcnt > 1000) {
                        printk(PRINT_PREF "error: too "
                               "many errors\n");
                        return -1;
                    }
                }
            for (k = use_offset + use_len;
                    k < mtd->ecclayout->oobavail; ++k)
                if (readbuf[k] != 0xff) {
                    printk(PRINT_PREF "error: verify 0xff "
                           "failed at %#llx\n",
                           (long long)addr);
                    errcnt += 1;
                    if (errcnt > 1000) {
                        printk(PRINT_PREF "error: too "
                               "many errors\n");
                        return -1;
                    }
                }
        }
        if (vary_offset)
            do_vary_offset();
    }
    return err;
}