PEL creation in case of HW/SW failure.
Creation of PEL in case the parser process fails to parse and/or publish
VPD data.
This commit handles both hardware or software failure and creates PEL
accordingly.
Tested on Simics.
Test procedure:
Step1 : Copy ibm_read_vpd in /tmp folder on simics
Step2 : Run ibm_read_vpd exe with a vpd file path having invalid VPD/ECC or
invalid JSON path. In this case we have given path to VPD file with
invalid VPD data.
command-> ./ibm_read_vpd --file <vpd_file_path>
Step3 : After the execution is over, look for PEL logged using command
"peltool -a"
PEL logged incase of invalid VPD:
[
{
"Private Header": {
"Section Version": "1",
"Sub-section type": "0",
"Created by": "0x4000",
"Created at": "11/27/2020 04:40:00",
"Committed at": "11/27/2020 04:40:00",
"Creator Subsystem": "BMC",
"CSSVER": "",
"Platform Log Id": "0x50000002",
"Entry Id": "0x50000002",
"BMC Event Log Id": "2"
},
"User Header": {
"Section Version": "1",
"Sub-section type": "0",
"Log Committed by": "0x2000",
"Subsystem": "CEC Hardware: VPD Interface",
"Event Scope": "Entire Platform",
"Event Severity": "Unrecoverable Error",
"Event Type": "Not Applicable",
"Action Flags": [
"Service Action Required",
"Report Externally",
"HMC Call Home"
],
"Host Transmission": "Not Sent"
},
"Primary SRC": {
"Section Version": "1",
"Sub-section type": "1",
"Created by": "0x4000",
"SRC Version": "0x02",
"SRC Format": "0x55",
"Virtual Progress SRC": "False",
"I5/OS Service Event Bit": "False",
"Hypervisor Dump Initiated":"False",
"Power Control Net Fault": "False",
"Backplane CCIN": "2E2D",
"Error Details": {
"Message": "A VPD data exception occurred."
},
"Valid Word Count": "0x09",
"Reference Code": "BD554001",
"Hex Word 2": "00000055",
"Hex Word 3": "2E2D0010",
"Hex Word 4": "00000000",
"Hex Word 5": "00000000",
"Hex Word 6": "00000000",
"Hex Word 7": "00000000",
"Hex Word 8": "00000000",
"Hex Word 9": "00000000",
"Callout Section": {
"Callout Count": "1",
"Callouts": [{
"FRU Type": "Normal Hardware FRU",
"Priority": "Mandatory, replace all with this type as a unit",
"Location Code": "U78DA.ND1.1234567-P0",
"Part Number": "F191014",
"CCIN": "2E2D",
"Serial Number": "YL2E2D010000"
}]
}
},
"Extended User Header": {
"Section Version": "1",
"Sub-section type": "0",
"Created by": "0x2000",
"Reporting Machine Type": "9105-22A",
"Reporting Serial Number": "SIMP10R",
"FW Released Ver": "",
"FW SubSys Version": "fw1020.00-6",
"Common Ref Time": "00/00/0000 00:00:00",
"Symptom Id Len": "20",
"Symptom Id": "BD554001_2E2D0010"
},
"Failing MTMS": {
"Section Version": "1",
"Sub-section type": "0",
"Created by": "0x2000",
"Machine Type Model": "9105-22A",
"Serial Number": "SIMP10R"
},
"User Data 0": {
"Section Version": "1",
"Sub-section type": "1",
"Created by": "0x2000",
"BMC Version ID": "fw1020.00-6-22-gbbd23f832",
"BMCState": "Ready",
"ChassisState": "Off",
"HostState": "Off",
"Process Name": "Unknown"
},
"User Data 1": {
"Section Version": "1",
"Sub-section type": "1",
"Created by": "0x2000",
"CALLOUT_INVENTORY_PATH": "/xyz/openbmc_project/inventory/system/chassis/motherboard",
"DESCRIPTION": "Invalid VPD data"
}
}
]
Signed-off-by: Sunny Srivastava <sunnsr25@in.ibm.com>
Change-Id: Ieb434bb45b4051d8b7b6d4c9022984d5471fc855
diff --git a/const.hpp b/const.hpp
index 40ffc62..e72abff 100644
--- a/const.hpp
+++ b/const.hpp
@@ -69,6 +69,18 @@
constexpr auto kwdVpdInf = "com.ibm.ipzvpd.VINI";
constexpr auto memVpdInf = "com.ibm.ipzvpd.VINI";
constexpr auto ipzVpdInf = "com.ibm.ipzvpd.";
+constexpr auto offsetJsonDirectory = "/var/lib/vpd/";
+constexpr auto mapperObjectPath = "/xyz/openbmc_project/object_mapper";
+constexpr auto mapperInterface = "xyz.openbmc_project.ObjectMapper";
+constexpr auto mapperDestination = "xyz.openbmc_project.ObjectMapper";
+constexpr auto loggerObjectPath = "/xyz/openbmc_project/logging";
+constexpr auto loggerCreateInterface = "xyz.openbmc_project.Logging.Create";
+constexpr auto errIntfForBlankSystemVPD = "com.ibm.VPD.Error.BlankSystemVPD";
+constexpr auto errIntfForInvalidVPD = "com.ibm.VPD.Error.InvalidVPD";
+constexpr auto errIntfForStreamFail = "com.ibm.VPD.Error.InavlidEepromPath";
+constexpr auto errIntfForEccCheckFail = "com.ibm.VPD.Error.EccCheckFailed";
+constexpr auto errIntfForJsonFailure = "com.ibm.VPD.Error.InvalidJson";
+constexpr auto errIntfForBusFailure = "com.ibm.VPD.Error.DbusFailure";
namespace lengths
{
diff --git a/ibm_vpd_app.cpp b/ibm_vpd_app.cpp
index e4c2c06..04bcbba 100644
--- a/ibm_vpd_app.cpp
+++ b/ibm_vpd_app.cpp
@@ -6,6 +6,7 @@
#include "memory_vpd_parser.hpp"
#include "parser_factory.hpp"
#include "utils.hpp"
+#include "vpd_exceptions.hpp"
#include <ctype.h>
@@ -30,6 +31,7 @@
using namespace openpower::vpd::inventory;
using namespace openpower::vpd::memory::parser;
using namespace openpower::vpd::parser::interface;
+using namespace openpower::vpd::exceptions;
static const deviceTreeMap deviceTreeSystemTypeMap = {
{RAINIER_2U, "conf@aspeed-bmc-ibm-rainier-2u.dtb"},
@@ -565,6 +567,15 @@
int main(int argc, char** argv)
{
int rc = 0;
+ string file{};
+ json js{};
+
+ // map to hold additional data in case of logging pel
+ PelAdditionalData additionalData{};
+
+ // this is needed to hold base fru inventory path in case there is ECC or
+ // vpd exception while parsing the file
+ std::string baseFruInventoryPath = {};
try
{
@@ -589,7 +600,20 @@
// Make sure that the file path we get is for a supported EEPROM
ifstream inventoryJson(jsonToParse);
- auto js = json::parse(inventoryJson);
+ if (!inventoryJson)
+ {
+ throw(
+ (VpdJsonException("Failed to access Json path", jsonToParse)));
+ }
+
+ try
+ {
+ js = json::parse(inventoryJson);
+ }
+ catch (json::parse_error& ex)
+ {
+ throw((VpdJsonException("Json parsing failed", jsonToParse)));
+ }
if ((js.find("frus") == js.end()) ||
(js["frus"].find(file) == js["frus"].end()))
@@ -598,6 +622,8 @@
return 0;
}
+ baseFruInventoryPath = js["frus"][file][0]["inventoryPath"];
+
Binary vpdVector = getVpdDataInVector(js, file);
ParserInterface* parser = ParserFactory::getParser(move(vpdVector));
@@ -616,6 +642,35 @@
// release the parser object
ParserFactory::freeParser(parser);
}
+ catch (const VpdJsonException& ex)
+ {
+ additionalData.emplace("JSON_PATH", ex.getJsonPath());
+ additionalData.emplace("DESCRIPTION", ex.what());
+ createPEL(additionalData, errIntfForJsonFailure);
+
+ cerr << ex.what() << "\n";
+ rc = -1;
+ }
+ catch (const VpdEccException& ex)
+ {
+ additionalData.emplace("DESCRIPTION", "ECC check failed");
+ additionalData.emplace("CALLOUT_INVENTORY_PATH",
+ INVENTORY_PATH + baseFruInventoryPath);
+ createPEL(additionalData, errIntfForEccCheckFail);
+
+ cerr << ex.what() << "\n";
+ rc = -1;
+ }
+ catch (const VpdDataException& ex)
+ {
+ additionalData.emplace("DESCRIPTION", "Invalid VPD data");
+ additionalData.emplace("CALLOUT_INVENTORY_PATH",
+ INVENTORY_PATH + baseFruInventoryPath);
+ createPEL(additionalData, errIntfForInvalidVPD);
+
+ cerr << ex.what() << "\n";
+ rc = -1;
+ }
catch (exception& e)
{
cerr << e.what() << "\n";
diff --git a/impl.cpp b/impl.cpp
index b64ba89..d8a6138 100644
--- a/impl.cpp
+++ b/impl.cpp
@@ -485,37 +485,24 @@
Store Impl::run()
{
- try
- {
- // Check if the VHDR record is present
- checkHeader();
+ // Check if the VHDR record is present
+ checkHeader();
- auto iterator = vpd.cbegin();
+ auto iterator = vpd.cbegin();
- // Read the table of contents record
- std::size_t ptLen = readTOC(iterator);
+ // Read the table of contents record
+ std::size_t ptLen = readTOC(iterator);
- // Read the table of contents record, to get offsets
- // to other records.
- auto offsets = readPT(iterator, ptLen);
- for (const auto& offset : offsets)
- {
- processRecord(offset);
- }
- // Return a Store object, which has interfaces to
- // access parsed VPD by record:keyword
- return Store(std::move(out));
- }
- catch (const VpdEccException& ex)
+ // Read the table of contents record, to get offsets
+ // to other records.
+ auto offsets = readPT(iterator, ptLen);
+ for (const auto& offset : offsets)
{
- // TODO: Create PEL
- throw std::runtime_error(ex.what());
+ processRecord(offset);
}
- catch (const VpdDataException& ex)
- {
- // TODO: Create PEL
- throw std::runtime_error(ex.what());
- }
+ // Return a Store object, which has interfaces to
+ // access parsed VPD by record:keyword
+ return Store(std::move(out));
}
void Impl::checkVPDHeader()
diff --git a/types.hpp b/types.hpp
index c80af32..5f24bd0 100644
--- a/types.hpp
+++ b/types.hpp
@@ -47,6 +47,7 @@
using systemType = std::string;
using deviceTree = std::string;
using deviceTreeMap = std::unordered_map<systemType, deviceTree>;
+using PelAdditionalData = std::map<std::string, std::string>;
} // namespace inventory
diff --git a/utils.cpp b/utils.cpp
index 24d7b4c..8b33305 100644
--- a/utils.cpp
+++ b/utils.cpp
@@ -12,31 +12,38 @@
namespace vpd
{
using namespace openpower::vpd::constants;
+using namespace inventory;
+using namespace phosphor::logging;
+
namespace inventory
{
-auto getPIMService()
+std::string getService(sdbusplus::bus::bus& bus, const std::string& path,
+ const std::string& interface)
{
- auto bus = sdbusplus::bus::new_default();
- auto mapper =
- bus.new_method_call("xyz.openbmc_project.ObjectMapper",
- "/xyz/openbmc_project/object_mapper",
- "xyz.openbmc_project.ObjectMapper", "GetObject");
-
- mapper.append(pimPath);
- mapper.append(std::vector<std::string>({pimIntf}));
-
- auto result = bus.call(mapper);
- if (result.is_method_error())
- {
- throw std::runtime_error("ObjectMapper GetObject failed");
- }
+ auto mapper = bus.new_method_call(mapperDestination, mapperObjectPath,
+ mapperInterface, "GetObject");
+ mapper.append(path, std::vector<std::string>({interface}));
std::map<std::string, std::vector<std::string>> response;
- result.read(response);
+ try
+ {
+ auto reply = bus.call(mapper);
+ reply.read(response);
+ }
+ catch (const sdbusplus::exception::SdBusError& e)
+ {
+ log<level::ERR>("D-Bus call exception",
+ entry("OBJPATH=%s", mapperObjectPath),
+ entry("INTERFACE=%s", mapperInterface),
+ entry("EXCEPTION=%s", e.what()));
+
+ throw std::runtime_error("Service name is not found");
+ }
+
if (response.empty())
{
- throw std::runtime_error("ObjectMapper GetObject bad response");
+ throw std::runtime_error("Service name response is empty");
}
return response.begin()->first;
@@ -44,12 +51,10 @@
void callPIM(ObjectMap&& objects)
{
- std::string service;
-
try
{
- service = getPIMService();
auto bus = sdbusplus::bus::new_default();
+ auto service = getService(bus, pimPath, pimIntf);
auto pimMsg =
bus.new_method_call(service.c_str(), pimPath, pimIntf, "Notify");
pimMsg.append(std::move(objects));
@@ -174,5 +179,27 @@
}
return propVal;
}
+
+void createPEL(const std::map<std::string, std::string>& additionalData,
+ const std::string& errIntf)
+{
+ try
+ {
+ auto bus = sdbusplus::bus::new_default();
+
+ auto service = getService(bus, loggerObjectPath, loggerCreateInterface);
+ auto method = bus.new_method_call(service.c_str(), loggerObjectPath,
+ loggerCreateInterface, "Create");
+
+ method.append(errIntf, "xyz.openbmc_project.Logging.Entry.Level.Error",
+ additionalData);
+ auto resp = bus.call(method);
+ }
+ catch (const sdbusplus::exception::SdBusError& e)
+ {
+ throw std::runtime_error(
+ "Error in invoking D-Bus logging create interface to register PEL");
+ }
+}
} // namespace vpd
} // namespace openpower
diff --git a/utils.hpp b/utils.hpp
index 54e562c..d531842 100644
--- a/utils.hpp
+++ b/utils.hpp
@@ -79,5 +79,13 @@
*/
string readBusProperty(const string& obj, const string& inf,
const string& prop);
+
+/**
+ * @brief API to create PEL entry
+ * @param[in] Map holding the additional data
+ * @param[in] error interface
+ */
+void createPEL(const std::map<std::string, std::string>& additionalData,
+ const std::string& errIntf);
} // namespace vpd
} // namespace openpower