blob: 41552efb8ed5ec0005cbe7e30c1fbd09710042b5 [file] [log] [blame]
Patrick Williams05e95592021-09-02 09:28:14 -05001#include "pldm.hpp"
2
3#include "file.hpp"
4
5#include <fmt/core.h>
6#include <libpldm/entity.h>
7#include <libpldm/platform.h>
8#include <libpldm/state_set.h>
Eddie James36313c72021-11-18 08:27:03 -06009#include <libpldm/state_set_oem_ibm.h>
Patrick Williams05e95592021-09-02 09:28:14 -050010
11#include <phosphor-logging/log.hpp>
Chris Cainbae4d072022-02-28 09:46:50 -060012#include <sdbusplus/bus.hpp>
13#include <sdeventplus/clock.hpp>
14#include <sdeventplus/exception.hpp>
15#include <sdeventplus/source/io.hpp>
16#include <sdeventplus/source/time.hpp>
17
18#include <algorithm>
Patrick Williams05e95592021-09-02 09:28:14 -050019
20namespace pldm
21{
22
Patrick Williams05e95592021-09-02 09:28:14 -050023using namespace phosphor::logging;
24
Chris Cainbae4d072022-02-28 09:46:50 -060025using namespace sdeventplus;
26using namespace sdeventplus::source;
27constexpr auto clockId = sdeventplus::ClockId::RealTime;
28using Clock = sdeventplus::Clock<clockId>;
29using Timer = Time<clockId>;
30
Eddie Jamescbad2192021-10-07 09:39:39 -050031void Interface::fetchSensorInfo(uint16_t stateSetId,
32 SensorToInstance& sensorInstanceMap,
33 SensorOffset& sensorOffset)
Patrick Williams05e95592021-09-02 09:28:14 -050034{
Eddie Jamescbad2192021-10-07 09:39:39 -050035 PdrList pdrs{};
Chris Cainbae4d072022-02-28 09:46:50 -060036 static bool tracedError = false;
Eddie Jamescbad2192021-10-07 09:39:39 -050037
38 auto& bus = open_power::occ::utils::getBus();
39 try
40 {
41 auto method = bus.new_method_call(
42 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
43 "xyz.openbmc_project.PLDM.PDR", "FindStateSensorPDR");
Chris Cainbae4d072022-02-28 09:46:50 -060044 method.append(tid, static_cast<uint16_t>(PLDM_ENTITY_PROC), stateSetId);
Eddie Jamescbad2192021-10-07 09:39:39 -050045
46 auto responseMsg = bus.call(method);
47 responseMsg.read(pdrs);
48 }
49 catch (const sdbusplus::exception::exception& e)
50 {
Chris Cainbae4d072022-02-28 09:46:50 -060051 if (!tracedError)
52 {
53 log<level::ERR>(
54 fmt::format(
55 "fetchSensorInfo: Failed to find stateSetID:{} PDR: {}",
56 stateSetId, e.what())
57 .c_str());
58 tracedError = true;
59 }
Eddie Jamescbad2192021-10-07 09:39:39 -050060 }
61
62 if (pdrs.empty())
63 {
Chris Cainbae4d072022-02-28 09:46:50 -060064 if (!tracedError)
65 {
66 log<level::ERR>(
67 fmt::format(
68 "fetchSensorInfo: state sensor PDRs ({}) not present",
69 stateSetId)
70 .c_str());
71 tracedError = true;
72 }
Eddie Jamescbad2192021-10-07 09:39:39 -050073 return;
74 }
75
Chris Cainbae4d072022-02-28 09:46:50 -060076 // Found PDR
77 if (tracedError)
78 {
79 log<level::INFO>(
80 fmt::format("fetchSensorInfo: found {} PDRs", pdrs.size()).c_str());
81 tracedError = false;
82 }
83
Patrick Williams05e95592021-09-02 09:28:14 -050084 bool offsetFound = false;
George Liuf3a4a692021-12-28 13:59:51 +080085 auto stateSensorPDR =
Patrick Williams05e95592021-09-02 09:28:14 -050086 reinterpret_cast<const pldm_state_sensor_pdr*>(pdrs.front().data());
George Liuf3a4a692021-12-28 13:59:51 +080087 auto possibleStatesPtr = stateSensorPDR->possible_states;
88 for (auto offset = 0; offset < stateSensorPDR->composite_sensor_count;
89 offset++)
Patrick Williams05e95592021-09-02 09:28:14 -050090 {
91 auto possibleStates =
92 reinterpret_cast<const state_sensor_possible_states*>(
93 possibleStatesPtr);
94
Eddie Jamescbad2192021-10-07 09:39:39 -050095 if (possibleStates->state_set_id == stateSetId)
Patrick Williams05e95592021-09-02 09:28:14 -050096 {
97 sensorOffset = offset;
98 offsetFound = true;
99 break;
100 }
101 possibleStatesPtr += sizeof(possibleStates->state_set_id) +
102 sizeof(possibleStates->possible_states_size) +
103 possibleStates->possible_states_size;
104 }
105
106 if (!offsetFound)
107 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500108 log<level::ERR>("pldm: state sensor PDR not found");
Patrick Williams05e95592021-09-02 09:28:14 -0500109 return;
110 }
111
112 // To order SensorID based on the EntityInstance.
113 // Note that when a proc is on a DCM, the PDRs for these sensors
114 // could have the same instance IDs but different container IDs.
115 std::map<uint32_t, SensorID> entityInstMap{};
116 for (auto& pdr : pdrs)
117 {
118 auto pdrPtr =
119 reinterpret_cast<const pldm_state_sensor_pdr*>(pdr.data());
120 uint32_t key = (static_cast<uint32_t>(pdrPtr->container_id) << 16) |
121 static_cast<uint32_t>(pdrPtr->entity_instance);
122 entityInstMap.emplace(key, static_cast<SensorID>(pdrPtr->sensor_id));
123 }
124
125 open_power::occ::instanceID count = start;
126 for (auto const& pair : entityInstMap)
127 {
128 sensorInstanceMap.emplace(pair.second, count);
129 count++;
130 }
131}
132
133void Interface::sensorEvent(sdbusplus::message::message& msg)
134{
135 if (!isOCCSensorCacheValid())
136 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500137 fetchSensorInfo(PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS,
138 sensorToOCCInstance, OCCSensorOffset);
139 }
Patrick Williams05e95592021-09-02 09:28:14 -0500140
Eddie Jamescbad2192021-10-07 09:39:39 -0500141 if (sensorToSBEInstance.empty())
142 {
143 fetchSensorInfo(PLDM_OEM_IBM_SBE_HRESET_STATE, sensorToSBEInstance,
144 SBESensorOffset);
Patrick Williams05e95592021-09-02 09:28:14 -0500145 }
146
147 TerminusID tid{};
148 SensorID sensorId{};
149 SensorOffset msgSensorOffset{};
150 EventState eventState{};
151 EventState previousEventState{};
152
153 msg.read(tid, sensorId, msgSensorOffset, eventState, previousEventState);
154
Eddie Jamescbad2192021-10-07 09:39:39 -0500155 if (msgSensorOffset == OCCSensorOffset)
Patrick Williams05e95592021-09-02 09:28:14 -0500156 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500157 auto sensorEntry = sensorToOCCInstance.find(sensorId);
Patrick Williams05e95592021-09-02 09:28:14 -0500158
Eddie James432dc482021-11-19 15:29:31 -0600159 if (sensorEntry != sensorToOCCInstance.end())
Eddie Jamescbad2192021-10-07 09:39:39 -0500160 {
Eddie James432dc482021-11-19 15:29:31 -0600161 if (eventState ==
162 static_cast<EventState>(
163 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_IN_SERVICE))
164 {
165 log<level::INFO>(
166 fmt::format("PLDM: OCC{} is RUNNING", sensorEntry->second)
167 .c_str());
168 callBack(sensorEntry->second, true);
169 }
170 else if (eventState ==
171 static_cast<EventState>(
172 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_STOPPED))
173 {
174 log<level::INFO>(fmt::format("PLDM: OCC{} has now STOPPED",
175 sensorEntry->second)
176 .c_str());
177 callBack(sensorEntry->second, false);
178 }
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",
186 sensorEntry->second)
187 .c_str());
188 callBack(sensorEntry->second, false);
189 }
190 else
191 {
192 log<level::INFO>(
193 fmt::format("PLDM: Unexpected PLDM state {} for OCC{}",
194 eventState, sensorEntry->second)
195 .c_str());
196 }
Eddie James432dc482021-11-19 15:29:31 -0600197
Eddie Jamescbad2192021-10-07 09:39:39 -0500198 return;
199 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500200 }
Eddie James432dc482021-11-19 15:29:31 -0600201
202 if (msgSensorOffset == SBESensorOffset)
Eddie Jamescbad2192021-10-07 09:39:39 -0500203 {
204 auto sensorEntry = sensorToSBEInstance.find(sensorId);
205
Eddie James432dc482021-11-19 15:29:31 -0600206 if (sensorEntry != sensorToSBEInstance.end())
Eddie Jamescbad2192021-10-07 09:39:39 -0500207 {
Chris Cain12d0b822022-04-22 17:29:18 -0500208 const uint8_t instance = sensorEntry->second;
209 auto match = std::find(outstandingHResets.begin(),
210 outstandingHResets.end(), instance);
211 if (match != outstandingHResets.end())
Eddie James432dc482021-11-19 15:29:31 -0600212 {
Chris Cain12d0b822022-04-22 17:29:18 -0500213 outstandingHResets.erase(match);
214 if (eventState == static_cast<EventState>(SBE_HRESET_NOT_READY))
215 {
216 log<level::INFO>(
217 fmt::format("pldm: HRESET is NOT READY (OCC{})",
218 instance)
219 .c_str());
220 }
221 else if (eventState ==
222 static_cast<EventState>(SBE_HRESET_READY))
223 {
224 sbeCallBack(instance, true);
225 }
226 else if (eventState ==
227 static_cast<EventState>(SBE_HRESET_FAILED))
228 {
229 sbeCallBack(instance, false);
230 }
Eddie James432dc482021-11-19 15:29:31 -0600231 }
Chris Cain12d0b822022-04-22 17:29:18 -0500232 // else request was not from us
Eddie Jamescbad2192021-10-07 09:39:39 -0500233 }
234 }
Patrick Williams05e95592021-09-02 09:28:14 -0500235}
236
237void Interface::hostStateEvent(sdbusplus::message::message& msg)
238{
239 std::map<std::string, std::variant<std::string>> properties{};
240 std::string interface;
241 msg.read(interface, properties);
242 const auto stateEntry = properties.find("CurrentHostState");
243 if (stateEntry != properties.end())
244 {
245 auto stateEntryValue = stateEntry->second;
246 auto propVal = std::get<std::string>(stateEntryValue);
247 if (propVal == "xyz.openbmc_project.State.Host.HostState.Off")
248 {
Chris Cainbae4d072022-02-28 09:46:50 -0600249 clearData();
Patrick Williams05e95592021-09-02 09:28:14 -0500250 }
251 }
252}
253
Chris Cainbae4d072022-02-28 09:46:50 -0600254void Interface::clearData()
255{
256 sensorToOCCInstance.clear();
257 occInstanceToEffecter.clear();
258
259 sensorToSBEInstance.clear();
260 sbeInstanceToEffecter.clear();
261}
262
Eddie James432dc482021-11-19 15:29:31 -0600263void Interface::fetchEffecterInfo(uint16_t stateSetId,
Eddie Jamescbad2192021-10-07 09:39:39 -0500264 InstanceToEffecter& instanceToEffecterMap,
265 CompositeEffecterCount& effecterCount,
266 uint8_t& stateIdPos)
Patrick Williams05e95592021-09-02 09:28:14 -0500267{
Eddie Jamescbad2192021-10-07 09:39:39 -0500268 PdrList pdrs{};
269
270 auto& bus = open_power::occ::utils::getBus();
271 try
272 {
273 auto method = bus.new_method_call(
274 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
275 "xyz.openbmc_project.PLDM.PDR", "FindStateEffecterPDR");
Chris Cainbae4d072022-02-28 09:46:50 -0600276 method.append(tid, static_cast<uint16_t>(PLDM_ENTITY_PROC), stateSetId);
Eddie Jamescbad2192021-10-07 09:39:39 -0500277
278 auto responseMsg = bus.call(method);
279 responseMsg.read(pdrs);
280 }
281 catch (const sdbusplus::exception::exception& e)
282 {
283 log<level::ERR>("pldm: Failed to fetch the state effecter PDRs",
284 entry("ERROR=%s", e.what()));
285 }
286
287 if (!pdrs.size())
288 {
289 log<level::ERR>("pldm: state effecter PDRs not present");
290 return;
291 }
292
Patrick Williams05e95592021-09-02 09:28:14 -0500293 bool offsetFound = false;
George Liuf3a4a692021-12-28 13:59:51 +0800294 auto stateEffecterPDR =
Patrick Williams05e95592021-09-02 09:28:14 -0500295 reinterpret_cast<const pldm_state_effecter_pdr*>(pdrs.front().data());
George Liuf3a4a692021-12-28 13:59:51 +0800296 auto possibleStatesPtr = stateEffecterPDR->possible_states;
297 for (auto offset = 0; offset < stateEffecterPDR->composite_effecter_count;
298 offset++)
Patrick Williams05e95592021-09-02 09:28:14 -0500299 {
300 auto possibleStates =
301 reinterpret_cast<const state_effecter_possible_states*>(
302 possibleStatesPtr);
303
Eddie Jamescbad2192021-10-07 09:39:39 -0500304 if (possibleStates->state_set_id == stateSetId)
Patrick Williams05e95592021-09-02 09:28:14 -0500305 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500306 stateIdPos = offset;
George Liuf3a4a692021-12-28 13:59:51 +0800307 effecterCount = stateEffecterPDR->composite_effecter_count;
Patrick Williams05e95592021-09-02 09:28:14 -0500308 offsetFound = true;
309 break;
310 }
311 possibleStatesPtr += sizeof(possibleStates->state_set_id) +
312 sizeof(possibleStates->possible_states_size) +
313 possibleStates->possible_states_size;
314 }
315
316 if (!offsetFound)
317 {
318 return;
319 }
320
Chris Cain0f516522022-02-07 14:48:28 -0600321 std::map<uint32_t, EffecterID> entityInstMap{};
Patrick Williams05e95592021-09-02 09:28:14 -0500322 for (auto& pdr : pdrs)
323 {
324 auto pdrPtr =
325 reinterpret_cast<const pldm_state_effecter_pdr*>(pdr.data());
326 uint32_t key = (static_cast<uint32_t>(pdrPtr->container_id) << 16) |
327 static_cast<uint32_t>(pdrPtr->entity_instance);
328 entityInstMap.emplace(key, static_cast<SensorID>(pdrPtr->effecter_id));
329 }
330
331 open_power::occ::instanceID position = start;
332 for (auto const& pair : entityInstMap)
333 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500334 instanceToEffecterMap.emplace(position, pair.second);
Patrick Williams05e95592021-09-02 09:28:14 -0500335 position++;
336 }
337}
338
339std::vector<uint8_t>
340 Interface::prepareSetEffecterReq(uint8_t instanceId, EffecterID effecterId,
341 CompositeEffecterCount effecterCount,
Eddie Jamescbad2192021-10-07 09:39:39 -0500342 uint8_t stateIdPos, uint8_t stateSetValue)
Patrick Williams05e95592021-09-02 09:28:14 -0500343{
344 std::vector<uint8_t> request(
345 sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(effecterCount) +
346 (effecterCount * sizeof(set_effecter_state_field)));
347 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
348 std::vector<set_effecter_state_field> stateField;
349
350 for (uint8_t effecterPos = 0; effecterPos < effecterCount; effecterPos++)
351 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500352 if (effecterPos == stateIdPos)
Patrick Williams05e95592021-09-02 09:28:14 -0500353 {
Eddie Jamescbad2192021-10-07 09:39:39 -0500354 stateField.emplace_back(
355 set_effecter_state_field{PLDM_REQUEST_SET, stateSetValue});
Patrick Williams05e95592021-09-02 09:28:14 -0500356 }
357 else
358 {
359 stateField.emplace_back(
360 set_effecter_state_field{PLDM_NO_CHANGE, 0});
361 }
362 }
363 auto rc = encode_set_state_effecter_states_req(
364 instanceId, effecterId, effecterCount, stateField.data(), requestMsg);
365 if (rc != PLDM_SUCCESS)
366 {
367 log<level::ERR>("encode set effecter states request returned error ",
368 entry("RC=%d", rc));
369 request.clear();
370 }
371 return request;
372}
373
374void Interface::resetOCC(open_power::occ::instanceID occInstanceId)
375{
Chris Cainbae4d072022-02-28 09:46:50 -0600376 if (open_power::occ::utils::isHostRunning())
Patrick Williams05e95592021-09-02 09:28:14 -0500377 {
Chris Cainbae4d072022-02-28 09:46:50 -0600378 if (!isPDREffecterCacheValid())
379 {
380 fetchEffecterInfo(PLDM_STATE_SET_BOOT_RESTART_CAUSE,
381 occInstanceToEffecter, OCCEffecterCount,
382 bootRestartPosition);
383 }
Patrick Williams05e95592021-09-02 09:28:14 -0500384
Chris Cainbae4d072022-02-28 09:46:50 -0600385 // Find the matching effecter for the OCC instance
386 auto effecterEntry = occInstanceToEffecter.find(occInstanceId);
387 if (effecterEntry == occInstanceToEffecter.end())
388 {
389 log<level::ERR>(
390 fmt::format(
391 "pldm: Failed to find a matching effecter for OCC instance {}",
392 occInstanceId)
393 .c_str());
394
395 return;
396 }
397
398 if (!getMctpInstanceId(mctpInstance))
399 {
400 return;
401 }
402
403 // Prepare the SetStateEffecterStates request to reset the OCC
404 auto request = prepareSetEffecterReq(
405 mctpInstance, effecterEntry->second, OCCEffecterCount,
406 bootRestartPosition, PLDM_STATE_SET_BOOT_RESTART_CAUSE_WARM_RESET);
407
408 if (request.empty())
409 {
410 log<level::ERR>(
411 "pldm: SetStateEffecterStates OCC reset request empty");
412 return;
413 }
414
415 // Send request to reset the OCCs/PM Complex (ignore response)
416 sendPldm(request, occInstanceId, false);
417 }
418 else
Patrick Williams05e95592021-09-02 09:28:14 -0500419 {
420 log<level::ERR>(
Chris Cainbae4d072022-02-28 09:46:50 -0600421 fmt::format("resetOCC: HOST is not running (OCC{})", occInstanceId)
Chris Cain0f516522022-02-07 14:48:28 -0600422 .c_str());
Chris Cainbae4d072022-02-28 09:46:50 -0600423 clearData();
Patrick Williams05e95592021-09-02 09:28:14 -0500424 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500425}
426
427void Interface::sendHRESET(open_power::occ::instanceID sbeInstanceId)
428{
Chris Cainbae4d072022-02-28 09:46:50 -0600429 if (open_power::occ::utils::isHostRunning())
Eddie Jamescbad2192021-10-07 09:39:39 -0500430 {
Chris Cainbae4d072022-02-28 09:46:50 -0600431 if (sbeInstanceToEffecter.empty())
432 {
433 fetchEffecterInfo(PLDM_OEM_IBM_SBE_MAINTENANCE_STATE,
434 sbeInstanceToEffecter, SBEEffecterCount,
435 sbeMaintenanceStatePosition);
436 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500437
Chris Cainbae4d072022-02-28 09:46:50 -0600438 auto effecterEntry = sbeInstanceToEffecter.find(sbeInstanceId);
439 if (effecterEntry == sbeInstanceToEffecter.end())
440 {
441 log<level::ERR>(
442 "pldm: Failed to find a matching effecter for SBE instance",
443 entry("SBE=%d", sbeInstanceId));
444 return;
445 }
446
447 if (!getMctpInstanceId(mctpInstance))
448 {
449 return;
450 }
451
452 // Prepare the SetStateEffecterStates request to HRESET the SBE
453 auto request = prepareSetEffecterReq(
454 mctpInstance, effecterEntry->second, SBEEffecterCount,
455 sbeMaintenanceStatePosition, SBE_RETRY_REQUIRED);
456
457 if (request.empty())
458 {
459 log<level::ERR>(
460 "pldm: SetStateEffecterStates HRESET request empty");
461 return;
462 }
463
464 // Send request to issue HRESET of SBE (ignore response)
465 sendPldm(request, sbeInstanceId, false);
Chris Cain12d0b822022-04-22 17:29:18 -0500466 outstandingHResets.insert(sbeInstanceId);
Chris Cainbae4d072022-02-28 09:46:50 -0600467 }
468 else
Eddie Jamescbad2192021-10-07 09:39:39 -0500469 {
Chris Cainbae4d072022-02-28 09:46:50 -0600470 log<level::ERR>(fmt::format("sendHRESET: HOST is not running (OCC{})",
471 sbeInstanceId)
472 .c_str());
473 clearData();
Eddie Jamescbad2192021-10-07 09:39:39 -0500474 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500475}
476
477bool Interface::getMctpInstanceId(uint8_t& instanceId)
478{
Patrick Williams05e95592021-09-02 09:28:14 -0500479 auto& bus = open_power::occ::utils::getBus();
480 try
481 {
482 auto method = bus.new_method_call(
483 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
484 "xyz.openbmc_project.PLDM.Requester", "GetInstanceId");
485 method.append(mctpEid);
486 auto reply = bus.call(method);
487 reply.read(instanceId);
488 }
Patrick Williams25613622021-09-02 09:29:54 -0500489 catch (const sdbusplus::exception::exception& e)
Patrick Williams05e95592021-09-02 09:28:14 -0500490 {
Chris Cainbd551de2022-04-26 13:41:16 -0500491 log<level::ERR>(
492 fmt::format("pldm: GetInstanceId failed: {}", e.what()).c_str());
Eddie Jamescbad2192021-10-07 09:39:39 -0500493 return false;
Patrick Williams05e95592021-09-02 09:28:14 -0500494 }
495
Eddie Jamescbad2192021-10-07 09:39:39 -0500496 return true;
497}
Patrick Williams05e95592021-09-02 09:28:14 -0500498
Chris Cainbae4d072022-02-28 09:46:50 -0600499void Interface::sendPldm(const std::vector<uint8_t>& request,
500 const uint8_t instance, const bool rspExpected)
Eddie Jamescbad2192021-10-07 09:39:39 -0500501{
Patrick Williams05e95592021-09-02 09:28:14 -0500502 // Connect to MCTP scoket
Chris Cainbae4d072022-02-28 09:46:50 -0600503 pldmFd = pldm_open();
504 auto openErrno = errno;
505 if (pldmFd == PLDM_REQUESTER_OPEN_FAIL)
Patrick Williams05e95592021-09-02 09:28:14 -0500506 {
Chris Caind1b68262022-02-28 09:56:50 -0600507 log<level::ERR>(
Chris Cainbae4d072022-02-28 09:46:50 -0600508 fmt::format(
509 "sendPldm: Failed to connect to MCTP socket, errno={}/{}",
510 openErrno, strerror(openErrno))
Chris Caind1b68262022-02-28 09:56:50 -0600511 .c_str());
Patrick Williams05e95592021-09-02 09:28:14 -0500512 return;
513 }
Eddie Jamescbad2192021-10-07 09:39:39 -0500514
Patrick Williams05e95592021-09-02 09:28:14 -0500515 // Send the PLDM request message to HBRT
Chris Cainbae4d072022-02-28 09:46:50 -0600516 if (rspExpected)
Patrick Williams05e95592021-09-02 09:28:14 -0500517 {
Chris Cainbae4d072022-02-28 09:46:50 -0600518 // Register callback when response is available
519 registerPldmRspCallback();
520
521 // Send PLDM request
522 log<level::INFO>(
523 fmt::format(
524 "sendPldm: calling pldm_send(OCC{}, instance:{}, {} bytes)",
525 instance, mctpInstance, request.size())
526 .c_str());
527 pldmResponseReceived = false;
528 pldmResponseTimeout = false;
529 pldmResponseOcc = instance;
530 auto pldmRc =
531 pldm_send(mctpEid, pldmFd, request.data(), request.size());
532 auto sendErrno = errno;
533 if (pldmRc != PLDM_REQUESTER_SUCCESS)
534 {
535 log<level::ERR>(
536 fmt::format(
537 "sendPldm: pldm_send failed with rc={} and errno={}/{}",
538 pldmRc, sendErrno, strerror(sendErrno))
539 .c_str());
540 pldmClose();
541 return;
542 }
543
544 // start timer waiting for the response
545 using namespace std::literals::chrono_literals;
Chris Cainbd551de2022-04-26 13:41:16 -0500546 pldmRspTimer.restartOnce(8s);
Chris Cainbae4d072022-02-28 09:46:50 -0600547
548 // Wait for response/timeout
549 }
550 else // not expecting the response
551 {
552 log<level::INFO>(
553 fmt::format(
554 "sendPldm: calling pldm_send(mctpID:{}, fd:{}, {} bytes) for OCC{}",
555 mctpEid, pldmFd, request.size(), instance)
556 .c_str());
557 auto rc = pldm_send(mctpEid, pldmFd, request.data(), request.size());
558 auto sendErrno = errno;
Chris Caind1b68262022-02-28 09:56:50 -0600559 if (rc)
560 {
561 log<level::ERR>(
562 fmt::format(
Chris Cainbae4d072022-02-28 09:46:50 -0600563 "sendPldm: pldm_send(mctpID:{}, fd:{}, {} bytes) failed with rc={} and errno={}/{}",
564 mctpEid, pldmFd, request.size(), rc, sendErrno,
565 strerror(sendErrno))
Chris Caind1b68262022-02-28 09:56:50 -0600566 .c_str());
567 }
Chris Cainbae4d072022-02-28 09:46:50 -0600568 pldmClose();
569 }
570}
Patrick Williams05e95592021-09-02 09:28:14 -0500571
Chris Cainbae4d072022-02-28 09:46:50 -0600572// Attaches the FD to event loop and registers the callback handler
573void Interface::registerPldmRspCallback()
574{
575 decltype(eventSource.get()) sourcePtr = nullptr;
576 auto rc = sd_event_add_io(event.get(), &sourcePtr, pldmFd, EPOLLIN,
577 pldmRspCallback, this);
578 if (rc < 0)
579 {
580 log<level::ERR>(
581 fmt::format(
582 "registerPldmRspCallback: sd_event_add_io: Error({})={} : fd={}",
583 rc, strerror(-rc), pldmFd)
584 .c_str());
Chris Caind1b68262022-02-28 09:56:50 -0600585 }
586 else
Patrick Williams05e95592021-09-02 09:28:14 -0500587 {
Chris Cainbae4d072022-02-28 09:46:50 -0600588 // puts sourcePtr in the event source.
589 eventSource.reset(sourcePtr);
590 }
591}
592
593// Add a timer to the event loop, default 30s.
594void Interface::pldmRspExpired()
595{
596 if (!pldmResponseReceived)
597 {
598 log<level::ERR>(
599 fmt::format(
600 "pldmRspExpired: timerCallback - timeout waiting for pldm response for OCC{}",
601 pldmResponseOcc)
602 .c_str());
603 pldmResponseTimeout = true;
604 if (pldmFd)
605 {
606 pldmClose();
607 }
608 }
609 return;
610};
611
612void Interface::pldmClose()
613{
614 if (pldmRspTimer.isEnabled())
615 {
616 // stop PLDM response timer
617 pldmRspTimer.setEnabled(false);
618 }
619 close(pldmFd);
620 pldmFd = -1;
621 eventSource.reset();
622}
623
624int Interface::pldmRspCallback(sd_event_source* /*es*/, int fd,
625 uint32_t revents, void* userData)
626{
627 if (!(revents & EPOLLIN))
628 {
629 log<level::INFO>(
630 fmt::format("pldmRspCallback - revents={:08X}", revents).c_str());
631 return -1;
632 }
633
634 auto pldmIface = static_cast<Interface*>(userData);
635
636 uint8_t* responseMsg = nullptr;
637 size_t responseMsgSize{};
638
639 log<level::INFO>(
640 fmt::format("pldmRspCallback: calling pldm_recv() instance:{}",
641 pldmIface->mctpInstance)
642 .c_str());
643 auto rc = pldm_recv(mctpEid, fd, pldmIface->mctpInstance, &responseMsg,
644 &responseMsgSize);
645 int lastErrno = errno;
646 if (rc)
647 {
648 log<level::ERR>(
649 fmt::format(
650 "pldmRspCallback: pldm_recv failed with rc={}, errno={}/{}", rc,
651 lastErrno, strerror(lastErrno))
652 .c_str());
653 return -1;
654 }
655 log<level::INFO>(
656 fmt::format("pldmRspCallback: pldm_recv() rsp was {} bytes",
657 responseMsgSize)
658 .c_str());
659
660 if (pldmIface->pldmRspTimer.isEnabled())
661 {
662 // stop PLDM response timer
663 pldmIface->pldmRspTimer.setEnabled(false);
664 }
665
666 // Set pointer to autodelete
667 std::unique_ptr<uint8_t, decltype(std::free)*> responseMsgPtr{responseMsg,
668 std::free};
669
670 // We've got the response meant for the PLDM request msg that was
671 // sent out
672 // io.set_enabled(Enabled::Off);
673 auto response = reinterpret_cast<pldm_msg*>(responseMsgPtr.get());
674 if (response->payload[0] != PLDM_SUCCESS)
675 {
676 log<level::ERR>(
677 fmt::format("pldmRspCallback: payload[0] was not success: {}",
678 response->payload[0])
679 .c_str());
680 pldmIface->pldmClose();
681 return -1;
682 }
683
684 // Decode the response
685 uint8_t compCode = 0, sensorCount = 1;
686 get_sensor_state_field field[6];
687 responseMsgSize -= sizeof(pldm_msg_hdr);
688 auto msgRc = decode_get_state_sensor_readings_resp(
689 response, responseMsgSize, &compCode, &sensorCount, field);
690 if ((msgRc != PLDM_SUCCESS) || (compCode != PLDM_SUCCESS))
691 {
692 log<level::ERR>(
693 fmt::format(
694 "pldmRspCallback: decode_get_state_sensor_readings failed with rc={} and compCode={}",
695 msgRc, compCode)
696 .c_str());
697 pldmIface->pldmClose();
698 return -1;
699 }
700
701 pldmIface->pldmClose();
702
703 const uint8_t instance = pldmIface->pldmResponseOcc;
704 const uint8_t occSensorState = field[0].present_state;
705 pldmIface->pldmResponseReceived = true;
706
707 if (occSensorState == PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_IN_SERVICE)
708 {
709 log<level::INFO>(
710 fmt::format("pldmRspCallback: OCC{} is RUNNING", instance).c_str());
711 pldmIface->callBack(instance, true);
712 }
Chris Cain733b2012022-05-04 11:54:06 -0500713 else if (occSensorState ==
714 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_DORMANT)
715 {
716 log<level::INFO>(
717 fmt::format(
718 "pldmRspCallback: OCC{} has now STOPPED and system is in SAFE MODE",
719 instance)
720 .c_str());
721 pldmIface->callBack(instance, false);
722 }
Chris Cainbae4d072022-02-28 09:46:50 -0600723 else
724 {
725 log<level::INFO>(
726 fmt::format("pldmRspCallback: OCC{} is not running (state:{})",
727 instance, occSensorState)
728 .c_str());
729 pldmIface->callBack(instance, false);
730 }
731
732 return 0;
733};
734
735std::vector<uint8_t> Interface::encodeGetStateSensorRequest(uint8_t instance,
736 uint16_t sensorId)
737{
738 bitfield8_t sRearm = {0};
739 const size_t msgSize =
740 sizeof(pldm_msg_hdr) + PLDM_GET_STATE_SENSOR_READINGS_REQ_BYTES;
741 std::vector<uint8_t> request(msgSize);
742 auto msg = reinterpret_cast<pldm_msg*>(request.data());
743 auto msgRc = encode_get_state_sensor_readings_req(mctpInstance, sensorId,
744 sRearm, 0, msg);
745 if (msgRc != PLDM_SUCCESS)
746 {
747 log<level::ERR>(
748 fmt::format(
749 "encodeGetStateSensorRequest: Failed to encode sensorId:0x{:08X} for OCC{} (rc={})",
750 sensorId, instance, msgRc)
751 .c_str());
752 }
753 return request;
754}
755
756// Initiate query of the specified OCC Active Sensor
757void Interface::checkActiveSensor(uint8_t instance)
758{
759 static bool tracedOnce = false;
760 if (pldmFd > 0)
761 {
762 if (!tracedOnce)
Chris Caind1b68262022-02-28 09:56:50 -0600763 {
764 log<level::ERR>(
765 fmt::format(
Chris Cainbae4d072022-02-28 09:46:50 -0600766 "checkActiveSensor: already waiting on OCC{} (fd={})",
767 pldmResponseOcc, pldmFd)
Chris Caind1b68262022-02-28 09:56:50 -0600768 .c_str());
Chris Cainbae4d072022-02-28 09:46:50 -0600769 tracedOnce = true;
Chris Caind1b68262022-02-28 09:56:50 -0600770 }
Chris Cainbae4d072022-02-28 09:46:50 -0600771 return;
772 }
773 tracedOnce = false;
774
775 if (!isOCCSensorCacheValid())
776 {
777 fetchSensorInfo(PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS,
778 sensorToOCCInstance, OCCSensorOffset);
779 }
780
781 // look up sensor id (key) based on instance
782 auto entry = std::find_if(
783 sensorToOCCInstance.begin(), sensorToOCCInstance.end(),
784 [instance](const auto& entry) { return instance == entry.second; });
785 if (entry != sensorToOCCInstance.end())
786 {
787 // Query the OCC Active Sensor state for this instance
788 // SensorID sID = entry->first;
789 log<level::INFO>(
790 fmt::format("checkActiveSensor: OCC{} / sensorID: 0x{:04X}",
791 instance, entry->first)
792 .c_str());
793
794 if (!getMctpInstanceId(mctpInstance))
795 {
796 log<level::ERR>("checkActiveSensor: failed to getMctpInstanceId");
797 return;
798 }
799
800 // Encode GetStateSensorReadings PLDM message
801 auto request = encodeGetStateSensorRequest(instance, entry->first);
802 if (request.empty())
803 {
804 return;
805 }
806
807 // Send request to PLDM and setup callback for response
808 sendPldm(request, instance, true);
809 }
810 else
811 {
812 log<level::ERR>(
813 fmt::format(
814 "checkActiveSensor: Unable to find PLDM sensor for OCC{}",
815 instance)
816 .c_str());
Patrick Williams05e95592021-09-02 09:28:14 -0500817 }
Patrick Williams05e95592021-09-02 09:28:14 -0500818}
819
820} // namespace pldm