예제 #1
0
static int verify_eraseblock(int ebnum)
{
	size_t read;
	int err = 0;
	loff_t addr = ebnum * mtd->erasesize;

	prandom_bytes_state(&rnd_state, writebuf, subpgsize);
	clear_data(readbuf, subpgsize);
	err = mtd_read(mtd, addr, subpgsize, &read, readbuf);
	if (unlikely(err || read != subpgsize)) {
		if (mtd_is_bitflip(err) && read == subpgsize) {
			pr_info("ECC correction at %#llx\n",
			       (long long)addr);
			err = 0;
		} else {
			pr_err("error: read failed at %#llx\n",
			       (long long)addr);
			return err ? err : -1;
		}
	}
	if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
		pr_err("error: verify failed at %#llx\n",
		       (long long)addr);
		pr_info("------------- written----------------\n");
		print_subpage(writebuf);
		pr_info("------------- read ------------------\n");
		print_subpage(readbuf);
		pr_info("-------------------------------------\n");
		errcnt += 1;
	}

	addr += subpgsize;

	prandom_bytes_state(&rnd_state, writebuf, subpgsize);
	clear_data(readbuf, subpgsize);
	err = mtd_read(mtd, addr, subpgsize, &read, readbuf);
	if (unlikely(err || read != subpgsize)) {
		if (mtd_is_bitflip(err) && read == subpgsize) {
			pr_info("ECC correction at %#llx\n",
			       (long long)addr);
			err = 0;
		} else {
			pr_err("error: read failed at %#llx\n",
			       (long long)addr);
			return err ? err : -1;
		}
	}
	if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
		pr_info("error: verify failed at %#llx\n",
		       (long long)addr);
		pr_info("------------- written----------------\n");
		print_subpage(writebuf);
		pr_info("------------- read ------------------\n");
		print_subpage(readbuf);
		pr_info("-------------------------------------\n");
		errcnt += 1;
	}

	return err;
}
예제 #2
0
static int verify_eraseblock2(int ebnum)
{
	size_t read;
	int err = 0, k;
	loff_t addr = ebnum * mtd->erasesize;

	for (k = 1; k < 33; ++k) {
		if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize)
			break;
		prandom_bytes_state(&rnd_state, writebuf, subpgsize * k);
		clear_data(readbuf, subpgsize * k);
		err = mtd_read(mtd, addr, subpgsize * k, &read, readbuf);
		if (unlikely(err || read != subpgsize * k)) {
			if (mtd_is_bitflip(err) && read == subpgsize * k) {
				pr_info("ECC correction at %#llx\n",
				       (long long)addr);
				err = 0;
			} else {
				pr_err("error: read failed at "
				       "%#llx\n", (long long)addr);
				return err ? err : -1;
			}
		}
		if (unlikely(memcmp(readbuf, writebuf, subpgsize * k))) {
			pr_err("error: verify failed at %#llx\n",
			       (long long)addr);
			errcnt += 1;
		}
		addr += subpgsize * k;
	}

	return err;
}
예제 #3
0
static int verify_eraseblock_ff(int ebnum)
{
	uint32_t j;
	size_t read;
	int err = 0;
	loff_t addr = ebnum * mtd->erasesize;

	memset(writebuf, 0xff, subpgsize);
	for (j = 0; j < mtd->erasesize / subpgsize; ++j) {
		clear_data(readbuf, subpgsize);
		err = mtd_read(mtd, addr, subpgsize, &read, readbuf);
		if (unlikely(err || read != subpgsize)) {
			if (mtd_is_bitflip(err) && read == subpgsize) {
				pr_info("ECC correction at %#llx\n",
				       (long long)addr);
				err = 0;
			} else {
				pr_err("error: read failed at "
				       "%#llx\n", (long long)addr);
				return err ? err : -1;
			}
		}
		if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
			pr_err("error: verify 0xff failed at "
			       "%#llx\n", (long long)addr);
			errcnt += 1;
		}
		addr += subpgsize;
	}

	return err;
}
static int read_eraseblock_by_page(int ebnum)
{
	size_t read;
	int i, err = 0;
	loff_t addr = ebnum * mtd->erasesize;
	void *buf = iobuf;

	for (i = 0; i < pgcnt; i++) {
		err = mtd_read(mtd, addr, pgsize, &read, buf);
		/* Ignore corrected ECC errors */
		if (mtd_is_bitflip(err))
			err = 0;
		if (err || read != pgsize) {
			printk(PRINT_PREF "error: read failed at %#llx\n",
			       addr);
			if (!err)
				err = -EINVAL;
			break;
		}
		addr += pgsize;
		buf += pgsize;
	}

	return err;
}
예제 #5
0
static int do_read(void)
{
	size_t read;
	int eb = rand_eb();
	int offs = rand_offs();
	int len = rand_len(offs), err;
	loff_t addr;

	if (bbt[eb + 1]) {
		if (offs >= mtd->erasesize)
			offs -= mtd->erasesize;
		if (offs + len > mtd->erasesize)
			len = mtd->erasesize - offs;
	}
	addr = eb * mtd->erasesize + offs;
	err = mtd_read(mtd, addr, len, &read, readbuf);
	if (mtd_is_bitflip(err))
		err = 0;
	if (unlikely(err || read != len)) {
		pr_err("error: read failed at 0x%llx\n",
		       (long long)addr);
		if (!err)
			err = -EINVAL;
		return err;
	}
	return 0;
}
static int erasetest(void)
{
	size_t read, written;
	int err = 0, i, ebnum, ok = 1;
	loff_t addr0;

	printk(PRINT_PREF "erasetest\n");

	ebnum = 0;
	addr0 = 0;
	for (i = 0; i < ebcnt && bbt[i]; ++i) {
		addr0 += mtd->erasesize;
		ebnum += 1;
	}

	printk(PRINT_PREF "erasing block %d\n", ebnum);
	err = erase_eraseblock(ebnum);
	if (err)
		return err;

	printk(PRINT_PREF "writing 1st page of block %d\n", ebnum);
	set_random_data(writebuf, pgsize);
	err = mtd_write(mtd, addr0, pgsize, &written, writebuf);
	if (err || written != pgsize) {
		printk(PRINT_PREF "error: write failed at %#llx\n",
		       (long long)addr0);
		return err ? err : -1;
	}

	printk(PRINT_PREF "erasing block %d\n", ebnum);
	err = erase_eraseblock(ebnum);
	if (err)
		return err;

	printk(PRINT_PREF "reading 1st page of block %d\n", ebnum);
	err = mtd_read(mtd, addr0, pgsize, &read, twopages);
	if (mtd_is_bitflip(err))
		err = 0;
	if (err || read != pgsize) {
		printk(PRINT_PREF "error: read failed at %#llx\n",
		       (long long)addr0);
		return err ? err : -1;
	}

	printk(PRINT_PREF "verifying 1st page of block %d is all 0xff\n",
	       ebnum);
	for (i = 0; i < pgsize; ++i)
		if (twopages[i] != 0xff) {
			printk(PRINT_PREF "verifying all 0xff failed at %d\n",
			       i);
			errcnt += 1;
			ok = 0;
			break;
		}

	if (ok && !err)
		printk(PRINT_PREF "erasetest ok\n");

	return err;
}
예제 #7
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 = subdev->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;
}
예제 #8
0
파일: mtdconcat.c 프로젝트: Noltari/u-boot
static int
concat_read(struct mtd_info *mtd, loff_t from, size_t len,
	    size_t * retlen, u_char * buf)
{
	struct mtd_concat *concat = CONCAT(mtd);
	int ret = 0, err;
	int i;

#ifdef __UBOOT__
	*retlen = 0;
#endif

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

		if (from >= subdev->size) {
			/* Not destined for this subdev */
			size = 0;
			from -= subdev->size;
			continue;
		}
		if (from + len > subdev->size)
			/* First part goes into this subdev */
			size = subdev->size - from;
		else
			/* Entire transaction goes into this subdev */
			size = len;

		err = mtd_read(subdev, from, size, &retsize, buf);

		/* 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;
		}

		*retlen += retsize;
		len -= size;
		if (len == 0)
			return ret;

		buf += size;
		from = 0;
	}
	return -EINVAL;
}
예제 #9
0
파일: io.c 프로젝트: CDACBANG/u-boot-wingz
/**
 * self_check_write - make sure write succeeded.
 * @ubi: UBI device description object
 * @buf: buffer with data which were written
 * @pnum: physical eraseblock number the data were written to
 * @offset: offset within the physical eraseblock the data were written to
 * @len: how many bytes were written
 *
 * This functions reads data which were recently written and compares it with
 * the original data buffer - the data have to match. Returns zero if the data
 * match and a negative error code if not or in case of failure.
 */
static int self_check_write(struct ubi_device *ubi, const void *buf, int pnum,
			    int offset, int len)
{
	int err, i;
	size_t read;
	void *buf1;
	loff_t addr = (loff_t)pnum * ubi->peb_size + offset;

	if (!ubi_dbg_chk_io(ubi))
		return 0;

	buf1 = __vmalloc(len, GFP_NOFS, PAGE_KERNEL);
	if (!buf1) {
		ubi_err("cannot allocate memory to check writes");
		return 0;
	}

	err = mtd_read(ubi->mtd, addr, len, &read, buf1);
	if (err && !mtd_is_bitflip(err))
		goto out_free;

	for (i = 0; i < len; i++) {
		uint8_t c = ((uint8_t *)buf)[i];
		uint8_t c1 = ((uint8_t *)buf1)[i];
#if !defined(CONFIG_UBI_SILENCE_MSG)
		int dump_len = max_t(int, 128, len - i);
#endif

		if (c == c1)
			continue;

		ubi_err("self-check failed for PEB %d:%d, len %d",
			pnum, offset, len);
		ubi_msg("data differ at position %d", i);
		ubi_msg("hex dump of the original buffer from %d to %d",
			i, i + dump_len);
		print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
			       buf + i, dump_len, 1);
		ubi_msg("hex dump of the read buffer from %d to %d",
			i, i + dump_len);
		print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
			       buf1 + i, dump_len, 1);
		dump_stack();
		err = -EINVAL;
		goto out_free;
	}

	vfree(buf1);
	return 0;

