Exemple #1
0
/**
 * \brief load page spare data to given block info structure
 *			with given page number
 * \param[in] dev uffs device
 * \param[in] work given block info to be filled with
 * \param[in] page given page number to be read from,
 *			  if #UFFS_ALL_PAGES is presented, it will read
 *			  all pages, otherwise it will read only one given page.
 * \return load result
 * \retval U_SUCC successful
 * \retval U_FAIL fail to load
 * \note work->block must be set before load block info
 */
URET uffs_BlockInfoLoad(uffs_Device *dev, uffs_BlockInfo *work, int page)
{
    int i, ret;
    uffs_PageSpare *spare;

    if (page == UFFS_ALL_PAGES) {
        for (i = 0; i < dev->attr->pages_per_block; i++) {
            spare = &(work->spares[i]);
            if (spare->expired == 0)
                continue;

            ret = uffs_FlashReadPageTag(dev, work->block, i,
                                        &(spare->tag));
            if (UFFS_FLASH_HAVE_ERR(ret)) {
                uffs_Perror(UFFS_MSG_SERIOUS,
                            "load block %d page %d spare fail.",
                            work->block, i);
                return U_FAIL;
            }
            spare->expired = 0;
            work->expired_count--;
        }
    }
    else {
        if (page < 0 || page >= dev->attr->pages_per_block) {
            uffs_Perror(UFFS_MSG_SERIOUS, "page out of range !");
            return U_FAIL;
        }
        spare = &(work->spares[page]);
        if (spare->expired != 0) {
            ret = uffs_FlashReadPageTag(dev, work->block, page,
                                        &(spare->tag));
            if (UFFS_FLASH_HAVE_ERR(ret)) {
                uffs_Perror(UFFS_MSG_SERIOUS,
                            "load block %d page %d spare fail.",
                            work->block, page);
                return U_FAIL;
            }
            spare->expired = 0;
            work->expired_count--;
        }
    }
    return U_SUCC;
}
static void DumpBlock(struct uffs_DeviceSt *dev, int block, dump_msg_cb *dump)
{
	int i;
	struct uffs_StorageAttrSt *attr = dev->attr;
	uffs_Tags tag;
	URET ret;

	dump(dev, "--- Block %d ---\n", block);

	if (uffs_FlashIsBadBlock(dev, block)) {
		dump(dev, "Bad block\n\n");
		return;
	}

	for (i = 0; i < attr->pages_per_block; i++) {

		memset(&tag, 0xFF, sizeof(tag));
		ret = uffs_FlashReadPageTag(dev, block, i, &tag);

		if (ret == UFFS_FLASH_IO_ERR) {
			dump(dev, "page %d tag I/O error\n", i);
			continue;
		}
		else if (ret == UFFS_FLASH_ECC_FAIL) {
			dump(dev, "page %d tag ECC error\n", i);
			continue;
		}
		else if (ret == UFFS_FLASH_NO_ERR || ret == UFFS_FLASH_ECC_OK) {
			if (ret == UFFS_FLASH_ECC_OK)
				dump(dev, "page %d tag has bit flip, corrected by ECC\n", i);

			if (DumpTag(dev, block, i, &tag, dump) == 0)
				continue;
			else
				break;
		}
		else {
			dump(dev, "read page %d tag return unexpected: %d\n", i, ret);
			continue;
		}
	}
	dump(dev, "\n");
}
Exemple #3
0
static void do_dump_device(uffs_Device *dev)
{
	URET ret;
	int block, page;
	uffs_Tags tag;
	uffs_Buf *buf;

	buf = uffs_BufClone(dev, NULL);
	if (buf == NULL) {
		MSGLN("Can't clone buf");
		return;
	}

	for (block = dev->par.start; block <= dev->par.end; block++) {
		MSG("---- block %d ----\n", block);
		for (page = 0; page < dev->attr->pages_per_block; page++) {
			MSG("  == page %d ==\n", page);
			ret = uffs_FlashReadPage(dev, block, page, buf, U_FALSE);
			if (UFFS_FLASH_HAVE_ERR(ret)) {
				MSG(" !!! Read page failed, ret = %d !!!\n", ret);
			}
			else {
				do_dump_page(dev, buf);
				if (buf->header[0] != 0xFF) {
					ret = uffs_FlashReadPageTag(dev, block, page, &tag);
					if (UFFS_FLASH_HAVE_ERR(ret)) {
						MSG(" !!! Read TAG failed, ret = %d !!!\n", ret);
					}
					else {
						do_dump_tag(dev, &tag);
					}
				}
			}
		}
	}
	uffs_BufFreeClone(dev, buf);
}
Exemple #4
0
/* usage: t_pgrw
 *
 * This test case test page read/write
 */
