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