blob: f5c1e53a749f0f9032624f11ea9e800acf7170e5 [file] [log] [blame]
Patrick Venture3a5071a2018-09-12 13:27:42 -07001#include "sensordatahandler.hpp"
2
3#include "sensorhandler.hpp"
4#include "types.hpp"
5#include "utils.hpp"
6
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -05007#include <bitset>
Patrick Venture3a5071a2018-09-12 13:27:42 -07008#include <phosphor-logging/elog-errors.hpp>
9#include <phosphor-logging/log.hpp>
10#include <xyz/openbmc_project/Common/error.hpp>
11
Vernon Mauery185b9f82018-07-20 10:52:36 -070012#if __has_include(<filesystem>)
13#include <filesystem>
14#elif __has_include(<experimental/filesystem>)
Tom Joseph816e92b2017-09-06 19:23:00 +053015#include <experimental/filesystem>
Patrick Venture0b02be92018-08-31 11:55:55 -070016namespace std
17{
18// splice experimental::filesystem into std
19namespace filesystem = std::experimental::filesystem;
20} // namespace std
Vernon Mauery185b9f82018-07-20 10:52:36 -070021#else
Patrick Venture0b02be92018-08-31 11:55:55 -070022#error filesystem not available
Vernon Mauery185b9f82018-07-20 10:52:36 -070023#endif
Patrick Venture0b02be92018-08-31 11:55:55 -070024
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -050025namespace ipmi
26{
27namespace sensor
28{
29
30using namespace phosphor::logging;
31using InternalFailure =
32 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
33
34static constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
35static constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
36static constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
37
38/** @brief get the D-Bus service and service path
39 * @param[in] bus - The Dbus bus object
40 * @param[in] interface - interface to the service
41 * @param[in] path - interested path in the list of objects
42 * @return pair of service path and service
43 */
44ServicePath getServiceAndPath(sdbusplus::bus::bus& bus,
45 const std::string& interface,
46 const std::string& path)
47{
48 auto depth = 0;
Patrick Venture0b02be92018-08-31 11:55:55 -070049 auto mapperCall = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
50 MAPPER_INTERFACE, "GetSubTree");
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -050051 mapperCall.append("/");
52 mapperCall.append(depth);
53 mapperCall.append(std::vector<Interface>({interface}));
54
55 auto mapperResponseMsg = bus.call(mapperCall);
56 if (mapperResponseMsg.is_method_error())
57 {
Dhruvaraj Subhashchandran18e99992017-08-09 09:10:47 -050058 log<level::ERR>("Mapper GetSubTree failed",
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 MapperResponseType mapperResponse;
65 mapperResponseMsg.read(mapperResponse);
66 if (mapperResponse.empty())
67 {
Dhruvaraj Subhashchandran18e99992017-08-09 09:10:47 -050068 log<level::ERR>("Invalid mapper response",
Joseph Reynolds510eb9c2018-05-30 11:51:28 -050069 entry("PATH=%s", path.c_str()),
70 entry("INTERFACE=%s", interface.c_str()));
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -050071 elog<InternalFailure>();
72 }
73
74 if (path.empty())
75 {
Patrick Venture0b02be92018-08-31 11:55:55 -070076 // Get the first one if the path is not in list.
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -050077 return std::make_pair(mapperResponse.begin()->first,
78 mapperResponse.begin()->second.begin()->first);
79 }
80 const auto& iter = mapperResponse.find(path);
81 if (iter == mapperResponse.end())
82 {
Gunnar Millsc9fa69e2018-04-08 16:35:25 -050083 log<level::ERR>("Couldn't find D-Bus path",
Joseph Reynolds510eb9c2018-05-30 11:51:28 -050084 entry("PATH=%s", path.c_str()),
85 entry("INTERFACE=%s", interface.c_str()));
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -050086 elog<InternalFailure>();
87 }
88 return std::make_pair(iter->first, iter->second.begin()->first);
89}
90
91AssertionSet getAssertionSet(const SetSensorReadingReq& cmdData)
92{
93 Assertion assertionStates =
94 (static_cast<Assertion>(cmdData.assertOffset8_14)) << 8 |
95 cmdData.assertOffset0_7;
96 Deassertion deassertionStates =
97 (static_cast<Deassertion>(cmdData.deassertOffset8_14)) << 8 |
98 cmdData.deassertOffset0_7;
99 return std::make_pair(assertionStates, deassertionStates);
100}
101
102ipmi_ret_t updateToDbus(IpmiUpdateData& msg)
103{
104 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
105 try
106 {
107 auto serviceResponseMsg = bus.call(msg);
108 if (serviceResponseMsg.is_method_error())
109 {
110 log<level::ERR>("Error in D-Bus call");
111 return IPMI_CC_UNSPECIFIED_ERROR;
112 }
113 }
114 catch (InternalFailure& e)
115 {
116 commit<InternalFailure>();
117 return IPMI_CC_UNSPECIFIED_ERROR;
118 }
119 return IPMI_CC_OK;
120}
121
Tom Joseph816e92b2017-09-06 19:23:00 +0530122namespace get
123{
124
Tom Josephb0adbcd2018-01-24 11:51:29 +0530125SensorName nameParentLeaf(const Info& sensorInfo)
126{
127 const auto pos = sensorInfo.sensorPath.find_last_of('/');
128 const auto leaf = sensorInfo.sensorPath.substr(pos + 1);
129
130 const auto remaining = sensorInfo.sensorPath.substr(0, pos);
131
132 const auto parentPos = remaining.find_last_of('/');
133 auto parent = remaining.substr(parentPos + 1);
134
135 parent += "_" + leaf;
136 return parent;
137}
138
Tom Joseph816e92b2017-09-06 19:23:00 +0530139GetSensorResponse mapDbusToAssertion(const Info& sensorInfo,
140 const InstancePath& path,
141 const DbusInterface& interface)
142{
143 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Patrick Venture0b02be92018-08-31 11:55:55 -0700144 GetSensorResponse response{};
Tom Joseph816e92b2017-09-06 19:23:00 +0530145 auto responseData = reinterpret_cast<GetReadingResponse*>(response.data());
146
147 auto service = ipmi::getService(bus, interface, path);
148
149 const auto& interfaceList = sensorInfo.propertyInterfaces;
150
151 for (const auto& interface : interfaceList)
152 {
153 for (const auto& property : interface.second)
154 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700155 auto propValue = ipmi::getDbusProperty(
156 bus, service, path, interface.first, property.first);
Tom Joseph816e92b2017-09-06 19:23:00 +0530157
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500158 for (const auto& value : std::get<OffsetValueMap>(property.second))
Tom Joseph816e92b2017-09-06 19:23:00 +0530159 {
160 if (propValue == value.second.assert)
161 {
162 setOffset(value.first, responseData);
163 break;
164 }
Tom Joseph816e92b2017-09-06 19:23:00 +0530165 }
166 }
167 }
168
169 return response;
170}
171
172GetSensorResponse assertion(const Info& sensorInfo)
173{
Patrick Venture0b02be92018-08-31 11:55:55 -0700174 return mapDbusToAssertion(sensorInfo, sensorInfo.sensorPath,
Tom Joseph816e92b2017-09-06 19:23:00 +0530175 sensorInfo.sensorInterface);
176}
177
Tom Josephe4014fc2017-09-06 23:57:36 +0530178GetSensorResponse eventdata2(const Info& sensorInfo)
179{
180 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Patrick Venture0b02be92018-08-31 11:55:55 -0700181 GetSensorResponse response{};
Tom Josephe4014fc2017-09-06 23:57:36 +0530182 auto responseData = reinterpret_cast<GetReadingResponse*>(response.data());
183
Patrick Venture0b02be92018-08-31 11:55:55 -0700184 auto service = ipmi::getService(bus, sensorInfo.sensorInterface,
Tom Josephe4014fc2017-09-06 23:57:36 +0530185 sensorInfo.sensorPath);
186
187 const auto& interfaceList = sensorInfo.propertyInterfaces;
188
189 for (const auto& interface : interfaceList)
190 {
191 for (const auto& property : interface.second)
192 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700193 auto propValue =
194 ipmi::getDbusProperty(bus, service, sensorInfo.sensorPath,
195 interface.first, property.first);
Tom Josephe4014fc2017-09-06 23:57:36 +0530196
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500197 for (const auto& value : std::get<OffsetValueMap>(property.second))
Tom Josephe4014fc2017-09-06 23:57:36 +0530198 {
199 if (propValue == value.second.assert)
200 {
201 setReading(value.first, responseData);
202 break;
203 }
204 }
205 }
206 }
207
208 return response;
209}
210
Patrick Venture0b02be92018-08-31 11:55:55 -0700211} // namespace get
Tom Joseph816e92b2017-09-06 19:23:00 +0530212
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500213namespace set
214{
215
216IpmiUpdateData makeDbusMsg(const std::string& updateInterface,
217 const std::string& sensorPath,
218 const std::string& command,
219 const std::string& sensorInterface)
220{
221 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
222 using namespace std::string_literals;
223
Patrick Venture0b02be92018-08-31 11:55:55 -0700224 auto dbusService = getService(bus, sensorInterface, sensorPath);
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500225
Patrick Venture0b02be92018-08-31 11:55:55 -0700226 return bus.new_method_call(dbusService.c_str(), sensorPath.c_str(),
227 updateInterface.c_str(), command.c_str());
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500228}
229
Patrick Venture0b02be92018-08-31 11:55:55 -0700230ipmi_ret_t eventdata(const SetSensorReadingReq& cmdData, const Info& sensorInfo,
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500231 uint8_t data)
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500232{
Patrick Venture0b02be92018-08-31 11:55:55 -0700233 auto msg =
234 makeDbusMsg("org.freedesktop.DBus.Properties", sensorInfo.sensorPath,
235 "Set", sensorInfo.sensorInterface);
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500236
237 const auto& interface = sensorInfo.propertyInterfaces.begin();
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500238 msg.append(interface->first);
239 for (const auto& property : interface->second)
240 {
241 msg.append(property.first);
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500242 const auto& iter = std::get<OffsetValueMap>(property.second).find(data);
243 if (iter == std::get<OffsetValueMap>(property.second).end())
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500244 {
245 log<level::ERR>("Invalid event data");
246 return IPMI_CC_PARM_OUT_OF_RANGE;
247 }
248 msg.append(iter->second.assert);
249 }
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500250 return updateToDbus(msg);
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500251}
252
Patrick Venture0b02be92018-08-31 11:55:55 -0700253ipmi_ret_t assertion(const SetSensorReadingReq& cmdData, const Info& sensorInfo)
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500254{
Brad Bishop06a0abf2018-02-26 20:46:00 -0500255 std::bitset<16> assertionSet(getAssertionSet(cmdData).first);
256 std::bitset<16> deassertionSet(getAssertionSet(cmdData).second);
257 auto bothSet = assertionSet ^ deassertionSet;
258
259 const auto& interface = sensorInfo.propertyInterfaces.begin();
260
261 for (const auto& property : interface->second)
262 {
263 Value tmp{mapbox::util::no_init()};
264 for (const auto& value : std::get<OffsetValueMap>(property.second))
265 {
266 if (bothSet.size() <= value.first || !bothSet.test(value.first))
267 {
268 // A BIOS shouldn't do this but ignore if they do.
269 continue;
270 }
271
272 if (assertionSet.test(value.first))
273 {
274 tmp = value.second.assert;
275 break;
276 }
277 if (deassertionSet.test(value.first))
278 {
279 tmp = value.second.deassert;
280 break;
281 }
282 }
283
284 if (tmp.valid())
285 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700286 auto msg = makeDbusMsg("org.freedesktop.DBus.Properties",
287 sensorInfo.sensorPath, "Set",
288 sensorInfo.sensorInterface);
Brad Bishop06a0abf2018-02-26 20:46:00 -0500289 msg.append(interface->first);
290 msg.append(property.first);
291 msg.append(tmp);
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500292
Brad Bishop06a0abf2018-02-26 20:46:00 -0500293 auto rc = updateToDbus(msg);
294 if (rc)
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500295 {
Brad Bishop06a0abf2018-02-26 20:46:00 -0500296 return rc;
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500297 }
298 }
299 }
Brad Bishop06a0abf2018-02-26 20:46:00 -0500300
301 return IPMI_CC_OK;
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500302}
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500303
Patrick Venture0b02be92018-08-31 11:55:55 -0700304} // namespace set
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500305
306namespace notify
307{
308
309IpmiUpdateData makeDbusMsg(const std::string& updateInterface,
310 const std::string& sensorPath,
311 const std::string& command,
312 const std::string& sensorInterface)
313{
314 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
315 using namespace std::string_literals;
316
Dhruvaraj Subhashchandranf915f852017-09-14 07:01:48 -0500317 static const auto dbusPath = "/xyz/openbmc_project/inventory"s;
318 std::string dbusService = ipmi::getService(bus, updateInterface, dbusPath);
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500319
Patrick Venture0b02be92018-08-31 11:55:55 -0700320 return bus.new_method_call(dbusService.c_str(), dbusPath.c_str(),
321 updateInterface.c_str(), command.c_str());
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500322}
323
Patrick Venture0b02be92018-08-31 11:55:55 -0700324ipmi_ret_t assertion(const SetSensorReadingReq& cmdData, const Info& sensorInfo)
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500325{
Patrick Venture0b02be92018-08-31 11:55:55 -0700326 auto msg = makeDbusMsg(sensorInfo.sensorInterface, sensorInfo.sensorPath,
327 "Notify", sensorInfo.sensorInterface);
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500328
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500329 std::bitset<16> assertionSet(getAssertionSet(cmdData).first);
330 std::bitset<16> deassertionSet(getAssertionSet(cmdData).second);
331 ipmi::sensor::ObjectMap objects;
332 ipmi::sensor::InterfaceMap interfaces;
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500333 for (const auto& interface : sensorInfo.propertyInterfaces)
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500334 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700335 // For a property like functional state the result will be
336 // calculated based on the true value of all conditions.
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500337 for (const auto& property : interface.second)
338 {
339 ipmi::sensor::PropertyMap props;
340 bool valid = false;
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500341 auto result = true;
342 for (const auto& value : std::get<OffsetValueMap>(property.second))
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500343 {
344 if (assertionSet.test(value.first))
345 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700346 // Skip update if skipOn is ASSERT
Dhruvaraj Subhashchandrane84841c2017-08-22 07:40:27 -0500347 if (SkipAssertion::ASSERT == value.second.skip)
348 {
349 return IPMI_CC_OK;
350 }
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500351 result = result && value.second.assert.get<bool>();
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500352 valid = true;
353 }
354 else if (deassertionSet.test(value.first))
355 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700356 // Skip update if skipOn is DEASSERT
Dhruvaraj Subhashchandrane84841c2017-08-22 07:40:27 -0500357 if (SkipAssertion::DEASSERT == value.second.skip)
358 {
359 return IPMI_CC_OK;
360 }
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500361 result = result && value.second.deassert.get<bool>();
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500362 valid = true;
363 }
364 }
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500365 for (const auto& value :
Patrick Venture0b02be92018-08-31 11:55:55 -0700366 std::get<PreReqOffsetValueMap>(property.second))
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500367 {
368 if (assertionSet.test(value.first))
369 {
370 result = result && value.second.assert.get<bool>();
371 }
372 else if (deassertionSet.test(value.first))
373 {
374 result = result && value.second.deassert.get<bool>();
375 }
376 }
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500377 if (valid)
378 {
Dhruvaraj Subhashchandrane245e4e2017-10-03 03:58:05 -0500379 props.emplace(property.first, result);
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500380 interfaces.emplace(interface.first, std::move(props));
381 }
382 }
383 }
Dhruvaraj Subhashchandrane84841c2017-08-22 07:40:27 -0500384
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500385 objects.emplace(sensorInfo.sensorPath, std::move(interfaces));
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500386 msg.append(std::move(objects));
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500387 return updateToDbus(msg);
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500388}
Tom Joseph816e92b2017-09-06 19:23:00 +0530389
Patrick Venture0b02be92018-08-31 11:55:55 -0700390} // namespace notify
Tom Joseph816e92b2017-09-06 19:23:00 +0530391
392namespace inventory
393{
394
395namespace get
396{
397
398GetSensorResponse assertion(const Info& sensorInfo)
399{
Vernon Mauery185b9f82018-07-20 10:52:36 -0700400 namespace fs = std::filesystem;
Tom Joseph816e92b2017-09-06 19:23:00 +0530401
402 fs::path path{ipmi::sensor::inventoryRoot};
403 path += sensorInfo.sensorPath;
404
405 return ipmi::sensor::get::mapDbusToAssertion(
Patrick Venture0b02be92018-08-31 11:55:55 -0700406 sensorInfo, path.string(),
407 sensorInfo.propertyInterfaces.begin()->first);
Tom Joseph816e92b2017-09-06 19:23:00 +0530408}
409
Patrick Venture0b02be92018-08-31 11:55:55 -0700410} // namespace get
Tom Joseph816e92b2017-09-06 19:23:00 +0530411
412} // namespace inventory
Patrick Venture0b02be92018-08-31 11:55:55 -0700413} // namespace sensor
414} // namespace ipmi