out_free:
	vfree(buf1);
	return err;
}
예제 #10
0
파일: mtdoops.c 프로젝트: matsufan/linux
static void find_next_position(struct mtdoops_context *cxt)
{
	struct mtd_info *mtd = cxt->mtd;
	int ret, page, maxpos = 0;
	u32 count[2], maxcount = 0xffffffff;
	size_t retlen;

	for (page = 0; page < cxt->oops_pages; page++) {
		if (mtd_can_have_bb(mtd) &&
		    mtd_block_isbad(mtd, page * record_size))
			continue;
		/* Assume the page is used */
		mark_page_used(cxt, page);
		ret = mtd_read(mtd, page * record_size, MTDOOPS_HEADER_SIZE,
			       &retlen, (u_char *)&count[0]);
		if (retlen != MTDOOPS_HEADER_SIZE ||
				(ret < 0 && !mtd_is_bitflip(ret))) {
			printk(KERN_ERR "mtdoops: read failure at %ld (%td of %d read), err %d\n",
			       page * record_size, retlen,
			       MTDOOPS_HEADER_SIZE, ret);
			continue;
		}

		if (count[0] == 0xffffffff && count[1] == 0xffffffff)
			mark_page_unused(cxt, page);
		if (count[0] == 0xffffffff)
			continue;
		if (maxcount == 0xffffffff) {
			maxcount = count[0];
			maxpos = page;
		} else if (count[0] < 0x40000000 && maxcount > 0xc0000000) {
			maxcount = count[0];
			maxpos = page;
		} else if (count[0] > maxcount && count[0] < 0xc0000000) {
			maxcount = count[0];
			maxpos = page;
		} else if (count[0] > maxcount && count[0] > 0xc0000000
					&& maxcount > 0x80000000) {
			maxcount = count[0];
			maxpos = page;
		}
	}
	if (maxcount == 0xffffffff) {
		cxt->nextpage = 0;
		cxt->nextcount = 1;
		schedule_work(&cxt->work_erase);
		return;
	}

	cxt->nextpage = maxpos;
	cxt->nextcount = maxcount;

	mtdoops_inc_counter(cxt);
}
예제 #11
0
/*
 * Check that the contents of eraseblock number @enbum is equivalent to the
 * @buf buffer.
 */
static inline int check_eraseblock(int ebnum, unsigned char *buf)
{
	int err, retries = 0;
	size_t read;
	loff_t addr = ebnum * mtd->erasesize;
	size_t len = mtd->erasesize;

	if (pgcnt) {
		addr = (ebnum + 1) * mtd->erasesize - pgcnt * pgsize;
		len = pgcnt * pgsize;
	}

retry:
	err = mtd_read(mtd, addr, len, &read, check_buf);
	if (mtd_is_bitflip(err))
		pr_err("single bit flip occurred at EB %d "
		       "MTD reported that it was fixed.\n", ebnum);
	else if (err) {
		pr_err("error %d while reading EB %d, "
		       "read %zd\n", err, ebnum, read);
		return err;
	}

	if (read != len) {
		pr_err("failed to read %zd bytes from EB %d, "
		       "read only %zd, but no error reported\n",
		       len, ebnum, read);
		return -EIO;
	}

	if (memcmp(buf, check_buf, len)) {
		pr_err("read wrong data from EB %d\n", ebnum);
		report_corrupt(check_buf, buf);

		if (retries++ < RETRIES) {
			/* Try read again */
			yield();
			pr_info("re-try reading data from EB %d\n",
			       ebnum);
			goto retry;
		} else {
			pr_info("retried %d times, still errors, "
			       "give-up\n", RETRIES);
			return -EINVAL;
		}
	}

	if (retries != 0)
		pr_info("only attempt number %d was OK (!!!)\n",
		       retries);

	return 0;
}
예제 #12
0
static int read_eraseblock_by_page(int ebnum)
{
	size_t read = 0;
	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;
}
static int read_eraseblock_by_2pages(int ebnum)
{
	size_t read, sz = pgsize * 2;
	int i, n = pgcnt / 2, err = 0;
	loff_t addr = ebnum * mtd->erasesize;
	void *buf = iobuf;

	for (i = 0; i < n; i++) {
		err = mtd_read(mtd, addr, sz, &read, buf);
		/* Ignore corrected ECC errors */
		if (mtd_is_bitflip(err))
			err = 0;
		if (err || read != sz) {
			printk(PRINT_PREF "error: read failed at %#llx\n",
			       addr);
			if (!err)
				err = -EINVAL;
			return err;
		}
		addr += sz;
		buf += sz;
	}
	if (pgcnt % 2) {
		err = mtd_read(mtd, addr, pgsize, &read, buf);
		/* Ignore corrected ECC errors */
		if (mtd_is_bitflip(err))
			err = 0;
		if (err || read != pgsize) {
			printk(PRINT_PREF "error: read failed at %#llx\n",
			       addr);
			if (!err)
				err = -EINVAL;
		}
	}

	return err;
}
예제 #14
0
int mtdtest_read(struct mtd_info *mtd, loff_t addr, size_t size, void *buf)
{
	size_t read;
	int err;

	err = mtd_read(mtd, addr, size, &read, buf);
	/* Ignore corrected ECC errors */
	if (mtd_is_bitflip(err))
		err = 0;
	if (!err && read != size)
		err = -EIO;
	if (err)
		pr_err("error: read failed at %#llx\n", addr);

	return err;
}
예제 #15
0
파일: mtdpart.c 프로젝트: DFE/u-boot
static int part_read(struct mtd_info *mtd, loff_t from, size_t len,
		size_t *retlen, u_char *buf)
{
	struct mtd_part *part = PART(mtd);
	struct mtd_ecc_stats stats;
	int res;

	stats = part->master->ecc_stats;
	res = mtd_read(part->master, from + part->offset, len, retlen, buf);
	if (unlikely(res)) {
		if (mtd_is_bitflip(res))
			mtd->ecc_stats.corrected += part->master->ecc_stats.corrected - stats.corrected;
		if (mtd_is_eccerr(res))
			mtd->ecc_stats.failed += part->master->ecc_stats.failed - stats.failed;
	}
	return res;
}
static int read_eraseblock(int ebnum)
{
	size_t read;
	int err = 0;
	loff_t addr = ebnum * mtd->erasesize;

	err = mtd_read(mtd, addr, mtd->erasesize, &read, iobuf);
	/* Ignore corrected ECC errors */
	if (mtd_is_bitflip(err))
		err = 0;
	if (err || read != mtd->erasesize) {
		printk(PRINT_PREF "error: read failed at %#llx\n", addr);
		if (!err)
			err = -EINVAL;
	}

	return err;
}
예제 #17
0
파일: io.c 프로젝트: 383530895/linux
/**
 * ubi_self_check_all_ff - check that a region of flash is empty.
 * @ubi: UBI device description object
 * @pnum: the physical eraseblock number to check
 * @offset: the starting offset within the physical eraseblock to check
 * @len: the length of the region to check
 *
 * This function returns zero if only 0xFF bytes are present at offset
 * @offset of the physical eraseblock @pnum, and a negative error code if not
 * or if an error occurred.
 */
