summaryrefslogtreecommitdiffstats
path: root/extensions/openpower-pels/src.cpp
diff options
context:
space:
mode:
authorHarisuddin Mohamed Isa <harisuddin@gmail.com>2020-01-15 20:05:33 +0800
committerHarisuddin Mohamed Isa <harisuddin@gmail.com>2020-02-03 11:56:44 +0800
commit0f717e1063154f0baec62f80e043d4d1c3317ce0 (patch)
tree4c2e91a3a7fe18bdd7456c7a77212c8501d15bfe /extensions/openpower-pels/src.cpp
parent56e08263d6c3c7dccca02a7b3338cc0a37f4d716 (diff)
downloadphosphor-logging-0f717e1063154f0baec62f80e043d4d1c3317ce0.tar.gz
phosphor-logging-0f717e1063154f0baec62f80e043d4d1c3317ce0.zip
PEL: Print SRC section into JSON
For BMC created errors, look up the reason code in the message registry for error description and also meaning of data stored in hexwords 6-9 (if any). Added registry message field in peltool list output. "Primary SRC": { "Section Version": "1", "Sub-section type": "1", "Created by": "0x1000", "SRC Version": "0x02", "SRC Format": "0x55", "Power Control Net Fault": "False", "Error Details": { "Message": "PS 0x64 had a PGOOD Fault", "PS_NUM": "0x64" }, "Valid Word Count": "0x09", "Reference Code": "BD8D1001", "Hex Word 2": "00000055", "Hex Word 3": "00000010", "Hex Word 4": "00000000", "Hex Word 5": "00000000", "Hex Word 6": "00000064", "Hex Word 7": "00000000", "Hex Word 8": "00000000", "Hex Word 9": "00000000" } "Primary SRC": { "Section Version": "1", "Sub-section type": "0", "Created by": "0x4552", "SRC Version": "0x02", "SRC Format": "0x2008000", "Power Control Net Fault": "False", "Valid Word Count": "0x04", "Reference Code": "B2001020", "Hex Word 2": "02008000", "Hex Word 3": "00000000", "Hex Word 4": "00000012", "Callout Section": { "Callout Count": "1", "Callouts": [{ "FRU Type": "Symbolic FRU", "Priority": "Medium Priority", "Part Number": "NEXTLVL" }] } } Testing: Manually run peltool and verified out. All unit tests passed. Signed-off-by: Harisuddin Mohamed Isa <harisuddin@gmail.com> Change-Id: I124627ba785413ebda02305b7d9f95431922e714
Diffstat (limited to 'extensions/openpower-pels/src.cpp')
-rw-r--r--extensions/openpower-pels/src.cpp258
1 files changed, 257 insertions, 1 deletions
diff --git a/extensions/openpower-pels/src.cpp b/extensions/openpower-pels/src.cpp
index b2b86bf..570c6c6 100644
--- a/extensions/openpower-pels/src.cpp
+++ b/extensions/openpower-pels/src.cpp
@@ -15,13 +15,18 @@
*/
#include "src.hpp"
+#include "json_utils.hpp"
+#include "paths.hpp"
+#include "pel_values.hpp"
+
#include <phosphor-logging/log.hpp>
namespace openpower
{
namespace pels
{
-
+namespace pv = openpower::pels::pel_values;
+namespace rg = openpower::pels::message;
using namespace phosphor::logging;
void SRC::unflatten(Stream& stream)
@@ -177,5 +182,256 @@ void SRC::validate()
_valid = failed ? false : true;
}
+std::optional<std::string> SRC::getErrorDetails(message::Registry& registry,
+ DetailLevel type,
+ bool toCache) const
+{
+ const std::string jsonIndent(indentLevel, 0x20);
+ std::string errorOut;
+ uint8_t errorType =
+ strtoul(asciiString().substr(0, 2).c_str(), nullptr, 16);
+ if (errorType == static_cast<uint8_t>(SRCType::bmcError) ||
+ errorType == static_cast<uint8_t>(SRCType::powerError))
+ {
+ auto entry = registry.lookup("0x" + asciiString().substr(4, 4),
+ rg::LookupType::reasonCode, toCache);
+ if (entry)
+ {
+ errorOut.append(jsonIndent + "\"Error Details\": {\n");
+ auto errorMsg = getErrorMessage(*entry);
+ if (errorMsg)
+ {
+ if (type == DetailLevel::message)
+ {
+ return errorMsg.value();
+ }
+ else
+ {
+ jsonInsert(errorOut, "Message", errorMsg.value(), 2);
+ }
+ }
+ if (entry->src.hexwordADFields)
+ {
+ std::map<size_t, std::string> adFields =
+ entry->src.hexwordADFields.value();
+ for (const auto& hexwordMap : adFields)
+ {
+ jsonInsert(errorOut, hexwordMap.second,
+ getNumberString("0x%X",
+ _hexData[getWordIndexFromWordNum(
+ hexwordMap.first)]),
+ 2);
+ }
+ }
+ errorOut.erase(errorOut.size() - 2);
+ errorOut.append("\n");
+ errorOut.append(jsonIndent + "},\n");
+ return errorOut;
+ }
+ }
+ return std::nullopt;
+}
+
+std::optional<std::string>
+ SRC::getErrorMessage(const message::Entry& regEntry) const
+{
+ try
+ {
+ if (regEntry.doc.messageArgSources)
+ {
+ size_t msgLen = regEntry.doc.message.length();
+ char msg[msgLen + 1];
+ strcpy(msg, regEntry.doc.message.c_str());
+ std::vector<uint32_t> argSourceVals;
+ std::string message;
+ const auto& argValues = regEntry.doc.messageArgSources.value();
+ for (size_t i = 0; i < argValues.size(); ++i)
+ {
+ argSourceVals.push_back(_hexData[getWordIndexFromWordNum(
+ argValues[i].back() - '0')]);
+ }
+ const char* msgPointer = msg;
+ while (*msgPointer)
+ {
+ if (*msgPointer == '%')
+ {
+ msgPointer++;
+ size_t wordIndex = *msgPointer - '0';
+ if (isdigit(*msgPointer) && wordIndex >= 1 &&
+ static_cast<uint16_t>(wordIndex) <=
+ argSourceVals.size())
+ {
+ message.append(getNumberString(
+ "0x%X", argSourceVals[wordIndex - 1]));
+ }
+ else
+ {
+ message.append("%" + std::string(1, *msgPointer));
+ }
+ }
+ else
+ {
+ message.push_back(*msgPointer);
+ }
+ msgPointer++;
+ }
+ return message;
+ }
+ else
+ {
+ return regEntry.doc.message;
+ }
+ }
+ catch (const std::exception& e)
+ {
+ log<level::ERR>("Cannot get error message from registry entry",
+ entry("ERROR=%s", e.what()));
+ }
+ return std::nullopt;
+}
+
+std::optional<std::string> SRC::getCallouts() const
+{
+ if (!_callouts)
+ {
+ return std::nullopt;
+ }
+ std::string printOut;
+ const std::string jsonIndent(indentLevel, 0x20);
+ const auto& callout = _callouts->callouts();
+ const auto& compDescrp = pv::failingComponentType;
+ printOut.append(jsonIndent + "\"Callout Section\": {\n");
+ jsonInsert(printOut, "Callout Count", std::to_string(callout.size()), 2);
+ printOut.append(jsonIndent + jsonIndent + "\"Callouts\": [");
+ for (auto& entry : callout)
+ {
+ printOut.append("{\n");
+ if (entry->fruIdentity())
+ {
+ jsonInsert(
+ printOut, "FRU Type",
+ compDescrp.at(entry->fruIdentity()->failingComponentType()), 3);
+ jsonInsert(printOut, "Priority",
+ pv::getValue(entry->priority(),
+ pel_values::calloutPriorityValues),
+ 3);
+ if (!entry->locationCode().empty())
+ {
+ jsonInsert(printOut, "Location Code", entry->locationCode(), 3);
+ }
+ if (entry->fruIdentity()->getPN().has_value())
+ {
+ jsonInsert(printOut, "Part Number",
+ entry->fruIdentity()->getPN().value(), 3);
+ }
+ if (entry->fruIdentity()->getMaintProc().has_value())
+ {
+ jsonInsert(printOut, "Procedure Number",
+ entry->fruIdentity()->getMaintProc().value(), 3);
+ if (pv::procedureDesc.find(
+ entry->fruIdentity()->getMaintProc().value()) !=
+ pv::procedureDesc.end())
+ {
+ jsonInsert(
+ printOut, "Description",
+ pv::procedureDesc.at(
+ entry->fruIdentity()->getMaintProc().value()),
+ 3);
+ }
+ }
+ if (entry->fruIdentity()->getCCIN().has_value())
+ {
+ jsonInsert(printOut, "CCIN",
+ entry->fruIdentity()->getCCIN().value(), 3);
+ }
+ if (entry->fruIdentity()->getSN().has_value())
+ {
+ jsonInsert(printOut, "Serial Number",
+ entry->fruIdentity()->getSN().value(), 3);
+ }
+ }
+ if (entry->pceIdentity())
+ {
+ const auto& pceIdentMtms = entry->pceIdentity()->mtms();
+ if (!pceIdentMtms.machineTypeAndModel().empty())
+ {
+ jsonInsert(printOut, "PCE MTMS",
+ pceIdentMtms.machineTypeAndModel() + "_" +
+ pceIdentMtms.machineSerialNumber(),
+ 3);
+ }
+ if (!entry->pceIdentity()->enclosureName().empty())
+ {
+ jsonInsert(printOut, "PCE Name",
+ entry->pceIdentity()->enclosureName(), 3);
+ }
+ }
+ if (entry->mru())
+ {
+ const auto& mruCallouts = entry->mru()->mrus();
+ std::string mruId;
+ for (auto& element : mruCallouts)
+ {
+ if (!mruId.empty())
+ {
+ mruId.append(", " + getNumberString("%08X", element.id));
+ }
+ else
+ {
+ mruId.append(getNumberString("%08X", element.id));
+ }
+ }
+ jsonInsert(printOut, "MRU Id", mruId, 3);
+ }
+ printOut.erase(printOut.size() - 2);
+ printOut.append("\n" + jsonIndent + jsonIndent + "}, ");
+ };
+ printOut.erase(printOut.size() - 2);
+ printOut.append("]\n" + jsonIndent + "}");
+ return printOut;
+}
+
+std::optional<std::string> SRC::getJSON() const
+{
+ std::string ps;
+ jsonInsert(ps, "Section Version", getNumberString("%d", _header.version),
+ 1);
+ jsonInsert(ps, "Sub-section type", getNumberString("%d", _header.subType),
+ 1);
+ jsonInsert(ps, "Created by", getNumberString("0x%X", _header.componentID),
+ 1);
+ jsonInsert(ps, "SRC Version", getNumberString("0x%02X", _version), 1);
+ jsonInsert(ps, "SRC Format", getNumberString("0x%02X", _hexData[0]), 1);
+ jsonInsert(ps, "Power Control Net Fault",
+ pv::boolString.at(isPowerFaultEvent()), 1);
+ rg::Registry registry(getMessageRegistryPath() / rg::registryFileName);
+ auto errorDetails = getErrorDetails(registry, DetailLevel::json);
+ if (errorDetails)
+ {
+ ps.append(errorDetails.value());
+ }
+ jsonInsert(ps, "Valid Word Count", getNumberString("0x%02X", _wordCount),
+ 1);
+ std::string refcode = asciiString();
+ refcode = refcode.substr(0, refcode.find(0x20));
+ jsonInsert(ps, "Reference Code", refcode, 1);
+ for (size_t i = 2; i <= _wordCount; i++)
+ {
+ jsonInsert(
+ ps, "Hex Word " + std::to_string(i),
+ getNumberString("%08X", _hexData[getWordIndexFromWordNum(i)]), 1);
+ }
+ auto calloutJson = getCallouts();
+ if (calloutJson)
+ {
+ ps.append(calloutJson.value());
+ }
+ else
+ {
+ ps.erase(ps.size() - 2);
+ }
+ return ps;
+}
+
} // namespace pels
} // namespace openpower
OpenPOWER on IntegriCloud