| #include <fmt/format.h> |
| extern "C" |
| { |
| #include <libpdbg.h> |
| #include <libpdbg_sbe.h> |
| } |
| |
| #include <libphal.H> |
| |
| #include <phosphor-logging/log.hpp> |
| #include <watchdog_common.hpp> |
| #include <watchdog_dbus.hpp> |
| #include <watchdog_handler.hpp> |
| #include <watchdog_logging.hpp> |
| |
| namespace watchdog |
| { |
| namespace dump |
| { |
| |
| using namespace phosphor::logging; |
| |
| void triggerHostbootDump(const uint32_t timeout) |
| { |
| constexpr auto HOST_STATE_DIAGNOSTIC_MODE = |
| "obmc-host-diagnostic-mode@0.target"; |
| constexpr auto HOST_STATE_QUIESCE_TGT = "obmc-host-quiesce@0.target"; |
| |
| // Put system into diagnostic mode |
| transitionHost(HOST_STATE_DIAGNOSTIC_MODE); |
| |
| eventWatchdogTimeout(timeout); |
| |
| // Put system into quiesce state |
| transitionHost(HOST_STATE_QUIESCE_TGT); |
| } |
| |
| /** |
| * @brief get SBE special callout information |
| * |
| * @details This function adds the special sbe callout in the user provided |
| * json callout list. includes BMC0002 procedure callout with high priority |
| * and processor callout with medium priority. |
| * |
| * @param[in] procTarget - pdbg processor target |
| * @param[out] jsonCalloutDataList - reference to json callout list |
| */ |
| static void getSBECallout(struct pdbg_target* procTarget, |
| json& jsonCalloutDataList) |
| { |
| using namespace openpower::phal::pdbg; |
| json jsonProcedCallout; |
| |
| // Add procedure callout |
| jsonProcedCallout["Procedure"] = "BMC0002"; |
| jsonProcedCallout["Priority"] = "H"; |
| jsonCalloutDataList.emplace_back(jsonProcedCallout); |
| try |
| { |
| ATTR_LOCATION_CODE_Type locationCode; |
| // Initialize with default data. |
| memset(&locationCode, '\0', sizeof(locationCode)); |
| // Get location code information |
| openpower::phal::pdbg::getLocationCode(procTarget, locationCode); |
| json jsonProcCallout; |
| jsonProcCallout["LocationCode"] = locationCode; |
| jsonProcCallout["Deconfigured"] = false; |
| jsonProcCallout["Guarded"] = false; |
| jsonProcCallout["Priority"] = "M"; |
| jsonCalloutDataList.emplace_back(jsonProcCallout); |
| } |
| catch (const std::exception& e) |
| { |
| log<level::ERR>(fmt::format("getLocationCode({}): Exception({})", |
| pdbg_target_path(procTarget), e.what()) |
| .c_str()); |
| } |
| } |
| |
| void handleSbeBootError(struct pdbg_target* procTarget, const uint32_t timeout) |
| { |
| using namespace openpower::phal; |
| |
| sbeError_t sbeError; |
| bool dumpIsRequired = false; |
| |
| try |
| { |
| // Capture FFDC information on primary processor |
| sbeError = sbe::captureFFDC(procTarget); |
| } |
| catch (const std::exception& e) |
| { |
| // Failed to collect FFDC information |
| log<level::ERR>( |
| fmt::format("captureFFDC: Exception{}", e.what()).c_str()); |
| dumpIsRequired = true; |
| } |
| |
| // event type |
| std::string event; |
| if ((sbeError.errType() == exception::SBE_FFDC_NO_DATA) || |
| (sbeError.errType() == exception::SBE_CMD_TIMEOUT) || (dumpIsRequired)) |
| { |
| log<level::INFO>("No FFDC data"); |
| event = "org.open_power.Processor.Error.SbeBootTimeout"; |
| dumpIsRequired = true; |
| } |
| else |
| { |
| log<level::ERR>("SBE Boot failure"); |
| event = "org.open_power.Processor.Error.SbeBootFailure"; |
| } |
| |
| // Additional data |
| std::map<std::string, std::string> additionalData; |
| |
| // SRC6 : [0:15] chip position |
| uint32_t index = pdbg_target_index(procTarget); |
| additionalData.emplace("SRC6", std::to_string(index << 16)); |
| additionalData.emplace("SBE_ERR_MSG", sbeError.what()); |
| |
| // FFDC |
| auto ffdc = std::vector<FFDCTuple>{}; |
| // get SBE ffdc file descriptor |
| auto fd = sbeError.getFd(); |
| |
| // Log error with additional ffdc if fd is valid |
| if (fd > 0) |
| { |
| ffdc.push_back( |
| std::make_tuple(sdbusplus::xyz::openbmc_project::Logging::server:: |
| Create::FFDCFormat::Custom, |
| static_cast<uint8_t>(0xCB), |
| static_cast<uint8_t>(0x01), sbeError.getFd())); |
| } |
| |
| std::unique_ptr<FFDCFile> ffdcFilePtr; |
| try |
| { |
| if (dumpIsRequired) |
| { |
| // Additional callout is required for SBE timeout case |
| // In this case no SBE FFDC information available and |
| // required to add default callouts. |
| json jsonCalloutDataList; |
| jsonCalloutDataList = json::array(); |
| getSBECallout(procTarget, jsonCalloutDataList); |
| ffdcFilePtr = std::make_unique<FFDCFile>(jsonCalloutDataList); |
| ffdc.push_back(std::make_tuple( |
| sdbusplus::xyz::openbmc_project::Logging::server::Create:: |
| FFDCFormat::JSON, |
| static_cast<uint8_t>(0xCA), static_cast<uint8_t>(0x01), |
| ffdcFilePtr->getFileDescriptor())); |
| } |
| } |
| catch (const std::exception& e) |
| { |
| log<level::ERR>( |
| fmt::format("Skipping SBE special callout due to Exception({})", |
| e.what()) |
| .c_str()); |
| } |
| auto pelId = createPel(event, additionalData, ffdc); |
| |
| if (dumpIsRequired) |
| { |
| try |
| { |
| using namespace openpower::phal; |
| |
| // Check SBE dump collection allowed |
| bool dumpAllowed = sbe::isDumpAllowed(procTarget); |
| if (!dumpAllowed) |
| { |
| // Possibly another collection in progress, skip dump collection |
| log<level::INFO>("Another collection is in progress, skipping " |
| "dump collection"); |
| return; |
| } |
| } |
| catch (const std::exception& e) |
| { |
| log<level::ERR>( |
| fmt::format("Exception {} occurred", e.what()).c_str()); |
| return; |
| } |
| |
| DumpParameters dumpParameters; |
| dumpParameters.logId = pelId; |
| dumpParameters.unitId = index; |
| dumpParameters.timeout = timeout; |
| dumpParameters.dumpType = DumpType::SBE; |
| |
| // will not return until dump is complete or timeout |
| requestDump(dumpParameters); |
| } |
| } |
| |
| } // namespace dump |
| } // namespace watchdog |