blob: 00f7830cc9a1c38b3eeaea90306bd70654c5088f [file] [log] [blame]
#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