static error_t vsvfl_store_vfl_cxt(vfl_vsvfl_device_t *_vfl, uint32_t _ce) { if(_ce >= _vfl->geometry.num_ce) system_panic("vfl: Can't store VFLCxt on non-existent CE\r\n"); vfl_vsvfl_context_t *curVFLCxt = &_vfl->contexts[_ce]; if(curVFLCxt->usn_page + 8 > _vfl->geometry.pages_per_block || FAILED(vsvfl_write_vfl_cxt_to_flash(_vfl, _ce))) { int startBlock = curVFLCxt->usn_block; int nextBlock = (curVFLCxt->usn_block + 1) % 4; while(startBlock != nextBlock) { if(curVFLCxt->vfl_context_block[nextBlock] != 0xFFFF) { int fail = 0; int i; for (i = 0; i < 4; i++) { uint32_t bankStart = (curVFLCxt->vfl_context_block[nextBlock] / _vfl->geometry.blocks_per_bank) * _vfl->geometry.bank_address_space; uint32_t blockOffset = curVFLCxt->vfl_context_block[nextBlock] % _vfl->geometry.blocks_per_bank; int status = nand_device_erase_single_block(_vfl->device, _ce, bankStart + blockOffset); if(SUCCEEDED(status)) break; //vsvfl_mark_bad_vfl_block(_vfl, _ce, curVFLCxt->vfl_context_block[nextBlock], status); if(i == 3) fail = 1; } if(!fail) { if(!vfl_check_checksum(_vfl, _ce)) system_panic("vsvfl_store_vfl_cxt: failed checksum\r\n"); curVFLCxt->usn_block = nextBlock; curVFLCxt->usn_page = 0; vfl_gen_checksum(_vfl, _ce); int result = vsvfl_write_vfl_cxt_to_flash(_vfl, _ce); if(SUCCEEDED(result)) return result; } } nextBlock = (nextBlock + 1) % 4; } return EIO; } 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; }