Add PEL creation for SBE chip-op failures
This commit introduces a new function within the SBE dump collection
mechanism to create PELs) when chip operations on SBE fail.
Test:
Make sure the PELs are logged during chip-op failure
Signed-off-by: Dhruvaraj Subhashchandran <dhruvaraj@in.ibm.com>
Change-Id: I23f78b702f4a2b9cf01315c3fbb487dc428bd2a0
diff --git a/dump/create_pel.cpp b/dump/create_pel.cpp
new file mode 100644
index 0000000..916d312
--- /dev/null
+++ b/dump/create_pel.cpp
@@ -0,0 +1,191 @@
+#include "create_pel.hpp"
+
+#include "dump_utils.hpp"
+
+#include <fcntl.h>
+#include <libekb.H>
+#include <unistd.h>
+
+#include <phosphor-logging/elog.hpp>
+#include <phosphor-logging/lg2.hpp>
+#include <xyz/openbmc_project/Logging/Create/server.hpp>
+#include <xyz/openbmc_project/Logging/Entry/server.hpp>
+
+#include <cerrno>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <format>
+#include <map>
+#include <stdexcept>
+#include <string>
+#include <tuple>
+#include <vector>
+
+namespace openpower::dump::pel
+{
+
+using namespace phosphor::logging;
+constexpr auto loggingObjectPath = "/xyz/openbmc_project/logging";
+constexpr auto loggingInterface = "xyz.openbmc_project.Logging.Create";
+constexpr auto opLoggingInterface = "org.open_power.Logging.PEL";
+
+uint32_t createSbeErrorPEL(const std::string& event, const sbeError_t& sbeError,
+ const FFDCData& ffdcData)
+{
+ uint32_t plid = 0;
+ std::unordered_map<std::string, std::string> additionalData = {
+ {"_PID", std::to_string(getpid())}, {"SBE_ERR_MSG", sbeError.what()}};
+ auto bus = sdbusplus::bus::new_default();
+
+ additionalData.emplace("_PID", std::to_string(getpid()));
+ additionalData.emplace("SBE_ERR_MSG", sbeError.what());
+
+ for (auto& data : ffdcData)
+ {
+ additionalData.emplace(data);
+ }
+
+ std::vector<std::tuple<
+ sdbusplus::xyz::openbmc_project::Logging::server::Create::FFDCFormat,
+ uint8_t, uint8_t, sdbusplus::message::unix_fd>>
+ pelFFDCInfo;
+
+ // get SBE ffdc file descriptor
+ auto fd = sbeError.getFd();
+
+ // Negative fd value indicates error case or invalid file
+ // No need of special processing , just log error with additional ffdc.
+ if (fd > 0)
+ {
+ // Refer phosphor-logging/extensions/openpower-pels/README.md section
+ // "Self Boot Engine(SBE) First Failure Data Capture(FFDC) Support"
+ // for details of related to createPEL with SBE FFDC information
+ // usin g CreateWithFFDCFiles api.
+ pelFFDCInfo.emplace_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()));
+ }
+ try
+ {
+ auto service = util::getService(bus, opLoggingInterface,
+ loggingObjectPath);
+ auto method = bus.new_method_call(service.c_str(), loggingObjectPath,
+ opLoggingInterface,
+ "CreatePELWithFFDCFiles");
+ auto level =
+ sdbusplus::xyz::openbmc_project::Logging::server::convertForMessage(
+ sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level::
+ Error);
+ method.append(event, level, additionalData, pelFFDCInfo);
+ auto response = bus.call(method);
+
+ // reply will be tuple containing bmc log id, platform log id
+ std::tuple<uint32_t, uint32_t> reply = {0, 0};
+
+ // parse dbus response into reply
+ response.read(reply);
+ plid = std::get<1>(reply); // platform log id is tuple "second"
+ }
+ catch (const sdbusplus::exception::exception& e)
+ {
+ lg2::error(
+ "D-Bus call exception OBJPATH={OBJPATH}, INTERFACE={INTERFACE}, "
+ "EXCEPTION={ERROR}",
+ "OBJPATH", loggingObjectPath, "INTERFACE", loggingInterface,
+ "ERROR", e);
+
+ throw;
+ }
+ catch (const std::exception& e)
+ {
+ throw;
+ }
+
+ return plid;
+}
+
+FFDCFile::FFDCFile(const json& pHALCalloutData) :
+ calloutData(pHALCalloutData.dump()),
+ calloutFile("/tmp/phalPELCalloutsJson.XXXXXX"), fileFD(-1)
+{
+ prepareFFDCFile();
+}
+
+FFDCFile::~FFDCFile()
+{
+ removeCalloutFile();
+}
+
+int FFDCFile::getFileFD() const
+{
+ return fileFD;
+}
+
+void FFDCFile::prepareFFDCFile()
+{
+ createCalloutFile();
+ writeCalloutData();
+ setCalloutFileSeekPos();
+}
+
+void FFDCFile::createCalloutFile()
+{
+ fileFD = mkostemp(const_cast<char*>(calloutFile.c_str()), O_RDWR);
+
+ if (fileFD == -1)
+ {
+ lg2::error("Failed to create phalPELCallouts file({FILE}), "
+ "errorno({ERRNO}) and errormsg({ERRORMSG})",
+ "FILE", calloutFile, "ERRNO", errno, "ERRORMSG",
+ strerror(errno));
+ throw std::runtime_error("Failed to create phalPELCallouts file");
+ }
+}
+
+void FFDCFile::writeCalloutData()
+{
+ ssize_t rc = write(fileFD, calloutData.c_str(), calloutData.size());
+
+ if (rc == -1)
+ {
+ lg2::error("Failed to write phaPELCallout info in file({FILE}), "
+ "errorno({ERRNO}), errormsg({ERRORMSG})",
+ "FILE", calloutFile, "ERRNO", errno, "ERRORMSG",
+ strerror(errno));
+ throw std::runtime_error("Failed to write phalPELCallouts info");
+ }
+ else if (rc != static_cast<ssize_t>(calloutData.size()))
+ {
+ lg2::warning("Could not write all phal callout info in file({FILE}), "
+ "written byte({WRITTEN}), total byte({TOTAL})",
+ "FILE", calloutFile, "WRITTEN", rc, "TOTAL",
+ calloutData.size());
+ }
+}
+
+void FFDCFile::setCalloutFileSeekPos()
+{
+ int rc = lseek(fileFD, 0, SEEK_SET);
+
+ if (rc == -1)
+ {
+ lg2::error("Failed to set SEEK_SET for phalPELCallouts in "
+ "file({FILE}), errorno({ERRNO}), errormsg({ERRORMSG})",
+ "FILE", calloutFile, "ERRNO", errno, "ERRORMSG",
+ strerror(errno));
+
+ throw std::runtime_error(
+ "Failed to set SEEK_SET for phalPELCallouts file");
+ }
+}
+
+void FFDCFile::removeCalloutFile()
+{
+ close(fileFD);
+ std::remove(calloutFile.c_str());
+}
+
+} // namespace openpower::dump::pel