blob: ae66a62dd38a0f576594bcd6492115c8d36aba4a [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
59void Error::addWatch()
60{
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
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +053066 // register the callback handler
67 registerCallBack();
68
69 // Set we are watching the error
70 watching = true;
71 }
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053072}
73
74// Stops watching for errors
75void Error::removeWatch()
76{
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +053077 if (watching)
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053078 {
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +053079 // Close the file
80 if (fd >= 0)
81 {
82 close(fd);
83 }
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053084
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +053085 // Reduce the reference count. Since there is only one instances
86 // of add_io, this will result empty loop
87 eventSource.reset();
88
89 // We are no more watching the error
90 watching = false;
91 }
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053092}
93
94// Callback handler when there is an activity on the FD
Gunnar Mills94df8c92018-09-14 14:50:03 -050095int Error::processEvents(sd_event_source* es, int fd, uint32_t revents,
96 void* userData)
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053097{
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053098 auto error = static_cast<Error*>(userData);
99
100 error->analyzeEvent();
101 return 0;
102}
103
104// Reads the error file and analyzes the data
105void Error::analyzeEvent()
106{
107 // Get the number of bytes to read
108 int len = -1;
109 auto r = ioctl(fd, FIONREAD, &len);
110 if (r < 0)
111 {
112 elog<ConfigFailure>(
Gunnar Mills94df8c92018-09-14 14:50:03 -0500113 phosphor::logging::org::open_power::OCC::Device::ConfigFailure::
114 CALLOUT_ERRNO(errno),
115 phosphor::logging::org::open_power::OCC::Device::ConfigFailure::
116 CALLOUT_DEVICE_PATH(file.c_str()));
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530117 }
118
119 // A non-zero data indicates an error condition
120 // Let the caller take appropriate action on this
121 auto data = readFile(len);
Eddie James482e31f2017-09-14 13:17:17 -0500122 bool error = !(data.empty() || data.front() == NO_ERROR);
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530123 if (callBack)
124 {
Eddie James482e31f2017-09-14 13:17:17 -0500125 callBack(error);
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530126 }
127 return;
128}
129
130// Reads so many bytes as passed in
131std::string Error::readFile(int len) const
132{
Gunnar Mills94df8c92018-09-14 14:50:03 -0500133 auto data = std::make_unique<char[]>(len + 1);
Andrew Geissler11110872018-01-17 11:07:01 -0800134 auto retries = 3;
135 auto delay = std::chrono::milliseconds{100};
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530136
Andrew Geissler11110872018-01-17 11:07:01 -0800137 // OCC / FSI have intermittent issues so retry all reads
138 while (true)
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530139 {
Andrew Geissler11110872018-01-17 11:07:01 -0800140 // This file get created soon after binding. A value of 0 is
141 // deemed success and anything else is a Failure
142 // Since all the sysfs files would have size of 4096, if we read 0
143 // bytes -or- value '0', then it just means we are fine
144 auto r = read(fd, data.get(), len);
145 if (r < 0)
146 {
147 retries--;
148 if (retries == 0)
149 {
150 elog<ReadFailure>(
151 phosphor::logging::org::open_power::OCC::Device::
152 ReadFailure::CALLOUT_ERRNO(errno),
153 phosphor::logging::org::open_power::OCC::Device::
154 ReadFailure::CALLOUT_DEVICE_PATH(file.c_str()));
155 break;
156 }
157 std::this_thread::sleep_for(delay);
158 continue;
159 }
160 break;
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530161 }
Vishwanatha Subbanna2c129132017-08-29 21:12:01 +0530162 // Need to seek to START, else the poll returns immediately telling
163 // there is data to be read
Andrew Geissler11110872018-01-17 11:07:01 -0800164 auto r = lseek(fd, 0, SEEK_SET);
Vishwanatha Subbanna2c129132017-08-29 21:12:01 +0530165 if (r < 0)
166 {
167 log<level::ERR>("Failure seeking error file to START");
168 elog<ConfigFailure>(
Gunnar Mills94df8c92018-09-14 14:50:03 -0500169 phosphor::logging::org::open_power::OCC::Device::ConfigFailure::
170 CALLOUT_ERRNO(errno),
171 phosphor::logging::org::open_power::OCC::Device::ConfigFailure::
172 CALLOUT_DEVICE_PATH(file.c_str()));
Vishwanatha Subbanna2c129132017-08-29 21:12:01 +0530173 }
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530174 return std::string(data.get());
175}
176
177} // namespace occ
178} // namespace open_power