1 #include "host_pdr_handler.hpp" 2 3 #include <libpldm/fru.h> 4 #ifdef OEM_IBM 5 #include <libpldm/oem/ibm/fru.h> 6 #endif 7 #include "custom_dbus.hpp" 8 9 #include <assert.h> 10 11 #include <nlohmann/json.hpp> 12 #include <phosphor-logging/lg2.hpp> 13 #include <sdeventplus/clock.hpp> 14 #include <sdeventplus/exception.hpp> 15 #include <sdeventplus/source/io.hpp> 16 #include <sdeventplus/source/time.hpp> 17 18 #include <fstream> 19 #include <type_traits> 20 21 PHOSPHOR_LOG2_USING; 22 23 namespace pldm 24 { 25 using namespace pldm::responder::events; 26 using namespace pldm::utils; 27 using namespace sdbusplus::bus::match::rules; 28 using namespace pldm::responder::pdr_utils; 29 using 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 pldm::responder::oem_platform::Handler* oemPlatformHandler) : 95 mctp_fd(mctp_fd), 96 mctp_eid(mctp_eid), event(event), repo(repo), 97 stateSensorHandler(eventsJsonsDir), entityTree(entityTree), 98 bmcEntityTree(bmcEntityTree), instanceIdDb(instanceIdDb), handler(handler), 99 oemPlatformHandler(oemPlatformHandler), 100 entityMaps(parseEntityMap(ENTITY_MAP_JSON)) 101 { 102 mergedHostParents = false; 103 hostOffMatch = std::make_unique<sdbusplus::bus::match_t>( 104 pldm::utils::DBusHandler::getBus(), 105 propertiesChanged("/xyz/openbmc_project/state/host0", 106 "xyz.openbmc_project.State.Host"), 107 [this, repo, entityTree, bmcEntityTree](sdbusplus::message_t& msg) { 108 DbusChangedProps props{}; 109 std::string intf; 110 msg.read(intf, props); 111 const auto itr = props.find("CurrentHostState"); 112 if (itr != props.end()) 113 { 114 PropertyValue value = itr->second; 115 auto propVal = std::get<std::string>(value); 116 if (propVal == "xyz.openbmc_project.State.Host.HostState.Off") 117 { 118 // Delete all the remote terminus information 119 std::erase_if(tlPDRInfo, [](const auto& item) { 120 auto const& [key, value] = item; 121 return key != TERMINUS_HANDLE; 122 }); 123 pldm_pdr_remove_remote_pdrs(repo); 124 pldm_entity_association_tree_destroy_root(entityTree); 125 pldm_entity_association_tree_copy_root(bmcEntityTree, 126 entityTree); 127 this->sensorMap.clear(); 128 this->responseReceived = false; 129 this->mergedHostParents = false; 130 } 131 } 132 }); 133 } 134 135 void HostPDRHandler::fetchPDR(PDRRecordHandles&& recordHandles) 136 { 137 pdrRecordHandles.clear(); 138 modifiedPDRRecordHandles.clear(); 139 140 if (isHostPdrModified) 141 { 142 modifiedPDRRecordHandles = std::move(recordHandles); 143 } 144 else 145 { 146 pdrRecordHandles = std::move(recordHandles); 147 } 148 149 // Defer the actual fetch of PDRs from the host (by queuing the call on the 150 // main event loop). That way, we can respond to the platform event msg from 151 // the host firmware. 152 pdrFetchEvent = std::make_unique<sdeventplus::source::Defer>( 153 event, std::bind(std::mem_fn(&HostPDRHandler::_fetchPDR), this, 154 std::placeholders::_1)); 155 } 156 157 void HostPDRHandler::_fetchPDR(sdeventplus::source::EventBase& /*source*/) 158 { 159 getHostPDR(); 160 } 161 162 void HostPDRHandler::getHostPDR(uint32_t nextRecordHandle) 163 { 164 pdrFetchEvent.reset(); 165 166 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) + 167 PLDM_GET_PDR_REQ_BYTES); 168 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 169 uint32_t recordHandle{}; 170 if (!nextRecordHandle && (!modifiedPDRRecordHandles.empty()) && 171 isHostPdrModified) 172 { 173 recordHandle = modifiedPDRRecordHandles.front(); 174 modifiedPDRRecordHandles.pop_front(); 175 } 176 else if (!nextRecordHandle && (!pdrRecordHandles.empty())) 177 { 178 recordHandle = pdrRecordHandles.front(); 179 pdrRecordHandles.pop_front(); 180 } 181 else 182 { 183 recordHandle = nextRecordHandle; 184 } 185 auto instanceId = instanceIdDb.next(mctp_eid); 186 187 auto rc = encode_get_pdr_req(instanceId, recordHandle, 0, 188 PLDM_GET_FIRSTPART, UINT16_MAX, 0, request, 189 PLDM_GET_PDR_REQ_BYTES); 190 if (rc != PLDM_SUCCESS) 191 { 192 instanceIdDb.free(mctp_eid, instanceId); 193 error("Failed to encode get pdr request, response code '{RC}'", "RC", 194 rc); 195 return; 196 } 197 198 rc = handler->registerRequest( 199 mctp_eid, instanceId, PLDM_PLATFORM, PLDM_GET_PDR, 200 std::move(requestMsg), 201 std::move(std::bind_front(&HostPDRHandler::processHostPDRs, this))); 202 if (rc) 203 { 204 error( 205 "Failed to send the getPDR request to remote terminus, response code '{RC}'", 206 "RC", rc); 207 } 208 } 209 210 int HostPDRHandler::handleStateSensorEvent(const StateSensorEntry& entry, 211 pdr::EventState state) 212 { 213 auto rc = stateSensorHandler.eventAction(entry, state); 214 if (rc != PLDM_SUCCESS) 215 { 216 error("Failed to fetch and update D-bus property, response code '{RC}'", 217 "RC", rc); 218 return rc; 219 } 220 return PLDM_SUCCESS; 221 } 222 223 void HostPDRHandler::mergeEntityAssociations( 224 const std::vector<uint8_t>& pdr, [[maybe_unused]] const uint32_t& size, 225 [[maybe_unused]] const uint32_t& record_handle) 226 { 227 size_t numEntities{}; 228 pldm_entity* entities = nullptr; 229 bool merged = false; 230 auto entityPdr = reinterpret_cast<pldm_pdr_entity_association*>( 231 const_cast<uint8_t*>(pdr.data()) + sizeof(pldm_pdr_hdr)); 232 233 if (oemPlatformHandler && 234 oemPlatformHandler->checkRecordHandleInRange(record_handle)) 235 { 236 // Adding the remote range PDRs to the repo before merging it 237 uint32_t handle = record_handle; 238 pldm_pdr_add_check(repo, pdr.data(), size, true, 0xFFFF, &handle); 239 } 240 241 pldm_entity_association_pdr_extract(pdr.data(), pdr.size(), &numEntities, 242 &entities); 243 if (numEntities > 0) 244 { 245 pldm_entity_node* pNode = nullptr; 246 if (!mergedHostParents) 247 { 248 pNode = pldm_entity_association_tree_find_with_locality( 249 entityTree, &entities[0], false); 250 } 251 else 252 { 253 pNode = pldm_entity_association_tree_find_with_locality( 254 entityTree, &entities[0], true); 255 } 256 if (!pNode) 257 { 258 return; 259 } 260 261 Entities entityAssoc; 262 entityAssoc.push_back(pNode); 263 for (size_t i = 1; i < numEntities; ++i) 264 { 265 bool isUpdateContainerId = true; 266 if (oemPlatformHandler) 267 { 268 isUpdateContainerId = 269 checkIfLogicalBitSet(entities[i].entity_container_id); 270 } 271 auto node = pldm_entity_association_tree_add_entity( 272 entityTree, &entities[i], entities[i].entity_instance_num, 273 pNode, entityPdr->association_type, true, isUpdateContainerId, 274 0xFFFF); 275 if (!node) 276 { 277 continue; 278 } 279 merged = true; 280 entityAssoc.push_back(node); 281 } 282 283 mergedHostParents = true; 284 if (merged) 285 { 286 entityAssociations.push_back(entityAssoc); 287 } 288 } 289 290 if (merged) 291 { 292 // Update our PDR repo with the merged entity association PDRs 293 pldm_entity_node* node = nullptr; 294 pldm_find_entity_ref_in_tree(entityTree, entities[0], &node); 295 if (node == nullptr) 296 { 297 error("Failed to find referrence of the entity in the tree"); 298 } 299 else 300 { 301 int rc = 0; 302 if (oemPlatformHandler) 303 { 304 auto record = oemPlatformHandler->fetchLastBMCRecord(repo); 305 306 uint32_t record_handle = pldm_pdr_get_record_handle(repo, 307 record); 308 309 rc = 310 pldm_entity_association_pdr_add_from_node_with_record_handle( 311 node, repo, &entities, numEntities, true, 312 TERMINUS_HANDLE, (record_handle + 1)); 313 } 314 else 315 { 316 rc = pldm_entity_association_pdr_add_from_node_check( 317 node, repo, &entities, numEntities, true, TERMINUS_HANDLE); 318 } 319 320 if (rc) 321 { 322 error( 323 "Failed to add entity association PDR from node, response code '{RC}'", 324 "RC", rc); 325 } 326 } 327 } 328 free(entities); 329 } 330 331 void HostPDRHandler::sendPDRRepositoryChgEvent(std::vector<uint8_t>&& pdrTypes, 332 uint8_t eventDataFormat) 333 { 334 assert(eventDataFormat == FORMAT_IS_PDR_HANDLES); 335 336 // Extract from the PDR repo record handles of PDRs we want the host 337 // to pull up. 338 std::vector<uint8_t> eventDataOps{PLDM_RECORDS_ADDED}; 339 std::vector<uint8_t> numsOfChangeEntries(1); 340 std::vector<std::vector<ChangeEntry>> changeEntries( 341 numsOfChangeEntries.size()); 342 for (auto pdrType : pdrTypes) 343 { 344 const pldm_pdr_record* record{}; 345 do 346 { 347 record = pldm_pdr_find_record_by_type(repo, pdrType, record, 348 nullptr, nullptr); 349 if (record && pldm_pdr_record_is_remote(record)) 350 { 351 changeEntries[0].push_back( 352 pldm_pdr_get_record_handle(repo, record)); 353 } 354 } while (record); 355 } 356 if (changeEntries.empty()) 357 { 358 return; 359 } 360 numsOfChangeEntries[0] = changeEntries[0].size(); 361 362 // Encode PLDM platform event msg to indicate a PDR repo change. 363 size_t maxSize = PLDM_PDR_REPOSITORY_CHG_EVENT_MIN_LENGTH + 364 PLDM_PDR_REPOSITORY_CHANGE_RECORD_MIN_LENGTH + 365 changeEntries[0].size() * sizeof(uint32_t); 366 std::vector<uint8_t> eventDataVec{}; 367 eventDataVec.resize(maxSize); 368 auto eventData = 369 reinterpret_cast<struct pldm_pdr_repository_chg_event_data*>( 370 eventDataVec.data()); 371 size_t actualSize{}; 372 auto firstEntry = changeEntries[0].data(); 373 auto rc = encode_pldm_pdr_repository_chg_event_data( 374 eventDataFormat, 1, eventDataOps.data(), numsOfChangeEntries.data(), 375 &firstEntry, eventData, &actualSize, maxSize); 376 if (rc != PLDM_SUCCESS) 377 { 378 error( 379 "Failed to encode pldm pdr repository change event data, response code '{RC}'", 380 "RC", rc); 381 return; 382 } 383 auto instanceId = instanceIdDb.next(mctp_eid); 384 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) + 385 PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES + 386 actualSize); 387 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 388 rc = encode_platform_event_message_req( 389 instanceId, 1, TERMINUS_ID, PLDM_PDR_REPOSITORY_CHG_EVENT, 390 eventDataVec.data(), actualSize, request, 391 actualSize + PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES); 392 if (rc != PLDM_SUCCESS) 393 { 394 instanceIdDb.free(mctp_eid, instanceId); 395 error( 396 "Failed to encode platform event message request, response code '{RC}'", 397 "RC", rc); 398 return; 399 } 400 401 auto platformEventMessageResponseHandler = 402 [](mctp_eid_t /*eid*/, const pldm_msg* response, size_t respMsgLen) { 403 if (response == nullptr || !respMsgLen) 404 { 405 error( 406 "Failed to receive response for the PDR repository changed event"); 407 return; 408 } 409 410 uint8_t completionCode{}; 411 uint8_t status{}; 412 auto responsePtr = reinterpret_cast<const struct pldm_msg*>(response); 413 auto rc = decode_platform_event_message_resp(responsePtr, respMsgLen, 414 &completionCode, &status); 415 if (rc || completionCode) 416 { 417 error( 418 "Failed to decode platform event message response, response code '{RC}' and completion code '{CC}'", 419 "RC", rc, "CC", completionCode); 420 } 421 }; 422 423 rc = handler->registerRequest( 424 mctp_eid, instanceId, PLDM_PLATFORM, PLDM_PLATFORM_EVENT_MESSAGE, 425 std::move(requestMsg), std::move(platformEventMessageResponseHandler)); 426 if (rc) 427 { 428 error( 429 "Failed to send the PDR repository changed event request, response code '{RC}'", 430 "RC", rc); 431 } 432 } 433 434 void HostPDRHandler::parseStateSensorPDRs(const PDRList& stateSensorPDRs) 435 { 436 for (const auto& pdr : stateSensorPDRs) 437 { 438 SensorEntry sensorEntry{}; 439 const auto& [terminusHandle, sensorID, sensorInfo] = 440 responder::pdr_utils::parseStateSensorPDR(pdr); 441 sensorEntry.sensorID = sensorID; 442 try 443 { 444 sensorEntry.terminusID = std::get<0>(tlPDRInfo.at(terminusHandle)); 445 } 446 // If there is no mapping for terminusHandle assign the reserved TID 447 // value of 0xFF to indicate that. 448 catch (const std::out_of_range&) 449 { 450 sensorEntry.terminusID = PLDM_TID_RESERVED; 451 } 452 sensorMap.emplace(sensorEntry, std::move(sensorInfo)); 453 } 454 } 455 456 void HostPDRHandler::processHostPDRs(mctp_eid_t /*eid*/, 457 const pldm_msg* response, 458 size_t respMsgLen) 459 { 460 static bool merged = false; 461 static PDRList stateSensorPDRs{}; 462 static PDRList fruRecordSetPDRs{}; 463 uint32_t nextRecordHandle{}; 464 uint8_t tlEid = 0; 465 bool tlValid = true; 466 uint32_t rh = 0; 467 uint16_t terminusHandle = 0; 468 uint16_t pdrTerminusHandle = 0; 469 uint8_t tid = 0; 470 471 uint8_t completionCode{}; 472 uint32_t nextDataTransferHandle{}; 473 uint8_t transferFlag{}; 474 uint16_t respCount{}; 475 uint8_t transferCRC{}; 476 if (response == nullptr || !respMsgLen) 477 { 478 error("Failed to receive response for the GetPDR command"); 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 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::move(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(sizeof(pldm_msg_hdr) + 707 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 static_cast<uint16_t>(response->payload[0])); 730 this->responseReceived = true; 731 getHostPDR(); 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 = 799 [=, this](mctp_eid_t /*eid*/, const pldm_msg* response, 800 size_t respMsgLen) { 801 if (response == nullptr || !respMsgLen) 802 { 803 error( 804 "Failed to receive response for get state sensor reading command for sensorID '{SENSOR_ID}' and instanceID '{INSTANCE}'", 805 "SENSOR_ID", sensorId, "INSTANCE", instanceId); 806 return; 807 } 808 std::array<get_sensor_state_field, 8> stateField{}; 809 uint8_t completionCode = 0; 810 uint8_t comp_sensor_count = 0; 811 812 auto rc = decode_get_state_sensor_readings_resp( 813 response, respMsgLen, &completionCode, 814 &comp_sensor_count, stateField.data()); 815 816 if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS) 817 { 818 error( 819 "Failed to decode get state sensor readings response for sensorID '{SENSOR_ID}' and instanceID '{INSTANCE}', response code'{RC}' and completion code '{CC}'", 820 "SENSOR_ID", sensorId, "INSTANCE", instanceId, "RC", 821 rc, "CC", completionCode); 822 pldm::utils::reportError( 823 "xyz.openbmc_project.bmc.pldm.InternalFailure"); 824 } 825 826 uint8_t eventState; 827 uint8_t previousEventState; 828 829 for (uint8_t sensorOffset = 0; 830 sensorOffset < comp_sensor_count; sensorOffset++) 831 { 832 eventState = stateField[sensorOffset].present_state; 833 previousEventState = 834 stateField[sensorOffset].previous_state; 835 836 emitStateSensorEventSignal(tid, sensorId, sensorOffset, 837 eventState, 838 previousEventState); 839 840 SensorEntry sensorEntry{tid, sensorId}; 841 842 pldm::pdr::EntityInfo entityInfo{}; 843 pldm::pdr::CompositeSensorStates 844 compositeSensorStates{}; 845 std::vector<pldm::pdr::StateSetId> stateSetIds{}; 846 847 try 848 { 849 std::tie(entityInfo, compositeSensorStates, 850 stateSetIds) = 851 lookupSensorInfo(sensorEntry); 852 } 853 catch (const std::out_of_range&) 854 { 855 try 856 { 857 sensorEntry.terminusID = PLDM_TID_RESERVED; 858 std::tie(entityInfo, compositeSensorStates, 859 stateSetIds) = 860 lookupSensorInfo(sensorEntry); 861 } 862 catch (const std::out_of_range&) 863 { 864 error("No mapping for the events"); 865 } 866 } 867 868 if ((compositeSensorStates.size() > 1) && 869 (sensorOffset > (compositeSensorStates.size() - 1))) 870 { 871 error( 872 "Error Invalid data, Invalid sensor offset '{SENSOR_OFFSET}'", 873 "SENSOR_OFFSET", sensorOffset); 874 return; 875 } 876 877 const auto& possibleStates = 878 compositeSensorStates[sensorOffset]; 879 if (possibleStates.find(eventState) == 880 possibleStates.end()) 881 { 882 error( 883 "Error invalid_data, Invalid event state '{STATE}'", 884 "STATE", eventState); 885 return; 886 } 887 const auto& [containerId, entityType, 888 entityInstance] = entityInfo; 889 auto stateSetId = stateSetIds[sensorOffset]; 890 pldm::responder::events::StateSensorEntry 891 stateSensorEntry{containerId, entityType, 892 entityInstance, sensorOffset, 893 stateSetId}; 894 handleStateSensorEvent(stateSensorEntry, eventState); 895 } 896 }; 897 898 rc = handler->registerRequest( 899 mctp_eid, instanceId, PLDM_PLATFORM, 900 PLDM_GET_STATE_SENSOR_READINGS, std::move(requestMsg), 901 std::move(getStateSensorReadingRespHandler)); 902 903 if (rc != PLDM_SUCCESS) 904 { 905 error( 906 "Failed to send request to get state sensor reading on remote terminus for sensorID '{SENSOR_ID}' and instanceID '{INSTANCE}', response code '{RC}'", 907 "SENSOR_ID", sensorId, "INSTANCE", instanceId, "RC", 908 rc); 909 } 910 } 911 } 912 } 913 } 914 915 void HostPDRHandler::getFRURecordTableMetadataByRemote( 916 const PDRList& fruRecordSetPDRs) 917 { 918 auto instanceId = instanceIdDb.next(mctp_eid); 919 std::vector<uint8_t> requestMsg( 920 sizeof(pldm_msg_hdr) + PLDM_GET_FRU_RECORD_TABLE_METADATA_REQ_BYTES); 921 922 // GetFruRecordTableMetadata 923 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 924 auto rc = encode_get_fru_record_table_metadata_req( 925 instanceId, request, requestMsg.size() - sizeof(pldm_msg_hdr)); 926 if (rc != PLDM_SUCCESS) 927 { 928 instanceIdDb.free(mctp_eid, instanceId); 929 error( 930 "Failed to encode get fru record table metadata request, response code '{RC}'", 931 "RC", lg2::hex, rc); 932 return; 933 } 934 935 auto getFruRecordTableMetadataResponseHandler = 936 [this, fruRecordSetPDRs](mctp_eid_t /*eid*/, const pldm_msg* response, 937 size_t respMsgLen) { 938 if (response == nullptr || !respMsgLen) 939 { 940 error( 941 "Failed to receive response for the get fru record table metadata"); 942 return; 943 } 944 945 uint8_t cc = 0; 946 uint8_t fru_data_major_version, fru_data_minor_version; 947 uint32_t fru_table_maximum_size, fru_table_length; 948 uint16_t total_record_set_identifiers; 949 uint16_t total; 950 uint32_t checksum; 951 952 auto rc = decode_get_fru_record_table_metadata_resp( 953 response, respMsgLen, &cc, &fru_data_major_version, 954 &fru_data_minor_version, &fru_table_maximum_size, &fru_table_length, 955 &total_record_set_identifiers, &total, &checksum); 956 957 if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS) 958 { 959 error( 960 "Failed to decode get fru record table metadata response, response code '{RC}' and completion code '{CC}'", 961 "RC", lg2::hex, rc, "CC", cc); 962 return; 963 } 964 965 // pass total to getFRURecordTableByRemote 966 this->getFRURecordTableByRemote(fruRecordSetPDRs, total); 967 }; 968 969 rc = handler->registerRequest( 970 mctp_eid, instanceId, PLDM_FRU, PLDM_GET_FRU_RECORD_TABLE_METADATA, 971 std::move(requestMsg), 972 std::move(getFruRecordTableMetadataResponseHandler)); 973 if (rc != PLDM_SUCCESS) 974 { 975 error( 976 "Failed to send the the set state effecter states request, response code '{RC}'", 977 "RC", rc); 978 } 979 980 return; 981 } 982 983 void HostPDRHandler::getFRURecordTableByRemote(const PDRList& fruRecordSetPDRs, 984 uint16_t totalTableRecords) 985 { 986 fruRecordData.clear(); 987 988 if (!totalTableRecords) 989 { 990 error("Failed to get fru record table"); 991 return; 992 } 993 994 auto instanceId = instanceIdDb.next(mctp_eid); 995 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) + 996 PLDM_GET_FRU_RECORD_TABLE_REQ_BYTES); 997 998 // send the getFruRecordTable command 999 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 1000 auto rc = encode_get_fru_record_table_req( 1001 instanceId, 0, PLDM_GET_FIRSTPART, request, 1002 requestMsg.size() - sizeof(pldm_msg_hdr)); 1003 if (rc != PLDM_SUCCESS) 1004 { 1005 instanceIdDb.free(mctp_eid, instanceId); 1006 error( 1007 "Failed to encode get fru record table request, response code '{RC}'", 1008 "RC", lg2::hex, rc); 1009 return; 1010 } 1011 1012 auto getFruRecordTableResponseHandler = 1013 [totalTableRecords, this, fruRecordSetPDRs]( 1014 mctp_eid_t /*eid*/, const pldm_msg* response, size_t respMsgLen) { 1015 if (response == nullptr || !respMsgLen) 1016 { 1017 error("Failed to receive response for the get fru record table"); 1018 return; 1019 } 1020 1021 uint8_t cc = 0; 1022 uint32_t next_data_transfer_handle = 0; 1023 uint8_t transfer_flag = 0; 1024 size_t fru_record_table_length = 0; 1025 std::vector<uint8_t> fru_record_table_data(respMsgLen - 1026 sizeof(pldm_msg_hdr)); 1027 auto responsePtr = reinterpret_cast<const struct pldm_msg*>(response); 1028 auto rc = decode_get_fru_record_table_resp( 1029 responsePtr, respMsgLen, &cc, &next_data_transfer_handle, 1030 &transfer_flag, fru_record_table_data.data(), 1031 &fru_record_table_length); 1032 1033 if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS) 1034 { 1035 error( 1036 "Failed to decode get fru record table resp, response code '{RC}' and completion code '{CC}'", 1037 "RC", lg2::hex, rc, "CC", cc); 1038 return; 1039 } 1040 1041 fruRecordData = responder::pdr_utils::parseFruRecordTable( 1042 fru_record_table_data.data(), fru_record_table_length); 1043 1044 if (totalTableRecords != fruRecordData.size()) 1045 { 1046 fruRecordData.clear(); 1047 1048 error("Failed to parse fru recrod data format."); 1049 return; 1050 } 1051 1052 this->setFRUDataOnDBus(fruRecordSetPDRs, fruRecordData); 1053 }; 1054 1055 rc = handler->registerRequest( 1056 mctp_eid, instanceId, PLDM_FRU, PLDM_GET_FRU_RECORD_TABLE, 1057 std::move(requestMsg), std::move(getFruRecordTableResponseHandler)); 1058 if (rc != PLDM_SUCCESS) 1059 { 1060 error("Failed to send the the set state effecter states request"); 1061 } 1062 } 1063 1064 std::optional<uint16_t> HostPDRHandler::getRSI(const PDRList& fruRecordSetPDRs, 1065 const pldm_entity& entity) 1066 { 1067 for (const auto& pdr : fruRecordSetPDRs) 1068 { 1069 auto fruPdr = reinterpret_cast<const pldm_pdr_fru_record_set*>( 1070 const_cast<uint8_t*>(pdr.data()) + sizeof(pldm_pdr_hdr)); 1071 1072 if (fruPdr->entity_type == entity.entity_type && 1073 fruPdr->entity_instance == entity.entity_instance_num && 1074 fruPdr->container_id == entity.entity_container_id) 1075 { 1076 return fruPdr->fru_rsi; 1077 } 1078 } 1079 1080 return std::nullopt; 1081 } 1082 1083 void HostPDRHandler::setFRUDataOnDBus( 1084 [[maybe_unused]] const PDRList& fruRecordSetPDRs, 1085 [[maybe_unused]] const std::vector< 1086 responder::pdr_utils::FruRecordDataFormat>& fruRecordData) 1087 { 1088 #ifdef OEM_IBM 1089 for (const auto& entity : objPathMap) 1090 { 1091 pldm_entity node = pldm_entity_extract(entity.second); 1092 auto fruRSI = getRSI(fruRecordSetPDRs, node); 1093 1094 for (const auto& data : fruRecordData) 1095 { 1096 if (!fruRSI || *fruRSI != data.fruRSI) 1097 { 1098 continue; 1099 } 1100 1101 if (data.fruRecType == PLDM_FRU_RECORD_TYPE_OEM) 1102 { 1103 for (const auto& tlv : data.fruTLV) 1104 { 1105 if (tlv.fruFieldType == 1106 PLDM_OEM_FRU_FIELD_TYPE_LOCATION_CODE) 1107 { 1108 CustomDBus::getCustomDBus().setLocationCode( 1109 entity.first, 1110 std::string(reinterpret_cast<const char*>( 1111 tlv.fruFieldValue.data()), 1112 tlv.fruFieldLen)); 1113 } 1114 } 1115 } 1116 } 1117 } 1118 #endif 1119 } 1120 void HostPDRHandler::createDbusObjects(const PDRList& fruRecordSetPDRs) 1121 { 1122 // TODO: Creating and Refreshing dbus hosted by remote PLDM entity Fru PDRs 1123 1124 getFRURecordTableMetadataByRemote(fruRecordSetPDRs); 1125 } 1126 1127 } // namespace pldm 1128