static void set_psn(UINT32 const lba, UINT32 const psn) //added by RED { //UINT32 src = (UINT32)g_psn_write + (sizeof(UINT32) * g_psn_write_temp); //UINT32 dst = SMT_ADDR + (lba * sizeof(UINT32)); //UINT32 size = sizeof(UINT32) * totals; //int i; //mem_copy(dst,src,size); UINT32 dst, bank, block, sector; UINT32 sectors_per_mblk = (SECTORS_PER_BANK + SMT_BANK_NUM - 1) / SMT_BANK_NUM; bank = lba / SECTORS_PER_BANK; block = ((lba % SECTORS_PER_BANK)) / (sectors_per_mblk); sector = ((lba % SECTORS_PER_BANK)) % (sectors_per_mblk); dst = smt_piece_map[bank * SMT_BANK_NUM + block]; if(dst == (UINT32)-1) { #if OPTION_FTL_TEST == 1 num_miss++; #endif load_smt_piece( bank * SMT_BANK_NUM + block); dst = smt_piece_map[bank * SMT_BANK_NUM + block]; while(_BSP_FSM(g_bank_to_wait) != BANK_IDLE); } dst = SMT_ADDR + (SMT_PIECE_BYTES * dst) + (sector * sizeof(UINT32)); smt_bit_map[bank][block / NUM_BANKS_MAX] |= ( 1 <<( block% NUM_BANKS_MAX) ); write_dram_32( (UINT32*)dst , psn ); }
static UINT32 get_psn(UINT32 const lba) //added by RED { //UINT32 src = SMT_ADDR + (lba * sizeof(UINT32)); //UINT32 dst = (UINT32)g_psn_read; //UINT32 size = sizeof(UINT32) * totals; //mem_copy(dst,src,size); UINT32 dst, bank, block, sector; UINT32 sectors_per_mblk = (SECTORS_PER_BANK + SMT_BANK_NUM - 1) / SMT_BANK_NUM; bank = lba / SECTORS_PER_BANK; block = (lba % SECTORS_PER_BANK) / (sectors_per_mblk); sector = (lba % SECTORS_PER_BANK) % (sectors_per_mblk); dst = smt_piece_map[bank * SMT_BANK_NUM + block]; if( dst == (UINT32)-1 ) { #if OPTION_FTL_TEST == 1 num_miss++; #endif load_smt_piece( bank * SMT_BANK_NUM + block); dst = smt_piece_map[bank * SMT_BANK_NUM + block]; while(_BSP_FSM(g_bank_to_wait) != BANK_IDLE); } dst = SMT_ADDR + (SMT_PIECE_BYTES * dst) + (sector * sizeof(UINT32)); return read_dram_32((UINT32*)dst); }
void flush_smt_piece(UINT32 idx) { UINT32 bank,row,block; UINT32 dest; bank = smt_dram_map[idx] / NUM_BANKS_MAX; block = smt_dram_map[idx] % NUM_BANKS_MAX; if((smt_bit_map[bank] & (1<<block)) != 0){ // smt piece data if( g_misc_meta[bank].smt_pieces[block] >= SMT_LIMIT - 1){ // erase nand_block_erase(bank,g_bad_list[bank][block]); } //update and flash g_misc_meta[bank].smt_pieces[block] = (g_misc_meta[bank].smt_pieces[block] + 1) % SMT_LIMIT; row = g_misc_meta[bank].smt_pieces[block] * SMT_INC_SIZE + ( PAGES_PER_VBLK * g_bad_list[bank][block]); // flash map data to nand SETREG(FCP_CMD, FC_COL_ROW_IN_PROG); SETREG(FCP_OPTION, FO_P | FO_E | FO_B_W_DRDY); SETREG(FCP_COL,0); SETREG(FCP_ROW_L(bank),row); SETREG(FCP_ROW_H(bank),row); dest = SMT_ADDR + (idx * SMT_PIECE_BYTES); SETREG(FCP_DMA_ADDR,dest); SETREG(FCP_DMA_CNT, SMT_PIECE_BYTES); while(_BSP_FSM(bank) != BANK_IDLE) { bank = bank; } flash_issue_cmd(bank,RETURN_WHEN_DONE); } smt_piece_map[smt_dram_map[idx]] = (UINT32)-1; }
void Main(void) { int count = 0; while (1) { if (eventq_get_count()) { count = 0; CMD_T cmd; eventq_get(&cmd); if (cmd.cmd_type == READ) { ftl_read(cmd.lba, cmd.sector_count); } else { if (cmd.cmd_type == WRITE) { if(cmd.lba == 0x3FFFFFFF) { ftl_trim(0, cmd.sector_count); } else { ftl_write(cmd.lba, cmd.sector_count); } } else { //uart_print_level_1("-\r\n"); } } } else { if (g_sata_context.slow_cmd.status == SLOW_CMD_STATUS_PENDING) { //uart_print_level_1("*\r\n"); void (*ata_function)(UINT32 lba, UINT32 sector_count); slow_cmd_t* slow_cmd = &g_sata_context.slow_cmd; slow_cmd->status = SLOW_CMD_STATUS_BUSY; ata_function = search_ata_function(slow_cmd->code); ata_function(slow_cmd->lba, slow_cmd->sector_count); slow_cmd->status = SLOW_CMD_STATUS_NONE; } else { count ++; if (count == 100000000) { //uart_print_level_1(".\r\n"); count = 0; //uart_print_level_1("Warning waiting too long in SATA main loop\r\n"); for (int i=0; i<NUM_BANKS; i++) { if (_BSP_FSM(REAL_BANK(i)) == BANK_TAKE) { uart_print_level_1("Bank "); uart_print_level_1_int(i); uart_print_level_1(" (real bank "); uart_print_level_1_int(REAL_BANK(i)); uart_print_level_1(") in state: "); uart_print_level_1_int((UINT8)_BSP_FSM(REAL_BANK(i))); uart_print_level_1("\r\n"); //uart_print_level_1("Try reset\r\n"); //flash_reset_one_bank(i); //break; } } } } } } }
/* g_smt_target, g_smt_victim */ void load_smt_piece(UINT32 idx){ UINT32 bank,row,block; UINT32 dest; UINT32 pblock; // physical block which have target mapping table bank = idx / SMT_BANK_NUM; block = idx % SMT_BANK_NUM; pblock = block / SMT_BLOCK; row = smt_pos[idx] * SMT_INC_SIZE + (PAGES_PER_VBLK * g_bad_list[bank][pblock]); if( g_smt_full == 1){ flush_smt_piece(g_smt_victim); g_smt_victim = (g_smt_victim +1 ) % SMT_DRAM; } SETREG(FCP_CMD, FC_COL_ROW_READ_OUT); SETREG(FCP_DMA_CNT,SMT_PIECE_BYTES); SETREG(FCP_COL, 0); dest = SMT_ADDR + (g_smt_target * SMT_PIECE_BYTES); SETREG(FCP_DMA_ADDR, dest); SETREG(FCP_OPTION, FO_P | FO_E ); SETREG(FCP_ROW_L(bank), row); SETREG(FCP_ROW_H(bank), row); // fully guarantee //flash_issue_cmd(bank, RETURN_WHEN_DONE); while(_BSP_FSM(g_bank_to_wait) != BANK_IDLE); flash_issue_cmd(bank, RETURN_ON_ISSUE); g_bank_to_wait = bank; smt_dram_map[g_smt_target] = idx; smt_piece_map[idx] = g_smt_target; smt_bit_map[bank][block/NUM_BANKS_MAX] &= ~( 1 <<(block % NUM_BANKS_MAX) ); /* init or not */ if(( g_misc_meta[bank].smt_init[block/NUM_BANKS_MAX] & ( 1 << (block % NUM_BANKS_MAX) ) ) == 0){ mem_set_dram( dest, 0x00, SMT_PIECE_BYTES); g_misc_meta[bank].smt_init[block/NUM_BANKS_MAX] |= (1 <<(block % NUM_BANKS_MAX)); } g_smt_target = (g_smt_target + 1) % SMT_DRAM; if( g_smt_target == 0 ){ g_smt_full = 1; } }
void ftl_write_sector(UINT32 const lba) { UINT32 new_bank, vsect_num, new_row; UINT32 new_psn; UINT32 temp; UINT32 dst,src; UINT32 index = lba % SECTORS_PER_PAGE; int i; //new_bank = lba % NUM_BANKS; // get bank number of sector new_bank = g_target_bank; temp = get_psn(lba); if( (temp & (UINT32)BIT31) != 0 ){ // If data, which located in same lba, is already in dram // copy sata host data to same merge buffer sector vsect_num = (temp ^ (UINT32)BIT31); dst = MERGE_BUFFER_ADDR + new_bank * BYTES_PER_PAGE + vsect_num * BYTES_PER_SECTOR; src = WR_BUF_PTR(g_ftl_write_buf_id) + index * BYTES_PER_SECTOR; mem_copy(dst,src, BYTES_PER_SECTOR); } else{ // copy sata host data to dram memory merge buffer page //vsect_num = g_misc_meta[new_bank].g_merge_buff_sect; vsect_num = g_target_sect; dst = MERGE_BUFFER_ADDR + new_bank * BYTES_PER_PAGE + vsect_num * BYTES_PER_SECTOR; src = WR_BUF_PTR(g_ftl_write_buf_id) + index * BYTES_PER_SECTOR; // Because Firmware does not know // about status of previous nand flash command, // wait until target bank is IDLE // ( target DRAM space is fully flashed ) while(_BSP_FSM(new_bank) != BANK_IDLE); mem_copy(dst, src, BYTES_PER_SECTOR); // set psn to -1 , it means that data is in dram set_psn(lba, ((UINT32)BIT31 | vsect_num )); // for change psn g_merge_buffer_lsn[vsect_num] = lba; vsect_num++; // If merge_buffer of bank is full , // than flush the merge buffer page to nand flash // and set a psn number of all sectors. if( vsect_num >= SECTORS_PER_PAGE ){ /* get free page */ new_row = get_free_page(new_bank); SETREG(FCP_CMD, FC_COL_ROW_IN_PROG); SETREG(FCP_OPTION, FO_P | FO_E | FO_B_W_DRDY); SETREG(FCP_DMA_ADDR, MERGE_BUFFER_ADDR + new_bank * BYTES_PER_PAGE); SETREG(FCP_DMA_CNT, BYTES_PER_PAGE); SETREG(FCP_COL,0); SETREG(FCP_ROW_L(new_bank),new_row); SETREG(FCP_ROW_H(new_bank),new_row); flash_issue_cmd(new_bank,RETURN_ON_ISSUE); /* initialize merge buffer page's sector point */ // g_misc_meta[new_bank].g_merge_buff_sect = 0; g_target_sect = 0; g_target_bank = (g_target_bank + 1 ) % NUM_BANKS; // allocate new psn //new_psn = new_row * SECTORS_PER_PAGE; new_psn = new_bank * SECTORS_PER_BANK + new_row * SECTORS_PER_PAGE; // vsn - > psn mapping for(i = 0 ;i < SECTORS_PER_PAGE; i++ ) { set_psn( g_merge_buffer_lsn[i], new_psn + i ); } } else { //g_misc_meta[new_bank].g_merge_buff_sect++; g_target_sect++; } } }