📄 map.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.
____________________________________________________________________________
____________________________________________________________________________
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 + -