blob: de3a8671c2818d6f69aaf68f108a20ae939e5b47 [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>
20
21enum class thresholdEventOffsets : uint8_t
22{
23 lowerNonCritGoingLow = 0x00,
24 lowerCritGoingLow = 0x02,
25 upperNonCritGoingHigh = 0x07,
26 upperCritGoingHigh = 0x09,
27};
28
29static constexpr const uint8_t thresholdEventDataTriggerReadingByte2 = (1 << 6);
30static constexpr const uint8_t thresholdEventDataTriggerReadingByte3 = (1 << 4);
31
32inline static sdbusplus::bus::match::match startThresholdEventMonitor(
33 std::shared_ptr<sdbusplus::asio::connection> conn)
34{
35 auto thresholdEventMatcherCallback = [conn](
36 sdbusplus::message::message &msg) {
37 // This static set of std::pair<path, event> tracks asserted events to
38 // avoid duplicate logs or deasserts logged without an assert
39 static boost::container::flat_set<std::pair<std::string, std::string>>
40 assertedEvents;
41 // SEL event data is three bytes where 0xFF means unspecified
42 std::vector<uint8_t> eventData(selEvtDataMaxSize, 0xFF);
43
44 // Get the event type and assertion details from the message
45 std::string thresholdInterface;
46 boost::container::flat_map<std::string,
47 sdbusplus::message::variant<bool>>
48 propertiesChanged;
49 msg.read(thresholdInterface, propertiesChanged);
50 std::string event = propertiesChanged.begin()->first;
51 bool *pval = sdbusplus::message::variant_ns::get_if<bool>(
52 &propertiesChanged.begin()->second);
53 if (!pval)
54 {
55 std::cerr << "threshold event direction has invalid type\n";
56 return;
57 }
58 bool assert = *pval;
59
60 // Check the asserted events to determine if we should log this event
61 std::pair<std::string, std::string> pathAndEvent(
62 std::string(msg.get_path()), event);
63 if (assert)
64 {
65 // For asserts, add the event to the set and only log it if it's new
66 if (assertedEvents.insert(pathAndEvent).second == false)
67 {
68 // event is already in the set
69 return;
70 }
71 }
72 else
73 {
74 // For deasserts, remove the event and only log the deassert if it
75 // was asserted
76 if (assertedEvents.erase(pathAndEvent) == 0)
77 {
78 // asserted event was not in the set
79 return;
80 }
81 }
82
83 // Set the IPMI threshold event type based on the event details from the
84 // message
85 if (event == "CriticalAlarmLow")
86 {
87 eventData[0] =
88 static_cast<uint8_t>(thresholdEventOffsets::lowerCritGoingLow);
89 }
90 else if (event == "WarningAlarmLow")
91 {
92 eventData[0] = static_cast<uint8_t>(
93 thresholdEventOffsets::lowerNonCritGoingLow);
94 }
95 else if (event == "WarningAlarmHigh")
96 {
97 eventData[0] = static_cast<uint8_t>(
98 thresholdEventOffsets::upperNonCritGoingHigh);
99 }
100 else if (event == "CriticalAlarmHigh")
101 {
102 eventData[0] =
103 static_cast<uint8_t>(thresholdEventOffsets::upperCritGoingHigh);
104 }
105 // Indicate that bytes 2 and 3 are threshold sensor trigger values
106 eventData[0] |= thresholdEventDataTriggerReadingByte2 |
107 thresholdEventDataTriggerReadingByte3;
108
109 // Get the sensor reading to put in the event data
110 sdbusplus::message::message getSensorValue =
111 conn->new_method_call(msg.get_sender(), msg.get_path(),
112 "org.freedesktop.DBus.Properties", "GetAll");
113 getSensorValue.append("xyz.openbmc_project.Sensor.Value");
114 boost::container::flat_map<std::string,
115 sdbusplus::message::variant<double>>
116 sensorValue;
117 try
118 {
119 sdbusplus::message::message getSensorValueResp =
120 conn->call(getSensorValue);
121 getSensorValueResp.read(sensorValue);
122 }
123 catch (sdbusplus::exception_t &)
124 {
125 std::cerr << "error getting sensor value from " << msg.get_path()
126 << "\n";
127 return;
128 }
129 double max = sdbusplus::message::variant_ns::visit(
130 ipmi::VariantToDoubleVisitor(), sensorValue["MaxValue"]);
131 double min = sdbusplus::message::variant_ns::visit(
132 ipmi::VariantToDoubleVisitor(), sensorValue["MinValue"]);
133 double sensorVal = sdbusplus::message::variant_ns::visit(
134 ipmi::VariantToDoubleVisitor(), sensorValue["Value"]);
135 try
136 {
137 eventData[1] = ipmi::getScaledIPMIValue(sensorVal, max, min);
138 }
139 catch (std::runtime_error &e)
140 {
141 std::cerr << e.what();
142 eventData[1] = 0xFF;
143 }
144
145 // Get the threshold value to put in the event data
146 // Get the threshold parameter by removing the "Alarm" text from the
147 // event string
148 std::string alarm("Alarm");
149 if (std::string::size_type pos = event.find(alarm);
150 pos != std::string::npos)
151 {
152 event.erase(pos, alarm.length());
153 }
154 sdbusplus::message::message getThreshold =
155 conn->new_method_call(msg.get_sender(), msg.get_path(),
156 "org.freedesktop.DBus.Properties", "Get");
157 getThreshold.append(thresholdInterface, event);
158 sdbusplus::message::variant<double> thresholdValue;
159 try
160 {
161 sdbusplus::message::message getThresholdResp =
162 conn->call(getThreshold);
163 getThresholdResp.read(thresholdValue);
164 }
165 catch (sdbusplus::exception_t &)
166 {
167 std::cerr << "error getting sensor threshold from "
168 << msg.get_path() << "\n";
169 return;
170 }
171 double thresholdVal = sdbusplus::message::variant_ns::visit(
172 ipmi::VariantToDoubleVisitor(), thresholdValue);
173 try
174 {
175 eventData[2] = ipmi::getScaledIPMIValue(thresholdVal, max, min);
176 }
177 catch (std::runtime_error &e)
178 {
179 std::cerr << e.what();
180 eventData[2] = 0xFF;
181 }
182
183 // Construct a human-readable message of this event for the log
184 std::experimental::string_view sensorName(msg.get_path());
185 sensorName.remove_prefix(
186 std::min(sensorName.find_last_of("/") + 1, sensorName.size()));
187 std::string journalMsg(sensorName.to_string() +
188 (assert ? " asserted " : " deasserted ") +
189 propertiesChanged.begin()->first +
190 ". Reading=" + std::to_string(sensorVal) +
191 " Threshold=" + std::to_string(thresholdVal));
192
193 selAddSystemRecord(journalMsg, std::string(msg.get_path()), eventData,
194 assert);
195 };
196 sdbusplus::bus::match::match thresholdEventMatcher(
197 static_cast<sdbusplus::bus::bus &>(*conn),
198 "type='signal',interface='org.freedesktop.DBus.Properties',member='"
199 "PropertiesChanged',arg0namespace='xyz.openbmc_project.Sensor."
200 "Threshold'",
201 std::move(thresholdEventMatcherCallback));
202 return thresholdEventMatcher;
203}