예제 #1
0
static int mtdraw_erase(struct cdev *cdev, size_t count, loff_t _offset)
{
	struct mtd_info *mtd = to_mtd(cdev);
	struct erase_info erase;
	unsigned long offset = _offset;
	int ret;

	offset = offset / (mtd->writesize + mtd->oobsize) * mtd->writesize;
	count = count / (mtd->writesize + mtd->oobsize) * mtd->writesize;

	memset(&erase, 0, sizeof(erase));
	erase.mtd = mtd;
	erase.addr = offset;
	erase.len = mtd->erasesize;

	while (count > 0) {
		debug("erase %d %d\n", erase.addr, erase.len);

		ret = mtd_block_isbad(mtd, erase.addr);
		if (ret > 0) {
			printf("Skipping bad block at 0x%08x\n", erase.addr);
		} else {
			ret = mtd->erase(mtd, &erase);
			if (ret)
				return ret;
		}

		erase.addr += mtd->erasesize;
		count -= count > mtd->erasesize ? mtd->erasesize : count;
	}

	return 0;
}
예제 #2
0
static void *dbbt_data_create(struct mtd_info *mtd)
{
	int n;
	int n_bad_blocks = 0;
	void *dbbt = xzalloc(mtd->writesize);
	uint32_t *bb = dbbt + 0x8;
	uint32_t *n_bad_blocksp = dbbt + 0x4;
	int num_blocks = mtd_div_by_eb(mtd->size, mtd);

	for (n = 0; n < num_blocks; n++) {
		loff_t offset = n * mtd->erasesize;
		if (mtd_block_isbad(mtd, offset)) {
			n_bad_blocks++;
			*bb = n;
			bb++;
		}
	}

	if (!n_bad_blocks) {
		free(dbbt);
		return NULL;
	}

	*n_bad_blocksp = n_bad_blocks;

	return dbbt;
}
예제 #3
0
static int concat_block_isbad(struct mtd_info *mtd, loff_t ofs)
{
	struct mtd_concat *concat = CONCAT(mtd);
	int i, res = 0;

	if (!mtd_can_have_bb(concat->subdev[0]))
		return res;

	if (ofs > mtd->size)
		return -EINVAL;

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

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

		res = mtd_block_isbad(subdev, ofs);
		break;
	}

	return res;
}
예제 #4
0
static int mtd_part_block_isbad(struct mtd_info *mtd, loff_t ofs)
{
	if (ofs >= mtd->size)
		return -EINVAL;
	ofs += mtd->master_offset;
	return mtd_block_isbad(mtd->master, ofs);
}
예제 #5
0
파일: mtdoops.c 프로젝트: matsufan/linux
/* Scheduled work - when we can't proceed without erasing a block */
static void mtdoops_workfunc_erase(struct work_struct *work)
{
	struct mtdoops_context *cxt =
			container_of(work, struct mtdoops_context, work_erase);
	struct mtd_info *mtd = cxt->mtd;
	int i = 0, j, ret, mod;

	/* We were unregistered */
	if (!mtd)
		return;

	mod = (cxt->nextpage * record_size) % mtd->erasesize;
	if (mod != 0) {
		cxt->nextpage = cxt->nextpage + ((mtd->erasesize - mod) / record_size);
		if (cxt->nextpage >= cxt->oops_pages)
			cxt->nextpage = 0;
	}

	while (mtd_can_have_bb(mtd)) {
		ret = mtd_block_isbad(mtd, cxt->nextpage * record_size);
		if (!ret)
			break;
		if (ret < 0) {
			printk(KERN_ERR "mtdoops: block_isbad failed, aborting\n");
			return;
		}
badblock:
		printk(KERN_WARNING "mtdoops: bad block at %08lx\n",
		       cxt->nextpage * record_size);
		i++;
		cxt->nextpage = cxt->nextpage + (mtd->erasesize / record_size);
		if (cxt->nextpage >= cxt->oops_pages)
			cxt->nextpage = 0;
		if (i == cxt->oops_pages / (mtd->erasesize / record_size)) {
			printk(KERN_ERR "mtdoops: all blocks bad!\n");
			return;
		}
	}

	for (j = 0, ret = -1; (j < 3) && (ret < 0); j++)
		ret = mtdoops_erase_block(cxt, cxt->nextpage * record_size);

	if (ret >= 0) {
		printk(KERN_DEBUG "mtdoops: ready %d, %d\n",
		       cxt->nextpage, cxt->nextcount);
		return;
	}

	if (mtd_can_have_bb(mtd) && ret == -EIO) {
		ret = mtd_block_markbad(mtd, cxt->nextpage * record_size);
		if (ret < 0) {
			printk(KERN_ERR "mtdoops: block_markbad failed, aborting\n");
			return;
		}
	}
	goto badblock;
}
예제 #6
0
static int is_block_bad(int ebnum)
{
	int ret;
	loff_t addr = ebnum * mtd->erasesize;

	ret = mtd_block_isbad(mtd, addr);
	if (ret)
		pr_info("block %d is bad\n", ebnum);
	return ret;
}
static int is_block_bad(int ebnum)
{
	loff_t addr = ebnum * mtd->erasesize;
	int ret;

	ret = mtd_block_isbad(mtd, addr);
	if (ret)
		printk(PRINT_PREF "block %d is bad\n", ebnum);
	return ret;
}
예제 #8
0
static int sharpsl_nand_init_ftl(struct mtd_info *mtd, struct sharpsl_ftl *ftl)
{
	unsigned int block_num, log_num, phymax;
	loff_t block_adr;
	u8 *oob;
	int i, ret;

	oob = kzalloc(mtd->oobsize, GFP_KERNEL);
	if (!oob)
		return -ENOMEM;

	phymax = mtd_div_by_eb(SHARPSL_FTL_PART_SIZE, mtd);

	/* FTL reserves 5% of the blocks + 1 spare  */
	ftl->logmax = ((phymax * 95) / 100) - 1;

	ftl->log2phy = kmalloc_array(ftl->logmax, sizeof(*ftl->log2phy),
				     GFP_KERNEL);
	if (!ftl->log2phy) {
		ret = -ENOMEM;
		goto exit;
	}

	/* initialize ftl->log2phy */
	for (i = 0; i < ftl->logmax; i++)
		ftl->log2phy[i] = UINT_MAX;

	/* create physical-logical table */
	for (block_num = 0; block_num < phymax; block_num++) {
		block_adr = block_num * mtd->erasesize;

		if (mtd_block_isbad(mtd, block_adr))
			continue;

		if (sharpsl_nand_read_oob(mtd, block_adr, oob))
			continue;

		/* get logical block */
		log_num = sharpsl_nand_get_logical_num(oob);

		/* cut-off errors and skip the out-of-range values */
		if (log_num > 0 && log_num < ftl->logmax) {
			if (ftl->log2phy[log_num] == UINT_MAX)
				ftl->log2phy[log_num] = block_num;
		}
	}

	pr_info("Sharp SL FTL: %d blocks used (%d logical, %d reserved)\n",
		phymax, ftl->logmax, phymax - ftl->logmax);

	ret = 0;
exit:
	kfree(oob);
	return ret;
}
static int yaffs_mtd_check_bad(struct yaffs_dev *dev, int block_no)
{
	struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
	int blocksize = dev->param.chunks_per_block * dev->param.total_bytes_per_chunk;
	int retval;

	yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "checking block %d bad", block_no);

	retval = mtd_block_isbad(mtd, (loff_t) blocksize * block_no);
	return (retval) ? YAFFS_FAIL : YAFFS_OK;
}
예제 #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
int mtd_blockdev_write(struct vmm_blockrq *brq,
		       struct vmm_request *r, void *priv)
{
	struct mtd_info *mtd = priv;
	physical_addr_t off = r->lba << mtd->erasesize_shift;
	physical_size_t len = r->bcnt << mtd->erasesize_shift;

	while (mtd_block_isbad(mtd, off)) {
		vmm_printf("%s: block at 0x%X is bad, skipping...\n",
			   __func__, off);
		off += mtd->erasesize;
	}

	return mtd_blockdev_erase_write(r, off, len, mtd);
}
예제 #12
0
static int yaffs_mtd_check_bad(struct yaffs_dev *dev, int block_no)
{
	struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
	int blocksize = dev->param.chunks_per_block * dev->data_bytes_per_chunk;
	int retval;

	yaffs_trace(YAFFS_TRACE_SCAN, "checking block %d bad", block_no);

#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
	retval = mtd_block_isbad(mtd, (loff_t) blocksize * block_no);
#else
	retval = mtd->block_isbad(mtd, (loff_t) blocksize * block_no);
#endif
	return (retval) ? YAFFS_FAIL : YAFFS_OK;
}
예제 #13
0
파일: core.c 프로젝트: bmourit/barebox
static int mtd_op_erase(struct cdev *cdev, size_t count, loff_t offset)
{
	struct mtd_info *mtd = cdev->priv;
	struct erase_info erase;
	uint32_t addr;
	int ret;

	ret = mtd_erase_align(mtd, &count, &offset);
	if (ret)
		return ret;

	memset(&erase, 0, sizeof(erase));
	erase.mtd = mtd;
	addr = offset;

	if (!mtd->block_isbad) {
		erase.addr = addr;
		erase.len = count;
		return mtd_erase(mtd, &erase);
	}

	erase.len = mtd->erasesize;

	while (count > 0) {
		dev_dbg(cdev->dev, "erase %d %d\n", addr, erase.len);

		if (!mtd->allow_erasebad)
			ret = mtd_block_isbad(mtd, addr);
		else
			ret = 0;

		erase.addr = addr;

		if (ret > 0) {
			printf("Skipping bad block at 0x%08x\n", addr);
		} else {
			ret = mtd_erase(mtd, &erase);
			if (ret)
				return ret;
		}

		addr += mtd->erasesize;
		count -= count > mtd->erasesize ? mtd->erasesize : count;
	}

	return 0;
}
int nandmtd2_query_block(struct yaffs_dev *dev, int block_no,
			 enum yaffs_block_state *state, u32 * seq_number)
{
	struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
	int retval;

	yaffs_trace(YAFFS_TRACE_MTD, "nandmtd2_query_block %d", block_no);
	retval =
	    mtd_block_isbad(mtd,
			     block_no * dev->param.chunks_per_block *
			     dev->param.total_bytes_per_chunk);

	if (retval) {
		yaffs_trace(YAFFS_TRACE_MTD, "block is bad");

		*state = YAFFS_BLOCK_STATE_DEAD;
		*seq_number = 0;
	} else {
		struct yaffs_ext_tags t;
		nandmtd2_read_chunk_tags(dev, block_no *
					 dev->param.chunks_per_block, NULL, &t);

		if (t.chunk_used) {
			*seq_number = t.seq_number;
			*state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
		} else {
			*seq_number = 0;
			*state = YAFFS_BLOCK_STATE_EMPTY;
		}
				/*if ecc unfixed, set the block empty. This block will be erased when allocate.*/
		if(t.ecc_result == YAFFS_ECC_RESULT_UNFIXED)
		{
			printk("yaffsdebug : unfixed ecc error when scan block, seqnum:0x%x\n",t.seq_number);
			*seq_number = 0;
			*state = YAFFS_BLOCK_STATE_EMPTY;
		}
	}
	yaffs_trace(YAFFS_TRACE_MTD,
		"block is bad seq %d state %d", *seq_number, *state);

	if (retval == 0)
		return YAFFS_OK;
	else
		return YAFFS_FAIL;
}
예제 #15
0
static int flash_erase(struct vmm_chardev *cdev,
		       flash_op *op)
{
	struct erase_info info;

	if (op->len & op->mtd->erasesize_mask) {
		vmm_cprintf(cdev, "Uncorrect length 0x%X, a block size is "
			    "0x%08X\n", op->len, op->mtd->erasesize);
		return VMM_EFAIL;
	}

	op->offset &= ~op->mtd->erasesize_mask;

	while (op->len) {
		if (mtd_block_isbad(op->mtd, op->offset)) {
			vmm_cprintf(cdev, "%s block at 0x%08X is bad, "
				    "skipping...", op->mtd->name, op->offset);
			op->offset += op->mtd->erasesize;
			op->len -= op->mtd->erasesize;
			continue;
		}

		vmm_cprintf(cdev, "This will erasing the %s block at "
			    "0x%08X\n", op->mtd->name, op->offset);
		if (!flash_question(cdev)) {
			vmm_cprintf(cdev, "Skipping...\n");
			op->offset += op->mtd->erasesize;
			op->len -= op->mtd->erasesize;
			continue;
		}
		vmm_cprintf(cdev, "Erasing...\n");
		memset(&info, 0, sizeof (struct erase_info));
		info.mtd = op->mtd;
		info.addr = op->offset;
		info.len = op->len;
		info.priv = (u_long)cdev;
		info.callback = flash_erase_cb;
		vmm_printf("Sizeof %zu, Addr 0x%p, cb 0x%p\n",
			   sizeof (struct erase_info),
			   &info, info.callback);
		mtd_erase(op->mtd, &info);
	}
	return VMM_OK;
}
예제 #16
0
파일: io.c 프로젝트: 383530895/linux
/**
 * ubi_io_is_bad - check if a physical eraseblock is bad.
 * @ubi: UBI device description object
 * @pnum: the physical eraseblock number to check
 *
 * This function returns a positive number if the physical eraseblock is bad,
 * zero if not, and a negative error code if an error occurred.
 */
int ubi_io_is_bad(const struct ubi_device *ubi, int pnum)
{
	struct mtd_info *mtd = ubi->mtd;

	ubi_assert(pnum >= 0 && pnum < ubi->peb_count);

	if (ubi->bad_allowed) {
		int ret;

		ret = mtd_block_isbad(mtd, (loff_t)pnum * ubi->peb_size);
		if (ret < 0)
			ubi_err(ubi, "error %d while checking if PEB %d is bad",
				ret, pnum);
		else if (ret)
			dbg_io("PEB %d is bad", pnum);
		return ret;
	}

	return 0;
}
예제 #17
0
static int mtd_test_scan_bad_block(void)
{
	unsigned int i = 0, bad = 0;

	bbt = (unsigned char *)vmalloc(ebcnt);
	if (!bbt) {
		pr_info("error: cannot allocate memory\n");
		return -ENOMEM;
	}

	pr_info("scanning for bad eraseblocks first\n");
	for (i = 0; i < ebcnt; ++i) {
		bbt[i] = mtd_block_isbad(mtd, i * mtd->erasesize) ? 1 : 0;
		if (bbt[i])
			bad += 1;
		cond_resched();
	}
	pr_info("scanned %d eraseblocks, %d are bad\n", ebcnt, bad);
	return 0;
}
int nandmtd2_query_block(struct yaffs_dev *dev, int block_no,
			 enum yaffs_block_state *state, u32 * seq_number)
{
	struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
	int retval;

