blob: 63c1881896cf45f2f5c189b4a553082619d9bc6d [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>
Chris Caina8857c52021-01-27 11:53:05 -06005#include <fmt/core.h>
Gunnar Mills94df8c92018-09-14 14:50:03 -05006#include <sys/ioctl.h>
7#include <unistd.h>
8
9#include <org/open_power/OCC/Device/error.hpp>
Patrick Williamsd8aab2a2023-04-21 11:15:54 -050010#include <phosphor-logging/elog-errors.hpp>
Gunnar Mills94df8c92018-09-14 14:50:03 -050011#include <phosphor-logging/elog.hpp>
12#include <phosphor-logging/log.hpp>
13#include <xyz/openbmc_project/Common/error.hpp>
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053014namespace open_power
15{
16namespace occ
17{
18
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053019using namespace phosphor::logging;
20using namespace sdbusplus::org::open_power::OCC::Device::Error;
Gunnar Mills94df8c92018-09-14 14:50:03 -050021using InternalFailure =
22 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053023
24// Populate the file descriptor on the error file
25void Error::openFile()
26{
27 using namespace phosphor::logging;
28
29 fd = open(file.c_str(), O_RDONLY | O_NONBLOCK);
Chris Caina8857c52021-01-27 11:53:05 -060030 const int open_errno = errno;
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053031 if (fd < 0)
32 {
Chris Caina8857c52021-01-27 11:53:05 -060033 log<level::ERR>(
34 fmt::format("Error::openFile: open failed (errno={})", open_errno)
35 .c_str());
Gunnar Mills94df8c92018-09-14 14:50:03 -050036 elog<OpenFailure>(phosphor::logging::org::open_power::OCC::Device::
Chris Caina8857c52021-01-27 11:53:05 -060037 OpenFailure::CALLOUT_ERRNO(open_errno),
Gunnar Mills94df8c92018-09-14 14:50:03 -050038 phosphor::logging::org::open_power::OCC::Device::
39 OpenFailure::CALLOUT_DEVICE_PATH(file.c_str()));
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053040 }
41}
42
43// Attaches the FD to event loop and registers the callback handler
44void Error::registerCallBack()
45{
46 decltype(eventSource.get()) sourcePtr = nullptr;
Gunnar Mills94df8c92018-09-14 14:50:03 -050047 auto r = sd_event_add_io(event.get(), &sourcePtr, fd, EPOLLPRI | EPOLLERR,
48 processEvents, this);
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053049 eventSource.reset(sourcePtr);
50
51 if (r < 0)
52 {
53 log<level::ERR>("Failed to register callback handler",
Gunnar Mills94df8c92018-09-14 14:50:03 -050054 entry("ERROR=%s", strerror(-r)));
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053055 elog<InternalFailure>();
56 }
57}
58
59// Starts to watch for errors
Eddie James774f9af2019-03-19 20:58:53 +000060void Error::addWatch(bool poll)
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053061{
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +053062 if (!watching)
63 {
64 // Open the file
65 openFile();
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053066
Eddie James774f9af2019-03-19 20:58:53 +000067 if (poll)
68 {
69 // register the callback handler
70 registerCallBack();
71 }
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +053072
73 // Set we are watching the error
74 watching = true;
75 }
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053076}
77
78// Stops watching for errors
79void Error::removeWatch()
80{
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +053081 if (watching)
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053082 {
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +053083 // Close the file
84 if (fd >= 0)
85 {
86 close(fd);
87 }
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053088
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +053089 // Reduce the reference count. Since there is only one instances
90 // of add_io, this will result empty loop
91 eventSource.reset();
92
93 // We are no more watching the error
94 watching = false;
95 }
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053096}
97
98// Callback handler when there is an activity on the FD
George Liud0345ae2021-09-10 13:13:28 +080099int Error::processEvents(sd_event_source* /*es*/, int /*fd*/,
100 uint32_t /*revents*/, void* userData)
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530101{
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530102 auto error = static_cast<Error*>(userData);
103
104 error->analyzeEvent();
105 return 0;
106}
107
108// Reads the error file and analyzes the data
109void Error::analyzeEvent()
110{
111 // Get the number of bytes to read
Eddie James9789e712022-05-25 15:43:40 -0500112 int err = 0;
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530113 int len = -1;
114 auto r = ioctl(fd, FIONREAD, &len);
115 if (r < 0)
116 {
117 elog<ConfigFailure>(
Gunnar Mills94df8c92018-09-14 14:50:03 -0500118 phosphor::logging::org::open_power::OCC::Device::ConfigFailure::
119 CALLOUT_ERRNO(errno),
120 phosphor::logging::org::open_power::OCC::Device::ConfigFailure::
121 CALLOUT_DEVICE_PATH(file.c_str()));
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530122 }
123
124 // A non-zero data indicates an error condition
125 // Let the caller take appropriate action on this
126 auto data = readFile(len);
Eddie James9789e712022-05-25 15:43:40 -0500127 if (!data.empty())
128 err = std::stoi(data, nullptr, 0);
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530129 if (callBack)
130 {
Eddie James9789e712022-05-25 15:43:40 -0500131 callBack(err);
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530132 }
133 return;
134}
135
136// Reads so many bytes as passed in
137std::string Error::readFile(int len) const
138{
Gunnar Mills94df8c92018-09-14 14:50:03 -0500139 auto data = std::make_unique<char[]>(len + 1);
Andrew Geissler11110872018-01-17 11:07:01 -0800140 auto retries = 3;
141 auto delay = std::chrono::milliseconds{100};
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530142
Andrew Geissler11110872018-01-17 11:07:01 -0800143 // OCC / FSI have intermittent issues so retry all reads
144 while (true)
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530145 {
Andrew Geissler11110872018-01-17 11:07:01 -0800146 // This file get created soon after binding. A value of 0 is
147 // deemed success and anything else is a Failure
148 // Since all the sysfs files would have size of 4096, if we read 0
149 // bytes -or- value '0', then it just means we are fine
150 auto r = read(fd, data.get(), len);
151 if (r < 0)
152 {
153 retries--;
154 if (retries == 0)
155 {
156 elog<ReadFailure>(
157 phosphor::logging::org::open_power::OCC::Device::
158 ReadFailure::CALLOUT_ERRNO(errno),
159 phosphor::logging::org::open_power::OCC::Device::
160 ReadFailure::CALLOUT_DEVICE_PATH(file.c_str()));
161 break;
162 }
163 std::this_thread::sleep_for(delay);
164 continue;
165 }
166 break;
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530167 }
Vishwanatha Subbanna2c129132017-08-29 21:12:01 +0530168 // Need to seek to START, else the poll returns immediately telling
169 // there is data to be read
Andrew Geissler11110872018-01-17 11:07:01 -0800170 auto r = lseek(fd, 0, SEEK_SET);
Vishwanatha Subbanna2c129132017-08-29 21:12:01 +0530171 if (r < 0)
172 {
173 log<level::ERR>("Failure seeking error file to START");
174 elog<ConfigFailure>(
Gunnar Mills94df8c92018-09-14 14:50:03 -0500175 phosphor::logging::org::open_power::OCC::Device::ConfigFailure::
176 CALLOUT_ERRNO(errno),
177 phosphor::logging::org::open_power::OCC::Device::ConfigFailure::
178 CALLOUT_DEVICE_PATH(file.c_str()));
Vishwanatha Subbanna2c129132017-08-29 21:12:01 +0530179 }
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530180 return std::string(data.get());
181}
182
183} // namespace occ
184} // namespace open_power