blob: ef5089aba94ffe1aeadf37d8c78eab96e472c59b [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>
Vernon Mauery185b9f82018-07-20 10:52:36 -07006namespace std {
7 // splice experimental::filesystem into std
8 namespace filesystem = std::experimental::filesystem;
9}
10#else
11# error filesystem not available
12#endif
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -050013#include <phosphor-logging/elog-errors.hpp>
14#include <phosphor-logging/log.hpp>
15#include "xyz/openbmc_project/Common/error.hpp"
16#include "types.hpp"
Tom Joseph816e92b2017-09-06 19:23:00 +053017#include "sensorhandler.h"
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -050018#include "sensordatahandler.hpp"
Tom Joseph816e92b2017-09-06 19:23:00 +053019#include "utils.hpp"
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -050020
21namespace ipmi
22{
23namespace sensor
24{
25
26using namespace phosphor::logging;
27using InternalFailure =
28 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
29
30static constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
31static constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
32static constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
33
34/** @brief get the D-Bus service and service path
35 * @param[in] bus - The Dbus bus object
36 * @param[in] interface - interface to the service
37 * @param[in] path - interested path in the list of objects
38 * @return pair of service path and service
39 */
40ServicePath getServiceAndPath(sdbusplus::bus::bus& bus,
41 const std::string& interface,
42 const std::string& path)
43{
44 auto depth = 0;
45 auto mapperCall = bus.new_method_call(MAPPER_BUSNAME,
46 MAPPER_PATH,
47 MAPPER_INTERFACE,
48 "GetSubTree");
49 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 {
74 //Get the first one if the path is not in list.
75 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()};
142 GetSensorResponse response {};
143 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 {
153 auto propValue = ipmi::getDbusProperty(bus,
154 service,
155 path,
156 interface.first,
157 property.first);
158
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500159 for (const auto& value : std::get<OffsetValueMap>(property.second))
Tom Joseph816e92b2017-09-06 19:23:00 +0530160 {
161 if (propValue == value.second.assert)
162 {
163 setOffset(value.first, responseData);
164 break;
165 }
166
167 }
168 }
169 }
170
171 return response;
172}
173
174GetSensorResponse assertion(const Info& sensorInfo)
175{
176 return mapDbusToAssertion(sensorInfo,
177 sensorInfo.sensorPath,
178 sensorInfo.sensorInterface);
179}
180
Tom Josephe4014fc2017-09-06 23:57:36 +0530181GetSensorResponse eventdata2(const Info& sensorInfo)
182{
183 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
184 GetSensorResponse response {};
185 auto responseData = reinterpret_cast<GetReadingResponse*>(response.data());
186
187 auto service = ipmi::getService(bus,
188 sensorInfo.sensorInterface,
189 sensorInfo.sensorPath);
190
191 const auto& interfaceList = sensorInfo.propertyInterfaces;
192
193 for (const auto& interface : interfaceList)
194 {
195 for (const auto& property : interface.second)
196 {
197 auto propValue = ipmi::getDbusProperty(bus,
198 service,
199 sensorInfo.sensorPath,
200 interface.first,
201 property.first);
202
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500203 for (const auto& value : std::get<OffsetValueMap>(property.second))
Tom Josephe4014fc2017-09-06 23:57:36 +0530204 {
205 if (propValue == value.second.assert)
206 {
207 setReading(value.first, responseData);
208 break;
209 }
210 }
211 }
212 }
213
214 return response;
215}
216
Tom Joseph816e92b2017-09-06 19:23:00 +0530217} //namespace get
218
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500219namespace set
220{
221
222IpmiUpdateData makeDbusMsg(const std::string& updateInterface,
223 const std::string& sensorPath,
224 const std::string& command,
225 const std::string& sensorInterface)
226{
227 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
228 using namespace std::string_literals;
229
Tom Josephc6a571a2017-11-28 16:46:22 +0530230 auto dbusService = getService(bus,
231 sensorInterface,
232 sensorPath);
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500233
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500234 return bus.new_method_call(dbusService.c_str(),
Tom Josephc6a571a2017-11-28 16:46:22 +0530235 sensorPath.c_str(),
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500236 updateInterface.c_str(),
237 command.c_str());
238}
239
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500240ipmi_ret_t eventdata(const SetSensorReadingReq& cmdData,
241 const Info& sensorInfo,
242 uint8_t data)
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500243{
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500244 auto msg = makeDbusMsg(
245 "org.freedesktop.DBus.Properties",
246 sensorInfo.sensorPath,
247 "Set",
248 sensorInfo.sensorInterface);
249
250 const auto& interface = sensorInfo.propertyInterfaces.begin();
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500251 msg.append(interface->first);
252 for (const auto& property : interface->second)
253 {
254 msg.append(property.first);
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500255 const auto& iter = std::get<OffsetValueMap>(property.second).find(data);
256 if (iter == std::get<OffsetValueMap>(property.second).end())
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500257 {
258 log<level::ERR>("Invalid event data");
259 return IPMI_CC_PARM_OUT_OF_RANGE;
260 }
261 msg.append(iter->second.assert);
262 }
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500263 return updateToDbus(msg);
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500264}
265
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500266ipmi_ret_t assertion(const SetSensorReadingReq& cmdData,
267 const Info& sensorInfo)
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500268{
Brad Bishop06a0abf2018-02-26 20:46:00 -0500269 std::bitset<16> assertionSet(getAssertionSet(cmdData).first);
270 std::bitset<16> deassertionSet(getAssertionSet(cmdData).second);
271 auto bothSet = assertionSet ^ deassertionSet;
272
273 const auto& interface = sensorInfo.propertyInterfaces.begin();
274
275 for (const auto& property : interface->second)
276 {
277 Value tmp{mapbox::util::no_init()};
278 for (const auto& value : std::get<OffsetValueMap>(property.second))
279 {
280 if (bothSet.size() <= value.first || !bothSet.test(value.first))
281 {
282 // A BIOS shouldn't do this but ignore if they do.
283 continue;
284 }
285
286 if (assertionSet.test(value.first))
287 {
288 tmp = value.second.assert;
289 break;
290 }
291 if (deassertionSet.test(value.first))
292 {
293 tmp = value.second.deassert;
294 break;
295 }
296 }
297
298 if (tmp.valid())
299 {
300 auto msg = makeDbusMsg(
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500301 "org.freedesktop.DBus.Properties",
302 sensorInfo.sensorPath,
303 "Set",
304 sensorInfo.sensorInterface);
Brad Bishop06a0abf2018-02-26 20:46:00 -0500305 msg.append(interface->first);
306 msg.append(property.first);
307 msg.append(tmp);
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500308
Brad Bishop06a0abf2018-02-26 20:46:00 -0500309 auto rc = updateToDbus(msg);
310 if (rc)
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500311 {
Brad Bishop06a0abf2018-02-26 20:46:00 -0500312 return rc;
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500313 }
314 }
315 }
Brad Bishop06a0abf2018-02-26 20:46:00 -0500316
317 return IPMI_CC_OK;
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500318}
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500319
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500320}//namespace set
321
322namespace notify
323{
324
325IpmiUpdateData makeDbusMsg(const std::string& updateInterface,
326 const std::string& sensorPath,
327 const std::string& command,
328 const std::string& sensorInterface)
329{
330 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
331 using namespace std::string_literals;
332
Dhruvaraj Subhashchandranf915f852017-09-14 07:01:48 -0500333 static const auto dbusPath = "/xyz/openbmc_project/inventory"s;
334 std::string dbusService = ipmi::getService(bus, updateInterface, dbusPath);
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500335
336 return bus.new_method_call(dbusService.c_str(),
337 dbusPath.c_str(),
338 updateInterface.c_str(),
339 command.c_str());
340}
341
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500342ipmi_ret_t assertion(const SetSensorReadingReq& cmdData,
343 const Info& sensorInfo)
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500344{
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500345 auto msg = makeDbusMsg(
346 sensorInfo.sensorInterface,
347 sensorInfo.sensorPath,
348 "Notify",
349 sensorInfo.sensorInterface);
350
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500351 std::bitset<16> assertionSet(getAssertionSet(cmdData).first);
352 std::bitset<16> deassertionSet(getAssertionSet(cmdData).second);
353 ipmi::sensor::ObjectMap objects;
354 ipmi::sensor::InterfaceMap interfaces;
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500355 for (const auto& interface : sensorInfo.propertyInterfaces)
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500356 {
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500357 //For a property like functional state the result will be
358 //calculated based on the true value of all conditions.
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500359 for (const auto& property : interface.second)
360 {
361 ipmi::sensor::PropertyMap props;
362 bool valid = false;
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500363 auto result = true;
364 for (const auto& value : std::get<OffsetValueMap>(property.second))
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500365 {
366 if (assertionSet.test(value.first))
367 {
Dhruvaraj Subhashchandrane84841c2017-08-22 07:40:27 -0500368 //Skip update if skipOn is ASSERT
369 if (SkipAssertion::ASSERT == value.second.skip)
370 {
371 return IPMI_CC_OK;
372 }
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500373 result = result && value.second.assert.get<bool>();
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500374 valid = true;
375 }
376 else if (deassertionSet.test(value.first))
377 {
Dhruvaraj Subhashchandrane84841c2017-08-22 07:40:27 -0500378 //Skip update if skipOn is DEASSERT
379 if (SkipAssertion::DEASSERT == value.second.skip)
380 {
381 return IPMI_CC_OK;
382 }
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500383 result = result && value.second.deassert.get<bool>();
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500384 valid = true;
385 }
386 }
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500387 for (const auto& value :
388 std::get<PreReqOffsetValueMap>(property.second))
389 {
390 if (assertionSet.test(value.first))
391 {
392 result = result && value.second.assert.get<bool>();
393 }
394 else if (deassertionSet.test(value.first))
395 {
396 result = result && value.second.deassert.get<bool>();
397 }
398 }
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500399 if (valid)
400 {
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500401 props.emplace(property.first, result);
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500402 interfaces.emplace(interface.first, std::move(props));
403 }
404 }
405 }
Dhruvaraj Subhashchandrane84841c2017-08-22 07:40:27 -0500406
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500407 objects.emplace(sensorInfo.sensorPath, std::move(interfaces));
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500408 msg.append(std::move(objects));
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500409 return updateToDbus(msg);
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500410}
Tom Joseph816e92b2017-09-06 19:23:00 +0530411
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500412}//namespace notify
Tom Joseph816e92b2017-09-06 19:23:00 +0530413
414namespace inventory
415{
416
417namespace get
418{
419
420GetSensorResponse assertion(const Info& sensorInfo)
421{
Vernon Mauery185b9f82018-07-20 10:52:36 -0700422 namespace fs = std::filesystem;
Tom Joseph816e92b2017-09-06 19:23:00 +0530423
424 fs::path path{ipmi::sensor::inventoryRoot};
425 path += sensorInfo.sensorPath;
426
427 return ipmi::sensor::get::mapDbusToAssertion(
428 sensorInfo,
429 path.string(),
430 sensorInfo.propertyInterfaces.begin()->first);
431}
432
433} //namespace get
434
435} // namespace inventory
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500436}//namespace sensor
437}//namespace ipmi