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