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