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