📄 sm.c
字号:
_media_data(assign_zone)=0;
g_addr_zone=0;
if ( k_success != map_build_sector_map())
return (k_error );
// sm_dump_log_blk(0) ;
trace0(0, sm, 0, "media identified") ;
// hmmmm... this may be redundant... done in identify-media...
_lun_data(media) &= ~kbm_lun_media_unknown ;
return (k_success);
}
//+-----------------------------------------------------------------------------
// Name:
// dfa_sm_read
//
// Declaration:
// void dfa_sm_read(void) reentrant
//
// Purpose:
// Read data from sm media
//
// Arguments:
// None.
// Uses _lun_data and g_bot_cbw to get its parameters.
//
// Return:
// No return value.
// However, on exit the DFA's argument pointer is written with a t_csw_status indicating:
// k_command_passed - command completed.
// k_command_failed - an error occurred.
//
// Notes:
// This is the start STATE of the dfa_ata_read DFA.
// It overrides dfa_lun_read.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
t_result sm_read_begin_xfer() reentrant
{
trace4(0, sm, 10, "sm_read_begin_xfer() - start:0x%04X%04X count:0x%04X%04X" , _hw(_fmc_get_start_lb_32()), _lw(_fmc_get_start_lb_32()), _hw(_fmc_get_lb_count_32()), _lw(_fmc_get_lb_count_32()));
_lun_data(sensep) = &sense_read_error;
if (k_success != map_lba2addr_rd( _fmc_get_start_lb_32() ) )
{
_lun_data(sensep)=&sense_illegal_address ;
trace0(0, sm, 0, "error in lba2addr") ;
return (k_error );
}
if (!g_addr_page)
{
_lun_data(max_lb_per_split) = _min( _media_data(pages_per_block), _fmc_get_lb_count_32());
trace5(0, sm, 10, "-----read begin xfer - zone:%02d phy:0x%04X log:0x%04X page:%02d count:%02d - first in block", g_addr_zone, g_addr_rd_phy_blk, g_addr_log_blk, g_addr_page, _lun_data(max_lb_per_split) );
}
else
{
_lun_data(max_lb_per_split) = _min( _media_data(pages_per_block) - g_addr_page, _fmc_get_lb_count_32());
trace5(0, sm, 10, "-----read begin xfer - zone:%02d phy:0x%04X log:0x%04X page:%02d count:%02d", g_addr_zone, g_addr_rd_phy_blk, g_addr_log_blk, g_addr_page, _lun_data(max_lb_per_split));
}
_lun_data(max_lb_per_burst) = _lun_data(max_lb_per_split) ;
return (k_success );
}
//+-----------------------------------------------------------------------------
// Name:
// sm_read_end_xfer
//
// Declaration:
// t_result sm_read_end_xfer(void);
//
// Purpose:
// Issue the read command to the smart media device.
//
// Arguments:
// None.
//
// Return:
// A t_result indicating:
// k_success - command completed.
//
// Notes:
// This is a FUNCTION, not a DFA.
// Do not yeild, or run a DFA, from within this callback.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
t_result sm_read_end_xfer(void) reentrant
{
trace0(0, sm, 1, "sm_read_end_xfer()") ;
_sm_hw_set_rd_standby() ;
if (k_success != _fmc_get_result())
return (k_error);
_lun_data(sensep) = &sense_none;
return (k_success );
}
//+-----------------------------------------------------------------------------
// Name:
// sm_read_begin_next_split
//
// Declaration:
// t_result sm_read_begin_next_split(void);
//
// Purpose:
// Issue the read command to subsequent splits after the first.
//
// Arguments:
// None.
//
// Return:
// A t_result indicating:
// k_success - command completed.
//
// Notes:
// This is a FUNCTION, not a DFA.
// Do not yeild, or run a DFA, from within this callback.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
t_result sm_read_begin_split(void) reentrant
{
trace0(0, sm, 1, "sm_read_begin_split()") ;
if (k_success != map_lba2addr_rd( _fmc_get_start_lb_32() ) )
{
_lun_data(sensep)=&sense_illegal_address ;
return (k_error );
}
if (map_log_blk_has_bad_data())
{
if (sm_check_data_status(g_addr_page, (uint8) _fmc_get_lb_count_32()))
{
trace0(0, sm, 0, "read error detected in lba range") ;
nand_cmd_reset_device();
return (k_error);
}
nand_cmd_reset_device();
trace0(0, sm, 0, "read in log blk that has bad data is OK");
}
trace4(0, sm, 0, "beginning split - zone:%d phy:%d log:%d page:%d", g_addr_zone, g_addr_rd_phy_blk, g_addr_log_blk, g_addr_page) ;
// convert virtual zone/block/sector into page/offset address
nand_rd_va2pa() ;
_sm_rd_cmd_begin(k_sm_read) ;
_media_set_read_addr() ;
if (k_success != sm_wait_rdy_with_timeout(k_sm_busy_read_timeout))
{
trace0(0, sm, 0, "ssfdc_readsect timeout on busy") ;
nand_cmd_reset_device();
return (k_error );
}
// must set these after the wait rdy otherwise, the rdy low->high will force the fmc-high and mask the interrupt
// clear ecc bits
_mcu_register_wr(x_smc_stat, (kbm_smc_stat_ecc_err_d_a|kbm_smc_stat_ecc_err_d_b|kbm_smc_stat_ecc_err_c_a|kbm_smc_stat_ecc_err_c_b));
// unmask the ecc err bits
_mcu_register_clr_bits(x_smc_stat_msk, (kbm_smc_stat_ecc_err_d_a|kbm_smc_stat_ecc_err_d_b|kbm_smc_stat_ecc_err_c_a|kbm_smc_stat_ecc_err_c_b));
// mask in fmc irqs
_mcu_register_clr_bits(x_imr0, kbm_isr0_fmc_irq);
// enable blk_xfer_ecc
_mcu_register_set_bits(sm_mode_ctl, kbm_sm_mode_ecc_blk_xfer_en) ;
trace0(0, sm, 0, "ecc on") ;
// enable ecc error detection
#if 0
/*
mcu_begin_critical_section();
trace1(0, sm, 0, " smc_stat: %02x", x_smc_stat) ;
trace1(0, sm, 0, "smc_stat_msk: %02x", x_smc_stat_msk) ;
trace1(0, sm, 0, " sm_mode_ctl: %02x", sm_mode_ctl) ;
trace1(0, sm, 0, " isr0: %02x", x_isr0);
trace1(0, sm, 0, " imr0: %02x", x_imr0);
mcu_end_critical_section();
*/
#endif
return (k_success);
}
//+-----------------------------------------------------------------------------
// Name:
// sm_read_end_split
//
// Declaration:
// t_result sm_read_end_split(void);
//
// Purpose:
// nothing to do at the beginning of a split
//
// Arguments:
// None.
//
// Return:
// A t_result indicating:
// k_success - command completed.
//
// Notes:
// This is a FUNCTION, not a DFA.
// Do not yeild, or run a DFA, from within this callback.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
t_result sm_read_end_first_split(void) reentrant
{
trace0(0, sm, 0, "sm_read_end_first_split()") ;
// go into overdrive
trace2(0, sm, 0, "adjusting split/burst size. before: max_lb_per_split:%d max_lb_per_burst: %d", _lun_data(max_lb_per_split), _lun_data(max_lb_per_burst)) ;
_lun_data(max_lb_per_split) = _min(_media_data(pages_per_block), g_n_lb_this_xfer.u32);
_lun_data(max_lb_per_burst) = _lun_data(max_lb_per_split) ;
trace2(0, sm, 0, "adjusting split/burst size. after: max_lb_per_split:%d max_lb_per_burst: %d", _lun_data(max_lb_per_split), _lun_data(max_lb_per_burst)) ;
// no need to callback here any more
_fmc_set_callback(sm_read_begin_xfer, sm_read_end_xfer,
sm_read_begin_split, sm_read_end_split,
fmc_dflt_callback, fmc_dflt_callback, sm_read_end_burst);
return (sm_read_end_split() );
}
//+-----------------------------------------------------------------------------
// Name:
// sm_read_end_split
//
// Declaration:
// t_result sm_read_end_split(void);
//
// Purpose:
// nothing to do at the beginning of a split
//
// Arguments:
// None.
//
// Return:
// A t_result indicating:
// k_success - command completed.
//
// Notes:
// This is a FUNCTION, not a DFA.
// Do not yeild, or run a DFA, from within this callback.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
t_result sm_read_end_split(void) reentrant
{
trace0(0, sm, 0, "sm_read_end_split()") ;
// sm_mode_ctl &= ~kbm_sm_mode_ecc_blk_xfer_en;
// TRACE0(247, sm, 0, "ecc_blk_xfer_en off") ;
_sm_hw_set_rd_standby() ;
return (k_success );
}
//+-----------------------------------------------------------------------------
// Name:
// sm_correct_sram_bit
//
// Declaration:
// t_result sm_correct_sram_bit(void);
//
// Purpose:
// TBD
//
// Arguments:
// None.
//
// Return:
// A t_result indicating:
// k_success - command completed.
//
// Notes:
// This is a FUNCTION, not a DFA.
// Do not yeild, or run a DFA, from within this callback.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void sm_correct_sram_bit(uint8 buffer, uint16 offset, uint8 ix_bit) reentrant
{
t_uw16 addr ;
uint8 err_byte;
trace3(0, sm, 0, "sm_correct_sram_bit(): buffer:%c, offset.bit:%d.%d", ((buffer==4)?'a':'b'), offset, ix_bit) ;
addr.u8.hi = k_pkt_addrhi[buffer] ;
addr.u8.lo = k_pkt_addrlo[buffer] ;
addr.u16 += offset ;
trace1(0, sm, 0, "sram byte addr: %04x", addr.u16) ;
_mcu_register_wr(x_sram_addr_lo, addr.u8.lo);
_mcu_register_wr(x_sram_addr_hi, addr.u8.hi);
_hdw_clk_domain_bug_workaround();
err_byte = _mcu_register_rd(x_sram_data) ;
err_byte ^= (1 << ix_bit) ;
_mcu_register_wr(x_sram_addr_lo, addr.u8.lo);
_mcu_register_wr(x_sram_addr_hi, addr.u8.hi);
_hdw_clk_domain_bug_workaround();
_mcu_register_wr(x_sram_data, err_byte) ;
}
//+-----------------------------------------------------------------------------
// Name:
// sm_read_end_burst
//
// Declaration:
// t_result sm_read_end_burst(void);
//
// Purpose:
// TBD
//
// Arguments:
// None.
//
// Return:
// A t_result indicating:
// k_success - command completed.
//
// Notes:
// This is a FUNCTION, not a DFA.
// Do not yeild, or run a DFA, from within this callback.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
t_result sm_read_end_burst(void) reentrant
{
t_result result ;
uint8 buffer ;
uint8 err_byte;
// uint8 isr ;
trace0(0, sm, 0, "sm_read_end_burst()") ;
result = k_success ;
buffer = 0 ;
// check blk_err bit to see if there was a correctable error.
err_byte = _mcu_register_rd(x_smc_stat) ;
trace1(0, sm, 0, "smc_stat:%02x", (_mcu_register_rd(x_smc_stat))) ;
if (err_byte&(kbm_smc_stat_ecc_err_d_a|kbm_smc_stat_ecc_err_d_b))
{
trace0(0, sm, 0, "smc_stat_ecc_err_d_a/b -> uncorrectable ecc error (2+bits)") ;
// sm_media_set_phyblock_failed();//DDD
nand_cmd_reset_device();
return (k_error );
}
if (err_byte& (kbm_smc_stat_ecc_err_c_a|kbm_smc_stat_ecc_err_c_b))
{
trace0(0, sm, 0, "single-bit ecc error detected!") ;
if (!sie_is_high_speed())
{
trace0(0, sm, 0, "cannot correct single-bit errors at full speed. reporting read error");
nand_cmd_reset_device();
return (k_error);
}
// this needs to be checked before turning auto-xfer off as per e-mail from Ben
buffer = (_mcu_register_rd(x_ep2_ctl)&kbm_ep2_ctl_ramwr_tog)?5:4;
trace1(0, sm, 0, "ramwr_toggle reports error in buffer %c", (buffer==4?'a':'b')) ;
// stop xfer and correct the error
_mcu_register_clr_bits(x_fmc_ctl, (kbm_fmc_ctl_auto_trans|kbm_fmc_ctl_auto_tog));
trace0(0, sm, 0, "auto transfer OFF") ;
if (x_smc_stat&kbm_smc_stat_ecc_err_c_a)
{
trace2(0, sm, 0, "blk xfer interrupted -> correctable 1-bit error addr:%d.%d", ecc_a_add_h, (ecc_a_add_l&0x07)) ;
sm_correct_sram_bit(buffer, ecc_a_add_h, (ecc_a_add_l&0x07));
_mcu_register_wr(x_smc_stat,kbm_smc_stat_ecc_err_c_a);
}
if (x_smc_stat&kbm_smc_stat_ecc_err_c_b)
{
trace2(0, sm, 0, "blk xfer interrupted -> correctable 1-bit error addr:%d.%d", (((uint16)ecc_b_add_h)+0x100), (ecc_b_add_l&0x07)) ;
sm_correct_sram_bit(buffer, (ecc_b_add_h+0x100), (ecc_b_add_l&0x07)) ;
_mcu_register_wr(x_smc_stat,kbm_smc_stat_ecc_err_c_b);
}
// toggle the buffer to be tx'd
if (buffer == 4)
{
_mcu_register_wr(x_ramrdbc_a1, 0x02) ;
_mcu_register_wr(x_ramrdbc_a2, 0x00) ;
_mcu_register_wr(x_ep2_ctl, kbm_ep2_ctl_rdtog_valid |(_mcu_register_rd(x_ep2_ctl) & ~kbm_ep2_ctl_ramrd_tog));
_hdw_clk_domain_bug_workaround();
while ( !(x_isr0&kbm_isr0_ramrd_a))
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -