/** * \brief put all memory block back, return how many memory blocks were put back */ int uffs_PoolPutAll(uffs_Pool *pool) { void *p = NULL; int count = 0; do { p = uffs_PoolFindNextAllocated(pool, p); if (p) { uffs_PoolPut(pool, p); count++; } } while (p); return count; }
/** * Put all dir entry buf match dev */ int uffs_DirEntryBufPutAll(uffs_Device *dev) { int count = 0; uffs_DIR *dirp = NULL; do { dirp = (uffs_DIR *) uffs_PoolFindNextAllocated(&_dir_pool, dirp); if (dirp && dirp->obj && dirp->obj->dev && dirp->obj->dev->dev_num == dev->dev_num) { uffs_PoolPut(&_dir_pool, dirp); count++; } } while (dirp); return count; }
/** * mark a clean page tag as 'dirty' and 'invalid'. * * \param[in] dev uffs device * \param[in] bc block info * \param[in] page * * \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_FlashMarkDirtyPage(uffs_Device *dev, uffs_BlockInfo *bc, int page) { u8 *spare; uffs_FlashOps *ops = dev->ops; UBOOL is_bad = U_FALSE; int ret = UFFS_FLASH_UNKNOWN_ERR; int block = bc->block; uffs_Tags *tag = GET_TAG(bc, page); struct uffs_TagStoreSt *ts = &tag->s; spare = (u8 *) uffs_PoolGet(SPOOL(dev)); if (spare == NULL) goto ext; memset(ts, 0xFF, sizeof(struct uffs_TagStoreSt)); ts->dirty = TAG_DIRTY; // set only 'dirty' bit, leave 'valid' bit to 1 (invalid). if (dev->attr->ecc_opt != UFFS_ECC_NONE) TagMakeEcc(ts); if (ops->WritePageWithLayout) { ret = ops->WritePageWithLayout(dev, block, page, NULL, 0, NULL, ts); } else { uffs_FlashMakeSpare(dev, ts, NULL, spare); ret = ops->WritePage(dev, block, page, NULL, 0, spare, dev->mem.spare_data_size); } if (UFFS_FLASH_IS_BAD_BLOCK(ret)) is_bad = U_TRUE; ext: if (is_bad) uffs_BadBlockAdd(dev, block); if (spare) uffs_PoolPut(SPOOL(dev), spare); return ret; }
static void PutDirEntry(uffs_DIR *p) { uffs_PoolPut(&_dir_pool, p); }
/** * put the object struct back to system */ void uffs_PutObject(uffs_Object *obj) { if (obj) uffs_PoolPut(&_object_pool, obj); }
static void _ForceFormatAndCheckBlock(uffs_Device *dev, int block) { int i, j; uffs_Buf *buf = NULL; UBOOL bad = U_TRUE; URET ret; struct uffs_FlashOpsSt *ops = dev->ops; struct uffs_TagStoreSt ts; u8 *spare = NULL; buf = uffs_BufClone(dev, NULL); if (buf == NULL) { uffs_Perror(UFFS_MSG_SERIOUS, "Alloc page buffer fail ! Format stoped."); goto ext; } spare = (u8 *)uffs_PoolGet(SPOOL(dev)); if (spare == NULL) goto ext; //step 1: Erase, fully fill with 0x0, and check ret = uffs_FlashEraseBlock(dev, block); if (UFFS_FLASH_IS_BAD_BLOCK(ret)) goto bad_out; memset(buf->header, 0, dev->com.pg_size); memset(&ts, 0, sizeof(ts)); memset(spare, 0, dev->attr->spare_size); for (i = 0; i < dev->attr->pages_per_block; i++) { if (ops->WritePageWithLayout) ret = ops->WritePageWithLayout(dev, block, i, buf->header, dev->com.pg_size, NULL, &ts); else ret = ops->WritePage(dev, block, i, buf->header, dev->com.pg_size, spare, dev->attr->spare_size); if (UFFS_FLASH_IS_BAD_BLOCK(ret)) goto bad_out; } for (i = 0; i < dev->attr->pages_per_block; i++) { memset(buf->header, 0xFF, dev->com.pg_size); memset(&ts, 0xFF, sizeof(ts)); memset(spare, 0xFF, dev->attr->spare_size); if (ops->ReadPageWithLayout) { ret = ops->ReadPageWithLayout(dev, block, i, buf->header, dev->com.pg_size, NULL, &ts, NULL); if (UFFS_FLASH_IS_BAD_BLOCK(ret)) goto bad_out; for (j = 0; j < dev->com.pg_size; j++) if (buf->header[j] != 0) goto bad_out; for (j = 0; j < sizeof(ts); j++) if (((u8 *)&ts)[j] != 0) goto bad_out; } else { ret = ops->ReadPage(dev, block, i, buf->header, dev->com.pg_size, NULL, spare, dev->attr->spare_size); if (UFFS_FLASH_IS_BAD_BLOCK(ret)) goto bad_out; for (j = 0; j < dev->com.pg_size; j++) if (buf->header[j] != 0) goto bad_out; for (j = 0; j < dev->attr->spare_size; j++) if (spare[j] != 0) goto bad_out; } } //step 2: Erase, and check ret = uffs_FlashEraseBlock(dev, block); if (UFFS_FLASH_IS_BAD_BLOCK(ret)) goto bad_out; for (i = 0; i < dev->attr->pages_per_block; i++) { memset(buf->header, 0, dev->com.pg_size); memset(&ts, 0, sizeof(ts)); memset(spare, 0, dev->attr->spare_size); if (ops->ReadPageWithLayout) { ret = ops->ReadPageWithLayout(dev, block, i, buf->header, dev->com.pg_size, NULL, &ts, NULL); if (UFFS_FLASH_IS_BAD_BLOCK(ret)) goto bad_out; for (j = 0; j < dev->com.pg_size; j++) if (buf->header[j] != 0xFF) goto bad_out; for (j = 0; j < sizeof(ts); j++) if (((u8 *)&ts)[j] != 0xFF) goto bad_out; } else { ret = ops->ReadPage(dev, block, i, buf->header, dev->com.pg_size, NULL, spare, dev->attr->spare_size); if (UFFS_FLASH_IS_BAD_BLOCK(ret)) goto bad_out; for (j = 0; j < dev->com.pg_size; j++) if (buf->header[j] != 0xFF) goto bad_out; for (j = 0; j < dev->attr->spare_size; j++) if (spare[j] != 0xFF) goto bad_out; } } // format succ bad = U_FALSE; bad_out: if (bad == U_TRUE) uffs_FlashMarkBadBlock(dev, block); ext: if (buf) uffs_BufFreeClone(dev, buf); if (spare) uffs_PoolPut(SPOOL(dev), spare); return; }
/** * Check the block by reading all pages. * * \return U_SUCC - all pages are clean, * U_FAIL - block is not clean */ URET uffs_FlashCheckErasedBlock(uffs_Device *dev, int block) { u8 *spare = NULL; uffs_FlashOps *ops = dev->ops; int ret = U_SUCC; int page; int flash_ret; u8 ecc_store[UFFS_MAX_ECC_SIZE]; uffs_TagStore ts; uffs_Buf *buf = NULL; int size = dev->com.pg_size; int i; u8 *p; spare = (u8 *) uffs_PoolGet(SPOOL(dev)); if (spare == NULL) { uffs_Perror(UFFS_MSG_SERIOUS, "Can't allocate spare buf."); goto ext; } buf = uffs_BufClone(dev, NULL); if (buf == NULL) { uffs_Perror(UFFS_MSG_SERIOUS, "Can't clone buf."); goto ext; } for (page = 0; page < dev->attr->pages_per_block; page++) { if (ops->ReadPageWithLayout) { flash_ret = ops->ReadPageWithLayout(dev, block, page, buf->header, size, NULL, &ts, ecc_store); if (flash_ret != UFFS_FLASH_IO_ERR) { // check page tag, should be all 0xFF for (i = 0, p = (u8 *)(&ts); i < sizeof(ts); i++, p++) { if (*p != 0xFF) { ret = U_FAIL; goto ext; } } // for hw or soft ecc, check stored ecc, should be all 0xFF if (dev->attr->ecc_opt == UFFS_ECC_HW || dev->attr->ecc_opt == UFFS_ECC_SOFT) { for (i = 0, p = ecc_store; i < ECC_SIZE(dev); i++, p++) { if (*p != 0xFF) { ret = U_FAIL; goto ext; } } } } } else { flash_ret = ops->ReadPage(dev, block, page, buf->header, size, NULL, spare, dev->attr->spare_size); if (flash_ret != UFFS_FLASH_IO_ERR) { // check spare data, should be all 0xFF for (i = 0, p = spare; i < dev->attr->spare_size; i++, p++) { if (*p != 0xFF) { ret = U_FAIL; goto ext; } } } } if (flash_ret != UFFS_FLASH_IO_ERR) { // check page data, should be all 0xFF for (i = 0, p = buf->header; i < size; i++, p++) { if (*p != 0xFF) { ret = U_FAIL; goto ext; } } } } ext: if (spare) uffs_PoolPut(SPOOL(dev), spare); if (buf) uffs_BufFreeClone(dev, buf); return ret; }
/** * 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; }
/** * 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; }