diff options
| author | Nick Bofferding <bofferdn@us.ibm.com> | 2019-03-13 15:22:30 -0500 |
|---|---|---|
| committer | Daniel M. Crowell <dcrowell@us.ibm.com> | 2019-03-20 09:44:13 -0500 |
| commit | 810394f870786da606ef3179315e6cbdaa35627b (patch) | |
| tree | f3727c8ea6bcbe91033e9f759dc44ce585a91ec1 /src | |
| parent | af6712fe5c035e7e61ea67a6f86f585b8ee1d51b (diff) | |
| download | talos-hostboot-810394f870786da606ef3179315e6cbdaa35627b.tar.gz talos-hostboot-810394f870786da606ef3179315e6cbdaa35627b.zip | |
UCD flash update invoker
Implements the main algorithm for finding applicable UCDs to perform flash
update on and walking the UCD flash image table of contents to find the
image associated with a UCD. Also adds a check to skip the update if
simics is running.
RTC: 201991
Change-Id: Ib35abec2f0a2ed22ae8d41a2acecd146f699bc43
Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/73484
Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com>
Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com>
Reviewed-by: Ilya Smirnov <ismirno@us.ibm.com>
Reviewed-by: Matthew Raybuck <matthew.raybuck@ibm.com>
Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot@us.ibm.com>
Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src')
| -rw-r--r-- | src/include/usr/isteps/istep_reasoncodes.H | 2 | ||||
| -rw-r--r-- | src/include/usr/isteps/ucd/updateUcdFlash.H | 24 | ||||
| -rw-r--r-- | src/include/usr/ucd/ucd_reasoncodes.H | 8 | ||||
| -rw-r--r-- | src/include/usr/util/utillidmgr.H | 1 | ||||
| -rw-r--r-- | src/usr/isteps/istep21/call_update_ucd_flash.C | 110 | ||||
| -rw-r--r-- | src/usr/isteps/ucd/updateUcdFlash.C | 502 |
6 files changed, 598 insertions, 49 deletions
diff --git a/src/include/usr/isteps/istep_reasoncodes.H b/src/include/usr/isteps/istep_reasoncodes.H index 09b12abdc..7aa3abc5e 100644 --- a/src/include/usr/isteps/istep_reasoncodes.H +++ b/src/include/usr/isteps/istep_reasoncodes.H @@ -66,6 +66,7 @@ namespace ISTEP MOD_APPLY_HCODE_GEN_CPU_REGS = 0x23, MOD_GET_LANEMASK_FROM_HX_KEYWORD = 0x24, MOD_MSS_SCRUB = 0x25, + MOD_CALL_UPDATE_UCD_FLASH = 0x26, }; /** @@ -138,6 +139,7 @@ namespace ISTEP RC_INVALID_HX_KEYWORD_DATA = ISTEP_COMP_ID | 0x4C, RC_PNOR_IPMI_NOT_ENABLED = ISTEP_COMP_ID | 0x4D, RC_SLAVE_CORE_WAKEUP_ERROR = ISTEP_COMP_ID | 0x4E, + RC_UCD_IMG_NOT_IN_CONTAINER = ISTEP_COMP_ID | 0x4F, }; }; diff --git a/src/include/usr/isteps/ucd/updateUcdFlash.H b/src/include/usr/isteps/ucd/updateUcdFlash.H index a1487e78d..2cc7e8e84 100644 --- a/src/include/usr/isteps/ucd/updateUcdFlash.H +++ b/src/include/usr/isteps/ucd/updateUcdFlash.H @@ -27,6 +27,7 @@ #define __UPDATE_UCD_FLASH_H #include <targeting/common/target.H> +#include <util/utilmem.H> #include <errl/errlentry.H> namespace POWER_SEQUENCER @@ -39,6 +40,29 @@ namespace UCD // UCD series { /** + * @brief Applies UCD data flash image updates (if needed) to the requested + * UCDs + * + * @param[in] i_powerSequencers Fixed vector of PowerSequencer targets to + * update flash image on + * @param[in] i_image Reference to UtilMem buffer holding the UCD flash image + * contents (including header, TOC entries, and flash images). Note: the + * implementation will not alter the buffer content, and will seek back + * to the beginning before handing control back. + * + * @return errlHndl_t Error log handle + * @retval nullptr Successfully took action against all requested UCDs. It's + * possible an individual UCD update failed, in which case the error is + * committed. + * @retval !nullptr Failed to take action against one or more requested UCDs. + * Typically this is due to a firmware problem. Handle points to valid + * error log + */ +errlHndl_t updateAllUcdFlashImages( + const TARGETING::TargetHandleList& i_powerSequencers, + UtilMem& i_image); + +/** * @brief Updates a UCD target's flash image * * @param[in] i_pUcd UCD's target; must not be nullptr diff --git a/src/include/usr/ucd/ucd_reasoncodes.H b/src/include/usr/ucd/ucd_reasoncodes.H index bfa18397f..4e7cc9841 100644 --- a/src/include/usr/ucd/ucd_reasoncodes.H +++ b/src/include/usr/ucd/ucd_reasoncodes.H @@ -32,13 +32,19 @@ namespace UCD_RC enum UcdModuleId { - MOD_UCD_INIT = 0x01, + MOD_UCD_INIT = 0x01, + MOD_UPDATE_ALL_UCD_FLASH_IMAGES = 0x02, }; enum UcdReasonCode { RC_DEVICE_READ_UNEXPECTED_SIZE_DEVICE_ID = UCD_COMP_ID | 0x01, RC_DEVICE_READ_UNEXPECTED_SIZE_MFR_REVISION = UCD_COMP_ID | 0x02, + UCD_INVALID_EYECATCHER = UCD_COMP_ID | 0x03, + UCD_INVALID_MAJOR_VER = UCD_COMP_ID | 0x04, + UCD_TOC_ENTRY_TOO_SMALL = UCD_COMP_ID | 0x05, + UCD_UNSUPPORTED_DEVICE_ID = UCD_COMP_ID | 0x06, + UCD_EOF = UCD_COMP_ID | 0x07, }; }; // namespace UCD diff --git a/src/include/usr/util/utillidmgr.H b/src/include/usr/util/utillidmgr.H index 64e77cfd3..e78eba133 100644 --- a/src/include/usr/util/utillidmgr.H +++ b/src/include/usr/util/utillidmgr.H @@ -63,6 +63,7 @@ enum LidId TARGETING_BINARY_LIDID = 0x81e00630, NVDIMM_16GB_LIDID = 0x81e00640, NVDIMM_32GB_LIDID = 0x81e00641, + UCD_LIDID = 0x81e00650, INVALID_LIDID = 0xFFFFFFFF }; diff --git a/src/usr/isteps/istep21/call_update_ucd_flash.C b/src/usr/isteps/istep21/call_update_ucd_flash.C index b2fb9e75d..31fe66d5f 100644 --- a/src/usr/isteps/istep21/call_update_ucd_flash.C +++ b/src/usr/isteps/istep21/call_update_ucd_flash.C @@ -26,6 +26,7 @@ #include <errl/errlentry.H> #include <trace/interface.H> #include <initservice/initserviceif.H> +#include <util/utillidmgr.H> #include <util/utilmclmgr.H> #include <errl/errlmanager.H> #include <hbotcompid.H> @@ -35,6 +36,9 @@ #include <secureboot/trustedbootif.H> #include <targeting/common/commontargeting.H> #include <targeting/common/utilFilter.H> +#include <util/utilmem.H> +#include <util/misc.H> +#include <isteps/istep_reasoncodes.H> #include "call_update_ucd_flash.H" namespace POWER_SEQUENCER @@ -56,7 +60,8 @@ void call_update_ucd_flash(void) do { // Update UCD flash images, if needed - if (INITSERVICE::spBaseServicesEnabled()) + if (INITSERVICE::spBaseServicesEnabled() && + !Util::isSimicsRunning()) { TARGETING::TargetHandleList powerSequencers; TARGETING::getAllAsics(powerSequencers, @@ -66,6 +71,11 @@ void call_update_ucd_flash(void) // Continue if no functional power sequencers. On MPIPL, // previously bad power sequencers will be ignored, and // Hostboot will not generate new errors. + TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,INFO_MRK + "call_update_ucd_flash: No functional UCD9090 or UCD90120A " + "power sequencers found to update"); + + // Done with update flow, no error break; } @@ -75,11 +85,28 @@ void call_update_ucd_flash(void) pError = mclManager.processSingleComponent(MCL::g_UcdCompId,info); if(pError) { + TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,ERR_MRK + "call_update_ucd_flash: Failed in call to " + "processSingleComponent() for UCD9090 " + "component ID"); + + // Failed update flow, commit at end of step break; } - // Make sure TPM queue is flushed before doing any I2C operations - TRUSTEDBOOT::flushTpmQueue(); + // Make sure TPM queue is flushed before doing any I2C operations, since + // loading via MCL drives PCR extends into the TPM, and TPM can share + // the same I2C bus as UCD devices + pError = TRUSTEDBOOT::flushTpmQueue(); + if(pError) + { + TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,ERR_MRK + "call_update_ucd_flash: Failed in call to " + "TRUSTEDBOOT::flushTpmQueue()"); + + // Failed update flow, commit at end of step + break; + } // Dump some LID info for(const auto& lid : info.lidIds) @@ -90,40 +117,69 @@ void call_update_ucd_flash(void) TRACFBIN(ISTEPS_TRACE::g_trac_isteps_trace,"LID",lid.vAddr,64); } - // Update every power sequencer's data flash - for(auto powerSequencer : powerSequencers) + // Locate the UCD flash image (ignore signature LID and any other LIDs + // in the container) + const auto lidItr = + std::find_if( + info.lidIds.begin(),info.lidIds.end(), + [](const MCL::LidInfo& i_lid) + { + return (i_lid.id == static_cast<decltype(i_lid.id)>( + Util::UCD_LIDID)); + }); + if(lidItr == info.lidIds.end()) + { + TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,ERR_MRK + "call_update_ucd_flash: Failed to locate UCD flash image LID " + "within UCD9090 component"); + + /*@ + * @errortype + * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE + * @reasoncode ISTEP::RC_UCD_IMG_NOT_IN_CONTAINER + * @moduleid ISTEP::MOD_CALL_UPDATE_UCD_FLASH + * @userdata1 UCD LID ID + * @devdesc The UCD content LID was not found within the UCD + * container + * @custdesc Unexpected IPL firmware data load error + */ + pError = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + ISTEP::MOD_CALL_UPDATE_UCD_FLASH, + ISTEP::RC_UCD_IMG_NOT_IN_CONTAINER, + Util::UCD_LIDID, + 0, + ERRORLOG::ErrlEntry::ADD_SW_CALLOUT); + + // Failed update flow, commit at end of step + break; + } + + // Use a UtilMem buffer to prevent sailing off end of the UCD flash + // data. Callee will seek back to beginning of content + UtilMem image(lidItr->vAddr,lidItr->size); + + pError = updateAllUcdFlashImages(powerSequencers,image); + if(pError) { - do { - - const auto i2cInfo = - powerSequencer->getAttr<TARGETING::ATTR_I2C_CONTROL_INFO>(); - const auto model = powerSequencer->getAttr<TARGETING::ATTR_MODEL>(); - - TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace, INFO_MRK - "Found functional power sequencer: HUID = 0x%08X, " - "Model = 0x%08X, e/p/a = %d/%d/0x%02X", - TARGETING::get_huid(powerSequencer), - model, - i2cInfo.engine, i2cInfo.port, i2cInfo.devAddr); - - // @TODO RTC 201990 add flash update algorithm - // - // errlHndl_t updateUcdFlash( - // TARGETING::Target* i_pUcd, - // const void* i_pFlashImage); - - } while(0); + TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,ERR_MRK + "call_update_ucd_flash: Failed in call to " + "updateAllUcdFlashImages"); + break; } // Destructor automatically unloads the UCD flash binary - } + + } // End valid machine and not-simcis for UCD updates } while(0); if(pError) { TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace, ERR_MRK - "call_update_ucd_flash failed"); + "call_update_ucd_flash: step failed"); + pError->collectTrace(UCD_COMP_NAME); + pError->collectTrace(ISTEP_COMP_NAME); errlCommit(pError, ISTEP_COMP_ID); } diff --git a/src/usr/isteps/ucd/updateUcdFlash.C b/src/usr/isteps/ucd/updateUcdFlash.C index 1211b460b..0d7335fb8 100644 --- a/src/usr/isteps/ucd/updateUcdFlash.C +++ b/src/usr/isteps/ucd/updateUcdFlash.C @@ -42,6 +42,9 @@ #include <trace/interface.H> #include <string.h> #include <hbotcompid.H> +#include <util/utilmem.H> +#include <util/utilstream.H> +#include <errl/errludstring.H> namespace POWER_SEQUENCER { @@ -59,8 +62,8 @@ private: enum DEVICE_OP_LENGTH : size_t { - MFR_REVISION_SIZE = 12, - DEVICE_ID_SIZE = 32, + MFR_REVISION_MAX_SIZE = 12, + DEVICE_ID_MAX_SIZE = 32, }; enum COMMAND : uint8_t @@ -144,7 +147,7 @@ public: do { - char deviceIdBuffer[DEVICE_ID_SIZE]{}; + char deviceIdBuffer[DEVICE_ID_MAX_SIZE]{}; // Get the I2C info for this UCD. const auto i2cInfo = iv_pUcd-> @@ -179,16 +182,16 @@ public: break; } - // Verify that the buffer is the size the we expected to get. - if (size != DEVICE_ID_SIZE) + // Verify that the buffer is not larger than the MAX_SIZE we expect + // (It is possible to receive a smaller size than MAX_SIZE) + if (size > DEVICE_ID_MAX_SIZE) { TRACFCOMP(g_trac_ucd, ERR_MRK"Ucd::Initialize(): Read from " - "UCD 0x%.8X returned " - "size different than requested. " + "UCD 0x%.8X for DEVICE_ID returned " + "size larger than expected. " "Actual %d, expected %d", get_huid(iv_pUcd), - size, DEVICE_ID_SIZE); - + size, DEVICE_ID_MAX_SIZE); /*@ * @errortype * @severity ERRL_SEV_UNRECOVERABLE @@ -206,7 +209,7 @@ public: ERRORLOG::ERRL_SEV_UNRECOVERABLE, UCD_RC::MOD_UCD_INIT, UCD_RC::RC_DEVICE_READ_UNEXPECTED_SIZE_DEVICE_ID, - TWO_UINT32_TO_UINT64(DEVICE_ID_SIZE, size), + TWO_UINT32_TO_UINT64(DEVICE_ID_MAX_SIZE, size), get_huid(iv_pUcd) ); @@ -224,9 +227,9 @@ public: } // Verify there is a null terminator at the end of the buffer. - if (deviceIdBuffer[DEVICE_ID_SIZE-1] != '\0') + if (deviceIdBuffer[DEVICE_ID_MAX_SIZE-1] != '\0') { - deviceIdBuffer[DEVICE_ID_SIZE-1] = '\0'; + deviceIdBuffer[DEVICE_ID_MAX_SIZE-1] = '\0'; } // Since the format of the buffer will be: Device Id|..|..|.. @@ -256,10 +259,10 @@ public: uint16_t value; // The MFR Revision represented as ASCII characters excluding // null terminator. - uint8_t str[MFR_REVISION_SIZE]; + uint8_t str[MFR_REVISION_MAX_SIZE]; } mfrBuf; - size = MFR_REVISION_SIZE; + size = MFR_REVISION_MAX_SIZE; // Read the MFR revision from the UCD device. err = deviceOp(DeviceFW::READ, @@ -284,16 +287,16 @@ public: break; } - // Verify that the buffer is the size the we expected to get. - if (size != MFR_REVISION_SIZE) + // Verify that the buffer is not larger than the MAX_SIZE we expect + // (It is possible to receive a smaller size than MAX_SIZE) + if (size > MFR_REVISION_MAX_SIZE) { TRACFCOMP(g_trac_ucd, ERR_MRK"Ucd::Initialize(): Read from UCD " - "0x%.8X returned " - "size different than requested. " + "0x%.8X for MFR Revision returned " + "size larger than expected. " "Actual %d, expected %d", get_huid(iv_pUcd), - size, MFR_REVISION_SIZE); - + size, MFR_REVISION_MAX_SIZE); /*@ * @errortype * @severity ERRL_SEV_UNRECOVERABLE @@ -311,7 +314,7 @@ public: ERRORLOG::ERRL_SEV_UNRECOVERABLE, UCD_RC::MOD_UCD_INIT, UCD_RC::RC_DEVICE_READ_UNEXPECTED_SIZE_MFR_REVISION, - TWO_UINT32_TO_UINT64(MFR_REVISION_SIZE, size), + TWO_UINT32_TO_UINT64(MFR_REVISION_MAX_SIZE, size), get_huid(iv_pUcd)); err->addI2cDeviceCallout(i2cMaster, @@ -363,6 +366,463 @@ public: }; +/** + * @brief Header for the UCD flash image content + */ +struct TocHeader +{ + uint64_t eyecatcher; //< Eyecatcher, see TOC_CONSTS::EYECATCHER + uint32_t majorVersion; //< Major header version; increases for incompatible + //< changes + uint32_t minorVersion; //< Minor version; increases for compatible changes + //< relative to a major version + uint32_t tocEntries; //< Number of TOC entries + uint32_t tocEntrySize; //< Size of TOC entry in bytes + uint32_t tocOffset; //< Offset of 0th TOC entry from beginning of + //< flash image + + /** + * @brief TOC header constructor + */ + TocHeader() + : eyecatcher(0), + majorVersion(0), + minorVersion(0), + tocEntries(0), + tocEntrySize(0), + tocOffset(0) + { + } +}; + +/** + * @brief Enumeration of UCD sub-flash image types + */ +enum IMAGE_TYPE : uint8_t +{ + DATA_FLASH_IMAGE = 0x00, ///< UCD data sub-flash image + UNKNOWN = 0xFF, ///< Unknown UCD sub-flash image type +}; + +/** + * @brief Miscellaneous constants used by the UCD flash image TOC and TOC + * entries + */ +enum TOC_CONSTS : uint64_t +{ + EYECATCHER = 0x554344464C534800ULL, //< UCDFLSH + 0x00 + DEVICE_ID_NULL_BYTE_INDEX = 31, //< Max size of device ID not including NULL + DEVICE_ID_MAX_SIZE = DEVICE_ID_NULL_BYTE_INDEX+1, //< Max size of + //< device ID + CURRENT_VERSION = 0x01, //< First supported version is 0x01 +}; + +/** + * @brief Table of contents entry used by UCD flash image + */ +struct TocEntry +{ + char deviceId[DEVICE_ID_MAX_SIZE]; //< NULL terminated ASCII device ID + //< string + IMAGE_TYPE imageType; //< Type of sub-flash image + uint8_t procPosition; //< Position of processor acting as I2C master + uint8_t i2cEngine; //< Engine driving the I2C device relative to + //< the I2C master target + uint8_t i2cPort; //< Port driving the I2C device relative to its + //< engine + uint8_t i2cAddress; //< I2C address the device responds at + uint8_t reserved1; //< Reserved for future use + uint16_t mfrRevision; //< A vendor supplied set of two ASCII + //< bytes which versions the flash content. + //< Hostboot updates the device's flash image + //< whenever the MFR_REVISION of the device differs + //< from the one in the TOC entry. + uint32_t imageOffset; //< Offset of sub-flash image from start of flash + //< image, in bytes + uint32_t imageSize; //< Size of sub-flash image, in bytes + + /** + * TOC entry constructor + */ + TocEntry() + : imageType(UNKNOWN), + procPosition(0), + i2cEngine(0), + i2cPort(0), + i2cAddress(0), + reserved1(0), + mfrRevision(0), + imageOffset(0), + imageSize(0) + { + memset(deviceId,0x00,sizeof(deviceId)); + } +}; + +errlHndl_t updateAllUcdFlashImages( + const TARGETING::TargetHandleList& i_powerSequencers, + UtilMem& i_image) +{ + TRACFCOMP(g_trac_ucd, ENTER_MRK + "updateAllUcdFlashImages: # UCDs = %d", + i_powerSequencers.size()); + + errlHndl_t pError = nullptr; + + do { + + // Read in the critical portions of the header + TocHeader header; + i_image.read(&header.eyecatcher,sizeof(header.eyecatcher)); + i_image >> header.majorVersion >> header.minorVersion; + pError=i_image.getLastError(); + if(pError) + { + TRACFCOMP(g_trac_ucd,ERR_MRK + "updateAllUcdFlashImages: Failed to read enough data from UCD " + "flash image to populate the minor version in the TOC header. " + "Image size reported as %d",i_image.size()); + break; + } + + // Validate eyecatcher, major, minor + if(header.eyecatcher != EYECATCHER) + { + TRACFCOMP(g_trac_ucd,ERR_MRK + "updateAllUcdFlashImages: UCD flash image has bad eyecatcher; " + "Expected 0x%16llX but found 0x%016llX", + EYECATCHER,header.eyecatcher); + /*@ + * @errortype + * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE + * @reasoncode UCD_RC::UCD_INVALID_EYECATCHER + * @moduleid UCD_RC::MOD_UPDATE_ALL_UCD_FLASH_IMAGES + * @userdata1 Expected eyecatcher + * @userdata2 Actual eyecatcher + * @devdesc The UCD flash image's eyecatcher did not match + * the expected value + * @custdesc Unexpected IPL firmware data format error + */ + pError = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + UCD_RC::MOD_UPDATE_ALL_UCD_FLASH_IMAGES, + UCD_RC::UCD_INVALID_EYECATCHER, + EYECATCHER, + header.eyecatcher, + ERRORLOG::ErrlEntry::ADD_SW_CALLOUT); + break; + } + + if(header.majorVersion != CURRENT_VERSION) + { + TRACFCOMP(g_trac_ucd,ERR_MRK + "updateAllUcdFlashImages: UCD flash image version not supported. " + "Image version is 0x%08X but boot firmware only supports 0x%08X", + header.majorVersion, + CURRENT_VERSION); + /*@ + * @errortype + * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE + * @reasoncode UCD_RC::UCD_INVALID_MAJOR_VER + * @moduleid UCD_RC::MOD_UPDATE_ALL_UCD_FLASH_IMAGES + * @userdata1 Current major version supported + * @userdata2 Advertised major version + * @devdesc The UCD flash image's major version number is + * not supported. + * @custdesc Unexpected IPL firmware data format error + */ + pError = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + UCD_RC::MOD_UPDATE_ALL_UCD_FLASH_IMAGES, + UCD_RC::UCD_INVALID_MAJOR_VER, + CURRENT_VERSION, + header.majorVersion, + ERRORLOG::ErrlEntry::ADD_SW_CALLOUT); + break; + } + + // Placeholder for future minor version checks. Currently should + // be able to handle any minor version when major version is 1 + + // Read in the TOC info + i_image >> header.tocEntries >> header.tocEntrySize >> header.tocOffset; + pError=i_image.getLastError(); + if(pError) + { + TRACFCOMP(g_trac_ucd,ERR_MRK + "updateAllUcdFlashImages: Failed to read enough data from UCD " + "flash image to populate full TOC header"); + break; + } + + // Each TOC entry should be at least the size of the entry that major + // version 1 knows about. This code can, however, handle larger entries if + // needed + if(header.tocEntrySize < sizeof(TocEntry)) + { + TRACFCOMP(g_trac_ucd,ERR_MRK + "updateAllUcdFlashImages: TOC entry size %d smaller than minimum " + "of %d", + header.tocEntrySize, sizeof(TocEntry)); + /*@ + * @errortype + * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE + * @reasoncode UCD_RC::UCD_TOC_ENTRY_TOO_SMALL + * @moduleid UCD_RC::MOD_UPDATE_ALL_UCD_FLASH_IMAGES + * @userdata1 Minimum required TOC entry size + * @userdata2 Advertised TOC entry size + * @devdesc The UCD flash image's TOC entry size is smaller + * than expected. + * @custdesc Unexpected IPL firmware data format error + */ + pError = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + UCD_RC::MOD_UPDATE_ALL_UCD_FLASH_IMAGES, + UCD_RC::UCD_TOC_ENTRY_TOO_SMALL, + sizeof(TocEntry), + header.tocEntrySize, + ERRORLOG::ErrlEntry::ADD_SW_CALLOUT); + break; + } + + // Check to see if each power sequencer needs to be updated + for(auto powerSequencer : i_powerSequencers) + { + const auto model = powerSequencer->getAttr<TARGETING::ATTR_MODEL>(); + + do { + + // If we ever let new UCDs into the object model of a type + // not supported, we'd want to introduce some attribute here + // indicating if it supports firmware update/etc. For now + // the model only has UCDs that can be updatable. + + const auto i2cInfo = + powerSequencer->getAttr<TARGETING::ATTR_I2C_CONTROL_INFO>(); + + const char* pMasterPath = i2cInfo.i2cMasterPath.toString(); + TRACFCOMP(g_trac_ucd, INFO_MRK + "updateAllUcdFlashImages: Found functional power sequencer: " + "HUID = 0x%08X, Model = 0x%08X, I2C master = %s, " + "e/p/a = %d/%d/0x%02X", + TARGETING::get_huid(powerSequencer), + model, + pMasterPath, i2cInfo.engine, i2cInfo.port, i2cInfo.devAddr); + free(const_cast<char*>(pMasterPath)); + pMasterPath = nullptr; + + auto pI2cMasterTarget = + TARGETING::targetService().toTarget(i2cInfo.i2cMasterPath); + assert(pI2cMasterTarget != nullptr,"nullptr I2C master target for UCD " + "with HUID of 0x%08X", + TARGETING::get_huid(powerSequencer)); + + const auto position = pI2cMasterTarget-> + getAttr<TARGETING::ATTR_POSITION>(); + + // @TODO RTC 205982 Reset UCD if needed to put it in a good state + + Ucd ucd(powerSequencer); + pError=ucd.initialize(); + if(pError) + { + TRACFCOMP(g_trac_ucd,ERR_MRK + "updateAllUcdFlashImages: Failed in Ucd::initialize() for UCD " + "with HUID of 0x%08X", + TARGETING::get_huid(powerSequencer)); + // @TODO: RTC 205982 mark non-functional, more FFDC + pError->collectTrace(UCD_COMP_NAME); + errlCommit(pError,UCD_COMP_ID); + break; + } + + const auto* const deviceId = ucd.getDeviceId(); + + const auto mfrRevision = ucd.getMfrRevision(); + + i_image.seek(header.tocOffset,UtilStream::START); + + for(size_t entry = 0 ; entry < header.tocEntries; ++entry) + { + bool nextUcd=false; + + do { + + TocEntry tocEntry; + i_image.read(&tocEntry,sizeof(TocEntry)); + pError=i_image.getLastError(); + if(pError) + { + TRACFCOMP(g_trac_ucd,ERR_MRK + "updateAllUcdFlashImages: Failed to read enough data from " + "UCD flash image to populate TOC entry %d. ", + entry); + break; + } + + if( (tocEntry.procPosition != position) + || (tocEntry.i2cEngine != i2cInfo.engine) + || (tocEntry.i2cPort != i2cInfo.port) + || (tocEntry.i2cAddress != i2cInfo.devAddr)) + { + // Did not find the UCD, move on to next TOC entry + break; + } + + // No matter what, last byte has to be 0 to prevent runaway + // parsing + tocEntry.deviceId[DEVICE_ID_NULL_BYTE_INDEX] = 0x00; + + if(strncmp(tocEntry.deviceId,deviceId, + sizeof(tocEntry.deviceId))!=0) + { + TRACFCOMP(g_trac_ucd,ERR_MRK + "updateAllUcdFlashImages: Mismatched device ID for UCD " + "with HUID of 0x%08X. " + "Expected device ID %s, got device ID of %s", + TARGETING::get_huid(powerSequencer), + tocEntry.deviceId,deviceId); + /*@ + * @errortype + * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE + * @reasoncode UCD_RC::UCD_UNSUPPORTED_DEVICE_ID + * @moduleid UCD_RC::MOD_UPDATE_ALL_UCD_FLASH_IMAGES + * @userdata1 UCD's HUID + * @devdesc The UCD device's device ID did not match the + * expected device ID from the UCD sub-flash image. This + * likely implies an escape of new parts into systems + * that are not supported by firmware. UCD will be + * marked as non-functional. + * @custdesc Unsupported device found during firmware IPL + */ + pError = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + UCD_RC::MOD_UPDATE_ALL_UCD_FLASH_IMAGES, + UCD_RC::UCD_UNSUPPORTED_DEVICE_ID, + TARGETING::get_huid(powerSequencer), + 0, + ERRORLOG::ErrlEntry::ADD_SW_CALLOUT); + ERRORLOG::ErrlUserDetailsStringSet deviceIds; + deviceIds.add("Expected device ID",tocEntry.deviceId); + deviceIds.add("Actual device ID",deviceId); + deviceIds.addToLog(pError); + // @TODO: RTC 205982 set non-functional, deconfig + pError->collectTrace(UCD_COMP_NAME); + errlCommit(pError,UCD_COMP_ID); + nextUcd=true; + break; + } + + if(tocEntry.mfrRevision == mfrRevision) + { + TRACFCOMP(g_trac_ucd,INFO_MRK + "updateAllUcdFlashImages: Device has MFR revision of " + "0x%04X which matches incoming UCD sub-flash image " + "version, so inhibit flash update", + mfrRevision); + nextUcd=true; + break; + } + + // Turns out doing the check via UtilMem is not that easy, + // so for feeding the image to the updater, use manual + // calculation + if(tocEntry.imageOffset+tocEntry.imageSize > i_image.size()) + { + TRACFCOMP(g_trac_ucd,ERR_MRK + "updateAllUcdFlashImages: UCD sub-flash image exceeds " + "upper boundary of UCD flash image. Offset=0x%08X, " + "size=0x%08X, lID size = 0%08X", + tocEntry.imageOffset,tocEntry.imageSize,i_image.size()); + /*@ + * @errortype + * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE + * @reasoncode UCD_RC::UCD_EOF + * @moduleid UCD_RC::MOD_UPDATE_ALL_UCD_FLASH_IMAGES + * @userdata1 UCD's HUID + * @devdesc Advertised UCD sub-flash image offset+size would + * pass the end of the UCD flash image. + * @custdesc Unexpected boot firmware data format error + */ + pError = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + UCD_RC::MOD_UPDATE_ALL_UCD_FLASH_IMAGES, + UCD_RC::UCD_EOF, + TARGETING::get_huid(powerSequencer), + 0, + ERRORLOG::ErrlEntry::ADD_SW_CALLOUT); + break; + } + + // Either way we'll be advancing to next UCD after the update + // attempt + nextUcd=true; + + // Update the UCD data flash + // @TODO RTC 205979 - Call this function + //pError = updateUcdFlash( + // powerSequencer, + // reinterpret_cast<const uint8_t*>(i_image.base()) + // + tocEntry.imageOffset, + // tocEntry.imageSize); + if(pError) + { + TRACFCOMP(g_trac_ucd,ERR_MRK + "updateAllUcdFlashImages: Failed in call to " + "updateUcdFlash for UCD with HUID of " + " 0x%08X.", + TARGETING::get_huid(powerSequencer)); + // @TODO: RTC 205982 Deconfigure UCD, call it out, etc. + pError->collectTrace(UCD_COMP_NAME); + errlCommit(pError,UCD_COMP_ID); + break; + } + + TRACFCOMP(g_trac_ucd,INFO_MRK + "updateAllUcdFlashImages: Successfully updated UCD " + "with HUID of 0x%08X.", + TARGETING::get_huid(powerSequencer)); + + } while(0); // End do/while processing individual TOC entry + + if(pError || nextUcd) + { + break; + } + + // Eat the delta between end of our TOC entry knowledge and the + // indicated TOC size + i_image.seek(header.tocEntrySize-sizeof(TocEntry), + UtilStream::CURRENT); + + } // End for loop searching for matching TOC entry + + if(pError) + { + break; + } + + // If failed to find TOC entry ... + + } while(0); // End do/while processing individual power sequencer + + if(pError) + { + break; + } + + } // End loop through all power sequencers + + } while(0); + + // Seek back to the beginning so caller gets identical state back + i_image.seek(0,UtilStream::START); + + TRACFCOMP(g_trac_ucd, EXIT_MRK + "updateAllUcdFlashImages"); + + return pError; +} errlHndl_t updateUcdFlash( TARGETING::Target* i_pUcd, |

