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