byte UFFS_PrintDiskInfo(const CLS1_StdIOType *io) { uffs_MountTable *m; //uffs_Device *d; int i, b = 0, g = 0; MSGLN("UFFS disk info:"); m = get_flash_mount_table(); while (m->dev) { MSGLN("Mount point: %s, start: %d, end: %d", m->mount, m->start_block, m->end_block); MSGLN("Space: %ld Used: %ld Free: %ld", uffs_space_total(m->mount), uffs_space_used(m->mount), uffs_space_free(m->mount)); for(i = m->start_block; i <= m->end_block; i++) { if(uffs_FlashIsBadBlock(m->dev, i)) b++; else g++; } MSGLN("Blocks: %d good: %d bad: %d (%d %%)", m->end_block - m->start_block + 1, g, b, b*100/(b+g)); m++; } return ERR_OK; }
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"); }
URET uffs_FormatDevice(uffs_Device *dev, UBOOL force) { u16 i, slot; URET ret = U_SUCC; if (dev == NULL) return U_FAIL; if (dev->ops == NULL) return U_FAIL; uffs_GlobalFsLockLock(); ret = uffs_BufFlushAll(dev); if (dev->ref_count > 1 && !force) { uffs_Perror(UFFS_MSG_NORMAL, "can't format when dev->ref_count = %d", dev->ref_count); ret = U_FAIL; } if (ret == U_SUCC && force) { uffs_DirEntryBufPutAll(dev); uffs_PutAllObjectBuf(dev); uffs_FdSignatureIncrease(); } if (ret == U_SUCC && uffs_BufIsAllFree(dev) == U_FALSE && !force) { uffs_Perror(UFFS_MSG_NORMAL, "some page still in used!"); ret = U_FAIL; } if (!force) { for (slot = 0; ret == U_SUCC && slot < dev->cfg.dirty_groups; slot++) { if (dev->buf.dirtyGroup[slot].count > 0) { uffs_Perror(UFFS_MSG_SERIOUS, "there still have dirty pages!"); ret = U_FAIL; } } } if (ret == U_SUCC) uffs_BufSetAllEmpty(dev); if (ret == U_SUCC && uffs_BlockInfoIsAllFree(dev) == U_FALSE && !force) { uffs_Perror(UFFS_MSG_NORMAL, "there still have block info cache ? fail to format"); ret = U_FAIL; } if (ret == U_SUCC) uffs_BlockInfoExpireAll(dev); for (i = dev->par.start; ret == U_SUCC && i <= dev->par.end; i++) { if (uffs_FlashIsBadBlock(dev, i) == U_FALSE) { uffs_FlashEraseBlock(dev, i); if (HAVE_BADBLOCK(dev)) uffs_BadBlockProcess(dev, NULL); } else { #ifdef CONFIG_ENABLE_BAD_BLOCK_VERIFY _ForceFormatAndCheckBlock(dev, i); #endif } } if (ret == U_SUCC && uffs_TreeRelease(dev) == U_FAIL) { ret = U_FAIL; } if (ret == U_SUCC && uffs_TreeInit(dev) == U_FAIL) { ret = U_FAIL; } if (ret == U_SUCC && uffs_BuildTree(dev) == U_FAIL) { ret = U_FAIL; } uffs_GlobalFsLockUnlock(); return ret; }
static URET _BuildTreeStepOne(uffs_Device *dev) { int block_lt; uffs_BlockInfo *bc = NULL; TreeNode *node; struct uffs_TreeSt *tree; uffs_Pool *pool; struct uffs_MiniHeaderSt header; URET ret = U_SUCC; struct BlockTypeStatSt st = {0, 0, 0}; tree = &(dev->tree); pool = TPOOL(dev); tree->bad = NULL; tree->bad_count = 0; tree->erased = NULL; tree->erased_tail = NULL; tree->erased_count = 0; uffs_Perror(UFFS_MSG_NOISY, "build tree step one"); // printf("s:%d e:%d\n", dev->par.start, dev->par.end); for (block_lt = dev->par.start; block_lt <= dev->par.end; block_lt++) { bc = uffs_BlockInfoGet(dev, block_lt); if (bc == NULL) { uffs_Perror(UFFS_MSG_SERIOUS, "step one:fail to get block info"); ret = U_FAIL; break; } node = (TreeNode *)uffs_PoolGet(pool); if (node == NULL) { uffs_Perror(UFFS_MSG_SERIOUS, "insufficient tree node!"); ret = U_FAIL; break; } // Need to check bad block at first ! if (uffs_FlashIsBadBlock(dev, block_lt) == U_TRUE) { node->u.list.block = block_lt; uffs_TreeInsertToBadBlockList(dev, node); uffs_Perror(UFFS_MSG_NORMAL, "found bad block %d", block_lt); } else if (uffs_IsPageErased(dev, bc, 0) == U_TRUE) { //@ read one spare: 0 // page 0 tag shows it's an erased block, we need to check the mini header status to make sure it is clean. if (uffs_LoadMiniHeader(dev, block_lt, 0, &header) == U_FAIL) { uffs_Perror(UFFS_MSG_SERIOUS, "I/O error when reading mini header !" "block %d page %d", block_lt, 0); ret = U_FAIL; break; } if (header.status != 0xFF) { // page 0 tag is clean but page data is dirty ??? // this block should be erased immediately ! uffs_FlashEraseBlock(dev, block_lt); } node->u.list.block = block_lt; if (HAVE_BADBLOCK(dev)) { uffs_Perror(UFFS_MSG_NORMAL, "New bad block (%d) discovered.", block_lt); uffs_BadBlockProcess(dev, node); } else { // page 0 is clean does not means all pages in this block are clean, // need to check this block later before use it. uffs_TreeInsertToErasedListTailEx(dev, node, 1); } } else { // this block have valid data page(s). ret = _ScanAndFixUnCleanPage(dev, bc); if (ret == U_FAIL) break; ret = _BuildValidTreeNode(dev, node, bc, &st); if (ret == U_FAIL) break; } uffs_BlockInfoPut(dev, bc); } //end of for if(ret == U_FAIL) uffs_BlockInfoPut(dev, bc); uffs_Perror(UFFS_MSG_NORMAL, "DIR %d, FILE %d, DATA %d", st.dir, st.file, st.data); return ret; }