nf_unusual.c

Go to the documentation of this file.
00001 /*This file has been prepared for Doxygen automatic documentation generation.*/
00016 
00017 /* Copyright (c) 2007, Atmel Corporation All rights reserved.
00018  *
00019  * Redistribution and use in source and binary forms, with or without
00020  * modification, are permitted provided that the following conditions are met:
00021  *
00022  * 1. Redistributions of source code must retain the above copyright notice,
00023  * this list of conditions and the following disclaimer.
00024  *
00025  * 2. Redistributions in binary form must reproduce the above copyright notice,
00026  * this list of conditions and the following disclaimer in the documentation
00027  * and/or other materials provided with the distribution.
00028  *
00029  * 3. The name of ATMEL may not be used to endorse or promote products derived
00030  * from this software without specific prior written permission.
00031  *
00032  * THIS SOFTWARE IS PROVIDED BY ATMEL ``AS IS'' AND ANY EXPRESS OR IMPLIED
00033  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00034  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND
00035  * SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT,
00036  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00037  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00038  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00039  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00040  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00041  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00042  */
00043 
00044 // TODO: remplacer les s_shift_xxx en (1<<s_shift_xxx): et ainsi faire des DIV/MUL plutot que des shift
00045 // TODO: decomposer s_phys_page_addr en s_phys_block et s_phys_page (offset dans le block)
00046 
00047 //_____  I N C L U D E S ___________________________________________________
00048 
00049 #define _TRACE_        (DISABLE)
00050 #include "config.h"
00051 #include "conf_nf.h"
00052 #include "nf.h"              // NAND Flash informations (structure, parameters)
00053 #include "nf_drv.h"
00054 #include "nf_mngt.h"
00055 #include "lib_mcu/debug.h"
00056 
00057 
00058 #ifndef __GNUC__
00059   extern __no_init volatile xdata Byte nf_send_cmd At(NF_CMD_LATCH_ENABLE_ADD);  // Command
00060   extern __no_init volatile xdata Byte nf_send_add At(NF_ADD_LATCH_ENABLE_ADD);  // Address
00061   extern __no_init volatile xdata Byte nf_data At(NF_ADDRESS_CMD_DATA);          // Data
00062 #else
00063   extern volatile unsigned char nf_send_cmd __attribute__ ((section (".nf_cmd")));
00064   extern volatile unsigned char nf_send_add __attribute__ ((section (".nf_add")));
00065   extern volatile unsigned char nf_data     __attribute__ ((section (".nf_dat")));
00066 #endif
00067 
00068 
00069 //_____ P R I V A T E    D E C L A R A T I O N _____________________________
00070 
00071 #if (NF_GENERIC_DRIVER==TRUE) || (defined NF_AUTO_DETECT_2KB) ||(defined NF_AUTO_DETECT_512B)
00072 extern _MEM_TYPE_SLOW_       U8   g_n_zones               ; // number of zones (=1024 blocks) per device
00073 extern _MEM_TYPE_SLOW_       U16  g_n_blocks              ; // number of blocks per device
00074 #endif
00075 extern _MEM_TYPE_SLOW_ U8   g_page_buffer[NF_FULL_PAGE_BUFFER_SIZE] ; // Used to bufferize a page
00076 extern _MEM_TYPE_BIT_  bit  g_nf_init                               ; // Boolean set when driver is initialized
00077 extern _MEM_TYPE_SLOW_ U16  g_last_sub_lut_log_sz                   ; // Size of the last sub-LUT. Unit in number of logical blocks
00078 extern _MEM_TYPE_SLOW_ U16  g_sub_lut_log_sz                        ; // Size of the sub-LUT. Unit in number of logical blocks
00079                        Bool g_is_found_lut                          ;
00080                        Bool g_is_found_fbb                          ;
00081 extern                 Bool g_fatal                                 ; // Used in LUT/FBB building and ECC management...
00082        _MEM_TYPE_SLOW_ U8   g_n_real_sub_lut;
00083        _MEM_TYPE_SLOW_ U16  g_curr_block_addr[    NF_N_DEVICES]; // holds the last block address for each device
00084        _MEM_TYPE_SLOW_ U8   g_byte[16]                              ; // Buffer which holds spare bytes
00085 extern _MEM_TYPE_SLOW_ U8   g_n_sub_lut                             ; // Holds the number of sub-Lut
00086 extern _MEM_TYPE_SLOW_ U16  g_lut_block_addr [ N_SUBLUT ]           ; // LUT block address
00087 extern _MEM_TYPE_SLOW_ U8   g_lut_block_index[ N_SUBLUT ]           ; // LUT index, unit in (LUT size/page size)
00088 static _MEM_TYPE_SLOW_ U8   s_nfd_rev                               ; // Nand Flash Driver revision;
00089 extern _MEM_TYPE_SLOW_ U16  g_nf_first_block                        ; // Block addr of the beginning of dynamic area
00090 static _MEM_TYPE_SLOW_ U8   s_n_quarantine_blocks[NF_N_DEVICES]     ; // count quarantine blocks (ECC error discovered in them, but block not yet bad) for each device
00091 static _MEM_TYPE_SLOW_ U16  s_n_invalid_blocks[   NF_N_DEVICES]     ; // count invalid blocks (bad, management, LUT, ...) for each device
00092 extern _MEM_TYPE_SLOW_ U16  g_n_export_blocks                       ; // Number of physical blocks exported for mass-storage use
00093 extern _MEM_TYPE_SLOW_ U16  g_n_free_blocks                         ; // Number of free physical blocks
00094 extern _MEM_TYPE_SLOW_ U16  g_fbb_block_addr                        ; // Free-Blocks block address
00095 extern _MEM_TYPE_SLOW_ U8   g_fbb_block_index                       ; // Free-Blocks block index
00096 extern _MEM_TYPE_SLOW_ U32  g_last_log_sector                       ; // Holds the last logical sector number
00097 extern _MEM_TYPE_SLOW_ U32  g_copy_src                              ; // Used to copy NF pages (source page)
00098 extern _MEM_TYPE_SLOW_ U16  g_block_to_kill[ NF_N_DEVICES]          ; // Holds the blocks number which will be erased
00099 extern _MEM_TYPE_FAST_ U32  g_phys_page_addr[NF_N_DEVICES]          ; // Holds the current phys page number for each device
00100 extern _MEM_TYPE_FAST_ U8   g_curr_dev_id                           ; // Holds the current device number that is used
00101 
00102 extern _MEM_TYPE_MEDFAST_ U16 g_log_block_id                        ; // Logical Block address
00103 
00104 extern _MEM_TYPE_SLOW_ Cache_lut g_cache_lut; // LUT cache
00105 extern _MEM_TYPE_SLOW_ Cache_fbb g_cache_fbb; // Free-Blocks block cache
00106 
00107 
00108 #if (ERASING_ALL==ENABLE)
00109 static void        ut_nfc_erase_all( void );
00110 #endif
00111 
00112 
00113 static void        nf_init_buffer(      void );
00114 static Status_bool nf_scan(             void );
00115 static Status_bool nf_rebuild(          void );
00116 static Bool        is_nf_invalid(       void );
00117 
00118 static U16         nf_fetch_free_block( U8 i_dev );
00119 
00120 static U8          nf_refine_index( U16 block_addr, U8 inc, U8 pattern) ;
00121 
00122 
00127 static void nf_init_buffer( void )
00128 {
00129    U16 u16_tmp;
00130    for ( u16_tmp=NF_FULL_PAGE_BUFFER_SIZE ; u16_tmp!=0 ; u16_tmp-=2 )
00131    {
00132       g_page_buffer[u16_tmp-1]=0xFF;
00133       g_page_buffer[u16_tmp-2]=0xFF;
00134    }
00135 }
00136 
00137 
00138 
00148 void nf_init ( void )
00149 {
00150    g_nf_init=FALSE;
00151 //   s_pending_write=FALSE;
00152 
00153 #if (NF_GENERIC_DRIVER==TRUE)
00154 #error Check this init...
00155    g_n_zones             = NF_N_ZONES;
00156    g_n_blocks            = NF_N_BLOCKS;
00157    g_shift_block_page    = NF_SHIFT_BLOCK_PAGE;
00158    g_shift_page_byte     = NF_SHIFT_PAGE_BYTE;
00159    s_shift_sector_byte   = NF_SHIFT_SECTOR_BYTE;
00160    g_n_row_cycles        = NF_N_ROW_CYCLES;
00161 
00162    if ( Is_nf_2k() ) // 2KB pages
00163    {
00164       g_ofst_blk_status     = 0;
00165    }
00166    if ( Is_nf_512() ) // 512B pages
00167    {
00168       g_ofst_blk_status     = 5;
00169    }
00170 
00171    s_shift_log_page_sector  = G_SHIFT_PAGE_BYTE - S_SHIFT_SECTOR_BYTE + NF_SHIFT_N_DEVICES;
00172    s_shift_log_block_sector = s_shift_log_page_sector + G_SHIFT_BLOCK_PAGE;
00173 #endif
00174 
00175    g_cache_lut.ctrl.valid = FALSE; g_cache_lut.ctrl.dirty = FALSE;
00176    g_cache_fbb.ctrl.valid = FALSE; g_cache_fbb.ctrl.dirty = FALSE;
00177    g_last_log_sector= 0xFFFFFFFF;
00178 }
00179 
00180 
00193 Status_bool nf_verify_resume( void )
00194 {
00195    U8 u8_nb_loop;
00196    Bool status_bool;
00197 
00198 
00199 #if (ERASING_ALL==ENABLE)
00200    ut_nfc_erase_all();
00201 #endif
00202    
00203    status_bool = nf_scan();
00204 
00205    if(( PASS!=status_bool )
00206    || ( is_nf_invalid()   )  // The NF is not cleanly built
00207    ) {
00208       // The NF seems not cleanly built, or not built at all.
00209       //
00210       u8_nb_loop = 0;
00211       while( 1 )
00212       {
00213          u8_nb_loop++;
00214          if( u8_nb_loop > 2 )
00215          {
00216             status_bool=FAIL;
00217             break;  // Error NF access or control
00218          }
00219          nf_cleanup_memory();
00220          if( PASS != nf_scan() )
00221             continue;
00222          if( PASS != nf_rebuild() )
00223             continue;
00224          status_bool = PASS;
00225          break;
00226       }
00227    }
00228    if (status_bool==PASS)
00229    {
00230       g_nf_init = TRUE;
00231       Nf_check_lut();
00232       Nf_check_fbb( FALSE );
00233    }
00234 
00235    return status_bool;
00236 }
00237 
00238 
00239 
00247 void nf_cleanup_memory(void)
00248 {
00249    U8   i_dev  =0;
00250    U16  i_block=0;
00251    U8   block_valid;
00252    U8   block_id;
00253 
00254    // Scan all the devices and looks for:
00255    // - the sub-LUT
00256    // - the recovery block
00257    // - the free-blocks block
00258    //
00259    for( i_dev=0 ; i_dev<NF_N_DEVICES ; i_dev++ )
00260    {
00261       // Select the devices
00262       //
00263       Nfc_action(NFC_ACT_DEV_SELECT, i_dev);
00264 
00265       for( i_block=g_nf_first_block ; i_block<G_N_BLOCKS ; i_block++ )
00266       {
00267 
00268          nfc_open_page_read( nf_block_2_page(i_block), NF_SPARE_POS);
00269          block_valid = Nfc_rd_data_fetch_next();
00270          block_id    = Nfc_rd_data()           ;
00271 
00272          if ( block_valid!=0xFF )
00273          {
00274             continue; // The block is bad
00275          }
00276 
00277          if(( NFC_BLK_ID_SUBLUT==block_id )
00278          || ( NFC_BLK_ID_FBB   ==block_id ))
00279          {
00280             nfc_erase_block( nf_block_2_page(i_block), TRUE ) ;
00281             if ( FAIL==nfc_check_status() )
00282             {
00283                nfc_mark_bad_block( nf_block_2_page(i_block) );
00284             }
00285          }
00286       } // for( i_block...
00287    } // for( i_dev...
00288 } // nf_cleanup_memory
00289 
00290 
00291 
00300 static Status_bool nf_scan( void )
00301 {
00302    U8          i_dev  =0;
00303    U16         i_block=0;
00304    U8          n_quarantine_blocks=0;
00305    U16         n_invalid_blocks=0;
00306 
00307    g_last_sub_lut_log_sz =(U16)-1;
00308    g_sub_lut_log_sz      =(U16)NF_SUBLUT_SIZE/NF_N_DEVICES;
00309 
00310 
00311    // Initialize the recovery structure. This should be done by the startup !
00312    //
00313    g_is_found_lut  =FALSE;
00314    g_is_found_fbb  =FALSE;
00315    g_fatal         =FALSE;
00316    g_n_real_sub_lut=0;
00317 
00318    // Scan all the devices and looks for:
00319    // - the sub-LUT blocks
00320    // - the recovery block
00321    // - the free-blocks block
00322    //
00323    for( i_dev=0 ; i_dev<NF_N_DEVICES ; i_dev++ )
00324    {
00325       n_invalid_blocks   = 0;
00326       n_quarantine_blocks= 0;
00327       g_curr_block_addr[i_dev]= G_N_BLOCKS -1; // points on the last block
00328 
00329       trace("Device "); trace_hex(i_dev); trace("\n\r");
00330       Nfc_action(NFC_ACT_DEV_SELECT, i_dev);
00331 
00332       for( i_block=g_nf_first_block ; i_block<G_N_BLOCKS ; i_block++ )
00333       {
00334          nfc_read_spare_byte( g_byte, 16, nf_block_2_page(i_block) );
00335          if ( g_byte[G_OFST_BLK_STATUS]!=0xFF )
00336          {
00337             n_invalid_blocks +=1 ;
00338             trace_hex16(i_block); trace(" ("); trace_u32(i_block); trace("): bad Block\n\r");
00339             continue; // The block is bad
00340          }
00341 
00342          if(( g_byte[NFC_SPARE_OFST_1_BLK_ID]!=NFC_BLK_ID_SUBLUT     )
00343          && ( g_byte[NFC_SPARE_OFST_1_BLK_ID]!=NFC_BLK_ID_FBB        )
00344          && ( g_byte[NFC_SPARE_OFST_1_BLK_ID]!=NFC_BLK_ID_QUARANTINE )
00345          && ( g_byte[NFC_SPARE_OFST_1_BLK_ID]!=NFC_BLK_ID_DATA       ))
00346          {
00347             n_invalid_blocks +=1;
00348             trace_hex16(i_block); trace(" ("); trace_u32(i_block); trace("): Unknown\n\r");
00349             continue;
00350          }
00351          else if ( g_byte[NFC_SPARE_OFST_1_BLK_ID]==NFC_BLK_ID_QUARANTINE )
00352          {
00353             n_quarantine_blocks +=1;
00354             trace_hex16(i_block); trace(" ("); trace_u32(i_block); trace("): Quarantine\n\r");
00355             continue;
00356          }
00357          else if ( g_byte[NFC_SPARE_OFST_1_BLK_ID]==NFC_BLK_ID_SUBLUT )
00358          {
00359             n_invalid_blocks +=1;
00360             if ( i_dev==S_MNGT_DEV )
00361             {
00362                U8 sub_lut_id                   = g_byte[NFC_SPARE_OFST_2_BYTE_2];
00363                g_n_sub_lut                     = g_byte[NFC_SPARE_OFST_4_BYTE_4];
00364                g_is_found_lut = TRUE;
00365                g_n_real_sub_lut++;
00366                g_lut_block_addr[sub_lut_id] = i_block;
00367                if ( sub_lut_id==(g_n_sub_lut-1) )
00368                {
00369                   MSB(g_last_sub_lut_log_sz)= g_byte[NFC_SPARE_OFST_6_LBA  ];
00370                   LSB(g_last_sub_lut_log_sz)= g_byte[NFC_SPARE_OFST_6_LBA+1];
00371                }
00372                g_lut_block_index[sub_lut_id]= nf_refine_index(i_block, 1, NFC_BLK_ID_SUBLUT);
00373                trace_hex16(i_block); trace(" ("); trace_u32(i_block); trace("): SUB-LUT (id ");trace_hex(sub_lut_id);trace(" ofst "); trace_hex(g_lut_block_index[sub_lut_id]); trace(")\n\r");
00374                continue ;
00375             }
00376             else
00377             {  // LUT found on bad NF
00378                g_fatal=TRUE;
00379                break;
00380             }
00381          }
00382 
00383          else if ( g_byte[NFC_SPARE_OFST_1_BLK_ID]==NFC_BLK_ID_FBB )
00384          {
00385             n_invalid_blocks +=1;
00386             if ( i_dev==S_MNGT_DEV )
00387             {
00388                if ( TRUE==g_is_found_fbb )
00389                {
00390                   g_fatal=TRUE; // already found
00391                   break;
00392                }
00393                g_fbb_block_addr  = i_block;
00394                g_fbb_block_index = nf_refine_index(i_block, 1, NFC_BLK_ID_FBB);
00395                nfc_read_spare_byte( g_byte, 16, nf_block_2_page(i_block) + (U32)g_fbb_block_index );     // Reload
00396                if( NFC_OFST_6_FBB_VALID!=g_byte[NFC_SPARE_OFST_6_LBA] )
00397                {
00398                   g_fatal=TRUE; // FBB not valid. Force rebuild
00399                   break;
00400                }
00401 
00402                MSB(g_n_free_blocks)   = g_byte[NFC_SPARE_OFST_2_BYTE_2];
00403                LSB(g_n_free_blocks)   = g_byte[NFC_SPARE_OFST_3_BYTE_3];
00404                s_nfd_rev              = g_byte[NFC_SPARE_OFST_4_BYTE_4];
00405                MSB(g_n_export_blocks) = g_byte[NFC_SPARE_OFST_EXPORT];
00406                LSB(g_n_export_blocks) = g_byte[NFC_SPARE_OFST_EXPORT+1];
00407                trace("      g_n_free_blocks="); trace_hex16(g_n_free_blocks); trace_nl();
00408                trace("      g_n_export_blocks="); trace_hex16(g_n_export_blocks); trace_nl();
00409                g_is_found_fbb=TRUE;
00410                trace_hex16(i_block); trace(" ("); trace_u32(i_block); trace("): FBB (ofst "); trace_hex( g_fbb_block_index ); trace(")\n\r");
00411                continue ;
00412             }
00413             else
00414             {
00415                g_fatal=TRUE;
00416                break;
00417             }
00418          }
00419       } // for ( i_block
00420 
00421       // A fatal error on one device is enough to cleanup all the devices !
00422       //
00423       s_n_invalid_blocks[   i_dev]= n_invalid_blocks;
00424       s_n_quarantine_blocks[i_dev]= n_quarantine_blocks;
00425 
00426       if ( TRUE==g_fatal ) { break; }
00427    } // for ( i_dev
00428 
00429    return (g_fatal==TRUE) ? FAIL: PASS;
00430 } // nf_scan
00431 
00432 
00441 static Bool is_nf_invalid ( void )
00442 {
00443    if( // If we do not find everything
00444       ( FALSE==g_is_found_lut )
00445    || ( FALSE==g_is_found_fbb )
00446    ) {
00447       g_fatal=TRUE;
00448    }
00449 
00450    // Test LUT coherency
00451    //
00452    if(( TRUE       ==g_is_found_lut   )
00453    && ( g_n_sub_lut!=g_n_real_sub_lut ))
00454    {
00455       g_fatal=TRUE;
00456    }
00457 
00458 //#error se proteger si le nombre de devices changent alors que lut, recovery et free blocs sont déjà créés sur le bloc MNGT.
00459    if ( (U16)-1==g_n_export_blocks     ) { g_fatal=TRUE; }
00460    if (       0==g_n_export_blocks     ) { g_fatal=TRUE; }
00461    if ( (U16)-1==g_last_sub_lut_log_sz ) { g_fatal=TRUE; }
00462 
00463    // Test Nand Flash driver release.
00464    //
00465    if ( s_nfd_rev!=NFC_OFST_4_FBB_DRIVER_RELEASE )
00466    {
00467       g_fatal=TRUE;
00468    }
00469 
00470    return g_fatal;
00471 }
00472 
00473 
00474 
00487 static Status_bool nf_rebuild ( void )
00488 {
00489    Status_bool status_bool=PASS;
00490    Bool        b_duplicate;
00491    U8   i_sub_lut;
00492    U8   i_dev  =0;
00493    _MEM_TYPE_SLOW_ U16  i_block=0;
00494    _MEM_TYPE_SLOW_ U16  u16_tmp;
00495    _MEM_TYPE_SLOW_ U16  sub_lut_log_sz;
00496    _MEM_TYPE_SLOW_ U16  log_block_addr;
00497    _MEM_TYPE_SLOW_ U16  log_block_addr_min;
00498    _MEM_TYPE_SLOW_ U16  log_block_addr_max;
00499 
00500    // Refine the computation
00501    //
00502    s_n_invalid_blocks[S_MNGT_DEV] +=
00503       1                                        // Need a block for the Free-blocks block
00504    +  (G_N_BLOCKS*NF_N_DEVICES)/NF_SUBLUT_SIZE // and one for each sub-LUT
00505    ;
00506 
00507    // Take the max number of invalid blocks of each devices
00508    //
00509    u16_tmp=s_n_invalid_blocks[0] ;
00510    for ( i_dev=1 ; i_dev<NF_N_DEVICES ; i_dev++ )
00511    {
00512       u16_tmp=Max( u16_tmp, s_n_invalid_blocks[i_dev] );
00513    }
00514 
00515    // Take the max number of quarantine blocks of each devices
00516    //
00517    i_sub_lut=s_n_quarantine_blocks[0] ;
00518    for ( i_dev=1 ; i_dev<NF_N_DEVICES ; i_dev++ )
00519    {
00520       i_sub_lut=Max( i_sub_lut, s_n_quarantine_blocks[i_dev] );
00521    }
00522 
00523    sub_lut_log_sz = (U16)NF_N_DEVICES*(G_N_BLOCKS -g_nf_first_block -u16_tmp);
00524 
00525    // Finally compute the number of exportable physical blocks and free blocks
00526    //
00527    Assert( u16_tmp<(G_N_BLOCKS -g_nf_first_block) );
00528    g_n_export_blocks= (U16)( ((U32)( (U32)sub_lut_log_sz ) * 1000) / 1024);
00529    g_n_export_blocks= Align_down( g_n_export_blocks, NF_N_DEVICES);
00530 
00531    g_n_free_blocks  = (U16)sub_lut_log_sz - g_n_export_blocks;
00532    g_n_free_blocks -= (U16)NF_N_DEVICES*i_sub_lut;
00533 
00534    if( g_n_free_blocks<=NF_LOW_N_FREE_THRESHOLD )
00535    {
00536       while(1); // TBD
00537    }
00538 
00539    Assert( g_n_free_blocks>0 );
00540    Assert( g_n_free_blocks<(1L<<NF_SHIFT_PAGE_BYTE) ); // limit the free blocks in order to fit in 1 page
00541 
00542    // Compute the number of needed sub-LUT
00543    // Affect to each management block a free block address
00544    //
00545    Nfc_action(NFC_ACT_DEV_SELECT, S_MNGT_DEV);
00546    g_fbb_block_addr = nf_fetch_free_block(S_MNGT_DEV);
00547    nfc_erase_block( nf_block_2_page( g_fbb_block_addr ), TRUE );
00548    g_n_sub_lut= 0;
00549    u16_tmp    = g_n_export_blocks;
00550 //#error il faut positionner les index(LUT, FBB, RCV...)
00551    while(1)
00552    {
00553       Assert( g_n_sub_lut<N_SUBLUT );
00554       g_lut_block_addr [g_n_sub_lut]=nf_fetch_free_block(S_MNGT_DEV);
00555       g_lut_block_index[g_n_sub_lut]=0;
00556       nfc_erase_block( nf_block_2_page( g_lut_block_addr [g_n_sub_lut] ), TRUE );
00557       g_n_sub_lut++;
00558       if( u16_tmp>NF_SUBLUT_SIZE )  u16_tmp-=NF_SUBLUT_SIZE;
00559       else                          break;
00560    }
00561    g_last_sub_lut_log_sz=u16_tmp/NF_N_DEVICES;
00562 
00563    // Build the sub-LUTs
00564    //
00565    for ( i_sub_lut=0 ; i_sub_lut<g_n_sub_lut ;  )
00566    {
00567       U8  n_sublut_in_buf = g_n_sub_lut - i_sub_lut; // Count remaining sublut to build
00568 
00569       log_block_addr_max =
00570       log_block_addr_min = (U16)i_sub_lut<<(NF_SHIFT_SUBLUT_PHYS-NF_SHIFT_N_DEVICES); // first included
00571 
00572       if( n_sublut_in_buf>(NF_PAGE_BUFFER_SIZE/(2*NF_SUBLUT_SIZE)) )
00573       {
00574          n_sublut_in_buf = NF_PAGE_BUFFER_SIZE/(2*NF_SUBLUT_SIZE);
00575          log_block_addr_max += ((U16)n_sublut_in_buf)*g_sub_lut_log_sz; // last not included
00576       }
00577       else
00578       {
00579          log_block_addr_max += ((U16)n_sublut_in_buf-1)*g_sub_lut_log_sz +g_last_sub_lut_log_sz; // last not included
00580       }
00581 
00582       nf_init_buffer();
00583 
00584       // Report affected logical blocks
00585       //
00586       u16_tmp=g_n_export_blocks/NF_N_DEVICES; // Number of logical blocks used for the mass storage
00587 
00588       b_duplicate=FALSE;
00589 
00590       for ( i_dev=0 ; i_dev<NF_N_DEVICES ; i_dev++ )
00591       {
00592          Nfc_action(NFC_ACT_DEV_SELECT, i_dev);
00593 
00594          g_block_to_kill[i_dev]=0xFFFF;
00595 
00596          for ( i_block=g_nf_first_block ; i_block<G_N_BLOCKS ; i_block++ )
00597          {
00598             nfc_read_spare_byte( g_byte, 8, nf_block_2_page(i_block) );
00599             if(( 0xFF           !=g_byte[G_OFST_BLK_STATUS          ] ) // The block is bad
00600             || ( NFC_BLK_ID_DATA!=g_byte[NFC_SPARE_OFST_1_BLK_ID    ] ) // or is not a data block
00601             || (  ( 0xFF        ==g_byte[NFC_SPARE_OFST_6_LBA       ] ) // or is not affected
00602                && ( 0xFF        ==g_byte[NFC_SPARE_OFST_6_LBA+1     ] )
00603                )
00604             ) {
00605                continue;
00606             }
00607 
00608             MSB(log_block_addr) = g_byte[NFC_SPARE_OFST_6_LBA  ];
00609             LSB(log_block_addr) = g_byte[NFC_SPARE_OFST_6_LBA+1];
00610 
00611             if( log_block_addr>=u16_tmp )
00612             {  // The LBA seems bad: it does not fit in any LUT. This happens when unplugging the player.
00613                // Block is erased.
00614                // Anyway, stay in the loop to track similar problems.
00615                nfc_erase_block( nf_block_2_page(i_block), TRUE );
00616                status_bool=FAIL;
00617             }
00618 
00619             if(( log_block_addr>=log_block_addr_min )
00620             && ( log_block_addr< log_block_addr_max ))
00621             {
00622                U16 ofst=2*((U16)i_dev + (log_block_addr%((U16)NF_PAGE_BUFFER_SIZE/2/NF_N_DEVICES))*NF_N_DEVICES) ;
00623                if(
00624                   ( 0xFF==g_page_buffer[ ofst    ] )
00625                && ( 0xFF==g_page_buffer[ ofst +1 ] )
00626                )
00627                {  // no redundant phys blocks
00628                   Assert(      ( ofst +1 ) < NF_PAGE_BUFFER_SIZE );
00629                   g_page_buffer[ ofst    ] = MSB(i_block);
00630                   g_page_buffer[ ofst +1 ] = LSB(i_block);
00631                }
00632                else
00633                {  // A duplicated logical block is detected. This happens when unplugging the player.
00634                   // Anyway, stay in the loop to track any other redundant blocks, for that sub-LUT.
00635                   _MEM_TYPE_SLOW_ U16 tmp_addr;
00636                   MSB(tmp_addr)=g_page_buffer[ ofst    ];
00637                   LSB(tmp_addr)=g_page_buffer[ ofst +1 ];
00638                   //trace("Dupl "); trace_hex32(tmp_addr); trace("-"); trace_hex32(i_block);; trace("\n\r");
00639 
00640                   if(0xFFFF!=g_block_to_kill[i_dev])
00641                   {  // !!! There are more than 1 duplicated block on the device. This should never happen...
00642                      nfc_erase_block( nf_block_2_page(g_block_to_kill[i_dev]), TRUE );
00643                      return FAIL;
00644                   }
00645 
00646                   b_duplicate=TRUE;
00647                   g_log_block_id=log_block_addr;
00648 
00649                   nfc_open_page_read(
00650                      nf_block_2_page(i_block)
00651                   ,  NF_SPARE_POS+NFC_SPARE_OFST_3_BYTE_3
00652                   );
00653                   if( NFC_OFST_3_DATA_DST!=Nfc_rd_data_fetch_next() )
00654                   {
00655                      trace("1. Src block="); trace_hex16(i_block); trace_nl();
00656                      trace("1. Dst block="); trace_hex16(tmp_addr); trace_nl();
00657                      //nfc_print_block(i_block, 0);
00658                      //nfc_print_block(tmp_addr, 0);
00659                      //while(1);
00660                      g_block_to_kill[i_dev]=i_block;                        // source block
00661                      g_phys_page_addr[i_dev] = nf_block_2_page( tmp_addr ); // recipient block
00662                   }
00663                   else
00664                   {
00665                      trace("2. Src block="); trace_hex16(tmp_addr); trace_nl();
00666                      trace("2. Dst block="); trace_hex16(i_block); trace_nl();
00667                      //nfc_print_block(tmp_addr, 0);
00668                      //nfc_print_block(i_block, 0);
00669                      //while(1);
00670                      g_block_to_kill[i_dev]= tmp_addr ;                     // source block
00671                      g_page_buffer[ ofst    ]=MSB(i_block);
00672                      g_page_buffer[ ofst +1 ]=LSB(i_block);
00673                      g_phys_page_addr[i_dev] = nf_block_2_page( i_block );  // recipient block
00674                   }
00675                }
00676             }
00677          } // for ( i_block ../..
00678       } // for ( i_dev ../..
00679 
00680       if( b_duplicate )
00681       {
00682          U8 i_page;
00683          U8 i_sect;
00684 
00685          trace("recovery\n\r");
00686          // Test that recovery can be done
00687          for ( i_dev=0 ; i_dev<NF_N_DEVICES ; i_dev++ )
00688          {
00689             if( 0xFFFF==g_block_to_kill[i_dev] )
00690             {  // !Ooops... we can not recover from that case since there are duplication
00691                // only on on device
00692                for ( i_dev=0 ; i_dev<NF_N_DEVICES ; i_dev++ )
00693                {
00694                   if( 0xFFFF!=g_block_to_kill[i_dev] )
00695                   {
00696                      nfc_erase_block( nf_block_2_page(g_block_to_kill[i_dev]), TRUE );
00697                   }
00698                }
00699                return FAIL;
00700             }
00701          }
00702 
00703          // Initialize variable for nf_copy_tail
00704          g_curr_dev_id=0;
00705          g_last_log_sector= ((U32)g_log_block_id) << S_SHIFT_LOG_BLOCK_SECTOR;
00706 
00707          // Look for last written sector
00708          for( i_page=0 ; i_page<SIZE_BLOCK_PAGE ; i_page++ )
00709          {
00710             Nfc_action(NFC_ACT_DEV_SELECT, g_curr_dev_id);  // open the current device
00711             for( i_sect=0 ; i_sect<SIZE_PAGE_SECTOR ; i_sect++ )
00712             {
00713                nfc_open_page_read(
00714                   g_phys_page_addr[g_curr_dev_id]
00715                ,  NF_SPARE_POS + (((U16)i_sect)*16) + NFC_SPARE_OFST_6_LBA
00716                );
00717                if(( 0xFF==Nfc_rd_data_fetch_next() )
00718                && ( 0xFF==Nfc_rd_data_fetch_next() ))
00719                   goto recovery_exit;
00720                else
00721                {
00722                   g_last_log_sector++;
00723                   trace("g_last_log_sector="); trace_hex32(g_last_log_sector); trace_nl();
00724                }
00725             }
00726             g_phys_page_addr[g_curr_dev_id]++;                                                   // update the current physical page of the current device
00727             g_curr_dev_id++;                                                                     // update the current device
00728             if( g_curr_dev_id==NF_N_DEVICES ) { g_curr_dev_id=0; }
00729             trace("g_curr_dev_id="); trace_hex(g_curr_dev_id); trace_nl();
00730             trace("g_phys_page_addr="); trace_hex32(g_phys_page_addr[g_curr_dev_id]); trace_nl();
00731          }
00732 recovery_exit:
00733          trace("recovery stop on g_last_log_sector="); trace_hex32(g_last_log_sector); trace_nl();
00734          trace("g_curr_dev_id="); trace_hex(g_curr_dev_id); trace_nl();
00735          trace("g_phys_page_addr="); trace_hex32(g_phys_page_addr[g_curr_dev_id]); trace_nl();
00736          //while(1);
00737          nf_copy_tail();
00738          return FAIL;
00739       }
00740 
00741       // At least one redundant have been found: the LUT must be rebuilt since the fetch of free block
00742       // may not have seen that affected block (redundant) are in fact free.
00743       if( PASS!=status_bool ) { return FAIL; }
00744 
00745       // Affect a free physical block to the logical block
00746       //
00747       for( i_dev=0 ; i_dev<NF_N_DEVICES ; i_dev++ )
00748       {
00749          Nfc_action(NFC_ACT_DEV_SELECT, i_dev);
00750 
00751          for(u16_tmp=0
00752          ;   u16_tmp<(log_block_addr_max-log_block_addr_min)
00753          ;   u16_tmp++ )
00754          {
00755             U16 ofst=2*((U16)i_dev + u16_tmp*NF_N_DEVICES);
00756             if(( 0xFF==g_page_buffer[ofst  ] )
00757             && ( 0xFF==g_page_buffer[ofst+1] ))
00758             {
00759                i_block=nf_fetch_free_block(i_dev);
00760                Assert(       ofst+1<NF_PAGE_BUFFER_SIZE);
00761                g_page_buffer[ofst  ] = MSB(i_block);
00762                g_page_buffer[ofst+1] = LSB(i_block);
00763             }
00764          }
00765       } // for ( i_dev ../..
00766 
00767       // Each sub-LUT will fit in a physical page and will be of the same size
00768       // except the last one which contains less
00769       //
00770       for( ; n_sublut_in_buf!=0 ; n_sublut_in_buf--, i_sub_lut++ )
00771       {
00772          sub_lut_log_sz= ( i_sub_lut==(g_n_sub_lut-1) ) ? g_last_sub_lut_log_sz : g_sub_lut_log_sz ;
00773 
00774          // Write the sub-LUT in the page
00775          //
00776          status_bool = nf_write_lut(i_sub_lut%(NF_PAGE_BUFFER_SIZE/(2*NF_SUBLUT_SIZE)), i_sub_lut, sub_lut_log_sz);
00777          if ( PASS!=status_bool )
00778          {
00779             nfc_mark_bad_block( nf_block_2_page( g_lut_block_addr[i_sub_lut] ) );
00780             return FAIL;
00781          }
00782       }
00783    }
00784 
00785 //#error: si recovery, il faut effacer la lut en question. Il faut donc la reconstruire.
00786 //        Pour cela, il faut trouver des blocs libres.
00787 // 1ere methode: effacer aussi le free-blocks block et le reconstruire, ainsi que la sub-LUT
00788 // 2eme methode: marquer les free block pour les reconnaitre et reconstruire la sub lut
00789 
00790    // Build the free-blocks block
00791    // First, fill the internal buffer with the free blocks
00792    //
00793    for ( i_dev=0 ; i_dev<NF_N_DEVICES ; i_dev++ )
00794    {
00795       Nfc_action(NFC_ACT_DEV_SELECT, i_dev);
00796 
00797       for ( u16_tmp=0 ; u16_tmp<(g_n_free_blocks/NF_N_DEVICES) ; u16_tmp++ )
00798       {
00799          // This define is better than using a variable that holds the expression...
00800          #define OFST   (2*(i_dev + u16_tmp*NF_N_DEVICES))
00801          i_block=nf_fetch_free_block(i_dev);
00802          nfc_erase_block( nf_block_2_page(i_block), TRUE );
00803          Assert(       OFST   <NF_PAGE_BUFFER_SIZE);
00804          Assert(       OFST +1<NF_PAGE_BUFFER_SIZE);
00805          Assert( i_block>=g_nf_first_block );
00806          Assert( i_block< G_N_BLOCKS       );
00807          g_page_buffer[OFST   ] = MSB(i_block);
00808          g_page_buffer[OFST +1] = LSB(i_block);
00809          #undef OFST
00810       }
00811    }
00812 
00813    // Then write the buffer in the free-blocks block
00814    // Note that the list of free-blocks holds on one page only; the
00815    // algo is thus made for both 512B and 2kB pages.
00816    //
00817    g_fbb_block_index=0;
00818    status_bool = nf_write_fbb();
00819    if ( PASS!=status_bool )
00820    {
00821       nfc_mark_bad_block( nf_block_2_page( g_fbb_block_addr ) );
00822       return FAIL;
00823    }
00824 
00825 //#error Effacer les free blocks !!!!!!
00826 //#error il faut determiner s_lut_index[all] pour les sub-lut existantes
00827 //#error si il existe un bloc de recovery, alors la lut associée n'est plus valide
00828 //#error rendre parametrable la taille du buffer (actuellement 2k). Si <512 et no partial prog: fatal error
00829 
00830    //nf_init_buffer(); // Cleanup the buffer
00831    return PASS;
00832 }
00833 
00834 
00835 
00844 static U16 nf_fetch_free_block(U8 i_dev)
00845 {
00846 
00847    U16 block_addr= g_curr_block_addr[i_dev];
00848 
00849    while ( block_addr>=g_nf_first_block )
00850    {
00851       nfc_read_spare_byte( g_byte, 8, nf_block_2_page( block_addr ) );
00852       if(( 0xFF           ==g_byte[G_OFST_BLK_STATUS          ] ) // the block is valid
00853       && ( NFC_BLK_ID_DATA==g_byte[NFC_SPARE_OFST_1_BLK_ID    ] ) // the block is a data block
00854       && ( 0xFF           ==g_byte[NFC_SPARE_OFST_6_LBA       ] ) // and is not affected
00855       && ( 0xFF           ==g_byte[NFC_SPARE_OFST_6_LBA+1     ] ))
00856       {
00857          // Since we rebuild the flash, we should not see any of these blocks
00858          //
00859          Assert( NFC_BLK_ID_SUBLUT!=g_byte[NFC_SPARE_OFST_1_BLK_ID] );
00860          Assert( NFC_BLK_ID_FBB   !=g_byte[NFC_SPARE_OFST_1_BLK_ID] );
00861 
00862          // Find a free and valid block addr. Store the current position
00863          //
00864          g_curr_block_addr[i_dev] = block_addr-1;
00865          return block_addr;
00866       }
00867       block_addr-=1 ;
00868    }
00869    // This situation is dramatic: it should never happen !
00870    // Force Rebuild on next startup
00871    nfc_erase_block( nf_block_2_page( g_fbb_block_addr ), TRUE );
00872    while(1);
00873    Assert( FALSE ) ; // Not enough free blocks: fatal error!
00874 }
00875 
00876 
00877 
00891 static U8 nf_refine_index(
00892    U16 block_addr
00893 ,  U8  inc
00894 ,  U8  pattern)
00895 {
00896    _MEM_TYPE_SLOW_ U8 u8_tmp;
00897    _MEM_TYPE_SLOW_ U8 val=0;
00898    do
00899    {
00900       val+= inc; // Assume that the pattern has already be seen previously
00901       if( val>=SIZE_BLOCK_PAGE )
00902          { break; }
00903       nfc_open_page_read(
00904          nf_block_2_page(block_addr) + val
00905       ,  NF_SPARE_POS+NFC_SPARE_OFST_1_BLK_ID
00906       );
00907       u8_tmp = Nfc_rd_data();
00908    } while( pattern==u8_tmp );
00909    val-= inc; // come back to last valid entry
00910    Assert( val<(1<<G_SHIFT_BLOCK_PAGE) ); // The offset shall not be outside the block
00911    return val;
00912 }
00913 
00914 
00915 
00916 #if (ERASING_ALL==ENABLE)
00917 static void ut_nfc_erase_all( void )
00918 {
00919    _MEM_TYPE_SLOW_ U8   i_dev  =0;
00920    _MEM_TYPE_SLOW_ U16  i_block=0;
00921    _MEM_TYPE_SLOW_ U32  page_addr;
00922 
00923    for( i_dev=0 ; i_dev<NF_N_DEVICES ; i_dev++ )
00924    {
00925       // Select the devices
00926       //
00927       Nfc_action(NFC_ACT_DEV_SELECT, i_dev);
00928 
00929       for( i_block=g_nf_first_block ; i_block<G_N_BLOCKS ; i_block++ )
00930       {
00931          page_addr= (U32)i_block<<NF_SHIFT_BLOCK_PAGE;
00932          nfc_erase_block( page_addr, FALSE ) ;
00933       }
00934    }
00935 }
00936 #endif
00937 

Generated on Fri Oct 31 14:31:24 2008 for ATMEL by  doxygen 1.5.3