int ubi_self_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len)
{
	size_t read;
	int err;
	void *buf;
	loff_t addr = (loff_t)pnum * ubi->peb_size + offset;

	if (!ubi_dbg_chk_io(ubi))
		return 0;

	buf = __vmalloc(len, GFP_NOFS, PAGE_KERNEL);
	if (!buf) {
		ubi_err(ubi, "cannot allocate memory to check for 0xFFs");
		return 0;
	}

	err = mtd_read(ubi->mtd, addr, len, &read, buf);
	if (err && !mtd_is_bitflip(err)) {
		ubi_err(ubi, "err %d while reading %d bytes from PEB %d:%d, read %zd bytes",
			err, len, pnum, offset, read);
		goto error;
	}

	err = ubi_check_pattern(buf, 0xFF, len);
	if (err == 0) {
		ubi_err(ubi, "flash region at PEB %d:%d, length %d does not contain all 0xFF bytes",
			pnum, offset, len);
		goto fail;
	}

	vfree(buf);
	return 0;

fail:
	ubi_err(ubi, "self-check failed for PEB %d", pnum);
	ubi_msg(ubi, "hex dump of the %d-%d region",
		 offset, offset + len);
	print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf, len, 1);
	err = -EINVAL;
error:
	dump_stack();
	vfree(buf);
	return err;
}
예제 #18
0
파일: mtdpart.c 프로젝트: 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;
}
예제 #19
0
static const char *bcm47xxpart_trx_data_part_name(struct mtd_info *master,
						  size_t offset)
{
	uint32_t buf;
	size_t bytes_read;
	int err;

	err  = mtd_read(master, offset, sizeof(buf), &bytes_read,
			(uint8_t *)&buf);
	if (err && !mtd_is_bitflip(err)) {
		pr_err("mtd_read error while parsing (offset: 0x%X): %d\n",
			offset, err);
		goto out_default;
	}

	if (buf == UBI_EC_MAGIC)
		return "ubi";

out_default:
	return "rootfs";
}
예제 #20
0
static int bitfliptest_do_read(void)
{
	int err = 0;
	size_t read = 0;
	loff_t addr = 0;
	unsigned int corrected_num = 0;
	unsigned int eb = bitfliptest_rand_eb();
	unsigned int offs = bitfliptest_rand_offs();
	unsigned int len = bitfliptest_rand_len(offs);
	struct mtd_ecc_stats stats= {0};

	if (bbt[eb + 1]) {
		if (offs >= mtd->erasesize)
			offs -= mtd->erasesize;
		if (offs + len > mtd->erasesize)
			len = mtd->erasesize - offs;
	}
	addr = eb * mtd->erasesize + offs;

//	pr_info("read, addr: 0x%.8x len: %d\n", (unsigned int)addr, len);
	stats = mtd_part->master->ecc_stats;
	err = mtd_read(mtd, addr, len, &read, readbuf);
	if (mtd_is_bitflip(err))
		err = 0;
	if (unlikely(err || read != len)) {
		pr_err("error: read failed at 0x%llx, err:%d len: %dread:%d\n",
		       (long long)addr, err, len, read);
		if (!err)
			err = -EINVAL;
		return err;
	}
	corrected_num = mtd_part->master->ecc_stats.corrected - stats.corrected;
	if(corrected_num != 0) {
		errcnt += corrected_num;
		pr_info("When we read addr:0x%.8x:0x%.8x, we found %d(%d) bit-flip!\n", (unsigned int)addr, len, corrected_num, errcnt);
	}
	rdpgcnt += len/mtd->writesize;
	rdcnt ++;
	return 0;
}
예제 #21
0
static int sharpsl_nand_read_laddr(struct mtd_info *mtd,
				   loff_t from,
				   size_t len,
				   void *buf,
				   struct sharpsl_ftl *ftl)
{
	unsigned int log_num, final_log_num;
	unsigned int block_num;
	loff_t block_adr;
	loff_t block_ofs;
	size_t retlen;
	int err;

	log_num = mtd_div_by_eb((u32)from, mtd);
	final_log_num = mtd_div_by_eb(((u32)from + len - 1), mtd);

	if (len <= 0 || log_num >= ftl->logmax || final_log_num > log_num)
		return -EINVAL;

	block_num = ftl->log2phy[log_num];
	block_adr = block_num * mtd->erasesize;
	block_ofs = mtd_mod_by_eb((u32)from, mtd);

	err = mtd_read(mtd, block_adr + block_ofs, len, &retlen, buf);
	/* Ignore corrected ECC errors */
	if (mtd_is_bitflip(err))
		err = 0;

	if (!err && retlen != len)
		err = -EIO;

	if (err)
		pr_err("sharpslpart: error, read failed at %#llx\n",
		       block_adr + block_ofs);

