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