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