	return err;
}
static int verify_eraseblock(int ebnum)
{
	uint32_t j;
	size_t read;
	int err = 0, i;
	loff_t addr0, addrn;
	loff_t addr = ebnum * mtd->erasesize;

	addr0 = 0;
	for (i = 0; i < ebcnt && bbt[i]; ++i)
		addr0 += mtd->erasesize;

	addrn = mtd->size;
	for (i = 0; i < ebcnt && bbt[ebcnt - i - 1]; ++i)
		addrn -= mtd->erasesize;

	set_random_data(writebuf, mtd->erasesize);
	for (j = 0; j < pgcnt - 1; ++j, addr += pgsize) {
		/* Do a read to set the internal dataRAMs to different data */
		err = mtd_read(mtd, addr0, bufsize, &read, twopages);
		if (mtd_is_bitflip(err))
			err = 0;
		if (err || read != bufsize) {
			printk(PRINT_PREF "error: read failed at %#llx\n",
			       (long long)addr0);
			return err;
		}
		err = mtd_read(mtd, addrn - bufsize, bufsize, &read, twopages);
		if (mtd_is_bitflip(err))
			err = 0;
		if (err || read != bufsize) {
			printk(PRINT_PREF "error: read failed at %#llx\n",
			       (long long)(addrn - bufsize));
			return err;
		}
		memset(twopages, 0, bufsize);
		err = mtd_read(mtd, addr, bufsize, &read, twopages);
		if (mtd_is_bitflip(err))
			err = 0;
		if (err || read != bufsize) {
			printk(PRINT_PREF "error: read failed at %#llx\n",
			       (long long)addr);
			break;
		}
		if (memcmp(twopages, writebuf + (j * pgsize), bufsize)) {
			printk(PRINT_PREF "error: verify failed at %#llx\n",
			       (long long)addr);
			errcnt += 1;
		}
	}
	/* Check boundary between eraseblocks */
	if (addr <= addrn - pgsize - pgsize && !bbt[ebnum + 1]) {
		unsigned long oldnext = next;
		/* Do a read to set the internal dataRAMs to different data */
		err = mtd_read(mtd, addr0, bufsize, &read, twopages);
		if (mtd_is_bitflip(err))
			err = 0;
		if (err || read != bufsize) {
			printk(PRINT_PREF "error: read failed at %#llx\n",
			       (long long)addr0);
			return err;
		}
		err = mtd_read(mtd, addrn - bufsize, bufsize, &read, twopages);
		if (mtd_is_bitflip(err))
			err = 0;
		if (err || read != bufsize) {
			printk(PRINT_PREF "error: read failed at %#llx\n",
			       (long long)(addrn - bufsize));
			return err;
		}
		memset(twopages, 0, bufsize);
		err = mtd_read(mtd, addr, bufsize, &read, twopages);
		if (mtd_is_bitflip(err))
			err = 0;
		if (err || read != bufsize) {
			printk(PRINT_PREF "error: read failed at %#llx\n",
			       (long long)addr);
			return err;
		}
		memcpy(boundary, writebuf + mtd->erasesize - pgsize, pgsize);
		set_random_data(boundary + pgsize, pgsize);
		if (memcmp(twopages, boundary, bufsize)) {
			printk(PRINT_PREF "error: verify failed at %#llx\n",
			       (long long)addr);
			errcnt += 1;
		}
		next = oldnext;
	}
	return err;
}
예제 #23
0
파일: io.c 프로젝트: 383530895/linux
/**
 * ubi_io_read - read data from a physical eraseblock.
 * @ubi: UBI device description object
 * @buf: buffer where to store the read data
 * @pnum: physical eraseblock number to read from
 * @offset: offset within the physical eraseblock from where to read
 * @len: how many bytes to read
 *
 * This function reads data from offset @offset of physical eraseblock @pnum
 * and stores the read data in the @buf buffer. The following return codes are
 * possible:
 *
 * o %0 if all the requested data were successfully read;
 * o %UBI_IO_BITFLIPS if all the requested data were successfully read, but
 *   correctable bit-flips were detected; this is harmless but may indicate
 *   that this eraseblock may become bad soon (but do not have to);
 * o %-EBADMSG if the MTD subsystem reported about data integrity problems, for
 *   example it can be an ECC error in case of NAND; this most probably means
 *   that the data is corrupted;
 * o %-EIO if some I/O error occurred;
 * o other negative error codes in case of other errors.
 */
int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset,
		int len)
{
	int err, retries = 0;
	size_t read;
	loff_t addr;

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

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

	err = self_check_not_bad(ubi, pnum);
	if (err)
		return err;

	/*
	 * Deliberately corrupt the buffer to improve robustness. Indeed, if we
	 * do not do this, the following may happen:
	 * 1. The buffer contains data from previous operation, e.g., read from
	 *    another PEB previously. The data looks like expected, e.g., if we
	 *    just do not read anything and return - the caller would not
	 *    notice this. E.g., if we are reading a VID header, the buffer may
	 *    contain a valid VID header from another PEB.
	 * 2. The driver is buggy and returns us success or -EBADMSG or
	 *    -EUCLEAN, but it does not actually put any data to the buffer.
	 *
	 * This may confuse UBI or upper layers - they may think the buffer
	 * contains valid data while in fact it is just old data. This is
	 * especially possible because UBI (and UBIFS) relies on CRC, and
	 * treats data as correct even in case of ECC errors if the CRC is
	 * correct.
	 *
	 * Try to prevent this situation by changing the first byte of the
	 * buffer.
	 */
	*((uint8_t *)buf) ^= 0xFF;

	addr = (loff_t)pnum * ubi->peb_size + offset;
retry:
	err = mtd_read(ubi->mtd, addr, len, &read, buf);
	if (err) {
		const char *errstr = mtd_is_eccerr(err) ? " (ECC error)" : "";

		if (mtd_is_bitflip(err)) {
			/*
			 * -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(ubi, "fixable bit-flip detected at PEB %d",
				pnum);
			ubi_assert(len == read);
			return UBI_IO_BITFLIPS;
		}

		if (retries++ < UBI_IO_RETRIES) {
			ubi_warn(ubi, "error %d%s while reading %d bytes from PEB %d:%d, read only %zd bytes, retry",
				 err, errstr, len, pnum, offset, read);
			yield();
			goto retry;
		}

		ubi_err(ubi, "error %d%s while reading %d bytes from PEB %d:%d, read %zd bytes",
			err, errstr, len, pnum, offset, read);
		dump_stack();

		/*
		 * The driver should never return -EBADMSG if it failed to read
		 * all the requested data. But some buggy drivers might do
		 * this, so we change it to -EIO.
		 */
		if (read != len && mtd_is_eccerr(err)) {
			ubi_assert(0);
			err = -EIO;
		}
	} else {
		ubi_assert(len == read);

		if (ubi_dbg_is_bitflip(ubi)) {
			dbg_gen("bit-flip (emulated)");
			err = UBI_IO_BITFLIPS;
		}
	}

	return err;
}
예제 #24
0
static int inftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,
			   char *buffer)
{
	struct INFTLrecord *inftl = (void *)mbd;
	unsigned int thisEUN = inftl->VUtable[block / (inftl->EraseSize / SECTORSIZE)];
	unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1);
	struct mtd_info *mtd = inftl->mbd.mtd;
	unsigned int status;
	int silly = MAX_LOOPS;
	struct inftl_bci bci;
	size_t retlen;

	pr_debug("INFTL: inftl_readblock(inftl=%p,block=%ld,"
		"buffer=%p)\n", inftl, block, buffer);

	while (thisEUN < inftl->nb_blocks) {
		if (inftl_read_oob(mtd, (thisEUN * inftl->EraseSize) +
				  blockofs, 8, &retlen, (char *)&bci) < 0)
			status = SECTOR_IGNORE;
		else
			status = bci.Status | bci.Status1;

		switch (status) {
		case SECTOR_DELETED:
			thisEUN = BLOCK_NIL;
			goto foundit;
		case SECTOR_USED:
			goto foundit;
		case SECTOR_FREE:
		case SECTOR_IGNORE:
			break;
		default:
			printk(KERN_WARNING "INFTL: unknown status for "
				"block %ld in EUN %d: 0x%04x\n",
				block, thisEUN, status);
			break;
		}

		if (!silly--) {
			printk(KERN_WARNING "INFTL: infinite loop in "
				"Virtual Unit Chain 0x%lx\n",
				block / (inftl->EraseSize / SECTORSIZE));
			return 1;
		}

		thisEUN = inftl->PUtable[thisEUN];
	}

