blob: 0d1182dfcda6182647e286095acada02794f2601 [file] [log] [blame]
Patrick Venture3a5071a2018-09-12 13:27:42 -07001#include "sensordatahandler.hpp"
2
3#include "sensorhandler.hpp"
Patrick Venture3a5071a2018-09-12 13:27:42 -07004
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -05005#include <bitset>
Vernon Mauerybdda8002019-02-26 10:18:51 -08006#include <filesystem>
Vernon Mauery33250242019-03-12 16:49:26 -07007#include <ipmid/types.hpp>
Vernon Mauery6a98fe72019-03-11 15:57:48 -07008#include <ipmid/utils.hpp>
William A. Kennington III4c008022018-10-12 17:18:14 -07009#include <optional>
Patrick Venture3a5071a2018-09-12 13:27:42 -070010#include <phosphor-logging/elog-errors.hpp>
11#include <phosphor-logging/log.hpp>
William A. Kennington III4c008022018-10-12 17:18:14 -070012#include <sdbusplus/message/types.hpp>
Patrick Venture3a5071a2018-09-12 13:27:42 -070013#include <xyz/openbmc_project/Common/error.hpp>
14
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -050015namespace ipmi
16{
17namespace sensor
18{
19
20using namespace phosphor::logging;
21using InternalFailure =
22 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
23
24static constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
25static constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
26static constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
27
28/** @brief get the D-Bus service and service path
29 * @param[in] bus - The Dbus bus object
30 * @param[in] interface - interface to the service
31 * @param[in] path - interested path in the list of objects
32 * @return pair of service path and service
33 */
34ServicePath getServiceAndPath(sdbusplus::bus::bus& bus,
35 const std::string& interface,
36 const std::string& path)
37{
38 auto depth = 0;
Patrick Venture0b02be92018-08-31 11:55:55 -070039 auto mapperCall = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
40 MAPPER_INTERFACE, "GetSubTree");
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -050041 mapperCall.append("/");
42 mapperCall.append(depth);
43 mapperCall.append(std::vector<Interface>({interface}));
44
45 auto mapperResponseMsg = bus.call(mapperCall);
46 if (mapperResponseMsg.is_method_error())
47 {
Dhruvaraj Subhashchandran18e99992017-08-09 09:10:47 -050048 log<level::ERR>("Mapper GetSubTree failed",
Joseph Reynolds510eb9c2018-05-30 11:51:28 -050049 entry("PATH=%s", path.c_str()),
50 entry("INTERFACE=%s", interface.c_str()));
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -050051 elog<InternalFailure>();
52 }
53
54 MapperResponseType mapperResponse;
55 mapperResponseMsg.read(mapperResponse);
56 if (mapperResponse.empty())
57 {
Dhruvaraj Subhashchandran18e99992017-08-09 09:10:47 -050058 log<level::ERR>("Invalid mapper response",
Joseph Reynolds510eb9c2018-05-30 11:51:28 -050059 entry("PATH=%s", path.c_str()),
60 entry("INTERFACE=%s", interface.c_str()));
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -050061 elog<InternalFailure>();
62 }
63
64 if (path.empty())
65 {
Patrick Venture0b02be92018-08-31 11:55:55 -070066 // Get the first one if the path is not in list.
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -050067 return std::make_pair(mapperResponse.begin()->first,
68 mapperResponse.begin()->second.begin()->first);
69 }
70 const auto& iter = mapperResponse.find(path);
71 if (iter == mapperResponse.end())
72 {
Gunnar Millsc9fa69e2018-04-08 16:35:25 -050073 log<level::ERR>("Couldn't find D-Bus path",
Joseph Reynolds510eb9c2018-05-30 11:51:28 -050074 entry("PATH=%s", path.c_str()),
75 entry("INTERFACE=%s", interface.c_str()));
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -050076 elog<InternalFailure>();
77 }
78 return std::make_pair(iter->first, iter->second.begin()->first);
79}
80
81AssertionSet getAssertionSet(const SetSensorReadingReq& cmdData)
82{
83 Assertion assertionStates =
84 (static_cast<Assertion>(cmdData.assertOffset8_14)) << 8 |
85 cmdData.assertOffset0_7;
86 Deassertion deassertionStates =
87 (static_cast<Deassertion>(cmdData.deassertOffset8_14)) << 8 |
88 cmdData.deassertOffset0_7;
89 return std::make_pair(assertionStates, deassertionStates);
90}
91
92ipmi_ret_t updateToDbus(IpmiUpdateData& msg)
93{
94 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
95 try
96 {
97 auto serviceResponseMsg = bus.call(msg);
98 if (serviceResponseMsg.is_method_error())
99 {
100 log<level::ERR>("Error in D-Bus call");
101 return IPMI_CC_UNSPECIFIED_ERROR;
102 }
103 }
104 catch (InternalFailure& e)
105 {
106 commit<InternalFailure>();
107 return IPMI_CC_UNSPECIFIED_ERROR;
108 }
109 return IPMI_CC_OK;
110}
111
Tom Joseph816e92b2017-09-06 19:23:00 +0530112namespace get
113{
114
Tom Josephb0adbcd2018-01-24 11:51:29 +0530115SensorName nameParentLeaf(const Info& sensorInfo)
116{
117 const auto pos = sensorInfo.sensorPath.find_last_of('/');
118 const auto leaf = sensorInfo.sensorPath.substr(pos + 1);
119
120 const auto remaining = sensorInfo.sensorPath.substr(0, pos);
121
122 const auto parentPos = remaining.find_last_of('/');
123 auto parent = remaining.substr(parentPos + 1);
124
125 parent += "_" + leaf;
126 return parent;
127}
128
Tom Joseph816e92b2017-09-06 19:23:00 +0530129GetSensorResponse mapDbusToAssertion(const Info& sensorInfo,
130 const InstancePath& path,
131 const DbusInterface& interface)
132{
133 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Patrick Venture0b02be92018-08-31 11:55:55 -0700134 GetSensorResponse response{};
Tom Joseph816e92b2017-09-06 19:23:00 +0530135
136 auto service = ipmi::getService(bus, interface, path);
137
138 const auto& interfaceList = sensorInfo.propertyInterfaces;
139
140 for (const auto& interface : interfaceList)
141 {
142 for (const auto& property : interface.second)
143 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700144 auto propValue = ipmi::getDbusProperty(
145 bus, service, path, interface.first, property.first);
Tom Joseph816e92b2017-09-06 19:23:00 +0530146
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500147 for (const auto& value : std::get<OffsetValueMap>(property.second))
Tom Joseph816e92b2017-09-06 19:23:00 +0530148 {
149 if (propValue == value.second.assert)
150 {
Sui Chen4cc42552019-09-11 10:28:35 -0700151 setOffset(value.first, &response);
Tom Joseph816e92b2017-09-06 19:23:00 +0530152 break;
153 }
Tom Joseph816e92b2017-09-06 19:23:00 +0530154 }
155 }
156 }
157
158 return response;
159}
160
161GetSensorResponse assertion(const Info& sensorInfo)
162{
Patrick Venture0b02be92018-08-31 11:55:55 -0700163 return mapDbusToAssertion(sensorInfo, sensorInfo.sensorPath,
Tom Joseph816e92b2017-09-06 19:23:00 +0530164 sensorInfo.sensorInterface);
165}
166
Tom Josephe4014fc2017-09-06 23:57:36 +0530167GetSensorResponse eventdata2(const Info& sensorInfo)
168{
169 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Patrick Venture0b02be92018-08-31 11:55:55 -0700170 GetSensorResponse response{};
Tom Josephe4014fc2017-09-06 23:57:36 +0530171
Patrick Venture0b02be92018-08-31 11:55:55 -0700172 auto service = ipmi::getService(bus, sensorInfo.sensorInterface,
Tom Josephe4014fc2017-09-06 23:57:36 +0530173 sensorInfo.sensorPath);
174
175 const auto& interfaceList = sensorInfo.propertyInterfaces;
176
177 for (const auto& interface : interfaceList)
178 {
179 for (const auto& property : interface.second)
180 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700181 auto propValue =
182 ipmi::getDbusProperty(bus, service, sensorInfo.sensorPath,
183 interface.first, property.first);
Tom Josephe4014fc2017-09-06 23:57:36 +0530184
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500185 for (const auto& value : std::get<OffsetValueMap>(property.second))
Tom Josephe4014fc2017-09-06 23:57:36 +0530186 {
187 if (propValue == value.second.assert)
188 {
Sui Chen4cc42552019-09-11 10:28:35 -0700189 setReading(value.first, &response);
Tom Josephe4014fc2017-09-06 23:57:36 +0530190 break;
191 }
192 }
193 }
194 }
195
196 return response;
197}
198
Patrick Venture0b02be92018-08-31 11:55:55 -0700199} // namespace get
Tom Joseph816e92b2017-09-06 19:23:00 +0530200
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500201namespace set
202{
203
204IpmiUpdateData makeDbusMsg(const std::string& updateInterface,
205 const std::string& sensorPath,
206 const std::string& command,
207 const std::string& sensorInterface)
208{
209 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
210 using namespace std::string_literals;
211
Patrick Venture0b02be92018-08-31 11:55:55 -0700212 auto dbusService = getService(bus, sensorInterface, sensorPath);
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500213
Patrick Venture0b02be92018-08-31 11:55:55 -0700214 return bus.new_method_call(dbusService.c_str(), sensorPath.c_str(),
215 updateInterface.c_str(), command.c_str());
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500216}
217
Patrick Venture0b02be92018-08-31 11:55:55 -0700218ipmi_ret_t eventdata(const SetSensorReadingReq& cmdData, const Info& sensorInfo,
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500219 uint8_t data)
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500220{
Patrick Venture0b02be92018-08-31 11:55:55 -0700221 auto msg =
222 makeDbusMsg("org.freedesktop.DBus.Properties", sensorInfo.sensorPath,
223 "Set", sensorInfo.sensorInterface);
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500224
225 const auto& interface = sensorInfo.propertyInterfaces.begin();
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500226 msg.append(interface->first);
227 for (const auto& property : interface->second)
228 {
229 msg.append(property.first);
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500230 const auto& iter = std::get<OffsetValueMap>(property.second).find(data);
231 if (iter == std::get<OffsetValueMap>(property.second).end())
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500232 {
233 log<level::ERR>("Invalid event data");
234 return IPMI_CC_PARM_OUT_OF_RANGE;
235 }
236 msg.append(iter->second.assert);
237 }
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500238 return updateToDbus(msg);
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500239}
240
Patrick Venture0b02be92018-08-31 11:55:55 -0700241ipmi_ret_t assertion(const SetSensorReadingReq& cmdData, const Info& sensorInfo)
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500242{
Brad Bishop06a0abf2018-02-26 20:46:00 -0500243 std::bitset<16> assertionSet(getAssertionSet(cmdData).first);
244 std::bitset<16> deassertionSet(getAssertionSet(cmdData).second);
245 auto bothSet = assertionSet ^ deassertionSet;
246
247 const auto& interface = sensorInfo.propertyInterfaces.begin();
248
249 for (const auto& property : interface->second)
250 {
William A. Kennington III4c008022018-10-12 17:18:14 -0700251 std::optional<Value> tmp;
Brad Bishop06a0abf2018-02-26 20:46:00 -0500252 for (const auto& value : std::get<OffsetValueMap>(property.second))
253 {
254 if (bothSet.size() <= value.first || !bothSet.test(value.first))
255 {
256 // A BIOS shouldn't do this but ignore if they do.
257 continue;
258 }
259
260 if (assertionSet.test(value.first))
261 {
262 tmp = value.second.assert;
263 break;
264 }
265 if (deassertionSet.test(value.first))
266 {
267 tmp = value.second.deassert;
268 break;
269 }
270 }
271
William A. Kennington III4c008022018-10-12 17:18:14 -0700272 if (tmp)
Brad Bishop06a0abf2018-02-26 20:46:00 -0500273 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700274 auto msg = makeDbusMsg("org.freedesktop.DBus.Properties",
275 sensorInfo.sensorPath, "Set",
276 sensorInfo.sensorInterface);
Brad Bishop06a0abf2018-02-26 20:46:00 -0500277 msg.append(interface->first);
278 msg.append(property.first);
William A. Kennington III4c008022018-10-12 17:18:14 -0700279 msg.append(*tmp);
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500280
Brad Bishop06a0abf2018-02-26 20:46:00 -0500281 auto rc = updateToDbus(msg);
282 if (rc)
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500283 {
Brad Bishop06a0abf2018-02-26 20:46:00 -0500284 return rc;
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500285 }
286 }
287 }
Brad Bishop06a0abf2018-02-26 20:46:00 -0500288
289 return IPMI_CC_OK;
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500290}
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500291
Patrick Venture0b02be92018-08-31 11:55:55 -0700292} // namespace set
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500293
294namespace notify
295{
296
297IpmiUpdateData makeDbusMsg(const std::string& updateInterface,
298 const std::string& sensorPath,
299 const std::string& command,
300 const std::string& sensorInterface)
301{
302 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
303 using namespace std::string_literals;
304
Dhruvaraj Subhashchandranf915f852017-09-14 07:01:48 -0500305 static const auto dbusPath = "/xyz/openbmc_project/inventory"s;
306 std::string dbusService = ipmi::getService(bus, updateInterface, dbusPath);
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500307
Patrick Venture0b02be92018-08-31 11:55:55 -0700308 return bus.new_method_call(dbusService.c_str(), dbusPath.c_str(),
309 updateInterface.c_str(), command.c_str());
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500310}
311
Patrick Venture0b02be92018-08-31 11:55:55 -0700312ipmi_ret_t assertion(const SetSensorReadingReq& cmdData, const Info& sensorInfo)
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500313{
Patrick Venture0b02be92018-08-31 11:55:55 -0700314 auto msg = makeDbusMsg(sensorInfo.sensorInterface, sensorInfo.sensorPath,
315 "Notify", sensorInfo.sensorInterface);
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500316
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500317 std::bitset<16> assertionSet(getAssertionSet(cmdData).first);
318 std::bitset<16> deassertionSet(getAssertionSet(cmdData).second);
319 ipmi::sensor::ObjectMap objects;
320 ipmi::sensor::InterfaceMap interfaces;
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500321 for (const auto& interface : sensorInfo.propertyInterfaces)
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500322 {
Santosh Puranikbbf8bd62019-05-01 19:02:52 +0530323 // An interface with no properties - It is possible that the sensor
324 // object on DBUS implements a DBUS interface with no properties.
325 // Make sure we add the interface to the list if interfaces on the
326 // object with an empty property map.
327 if (interface.second.empty())
328 {
329 interfaces.emplace(interface.first, ipmi::sensor::PropertyMap{});
330 continue;
331 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700332 // For a property like functional state the result will be
333 // calculated based on the true value of all conditions.
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500334 for (const auto& property : interface.second)
335 {
336 ipmi::sensor::PropertyMap props;
337 bool valid = false;
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500338 auto result = true;
339 for (const auto& value : std::get<OffsetValueMap>(property.second))
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500340 {
341 if (assertionSet.test(value.first))
342 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700343 // Skip update if skipOn is ASSERT
Dhruvaraj Subhashchandrane84841c2017-08-22 07:40:27 -0500344 if (SkipAssertion::ASSERT == value.second.skip)
345 {
346 return IPMI_CC_OK;
347 }
Vernon Maueryf442e112019-04-09 11:44:36 -0700348 result = result && std::get<bool>(value.second.assert);
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500349 valid = true;
350 }
351 else if (deassertionSet.test(value.first))
352 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700353 // Skip update if skipOn is DEASSERT
Dhruvaraj Subhashchandrane84841c2017-08-22 07:40:27 -0500354 if (SkipAssertion::DEASSERT == value.second.skip)
355 {
356 return IPMI_CC_OK;
357 }
Vernon Maueryf442e112019-04-09 11:44:36 -0700358 result = result && std::get<bool>(value.second.deassert);
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500359 valid = true;
360 }
361 }
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500362 for (const auto& value :
Patrick Venture0b02be92018-08-31 11:55:55 -0700363 std::get<PreReqOffsetValueMap>(property.second))
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500364 {
365 if (assertionSet.test(value.first))
366 {
Vernon Maueryf442e112019-04-09 11:44:36 -0700367 result = result && std::get<bool>(value.second.assert);
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500368 }
369 else if (deassertionSet.test(value.first))
370 {
Vernon Maueryf442e112019-04-09 11:44:36 -0700371 result = result && std::get<bool>(value.second.deassert);
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500372 }
373 }
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500374 if (valid)
375 {
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500376 props.emplace(property.first, result);
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500377 interfaces.emplace(interface.first, std::move(props));
378 }
379 }
380 }
Dhruvaraj Subhashchandrane84841c2017-08-22 07:40:27 -0500381
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500382 objects.emplace(sensorInfo.sensorPath, std::move(interfaces));
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500383 msg.append(std::move(objects));
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500384 return updateToDbus(msg);
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500385}
Tom Joseph816e92b2017-09-06 19:23:00 +0530386
Patrick Venture0b02be92018-08-31 11:55:55 -0700387} // namespace notify
Tom Joseph816e92b2017-09-06 19:23:00 +0530388
389namespace inventory
390{
391
392namespace get
393{
394
395GetSensorResponse assertion(const Info& sensorInfo)
396{
Vernon Mauery185b9f82018-07-20 10:52:36 -0700397 namespace fs = std::filesystem;
Tom Joseph816e92b2017-09-06 19:23:00 +0530398
399 fs::path path{ipmi::sensor::inventoryRoot};
400 path += sensorInfo.sensorPath;
401
402 return ipmi::sensor::get::mapDbusToAssertion(
Patrick Venture0b02be92018-08-31 11:55:55 -0700403 sensorInfo, path.string(),
404 sensorInfo.propertyInterfaces.begin()->first);
Tom Joseph816e92b2017-09-06 19:23:00 +0530405}
406
Patrick Venture0b02be92018-08-31 11:55:55 -0700407} // namespace get
Tom Joseph816e92b2017-09-06 19:23:00 +0530408
409} // namespace inventory
Patrick Venture0b02be92018-08-31 11:55:55 -0700410} // namespace sensor
411} // namespace ipmi