1 #include <libpldm/oem/ibm/state_set.h> 2 #include <libpldm/platform.h> 3 #include <libpldm/pldm.h> 4 5 #include <util/dbus.hpp> 6 #include <util/trace.hpp> 7 8 namespace util 9 { 10 namespace pldm 11 { 12 /** @brief Send PLDM request 13 * 14 * @param[in] request - the request data 15 * @param[in] mcptEid - the mctp endpoint ID 16 * @param[out] pldmFd - pldm socket file descriptor 17 * 18 * @pre a mctp instance must have been 19 * @return true if send is successful false otherwise 20 */ 21 bool sendPldm(const std::vector<uint8_t>& request, uint8_t mctpEid, int& pldmFd) 22 { 23 // connect to socket 24 pldmFd = pldm_open(); 25 if (-1 == pldmFd) 26 { 27 trace::err("failed to connect to pldm"); 28 return false; 29 } 30 31 // send PLDM request 32 auto pldmRc = pldm_send(mctpEid, pldmFd, request.data(), request.size()); 33 34 trace::inf("sent pldm request"); 35 36 return pldmRc == PLDM_REQUESTER_SUCCESS ? true : false; 37 } 38 39 /** @brief Prepare a request for SetStateEffecterStates 40 * 41 * @param[in] effecterId - the effecter ID 42 * @param[in] effecterCount - composite effecter count 43 * @param[in] stateIdPos - position of the state set 44 * @param[in] stateSetValue - the value to set the state 45 * @param[in] mcptEid - the MCTP endpoint ID 46 * 47 * @return PLDM request message to be sent to host, empty message on error 48 */ 49 std::vector<uint8_t> prepareSetEffecterReq( 50 uint16_t effecterId, uint8_t effecterCount, uint8_t stateIdPos, 51 uint8_t stateSetValue, uint8_t mctpEid) 52 { 53 // get mctp instance associated with the endpoint ID 54 uint8_t mctpInstance; 55 if (!util::dbus::getMctpInstance(mctpInstance, mctpEid)) 56 { 57 return std::vector<uint8_t>(); 58 } 59 60 // form the request message 61 std::vector<uint8_t> request( 62 sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(effecterCount) + 63 (effecterCount * sizeof(set_effecter_state_field))); 64 65 // encode the state data with the change we want to elicit 66 std::vector<set_effecter_state_field> stateField; 67 for (uint8_t effecterPos = 0; effecterPos < effecterCount; effecterPos++) 68 { 69 if (effecterPos == stateIdPos) 70 { 71 stateField.emplace_back( 72 set_effecter_state_field{PLDM_REQUEST_SET, stateSetValue}); 73 } 74 else 75 { 76 stateField.emplace_back( 77 set_effecter_state_field{PLDM_NO_CHANGE, 0}); 78 } 79 } 80 81 // encode the message with state data 82 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data()); 83 auto rc = encode_set_state_effecter_states_req( 84 mctpInstance, effecterId, effecterCount, stateField.data(), requestMsg); 85 86 if (rc != PLDM_SUCCESS) 87 { 88 trace::err("encode set effecter states request failed"); 89 request.clear(); 90 } 91 92 return request; 93 } 94 95 /** @brief Return map of sensor ID to SBE instance 96 * 97 * @param[in] stateSetId - the state set ID of interest 98 * @param[out] sensorInstanceMap - map of sensor to SBE instance 99 * @param[out] sensorOffset - position of sensor with state set ID within map 100 * 101 * @return true if sensor info is available false otherwise 102 */ 103 bool fetchSensorInfo(uint16_t stateSetId, 104 std::map<uint16_t, unsigned int>& sensorInstanceMap, 105 uint8_t& sensorOffset) 106 { 107 // get state sensor PDRs 108 std::vector<std::vector<uint8_t>> pdrs{}; 109 if (!util::dbus::getStateSensorPdrs(pdrs, stateSetId)) 110 { 111 return false; 112 } 113 114 // check for any PDRs available 115 if (!pdrs.size()) 116 { 117 trace::err("state sensor PDRs not present"); 118 return false; 119 } 120 121 // find the offset of specified sensor withing PDRs 122 bool offsetFound = false; 123 auto stateSensorPDR = 124 reinterpret_cast<const pldm_state_sensor_pdr*>(pdrs.front().data()); 125 auto possibleStatesPtr = stateSensorPDR->possible_states; 126 127 for (auto offset = 0; offset < stateSensorPDR->composite_sensor_count; 128 offset++) 129 { 130 auto possibleStates = 131 reinterpret_cast<const state_sensor_possible_states*>( 132 possibleStatesPtr); 133 134 if (possibleStates->state_set_id == stateSetId) 135 { 136 sensorOffset = offset; 137 offsetFound = true; 138 break; 139 } 140 possibleStatesPtr += sizeof(possibleStates->state_set_id) + 141 sizeof(possibleStates->possible_states_size) + 142 possibleStates->possible_states_size; 143 } 144 145 if (!offsetFound) 146 { 147 trace::err("state sensor not found"); 148 return false; 149 } 150 151 // map sensor ID to equivelent 16 bit value 152 std::map<uint32_t, uint16_t> entityInstMap{}; 153 for (auto& pdr : pdrs) 154 { 155 auto pdrPtr = 156 reinterpret_cast<const pldm_state_sensor_pdr*>(pdr.data()); 157 uint32_t key = pdrPtr->sensor_id; 158 entityInstMap.emplace(key, static_cast<uint16_t>(pdrPtr->sensor_id)); 159 } 160 161 // map sensor ID to zero based SBE instance 162 unsigned int position = 0; 163 for (const auto& pair : entityInstMap) 164 { 165 sensorInstanceMap.emplace(pair.second, position); 166 position++; 167 } 168 169 return true; 170 } 171 172 /** @brief Return map of SBE instance to effecter ID 173 * 174 * @param[in] stateSetId - the state set ID of interest 175 * @param[out] instanceToEffecterMap - map of sbe instance to effecter ID 176 * @param[out] effecterCount - composite effecter count 177 * @param[out] stateIdPos - position of effecter with state set ID within map 178 * 179 * @return true if effector info is available false otherwise 180 */ 181 bool fetchEffecterInfo(uint16_t stateSetId, 182 std::map<unsigned int, uint16_t>& instanceToEffecterMap, 183 uint8_t& effecterCount, uint8_t& stateIdPos) 184 { 185 // get state effecter PDRs 186 std::vector<std::vector<uint8_t>> pdrs{}; 187 if (!util::dbus::getStateEffecterPdrs(pdrs, stateSetId)) 188 { 189 return false; 190 } 191 192 // check for any PDRs available 193 if (!pdrs.size()) 194 { 195 trace::err("state effecter PDRs not present"); 196 return false; 197 } 198 199 // find the offset of specified effector within PDRs 200 bool offsetFound = false; 201 auto stateEffecterPDR = 202 reinterpret_cast<const pldm_state_effecter_pdr*>(pdrs.front().data()); 203 auto possibleStatesPtr = stateEffecterPDR->possible_states; 204 205 for (auto offset = 0; offset < stateEffecterPDR->composite_effecter_count; 206 offset++) 207 { 208 auto possibleStates = 209 reinterpret_cast<const state_effecter_possible_states*>( 210 possibleStatesPtr); 211 212 if (possibleStates->state_set_id == stateSetId) 213 { 214 stateIdPos = offset; 215 effecterCount = stateEffecterPDR->composite_effecter_count; 216 offsetFound = true; 217 break; 218 } 219 possibleStatesPtr += sizeof(possibleStates->state_set_id) + 220 sizeof(possibleStates->possible_states_size) + 221 possibleStates->possible_states_size; 222 } 223 224 if (!offsetFound) 225 { 226 trace::err("state set effecter not found"); 227 return false; 228 } 229 230 // map effecter ID to equivelent 16 bit value 231 std::map<uint32_t, uint16_t> entityInstMap{}; 232 for (auto& pdr : pdrs) 233 { 234 auto pdrPtr = 235 reinterpret_cast<const pldm_state_effecter_pdr*>(pdr.data()); 236 uint32_t key = pdrPtr->effecter_id; 237 entityInstMap.emplace(key, static_cast<uint16_t>(pdrPtr->effecter_id)); 238 } 239 240 // map zero based SBE instance to effecter ID 241 unsigned int position = 0; 242 for (const auto& pair : entityInstMap) 243 { 244 instanceToEffecterMap.emplace(position, pair.second); 245 position++; 246 } 247 248 return true; 249 } 250 251 /** @brief Reset SBE using HBRT PLDM interface */ 252 bool hresetSbe(unsigned int sbeInstance) 253 { 254 trace::inf("requesting sbe hreset"); 255 256 // get effecter info 257 std::map<unsigned int, uint16_t> sbeInstanceToEffecter; 258 uint8_t SBEEffecterCount = 0; 259 uint8_t sbeMaintenanceStatePosition = 0; 260 261 if (!fetchEffecterInfo(PLDM_OEM_IBM_SBE_MAINTENANCE_STATE, 262 sbeInstanceToEffecter, SBEEffecterCount, 263 sbeMaintenanceStatePosition)) 264 { 265 return false; 266 } 267 268 // find the state effecter ID for the given SBE instance 269 auto effecterEntry = sbeInstanceToEffecter.find(sbeInstance); 270 if (effecterEntry == sbeInstanceToEffecter.end()) 271 { 272 trace::err("failed to find effecter for SBE"); 273 return false; 274 } 275 276 // create request to HRESET the SBE 277 constexpr uint8_t hbrtMctpEid = 10; // HBRT MCTP EID 278 279 auto request = prepareSetEffecterReq( 280 effecterEntry->second, SBEEffecterCount, sbeMaintenanceStatePosition, 281 SBE_RETRY_REQUIRED, hbrtMctpEid); 282 283 if (request.empty()) 284 { 285 trace::err("HRESET effecter request empty"); 286 return false; 287 } 288 289 // get sensor info for validating sensor change 290 std::map<uint16_t, unsigned int> sensorToSbeInstance; 291 uint8_t sbeSensorOffset = 0; 292 if (!fetchSensorInfo(PLDM_OEM_IBM_SBE_HRESET_STATE, sensorToSbeInstance, 293 sbeSensorOffset)) 294 { 295 return false; 296 } 297 298 // register signal change listener 299 std::string hresetStatus = "requested"; 300 constexpr auto interface = "xyz.openbmc_project.PLDM.Event"; 301 constexpr auto path = "/xyz/openbmc_project/pldm"; 302 constexpr auto member = "StateSensorEvent"; 303 304 auto bus = sdbusplus::bus::new_default(); 305 std::unique_ptr<sdbusplus::bus::match_t> match = 306 std::make_unique<sdbusplus::bus::match_t>( 307 bus, 308 sdbusplus::bus::match::rules::type::signal() + 309 sdbusplus::bus::match::rules::member(member) + 310 sdbusplus::bus::match::rules::path(path) + 311 sdbusplus::bus::match::rules::interface(interface), 312 [&](auto& msg) { 313 uint8_t sensorTid{}; 314 uint16_t sensorId{}; 315 uint8_t msgSensorOffset{}; 316 uint8_t eventState{}; 317 uint8_t previousEventState{}; 318 319 // get sensor event details 320 msg.read(sensorTid, sensorId, msgSensorOffset, eventState, 321 previousEventState); 322 323 // does sensor offset match? 324 if (sbeSensorOffset == msgSensorOffset) 325 { 326 // does sensor ID match? 327 auto sensorEntry = sensorToSbeInstance.find(sensorId); 328 if (sensorEntry != sensorToSbeInstance.end()) 329 { 330 const uint8_t instance = sensorEntry->second; 331 332 // if instances matche check status 333 if (instance == sbeInstance) 334 { 335 if (eventState == 336 static_cast<uint8_t>(SBE_HRESET_READY)) 337 { 338 hresetStatus = "success"; 339 } 340 else if (eventState == 341 static_cast<uint8_t>(SBE_HRESET_FAILED)) 342 { 343 hresetStatus = "fail"; 344 } 345 } 346 } 347 } 348 }); 349 350 // send request to issue hreset of sbe 351 int pldmFd = -1; // mctp socket file descriptor 352 if (!sendPldm(request, hbrtMctpEid, pldmFd)) 353 { 354 trace::err("send pldm request failed"); 355 if (-1 != pldmFd) 356 { 357 close(pldmFd); 358 } 359 return false; 360 } 361 362 // keep track of elapsed time 363 uint64_t timeRemaining = 60000000; // microseconds, 1 minute 364 std::chrono::steady_clock::time_point begin = 365 std::chrono::steady_clock::now(); 366 367 // wait for status update or timeout 368 trace::inf("waiting on sbe hreset"); 369 while ("requested" == hresetStatus && 0 != timeRemaining) 370 { 371 bus.wait(timeRemaining); 372 uint64_t timeElapsed = 373 std::chrono::duration_cast<std::chrono::microseconds>( 374 std::chrono::steady_clock::now() - begin) 375 .count(); 376 377 timeRemaining = 378 timeElapsed > timeRemaining ? 0 : timeRemaining - timeElapsed; 379 380 bus.process_discard(); 381 } 382 383 if (0 == timeRemaining) 384 { 385 trace::err("hreset timed out"); 386 } 387 388 close(pldmFd); // close pldm socket 389 390 return hresetStatus == "success" ? true : false; 391 } 392 393 } // namespace pldm 394 } // namespace util 395