foundit:
	if (thisEUN == BLOCK_NIL) {
		/* The requested block is not on the media, return all 0x00 */
		memset(buffer, 0, SECTORSIZE);
	} else {
		size_t retlen;
		loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs;
		int ret = mtd->read(mtd, ptr, SECTORSIZE, &retlen, buffer);

		/* Handle corrected bit flips gracefully */
		if (ret < 0 && !mtd_is_bitflip(ret))
			return -EIO;
	}
	return 0;
}
예제 #25
0
static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned pendingblock)
{
	u16 BlockMap[MAX_SECTORS_PER_UNIT];
	unsigned char BlockDeleted[MAX_SECTORS_PER_UNIT];
	unsigned int thisEUN, prevEUN, status;
	struct mtd_info *mtd = inftl->mbd.mtd;
	int block, silly;
	unsigned int targetEUN;
	struct inftl_oob oob;
	size_t retlen;

	pr_debug("INFTL: INFTL_foldchain(inftl=%p,thisVUC=%d,pending=%d)\n",
			inftl, thisVUC, pendingblock);

	memset(BlockMap, 0xff, sizeof(BlockMap));
	memset(BlockDeleted, 0, sizeof(BlockDeleted));

	thisEUN = targetEUN = inftl->VUtable[thisVUC];

	if (thisEUN == BLOCK_NIL) {
		printk(KERN_WARNING "INFTL: trying to fold non-existent "
		       "Virtual Unit Chain %d!\n", thisVUC);
		return BLOCK_NIL;
	}

	/*
	 * Scan to find the Erase Unit which holds the actual data for each
	 * 512-byte block within the Chain.
	 */
	silly = MAX_LOOPS;
	while (thisEUN < inftl->nb_blocks) {
		for (block = 0; block < inftl->EraseSize/SECTORSIZE; block ++) {
			if ((BlockMap[block] != BLOCK_NIL) ||
			    BlockDeleted[block])
				continue;

			if (inftl_read_oob(mtd, (thisEUN * inftl->EraseSize)
					   + (block * SECTORSIZE), 16, &retlen,
					   (char *)&oob) < 0)
				status = SECTOR_IGNORE;
			else
				status = oob.b.Status | oob.b.Status1;

			switch(status) {
			case SECTOR_FREE:
			case SECTOR_IGNORE:
				break;
			case SECTOR_USED:
				BlockMap[block] = thisEUN;
				continue;
			case SECTOR_DELETED:
				BlockDeleted[block] = 1;
				continue;
			default:
				printk(KERN_WARNING "INFTL: unknown status "
					"for block %d in EUN %d: %x\n",
					block, thisEUN, status);
				break;
			}
		}

		if (!silly--) {
			printk(KERN_WARNING "INFTL: infinite loop in Virtual "
				"Unit Chain 0x%x\n", thisVUC);
			return BLOCK_NIL;
		}

		thisEUN = inftl->PUtable[thisEUN];
	}

	/*
	 * OK. We now know the location of every block in the Virtual Unit
	 * Chain, and the Erase Unit into which we are supposed to be copying.
	 * Go for it.
	 */
	pr_debug("INFTL: folding chain %d into unit %d\n", thisVUC, targetEUN);

	for (block = 0; block < inftl->EraseSize/SECTORSIZE ; block++) {
		unsigned char movebuf[SECTORSIZE];
		int ret;

		/*
		 * If it's in the target EUN already, or if it's pending write,
		 * do nothing.
		 */
		if (BlockMap[block] == targetEUN || (pendingblock ==
		    (thisVUC * (inftl->EraseSize / SECTORSIZE) + block))) {
			continue;
		}

		/*
		 * Copy only in non free block (free blocks can only
                 * happen in case of media errors or deleted blocks).
		 */
		if (BlockMap[block] == BLOCK_NIL)
			continue;

		ret = mtd->read(mtd, (inftl->EraseSize * BlockMap[block]) +
				(block * SECTORSIZE), SECTORSIZE, &retlen,
				movebuf);
		if (ret < 0 && !mtd_is_bitflip(ret)) {
			ret = mtd->read(mtd,
					(inftl->EraseSize * BlockMap[block]) +
					(block * SECTORSIZE), SECTORSIZE,
					&retlen, movebuf);
			if (ret != -EIO)
				pr_debug("INFTL: error went away on retry?\n");
		}
		memset(&oob, 0xff, sizeof(struct inftl_oob));
		oob.b.Status = oob.b.Status1 = SECTOR_USED;

		inftl_write(inftl->mbd.mtd, (inftl->EraseSize * targetEUN) +
			    (block * SECTORSIZE), SECTORSIZE, &retlen,
			    movebuf, (char *)&oob);
	}

	/*
	 * Newest unit in chain now contains data from _all_ older units.
	 * So go through and erase each unit in chain, oldest first. (This
	 * is important, by doing oldest first if we crash/reboot then it
	 * it is relatively simple to clean up the mess).
	 */
	pr_debug("INFTL: want to erase virtual chain %d\n", thisVUC);

	for (;;) {
		/* Find oldest unit in chain. */
		thisEUN = inftl->VUtable[thisVUC];
		prevEUN = BLOCK_NIL;
		while (inftl->PUtable[thisEUN] != BLOCK_NIL) {
			prevEUN = thisEUN;
			thisEUN = inftl->PUtable[thisEUN];
		}

		/* Check if we are all done */
		if (thisEUN == targetEUN)
			break;

		/* Unlink the last block from the chain. */
		inftl->PUtable[prevEUN] = BLOCK_NIL;

		/* Now try to erase it. */
		if (INFTL_formatblock(inftl, thisEUN) < 0) {
			/*
			 * Could not erase : mark block as reserved.
			 */
			inftl->PUtable[thisEUN] = BLOCK_RESERVED;
		} else {
			/* Correctly erased : mark it as free */
			inftl->PUtable[thisEUN] = BLOCK_FREE;
			inftl->numfreeEUNs++;
		}
	}

	return targetEUN;
}
예제 #26
0
static int bcm47xxpart_parse(struct mtd_info *master,
			     const struct mtd_partition **pparts,
			     struct mtd_part_parser_data *data)
{
	struct mtd_partition *parts;
	uint8_t i, curr_part = 0;
	uint32_t *buf;
	size_t bytes_read;
	uint32_t offset;
	uint32_t blocksize = master->erasesize;
	int trx_parts[2]; /* Array with indexes of TRX partitions */
	int trx_num = 0; /* Number of found TRX partitions */
	int possible_nvram_sizes[] = { 0x8000, 0xF000, 0x10000, };
	int err;

	/*
	 * Some really old flashes (like AT45DB*) had smaller erasesize-s, but
	 * partitions were aligned to at least 0x1000 anyway.
	 */
	if (blocksize < 0x1000)
		blocksize = 0x1000;

	/* Alloc */
	parts = kcalloc(BCM47XXPART_MAX_PARTS, sizeof(struct mtd_partition),
			GFP_KERNEL);
	if (!parts)
		return -ENOMEM;

	buf = kzalloc(BCM47XXPART_BYTES_TO_READ, GFP_KERNEL);
	if (!buf) {
		kfree(parts);
		return -ENOMEM;
	}

