📄 inftl.c
字号:
#endif /* FL_READ_ONLY */
/*----------------------------------------------------------------------*/
/* g e t U n i t D a t a */
/* */
/* Get virtual unit No. and replacement unit no. of a unit. */
/* */
/* Parameters: */
/* vol : Pointer identifying drive */
/* unitNo : Physical unit number */
/* virtualUnitNo : Returns the virtual unit no. */
/* prevUnitNo : Returns the previous unit no. */
/* ANAC : Returns the Accumulating Number Along Chain. */
/* NAC : Returns the Number Along Chain value. */
/* validFields : Returns a bit map of the valid fields. */
/* */
/* Returns: */
/* flOK on success, flHWProtection on H/W read protection. */
/*----------------------------------------------------------------------*/
static FLStatus getUnitData(Bnand vol,
ANANDUnitNo unitNo,
ANANDUnitNo *virtualUnitNo,
ANANDUnitNo *prevUnitNo,
byte *ANAC,
byte *NAC,
byte *validFields)
{
ANANDUnitHeader unitData;
SecondANANDUnitHeader secondUnitData;
FLStatus status;
byte parityPerField=0;
byte temp;
byte returnedValidField = ALL_PARITY_BITS_OK;
byte curValidFields[2];
int index;
#ifdef NFTL_CACHE
/* on cache miss read ANANDUnitHeader from flash and re-fill cache */
if ((vol.ucache != NULL)&&(vol.ucache[unitNo].virtualUnitNo != 0xDEAD) &&
(vol.ucache[unitNo].prevUnitNo != 0xDEAD))
{
*virtualUnitNo = vol.ucache[unitNo].virtualUnitNo;
*prevUnitNo = vol.ucache[unitNo].prevUnitNo;
*ANAC = vol.ucache[unitNo].ANAC;
*NAC = vol.ucache[unitNo].NAC;
}
else
#endif /* NFTL_CACHE */
{ /* no ANANDUnitHeader cache MUST read first header */
*validFields = 0; /* Set all fields to be invalid */
/* Read first unit data */
status = vol.flash->read(vol.flash,
unitBaseAddress(vol,unitNo) + UNIT_DATA_OFFSET,
&unitData,
sizeof(ANANDUnitHeader),
EXTRA);
if(status != flOK)
return status;
*virtualUnitNo = LE2(unitData.virtualUnitNo);
*prevUnitNo = LE2(unitData.prevUnitNo );
*ANAC = unitData.ANAC;
*NAC = unitData.NAC;
for(index=0;index<2;index++)
{
/* If all data is 0xff assume a free unit */
if((*virtualUnitNo == ANAND_NO_UNIT )&&
(*prevUnitNo == ANAND_NO_UNIT )&&
(*ANAC == ANAND_UNIT_FREE)&&
(*NAC == ANAND_UNIT_FREE)&&
(unitData.discarded == ANAND_UNIT_FREE))
{
#ifndef FL_READ_ONLY
if(index!=0)
{
/* If this is the second copy then the first was not */
/* erased, but since it was written first it makes no */
/* sence. Let us erase it just in case. */
status = formatUnit(&vol,unitNo,UNIT_TAILER_OFFSET);
if(status != flOK)
return status;
}
#endif /* FL_READ_ONLY */
break;
}
/* Not a free unit check unit data validity (discard and partity) */
if ((onesCount((byte)(unitData.discarded^DISCARD))>1))
{
/* Discarded mark is more then 1 bit distance from 0xAA */
/* Assume erase operation was interrupted and erase unit */
TL_DEBUG_PRINT(tl_out,"getUnitData : unit %d has an invalid discard mark\n",unitNo);
TL_DEBUG_PRINT(tl_out," it might be helpful to know it was %d\n",unitData.discarded);
#ifndef FL_READ_ONLY
status = formatUnit(&vol,unitNo,UNIT_TAILER_OFFSET);
if(status != flOK)
return status;
#endif /* FL_READ_ONLY */
*virtualUnitNo = ANAND_NO_UNIT;
*prevUnitNo = ANAND_NO_UNIT;
*ANAC = ANAND_UNIT_FREE;
*NAC = ANAND_UNIT_FREE;
break;
}
/* Discarded OK now check parity field */
parityPerField = 0;
temp=(byte)(((byte *)virtualUnitNo)[0]^((byte *)virtualUnitNo)[1]);
if((onesCount(temp) & 1)==1)
parityPerField|=VU_PARITY_BIT;
temp=(byte)(((byte *)prevUnitNo)[0]^((byte *)prevUnitNo)[1]);
if((onesCount(temp) & 1)==1)
parityPerField|=PU_PARITY_BIT;
if((onesCount(unitData.ANAC) & 1)==1)
parityPerField|=ANAC_PARITY_BIT;
if((onesCount(unitData.NAC) & 1)==1)
parityPerField|=NAC_PARITY_BIT;
/* Store valid fields using bitmap */
curValidFields[index] = (byte)((~(parityPerField ^ unitData.parityPerField))
& ALL_PARITY_BITS_OK);
if(curValidFields[index] == ALL_PARITY_BITS_OK)
{
/* If either copies has valid fields (all of them) use it */
break;
}
else
{
if(index>0)
{
/* Use first header data if possible otherwise use second */
returnedValidField = (byte)(curValidFields[0] | curValidFields[1]);
TL_DEBUG_PRINT(tl_out,"getUnitData : The returned valid field indicator is %d\n",returnedValidField);
TL_DEBUG_PRINT(tl_out," While %d indicates a valid unit data\n",ALL_PARITY_BITS_OK);
if(curValidFields[0] & VU_PARITY_BIT)
*virtualUnitNo = LE2(unitData.virtualUnitNo);
if(curValidFields[0] & PU_PARITY_BIT)
*prevUnitNo = LE2(unitData.prevUnitNo );
if(curValidFields[0] & ANAC_PARITY_BIT)
*ANAC = unitData.ANAC;
if(curValidFields[0] & NAC_PARITY_BIT)
*NAC = unitData.ANAC;
break;
}
}
/* Read second unit header for next iteration */
status = vol.flash->read(vol.flash, unitBaseAddress(vol,unitNo) +
SECOND_HEADER_OFFSET + UNIT_DATA_OFFSET,
&secondUnitData,
sizeof(SecondANANDUnitHeader),
EXTRA);
if(status != flOK)
return status;
*virtualUnitNo = LE2(secondUnitData.virtualUnitNo);
*prevUnitNo = LE2(secondUnitData.prevUnitNo );
*ANAC = secondUnitData.ANAC;
*NAC = secondUnitData.NAC;
TL_DEBUG_PRINT(tl_out,"getUnitData : First unit header is not OK in unit %d \n",unitNo);
TL_DEBUG_PRINT(tl_out,"getUnitData : Virtual Unit No = %d \n",LE2(unitData.virtualUnitNo));
TL_DEBUG_PRINT(tl_out,"getUnitData : Previous Unit No = %d \n",LE2(unitData.prevUnitNo));
TL_DEBUG_PRINT(tl_out,"getUnitData : ANAC = %d \n",unitData.ANAC);
TL_DEBUG_PRINT(tl_out,"getUnitData : NAC = %d \n",unitData.NAC);
TL_DEBUG_PRINT(tl_out,"getUnitData : ParityPerField = %d \n",unitData.parityPerField);
TL_DEBUG_PRINT(tl_out,"getUnitData : Discarded = %d \n",unitData.discarded);
TL_DEBUG_PRINT(tl_out,"getUnitData : Second unit header of the same unit %d is:\n",unitNo);
TL_DEBUG_PRINT(tl_out,"getUnitData : Virtual Unit No = %d \n",LE2(secondUnitData.virtualUnitNo));
TL_DEBUG_PRINT(tl_out,"getUnitData : Previous Unit No = %d \n",LE2(secondUnitData.prevUnitNo));
TL_DEBUG_PRINT(tl_out,"getUnitData : ANAC = %d \n",secondUnitData.ANAC);
TL_DEBUG_PRINT(tl_out,"getUnitData : NAC = %d \n",secondUnitData.NAC);
TL_DEBUG_PRINT(tl_out,"getUnitData : ParityPerField = %d \n",secondUnitData.parityPerField);
}
#ifdef NFTL_CACHE
if ((vol.ucache != NULL) && /* Cache enabled */
(returnedValidField == ALL_PARITY_BITS_OK)) /* All fields valid */
{
vol.ucache[unitNo].virtualUnitNo = *virtualUnitNo;
vol.ucache[unitNo].prevUnitNo = *prevUnitNo;
vol.ucache[unitNo].ANAC = *ANAC;
vol.ucache[unitNo].NAC = *NAC;
}
#endif /* NFTL_CACHE */
}
*validFields = returnedValidField;
return flOK;
}
/*----------------------------------------------------------------------*/
/* g e t P r e v U n i t */
/* */
/* Get next unit in chain. */
/* */
/* Parameters: */
/* vol : Pointer identifying drive */
/* unitNo : Physical unit number */
/* virUnitNo : The expected virtual unit number */
/* */
/* Returns: */
/* Physical unit number of the unit following unitNo in the chain. */
/* If such unit do not exist, return ANAND_NO_UNIT. */
/*----------------------------------------------------------------------*/
static ANANDUnitNo getPrevUnit(Bnand vol, ANANDUnitNo unitNo, ANANDUnitNo virUnitNo)
{
ANANDUnitNo virtualUnitNo, replacementUnitNo;
byte ANAC,NAC;
byte parityPerField;
/* If first in chain there can be not previous unit */
if ((vol.physicalUnits[unitNo] & FIRST_IN_CHAIN))
return ANAND_NO_UNIT;
getUnitData(&vol,unitNo,&virtualUnitNo,&replacementUnitNo,&ANAC,&NAC,&parityPerField);
/* check if unit is valid */
if((badParityResult(parityPerField)) || ( virUnitNo != virtualUnitNo ))
{
TL_DEBUG_PRINT(tl_out,"getPrevUnit : An invalid unit was detected on getPrevUnit - parity is %x/0xf ",parityPerField);
TL_DEBUG_PRINT(tl_out,"given virtual unit no is %d ",virUnitNo);
TL_DEBUG_PRINT(tl_out,"where %d was read\n",virtualUnitNo);
SET_EXIT(INFTL_FAILED_MOUNT);
return ANAND_BAD_CHAIN_UNIT;
}
return replacementUnitNo;
}
#ifdef NFTL_CACHE
/*----------------------------------------------------------------------*/
/* g e t S e c t o r F l a g s F r o m C a c h e */
/* */
/* Get sector flags from Sector Cache. */
/* */
/* Parameters: */
/* vol : Pointer identifying drive */
/* address : starting address of the sector */
/* */
/* Returns: */
/* sector flags (SECTOR_USED, SECTOR_DELETED etc.) */
/*----------------------------------------------------------------------*/
static byte getSectorFlagsFromCache(Bnand vol, CardAddress address)
{
return scacheTable[((vol.scache[(address - vol.firstUnitAddress) >> (SECTOR_SIZE_BITS+2)] >>
(((word)address >> 8) & 0x7)) & 0x3)];
}
/*----------------------------------------------------------------------*/
/* s e t S e c t o r F l a g s C a c h e */
/* */
/* Get sector flags from Sector Cache. */
/* */
/* Parameters: */
/* vol : Pointer identifying drive */
/* address : starting address of the sector */
/* sectorFlags : one of SECTOR_USED, SECTOR_DELETED etc. */
/* */
/*----------------------------------------------------------------------*/
static void setSectorFlagsCache(Bnand vol, CardAddress address,
byte sectorFlags)
{
register byte tmp, val;
if (vol.scache == NULL)
return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -