blob: f4a1c739c50cf4260bee7b7b9f2767075e76f3fa [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 {
Chris Cain8b508bf2022-05-26 14:01:31 -0500161 const uint8_t instance = sensorEntry->second;
Eddie James432dc482021-11-19 15:29:31 -0600162 if (eventState ==
163 static_cast<EventState>(
164 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_IN_SERVICE))
165 {
166 log<level::INFO>(
Chris Cain8b508bf2022-05-26 14:01:31 -0500167 fmt::format("PLDM: OCC{} is RUNNING", instance).c_str());
Eddie James432dc482021-11-19 15:29:31 -0600168 callBack(sensorEntry->second, true);
169 }
170 else if (eventState ==
171 static_cast<EventState>(
172 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_STOPPED))
173 {
Chris Cain8b508bf2022-05-26 14:01:31 -0500174 log<level::INFO>(
175 fmt::format("PLDM: OCC{} has now STOPPED", instance)
176 .c_str());
177 callBack(instance, false);
Eddie James432dc482021-11-19 15:29:31 -0600178 }
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",
Chris Cain8b508bf2022-05-26 14:01:31 -0500186 instance)
Chris Cainbae4d072022-02-28 09:46:50 -0600187 .c_str());
Sheldon Bailey31a2f132022-05-20 11:31:52 -0500188
189 // Setting safe mode true
190 safeModeCallBack(true);
191
Chris Cain8b508bf2022-05-26 14:01:31 -0500192 callBack(instance, false);
Chris Cainbae4d072022-02-28 09:46:50 -0600193 }
194 else
195 {
196 log<level::INFO>(
197 fmt::format("PLDM: Unexpected PLDM state {} for OCC{}",
Chris Cain8b508bf2022-05-26 14:01:31 -0500198 eventState, instance)
Chris Cainbae4d072022-02-28 09:46:50 -0600199 .c_str());
200 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500201 return;
202 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500203 }
Eddie James432dc482021-11-19 15:29:31 -0600204
205 if (msgSensorOffset == SBESensorOffset)
Eddie Jamescbad2192021-10-07 09:39:39 -0500206 {
207 auto sensorEntry = sensorToSBEInstance.find(sensorId);
208
Eddie James432dc482021-11-19 15:29:31 -0600209 if (sensorEntry != sensorToSBEInstance.end())
Eddie Jamescbad2192021-10-07 09:39:39 -0500210 {
Chris Cain12d0b822022-04-22 17:29:18 -0500211 const uint8_t instance = sensorEntry->second;
212 auto match = std::find(outstandingHResets.begin(),
213 outstandingHResets.end(), instance);
214 if (match != outstandingHResets.end())
Eddie James432dc482021-11-19 15:29:31 -0600215 {
Chris Cain12d0b822022-04-22 17:29:18 -0500216 outstandingHResets.erase(match);
217 if (eventState == static_cast<EventState>(SBE_HRESET_NOT_READY))
218 {
219 log<level::INFO>(
220 fmt::format("pldm: HRESET is NOT READY (OCC{})",
221 instance)
222 .c_str());
223 }
224 else if (eventState ==
225 static_cast<EventState>(SBE_HRESET_READY))
226 {
227 sbeCallBack(instance, true);
228 }
229 else if (eventState ==
230 static_cast<EventState>(SBE_HRESET_FAILED))
231 {
232 sbeCallBack(instance, false);
233 }
Eddie James432dc482021-11-19 15:29:31 -0600234 }
Chris Cain12d0b822022-04-22 17:29:18 -0500235 // else request was not from us
Eddie Jamescbad2192021-10-07 09:39:39 -0500236 }
237 }
Patrick Williams05e95592021-09-02 09:28:14 -0500238}
239
240void Interface::hostStateEvent(sdbusplus::message::message& msg)
241{
242 std::map<std::string, std::variant<std::string>> properties{};
243 std::string interface;
244 msg.read(interface, properties);
245 const auto stateEntry = properties.find("CurrentHostState");
246 if (stateEntry != properties.end())
247 {
248 auto stateEntryValue = stateEntry->second;
249 auto propVal = std::get<std::string>(stateEntryValue);
250 if (propVal == "xyz.openbmc_project.State.Host.HostState.Off")
251 {
Chris Cainbae4d072022-02-28 09:46:50 -0600252 clearData();
Patrick Williams05e95592021-09-02 09:28:14 -0500253 }
254 }
255}
256
Chris Cainbae4d072022-02-28 09:46:50 -0600257void Interface::clearData()
258{
259 sensorToOCCInstance.clear();
260 occInstanceToEffecter.clear();
261
262 sensorToSBEInstance.clear();
263 sbeInstanceToEffecter.clear();
264}
265
Eddie James432dc482021-11-19 15:29:31 -0600266void Interface::fetchEffecterInfo(uint16_t stateSetId,
Eddie Jamescbad2192021-10-07 09:39:39 -0500267 InstanceToEffecter& instanceToEffecterMap,
268 CompositeEffecterCount& effecterCount,
269 uint8_t& stateIdPos)
Patrick Williams05e95592021-09-02 09:28:14 -0500270{
Eddie Jamescbad2192021-10-07 09:39:39 -0500271 PdrList pdrs{};
272
273 auto& bus = open_power::occ::utils::getBus();
274 try
275 {
276 auto method = bus.new_method_call(
277 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
278 "xyz.openbmc_project.PLDM.PDR", "FindStateEffecterPDR");
Chris Cainbae4d072022-02-28 09:46:50 -0600279 method.append(tid, static_cast<uint16_t>(PLDM_ENTITY_PROC), stateSetId);
Eddie Jamescbad2192021-10-07 09:39:39 -0500280
281 auto responseMsg = bus.call(method);
282 responseMsg.read(pdrs);
283 }
284 catch (const sdbusplus::exception::exception& e)
285 {
286 log<level::ERR>("pldm: Failed to fetch the state effecter PDRs",
287 entry("ERROR=%s", e.what()));
288 }
289
290 if (!pdrs.size())
291 {
292 log<level::ERR>("pldm: state effecter PDRs not present");
293 return;
294 }
295
Patrick Williams05e95592021-09-02 09:28:14 -0500296 bool offsetFound = false;
George Liuf3a4a692021-12-28 13:59:51 +0800297 auto stateEffecterPDR =
Patrick Williams05e95592021-09-02 09:28:14 -0500298 reinterpret_cast<const pldm_state_effecter_pdr*>(pdrs.front().data());
George Liuf3a4a692021-12-28 13:59:51 +0800299 auto possibleStatesPtr = stateEffecterPDR->possible_states;
300 for (auto offset = 0; offset < stateEffecterPDR->composite_effecter_count;
301 offset++)
Patrick Williams05e95592021-09-02 09:28:14 -0500302 {
303 auto possibleStates =
304 reinterpret_cast<const state_effecter_possible_states*>(
305 possibleStatesPtr);
306
Eddie Jamescbad2192021-10-07 09:39:39 -0500307 if (possibleStates->state_set_id == stateSetId)
Patrick Williams05e95592021-09-02 09:28:14 -0500308 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500309 stateIdPos = offset;
George Liuf3a4a692021-12-28 13:59:51 +0800310 effecterCount = stateEffecterPDR->composite_effecter_count;
Patrick Williams05e95592021-09-02 09:28:14 -0500311 offsetFound = true;
312 break;
313 }
314 possibleStatesPtr += sizeof(possibleStates->state_set_id) +
315 sizeof(possibleStates->possible_states_size) +
316 possibleStates->possible_states_size;
317 }
318
319 if (!offsetFound)
320 {
321 return;
322 }
323
Chris Cain0f516522022-02-07 14:48:28 -0600324 std::map<uint32_t, EffecterID> entityInstMap{};
Patrick Williams05e95592021-09-02 09:28:14 -0500325 for (auto& pdr : pdrs)
326 {
327 auto pdrPtr =
328 reinterpret_cast<const pldm_state_effecter_pdr*>(pdr.data());
329 uint32_t key = (static_cast<uint32_t>(pdrPtr->container_id) << 16) |
330 static_cast<uint32_t>(pdrPtr->entity_instance);
331 entityInstMap.emplace(key, static_cast<SensorID>(pdrPtr->effecter_id));
332 }
333
334 open_power::occ::instanceID position = start;
335 for (auto const& pair : entityInstMap)
336 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500337 instanceToEffecterMap.emplace(position, pair.second);
Patrick Williams05e95592021-09-02 09:28:14 -0500338 position++;
339 }
340}
341
342std::vector<uint8_t>
Chris Cain8b508bf2022-05-26 14:01:31 -0500343 Interface::prepareSetEffecterReq(EffecterID effecterId,
Patrick Williams05e95592021-09-02 09:28:14 -0500344 CompositeEffecterCount effecterCount,
Eddie Jamescbad2192021-10-07 09:39:39 -0500345 uint8_t stateIdPos, uint8_t stateSetValue)
Patrick Williams05e95592021-09-02 09:28:14 -0500346{
Chris Cain8b508bf2022-05-26 14:01:31 -0500347 if (!getMctpInstanceId())
348 {
349 return std::vector<uint8_t>();
350 }
351
Patrick Williams05e95592021-09-02 09:28:14 -0500352 std::vector<uint8_t> request(
353 sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(effecterCount) +
354 (effecterCount * sizeof(set_effecter_state_field)));
355 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
356 std::vector<set_effecter_state_field> stateField;
357
358 for (uint8_t effecterPos = 0; effecterPos < effecterCount; effecterPos++)
359 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500360 if (effecterPos == stateIdPos)
Patrick Williams05e95592021-09-02 09:28:14 -0500361 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500362 stateField.emplace_back(
363 set_effecter_state_field{PLDM_REQUEST_SET, stateSetValue});
Patrick Williams05e95592021-09-02 09:28:14 -0500364 }
365 else
366 {
367 stateField.emplace_back(
368 set_effecter_state_field{PLDM_NO_CHANGE, 0});
369 }
370 }
371 auto rc = encode_set_state_effecter_states_req(
Chris Cain8b508bf2022-05-26 14:01:31 -0500372 mctpInstance.value(), effecterId, effecterCount, stateField.data(),
373 requestMsg);
Patrick Williams05e95592021-09-02 09:28:14 -0500374 if (rc != PLDM_SUCCESS)
375 {
376 log<level::ERR>("encode set effecter states request returned error ",
377 entry("RC=%d", rc));
378 request.clear();
379 }
380 return request;
381}
382
383void Interface::resetOCC(open_power::occ::instanceID occInstanceId)
384{
Chris Cainbae4d072022-02-28 09:46:50 -0600385 if (open_power::occ::utils::isHostRunning())
Patrick Williams05e95592021-09-02 09:28:14 -0500386 {
Chris Cainbae4d072022-02-28 09:46:50 -0600387 if (!isPDREffecterCacheValid())
388 {
389 fetchEffecterInfo(PLDM_STATE_SET_BOOT_RESTART_CAUSE,
390 occInstanceToEffecter, OCCEffecterCount,
391 bootRestartPosition);
392 }
Patrick Williams05e95592021-09-02 09:28:14 -0500393
Chris Cainbae4d072022-02-28 09:46:50 -0600394 // Find the matching effecter for the OCC instance
395 auto effecterEntry = occInstanceToEffecter.find(occInstanceId);
396 if (effecterEntry == occInstanceToEffecter.end())
397 {
398 log<level::ERR>(
399 fmt::format(
400 "pldm: Failed to find a matching effecter for OCC instance {}",
401 occInstanceId)
402 .c_str());
403
404 return;
405 }
406
Chris Cainbae4d072022-02-28 09:46:50 -0600407 // Prepare the SetStateEffecterStates request to reset the OCC
408 auto request = prepareSetEffecterReq(
Chris Cain8b508bf2022-05-26 14:01:31 -0500409 effecterEntry->second, OCCEffecterCount, bootRestartPosition,
410 PLDM_STATE_SET_BOOT_RESTART_CAUSE_WARM_RESET);
Chris Cainbae4d072022-02-28 09:46:50 -0600411
412 if (request.empty())
413 {
414 log<level::ERR>(
415 "pldm: SetStateEffecterStates OCC reset request empty");
416 return;
417 }
418
419 // Send request to reset the OCCs/PM Complex (ignore response)
420 sendPldm(request, occInstanceId, false);
421 }
422 else
Patrick Williams05e95592021-09-02 09:28:14 -0500423 {
424 log<level::ERR>(
Chris Cainbae4d072022-02-28 09:46:50 -0600425 fmt::format("resetOCC: HOST is not running (OCC{})", occInstanceId)
Chris Cain0f516522022-02-07 14:48:28 -0600426 .c_str());
Chris Cainbae4d072022-02-28 09:46:50 -0600427 clearData();
Patrick Williams05e95592021-09-02 09:28:14 -0500428 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500429}
430
431void Interface::sendHRESET(open_power::occ::instanceID sbeInstanceId)
432{
Chris Cainbae4d072022-02-28 09:46:50 -0600433 if (open_power::occ::utils::isHostRunning())
Eddie Jamescbad2192021-10-07 09:39:39 -0500434 {
Chris Cainbae4d072022-02-28 09:46:50 -0600435 if (sbeInstanceToEffecter.empty())
436 {
437 fetchEffecterInfo(PLDM_OEM_IBM_SBE_MAINTENANCE_STATE,
438 sbeInstanceToEffecter, SBEEffecterCount,
439 sbeMaintenanceStatePosition);
440 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500441
Chris Cainbae4d072022-02-28 09:46:50 -0600442 auto effecterEntry = sbeInstanceToEffecter.find(sbeInstanceId);
443 if (effecterEntry == sbeInstanceToEffecter.end())
444 {
445 log<level::ERR>(
446 "pldm: Failed to find a matching effecter for SBE instance",
447 entry("SBE=%d", sbeInstanceId));
448 return;
449 }
450
Chris Cainbae4d072022-02-28 09:46:50 -0600451 // Prepare the SetStateEffecterStates request to HRESET the SBE
452 auto request = prepareSetEffecterReq(
Chris Cain8b508bf2022-05-26 14:01:31 -0500453 effecterEntry->second, SBEEffecterCount,
Chris Cainbae4d072022-02-28 09:46:50 -0600454 sbeMaintenanceStatePosition, SBE_RETRY_REQUIRED);
455
456 if (request.empty())
457 {
458 log<level::ERR>(
459 "pldm: SetStateEffecterStates HRESET request empty");
460 return;
461 }
462
463 // Send request to issue HRESET of SBE (ignore response)
464 sendPldm(request, sbeInstanceId, false);
Chris Cain12d0b822022-04-22 17:29:18 -0500465 outstandingHResets.insert(sbeInstanceId);
Chris Cainbae4d072022-02-28 09:46:50 -0600466 }
467 else
Eddie Jamescbad2192021-10-07 09:39:39 -0500468 {
Chris Cainbae4d072022-02-28 09:46:50 -0600469 log<level::ERR>(fmt::format("sendHRESET: HOST is not running (OCC{})",
470 sbeInstanceId)
471 .c_str());
472 clearData();
Eddie Jamescbad2192021-10-07 09:39:39 -0500473 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500474}
475
Chris Cain8b508bf2022-05-26 14:01:31 -0500476bool Interface::getMctpInstanceId()
Eddie Jamescbad2192021-10-07 09:39:39 -0500477{
Chris Cain8b508bf2022-05-26 14:01:31 -0500478 if (!mctpInstance)
Patrick Williams05e95592021-09-02 09:28:14 -0500479 {
Chris Cain8b508bf2022-05-26 14:01:31 -0500480 // Request new instance ID
481 auto& bus = open_power::occ::utils::getBus();
482 try
483 {
484 auto method = bus.new_method_call(
485 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
486 "xyz.openbmc_project.PLDM.Requester", "GetInstanceId");
487 method.append(mctpEid);
488 auto reply = bus.call(method);
489 uint8_t newInstanceId;
490 reply.read(newInstanceId);
491 mctpInstance = newInstanceId;
492 log<level::INFO>(fmt::format("pldm: got new InstanceId: {}",
493 mctpInstance.value())
494 .c_str());
495 }
496 catch (const sdbusplus::exception::exception& e)
497 {
498 log<level::ERR>(
499 fmt::format("pldm: GetInstanceId failed: {}", e.what())
500 .c_str());
501 return false;
502 }
Patrick Williams05e95592021-09-02 09:28:14 -0500503 }
504
Eddie Jamescbad2192021-10-07 09:39:39 -0500505 return true;
506}
Patrick Williams05e95592021-09-02 09:28:14 -0500507
Chris Cainbae4d072022-02-28 09:46:50 -0600508void Interface::sendPldm(const std::vector<uint8_t>& request,
509 const uint8_t instance, const bool rspExpected)
Eddie Jamescbad2192021-10-07 09:39:39 -0500510{
Chris Cain8b508bf2022-05-26 14:01:31 -0500511 if (!mctpInstance)
512 {
513 log<level::ERR>("sendPldm: No MCTP Instance ID found!");
514 return;
515 }
516
Patrick Williams05e95592021-09-02 09:28:14 -0500517 // Connect to MCTP scoket
Chris Cainbae4d072022-02-28 09:46:50 -0600518 pldmFd = pldm_open();
519 auto openErrno = errno;
520 if (pldmFd == PLDM_REQUESTER_OPEN_FAIL)
Patrick Williams05e95592021-09-02 09:28:14 -0500521 {
Chris Caind1b68262022-02-28 09:56:50 -0600522 log<level::ERR>(
Chris Cainbae4d072022-02-28 09:46:50 -0600523 fmt::format(
524 "sendPldm: Failed to connect to MCTP socket, errno={}/{}",
525 openErrno, strerror(openErrno))
Chris Caind1b68262022-02-28 09:56:50 -0600526 .c_str());
Patrick Williams05e95592021-09-02 09:28:14 -0500527 return;
528 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500529
Patrick Williams05e95592021-09-02 09:28:14 -0500530 // Send the PLDM request message to HBRT
Chris Cainbae4d072022-02-28 09:46:50 -0600531 if (rspExpected)
Patrick Williams05e95592021-09-02 09:28:14 -0500532 {
Chris Cainbae4d072022-02-28 09:46:50 -0600533 // Register callback when response is available
534 registerPldmRspCallback();
535
536 // Send PLDM request
537 log<level::INFO>(
538 fmt::format(
539 "sendPldm: calling pldm_send(OCC{}, instance:{}, {} bytes)",
Chris Cain8b508bf2022-05-26 14:01:31 -0500540 instance, mctpInstance.value(), request.size())
Chris Cainbae4d072022-02-28 09:46:50 -0600541 .c_str());
542 pldmResponseReceived = false;
543 pldmResponseTimeout = false;
544 pldmResponseOcc = instance;
545 auto pldmRc =
546 pldm_send(mctpEid, pldmFd, request.data(), request.size());
547 auto sendErrno = errno;
548 if (pldmRc != PLDM_REQUESTER_SUCCESS)
549 {
550 log<level::ERR>(
551 fmt::format(
552 "sendPldm: pldm_send failed with rc={} and errno={}/{}",
553 pldmRc, sendErrno, strerror(sendErrno))
554 .c_str());
555 pldmClose();
556 return;
557 }
558
559 // start timer waiting for the response
560 using namespace std::literals::chrono_literals;
Chris Cainbd551de2022-04-26 13:41:16 -0500561 pldmRspTimer.restartOnce(8s);
Chris Cainbae4d072022-02-28 09:46:50 -0600562
563 // Wait for response/timeout
564 }
565 else // not expecting the response
566 {
567 log<level::INFO>(
568 fmt::format(
569 "sendPldm: calling pldm_send(mctpID:{}, fd:{}, {} bytes) for OCC{}",
570 mctpEid, pldmFd, request.size(), instance)
571 .c_str());
572 auto rc = pldm_send(mctpEid, pldmFd, request.data(), request.size());
573 auto sendErrno = errno;
Chris Caind1b68262022-02-28 09:56:50 -0600574 if (rc)
575 {
576 log<level::ERR>(
577 fmt::format(
Chris Cainbae4d072022-02-28 09:46:50 -0600578 "sendPldm: pldm_send(mctpID:{}, fd:{}, {} bytes) failed with rc={} and errno={}/{}",
579 mctpEid, pldmFd, request.size(), rc, sendErrno,
580 strerror(sendErrno))
Chris Caind1b68262022-02-28 09:56:50 -0600581 .c_str());
582 }
Chris Cain8b508bf2022-05-26 14:01:31 -0500583 else
584 {
585 // Not waiting for response, instance ID should be freed
586 mctpInstance = std::nullopt;
587 }
Chris Cainbae4d072022-02-28 09:46:50 -0600588 pldmClose();
589 }
590}
Patrick Williams05e95592021-09-02 09:28:14 -0500591
Chris Cainbae4d072022-02-28 09:46:50 -0600592// Attaches the FD to event loop and registers the callback handler
593void Interface::registerPldmRspCallback()
594{
595 decltype(eventSource.get()) sourcePtr = nullptr;
596 auto rc = sd_event_add_io(event.get(), &sourcePtr, pldmFd, EPOLLIN,
597 pldmRspCallback, this);
598 if (rc < 0)
599 {
600 log<level::ERR>(
601 fmt::format(
602 "registerPldmRspCallback: sd_event_add_io: Error({})={} : fd={}",
603 rc, strerror(-rc), pldmFd)
604 .c_str());
Chris Caind1b68262022-02-28 09:56:50 -0600605 }
606 else
Patrick Williams05e95592021-09-02 09:28:14 -0500607 {
Chris Cainbae4d072022-02-28 09:46:50 -0600608 // puts sourcePtr in the event source.
609 eventSource.reset(sourcePtr);
610 }
611}
612
613// Add a timer to the event loop, default 30s.
614void Interface::pldmRspExpired()
615{
616 if (!pldmResponseReceived)
617 {
618 log<level::ERR>(
619 fmt::format(
620 "pldmRspExpired: timerCallback - timeout waiting for pldm response for OCC{}",
621 pldmResponseOcc)
622 .c_str());
623 pldmResponseTimeout = true;
624 if (pldmFd)
625 {
626 pldmClose();
627 }
628 }
629 return;
630};
631
632void Interface::pldmClose()
633{
634 if (pldmRspTimer.isEnabled())
635 {
636 // stop PLDM response timer
637 pldmRspTimer.setEnabled(false);
638 }
639 close(pldmFd);
640 pldmFd = -1;
641 eventSource.reset();
642}
643
644int Interface::pldmRspCallback(sd_event_source* /*es*/, int fd,
645 uint32_t revents, void* userData)
646{
647 if (!(revents & EPOLLIN))
648 {
649 log<level::INFO>(
650 fmt::format("pldmRspCallback - revents={:08X}", revents).c_str());
651 return -1;
652 }
653
654 auto pldmIface = static_cast<Interface*>(userData);
655
Chris Cain8b508bf2022-05-26 14:01:31 -0500656 if (!pldmIface->mctpInstance)
657 {
658 log<level::ERR>(
659 "pldmRspCallback: No outstanding MCTP Instance ID found");
660 return -1;
661 }
662
Chris Cainbae4d072022-02-28 09:46:50 -0600663 uint8_t* responseMsg = nullptr;
664 size_t responseMsgSize{};
665
666 log<level::INFO>(
667 fmt::format("pldmRspCallback: calling pldm_recv() instance:{}",
Chris Cain8b508bf2022-05-26 14:01:31 -0500668 pldmIface->mctpInstance.value())
Chris Cainbae4d072022-02-28 09:46:50 -0600669 .c_str());
Chris Cain8b508bf2022-05-26 14:01:31 -0500670 auto rc = pldm_recv(mctpEid, fd, pldmIface->mctpInstance.value(),
671 &responseMsg, &responseMsgSize);
Chris Cainbae4d072022-02-28 09:46:50 -0600672 int lastErrno = errno;
673 if (rc)
674 {
675 log<level::ERR>(
676 fmt::format(
677 "pldmRspCallback: pldm_recv failed with rc={}, errno={}/{}", rc,
678 lastErrno, strerror(lastErrno))
679 .c_str());
680 return -1;
681 }
Chris Cain8b508bf2022-05-26 14:01:31 -0500682
683 // We got the response for the PLDM request msg that was sent
Chris Cainbae4d072022-02-28 09:46:50 -0600684 log<level::INFO>(
685 fmt::format("pldmRspCallback: pldm_recv() rsp was {} bytes",
686 responseMsgSize)
687 .c_str());
688
689 if (pldmIface->pldmRspTimer.isEnabled())
690 {
691 // stop PLDM response timer
692 pldmIface->pldmRspTimer.setEnabled(false);
693 }
694
Chris Cain8b508bf2022-05-26 14:01:31 -0500695 // instance ID should be freed
696 pldmIface->mctpInstance = std::nullopt;
697
Chris Cainbae4d072022-02-28 09:46:50 -0600698 // Set pointer to autodelete
699 std::unique_ptr<uint8_t, decltype(std::free)*> responseMsgPtr{responseMsg,
700 std::free};
701
Chris Cainbae4d072022-02-28 09:46:50 -0600702 auto response = reinterpret_cast<pldm_msg*>(responseMsgPtr.get());
703 if (response->payload[0] != PLDM_SUCCESS)
704 {
705 log<level::ERR>(
706 fmt::format("pldmRspCallback: payload[0] was not success: {}",
707 response->payload[0])
708 .c_str());
709 pldmIface->pldmClose();
710 return -1;
711 }
712
713 // Decode the response
714 uint8_t compCode = 0, sensorCount = 1;
715 get_sensor_state_field field[6];
716 responseMsgSize -= sizeof(pldm_msg_hdr);
717 auto msgRc = decode_get_state_sensor_readings_resp(
718 response, responseMsgSize, &compCode, &sensorCount, field);
719 if ((msgRc != PLDM_SUCCESS) || (compCode != PLDM_SUCCESS))
720 {
721 log<level::ERR>(
722 fmt::format(
723 "pldmRspCallback: decode_get_state_sensor_readings failed with rc={} and compCode={}",
724 msgRc, compCode)
725 .c_str());
726 pldmIface->pldmClose();
727 return -1;
728 }
729
730 pldmIface->pldmClose();
731
732 const uint8_t instance = pldmIface->pldmResponseOcc;
733 const uint8_t occSensorState = field[0].present_state;
734 pldmIface->pldmResponseReceived = true;
735
736 if (occSensorState == PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_IN_SERVICE)
737 {
738 log<level::INFO>(
739 fmt::format("pldmRspCallback: OCC{} is RUNNING", instance).c_str());
740 pldmIface->callBack(instance, true);
741 }
Chris Cain733b2012022-05-04 11:54:06 -0500742 else if (occSensorState ==
743 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_DORMANT)
744 {
745 log<level::INFO>(
746 fmt::format(
747 "pldmRspCallback: OCC{} has now STOPPED and system is in SAFE MODE",
748 instance)
749 .c_str());
Sheldon Bailey31a2f132022-05-20 11:31:52 -0500750
751 // Setting safe mode true
752 pldmIface->safeModeCallBack(true);
753
Chris Cain733b2012022-05-04 11:54:06 -0500754 pldmIface->callBack(instance, false);
755 }
Chris Cainbae4d072022-02-28 09:46:50 -0600756 else
757 {
758 log<level::INFO>(
Chris Cain8b508bf2022-05-26 14:01:31 -0500759 fmt::format(
760 "pldmRspCallback: OCC{} is not running (sensor state:{})",
761 instance, occSensorState)
Chris Cainbae4d072022-02-28 09:46:50 -0600762 .c_str());
763 pldmIface->callBack(instance, false);
764 }
765
766 return 0;
767};
768
769std::vector<uint8_t> Interface::encodeGetStateSensorRequest(uint8_t instance,
770 uint16_t sensorId)
771{
Chris Cain8b508bf2022-05-26 14:01:31 -0500772 if (!getMctpInstanceId())
773 {
774 log<level::ERR>(
775 "encodeGetStateSensorRequest: failed to getMctpInstanceId");
776 return std::vector<uint8_t>();
777 }
778
Chris Cainbae4d072022-02-28 09:46:50 -0600779 bitfield8_t sRearm = {0};
780 const size_t msgSize =
781 sizeof(pldm_msg_hdr) + PLDM_GET_STATE_SENSOR_READINGS_REQ_BYTES;
782 std::vector<uint8_t> request(msgSize);
Chris Cain8b508bf2022-05-26 14:01:31 -0500783
Chris Cainbae4d072022-02-28 09:46:50 -0600784 auto msg = reinterpret_cast<pldm_msg*>(request.data());
Chris Cain8b508bf2022-05-26 14:01:31 -0500785 auto msgRc = encode_get_state_sensor_readings_req(mctpInstance.value(),
786 sensorId, sRearm, 0, msg);
Chris Cainbae4d072022-02-28 09:46:50 -0600787 if (msgRc != PLDM_SUCCESS)
788 {
789 log<level::ERR>(
790 fmt::format(
791 "encodeGetStateSensorRequest: Failed to encode sensorId:0x{:08X} for OCC{} (rc={})",
792 sensorId, instance, msgRc)
793 .c_str());
794 }
795 return request;
796}
797
798// Initiate query of the specified OCC Active Sensor
799void Interface::checkActiveSensor(uint8_t instance)
800{
801 static bool tracedOnce = false;
802 if (pldmFd > 0)
803 {
804 if (!tracedOnce)
Chris Caind1b68262022-02-28 09:56:50 -0600805 {
806 log<level::ERR>(
807 fmt::format(
Chris Cainbae4d072022-02-28 09:46:50 -0600808 "checkActiveSensor: already waiting on OCC{} (fd={})",
809 pldmResponseOcc, pldmFd)
Chris Caind1b68262022-02-28 09:56:50 -0600810 .c_str());
Chris Cainbae4d072022-02-28 09:46:50 -0600811 tracedOnce = true;
Chris Caind1b68262022-02-28 09:56:50 -0600812 }
Chris Cainbae4d072022-02-28 09:46:50 -0600813 return;
814 }
815 tracedOnce = false;
816
817 if (!isOCCSensorCacheValid())
818 {
819 fetchSensorInfo(PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS,
820 sensorToOCCInstance, OCCSensorOffset);
821 }
822
823 // look up sensor id (key) based on instance
824 auto entry = std::find_if(
825 sensorToOCCInstance.begin(), sensorToOCCInstance.end(),
826 [instance](const auto& entry) { return instance == entry.second; });
827 if (entry != sensorToOCCInstance.end())
828 {
829 // Query the OCC Active Sensor state for this instance
830 // SensorID sID = entry->first;
831 log<level::INFO>(
832 fmt::format("checkActiveSensor: OCC{} / sensorID: 0x{:04X}",
833 instance, entry->first)
834 .c_str());
835
Chris Cainbae4d072022-02-28 09:46:50 -0600836 // Encode GetStateSensorReadings PLDM message
837 auto request = encodeGetStateSensorRequest(instance, entry->first);
838 if (request.empty())
839 {
840 return;
841 }
842
843 // Send request to PLDM and setup callback for response
844 sendPldm(request, instance, true);
845 }
846 else
847 {
848 log<level::ERR>(
849 fmt::format(
850 "checkActiveSensor: Unable to find PLDM sensor for OCC{}",
851 instance)
852 .c_str());
Patrick Williams05e95592021-09-02 09:28:14 -0500853 }
Patrick Williams05e95592021-09-02 09:28:14 -0500854}
855
856} // namespace pldm