diff options
| author | Vishwanatha Subbanna <vishwa@linux.vnet.ibm.com> | 2017-06-29 18:35:00 +0530 | 
|---|---|---|
| committer | Vishwanatha Subbanna <vishwa@linux.vnet.ibm.com> | 2017-07-29 23:57:59 +0530 | 
| commit | ee4d83dfc7b6cf3b5979541ab5b1918b68e6bbdb (patch) | |
| tree | 4d186ddf133d77880e857fccdddb71fcc155a6bf /occ_errors.cpp | |
| parent | 554d60059e7d0b699b3cdcbe8de2c341613e9931 (diff) | |
| download | openpower-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.cpp | 145 | 
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 | 

