⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 map.c

📁 <B>SMSC USB2.0 Flash硬盘驱动源码</B>
💻 C
📖 第 1 页 / 共 4 页
字号:
/*============================================================================
  ____________________________________________________________________________
                                ______________________________________________
   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.
  ____________________________________________________________________________
  ____________________________________________________________________________

  map.c - implements common sector mapping algorithms

  ____________________________________________________________________________

  comments tbd
  ____________________________________________________________________________

  Revision History
  Date      Who  Comment
  ________  ___  _____________________________________________________________
  03/11/02  cds  initial version - moved from former media.c location
  04/18/02  cds  tweaked the conflict-resolution logic to comform to SMART MEDIA's
                 recovery.  The log2phy conflict-resolution code is soon to be
                 moved into the media so that memory stick and smart media
                 can handle 'em differently.  for now this code WILL LIKELY BREAK
                 MEMORY STICK, should a conflicting log2phy situation occur!
  04/19/02  cds  map_build_sector_map() now calls media specific routine to
                 resolve conflicting log2phy bindings.
  04/24/02  cds  updated map_lba2addr_rd & map_build_sector_map() to try to
                 eliminate some stack variables which were causing
                 stack overflows.  More may be necessary
  07/10/02  cds  added (but #if 0'd out) code that would return a blank block
                 address (but valid) instead of k_block_free.
  07/29/02  cds  - removed g_media_err_code references (old smil leftover)
                 - removed (uint8) cast of g_addr_sector calculation in build sector map
  08/06/02  tbh  enabled dormant code to reclaim inconsistent blocks.  this is
                 part of the solution for br308 (though it is not required for
                 that bug fix... so if it causes a problem it can be disabled here
                 in both locations and not affect he SanDisk issue as resolved in
                 ms.c and ms_media.c)
  08/20/02  cds  the above br308 fix did infact cause problems, but the fix was
                 introduced a new bug where when paging in a new zone (for any
                 mapped media), if there was no logical binding for the first 
                 block during a write split, the mapper would select the same
                 block for both the rd and wr phy block, thus erasing the block
                 immediately after writing valid data to it.  To fix this, 
                 the block selected for reading is given a temporary binding and
                 marked as used.
  08/27/02  cds  updated map_erase_rd_blk to reflect the accurate recovery 
                 processing for smart media.  the new code attempts retry the
                 erase command on failure.  If it fails a second time, the
                 block is marked "bad" by calls to the media functions, but
                 the erase reports success.  The non-erased block should no
                 longer be in the working set, even when the map is reconstructed.
  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)
  09/19/02  cds  - initial erase caching code.  added new functions:
                     map_erase_block()
                     map_erase_block_cache()
                     map_erase_cache_flush_one()
                     map_erase_cache_flush_all()     
                 - call to map_erase_rd_blk() calls the erase cache if enabled
                   for the media
  09/21/02  cds  - fixed bug that was double-incrementing the erase_cache_head_ptr                    
                   when adding blocks to the cache.
                 - write_caching implemented.  The caching appears to do what it's
                   supposed to, but the xfer halts w/o error or timeout when flushing
                   a write on a read command.  Have a feeling it's to do with 
                   sharing the fmdu...
  09/22/02  cds  - All tables and erase cache variables have been moved into the 
                   media_data(...) structure for per-instance erase caching.  
                 - Added support for one erase_cache map for each zone mapped into
                   the media_data() so that it gets updated whenever the zone maps
                   paged-in/paged-out.
                 - redefined a few of teh erase_cache functions to take advantage
                   of the existing code that does the 'usage' tracking for free blocks.
                   Instead of 'used' meaning 'written', used means 'cached'.
                 - cleaned up unused caching experiments
                 - #if'd out write-caching for code-space
  09/23/02  cds  - optimized mapper to not erase read-blocks that had no logical
                   binding.  (improves efficiency of large > 1/2-zone file streams)
  09/24/02  cds  - added k_erase_cnt which can be adjusted to tune how many blocks
                   are erased per call to flush single... this boosts the degraded
                   performance up to 711K/sec hs.
  10/01/02  cds  - fixed _xxx_map() functions to use reentrant stack
                 - updated erase cache code to reduce stack size by storing addresses in xdata
                   instead of on the stack (makes 'em non-reentrant tho)
  10/05/02  cds  - protected all erase cache code with #ifdef k_opt_erase_cache to reduce 210 code space
                 - defined k_opt_erase_cache to be defined for 211 and 242
  10/08/02  cds  - updated soft logical binding code (in lba2addr_rd & erase_rd_blk) to tag soft bound (ram only)\
                   log2phy entries with a bit indicating that phy blk is not written.  On erase_rd_blk, this bit
                   is checked, and if set, only marks the rd_phy blk free.  If the bit is NOT set, then the block
                   is erased or added to the erase cache.
                 - fixed erase_cache_flush_one() to ensure that only valid phy blocks are erased.  
  10/23/02  cds  - added feature to mark source block "bad" when a read (copy_src) error occurs, but pass the copy
                 - added feature to erase dest block when copy write (copy_dst) error occurs, and fail the copy
  10/29/02  cds  - added feature to precheck for bad data pages in blocks.  memories like memory stick should be unaffected
                   because the default media_block_has_bad_data() function returns false always.
                 - added hook for sm.c, nand.c, and sm_media.c to check if a logical block has a bad data block in it.
                   ( map_log_blk_has_bad_data() )
  10/30/02  cds  - fixed copy_tail to use bitwise OR rather than logical OR when updating log2phy table
                 - fixed copy_tail to return a result explicity.
  11/02/02  cds  - updated map_build_sector_map() to always call the virtual _media_resolve_conflict() when 2 phy blocks
                   report the same logical binding.  this allows greater flexibility in handling differences between 
                   sm, nand and ms compliance issues.
  11/03/02  cds  - updated map_build_sector_map() to call _media_is_phyblock_reserved() instead of assuming which blocks are OK
                 - updated map_build_sector_map() to check if a block is good before checking if it is blank                   
                 
==============================================================================*/

