blob: b8cf3face86ba99302e084e5a0fd60b011e7a360 [file] [log] [blame]
Willy Tude54f482021-01-26 15:59:09 -08001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16
17#include "dbus-sdr/sdrutils.hpp"
18
George Liuc1c7eac2024-02-04 17:24:19 +080019#include <ipmid/utils.hpp>
Johnathan Mantey04b0b072023-10-10 12:30:35 -070020#include <nlohmann/json.hpp>
21
22#include <fstream>
Willy Tu4eca2512022-06-20 21:14:51 -070023#include <optional>
24#include <unordered_set>
25
Scron Chang2703b022021-07-06 15:47:45 +080026#ifdef FEATURE_HYBRID_SENSORS
27
28#include <ipmid/utils.hpp>
29namespace ipmi
30{
31namespace sensor
32{
33extern const IdInfoMap sensors;
34} // namespace sensor
35} // namespace ipmi
36
37#endif
38
Johnathan Mantey34d19732024-07-17 07:59:54 -070039boost::container::flat_map<
40 const char*, std::pair<SensorTypeCodes, SensorEventTypeCodes>, CmpStr>
41 sensorTypes{
42 {{"temperature", std::make_pair(SensorTypeCodes::temperature,
43 SensorEventTypeCodes::threshold)},
44 {"voltage", std::make_pair(SensorTypeCodes::voltage,
45 SensorEventTypeCodes::threshold)},
46 {"current", std::make_pair(SensorTypeCodes::current,
47 SensorEventTypeCodes::threshold)},
48 {"fan_tach", std::make_pair(SensorTypeCodes::fan,
49 SensorEventTypeCodes::threshold)},
50 {"fan_pwm", std::make_pair(SensorTypeCodes::fan,
51 SensorEventTypeCodes::threshold)},
52 {"intrusion", std::make_pair(SensorTypeCodes::physical_security,
53 SensorEventTypeCodes::sensorSpecified)},
54 {"processor", std::make_pair(SensorTypeCodes::processor,
55 SensorEventTypeCodes::sensorSpecified)},
56 {"power", std::make_pair(SensorTypeCodes::other,
57 SensorEventTypeCodes::threshold)},
58 {"memory", std::make_pair(SensorTypeCodes::memory,
59 SensorEventTypeCodes::sensorSpecified)},
60 {"state", std::make_pair(SensorTypeCodes::power_unit,
61 SensorEventTypeCodes::sensorSpecified)},
62 {"buttons", std::make_pair(SensorTypeCodes::buttons,
63 SensorEventTypeCodes::sensorSpecified)},
64 {"watchdog", std::make_pair(SensorTypeCodes::watchdog2,
65 SensorEventTypeCodes::sensorSpecified)},
66 {"entity", std::make_pair(SensorTypeCodes::entity,
67 SensorEventTypeCodes::sensorSpecified)},
68 {"energy", std::make_pair(SensorTypeCodes::other,
69 SensorEventTypeCodes::threshold)}}};
70
Willy Tude54f482021-01-26 15:59:09 -080071namespace details
72{
Johnathan Mantey04b0b072023-10-10 12:30:35 -070073
74// IPMI supports a smaller number of sensors than are available via Redfish.
75// Trim the list of sensors, via a configuration file.
76// Read the IPMI Sensor Filtering section in docs/configuration.md for
77// a more detailed description.
78static void filterSensors(SensorSubTree& subtree)
79{
80 constexpr const char* filterFilename =
81 "/usr/share/ipmi-providers/sensor_filter.json";
82 std::ifstream filterFile(filterFilename);
83 if (!filterFile.good())
84 {
85 return;
86 }
87 nlohmann::json sensorFilterJSON = nlohmann::json::parse(filterFile, nullptr,
88 false);
89 nlohmann::json::iterator svcFilterit =
90 sensorFilterJSON.find("ServiceFilter");
91 if (svcFilterit == sensorFilterJSON.end())
92 {
93 return;
94 }
95
96 subtree.erase(std::remove_if(subtree.begin(), subtree.end(),
97 [svcFilterit](SensorSubTree::value_type& kv) {
98 auto& [_, serviceToIfaces] = kv;
99
100 for (auto service = svcFilterit->begin(); service != svcFilterit->end();
101 ++service)
102 {
103 serviceToIfaces.erase(*service);
104 }
105 return serviceToIfaces.empty();
106 }),
107 subtree.end());
108}
109
Kuiying Wanga8b5b262021-02-06 23:38:22 +0800110uint16_t getSensorSubtree(std::shared_ptr<SensorSubTree>& subtree)
Willy Tude54f482021-01-26 15:59:09 -0800111{
112 static std::shared_ptr<SensorSubTree> sensorTreePtr;
Kuiying Wanga8b5b262021-02-06 23:38:22 +0800113 static uint16_t sensorUpdatedIndex = 0;
Willy Tude54f482021-01-26 15:59:09 -0800114 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williams5d82f472022-07-22 19:26:53 -0500115 static sdbusplus::bus::match_t sensorAdded(
Willy Tude54f482021-01-26 15:59:09 -0800116 *dbus,
117 "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/"
118 "sensors/'",
Patrick Williams5d82f472022-07-22 19:26:53 -0500119 [](sdbusplus::message_t&) { sensorTreePtr.reset(); });
Willy Tude54f482021-01-26 15:59:09 -0800120
Patrick Williams5d82f472022-07-22 19:26:53 -0500121 static sdbusplus::bus::match_t sensorRemoved(
Willy Tude54f482021-01-26 15:59:09 -0800122 *dbus,
123 "type='signal',member='InterfacesRemoved',arg0path='/xyz/"
124 "openbmc_project/sensors/'",
Patrick Williams5d82f472022-07-22 19:26:53 -0500125 [](sdbusplus::message_t&) { sensorTreePtr.reset(); });
Willy Tude54f482021-01-26 15:59:09 -0800126
Willy Tude54f482021-01-26 15:59:09 -0800127 if (sensorTreePtr)
128 {
129 subtree = sensorTreePtr;
Kuiying Wanga8b5b262021-02-06 23:38:22 +0800130 return sensorUpdatedIndex;
Willy Tude54f482021-01-26 15:59:09 -0800131 }
132
133 sensorTreePtr = std::make_shared<SensorSubTree>();
134
Willy Tude54f482021-01-26 15:59:09 -0800135 static constexpr const int32_t depth = 2;
Hao Jiang9a5b51e2021-01-06 10:32:22 -0800136
Patrick Williams369824e2023-10-20 11:18:23 -0500137 auto lbdUpdateSensorTree = [&dbus](const char* path,
138 const auto& interfaces) {
Hao Jiang9a5b51e2021-01-06 10:32:22 -0800139 auto mapperCall = dbus->new_method_call(
140 "xyz.openbmc_project.ObjectMapper",
141 "/xyz/openbmc_project/object_mapper",
142 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
143 SensorSubTree sensorTreePartial;
144
145 mapperCall.append(path, depth, interfaces);
146
147 try
148 {
149 auto mapperReply = dbus->call(mapperCall);
150 mapperReply.read(sensorTreePartial);
151 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500152 catch (const sdbusplus::exception_t& e)
Hao Jiang9a5b51e2021-01-06 10:32:22 -0800153 {
154 phosphor::logging::log<phosphor::logging::level::ERR>(
155 "fail to update subtree",
156 phosphor::logging::entry("PATH=%s", path),
157 phosphor::logging::entry("WHAT=%s", e.what()));
158 return false;
159 }
160 if constexpr (debug)
161 {
162 std::fprintf(stderr, "IPMI updated: %zu sensors under %s\n",
163 sensorTreePartial.size(), path);
164 }
165 sensorTreePtr->merge(std::move(sensorTreePartial));
166 return true;
167 };
168
169 // Add sensors to SensorTree
170 static constexpr const std::array sensorInterfaces = {
Willy Tude54f482021-01-26 15:59:09 -0800171 "xyz.openbmc_project.Sensor.Value",
Jie Yangf0a89942021-07-29 15:30:25 -0700172 "xyz.openbmc_project.Sensor.ValueMutability",
Willy Tude54f482021-01-26 15:59:09 -0800173 "xyz.openbmc_project.Sensor.Threshold.Warning",
174 "xyz.openbmc_project.Sensor.Threshold.Critical"};
Hao Jiang9a5b51e2021-01-06 10:32:22 -0800175 static constexpr const std::array vrInterfaces = {
176 "xyz.openbmc_project.Control.VoltageRegulatorMode"};
Willy Tude54f482021-01-26 15:59:09 -0800177
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500178 bool sensorRez = lbdUpdateSensorTree("/xyz/openbmc_project/sensors",
179 sensorInterfaces);
Hao Jiang9a5b51e2021-01-06 10:32:22 -0800180
Scron Chang2703b022021-07-06 15:47:45 +0800181#ifdef FEATURE_HYBRID_SENSORS
182
183 if (!ipmi::sensor::sensors.empty())
184 {
185 for (const auto& sensor : ipmi::sensor::sensors)
186 {
187 // Threshold sensors should not be emplaced in here.
188 if (boost::starts_with(sensor.second.sensorPath,
189 "/xyz/openbmc_project/sensors/"))
190 {
191 continue;
192 }
193
194 // The bus service name is not listed in ipmi::sensor::Info. Give it
195 // an empty string. For those function using non-threshold sensors,
196 // the bus service name will be retrieved in an alternative way.
197 boost::container::flat_map<std::string, std::vector<std::string>>
198 connectionMap{
199 {"", {sensor.second.propertyInterfaces.begin()->first}}};
200 sensorTreePtr->emplace(sensor.second.sensorPath, connectionMap);
201 }
202 }
203
204#endif
205
Hao Jiang9a5b51e2021-01-06 10:32:22 -0800206 // Error if searching for sensors failed.
207 if (!sensorRez)
Willy Tude54f482021-01-26 15:59:09 -0800208 {
Kuiying Wanga8b5b262021-02-06 23:38:22 +0800209 return sensorUpdatedIndex;
Willy Tude54f482021-01-26 15:59:09 -0800210 }
Hao Jiang9a5b51e2021-01-06 10:32:22 -0800211
Johnathan Mantey04b0b072023-10-10 12:30:35 -0700212 filterSensors(*sensorTreePtr);
Hao Jiang9a5b51e2021-01-06 10:32:22 -0800213 // Add VR control as optional search path.
214 (void)lbdUpdateSensorTree("/xyz/openbmc_project/vr", vrInterfaces);
215
Willy Tude54f482021-01-26 15:59:09 -0800216 subtree = sensorTreePtr;
Kuiying Wanga8b5b262021-02-06 23:38:22 +0800217 sensorUpdatedIndex++;
Josh Lehana55c9532020-10-28 21:59:06 -0700218 // The SDR is being regenerated, wipe the old stats
219 sdrStatsTable.wipeTable();
Jie Yangf0a89942021-07-29 15:30:25 -0700220 sdrWriteTable.wipeTable();
Kuiying Wanga8b5b262021-02-06 23:38:22 +0800221 return sensorUpdatedIndex;
Willy Tude54f482021-01-26 15:59:09 -0800222}
223
224bool getSensorNumMap(std::shared_ptr<SensorNumMap>& sensorNumMap)
225{
226 static std::shared_ptr<SensorNumMap> sensorNumMapPtr;
227 bool sensorNumMapUpated = false;
Kuiying Wanga8b5b262021-02-06 23:38:22 +0800228 static uint16_t prevSensorUpdatedIndex = 0;
Willy Tude54f482021-01-26 15:59:09 -0800229 std::shared_ptr<SensorSubTree> sensorTree;
Kuiying Wanga8b5b262021-02-06 23:38:22 +0800230 uint16_t curSensorUpdatedIndex = details::getSensorSubtree(sensorTree);
Willy Tude54f482021-01-26 15:59:09 -0800231 if (!sensorTree)
232 {
233 return sensorNumMapUpated;
234 }
235
Kuiying Wanga8b5b262021-02-06 23:38:22 +0800236 if ((curSensorUpdatedIndex == prevSensorUpdatedIndex) && sensorNumMapPtr)
Willy Tude54f482021-01-26 15:59:09 -0800237 {
238 sensorNumMap = sensorNumMapPtr;
239 return sensorNumMapUpated;
240 }
Kuiying Wanga8b5b262021-02-06 23:38:22 +0800241 prevSensorUpdatedIndex = curSensorUpdatedIndex;
Willy Tude54f482021-01-26 15:59:09 -0800242
243 sensorNumMapPtr = std::make_shared<SensorNumMap>();
244
245 uint16_t sensorNum = 0;
246 uint16_t sensorIndex = 0;
247 for (const auto& sensor : *sensorTree)
248 {
249 sensorNumMapPtr->insert(
250 SensorNumMap::value_type(sensorNum, sensor.first));
251 sensorIndex++;
252 if (sensorIndex == maxSensorsPerLUN)
253 {
254 sensorIndex = lun1Sensor0;
255 }
256 else if (sensorIndex == (lun1Sensor0 | maxSensorsPerLUN))
257 {
258 // Skip assigning LUN 0x2 any sensors
259 sensorIndex = lun3Sensor0;
260 }
261 else if (sensorIndex == (lun3Sensor0 | maxSensorsPerLUN))
262 {
263 // this is an error, too many IPMI sensors
264 throw std::out_of_range("Maximum number of IPMI sensors exceeded.");
265 }
266 sensorNum = sensorIndex;
267 }
268 sensorNumMap = sensorNumMapPtr;
269 sensorNumMapUpated = true;
270 return sensorNumMapUpated;
271}
272} // namespace details
273
274bool getSensorSubtree(SensorSubTree& subtree)
275{
276 std::shared_ptr<SensorSubTree> sensorTree;
277 details::getSensorSubtree(sensorTree);
278 if (!sensorTree)
279 {
280 return false;
281 }
282
283 subtree = *sensorTree;
284 return true;
285}
286
Scron Chang2703b022021-07-06 15:47:45 +0800287#ifdef FEATURE_HYBRID_SENSORS
288// Static sensors are listed in sensor-gen.cpp.
289ipmi::sensor::IdInfoMap::const_iterator
290 findStaticSensor(const std::string& path)
291{
292 return std::find_if(
293 ipmi::sensor::sensors.begin(), ipmi::sensor::sensors.end(),
294 [&path](const ipmi::sensor::IdInfoMap::value_type& findSensor) {
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500295 return findSensor.second.sensorPath == path;
Patrick Williams369824e2023-10-20 11:18:23 -0500296 });
Scron Chang2703b022021-07-06 15:47:45 +0800297}
298#endif
299
Willy Tude54f482021-01-26 15:59:09 -0800300std::string getSensorTypeStringFromPath(const std::string& path)
301{
302 // get sensor type string from path, path is defined as
303 // /xyz/openbmc_project/sensors/<type>/label
304 size_t typeEnd = path.rfind("/");
305 if (typeEnd == std::string::npos)
306 {
307 return path;
308 }
309 size_t typeStart = path.rfind("/", typeEnd - 1);
310 if (typeStart == std::string::npos)
311 {
312 return path;
313 }
314 // Start at the character after the '/'
315 typeStart++;
316 return path.substr(typeStart, typeEnd - typeStart);
317}
318
319uint8_t getSensorTypeFromPath(const std::string& path)
320{
321 uint8_t sensorType = 0;
322 std::string type = getSensorTypeStringFromPath(path);
323 auto findSensor = sensorTypes.find(type.c_str());
324 if (findSensor != sensorTypes.end())
325 {
Scron Chang2b42d7e2021-07-06 15:45:47 +0800326 sensorType =
327 static_cast<uint8_t>(std::get<sensorTypeCodes>(findSensor->second));
Willy Tude54f482021-01-26 15:59:09 -0800328 } // else default 0x0 RESERVED
329
330 return sensorType;
331}
332
333uint16_t getSensorNumberFromPath(const std::string& path)
334{
335 std::shared_ptr<SensorNumMap> sensorNumMapPtr;
336 details::getSensorNumMap(sensorNumMapPtr);
337 if (!sensorNumMapPtr)
338 {
339 return invalidSensorNumber;
340 }
341
342 try
343 {
344 return sensorNumMapPtr->right.at(path);
345 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500346 catch (const std::out_of_range& e)
Willy Tude54f482021-01-26 15:59:09 -0800347 {
Willy Tude54f482021-01-26 15:59:09 -0800348 return invalidSensorNumber;
349 }
350}
351
352uint8_t getSensorEventTypeFromPath(const std::string& path)
353{
Scron Chang2b42d7e2021-07-06 15:45:47 +0800354 uint8_t sensorEventType = 0;
355 std::string type = getSensorTypeStringFromPath(path);
356 auto findSensor = sensorTypes.find(type.c_str());
357 if (findSensor != sensorTypes.end())
358 {
359 sensorEventType = static_cast<uint8_t>(
360 std::get<sensorEventTypeCodes>(findSensor->second));
361 }
362
363 return sensorEventType;
Willy Tude54f482021-01-26 15:59:09 -0800364}
365
366std::string getPathFromSensorNumber(uint16_t sensorNum)
367{
368 std::shared_ptr<SensorNumMap> sensorNumMapPtr;
369 details::getSensorNumMap(sensorNumMapPtr);
370 if (!sensorNumMapPtr)
371 {
372 return std::string();
373 }
374
375 try
376 {
377 return sensorNumMapPtr->left.at(sensorNum);
378 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500379 catch (const std::out_of_range& e)
Willy Tude54f482021-01-26 15:59:09 -0800380 {
Willy Tude54f482021-01-26 15:59:09 -0800381 return std::string();
382 }
383}
384
385namespace ipmi
386{
387
Alexander Hansen8fb5b892023-11-02 17:29:34 +0100388std::optional<std::map<std::string, std::vector<std::string>>>
Willy Tude54f482021-01-26 15:59:09 -0800389 getObjectInterfaces(const char* path)
390{
391 std::map<std::string, std::vector<std::string>> interfacesResponse;
392 std::vector<std::string> interfaces;
393 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
394
Patrick Williams5d82f472022-07-22 19:26:53 -0500395 sdbusplus::message_t getObjectMessage =
Willy Tude54f482021-01-26 15:59:09 -0800396 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
397 "/xyz/openbmc_project/object_mapper",
398 "xyz.openbmc_project.ObjectMapper", "GetObject");
399 getObjectMessage.append(path, interfaces);
400
401 try
402 {
Patrick Williams5d82f472022-07-22 19:26:53 -0500403 sdbusplus::message_t response = dbus->call(getObjectMessage);
Willy Tude54f482021-01-26 15:59:09 -0800404 response.read(interfacesResponse);
405 }
406 catch (const std::exception& e)
407 {
Alexander Hansen8fb5b892023-11-02 17:29:34 +0100408 return std::nullopt;
Willy Tude54f482021-01-26 15:59:09 -0800409 }
410
411 return interfacesResponse;
412}
413
414std::map<std::string, Value> getEntityManagerProperties(const char* path,
415 const char* interface)
416{
417 std::map<std::string, Value> properties;
418 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
419
Patrick Williams5d82f472022-07-22 19:26:53 -0500420 sdbusplus::message_t getProperties =
Willy Tude54f482021-01-26 15:59:09 -0800421 dbus->new_method_call("xyz.openbmc_project.EntityManager", path,
422 "org.freedesktop.DBus.Properties", "GetAll");
423 getProperties.append(interface);
424
425 try
426 {
Patrick Williams5d82f472022-07-22 19:26:53 -0500427 sdbusplus::message_t response = dbus->call(getProperties);
Willy Tude54f482021-01-26 15:59:09 -0800428 response.read(properties);
429 }
430 catch (const std::exception& e)
431 {
432 phosphor::logging::log<phosphor::logging::level::ERR>(
433 "Failed to GetAll", phosphor::logging::entry("PATH=%s", path),
434 phosphor::logging::entry("INTF=%s", interface),
435 phosphor::logging::entry("WHAT=%s", e.what()));
436 }
437
438 return properties;
439}
440
Willy Tu4eca2512022-06-20 21:14:51 -0700441// Fetch the ipmiDecoratorPaths to get the list of dbus objects that
442// have ipmi decorator to prevent unnessary dbus call to fetch the info
443std::optional<std::unordered_set<std::string>>&
444 getIpmiDecoratorPaths(const std::optional<ipmi::Context::ptr>& ctx)
445{
446 static std::optional<std::unordered_set<std::string>> ipmiDecoratorPaths;
447
448 if (!ctx.has_value() || ipmiDecoratorPaths != std::nullopt)
449 {
450 return ipmiDecoratorPaths;
451 }
452
453 boost::system::error_code ec;
454 std::vector<std::string> paths =
455 (*ctx)->bus->yield_method_call<std::vector<std::string>>(
456 (*ctx)->yield, ec, "xyz.openbmc_project.ObjectMapper",
457 "/xyz/openbmc_project/object_mapper",
458 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/",
459 int32_t(0),
460 std::array<const char*, 1>{
461 "xyz.openbmc_project.Inventory.Decorator.Ipmi"});
462 if (ec)
463 {
464 return ipmiDecoratorPaths;
465 }
466
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500467 ipmiDecoratorPaths = std::unordered_set<std::string>(paths.begin(),
468 paths.end());
Willy Tu4eca2512022-06-20 21:14:51 -0700469 return ipmiDecoratorPaths;
470}
471
Willy Tude54f482021-01-26 15:59:09 -0800472const std::string* getSensorConfigurationInterface(
473 const std::map<std::string, std::vector<std::string>>&
474 sensorInterfacesResponse)
475{
476 auto entityManagerService =
477 sensorInterfacesResponse.find("xyz.openbmc_project.EntityManager");
478 if (entityManagerService == sensorInterfacesResponse.end())
479 {
480 return nullptr;
481 }
482
483 // Find the fan configuration first (fans can have multiple configuration
484 // interfaces).
485 for (const auto& entry : entityManagerService->second)
486 {
487 if (entry == "xyz.openbmc_project.Configuration.AspeedFan" ||
488 entry == "xyz.openbmc_project.Configuration.I2CFan" ||
489 entry == "xyz.openbmc_project.Configuration.NuvotonFan")
490 {
491 return &entry;
492 }
493 }
494
495 for (const auto& entry : entityManagerService->second)
496 {
497 if (boost::algorithm::starts_with(entry,
498 "xyz.openbmc_project.Configuration."))
499 {
500 return &entry;
501 }
502 }
503
504 return nullptr;
505}
506
507// Follow Association properties for Sensor back to the Board dbus object to
508// check for an EntityId and EntityInstance property.
Willy Tu4eca2512022-06-20 21:14:51 -0700509void updateIpmiFromAssociation(
510 const std::string& path,
511 const std::unordered_set<std::string>& ipmiDecoratorPaths,
512 const DbusInterfaceMap& sensorMap, uint8_t& entityId,
513 uint8_t& entityInstance)
Willy Tude54f482021-01-26 15:59:09 -0800514{
515 namespace fs = std::filesystem;
516
517 auto sensorAssociationObject =
518 sensorMap.find("xyz.openbmc_project.Association.Definitions");
519 if (sensorAssociationObject == sensorMap.end())
520 {
521 if constexpr (debug)
522 {
523 std::fprintf(stderr, "path=%s, no association interface found\n",
524 path.c_str());
525 }
526
527 return;
528 }
529
530 auto associationObject =
531 sensorAssociationObject->second.find("Associations");
532 if (associationObject == sensorAssociationObject->second.end())
533 {
534 if constexpr (debug)
535 {
536 std::fprintf(stderr, "path=%s, no association records found\n",
537 path.c_str());
538 }
539
540 return;
541 }
542
543 std::vector<Association> associationValues =
544 std::get<std::vector<Association>>(associationObject->second);
545
546 // loop through the Associations looking for the right one:
547 for (const auto& entry : associationValues)
548 {
549 // forward, reverse, endpoint
550 const std::string& forward = std::get<0>(entry);
551 const std::string& reverse = std::get<1>(entry);
552 const std::string& endpoint = std::get<2>(entry);
553
554 // We only currently concern ourselves with chassis+all_sensors.
555 if (!(forward == "chassis" && reverse == "all_sensors"))
556 {
557 continue;
558 }
559
560 // the endpoint is the board entry provided by
561 // Entity-Manager. so let's grab its properties if it has
562 // the right interface.
563
564 // just try grabbing the properties first.
Willy Tu4eca2512022-06-20 21:14:51 -0700565 ipmi::PropertyMap::iterator entityIdProp;
566 ipmi::PropertyMap::iterator entityInstanceProp;
567 if (ipmiDecoratorPaths.contains(endpoint))
568 {
569 std::map<std::string, Value> ipmiProperties =
570 getEntityManagerProperties(
571 endpoint.c_str(),
572 "xyz.openbmc_project.Inventory.Decorator.Ipmi");
Willy Tude54f482021-01-26 15:59:09 -0800573
Willy Tu4eca2512022-06-20 21:14:51 -0700574 entityIdProp = ipmiProperties.find("EntityId");
575 entityInstanceProp = ipmiProperties.find("EntityInstance");
576 if (entityIdProp != ipmiProperties.end())
577 {
578 entityId = static_cast<uint8_t>(
579 std::get<uint64_t>(entityIdProp->second));
580 }
581 if (entityInstanceProp != ipmiProperties.end())
582 {
583 entityInstance = static_cast<uint8_t>(
584 std::get<uint64_t>(entityInstanceProp->second));
585 }
Willy Tude54f482021-01-26 15:59:09 -0800586 }
587
588 // Now check the entity-manager entry for this sensor to see
589 // if it has its own value and use that instead.
590 //
591 // In theory, checking this first saves us from checking
592 // both, except in most use-cases identified, there won't be
593 // a per sensor override, so we need to always check both.
594 std::string sensorNameFromPath = fs::path(path).filename();
595
596 std::string sensorConfigPath = endpoint + "/" + sensorNameFromPath;
597
598 // Download the interfaces for the sensor from
599 // Entity-Manager to find the name of the configuration
600 // interface.
Alexander Hansen8fb5b892023-11-02 17:29:34 +0100601 std::optional<std::map<std::string, std::vector<std::string>>>
602 sensorInterfacesResponseOpt =
Willy Tude54f482021-01-26 15:59:09 -0800603 getObjectInterfaces(sensorConfigPath.c_str());
604
Alexander Hansen8fb5b892023-11-02 17:29:34 +0100605 if (!sensorInterfacesResponseOpt.has_value())
606 {
607 phosphor::logging::log<phosphor::logging::level::DEBUG>(
608 "Failed to GetObject",
609 phosphor::logging::entry("PATH=%s", sensorConfigPath.c_str()));
610 continue;
611 }
612
Willy Tude54f482021-01-26 15:59:09 -0800613 const std::string* configurationInterface =
Alexander Hansen8fb5b892023-11-02 17:29:34 +0100614 getSensorConfigurationInterface(
615 sensorInterfacesResponseOpt.value());
Willy Tude54f482021-01-26 15:59:09 -0800616
Harvey Wu7bb84db2023-06-26 10:02:08 +0800617 // If there are multi association path settings and only one path exist,
618 // we need to continue if cannot find configuration interface for this
619 // sensor.
Willy Tude54f482021-01-26 15:59:09 -0800620 if (!configurationInterface)
621 {
Harvey Wu7bb84db2023-06-26 10:02:08 +0800622 continue;
Willy Tude54f482021-01-26 15:59:09 -0800623 }
624
625 // We found a configuration interface.
626 std::map<std::string, Value> configurationProperties =
627 getEntityManagerProperties(sensorConfigPath.c_str(),
628 configurationInterface->c_str());
629
630 entityIdProp = configurationProperties.find("EntityId");
631 entityInstanceProp = configurationProperties.find("EntityInstance");
632 if (entityIdProp != configurationProperties.end())
633 {
634 entityId =
635 static_cast<uint8_t>(std::get<uint64_t>(entityIdProp->second));
636 }
637 if (entityInstanceProp != configurationProperties.end())
638 {
639 entityInstance = static_cast<uint8_t>(
640 std::get<uint64_t>(entityInstanceProp->second));
641 }
642
643 // stop searching Association records.
644 break;
645 } // end for Association vectors.
646
647 if constexpr (debug)
648 {
649 std::fprintf(stderr, "path=%s, entityId=%d, entityInstance=%d\n",
650 path.c_str(), entityId, entityInstance);
651 }
652}
653
654} // namespace ipmi