1 #include "host_pdr_handler.hpp" 2 3 #include "libpldm/fru.h" 4 #ifdef OEM_IBM 5 #include "libpldm/fru_oem_ibm.h" 6 #endif 7 8 #include "custom_dbus.hpp" 9 10 #include <assert.h> 11 #include <libpldm/pldm.h> 12 13 #include <nlohmann/json.hpp> 14 #include <phosphor-logging/lg2.hpp> 15 #include <sdeventplus/clock.hpp> 16 #include <sdeventplus/exception.hpp> 17 #include <sdeventplus/source/io.hpp> 18 #include <sdeventplus/source/time.hpp> 19 20 #include <fstream> 21 22 PHOSPHOR_LOG2_USING; 23 24 namespace pldm 25 { 26 using namespace pldm::responder::events; 27 using namespace pldm::utils; 28 using namespace sdbusplus::bus::match::rules; 29 using Json = nlohmann::json; 30 namespace fs = std::filesystem; 31 using namespace pldm::dbus; 32 constexpr auto fruJson = "host_frus.json"; 33 const Json emptyJson{}; 34 const std::vector<Json> emptyJsonList{}; 35 36 template <typename T> 37 uint16_t extractTerminusHandle(std::vector<uint8_t>& pdr) 38 { 39 T* var = nullptr; 40 if (std::is_same<T, pldm_pdr_fru_record_set>::value) 41 { 42 var = (T*)(pdr.data() + sizeof(pldm_pdr_hdr)); 43 } 44 else 45 { 46 var = (T*)(pdr.data()); 47 } 48 if (var != nullptr) 49 { 50 return var->terminus_handle; 51 } 52 return TERMINUS_HANDLE; 53 } 54 55 HostPDRHandler::HostPDRHandler( 56 int mctp_fd, uint8_t mctp_eid, sdeventplus::Event& event, pldm_pdr* repo, 57 const std::string& eventsJsonsDir, pldm_entity_association_tree* entityTree, 58 pldm_entity_association_tree* bmcEntityTree, 59 pldm::InstanceIdDb& instanceIdDb, 60 pldm::requester::Handler<pldm::requester::Request>* handler) : 61 mctp_fd(mctp_fd), 62 mctp_eid(mctp_eid), event(event), repo(repo), 63 stateSensorHandler(eventsJsonsDir), entityTree(entityTree), 64 bmcEntityTree(bmcEntityTree), instanceIdDb(instanceIdDb), handler(handler) 65 { 66 mergedHostParents = false; 67 fs::path hostFruJson(fs::path(HOST_JSONS_DIR) / fruJson); 68 if (fs::exists(hostFruJson)) 69 { 70 // Note parent entities for entities sent down by the host firmware. 71 // This will enable a merge of entity associations. 72 try 73 { 74 std::ifstream jsonFile(hostFruJson); 75 auto data = Json::parse(jsonFile, nullptr, false); 76 if (data.is_discarded()) 77 { 78 error("Parsing Host FRU json file failed"); 79 } 80 else 81 { 82 auto entities = data.value("entities", emptyJsonList); 83 for (auto& entity : entities) 84 { 85 EntityType entityType = entity.value("entity_type", 0); 86 auto parent = entity.value("parent", emptyJson); 87 pldm_entity p{}; 88 p.entity_type = parent.value("entity_type", 0); 89 p.entity_instance_num = parent.value("entity_instance", 0); 90 parents.emplace(entityType, std::move(p)); 91 } 92 } 93 } 94 catch (const std::exception& e) 95 { 96 error("Parsing Host FRU json file failed, exception = {ERR_EXCEP}", 97 "ERR_EXCEP", e.what()); 98 } 99 } 100 101 hostOffMatch = std::make_unique<sdbusplus::bus::match_t>( 102 pldm::utils::DBusHandler::getBus(), 103 propertiesChanged("/xyz/openbmc_project/state/host0", 104 "xyz.openbmc_project.State.Host"), 105 [this, repo, entityTree, bmcEntityTree](sdbusplus::message_t& msg) { 106 DbusChangedProps props{}; 107 std::string intf; 108 msg.read(intf, props); 109 const auto itr = props.find("CurrentHostState"); 110 if (itr != props.end()) 111 { 112 PropertyValue value = itr->second; 113 auto propVal = std::get<std::string>(value); 114 if (propVal == "xyz.openbmc_project.State.Host.HostState.Off") 115 { 116 // Delete all the remote terminus information 117 std::erase_if(tlPDRInfo, [](const auto& item) { 118 auto const& [key, value] = item; 119 return key != TERMINUS_HANDLE; 120 }); 121 pldm_pdr_remove_remote_pdrs(repo); 122 pldm_entity_association_tree_destroy_root(entityTree); 123 pldm_entity_association_tree_copy_root(bmcEntityTree, 124 entityTree); 125 this->sensorMap.clear(); 126 this->responseReceived = false; 127 this->mergedHostParents = false; 128 } 129 } 130 }); 131 } 132 133 void HostPDRHandler::fetchPDR(PDRRecordHandles&& recordHandles) 134 { 135 pdrRecordHandles.clear(); 136 modifiedPDRRecordHandles.clear(); 137 138 if (isHostPdrModified) 139 { 140 modifiedPDRRecordHandles = std::move(recordHandles); 141 } 142 else 143 { 144 pdrRecordHandles = std::move(recordHandles); 145 } 146 147 // Defer the actual fetch of PDRs from the host (by queuing the call on the 148 // main event loop). That way, we can respond to the platform event msg from 149 // the host firmware. 150 pdrFetchEvent = std::make_unique<sdeventplus::source::Defer>( 151 event, std::bind(std::mem_fn(&HostPDRHandler::_fetchPDR), this, 152 std::placeholders::_1)); 153 } 154 155 void HostPDRHandler::_fetchPDR(sdeventplus::source::EventBase& /*source*/) 156 { 157 getHostPDR(); 158 } 159 160 void HostPDRHandler::getHostPDR(uint32_t nextRecordHandle) 161 { 162 pdrFetchEvent.reset(); 163 164 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) + 165 PLDM_GET_PDR_REQ_BYTES); 166 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 167 uint32_t recordHandle{}; 168 if (!nextRecordHandle && (!modifiedPDRRecordHandles.empty()) && 169 isHostPdrModified) 170 { 171 recordHandle = modifiedPDRRecordHandles.front(); 172 modifiedPDRRecordHandles.pop_front(); 173 } 174 else if (!nextRecordHandle && (!pdrRecordHandles.empty())) 175 { 176 recordHandle = pdrRecordHandles.front(); 177 pdrRecordHandles.pop_front(); 178 } 179 else 180 { 181 recordHandle = nextRecordHandle; 182 } 183 auto instanceId = instanceIdDb.next(mctp_eid); 184 185 auto rc = encode_get_pdr_req(instanceId, recordHandle, 0, 186 PLDM_GET_FIRSTPART, UINT16_MAX, 0, request, 187 PLDM_GET_PDR_REQ_BYTES); 188 if (rc != PLDM_SUCCESS) 189 { 190 instanceIdDb.free(mctp_eid, instanceId); 191 error("Failed to encode_get_pdr_req, rc = {RC}", "RC", rc); 192 return; 193 } 194 195 rc = handler->registerRequest( 196 mctp_eid, instanceId, PLDM_PLATFORM, PLDM_GET_PDR, 197 std::move(requestMsg), 198 std::move(std::bind_front(&HostPDRHandler::processHostPDRs, this))); 199 if (rc) 200 { 201 error("Failed to send the GetPDR request to Host"); 202 } 203 } 204 205 int HostPDRHandler::handleStateSensorEvent(const StateSensorEntry& entry, 206 pdr::EventState state) 207 { 208 auto rc = stateSensorHandler.eventAction(entry, state); 209 if (rc != PLDM_SUCCESS) 210 { 211 error("Failed to fetch and update D-bus property, rc = {RC}", "RC", rc); 212 return rc; 213 } 214 return PLDM_SUCCESS; 215 } 216 217 void HostPDRHandler::mergeEntityAssociations(const std::vector<uint8_t>& pdr) 218 { 219 size_t numEntities{}; 220 pldm_entity* entities = nullptr; 221 bool merged = false; 222 auto entityPdr = reinterpret_cast<pldm_pdr_entity_association*>( 223 const_cast<uint8_t*>(pdr.data()) + sizeof(pldm_pdr_hdr)); 224 225 pldm_entity_association_pdr_extract(pdr.data(), pdr.size(), &numEntities, 226 &entities); 227 if (numEntities > 0) 228 { 229 pldm_entity_node* pNode = nullptr; 230 if (!mergedHostParents) 231 { 232 pNode = pldm_entity_association_tree_find_with_locality( 233 entityTree, &entities[0], false); 234 } 235 else 236 { 237 pNode = pldm_entity_association_tree_find_with_locality( 238 entityTree, &entities[0], true); 239 } 240 if (!pNode) 241 { 242 return; 243 } 244 245 Entities entityAssoc; 246 entityAssoc.push_back(pNode); 247 for (size_t i = 1; i < numEntities; ++i) 248 { 249 auto node = pldm_entity_association_tree_add_entity( 250 entityTree, &entities[i], entities[i].entity_instance_num, 251 pNode, entityPdr->association_type, true, true, 0xFFFF); 252 merged = true; 253 entityAssoc.push_back(node); 254 } 255 256 mergedHostParents = true; 257 if (merged) 258 { 259 entityAssociations.push_back(entityAssoc); 260 } 261 } 262 263 if (merged) 264 { 265 // Update our PDR repo with the merged entity association PDRs 266 pldm_entity_node* node = nullptr; 267 pldm_find_entity_ref_in_tree(entityTree, entities[0], &node); 268 if (node == nullptr) 269 { 270 error("could not find referrence of the entity in the tree"); 271 } 272 else 273 { 274 int rc = pldm_entity_association_pdr_add_from_node_check( 275 node, repo, &entities, numEntities, true, TERMINUS_HANDLE); 276 if (rc) 277 { 278 error( 279 "Failed to add entity association PDR from node: {LIBPLDM_ERROR}", 280 "LIBPLDM_ERROR", rc); 281 } 282 } 283 } 284 free(entities); 285 } 286 287 void HostPDRHandler::sendPDRRepositoryChgEvent(std::vector<uint8_t>&& pdrTypes, 288 uint8_t eventDataFormat) 289 { 290 assert(eventDataFormat == FORMAT_IS_PDR_HANDLES); 291 292 // Extract from the PDR repo record handles of PDRs we want the host 293 // to pull up. 294 std::vector<uint8_t> eventDataOps{PLDM_RECORDS_ADDED}; 295 std::vector<uint8_t> numsOfChangeEntries(1); 296 std::vector<std::vector<ChangeEntry>> changeEntries( 297 numsOfChangeEntries.size()); 298 for (auto pdrType : pdrTypes) 299 { 300 const pldm_pdr_record* record{}; 301 do 302 { 303 record = pldm_pdr_find_record_by_type(repo, pdrType, record, 304 nullptr, nullptr); 305 if (record && pldm_pdr_record_is_remote(record)) 306 { 307 changeEntries[0].push_back( 308 pldm_pdr_get_record_handle(repo, record)); 309 } 310 } while (record); 311 } 312 if (changeEntries.empty()) 313 { 314 return; 315 } 316 numsOfChangeEntries[0] = changeEntries[0].size(); 317 318 // Encode PLDM platform event msg to indicate a PDR repo change. 319 size_t maxSize = PLDM_PDR_REPOSITORY_CHG_EVENT_MIN_LENGTH + 320 PLDM_PDR_REPOSITORY_CHANGE_RECORD_MIN_LENGTH + 321 changeEntries[0].size() * sizeof(uint32_t); 322 std::vector<uint8_t> eventDataVec{}; 323 eventDataVec.resize(maxSize); 324 auto eventData = 325 reinterpret_cast<struct pldm_pdr_repository_chg_event_data*>( 326 eventDataVec.data()); 327 size_t actualSize{}; 328 auto firstEntry = changeEntries[0].data(); 329 auto rc = encode_pldm_pdr_repository_chg_event_data( 330 eventDataFormat, 1, eventDataOps.data(), numsOfChangeEntries.data(), 331 &firstEntry, eventData, &actualSize, maxSize); 332 if (rc != PLDM_SUCCESS) 333 { 334 error("Failed to encode_pldm_pdr_repository_chg_event_data, rc = {RC}", 335 "RC", rc); 336 return; 337 } 338 auto instanceId = instanceIdDb.next(mctp_eid); 339 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) + 340 PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES + 341 actualSize); 342 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 343 rc = encode_platform_event_message_req( 344 instanceId, 1, TERMINUS_ID, PLDM_PDR_REPOSITORY_CHG_EVENT, 345 eventDataVec.data(), actualSize, request, 346 actualSize + PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES); 347 if (rc != PLDM_SUCCESS) 348 { 349 instanceIdDb.free(mctp_eid, instanceId); 350 error("Failed to encode_platform_event_message_req, rc = {RC}", "RC", 351 rc); 352 return; 353 } 354 355 auto platformEventMessageResponseHandler = 356 [](mctp_eid_t /*eid*/, const pldm_msg* response, size_t respMsgLen) { 357 if (response == nullptr || !respMsgLen) 358 { 359 error( 360 "Failed to receive response for the PDR repository changed event"); 361 return; 362 } 363 364 uint8_t completionCode{}; 365 uint8_t status{}; 366 auto responsePtr = reinterpret_cast<const struct pldm_msg*>(response); 367 auto rc = decode_platform_event_message_resp(responsePtr, respMsgLen, 368 &completionCode, &status); 369 if (rc || completionCode) 370 { 371 error( 372 "Failed to decode_platform_event_message_resp: {RC}, cc = {CC}", 373 "RC", rc, "CC", static_cast<unsigned>(completionCode)); 374 } 375 }; 376 377 rc = handler->registerRequest( 378 mctp_eid, instanceId, PLDM_PLATFORM, PLDM_PLATFORM_EVENT_MESSAGE, 379 std::move(requestMsg), std::move(platformEventMessageResponseHandler)); 380 if (rc) 381 { 382 error("Failed to send the PDR repository changed event request"); 383 } 384 } 385 386 void HostPDRHandler::parseStateSensorPDRs(const PDRList& stateSensorPDRs) 387 { 388 for (const auto& pdr : stateSensorPDRs) 389 { 390 SensorEntry sensorEntry{}; 391 const auto& [terminusHandle, sensorID, sensorInfo] = 392 responder::pdr_utils::parseStateSensorPDR(pdr); 393 sensorEntry.sensorID = sensorID; 394 try 395 { 396 sensorEntry.terminusID = std::get<0>(tlPDRInfo.at(terminusHandle)); 397 } 398 // If there is no mapping for terminusHandle assign the reserved TID 399 // value of 0xFF to indicate that. 400 catch (const std::out_of_range& e) 401 { 402 sensorEntry.terminusID = PLDM_TID_RESERVED; 403 } 404 sensorMap.emplace(sensorEntry, std::move(sensorInfo)); 405 } 406 } 407 408 void HostPDRHandler::processHostPDRs(mctp_eid_t /*eid*/, 409 const pldm_msg* response, 410 size_t respMsgLen) 411 { 412 static bool merged = false; 413 static PDRList stateSensorPDRs{}; 414 static PDRList fruRecordSetPDRs{}; 415 uint32_t nextRecordHandle{}; 416 uint8_t tlEid = 0; 417 bool tlValid = true; 418 uint32_t rh = 0; 419 uint16_t terminusHandle = 0; 420 uint16_t pdrTerminusHandle = 0; 421 uint8_t tid = 0; 422 423 uint8_t completionCode{}; 424 uint32_t nextDataTransferHandle{}; 425 uint8_t transferFlag{}; 426 uint16_t respCount{}; 427 uint8_t transferCRC{}; 428 if (response == nullptr || !respMsgLen) 429 { 430 error("Failed to receive response for the GetPDR command"); 431 return; 432 } 433 434 auto rc = decode_get_pdr_resp( 435 response, respMsgLen /*- sizeof(pldm_msg_hdr)*/, &completionCode, 436 &nextRecordHandle, &nextDataTransferHandle, &transferFlag, &respCount, 437 nullptr, 0, &transferCRC); 438 std::vector<uint8_t> responsePDRMsg; 439 responsePDRMsg.resize(respMsgLen + sizeof(pldm_msg_hdr)); 440 memcpy(responsePDRMsg.data(), response, respMsgLen + sizeof(pldm_msg_hdr)); 441 if (rc != PLDM_SUCCESS) 442 { 443 error("Failed to decode_get_pdr_resp, rc = {RC}", "RC", rc); 444 return; 445 } 446 else 447 { 448 std::vector<uint8_t> pdr(respCount, 0); 449 rc = decode_get_pdr_resp(response, respMsgLen, &completionCode, 450 &nextRecordHandle, &nextDataTransferHandle, 451 &transferFlag, &respCount, pdr.data(), 452 respCount, &transferCRC); 453 if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS) 454 { 455 error("Failed to decode_get_pdr_resp: rc = {RC}, cc = {CC}", "RC", 456 rc, "CC", static_cast<unsigned>(completionCode)); 457 return; 458 } 459 else 460 { 461 // when nextRecordHandle is 0, we need the recordHandle of the last 462 // PDR and not 0-1. 463 if (!nextRecordHandle) 464 { 465 rh = nextRecordHandle; 466 } 467 else 468 { 469 rh = nextRecordHandle - 1; 470 } 471 472 auto pdrHdr = reinterpret_cast<pldm_pdr_hdr*>(pdr.data()); 473 if (!rh) 474 { 475 rh = pdrHdr->record_handle; 476 } 477 478 if (pdrHdr->type == PLDM_PDR_ENTITY_ASSOCIATION) 479 { 480 this->mergeEntityAssociations(pdr); 481 merged = true; 482 } 483 else 484 { 485 if (pdrHdr->type == PLDM_TERMINUS_LOCATOR_PDR) 486 { 487 pdrTerminusHandle = 488 extractTerminusHandle<pldm_terminus_locator_pdr>(pdr); 489 auto tlpdr = 490 reinterpret_cast<const pldm_terminus_locator_pdr*>( 491 pdr.data()); 492 493 terminusHandle = tlpdr->terminus_handle; 494 tid = tlpdr->tid; 495 auto terminus_locator_type = tlpdr->terminus_locator_type; 496 if (terminus_locator_type == 497 PLDM_TERMINUS_LOCATOR_TYPE_MCTP_EID) 498 { 499 auto locatorValue = reinterpret_cast< 500 const pldm_terminus_locator_type_mctp_eid*>( 501 tlpdr->terminus_locator_value); 502 tlEid = static_cast<uint8_t>(locatorValue->eid); 503 } 504 if (tlpdr->validity == 0) 505 { 506 tlValid = false; 507 } 508 for (const auto& terminusMap : tlPDRInfo) 509 { 510 if ((terminusHandle == (terminusMap.first)) && 511 (get<1>(terminusMap.second) == tlEid) && 512 (get<2>(terminusMap.second) == tlpdr->validity)) 513 { 514 // TL PDR already present with same validity don't 515 // add the PDR to the repo just return 516 return; 517 } 518 } 519 tlPDRInfo.insert_or_assign( 520 tlpdr->terminus_handle, 521 std::make_tuple(tlpdr->tid, tlEid, tlpdr->validity)); 522 } 523 else if (pdrHdr->type == PLDM_STATE_SENSOR_PDR) 524 { 525 pdrTerminusHandle = 526 extractTerminusHandle<pldm_state_sensor_pdr>(pdr); 527 stateSensorPDRs.emplace_back(pdr); 528 } 529 else if (pdrHdr->type == PLDM_PDR_FRU_RECORD_SET) 530 { 531 pdrTerminusHandle = 532 extractTerminusHandle<pldm_pdr_fru_record_set>(pdr); 533 fruRecordSetPDRs.emplace_back(pdr); 534 } 535 else if (pdrHdr->type == PLDM_STATE_EFFECTER_PDR) 536 { 537 pdrTerminusHandle = 538 extractTerminusHandle<pldm_state_effecter_pdr>(pdr); 539 } 540 else if (pdrHdr->type == PLDM_NUMERIC_EFFECTER_PDR) 541 { 542 pdrTerminusHandle = 543 extractTerminusHandle<pldm_numeric_effecter_value_pdr>( 544 pdr); 545 } 546 // if the TLPDR is invalid update the repo accordingly 547 if (!tlValid) 548 { 549 pldm_pdr_update_TL_pdr(repo, terminusHandle, tid, tlEid, 550 tlValid); 551 } 552 else 553 { 554 rc = pldm_pdr_add_check(repo, pdr.data(), respCount, true, 555 pdrTerminusHandle, &rh); 556 if (rc) 557 { 558 // pldm_pdr_add() assert()ed on failure to add a PDR. 559 throw std::runtime_error("Failed to add PDR"); 560 } 561 } 562 } 563 } 564 } 565 if (!nextRecordHandle) 566 { 567 updateEntityAssociation(entityAssociations, entityTree, objPathMap); 568 569 /*received last record*/ 570 this->parseStateSensorPDRs(stateSensorPDRs); 571 this->createDbusObjects(fruRecordSetPDRs); 572 if (isHostUp()) 573 { 574 this->setHostSensorState(stateSensorPDRs); 575 } 576 stateSensorPDRs.clear(); 577 fruRecordSetPDRs.clear(); 578 entityAssociations.clear(); 579 580 if (merged) 581 { 582 merged = false; 583 deferredPDRRepoChgEvent = 584 std::make_unique<sdeventplus::source::Defer>( 585 event, 586 std::bind( 587 std::mem_fn((&HostPDRHandler::_processPDRRepoChgEvent)), 588 this, std::placeholders::_1)); 589 } 590 } 591 else 592 { 593 if (modifiedPDRRecordHandles.empty() && isHostPdrModified) 594 { 595 isHostPdrModified = false; 596 } 597 else 598 { 599 deferredFetchPDREvent = 600 std::make_unique<sdeventplus::source::Defer>( 601 event, 602 std::bind( 603 std::mem_fn((&HostPDRHandler::_processFetchPDREvent)), 604 this, nextRecordHandle, std::placeholders::_1)); 605 } 606 } 607 } 608 609 void HostPDRHandler::_processPDRRepoChgEvent( 610 sdeventplus::source::EventBase& /*source */) 611 { 612 deferredPDRRepoChgEvent.reset(); 613 this->sendPDRRepositoryChgEvent( 614 std::move(std::vector<uint8_t>(1, PLDM_PDR_ENTITY_ASSOCIATION)), 615 FORMAT_IS_PDR_HANDLES); 616 } 617 618 void HostPDRHandler::_processFetchPDREvent( 619 uint32_t nextRecordHandle, sdeventplus::source::EventBase& /*source */) 620 { 621 deferredFetchPDREvent.reset(); 622 if (!this->pdrRecordHandles.empty()) 623 { 624 nextRecordHandle = this->pdrRecordHandles.front(); 625 this->pdrRecordHandles.pop_front(); 626 } 627 if (isHostPdrModified && (!this->modifiedPDRRecordHandles.empty())) 628 { 629 nextRecordHandle = this->modifiedPDRRecordHandles.front(); 630 this->modifiedPDRRecordHandles.pop_front(); 631 } 632 this->getHostPDR(nextRecordHandle); 633 } 634 635 void HostPDRHandler::setHostFirmwareCondition() 636 { 637 responseReceived = false; 638 auto instanceId = instanceIdDb.next(mctp_eid); 639 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) + 640 PLDM_GET_VERSION_REQ_BYTES); 641 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 642 auto rc = encode_get_version_req(instanceId, 0, PLDM_GET_FIRSTPART, 643 PLDM_BASE, request); 644 if (rc != PLDM_SUCCESS) 645 { 646 error("GetPLDMVersion encode failure. PLDM error code = {RC}", "RC", 647 lg2::hex, rc); 648 instanceIdDb.free(mctp_eid, instanceId); 649 return; 650 } 651 652 auto getPLDMVersionHandler = [this](mctp_eid_t /*eid*/, 653 const pldm_msg* response, 654 size_t respMsgLen) { 655 if (response == nullptr || !respMsgLen) 656 { 657 error( 658 "Failed to receive response for getPLDMVersion command, Host seems to be off"); 659 return; 660 } 661 info("Getting the response. PLDM RC = {RC}", "RC", lg2::hex, 662 static_cast<uint16_t>(response->payload[0])); 663 this->responseReceived = true; 664 getHostPDR(); 665 }; 666 rc = handler->registerRequest(mctp_eid, instanceId, PLDM_BASE, 667 PLDM_GET_PLDM_VERSION, std::move(requestMsg), 668 std::move(getPLDMVersionHandler)); 669 if (rc) 670 { 671 error("Failed to discover Host state. Assuming Host as off"); 672 } 673 } 674 675 bool HostPDRHandler::isHostUp() 676 { 677 return responseReceived; 678 } 679 680 void HostPDRHandler::setHostSensorState(const PDRList& stateSensorPDRs) 681 { 682 for (const auto& stateSensorPDR : stateSensorPDRs) 683 { 684 auto pdr = reinterpret_cast<const pldm_state_sensor_pdr*>( 685 stateSensorPDR.data()); 686 687 if (!pdr) 688 { 689 error("Failed to get State sensor PDR"); 690 pldm::utils::reportError( 691 "xyz.openbmc_project.bmc.pldm.InternalFailure"); 692 return; 693 } 694 695 uint16_t sensorId = pdr->sensor_id; 696 697 for (const auto& [terminusHandle, terminusInfo] : tlPDRInfo) 698 { 699 if (terminusHandle == pdr->terminus_handle) 700 { 701 if (std::get<2>(terminusInfo) == PLDM_TL_PDR_VALID) 702 { 703 mctp_eid = std::get<1>(terminusInfo); 704 } 705 706 bitfield8_t sensorRearm; 707 sensorRearm.byte = 0; 708 uint8_t tid = std::get<0>(terminusInfo); 709 710 auto instanceId = instanceIdDb.next(mctp_eid); 711 std::vector<uint8_t> requestMsg( 712 sizeof(pldm_msg_hdr) + 713 PLDM_GET_STATE_SENSOR_READINGS_REQ_BYTES); 714 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 715 auto rc = encode_get_state_sensor_readings_req( 716 instanceId, sensorId, sensorRearm, 0, request); 717 718 if (rc != PLDM_SUCCESS) 719 { 720 instanceIdDb.free(mctp_eid, instanceId); 721 error( 722 "Failed to encode_get_state_sensor_readings_req, rc = {RC}", 723 "RC", rc); 724 pldm::utils::reportError( 725 "xyz.openbmc_project.bmc.pldm.InternalFailure"); 726 return; 727 } 728 729 auto getStateSensorReadingRespHandler = 730 [=, this](mctp_eid_t /*eid*/, const pldm_msg* response, 731 size_t respMsgLen) { 732 if (response == nullptr || !respMsgLen) 733 { 734 error( 735 "Failed to receive response for getStateSensorReading command"); 736 return; 737 } 738 std::array<get_sensor_state_field, 8> stateField{}; 739 uint8_t completionCode = 0; 740 uint8_t comp_sensor_count = 0; 741 742 auto rc = decode_get_state_sensor_readings_resp( 743 response, respMsgLen, &completionCode, 744 &comp_sensor_count, stateField.data()); 745 746 if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS) 747 { 748 error( 749 "Failed to decode_get_state_sensor_readings_resp, rc = {RC} cc = {CC}", 750 "RC", rc, "CC", 751 static_cast<unsigned>(completionCode)); 752 pldm::utils::reportError( 753 "xyz.openbmc_project.bmc.pldm.InternalFailure"); 754 } 755 756 uint8_t eventState; 757 uint8_t previousEventState; 758 759 for (uint8_t sensorOffset = 0; 760 sensorOffset < comp_sensor_count; sensorOffset++) 761 { 762 eventState = stateField[sensorOffset].present_state; 763 previousEventState = 764 stateField[sensorOffset].previous_state; 765 766 emitStateSensorEventSignal(tid, sensorId, sensorOffset, 767 eventState, 768 previousEventState); 769 770 SensorEntry sensorEntry{tid, sensorId}; 771 772 pldm::pdr::EntityInfo entityInfo{}; 773 pldm::pdr::CompositeSensorStates 774 compositeSensorStates{}; 775 776 try 777 { 778 std::tie(entityInfo, compositeSensorStates) = 779 lookupSensorInfo(sensorEntry); 780 } 781 catch (const std::out_of_range& e) 782 { 783 try 784 { 785 sensorEntry.terminusID = PLDM_TID_RESERVED; 786 std::tie(entityInfo, compositeSensorStates) = 787 lookupSensorInfo(sensorEntry); 788 } 789 catch (const std::out_of_range& e) 790 { 791 error("No mapping for the events"); 792 } 793 } 794 795 if (sensorOffset > compositeSensorStates.size()) 796 { 797 error("Error Invalid data, Invalid sensor offset"); 798 return; 799 } 800 801 const auto& possibleStates = 802 compositeSensorStates[sensorOffset]; 803 if (possibleStates.find(eventState) == 804 possibleStates.end()) 805 { 806 error("Error invalid_data, Invalid event state"); 807 return; 808 } 809 const auto& [containerId, entityType, 810 entityInstance] = entityInfo; 811 pldm::responder::events::StateSensorEntry 812 stateSensorEntry{containerId, entityType, 813 entityInstance, sensorOffset}; 814 handleStateSensorEvent(stateSensorEntry, eventState); 815 } 816 }; 817 818 rc = handler->registerRequest( 819 mctp_eid, instanceId, PLDM_PLATFORM, 820 PLDM_GET_STATE_SENSOR_READINGS, std::move(requestMsg), 821 std::move(getStateSensorReadingRespHandler)); 822 823 if (rc != PLDM_SUCCESS) 824 { 825 error( 826 "Failed to send request to get State sensor reading on Host"); 827 } 828 } 829 } 830 } 831 } 832 833 void HostPDRHandler::getFRURecordTableMetadataByRemote( 834 const PDRList& fruRecordSetPDRs) 835 { 836 auto instanceId = instanceIdDb.next(mctp_eid); 837 std::vector<uint8_t> requestMsg( 838 sizeof(pldm_msg_hdr) + PLDM_GET_FRU_RECORD_TABLE_METADATA_REQ_BYTES); 839 840 // GetFruRecordTableMetadata 841 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 842 auto rc = encode_get_fru_record_table_metadata_req( 843 instanceId, request, requestMsg.size() - sizeof(pldm_msg_hdr)); 844 if (rc != PLDM_SUCCESS) 845 { 846 instanceIdDb.free(mctp_eid, instanceId); 847 lg2::error( 848 "Failed to encode_get_fru_record_table_metadata_req, rc = {RC}", 849 "RC", lg2::hex, rc); 850 return; 851 } 852 853 auto getFruRecordTableMetadataResponseHandler = 854 [this, fruRecordSetPDRs](mctp_eid_t /*eid*/, const pldm_msg* response, 855 size_t respMsgLen) { 856 if (response == nullptr || !respMsgLen) 857 { 858 lg2::error( 859 "Failed to receive response for the Get FRU Record Table Metadata"); 860 return; 861 } 862 863 uint8_t cc = 0; 864 uint8_t fru_data_major_version, fru_data_minor_version; 865 uint32_t fru_table_maximum_size, fru_table_length; 866 uint16_t total_record_set_identifiers; 867 uint16_t total; 868 uint32_t checksum; 869 870 auto rc = decode_get_fru_record_table_metadata_resp( 871 response, respMsgLen, &cc, &fru_data_major_version, 872 &fru_data_minor_version, &fru_table_maximum_size, &fru_table_length, 873 &total_record_set_identifiers, &total, &checksum); 874 875 if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS) 876 { 877 lg2::error( 878 "Faile to decode get fru record table metadata resp, Message Error: {RC}, cc: {CC}", 879 "RC", lg2::hex, rc, "CC", cc); 880 return; 881 } 882 883 // pass total to getFRURecordTableByRemote 884 this->getFRURecordTableByRemote(fruRecordSetPDRs, total); 885 }; 886 887 rc = handler->registerRequest( 888 mctp_eid, instanceId, PLDM_FRU, PLDM_GET_FRU_RECORD_TABLE_METADATA, 889 std::move(requestMsg), 890 std::move(getFruRecordTableMetadataResponseHandler)); 891 if (rc != PLDM_SUCCESS) 892 { 893 lg2::error("Failed to send the the Set State Effecter States request"); 894 } 895 896 return; 897 } 898 899 void HostPDRHandler::getFRURecordTableByRemote(const PDRList& fruRecordSetPDRs, 900 uint16_t totalTableRecords) 901 { 902 fruRecordData.clear(); 903 904 if (!totalTableRecords) 905 { 906 lg2::error("Failed to get fru record table"); 907 return; 908 } 909 910 auto instanceId = instanceIdDb.next(mctp_eid); 911 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) + 912 PLDM_GET_FRU_RECORD_TABLE_REQ_BYTES); 913 914 // send the getFruRecordTable command 915 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 916 auto rc = encode_get_fru_record_table_req( 917 instanceId, 0, PLDM_GET_FIRSTPART, request, 918 requestMsg.size() - sizeof(pldm_msg_hdr)); 919 if (rc != PLDM_SUCCESS) 920 { 921 instanceIdDb.free(mctp_eid, instanceId); 922 lg2::error("Failed to encode_get_fru_record_table_req, rc = {RC}", "RC", 923 lg2::hex, rc); 924 return; 925 } 926 927 auto getFruRecordTableResponseHandler = 928 [totalTableRecords, this, fruRecordSetPDRs]( 929 mctp_eid_t /*eid*/, const pldm_msg* response, size_t respMsgLen) { 930 if (response == nullptr || !respMsgLen) 931 { 932 lg2::error( 933 "Failed to receive response for the Get FRU Record Table"); 934 return; 935 } 936 937 uint8_t cc = 0; 938 uint32_t next_data_transfer_handle = 0; 939 uint8_t transfer_flag = 0; 940 size_t fru_record_table_length = 0; 941 std::vector<uint8_t> fru_record_table_data(respMsgLen - 942 sizeof(pldm_msg_hdr)); 943 auto responsePtr = reinterpret_cast<const struct pldm_msg*>(response); 944 auto rc = decode_get_fru_record_table_resp( 945 responsePtr, respMsgLen - sizeof(pldm_msg_hdr), &cc, 946 &next_data_transfer_handle, &transfer_flag, 947 fru_record_table_data.data(), &fru_record_table_length); 948 949 if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS) 950 { 951 lg2::error( 952 "Failed to decode get fru record table resp, Message Error: {RC}, cc: {CC}", 953 "RC", lg2::hex, rc, "CC", cc); 954 return; 955 } 956 957 fruRecordData = responder::pdr_utils::parseFruRecordTable( 958 fru_record_table_data.data(), fru_record_table_length); 959 960 if (totalTableRecords != fruRecordData.size()) 961 { 962 fruRecordData.clear(); 963 964 lg2::error("failed to parse fru recrod data format."); 965 return; 966 } 967 968 this->setFRUDataOnDBus(fruRecordSetPDRs, fruRecordData); 969 }; 970 971 rc = handler->registerRequest( 972 mctp_eid, instanceId, PLDM_FRU, PLDM_GET_FRU_RECORD_TABLE, 973 std::move(requestMsg), std::move(getFruRecordTableResponseHandler)); 974 if (rc != PLDM_SUCCESS) 975 { 976 lg2::error("Failed to send the the Set State Effecter States request"); 977 } 978 } 979 980 std::optional<uint16_t> HostPDRHandler::getRSI(const PDRList& fruRecordSetPDRs, 981 const pldm_entity& entity) 982 { 983 for (const auto& pdr : fruRecordSetPDRs) 984 { 985 auto fruPdr = reinterpret_cast<const pldm_pdr_fru_record_set*>( 986 const_cast<uint8_t*>(pdr.data()) + sizeof(pldm_pdr_hdr)); 987 988 if (fruPdr->entity_type == entity.entity_type && 989 fruPdr->entity_instance == entity.entity_instance_num && 990 fruPdr->container_id == entity.entity_container_id) 991 { 992 return fruPdr->fru_rsi; 993 } 994 } 995 996 return std::nullopt; 997 } 998 999 void HostPDRHandler::setFRUDataOnDBus( 1000 [[maybe_unused]] const PDRList& fruRecordSetPDRs, 1001 [[maybe_unused]] const std::vector< 1002 responder::pdr_utils::FruRecordDataFormat>& fruRecordData) 1003 { 1004 #ifdef OEM_IBM 1005 for (const auto& entity : objPathMap) 1006 { 1007 pldm_entity node = pldm_entity_extract(entity.second); 1008 auto fruRSI = getRSI(fruRecordSetPDRs, node); 1009 1010 for (const auto& data : fruRecordData) 1011 { 1012 if (!fruRSI || *fruRSI != data.fruRSI) 1013 { 1014 continue; 1015 } 1016 1017 if (data.fruRecType == PLDM_FRU_RECORD_TYPE_OEM) 1018 { 1019 for (const auto& tlv : data.fruTLV) 1020 { 1021 if (tlv.fruFieldType == 1022 PLDM_OEM_FRU_FIELD_TYPE_LOCATION_CODE) 1023 { 1024 CustomDBus::getCustomDBus().setLocationCode( 1025 entity.first, 1026 std::string(reinterpret_cast<const char*>( 1027 tlv.fruFieldValue.data()), 1028 tlv.fruFieldLen)); 1029 } 1030 } 1031 } 1032 } 1033 } 1034 #endif 1035 } 1036 void HostPDRHandler::createDbusObjects(const PDRList& fruRecordSetPDRs) 1037 { 1038 // TODO: Creating and Refreshing dbus hosted by remote PLDM entity Fru PDRs 1039 1040 getFRURecordTableMetadataByRemote(fruRecordSetPDRs); 1041 } 1042 1043 } // namespace pldm 1044