blob: bff995c1bb2214ffc87201c1bc61e917317543bd [file] [log] [blame]
Patrick Williams05e95592021-09-02 09:28:14 -05001#include "pldm.hpp"
2
3#include "file.hpp"
4
5#include <fmt/core.h>
6#include <libpldm/entity.h>
7#include <libpldm/platform.h>
8#include <libpldm/state_set.h>
Eddie James36313c72021-11-18 08:27:03 -06009#include <libpldm/state_set_oem_ibm.h>
Patrick Williams05e95592021-09-02 09:28:14 -050010
11#include <phosphor-logging/log.hpp>
Chris Cainbae4d072022-02-28 09:46:50 -060012#include <sdbusplus/bus.hpp>
13#include <sdeventplus/clock.hpp>
14#include <sdeventplus/exception.hpp>
15#include <sdeventplus/source/io.hpp>
16#include <sdeventplus/source/time.hpp>
17
18#include <algorithm>
Patrick Williams05e95592021-09-02 09:28:14 -050019
20namespace pldm
21{
22
Patrick Williams05e95592021-09-02 09:28:14 -050023using namespace phosphor::logging;
24
Chris Cainbae4d072022-02-28 09:46:50 -060025using namespace sdeventplus;
26using namespace sdeventplus::source;
27constexpr auto clockId = sdeventplus::ClockId::RealTime;
28using Clock = sdeventplus::Clock<clockId>;
29using Timer = Time<clockId>;
30
Eddie Jamescbad2192021-10-07 09:39:39 -050031void Interface::fetchSensorInfo(uint16_t stateSetId,
32 SensorToInstance& sensorInstanceMap,
33 SensorOffset& sensorOffset)
Patrick Williams05e95592021-09-02 09:28:14 -050034{
Eddie Jamescbad2192021-10-07 09:39:39 -050035 PdrList pdrs{};
Chris Cainbae4d072022-02-28 09:46:50 -060036 static bool tracedError = false;
Eddie Jamescbad2192021-10-07 09:39:39 -050037
38 auto& bus = open_power::occ::utils::getBus();
39 try
40 {
41 auto method = bus.new_method_call(
42 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
43 "xyz.openbmc_project.PLDM.PDR", "FindStateSensorPDR");
Chris Cainbae4d072022-02-28 09:46:50 -060044 method.append(tid, static_cast<uint16_t>(PLDM_ENTITY_PROC), stateSetId);
Eddie Jamescbad2192021-10-07 09:39:39 -050045
46 auto responseMsg = bus.call(method);
47 responseMsg.read(pdrs);
48 }
49 catch (const sdbusplus::exception::exception& e)
50 {
Chris Cainbae4d072022-02-28 09:46:50 -060051 if (!tracedError)
52 {
53 log<level::ERR>(
54 fmt::format(
55 "fetchSensorInfo: Failed to find stateSetID:{} PDR: {}",
56 stateSetId, e.what())
57 .c_str());
58 tracedError = true;
59 }
Eddie Jamescbad2192021-10-07 09:39:39 -050060 }
61
62 if (pdrs.empty())
63 {
Chris Cainbae4d072022-02-28 09:46:50 -060064 if (!tracedError)
65 {
66 log<level::ERR>(
67 fmt::format(
68 "fetchSensorInfo: state sensor PDRs ({}) not present",
69 stateSetId)
70 .c_str());
71 tracedError = true;
72 }
Eddie Jamescbad2192021-10-07 09:39:39 -050073 return;
74 }
75
Chris Cainbae4d072022-02-28 09:46:50 -060076 // Found PDR
77 if (tracedError)
78 {
79 log<level::INFO>(
80 fmt::format("fetchSensorInfo: found {} PDRs", pdrs.size()).c_str());
81 tracedError = false;
82 }
83
Patrick Williams05e95592021-09-02 09:28:14 -050084 bool offsetFound = false;
George Liuf3a4a692021-12-28 13:59:51 +080085 auto stateSensorPDR =
Patrick Williams05e95592021-09-02 09:28:14 -050086 reinterpret_cast<const pldm_state_sensor_pdr*>(pdrs.front().data());
George Liuf3a4a692021-12-28 13:59:51 +080087 auto possibleStatesPtr = stateSensorPDR->possible_states;
88 for (auto offset = 0; offset < stateSensorPDR->composite_sensor_count;
89 offset++)
Patrick Williams05e95592021-09-02 09:28:14 -050090 {
91 auto possibleStates =
92 reinterpret_cast<const state_sensor_possible_states*>(
93 possibleStatesPtr);
94
Eddie Jamescbad2192021-10-07 09:39:39 -050095 if (possibleStates->state_set_id == stateSetId)
Patrick Williams05e95592021-09-02 09:28:14 -050096 {
97 sensorOffset = offset;
98 offsetFound = true;
99 break;
100 }
101 possibleStatesPtr += sizeof(possibleStates->state_set_id) +
102 sizeof(possibleStates->possible_states_size) +
103 possibleStates->possible_states_size;
104 }
105
106 if (!offsetFound)
107 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500108 log<level::ERR>("pldm: state sensor PDR not found");
Patrick Williams05e95592021-09-02 09:28:14 -0500109 return;
110 }
111
112 // To order SensorID based on the EntityInstance.
113 // Note that when a proc is on a DCM, the PDRs for these sensors
114 // could have the same instance IDs but different container IDs.
115 std::map<uint32_t, SensorID> entityInstMap{};
116 for (auto& pdr : pdrs)
117 {
118 auto pdrPtr =
119 reinterpret_cast<const pldm_state_sensor_pdr*>(pdr.data());
120 uint32_t key = (static_cast<uint32_t>(pdrPtr->container_id) << 16) |
121 static_cast<uint32_t>(pdrPtr->entity_instance);
122 entityInstMap.emplace(key, static_cast<SensorID>(pdrPtr->sensor_id));
123 }
124
125 open_power::occ::instanceID count = start;
126 for (auto const& pair : entityInstMap)
127 {
128 sensorInstanceMap.emplace(pair.second, count);
129 count++;
130 }
131}
132
133void Interface::sensorEvent(sdbusplus::message::message& msg)
134{
135 if (!isOCCSensorCacheValid())
136 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500137 fetchSensorInfo(PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS,
138 sensorToOCCInstance, OCCSensorOffset);
139 }
Patrick Williams05e95592021-09-02 09:28:14 -0500140
Eddie Jamescbad2192021-10-07 09:39:39 -0500141 if (sensorToSBEInstance.empty())
142 {
143 fetchSensorInfo(PLDM_OEM_IBM_SBE_HRESET_STATE, sensorToSBEInstance,
144 SBESensorOffset);
Patrick Williams05e95592021-09-02 09:28:14 -0500145 }
146
147 TerminusID tid{};
148 SensorID sensorId{};
149 SensorOffset msgSensorOffset{};
150 EventState eventState{};
151 EventState previousEventState{};
152
153 msg.read(tid, sensorId, msgSensorOffset, eventState, previousEventState);
154
Eddie Jamescbad2192021-10-07 09:39:39 -0500155 if (msgSensorOffset == OCCSensorOffset)
Patrick Williams05e95592021-09-02 09:28:14 -0500156 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500157 auto sensorEntry = sensorToOCCInstance.find(sensorId);
Patrick Williams05e95592021-09-02 09:28:14 -0500158
Eddie James432dc482021-11-19 15:29:31 -0600159 if (sensorEntry != sensorToOCCInstance.end())
Eddie Jamescbad2192021-10-07 09:39:39 -0500160 {
Eddie James432dc482021-11-19 15:29:31 -0600161 if (eventState ==
162 static_cast<EventState>(
163 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_IN_SERVICE))
164 {
165 log<level::INFO>(
166 fmt::format("PLDM: OCC{} is RUNNING", sensorEntry->second)
167 .c_str());
168 callBack(sensorEntry->second, true);
169 }
170 else if (eventState ==
171 static_cast<EventState>(
172 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_STOPPED))
173 {
174 log<level::INFO>(fmt::format("PLDM: OCC{} has now STOPPED",
175 sensorEntry->second)
176 .c_str());
177 callBack(sensorEntry->second, false);
178 }
Chris Cainbae4d072022-02-28 09:46:50 -0600179 else if (eventState ==
180 static_cast<EventState>(
181 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_DORMANT))
182 {
183 log<level::INFO>(
184 fmt::format(
185 "PLDM: OCC{} has now STOPPED and system is in SAFE MODE",
186 sensorEntry->second)
187 .c_str());
188 callBack(sensorEntry->second, false);
189 }
190 else
191 {
192 log<level::INFO>(
193 fmt::format("PLDM: Unexpected PLDM state {} for OCC{}",
194 eventState, sensorEntry->second)
195 .c_str());
196 }
Eddie James432dc482021-11-19 15:29:31 -0600197
Eddie Jamescbad2192021-10-07 09:39:39 -0500198 return;
199 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500200 }
Eddie James432dc482021-11-19 15:29:31 -0600201
202 if (msgSensorOffset == SBESensorOffset)
Eddie Jamescbad2192021-10-07 09:39:39 -0500203 {
204 auto sensorEntry = sensorToSBEInstance.find(sensorId);
205
Eddie James432dc482021-11-19 15:29:31 -0600206 if (sensorEntry != sensorToSBEInstance.end())
Eddie Jamescbad2192021-10-07 09:39:39 -0500207 {
Eddie James432dc482021-11-19 15:29:31 -0600208 if (eventState == static_cast<EventState>(SBE_HRESET_NOT_READY))
209 {
Chris Cainbae4d072022-02-28 09:46:50 -0600210 log<level::INFO>(
211 fmt::format("pldm: HRESET is NOT READY (OCC{})",
212 sensorEntry->second)
213 .c_str());
Eddie James432dc482021-11-19 15:29:31 -0600214 }
215 else if (eventState == static_cast<EventState>(SBE_HRESET_READY))
216 {
217 sbeCallBack(sensorEntry->second, true);
218 }
219 else if (eventState == static_cast<EventState>(SBE_HRESET_FAILED))
220 {
221 sbeCallBack(sensorEntry->second, false);
222 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500223 }
224 }
Patrick Williams05e95592021-09-02 09:28:14 -0500225}
226
227void Interface::hostStateEvent(sdbusplus::message::message& msg)
228{
229 std::map<std::string, std::variant<std::string>> properties{};
230 std::string interface;
231 msg.read(interface, properties);
232 const auto stateEntry = properties.find("CurrentHostState");
233 if (stateEntry != properties.end())
234 {
235 auto stateEntryValue = stateEntry->second;
236 auto propVal = std::get<std::string>(stateEntryValue);
237 if (propVal == "xyz.openbmc_project.State.Host.HostState.Off")
238 {
Chris Cainbae4d072022-02-28 09:46:50 -0600239 clearData();
Patrick Williams05e95592021-09-02 09:28:14 -0500240 }
241 }
242}
243
Chris Cainbae4d072022-02-28 09:46:50 -0600244void Interface::clearData()
245{
246 sensorToOCCInstance.clear();
247 occInstanceToEffecter.clear();
248
249 sensorToSBEInstance.clear();
250 sbeInstanceToEffecter.clear();
251}
252
Eddie James432dc482021-11-19 15:29:31 -0600253void Interface::fetchEffecterInfo(uint16_t stateSetId,
Eddie Jamescbad2192021-10-07 09:39:39 -0500254 InstanceToEffecter& instanceToEffecterMap,
255 CompositeEffecterCount& effecterCount,
256 uint8_t& stateIdPos)
Patrick Williams05e95592021-09-02 09:28:14 -0500257{
Eddie Jamescbad2192021-10-07 09:39:39 -0500258 PdrList pdrs{};
259
260 auto& bus = open_power::occ::utils::getBus();
261 try
262 {
263 auto method = bus.new_method_call(
264 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
265 "xyz.openbmc_project.PLDM.PDR", "FindStateEffecterPDR");
Chris Cainbae4d072022-02-28 09:46:50 -0600266 method.append(tid, static_cast<uint16_t>(PLDM_ENTITY_PROC), stateSetId);
Eddie Jamescbad2192021-10-07 09:39:39 -0500267
268 auto responseMsg = bus.call(method);
269 responseMsg.read(pdrs);
270 }
271 catch (const sdbusplus::exception::exception& e)
272 {
273 log<level::ERR>("pldm: Failed to fetch the state effecter PDRs",
274 entry("ERROR=%s", e.what()));
275 }
276
277 if (!pdrs.size())
278 {
279 log<level::ERR>("pldm: state effecter PDRs not present");
280 return;
281 }
282
Patrick Williams05e95592021-09-02 09:28:14 -0500283 bool offsetFound = false;
George Liuf3a4a692021-12-28 13:59:51 +0800284 auto stateEffecterPDR =
Patrick Williams05e95592021-09-02 09:28:14 -0500285 reinterpret_cast<const pldm_state_effecter_pdr*>(pdrs.front().data());
George Liuf3a4a692021-12-28 13:59:51 +0800286 auto possibleStatesPtr = stateEffecterPDR->possible_states;
287 for (auto offset = 0; offset < stateEffecterPDR->composite_effecter_count;
288 offset++)
Patrick Williams05e95592021-09-02 09:28:14 -0500289 {
290 auto possibleStates =
291 reinterpret_cast<const state_effecter_possible_states*>(
292 possibleStatesPtr);
293
Eddie Jamescbad2192021-10-07 09:39:39 -0500294 if (possibleStates->state_set_id == stateSetId)
Patrick Williams05e95592021-09-02 09:28:14 -0500295 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500296 stateIdPos = offset;
George Liuf3a4a692021-12-28 13:59:51 +0800297 effecterCount = stateEffecterPDR->composite_effecter_count;
Patrick Williams05e95592021-09-02 09:28:14 -0500298 offsetFound = true;
299 break;
300 }
301 possibleStatesPtr += sizeof(possibleStates->state_set_id) +
302 sizeof(possibleStates->possible_states_size) +
303 possibleStates->possible_states_size;
304 }
305
306 if (!offsetFound)
307 {
308 return;
309 }
310
Chris Cain0f516522022-02-07 14:48:28 -0600311 std::map<uint32_t, EffecterID> entityInstMap{};
Patrick Williams05e95592021-09-02 09:28:14 -0500312 for (auto& pdr : pdrs)
313 {
314 auto pdrPtr =
315 reinterpret_cast<const pldm_state_effecter_pdr*>(pdr.data());
316 uint32_t key = (static_cast<uint32_t>(pdrPtr->container_id) << 16) |
317 static_cast<uint32_t>(pdrPtr->entity_instance);
318 entityInstMap.emplace(key, static_cast<SensorID>(pdrPtr->effecter_id));
319 }
320
321 open_power::occ::instanceID position = start;
322 for (auto const& pair : entityInstMap)
323 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500324 instanceToEffecterMap.emplace(position, pair.second);
Patrick Williams05e95592021-09-02 09:28:14 -0500325 position++;
326 }
327}
328
329std::vector<uint8_t>
330 Interface::prepareSetEffecterReq(uint8_t instanceId, EffecterID effecterId,
331 CompositeEffecterCount effecterCount,
Eddie Jamescbad2192021-10-07 09:39:39 -0500332 uint8_t stateIdPos, uint8_t stateSetValue)
Patrick Williams05e95592021-09-02 09:28:14 -0500333{
334 std::vector<uint8_t> request(
335 sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(effecterCount) +
336 (effecterCount * sizeof(set_effecter_state_field)));
337 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
338 std::vector<set_effecter_state_field> stateField;
339
340 for (uint8_t effecterPos = 0; effecterPos < effecterCount; effecterPos++)
341 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500342 if (effecterPos == stateIdPos)
Patrick Williams05e95592021-09-02 09:28:14 -0500343 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500344 stateField.emplace_back(
345 set_effecter_state_field{PLDM_REQUEST_SET, stateSetValue});
Patrick Williams05e95592021-09-02 09:28:14 -0500346 }
347 else
348 {
349 stateField.emplace_back(
350 set_effecter_state_field{PLDM_NO_CHANGE, 0});
351 }
352 }
353 auto rc = encode_set_state_effecter_states_req(
354 instanceId, effecterId, effecterCount, stateField.data(), requestMsg);
355 if (rc != PLDM_SUCCESS)
356 {
357 log<level::ERR>("encode set effecter states request returned error ",
358 entry("RC=%d", rc));
359 request.clear();
360 }
361 return request;
362}
363
364void Interface::resetOCC(open_power::occ::instanceID occInstanceId)
365{
Chris Cainbae4d072022-02-28 09:46:50 -0600366 if (open_power::occ::utils::isHostRunning())
Patrick Williams05e95592021-09-02 09:28:14 -0500367 {
Chris Cainbae4d072022-02-28 09:46:50 -0600368 if (!isPDREffecterCacheValid())
369 {
370 fetchEffecterInfo(PLDM_STATE_SET_BOOT_RESTART_CAUSE,
371 occInstanceToEffecter, OCCEffecterCount,
372 bootRestartPosition);
373 }
Patrick Williams05e95592021-09-02 09:28:14 -0500374
Chris Cainbae4d072022-02-28 09:46:50 -0600375 // Find the matching effecter for the OCC instance
376 auto effecterEntry = occInstanceToEffecter.find(occInstanceId);
377 if (effecterEntry == occInstanceToEffecter.end())
378 {
379 log<level::ERR>(
380 fmt::format(
381 "pldm: Failed to find a matching effecter for OCC instance {}",
382 occInstanceId)
383 .c_str());
384
385 return;
386 }
387
388 if (!getMctpInstanceId(mctpInstance))
389 {
390 return;
391 }
392
393 // Prepare the SetStateEffecterStates request to reset the OCC
394 auto request = prepareSetEffecterReq(
395 mctpInstance, effecterEntry->second, OCCEffecterCount,
396 bootRestartPosition, PLDM_STATE_SET_BOOT_RESTART_CAUSE_WARM_RESET);
397
398 if (request.empty())
399 {
400 log<level::ERR>(
401 "pldm: SetStateEffecterStates OCC reset request empty");
402 return;
403 }
404
405 // Send request to reset the OCCs/PM Complex (ignore response)
406 sendPldm(request, occInstanceId, false);
407 }
408 else
Patrick Williams05e95592021-09-02 09:28:14 -0500409 {
410 log<level::ERR>(
Chris Cainbae4d072022-02-28 09:46:50 -0600411 fmt::format("resetOCC: HOST is not running (OCC{})", occInstanceId)
Chris Cain0f516522022-02-07 14:48:28 -0600412 .c_str());
Chris Cainbae4d072022-02-28 09:46:50 -0600413 clearData();
Patrick Williams05e95592021-09-02 09:28:14 -0500414 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500415}
416
417void Interface::sendHRESET(open_power::occ::instanceID sbeInstanceId)
418{
Chris Cainbae4d072022-02-28 09:46:50 -0600419 if (open_power::occ::utils::isHostRunning())
Eddie Jamescbad2192021-10-07 09:39:39 -0500420 {
Chris Cainbae4d072022-02-28 09:46:50 -0600421 if (sbeInstanceToEffecter.empty())
422 {
423 fetchEffecterInfo(PLDM_OEM_IBM_SBE_MAINTENANCE_STATE,
424 sbeInstanceToEffecter, SBEEffecterCount,
425 sbeMaintenanceStatePosition);
426 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500427
Chris Cainbae4d072022-02-28 09:46:50 -0600428 auto effecterEntry = sbeInstanceToEffecter.find(sbeInstanceId);
429 if (effecterEntry == sbeInstanceToEffecter.end())
430 {
431 log<level::ERR>(
432 "pldm: Failed to find a matching effecter for SBE instance",
433 entry("SBE=%d", sbeInstanceId));
434 return;
435 }
436
437 if (!getMctpInstanceId(mctpInstance))
438 {
439 return;
440 }
441
442 // Prepare the SetStateEffecterStates request to HRESET the SBE
443 auto request = prepareSetEffecterReq(
444 mctpInstance, effecterEntry->second, SBEEffecterCount,
445 sbeMaintenanceStatePosition, SBE_RETRY_REQUIRED);
446
447 if (request.empty())
448 {
449 log<level::ERR>(
450 "pldm: SetStateEffecterStates HRESET request empty");
451 return;
452 }
453
454 // Send request to issue HRESET of SBE (ignore response)
455 sendPldm(request, sbeInstanceId, false);
456 }
457 else
Eddie Jamescbad2192021-10-07 09:39:39 -0500458 {
Chris Cainbae4d072022-02-28 09:46:50 -0600459 log<level::ERR>(fmt::format("sendHRESET: HOST is not running (OCC{})",
460 sbeInstanceId)
461 .c_str());
462 clearData();
Eddie Jamescbad2192021-10-07 09:39:39 -0500463 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500464}
465
466bool Interface::getMctpInstanceId(uint8_t& instanceId)
467{
Patrick Williams05e95592021-09-02 09:28:14 -0500468 auto& bus = open_power::occ::utils::getBus();
469 try
470 {
471 auto method = bus.new_method_call(
472 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
473 "xyz.openbmc_project.PLDM.Requester", "GetInstanceId");
474 method.append(mctpEid);
475 auto reply = bus.call(method);
476 reply.read(instanceId);
477 }
Patrick Williams25613622021-09-02 09:29:54 -0500478 catch (const sdbusplus::exception::exception& e)
Patrick Williams05e95592021-09-02 09:28:14 -0500479 {
480 log<level::ERR>("pldm: GetInstanceId returned error",
481 entry("ERROR=%s", e.what()));
Eddie Jamescbad2192021-10-07 09:39:39 -0500482 return false;
Patrick Williams05e95592021-09-02 09:28:14 -0500483 }
484
Eddie Jamescbad2192021-10-07 09:39:39 -0500485 return true;
486}
Patrick Williams05e95592021-09-02 09:28:14 -0500487
Chris Cainbae4d072022-02-28 09:46:50 -0600488void Interface::sendPldm(const std::vector<uint8_t>& request,
489 const uint8_t instance, const bool rspExpected)
Eddie Jamescbad2192021-10-07 09:39:39 -0500490{
Patrick Williams05e95592021-09-02 09:28:14 -0500491 // Connect to MCTP scoket
Chris Cainbae4d072022-02-28 09:46:50 -0600492 pldmFd = pldm_open();
493 auto openErrno = errno;
494 if (pldmFd == PLDM_REQUESTER_OPEN_FAIL)
Patrick Williams05e95592021-09-02 09:28:14 -0500495 {
Chris Caind1b68262022-02-28 09:56:50 -0600496 log<level::ERR>(
Chris Cainbae4d072022-02-28 09:46:50 -0600497 fmt::format(
498 "sendPldm: Failed to connect to MCTP socket, errno={}/{}",
499 openErrno, strerror(openErrno))
Chris Caind1b68262022-02-28 09:56:50 -0600500 .c_str());
Patrick Williams05e95592021-09-02 09:28:14 -0500501 return;
502 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500503
Patrick Williams05e95592021-09-02 09:28:14 -0500504 // Send the PLDM request message to HBRT
Chris Cainbae4d072022-02-28 09:46:50 -0600505 if (rspExpected)
Patrick Williams05e95592021-09-02 09:28:14 -0500506 {
Chris Cainbae4d072022-02-28 09:46:50 -0600507 // Register callback when response is available
508 registerPldmRspCallback();
509
510 // Send PLDM request
511 log<level::INFO>(
512 fmt::format(
513 "sendPldm: calling pldm_send(OCC{}, instance:{}, {} bytes)",
514 instance, mctpInstance, request.size())
515 .c_str());
516 pldmResponseReceived = false;
517 pldmResponseTimeout = false;
518 pldmResponseOcc = instance;
519 auto pldmRc =
520 pldm_send(mctpEid, pldmFd, request.data(), request.size());
521 auto sendErrno = errno;
522 if (pldmRc != PLDM_REQUESTER_SUCCESS)
523 {
524 log<level::ERR>(
525 fmt::format(
526 "sendPldm: pldm_send failed with rc={} and errno={}/{}",
527 pldmRc, sendErrno, strerror(sendErrno))
528 .c_str());
529 pldmClose();
530 return;
531 }
532
533 // start timer waiting for the response
534 using namespace std::literals::chrono_literals;
535 pldmRspTimer.restartOnce(10s);
536
537 // Wait for response/timeout
538 }
539 else // not expecting the response
540 {
541 log<level::INFO>(
542 fmt::format(
543 "sendPldm: calling pldm_send(mctpID:{}, fd:{}, {} bytes) for OCC{}",
544 mctpEid, pldmFd, request.size(), instance)
545 .c_str());
546 auto rc = pldm_send(mctpEid, pldmFd, request.data(), request.size());
547 auto sendErrno = errno;
Chris Caind1b68262022-02-28 09:56:50 -0600548 if (rc)
549 {
550 log<level::ERR>(
551 fmt::format(
Chris Cainbae4d072022-02-28 09:46:50 -0600552 "sendPldm: pldm_send(mctpID:{}, fd:{}, {} bytes) failed with rc={} and errno={}/{}",
553 mctpEid, pldmFd, request.size(), rc, sendErrno,
554 strerror(sendErrno))
Chris Caind1b68262022-02-28 09:56:50 -0600555 .c_str());
556 }
Chris Cainbae4d072022-02-28 09:46:50 -0600557 pldmClose();
558 }
559}
Patrick Williams05e95592021-09-02 09:28:14 -0500560
Chris Cainbae4d072022-02-28 09:46:50 -0600561// Attaches the FD to event loop and registers the callback handler
562void Interface::registerPldmRspCallback()
563{
564 decltype(eventSource.get()) sourcePtr = nullptr;
565 auto rc = sd_event_add_io(event.get(), &sourcePtr, pldmFd, EPOLLIN,
566 pldmRspCallback, this);
567 if (rc < 0)
568 {
569 log<level::ERR>(
570 fmt::format(
571 "registerPldmRspCallback: sd_event_add_io: Error({})={} : fd={}",
572 rc, strerror(-rc), pldmFd)
573 .c_str());
Chris Caind1b68262022-02-28 09:56:50 -0600574 }
575 else
Patrick Williams05e95592021-09-02 09:28:14 -0500576 {
Chris Cainbae4d072022-02-28 09:46:50 -0600577 // puts sourcePtr in the event source.
578 eventSource.reset(sourcePtr);
579 }
580}
581
582// Add a timer to the event loop, default 30s.
583void Interface::pldmRspExpired()
584{
585 if (!pldmResponseReceived)
586 {
587 log<level::ERR>(
588 fmt::format(
589 "pldmRspExpired: timerCallback - timeout waiting for pldm response for OCC{}",
590 pldmResponseOcc)
591 .c_str());
592 pldmResponseTimeout = true;
593 if (pldmFd)
594 {
595 pldmClose();
596 }
597 }
598 return;
599};
600
601void Interface::pldmClose()
602{
603 if (pldmRspTimer.isEnabled())
604 {
605 // stop PLDM response timer
606 pldmRspTimer.setEnabled(false);
607 }
608 close(pldmFd);
609 pldmFd = -1;
610 eventSource.reset();
611}
612
613int Interface::pldmRspCallback(sd_event_source* /*es*/, int fd,
614 uint32_t revents, void* userData)
615{
616 if (!(revents & EPOLLIN))
617 {
618 log<level::INFO>(
619 fmt::format("pldmRspCallback - revents={:08X}", revents).c_str());
620 return -1;
621 }
622
623 auto pldmIface = static_cast<Interface*>(userData);
624
625 uint8_t* responseMsg = nullptr;
626 size_t responseMsgSize{};
627
628 log<level::INFO>(
629 fmt::format("pldmRspCallback: calling pldm_recv() instance:{}",
630 pldmIface->mctpInstance)
631 .c_str());
632 auto rc = pldm_recv(mctpEid, fd, pldmIface->mctpInstance, &responseMsg,
633 &responseMsgSize);
634 int lastErrno = errno;
635 if (rc)
636 {
637 log<level::ERR>(
638 fmt::format(
639 "pldmRspCallback: pldm_recv failed with rc={}, errno={}/{}", rc,
640 lastErrno, strerror(lastErrno))
641 .c_str());
642 return -1;
643 }
644 log<level::INFO>(
645 fmt::format("pldmRspCallback: pldm_recv() rsp was {} bytes",
646 responseMsgSize)
647 .c_str());
648
649 if (pldmIface->pldmRspTimer.isEnabled())
650 {
651 // stop PLDM response timer
652 pldmIface->pldmRspTimer.setEnabled(false);
653 }
654
655 // Set pointer to autodelete
656 std::unique_ptr<uint8_t, decltype(std::free)*> responseMsgPtr{responseMsg,
657 std::free};
658
659 // We've got the response meant for the PLDM request msg that was
660 // sent out
661 // io.set_enabled(Enabled::Off);
662 auto response = reinterpret_cast<pldm_msg*>(responseMsgPtr.get());
663 if (response->payload[0] != PLDM_SUCCESS)
664 {
665 log<level::ERR>(
666 fmt::format("pldmRspCallback: payload[0] was not success: {}",
667 response->payload[0])
668 .c_str());
669 pldmIface->pldmClose();
670 return -1;
671 }
672
673 // Decode the response
674 uint8_t compCode = 0, sensorCount = 1;
675 get_sensor_state_field field[6];
676 responseMsgSize -= sizeof(pldm_msg_hdr);
677 auto msgRc = decode_get_state_sensor_readings_resp(
678 response, responseMsgSize, &compCode, &sensorCount, field);
679 if ((msgRc != PLDM_SUCCESS) || (compCode != PLDM_SUCCESS))
680 {
681 log<level::ERR>(
682 fmt::format(
683 "pldmRspCallback: decode_get_state_sensor_readings failed with rc={} and compCode={}",
684 msgRc, compCode)
685 .c_str());
686 pldmIface->pldmClose();
687 return -1;
688 }
689
690 pldmIface->pldmClose();
691
692 const uint8_t instance = pldmIface->pldmResponseOcc;
693 const uint8_t occSensorState = field[0].present_state;
694 pldmIface->pldmResponseReceived = true;
695
696 if (occSensorState == PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_IN_SERVICE)
697 {
698 log<level::INFO>(
699 fmt::format("pldmRspCallback: OCC{} is RUNNING", instance).c_str());
700 pldmIface->callBack(instance, true);
701 }
702 else
703 {
704 log<level::INFO>(
705 fmt::format("pldmRspCallback: OCC{} is not running (state:{})",
706 instance, occSensorState)
707 .c_str());
708 pldmIface->callBack(instance, false);
709 }
710
711 return 0;
712};
713
714std::vector<uint8_t> Interface::encodeGetStateSensorRequest(uint8_t instance,
715 uint16_t sensorId)
716{
717 bitfield8_t sRearm = {0};
718 const size_t msgSize =
719 sizeof(pldm_msg_hdr) + PLDM_GET_STATE_SENSOR_READINGS_REQ_BYTES;
720 std::vector<uint8_t> request(msgSize);
721 auto msg = reinterpret_cast<pldm_msg*>(request.data());
722 auto msgRc = encode_get_state_sensor_readings_req(mctpInstance, sensorId,
723 sRearm, 0, msg);
724 if (msgRc != PLDM_SUCCESS)
725 {
726 log<level::ERR>(
727 fmt::format(
728 "encodeGetStateSensorRequest: Failed to encode sensorId:0x{:08X} for OCC{} (rc={})",
729 sensorId, instance, msgRc)
730 .c_str());
731 }
732 return request;
733}
734
735// Initiate query of the specified OCC Active Sensor
736void Interface::checkActiveSensor(uint8_t instance)
737{
738 static bool tracedOnce = false;
739 if (pldmFd > 0)
740 {
741 if (!tracedOnce)
Chris Caind1b68262022-02-28 09:56:50 -0600742 {
743 log<level::ERR>(
744 fmt::format(
Chris Cainbae4d072022-02-28 09:46:50 -0600745 "checkActiveSensor: already waiting on OCC{} (fd={})",
746 pldmResponseOcc, pldmFd)
Chris Caind1b68262022-02-28 09:56:50 -0600747 .c_str());
Chris Cainbae4d072022-02-28 09:46:50 -0600748 tracedOnce = true;
Chris Caind1b68262022-02-28 09:56:50 -0600749 }
Chris Cainbae4d072022-02-28 09:46:50 -0600750 return;
751 }
752 tracedOnce = false;
753
754 if (!isOCCSensorCacheValid())
755 {
756 fetchSensorInfo(PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS,
757 sensorToOCCInstance, OCCSensorOffset);
758 }
759
760 // look up sensor id (key) based on instance
761 auto entry = std::find_if(
762 sensorToOCCInstance.begin(), sensorToOCCInstance.end(),
763 [instance](const auto& entry) { return instance == entry.second; });
764 if (entry != sensorToOCCInstance.end())
765 {
766 // Query the OCC Active Sensor state for this instance
767 // SensorID sID = entry->first;
768 log<level::INFO>(
769 fmt::format("checkActiveSensor: OCC{} / sensorID: 0x{:04X}",
770 instance, entry->first)
771 .c_str());
772
773 if (!getMctpInstanceId(mctpInstance))
774 {
775 log<level::ERR>("checkActiveSensor: failed to getMctpInstanceId");
776 return;
777 }
778
779 // Encode GetStateSensorReadings PLDM message
780 auto request = encodeGetStateSensorRequest(instance, entry->first);
781 if (request.empty())
782 {
783 return;
784 }
785
786 // Send request to PLDM and setup callback for response
787 sendPldm(request, instance, true);
788 }
789 else
790 {
791 log<level::ERR>(
792 fmt::format(
793 "checkActiveSensor: Unable to find PLDM sensor for OCC{}",
794 instance)
795 .c_str());
Patrick Williams05e95592021-09-02 09:28:14 -0500796 }
Patrick Williams05e95592021-09-02 09:28:14 -0500797}
798
799} // namespace pldm