	yaffs_trace(YAFFS_TRACE_MTD, "nandmtd2_query_block %d", block_no);
	retval =
	    mtd_block_isbad(mtd,
			     block_no * dev->param.chunks_per_block *
			     dev->param.total_bytes_per_chunk);

	if (retval) {
		yaffs_trace(YAFFS_TRACE_MTD, "block is bad");

		*state = YAFFS_BLOCK_STATE_DEAD;
		*seq_number = 0;
	} else {
		struct yaffs_ext_tags t;
		nandmtd2_read_chunk_tags(dev, block_no *
					 dev->param.chunks_per_block, NULL, &t);

		if (t.chunk_used) {
			*seq_number = t.seq_number;
			*state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
		} else {
			*seq_number = 0;
			*state = YAFFS_BLOCK_STATE_EMPTY;
		}
	}
	yaffs_trace(YAFFS_TRACE_MTD,
		"block is bad seq %d state %d", *seq_number, *state);

	if (retval == 0)
		return YAFFS_OK;
	else
		return YAFFS_FAIL;
}
예제 #19
0
static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
				  unsigned char *buf, uint32_t buf_size, struct jffs2_summary *s) {
	struct jffs2_unknown_node *node;
	struct jffs2_unknown_node crcnode;
	uint32_t ofs, prevofs, max_ofs;
	uint32_t hdr_crc, buf_ofs, buf_len;
	int err;
	int noise = 0;


#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
	int cleanmarkerfound = 0;
#endif

	ofs = jeb->offset;
	prevofs = jeb->offset - 1;

	jffs2_dbg(1, "%s(): Scanning block at 0x%x\n", __func__, ofs);

#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
	if (jffs2_cleanmarker_oob(c)) {
		int ret;

		if (mtd_block_isbad(c->mtd, jeb->offset))
			return BLK_STATE_BADBLOCK;

		ret = jffs2_check_nand_cleanmarker(c, jeb);
		jffs2_dbg(2, "jffs_check_nand_cleanmarker returned %d\n", ret);

		switch (ret) {
		case 0:		cleanmarkerfound = 1; break;
		case 1: 	break;
		default: 	return ret;
		}
	}
#endif

	if (jffs2_sum_active()) {
		struct jffs2_sum_marker *sm;
		void *sumptr = NULL;
		uint32_t sumlen;
	      
		if (!buf_size) {
			
			sm = (void *)buf + c->sector_size - sizeof(*sm);
			if (je32_to_cpu(sm->magic) == JFFS2_SUM_MAGIC) {
				sumptr = buf + je32_to_cpu(sm->offset);
				sumlen = c->sector_size - je32_to_cpu(sm->offset);
			}
		} else {
			
			if (c->wbuf_pagesize)
				buf_len = c->wbuf_pagesize;
			else
				buf_len = sizeof(*sm);

			
			err = jffs2_fill_scan_buf(c, buf + buf_size - buf_len, 
						  jeb->offset + c->sector_size - buf_len,
						  buf_len);				
			if (err)
				return err;

			sm = (void *)buf + buf_size - sizeof(*sm);
			if (je32_to_cpu(sm->magic) == JFFS2_SUM_MAGIC) {
				sumlen = c->sector_size - je32_to_cpu(sm->offset);
				sumptr = buf + buf_size - sumlen;

				
				if (sumlen > buf_size) {
					
					sumptr = kmalloc(sumlen, GFP_KERNEL);
					if (!sumptr)
						return -ENOMEM;
					memcpy(sumptr + sumlen - buf_len, buf + buf_size - buf_len, buf_len);
				}
				if (buf_len < sumlen) {
					
					err = jffs2_fill_scan_buf(c, sumptr, 
								  jeb->offset + c->sector_size - sumlen,
								  sumlen - buf_len);				
					if (err)
						return err;
				}
			}

		}

		if (sumptr) {
			err = jffs2_sum_scan_sumnode(c, jeb, sumptr, sumlen, &pseudo_random);

			if (buf_size && sumlen > buf_size)
				kfree(sumptr);
			if (err)
				return err;
		}
	}

	buf_ofs = jeb->offset;

	if (!buf_size) {
		
		buf_len = c->sector_size;
	} else {
		buf_len = EMPTY_SCAN_SIZE(c->sector_size);
		err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len);
		if (err)
			return err;
	}

	
	ofs = 0;
	max_ofs = EMPTY_SCAN_SIZE(c->sector_size);
	
	while(ofs < max_ofs && *(uint32_t *)(&buf[ofs]) == 0xFFFFFFFF)
		ofs += 4;

	if (ofs == max_ofs) {
#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
		if (jffs2_cleanmarker_oob(c)) {
			
			int ret = jffs2_check_oob_empty(c, jeb, cleanmarkerfound);
			jffs2_dbg(2, "jffs2_check_oob_empty returned %d\n",
				  ret);
			switch (ret) {
			case 0:		return cleanmarkerfound ? BLK_STATE_CLEANMARKER : BLK_STATE_ALLFF;
			case 1: 	return BLK_STATE_ALLDIRTY;
			default: 	return ret;
			}
		}
#endif
		jffs2_dbg(1, "Block at 0x%08x is empty (erased)\n",
			  jeb->offset);
		if (c->cleanmarker_size == 0)
			return BLK_STATE_CLEANMARKER;	
		else
			return BLK_STATE_ALLFF;	
	}
	if (ofs) {
		jffs2_dbg(1, "Free space at %08x ends at %08x\n", jeb->offset,
			  jeb->offset + ofs);
		if ((err = jffs2_prealloc_raw_node_refs(c, jeb, 1)))
			return err;
		if ((err = jffs2_scan_dirty_space(c, jeb, ofs)))
			return err;
	}

	
	ofs += jeb->offset;

	noise = 10;

	dbg_summary("no summary found in jeb 0x%08x. Apply original scan.\n",jeb->offset);

