nf_unusual.c

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

Generated on Wed Sep 23 09:17:02 2009 for ATMEL by  doxygen 1.5.3