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