blob: a6c4ac1db9f6f5b30b9a874f602607326594901c [file] [log] [blame]
James Feist6ef20402019-01-07 16:45:08 -08001/*
2// Copyright (c) 2019 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
Andrew Jefferye73bd0a2023-01-25 10:39:57 +103017#include "IpmbSensor.hpp"
18
19#include "IpmbSDRSensor.hpp"
Ed Tanouseacbfdd2024-04-04 12:00:24 -070020#include "SensorPaths.hpp"
21#include "Thresholds.hpp"
Andrew Jefferye73bd0a2023-01-25 10:39:57 +103022#include "Utils.hpp"
23#include "VariantVisitors.hpp"
Ed Tanouseacbfdd2024-04-04 12:00:24 -070024#include "sensor.hpp"
Andrew Jefferye73bd0a2023-01-25 10:39:57 +103025
Ed Tanouseacbfdd2024-04-04 12:00:24 -070026#include <boost/asio/error.hpp>
27#include <boost/asio/io_context.hpp>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070028#include <boost/asio/steady_timer.hpp>
Patrick Venture96e97db2019-10-31 13:44:38 -070029#include <boost/container/flat_map.hpp>
George Liu73f6cdc2025-02-20 15:15:19 +080030#include <phosphor-logging/lg2.hpp>
James Feist38fb5982020-05-28 10:09:54 -070031#include <sdbusplus/asio/connection.hpp>
32#include <sdbusplus/asio/object_server.hpp>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070033#include <sdbusplus/message.hpp>
34#include <sdbusplus/message/native_types.hpp>
James Feist38fb5982020-05-28 10:09:54 -070035
Ed Tanouseacbfdd2024-04-04 12:00:24 -070036#include <algorithm>
37#include <array>
James Feist6ef20402019-01-07 16:45:08 -080038#include <chrono>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070039#include <cstddef>
40#include <cstdint>
George Liu73f6cdc2025-02-20 15:15:19 +080041#include <iomanip>
James Feist6ef20402019-01-07 16:45:08 -080042#include <iostream>
43#include <limits>
Patrick Venture96e97db2019-10-31 13:44:38 -070044#include <memory>
George Liu73f6cdc2025-02-20 15:15:19 +080045#include <sstream>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070046#include <stdexcept>
Patrick Venture96e97db2019-10-31 13:44:38 -070047#include <string>
48#include <tuple>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070049#include <utility>
Patrick Venture96e97db2019-10-31 13:44:38 -070050#include <variant>
James Feist6ef20402019-01-07 16:45:08 -080051#include <vector>
52
James Feist6ef20402019-01-07 16:45:08 -080053static constexpr double ipmbMaxReading = 0xFF;
54static constexpr double ipmbMinReading = 0;
55
56static constexpr uint8_t meAddress = 1;
57static constexpr uint8_t lun = 0;
Anoop S832a2c62020-11-20 19:21:22 +000058static constexpr uint8_t hostSMbusIndexDefault = 0x03;
Jayashree Dhanapal6ee62942021-12-14 15:22:23 +053059static constexpr uint8_t ipmbBusIndexDefault = 0;
Jayashree-D9f6d4fd2021-04-13 18:27:22 +053060static constexpr float pollRateDefault = 1; // in seconds
James Feist6ef20402019-01-07 16:45:08 -080061
Vijay Khemka682a5cb2019-07-18 17:34:03 -070062static constexpr const char* sensorPathPrefix = "/xyz/openbmc_project/sensors/";
63
Patrick Williams2aaf7172024-08-16 15:20:40 -040064IpmbSensor::IpmbSensor(
65 std::shared_ptr<sdbusplus::asio::connection>& conn,
66 boost::asio::io_context& io, const std::string& sensorName,
67 const std::string& sensorConfiguration,
68 sdbusplus::asio::object_server& objectServer,
69 std::vector<thresholds::Threshold>&& thresholdData, uint8_t deviceAddress,
70 uint8_t hostSMbusIndex, const float pollRate, std::string& sensorTypeName) :
Zhikui Renda98f092021-11-01 09:41:08 -070071 Sensor(escapeName(sensorName), std::move(thresholdData),
Zev Weiss054aad82022-08-18 01:37:34 -070072 sensorConfiguration, "IpmbSensor", false, false, ipmbMaxReading,
73 ipmbMinReading, conn, PowerState::on),
Anoop S832a2c62020-11-20 19:21:22 +000074 deviceAddress(deviceAddress), hostSMbusIndex(hostSMbusIndex),
Jayashree-D9f6d4fd2021-04-13 18:27:22 +053075 sensorPollMs(static_cast<int>(pollRate * 1000)), objectServer(objectServer),
76 waitTimer(io)
James Feist6ef20402019-01-07 16:45:08 -080077{
Vijay Khemka682a5cb2019-07-18 17:34:03 -070078 std::string dbusPath = sensorPathPrefix + sensorTypeName + "/" + name;
79
James Feist6ef20402019-01-07 16:45:08 -080080 sensorInterface = objectServer.add_interface(
Vijay Khemka682a5cb2019-07-18 17:34:03 -070081 dbusPath, "xyz.openbmc_project.Sensor.Value");
James Feist6ef20402019-01-07 16:45:08 -080082
Jayashree Dhanapal56678082022-01-04 17:27:20 +053083 for (const auto& threshold : thresholds)
James Feist6ef20402019-01-07 16:45:08 -080084 {
Jayashree Dhanapal56678082022-01-04 17:27:20 +053085 std::string interface = thresholds::getInterface(threshold.level);
86 thresholdInterfaces[static_cast<size_t>(threshold.level)] =
87 objectServer.add_interface(dbusPath, interface);
James Feist6ef20402019-01-07 16:45:08 -080088 }
James Feist2adc95c2019-09-30 14:55:28 -070089 association = objectServer.add_interface(dbusPath, association::interface);
James Feist6ef20402019-01-07 16:45:08 -080090}
91
92IpmbSensor::~IpmbSensor()
93{
94 waitTimer.cancel();
Jayashree Dhanapal56678082022-01-04 17:27:20 +053095 for (const auto& iface : thresholdInterfaces)
96 {
97 objectServer.remove_interface(iface);
98 }
James Feist6ef20402019-01-07 16:45:08 -080099 objectServer.remove_interface(sensorInterface);
James Feist078f2322019-03-08 11:09:05 -0800100 objectServer.remove_interface(association);
James Feist6ef20402019-01-07 16:45:08 -0800101}
102
Ed Tanous201a1012024-04-03 18:07:28 -0700103std::string IpmbSensor::getSubTypeUnits() const
Zev Weiss6b6891c2021-04-22 02:46:21 -0500104{
105 switch (subType)
106 {
107 case IpmbSubType::temp:
108 return sensor_paths::unitDegreesC;
109 case IpmbSubType::curr:
110 return sensor_paths::unitAmperes;
111 case IpmbSubType::power:
112 return sensor_paths::unitWatts;
113 case IpmbSubType::volt:
114 return sensor_paths::unitVolts;
115 case IpmbSubType::util:
116 return sensor_paths::unitPercent;
117 default:
118 throw std::runtime_error("Invalid sensor type");
119 }
120}
121
Ed Tanous201a1012024-04-03 18:07:28 -0700122void IpmbSensor::init()
James Feist6ef20402019-01-07 16:45:08 -0800123{
James Feist6ef20402019-01-07 16:45:08 -0800124 loadDefaults();
Andrei Kartashev39287412022-02-04 16:04:47 +0300125 setInitialProperties(getSubTypeUnits());
Patrick Williamsebd2a382025-05-14 08:48:58 -0400126 runInitCmd();
James Feistf7e2c5d2019-02-13 17:27:51 -0800127 read();
128}
129
Vikash Chandola1f847972022-09-28 09:47:32 +0000130static void initCmdCb(const std::weak_ptr<IpmbSensor>& weakRef,
131 const boost::system::error_code& ec,
132 const IpmbMethodType& response)
133{
134 std::shared_ptr<IpmbSensor> self = weakRef.lock();
135 if (!self)
136 {
137 return;
138 }
139 const int& status = std::get<0>(response);
140 if (ec || (status != 0))
141 {
George Liu73f6cdc2025-02-20 15:15:19 +0800142 lg2::error("Error setting init command for device: '{NAME}'", "NAME",
143 self->name);
Vikash Chandola1f847972022-09-28 09:47:32 +0000144 }
145}
146
James Feistf7e2c5d2019-02-13 17:27:51 -0800147void IpmbSensor::runInitCmd()
148{
Patrick Williamsebd2a382025-05-14 08:48:58 -0400149 if (!initCommand.has_value())
James Feistf7e2c5d2019-02-13 17:27:51 -0800150 {
Vikash Chandola1f847972022-09-28 09:47:32 +0000151 return;
James Feist6ef20402019-01-07 16:45:08 -0800152 }
Vikash Chandola1f847972022-09-28 09:47:32 +0000153 dbusConnection->async_method_call(
154 [weakRef{weak_from_this()}](const boost::system::error_code& ec,
155 const IpmbMethodType& response) {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400156 initCmdCb(weakRef, ec, response);
157 },
Vikash Chandola1f847972022-09-28 09:47:32 +0000158 "xyz.openbmc_project.Ipmi.Channel.Ipmb",
159 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb",
Patrick Williamsebd2a382025-05-14 08:48:58 -0400160 "sendRequest", commandAddress, netfn, lun, initCommand.value_or(0),
161 initData);
James Feist6ef20402019-01-07 16:45:08 -0800162}
163
164void IpmbSensor::loadDefaults()
165{
166 if (type == IpmbType::meSensor)
167 {
168 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200169 netfn = ipmi::sensor::netFn;
170 command = ipmi::sensor::getSensorReading;
James Feist6ef20402019-01-07 16:45:08 -0800171 commandData = {deviceAddress};
James Feistd7ae29a2020-06-25 15:42:46 -0700172 readingFormat = ReadingFormat::byte0;
James Feist6ef20402019-01-07 16:45:08 -0800173 }
174 else if (type == IpmbType::PXE1410CVR)
175 {
176 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200177 netfn = ipmi::me_bridge::netFn;
178 command = ipmi::me_bridge::sendRawPmbus;
179 initCommand = ipmi::me_bridge::sendRawPmbus;
James Feistd7ae29a2020-06-25 15:42:46 -0700180 // pmbus read temp
Anoop S832a2c62020-11-20 19:21:22 +0000181 commandData = {0x57, 0x01, 0x00, 0x16, hostSMbusIndex,
182 deviceAddress, 0x00, 0x00, 0x00, 0x00,
183 0x01, 0x02, 0x8d};
James Feistd7ae29a2020-06-25 15:42:46 -0700184 // goto page 0
Anoop S832a2c62020-11-20 19:21:22 +0000185 initData = {0x57, 0x01, 0x00, 0x14, hostSMbusIndex,
186 deviceAddress, 0x00, 0x00, 0x00, 0x00,
187 0x02, 0x00, 0x00, 0x00};
Jayashree-D37322572021-03-19 17:40:56 +0530188 readingFormat = ReadingFormat::linearElevenBit;
James Feist6ef20402019-01-07 16:45:08 -0800189 }
190 else if (type == IpmbType::IR38363VR)
191 {
192 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200193 netfn = ipmi::me_bridge::netFn;
194 command = ipmi::me_bridge::sendRawPmbus;
James Feistd7ae29a2020-06-25 15:42:46 -0700195 // pmbus read temp
Anoop S832a2c62020-11-20 19:21:22 +0000196 commandData = {0x57, 0x01, 0x00, 0x16, hostSMbusIndex,
197 deviceAddress, 00, 0x00, 0x00, 0x00,
198 0x01, 0x02, 0x8D};
James Feistd7ae29a2020-06-25 15:42:46 -0700199 readingFormat = ReadingFormat::elevenBitShift;
James Feist6ef20402019-01-07 16:45:08 -0800200 }
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700201 else if (type == IpmbType::ADM1278HSC)
202 {
203 commandAddress = meAddress;
Ed Tanousa771f6a2022-01-14 09:36:51 -0800204 uint8_t snsNum = 0;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700205 switch (subType)
206 {
207 case IpmbSubType::temp:
208 case IpmbSubType::curr:
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700209 if (subType == IpmbSubType::temp)
Ed Tanous8a57ec02020-10-09 12:46:52 -0700210 {
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700211 snsNum = 0x8d;
Ed Tanous8a57ec02020-10-09 12:46:52 -0700212 }
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700213 else
Ed Tanous8a57ec02020-10-09 12:46:52 -0700214 {
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700215 snsNum = 0x8c;
Ed Tanous8a57ec02020-10-09 12:46:52 -0700216 }
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200217 netfn = ipmi::me_bridge::netFn;
218 command = ipmi::me_bridge::sendRawPmbus;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700219 commandData = {0x57, 0x01, 0x00, 0x86, deviceAddress,
220 0x00, 0x00, 0x01, 0x02, snsNum};
James Feistd7ae29a2020-06-25 15:42:46 -0700221 readingFormat = ReadingFormat::elevenBit;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700222 break;
223 case IpmbSubType::power:
224 case IpmbSubType::volt:
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200225 netfn = ipmi::sensor::netFn;
226 command = ipmi::sensor::getSensorReading;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700227 commandData = {deviceAddress};
James Feistd7ae29a2020-06-25 15:42:46 -0700228 readingFormat = ReadingFormat::byte0;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700229 break;
230 default:
231 throw std::runtime_error("Invalid sensor type");
232 }
233 }
James Feist6ef20402019-01-07 16:45:08 -0800234 else if (type == IpmbType::mpsVR)
235 {
236 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200237 netfn = ipmi::me_bridge::netFn;
238 command = ipmi::me_bridge::sendRawPmbus;
239 initCommand = ipmi::me_bridge::sendRawPmbus;
James Feistd7ae29a2020-06-25 15:42:46 -0700240 // pmbus read temp
Anoop S832a2c62020-11-20 19:21:22 +0000241 commandData = {0x57, 0x01, 0x00, 0x16, hostSMbusIndex,
242 deviceAddress, 0x00, 0x00, 0x00, 0x00,
243 0x01, 0x02, 0x8d};
James Feistd7ae29a2020-06-25 15:42:46 -0700244 // goto page 0
Anoop S832a2c62020-11-20 19:21:22 +0000245 initData = {0x57, 0x01, 0x00, 0x14, hostSMbusIndex,
246 deviceAddress, 0x00, 0x00, 0x00, 0x00,
247 0x02, 0x00, 0x00, 0x00};
James Feistd7ae29a2020-06-25 15:42:46 -0700248 readingFormat = ReadingFormat::byte3;
James Feist6ef20402019-01-07 16:45:08 -0800249 }
Rebecca Cran394f0c52023-12-17 20:08:55 -0700250 else if (type == IpmbType::SMPro)
251 {
252 // This is an Ampere SMPro reachable via a BMC. For example,
253 // this architecture is used on ADLINK Ampere Altra systems.
254 // See the Ampere Family SoC BMC Interface Specification at
255 // https://amperecomputing.com/customer-connect/products/altra-family-software---firmware
256 // for details of the sensors.
257 commandAddress = 0;
258 netfn = 0x30;
259 command = 0x31;
260 commandData = {0x9e, deviceAddress};
261 switch (subType)
262 {
263 case IpmbSubType::temp:
264 readingFormat = ReadingFormat::nineBit;
265 break;
266 case IpmbSubType::power:
267 readingFormat = ReadingFormat::tenBit;
268 break;
269 case IpmbSubType::curr:
270 case IpmbSubType::volt:
271 readingFormat = ReadingFormat::fifteenBit;
272 break;
273 default:
274 throw std::runtime_error("Invalid sensor type");
275 }
276 }
James Feist6ef20402019-01-07 16:45:08 -0800277 else
278 {
279 throw std::runtime_error("Invalid sensor type");
280 }
Adrian Ambrożewicz45e92772020-06-04 13:59:55 +0200281
282 if (subType == IpmbSubType::util)
283 {
284 // Utilization need to be scaled to percent
285 maxValue = 100;
286 minValue = 0;
287 }
James Feist6ef20402019-01-07 16:45:08 -0800288}
289
Ed Tanous201a1012024-04-03 18:07:28 -0700290void IpmbSensor::checkThresholds()
James Feist6ef20402019-01-07 16:45:08 -0800291{
James Feist6ef20402019-01-07 16:45:08 -0800292 thresholds::checkThresholds(this);
293}
294
Ed Tanous828c5a62024-02-09 16:59:22 -0800295bool IpmbSensor::processReading(ReadingFormat readingFormat, uint8_t command,
296 const std::vector<uint8_t>& data, double& resp,
297 size_t errCount)
James Feistd7ae29a2020-06-25 15:42:46 -0700298{
James Feistd7ae29a2020-06-25 15:42:46 -0700299 switch (readingFormat)
300 {
301 case (ReadingFormat::byte0):
James Feiste4a970d2020-08-19 11:21:58 -0700302 {
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200303 if (command == ipmi::sensor::getSensorReading &&
304 !ipmi::sensor::isValid(data))
James Feistcf4238e2020-07-28 16:40:03 -0700305 {
306 return false;
307 }
James Feist961bf092020-07-01 16:38:12 -0700308 resp = data[0];
309 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700310 }
James Feistd7ae29a2020-06-25 15:42:46 -0700311 case (ReadingFormat::byte3):
James Feiste4a970d2020-08-19 11:21:58 -0700312 {
James Feistd7ae29a2020-06-25 15:42:46 -0700313 if (data.size() < 4)
314 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700315 if (errCount == 0U)
James Feist961bf092020-07-01 16:38:12 -0700316 {
George Liu73f6cdc2025-02-20 15:15:19 +0800317 lg2::error("Invalid data length returned");
James Feist961bf092020-07-01 16:38:12 -0700318 }
319 return false;
James Feistd7ae29a2020-06-25 15:42:46 -0700320 }
James Feist961bf092020-07-01 16:38:12 -0700321 resp = data[3];
322 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700323 }
Rebecca Cran394f0c52023-12-17 20:08:55 -0700324 case (ReadingFormat::nineBit):
325 case (ReadingFormat::tenBit):
326 case (ReadingFormat::fifteenBit):
327 {
328 if (data.size() != 2)
329 {
330 if (errCount == 0U)
331 {
George Liu73f6cdc2025-02-20 15:15:19 +0800332 lg2::error("Invalid data length returned");
Rebecca Cran394f0c52023-12-17 20:08:55 -0700333 }
334 return false;
335 }
336
337 // From the Altra Family SoC BMC Interface Specification:
338 // 0xFFFF – This sensor data is either missing or is not supported
339 // by the device.
340 if ((data[0] == 0xff) && (data[1] == 0xff))
341 {
342 return false;
343 }
344
345 if (readingFormat == ReadingFormat::nineBit)
346 {
347 int16_t value = data[0];
348 if ((data[1] & 0x1) != 0)
349 {
350 // Sign extend to 16 bits
351 value |= 0xFF00;
352 }
353 resp = value;
354 }
355 else if (readingFormat == ReadingFormat::tenBit)
356 {
357 uint16_t value = ((data[1] & 0x3) << 8) + data[0];
358 resp = value;
359 }
360 else if (readingFormat == ReadingFormat::fifteenBit)
361 {
362 uint16_t value = ((data[1] & 0x7F) << 8) + data[0];
363 // Convert mV to V
364 resp = value / 1000.0;
365 }
366
367 return true;
368 }
James Feistd7ae29a2020-06-25 15:42:46 -0700369 case (ReadingFormat::elevenBit):
James Feiste4a970d2020-08-19 11:21:58 -0700370 {
James Feistd7ae29a2020-06-25 15:42:46 -0700371 if (data.size() < 5)
372 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700373 if (errCount == 0U)
James Feist961bf092020-07-01 16:38:12 -0700374 {
George Liu73f6cdc2025-02-20 15:15:19 +0800375 lg2::error("Invalid data length returned");
James Feist961bf092020-07-01 16:38:12 -0700376 }
377 return false;
James Feistd7ae29a2020-06-25 15:42:46 -0700378 }
379
James Feiste4a970d2020-08-19 11:21:58 -0700380 int16_t value = ((data[4] << 8) | data[3]);
James Feiste4a970d2020-08-19 11:21:58 -0700381 resp = value;
James Feist961bf092020-07-01 16:38:12 -0700382 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700383 }
James Feistd7ae29a2020-06-25 15:42:46 -0700384 case (ReadingFormat::elevenBitShift):
James Feiste4a970d2020-08-19 11:21:58 -0700385 {
James Feistd7ae29a2020-06-25 15:42:46 -0700386 if (data.size() < 5)
387 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700388 if (errCount == 0U)
James Feist961bf092020-07-01 16:38:12 -0700389 {
George Liu73f6cdc2025-02-20 15:15:19 +0800390 lg2::error("Invalid data length returned");
James Feist961bf092020-07-01 16:38:12 -0700391 }
392 return false;
James Feistd7ae29a2020-06-25 15:42:46 -0700393 }
394
James Feist961bf092020-07-01 16:38:12 -0700395 resp = ((data[4] << 8) | data[3]) >> 3;
396 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700397 }
Jayashree-D37322572021-03-19 17:40:56 +0530398 case (ReadingFormat::linearElevenBit):
399 {
400 if (data.size() < 5)
401 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700402 if (errCount == 0U)
Jayashree-D37322572021-03-19 17:40:56 +0530403 {
George Liu73f6cdc2025-02-20 15:15:19 +0800404 lg2::error("Invalid data length returned");
Jayashree-D37322572021-03-19 17:40:56 +0530405 }
406 return false;
407 }
408
409 int16_t value = ((data[4] << 8) | data[3]);
410 constexpr const size_t shift = 16 - 11; // 11bit into 16bit
411 value <<= shift;
412 value >>= shift;
413 resp = value;
414 return true;
415 }
James Feistd7ae29a2020-06-25 15:42:46 -0700416 default:
417 throw std::runtime_error("Invalid reading type");
418 }
419}
420
Vikash Chandola1f847972022-09-28 09:47:32 +0000421void IpmbSensor::ipmbRequestCompletionCb(const boost::system::error_code& ec,
422 const IpmbMethodType& response)
423{
424 const int& status = std::get<0>(response);
425 if (ec || (status != 0))
426 {
427 incrementError();
428 read();
429 return;
430 }
431 const std::vector<uint8_t>& data = std::get<5>(response);
Alexander Hansen89be6142025-09-18 15:36:16 +0200432
433 std::ostringstream tempStream;
434 for (int d : data)
Vikash Chandola1f847972022-09-28 09:47:32 +0000435 {
Alexander Hansen89be6142025-09-18 15:36:16 +0200436 tempStream << std::setfill('0') << std::setw(2) << std::hex << d << " ";
Vikash Chandola1f847972022-09-28 09:47:32 +0000437 }
Alexander Hansen89be6142025-09-18 15:36:16 +0200438 lg2::debug("'{NAME}': '{DATA}'", "NAME", name, "DATA", tempStream.str());
439
Vikash Chandola1f847972022-09-28 09:47:32 +0000440 if (data.empty())
441 {
442 incrementError();
443 read();
444 return;
445 }
446
447 double value = 0;
448
Ed Tanous828c5a62024-02-09 16:59:22 -0800449 if (!processReading(readingFormat, command, data, value, errCount))
Vikash Chandola1f847972022-09-28 09:47:32 +0000450 {
451 incrementError();
452 read();
453 return;
454 }
455
456 // rawValue only used in debug logging
457 // up to 5th byte in data are used to derive value
458 size_t end = std::min(sizeof(uint64_t), data.size());
459 uint64_t rawData = 0;
460 for (size_t i = 0; i < end; i++)
461 {
462 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
463 reinterpret_cast<uint8_t*>(&rawData)[i] = data[i];
464 }
465 rawValue = static_cast<double>(rawData);
466
467 /* Adjust value as per scale and offset */
468 value = (value * scaleVal) + offsetVal;
469 updateValue(value);
470 read();
471}
472
Ed Tanous201a1012024-04-03 18:07:28 -0700473void IpmbSensor::read()
James Feist6ef20402019-01-07 16:45:08 -0800474{
Ed Tanous83db50c2023-03-01 10:20:24 -0800475 waitTimer.expires_after(std::chrono::milliseconds(sensorPollMs));
Vikash Chandola1f847972022-09-28 09:47:32 +0000476 waitTimer.async_wait(
477 [weakRef{weak_from_this()}](const boost::system::error_code& ec) {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400478 if (ec == boost::asio::error::operation_aborted)
479 {
480 return; // we're being canceled
481 }
482 std::shared_ptr<IpmbSensor> self = weakRef.lock();
483 if (!self)
484 {
485 return;
486 }
487 self->sendIpmbRequest();
488 });
James Feist6ef20402019-01-07 16:45:08 -0800489}
Jayashree Dhanapal84189752022-03-07 12:51:54 +0530490
Vikash Chandola1f847972022-09-28 09:47:32 +0000491void IpmbSensor::sendIpmbRequest()
492{
493 if (!readingStateGood())
494 {
495 updateValue(std::numeric_limits<double>::quiet_NaN());
496 read();
497 return;
498 }
499 dbusConnection->async_method_call(
500 [weakRef{weak_from_this()}](boost::system::error_code ec,
501 const IpmbMethodType& response) {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400502 std::shared_ptr<IpmbSensor> self = weakRef.lock();
503 if (!self)
504 {
505 return;
506 }
507 self->ipmbRequestCompletionCb(ec, response);
508 },
Vikash Chandola1f847972022-09-28 09:47:32 +0000509 "xyz.openbmc_project.Ipmi.Channel.Ipmb",
510 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb",
511 "sendRequest", commandAddress, netfn, lun, command, commandData);
512}
513
Jayashree Dhanapal84189752022-03-07 12:51:54 +0530514bool IpmbSensor::sensorClassType(const std::string& sensorClass)
515{
516 if (sensorClass == "PxeBridgeTemp")
517 {
518 type = IpmbType::PXE1410CVR;
519 }
520 else if (sensorClass == "IRBridgeTemp")
521 {
522 type = IpmbType::IR38363VR;
523 }
524 else if (sensorClass == "HSCBridge")
525 {
526 type = IpmbType::ADM1278HSC;
527 }
528 else if (sensorClass == "MpsBridgeTemp")
529 {
530 type = IpmbType::mpsVR;
531 }
532 else if (sensorClass == "METemp" || sensorClass == "MESensor")
533 {
534 type = IpmbType::meSensor;
535 }
Rebecca Cran394f0c52023-12-17 20:08:55 -0700536 else if (sensorClass == "SMPro")
537 {
538 type = IpmbType::SMPro;
539 }
Jayashree Dhanapal84189752022-03-07 12:51:54 +0530540 else
541 {
George Liu73f6cdc2025-02-20 15:15:19 +0800542 lg2::error("Invalid class '{SENSOR}'", "SENSOR", sensorClass);
Jayashree Dhanapal84189752022-03-07 12:51:54 +0530543 return false;
544 }
545 return true;
546}
547
548void IpmbSensor::sensorSubType(const std::string& sensorTypeName)
549{
550 if (sensorTypeName == "voltage")
551 {
552 subType = IpmbSubType::volt;
553 }
554 else if (sensorTypeName == "power")
555 {
556 subType = IpmbSubType::power;
557 }
558 else if (sensorTypeName == "current")
559 {
560 subType = IpmbSubType::curr;
561 }
562 else if (sensorTypeName == "utilization")
563 {
564 subType = IpmbSubType::util;
565 }
566 else
567 {
568 subType = IpmbSubType::temp;
569 }
570}
571
572void IpmbSensor::parseConfigValues(const SensorBaseConfigMap& entry)
573{
574 auto findScaleVal = entry.find("ScaleValue");
575 if (findScaleVal != entry.end())
576 {
577 scaleVal = std::visit(VariantToDoubleVisitor(), findScaleVal->second);
578 }
579
580 auto findOffsetVal = entry.find("OffsetValue");
581 if (findOffsetVal != entry.end())
582 {
583 offsetVal = std::visit(VariantToDoubleVisitor(), findOffsetVal->second);
584 }
585
Zev Weissa4d27682022-07-19 15:30:36 -0700586 readState = getPowerState(entry);
Jayashree Dhanapal84189752022-03-07 12:51:54 +0530587}
588
James Feist6ef20402019-01-07 16:45:08 -0800589void createSensors(
Ed Tanous1f978632023-02-28 18:16:39 -0800590 boost::asio::io_context& io, sdbusplus::asio::object_server& objectServer,
Vikash Chandola1f847972022-09-28 09:47:32 +0000591 boost::container::flat_map<std::string, std::shared_ptr<IpmbSensor>>&
James Feist6ef20402019-01-07 16:45:08 -0800592 sensors,
593 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection)
594{
595 if (!dbusConnection)
596 {
George Liu73f6cdc2025-02-20 15:15:19 +0800597 lg2::error("Connection not created");
James Feist6ef20402019-01-07 16:45:08 -0800598 return;
599 }
600 dbusConnection->async_method_call(
601 [&](boost::system::error_code ec, const ManagedObjectType& resp) {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400602 if (ec)
James Feist6ef20402019-01-07 16:45:08 -0800603 {
George Liu73f6cdc2025-02-20 15:15:19 +0800604 lg2::error("Error contacting entity manager");
Patrick Williams2aaf7172024-08-16 15:20:40 -0400605 return;
James Feist6ef20402019-01-07 16:45:08 -0800606 }
Patrick Williams2aaf7172024-08-16 15:20:40 -0400607 for (const auto& [path, interfaces] : resp)
608 {
609 for (const auto& [intf, cfg] : interfaces)
610 {
611 if (intf != configInterfaceName(sensorType))
612 {
613 continue;
614 }
615 std::string name = loadVariant<std::string>(cfg, "Name");
616
617 std::vector<thresholds::Threshold> sensorThresholds;
618 if (!parseThresholdsFromConfig(interfaces,
619 sensorThresholds))
620 {
George Liu73f6cdc2025-02-20 15:15:19 +0800621 lg2::error("error populating thresholds '{NAME}'",
622 "NAME", name);
Patrick Williams2aaf7172024-08-16 15:20:40 -0400623 }
624 uint8_t deviceAddress =
625 loadVariant<uint8_t>(cfg, "Address");
626
627 std::string sensorClass =
628 loadVariant<std::string>(cfg, "Class");
629
630 uint8_t hostSMbusIndex = hostSMbusIndexDefault;
631 auto findSmType = cfg.find("HostSMbusIndex");
632 if (findSmType != cfg.end())
633 {
634 hostSMbusIndex = std::visit(
635 VariantToUnsignedIntVisitor(), findSmType->second);
636 }
637
638 float pollRate = getPollRate(cfg, pollRateDefault);
639
640 uint8_t ipmbBusIndex = ipmbBusIndexDefault;
641 auto findBusType = cfg.find("Bus");
642 if (findBusType != cfg.end())
643 {
644 ipmbBusIndex = std::visit(VariantToUnsignedIntVisitor(),
645 findBusType->second);
George Liu73f6cdc2025-02-20 15:15:19 +0800646 lg2::error("Ipmb Bus Index for '{NAME}' is '{INDEX}'",
647 "NAME", name, "INDEX", ipmbBusIndex);
Patrick Williams2aaf7172024-08-16 15:20:40 -0400648 }
649
650 /* Default sensor type is "temperature" */
651 std::string sensorTypeName = "temperature";
652 auto findType = cfg.find("SensorType");
653 if (findType != cfg.end())
654 {
655 sensorTypeName = std::visit(VariantToStringVisitor(),
656 findType->second);
657 }
658
659 auto& sensor = sensors[name];
660 sensor = nullptr;
661 sensor = std::make_shared<IpmbSensor>(
662 dbusConnection, io, name, path, objectServer,
663 std::move(sensorThresholds), deviceAddress,
664 hostSMbusIndex, pollRate, sensorTypeName);
665
666 sensor->parseConfigValues(cfg);
667 if (!(sensor->sensorClassType(sensorClass)))
668 {
669 continue;
670 }
671 sensor->sensorSubType(sensorTypeName);
672 sensor->init();
673 }
674 }
675 },
JeffLin2c5a1f22022-10-05 15:19:09 +0800676 entityManagerName, "/xyz/openbmc_project/inventory",
677 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
James Feist6ef20402019-01-07 16:45:08 -0800678}
679
Kumar Thangavel5d032bc2022-11-30 20:24:47 +0530680void interfaceRemoved(
681 sdbusplus::message_t& message,
682 boost::container::flat_map<std::string, std::shared_ptr<IpmbSensor>>&
683 sensors)
684{
685 if (message.is_method_error())
686 {
George Liu73f6cdc2025-02-20 15:15:19 +0800687 lg2::error("interfacesRemoved callback method error");
Kumar Thangavel5d032bc2022-11-30 20:24:47 +0530688 return;
689 }
690
691 sdbusplus::message::object_path removedPath;
692 std::vector<std::string> interfaces;
693
694 message.read(removedPath, interfaces);
695
696 // If the xyz.openbmc_project.Confguration.X interface was removed
697 // for one or more sensors, delete those sensor objects.
698 auto sensorIt = sensors.begin();
699 while (sensorIt != sensors.end())
700 {
701 if ((sensorIt->second->configurationPath == removedPath) &&
702 (std::find(interfaces.begin(), interfaces.end(),
703 configInterfaceName(sdrInterface)) != interfaces.end()))
704 {
705 sensorIt = sensors.erase(sensorIt);
706 }
707 else
708 {
709 sensorIt++;
710 }
711 }
712}