xref: /openbmc/openpower-debug-collector/dump/create_pel.cpp (revision 535dfb2faa75e54189ece65727c0978f216296a9)
1 #include "create_pel.hpp"
2 
3 #include "dump_utils.hpp"
4 #include "sbe_consts.hpp"
5 
6 #include <fcntl.h>
7 #include <libekb.H>
8 #include <unistd.h>
9 
10 #include <phosphor-logging/elog.hpp>
11 #include <phosphor-logging/lg2.hpp>
12 #include <xyz/openbmc_project/Logging/Create/server.hpp>
13 #include <xyz/openbmc_project/Logging/Entry/server.hpp>
14 
15 #include <cerrno>
16 #include <cstdio>
17 #include <cstdlib>
18 #include <cstring>
19 #include <format>
20 #include <map>
21 #include <stdexcept>
22 #include <string>
23 #include <tuple>
24 #include <vector>
25 
26 namespace openpower::dump::pel
27 {
28 
29 using namespace phosphor::logging;
30 using namespace openpower::dump::SBE;
31 constexpr auto loggingObjectPath = "/xyz/openbmc_project/logging";
32 constexpr auto loggingInterface = "xyz.openbmc_project.Logging.Create";
33 constexpr auto opLoggingInterface = "org.open_power.Logging.PEL";
34 constexpr auto entryInterface = "xyz.openbmc_project.Logging.Entry";
35 constexpr auto opEntryInterface = "org.open_power.Logging.PEL.Entry";
36 
createSbeErrorPEL(const std::string & event,const sbeError_t & sbeError,const FFDCData & ffdcData,const Severity severity,const std::optional<PELFFDCInfo> & pelFFDCInfoOpt)37 uint32_t createSbeErrorPEL(const std::string& event, const sbeError_t& sbeError,
38                            const FFDCData& ffdcData, const Severity severity,
39                            const std::optional<PELFFDCInfo>& pelFFDCInfoOpt)
40 {
41     uint32_t plid = 0;
42     std::unordered_map<std::string, std::string> additionalData = {
43         {"_PID", std::to_string(getpid())}, {"SBE_ERR_MSG", sbeError.what()}};
44     auto bus = sdbusplus::bus::new_default();
45 
46     additionalData.emplace("_PID", std::to_string(getpid()));
47     additionalData.emplace("SBE_ERR_MSG", sbeError.what());
48 
49     for (auto& data : ffdcData)
50     {
51         additionalData.emplace(data);
52     }
53 
54     PELFFDCInfo pelFFDCInfo;
55     if (pelFFDCInfoOpt)
56     {
57         pelFFDCInfo = *pelFFDCInfoOpt;
58     }
59 
60     // Negative fd value indicates error case or invalid file
61     // No need of special processing , just log error with additional ffdc.
62     else if (sbeError.getFd() > 0)
63     {
64         // Refer phosphor-logging/extensions/openpower-pels/README.md section
65         // "Self Boot Engine(SBE) First Failure Data Capture(FFDC) Support"
66         // for details of related to createPEL with SBE FFDC information
67         // using CreateWithFFDCFiles api.
68         pelFFDCInfo.emplace_back(std::make_tuple(
69             sdbusplus::xyz::openbmc_project::Logging::server::Create::
70                 FFDCFormat::Custom,
71             FFDC_FORMAT_SUBTYPE, FFDC_FORMAT_VERSION, sbeError.getFd()));
72     }
73     try
74     {
75         auto service =
76             util::getService(bus, opLoggingInterface, loggingObjectPath);
77         auto method =
78             bus.new_method_call(service.c_str(), loggingObjectPath,
79                                 opLoggingInterface, "CreatePELWithFFDCFiles");
80         auto level =
81             sdbusplus::xyz::openbmc_project::Logging::server::convertForMessage(
82                 severity);
83         method.append(event, level, additionalData, pelFFDCInfo);
84         auto response = bus.call(method);
85 
86         // reply will be tuple containing bmc log id, platform log id
87         std::tuple<uint32_t, uint32_t> reply = {0, 0};
88 
89         // parse dbus response into reply
90         response.read(reply);
91         plid = std::get<0>(reply); // dbus entry id is tuple "first"
92     }
93     catch (const sdbusplus::exception_t& e)
94     {
95         lg2::error(
96             "D-Bus call exception OBJPATH={OBJPATH}, INTERFACE={INTERFACE}, "
97             "EXCEPTION={ERROR}",
98             "OBJPATH", loggingObjectPath, "INTERFACE", loggingInterface,
99             "ERROR", e);
100 
101         throw;
102     }
103     catch (const std::exception& e)
104     {
105         throw;
106     }
107 
108     return plid;
109 }
110 
convertSeverityToEnum(uint8_t severity)111 openpower::dump::pel::Severity convertSeverityToEnum(uint8_t severity)
112 {
113     switch (severity)
114     {
115         case openpower::phal::FAPI2_ERRL_SEV_RECOVERED:
116             return openpower::dump::pel::Severity::Informational;
117         case openpower::phal::FAPI2_ERRL_SEV_PREDICTIVE:
118             return openpower::dump::pel::Severity::Warning;
119         case openpower::phal::FAPI2_ERRL_SEV_UNRECOVERABLE:
120             return openpower::dump::pel::Severity::Error;
121         default:
122             return openpower::dump::pel::Severity::Error;
123     }
124 }
125 
processFFDCPackets(const openpower::phal::sbeError_t & sbeError,const std::string & event,openpower::dump::pel::FFDCData & pelAdditionalData)126 std::vector<uint32_t> processFFDCPackets(
127     const openpower::phal::sbeError_t& sbeError, const std::string& event,
128     openpower::dump::pel::FFDCData& pelAdditionalData)
129 {
130     const auto& ffdcFileList = sbeError.getFfdcFileList();
131     std::vector<uint32_t> logIdList;
132     for (const auto& [slid, ffdcTuple] : ffdcFileList)
133     {
134         uint8_t severity;
135         int fd;
136         std::filesystem::path path;
137         std::tie(severity, fd, path) = ffdcTuple;
138 
139         Severity logSeverity = convertSeverityToEnum(severity);
140 
141         if (logSeverity != openpower::dump::pel::Severity::Informational)
142         {
143             lg2::info(
144                 "Changing severity from {SEV_ORIG} to informational in the "
145                 "dumping path",
146                 "SEV_ORIG", logSeverity);
147             logSeverity = openpower::dump::pel::Severity::Informational;
148         }
149 
150         PELFFDCInfo pelFFDCInfo;
151         pelFFDCInfo.emplace_back(
152             std::make_tuple(sdbusplus::xyz::openbmc_project::Logging::server::
153                                 Create::FFDCFormat::Custom,
154                             FFDC_FORMAT_SUBTYPE, FFDC_FORMAT_VERSION, fd));
155 
156         auto logId = openpower::dump::pel::createSbeErrorPEL(
157             event, sbeError, pelAdditionalData, logSeverity);
158         lg2::info("Logged PEL {PELID} for SLID {SLID}", "PELID", logId, "SLID",
159                   slid);
160         logIdList.push_back(logId);
161     }
162     return logIdList;
163 }
164 
getLogInfo(uint32_t logId)165 std::tuple<uint32_t, std::string> getLogInfo(uint32_t logId)
166 {
167     uint32_t pelId;
168     std::string src;
169     try
170     {
171         auto bus = sdbusplus::bus::new_default();
172         const auto loggingEntryObjectPath =
173             std::string(loggingObjectPath) + "/entry/" + std::to_string(logId);
174         auto service =
175             util::getService(bus, entryInterface, loggingEntryObjectPath);
176         auto method =
177             bus.new_method_call(service.c_str(), loggingEntryObjectPath.c_str(),
178                                 "org.freedesktop.DBus.Properties", "Get");
179         method.append(opEntryInterface);
180         method.append("PlatformLogID");
181         auto response = bus.call(method);
182         std::variant<uint32_t, std::string> v;
183         response.read(v);
184         pelId = std::get<uint32_t>(v);
185         method =
186             bus.new_method_call(service.c_str(), loggingEntryObjectPath.c_str(),
187                                 "org.freedesktop.DBus.Properties", "Get");
188         method.append(entryInterface);
189         method.append("EventId");
190         response = bus.call(method);
191         response.read(v);
192         std::istringstream iss(std::get<std::string>(v));
193         iss >> src;
194     }
195     catch (const sdbusplus::exception_t& e)
196     {
197         lg2::error("D-Bus call exception "
198                    "EXCEPTION={ERROR}",
199                    "ERROR", e);
200         throw;
201     }
202     catch (const std::exception& e)
203     {
204         throw;
205     }
206 
207     return std::tuple<uint32_t, std::string>(pelId, src);
208 }
209 
FFDCFile(const json & pHALCalloutData)210 FFDCFile::FFDCFile(const json& pHALCalloutData) :
211     calloutData(pHALCalloutData.dump()),
212     calloutFile("/tmp/phalPELCalloutsJson.XXXXXX"), fileFD(-1)
213 {
214     prepareFFDCFile();
215 }
216 
~FFDCFile()217 FFDCFile::~FFDCFile()
218 {
219     removeCalloutFile();
220 }
221 
getFileFD() const222 int FFDCFile::getFileFD() const
223 {
224     return fileFD;
225 }
226 
prepareFFDCFile()227 void FFDCFile::prepareFFDCFile()
228 {
229     createCalloutFile();
230     writeCalloutData();
231     setCalloutFileSeekPos();
232 }
233 
createCalloutFile()234 void FFDCFile::createCalloutFile()
235 {
236     fileFD = mkostemp(const_cast<char*>(calloutFile.c_str()), O_RDWR);
237 
238     if (fileFD == -1)
239     {
240         lg2::error("Failed to create phalPELCallouts file({FILE}), "
241                    "errorno({ERRNO}) and errormsg({ERRORMSG})",
242                    "FILE", calloutFile, "ERRNO", errno, "ERRORMSG",
243                    strerror(errno));
244         throw std::runtime_error("Failed to create phalPELCallouts file");
245     }
246 }
247 
writeCalloutData()248 void FFDCFile::writeCalloutData()
249 {
250     ssize_t rc = write(fileFD, calloutData.c_str(), calloutData.size());
251 
252     if (rc == -1)
253     {
254         lg2::error("Failed to write phaPELCallout info in file({FILE}), "
255                    "errorno({ERRNO}), errormsg({ERRORMSG})",
256                    "FILE", calloutFile, "ERRNO", errno, "ERRORMSG",
257                    strerror(errno));
258         throw std::runtime_error("Failed to write phalPELCallouts info");
259     }
260     else if (rc != static_cast<ssize_t>(calloutData.size()))
261     {
262         lg2::warning("Could not write all phal callout info in file({FILE}), "
263                      "written byte({WRITTEN}), total byte({TOTAL})",
264                      "FILE", calloutFile, "WRITTEN", rc, "TOTAL",
265                      calloutData.size());
266     }
267 }
268 
setCalloutFileSeekPos()269 void FFDCFile::setCalloutFileSeekPos()
270 {
271     int rc = lseek(fileFD, 0, SEEK_SET);
272 
273     if (rc == -1)
274     {
275         lg2::error("Failed to set SEEK_SET for phalPELCallouts in "
276                    "file({FILE}), errorno({ERRNO}), errormsg({ERRORMSG})",
277                    "FILE", calloutFile, "ERRNO", errno, "ERRORMSG",
278                    strerror(errno));
279 
280         throw std::runtime_error(
281             "Failed to set SEEK_SET for phalPELCallouts file");
282     }
283 }
284 
removeCalloutFile()285 void FFDCFile::removeCalloutFile()
286 {
287     close(fileFD);
288     std::remove(calloutFile.c_str());
289 }
290 
291 } // namespace openpower::dump::pel
292