xref: /openbmc/openpower-occ-control/occ_errors.cpp (revision 37abe9be91df2bb173c9642a2740a425904d7921)
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