static error_t virtual_page_number_to_physical(vfl_vsvfl_device_t *_vfl, uint32_t _vpNum, uint32_t* _ce, uint32_t* _page) { uint32_t ce, vBank, ret, bank_offset, pBlock; vBank = _vpNum % _vfl->geometry.banks_total; ce = vBank % _vfl->geometry.num_ce; ret = virtual_block_to_physical_block(_vfl, vBank, _vpNum / _vfl->geometry.pages_per_sublk, &pBlock); if(FAILED(ret)) return ret; pBlock = remap_block(_vfl, ce, pBlock, 0); bank_offset = _vfl->geometry.bank_address_space * (pBlock / _vfl->geometry.blocks_per_bank); *_ce = ce; *_page = _vfl->geometry.pages_per_block_2 * (bank_offset + (pBlock % _vfl->geometry.blocks_per_bank)) + ((_vpNum % _vfl->geometry.pages_per_sublk) / _vfl->geometry.banks_total); return SUCCESS; }
static error_t vfl_vsvfl_erase_single_block(vfl_device_t *_vfl, uint32_t _vbn, int _replaceBadBlock) { vfl_vsvfl_device_t *vfl = CONTAINER_OF(vfl_vsvfl_device_t, vfl, _vfl); uint32_t bank; // In order to erase a single virtual block, we have to erase the matching // blocks across all banks. for (bank = 0; bank < vfl->geometry.banks_total; bank++) { uint32_t pBlock, pCE, blockRemapped; // Find the physical block before bad-block remapping. virtual_block_to_physical_block(vfl, bank, _vbn, &pBlock); pCE = bank % vfl->geometry.num_ce; vfl->blockBuffer[bank] = pBlock; if (is_block_in_scrub_list(vfl, pCE, pBlock)) { // TODO: this. system_panic("vsvfl: scrub list support not yet!\r\n"); } // Remap the block and calculate its physical number (considering bank address space). blockRemapped = remap_block(vfl, pCE, pBlock, 0); vfl->blockBuffer[bank] = blockRemapped % vfl->geometry.blocks_per_bank + (blockRemapped / vfl->geometry.blocks_per_bank) * vfl->geometry.bank_address_space; } // TODO: H2FMI erase multiple blocks. Currently we erase the blocks one by one. // Actually, the block buffer is used for erase multiple blocks, so we won't use it here. uint32_t status = EINVAL; for (bank = 0; bank < vfl->geometry.banks_total; bank++) { uint32_t pBlock, pCE, tries; virtual_block_to_physical_block(vfl, bank, _vbn, &pBlock); pCE = bank % vfl->geometry.num_ce; // Try to erase each block at most 3 times. for (tries = 0; tries < 3; tries++) { uint32_t blockRemapped, bankStart, blockOffset; blockRemapped = remap_block(vfl, pCE, pBlock, 0); bankStart = (blockRemapped / vfl->geometry.blocks_per_bank) * vfl->geometry.bank_address_space; blockOffset = blockRemapped % vfl->geometry.blocks_per_bank; status = nand_device_erase_single_block(vfl->device, pCE, bankStart + blockOffset); if (status == 0) break; // TODO: add block map support. //mark_bad_block(vfl, pCE, pBlock, status); bufferPrintf("vfl: failed erasing physical block %d on bank %d. status: 0x%08x\r\n", blockRemapped, bank, status); if (!_replaceBadBlock) return EINVAL; // TODO: complete bad block replacement. system_panic("vfl: found a bad block. we don't treat those for now. sorry!\r\n"); } } if (status) system_panic("vfl: failed to erase virtual block %d!\r\n", _vbn); return 0; }