示例#1
0
static int program_sdata(uffs_Device *dev, int block, int page)
{
	uffs_FileEmu *emu = (uffs_FileEmu *)(dev->attr->_private);
	int abs_page;
	struct uffs_StorageAttrSt *attr = dev->attr;
	u8 ecc_buf[RS_ECC_SIZE];
	int writtern;

	// In the real world, MLC controller will generate RS-ECC code in serial data buffer
	// and might start auto programing NAND flash. Here, we use software ECC to emulate RS-ECC.
	memset(ecc_buf, 0xFF, sizeof(ecc_buf));
	uffs_EccMake(g_sdata_buf, attr->page_data_size, ecc_buf);
	feed_sdata(ecc_buf, RS_ECC_SIZE);

	uffs_Assert(g_sdata_buf_pointer == PAGE_FULL_SIZE, "Serial Data Buffer is not fully filled !!");

	abs_page = attr->pages_per_block * block + page;

	fseek(emu->fp, abs_page * PAGE_FULL_SIZE, SEEK_SET);
	writtern = fwrite(g_sdata_buf, 1, PAGE_FULL_SIZE, emu->fp);

	return (writtern == PAGE_FULL_SIZE) ? UFFS_FLASH_NO_ERR : UFFS_FLASH_IO_ERR;
}
示例#2
0
static int load_sdata(uffs_Device *dev, int block, int page)
{
	uffs_FileEmu *emu = (uffs_FileEmu *)(dev->attr->_private);
	int abs_page;
	struct uffs_StorageAttrSt *attr = dev->attr;
	int nread;
	int ret;
	u8 ecc_buf[RS_ECC_SIZE];
	u8 *ecc_store;

	abs_page = attr->pages_per_block * block + page;

	fseek(emu->fp, abs_page * PAGE_FULL_SIZE, SEEK_SET);
	nread = fread(g_sdata_buf, 1, PAGE_FULL_SIZE, emu->fp);
	g_sdata_buf_pointer = 0;

	ret = ((nread == PAGE_FULL_SIZE) ? UFFS_FLASH_NO_ERR : UFFS_FLASH_IO_ERR);

	if (ret == UFFS_FLASH_NO_ERR) {

		// Perform ECC check & correction
		// In the real world, this is done by MLC controller hardware
		memset(ecc_buf, 0xFF, RS_ECC_SIZE);
		uffs_EccMake(g_sdata_buf, attr->page_data_size, ecc_buf);

		ecc_store = g_sdata_buf + PAGE_FULL_SIZE - RS_ECC_SIZE;

		ret = uffs_EccCorrect(g_sdata_buf, attr->page_data_size, ecc_store, ecc_buf);

		ret = (ret < 0 ? UFFS_FLASH_ECC_FAIL :
				(ret > 0 ? UFFS_FLASH_ECC_OK : UFFS_FLASH_NO_ERR));
		
	}

	return ret;
}
static int femu_hw_WritePageWithLayout(uffs_Device *dev, u32 block, u32 page,
							const u8 *data, int data_len, const u8 *ecc, const uffs_TagStore *ts)
{
	int written;
	int abs_page;
	int full_page_size;
	uffs_FileEmu *emu;
	struct uffs_StorageAttrSt *attr = dev->attr;
	u8 spare[UFFS_MAX_SPARE_SIZE];
	u8 ecc_buf[UFFS_MAX_ECC_SIZE];
	int spare_len;


	emu = (uffs_FileEmu *)(dev->attr->_private);

	if (!emu || !(emu->fp)) {
		goto err;
	}

	abs_page = attr->pages_per_block * block + page;
	full_page_size = attr->page_data_size + attr->spare_size;

	if (data && data_len > 0) {
		if (data_len > attr->page_data_size)
			goto err;

		emu->em_monitor_page[abs_page]++;
		if (emu->em_monitor_page[abs_page] > PAGE_DATA_WRITE_COUNT_LIMIT) {
			MSG("Warrning: block %d page %d exceed it's maximum write time!", block, page);
			goto err;
		}
		
		fseek(emu->fp, abs_page * full_page_size, SEEK_SET);

		written = fwrite(data, 1, data_len, emu->fp);
		
		if (written != data_len) {
			MSG("write page I/O error ?");
			goto err;
		}

		dev->st.page_write_count++;
		dev->st.io_write += written;

	}

	if (ts) {

		emu->em_monitor_spare[abs_page]++;
		if (emu->em_monitor_spare[abs_page] > PAGE_SPARE_WRITE_COUNT_LIMIT) {
			MSG("Warrning: block %d page %d (spare) exceed it's maximum write time!", block, page);
			goto err;
		}

		uffs_Assert(data != NULL, "BUG: Write spare without data ?");
		uffs_EccMake(data, data_len, ecc_buf);
		uffs_FlashMakeSpare(dev, ts, ecc_buf, spare);
		spare_len = dev->mem.spare_data_size;
		
		fseek(emu->fp, abs_page * full_page_size + attr->page_data_size, SEEK_SET);
		written = fwrite(spare, 1, spare_len, emu->fp);
		if (written != spare_len) {
			MSG("write spare I/O error ?");
			goto err;
		}

		dev->st.spare_write_count++;
		dev->st.io_write += written;
	}

	if (data == NULL && ts == NULL) {
		// mark bad block
		fseek(emu->fp, abs_page * full_page_size + attr->page_data_size + attr->block_status_offs, SEEK_SET);
		written = fwrite("\0", 1, 1, emu->fp);
		if (written != 1) {
			MSG("write bad block mark I/O error ?");
			goto err;
		}
		dev->st.io_write++;
	}

	fflush(emu->fp);
	return UFFS_FLASH_NO_ERR;
err:
	fflush(emu->fp);
	return UFFS_FLASH_IO_ERR;
}
static URET femu_hw_ReadPageWithLayout(uffs_Device *dev, u32 block, u32 page, u8* data, int data_len, u8 *ecc,
									uffs_TagStore *ts, u8 *ecc_store)
{
	int nread;
	uffs_FileEmu *emu;
	int abs_page;
	int full_page_size;
	struct uffs_StorageAttrSt *attr = dev->attr;
	unsigned char status;
	u8 spare[UFFS_MAX_SPARE_SIZE];
	int spare_len;

	emu = (uffs_FileEmu *)(dev->attr->_private);

	if (!emu || !(emu->fp)) {
		goto err;
	}

	abs_page = attr->pages_per_block * block + page;
	full_page_size = attr->page_data_size + attr->spare_size;

	if (data && data_len > 0) {
		if (data_len > attr->page_data_size)
			goto err;

		fseek(emu->fp, abs_page * full_page_size, SEEK_SET);
		nread = fread(data, 1, data_len, emu->fp);

		if (nread != data_len) {
			MSG("read page I/O error ?");
			goto err;
		}
		dev->st.io_read += nread;
		dev->st.page_read_count++;

		if (ecc) {
			// calculate ECC for data
			uffs_EccMake(data, data_len, ecc);
		}
	}

	if (ts) {

		spare_len = dev->mem.spare_data_size;
		fseek(emu->fp, abs_page * full_page_size + attr->page_data_size, SEEK_SET);
		nread = fread(spare, 1, spare_len, emu->fp);

		if (nread != spare_len) {
			MSG("read page spare I/O error ?");
			goto err;
		}

		// unload ts and ecc from spare
		uffs_FlashUnloadSpare(dev, spare, ts, ecc_store);

		dev->st.io_read += nread;
		dev->st.spare_read_count++;
	}

	if (data == NULL && ts == NULL) {
		// read bad block mark
		fseek(emu->fp, abs_page * full_page_size + attr->page_data_size + attr->block_status_offs, SEEK_SET);
		nread = fread(&status, 1, 1, emu->fp);

		if (nread != 1) {
			MSG("read badblock mark I/O error ?");
			goto err;
		}
		dev->st.io_read++;

		return status == 0xFF ? UFFS_FLASH_NO_ERR : UFFS_FLASH_BAD_BLK;
	}

	return UFFS_FLASH_NO_ERR;
err:
	return UFFS_FLASH_IO_ERR;
}
/**
 * write the whole page, include data and tag
 *
 * \param[in] dev uffs device
 * \param[in] block
 * \param[in] page
 * \param[in] buf contains data to be wrote
 * \param[in] tag tag to be wrote
 *
 * \return	#UFFS_FLASH_NO_ERR: success.
 *			#UFFS_FLASH_IO_ERR: I/O error, expect retry ?
 *			#UFFS_FLASH_BAD_BLK: a new bad block detected.
 */
