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 <sdeventplus/clock.hpp> 10 #include <sdeventplus/exception.hpp> 11 #include <sdeventplus/source/io.hpp> 12 #include <sdeventplus/source/time.hpp> 13 14 #include <fstream> 15 16 namespace pldm 17 { 18 using namespace pldm::dbus_api; 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, Requester& requester, 51 pldm::requester::Handler<pldm::requester::Request>* handler) : 52 mctp_fd(mctp_fd), 53 mctp_eid(mctp_eid), event(event), repo(repo), 54 stateSensorHandler(eventsJsonsDir), entityTree(entityTree), 55 bmcEntityTree(bmcEntityTree), requester(requester), handler(handler) 56 { 57 fs::path hostFruJson(fs::path(HOST_JSONS_DIR) / fruJson); 58 if (fs::exists(hostFruJson)) 59 { 60 // Note parent entities for entities sent down by the host firmware. 61 // This will enable a merge of entity associations. 62 try 63 { 64 std::ifstream jsonFile(hostFruJson); 65 auto data = Json::parse(jsonFile, nullptr, false); 66 if (data.is_discarded()) 67 { 68 std::cerr << "Parsing Host FRU json file failed" << std::endl; 69 } 70 else 71 { 72 auto entities = data.value("entities", emptyJsonList); 73 for (auto& entity : entities) 74 { 75 EntityType entityType = entity.value("entity_type", 0); 76 auto parent = entity.value("parent", emptyJson); 77 pldm_entity p{}; 78 p.entity_type = parent.value("entity_type", 0); 79 p.entity_instance_num = parent.value("entity_instance", 0); 80 parents.emplace(entityType, std::move(p)); 81 } 82 } 83 } 84 catch (const std::exception& e) 85 { 86 std::cerr << "Parsing Host FRU json file failed, exception = " 87 << e.what() << std::endl; 88 } 89 } 90 91 hostOffMatch = std::make_unique<sdbusplus::bus::match_t>( 92 pldm::utils::DBusHandler::getBus(), 93 propertiesChanged("/xyz/openbmc_project/state/host0", 94 "xyz.openbmc_project.State.Host"), 95 [this, repo, entityTree, bmcEntityTree](sdbusplus::message_t& msg) { 96 DbusChangedProps props{}; 97 std::string intf; 98 msg.read(intf, props); 99 const auto itr = props.find("CurrentHostState"); 100 if (itr != props.end()) 101 { 102 PropertyValue value = itr->second; 103 auto propVal = std::get<std::string>(value); 104 if (propVal == "xyz.openbmc_project.State.Host.HostState.Off") 105 { 106 // Delete all the remote terminus information 107 std::erase_if(tlPDRInfo, [](const auto& item) { 108 auto const& [key, value] = item; 109 return key != TERMINUS_HANDLE; 110 }); 111 pldm_pdr_remove_remote_pdrs(repo); 112 pldm_entity_association_tree_destroy_root(entityTree); 113 pldm_entity_association_tree_copy_root(bmcEntityTree, 114 entityTree); 115 this->sensorMap.clear(); 116 this->responseReceived = false; 117 } 118 } 119 }); 120 } 121 122 void HostPDRHandler::fetchPDR(PDRRecordHandles&& recordHandles) 123 { 124 pdrRecordHandles.clear(); 125 modifiedPDRRecordHandles.clear(); 126 127 if (isHostPdrModified) 128 { 129 modifiedPDRRecordHandles = std::move(recordHandles); 130 } 131 else 132 { 133 pdrRecordHandles = std::move(recordHandles); 134 } 135 136 // Defer the actual fetch of PDRs from the host (by queuing the call on the 137 // main event loop). That way, we can respond to the platform event msg from 138 // the host firmware. 139 pdrFetchEvent = std::make_unique<sdeventplus::source::Defer>( 140 event, std::bind(std::mem_fn(&HostPDRHandler::_fetchPDR), this, 141 std::placeholders::_1)); 142 } 143 144 void HostPDRHandler::_fetchPDR(sdeventplus::source::EventBase& /*source*/) 145 { 146 getHostPDR(); 147 } 148 149 void HostPDRHandler::getHostPDR(uint32_t nextRecordHandle) 150 { 151 pdrFetchEvent.reset(); 152 153 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) + 154 PLDM_GET_PDR_REQ_BYTES); 155 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 156 uint32_t recordHandle{}; 157 if (!nextRecordHandle && (!modifiedPDRRecordHandles.empty()) && 158 isHostPdrModified) 159 { 160 recordHandle = modifiedPDRRecordHandles.front(); 161 modifiedPDRRecordHandles.pop_front(); 162 } 163 else if (!nextRecordHandle && (!pdrRecordHandles.empty())) 164 { 165 recordHandle = pdrRecordHandles.front(); 166 pdrRecordHandles.pop_front(); 167 } 168 else 169 { 170 recordHandle = nextRecordHandle; 171 } 172 auto instanceId = requester.getInstanceId(mctp_eid); 173 174 auto rc = 175 encode_get_pdr_req(instanceId, recordHandle, 0, PLDM_GET_FIRSTPART, 176 UINT16_MAX, 0, request, PLDM_GET_PDR_REQ_BYTES); 177 if (rc != PLDM_SUCCESS) 178 { 179 requester.markFree(mctp_eid, instanceId); 180 std::cerr << "Failed to encode_get_pdr_req, rc = " << rc << std::endl; 181 return; 182 } 183 184 rc = handler->registerRequest( 185 mctp_eid, instanceId, PLDM_PLATFORM, PLDM_GET_PDR, 186 std::move(requestMsg), 187 std::move(std::bind_front(&HostPDRHandler::processHostPDRs, this))); 188 if (rc) 189 { 190 std::cerr << "Failed to send the GetPDR request to Host \n"; 191 } 192 } 193 194 int HostPDRHandler::handleStateSensorEvent(const StateSensorEntry& entry, 195 pdr::EventState state) 196 { 197 auto rc = stateSensorHandler.eventAction(entry, state); 198 if (rc != PLDM_SUCCESS) 199 { 200 std::cerr << "Failed to fetch and update D-bus property, rc = " << rc 201 << std::endl; 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 std::cerr 253 << "\ncould not find referrence of the entity in the tree \n"; 254 } 255 else 256 { 257 pldm_entity_association_pdr_add_from_node( 258 node, repo, &entities, numEntities, true, TERMINUS_HANDLE); 259 } 260 } 261 free(entities); 262 } 263 264 void HostPDRHandler::sendPDRRepositoryChgEvent(std::vector<uint8_t>&& pdrTypes, 265 uint8_t eventDataFormat) 266 { 267 assert(eventDataFormat == FORMAT_IS_PDR_HANDLES); 268 269 // Extract from the PDR repo record handles of PDRs we want the host 270 // to pull up. 271 std::vector<uint8_t> eventDataOps{PLDM_RECORDS_ADDED}; 272 std::vector<uint8_t> numsOfChangeEntries(1); 273 std::vector<std::vector<ChangeEntry>> changeEntries( 274 numsOfChangeEntries.size()); 275 for (auto pdrType : pdrTypes) 276 { 277 const pldm_pdr_record* record{}; 278 do 279 { 280 record = pldm_pdr_find_record_by_type(repo, pdrType, record, 281 nullptr, nullptr); 282 if (record && pldm_pdr_record_is_remote(record)) 283 { 284 changeEntries[0].push_back( 285 pldm_pdr_get_record_handle(repo, record)); 286 } 287 } while (record); 288 } 289 if (changeEntries.empty()) 290 { 291 return; 292 } 293 numsOfChangeEntries[0] = changeEntries[0].size(); 294 295 // Encode PLDM platform event msg to indicate a PDR repo change. 296 size_t maxSize = PLDM_PDR_REPOSITORY_CHG_EVENT_MIN_LENGTH + 297 PLDM_PDR_REPOSITORY_CHANGE_RECORD_MIN_LENGTH + 298 changeEntries[0].size() * sizeof(uint32_t); 299 std::vector<uint8_t> eventDataVec{}; 300 eventDataVec.resize(maxSize); 301 auto eventData = 302 reinterpret_cast<struct pldm_pdr_repository_chg_event_data*>( 303 eventDataVec.data()); 304 size_t actualSize{}; 305 auto firstEntry = changeEntries[0].data(); 306 auto rc = encode_pldm_pdr_repository_chg_event_data( 307 eventDataFormat, 1, eventDataOps.data(), numsOfChangeEntries.data(), 308 &firstEntry, eventData, &actualSize, maxSize); 309 if (rc != PLDM_SUCCESS) 310 { 311 std::cerr 312 << "Failed to encode_pldm_pdr_repository_chg_event_data, rc = " 313 << rc << std::endl; 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, 0, PLDM_PDR_REPOSITORY_CHG_EVENT, eventDataVec.data(), 323 actualSize, request, 324 actualSize + PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES); 325 if (rc != PLDM_SUCCESS) 326 { 327 requester.markFree(mctp_eid, instanceId); 328 std::cerr << "Failed to encode_platform_event_message_req, rc = " << rc 329 << std::endl; 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 std::cerr << "Failed to receive response for the PDR repository " 339 "changed event" 340 << "\n"; 341 return; 342 } 343 344 uint8_t completionCode{}; 345 uint8_t status{}; 346 auto responsePtr = reinterpret_cast<const struct pldm_msg*>(response); 347 auto rc = decode_platform_event_message_resp(responsePtr, respMsgLen, 348 &completionCode, &status); 349 if (rc || completionCode) 350 { 351 std::cerr << "Failed to decode_platform_event_message_resp: " 352 << "rc=" << rc 353 << ", cc=" << static_cast<unsigned>(completionCode) 354 << std::endl; 355 } 356 }; 357 358 rc = handler->registerRequest( 359 mctp_eid, instanceId, PLDM_PLATFORM, PLDM_PLATFORM_EVENT_MESSAGE, 360 std::move(requestMsg), std::move(platformEventMessageResponseHandler)); 361 if (rc) 362 { 363 std::cerr << "Failed to send the PDR repository changed event request" 364 << "\n"; 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 std::cerr << "Failed to receive response for the GetPDR" 412 " command \n"; 413 return; 414 } 415 416 auto rc = decode_get_pdr_resp( 417 response, respMsgLen /*- sizeof(pldm_msg_hdr)*/, &completionCode, 418 &nextRecordHandle, &nextDataTransferHandle, &transferFlag, &respCount, 419 nullptr, 0, &transferCRC); 420 std::vector<uint8_t> responsePDRMsg; 421 responsePDRMsg.resize(respMsgLen + sizeof(pldm_msg_hdr)); 422 memcpy(responsePDRMsg.data(), response, respMsgLen + sizeof(pldm_msg_hdr)); 423 if (rc != PLDM_SUCCESS) 424 { 425 std::cerr << "Failed to decode_get_pdr_resp, rc = " << rc << std::endl; 426 return; 427 } 428 else 429 { 430 std::vector<uint8_t> pdr(respCount, 0); 431 rc = decode_get_pdr_resp(response, respMsgLen, &completionCode, 432 &nextRecordHandle, &nextDataTransferHandle, 433 &transferFlag, &respCount, pdr.data(), 434 respCount, &transferCRC); 435 if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS) 436 { 437 std::cerr << "Failed to decode_get_pdr_resp: " 438 << "rc=" << rc 439 << ", cc=" << static_cast<unsigned>(completionCode) 440 << std::endl; 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 pldm_pdr_add(repo, pdr.data(), respCount, rh, true, 538 pdrTerminusHandle); 539 } 540 } 541 } 542 } 543 if (!nextRecordHandle) 544 { 545 /*received last record*/ 546 this->parseStateSensorPDRs(stateSensorPDRs); 547 if (isHostUp()) 548 { 549 this->setHostSensorState(stateSensorPDRs); 550 } 551 stateSensorPDRs.clear(); 552 if (merged) 553 { 554 merged = false; 555 deferredPDRRepoChgEvent = 556 std::make_unique<sdeventplus::source::Defer>( 557 event, 558 std::bind( 559 std::mem_fn((&HostPDRHandler::_processPDRRepoChgEvent)), 560 this, std::placeholders::_1)); 561 } 562 } 563 else 564 { 565 if (modifiedPDRRecordHandles.empty() && isHostPdrModified) 566 { 567 isHostPdrModified = false; 568 } 569 else 570 { 571 deferredFetchPDREvent = 572 std::make_unique<sdeventplus::source::Defer>( 573 event, 574 std::bind( 575 std::mem_fn((&HostPDRHandler::_processFetchPDREvent)), 576 this, nextRecordHandle, std::placeholders::_1)); 577 } 578 } 579 } 580 581 void HostPDRHandler::_processPDRRepoChgEvent( 582 sdeventplus::source::EventBase& /*source */) 583 { 584 deferredPDRRepoChgEvent.reset(); 585 this->sendPDRRepositoryChgEvent( 586 std::move(std::vector<uint8_t>(1, PLDM_PDR_ENTITY_ASSOCIATION)), 587 FORMAT_IS_PDR_HANDLES); 588 } 589 590 void HostPDRHandler::_processFetchPDREvent( 591 uint32_t nextRecordHandle, sdeventplus::source::EventBase& /*source */) 592 { 593 deferredFetchPDREvent.reset(); 594 if (!this->pdrRecordHandles.empty()) 595 { 596 nextRecordHandle = this->pdrRecordHandles.front(); 597 this->pdrRecordHandles.pop_front(); 598 } 599 if (isHostPdrModified && (!this->modifiedPDRRecordHandles.empty())) 600 { 601 nextRecordHandle = this->modifiedPDRRecordHandles.front(); 602 this->modifiedPDRRecordHandles.pop_front(); 603 } 604 this->getHostPDR(nextRecordHandle); 605 } 606 607 void HostPDRHandler::setHostFirmwareCondition() 608 { 609 responseReceived = false; 610 auto instanceId = requester.getInstanceId(mctp_eid); 611 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) + 612 PLDM_GET_VERSION_REQ_BYTES); 613 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 614 auto rc = encode_get_version_req(instanceId, 0, PLDM_GET_FIRSTPART, 615 PLDM_BASE, request); 616 if (rc != PLDM_SUCCESS) 617 { 618 std::cerr << "GetPLDMVersion encode failure. PLDM error code = " 619 << std::hex << std::showbase << rc << "\n"; 620 requester.markFree(mctp_eid, instanceId); 621 return; 622 } 623 624 auto getPLDMVersionHandler = [this](mctp_eid_t /*eid*/, 625 const pldm_msg* response, 626 size_t respMsgLen) { 627 if (response == nullptr || !respMsgLen) 628 { 629 std::cerr << "Failed to receive response for " 630 << "getPLDMVersion command, Host seems to be off \n"; 631 return; 632 } 633 std::cout << "Getting the response. PLDM RC = " << std::hex 634 << std::showbase 635 << static_cast<uint16_t>(response->payload[0]) << "\n"; 636 this->responseReceived = true; 637 getHostPDR(); 638 }; 639 rc = handler->registerRequest(mctp_eid, instanceId, PLDM_BASE, 640 PLDM_GET_PLDM_VERSION, std::move(requestMsg), 641 std::move(getPLDMVersionHandler)); 642 if (rc) 643 { 644 std::cerr << "Failed to discover Host state. Assuming Host as off \n"; 645 } 646 } 647 648 bool HostPDRHandler::isHostUp() 649 { 650 return responseReceived; 651 } 652 653 void HostPDRHandler::setHostSensorState(const PDRList& stateSensorPDRs) 654 { 655 for (const auto& stateSensorPDR : stateSensorPDRs) 656 { 657 auto pdr = reinterpret_cast<const pldm_state_sensor_pdr*>( 658 stateSensorPDR.data()); 659 660 if (!pdr) 661 { 662 std::cerr << "Failed to get State sensor PDR" << std::endl; 663 pldm::utils::reportError( 664 "xyz.openbmc_project.bmc.pldm.InternalFailure"); 665 return; 666 } 667 668 uint16_t sensorId = pdr->sensor_id; 669 670 for (const auto& [terminusHandle, terminusInfo] : tlPDRInfo) 671 { 672 if (terminusHandle == pdr->terminus_handle) 673 { 674 if (std::get<2>(terminusInfo) == PLDM_TL_PDR_VALID) 675 { 676 mctp_eid = std::get<1>(terminusInfo); 677 } 678 679 bitfield8_t sensorRearm; 680 sensorRearm.byte = 0; 681 uint8_t tid = std::get<0>(terminusInfo); 682 683 auto instanceId = requester.getInstanceId(mctp_eid); 684 std::vector<uint8_t> requestMsg( 685 sizeof(pldm_msg_hdr) + 686 PLDM_GET_STATE_SENSOR_READINGS_REQ_BYTES); 687 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 688 auto rc = encode_get_state_sensor_readings_req( 689 instanceId, sensorId, sensorRearm, 0, request); 690 691 if (rc != PLDM_SUCCESS) 692 { 693 requester.markFree(mctp_eid, instanceId); 694 std::cerr << "Failed to " 695 "encode_get_state_sensor_readings_req, rc = " 696 << rc << std::endl; 697 pldm::utils::reportError( 698 "xyz.openbmc_project.bmc.pldm.InternalFailure"); 699 return; 700 } 701 702 auto getStateSensorReadingRespHandler = [=, this]( 703 mctp_eid_t /*eid*/, 704 const pldm_msg* 705 response, 706 size_t respMsgLen) { 707 if (response == nullptr || !respMsgLen) 708 { 709 std::cerr << "Failed to receive response for " 710 "getStateSensorReading command \n"; 711 return; 712 } 713 std::array<get_sensor_state_field, 8> stateField{}; 714 uint8_t completionCode = 0; 715 uint8_t comp_sensor_count = 0; 716 717 auto rc = decode_get_state_sensor_readings_resp( 718 response, respMsgLen, &completionCode, 719 &comp_sensor_count, stateField.data()); 720 721 if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS) 722 { 723 std::cerr 724 << "Failed to " 725 "decode_get_state_sensor_readings_resp, rc = " 726 << rc 727 << " cc=" << static_cast<unsigned>(completionCode) 728 << std::endl; 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 std::cerr << "No mapping for the events" 769 << std::endl; 770 } 771 } 772 773 if (sensorOffset > compositeSensorStates.size()) 774 { 775 std::cerr 776 << " Error Invalid data, Invalid sensor offset" 777 << std::endl; 778 return; 779 } 780 781 const auto& possibleStates = 782 compositeSensorStates[sensorOffset]; 783 if (possibleStates.find(eventState) == 784 possibleStates.end()) 785 { 786 std::cerr 787 << " Error invalid_data, Invalid event state" 788 << std::endl; 789 return; 790 } 791 const auto& [containerId, entityType, entityInstance] = 792 entityInfo; 793 pldm::responder::events::StateSensorEntry 794 stateSensorEntry{containerId, entityType, 795 entityInstance, sensorOffset}; 796 handleStateSensorEvent(stateSensorEntry, eventState); 797 } 798 }; 799 800 rc = handler->registerRequest( 801 mctp_eid, instanceId, PLDM_PLATFORM, 802 PLDM_GET_STATE_SENSOR_READINGS, std::move(requestMsg), 803 std::move(getStateSensorReadingRespHandler)); 804 805 if (rc != PLDM_SUCCESS) 806 { 807 std::cerr << " Failed to send request to get State sensor " 808 "reading on Host " 809 << std::endl; 810 } 811 } 812 } 813 } 814 } 815 } // namespace pldm 816