blob: ab7663aad0ebdd72d57f3fa2996c9a318d26219c [file] [log] [blame]
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +05301#include "occ_errors.hpp"
Gunnar Mills94df8c92018-09-14 14:50:03 -05002
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +05303#include "elog-errors.hpp"
Gunnar Mills94df8c92018-09-14 14:50:03 -05004
5#include <errno.h>
6#include <fcntl.h>
7#include <sys/ioctl.h>
8#include <unistd.h>
9
10#include <org/open_power/OCC/Device/error.hpp>
11#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
19// Value in error file indicating success
20constexpr auto NO_ERROR = '0';
21
22using namespace phosphor::logging;
23using namespace sdbusplus::org::open_power::OCC::Device::Error;
Gunnar Mills94df8c92018-09-14 14:50:03 -050024using InternalFailure =
25 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053026
27// Populate the file descriptor on the error file
28void Error::openFile()
29{
30 using namespace phosphor::logging;
31
32 fd = open(file.c_str(), O_RDONLY | O_NONBLOCK);
33 if (fd < 0)
34 {
Gunnar Mills94df8c92018-09-14 14:50:03 -050035 elog<OpenFailure>(phosphor::logging::org::open_power::OCC::Device::
36 OpenFailure::CALLOUT_ERRNO(errno),
37 phosphor::logging::org::open_power::OCC::Device::
38 OpenFailure::CALLOUT_DEVICE_PATH(file.c_str()));
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053039 }
40}
41
42// Attaches the FD to event loop and registers the callback handler
43void Error::registerCallBack()
44{
45 decltype(eventSource.get()) sourcePtr = nullptr;
Gunnar Mills94df8c92018-09-14 14:50:03 -050046 auto r = sd_event_add_io(event.get(), &sourcePtr, fd, EPOLLPRI | EPOLLERR,
47 processEvents, this);
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053048 eventSource.reset(sourcePtr);
49
50 if (r < 0)
51 {
52 log<level::ERR>("Failed to register callback handler",
Gunnar Mills94df8c92018-09-14 14:50:03 -050053 entry("ERROR=%s", strerror(-r)));
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053054 elog<InternalFailure>();
55 }
56}
57
58// Starts to watch for errors
Eddie James774f9af2019-03-19 20:58:53 +000059void Error::addWatch(bool poll)
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053060{
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +053061 if (!watching)
62 {
63 // Open the file
64 openFile();
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053065
Eddie James774f9af2019-03-19 20:58:53 +000066 if (poll)
67 {
68 // register the callback handler
69 registerCallBack();
70 }
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +053071
72 // Set we are watching the error
73 watching = true;
74 }
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053075}
76
77// Stops watching for errors
78void Error::removeWatch()
79{
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +053080 if (watching)
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053081 {
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +053082 // Close the file
83 if (fd >= 0)
84 {
85 close(fd);
86 }
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053087
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +053088 // Reduce the reference count. Since there is only one instances
89 // of add_io, this will result empty loop
90 eventSource.reset();
91
92 // We are no more watching the error
93 watching = false;
94 }
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053095}
96
97// Callback handler when there is an activity on the FD
Gunnar Mills94df8c92018-09-14 14:50:03 -050098int Error::processEvents(sd_event_source* es, int fd, uint32_t revents,
99 void* userData)
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530100{
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530101 auto error = static_cast<Error*>(userData);
102
103 error->analyzeEvent();
104 return 0;
105}
106
107// Reads the error file and analyzes the data
108void Error::analyzeEvent()
109{
110 // Get the number of bytes to read
111 int len = -1;
112 auto r = ioctl(fd, FIONREAD, &len);
113 if (r < 0)
114 {
115 elog<ConfigFailure>(
Gunnar Mills94df8c92018-09-14 14:50:03 -0500116 phosphor::logging::org::open_power::OCC::Device::ConfigFailure::
117 CALLOUT_ERRNO(errno),
118 phosphor::logging::org::open_power::OCC::Device::ConfigFailure::
119 CALLOUT_DEVICE_PATH(file.c_str()));
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530120 }
121
122 // A non-zero data indicates an error condition
123 // Let the caller take appropriate action on this
124 auto data = readFile(len);
Eddie James482e31f2017-09-14 13:17:17 -0500125 bool error = !(data.empty() || data.front() == NO_ERROR);
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530126 if (callBack)
127 {
Eddie James482e31f2017-09-14 13:17:17 -0500128 callBack(error);
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530129 }
130 return;
131}
132
133// Reads so many bytes as passed in
134std::string Error::readFile(int len) const
135{
Gunnar Mills94df8c92018-09-14 14:50:03 -0500136 auto data = std::make_unique<char[]>(len + 1);
Andrew Geissler11110872018-01-17 11:07:01 -0800137 auto retries = 3;
138 auto delay = std::chrono::milliseconds{100};
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530139
Andrew Geissler11110872018-01-17 11:07:01 -0800140 // OCC / FSI have intermittent issues so retry all reads
141 while (true)
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530142 {
Andrew Geissler11110872018-01-17 11:07:01 -0800143 // This file get created soon after binding. A value of 0 is
144 // deemed success and anything else is a Failure
145 // Since all the sysfs files would have size of 4096, if we read 0
146 // bytes -or- value '0', then it just means we are fine
147 auto r = read(fd, data.get(), len);
148 if (r < 0)
149 {
150 retries--;
151 if (retries == 0)
152 {
153 elog<ReadFailure>(
154 phosphor::logging::org::open_power::OCC::Device::
155 ReadFailure::CALLOUT_ERRNO(errno),
156 phosphor::logging::org::open_power::OCC::Device::
157 ReadFailure::CALLOUT_DEVICE_PATH(file.c_str()));
158 break;
159 }
160 std::this_thread::sleep_for(delay);
161 continue;
162 }
163 break;
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530164 }
Vishwanatha Subbanna2c129132017-08-29 21:12:01 +0530165 // Need to seek to START, else the poll returns immediately telling
166 // there is data to be read
Andrew Geissler11110872018-01-17 11:07:01 -0800167 auto r = lseek(fd, 0, SEEK_SET);
Vishwanatha Subbanna2c129132017-08-29 21:12:01 +0530168 if (r < 0)
169 {
170 log<level::ERR>("Failure seeking error file to START");
171 elog<ConfigFailure>(
Gunnar Mills94df8c92018-09-14 14:50:03 -0500172 phosphor::logging::org::open_power::OCC::Device::ConfigFailure::
173 CALLOUT_ERRNO(errno),
174 phosphor::logging::org::open_power::OCC::Device::ConfigFailure::
175 CALLOUT_DEVICE_PATH(file.c_str()));
Vishwanatha Subbanna2c129132017-08-29 21:12:01 +0530176 }
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530177 return std::string(data.get());
178}
179
180} // namespace occ
181} // namespace open_power