-
Notifications
You must be signed in to change notification settings - Fork 6
/
pldm.hpp
443 lines (372 loc) · 14.9 KB
/
pldm.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
#pragma once
#include "occ_events.hpp"
#include "occ_status.hpp"
#include "utils.hpp"
#include <libpldm/instance-id.h>
#include <libpldm/pldm.h>
#include <libpldm/transport.h>
#include <libpldm/transport/af-mctp.h>
#include <libpldm/transport/mctp-demux.h>
#include <sdbusplus/bus/match.hpp>
#include <sdeventplus/event.hpp>
#include <sdeventplus/utility/timer.hpp>
enum pldm_msg_type
{
MSG_UNDEFINED = 0,
MSG_SENSOR_STATUS = 1,
MSG_OCC_RESET = 2,
MSG_HRESET = 3
};
namespace pldm
{
namespace MatchRules = sdbusplus::bus::match::rules;
using namespace open_power::occ;
using CompositeEffecterCount = uint8_t;
using EffecterID = uint16_t;
using EntityType = uint16_t;
using EntityInstance = uint16_t;
using EventState = uint8_t;
using InstanceToEffecter = std::map<open_power::occ::instanceID, EffecterID>;
using PdrList = std::vector<std::vector<uint8_t>>;
using SensorID = uint16_t;
using SensorOffset = uint8_t;
using SensorToInstance = std::map<SensorID, open_power::occ::instanceID>;
using TerminusID = uint8_t;
/** @brief OCC instance starts with 0 for example "occ0" */
constexpr open_power::occ::instanceID start = 0;
/** @brief Hardcoded mctpEid for HBRT */
constexpr mctp_eid_t mctpEid = 10;
/** @brief Hardcoded TID */
constexpr TerminusID tid = mctpEid;
/** @class Interface
*
* @brief Abstracts the PLDM details related to the OCC
*/
class Interface
{
public:
Interface() = delete;
//~Interface() = default;
Interface(const Interface&) = delete;
Interface& operator=(const Interface&) = delete;
Interface(Interface&&) = delete;
Interface& operator=(Interface&&) = delete;
/** @brief Constructs the PLDM Interface object for OCC functions
*
* @param[in] occActiveCallBack - callBack handler to invoke when the OCC
* state changes.
* @param[in] sbeCallBack - callBack handler to invoke when the SBE
* state changes.
* @param[in] safeModeCallBack - callBack handler to invoke when the
* system is in safe mode.
*/
explicit Interface(
std::function<bool(open_power::occ::instanceID, bool)>
occActiveCallBack,
std::function<void(open_power::occ::instanceID, bool)> sbeCallBack,
std::function<void(bool)> safeModeCallBack, EventPtr& event) :
occActiveCallBack(occActiveCallBack), sbeCallBack(sbeCallBack),
safeModeCallBack(safeModeCallBack), event(event),
pldmEventSignal(
open_power::occ::utils::getBus(),
MatchRules::type::signal() +
MatchRules::member("StateSensorEvent") +
MatchRules::path("/xyz/openbmc_project/pldm") +
MatchRules::interface("xyz.openbmc_project.PLDM.Event"),
std::bind(std::mem_fn(&Interface::sensorEvent), this,
std::placeholders::_1)),
hostStateSignal(
open_power::occ::utils::getBus(),
MatchRules::propertiesChanged("/xyz/openbmc_project/state/host0",
"xyz.openbmc_project.State.Host"),
std::bind(std::mem_fn(&Interface::hostStateEvent), this,
std::placeholders::_1)),
sdpEvent(sdeventplus::Event::get_default()),
pldmRspTimer(
sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>(
sdpEvent, std::bind(&Interface::pldmRspExpired, this)))
{
int rc = pldm_instance_db_init_default(&pldmInstanceIdDb);
if (rc)
{
throw std::system_category().default_error_condition(rc);
}
}
~Interface()
{
int rc = pldm_instance_db_destroy(pldmInstanceIdDb);
if (rc)
{
std::cout << "pldm_instance_db_destroy failed, rc =" << rc << "\n";
}
}
/** @brief Fetch the state sensor PDRs and populate the cache with
* sensorId to OCC/SBE instance mapping information and the sensor
* offset for the relevent state set.
*
* @param[in] stateSetId - the state set ID to look for
* @param[out] sensorInstanceMap - map of sensorID to instance
* @param[out] sensorOffset - sensor offset of interested state set ID
*/
void fetchSensorInfo(uint16_t stateSetId,
SensorToInstance& sensorInstanceMap,
SensorOffset& sensorOffset);
/** @brief Fetch the OCC/SBE state effecter PDRs and populate the cache
* with OCC/SBE instance to EffecterID information.
*
* @param[in] stateSetId - the state set ID to look for
* @param[out] instanceToEffecterMap - map of instance to effecterID
* @param[out] count - sensor offset of interested state set ID
* @param[out] stateIdPos - position of the stateSetID
*/
void fetchEffecterInfo(uint16_t stateSetId,
InstanceToEffecter& instanceToEffecterMap,
CompositeEffecterCount& count, uint8_t& stateIdPos);
/** @brief Prepare the request for SetStateEffecterStates command
*
* @param[in] effecterId - the instance effecter ID
* @param[in] effecterCount - compositeEffecterCount for the effecter PDR
* @param[in] stateIdPos - position of the stateSetID
* @param[in] stateSetValue - the value to set the state set to
*
* @return PLDM request message to be sent to host for OCC reset or SBE
* HRESET, empty response in the case of failure.
*/
std::vector<uint8_t> prepareSetEffecterReq(
EffecterID effecterId, CompositeEffecterCount effecterCount,
uint8_t stateIdPos, uint8_t stateSetValue);
/** @brief Send the PLDM message to reset the OCC
*
* @param[in] instanceId - OCC instance to reset
*
*/
void resetOCC(open_power::occ::instanceID occInstanceId);
/** @brief Send the PLDM message to perform the HRESET
*
* @param[in] instanceID - SBE instance to HRESET
*/
void sendHRESET(open_power::occ::instanceID sbeInstanceId);
/** @brief Check if the OCC active sensor is available
* On successful read, the Manager callback will be called to update
* the status
*
* @param[in] instance - OCC instance to check
*/
void checkActiveSensor(uint8_t instance);
/** @brief Set the throttleTraces flag
*
* @param[in] throttle - Flag to indicate if traces should be throttled
*/
void setTraceThrottle(const bool throttle);
private:
/** @brief PLDM instance ID database object used to get instance IDs
*/
pldm_instance_db* pldmInstanceIdDb = nullptr;
/** @brief PLDM instance number used in PLDM requests
*/
std::optional<uint8_t> pldmInstanceID;
/** @brief Callback handler to be invoked when the state of the OCC
* changes
*/
std::function<bool(open_power::occ::instanceID, bool)> occActiveCallBack =
nullptr;
/** @brief Callback handler to be invoked when the maintenance state of the
* SBE changes
*/
std::function<void(open_power::occ::instanceID, bool)> sbeCallBack =
nullptr;
/** @brief Callback handler to be invoked when the OCC is in SAFE Mode =
* true or when OCCs are in_service = false.
*/
std::function<void(bool)> safeModeCallBack = nullptr;
/** @brief reference to sd_event wrapped in unique_ptr */
EventPtr& event;
/** @brief event source wrapped in unique_ptr */
EventSourcePtr eventSource;
/** @brief Used to subscribe to D-Bus PLDM StateSensorEvent signal and
* processes if the event corresponds to OCC state change.
*/
sdbusplus::bus::match_t pldmEventSignal;
/** @brief Used to subscribe for host state change signal */
sdbusplus::bus::match_t hostStateSignal;
/** @brief PLDM Sensor ID to OCC Instance mapping
*/
SensorToInstance sensorToOCCInstance;
/** @brief PLDM Sensor ID to SBE Instance mapping
*/
SensorToInstance sensorToSBEInstance;
/** @brief Sensor offset of OCC state set ID
* PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS in state sensor PDR.
*/
SensorOffset OCCSensorOffset = 0;
/** @brief Sensor offset of the SBE state set ID
* PLDM_OEM_IBM_SBE_HRESET_STATE in state sensor PDR.
*/
SensorOffset SBESensorOffset = 0;
/** @brief OCC Instance mapping to PLDM Effecter ID
*/
InstanceToEffecter occInstanceToEffecter;
/** @brief SBE instance mapping to PLDM Effecter ID
*/
InstanceToEffecter sbeInstanceToEffecter;
/** @brief compositeEffecterCount for OCC reset state effecter PDR */
CompositeEffecterCount OCCEffecterCount = 0;
/** @brief compositeEffecterCount for SBE HRESET state effecter PDR */
CompositeEffecterCount SBEEffecterCount = 0;
/** @brief Position of Boot/Restart Cause stateSetID in OCC state
* effecter PDR
*/
uint8_t bootRestartPosition = 0;
/** @brief Position of the SBE maintenance stateSetID in the state
* effecter PDR
*/
uint8_t sbeMaintenanceStatePosition = 0;
/** @brief OCC instance number for the PLDM message */
uint8_t pldmResponseOcc = 0;
/** @brief File descriptor for PLDM messages */
int pldmFd = -1;
/** pldm transport instance */
struct pldm_transport* pldmTransport = NULL;
static enum pldm_msg_type msgType;
union TransportImpl
{
struct pldm_transport_mctp_demux* mctpDemux;
struct pldm_transport_af_mctp* afMctp;
};
TransportImpl impl;
/** @brief The response for the PLDM request msg is received flag.
*/
bool pldmResponseReceived = false;
/** @brief The response for the PLDM request has timed out.
*/
bool pldmResponseTimeout = false;
/** @brief The instance ID for the OCC/HRESET request */
static open_power::occ::instanceID resetInstance;
/** @brief timer event */
sdeventplus::Event sdpEvent;
/** @brief Timer that is started when PLDM command is sent
*/
sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> pldmRspTimer;
std::set<uint8_t> outstandingHResets;
/** @brief Flag to indicate that traces should be throttled.
Used to limit traces when there are issues getting OCC status.
*/
static bool throttleTraces;
/** @brief Callback when PLDM response has not been received within the
* timeout period.
*/
void pldmRspExpired();
/** @brief Close the MCTP file */
void pldmClose();
/** @brief When the OCC state changes host sends PlatformEventMessage
* StateSensorEvent, this function processes the D-Bus signal
* with the sensor event information and invokes the callback
* to change the OCC state.
*
* @param[in] msg - data associated with the subscribed signal
*/
void sensorEvent(sdbusplus::message_t& msg);
/** @brief When the host state changes and if the CurrentHostState is
* xyz.openbmc_project.State.Host.HostState.Off then
* the cache of OCC sensors and effecters mapping is cleared.
*
* @param[in] msg - data associated with the subscribed signal
*/
void hostStateEvent(sdbusplus::message_t& msg);
/** @brief Called when it is determined that the Host is not running.
* The cache of OCC sensors and effecters mapping is cleared.
*/
void clearData();
/** @brief Check if the PDR cache for PLDM OCC sensors is valid
*
* @return true if cache is populated and false if the cache is not
* populated.
*/
auto isOCCSensorCacheValid()
{
return (sensorToOCCInstance.empty() ? false : true);
}
/** @brief Check if the PDR cache for PLDM OCC effecters is valid
*
* @return true if cache is populated and false if the cache is not
* populated.
*/
auto isPDREffecterCacheValid()
{
return (occInstanceToEffecter.empty() ? false : true);
}
/** @brief Get a PLDM requester instance id
*
* @return true if the id was found and false if not
*/
bool getPldmInstanceId();
/** @brief Free PLDM requester instance id */
void freePldmInstanceId();
/** @brief Encode a GetStateSensor command into a PLDM request
* @param[in] instance - OCC instance number
* @param[in] sensorId - OCC Active sensor ID number
*
* @return request - The encoded PLDM messsage to be sent
*/
std::vector<uint8_t>
encodeGetStateSensorRequest(uint8_t instance, uint16_t sensorId);
/** @brief setup PLDM transport for sending and receiving PLDM messages.
*
* @return true on success, otherwise return false
*/
int pldmOpen(void);
/** @brief Opens the MCTP socket for sending and receiving messages.
*
* @return 0 on success, otherwise returns a negative error code
*/
int openMctpDemuxTransport();
/** @brief Opens the MCTP AF_MCTP for sending and receiving messages.
*
* @return 0 on success, otherwise returns a negative error code
*/
int openAfMctpTransport();
/** @brief Send the PLDM request
*
* @param[in] request - the request data
* @param[in] rspExpected - false: no need to wait for the response
* true: will need to process response in callback
*/
void sendPldm(const std::vector<uint8_t>& request, const uint8_t instance,
const bool rspExpected = false);
/** @brief Register a callback function to handle the PLDM response */
void registerPldmRspCallback();
/** @brief callback for the PLDM response event
*
* @param[in] es - Populated event source
* @param[in] fd - Associated File descriptor
* @param[in] revents - Type of event
* @param[in] userData - User data that was passed during registration
*
* @return - 0 or positive number on success and negative
* errno otherwise
*/
static int pldmRspCallback(sd_event_source* es, int fd, uint32_t revents,
void* userData);
/** @brief callback for a OCC / HRESET response event
*
* @param[in] es - Populated event source
* @param[in] fd - Associated File descriptor
* @param[in] revents - Type of event
* @param[in] userData - User data that was passed during registration
*
* @return - 0 or positive number on success and negative
* errno otherwise
*/
static int pldmResetCallback(sd_event_source* /*es*/,
__attribute__((unused)) int fd,
uint32_t revents, void* userData);
};
} // namespace pldm
template <>
struct std::formatter<enum pldm_msg_type> : formatter<int>
{
auto format(enum pldm_msg_type m, format_context& ctx) const
{
return formatter<int>::format(std::to_underlying(m), ctx);
}
};