static URET femu_hw_auto_ReadPageWithLayout(uffs_Device *dev, u32 block, u32 page, u8* data, int data_len, u8 *ecc,
        uffs_TagStore *ts, u8 *ecc_store)
{
    uffs_FileEmu *emu;
    int abs_page;
    struct uffs_StorageAttrSt *attr = dev->attr;
    unsigned char status;
    int spare_len;
    u8 spare[PAGE_SPARE_SIZE];
    u8 ecc_buf[RS_ECC_SIZE];
    int ret = UFFS_FLASH_IO_ERR;

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

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

    abs_page = attr->pages_per_block * block + page;

    // now load full page to serial data buffer
    ret = load_sdata(dev, block, page);
    if (ret != UFFS_FLASH_NO_ERR)
        goto ext;

    start_sdata_access();

    dev->st.io_read += PAGE_FULL_SIZE;
    dev->st.page_read_count++;
    dev->st.spare_read_count++;

    if (data || ts) {

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

            drain_sdata(data, data_len);
        }

        if (ts) {
            if (g_sdata_buf_pointer < attr->page_data_size)
                drain_sdata(NULL, attr->page_data_size - g_sdata_buf_pointer);

            drain_sdata(spare, PAGE_SPARE_SIZE - RS_ECC_SIZE);

            // unload ts from spare
            uffs_FlashUnloadSpare(dev, spare, ts, NULL);
        }
    } else {
        // read bad block mark
        drain_sdata(NULL, attr->page_data_size + attr->block_status_offs - 1);
        drain_sdata(&status, 1);

        ret = (status == 0xFF ? UFFS_FLASH_NO_ERR : UFFS_FLASH_BAD_BLK);
    }

ext:
    return ret;
}
Example #2
0
static int femu_hw_auto_WritePageWithLayout(uffs_Device *dev, u32 block, u32 page,
							const u8 *data, int data_len, const u8 *ecc, const uffs_TagStore *ts)
{
	int abs_page;
	uffs_FileEmu *emu;
	struct uffs_StorageAttrSt *attr = dev->attr;
	u8 spare[PAGE_SPARE_SIZE];
	int ret = UFFS_FLASH_IO_ERR;

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

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

	abs_page = attr->pages_per_block * block + page;

	start_sdata_access();

	dev->st.page_write_count++;
	dev->st.spare_write_count++;
	dev->st.io_write += PAGE_FULL_SIZE;

	if (data || ts) {
		// normal page write
		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) {
				MSGLN("Warrning: block %d page %d exceed it's maximum write time!", block, page);
				goto err;
			}
			
			// Copy data to serial data buffer
			feed_sdata(data, data_len);

			// Pad the rest data as 0xFF
			feed_sdata_constant(0xFF, attr->page_data_size - data_len);

		}
		else {
			// We still need to feed data to serial data buffer to make MLC controller happy
			// The current UFFS won't write ts only, so we'll never run to here.
			feed_sdata_constant(0xFF, attr->page_data_size);
		}

		if (ts) {

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

			memset(spare, 0xFF, sizeof(spare));
			uffs_FlashMakeSpare(dev, ts, NULL, spare);	// do not pack ECC, as MLC controller will
														// automatically write RS-ECC to the latest 10 bytes.

			// feed spare data to serial data buffer
			feed_sdata(spare, PAGE_SPARE_SIZE - RS_ECC_SIZE);			
		}
	}
	else {
		// mark bad block

		// feed data to serial data buffer to make MLC controller happy
		feed_sdata_constant(0xFF, attr->page_data_size);

		memset(spare, 0xFF, sizeof(spare));
		spare[attr->block_status_offs] = 0;

		// feed spare data to serial data buffer
		feed_sdata(spare, PAGE_SPARE_SIZE - RS_ECC_SIZE);

		dev->st.io_write++;
	}

	// now, program serial data buffer to NAND flash
	ret = program_sdata(dev, block, page);

	fflush(emu->fp);
	return ret;
err:
	fflush(emu->fp);
	return ret;
}