blob: fb2c24595355fc50d02f2ea44b0b835b178e4fce [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 }
Patrick Williamsaf408082022-07-22 19:26:54 -050049 catch (const sdbusplus::exception_t& e)
Eddie Jamescbad2192021-10-07 09:39:39 -050050 {
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());
Chris Cain72d01aa2022-06-14 16:28:03 -0500120 uint32_t key = pdrPtr->sensor_id;
Patrick Williams05e95592021-09-02 09:28:14 -0500121 entityInstMap.emplace(key, static_cast<SensorID>(pdrPtr->sensor_id));
122 }
123
124 open_power::occ::instanceID count = start;
125 for (auto const& pair : entityInstMap)
126 {
127 sensorInstanceMap.emplace(pair.second, count);
128 count++;
129 }
130}
131
Patrick Williamsaf408082022-07-22 19:26:54 -0500132void Interface::sensorEvent(sdbusplus::message_t& msg)
Patrick Williams05e95592021-09-02 09:28:14 -0500133{
134 if (!isOCCSensorCacheValid())
135 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500136 fetchSensorInfo(PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS,
137 sensorToOCCInstance, OCCSensorOffset);
138 }
Patrick Williams05e95592021-09-02 09:28:14 -0500139
Eddie Jamescbad2192021-10-07 09:39:39 -0500140 if (sensorToSBEInstance.empty())
141 {
142 fetchSensorInfo(PLDM_OEM_IBM_SBE_HRESET_STATE, sensorToSBEInstance,
143 SBESensorOffset);
Patrick Williams05e95592021-09-02 09:28:14 -0500144 }
145
Chris Cain72d01aa2022-06-14 16:28:03 -0500146 TerminusID sensorTid{};
Patrick Williams05e95592021-09-02 09:28:14 -0500147 SensorID sensorId{};
148 SensorOffset msgSensorOffset{};
149 EventState eventState{};
150 EventState previousEventState{};
151
Chris Cain72d01aa2022-06-14 16:28:03 -0500152 msg.read(sensorTid, sensorId, msgSensorOffset, eventState,
153 previousEventState);
Patrick Williams05e95592021-09-02 09:28:14 -0500154
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;
Chris Cain7b00cde2023-03-14 15:47:12 -0500162 bool isRunning = false;
Eddie James432dc482021-11-19 15:29:31 -0600163 if (eventState ==
164 static_cast<EventState>(
165 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_IN_SERVICE))
166 {
167 log<level::INFO>(
Chris Cain8b508bf2022-05-26 14:01:31 -0500168 fmt::format("PLDM: OCC{} is RUNNING", instance).c_str());
Chris Cain7b00cde2023-03-14 15:47:12 -0500169 isRunning = true;
Eddie James432dc482021-11-19 15:29:31 -0600170 }
171 else if (eventState ==
172 static_cast<EventState>(
173 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_STOPPED))
174 {
Chris Cain8b508bf2022-05-26 14:01:31 -0500175 log<level::INFO>(
176 fmt::format("PLDM: OCC{} has now STOPPED", instance)
177 .c_str());
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);
Chris Cainbae4d072022-02-28 09:46:50 -0600191 }
192 else
193 {
194 log<level::INFO>(
195 fmt::format("PLDM: Unexpected PLDM state {} for OCC{}",
Chris Cain8b508bf2022-05-26 14:01:31 -0500196 eventState, instance)
Chris Cainbae4d072022-02-28 09:46:50 -0600197 .c_str());
198 }
Chris Cain7b00cde2023-03-14 15:47:12 -0500199
200 if (!open_power::occ::utils::isHostRunning())
201 {
202 log<level::INFO>("PLDM: HOST is not running");
203 isRunning = false;
204 }
205 callBack(instance, isRunning);
206
Eddie Jamescbad2192021-10-07 09:39:39 -0500207 return;
208 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500209 }
Eddie James432dc482021-11-19 15:29:31 -0600210
211 if (msgSensorOffset == SBESensorOffset)
Eddie Jamescbad2192021-10-07 09:39:39 -0500212 {
213 auto sensorEntry = sensorToSBEInstance.find(sensorId);
214
Eddie James432dc482021-11-19 15:29:31 -0600215 if (sensorEntry != sensorToSBEInstance.end())
Eddie Jamescbad2192021-10-07 09:39:39 -0500216 {
Chris Cain12d0b822022-04-22 17:29:18 -0500217 const uint8_t instance = sensorEntry->second;
218 auto match = std::find(outstandingHResets.begin(),
219 outstandingHResets.end(), instance);
220 if (match != outstandingHResets.end())
Eddie James432dc482021-11-19 15:29:31 -0600221 {
Chris Cain12d0b822022-04-22 17:29:18 -0500222 outstandingHResets.erase(match);
223 if (eventState == static_cast<EventState>(SBE_HRESET_NOT_READY))
224 {
225 log<level::INFO>(
226 fmt::format("pldm: HRESET is NOT READY (OCC{})",
227 instance)
228 .c_str());
229 }
230 else if (eventState ==
231 static_cast<EventState>(SBE_HRESET_READY))
232 {
233 sbeCallBack(instance, true);
234 }
235 else if (eventState ==
236 static_cast<EventState>(SBE_HRESET_FAILED))
237 {
238 sbeCallBack(instance, false);
239 }
Eddie James432dc482021-11-19 15:29:31 -0600240 }
Chris Cain12d0b822022-04-22 17:29:18 -0500241 // else request was not from us
Eddie Jamescbad2192021-10-07 09:39:39 -0500242 }
243 }
Patrick Williams05e95592021-09-02 09:28:14 -0500244}
245
Patrick Williamsaf408082022-07-22 19:26:54 -0500246void Interface::hostStateEvent(sdbusplus::message_t& msg)
Chris Cain157467d2022-06-24 11:25:23 -0500247{
248 std::map<std::string, std::variant<std::string>> properties{};
249 std::string interface;
250 msg.read(interface, properties);
251 const auto stateEntry = properties.find("CurrentHostState");
252 if (stateEntry != properties.end())
253 {
254 auto stateEntryValue = stateEntry->second;
255 auto propVal = std::get<std::string>(stateEntryValue);
256 if (propVal == "xyz.openbmc_project.State.Host.HostState.Off")
257 {
258 clearData();
259 }
260 }
261}
262
Chris Cainbae4d072022-02-28 09:46:50 -0600263void Interface::clearData()
264{
Chris Cain72d01aa2022-06-14 16:28:03 -0500265 if (!sensorToOCCInstance.empty())
266 {
267 log<level::INFO>(
268 fmt::format("clearData: Clearing sensorToOCCInstance ({} entries)",
269 sensorToOCCInstance.size())
270 .c_str());
271 for (auto entry : sensorToOCCInstance)
272 {
273 log<level::INFO>(
274 fmt::format("clearData: OCC{} / sensorID: 0x{:04X}",
275 entry.second, entry.first)
276 .c_str());
277 }
278 sensorToOCCInstance.clear();
279 }
280 if (!occInstanceToEffecter.empty())
281 {
282 log<level::DEBUG>(
283 fmt::format(
284 "clearData: Clearing occInstanceToEffecter ({} entries)",
285 occInstanceToEffecter.size())
286 .c_str());
287 occInstanceToEffecter.clear();
288 }
289 if (!sensorToSBEInstance.empty())
290 {
291 log<level::DEBUG>(
292 fmt::format("clearData: Clearing sensorToSBEInstance ({} entries)",
293 sensorToSBEInstance.size())
294 .c_str());
295 sensorToSBEInstance.clear();
296 }
297 if (!sbeInstanceToEffecter.empty())
298 {
299 log<level::DEBUG>(
300 fmt::format(
301 "clearData: Clearing sbeInstanceToEffecter ({} entries)",
302 sbeInstanceToEffecter.size())
303 .c_str());
304 sbeInstanceToEffecter.clear();
305 }
Chris Cainbae4d072022-02-28 09:46:50 -0600306}
307
Eddie James432dc482021-11-19 15:29:31 -0600308void Interface::fetchEffecterInfo(uint16_t stateSetId,
Eddie Jamescbad2192021-10-07 09:39:39 -0500309 InstanceToEffecter& instanceToEffecterMap,
310 CompositeEffecterCount& effecterCount,
311 uint8_t& stateIdPos)
Patrick Williams05e95592021-09-02 09:28:14 -0500312{
Eddie Jamescbad2192021-10-07 09:39:39 -0500313 PdrList pdrs{};
314
315 auto& bus = open_power::occ::utils::getBus();
316 try
317 {
318 auto method = bus.new_method_call(
319 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
320 "xyz.openbmc_project.PLDM.PDR", "FindStateEffecterPDR");
Chris Cainbae4d072022-02-28 09:46:50 -0600321 method.append(tid, static_cast<uint16_t>(PLDM_ENTITY_PROC), stateSetId);
Eddie Jamescbad2192021-10-07 09:39:39 -0500322
323 auto responseMsg = bus.call(method);
324 responseMsg.read(pdrs);
325 }
Patrick Williamsaf408082022-07-22 19:26:54 -0500326 catch (const sdbusplus::exception_t& e)
Eddie Jamescbad2192021-10-07 09:39:39 -0500327 {
328 log<level::ERR>("pldm: Failed to fetch the state effecter PDRs",
329 entry("ERROR=%s", e.what()));
330 }
331
332 if (!pdrs.size())
333 {
334 log<level::ERR>("pldm: state effecter PDRs not present");
335 return;
336 }
337
Patrick Williams05e95592021-09-02 09:28:14 -0500338 bool offsetFound = false;
George Liuf3a4a692021-12-28 13:59:51 +0800339 auto stateEffecterPDR =
Patrick Williams05e95592021-09-02 09:28:14 -0500340 reinterpret_cast<const pldm_state_effecter_pdr*>(pdrs.front().data());
George Liuf3a4a692021-12-28 13:59:51 +0800341 auto possibleStatesPtr = stateEffecterPDR->possible_states;
342 for (auto offset = 0; offset < stateEffecterPDR->composite_effecter_count;
343 offset++)
Patrick Williams05e95592021-09-02 09:28:14 -0500344 {
345 auto possibleStates =
346 reinterpret_cast<const state_effecter_possible_states*>(
347 possibleStatesPtr);
348
Eddie Jamescbad2192021-10-07 09:39:39 -0500349 if (possibleStates->state_set_id == stateSetId)
Patrick Williams05e95592021-09-02 09:28:14 -0500350 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500351 stateIdPos = offset;
George Liuf3a4a692021-12-28 13:59:51 +0800352 effecterCount = stateEffecterPDR->composite_effecter_count;
Patrick Williams05e95592021-09-02 09:28:14 -0500353 offsetFound = true;
354 break;
355 }
356 possibleStatesPtr += sizeof(possibleStates->state_set_id) +
357 sizeof(possibleStates->possible_states_size) +
358 possibleStates->possible_states_size;
359 }
360
361 if (!offsetFound)
362 {
363 return;
364 }
365
Chris Cain0f516522022-02-07 14:48:28 -0600366 std::map<uint32_t, EffecterID> entityInstMap{};
Patrick Williams05e95592021-09-02 09:28:14 -0500367 for (auto& pdr : pdrs)
368 {
369 auto pdrPtr =
370 reinterpret_cast<const pldm_state_effecter_pdr*>(pdr.data());
Chris Cain72d01aa2022-06-14 16:28:03 -0500371 uint32_t key = pdrPtr->effecter_id;
Patrick Williams05e95592021-09-02 09:28:14 -0500372 entityInstMap.emplace(key, static_cast<SensorID>(pdrPtr->effecter_id));
373 }
374
375 open_power::occ::instanceID position = start;
376 for (auto const& pair : entityInstMap)
377 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500378 instanceToEffecterMap.emplace(position, pair.second);
Patrick Williams05e95592021-09-02 09:28:14 -0500379 position++;
380 }
381}
382
383std::vector<uint8_t>
Chris Cain8b508bf2022-05-26 14:01:31 -0500384 Interface::prepareSetEffecterReq(EffecterID effecterId,
Patrick Williams05e95592021-09-02 09:28:14 -0500385 CompositeEffecterCount effecterCount,
Eddie Jamescbad2192021-10-07 09:39:39 -0500386 uint8_t stateIdPos, uint8_t stateSetValue)
Patrick Williams05e95592021-09-02 09:28:14 -0500387{
Chris Cain8b508bf2022-05-26 14:01:31 -0500388 if (!getMctpInstanceId())
389 {
390 return std::vector<uint8_t>();
391 }
392
Patrick Williams05e95592021-09-02 09:28:14 -0500393 std::vector<uint8_t> request(
394 sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(effecterCount) +
395 (effecterCount * sizeof(set_effecter_state_field)));
396 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
397 std::vector<set_effecter_state_field> stateField;
398
399 for (uint8_t effecterPos = 0; effecterPos < effecterCount; effecterPos++)
400 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500401 if (effecterPos == stateIdPos)
Patrick Williams05e95592021-09-02 09:28:14 -0500402 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500403 stateField.emplace_back(
404 set_effecter_state_field{PLDM_REQUEST_SET, stateSetValue});
Patrick Williams05e95592021-09-02 09:28:14 -0500405 }
406 else
407 {
408 stateField.emplace_back(
409 set_effecter_state_field{PLDM_NO_CHANGE, 0});
410 }
411 }
412 auto rc = encode_set_state_effecter_states_req(
Chris Cain8b508bf2022-05-26 14:01:31 -0500413 mctpInstance.value(), effecterId, effecterCount, stateField.data(),
414 requestMsg);
Patrick Williams05e95592021-09-02 09:28:14 -0500415 if (rc != PLDM_SUCCESS)
416 {
417 log<level::ERR>("encode set effecter states request returned error ",
418 entry("RC=%d", rc));
419 request.clear();
420 }
421 return request;
422}
423
424void Interface::resetOCC(open_power::occ::instanceID occInstanceId)
425{
Chris Cainbae4d072022-02-28 09:46:50 -0600426 if (open_power::occ::utils::isHostRunning())
Patrick Williams05e95592021-09-02 09:28:14 -0500427 {
Chris Cainbae4d072022-02-28 09:46:50 -0600428 if (!isPDREffecterCacheValid())
429 {
430 fetchEffecterInfo(PLDM_STATE_SET_BOOT_RESTART_CAUSE,
431 occInstanceToEffecter, OCCEffecterCount,
432 bootRestartPosition);
433 }
Patrick Williams05e95592021-09-02 09:28:14 -0500434
Chris Cainbae4d072022-02-28 09:46:50 -0600435 // Find the matching effecter for the OCC instance
436 auto effecterEntry = occInstanceToEffecter.find(occInstanceId);
437 if (effecterEntry == occInstanceToEffecter.end())
438 {
439 log<level::ERR>(
440 fmt::format(
441 "pldm: Failed to find a matching effecter for OCC instance {}",
442 occInstanceId)
443 .c_str());
444
445 return;
446 }
447
Chris Cainbae4d072022-02-28 09:46:50 -0600448 // Prepare the SetStateEffecterStates request to reset the OCC
449 auto request = prepareSetEffecterReq(
Chris Cain8b508bf2022-05-26 14:01:31 -0500450 effecterEntry->second, OCCEffecterCount, bootRestartPosition,
451 PLDM_STATE_SET_BOOT_RESTART_CAUSE_WARM_RESET);
Chris Cainbae4d072022-02-28 09:46:50 -0600452
453 if (request.empty())
454 {
455 log<level::ERR>(
456 "pldm: SetStateEffecterStates OCC reset request empty");
457 return;
458 }
459
460 // Send request to reset the OCCs/PM Complex (ignore response)
461 sendPldm(request, occInstanceId, false);
462 }
463 else
Patrick Williams05e95592021-09-02 09:28:14 -0500464 {
465 log<level::ERR>(
Chris Cainbae4d072022-02-28 09:46:50 -0600466 fmt::format("resetOCC: HOST is not running (OCC{})", occInstanceId)
Chris Cain0f516522022-02-07 14:48:28 -0600467 .c_str());
Chris Cainbae4d072022-02-28 09:46:50 -0600468 clearData();
Patrick Williams05e95592021-09-02 09:28:14 -0500469 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500470}
471
472void Interface::sendHRESET(open_power::occ::instanceID sbeInstanceId)
473{
Chris Cainbae4d072022-02-28 09:46:50 -0600474 if (open_power::occ::utils::isHostRunning())
Eddie Jamescbad2192021-10-07 09:39:39 -0500475 {
Chris Cainbae4d072022-02-28 09:46:50 -0600476 if (sbeInstanceToEffecter.empty())
477 {
478 fetchEffecterInfo(PLDM_OEM_IBM_SBE_MAINTENANCE_STATE,
479 sbeInstanceToEffecter, SBEEffecterCount,
480 sbeMaintenanceStatePosition);
481 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500482
Chris Cainbae4d072022-02-28 09:46:50 -0600483 auto effecterEntry = sbeInstanceToEffecter.find(sbeInstanceId);
484 if (effecterEntry == sbeInstanceToEffecter.end())
485 {
486 log<level::ERR>(
487 "pldm: Failed to find a matching effecter for SBE instance",
488 entry("SBE=%d", sbeInstanceId));
489 return;
490 }
491
Chris Cainbae4d072022-02-28 09:46:50 -0600492 // Prepare the SetStateEffecterStates request to HRESET the SBE
493 auto request = prepareSetEffecterReq(
Chris Cain8b508bf2022-05-26 14:01:31 -0500494 effecterEntry->second, SBEEffecterCount,
Chris Cainbae4d072022-02-28 09:46:50 -0600495 sbeMaintenanceStatePosition, SBE_RETRY_REQUIRED);
496
497 if (request.empty())
498 {
499 log<level::ERR>(
500 "pldm: SetStateEffecterStates HRESET request empty");
501 return;
502 }
503
504 // Send request to issue HRESET of SBE (ignore response)
505 sendPldm(request, sbeInstanceId, false);
Chris Cain12d0b822022-04-22 17:29:18 -0500506 outstandingHResets.insert(sbeInstanceId);
Chris Cainbae4d072022-02-28 09:46:50 -0600507 }
508 else
Eddie Jamescbad2192021-10-07 09:39:39 -0500509 {
Chris Cainbae4d072022-02-28 09:46:50 -0600510 log<level::ERR>(fmt::format("sendHRESET: HOST is not running (OCC{})",
511 sbeInstanceId)
512 .c_str());
513 clearData();
Eddie Jamescbad2192021-10-07 09:39:39 -0500514 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500515}
516
Chris Cain8b508bf2022-05-26 14:01:31 -0500517bool Interface::getMctpInstanceId()
Eddie Jamescbad2192021-10-07 09:39:39 -0500518{
Chris Cain8b508bf2022-05-26 14:01:31 -0500519 if (!mctpInstance)
Patrick Williams05e95592021-09-02 09:28:14 -0500520 {
Chris Cain8b508bf2022-05-26 14:01:31 -0500521 // Request new instance ID
522 auto& bus = open_power::occ::utils::getBus();
523 try
524 {
525 auto method = bus.new_method_call(
526 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
527 "xyz.openbmc_project.PLDM.Requester", "GetInstanceId");
528 method.append(mctpEid);
529 auto reply = bus.call(method);
530 uint8_t newInstanceId;
531 reply.read(newInstanceId);
532 mctpInstance = newInstanceId;
533 log<level::INFO>(fmt::format("pldm: got new InstanceId: {}",
534 mctpInstance.value())
535 .c_str());
536 }
Patrick Williamsaf408082022-07-22 19:26:54 -0500537 catch (const sdbusplus::exception_t& e)
Chris Cain8b508bf2022-05-26 14:01:31 -0500538 {
539 log<level::ERR>(
540 fmt::format("pldm: GetInstanceId failed: {}", e.what())
541 .c_str());
542 return false;
543 }
Patrick Williams05e95592021-09-02 09:28:14 -0500544 }
545
Eddie Jamescbad2192021-10-07 09:39:39 -0500546 return true;
547}
Patrick Williams05e95592021-09-02 09:28:14 -0500548
Chris Cainbae4d072022-02-28 09:46:50 -0600549void Interface::sendPldm(const std::vector<uint8_t>& request,
550 const uint8_t instance, const bool rspExpected)
Eddie Jamescbad2192021-10-07 09:39:39 -0500551{
Chris Cain8b508bf2022-05-26 14:01:31 -0500552 if (!mctpInstance)
553 {
554 log<level::ERR>("sendPldm: No MCTP Instance ID found!");
555 return;
556 }
557
Chris Cainc9dc4412023-03-06 15:56:34 -0600558 // Connect to MCTP socket
Chris Cainbae4d072022-02-28 09:46:50 -0600559 pldmFd = pldm_open();
560 auto openErrno = errno;
561 if (pldmFd == PLDM_REQUESTER_OPEN_FAIL)
Patrick Williams05e95592021-09-02 09:28:14 -0500562 {
Chris Caind1b68262022-02-28 09:56:50 -0600563 log<level::ERR>(
Chris Cainbae4d072022-02-28 09:46:50 -0600564 fmt::format(
565 "sendPldm: Failed to connect to MCTP socket, errno={}/{}",
566 openErrno, strerror(openErrno))
Chris Caind1b68262022-02-28 09:56:50 -0600567 .c_str());
Patrick Williams05e95592021-09-02 09:28:14 -0500568 return;
569 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500570
Patrick Williams05e95592021-09-02 09:28:14 -0500571 // Send the PLDM request message to HBRT
Chris Cainbae4d072022-02-28 09:46:50 -0600572 if (rspExpected)
Patrick Williams05e95592021-09-02 09:28:14 -0500573 {
Chris Cainbae4d072022-02-28 09:46:50 -0600574 // Register callback when response is available
575 registerPldmRspCallback();
576
577 // Send PLDM request
578 log<level::INFO>(
579 fmt::format(
580 "sendPldm: calling pldm_send(OCC{}, instance:{}, {} bytes)",
Chris Cain8b508bf2022-05-26 14:01:31 -0500581 instance, mctpInstance.value(), request.size())
Chris Cainbae4d072022-02-28 09:46:50 -0600582 .c_str());
583 pldmResponseReceived = false;
584 pldmResponseTimeout = false;
585 pldmResponseOcc = instance;
586 auto pldmRc =
587 pldm_send(mctpEid, pldmFd, request.data(), request.size());
588 auto sendErrno = errno;
589 if (pldmRc != PLDM_REQUESTER_SUCCESS)
590 {
591 log<level::ERR>(
592 fmt::format(
593 "sendPldm: pldm_send failed with rc={} and errno={}/{}",
594 pldmRc, sendErrno, strerror(sendErrno))
595 .c_str());
596 pldmClose();
597 return;
598 }
599
600 // start timer waiting for the response
601 using namespace std::literals::chrono_literals;
Chris Cainbd551de2022-04-26 13:41:16 -0500602 pldmRspTimer.restartOnce(8s);
Chris Cainbae4d072022-02-28 09:46:50 -0600603
604 // Wait for response/timeout
605 }
606 else // not expecting the response
607 {
608 log<level::INFO>(
609 fmt::format(
610 "sendPldm: calling pldm_send(mctpID:{}, fd:{}, {} bytes) for OCC{}",
611 mctpEid, pldmFd, request.size(), instance)
612 .c_str());
613 auto rc = pldm_send(mctpEid, pldmFd, request.data(), request.size());
614 auto sendErrno = errno;
Chris Caind1b68262022-02-28 09:56:50 -0600615 if (rc)
616 {
617 log<level::ERR>(
618 fmt::format(
Chris Cainbae4d072022-02-28 09:46:50 -0600619 "sendPldm: pldm_send(mctpID:{}, fd:{}, {} bytes) failed with rc={} and errno={}/{}",
620 mctpEid, pldmFd, request.size(), rc, sendErrno,
621 strerror(sendErrno))
Chris Caind1b68262022-02-28 09:56:50 -0600622 .c_str());
623 }
Chris Cain8b508bf2022-05-26 14:01:31 -0500624 else
625 {
626 // Not waiting for response, instance ID should be freed
627 mctpInstance = std::nullopt;
628 }
Chris Cainbae4d072022-02-28 09:46:50 -0600629 pldmClose();
630 }
631}
Patrick Williams05e95592021-09-02 09:28:14 -0500632
Chris Cainbae4d072022-02-28 09:46:50 -0600633// Attaches the FD to event loop and registers the callback handler
634void Interface::registerPldmRspCallback()
635{
636 decltype(eventSource.get()) sourcePtr = nullptr;
637 auto rc = sd_event_add_io(event.get(), &sourcePtr, pldmFd, EPOLLIN,
638 pldmRspCallback, this);
639 if (rc < 0)
640 {
641 log<level::ERR>(
642 fmt::format(
643 "registerPldmRspCallback: sd_event_add_io: Error({})={} : fd={}",
644 rc, strerror(-rc), pldmFd)
645 .c_str());
Chris Caind1b68262022-02-28 09:56:50 -0600646 }
647 else
Patrick Williams05e95592021-09-02 09:28:14 -0500648 {
Chris Cainbae4d072022-02-28 09:46:50 -0600649 // puts sourcePtr in the event source.
650 eventSource.reset(sourcePtr);
651 }
652}
653
654// Add a timer to the event loop, default 30s.
655void Interface::pldmRspExpired()
656{
657 if (!pldmResponseReceived)
658 {
659 log<level::ERR>(
660 fmt::format(
661 "pldmRspExpired: timerCallback - timeout waiting for pldm response for OCC{}",
662 pldmResponseOcc)
663 .c_str());
664 pldmResponseTimeout = true;
665 if (pldmFd)
666 {
667 pldmClose();
668 }
669 }
670 return;
671};
672
673void Interface::pldmClose()
674{
675 if (pldmRspTimer.isEnabled())
676 {
677 // stop PLDM response timer
678 pldmRspTimer.setEnabled(false);
679 }
680 close(pldmFd);
681 pldmFd = -1;
682 eventSource.reset();
683}
684
685int Interface::pldmRspCallback(sd_event_source* /*es*/, int fd,
686 uint32_t revents, void* userData)
687{
688 if (!(revents & EPOLLIN))
689 {
690 log<level::INFO>(
691 fmt::format("pldmRspCallback - revents={:08X}", revents).c_str());
692 return -1;
693 }
694
695 auto pldmIface = static_cast<Interface*>(userData);
696
Chris Cain8b508bf2022-05-26 14:01:31 -0500697 if (!pldmIface->mctpInstance)
698 {
699 log<level::ERR>(
700 "pldmRspCallback: No outstanding MCTP Instance ID found");
701 return -1;
702 }
703
Chris Cainbae4d072022-02-28 09:46:50 -0600704 uint8_t* responseMsg = nullptr;
705 size_t responseMsgSize{};
706
707 log<level::INFO>(
708 fmt::format("pldmRspCallback: calling pldm_recv() instance:{}",
Chris Cain8b508bf2022-05-26 14:01:31 -0500709 pldmIface->mctpInstance.value())
Chris Cainbae4d072022-02-28 09:46:50 -0600710 .c_str());
Chris Cain8b508bf2022-05-26 14:01:31 -0500711 auto rc = pldm_recv(mctpEid, fd, pldmIface->mctpInstance.value(),
712 &responseMsg, &responseMsgSize);
Chris Cainbae4d072022-02-28 09:46:50 -0600713 int lastErrno = errno;
714 if (rc)
715 {
716 log<level::ERR>(
717 fmt::format(
718 "pldmRspCallback: pldm_recv failed with rc={}, errno={}/{}", rc,
719 lastErrno, strerror(lastErrno))
720 .c_str());
721 return -1;
722 }
Chris Cain8b508bf2022-05-26 14:01:31 -0500723
724 // We got the response for the PLDM request msg that was sent
Chris Cainbae4d072022-02-28 09:46:50 -0600725 log<level::INFO>(
726 fmt::format("pldmRspCallback: pldm_recv() rsp was {} bytes",
727 responseMsgSize)
728 .c_str());
729
730 if (pldmIface->pldmRspTimer.isEnabled())
731 {
732 // stop PLDM response timer
733 pldmIface->pldmRspTimer.setEnabled(false);
734 }
735
Chris Cain8b508bf2022-05-26 14:01:31 -0500736 // instance ID should be freed
737 pldmIface->mctpInstance = std::nullopt;
738
Chris Cainbae4d072022-02-28 09:46:50 -0600739 // Set pointer to autodelete
740 std::unique_ptr<uint8_t, decltype(std::free)*> responseMsgPtr{responseMsg,
741 std::free};
742
Chris Cainbae4d072022-02-28 09:46:50 -0600743 auto response = reinterpret_cast<pldm_msg*>(responseMsgPtr.get());
744 if (response->payload[0] != PLDM_SUCCESS)
745 {
746 log<level::ERR>(
747 fmt::format("pldmRspCallback: payload[0] was not success: {}",
748 response->payload[0])
749 .c_str());
750 pldmIface->pldmClose();
751 return -1;
752 }
753
754 // Decode the response
755 uint8_t compCode = 0, sensorCount = 1;
756 get_sensor_state_field field[6];
757 responseMsgSize -= sizeof(pldm_msg_hdr);
758 auto msgRc = decode_get_state_sensor_readings_resp(
759 response, responseMsgSize, &compCode, &sensorCount, field);
760 if ((msgRc != PLDM_SUCCESS) || (compCode != PLDM_SUCCESS))
761 {
762 log<level::ERR>(
763 fmt::format(
764 "pldmRspCallback: decode_get_state_sensor_readings failed with rc={} and compCode={}",
765 msgRc, compCode)
766 .c_str());
767 pldmIface->pldmClose();
768 return -1;
769 }
770
771 pldmIface->pldmClose();
772
773 const uint8_t instance = pldmIface->pldmResponseOcc;
774 const uint8_t occSensorState = field[0].present_state;
775 pldmIface->pldmResponseReceived = true;
776
777 if (occSensorState == PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_IN_SERVICE)
778 {
779 log<level::INFO>(
780 fmt::format("pldmRspCallback: OCC{} is RUNNING", instance).c_str());
781 pldmIface->callBack(instance, true);
782 }
Chris Cain733b2012022-05-04 11:54:06 -0500783 else if (occSensorState ==
784 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_DORMANT)
785 {
786 log<level::INFO>(
787 fmt::format(
788 "pldmRspCallback: OCC{} has now STOPPED and system is in SAFE MODE",
789 instance)
790 .c_str());
Sheldon Bailey31a2f132022-05-20 11:31:52 -0500791
792 // Setting safe mode true
793 pldmIface->safeModeCallBack(true);
794
Chris Cain733b2012022-05-04 11:54:06 -0500795 pldmIface->callBack(instance, false);
796 }
Chris Cainbae4d072022-02-28 09:46:50 -0600797 else
798 {
799 log<level::INFO>(
Chris Cain8b508bf2022-05-26 14:01:31 -0500800 fmt::format(
801 "pldmRspCallback: OCC{} is not running (sensor state:{})",
802 instance, occSensorState)
Chris Cainbae4d072022-02-28 09:46:50 -0600803 .c_str());
Chris Cainc9dc4412023-03-06 15:56:34 -0600804 if (occSensorState != PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_STOPPED)
805 {
806 const size_t rspLength = responseMsgSize + sizeof(pldm_msg_hdr);
807 std::vector<std::uint8_t> pldmResponse(rspLength);
808 memcpy(&pldmResponse[0], reinterpret_cast<std::uint8_t*>(response),
809 rspLength);
810 log<level::ERR>(
811 fmt::format(
812 "pldmRspCallback: Bad State - PLDM response ({} bytes) for OCC{}:",
813 rspLength, instance)
814 .c_str());
815 dump_hex(pldmResponse);
816 }
Chris Cainbae4d072022-02-28 09:46:50 -0600817 pldmIface->callBack(instance, false);
818 }
819
820 return 0;
821};
822
823std::vector<uint8_t> Interface::encodeGetStateSensorRequest(uint8_t instance,
824 uint16_t sensorId)
825{
Chris Cain8b508bf2022-05-26 14:01:31 -0500826 if (!getMctpInstanceId())
827 {
828 log<level::ERR>(
829 "encodeGetStateSensorRequest: failed to getMctpInstanceId");
830 return std::vector<uint8_t>();
831 }
832
Chris Cainbae4d072022-02-28 09:46:50 -0600833 bitfield8_t sRearm = {0};
834 const size_t msgSize =
835 sizeof(pldm_msg_hdr) + PLDM_GET_STATE_SENSOR_READINGS_REQ_BYTES;
836 std::vector<uint8_t> request(msgSize);
Chris Cain8b508bf2022-05-26 14:01:31 -0500837
Chris Cainbae4d072022-02-28 09:46:50 -0600838 auto msg = reinterpret_cast<pldm_msg*>(request.data());
Chris Cain8b508bf2022-05-26 14:01:31 -0500839 auto msgRc = encode_get_state_sensor_readings_req(mctpInstance.value(),
840 sensorId, sRearm, 0, msg);
Chris Cainbae4d072022-02-28 09:46:50 -0600841 if (msgRc != PLDM_SUCCESS)
842 {
843 log<level::ERR>(
844 fmt::format(
845 "encodeGetStateSensorRequest: Failed to encode sensorId:0x{:08X} for OCC{} (rc={})",
846 sensorId, instance, msgRc)
847 .c_str());
848 }
849 return request;
850}
851
852// Initiate query of the specified OCC Active Sensor
853void Interface::checkActiveSensor(uint8_t instance)
854{
855 static bool tracedOnce = false;
856 if (pldmFd > 0)
857 {
858 if (!tracedOnce)
Chris Caind1b68262022-02-28 09:56:50 -0600859 {
860 log<level::ERR>(
861 fmt::format(
Chris Cainbae4d072022-02-28 09:46:50 -0600862 "checkActiveSensor: already waiting on OCC{} (fd={})",
863 pldmResponseOcc, pldmFd)
Chris Caind1b68262022-02-28 09:56:50 -0600864 .c_str());
Chris Cainbae4d072022-02-28 09:46:50 -0600865 tracedOnce = true;
Chris Caind1b68262022-02-28 09:56:50 -0600866 }
Chris Cainbae4d072022-02-28 09:46:50 -0600867 return;
868 }
869 tracedOnce = false;
870
871 if (!isOCCSensorCacheValid())
872 {
873 fetchSensorInfo(PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS,
874 sensorToOCCInstance, OCCSensorOffset);
875 }
876
877 // look up sensor id (key) based on instance
878 auto entry = std::find_if(
879 sensorToOCCInstance.begin(), sensorToOCCInstance.end(),
880 [instance](const auto& entry) { return instance == entry.second; });
881 if (entry != sensorToOCCInstance.end())
882 {
883 // Query the OCC Active Sensor state for this instance
884 // SensorID sID = entry->first;
885 log<level::INFO>(
886 fmt::format("checkActiveSensor: OCC{} / sensorID: 0x{:04X}",
887 instance, entry->first)
888 .c_str());
889
Chris Cainbae4d072022-02-28 09:46:50 -0600890 // Encode GetStateSensorReadings PLDM message
891 auto request = encodeGetStateSensorRequest(instance, entry->first);
892 if (request.empty())
893 {
894 return;
895 }
896
897 // Send request to PLDM and setup callback for response
898 sendPldm(request, instance, true);
899 }
900 else
901 {
902 log<level::ERR>(
903 fmt::format(
904 "checkActiveSensor: Unable to find PLDM sensor for OCC{}",
905 instance)
906 .c_str());
Chris Cain8cf74962022-06-29 08:45:16 -0500907 log<level::INFO>(
908 "checkActiveSensor: fetching STATE_SET_OPERATIONAL_RUNNING_STATUS");
909 fetchSensorInfo(PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS,
910 sensorToOCCInstance, OCCSensorOffset);
Patrick Williams05e95592021-09-02 09:28:14 -0500911 }
Patrick Williams05e95592021-09-02 09:28:14 -0500912}
913
914} // namespace pldm