int uffs_FlashWritePageCombine(uffs_Device *dev,
							   int block, int page,
							   uffs_Buf *buf, uffs_Tags *tag)
{
	uffs_FlashOps *ops = dev->ops;
	int size = dev->com.pg_size;
	u8 ecc_buf[UFFS_MAX_ECC_SIZE];
	u8 *ecc = NULL;
	u8 *spare;
	struct uffs_MiniHeaderSt *header;
	int ret = UFFS_FLASH_UNKNOWN_ERR;
	UBOOL is_bad = U_FALSE;
	uffs_Buf *verify_buf;
#ifdef CONFIG_PAGE_WRITE_VERIFY
	uffs_Tags chk_tag;
#endif
	
	spare = (u8 *) uffs_PoolGet(SPOOL(dev));
	if (spare == NULL)
		goto ext;

	// setup header
	header = HEADER(buf);
	memset(header, 0xFF, sizeof(struct uffs_MiniHeaderSt));
	header->status = 0;
#ifdef CONFIG_ENABLE_PAGE_DATA_CRC
	header->crc = uffs_crc16sum(buf->data, size - sizeof(struct uffs_MiniHeaderSt));
#endif

	// setup tag
	TAG_DIRTY_BIT(tag) = TAG_DIRTY;		//!< set dirty bit
	TAG_VALID_BIT(tag) = TAG_VALID;		//!< set valid bit
	SEAL_TAG(tag);						//!< seal tag (the real seal byte will be set in uffs_FlashMakeSpare())

	if (dev->attr->ecc_opt != UFFS_ECC_NONE)
		TagMakeEcc(&tag->s);
	else
		tag->s.tag_ecc = TAG_ECC_DEFAULT;
	
	if (dev->attr->ecc_opt == UFFS_ECC_SOFT) {
		uffs_EccMake(buf->header, size, ecc_buf);
		ecc = ecc_buf;
	}
	else if (dev->attr->ecc_opt == UFFS_ECC_HW) {
		ecc = ecc_buf;
	}

	if (ops->WritePageWithLayout) {
		ret = ops->WritePageWithLayout(dev, block, page,
							buf->header, size, ecc, &tag->s);
	}
	else {

		if (!uffs_Assert(!(dev->attr->layout_opt == UFFS_LAYOUT_FLASH ||
					dev->attr->ecc_opt == UFFS_ECC_HW ||
					dev->attr->ecc_opt == UFFS_ECC_HW_AUTO), "WritePageWithLayout() not implemented ?")) {
			ret = UFFS_FLASH_IO_ERR;
			goto ext;
		}

		uffs_FlashMakeSpare(dev, &tag->s, ecc, spare);

		ret = ops->WritePage(dev, block, page, buf->header, size, spare, dev->mem.spare_data_size);

	}
	
	if (UFFS_FLASH_IS_BAD_BLOCK(ret))
		is_bad = U_TRUE;

	if (UFFS_FLASH_HAVE_ERR(ret))
		goto ext;

#ifdef CONFIG_PAGE_WRITE_VERIFY
	verify_buf = uffs_BufClone(dev, NULL);
	if (verify_buf) {
		ret = uffs_FlashReadPage(dev, block, page, verify_buf, U_FALSE);
		if (!UFFS_FLASH_HAVE_ERR(ret)) {
			if (memcmp(buf->header, verify_buf->header, size) != 0) {
				uffs_Perror(UFFS_MSG_NORMAL,
							"Page write verify failed (block %d page %d)",
							block, page);
				ret = UFFS_FLASH_BAD_BLK;
			}
		}

		uffs_BufFreeClone(dev, verify_buf);
	}
	else {
		uffs_Perror(UFFS_MSG_SERIOUS, "Insufficient buf, clone buf failed.");
	}

	ret = uffs_FlashReadPageTag(dev, block, page, &chk_tag);
	if (UFFS_FLASH_HAVE_ERR(ret))
		goto ext;
	
	if (memcmp(&tag->s, &chk_tag.s, sizeof(uffs_TagStore)) != 0) {
		uffs_Perror(UFFS_MSG_NORMAL, "Page tag write verify failed (block %d page %d)",
					block, page);
		ret = UFFS_FLASH_BAD_BLK;
	}

	if (UFFS_FLASH_IS_BAD_BLOCK(ret))
		is_bad = U_TRUE;
	
#endif
ext:
	if (is_bad)
		uffs_BadBlockAdd(dev, block);

	if (spare)
		uffs_PoolPut(SPOOL(dev), spare);

	return ret;
}
/**
 * Read page data to buf (do ECC error correction if needed)
 * \param[in] dev uffs device
 * \param[in] block flash block num
 * \param[in] page flash page num of the block
 * \param[out] buf holding the read out data
 * \param[in] skip_ecc skip ecc when reading data from flash
 *
 * \return	#UFFS_FLASH_NO_ERR: success and/or has no flip bits.
 *			#UFFS_FLASH_IO_ERR: I/O error, expect retry ?
 *			#UFFS_FLASH_ECC_FAIL: spare data has flip bits and ecc correct failed.
 *			#UFFS_FLASH_ECC_OK: spare data has flip bits and corrected by ecc.
 *			#UFFS_FLASH_CRC_ERR: CRC verification failed.
 *			#UFFS_FLASH_UNKNOWN_ERR:
 *
 * \note if skip_ecc is U_TRUE, skip CRC as well.
 */
