1ee4d83dfSVishwanatha Subbanna #include "occ_errors.hpp"
294df8c90SGunnar Mills
394df8c90SGunnar Mills #include <errno.h>
494df8c90SGunnar Mills #include <fcntl.h>
594df8c90SGunnar Mills #include <sys/ioctl.h>
694df8c90SGunnar Mills #include <unistd.h>
794df8c90SGunnar Mills
894df8c90SGunnar Mills #include <org/open_power/OCC/Device/error.hpp>
9d8aab2a9SPatrick Williams #include <phosphor-logging/elog-errors.hpp>
1094df8c90SGunnar Mills #include <phosphor-logging/elog.hpp>
11*37abe9beSChris Cain #include <phosphor-logging/lg2.hpp>
1294df8c90SGunnar Mills #include <phosphor-logging/log.hpp>
1394df8c90SGunnar Mills #include <xyz/openbmc_project/Common/error.hpp>
1448002498SPatrick Williams
15ee4d83dfSVishwanatha Subbanna namespace open_power
16ee4d83dfSVishwanatha Subbanna {
17ee4d83dfSVishwanatha Subbanna namespace occ
18ee4d83dfSVishwanatha Subbanna {
19ee4d83dfSVishwanatha Subbanna
20ee4d83dfSVishwanatha Subbanna using namespace phosphor::logging;
21ee4d83dfSVishwanatha Subbanna using namespace sdbusplus::org::open_power::OCC::Device::Error;
2294df8c90SGunnar Mills using InternalFailure =
2394df8c90SGunnar Mills sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
24ee4d83dfSVishwanatha Subbanna
25ee4d83dfSVishwanatha Subbanna // Populate the file descriptor on the error file
openFile()26ee4d83dfSVishwanatha Subbanna void Error::openFile()
27ee4d83dfSVishwanatha Subbanna {
28ee4d83dfSVishwanatha Subbanna using namespace phosphor::logging;
29ee4d83dfSVishwanatha Subbanna
30ee4d83dfSVishwanatha Subbanna fd = open(file.c_str(), O_RDONLY | O_NONBLOCK);
31a8857c50SChris Cain const int open_errno = errno;
32ee4d83dfSVishwanatha Subbanna if (fd < 0)
33ee4d83dfSVishwanatha Subbanna {
34*37abe9beSChris Cain lg2::error("Error::openFile: open of {FILE} failed (errno={ERR})",
35*37abe9beSChris Cain "FILE", file.c_str(), "ERR", open_errno);
3694df8c90SGunnar Mills elog<OpenFailure>(phosphor::logging::org::open_power::OCC::Device::
37a8857c50SChris Cain OpenFailure::CALLOUT_ERRNO(open_errno),
38ee4d83dfSVishwanatha Subbanna phosphor::logging::org::open_power::OCC::Device::
39ee4d83dfSVishwanatha Subbanna OpenFailure::CALLOUT_DEVICE_PATH(file.c_str()));
40ee4d83dfSVishwanatha Subbanna }
41ee4d83dfSVishwanatha Subbanna }
42ee4d83dfSVishwanatha Subbanna
43ee4d83dfSVishwanatha Subbanna // Attaches the FD to event loop and registers the callback handler
registerCallBack()44ee4d83dfSVishwanatha Subbanna void Error::registerCallBack()
45ee4d83dfSVishwanatha Subbanna {
46ee4d83dfSVishwanatha Subbanna decltype(eventSource.get()) sourcePtr = nullptr;
4794df8c90SGunnar Mills auto r = sd_event_add_io(event.get(), &sourcePtr, fd, EPOLLPRI | EPOLLERR,
4894df8c90SGunnar Mills processEvents, this);
49ee4d83dfSVishwanatha Subbanna eventSource.reset(sourcePtr);
50ee4d83dfSVishwanatha Subbanna
51ee4d83dfSVishwanatha Subbanna if (r < 0)
52ee4d83dfSVishwanatha Subbanna {
53*37abe9beSChris Cain lg2::error("Failed to register callback handler: error={ERR}", "ERR",
54*37abe9beSChris Cain strerror(-r));
55ee4d83dfSVishwanatha Subbanna elog<InternalFailure>();
56ee4d83dfSVishwanatha Subbanna }
57ee4d83dfSVishwanatha Subbanna }
58ee4d83dfSVishwanatha Subbanna
59ee4d83dfSVishwanatha Subbanna // Starts to watch for errors
addWatch(bool poll)60774f9af9SEddie James void Error::addWatch(bool poll)
61ee4d83dfSVishwanatha Subbanna {
622dc9b1a2SVishwanatha Subbanna if (!watching)
632dc9b1a2SVishwanatha Subbanna {
64ee4d83dfSVishwanatha Subbanna // Open the file
65ee4d83dfSVishwanatha Subbanna openFile();
66ee4d83dfSVishwanatha Subbanna
67774f9af9SEddie James if (poll)
68774f9af9SEddie James {
69ee4d83dfSVishwanatha Subbanna // register the callback handler
70ee4d83dfSVishwanatha Subbanna registerCallBack();
71774f9af9SEddie James }
722dc9b1a2SVishwanatha Subbanna
732dc9b1a2SVishwanatha Subbanna // Set we are watching the error
742dc9b1a2SVishwanatha Subbanna watching = true;
752dc9b1a2SVishwanatha Subbanna }
76ee4d83dfSVishwanatha Subbanna }
77ee4d83dfSVishwanatha Subbanna
78ee4d83dfSVishwanatha Subbanna // Stops watching for errors
removeWatch()79ee4d83dfSVishwanatha Subbanna void Error::removeWatch()
80ee4d83dfSVishwanatha Subbanna {
812dc9b1a2SVishwanatha Subbanna if (watching)
822dc9b1a2SVishwanatha Subbanna {
83ee4d83dfSVishwanatha Subbanna // Close the file
84ee4d83dfSVishwanatha Subbanna if (fd >= 0)
85ee4d83dfSVishwanatha Subbanna {
86ee4d83dfSVishwanatha Subbanna close(fd);
87ee4d83dfSVishwanatha Subbanna }
88ee4d83dfSVishwanatha Subbanna
89ee4d83dfSVishwanatha Subbanna // Reduce the reference count. Since there is only one instances
90ee4d83dfSVishwanatha Subbanna // of add_io, this will result empty loop
91ee4d83dfSVishwanatha Subbanna eventSource.reset();
922dc9b1a2SVishwanatha Subbanna
932dc9b1a2SVishwanatha Subbanna // We are no more watching the error
942dc9b1a2SVishwanatha Subbanna watching = false;
952dc9b1a2SVishwanatha Subbanna }
96ee4d83dfSVishwanatha Subbanna }
97ee4d83dfSVishwanatha Subbanna
98ee4d83dfSVishwanatha Subbanna // Callback handler when there is an activity on the FD
processEvents(sd_event_source *,int,uint32_t,void * userData)99d0345ae0SGeorge Liu int Error::processEvents(sd_event_source* /*es*/, int /*fd*/,
100d0345ae0SGeorge Liu uint32_t /*revents*/, void* userData)
101ee4d83dfSVishwanatha Subbanna {
102ee4d83dfSVishwanatha Subbanna auto error = static_cast<Error*>(userData);
103ee4d83dfSVishwanatha Subbanna
104ee4d83dfSVishwanatha Subbanna error->analyzeEvent();
105ee4d83dfSVishwanatha Subbanna return 0;
106ee4d83dfSVishwanatha Subbanna }
107ee4d83dfSVishwanatha Subbanna
108ee4d83dfSVishwanatha Subbanna // Reads the error file and analyzes the data
analyzeEvent()109ee4d83dfSVishwanatha Subbanna void Error::analyzeEvent()
110ee4d83dfSVishwanatha Subbanna {
111ee4d83dfSVishwanatha Subbanna // Get the number of bytes to read
1129789e71fSEddie James int err = 0;
113ee4d83dfSVishwanatha Subbanna int len = -1;
114ee4d83dfSVishwanatha Subbanna auto r = ioctl(fd, FIONREAD, &len);
115ee4d83dfSVishwanatha Subbanna if (r < 0)
116ee4d83dfSVishwanatha Subbanna {
117ee4d83dfSVishwanatha Subbanna elog<ConfigFailure>(
11894df8c90SGunnar Mills phosphor::logging::org::open_power::OCC::Device::ConfigFailure::
11994df8c90SGunnar Mills CALLOUT_ERRNO(errno),
12094df8c90SGunnar Mills phosphor::logging::org::open_power::OCC::Device::ConfigFailure::
12194df8c90SGunnar Mills CALLOUT_DEVICE_PATH(file.c_str()));
122ee4d83dfSVishwanatha Subbanna }
123ee4d83dfSVishwanatha Subbanna
124ee4d83dfSVishwanatha Subbanna // A non-zero data indicates an error condition
125ee4d83dfSVishwanatha Subbanna // Let the caller take appropriate action on this
126ee4d83dfSVishwanatha Subbanna auto data = readFile(len);
1279789e71fSEddie James if (!data.empty())
1289789e71fSEddie James err = std::stoi(data, nullptr, 0);
129ee4d83dfSVishwanatha Subbanna if (callBack)
130ee4d83dfSVishwanatha Subbanna {
1319789e71fSEddie James callBack(err);
132ee4d83dfSVishwanatha Subbanna }
133ee4d83dfSVishwanatha Subbanna return;
134ee4d83dfSVishwanatha Subbanna }
135ee4d83dfSVishwanatha Subbanna
136ee4d83dfSVishwanatha Subbanna // Reads so many bytes as passed in
readFile(int len) const137ee4d83dfSVishwanatha Subbanna std::string Error::readFile(int len) const
138ee4d83dfSVishwanatha Subbanna {
139ee4d83dfSVishwanatha Subbanna auto data = std::make_unique<char[]>(len + 1);
1401111087eSAndrew Geissler auto retries = 3;
1411111087eSAndrew Geissler auto delay = std::chrono::milliseconds{100};
142ee4d83dfSVishwanatha Subbanna
1431111087eSAndrew Geissler // OCC / FSI have intermittent issues so retry all reads
1441111087eSAndrew Geissler while (true)
1451111087eSAndrew Geissler {
146ee4d83dfSVishwanatha Subbanna // This file get created soon after binding. A value of 0 is
147ee4d83dfSVishwanatha Subbanna // deemed success and anything else is a Failure
148ee4d83dfSVishwanatha Subbanna // Since all the sysfs files would have size of 4096, if we read 0
149ee4d83dfSVishwanatha Subbanna // bytes -or- value '0', then it just means we are fine
150ee4d83dfSVishwanatha Subbanna auto r = read(fd, data.get(), len);
151ee4d83dfSVishwanatha Subbanna if (r < 0)
152ee4d83dfSVishwanatha Subbanna {
1531111087eSAndrew Geissler retries--;
1541111087eSAndrew Geissler if (retries == 0)
1551111087eSAndrew Geissler {
156ee4d83dfSVishwanatha Subbanna elog<ReadFailure>(
157ee4d83dfSVishwanatha Subbanna phosphor::logging::org::open_power::OCC::Device::
158ee4d83dfSVishwanatha Subbanna ReadFailure::CALLOUT_ERRNO(errno),
159ee4d83dfSVishwanatha Subbanna phosphor::logging::org::open_power::OCC::Device::
160ee4d83dfSVishwanatha Subbanna ReadFailure::CALLOUT_DEVICE_PATH(file.c_str()));
1611111087eSAndrew Geissler break;
162ee4d83dfSVishwanatha Subbanna }
1631111087eSAndrew Geissler std::this_thread::sleep_for(delay);
1641111087eSAndrew Geissler continue;
1651111087eSAndrew Geissler }
1661111087eSAndrew Geissler break;
1671111087eSAndrew Geissler }
1682c129132SVishwanatha Subbanna // Need to seek to START, else the poll returns immediately telling
1692c129132SVishwanatha Subbanna // there is data to be read
1701111087eSAndrew Geissler auto r = lseek(fd, 0, SEEK_SET);
1712c129132SVishwanatha Subbanna if (r < 0)
1722c129132SVishwanatha Subbanna {
173*37abe9beSChris Cain lg2::error("Failure seeking error file to START");
1742c129132SVishwanatha Subbanna elog<ConfigFailure>(
17594df8c90SGunnar Mills phosphor::logging::org::open_power::OCC::Device::ConfigFailure::
17694df8c90SGunnar Mills CALLOUT_ERRNO(errno),
17794df8c90SGunnar Mills phosphor::logging::org::open_power::OCC::Device::ConfigFailure::
17894df8c90SGunnar Mills CALLOUT_DEVICE_PATH(file.c_str()));
1792c129132SVishwanatha Subbanna }
180ee4d83dfSVishwanatha Subbanna return std::string(data.get());
181ee4d83dfSVishwanatha Subbanna }
182ee4d83dfSVishwanatha Subbanna
183ee4d83dfSVishwanatha Subbanna } // namespace occ
184ee4d83dfSVishwanatha Subbanna } // namespace open_power
185