1 #include "oem_ibm_handler.hpp"
2 
3 #include "collect_slot_vpd.hpp"
4 #include "file_io_type_lid.hpp"
5 #include "libpldmresponder/file_io.hpp"
6 #include "libpldmresponder/pdr_utils.hpp"
7 
8 #include <libpldm/entity.h>
9 #include <libpldm/oem/ibm/entity.h>
10 #include <libpldm/pldm.h>
11 
12 #include <phosphor-logging/lg2.hpp>
13 #include <xyz/openbmc_project/State/BMC/client.hpp>
14 
15 PHOSPHOR_LOG2_USING;
16 
17 using namespace pldm::pdr;
18 using namespace pldm::utils;
19 
20 namespace pldm
21 {
22 namespace responder
23 {
24 namespace oem_ibm_platform
25 {
26 int pldm::responder::oem_ibm_platform::Handler::
27     getOemStateSensorReadingsHandler(
28         pldm::pdr::EntityType entityType, EntityInstance entityInstance,
29         ContainerID containerId, StateSetId stateSetId,
30         CompositeCount compSensorCnt, uint16_t /*sensorId*/,
31         std::vector<get_sensor_state_field>& stateField)
32 {
33     auto& entityAssociationMap = getAssociateEntityMap();
34     int rc = PLDM_SUCCESS;
35     stateField.clear();
36 
37     for (size_t i = 0; i < compSensorCnt; i++)
38     {
39         uint8_t sensorOpState{};
40         if (entityType == PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE &&
41             stateSetId == PLDM_OEM_IBM_BOOT_STATE)
42         {
43             sensorOpState = fetchBootSide(entityInstance, codeUpdate);
44         }
45         else if (entityType == PLDM_ENTITY_SLOT &&
46                  stateSetId == PLDM_OEM_IBM_PCIE_SLOT_SENSOR_STATE)
47         {
48             for (const auto& [key, value] : entityAssociationMap)
49             {
50                 if (value.entity_type == entityType &&
51                     value.entity_instance_num == entityInstance &&
52                     value.entity_container_id == containerId)
53                 {
54                     sensorOpState = slotHandler->fetchSlotSensorState(key);
55                     break;
56                 }
57             }
58         }
59         else
60         {
61             rc = PLDM_PLATFORM_INVALID_STATE_VALUE;
62             break;
63         }
64         stateField.push_back({PLDM_SENSOR_ENABLED, PLDM_SENSOR_UNKNOWN,
65                               PLDM_SENSOR_UNKNOWN, sensorOpState});
66     }
67     return rc;
68 }
69 
70 int pldm::responder::oem_ibm_platform::Handler::
71     oemSetStateEffecterStatesHandler(
72         uint16_t entityType, uint16_t entityInstance, uint16_t stateSetId,
73         uint8_t compEffecterCnt,
74         std::vector<set_effecter_state_field>& stateField, uint16_t effecterId)
75 {
76     int rc = PLDM_SUCCESS;
77     auto& entityAssociationMap = getAssociateEntityMap();
78 
79     for (uint8_t currState = 0; currState < compEffecterCnt; ++currState)
80     {
81         if (stateField[currState].set_request == PLDM_REQUEST_SET)
82         {
83             if (entityType == PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE &&
84                 stateSetId == PLDM_OEM_IBM_BOOT_STATE)
85             {
86                 rc = setBootSide(entityInstance, currState, stateField,
87                                  codeUpdate);
88             }
89             else if (entityType == PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE &&
90                      stateSetId == PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE)
91             {
92                 if (stateField[currState].effecter_state ==
93                     uint8_t(CodeUpdateState::START))
94                 {
95                     codeUpdate->setCodeUpdateProgress(true);
96                     startUpdateEvent =
97                         std::make_unique<sdeventplus::source::Defer>(
98                             event,
99                             std::bind(std::mem_fn(&oem_ibm_platform::Handler::
100                                                       _processStartUpdate),
101                                       this, std::placeholders::_1));
102                 }
103                 else if (stateField[currState].effecter_state ==
104                          uint8_t(CodeUpdateState::END))
105                 {
106                     rc = PLDM_SUCCESS;
107                     assembleImageEvent = std::make_unique<
108                         sdeventplus::source::Defer>(
109                         event,
110                         std::bind(
111                             std::mem_fn(
112                                 &oem_ibm_platform::Handler::_processEndUpdate),
113                             this, std::placeholders::_1));
114 
115                     // sendCodeUpdateEvent(effecterId, END, START);
116                 }
117                 else if (stateField[currState].effecter_state ==
118                          uint8_t(CodeUpdateState::ABORT))
119                 {
120                     codeUpdate->setCodeUpdateProgress(false);
121                     codeUpdate->clearDirPath(LID_STAGING_DIR);
122                     auto sensorId = codeUpdate->getFirmwareUpdateSensor();
123                     sendStateSensorEvent(sensorId, PLDM_STATE_SENSOR_STATE, 0,
124                                          uint8_t(CodeUpdateState::ABORT),
125                                          uint8_t(CodeUpdateState::START));
126                     // sendCodeUpdateEvent(effecterId, ABORT, END);
127                 }
128                 else if (stateField[currState].effecter_state ==
129                          uint8_t(CodeUpdateState::ACCEPT))
130                 {
131                     auto sensorId = codeUpdate->getFirmwareUpdateSensor();
132                     sendStateSensorEvent(sensorId, PLDM_STATE_SENSOR_STATE, 0,
133                                          uint8_t(CodeUpdateState::ACCEPT),
134                                          uint8_t(CodeUpdateState::END));
135                     // TODO Set new Dbus property provided by code update app
136                     // sendCodeUpdateEvent(effecterId, ACCEPT, END);
137                 }
138                 else if (stateField[currState].effecter_state ==
139                          uint8_t(CodeUpdateState::REJECT))
140                 {
141                     auto sensorId = codeUpdate->getFirmwareUpdateSensor();
142                     sendStateSensorEvent(sensorId, PLDM_STATE_SENSOR_STATE, 0,
143                                          uint8_t(CodeUpdateState::REJECT),
144                                          uint8_t(CodeUpdateState::END));
145                     // TODO Set new Dbus property provided by code update app
146                     // sendCodeUpdateEvent(effecterId, REJECT, END);
147                 }
148             }
149             else if (entityType == PLDM_ENTITY_SYSTEM_CHASSIS &&
150                      stateSetId == PLDM_OEM_IBM_SYSTEM_POWER_STATE)
151             {
152                 if (stateField[currState].effecter_state == POWER_CYCLE_HARD)
153                 {
154                     systemRebootEvent =
155                         std::make_unique<sdeventplus::source::Defer>(
156                             event,
157                             std::bind(std::mem_fn(&oem_ibm_platform::Handler::
158                                                       _processSystemReboot),
159                                       this, std::placeholders::_1));
160                 }
161             }
162             else if (stateSetId == PLDM_OEM_IBM_PCIE_SLOT_EFFECTER_STATE)
163             {
164                 slotHandler->enableSlot(effecterId, entityAssociationMap,
165                                         stateField[currState].effecter_state);
166             }
167             else
168             {
169                 rc = PLDM_PLATFORM_SET_EFFECTER_UNSUPPORTED_SENSORSTATE;
170             }
171         }
172         if (rc != PLDM_SUCCESS)
173         {
174             break;
175         }
176     }
177     return rc;
178 }
179 
180 void buildAllCodeUpdateEffecterPDR(oem_ibm_platform::Handler* platformHandler,
181                                    uint16_t entityType, uint16_t entityInstance,
182                                    uint16_t stateSetID, pdr_utils::Repo& repo)
183 {
184     size_t pdrSize = 0;
185     pdrSize = sizeof(pldm_state_effecter_pdr) +
186               sizeof(state_effecter_possible_states);
187     std::vector<uint8_t> entry{};
188     entry.resize(pdrSize);
189     pldm_state_effecter_pdr* pdr =
190         reinterpret_cast<pldm_state_effecter_pdr*>(entry.data());
191     if (!pdr)
192     {
193         error("Failed to get record by PDR type, error - {ERROR}", "ERROR",
194               lg2::hex,
195               static_cast<unsigned>(PLDM_PLATFORM_INVALID_EFFECTER_ID));
196         return;
197     }
198     pdr->hdr.record_handle = 0;
199     pdr->hdr.version = 1;
200     pdr->hdr.type = PLDM_STATE_EFFECTER_PDR;
201     pdr->hdr.record_change_num = 0;
202     pdr->hdr.length = sizeof(pldm_state_effecter_pdr) - sizeof(pldm_pdr_hdr);
203     pdr->terminus_handle = TERMINUS_HANDLE;
204     pdr->effecter_id = platformHandler->getNextEffecterId();
205     pdr->entity_type = entityType;
206     pdr->entity_instance = entityInstance;
207     pdr->container_id = 1;
208     pdr->effecter_semantic_id = 0;
209     pdr->effecter_init = PLDM_NO_INIT;
210     pdr->has_description_pdr = false;
211     pdr->composite_effecter_count = 1;
212 
213     auto* possibleStatesPtr = pdr->possible_states;
214     auto possibleStates =
215         reinterpret_cast<state_effecter_possible_states*>(possibleStatesPtr);
216     possibleStates->state_set_id = stateSetID;
217     possibleStates->possible_states_size = 2;
218     auto state =
219         reinterpret_cast<state_effecter_possible_states*>(possibleStates);
220     if (stateSetID == PLDM_OEM_IBM_BOOT_STATE)
221         state->states[0].byte = 6;
222     else if (stateSetID == PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE)
223         state->states[0].byte = 126;
224     else if (stateSetID == PLDM_OEM_IBM_SYSTEM_POWER_STATE)
225         state->states[0].byte = 2;
226     pldm::responder::pdr_utils::PdrEntry pdrEntry{};
227     pdrEntry.data = entry.data();
228     pdrEntry.size = pdrSize;
229     repo.addRecord(pdrEntry);
230 }
231 
232 void buildAllSlotEnableEffecterPDR(oem_ibm_platform::Handler* platformHandler,
233                                    pdr_utils::Repo& repo,
234                                    const std::vector<std::string>& slotobjpaths)
235 {
236     size_t pdrSize = 0;
237     pdrSize = sizeof(pldm_state_effecter_pdr) +
238               sizeof(state_effecter_possible_states);
239     std::vector<uint8_t> entry{};
240     entry.resize(pdrSize);
241     pldm_state_effecter_pdr* pdr =
242         reinterpret_cast<pldm_state_effecter_pdr*>(entry.data());
243     if (!pdr)
244     {
245         error("Failed to get record by PDR type, ERROR:{ERR}", "ERR", lg2::hex,
246               static_cast<unsigned>(PLDM_PLATFORM_INVALID_EFFECTER_ID));
247         return;
248     }
249 
250     auto& associatedEntityMap = platformHandler->getAssociateEntityMap();
251     for (const auto& entity_path : slotobjpaths)
252     {
253         pdr->hdr.record_handle = 0;
254         pdr->hdr.version = 1;
255         pdr->hdr.type = PLDM_STATE_EFFECTER_PDR;
256         pdr->hdr.record_change_num = 0;
257         pdr->hdr.length =
258             sizeof(pldm_state_effecter_pdr) - sizeof(pldm_pdr_hdr);
259         pdr->terminus_handle = TERMINUS_HANDLE;
260         pdr->effecter_id = platformHandler->getNextEffecterId();
261 
262         if (entity_path != "" && associatedEntityMap.contains(entity_path))
263         {
264             pdr->entity_type = associatedEntityMap.at(entity_path).entity_type;
265             pdr->entity_instance =
266                 associatedEntityMap.at(entity_path).entity_instance_num;
267             pdr->container_id =
268                 associatedEntityMap.at(entity_path).entity_container_id;
269             platformHandler->effecterIdToDbusMap[pdr->effecter_id] =
270                 entity_path;
271         }
272         else
273         {
274             // the slots are not present, dont create the PDR
275             continue;
276         }
277         pdr->effecter_semantic_id = 0;
278         pdr->effecter_init = PLDM_NO_INIT;
279         pdr->has_description_pdr = false;
280         pdr->composite_effecter_count = 1;
281 
282         auto* possibleStatesPtr = pdr->possible_states;
283         auto possibleStates = reinterpret_cast<state_effecter_possible_states*>(
284             possibleStatesPtr);
285         possibleStates->state_set_id = PLDM_OEM_IBM_PCIE_SLOT_EFFECTER_STATE;
286         possibleStates->possible_states_size = 2;
287         auto state =
288             reinterpret_cast<state_effecter_possible_states*>(possibleStates);
289         state->states[0].byte = 14;
290         pldm::responder::pdr_utils::PdrEntry pdrEntry{};
291         pdrEntry.data = entry.data();
292         pdrEntry.size = pdrSize;
293         repo.addRecord(pdrEntry);
294     }
295 }
296 
297 void buildAllCodeUpdateSensorPDR(oem_ibm_platform::Handler* platformHandler,
298                                  uint16_t entityType, uint16_t entityInstance,
299                                  uint16_t stateSetID, pdr_utils::Repo& repo)
300 {
301     size_t pdrSize = 0;
302     pdrSize = sizeof(pldm_state_sensor_pdr) +
303               sizeof(state_sensor_possible_states);
304     std::vector<uint8_t> entry{};
305     entry.resize(pdrSize);
306     pldm_state_sensor_pdr* pdr =
307         reinterpret_cast<pldm_state_sensor_pdr*>(entry.data());
308     if (!pdr)
309     {
310         error("Failed to get record by PDR type, error - {ERROR}", "ERROR",
311               lg2::hex, static_cast<unsigned>(PLDM_PLATFORM_INVALID_SENSOR_ID));
312         return;
313     }
314     pdr->hdr.record_handle = 0;
315     pdr->hdr.version = 1;
316     pdr->hdr.type = PLDM_STATE_SENSOR_PDR;
317     pdr->hdr.record_change_num = 0;
318     pdr->hdr.length = sizeof(pldm_state_sensor_pdr) - sizeof(pldm_pdr_hdr);
319     pdr->terminus_handle = TERMINUS_HANDLE;
320     pdr->sensor_id = platformHandler->getNextSensorId();
321     pdr->entity_type = entityType;
322     pdr->entity_instance = entityInstance;
323     pdr->container_id = 1;
324     pdr->sensor_init = PLDM_NO_INIT;
325     pdr->sensor_auxiliary_names_pdr = false;
326     pdr->composite_sensor_count = 1;
327 
328     auto* possibleStatesPtr = pdr->possible_states;
329     auto possibleStates =
330         reinterpret_cast<state_sensor_possible_states*>(possibleStatesPtr);
331     possibleStates->state_set_id = stateSetID;
332     possibleStates->possible_states_size = 2;
333     auto state =
334         reinterpret_cast<state_sensor_possible_states*>(possibleStates);
335     if ((stateSetID == PLDM_OEM_IBM_BOOT_STATE) ||
336         (stateSetID == PLDM_OEM_IBM_VERIFICATION_STATE))
337         state->states[0].byte = 6;
338     else if (stateSetID == PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE)
339         state->states[0].byte = 126;
340     pldm::responder::pdr_utils::PdrEntry pdrEntry{};
341     pdrEntry.data = entry.data();
342     pdrEntry.size = pdrSize;
343     repo.addRecord(pdrEntry);
344 }
345 
346 void buildAllSlotEnableSensorPDR(oem_ibm_platform::Handler* platformHandler,
347                                  pdr_utils::Repo& repo,
348                                  const std::vector<std::string>& slotobjpaths)
349 {
350     size_t pdrSize = 0;
351     pdrSize = sizeof(pldm_state_sensor_pdr) +
352               sizeof(state_sensor_possible_states);
353     std::vector<uint8_t> entry{};
354     entry.resize(pdrSize);
355     pldm_state_sensor_pdr* pdr =
356         reinterpret_cast<pldm_state_sensor_pdr*>(entry.data());
357     if (!pdr)
358     {
359         error("Failed to get record by PDR type, ERROR:{ERR}", "ERR", lg2::hex,
360               static_cast<unsigned>(PLDM_PLATFORM_INVALID_SENSOR_ID));
361         return;
362     }
363     auto& associatedEntityMap = platformHandler->getAssociateEntityMap();
364     for (const auto& entity_path : slotobjpaths)
365     {
366         pdr->hdr.record_handle = 0;
367         pdr->hdr.version = 1;
368         pdr->hdr.type = PLDM_STATE_SENSOR_PDR;
369         pdr->hdr.record_change_num = 0;
370         pdr->hdr.length = sizeof(pldm_state_sensor_pdr) - sizeof(pldm_pdr_hdr);
371         pdr->terminus_handle = TERMINUS_HANDLE;
372         pdr->sensor_id = platformHandler->getNextSensorId();
373         if (entity_path != "" && associatedEntityMap.contains(entity_path))
374         {
375             pdr->entity_type = associatedEntityMap.at(entity_path).entity_type;
376             pdr->entity_instance =
377                 associatedEntityMap.at(entity_path).entity_instance_num;
378             pdr->container_id =
379                 associatedEntityMap.at(entity_path).entity_container_id;
380         }
381         else
382         {
383             // the slots are not present, dont create the PDR
384             continue;
385         }
386 
387         pdr->sensor_init = PLDM_NO_INIT;
388         pdr->sensor_auxiliary_names_pdr = false;
389         pdr->composite_sensor_count = 1;
390 
391         auto* possibleStatesPtr = pdr->possible_states;
392         auto possibleStates =
393             reinterpret_cast<state_sensor_possible_states*>(possibleStatesPtr);
394         possibleStates->state_set_id = PLDM_OEM_IBM_PCIE_SLOT_SENSOR_STATE;
395         possibleStates->possible_states_size = 1;
396         auto state =
397             reinterpret_cast<state_sensor_possible_states*>(possibleStates);
398         state->states[0].byte = 15;
399         pldm::responder::pdr_utils::PdrEntry pdrEntry{};
400         pdrEntry.data = entry.data();
401         pdrEntry.size = pdrSize;
402         repo.addRecord(pdrEntry);
403     }
404 }
405 
406 void pldm::responder::oem_ibm_platform::Handler::buildOEMPDR(
407     pdr_utils::Repo& repo)
408 {
409     buildAllCodeUpdateEffecterPDR(this, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE,
410                                   ENTITY_INSTANCE_0, PLDM_OEM_IBM_BOOT_STATE,
411                                   repo);
412     buildAllCodeUpdateEffecterPDR(this, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE,
413                                   ENTITY_INSTANCE_1, PLDM_OEM_IBM_BOOT_STATE,
414                                   repo);
415     buildAllCodeUpdateEffecterPDR(this, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE,
416                                   ENTITY_INSTANCE_0,
417                                   PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE, repo);
418     buildAllCodeUpdateEffecterPDR(this, PLDM_ENTITY_SYSTEM_CHASSIS,
419                                   ENTITY_INSTANCE_1,
420                                   PLDM_OEM_IBM_SYSTEM_POWER_STATE, repo);
421 
422     static constexpr auto objectPath = "/xyz/openbmc_project/inventory/system";
423     const std::vector<std::string> slotInterface = {
424         "xyz.openbmc_project.Inventory.Item.PCIeSlot"};
425     auto slotPaths = dBusIntf->getSubTreePaths(objectPath, 0, slotInterface);
426     buildAllSlotEnableEffecterPDR(this, repo, slotPaths);
427     buildAllSlotEnableSensorPDR(this, repo, slotPaths);
428 
429     buildAllCodeUpdateSensorPDR(this, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE,
430                                 ENTITY_INSTANCE_0, PLDM_OEM_IBM_BOOT_STATE,
431                                 repo);
432     buildAllCodeUpdateSensorPDR(this, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE,
433                                 ENTITY_INSTANCE_1, PLDM_OEM_IBM_BOOT_STATE,
434                                 repo);
435     buildAllCodeUpdateSensorPDR(this, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE,
436                                 ENTITY_INSTANCE_0,
437                                 PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE, repo);
438     buildAllCodeUpdateSensorPDR(this, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE,
439                                 ENTITY_INSTANCE_0,
440                                 PLDM_OEM_IBM_VERIFICATION_STATE, repo);
441     auto sensorId = findStateSensorId(
442         repo.getPdr(), 0, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE,
443         ENTITY_INSTANCE_0, 1, PLDM_OEM_IBM_VERIFICATION_STATE);
444     codeUpdate->setMarkerLidSensor(sensorId);
445     sensorId = findStateSensorId(
446         repo.getPdr(), 0, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE,
447         ENTITY_INSTANCE_0, 1, PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE);
448     codeUpdate->setFirmwareUpdateSensor(sensorId);
449 }
450 
451 void pldm::responder::oem_ibm_platform::Handler::setPlatformHandler(
452     pldm::responder::platform::Handler* handler)
453 {
454     platformHandler = handler;
455 }
456 
457 int pldm::responder::oem_ibm_platform::Handler::sendEventToHost(
458     std::vector<uint8_t>& requestMsg, uint8_t instanceId)
459 {
460     if (requestMsg.size())
461     {
462         std::ostringstream tempStream;
463         for (int byte : requestMsg)
464         {
465             tempStream << std::setfill('0') << std::setw(2) << std::hex << byte
466                        << " ";
467         }
468         std::cout << tempStream.str() << std::endl;
469     }
470     auto oemPlatformEventMessageResponseHandler = [](mctp_eid_t /*eid*/,
471                                                      const pldm_msg* response,
472                                                      size_t respMsgLen) {
473         uint8_t completionCode{};
474         uint8_t status{};
475         auto rc = decode_platform_event_message_resp(response, respMsgLen,
476                                                      &completionCode, &status);
477         if (rc || completionCode)
478         {
479             error(
480                 "Failed to decode platform event message response for code update event with response code '{RC}' and completion code '{CC}'",
481                 "RC", rc, "CC", completionCode);
482         }
483     };
484     auto rc = handler->registerRequest(
485         mctp_eid, instanceId, PLDM_PLATFORM, PLDM_PLATFORM_EVENT_MESSAGE,
486         std::move(requestMsg),
487         std::move(oemPlatformEventMessageResponseHandler));
488     if (rc)
489     {
490         error("Failed to send BIOS attribute change event message ");
491     }
492 
493     return rc;
494 }
495 
496 int encodeEventMsg(uint8_t eventType, const std::vector<uint8_t>& eventDataVec,
497                    std::vector<uint8_t>& requestMsg, uint8_t instanceId)
498 {
499     auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
500 
501     auto rc = encode_platform_event_message_req(
502         instanceId, 1 /*formatVersion*/, TERMINUS_ID /*tId*/, eventType,
503         eventDataVec.data(), eventDataVec.size(), request,
504         eventDataVec.size() + PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES);
505 
506     return rc;
507 }
508 
509 void pldm::responder::oem_ibm_platform::Handler::sendStateSensorEvent(
510     uint16_t sensorId, enum sensor_event_class_states sensorEventClass,
511     uint8_t sensorOffset, uint8_t eventState, uint8_t prevEventState)
512 {
513     std::vector<uint8_t> sensorEventDataVec{};
514     size_t sensorEventSize = PLDM_SENSOR_EVENT_DATA_MIN_LENGTH + 1;
515     sensorEventDataVec.resize(sensorEventSize);
516     auto eventData = reinterpret_cast<struct pldm_sensor_event_data*>(
517         sensorEventDataVec.data());
518     eventData->sensor_id = sensorId;
519     eventData->sensor_event_class_type = sensorEventClass;
520     auto eventClassStart = eventData->event_class;
521     auto eventClass =
522         reinterpret_cast<struct pldm_sensor_event_state_sensor_state*>(
523             eventClassStart);
524     eventClass->sensor_offset = sensorOffset;
525     eventClass->event_state = eventState;
526     eventClass->previous_event_state = prevEventState;
527     auto instanceId = instanceIdDb.next(mctp_eid);
528     std::vector<uint8_t> requestMsg(
529         sizeof(pldm_msg_hdr) + PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES +
530         sensorEventDataVec.size());
531     auto rc = encodeEventMsg(PLDM_SENSOR_EVENT, sensorEventDataVec, requestMsg,
532                              instanceId);
533     if (rc != PLDM_SUCCESS)
534     {
535         error("Failed to encode state sensor event with response code '{RC}'",
536               "RC", rc);
537         instanceIdDb.free(mctp_eid, instanceId);
538         return;
539     }
540     rc = sendEventToHost(requestMsg, instanceId);
541     if (rc != PLDM_SUCCESS)
542     {
543         error(
544             "Failed to send event to remote terminus with response code '{RC}'",
545             "RC", rc);
546     }
547     return;
548 }
549 
550 void pldm::responder::oem_ibm_platform::Handler::_processEndUpdate(
551     sdeventplus::source::EventBase& /*source */)
552 {
553     assembleImageEvent.reset();
554     int retc = codeUpdate->assembleCodeUpdateImage();
555     if (retc != PLDM_SUCCESS)
556     {
557         codeUpdate->setCodeUpdateProgress(false);
558         auto sensorId = codeUpdate->getFirmwareUpdateSensor();
559         sendStateSensorEvent(sensorId, PLDM_STATE_SENSOR_STATE, 0,
560                              uint8_t(CodeUpdateState::FAIL),
561                              uint8_t(CodeUpdateState::START));
562     }
563 }
564 
565 void pldm::responder::oem_ibm_platform::Handler::_processStartUpdate(
566     sdeventplus::source::EventBase& /*source */)
567 {
568     codeUpdate->deleteImage();
569     CodeUpdateState state = CodeUpdateState::START;
570     auto rc = codeUpdate->setRequestedApplyTime();
571     if (rc != PLDM_SUCCESS)
572     {
573         error("setRequestedApplyTime failed");
574         state = CodeUpdateState::FAIL;
575     }
576     auto sensorId = codeUpdate->getFirmwareUpdateSensor();
577     sendStateSensorEvent(sensorId, PLDM_STATE_SENSOR_STATE, 0, uint8_t(state),
578                          uint8_t(CodeUpdateState::END));
579 }
580 
581 void pldm::responder::oem_ibm_platform::Handler::updateOemDbusPaths(
582     std::string& dbusPath)
583 {
584     std::string toFind("system1/chassis1/motherboard1");
585     if (dbusPath.find(toFind) != std::string::npos)
586     {
587         size_t pos = dbusPath.find(toFind);
588         dbusPath.replace(pos, toFind.length(), "system/chassis/motherboard");
589     }
590     toFind = "system1";
591     if (dbusPath.find(toFind) != std::string::npos)
592     {
593         size_t pos = dbusPath.find(toFind);
594         dbusPath.replace(pos, toFind.length(), "system");
595     }
596     /* below logic to replace path 'motherboard/socket/chassis' to
597        'motherboard/chassis' or 'motherboard/socket123/chassis' to
598        'motherboard/chassis' */
599     toFind = "socket";
600     size_t pos1 = dbusPath.find(toFind);
601     // while loop to detect multiple substring 'socket' in the path
602     while (pos1 != std::string::npos)
603     {
604         size_t pos2 = dbusPath.substr(pos1 + 1).find('/') + 1;
605         // Replacing starting from substring to next occurrence of char '/'
606         dbusPath.replace(pos1, pos2 + 1, "");
607         pos1 = dbusPath.find(toFind);
608     }
609 }
610 
611 void pldm::responder::oem_ibm_platform::Handler::_processSystemReboot(
612     sdeventplus::source::EventBase& /*source */)
613 {
614     pldm::utils::PropertyValue value =
615         "xyz.openbmc_project.State.Chassis.Transition.Off";
616     pldm::utils::DBusMapping dbusMapping{"/xyz/openbmc_project/state/chassis0",
617                                          "xyz.openbmc_project.State.Chassis",
618                                          "RequestedPowerTransition", "string"};
619     try
620     {
621         dBusIntf->setDbusProperty(dbusMapping, value);
622     }
623     catch (const std::exception& e)
624     {
625         error(
626             "Failure in chassis State transition to Off, unable to set property RequestedPowerTransition, error - {ERROR}",
627             "ERROR", e);
628     }
629 
630     using namespace sdbusplus::bus::match::rules;
631     chassisOffMatch = std::make_unique<sdbusplus::bus::match_t>(
632         pldm::utils::DBusHandler::getBus(),
633         propertiesChanged("/xyz/openbmc_project/state/chassis0",
634                           "xyz.openbmc_project.State.Chassis"),
635         [this](sdbusplus::message_t& msg) {
636             DbusChangedProps props{};
637             std::string intf;
638             msg.read(intf, props);
639             const auto itr = props.find("CurrentPowerState");
640             if (itr != props.end())
641             {
642                 PropertyValue value = itr->second;
643                 auto propVal = std::get<std::string>(value);
644                 if (propVal ==
645                     "xyz.openbmc_project.State.Chassis.PowerState.Off")
646                 {
647                     pldm::utils::DBusMapping dbusMapping{
648                         "/xyz/openbmc_project/control/host0/"
649                         "power_restore_policy/one_time",
650                         "xyz.openbmc_project.Control.Power.RestorePolicy",
651                         "PowerRestorePolicy", "string"};
652                     value = "xyz.openbmc_project.Control.Power.RestorePolicy."
653                             "Policy.AlwaysOn";
654                     try
655                     {
656                         dBusIntf->setDbusProperty(dbusMapping, value);
657                     }
658                     catch (const std::exception& e)
659                     {
660                         error(
661                             "Failure in setting one-time restore policy, unable to set property PowerRestorePolicy, error - {ERROR}",
662                             "ERROR", e);
663                     }
664                     dbusMapping = pldm::utils::DBusMapping{
665                         "/xyz/openbmc_project/state/bmc0",
666                         "xyz.openbmc_project.State.BMC",
667                         "RequestedBMCTransition", "string"};
668                     value = "xyz.openbmc_project.State.BMC.Transition.Reboot";
669                     try
670                     {
671                         dBusIntf->setDbusProperty(dbusMapping, value);
672                     }
673                     catch (const std::exception& e)
674                     {
675                         error(
676                             "Failure in BMC state transition to reboot, unable to set property RequestedBMCTransition , error - {ERROR}",
677                             "ERROR", e);
678                     }
679                 }
680             }
681         });
682 }
683 
684 void pldm::responder::oem_ibm_platform::Handler::checkAndDisableWatchDog()
685 {
686     if (!hostOff && setEventReceiverCnt == SET_EVENT_RECEIVER_SENT)
687     {
688         disableWatchDogTimer();
689     }
690 
691     return;
692 }
693 
694 bool pldm::responder::oem_ibm_platform::Handler::watchDogRunning()
695 {
696     static constexpr auto watchDogObjectPath =
697         "/xyz/openbmc_project/watchdog/host0";
698     static constexpr auto watchDogEnablePropName = "Enabled";
699     static constexpr auto watchDogInterface =
700         "xyz.openbmc_project.State.Watchdog";
701     bool isWatchDogRunning = false;
702     try
703     {
704         isWatchDogRunning = pldm::utils::DBusHandler().getDbusProperty<bool>(
705             watchDogObjectPath, watchDogEnablePropName, watchDogInterface);
706     }
707     catch (const std::exception&)
708     {
709         return false;
710     }
711     return isWatchDogRunning;
712 }
713 
714 void pldm::responder::oem_ibm_platform::Handler::resetWatchDogTimer()
715 {
716     static constexpr auto watchDogService = "xyz.openbmc_project.Watchdog";
717     static constexpr auto watchDogObjectPath =
718         "/xyz/openbmc_project/watchdog/host0";
719     static constexpr auto watchDogInterface =
720         "xyz.openbmc_project.State.Watchdog";
721     static constexpr auto watchDogResetPropName = "ResetTimeRemaining";
722 
723     bool wdStatus = watchDogRunning();
724     if (wdStatus == false)
725     {
726         return;
727     }
728     try
729     {
730         auto& bus = pldm::utils::DBusHandler::getBus();
731         auto resetMethod =
732             bus.new_method_call(watchDogService, watchDogObjectPath,
733                                 watchDogInterface, watchDogResetPropName);
734         resetMethod.append(true);
735         bus.call_noreply(resetMethod, dbusTimeout);
736     }
737     catch (const std::exception& e)
738     {
739         error("Failed to reset watchdog timer, error - {ERROR}", "ERROR", e);
740         return;
741     }
742 }
743 
744 void pldm::responder::oem_ibm_platform::Handler::disableWatchDogTimer()
745 {
746     setEventReceiverCnt = 0;
747     pldm::utils::DBusMapping dbusMapping{
748         "/xyz/openbmc_project/watchdog/host0",
749         "xyz.openbmc_project.State.Watchdog", "Enabled", "bool"};
750     bool wdStatus = watchDogRunning();
751 
752     if (!wdStatus)
753     {
754         return;
755     }
756     try
757     {
758         pldm::utils::DBusHandler().setDbusProperty(dbusMapping, false);
759     }
760     catch (const std::exception& e)
761     {
762         error("Failed to disable watchdog timer, error - {ERROR}", "ERROR", e);
763     }
764 }
765 int pldm::responder::oem_ibm_platform::Handler::checkBMCState()
766 {
767     using BMC = sdbusplus::client::xyz::openbmc_project::state::BMC<>;
768     auto bmcPath = sdbusplus::message::object_path(BMC::namespace_path::value) /
769                    BMC::namespace_path::bmc;
770     try
771     {
772         pldm::utils::PropertyValue propertyValue =
773             pldm::utils::DBusHandler().getDbusPropertyVariant(
774                 bmcPath.str.c_str(), "CurrentBMCState", BMC::interface);
775 
776         if (std::get<std::string>(propertyValue) ==
777             "xyz.openbmc_project.State.BMC.BMCState.NotReady")
778         {
779             error("GetPDR : PLDM stack is not ready for PDR exchange");
780             return PLDM_ERROR_NOT_READY;
781         }
782     }
783     catch (const std::exception& e)
784     {
785         error("Error getting the current BMC state, error - {ERROR}", "ERROR",
786               e);
787         return PLDM_ERROR;
788     }
789     return PLDM_SUCCESS;
790 }
791 
792 const pldm_pdr_record*
793     pldm::responder::oem_ibm_platform::Handler::fetchLastBMCRecord(
794         const pldm_pdr* repo)
795 {
796     return pldm_pdr_find_last_in_range(repo, BMC_PDR_START_RANGE,
797                                        BMC_PDR_END_RANGE);
798 }
799 
800 bool pldm::responder::oem_ibm_platform::Handler::checkRecordHandleInRange(
801     const uint32_t& record_handle)
802 {
803     return record_handle >= HOST_PDR_START_RANGE &&
804            record_handle <= HOST_PDR_END_RANGE;
805 }
806 
807 void Handler::processSetEventReceiver()
808 {
809     this->setEventReceiver();
810 }
811 
812 void pldm::responder::oem_ibm_platform::Handler::startStopTimer(bool value)
813 {
814     if (value)
815     {
816         timer.restart(
817             std::chrono::seconds(HEARTBEAT_TIMEOUT + HEARTBEAT_TIMEOUT_DELTA));
818     }
819     else
820     {
821         timer.setEnabled(value);
822     }
823 }
824 
825 void pldm::responder::oem_ibm_platform::Handler::setSurvTimer(uint8_t tid,
826                                                               bool value)
827 {
828     if ((hostOff || hostTransitioningToOff || (tid != HYPERVISOR_TID)) &&
829         timer.isEnabled())
830     {
831         startStopTimer(false);
832         return;
833     }
834     if (value)
835     {
836         startStopTimer(value);
837     }
838     else if (timer.isEnabled())
839     {
840         info(
841             "Failed to stop surveillance timer while remote terminus status is ‘{HOST_TRANST_OFF}’ with Terminus ID ‘{TID}’ ",
842             "HOST_TRANST_OFF", hostTransitioningToOff, "TID", tid);
843         startStopTimer(value);
844         pldm::utils::reportError(
845             "xyz.openbmc_project.PLDM.Error.setSurvTimer.RecvSurveillancePingFail");
846     }
847 }
848 
849 } // namespace oem_ibm_platform
850 } // namespace responder
851 } // namespace pldm
852