blob: fa96c6b63bc58ecc8aeec983371a9850cd9c9d5c [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
Willy Tude54f482021-01-26 15:59:09 -080039namespace details
40{
Johnathan Mantey04b0b072023-10-10 12:30:35 -070041
42// IPMI supports a smaller number of sensors than are available via Redfish.
43// Trim the list of sensors, via a configuration file.
44// Read the IPMI Sensor Filtering section in docs/configuration.md for
45// a more detailed description.
46static void filterSensors(SensorSubTree& subtree)
47{
48 constexpr const char* filterFilename =
49 "/usr/share/ipmi-providers/sensor_filter.json";
50 std::ifstream filterFile(filterFilename);
51 if (!filterFile.good())
52 {
53 return;
54 }
55 nlohmann::json sensorFilterJSON = nlohmann::json::parse(filterFile, nullptr,
56 false);
57 nlohmann::json::iterator svcFilterit =
58 sensorFilterJSON.find("ServiceFilter");
59 if (svcFilterit == sensorFilterJSON.end())
60 {
61 return;
62 }
63
64 subtree.erase(std::remove_if(subtree.begin(), subtree.end(),
65 [svcFilterit](SensorSubTree::value_type& kv) {
66 auto& [_, serviceToIfaces] = kv;
67
68 for (auto service = svcFilterit->begin(); service != svcFilterit->end();
69 ++service)
70 {
71 serviceToIfaces.erase(*service);
72 }
73 return serviceToIfaces.empty();
74 }),
75 subtree.end());
76}
77
Kuiying Wanga8b5b262021-02-06 23:38:22 +080078uint16_t getSensorSubtree(std::shared_ptr<SensorSubTree>& subtree)
Willy Tude54f482021-01-26 15:59:09 -080079{
80 static std::shared_ptr<SensorSubTree> sensorTreePtr;
Kuiying Wanga8b5b262021-02-06 23:38:22 +080081 static uint16_t sensorUpdatedIndex = 0;
Willy Tude54f482021-01-26 15:59:09 -080082 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williams5d82f472022-07-22 19:26:53 -050083 static sdbusplus::bus::match_t sensorAdded(
Willy Tude54f482021-01-26 15:59:09 -080084 *dbus,
85 "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/"
86 "sensors/'",
Patrick Williams5d82f472022-07-22 19:26:53 -050087 [](sdbusplus::message_t&) { sensorTreePtr.reset(); });
Willy Tude54f482021-01-26 15:59:09 -080088
Patrick Williams5d82f472022-07-22 19:26:53 -050089 static sdbusplus::bus::match_t sensorRemoved(
Willy Tude54f482021-01-26 15:59:09 -080090 *dbus,
91 "type='signal',member='InterfacesRemoved',arg0path='/xyz/"
92 "openbmc_project/sensors/'",
Patrick Williams5d82f472022-07-22 19:26:53 -050093 [](sdbusplus::message_t&) { sensorTreePtr.reset(); });
Willy Tude54f482021-01-26 15:59:09 -080094
Willy Tude54f482021-01-26 15:59:09 -080095 if (sensorTreePtr)
96 {
97 subtree = sensorTreePtr;
Kuiying Wanga8b5b262021-02-06 23:38:22 +080098 return sensorUpdatedIndex;
Willy Tude54f482021-01-26 15:59:09 -080099 }
100
101 sensorTreePtr = std::make_shared<SensorSubTree>();
102
Willy Tude54f482021-01-26 15:59:09 -0800103 static constexpr const int32_t depth = 2;
Hao Jiang9a5b51e2021-01-06 10:32:22 -0800104
Patrick Williams369824e2023-10-20 11:18:23 -0500105 auto lbdUpdateSensorTree = [&dbus](const char* path,
106 const auto& interfaces) {
Hao Jiang9a5b51e2021-01-06 10:32:22 -0800107 auto mapperCall = dbus->new_method_call(
108 "xyz.openbmc_project.ObjectMapper",
109 "/xyz/openbmc_project/object_mapper",
110 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
111 SensorSubTree sensorTreePartial;
112
113 mapperCall.append(path, depth, interfaces);
114
115 try
116 {
117 auto mapperReply = dbus->call(mapperCall);
118 mapperReply.read(sensorTreePartial);
119 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500120 catch (const sdbusplus::exception_t& e)
Hao Jiang9a5b51e2021-01-06 10:32:22 -0800121 {
122 phosphor::logging::log<phosphor::logging::level::ERR>(
123 "fail to update subtree",
124 phosphor::logging::entry("PATH=%s", path),
125 phosphor::logging::entry("WHAT=%s", e.what()));
126 return false;
127 }
128 if constexpr (debug)
129 {
130 std::fprintf(stderr, "IPMI updated: %zu sensors under %s\n",
131 sensorTreePartial.size(), path);
132 }
133 sensorTreePtr->merge(std::move(sensorTreePartial));
134 return true;
135 };
136
137 // Add sensors to SensorTree
138 static constexpr const std::array sensorInterfaces = {
Willy Tude54f482021-01-26 15:59:09 -0800139 "xyz.openbmc_project.Sensor.Value",
Jie Yangf0a89942021-07-29 15:30:25 -0700140 "xyz.openbmc_project.Sensor.ValueMutability",
Willy Tude54f482021-01-26 15:59:09 -0800141 "xyz.openbmc_project.Sensor.Threshold.Warning",
142 "xyz.openbmc_project.Sensor.Threshold.Critical"};
Hao Jiang9a5b51e2021-01-06 10:32:22 -0800143 static constexpr const std::array vrInterfaces = {
144 "xyz.openbmc_project.Control.VoltageRegulatorMode"};
Willy Tude54f482021-01-26 15:59:09 -0800145
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500146 bool sensorRez = lbdUpdateSensorTree("/xyz/openbmc_project/sensors",
147 sensorInterfaces);
Hao Jiang9a5b51e2021-01-06 10:32:22 -0800148
Scron Chang2703b022021-07-06 15:47:45 +0800149#ifdef FEATURE_HYBRID_SENSORS
150
151 if (!ipmi::sensor::sensors.empty())
152 {
153 for (const auto& sensor : ipmi::sensor::sensors)
154 {
155 // Threshold sensors should not be emplaced in here.
156 if (boost::starts_with(sensor.second.sensorPath,
157 "/xyz/openbmc_project/sensors/"))
158 {
159 continue;
160 }
161
162 // The bus service name is not listed in ipmi::sensor::Info. Give it
163 // an empty string. For those function using non-threshold sensors,
164 // the bus service name will be retrieved in an alternative way.
165 boost::container::flat_map<std::string, std::vector<std::string>>
166 connectionMap{
167 {"", {sensor.second.propertyInterfaces.begin()->first}}};
168 sensorTreePtr->emplace(sensor.second.sensorPath, connectionMap);
169 }
170 }
171
172#endif
173
Hao Jiang9a5b51e2021-01-06 10:32:22 -0800174 // Error if searching for sensors failed.
175 if (!sensorRez)
Willy Tude54f482021-01-26 15:59:09 -0800176 {
Kuiying Wanga8b5b262021-02-06 23:38:22 +0800177 return sensorUpdatedIndex;
Willy Tude54f482021-01-26 15:59:09 -0800178 }
Hao Jiang9a5b51e2021-01-06 10:32:22 -0800179
Johnathan Mantey04b0b072023-10-10 12:30:35 -0700180 filterSensors(*sensorTreePtr);
Hao Jiang9a5b51e2021-01-06 10:32:22 -0800181 // Add VR control as optional search path.
182 (void)lbdUpdateSensorTree("/xyz/openbmc_project/vr", vrInterfaces);
183
Willy Tude54f482021-01-26 15:59:09 -0800184 subtree = sensorTreePtr;
Kuiying Wanga8b5b262021-02-06 23:38:22 +0800185 sensorUpdatedIndex++;
Josh Lehana55c9532020-10-28 21:59:06 -0700186 // The SDR is being regenerated, wipe the old stats
187 sdrStatsTable.wipeTable();
Jie Yangf0a89942021-07-29 15:30:25 -0700188 sdrWriteTable.wipeTable();
Kuiying Wanga8b5b262021-02-06 23:38:22 +0800189 return sensorUpdatedIndex;
Willy Tude54f482021-01-26 15:59:09 -0800190}
191
192bool getSensorNumMap(std::shared_ptr<SensorNumMap>& sensorNumMap)
193{
194 static std::shared_ptr<SensorNumMap> sensorNumMapPtr;
195 bool sensorNumMapUpated = false;
Kuiying Wanga8b5b262021-02-06 23:38:22 +0800196 static uint16_t prevSensorUpdatedIndex = 0;
Willy Tude54f482021-01-26 15:59:09 -0800197 std::shared_ptr<SensorSubTree> sensorTree;
Kuiying Wanga8b5b262021-02-06 23:38:22 +0800198 uint16_t curSensorUpdatedIndex = details::getSensorSubtree(sensorTree);
Willy Tude54f482021-01-26 15:59:09 -0800199 if (!sensorTree)
200 {
201 return sensorNumMapUpated;
202 }
203
Kuiying Wanga8b5b262021-02-06 23:38:22 +0800204 if ((curSensorUpdatedIndex == prevSensorUpdatedIndex) && sensorNumMapPtr)
Willy Tude54f482021-01-26 15:59:09 -0800205 {
206 sensorNumMap = sensorNumMapPtr;
207 return sensorNumMapUpated;
208 }
Kuiying Wanga8b5b262021-02-06 23:38:22 +0800209 prevSensorUpdatedIndex = curSensorUpdatedIndex;
Willy Tude54f482021-01-26 15:59:09 -0800210
211 sensorNumMapPtr = std::make_shared<SensorNumMap>();
212
213 uint16_t sensorNum = 0;
214 uint16_t sensorIndex = 0;
215 for (const auto& sensor : *sensorTree)
216 {
217 sensorNumMapPtr->insert(
218 SensorNumMap::value_type(sensorNum, sensor.first));
219 sensorIndex++;
220 if (sensorIndex == maxSensorsPerLUN)
221 {
222 sensorIndex = lun1Sensor0;
223 }
224 else if (sensorIndex == (lun1Sensor0 | maxSensorsPerLUN))
225 {
226 // Skip assigning LUN 0x2 any sensors
227 sensorIndex = lun3Sensor0;
228 }
229 else if (sensorIndex == (lun3Sensor0 | maxSensorsPerLUN))
230 {
231 // this is an error, too many IPMI sensors
232 throw std::out_of_range("Maximum number of IPMI sensors exceeded.");
233 }
234 sensorNum = sensorIndex;
235 }
236 sensorNumMap = sensorNumMapPtr;
237 sensorNumMapUpated = true;
238 return sensorNumMapUpated;
239}
240} // namespace details
241
242bool getSensorSubtree(SensorSubTree& subtree)
243{
244 std::shared_ptr<SensorSubTree> sensorTree;
245 details::getSensorSubtree(sensorTree);
246 if (!sensorTree)
247 {
248 return false;
249 }
250
251 subtree = *sensorTree;
252 return true;
253}
254
Scron Chang2703b022021-07-06 15:47:45 +0800255#ifdef FEATURE_HYBRID_SENSORS
256// Static sensors are listed in sensor-gen.cpp.
257ipmi::sensor::IdInfoMap::const_iterator
258 findStaticSensor(const std::string& path)
259{
260 return std::find_if(
261 ipmi::sensor::sensors.begin(), ipmi::sensor::sensors.end(),
262 [&path](const ipmi::sensor::IdInfoMap::value_type& findSensor) {
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500263 return findSensor.second.sensorPath == path;
Patrick Williams369824e2023-10-20 11:18:23 -0500264 });
Scron Chang2703b022021-07-06 15:47:45 +0800265}
266#endif
267
Willy Tude54f482021-01-26 15:59:09 -0800268std::string getSensorTypeStringFromPath(const std::string& path)
269{
270 // get sensor type string from path, path is defined as
271 // /xyz/openbmc_project/sensors/<type>/label
272 size_t typeEnd = path.rfind("/");
273 if (typeEnd == std::string::npos)
274 {
275 return path;
276 }
277 size_t typeStart = path.rfind("/", typeEnd - 1);
278 if (typeStart == std::string::npos)
279 {
280 return path;
281 }
282 // Start at the character after the '/'
283 typeStart++;
284 return path.substr(typeStart, typeEnd - typeStart);
285}
286
287uint8_t getSensorTypeFromPath(const std::string& path)
288{
289 uint8_t sensorType = 0;
290 std::string type = getSensorTypeStringFromPath(path);
291 auto findSensor = sensorTypes.find(type.c_str());
292 if (findSensor != sensorTypes.end())
293 {
Scron Chang2b42d7e2021-07-06 15:45:47 +0800294 sensorType =
295 static_cast<uint8_t>(std::get<sensorTypeCodes>(findSensor->second));
Willy Tude54f482021-01-26 15:59:09 -0800296 } // else default 0x0 RESERVED
297
298 return sensorType;
299}
300
301uint16_t getSensorNumberFromPath(const std::string& path)
302{
303 std::shared_ptr<SensorNumMap> sensorNumMapPtr;
304 details::getSensorNumMap(sensorNumMapPtr);
305 if (!sensorNumMapPtr)
306 {
307 return invalidSensorNumber;
308 }
309
310 try
311 {
312 return sensorNumMapPtr->right.at(path);
313 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500314 catch (const std::out_of_range& e)
Willy Tude54f482021-01-26 15:59:09 -0800315 {
Willy Tude54f482021-01-26 15:59:09 -0800316 return invalidSensorNumber;
317 }
318}
319
320uint8_t getSensorEventTypeFromPath(const std::string& path)
321{
Scron Chang2b42d7e2021-07-06 15:45:47 +0800322 uint8_t sensorEventType = 0;
323 std::string type = getSensorTypeStringFromPath(path);
324 auto findSensor = sensorTypes.find(type.c_str());
325 if (findSensor != sensorTypes.end())
326 {
327 sensorEventType = static_cast<uint8_t>(
328 std::get<sensorEventTypeCodes>(findSensor->second));
329 }
330
331 return sensorEventType;
Willy Tude54f482021-01-26 15:59:09 -0800332}
333
334std::string getPathFromSensorNumber(uint16_t sensorNum)
335{
336 std::shared_ptr<SensorNumMap> sensorNumMapPtr;
337 details::getSensorNumMap(sensorNumMapPtr);
338 if (!sensorNumMapPtr)
339 {
340 return std::string();
341 }
342
343 try
344 {
345 return sensorNumMapPtr->left.at(sensorNum);
346 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500347 catch (const std::out_of_range& e)
Willy Tude54f482021-01-26 15:59:09 -0800348 {
Willy Tude54f482021-01-26 15:59:09 -0800349 return std::string();
350 }
351}
352
353namespace ipmi
354{
355
Alexander Hansen8fb5b892023-11-02 17:29:34 +0100356std::optional<std::map<std::string, std::vector<std::string>>>
Willy Tude54f482021-01-26 15:59:09 -0800357 getObjectInterfaces(const char* path)
358{
359 std::map<std::string, std::vector<std::string>> interfacesResponse;
360 std::vector<std::string> interfaces;
361 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
362
Patrick Williams5d82f472022-07-22 19:26:53 -0500363 sdbusplus::message_t getObjectMessage =
Willy Tude54f482021-01-26 15:59:09 -0800364 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
365 "/xyz/openbmc_project/object_mapper",
366 "xyz.openbmc_project.ObjectMapper", "GetObject");
367 getObjectMessage.append(path, interfaces);
368
369 try
370 {
Patrick Williams5d82f472022-07-22 19:26:53 -0500371 sdbusplus::message_t response = dbus->call(getObjectMessage);
Willy Tude54f482021-01-26 15:59:09 -0800372 response.read(interfacesResponse);
373 }
374 catch (const std::exception& e)
375 {
Alexander Hansen8fb5b892023-11-02 17:29:34 +0100376 return std::nullopt;
Willy Tude54f482021-01-26 15:59:09 -0800377 }
378
379 return interfacesResponse;
380}
381
382std::map<std::string, Value> getEntityManagerProperties(const char* path,
383 const char* interface)
384{
385 std::map<std::string, Value> properties;
386 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
387
Patrick Williams5d82f472022-07-22 19:26:53 -0500388 sdbusplus::message_t getProperties =
Willy Tude54f482021-01-26 15:59:09 -0800389 dbus->new_method_call("xyz.openbmc_project.EntityManager", path,
390 "org.freedesktop.DBus.Properties", "GetAll");
391 getProperties.append(interface);
392
393 try
394 {
Patrick Williams5d82f472022-07-22 19:26:53 -0500395 sdbusplus::message_t response = dbus->call(getProperties);
Willy Tude54f482021-01-26 15:59:09 -0800396 response.read(properties);
397 }
398 catch (const std::exception& e)
399 {
400 phosphor::logging::log<phosphor::logging::level::ERR>(
401 "Failed to GetAll", phosphor::logging::entry("PATH=%s", path),
402 phosphor::logging::entry("INTF=%s", interface),
403 phosphor::logging::entry("WHAT=%s", e.what()));
404 }
405
406 return properties;
407}
408
Willy Tu4eca2512022-06-20 21:14:51 -0700409// Fetch the ipmiDecoratorPaths to get the list of dbus objects that
410// have ipmi decorator to prevent unnessary dbus call to fetch the info
411std::optional<std::unordered_set<std::string>>&
412 getIpmiDecoratorPaths(const std::optional<ipmi::Context::ptr>& ctx)
413{
414 static std::optional<std::unordered_set<std::string>> ipmiDecoratorPaths;
415
416 if (!ctx.has_value() || ipmiDecoratorPaths != std::nullopt)
417 {
418 return ipmiDecoratorPaths;
419 }
420
421 boost::system::error_code ec;
422 std::vector<std::string> paths =
423 (*ctx)->bus->yield_method_call<std::vector<std::string>>(
424 (*ctx)->yield, ec, "xyz.openbmc_project.ObjectMapper",
425 "/xyz/openbmc_project/object_mapper",
426 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/",
427 int32_t(0),
428 std::array<const char*, 1>{
429 "xyz.openbmc_project.Inventory.Decorator.Ipmi"});
430 if (ec)
431 {
432 return ipmiDecoratorPaths;
433 }
434
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500435 ipmiDecoratorPaths = std::unordered_set<std::string>(paths.begin(),
436 paths.end());
Willy Tu4eca2512022-06-20 21:14:51 -0700437 return ipmiDecoratorPaths;
438}
439
Willy Tude54f482021-01-26 15:59:09 -0800440const std::string* getSensorConfigurationInterface(
441 const std::map<std::string, std::vector<std::string>>&
442 sensorInterfacesResponse)
443{
444 auto entityManagerService =
445 sensorInterfacesResponse.find("xyz.openbmc_project.EntityManager");
446 if (entityManagerService == sensorInterfacesResponse.end())
447 {
448 return nullptr;
449 }
450
451 // Find the fan configuration first (fans can have multiple configuration
452 // interfaces).
453 for (const auto& entry : entityManagerService->second)
454 {
455 if (entry == "xyz.openbmc_project.Configuration.AspeedFan" ||
456 entry == "xyz.openbmc_project.Configuration.I2CFan" ||
457 entry == "xyz.openbmc_project.Configuration.NuvotonFan")
458 {
459 return &entry;
460 }
461 }
462
463 for (const auto& entry : entityManagerService->second)
464 {
465 if (boost::algorithm::starts_with(entry,
466 "xyz.openbmc_project.Configuration."))
467 {
468 return &entry;
469 }
470 }
471
472 return nullptr;
473}
474
475// Follow Association properties for Sensor back to the Board dbus object to
476// check for an EntityId and EntityInstance property.
Willy Tu4eca2512022-06-20 21:14:51 -0700477void updateIpmiFromAssociation(
478 const std::string& path,
479 const std::unordered_set<std::string>& ipmiDecoratorPaths,
480 const DbusInterfaceMap& sensorMap, uint8_t& entityId,
481 uint8_t& entityInstance)
Willy Tude54f482021-01-26 15:59:09 -0800482{
483 namespace fs = std::filesystem;
484
485 auto sensorAssociationObject =
486 sensorMap.find("xyz.openbmc_project.Association.Definitions");
487 if (sensorAssociationObject == sensorMap.end())
488 {
489 if constexpr (debug)
490 {
491 std::fprintf(stderr, "path=%s, no association interface found\n",
492 path.c_str());
493 }
494
495 return;
496 }
497
498 auto associationObject =
499 sensorAssociationObject->second.find("Associations");
500 if (associationObject == sensorAssociationObject->second.end())
501 {
502 if constexpr (debug)
503 {
504 std::fprintf(stderr, "path=%s, no association records found\n",
505 path.c_str());
506 }
507
508 return;
509 }
510
511 std::vector<Association> associationValues =
512 std::get<std::vector<Association>>(associationObject->second);
513
514 // loop through the Associations looking for the right one:
515 for (const auto& entry : associationValues)
516 {
517 // forward, reverse, endpoint
518 const std::string& forward = std::get<0>(entry);
519 const std::string& reverse = std::get<1>(entry);
520 const std::string& endpoint = std::get<2>(entry);
521
522 // We only currently concern ourselves with chassis+all_sensors.
523 if (!(forward == "chassis" && reverse == "all_sensors"))
524 {
525 continue;
526 }
527
528 // the endpoint is the board entry provided by
529 // Entity-Manager. so let's grab its properties if it has
530 // the right interface.
531
532 // just try grabbing the properties first.
Willy Tu4eca2512022-06-20 21:14:51 -0700533 ipmi::PropertyMap::iterator entityIdProp;
534 ipmi::PropertyMap::iterator entityInstanceProp;
535 if (ipmiDecoratorPaths.contains(endpoint))
536 {
537 std::map<std::string, Value> ipmiProperties =
538 getEntityManagerProperties(
539 endpoint.c_str(),
540 "xyz.openbmc_project.Inventory.Decorator.Ipmi");
Willy Tude54f482021-01-26 15:59:09 -0800541
Willy Tu4eca2512022-06-20 21:14:51 -0700542 entityIdProp = ipmiProperties.find("EntityId");
543 entityInstanceProp = ipmiProperties.find("EntityInstance");
544 if (entityIdProp != ipmiProperties.end())
545 {
546 entityId = static_cast<uint8_t>(
547 std::get<uint64_t>(entityIdProp->second));
548 }
549 if (entityInstanceProp != ipmiProperties.end())
550 {
551 entityInstance = static_cast<uint8_t>(
552 std::get<uint64_t>(entityInstanceProp->second));
553 }
Willy Tude54f482021-01-26 15:59:09 -0800554 }
555
556 // Now check the entity-manager entry for this sensor to see
557 // if it has its own value and use that instead.
558 //
559 // In theory, checking this first saves us from checking
560 // both, except in most use-cases identified, there won't be
561 // a per sensor override, so we need to always check both.
562 std::string sensorNameFromPath = fs::path(path).filename();
563
564 std::string sensorConfigPath = endpoint + "/" + sensorNameFromPath;
565
566 // Download the interfaces for the sensor from
567 // Entity-Manager to find the name of the configuration
568 // interface.
Alexander Hansen8fb5b892023-11-02 17:29:34 +0100569 std::optional<std::map<std::string, std::vector<std::string>>>
570 sensorInterfacesResponseOpt =
Willy Tude54f482021-01-26 15:59:09 -0800571 getObjectInterfaces(sensorConfigPath.c_str());
572
Alexander Hansen8fb5b892023-11-02 17:29:34 +0100573 if (!sensorInterfacesResponseOpt.has_value())
574 {
575 phosphor::logging::log<phosphor::logging::level::DEBUG>(
576 "Failed to GetObject",
577 phosphor::logging::entry("PATH=%s", sensorConfigPath.c_str()));
578 continue;
579 }
580
Willy Tude54f482021-01-26 15:59:09 -0800581 const std::string* configurationInterface =
Alexander Hansen8fb5b892023-11-02 17:29:34 +0100582 getSensorConfigurationInterface(
583 sensorInterfacesResponseOpt.value());
Willy Tude54f482021-01-26 15:59:09 -0800584
Harvey Wu7bb84db2023-06-26 10:02:08 +0800585 // If there are multi association path settings and only one path exist,
586 // we need to continue if cannot find configuration interface for this
587 // sensor.
Willy Tude54f482021-01-26 15:59:09 -0800588 if (!configurationInterface)
589 {
Harvey Wu7bb84db2023-06-26 10:02:08 +0800590 continue;
Willy Tude54f482021-01-26 15:59:09 -0800591 }
592
593 // We found a configuration interface.
594 std::map<std::string, Value> configurationProperties =
595 getEntityManagerProperties(sensorConfigPath.c_str(),
596 configurationInterface->c_str());
597
598 entityIdProp = configurationProperties.find("EntityId");
599 entityInstanceProp = configurationProperties.find("EntityInstance");
600 if (entityIdProp != configurationProperties.end())
601 {
602 entityId =
603 static_cast<uint8_t>(std::get<uint64_t>(entityIdProp->second));
604 }
605 if (entityInstanceProp != configurationProperties.end())
606 {
607 entityInstance = static_cast<uint8_t>(
608 std::get<uint64_t>(entityInstanceProp->second));
609 }
610
611 // stop searching Association records.
612 break;
613 } // end for Association vectors.
614
615 if constexpr (debug)
616 {
617 std::fprintf(stderr, "path=%s, entityId=%d, entityInstance=%d\n",
618 path.c_str(), entityId, entityInstance);
619 }
620}
621
622} // namespace ipmi