blob: 2d4ac3a65c43f84f3ebef6f84f698899b5c5ccf3 [file] [log] [blame]
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -05001#include <bitset>
Tom Joseph816e92b2017-09-06 19:23:00 +05302#include <experimental/filesystem>
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -05003#include <phosphor-logging/elog-errors.hpp>
4#include <phosphor-logging/log.hpp>
5#include "xyz/openbmc_project/Common/error.hpp"
6#include "types.hpp"
Tom Joseph816e92b2017-09-06 19:23:00 +05307#include "sensorhandler.h"
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -05008#include "sensordatahandler.hpp"
Tom Joseph816e92b2017-09-06 19:23:00 +05309#include "utils.hpp"
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -050010
11namespace ipmi
12{
13namespace sensor
14{
15
16using namespace phosphor::logging;
17using InternalFailure =
18 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
19
20static constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
21static constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
22static constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
23
24/** @brief get the D-Bus service and service path
25 * @param[in] bus - The Dbus bus object
26 * @param[in] interface - interface to the service
27 * @param[in] path - interested path in the list of objects
28 * @return pair of service path and service
29 */
30ServicePath getServiceAndPath(sdbusplus::bus::bus& bus,
31 const std::string& interface,
32 const std::string& path)
33{
34 auto depth = 0;
35 auto mapperCall = bus.new_method_call(MAPPER_BUSNAME,
36 MAPPER_PATH,
37 MAPPER_INTERFACE,
38 "GetSubTree");
39 mapperCall.append("/");
40 mapperCall.append(depth);
41 mapperCall.append(std::vector<Interface>({interface}));
42
43 auto mapperResponseMsg = bus.call(mapperCall);
44 if (mapperResponseMsg.is_method_error())
45 {
Dhruvaraj Subhashchandran18e99992017-08-09 09:10:47 -050046 log<level::ERR>("Mapper GetSubTree failed",
Joseph Reynolds510eb9c2018-05-30 11:51:28 -050047 entry("PATH=%s", path.c_str()),
48 entry("INTERFACE=%s", interface.c_str()));
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -050049 elog<InternalFailure>();
50 }
51
52 MapperResponseType mapperResponse;
53 mapperResponseMsg.read(mapperResponse);
54 if (mapperResponse.empty())
55 {
Dhruvaraj Subhashchandran18e99992017-08-09 09:10:47 -050056 log<level::ERR>("Invalid mapper response",
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 if (path.empty())
63 {
64 //Get the first one if the path is not in list.
65 return std::make_pair(mapperResponse.begin()->first,
66 mapperResponse.begin()->second.begin()->first);
67 }
68 const auto& iter = mapperResponse.find(path);
69 if (iter == mapperResponse.end())
70 {
Gunnar Millsc9fa69e2018-04-08 16:35:25 -050071 log<level::ERR>("Couldn't find D-Bus path",
Joseph Reynolds510eb9c2018-05-30 11:51:28 -050072 entry("PATH=%s", path.c_str()),
73 entry("INTERFACE=%s", interface.c_str()));
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -050074 elog<InternalFailure>();
75 }
76 return std::make_pair(iter->first, iter->second.begin()->first);
77}
78
79AssertionSet getAssertionSet(const SetSensorReadingReq& cmdData)
80{
81 Assertion assertionStates =
82 (static_cast<Assertion>(cmdData.assertOffset8_14)) << 8 |
83 cmdData.assertOffset0_7;
84 Deassertion deassertionStates =
85 (static_cast<Deassertion>(cmdData.deassertOffset8_14)) << 8 |
86 cmdData.deassertOffset0_7;
87 return std::make_pair(assertionStates, deassertionStates);
88}
89
90ipmi_ret_t updateToDbus(IpmiUpdateData& msg)
91{
92 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
93 try
94 {
95 auto serviceResponseMsg = bus.call(msg);
96 if (serviceResponseMsg.is_method_error())
97 {
98 log<level::ERR>("Error in D-Bus call");
99 return IPMI_CC_UNSPECIFIED_ERROR;
100 }
101 }
102 catch (InternalFailure& e)
103 {
104 commit<InternalFailure>();
105 return IPMI_CC_UNSPECIFIED_ERROR;
106 }
107 return IPMI_CC_OK;
108}
109
Tom Joseph816e92b2017-09-06 19:23:00 +0530110namespace get
111{
112
Tom Josephb0adbcd2018-01-24 11:51:29 +0530113SensorName nameParentLeaf(const Info& sensorInfo)
114{
115 const auto pos = sensorInfo.sensorPath.find_last_of('/');
116 const auto leaf = sensorInfo.sensorPath.substr(pos + 1);
117
118 const auto remaining = sensorInfo.sensorPath.substr(0, pos);
119
120 const auto parentPos = remaining.find_last_of('/');
121 auto parent = remaining.substr(parentPos + 1);
122
123 parent += "_" + leaf;
124 return parent;
125}
126
Tom Joseph816e92b2017-09-06 19:23:00 +0530127GetSensorResponse mapDbusToAssertion(const Info& sensorInfo,
128 const InstancePath& path,
129 const DbusInterface& interface)
130{
131 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
132 GetSensorResponse response {};
133 auto responseData = reinterpret_cast<GetReadingResponse*>(response.data());
134
135 auto service = ipmi::getService(bus, interface, path);
136
137 const auto& interfaceList = sensorInfo.propertyInterfaces;
138
139 for (const auto& interface : interfaceList)
140 {
141 for (const auto& property : interface.second)
142 {
143 auto propValue = ipmi::getDbusProperty(bus,
144 service,
145 path,
146 interface.first,
147 property.first);
148
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500149 for (const auto& value : std::get<OffsetValueMap>(property.second))
Tom Joseph816e92b2017-09-06 19:23:00 +0530150 {
151 if (propValue == value.second.assert)
152 {
153 setOffset(value.first, responseData);
154 break;
155 }
156
157 }
158 }
159 }
160
161 return response;
162}
163
164GetSensorResponse assertion(const Info& sensorInfo)
165{
166 return mapDbusToAssertion(sensorInfo,
167 sensorInfo.sensorPath,
168 sensorInfo.sensorInterface);
169}
170
Tom Josephe4014fc2017-09-06 23:57:36 +0530171GetSensorResponse eventdata2(const Info& sensorInfo)
172{
173 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
174 GetSensorResponse response {};
175 auto responseData = reinterpret_cast<GetReadingResponse*>(response.data());
176
177 auto service = ipmi::getService(bus,
178 sensorInfo.sensorInterface,
179 sensorInfo.sensorPath);
180
181 const auto& interfaceList = sensorInfo.propertyInterfaces;
182
183 for (const auto& interface : interfaceList)
184 {
185 for (const auto& property : interface.second)
186 {
187 auto propValue = ipmi::getDbusProperty(bus,
188 service,
189 sensorInfo.sensorPath,
190 interface.first,
191 property.first);
192
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500193 for (const auto& value : std::get<OffsetValueMap>(property.second))
Tom Josephe4014fc2017-09-06 23:57:36 +0530194 {
195 if (propValue == value.second.assert)
196 {
197 setReading(value.first, responseData);
198 break;
199 }
200 }
201 }
202 }
203
204 return response;
205}
206
Tom Joseph816e92b2017-09-06 19:23:00 +0530207} //namespace get
208
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500209namespace set
210{
211
212IpmiUpdateData makeDbusMsg(const std::string& updateInterface,
213 const std::string& sensorPath,
214 const std::string& command,
215 const std::string& sensorInterface)
216{
217 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
218 using namespace std::string_literals;
219
Tom Josephc6a571a2017-11-28 16:46:22 +0530220 auto dbusService = getService(bus,
221 sensorInterface,
222 sensorPath);
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500223
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500224 return bus.new_method_call(dbusService.c_str(),
Tom Josephc6a571a2017-11-28 16:46:22 +0530225 sensorPath.c_str(),
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500226 updateInterface.c_str(),
227 command.c_str());
228}
229
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500230ipmi_ret_t eventdata(const SetSensorReadingReq& cmdData,
231 const Info& sensorInfo,
232 uint8_t data)
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500233{
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500234 auto msg = makeDbusMsg(
235 "org.freedesktop.DBus.Properties",
236 sensorInfo.sensorPath,
237 "Set",
238 sensorInfo.sensorInterface);
239
240 const auto& interface = sensorInfo.propertyInterfaces.begin();
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500241 msg.append(interface->first);
242 for (const auto& property : interface->second)
243 {
244 msg.append(property.first);
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500245 const auto& iter = std::get<OffsetValueMap>(property.second).find(data);
246 if (iter == std::get<OffsetValueMap>(property.second).end())
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500247 {
248 log<level::ERR>("Invalid event data");
249 return IPMI_CC_PARM_OUT_OF_RANGE;
250 }
251 msg.append(iter->second.assert);
252 }
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500253 return updateToDbus(msg);
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500254}
255
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500256ipmi_ret_t assertion(const SetSensorReadingReq& cmdData,
257 const Info& sensorInfo)
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500258{
Brad Bishop06a0abf2018-02-26 20:46:00 -0500259 std::bitset<16> assertionSet(getAssertionSet(cmdData).first);
260 std::bitset<16> deassertionSet(getAssertionSet(cmdData).second);
261 auto bothSet = assertionSet ^ deassertionSet;
262
263 const auto& interface = sensorInfo.propertyInterfaces.begin();
264
265 for (const auto& property : interface->second)
266 {
267 Value tmp{mapbox::util::no_init()};
268 for (const auto& value : std::get<OffsetValueMap>(property.second))
269 {
270 if (bothSet.size() <= value.first || !bothSet.test(value.first))
271 {
272 // A BIOS shouldn't do this but ignore if they do.
273 continue;
274 }
275
276 if (assertionSet.test(value.first))
277 {
278 tmp = value.second.assert;
279 break;
280 }
281 if (deassertionSet.test(value.first))
282 {
283 tmp = value.second.deassert;
284 break;
285 }
286 }
287
288 if (tmp.valid())
289 {
290 auto msg = makeDbusMsg(
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500291 "org.freedesktop.DBus.Properties",
292 sensorInfo.sensorPath,
293 "Set",
294 sensorInfo.sensorInterface);
Brad Bishop06a0abf2018-02-26 20:46:00 -0500295 msg.append(interface->first);
296 msg.append(property.first);
297 msg.append(tmp);
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500298
Brad Bishop06a0abf2018-02-26 20:46:00 -0500299 auto rc = updateToDbus(msg);
300 if (rc)
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500301 {
Brad Bishop06a0abf2018-02-26 20:46:00 -0500302 return rc;
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500303 }
304 }
305 }
Brad Bishop06a0abf2018-02-26 20:46:00 -0500306
307 return IPMI_CC_OK;
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500308}
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500309
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500310}//namespace set
311
312namespace notify
313{
314
315IpmiUpdateData makeDbusMsg(const std::string& updateInterface,
316 const std::string& sensorPath,
317 const std::string& command,
318 const std::string& sensorInterface)
319{
320 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
321 using namespace std::string_literals;
322
Dhruvaraj Subhashchandranf915f852017-09-14 07:01:48 -0500323 static const auto dbusPath = "/xyz/openbmc_project/inventory"s;
324 std::string dbusService = ipmi::getService(bus, updateInterface, dbusPath);
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500325
326 return bus.new_method_call(dbusService.c_str(),
327 dbusPath.c_str(),
328 updateInterface.c_str(),
329 command.c_str());
330}
331
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500332ipmi_ret_t assertion(const SetSensorReadingReq& cmdData,
333 const Info& sensorInfo)
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500334{
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500335 auto msg = makeDbusMsg(
336 sensorInfo.sensorInterface,
337 sensorInfo.sensorPath,
338 "Notify",
339 sensorInfo.sensorInterface);
340
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500341 std::bitset<16> assertionSet(getAssertionSet(cmdData).first);
342 std::bitset<16> deassertionSet(getAssertionSet(cmdData).second);
343 ipmi::sensor::ObjectMap objects;
344 ipmi::sensor::InterfaceMap interfaces;
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500345 for (const auto& interface : sensorInfo.propertyInterfaces)
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500346 {
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500347 //For a property like functional state the result will be
348 //calculated based on the true value of all conditions.
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500349 for (const auto& property : interface.second)
350 {
351 ipmi::sensor::PropertyMap props;
352 bool valid = false;
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500353 auto result = true;
354 for (const auto& value : std::get<OffsetValueMap>(property.second))
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500355 {
356 if (assertionSet.test(value.first))
357 {
Dhruvaraj Subhashchandrane84841c2017-08-22 07:40:27 -0500358 //Skip update if skipOn is ASSERT
359 if (SkipAssertion::ASSERT == value.second.skip)
360 {
361 return IPMI_CC_OK;
362 }
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500363 result = result && value.second.assert.get<bool>();
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500364 valid = true;
365 }
366 else if (deassertionSet.test(value.first))
367 {
Dhruvaraj Subhashchandrane84841c2017-08-22 07:40:27 -0500368 //Skip update if skipOn is DEASSERT
369 if (SkipAssertion::DEASSERT == value.second.skip)
370 {
371 return IPMI_CC_OK;
372 }
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500373 result = result && value.second.deassert.get<bool>();
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500374 valid = true;
375 }
376 }
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500377 for (const auto& value :
378 std::get<PreReqOffsetValueMap>(property.second))
379 {
380 if (assertionSet.test(value.first))
381 {
382 result = result && value.second.assert.get<bool>();
383 }
384 else if (deassertionSet.test(value.first))
385 {
386 result = result && value.second.deassert.get<bool>();
387 }
388 }
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500389 if (valid)
390 {
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500391 props.emplace(property.first, result);
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500392 interfaces.emplace(interface.first, std::move(props));
393 }
394 }
395 }
Dhruvaraj Subhashchandrane84841c2017-08-22 07:40:27 -0500396
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500397 objects.emplace(sensorInfo.sensorPath, std::move(interfaces));
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500398 msg.append(std::move(objects));
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500399 return updateToDbus(msg);
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500400}
Tom Joseph816e92b2017-09-06 19:23:00 +0530401
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500402}//namespace notify
Tom Joseph816e92b2017-09-06 19:23:00 +0530403
404namespace inventory
405{
406
407namespace get
408{
409
410GetSensorResponse assertion(const Info& sensorInfo)
411{
412 namespace fs = std::experimental::filesystem;
413
414 fs::path path{ipmi::sensor::inventoryRoot};
415 path += sensorInfo.sensorPath;
416
417 return ipmi::sensor::get::mapDbusToAssertion(
418 sensorInfo,
419 path.string(),
420 sensorInfo.propertyInterfaces.begin()->first);
421}
422
423} //namespace get
424
425} // namespace inventory
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500426}//namespace sensor
427}//namespace ipmi