blob: 1ce23f43f11c34a195427d15ebac7e4a0d45e327 [file] [log] [blame]
Patrick Williams05e95592021-09-02 09:28:14 -05001#include "pldm.hpp"
2
3#include "file.hpp"
4
5#include <fmt/core.h>
6#include <libpldm/entity.h>
7#include <libpldm/platform.h>
8#include <libpldm/state_set.h>
Eddie James36313c72021-11-18 08:27:03 -06009#include <libpldm/state_set_oem_ibm.h>
Patrick Williams05e95592021-09-02 09:28:14 -050010
11#include <phosphor-logging/log.hpp>
Chris Cainbae4d072022-02-28 09:46:50 -060012#include <sdbusplus/bus.hpp>
13#include <sdeventplus/clock.hpp>
14#include <sdeventplus/exception.hpp>
15#include <sdeventplus/source/io.hpp>
16#include <sdeventplus/source/time.hpp>
17
18#include <algorithm>
Patrick Williams05e95592021-09-02 09:28:14 -050019
20namespace pldm
21{
22
Patrick Williams05e95592021-09-02 09:28:14 -050023using namespace phosphor::logging;
24
Chris Cainbae4d072022-02-28 09:46:50 -060025using namespace sdeventplus;
26using namespace sdeventplus::source;
27constexpr auto clockId = sdeventplus::ClockId::RealTime;
28using Clock = sdeventplus::Clock<clockId>;
29using Timer = Time<clockId>;
30
Eddie Jamescbad2192021-10-07 09:39:39 -050031void Interface::fetchSensorInfo(uint16_t stateSetId,
32 SensorToInstance& sensorInstanceMap,
33 SensorOffset& sensorOffset)
Patrick Williams05e95592021-09-02 09:28:14 -050034{
Eddie Jamescbad2192021-10-07 09:39:39 -050035 PdrList pdrs{};
Chris Cainbae4d072022-02-28 09:46:50 -060036 static bool tracedError = false;
Eddie Jamescbad2192021-10-07 09:39:39 -050037
38 auto& bus = open_power::occ::utils::getBus();
39 try
40 {
41 auto method = bus.new_method_call(
42 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
43 "xyz.openbmc_project.PLDM.PDR", "FindStateSensorPDR");
Chris Cainbae4d072022-02-28 09:46:50 -060044 method.append(tid, static_cast<uint16_t>(PLDM_ENTITY_PROC), stateSetId);
Eddie Jamescbad2192021-10-07 09:39:39 -050045
46 auto responseMsg = bus.call(method);
47 responseMsg.read(pdrs);
48 }
49 catch (const sdbusplus::exception::exception& e)
50 {
Chris Cainbae4d072022-02-28 09:46:50 -060051 if (!tracedError)
52 {
53 log<level::ERR>(
54 fmt::format(
55 "fetchSensorInfo: Failed to find stateSetID:{} PDR: {}",
56 stateSetId, e.what())
57 .c_str());
58 tracedError = true;
59 }
Eddie Jamescbad2192021-10-07 09:39:39 -050060 }
61
62 if (pdrs.empty())
63 {
Chris Cainbae4d072022-02-28 09:46:50 -060064 if (!tracedError)
65 {
66 log<level::ERR>(
67 fmt::format(
68 "fetchSensorInfo: state sensor PDRs ({}) not present",
69 stateSetId)
70 .c_str());
71 tracedError = true;
72 }
Eddie Jamescbad2192021-10-07 09:39:39 -050073 return;
74 }
75
Chris Cainbae4d072022-02-28 09:46:50 -060076 // Found PDR
77 if (tracedError)
78 {
79 log<level::INFO>(
80 fmt::format("fetchSensorInfo: found {} PDRs", pdrs.size()).c_str());
81 tracedError = false;
82 }
83
Patrick Williams05e95592021-09-02 09:28:14 -050084 bool offsetFound = false;
George Liuf3a4a692021-12-28 13:59:51 +080085 auto stateSensorPDR =
Patrick Williams05e95592021-09-02 09:28:14 -050086 reinterpret_cast<const pldm_state_sensor_pdr*>(pdrs.front().data());
George Liuf3a4a692021-12-28 13:59:51 +080087 auto possibleStatesPtr = stateSensorPDR->possible_states;
88 for (auto offset = 0; offset < stateSensorPDR->composite_sensor_count;
89 offset++)
Patrick Williams05e95592021-09-02 09:28:14 -050090 {
91 auto possibleStates =
92 reinterpret_cast<const state_sensor_possible_states*>(
93 possibleStatesPtr);
94
Eddie Jamescbad2192021-10-07 09:39:39 -050095 if (possibleStates->state_set_id == stateSetId)
Patrick Williams05e95592021-09-02 09:28:14 -050096 {
97 sensorOffset = offset;
98 offsetFound = true;
99 break;
100 }
101 possibleStatesPtr += sizeof(possibleStates->state_set_id) +
102 sizeof(possibleStates->possible_states_size) +
103 possibleStates->possible_states_size;
104 }
105
106 if (!offsetFound)
107 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500108 log<level::ERR>("pldm: state sensor PDR not found");
Patrick Williams05e95592021-09-02 09:28:14 -0500109 return;
110 }
111
112 // To order SensorID based on the EntityInstance.
113 // Note that when a proc is on a DCM, the PDRs for these sensors
114 // could have the same instance IDs but different container IDs.
115 std::map<uint32_t, SensorID> entityInstMap{};
116 for (auto& pdr : pdrs)
117 {
118 auto pdrPtr =
119 reinterpret_cast<const pldm_state_sensor_pdr*>(pdr.data());
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
132void Interface::sensorEvent(sdbusplus::message::message& msg)
133{
Chris Cain72d01aa2022-06-14 16:28:03 -0500134 if (!open_power::occ::utils::isHostRunning())
135 {
136 clearData();
137 return;
138 }
139
Patrick Williams05e95592021-09-02 09:28:14 -0500140 if (!isOCCSensorCacheValid())
141 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500142 fetchSensorInfo(PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS,
143 sensorToOCCInstance, OCCSensorOffset);
144 }
Patrick Williams05e95592021-09-02 09:28:14 -0500145
Eddie Jamescbad2192021-10-07 09:39:39 -0500146 if (sensorToSBEInstance.empty())
147 {
148 fetchSensorInfo(PLDM_OEM_IBM_SBE_HRESET_STATE, sensorToSBEInstance,
149 SBESensorOffset);
Patrick Williams05e95592021-09-02 09:28:14 -0500150 }
151
Chris Cain72d01aa2022-06-14 16:28:03 -0500152 TerminusID sensorTid{};
Patrick Williams05e95592021-09-02 09:28:14 -0500153 SensorID sensorId{};
154 SensorOffset msgSensorOffset{};
155 EventState eventState{};
156 EventState previousEventState{};
157
Chris Cain72d01aa2022-06-14 16:28:03 -0500158 msg.read(sensorTid, sensorId, msgSensorOffset, eventState,
159 previousEventState);
Patrick Williams05e95592021-09-02 09:28:14 -0500160
Eddie Jamescbad2192021-10-07 09:39:39 -0500161 if (msgSensorOffset == OCCSensorOffset)
Patrick Williams05e95592021-09-02 09:28:14 -0500162 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500163 auto sensorEntry = sensorToOCCInstance.find(sensorId);
Patrick Williams05e95592021-09-02 09:28:14 -0500164
Eddie James432dc482021-11-19 15:29:31 -0600165 if (sensorEntry != sensorToOCCInstance.end())
Eddie Jamescbad2192021-10-07 09:39:39 -0500166 {
Chris Cain8b508bf2022-05-26 14:01:31 -0500167 const uint8_t instance = sensorEntry->second;
Eddie James432dc482021-11-19 15:29:31 -0600168 if (eventState ==
169 static_cast<EventState>(
170 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_IN_SERVICE))
171 {
172 log<level::INFO>(
Chris Cain8b508bf2022-05-26 14:01:31 -0500173 fmt::format("PLDM: OCC{} is RUNNING", instance).c_str());
Eddie James432dc482021-11-19 15:29:31 -0600174 callBack(sensorEntry->second, true);
175 }
176 else if (eventState ==
177 static_cast<EventState>(
178 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_STOPPED))
179 {
Chris Cain8b508bf2022-05-26 14:01:31 -0500180 log<level::INFO>(
181 fmt::format("PLDM: OCC{} has now STOPPED", instance)
182 .c_str());
183 callBack(instance, false);
Eddie James432dc482021-11-19 15:29:31 -0600184 }
Chris Cainbae4d072022-02-28 09:46:50 -0600185 else if (eventState ==
186 static_cast<EventState>(
187 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_DORMANT))
188 {
189 log<level::INFO>(
190 fmt::format(
191 "PLDM: OCC{} has now STOPPED and system is in SAFE MODE",
Chris Cain8b508bf2022-05-26 14:01:31 -0500192 instance)
Chris Cainbae4d072022-02-28 09:46:50 -0600193 .c_str());
Sheldon Bailey31a2f132022-05-20 11:31:52 -0500194
195 // Setting safe mode true
196 safeModeCallBack(true);
197
Chris Cain8b508bf2022-05-26 14:01:31 -0500198 callBack(instance, false);
Chris Cainbae4d072022-02-28 09:46:50 -0600199 }
200 else
201 {
202 log<level::INFO>(
203 fmt::format("PLDM: Unexpected PLDM state {} for OCC{}",
Chris Cain8b508bf2022-05-26 14:01:31 -0500204 eventState, instance)
Chris Cainbae4d072022-02-28 09:46:50 -0600205 .c_str());
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
Chris Cainbae4d072022-02-28 09:46:50 -0600246void Interface::clearData()
247{
Chris Cain72d01aa2022-06-14 16:28:03 -0500248 if (!sensorToOCCInstance.empty())
249 {
250 log<level::INFO>(
251 fmt::format("clearData: Clearing sensorToOCCInstance ({} entries)",
252 sensorToOCCInstance.size())
253 .c_str());
254 for (auto entry : sensorToOCCInstance)
255 {
256 log<level::INFO>(
257 fmt::format("clearData: OCC{} / sensorID: 0x{:04X}",
258 entry.second, entry.first)
259 .c_str());
260 }
261 sensorToOCCInstance.clear();
262 }
263 if (!occInstanceToEffecter.empty())
264 {
265 log<level::DEBUG>(
266 fmt::format(
267 "clearData: Clearing occInstanceToEffecter ({} entries)",
268 occInstanceToEffecter.size())
269 .c_str());
270 occInstanceToEffecter.clear();
271 }
272 if (!sensorToSBEInstance.empty())
273 {
274 log<level::DEBUG>(
275 fmt::format("clearData: Clearing sensorToSBEInstance ({} entries)",
276 sensorToSBEInstance.size())
277 .c_str());
278 sensorToSBEInstance.clear();
279 }
280 if (!sbeInstanceToEffecter.empty())
281 {
282 log<level::DEBUG>(
283 fmt::format(
284 "clearData: Clearing sbeInstanceToEffecter ({} entries)",
285 sbeInstanceToEffecter.size())
286 .c_str());
287 sbeInstanceToEffecter.clear();
288 }
Chris Cainbae4d072022-02-28 09:46:50 -0600289}
290
Eddie James432dc482021-11-19 15:29:31 -0600291void Interface::fetchEffecterInfo(uint16_t stateSetId,
Eddie Jamescbad2192021-10-07 09:39:39 -0500292 InstanceToEffecter& instanceToEffecterMap,
293 CompositeEffecterCount& effecterCount,
294 uint8_t& stateIdPos)
Patrick Williams05e95592021-09-02 09:28:14 -0500295{
Eddie Jamescbad2192021-10-07 09:39:39 -0500296 PdrList pdrs{};
297
298 auto& bus = open_power::occ::utils::getBus();
299 try
300 {
301 auto method = bus.new_method_call(
302 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
303 "xyz.openbmc_project.PLDM.PDR", "FindStateEffecterPDR");
Chris Cainbae4d072022-02-28 09:46:50 -0600304 method.append(tid, static_cast<uint16_t>(PLDM_ENTITY_PROC), stateSetId);
Eddie Jamescbad2192021-10-07 09:39:39 -0500305
306 auto responseMsg = bus.call(method);
307 responseMsg.read(pdrs);
308 }
309 catch (const sdbusplus::exception::exception& e)
310 {
311 log<level::ERR>("pldm: Failed to fetch the state effecter PDRs",
312 entry("ERROR=%s", e.what()));
313 }
314
315 if (!pdrs.size())
316 {
317 log<level::ERR>("pldm: state effecter PDRs not present");
318 return;
319 }
320
Patrick Williams05e95592021-09-02 09:28:14 -0500321 bool offsetFound = false;
George Liuf3a4a692021-12-28 13:59:51 +0800322 auto stateEffecterPDR =
Patrick Williams05e95592021-09-02 09:28:14 -0500323 reinterpret_cast<const pldm_state_effecter_pdr*>(pdrs.front().data());
George Liuf3a4a692021-12-28 13:59:51 +0800324 auto possibleStatesPtr = stateEffecterPDR->possible_states;
325 for (auto offset = 0; offset < stateEffecterPDR->composite_effecter_count;
326 offset++)
Patrick Williams05e95592021-09-02 09:28:14 -0500327 {
328 auto possibleStates =
329 reinterpret_cast<const state_effecter_possible_states*>(
330 possibleStatesPtr);
331
Eddie Jamescbad2192021-10-07 09:39:39 -0500332 if (possibleStates->state_set_id == stateSetId)
Patrick Williams05e95592021-09-02 09:28:14 -0500333 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500334 stateIdPos = offset;
George Liuf3a4a692021-12-28 13:59:51 +0800335 effecterCount = stateEffecterPDR->composite_effecter_count;
Patrick Williams05e95592021-09-02 09:28:14 -0500336 offsetFound = true;
337 break;
338 }
339 possibleStatesPtr += sizeof(possibleStates->state_set_id) +
340 sizeof(possibleStates->possible_states_size) +
341 possibleStates->possible_states_size;
342 }
343
344 if (!offsetFound)
345 {
346 return;
347 }
348
Chris Cain0f516522022-02-07 14:48:28 -0600349 std::map<uint32_t, EffecterID> entityInstMap{};
Patrick Williams05e95592021-09-02 09:28:14 -0500350 for (auto& pdr : pdrs)
351 {
352 auto pdrPtr =
353 reinterpret_cast<const pldm_state_effecter_pdr*>(pdr.data());
Chris Cain72d01aa2022-06-14 16:28:03 -0500354 uint32_t key = pdrPtr->effecter_id;
Patrick Williams05e95592021-09-02 09:28:14 -0500355 entityInstMap.emplace(key, static_cast<SensorID>(pdrPtr->effecter_id));
356 }
357
358 open_power::occ::instanceID position = start;
359 for (auto const& pair : entityInstMap)
360 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500361 instanceToEffecterMap.emplace(position, pair.second);
Patrick Williams05e95592021-09-02 09:28:14 -0500362 position++;
363 }
364}
365
366std::vector<uint8_t>
Chris Cain8b508bf2022-05-26 14:01:31 -0500367 Interface::prepareSetEffecterReq(EffecterID effecterId,
Patrick Williams05e95592021-09-02 09:28:14 -0500368 CompositeEffecterCount effecterCount,
Eddie Jamescbad2192021-10-07 09:39:39 -0500369 uint8_t stateIdPos, uint8_t stateSetValue)
Patrick Williams05e95592021-09-02 09:28:14 -0500370{
Chris Cain8b508bf2022-05-26 14:01:31 -0500371 if (!getMctpInstanceId())
372 {
373 return std::vector<uint8_t>();
374 }
375
Patrick Williams05e95592021-09-02 09:28:14 -0500376 std::vector<uint8_t> request(
377 sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(effecterCount) +
378 (effecterCount * sizeof(set_effecter_state_field)));
379 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
380 std::vector<set_effecter_state_field> stateField;
381
382 for (uint8_t effecterPos = 0; effecterPos < effecterCount; effecterPos++)
383 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500384 if (effecterPos == stateIdPos)
Patrick Williams05e95592021-09-02 09:28:14 -0500385 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500386 stateField.emplace_back(
387 set_effecter_state_field{PLDM_REQUEST_SET, stateSetValue});
Patrick Williams05e95592021-09-02 09:28:14 -0500388 }
389 else
390 {
391 stateField.emplace_back(
392 set_effecter_state_field{PLDM_NO_CHANGE, 0});
393 }
394 }
395 auto rc = encode_set_state_effecter_states_req(
Chris Cain8b508bf2022-05-26 14:01:31 -0500396 mctpInstance.value(), effecterId, effecterCount, stateField.data(),
397 requestMsg);
Patrick Williams05e95592021-09-02 09:28:14 -0500398 if (rc != PLDM_SUCCESS)
399 {
400 log<level::ERR>("encode set effecter states request returned error ",
401 entry("RC=%d", rc));
402 request.clear();
403 }
404 return request;
405}
406
407void Interface::resetOCC(open_power::occ::instanceID occInstanceId)
408{
Chris Cainbae4d072022-02-28 09:46:50 -0600409 if (open_power::occ::utils::isHostRunning())
Patrick Williams05e95592021-09-02 09:28:14 -0500410 {
Chris Cainbae4d072022-02-28 09:46:50 -0600411 if (!isPDREffecterCacheValid())
412 {
413 fetchEffecterInfo(PLDM_STATE_SET_BOOT_RESTART_CAUSE,
414 occInstanceToEffecter, OCCEffecterCount,
415 bootRestartPosition);
416 }
Patrick Williams05e95592021-09-02 09:28:14 -0500417
Chris Cainbae4d072022-02-28 09:46:50 -0600418 // Find the matching effecter for the OCC instance
419 auto effecterEntry = occInstanceToEffecter.find(occInstanceId);
420 if (effecterEntry == occInstanceToEffecter.end())
421 {
422 log<level::ERR>(
423 fmt::format(
424 "pldm: Failed to find a matching effecter for OCC instance {}",
425 occInstanceId)
426 .c_str());
427
428 return;
429 }
430
Chris Cainbae4d072022-02-28 09:46:50 -0600431 // Prepare the SetStateEffecterStates request to reset the OCC
432 auto request = prepareSetEffecterReq(
Chris Cain8b508bf2022-05-26 14:01:31 -0500433 effecterEntry->second, OCCEffecterCount, bootRestartPosition,
434 PLDM_STATE_SET_BOOT_RESTART_CAUSE_WARM_RESET);
Chris Cainbae4d072022-02-28 09:46:50 -0600435
436 if (request.empty())
437 {
438 log<level::ERR>(
439 "pldm: SetStateEffecterStates OCC reset request empty");
440 return;
441 }
442
443 // Send request to reset the OCCs/PM Complex (ignore response)
444 sendPldm(request, occInstanceId, false);
445 }
446 else
Patrick Williams05e95592021-09-02 09:28:14 -0500447 {
448 log<level::ERR>(
Chris Cainbae4d072022-02-28 09:46:50 -0600449 fmt::format("resetOCC: HOST is not running (OCC{})", occInstanceId)
Chris Cain0f516522022-02-07 14:48:28 -0600450 .c_str());
Chris Cainbae4d072022-02-28 09:46:50 -0600451 clearData();
Patrick Williams05e95592021-09-02 09:28:14 -0500452 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500453}
454
455void Interface::sendHRESET(open_power::occ::instanceID sbeInstanceId)
456{
Chris Cainbae4d072022-02-28 09:46:50 -0600457 if (open_power::occ::utils::isHostRunning())
Eddie Jamescbad2192021-10-07 09:39:39 -0500458 {
Chris Cainbae4d072022-02-28 09:46:50 -0600459 if (sbeInstanceToEffecter.empty())
460 {
461 fetchEffecterInfo(PLDM_OEM_IBM_SBE_MAINTENANCE_STATE,
462 sbeInstanceToEffecter, SBEEffecterCount,
463 sbeMaintenanceStatePosition);
464 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500465
Chris Cainbae4d072022-02-28 09:46:50 -0600466 auto effecterEntry = sbeInstanceToEffecter.find(sbeInstanceId);
467 if (effecterEntry == sbeInstanceToEffecter.end())
468 {
469 log<level::ERR>(
470 "pldm: Failed to find a matching effecter for SBE instance",
471 entry("SBE=%d", sbeInstanceId));
472 return;
473 }
474
Chris Cainbae4d072022-02-28 09:46:50 -0600475 // Prepare the SetStateEffecterStates request to HRESET the SBE
476 auto request = prepareSetEffecterReq(
Chris Cain8b508bf2022-05-26 14:01:31 -0500477 effecterEntry->second, SBEEffecterCount,
Chris Cainbae4d072022-02-28 09:46:50 -0600478 sbeMaintenanceStatePosition, SBE_RETRY_REQUIRED);
479
480 if (request.empty())
481 {
482 log<level::ERR>(
483 "pldm: SetStateEffecterStates HRESET request empty");
484 return;
485 }
486
487 // Send request to issue HRESET of SBE (ignore response)
488 sendPldm(request, sbeInstanceId, false);
Chris Cain12d0b822022-04-22 17:29:18 -0500489 outstandingHResets.insert(sbeInstanceId);
Chris Cainbae4d072022-02-28 09:46:50 -0600490 }
491 else
Eddie Jamescbad2192021-10-07 09:39:39 -0500492 {
Chris Cainbae4d072022-02-28 09:46:50 -0600493 log<level::ERR>(fmt::format("sendHRESET: HOST is not running (OCC{})",
494 sbeInstanceId)
495 .c_str());
496 clearData();
Eddie Jamescbad2192021-10-07 09:39:39 -0500497 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500498}
499
Chris Cain8b508bf2022-05-26 14:01:31 -0500500bool Interface::getMctpInstanceId()
Eddie Jamescbad2192021-10-07 09:39:39 -0500501{
Chris Cain8b508bf2022-05-26 14:01:31 -0500502 if (!mctpInstance)
Patrick Williams05e95592021-09-02 09:28:14 -0500503 {
Chris Cain8b508bf2022-05-26 14:01:31 -0500504 // Request new instance ID
505 auto& bus = open_power::occ::utils::getBus();
506 try
507 {
508 auto method = bus.new_method_call(
509 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
510 "xyz.openbmc_project.PLDM.Requester", "GetInstanceId");
511 method.append(mctpEid);
512 auto reply = bus.call(method);
513 uint8_t newInstanceId;
514 reply.read(newInstanceId);
515 mctpInstance = newInstanceId;
516 log<level::INFO>(fmt::format("pldm: got new InstanceId: {}",
517 mctpInstance.value())
518 .c_str());
519 }
520 catch (const sdbusplus::exception::exception& e)
521 {
522 log<level::ERR>(
523 fmt::format("pldm: GetInstanceId failed: {}", e.what())
524 .c_str());
525 return false;
526 }
Patrick Williams05e95592021-09-02 09:28:14 -0500527 }
528
Eddie Jamescbad2192021-10-07 09:39:39 -0500529 return true;
530}
Patrick Williams05e95592021-09-02 09:28:14 -0500531
Chris Cainbae4d072022-02-28 09:46:50 -0600532void Interface::sendPldm(const std::vector<uint8_t>& request,
533 const uint8_t instance, const bool rspExpected)
Eddie Jamescbad2192021-10-07 09:39:39 -0500534{
Chris Cain8b508bf2022-05-26 14:01:31 -0500535 if (!mctpInstance)
536 {
537 log<level::ERR>("sendPldm: No MCTP Instance ID found!");
538 return;
539 }
540
Patrick Williams05e95592021-09-02 09:28:14 -0500541 // Connect to MCTP scoket
Chris Cainbae4d072022-02-28 09:46:50 -0600542 pldmFd = pldm_open();
543 auto openErrno = errno;
544 if (pldmFd == PLDM_REQUESTER_OPEN_FAIL)
Patrick Williams05e95592021-09-02 09:28:14 -0500545 {
Chris Caind1b68262022-02-28 09:56:50 -0600546 log<level::ERR>(
Chris Cainbae4d072022-02-28 09:46:50 -0600547 fmt::format(
548 "sendPldm: Failed to connect to MCTP socket, errno={}/{}",
549 openErrno, strerror(openErrno))
Chris Caind1b68262022-02-28 09:56:50 -0600550 .c_str());
Patrick Williams05e95592021-09-02 09:28:14 -0500551 return;
552 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500553
Patrick Williams05e95592021-09-02 09:28:14 -0500554 // Send the PLDM request message to HBRT
Chris Cainbae4d072022-02-28 09:46:50 -0600555 if (rspExpected)
Patrick Williams05e95592021-09-02 09:28:14 -0500556 {
Chris Cainbae4d072022-02-28 09:46:50 -0600557 // Register callback when response is available
558 registerPldmRspCallback();
559
560 // Send PLDM request
561 log<level::INFO>(
562 fmt::format(
563 "sendPldm: calling pldm_send(OCC{}, instance:{}, {} bytes)",
Chris Cain8b508bf2022-05-26 14:01:31 -0500564 instance, mctpInstance.value(), request.size())
Chris Cainbae4d072022-02-28 09:46:50 -0600565 .c_str());
566 pldmResponseReceived = false;
567 pldmResponseTimeout = false;
568 pldmResponseOcc = instance;
569 auto pldmRc =
570 pldm_send(mctpEid, pldmFd, request.data(), request.size());
571 auto sendErrno = errno;
572 if (pldmRc != PLDM_REQUESTER_SUCCESS)
573 {
574 log<level::ERR>(
575 fmt::format(
576 "sendPldm: pldm_send failed with rc={} and errno={}/{}",
577 pldmRc, sendErrno, strerror(sendErrno))
578 .c_str());
579 pldmClose();
580 return;
581 }
582
583 // start timer waiting for the response
584 using namespace std::literals::chrono_literals;
Chris Cainbd551de2022-04-26 13:41:16 -0500585 pldmRspTimer.restartOnce(8s);
Chris Cainbae4d072022-02-28 09:46:50 -0600586
587 // Wait for response/timeout
588 }
589 else // not expecting the response
590 {
591 log<level::INFO>(
592 fmt::format(
593 "sendPldm: calling pldm_send(mctpID:{}, fd:{}, {} bytes) for OCC{}",
594 mctpEid, pldmFd, request.size(), instance)
595 .c_str());
596 auto rc = pldm_send(mctpEid, pldmFd, request.data(), request.size());
597 auto sendErrno = errno;
Chris Caind1b68262022-02-28 09:56:50 -0600598 if (rc)
599 {
600 log<level::ERR>(
601 fmt::format(
Chris Cainbae4d072022-02-28 09:46:50 -0600602 "sendPldm: pldm_send(mctpID:{}, fd:{}, {} bytes) failed with rc={} and errno={}/{}",
603 mctpEid, pldmFd, request.size(), rc, sendErrno,
604 strerror(sendErrno))
Chris Caind1b68262022-02-28 09:56:50 -0600605 .c_str());
606 }
Chris Cain8b508bf2022-05-26 14:01:31 -0500607 else
608 {
609 // Not waiting for response, instance ID should be freed
610 mctpInstance = std::nullopt;
611 }
Chris Cainbae4d072022-02-28 09:46:50 -0600612 pldmClose();
613 }
614}
Patrick Williams05e95592021-09-02 09:28:14 -0500615
Chris Cainbae4d072022-02-28 09:46:50 -0600616// Attaches the FD to event loop and registers the callback handler
617void Interface::registerPldmRspCallback()
618{
619 decltype(eventSource.get()) sourcePtr = nullptr;
620 auto rc = sd_event_add_io(event.get(), &sourcePtr, pldmFd, EPOLLIN,
621 pldmRspCallback, this);
622 if (rc < 0)
623 {
624 log<level::ERR>(
625 fmt::format(
626 "registerPldmRspCallback: sd_event_add_io: Error({})={} : fd={}",
627 rc, strerror(-rc), pldmFd)
628 .c_str());
Chris Caind1b68262022-02-28 09:56:50 -0600629 }
630 else
Patrick Williams05e95592021-09-02 09:28:14 -0500631 {
Chris Cainbae4d072022-02-28 09:46:50 -0600632 // puts sourcePtr in the event source.
633 eventSource.reset(sourcePtr);
634 }
635}
636
637// Add a timer to the event loop, default 30s.
638void Interface::pldmRspExpired()
639{
640 if (!pldmResponseReceived)
641 {
642 log<level::ERR>(
643 fmt::format(
644 "pldmRspExpired: timerCallback - timeout waiting for pldm response for OCC{}",
645 pldmResponseOcc)
646 .c_str());
647 pldmResponseTimeout = true;
648 if (pldmFd)
649 {
650 pldmClose();
651 }
652 }
653 return;
654};
655
656void Interface::pldmClose()
657{
658 if (pldmRspTimer.isEnabled())
659 {
660 // stop PLDM response timer
661 pldmRspTimer.setEnabled(false);
662 }
663 close(pldmFd);
664 pldmFd = -1;
665 eventSource.reset();
666}
667
668int Interface::pldmRspCallback(sd_event_source* /*es*/, int fd,
669 uint32_t revents, void* userData)
670{
671 if (!(revents & EPOLLIN))
672 {
673 log<level::INFO>(
674 fmt::format("pldmRspCallback - revents={:08X}", revents).c_str());
675 return -1;
676 }
677
678 auto pldmIface = static_cast<Interface*>(userData);
679
Chris Cain8b508bf2022-05-26 14:01:31 -0500680 if (!pldmIface->mctpInstance)
681 {
682 log<level::ERR>(
683 "pldmRspCallback: No outstanding MCTP Instance ID found");
684 return -1;
685 }
686
Chris Cainbae4d072022-02-28 09:46:50 -0600687 uint8_t* responseMsg = nullptr;
688 size_t responseMsgSize{};
689
690 log<level::INFO>(
691 fmt::format("pldmRspCallback: calling pldm_recv() instance:{}",
Chris Cain8b508bf2022-05-26 14:01:31 -0500692 pldmIface->mctpInstance.value())
Chris Cainbae4d072022-02-28 09:46:50 -0600693 .c_str());
Chris Cain8b508bf2022-05-26 14:01:31 -0500694 auto rc = pldm_recv(mctpEid, fd, pldmIface->mctpInstance.value(),
695 &responseMsg, &responseMsgSize);
Chris Cainbae4d072022-02-28 09:46:50 -0600696 int lastErrno = errno;
697 if (rc)
698 {
699 log<level::ERR>(
700 fmt::format(
701 "pldmRspCallback: pldm_recv failed with rc={}, errno={}/{}", rc,
702 lastErrno, strerror(lastErrno))
703 .c_str());
704 return -1;
705 }
Chris Cain8b508bf2022-05-26 14:01:31 -0500706
707 // We got the response for the PLDM request msg that was sent
Chris Cainbae4d072022-02-28 09:46:50 -0600708 log<level::INFO>(
709 fmt::format("pldmRspCallback: pldm_recv() rsp was {} bytes",
710 responseMsgSize)
711 .c_str());
712
713 if (pldmIface->pldmRspTimer.isEnabled())
714 {
715 // stop PLDM response timer
716 pldmIface->pldmRspTimer.setEnabled(false);
717 }
718
Chris Cain8b508bf2022-05-26 14:01:31 -0500719 // instance ID should be freed
720 pldmIface->mctpInstance = std::nullopt;
721
Chris Cainbae4d072022-02-28 09:46:50 -0600722 // Set pointer to autodelete
723 std::unique_ptr<uint8_t, decltype(std::free)*> responseMsgPtr{responseMsg,
724 std::free};
725
Chris Cainbae4d072022-02-28 09:46:50 -0600726 auto response = reinterpret_cast<pldm_msg*>(responseMsgPtr.get());
727 if (response->payload[0] != PLDM_SUCCESS)
728 {
729 log<level::ERR>(
730 fmt::format("pldmRspCallback: payload[0] was not success: {}",
731 response->payload[0])
732 .c_str());
733 pldmIface->pldmClose();
734 return -1;
735 }
736
737 // Decode the response
738 uint8_t compCode = 0, sensorCount = 1;
739 get_sensor_state_field field[6];
740 responseMsgSize -= sizeof(pldm_msg_hdr);
741 auto msgRc = decode_get_state_sensor_readings_resp(
742 response, responseMsgSize, &compCode, &sensorCount, field);
743 if ((msgRc != PLDM_SUCCESS) || (compCode != PLDM_SUCCESS))
744 {
745 log<level::ERR>(
746 fmt::format(
747 "pldmRspCallback: decode_get_state_sensor_readings failed with rc={} and compCode={}",
748 msgRc, compCode)
749 .c_str());
750 pldmIface->pldmClose();
751 return -1;
752 }
753
754 pldmIface->pldmClose();
755
756 const uint8_t instance = pldmIface->pldmResponseOcc;
757 const uint8_t occSensorState = field[0].present_state;
758 pldmIface->pldmResponseReceived = true;
759
760 if (occSensorState == PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_IN_SERVICE)
761 {
762 log<level::INFO>(
763 fmt::format("pldmRspCallback: OCC{} is RUNNING", instance).c_str());
764 pldmIface->callBack(instance, true);
765 }
Chris Cain733b2012022-05-04 11:54:06 -0500766 else if (occSensorState ==
767 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_DORMANT)
768 {
769 log<level::INFO>(
770 fmt::format(
771 "pldmRspCallback: OCC{} has now STOPPED and system is in SAFE MODE",
772 instance)
773 .c_str());
Sheldon Bailey31a2f132022-05-20 11:31:52 -0500774
775 // Setting safe mode true
776 pldmIface->safeModeCallBack(true);
777
Chris Cain733b2012022-05-04 11:54:06 -0500778 pldmIface->callBack(instance, false);
779 }
Chris Cainbae4d072022-02-28 09:46:50 -0600780 else
781 {
782 log<level::INFO>(
Chris Cain8b508bf2022-05-26 14:01:31 -0500783 fmt::format(
784 "pldmRspCallback: OCC{} is not running (sensor state:{})",
785 instance, occSensorState)
Chris Cainbae4d072022-02-28 09:46:50 -0600786 .c_str());
787 pldmIface->callBack(instance, false);
788 }
789
790 return 0;
791};
792
793std::vector<uint8_t> Interface::encodeGetStateSensorRequest(uint8_t instance,
794 uint16_t sensorId)
795{
Chris Cain8b508bf2022-05-26 14:01:31 -0500796 if (!getMctpInstanceId())
797 {
798 log<level::ERR>(
799 "encodeGetStateSensorRequest: failed to getMctpInstanceId");
800 return std::vector<uint8_t>();
801 }
802
Chris Cainbae4d072022-02-28 09:46:50 -0600803 bitfield8_t sRearm = {0};
804 const size_t msgSize =
805 sizeof(pldm_msg_hdr) + PLDM_GET_STATE_SENSOR_READINGS_REQ_BYTES;
806 std::vector<uint8_t> request(msgSize);
Chris Cain8b508bf2022-05-26 14:01:31 -0500807
Chris Cainbae4d072022-02-28 09:46:50 -0600808 auto msg = reinterpret_cast<pldm_msg*>(request.data());
Chris Cain8b508bf2022-05-26 14:01:31 -0500809 auto msgRc = encode_get_state_sensor_readings_req(mctpInstance.value(),
810 sensorId, sRearm, 0, msg);
Chris Cainbae4d072022-02-28 09:46:50 -0600811 if (msgRc != PLDM_SUCCESS)
812 {
813 log<level::ERR>(
814 fmt::format(
815 "encodeGetStateSensorRequest: Failed to encode sensorId:0x{:08X} for OCC{} (rc={})",
816 sensorId, instance, msgRc)
817 .c_str());
818 }
819 return request;
820}
821
822// Initiate query of the specified OCC Active Sensor
823void Interface::checkActiveSensor(uint8_t instance)
824{
825 static bool tracedOnce = false;
826 if (pldmFd > 0)
827 {
828 if (!tracedOnce)
Chris Caind1b68262022-02-28 09:56:50 -0600829 {
830 log<level::ERR>(
831 fmt::format(
Chris Cainbae4d072022-02-28 09:46:50 -0600832 "checkActiveSensor: already waiting on OCC{} (fd={})",
833 pldmResponseOcc, pldmFd)
Chris Caind1b68262022-02-28 09:56:50 -0600834 .c_str());
Chris Cainbae4d072022-02-28 09:46:50 -0600835 tracedOnce = true;
Chris Caind1b68262022-02-28 09:56:50 -0600836 }
Chris Cainbae4d072022-02-28 09:46:50 -0600837 return;
838 }
839 tracedOnce = false;
840
841 if (!isOCCSensorCacheValid())
842 {
843 fetchSensorInfo(PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS,
844 sensorToOCCInstance, OCCSensorOffset);
845 }
846
847 // look up sensor id (key) based on instance
848 auto entry = std::find_if(
849 sensorToOCCInstance.begin(), sensorToOCCInstance.end(),
850 [instance](const auto& entry) { return instance == entry.second; });
851 if (entry != sensorToOCCInstance.end())
852 {
853 // Query the OCC Active Sensor state for this instance
854 // SensorID sID = entry->first;
855 log<level::INFO>(
856 fmt::format("checkActiveSensor: OCC{} / sensorID: 0x{:04X}",
857 instance, entry->first)
858 .c_str());
859
Chris Cainbae4d072022-02-28 09:46:50 -0600860 // Encode GetStateSensorReadings PLDM message
861 auto request = encodeGetStateSensorRequest(instance, entry->first);
862 if (request.empty())
863 {
864 return;
865 }
866
867 // Send request to PLDM and setup callback for response
868 sendPldm(request, instance, true);
869 }
870 else
871 {
872 log<level::ERR>(
873 fmt::format(
874 "checkActiveSensor: Unable to find PLDM sensor for OCC{}",
875 instance)
876 .c_str());
Chris Cain72d01aa2022-06-14 16:28:03 -0500877 // Clear cache to recollect the sensor ids
878 clearData();
Patrick Williams05e95592021-09-02 09:28:14 -0500879 }
Patrick Williams05e95592021-09-02 09:28:14 -0500880}
881
882} // namespace pldm