scan_more:
	while(ofs < jeb->offset + c->sector_size) {

		jffs2_dbg_acct_paranoia_check_nolock(c, jeb);

		
		err = jffs2_prealloc_raw_node_refs(c, jeb, 2);
		if (err)
			return err;

		cond_resched();

		if (ofs & 3) {
			pr_warn("Eep. ofs 0x%08x not word-aligned!\n", ofs);
			ofs = PAD(ofs);
			continue;
		}
		if (ofs == prevofs) {
			pr_warn("ofs 0x%08x has already been seen. Skipping\n",
				ofs);
			if ((err = jffs2_scan_dirty_space(c, jeb, 4)))
				return err;
			ofs += 4;
			continue;
		}
		prevofs = ofs;

		if (jeb->offset + c->sector_size < ofs + sizeof(*node)) {
			jffs2_dbg(1, "Fewer than %zd bytes left to end of block. (%x+%x<%x+%zx) Not reading\n",
				  sizeof(struct jffs2_unknown_node),
				  jeb->offset, c->sector_size, ofs,
				  sizeof(*node));
			if ((err = jffs2_scan_dirty_space(c, jeb, (jeb->offset + c->sector_size)-ofs)))
				return err;
			break;
		}

		if (buf_ofs + buf_len < ofs + sizeof(*node)) {
			buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
			jffs2_dbg(1, "Fewer than %zd bytes (node header) left to end of buf. Reading 0x%x at 0x%08x\n",
				  sizeof(struct jffs2_unknown_node),
				  buf_len, ofs);
			err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
			if (err)
				return err;
			buf_ofs = ofs;
		}

		node = (struct jffs2_unknown_node *)&buf[ofs-buf_ofs];

		if (*(uint32_t *)(&buf[ofs-buf_ofs]) == 0xffffffff) {
			uint32_t inbuf_ofs;
			uint32_t empty_start, scan_end;

			empty_start = ofs;
			ofs += 4;
			scan_end = min_t(uint32_t, EMPTY_SCAN_SIZE(c->sector_size)/8, buf_len);

			jffs2_dbg(1, "Found empty flash at 0x%08x\n", ofs);
		more_empty:
			inbuf_ofs = ofs - buf_ofs;
			while (inbuf_ofs < scan_end) {
				if (unlikely(*(uint32_t *)(&buf[inbuf_ofs]) != 0xffffffff)) {
					pr_warn("Empty flash at 0x%08x ends at 0x%08x\n",
						empty_start, ofs);
					if ((err = jffs2_scan_dirty_space(c, jeb, ofs-empty_start)))
						return err;
					goto scan_more;
				}

				inbuf_ofs+=4;
				ofs += 4;
			}
			
			jffs2_dbg(1, "Empty flash to end of buffer at 0x%08x\n",
				  ofs);

			if (buf_ofs == jeb->offset && jeb->used_size == PAD(c->cleanmarker_size) &&
			    c->cleanmarker_size && !jeb->dirty_size && !ref_next(jeb->first_node)) {
				jffs2_dbg(1, "%d bytes at start of block seems clean... assuming all clean\n",
					  EMPTY_SCAN_SIZE(c->sector_size));
				return BLK_STATE_CLEANMARKER;
			}
			if (!buf_size && (scan_end != buf_len)) {
				scan_end = buf_len;
				goto more_empty;
			}
			
			
			buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
			if (!buf_len) {
				jffs2_dbg(1, "Empty flash at %08x runs to end of block. Treating as free_space\n",
					  empty_start);
				break;
			}
			
			scan_end = buf_len;
			jffs2_dbg(1, "Reading another 0x%x at 0x%08x\n",
				  buf_len, ofs);
			err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
			if (err)
				return err;
			buf_ofs = ofs;
			goto more_empty;
		}

		if (ofs == jeb->offset && je16_to_cpu(node->magic) == KSAMTIB_CIGAM_2SFFJ) {
			pr_warn("Magic bitmask is backwards at offset 0x%08x. Wrong endian filesystem?\n",
				ofs);
			if ((err = jffs2_scan_dirty_space(c, jeb, 4)))
				return err;
			ofs += 4;
			continue;
		}
		if (je16_to_cpu(node->magic) == JFFS2_DIRTY_BITMASK) {
			jffs2_dbg(1, "Dirty bitmask at 0x%08x\n", ofs);
			if ((err = jffs2_scan_dirty_space(c, jeb, 4)))
				return err;
			ofs += 4;
			continue;
		}
		if (je16_to_cpu(node->magic) == JFFS2_OLD_MAGIC_BITMASK) {
			pr_warn("Old JFFS2 bitmask found at 0x%08x\n", ofs);
			pr_warn("You cannot use older JFFS2 filesystems with newer kernels\n");
			if ((err = jffs2_scan_dirty_space(c, jeb, 4)))
				return err;
			ofs += 4;
			continue;
		}
		if (je16_to_cpu(node->magic) != JFFS2_MAGIC_BITMASK) {
			
			noisy_printk(&noise, "%s(): Magic bitmask 0x%04x not found at 0x%08x: 0x%04x instead\n",
				     __func__,
				     JFFS2_MAGIC_BITMASK, ofs,
				     je16_to_cpu(node->magic));
			if ((err = jffs2_scan_dirty_space(c, jeb, 4)))
				return err;
			ofs += 4;
			continue;
		}
		
		crcnode.magic = node->magic;
		crcnode.nodetype = cpu_to_je16( je16_to_cpu(node->nodetype) | JFFS2_NODE_ACCURATE);
		crcnode.totlen = node->totlen;
		hdr_crc = crc32(0, &crcnode, sizeof(crcnode)-4);

		if (hdr_crc != je32_to_cpu(node->hdr_crc)) {
			noisy_printk(&noise, "%s(): Node at 0x%08x {0x%04x, 0x%04x, 0x%08x) has invalid CRC 0x%08x (calculated 0x%08x)\n",
				     __func__,
				     ofs, je16_to_cpu(node->magic),
				     je16_to_cpu(node->nodetype),
				     je32_to_cpu(node->totlen),
				     je32_to_cpu(node->hdr_crc),
				     hdr_crc);
			if ((err = jffs2_scan_dirty_space(c, jeb, 4)))
				return err;
			ofs += 4;
			continue;
		}

		if (ofs + je32_to_cpu(node->totlen) > jeb->offset + c->sector_size) {
			
			pr_warn("Node at 0x%08x with length 0x%08x would run over the end of the erase block\n",
				ofs, je32_to_cpu(node->totlen));
			pr_warn("Perhaps the file system was created with the wrong erase size?\n");
			if ((err = jffs2_scan_dirty_space(c, jeb, 4)))
				return err;
			ofs += 4;
			continue;
		}

		if (!(je16_to_cpu(node->nodetype) & JFFS2_NODE_ACCURATE)) {
			
			jffs2_dbg(2, "Node at 0x%08x is obsolete. Skipping\n",
				  ofs);
			if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(node->totlen)))))
				return err;
			ofs += PAD(je32_to_cpu(node->totlen));
			continue;
		}

		switch(je16_to_cpu(node->nodetype)) {
		case JFFS2_NODETYPE_INODE:
			if (buf_ofs + buf_len < ofs + sizeof(struct jffs2_raw_inode)) {
				buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
				jffs2_dbg(1, "Fewer than %zd bytes (inode node) left to end of buf. Reading 0x%x at 0x%08x\n",
					  sizeof(struct jffs2_raw_inode),
					  buf_len, ofs);
				err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
				if (err)
					return err;
				buf_ofs = ofs;
				node = (void *)buf;
			}
			err = jffs2_scan_inode_node(c, jeb, (void *)node, ofs, s);
			if (err) return err;
			ofs += PAD(je32_to_cpu(node->totlen));
			break;

		case JFFS2_NODETYPE_DIRENT:
			if (buf_ofs + buf_len < ofs + je32_to_cpu(node->totlen)) {
				buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
				jffs2_dbg(1, "Fewer than %d bytes (dirent node) left to end of buf. Reading 0x%x at 0x%08x\n",
					  je32_to_cpu(node->totlen), buf_len,
					  ofs);
				err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
				if (err)
					return err;
				buf_ofs = ofs;
				node = (void *)buf;
			}
			err = jffs2_scan_dirent_node(c, jeb, (void *)node, ofs, s);
			if (err) return err;
			ofs += PAD(je32_to_cpu(node->totlen));
			break;

#ifdef CONFIG_JFFS2_FS_XATTR
		case JFFS2_NODETYPE_XATTR:
			if (buf_ofs + buf_len < ofs + je32_to_cpu(node->totlen)) {
				buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
				jffs2_dbg(1, "Fewer than %d bytes (xattr node) left to end of buf. Reading 0x%x at 0x%08x\n",
					  je32_to_cpu(node->totlen), buf_len,
					  ofs);
				err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
				if (err)
					return err;
				buf_ofs = ofs;
				node = (void *)buf;
			}
			err = jffs2_scan_xattr_node(c, jeb, (void *)node, ofs, s);
			if (err)
				return err;
			ofs += PAD(je32_to_cpu(node->totlen));
			break;
		case JFFS2_NODETYPE_XREF:
			if (buf_ofs + buf_len < ofs + je32_to_cpu(node->totlen)) {
				buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
				jffs2_dbg(1, "Fewer than %d bytes (xref node) left to end of buf. Reading 0x%x at 0x%08x\n",
					  je32_to_cpu(node->totlen), buf_len,
					  ofs);
				err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
				if (err)
					return err;
				buf_ofs = ofs;
				node = (void *)buf;
			}
			err = jffs2_scan_xref_node(c, jeb, (void *)node, ofs, s);
			if (err)
				return err;
			ofs += PAD(je32_to_cpu(node->totlen));
			break;
#endif	

		case JFFS2_NODETYPE_CLEANMARKER:
			jffs2_dbg(1, "CLEANMARKER node found at 0x%08x\n", ofs);
			if (je32_to_cpu(node->totlen) != c->cleanmarker_size) {
				pr_notice("CLEANMARKER node found at 0x%08x has totlen 0x%x != normal 0x%x\n",
					  ofs, je32_to_cpu(node->totlen),
					  c->cleanmarker_size);
				if ((err = jffs2_scan_dirty_space(c, jeb, PAD(sizeof(struct jffs2_unknown_node)))))
					return err;
				ofs += PAD(sizeof(struct jffs2_unknown_node));
			} else if (jeb->first_node) {
				pr_notice("CLEANMARKER node found at 0x%08x, not first node in block (0x%08x)\n",
					  ofs, jeb->offset);
				if ((err = jffs2_scan_dirty_space(c, jeb, PAD(sizeof(struct jffs2_unknown_node)))))
					return err;
				ofs += PAD(sizeof(struct jffs2_unknown_node));
			} else {
				jffs2_link_node_ref(c, jeb, ofs | REF_NORMAL, c->cleanmarker_size, NULL);

				ofs += PAD(c->cleanmarker_size);
			}
			break;

		case JFFS2_NODETYPE_PADDING:
			if (jffs2_sum_active())
				jffs2_sum_add_padding_mem(s, je32_to_cpu(node->totlen));
			if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(node->totlen)))))
				return err;
			ofs += PAD(je32_to_cpu(node->totlen));
			break;

		default:
			switch (je16_to_cpu(node->nodetype) & JFFS2_COMPAT_MASK) {
			case JFFS2_FEATURE_ROCOMPAT:
				pr_notice("Read-only compatible feature node (0x%04x) found at offset 0x%08x\n",
					  je16_to_cpu(node->nodetype), ofs);
				c->flags |= JFFS2_SB_FLAG_RO;
				if (!(jffs2_is_readonly(c)))
					return -EROFS;
				if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(node->totlen)))))
					return err;
				ofs += PAD(je32_to_cpu(node->totlen));
				break;

			case JFFS2_FEATURE_INCOMPAT:
				pr_notice("Incompatible feature node (0x%04x) found at offset 0x%08x\n",
					  je16_to_cpu(node->nodetype), ofs);
				return -EINVAL;

			case JFFS2_FEATURE_RWCOMPAT_DELETE:
				jffs2_dbg(1, "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n",
					  je16_to_cpu(node->nodetype), ofs);
				if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(node->totlen)))))
					return err;
				ofs += PAD(je32_to_cpu(node->totlen));
				break;

			case JFFS2_FEATURE_RWCOMPAT_COPY: {
				jffs2_dbg(1, "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n",
					  je16_to_cpu(node->nodetype), ofs);

				jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, PAD(je32_to_cpu(node->totlen)), NULL);

				
				jffs2_sum_disable_collecting(s);
				ofs += PAD(je32_to_cpu(node->totlen));
				break;
				}
			}
		}
	}

	if (jffs2_sum_active()) {
		if (PAD(s->sum_size + JFFS2_SUMMARY_FRAME_SIZE) > jeb->free_size) {
			dbg_summary("There is not enough space for "
				"summary information, disabling for this jeb!\n");
			jffs2_sum_disable_collecting(s);
		}
	}

	jffs2_dbg(1, "Block at 0x%08x: free 0x%08x, dirty 0x%08x, unchecked 0x%08x, used 0x%08x, wasted 0x%08x\n",
		  jeb->offset, jeb->free_size, jeb->dirty_size,
		  jeb->unchecked_size, jeb->used_size, jeb->wasted_size);
	
	
	if (jeb->wasted_size) {
		jeb->dirty_size += jeb->wasted_size;
		c->dirty_size += jeb->wasted_size;
		c->wasted_size -= jeb->wasted_size;
		jeb->wasted_size = 0;
	}

	return jffs2_scan_classify_jeb(c, jeb);
}
예제 #20
0
파일: core.c 프로젝트: bmourit/barebox
int mtd_ioctl(struct cdev *cdev, int request, void *buf)
{
	int ret = 0;
	struct mtd_info *mtd = cdev->priv;
	struct mtd_info_user *user = buf;
#if (defined(CONFIG_NAND_ECC_HW) || defined(CONFIG_NAND_ECC_SOFT))
	struct mtd_ecc_stats *ecc = buf;
#endif
	struct region_info_user *reg = buf;
#ifdef CONFIG_MTD_WRITE
	struct erase_info_user *ei = buf;
#endif
	loff_t *offset = buf;

	switch (request) {
	case MEMGETBADBLOCK:
		dev_dbg(cdev->dev, "MEMGETBADBLOCK: 0x%08llx\n", *offset);
		ret = mtd_block_isbad(mtd, *offset);
		break;
#ifdef CONFIG_MTD_WRITE
	case MEMSETBADBLOCK:
		dev_dbg(cdev->dev, "MEMSETBADBLOCK: 0x%08llx\n", *offset);
		ret = mtd_block_markbad(mtd, *offset);
		break;
	case MEMERASE:
		ret = mtd_op_erase(cdev, ei->length, ei->start + cdev->offset);
		break;
#endif
	case MEMGETINFO:
		user->type	= mtd->type;
		user->flags	= mtd->flags;
		user->size	= mtd->size;
		user->erasesize	= mtd->erasesize;
		user->writesize	= mtd->writesize;
		user->oobsize	= mtd->oobsize;
		user->subpagesize = mtd->writesize >> mtd->subpage_sft;
		user->mtd	= mtd;
		/* The below fields are obsolete */
		user->ecctype	= -1;
		user->eccsize	= 0;
		break;
#if (defined(CONFIG_NAND_ECC_HW) || defined(CONFIG_NAND_ECC_SOFT))
	case ECCGETSTATS:
		ecc->corrected = mtd->ecc_stats.corrected;
		ecc->failed = mtd->ecc_stats.failed;
		ecc->badblocks = mtd->ecc_stats.badblocks;
		ecc->bbtblocks = mtd->ecc_stats.bbtblocks;
		break;
#endif
	case MEMGETREGIONINFO:
		if (cdev->mtd) {
			unsigned long size = cdev->size;
			reg->offset = cdev->offset;
			reg->erasesize = cdev->mtd->erasesize;
			reg->numblocks = size / reg->erasesize;
			reg->regionindex = cdev->mtd->index;
		}
		break;
	default:
		ret = -EINVAL;
	}

	return ret;
}
예제 #21
0
파일: mtdpart.c 프로젝트: DFE/u-boot
static int part_block_isbad(struct mtd_info *mtd, loff_t ofs)
{
	struct mtd_part *part = PART(mtd);
	ofs += part->offset;
	return mtd_block_isbad(part->master, ofs);
}
boolean flash_get_share_region_info(rgn_pos_e_type region_type,void* data,uint32 data_len)
{
    unsigned int     page_index       = 0;
    unsigned int     blk_size             = 0;
    unsigned int     blk_count          = 0;
    unsigned int     blk_index          = INVALID_BLOCK_ID;
    rgn_hd_type* rgn_hd;
    unsigned int     offset                 = 0;
    unsigned int     start_offset       = 0;
    unsigned int     page_size          = 0;
    uint8*     read_buf          = NULL;
    int           retlength            = 0;
    
    if (NULL == flash_nand_oper_region_init(SHARE_REGION))
    {
        printk(KERN_ERR "flash_get_share_region_info init fail  \n");
        return FALSE;
    }
    
    /*Get Partition and Device Info*/
    blk_count      = child_region[SHARE_REGION].length;
    blk_size        = operation_region[SHARE_REGION].block_size;
    start_offset  = operation_region[SHARE_REGION].start_addr;
    page_size    = operation_region[SHARE_REGION].page_size;
    read_buf      = operation_region[SHARE_REGION].buffer;
    
    for (blk_index = 0; blk_index < blk_count; blk_index++)
    {
        offset = start_offset + blk_size * blk_index;
        /*If the blk is bad blk or it is erased*/
        if (mtd_block_isbad(g_mtd, offset))
        {
            printk(KERN_DEBUG "flash_get_share_region_info Block ID = 0x%x is bad block \n",
                   (offset / blk_size));
            continue;
        }

        /*If current blk is not erased, then read the first page and check its magic*/
        /*lint -e64*/
        if (!mtd_read(g_mtd, offset, page_size, &retlength, (unsigned char*)read_buf))
        /*lint +e64*/
        {
           /*Firstly we need to check the Share Region Info,If it was a valid block
            then read corresponding page*/
            rgn_hd = (rgn_hd_type*)read_buf;
            if(SHARE_RGN_MAGIC == rgn_hd->magic)
            {
                /*Read Spec Region Flag Info*/
                page_index += region_type;
                offset = offset + page_index * page_size;

                memset((void *)read_buf, NAND_FILL_CHAR_APP, page_size);
                /*lint -e64*/
                if(!mtd_read(g_mtd, offset, page_size, &retlength,
                   (unsigned char*)read_buf))
                /*lint +e64*/
                {
                    memcpy(data,read_buf,data_len);
                    flash_nand_oper_region_close(SHARE_REGION);
                    return TRUE;
                }  
                printk(KERN_DEBUG "flash_get_share_region_info fail  \n");
            }
        }
    }
    printk(KERN_ERR "flash_get_share_region_info error  \n");

    flash_nand_oper_region_close(SHARE_REGION);
    return FALSE;
}
/*===========================================================================
 
FUNCTION  FLASH_UPDATE_SHARE_REGION_INFO
 
DESCRIPTION
    update user flag,nv_mbn,and iso header info in the share region.
    This function use page to store these info, 

    Page 0: Share region Info:
           Magic:
           Sub region len:
    Page 1: Nv restore flag:
           In Used Flag Magic: 4 Byte
           Auto Restore Magic: 4Byte
           Auto Restore Flag: 
    Page 2:
          In User Flag Magic:
          MBN Magic:
          MBN Info Num:
          MBN: Version:
          MBN nv data
    Page 3:
          ISO Header Info;
          
    We use two block to implement this feature, when the first time to update this feature directly write it to the 
first available block,and then we update this info then firstly read the page info to cache, update the cache value
and then write it to another block, erase lasted block.

Author: ChenFeng 2010-3-20

RETURN VALUE
    TRUE if Op Succeed
    FALSE if Op Failure
 
SIDE EFFECTS
  None
 
===========================================================================*/
boolean flash_update_share_region_info(rgn_pos_e_type region_type,void* data)
{
    unsigned int    block_index        = 0;
    unsigned int    start_index         = 0;
    unsigned int    blk_size              = 0;
    unsigned int    blk_count            = 0;
    unsigned int    max_rgn_num    = 0;
    unsigned int    dest_block          = 0;
    unsigned int    current_block     = INVALID_BLOCK_ID;
    unsigned int    current_page      = INVALID_PAGE_ID;
    unsigned int    dest_page           = INVALID_PAGE_ID;
    rgn_hd_type* rgn_hd       = NULL;
    unsigned int   offset                    = 0;
    unsigned int   page_size             = 0;
    uint8 *   cache_buf            = NULL;
    unsigned int   start_offset           = 0;
    struct   erase_info instr;
    int retlength = 0;
    rgn_hd_type rgn_hd_1 = {0};

    /*入参条件检测*/
    if (region_type >= RGN_MAX_NUM || NULL == data)
    {
        printk(KERN_ERR "Input parm error \n");
        return FALSE;
    }

    if(NULL == flash_nand_oper_region_init(SHARE_REGION))
    {
        printk(KERN_ERR "flash_update_share_region_info init error \n");
        return FALSE;
    }

    /*Get Partition and Device Info*/
    blk_count    = child_region[SHARE_REGION].length;
    blk_size       = operation_region[SHARE_REGION].block_size;
    start_offset = operation_region[SHARE_REGION].start_addr;
    page_size   = operation_region[SHARE_REGION].page_size;
    cache_buf    = operation_region[SHARE_REGION].buffer;
    
    instr.mtd = g_mtd;
    instr.len = g_mtd->erasesize;
    instr.callback = NULL;
    instr.priv = 0;
    
    /*instr.addr*/
    for (block_index = 0; block_index < blk_count; block_index++)
    {
        offset = start_offset + blk_size * block_index;
        
        /*If the blk is bad blk or it is erase */
        if (mtd_block_isbad(g_mtd, offset))
        {
            printk(KERN_DEBUG "Find Current Block ID = 0x%x is bad block \n",(offset / blk_size));
            continue;
        }

        /*lint -e64*/
        if (!mtd_read(g_mtd, offset, page_size, &retlength, (unsigned char*)cache_buf))
        /*lint +e64*/
        {
            /*Firstly we need to check the Share Region Info,If it was a valid block
            then read corresponding page*/
            rgn_hd = (rgn_hd_type*)cache_buf;
            
            if (SHARE_RGN_MAGIC == rgn_hd->magic)
            {
                current_page = block_index * blk_size;
                max_rgn_num = rgn_hd->sub_rgn_num;
                current_block = block_index;
                printk(KERN_DEBUG "Print entery current page = 0x%x  max_rgn_num = 0x%x  \n",
                       current_page, max_rgn_num);
                break;
            }  
            else
            {
                instr.addr = offset;
                if (mtd_erase(g_mtd, &instr))
                {
                    printk(KERN_DEBUG "Current Erase error ,Mark bad block \n");
                    /* mark bad */
                    mtd_block_markbad(g_mtd, offset);
                }
                printk(KERN_DEBUG "Print nand_erase offset = 0x%x  \n", offset);
                continue;
            }
        }
        else
        {
            printk(KERN_ERR "Nand_read  error  !\n");
            return FALSE;
        }
    }

    printk(KERN_DEBUG "Print first current page = %u  \n", current_page);

    if(block_index != blk_count)
    {
        /*从 当前block 的 下一个block 分区开始寻找下一个 没使用的BLOCK*/
        dest_block = (block_index + 1) % blk_count;
    }

    /*Find the first unused block*/
    for (block_index  = 0; block_index  < blk_count; block_index++)
    {
        offset = start_offset + dest_block * blk_size;
        if (mtd_block_isbad(g_mtd, offset))
        {
                printk(KERN_DEBUG "Find Dest Block ID = 0x%x is bad block \n", (offset / blk_size));
                continue;
        }
        else
        {
            if (current_block != dest_block)
            {
                instr.addr = offset;
                if (mtd_erase(g_mtd, &instr))
                {
                    /* mark bad */
                    mtd_block_markbad(g_mtd, offset);
                    
                    dest_block = (dest_block + 1) % blk_count;
                    printk(KERN_DEBUG "Dest Erase error ,Mark bad block \n");
                    continue;
                }
                dest_page = dest_block * blk_size;
                break;
            }
        }
        dest_block = (dest_block + 1) % blk_count;
    }

    /*将当前页的数据和更新的数据分别取出写入目标BLOCK*/
    if (INVALID_PAGE_ID != dest_page)
    {   
        start_index = 0;
        /*第一次升级SHARE RGN分区  或者RGN_MAX_NUM有变化*/
        if ((unsigned int)region_type >= max_rgn_num)
        {
            offset = start_offset;
            memset(cache_buf,0xFF, page_size);  /*flash 操作buf 清为0XFF*/
            rgn_hd_1.magic = SHARE_RGN_MAGIC;
            rgn_hd_1.sub_rgn_num = RGN_MAX_NUM;
            memcpy(cache_buf,(void *)&rgn_hd_1,sizeof(rgn_hd_type));
            printk(KERN_DEBUG "Print First Dest page = %u  \n",dest_page);

            /*擦除当前BLOCK*/
            if ((INVALID_BLOCK_ID == current_block) || (0 < max_rgn_num))
            {
                offset = offset + dest_page;
            }
            else
            {
                offset = offset + current_page;
            }

            /*lint -e64*/
            if (mtd_write(g_mtd, offset, page_size, &retlength,
                (unsigned char*)cache_buf))
            /*lint +e64*/
            {
                printk(KERN_ERR "nand_write rgn_hd error  \n");
                goto FalseQuit;
            }

            memset(cache_buf,0xFF, page_size); /*flash 操作buf 清为0XFF*/
            memcpy(cache_buf,data,page_size);
            /*lint -e64*/
            if (mtd_write(g_mtd, (offset  + region_type * page_size),
                page_size, &retlength, (unsigned char*)cache_buf))
            /*lint +e64*/
            {
                printk(KERN_ERR "nand_write region page error  \n");
                goto FalseQuit;
            }
            start_index = 1;

        }

        if (INVALID_PAGE_ID != current_page && dest_page != current_page)
        {  
            offset = start_offset;
            printk(KERN_DEBUG "Print not First Dest page = %u  \n",dest_page);
            printk(KERN_DEBUG "Print last current page = %u  \n",current_page);
            for (; start_index < max_rgn_num; start_index++)            
            {
                if (start_index != region_type)
                {
                    memset(cache_buf,0xFF, page_size); /*flash 操作buf 清为0XFF*/
                    /*lint -e64*/
                    if (!mtd_read(g_mtd,(offset + current_page + start_index * page_size),
                    page_size, &retlength,(unsigned char*)cache_buf))
                    /*lint +e64*/
                    {
                        if (0 == start_index)
                        {
                            rgn_hd_type *temp_hd = NULL;
                            temp_hd = (rgn_hd_type *)cache_buf;
                            printk(KERN_DEBUG "magic = 0x%x   max_num = 0x%x \n", (unsigned int)temp_hd->magic,
                                    (unsigned int)temp_hd->sub_rgn_num);  
                        }
                        /*lint -e64*/
                        if (mtd_write(g_mtd, (offset + dest_page 
                            + start_index * page_size),
                            page_size, &retlength, (unsigned char*)cache_buf))
                        /*lint -e64*/
                        {
                            printk(KERN_DEBUG "nand_write start_index = %u  offset = 0x%x\n",
                                   start_index, (offset + dest_page
                                   + region_type * page_size));
                            continue;
                        }
                    }
                }
                else
                {
                    memset(cache_buf,0xFF, page_size); /*flash 操作buf 清为0XFF*/
                    memcpy(cache_buf,data,page_size);
                    /*lint -e64*/
                    if (mtd_write(g_mtd, (offset + dest_page + region_type * page_size),
                        page_size, &retlength, (unsigned char*)cache_buf))
                    /*lint -e64*/
                    {
                        printk(KERN_ERR "nand_write error \n");
                        goto FalseQuit;
                    }
                    printk(KERN_DEBUG "Write offset = 0x%x ! \n",
                           (offset + dest_page + region_type * page_size)); 
                }
            }

            instr.addr = offset + current_page;
            if (!mtd_erase(g_mtd, &instr))
            {
                printk(KERN_DEBUG "nand_erase offset = 0x%x ! \n",(offset + current_page)); 
            }
            else
            {
                printk(KERN_DEBUG "Last Erase current error ,Mark bad block \n");
                /* mark bad */
                mtd_block_markbad(g_mtd, offset);
                goto FalseQuit;
            } 
        }
        else if (dest_page == current_page)
        {
            printk(KERN_DEBUG "Error dest_page == current_page offset = 0x%x  \n", current_page);
            goto FalseQuit;
        }
        
        flash_nand_oper_region_close(SHARE_REGION);
        return TRUE;
    }
FalseQuit:
    printk(KERN_ERR "flash_update_share_region_info error \n");
    flash_nand_oper_region_close(SHARE_REGION);
    return FALSE;
}
예제 #24
0
static int write_block(struct mtd_info* mtd, uint64_t* offset, unsigned char* buf, unsigned char* tmpbuf, int has_oob)
{

    int ret=0;
    int retry;
    int markbad=0;
next:
    markbad = 0;
    ret = mtd_block_isbad(mtd, *offset);
    if(ret < 0) {
        printf("\nFWU bad block detection failure: off 0x%012llX\n",
               *offset);
        return -1;
    }
    else if (ret == 1) {
        printf("\nFWU bad block detected: off 0x%012llX\n",
               *offset);
        *offset += mtd->erasesize;
        goto next;
    }

    for(retry=0; (retry<3); retry++) {
        printf("FWU rewriting block: off 0x%012llX / %lldM %s %d\t\t\r",
               *offset,
               *offset / 1024 / 1024,
               retry == 0 ? "" : " \t(again)\n", retry);

        if (retry) {
            ret = mtd_erase1(mtd, *offset);
            if(ret < 0) {
                printf("\nFWU erase err: off 0x%012llX ret %d\n",
                       *offset, ret);
                markbad = 1;
                continue;
            }
        }

        if (!has_oob)
            ret = mtd_write(mtd, *offset, buf, mtd->erasesize);
        else {
            int tmp;
            for (tmp=0; tmp < (mtd->erasesize / mtd->writesize); tmp++ ) {
                ret = mtd_writeoob(mtd,
                                   *offset + (tmp * mtd->writesize),
                                   buf + tmp * (mtd->writesize + mtd->oobsize),
                                   mtd->writesize);
                if (ret<0)
                    break;
            }
        }

        if(ret < 0) {
            printf("\nFWU write err: off 0x%012llX ret %d\n",
                   *offset, ret);
            markbad = 1;
            continue;
        }

        /* read back to force hardware CRC checks */
        ret = mtd_read(mtd, *offset, tmpbuf, mtd->erasesize);
        if(ret < 0) {
            printf("\nFWU checkread err: off 0x%012llX ret %d\n",
                   *offset, ret);
            markbad = 1;
            continue;
        }
        *offset += mtd->erasesize;
        break;
    }

    if (markbad) {
        printf("\nFWU failed to overwrite block, skipping it and marking bad: off 0x%012llX ret %d\n",
               *offset, ret);
        mtd_erase1(mtd, *offset); /* Try to make sure block is somewhat clean */
        mtd_block_markbad(mtd, *offset);
        *offset += mtd->erasesize;
        goto next;
    }
    return 0;
}
예제 #25
0
static int fwu_tftp_cb(uint32_t off, u8* buf, size_t len, int last, void* priv)
{
    int ret;
    struct fwu_tftp_ctx *ctx = (struct fwu_tftp_ctx*)priv;

    if(ctx == NULL) {
        return -EINVAL;
    }

    struct mtd_info *mtd = ctx->mtd;

    BUG_ON(ctx->last);
    ctx->last = last;

    ret = 0;
    while(len > 0) {
        size_t len1 = MIN(mtd->erasesize - ctx->block_sz, len);
        memcpy(&ctx->block[ctx->block_sz], buf, len1);

        ctx->block_sz += len1;
        buf += len1;
        len -= len1;

        if((ctx->block_sz == mtd->erasesize) || last) {

            int retry;
            int bad = 0;

            ret = mtd_block_isbad(mtd, ctx->flash_offset);
            if(ret < 0) {
                printf("\nFWU bad block detection failure: off 0x%012llX\n",
                       ctx->flash_offset);
                goto err;
            }
            else if (ret == 1) {
                printf("\nFWU bad block detected: off 0x%012llX\n",
                       ctx->flash_offset);
                bad = 1;
                ret = 0;
            }

            for(retry=0; ((retry<3) && (ctx->block_sz>0)); retry++) {
                printf("FWU rewriting block: off 0x%012llX / %lldM %s%s %d\t\t\r",
                       ctx->flash_offset,
                       ctx->flash_offset / 1024 / 1024,
                       bad ? " \t(BAD)\n" : "",
                       retry == 0 ? "" : " \t(again)\n", retry);

                if (retry) {
                    ret = mtd_erase1(mtd, ctx->flash_offset);
                    if(ret < 0) {
                        printf("\nFWU erase err: off 0x%012llX ret %d\n",
                               ctx->flash_offset, ret);
                        continue;
                    }
                }

                if (ctx->oob==0)
                    ret = mtd_write(mtd, ctx->flash_offset, ctx->block, mtd->erasesize);
                else {
                    int tmp;
                    for (tmp=0; tmp < (mtd->erasesize / mtd->writesize); tmp ++ ) {
                        ret = mtd_writeoob(mtd,
                                           ctx->flash_offset + (tmp * mtd->writesize),
                                           ctx->block + tmp * (mtd->writesize + mtd->oobsize),
                                           mtd->writesize);
                        if (ret<0)
                            break;
                    }
                }

                if(ret < 0) {
                    printf("\nFWU write err: off 0x%012llX ret %d\n",
                           ctx->flash_offset, ret);
                    continue;
                }

                /* read back to force hardware CRC checks */
                ret = mtd_read(mtd, ctx->flash_offset, ctx->block, mtd->erasesize);
                if(ret < 0) {
                    printf("\nFWU checkread err: off 0x%012llX ret %d\n",
                           ctx->flash_offset, ret);
                    continue;
                }
                ctx->flash_offset += mtd->erasesize;
                ctx->block_sz = 0;
            }

            if(ctx->block_sz > 0) {
                printf("\nFWU failed to overwrite block, skipping it and marking bad: off 0x%012llX ret %d\n",
                       ctx->flash_offset, ret);
                mtd_erase1(mtd, ctx->flash_offset); /* Don't allow just to screw us */
                mtd_block_markbad(mtd, ctx->flash_offset);
                ctx->flash_offset += mtd->erasesize;
            }
        }
    }

err:
    return ret;
}
예제 #26
0
파일: inftlmount.c 프로젝트: 020gzh/linux
/*
 * find_boot_record: Find the INFTL Media Header and its Spare copy which
 *	contains the various device information of the INFTL partition and
 *	Bad Unit Table. Update the PUtable[] table according to the Bad
 *	Unit Table. PUtable[] is used for management of Erase Unit in
 *	other routines in inftlcore.c and inftlmount.c.
 */
