summaryrefslogtreecommitdiffstats
path: root/occ_errors.cpp
diff options
context:
space:
mode:
authorVishwanatha Subbanna <vishwa@linux.vnet.ibm.com>2017-06-29 18:35:00 +0530
committerVishwanatha Subbanna <vishwa@linux.vnet.ibm.com>2017-07-29 23:57:59 +0530
commitee4d83dfc7b6cf3b5979541ab5b1918b68e6bbdb (patch)
tree4d186ddf133d77880e857fccdddb71fcc155a6bf /occ_errors.cpp
parent554d60059e7d0b699b3cdcbe8de2c341613e9931 (diff)
downloadopenpower-occ-control-ee4d83dfc7b6cf3b5979541ab5b1918b68e6bbdb.tar.gz
openpower-occ-control-ee4d83dfc7b6cf3b5979541ab5b1918b68e6bbdb.zip
Add support to watch for OCC errors
Change-Id: I98d95020a2d01e281e5c8efa825d6b4bd4c6c160 Signed-off-by: Vishwanatha Subbanna <vishwa@linux.vnet.ibm.com>
Diffstat (limited to 'occ_errors.cpp')
-rw-r--r--occ_errors.cpp145
1 files changed, 145 insertions, 0 deletions
diff --git a/occ_errors.cpp b/occ_errors.cpp
new file mode 100644
index 0000000..f2da49f
--- /dev/null
+++ b/occ_errors.cpp
@@ -0,0 +1,145 @@
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <phosphor-logging/log.hpp>
+#include <phosphor-logging/elog.hpp>
+#include <xyz/openbmc_project/Common/error.hpp>
+#include <org/open_power/OCC/Device/error.hpp>
+#include "occ_errors.hpp"
+#include "elog-errors.hpp"
+namespace open_power
+{
+namespace occ
+{
+
+// Value in error file indicating success
+constexpr auto NO_ERROR = '0';
+
+using namespace phosphor::logging;
+using namespace sdbusplus::org::open_power::OCC::Device::Error;
+using InternalFailure = sdbusplus::xyz::openbmc_project::Common::
+ Error::InternalFailure;
+
+// Populate the file descriptor on the error file
+void Error::openFile()
+{
+ using namespace phosphor::logging;
+
+ fd = open(file.c_str(), O_RDONLY | O_NONBLOCK);
+ if (fd < 0)
+ {
+ elog<OpenFailure>(
+ phosphor::logging::org::open_power::OCC::Device::
+ OpenFailure::CALLOUT_ERRNO(errno),
+ phosphor::logging::org::open_power::OCC::Device::
+ OpenFailure::CALLOUT_DEVICE_PATH(file.c_str()));
+ }
+}
+
+// Attaches the FD to event loop and registers the callback handler
+void Error::registerCallBack()
+{
+ decltype(eventSource.get()) sourcePtr = nullptr;
+ auto r = sd_event_add_io(event.get(), &sourcePtr, fd,
+ EPOLLIN, processEvents, this);
+ eventSource.reset(sourcePtr);
+
+ if (r < 0)
+ {
+ log<level::ERR>("Failed to register callback handler",
+ entry("ERROR=%s", strerror(-r)));
+ elog<InternalFailure>();
+ }
+}
+
+// Starts to watch for errors
+void Error::addWatch()
+{
+ // Open the file
+ openFile();
+
+ // register the callback handler
+ registerCallBack();
+}
+
+// Stops watching for errors
+void Error::removeWatch()
+{
+ // Close the file
+ if (fd >= 0)
+ {
+ close(fd);
+ }
+
+ // Reduce the reference count. Since there is only one instances
+ // of add_io, this will result empty loop
+ eventSource.reset();
+}
+
+// Callback handler when there is an activity on the FD
+int Error::processEvents(sd_event_source* es, int fd,
+ uint32_t revents, void* userData)
+{
+ log<level::INFO>("Error file updated");
+ auto error = static_cast<Error*>(userData);
+
+ error->analyzeEvent();
+ return 0;
+}
+
+// Reads the error file and analyzes the data
+void Error::analyzeEvent()
+{
+ // Get the number of bytes to read
+ int len = -1;
+ auto r = ioctl(fd, FIONREAD, &len);
+ if (r < 0)
+ {
+ elog<ConfigFailure>(
+ phosphor::logging::org::open_power::OCC::Device::
+ ConfigFailure::CALLOUT_ERRNO(errno),
+ phosphor::logging::org::open_power::OCC::Device::
+ ConfigFailure::CALLOUT_DEVICE_PATH(file.c_str()));
+ }
+
+ // A non-zero data indicates an error condition
+ // Let the caller take appropriate action on this
+ auto data = readFile(len);
+ if (data.empty() ||
+ data.front() == NO_ERROR)
+ {
+ return;
+ }
+
+ // This must be an error
+ if (callBack)
+ {
+ callBack();
+ }
+ return;
+}
+
+// Reads so many bytes as passed in
+std::string Error::readFile(int len) const
+{
+ auto data = std::make_unique<char[]>(len+1);
+
+ // This file get created soon after binding. A value of 0 is
+ // deemed success and anything else is a Failure
+ // Since all the sysfs files would have size of 4096, if we read 0
+ // bytes -or- value '0', then it just means we are fine
+ auto r = read(fd, data.get(), len);
+ if (r < 0)
+ {
+ elog<ReadFailure>(
+ phosphor::logging::org::open_power::OCC::Device::
+ ReadFailure::CALLOUT_ERRNO(errno),
+ phosphor::logging::org::open_power::OCC::Device::
+ ReadFailure::CALLOUT_DEVICE_PATH(file.c_str()));
+ }
+ return std::string(data.get());
+}
+
+} // namespace occ
+} // namespace open_power
OpenPOWER on IntegriCloud