blob: 27dd011ea3c1b948b1bdf36dba753f9823685a08 [file] [log] [blame]
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -05001#include <bitset>
Vernon Mauery185b9f82018-07-20 10:52:36 -07002#if __has_include(<filesystem>)
3#include <filesystem>
4#elif __has_include(<experimental/filesystem>)
Tom Joseph816e92b2017-09-06 19:23:00 +05305#include <experimental/filesystem>
Patrick Venture0b02be92018-08-31 11:55:55 -07006namespace std
7{
8// splice experimental::filesystem into std
9namespace filesystem = std::experimental::filesystem;
10} // namespace std
Vernon Mauery185b9f82018-07-20 10:52:36 -070011#else
Patrick Venture0b02be92018-08-31 11:55:55 -070012#error filesystem not available
Vernon Mauery185b9f82018-07-20 10:52:36 -070013#endif
Patrick Venture0b02be92018-08-31 11:55:55 -070014#include "sensordatahandler.hpp"
Patrick Venture46470a32018-09-07 19:26:25 -070015#include "sensorhandler.hpp"
Patrick Venture0b02be92018-08-31 11:55:55 -070016#include "types.hpp"
17#include "utils.hpp"
18
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -050019#include <phosphor-logging/elog-errors.hpp>
20#include <phosphor-logging/log.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070021#include <xyz/openbmc_project/Common/error.hpp>
22
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -050023namespace ipmi
24{
25namespace sensor
26{
27
28using namespace phosphor::logging;
29using InternalFailure =
30 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
31
32static constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
33static constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
34static constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
35
36/** @brief get the D-Bus service and service path
37 * @param[in] bus - The Dbus bus object
38 * @param[in] interface - interface to the service
39 * @param[in] path - interested path in the list of objects
40 * @return pair of service path and service
41 */
42ServicePath getServiceAndPath(sdbusplus::bus::bus& bus,
43 const std::string& interface,
44 const std::string& path)
45{
46 auto depth = 0;
Patrick Venture0b02be92018-08-31 11:55:55 -070047 auto mapperCall = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
48 MAPPER_INTERFACE, "GetSubTree");
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -050049 mapperCall.append("/");
50 mapperCall.append(depth);
51 mapperCall.append(std::vector<Interface>({interface}));
52
53 auto mapperResponseMsg = bus.call(mapperCall);
54 if (mapperResponseMsg.is_method_error())
55 {
Dhruvaraj Subhashchandran18e99992017-08-09 09:10:47 -050056 log<level::ERR>("Mapper GetSubTree failed",
Joseph Reynolds510eb9c2018-05-30 11:51:28 -050057 entry("PATH=%s", path.c_str()),
58 entry("INTERFACE=%s", interface.c_str()));
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -050059 elog<InternalFailure>();
60 }
61
62 MapperResponseType mapperResponse;
63 mapperResponseMsg.read(mapperResponse);
64 if (mapperResponse.empty())
65 {
Dhruvaraj Subhashchandran18e99992017-08-09 09:10:47 -050066 log<level::ERR>("Invalid mapper response",
Joseph Reynolds510eb9c2018-05-30 11:51:28 -050067 entry("PATH=%s", path.c_str()),
68 entry("INTERFACE=%s", interface.c_str()));
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -050069 elog<InternalFailure>();
70 }
71
72 if (path.empty())
73 {
Patrick Venture0b02be92018-08-31 11:55:55 -070074 // Get the first one if the path is not in list.
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -050075 return std::make_pair(mapperResponse.begin()->first,
76 mapperResponse.begin()->second.begin()->first);
77 }
78 const auto& iter = mapperResponse.find(path);
79 if (iter == mapperResponse.end())
80 {
Gunnar Millsc9fa69e2018-04-08 16:35:25 -050081 log<level::ERR>("Couldn't find D-Bus path",
Joseph Reynolds510eb9c2018-05-30 11:51:28 -050082 entry("PATH=%s", path.c_str()),
83 entry("INTERFACE=%s", interface.c_str()));
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -050084 elog<InternalFailure>();
85 }
86 return std::make_pair(iter->first, iter->second.begin()->first);
87}
88
89AssertionSet getAssertionSet(const SetSensorReadingReq& cmdData)
90{
91 Assertion assertionStates =
92 (static_cast<Assertion>(cmdData.assertOffset8_14)) << 8 |
93 cmdData.assertOffset0_7;
94 Deassertion deassertionStates =
95 (static_cast<Deassertion>(cmdData.deassertOffset8_14)) << 8 |
96 cmdData.deassertOffset0_7;
97 return std::make_pair(assertionStates, deassertionStates);
98}
99
100ipmi_ret_t updateToDbus(IpmiUpdateData& msg)
101{
102 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
103 try
104 {
105 auto serviceResponseMsg = bus.call(msg);
106 if (serviceResponseMsg.is_method_error())
107 {
108 log<level::ERR>("Error in D-Bus call");
109 return IPMI_CC_UNSPECIFIED_ERROR;
110 }
111 }
112 catch (InternalFailure& e)
113 {
114 commit<InternalFailure>();
115 return IPMI_CC_UNSPECIFIED_ERROR;
116 }
117 return IPMI_CC_OK;
118}
119
Tom Joseph816e92b2017-09-06 19:23:00 +0530120namespace get
121{
122
Tom Josephb0adbcd2018-01-24 11:51:29 +0530123SensorName nameParentLeaf(const Info& sensorInfo)
124{
125 const auto pos = sensorInfo.sensorPath.find_last_of('/');
126 const auto leaf = sensorInfo.sensorPath.substr(pos + 1);
127
128 const auto remaining = sensorInfo.sensorPath.substr(0, pos);
129
130 const auto parentPos = remaining.find_last_of('/');
131 auto parent = remaining.substr(parentPos + 1);
132
133 parent += "_" + leaf;
134 return parent;
135}
136
Tom Joseph816e92b2017-09-06 19:23:00 +0530137GetSensorResponse mapDbusToAssertion(const Info& sensorInfo,
138 const InstancePath& path,
139 const DbusInterface& interface)
140{
141 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Patrick Venture0b02be92018-08-31 11:55:55 -0700142 GetSensorResponse response{};
Tom Joseph816e92b2017-09-06 19:23:00 +0530143 auto responseData = reinterpret_cast<GetReadingResponse*>(response.data());
144
145 auto service = ipmi::getService(bus, interface, path);
146
147 const auto& interfaceList = sensorInfo.propertyInterfaces;
148
149 for (const auto& interface : interfaceList)
150 {
151 for (const auto& property : interface.second)
152 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700153 auto propValue = ipmi::getDbusProperty(
154 bus, service, path, interface.first, property.first);
Tom Joseph816e92b2017-09-06 19:23:00 +0530155
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500156 for (const auto& value : std::get<OffsetValueMap>(property.second))
Tom Joseph816e92b2017-09-06 19:23:00 +0530157 {
158 if (propValue == value.second.assert)
159 {
160 setOffset(value.first, responseData);
161 break;
162 }
Tom Joseph816e92b2017-09-06 19:23:00 +0530163 }
164 }
165 }
166
167 return response;
168}
169
170GetSensorResponse assertion(const Info& sensorInfo)
171{
Patrick Venture0b02be92018-08-31 11:55:55 -0700172 return mapDbusToAssertion(sensorInfo, sensorInfo.sensorPath,
Tom Joseph816e92b2017-09-06 19:23:00 +0530173 sensorInfo.sensorInterface);
174}
175
Tom Josephe4014fc2017-09-06 23:57:36 +0530176GetSensorResponse eventdata2(const Info& sensorInfo)
177{
178 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Patrick Venture0b02be92018-08-31 11:55:55 -0700179 GetSensorResponse response{};
Tom Josephe4014fc2017-09-06 23:57:36 +0530180 auto responseData = reinterpret_cast<GetReadingResponse*>(response.data());
181
Patrick Venture0b02be92018-08-31 11:55:55 -0700182 auto service = ipmi::getService(bus, sensorInfo.sensorInterface,
Tom Josephe4014fc2017-09-06 23:57:36 +0530183 sensorInfo.sensorPath);
184
185 const auto& interfaceList = sensorInfo.propertyInterfaces;
186
187 for (const auto& interface : interfaceList)
188 {
189 for (const auto& property : interface.second)
190 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700191 auto propValue =
192 ipmi::getDbusProperty(bus, service, sensorInfo.sensorPath,
193 interface.first, property.first);
Tom Josephe4014fc2017-09-06 23:57:36 +0530194
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500195 for (const auto& value : std::get<OffsetValueMap>(property.second))
Tom Josephe4014fc2017-09-06 23:57:36 +0530196 {
197 if (propValue == value.second.assert)
198 {
199 setReading(value.first, responseData);
200 break;
201 }
202 }
203 }
204 }
205
206 return response;
207}
208
Patrick Venture0b02be92018-08-31 11:55:55 -0700209} // namespace get
Tom Joseph816e92b2017-09-06 19:23:00 +0530210
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500211namespace set
212{
213
214IpmiUpdateData makeDbusMsg(const std::string& updateInterface,
215 const std::string& sensorPath,
216 const std::string& command,
217 const std::string& sensorInterface)
218{
219 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
220 using namespace std::string_literals;
221
Patrick Venture0b02be92018-08-31 11:55:55 -0700222 auto dbusService = getService(bus, sensorInterface, sensorPath);
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500223
Patrick Venture0b02be92018-08-31 11:55:55 -0700224 return bus.new_method_call(dbusService.c_str(), sensorPath.c_str(),
225 updateInterface.c_str(), command.c_str());
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500226}
227
Patrick Venture0b02be92018-08-31 11:55:55 -0700228ipmi_ret_t eventdata(const SetSensorReadingReq& cmdData, const Info& sensorInfo,
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500229 uint8_t data)
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500230{
Patrick Venture0b02be92018-08-31 11:55:55 -0700231 auto msg =
232 makeDbusMsg("org.freedesktop.DBus.Properties", sensorInfo.sensorPath,
233 "Set", sensorInfo.sensorInterface);
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500234
235 const auto& interface = sensorInfo.propertyInterfaces.begin();
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500236 msg.append(interface->first);
237 for (const auto& property : interface->second)
238 {
239 msg.append(property.first);
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500240 const auto& iter = std::get<OffsetValueMap>(property.second).find(data);
241 if (iter == std::get<OffsetValueMap>(property.second).end())
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500242 {
243 log<level::ERR>("Invalid event data");
244 return IPMI_CC_PARM_OUT_OF_RANGE;
245 }
246 msg.append(iter->second.assert);
247 }
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500248 return updateToDbus(msg);
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500249}
250
Patrick Venture0b02be92018-08-31 11:55:55 -0700251ipmi_ret_t assertion(const SetSensorReadingReq& cmdData, const Info& sensorInfo)
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500252{
Brad Bishop06a0abf2018-02-26 20:46:00 -0500253 std::bitset<16> assertionSet(getAssertionSet(cmdData).first);
254 std::bitset<16> deassertionSet(getAssertionSet(cmdData).second);
255 auto bothSet = assertionSet ^ deassertionSet;
256
257 const auto& interface = sensorInfo.propertyInterfaces.begin();
258
259 for (const auto& property : interface->second)
260 {
261 Value tmp{mapbox::util::no_init()};
262 for (const auto& value : std::get<OffsetValueMap>(property.second))
263 {
264 if (bothSet.size() <= value.first || !bothSet.test(value.first))
265 {
266 // A BIOS shouldn't do this but ignore if they do.
267 continue;
268 }
269
270 if (assertionSet.test(value.first))
271 {
272 tmp = value.second.assert;
273 break;
274 }
275 if (deassertionSet.test(value.first))
276 {
277 tmp = value.second.deassert;
278 break;
279 }
280 }
281
282 if (tmp.valid())
283 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700284 auto msg = makeDbusMsg("org.freedesktop.DBus.Properties",
285 sensorInfo.sensorPath, "Set",
286 sensorInfo.sensorInterface);
Brad Bishop06a0abf2018-02-26 20:46:00 -0500287 msg.append(interface->first);
288 msg.append(property.first);
289 msg.append(tmp);
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500290
Brad Bishop06a0abf2018-02-26 20:46:00 -0500291 auto rc = updateToDbus(msg);
292 if (rc)
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500293 {
Brad Bishop06a0abf2018-02-26 20:46:00 -0500294 return rc;
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500295 }
296 }
297 }
Brad Bishop06a0abf2018-02-26 20:46:00 -0500298
299 return IPMI_CC_OK;
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500300}
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500301
Patrick Venture0b02be92018-08-31 11:55:55 -0700302} // namespace set
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500303
304namespace notify
305{
306
307IpmiUpdateData makeDbusMsg(const std::string& updateInterface,
308 const std::string& sensorPath,
309 const std::string& command,
310 const std::string& sensorInterface)
311{
312 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
313 using namespace std::string_literals;
314
Dhruvaraj Subhashchandranf915f852017-09-14 07:01:48 -0500315 static const auto dbusPath = "/xyz/openbmc_project/inventory"s;
316 std::string dbusService = ipmi::getService(bus, updateInterface, dbusPath);
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500317
Patrick Venture0b02be92018-08-31 11:55:55 -0700318 return bus.new_method_call(dbusService.c_str(), dbusPath.c_str(),
319 updateInterface.c_str(), command.c_str());
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500320}
321
Patrick Venture0b02be92018-08-31 11:55:55 -0700322ipmi_ret_t assertion(const SetSensorReadingReq& cmdData, const Info& sensorInfo)
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500323{
Patrick Venture0b02be92018-08-31 11:55:55 -0700324 auto msg = makeDbusMsg(sensorInfo.sensorInterface, sensorInfo.sensorPath,
325 "Notify", sensorInfo.sensorInterface);
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500326
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500327 std::bitset<16> assertionSet(getAssertionSet(cmdData).first);
328 std::bitset<16> deassertionSet(getAssertionSet(cmdData).second);
329 ipmi::sensor::ObjectMap objects;
330 ipmi::sensor::InterfaceMap interfaces;
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500331 for (const auto& interface : sensorInfo.propertyInterfaces)
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500332 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700333 // For a property like functional state the result will be
334 // calculated based on the true value of all conditions.
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500335 for (const auto& property : interface.second)
336 {
337 ipmi::sensor::PropertyMap props;
338 bool valid = false;
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500339 auto result = true;
340 for (const auto& value : std::get<OffsetValueMap>(property.second))
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500341 {
342 if (assertionSet.test(value.first))
343 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700344 // Skip update if skipOn is ASSERT
Dhruvaraj Subhashchandrane84841c2017-08-22 07:40:27 -0500345 if (SkipAssertion::ASSERT == value.second.skip)
346 {
347 return IPMI_CC_OK;
348 }
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500349 result = result && value.second.assert.get<bool>();
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500350 valid = true;
351 }
352 else if (deassertionSet.test(value.first))
353 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700354 // Skip update if skipOn is DEASSERT
Dhruvaraj Subhashchandrane84841c2017-08-22 07:40:27 -0500355 if (SkipAssertion::DEASSERT == value.second.skip)
356 {
357 return IPMI_CC_OK;
358 }
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500359 result = result && value.second.deassert.get<bool>();
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500360 valid = true;
361 }
362 }
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500363 for (const auto& value :
Patrick Venture0b02be92018-08-31 11:55:55 -0700364 std::get<PreReqOffsetValueMap>(property.second))
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500365 {
366 if (assertionSet.test(value.first))
367 {
368 result = result && value.second.assert.get<bool>();
369 }
370 else if (deassertionSet.test(value.first))
371 {
372 result = result && value.second.deassert.get<bool>();
373 }
374 }
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500375 if (valid)
376 {
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500377 props.emplace(property.first, result);
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500378 interfaces.emplace(interface.first, std::move(props));
379 }
380 }
381 }
Dhruvaraj Subhashchandrane84841c2017-08-22 07:40:27 -0500382
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500383 objects.emplace(sensorInfo.sensorPath, std::move(interfaces));
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500384 msg.append(std::move(objects));
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500385 return updateToDbus(msg);
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500386}
Tom Joseph816e92b2017-09-06 19:23:00 +0530387
Patrick Venture0b02be92018-08-31 11:55:55 -0700388} // namespace notify
Tom Joseph816e92b2017-09-06 19:23:00 +0530389
390namespace inventory
391{
392
393namespace get
394{
395
396GetSensorResponse assertion(const Info& sensorInfo)
397{
Vernon Mauery185b9f82018-07-20 10:52:36 -0700398 namespace fs = std::filesystem;
Tom Joseph816e92b2017-09-06 19:23:00 +0530399
400 fs::path path{ipmi::sensor::inventoryRoot};
401 path += sensorInfo.sensorPath;
402
403 return ipmi::sensor::get::mapDbusToAssertion(
Patrick Venture0b02be92018-08-31 11:55:55 -0700404 sensorInfo, path.string(),
405 sensorInfo.propertyInterfaces.begin()->first);
Tom Joseph816e92b2017-09-06 19:23:00 +0530406}
407
Patrick Venture0b02be92018-08-31 11:55:55 -0700408} // namespace get
Tom Joseph816e92b2017-09-06 19:23:00 +0530409
410} // namespace inventory
Patrick Venture0b02be92018-08-31 11:55:55 -0700411} // namespace sensor
412} // namespace ipmi