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