blob: b50daf27b99ecb25d04a0b439e5d67d43cb7ac53 [file] [log] [blame]
Gilbert Chen77e6fe72024-08-06 09:23:30 +00001#include "event_manager.hpp"
2
3#include "libpldm/utils.h"
4
5#include "terminus_manager.hpp"
6
7#include <phosphor-logging/lg2.hpp>
8#include <xyz/openbmc_project/Logging/Entry/server.hpp>
9
10#include <cerrno>
11#include <memory>
12
13PHOSPHOR_LOG2_USING;
14
15namespace pldm
16{
17namespace platform_mc
18{
19namespace fs = std::filesystem;
20
21int EventManager::handlePlatformEvent(
22 pldm_tid_t tid, uint16_t eventId, uint8_t eventClass,
23 const uint8_t* eventData, size_t eventDataSize)
24{
25 /* EventClass sensorEvent `Table 11 - PLDM Event Types` DSP0248 */
26 if (eventClass == PLDM_SENSOR_EVENT)
27 {
28 uint16_t sensorId = 0;
29 uint8_t sensorEventClassType = 0;
30 size_t eventClassDataOffset = 0;
31 auto rc = decode_sensor_event_data(eventData, eventDataSize, &sensorId,
32 &sensorEventClassType,
33 &eventClassDataOffset);
34 if (rc)
35 {
36 lg2::error(
37 "Failed to decode sensor event data from terminus ID {TID}, event class {CLASS}, event ID {EVENTID} with return code {RC}.",
38 "TID", tid, "CLASS", eventClass, "EVENTID", eventId, "RC", rc);
39 return rc;
40 }
41 switch (sensorEventClassType)
42 {
43 case PLDM_NUMERIC_SENSOR_STATE:
44 {
45 const uint8_t* sensorData = eventData + eventClassDataOffset;
46 size_t sensorDataLength = eventDataSize - eventClassDataOffset;
47 return processNumericSensorEvent(tid, sensorId, sensorData,
48 sensorDataLength);
49 }
50 case PLDM_STATE_SENSOR_STATE:
51 case PLDM_SENSOR_OP_STATE:
52 default:
53 lg2::info(
54 "Unsupported class type {CLASSTYPE} for the sensor event from terminus ID {TID} sensorId {SID}",
55 "CLASSTYPE", sensorEventClassType, "TID", tid, "SID",
56 sensorId);
57 return PLDM_ERROR;
58 }
59 }
60
Thu Nguyen9fc79122024-09-10 10:15:01 +000061 /* EventClass CPEREvent as `Table 11 - PLDM Event Types` DSP0248 V1.3.0 */
62 if (eventClass == PLDM_CPER_EVENT)
63 {
64 return processCperEvent(tid, eventId, eventData, eventDataSize);
65 }
66
Gilbert Chen77e6fe72024-08-06 09:23:30 +000067 lg2::info("Unsupported class type {CLASSTYPE}", "CLASSTYPE", eventClass);
68
69 return PLDM_ERROR;
70}
71
72int EventManager::processNumericSensorEvent(pldm_tid_t tid, uint16_t sensorId,
73 const uint8_t* sensorData,
74 size_t sensorDataLength)
75{
76 uint8_t eventState = 0;
77 uint8_t previousEventState = 0;
78 uint8_t sensorDataSize = 0;
79 uint32_t presentReading;
80 auto rc = decode_numeric_sensor_data(
81 sensorData, sensorDataLength, &eventState, &previousEventState,
82 &sensorDataSize, &presentReading);
83 if (rc)
84 {
85 lg2::error(
86 "Failed to decode numericSensorState event for terminus ID {TID}, error {RC} ",
87 "TID", tid, "RC", rc);
88 return rc;
89 }
90
91 double value = static_cast<double>(presentReading);
92 lg2::error(
93 "processNumericSensorEvent tid {TID}, sensorID {SID} value {VAL} previousState {PSTATE} eventState {ESTATE}",
94 "TID", tid, "SID", sensorId, "VAL", value, "PSTATE", previousEventState,
95 "ESTATE", eventState);
96
97 if (!termini.contains(tid) || !termini[tid])
98 {
99 lg2::error("Terminus ID {TID} is not in the managing list.", "TID",
100 tid);
101 return PLDM_ERROR;
102 }
103
104 auto& terminus = termini[tid];
105
106 auto sensor = terminus->getSensorObject(sensorId);
107 if (!sensor)
108 {
109 lg2::error(
110 "Terminus ID {TID} has no sensor object with sensor ID {SID}.",
111 "TID", tid, "SID", sensorId);
112 return PLDM_ERROR;
113 }
114
115 switch (previousEventState)
116 {
117 case PLDM_SENSOR_UNKNOWN:
118 case PLDM_SENSOR_NORMAL:
119 {
120 switch (eventState)
121 {
122 case PLDM_SENSOR_UPPERFATAL:
123 case PLDM_SENSOR_UPPERCRITICAL:
124 {
125 sensor->triggerThresholdEvent(pldm::utils::Level::WARNING,
126 pldm::utils::Direction::HIGH,
127 value, true, true);
128 return sensor->triggerThresholdEvent(
129 pldm::utils::Level::CRITICAL,
130 pldm::utils::Direction::HIGH, value, true, true);
131 }
132 case PLDM_SENSOR_UPPERWARNING:
133 {
134 return sensor->triggerThresholdEvent(
135 pldm::utils::Level::WARNING,
136 pldm::utils::Direction::HIGH, value, true, true);
137 }
138 case PLDM_SENSOR_NORMAL:
139 break;
140 case PLDM_SENSOR_LOWERWARNING:
141 {
142 return sensor->triggerThresholdEvent(
143 pldm::utils::Level::WARNING,
144 pldm::utils::Direction::LOW, value, true, true);
145 }
146 case PLDM_SENSOR_LOWERCRITICAL:
147 case PLDM_SENSOR_LOWERFATAL:
148 {
149 sensor->triggerThresholdEvent(pldm::utils::Level::WARNING,
150 pldm::utils::Direction::LOW,
151 value, true, true);
152 return sensor->triggerThresholdEvent(
153 pldm::utils::Level::CRITICAL,
154 pldm::utils::Direction::LOW, value, true, true);
155 }
156 default:
157 break;
158 }
159 break;
160 }
161 case PLDM_SENSOR_LOWERWARNING:
162 {
163 switch (eventState)
164 {
165 case PLDM_SENSOR_UPPERFATAL:
166 case PLDM_SENSOR_UPPERCRITICAL:
167 break;
168 case PLDM_SENSOR_UPPERWARNING:
169 {
170 sensor->triggerThresholdEvent(pldm::utils::Level::WARNING,
171 pldm::utils::Direction::LOW,
172 value, false, false);
173 return sensor->triggerThresholdEvent(
174 pldm::utils::Level::WARNING,
175 pldm::utils::Direction::HIGH, value, true, true);
176 }
177 case PLDM_SENSOR_NORMAL:
178 {
179 return sensor->triggerThresholdEvent(
180 pldm::utils::Level::WARNING,
181 pldm::utils::Direction::LOW, value, false, false);
182 }
183 case PLDM_SENSOR_LOWERWARNING:
184 break;
185 case PLDM_SENSOR_LOWERCRITICAL:
186 case PLDM_SENSOR_LOWERFATAL:
187 {
188 return sensor->triggerThresholdEvent(
189 pldm::utils::Level::CRITICAL,
190 pldm::utils::Direction::LOW, value, true, true);
191 }
192 default:
193 break;
194 }
195 break;
196 }
197 case PLDM_SENSOR_LOWERCRITICAL:
198 case PLDM_SENSOR_LOWERFATAL:
199 {
200 switch (eventState)
201 {
202 case PLDM_SENSOR_UPPERFATAL:
203 case PLDM_SENSOR_UPPERCRITICAL:
204 case PLDM_SENSOR_UPPERWARNING:
205 break;
206 case PLDM_SENSOR_NORMAL:
207 {
208 sensor->triggerThresholdEvent(pldm::utils::Level::CRITICAL,
209 pldm::utils::Direction::LOW,
210 value, false, false);
211 sensor->triggerThresholdEvent(pldm::utils::Level::WARNING,
212 pldm::utils::Direction::LOW,
213 value, true, true);
214 return sensor->triggerThresholdEvent(
215 pldm::utils::Level::WARNING,
216 pldm::utils::Direction::LOW, value, false, false);
217 }
218 case PLDM_SENSOR_LOWERWARNING:
219 {
220 sensor->triggerThresholdEvent(pldm::utils::Level::CRITICAL,
221 pldm::utils::Direction::LOW,
222 value, false, false);
223 return sensor->triggerThresholdEvent(
224 pldm::utils::Level::WARNING,
225 pldm::utils::Direction::LOW, value, true, true);
226 }
227 case PLDM_SENSOR_LOWERCRITICAL:
228 case PLDM_SENSOR_LOWERFATAL:
229 default:
230 break;
231 }
232 break;
233 }
234 case PLDM_SENSOR_UPPERFATAL:
235 case PLDM_SENSOR_UPPERCRITICAL:
236 {
237 switch (eventState)
238 {
239 case PLDM_SENSOR_UPPERFATAL:
240 case PLDM_SENSOR_UPPERCRITICAL:
241 break;
242 case PLDM_SENSOR_UPPERWARNING:
243 {
244 sensor->triggerThresholdEvent(pldm::utils::Level::CRITICAL,
245 pldm::utils::Direction::HIGH,
246 value, false, false);
247 return sensor->triggerThresholdEvent(
248 pldm::utils::Level::WARNING,
249 pldm::utils::Direction::HIGH, value, true, true);
250 }
251 case PLDM_SENSOR_NORMAL:
252 {
253 sensor->triggerThresholdEvent(pldm::utils::Level::CRITICAL,
254 pldm::utils::Direction::HIGH,
255 value, false, false);
256 sensor->triggerThresholdEvent(pldm::utils::Level::WARNING,
257 pldm::utils::Direction::HIGH,
258 value, true, true);
259 return sensor->triggerThresholdEvent(
260 pldm::utils::Level::WARNING,
261 pldm::utils::Direction::HIGH, value, false, false);
262 }
263 case PLDM_SENSOR_LOWERWARNING:
264 case PLDM_SENSOR_LOWERCRITICAL:
265 case PLDM_SENSOR_LOWERFATAL:
266 default:
267 break;
268 }
269 break;
270 }
271 case PLDM_SENSOR_UPPERWARNING:
272 {
273 switch (eventState)
274 {
275 case PLDM_SENSOR_UPPERFATAL:
276 case PLDM_SENSOR_UPPERCRITICAL:
277 {
278 return sensor->triggerThresholdEvent(
279 pldm::utils::Level::CRITICAL,
280 pldm::utils::Direction::HIGH, value, true, true);
281 }
282 case PLDM_SENSOR_UPPERWARNING:
283 break;
284 case PLDM_SENSOR_NORMAL:
285 {
286 return sensor->triggerThresholdEvent(
287 pldm::utils::Level::WARNING,
288 pldm::utils::Direction::HIGH, value, false, false);
289 }
290 case PLDM_SENSOR_LOWERWARNING:
291 {
292 sensor->triggerThresholdEvent(pldm::utils::Level::WARNING,
293 pldm::utils::Direction::HIGH,
294 value, false, false);
295 return sensor->triggerThresholdEvent(
296 pldm::utils::Level::WARNING,
297 pldm::utils::Direction::LOW, value, true, true);
298 }
299 case PLDM_SENSOR_LOWERCRITICAL:
300 case PLDM_SENSOR_LOWERFATAL:
301 default:
302 break;
303 }
304 break;
305 }
306 default:
307 break;
308 }
309
310 return PLDM_SUCCESS;
311}
312
Thu Nguyen9fc79122024-09-10 10:15:01 +0000313int EventManager::processCperEvent(pldm_tid_t tid, uint16_t eventId,
314 const uint8_t* eventData,
315 const size_t eventDataSize)
316{
317 if (eventDataSize < PLDM_PLATFORM_CPER_EVENT_MIN_LENGTH)
318 {
319 lg2::error(
320 "Error : Invalid CPER Event data length for eventId {EVENTID}.",
321 "EVENTID", eventId);
322 return PLDM_ERROR;
323 }
324 const size_t cperEventDataSize =
325 eventDataSize - PLDM_PLATFORM_CPER_EVENT_MIN_LENGTH;
326 const size_t msgDataLen =
327 sizeof(pldm_platform_cper_event) + cperEventDataSize;
328 std::string terminusName = "";
329 auto msgData = std::make_unique<unsigned char[]>(msgDataLen);
330 auto cperEvent = new (msgData.get()) pldm_platform_cper_event;
331
332 auto rc = decode_pldm_platform_cper_event(eventData, eventDataSize,
333 cperEvent, msgDataLen);
334
335 if (rc)
336 {
337 lg2::error(
338 "Failed to decode CPER event for eventId {EVENTID} of terminus ID {TID} error {RC}.",
339 "EVENTID", eventId, "TID", tid, "RC", rc);
340 return rc;
341 }
342
343 if (termini.contains(tid) && !termini[tid])
344 {
345 auto tmp = termini[tid]->getTerminusName();
346 if (tmp && !tmp.value().empty())
347 {
348 terminusName = static_cast<std::string>(tmp.value());
349 }
350 }
351
352 // Save event data to file
353 std::filesystem::path dirName{"/var/cper"};
354 if (!std::filesystem::exists(dirName))
355 {
356 try
357 {
358 std::filesystem::create_directory(dirName);
359 }
360 catch (const std::filesystem::filesystem_error& e)
361 {
362 lg2::error("Failed to create /var/cper directory: {ERROR}", "ERROR",
363 e);
364 return PLDM_ERROR;
365 }
366 }
367
368 std::string fileName{dirName.string() + "/cper-XXXXXX"};
369 auto fd = mkstemp(fileName.data());
370 if (fd < 0)
371 {
372 lg2::error("Failed to generate temp file, error {ERRORNO}", "ERRORNO",
373 std::strerror(errno));
374 return PLDM_ERROR;
375 }
376 close(fd);
377
378 std::ofstream ofs;
379 ofs.exceptions(std::ofstream::failbit | std::ofstream::badbit |
380 std::ofstream::eofbit);
381
382 try
383 {
384 ofs.open(fileName);
385 ofs.write(reinterpret_cast<const char*>(
386 pldm_platform_cper_event_event_data(cperEvent)),
387 cperEvent->event_data_length);
388 if (cperEvent->format_type == PLDM_PLATFORM_CPER_EVENT_WITH_HEADER)
389 {
390 rc = createCperDumpEntry("CPER", fileName, terminusName);
391 }
392 else
393 {
394 rc = createCperDumpEntry("CPERSection", fileName, terminusName);
395 }
396 ofs.close();
397 }
398 catch (const std::ofstream::failure& e)
399 {
400 lg2::error("Failed to save CPER to '{FILENAME}', error - {ERROR}.",
401 "FILENAME", fileName, "ERROR", e);
402 return PLDM_ERROR;
403 }
404 return rc;
405}
406
407int EventManager::createCperDumpEntry(const std::string& dataType,
408 const std::string& dataPath,
409 const std::string& typeName)
410{
411 auto createDump =
412 [](std::map<std::string, std::variant<std::string, uint64_t>>&
413 addData) {
414 static constexpr auto dumpObjPath =
415 "/xyz/openbmc_project/dump/faultlog";
416 static constexpr auto dumpInterface =
417 "xyz.openbmc_project.Dump.Create";
418 auto& bus = pldm::utils::DBusHandler::getBus();
419
420 try
421 {
422 auto service = pldm::utils::DBusHandler().getService(
423 dumpObjPath, dumpInterface);
424 auto method = bus.new_method_call(service.c_str(), dumpObjPath,
425 dumpInterface, "CreateDump");
426 method.append(addData);
427 bus.call_noreply(method);
428 }
429 catch (const std::exception& e)
430 {
431 lg2::error(
432 "Failed to create D-Bus Dump entry, error - {ERROR}.",
433 "ERROR", e);
434 }
435 };
436
437 std::map<std::string, std::variant<std::string, uint64_t>> addData;
438 addData["Type"] = dataType;
439 addData["PrimaryLogId"] = dataPath;
440 addData["AdditionalTypeName"] = typeName;
441 createDump(addData);
442 return PLDM_SUCCESS;
443}
444
Gilbert Chen77e6fe72024-08-06 09:23:30 +0000445} // namespace platform_mc
446} // namespace pldm