static int hasDeviceInfoBBT() { int bank; int good = TRUE; for(bank = 0; bank < Data->banksTotal; bank++) { good = findDeviceInfoBBT(bank, NULL); if(!good) return FALSE; } return good; }
static bool hasDeviceInfoBBT(void) { int bank; bool good = true; for(bank = 0; bank < NANDGeometry->banksTotal; bank++) { good = findDeviceInfoBBT(bank, NULL); if(!good) return false; } return good; }
int VFL_Open(void) { void* FTLCtrlBlock; u16 buffer[3]; int bank = 0; for(bank = 0; bank < NANDGeometry->banksTotal; bank++) { VFLCxt* curVFLCxt; int i; int minUsn; int VFLCxtIdx; int last; int page; if(!findDeviceInfoBBT(bank, pstBBTArea)) { LOG("ftl: findDeviceInfoBBT failed\n"); return -1; } if(bank >= NANDGeometry->banksTotal) { return -1; } curVFLCxt = &pstVFLCxt[bank]; // Any VFLCxt page will contain an up-to-date list of all blocks used to store VFLCxt pages. Find any such // page in the system area. for(i = 1; i < FTLData->sysSuBlks; i++) { // so pstBBTArea is a bit array of some sort if(!(pstBBTArea[i / 8] & (1 << (i & 0x7)))) continue; if(nand_read_vfl_cxt_page(bank, i, 0, PageBuffer, SpareBuffer) == true) { memcpy(curVFLCxt->VFLCxtBlock, ((VFLCxt*)PageBuffer)->VFLCxtBlock, sizeof(curVFLCxt->VFLCxtBlock)); break; } } if(i == FTLData->sysSuBlks) { LOG("ftl: cannot find readable VFLCxtBlock\n"); return -1; } // Since VFLCxtBlock is a ringbuffer, if blockA.page0.spare.usnDec < blockB.page0.usnDec, then for any page a // in blockA and any page b in blockB, a.spare.usNDec < b.spare.usnDec. Therefore, to begin finding the // page/VFLCxt with the lowest usnDec, we should just look at the first page of each block in the ring. minUsn = 0xFFFFFFFF; VFLCxtIdx = 4; for(i = 0; i < 4; i++) { SpareData* spareData; u16 block = curVFLCxt->VFLCxtBlock[i]; if(block == 0xFFFF) continue; if(nand_read_vfl_cxt_page(bank, block, 0, PageBuffer, SpareBuffer) != true) continue; spareData = (SpareData*) SpareBuffer; if(spareData->meta.usnDec > 0 && spareData->meta.usnDec <= minUsn) { minUsn = spareData->meta.usnDec; VFLCxtIdx = i; } } if(VFLCxtIdx == 4) { LOG("ftl: cannot find readable VFLCxtBlock index in spares\n"); return -1; } // VFLCxts are stored in the block such that they are duplicated 8 times. Therefore, we only need to // read every 8th page, and nand_read_vfl_cxt_page will try the 7 subsequent pages if the first was // no good. The last non-blank page will have the lowest spare.usnDec and highest usnInc for VFLCxt // in all the land (and is the newest). last = 0; for(page = 8; page < NANDGeometry->pagesPerBlock; page += 8) { if(nand_read_vfl_cxt_page(bank, curVFLCxt->VFLCxtBlock[VFLCxtIdx], page, PageBuffer, SpareBuffer) == false) { break; } last = page; } if(nand_read_vfl_cxt_page(bank, curVFLCxt->VFLCxtBlock[VFLCxtIdx], last, PageBuffer, SpareBuffer) == false) { LOG("ftl: cannot find readable VFLCxt\n"); return -1; } // Aha, so the upshot is that this finds the VFLCxt and copies it into pstVFLCxt memcpy(&pstVFLCxt[bank], PageBuffer, sizeof(VFLCxt)); // This is the newest VFLCxt across all banks if(curVFLCxt->usnInc >= curVFLusnInc) { curVFLusnInc = curVFLCxt->usnInc; } // Verify the checksum if(vfl_check_checksum(bank) == false) { LOG("ftl: VFLCxt has bad checksum\n"); return -1; } } // retrieve the FTL control blocks from the latest VFL across all banks. FTLCtrlBlock = VFL_GetFTLCtrlBlock(); // Need a buffer because eventually we'll copy over the source memcpy(buffer, FTLCtrlBlock, sizeof(buffer)); // Then we update the VFLCxts on every bank with that information. for(bank = 0; bank < NANDGeometry->banksTotal; bank++) { memcpy(pstVFLCxt[bank].FTLCtrlBlock, buffer, sizeof(buffer)); vfl_gen_checksum(bank); } return 0; }
static int VFL_Open() { int bank = 0; for(bank = 0; bank < Data->banksTotal; bank++) { if(!findDeviceInfoBBT(bank, pstBBTArea)) { bufferPrintf("ftl: findDeviceInfoBBT failed\r\n"); return -1; } if(bank >= Data->banksTotal) { return -1; } VFLCxt* curVFLCxt = &pstVFLCxt[bank]; uint8_t* pageBuffer = malloc(Data->bytesPerPage); uint8_t* spareBuffer = malloc(Data->bytesPerSpare); if(pageBuffer == NULL || spareBuffer == NULL) { bufferPrintf("ftl: cannot allocate page and spare buffer\r\n"); return -1; } int i = 1; for(i = 1; i < Data2->field_0; i++) { // so pstBBTArea is a bit array of some sort if(!(pstBBTArea[i / 8] & (1 << (i & 0x7)))) continue; if(vfl_read_page(bank, i, 0, pageBuffer, spareBuffer) == TRUE) { memcpy(curVFLCxt->VFLCxtBlock, ((VFLCxt*)pageBuffer)->VFLCxtBlock, sizeof(curVFLCxt->VFLCxtBlock)); break; } } if(i == Data2->field_0) { bufferPrintf("ftl: cannot find readable VFLCxtBlock\r\n"); free(pageBuffer); free(spareBuffer); return -1; } int minLpn = 0xFFFFFFFF; int VFLCxtIdx = 4; for(i = 0; i < 4; i++) { uint16_t block = curVFLCxt->VFLCxtBlock[i]; if(block == 0xFFFF) continue; if(vfl_read_page(bank, block, 0, pageBuffer, spareBuffer) != TRUE) continue; SpareData* spareData = (SpareData*) spareBuffer; if(spareData->logicalPageNumber > 0 && spareData->logicalPageNumber <= minLpn) { minLpn = spareData->logicalPageNumber; VFLCxtIdx = i; } } if(VFLCxtIdx == 4) { bufferPrintf("ftl: cannot find readable VFLCxtBlock index in spares\r\n"); free(pageBuffer); free(spareBuffer); return -1; } int page = 8; int last = 0; for(page = 8; page < Data->pagesPerBlock; page += 8) { if(vfl_read_page(bank, curVFLCxt->VFLCxtBlock[VFLCxtIdx], page, pageBuffer, spareBuffer) == FALSE) { break; } last = page; } if(vfl_read_page(bank, curVFLCxt->VFLCxtBlock[VFLCxtIdx], last, pageBuffer, spareBuffer) == FALSE) { bufferPrintf("ftl: cannot find readable VFLCxt\n"); free(pageBuffer); free(spareBuffer); return -1; } // Aha, so the upshot is that this finds the VFLCxt and copies it into pstVFLCxt memcpy(&pstVFLCxt[bank], pageBuffer, sizeof(VFLCxt)); if(curVFLCxt->field_0 >= VFLData4) { VFLData4 = curVFLCxt->field_0; } free(pageBuffer); free(spareBuffer); if(vfl_check_checksum(bank) == FALSE) { bufferPrintf("ftl: VFLCxt has bad checksum\n"); return -1; } } void* maxThing = VFL_get_maxThing(); uint16_t buffer[3]; memcpy(buffer, maxThing, 6); for(bank = 0; bank < Data->banksTotal; bank++) { memcpy(pstVFLCxt[bank].field_4, buffer, sizeof(buffer)); vfl_gen_checksum(bank); } return 0; }