1 #include "config.h" 2 3 #include "host_pdr_handler.hpp" 4 5 #include <assert.h> 6 #include <libpldm/pldm.h> 7 8 #include <nlohmann/json.hpp> 9 #include <phosphor-logging/lg2.hpp> 10 #include <sdeventplus/clock.hpp> 11 #include <sdeventplus/exception.hpp> 12 #include <sdeventplus/source/io.hpp> 13 #include <sdeventplus/source/time.hpp> 14 15 #include <fstream> 16 17 PHOSPHOR_LOG2_USING; 18 19 namespace pldm 20 { 21 using namespace pldm::dbus_api; 22 using namespace pldm::responder::events; 23 using namespace pldm::utils; 24 using namespace sdbusplus::bus::match::rules; 25 using Json = nlohmann::json; 26 namespace fs = std::filesystem; 27 constexpr auto fruJson = "host_frus.json"; 28 const Json emptyJson{}; 29 const std::vector<Json> emptyJsonList{}; 30 31 template <typename T> 32 uint16_t extractTerminusHandle(std::vector<uint8_t>& pdr) 33 { 34 T* var = nullptr; 35 if (std::is_same<T, pldm_pdr_fru_record_set>::value) 36 { 37 var = (T*)(pdr.data() + sizeof(pldm_pdr_hdr)); 38 } 39 else 40 { 41 var = (T*)(pdr.data()); 42 } 43 if (var != nullptr) 44 { 45 return var->terminus_handle; 46 } 47 return TERMINUS_HANDLE; 48 } 49 50 HostPDRHandler::HostPDRHandler( 51 int mctp_fd, uint8_t mctp_eid, sdeventplus::Event& event, pldm_pdr* repo, 52 const std::string& eventsJsonsDir, pldm_entity_association_tree* entityTree, 53 pldm_entity_association_tree* bmcEntityTree, Requester& requester, 54 pldm::requester::Handler<pldm::requester::Request>* handler) : 55 mctp_fd(mctp_fd), 56 mctp_eid(mctp_eid), event(event), repo(repo), 57 stateSensorHandler(eventsJsonsDir), entityTree(entityTree), 58 bmcEntityTree(bmcEntityTree), requester(requester), handler(handler) 59 { 60 fs::path hostFruJson(fs::path(HOST_JSONS_DIR) / fruJson); 61 if (fs::exists(hostFruJson)) 62 { 63 // Note parent entities for entities sent down by the host firmware. 64 // This will enable a merge of entity associations. 65 try 66 { 67 std::ifstream jsonFile(hostFruJson); 68 auto data = Json::parse(jsonFile, nullptr, false); 69 if (data.is_discarded()) 70 { 71 error("Parsing Host FRU json file failed"); 72 } 73 else 74 { 75 auto entities = data.value("entities", emptyJsonList); 76 for (auto& entity : entities) 77 { 78 EntityType entityType = entity.value("entity_type", 0); 79 auto parent = entity.value("parent", emptyJson); 80 pldm_entity p{}; 81 p.entity_type = parent.value("entity_type", 0); 82 p.entity_instance_num = parent.value("entity_instance", 0); 83 parents.emplace(entityType, std::move(p)); 84 } 85 } 86 } 87 catch (const std::exception& e) 88 { 89 error("Parsing Host FRU json file failed, exception = {ERR_EXCEP}", 90 "ERR_EXCEP", e.what()); 91 } 92 } 93 94 hostOffMatch = std::make_unique<sdbusplus::bus::match_t>( 95 pldm::utils::DBusHandler::getBus(), 96 propertiesChanged("/xyz/openbmc_project/state/host0", 97 "xyz.openbmc_project.State.Host"), 98 [this, repo, entityTree, bmcEntityTree](sdbusplus::message_t& msg) { 99 DbusChangedProps props{}; 100 std::string intf; 101 msg.read(intf, props); 102 const auto itr = props.find("CurrentHostState"); 103 if (itr != props.end()) 104 { 105 PropertyValue value = itr->second; 106 auto propVal = std::get<std::string>(value); 107 if (propVal == "xyz.openbmc_project.State.Host.HostState.Off") 108 { 109 // Delete all the remote terminus information 110 std::erase_if(tlPDRInfo, [](const auto& item) { 111 auto const& [key, value] = item; 112 return key != TERMINUS_HANDLE; 113 }); 114 pldm_pdr_remove_remote_pdrs(repo); 115 pldm_entity_association_tree_destroy_root(entityTree); 116 pldm_entity_association_tree_copy_root(bmcEntityTree, 117 entityTree); 118 this->sensorMap.clear(); 119 this->responseReceived = false; 120 } 121 } 122 }); 123 } 124 125 void HostPDRHandler::fetchPDR(PDRRecordHandles&& recordHandles) 126 { 127 pdrRecordHandles.clear(); 128 modifiedPDRRecordHandles.clear(); 129 130 if (isHostPdrModified) 131 { 132 modifiedPDRRecordHandles = std::move(recordHandles); 133 } 134 else 135 { 136 pdrRecordHandles = std::move(recordHandles); 137 } 138 139 // Defer the actual fetch of PDRs from the host (by queuing the call on the 140 // main event loop). That way, we can respond to the platform event msg from 141 // the host firmware. 142 pdrFetchEvent = std::make_unique<sdeventplus::source::Defer>( 143 event, std::bind(std::mem_fn(&HostPDRHandler::_fetchPDR), this, 144 std::placeholders::_1)); 145 } 146 147 void HostPDRHandler::_fetchPDR(sdeventplus::source::EventBase& /*source*/) 148 { 149 getHostPDR(); 150 } 151 152 void HostPDRHandler::getHostPDR(uint32_t nextRecordHandle) 153 { 154 pdrFetchEvent.reset(); 155 156 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) + 157 PLDM_GET_PDR_REQ_BYTES); 158 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 159 uint32_t recordHandle{}; 160 if (!nextRecordHandle && (!modifiedPDRRecordHandles.empty()) && 161 isHostPdrModified) 162 { 163 recordHandle = modifiedPDRRecordHandles.front(); 164 modifiedPDRRecordHandles.pop_front(); 165 } 166 else if (!nextRecordHandle && (!pdrRecordHandles.empty())) 167 { 168 recordHandle = pdrRecordHandles.front(); 169 pdrRecordHandles.pop_front(); 170 } 171 else 172 { 173 recordHandle = nextRecordHandle; 174 } 175 auto instanceId = requester.getInstanceId(mctp_eid); 176 177 auto rc = 178 encode_get_pdr_req(instanceId, recordHandle, 0, PLDM_GET_FIRSTPART, 179 UINT16_MAX, 0, request, PLDM_GET_PDR_REQ_BYTES); 180 if (rc != PLDM_SUCCESS) 181 { 182 requester.markFree(mctp_eid, instanceId); 183 error("Failed to encode_get_pdr_req, rc = {RC}", "RC", rc); 184 return; 185 } 186 187 rc = handler->registerRequest( 188 mctp_eid, instanceId, PLDM_PLATFORM, PLDM_GET_PDR, 189 std::move(requestMsg), 190 std::move(std::bind_front(&HostPDRHandler::processHostPDRs, this))); 191 if (rc) 192 { 193 error("Failed to send the GetPDR request to Host"); 194 } 195 } 196 197 int HostPDRHandler::handleStateSensorEvent(const StateSensorEntry& entry, 198 pdr::EventState state) 199 { 200 auto rc = stateSensorHandler.eventAction(entry, state); 201 if (rc != PLDM_SUCCESS) 202 { 203 error("Failed to fetch and update D-bus property, rc = {RC}", "RC", rc); 204 return rc; 205 } 206 return PLDM_SUCCESS; 207 } 208 bool HostPDRHandler::getParent(EntityType type, pldm_entity& parent) 209 { 210 auto found = parents.find(type); 211 if (found != parents.end()) 212 { 213 parent.entity_type = found->second.entity_type; 214 parent.entity_instance_num = found->second.entity_instance_num; 215 return true; 216 } 217 218 return false; 219 } 220 221 void HostPDRHandler::mergeEntityAssociations(const std::vector<uint8_t>& pdr) 222 { 223 size_t numEntities{}; 224 pldm_entity* entities = nullptr; 225 bool merged = false; 226 auto entityPdr = reinterpret_cast<pldm_pdr_entity_association*>( 227 const_cast<uint8_t*>(pdr.data()) + sizeof(pldm_pdr_hdr)); 228 229 pldm_entity_association_pdr_extract(pdr.data(), pdr.size(), &numEntities, 230 &entities); 231 for (size_t i = 0; i < numEntities; ++i) 232 { 233 pldm_entity parent{}; 234 if (getParent(entities[i].entity_type, parent)) 235 { 236 auto node = pldm_entity_association_tree_find(entityTree, &parent); 237 if (node) 238 { 239 pldm_entity_association_tree_add(entityTree, &entities[i], 240 0xFFFF, node, 241 entityPdr->association_type); 242 merged = true; 243 } 244 } 245 } 246 247 if (merged) 248 { 249 // Update our PDR repo with the merged entity association PDRs 250 pldm_entity_node* node = nullptr; 251 pldm_find_entity_ref_in_tree(entityTree, entities[0], &node); 252 if (node == nullptr) 253 { 254 error("could not find referrence of the entity in the tree"); 255 } 256 else 257 { 258 pldm_entity_association_pdr_add_from_node( 259 node, repo, &entities, numEntities, true, TERMINUS_HANDLE); 260 } 261 } 262 free(entities); 263 } 264 265 void HostPDRHandler::sendPDRRepositoryChgEvent(std::vector<uint8_t>&& pdrTypes, 266 uint8_t eventDataFormat) 267 { 268 assert(eventDataFormat == FORMAT_IS_PDR_HANDLES); 269 270 // Extract from the PDR repo record handles of PDRs we want the host 271 // to pull up. 272 std::vector<uint8_t> eventDataOps{PLDM_RECORDS_ADDED}; 273 std::vector<uint8_t> numsOfChangeEntries(1); 274 std::vector<std::vector<ChangeEntry>> changeEntries( 275 numsOfChangeEntries.size()); 276 for (auto pdrType : pdrTypes) 277 { 278 const pldm_pdr_record* record{}; 279 do 280 { 281 record = pldm_pdr_find_record_by_type(repo, pdrType, record, 282 nullptr, nullptr); 283 if (record && pldm_pdr_record_is_remote(record)) 284 { 285 changeEntries[0].push_back( 286 pldm_pdr_get_record_handle(repo, record)); 287 } 288 } while (record); 289 } 290 if (changeEntries.empty()) 291 { 292 return; 293 } 294 numsOfChangeEntries[0] = changeEntries[0].size(); 295 296 // Encode PLDM platform event msg to indicate a PDR repo change. 297 size_t maxSize = PLDM_PDR_REPOSITORY_CHG_EVENT_MIN_LENGTH + 298 PLDM_PDR_REPOSITORY_CHANGE_RECORD_MIN_LENGTH + 299 changeEntries[0].size() * sizeof(uint32_t); 300 std::vector<uint8_t> eventDataVec{}; 301 eventDataVec.resize(maxSize); 302 auto eventData = 303 reinterpret_cast<struct pldm_pdr_repository_chg_event_data*>( 304 eventDataVec.data()); 305 size_t actualSize{}; 306 auto firstEntry = changeEntries[0].data(); 307 auto rc = encode_pldm_pdr_repository_chg_event_data( 308 eventDataFormat, 1, eventDataOps.data(), numsOfChangeEntries.data(), 309 &firstEntry, eventData, &actualSize, maxSize); 310 if (rc != PLDM_SUCCESS) 311 { 312 error("Failed to encode_pldm_pdr_repository_chg_event_data, rc = {RC}", 313 "RC", rc); 314 return; 315 } 316 auto instanceId = requester.getInstanceId(mctp_eid); 317 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) + 318 PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES + 319 actualSize); 320 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 321 rc = encode_platform_event_message_req( 322 instanceId, 1, TERMINUS_ID, PLDM_PDR_REPOSITORY_CHG_EVENT, 323 eventDataVec.data(), actualSize, request, 324 actualSize + PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES); 325 if (rc != PLDM_SUCCESS) 326 { 327 requester.markFree(mctp_eid, instanceId); 328 error("Failed to encode_platform_event_message_req, rc = {RC}", "RC", 329 rc); 330 return; 331 } 332 333 auto platformEventMessageResponseHandler = [](mctp_eid_t /*eid*/, 334 const pldm_msg* response, 335 size_t respMsgLen) { 336 if (response == nullptr || !respMsgLen) 337 { 338 error( 339 "Failed to receive response for the PDR repository changed event"); 340 return; 341 } 342 343 uint8_t completionCode{}; 344 uint8_t status{}; 345 auto responsePtr = reinterpret_cast<const struct pldm_msg*>(response); 346 auto rc = decode_platform_event_message_resp(responsePtr, respMsgLen, 347 &completionCode, &status); 348 if (rc || completionCode) 349 { 350 error( 351 "Failed to decode_platform_event_message_resp: {RC}, cc = {CC}", 352 "RC", rc, "CC", static_cast<unsigned>(completionCode)); 353 } 354 }; 355 356 rc = handler->registerRequest( 357 mctp_eid, instanceId, PLDM_PLATFORM, PLDM_PLATFORM_EVENT_MESSAGE, 358 std::move(requestMsg), std::move(platformEventMessageResponseHandler)); 359 if (rc) 360 { 361 error("Failed to send the PDR repository changed event request"); 362 } 363 } 364 365 void HostPDRHandler::parseStateSensorPDRs(const PDRList& stateSensorPDRs) 366 { 367 for (const auto& pdr : stateSensorPDRs) 368 { 369 SensorEntry sensorEntry{}; 370 const auto& [terminusHandle, sensorID, sensorInfo] = 371 responder::pdr_utils::parseStateSensorPDR(pdr); 372 sensorEntry.sensorID = sensorID; 373 try 374 { 375 sensorEntry.terminusID = std::get<0>(tlPDRInfo.at(terminusHandle)); 376 } 377 // If there is no mapping for terminusHandle assign the reserved TID 378 // value of 0xFF to indicate that. 379 catch (const std::out_of_range& e) 380 { 381 sensorEntry.terminusID = PLDM_TID_RESERVED; 382 } 383 sensorMap.emplace(sensorEntry, std::move(sensorInfo)); 384 } 385 } 386 387 void HostPDRHandler::processHostPDRs(mctp_eid_t /*eid*/, 388 const pldm_msg* response, 389 size_t respMsgLen) 390 { 391 static bool merged = false; 392 static PDRList stateSensorPDRs{}; 393 uint32_t nextRecordHandle{}; 394 uint8_t tlEid = 0; 395 bool tlValid = true; 396 uint32_t rh = 0; 397 uint16_t terminusHandle = 0; 398 uint16_t pdrTerminusHandle = 0; 399 uint8_t tid = 0; 400 401 uint8_t completionCode{}; 402 uint32_t nextDataTransferHandle{}; 403 uint8_t transferFlag{}; 404 uint16_t respCount{}; 405 uint8_t transferCRC{}; 406 if (response == nullptr || !respMsgLen) 407 { 408 error("Failed to receive response for the GetPDR command"); 409 return; 410 } 411 412 auto rc = decode_get_pdr_resp( 413 response, respMsgLen /*- sizeof(pldm_msg_hdr)*/, &completionCode, 414 &nextRecordHandle, &nextDataTransferHandle, &transferFlag, &respCount, 415 nullptr, 0, &transferCRC); 416 std::vector<uint8_t> responsePDRMsg; 417 responsePDRMsg.resize(respMsgLen + sizeof(pldm_msg_hdr)); 418 memcpy(responsePDRMsg.data(), response, respMsgLen + sizeof(pldm_msg_hdr)); 419 if (rc != PLDM_SUCCESS) 420 { 421 error("Failed to decode_get_pdr_resp, rc = {RC}", "RC", rc); 422 return; 423 } 424 else 425 { 426 std::vector<uint8_t> pdr(respCount, 0); 427 rc = decode_get_pdr_resp(response, respMsgLen, &completionCode, 428 &nextRecordHandle, &nextDataTransferHandle, 429 &transferFlag, &respCount, pdr.data(), 430 respCount, &transferCRC); 431 if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS) 432 { 433 error("Failed to decode_get_pdr_resp: rc = {RC}, cc = {CC}", "RC", 434 rc, "CC", static_cast<unsigned>(completionCode)); 435 return; 436 } 437 else 438 { 439 // when nextRecordHandle is 0, we need the recordHandle of the last 440 // PDR and not 0-1. 441 if (!nextRecordHandle) 442 { 443 rh = nextRecordHandle; 444 } 445 else 446 { 447 rh = nextRecordHandle - 1; 448 } 449 450 auto pdrHdr = reinterpret_cast<pldm_pdr_hdr*>(pdr.data()); 451 if (!rh) 452 { 453 rh = pdrHdr->record_handle; 454 } 455 456 if (pdrHdr->type == PLDM_PDR_ENTITY_ASSOCIATION) 457 { 458 this->mergeEntityAssociations(pdr); 459 merged = true; 460 } 461 else 462 { 463 if (pdrHdr->type == PLDM_TERMINUS_LOCATOR_PDR) 464 { 465 pdrTerminusHandle = 466 extractTerminusHandle<pldm_terminus_locator_pdr>(pdr); 467 auto tlpdr = 468 reinterpret_cast<const pldm_terminus_locator_pdr*>( 469 pdr.data()); 470 471 terminusHandle = tlpdr->terminus_handle; 472 tid = tlpdr->tid; 473 auto terminus_locator_type = tlpdr->terminus_locator_type; 474 if (terminus_locator_type == 475 PLDM_TERMINUS_LOCATOR_TYPE_MCTP_EID) 476 { 477 auto locatorValue = reinterpret_cast< 478 const pldm_terminus_locator_type_mctp_eid*>( 479 tlpdr->terminus_locator_value); 480 tlEid = static_cast<uint8_t>(locatorValue->eid); 481 } 482 if (tlpdr->validity == 0) 483 { 484 tlValid = false; 485 } 486 for (const auto& terminusMap : tlPDRInfo) 487 { 488 if ((terminusHandle == (terminusMap.first)) && 489 (get<1>(terminusMap.second) == tlEid) && 490 (get<2>(terminusMap.second) == tlpdr->validity)) 491 { 492 // TL PDR already present with same validity don't 493 // add the PDR to the repo just return 494 return; 495 } 496 } 497 tlPDRInfo.insert_or_assign( 498 tlpdr->terminus_handle, 499 std::make_tuple(tlpdr->tid, tlEid, tlpdr->validity)); 500 } 501 else if (pdrHdr->type == PLDM_STATE_SENSOR_PDR) 502 { 503 pdrTerminusHandle = 504 extractTerminusHandle<pldm_state_sensor_pdr>(pdr); 505 stateSensorPDRs.emplace_back(pdr); 506 } 507 else if (pdrHdr->type == PLDM_PDR_FRU_RECORD_SET) 508 { 509 pdrTerminusHandle = 510 extractTerminusHandle<pldm_pdr_fru_record_set>(pdr); 511 } 512 else if (pdrHdr->type == PLDM_STATE_EFFECTER_PDR) 513 { 514 pdrTerminusHandle = 515 extractTerminusHandle<pldm_state_effecter_pdr>(pdr); 516 } 517 else if (pdrHdr->type == PLDM_NUMERIC_EFFECTER_PDR) 518 { 519 pdrTerminusHandle = 520 extractTerminusHandle<pldm_numeric_effecter_value_pdr>( 521 pdr); 522 } 523 // if the TLPDR is invalid update the repo accordingly 524 if (!tlValid) 525 { 526 pldm_pdr_update_TL_pdr(repo, terminusHandle, tid, tlEid, 527 tlValid); 528 } 529 else 530 { 531 pldm_pdr_add(repo, pdr.data(), respCount, rh, true, 532 pdrTerminusHandle); 533 } 534 } 535 } 536 } 537 if (!nextRecordHandle) 538 { 539 /*received last record*/ 540 this->parseStateSensorPDRs(stateSensorPDRs); 541 if (isHostUp()) 542 { 543 this->setHostSensorState(stateSensorPDRs); 544 } 545 stateSensorPDRs.clear(); 546 if (merged) 547 { 548 merged = false; 549 deferredPDRRepoChgEvent = 550 std::make_unique<sdeventplus::source::Defer>( 551 event, 552 std::bind( 553 std::mem_fn((&HostPDRHandler::_processPDRRepoChgEvent)), 554 this, std::placeholders::_1)); 555 } 556 } 557 else 558 { 559 if (modifiedPDRRecordHandles.empty() && isHostPdrModified) 560 { 561 isHostPdrModified = false; 562 } 563 else 564 { 565 deferredFetchPDREvent = 566 std::make_unique<sdeventplus::source::Defer>( 567 event, 568 std::bind( 569 std::mem_fn((&HostPDRHandler::_processFetchPDREvent)), 570 this, nextRecordHandle, std::placeholders::_1)); 571 } 572 } 573 } 574 575 void HostPDRHandler::_processPDRRepoChgEvent( 576 sdeventplus::source::EventBase& /*source */) 577 { 578 deferredPDRRepoChgEvent.reset(); 579 this->sendPDRRepositoryChgEvent( 580 std::move(std::vector<uint8_t>(1, PLDM_PDR_ENTITY_ASSOCIATION)), 581 FORMAT_IS_PDR_HANDLES); 582 } 583 584 void HostPDRHandler::_processFetchPDREvent( 585 uint32_t nextRecordHandle, sdeventplus::source::EventBase& /*source */) 586 { 587 deferredFetchPDREvent.reset(); 588 if (!this->pdrRecordHandles.empty()) 589 { 590 nextRecordHandle = this->pdrRecordHandles.front(); 591 this->pdrRecordHandles.pop_front(); 592 } 593 if (isHostPdrModified && (!this->modifiedPDRRecordHandles.empty())) 594 { 595 nextRecordHandle = this->modifiedPDRRecordHandles.front(); 596 this->modifiedPDRRecordHandles.pop_front(); 597 } 598 this->getHostPDR(nextRecordHandle); 599 } 600 601 void HostPDRHandler::setHostFirmwareCondition() 602 { 603 responseReceived = false; 604 auto instanceId = requester.getInstanceId(mctp_eid); 605 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) + 606 PLDM_GET_VERSION_REQ_BYTES); 607 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 608 auto rc = encode_get_version_req(instanceId, 0, PLDM_GET_FIRSTPART, 609 PLDM_BASE, request); 610 if (rc != PLDM_SUCCESS) 611 { 612 error("GetPLDMVersion encode failure. PLDM error code = {RC}", "RC", 613 lg2::hex, rc); 614 requester.markFree(mctp_eid, instanceId); 615 return; 616 } 617 618 auto getPLDMVersionHandler = [this](mctp_eid_t /*eid*/, 619 const pldm_msg* response, 620 size_t respMsgLen) { 621 if (response == nullptr || !respMsgLen) 622 { 623 error( 624 "Failed to receive response for getPLDMVersion command, Host seems to be off"); 625 return; 626 } 627 info("Getting the response. PLDM RC = {RC}", "RC", lg2::hex, 628 static_cast<uint16_t>(response->payload[0])); 629 this->responseReceived = true; 630 getHostPDR(); 631 }; 632 rc = handler->registerRequest(mctp_eid, instanceId, PLDM_BASE, 633 PLDM_GET_PLDM_VERSION, std::move(requestMsg), 634 std::move(getPLDMVersionHandler)); 635 if (rc) 636 { 637 error("Failed to discover Host state. Assuming Host as off"); 638 } 639 } 640 641 bool HostPDRHandler::isHostUp() 642 { 643 return responseReceived; 644 } 645 646 void HostPDRHandler::setHostSensorState(const PDRList& stateSensorPDRs) 647 { 648 for (const auto& stateSensorPDR : stateSensorPDRs) 649 { 650 auto pdr = reinterpret_cast<const pldm_state_sensor_pdr*>( 651 stateSensorPDR.data()); 652 653 if (!pdr) 654 { 655 error("Failed to get State sensor PDR"); 656 pldm::utils::reportError( 657 "xyz.openbmc_project.bmc.pldm.InternalFailure"); 658 return; 659 } 660 661 uint16_t sensorId = pdr->sensor_id; 662 663 for (const auto& [terminusHandle, terminusInfo] : tlPDRInfo) 664 { 665 if (terminusHandle == pdr->terminus_handle) 666 { 667 if (std::get<2>(terminusInfo) == PLDM_TL_PDR_VALID) 668 { 669 mctp_eid = std::get<1>(terminusInfo); 670 } 671 672 bitfield8_t sensorRearm; 673 sensorRearm.byte = 0; 674 uint8_t tid = std::get<0>(terminusInfo); 675 676 auto instanceId = requester.getInstanceId(mctp_eid); 677 std::vector<uint8_t> requestMsg( 678 sizeof(pldm_msg_hdr) + 679 PLDM_GET_STATE_SENSOR_READINGS_REQ_BYTES); 680 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 681 auto rc = encode_get_state_sensor_readings_req( 682 instanceId, sensorId, sensorRearm, 0, request); 683 684 if (rc != PLDM_SUCCESS) 685 { 686 requester.markFree(mctp_eid, instanceId); 687 error( 688 "Failed to encode_get_state_sensor_readings_req, rc = {RC}", 689 "RC", rc); 690 pldm::utils::reportError( 691 "xyz.openbmc_project.bmc.pldm.InternalFailure"); 692 return; 693 } 694 695 auto getStateSensorReadingRespHandler = [=, this]( 696 mctp_eid_t /*eid*/, 697 const pldm_msg* 698 response, 699 size_t respMsgLen) { 700 if (response == nullptr || !respMsgLen) 701 { 702 error( 703 "Failed to receive response for getStateSensorReading command"); 704 return; 705 } 706 std::array<get_sensor_state_field, 8> stateField{}; 707 uint8_t completionCode = 0; 708 uint8_t comp_sensor_count = 0; 709 710 auto rc = decode_get_state_sensor_readings_resp( 711 response, respMsgLen, &completionCode, 712 &comp_sensor_count, stateField.data()); 713 714 if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS) 715 { 716 error( 717 "Failed to decode_get_state_sensor_readings_resp, rc = {RC} cc = {CC}", 718 "RC", rc, "CC", 719 static_cast<unsigned>(completionCode)); 720 pldm::utils::reportError( 721 "xyz.openbmc_project.bmc.pldm.InternalFailure"); 722 } 723 724 uint8_t eventState; 725 uint8_t previousEventState; 726 727 for (uint8_t sensorOffset = 0; 728 sensorOffset < comp_sensor_count; sensorOffset++) 729 { 730 eventState = stateField[sensorOffset].present_state; 731 previousEventState = 732 stateField[sensorOffset].previous_state; 733 734 emitStateSensorEventSignal(tid, sensorId, sensorOffset, 735 eventState, 736 previousEventState); 737 738 SensorEntry sensorEntry{tid, sensorId}; 739 740 pldm::pdr::EntityInfo entityInfo{}; 741 pldm::pdr::CompositeSensorStates 742 compositeSensorStates{}; 743 744 try 745 { 746 std::tie(entityInfo, compositeSensorStates) = 747 lookupSensorInfo(sensorEntry); 748 } 749 catch (const std::out_of_range& e) 750 { 751 try 752 { 753 sensorEntry.terminusID = PLDM_TID_RESERVED; 754 std::tie(entityInfo, compositeSensorStates) = 755 lookupSensorInfo(sensorEntry); 756 } 757 catch (const std::out_of_range& e) 758 { 759 error("No mapping for the events"); 760 } 761 } 762 763 if (sensorOffset > compositeSensorStates.size()) 764 { 765 error("Error Invalid data, Invalid sensor offset"); 766 return; 767 } 768 769 const auto& possibleStates = 770 compositeSensorStates[sensorOffset]; 771 if (possibleStates.find(eventState) == 772 possibleStates.end()) 773 { 774 error("Error invalid_data, Invalid event state"); 775 return; 776 } 777 const auto& [containerId, entityType, entityInstance] = 778 entityInfo; 779 pldm::responder::events::StateSensorEntry 780 stateSensorEntry{containerId, entityType, 781 entityInstance, sensorOffset}; 782 handleStateSensorEvent(stateSensorEntry, eventState); 783 } 784 }; 785 786 rc = handler->registerRequest( 787 mctp_eid, instanceId, PLDM_PLATFORM, 788 PLDM_GET_STATE_SENSOR_READINGS, std::move(requestMsg), 789 std::move(getStateSensorReadingRespHandler)); 790 791 if (rc != PLDM_SUCCESS) 792 { 793 error( 794 "Failed to send request to get State sensor reading on Host"); 795 } 796 } 797 } 798 } 799 } 800 } // namespace pldm 801