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