int uffs_FlashReadPage(uffs_Device *dev, int block, int page, uffs_Buf *buf, UBOOL skip_ecc)
{
	uffs_FlashOps *ops = dev->ops;
	struct uffs_StorageAttrSt *attr = dev->attr;
	int size = dev->com.pg_size;
	u8 ecc_buf[UFFS_MAX_ECC_SIZE];
	u8 ecc_store[UFFS_MAX_ECC_SIZE];
	UBOOL is_bad = U_FALSE;
#ifdef CONFIG_ENABLE_PAGE_DATA_CRC
	UBOOL crc_ok = U_TRUE;
#endif
	u8 * spare;

	int ret = UFFS_FLASH_UNKNOWN_ERR;

	spare = (u8 *) uffs_PoolGet(SPOOL(dev));
	if (spare == NULL)
		goto ext;

	if (ops->ReadPageWithLayout) {
		if (skip_ecc)
			ret = ops->ReadPageWithLayout(dev, block, page, buf->header, size, NULL, NULL, NULL);
		else
			ret = ops->ReadPageWithLayout(dev, block, page, buf->header, size, ecc_buf, NULL, ecc_store);
	}
	else {
		if (skip_ecc)
			ret = ops->ReadPage(dev, block, page, buf->header, size, NULL, NULL, 0);
		else
			ret = ops->ReadPage(dev, block, page, buf->header, size, ecc_buf, spare, dev->mem.spare_data_size);
	}

	if (UFFS_FLASH_IS_BAD_BLOCK(ret))
		is_bad = U_TRUE;

	if (UFFS_FLASH_HAVE_ERR(ret))
		goto ext;

#ifdef CONFIG_ENABLE_PAGE_DATA_CRC
	if (!skip_ecc) {
		crc_ok = (HEADER(buf)->crc == uffs_crc16sum(buf->data, size - sizeof(struct uffs_MiniHeaderSt)) ? U_TRUE : U_FALSE);

		if (crc_ok)
			goto ext;	// CRC is matched, no need to do ECC correction.
		else {
			if (dev->attr->ecc_opt == UFFS_ECC_NONE || dev->attr->ecc_opt == UFFS_ECC_HW_AUTO) {
				// ECC is not enabled or ecc correction already done, error return immediately,
				// otherwise, we try CRC check again after ecc correction.
				ret = UFFS_FLASH_CRC_ERR;
				goto ext;
			}
		}
	}
#endif

	// make ECC for UFFS_ECC_SOFT
	if (attr->ecc_opt == UFFS_ECC_SOFT && !skip_ecc)
		uffs_EccMake(buf->header, size, ecc_buf);

	// unload ecc_store if driver doesn't do the layout
	if (ops->ReadPageWithLayout == NULL) {
		if (!skip_ecc && (attr->ecc_opt == UFFS_ECC_SOFT || attr->ecc_opt == UFFS_ECC_HW))
			uffs_FlashUnloadSpare(dev, spare, NULL, ecc_store);
	}

	// check page data ecc
	if (!skip_ecc && (dev->attr->ecc_opt == UFFS_ECC_SOFT || dev->attr->ecc_opt == UFFS_ECC_HW)) {

		ret = uffs_EccCorrect(buf->header, size, ecc_store, ecc_buf);
		ret = (ret < 0 ? UFFS_FLASH_ECC_FAIL :
				(ret > 0 ? UFFS_FLASH_ECC_OK : UFFS_FLASH_NO_ERR));

		if (UFFS_FLASH_IS_BAD_BLOCK(ret))
			is_bad = U_TRUE;

		if (UFFS_FLASH_HAVE_ERR(ret))
			goto ext;
	}

#ifdef CONFIG_ENABLE_PAGE_DATA_CRC
	if (!skip_ecc && !UFFS_FLASH_HAVE_ERR(ret)) {
		// Everything seems ok, do CRC check again.
		if (HEADER(buf)->crc == uffs_crc16sum(buf->data, size - sizeof(struct uffs_MiniHeaderSt))) {
			ret = UFFS_FLASH_CRC_ERR;
			goto ext;
		}
	}
#endif

ext:
	switch(ret) {
		case UFFS_FLASH_IO_ERR:
			uffs_Perror(UFFS_MSG_NORMAL, "Read block %d page %d I/O error", block, page);
			break;
		case UFFS_FLASH_ECC_FAIL:
			uffs_Perror(UFFS_MSG_NORMAL, "Read block %d page %d ECC failed", block, page);
			ret = UFFS_FLASH_BAD_BLK;	// treat ECC FAIL as BAD BLOCK
			is_bad = U_TRUE;
			break;
		case UFFS_FLASH_ECC_OK:
			uffs_Perror(UFFS_MSG_NORMAL, "Read block %d page %d bit flip corrected by ECC", block, page);
			break;
		case UFFS_FLASH_BAD_BLK:
			uffs_Perror(UFFS_MSG_NORMAL, "Read block %d page %d BAD BLOCK found", block, page);
			break;
		case UFFS_FLASH_UNKNOWN_ERR:
			uffs_Perror(UFFS_MSG_NORMAL, "Read block %d page %d UNKNOWN error!", block, page);
			break;
		case UFFS_FLASH_CRC_ERR:
			uffs_Perror(UFFS_MSG_NORMAL, "Read block %d page %d CRC failed", block, page);
			break;
		default:
			break;
	}

	if (is_bad)
		uffs_BadBlockAdd(dev, block);

	if (spare)
		uffs_PoolPut(SPOOL(dev), spare);


	return ret;
}