static int find_boot_record(struct INFTLrecord *inftl)
{
	struct inftl_unittail h1;
	//struct inftl_oob oob;
	unsigned int i, block;
	u8 buf[SECTORSIZE];
	struct INFTLMediaHeader *mh = &inftl->MediaHdr;
	struct mtd_info *mtd = inftl->mbd.mtd;
	struct INFTLPartition *ip;
	size_t retlen;

	pr_debug("INFTL: find_boot_record(inftl=%p)\n", inftl);

        /*
	 * Assume logical EraseSize == physical erasesize for starting the
	 * scan. We'll sort it out later if we find a MediaHeader which says
	 * otherwise.
	 */
	inftl->EraseSize = inftl->mbd.mtd->erasesize;
        inftl->nb_blocks = (u32)inftl->mbd.mtd->size / inftl->EraseSize;

	inftl->MediaUnit = BLOCK_NIL;

	/* Search for a valid boot record */
	for (block = 0; block < inftl->nb_blocks; block++) {
		int ret;

		/*
		 * Check for BNAND header first. Then whinge if it's found
		 * but later checks fail.
		 */
		ret = mtd_read(mtd, block * inftl->EraseSize, SECTORSIZE,
			       &retlen, buf);
		/* We ignore ret in case the ECC of the MediaHeader is invalid
		   (which is apparently acceptable) */
		if (retlen != SECTORSIZE) {
			static int warncount = 5;

			if (warncount) {
				printk(KERN_WARNING "INFTL: block read at 0x%x "
					"of mtd%d failed: %d\n",
					block * inftl->EraseSize,
					inftl->mbd.mtd->index, ret);
				if (!--warncount)
					printk(KERN_WARNING "INFTL: further "
						"failures for this block will "
						"not be printed\n");
			}
			continue;
		}

		if (retlen < 6 || memcmp(buf, "BNAND", 6)) {
			/* BNAND\0 not found. Continue */
			continue;
		}

		/* To be safer with BIOS, also use erase mark as discriminant */
		ret = inftl_read_oob(mtd,
				     block * inftl->EraseSize + SECTORSIZE + 8,
				     8, &retlen,(char *)&h1);
		if (ret < 0) {
			printk(KERN_WARNING "INFTL: ANAND header found at "
				"0x%x in mtd%d, but OOB data read failed "
				"(err %d)\n", block * inftl->EraseSize,
				inftl->mbd.mtd->index, ret);
			continue;
		}


		/*
		 * This is the first we've seen.
		 * Copy the media header structure into place.
		 */
		memcpy(mh, buf, sizeof(struct INFTLMediaHeader));

		/* Read the spare media header at offset 4096 */
		mtd_read(mtd, block * inftl->EraseSize + 4096, SECTORSIZE,
			 &retlen, buf);
		if (retlen != SECTORSIZE) {
			printk(KERN_WARNING "INFTL: Unable to read spare "
			       "Media Header\n");
			return -1;
		}
		/* Check if this one is the same as the first one we found. */
		if (memcmp(mh, buf, sizeof(struct INFTLMediaHeader))) {
			printk(KERN_WARNING "INFTL: Primary and spare Media "
			       "Headers disagree.\n");
			return -1;
		}

		mh->NoOfBootImageBlocks = le32_to_cpu(mh->NoOfBootImageBlocks);
		mh->NoOfBinaryPartitions = le32_to_cpu(mh->NoOfBinaryPartitions);
		mh->NoOfBDTLPartitions = le32_to_cpu(mh->NoOfBDTLPartitions);
		mh->BlockMultiplierBits = le32_to_cpu(mh->BlockMultiplierBits);
		mh->FormatFlags = le32_to_cpu(mh->FormatFlags);
		mh->PercentUsed = le32_to_cpu(mh->PercentUsed);

		pr_debug("INFTL: Media Header ->\n"
			 "    bootRecordID          = %s\n"
			 "    NoOfBootImageBlocks   = %d\n"
			 "    NoOfBinaryPartitions  = %d\n"
			 "    NoOfBDTLPartitions    = %d\n"
			 "    BlockMultiplerBits    = %d\n"
			 "    FormatFlgs            = %d\n"
			 "    OsakVersion           = 0x%x\n"
			 "    PercentUsed           = %d\n",
			 mh->bootRecordID, mh->NoOfBootImageBlocks,
			 mh->NoOfBinaryPartitions,
			 mh->NoOfBDTLPartitions,
			 mh->BlockMultiplierBits, mh->FormatFlags,
			 mh->OsakVersion, mh->PercentUsed);

		if (mh->NoOfBDTLPartitions == 0) {
			printk(KERN_WARNING "INFTL: Media Header sanity check "
				"failed: NoOfBDTLPartitions (%d) == 0, "
				"must be at least 1\n", mh->NoOfBDTLPartitions);
			return -1;
		}

		if ((mh->NoOfBDTLPartitions + mh->NoOfBinaryPartitions) > 4) {
			printk(KERN_WARNING "INFTL: Media Header sanity check "
				"failed: Total Partitions (%d) > 4, "
				"BDTL=%d Binary=%d\n", mh->NoOfBDTLPartitions +
				mh->NoOfBinaryPartitions,
				mh->NoOfBDTLPartitions,
				mh->NoOfBinaryPartitions);
			return -1;
		}

		if (mh->BlockMultiplierBits > 1) {
			printk(KERN_WARNING "INFTL: sorry, we don't support "
				"UnitSizeFactor 0x%02x\n",
				mh->BlockMultiplierBits);
			return -1;
		} else if (mh->BlockMultiplierBits == 1) {
			printk(KERN_WARNING "INFTL: support for INFTL with "
				"UnitSizeFactor 0x%02x is experimental\n",
				mh->BlockMultiplierBits);
			inftl->EraseSize = inftl->mbd.mtd->erasesize <<
				mh->BlockMultiplierBits;
			inftl->nb_blocks = (u32)inftl->mbd.mtd->size / inftl->EraseSize;
			block >>= mh->BlockMultiplierBits;
		}

		/* Scan the partitions */
		for (i = 0; (i < 4); i++) {
			ip = &mh->Partitions[i];
			ip->virtualUnits = le32_to_cpu(ip->virtualUnits);
			ip->firstUnit = le32_to_cpu(ip->firstUnit);
			ip->lastUnit = le32_to_cpu(ip->lastUnit);
			ip->flags = le32_to_cpu(ip->flags);
			ip->spareUnits = le32_to_cpu(ip->spareUnits);
			ip->Reserved0 = le32_to_cpu(ip->Reserved0);

			pr_debug("    PARTITION[%d] ->\n"
				 "        virtualUnits    = %d\n"
				 "        firstUnit       = %d\n"
				 "        lastUnit        = %d\n"
				 "        flags           = 0x%x\n"
				 "        spareUnits      = %d\n",
				 i, ip->virtualUnits, ip->firstUnit,
				 ip->lastUnit, ip->flags,
				 ip->spareUnits);

			if (ip->Reserved0 != ip->firstUnit) {
				struct erase_info *instr = &inftl->instr;

				instr->mtd = inftl->mbd.mtd;

				/*
				 * 	Most likely this is using the
				 * 	undocumented qiuck mount feature.
				 * 	We don't support that, we will need
				 * 	to erase the hidden block for full
				 * 	compatibility.
				 */
				instr->addr = ip->Reserved0 * inftl->EraseSize;
				instr->len = inftl->EraseSize;
				mtd_erase(mtd, instr);
			}
			if ((ip->lastUnit - ip->firstUnit + 1) < ip->virtualUnits) {
				printk(KERN_WARNING "INFTL: Media Header "
					"Partition %d sanity check failed\n"
					"    firstUnit %d : lastUnit %d  >  "
					"virtualUnits %d\n", i, ip->lastUnit,
					ip->firstUnit, ip->Reserved0);
				return -1;
			}
			if (ip->Reserved1 != 0) {
				printk(KERN_WARNING "INFTL: Media Header "
					"Partition %d sanity check failed: "
					"Reserved1 %d != 0\n",
					i, ip->Reserved1);
				return -1;
			}

			if (ip->flags & INFTL_BDTL)
				break;
		}

		if (i >= 4) {
			printk(KERN_WARNING "INFTL: Media Header Partition "
				"sanity check failed:\n       No partition "
				"marked as Disk Partition\n");
			return -1;
		}

		inftl->nb_boot_blocks = ip->firstUnit;
		inftl->numvunits = ip->virtualUnits;
		if (inftl->numvunits > (inftl->nb_blocks -
		    inftl->nb_boot_blocks - 2)) {
			printk(KERN_WARNING "INFTL: Media Header sanity check "
				"failed:\n        numvunits (%d) > nb_blocks "
				"(%d) - nb_boot_blocks(%d) - 2\n",
				inftl->numvunits, inftl->nb_blocks,
				inftl->nb_boot_blocks);
			return -1;
		}

		inftl->mbd.size  = inftl->numvunits *
			(inftl->EraseSize / SECTORSIZE);

		/*
		 * Block count is set to last used EUN (we won't need to keep
		 * any meta-data past that point).
		 */
		inftl->firstEUN = ip->firstUnit;
		inftl->lastEUN = ip->lastUnit;
		inftl->nb_blocks = ip->lastUnit + 1;

		/* Memory alloc */
		inftl->PUtable = kmalloc(inftl->nb_blocks * sizeof(u16), GFP_KERNEL);
		if (!inftl->PUtable) {
			printk(KERN_WARNING "INFTL: allocation of PUtable "
				"failed (%zd bytes)\n",
				inftl->nb_blocks * sizeof(u16));
			return -ENOMEM;
		}

		inftl->VUtable = kmalloc(inftl->nb_blocks * sizeof(u16), GFP_KERNEL);
		if (!inftl->VUtable) {
			kfree(inftl->PUtable);
			printk(KERN_WARNING "INFTL: allocation of VUtable "
				"failed (%zd bytes)\n",
				inftl->nb_blocks * sizeof(u16));
			return -ENOMEM;
		}

		/* Mark the blocks before INFTL MediaHeader as reserved */
		for (i = 0; i < inftl->nb_boot_blocks; i++)
			inftl->PUtable[i] = BLOCK_RESERVED;
		/* Mark all remaining blocks as potentially containing data */
		for (; i < inftl->nb_blocks; i++)
			inftl->PUtable[i] = BLOCK_NOTEXPLORED;

		/* Mark this boot record (NFTL MediaHeader) block as reserved */
		inftl->PUtable[block] = BLOCK_RESERVED;

		/* Read Bad Erase Unit Table and modify PUtable[] accordingly */
		for (i = 0; i < inftl->nb_blocks; i++) {
			int physblock;
			/* If any of the physical eraseblocks are bad, don't
			   use the unit. */
			for (physblock = 0; physblock < inftl->EraseSize; physblock += inftl->mbd.mtd->erasesize) {
				if (mtd_block_isbad(inftl->mbd.mtd,
						    i * inftl->EraseSize + physblock))
					inftl->PUtable[i] = BLOCK_RESERVED;
			}
		}

		inftl->MediaUnit = block;
		return 0;
	}
예제 #27
0
static int __init init_axis_flash(void)
{
	struct mtd_info *main_mtd;
	struct mtd_info *aux_mtd = NULL;
	int err = 0;
	int pidx = 0;
	struct partitiontable_head *ptable_head = NULL;
	struct partitiontable_entry *ptable;
	int ptable_ok = 0;
	static char page[PAGESIZE];
	size_t len;
	int ram_rootfs_partition = -1; 
	int part;

#if !defined(CONFIG_MTD_MTDRAM) || (CONFIG_MTDRAM_TOTAL_SIZE != 0) || (CONFIG_MTDRAM_ABS_POS != 0)
	if (!romfs_in_flash && !nand_boot) {
		printk(KERN_EMERG "axisflashmap: Cannot create an MTD RAM "
		       "device; configure CONFIG_MTD_MTDRAM with size = 0!\n");
		panic("This kernel cannot boot from RAM!\n");
	}
#endif

#ifndef CONFIG_ETRAX_VCS_SIM
	main_mtd = flash_probe();
	if (main_mtd)
		printk(KERN_INFO "%s: 0x%08x bytes of NOR flash memory.\n",
		       main_mtd->name, main_mtd->size);

#ifdef CONFIG_ETRAX_NANDFLASH
	aux_mtd = crisv32_nand_flash_probe();
	if (aux_mtd)
		printk(KERN_INFO "%s: 0x%08x bytes of NAND flash memory.\n",
			aux_mtd->name, aux_mtd->size);

#ifdef CONFIG_ETRAX_NANDBOOT
	{
		struct mtd_info *tmp_mtd;

		printk(KERN_INFO "axisflashmap: Set to boot from NAND flash, "
		       "making NAND flash primary device.\n");
		tmp_mtd = main_mtd;
		main_mtd = aux_mtd;
		aux_mtd = tmp_mtd;
	}
#endif 
#endif 

	if (!main_mtd && !aux_mtd) {
		printk(KERN_INFO "axisflashmap: Found no flash chip.\n");
	}

#if 0 
	if (main_mtd) {
		int sectoraddr, i;
		for (sectoraddr = 0; sectoraddr < 2*65536+4096;
				sectoraddr += PAGESIZE) {
			main_mtd->read(main_mtd, sectoraddr, PAGESIZE, &len,
				page);
			printk(KERN_INFO
			       "Sector at %d (length %d):\n",
			       sectoraddr, len);
			for (i = 0; i < PAGESIZE; i += 16) {
				printk(KERN_INFO
				       "%02x %02x %02x %02x "
				       "%02x %02x %02x %02x "
				       "%02x %02x %02x %02x "
				       "%02x %02x %02x %02x\n",
				       page[i] & 255, page[i+1] & 255,
				       page[i+2] & 255, page[i+3] & 255,
				       page[i+4] & 255, page[i+5] & 255,
				       page[i+6] & 255, page[i+7] & 255,
				       page[i+8] & 255, page[i+9] & 255,
				       page[i+10] & 255, page[i+11] & 255,
				       page[i+12] & 255, page[i+13] & 255,
				       page[i+14] & 255, page[i+15] & 255);
			}
		}
	}
#endif

	if (main_mtd) {
		main_mtd->owner = THIS_MODULE;
		axisflash_mtd = main_mtd;

		loff_t ptable_sector = CONFIG_ETRAX_PTABLE_SECTOR;

		
		pidx++;
#ifdef CONFIG_ETRAX_NANDBOOT
		int blockstat;
		do {
			blockstat = mtd_block_isbad(main_mtd, ptable_sector);
			if (blockstat < 0)
				ptable_sector = 0; 
			else if (blockstat)
				ptable_sector += main_mtd->erasesize;
		} while (blockstat && ptable_sector);
#endif
		if (ptable_sector) {
			mtd_read(main_mtd, ptable_sector, PAGESIZE, &len,
				 page);
			ptable_head = &((struct partitiontable *) page)->head;
		}

#if 0 
		printk(KERN_INFO
		       "axisflashmap: flash read %d bytes at 0x%08x, data: "
		       "%02x %02x %02x %02x %02x %02x %02x %02x\n",
		       len, CONFIG_ETRAX_PTABLE_SECTOR,
		       page[0] & 255, page[1] & 255,
		       page[2] & 255, page[3] & 255,
		       page[4] & 255, page[5] & 255,
		       page[6] & 255, page[7] & 255);
		printk(KERN_INFO
		       "axisflashmap: partition table offset %d, data: "
		       "%02x %02x %02x %02x %02x %02x %02x %02x\n",
		       PARTITION_TABLE_OFFSET,
		       page[PARTITION_TABLE_OFFSET+0] & 255,
		       page[PARTITION_TABLE_OFFSET+1] & 255,
		       page[PARTITION_TABLE_OFFSET+2] & 255,
		       page[PARTITION_TABLE_OFFSET+3] & 255,
		       page[PARTITION_TABLE_OFFSET+4] & 255,
		       page[PARTITION_TABLE_OFFSET+5] & 255,
		       page[PARTITION_TABLE_OFFSET+6] & 255,
		       page[PARTITION_TABLE_OFFSET+7] & 255);
#endif
	}

	if (ptable_head && (ptable_head->magic == PARTITION_TABLE_MAGIC)
	    && (ptable_head->size <
		(MAX_PARTITIONS * sizeof(struct partitiontable_entry) +
		PARTITIONTABLE_END_MARKER_SIZE))
	    && (*(unsigned long*)((void*)ptable_head + sizeof(*ptable_head) +
				  ptable_head->size -
				  PARTITIONTABLE_END_MARKER_SIZE)
		== PARTITIONTABLE_END_MARKER)) {
		struct partitiontable_entry *max_addr =
			(struct partitiontable_entry *)
			((unsigned long)ptable_head + sizeof(*ptable_head) +
			 ptable_head->size);
		unsigned long offset = CONFIG_ETRAX_PTABLE_SECTOR;
		unsigned char *p;
		unsigned long csum = 0;

		ptable = (struct partitiontable_entry *)
			((unsigned long)ptable_head + sizeof(*ptable_head));

		
		p = (unsigned char*) ptable;

		while (p <= (unsigned char*)max_addr) {
			csum += *p++;
			csum += *p++;
			csum += *p++;
			csum += *p++;
		}
		ptable_ok = (csum == ptable_head->checksum);

		
		printk(KERN_INFO "axisflashmap: "
		       "Found a%s partition table at 0x%p-0x%p.\n",
		       (ptable_ok ? " valid" : "n invalid"), ptable_head,
		       max_addr);

		while (ptable_ok
		       && ptable->offset != PARTITIONTABLE_END_MARKER
		       && ptable < max_addr
		       && pidx < MAX_PARTITIONS - 1) {

			axis_partitions[pidx].offset = offset + ptable->offset;
#ifdef CONFIG_ETRAX_NANDFLASH
			if (main_mtd->type == MTD_NANDFLASH) {
				axis_partitions[pidx].size =
					(((ptable+1)->offset ==
					  PARTITIONTABLE_END_MARKER) ?
					  main_mtd->size :
					  ((ptable+1)->offset + offset)) -
					(ptable->offset + offset);

			} else
#endif 
				axis_partitions[pidx].size = ptable->size;
#ifdef CONFIG_ETRAX_NANDBOOT
			if (!nand_boot &&
			    ram_rootfs_partition < 0 && 
			    ptable->type == PARTITION_TYPE_JFFS2 &&
			    (ptable->flags & PARTITION_FLAGS_READONLY_MASK) ==
				PARTITION_FLAGS_READONLY)
				ram_rootfs_partition = pidx;
#endif 
			pidx++;
			ptable++;
		}
	}

	
	

	struct mtd_partition *partition = &axis_partitions[0];
	if (main_mtd && !ptable_ok) {
		memcpy(axis_partitions, axis_default_partitions,
		       sizeof(axis_default_partitions));
		pidx = NUM_DEFAULT_PARTITIONS;
		ram_rootfs_partition = DEFAULT_ROOTFS_PARTITION_NO;
	}

	
	if (romfs_in_flash) {
		printk(KERN_INFO "axisflashmap: Adding partition for "
		       "overlapping root file system image\n");
		axis_partitions[pidx].size = romfs_length;
		axis_partitions[pidx].offset = romfs_start - FLASH_CACHED_ADDR;
		axis_partitions[pidx].name = "romfs";
		axis_partitions[pidx].mask_flags |= MTD_WRITEABLE;
		ram_rootfs_partition = -1;
		pidx++;
	} else if (romfs_length && !nand_boot) {
		if (ram_rootfs_partition < 0) {
			
			ram_rootfs_partition = pidx;
			pidx++;
		}
		printk(KERN_INFO "axisflashmap: Adding partition for "
		       "root file system image in RAM\n");
		axis_partitions[ram_rootfs_partition].size = romfs_length;
		axis_partitions[ram_rootfs_partition].offset = romfs_start;
		axis_partitions[ram_rootfs_partition].name = "romfs";
		axis_partitions[ram_rootfs_partition].mask_flags |=
			MTD_WRITEABLE;
	}

#ifdef CONFIG_ETRAX_AXISFLASHMAP_MTD0WHOLE
	if (main_mtd) {
		main_partition.size = main_mtd->size;
		err = mtd_device_register(main_mtd, &main_partition, 1);
		if (err)
			panic("axisflashmap: Could not initialize "
			      "partition for whole main mtd device!\n");
	}
#endif


	for (part = 0; part < pidx; part++) {
		if (part == ram_rootfs_partition) {
			
			struct mtd_info *mtd_ram;

			mtd_ram = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
			if (!mtd_ram)
				panic("axisflashmap: Couldn't allocate memory "
				      "for mtd_info!\n");
			printk(KERN_INFO "axisflashmap: Adding RAM partition "
			       "for rootfs image.\n");
			err = mtdram_init_device(mtd_ram,
						 (void *)partition[part].offset,
						 partition[part].size,
						 partition[part].name);
			if (err)
				panic("axisflashmap: Could not initialize "
				      "MTD RAM device!\n");
			mtd_ram->erasesize = (main_mtd ? main_mtd->erasesize :
				CONFIG_ETRAX_PTABLE_SECTOR);
		} else {
			err = mtd_device_register(main_mtd, &partition[part],
						  1);
			if (err)
				panic("axisflashmap: Could not add mtd "
					"partition %d\n", part);
		}
	}
#endif 

#ifdef CONFIG_ETRAX_VCS_SIM
	struct mtd_info *mtd_ram;

	mtd_ram = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
	if (!mtd_ram) {
		panic("axisflashmap: Couldn't allocate memory for "
		      "mtd_info!\n");
	}

	printk(KERN_INFO "axisflashmap: Adding RAM partition for romfs, "
	       "at %u, size %u\n",
	       (unsigned) romfs_start, (unsigned) romfs_length);

	err = mtdram_init_device(mtd_ram, (void *)romfs_start,
				 romfs_length, "romfs");
	if (err) {
		panic("axisflashmap: Could not initialize MTD RAM "
		      "device!\n");
	}
#endif 

#ifndef CONFIG_ETRAX_VCS_SIM
	if (aux_mtd) {
		aux_partition.size = aux_mtd->size;
		err = mtd_device_register(aux_mtd, &aux_partition, 1);
		if (err)
			panic("axisflashmap: Could not initialize "
			      "aux mtd device!\n");

	}
#endif 

	return err;
}
예제 #28
0
파일: axisflashmap.c 프로젝트: 1314cc/linux
/*
 * Probe the flash chip(s) and, if it succeeds, read the partition-table
 * and register the partitions with MTD.
 */
static int __init init_axis_flash(void)
{
	struct mtd_info *main_mtd;
	struct mtd_info *aux_mtd = NULL;
	int err = 0;
	int pidx = 0;
	struct partitiontable_head *ptable_head = NULL;
	struct partitiontable_entry *ptable;
	int ptable_ok = 0;
	static char page[PAGESIZE];
	size_t len;
	int ram_rootfs_partition = -1; /* -1 => no RAM rootfs partition */
	int part;
	struct mtd_partition *partition;

	/* We need a root fs. If it resides in RAM, we need to use an
	 * MTDRAM device, so it must be enabled in the kernel config,
	 * but its size must be configured as 0 so as not to conflict
	 * with our usage.
	 */
#if !defined(CONFIG_MTD_MTDRAM) || (CONFIG_MTDRAM_TOTAL_SIZE != 0) || (CONFIG_MTDRAM_ABS_POS != 0)
	if (!romfs_in_flash && !nand_boot) {
		printk(KERN_EMERG "axisflashmap: Cannot create an MTD RAM "
		       "device; configure CONFIG_MTD_MTDRAM with size = 0!\n");
		panic("This kernel cannot boot from RAM!\n");
	}
#endif

	main_mtd = flash_probe();
	if (main_mtd)
		printk(KERN_INFO "%s: 0x%08llx bytes of NOR flash memory.\n",
		       main_mtd->name, main_mtd->size);

#ifdef CONFIG_ETRAX_NANDFLASH
	aux_mtd = crisv32_nand_flash_probe();
	if (aux_mtd)
		printk(KERN_INFO "%s: 0x%08x bytes of NAND flash memory.\n",
			aux_mtd->name, aux_mtd->size);

#ifdef CONFIG_ETRAX_NANDBOOT
	{
		struct mtd_info *tmp_mtd;

		printk(KERN_INFO "axisflashmap: Set to boot from NAND flash, "
		       "making NAND flash primary device.\n");
		tmp_mtd = main_mtd;
		main_mtd = aux_mtd;
		aux_mtd = tmp_mtd;
	}
#endif /* CONFIG_ETRAX_NANDBOOT */
#endif /* CONFIG_ETRAX_NANDFLASH */

	if (!main_mtd && !aux_mtd) {
		/* There's no reason to use this module if no flash chip can
		 * be identified. Make sure that's understood.
		 */
		printk(KERN_INFO "axisflashmap: Found no flash chip.\n");
	}

#if 0 /* Dump flash memory so we can see what is going on */
	if (main_mtd) {
		int sectoraddr;
		for (sectoraddr = 0; sectoraddr < 2*65536+4096;
				sectoraddr += PAGESIZE) {
			main_mtd->read(main_mtd, sectoraddr, PAGESIZE, &len,
				page);
			printk(KERN_INFO
			       "Sector at %d (length %d):\n",
			       sectoraddr, len);
			print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1, page, PAGESIZE, false);
		}
	}
#endif

	if (main_mtd) {
		loff_t ptable_sector = CONFIG_ETRAX_PTABLE_SECTOR;
		main_mtd->owner = THIS_MODULE;
		axisflash_mtd = main_mtd;


		/* First partition (rescue) is always set to the default. */
		pidx++;
#ifdef CONFIG_ETRAX_NANDBOOT
		/* We know where the partition table should be located,
		 * it will be in first good block after that.
		 */
		int blockstat;
		do {
			blockstat = mtd_block_isbad(main_mtd, ptable_sector);
			if (blockstat < 0)
				ptable_sector = 0; /* read error */
			else if (blockstat)
				ptable_sector += main_mtd->erasesize;
		} while (blockstat && ptable_sector);
#endif
		if (ptable_sector) {
			mtd_read(main_mtd, ptable_sector, PAGESIZE, &len,
				 page);
			ptable_head = &((struct partitiontable *) page)->head;
		}

#if 0 /* Dump partition table so we can see what is going on */
		printk(KERN_INFO
		       "axisflashmap: flash read %d bytes at 0x%08x, data: %8ph\n",
		       len, CONFIG_ETRAX_PTABLE_SECTOR, page);
		printk(KERN_INFO
		       "axisflashmap: partition table offset %d, data: %8ph\n",
		       PARTITION_TABLE_OFFSET, page + PARTITION_TABLE_OFFSET);
#endif
	}

	if (ptable_head && (ptable_head->magic == PARTITION_TABLE_MAGIC)
	    && (ptable_head->size <
		(MAX_PARTITIONS * sizeof(struct partitiontable_entry) +
		PARTITIONTABLE_END_MARKER_SIZE))
	    && (*(unsigned long*)((void*)ptable_head + sizeof(*ptable_head) +
				  ptable_head->size -
				  PARTITIONTABLE_END_MARKER_SIZE)
		== PARTITIONTABLE_END_MARKER)) {
		/* Looks like a start, sane length and end of a
		 * partition table, lets check csum etc.
		 */
		struct partitiontable_entry *max_addr =
			(struct partitiontable_entry *)
			((unsigned long)ptable_head + sizeof(*ptable_head) +
			 ptable_head->size);
		unsigned long offset = CONFIG_ETRAX_PTABLE_SECTOR;
		unsigned char *p;
		unsigned long csum = 0;

		ptable = (struct partitiontable_entry *)
			((unsigned long)ptable_head + sizeof(*ptable_head));

		/* Lets be PARANOID, and check the checksum. */
		p = (unsigned char*) ptable;

		while (p <= (unsigned char*)max_addr) {
			csum += *p++;
			csum += *p++;
			csum += *p++;
			csum += *p++;
		}
		ptable_ok = (csum == ptable_head->checksum);

		/* Read the entries and use/show the info.  */
		printk(KERN_INFO "axisflashmap: "
		       "Found a%s partition table at 0x%p-0x%p.\n",
		       (ptable_ok ? " valid" : "n invalid"), ptable_head,
		       max_addr);

		/* We have found a working bootblock.  Now read the
		 * partition table.  Scan the table.  It ends with 0xffffffff.
		 */
		while (ptable_ok
		       && ptable->offset != PARTITIONTABLE_END_MARKER
		       && ptable < max_addr
		       && pidx < MAX_PARTITIONS - 1) {

			axis_partitions[pidx].offset = offset + ptable->offset;
#ifdef CONFIG_ETRAX_NANDFLASH
			if (main_mtd->type == MTD_NANDFLASH) {
				axis_partitions[pidx].size =
					(((ptable+1)->offset ==
					  PARTITIONTABLE_END_MARKER) ?
					  main_mtd->size :
					  ((ptable+1)->offset + offset)) -
					(ptable->offset + offset);

			} else
#endif /* CONFIG_ETRAX_NANDFLASH */
				axis_partitions[pidx].size = ptable->size;
#ifdef CONFIG_ETRAX_NANDBOOT
			/* Save partition number of jffs2 ro partition.
			 * Needed if RAM booting or root file system in RAM.
			 */
			if (!nand_boot &&
			    ram_rootfs_partition < 0 && /* not already set */
			    ptable->type == PARTITION_TYPE_JFFS2 &&
			    (ptable->flags & PARTITION_FLAGS_READONLY_MASK) ==
				PARTITION_FLAGS_READONLY)
				ram_rootfs_partition = pidx;
#endif /* CONFIG_ETRAX_NANDBOOT */
			pidx++;
			ptable++;
		}
	}

	/* Decide whether to use default partition table. */
	/* Only use default table if we actually have a device (main_mtd) */

	partition = &axis_partitions[0];
	if (main_mtd && !ptable_ok) {
		memcpy(axis_partitions, axis_default_partitions,
		       sizeof(axis_default_partitions));
		pidx = NUM_DEFAULT_PARTITIONS;
		ram_rootfs_partition = DEFAULT_ROOTFS_PARTITION_NO;
	}

	/* Add artificial partitions for rootfs if necessary */
	if (romfs_in_flash) {
		/* rootfs is in directly accessible flash memory = NOR flash.
		   Add an overlapping device for the rootfs partition. */
		printk(KERN_INFO "axisflashmap: Adding partition for "
		       "overlapping root file system image\n");
		axis_partitions[pidx].size = romfs_length;
		axis_partitions[pidx].offset = romfs_start - FLASH_CACHED_ADDR;
		axis_partitions[pidx].name = "romfs";
		axis_partitions[pidx].mask_flags |= MTD_WRITEABLE;
		ram_rootfs_partition = -1;
		pidx++;
	} else if (romfs_length && !nand_boot) {
		/* romfs exists in memory, but not in flash, so must be in RAM.
		 * Configure an MTDRAM partition. */
		if (ram_rootfs_partition < 0) {
			/* None set yet, put it at the end */
			ram_rootfs_partition = pidx;
			pidx++;
		}
		printk(KERN_INFO "axisflashmap: Adding partition for "
		       "root file system image in RAM\n");
		axis_partitions[ram_rootfs_partition].size = romfs_length;
		axis_partitions[ram_rootfs_partition].offset = romfs_start;
		axis_partitions[ram_rootfs_partition].name = "romfs";
		axis_partitions[ram_rootfs_partition].mask_flags |=
			MTD_WRITEABLE;
	}

#ifdef CONFIG_ETRAX_AXISFLASHMAP_MTD0WHOLE
	if (main_mtd) {
		main_partition.size = main_mtd->size;
		err = mtd_device_register(main_mtd, &main_partition, 1);
		if (err)
			panic("axisflashmap: Could not initialize "
			      "partition for whole main mtd device!\n");
	}
#endif

	/* Now, register all partitions with mtd.
	 * We do this one at a time so we can slip in an MTDRAM device
	 * in the proper place if required. */

	for (part = 0; part < pidx; part++) {
		if (part == ram_rootfs_partition) {
			/* add MTDRAM partition here */
			struct mtd_info *mtd_ram;

			mtd_ram = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
			if (!mtd_ram)
				panic("axisflashmap: Couldn't allocate memory "
				      "for mtd_info!\n");
			printk(KERN_INFO "axisflashmap: Adding RAM partition "
			       "for rootfs image.\n");
			err = mtdram_init_device(mtd_ram,
						 (void *)(u_int32_t)partition[part].offset,
						 partition[part].size,
						 partition[part].name);
			if (err)
				panic("axisflashmap: Could not initialize "
				      "MTD RAM device!\n");
			/* JFFS2 likes to have an erasesize. Keep potential
			 * JFFS2 rootfs happy by providing one. Since image
			 * was most likely created for main mtd, use that
			 * erasesize, if available. Otherwise, make a guess. */
			mtd_ram->erasesize = (main_mtd ? main_mtd->erasesize :
				CONFIG_ETRAX_PTABLE_SECTOR);
		} else {
			err = mtd_device_register(main_mtd, &partition[part],
						  1);
			if (err)
				panic("axisflashmap: Could not add mtd "
					"partition %d\n", part);
		}
	}

	if (aux_mtd) {
		aux_partition.size = aux_mtd->size;
		err = mtd_device_register(aux_mtd, &aux_partition, 1);
		if (err)
			panic("axisflashmap: Could not initialize "
			      "aux mtd device!\n");

	}

	return err;
}
예제 #29
0
파일: mtdpart.c 프로젝트: DFE/u-boot
static struct mtd_part *add_one_partition(struct mtd_info *master,
		const struct mtd_partition *part, int partno,
		uint64_t cur_offset)
{
	struct mtd_part *slave;

	/* allocate the partition structure */
	slave = kzalloc(sizeof(*slave), GFP_KERNEL);
	if (!slave) {
		printk(KERN_ERR"memory allocation error while creating partitions for \"%s\"\n",
			master->name);
		del_mtd_partitions(master);
		return NULL;
	}
	list_add(&slave->list, &mtd_partitions);

	/* set up the MTD object for this partition */
	slave->mtd.type = master->type;
	slave->mtd.flags = master->flags & ~part->mask_flags;
	slave->mtd.size = part->size;
	slave->mtd.writesize = master->writesize;
	slave->mtd.oobsize = master->oobsize;
	slave->mtd.oobavail = master->oobavail;
	slave->mtd.subpage_sft = master->subpage_sft;

	slave->mtd.name = part->name;
	slave->mtd.owner = master->owner;

	slave->mtd._read = part_read;
	slave->mtd._write = part_write;

	if (master->_read_oob)
		slave->mtd._read_oob = part_read_oob;
	if (master->_write_oob)
		slave->mtd._write_oob = part_write_oob;
	if (master->_read_user_prot_reg)
		slave->mtd._read_user_prot_reg = part_read_user_prot_reg;
	if (master->_read_fact_prot_reg)
		slave->mtd._read_fact_prot_reg = part_read_fact_prot_reg;
	if (master->_write_user_prot_reg)
		slave->mtd._write_user_prot_reg = part_write_user_prot_reg;
	if (master->_lock_user_prot_reg)
		slave->mtd._lock_user_prot_reg = part_lock_user_prot_reg;
	if (master->_get_user_prot_info)
		slave->mtd._get_user_prot_info = part_get_user_prot_info;
	if (master->_get_fact_prot_info)
		slave->mtd._get_fact_prot_info = part_get_fact_prot_info;
	if (master->_sync)
		slave->mtd._sync = part_sync;
	if (master->_lock)
		slave->mtd._lock = part_lock;
	if (master->_unlock)
		slave->mtd._unlock = part_unlock;
	if (master->_block_isbad)
		slave->mtd._block_isbad = part_block_isbad;
	if (master->_block_markbad)
		slave->mtd._block_markbad = part_block_markbad;
	slave->mtd._erase = part_erase;
	slave->master = master;
	slave->offset = part->offset;
	slave->index = partno;

	if (slave->offset == MTDPART_OFS_APPEND)
		slave->offset = cur_offset;
	if (slave->offset == MTDPART_OFS_NXTBLK) {
		slave->offset = cur_offset;
		if (mtd_mod_by_eb(cur_offset, master) != 0) {
			/* Round up to next erasesize */
			slave->offset = (mtd_div_by_eb(cur_offset, master) + 1) * master->erasesize;
			debug("Moving partition %d: 0x%012llx -> 0x%012llx\n",
			      partno, (unsigned long long)cur_offset,
			      (unsigned long long)slave->offset);
		}
	}
	if (slave->mtd.size == MTDPART_SIZ_FULL)
		slave->mtd.size = master->size - slave->offset;

	debug("0x%012llx-0x%012llx : \"%s\"\n",
	      (unsigned long long)slave->offset,
	      (unsigned long long)(slave->offset + slave->mtd.size),
	      slave->mtd.name);

	/* let's do some sanity checks */
	if (slave->offset >= master->size) {
		/* let's register it anyway to preserve ordering */
		slave->offset = 0;
		slave->mtd.size = 0;
		printk(KERN_ERR"mtd: partition \"%s\" is out of reach -- disabled\n",
			part->name);
		goto out_register;
	}
	if (slave->offset + slave->mtd.size > master->size) {
		slave->mtd.size = master->size - slave->offset;
		printk(KERN_WARNING"mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#llx\n",
			part->name, master->name, (unsigned long long)slave->mtd.size);
	}
	if (master->numeraseregions > 1) {
		/* Deal with variable erase size stuff */
		int i, max = master->numeraseregions;
		u64 end = slave->offset + slave->mtd.size;
		struct mtd_erase_region_info *regions = master->eraseregions;

		/* Find the first erase regions which is part of this
		 * partition. */
		for (i = 0; i < max && regions[i].offset <= slave->offset; i++)
			;
		/* The loop searched for the region _behind_ the first one */
		i--;

		/* Pick biggest erasesize */
		for (; i < max && regions[i].offset < end; i++) {
			if (slave->mtd.erasesize < regions[i].erasesize) {
				slave->mtd.erasesize = regions[i].erasesize;
			}
		}
		BUG_ON(slave->mtd.erasesize == 0);
	} else {
		/* Single erase size */
		slave->mtd.erasesize = master->erasesize;
	}

	if ((slave->mtd.flags & MTD_WRITEABLE) &&
	    mtd_mod_by_eb(slave->offset, &slave->mtd)) {
		/* Doesn't start on a boundary of major erase size */
		/* FIXME: Let it be writable if it is on a boundary of
		 * _minor_ erase size though */
		slave->mtd.flags &= ~MTD_WRITEABLE;
		printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n",
			part->name);
	}
	if ((slave->mtd.flags & MTD_WRITEABLE) &&
	    mtd_mod_by_eb(slave->mtd.size, &slave->mtd)) {
		slave->mtd.flags &= ~MTD_WRITEABLE;
		printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n",
			part->name);
	}

	slave->mtd.ecclayout = master->ecclayout;
	if (master->_block_isbad) {
		uint64_t offs = 0;

		while (offs < slave->mtd.size) {
			if (mtd_block_isbad(master, offs + slave->offset))
				slave->mtd.ecc_stats.badblocks++;
			offs += slave->mtd.erasesize;
		}
	}

