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