/** * calculate sum of datam, 16bit version * \param[in] p data pointer * \param[in] len length of data * \return return sum of data, 16bit */ u16 uffs_MakeSum16(const void *p, int len) { return uffs_crc16sum(p, len); }
/** * 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; }
/** * calculate sum of data, 8bit version * \param[in] p data pointer * \param[in] len length of data * \return return sum of data, 8bit */ u8 uffs_MakeSum8(const void *p, int len) { return uffs_crc16sum(p, len) & 0xFF; }
/** * 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; }