blob: 633914bc72bd217330fb2836e5e59e6985f2123e [file] [log] [blame]
Eddie James2f9f9bb2021-09-20 14:26:31 -05001#include "occ_ffdc.hpp"
2
3#include "elog-errors.hpp"
4#include "utils.hpp"
5
6#include <errno.h>
7#include <fcntl.h>
Eddie James9789e712022-05-25 15:43:40 -05008#include <fmt/core.h>
Eddie James2f9f9bb2021-09-20 14:26:31 -05009#include <stdio.h>
10#include <sys/ioctl.h>
11#include <unistd.h>
12
13#include <org/open_power/OCC/Device/error.hpp>
14#include <phosphor-logging/elog.hpp>
15#include <phosphor-logging/log.hpp>
16#include <xyz/openbmc_project/Common/error.hpp>
17#include <xyz/openbmc_project/Logging/Create/server.hpp>
18
19namespace open_power
20{
21namespace occ
22{
23
24static constexpr size_t max_ffdc_size = 8192;
25static constexpr size_t sbe_status_header_size = 8;
26
27static constexpr auto loggingObjectPath = "/xyz/openbmc_project/logging";
Eddie James9789e712022-05-25 15:43:40 -050028static constexpr auto loggingInterface = "xyz.openbmc_project.Logging.Create";
29static constexpr auto opLoggingInterface = "org.open_power.Logging.PEL";
Eddie James2f9f9bb2021-09-20 14:26:31 -050030
31using namespace phosphor::logging;
32using namespace sdbusplus::org::open_power::OCC::Device::Error;
33using InternalFailure =
34 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
35
36uint32_t FFDC::createPEL(const char* path, uint32_t src6, const char* msg,
37 int fd)
38{
39 uint32_t plid = 0;
40 std::vector<std::tuple<
41 sdbusplus::xyz::openbmc_project::Logging::server::Create::FFDCFormat,
42 uint8_t, uint8_t, sdbusplus::message::unix_fd>>
43 pelFFDCInfo;
44
Chris Cainf9fd1e52022-10-04 13:39:24 -050045 log<level::INFO>(
46 fmt::format("Creating PEL for OCC{} with SBE FFDC: {} - SRC6: 0x{:08X}",
47 src6 >> 16, path, src6)
48 .c_str());
Eddie James2f9f9bb2021-09-20 14:26:31 -050049
50 if (fd > 0)
51 {
52 pelFFDCInfo.push_back(std::make_tuple(
53 sdbusplus::xyz::openbmc_project::Logging::server::Create::
54 FFDCFormat::Custom,
55 static_cast<uint8_t>(0xCB), static_cast<uint8_t>(0x01), fd));
56 }
57
58 std::map<std::string, std::string> additionalData;
59 additionalData.emplace("SRC6", std::to_string(src6));
60 additionalData.emplace("_PID", std::to_string(getpid()));
61 additionalData.emplace("SBE_ERR_MSG", msg);
62
Eddie James2f9f9bb2021-09-20 14:26:31 -050063 auto& bus = utils::getBus();
64
65 try
66 {
Eddie James338748b2021-10-29 10:06:50 -050067 std::string service =
Eddie James9789e712022-05-25 15:43:40 -050068 utils::getService(loggingObjectPath, opLoggingInterface);
Eddie James2f9f9bb2021-09-20 14:26:31 -050069 auto method =
70 bus.new_method_call(service.c_str(), loggingObjectPath,
Eddie James9789e712022-05-25 15:43:40 -050071 opLoggingInterface, "CreatePELWithFFDCFiles");
Chris Cainf9fd1e52022-10-04 13:39:24 -050072 // Set level to Notice (Informational). Error should trigger an OCC
73 // reset and if it does not recover, HTMGT/HBRT will create an
74 // unrecoverable error.
Eddie James2f9f9bb2021-09-20 14:26:31 -050075 auto level =
76 sdbusplus::xyz::openbmc_project::Logging::server::convertForMessage(
77 sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level::
Chris Cainf9fd1e52022-10-04 13:39:24 -050078 Notice);
Eddie James2f9f9bb2021-09-20 14:26:31 -050079 method.append(path, level, additionalData, pelFFDCInfo);
80 auto response = bus.call(method);
81 std::tuple<uint32_t, uint32_t> reply = {0, 0};
82
83 response.read(reply);
84 plid = std::get<1>(reply);
85 }
Patrick Williamsaf408082022-07-22 19:26:54 -050086 catch (const sdbusplus::exception_t& e)
Eddie James2f9f9bb2021-09-20 14:26:31 -050087 {
Chris Cainf9fd1e52022-10-04 13:39:24 -050088 log<level::ERR>(
89 fmt::format("Failed to create PEL: {}", e.what()).c_str());
Eddie James2f9f9bb2021-09-20 14:26:31 -050090 }
91
92 return plid;
93}
94
Eddie James9789e712022-05-25 15:43:40 -050095void FFDC::createOCCResetPEL(unsigned int instance, const char* path, int err,
96 const char* callout)
97{
98 std::map<std::string, std::string> additionalData;
99
100 additionalData.emplace("_PID", std::to_string(getpid()));
101
102 if (err)
103 {
104 additionalData.emplace("CALLOUT_ERRNO", std::to_string(-err));
105 }
106
107 if (callout)
108 {
109 additionalData.emplace("CALLOUT_DEVICE_PATH", std::string(callout));
110 }
111
112 additionalData.emplace("OCC", std::to_string(instance));
113
Chris Cainf9fd1e52022-10-04 13:39:24 -0500114 log<level::INFO>(
115 fmt::format("Creating OCC Reset PEL for OCC{}: {}", instance, path)
116 .c_str());
117
Eddie James9789e712022-05-25 15:43:40 -0500118 auto& bus = utils::getBus();
119
120 try
121 {
122 std::string service =
123 utils::getService(loggingObjectPath, loggingInterface);
124 auto method = bus.new_method_call(service.c_str(), loggingObjectPath,
125 loggingInterface, "Create");
Chris Cainf9fd1e52022-10-04 13:39:24 -0500126 // Set level to Notice (Informational). Error should trigger an OCC
127 // reset and if it does not recover, HTMGT/HBRT will create an
128 // unrecoverable error.
Eddie James9789e712022-05-25 15:43:40 -0500129 auto level =
130 sdbusplus::xyz::openbmc_project::Logging::server::convertForMessage(
131 sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level::
Chris Cainf9fd1e52022-10-04 13:39:24 -0500132 Notice);
Eddie James9789e712022-05-25 15:43:40 -0500133 method.append(path, level, additionalData);
134 bus.call(method);
135 }
Patrick Williamsaf408082022-07-22 19:26:54 -0500136 catch (const sdbusplus::exception_t& e)
Eddie James9789e712022-05-25 15:43:40 -0500137 {
138 log<level::ERR>(
Chris Cainf9fd1e52022-10-04 13:39:24 -0500139 fmt::format("Failed to create OCC Reset PEL: {}", e.what())
140 .c_str());
Eddie James9789e712022-05-25 15:43:40 -0500141 }
142}
143
Eddie James2f9f9bb2021-09-20 14:26:31 -0500144// Reads the FFDC file and create an error log
145void FFDC::analyzeEvent()
146{
147 int tfd = -1;
148 size_t total = 0;
149 auto data = std::make_unique<unsigned char[]>(max_ffdc_size);
150 while (total < max_ffdc_size)
151 {
152 auto r = read(fd, data.get() + total, max_ffdc_size - total);
153 if (r < 0)
154 {
155 elog<ReadFailure>(
156 phosphor::logging::org::open_power::OCC::Device::ReadFailure::
157 CALLOUT_ERRNO(errno),
158 phosphor::logging::org::open_power::OCC::Device::ReadFailure::
159 CALLOUT_DEVICE_PATH(file.c_str()));
160 return;
161 }
162 if (!r)
163 {
164 break;
165 }
166 total += r;
167 }
168
169 lseek(fd, 0, SEEK_SET);
170
Eddie James338748b2021-10-29 10:06:50 -0500171 if (!total)
172 {
173 // no error
174 return;
175 }
176
Eddie James2f9f9bb2021-09-20 14:26:31 -0500177 uint32_t src6 = instance << 16;
178 src6 |= *(data.get() + 2) << 8;
179 src6 |= *(data.get() + 3);
180
181 if (total > sbe_status_header_size)
182 {
183 std::string templateString =
184 fs::temp_directory_path() / "OCC_FFDC_XXXXXX";
185 tfd = mkostemp(templateString.data(), O_RDWR);
186 if (tfd < 0)
187 {
188 log<level::ERR>("Couldn't create temporary FFDC file");
189 }
190 else
191 {
192 temporaryFiles.emplace_back(templateString, tfd);
193 size_t written = sbe_status_header_size;
194 while (written < total)
195 {
196 auto r = write(tfd, data.get() + written, total - written);
197 if (r < 0)
198 {
199 close(temporaryFiles.back().second);
200 fs::remove(temporaryFiles.back().first);
201 temporaryFiles.pop_back();
202 tfd = -1;
203 log<level::ERR>("Couldn't write temporary FFDC file");
204 break;
205 }
206 if (!r)
207 {
208 break;
209 }
210 written += r;
211 }
212 }
213 }
214
215 createPEL("org.open_power.Processor.Error.SbeChipOpFailure", src6,
216 "SBE command reported error", tfd);
217}
218
219} // namespace occ
220} // namespace open_power