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