out_register:
	if (part->mtdp) {
		/* store the object pointer (caller may or may not register it*/
		*part->mtdp = &slave->mtd;
		slave->registered = 0;
	} else {
		/* register our partition */
		add_mtd_device(&slave->mtd);
		slave->registered = 1;
	}
	return slave;
}
예제 #30
0
/* Called with 'buf_size == 0' if buf is in fact a pointer _directly_ into
   the flash, XIP-style */
static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
				  unsigned char *buf, uint32_t buf_size, struct jffs2_summary *s) {
	struct jffs2_unknown_node *node;
	struct jffs2_unknown_node crcnode;
	uint32_t ofs, prevofs, max_ofs;
	uint32_t hdr_crc, buf_ofs, buf_len;
	int err;
	int noise = 0;


#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
	int cleanmarkerfound = 0;
#endif

	ofs = jeb->offset;
	prevofs = jeb->offset - 1;

	D1(printk(KERN_DEBUG "jffs2_scan_eraseblock(): Scanning block at 0x%x\n", ofs));

#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
	if (jffs2_cleanmarker_oob(c)) {
		int ret;

		if (mtd_block_isbad(c->mtd, jeb->offset))
			return BLK_STATE_BADBLOCK;

		ret = jffs2_check_nand_cleanmarker(c, jeb);
		D2(printk(KERN_NOTICE "jffs_check_nand_cleanmarker returned %d\n",ret));

		/* Even if it's not found, we still scan to see
		   if the block is empty. We use this information
		   to decide whether to erase it or not. */
		switch (ret) {
		case 0:		cleanmarkerfound = 1; break;
		case 1: 	break;
		default: 	return ret;
		}
	}
#endif

	if (jffs2_sum_active()) {
		struct jffs2_sum_marker *sm;
		void *sumptr = NULL;
		uint32_t sumlen;
	      
		if (!buf_size) {
			/* XIP case. Just look, point at the summary if it's there */
			sm = (void *)buf + c->sector_size - sizeof(*sm);
			if (je32_to_cpu(sm->magic) == JFFS2_SUM_MAGIC) {
				sumptr = buf + je32_to_cpu(sm->offset);
				sumlen = c->sector_size - je32_to_cpu(sm->offset);
			}
		} else {
			/* If NAND flash, read a whole page of it. Else just the end */
			if (c->wbuf_pagesize)
				buf_len = c->wbuf_pagesize;
			else
				buf_len = sizeof(*sm);

			/* Read as much as we want into the _end_ of the preallocated buffer */
			err = jffs2_fill_scan_buf(c, buf + buf_size - buf_len, 
						  jeb->offset + c->sector_size - buf_len,
						  buf_len);				
			if (err)
				return err;

			sm = (void *)buf + buf_size - sizeof(*sm);
			if (je32_to_cpu(sm->magic) == JFFS2_SUM_MAGIC) {
				sumlen = c->sector_size - je32_to_cpu(sm->offset);
				sumptr = buf + buf_size - sumlen;

				/* Now, make sure the summary itself is available */
				if (sumlen > buf_size) {
					/* Need to kmalloc for this. */
					sumptr = kmalloc(sumlen, GFP_KERNEL);
					if (!sumptr)
						return -ENOMEM;
					memcpy(sumptr + sumlen - buf_len, buf + buf_size - buf_len, buf_len);
				}
				if (buf_len < sumlen) {
					/* Need to read more so that the entire summary node is present */
					err = jffs2_fill_scan_buf(c, sumptr, 
								  jeb->offset + c->sector_size - sumlen,
								  sumlen - buf_len);				
					if (err)
						return err;
				}
			}

		}

		if (sumptr) {
			err = jffs2_sum_scan_sumnode(c, jeb, sumptr, sumlen, &pseudo_random);

			if (buf_size && sumlen > buf_size)
				kfree(sumptr);
			/* If it returns with a real error, bail. 
			   If it returns positive, that's a block classification
			   (i.e. BLK_STATE_xxx) so return that too.
			   If it returns zero, fall through to full scan. */
			if (err)
				return err;
		}
	}

	buf_ofs = jeb->offset;

	if (!buf_size) {
		/* This is the XIP case -- we're reading _directly_ from the flash chip */
		buf_len = c->sector_size;
	} else {
		buf_len = EMPTY_SCAN_SIZE(c->sector_size);
		err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len);
		if (err)
			return err;
	}

	/* We temporarily use 'ofs' as a pointer into the buffer/jeb */
	ofs = 0;
	max_ofs = EMPTY_SCAN_SIZE(c->sector_size);
	/* Scan only EMPTY_SCAN_SIZE of 0xFF before declaring it's empty */
	while(ofs < max_ofs && *(uint32_t *)(&buf[ofs]) == 0xFFFFFFFF)
		ofs += 4;

	if (ofs == max_ofs) {
#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
		if (jffs2_cleanmarker_oob(c)) {
			/* scan oob, take care of cleanmarker */
			int ret = jffs2_check_oob_empty(c, jeb, cleanmarkerfound);
			D2(printk(KERN_NOTICE "jffs2_check_oob_empty returned %d\n",ret));
			switch (ret) {
			case 0:		return cleanmarkerfound ? BLK_STATE_CLEANMARKER : BLK_STATE_ALLFF;
			case 1: 	return BLK_STATE_ALLDIRTY;
			default: 	return ret;
			}
		}
#endif
		D1(printk(KERN_DEBUG "Block at 0x%08x is empty (erased)\n", jeb->offset));
		if (c->cleanmarker_size == 0)
			return BLK_STATE_CLEANMARKER;	/* don't bother with re-erase */
		else
			return BLK_STATE_ALLFF;	/* OK to erase if all blocks are like this */
	}
	if (ofs) {
		D1(printk(KERN_DEBUG "Free space at %08x ends at %08x\n", jeb->offset,
			  jeb->offset + ofs));
		if ((err = jffs2_prealloc_raw_node_refs(c, jeb, 1)))
			return err;
		if ((err = jffs2_scan_dirty_space(c, jeb, ofs)))
			return err;
	}

	/* Now ofs is a complete physical flash offset as it always was... */
	ofs += jeb->offset;

	noise = 10;

	dbg_summary("no summary found in jeb 0x%08x. Apply original scan.\n",jeb->offset);