static int cmd_TestPageReadWrite(int argc, char *argv[])
{
	TreeNode *node = NULL;
	uffs_Device *dev;
	uffs_Tags local_tag;
	uffs_Tags *tag = &local_tag;
	int ret;
	u16 block;
	u16 page;
	uffs_Buf *buf = NULL;

	u32 i;
	int rc = -1;

	dev = uffs_GetDeviceFromMountPoint("/");
	if (!dev)
		goto ext;

	buf = uffs_BufClone(dev, NULL);
	if (!buf)
		goto ext;

	node = uffs_TreeGetErasedNode(dev);
	if (!node) {
		MSGLN("no free block ?");
		goto ext;
	}

	for (i = 0; i < dev->com.pg_data_size; i++) {
		buf->data[i] = i & 0xFF;
	}

	block = node->u.list.block;
	page = 1;

	TAG_DIRTY_BIT(tag) = TAG_DIRTY;
	TAG_VALID_BIT(tag) = TAG_VALID;
	TAG_DATA_LEN(tag) = dev->com.pg_data_size;
	TAG_TYPE(tag) = UFFS_TYPE_DATA;
	TAG_PAGE_ID(tag) = 3;
	TAG_PARENT(tag) = 100;
	TAG_SERIAL(tag) = 10;
	TAG_BLOCK_TS(tag) = 1;
	SEAL_TAG(tag);

	ret = uffs_FlashWritePageCombine(dev, block, page, buf, tag);
	if (UFFS_FLASH_HAVE_ERR(ret)) {
		MSGLN("Write page error: %d", ret);
		goto ext;
	}

	ret = uffs_FlashReadPage(dev, block, page, buf, U_FALSE);
	if (UFFS_FLASH_HAVE_ERR(ret)) {
		MSGLN("Read page error: %d", ret);
		goto ext;
	}

	for (i = 0; i < dev->com.pg_data_size; i++) {
		if (buf->data[i] != (i & 0xFF)) {
			MSGLN("Data verify fail at: %d", i);
			goto ext;
		}
	}

	ret = uffs_FlashReadPageTag(dev, block, page, tag);
	if (UFFS_FLASH_HAVE_ERR(ret)) {
		MSGLN("Read tag (page spare) error: %d", ret);
		goto ext;
	}
	
	// verify tag:
	if (!TAG_IS_SEALED(tag)) {
		MSGLN("not sealed ? Tag verify fail!");
		goto ext;
	}

	if (!TAG_IS_DIRTY(tag)) {
		MSGLN("not dirty ? Tag verify fail!");
		goto ext;
	}

	if (!TAG_IS_VALID(tag)) {
		MSGLN("not valid ? Tag verify fail!");
		goto ext;
	}

	if (TAG_DATA_LEN(tag) != dev->com.pg_data_size ||
		TAG_TYPE(tag) != UFFS_TYPE_DATA ||
		TAG_PAGE_ID(tag) != 3 ||
		TAG_PARENT(tag) != 100 ||
		TAG_SERIAL(tag) != 10 ||
		TAG_BLOCK_TS(tag) != 1) {

		MSGLN("Tag verify fail!");
		goto ext;
	}

	MSGLN("Page read/write test succ.");
	rc = 0;

ext:
	if (node) {
		uffs_TreeEraseNode(dev, node);
		uffs_TreeInsertToErasedListTail(dev, node);
	}

	if (dev)
		uffs_PutDevice(dev);

	if (buf)
		uffs_BufFreeClone(dev, buf);

	return rc;
}
Exemple #5
0
/* usage: t_pgrw
 *
 * This test case test page read/write
 */
static BOOL cmdTestPageReadWrite(const char *tail)
{
	TreeNode *node;
	uffs_Device *dev;
	uffs_Tags local_tag;
	uffs_Tags *tag = &local_tag;
	int ret;
	u16 block;
	u16 page;
	uffs_Buf *buf;

	u32 i;

	dev = uffs_GetDeviceFromMountPoint("/");
	if (!dev)
		goto ext;

	buf = uffs_BufClone(dev, NULL);
	if (!buf)
		goto ext;

	node = uffs_TreeGetErasedNode(dev);
	if (!node) {
		MSGLN("no free block ?");
		goto ext;
	}

	for (i = 0; i < dev->com.pg_data_size; i++) {
		buf->data[i] = i & 0xFF;
	}

	block = node->u.list.block;
	page = 1;

	TAG_DATA_LEN(tag) = dev->com.pg_data_size;
	TAG_TYPE(tag) = UFFS_TYPE_DATA;
	TAG_PAGE_ID(tag) = 3;
	TAG_PARENT(tag) = 100;
	TAG_SERIAL(tag) = 10;
	TAG_BLOCK_TS(tag) = 1;

	ret = uffs_FlashWritePageCombine(dev, block, page, buf, tag);
	if (UFFS_FLASH_HAVE_ERR(ret)) {
		MSGLN("Write page error: %d", ret);
		goto ext;
	}

	ret = uffs_FlashReadPage(dev, block, page, buf);
	if (UFFS_FLASH_HAVE_ERR(ret)) {
		MSGLN("Read page error: %d", ret);
		goto ext;
	}

	for (i = 0; i < dev->com.pg_data_size; i++) {
		if (buf->data[i] != (i & 0xFF)) {
			MSGLN("Data verify fail at: %d", i);
			goto ext;
		}
	}

	ret = uffs_FlashReadPageTag(dev, block, page, tag);
	if (UFFS_FLASH_HAVE_ERR(ret)) {
		MSGLN("Read tag (page spare) error: %d", ret);
		goto ext;
	}
	
	// verify tag:
	if (!TAG_IS_DIRTY(tag)) {
		MSGLN("not dirty ? Tag verify fail!");
		goto ext;
	}

	if (!TAG_IS_VALID(tag)) {
		MSGLN("not valid ? Tag verify fail!");
		goto ext;
	}

	if (TAG_DATA_LEN(tag) != dev->com.pg_data_size ||
		TAG_TYPE(tag) != UFFS_TYPE_DATA ||
		TAG_PAGE_ID(tag) != 3 ||
		TAG_PARENT(tag) != 100 ||
		TAG_SERIAL(tag) != 10 ||
		TAG_BLOCK_TS(tag) != 1) {

		MSGLN("Tag verify fail!");
		goto ext;
	}

	MSGLN("Page read/write test succ.");

ext:
	if (node) {
		uffs_FlashEraseBlock(dev, node->u.list.block);
		if (HAVE_BADBLOCK(dev))
			uffs_BadBlockProcess(dev, node);
		else
			uffs_InsertToErasedListHead(dev, node);
	}

	if (dev)
		uffs_PutDevice(dev);

	if (buf)
		uffs_BufFreeClone(dev, buf);

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