blob: 6e3dfe698cab22c4a9e6bbe63f46cc20a5e3fb0a [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());
Sheldon Bailey31a2f132022-05-20 11:31:52 -0500168
Eddie James432dc482021-11-19 15:29:31 -0600169 callBack(sensorEntry->second, true);
170 }
171 else if (eventState ==
172 static_cast<EventState>(
173 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_STOPPED))
174 {
175 log<level::INFO>(fmt::format("PLDM: OCC{} has now STOPPED",
176 sensorEntry->second)
177 .c_str());
178 callBack(sensorEntry->second, false);
179 }
Chris Cainbae4d072022-02-28 09:46:50 -0600180 else if (eventState ==
181 static_cast<EventState>(
182 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_DORMANT))
183 {
184 log<level::INFO>(
185 fmt::format(
186 "PLDM: OCC{} has now STOPPED and system is in SAFE MODE",
187 sensorEntry->second)
188 .c_str());
Sheldon Bailey31a2f132022-05-20 11:31:52 -0500189
190 // Setting safe mode true
191 safeModeCallBack(true);
192
Chris Cainbae4d072022-02-28 09:46:50 -0600193 callBack(sensorEntry->second, false);
194 }
195 else
196 {
197 log<level::INFO>(
198 fmt::format("PLDM: Unexpected PLDM state {} for OCC{}",
199 eventState, sensorEntry->second)
200 .c_str());
201 }
Eddie James432dc482021-11-19 15:29:31 -0600202
Eddie Jamescbad2192021-10-07 09:39:39 -0500203 return;
204 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500205 }
Eddie James432dc482021-11-19 15:29:31 -0600206
207 if (msgSensorOffset == SBESensorOffset)
Eddie Jamescbad2192021-10-07 09:39:39 -0500208 {
209 auto sensorEntry = sensorToSBEInstance.find(sensorId);
210
Eddie James432dc482021-11-19 15:29:31 -0600211 if (sensorEntry != sensorToSBEInstance.end())
Eddie Jamescbad2192021-10-07 09:39:39 -0500212 {
Chris Cain12d0b822022-04-22 17:29:18 -0500213 const uint8_t instance = sensorEntry->second;
214 auto match = std::find(outstandingHResets.begin(),
215 outstandingHResets.end(), instance);
216 if (match != outstandingHResets.end())
Eddie James432dc482021-11-19 15:29:31 -0600217 {
Chris Cain12d0b822022-04-22 17:29:18 -0500218 outstandingHResets.erase(match);
219 if (eventState == static_cast<EventState>(SBE_HRESET_NOT_READY))
220 {
221 log<level::INFO>(
222 fmt::format("pldm: HRESET is NOT READY (OCC{})",
223 instance)
224 .c_str());
225 }
226 else if (eventState ==
227 static_cast<EventState>(SBE_HRESET_READY))
228 {
229 sbeCallBack(instance, true);
230 }
231 else if (eventState ==
232 static_cast<EventState>(SBE_HRESET_FAILED))
233 {
234 sbeCallBack(instance, false);
235 }
Eddie James432dc482021-11-19 15:29:31 -0600236 }
Chris Cain12d0b822022-04-22 17:29:18 -0500237 // else request was not from us
Eddie Jamescbad2192021-10-07 09:39:39 -0500238 }
239 }
Patrick Williams05e95592021-09-02 09:28:14 -0500240}
241
242void Interface::hostStateEvent(sdbusplus::message::message& msg)
243{
244 std::map<std::string, std::variant<std::string>> properties{};
245 std::string interface;
246 msg.read(interface, properties);
247 const auto stateEntry = properties.find("CurrentHostState");
248 if (stateEntry != properties.end())
249 {
250 auto stateEntryValue = stateEntry->second;
251 auto propVal = std::get<std::string>(stateEntryValue);
252 if (propVal == "xyz.openbmc_project.State.Host.HostState.Off")
253 {
Chris Cainbae4d072022-02-28 09:46:50 -0600254 clearData();
Patrick Williams05e95592021-09-02 09:28:14 -0500255 }
256 }
257}
258
Chris Cainbae4d072022-02-28 09:46:50 -0600259void Interface::clearData()
260{
261 sensorToOCCInstance.clear();
262 occInstanceToEffecter.clear();
263
264 sensorToSBEInstance.clear();
265 sbeInstanceToEffecter.clear();
266}
267
Eddie James432dc482021-11-19 15:29:31 -0600268void Interface::fetchEffecterInfo(uint16_t stateSetId,
Eddie Jamescbad2192021-10-07 09:39:39 -0500269 InstanceToEffecter& instanceToEffecterMap,
270 CompositeEffecterCount& effecterCount,
271 uint8_t& stateIdPos)
Patrick Williams05e95592021-09-02 09:28:14 -0500272{
Eddie Jamescbad2192021-10-07 09:39:39 -0500273 PdrList pdrs{};
274
275 auto& bus = open_power::occ::utils::getBus();
276 try
277 {
278 auto method = bus.new_method_call(
279 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
280 "xyz.openbmc_project.PLDM.PDR", "FindStateEffecterPDR");
Chris Cainbae4d072022-02-28 09:46:50 -0600281 method.append(tid, static_cast<uint16_t>(PLDM_ENTITY_PROC), stateSetId);
Eddie Jamescbad2192021-10-07 09:39:39 -0500282
283 auto responseMsg = bus.call(method);
284 responseMsg.read(pdrs);
285 }
286 catch (const sdbusplus::exception::exception& e)
287 {
288 log<level::ERR>("pldm: Failed to fetch the state effecter PDRs",
289 entry("ERROR=%s", e.what()));
290 }
291
292 if (!pdrs.size())
293 {
294 log<level::ERR>("pldm: state effecter PDRs not present");
295 return;
296 }
297
Patrick Williams05e95592021-09-02 09:28:14 -0500298 bool offsetFound = false;
George Liuf3a4a692021-12-28 13:59:51 +0800299 auto stateEffecterPDR =
Patrick Williams05e95592021-09-02 09:28:14 -0500300 reinterpret_cast<const pldm_state_effecter_pdr*>(pdrs.front().data());
George Liuf3a4a692021-12-28 13:59:51 +0800301 auto possibleStatesPtr = stateEffecterPDR->possible_states;
302 for (auto offset = 0; offset < stateEffecterPDR->composite_effecter_count;
303 offset++)
Patrick Williams05e95592021-09-02 09:28:14 -0500304 {
305 auto possibleStates =
306 reinterpret_cast<const state_effecter_possible_states*>(
307 possibleStatesPtr);
308
Eddie Jamescbad2192021-10-07 09:39:39 -0500309 if (possibleStates->state_set_id == stateSetId)
Patrick Williams05e95592021-09-02 09:28:14 -0500310 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500311 stateIdPos = offset;
George Liuf3a4a692021-12-28 13:59:51 +0800312 effecterCount = stateEffecterPDR->composite_effecter_count;
Patrick Williams05e95592021-09-02 09:28:14 -0500313 offsetFound = true;
314 break;
315 }
316 possibleStatesPtr += sizeof(possibleStates->state_set_id) +
317 sizeof(possibleStates->possible_states_size) +
318 possibleStates->possible_states_size;
319 }
320
321 if (!offsetFound)
322 {
323 return;
324 }
325
Chris Cain0f516522022-02-07 14:48:28 -0600326 std::map<uint32_t, EffecterID> entityInstMap{};
Patrick Williams05e95592021-09-02 09:28:14 -0500327 for (auto& pdr : pdrs)
328 {
329 auto pdrPtr =
330 reinterpret_cast<const pldm_state_effecter_pdr*>(pdr.data());
331 uint32_t key = (static_cast<uint32_t>(pdrPtr->container_id) << 16) |
332 static_cast<uint32_t>(pdrPtr->entity_instance);
333 entityInstMap.emplace(key, static_cast<SensorID>(pdrPtr->effecter_id));
334 }
335
336 open_power::occ::instanceID position = start;
337 for (auto const& pair : entityInstMap)
338 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500339 instanceToEffecterMap.emplace(position, pair.second);
Patrick Williams05e95592021-09-02 09:28:14 -0500340 position++;
341 }
342}
343
344std::vector<uint8_t>
345 Interface::prepareSetEffecterReq(uint8_t instanceId, EffecterID effecterId,
346 CompositeEffecterCount effecterCount,
Eddie Jamescbad2192021-10-07 09:39:39 -0500347 uint8_t stateIdPos, uint8_t stateSetValue)
Patrick Williams05e95592021-09-02 09:28:14 -0500348{
349 std::vector<uint8_t> request(
350 sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(effecterCount) +
351 (effecterCount * sizeof(set_effecter_state_field)));
352 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
353 std::vector<set_effecter_state_field> stateField;
354
355 for (uint8_t effecterPos = 0; effecterPos < effecterCount; effecterPos++)
356 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500357 if (effecterPos == stateIdPos)
Patrick Williams05e95592021-09-02 09:28:14 -0500358 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500359 stateField.emplace_back(
360 set_effecter_state_field{PLDM_REQUEST_SET, stateSetValue});
Patrick Williams05e95592021-09-02 09:28:14 -0500361 }
362 else
363 {
364 stateField.emplace_back(
365 set_effecter_state_field{PLDM_NO_CHANGE, 0});
366 }
367 }
368 auto rc = encode_set_state_effecter_states_req(
369 instanceId, effecterId, effecterCount, stateField.data(), requestMsg);
370 if (rc != PLDM_SUCCESS)
371 {
372 log<level::ERR>("encode set effecter states request returned error ",
373 entry("RC=%d", rc));
374 request.clear();
375 }
376 return request;
377}
378
379void Interface::resetOCC(open_power::occ::instanceID occInstanceId)
380{
Chris Cainbae4d072022-02-28 09:46:50 -0600381 if (open_power::occ::utils::isHostRunning())
Patrick Williams05e95592021-09-02 09:28:14 -0500382 {
Chris Cainbae4d072022-02-28 09:46:50 -0600383 if (!isPDREffecterCacheValid())
384 {
385 fetchEffecterInfo(PLDM_STATE_SET_BOOT_RESTART_CAUSE,
386 occInstanceToEffecter, OCCEffecterCount,
387 bootRestartPosition);
388 }
Patrick Williams05e95592021-09-02 09:28:14 -0500389
Chris Cainbae4d072022-02-28 09:46:50 -0600390 // Find the matching effecter for the OCC instance
391 auto effecterEntry = occInstanceToEffecter.find(occInstanceId);
392 if (effecterEntry == occInstanceToEffecter.end())
393 {
394 log<level::ERR>(
395 fmt::format(
396 "pldm: Failed to find a matching effecter for OCC instance {}",
397 occInstanceId)
398 .c_str());
399
400 return;
401 }
402
403 if (!getMctpInstanceId(mctpInstance))
404 {
405 return;
406 }
407
408 // Prepare the SetStateEffecterStates request to reset the OCC
409 auto request = prepareSetEffecterReq(
410 mctpInstance, effecterEntry->second, OCCEffecterCount,
411 bootRestartPosition, PLDM_STATE_SET_BOOT_RESTART_CAUSE_WARM_RESET);
412
413 if (request.empty())
414 {
415 log<level::ERR>(
416 "pldm: SetStateEffecterStates OCC reset request empty");
417 return;
418 }
419
420 // Send request to reset the OCCs/PM Complex (ignore response)
421 sendPldm(request, occInstanceId, false);
422 }
423 else
Patrick Williams05e95592021-09-02 09:28:14 -0500424 {
425 log<level::ERR>(
Chris Cainbae4d072022-02-28 09:46:50 -0600426 fmt::format("resetOCC: HOST is not running (OCC{})", occInstanceId)
Chris Cain0f516522022-02-07 14:48:28 -0600427 .c_str());
Chris Cainbae4d072022-02-28 09:46:50 -0600428 clearData();
Patrick Williams05e95592021-09-02 09:28:14 -0500429 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500430}
431
432void Interface::sendHRESET(open_power::occ::instanceID sbeInstanceId)
433{
Chris Cainbae4d072022-02-28 09:46:50 -0600434 if (open_power::occ::utils::isHostRunning())
Eddie Jamescbad2192021-10-07 09:39:39 -0500435 {
Chris Cainbae4d072022-02-28 09:46:50 -0600436 if (sbeInstanceToEffecter.empty())
437 {
438 fetchEffecterInfo(PLDM_OEM_IBM_SBE_MAINTENANCE_STATE,
439 sbeInstanceToEffecter, SBEEffecterCount,
440 sbeMaintenanceStatePosition);
441 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500442
Chris Cainbae4d072022-02-28 09:46:50 -0600443 auto effecterEntry = sbeInstanceToEffecter.find(sbeInstanceId);
444 if (effecterEntry == sbeInstanceToEffecter.end())
445 {
446 log<level::ERR>(
447 "pldm: Failed to find a matching effecter for SBE instance",
448 entry("SBE=%d", sbeInstanceId));
449 return;
450 }
451
452 if (!getMctpInstanceId(mctpInstance))
453 {
454 return;
455 }
456
457 // Prepare the SetStateEffecterStates request to HRESET the SBE
458 auto request = prepareSetEffecterReq(
459 mctpInstance, effecterEntry->second, SBEEffecterCount,
460 sbeMaintenanceStatePosition, SBE_RETRY_REQUIRED);
461
462 if (request.empty())
463 {
464 log<level::ERR>(
465 "pldm: SetStateEffecterStates HRESET request empty");
466 return;
467 }
468
469 // Send request to issue HRESET of SBE (ignore response)
470 sendPldm(request, sbeInstanceId, false);
Chris Cain12d0b822022-04-22 17:29:18 -0500471 outstandingHResets.insert(sbeInstanceId);
Chris Cainbae4d072022-02-28 09:46:50 -0600472 }
473 else
Eddie Jamescbad2192021-10-07 09:39:39 -0500474 {
Chris Cainbae4d072022-02-28 09:46:50 -0600475 log<level::ERR>(fmt::format("sendHRESET: HOST is not running (OCC{})",
476 sbeInstanceId)
477 .c_str());
478 clearData();
Eddie Jamescbad2192021-10-07 09:39:39 -0500479 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500480}
481
482bool Interface::getMctpInstanceId(uint8_t& instanceId)
483{
Patrick Williams05e95592021-09-02 09:28:14 -0500484 auto& bus = open_power::occ::utils::getBus();
485 try
486 {
487 auto method = bus.new_method_call(
488 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
489 "xyz.openbmc_project.PLDM.Requester", "GetInstanceId");
490 method.append(mctpEid);
491 auto reply = bus.call(method);
492 reply.read(instanceId);
493 }
Patrick Williams25613622021-09-02 09:29:54 -0500494 catch (const sdbusplus::exception::exception& e)
Patrick Williams05e95592021-09-02 09:28:14 -0500495 {
Chris Cainbd551de2022-04-26 13:41:16 -0500496 log<level::ERR>(
497 fmt::format("pldm: GetInstanceId failed: {}", e.what()).c_str());
Eddie Jamescbad2192021-10-07 09:39:39 -0500498 return false;
Patrick Williams05e95592021-09-02 09:28:14 -0500499 }
500
Eddie Jamescbad2192021-10-07 09:39:39 -0500501 return true;
502}
Patrick Williams05e95592021-09-02 09:28:14 -0500503
Chris Cainbae4d072022-02-28 09:46:50 -0600504void Interface::sendPldm(const std::vector<uint8_t>& request,
505 const uint8_t instance, const bool rspExpected)
Eddie Jamescbad2192021-10-07 09:39:39 -0500506{
Patrick Williams05e95592021-09-02 09:28:14 -0500507 // Connect to MCTP scoket
Chris Cainbae4d072022-02-28 09:46:50 -0600508 pldmFd = pldm_open();
509 auto openErrno = errno;
510 if (pldmFd == PLDM_REQUESTER_OPEN_FAIL)
Patrick Williams05e95592021-09-02 09:28:14 -0500511 {
Chris Caind1b68262022-02-28 09:56:50 -0600512 log<level::ERR>(
Chris Cainbae4d072022-02-28 09:46:50 -0600513 fmt::format(
514 "sendPldm: Failed to connect to MCTP socket, errno={}/{}",
515 openErrno, strerror(openErrno))
Chris Caind1b68262022-02-28 09:56:50 -0600516 .c_str());
Patrick Williams05e95592021-09-02 09:28:14 -0500517 return;
518 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500519
Patrick Williams05e95592021-09-02 09:28:14 -0500520 // Send the PLDM request message to HBRT
Chris Cainbae4d072022-02-28 09:46:50 -0600521 if (rspExpected)
Patrick Williams05e95592021-09-02 09:28:14 -0500522 {
Chris Cainbae4d072022-02-28 09:46:50 -0600523 // Register callback when response is available
524 registerPldmRspCallback();
525
526 // Send PLDM request
527 log<level::INFO>(
528 fmt::format(
529 "sendPldm: calling pldm_send(OCC{}, instance:{}, {} bytes)",
530 instance, mctpInstance, request.size())
531 .c_str());
532 pldmResponseReceived = false;
533 pldmResponseTimeout = false;
534 pldmResponseOcc = instance;
535 auto pldmRc =
536 pldm_send(mctpEid, pldmFd, request.data(), request.size());
537 auto sendErrno = errno;
538 if (pldmRc != PLDM_REQUESTER_SUCCESS)
539 {
540 log<level::ERR>(
541 fmt::format(
542 "sendPldm: pldm_send failed with rc={} and errno={}/{}",
543 pldmRc, sendErrno, strerror(sendErrno))
544 .c_str());
545 pldmClose();
546 return;
547 }
548
549 // start timer waiting for the response
550 using namespace std::literals::chrono_literals;
Chris Cainbd551de2022-04-26 13:41:16 -0500551 pldmRspTimer.restartOnce(8s);
Chris Cainbae4d072022-02-28 09:46:50 -0600552
553 // Wait for response/timeout
554 }
555 else // not expecting the response
556 {
557 log<level::INFO>(
558 fmt::format(
559 "sendPldm: calling pldm_send(mctpID:{}, fd:{}, {} bytes) for OCC{}",
560 mctpEid, pldmFd, request.size(), instance)
561 .c_str());
562 auto rc = pldm_send(mctpEid, pldmFd, request.data(), request.size());
563 auto sendErrno = errno;
Chris Caind1b68262022-02-28 09:56:50 -0600564 if (rc)
565 {
566 log<level::ERR>(
567 fmt::format(
Chris Cainbae4d072022-02-28 09:46:50 -0600568 "sendPldm: pldm_send(mctpID:{}, fd:{}, {} bytes) failed with rc={} and errno={}/{}",
569 mctpEid, pldmFd, request.size(), rc, sendErrno,
570 strerror(sendErrno))
Chris Caind1b68262022-02-28 09:56:50 -0600571 .c_str());
572 }
Chris Cainbae4d072022-02-28 09:46:50 -0600573 pldmClose();
574 }
575}
Patrick Williams05e95592021-09-02 09:28:14 -0500576
Chris Cainbae4d072022-02-28 09:46:50 -0600577// Attaches the FD to event loop and registers the callback handler
578void Interface::registerPldmRspCallback()
579{
580 decltype(eventSource.get()) sourcePtr = nullptr;
581 auto rc = sd_event_add_io(event.get(), &sourcePtr, pldmFd, EPOLLIN,
582 pldmRspCallback, this);
583 if (rc < 0)
584 {
585 log<level::ERR>(
586 fmt::format(
587 "registerPldmRspCallback: sd_event_add_io: Error({})={} : fd={}",
588 rc, strerror(-rc), pldmFd)
589 .c_str());
Chris Caind1b68262022-02-28 09:56:50 -0600590 }
591 else
Patrick Williams05e95592021-09-02 09:28:14 -0500592 {
Chris Cainbae4d072022-02-28 09:46:50 -0600593 // puts sourcePtr in the event source.
594 eventSource.reset(sourcePtr);
595 }
596}
597
598// Add a timer to the event loop, default 30s.
599void Interface::pldmRspExpired()
600{
601 if (!pldmResponseReceived)
602 {
603 log<level::ERR>(
604 fmt::format(
605 "pldmRspExpired: timerCallback - timeout waiting for pldm response for OCC{}",
606 pldmResponseOcc)
607 .c_str());
608 pldmResponseTimeout = true;
609 if (pldmFd)
610 {
611 pldmClose();
612 }
613 }
614 return;
615};
616
617void Interface::pldmClose()
618{
619 if (pldmRspTimer.isEnabled())
620 {
621 // stop PLDM response timer
622 pldmRspTimer.setEnabled(false);
623 }
624 close(pldmFd);
625 pldmFd = -1;
626 eventSource.reset();
627}
628
629int Interface::pldmRspCallback(sd_event_source* /*es*/, int fd,
630 uint32_t revents, void* userData)
631{
632 if (!(revents & EPOLLIN))
633 {
634 log<level::INFO>(
635 fmt::format("pldmRspCallback - revents={:08X}", revents).c_str());
636 return -1;
637 }
638
639 auto pldmIface = static_cast<Interface*>(userData);
640
641 uint8_t* responseMsg = nullptr;
642 size_t responseMsgSize{};
643
644 log<level::INFO>(
645 fmt::format("pldmRspCallback: calling pldm_recv() instance:{}",
646 pldmIface->mctpInstance)
647 .c_str());
648 auto rc = pldm_recv(mctpEid, fd, pldmIface->mctpInstance, &responseMsg,
649 &responseMsgSize);
650 int lastErrno = errno;
651 if (rc)
652 {
653 log<level::ERR>(
654 fmt::format(
655 "pldmRspCallback: pldm_recv failed with rc={}, errno={}/{}", rc,
656 lastErrno, strerror(lastErrno))
657 .c_str());
658 return -1;
659 }
660 log<level::INFO>(
661 fmt::format("pldmRspCallback: pldm_recv() rsp was {} bytes",
662 responseMsgSize)
663 .c_str());
664
665 if (pldmIface->pldmRspTimer.isEnabled())
666 {
667 // stop PLDM response timer
668 pldmIface->pldmRspTimer.setEnabled(false);
669 }
670
671 // Set pointer to autodelete
672 std::unique_ptr<uint8_t, decltype(std::free)*> responseMsgPtr{responseMsg,
673 std::free};
674
675 // We've got the response meant for the PLDM request msg that was
676 // sent out
677 // io.set_enabled(Enabled::Off);
678 auto response = reinterpret_cast<pldm_msg*>(responseMsgPtr.get());
679 if (response->payload[0] != PLDM_SUCCESS)
680 {
681 log<level::ERR>(
682 fmt::format("pldmRspCallback: payload[0] was not success: {}",
683 response->payload[0])
684 .c_str());
685 pldmIface->pldmClose();
686 return -1;
687 }
688
689 // Decode the response
690 uint8_t compCode = 0, sensorCount = 1;
691 get_sensor_state_field field[6];
692 responseMsgSize -= sizeof(pldm_msg_hdr);
693 auto msgRc = decode_get_state_sensor_readings_resp(
694 response, responseMsgSize, &compCode, &sensorCount, field);
695 if ((msgRc != PLDM_SUCCESS) || (compCode != PLDM_SUCCESS))
696 {
697 log<level::ERR>(
698 fmt::format(
699 "pldmRspCallback: decode_get_state_sensor_readings failed with rc={} and compCode={}",
700 msgRc, compCode)
701 .c_str());
702 pldmIface->pldmClose();
703 return -1;
704 }
705
706 pldmIface->pldmClose();
707
708 const uint8_t instance = pldmIface->pldmResponseOcc;
709 const uint8_t occSensorState = field[0].present_state;
710 pldmIface->pldmResponseReceived = true;
711
712 if (occSensorState == PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_IN_SERVICE)
713 {
714 log<level::INFO>(
715 fmt::format("pldmRspCallback: OCC{} is RUNNING", instance).c_str());
716 pldmIface->callBack(instance, true);
717 }
Chris Cain733b2012022-05-04 11:54:06 -0500718 else if (occSensorState ==
719 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_DORMANT)
720 {
721 log<level::INFO>(
722 fmt::format(
723 "pldmRspCallback: OCC{} has now STOPPED and system is in SAFE MODE",
724 instance)
725 .c_str());
Sheldon Bailey31a2f132022-05-20 11:31:52 -0500726
727 // Setting safe mode true
728 pldmIface->safeModeCallBack(true);
729
Chris Cain733b2012022-05-04 11:54:06 -0500730 pldmIface->callBack(instance, false);
731 }
Chris Cainbae4d072022-02-28 09:46:50 -0600732 else
733 {
734 log<level::INFO>(
735 fmt::format("pldmRspCallback: OCC{} is not running (state:{})",
736 instance, occSensorState)
737 .c_str());
738 pldmIface->callBack(instance, false);
739 }
740
741 return 0;
742};
743
744std::vector<uint8_t> Interface::encodeGetStateSensorRequest(uint8_t instance,
745 uint16_t sensorId)
746{
747 bitfield8_t sRearm = {0};
748 const size_t msgSize =
749 sizeof(pldm_msg_hdr) + PLDM_GET_STATE_SENSOR_READINGS_REQ_BYTES;
750 std::vector<uint8_t> request(msgSize);
751 auto msg = reinterpret_cast<pldm_msg*>(request.data());
752 auto msgRc = encode_get_state_sensor_readings_req(mctpInstance, sensorId,
753 sRearm, 0, msg);
754 if (msgRc != PLDM_SUCCESS)
755 {
756 log<level::ERR>(
757 fmt::format(
758 "encodeGetStateSensorRequest: Failed to encode sensorId:0x{:08X} for OCC{} (rc={})",
759 sensorId, instance, msgRc)
760 .c_str());
761 }
762 return request;
763}
764
765// Initiate query of the specified OCC Active Sensor
766void Interface::checkActiveSensor(uint8_t instance)
767{
768 static bool tracedOnce = false;
769 if (pldmFd > 0)
770 {
771 if (!tracedOnce)
Chris Caind1b68262022-02-28 09:56:50 -0600772 {
773 log<level::ERR>(
774 fmt::format(
Chris Cainbae4d072022-02-28 09:46:50 -0600775 "checkActiveSensor: already waiting on OCC{} (fd={})",
776 pldmResponseOcc, pldmFd)
Chris Caind1b68262022-02-28 09:56:50 -0600777 .c_str());
Chris Cainbae4d072022-02-28 09:46:50 -0600778 tracedOnce = true;
Chris Caind1b68262022-02-28 09:56:50 -0600779 }
Chris Cainbae4d072022-02-28 09:46:50 -0600780 return;
781 }
782 tracedOnce = false;
783
784 if (!isOCCSensorCacheValid())
785 {
786 fetchSensorInfo(PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS,
787 sensorToOCCInstance, OCCSensorOffset);
788 }
789
790 // look up sensor id (key) based on instance
791 auto entry = std::find_if(
792 sensorToOCCInstance.begin(), sensorToOCCInstance.end(),
793 [instance](const auto& entry) { return instance == entry.second; });
794 if (entry != sensorToOCCInstance.end())
795 {
796 // Query the OCC Active Sensor state for this instance
797 // SensorID sID = entry->first;
798 log<level::INFO>(
799 fmt::format("checkActiveSensor: OCC{} / sensorID: 0x{:04X}",
800 instance, entry->first)
801 .c_str());
802
803 if (!getMctpInstanceId(mctpInstance))
804 {
805 log<level::ERR>("checkActiveSensor: failed to getMctpInstanceId");
806 return;
807 }
808
809 // Encode GetStateSensorReadings PLDM message
810 auto request = encodeGetStateSensorRequest(instance, entry->first);
811 if (request.empty())
812 {
813 return;
814 }
815
816 // Send request to PLDM and setup callback for response
817 sendPldm(request, instance, true);
818 }
819 else
820 {
821 log<level::ERR>(
822 fmt::format(
823 "checkActiveSensor: Unable to find PLDM sensor for OCC{}",
824 instance)
825 .c_str());
Patrick Williams05e95592021-09-02 09:28:14 -0500826 }
Patrick Williams05e95592021-09-02 09:28:14 -0500827}
828
829} // namespace pldm