#include "project.h"

#define k_erase_cnt 4

#if defined(k_mcu_97211) || defined(k_mcu_97242)
#define k_opt_erase_cache
#endif


//-----------------------------------------------------------------------------
// bit control macros
//-----------------------------------------------------------------------------
static code char k_tbl_bitdata[] = { 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80} ;
#define _setbit(__buffer,__bitaddr) (__buffer[(uint8)((__bitaddr)/8)] |=  k_tbl_bitdata[(__bitaddr)%8])
#define _clrbit(__buffer,__bitaddr) (__buffer[(uint8)((__bitaddr)/8)] &= ~k_tbl_bitdata[(__bitaddr)%8])
#define _chkbit(__buffer,__bitaddr) (__buffer[(uint8)((__bitaddr)/8)] &   k_tbl_bitdata[(__bitaddr)%8])
#define _flpbit(__buffer,__bitaddr) (__buffer[(uint8)((__bitaddr)/8)] ^=  k_tbl_bitdata[(__bitaddr)%8])

//-----------------------------------------------------------------------------
// more clearly defined macros to wrap set/clr/flip bit macros
//-----------------------------------------------------------------------------
#define _map_phy_blk_used( __map, __blk )     ( _setbit( __map, __blk ) )
#define _map_phy_blk_free( __map, __blk )     ( _clrbit( __map, __blk ) )
#define _map_is_phy_blk_free( __map, __blk )  (!(_chkbit( __map, __blk)))
#define _map_is_phy_blk_used( __map, __blk )  ( _chkbit( __map, __blk))

//+-----------------------------------------------------------------------------
// obtain pointer to log2phy map for the given zone from the media data
//------------------------------------------------------------------------------
// $$$ => will leave this alone, as long as logical-blocks-per-boot_zone is < every other zone, we'll be ok
// $$$ converted this to a function to save code space...  
t_log2phy_map_ref _log_map(uint8 __zone) reentrant 
{
  return ((_media_data(log2phy_map) + ((__zone?1:0)*_media_data(logical_blocks_per_zone))));
}

//+-----------------------------------------------------------------------------
// obtain pointer to assignment map for the given zone from the media data
//------------------------------------------------------------------------------
t_assign_map_ref _assign_map( uint8 __zone ) reentrant
{
  return ((_media_data(assign_map)+((__zone?1:0)*_media_data(physical_blocks_per_zone)/8)));
}

