diff options
author | Mike Baiocchi <baiocchi@us.ibm.com> | 2015-02-17 13:07:13 -0600 |
---|---|---|
committer | A. Patrick Williams III <iawillia@us.ibm.com> | 2015-03-01 16:22:19 -0600 |
commit | 19b0400e8e2123bdfe1231616bfdaf2fc0d1f3e2 (patch) | |
tree | 52b29b9d9cf4e40ef379fff36a47a5af6531d6a6 /src/usr/sbe | |
parent | f8ff70afe17963e03abdbc113cf8c1f6198857c3 (diff) | |
download | talos-hostboot-19b0400e8e2123bdfe1231616bfdaf2fc0d1f3e2.tar.gz talos-hostboot-19b0400e8e2123bdfe1231616bfdaf2fc0d1f3e2.zip |
GOLDEN SBE Update Support - Reconcile SBE images and PNOR sides
This code adds a new function at istep 6 to reconcile the two
SBE Seeproms with the PNOR side and mode (ie, 2-sided, golden, etc).
It also updates what happens in istep 9 in SBE_UPDATE_INDEPENDENT
mode.
Change-Id: If71ca52338a179b8cf38cfa336d9790737844715
RTC: 120734
Reviewed-on: http://gfw160.aus.stglabs.ibm.com:8080/gerrit/15790
Tested-by: Jenkins Server
Reviewed-by: PRACHI GUPTA <pragupta@us.ibm.com>
Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Reviewed-by: Richard J. Knight <rjknight@us.ibm.com>
Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
Diffstat (limited to 'src/usr/sbe')
-rw-r--r-- | src/usr/sbe/HBconfig | 6 | ||||
-rw-r--r-- | src/usr/sbe/makefile | 5 | ||||
-rw-r--r-- | src/usr/sbe/sbe_resolve_sides.C | 1363 | ||||
-rw-r--r-- | src/usr/sbe/sbe_resolve_sides.H | 259 | ||||
-rw-r--r-- | src/usr/sbe/sbe_update.C | 124 |
5 files changed, 1720 insertions, 37 deletions
diff --git a/src/usr/sbe/HBconfig b/src/usr/sbe/HBconfig index 0fa24413d..fd2a8d07b 100644 --- a/src/usr/sbe/HBconfig +++ b/src/usr/sbe/HBconfig @@ -20,9 +20,9 @@ config SBE_UPDATE_INDEPENDENT depends on !SBE_UPDATE_SEQUENTIAL && !SBE_UPDATE_SIMULTANEOUS help If an update is necessary, and if the "current" SBE SEEPROM of this - IPL is not the 'GOLDEN' SBE SEEPROM, then only the current SBE SEEPROM - will be updated. After the update a re-IPL request will be issued. - The other SBE SEEPROM, whether 'GOLDEN' or not, will not be updated. + IPL is not pointing at PNOR's 'GOLDEN' side, then only the current SBE + SEEPROM will be updated. After the update a re-IPL request will be + issued. The other SBE SEEPROM will not be updated. config NO_SBE_UPDATES default n diff --git a/src/usr/sbe/makefile b/src/usr/sbe/makefile index 06159ff01..c45206e1e 100644 --- a/src/usr/sbe/makefile +++ b/src/usr/sbe/makefile @@ -5,7 +5,9 @@ # # OpenPOWER HostBoot Project # -# COPYRIGHT International Business Machines Corp. 2013,2014 +# Contributors Listed Below - COPYRIGHT 2013,2015 +# [+] International Business Machines Corp. +# # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -36,6 +38,7 @@ EXTRAINCDIR += ${ROOTPATH}/src/usr/hwpf/hwp/include EXTRAINCDIR += ${ROOTPATH}/src/usr/hwpf/hwp/build_winkle_images/p8_slw_build OBJS += sbe_update.o +OBJS += sbe_resolve_sides.o SUBDIRS += test.d diff --git a/src/usr/sbe/sbe_resolve_sides.C b/src/usr/sbe/sbe_resolve_sides.C new file mode 100644 index 000000000..df9958d65 --- /dev/null +++ b/src/usr/sbe/sbe_resolve_sides.C @@ -0,0 +1,1363 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/sbe/sbe_resolve_sides.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ + +#include <trace/interface.H> +#include <errl/errlentry.H> +#include <errl/errlmanager.H> +#include <errl/errludtarget.H> +#include <errl/errlreasoncodes.H> +#include <errl/hberrltypes.H> +#include <targeting/common/predicates/predicatectm.H> +#include <targeting/common/utilFilter.H> +#include <targeting/common/targetservice.H> +#include <util/misc.H> +#include <pnor/pnorif.H> +#include <pnor/ecc.H> +#include <devicefw/driverif.H> +#include <sys/mm.h> +#include <sys/misc.h> +#include <hwas/common/deconfigGard.H> +#include <initservice/initserviceif.H> +#include <config.h> +#include <ipmi/ipmiwatchdog.H> +#include <ipmi/ipmisensor.H> +#include <sbe/sbeif.H> +#include <sbe/sbereasoncodes.H> +#include "sbe_resolve_sides.H" +#include "sbe_update.H" + +// fapi support +#include <fapi.H> +#include <fapiHwpExecutor.H> +#include <hwpf/plat/fapiPlatHwpInvoker.H> +#include <hwpf/plat/fapiPlatTrace.H> + +//Procedures +#include <p8_xip_customize.H> +#include <sbe_xip_image.h> +#include <p8_image_help_base.H> + +// ---------------------------------------------- +// Trace definitions +// ---------------------------------------------- +extern trace_desc_t* g_trac_sbe; + +// ------------------------ +// Macros for unit testing +//#define TRACUCOMP(args...) TRACFCOMP(args) +#define TRACUCOMP(args...) + + +using namespace ERRORLOG; +using namespace TARGETING; + +namespace SBE +{ + enum { + SBE_IMG_VADDR = VMM_VADDR_SBE_UPDATE, + RING_BUF1_VADDR = FIXED_SEEPROM_WORK_SPACE + SBE_IMG_VADDR, + RING_BUF2_VADDR = RING_BUF1_VADDR + FIXED_RING_BUF_SIZE, + //NOTE: recycling the same memory space for different + //steps in the process. + SBE_ECC_IMG_VADDR = RING_BUF1_VADDR, + SBE_ECC_IMG_MAX_SIZE = VMM_VADDR_SBE_UPDATE_END - SBE_ECC_IMG_VADDR, + }; + +///////////////////////////////////////////////////////////////////// +errlHndl_t resolveProcessorSbeSeeproms() +{ + errlHndl_t err = NULL; + errlHndl_t err_cleanup = NULL; + sbeResolveState_t sideState; + bool l_cleanupVmmSpace = false; + bool l_restartNeeded = false; + + TRACUCOMP( g_trac_sbe, + ENTER_MRK"resolveProcessorSbeSeeproms()" ); + + do{ + +#ifdef CONFIG_NO_SBE_UPDATES + TRACFCOMP( g_trac_sbe, INFO_MRK"resolveProcessorSbeSeeproms() - " + "SBE updates not configured"); + break; +#endif + +#ifdef CONFIG_SBE_UPDATE_SIMULTANEOUS + TRACFCOMP( g_trac_sbe, INFO_MRK"resolveProcessorSbeSeeproms() - " + "Do Nothing in SBE_UPDATE_SIMULTANEOUS mode"); + break; +#endif + +#ifdef CONFIG_SBE_UPDATE_SEQUENTIAL + // Check if FSP-services are enabled and if we're running in simics + if ( !INITSERVICE::spBaseServicesEnabled() && + !Util::isSimicsRunning() ) + { + assert (false, "resolveProcessorSbeSeeproms() - " + "SBE_UPDATE_SEQUENTIAL mode, but FSP-services are not " + "enabled - Invalid Configuration"); + } + else + { + TRACUCOMP( g_trac_sbe, INFO_MRK"resolveProcessorSbeSeeproms() - " + "Do Nothing in SBE_UPDATE_INDEPENDENT mode with FSP-" + "services enabled or running in simics"); + break; + } +#endif + + // Get Target Service, and the system target. + TargetService& tS = targetService(); + TARGETING::Target* sys = NULL; + (void) tS.getTopLevelTarget( sys ); + assert(sys, "resolveProcessorSbeSeeproms() system target is NULL"); + + + //Make sure procedure constants keep within expected range. + assert((FIXED_SEEPROM_WORK_SPACE <= VMM_SBE_UPDATE_SIZE/2), + "resolveProcessorSbeSeeproms() FIXED_SEEPROM_WORK_SPACE " + "too large"); + assert((FIXED_RING_BUF_SIZE <= VMM_SBE_UPDATE_SIZE/4), + "resolveProcessorSbeSeeproms() FIXED_RING_BUF_SIZE too " + "large"); + + // Create VMM space for p8_xip_customize() procedure + err = createSbeImageVmmSpace(); + if (err) + { + TRACFCOMP( g_trac_sbe, + INFO_MRK"resolveProcessorSbeSeeproms: " + "createSbeImageVmmSpace() Failed. ", + "rc=0x%.4X", err->reasonCode() ); + + break; + } + else + { + // Make sure cleanup gets called + l_cleanupVmmSpace = true; + } + + /*****************************************************************/ + /* Iterate over all the functional processors and do for each: */ + /*****************************************************************/ + TARGETING::TargetHandleList procList; + TARGETING::getAllChips(procList, + TARGETING::TYPE_PROC, + true); // true: return functional targets + + if( ( 0 == procList.size() ) || + ( NULL == procList[0] ) ) + { + TRACFCOMP( g_trac_sbe, ERR_MRK"resolveProcessorSbeSeeproms() - " + "No functional processors Found!" ); + break; + } + + for(uint32_t i=0; i<procList.size(); i++) + { + /***********************************************/ + /* Get Side This Processor did/will boot from */ + /***********************************************/ + memset(&sideState, 0, sizeof(sideState)); + sideState.tgt = procList[i]; + + err = getSideState(sideState); + if ( err ) + { + TRACFCOMP( g_trac_sbe, ERR_MRK + "resolveProcessorSbeSeeproms: Error returned " + "from getSideState() " + "rc=0x%.4X, Target UID=0x%X", + err->reasonCode(), + TARGETING::get_huid(sideState.tgt)); + // Don't break - handle error at the end of the loop + } + + + /**********************************************/ + /* Determine the necessary actions */ + /**********************************************/ + // Skip if we got an error previously + if ( err == NULL ) + { + err = getSideActions(sideState); + if (err) + { + TRACFCOMP( g_trac_sbe, + INFO_MRK"resolveProcessorSbeSeeproms: " + "getSideActions() Failed " + "rc=0x%.4X, Target UID=0x%X", + err->reasonCode(), + TARGETING::get_huid(sideState.tgt)); + + // Don't break - handle error at the end of the loop, + } + } + + /**********************************************/ + /* Perform the necessary actions */ + /**********************************************/ + // Skip if we got an error previously + if ( err == NULL ) + { + err = performSideActions(sideState); + if (err) + { + TRACFCOMP( g_trac_sbe, + INFO_MRK"resolveProcessorSbeSeeproms: " + "performSideActions() Failed " + "rc=0x%.4X, Target UID=0x%X", + err->reasonCode(), + TARGETING::get_huid(sideState.tgt)); + + // Don't break - handle error at the end of the loop, + } + else + { + // Target updated without failure, so set IPL_RESTART + // flag, if necessary + if (sideState.actions & REIPL) + { + l_restartNeeded = true; + } + } + } + + /**********************************************/ + /* Handle Errors */ + /**********************************************/ + + if ( err ) + { + // Something failed for this target. + + // Commit the error here and move on to the next target, + // or if no targets left, will just continue the IPL + TRACFCOMP( g_trac_sbe, + INFO_MRK"resolveProcessorSbeSeeproms: " + "Committing Error Log rc=0x%.4X eid=0x%.8X " + "plid=0x%.8X for Target UID=0x%X, but " + "continuing procedure", + err->reasonCode(), + err->eid(), + err->plid(), + TARGETING::get_huid(sideState.tgt)); + errlCommit( err, SBE_COMP_ID ); + } + + + } //end of Target for loop collecting each target's SBE State + + + /**************************************************************/ + /* Perform System Operation */ + /**************************************************************/ + // Restart IPL if SBE Update requires it + if ( l_restartNeeded == true ) + { + TRACFCOMP( g_trac_sbe, + INFO_MRK"resolveProcessorSbeSeeprom: Restart " + "Needed (%d).", + l_restartNeeded); + +#ifdef CONFIG_BMC_IPMI + sbePreShutdownIpmiCalls(); +#endif + + TRACFCOMP( g_trac_sbe, + INFO_MRK"resolveProcessorSbeSeeproms: Calling " + "INITSERVICE::doShutdown() with " + "SBE_UPDATE_REQUEST_REIPL = 0x%X", + SBE_UPDATE_REQUEST_REIPL ); + INITSERVICE::doShutdown(SBE_UPDATE_REQUEST_REIPL); + } + + }while(0); + + + // Cleanup VMM Workspace + if ( l_cleanupVmmSpace == true ) + { + err_cleanup = cleanupSbeImageVmmSpace(); + if ( err_cleanup != NULL ) + { + + if ( err != NULL ) + { + // 2 error logs, so commit the cleanup log here + TRACFCOMP( g_trac_sbe, + ERR_MRK"resolveProcessorSbeSeeproms: Previous " + "error (rc=0x%X) before cleanupSbeImageVmmSpace" + "() failed. Committing cleanup error (rc=0x%X) " + "and returning original error", + err->reasonCode(), err_cleanup->reasonCode() ); + + errlCommit( err_cleanup, SBE_COMP_ID ); + } + else + { + // no previous error, so returning cleanup error + TRACFCOMP( g_trac_sbe, + ERR_MRK"resolveProcessorSbeSeeproms: " + "cleanupSbeImageVmmSpace() failed.", + "rc=0x%.4X", err_cleanup->reasonCode() ); + err = err_cleanup; + } + } + } + + + TRACUCOMP( g_trac_sbe, + EXIT_MRK"resolveProcessorSbeSeeproms()" ); + + return err; +} + +///////////////////////////////////////////////////////////////////// +errlHndl_t getSideState(sbeResolveState_t& io_sideState) +{ + errlHndl_t err = NULL; + TRACUCOMP( g_trac_sbe, + ENTER_MRK"getSideState()" ); + + do{ + + /***********************************************/ + /* Get Side This Processor did/will boot from */ + /***********************************************/ + PNOR::sbeSeepromSide_t tmp_cur_side = PNOR::SBE_SEEPROM_INVALID; + err = PNOR::getSbeBootSeeprom(io_sideState.tgt, tmp_cur_side); + if ( err ) + { + TRACFCOMP( g_trac_sbe, ERR_MRK + "resolveProcessorSbeSeeproms() - Error returned " + "from PNOR::getSbeBootSeeprom() " + "rc=0x%.4X, Target UID=0x%X", + err->reasonCode(), + TARGETING::get_huid(io_sideState.tgt)); + break; + } + + io_sideState.cur_side = tmp_cur_side; + + io_sideState.alt_side = (tmp_cur_side == PNOR::SBE_SEEPROM0) + ? PNOR::SBE_SEEPROM1 : PNOR::SBE_SEEPROM0; + + /**********************************************/ + /* Get PNOR Side Information */ + /**********************************************/ + PNOR::SideId tmp_side = PNOR::WORKING; + PNOR::SideInfo_t tmp_side_info; + err = PNOR::getSideInfo (tmp_side, tmp_side_info); + if ( err ) + { + TRACFCOMP( g_trac_sbe, ERR_MRK + "resolveProcessorSbeSeeproms() - Error returned " + "from PNOR::getSideInfo() " + "rc=0x%.4X, Target UID=0x%X", + err->reasonCode(), + TARGETING::get_huid(io_sideState.tgt)); + break; + } + + io_sideState.pnor_sideId = tmp_side_info.id; + io_sideState.pnor_side = tmp_side_info.side; + io_sideState.pnor_isGolden = tmp_side_info.isGolden; + io_sideState.pnor_hasOtherSide = tmp_side_info.hasOtherSide; + + }while(0); + + + TRACUCOMP( g_trac_sbe, + EXIT_MRK"getSideState(): cur/alt=%d/%d. Side-%c(%d): " + "isGolden=%d, hasOtherSide=%d", + io_sideState.cur_side, io_sideState.alt_side, + io_sideState.pnor_side, io_sideState.pnor_sideId, + io_sideState.pnor_isGolden, io_sideState.pnor_hasOtherSide ); + + return err; +} + + +///////////////////////////////////////////////////////////////////// +errlHndl_t getSideActions(sbeResolveState_t& io_sideState) +{ + errlHndl_t err = NULL; + uint32_t l_actions = NO_ACTIONS; + TRACUCOMP( g_trac_sbe, + ENTER_MRK"getSideActions()" ); + + do{ + + // Check if PNOR is running from its GOLDEN side + if ( io_sideState.pnor_isGolden == true ) + { + + // If Booting From Seeprom that is pointing to PNOR's GOLDEN Side + // and is possibly the READ_ONLY_SEEPROM - No Re-IPL + if ( io_sideState.cur_side == READ_ONLY_SEEPROM ) + { + l_actions |= COPY_READ_ONLY_TO_WORKING; + io_sideState.update_side = io_sideState.alt_side; +#ifdef CONFIG_PNOR_TWO_SIDE_SUPPORT + // Need info from PNOR's non-working side for update side + l_actions |= USE_PNOR_ALT_SIDE; + TRACUCOMP( g_trac_sbe, "getSideActions(): Asking for " + "USE_PNOR_ALT_SIDE: actions=0x%X", l_actions); +#endif + } + else + { + // non-READ_ONLY_SEEPROM is pointing to PNOR's GOLDEN side + // This requires an update and re-IPL (Possibly Genesis Mode) + l_actions |= COPY_READ_ONLY_TO_WORKING; + l_actions |= REIPL; + io_sideState.update_side = io_sideState.cur_side; + +#ifdef CONFIG_PNOR_TWO_SIDE_SUPPORT + // Need info from PNOR's non-working side for update side + l_actions |= USE_PNOR_ALT_SIDE; + TRACUCOMP( g_trac_sbe, "getSideActions(): Asking for " + "USE_PNOR_ALT_SIDE: actions=0x%X", l_actions); +#endif + + } + } + + // Even though READ_ONLY_SEEPROM is not pointing to PNOR's GOLDEN side, + // treat like it is if there is only 1 side (ie, Palmetto configuration) + else if ( ( io_sideState.pnor_hasOtherSide == false ) && + ( io_sideState.cur_side == READ_ONLY_SEEPROM ) ) + { + l_actions |= COPY_READ_ONLY_TO_WORKING; + io_sideState.update_side = io_sideState.alt_side; + } + + else // current Seeprom not pointing to PNOR's GOLDEN side + { + l_actions |= CHECK_WORKING_HBB; + io_sideState.update_side = io_sideState.cur_side; + // REIPL action will be determined later + } + + io_sideState.actions = l_actions; + + TRACUCOMP( g_trac_sbe, "getSideActions() Tgt=0x%X: " + "pnor_isGolden/hasOtherSide=%d/%d, actions=0x%.8X, " + "Update Side=0x%X, cur=%d", + TARGETING::get_huid(io_sideState.tgt), + io_sideState.pnor_isGolden, io_sideState.pnor_hasOtherSide, + io_sideState.actions, + io_sideState.update_side, + io_sideState.cur_side); + + }while(0); + + TRACUCOMP( g_trac_sbe, + EXIT_MRK"getSideActions()" ); + + return err; +} + + + +///////////////////////////////////////////////////////////////////// +errlHndl_t performSideActions(sbeResolveState_t& io_sideState) +{ + errlHndl_t err = NULL; + TRACUCOMP( g_trac_sbe, + ENTER_MRK"performSideActions()" ); + + bool updateForHBB = false; + size_t image_size = 0; + sbeSeepromVersionInfo_t image_version; + + do{ + if ( io_sideState.actions & COPY_READ_ONLY_TO_WORKING ) + { + // Copy READ_ONLY SBE Seeprom Image to Memory + err = readSbeImage(io_sideState.tgt, + reinterpret_cast<void*>(SBE_IMG_VADDR), + READ_ONLY_SEEPROM, + image_size, + image_version); + if ( err ) + { + TRACFCOMP( g_trac_sbe, ERR_MRK + "performSideActions: Error returned from " + "getSetSbeImage() rc=0x%.4X, Target UID=0x%X, " + "actions = 0x%X, image_size=0x%X", + err->reasonCode(), + TARGETING::get_huid(io_sideState.tgt), + io_sideState.actions, image_size); + break; + } + } + + if ( io_sideState.actions & CHECK_WORKING_HBB ) + { + + // Copy current SBE Seeprom Image to Memory + // NOTE: Seprate section from above because of possible future + // improvement to use MBPD SB Keyword bit to keep track of HBB + + err = readSbeImage(io_sideState.tgt, + reinterpret_cast<void*>(SBE_IMG_VADDR), + io_sideState.update_side, + image_size, + image_version); + if ( err ) + { + TRACFCOMP( g_trac_sbe, ERR_MRK + "performSideActions: Error returned from " + "getSetSbeImage() rc=0x%.4X, Target UID=0x%X, " + "actions = 0x%X, image_size=0x%X", + err->reasonCode(), + TARGETING::get_huid(io_sideState.tgt), + io_sideState.actions, image_size); + break; + } + + } + + + if ( ( io_sideState.actions & COPY_READ_ONLY_TO_WORKING ) || + ( io_sideState.actions & CHECK_WORKING_HBB ) ) + { + // verify HBB + PNOR::SideId pnor_side = PNOR::WORKING; + +#ifdef CONFIG_PNOR_TWO_SIDE_SUPPORT + // In certain situations need info from Alternate PNOR + if ( io_sideState.actions & USE_PNOR_ALT_SIDE) + { + pnor_side = PNOR::ALTERNATE; + } +#endif + + + + err = resolveImageHBBaddr(io_sideState.tgt, + reinterpret_cast<void*>(SBE_IMG_VADDR), + io_sideState.update_side, + pnor_side, + updateForHBB); + if ( err ) + { + TRACFCOMP( g_trac_sbe, ERR_MRK + "performSideActions: Error returned from " + "resolveImageHBBaddr() rc=0x%.4X, Target UID=0x%X, " + "actions = 0x%X", + err->reasonCode(), + TARGETING::get_huid(io_sideState.tgt), + io_sideState.actions); + break; + } + + // Since HBB was updated, we need to re-IPL if not booting on + // READ_ONLY seeprom + if ( ( updateForHBB == true ) && + ( io_sideState.cur_side != READ_ONLY_SEEPROM ) ) + { + io_sideState.actions |= REIPL; + TRACUCOMP( g_trac_sbe, ERR_MRK + "performSideActions: resolveImageHBBaddr returned " + "updateForHBB=%d, and not on READ_ONLY_SEEPROM so " + "REIPL (actions=0x%X)", + updateForHBB, io_sideState.actions); + } + } + + if ( ( io_sideState.actions & COPY_READ_ONLY_TO_WORKING ) || + ( updateForHBB == true ) ) + { + // Write Seeprom Image from memory to Seeprom + err = writeSbeImage(io_sideState.tgt, + reinterpret_cast<void*>(SBE_IMG_VADDR), + io_sideState.update_side, + image_size, + image_version); + if ( err ) + { + TRACFCOMP( g_trac_sbe, ERR_MRK + "performSideActions: Error returned from " + "getSetSbeImage() rc=0x%.4X, Target UID=0x%X, " + "actions = 0x%X", + err->reasonCode(), + TARGETING::get_huid(io_sideState.tgt), + io_sideState.actions); + break; + } + } + + }while(0); + + TRACUCOMP( g_trac_sbe, + EXIT_MRK"performSideActions()" ); + + return err; +} + + +///////////////////////////////////////////////////////////////////// +errlHndl_t readSbeImage(TARGETING::Target* i_target, + void* o_imgPtr, + PNOR::sbeSeepromSide_t i_side, + size_t& o_image_size, + sbeSeepromVersionInfo_t& o_image_version) +{ + TRACUCOMP( g_trac_sbe, + ENTER_MRK"readSbeImage(): tgt=0x%X, i_side=%d " + "o_imgPtr=%p, o_image_size=0x%X", + TARGETING::get_huid(i_target), i_side, o_imgPtr, o_image_size); + + errlHndl_t err = NULL; + int64_t rc = 0; + PNOR::ECC::eccStatus eccStatus = PNOR::ECC::CLEAN; + EEPROM::eeprom_chip_types_t l_seeprom = sbe_side_sync[i_side]; + size_t image_size_ECC = 0; + + // Need to ensure that io_imgPtr is at SBE_IMG_VADDR = VMM_VADDR_SBE_UPDATE + // since we need to use the VMM_VADDR_SBE_UPDATE space + assert ( o_imgPtr == reinterpret_cast<void*>(SBE_IMG_VADDR), + "getSetSbeImage() - o_imgPtr is not at SBE_IMG_VADDR"); + + do{ + + // Clear out back half of page block to use as temp space + // for ECC injected SBE Image. + rc = mm_remove_pages(RELEASE, + reinterpret_cast<void*> + (SBE_ECC_IMG_VADDR), + SBE_ECC_IMG_MAX_SIZE); + if( rc ) + { + TRACFCOMP( g_trac_sbe, ERR_MRK"getSetSbeImage() - Error " + "from mm_remove_pages : rc=%d, HUID=0x%.8X.", + rc, TARGETING::get_huid(i_target) ); + /*@ + * @errortype + * @moduleid SBE_READ_SBE_IMAGE + * @reasoncode SBE_REMOVE_PAGES_FOR_EC + * @userdata1 Requested Address + * @userdata2 rc from mm_remove_pages + * @devdesc updateProcessorSbeSeeproms> mm_remove_pages + * RELEASE failed + * @custdesc A problem occurred while updating processor + * boot code. + */ + err = new ErrlEntry(ERRL_SEV_UNRECOVERABLE, + SBE_READ_SBE_IMAGE, + SBE_REMOVE_PAGES_FOR_EC, + TO_UINT64(SBE_ECC_IMG_VADDR), + TO_UINT64(rc), + true /*Add HB SW Callout*/ ); + + //Target isn't directly related to fail, but could be useful + // to see how far we got before failing. + ErrlUserDetailsTarget(i_target).addToLog(err); + err->collectTrace(SBE_COMP_NAME); + break; + } + + /*****************************************/ + /* Get Image Size */ + /*****************************************/ + err = getSbeImageSize(i_target, + o_imgPtr, + i_side, + o_image_size); + if(err) + { + TRACFCOMP( g_trac_sbe, ERR_MRK"readSbeImage: - Error from " + "getSbeImageSize(): rc=0x%.4X, side=%d, HUID=0x%.8X.", + err->reasonCode(), + i_side, TARGETING::get_huid(i_target)); + break; + } + + + /*****************************************/ + /* Do Actual Read */ + /*****************************************/ + image_size_ECC = ALIGN_8((o_image_size*9)/8); + + assert(image_size_ECC <= SBE_ECC_IMG_MAX_SIZE, + "getSetSbeImage() SBE Image with ECC too large"); + + // Read image to memory space + err = DeviceFW::deviceOp( + DeviceFW::READ, + i_target, + reinterpret_cast<void*> + (SBE_ECC_IMG_VADDR), + image_size_ECC, + DEVICE_EEPROM_ADDRESS( + l_seeprom, + SBE_IMAGE_SEEPROM_ADDRESS)); + + if(err) + { + TRACFCOMP( g_trac_sbe, ERR_MRK"readSbeImage: - Error " + "from EEPROM op: rc=0x%.4X, seeprom=%d (side=%d). " + "HUID=0x%.8X. SBE_VADDR=0x%.16X, ECC_VADDR=0x%.16X, " + "size=0x%.8X, eccSize=0x%.8X, EEPROM offset=0x%X", + err->reasonCode(), l_seeprom, i_side, + TARGETING::get_huid(i_target), + SBE_IMG_VADDR, SBE_ECC_IMG_VADDR, o_image_size, + image_size_ECC, SBE_IMAGE_SEEPROM_ADDRESS); + break; + } + + /*****************************************/ + /* Remove ECC From Image */ + /*****************************************/ + + // Clear destination + memset( o_imgPtr, 0, MAX_SEEPROM_IMAGE_SIZE ); + + // Remove ECC + eccStatus = PNOR::ECC::removeECC(reinterpret_cast<uint8_t*> + (SBE_ECC_IMG_VADDR), + reinterpret_cast<uint8_t*> + (o_imgPtr), + image_size_ECC); + + // Fail if uncorrectable ECC + if ( eccStatus == PNOR::ECC::UNCORRECTABLE ) + { + // There is an ECC issue with this SEEPROM + + TRACFCOMP( g_trac_sbe,ERR_MRK"readSbeImage: ECC Error " + "On SBE Image Read eccStatus=%d sI=%d, sI_ECC=" + "%d, HUID=0x%.8X, Seeprom %d (side=%d)", + eccStatus, o_image_size, image_size_ECC, + TARGETING::get_huid(i_target), + l_seeprom, i_side ); + + /*@ + * @errortype + * @moduleid SBE_READ_SBE_IMAGE + * @reasoncode SBE_ECC_FAIL + * @userdata1[0:15] ECC Status + * @userdata1[16:31] SEEPROM Side + * @userdata1[32:63] Target HUID + * @userdata2[0:31] Size - No Ecc + * @userdata2[32:63] Size - ECC + * @devdesc ECC Fail Reading SBE Image + */ + err = new ErrlEntry(ERRL_SEV_PREDICTIVE, + SBE_READ_SBE_IMAGE, + SBE_ECC_FAIL, + TWO_UINT32_TO_UINT64( + ( (eccStatus << 16 ) | + l_seeprom ), + TARGETING::get_huid(i_target)), + TWO_UINT32_TO_UINT64(o_image_size, + image_size_ECC)); + + err->collectTrace(SBE_COMP_NAME); + + err->addPartCallout( + i_target, + HWAS::SBE_SEEPROM_PART_TYPE, + HWAS::SRCI_PRIORITY_HIGH, + HWAS::NO_DECONFIG, + HWAS::GARD_NULL ); + + ErrlUserDetailsTarget(i_target).addToLog(err); + + break; + + } // ECC check + + + // Read out SBE Version Info + bool seeprom_ver_ECC_fail = false; + err = getSeepromSideVersion(i_target, + l_seeprom, + o_image_version, + seeprom_ver_ECC_fail); + + + if(err) + { + TRACFCOMP( g_trac_sbe, ERR_MRK"readSbeImage: - Error " + "from getSeepromSideVersion: rc=0x%.4X, seeprom=%d " + "(side=%d). HUID=0x%.8X", + err->reasonCode(), l_seeprom, i_side, + TARGETING::get_huid(i_target)); + break; + } + + else if (seeprom_ver_ECC_fail == true) + { + // For now, any issues will be addressed in SBE Update + // later in the IPL + TRACFCOMP( g_trac_sbe, ERR_MRK"readSbeImage: ECC fail=%d " + "Reading Seeprom Version seeprom=%d " + "(side=%d). HUID=0x%.8X", + seeprom_ver_ECC_fail, l_seeprom, i_side, + TARGETING::get_huid(i_target)); + } + + TRACDBIN(g_trac_sbe, "readSbeImage: SBE Info Version", + reinterpret_cast<uint8_t*>(&o_image_version), + sizeof(o_image_version)); + + }while(0); + + + TRACUCOMP( g_trac_sbe, + EXIT_MRK"readSbeImage() - eccStatus=%d, " + "size=0x%X, size_ECC=0x%X", + eccStatus, o_image_size, image_size_ECC); + + + return err; +} + + +///////////////////////////////////////////////////////////////////// +errlHndl_t writeSbeImage(TARGETING::Target* i_target, + void* i_imgPtr, + PNOR::sbeSeepromSide_t i_side, + size_t i_image_size, + sbeSeepromVersionInfo_t& io_version) + +{ + TRACFCOMP( g_trac_sbe, + ENTER_MRK"writeSbeImage(): tgt=0x%X, i_side=%d " + "i_imgPtr=%p, i_image_size=0x%X", + TARGETING::get_huid(i_target), i_side, i_imgPtr, i_image_size); + + errlHndl_t err = NULL; + int64_t rc = 0; + EEPROM::eeprom_chip_types_t l_seeprom = sbe_side_sync[i_side]; + size_t image_size_ECC = 0; + + // For Version Information + size_t sbeInfoSize = sizeof(sbeSeepromVersionInfo_t); + size_t sbeInfoSize_ECC = (sbeInfoSize*9)/8; + + uint8_t * sbeInfo_data_ECC = static_cast<uint8_t*> + (malloc(sbeInfoSize_ECC)); + + + // Need to ensure that io_imgPtr is at SBE_IMG_VADDR = VMM_VADDR_SBE_UPDATE + // since we need to use the VMM_VADDR_SBE_UPDATE space + assert ( i_imgPtr == reinterpret_cast<void*>(SBE_IMG_VADDR), + "writeSbeImage() - io_imgPtr is not at SBE_IMG_VADDR"); + + do{ + + // Clear out back half of page block to use as temp space + // for ECC injected SBE Image. + rc = mm_remove_pages(RELEASE, + reinterpret_cast<void*> + (SBE_ECC_IMG_VADDR), + SBE_ECC_IMG_MAX_SIZE); + if( rc ) + { + TRACFCOMP( g_trac_sbe, ERR_MRK"writeSbeImage() - Error " + "from mm_remove_pages : rc=%d, HUID=0x%.8X.", + rc, TARGETING::get_huid(i_target) ); + /*@ + * @errortype + * @moduleid SBE_WRITE_SBE_IMAGE + * @reasoncode SBE_REMOVE_PAGES_FOR_EC + * @userdata1 Requested Address + * @userdata2 rc from mm_remove_pages + * @devdesc updateProcessorSbeSeeproms> mm_remove_pages + * RELEASE failed + * @custdesc A problem occurred while updating processor + * boot code. + */ + + err = new ErrlEntry(ERRL_SEV_UNRECOVERABLE, + SBE_WRITE_SBE_IMAGE, + SBE_REMOVE_PAGES_FOR_EC, + TO_UINT64(SBE_ECC_IMG_VADDR), + TO_UINT64(rc), + true /*Add HB SW Callout*/ ); + + //Target isn't directly related to fail, but could be useful + //to see how far we got before failing. + ErrlUserDetailsTarget(i_target).addToLog(err); + err->collectTrace(SBE_COMP_NAME); + break; + } + + // Inject ECC + PNOR::ECC::injectECC(reinterpret_cast<uint8_t*>(i_imgPtr), + ALIGN_8(i_image_size), + reinterpret_cast<uint8_t*> + (SBE_ECC_IMG_VADDR)); + + /*****************************************/ + /* Do Actual Write of Image */ + /*****************************************/ + image_size_ECC = ALIGN_8((i_image_size*9)/8); + + assert(image_size_ECC <= SBE_ECC_IMG_MAX_SIZE, + "writeSbeImage() SBE Image with ECC too large"); + + err = deviceWrite(i_target, + reinterpret_cast<void*> + (SBE_ECC_IMG_VADDR), + image_size_ECC, + DEVICE_EEPROM_ADDRESS( + l_seeprom, + SBE_IMAGE_SEEPROM_ADDRESS)); + + if(err) + { + TRACFCOMP( g_trac_sbe, ERR_MRK"writeSbeImage: - Error " + "from EEPROM op: rc=0x%.4X, seeprom=%d (side=%d). " + "HUID=0x%.8X. SBE_VADDR=0x%.16X, ECC_VADDR=0x%.16X, " + "size=0x%.8X, eccSize=0x%.8X, EEPROM offset=0x%X", + err->reasonCode(), l_seeprom, i_side, + TARGETING::get_huid(i_target), + SBE_IMG_VADDR, SBE_ECC_IMG_VADDR, i_image_size, + image_size_ECC, SBE_IMAGE_SEEPROM_ADDRESS); + break; + } + + /********************************************/ + /* Do Actual Write of Version Information */ + /********************************************/ + + // Update the image crc in the version information + uint32_t image_crc = Util::crc32_calc(i_imgPtr, i_image_size); + + memcpy( &(io_version.data_crc), + &image_crc, + sizeof(image_crc)); + + TRACDBIN( g_trac_sbe, "writeSbeImage: Version no ECC", + reinterpret_cast<uint8_t*>(&io_version), sizeof(io_version)); + + // Inject ECC + memset( sbeInfo_data_ECC, 0, sbeInfoSize_ECC); + PNOR::ECC::injectECC(reinterpret_cast<uint8_t*>(&io_version), + sbeInfoSize, sbeInfo_data_ECC); + + TRACDBIN( g_trac_sbe, "writeSbeImage: Version with ECC", + sbeInfo_data_ECC, sbeInfoSize_ECC); + + err = deviceWrite( i_target, + sbeInfo_data_ECC, + sbeInfoSize_ECC, + DEVICE_EEPROM_ADDRESS( + l_seeprom, + SBE_VERSION_SEEPROM_ADDRESS)); + + if(err) + { + TRACFCOMP( g_trac_sbe, ERR_MRK"writeSbeImage: - Error " + "Writing SBE Version Info: rc=0x%.4X, " + "HUID=0x%.8X, seeprom=%d, side=%d", + err->reasonCode(), + TARGETING::get_huid(i_target), l_seeprom, i_side); + break; + } + + }while(0); + + // Free allocated memory + free(sbeInfo_data_ECC); + + TRACUCOMP( g_trac_sbe, + EXIT_MRK"writeSetSbeImage()" ); + + return err; +} + + + + +///////////////////////////////////////////////////////////////////// +errlHndl_t getSbeImageSize(TARGETING::Target* i_target, + void* i_imgPtr, + PNOR::sbeSeepromSide_t i_side, + size_t& o_image_size) +{ + TRACUCOMP( g_trac_sbe, + ENTER_MRK"geSbeImageSize(): tgt=0x%X, i_side=%d " + "i_imgPtr=%p, o_image_size=0x%X", + TARGETING::get_huid(i_target), i_side, i_imgPtr, o_image_size); + + errlHndl_t err = NULL; + PNOR::ECC::eccStatus eccStatus = PNOR::ECC::CLEAN; + EEPROM::eeprom_chip_types_t l_seeprom = sbe_side_sync[i_side]; + size_t image_size_ECC = 0; + + // Need to ensure that i_imgPtr is at SBE_IMG_VADDR = VMM_VADDR_SBE_UPDATE + // since we need to use the VMM_VADDR_SBE_UPDATE space + + assert ( i_imgPtr == reinterpret_cast<void*>(SBE_IMG_VADDR), + "getSbeImageSize() - i_imgPtr is not at SBE_IMG_VADDR"); + + do{ + // Need to read the SbeXipHeader of the image to determine size + // of the image to read out. + // Using io_imgPtr space. First read our header+ECC from SBE + // Seeprom and then use space after that to put header without ECC + + + size_t hdr_size = ALIGN_8(sizeof(SbeXipHeader)); + size_t hdr_size_ECC = (hdr_size * 9)/8; + + uint8_t* hdr_ptr = reinterpret_cast<uint8_t*>(i_imgPtr) + hdr_size_ECC; + + memset( i_imgPtr, 0, hdr_size_ECC + hdr_size ); + + TRACUCOMP( g_trac_sbe, INFO_MRK"getSetSbeImage() Reading " + "SbeXipHeader for Target 0x%X, Seeprom %d " + "(side=%d), size_ECC=0x%X (size=0x%X)", + TARGETING::get_huid(i_target), + l_seeprom, i_side, hdr_size_ECC, hdr_size ); + + err = DeviceFW::deviceOp( DeviceFW::READ, + i_target, + i_imgPtr, + hdr_size_ECC, + DEVICE_EEPROM_ADDRESS( + l_seeprom, + SBE_IMAGE_SEEPROM_ADDRESS)); + + if(err) + { + TRACFCOMP( g_trac_sbe, ERR_MRK"getSbeImageSize: - Error " + "Reading SbeXipHeader: rc=0x%.4X, seeprom=%d (side=%d). " + "HUID=0x%.8X. size=0x%.8X, EEPROM offset=0x%X", + err->reasonCode(), l_seeprom, i_side, + TARGETING::get_huid(i_target), sizeof(SbeXipHeader), + SBE_IMAGE_SEEPROM_ADDRESS); + break; + } + + + TRACDBIN( g_trac_sbe, + "Data with ECC read from Seeprom", + i_imgPtr, + hdr_size_ECC ); + + // Remove ECC + eccStatus = PNOR::ECC::removeECC( + reinterpret_cast<uint8_t*>(i_imgPtr), + hdr_ptr, + hdr_size); + + // Fail if uncorrectable ECC + if ( eccStatus == PNOR::ECC::UNCORRECTABLE ) + { + TRACFCOMP( g_trac_sbe,ERR_MRK"getSbeImageSize: ECC Error " + "On SBE Image Read eccStatus=%d sI=%d, sI_ECC=" + "%d, HUID=0x%.8X, Seeprom %d (side=%d)", + eccStatus, o_image_size, image_size_ECC, + TARGETING::get_huid(i_target), + l_seeprom, i_side ); + /*@ + * @errortype + * @moduleid SBE_GET_SBE_IMAGE_SIZE + * @reasoncode SBE_ECC_FAIL + * @userdata1[0:15] ECC Status + * @userdata1[16:31] SEEPROM Side + * @userdata1[32:63] Target HUID + * @userdata2[0:31] Size - No Ecc + * @userdata2[32:63] Size - ECC + * @devdesc ECC Fail Reading SBE Image + */ + err = new ErrlEntry(ERRL_SEV_PREDICTIVE, + SBE_GET_SBE_IMAGE_SIZE, + SBE_ECC_FAIL, + TWO_UINT32_TO_UINT64( + ( (eccStatus << 16 ) | + l_seeprom ), + TARGETING::get_huid(i_target)), + TWO_UINT32_TO_UINT64(o_image_size, + image_size_ECC)); + err->collectTrace(SBE_COMP_NAME); + err->addPartCallout( + i_target, + HWAS::SBE_SEEPROM_PART_TYPE, + HWAS::SRCI_PRIORITY_HIGH, + HWAS::NO_DECONFIG, + HWAS::GARD_NULL ); + + ErrlUserDetailsTarget(i_target).addToLog(err); + + break; + } + + TRACDBIN( g_trac_sbe, + "Data without ECC read from Seeprom", + hdr_ptr, + hdr_size ); + + o_image_size = (((SbeXipHeader*)hdr_ptr)->iv_imageSize); + + }while(0); + + TRACFCOMP( g_trac_sbe, + EXIT_MRK"getSbeImageSize(): o_image_size=0x%X", o_image_size ); + + return err; +} + + + +///////////////////////////////////////////////////////////////////// +errlHndl_t resolveImageHBBaddr(TARGETING::Target* i_target, + void* io_imgPtr, + PNOR::sbeSeepromSide_t i_side, + PNOR::SideId i_pnorSideId, + bool& o_imageWasUpdated ) +{ + errlHndl_t err = NULL; + uint64_t data = 0; + int rc = 0; + bool rc_fail_on_get = false; // 1=get failed, 0=set failed + + o_imageWasUpdated = false; + + TRACUCOMP( g_trac_sbe, + ENTER_MRK"resolveImageHBBaddr() - tgt=0x%X, i_side=%d, " + "i_pnorSideId=%d", + TARGETING::get_huid(i_target), i_side, i_pnorSideId); + + do{ + + // Get info from PNOR + PNOR::SideInfo_t pnor_side_info; + err = PNOR::getSideInfo (i_pnorSideId, pnor_side_info); + if ( err ) + { + TRACFCOMP( g_trac_sbe, ERR_MRK + "resolveImageHBBaddr() - Error returned " + "from PNOR::getSideInfo() rc=0x%.4X, Target UID=0x%X " + "i_pnorSideId", + err->reasonCode(), + TARGETING::get_huid(i_target), i_pnorSideId); + break; + } + + + // Only Need to Check/Update if PNOR has Other Side + // and Seeprom isn't pointing at PNOR's GOLDEN side + if ( ( pnor_side_info.hasOtherSide == true ) && + ( pnor_side_info.isGolden == false ) ) + { + + // Read the MMIO offset associated with the HBB address + // from the image + rc = sbe_xip_get_scalar( io_imgPtr, + "standalone_mbox2_value", + &data); + if ( rc != 0 ) + { + rc_fail_on_get = true; // get failed + + TRACFCOMP( g_trac_sbe, ERR_MRK"resolveImageHBBaddr() - " + "sbe_xip_get_scalar() failed rc = 0x%X (%d)", + rc, rc_fail_on_get); + break; + } + + if ( pnor_side_info.hbbMmioOffset == data ) + { + TRACUCOMP( g_trac_sbe, "resolveImageHBBaddr: Image has MMIO " + "offset = 0x%X that matches PNOR MMIO=" + "0x%X for HBB Address=0x%X", + data, pnor_side_info.hbbMmioOffset, + pnor_side_info.hbbAddress); + } + else + { + TRACFCOMP( g_trac_sbe, "resolveImageHBBaddr: Image has MMIO " + "offset = 0x%X does NOT match PNOR MMIO=" + "0x%X for HBB Address=0x%X. Updating Image", + data, pnor_side_info.hbbMmioOffset, + pnor_side_info.hbbAddress); + + TRACDBIN (g_trac_sbe, "resolveImageHBBaddr: data", &data, 8 ); + + TRACDBIN (g_trac_sbe, "resolveImageHBBaddr: hbbMmioOffset", + &pnor_side_info.hbbMmioOffset, 8 ); + TRACDBIN (g_trac_sbe, "resolveImageHBBaddr: hbbAddress", + &pnor_side_info.hbbAddress, 8); + + rc = sbe_xip_set_scalar( io_imgPtr, "standalone_mbox2_value", + pnor_side_info.hbbMmioOffset); + + if ( rc != 0 ) + { + rc_fail_on_get = false; // set failed + + TRACFCOMP( g_trac_sbe, ERR_MRK"resolveImageHBBaddr() - " + "sbe_xip_set_scalar() failed rc = 0x%X (%d)", + rc, rc_fail_on_get); + break; + } + o_imageWasUpdated = true; + } + + } + else + { + // pnor_side_info.hasOtherSide is false + TRACUCOMP( g_trac_sbe, "resolveImageHBBaddr: PNOR only has " + "1 side - No Update Required"); + } + + }while(0); + + + if ( ( err == NULL ) && ( rc != 0) ) + { + // We failed on get/set cmd above (already traced) + + /*@ + * @errortype + * @moduleid SBE_RESOLVE_HBB_ADDR + * @reasoncode SBE_IMAGE_GET_SET_SCALAR_FAIL + * @userdata1 Return Code of failed operation + * @userdata2 True/False if Get (true) or Set (false) Op failed + * @devdesc sbe_xip_get/set_scalar() failed when accessing the + HBB Address MMIO offset in 'standalone_mbox2_value' + * @custdesc A problem occurred while updating processor + * boot code. + */ + err = new ErrlEntry(ERRL_SEV_UNRECOVERABLE, + SBE_RESOLVE_HBB_ADDR, + SBE_IMAGE_GET_SET_SCALAR_FAIL, + TO_UINT64(rc), + TO_UINT64(rc_fail_on_get), + true /*Add HB SW Callout*/ ); + + err->collectTrace(SBE_COMP_NAME); + } + + + TRACUCOMP( g_trac_sbe, + EXIT_MRK"resolveImageHBBaddr() - o_imageWasUpdated = %d", + o_imageWasUpdated); + + return err; +} + +#ifdef CONFIG_BMC_IPMI +///////////////////////////////////////////////////////////////////// +void sbePreShutdownIpmiCalls( void ) +{ + errlHndl_t err = NULL; + + TRACFCOMP( g_trac_sbe, ENTER_MRK"sbePreShutdownIpmiCalls"); + + do{ + uint16_t count = 0; + SENSOR::RebootCountSensor l_sensor; + + // Read reboot count sensor + err = l_sensor.getRebootCount(count); + if ( err ) + { + TRACFCOMP( g_trac_sbe, + ERR_MRK"sbePreShutdownIpmiCalls: " + "FAIL Reading Reboot Sensor Count. " + "Committing Error Log rc=0x%.4X eid=0x%.8X " + "plid=0x%.8X, but continuing shutdown", + err->reasonCode(), + err->eid(), + err->plid()); + err->collectTrace(SBE_COMP_NAME); + errlCommit( err, SBE_COMP_ID ); + + // No Break - Still Do Watchdog Timer Call + } + else + { + // Increment Reboot Count Sensor + count++; + TRACFCOMP( g_trac_sbe, + INFO_MRK"sbePreShutdownIpmiCalls: " + "Writing Reboot Sensor Count=%d", count); + + err = l_sensor.setRebootCount( count ); + if ( err ) + { + TRACFCOMP( g_trac_sbe, + ERR_MRK"sbePreShutdownIpmiCalls: " + "FAIL Writing Reboot Sensor Count to %d. " + "Committing Error Log rc=0x%.4X eid=0x%.8X " + "plid=0x%.8X, but continuing shutdown", + count, + err->reasonCode(), + err->eid(), + err->plid()); + err->collectTrace(SBE_COMP_NAME); + errlCommit( err, SBE_COMP_ID ); + + // No Break - Still Do Watchdog Timer Call + } + } + + // @todo RTC 124679 - Remove Once BMC Monitors Shutdown Attention + // Set Watchdog Timer To 10 seconds + const uint16_t SET_WD_TIMER_10_SECS = 10; + TRACFCOMP( g_trac_sbe,"sbePreShutdownIpmiCalls: " + "Set Watch Dog Timer To %d Seconds", + SET_WD_TIMER_10_SECS); + + err = IPMIWATCHDOG::setWatchDogTimer(SET_WD_TIMER_10_SECS); + if(err) + { + TRACFCOMP( g_trac_sbe, + ERR_MRK"sbePreShutdownIpmiCalls: " + "FAIL Setting Watch Dog Timer to %d seconds. " + "Committing Error Log rc=0x%.4X eid=0x%.8X " + "plid=0x%.8X, but continuing shutdown", + SET_WD_TIMER_10_SECS, + err->reasonCode(), + err->eid(), + err->plid()); + + err->collectTrace(SBE_COMP_NAME); + errlCommit(err, SBE_COMP_ID ); + } + + }while(0); + + TRACFCOMP( g_trac_sbe, EXIT_MRK"sbePreShutdownIpmiCalls"); + + return; +} +#endif // CONFIG_BMC_IPMI + + +} //end SBE Namespace diff --git a/src/usr/sbe/sbe_resolve_sides.H b/src/usr/sbe/sbe_resolve_sides.H new file mode 100644 index 000000000..42f727ae6 --- /dev/null +++ b/src/usr/sbe/sbe_resolve_sides.H @@ -0,0 +1,259 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/sbe/sbe_resolve_sides.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +#ifndef __SBE_SBE_RESOLVE_SIDES_H +#define __SBE_SBE_RESOLVE_SIDES_H + + +#include <stdint.h> +#include <builtins.h> +#include <errl/errlentry.H> +#include <pnor/pnorif.H> +#include <util/align.H> +#include <vmmconst.h> +#include <targeting/common/targetservice.H> +#include <i2c/eepromif.H> +#include "sbe_update.H" + +namespace SBE +{ + /******************************************/ + /* Constants */ + /******************************************/ + + // This seeprom is a candidate to be READ_ONLY (ie, not updated) + const PNOR::sbeSeepromSide_t READ_ONLY_SEEPROM = PNOR::SBE_SEEPROM1; + + // Used to keep SBE Seeproms in sync with EEPROM::eeprom_chip_types_t + const EEPROM::eeprom_chip_types_t sbe_side_sync[2] = + { EEPROM::SBE_PRIMARY, + EEPROM::SBE_BACKUP }; + + /******************************************/ + /* Enums */ + /******************************************/ + + // Actions can be combined + enum + { + NO_ACTIONS = 0x00000000, + REIPL = 0x00000001, + + // Use PNOR::ALTERNATE SideId for HBB Address info + USE_PNOR_ALT_SIDE = 0x00000002, + + // NOTE: These next 2 values are mutually exclusive + CHECK_WORKING_HBB = 0x00000010, + COPY_READ_ONLY_TO_WORKING = 0x00000020, + }; + + /******************************************/ + /* Structs */ + /******************************************/ + struct sbeResolveState_t + { + + // Target Information + TARGETING::Target* tgt; + + PNOR::sbeSeepromSide_t cur_side; // aka 'booted' side + PNOR::sbeSeepromSide_t alt_side; // non-booted/non-cur side + PNOR::sbeSeepromSide_t update_side; // side to be updated + + // Info from PNOR + PNOR::SideId pnor_sideId; + char pnor_side; /**< name of the side either A or B */ + bool pnor_isGolden; /**< True if side is golden */ + bool pnor_hasOtherSide; /**< True if a valid alternate side exists*/ + + uint32_t actions; + + // Constructor to default certain values + sbeResolveState_t() : + tgt(NULL), cur_side(PNOR::SBE_SEEPROM_INVALID), + alt_side(PNOR::SBE_SEEPROM_INVALID), + update_side(PNOR::SBE_SEEPROM_INVALID), + pnor_sideId(PNOR::WORKING), + pnor_side(NULL), + pnor_isGolden(false), pnor_hasOtherSide(false), + actions(NO_ACTIONS) + {} + + }; + + + /******************************************/ + /* Functions -- High Level Functions */ + /******************************************/ + + /** + * @brief Collects SBE Side Information for a specifc target + * + * @param[io/out] io_sideState Struct containing SBE State of the target + * + * @return errlHndl_t Error log handle on failure. + */ + errlHndl_t getSideState(sbeResolveState_t& io_sideState); + + /** + * @brief Analyze and Determine Update Actions for a specific target + * + * @param[io/out] io_sideState Struct containing SBE State of the target + * + * @return errlHndl_t Error log handle on failure. + */ + errlHndl_t getSideActions(sbeResolveState_t& io_sideState); + + /** + * @brief Performs the Update Actions for a specific target + * + * @param[io/out] io_sideState Struct containing SBE State of the target + * + * @return errlHndl_t Error log handle on failure. + */ + errlHndl_t performSideActions(sbeResolveState_t& io_sideState); + + + + /******************************************/ + /* Functions -- System Access */ + /******************************************/ + + + /** + * @brief Read SBE Image from SBE Seeprom + * + * @param[in] i_target Target processor + * + * @param[out] o_imgPtr Pointer to SBE image in memory + * Memory for this pointer is expected to be + * pre-alloacted + * NOTE: ECC is handled internally in this + * function. io_imgPtr points to non-ECC image + * + * @param[in] i_side Seeprom Side to access + * + * @param[in] o_image_size The size of the image (non-ECC) + * + * @param[in] o_version SBE Version struct from seeprom (non-ECC) + * + * @return errlHndl_t Error log handle on failure. + */ + errlHndl_t readSbeImage(TARGETING::Target* i_target, + void* o_imgPtr, + PNOR::sbeSeepromSide_t i_side, + size_t& o_image_size, + sbeSeepromVersionInfo_t& o_version); + + /** + * @brief Write SBE Image from SBE Seeprom + * + * @param[in] i_target Target processor + * + * @param[in] i_imgPtr Pointer to SBE image in memory + * Memory for this pointer is expected to be + * pre-alloacted + * NOTE: ECC is handled internally in this function + * i_imgPtr points to non-ECC image + * + * @param[in] i_side Seeprom Side to access + * + * @param[in] i_image_size Size of image to write (non-ECC) + * + * @param[in] io_version SBE Version struct to write (non-ECC) + * NOTE: data_crc updated in this function + * + * @return errlHndl_t Error log handle on failure. + */ + errlHndl_t writeSbeImage(TARGETING::Target* i_target, + void* i_imgPtr, + PNOR::sbeSeepromSide_t i_side, + size_t i_image_size, + sbeSeepromVersionInfo_t& io_version); + + + /** + * @brief Read SBE Image Header from SBE Seeprom and gets the + * Image size from the heaser + * + * @param[in] i_target Target processor + * + * @param[out] i_imgPtr Pointer to pre-allocated memory to be used + * for different operations + * + * @param[in] i_side Seeprom Side to access + * + * @param[in] o_image_size The size of the image (non-ECC) + * + * @return errlHndl_t Error log handle on failure. + */ + errlHndl_t getSbeImageSize(TARGETING::Target* i_target, + void* i_imgPtr, + PNOR::sbeSeepromSide_t i_side, + size_t& o_image_size); + + + + + /******************************************/ + /* Functions -- Helper Functions */ + /******************************************/ + + /** + * @brief Check and Update (if necessary) the HBB Address MMIO offset + * in a customized SBE Image for the current Processor + * + * @param[in] i_target Target processor to customize + * + * @param[in/out] io_imgPtr Pointer to SBE image in memory + * Memory for this pointer is expected to be + * pre-alloacted + * + * @param[in] i_side Seeprom Side to access + * + * @param[in] i_pnorSideId PNOR side to get information for + * + * @param[out] o_imageWasUpdated Set to true if Image was updated; + * otherwise false + * + * @return errlHndl_t Error log handle on failure. + */ + errlHndl_t resolveImageHBBaddr(TARGETING::Target* i_target, + void* io_imgPtr, + PNOR::sbeSeepromSide_t i_side, + PNOR::SideId i_pnorSideId, + bool& o_imageWasUpdated); + +#ifdef CONFIG_BMC_IPMI + /** + * @brief Performs any necessary IPMI calls before shutting down the system + * + * @return void Any generated Error Logs will be commited before the + * function returns + */ + void sbePreShutdownIpmiCalls( void ); +#endif + +} //end namespace SBE +#endif diff --git a/src/usr/sbe/sbe_update.C b/src/usr/sbe/sbe_update.C index 97a048426..562798b20 100644 --- a/src/usr/sbe/sbe_update.C +++ b/src/usr/sbe/sbe_update.C @@ -50,6 +50,7 @@ #include <sbe/sbeif.H> #include <sbe/sbereasoncodes.H> #include "sbe_update.H" +#include "sbe_resolve_sides.H" // fapi support #include <fapi.H> @@ -112,6 +113,25 @@ namespace SBE do{ +#ifdef CONFIG_NO_SBE_UPDATES + TRACFCOMP( g_trac_sbe, INFO_MRK"updateProcessorSbeSeeproms() - " + "SBE updates not configured"); + break; +#endif + +#ifdef CONFIG_SBE_UPDATE_SEQUENTIAL + // Check if FSP-services are enabled and if we're running in simics + if ( !INITSERVICE::spBaseServicesEnabled() && + !Util::isSimicsRunning() ) + { + assert (false, "resolveProcessorSbeSeeproms() - " + "SBE_UPDATE_SEQUENTIAL mode, but FSP-services are not " + "enabled - Invalid Configuration"); + } + // else - continue on +#endif + + // Get Target Service, and the system target. TargetService& tS = targetService(); TARGETING::Target* sys = NULL; @@ -204,11 +224,6 @@ namespace SBE err = NULL; } -#ifdef CONFIG_NO_SBE_UPDATES - TRACFCOMP( g_trac_sbe, INFO_MRK"updateProcessorSbeSeeproms() - " - "SBE updates not configured"); - break; -#endif for(uint32_t i=0; i<procList.size(); i++) { @@ -277,7 +292,6 @@ namespace SBE /**********************************************/ if ((err == NULL) && (sbeState.update_actions & DO_UPDATE)) { - err = performUpdateActions(sbeState); if (err) { @@ -328,7 +342,6 @@ namespace SBE } //end of Target for loop collecting each target's SBE State - /**************************************************************/ /* Perform System Operation */ /**************************************************************/ @@ -355,7 +368,7 @@ namespace SBE } #ifdef CONFIG_BMC_IPMI - // @todo RTC 120734 reset system's reboot count via IPMI sensor + sbePreShutdownIpmiCalls(); #endif TRACFCOMP( g_trac_sbe, @@ -685,14 +698,15 @@ namespace SBE do{ - // @todo RTC 120734 - before customizing, ensure correct HBB address - // is set in the necessary attribute - // cast OUR type of target to a FAPI type of target. const fapi::Target l_fapiTarg(fapi::TARGET_TYPE_PROC_CHIP, (const_cast<TARGETING::Target*>(i_target))); + // NOTE: The p8_xip_customize_procedure uses SBE_IMAGE_OFFSET + // attribute for HBB address value. Purpsely leaving this + // attribute as-is for now and will do the check for HBB address + // later. // The p8_xip_customize() procedure tries to include as much core // information as possible, but is limited by SBE Image size @@ -871,7 +885,6 @@ namespace SBE HWAS::SRCI_PRIORITY_HIGH ); } - }while(0); TRACUCOMP( g_trac_sbe, @@ -1715,6 +1728,26 @@ namespace SBE // The Customized Image For This Target Still Resides In // The SBE Update VMM Space: SBE_IMG_VADDR = VMM_VADDR_SBE_UPDATE +#ifdef CONFIG_SBE_UPDATE_INDEPENDENT + // Ensure HBB address value in the customized image is correct + // for this side + bool imageWasUpdated=false; + err = resolveImageHBBaddr ( io_sbeState.target, + reinterpret_cast<void*>(SBE_IMG_VADDR), + ((io_sbeState.seeprom_side_to_update == + EEPROM::SBE_PRIMARY ) ? + PNOR::SBE_SEEPROM0 : + PNOR::SBE_SEEPROM1 ), + PNOR::WORKING, + imageWasUpdated ); + + if (imageWasUpdated == true ) + { + TRACUCOMP( g_trac_sbe, ERR_MRK"updateSeepromSide() - " + "HBB Address's MMIO Offset Updated in Image"); + } + +#endif // Inject ECC // clear out back half of page block to use as temp space @@ -1941,7 +1974,6 @@ namespace SBE io_sbeState.seeprom_0_ver.data_crc, isSimics_check); } - /**************************************************************/ /* Compare SEEPROM 1 with PNOR and Customized Image CRC -- */ /* -- dirty or clean? */ @@ -2153,22 +2185,55 @@ namespace SBE #ifdef CONFIG_SBE_UPDATE_INDEPENDENT // The 2 SBE SEEPROMs are independent of each other - // Determine if PNOR is 1- or 2-sided and if there is a - // GOLDEN boot involved + // Determine if PNOR is 1- or 2-sided and if the current + // Seeprom is pointing at PNOR's GOLDEN side + + PNOR::SideId tmp_side = PNOR::WORKING; + PNOR::SideInfo_t pnor_side_info; + err = PNOR::getSideInfo (tmp_side, pnor_side_info); + if ( err ) + { + TRACFCOMP( g_trac_sbe, ERR_MRK + "SBE Update() - Error returned from " + "PNOR::getSideInfo() rc=0x%.4X, Target UID=0x%X", + err->reasonCode(), + TARGETING::get_huid(io_sbeState.target)); + break; + } -#ifdef CONFIG_PNOR_TWO_SIDE_SUPPORT + TRACUCOMP( g_trac_sbe, INFO_MRK"SBE Update tgt=0x%X: PNOR Info: " + "side-%c, sideId=0x%X, isGolden=%d, hasOtherSide=%d", + TARGETING::get_huid(io_sbeState.target), + pnor_side_info.side, pnor_side_info.id, + pnor_side_info.isGolden, pnor_side_info.hasOtherSide); - // @todo RTC 120734 - ask PNOR if we are in "GOLDEN" mode, - // which would mean that we are booting off the the GOLDEN - // SBE SEEPROM which corresponds to the GOLDEN side of PNOR -/* - if (true) + if ( pnor_side_info.isGolden == true ) { // If true, nothing to do (covered in istep 6 function) l_actions = CLEAR_ACTIONS; TRACFCOMP( g_trac_sbe, INFO_MRK"SBE Update tgt=0x%X: " - "Booting GOLDEN SBE SEEPROM in PNOR 2-sided Mode. " + "Booting READ_ONLY SEEPROM pointing at PNOR's " + "GOLDEN side. No updates for cur side=%d. Continue " + "IPL. (sit=0x%.2X, act=0x%.8X flags=0x%.2X)", + TARGETING::get_huid(io_sbeState.target), + io_sbeState.cur_seeprom_side, + i_system_situation, l_actions, + io_sbeState.mvpdSbKeyword.flags); + break; + } + + else if ( ( pnor_side_info.hasOtherSide == false ) && + ( io_sbeState.cur_seeprom_side == READ_ONLY_SEEPROM ) ) + { + // Even though current seeprom is not pointing at PNOR's + // GOLDEN side, treat like READ_ONLY if booting from READ_ONLY + // seeprom and and PNOR does not have another side - No Update + // (ie, Palmetto configuration) + l_actions = CLEAR_ACTIONS; + + TRACFCOMP( g_trac_sbe, INFO_MRK"SBE Update tgt=0x%X: " + "Treating cur like READ_ONLY SBE SEEPROM. " "No updates for cur side=%d. Continue IPL. " "(sit=0x%.2X, act=0x%.8X flags=0x%.2X)", TARGETING::get_huid(io_sbeState.target), @@ -2179,22 +2244,14 @@ namespace SBE } else // proceed to update this side { + // proceed to update this side TRACUCOMP( g_trac_sbe, INFO_MRK"SBE Update tgt=0x%X: " - "NOT Booting GOLDEN SBE SEEPROM in PNOR 2-sided " - "mode. Checking for update on cur side=%d ", + "NOT Booting READ_ONLY SEEPROM. Check for update " + "on cur side=%d ", TARGETING::get_huid(io_sbeState.target), io_sbeState.cur_seeprom_side) } -*/ -#else - // @todo RTC 120734 - check this assumption - // Assume that we're only checking/updating the current side - TRACUCOMP( g_trac_sbe, INFO_MRK"SBE Update tgt=0x%X: " - "PNOR 1-sided so only check for update on cur side=%d", - TARGETING::get_huid(io_sbeState.target), - io_sbeState.cur_seeprom_side); -#endif // Check for clean vs. dirty only on cur side if ( i_system_situation & SITUATION_CUR_IS_DIRTY ) @@ -2203,6 +2260,7 @@ namespace SBE l_actions |= IPL_RESTART; l_actions |= DO_UPDATE; l_actions |= UPDATE_SBE; + l_actions |= UPDATE_MVPD; // even though flags byte not updated // Set Update side to cur io_sbeState.seeprom_side_to_update = |