blob: 7027d6539d83579c08fe1c83fd8577db675e1800 [file] [log] [blame]
#include <memory>
#include <algorithm>
#include <fcntl.h>
#include <errno.h>
#include <phosphor-logging/log.hpp>
#include <phosphor-logging/elog.hpp>
#include <org/open_power/OCC/PassThrough/error.hpp>
#include "occ_pass_through.hpp"
#include "occ_finder.hpp"
#include "elog-errors.hpp"
namespace open_power
{
namespace occ
{
namespace pass_through
{
void run()
{
auto bus = sdbusplus::bus::new_default();
sdbusplus::server::manager::manager objManager(bus,
OCC_PASS_THROUGH_ROOT);
std::vector<std::unique_ptr<PassThrough>> objects;
auto occs = open_power::occ::finder::get();
for (const auto& occ : occs)
{
auto occPassThrough = object(occ);
objects.emplace_back(
std::make_unique<PassThrough>(bus, occPassThrough.c_str()));
}
bus.request_name(OCC_PASS_THROUGH_BUSNAME);
while (true)
{
bus.process_discard();
bus.wait();
}
}
PassThrough::PassThrough(
sdbusplus::bus::bus& bus,
const char* path) :
Iface(bus, path),
path(path),
fd(openDevice())
{
// Nothing to do.
}
int PassThrough::openDevice()
{
using namespace phosphor::logging;
using namespace sdbusplus::org::open_power::OCC::PassThrough::Error;
// Device instance number starts from 1.
devicePath.append(std::to_string((this->path.back() - '0') + 1));
int fd = open(devicePath.c_str(), O_RDWR | O_NONBLOCK);
if (fd < 0)
{
// This would log and terminate since its not handled.
elog<OpenFailure>(
phosphor::logging::org::open_power::OCC::PassThrough::
OpenFailure::CALLOUT_ERRNO(errno),
phosphor::logging::org::open_power::OCC::PassThrough::
OpenFailure::CALLOUT_DEVICE_PATH(devicePath.c_str()));
}
return fd;
}
std::vector<int32_t> PassThrough::send(std::vector<int32_t> command)
{
using namespace phosphor::logging;
using namespace sdbusplus::org::open_power::OCC::PassThrough::Error;
std::vector<int32_t> response {};
// OCC only understands [bytes] so need array of bytes. Doing this
// because rest-server currently treats all int* as 32 bit integer.
std::vector<uint8_t> cmdInBytes;
cmdInBytes.resize(command.size());
// Populate uint8_t version of vector.
std::transform(command.begin(), command.end(), cmdInBytes.begin(),
[](decltype(cmdInBytes)::value_type x){return x;});
ssize_t size = cmdInBytes.size() * sizeof(decltype(cmdInBytes)::value_type);
auto rc = write((fd)(), cmdInBytes.data(), size);
if (rc < 0 || (rc != size))
{
// This would log and terminate since its not handled.
elog<WriteFailure>(
phosphor::logging::org::open_power::OCC::PassThrough::
WriteFailure::CALLOUT_ERRNO(errno),
phosphor::logging::org::open_power::OCC::PassThrough::
WriteFailure::CALLOUT_DEVICE_PATH(devicePath.c_str()));
}
// Now read the response. This would be the content of occ-sram
while(1)
{
uint8_t data {};
auto len = read((fd)(), &data, sizeof(data));
if (len > 0)
{
response.emplace_back(data);
}
else if (len < 0 && errno == EAGAIN)
{
// We may have data coming still.
// This driver does not need a sleep for a retry.
continue;
}
else if (len == 0)
{
// We have read all that we can.
break;
}
else
{
// This would log and terminate since its not handled.
elog<ReadFailure>(
phosphor::logging::org::open_power::OCC::PassThrough::
ReadFailure::CALLOUT_ERRNO(errno),
phosphor::logging::org::open_power::OCC::PassThrough::
ReadFailure::CALLOUT_DEVICE_PATH(devicePath.c_str()));
}
}
return response;
}
} // namespace pass_through
} // namespace occ
} // namespace open_power