📄 sm_media.c
字号:
/*============================================================================
____________________________________________________________________________
______________________________________________
SSSS M M CCCC Standard Microsystems Corporation
S MM MM SSSS C Austin Design Center
SSS M M M S C 11000 N. Mopac Expressway
S M M SSS C Stonelake Bldg. 6, Suite 500
SSSS M M S CCCC Austin, Texas 78759
SSSS ______________________________________________
____________________________________________________________________________
Copyright(C) 1999, Standard Microsystems Corporation
All Rights Reserved.
This program code listing is proprietary to SMSC and may not be copied,
distributed, or used without a license to do so. Such license may have
Limited or Restricted Rights. Please refer to the license for further
clarification.
____________________________________________________________________________
Notice: The program contained in this listing is a proprietary trade
secret of SMSC, Hauppauge, New York, and is copyrighted
under the United States Copyright Act of 1976 as an unpublished work,
pursuant to Section 104 and Section 408 of Title XVII of the United
States code. Unauthorized copying, adaption, distribution, use, or
display is prohibited by this law.
____________________________________________________________________________
Use, duplication, or disclosure by the Government is subject to
restrictions as set forth in subparagraph(c)(1)(ii) of the Rights
in Technical Data and Computer Software clause at DFARS 52.227-7013.
Contractor/Manufacturer is Standard Microsystems Corporation,
80 Arkay Drive, Hauppauge, New York, 1178-8847.
____________________________________________________________________________
____________________________________________________________________________
sm_media.c - implements smart media-specific routines used by the mapper
to abstract sector mapping from lun processing
____________________________________________________________________________
comments tbd
____________________________________________________________________________
Revision History
Date Who Comment
________ ___ _____________________________________________________________
03/11/02 cds initial version - moved from former media.c location
04/18/02 cds expanded the macros which issued the command to read extra data
to debug why sometimes certain phy_blks would report blank extra data
and other times that it would not. Does not affect functionality.
04/19/02 cds derived sm_media_resolve_conflict() which resolves a log2phy binding
conflict for the mapper.
05/16/02 cds updated the card_repair function and surrounded all card repair
tables with #if k_sm_repair_card guards so that repair-specific
code is only included with the repair build, not a real, functional build
05/30/02 cds added sm_media_copy_sector() override which reads/writes to the sram
using the fmdu instead of using pio to move the data. this
improves write performance (approx 3x) by optimizing copy_head/copy_tail
when overwritting buffers
06/27/02 cds added smart-media specific overrides for setting read/write/erase
addresses when accessing the removable-media type flash cards.
07/09/02 cds renamed WorkBuf to g_sector_buffer
07/29/02 cds protected software ecc calls to be included only if a sm-lun is
in the build.
08/09/02 cds - used attribute flag to determine whether to force Smart Media
compatible rw cycle timing for a data xfer.
- separated setting the device address from code that calculates
a the physical address from the mapper's virtual address.
- converted physical address variable into 3 separate xdata bytes
for quick-access when incrementing & writing to the device.
08/20/02 cds - fixed a potential bug in sm_media_write_extra_data, which
checked the wrong value of the media_sts_sm_256_page bit, preventing
writes to 512 page extra data.
- added trace points to places where errors could occur
08/27/02 cds updated set_phyblock_failed to write a failed block status in the
extra data of every page in the block
09/04/02 cds - address name & usage change-over
g_addr_sector => g_addr_page,
g_addr_page => g_addr_segment,
_media_data(sectors_per_block) => _media_data(pages_per_block)
_media_data(cis_phy_block) => _media_data(boot_block)
_media_data(cis_sector) => _media_data(boot_sector)
(new item) => _media_data(segments_per_page)
09/05/02 cds set g_addr_page to 0 before calculating erase address
10/05/02 cds fixed a glitch in sm_set_write_address which failed to drop the
address latch enable bit after setting the address for smart-media cards.
10/14/02 cds - added ecc correction to sm/nand copy-sector() function
10/16/02 cds removed protection of boot block in sm_media_write_sector(), so
nand_boot_write_flush can call it.
10/17/02 cds - project-wide lun data & vtbl paging to reduce code space.
- removed g_active_media from _lun_data, _lun_() virtual functions
- added _lun_data_rd() and _lun_data_wr() macros to bypass lun paging
- added lun_set_active(log_lun) function to switch luns
10/23/02 cds - converted copy-sector to perform read-retries on 2-bit errors. on second failure,
block the destination data-status is marked "bad", new ecc data is generated, and
copy completes with a media_copy_error_src
- converted rd/wr_va2pa(...) funcs to use 32-bit math to fix multi-zoned 2k page chip 16-bit overflow error.
10/29/02 cds - updated copy_sector to copy data-status field if read phy_block has marked that it has a bad data page in it.
- overrode media_block_has_bad_data() to check if the data status field shows an error on any pages in a phy block
10/30/02 cds - moved nand address and card select into sm.c
11/02/02 cds - fixed read-retry in sm_media_copy_sector function so that on a read-retry, it flips the ep2 direction to prevent
user lba from being received from the host and lost in the copy. This should fix the 2-bit ecc compliance issues.
- updated resolve conflict for new implementation in the mapper which ALWAYS calls the media resolve conflict when two
physical blocks have the same logical binding. By default, we call the map_resolve_conflict first as was behavior in
previous versions.
11/03/02 cds - implemented sm_media_is_phyblock_reserved() to single out boot blocks.
11/13/02 ds added a prototype for check_status
==============================================================================*/
#define __sm_media_dot_c__
#include "project.h"
// provide vtable definition '_vtbl_cf'
code _vtbl_defn(sm_media) ;
extern uint8 bit_count16(uint16 val) reentrant ;
extern void sm_dbg_dump_redt_data() reentrant;
extern t_result ecc_check_rd_error() reentrant ;
extern t_result ecc_check_and_correct(unsigned char *buf) reentrant ;
extern void sm_pio_rd_buf(uint8 *databuf) reentrant ;
extern void sm_pio_wr_buf(uint8 *databuf) reentrant ;
extern uint8 bit_count8(uint8 val) reentrant ;
extern t_result sm_redt_is_data_valid( void ) reentrant ;
extern t_result sm_check_status(void) reentrant ;
extern t_result sm_read_sect(uint8 *buf) reentrant ;
extern t_result sm_validate_cis(uint8 *buf) reentrant ;
extern t_result sm_wait_rdy_with_timeout(uint16 ticks) reentrant;
void fmc_dbg_dump_sector(uint8* sector) reentrant;
extern xdata uint8 x_sm_redt_data[] ;
extern xdata uint8 g_sector_buffer[] ;
//------------------------------------------------------------------------------
// NAND Flash configuration.
xdata uint8 g_nand_num_chips ;
xdata uint8 g_nand_zones_per_chip ;
//+-----------------------------------------------------------------------------
// Name:
// sm_media_erase_block()
//
// Declaration:
// t_result sm_media_erase_block(void) reentrant
//
// Purpose:
//
// Arguments:
//
// Return:
//
// Notes:
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
t_result sm_media_erase_block(void) reentrant
{
uint8 save_page ;
trace4(0, sm_media, 0, "sm_media_erase_block() - zone:%d wr_phy:%d log:%d page:%d", g_addr_zone, g_addr_wr_phy_blk, g_addr_log_blk, g_addr_page) ;
if( (g_addr_wr_phy_blk == k_block_free) )
return k_media_err_illegal_lba ;
save_page = g_addr_page ;
g_addr_page=0;
nand_wr_va2pa() ;
g_addr_page=save_page ;
_sm_wr_cmd_begin(k_sm_erase1);
_media_set_erase_addr() ;
_sm_set_wr_cmd(k_sm_erase2);
if (sm_wait_rdy_with_timeout(k_sm_busy_erase_timeout))
{
trace0(0, sm_media, 0, "block erase failed.") ;
nand_cmd_reset_device();
return k_error ;
}
_sm_hw_set_wr_standby();
_sm_hw_set_rd_standby();
return k_success ;
}
//------------------------------------------------------------------------------
//+-----------------------------------------------------------------------------
// Name:
// sm_media_read_sector()
//
// Declaration:
// t_result sm_media_read_sector(void) reentrant
//
// Purpose:
//
// Arguments:
//
// Return:
//
// Notes:
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
t_result sm_media_read_sector(void) reentrant
{
uint8*buf ;
uint8 i ;
trace4(0, sm_media, 0, "+sm_media_read_sector() - zone:%d RD_PHY:%d log:%d page:%d", g_addr_zone, g_addr_rd_phy_blk, g_addr_log_blk, g_addr_page) ;
buf = _media_data(sector_buffer) ;
nand_rd_va2pa() ;
if(!(_mcu_register_rd(x_media_sts) & kbm_media_sts_sm_256_page) )
{
trace0(0, sm_media, 0, "reading sector mode: 512+16") ;
_sm_rd_cmd_begin(k_sm_read) ;
_media_set_read_addr() ;
trace0(0, sm_media, 0, "waiting for data to be read") ;
if (k_success != sm_wait_rdy_with_timeout(k_sm_busy_read_timeout))
{
trace0(0, sm_media, 0, "ssfdc_readsect timeout on busy") ;
nand_cmd_reset_device();
return k_error ;
}
// read sector
sm_pio_rd_buf(buf) ;
// read redundant data
for (i=0x00;i<k_sm_redt_buffer_sz;i++)
x_sm_redt_data[i] =_sm_data_rd();
if (k_success != sm_wait_rdy_with_timeout(k_sm_busy_read_timeout))
{
trace0(0, sm_media, 0, "ssfdc_readsect timed out busy") ;
nand_cmd_reset_device();
return k_error ;
}
}
else
{
// read even page
trace0(0, sm_media, 0, "Read Mode: 256+8") ;
_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_media, 0, "ssfdc_readsect timeout on busy") ;
nand_cmd_reset_device();
return k_error ;
}
// read sector
sm_pio_rd_buf(buf) ;
// read extra data
for (i=0x00;i<0x08;i++)
x_sm_redt_data[i] =_sm_data_rd();
if (k_success != sm_wait_rdy_with_timeout(k_sm_busy_read_timeout))
{
trace0(0, sm_media, 0, "ssfdc_readsect timed out busy") ;
nand_cmd_reset_device();
return k_error ;
}
// read the odd page
nand_incr_addr() ;
_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_media, 0, "ReadSect: Timed Out") ;
nand_cmd_reset_device();
return k_error ;
}
// move the data
sm_pio_rd_buf(buf+0x0100);
// move redundant data
for (i=0x08;i<k_sm_redt_buffer_sz;i++)
x_sm_redt_data[i] =_sm_data_rd();
if (k_success != sm_wait_rdy_with_timeout(k_sm_busy_read_timeout))
{
nand_cmd_reset_device();
return k_error ;
}
}
_sm_hw_set_rd_standby();
sm_synch_hw_buff_to_redt_buf() ;
return k_success ;
}
//+-----------------------------------------------------------------------------
// Name:
// sm_media_validate_sector()
//
// Declaration:
// t_result sm_media_validate_sector(void) reentrant
//
// Purpose:
// TBD
//
// Arguments:
// TBD
//
// Return:
// TBD
//
// Notes:
// TBD
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
t_result sm_media_validate_sector(uint8* buf) reentrant ;
t_result sm_media_validate_sector(uint8* buf) reentrant
{
#if (k_log_lun_sm < k_max_log_lun)
// if we're doing sofware ecc, calculate it now
mcu_begin_critical_section() ;
ecc_sw_calculate(buf);
x_eccbuf[1]=ecc_lp_hi;
x_eccbuf[0]=ecc_lp_lo;
x_eccbuf[2]=ecc_cp;
ecc_sw_calculate(buf+0x0100);
x_eccbuf[4]=ecc_lp_hi;
x_eccbuf[3]=ecc_lp_lo;
x_eccbuf[5]=ecc_cp;
mcu_end_critical_section() ;
// check buffer for ecc error detection
if (k_success != ecc_check_rd_error())
{
// try to correct the buffer
if (k_success != ecc_check_and_correct(buf))
return k_error ;
}
return k_success ;
#else
trace0(0, sm_media, 0, "sm_media_validate_sector(): warning - software ecc disabled") ;
buf=buf ; // quiet the compiler
return k_error ;
#endif
}
//+-----------------------------------------------------------------------------
// Name:
// sm_media_write_sector()
//
// Declaration:
// t_result sm_media_write_sector(uint8 *buf) reentrant
//
// Purpose:
//
// Arguments:
//
// Return:
//
// Notes:
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
t_result sm_media_write_sector() reentrant
{
uint8 i ;
uint8* buf ;
trace4(0, sm_media, 0, "+sm_media_write_sector() zone:%d WR_PHY:%d log:%d page:%d", g_addr_zone, g_addr_wr_phy_blk, g_addr_log_blk, g_addr_page) ;
if( (g_addr_wr_phy_blk == k_block_free) )
return k_media_err_illegal_lba ;
buf = _media_data(sector_buffer) ;
nand_wr_va2pa() ;
// issue start-of-write command
_sm_wr_cmd_begin(k_sm_write_data);
// set the address
_media_set_write_addr() ;
// send the even page
sm_pio_wr_buf(buf);
// send even page extra data
for (i=0x00;i<((_mcu_register_rd(x_media_sts)&kbm_media_sts_sm_256_page)?0x08:0x10);i++)
_sm_data_wr(x_sm_redt_data[i]);
// issue the end-of-write command
#if 1
trace0(0, sm, 0, "cmd: write") ;
_sm_set_wr_cmd(k_sm_write);
#else
if(g_addr_page==(_media_data(pages_per_block)-1))
{
trace0(0, sm, 0, "cmd: write") ;
_sm_set_wr_cmd(k_sm_write);
}
else
{
trace0(0, sm, 0, "cmd: write cache");
_sm_set_wr_cmd(k_nand_cmd_write_cache);
}
#endif
if (sm_wait_rdy_with_timeout(k_sm_busy_programming_timeout))
{
trace0(0, sm_media, 0, "error waiting for sm to program") ;
nand_cmd_reset_device();
return k_error ;
}
// for odd pages (on devices that use 'em) do it again.
if (( _mcu_register_rd(x_media_sts)&kbm_media_sts_sm_256_page))
{
_sm_wr_cmd_begin(k_sm_write_data);
_media_set_write_addr() ;
sm_pio_wr_buf(buf+0x0100);
for (i=0x08;i<k_sm_redt_buffer_sz;i++)
_sm_data_wr(x_sm_redt_data[i]);
_sm_set_wr_cmd(k_sm_write);
if (sm_wait_rdy_with_timeout(k_sm_busy_programming_timeout))
{
nand_cmd_reset_device();
return k_error ;
}
}
_sm_hw_set_wr_standby();
_sm_hw_set_rd_standby();
return k_success;
}
//+-----------------------------------------------------------------------------
// Name:
// sm_media_copy_sector()
//
// Declaration:
// t_result sm_media_copy_sector() reentrant
//
// Purpose:
//
// Arguments:
//
// Return:
//
// Notes:
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
t_result sm_media_copy_sector() reentrant
{
uint8 err_byte;
t_bool retry;
uint8 data_status;
t_result result;
trace4(0, sm_media, 0, "+sm_media_copy_sector() zone:%d SRC_BLK:%d DEST_BLK:%d page:%d", g_addr_zone, g_addr_rd_phy_blk, g_addr_wr_phy_blk, g_addr_page) ;
if( (g_addr_wr_phy_blk == k_block_free) )
{
trace0(0, sm_media, 0, " error. invalid wr_phy_block: 0xffff") ;
return k_media_err_illegal_lba ;
}
nand_rd_va2pa() ;
// read retries and data status
retry=k_false;
// data status is good
data_status=0xff;
result=k_success;
do
{
// TRACE0(164, sm_media, 0, "reading sector mode: 512+16") ;
_sm_rd_cmd_begin(k_sm_read) ;
_media_set_read_addr() ;
_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));
_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));
_mcu_register_set_bits(sm_mode_ctl, kbm_sm_mode_ecc_blk_xfer_en) ;
x_isr0 = kbm_isr0_fmc_irq ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -