blob: bfff1113a86949d21d0e5813317156800e08b315 [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>(
Chris Cainf0295f52024-09-12 15:41:14 -050035 std::format("Error::openFile: open of {} failed (errno={})",
36 file.c_str(), open_errno)
Chris Caina8857c52021-01-27 11:53:05 -060037 .c_str());
Gunnar Mills94df8c92018-09-14 14:50:03 -050038 elog<OpenFailure>(phosphor::logging::org::open_power::OCC::Device::
Chris Caina8857c52021-01-27 11:53:05 -060039 OpenFailure::CALLOUT_ERRNO(open_errno),
Gunnar Mills94df8c92018-09-14 14:50:03 -050040 phosphor::logging::org::open_power::OCC::Device::
41 OpenFailure::CALLOUT_DEVICE_PATH(file.c_str()));
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053042 }
43}
44
45// Attaches the FD to event loop and registers the callback handler
46void Error::registerCallBack()
47{
48 decltype(eventSource.get()) sourcePtr = nullptr;
Gunnar Mills94df8c92018-09-14 14:50:03 -050049 auto r = sd_event_add_io(event.get(), &sourcePtr, fd, EPOLLPRI | EPOLLERR,
50 processEvents, this);
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053051 eventSource.reset(sourcePtr);
52
53 if (r < 0)
54 {
55 log<level::ERR>("Failed to register callback handler",
Gunnar Mills94df8c92018-09-14 14:50:03 -050056 entry("ERROR=%s", strerror(-r)));
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053057 elog<InternalFailure>();
58 }
59}
60
61// Starts to watch for errors
Eddie James774f9af2019-03-19 20:58:53 +000062void Error::addWatch(bool poll)
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053063{
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +053064 if (!watching)
65 {
66 // Open the file
67 openFile();
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053068
Eddie James774f9af2019-03-19 20:58:53 +000069 if (poll)
70 {
71 // register the callback handler
72 registerCallBack();
73 }
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +053074
75 // Set we are watching the error
76 watching = true;
77 }
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053078}
79
80// Stops watching for errors
81void Error::removeWatch()
82{
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +053083 if (watching)
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053084 {
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +053085 // Close the file
86 if (fd >= 0)
87 {
88 close(fd);
89 }
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053090
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +053091 // Reduce the reference count. Since there is only one instances
92 // of add_io, this will result empty loop
93 eventSource.reset();
94
95 // We are no more watching the error
96 watching = false;
97 }
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053098}
99
100// Callback handler when there is an activity on the FD
George Liud0345ae2021-09-10 13:13:28 +0800101int Error::processEvents(sd_event_source* /*es*/, int /*fd*/,
102 uint32_t /*revents*/, void* userData)
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530103{
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530104 auto error = static_cast<Error*>(userData);
105
106 error->analyzeEvent();
107 return 0;
108}
109
110// Reads the error file and analyzes the data
111void Error::analyzeEvent()
112{
113 // Get the number of bytes to read
Eddie James9789e712022-05-25 15:43:40 -0500114 int err = 0;
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530115 int len = -1;
116 auto r = ioctl(fd, FIONREAD, &len);
117 if (r < 0)
118 {
119 elog<ConfigFailure>(
Gunnar Mills94df8c92018-09-14 14:50:03 -0500120 phosphor::logging::org::open_power::OCC::Device::ConfigFailure::
121 CALLOUT_ERRNO(errno),
122 phosphor::logging::org::open_power::OCC::Device::ConfigFailure::
123 CALLOUT_DEVICE_PATH(file.c_str()));
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530124 }
125
126 // A non-zero data indicates an error condition
127 // Let the caller take appropriate action on this
128 auto data = readFile(len);
Eddie James9789e712022-05-25 15:43:40 -0500129 if (!data.empty())
130 err = std::stoi(data, nullptr, 0);
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530131 if (callBack)
132 {
Eddie James9789e712022-05-25 15:43:40 -0500133 callBack(err);
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530134 }
135 return;
136}
137
138// Reads so many bytes as passed in
139std::string Error::readFile(int len) const
140{
Gunnar Mills94df8c92018-09-14 14:50:03 -0500141 auto data = std::make_unique<char[]>(len + 1);
Andrew Geissler11110872018-01-17 11:07:01 -0800142 auto retries = 3;
143 auto delay = std::chrono::milliseconds{100};
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530144
Andrew Geissler11110872018-01-17 11:07:01 -0800145 // OCC / FSI have intermittent issues so retry all reads
146 while (true)
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530147 {
Andrew Geissler11110872018-01-17 11:07:01 -0800148 // This file get created soon after binding. A value of 0 is
149 // deemed success and anything else is a Failure
150 // Since all the sysfs files would have size of 4096, if we read 0
151 // bytes -or- value '0', then it just means we are fine
152 auto r = read(fd, data.get(), len);
153 if (r < 0)
154 {
155 retries--;
156 if (retries == 0)
157 {
158 elog<ReadFailure>(
159 phosphor::logging::org::open_power::OCC::Device::
160 ReadFailure::CALLOUT_ERRNO(errno),
161 phosphor::logging::org::open_power::OCC::Device::
162 ReadFailure::CALLOUT_DEVICE_PATH(file.c_str()));
163 break;
164 }
165 std::this_thread::sleep_for(delay);
166 continue;
167 }
168 break;
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530169 }
Vishwanatha Subbanna2c129132017-08-29 21:12:01 +0530170 // Need to seek to START, else the poll returns immediately telling
171 // there is data to be read
Andrew Geissler11110872018-01-17 11:07:01 -0800172 auto r = lseek(fd, 0, SEEK_SET);
Vishwanatha Subbanna2c129132017-08-29 21:12:01 +0530173 if (r < 0)
174 {
175 log<level::ERR>("Failure seeking error file to START");
176 elog<ConfigFailure>(
Gunnar Mills94df8c92018-09-14 14:50:03 -0500177 phosphor::logging::org::open_power::OCC::Device::ConfigFailure::
178 CALLOUT_ERRNO(errno),
179 phosphor::logging::org::open_power::OCC::Device::ConfigFailure::
180 CALLOUT_DEVICE_PATH(file.c_str()));
Vishwanatha Subbanna2c129132017-08-29 21:12:01 +0530181 }
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530182 return std::string(data.get());
183}
184
185} // namespace occ
186} // namespace open_power