#ifdef k_opt_erase_cache
//+-----------------------------------------------------------------------------
// obtain pointer to cached-erase map for the given zone from the media data
//------------------------------------------------------------------------------
t_erase_cache_ref _erase_cache(uint8 __zone) reentrant
{
  return ((_media_data(erase_cache)+((__zone?1:0)*_media_data(physical_blocks_per_zone)/8)));
}
#endif

#define kbm_map_soft_l2p_binding (0x8000)
#define kbm_map_blk_has_bad_data (0x4000)
#define kbm_map_l2p_bits         (0x0FFF)


// cached pointers to the log2phy and assignment map for a single zone
static xdata t_log2phy_map_ref  _l2p_map;
static xdata t_assign_map_ref   _a_map;
static xdata t_erase_cache_ref  _e_map;


#ifdef k_opt_erase_cache
// cache status macros
#define _is_erase_cache_empty(__zone) ( _media_data(erase_start)[(__zone)?1:0]==k_block_free)
extern void erase_cache_flush_one() reentrant;
#endif


//------------------------------------------------------------------------------
// write caching data (don't argue with it)
//------------------------------------------------------------------------------
xdata uint16 g_wr_cache_tail_log;
xdata uint16 g_wr_cache_tail_src;
xdata uint16 g_wr_cache_tail_dst;
xdata uint16 g_wr_cache_tail_page;
xdata uint16 g_wr_cache_tail_zone;
// #define _write_cache_is_empty() ((g_wr_cache_head_log==k_block_free)&&(g_wr_cache_tail_log==k_block_free))
#define _write_cache_is_empty() (g_wr_cache_tail_log==k_block_free)
#define _write_cache_is_full()  (!_write_cache_empty())


//+-----------------------------------------------------------------------------
// Name:
//   map_resolve_conflict()
//
// Declaration:
//  t_result sm_media_resolve_conflict(void) reentrant
//
// Purpose:
//  resolve a log2phy binding in a media-specific algorithm
//
// Arguments:
//  - see Notes
//
// Return:
//  k_success always
//
// Notes:
//  when called,
//    g_addr_rd_phy_blk contains one of the bindings,
//    g_addr_wr_phy_blk contains the original mapping
//
//  before returning, ensure:
//    g_addr_rd_phy_blk should contain the correct mapping
//    g_addr_wr_phy_blk should contain the block to be erased (or not used)
//
// Since:
//   fmc-1.0
//------------------------------------------------------------------------------

static xdata uint16 _save_rd_pb ;
static xdata uint16 _save_wr_pb ;
static xdata uint16 _save_lb ;

