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