extern "C" { #include #include } #include #ifdef CONFIG_PHAL_API #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace attn { /** * @brief Handle checkstop attention * * @param i_attention Attention object * @return 0 indicates that the checkstop attention was successfully handled * 1 indicates that the checkstop attention was NOT successfully * handled. */ int handleCheckstop(Attention* i_attention); /** * @brief Handle special attention * * @param i_attention Attention object * @return 0 indicates that the special attention was successfully handled * 1 indicates that the special attention was NOT successfully handled */ int handleSpecial(Attention* i_attention); /** @brief Determine if attention is active and not masked */ bool activeAttn(uint32_t i_val, uint32_t i_mask, uint32_t i_attn); #ifdef CONFIG_PHAL_API /** @brief Handle phal sbe exception */ void phalSbeExceptionHandler(openpower::phal::exception::SbeError& e, uint32_t procNum); #endif /** @brief Get static TI info data based on host state */ void getStaticTiInfo(uint8_t*& tiInfoPtr); /** @brief Check if TI info data is valid */ bool tiInfoValid(uint8_t* tiInfo); /** * @brief The main attention handler logic * * @param i_breakpoints true = breakpoint special attn handling enabled */ void attnHandler(Config* i_config) { // Vector of active attentions to be handled std::vector active_attentions; uint32_t isr_val, isr_mask; // loop through processors looking for active attentions trace("Attention handler started"); pdbg_target* target; pdbg_for_each_class_target("proc", target) { if (PDBG_TARGET_ENABLED == pdbg_target_probe(target)) { auto proc = pdbg_target_index(target); // get processor number // Use PIB target to determine if a processor is enabled char path[16]; sprintf(path, "/proc%d/pib", proc); pdbg_target* pibTarget = pdbg_target_from_path(nullptr, path); // sanity check if (nullptr == pibTarget) { trace("pib path or target not found"); continue; } // check if pib target is enabled if (PDBG_TARGET_ENABLED == pdbg_target_probe(pibTarget)) { // The processor FSI target is required for CFAM read sprintf(path, "/proc%d/fsi", proc); pdbg_target* fsiTarget = pdbg_target_from_path(nullptr, path); // sanity check if (nullptr == fsiTarget) { trace("fsi path or target not found"); continue; } // trace the proc number std::string traceMsg = "proc: " + std::to_string(proc); trace(traceMsg.c_str()); isr_val = 0xffffffff; // invalid isr value // get active attentions on processor if (RC_SUCCESS != fsi_read(fsiTarget, 0x1007, &isr_val)) { // log cfam read error trace("Error! cfam read 0x1007 FAILED"); eventAttentionFail((int)AttnSection::attnHandler | ATTN_PDBG_CFAM); } else if (0xffffffff == isr_val) { trace("Error! cfam read 0x1007 INVALID"); continue; } else { // trace isr value std::stringstream ssIsr; ssIsr << "cfam 0x1007 = 0x" << std::setw(8) << std::setfill('0') << std::hex << isr_val; std::string strobjIsr = ssIsr.str(); trace(strobjIsr.c_str()); isr_mask = 0xffffffff; // invalid isr mask // get interrupt enabled special attentions mask if (RC_SUCCESS != fsi_read(fsiTarget, 0x100d, &isr_mask)) { // log cfam read error trace("Error! cfam read 0x100d FAILED"); eventAttentionFail((int)AttnSection::attnHandler | ATTN_PDBG_CFAM); } else if (0xffffffff == isr_mask) { trace("Error! cfam read 0x100d INVALID"); continue; } else { // trace true mask std::stringstream ssMask; ssMask << "cfam 0x100d = 0x" << std::setw(8) << std::setfill('0') << std::hex << isr_mask; std::string strobjMask = ssMask.str(); trace(strobjMask.c_str()); // SBE vital attention active and not masked? if (true == activeAttn(isr_val, isr_mask, SBE_ATTN)) { active_attentions.emplace_back(Attention::Vital, handleVital, target, i_config); } // Checkstop attention active and not masked? if (true == activeAttn(isr_val, isr_mask, CHECKSTOP_ATTN)) { active_attentions.emplace_back(Attention::Checkstop, handleCheckstop, target, i_config); } // Special attention active and not masked? if (true == activeAttn(isr_val, isr_mask, SPECIAL_ATTN)) { active_attentions.emplace_back(Attention::Special, handleSpecial, target, i_config); } } // cfam 0x100d valid } // cfam 0x1007 valid } // fsi target enabled } // pib target enabled } // next processor // convert to heap, highest priority is at front if (!std::is_heap(active_attentions.begin(), active_attentions.end())) { std::make_heap(active_attentions.begin(), active_attentions.end()); } // call the attention handler until one is handled or all were attempted while (false == active_attentions.empty()) { // handle highest priority attention, done if successful if (RC_SUCCESS == active_attentions.front().handle()) { // an attention was handled so we are done break; } // move attention to back of vector std::pop_heap(active_attentions.begin(), active_attentions.end()); // remove attention from vector active_attentions.pop_back(); } } /** * @brief Handle checkstop attention * * @param i_attention Attention object * @return 0 indicates that the checkstop attention was successfully handled * 1 indicates that the checkstop attention was NOT successfully * handled. */ int handleCheckstop(Attention* i_attention) { int rc = RC_SUCCESS; // assume checkstop handled trace("checkstop handler started"); // capture some additional data for logs/traces addHbStatusRegs(); // if checkstop handling enabled, handle checkstop attention if (false == (i_attention->getConfig()->getFlag(enCheckstop))) { trace("Checkstop handling disabled"); } else { // wait for power fault handling before starting analyses sleepSeconds(POWER_FAULT_WAIT); // Look for any attentions found in hardware. This will generate and // commit a PEL if any errors are found. DumpParameters dumpParameters; auto logid = analyzer::analyzeHardware(dumpParameters); if (0 == logid) { // A PEL should exist for a checkstop attention. rc = RC_ANALYZER_ERROR; } else { requestDump(logid, dumpParameters); util::dbus::transitionHost(util::dbus::HostState::Quiesce); } } return rc; } /** * @brief Handle special attention * * @param i_attention Attention object * @return 0 indicates that the special attention was successfully handled * 1 indicates that the special attention was NOT successfully handled */ int handleSpecial(Attention* i_attention) { int rc = RC_SUCCESS; // assume special attention handled // The TI info chipop will give us a pointer to the TI info data uint8_t* tiInfo = nullptr; // ptr to TI info data uint32_t tiInfoLen = 0; // length of TI info data pdbg_target* attnProc = i_attention->getTarget(); // proc with attention bool tiInfoStatic = false; // assume TI info was provided (not created) // need proc target to get dynamic TI info if (nullptr != attnProc) { #ifdef CONFIG_PHAL_API trace("using libphal to get TI info"); // phal library uses proc target for get ti info if (PDBG_TARGET_ENABLED == pdbg_target_probe(attnProc)) { try { // get dynamic TI info openpower::phal::sbe::getTiInfo(attnProc, &tiInfo, &tiInfoLen); } catch (openpower::phal::exception::SbeError& e) { // library threw an exception uint32_t procNum = pdbg_target_index(attnProc); phalSbeExceptionHandler(e, procNum); } } #else trace("using libpdbg to get TI info"); // pdbg library uses pib target for get ti info char path[16]; sprintf(path, "/proc%d/pib", pdbg_target_index(attnProc)); pdbg_target* tiInfoTarget = pdbg_target_from_path(nullptr, path); if (nullptr != tiInfoTarget) { if (PDBG_TARGET_ENABLED == pdbg_target_probe(tiInfoTarget)) { sbe_mpipl_get_ti_info(tiInfoTarget, &tiInfo, &tiInfoLen); } } #endif } // dynamic TI info is not available if (nullptr == tiInfo) { trace("TI info data ptr is invalid"); getStaticTiInfo(tiInfo); tiInfoStatic = true; } // check TI info for validity and handle if (true == tiInfoValid(tiInfo)) { // TI info is valid handle TI if support enabled if (true == (i_attention->getConfig()->getFlag(enTerminate))) { // Call TI special attention handler rc = tiHandler((TiDataArea*)tiInfo); } } else { trace("TI info NOT valid"); // if configured to handle TI as default special attention if (i_attention->getConfig()->getFlag(dfltTi)) { // TI handling may be disabled if (true == (i_attention->getConfig()->getFlag(enTerminate))) { // Call TI special attention handler rc = tiHandler((TiDataArea*)tiInfo); } } // configured to handle breakpoint as default special attention else { // breakpoint handling may be disabled if (true == (i_attention->getConfig()->getFlag(enBreakpoints))) { // Call the breakpoint special attention handler rc = bpHandler(); } } } // release TI data buffer if not ours if (false == tiInfoStatic) { // sanity check if (nullptr != tiInfo) { free(tiInfo); } } // trace non-successful exit condition if (RC_SUCCESS != rc) { trace("Special attn not handled"); } return rc; } /** * @brief Determine if attention is active and not masked * * Determine whether an attention needs to be handled and trace details of * attention type and whether it is masked or not. * * @param i_val attention status register * @param i_mask attention true mask register * @param i_attn attention type * @param i_proc processor associated with registers * * @return true if attention is active and not masked, otherwise false */ bool activeAttn(uint32_t i_val, uint32_t i_mask, uint32_t i_attn) { bool rc = false; // assume attn masked and/or inactive // if attention active if (0 != (i_val & i_attn)) { std::stringstream ss; bool validAttn = true; // known attention type switch (i_attn) { case SBE_ATTN: ss << "SBE attn"; break; case CHECKSTOP_ATTN: ss << "Checkstop attn"; break; case SPECIAL_ATTN: ss << "Special attn"; break; default: ss << "Unknown attn"; validAttn = false; } // see if attention is masked if (true == validAttn) { if (0 != (i_mask & i_attn)) { rc = true; // attention active and not masked } else { ss << " masked"; } } std::string strobj = ss.str(); // ss.str() is temporary trace(strobj.c_str()); // commit trace stream } return rc; } #ifdef CONFIG_PHAL_API /** * @brief Handle phal sbe exception * * @param[in] e - exception object * @param[in] procNum - processor number associated with sbe exception */ void phalSbeExceptionHandler(openpower::phal::exception::SbeError& e, uint32_t procNum) { // trace exception details std::string traceMsg = std::string(e.what()); trace(traceMsg.c_str()); // Handle SBE chipop timeout error if (e.errType() == openpower::phal::exception::SBE_CHIPOP_NOT_ALLOWED) { eventPhalSbeChipop(procNum); } } #endif /** * @brief Get static TI info data based on host state * * @param[out] tiInfo - pointer to static TI info data */ void getStaticTiInfo(uint8_t*& tiInfo) { util::dbus::HostRunningState runningState = util::dbus::hostRunningState(); // assume host state is unknown std::string stateString = "host state unknown"; if ((util::dbus::HostRunningState::Started == runningState) || (util::dbus::HostRunningState::Unknown == runningState)) { if (util::dbus::HostRunningState::Started == runningState) { stateString = "host started"; } tiInfo = (uint8_t*)defaultPhypTiInfo; } else { stateString = "host not started"; tiInfo = (uint8_t*)defaultHbTiInfo; } // trace host state trace(stateString.c_str()); } /** * @brief Check if TI info data is valid * * @param[in] tiInfo - pointer to TI info data * @return true if TI info data is valid, else false */ bool tiInfoValid(uint8_t* tiInfo) { bool tiInfoValid = false; // assume TI info invalid // TI info data[0] non-zero indicates TI info valid (usually) if ((nullptr != tiInfo) && (0 != tiInfo[0])) { TiDataArea* tiDataArea = (TiDataArea*)tiInfo; std::stringstream ss; // string stream object for tracing std::string strobj; // string object for tracing // trace a few known TI data area values ss.str(std::string()); // empty the stream ss.clear(); // clear the stream ss << "TI data command = 0x" << std::setw(2) << std::setfill('0') << std::hex << (int)tiDataArea->command; strobj = ss.str(); trace(strobj.c_str()); // Another check for valid TI Info since it has been seen that // tiInfo[0] != 0 but TI info is not valid if (0xa1 == tiDataArea->command) { tiInfoValid = true; // trace some more data since TI info appears valid ss.str(std::string()); // empty the stream ss.clear(); // clear the stream ss << "TI data term-type = 0x" << std::setw(2) << std::setfill('0') << std::hex << (int)tiDataArea->hbTerminateType; strobj = ss.str(); trace(strobj.c_str()); ss.str(std::string()); // empty the stream ss.clear(); // clear the stream ss << "TI data SRC format = 0x" << std::setw(2) << std::setfill('0') << std::hex << (int)tiDataArea->srcFormat; strobj = ss.str(); trace(strobj.c_str()); ss.str(std::string()); // empty the stream ss.clear(); // clear the stream ss << "TI data source = 0x" << std::setw(2) << std::setfill('0') << std::hex << (int)tiDataArea->source; strobj = ss.str(); trace(strobj.c_str()); } } return tiInfoValid; } } // namespace attn