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