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