📄 fsmplr.c
字号:
/*****************************************************************************
FILE NAME: FsmPlr.c
DESCRIPTION:
Power lost recovery for data file system.
Copyright (c) 2002, VIA Technologies, Inc.
*****************************************************************************/
#include "fsmdefs.h"
#include "FsmDfs.h"
#include "fsmdev.h"
#define EMPTYLSN 0xFFFFFFFF
#define DIRTYLSN 0xFFFFFFFE
typedef /*PACKED*/ struct _DFS_PLR_QUEUE
{
uint32 Psn;
uint16 Status;
struct _DFS_PLR_QUEUE* NextP;
} DfsPlrQueueT;
static uint32 DfsPlrScanBlock(FsmDevObjHdrT* pDev, uint32 block_size, uint32 block_num);
static uint32 DfsPlrScanSector(FsmDevObjHdrT* pDev,
uint32 block_size,
uint32 block_num,
DfsPlrQueueT ** head,
uint32 * Psn2LsnP);
static uint32 DfsPlrSecUpdating(uint32 Psn,
uint32 * Psn2LsnP,
FsmDevObjHdrT* pDev,
uint32 block_size,
uint32 block_num);
static uint32 DfsPlrSecAppending(uint32 Psn,
uint32 * Psn2LsnP,
FsmDevObjHdrT* pDev,
uint32 block_size,
uint32 block_num);
#if 0
static uint32 DfsPlrEntrySecAppending(uint32 Psn,
uint32 * Psn2LsnP,
FsmDevObjHdrT* pDev,
uint32 block_size,
uint32 block_num);
#endif
static uint32 DfsPlrEntryAllocated(uint32 first_lsn,
uint32 * Psn2LsnP,
FsmDevObjHdrT* pDev,
uint32 block_size,
uint32 block_num);
static uint32 DfsPlrEntryDeleting(uint32 first_lsn,
uint32 entry_sector_psn,
uint16 entry_num,
uint32 * Psn2LsnP,
FsmDevObjHdrT* pDev,
uint32 block_size,
uint32 block_num);
static uint32 DfsPlrEntryUpdating(uint32 first_lsn,
uint32 * Psn2LsnP,
FsmDevObjHdrT* pDev,
uint32 block_size,
uint32 block_num);
static uint32 DfsPlrItemEntry(uint32 first_lsn,
uint32 * Psn2LsnP,
FsmDevObjHdrT* pDev,
uint32 block_size,
uint32 block_num);
static uint32 DfsPlrFileEntry(uint32 first_lsn,
uint32 * Psn2LsnP,
FsmDevObjHdrT* pDev,
uint32 block_size,
uint32 block_num);
static uint32 DfsPlrSecMultiInstances(uint32 Psn,
FsmDevObjHdrT * pDev,
uint32 block_size,
uint32 block_num);
static uint32 AddQueue(uint32 Psn,
uint16 psn_status,
DfsPlrQueueT ** head);
static uint32 DfsGetAddr(uint32 Psn,
uint16 block_sectors,
uint32 block_size,
uint32 sector_size);
static uint32 DfsGetAddr2(uint32 pbn, uint32 index, uint32 block_size, uint32 sector_size);
/*#############################################################################
### FsmPlrDfsCheck
###
### DESCRIPTION:
### Initialize Lsn2Psn map and block statistic data.
### Call function DfsPlrScanBlock to recover flash blocks.
### Call function DfsPlrScanSector to recover flash sectors and dirctory entries.
###
### PARAMETERS:
### IN: pDev - poiter to designated FsmDevObjHdrT of data file system.
### BlockSize - flash block size.
### Blocks - flash block number.
### OUT: Lsn2Psn - every lsn has corresponding psn.
### BlockInfo - the statistic of free, dirty, used sector number and erase
### count of every block
###
### RETURNS:
### If the recovery process is not successful, the function returns ERR_INIT.
### Otherwise, the function returns ERR_NONE.
###
*/
uint32 FsmPlrDfsCheck(FsmDevObjHdrT * pDev, uint32 BlockSize, uint32 Blocks)
{
FsmFlashMediaT * MediaP;
FsmBlockStatisticT * BlockStatP;
uint32 MaxPsn;
uint32 i;
uint32 status;
uint32 * Psn2LsnP;
DfsPlrQueueT * head;
#ifdef DEBUG_FSM
MonPrintf("Enter Interface FsmPlrDfsCheck!\n");
#endif
MediaP = (FsmFlashMediaT *)(pDev->MediaObjP);
BlockStatP = MediaP->BlockInfoP;
MaxPsn = MediaP->MaxPsn;
MediaP->SpareBlk = (uint16)(-1);
/* Set initial value of Lsn2Psn map member. */
for(i = 0; i < MaxPsn; i++)
{
MediaP->Lsn2PsnP[i] = INVALID_PSN; /* (LSN i) --> (INVALID_PSN) */
}
/* Set initial value of BlockInfo member. */
for(i = 0; i < Blocks; i++)
{
BlockStatP[i].FreeSectors = 0;
BlockStatP[i].UsedSectors = 0;
BlockStatP[i].DirtySectors = 0;
BlockStatP[i].EraseCount = 0;
}
status = DfsPlrScanBlock(pDev, BlockSize, Blocks);
if(status != ERR_NONE)
return status;
head = NULL;
Psn2LsnP = (uint32 *)FsmTryMalloc(MaxPsn * sizeof(uint32));
if(Psn2LsnP == NULL)
{
#ifdef DEBUG_FSM
MonPrintf("Memory allocation for Psn2LsnP false!\n");
#endif
return ERR_SYSTEM;
}
/* Initialize Psn2Lsn map. */
for(i = 0 ; i < MaxPsn ; i++)
{
Psn2LsnP[i] = EMPTYLSN;
}
status = DfsPlrScanSector(pDev, BlockSize, Blocks, &head, Psn2LsnP);
FsmFree(Psn2LsnP);
if(status != ERR_NONE)
{
DfsPlrQueueT * queue_entry;
while(head != NULL)
{
queue_entry = head;
head = head->NextP;
FsmFree((void *)queue_entry);
}
return ERR_INIT;
}
#ifdef DEBUG_FSM
MonPrintf("Exit Interface FsmPlrDfsCheck successfully!\n");
#endif
return ERR_NONE;
}
/*#############################################################################
### DfsPlrScanBlock
###
### DESCRIPTION:
### Scan blocks one by one. Erase the block in BLOCK_WRITEING status and with
### correct tag. Continue reclamation process before power-lost if any block
### found in BLOCK_ERASING status and with correct tag.
### Erase the block with incorrect tag.
### Designate spare block number and statistic of block erase count
###
### PARAMETERS:
### IN: pDev - poiter to designated FsmDevObjHdrT of data file system.
### BlockSize - flash block size.
### Blocks - flash block number.
### OUT: SpareBlk - spare block number.
### EraseCount - erase count of every block.
###
### RETURNS:
### If flash read operation is not successful, the function returns ERR_READ.
### If flash write operation is not successful, the function returns ERR_WRITE.
### If flash erase operation is not successful, the function returns ERR_ERASE.
### If spare block cannot be found or designated, the function returns ERR_FULL.
### Otherwise, the function returns ERR_NONE.
###
*/
static uint32 DfsPlrScanBlock(FsmDevObjHdrT* pDev, uint32 BlockSize, uint32 Blocks)
{
FsmBlockStatisticT * BlockStatP;
FsmBlockInfoT BlockInfo;
uint32 block_tag;
uint16 block_status;
uint16 spare_block;
uint16 Pbn;
uint32 block_address;
uint32 info_offset;
uint32 info_address; /* for write and read operation */
uint32 hw_status;
uint8 invalid_tag;
uint32 MaxEraseCount;
uint32 MinEraseCount;
uint32 avg_erasecount; /* used for blocks with uncorrect tag */
DEV_WRITE_FUNCPTR DevWrite = pDev->DevDrvP->FsmDevWrite;
DEV_READ_FUNCPTR DevRead = pDev->DevDrvP->FsmDevRead;
DEV_ERASE_FUNCPTR DevErase = pDev->DevDrvP->FsmDevErase;
#ifdef DEBUG_FSM
MonPrintf("Enter Interface DfsPlrScanBlock!\n");
#endif
BlockStatP = ((FsmFlashMediaT *)(pDev->MediaObjP))->BlockInfoP;
spare_block = ((FsmFlashMediaT *)(pDev->MediaObjP))->SpareBlk;
MaxEraseCount = 0;
MinEraseCount = (uint32)(-1);
invalid_tag = 0;
info_offset = BlockSize - sizeof(FsmBlockInfoT);
for(Pbn = 0; Pbn < Blocks; Pbn++)
{
block_address = Pbn * BlockSize;
/* read information of block in flash. */
info_address = block_address + info_offset;
hw_status = DevRead(pDev,
(uint8 *)&BlockInfo,
info_address,
sizeof(FsmBlockInfoT)
);
if(hw_status != HW_ERR_NONE)
return ERR_READ;
if(BlockInfo.Tag == FSM_TAG)
{
/* recover the blocks in undefined status. */
if((block_status = VALID_BLOCK_STATE(BlockInfo.Status)) != 0)
{
BlockInfo.Status = FIX_BLOCK_STATE(block_status, BlockInfo.Status);
hw_status = DevWrite(pDev,
(uint8 *)&(BlockInfo.Status),
info_address + FIELD_OFFSET(FsmBlockInfoT, Status),
FIELD_SIZE(FsmBlockInfoT, Status)
);
if(hw_status != HW_ERR_NONE)
return ERR_WRITE;
}
switch(BlockInfo.Status)
{
case BLOCK_ERASED:
if((spare_block != (uint16)(-1)) && (spare_block != Pbn))
{
return ERR_FORMAT;
}
spare_block = Pbn;
break;
case BLOCK_WRITING:
#ifdef DEBUG_FSM
MonPrintf("No.%d block is found in BLOCK_WRITING status!\n", Pbn);
#endif
if((spare_block != (uint16)(-1)) && (spare_block != Pbn))
{
return ERR_FORMAT;
}
/* erase this block. */
block_tag = 0;
hw_status = DevWrite( pDev,
(uint8 *)&block_tag,
info_address + FIELD_OFFSET(FsmBlockInfoT, Tag),
FIELD_SIZE(FsmBlockInfoT, Tag)
);
if(hw_status != HW_ERR_NONE)
return ERR_WRITE;
hw_status = DevErase(pDev, block_address);
if(hw_status != HW_ERR_NONE)
{
return ERR_ERASE;
}
BlockInfo.BackupEraseCount = (uint32)(-1);
BlockInfo.EraseCount++;
BlockInfo.Pbn = (uint16)(-1);
BlockInfo.Status = BLOCK_ERASED;
BlockInfo.Tag = FSM_TAG;
hw_status=DevWrite(pDev,
(uint8 *)&BlockInfo,
info_address,
sizeof(FsmBlockInfoT)
);
if(hw_status != HW_ERR_NONE)
return ERR_WRITE;
spare_block = Pbn;
break;
case BLOCK_ERASING:
#ifdef DEBUG_FSM
MonPrintf("No.%d block is found in BLOCK_ERASING status!\n", Pbn);
MonPrintf("No.%d block is the reclamation block in process before power lost!\n", BlockInfo.Pbn);
#endif
if((spare_block != (uint16)(-1)) && (spare_block != BlockInfo.Pbn))
{
return ERR_FORMAT;
}
info_address = BlockInfo.Pbn * BlockSize + info_offset;
hw_status = DevRead(pDev,
(uint8 *)&block_status,
info_address + FIELD_OFFSET(FsmBlockInfoT, Status),
FIELD_SIZE(FsmBlockInfoT, Status)
);
if(hw_status != HW_ERR_NONE)
return ERR_READ;
hw_status = DevRead(pDev,
(uint8 *)&block_tag,
info_address + FIELD_OFFSET(FsmBlockInfoT, Tag),
FIELD_SIZE(FsmBlockInfoT, Tag)
);
if(hw_status != HW_ERR_NONE)
return ERR_READ;
if((block_tag != FSM_TAG) || (block_status != BLOCK_ERASED))
{
if(block_tag == FSM_TAG)
{
block_tag = 0;
hw_status = DevWrite(pDev,
(uint8 *)&block_tag,
info_address + FIELD_OFFSET(FsmBlockInfoT, Tag),
FIELD_SIZE(FsmBlockInfoT, Tag)
);
if(hw_status != HW_ERR_NONE)
return ERR_WRITE;
}
hw_status = DevErase(pDev, BlockInfo.Pbn * BlockSize);
if(hw_status != HW_ERR_NONE)
{
return ERR_ERASE;
}
BlockInfo.BackupEraseCount++;
/* write block erase count. */
hw_status = DevWrite(pDev,
(uint8 *)&(BlockInfo.BackupEraseCount),
info_address + FIELD_OFFSET(FsmBlockInfoT, EraseCount),
FIELD_SIZE(FsmBlockInfoT, EraseCount)
);
if(hw_status != HW_ERR_NONE)
return ERR_WRITE;
/* write block tag. */
block_tag = FSM_TAG;
hw_status = DevWrite(pDev,
(uint8 *)&(block_tag),
info_address + FIELD_OFFSET(FsmBlockInfoT, Tag),
FIELD_SIZE(FsmBlockInfoT, Tag)
);
if(hw_status != HW_ERR_NONE)
return ERR_WRITE;
BlockStatP[BlockInfo.Pbn].EraseCount = BlockInfo.BackupEraseCount;
}
BlockInfo.Status = BLOCK_VALID;
info_address = block_address + info_offset;
hw_status = DevWrite(pDev,
(uint8 *)&(BlockInfo.Status),
info_address + FIELD_OFFSET(FsmBlockInfoT, Status),
FIELD_SIZE(FsmBlockInfoT, Status)
);
if(hw_status != HW_ERR_NONE)
return ERR_WRITE;
spare_block = BlockInfo.Pbn;
break;
case BLOCK_VALID:
break;
default:
#ifdef DEBUG_FSM
MonPrintf("No.%d block is found in unknown status %x!\n", Pbn, BlockInfo.Status);
#endif
return ERR_FORMAT;
break;
}
BlockStatP[Pbn].EraseCount = BlockInfo.EraseCount;
if(BlockInfo.EraseCount > MaxEraseCount)
{
MaxEraseCount = BlockInfo.EraseCount;
}
if(BlockInfo.EraseCount < MinEraseCount)
{
MinEraseCount = BlockInfo.EraseCount;
}
}
else
{
#ifdef DEBUG_FSM
MonPrintf("No.%d block is found with invalid tag!\n", Pbn);
#endif
invalid_tag = 1; /* Cannot use invalid_tag++ here,
* because the branch 'case BLOCK_ERASING:'
* may have fixed the block with invalid TAG.
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -