⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fsmplr.c

📁 norflash的文件系统。 用于中低端手机开发的参考
💻 C
📖 第 1 页 / 共 5 页
字号:
/*****************************************************************************
 
  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 + -