xref: /openbmc/pldm/oem/ibm/libpldmresponder/oem_ibm_handler.cpp (revision 70262ed7bf854b25d4b65628bc3c892ddfe9380f)
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::
getOemStateSensorReadingsHandler(pldm::pdr::EntityType entityType,EntityInstance entityInstance,ContainerID containerId,StateSetId stateSetId,CompositeCount compSensorCnt,uint16_t,std::vector<get_sensor_state_field> & stateField)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::
oemSetStateEffecterStatesHandler(uint16_t entityType,uint16_t entityInstance,uint16_t stateSetId,uint8_t compEffecterCnt,std::vector<set_effecter_state_field> & stateField,uint16_t effecterId)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 
buildAllCodeUpdateEffecterPDR(oem_ibm_platform::Handler * platformHandler,uint16_t entityType,uint16_t entityInstance,uint16_t stateSetID,pdr_utils::Repo & repo)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 
buildAllSlotEnableEffecterPDR(oem_ibm_platform::Handler * platformHandler,pdr_utils::Repo & repo,const std::vector<std::string> & slotobjpaths)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 
buildAllCodeUpdateSensorPDR(oem_ibm_platform::Handler * platformHandler,uint16_t entityType,uint16_t entityInstance,uint16_t stateSetID,pdr_utils::Repo & repo)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 
buildAllSlotEnableSensorPDR(oem_ibm_platform::Handler * platformHandler,pdr_utils::Repo & repo,const std::vector<std::string> & slotobjpaths)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 
buildOEMPDR(pdr_utils::Repo & repo)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 
setPlatformHandler(pldm::responder::platform::Handler * handler)451 void pldm::responder::oem_ibm_platform::Handler::setPlatformHandler(
452     pldm::responder::platform::Handler* handler)
453 {
454     platformHandler = handler;
455 }
456 
sendEventToHost(std::vector<uint8_t> & requestMsg,uint8_t instanceId)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 
encodeEventMsg(uint8_t eventType,const std::vector<uint8_t> & eventDataVec,std::vector<uint8_t> & requestMsg,uint8_t instanceId)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 
sendStateSensorEvent(uint16_t sensorId,enum sensor_event_class_states sensorEventClass,uint8_t sensorOffset,uint8_t eventState,uint8_t prevEventState)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 instanceIdResult =
528         pldm::utils::getInstanceId(instanceIdDb.next(mctp_eid));
529     if (!instanceIdResult)
530     {
531         return;
532     }
533     auto instanceId = instanceIdResult.value();
534     std::vector<uint8_t> requestMsg(
535         sizeof(pldm_msg_hdr) + PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES +
536         sensorEventDataVec.size());
537     auto rc = encodeEventMsg(PLDM_SENSOR_EVENT, sensorEventDataVec, requestMsg,
538                              instanceId);
539     if (rc != PLDM_SUCCESS)
540     {
541         error("Failed to encode state sensor event with response code '{RC}'",
542               "RC", rc);
543         instanceIdDb.free(mctp_eid, instanceId);
544         return;
545     }
546     rc = sendEventToHost(requestMsg, instanceId);
547     if (rc != PLDM_SUCCESS)
548     {
549         error(
550             "Failed to send event to remote terminus with response code '{RC}'",
551             "RC", rc);
552     }
553     return;
554 }
555 
_processEndUpdate(sdeventplus::source::EventBase &)556 void pldm::responder::oem_ibm_platform::Handler::_processEndUpdate(
557     sdeventplus::source::EventBase& /*source */)
558 {
559     assembleImageEvent.reset();
560     int retc = codeUpdate->assembleCodeUpdateImage();
561     if (retc != PLDM_SUCCESS)
562     {
563         codeUpdate->setCodeUpdateProgress(false);
564         auto sensorId = codeUpdate->getFirmwareUpdateSensor();
565         sendStateSensorEvent(sensorId, PLDM_STATE_SENSOR_STATE, 0,
566                              uint8_t(CodeUpdateState::FAIL),
567                              uint8_t(CodeUpdateState::START));
568     }
569 }
570 
_processStartUpdate(sdeventplus::source::EventBase &)571 void pldm::responder::oem_ibm_platform::Handler::_processStartUpdate(
572     sdeventplus::source::EventBase& /*source */)
573 {
574     codeUpdate->deleteImage();
575     CodeUpdateState state = CodeUpdateState::START;
576     auto rc = codeUpdate->setRequestedApplyTime();
577     if (rc != PLDM_SUCCESS)
578     {
579         error("setRequestedApplyTime failed");
580         state = CodeUpdateState::FAIL;
581     }
582     auto sensorId = codeUpdate->getFirmwareUpdateSensor();
583     sendStateSensorEvent(sensorId, PLDM_STATE_SENSOR_STATE, 0, uint8_t(state),
584                          uint8_t(CodeUpdateState::END));
585 }
586 
updateOemDbusPaths(std::string & dbusPath)587 void pldm::responder::oem_ibm_platform::Handler::updateOemDbusPaths(
588     std::string& dbusPath)
589 {
590     std::string toFind("system1/chassis1/motherboard1");
591     if (dbusPath.find(toFind) != std::string::npos)
592     {
593         size_t pos = dbusPath.find(toFind);
594         dbusPath.replace(pos, toFind.length(), "system/chassis/motherboard");
595     }
596     toFind = "system1";
597     if (dbusPath.find(toFind) != std::string::npos)
598     {
599         size_t pos = dbusPath.find(toFind);
600         dbusPath.replace(pos, toFind.length(), "system");
601     }
602     /* below logic to replace path 'motherboard/socket/chassis' to
603        'motherboard/chassis' or 'motherboard/socket123/chassis' to
604        'motherboard/chassis' */
605     toFind = "socket";
606     size_t pos1 = dbusPath.find(toFind);
607     // while loop to detect multiple substring 'socket' in the path
608     while (pos1 != std::string::npos)
609     {
610         size_t pos2 = dbusPath.substr(pos1 + 1).find('/') + 1;
611         // Replacing starting from substring to next occurrence of char '/'
612         dbusPath.replace(pos1, pos2 + 1, "");
613         pos1 = dbusPath.find(toFind);
614     }
615 }
616 
_processSystemReboot(sdeventplus::source::EventBase &)617 void pldm::responder::oem_ibm_platform::Handler::_processSystemReboot(
618     sdeventplus::source::EventBase& /*source */)
619 {
620     pldm::utils::PropertyValue value =
621         "xyz.openbmc_project.State.Chassis.Transition.Off";
622     pldm::utils::DBusMapping dbusMapping{"/xyz/openbmc_project/state/chassis0",
623                                          "xyz.openbmc_project.State.Chassis",
624                                          "RequestedPowerTransition", "string"};
625     try
626     {
627         dBusIntf->setDbusProperty(dbusMapping, value);
628     }
629     catch (const std::exception& e)
630     {
631         error(
632             "Failure in chassis State transition to Off, unable to set property RequestedPowerTransition, error - {ERROR}",
633             "ERROR", e);
634     }
635 
636     using namespace sdbusplus::bus::match::rules;
637     chassisOffMatch = std::make_unique<sdbusplus::bus::match_t>(
638         pldm::utils::DBusHandler::getBus(),
639         propertiesChanged("/xyz/openbmc_project/state/chassis0",
640                           "xyz.openbmc_project.State.Chassis"),
641         [this](sdbusplus::message_t& msg) {
642             DbusChangedProps props{};
643             std::string intf;
644             msg.read(intf, props);
645             const auto itr = props.find("CurrentPowerState");
646             if (itr != props.end())
647             {
648                 PropertyValue value = itr->second;
649                 auto propVal = std::get<std::string>(value);
650                 if (propVal ==
651                     "xyz.openbmc_project.State.Chassis.PowerState.Off")
652                 {
653                     pldm::utils::DBusMapping dbusMapping{
654                         "/xyz/openbmc_project/control/host0/"
655                         "power_restore_policy/one_time",
656                         "xyz.openbmc_project.Control.Power.RestorePolicy",
657                         "PowerRestorePolicy", "string"};
658                     value = "xyz.openbmc_project.Control.Power.RestorePolicy."
659                             "Policy.AlwaysOn";
660                     try
661                     {
662                         dBusIntf->setDbusProperty(dbusMapping, value);
663                     }
664                     catch (const std::exception& e)
665                     {
666                         error(
667                             "Failure in setting one-time restore policy, unable to set property PowerRestorePolicy, error - {ERROR}",
668                             "ERROR", e);
669                     }
670                     dbusMapping = pldm::utils::DBusMapping{
671                         "/xyz/openbmc_project/state/bmc0",
672                         "xyz.openbmc_project.State.BMC",
673                         "RequestedBMCTransition", "string"};
674                     value = "xyz.openbmc_project.State.BMC.Transition.Reboot";
675                     try
676                     {
677                         dBusIntf->setDbusProperty(dbusMapping, value);
678                     }
679                     catch (const std::exception& e)
680                     {
681                         error(
682                             "Failure in BMC state transition to reboot, unable to set property RequestedBMCTransition , error - {ERROR}",
683                             "ERROR", e);
684                     }
685                 }
686             }
687         });
688 }
689 
checkAndDisableWatchDog()690 void pldm::responder::oem_ibm_platform::Handler::checkAndDisableWatchDog()
691 {
692     if (!hostOff && setEventReceiverCnt == SET_EVENT_RECEIVER_SENT)
693     {
694         disableWatchDogTimer();
695     }
696 
697     return;
698 }
699 
watchDogRunning()700 bool pldm::responder::oem_ibm_platform::Handler::watchDogRunning()
701 {
702     static constexpr auto watchDogObjectPath =
703         "/xyz/openbmc_project/watchdog/host0";
704     static constexpr auto watchDogEnablePropName = "Enabled";
705     static constexpr auto watchDogInterface =
706         "xyz.openbmc_project.State.Watchdog";
707     bool isWatchDogRunning = false;
708     try
709     {
710         isWatchDogRunning = pldm::utils::DBusHandler().getDbusProperty<bool>(
711             watchDogObjectPath, watchDogEnablePropName, watchDogInterface);
712     }
713     catch (const std::exception&)
714     {
715         return false;
716     }
717     return isWatchDogRunning;
718 }
719 
resetWatchDogTimer()720 void pldm::responder::oem_ibm_platform::Handler::resetWatchDogTimer()
721 {
722     static constexpr auto watchDogService = "xyz.openbmc_project.Watchdog";
723     static constexpr auto watchDogObjectPath =
724         "/xyz/openbmc_project/watchdog/host0";
725     static constexpr auto watchDogInterface =
726         "xyz.openbmc_project.State.Watchdog";
727     static constexpr auto watchDogResetPropName = "ResetTimeRemaining";
728 
729     bool wdStatus = watchDogRunning();
730     if (wdStatus == false)
731     {
732         return;
733     }
734     try
735     {
736         auto& bus = pldm::utils::DBusHandler::getBus();
737         auto resetMethod =
738             bus.new_method_call(watchDogService, watchDogObjectPath,
739                                 watchDogInterface, watchDogResetPropName);
740         resetMethod.append(true);
741         bus.call_noreply(resetMethod, dbusTimeout);
742     }
743     catch (const std::exception& e)
744     {
745         error("Failed to reset watchdog timer, error - {ERROR}", "ERROR", e);
746         return;
747     }
748 }
749 
disableWatchDogTimer()750 void pldm::responder::oem_ibm_platform::Handler::disableWatchDogTimer()
751 {
752     setEventReceiverCnt = 0;
753     pldm::utils::DBusMapping dbusMapping{
754         "/xyz/openbmc_project/watchdog/host0",
755         "xyz.openbmc_project.State.Watchdog", "Enabled", "bool"};
756     bool wdStatus = watchDogRunning();
757 
758     if (!wdStatus)
759     {
760         return;
761     }
762     try
763     {
764         pldm::utils::DBusHandler().setDbusProperty(dbusMapping, false);
765     }
766     catch (const std::exception& e)
767     {
768         error("Failed to disable watchdog timer, error - {ERROR}", "ERROR", e);
769     }
770 }
checkBMCState()771 int pldm::responder::oem_ibm_platform::Handler::checkBMCState()
772 {
773     using BMC = sdbusplus::client::xyz::openbmc_project::state::BMC<>;
774     auto bmcPath = sdbusplus::message::object_path(BMC::namespace_path::value) /
775                    BMC::namespace_path::bmc;
776     try
777     {
778         pldm::utils::PropertyValue propertyValue =
779             pldm::utils::DBusHandler().getDbusPropertyVariant(
780                 bmcPath.str.c_str(), "CurrentBMCState", BMC::interface);
781 
782         if (std::get<std::string>(propertyValue) !=
783             "xyz.openbmc_project.State.BMC.BMCState.Ready")
784         {
785             error("GetPDR : PLDM stack is not ready for PDR exchange");
786             return PLDM_ERROR_NOT_READY;
787         }
788     }
789     catch (const std::exception& e)
790     {
791         error("Error getting the current BMC state, error - {ERROR}", "ERROR",
792               e);
793         return PLDM_ERROR;
794     }
795     return PLDM_SUCCESS;
796 }
797 
798 const pldm_pdr_record*
fetchLastBMCRecord(const pldm_pdr * repo)799     pldm::responder::oem_ibm_platform::Handler::fetchLastBMCRecord(
800         const pldm_pdr* repo)
801 {
802     return pldm_pdr_find_last_in_range(repo, BMC_PDR_START_RANGE,
803                                        BMC_PDR_END_RANGE);
804 }
805 
checkRecordHandleInRange(const uint32_t & record_handle)806 bool pldm::responder::oem_ibm_platform::Handler::checkRecordHandleInRange(
807     const uint32_t& record_handle)
808 {
809     return record_handle >= HOST_PDR_START_RANGE &&
810            record_handle <= HOST_PDR_END_RANGE;
811 }
812 
processSetEventReceiver()813 void Handler::processSetEventReceiver()
814 {
815     this->setEventReceiver();
816 }
817 
startStopTimer(bool value)818 void pldm::responder::oem_ibm_platform::Handler::startStopTimer(bool value)
819 {
820     if (value)
821     {
822         timer.restart(
823             std::chrono::seconds(HEARTBEAT_TIMEOUT + HEARTBEAT_TIMEOUT_DELTA));
824     }
825     else
826     {
827         timer.setEnabled(value);
828     }
829 }
830 
setSurvTimer(uint8_t tid,bool value)831 void pldm::responder::oem_ibm_platform::Handler::setSurvTimer(uint8_t tid,
832                                                               bool value)
833 {
834     if ((hostOff || hostTransitioningToOff || (tid != HYPERVISOR_TID)) &&
835         timer.isEnabled())
836     {
837         startStopTimer(false);
838         return;
839     }
840     if (value)
841     {
842         startStopTimer(value);
843     }
844     else if (timer.isEnabled())
845     {
846         info(
847             "Failed to stop surveillance timer while remote terminus status is ‘{HOST_TRANST_OFF}’ with Terminus ID ‘{TID}’ ",
848             "HOST_TRANST_OFF", hostTransitioningToOff, "TID", tid);
849         startStopTimer(value);
850         pldm::utils::reportError(
851             "xyz.openbmc_project.PLDM.Error.setSurvTimer.RecvSurveillancePingFail");
852     }
853 }
854 
855 } // namespace oem_ibm_platform
856 } // namespace responder
857 } // namespace pldm
858