errlHndl_t mboxddShutDown(TARGETING::Target* i_target) { size_t scom_len = sizeof(uint64_t); uint64_t scom_data = 0; errlHndl_t err = mboxddMaskInterrupts(i_target); if(!err) { // Clear the status reg //Turn off Permission to Send //Turn off everything possible err = deviceOp(DeviceFW::WRITE, i_target, reinterpret_cast<void*>(&scom_data), scom_len, DEVICE_XSCOM_ADDRESS(MBOX_DB_STAT_CNTRL_1)); } // Clear any pending stuff if(!err) { err = deviceOp(DeviceFW::READ, i_target, reinterpret_cast<void*>(&scom_data), scom_len, DEVICE_XSCOM_ADDRESS(MBOX_DB_INT_REG_PIB)); } if(!err) { err = deviceOp(DeviceFW::WRITE, i_target, reinterpret_cast<void*>(&scom_data), scom_len, DEVICE_XSCOM_ADDRESS(MBOX_DB_INT_REG_PIB)); } // Others? return err; }
errlHndl_t mboxddEnableInterrupts(TARGETING::Target * i_target) { errlHndl_t err = NULL; size_t scom_len = sizeof(uint64_t); // Setup mailbox intr mask reg // Set bits 2,1,0 // assume we always use mailbox 1 uint64_t scom_data = (static_cast<uint64_t>(MBOX_DOORBELL_ERROR) | static_cast<uint64_t>(MBOX_HW_ACK) | static_cast<uint64_t>(MBOX_DATA_PENDING)) << 32; err = deviceOp(DeviceFW::WRITE, i_target, reinterpret_cast<void*>(&scom_data), scom_len, DEVICE_XSCOM_ADDRESS(MBOX_DB_INT_MASK_PIB_RS)); return err; }
errlHndl_t mboxddMaskInterrupts(TARGETING::Target * i_target) { errlHndl_t err = NULL; // Mask off all interrupts // Reset intr enable bits by setting the bits in MBOX_DB_INT_MASK_PIB_RC uint64_t scom_data = (static_cast<uint64_t>(MBOX_DOORBELL_ERROR) | static_cast<uint64_t>(MBOX_HW_ACK) | static_cast<uint64_t>(MBOX_DATA_PENDING)) << 32; size_t scom_len = sizeof(uint64_t); err = deviceOp(DeviceFW::WRITE, i_target, reinterpret_cast<void*>(&scom_data), scom_len, DEVICE_XSCOM_ADDRESS(MBOX_DB_INT_MASK_PIB_RC)); return err; }
/** * @brief Reads the mailbox PIB error status register */ errlHndl_t mboxGetErrStat(TARGETING::Target* i_target,uint64_t &o_status) { errlHndl_t l_err = NULL; uint32_t l_64bitBuf[2] = {0}; size_t l_64bitSize = sizeof(uint64_t); do { l_err = deviceOp(DeviceFW::READ,i_target, l_64bitBuf,l_64bitSize, DEVICE_XSCOM_ADDRESS(MBOX_DB_ERR_STAT_PIB)); if (l_err) { TRACFCOMP(g_trac_mbox, ERR_MRK "mboxGetErrStat> Unable to read PIB Error Status"); break; } else { //Check for Illegal Op if ((l_64bitBuf[0] & MBOX_ILLEGAL_OP) == MBOX_ILLEGAL_OP) { o_status |= MBOX_ILLEGAL_OP; } //Check for Write Full if ((l_64bitBuf[0] & MBOX_DATA_WRITE_ERR) == MBOX_DATA_WRITE_ERR) { o_status |= MBOX_DATA_WRITE_ERR; } //Check for Read Empty if ((l_64bitBuf[0] & MBOX_DATA_READ_ERR) == MBOX_DATA_READ_ERR) { o_status |= MBOX_DATA_READ_ERR; } //Check for Parity Error & add address of parity error if ((l_64bitBuf[0] & MBOX_PARITY_ERR) == MBOX_PARITY_ERR) { o_status |= MBOX_PARITY_ERR; uint64_t l_temp = (l_64bitBuf[0] & 0x00FF0000); o_status |= (l_temp << 40); } } //Write '1' to Clear Status(16) l_64bitBuf[0] = 0x00010000; l_err = deviceOp(DeviceFW::WRITE,i_target, l_64bitBuf,l_64bitSize, DEVICE_XSCOM_ADDRESS(MBOX_DB_ERR_STAT_PIB)); if (l_err) { TRACFCOMP(g_trac_mbox, ERR_MRK "mboxGetErrStat> Unable to clear PIB Error Status"); break; } } while(0); return l_err; }
/** * @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; }
/** * @brief Performs a mailbox read operation */ errlHndl_t mboxRead(TARGETING::Target* i_target,void *o_buffer, size_t &io_buflen,uint64_t* o_status) { uint64_t l_stat = 0; errlHndl_t l_err = NULL; uint32_t l_64bitBuf[2] = {0}; uint32_t l_StatusReg[2] = {0}; uint32_t l_IntReg[2] = {0}; size_t l_64bitSize = sizeof(uint64_t); size_t input_buflen = io_buflen; io_buflen = 0; do { // no longer check for buffer length.. MBox DD will pass back the max // allowed data if the buflen is > the max size. This is done prior // to reading the data from the mbox registers. // Read the Int Reg B l_err = deviceOp(DeviceFW::READ,i_target, l_IntReg,l_64bitSize, DEVICE_XSCOM_ADDRESS(MBOX_DB_INT_REG_PIB)); if (l_err) { TRACFCOMP(g_trac_mbox, ERR_MRK "mboxRead> Unable to read PIB Interrupt Register"); break; } /*if nothing on in the interrupt reg -- nothing for this function to do*/ if(!(l_IntReg[0])) { break; } // Check to see if there is an error bit set. if ((l_IntReg[0] & MBOX_DOORBELL_ERROR) == MBOX_DOORBELL_ERROR) { TRACFCOMP(g_trac_mbox, INFO_MRK "mboxRead> Found interrupt on error status register"); // Go get the error info l_err = mboxGetErrStat(i_target,l_stat); if (l_err) { break; } } #if defined(__DESTRUCTIVE_MBOX_TEST__) if(g_forceError) { TRACFCOMP(g_trac_mbox,"MBOXDD> forcing error!"); g_forceError = false; l_stat |= MBOX_DOORBELL_ERROR | MBOX_DATA_WRITE_ERR; } #endif // No errors so read the doorbell status and control 1a register 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 "mboxRead> 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 */ //If the Acknowledge bit is on and the Xup bit is on if ((l_IntReg[0] & MBOX_HW_ACK) == MBOX_HW_ACK && (l_64bitBuf[0] & MBOX_XUP) == MBOX_XUP) { l_stat |= MBOX_HW_ACK; l_StatusReg[0] |= MBOX_XUP; } //Check for PIB Pending. If PIB pending is found then we need // to go read the data from the mailbox registers. if ((l_IntReg[0] & MBOX_DATA_PENDING) == MBOX_DATA_PENDING && (l_64bitBuf[0] & MBOX_PIB_SLAVE_A_PND) == MBOX_PIB_SLAVE_A_PND) { l_stat |= MBOX_DATA_PENDING; //Set the io_buflen to the number of bytes of data available to // be read. io_buflen = (l_64bitBuf[0] & MBOX_DATA_LBUS_SLAVE_B); // If the buffer length passed in is less than the data size read, // then set the buffer length to the passed in size and only read // that much data. (truncate the data to fit into the buffer) // Conversely, if the input_buflen is greater than the size of the // data read, the io_buflen returned to the user becomes the size // of the data read. if (input_buflen < io_buflen) { TRACFCOMP(g_trac_mbox, INFO_MRK "mboxRead> Data truncated, input buffer length less than number of significant bytes"); // set the io_buflen to the size of the buffer passed in. // which will only read enough data to fill the buffer. io_buflen = input_buflen; } // Current register counter indicating which of the mbox registers // we are currently reading from. uint32_t cur_reg_cntr = 0; uint32_t l_data[2]; // Total number of registers to read to get all the data. uint8_t l_numRegsToRead = (io_buflen*sizeof(uint8_t))/sizeof(uint32_t); uint8_t l_numBytesLeft = (io_buflen*sizeof(uint8_t))%sizeof(uint32_t); if (l_numBytesLeft != 0) { l_numRegsToRead++; } uint32_t *local_buf = static_cast<uint32_t *>(o_buffer); // For the read we extract the data from the MBOX data registers. // MBOX_DATA_LBUS_START = 0x00050080 and the end address is // MBOX_DATA_LBUS_END = 0x0005008F // each address inbetween increments by 1. //Loop through the mbox registers until all the data to be read has // been extracted from the mbox registers. while (cur_reg_cntr < l_numRegsToRead) { l_err = deviceOp(DeviceFW::READ,i_target, l_data,l_64bitSize, DEVICE_XSCOM_ADDRESS(MBOX_DATA_LBUS_START+cur_reg_cntr)); if (l_err) { TRACFCOMP(g_trac_mbox, ERR_MRK "mboxRead> Unable to read Data Area Register 0x%X",MBOX_DATA_LBUS_START+cur_reg_cntr); break; } // Need to check here to make sure we are not overrunning our // buffer. // If this is the last register we need to read and we are not word aligned if (((cur_reg_cntr + 1) == l_numRegsToRead) && (l_numBytesLeft != 0)) { // Only copy the number of bytes remaining.. memcpy( local_buf + cur_reg_cntr, &l_data[0], l_numBytesLeft); } // normal copy path.. copy the entire word. else { memcpy( local_buf + cur_reg_cntr, &l_data[0], sizeof(uint32_t)); } cur_reg_cntr++; } if (l_err) { break; } //Write-to-Clear Xup,and bits 20-32 (data and header count) //Write to set Xup (by setting PIB_SLAVE_PND) //Write the Xdn to indicate read is done l_StatusReg[0] |= MBOX_PIB_SLAVE_A_PND | MBOX_XDN | MBOX_HDR_LBUS_SLAVE_B | MBOX_DATA_LBUS_SLAVE_B; } //Write to clear PIB Pending, Abort, and XUP (all that apply) if(l_StatusReg[0]) { l_err = deviceOp(DeviceFW::WRITE,i_target, l_StatusReg,l_64bitSize, DEVICE_XSCOM_ADDRESS(MBOX_DB_STAT_CNTRL_1)); if (l_err) { TRACFCOMP(g_trac_mbox, ERR_MRK "mboxRead> Unable to clear Doorbell Status/Control Register"); break; } } //Write-to-Clear 'on' bits of interrupt reg if(l_IntReg[0]) { l_err = deviceOp(DeviceFW::WRITE,i_target, l_IntReg,l_64bitSize, DEVICE_XSCOM_ADDRESS(MBOX_DB_INT_REG_PIB)); if (l_err) { TRACFCOMP(g_trac_mbox, ERR_MRK "mboxRead> Unable to clear PIB Interrupt Register"); break; } } } while(0); (*o_status) = l_stat; return l_err; }
errlHndl_t doScomOp(DeviceFW::OperationType i_opType, TARGETING::Target* i_target, void* io_buffer, size_t& io_buflen, int64_t i_accessType, uint64_t i_addr) { errlHndl_t l_err = NULL; do{ TARGETING::ScomSwitches scomSetting; scomSetting.useXscom = true; //Default to Xscom supported. if(TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL != i_target) { scomSetting = i_target->getAttr<TARGETING::ATTR_SCOM_SWITCHES>(); } //Always XSCOM the Master Sentinel if((TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL == i_target) || (scomSetting.useXscom)) { //do XSCOM l_err = deviceOp(i_opType, i_target, io_buffer, io_buflen, DEVICE_XSCOM_ADDRESS(i_addr)); break; } else if(scomSetting.useInbandScom) { //do IBSCOM l_err = deviceOp(i_opType, i_target, io_buffer, io_buflen, DEVICE_IBSCOM_ADDRESS(i_addr)); if( l_err ) { break; } } else if(scomSetting.useFsiScom) { //do FSISCOM l_err = deviceOp(i_opType, i_target, io_buffer, io_buflen, DEVICE_FSISCOM_ADDRESS(i_addr)); if( l_err ) { break; } } else { assert(0,"SCOM::scomPerformOp> ATTR_SCOM_SWITCHES does not indicate Xscom, Ibscom, or FSISCOM is supported. i_target=0x%.8x", get_huid(i_target)); break; } }while(0); //Look for special retry codes if( l_err && (0xFFFFFFFF != i_accessType) && (l_err->reasonCode() == IBSCOM::IBSCOM_RETRY_DUE_TO_ERROR) ) { delete l_err; TRACFCOMP(g_trac_scom, "Forcing retry of Scom to %.16X on %.8X", i_addr, TARGETING::get_huid(i_target)); // use the unused i_accessType parameter to avoid an infinite recursion int64_t accessType_flag = 0xFFFFFFFF; l_err = doScomOp( i_opType, i_target, io_buffer, io_buflen, accessType_flag, i_addr ); } //Add some additional FFDC based on the specific operation if( l_err ) { addScomFailFFDC( l_err, i_target, i_addr ); } return l_err; }
/** * @brief Collect XSCOM FFDC data and add to the originating xscom failing * errorlog. * * @param[in] i_target XSCom target * @param[in] i_virtAddr Target's virtual address * @param[in/out] io_errl Originating errorlog that we will add FFDC data * to * @return none */ void collectXscomFFDC(TARGETING::Target* i_target, uint64_t* i_virtAddr, errlHndl_t& io_errl) { errlHndl_t l_err = NULL; HMER l_hmer; uint64_t io_buffer = 0; size_t io_buflen = XSCOM_BUFFER_SIZE; uint64_t* l_virtAddr = 0; // xscom registers that need to be set. XscomAddrType_t XscomAddr[4] = { {0x0202000F, CurThreadCpu}, {0x02020004, TargetCpu}, {0x02020007, TargetCpu}, {0x02020009, TargetCpu},}; TRACFCOMP(g_trac_xscom,"collectXscomFFDC: XSCOM COLLECT FFDC STARTED"); ERRORLOG::ErrlUserDetailsLogRegister l_logReg(i_target); // Loop through the addresses you want to collect. for (int i = 0; i<4; i++) { // If collecting first address, need to collect from Source Chip if (XscomAddr[i].target_type == CurThreadCpu) { l_virtAddr = getCpuIdVirtualAddress(); } else { l_virtAddr = i_virtAddr; } //********************************************************* // READ SCOM ADDR //********************************************************* l_err = xScomDoOp(DeviceFW::READ, l_virtAddr, XscomAddr[i].addr, &io_buffer, io_buflen, l_hmer); // If not successful if (l_err) { delete l_err; TRACFCOMP(g_trac_xscom,ERR_MRK "XSCOM Collect FFDC FAILED: XscomAddr = %.16llx, VAddr=%llx",XscomAddr[i], l_virtAddr); } // only add the Register data to the originating errorlog if successful else { // Collect the data from the read l_logReg.addDataBuffer(&io_buffer, sizeof(io_buffer), DEVICE_XSCOM_ADDRESS(XscomAddr[i].addr)); } // unmap the device now that we are done with the scom to that area. if (XscomAddr[i].target_type == CurThreadCpu) { mmio_dev_unmap(reinterpret_cast<void*>(l_virtAddr)); } } // Add the register FFDC to the errorlog passed in. l_logReg.addToLog(io_errl); return; }
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; }