blob: f1df9bd07067da71f1bbc49fa83f00be95198428 [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
18#include <sel_logger.hpp>
19#include <sensorutils.hpp>
Zhikui Ren672bdfc2020-07-14 11:37:01 -070020
Jason M. Bills2b9704d2018-11-02 13:12:09 -070021#include <string_view>
Jason M. Bills2bc9f0d2019-03-27 11:13:12 -070022#include <variant>
Jason M. Bills5e049d32018-10-19 12:59:38 -070023
24enum class thresholdEventOffsets : uint8_t
25{
26 lowerNonCritGoingLow = 0x00,
27 lowerCritGoingLow = 0x02,
28 upperNonCritGoingHigh = 0x07,
29 upperCritGoingHigh = 0x09,
30};
31
32static constexpr const uint8_t thresholdEventDataTriggerReadingByte2 = (1 << 6);
33static constexpr const uint8_t thresholdEventDataTriggerReadingByte3 = (1 << 4);
34
Jason M. Bills60ec28a2019-04-11 16:53:44 -070035static const std::string openBMCMessageRegistryVersion("0.1");
Jason M. Bills2b9704d2018-11-02 13:12:09 -070036
Zhikui Ren25b26e12020-06-26 20:18:19 -070037inline static sdbusplus::bus::match::match startThresholdAssertMonitor(
Jason M. Bills5e049d32018-10-19 12:59:38 -070038 std::shared_ptr<sdbusplus::asio::connection> conn)
39{
Zhikui Ren25b26e12020-06-26 20:18:19 -070040 auto thresholdAssertMatcherCallback = [conn](sdbusplus::message::message&
41 msg) {
Jason M. Bills5e049d32018-10-19 12:59:38 -070042 // This static set of std::pair<path, event> tracks asserted events to
43 // avoid duplicate logs or deasserts logged without an assert
44 static boost::container::flat_set<std::pair<std::string, std::string>>
45 assertedEvents;
Zhikui Ren25b26e12020-06-26 20:18:19 -070046 std::vector<uint8_t> eventData(selEvtDataMaxSize,
47 selEvtDataUnspecified);
Jason M. Bills5e049d32018-10-19 12:59:38 -070048
49 // Get the event type and assertion details from the message
Zhikui Ren25b26e12020-06-26 20:18:19 -070050 std::string sensorName;
Jason M. Bills5e049d32018-10-19 12:59:38 -070051 std::string thresholdInterface;
Zhikui Ren25b26e12020-06-26 20:18:19 -070052 std::string event;
53 bool assert;
54 double assertValue;
55 try
Jason M. Bills5e049d32018-10-19 12:59:38 -070056 {
Zhikui Ren25b26e12020-06-26 20:18:19 -070057 msg.read(sensorName, thresholdInterface, event, assert,
58 assertValue);
59 }
60 catch (sdbusplus::exception_t&)
61 {
62 std::cerr << "error getting assert signal data from "
63 << msg.get_path() << "\n";
Jason M. Bills5e049d32018-10-19 12:59:38 -070064 return;
65 }
Jason M. Bills5e049d32018-10-19 12:59:38 -070066
67 // Check the asserted events to determine if we should log this event
68 std::pair<std::string, std::string> pathAndEvent(
69 std::string(msg.get_path()), event);
70 if (assert)
71 {
72 // For asserts, add the event to the set and only log it if it's new
73 if (assertedEvents.insert(pathAndEvent).second == false)
74 {
75 // event is already in the set
76 return;
77 }
78 }
79 else
80 {
81 // For deasserts, remove the event and only log the deassert if it
82 // was asserted
83 if (assertedEvents.erase(pathAndEvent) == 0)
84 {
85 // asserted event was not in the set
86 return;
87 }
88 }
89
90 // Set the IPMI threshold event type based on the event details from the
91 // message
92 if (event == "CriticalAlarmLow")
93 {
94 eventData[0] =
95 static_cast<uint8_t>(thresholdEventOffsets::lowerCritGoingLow);
96 }
97 else if (event == "WarningAlarmLow")
98 {
99 eventData[0] = static_cast<uint8_t>(
100 thresholdEventOffsets::lowerNonCritGoingLow);
101 }
102 else if (event == "WarningAlarmHigh")
103 {
104 eventData[0] = static_cast<uint8_t>(
105 thresholdEventOffsets::upperNonCritGoingHigh);
106 }
107 else if (event == "CriticalAlarmHigh")
108 {
109 eventData[0] =
110 static_cast<uint8_t>(thresholdEventOffsets::upperCritGoingHigh);
111 }
112 // Indicate that bytes 2 and 3 are threshold sensor trigger values
113 eventData[0] |= thresholdEventDataTriggerReadingByte2 |
114 thresholdEventDataTriggerReadingByte3;
115
116 // Get the sensor reading to put in the event data
117 sdbusplus::message::message getSensorValue =
118 conn->new_method_call(msg.get_sender(), msg.get_path(),
119 "org.freedesktop.DBus.Properties", "GetAll");
120 getSensorValue.append("xyz.openbmc_project.Sensor.Value");
George Hungd9d78962019-03-27 13:25:24 +0800121 boost::container::flat_map<std::string, std::variant<double, int64_t>>
Jason M. Bills5e049d32018-10-19 12:59:38 -0700122 sensorValue;
123 try
124 {
125 sdbusplus::message::message getSensorValueResp =
126 conn->call(getSensorValue);
127 getSensorValueResp.read(sensorValue);
128 }
Zhikui Ren672bdfc2020-07-14 11:37:01 -0700129 catch (sdbusplus::exception_t&)
Jason M. Bills5e049d32018-10-19 12:59:38 -0700130 {
131 std::cerr << "error getting sensor value from " << msg.get_path()
132 << "\n";
133 return;
134 }
Jason M. Billsbb071fb2019-03-27 11:15:42 -0700135 double max = 0;
136 auto findMax = sensorValue.find("MaxValue");
137 if (findMax != sensorValue.end())
138 {
139 max = std::visit(ipmi::VariantToDoubleVisitor(), findMax->second);
140 }
141 double min = 0;
142 auto findMin = sensorValue.find("MinValue");
143 if (findMin != sensorValue.end())
144 {
145 min = std::visit(ipmi::VariantToDoubleVisitor(), findMin->second);
146 }
George Hungd9d78962019-03-27 13:25:24 +0800147
Jason M. Bills5e049d32018-10-19 12:59:38 -0700148 try
149 {
Zhikui Ren25b26e12020-06-26 20:18:19 -0700150 eventData[1] = ipmi::getScaledIPMIValue(assertValue, max, min);
Jason M. Bills5e049d32018-10-19 12:59:38 -0700151 }
Zhikui Ren672bdfc2020-07-14 11:37:01 -0700152 catch (const std::exception& e)
Jason M. Bills5e049d32018-10-19 12:59:38 -0700153 {
154 std::cerr << e.what();
Zhikui Ren25b26e12020-06-26 20:18:19 -0700155 eventData[1] = selEvtDataUnspecified;
Jason M. Bills5e049d32018-10-19 12:59:38 -0700156 }
157
158 // Get the threshold value to put in the event data
159 // Get the threshold parameter by removing the "Alarm" text from the
160 // event string
161 std::string alarm("Alarm");
162 if (std::string::size_type pos = event.find(alarm);
163 pos != std::string::npos)
164 {
165 event.erase(pos, alarm.length());
166 }
167 sdbusplus::message::message getThreshold =
168 conn->new_method_call(msg.get_sender(), msg.get_path(),
169 "org.freedesktop.DBus.Properties", "Get");
170 getThreshold.append(thresholdInterface, event);
George Hungd9d78962019-03-27 13:25:24 +0800171 std::variant<double, int64_t> thresholdValue;
Jason M. Bills5e049d32018-10-19 12:59:38 -0700172 try
173 {
174 sdbusplus::message::message getThresholdResp =
175 conn->call(getThreshold);
176 getThresholdResp.read(thresholdValue);
177 }
Zhikui Ren672bdfc2020-07-14 11:37:01 -0700178 catch (sdbusplus::exception_t&)
Jason M. Bills5e049d32018-10-19 12:59:38 -0700179 {
180 std::cerr << "error getting sensor threshold from "
181 << msg.get_path() << "\n";
182 return;
183 }
Jason M. Bills2bc9f0d2019-03-27 11:13:12 -0700184 double thresholdVal =
185 std::visit(ipmi::VariantToDoubleVisitor(), thresholdValue);
Zhikui Ren25b26e12020-06-26 20:18:19 -0700186
187 double scale = 0;
188 auto findScale = sensorValue.find("Scale");
George Hungd9d78962019-03-27 13:25:24 +0800189 if (findScale != sensorValue.end())
190 {
Zhikui Ren25b26e12020-06-26 20:18:19 -0700191 scale =
192 std::visit(ipmi::VariantToDoubleVisitor(), findScale->second);
George Hungd9d78962019-03-27 13:25:24 +0800193 thresholdVal *= std::pow(10, scale);
194 }
Jason M. Bills5e049d32018-10-19 12:59:38 -0700195 try
196 {
197 eventData[2] = ipmi::getScaledIPMIValue(thresholdVal, max, min);
198 }
Zhikui Ren672bdfc2020-07-14 11:37:01 -0700199 catch (const std::exception& e)
Jason M. Bills5e049d32018-10-19 12:59:38 -0700200 {
201 std::cerr << e.what();
Zhikui Ren25b26e12020-06-26 20:18:19 -0700202 eventData[2] = selEvtDataUnspecified;
Jason M. Bills5e049d32018-10-19 12:59:38 -0700203 }
204
Jason M. Bills2b9704d2018-11-02 13:12:09 -0700205 std::string threshold;
206 std::string direction;
Jason M. Billsf2552a52019-03-28 11:54:48 -0700207 std::string redfishMessageID =
Jason M. Bills60ec28a2019-04-11 16:53:44 -0700208 "OpenBMC." + openBMCMessageRegistryVersion;
Jason M. Bills2b9704d2018-11-02 13:12:09 -0700209 if (event == "CriticalLow")
210 {
211 threshold = "critical low";
212 if (assert)
213 {
214 direction = "low";
Jason M. Bills60ec28a2019-04-11 16:53:44 -0700215 redfishMessageID += ".SensorThresholdCriticalLowGoingLow";
Jason M. Bills2b9704d2018-11-02 13:12:09 -0700216 }
217 else
218 {
219 direction = "high";
Jason M. Bills60ec28a2019-04-11 16:53:44 -0700220 redfishMessageID += ".SensorThresholdCriticalLowGoingHigh";
Jason M. Bills2b9704d2018-11-02 13:12:09 -0700221 }
222 }
223 else if (event == "WarningLow")
224 {
225 threshold = "warning low";
226 if (assert)
227 {
228 direction = "low";
Jason M. Bills60ec28a2019-04-11 16:53:44 -0700229 redfishMessageID += ".SensorThresholdWarningLowGoingLow";
Jason M. Bills2b9704d2018-11-02 13:12:09 -0700230 }
231 else
232 {
233 direction = "high";
Jason M. Bills60ec28a2019-04-11 16:53:44 -0700234 redfishMessageID += ".SensorThresholdWarningLowGoingHigh";
Jason M. Bills2b9704d2018-11-02 13:12:09 -0700235 }
236 }
237 else if (event == "WarningHigh")
238 {
239 threshold = "warning high";
240 if (assert)
241 {
242 direction = "high";
Jason M. Bills60ec28a2019-04-11 16:53:44 -0700243 redfishMessageID += ".SensorThresholdWarningHighGoingHigh";
Jason M. Bills2b9704d2018-11-02 13:12:09 -0700244 }
245 else
246 {
247 direction = "low";
Jason M. Bills60ec28a2019-04-11 16:53:44 -0700248 redfishMessageID += ".SensorThresholdWarningHighGoingLow";
Jason M. Bills2b9704d2018-11-02 13:12:09 -0700249 }
250 }
251 else if (event == "CriticalHigh")
252 {
253 threshold = "critical high";
254 if (assert)
255 {
256 direction = "high";
Jason M. Bills60ec28a2019-04-11 16:53:44 -0700257 redfishMessageID += ".SensorThresholdCriticalHighGoingHigh";
Jason M. Bills2b9704d2018-11-02 13:12:09 -0700258 }
259 else
260 {
261 direction = "low";
Jason M. Bills60ec28a2019-04-11 16:53:44 -0700262 redfishMessageID += ".SensorThresholdCriticalHighGoingLow";
Jason M. Bills2b9704d2018-11-02 13:12:09 -0700263 }
264 }
265
266 std::string journalMsg(std::string(sensorName) + " sensor crossed a " +
267 threshold + " threshold going " + direction +
Zhikui Ren25b26e12020-06-26 20:18:19 -0700268 ". Reading=" + std::to_string(assertValue) +
Jason M. Bills2b9704d2018-11-02 13:12:09 -0700269 " Threshold=" + std::to_string(thresholdVal) +
270 ".");
Jason M. Bills5e049d32018-10-19 12:59:38 -0700271
Jason M. Bills5ff505f2019-04-11 16:58:01 -0700272 selAddSystemRecord(
273 journalMsg, std::string(msg.get_path()), eventData, assert,
274 selBMCGenID, "REDFISH_MESSAGE_ID=%s", redfishMessageID.c_str(),
275 "REDFISH_MESSAGE_ARGS=%.*s,%f,%f", sensorName.length(),
Zhikui Ren25b26e12020-06-26 20:18:19 -0700276 sensorName.data(), assertValue, thresholdVal);
Jason M. Bills5e049d32018-10-19 12:59:38 -0700277 };
Zhikui Ren25b26e12020-06-26 20:18:19 -0700278 sdbusplus::bus::match::match thresholdAssertMatcher(
Zhikui Ren672bdfc2020-07-14 11:37:01 -0700279 static_cast<sdbusplus::bus::bus&>(*conn),
Zhikui Ren25b26e12020-06-26 20:18:19 -0700280 "type='signal', member='ThresholdAsserted'",
281 std::move(thresholdAssertMatcherCallback));
282 return thresholdAssertMatcher;
Jason M. Bills5e049d32018-10-19 12:59:38 -0700283}