blob: a35637892dd8009c07d2c3adf40830522d43b3aa [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>
Chris Caina8857c52021-01-27 11:53:05 -06007#include <fmt/core.h>
Gunnar Mills94df8c92018-09-14 14:50:03 -05008#include <sys/ioctl.h>
9#include <unistd.h>
10
11#include <org/open_power/OCC/Device/error.hpp>
12#include <phosphor-logging/elog.hpp>
13#include <phosphor-logging/log.hpp>
14#include <xyz/openbmc_project/Common/error.hpp>
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053015namespace open_power
16{
17namespace occ
18{
19
20// Value in error file indicating success
21constexpr auto NO_ERROR = '0';
22
23using namespace phosphor::logging;
24using namespace sdbusplus::org::open_power::OCC::Device::Error;
Gunnar Mills94df8c92018-09-14 14:50:03 -050025using InternalFailure =
26 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053027
28// Populate the file descriptor on the error file
29void Error::openFile()
30{
31 using namespace phosphor::logging;
32
33 fd = open(file.c_str(), O_RDONLY | O_NONBLOCK);
Chris Caina8857c52021-01-27 11:53:05 -060034 const int open_errno = errno;
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053035 if (fd < 0)
36 {
Chris Caina8857c52021-01-27 11:53:05 -060037 log<level::ERR>(
38 fmt::format("Error::openFile: open failed (errno={})", open_errno)
39 .c_str());
Gunnar Mills94df8c92018-09-14 14:50:03 -050040 elog<OpenFailure>(phosphor::logging::org::open_power::OCC::Device::
Chris Caina8857c52021-01-27 11:53:05 -060041 OpenFailure::CALLOUT_ERRNO(open_errno),
Gunnar Mills94df8c92018-09-14 14:50:03 -050042 phosphor::logging::org::open_power::OCC::Device::
43 OpenFailure::CALLOUT_DEVICE_PATH(file.c_str()));
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053044 }
45}
46
47// Attaches the FD to event loop and registers the callback handler
48void Error::registerCallBack()
49{
50 decltype(eventSource.get()) sourcePtr = nullptr;
Gunnar Mills94df8c92018-09-14 14:50:03 -050051 auto r = sd_event_add_io(event.get(), &sourcePtr, fd, EPOLLPRI | EPOLLERR,
52 processEvents, this);
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053053 eventSource.reset(sourcePtr);
54
55 if (r < 0)
56 {
57 log<level::ERR>("Failed to register callback handler",
Gunnar Mills94df8c92018-09-14 14:50:03 -050058 entry("ERROR=%s", strerror(-r)));
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053059 elog<InternalFailure>();
60 }
61}
62
63// Starts to watch for errors
Eddie James774f9af2019-03-19 20:58:53 +000064void Error::addWatch(bool poll)
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053065{
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +053066 if (!watching)
67 {
68 // Open the file
69 openFile();
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053070
Eddie James774f9af2019-03-19 20:58:53 +000071 if (poll)
72 {
73 // register the callback handler
74 registerCallBack();
75 }
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +053076
77 // Set we are watching the error
78 watching = true;
79 }
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053080}
81
82// Stops watching for errors
83void Error::removeWatch()
84{
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +053085 if (watching)
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053086 {
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +053087 // Close the file
88 if (fd >= 0)
89 {
90 close(fd);
91 }
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +053092
Vishwanatha Subbanna2dc9b1a2017-08-18 18:29:41 +053093 // Reduce the reference count. Since there is only one instances
94 // of add_io, this will result empty loop
95 eventSource.reset();
96
97 // We are no more watching the error
98 watching = false;
99 }
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530100}
101
102// Callback handler when there is an activity on the FD
Gunnar Mills94df8c92018-09-14 14:50:03 -0500103int Error::processEvents(sd_event_source* es, int fd, uint32_t revents,
104 void* userData)
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530105{
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530106 auto error = static_cast<Error*>(userData);
107
108 error->analyzeEvent();
109 return 0;
110}
111
112// Reads the error file and analyzes the data
113void Error::analyzeEvent()
114{
115 // Get the number of bytes to read
116 int len = -1;
117 auto r = ioctl(fd, FIONREAD, &len);
118 if (r < 0)
119 {
120 elog<ConfigFailure>(
Gunnar Mills94df8c92018-09-14 14:50:03 -0500121 phosphor::logging::org::open_power::OCC::Device::ConfigFailure::
122 CALLOUT_ERRNO(errno),
123 phosphor::logging::org::open_power::OCC::Device::ConfigFailure::
124 CALLOUT_DEVICE_PATH(file.c_str()));
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530125 }
126
127 // A non-zero data indicates an error condition
128 // Let the caller take appropriate action on this
129 auto data = readFile(len);
Eddie James482e31f2017-09-14 13:17:17 -0500130 bool error = !(data.empty() || data.front() == NO_ERROR);
Vishwanatha Subbannaee4d83d2017-06-29 18:35:00 +0530131 if (callBack)
132 {
Eddie James482e31f2017-09-14 13:17:17 -0500133 callBack(error);
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