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