blob: 9f52756ec823caa41b3161e4d5557c0f7f36af51 [file] [log] [blame]
Chau Lya743e382024-10-26 11:12:22 +00001#include "oem_event_manager.hpp"
2
3#include "requester/handler.hpp"
4#include "requester/request.hpp"
5
6#include <config.h>
7#include <libpldm/pldm.h>
8#include <libpldm/utils.h>
9#include <systemd/sd-journal.h>
10
11#include <phosphor-logging/lg2.hpp>
12#include <xyz/openbmc_project/Logging/Entry/server.hpp>
13
14#include <algorithm>
15#include <map>
16#include <sstream>
17#include <string>
18#include <unordered_map>
19
20namespace pldm
21{
22namespace oem_ampere
23{
24namespace boot_stage = boot::stage;
25
Chau Ly3de0d942024-10-03 08:57:11 +000026constexpr const char* ampereEventRegistry = "OpenBMC.0.1.AmpereEvent.OK";
27constexpr const char* ampereWarningRegistry =
28 "OpenBMC.0.1.AmpereWarning.Warning";
29constexpr const char* ampereCriticalRegistry =
30 "OpenBMC.0.1.AmpereCritical.Critical";
Chau Lya743e382024-10-26 11:12:22 +000031constexpr const char* BIOSFWPanicRegistry =
32 "OpenBMC.0.1.BIOSFirmwarePanicReason.Warning";
33constexpr auto maxDIMMIdxBitNum = 24;
34
35/*
36 An array of possible boot status of a boot stage.
37 The index maps with byte 0 of boot code.
38*/
39std::array<std::string, 3> bootStatMsg = {" booting", " completed", " failed"};
40
41/*
42 An array of possible boot status of DDR training stage.
43 The index maps with byte 0 of boot code.
44*/
45std::array<std::string, 3> ddrTrainingMsg = {
46 " progress started", " in-progress", " progress completed"};
47
48/*
49 In Ampere systems, BMC only directly communicates with MCTP/PLDM SoC
50 EPs through SMBus and PCIe. When host boots up, SMBUS interface
51 comes up first. In this interface, BMC is bus owner.
52
53 mctpd will set the EID 0x14 for S0 and 0x16 for S1 (if available).
54 pldmd will always use TID 1 for S0 and TID 2 for S1 (if available).
55*/
56EventToMsgMap_t tidToSocketNameMap = {{1, "SOCKET 0"}, {2, "SOCKET 1"}};
57
58/*
59 A map between sensor IDs and their names in string.
60 Using pldm::oem::sensor_ids
61*/
Chau Ly3de0d942024-10-03 08:57:11 +000062EventToMsgMap_t sensorIdToStrMap = {{PCIE_HOT_PLUG, "PCIE_HOT_PLUG"},
63 {BOOT_OVERALL, "BOOT_OVERALL"}};
Chau Lya743e382024-10-26 11:12:22 +000064
65/*
66 A map between the boot stages and logging strings.
67 Using pldm::oem::boot::stage::boot_stage
68*/
69EventToMsgMap_t bootStageToMsgMap = {
70 {boot_stage::SECPRO, "SECpro"},
71 {boot_stage::MPRO, "Mpro"},
72 {boot_stage::ATF_BL1, "ATF BL1"},
73 {boot_stage::ATF_BL2, "ATF BL2"},
74 {boot_stage::DDR_INITIALIZATION, "DDR initialization"},
75 {boot_stage::DDR_TRAINING, "DDR training"},
76 {boot_stage::S0_DDR_TRAINING_FAILURE, "DDR training failure"},
77 {boot_stage::ATF_BL31, "ATF BL31"},
78 {boot_stage::ATF_BL32, "ATF BL32"},
79 {boot_stage::S1_DDR_TRAINING_FAILURE, "DDR training failure"},
80 {boot_stage::UEFI_STATUS_CLASS_CODE_MIN,
81 "ATF BL33 (UEFI) booting status = "}};
82
83/*
84 A map between log level and the registry used for Redfish SEL log
85 Using pldm::oem::log_level
86*/
87std::unordered_map<log_level, std::string> logLevelToRedfishMsgIdMap = {
Chau Ly3de0d942024-10-03 08:57:11 +000088 {log_level::OK, ampereEventRegistry},
89 {log_level::WARNING, ampereWarningRegistry},
90 {log_level::CRITICAL, ampereCriticalRegistry},
Chau Lya743e382024-10-26 11:12:22 +000091 {log_level::BIOSFWPANIC, BIOSFWPanicRegistry}};
92
93std::string
94 OemEventManager::prefixMsgStrCreation(pldm_tid_t tid, uint16_t sensorId)
95{
96 std::string description;
97 if (!tidToSocketNameMap.contains(tid))
98 {
99 description += "TID " + std::to_string(tid) + ": ";
100 }
101 else
102 {
103 description += tidToSocketNameMap[tid] + ": ";
104 }
105
106 if (!sensorIdToStrMap.contains(sensorId))
107 {
108 description += "Sensor ID " + std::to_string(sensorId) + ": ";
109 }
110 else
111 {
112 description += sensorIdToStrMap[sensorId] + ": ";
113 }
114
115 return description;
116}
117
118void OemEventManager::sendJournalRedfish(const std::string& description,
119 log_level& logLevel)
120{
121 if (description.empty())
122 {
123 return;
124 }
125
126 if (!logLevelToRedfishMsgIdMap.contains(logLevel))
127 {
128 lg2::error("Invalid {LEVEL} Description {DES}", "LEVEL", logLevel,
129 "DES", description);
130 return;
131 }
132 auto redfishMsgId = logLevelToRedfishMsgIdMap[logLevel];
133 lg2::info("MESSAGE={DES}", "DES", description, "REDFISH_MESSAGE_ID",
134 redfishMsgId, "REDFISH_MESSAGE_ARGS", description);
135}
136
137std::string OemEventManager::dimmIdxsToString(uint32_t dimmIdxs)
138{
139 std::string description;
140 for (const auto bitIdx : std::views::iota(0, maxDIMMIdxBitNum))
141 {
142 if (dimmIdxs & (static_cast<uint32_t>(1) << bitIdx))
143 {
144 description += " #" + std::to_string(bitIdx);
145 }
146 }
147 return description;
148}
149
150void OemEventManager::handleBootOverallEvent(
151 pldm_tid_t /*tid*/, uint16_t /*sensorId*/, uint32_t presentReading)
152{
153 log_level logLevel{log_level::OK};
154 std::string description;
155 std::stringstream strStream;
156
157 uint8_t byte0 = (presentReading & 0x000000ff);
158 uint8_t byte1 = (presentReading & 0x0000ff00) >> 8;
159 uint8_t byte2 = (presentReading & 0x00ff0000) >> 16;
160 uint8_t byte3 = (presentReading & 0xff000000) >> 24;
161 /*
162 * Handle SECpro, Mpro, ATF BL1, ATF BL2, ATF BL31,
163 * ATF BL32 and DDR initialization
164 */
165 if (bootStageToMsgMap.contains(byte3))
166 {
167 // Boot stage adding
168 description += bootStageToMsgMap[byte3];
169
170 switch (byte3)
171 {
172 case boot_stage::DDR_TRAINING:
173 if (byte0 >= ddrTrainingMsg.size())
174 {
175 logLevel = log_level::BIOSFWPANIC;
176 description += " unknown status";
177 }
178 else
179 {
180 description += ddrTrainingMsg[byte0];
181 }
182 if (0x01 == byte0)
183 {
184 // Add complete percentage
185 description += " at " + std::to_string(byte1) + "%";
186 }
187 break;
188 case boot_stage::S0_DDR_TRAINING_FAILURE:
189 case boot_stage::S1_DDR_TRAINING_FAILURE:
190 // ddr_training_status_msg()
191 logLevel = log_level::BIOSFWPANIC;
192 description += " at DIMMs:";
193 // dimmIdxs = presentReading & 0x00ffffff;
194 description += dimmIdxsToString(presentReading & 0x00ffffff);
195 description += " of socket ";
196 description +=
197 (boot_stage::S0_DDR_TRAINING_FAILURE == byte3) ? "0" : "1";
198 break;
199 default:
200 if (byte0 >= bootStatMsg.size())
201 {
202 logLevel = log_level::BIOSFWPANIC;
203 description += " unknown status";
204 }
205 else
206 {
207 description += bootStatMsg[byte0];
208 }
209 break;
210 }
211
212 // Sensor report action is fail
213 if (boot::status::BOOT_STATUS_FAILURE == byte2)
214 {
215 logLevel = log_level::BIOSFWPANIC;
216 }
217 }
218 else
219 {
220 if (byte3 <= boot_stage::UEFI_STATUS_CLASS_CODE_MAX)
221 {
222 description +=
223 bootStageToMsgMap[boot_stage::UEFI_STATUS_CLASS_CODE_MIN];
224
225 strStream
226 << "Segment (0x" << std::setfill('0') << std::hex
227 << std::setw(8) << static_cast<uint32_t>(presentReading)
Chau Ly3de0d942024-10-03 08:57:11 +0000228 << "); Status Class (0x" << std::setw(2)
229 << static_cast<uint32_t>(byte3) << "); Status SubClass (0x"
Chau Lya743e382024-10-26 11:12:22 +0000230 << std::setw(2) << static_cast<uint32_t>(byte2)
Chau Ly3de0d942024-10-03 08:57:11 +0000231 << "); Operation Code (0x" << std::setw(4)
Chau Lya743e382024-10-26 11:12:22 +0000232 << static_cast<uint32_t>((presentReading & 0xffff0000) >> 16)
233 << ")" << std::dec;
234
235 description += strStream.str();
236 }
237 }
238
239 // Log to Redfish event
240 sendJournalRedfish(description, logLevel);
241}
242
243int OemEventManager::processNumericSensorEvent(
244 pldm_tid_t tid, uint16_t sensorId, const uint8_t* sensorData,
245 size_t sensorDataLength)
246{
247 uint8_t eventState = 0;
248 uint8_t previousEventState = 0;
249 uint8_t sensorDataSize = 0;
250 uint32_t presentReading;
251 auto rc = decode_numeric_sensor_data(
252 sensorData, sensorDataLength, &eventState, &previousEventState,
253 &sensorDataSize, &presentReading);
254 if (rc)
255 {
256 lg2::error(
257 "Failed to decode numericSensorState event for terminus ID {TID}, error {RC} ",
258 "TID", tid, "RC", rc);
259 return rc;
260 }
261
262 switch (sensorId)
263 {
264 case BOOT_OVERALL:
265 handleBootOverallEvent(tid, sensorId, presentReading);
266 break;
Chau Ly3de0d942024-10-03 08:57:11 +0000267 case PCIE_HOT_PLUG:
268 handlePCIeHotPlugEvent(tid, sensorId, presentReading);
269 break;
Chau Lya743e382024-10-26 11:12:22 +0000270 default:
271 std::string description;
272 std::stringstream strStream;
273 log_level logLevel = log_level::OK;
274
275 description += "SENSOR_EVENT : NUMERIC_SENSOR_STATE: ";
276 description += prefixMsgStrCreation(tid, sensorId);
277 strStream << std::setfill('0') << std::hex << "eventState 0x"
278 << std::setw(2) << static_cast<uint32_t>(eventState)
279 << " previousEventState 0x" << std::setw(2)
280 << static_cast<uint32_t>(previousEventState)
281 << " sensorDataSize 0x" << std::setw(2)
282 << static_cast<uint32_t>(sensorDataSize)
283 << " presentReading 0x" << std::setw(8)
284 << static_cast<uint32_t>(presentReading) << std::dec;
285 description += strStream.str();
286
287 sendJournalRedfish(description, logLevel);
288 break;
289 }
290 return PLDM_SUCCESS;
291}
292
293int OemEventManager::processStateSensorEvent(pldm_tid_t tid, uint16_t sensorId,
294 const uint8_t* sensorData,
295 size_t sensorDataLength)
296{
297 uint8_t sensorOffset = 0;
298 uint8_t eventState = 0;
299 uint8_t previousEventState = 0;
300
301 auto rc =
302 decode_state_sensor_data(sensorData, sensorDataLength, &sensorOffset,
303 &eventState, &previousEventState);
304 if (rc)
305 {
306 lg2::error(
307 "Failed to decode stateSensorState event for terminus ID {TID}, error {RC}",
308 "TID", tid, "RC", rc);
309 return rc;
310 }
311
312 std::string description;
313 std::stringstream strStream;
314 log_level logLevel = log_level::OK;
315
316 description += "SENSOR_EVENT : STATE_SENSOR_STATE: ";
317 description += prefixMsgStrCreation(tid, sensorId);
318 strStream << std::setfill('0') << std::hex << "sensorOffset 0x"
319 << std::setw(2) << static_cast<uint32_t>(sensorOffset)
320 << "eventState 0x" << std::setw(2)
321 << static_cast<uint32_t>(eventState) << " previousEventState 0x"
322 << std::setw(2) << static_cast<uint32_t>(previousEventState)
323 << std::dec;
324 description += strStream.str();
325
326 sendJournalRedfish(description, logLevel);
327
328 return PLDM_SUCCESS;
329}
330
331int OemEventManager::processSensorOpStateEvent(
332 pldm_tid_t tid, uint16_t sensorId, const uint8_t* sensorData,
333 size_t sensorDataLength)
334{
335 uint8_t present_op_state = 0;
336 uint8_t previous_op_state = 0;
337
338 auto rc = decode_sensor_op_data(sensorData, sensorDataLength,
339 &present_op_state, &previous_op_state);
340 if (rc)
341 {
342 lg2::error(
343 "Failed to decode sensorOpState event for terminus ID {TID}, error {RC}",
344 "TID", tid, "RC", rc);
345 return rc;
346 }
347
348 std::string description;
349 std::stringstream strStream;
350 log_level logLevel = log_level::OK;
351
352 description += "SENSOR_EVENT : SENSOR_OP_STATE: ";
353 description += prefixMsgStrCreation(tid, sensorId);
354 strStream << std::setfill('0') << std::hex << "present_op_state 0x"
355 << std::setw(2) << static_cast<uint32_t>(present_op_state)
356 << "previous_op_state 0x" << std::setw(2)
357 << static_cast<uint32_t>(previous_op_state) << std::dec;
358 description += strStream.str();
359
360 sendJournalRedfish(description, logLevel);
361
362 return PLDM_SUCCESS;
363}
364
365int OemEventManager::handleSensorEvent(
366 const pldm_msg* request, size_t payloadLength, uint8_t /* formatVersion */,
367 pldm_tid_t tid, size_t eventDataOffset)
368{
369 /* This OEM event handler is only used for SoC terminus*/
370 if (!tidToSocketNameMap.contains(tid))
371 {
372 return PLDM_SUCCESS;
373 }
374 auto eventData =
375 reinterpret_cast<const uint8_t*>(request->payload) + eventDataOffset;
376 auto eventDataSize = payloadLength - eventDataOffset;
377
378 uint16_t sensorId = 0;
379 uint8_t sensorEventClassType = 0;
380 size_t eventClassDataOffset = 0;
381 auto rc =
382 decode_sensor_event_data(eventData, eventDataSize, &sensorId,
383 &sensorEventClassType, &eventClassDataOffset);
384 if (rc)
385 {
386 lg2::error("Failed to decode sensor event data return code {RC}.", "RC",
387 rc);
388 return rc;
389 }
390 const uint8_t* sensorData = eventData + eventClassDataOffset;
391 size_t sensorDataLength = eventDataSize - eventClassDataOffset;
392
393 switch (sensorEventClassType)
394 {
395 case PLDM_NUMERIC_SENSOR_STATE:
396 {
397 return processNumericSensorEvent(tid, sensorId, sensorData,
398 sensorDataLength);
399 }
400 case PLDM_STATE_SENSOR_STATE:
401 {
402 return processStateSensorEvent(tid, sensorId, sensorData,
403 sensorDataLength);
404 }
405 case PLDM_SENSOR_OP_STATE:
406 {
407 return processSensorOpStateEvent(tid, sensorId, sensorData,
408 sensorDataLength);
409 }
410 default:
411 std::string description;
412 std::stringstream strStream;
413 log_level logLevel = log_level::OK;
414
415 description += "SENSOR_EVENT : Unsupported Sensor Class " +
416 std::to_string(sensorEventClassType) + ": ";
417 description += prefixMsgStrCreation(tid, sensorId);
418 strStream << std::setfill('0') << std::hex
419 << std::setw(sizeof(sensorData) * 2) << "Sensor data: ";
420
421 auto dataPtr = sensorData;
422 for ([[maybe_unused]] const auto& i :
423 std::views::iota(0, (int)sensorDataLength))
424 {
425 strStream << "0x" << static_cast<uint32_t>(*dataPtr);
426 dataPtr += sizeof(sensorData);
427 }
428
429 description += strStream.str();
430
431 sendJournalRedfish(description, logLevel);
432 }
433 lg2::info("Unsupported class type {CLASSTYPE}", "CLASSTYPE",
434 sensorEventClassType);
435 return PLDM_ERROR;
436}
437
Chau Ly3de0d942024-10-03 08:57:11 +0000438void OemEventManager::handlePCIeHotPlugEvent(pldm_tid_t tid, uint16_t sensorId,
439 uint32_t presentReading)
440{
441 std::string description;
442 std::stringstream strStream;
443 PCIeHotPlugEventRecord_t record{presentReading};
444
445 std::string sAction = (!record.bits.action) ? "Insertion" : "Removal";
446 std::string sOpStatus = (!record.bits.opStatus) ? "Successful" : "Failed";
447 log_level logLevel =
448 (!record.bits.opStatus) ? log_level::OK : log_level::WARNING;
449
450 description += prefixMsgStrCreation(tid, sensorId);
451
452 strStream << "Segment (0x" << std::setfill('0') << std::hex << std::setw(2)
453 << static_cast<uint32_t>(record.bits.segment) << "); Bus (0x"
454 << std::setw(2) << static_cast<uint32_t>(record.bits.bus)
455 << "); Device (0x" << std::setw(2)
456 << static_cast<uint32_t>(record.bits.device) << "); Function (0x"
457 << std::setw(2) << static_cast<uint32_t>(record.bits.function)
458 << "); Action (" << sAction << "); Operation status ("
459 << sOpStatus << "); Media slot number (" << std::dec
460 << static_cast<uint32_t>(record.bits.mediaSlot) << ")";
461
462 description += strStream.str();
463
464 // Log to Redfish event
465 sendJournalRedfish(description, logLevel);
466}
467
Chau Lya743e382024-10-26 11:12:22 +0000468} // namespace oem_ampere
469} // namespace pldm