www.pudn.com > SMSC USB2.0.zip > 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 data bad, 0xff=>no errors or 1-bit error corrected
XBYTE[0x3664]=x_sm_redt_data[k_ix_redt_data_status]=data_status;
trace1(0, sm, 0, "copy: page data status:%02x", data_status);
// reverse data flow direction
_mcu_register_clr_bits( x_ep2_ctl, kbm_ep2_ctl_dir) ;
x_smc_stat = kbm_smc_stat_rdy ;
_sm_set_wr_cmd(k_sm_write_data);
_media_set_write_addr() ;
sm_mode_ctl |= kbm_sm_mode_ecc_blk_xfer_en;
_sm_hw_ecc_wr_start() ;
trace0(0, sm, 0, "ecc_en on") ;
// set fmc ctl reg - 1 sector
_mcu_register_wr(x_fmc_cnt3, 0x00) ;
_mcu_register_wr(x_fmc_cnt2, 0x00) ;
_mcu_register_wr(x_fmc_cnt1, 0x02) ;
_mcu_register_wr(x_fmc_cnt0, 0x00) ;
// enable blk xfer
_mcu_register_wr(x_fmc_ctl, (kbm_fmc_ctl_512_byte_pkt|kbm_fmc_ctl_blk_xfer_en)) ;
// point the rd toggle & count to buffer a (rd toggles point the dest (SIE or DBUF) where to read)
_mcu_register_wr( x_ramrdbc_a1, 0x02) ;
_mcu_register_wr( x_ramrdbc_a2, 0x00) ;
// aim fmc at buffer a
// _mcu_register_set_bits( x_ep2_ctl, kbm_ep2_ctl_rdtog_valid) ;
_mcu_register_wr(x_ep2_ctl, kbm_ep2_ctl_rdtog_valid |(_mcu_register_rd(x_ep2_ctl) & ~kbm_ep2_ctl_ramrd_tog));
// bad bad bad form.... do a while loop
while(_mcu_register_rd( x_fmc_ctl)&kbm_fmc_ctl_blk_xfer_en)
{
if(thread_got_sync(kbm_sync_timer) )
{
trace0(0, sm_media, 0, "timeout trying to write sector. aborting") ;
return k_media_copy_error_dst ;
}
}
_sm_hw_ecc_wr_stop() ;
sm_mode_ctl &= ~kbm_sm_mode_ecc_blk_xfer_en;
trace0(0, sm, 0, "ecc_en off") ;
// send the write command to program the data to the card
trace0(0, sm, 0, "cmd: write") ;
_sm_set_wr_cmd(k_sm_write);
if (k_success != sm_wait_rdy_with_timeout(k_sm_busy_programming_timeout))
{
nand_cmd_reset_device();
trace0(0, sm, 0, "error writing sector for copy") ;
return k_media_copy_error_dst ;
}
if (k_success != nand_cmd_check_status())
{
trace0(0, sm, 0, "sm_write_end_split - write fault") ;
return k_media_copy_error_dst ;
}
_sm_hw_set_wr_standby();
_sm_hw_set_rd_standby();
return result;
}
//------------------------------------------------------------------------------
//+-----------------------------------------------------------------------------
// Name:
// sm_media_phy2log()
//
// Declaration:
// t_result sm_get_lba(void) reentrant
//
// Purpose:
// TBD
//
// Arguments:
// TBD
//
// Return:
// TBD
//
// Notes:
// TBD
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
t_result sm_media_phy2log(void) reentrant
{
uint16 addr1;
uint16 addr2;
trace0(0, sm_media, 0, "sm_media_phy2log()") ;
addr1=_uint16( x_sm_redt_data[k_ix_redt_lba1_hi],x_sm_redt_data[k_ix_redt_lba1_lo]) ;
addr2=_uint16( x_sm_redt_data[k_ix_redt_lba2_hi],x_sm_redt_data[k_ix_redt_lba2_lo]) ;
if (addr1==addr2)
{
// addresses are equal
if ((addr1 &0xF000)==0x1000)
{
g_addr_log_blk=(addr1 &0x0FFF)/2;
trace2(0, sm_media, 0, "RD_PHY:%d => log_blk:%d", g_addr_rd_phy_blk, g_addr_log_blk) ;
return k_success;
}
}
if (bit_count16(addr1^addr2)!=0x01)
{
// more than 1 bit error
trace2(0, sm_media, 0, "inconsistant log_blk binding: addr1:%04x addr2:%04x", addr1, addr2) ;
return k_error ;
}
// only 1 bit error
if ((addr1 &0xF000)==0x1000)
{
if (0 == (bit_count16(addr1) &0x01))
{
g_addr_log_blk=(addr1 &0x0FFF)/2;
trace2(0, sm_media, 0, "RD_PHY:%d => log_blk:%d", g_addr_rd_phy_blk, g_addr_log_blk) ;
return k_success;
}
}
if ((addr2 &0xF000)==0x1000)
{
if (0 == (bit_count16(addr2) &0x01))
{
g_addr_log_blk=(addr2 &0x0FFF)/2;
trace2(0, sm_media, 0, "phyblock:%d => log_blk:%d", g_addr_rd_phy_blk, g_addr_log_blk) ;
return k_success;
}
}
trace2(0, sm_media, 0, "inconsistant log_blk binding: addr1:%04x addr2:%04x", addr1, addr2) ;
return k_error ;
}
//+-----------------------------------------------------------------------------
// Name:
// sm_media_bind_log2phy()
//
// Declaration:
// t_result sm_media_bind_log2phy(void) reentrant
//
// Purpose:
// TBD
//
// Arguments:
// TBD
//
// Return:
// TBD
//
// Notes:
// TBD
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
t_result sm_media_bind_log2phy(void) reentrant
{
uint16 addr;
trace1(0, sm_media, 0, "+sm_media_bind_log2phy(log_blk:%d)", g_addr_log_blk) ;
x_sm_redt_data[k_ix_redt_block_status]=0xFF;
x_sm_redt_data[k_ix_redt_data_status] =0xFF;
addr=g_addr_log_blk*2+0x1000;
if ((bit_count16(addr)%2)) addr++;
x_sm_redt_data[k_ix_redt_lba1_hi]=x_sm_redt_data[k_ix_redt_lba2_hi]= _h(addr) ;
x_sm_redt_data[k_ix_redt_lba1_lo]=x_sm_redt_data[k_ix_redt_lba2_lo]= _l(addr) ;
// bind the smc buffer too... just to keep 'em all the same
sm_synch_hw_buff_to_redt_buf() ;
// note.. this binding is not set until the data is written! it's only in the
// redundant (extra) data section
return k_success ;
}
//+-----------------------------------------------------------------------------
// Name:
// sm_map_set_phyblock_failed()
//
// Declaration:
// t_result sm_map_set_phyblock_failed(void) reentrant
//
// Purpose:
//
// Arguments:
//
// Return:
//
// Notes:
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
t_result sm_media_set_phyblock_failed(void) reentrant
{
uint8 page;
uint8 i ;
page=g_addr_page ;
trace0(0, sm_media, 0, "sm_media_set_phyblock_failed()...") ;
// mark the block bad in the x_sm_redt_data data buffer
for (i=0; i factory-marked bad-block") ;
return k_false;
}
if (bit_count8(data_status)<5)
{
trace0(0, sm_media, 0, "data status:0x02X -> 4 bits +/- 1 bit error: data either marked bad, or set bad by factory") ;
return k_false;
}
return k_true;
}
//+-----------------------------------------------------------------------------
// Name:
// sm_media_read_extra_data()
//
// Declaration:
// TBD
//
// Purpose:
// TBD
//
// Arguments:
// TBD
//
// Return:
// TBD
//
// Notes:
// TBD
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
t_result sm_media_read_extra_data(void) reentrant
{
uint8 i ;
trace3(0, sm_media, 0, "sm_media_read_extra_data() - zone:%d RD_PHY:%d page:%d", g_addr_zone, g_addr_rd_phy_blk, g_addr_page) ;
nand_rd_va2pa() ;
_sm_rd_cmd_begin(k_sm_read_redt) ;
_sm_set_rd_cmd(k_sm_read_redt);
_media_set_read_addr() ;
if (k_success != sm_wait_rdy_with_timeout(k_sm_busy_read_timeout))
{
trace0(0, sm_media, 0, "**** sm_media_read_extra_data() - timed out trying to read extra data") ;
nand_cmd_reset_device() ;
return(k_error);
}
if( !(x_media_sts&kbm_media_sts_sm_256_page) )
{
trace0(0, sm, 0, "reading 512+16 media extra data") ;
// read redundant data (512+16 media) ----------------------
for (i=0x00;i