/******************************************************************* * [BMT Interface] * * Description: * Update BMT. * * Parameter: * offset: update block/page offset. * reason: update reason, see update_reason_t for reason. * dat/oob: data and oob buffer for write fail. * * Return: * Return true for success, and false for failure. *******************************************************************/ bool update_bmt(u32 offset, update_reason_t reason, u8 *dat, u8 *oob) { int map_index; int orig_bad_block = -1; // int bmt_update_index; int i; int bad_index = offset / BLOCK_SIZE_BMT; //return false; if (reason == UPDATE_WRITE_FAIL) { MSG(INIT, "Write fail, need to migrate\n"); if ( !(map_index = migrate_from_bad(offset, dat, oob)) ) { MSG(INIT, "migrate fail\n"); return false; } } else { if ( !(map_index = find_available_block(false)) ) { MSG(INIT, "Cannot find block in pool\n"); return false; } } // now let's update BMT if (bad_index >= system_block_count) // mapped block become bad, find original bad block { for (i = 0; i < bmt_block_count; i++) { if (bmt.table[i].mapped_index == bad_index) { orig_bad_block = bmt.table[i].bad_index; break; } } // bmt.bad_count++; MSG(INIT, "Mapped block becomes bad, orig bad block is 0x%x\n", orig_bad_block); bmt.table[i].mapped_index = map_index; } else { bmt.table[bmt.mapped_count].mapped_index = map_index; bmt.table[bmt.mapped_count].bad_index = bad_index; bmt.mapped_count++; } memset(oob_buf, 0xFF, sizeof(oob_buf)); fill_nand_bmt_buffer(&bmt, dat_buf, oob_buf); if (!write_bmt_to_flash(dat_buf, oob_buf)) return false; mark_block_bad_bmt(offset); return true; }
/******************************************************************* * [BMT Interface] * * Description: * Update BMT. * * Parameter: * offset: update block/page offset. * reason: update reason, see update_reason_t for reason. * dat/oob: data and oob buffer for write fail. * * Return: * Return true for success, and false for failure. *******************************************************************/ bool update_bmt(u32 offset, update_reason_t reason, u8 *dat, u8 *oob) { int map_index; int orig_bad_block __attribute__((unused)) = -1; int i; int bad_index = offset / BLOCK_SIZE_BMT; if (reason == UPDATE_WRITE_FAIL) { if ( !(map_index = migrate_from_bad(offset, dat, oob)) ) { MSG("migrate fail \n"); return false; } } else { if ( !(map_index = find_available_block(false)) ) { MSG("Cannot find block in pool \n"); return false; } } // now let's update BMT if (bad_index >= system_block_count) // mapped block become bad, find original bad block { for (i = 0; i < bmt_block_count; i++) { if (bmt.table[i].mapped_index == bad_index) { orig_bad_block = bmt.table[i].bad_index; break; } } MSG("Mapped block becomes bad, orig bad block is %d \n", orig_bad_block); bmt.table[i].mapped_index = map_index; } else { bmt.table[bmt.mapped_count].mapped_index = map_index; bmt.table[bmt.mapped_count].bad_index = bad_index; bmt.mapped_count++; } memset(dat_buf, 0xFF, sizeof(dat_buf)); memset(oob_buf, 0xFF, sizeof(oob_buf)); fill_nand_bmt_buffer(&bmt, dat_buf, oob_buf); if (!write_bmt_to_flash(dat_buf, oob_buf)) return false; if (bad_index >= system_block_count) mark_block_bad_bmt(offset, BMT_BADBLOCK_GENERATE_LATER); else mark_block_bad_bmt(offset, BAD_BLOCK_RAW); return true; }
int write_bbt_or_bmt_to_flash(void) { if(need_write_bmt_to_nand) { // fill NAND BMT buffer memset(dat_buf, 0xFF, sizeof(dat_buf)); memset(oob_buf, 0xFF, sizeof(oob_buf)); fill_nand_bmt_buffer(&bmt, dat_buf, oob_buf); // write BMT back if (!write_bmt_to_flash(dat_buf, oob_buf)) { MSG("save bmt to nand fail! \n"); return -1; } } if(need_write_bbt_to_nand) { // fill NAND BBT buffer memset(dat_buf, 0xFF, sizeof(dat_buf)); memset(oob_buf, 0xFF, sizeof(oob_buf)); fill_nand_bbt_buffer(&init_bbt, dat_buf, oob_buf); // write BBT back if (!write_bbt_to_flash(dat_buf, oob_buf)) { MSG("save bbt to nand fail! \n"); return -1; } } return 0; }
/******************************************************************* * Reconstruct bmt, called when found bmt info doesn't match bad * block info in flash. * * Return NULL for failure *******************************************************************/ bmt_struct *reconstruct_bmt(bmt_struct * bmt) { int i; int index = system_block_count; unsigned short bad_index; int mapped; bmt->version = BMT_VERSION; bmt->bad_count = 0; bmt->mapped_count = 0; memset(bmt->table, 0, bmt_block_count * sizeof(bmt_entry)); for (i = 0; i < bmt_block_count; i++, index++) { if (nand_block_bad_bmt(OFFSET(index))) { MSG(INFO, "Skip bad block: 0x%x\n", index); continue; } nand_read_page_bmt(PAGE_ADDR(index), dat_buf, oob_buf); if ((bad_index = get_bad_index_from_oob(oob_buf)) >= system_block_count) { MSG(INIT, "get bad index: 0x%x\n", bad_index); if (bad_index != 0xFFFF) MSG(INIT, "Invalid bad index found in block 0x%x, bad index 0x%x\n", index, bad_index); continue; } MSG(INIT, "Block 0x%x is mapped to bad block: 0x%x\n", index, bad_index); if (!nand_block_bad_bmt(OFFSET(bad_index))) { MSG(INIT, "\tbut block 0x%x is not marked as bad, invalid mapping\n", bad_index); continue; // no need to erase here, it will be erased later when trying to write BMT } if ((mapped = is_block_mapped(bad_index)) >= 0) { MSG(INIT, "bad block 0x%x is mapped to 0x%x, should be caused by power lost, replace with one\n", bmt->table[mapped].bad_index, bmt->table[mapped].mapped_index); bmt->table[mapped].mapped_index = index; // use new one instead. } else { bmt->table[bmt->mapped_count].bad_index = bad_index; bmt->table[bmt->mapped_count].mapped_index = index; bmt->mapped_count++; } MSG(INIT, "Add mapping: 0x%x -> 0x%x to BMT\n", bad_index, index); } MSG(INIT, "Scan replace pool done, mapped block: %d\n", bmt->mapped_count); memset(oob_buf, 0xFF, sizeof(oob_buf)); fill_nand_bmt_buffer(bmt, dat_buf, oob_buf); if (!write_bmt_to_flash(dat_buf, oob_buf)) { MSG(INIT, "TRAGEDY: cannot find a place to write BMT!!!!\n"); } return bmt; }
/******************************************************************* * Reconstruct bmt, called when found bmt info doesn't match bad * block info in flash. * * Return NULL for failure *******************************************************************/ bmt_struct *reconstruct_bmt(bmt_struct * bmt) { int i; int index = system_block_count; unsigned short bad_index; int mapped; // init everything in BMT struct bmt->version = BMT_VERSION; bmt->bad_count = 0; bmt->mapped_count = 0; memset(bmt->table, 0, bmt_block_count * sizeof(bmt_entry)); for (i = 0; i < bmt_block_count; i++, index++) { if (nand_block_bad_bmt(OFFSET(index))) { // MSG(INIT, "Skip bad block: 0x%x\n", index); // bmt->bad_count++; continue; } // MSG(INIT, "read page: 0x%x\n", PAGE_ADDR(index)); nand_read_page_bmt(PAGE_ADDR(index), dat_buf, oob_buf); /* if (mt6573_nand_read_page_hw(PAGE_ADDR(index), dat_buf)) { MSG(INIT, "Error when read block %d\n", bmt_block_index); continue; } */ if ((bad_index = get_bad_index_from_oob(oob_buf)) >= system_block_count) { // MSG(INIT, "get bad index: 0x%x\n", bad_index); if (bad_index != 0xFFFF) MSG(INIT, "warning @ 0x%x\n", index); continue; } // MSG(INIT, "Block 0x%x is mapped to bad block: 0x%x\n", index, bad_index); if (!nand_block_bad_bmt(OFFSET(bad_index))) { // MSG(INIT, "\tbut block 0x%x is not marked as bad, invalid mapping\n", bad_index); continue; // no need to erase here, it will be erased later when trying to write BMT } if ( (mapped = is_block_mapped(bad_index)) >= 0) { // MSG(INIT, "bad block 0x%x is mapped to 0x%x, should be caused by power lost, replace with one\n", // bmt->table[mapped].bad_index, bmt->table[mapped].mapped_index); bmt->table[mapped].mapped_index = index; // use new one instead. } else { // add mapping to BMT bmt->table[bmt->mapped_count].bad_index = bad_index; bmt->table[bmt->mapped_count].mapped_index = index; bmt->mapped_count++; } MSG(INIT, "Add mapping: 0x%x -> 0x%x to BMT\n", bad_index, index); } MSG(INIT, "Scan replace pool done, mapped block: %d\n", bmt->mapped_count); // dump_bmt_info(bmt); // fill NAND BMT buffer memset(oob_buf, 0xFF, sizeof(oob_buf)); fill_nand_bmt_buffer(bmt, dat_buf, oob_buf); // write BMT back if (!write_bmt_to_flash(dat_buf, oob_buf)) { MSG(INIT, "TRAGEDY\n"); } return bmt; }