blob: 687e3b4e290a8c8ed5a5acefe6c09b2dceff2210 [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;
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
Patrick Williamsaf408082022-07-22 19:26:54 -0500240void Interface::hostStateEvent(sdbusplus::message_t& msg)
Chris Cain157467d2022-06-24 11:25:23 -0500241{
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 {
252 clearData();
253 }
254 }
255}
256
Chris Cainbae4d072022-02-28 09:46:50 -0600257void Interface::clearData()
258{
Chris Cain72d01aa2022-06-14 16:28:03 -0500259 if (!sensorToOCCInstance.empty())
260 {
261 log<level::INFO>(
262 fmt::format("clearData: Clearing sensorToOCCInstance ({} entries)",
263 sensorToOCCInstance.size())
264 .c_str());
265 for (auto entry : sensorToOCCInstance)
266 {
267 log<level::INFO>(
268 fmt::format("clearData: OCC{} / sensorID: 0x{:04X}",
269 entry.second, entry.first)
270 .c_str());
271 }
272 sensorToOCCInstance.clear();
273 }
274 if (!occInstanceToEffecter.empty())
275 {
276 log<level::DEBUG>(
277 fmt::format(
278 "clearData: Clearing occInstanceToEffecter ({} entries)",
279 occInstanceToEffecter.size())
280 .c_str());
281 occInstanceToEffecter.clear();
282 }
283 if (!sensorToSBEInstance.empty())
284 {
285 log<level::DEBUG>(
286 fmt::format("clearData: Clearing sensorToSBEInstance ({} entries)",
287 sensorToSBEInstance.size())
288 .c_str());
289 sensorToSBEInstance.clear();
290 }
291 if (!sbeInstanceToEffecter.empty())
292 {
293 log<level::DEBUG>(
294 fmt::format(
295 "clearData: Clearing sbeInstanceToEffecter ({} entries)",
296 sbeInstanceToEffecter.size())
297 .c_str());
298 sbeInstanceToEffecter.clear();
299 }
Chris Cainbae4d072022-02-28 09:46:50 -0600300}
301
Eddie James432dc482021-11-19 15:29:31 -0600302void Interface::fetchEffecterInfo(uint16_t stateSetId,
Eddie Jamescbad2192021-10-07 09:39:39 -0500303 InstanceToEffecter& instanceToEffecterMap,
304 CompositeEffecterCount& effecterCount,
305 uint8_t& stateIdPos)
Patrick Williams05e95592021-09-02 09:28:14 -0500306{
Eddie Jamescbad2192021-10-07 09:39:39 -0500307 PdrList pdrs{};
308
309 auto& bus = open_power::occ::utils::getBus();
310 try
311 {
312 auto method = bus.new_method_call(
313 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
314 "xyz.openbmc_project.PLDM.PDR", "FindStateEffecterPDR");
Chris Cainbae4d072022-02-28 09:46:50 -0600315 method.append(tid, static_cast<uint16_t>(PLDM_ENTITY_PROC), stateSetId);
Eddie Jamescbad2192021-10-07 09:39:39 -0500316
317 auto responseMsg = bus.call(method);
318 responseMsg.read(pdrs);
319 }
Patrick Williamsaf408082022-07-22 19:26:54 -0500320 catch (const sdbusplus::exception_t& e)
Eddie Jamescbad2192021-10-07 09:39:39 -0500321 {
322 log<level::ERR>("pldm: Failed to fetch the state effecter PDRs",
323 entry("ERROR=%s", e.what()));
324 }
325
326 if (!pdrs.size())
327 {
328 log<level::ERR>("pldm: state effecter PDRs not present");
329 return;
330 }
331
Patrick Williams05e95592021-09-02 09:28:14 -0500332 bool offsetFound = false;
George Liuf3a4a692021-12-28 13:59:51 +0800333 auto stateEffecterPDR =
Patrick Williams05e95592021-09-02 09:28:14 -0500334 reinterpret_cast<const pldm_state_effecter_pdr*>(pdrs.front().data());
George Liuf3a4a692021-12-28 13:59:51 +0800335 auto possibleStatesPtr = stateEffecterPDR->possible_states;
336 for (auto offset = 0; offset < stateEffecterPDR->composite_effecter_count;
337 offset++)
Patrick Williams05e95592021-09-02 09:28:14 -0500338 {
339 auto possibleStates =
340 reinterpret_cast<const state_effecter_possible_states*>(
341 possibleStatesPtr);
342
Eddie Jamescbad2192021-10-07 09:39:39 -0500343 if (possibleStates->state_set_id == stateSetId)
Patrick Williams05e95592021-09-02 09:28:14 -0500344 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500345 stateIdPos = offset;
George Liuf3a4a692021-12-28 13:59:51 +0800346 effecterCount = stateEffecterPDR->composite_effecter_count;
Patrick Williams05e95592021-09-02 09:28:14 -0500347 offsetFound = true;
348 break;
349 }
350 possibleStatesPtr += sizeof(possibleStates->state_set_id) +
351 sizeof(possibleStates->possible_states_size) +
352 possibleStates->possible_states_size;
353 }
354
355 if (!offsetFound)
356 {
357 return;
358 }
359
Chris Cain0f516522022-02-07 14:48:28 -0600360 std::map<uint32_t, EffecterID> entityInstMap{};
Patrick Williams05e95592021-09-02 09:28:14 -0500361 for (auto& pdr : pdrs)
362 {
363 auto pdrPtr =
364 reinterpret_cast<const pldm_state_effecter_pdr*>(pdr.data());
Chris Cain72d01aa2022-06-14 16:28:03 -0500365 uint32_t key = pdrPtr->effecter_id;
Patrick Williams05e95592021-09-02 09:28:14 -0500366 entityInstMap.emplace(key, static_cast<SensorID>(pdrPtr->effecter_id));
367 }
368
369 open_power::occ::instanceID position = start;
370 for (auto const& pair : entityInstMap)
371 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500372 instanceToEffecterMap.emplace(position, pair.second);
Patrick Williams05e95592021-09-02 09:28:14 -0500373 position++;
374 }
375}
376
377std::vector<uint8_t>
Chris Cain8b508bf2022-05-26 14:01:31 -0500378 Interface::prepareSetEffecterReq(EffecterID effecterId,
Patrick Williams05e95592021-09-02 09:28:14 -0500379 CompositeEffecterCount effecterCount,
Eddie Jamescbad2192021-10-07 09:39:39 -0500380 uint8_t stateIdPos, uint8_t stateSetValue)
Patrick Williams05e95592021-09-02 09:28:14 -0500381{
Chris Cain8b508bf2022-05-26 14:01:31 -0500382 if (!getMctpInstanceId())
383 {
384 return std::vector<uint8_t>();
385 }
386
Patrick Williams05e95592021-09-02 09:28:14 -0500387 std::vector<uint8_t> request(
388 sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(effecterCount) +
389 (effecterCount * sizeof(set_effecter_state_field)));
390 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
391 std::vector<set_effecter_state_field> stateField;
392
393 for (uint8_t effecterPos = 0; effecterPos < effecterCount; effecterPos++)
394 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500395 if (effecterPos == stateIdPos)
Patrick Williams05e95592021-09-02 09:28:14 -0500396 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500397 stateField.emplace_back(
398 set_effecter_state_field{PLDM_REQUEST_SET, stateSetValue});
Patrick Williams05e95592021-09-02 09:28:14 -0500399 }
400 else
401 {
402 stateField.emplace_back(
403 set_effecter_state_field{PLDM_NO_CHANGE, 0});
404 }
405 }
406 auto rc = encode_set_state_effecter_states_req(
Chris Cain8b508bf2022-05-26 14:01:31 -0500407 mctpInstance.value(), effecterId, effecterCount, stateField.data(),
408 requestMsg);
Patrick Williams05e95592021-09-02 09:28:14 -0500409 if (rc != PLDM_SUCCESS)
410 {
411 log<level::ERR>("encode set effecter states request returned error ",
412 entry("RC=%d", rc));
413 request.clear();
414 }
415 return request;
416}
417
418void Interface::resetOCC(open_power::occ::instanceID occInstanceId)
419{
Chris Cainbae4d072022-02-28 09:46:50 -0600420 if (open_power::occ::utils::isHostRunning())
Patrick Williams05e95592021-09-02 09:28:14 -0500421 {
Chris Cainbae4d072022-02-28 09:46:50 -0600422 if (!isPDREffecterCacheValid())
423 {
424 fetchEffecterInfo(PLDM_STATE_SET_BOOT_RESTART_CAUSE,
425 occInstanceToEffecter, OCCEffecterCount,
426 bootRestartPosition);
427 }
Patrick Williams05e95592021-09-02 09:28:14 -0500428
Chris Cainbae4d072022-02-28 09:46:50 -0600429 // Find the matching effecter for the OCC instance
430 auto effecterEntry = occInstanceToEffecter.find(occInstanceId);
431 if (effecterEntry == occInstanceToEffecter.end())
432 {
433 log<level::ERR>(
434 fmt::format(
435 "pldm: Failed to find a matching effecter for OCC instance {}",
436 occInstanceId)
437 .c_str());
438
439 return;
440 }
441
Chris Cainbae4d072022-02-28 09:46:50 -0600442 // Prepare the SetStateEffecterStates request to reset the OCC
443 auto request = prepareSetEffecterReq(
Chris Cain8b508bf2022-05-26 14:01:31 -0500444 effecterEntry->second, OCCEffecterCount, bootRestartPosition,
445 PLDM_STATE_SET_BOOT_RESTART_CAUSE_WARM_RESET);
Chris Cainbae4d072022-02-28 09:46:50 -0600446
447 if (request.empty())
448 {
449 log<level::ERR>(
450 "pldm: SetStateEffecterStates OCC reset request empty");
451 return;
452 }
453
454 // Send request to reset the OCCs/PM Complex (ignore response)
455 sendPldm(request, occInstanceId, false);
456 }
457 else
Patrick Williams05e95592021-09-02 09:28:14 -0500458 {
459 log<level::ERR>(
Chris Cainbae4d072022-02-28 09:46:50 -0600460 fmt::format("resetOCC: HOST is not running (OCC{})", occInstanceId)
Chris Cain0f516522022-02-07 14:48:28 -0600461 .c_str());
Chris Cainbae4d072022-02-28 09:46:50 -0600462 clearData();
Patrick Williams05e95592021-09-02 09:28:14 -0500463 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500464}
465
466void Interface::sendHRESET(open_power::occ::instanceID sbeInstanceId)
467{
Chris Cainbae4d072022-02-28 09:46:50 -0600468 if (open_power::occ::utils::isHostRunning())
Eddie Jamescbad2192021-10-07 09:39:39 -0500469 {
Chris Cainbae4d072022-02-28 09:46:50 -0600470 if (sbeInstanceToEffecter.empty())
471 {
472 fetchEffecterInfo(PLDM_OEM_IBM_SBE_MAINTENANCE_STATE,
473 sbeInstanceToEffecter, SBEEffecterCount,
474 sbeMaintenanceStatePosition);
475 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500476
Chris Cainbae4d072022-02-28 09:46:50 -0600477 auto effecterEntry = sbeInstanceToEffecter.find(sbeInstanceId);
478 if (effecterEntry == sbeInstanceToEffecter.end())
479 {
480 log<level::ERR>(
481 "pldm: Failed to find a matching effecter for SBE instance",
482 entry("SBE=%d", sbeInstanceId));
483 return;
484 }
485
Chris Cainbae4d072022-02-28 09:46:50 -0600486 // Prepare the SetStateEffecterStates request to HRESET the SBE
487 auto request = prepareSetEffecterReq(
Chris Cain8b508bf2022-05-26 14:01:31 -0500488 effecterEntry->second, SBEEffecterCount,
Chris Cainbae4d072022-02-28 09:46:50 -0600489 sbeMaintenanceStatePosition, SBE_RETRY_REQUIRED);
490
491 if (request.empty())
492 {
493 log<level::ERR>(
494 "pldm: SetStateEffecterStates HRESET request empty");
495 return;
496 }
497
498 // Send request to issue HRESET of SBE (ignore response)
499 sendPldm(request, sbeInstanceId, false);
Chris Cain12d0b822022-04-22 17:29:18 -0500500 outstandingHResets.insert(sbeInstanceId);
Chris Cainbae4d072022-02-28 09:46:50 -0600501 }
502 else
Eddie Jamescbad2192021-10-07 09:39:39 -0500503 {
Chris Cainbae4d072022-02-28 09:46:50 -0600504 log<level::ERR>(fmt::format("sendHRESET: HOST is not running (OCC{})",
505 sbeInstanceId)
506 .c_str());
507 clearData();
Eddie Jamescbad2192021-10-07 09:39:39 -0500508 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500509}
510
Chris Cain8b508bf2022-05-26 14:01:31 -0500511bool Interface::getMctpInstanceId()
Eddie Jamescbad2192021-10-07 09:39:39 -0500512{
Chris Cain8b508bf2022-05-26 14:01:31 -0500513 if (!mctpInstance)
Patrick Williams05e95592021-09-02 09:28:14 -0500514 {
Chris Cain8b508bf2022-05-26 14:01:31 -0500515 // Request new instance ID
516 auto& bus = open_power::occ::utils::getBus();
517 try
518 {
519 auto method = bus.new_method_call(
520 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
521 "xyz.openbmc_project.PLDM.Requester", "GetInstanceId");
522 method.append(mctpEid);
523 auto reply = bus.call(method);
524 uint8_t newInstanceId;
525 reply.read(newInstanceId);
526 mctpInstance = newInstanceId;
527 log<level::INFO>(fmt::format("pldm: got new InstanceId: {}",
528 mctpInstance.value())
529 .c_str());
530 }
Patrick Williamsaf408082022-07-22 19:26:54 -0500531 catch (const sdbusplus::exception_t& e)
Chris Cain8b508bf2022-05-26 14:01:31 -0500532 {
533 log<level::ERR>(
534 fmt::format("pldm: GetInstanceId failed: {}", e.what())
535 .c_str());
536 return false;
537 }
Patrick Williams05e95592021-09-02 09:28:14 -0500538 }
539
Eddie Jamescbad2192021-10-07 09:39:39 -0500540 return true;
541}
Patrick Williams05e95592021-09-02 09:28:14 -0500542
Chris Cainbae4d072022-02-28 09:46:50 -0600543void Interface::sendPldm(const std::vector<uint8_t>& request,
544 const uint8_t instance, const bool rspExpected)
Eddie Jamescbad2192021-10-07 09:39:39 -0500545{
Chris Cain8b508bf2022-05-26 14:01:31 -0500546 if (!mctpInstance)
547 {
548 log<level::ERR>("sendPldm: No MCTP Instance ID found!");
549 return;
550 }
551
Chris Cainc9dc4412023-03-06 15:56:34 -0600552 // Connect to MCTP socket
Chris Cainbae4d072022-02-28 09:46:50 -0600553 pldmFd = pldm_open();
554 auto openErrno = errno;
555 if (pldmFd == PLDM_REQUESTER_OPEN_FAIL)
Patrick Williams05e95592021-09-02 09:28:14 -0500556 {
Chris Caind1b68262022-02-28 09:56:50 -0600557 log<level::ERR>(
Chris Cainbae4d072022-02-28 09:46:50 -0600558 fmt::format(
559 "sendPldm: Failed to connect to MCTP socket, errno={}/{}",
560 openErrno, strerror(openErrno))
Chris Caind1b68262022-02-28 09:56:50 -0600561 .c_str());
Patrick Williams05e95592021-09-02 09:28:14 -0500562 return;
563 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500564
Patrick Williams05e95592021-09-02 09:28:14 -0500565 // Send the PLDM request message to HBRT
Chris Cainbae4d072022-02-28 09:46:50 -0600566 if (rspExpected)
Patrick Williams05e95592021-09-02 09:28:14 -0500567 {
Chris Cainbae4d072022-02-28 09:46:50 -0600568 // Register callback when response is available
569 registerPldmRspCallback();
570
571 // Send PLDM request
572 log<level::INFO>(
573 fmt::format(
574 "sendPldm: calling pldm_send(OCC{}, instance:{}, {} bytes)",
Chris Cain8b508bf2022-05-26 14:01:31 -0500575 instance, mctpInstance.value(), request.size())
Chris Cainbae4d072022-02-28 09:46:50 -0600576 .c_str());
577 pldmResponseReceived = false;
578 pldmResponseTimeout = false;
579 pldmResponseOcc = instance;
580 auto pldmRc =
581 pldm_send(mctpEid, pldmFd, request.data(), request.size());
582 auto sendErrno = errno;
583 if (pldmRc != PLDM_REQUESTER_SUCCESS)
584 {
585 log<level::ERR>(
586 fmt::format(
587 "sendPldm: pldm_send failed with rc={} and errno={}/{}",
588 pldmRc, sendErrno, strerror(sendErrno))
589 .c_str());
590 pldmClose();
591 return;
592 }
593
594 // start timer waiting for the response
595 using namespace std::literals::chrono_literals;
Chris Cainbd551de2022-04-26 13:41:16 -0500596 pldmRspTimer.restartOnce(8s);
Chris Cainbae4d072022-02-28 09:46:50 -0600597
598 // Wait for response/timeout
599 }
600 else // not expecting the response
601 {
602 log<level::INFO>(
603 fmt::format(
604 "sendPldm: calling pldm_send(mctpID:{}, fd:{}, {} bytes) for OCC{}",
605 mctpEid, pldmFd, request.size(), instance)
606 .c_str());
607 auto rc = pldm_send(mctpEid, pldmFd, request.data(), request.size());
608 auto sendErrno = errno;
Chris Caind1b68262022-02-28 09:56:50 -0600609 if (rc)
610 {
611 log<level::ERR>(
612 fmt::format(
Chris Cainbae4d072022-02-28 09:46:50 -0600613 "sendPldm: pldm_send(mctpID:{}, fd:{}, {} bytes) failed with rc={} and errno={}/{}",
614 mctpEid, pldmFd, request.size(), rc, sendErrno,
615 strerror(sendErrno))
Chris Caind1b68262022-02-28 09:56:50 -0600616 .c_str());
617 }
Chris Cain8b508bf2022-05-26 14:01:31 -0500618 else
619 {
620 // Not waiting for response, instance ID should be freed
621 mctpInstance = std::nullopt;
622 }
Chris Cainbae4d072022-02-28 09:46:50 -0600623 pldmClose();
624 }
625}
Patrick Williams05e95592021-09-02 09:28:14 -0500626
Chris Cainbae4d072022-02-28 09:46:50 -0600627// Attaches the FD to event loop and registers the callback handler
628void Interface::registerPldmRspCallback()
629{
630 decltype(eventSource.get()) sourcePtr = nullptr;
631 auto rc = sd_event_add_io(event.get(), &sourcePtr, pldmFd, EPOLLIN,
632 pldmRspCallback, this);
633 if (rc < 0)
634 {
635 log<level::ERR>(
636 fmt::format(
637 "registerPldmRspCallback: sd_event_add_io: Error({})={} : fd={}",
638 rc, strerror(-rc), pldmFd)
639 .c_str());
Chris Caind1b68262022-02-28 09:56:50 -0600640 }
641 else
Patrick Williams05e95592021-09-02 09:28:14 -0500642 {
Chris Cainbae4d072022-02-28 09:46:50 -0600643 // puts sourcePtr in the event source.
644 eventSource.reset(sourcePtr);
645 }
646}
647
648// Add a timer to the event loop, default 30s.
649void Interface::pldmRspExpired()
650{
651 if (!pldmResponseReceived)
652 {
653 log<level::ERR>(
654 fmt::format(
655 "pldmRspExpired: timerCallback - timeout waiting for pldm response for OCC{}",
656 pldmResponseOcc)
657 .c_str());
658 pldmResponseTimeout = true;
659 if (pldmFd)
660 {
661 pldmClose();
662 }
663 }
664 return;
665};
666
667void Interface::pldmClose()
668{
669 if (pldmRspTimer.isEnabled())
670 {
671 // stop PLDM response timer
672 pldmRspTimer.setEnabled(false);
673 }
674 close(pldmFd);
675 pldmFd = -1;
676 eventSource.reset();
677}
678
679int Interface::pldmRspCallback(sd_event_source* /*es*/, int fd,
680 uint32_t revents, void* userData)
681{
682 if (!(revents & EPOLLIN))
683 {
684 log<level::INFO>(
685 fmt::format("pldmRspCallback - revents={:08X}", revents).c_str());
686 return -1;
687 }
688
689 auto pldmIface = static_cast<Interface*>(userData);
690
Chris Cain8b508bf2022-05-26 14:01:31 -0500691 if (!pldmIface->mctpInstance)
692 {
693 log<level::ERR>(
694 "pldmRspCallback: No outstanding MCTP Instance ID found");
695 return -1;
696 }
697
Chris Cainbae4d072022-02-28 09:46:50 -0600698 uint8_t* responseMsg = nullptr;
699 size_t responseMsgSize{};
700
701 log<level::INFO>(
702 fmt::format("pldmRspCallback: calling pldm_recv() instance:{}",
Chris Cain8b508bf2022-05-26 14:01:31 -0500703 pldmIface->mctpInstance.value())
Chris Cainbae4d072022-02-28 09:46:50 -0600704 .c_str());
Chris Cain8b508bf2022-05-26 14:01:31 -0500705 auto rc = pldm_recv(mctpEid, fd, pldmIface->mctpInstance.value(),
706 &responseMsg, &responseMsgSize);
Chris Cainbae4d072022-02-28 09:46:50 -0600707 int lastErrno = errno;
708 if (rc)
709 {
710 log<level::ERR>(
711 fmt::format(
712 "pldmRspCallback: pldm_recv failed with rc={}, errno={}/{}", rc,
713 lastErrno, strerror(lastErrno))
714 .c_str());
715 return -1;
716 }
Chris Cain8b508bf2022-05-26 14:01:31 -0500717
718 // We got the response for the PLDM request msg that was sent
Chris Cainbae4d072022-02-28 09:46:50 -0600719 log<level::INFO>(
720 fmt::format("pldmRspCallback: pldm_recv() rsp was {} bytes",
721 responseMsgSize)
722 .c_str());
723
724 if (pldmIface->pldmRspTimer.isEnabled())
725 {
726 // stop PLDM response timer
727 pldmIface->pldmRspTimer.setEnabled(false);
728 }
729
Chris Cain8b508bf2022-05-26 14:01:31 -0500730 // instance ID should be freed
731 pldmIface->mctpInstance = std::nullopt;
732
Chris Cainbae4d072022-02-28 09:46:50 -0600733 // Set pointer to autodelete
734 std::unique_ptr<uint8_t, decltype(std::free)*> responseMsgPtr{responseMsg,
735 std::free};
736
Chris Cainbae4d072022-02-28 09:46:50 -0600737 auto response = reinterpret_cast<pldm_msg*>(responseMsgPtr.get());
738 if (response->payload[0] != PLDM_SUCCESS)
739 {
740 log<level::ERR>(
741 fmt::format("pldmRspCallback: payload[0] was not success: {}",
742 response->payload[0])
743 .c_str());
744 pldmIface->pldmClose();
745 return -1;
746 }
747
748 // Decode the response
749 uint8_t compCode = 0, sensorCount = 1;
750 get_sensor_state_field field[6];
751 responseMsgSize -= sizeof(pldm_msg_hdr);
752 auto msgRc = decode_get_state_sensor_readings_resp(
753 response, responseMsgSize, &compCode, &sensorCount, field);
754 if ((msgRc != PLDM_SUCCESS) || (compCode != PLDM_SUCCESS))
755 {
756 log<level::ERR>(
757 fmt::format(
758 "pldmRspCallback: decode_get_state_sensor_readings failed with rc={} and compCode={}",
759 msgRc, compCode)
760 .c_str());
761 pldmIface->pldmClose();
762 return -1;
763 }
764
765 pldmIface->pldmClose();
766
767 const uint8_t instance = pldmIface->pldmResponseOcc;
768 const uint8_t occSensorState = field[0].present_state;
769 pldmIface->pldmResponseReceived = true;
770
771 if (occSensorState == PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_IN_SERVICE)
772 {
773 log<level::INFO>(
774 fmt::format("pldmRspCallback: OCC{} is RUNNING", instance).c_str());
775 pldmIface->callBack(instance, true);
776 }
Chris Cain733b2012022-05-04 11:54:06 -0500777 else if (occSensorState ==
778 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_DORMANT)
779 {
780 log<level::INFO>(
781 fmt::format(
782 "pldmRspCallback: OCC{} has now STOPPED and system is in SAFE MODE",
783 instance)
784 .c_str());
Sheldon Bailey31a2f132022-05-20 11:31:52 -0500785
786 // Setting safe mode true
787 pldmIface->safeModeCallBack(true);
788
Chris Cain733b2012022-05-04 11:54:06 -0500789 pldmIface->callBack(instance, false);
790 }
Chris Cainbae4d072022-02-28 09:46:50 -0600791 else
792 {
793 log<level::INFO>(
Chris Cain8b508bf2022-05-26 14:01:31 -0500794 fmt::format(
795 "pldmRspCallback: OCC{} is not running (sensor state:{})",
796 instance, occSensorState)
Chris Cainbae4d072022-02-28 09:46:50 -0600797 .c_str());
Chris Cainc9dc4412023-03-06 15:56:34 -0600798 if (occSensorState != PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_STOPPED)
799 {
800 const size_t rspLength = responseMsgSize + sizeof(pldm_msg_hdr);
801 std::vector<std::uint8_t> pldmResponse(rspLength);
802 memcpy(&pldmResponse[0], reinterpret_cast<std::uint8_t*>(response),
803 rspLength);
804 log<level::ERR>(
805 fmt::format(
806 "pldmRspCallback: Bad State - PLDM response ({} bytes) for OCC{}:",
807 rspLength, instance)
808 .c_str());
809 dump_hex(pldmResponse);
810 }
Chris Cainbae4d072022-02-28 09:46:50 -0600811 pldmIface->callBack(instance, false);
812 }
813
814 return 0;
815};
816
817std::vector<uint8_t> Interface::encodeGetStateSensorRequest(uint8_t instance,
818 uint16_t sensorId)
819{
Chris Cain8b508bf2022-05-26 14:01:31 -0500820 if (!getMctpInstanceId())
821 {
822 log<level::ERR>(
823 "encodeGetStateSensorRequest: failed to getMctpInstanceId");
824 return std::vector<uint8_t>();
825 }
826
Chris Cainbae4d072022-02-28 09:46:50 -0600827 bitfield8_t sRearm = {0};
828 const size_t msgSize =
829 sizeof(pldm_msg_hdr) + PLDM_GET_STATE_SENSOR_READINGS_REQ_BYTES;
830 std::vector<uint8_t> request(msgSize);
Chris Cain8b508bf2022-05-26 14:01:31 -0500831
Chris Cainbae4d072022-02-28 09:46:50 -0600832 auto msg = reinterpret_cast<pldm_msg*>(request.data());
Chris Cain8b508bf2022-05-26 14:01:31 -0500833 auto msgRc = encode_get_state_sensor_readings_req(mctpInstance.value(),
834 sensorId, sRearm, 0, msg);
Chris Cainbae4d072022-02-28 09:46:50 -0600835 if (msgRc != PLDM_SUCCESS)
836 {
837 log<level::ERR>(
838 fmt::format(
839 "encodeGetStateSensorRequest: Failed to encode sensorId:0x{:08X} for OCC{} (rc={})",
840 sensorId, instance, msgRc)
841 .c_str());
842 }
843 return request;
844}
845
846// Initiate query of the specified OCC Active Sensor
847void Interface::checkActiveSensor(uint8_t instance)
848{
849 static bool tracedOnce = false;
850 if (pldmFd > 0)
851 {
852 if (!tracedOnce)
Chris Caind1b68262022-02-28 09:56:50 -0600853 {
854 log<level::ERR>(
855 fmt::format(
Chris Cainbae4d072022-02-28 09:46:50 -0600856 "checkActiveSensor: already waiting on OCC{} (fd={})",
857 pldmResponseOcc, pldmFd)
Chris Caind1b68262022-02-28 09:56:50 -0600858 .c_str());
Chris Cainbae4d072022-02-28 09:46:50 -0600859 tracedOnce = true;
Chris Caind1b68262022-02-28 09:56:50 -0600860 }
Chris Cainbae4d072022-02-28 09:46:50 -0600861 return;
862 }
863 tracedOnce = false;
864
865 if (!isOCCSensorCacheValid())
866 {
867 fetchSensorInfo(PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS,
868 sensorToOCCInstance, OCCSensorOffset);
869 }
870
871 // look up sensor id (key) based on instance
872 auto entry = std::find_if(
873 sensorToOCCInstance.begin(), sensorToOCCInstance.end(),
874 [instance](const auto& entry) { return instance == entry.second; });
875 if (entry != sensorToOCCInstance.end())
876 {
877 // Query the OCC Active Sensor state for this instance
878 // SensorID sID = entry->first;
879 log<level::INFO>(
880 fmt::format("checkActiveSensor: OCC{} / sensorID: 0x{:04X}",
881 instance, entry->first)
882 .c_str());
883
Chris Cainbae4d072022-02-28 09:46:50 -0600884 // Encode GetStateSensorReadings PLDM message
885 auto request = encodeGetStateSensorRequest(instance, entry->first);
886 if (request.empty())
887 {
888 return;
889 }
890
891 // Send request to PLDM and setup callback for response
892 sendPldm(request, instance, true);
893 }
894 else
895 {
896 log<level::ERR>(
897 fmt::format(
898 "checkActiveSensor: Unable to find PLDM sensor for OCC{}",
899 instance)
900 .c_str());
Chris Cain8cf74962022-06-29 08:45:16 -0500901 log<level::INFO>(
902 "checkActiveSensor: fetching STATE_SET_OPERATIONAL_RUNNING_STATUS");
903 fetchSensorInfo(PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS,
904 sensorToOCCInstance, OCCSensorOffset);
Patrick Williams05e95592021-09-02 09:28:14 -0500905 }
Patrick Williams05e95592021-09-02 09:28:14 -0500906}
907
908} // namespace pldm