blob: 5c9c48f29b7e5e76964e104ca5278aa5927b0f37 [file] [log] [blame]
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +05301#include "occ_errors.hpp"
Gunnar Mills94df8c92018-09-14 14:50:03 -05002
Gunnar Mills94df8c92018-09-14 14:50:03 -05003#include <errno.h>
4#include <fcntl.h>
5#include <sys/ioctl.h>
6#include <unistd.h>
7
8#include <org/open_power/OCC/Device/error.hpp>
Patrick Williamsd8aab2a2023-04-21 11:15:54 -05009#include <phosphor-logging/elog-errors.hpp>
Gunnar Mills94df8c92018-09-14 14:50:03 -050010#include <phosphor-logging/elog.hpp>
11#include <phosphor-logging/log.hpp>
12#include <xyz/openbmc_project/Common/error.hpp>
Patrick Williams48002492024-02-13 21:43:32 -060013
14#include <format>
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053015namespace open_power
16{
17namespace occ
18{
19
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053020using namespace phosphor::logging;
21using namespace sdbusplus::org::open_power::OCC::Device::Error;
Gunnar Mills94df8c92018-09-14 14:50:03 -050022using InternalFailure =
23 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053024
25// Populate the file descriptor on the error file
26void Error::openFile()
27{
28 using namespace phosphor::logging;
29
30 fd = open(file.c_str(), O_RDONLY | O_NONBLOCK);
Chris Caina8857c52021-01-27 11:53:05 -060031 const int open_errno = errno;
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053032 if (fd < 0)
33 {
Chris Caina8857c52021-01-27 11:53:05 -060034 log<level::ERR>(
Patrick Williams48002492024-02-13 21:43:32 -060035 std::format("Error::openFile: open failed (errno={})", open_errno)
Chris Caina8857c52021-01-27 11:53:05 -060036 .c_str());
Gunnar Mills94df8c92018-09-14 14:50:03 -050037 elog<OpenFailure>(phosphor::logging::org::open_power::OCC::Device::
Chris Caina8857c52021-01-27 11:53:05 -060038 OpenFailure::CALLOUT_ERRNO(open_errno),
Gunnar Mills94df8c92018-09-14 14:50:03 -050039 phosphor::logging::org::open_power::OCC::Device::
40 OpenFailure::CALLOUT_DEVICE_PATH(file.c_str()));
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053041 }
42}
43
44// Attaches the FD to event loop and registers the callback handler
45void Error::registerCallBack()
46{
47 decltype(eventSource.get()) sourcePtr = nullptr;
Gunnar Mills94df8c92018-09-14 14:50:03 -050048 auto r = sd_event_add_io(event.get(), &sourcePtr, fd, EPOLLPRI | EPOLLERR,
49 processEvents, this);
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053050 eventSource.reset(sourcePtr);
51
52 if (r < 0)
53 {
54 log<level::ERR>("Failed to register callback handler",
Gunnar Mills94df8c92018-09-14 14:50:03 -050055 entry("ERROR=%s", strerror(-r)));
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053056 elog<InternalFailure>();
57 }
58}
59
60// Starts to watch for errors
Eddie James774f9af2019-03-19 20:58:53 +000061void Error::addWatch(bool poll)
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053062{
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +053063 if (!watching)
64 {
65 // Open the file
66 openFile();
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053067
Eddie James774f9af2019-03-19 20:58:53 +000068 if (poll)
69 {
70 // register the callback handler
71 registerCallBack();
72 }
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +053073
74 // Set we are watching the error
75 watching = true;
76 }
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053077}
78
79// Stops watching for errors
80void Error::removeWatch()
81{
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +053082 if (watching)
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053083 {
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +053084 // Close the file
85 if (fd >= 0)
86 {
87 close(fd);
88 }
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053089
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +053090 // Reduce the reference count. Since there is only one instances
91 // of add_io, this will result empty loop
92 eventSource.reset();
93
94 // We are no more watching the error
95 watching = false;
96 }
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053097}
98
99// Callback handler when there is an activity on the FD
George Liud0345ae2021-09-10 13:13:28 +0800100int Error::processEvents(sd_event_source* /*es*/, int /*fd*/,
101 uint32_t /*revents*/, void* userData)
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530102{
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530103 auto error = static_cast<Error*>(userData);
104
105 error->analyzeEvent();
106 return 0;
107}
108
109// Reads the error file and analyzes the data
110void Error::analyzeEvent()
111{
112 // Get the number of bytes to read
Eddie James9789e712022-05-25 15:43:40 -0500113 int err = 0;
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530114 int len = -1;
115 auto r = ioctl(fd, FIONREAD, &len);
116 if (r < 0)
117 {
118 elog<ConfigFailure>(
Gunnar Mills94df8c92018-09-14 14:50:03 -0500119 phosphor::logging::org::open_power::OCC::Device::ConfigFailure::
120 CALLOUT_ERRNO(errno),
121 phosphor::logging::org::open_power::OCC::Device::ConfigFailure::
122 CALLOUT_DEVICE_PATH(file.c_str()));
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530123 }
124
125 // A non-zero data indicates an error condition
126 // Let the caller take appropriate action on this
127 auto data = readFile(len);
Eddie James9789e712022-05-25 15:43:40 -0500128 if (!data.empty())
129 err = std::stoi(data, nullptr, 0);
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530130 if (callBack)
131 {
Eddie James9789e712022-05-25 15:43:40 -0500132 callBack(err);
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530133 }
134 return;
135}
136
137// Reads so many bytes as passed in
138std::string Error::readFile(int len) const
139{
Gunnar Mills94df8c92018-09-14 14:50:03 -0500140 auto data = std::make_unique<char[]>(len + 1);
Andrew Geissler11110872018-01-17 11:07:01 -0800141 auto retries = 3;
142 auto delay = std::chrono::milliseconds{100};
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530143
Andrew Geissler11110872018-01-17 11:07:01 -0800144 // OCC / FSI have intermittent issues so retry all reads
145 while (true)
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530146 {
Andrew Geissler11110872018-01-17 11:07:01 -0800147 // This file get created soon after binding. A value of 0 is
148 // deemed success and anything else is a Failure
149 // Since all the sysfs files would have size of 4096, if we read 0
150 // bytes -or- value '0', then it just means we are fine
151 auto r = read(fd, data.get(), len);
152 if (r < 0)
153 {
154 retries--;
155 if (retries == 0)
156 {
157 elog<ReadFailure>(
158 phosphor::logging::org::open_power::OCC::Device::
159 ReadFailure::CALLOUT_ERRNO(errno),
160 phosphor::logging::org::open_power::OCC::Device::
161 ReadFailure::CALLOUT_DEVICE_PATH(file.c_str()));
162 break;
163 }
164 std::this_thread::sleep_for(delay);
165 continue;
166 }
167 break;
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530168 }
Vishwanatha Subbanna2c129132017-08-29 21:12:01 +0530169 // Need to seek to START, else the poll returns immediately telling
170 // there is data to be read
Andrew Geissler11110872018-01-17 11:07:01 -0800171 auto r = lseek(fd, 0, SEEK_SET);
Vishwanatha Subbanna2c129132017-08-29 21:12:01 +0530172 if (r < 0)
173 {
174 log<level::ERR>("Failure seeking error file to START");
175 elog<ConfigFailure>(
Gunnar Mills94df8c92018-09-14 14:50:03 -0500176 phosphor::logging::org::open_power::OCC::Device::ConfigFailure::
177 CALLOUT_ERRNO(errno),
178 phosphor::logging::org::open_power::OCC::Device::ConfigFailure::
179 CALLOUT_DEVICE_PATH(file.c_str()));
Vishwanatha Subbanna2c129132017-08-29 21:12:01 +0530180 }
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530181 return std::string(data.get());
182}
183
184} // namespace occ
185} // namespace open_power