16b492fbfSDeepak Kodihalli #include <memory>
202ba9eccSDeepak Kodihalli #include <algorithm>
338b08d79SVishwanatha Subbanna #include <fcntl.h>
467d50ad6SVishwanatha Subbanna #include <errno.h>
53e5422edSVishwanatha Subbanna #include <string>
63e5422edSVishwanatha Subbanna #include <unistd.h>
702ba9eccSDeepak Kodihalli #include <phosphor-logging/log.hpp>
89bb065b8SVishwanatha Subbanna #include <phosphor-logging/elog.hpp>
9ee4d83dfSVishwanatha Subbanna #include <org/open_power/OCC/Device/error.hpp>
106b492fbfSDeepak Kodihalli #include "occ_pass_through.hpp"
119bb065b8SVishwanatha Subbanna #include "elog-errors.hpp"
123e5422edSVishwanatha Subbanna #include "config.h"
136b492fbfSDeepak Kodihalli namespace open_power
146b492fbfSDeepak Kodihalli {
156b492fbfSDeepak Kodihalli namespace occ
166b492fbfSDeepak Kodihalli {
176b492fbfSDeepak Kodihalli 
186b492fbfSDeepak Kodihalli PassThrough::PassThrough(
196b492fbfSDeepak Kodihalli     sdbusplus::bus::bus& bus,
206b492fbfSDeepak Kodihalli     const char* path) :
216b492fbfSDeepak Kodihalli     Iface(bus, path),
2238b08d79SVishwanatha Subbanna     path(path),
233e5422edSVishwanatha Subbanna     devicePath(OCC_DEV_PATH + std::to_string((this->path.back() - '0') + 1)),
243e5422edSVishwanatha Subbanna     activeStatusSignal(
253e5422edSVishwanatha Subbanna             bus,
263e5422edSVishwanatha Subbanna             sdbusRule::propertiesChanged(path, "org.open_power.OCC.Status"),
273e5422edSVishwanatha Subbanna             std::bind(std::mem_fn(&PassThrough::activeStatusEvent),
283e5422edSVishwanatha Subbanna                 this, std::placeholders::_1))
296b492fbfSDeepak Kodihalli {
3038b08d79SVishwanatha Subbanna     // Nothing to do.
3138b08d79SVishwanatha Subbanna }
3238b08d79SVishwanatha Subbanna 
333e5422edSVishwanatha Subbanna void PassThrough::openDevice()
3438b08d79SVishwanatha Subbanna {
359bb065b8SVishwanatha Subbanna     using namespace phosphor::logging;
36ee4d83dfSVishwanatha Subbanna     using namespace sdbusplus::org::open_power::OCC::Device::Error;
379bb065b8SVishwanatha Subbanna 
38*4f4712d8SEddie James     if (!occActive)
39*4f4712d8SEddie James     {
40*4f4712d8SEddie James          log<level::INFO>("OCC is inactive; cannot perform pass-through");
41*4f4712d8SEddie James          return;
42*4f4712d8SEddie James     }
43*4f4712d8SEddie James 
443e5422edSVishwanatha Subbanna     fd = open(devicePath.c_str(), O_RDWR | O_NONBLOCK);
4538b08d79SVishwanatha Subbanna     if (fd < 0)
4638b08d79SVishwanatha Subbanna     {
479bb065b8SVishwanatha Subbanna         // This would log and terminate since its not handled.
489bb065b8SVishwanatha Subbanna         elog<OpenFailure>(
49ee4d83dfSVishwanatha Subbanna             phosphor::logging::org::open_power::OCC::Device::
509bb065b8SVishwanatha Subbanna                 OpenFailure::CALLOUT_ERRNO(errno),
51ee4d83dfSVishwanatha Subbanna             phosphor::logging::org::open_power::OCC::Device::
529bb065b8SVishwanatha Subbanna                 OpenFailure::CALLOUT_DEVICE_PATH(devicePath.c_str()));
5338b08d79SVishwanatha Subbanna     }
543e5422edSVishwanatha Subbanna     return;
553e5422edSVishwanatha Subbanna }
563e5422edSVishwanatha Subbanna 
573e5422edSVishwanatha Subbanna void PassThrough::closeDevice()
583e5422edSVishwanatha Subbanna {
593e5422edSVishwanatha Subbanna     if (fd >= 0)
603e5422edSVishwanatha Subbanna     {
613e5422edSVishwanatha Subbanna         close(fd);
62*4f4712d8SEddie James         fd = -1;
633e5422edSVishwanatha Subbanna     }
646b492fbfSDeepak Kodihalli }
656b492fbfSDeepak Kodihalli 
666b492fbfSDeepak Kodihalli std::vector<int32_t> PassThrough::send(std::vector<int32_t> command)
676b492fbfSDeepak Kodihalli {
6867d50ad6SVishwanatha Subbanna     using namespace phosphor::logging;
69ee4d83dfSVishwanatha Subbanna     using namespace sdbusplus::org::open_power::OCC::Device::Error;
7067d50ad6SVishwanatha Subbanna 
7167d50ad6SVishwanatha Subbanna     std::vector<int32_t> response {};
7267d50ad6SVishwanatha Subbanna 
73*4f4712d8SEddie James     openDevice();
74*4f4712d8SEddie James 
75*4f4712d8SEddie James     if (fd < 0)
76*4f4712d8SEddie James     {
77*4f4712d8SEddie James         // OCC is inactive; empty response
78*4f4712d8SEddie James         return response;
79*4f4712d8SEddie James     }
80*4f4712d8SEddie James 
817d700e26SVishwanatha Subbanna     // OCC only understands [bytes] so need array of bytes. Doing this
827d700e26SVishwanatha Subbanna     // because rest-server currently treats all int* as 32 bit integer.
837d700e26SVishwanatha Subbanna     std::vector<uint8_t> cmdInBytes;
847d700e26SVishwanatha Subbanna     cmdInBytes.resize(command.size());
857d700e26SVishwanatha Subbanna 
867d700e26SVishwanatha Subbanna     // Populate uint8_t version of vector.
877d700e26SVishwanatha Subbanna     std::transform(command.begin(), command.end(), cmdInBytes.begin(),
887d700e26SVishwanatha Subbanna             [](decltype(cmdInBytes)::value_type x){return x;});
897d700e26SVishwanatha Subbanna 
907d700e26SVishwanatha Subbanna     ssize_t size = cmdInBytes.size() * sizeof(decltype(cmdInBytes)::value_type);
913e5422edSVishwanatha Subbanna     auto rc = write(fd, cmdInBytes.data(), size);
9267d50ad6SVishwanatha Subbanna     if (rc < 0 || (rc != size))
9367d50ad6SVishwanatha Subbanna     {
949bb065b8SVishwanatha Subbanna         // This would log and terminate since its not handled.
959bb065b8SVishwanatha Subbanna         elog<WriteFailure>(
96ee4d83dfSVishwanatha Subbanna             phosphor::logging::org::open_power::OCC::Device::
979bb065b8SVishwanatha Subbanna                 WriteFailure::CALLOUT_ERRNO(errno),
98ee4d83dfSVishwanatha Subbanna             phosphor::logging::org::open_power::OCC::Device::
999bb065b8SVishwanatha Subbanna                 WriteFailure::CALLOUT_DEVICE_PATH(devicePath.c_str()));
1006b492fbfSDeepak Kodihalli     }
1016b492fbfSDeepak Kodihalli 
10267d50ad6SVishwanatha Subbanna     // Now read the response. This would be the content of occ-sram
10367d50ad6SVishwanatha Subbanna     while(1)
10467d50ad6SVishwanatha Subbanna     {
1057d700e26SVishwanatha Subbanna         uint8_t data {};
1063e5422edSVishwanatha Subbanna         auto len = read(fd, &data, sizeof(data));
10767d50ad6SVishwanatha Subbanna         if (len > 0)
10867d50ad6SVishwanatha Subbanna         {
10967d50ad6SVishwanatha Subbanna             response.emplace_back(data);
11067d50ad6SVishwanatha Subbanna         }
11167d50ad6SVishwanatha Subbanna         else if (len < 0 && errno == EAGAIN)
11267d50ad6SVishwanatha Subbanna         {
1139bb065b8SVishwanatha Subbanna             // We may have data coming still.
1149bb065b8SVishwanatha Subbanna             // This driver does not need a sleep for a retry.
11567d50ad6SVishwanatha Subbanna             continue;
11667d50ad6SVishwanatha Subbanna         }
11767d50ad6SVishwanatha Subbanna         else if (len == 0)
11867d50ad6SVishwanatha Subbanna         {
11967d50ad6SVishwanatha Subbanna             // We have read all that we can.
12067d50ad6SVishwanatha Subbanna             break;
12167d50ad6SVishwanatha Subbanna         }
12267d50ad6SVishwanatha Subbanna         else
12367d50ad6SVishwanatha Subbanna         {
1249bb065b8SVishwanatha Subbanna             // This would log and terminate since its not handled.
1259bb065b8SVishwanatha Subbanna             elog<ReadFailure>(
126ee4d83dfSVishwanatha Subbanna                 phosphor::logging::org::open_power::OCC::Device::
1279bb065b8SVishwanatha Subbanna                     ReadFailure::CALLOUT_ERRNO(errno),
128ee4d83dfSVishwanatha Subbanna                 phosphor::logging::org::open_power::OCC::Device::
1299bb065b8SVishwanatha Subbanna                     ReadFailure::CALLOUT_DEVICE_PATH(devicePath.c_str()));
13067d50ad6SVishwanatha Subbanna         }
13167d50ad6SVishwanatha Subbanna     }
13267d50ad6SVishwanatha Subbanna 
133*4f4712d8SEddie James     closeDevice();
134*4f4712d8SEddie James 
13567d50ad6SVishwanatha Subbanna     return response;
13667d50ad6SVishwanatha Subbanna }
13767d50ad6SVishwanatha Subbanna 
1383e5422edSVishwanatha Subbanna // Called at OCC Status change signal
1393e5422edSVishwanatha Subbanna void PassThrough::activeStatusEvent(sdbusplus::message::message& msg)
1403e5422edSVishwanatha Subbanna {
1413e5422edSVishwanatha Subbanna     std::string statusInterface;
1423e5422edSVishwanatha Subbanna     std::map<std::string, sdbusplus::message::variant<bool>> msgData;
1433e5422edSVishwanatha Subbanna     msg.read(statusInterface, msgData);
1443e5422edSVishwanatha Subbanna 
1453e5422edSVishwanatha Subbanna     auto propertyMap = msgData.find("OccActive");
1463e5422edSVishwanatha Subbanna     if (propertyMap != msgData.end())
1473e5422edSVishwanatha Subbanna     {
1483e5422edSVishwanatha Subbanna         // Extract the OccActive property
1493e5422edSVishwanatha Subbanna         if (sdbusplus::message::variant_ns::get<bool>(propertyMap->second))
1503e5422edSVishwanatha Subbanna         {
151*4f4712d8SEddie James             occActive = true;
1523e5422edSVishwanatha Subbanna         }
1533e5422edSVishwanatha Subbanna         else
1543e5422edSVishwanatha Subbanna         {
155*4f4712d8SEddie James             occActive = false;
1563e5422edSVishwanatha Subbanna             this->closeDevice();
1573e5422edSVishwanatha Subbanna         }
1583e5422edSVishwanatha Subbanna     }
1593e5422edSVishwanatha Subbanna     return;
1603e5422edSVishwanatha Subbanna }
1613e5422edSVishwanatha Subbanna 
1626b492fbfSDeepak Kodihalli } // namespace occ
1636b492fbfSDeepak Kodihalli } // namespace open_power
164