	/* Parse block by block looking for magics */
	for (offset = 0; offset <= master->size - blocksize;
	     offset += blocksize) {
		/* Nothing more in higher memory on BCM47XX (MIPS) */
		if (IS_ENABLED(CONFIG_BCM47XX) && offset >= 0x2000000)
			break;

		if (curr_part >= BCM47XXPART_MAX_PARTS) {
			pr_warn("Reached maximum number of partitions, scanning stopped!\n");
			break;
		}

		/* Read beginning of the block */
		err = mtd_read(master, offset, BCM47XXPART_BYTES_TO_READ,
			       &bytes_read, (uint8_t *)buf);
		if (err && !mtd_is_bitflip(err)) {
			pr_err("mtd_read error while parsing (offset: 0x%X): %d\n",
			       offset, err);
			continue;
		}

		/* Magic or small NVRAM at 0x400 */
		if ((buf[0x4e0 / 4] == CFE_MAGIC && buf[0x4e4 / 4] == CFE_MAGIC) ||
		    (buf[0x400 / 4] == NVRAM_HEADER)) {
			bcm47xxpart_add_part(&parts[curr_part++], "boot",
					     offset, MTD_WRITEABLE);
			continue;
		}

		/*
		 * board_data starts with board_id which differs across boards,
		 * but we can use 'MPFR' (hopefully) magic at 0x100
		 */
		if (buf[0x100 / 4] == BOARD_DATA_MAGIC) {
			bcm47xxpart_add_part(&parts[curr_part++], "board_data",
					     offset, MTD_WRITEABLE);
			continue;
		}

		/* Found on Huawei E970 */
		if (buf[0x000 / 4] == FACTORY_MAGIC) {
			bcm47xxpart_add_part(&parts[curr_part++], "factory",
					     offset, MTD_WRITEABLE);
			continue;
		}

		/* POT(TOP) */
		if (buf[0x000 / 4] == POT_MAGIC1 &&
		    (buf[0x004 / 4] & 0xFFFF) == POT_MAGIC2) {
			bcm47xxpart_add_part(&parts[curr_part++], "POT", offset,
					     MTD_WRITEABLE);
			continue;
		}

		/* ML */
		if (buf[0x010 / 4] == ML_MAGIC1 &&
		    buf[0x014 / 4] == ML_MAGIC2) {
			bcm47xxpart_add_part(&parts[curr_part++], "ML", offset,
					     MTD_WRITEABLE);
			continue;
		}

		/* TRX */
		if (buf[0x000 / 4] == TRX_MAGIC) {
			struct trx_header *trx;
			uint32_t last_subpart;
			uint32_t trx_size;

			if (trx_num >= ARRAY_SIZE(trx_parts))
				pr_warn("No enough space to store another TRX found at 0x%X\n",
					offset);
			else
				trx_parts[trx_num++] = curr_part;
			bcm47xxpart_add_part(&parts[curr_part++], "firmware",
					     offset, 0);

			/*
			 * Try to find TRX size. The "length" field isn't fully
			 * reliable as it could be decreased to make CRC32 cover
			 * only part of TRX data. It's commonly used as checksum
			 * can't cover e.g. ever-changing rootfs partition.
			 * Use offsets as helpers for assuming min TRX size.
			 */
			trx = (struct trx_header *)buf;
			last_subpart = max3(trx->offset[0], trx->offset[1],
					    trx->offset[2]);
			trx_size = max(trx->length, last_subpart + blocksize);

			/*
			 * Skip the TRX data. Decrease offset by block size as
			 * the next loop iteration will increase it.
			 */
			offset += roundup(trx_size, blocksize) - blocksize;
			continue;
		}

		/* Squashfs on devices not using TRX */
		if (le32_to_cpu(buf[0x000 / 4]) == SQUASHFS_MAGIC ||
		    buf[0x000 / 4] == SHSQ_MAGIC) {
			bcm47xxpart_add_part(&parts[curr_part++], "rootfs",
					     offset, 0);
			continue;
		}

		/*
		 * New (ARM?) devices may have NVRAM in some middle block. Last
		 * block will be checked later, so skip it.
		 */
		if (offset != master->size - blocksize &&
		    buf[0x000 / 4] == NVRAM_HEADER) {
			bcm47xxpart_add_part(&parts[curr_part++], "nvram",
					     offset, 0);
			continue;
		}

		/* Read middle of the block */
		err = mtd_read(master, offset + 0x8000, 0x4, &bytes_read,
			       (uint8_t *)buf);
		if (err && !mtd_is_bitflip(err)) {
			pr_err("mtd_read error while parsing (offset: 0x%X): %d\n",
			       offset, err);
			continue;
		}

		/* Some devices (ex. WNDR3700v3) don't have a standard 'MPFR' */
		if (buf[0x000 / 4] == BOARD_DATA_MAGIC2) {
			bcm47xxpart_add_part(&parts[curr_part++], "board_data",
					     offset, MTD_WRITEABLE);
			continue;
		}
	}

	/* Look for NVRAM at the end of the last block. */
	for (i = 0; i < ARRAY_SIZE(possible_nvram_sizes); i++) {
		if (curr_part >= BCM47XXPART_MAX_PARTS) {
			pr_warn("Reached maximum number of partitions, scanning stopped!\n");
			break;
		}

		offset = master->size - possible_nvram_sizes[i];
		err = mtd_read(master, offset, 0x4, &bytes_read,
			       (uint8_t *)buf);
		if (err && !mtd_is_bitflip(err)) {
			pr_err("mtd_read error while reading (offset 0x%X): %d\n",
			       offset, err);
			continue;
		}

		/* Standard NVRAM */
		if (buf[0] == NVRAM_HEADER) {
			bcm47xxpart_add_part(&parts[curr_part++], "nvram",
					     master->size - blocksize, 0);
			break;
		}
	}

	kfree(buf);

	/*
	 * Assume that partitions end at the beginning of the one they are
	 * followed by.
	 */
	for (i = 0; i < curr_part; i++) {
		u64 next_part_offset = (i < curr_part - 1) ?
				       parts[i + 1].offset : master->size;

		parts[i].size = next_part_offset - parts[i].offset;
	}

	/* If there was TRX parse it now */
	for (i = 0; i < trx_num; i++) {
		struct mtd_partition *trx = &parts[trx_parts[i]];

		if (i == bcm47xxpart_bootpartition())
			trx->types = trx_types;
		else
			trx->name = "failsafe";
	}

	*pparts = parts;
	return curr_part;
};
예제 #27
0
static int bcm47xxpart_parse(struct mtd_info *master,
			     const struct mtd_partition **pparts,
			     struct mtd_part_parser_data *data)
{
	struct mtd_partition *parts;
	uint8_t i, curr_part = 0;
	uint32_t *buf;
	size_t bytes_read;
	uint32_t offset;
	uint32_t blocksize = master->erasesize;
	struct trx_header *trx;
	int trx_part = -1;
	int last_trx_part = -1;
	int possible_nvram_sizes[] = { 0x8000, 0xF000, 0x10000, };
	int err;

	/*
	 * Some really old flashes (like AT45DB*) had smaller erasesize-s, but
	 * partitions were aligned to at least 0x1000 anyway.
	 */
	if (blocksize < 0x1000)
		blocksize = 0x1000;

	/* Alloc */
	parts = kzalloc(sizeof(struct mtd_partition) * BCM47XXPART_MAX_PARTS,
			GFP_KERNEL);
	if (!parts)
		return -ENOMEM;

	buf = kzalloc(BCM47XXPART_BYTES_TO_READ, GFP_KERNEL);
	if (!buf) {
		kfree(parts);
		return -ENOMEM;
	}

