blob: 3c71eb9b4382b00d6449b793f5e695256d18ef83 [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;
Patrick Williamsa49c9872023-05-10 07:50:35 -0500125 for (const auto& pair : entityInstMap)
Patrick Williams05e95592021-09-02 09:28:14 -0500126 {
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
Chris Cain7b00cde2023-03-14 15:47:12 -0500200 callBack(instance, isRunning);
201
Eddie Jamescbad2192021-10-07 09:39:39 -0500202 return;
203 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500204 }
Eddie James432dc482021-11-19 15:29:31 -0600205
206 if (msgSensorOffset == SBESensorOffset)
Eddie Jamescbad2192021-10-07 09:39:39 -0500207 {
208 auto sensorEntry = sensorToSBEInstance.find(sensorId);
209
Eddie James432dc482021-11-19 15:29:31 -0600210 if (sensorEntry != sensorToSBEInstance.end())
Eddie Jamescbad2192021-10-07 09:39:39 -0500211 {
Chris Cain12d0b822022-04-22 17:29:18 -0500212 const uint8_t instance = sensorEntry->second;
213 auto match = std::find(outstandingHResets.begin(),
214 outstandingHResets.end(), instance);
215 if (match != outstandingHResets.end())
Eddie James432dc482021-11-19 15:29:31 -0600216 {
Chris Cain12d0b822022-04-22 17:29:18 -0500217 outstandingHResets.erase(match);
218 if (eventState == static_cast<EventState>(SBE_HRESET_NOT_READY))
219 {
220 log<level::INFO>(
221 fmt::format("pldm: HRESET is NOT READY (OCC{})",
222 instance)
223 .c_str());
224 }
225 else if (eventState ==
226 static_cast<EventState>(SBE_HRESET_READY))
227 {
228 sbeCallBack(instance, true);
229 }
230 else if (eventState ==
231 static_cast<EventState>(SBE_HRESET_FAILED))
232 {
233 sbeCallBack(instance, false);
234 }
Eddie James432dc482021-11-19 15:29:31 -0600235 }
Chris Cain12d0b822022-04-22 17:29:18 -0500236 // else request was not from us
Eddie Jamescbad2192021-10-07 09:39:39 -0500237 }
238 }
Patrick Williams05e95592021-09-02 09:28:14 -0500239}
240
Patrick Williamsaf408082022-07-22 19:26:54 -0500241void Interface::hostStateEvent(sdbusplus::message_t& msg)
Chris Cain157467d2022-06-24 11:25:23 -0500242{
243 std::map<std::string, std::variant<std::string>> properties{};
244 std::string interface;
245 msg.read(interface, properties);
246 const auto stateEntry = properties.find("CurrentHostState");
247 if (stateEntry != properties.end())
248 {
249 auto stateEntryValue = stateEntry->second;
250 auto propVal = std::get<std::string>(stateEntryValue);
251 if (propVal == "xyz.openbmc_project.State.Host.HostState.Off")
252 {
253 clearData();
254 }
255 }
256}
257
Chris Cainbae4d072022-02-28 09:46:50 -0600258void Interface::clearData()
259{
Chris Cain72d01aa2022-06-14 16:28:03 -0500260 if (!sensorToOCCInstance.empty())
261 {
262 log<level::INFO>(
263 fmt::format("clearData: Clearing sensorToOCCInstance ({} entries)",
264 sensorToOCCInstance.size())
265 .c_str());
266 for (auto entry : sensorToOCCInstance)
267 {
268 log<level::INFO>(
269 fmt::format("clearData: OCC{} / sensorID: 0x{:04X}",
270 entry.second, entry.first)
271 .c_str());
Chris Cain082a6ca2023-03-21 10:27:26 -0500272 callBack(entry.second, false);
Chris Cain72d01aa2022-06-14 16:28:03 -0500273 }
274 sensorToOCCInstance.clear();
275 }
276 if (!occInstanceToEffecter.empty())
277 {
278 log<level::DEBUG>(
279 fmt::format(
280 "clearData: Clearing occInstanceToEffecter ({} entries)",
281 occInstanceToEffecter.size())
282 .c_str());
283 occInstanceToEffecter.clear();
284 }
285 if (!sensorToSBEInstance.empty())
286 {
287 log<level::DEBUG>(
288 fmt::format("clearData: Clearing sensorToSBEInstance ({} entries)",
289 sensorToSBEInstance.size())
290 .c_str());
291 sensorToSBEInstance.clear();
292 }
293 if (!sbeInstanceToEffecter.empty())
294 {
295 log<level::DEBUG>(
296 fmt::format(
297 "clearData: Clearing sbeInstanceToEffecter ({} entries)",
298 sbeInstanceToEffecter.size())
299 .c_str());
300 sbeInstanceToEffecter.clear();
301 }
Chris Cainbae4d072022-02-28 09:46:50 -0600302}
303
Eddie James432dc482021-11-19 15:29:31 -0600304void Interface::fetchEffecterInfo(uint16_t stateSetId,
Eddie Jamescbad2192021-10-07 09:39:39 -0500305 InstanceToEffecter& instanceToEffecterMap,
306 CompositeEffecterCount& effecterCount,
307 uint8_t& stateIdPos)
Patrick Williams05e95592021-09-02 09:28:14 -0500308{
Eddie Jamescbad2192021-10-07 09:39:39 -0500309 PdrList pdrs{};
310
311 auto& bus = open_power::occ::utils::getBus();
312 try
313 {
314 auto method = bus.new_method_call(
315 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
316 "xyz.openbmc_project.PLDM.PDR", "FindStateEffecterPDR");
Chris Cainbae4d072022-02-28 09:46:50 -0600317 method.append(tid, static_cast<uint16_t>(PLDM_ENTITY_PROC), stateSetId);
Eddie Jamescbad2192021-10-07 09:39:39 -0500318
319 auto responseMsg = bus.call(method);
320 responseMsg.read(pdrs);
321 }
Patrick Williamsaf408082022-07-22 19:26:54 -0500322 catch (const sdbusplus::exception_t& e)
Eddie Jamescbad2192021-10-07 09:39:39 -0500323 {
324 log<level::ERR>("pldm: Failed to fetch the state effecter PDRs",
325 entry("ERROR=%s", e.what()));
326 }
327
328 if (!pdrs.size())
329 {
330 log<level::ERR>("pldm: state effecter PDRs not present");
331 return;
332 }
333
Patrick Williams05e95592021-09-02 09:28:14 -0500334 bool offsetFound = false;
George Liuf3a4a692021-12-28 13:59:51 +0800335 auto stateEffecterPDR =
Patrick Williams05e95592021-09-02 09:28:14 -0500336 reinterpret_cast<const pldm_state_effecter_pdr*>(pdrs.front().data());
George Liuf3a4a692021-12-28 13:59:51 +0800337 auto possibleStatesPtr = stateEffecterPDR->possible_states;
338 for (auto offset = 0; offset < stateEffecterPDR->composite_effecter_count;
339 offset++)
Patrick Williams05e95592021-09-02 09:28:14 -0500340 {
341 auto possibleStates =
342 reinterpret_cast<const state_effecter_possible_states*>(
343 possibleStatesPtr);
344
Eddie Jamescbad2192021-10-07 09:39:39 -0500345 if (possibleStates->state_set_id == stateSetId)
Patrick Williams05e95592021-09-02 09:28:14 -0500346 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500347 stateIdPos = offset;
George Liuf3a4a692021-12-28 13:59:51 +0800348 effecterCount = stateEffecterPDR->composite_effecter_count;
Patrick Williams05e95592021-09-02 09:28:14 -0500349 offsetFound = true;
350 break;
351 }
352 possibleStatesPtr += sizeof(possibleStates->state_set_id) +
353 sizeof(possibleStates->possible_states_size) +
354 possibleStates->possible_states_size;
355 }
356
357 if (!offsetFound)
358 {
359 return;
360 }
361
Chris Cain0f516522022-02-07 14:48:28 -0600362 std::map<uint32_t, EffecterID> entityInstMap{};
Patrick Williams05e95592021-09-02 09:28:14 -0500363 for (auto& pdr : pdrs)
364 {
365 auto pdrPtr =
366 reinterpret_cast<const pldm_state_effecter_pdr*>(pdr.data());
Chris Cain72d01aa2022-06-14 16:28:03 -0500367 uint32_t key = pdrPtr->effecter_id;
Patrick Williams05e95592021-09-02 09:28:14 -0500368 entityInstMap.emplace(key, static_cast<SensorID>(pdrPtr->effecter_id));
369 }
370
371 open_power::occ::instanceID position = start;
Patrick Williamsa49c9872023-05-10 07:50:35 -0500372 for (const auto& pair : entityInstMap)
Patrick Williams05e95592021-09-02 09:28:14 -0500373 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500374 instanceToEffecterMap.emplace(position, pair.second);
Patrick Williams05e95592021-09-02 09:28:14 -0500375 position++;
376 }
377}
378
379std::vector<uint8_t>
Chris Cain8b508bf2022-05-26 14:01:31 -0500380 Interface::prepareSetEffecterReq(EffecterID effecterId,
Patrick Williams05e95592021-09-02 09:28:14 -0500381 CompositeEffecterCount effecterCount,
Eddie Jamescbad2192021-10-07 09:39:39 -0500382 uint8_t stateIdPos, uint8_t stateSetValue)
Patrick Williams05e95592021-09-02 09:28:14 -0500383{
Chris Cain8b508bf2022-05-26 14:01:31 -0500384 if (!getMctpInstanceId())
385 {
386 return std::vector<uint8_t>();
387 }
388
Patrick Williams05e95592021-09-02 09:28:14 -0500389 std::vector<uint8_t> request(
390 sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(effecterCount) +
391 (effecterCount * sizeof(set_effecter_state_field)));
392 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
393 std::vector<set_effecter_state_field> stateField;
394
395 for (uint8_t effecterPos = 0; effecterPos < effecterCount; effecterPos++)
396 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500397 if (effecterPos == stateIdPos)
Patrick Williams05e95592021-09-02 09:28:14 -0500398 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500399 stateField.emplace_back(
400 set_effecter_state_field{PLDM_REQUEST_SET, stateSetValue});
Patrick Williams05e95592021-09-02 09:28:14 -0500401 }
402 else
403 {
404 stateField.emplace_back(
405 set_effecter_state_field{PLDM_NO_CHANGE, 0});
406 }
407 }
408 auto rc = encode_set_state_effecter_states_req(
Chris Cain8b508bf2022-05-26 14:01:31 -0500409 mctpInstance.value(), effecterId, effecterCount, stateField.data(),
410 requestMsg);
Patrick Williams05e95592021-09-02 09:28:14 -0500411 if (rc != PLDM_SUCCESS)
412 {
413 log<level::ERR>("encode set effecter states request returned error ",
414 entry("RC=%d", rc));
415 request.clear();
416 }
417 return request;
418}
419
420void Interface::resetOCC(open_power::occ::instanceID occInstanceId)
421{
Chris Cainbae4d072022-02-28 09:46:50 -0600422 if (open_power::occ::utils::isHostRunning())
Patrick Williams05e95592021-09-02 09:28:14 -0500423 {
Chris Cainbae4d072022-02-28 09:46:50 -0600424 if (!isPDREffecterCacheValid())
425 {
426 fetchEffecterInfo(PLDM_STATE_SET_BOOT_RESTART_CAUSE,
427 occInstanceToEffecter, OCCEffecterCount,
428 bootRestartPosition);
429 }
Patrick Williams05e95592021-09-02 09:28:14 -0500430
Chris Cainbae4d072022-02-28 09:46:50 -0600431 // Find the matching effecter for the OCC instance
432 auto effecterEntry = occInstanceToEffecter.find(occInstanceId);
433 if (effecterEntry == occInstanceToEffecter.end())
434 {
435 log<level::ERR>(
436 fmt::format(
437 "pldm: Failed to find a matching effecter for OCC instance {}",
438 occInstanceId)
439 .c_str());
440
441 return;
442 }
443
Chris Cainbae4d072022-02-28 09:46:50 -0600444 // Prepare the SetStateEffecterStates request to reset the OCC
445 auto request = prepareSetEffecterReq(
Chris Cain8b508bf2022-05-26 14:01:31 -0500446 effecterEntry->second, OCCEffecterCount, bootRestartPosition,
447 PLDM_STATE_SET_BOOT_RESTART_CAUSE_WARM_RESET);
Chris Cainbae4d072022-02-28 09:46:50 -0600448
449 if (request.empty())
450 {
451 log<level::ERR>(
452 "pldm: SetStateEffecterStates OCC reset request empty");
453 return;
454 }
455
456 // Send request to reset the OCCs/PM Complex (ignore response)
457 sendPldm(request, occInstanceId, false);
458 }
459 else
Patrick Williams05e95592021-09-02 09:28:14 -0500460 {
461 log<level::ERR>(
Chris Cainbae4d072022-02-28 09:46:50 -0600462 fmt::format("resetOCC: HOST is not running (OCC{})", occInstanceId)
Chris Cain0f516522022-02-07 14:48:28 -0600463 .c_str());
Chris Cainbae4d072022-02-28 09:46:50 -0600464 clearData();
Patrick Williams05e95592021-09-02 09:28:14 -0500465 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500466}
467
468void Interface::sendHRESET(open_power::occ::instanceID sbeInstanceId)
469{
Chris Cainbae4d072022-02-28 09:46:50 -0600470 if (open_power::occ::utils::isHostRunning())
Eddie Jamescbad2192021-10-07 09:39:39 -0500471 {
Chris Cainbae4d072022-02-28 09:46:50 -0600472 if (sbeInstanceToEffecter.empty())
473 {
474 fetchEffecterInfo(PLDM_OEM_IBM_SBE_MAINTENANCE_STATE,
475 sbeInstanceToEffecter, SBEEffecterCount,
476 sbeMaintenanceStatePosition);
477 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500478
Chris Cainbae4d072022-02-28 09:46:50 -0600479 auto effecterEntry = sbeInstanceToEffecter.find(sbeInstanceId);
480 if (effecterEntry == sbeInstanceToEffecter.end())
481 {
482 log<level::ERR>(
483 "pldm: Failed to find a matching effecter for SBE instance",
484 entry("SBE=%d", sbeInstanceId));
485 return;
486 }
487
Chris Cainbae4d072022-02-28 09:46:50 -0600488 // Prepare the SetStateEffecterStates request to HRESET the SBE
489 auto request = prepareSetEffecterReq(
Chris Cain8b508bf2022-05-26 14:01:31 -0500490 effecterEntry->second, SBEEffecterCount,
Chris Cainbae4d072022-02-28 09:46:50 -0600491 sbeMaintenanceStatePosition, SBE_RETRY_REQUIRED);
492
493 if (request.empty())
494 {
495 log<level::ERR>(
496 "pldm: SetStateEffecterStates HRESET request empty");
497 return;
498 }
499
500 // Send request to issue HRESET of SBE (ignore response)
501 sendPldm(request, sbeInstanceId, false);
Chris Cain12d0b822022-04-22 17:29:18 -0500502 outstandingHResets.insert(sbeInstanceId);
Chris Cainbae4d072022-02-28 09:46:50 -0600503 }
504 else
Eddie Jamescbad2192021-10-07 09:39:39 -0500505 {
Chris Cainbae4d072022-02-28 09:46:50 -0600506 log<level::ERR>(fmt::format("sendHRESET: HOST is not running (OCC{})",
507 sbeInstanceId)
508 .c_str());
509 clearData();
Eddie Jamescbad2192021-10-07 09:39:39 -0500510 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500511}
512
Chris Cain8b508bf2022-05-26 14:01:31 -0500513bool Interface::getMctpInstanceId()
Eddie Jamescbad2192021-10-07 09:39:39 -0500514{
Chris Cain8b508bf2022-05-26 14:01:31 -0500515 if (!mctpInstance)
Patrick Williams05e95592021-09-02 09:28:14 -0500516 {
Chris Cain8b508bf2022-05-26 14:01:31 -0500517 // Request new instance ID
518 auto& bus = open_power::occ::utils::getBus();
519 try
520 {
521 auto method = bus.new_method_call(
522 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
523 "xyz.openbmc_project.PLDM.Requester", "GetInstanceId");
524 method.append(mctpEid);
525 auto reply = bus.call(method);
526 uint8_t newInstanceId;
527 reply.read(newInstanceId);
528 mctpInstance = newInstanceId;
529 log<level::INFO>(fmt::format("pldm: got new InstanceId: {}",
530 mctpInstance.value())
531 .c_str());
532 }
Patrick Williamsaf408082022-07-22 19:26:54 -0500533 catch (const sdbusplus::exception_t& e)
Chris Cain8b508bf2022-05-26 14:01:31 -0500534 {
535 log<level::ERR>(
536 fmt::format("pldm: GetInstanceId failed: {}", e.what())
537 .c_str());
538 return false;
539 }
Patrick Williams05e95592021-09-02 09:28:14 -0500540 }
541
Eddie Jamescbad2192021-10-07 09:39:39 -0500542 return true;
543}
Patrick Williams05e95592021-09-02 09:28:14 -0500544
Chris Cainbae4d072022-02-28 09:46:50 -0600545void Interface::sendPldm(const std::vector<uint8_t>& request,
546 const uint8_t instance, const bool rspExpected)
Eddie Jamescbad2192021-10-07 09:39:39 -0500547{
Chris Cain8b508bf2022-05-26 14:01:31 -0500548 if (!mctpInstance)
549 {
550 log<level::ERR>("sendPldm: No MCTP Instance ID found!");
551 return;
552 }
553
Chris Cainc9dc4412023-03-06 15:56:34 -0600554 // Connect to MCTP socket
Chris Cainbae4d072022-02-28 09:46:50 -0600555 pldmFd = pldm_open();
556 auto openErrno = errno;
557 if (pldmFd == PLDM_REQUESTER_OPEN_FAIL)
Patrick Williams05e95592021-09-02 09:28:14 -0500558 {
Chris Caind1b68262022-02-28 09:56:50 -0600559 log<level::ERR>(
Chris Cainbae4d072022-02-28 09:46:50 -0600560 fmt::format(
561 "sendPldm: Failed to connect to MCTP socket, errno={}/{}",
562 openErrno, strerror(openErrno))
Chris Caind1b68262022-02-28 09:56:50 -0600563 .c_str());
Patrick Williams05e95592021-09-02 09:28:14 -0500564 return;
565 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500566
Patrick Williams05e95592021-09-02 09:28:14 -0500567 // Send the PLDM request message to HBRT
Chris Cainbae4d072022-02-28 09:46:50 -0600568 if (rspExpected)
Patrick Williams05e95592021-09-02 09:28:14 -0500569 {
Chris Cainbae4d072022-02-28 09:46:50 -0600570 // Register callback when response is available
571 registerPldmRspCallback();
572
573 // Send PLDM request
574 log<level::INFO>(
575 fmt::format(
576 "sendPldm: calling pldm_send(OCC{}, instance:{}, {} bytes)",
Chris Cain8b508bf2022-05-26 14:01:31 -0500577 instance, mctpInstance.value(), request.size())
Chris Cainbae4d072022-02-28 09:46:50 -0600578 .c_str());
579 pldmResponseReceived = false;
580 pldmResponseTimeout = false;
581 pldmResponseOcc = instance;
Patrick Williamsa49c9872023-05-10 07:50:35 -0500582 auto pldmRc = pldm_send(mctpEid, pldmFd, request.data(),
583 request.size());
Chris Cainbae4d072022-02-28 09:46:50 -0600584 auto sendErrno = errno;
585 if (pldmRc != PLDM_REQUESTER_SUCCESS)
586 {
587 log<level::ERR>(
588 fmt::format(
589 "sendPldm: pldm_send failed with rc={} and errno={}/{}",
Chris Cain5161a022023-08-15 10:07:12 -0500590 static_cast<
591 std::underlying_type_t<pldm_requester_error_codes>>(
592 pldmRc),
593 sendErrno, strerror(sendErrno))
Chris Cainbae4d072022-02-28 09:46:50 -0600594 .c_str());
595 pldmClose();
596 return;
597 }
598
599 // start timer waiting for the response
600 using namespace std::literals::chrono_literals;
Chris Cainbd551de2022-04-26 13:41:16 -0500601 pldmRspTimer.restartOnce(8s);
Chris Cainbae4d072022-02-28 09:46:50 -0600602
603 // Wait for response/timeout
604 }
605 else // not expecting the response
606 {
607 log<level::INFO>(
608 fmt::format(
609 "sendPldm: calling pldm_send(mctpID:{}, fd:{}, {} bytes) for OCC{}",
610 mctpEid, pldmFd, request.size(), instance)
611 .c_str());
612 auto rc = pldm_send(mctpEid, pldmFd, request.data(), request.size());
613 auto sendErrno = errno;
Chris Caind1b68262022-02-28 09:56:50 -0600614 if (rc)
615 {
616 log<level::ERR>(
617 fmt::format(
Chris Cainbae4d072022-02-28 09:46:50 -0600618 "sendPldm: pldm_send(mctpID:{}, fd:{}, {} bytes) failed with rc={} and errno={}/{}",
Chris Cain5161a022023-08-15 10:07:12 -0500619 mctpEid, pldmFd, request.size(),
620 static_cast<
621 std::underlying_type_t<pldm_requester_error_codes>>(rc),
622 sendErrno, strerror(sendErrno))
Chris Caind1b68262022-02-28 09:56:50 -0600623 .c_str());
624 }
Chris Cain8b508bf2022-05-26 14:01:31 -0500625 else
626 {
627 // Not waiting for response, instance ID should be freed
628 mctpInstance = std::nullopt;
629 }
Chris Cainbae4d072022-02-28 09:46:50 -0600630 pldmClose();
631 }
632}
Patrick Williams05e95592021-09-02 09:28:14 -0500633
Chris Cainbae4d072022-02-28 09:46:50 -0600634// Attaches the FD to event loop and registers the callback handler
635void Interface::registerPldmRspCallback()
636{
637 decltype(eventSource.get()) sourcePtr = nullptr;
638 auto rc = sd_event_add_io(event.get(), &sourcePtr, pldmFd, EPOLLIN,
639 pldmRspCallback, this);
640 if (rc < 0)
641 {
642 log<level::ERR>(
643 fmt::format(
644 "registerPldmRspCallback: sd_event_add_io: Error({})={} : fd={}",
645 rc, strerror(-rc), pldmFd)
646 .c_str());
Chris Caind1b68262022-02-28 09:56:50 -0600647 }
648 else
Patrick Williams05e95592021-09-02 09:28:14 -0500649 {
Chris Cainbae4d072022-02-28 09:46:50 -0600650 // puts sourcePtr in the event source.
651 eventSource.reset(sourcePtr);
652 }
653}
654
655// Add a timer to the event loop, default 30s.
656void Interface::pldmRspExpired()
657{
658 if (!pldmResponseReceived)
659 {
Chris Cain082a6ca2023-03-21 10:27:26 -0500660 log<level::WARNING>(
Chris Cainbae4d072022-02-28 09:46:50 -0600661 fmt::format(
662 "pldmRspExpired: timerCallback - timeout waiting for pldm response for OCC{}",
663 pldmResponseOcc)
664 .c_str());
665 pldmResponseTimeout = true;
666 if (pldmFd)
667 {
668 pldmClose();
669 }
670 }
671 return;
672};
673
674void Interface::pldmClose()
675{
676 if (pldmRspTimer.isEnabled())
677 {
678 // stop PLDM response timer
679 pldmRspTimer.setEnabled(false);
680 }
Pavithra Barithaya159a2272023-09-27 06:10:55 -0500681 pldm_close();
Chris Cainbae4d072022-02-28 09:46:50 -0600682 pldmFd = -1;
683 eventSource.reset();
684}
685
686int Interface::pldmRspCallback(sd_event_source* /*es*/, int fd,
687 uint32_t revents, void* userData)
688{
689 if (!(revents & EPOLLIN))
690 {
691 log<level::INFO>(
692 fmt::format("pldmRspCallback - revents={:08X}", revents).c_str());
693 return -1;
694 }
695
696 auto pldmIface = static_cast<Interface*>(userData);
697
Chris Cain8b508bf2022-05-26 14:01:31 -0500698 if (!pldmIface->mctpInstance)
699 {
700 log<level::ERR>(
701 "pldmRspCallback: No outstanding MCTP Instance ID found");
702 return -1;
703 }
704
Chris Cainbae4d072022-02-28 09:46:50 -0600705 uint8_t* responseMsg = nullptr;
706 size_t responseMsgSize{};
707
708 log<level::INFO>(
709 fmt::format("pldmRspCallback: calling pldm_recv() instance:{}",
Chris Cain8b508bf2022-05-26 14:01:31 -0500710 pldmIface->mctpInstance.value())
Chris Cainbae4d072022-02-28 09:46:50 -0600711 .c_str());
Chris Cain8b508bf2022-05-26 14:01:31 -0500712 auto rc = pldm_recv(mctpEid, fd, pldmIface->mctpInstance.value(),
713 &responseMsg, &responseMsgSize);
Chris Cainbae4d072022-02-28 09:46:50 -0600714 int lastErrno = errno;
715 if (rc)
716 {
717 log<level::ERR>(
718 fmt::format(
Chris Cain5161a022023-08-15 10:07:12 -0500719 "pldmRspCallback: pldm_recv failed with rc={}, errno={}/{}",
720 static_cast<std::underlying_type_t<pldm_requester_error_codes>>(
721 rc),
Chris Cainbae4d072022-02-28 09:46:50 -0600722 lastErrno, strerror(lastErrno))
723 .c_str());
724 return -1;
725 }
Chris Cain8b508bf2022-05-26 14:01:31 -0500726
727 // We got the response for the PLDM request msg that was sent
Chris Cainbae4d072022-02-28 09:46:50 -0600728 log<level::INFO>(
729 fmt::format("pldmRspCallback: pldm_recv() rsp was {} bytes",
730 responseMsgSize)
731 .c_str());
732
733 if (pldmIface->pldmRspTimer.isEnabled())
734 {
735 // stop PLDM response timer
736 pldmIface->pldmRspTimer.setEnabled(false);
737 }
738
Chris Cain8b508bf2022-05-26 14:01:31 -0500739 // instance ID should be freed
740 pldmIface->mctpInstance = std::nullopt;
741
Chris Cainbae4d072022-02-28 09:46:50 -0600742 // Set pointer to autodelete
743 std::unique_ptr<uint8_t, decltype(std::free)*> responseMsgPtr{responseMsg,
744 std::free};
745
Chris Cainbae4d072022-02-28 09:46:50 -0600746 auto response = reinterpret_cast<pldm_msg*>(responseMsgPtr.get());
747 if (response->payload[0] != PLDM_SUCCESS)
748 {
749 log<level::ERR>(
750 fmt::format("pldmRspCallback: payload[0] was not success: {}",
751 response->payload[0])
752 .c_str());
753 pldmIface->pldmClose();
754 return -1;
755 }
756
757 // Decode the response
758 uint8_t compCode = 0, sensorCount = 1;
759 get_sensor_state_field field[6];
760 responseMsgSize -= sizeof(pldm_msg_hdr);
761 auto msgRc = decode_get_state_sensor_readings_resp(
762 response, responseMsgSize, &compCode, &sensorCount, field);
763 if ((msgRc != PLDM_SUCCESS) || (compCode != PLDM_SUCCESS))
764 {
765 log<level::ERR>(
766 fmt::format(
767 "pldmRspCallback: decode_get_state_sensor_readings failed with rc={} and compCode={}",
768 msgRc, compCode)
769 .c_str());
770 pldmIface->pldmClose();
771 return -1;
772 }
773
774 pldmIface->pldmClose();
775
776 const uint8_t instance = pldmIface->pldmResponseOcc;
777 const uint8_t occSensorState = field[0].present_state;
778 pldmIface->pldmResponseReceived = true;
779
780 if (occSensorState == PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_IN_SERVICE)
781 {
782 log<level::INFO>(
783 fmt::format("pldmRspCallback: OCC{} is RUNNING", instance).c_str());
784 pldmIface->callBack(instance, true);
785 }
Chris Cain733b2012022-05-04 11:54:06 -0500786 else if (occSensorState ==
787 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_DORMANT)
788 {
789 log<level::INFO>(
790 fmt::format(
791 "pldmRspCallback: OCC{} has now STOPPED and system is in SAFE MODE",
792 instance)
793 .c_str());
Sheldon Bailey31a2f132022-05-20 11:31:52 -0500794
795 // Setting safe mode true
796 pldmIface->safeModeCallBack(true);
797
Chris Cain733b2012022-05-04 11:54:06 -0500798 pldmIface->callBack(instance, false);
799 }
Chris Cainbae4d072022-02-28 09:46:50 -0600800 else
801 {
802 log<level::INFO>(
Chris Cain8b508bf2022-05-26 14:01:31 -0500803 fmt::format(
804 "pldmRspCallback: OCC{} is not running (sensor state:{})",
805 instance, occSensorState)
Chris Cainbae4d072022-02-28 09:46:50 -0600806 .c_str());
Chris Cainc9dc4412023-03-06 15:56:34 -0600807 if (occSensorState != PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_STOPPED)
808 {
809 const size_t rspLength = responseMsgSize + sizeof(pldm_msg_hdr);
810 std::vector<std::uint8_t> pldmResponse(rspLength);
811 memcpy(&pldmResponse[0], reinterpret_cast<std::uint8_t*>(response),
812 rspLength);
813 log<level::ERR>(
814 fmt::format(
815 "pldmRspCallback: Bad State - PLDM response ({} bytes) for OCC{}:",
816 rspLength, instance)
817 .c_str());
818 dump_hex(pldmResponse);
819 }
Chris Cainbae4d072022-02-28 09:46:50 -0600820 pldmIface->callBack(instance, false);
821 }
822
823 return 0;
824};
825
826std::vector<uint8_t> Interface::encodeGetStateSensorRequest(uint8_t instance,
827 uint16_t sensorId)
828{
Chris Cain8b508bf2022-05-26 14:01:31 -0500829 if (!getMctpInstanceId())
830 {
831 log<level::ERR>(
832 "encodeGetStateSensorRequest: failed to getMctpInstanceId");
833 return std::vector<uint8_t>();
834 }
835
Chris Cainbae4d072022-02-28 09:46:50 -0600836 bitfield8_t sRearm = {0};
Patrick Williamsa49c9872023-05-10 07:50:35 -0500837 const size_t msgSize = sizeof(pldm_msg_hdr) +
838 PLDM_GET_STATE_SENSOR_READINGS_REQ_BYTES;
Chris Cainbae4d072022-02-28 09:46:50 -0600839 std::vector<uint8_t> request(msgSize);
Chris Cain8b508bf2022-05-26 14:01:31 -0500840
Chris Cainbae4d072022-02-28 09:46:50 -0600841 auto msg = reinterpret_cast<pldm_msg*>(request.data());
Chris Cain8b508bf2022-05-26 14:01:31 -0500842 auto msgRc = encode_get_state_sensor_readings_req(mctpInstance.value(),
843 sensorId, sRearm, 0, msg);
Chris Cainbae4d072022-02-28 09:46:50 -0600844 if (msgRc != PLDM_SUCCESS)
845 {
846 log<level::ERR>(
847 fmt::format(
848 "encodeGetStateSensorRequest: Failed to encode sensorId:0x{:08X} for OCC{} (rc={})",
849 sensorId, instance, msgRc)
850 .c_str());
851 }
852 return request;
853}
854
855// Initiate query of the specified OCC Active Sensor
856void Interface::checkActiveSensor(uint8_t instance)
857{
858 static bool tracedOnce = false;
859 if (pldmFd > 0)
860 {
861 if (!tracedOnce)
Chris Caind1b68262022-02-28 09:56:50 -0600862 {
863 log<level::ERR>(
864 fmt::format(
Chris Cainbae4d072022-02-28 09:46:50 -0600865 "checkActiveSensor: already waiting on OCC{} (fd={})",
866 pldmResponseOcc, pldmFd)
Chris Caind1b68262022-02-28 09:56:50 -0600867 .c_str());
Chris Cainbae4d072022-02-28 09:46:50 -0600868 tracedOnce = true;
Chris Caind1b68262022-02-28 09:56:50 -0600869 }
Chris Cainbae4d072022-02-28 09:46:50 -0600870 return;
871 }
872 tracedOnce = false;
873
874 if (!isOCCSensorCacheValid())
875 {
876 fetchSensorInfo(PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS,
877 sensorToOCCInstance, OCCSensorOffset);
878 }
879
880 // look up sensor id (key) based on instance
881 auto entry = std::find_if(
882 sensorToOCCInstance.begin(), sensorToOCCInstance.end(),
883 [instance](const auto& entry) { return instance == entry.second; });
884 if (entry != sensorToOCCInstance.end())
885 {
886 // Query the OCC Active Sensor state for this instance
887 // SensorID sID = entry->first;
888 log<level::INFO>(
889 fmt::format("checkActiveSensor: OCC{} / sensorID: 0x{:04X}",
890 instance, entry->first)
891 .c_str());
892
Chris Cainbae4d072022-02-28 09:46:50 -0600893 // Encode GetStateSensorReadings PLDM message
894 auto request = encodeGetStateSensorRequest(instance, entry->first);
895 if (request.empty())
896 {
897 return;
898 }
899
900 // Send request to PLDM and setup callback for response
901 sendPldm(request, instance, true);
902 }
903 else
904 {
905 log<level::ERR>(
906 fmt::format(
907 "checkActiveSensor: Unable to find PLDM sensor for OCC{}",
908 instance)
909 .c_str());
Chris Cain8cf74962022-06-29 08:45:16 -0500910 log<level::INFO>(
911 "checkActiveSensor: fetching STATE_SET_OPERATIONAL_RUNNING_STATUS");
912 fetchSensorInfo(PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS,
913 sensorToOCCInstance, OCCSensorOffset);
Patrick Williams05e95592021-09-02 09:28:14 -0500914 }
Patrick Williams05e95592021-09-02 09:28:14 -0500915}
916
917} // namespace pldm