/******************************************************************* * 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; }
/************************************************************************* * Find an available block and erase. * * start_from_end: if true, find available block from end of flash. * * else, find from the beginning of the pool * * need_erase: if true, all unmapped blocks in the pool will be erased * *************************************************************************/ static int find_available_block(bool start_from_end) { int i; int block = system_block_count; int direction; MSG("Try to find_available_block, pool_erase: %d\n", pool_erased); // erase all un-mapped blocks in pool when finding avaliable block if (!pool_erased) { for (i = 0; i < bmt_block_count; i++) { if ((block + i) == bmt_block_index) { MSG("Skip bmt block %d \n", block + i); continue; } if ((block + i) == bbt_block_index) { MSG("Skip bbt block %d \n", block + i); continue; } if (nand_block_bad_bmt(OFFSET(block + i), BAD_BLOCK_RAW) || nand_block_bad_bmt(OFFSET(block + i), BMT_BADBLOCK_GENERATE_LATER)) { MSG("Skip bad block %d \n", block + i); continue; } if (is_block_mapped(block + i) >= 0) { MSG("Skip mapped block %d \n", block + i); continue; } if (nand_erase_bmt(OFFSET(block + i))) { MSG("Erase block %d fail\n", block + i); mark_block_bad_bmt(OFFSET(block + i), BMT_BADBLOCK_GENERATE_LATER); } } pool_erased = 1; } if (start_from_end) { block = total_block_count - 1; direction = -1; } else { block = system_block_count; direction = 1; } for (i = 0; i < bmt_block_count; i++, block += direction) { if (block == bmt_block_index) { MSG("Skip bmt block %d \n", block); continue; } if (block == bbt_block_index) { MSG("Skip bbt block %d \n", block); continue; } if (nand_block_bad_bmt(OFFSET(block), BAD_BLOCK_RAW) || nand_block_bad_bmt(OFFSET(block), BMT_BADBLOCK_GENERATE_LATER)) { MSG("Skip bad block %d \n", block); continue; } if (is_block_mapped(block) >= 0) { MSG("Skip mapped block %d \n", block); continue; } MSG("Find block %d available\n", block); return block; } return 0; }
/************************************************************************* * Find an available block and erase. * * start_from_end: if true, find available block from end of flash. * * else, find from the beginning of the pool * * need_erase: if true, all unmapped blocks in the pool will be erased * *************************************************************************/ static int find_available_block(bool start_from_end) { int i; // , j; int block = system_block_count; int direction; MSG(INIT, "Try to find_available_block, pool_erase: %d\n", pool_erased); if (!pool_erased) { MSG(INIT, "Erase all un-mapped blocks in pool\n"); for (i = 0; i < bmt_block_count; i++) { if (block == bmt_block_index) { MSG(INIT, "Skip bmt block 0x%x\n", block); continue; } if (nand_block_bad_bmt(OFFSET(block + i))) { MSG(INIT, "Skip bad block 0x%x\n", block + i); continue; } if (is_block_mapped(block + i) >= 0) { MSG(INIT, "Skip mapped block 0x%x\n", block + i); continue; } if (!nand_erase_bmt(OFFSET(block + i))) { MSG(INIT, "Erase block 0x%x failed\n", block + i); mark_block_bad_bmt(OFFSET(block + i)); } } pool_erased = 1; } if (start_from_end) { block = total_block_count - 1; direction = -1; } else { block = system_block_count; direction = 1; } for (i = 0; i < bmt_block_count; i++, block += direction) { if (block == bmt_block_index) { MSG(INIT, "Skip bmt block 0x%x\n", block); continue; } if (nand_block_bad_bmt(OFFSET(block))) { MSG(INIT, "Skip bad block 0x%x\n", block); continue; } if (is_block_mapped(block) >= 0) { MSG(INIT, "Skip mapped block 0x%x\n", block); continue; } MSG(INIT, "Find block 0x%x available\n", block); return block; } 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; // 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; }