xref: /openbmc/openpower-occ-control/occ_ffdc.cpp (revision 2f9f9bba661dcae2f0dd05ea6ddae9eb11a909d9)
1 #include "occ_ffdc.hpp"
2 
3 #include "elog-errors.hpp"
4 #include "utils.hpp"
5 
6 #include <errno.h>
7 #include <fcntl.h>
8 #include <stdio.h>
9 #include <sys/ioctl.h>
10 #include <unistd.h>
11 
12 #include <org/open_power/OCC/Device/error.hpp>
13 #include <phosphor-logging/elog.hpp>
14 #include <phosphor-logging/log.hpp>
15 #include <xyz/openbmc_project/Common/error.hpp>
16 #include <xyz/openbmc_project/Logging/Create/server.hpp>
17 
18 namespace open_power
19 {
20 namespace occ
21 {
22 
23 static constexpr size_t max_ffdc_size = 8192;
24 static constexpr size_t sbe_status_header_size = 8;
25 
26 static constexpr auto loggingObjectPath = "/xyz/openbmc_project/logging";
27 static constexpr auto loggingInterface = "org.open_power.Logging.PEL";
28 
29 using namespace phosphor::logging;
30 using namespace sdbusplus::org::open_power::OCC::Device::Error;
31 using InternalFailure =
32     sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
33 
34 uint32_t FFDC::createPEL(const char* path, uint32_t src6, const char* msg,
35                          int fd)
36 {
37     uint32_t plid = 0;
38     std::vector<std::tuple<
39         sdbusplus::xyz::openbmc_project::Logging::server::Create::FFDCFormat,
40         uint8_t, uint8_t, sdbusplus::message::unix_fd>>
41         pelFFDCInfo;
42 
43     log<level::INFO>("Creating PEL with SBE FFDC", entry("SRC6=%08x", src6));
44 
45     if (fd > 0)
46     {
47         pelFFDCInfo.push_back(std::make_tuple(
48             sdbusplus::xyz::openbmc_project::Logging::server::Create::
49                 FFDCFormat::Custom,
50             static_cast<uint8_t>(0xCB), static_cast<uint8_t>(0x01), fd));
51     }
52 
53     std::map<std::string, std::string> additionalData;
54     additionalData.emplace("SRC6", std::to_string(src6));
55     additionalData.emplace("_PID", std::to_string(getpid()));
56     additionalData.emplace("SBE_ERR_MSG", msg);
57 
58     std::string service =
59         utils::getService(loggingObjectPath, loggingInterface);
60     auto& bus = utils::getBus();
61 
62     try
63     {
64         auto method =
65             bus.new_method_call(service.c_str(), loggingObjectPath,
66                                 loggingInterface, "CreatePELWithFFDCFiles");
67         auto level =
68             sdbusplus::xyz::openbmc_project::Logging::server::convertForMessage(
69                 sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level::
70                     Error);
71         method.append(path, level, additionalData, pelFFDCInfo);
72         auto response = bus.call(method);
73         std::tuple<uint32_t, uint32_t> reply = {0, 0};
74 
75         response.read(reply);
76         plid = std::get<1>(reply);
77     }
78     catch (const sdbusplus::exception::exception& e)
79     {
80         log<level::ERR>("Failed to create PEL");
81     }
82 
83     return plid;
84 }
85 
86 // Reads the FFDC file and create an error log
87 void FFDC::analyzeEvent()
88 {
89     int tfd = -1;
90     size_t total = 0;
91     auto data = std::make_unique<unsigned char[]>(max_ffdc_size);
92     while (total < max_ffdc_size)
93     {
94         auto r = read(fd, data.get() + total, max_ffdc_size - total);
95         if (r < 0)
96         {
97             elog<ReadFailure>(
98                 phosphor::logging::org::open_power::OCC::Device::ReadFailure::
99                     CALLOUT_ERRNO(errno),
100                 phosphor::logging::org::open_power::OCC::Device::ReadFailure::
101                     CALLOUT_DEVICE_PATH(file.c_str()));
102             return;
103         }
104         if (!r)
105         {
106             break;
107         }
108         total += r;
109     }
110 
111     lseek(fd, 0, SEEK_SET);
112 
113     uint32_t src6 = instance << 16;
114     src6 |= *(data.get() + 2) << 8;
115     src6 |= *(data.get() + 3);
116 
117     if (total > sbe_status_header_size)
118     {
119         std::string templateString =
120             fs::temp_directory_path() / "OCC_FFDC_XXXXXX";
121         tfd = mkostemp(templateString.data(), O_RDWR);
122         if (tfd < 0)
123         {
124             log<level::ERR>("Couldn't create temporary FFDC file");
125         }
126         else
127         {
128             temporaryFiles.emplace_back(templateString, tfd);
129             size_t written = sbe_status_header_size;
130             while (written < total)
131             {
132                 auto r = write(tfd, data.get() + written, total - written);
133                 if (r < 0)
134                 {
135                     close(temporaryFiles.back().second);
136                     fs::remove(temporaryFiles.back().first);
137                     temporaryFiles.pop_back();
138                     tfd = -1;
139                     log<level::ERR>("Couldn't write temporary FFDC file");
140                     break;
141                 }
142                 if (!r)
143                 {
144                     break;
145                 }
146                 written += r;
147             }
148         }
149     }
150 
151     createPEL("org.open_power.Processor.Error.SbeChipOpFailure", src6,
152               "SBE command reported error", tfd);
153 }
154 
155 } // namespace occ
156 } // namespace open_power
157