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