errlHndl_t RtPnor::getSideInfo( PNOR::SideId i_side, PNOR::SideInfo_t& o_info) { errlHndl_t l_err = nullptr; do { // We only support the working side at runtime if( i_side != PNOR::WORKING ) { /*@ * @errortype * @moduleid PNOR::MOD_RTPNOR_GETSIDEINFO * @reasoncode PNOR::RC_INVALID_PNOR_SIDE * @userdata1 Requested SIDE * @userdata2 0 * @devdesc getSideInfo> Side not supported * @custdesc A problem occurred while accessing the boot flash. */ l_err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, PNOR::MOD_RTPNOR_GETSIDEINFO, PNOR::RC_INVALID_PNOR_SIDE, TO_UINT64(i_side), 0,true); break; } o_info.id = PNOR::WORKING; o_info.side = (ALIGN_DOWN_X(iv_TOC[PNOR::HB_BASE_CODE].flashAddr,32*MEGABYTE) == 0) ? 'A':'B'; //@fixme TODO RTC:134436 //iv_side[i].isGolden = (ffsUserData->miscFlags & FFS_MISC_GOLDEN); o_info.isGolden = false; //@fixme TODO RTC:134436 o_info.isGuardPresent = (iv_TOC[PNOR::GUARD_DATA].flashAddr == 0) ? false : true; o_info.hasOtherSide = false; //@fixme TODO RTC:134436 o_info.primaryTOC = iv_TOC[PNOR::TOC].flashAddr; o_info.backupTOC = 0; //@fixme TODO RTC:134436 o_info.hbbAddress = iv_TOC[PNOR::HB_BASE_CODE].flashAddr; o_info.hbbMmioOffset = 0; //@fixme TODO RTC:134436 } while(0); return l_err; }
/** * @brief Performs a presence detect operation on a Processor Chip. * * This function does FSI presence detect and compares it to the Module * VPD that is present, following the pre-defined prototype for a * device-driver framework function. * * @param[in] i_opType Operation type, see DeviceFW::OperationType * in driverif.H * @param[in] i_target Presence detect target * @param[in/out] io_buffer Read: Pointer to output data storage * Write: Pointer to input data storage * @param[in/out] io_buflen Input: size of io_buffer (in bytes, always 1) * Output: Success = 1, Failure = 0 * @param[in] i_accessType DeviceFW::AccessType enum (userif.H) * @param[in] i_args This is an argument list for DD framework. * In this function, there are no arguments. * @return errlHndl_t */ errlHndl_t procPresenceDetect(DeviceFW::OperationType i_opType, TARGETING::Target* i_target, void* io_buffer, size_t& io_buflen, int64_t i_accessType, va_list i_args) { errlHndl_t l_errl = NULL; uint32_t l_saved_plid = 0; if (unlikely(io_buflen < sizeof(bool))) { TRACFCOMP(g_trac_fsi, ERR_MRK "FSI::procPresenceDetect> Invalid data length: %d", io_buflen); /*@ * @errortype * @moduleid FSI::MOD_FSIPRES_PROCPRESENCEDETECT * @reasoncode FSI::RC_INVALID_LENGTH * @userdata1 Data Length * @devdesc presenceDetect> Invalid data length (!= 1 bytes) */ l_errl = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, FSI::MOD_FSIPRES_PROCPRESENCEDETECT, FSI::RC_INVALID_LENGTH, TO_UINT64(io_buflen), true /*SW error*/); io_buflen = 0; return l_errl; } // First look for FSI presence bits bool fsi_present = false; TARGETING::Target* l_masterChip = NULL; TARGETING::targetService().masterProcChipTargetHandle(l_masterChip); if ((i_target == TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL) || (i_target == l_masterChip)) { fsi_present = true; } else { fsi_present = isSlavePresent(i_target); } // Next look for valid Module VPD bool check_for_mvpd = true; #ifdef CONFIG_MVPD_READ_FROM_HW check_for_mvpd = fsi_present; #endif // CONFIG_MVPD_READ_FROM_HW bool mvpd_present = false; size_t theSize = 0; if ( check_for_mvpd ) { l_errl = deviceRead( i_target, NULL, theSize, DEVICE_MVPD_ADDRESS( MVPD::CP00, MVPD::VD ) ); if( l_errl ) { if( fsi_present ) { // Save this plid to use later l_saved_plid = l_errl->plid(); // commit this log because we expected to have VPD errlCommit( l_errl, FSI_COMP_ID ); } else { // just delete this delete l_errl; } } if( theSize > 0 ) { uint8_t theData[theSize]; l_errl = deviceRead( i_target, theData, theSize, DEVICE_MVPD_ADDRESS( MVPD::CP00, MVPD::VD ) ); if( l_errl ) { if( fsi_present ) { // Save this plid to use later l_saved_plid = l_errl->plid(); // commit this log because we expected to have VPD errlCommit( l_errl, FSI_COMP_ID ); } else { // just delete this delete l_errl; } } else { mvpd_present = true; } } } // Finally compare the 2 methods if( fsi_present != mvpd_present ) { TRACFCOMP(g_trac_fsi, ERR_MRK "FSI::procPresenceDetect> FSI (=%d) and MVPD (=%d) do not agree for %.8X", fsi_present, mvpd_present, TARGETING::get_huid(i_target)); /*@ * @errortype * @moduleid FSI::MOD_FSIPRES_PROCPRESENCEDETECT * @reasoncode FSI::RC_FSI_MVPD_MISMATCH * @userdata1 HUID of processor * @userdata2[0:31] FSI Presence * @userdata2[32:63] MVPD Presence * @devdesc presenceDetect> FSI and MVPD do not agree */ l_errl = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, FSI::MOD_FSIPRES_PROCPRESENCEDETECT, FSI::RC_FSI_MVPD_MISMATCH, TARGETING::get_huid(i_target), TWO_UINT32_TO_UINT64( fsi_present, mvpd_present)); // Callout the processor l_errl->addHwCallout( i_target, HWAS::SRCI_PRIORITY_LOW, HWAS::NO_DECONFIG, HWAS::GARD_NULL ); // if there is a saved PLID, apply it to this error log if (l_saved_plid) { l_errl->plid(l_saved_plid); } // Add FFDC for the target to an error log getFsiFFDC( FFDC_PRESENCE_FAIL, l_errl, i_target); // Add FSI and VPD trace l_errl->collectTrace("FSI"); l_errl->collectTrace("VPD"); // commit this log and move on errlCommit( l_errl, FSI_COMP_ID ); } bool present = fsi_present && mvpd_present; memcpy(io_buffer, &present, sizeof(present)); io_buflen = sizeof(present); return NULL; }
/** * @brief Performs a mailbox write operation */ errlHndl_t mboxWrite(TARGETING::Target* i_target,void* i_buffer, size_t& i_buflen) { errlHndl_t l_err = NULL; uint32_t l_64bitBuf[2] = {0}; size_t l_64bitSize = sizeof(uint64_t); do { //If the expected siZe in bytes is bigger than the max data allowed // send back an error. if (i_buflen > MBOX_MAX_DATA_BYTES) { TRACFCOMP(g_trac_mbox, ERR_MRK "MBOX::write> Invalid data length : i_buflen=%d", i_buflen); /*@ * @errortype * @moduleid MBOX::MOD_MBOXDD_WRITE * @reasoncode MBOX::RC_INVALID_LENGTH * @userdata1 Target ID String... * @userdata2 Data Length * @devdesc MboxDD::write> Invalid data length (> msg_t size) * @custdesc A problem occurred during the * IPL of the system. */ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, MBOX::MOD_MBOXDD_WRITE, MBOX::RC_INVALID_LENGTH, TARGETING::get_huid(i_target), TO_UINT64(i_buflen), true /*Add HB Software Callout*/); l_err->collectTrace(MBOX_TRACE_NAME,1024); // Set the i_buflen to 0 to indicate no write occured i_buflen = 0; break; } // read the DB_STATUS_1A_REG: doorbell status and control 1a l_err = deviceOp(DeviceFW::READ,i_target, l_64bitBuf,l_64bitSize, DEVICE_XSCOM_ADDRESS(MBOX_DB_STAT_CNTRL_1)); if (l_err) { TRACFCOMP(g_trac_mbox, ERR_MRK "mboxWrite> Unable to read Doorbell Status/Control Register"); break; } /* * DB_STATUS_1A_REG: doorbell status and control 1a * Bit31(MSB) : Permission to Send Doorbell 1 * Bit30 : Abort Doorbell 1 * Bit29 : LBUS Slave B Pending Doorbell 1 * Bit28 : PIB Slave A Pending Doorbell 1 * Bit27 : Reserved * Bit26 : Xdn Doorbell 1 * Bit25 : Xup Doorbell 1 * Bit24 : Reserved * Bit23-20 : Header Count PIB Slave A Doorbell 1 * Bit19-12 : Data Count PIB Slave A Doorbell 1 * Bit11-8 : Header Count LBUS Slave B Doorbell 1 * Bit7-0 : Data Count LBUS Slave B Doorbell 1 */ //Verify There is no LBUS Pending, if ((l_64bitBuf[0] & (MBOX_LBUS_SLAVE_B_PND | MBOX_HDR_PIB_SLAVE_A | MBOX_DATA_PIB_SLAVE_A)) == 0) { // Current register counter indicating which of the mbox registers // to write to uint32_t cur_reg_cntr = 0; uint32_t l_data[2] = {0}; // Total number of registers to read to get all the data. uint8_t l_numRegsToWrite = (i_buflen*sizeof(uint8_t))/sizeof(uint32_t); uint8_t l_numBytesLeft = (i_buflen*sizeof(uint8_t))%sizeof(uint32_t); if (l_numBytesLeft != 0) { l_numRegsToWrite++; } uint32_t *l_buf = static_cast<uint32_t *>(i_buffer); // For the write we put the data into the MBOX data registers. // MBOX_DATA_PIB_START = 0x00050040 and the end address is // MBOX_DATA_PIB_END = 0x0005004F // each address inbetween increments by 1. //Write Data registers. Start at the first and increment through //the registers until all the data has been written. while (cur_reg_cntr < l_numRegsToWrite) { // If this is the last register we need to write and are not word aligned if (((cur_reg_cntr + 1) == l_numRegsToWrite) && (l_numBytesLeft != 0)) { // zero out the data reg. l_data[0] = 0; // Only copy the number of bytes remaining.. memcpy(&l_data[0], l_buf+cur_reg_cntr,l_numBytesLeft); } else { // point to the next 32bits of data in the buffer. l_data[0] = *(l_buf+cur_reg_cntr); } l_err = deviceOp(DeviceFW::WRITE,i_target, l_data,l_64bitSize, DEVICE_XSCOM_ADDRESS(MBOX_DATA_PIB_START+cur_reg_cntr)); if (l_err) { TRACFCOMP(g_trac_mbox, ERR_MRK "mboxWrite> Unable to write Data Area Register 0x%X",MBOX_DATA_PIB_START+cur_reg_cntr); break; } //increment counter so we are at the next register cur_reg_cntr++; } if (l_err) { break; } //Write LBUS Pending(28) and Data Count bits(11-0) to indicate // data has been written. l_64bitBuf[0] = MBOX_LBUS_SLAVE_B_PND | (MBOX_DATA_PIB_SLAVE_A & (i_buflen << 12)); l_err = deviceOp(DeviceFW::WRITE,i_target, l_64bitBuf,l_64bitSize, DEVICE_XSCOM_ADDRESS(MBOX_DB_STAT_CNTRL_1)); if (l_err) { TRACFCOMP(g_trac_mbox, ERR_MRK "mboxWrite> Unable to set Doorbell Status/Control Register"); break; } } else { TRACFCOMP(g_trac_mbox, ERR_MRK "mboxWrite> Message still pending : MBOX_DB_STAT_CNTRL_1=%X", l_64bitBuf[0]); /*@ * @errortype * @moduleid MBOX::MOD_MBOXDD_WRITE * @reasoncode MBOX::RC_MSG_PENDING * @userdata1 Target ID String... * @userdata2 Status/Control Register * @devdesc MboxDD::write> Message still pending * @custdesc A problem occurred during the * IPL of the system. */ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, MBOX::MOD_MBOXDD_WRITE, MBOX::RC_MSG_PENDING, TARGETING::get_huid(i_target), reinterpret_cast<uint64_t>(l_64bitBuf), true /*Add HB Software Callout*/); // Set the i_buflen to 0 to indicate no write occured i_buflen = 0; l_err->collectTrace(MBOX_TRACE_NAME,1024); break; } } while(0); return l_err; }
// ------------------------------------------------------------------ // ensureCacheIsInSync // ------------------------------------------------------------------ errlHndl_t ensureCacheIsInSync ( TARGETING::Target * i_target ) { errlHndl_t l_err = NULL; TRACSSCOMP( g_trac_vpd, ENTER_MRK"ensureCacheIsInSync() " ); IpVpdFacade& l_ipvpd = Singleton<MvpdFacade>::instance(); vpdRecord l_record = 0; vpdKeyword l_keywordPN = 0; vpdKeyword l_keywordSN = 0; TARGETING::TYPE l_type = i_target->getAttr<TARGETING::ATTR_TYPE>(); if( l_type == TARGETING::TYPE_PROC ) { l_record = MVPD::VINI; l_keywordPN = MVPD::PN; l_keywordSN = MVPD::SN; } else if( l_type == TARGETING::TYPE_MEMBUF ) { l_ipvpd = Singleton<CvpdFacade>::instance(); l_record = CVPD::VINI; l_keywordPN = CVPD::PN; l_keywordSN = CVPD::SN; } else if( l_type == TARGETING::TYPE_DIMM ) { // SPD does not have a singleton instance // SPD does not use records l_keywordPN = SPD::MODULE_PART_NUMBER; l_keywordSN = SPD::MODULE_SERIAL_NUMBER; } else { TRACFCOMP(g_trac_vpd,ERR_MRK"ensureCacheIsInSync() Unexpected target type, huid=0x%X",TARGETING::get_huid(i_target)); /*@ * @errortype * @moduleid VPD_ENSURE_CACHE_IS_IN_SYNC * @reasoncode VPD_UNEXPECTED_TARGET_TYPE * @userdata1 Target HUID * @userdata2 <UNUSED> * @devdesc Unexpected target type */ l_err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, VPD_ENSURE_CACHE_IS_IN_SYNC, VPD_UNEXPECTED_TARGET_TYPE, TO_UINT64(TARGETING::get_huid(i_target)), 0x0, true /*Add HB Software Callout*/ ); return l_err; } do { // Compare the Part Numbers in PNOR/SEEPROM bool l_matchPN = false; if( ( l_type == TARGETING::TYPE_PROC ) || ( l_type == TARGETING::TYPE_MEMBUF ) ) { l_err = l_ipvpd.cmpPnorToSeeprom( i_target, l_record, l_keywordPN, l_matchPN ); } else if( l_type == TARGETING::TYPE_DIMM ) { l_err = SPD::cmpPnorToSeeprom( i_target, l_keywordPN, l_matchPN ); } if (l_err) { TRACFCOMP(g_trac_vpd,ERR_MRK"VPD::ensureCacheIsInSync: Error checking for PNOR/SEEPROM PN match"); break; } // Compare the Serial Numbers in PNOR/SEEPROM bool l_matchSN = false; if( ( l_type == TARGETING::TYPE_PROC ) || ( l_type == TARGETING::TYPE_MEMBUF ) ) { l_err = l_ipvpd.cmpPnorToSeeprom( i_target, l_record, l_keywordSN, l_matchSN ); } else if( l_type == TARGETING::TYPE_DIMM ) { l_err = SPD::cmpPnorToSeeprom( i_target, l_keywordSN, l_matchSN ); } if( l_err ) { TRACFCOMP(g_trac_vpd,ERR_MRK"VPD::ensureCacheIsInSync: Error checking for PNOR/SEEPROM SN match"); break; } // If we did not match, we need to load SEEPROM VPD data into PNOR if( l_matchPN && l_matchSN ) { TRACFCOMP(g_trac_vpd,"VPD::ensureCacheIsInSync: PNOR_PN/SN = SEEPROM_PN/SN"); } else { TRACFCOMP(g_trac_vpd,"VPD::ensureCacheIsInSync: PNOR_PN/SN != SEEPROM_PN/SN, Loading PNOR from SEEPROM"); // @todo RTC 116553 - Need HCDB update call here // Load the PNOR data from the SEEPROM if( ( l_type == TARGETING::TYPE_PROC ) || ( l_type == TARGETING::TYPE_MEMBUF ) ) { l_err = l_ipvpd.loadPnor( i_target ); } else if( l_type == TARGETING::TYPE_DIMM ) { l_err = SPD::loadPnor( i_target ); } if( l_err ) { TRACFCOMP(g_trac_vpd,"Error loading SEEPROM VPD into PNOR"); break; } } // Set target attribute switch that says VPD is loaded into PNOR TARGETING::ATTR_VPD_SWITCHES_type vpdSwitches = i_target->getAttr<TARGETING::ATTR_VPD_SWITCHES>(); vpdSwitches.pnorLoaded = 1; i_target->setAttr<TARGETING::ATTR_VPD_SWITCHES>( vpdSwitches ); } while(0); TRACSSCOMP( g_trac_vpd, EXIT_MRK"ensureCacheIsInSync()" ); return l_err; }
// ------------------------------------------------------------------ // writePNOR // ------------------------------------------------------------------ errlHndl_t writePNOR ( uint64_t i_byteAddr, size_t i_numBytes, void * i_data, TARGETING::Target * i_target, pnorInformation & i_pnorInfo, uint64_t &io_cachedAddr, mutex_t * i_mutex ) { errlHndl_t err = NULL; int64_t vpdLocation = 0; uint64_t addr = 0x0; const char * writeAddr = NULL; TRACSSCOMP( g_trac_vpd, ENTER_MRK"writePNOR()" ); do { // Check if we have the PNOR addr cached. if( 0x0 == io_cachedAddr ) { err = getPnorAddr( i_pnorInfo, io_cachedAddr, i_mutex ); if( err ) { break; } } addr = io_cachedAddr; // Find vpd location of the target err = getVpdLocation( vpdLocation, i_target ); if( err ) { break; } // Offset cached address by vpd location multiplier addr += (vpdLocation * i_pnorInfo.segmentSize); // Now offset into that chunk of data by i_byteAddr addr += i_byteAddr; //TODO: Validate write is within bounds of appropriate PNOR // partition/section. RTC: 51807 TRACUCOMP( g_trac_vpd, INFO_MRK"Address to write: 0x%08x", addr ); // Write the data writeAddr = reinterpret_cast<const char*>( addr ); memcpy( (void*)(writeAddr), i_data, i_numBytes ); // @todo RTC:117042 - enable flush once PNOR writes supported // Flush the page to make sure it gets to the PNOR #if 0 int rc = mm_remove_pages( FLUSH, (void*)addr, i_numBytes ); if( rc ) { TRACFCOMP(g_trac_vpd,ERR_MRK"writePNOR() Error from mm_remove_pages, rc=%d",rc); /*@ * @errortype * @moduleid VPD_WRITE_PNOR * @reasoncode VPD_REMOVE_PAGES_FAIL * @userdata1 Requested Address * @userdata2 rc from mm_remove_pages * @devdesc writePNOR mm_remove_pages FLUSH failed */ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, VPD_WRITE_PNOR, VPD_REMOVE_PAGES_FAIL, addr, TO_UINT64(rc), true /*Add HB Software Callout*/ ); } #endif } while( 0 ); TRACSSCOMP( g_trac_vpd, EXIT_MRK"writePNOR()" ); return err; }
/////////////////////////////////////////////////////////////////////////////// // See header file for doxygen documentation /////////////////////////////////////////////////////////////////////////////// errlHndl_t validateInputs(DeviceFW::OperationType i_opType, const TARGETING::Target* i_target, size_t i_buflen, uint64_t i_scomAddr) { errlHndl_t l_err = nullptr; uint32_t l_commonPlid = 0; // If there are multiple issues found link logs with first // Verify that the target is of type OCMB_CHIP TARGETING::ATTR_TYPE_type l_targetType = i_target->getAttr<TARGETING::ATTR_TYPE>(); // Only target we can perform ocmb scoms on are OCMB chip targets if( l_targetType != TARGETING::TYPE_OCMB_CHIP ) { TRACFCOMP( g_trac_expscom, ERR_MRK "validateInputs> Invalid target type : l_targetType=0x%X", l_targetType ); /*@ * @errortype * @moduleid EXPSCOM::MOD_OCMB_UTILS * @reasoncode EXPSCOM::RC_INVALID_MODEL_TYPE * @userdata1 SCOM Address * @userdata2 Model Type * @devdesc validateInputs> Invalid target type (!= OCMB_CHIP) * @custdesc A problem occurred during the IPL of the system: * Invalid target type for a SCOM operation. */ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, EXPSCOM::MOD_OCMB_UTILS, EXPSCOM::RC_INVALID_MODEL_TYPE, i_scomAddr, l_targetType, ERRORLOG::ErrlEntry::ADD_SW_CALLOUT); l_err->collectTrace(EXPSCOM_COMP_NAME); ERRORLOG::ErrlUserDetailsTarget(i_target,"SCOM Target"). addToLog(l_err); l_commonPlid = l_err->plid(); } // The address passed to the OCMB scom functions is really only 32 bits // just to be safe make sure that first 4 bytes are 0s if( i_scomAddr & FIRST_4_BYTES ) { TRACFCOMP( g_trac_expscom, ERR_MRK "validateInputs> Invalid address : i_scomAddr=0x%lx , first 32 bits should be 0's", i_scomAddr ); // If there is already an error from prev checks, then commit it if(l_err) { errlCommit(l_err, EXPSCOM_COMP_ID); } /*@ * @errortype * @moduleid EXPSCOM::MOD_OCMB_UTILS * @reasoncode EXPSCOM::RC_INVALID_ADDRESS * @userdata1 SCOM Address * @userdata2 Target HUID * @devdesc validateInputs> Invalid scom address, first 4 * bytes should be 0's * @custdesc A problem occurred during the IPL of the system: * Invalid address for a SCOM operation. */ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, EXPSCOM::MOD_OCMB_UTILS, EXPSCOM::RC_INVALID_ADDRESS, i_scomAddr, TARGETING::get_huid(i_target), ERRORLOG::ErrlEntry::ADD_SW_CALLOUT); l_err->collectTrace(EXPSCOM_COMP_NAME); ERRORLOG::ErrlUserDetailsTarget(i_target,"SCOM Target"). addToLog(l_err); if(l_commonPlid == 0) { l_commonPlid = l_err->plid(); } else { l_err->plid(l_commonPlid); } } // The buffer passed into validateInputs should ALWAYS be 8 bytes. // If it is an IBM scom then all 8 bytes are used. If its microchip scom // then only the last 4 bytes are used. if (i_buflen != sizeof(uint64_t)) { TRACFCOMP( g_trac_expscom, ERR_MRK "validateInputs> Invalid data length : io_buflen=%d ," " expected sizeof(uint64_t)", i_buflen ); // If there is already an error from prev checks, then commit it if(l_err) { errlCommit(l_err, EXPSCOM_COMP_ID); } /*@ * @errortype * @moduleid EXPSCOM::MOD_OCMB_UTILS * @reasoncode EXPSCOM::RC_INVALID_LENGTH * @userdata1 SCOM Address * @userdata2 Data Length * @devdesc validateInputs> Invalid data length (!= 8 bytes) * @custdesc A problem occurred during the IPL of the system: * Invalid data length for a SCOM operation. */ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, EXPSCOM::MOD_OCMB_UTILS, EXPSCOM::RC_INVALID_LENGTH, i_scomAddr, TO_UINT64(i_buflen), ERRORLOG::ErrlEntry::ADD_SW_CALLOUT); l_err->collectTrace(EXPSCOM_COMP_NAME); ERRORLOG::ErrlUserDetailsTarget(i_target,"SCOM Target"). addToLog(l_err); if(l_commonPlid == 0) { l_commonPlid = l_err->plid(); } else { l_err->plid(l_commonPlid); } } // The only valid operations are READ and WRITE if anything else comes in we need to error out if (i_opType != DeviceFW::READ && i_opType != DeviceFW::WRITE ) { TRACFCOMP( g_trac_expscom, ERR_MRK "validateInputs> Invalid operation type : i_opType=%d", i_opType ); if(l_err) { errlCommit(l_err, EXPSCOM_COMP_ID); } /*@ * @errortype * @moduleid EXPSCOM::MOD_OCMB_UTILS * @reasoncode EXPSCOM::RC_INVALID_OPTYPE * @userdata1 SCOM Address * @userdata2 Access Type * @devdesc validateInputs> Invalid OP type (!= READ or WRITE) * @custdesc A problem occurred during the IPL of the system: * Invalid operation type for a SCOM operation. */ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, EXPSCOM::MOD_OCMB_UTILS, EXPSCOM::RC_INVALID_OPTYPE, i_scomAddr, i_opType, ERRORLOG::ErrlEntry::ADD_SW_CALLOUT); l_err->collectTrace(EXPSCOM_COMP_NAME); ERRORLOG::ErrlUserDetailsTarget(i_target,"SCOM Target"). addToLog(l_err); if(l_commonPlid == 0) { l_commonPlid = l_err->plid(); } else { l_err->plid(l_commonPlid); } } return l_err; }
/** * @brief Performs a presence detect operation on a Processor Chip. * * This function does FSI presence detect and compares it to the Module * VPD that is present, following the pre-defined prototype for a * device-driver framework function. * * @param[in] i_opType Operation type, see DeviceFW::OperationType * in driverif.H * @param[in] i_target Presence detect target * @param[in/out] io_buffer Read: Pointer to output data storage * Write: Pointer to input data storage * @param[in/out] io_buflen Input: size of io_buffer (in bytes, always 1) * Output: Success = 1, Failure = 0 * @param[in] i_accessType DeviceFW::AccessType enum (userif.H) * @param[in] i_args This is an argument list for DD framework. * In this function, there are no arguments. * @return errlHndl_t */ errlHndl_t procPresenceDetect(DeviceFW::OperationType i_opType, TARGETING::Target* i_target, void* io_buffer, size_t& io_buflen, int64_t i_accessType, va_list i_args) { errlHndl_t l_errl = NULL; uint32_t l_saved_plid = 0; if (unlikely(io_buflen < sizeof(bool))) { TRACFCOMP(g_trac_fsi, ERR_MRK "FSI::procPresenceDetect> Invalid data length: %d", io_buflen); /*@ * @errortype * @moduleid FSI::MOD_FSIPRES_PROCPRESENCEDETECT * @reasoncode FSI::RC_INVALID_LENGTH * @userdata1 Data Length * @devdesc presenceDetect> Invalid data length (!= 1 bytes) */ l_errl = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, FSI::MOD_FSIPRES_PROCPRESENCEDETECT, FSI::RC_INVALID_LENGTH, TO_UINT64(io_buflen), true /*SW error*/); io_buflen = 0; return l_errl; } // First look for FSI presence bits bool fsi_present = false; TARGETING::Target* l_masterChip = NULL; TARGETING::targetService().masterProcChipTargetHandle(l_masterChip); if ((i_target == TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL) || (i_target == l_masterChip)) { fsi_present = true; } else { fsi_present = isSlavePresent(i_target); } // Next look for valid Module VPD bool mvpd_present = false; bool check_for_mvpd = true; #ifdef CONFIG_MVPD_READ_FROM_HW check_for_mvpd = fsi_present; #endif if ( check_for_mvpd ) { mvpd_present = VPD::mvpdPresent( i_target ); } #if defined(CONFIG_MVPD_READ_FROM_HW) && defined(CONFIG_MVPD_READ_FROM_PNOR) if( mvpd_present ) { // Check if the VPD data in the PNOR matches the SEEPROM l_errl = VPD::ensureCacheIsInSync( i_target ); if( l_errl ) { // Save this plid to use later l_saved_plid = l_errl->plid(); mvpd_present = false; TRACFCOMP(g_trac_fsi,ERR_MRK "FSI::procPresenceDetect> Error during ensureCacheIsInSync (MVPD)" ); errlCommit( l_errl, FSI_COMP_ID ); } } else { // Invalidate MVPD in the PNOR l_errl = VPD::invalidatePnorCache(i_target); if (l_errl) { TRACFCOMP( g_trac_fsi, "Error invalidating MVPD in PNOR" ); errlCommit( l_errl, FSI_COMP_ID ); } } #endif // Finally compare the 2 methods if( fsi_present != mvpd_present ) { TRACFCOMP(g_trac_fsi, ERR_MRK "FSI::procPresenceDetect> " "FSI (=%d) and MVPD (=%d) do not agree for %.8X", fsi_present, mvpd_present, TARGETING::get_huid(i_target)); /*@ * @errortype * @moduleid FSI::MOD_FSIPRES_PROCPRESENCEDETECT * @reasoncode FSI::RC_FSI_MVPD_MISMATCH * @userdata1 HUID of processor * @userdata2[0:31] FSI Presence * @userdata2[32:63] MVPD Presence * @devdesc presenceDetect> FSI and MVPD do not agree */ l_errl = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, FSI::MOD_FSIPRES_PROCPRESENCEDETECT, FSI::RC_FSI_MVPD_MISMATCH, TARGETING::get_huid(i_target), TWO_UINT32_TO_UINT64( fsi_present, mvpd_present)); // Callout the processor l_errl->addHwCallout( i_target, HWAS::SRCI_PRIORITY_LOW, HWAS::NO_DECONFIG, HWAS::GARD_NULL ); // If there is a saved PLID, apply it to this error log if (l_saved_plid) { l_errl->plid(l_saved_plid); } // Add FFDC for the target to an error log getFsiFFDC( FFDC_PRESENCE_FAIL, l_errl, i_target); // Add FSI and VPD trace l_errl->collectTrace("FSI"); l_errl->collectTrace("VPD"); // Commit this log and move on errlCommit( l_errl, FSI_COMP_ID ); } bool present = fsi_present && mvpd_present; if( present ) { //Fsp sets PN/SN so if there is none, do it here if(!INITSERVICE::spBaseServicesEnabled()) { // set part and serial number attributes for current target VPD::setPartAndSerialNumberAttributes( i_target ); } } memcpy(io_buffer, &present, sizeof(present)); io_buflen = sizeof(present); return NULL; }
/** * @brief Message receiver */ void PnorRP::waitForMessage() { TRACFCOMP(g_trac_pnor, "PnorRP::waitForMessage>" ); errlHndl_t l_errhdl = NULL; msg_t* message = NULL; uint8_t* user_addr = NULL; uint8_t* eff_addr = NULL; uint64_t dev_offset = 0; uint64_t chip_select = 0xF; bool needs_ecc = false; int rc = 0; uint64_t status_rc = 0; uint64_t fatal_error = 0; while(1) { status_rc = 0; TRACUCOMP(g_trac_pnor, "PnorRP::waitForMessage> waiting for message" ); message = msg_wait( iv_msgQ ); if( message ) { /* data[0] = virtual address requested * data[1] = address to place contents */ eff_addr = (uint8_t*)message->data[0]; user_addr = (uint8_t*)message->data[1]; //figure out the real pnor offset l_errhdl = computeDeviceAddr( eff_addr, dev_offset, chip_select, needs_ecc ); if( l_errhdl ) { status_rc = -EFAULT; /* Bad address */ } else { switch(message->type) { case( MSG_MM_RP_READ ): l_errhdl = readFromDevice( dev_offset, chip_select, needs_ecc, user_addr, fatal_error ); if( l_errhdl || ( 0 != fatal_error ) ) { status_rc = -EIO; /* I/O error */ } break; case( MSG_MM_RP_WRITE ): l_errhdl = writeToDevice( dev_offset, chip_select, needs_ecc, user_addr ); if( l_errhdl ) { status_rc = -EIO; /* I/O error */ } break; default: TRACFCOMP( g_trac_pnor, "PnorRP::waitForMessage> Unrecognized message type : user_addr=%p, eff_addr=%p, msgtype=%d", user_addr, eff_addr, message->type ); /*@ * @errortype * @moduleid PNOR::MOD_PNORRP_WAITFORMESSAGE * @reasoncode PNOR::RC_INVALID_MESSAGE_TYPE * @userdata1 Message type * @userdata2 Requested Virtual Address * @devdesc PnorRP::waitForMessage> Unrecognized * message type * @custdesc A problem occurred while accessing * the boot flash. */ l_errhdl = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, PNOR::MOD_PNORRP_WAITFORMESSAGE, PNOR::RC_INVALID_MESSAGE_TYPE, TO_UINT64(message->type), (uint64_t)eff_addr, true /*Add HB SW Callout*/); l_errhdl->collectTrace(PNOR_COMP_NAME); status_rc = -EINVAL; /* Invalid argument */ } } if( !l_errhdl && msg_is_async(message) ) { TRACFCOMP( g_trac_pnor, "PnorRP::waitForMessage> Unsupported Asynchronous Message : user_addr=%p, eff_addr=%p, msgtype=%d", user_addr, eff_addr, message->type ); /*@ * @errortype * @moduleid PNOR::MOD_PNORRP_WAITFORMESSAGE * @reasoncode PNOR::RC_INVALID_ASYNC_MESSAGE * @userdata1 Message type * @userdata2 Requested Virtual Address * @devdesc PnorRP::waitForMessage> Unrecognized message * type * @custdesc A problem occurred while accessing the boot * flash. */ l_errhdl = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, PNOR::MOD_PNORRP_WAITFORMESSAGE, PNOR::RC_INVALID_ASYNC_MESSAGE, TO_UINT64(message->type), (uint64_t)eff_addr, true /*Add HB SW Callout*/); l_errhdl->collectTrace(PNOR_COMP_NAME); status_rc = -EINVAL; /* Invalid argument */ } if( l_errhdl ) { errlCommit(l_errhdl,PNOR_COMP_ID); } /* Expected Response: * data[0] = virtual address requested * data[1] = rc (0 or negative errno value) * extra_data = Specific reason code. */ message->data[1] = status_rc; message->extra_data = reinterpret_cast<void*>(fatal_error); rc = msg_respond( iv_msgQ, message ); if( rc ) { TRACFCOMP(g_trac_pnor, "PnorRP::waitForMessage> Error from msg_respond, giving up : rc=%d", rc ); break; } } } TRACFCOMP(g_trac_pnor, "< PnorRP::waitForMessage" ); }
/** * @brief Return the size and address of a given section of PNOR data */ errlHndl_t PnorRP::getSectionInfo( PNOR::SectionId i_section, PNOR::SectionInfo_t& o_info ) { //TRACDCOMP(g_trac_pnor, "PnorRP::getSectionInfo> i_section=%d", i_section ); errlHndl_t l_errhdl = NULL; PNOR::SectionId id = i_section; do { // Abort this operation if we had a startup failure uint64_t rc = 0; if( didStartupFail(rc) ) { TRACFCOMP( g_trac_pnor, "PnorRP::getSectionInfo> RP not properly initialized, failing : rc=%X", rc ); /*@ * @errortype * @moduleid PNOR::MOD_PNORRP_GETSECTIONINFO * @reasoncode PNOR::RC_STARTUP_FAIL * @userdata1 Requested Section * @userdata2 Startup RC * @devdesc PnorRP::getSectionInfo> RP not properly initialized * @custdesc A problem occurred while accessing the boot flash. */ l_errhdl = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, PNOR::MOD_PNORRP_GETSECTIONINFO, PNOR::RC_STARTUP_FAIL, TO_UINT64(i_section), rc, true /*Add HB SW Callout*/); l_errhdl->collectTrace(PNOR_COMP_NAME); // set the return section to our invalid data id = PNOR::INVALID_SECTION; break; } // Zero-length means the section is invalid if( 0 == iv_TOC[id].size ) { TRACFCOMP( g_trac_pnor, "PnorRP::getSectionInfo> Invalid Section Requested : i_section=%d", i_section ); TRACFCOMP(g_trac_pnor, "o_info={ id=%d, size=%d }", iv_TOC[i_section].id, iv_TOC[i_section].size ); /*@ * @errortype * @moduleid PNOR::MOD_PNORRP_GETSECTIONINFO * @reasoncode PNOR::RC_INVALID_SECTION * @userdata1 Requested Section * @userdata2 TOC used * @devdesc PnorRP::getSectionInfo> Invalid Address for read/write * @custdesc A problem occurred while accessing the boot flash. */ l_errhdl = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, PNOR::MOD_PNORRP_GETSECTIONINFO, PNOR::RC_INVALID_SECTION, TO_UINT64(i_section), iv_TOC_used, true /*Add HB SW Callout*/); l_errhdl->collectTrace(PNOR_COMP_NAME); // set the return section to our invalid data id = PNOR::INVALID_SECTION; break; } } while(0); if (PNOR::INVALID_SECTION != id) { TRACDCOMP( g_trac_pnor, "PnorRP::getSectionInfo: i_section=%d, id=%d", i_section, iv_TOC[i_section].id ); // copy my data into the external format o_info.id = iv_TOC[id].id; o_info.name = cv_EYECATCHER[id]; o_info.vaddr = iv_TOC[id].virtAddr; o_info.size = iv_TOC[id].size; o_info.eccProtected = ((iv_TOC[id].integrity & FFS_INTEG_ECC_PROTECT) != 0) ? true : false; o_info.sha512Version = ((iv_TOC[id].version & FFS_VERS_SHA512) != 0) ? true : false; o_info.sha512perEC = ((iv_TOC[id].version & FFS_VERS_SHA512_PER_EC) != 0) ? true : false; } return l_errhdl; }
/** * @brief Initialize the daemon */ void PnorRP::initDaemon() { TRACUCOMP(g_trac_pnor, "PnorRP::initDaemon> " ); errlHndl_t l_errhdl = NULL; do { // read the TOC in the PNOR to compute the sections l_errhdl = readTOC(); if( l_errhdl ) { break; } // create a message queue iv_msgQ = msg_q_create(); // create a Block, passing in the message queue int rc = mm_alloc_block( iv_msgQ, (void*) BASE_VADDR, TOTAL_SIZE ); if( rc ) { TRACFCOMP( g_trac_pnor, "PnorRP::initDaemon> Error from mm_alloc_block : rc=%d", rc ); /*@ * @errortype * @moduleid PNOR::MOD_PNORRP_INITDAEMON * @reasoncode PNOR::RC_EXTERNAL_ERROR * @userdata1 Requested Address * @userdata2 rc from mm_alloc_block * @devdesc PnorRP::initDaemon> Error from mm_alloc_block * @custdesc A problem occurred while accessing the boot flash. */ l_errhdl = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, PNOR::MOD_PNORRP_INITDAEMON, PNOR::RC_EXTERNAL_ERROR, TO_UINT64(BASE_VADDR), TO_UINT64(rc), true /*Add HB SW Callout*/); l_errhdl->collectTrace(PNOR_COMP_NAME); break; } //Register this memory range to be FLUSHed during a shutdown. INITSERVICE::registerBlock(reinterpret_cast<void*>(BASE_VADDR), TOTAL_SIZE,PNOR_PRIORITY); // Need to set permissions to R/W rc = mm_set_permission((void*) BASE_VADDR,TOTAL_SIZE, WRITABLE | WRITE_TRACKED); // start task to wait on the queue task_create( wait_for_message, NULL ); } while(0); if( l_errhdl ) { iv_startupRC = l_errhdl->reasonCode(); errlCommit(l_errhdl,PNOR_COMP_ID); } // call ErrlManager function - tell him that PNOR is ready! ERRORLOG::ErrlManager::errlResourceReady(ERRORLOG::PNOR); TRACUCOMP(g_trac_pnor, "< PnorRP::initDaemon" ); }
/** * @brief Performs a presence detect operation on MCSs * * Although not a physical part, presence detect confirms access * to direct access memory vpd. * * @param[in] i_opType Operation type, see DeviceFW::OperationType * in driverif.H * @param[in] i_target Presence detect target * @param[in/out] io_buffer Read: Pointer to output data storage * Write: Pointer to input data storage * @param[in/out] io_buflen Input: size of io_buffer (in bytes, always 1) * Output: Success = 1, Failure = 0 * @param[in] i_accessType DeviceFW::AccessType enum (userif.H) * @param[in] i_args This is an argument list for DD framework. * In this function, there are no arguments. * @return errlHndl_t */ errlHndl_t directMemoryPresenceDetect(DeviceFW::OperationType i_opType, TARGETING::Target* i_target, void* io_buffer, size_t& io_buflen, int64_t i_accessType, va_list i_args) { errlHndl_t l_errl = NULL; bool dvpd_present = false; TRACSSCOMP(g_trac_vpd, ENTER_MRK "directMemoryPresenceDetect"); if (unlikely(io_buflen < sizeof(bool))) { TRACFCOMP(g_trac_vpd, ERR_MRK "directMemoryPresenceDetect> Invalid data length: %d", io_buflen); /*@ * @errortype * @moduleid VPD::VPD_DVPD_PRESENCEDETECT * @reasoncode VPD::VPD_INVALID_LENGTH * @userdata1 Data Length * @devdesc presenceDetect> Invalid data length (!= 1 bytes) */ l_errl = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, VPD::VPD_DVPD_PRESENCEDETECT, VPD::VPD_INVALID_LENGTH, TO_UINT64(io_buflen), true /*SW error*/); io_buflen = 0; return l_errl; } dvpd_present = DVPD::dvpdPresent( i_target ); #if defined(CONFIG_MEMVPD_READ_FROM_HW) && defined(CONFIG_MEMVPD_READ_FROM_PNOR) //skipping cache sync when dvpd is present as it will be taken care by node //vpd if( !dvpd_present ) { TRACFCOMP(g_trac_vpd, ERR_MRK "directMemoryPresenceDetect> failed presence detect"); // Defer invalidating DVPD in the PNOR in case another target might be // sharing this VPD_REC_NUM. Check all targets sharing this // VPD_REC_NUM after target discovery in VPD::validateSharedPnorCache. // Ensure the VPD_SWITCHES cache valid bit is invalid at this point. TARGETING::ATTR_VPD_SWITCHES_type vpdSwitches = i_target->getAttr<TARGETING::ATTR_VPD_SWITCHES>(); vpdSwitches.pnorCacheValid = 0; i_target->setAttr<TARGETING::ATTR_VPD_SWITCHES>( vpdSwitches ); } #endif memcpy(io_buffer, &dvpd_present, sizeof(dvpd_present)); io_buflen = sizeof(dvpd_present); TRACSSCOMP(g_trac_vpd, EXIT_MRK "directMemoryPresenceDetect = %d",dvpd_present); return NULL; }
// ------------------------------------------------------------------ // dimmPresenceDetect // ------------------------------------------------------------------ errlHndl_t dimmPresenceDetect( DeviceFW::OperationType i_opType, TARGETING::Target * i_target, void * io_buffer, size_t & io_buflen, int64_t i_accessType, va_list i_args ) { errlHndl_t err = NULL; bool present = false; size_t presentSz = sizeof(present); TRACSSCOMP( g_trac_spd, ENTER_MRK"dimmPresenceDetect()" ); do { // Check to be sure that the buffer is big enough. if( !(io_buflen >= sizeof(bool)) ) { TRACFCOMP( g_trac_spd, ERR_MRK"dimmPresenceDetect() - Invalid Data Length: %d", io_buflen ); /*@ * @errortype * @reasoncode VPD::VPD_INSUFFICIENT_BUFFER_SIZE * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE * @moduleid VPD::VPD_SPD_PRESENCE_DETECT * @userdata1 Buffer Length * @userdata2 <UNUSED> * @devdesc Buffer for checking Presence Detect * was not the correct size. */ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, VPD::VPD_SPD_PRESENCE_DETECT, VPD::VPD_INSUFFICIENT_BUFFER_SIZE, TO_UINT64(io_buflen), 0x0, true /*Add HB Software Callout*/); err->collectTrace( "SPD", 256); break; } // Is the target present #ifdef CONFIG_DJVPD_READ_FROM_HW // Check if the parent MBA/MEMBUF is present. If it is not then // no reason to check the DIMM which would otherwise generate // tons of FSI errors. We can't just check if parent MBA // is functional because DIMM presence detect is called before // the parent MBA/MEMBUF is set as present/functional. TARGETING::TargetHandleList membufList; TARGETING::PredicateCTM membufPred( TARGETING::CLASS_CHIP, TARGETING::TYPE_MEMBUF ); TARGETING::targetService().getAssociated( membufList, i_target, TARGETING::TargetService::PARENT_BY_AFFINITY, TARGETING::TargetService::ALL, &membufPred); bool parentPresent = false; const TARGETING::TargetHandle_t membufTarget = *(membufList.begin()); err = deviceRead(membufTarget, &parentPresent, presentSz, DEVICE_PRESENT_ADDRESS()); if (err) { TRACFCOMP( g_trac_spd, "Error reading parent MEMBUF present: huid 0x%X DIMM huid 0x%X", TARGETING::get_huid(membufTarget), TARGETING::get_huid(i_target) ); break; } if (!parentPresent) { present = false; // Invalidate the SPD in PNOR err = VPD::invalidatePnorCache(i_target); if (err) { TRACFCOMP( g_trac_spd, "Error invalidating SPD in PNOR" ); } break; } #endif present = spdPresent( i_target ); if( present == false ) { TRACUCOMP( g_trac_spd, INFO_MRK"Dimm was found to be NOT present." ); } else { TRACUCOMP( g_trac_spd, INFO_MRK"Dimm was found to be present." ); } #if defined(CONFIG_DJVPD_READ_FROM_HW) && defined(CONFIG_DJVPD_READ_FROM_PNOR) if( present ) { // Check if the VPD data in the PNOR matches the SEEPROM err = VPD::ensureCacheIsInSync( i_target ); if( err ) { present = false; TRACFCOMP(g_trac_spd,ERR_MRK "dimmPresenceDetectt> Error during ensureCacheIsInSync (SPD)" ); break; } } else { // SPD is not present, invalidate the SPD in PNOR err = VPD::invalidatePnorCache(i_target); if (err) { TRACFCOMP( g_trac_spd, "Error invalidating SPD in PNOR" ); } } #endif if( present && !err ) { //Fsp sets PN/SN so if there is none, do it here if(!INITSERVICE::spBaseServicesEnabled()) { //populate serial and part number attributes SPD::setPartAndSerialNumberAttributes( i_target ); } // Read ATTR_CLEAR_DIMM_SPD_ENABLE attribute TARGETING::Target* l_sys = NULL; TARGETING::targetService().getTopLevelTarget(l_sys); TARGETING::ATTR_CLEAR_DIMM_SPD_ENABLE_type l_clearSPD = l_sys->getAttr<TARGETING::ATTR_CLEAR_DIMM_SPD_ENABLE>(); // If SPD clear is enabled then write 0's into magic word for // DIMM_BAD_DQ_DATA keyword // Note: If there's an error from performing the clearing, // just log the error and continue. if (l_clearSPD) { size_t l_size = 0; // Do a read to get the DIMM_BAD_DQ_DATA keyword size err = deviceRead(i_target, NULL, l_size, DEVICE_SPD_ADDRESS( DIMM_BAD_DQ_DATA )); if (err) { TRACFCOMP(g_trac_spd, "dimmPresenceDetect - " "Error reading DIMM_BAD_DQ_DATA keyword size"); errlCommit( err, VPD_COMP_ID ); } else { // Clear the data TRACFCOMP( g_trac_spd, "Clearing out BAD_DQ_DATA SPD on " "DIMM HUID 0x%X", TARGETING::get_huid(i_target)); uint8_t * l_data = static_cast<uint8_t*>(malloc( l_size )); memset(l_data, 0, l_size); err = deviceWrite(i_target, l_data, l_size, DEVICE_SPD_ADDRESS( DIMM_BAD_DQ_DATA )); if (err) { TRACFCOMP( g_trac_spd, "Error trying to clear SPD on " "DIMM HUID 0x%X", TARGETING::get_huid(i_target)); errlCommit( err, VPD_COMP_ID ); } // Free the memory if (NULL != l_data) { free(l_data); } } } } // copy present value into output buffer so caller can read it memcpy( io_buffer, &present, presentSz ); io_buflen = presentSz; } while( 0 ); TRACSSCOMP( g_trac_spd, EXIT_MRK"dimmPresenceDetect()" ); return err; } // end dimmPresenceDetect
// ------------------------------------------------------------------ // dimmPresenceDetect // ------------------------------------------------------------------ errlHndl_t dimmPresenceDetect( DeviceFW::OperationType i_opType, TARGETING::Target * i_target, void * io_buffer, size_t & io_buflen, int64_t i_accessType, va_list i_args ) { errlHndl_t err = NULL; bool present = false; size_t presentSz = sizeof(present); TRACSSCOMP( g_trac_spd, ENTER_MRK"dimmPresenceDetect() " "DIMM HUID 0x%X", TARGETING::get_huid(i_target)); do { // Check to be sure that the buffer is big enough. if( !(io_buflen >= sizeof(bool)) ) { TRACFCOMP( g_trac_spd, ERR_MRK"dimmPresenceDetect() " "Invalid Data Length: %d", io_buflen ); /*@ * @errortype * @reasoncode VPD::VPD_INSUFFICIENT_BUFFER_SIZE * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE * @moduleid VPD::VPD_SPD_PRESENCE_DETECT * @userdata1 Buffer Length * @userdata2 <UNUSED> * @devdesc Buffer for checking Presence Detect * was not the correct size. */ err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, VPD::VPD_SPD_PRESENCE_DETECT, VPD::VPD_INSUFFICIENT_BUFFER_SIZE, TO_UINT64(io_buflen), 0x0, true /*Add HB Software Callout*/); err->collectTrace( "SPD", 256); break; } // Is the target present? #ifdef CONFIG_DJVPD_READ_FROM_HW // Check if the i2c master is present. // If it is not then no reason to check the DIMM which would // otherwise generate tons of FSI errors. // We can't just check if parent MCA or MBA // is functional because DIMM presence detect is called before // the parent MCS/MCA or MBA/MEMBUF is set as present/functional. bool l_i2cMasterPresent = false; do { // get eeprom vpd primary info TARGETING::EepromVpdPrimaryInfo eepromData; if( !(i_target-> tryGetAttr<TARGETING::ATTR_EEPROM_VPD_PRIMARY_INFO> ( eepromData ) ) ) { TRACFCOMP( g_trac_spd, ERR_MRK"dimmPresenceDetect() " "Error: no eeprom vpd primary info" ); break; } // find i2c master target TARGETING::TargetService& tS = TARGETING::targetService(); bool exists = false; tS.exists( eepromData.i2cMasterPath, exists ); if( !exists ) { TRACFCOMP( g_trac_spd, ERR_MRK"dimmPresenceDetect() " "i2cMasterPath attribute path doesn't exist"); break; } // Since it exists, convert to a target TARGETING::Target * l_i2cMasterTarget = tS.toTarget( eepromData.i2cMasterPath ); if( NULL == l_i2cMasterTarget ) { TRACFCOMP( g_trac_spd, ERR_MRK"dimmPresenceDetect() " "i2cMasterPath target is NULL"); break; } TRACSSCOMP( g_trac_spd, "dimmPresenceDetect() " "i2c master HUID 0x%X", TARGETING::get_huid(l_i2cMasterTarget)); // Check if present TARGETING::Target* masterProcTarget = NULL; TARGETING::targetService().masterProcChipTargetHandle( masterProcTarget ); // Master proc is taken as always present. Validate other targets. if (l_i2cMasterTarget != masterProcTarget) { l_i2cMasterPresent = FSI::isSlavePresent(l_i2cMasterTarget); if( !l_i2cMasterPresent ) { TRACFCOMP( g_trac_spd, ERR_MRK"dimmPresenceDetect() " "isSlavePresent failed"); break; } } l_i2cMasterPresent = true; } while (0); if (!l_i2cMasterPresent) { present = false; // Invalidate the SPD in PNOR err = VPD::invalidatePnorCache(i_target); if (err) { TRACFCOMP( g_trac_spd, ERR_MRK"dimmPresenceDetect() " "Error invalidating SPD in PNOR" ); } break; } #endif present = spdPresent( i_target ); if( present == false ) { TRACUCOMP( g_trac_spd, INFO_MRK"dimmPresenceDetect() " "Dimm was found to be NOT present." ); } else { TRACUCOMP( g_trac_spd, INFO_MRK"dimmPresenceDetect() " "Dimm was found to be present." ); } #if defined(CONFIG_DJVPD_READ_FROM_HW) && defined(CONFIG_DJVPD_READ_FROM_PNOR) if( present ) { // Check if the VPD data in the PNOR matches the SEEPROM err = VPD::ensureCacheIsInSync( i_target ); if( err ) { present = false; TRACFCOMP( g_trac_spd, ERR_MRK"dimmPresenceDetect() " "Error during ensureCacheIsInSync (SPD)" ); break; } } else { // SPD is not present, invalidate the SPD in PNOR err = VPD::invalidatePnorCache(i_target); if (err) { TRACFCOMP( g_trac_spd, ERR_MRK"dimmPresenceDetect() " "Error invalidating SPD in PNOR" ); } } #endif if( present && !err ) { //Fsp sets PN/SN so if there is none, do it here if(!INITSERVICE::spBaseServicesEnabled()) { //populate serial and part number attributes SPD::setPartAndSerialNumberAttributes( i_target ); } // Read ATTR_CLEAR_DIMM_SPD_ENABLE attribute TARGETING::Target* l_sys = NULL; TARGETING::targetService().getTopLevelTarget(l_sys); TARGETING::ATTR_CLEAR_DIMM_SPD_ENABLE_type l_clearSPD = l_sys->getAttr<TARGETING::ATTR_CLEAR_DIMM_SPD_ENABLE>(); // If SPD clear is enabled then write 0's into magic word for // DIMM_BAD_DQ_DATA keyword // Note: If there's an error from performing the clearing, // just log the error and continue. if (l_clearSPD) { size_t l_size = 0; // Do a read to get the DIMM_BAD_DQ_DATA keyword size err = deviceRead(i_target, NULL, l_size, DEVICE_SPD_ADDRESS( DIMM_BAD_DQ_DATA )); if (err) { TRACFCOMP( g_trac_spd, ERR_MRK"dimmPresenceDetect() " "Error reading DIMM_BAD_DQ_DATA keyword size"); errlCommit( err, VPD_COMP_ID ); } else { // Clear the data TRACFCOMP( g_trac_spd, "Clearing out BAD_DQ_DATA SPD on " "DIMM HUID 0x%X", TARGETING::get_huid(i_target)); uint8_t * l_data = static_cast<uint8_t*>(malloc( l_size )); memset(l_data, 0, l_size); err = deviceWrite(i_target, l_data, l_size, DEVICE_SPD_ADDRESS( DIMM_BAD_DQ_DATA )); if (err) { TRACFCOMP(g_trac_spd, ERR_MRK"dimmPresenceDetect() " "Error trying to clear SPD on DIMM HUID 0x%X", TARGETING::get_huid(i_target)); errlCommit( err, VPD_COMP_ID ); } // Free the memory if (NULL != l_data) { free(l_data); } } } } // copy present value into output buffer so caller can read it memcpy( io_buffer, &present, presentSz ); io_buflen = presentSz; } while( 0 ); TRACSSCOMP( g_trac_spd, EXIT_MRK"dimmPresenceDetect()" ); return err; } // end dimmPresenceDetect
errlHndl_t fsiScomPerformOp(DeviceFW::OperationType i_opType, TARGETING::Target* i_target, void* io_buffer, size_t& io_buflen, int64_t i_accessType, va_list i_args) { errlHndl_t l_err = NULL; uint64_t l_scomAddr = va_arg(i_args,uint64_t); ioData6432 scratchData; uint32_t l_command = 0; uint32_t l_status = 0; bool need_unlock = false; size_t op_size = sizeof(uint32_t); mutex_t* l_mutex = NULL; do{ if( io_buflen != sizeof(uint64_t) ) { TRACFCOMP( g_trac_fsiscom, ERR_MRK "fsiScomPerformOp> Invalid data length : io_buflen=%d", io_buflen ); /*@ * @errortype * @moduleid FSISCOM::MOD_FSISCOM_PERFORMOP * @reasoncode FSISCOM::RC_INVALID_LENGTH * @userdata1 SCOM Address * @userdata2 Data Length * @devdesc fsiScomPerformOp> Invalid data length (!= 8 bytes) * @custdesc A problem occurred during the IPL of the system: * Invalid data length for a SCOM operation. */ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, FSISCOM::MOD_FSISCOM_PERFORMOP, FSISCOM::RC_INVALID_LENGTH, l_scomAddr, TO_UINT64(io_buflen)); l_err->addProcedureCallout( HWAS::EPUB_PRC_HB_CODE, HWAS::SRCI_PRIORITY_LOW ); ERRORLOG::ErrlUserDetailsTarget(i_target,"SCOM Target"). addToLog(l_err); break; } if( (l_scomAddr & 0xFFFFFFFF80000000) != 0) { TRACFCOMP( g_trac_fsiscom, ERR_MRK "fsiScomPerformOp> Address contains more than 31 bits : l_scomAddr=0x%.16X", l_scomAddr ); /*@ * @errortype * @moduleid FSISCOM::MOD_FSISCOM_PERFORMOP * @reasoncode FSISCOM::RC_INVALID_ADDRESS * @userdata1 SCOM Address * @userdata2 Target HUID * @devdesc fsiScomPerformOp> Address contains * more than 31 bits. * @custdesc A problem occurred during the IPL of the system: * Invalid address on a SCOM operation. */ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, FSISCOM::MOD_FSISCOM_PERFORMOP, FSISCOM::RC_INVALID_ADDRESS, l_scomAddr, TARGETING::get_huid(i_target)); l_err->addProcedureCallout( HWAS::EPUB_PRC_HB_CODE, HWAS::SRCI_PRIORITY_LOW ); ERRORLOG::ErrlUserDetailsTarget(i_target,"SCOM Target"). addToLog(l_err); break; } l_command = static_cast<uint32_t>(l_scomAddr & 0x000000007FFFFFFF); // use the chip-specific mutex attribute l_mutex = i_target->getHbMutexAttr<TARGETING::ATTR_FSI_SCOM_MUTEX>(); if(i_opType == DeviceFW::WRITE) { memcpy(&(scratchData.data64), io_buffer, 8); TRACUCOMP( g_trac_fsiscom, "fsiScomPerformOp> Write(l_scomAddr=0x%X, l_data0=0x%X, l_data1=0x%X)", l_scomAddr, scratchData.data32_0, scratchData.data32_1); // atomic section >> mutex_lock(l_mutex); need_unlock = true; //write bits 0-31 to data0 l_err = DeviceFW::deviceOp( DeviceFW::WRITE, i_target, &scratchData.data32_0, op_size, DEVICE_FSI_ADDRESS(DATA0_REG)); if(l_err) { break; } //write bits 32-63 to data1 l_err = DeviceFW::deviceOp( DeviceFW::WRITE, i_target, &scratchData.data32_1, op_size, DEVICE_FSI_ADDRESS(DATA1_REG)); if(l_err) { break; } //write to FSI2PIB command reg starts write operation //bit 0 high => write command l_command = 0x80000000 | l_command; l_err = DeviceFW::deviceOp( DeviceFW::WRITE, i_target, &l_command, op_size, DEVICE_FSI_ADDRESS(COMMAND_REG)); if(l_err) { break; } //check status reg to see result l_err = DeviceFW::deviceOp( DeviceFW::READ, i_target, &l_status, op_size, DEVICE_FSI_ADDRESS(STATUS_REG)); if(l_err) { break; } // Check the status reg for errors if( (l_status & PIB_ERROR_BITS) // PCB/PIB Errors || (l_status & PIB_ABORT_BIT) ) // PIB Abort { TRACFCOMP( g_trac_fsiscom, ERR_MRK"fsiScomPerformOp:Write: PCB/PIB error received: l_status=0x%X)", l_status); /*@ * @errortype * @moduleid FSISCOM::MOD_FSISCOM_PERFORMOP * @reasoncode FSISCOM::RC_WRITE_ERROR * @userdata1 SCOM Addr * @userdata2[00:31] Target HUID * @userdata2[32:63] SCOM Status Reg * @devdesc fsiScomPerformOp> Error returned * from SCOM Engine after write * @custdesc A problem occurred during the IPL of the system: * Error returned from SCOM engine after write. */ l_err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, FSISCOM::MOD_FSISCOM_PERFORMOP, FSISCOM::RC_WRITE_ERROR, l_scomAddr, TWO_UINT32_TO_UINT64( TARGETING::get_huid(i_target), l_status)); // call common error handler to do callouts and recovery pib_error_handler( i_target, l_err, l_status, l_scomAddr ); //Grab the PIB2OPB Status reg for a XSCOM Block error if( (l_status & 0x00007000) == 0x00001000 ) //piberr=001 { //@todo: Switch to external FSI FFDC interfaces RTC:35064 TARGETING::Target* l_master = NULL; TARGETING::targetService(). masterProcChipTargetHandle(l_master); uint64_t scomdata = 0; size_t scomsize = sizeof(uint64_t); errlHndl_t l_err2 = DeviceFW::deviceOp( DeviceFW::READ, l_master, &scomdata, scomsize, DEVICE_XSCOM_ADDRESS(0x00020001)); if( l_err2 ) { delete l_err2; } else { TRACFCOMP( g_trac_fsiscom, "PIB2OPB Status = %.16X", scomdata ); } } break; } // atomic section << need_unlock = false; mutex_unlock(l_mutex); } else if(i_opType == DeviceFW::READ) { TRACUCOMP( g_trac_fsiscom, "fsiScomPerformOp: Read(l_scomAddr=0x%.8X)", l_scomAddr); // atomic section >> mutex_lock(l_mutex); need_unlock = true; //write to FSI2PIB command reg starts read operation // bit 0 low -> read command l_err = DeviceFW::deviceOp( DeviceFW::WRITE, i_target, &l_command, op_size, DEVICE_FSI_ADDRESS(COMMAND_REG)); if(l_err) { break; } //check ststus reg to see result l_err = DeviceFW::deviceOp( DeviceFW::READ, i_target, &l_status, op_size, DEVICE_FSI_ADDRESS(STATUS_REG)); if(l_err) { break; } // Check the status reg for errors if( (l_status & PIB_ERROR_BITS) // PCB/PIB Errors || (l_status & PIB_ABORT_BIT) ) // PIB Abort { TRACFCOMP( g_trac_fsiscom, ERR_MRK"fsiScomPerformOp:Read: PCB/PIB error received: l_status=0x%0.8X)", l_status); /*@ * @errortype * @moduleid FSISCOM::MOD_FSISCOM_PERFORMOP * @reasoncode FSISCOM::RC_READ_ERROR * @userdata1 SCOM Addr * @userdata2[00:31] Target HUID * @userdata2[32:63] SCOM Status Reg * @devdesc fsiScomPerformOp> Error returned from SCOM Engine after read. * @custdesc A problem occurred during the IPL of the system: * Error returned from SCOM engine after read. */ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, FSISCOM::MOD_FSISCOM_PERFORMOP, FSISCOM::RC_READ_ERROR, l_scomAddr, TWO_UINT32_TO_UINT64( TARGETING::get_huid(i_target), l_status)); // call common error handler to do callouts and recovery pib_error_handler( i_target, l_err, l_status, l_scomAddr ); break; } //read bits 0-31 to data0 l_err = DeviceFW::deviceOp( DeviceFW::READ, i_target, &scratchData.data32_0, op_size, DEVICE_FSI_ADDRESS(DATA0_REG)); if(l_err) { break; } //read bits 32-63 to data1 l_err = DeviceFW::deviceOp( DeviceFW::READ, i_target, &scratchData.data32_1, op_size, DEVICE_FSI_ADDRESS(DATA1_REG)); if(l_err) { break; } // atomic section << need_unlock = false; mutex_unlock(l_mutex); TRACUCOMP( g_trac_fsiscom, "fsiScomPerformOp: Read: l_scomAddr=0x%X, l_data0=0x%X, l_data1=0x%X", l_scomAddr, scratchData.data32_0, scratchData.data32_1); memcpy(io_buffer, &(scratchData.data64), 8); } else { TRACFCOMP( g_trac_fsiscom, ERR_MRK"fsiScomPerformOp:Unsupported Operation Type: i_opType=%d)", i_opType); /*@ * @errortype * @moduleid FSISCOM::MOD_FSISCOM_PERFORMOP * @reasoncode FSISCOM::RC_INVALID_OPTYPE * @userdata1[0:31] Operation Type (i_opType) : 0=READ, 1=WRITE * @userdata1[32:64] Input scom address * @userdata2 Target HUID * @devdesc fsiScomPerformOp> Unsupported Operation Type specified * @custdesc A problem occurred during the IPL of the system: * Unsupported SCOM operation type. */ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, FSISCOM::MOD_FSISCOM_PERFORMOP, FSISCOM::RC_INVALID_OPTYPE, TWO_UINT32_TO_UINT64(i_opType, l_scomAddr), TARGETING::get_huid(i_target), true /*SW error*/); //Add this target to the FFDC ERRORLOG::ErrlUserDetailsTarget(i_target,"SCOM Target"). addToLog(l_err); break; } }while(0); if( need_unlock && l_mutex ) { mutex_unlock(l_mutex); } return l_err; }