blob: 9b942f28a246f5fd6f20ca4b99ecd25f1b21c5d1 [file] [log] [blame]
George Hung486e42e2021-04-14 20:20:42 +08001/*
2// Copyright (c) 2021 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 <boost/container/flat_map.hpp>
19#include <sel_logger.hpp>
20#include <sensorutils.hpp>
21
22#include <map>
23#include <string_view>
24#include <variant>
25
26using sdbusMatch = std::shared_ptr<sdbusplus::bus::match::match>;
27static sdbusMatch warningLowAssertedMatcher;
28static sdbusMatch warningLowDeassertedMatcher;
29static sdbusMatch warningHighAssertedMatcher;
30static sdbusMatch warningHighDeassertedMatcher;
31static sdbusMatch criticalLowAssertedMatcher;
32static sdbusMatch criticalLowDeassertedMatcher;
33static sdbusMatch criticalHighAssertedMatcher;
34static sdbusMatch criticalHighDeassertedMatcher;
35
36static boost::container::flat_map<std::string, sdbusMatch> matchers = {
37 {"WarningLowAlarmAsserted", warningLowAssertedMatcher},
38 {"WarningLowAlarmDeasserted", warningLowDeassertedMatcher},
39 {"WarningHighAlarmAsserted", warningHighAssertedMatcher},
40 {"WarningHighAlarmDeasserted", warningHighDeassertedMatcher},
41 {"CriticalLowAlarmAsserted", criticalLowAssertedMatcher},
42 {"CriticalLowAlarmDeasserted", criticalLowDeassertedMatcher},
43 {"CriticalHighAlarmAsserted", criticalHighAssertedMatcher},
44 {"CriticalHighAlarmDeasserted", criticalHighDeassertedMatcher}};
45
46void generateEvent(std::string signalName,
47 std::shared_ptr<sdbusplus::asio::connection> conn,
48 sdbusplus::message::message& msg)
49{
50 double assertValue;
51 try
52 {
53 msg.read(assertValue);
54 }
55 catch (sdbusplus::exception_t&)
56 {
57 std::cerr << "error getting assert signal data from " << msg.get_path()
58 << "\n";
59 return;
60 }
61
62 std::string event;
63 std::string thresholdInterface;
64 std::string threshold;
65 std::string direction;
66 bool assert = false;
67 std::vector<uint8_t> eventData(selEvtDataMaxSize, selEvtDataUnspecified);
68 std::string redfishMessageID = "OpenBMC." + openBMCMessageRegistryVersion;
69
70 if (signalName == "WarningLowAlarmAsserted" ||
71 signalName == "WarningLowAlarmDeasserted")
72 {
73 event = "WarningLow";
74 thresholdInterface = "xyz.openbmc_project.Sensor.Threshold.Warning";
75 eventData[0] =
76 static_cast<uint8_t>(thresholdEventOffsets::lowerNonCritGoingLow);
77 threshold = "warning low";
78 if (signalName == "WarningLowAlarmAsserted")
79 {
80 assert = true;
81 direction = "low";
82 redfishMessageID += ".SensorThresholdWarningLowGoingLow";
83 }
84 else if (signalName == "WarningLowAlarmDeasserted")
85 {
86 direction = "high";
87 redfishMessageID += ".SensorThresholdWarningLowGoingHigh";
88 }
89 }
90 else if (signalName == "WarningHighAlarmAsserted" ||
91 signalName == "WarningHighAlarmDeasserted")
92 {
93 event = "WarningHigh";
94 thresholdInterface = "xyz.openbmc_project.Sensor.Threshold.Warning";
95 eventData[0] =
96 static_cast<uint8_t>(thresholdEventOffsets::upperNonCritGoingHigh);
97 threshold = "warning high";
98 if (signalName == "WarningHighAlarmAsserted")
99 {
100 assert = true;
101 direction = "high";
102 redfishMessageID += ".SensorThresholdWarningHighGoingHigh";
103 }
104 else if (signalName == "WarningHighAlarmDeasserted")
105 {
106 direction = "low";
107 redfishMessageID += ".SensorThresholdWarningHighGoingLow";
108 }
109 }
110 else if (signalName == "CriticalLowAlarmAsserted" ||
111 signalName == "CriticalLowAlarmDeasserted")
112 {
113 event = "CriticalLow";
114 thresholdInterface = "xyz.openbmc_project.Sensor.Threshold.Critical";
115 eventData[0] =
116 static_cast<uint8_t>(thresholdEventOffsets::lowerCritGoingLow);
117 threshold = "critical low";
118 if (signalName == "CriticalLowAlarmAsserted")
119 {
120 assert = true;
121 direction = "low";
122 redfishMessageID += ".SensorThresholdCriticalLowGoingLow";
123 }
124 else if (signalName == "CriticalLowAlarmDeasserted")
125 {
126 direction = "high";
127 redfishMessageID += ".SensorThresholdCriticalLowGoingHigh";
128 }
129 }
130 else if (signalName == "CriticalHighAlarmAsserted" ||
131 signalName == "CriticalHighAlarmDeasserted")
132 {
133 event = "CriticalHigh";
134 thresholdInterface = "xyz.openbmc_project.Sensor.Threshold.Critical";
135 eventData[0] =
136 static_cast<uint8_t>(thresholdEventOffsets::upperCritGoingHigh);
137 threshold = "critical high";
138 if (signalName == "CriticalHighAlarmAsserted")
139 {
140 assert = true;
141 direction = "high";
142 redfishMessageID += ".SensorThresholdCriticalHighGoingHigh";
143 }
144 else if (signalName == "CriticalHighAlarmDeasserted")
145 {
146 direction = "low";
147 redfishMessageID += ".SensorThresholdCriticalHighGoingLow";
148 }
149 }
150 // Indicate that bytes 2 and 3 are threshold sensor trigger values
151 eventData[0] |= thresholdEventDataTriggerReadingByte2 |
152 thresholdEventDataTriggerReadingByte3;
153
154 // Get the sensor reading to put in the event data
155 sdbusplus::message::message getSensorValue =
156 conn->new_method_call(msg.get_sender(), msg.get_path(),
157 "org.freedesktop.DBus.Properties", "GetAll");
158 getSensorValue.append("xyz.openbmc_project.Sensor.Value");
159 boost::container::flat_map<std::string, std::variant<double, int64_t>>
160 sensorValue;
161 try
162 {
163 sdbusplus::message::message getSensorValueResp =
164 conn->call(getSensorValue);
165 getSensorValueResp.read(sensorValue);
166 }
167 catch (sdbusplus::exception_t&)
168 {
169 std::cerr << "error getting sensor value from " << msg.get_path()
170 << "\n";
171 return;
172 }
173 double max = 0;
174 auto findMax = sensorValue.find("MaxValue");
175 if (findMax != sensorValue.end())
176 {
177 max = std::visit(ipmi::VariantToDoubleVisitor(), findMax->second);
178 }
179 double min = 0;
180 auto findMin = sensorValue.find("MinValue");
181 if (findMin != sensorValue.end())
182 {
183 min = std::visit(ipmi::VariantToDoubleVisitor(), findMin->second);
184 }
185
186 try
187 {
188 eventData[1] = ipmi::getScaledIPMIValue(assertValue, max, min);
189 }
190 catch (const std::exception& e)
191 {
192 std::cerr << e.what();
193 eventData[1] = selEvtDataUnspecified;
194 }
195
196 // Get the threshold value to put in the event data
197 sdbusplus::message::message getThreshold =
198 conn->new_method_call(msg.get_sender(), msg.get_path(),
199 "org.freedesktop.DBus.Properties", "Get");
200 getThreshold.append(thresholdInterface, event);
201 std::variant<double, int64_t> thresholdValue;
202 try
203 {
204 sdbusplus::message::message getThresholdResp = conn->call(getThreshold);
205 getThresholdResp.read(thresholdValue);
206 }
207 catch (sdbusplus::exception_t&)
208 {
209 std::cerr << "error getting sensor threshold from " << msg.get_path()
210 << "\n";
211 return;
212 }
213 double thresholdVal =
214 std::visit(ipmi::VariantToDoubleVisitor(), thresholdValue);
215
216 double scale = 0;
217 auto findScale = sensorValue.find("Scale");
218 if (findScale != sensorValue.end())
219 {
220 scale = std::visit(ipmi::VariantToDoubleVisitor(), findScale->second);
221 thresholdVal *= std::pow(10, scale);
222 }
223 try
224 {
225 eventData[2] = ipmi::getScaledIPMIValue(thresholdVal, max, min);
226 }
227 catch (const std::exception& e)
228 {
229 std::cerr << e.what();
230 eventData[2] = selEvtDataUnspecified;
231 }
232
233 std::string_view sensorName(msg.get_path());
234 sensorName.remove_prefix(
235 std::min(sensorName.find_last_of("/") + 1, sensorName.size()));
236
237 std::string journalMsg(std::string(sensorName) + " sensor crossed a " +
238 threshold + " threshold going " + direction +
239 ". Reading=" + std::to_string(assertValue) +
240 " Threshold=" + std::to_string(thresholdVal) + ".");
241
242 selAddSystemRecord(journalMsg, std::string(msg.get_path()), eventData,
243 assert, selBMCGenID, "REDFISH_MESSAGE_ID=%s",
244 redfishMessageID.c_str(),
245 "REDFISH_MESSAGE_ARGS=%.*s,%f,%f", sensorName.length(),
246 sensorName.data(), assertValue, thresholdVal);
247}
248
249inline static void startThresholdAlarmMonitor(
250 std::shared_ptr<sdbusplus::asio::connection> conn)
251{
252 for (auto iter = matchers.begin(); iter != matchers.end(); iter++)
253 {
254 iter->second = std::make_shared<sdbusplus::bus::match::match>(
255 static_cast<sdbusplus::bus::bus&>(*conn),
256 "type='signal',member=" + iter->first,
257 [conn, iter](sdbusplus::message::message& msg) {
258 generateEvent(iter->first, conn, msg);
259 });
260 }
261}