/** * @brief Write 1 page of data to the PNOR device */ errlHndl_t PnorRP::writeToDevice( uint64_t i_offset, uint64_t i_chip, bool i_ecc, void* i_src ) { TRACUCOMP(g_trac_pnor, "PnorRP::writeToDevice> i_offset=%X, i_chip=%d", i_offset, i_chip ); errlHndl_t l_errhdl = NULL; uint8_t* ecc_buffer = NULL; do { #ifdef CONFIG_SFC_IS_AST2400 //@todo RTC:106881 -- Add full write/erase support TRACFCOMP(g_trac_pnor, "PnorRP::writeToDevice> Skipping all writes in BMC for now" ); break; #endif TARGETING::Target* pnor_target = TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL; // assume a single page to write void* data_to_write = i_src; size_t write_size = PAGESIZE; // apply ECC to data if needed if( i_ecc ) { ecc_buffer = new uint8_t[PAGESIZE_PLUS_ECC]; PNOR::ECC::injectECC( reinterpret_cast<uint8_t*>(i_src), PAGESIZE, reinterpret_cast<uint8_t*>(ecc_buffer) ); data_to_write = reinterpret_cast<void*>(ecc_buffer); write_size = PAGESIZE_PLUS_ECC; } //no need for mutex since only ever a singleton object iv_stats[i_offset/PAGESIZE].numWrites++; // write the data out to the PNOR DD errlHndl_t l_errhdl = DeviceFW::deviceWrite( pnor_target, data_to_write, write_size, DEVICE_PNOR_ADDRESS(i_chip,i_offset) ); if( l_errhdl ) { TRACFCOMP(g_trac_pnor, "PnorRP::writeToDevice> Error from device : RC=%X", l_errhdl->reasonCode() ); break; } } while(0); if( ecc_buffer ) { delete[] ecc_buffer; } TRACUCOMP(g_trac_pnor, "< PnorRP::writeToDevice" ); return l_errhdl; }
/** * @brief Retrieve 1 page of data from the PNOR device */ errlHndl_t PnorRP::readFromDevice( uint64_t i_offset, uint64_t i_chip, bool i_ecc, void* o_dest, uint64_t& o_fatalError ) { TRACUCOMP(g_trac_pnor, "PnorRP::readFromDevice> i_offset=0x%X, i_chip=%d", i_offset, i_chip ); errlHndl_t l_errhdl = NULL; uint8_t* ecc_buffer = NULL; o_fatalError = 0; do { TARGETING::Target* pnor_target = TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL; // assume a single page void* data_to_read = o_dest; size_t read_size = PAGESIZE; // if we need to handle ECC we need to read more than 1 page if( i_ecc ) { ecc_buffer = new uint8_t[PAGESIZE_PLUS_ECC](); data_to_read = ecc_buffer; read_size = PAGESIZE_PLUS_ECC; } // get the data from the PNOR DD l_errhdl = DeviceFW::deviceRead(pnor_target, data_to_read, read_size, DEVICE_PNOR_ADDRESS(i_chip,i_offset) ); if( l_errhdl ) { TRACFCOMP(g_trac_pnor, "PnorRP::readFromDevice> Error from device : RC=%X", l_errhdl->reasonCode() ); break; } // remove the ECC data if( i_ecc ) { // remove the ECC and fix the original data if it is broken PNOR::ECC::eccStatus ecc_stat = PNOR::ECC::removeECC( reinterpret_cast<uint8_t*>(data_to_read), reinterpret_cast<uint8_t*>(o_dest), PAGESIZE ); // create an error if we couldn't correct things if( ecc_stat == PNOR::ECC::UNCORRECTABLE ) { TRACFCOMP( g_trac_pnor, "PnorRP::readFromDevice> Uncorrectable ECC error : chip=%d,offset=0x%.X", i_chip, i_offset ); // Need to shutdown here instead of creating an error log // because the bad page could be critical to the regular // error handling path and cause an infinite loop. // Also need to spawn a separate task to do the shutdown // so that the regular PNOR task can service the writes // that happen during shutdown. o_fatalError = PNOR::RC_ECC_UE; INITSERVICE::doShutdown( PNOR::RC_ECC_UE, true ); } // found an error so we need to fix something else if( ecc_stat != PNOR::ECC::CLEAN ) { TRACFCOMP( g_trac_pnor, "PnorRP::readFromDevice> Correctable ECC error : chip=%d, offset=0x%.X", i_chip, i_offset ); // need to write good data back to PNOR l_errhdl = DeviceFW::deviceWrite(pnor_target, data_to_read,//corrected data read_size, DEVICE_PNOR_ADDRESS(i_chip,i_offset) ); if( l_errhdl ) { TRACFCOMP(g_trac_pnor, "PnorRP::readFromDevice> Error writing corrected data back to device : RC=%X", l_errhdl->reasonCode() ); // we don't need to fail here since we can correct // it the next time we read it again, instead just // commit the log here errlCommit(l_errhdl,PNOR_COMP_ID); } // keep some stats here in case we want them someday //no need for mutex since only ever 1 thread accessing this iv_stats[i_offset/PAGESIZE].numCEs++; } } } while(0); if( ecc_buffer ) { delete[] ecc_buffer; } TRACUCOMP(g_trac_pnor, "< PnorRP::readFromDevice" ); return l_errhdl; }