blob: 93528057fdc54ab30a92292d0b51456460b48353 [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>
Jason M. Bills2b9704d2018-11-02 13:12:09 -070020#include <string_view>
Jason M. Bills5e049d32018-10-19 12:59:38 -070021
22enum class thresholdEventOffsets : uint8_t
23{
24 lowerNonCritGoingLow = 0x00,
25 lowerCritGoingLow = 0x02,
26 upperNonCritGoingHigh = 0x07,
27 upperCritGoingHigh = 0x09,
28};
29
30static constexpr const uint8_t thresholdEventDataTriggerReadingByte2 = (1 << 6);
31static constexpr const uint8_t thresholdEventDataTriggerReadingByte3 = (1 << 4);
32
Jason M. Bills2b9704d2018-11-02 13:12:09 -070033static const std::string openBMCMessageRegistryVersion("0.1");
34
Jason M. Bills5e049d32018-10-19 12:59:38 -070035inline static sdbusplus::bus::match::match startThresholdEventMonitor(
36 std::shared_ptr<sdbusplus::asio::connection> conn)
37{
38 auto thresholdEventMatcherCallback = [conn](
39 sdbusplus::message::message &msg) {
40 // This static set of std::pair<path, event> tracks asserted events to
41 // avoid duplicate logs or deasserts logged without an assert
42 static boost::container::flat_set<std::pair<std::string, std::string>>
43 assertedEvents;
44 // SEL event data is three bytes where 0xFF means unspecified
45 std::vector<uint8_t> eventData(selEvtDataMaxSize, 0xFF);
46
47 // Get the event type and assertion details from the message
48 std::string thresholdInterface;
49 boost::container::flat_map<std::string,
50 sdbusplus::message::variant<bool>>
51 propertiesChanged;
52 msg.read(thresholdInterface, propertiesChanged);
53 std::string event = propertiesChanged.begin()->first;
54 bool *pval = sdbusplus::message::variant_ns::get_if<bool>(
55 &propertiesChanged.begin()->second);
56 if (!pval)
57 {
58 std::cerr << "threshold event direction has invalid type\n";
59 return;
60 }
61 bool assert = *pval;
62
63 // Check the asserted events to determine if we should log this event
64 std::pair<std::string, std::string> pathAndEvent(
65 std::string(msg.get_path()), event);
66 if (assert)
67 {
68 // For asserts, add the event to the set and only log it if it's new
69 if (assertedEvents.insert(pathAndEvent).second == false)
70 {
71 // event is already in the set
72 return;
73 }
74 }
75 else
76 {
77 // For deasserts, remove the event and only log the deassert if it
78 // was asserted
79 if (assertedEvents.erase(pathAndEvent) == 0)
80 {
81 // asserted event was not in the set
82 return;
83 }
84 }
85
86 // Set the IPMI threshold event type based on the event details from the
87 // message
88 if (event == "CriticalAlarmLow")
89 {
90 eventData[0] =
91 static_cast<uint8_t>(thresholdEventOffsets::lowerCritGoingLow);
92 }
93 else if (event == "WarningAlarmLow")
94 {
95 eventData[0] = static_cast<uint8_t>(
96 thresholdEventOffsets::lowerNonCritGoingLow);
97 }
98 else if (event == "WarningAlarmHigh")
99 {
100 eventData[0] = static_cast<uint8_t>(
101 thresholdEventOffsets::upperNonCritGoingHigh);
102 }
103 else if (event == "CriticalAlarmHigh")
104 {
105 eventData[0] =
106 static_cast<uint8_t>(thresholdEventOffsets::upperCritGoingHigh);
107 }
108 // Indicate that bytes 2 and 3 are threshold sensor trigger values
109 eventData[0] |= thresholdEventDataTriggerReadingByte2 |
110 thresholdEventDataTriggerReadingByte3;
111
112 // Get the sensor reading to put in the event data
113 sdbusplus::message::message getSensorValue =
114 conn->new_method_call(msg.get_sender(), msg.get_path(),
115 "org.freedesktop.DBus.Properties", "GetAll");
116 getSensorValue.append("xyz.openbmc_project.Sensor.Value");
117 boost::container::flat_map<std::string,
118 sdbusplus::message::variant<double>>
119 sensorValue;
120 try
121 {
122 sdbusplus::message::message getSensorValueResp =
123 conn->call(getSensorValue);
124 getSensorValueResp.read(sensorValue);
125 }
126 catch (sdbusplus::exception_t &)
127 {
128 std::cerr << "error getting sensor value from " << msg.get_path()
129 << "\n";
130 return;
131 }
132 double max = sdbusplus::message::variant_ns::visit(
133 ipmi::VariantToDoubleVisitor(), sensorValue["MaxValue"]);
134 double min = sdbusplus::message::variant_ns::visit(
135 ipmi::VariantToDoubleVisitor(), sensorValue["MinValue"]);
136 double sensorVal = sdbusplus::message::variant_ns::visit(
137 ipmi::VariantToDoubleVisitor(), sensorValue["Value"]);
138 try
139 {
140 eventData[1] = ipmi::getScaledIPMIValue(sensorVal, max, min);
141 }
142 catch (std::runtime_error &e)
143 {
144 std::cerr << e.what();
145 eventData[1] = 0xFF;
146 }
147
148 // Get the threshold value to put in the event data
149 // Get the threshold parameter by removing the "Alarm" text from the
150 // event string
151 std::string alarm("Alarm");
152 if (std::string::size_type pos = event.find(alarm);
153 pos != std::string::npos)
154 {
155 event.erase(pos, alarm.length());
156 }
157 sdbusplus::message::message getThreshold =
158 conn->new_method_call(msg.get_sender(), msg.get_path(),
159 "org.freedesktop.DBus.Properties", "Get");
160 getThreshold.append(thresholdInterface, event);
161 sdbusplus::message::variant<double> thresholdValue;
162 try
163 {
164 sdbusplus::message::message getThresholdResp =
165 conn->call(getThreshold);
166 getThresholdResp.read(thresholdValue);
167 }
168 catch (sdbusplus::exception_t &)
169 {
170 std::cerr << "error getting sensor threshold from "
171 << msg.get_path() << "\n";
172 return;
173 }
174 double thresholdVal = sdbusplus::message::variant_ns::visit(
175 ipmi::VariantToDoubleVisitor(), thresholdValue);
176 try
177 {
178 eventData[2] = ipmi::getScaledIPMIValue(thresholdVal, max, min);
179 }
180 catch (std::runtime_error &e)
181 {
182 std::cerr << e.what();
183 eventData[2] = 0xFF;
184 }
185
186 // Construct a human-readable message of this event for the log
Jason M. Bills2b9704d2018-11-02 13:12:09 -0700187 std::string_view sensorName(msg.get_path());
Jason M. Bills5e049d32018-10-19 12:59:38 -0700188 sensorName.remove_prefix(
189 std::min(sensorName.find_last_of("/") + 1, sensorName.size()));
Jason M. Bills2b9704d2018-11-02 13:12:09 -0700190
191 std::string threshold;
192 std::string direction;
193 std::string redfishMessageID;
194 if (event == "CriticalLow")
195 {
196 threshold = "critical low";
197 if (assert)
198 {
199 direction = "low";
200 redfishMessageID = "OpenBMC." + openBMCMessageRegistryVersion +
201 ".SensorThresholdCriticalLowGoingLow";
202 }
203 else
204 {
205 direction = "high";
206 redfishMessageID = "OpenBMC." + openBMCMessageRegistryVersion +
207 ".SensorThresholdCriticalLowGoingHigh";
208 }
209 }
210 else if (event == "WarningLow")
211 {
212 threshold = "warning low";
213 if (assert)
214 {
215 direction = "low";
216 redfishMessageID = "OpenBMC." + openBMCMessageRegistryVersion +
217 ".SensorThresholdWarningLowGoingLow";
218 }
219 else
220 {
221 direction = "high";
222 redfishMessageID = "OpenBMC." + openBMCMessageRegistryVersion +
223 ".SensorThresholdWarningLowGoingHigh";
224 }
225 }
226 else if (event == "WarningHigh")
227 {
228 threshold = "warning high";
229 if (assert)
230 {
231 direction = "high";
232 redfishMessageID = "OpenBMC." + openBMCMessageRegistryVersion +
233 ".SensorThresholdWarningHighGoingHigh";
234 }
235 else
236 {
237 direction = "low";
238 redfishMessageID = "OpenBMC." + openBMCMessageRegistryVersion +
239 ".SensorThresholdWarningHighGoingLow";
240 }
241 }
242 else if (event == "CriticalHigh")
243 {
244 threshold = "critical high";
245 if (assert)
246 {
247 direction = "high";
248 redfishMessageID = "OpenBMC." + openBMCMessageRegistryVersion +
249 ".SensorThresholdCriticalHighGoingHigh";
250 }
251 else
252 {
253 direction = "low";
254 redfishMessageID = "OpenBMC." + openBMCMessageRegistryVersion +
255 ".SensorThresholdCriticalHighGoingLow";
256 }
257 }
258
259 std::string journalMsg(std::string(sensorName) + " sensor crossed a " +
260 threshold + " threshold going " + direction +
Jason M. Bills5e049d32018-10-19 12:59:38 -0700261 ". Reading=" + std::to_string(sensorVal) +
Jason M. Bills2b9704d2018-11-02 13:12:09 -0700262 " Threshold=" + std::to_string(thresholdVal) +
263 ".");
Jason M. Bills5e049d32018-10-19 12:59:38 -0700264
265 selAddSystemRecord(journalMsg, std::string(msg.get_path()), eventData,
Jason M. Bills2b9704d2018-11-02 13:12:09 -0700266 assert, selBMCGenID, "REDFISH_MESSAGE_ID=%.*s",
267 redfishMessageID.length(), redfishMessageID.data(),
268 "REDFISH_MESSAGE_ARG_1=%.*s", sensorName.length(),
269 sensorName.data(), "REDFISH_MESSAGE_ARG_2=%f",
270 sensorVal, "REDFISH_MESSAGE_ARG_3=%f", thresholdVal);
Jason M. Bills5e049d32018-10-19 12:59:38 -0700271 };
272 sdbusplus::bus::match::match thresholdEventMatcher(
273 static_cast<sdbusplus::bus::bus &>(*conn),
274 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
275 "PropertiesChanged',arg0namespace='xyz.openbmc_project.Sensor."
276 "Threshold'",
277 std::move(thresholdEventMatcherCallback));
278 return thresholdEventMatcher;
279}