scan_more:
	while(ofs < jeb->offset + c->sector_size) {

		jffs2_dbg_acct_paranoia_check_nolock(c, jeb);

		/* Make sure there are node refs available for use */
		err = jffs2_prealloc_raw_node_refs(c, jeb, 2);
		if (err)
			return err;

		cond_resched();

		if (ofs & 3) {
			printk(KERN_WARNING "Eep. ofs 0x%08x not word-aligned!\n", ofs);
			ofs = PAD(ofs);
			continue;
		}
		if (ofs == prevofs) {
			printk(KERN_WARNING "ofs 0x%08x has already been seen. Skipping\n", ofs);
			if ((err = jffs2_scan_dirty_space(c, jeb, 4)))
				return err;
			ofs += 4;
			continue;
		}
		prevofs = ofs;

		if (jeb->offset + c->sector_size < ofs + sizeof(*node)) {
			D1(printk(KERN_DEBUG "Fewer than %zd bytes left to end of block. (%x+%x<%x+%zx) Not reading\n", sizeof(struct jffs2_unknown_node),
				  jeb->offset, c->sector_size, ofs, sizeof(*node)));
			if ((err = jffs2_scan_dirty_space(c, jeb, (jeb->offset + c->sector_size)-ofs)))
				return err;
			break;
		}

		if (buf_ofs + buf_len < ofs + sizeof(*node)) {
			buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
			D1(printk(KERN_DEBUG "Fewer than %zd bytes (node header) left to end of buf. Reading 0x%x at 0x%08x\n",
				  sizeof(struct jffs2_unknown_node), buf_len, ofs));
			err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
			if (err)
				return err;
			buf_ofs = ofs;
		}

		node = (struct jffs2_unknown_node *)&buf[ofs-buf_ofs];

		if (*(uint32_t *)(&buf[ofs-buf_ofs]) == 0xffffffff) {
			uint32_t inbuf_ofs;
			uint32_t empty_start, scan_end;

			empty_start = ofs;
			ofs += 4;
			scan_end = min_t(uint32_t, EMPTY_SCAN_SIZE(c->sector_size)/8, buf_len);

			D1(printk(KERN_DEBUG "Found empty flash at 0x%08x\n", ofs));
		more_empty:
			inbuf_ofs = ofs - buf_ofs;
			while (inbuf_ofs < scan_end) {
				if (unlikely(*(uint32_t *)(&buf[inbuf_ofs]) != 0xffffffff)) {
					printk(KERN_WARNING "Empty flash at 0x%08x ends at 0x%08x\n",
					       empty_start, ofs);
					if ((err = jffs2_scan_dirty_space(c, jeb, ofs-empty_start)))
						return err;
					goto scan_more;
				}

				inbuf_ofs+=4;
				ofs += 4;
			}
			/* Ran off end. */
			D1(printk(KERN_DEBUG "Empty flash to end of buffer at 0x%08x\n", ofs));

			/* If we're only checking the beginning of a block with a cleanmarker,
			   bail now */
			if (buf_ofs == jeb->offset && jeb->used_size == PAD(c->cleanmarker_size) &&
			    c->cleanmarker_size && !jeb->dirty_size && !ref_next(jeb->first_node)) {
				D1(printk(KERN_DEBUG "%d bytes at start of block seems clean... assuming all clean\n", EMPTY_SCAN_SIZE(c->sector_size)));
				return BLK_STATE_CLEANMARKER;
			}
			if (!buf_size && (scan_end != buf_len)) {/* XIP/point case */
				scan_end = buf_len;
				goto more_empty;
			}
			
			/* See how much more there is to read in this eraseblock... */
			buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
			if (!buf_len) {
				/* No more to read. Break out of main loop without marking
				   this range of empty space as dirty (because it's not) */
				D1(printk(KERN_DEBUG "Empty flash at %08x runs to end of block. Treating as free_space\n",
					  empty_start));
				break;
			}
			/* point never reaches here */
			scan_end = buf_len;
			D1(printk(KERN_DEBUG "Reading another 0x%x at 0x%08x\n", buf_len, ofs));
			err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
			if (err)
				return err;
			buf_ofs = ofs;
			goto more_empty;
		}

		if (ofs == jeb->offset && je16_to_cpu(node->magic) == KSAMTIB_CIGAM_2SFFJ) {
			printk(KERN_WARNING "Magic bitmask is backwards at offset 0x%08x. Wrong endian filesystem?\n", ofs);
			if ((err = jffs2_scan_dirty_space(c, jeb, 4)))
				return err;
			ofs += 4;
			continue;
		}
		if (je16_to_cpu(node->magic) == JFFS2_DIRTY_BITMASK) {
			D1(printk(KERN_DEBUG "Dirty bitmask at 0x%08x\n", ofs));
			if ((err = jffs2_scan_dirty_space(c, jeb, 4)))
				return err;
			ofs += 4;
			continue;
		}
		if (je16_to_cpu(node->magic) == JFFS2_OLD_MAGIC_BITMASK) {
			printk(KERN_WARNING "Old JFFS2 bitmask found at 0x%08x\n", ofs);
			printk(KERN_WARNING "You cannot use older JFFS2 filesystems with newer kernels\n");
			if ((err = jffs2_scan_dirty_space(c, jeb, 4)))
				return err;
			ofs += 4;
			continue;
		}
		if (je16_to_cpu(node->magic) != JFFS2_MAGIC_BITMASK) {
			/* OK. We're out of possibilities. Whinge and move on */
			noisy_printk(&noise, "jffs2_scan_eraseblock(): Magic bitmask 0x%04x not found at 0x%08x: 0x%04x instead\n",
				     JFFS2_MAGIC_BITMASK, ofs,
				     je16_to_cpu(node->magic));
			if ((err = jffs2_scan_dirty_space(c, jeb, 4)))
				return err;
			ofs += 4;
			continue;
		}
		/* We seem to have a node of sorts. Check the CRC */
		crcnode.magic = node->magic;
		crcnode.nodetype = cpu_to_je16( je16_to_cpu(node->nodetype) | JFFS2_NODE_ACCURATE);
		crcnode.totlen = node->totlen;
		hdr_crc = crc32(0, &crcnode, sizeof(crcnode)-4);

		if (hdr_crc != je32_to_cpu(node->hdr_crc)) {
			noisy_printk(&noise, "jffs2_scan_eraseblock(): Node at 0x%08x {0x%04x, 0x%04x, 0x%08x) has invalid CRC 0x%08x (calculated 0x%08x)\n",
				     ofs, je16_to_cpu(node->magic),
				     je16_to_cpu(node->nodetype),
				     je32_to_cpu(node->totlen),
				     je32_to_cpu(node->hdr_crc),
				     hdr_crc);
			if ((err = jffs2_scan_dirty_space(c, jeb, 4)))
				return err;
			ofs += 4;
			continue;
		}

		if (ofs + je32_to_cpu(node->totlen) > jeb->offset + c->sector_size) {
			/* Eep. Node goes over the end of the erase block. */
			printk(KERN_WARNING "Node at 0x%08x with length 0x%08x would run over the end of the erase block\n",
			       ofs, je32_to_cpu(node->totlen));
			printk(KERN_WARNING "Perhaps the file system was created with the wrong erase size?\n");
			if ((err = jffs2_scan_dirty_space(c, jeb, 4)))
				return err;
			ofs += 4;
			continue;
		}

		if (!(je16_to_cpu(node->nodetype) & JFFS2_NODE_ACCURATE)) {
			/* Wheee. This is an obsoleted node */
			D2(printk(KERN_DEBUG "Node at 0x%08x is obsolete. Skipping\n", ofs));
			if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(node->totlen)))))
				return err;
			ofs += PAD(je32_to_cpu(node->totlen));
			continue;
		}

		switch(je16_to_cpu(node->nodetype)) {
		case JFFS2_NODETYPE_INODE:
			if (buf_ofs + buf_len < ofs + sizeof(struct jffs2_raw_inode)) {
				buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
				D1(printk(KERN_DEBUG "Fewer than %zd bytes (inode node) left to end of buf. Reading 0x%x at 0x%08x\n",
					  sizeof(struct jffs2_raw_inode), buf_len, ofs));
				err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
				if (err)
					return err;
				buf_ofs = ofs;
				node = (void *)buf;
			}
			err = jffs2_scan_inode_node(c, jeb, (void *)node, ofs, s);
			if (err) return err;
			ofs += PAD(je32_to_cpu(node->totlen));
			break;

		case JFFS2_NODETYPE_DIRENT:
			if (buf_ofs + buf_len < ofs + je32_to_cpu(node->totlen)) {
				buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
				D1(printk(KERN_DEBUG "Fewer than %d bytes (dirent node) left to end of buf. Reading 0x%x at 0x%08x\n",
					  je32_to_cpu(node->totlen), buf_len, ofs));
				err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
				if (err)
					return err;
				buf_ofs = ofs;
				node = (void *)buf;
			}
			err = jffs2_scan_dirent_node(c, jeb, (void *)node, ofs, s);
			if (err) return err;
			ofs += PAD(je32_to_cpu(node->totlen));
			break;

#ifdef CONFIG_JFFS2_FS_XATTR
		case JFFS2_NODETYPE_XATTR:
			if (buf_ofs + buf_len < ofs + je32_to_cpu(node->totlen)) {
				buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
				D1(printk(KERN_DEBUG "Fewer than %d bytes (xattr node)"
					  " left to end of buf. Reading 0x%x at 0x%08x\n",
					  je32_to_cpu(node->totlen), buf_len, ofs));
				err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
				if (err)
					return err;
				buf_ofs = ofs;
				node = (void *)buf;
			}
			err = jffs2_scan_xattr_node(c, jeb, (void *)node, ofs, s);
			if (err)
				return err;
			ofs += PAD(je32_to_cpu(node->totlen));
			break;
		case JFFS2_NODETYPE_XREF:
			if (buf_ofs + buf_len < ofs + je32_to_cpu(node->totlen)) {
				buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
				D1(printk(KERN_DEBUG "Fewer than %d bytes (xref node)"
					  " left to end of buf. Reading 0x%x at 0x%08x\n",
					  je32_to_cpu(node->totlen), buf_len, ofs));
				err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
				if (err)
					return err;
				buf_ofs = ofs;
				node = (void *)buf;
			}
			err = jffs2_scan_xref_node(c, jeb, (void *)node, ofs, s);
			if (err)
				return err;
			ofs += PAD(je32_to_cpu(node->totlen));
			break;
#endif	/* CONFIG_JFFS2_FS_XATTR */

		case JFFS2_NODETYPE_CLEANMARKER:
			D1(printk(KERN_DEBUG "CLEANMARKER node found at 0x%08x\n", ofs));
			if (je32_to_cpu(node->totlen) != c->cleanmarker_size) {
				printk(KERN_NOTICE "CLEANMARKER node found at 0x%08x has totlen 0x%x != normal 0x%x\n",
				       ofs, je32_to_cpu(node->totlen), c->cleanmarker_size);
				if ((err = jffs2_scan_dirty_space(c, jeb, PAD(sizeof(struct jffs2_unknown_node)))))
					return err;
				ofs += PAD(sizeof(struct jffs2_unknown_node));
			} else if (jeb->first_node) {
				printk(KERN_NOTICE "CLEANMARKER node found at 0x%08x, not first node in block (0x%08x)\n", ofs, jeb->offset);
				if ((err = jffs2_scan_dirty_space(c, jeb, PAD(sizeof(struct jffs2_unknown_node)))))
					return err;
				ofs += PAD(sizeof(struct jffs2_unknown_node));
			} else {
				jffs2_link_node_ref(c, jeb, ofs | REF_NORMAL, c->cleanmarker_size, NULL);

				ofs += PAD(c->cleanmarker_size);
			}
			break;

		case JFFS2_NODETYPE_PADDING:
			if (jffs2_sum_active())
				jffs2_sum_add_padding_mem(s, je32_to_cpu(node->totlen));
			if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(node->totlen)))))
				return err;
			ofs += PAD(je32_to_cpu(node->totlen));
			break;

		default:
			switch (je16_to_cpu(node->nodetype) & JFFS2_COMPAT_MASK) {
			case JFFS2_FEATURE_ROCOMPAT:
				printk(KERN_NOTICE "Read-only compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs);
				c->flags |= JFFS2_SB_FLAG_RO;
				if (!(jffs2_is_readonly(c)))
					return -EROFS;
				if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(node->totlen)))))
					return err;
				ofs += PAD(je32_to_cpu(node->totlen));
				break;

			case JFFS2_FEATURE_INCOMPAT:
				printk(KERN_NOTICE "Incompatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs);
				return -EINVAL;

			case JFFS2_FEATURE_RWCOMPAT_DELETE:
				D1(printk(KERN_NOTICE "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs));
				if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(node->totlen)))))
					return err;
				ofs += PAD(je32_to_cpu(node->totlen));
				break;

			case JFFS2_FEATURE_RWCOMPAT_COPY: {
				D1(printk(KERN_NOTICE "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs));

				jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, PAD(je32_to_cpu(node->totlen)), NULL);

				/* We can't summarise nodes we don't grok */
				jffs2_sum_disable_collecting(s);
				ofs += PAD(je32_to_cpu(node->totlen));
				break;
				}
			}
		}
	}

	if (jffs2_sum_active()) {
		if (PAD(s->sum_size + JFFS2_SUMMARY_FRAME_SIZE) > jeb->free_size) {
			dbg_summary("There is not enough space for "
				"summary information, disabling for this jeb!\n");
			jffs2_sum_disable_collecting(s);
		}
	}

	D1(printk(KERN_DEBUG "Block at 0x%08x: free 0x%08x, dirty 0x%08x, unchecked 0x%08x, used 0x%08x, wasted 0x%08x\n",
		  jeb->offset,jeb->free_size, jeb->dirty_size, jeb->unchecked_size, jeb->used_size, jeb->wasted_size));
	
	/* mark_node_obsolete can add to wasted !! */
	if (jeb->wasted_size) {
		jeb->dirty_size += jeb->wasted_size;
		c->dirty_size += jeb->wasted_size;
		c->wasted_size -= jeb->wasted_size;
		jeb->wasted_size = 0;
	}

	return jffs2_scan_classify_jeb(c, jeb);
}