blob: 8e9b4589f0a66d818fbb97e725a792fb75e51a72 [file] [log] [blame]
Jason M. Bills5e049d32018-10-19 12:59:38 -07001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16
17#pragma once
Lei YU9916d412025-02-06 11:51:18 +000018#include <boost/container/flat_map.hpp>
19#include <boost/container/flat_set.hpp>
20#include <sdbusplus/bus/match.hpp>
Jason M. Bills5e049d32018-10-19 12:59:38 -070021#include <sel_logger.hpp>
22#include <sensorutils.hpp>
Zhikui Ren672bdfc2020-07-14 11:37:01 -070023
Jason M. Bills2b9704d2018-11-02 13:12:09 -070024#include <string_view>
Jason M. Bills2bc9f0d2019-03-27 11:13:12 -070025#include <variant>
Jason M. Bills5e049d32018-10-19 12:59:38 -070026
27enum class thresholdEventOffsets : uint8_t
28{
29 lowerNonCritGoingLow = 0x00,
30 lowerCritGoingLow = 0x02,
31 upperNonCritGoingHigh = 0x07,
32 upperCritGoingHigh = 0x09,
33};
34
35static constexpr const uint8_t thresholdEventDataTriggerReadingByte2 = (1 << 6);
36static constexpr const uint8_t thresholdEventDataTriggerReadingByte3 = (1 << 4);
37
Jason M. Bills60ec28a2019-04-11 16:53:44 -070038static const std::string openBMCMessageRegistryVersion("0.1");
Jason M. Bills2b9704d2018-11-02 13:12:09 -070039
Patrick Williamsccef2272022-07-22 19:26:54 -050040inline static sdbusplus::bus::match_t startThresholdAssertMonitor(
Jason M. Bills5e049d32018-10-19 12:59:38 -070041 std::shared_ptr<sdbusplus::asio::connection> conn)
42{
Patrick Williamsccef2272022-07-22 19:26:54 -050043 auto thresholdAssertMatcherCallback = [conn](sdbusplus::message_t& msg) {
Jason M. Bills5e049d32018-10-19 12:59:38 -070044 // This static set of std::pair<path, event> tracks asserted events to
45 // avoid duplicate logs or deasserts logged without an assert
46 static boost::container::flat_set<std::pair<std::string, std::string>>
47 assertedEvents;
Zhikui Ren25b26e12020-06-26 20:18:19 -070048 std::vector<uint8_t> eventData(selEvtDataMaxSize,
49 selEvtDataUnspecified);
Jason M. Bills5e049d32018-10-19 12:59:38 -070050
51 // Get the event type and assertion details from the message
Zhikui Ren25b26e12020-06-26 20:18:19 -070052 std::string sensorName;
Jason M. Bills5e049d32018-10-19 12:59:38 -070053 std::string thresholdInterface;
Zhikui Ren25b26e12020-06-26 20:18:19 -070054 std::string event;
55 bool assert;
56 double assertValue;
57 try
Jason M. Bills5e049d32018-10-19 12:59:38 -070058 {
Zhikui Ren25b26e12020-06-26 20:18:19 -070059 msg.read(sensorName, thresholdInterface, event, assert,
60 assertValue);
61 }
Patrick Williams3f4cd972021-10-06 12:42:50 -050062 catch (const sdbusplus::exception_t&)
Zhikui Ren25b26e12020-06-26 20:18:19 -070063 {
64 std::cerr << "error getting assert signal data from "
65 << msg.get_path() << "\n";
Jason M. Bills5e049d32018-10-19 12:59:38 -070066 return;
67 }
Jason M. Bills5e049d32018-10-19 12:59:38 -070068
69 // Check the asserted events to determine if we should log this event
70 std::pair<std::string, std::string> pathAndEvent(
71 std::string(msg.get_path()), event);
72 if (assert)
73 {
74 // For asserts, add the event to the set and only log it if it's new
75 if (assertedEvents.insert(pathAndEvent).second == false)
76 {
77 // event is already in the set
78 return;
79 }
80 }
81 else
82 {
83 // For deasserts, remove the event and only log the deassert if it
84 // was asserted
85 if (assertedEvents.erase(pathAndEvent) == 0)
86 {
87 // asserted event was not in the set
88 return;
89 }
90 }
91
92 // Set the IPMI threshold event type based on the event details from the
93 // message
94 if (event == "CriticalAlarmLow")
95 {
96 eventData[0] =
97 static_cast<uint8_t>(thresholdEventOffsets::lowerCritGoingLow);
98 }
99 else if (event == "WarningAlarmLow")
100 {
101 eventData[0] = static_cast<uint8_t>(
102 thresholdEventOffsets::lowerNonCritGoingLow);
103 }
104 else if (event == "WarningAlarmHigh")
105 {
106 eventData[0] = static_cast<uint8_t>(
107 thresholdEventOffsets::upperNonCritGoingHigh);
108 }
109 else if (event == "CriticalAlarmHigh")
110 {
111 eventData[0] =
112 static_cast<uint8_t>(thresholdEventOffsets::upperCritGoingHigh);
113 }
114 // Indicate that bytes 2 and 3 are threshold sensor trigger values
115 eventData[0] |= thresholdEventDataTriggerReadingByte2 |
116 thresholdEventDataTriggerReadingByte3;
117
118 // Get the sensor reading to put in the event data
Patrick Williamsccef2272022-07-22 19:26:54 -0500119 sdbusplus::message_t getSensorValue =
Jason M. Bills5e049d32018-10-19 12:59:38 -0700120 conn->new_method_call(msg.get_sender(), msg.get_path(),
121 "org.freedesktop.DBus.Properties", "GetAll");
122 getSensorValue.append("xyz.openbmc_project.Sensor.Value");
George Hungd9d78962019-03-27 13:25:24 +0800123 boost::container::flat_map<std::string, std::variant<double, int64_t>>
Jason M. Bills5e049d32018-10-19 12:59:38 -0700124 sensorValue;
125 try
126 {
Patrick Williamsccef2272022-07-22 19:26:54 -0500127 sdbusplus::message_t getSensorValueResp =
Jason M. Bills5e049d32018-10-19 12:59:38 -0700128 conn->call(getSensorValue);
129 getSensorValueResp.read(sensorValue);
130 }
Patrick Williams3f4cd972021-10-06 12:42:50 -0500131 catch (const sdbusplus::exception_t&)
Jason M. Bills5e049d32018-10-19 12:59:38 -0700132 {
133 std::cerr << "error getting sensor value from " << msg.get_path()
134 << "\n";
135 return;
136 }
Jason M. Billsbb071fb2019-03-27 11:15:42 -0700137 double max = 0;
138 auto findMax = sensorValue.find("MaxValue");
139 if (findMax != sensorValue.end())
140 {
141 max = std::visit(ipmi::VariantToDoubleVisitor(), findMax->second);
142 }
143 double min = 0;
144 auto findMin = sensorValue.find("MinValue");
145 if (findMin != sensorValue.end())
146 {
147 min = std::visit(ipmi::VariantToDoubleVisitor(), findMin->second);
148 }
George Hungd9d78962019-03-27 13:25:24 +0800149
Jason M. Bills5e049d32018-10-19 12:59:38 -0700150 try
151 {
Zhikui Ren25b26e12020-06-26 20:18:19 -0700152 eventData[1] = ipmi::getScaledIPMIValue(assertValue, max, min);
Jason M. Bills5e049d32018-10-19 12:59:38 -0700153 }
Zhikui Ren672bdfc2020-07-14 11:37:01 -0700154 catch (const std::exception& e)
Jason M. Bills5e049d32018-10-19 12:59:38 -0700155 {
156 std::cerr << e.what();
Zhikui Ren25b26e12020-06-26 20:18:19 -0700157 eventData[1] = selEvtDataUnspecified;
Jason M. Bills5e049d32018-10-19 12:59:38 -0700158 }
159
160 // Get the threshold value to put in the event data
161 // Get the threshold parameter by removing the "Alarm" text from the
162 // event string
163 std::string alarm("Alarm");
164 if (std::string::size_type pos = event.find(alarm);
165 pos != std::string::npos)
166 {
167 event.erase(pos, alarm.length());
168 }
Patrick Williamsccef2272022-07-22 19:26:54 -0500169 sdbusplus::message_t getThreshold =
Jason M. Bills5e049d32018-10-19 12:59:38 -0700170 conn->new_method_call(msg.get_sender(), msg.get_path(),
171 "org.freedesktop.DBus.Properties", "Get");
172 getThreshold.append(thresholdInterface, event);
George Hungd9d78962019-03-27 13:25:24 +0800173 std::variant<double, int64_t> thresholdValue;
Jason M. Bills5e049d32018-10-19 12:59:38 -0700174 try
175 {
Patrick Williamsccef2272022-07-22 19:26:54 -0500176 sdbusplus::message_t getThresholdResp = conn->call(getThreshold);
Jason M. Bills5e049d32018-10-19 12:59:38 -0700177 getThresholdResp.read(thresholdValue);
178 }
Patrick Williams3f4cd972021-10-06 12:42:50 -0500179 catch (const sdbusplus::exception_t&)
Jason M. Bills5e049d32018-10-19 12:59:38 -0700180 {
181 std::cerr << "error getting sensor threshold from "
182 << msg.get_path() << "\n";
183 return;
184 }
Patrick Williams5a18f102024-08-16 15:20:38 -0400185 double thresholdVal =
186 std::visit(ipmi::VariantToDoubleVisitor(), thresholdValue);
Zhikui Ren25b26e12020-06-26 20:18:19 -0700187
188 double scale = 0;
189 auto findScale = sensorValue.find("Scale");
George Hungd9d78962019-03-27 13:25:24 +0800190 if (findScale != sensorValue.end())
191 {
Patrick Williams5a18f102024-08-16 15:20:38 -0400192 scale =
193 std::visit(ipmi::VariantToDoubleVisitor(), findScale->second);
George Hungd9d78962019-03-27 13:25:24 +0800194 thresholdVal *= std::pow(10, scale);
195 }
Jason M. Bills5e049d32018-10-19 12:59:38 -0700196 try
197 {
198 eventData[2] = ipmi::getScaledIPMIValue(thresholdVal, max, min);
199 }
Zhikui Ren672bdfc2020-07-14 11:37:01 -0700200 catch (const std::exception& e)
Jason M. Bills5e049d32018-10-19 12:59:38 -0700201 {
202 std::cerr << e.what();
Zhikui Ren25b26e12020-06-26 20:18:19 -0700203 eventData[2] = selEvtDataUnspecified;
Jason M. Bills5e049d32018-10-19 12:59:38 -0700204 }
205
Jason M. Bills2b9704d2018-11-02 13:12:09 -0700206 std::string threshold;
207 std::string direction;
Patrick Williams5a18f102024-08-16 15:20:38 -0400208 std::string redfishMessageID =
209 "OpenBMC." + openBMCMessageRegistryVersion;
Glukhov Mikhail3fc535c2023-03-15 09:50:55 +0300210 enum EventType
211 {
212 eventNone,
213 eventInfo,
214 eventWarn,
215 eventErr
216 };
Glukhov Mikhail8cb7d0a2023-04-06 07:21:23 +0300217 [[maybe_unused]] EventType eventType = eventNone;
Jason M. Bills2b9704d2018-11-02 13:12:09 -0700218 if (event == "CriticalLow")
219 {
220 threshold = "critical low";
221 if (assert)
222 {
Glukhov Mikhail3fc535c2023-03-15 09:50:55 +0300223 eventType = eventErr;
Jason M. Bills2b9704d2018-11-02 13:12:09 -0700224 direction = "low";
Jason M. Bills60ec28a2019-04-11 16:53:44 -0700225 redfishMessageID += ".SensorThresholdCriticalLowGoingLow";
Jason M. Bills2b9704d2018-11-02 13:12:09 -0700226 }
227 else
228 {
Glukhov Mikhail3fc535c2023-03-15 09:50:55 +0300229 eventType = eventInfo;
Jason M. Bills2b9704d2018-11-02 13:12:09 -0700230 direction = "high";
Jason M. Bills60ec28a2019-04-11 16:53:44 -0700231 redfishMessageID += ".SensorThresholdCriticalLowGoingHigh";
Jason M. Bills2b9704d2018-11-02 13:12:09 -0700232 }
233 }
234 else if (event == "WarningLow")
235 {
236 threshold = "warning low";
237 if (assert)
238 {
Glukhov Mikhail3fc535c2023-03-15 09:50:55 +0300239 eventType = eventWarn;
Jason M. Bills2b9704d2018-11-02 13:12:09 -0700240 direction = "low";
Jason M. Bills60ec28a2019-04-11 16:53:44 -0700241 redfishMessageID += ".SensorThresholdWarningLowGoingLow";
Jason M. Bills2b9704d2018-11-02 13:12:09 -0700242 }
243 else
244 {
Glukhov Mikhail3fc535c2023-03-15 09:50:55 +0300245 eventType = eventInfo;
Jason M. Bills2b9704d2018-11-02 13:12:09 -0700246 direction = "high";
Jason M. Bills60ec28a2019-04-11 16:53:44 -0700247 redfishMessageID += ".SensorThresholdWarningLowGoingHigh";
Jason M. Bills2b9704d2018-11-02 13:12:09 -0700248 }
249 }
250 else if (event == "WarningHigh")
251 {
252 threshold = "warning high";
253 if (assert)
254 {
Glukhov Mikhail3fc535c2023-03-15 09:50:55 +0300255 eventType = eventWarn;
Jason M. Bills2b9704d2018-11-02 13:12:09 -0700256 direction = "high";
Jason M. Bills60ec28a2019-04-11 16:53:44 -0700257 redfishMessageID += ".SensorThresholdWarningHighGoingHigh";
Jason M. Bills2b9704d2018-11-02 13:12:09 -0700258 }
259 else
260 {
Glukhov Mikhail3fc535c2023-03-15 09:50:55 +0300261 eventType = eventInfo;
Jason M. Bills2b9704d2018-11-02 13:12:09 -0700262 direction = "low";
Jason M. Bills60ec28a2019-04-11 16:53:44 -0700263 redfishMessageID += ".SensorThresholdWarningHighGoingLow";
Jason M. Bills2b9704d2018-11-02 13:12:09 -0700264 }
265 }
266 else if (event == "CriticalHigh")
267 {
268 threshold = "critical high";
269 if (assert)
270 {
Glukhov Mikhail3fc535c2023-03-15 09:50:55 +0300271 eventType = eventErr;
Jason M. Bills2b9704d2018-11-02 13:12:09 -0700272 direction = "high";
Jason M. Bills60ec28a2019-04-11 16:53:44 -0700273 redfishMessageID += ".SensorThresholdCriticalHighGoingHigh";
Jason M. Bills2b9704d2018-11-02 13:12:09 -0700274 }
275 else
276 {
Glukhov Mikhail3fc535c2023-03-15 09:50:55 +0300277 eventType = eventInfo;
Jason M. Bills2b9704d2018-11-02 13:12:09 -0700278 direction = "low";
Jason M. Bills60ec28a2019-04-11 16:53:44 -0700279 redfishMessageID += ".SensorThresholdCriticalHighGoingLow";
Jason M. Bills2b9704d2018-11-02 13:12:09 -0700280 }
281 }
282
Konstantin Aladyshevd067a6b2023-03-31 09:22:49 +0000283 std::string journalMsg(
284 std::string(sensorName) + " " + threshold + " threshold " +
285 (assert ? "assert" : "deassert") +
286 ". Reading=" + std::to_string(assertValue) +
287 " Threshold=" + std::to_string(thresholdVal) + ".");
Jason M. Bills5e049d32018-10-19 12:59:38 -0700288
Glukhov Mikhail3fc535c2023-03-15 09:50:55 +0300289#ifdef SEL_LOGGER_SEND_TO_LOGGING_SERVICE
290 std::string LogLevel = "";
291 switch (eventType)
292 {
293 case eventInfo:
294 {
295 LogLevel =
296 "xyz.openbmc_project.Logging.Entry.Level.Informational";
297 break;
298 }
299 case eventWarn:
300 {
301 LogLevel = "xyz.openbmc_project.Logging.Entry.Level.Warning";
302 break;
303 }
304 case eventErr:
305 {
306 LogLevel = "xyz.openbmc_project.Logging.Entry.Level.Critical";
307 break;
308 }
309 default:
310 {
311 LogLevel = "xyz.openbmc_project.Logging.Entry.Level.Debug";
312 break;
313 }
314 }
315 if (eventType != eventNone)
316 {
Patrick Williams99f69972023-03-28 02:31:11 -0500317 sdbusplus::message_t AddToLog = conn->new_method_call(
Glukhov Mikhail3fc535c2023-03-15 09:50:55 +0300318 "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging",
319 "xyz.openbmc_project.Logging.Create", "Create");
320 AddToLog.append(journalMsg, LogLevel,
321 std::map<std::string, std::string>(
322 {{"SENSOR_PATH", std::string(msg.get_path())},
323 {"EVENT", threshold},
324 {"DIRECTION", direction},
325 {"THRESHOLD", std::to_string(thresholdVal)},
326 {"READING", std::to_string(assertValue)}}));
327 conn->call(AddToLog);
328 }
329#else
Jason M. Bills5ff505f2019-04-11 16:58:01 -0700330 selAddSystemRecord(
Konstantin Aladyshev6f5342d2023-04-19 09:23:11 +0000331 conn, journalMsg, std::string(msg.get_path()), eventData, assert,
Jason M. Bills5ff505f2019-04-11 16:58:01 -0700332 selBMCGenID, "REDFISH_MESSAGE_ID=%s", redfishMessageID.c_str(),
333 "REDFISH_MESSAGE_ARGS=%.*s,%f,%f", sensorName.length(),
Zhikui Ren25b26e12020-06-26 20:18:19 -0700334 sensorName.data(), assertValue, thresholdVal);
Glukhov Mikhail3fc535c2023-03-15 09:50:55 +0300335#endif
Jason M. Bills5e049d32018-10-19 12:59:38 -0700336 };
Patrick Williamsccef2272022-07-22 19:26:54 -0500337 sdbusplus::bus::match_t thresholdAssertMatcher(
338 static_cast<sdbusplus::bus_t&>(*conn),
Zhikui Ren25b26e12020-06-26 20:18:19 -0700339 "type='signal', member='ThresholdAsserted'",
340 std::move(thresholdAssertMatcherCallback));
341 return thresholdAssertMatcher;
Jason M. Bills5e049d32018-10-19 12:59:38 -0700342}