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 using namespace phosphor::logging;
26 using namespace sdbusplus::org::open_power::OCC::Device::Error;
27 
28 PassThrough::PassThrough(
29     const char* path
30 #ifdef POWER10
31     ,
32     std::unique_ptr<open_power::occ::powermode::PowerMode>& powerModeRef
33 #endif
34     ) :
35     Iface(utils::getBus(), path),
36     path(path),
37 #ifdef POWER10
38     pmode(powerModeRef),
39 #endif
40     devicePath(OCC_DEV_PATH + std::to_string((this->path.back() - '0') + 1)),
41     occInstance(this->path.back() - '0'),
42     activeStatusSignal(
43         utils::getBus(),
44         sdbusRule::propertiesChanged(path, "org.open_power.OCC.Status"),
45         std::bind(std::mem_fn(&PassThrough::activeStatusEvent), this,
46                   std::placeholders::_1)),
47     occCmd(occInstance, path)
48 {
49     // Nothing to do.
50 }
51 
52 std::vector<int32_t> PassThrough::send(std::vector<int32_t> command)
53 {
54     std::vector<int32_t> response{};
55 
56     // OCC only understands [bytes] so need array of bytes. Doing this
57     // because rest-server currently treats all int* as 32 bit integer.
58     std::vector<uint8_t> cmdInBytes, rsp;
59     cmdInBytes.resize(command.size());
60 
61     // Populate uint8_t version of vector.
62     std::transform(command.begin(), command.end(), cmdInBytes.begin(),
63                    [](decltype(cmdInBytes)::value_type x) { return x; });
64 
65     rsp = send(cmdInBytes);
66 
67     response.resize(rsp.size());
68     std::transform(rsp.begin(), rsp.end(), response.begin(),
69                    [](decltype(response)::value_type x) { return x; });
70 
71     return response;
72 }
73 
74 std::vector<uint8_t> PassThrough::send(std::vector<uint8_t> command)
75 {
76     std::vector<uint8_t> response{};
77 
78     if (!occActive)
79     {
80         log<level::ERR>(
81             fmt::format(
82                 "PassThrough::send() - OCC{} not active, command not sent",
83                 occInstance)
84                 .c_str());
85         return response;
86     }
87 
88     log<level::INFO>(
89         fmt::format("PassThrough::send() Sending 0x{:02X} command to OCC{}",
90                     command.front(), occInstance)
91             .c_str());
92     CmdStatus status = occCmd.send(command, response);
93     if (status == CmdStatus::SUCCESS)
94     {
95         if (response.size() >= 5)
96         {
97             log<level::DEBUG>(
98                 fmt::format("PassThrough::send() response had {} bytes",
99                             response.size())
100                     .c_str());
101         }
102         else
103         {
104             log<level::ERR>("PassThrough::send() Invalid OCC response");
105             dump_hex(response);
106         }
107     }
108     else
109     {
110         log<level::ERR>(
111             fmt::format(
112                 "PassThrough::send(): OCC command failed with status {}",
113                 uint32_t(status))
114                 .c_str());
115     }
116 
117     return response;
118 }
119 
120 bool PassThrough::setMode(const uint8_t mode, const uint16_t modeData)
121 {
122 #ifdef POWER10
123     SysPwrMode newMode = SysPwrMode(mode);
124 
125     if ((!VALID_POWER_MODE_SETTING(newMode)) &&
126         (!VALID_OEM_POWER_MODE_SETTING(newMode)))
127     {
128         log<level::ERR>(
129             fmt::format(
130                 "PassThrough::setMode() Unsupported mode {} requested (0x{:04X})",
131                 newMode, modeData)
132                 .c_str());
133         return false;
134     }
135 
136     if (((newMode == SysPwrMode::FFO) || (newMode == SysPwrMode::SFP)) &&
137         (modeData == 0))
138     {
139         log<level::ERR>(
140             fmt::format(
141                 "PassThrough::setMode() Mode {} requires non-zero frequency point.",
142                 newMode)
143                 .c_str());
144         return false;
145     }
146 
147     if (!pmode)
148     {
149         log<level::ERR>("PassThrough::setMode: PowerMode is not defined!");
150         return false;
151     }
152 
153     log<level::INFO>(
154         fmt::format("PassThrough::setMode() Setting Power Mode {} (data: {})",
155                     newMode, modeData)
156             .c_str());
157     return pmode->setMode(newMode, modeData);
158 #else
159     log<level::DEBUG>(
160         fmt::format(
161             "PassThrough::setMode() No support to setting Power Mode {} (data: {})",
162             mode, modeData)
163             .c_str());
164     return false;
165 #endif
166 }
167 
168 // Called at OCC Status change signal
169 void PassThrough::activeStatusEvent(sdbusplus::message::message& msg)
170 {
171     std::string statusInterface;
172     std::map<std::string, std::variant<bool>> msgData;
173     msg.read(statusInterface, msgData);
174 
175     auto propertyMap = msgData.find("OccActive");
176     if (propertyMap != msgData.end())
177     {
178         // Extract the OccActive property
179         if (std::get<bool>(propertyMap->second))
180         {
181             occActive = true;
182         }
183         else
184         {
185             occActive = false;
186         }
187     }
188     return;
189 }
190 
191 } // namespace occ
192 } // namespace open_power
193