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; }
static URET ReadPageWithLayout(uffs_Device *dev, u32 block, u32 page, u8 *data, int data_len, u8 *ecc, //NULL uffs_TagStore *ts, u8 *ecc_store) //NULL { int res = UFFS_FLASH_NO_ERR; int spare_len; rt_uint8_t spare[UFFS_MAX_SPARE_SIZE]; RT_ASSERT(UFFS_MAX_SPARE_SIZE >= dev->attr->spare_size); page = block * dev->attr->pages_per_block + page; spare_len = dev->mem.spare_data_size; if (data == RT_NULL && ts == RT_NULL) { #if defined(RT_UFFS_USE_CHECK_MARK_FUNCITON) RT_ASSERT(0); //should not be here #else /* check block good or bad */ rt_mtd_nand_read(RT_MTD_NAND_DEVICE(dev->_private), page, RT_NULL, 0, spare, dev->attr->spare_size);//dev->mem.spare_data_size dev->st.io_read++; res = spare[dev->attr->block_status_offs] == 0xFF ? UFFS_FLASH_NO_ERR : UFFS_FLASH_BAD_BLK; return res; #endif } if (data != RT_NULL) { dev->st.io_read += data_len; dev->st.page_read_count++; } res = rt_mtd_nand_read(RT_MTD_NAND_DEVICE(dev->_private), page, data, data_len, spare, spare_len); if (res == 0) res = UFFS_FLASH_NO_ERR; else if (res == -1) { //TODO ecc correct, add code to use hardware do ecc correct res = UFFS_FLASH_ECC_OK; } else res = UFFS_FLASH_ECC_FAIL; if (ts != RT_NULL) { // unload ts and ecc from spare, you can modify it if you like uffs_FlashUnloadSpare(dev, (const u8 *)spare, ts, RT_NULL); if ((spare[spare_len - 1] == 0xFF) && (res == UFFS_FLASH_NO_ERR)) res = UFFS_FLASH_NOT_SEALED; dev->st.io_read += spare_len; dev->st.spare_read_count++; } return res; }
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; }
/** * 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; }
/** * Read tag from page spare * * \param[in] dev uffs device * \param[in] block flash block num * \param[in] page flash page num * \param[out] tag tag to be filled * * \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. */ int uffs_FlashReadPageTag(uffs_Device *dev, int block, int page, uffs_Tags *tag) { uffs_FlashOps *ops = dev->ops; u8 * spare_buf; int ret = UFFS_FLASH_UNKNOWN_ERR; int tmp_ret; UBOOL is_bad = U_FALSE; spare_buf = (u8 *) uffs_PoolGet(SPOOL(dev)); if (spare_buf == NULL) goto ext; if (ops->ReadPageWithLayout) { ret = ops->ReadPageWithLayout(dev, block, page, NULL, 0, NULL, tag ? &tag->s : NULL, NULL); if (tag) tag->seal_byte = (ret == UFFS_FLASH_NOT_SEALED ? 0xFF : 0); } else { ret = ops->ReadPage(dev, block, page, NULL, 0, NULL, spare_buf, dev->mem.spare_data_size); if (tag) { tag->seal_byte = SEAL_BYTE(dev, spare_buf); if (!UFFS_FLASH_HAVE_ERR(ret)) uffs_FlashUnloadSpare(dev, spare_buf, &tag->s, NULL); } } if (UFFS_FLASH_IS_BAD_BLOCK(ret)) is_bad = U_TRUE; if (UFFS_FLASH_HAVE_ERR(ret)) goto ext; if (tag) { if (!TAG_IS_SEALED(tag)) // not sealed ? don't try tag ECC correction goto ext; if (!TAG_IS_VALID(tag)) { if (dev->attr->ecc_opt != UFFS_ECC_NONE) { /* * There could be a special case if: * a) tag is sealed (so we are here), and * b) s.valid == 1 and this bit is a 'bad' bit, and * c) after tag ECC (corrected by tag ECC) s.valid == 0. * * So we need to try tag ECC (don't treat it as bad block if ECC failed) */ struct uffs_TagStoreSt s; memcpy(&s, &tag->s, sizeof(s)); tmp_ret = TagEccCorrect(&s); if (tmp_ret <= 0 || !TAG_IS_VALID(tag)) // can not corrected by ECC. goto ext; } else { goto ext; } } // do tag ecc correction if (dev->attr->ecc_opt != UFFS_ECC_NONE) { ret = TagEccCorrect(&tag->s); 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; } } ext: if (is_bad) { uffs_BadBlockAdd(dev, block); uffs_Perror(UFFS_MSG_NORMAL, "A new bad block (%d) is detected.", block); } if (spare_buf) uffs_PoolPut(SPOOL(dev), spare_buf); return ret; }