blob: b4389dff20ec10e0effda53bd244a245b091151e [file] [log] [blame]
#include <attn/attention.hpp>
#include <attn/attn_common.hpp>
#include <attn/attn_dump.hpp>
#include <attn/attn_handler.hpp>
#include <attn/attn_logging.hpp>
#include <sdbusplus/bus.hpp>
#include <util/dbus.hpp>
#include <util/pdbg.hpp>
#include <util/pldm.hpp>
#include <util/trace.hpp>
namespace attn
{
/*
* @brief Request SBE hreset and try to clear sbe attentions
*
* @param[in] sbeInstance - sbe instance to hreset (0 based)
*
* @return true if hreset is successful and attentions cleared
*/
bool attemptSbeRecovery(int sbeInstance)
{
// attempt sbe hreset and attention interrupt clear
if (!util::pldm::hresetSbe(sbeInstance))
{
return false;
}
trace::inf("hreset completed");
// try to clear attention interrupts
clearAttnInterrupts();
// loop through processors checking attention interrupts
bool recovered = true;
pdbg_target* procTarget;
pdbg_for_each_class_target("proc", procTarget)
{
// active processors only
if (PDBG_TARGET_ENABLED !=
pdbg_target_probe(util::pdbg::getPibTrgt(procTarget)))
{
continue;
}
// get cfam is an fsi read
pdbg_target* fsiTarget = util::pdbg::getFsiTrgt(procTarget);
uint32_t int_val;
// get attention interrupts on processor
if (RC_SUCCESS == fsi_read(fsiTarget, 0x100b, &int_val))
{
if (int_val & SBE_ATTN)
{
trace::err("sbe attention did not clear");
recovered = false;
break;
}
}
else
{
// log cfam read error
trace::err("cfam read error");
recovered = false;
break;
}
}
if (recovered)
{
trace::inf("sbe attention cleared");
}
return recovered;
}
/**
* @brief Check for active checkstop attention
*
* @param procInstance - proc to check for attentions
*
* @pre pdbg target associated with proc instance is enabled for fsi access
*
* @return true if checkstop acive false otherwise
* */
bool checkstopActive(int procInstance)
{
// get fsi target
char path[16];
sprintf(path, "/proc%d/fsi", procInstance);
pdbg_target* fsiTarget = pdbg_target_from_path(nullptr, path);
if (nullptr == fsiTarget)
{
trace::inf("fsi path or target not found");
return false;
}
// check for active checkstop attention
int r;
uint32_t isr_val, isr_mask;
isr_val = 0xffffffff;
r = fsi_read(fsiTarget, 0x1007, &isr_val);
if ((RC_SUCCESS != r) || (0xffffffff == isr_val))
{
trace::err("cfam 1007 read error");
return false;
}
isr_mask = 0xffffffff;
r = fsi_read(fsiTarget, 0x100d, &isr_mask);
if ((RC_SUCCESS != r) || (0xffffffff == isr_mask))
{
trace::err("cfam 100d read error");
return false;
}
return activeAttn(isr_val, isr_mask, CHECKSTOP_ATTN);
}
/**
* @brief Handle SBE vital attention
*
* @param i_attention - attention object
*
* @return non-zero if attention was not successfully handled
*/
int handleVital(Attention* i_attention)
{
trace::inf("vital handler started");
// if vital handling disabled
if (false == (i_attention->getConfig()->getFlag(enVital)))
{
trace::inf("vital handling disabled");
return RC_NOT_HANDLED;
}
// if power fault then we don't do anything
sleepSeconds(POWER_FAULT_WAIT);
if (util::dbus::powerFault())
{
trace::inf("power fault was reported");
return RC_SUCCESS;
}
// if no checkstop and host is running
int instance =
pdbg_target_index(i_attention->getTarget()); // get processor number
if (!checkstopActive(instance) &&
util::dbus::HostRunningState::Started == util::dbus::hostRunningState())
{
// attempt to recover the sbe
if (attemptSbeRecovery(instance))
{
eventVital(levelPelInfo);
return RC_SUCCESS;
}
}
// host not running, checkstop active or recovery failed
auto pelId = eventVital(levelPelError);
requestDump(pelId, DumpParameters{0, DumpType::SBE});
util::dbus::transitionHost(util::dbus::HostState::Quiesce);
return RC_SUCCESS;
}
} // namespace attn