blob: 476b893b01c6ab175267cce1935b0595f998961b [file] [log] [blame]
#include "extensions/phal/create_pel.hpp"
#include "extensions/phal/dump_utils.hpp"
#include "registration.hpp"
#include <attributes_info.H>
#include <fmt/format.h>
#include <libphal.H>
#include <phal_exception.H>
extern "C"
{
#include <libpdbg.h>
}
#include <phosphor-logging/log.hpp>
namespace openpower
{
namespace phal
{
using namespace openpower::pel;
using namespace openpower::phal::exception;
using namespace phosphor::logging;
/**
* @brief Stop instruction executions on all functional threads in the
* host processors.
* This procedure is used to stop all threads in the system in
* Attempt best case approch. Like issue processor level stopall
* chip-op with ignore hardware error mode. Since this function
* is used in power-off/error path, ignore the internal error now.
*/
void threadStopAll(void)
{
// CMD details based on SBE spec, used for logging purpose
constexpr auto SBEFIFO_CMD_CLASS_INSTRUCTION = 0xA700;
constexpr auto SBEFIFO_CMD_CONTROL_INSN = 0x01;
uint32_t cmd = SBEFIFO_CMD_CLASS_INSTRUCTION | SBEFIFO_CMD_CONTROL_INSN;
try
{
// initialize the pdbg.
openpower::phal::pdbg::init();
// Check Host is started.
if (!openpower::phal::sbe::isPrimaryIplDone())
{
log<level::INFO>("threadStopAll : skipping, Host is not running");
return;
}
struct pdbg_target* procTarget;
ATTR_HWAS_STATE_Type hwasState;
pdbg_for_each_class_target("proc", procTarget)
{
if (DT_GET_PROP(ATTR_HWAS_STATE, procTarget, hwasState))
{
log<level::ERR>(
fmt::format("({})Could not read HWAS_STATE attribute",
pdbg_target_path(procTarget))
.c_str());
continue;
}
if (!hwasState.functional)
{
continue;
}
try
{
openpower::phal::sbe::threadStopProc(procTarget);
}
catch (const sbeError_t& sbeError)
{
auto errType = sbeError.errType();
// Create PEL only for valid SBE reported failures
if (errType == SBE_CMD_FAILED)
{
log<level::ERR>(
fmt::format("threadStopAll failed({}) on proc({})",
errType, pdbg_target_index(procTarget))
.c_str());
uint32_t index = pdbg_target_index(procTarget);
// To store additional data about ffdc.
FFDCData pelAdditionalData;
// SRC6 : [0:15] chip position
// [16:23] command class, [24:31] Type
pelAdditionalData.emplace_back(
"SRC6", std::to_string((index << 16) | cmd));
// Create informational error log.
createSbeErrorPEL(
"org.open_power.Processor.Error.SbeChipOpFailure",
sbeError, pelAdditionalData, Severity::Informational);
}
else
{
// SBE is not ready to accept chip-ops,
// Skip the request, no additional error handling required.
log<level::INFO>(
fmt::format("threadStopAll: Skipping ({}) on proc({})",
sbeError.what(),
pdbg_target_index(procTarget))
.c_str());
}
continue;
}
log<level::INFO>(
fmt::format("Processor thread stopall completed on proc({})",
pdbg_target_index(procTarget))
.c_str());
}
}
// Capture general exception
catch (const std::exception& ex)
{
// This failure could be related to BMC firmware
// Dont throw exception on failure because, need to proceed
// further to complete power-off/reboot.
log<level::ERR>(
fmt::format("threadStopAll: Exception({})", ex.what()).c_str());
// To store additional data about ffdc.
FFDCData pelAdditionalData;
// SRC6 : [0:15] chip position, setting 0xFF to indicate generic fail
// [16:23] command class, [24:31] Type
pelAdditionalData.emplace_back("SRC6",
std::to_string((0xFF << 16) | cmd));
json jsonCalloutDataList;
jsonCalloutDataList = json::array();
json jsonCalloutData;
jsonCalloutData["Procedure"] = "BMC0001";
jsonCalloutData["Priority"] = "H";
jsonCalloutDataList.emplace_back(jsonCalloutData);
openpower::pel::createErrorPEL(
"org.open_power.Processor.Error.SbeChipOpFailure",
jsonCalloutDataList, pelAdditionalData);
return;
}
}
REGISTER_PROCEDURE("threadStopAll", threadStopAll)
} // namespace phal
} // namespace openpower