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