static int add_block_to_scrub_list(vfl_vsvfl_device_t *_vfl, uint32_t _ce, uint32_t _block) { if(is_block_in_scrub_list(_vfl, _ce, _block)) return 0; if(_vfl->contexts[_ce].scrub_list_length > 0x13) { bufferPrintf("vfl: too many scrubs!\r\n"); return 0; } if(!vfl_check_checksum(_vfl, _ce)) system_panic("vfl_add_block_to_scrub_list: failed checksum\r\n"); _vfl->contexts[_ce].scrub_list[_vfl->contexts[_ce].scrub_list_length++] = _block; vfl_gen_checksum(_vfl, _ce); return vsvfl_store_vfl_cxt(_vfl, _ce); }
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; }