1 #include "config.h"
2 
3 #include "occ_pass_through.hpp"
4 
5 #include "elog-errors.hpp"
6 
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <fmt/core.h>
10 #include <unistd.h>
11 
12 #include <algorithm>
13 #include <memory>
14 #include <org/open_power/OCC/Device/error.hpp>
15 #include <phosphor-logging/elog.hpp>
16 #include <phosphor-logging/log.hpp>
17 #include <string>
18 
19 namespace open_power
20 {
21 namespace occ
22 {
23 
24 PassThrough::PassThrough(sdbusplus::bus::bus& bus, const char* path) :
25     Iface(bus, path), path(path),
26     devicePath(OCC_DEV_PATH + std::to_string((this->path.back() - '0') + 1)),
27     occInstance(this->path.back() - '0'),
28     activeStatusSignal(
29         bus, sdbusRule::propertiesChanged(path, "org.open_power.OCC.Status"),
30         std::bind(std::mem_fn(&PassThrough::activeStatusEvent), this,
31                   std::placeholders::_1)),
32     occCmd(occInstance, bus, path)
33 {
34     // Nothing to do.
35 }
36 
37 std::vector<int32_t> PassThrough::send(std::vector<int32_t> command)
38 {
39     std::vector<int32_t> response{};
40 
41     // OCC only understands [bytes] so need array of bytes. Doing this
42     // because rest-server currently treats all int* as 32 bit integer.
43     std::vector<uint8_t> cmdInBytes, rsp;
44     cmdInBytes.resize(command.size());
45 
46     // Populate uint8_t version of vector.
47     std::transform(command.begin(), command.end(), cmdInBytes.begin(),
48                    [](decltype(cmdInBytes)::value_type x) { return x; });
49 
50     rsp = send(cmdInBytes);
51 
52     response.resize(rsp.size());
53     std::transform(rsp.begin(), rsp.end(), response.begin(),
54                    [](decltype(response)::value_type x) { return x; });
55 
56     return response;
57 }
58 
59 std::vector<uint8_t> PassThrough::send(std::vector<uint8_t> command)
60 {
61     using namespace phosphor::logging;
62     using namespace sdbusplus::org::open_power::OCC::Device::Error;
63 
64     std::vector<uint8_t> response{};
65 
66     log<level::DEBUG>(
67         fmt::format("PassThrough::send() Sending 0x{:02X} command to OCC{}",
68                     command.front(), occInstance)
69             .c_str());
70     CmdStatus status = occCmd.send(command, response);
71     if (status == CmdStatus::SUCCESS)
72     {
73         if (response.size() >= 5)
74         {
75             log<level::DEBUG>(fmt::format("PassThrough::send() "
76                                           "response had {} bytes",
77                                           response.size())
78                                   .c_str());
79         }
80         else
81         {
82             log<level::ERR>("PassThrough::send() Invalid OCC response");
83             dump_hex(response);
84         }
85     }
86     else
87     {
88         if (status == CmdStatus::OPEN_FAILURE)
89         {
90             log<level::WARNING>("PassThrough::send() - OCC not active yet");
91         }
92         else
93         {
94             log<level::ERR>("PassThrough::send() - OCC command failed!");
95         }
96     }
97 
98     return response;
99 }
100 
101 // Called at OCC Status change signal
102 void PassThrough::activeStatusEvent(sdbusplus::message::message& msg)
103 {
104     std::string statusInterface;
105     std::map<std::string, std::variant<bool>> msgData;
106     msg.read(statusInterface, msgData);
107 
108     auto propertyMap = msgData.find("OccActive");
109     if (propertyMap != msgData.end())
110     {
111         // Extract the OccActive property
112         if (std::get<bool>(propertyMap->second))
113         {
114             occActive = true;
115         }
116         else
117         {
118             occActive = false;
119         }
120     }
121     return;
122 }
123 
124 } // namespace occ
125 } // namespace open_power
126