static xdata uint16 _pb1 ;
static xdata uint16 _lb1_first ;
static xdata uint16 _lb1_last ;
static xdata uint16 _pb2 ;
static xdata uint16 _lb2_first ;
static xdata uint16 _lb2_last ;
t_result map_resolve_conflict(void) reentrant
{
  trace0(0, map, 0, "map_resolve_conflict()") ;
  // store the rd/wr/log blks in case we can't resolve the conflict here, and need to
  // defer to the media-specific method.
  _save_rd_pb = g_addr_rd_phy_blk ;
  _save_wr_pb = g_addr_wr_phy_blk ;
  _save_lb = g_addr_log_blk ;

  // set-up vars
  _pb1 = g_addr_rd_phy_blk ;
  _pb2 = g_addr_wr_phy_blk ;
  _lb1_first = _lb2_first = g_addr_log_blk ;

  // read last-sector extra-data for first pb
  g_addr_page = (_media_data(pages_per_block)-1);

  if ( k_success != _media_read_extra_data() )
  {
    trace2(0, map, 0, "resolve conflict case 1: result: %d. reason: could not read extra data for pb %d.", _pb2, _pb1) ;
    // conflict resolved:  pb2 is the winner
    g_addr_rd_phy_blk = _pb2 ;
    g_addr_wr_phy_blk = _pb1 ;
    g_addr_log_blk = _save_lb ;
    return k_success ;
  }

  if ( k_success != _media_phy2log() )
  {
    trace2(0, map, 0, "resolve conflict case 2: result: %d. reason: could not read log binding for last sector of pb %d.", _pb2, _pb1) ;
    // conflict resolved:  pb2 is winner
    g_addr_rd_phy_blk = _pb2 ;
    g_addr_wr_phy_blk = _pb1 ;
    g_addr_log_blk = _save_lb ;
    return k_success ;
  }
  _lb1_last = g_addr_log_blk ;

  if( _lb1_first != _lb1_last)
  {
    trace2(0, map, 0, "resolve conflict case 3: result: %d. reason: pb %d first and last sectors report different logical bindings.", _pb2, _pb1) ;
    // conflict resolved:  pb1 has conflicting bindings between
    // first and last sector, so pb2 is chosen
    // conflict resolved:  pb2 is winner
    g_addr_rd_phy_blk = _pb2 ;
    g_addr_wr_phy_blk = _pb1 ;
    g_addr_log_blk = _save_lb ;
    return k_success ;
  }


  // read last-sector extra-data for second pb
  g_addr_rd_phy_blk = _pb2 ;

  if ( k_success != _media_read_extra_data() )
  {
    // conflict resolved:  pb1 is the winner
    trace2(0, map, 0, "resolve conflict case 4: result: %d. reason: could not read extra data for pb %d.", _pb1, _pb2) ;
    g_addr_rd_phy_blk = _pb1 ;
    g_addr_wr_phy_blk = _pb2 ;
    g_addr_log_blk = _save_lb ;
    return k_success ;
  }

  if ( k_success != _media_phy2log() )
  {
    // conflict resolved:  pb1 is winner
    trace2(0, map, 0, "resolve conflict case 5: result: %d. reason: could not read log binding for last sector of pb %d.", _pb1, _pb2) ;
    g_addr_rd_phy_blk = _pb1 ;
    g_addr_wr_phy_blk = _pb2 ;
    g_addr_log_blk = _save_lb ;
    return k_success ;
  }
  _lb2_last = g_addr_log_blk ;

  if( _lb2_first != _lb2_last)
  {
    trace2(0, map, 0, "resolve conflict case 6: result: %d. reason: pb %d first and last sectors report different logical bindings.", _pb1, _pb2) ;

    // conflict resolved:  pb2 has conflicting logical bindings between
    // first and last sector, so pb1 is chosen
    g_addr_rd_phy_blk = _pb1 ;
    g_addr_wr_phy_blk = _pb2 ;
    g_addr_log_blk = _save_lb ;
    return k_success ;
  }

//  TRACE0(244, map, 0, "resolve conflict case 7: result: unresolved.  calling media specific method.") ;

  // at this point we know that pb1 and pb2 both have the same log block,
  // and the first and last sectors both report the same log block, so
  // we don't know which to choose, so we have to call the media-specific
  // arbitrator.

  // restore the g_addrs
  g_addr_rd_phy_blk = _save_rd_pb ;
  g_addr_wr_phy_blk = _save_wr_pb ;
  g_addr_log_blk = _save_lb ;
  return k_error ;
  // $$$ took this out because of a stack overflow
  // return _media_resolve_conflict() ;
}


//+-----------------------------------------------------------------------------
// Name:
//   map_build_sector_map()
//
// Declaration:
//   t_result sm_build_sector_map(void) reentrant
//
// Purpose:
//
// Arguments:
//
// Return:
//
// Notes:
//
// Since:
//   fmc-1.0
//------------------------------------------------------------------------------
t_result map_build_sector_map(void) reentrant
{
  uint16  max_lb;
  uint16  pb;
  uint16  lb;
  t_bool  bad_data;

  trace0(0, map, 0, "map_build_sector_map()") ;
  //_stack_dump() ;

  g_addr_segment=0;
  g_addr_page=0;

  trace2(0, map, 0, "mapping zone %d into map index %d", g_addr_zone, (g_addr_zone?1:0)) ;
  _l2p_map = _log_map(g_addr_zone);
  _a_map = _assign_map(g_addr_zone);
  trace1(0, n2k, 0, "&_l2p_map:%04x", ((uint16)_l2p_map));
  trace1(0, n2k, 0, "&_a_map  :%04x", ((uint16)_a_map));

#ifdef k_opt_erase_cache
  if( _media_data(options)&kbm_media_data_opt_erase_cache)
  {
    _e_map = _erase_cache(g_addr_zone);
  }
  else
#endif
  {
    // this simplifies the clearing of the data below
    _e_map = _a_map;
  }
  trace1(0, cache, 0, "&_e_map  :%04x", ((uint16)_e_map));

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -