/* ************************************************************************************************************************ * SET LOG BLOCK PARAMETER IN THE LOG BLOCK TABLE * *Description: Set the parameter for log block in the log block table. * *Arguments : nLogicBlk the logical block number which the log block is belonged to; * pLogBlk the pointer to log block parameter which need be set to log block table. * *Return : set log block result; * = 0 set log block successful; * < 0 set log block failed. ************************************************************************************************************************ */ __s32 BMM_SetLogBlk(__u32 nLogicBlk, struct __LogBlkType_t *pLogBlk) { __s32 tmpLogPst; tmpLogPst = _GetLogBlkPst(nLogicBlk); if(tmpLogPst < 0) { tmpLogPst = _GetLogBlkPst(0xffff); if(tmpLogPst < 0) { MAPPING_ERR("[MAPPING_ERR] Set log block table item failed!\n"); return -1; } } //set the log block item in the log block table LOG_BLK_TBL[tmpLogPst] = *pLogBlk; return 0; }
/* ************************************************************************************************************************ * GET LOG PAGE PARAMETER * *Description: Get a page from log block for read or write. * *Arguments : nBlk the logical block number of the log block; * nPage the number of the logical page, which page need log page; * nMode the type of get log page, 'r' or 'w', others is invalid. * *Return : the number of the log page; * != 0xffff get log page successful, return page number; * = 0xffff get log page failed. * *Note : Scan the log block table to try to get the log block. * when the get type is 'r', if the log block is exsit and the logical * page contain a log page, return the number of the log page, else, * return 0xffff; * when the get type is 'w', if the log block is not exsit, need create * log block, then, if get log page failed, need merge the log block, and * try to get log page again, this mode should return a value page number * except there is no enough valid blocks. ************************************************************************************************************************ */ __u32 PMM_GetLogPage(__u32 nBlk, __u32 nPage, __u8 nMode) { __s32 result, tmpLogPst; __u16 tmpPage, PhyPageNum; if(nMode == 'r') { tmpLogPst = _GetLogBlkPst(nBlk); if(tmpLogPst < 0) { //get log page by read mode, there is no log block, return invalid value return INVALID_PAGE_NUM; } //need swap the page mapping table to ram which is accessing currently result = PMM_SwitchMapTbl(tmpLogPst); if(result < 0) { MAPPING_ERR("[MAPPING_ERR] Switch page mapping table failed when get log page! Err:0x%x\n", result); return INVALID_PAGE_NUM; } _CalLogAccessCnt(tmpLogPst); //get active read log block index if((SUPPORT_LOG_BLOCK_MANAGE)&&(LOG_BLK_TBL[tmpLogPst].LogBlkType == LSB_TYPE)) { PhyPageNum = PAGE_MAP_TBL[nPage].PhyPageNum; if((PhyPageNum&(0x1<<15))&&(PhyPageNum!= 0xffff)) { LOG_BLK_TBL[tmpLogPst].ReadBlkIndex = 1; PhyPageNum &= 0x7fff; } else LOG_BLK_TBL[tmpLogPst].ReadBlkIndex = 0; return (PhyPageNum|LOG_BLK_TBL[tmpLogPst].ReadBlkIndex<<16); } else { LOG_BLK_TBL[tmpLogPst].ReadBlkIndex = 0; return PAGE_MAP_TBL[nPage].PhyPageNum; } } result = _GetLogPageForWrite(nBlk, nPage, &tmpPage, (__u32 *)&tmpLogPst); if(result < 0) { //get log page for write failed MAPPING_ERR("[MAPPING_ERR] Get log page for write failed!\n"); return INVALID_PAGE_NUM; } //check if the log page is valid if(!(tmpPage < PAGE_CNT_OF_SUPER_BLK)) { //the log page is not invalid, need to merge the log block, and get again result = LML_MergeLogBlk(SPECIAL_MERGE_MODE, nBlk); if(result < 0) { //merge log block failed, report error MAPPING_ERR("[MAPPING_ERR] Merge log block failed when get log page! Err:0x%x\n", result); return INVALID_PAGE_NUM; } //try to get log page for write again result = _GetLogPageForWrite(nBlk, nPage, &tmpPage, (__u32 *)&tmpLogPst); if(result < 0) { //get log page for write failed MAPPING_ERR("[MAPPING_ERR] Get log page for write failed!\n"); return INVALID_PAGE_NUM; } } //check if the log page is valid if(!(tmpPage < PAGE_CNT_OF_SUPER_BLK)) { //get log page for write failed MAPPING_ERR("[MAPPING_ERR] Get log page for write failed!\n"); return INVALID_PAGE_NUM; } else { LOG_BLK_TBL[tmpLogPst].LastUsedPage = tmpPage; } //update the page mapping table item if((SUPPORT_LOG_BLOCK_MANAGE)&&(LOG_BLK_TBL[tmpLogPst].LogBlkType == LSB_TYPE)) { DBUG_MSG("[DBUG_MSG] PMM_GetLogPage 2, select bak log block\n"); PAGE_MAP_TBL[nPage].PhyPageNum = tmpPage|((LOG_BLK_TBL[tmpLogPst].WriteBlkIndex&0x1)<<15); } else PAGE_MAP_TBL[nPage].PhyPageNum = tmpPage; //set the flag that mark need update the page mapping table PAGE_MAP_CACHE->DirtyFlag = 1; _CalLogAccessCnt(tmpLogPst); if((SUPPORT_LOG_BLOCK_MANAGE)&&(LOG_BLK_TBL[tmpLogPst].LogBlkType == LSB_TYPE)) return (tmpPage|LOG_BLK_TBL[tmpLogPst].WriteBlkIndex<<16); else return tmpPage; }
/* ************************************************************************************************************************ * GET LOG PAGE FOR WRITE * *Description: Get a log page for write. * *Arguments : nBlk the logical block number of the log block; * nPage the number of the logical page, which page need log page; * pLogPage the pointer to the log page number, for return value; * pLogPst the pointer to the position of the log block in the log block table. * *Return : get log page result. * = 0 get log page for write successful; * =-1 get log page for write failed. ************************************************************************************************************************ */ static __s32 _GetLogPageForWrite(__u32 nBlk, __u32 nPage, __u16 *pLogPage, __u32 *pLogPst) { __s32 result, tmpLogPst; __u16 tmpPage, tempBank; struct __PhysicOpPara_t tmpPhyPage; struct __NandUserData_t tmpSpare[2]; tmpLogPst = _GetLogBlkPst(nBlk); if(tmpLogPst < 0) { //get log block position failed, there is no such log block, need create a new one result = _CreateNewLogBlk(nBlk, (__u32 *)&tmpLogPst); if(result < 0) { MAPPING_ERR("[MAPPING_ERR] Create new log block failed!\n"); return -1; } } //need swap the page mapping table to ram which is accessing currently result = PMM_SwitchMapTbl(tmpLogPst); if(result < 0) { MAPPING_ERR("[MAPPING_ERR] Switch page mapping table failed when get log page! Err:0x%x\n", result); return -1; } //need get log page by write mode, tmpPage = LOG_BLK_TBL[tmpLogPst].LastUsedPage; if(SUPPORT_ALIGN_NAND_BNK) { if(tmpPage == 0xffff) { //the log block is empty, need get log page in the first page line tmpPage = nPage % INTERLEAVE_BANK_CNT; } else { //need bank align, the log page and the data page should be in the same bank if((nPage % INTERLEAVE_BANK_CNT) > (tmpPage % INTERLEAVE_BANK_CNT)) { //get the log page in the same page line with last used page tmpPage = tmpPage + ((nPage % INTERLEAVE_BANK_CNT) - (tmpPage % INTERLEAVE_BANK_CNT)); } else { //need get the log page in the next page line of the last used page tmpPage = tmpPage + (nPage % INTERLEAVE_BANK_CNT) + (INTERLEAVE_BANK_CNT - (tmpPage % INTERLEAVE_BANK_CNT)); } } } else { //use the page which is the next of the last used page tmpPage = tmpPage + 1; } if((SUPPORT_LOG_BLOCK_MANAGE)&&(LOG_BLK_TBL[tmpLogPst].LogBlkType == LSB_TYPE)) { DBUG_MSG("[DBUG_MSG] _GetLogPageForWrite, select bak log block\n"); if(SUPPORT_ALIGN_NAND_BNK) { tempBank = tmpPage%INTERLEAVE_BANK_CNT; tmpPage =PMM_CalNextLogPage(tmpPage); while(tmpPage%INTERLEAVE_BANK_CNT != tempBank) { tmpPage++; tmpPage =PMM_CalNextLogPage(tmpPage); if(tmpPage>=PAGE_CNT_OF_SUPER_BLK) break; } } else { tmpPage =PMM_CalNextLogPage(tmpPage); } if((tmpPage >= PAGE_CNT_OF_SUPER_BLK)&&(LOG_BLK_TBL[tmpLogPst].WriteBlkIndex == 0)) { LOG_BLK_TBL[tmpLogPst].WriteBlkIndex = 1; tmpPage = tmpPage - PAGE_CNT_OF_SUPER_BLK; } if(LOG_BLK_TBL[tmpLogPst].WriteBlkIndex == 1) DBUG_MSG("[DBUG_MSG] _GetLogPageForWrite, log block index: %x, log block num: %x, page: %x \n", LOG_BLK_TBL[tmpLogPst].WriteBlkIndex, LOG_BLK_TBL[tmpLogPst].PhyBlk1.PhyBlkNum, tmpPage); else DBUG_MSG("[DBUG_MSG] _GetLogPageForWrite, log block index: %x, log block num: %x, page: %x \n", LOG_BLK_TBL[tmpLogPst].WriteBlkIndex, LOG_BLK_TBL[tmpLogPst].PhyBlk.PhyBlkNum, tmpPage); } __CHECK_WRITE_LOGICAL_INFO_OF_LOG_BLOCK: //check if need write the logical information in the first page of the log block if((LOG_BLK_TBL[tmpLogPst].LastUsedPage == 0xffff) && (tmpPage != 0)) { //get logical information from the data block LML_CalculatePhyOpPar(&tmpPhyPage, CUR_MAP_ZONE, DATA_BLK_TBL[nBlk].PhyBlkNum, 0); tmpPhyPage.SectBitmap = 0x03; tmpPhyPage.MDataPtr = LML_TEMP_BUF; tmpPhyPage.SDataPtr = (void *)tmpSpare; LML_VirtualPageRead(&tmpPhyPage); //if((SUPPORT_LOG_BLOCK_MANAGE)&&(LOG_BLK_TBL[tmpLogPst].LogBlkType == LSB_TYPE)) //{ // PRINT("_GetLogPageForWrite log %x page 0, data age: %x, log age: %x\n", LOG_BLK_TBL[tmpLogPst].WriteBlkIndex, tmpSpare[0].PageStatus, tmpSpare[0].PageStatus+1); //} tmpSpare[0].BadBlkFlag = 0xff; tmpSpare[1].BadBlkFlag = 0xff; tmpSpare[0].LogicInfo = ((CUR_MAP_ZONE % ZONE_CNT_OF_DIE)<<10) | nBlk; tmpSpare[1].LogicInfo = ((CUR_MAP_ZONE % ZONE_CNT_OF_DIE)<<10) | nBlk; tmpSpare[0].LogicPageNum = 0xffff; tmpSpare[1].LogicPageNum = 0xffff; tmpSpare[0].PageStatus = tmpSpare[0].PageStatus + 1; tmpSpare[1].PageStatus = tmpSpare[0].PageStatus; if((SUPPORT_LOG_BLOCK_MANAGE)&&(LOG_BLK_TBL[tmpLogPst].LogBlkType == LSB_TYPE)) { tmpSpare[0].LogType = LSB_TYPE|(LOG_BLK_TBL[tmpLogPst].WriteBlkIndex<<4); tmpSpare[1].LogType = LSB_TYPE|(LOG_BLK_TBL[tmpLogPst].WriteBlkIndex<<4); } else { tmpSpare[0].LogType = 0xff; tmpSpare[1].LogType = 0xff; } //write the logical information to the spare area of the data block if((SUPPORT_LOG_BLOCK_MANAGE)&&(LOG_BLK_TBL[tmpLogPst].LogBlkType == LSB_TYPE)) { DBUG_MSG("[DBUG] _GetLogPageForWrite, write the logical information to log page 0, writeblkindex: %x\n", LOG_BLK_TBL[tmpLogPst].WriteBlkIndex); LML_CalculatePhyOpPar(&tmpPhyPage, CUR_MAP_ZONE, LOG_BLK_TBL[tmpLogPst].PhyBlk.PhyBlkNum, 0); } else LML_CalculatePhyOpPar(&tmpPhyPage, CUR_MAP_ZONE, LOG_BLK_TBL[tmpLogPst].PhyBlk.PhyBlkNum, 0); tmpPhyPage.SectBitmap = FULL_BITMAP_OF_SUPER_PAGE; result = LML_VirtualPageWrite(&tmpPhyPage); if(result < 0) { LOGICCTL_ERR("[MAPPING_ERR] Physical write module failed when write logical information, Err:0x%x!\n", result); return -1; } result = PHY_SynchBank(tmpPhyPage.BankNum, SYNC_CHIP_MODE); if(result < 0) { //the last write operation on current bank is failed, the block is bad, need proccess it LOGICCTL_DBG("[LOGICCTL_DBG] Find a bad block when write logical page! bank:0x%x, block:0x%x, page:0x%x\n", tmpPhyPage.BankNum, tmpPhyPage.BlkNum, tmpPhyPage.PageNum); //process the bad block result = LML_BadBlkManage(&LOG_BLK_TBL[tmpLogPst].PhyBlk, CUR_MAP_ZONE, 0, &LOG_BLK_TBL[tmpLogPst].PhyBlk); if(result < 0) { LOGICCTL_ERR("[MAPPING_ERR] Bad block process failed when get log page for write, Err:0x%x!\n", result); return -1; } goto __CHECK_WRITE_LOGICAL_INFO_OF_LOG_BLOCK; } } //set the log page number for return *pLogPage = tmpPage; *pLogPst = tmpLogPst; return 0; }
/* ************************************************************************************************************************ * GET PARAMETER OF LOG BLOCK * *Description: Get parameter of log block. * *Arguments : nLogicBlk the logical block number which the log block is belonged to; * pLogBlk the pointer to the log block item for return; * *Return : get log block result; * = 0 get log block successful; * =-1 get log block failed. * *Note : Scan the log block table which is accessing in the buffer currently, * to look for the log block, if the log block is exsit, return 0, * else, return -1 ************************************************************************************************************************ */ __s32 BMM_GetLogBlk(__u32 nLogicBlk, struct __LogBlkType_t *pLogBlk) { __s32 tmpLogPst, result; struct __SuperPhyBlkType_t tmpFreeBlk1; __u32 LogBlkType; tmpLogPst = _GetLogBlkPst(nLogicBlk); if(tmpLogPst < 0) { //if the logic block number is invalid, report error if(nLogicBlk > DATA_BLK_CNT_OF_ZONE) { MAPPING_ERR("[MAPPING_ERR] Logical block number(0x%x) is invalid when get log block!\n", nLogicBlk); } if(pLogBlk != NULL) { pLogBlk->LogicBlkNum = 0xffff; pLogBlk->LastUsedPage = 0xffff; pLogBlk->LogBlkType = 0; pLogBlk->ReadBlkIndex = 0; pLogBlk->WriteBlkIndex = 0; pLogBlk->PhyBlk.PhyBlkNum = 0xffff; pLogBlk->PhyBlk.BlkEraseCnt = 0xffff; pLogBlk->PhyBlk1.PhyBlkNum = 0xffff; pLogBlk->PhyBlk1.BlkEraseCnt = 0xffff; pLogBlk->PhyBlk2.PhyBlkNum = 0xffff; pLogBlk->PhyBlk2.BlkEraseCnt = 0xffff; } return -1; } else { if(pLogBlk != NULL) { if(SUPPORT_LOG_BLOCK_MANAGE) { LogBlkType = BMM_CalLogBlkType(nLogicBlk); if(LOG_BLK_TBL[tmpLogPst].LogBlkType == 0xffff) { PRINT("[DBUG] find a log table item with valid log block type!\n"); LOG_BLK_TBL[tmpLogPst].LogBlkType = 0; LOG_BLK_TBL[tmpLogPst].WriteBlkIndex = 0; LOG_BLK_TBL[tmpLogPst].ReadBlkIndex = 0; } //check log type for debug if(LOG_BLK_TBL[tmpLogPst].LogBlkType != LogBlkType) { PRINT("[DBUG] LogBlkTye mismatch: 0x%x, 0x%x\n",LOG_BLK_TBL[tmpLogPst].LogBlkType, LogBlkType); if((LOG_BLK_TBL[tmpLogPst].LogBlkType == NORMAL_TYPE)&&(LogBlkType == LSB_TYPE)) { //get a free block to create a new log block result = BMM_GetFreeBlk(LOWEST_EC_TYPE, &tmpFreeBlk1); if(result < 0) { MAPPING_ERR("[MAPPING_ERR] Get free block failed when create new log block!\n"); return -1; } //make a new log item in the log block table LOG_BLK_TBL[tmpLogPst].LogBlkType = LogBlkType; LOG_BLK_TBL[tmpLogPst].WriteBlkIndex = 0; LOG_BLK_TBL[tmpLogPst].ReadBlkIndex = 0; LOG_BLK_TBL[tmpLogPst].PhyBlk1.PhyBlkNum = tmpFreeBlk1.PhyBlkNum; LOG_BLK_TBL[tmpLogPst].PhyBlk1.BlkEraseCnt = tmpFreeBlk1.BlkEraseCnt; *pLogBlk = LOG_BLK_TBL[tmpLogPst]; } } else { *pLogBlk = LOG_BLK_TBL[tmpLogPst]; } } else { *pLogBlk = LOG_BLK_TBL[tmpLogPst]; } } } return 0; }