	/* Parse block by block looking for magics */
	for (offset = 0; offset <= master->size - blocksize;
	     offset += blocksize) {
		/* Nothing more in higher memory on BCM47XX (MIPS) */
		if (IS_ENABLED(CONFIG_BCM47XX) && offset >= 0x2000000)
			break;

		if (curr_part >= BCM47XXPART_MAX_PARTS) {
			pr_warn("Reached maximum number of partitions, scanning stopped!\n");
			break;
		}

		/* Read beginning of the block */
		err = mtd_read(master, offset, BCM47XXPART_BYTES_TO_READ,
			       &bytes_read, (uint8_t *)buf);
		if (err && !mtd_is_bitflip(err)) {
			pr_err("mtd_read error while parsing (offset: 0x%X): %d\n",
			       offset, err);
			continue;
		}

		/* Magic or small NVRAM at 0x400 */
		if ((buf[0x4e0 / 4] == CFE_MAGIC && buf[0x4e4 / 4] == CFE_MAGIC) ||
		    (buf[0x400 / 4] == NVRAM_HEADER)) {
			bcm47xxpart_add_part(&parts[curr_part++], "boot",
					     offset, MTD_WRITEABLE);
			continue;
		}

		/*
		 * board_data starts with board_id which differs across boards,
		 * but we can use 'MPFR' (hopefully) magic at 0x100
		 */
		if (buf[0x100 / 4] == BOARD_DATA_MAGIC) {
			bcm47xxpart_add_part(&parts[curr_part++], "board_data",
					     offset, MTD_WRITEABLE);
			continue;
		}

		/* Found on Huawei E970 */
		if (buf[0x000 / 4] == FACTORY_MAGIC) {
			bcm47xxpart_add_part(&parts[curr_part++], "factory",
					     offset, MTD_WRITEABLE);
			continue;
		}

		/* POT(TOP) */
		if (buf[0x000 / 4] == POT_MAGIC1 &&
		    (buf[0x004 / 4] & 0xFFFF) == POT_MAGIC2) {
			bcm47xxpart_add_part(&parts[curr_part++], "POT", offset,
					     MTD_WRITEABLE);
			continue;
		}

		/* ML */
		if (buf[0x010 / 4] == ML_MAGIC1 &&
		    buf[0x014 / 4] == ML_MAGIC2) {
			bcm47xxpart_add_part(&parts[curr_part++], "ML", offset,
					     MTD_WRITEABLE);
			continue;
		}

		/* TRX */
		if (buf[0x000 / 4] == TRX_MAGIC) {
			if (BCM47XXPART_MAX_PARTS - curr_part < 4) {
				pr_warn("Not enough partitions left to register trx, scanning stopped!\n");
				break;
			}

			trx = (struct trx_header *)buf;

			trx_part = curr_part;
			bcm47xxpart_add_part(&parts[curr_part++], "firmware",
					     offset, 0);

			i = 0;
			/* We have LZMA loader if offset[2] points to sth */
			if (trx->offset[2]) {
				bcm47xxpart_add_part(&parts[curr_part++],
						     "loader",
						     offset + trx->offset[i],
						     0);
				i++;
			}

			if (trx->offset[i]) {
				bcm47xxpart_add_part(&parts[curr_part++],
						     "linux",
						     offset + trx->offset[i],
						     0);
				i++;
			}

			/*
			 * Pure rootfs size is known and can be calculated as:
			 * trx->length - trx->offset[i]. We don't fill it as
			 * we want to have jffs2 (overlay) in the same mtd.
			 */
			if (trx->offset[i]) {
				const char *name;

				name = bcm47xxpart_trx_data_part_name(master, offset + trx->offset[i]);
				bcm47xxpart_add_part(&parts[curr_part++],
						     name,
						     offset + trx->offset[i],
						     0);
				i++;
			}

			last_trx_part = curr_part - 1;

			/* Jump to the end of TRX */
			offset = roundup(offset + trx->length, blocksize);
			/* Next loop iteration will increase the offset */
			offset -= blocksize;
			continue;
		}

		/* Squashfs on devices not using TRX */
		if (le32_to_cpu(buf[0x000 / 4]) == SQUASHFS_MAGIC ||
		    buf[0x000 / 4] == SHSQ_MAGIC) {
			bcm47xxpart_add_part(&parts[curr_part++], "rootfs",
					     offset, 0);
			continue;
		}

		/*
		 * New (ARM?) devices may have NVRAM in some middle block. Last
		 * block will be checked later, so skip it.
		 */
		if (offset != master->size - blocksize &&
		    buf[0x000 / 4] == NVRAM_HEADER) {
			bcm47xxpart_add_part(&parts[curr_part++], "nvram",
					     offset, 0);
			continue;
		}

		/* Read middle of the block */
		err = mtd_read(master, offset + 0x8000, 0x4, &bytes_read,
			       (uint8_t *)buf);
		if (err && !mtd_is_bitflip(err)) {
			pr_err("mtd_read error while parsing (offset: 0x%X): %d\n",
			       offset, err);
			continue;
		}

		/* Some devices (ex. WNDR3700v3) don't have a standard 'MPFR' */
		if (buf[0x000 / 4] == BOARD_DATA_MAGIC2) {
			bcm47xxpart_add_part(&parts[curr_part++], "board_data",
					     offset, MTD_WRITEABLE);
			continue;
		}
	}

	/* Look for NVRAM at the end of the last block. */
	for (i = 0; i < ARRAY_SIZE(possible_nvram_sizes); i++) {
		if (curr_part >= BCM47XXPART_MAX_PARTS) {
			pr_warn("Reached maximum number of partitions, scanning stopped!\n");
			break;
		}

		offset = master->size - possible_nvram_sizes[i];
		err = mtd_read(master, offset, 0x4, &bytes_read,
			       (uint8_t *)buf);
		if (err && !mtd_is_bitflip(err)) {
			pr_err("mtd_read error while reading (offset 0x%X): %d\n",
			       offset, err);
			continue;
		}

		/* Standard NVRAM */
		if (buf[0] == NVRAM_HEADER) {
			bcm47xxpart_add_part(&parts[curr_part++], "nvram",
					     master->size - blocksize, 0);
			break;
		}
	}

	kfree(buf);

	/*
	 * Assume that partitions end at the beginning of the one they are
	 * followed by.
	 */
	for (i = 0; i < curr_part; i++) {
		u64 next_part_offset = (i < curr_part - 1) ?
				       parts[i + 1].offset : master->size;

		parts[i].size = next_part_offset - parts[i].offset;
		if (i == last_trx_part && trx_part >= 0)
			parts[trx_part].size = next_part_offset -
					       parts[trx_part].offset;
	}

	*pparts = parts;
	return curr_part;
};
static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned pendingblock)
{
	u16 BlockMap[MAX_SECTORS_PER_UNIT];
	unsigned char BlockDeleted[MAX_SECTORS_PER_UNIT];
	unsigned int thisEUN, prevEUN, status;
	struct mtd_info *mtd = inftl->mbd.mtd;
	int block, silly;
	unsigned int targetEUN;
	struct inftl_oob oob;
	size_t retlen;

	pr_debug("INFTL: INFTL_foldchain(inftl=%p,thisVUC=%d,pending=%d)\n",
			inftl, thisVUC, pendingblock);

	memset(BlockMap, 0xff, sizeof(BlockMap));
	memset(BlockDeleted, 0, sizeof(BlockDeleted));

	thisEUN = targetEUN = inftl->VUtable[thisVUC];

	if (thisEUN == BLOCK_NIL) {
		printk(KERN_WARNING "INFTL: trying to fold non-existent "
		       "Virtual Unit Chain %d!\n", thisVUC);
		return BLOCK_NIL;
	}

	silly = MAX_LOOPS;
	while (thisEUN < inftl->nb_blocks) {
		for (block = 0; block < inftl->EraseSize/SECTORSIZE; block ++) {
			if ((BlockMap[block] != BLOCK_NIL) ||
			    BlockDeleted[block])
				continue;

			if (inftl_read_oob(mtd, (thisEUN * inftl->EraseSize)
					   + (block * SECTORSIZE), 16, &retlen,
					   (char *)&oob) < 0)
				status = SECTOR_IGNORE;
			else
				status = oob.b.Status | oob.b.Status1;

			switch(status) {
			case SECTOR_FREE:
			case SECTOR_IGNORE:
				break;
			case SECTOR_USED:
				BlockMap[block] = thisEUN;
				continue;
			case SECTOR_DELETED:
				BlockDeleted[block] = 1;
				continue;
			default:
				printk(KERN_WARNING "INFTL: unknown status "
					"for block %d in EUN %d: %x\n",
					block, thisEUN, status);
				break;
			}
		}

		if (!silly--) {
			printk(KERN_WARNING "INFTL: infinite loop in Virtual "
				"Unit Chain 0x%x\n", thisVUC);
			return BLOCK_NIL;
		}

		thisEUN = inftl->PUtable[thisEUN];
	}

	pr_debug("INFTL: folding chain %d into unit %d\n", thisVUC, targetEUN);

	for (block = 0; block < inftl->EraseSize/SECTORSIZE ; block++) {
		unsigned char movebuf[SECTORSIZE];
		int ret;

		if (BlockMap[block] == targetEUN || (pendingblock ==
		    (thisVUC * (inftl->EraseSize / SECTORSIZE) + block))) {
			continue;
		}

		if (BlockMap[block] == BLOCK_NIL)
			continue;

		ret = mtd_read(mtd,
			       (inftl->EraseSize * BlockMap[block]) + (block * SECTORSIZE),
			       SECTORSIZE,
			       &retlen,
			       movebuf);
		if (ret < 0 && !mtd_is_bitflip(ret)) {
			ret = mtd_read(mtd,
				       (inftl->EraseSize * BlockMap[block]) + (block * SECTORSIZE),
				       SECTORSIZE,
				       &retlen,
				       movebuf);
			if (ret != -EIO)
				pr_debug("INFTL: error went away on retry?\n");
		}
		memset(&oob, 0xff, sizeof(struct inftl_oob));
		oob.b.Status = oob.b.Status1 = SECTOR_USED;

		inftl_write(inftl->mbd.mtd, (inftl->EraseSize * targetEUN) +
			    (block * SECTORSIZE), SECTORSIZE, &retlen,
			    movebuf, (char *)&oob);
	}

	pr_debug("INFTL: want to erase virtual chain %d\n", thisVUC);

	for (;;) {
		
		thisEUN = inftl->VUtable[thisVUC];
		prevEUN = BLOCK_NIL;
		while (inftl->PUtable[thisEUN] != BLOCK_NIL) {
			prevEUN = thisEUN;
			thisEUN = inftl->PUtable[thisEUN];
		}

		
		if (thisEUN == targetEUN)
			break;

		
		inftl->PUtable[prevEUN] = BLOCK_NIL;

		
		if (INFTL_formatblock(inftl, thisEUN) < 0) {
			inftl->PUtable[thisEUN] = BLOCK_RESERVED;
		} else {
			
			inftl->PUtable[thisEUN] = BLOCK_FREE;
			inftl->numfreeEUNs++;
		}
	}

	return targetEUN;
}
static int crosstest(void)
{
	size_t read;
	int err = 0, i;
	loff_t addr, addr0, addrn;
	unsigned char *pp1, *pp2, *pp3, *pp4;

	printk(PRINT_PREF "crosstest\n");
	pp1 = kmalloc(pgsize * 4, GFP_KERNEL);
	if (!pp1) {
		printk(PRINT_PREF "error: cannot allocate memory\n");
		return -ENOMEM;
	}
	pp2 = pp1 + pgsize;
	pp3 = pp2 + pgsize;
	pp4 = pp3 + pgsize;
	memset(pp1, 0, pgsize * 4);

	addr0 = 0;
	for (i = 0; i < ebcnt && bbt[i]; ++i)
		addr0 += mtd->erasesize;

	addrn = mtd->size;
	for (i = 0; i < ebcnt && bbt[ebcnt - i - 1]; ++i)
		addrn -= mtd->erasesize;

	/* Read 2nd-to-last page to pp1 */
	addr = addrn - pgsize - pgsize;
	err = mtd_read(mtd, addr, pgsize, &read, pp1);
	if (mtd_is_bitflip(err))
		err = 0;
	if (err || read != pgsize) {
		printk(PRINT_PREF "error: read failed at %#llx\n",
		       (long long)addr);
		kfree(pp1);
		return err;
	}

	/* Read 3rd-to-last page to pp1 */
	addr = addrn - pgsize - pgsize - pgsize;
	err = mtd_read(mtd, addr, pgsize, &read, pp1);
	if (mtd_is_bitflip(err))
		err = 0;
	if (err || read != pgsize) {
		printk(PRINT_PREF "error: read failed at %#llx\n",
		       (long long)addr);
		kfree(pp1);
		return err;
	}

	/* Read first page to pp2 */
	addr = addr0;
	printk(PRINT_PREF "reading page at %#llx\n", (long long)addr);
	err = mtd_read(mtd, addr, pgsize, &read, pp2);
	if (mtd_is_bitflip(err))
		err = 0;
	if (err || read != pgsize) {
		printk(PRINT_PREF "error: read failed at %#llx\n",
		       (long long)addr);
		kfree(pp1);
		return err;
	}

	/* Read last page to pp3 */
	addr = addrn - pgsize;
	printk(PRINT_PREF "reading page at %#llx\n", (long long)addr);
	err = mtd_read(mtd, addr, pgsize, &read, pp3);
	if (mtd_is_bitflip(err))
		err = 0;
	if (err || read != pgsize) {
		printk(PRINT_PREF "error: read failed at %#llx\n",
		       (long long)addr);
		kfree(pp1);
		return err;
	}

	/* Read first page again to pp4 */
	addr = addr0;
	printk(PRINT_PREF "reading page at %#llx\n", (long long)addr);
	err = mtd_read(mtd, addr, pgsize, &read, pp4);
	if (mtd_is_bitflip(err))
		err = 0;
	if (err || read != pgsize) {
		printk(PRINT_PREF "error: read failed at %#llx\n",
		       (long long)addr);
		kfree(pp1);
		return err;
	}

	/* pp2 and pp4 should be the same */
	printk(PRINT_PREF "verifying pages read at %#llx match\n",
	       (long long)addr0);
	if (memcmp(pp2, pp4, pgsize)) {
		printk(PRINT_PREF "verify failed!\n");
		errcnt += 1;
	} else if (!err)
		printk(PRINT_PREF "crosstest ok\n");
	kfree(pp1);
	return err;
}
static int erasecrosstest(void)
{
	size_t read, written;
	int err = 0, i, ebnum, ebnum2;
	loff_t addr0;
	char *readbuf = twopages;

	printk(PRINT_PREF "erasecrosstest\n");

	ebnum = 0;
	addr0 = 0;
	for (i = 0; i < ebcnt && bbt[i]; ++i) {
		addr0 += mtd->erasesize;
		ebnum += 1;
	}

	ebnum2 = ebcnt - 1;
	while (ebnum2 && bbt[ebnum2])
		ebnum2 -= 1;

	printk(PRINT_PREF "erasing block %d\n", ebnum);
	err = erase_eraseblock(ebnum);
	if (err)
		return err;

	printk(PRINT_PREF "writing 1st page of block %d\n", ebnum);
	set_random_data(writebuf, pgsize);
	strcpy(writebuf, "There is no data like this!");
	err = mtd_write(mtd, addr0, pgsize, &written, writebuf);
	if (err || written != pgsize) {
		printk(PRINT_PREF "error: write failed at %#llx\n",
		       (long long)addr0);
		return err ? err : -1;
	}

	printk(PRINT_PREF "reading 1st page of block %d\n", ebnum);
	memset(readbuf, 0, pgsize);
	err = mtd_read(mtd, addr0, pgsize, &read, readbuf);
	if (mtd_is_bitflip(err))
		err = 0;
	if (err || read != pgsize) {
		printk(PRINT_PREF "error: read failed at %#llx\n",
		       (long long)addr0);
		return err ? err : -1;
	}

	printk(PRINT_PREF "verifying 1st page of block %d\n", ebnum);
	if (memcmp(writebuf, readbuf, pgsize)) {
		printk(PRINT_PREF "verify failed!\n");
		errcnt += 1;
		return -1;
	}

	printk(PRINT_PREF "erasing block %d\n", ebnum);
	err = erase_eraseblock(ebnum);
	if (err)
		return err;

	printk(PRINT_PREF "writing 1st page of block %d\n", ebnum);
	set_random_data(writebuf, pgsize);
	strcpy(writebuf, "There is no data like this!");
	err = mtd_write(mtd, addr0, pgsize, &written, writebuf);
	if (err || written != pgsize) {
		printk(PRINT_PREF "error: write failed at %#llx\n",
		       (long long)addr0);
		return err ? err : -1;
	}

	printk(PRINT_PREF "erasing block %d\n", ebnum2);
	err = erase_eraseblock(ebnum2);
	if (err)
		return err;

	printk(PRINT_PREF "reading 1st page of block %d\n", ebnum);
	memset(readbuf, 0, pgsize);
	err = mtd_read(mtd, addr0, pgsize, &read, readbuf);
	if (mtd_is_bitflip(err))
		err = 0;
	if (err || read != pgsize) {
		printk(PRINT_PREF "error: read failed at %#llx\n",
		       (long long)addr0);
		return err ? err : -1;
	}

	printk(PRINT_PREF "verifying 1st page of block %d\n", ebnum);
	if (memcmp(writebuf, readbuf, pgsize)) {
		printk(PRINT_PREF "verify failed!\n");
		errcnt += 1;
		return -1;
	}

	if (!err)
		printk(PRINT_PREF "erasecrosstest ok\n");
	return err;
}