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 int rc = pldm_entity_association_pdr_add_from_node_check( 257 node, repo, &entities, numEntities, true, TERMINUS_HANDLE); 258 if (rc) 259 { 260 error( 261 "Failed to add entity association PDR from node: {LIBPLDM_ERROR}", 262 "LIBPLDM_ERROR", rc); 263 } 264 } 265 } 266 free(entities); 267 } 268 269 void HostPDRHandler::sendPDRRepositoryChgEvent(std::vector<uint8_t>&& pdrTypes, 270 uint8_t eventDataFormat) 271 { 272 assert(eventDataFormat == FORMAT_IS_PDR_HANDLES); 273 274 // Extract from the PDR repo record handles of PDRs we want the host 275 // to pull up. 276 std::vector<uint8_t> eventDataOps{PLDM_RECORDS_ADDED}; 277 std::vector<uint8_t> numsOfChangeEntries(1); 278 std::vector<std::vector<ChangeEntry>> changeEntries( 279 numsOfChangeEntries.size()); 280 for (auto pdrType : pdrTypes) 281 { 282 const pldm_pdr_record* record{}; 283 do 284 { 285 record = pldm_pdr_find_record_by_type(repo, pdrType, record, 286 nullptr, nullptr); 287 if (record && pldm_pdr_record_is_remote(record)) 288 { 289 changeEntries[0].push_back( 290 pldm_pdr_get_record_handle(repo, record)); 291 } 292 } while (record); 293 } 294 if (changeEntries.empty()) 295 { 296 return; 297 } 298 numsOfChangeEntries[0] = changeEntries[0].size(); 299 300 // Encode PLDM platform event msg to indicate a PDR repo change. 301 size_t maxSize = PLDM_PDR_REPOSITORY_CHG_EVENT_MIN_LENGTH + 302 PLDM_PDR_REPOSITORY_CHANGE_RECORD_MIN_LENGTH + 303 changeEntries[0].size() * sizeof(uint32_t); 304 std::vector<uint8_t> eventDataVec{}; 305 eventDataVec.resize(maxSize); 306 auto eventData = 307 reinterpret_cast<struct pldm_pdr_repository_chg_event_data*>( 308 eventDataVec.data()); 309 size_t actualSize{}; 310 auto firstEntry = changeEntries[0].data(); 311 auto rc = encode_pldm_pdr_repository_chg_event_data( 312 eventDataFormat, 1, eventDataOps.data(), numsOfChangeEntries.data(), 313 &firstEntry, eventData, &actualSize, maxSize); 314 if (rc != PLDM_SUCCESS) 315 { 316 error("Failed to encode_pldm_pdr_repository_chg_event_data, rc = {RC}", 317 "RC", rc); 318 return; 319 } 320 auto instanceId = instanceIdDb.next(mctp_eid); 321 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) + 322 PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES + 323 actualSize); 324 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 325 rc = encode_platform_event_message_req( 326 instanceId, 1, TERMINUS_ID, PLDM_PDR_REPOSITORY_CHG_EVENT, 327 eventDataVec.data(), actualSize, request, 328 actualSize + PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES); 329 if (rc != PLDM_SUCCESS) 330 { 331 instanceIdDb.free(mctp_eid, instanceId); 332 error("Failed to encode_platform_event_message_req, rc = {RC}", "RC", 333 rc); 334 return; 335 } 336 337 auto platformEventMessageResponseHandler = 338 [](mctp_eid_t /*eid*/, const pldm_msg* response, size_t respMsgLen) { 339 if (response == nullptr || !respMsgLen) 340 { 341 error( 342 "Failed to receive response for the PDR repository changed event"); 343 return; 344 } 345 346 uint8_t completionCode{}; 347 uint8_t status{}; 348 auto responsePtr = reinterpret_cast<const struct pldm_msg*>(response); 349 auto rc = decode_platform_event_message_resp(responsePtr, respMsgLen, 350 &completionCode, &status); 351 if (rc || completionCode) 352 { 353 error( 354 "Failed to decode_platform_event_message_resp: {RC}, cc = {CC}", 355 "RC", rc, "CC", static_cast<unsigned>(completionCode)); 356 } 357 }; 358 359 rc = handler->registerRequest( 360 mctp_eid, instanceId, PLDM_PLATFORM, PLDM_PLATFORM_EVENT_MESSAGE, 361 std::move(requestMsg), std::move(platformEventMessageResponseHandler)); 362 if (rc) 363 { 364 error("Failed to send the PDR repository changed event request"); 365 } 366 } 367 368 void HostPDRHandler::parseStateSensorPDRs(const PDRList& stateSensorPDRs) 369 { 370 for (const auto& pdr : stateSensorPDRs) 371 { 372 SensorEntry sensorEntry{}; 373 const auto& [terminusHandle, sensorID, sensorInfo] = 374 responder::pdr_utils::parseStateSensorPDR(pdr); 375 sensorEntry.sensorID = sensorID; 376 try 377 { 378 sensorEntry.terminusID = std::get<0>(tlPDRInfo.at(terminusHandle)); 379 } 380 // If there is no mapping for terminusHandle assign the reserved TID 381 // value of 0xFF to indicate that. 382 catch (const std::out_of_range& e) 383 { 384 sensorEntry.terminusID = PLDM_TID_RESERVED; 385 } 386 sensorMap.emplace(sensorEntry, std::move(sensorInfo)); 387 } 388 } 389 390 void HostPDRHandler::processHostPDRs(mctp_eid_t /*eid*/, 391 const pldm_msg* response, 392 size_t respMsgLen) 393 { 394 static bool merged = false; 395 static PDRList stateSensorPDRs{}; 396 uint32_t nextRecordHandle{}; 397 uint8_t tlEid = 0; 398 bool tlValid = true; 399 uint32_t rh = 0; 400 uint16_t terminusHandle = 0; 401 uint16_t pdrTerminusHandle = 0; 402 uint8_t tid = 0; 403 404 uint8_t completionCode{}; 405 uint32_t nextDataTransferHandle{}; 406 uint8_t transferFlag{}; 407 uint16_t respCount{}; 408 uint8_t transferCRC{}; 409 if (response == nullptr || !respMsgLen) 410 { 411 error("Failed to receive response for the GetPDR command"); 412 return; 413 } 414 415 auto rc = decode_get_pdr_resp( 416 response, respMsgLen /*- sizeof(pldm_msg_hdr)*/, &completionCode, 417 &nextRecordHandle, &nextDataTransferHandle, &transferFlag, &respCount, 418 nullptr, 0, &transferCRC); 419 std::vector<uint8_t> responsePDRMsg; 420 responsePDRMsg.resize(respMsgLen + sizeof(pldm_msg_hdr)); 421 memcpy(responsePDRMsg.data(), response, respMsgLen + sizeof(pldm_msg_hdr)); 422 if (rc != PLDM_SUCCESS) 423 { 424 error("Failed to decode_get_pdr_resp, rc = {RC}", "RC", rc); 425 return; 426 } 427 else 428 { 429 std::vector<uint8_t> pdr(respCount, 0); 430 rc = decode_get_pdr_resp(response, respMsgLen, &completionCode, 431 &nextRecordHandle, &nextDataTransferHandle, 432 &transferFlag, &respCount, pdr.data(), 433 respCount, &transferCRC); 434 if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS) 435 { 436 error("Failed to decode_get_pdr_resp: rc = {RC}, cc = {CC}", "RC", 437 rc, "CC", static_cast<unsigned>(completionCode)); 438 return; 439 } 440 else 441 { 442 // when nextRecordHandle is 0, we need the recordHandle of the last 443 // PDR and not 0-1. 444 if (!nextRecordHandle) 445 { 446 rh = nextRecordHandle; 447 } 448 else 449 { 450 rh = nextRecordHandle - 1; 451 } 452 453 auto pdrHdr = reinterpret_cast<pldm_pdr_hdr*>(pdr.data()); 454 if (!rh) 455 { 456 rh = pdrHdr->record_handle; 457 } 458 459 if (pdrHdr->type == PLDM_PDR_ENTITY_ASSOCIATION) 460 { 461 this->mergeEntityAssociations(pdr); 462 merged = true; 463 } 464 else 465 { 466 if (pdrHdr->type == PLDM_TERMINUS_LOCATOR_PDR) 467 { 468 pdrTerminusHandle = 469 extractTerminusHandle<pldm_terminus_locator_pdr>(pdr); 470 auto tlpdr = 471 reinterpret_cast<const pldm_terminus_locator_pdr*>( 472 pdr.data()); 473 474 terminusHandle = tlpdr->terminus_handle; 475 tid = tlpdr->tid; 476 auto terminus_locator_type = tlpdr->terminus_locator_type; 477 if (terminus_locator_type == 478 PLDM_TERMINUS_LOCATOR_TYPE_MCTP_EID) 479 { 480 auto locatorValue = reinterpret_cast< 481 const pldm_terminus_locator_type_mctp_eid*>( 482 tlpdr->terminus_locator_value); 483 tlEid = static_cast<uint8_t>(locatorValue->eid); 484 } 485 if (tlpdr->validity == 0) 486 { 487 tlValid = false; 488 } 489 for (const auto& terminusMap : tlPDRInfo) 490 { 491 if ((terminusHandle == (terminusMap.first)) && 492 (get<1>(terminusMap.second) == tlEid) && 493 (get<2>(terminusMap.second) == tlpdr->validity)) 494 { 495 // TL PDR already present with same validity don't 496 // add the PDR to the repo just return 497 return; 498 } 499 } 500 tlPDRInfo.insert_or_assign( 501 tlpdr->terminus_handle, 502 std::make_tuple(tlpdr->tid, tlEid, tlpdr->validity)); 503 } 504 else if (pdrHdr->type == PLDM_STATE_SENSOR_PDR) 505 { 506 pdrTerminusHandle = 507 extractTerminusHandle<pldm_state_sensor_pdr>(pdr); 508 stateSensorPDRs.emplace_back(pdr); 509 } 510 else if (pdrHdr->type == PLDM_PDR_FRU_RECORD_SET) 511 { 512 pdrTerminusHandle = 513 extractTerminusHandle<pldm_pdr_fru_record_set>(pdr); 514 } 515 else if (pdrHdr->type == PLDM_STATE_EFFECTER_PDR) 516 { 517 pdrTerminusHandle = 518 extractTerminusHandle<pldm_state_effecter_pdr>(pdr); 519 } 520 else if (pdrHdr->type == PLDM_NUMERIC_EFFECTER_PDR) 521 { 522 pdrTerminusHandle = 523 extractTerminusHandle<pldm_numeric_effecter_value_pdr>( 524 pdr); 525 } 526 // if the TLPDR is invalid update the repo accordingly 527 if (!tlValid) 528 { 529 pldm_pdr_update_TL_pdr(repo, terminusHandle, tid, tlEid, 530 tlValid); 531 } 532 else 533 { 534 rc = pldm_pdr_add_check(repo, pdr.data(), respCount, true, 535 pdrTerminusHandle, &rh); 536 if (rc) 537 { 538 // pldm_pdr_add() assert()ed on failure to add a PDR. 539 throw std::runtime_error("Failed to add PDR"); 540 } 541 } 542 } 543 } 544 } 545 if (!nextRecordHandle) 546 { 547 /*received last record*/ 548 this->parseStateSensorPDRs(stateSensorPDRs); 549 if (isHostUp()) 550 { 551 this->setHostSensorState(stateSensorPDRs); 552 } 553 stateSensorPDRs.clear(); 554 if (merged) 555 { 556 merged = false; 557 deferredPDRRepoChgEvent = 558 std::make_unique<sdeventplus::source::Defer>( 559 event, 560 std::bind( 561 std::mem_fn((&HostPDRHandler::_processPDRRepoChgEvent)), 562 this, std::placeholders::_1)); 563 } 564 } 565 else 566 { 567 if (modifiedPDRRecordHandles.empty() && isHostPdrModified) 568 { 569 isHostPdrModified = false; 570 } 571 else 572 { 573 deferredFetchPDREvent = 574 std::make_unique<sdeventplus::source::Defer>( 575 event, 576 std::bind( 577 std::mem_fn((&HostPDRHandler::_processFetchPDREvent)), 578 this, nextRecordHandle, std::placeholders::_1)); 579 } 580 } 581 } 582 583 void HostPDRHandler::_processPDRRepoChgEvent( 584 sdeventplus::source::EventBase& /*source */) 585 { 586 deferredPDRRepoChgEvent.reset(); 587 this->sendPDRRepositoryChgEvent( 588 std::move(std::vector<uint8_t>(1, PLDM_PDR_ENTITY_ASSOCIATION)), 589 FORMAT_IS_PDR_HANDLES); 590 } 591 592 void HostPDRHandler::_processFetchPDREvent( 593 uint32_t nextRecordHandle, sdeventplus::source::EventBase& /*source */) 594 { 595 deferredFetchPDREvent.reset(); 596 if (!this->pdrRecordHandles.empty()) 597 { 598 nextRecordHandle = this->pdrRecordHandles.front(); 599 this->pdrRecordHandles.pop_front(); 600 } 601 if (isHostPdrModified && (!this->modifiedPDRRecordHandles.empty())) 602 { 603 nextRecordHandle = this->modifiedPDRRecordHandles.front(); 604 this->modifiedPDRRecordHandles.pop_front(); 605 } 606 this->getHostPDR(nextRecordHandle); 607 } 608 609 void HostPDRHandler::setHostFirmwareCondition() 610 { 611 responseReceived = false; 612 auto instanceId = instanceIdDb.next(mctp_eid); 613 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) + 614 PLDM_GET_VERSION_REQ_BYTES); 615 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 616 auto rc = encode_get_version_req(instanceId, 0, PLDM_GET_FIRSTPART, 617 PLDM_BASE, request); 618 if (rc != PLDM_SUCCESS) 619 { 620 error("GetPLDMVersion encode failure. PLDM error code = {RC}", "RC", 621 lg2::hex, rc); 622 instanceIdDb.free(mctp_eid, instanceId); 623 return; 624 } 625 626 auto getPLDMVersionHandler = [this](mctp_eid_t /*eid*/, 627 const pldm_msg* response, 628 size_t respMsgLen) { 629 if (response == nullptr || !respMsgLen) 630 { 631 error( 632 "Failed to receive response for getPLDMVersion command, Host seems to be off"); 633 return; 634 } 635 info("Getting the response. PLDM RC = {RC}", "RC", lg2::hex, 636 static_cast<uint16_t>(response->payload[0])); 637 this->responseReceived = true; 638 getHostPDR(); 639 }; 640 rc = handler->registerRequest(mctp_eid, instanceId, PLDM_BASE, 641 PLDM_GET_PLDM_VERSION, std::move(requestMsg), 642 std::move(getPLDMVersionHandler)); 643 if (rc) 644 { 645 error("Failed to discover Host state. Assuming Host as off"); 646 } 647 } 648 649 bool HostPDRHandler::isHostUp() 650 { 651 return responseReceived; 652 } 653 654 void HostPDRHandler::setHostSensorState(const PDRList& stateSensorPDRs) 655 { 656 for (const auto& stateSensorPDR : stateSensorPDRs) 657 { 658 auto pdr = reinterpret_cast<const pldm_state_sensor_pdr*>( 659 stateSensorPDR.data()); 660 661 if (!pdr) 662 { 663 error("Failed to get State sensor PDR"); 664 pldm::utils::reportError( 665 "xyz.openbmc_project.bmc.pldm.InternalFailure"); 666 return; 667 } 668 669 uint16_t sensorId = pdr->sensor_id; 670 671 for (const auto& [terminusHandle, terminusInfo] : tlPDRInfo) 672 { 673 if (terminusHandle == pdr->terminus_handle) 674 { 675 if (std::get<2>(terminusInfo) == PLDM_TL_PDR_VALID) 676 { 677 mctp_eid = std::get<1>(terminusInfo); 678 } 679 680 bitfield8_t sensorRearm; 681 sensorRearm.byte = 0; 682 uint8_t tid = std::get<0>(terminusInfo); 683 684 auto instanceId = instanceIdDb.next(mctp_eid); 685 std::vector<uint8_t> requestMsg( 686 sizeof(pldm_msg_hdr) + 687 PLDM_GET_STATE_SENSOR_READINGS_REQ_BYTES); 688 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 689 auto rc = encode_get_state_sensor_readings_req( 690 instanceId, sensorId, sensorRearm, 0, request); 691 692 if (rc != PLDM_SUCCESS) 693 { 694 instanceIdDb.free(mctp_eid, instanceId); 695 error( 696 "Failed to encode_get_state_sensor_readings_req, rc = {RC}", 697 "RC", rc); 698 pldm::utils::reportError( 699 "xyz.openbmc_project.bmc.pldm.InternalFailure"); 700 return; 701 } 702 703 auto getStateSensorReadingRespHandler = 704 [=, this](mctp_eid_t /*eid*/, const pldm_msg* response, 705 size_t respMsgLen) { 706 if (response == nullptr || !respMsgLen) 707 { 708 error( 709 "Failed to receive response for getStateSensorReading command"); 710 return; 711 } 712 std::array<get_sensor_state_field, 8> stateField{}; 713 uint8_t completionCode = 0; 714 uint8_t comp_sensor_count = 0; 715 716 auto rc = decode_get_state_sensor_readings_resp( 717 response, respMsgLen, &completionCode, 718 &comp_sensor_count, stateField.data()); 719 720 if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS) 721 { 722 error( 723 "Failed to decode_get_state_sensor_readings_resp, rc = {RC} cc = {CC}", 724 "RC", rc, "CC", 725 static_cast<unsigned>(completionCode)); 726 pldm::utils::reportError( 727 "xyz.openbmc_project.bmc.pldm.InternalFailure"); 728 } 729 730 uint8_t eventState; 731 uint8_t previousEventState; 732 733 for (uint8_t sensorOffset = 0; 734 sensorOffset < comp_sensor_count; sensorOffset++) 735 { 736 eventState = stateField[sensorOffset].present_state; 737 previousEventState = 738 stateField[sensorOffset].previous_state; 739 740 emitStateSensorEventSignal(tid, sensorId, sensorOffset, 741 eventState, 742 previousEventState); 743 744 SensorEntry sensorEntry{tid, sensorId}; 745 746 pldm::pdr::EntityInfo entityInfo{}; 747 pldm::pdr::CompositeSensorStates 748 compositeSensorStates{}; 749 750 try 751 { 752 std::tie(entityInfo, compositeSensorStates) = 753 lookupSensorInfo(sensorEntry); 754 } 755 catch (const std::out_of_range& e) 756 { 757 try 758 { 759 sensorEntry.terminusID = PLDM_TID_RESERVED; 760 std::tie(entityInfo, compositeSensorStates) = 761 lookupSensorInfo(sensorEntry); 762 } 763 catch (const std::out_of_range& e) 764 { 765 error("No mapping for the events"); 766 } 767 } 768 769 if (sensorOffset > compositeSensorStates.size()) 770 { 771 error("Error Invalid data, Invalid sensor offset"); 772 return; 773 } 774 775 const auto& possibleStates = 776 compositeSensorStates[sensorOffset]; 777 if (possibleStates.find(eventState) == 778 possibleStates.end()) 779 { 780 error("Error invalid_data, Invalid event state"); 781 return; 782 } 783 const auto& [containerId, entityType, 784 entityInstance] = entityInfo; 785 pldm::responder::events::StateSensorEntry 786 stateSensorEntry{containerId, entityType, 787 entityInstance, sensorOffset}; 788 handleStateSensorEvent(stateSensorEntry, eventState); 789 } 790 }; 791 792 rc = handler->registerRequest( 793 mctp_eid, instanceId, PLDM_PLATFORM, 794 PLDM_GET_STATE_SENSOR_READINGS, std::move(requestMsg), 795 std::move(getStateSensorReadingRespHandler)); 796 797 if (rc != PLDM_SUCCESS) 798 { 799 error( 800 "Failed to send request to get State sensor reading on Host"); 801 } 802 } 803 } 804 } 805 } 806 } // namespace pldm 807