blob: 658c87578b38c5803f5dce43226677569959df32 [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
53constexpr const bool debug = false;
54
James Feist6ef20402019-01-07 16:45:08 -080055static constexpr double ipmbMaxReading = 0xFF;
56static constexpr double ipmbMinReading = 0;
57
58static constexpr uint8_t meAddress = 1;
59static constexpr uint8_t lun = 0;
Anoop S832a2c62020-11-20 19:21:22 +000060static constexpr uint8_t hostSMbusIndexDefault = 0x03;
Jayashree Dhanapal6ee62942021-12-14 15:22:23 +053061static constexpr uint8_t ipmbBusIndexDefault = 0;
Jayashree-D9f6d4fd2021-04-13 18:27:22 +053062static constexpr float pollRateDefault = 1; // in seconds
James Feist6ef20402019-01-07 16:45:08 -080063
Vijay Khemka682a5cb2019-07-18 17:34:03 -070064static constexpr const char* sensorPathPrefix = "/xyz/openbmc_project/sensors/";
65
Patrick Williams2aaf7172024-08-16 15:20:40 -040066IpmbSensor::IpmbSensor(
67 std::shared_ptr<sdbusplus::asio::connection>& conn,
68 boost::asio::io_context& io, const std::string& sensorName,
69 const std::string& sensorConfiguration,
70 sdbusplus::asio::object_server& objectServer,
71 std::vector<thresholds::Threshold>&& thresholdData, uint8_t deviceAddress,
72 uint8_t hostSMbusIndex, const float pollRate, std::string& sensorTypeName) :
Zhikui Renda98f092021-11-01 09:41:08 -070073 Sensor(escapeName(sensorName), std::move(thresholdData),
Zev Weiss054aad82022-08-18 01:37:34 -070074 sensorConfiguration, "IpmbSensor", false, false, ipmbMaxReading,
75 ipmbMinReading, conn, PowerState::on),
Anoop S832a2c62020-11-20 19:21:22 +000076 deviceAddress(deviceAddress), hostSMbusIndex(hostSMbusIndex),
Jayashree-D9f6d4fd2021-04-13 18:27:22 +053077 sensorPollMs(static_cast<int>(pollRate * 1000)), objectServer(objectServer),
78 waitTimer(io)
James Feist6ef20402019-01-07 16:45:08 -080079{
Vijay Khemka682a5cb2019-07-18 17:34:03 -070080 std::string dbusPath = sensorPathPrefix + sensorTypeName + "/" + name;
81
James Feist6ef20402019-01-07 16:45:08 -080082 sensorInterface = objectServer.add_interface(
Vijay Khemka682a5cb2019-07-18 17:34:03 -070083 dbusPath, "xyz.openbmc_project.Sensor.Value");
James Feist6ef20402019-01-07 16:45:08 -080084
Jayashree Dhanapal56678082022-01-04 17:27:20 +053085 for (const auto& threshold : thresholds)
James Feist6ef20402019-01-07 16:45:08 -080086 {
Jayashree Dhanapal56678082022-01-04 17:27:20 +053087 std::string interface = thresholds::getInterface(threshold.level);
88 thresholdInterfaces[static_cast<size_t>(threshold.level)] =
89 objectServer.add_interface(dbusPath, interface);
James Feist6ef20402019-01-07 16:45:08 -080090 }
James Feist2adc95c2019-09-30 14:55:28 -070091 association = objectServer.add_interface(dbusPath, association::interface);
James Feist6ef20402019-01-07 16:45:08 -080092}
93
94IpmbSensor::~IpmbSensor()
95{
96 waitTimer.cancel();
Jayashree Dhanapal56678082022-01-04 17:27:20 +053097 for (const auto& iface : thresholdInterfaces)
98 {
99 objectServer.remove_interface(iface);
100 }
James Feist6ef20402019-01-07 16:45:08 -0800101 objectServer.remove_interface(sensorInterface);
James Feist078f2322019-03-08 11:09:05 -0800102 objectServer.remove_interface(association);
James Feist6ef20402019-01-07 16:45:08 -0800103}
104
Ed Tanous201a1012024-04-03 18:07:28 -0700105std::string IpmbSensor::getSubTypeUnits() const
Zev Weiss6b6891c2021-04-22 02:46:21 -0500106{
107 switch (subType)
108 {
109 case IpmbSubType::temp:
110 return sensor_paths::unitDegreesC;
111 case IpmbSubType::curr:
112 return sensor_paths::unitAmperes;
113 case IpmbSubType::power:
114 return sensor_paths::unitWatts;
115 case IpmbSubType::volt:
116 return sensor_paths::unitVolts;
117 case IpmbSubType::util:
118 return sensor_paths::unitPercent;
119 default:
120 throw std::runtime_error("Invalid sensor type");
121 }
122}
123
Ed Tanous201a1012024-04-03 18:07:28 -0700124void IpmbSensor::init()
James Feist6ef20402019-01-07 16:45:08 -0800125{
James Feist6ef20402019-01-07 16:45:08 -0800126 loadDefaults();
Andrei Kartashev39287412022-02-04 16:04:47 +0300127 setInitialProperties(getSubTypeUnits());
James Feist6ef20402019-01-07 16:45:08 -0800128 if (initCommand)
129 {
James Feistf7e2c5d2019-02-13 17:27:51 -0800130 runInitCmd();
131 }
132 read();
133}
134
Vikash Chandola1f847972022-09-28 09:47:32 +0000135static void initCmdCb(const std::weak_ptr<IpmbSensor>& weakRef,
136 const boost::system::error_code& ec,
137 const IpmbMethodType& response)
138{
139 std::shared_ptr<IpmbSensor> self = weakRef.lock();
140 if (!self)
141 {
142 return;
143 }
144 const int& status = std::get<0>(response);
145 if (ec || (status != 0))
146 {
George Liu73f6cdc2025-02-20 15:15:19 +0800147 lg2::error("Error setting init command for device: '{NAME}'", "NAME",
148 self->name);
Vikash Chandola1f847972022-09-28 09:47:32 +0000149 }
150}
151
James Feistf7e2c5d2019-02-13 17:27:51 -0800152void IpmbSensor::runInitCmd()
153{
Vikash Chandola1f847972022-09-28 09:47:32 +0000154 if (!initCommand)
James Feistf7e2c5d2019-02-13 17:27:51 -0800155 {
Vikash Chandola1f847972022-09-28 09:47:32 +0000156 return;
James Feist6ef20402019-01-07 16:45:08 -0800157 }
Vikash Chandola1f847972022-09-28 09:47:32 +0000158 dbusConnection->async_method_call(
159 [weakRef{weak_from_this()}](const boost::system::error_code& ec,
160 const IpmbMethodType& response) {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400161 initCmdCb(weakRef, ec, response);
162 },
Vikash Chandola1f847972022-09-28 09:47:32 +0000163 "xyz.openbmc_project.Ipmi.Channel.Ipmb",
164 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb",
165 "sendRequest", commandAddress, netfn, lun, *initCommand, initData);
James Feist6ef20402019-01-07 16:45:08 -0800166}
167
168void IpmbSensor::loadDefaults()
169{
170 if (type == IpmbType::meSensor)
171 {
172 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200173 netfn = ipmi::sensor::netFn;
174 command = ipmi::sensor::getSensorReading;
James Feist6ef20402019-01-07 16:45:08 -0800175 commandData = {deviceAddress};
James Feistd7ae29a2020-06-25 15:42:46 -0700176 readingFormat = ReadingFormat::byte0;
James Feist6ef20402019-01-07 16:45:08 -0800177 }
178 else if (type == IpmbType::PXE1410CVR)
179 {
180 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200181 netfn = ipmi::me_bridge::netFn;
182 command = ipmi::me_bridge::sendRawPmbus;
183 initCommand = ipmi::me_bridge::sendRawPmbus;
James Feistd7ae29a2020-06-25 15:42:46 -0700184 // pmbus read temp
Anoop S832a2c62020-11-20 19:21:22 +0000185 commandData = {0x57, 0x01, 0x00, 0x16, hostSMbusIndex,
186 deviceAddress, 0x00, 0x00, 0x00, 0x00,
187 0x01, 0x02, 0x8d};
James Feistd7ae29a2020-06-25 15:42:46 -0700188 // goto page 0
Anoop S832a2c62020-11-20 19:21:22 +0000189 initData = {0x57, 0x01, 0x00, 0x14, hostSMbusIndex,
190 deviceAddress, 0x00, 0x00, 0x00, 0x00,
191 0x02, 0x00, 0x00, 0x00};
Jayashree-D37322572021-03-19 17:40:56 +0530192 readingFormat = ReadingFormat::linearElevenBit;
James Feist6ef20402019-01-07 16:45:08 -0800193 }
194 else if (type == IpmbType::IR38363VR)
195 {
196 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200197 netfn = ipmi::me_bridge::netFn;
198 command = ipmi::me_bridge::sendRawPmbus;
James Feistd7ae29a2020-06-25 15:42:46 -0700199 // pmbus read temp
Anoop S832a2c62020-11-20 19:21:22 +0000200 commandData = {0x57, 0x01, 0x00, 0x16, hostSMbusIndex,
201 deviceAddress, 00, 0x00, 0x00, 0x00,
202 0x01, 0x02, 0x8D};
James Feistd7ae29a2020-06-25 15:42:46 -0700203 readingFormat = ReadingFormat::elevenBitShift;
James Feist6ef20402019-01-07 16:45:08 -0800204 }
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700205 else if (type == IpmbType::ADM1278HSC)
206 {
207 commandAddress = meAddress;
Ed Tanousa771f6a2022-01-14 09:36:51 -0800208 uint8_t snsNum = 0;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700209 switch (subType)
210 {
211 case IpmbSubType::temp:
212 case IpmbSubType::curr:
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700213 if (subType == IpmbSubType::temp)
Ed Tanous8a57ec02020-10-09 12:46:52 -0700214 {
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700215 snsNum = 0x8d;
Ed Tanous8a57ec02020-10-09 12:46:52 -0700216 }
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700217 else
Ed Tanous8a57ec02020-10-09 12:46:52 -0700218 {
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700219 snsNum = 0x8c;
Ed Tanous8a57ec02020-10-09 12:46:52 -0700220 }
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200221 netfn = ipmi::me_bridge::netFn;
222 command = ipmi::me_bridge::sendRawPmbus;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700223 commandData = {0x57, 0x01, 0x00, 0x86, deviceAddress,
224 0x00, 0x00, 0x01, 0x02, snsNum};
James Feistd7ae29a2020-06-25 15:42:46 -0700225 readingFormat = ReadingFormat::elevenBit;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700226 break;
227 case IpmbSubType::power:
228 case IpmbSubType::volt:
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200229 netfn = ipmi::sensor::netFn;
230 command = ipmi::sensor::getSensorReading;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700231 commandData = {deviceAddress};
James Feistd7ae29a2020-06-25 15:42:46 -0700232 readingFormat = ReadingFormat::byte0;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700233 break;
234 default:
235 throw std::runtime_error("Invalid sensor type");
236 }
237 }
James Feist6ef20402019-01-07 16:45:08 -0800238 else if (type == IpmbType::mpsVR)
239 {
240 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200241 netfn = ipmi::me_bridge::netFn;
242 command = ipmi::me_bridge::sendRawPmbus;
243 initCommand = ipmi::me_bridge::sendRawPmbus;
James Feistd7ae29a2020-06-25 15:42:46 -0700244 // pmbus read temp
Anoop S832a2c62020-11-20 19:21:22 +0000245 commandData = {0x57, 0x01, 0x00, 0x16, hostSMbusIndex,
246 deviceAddress, 0x00, 0x00, 0x00, 0x00,
247 0x01, 0x02, 0x8d};
James Feistd7ae29a2020-06-25 15:42:46 -0700248 // goto page 0
Anoop S832a2c62020-11-20 19:21:22 +0000249 initData = {0x57, 0x01, 0x00, 0x14, hostSMbusIndex,
250 deviceAddress, 0x00, 0x00, 0x00, 0x00,
251 0x02, 0x00, 0x00, 0x00};
James Feistd7ae29a2020-06-25 15:42:46 -0700252 readingFormat = ReadingFormat::byte3;
James Feist6ef20402019-01-07 16:45:08 -0800253 }
Rebecca Cran394f0c52023-12-17 20:08:55 -0700254 else if (type == IpmbType::SMPro)
255 {
256 // This is an Ampere SMPro reachable via a BMC. For example,
257 // this architecture is used on ADLINK Ampere Altra systems.
258 // See the Ampere Family SoC BMC Interface Specification at
259 // https://amperecomputing.com/customer-connect/products/altra-family-software---firmware
260 // for details of the sensors.
261 commandAddress = 0;
262 netfn = 0x30;
263 command = 0x31;
264 commandData = {0x9e, deviceAddress};
265 switch (subType)
266 {
267 case IpmbSubType::temp:
268 readingFormat = ReadingFormat::nineBit;
269 break;
270 case IpmbSubType::power:
271 readingFormat = ReadingFormat::tenBit;
272 break;
273 case IpmbSubType::curr:
274 case IpmbSubType::volt:
275 readingFormat = ReadingFormat::fifteenBit;
276 break;
277 default:
278 throw std::runtime_error("Invalid sensor type");
279 }
280 }
James Feist6ef20402019-01-07 16:45:08 -0800281 else
282 {
283 throw std::runtime_error("Invalid sensor type");
284 }
Adrian Ambrożewicz45e92772020-06-04 13:59:55 +0200285
286 if (subType == IpmbSubType::util)
287 {
288 // Utilization need to be scaled to percent
289 maxValue = 100;
290 minValue = 0;
291 }
James Feist6ef20402019-01-07 16:45:08 -0800292}
293
Ed Tanous201a1012024-04-03 18:07:28 -0700294void IpmbSensor::checkThresholds()
James Feist6ef20402019-01-07 16:45:08 -0800295{
James Feist6ef20402019-01-07 16:45:08 -0800296 thresholds::checkThresholds(this);
297}
298
Ed Tanous828c5a62024-02-09 16:59:22 -0800299bool IpmbSensor::processReading(ReadingFormat readingFormat, uint8_t command,
300 const std::vector<uint8_t>& data, double& resp,
301 size_t errCount)
James Feistd7ae29a2020-06-25 15:42:46 -0700302{
James Feistd7ae29a2020-06-25 15:42:46 -0700303 switch (readingFormat)
304 {
305 case (ReadingFormat::byte0):
James Feiste4a970d2020-08-19 11:21:58 -0700306 {
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200307 if (command == ipmi::sensor::getSensorReading &&
308 !ipmi::sensor::isValid(data))
James Feistcf4238e2020-07-28 16:40:03 -0700309 {
310 return false;
311 }
James Feist961bf092020-07-01 16:38:12 -0700312 resp = data[0];
313 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700314 }
James Feistd7ae29a2020-06-25 15:42:46 -0700315 case (ReadingFormat::byte3):
James Feiste4a970d2020-08-19 11:21:58 -0700316 {
James Feistd7ae29a2020-06-25 15:42:46 -0700317 if (data.size() < 4)
318 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700319 if (errCount == 0U)
James Feist961bf092020-07-01 16:38:12 -0700320 {
George Liu73f6cdc2025-02-20 15:15:19 +0800321 lg2::error("Invalid data length returned");
James Feist961bf092020-07-01 16:38:12 -0700322 }
323 return false;
James Feistd7ae29a2020-06-25 15:42:46 -0700324 }
James Feist961bf092020-07-01 16:38:12 -0700325 resp = data[3];
326 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700327 }
Rebecca Cran394f0c52023-12-17 20:08:55 -0700328 case (ReadingFormat::nineBit):
329 case (ReadingFormat::tenBit):
330 case (ReadingFormat::fifteenBit):
331 {
332 if (data.size() != 2)
333 {
334 if (errCount == 0U)
335 {
George Liu73f6cdc2025-02-20 15:15:19 +0800336 lg2::error("Invalid data length returned");
Rebecca Cran394f0c52023-12-17 20:08:55 -0700337 }
338 return false;
339 }
340
341 // From the Altra Family SoC BMC Interface Specification:
342 // 0xFFFF – This sensor data is either missing or is not supported
343 // by the device.
344 if ((data[0] == 0xff) && (data[1] == 0xff))
345 {
346 return false;
347 }
348
349 if (readingFormat == ReadingFormat::nineBit)
350 {
351 int16_t value = data[0];
352 if ((data[1] & 0x1) != 0)
353 {
354 // Sign extend to 16 bits
355 value |= 0xFF00;
356 }
357 resp = value;
358 }
359 else if (readingFormat == ReadingFormat::tenBit)
360 {
361 uint16_t value = ((data[1] & 0x3) << 8) + data[0];
362 resp = value;
363 }
364 else if (readingFormat == ReadingFormat::fifteenBit)
365 {
366 uint16_t value = ((data[1] & 0x7F) << 8) + data[0];
367 // Convert mV to V
368 resp = value / 1000.0;
369 }
370
371 return true;
372 }
James Feistd7ae29a2020-06-25 15:42:46 -0700373 case (ReadingFormat::elevenBit):
James Feiste4a970d2020-08-19 11:21:58 -0700374 {
James Feistd7ae29a2020-06-25 15:42:46 -0700375 if (data.size() < 5)
376 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700377 if (errCount == 0U)
James Feist961bf092020-07-01 16:38:12 -0700378 {
George Liu73f6cdc2025-02-20 15:15:19 +0800379 lg2::error("Invalid data length returned");
James Feist961bf092020-07-01 16:38:12 -0700380 }
381 return false;
James Feistd7ae29a2020-06-25 15:42:46 -0700382 }
383
James Feiste4a970d2020-08-19 11:21:58 -0700384 int16_t value = ((data[4] << 8) | data[3]);
James Feiste4a970d2020-08-19 11:21:58 -0700385 resp = value;
James Feist961bf092020-07-01 16:38:12 -0700386 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700387 }
James Feistd7ae29a2020-06-25 15:42:46 -0700388 case (ReadingFormat::elevenBitShift):
James Feiste4a970d2020-08-19 11:21:58 -0700389 {
James Feistd7ae29a2020-06-25 15:42:46 -0700390 if (data.size() < 5)
391 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700392 if (errCount == 0U)
James Feist961bf092020-07-01 16:38:12 -0700393 {
George Liu73f6cdc2025-02-20 15:15:19 +0800394 lg2::error("Invalid data length returned");
James Feist961bf092020-07-01 16:38:12 -0700395 }
396 return false;
James Feistd7ae29a2020-06-25 15:42:46 -0700397 }
398
James Feist961bf092020-07-01 16:38:12 -0700399 resp = ((data[4] << 8) | data[3]) >> 3;
400 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700401 }
Jayashree-D37322572021-03-19 17:40:56 +0530402 case (ReadingFormat::linearElevenBit):
403 {
404 if (data.size() < 5)
405 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700406 if (errCount == 0U)
Jayashree-D37322572021-03-19 17:40:56 +0530407 {
George Liu73f6cdc2025-02-20 15:15:19 +0800408 lg2::error("Invalid data length returned");
Jayashree-D37322572021-03-19 17:40:56 +0530409 }
410 return false;
411 }
412
413 int16_t value = ((data[4] << 8) | data[3]);
414 constexpr const size_t shift = 16 - 11; // 11bit into 16bit
415 value <<= shift;
416 value >>= shift;
417 resp = value;
418 return true;
419 }
James Feistd7ae29a2020-06-25 15:42:46 -0700420 default:
421 throw std::runtime_error("Invalid reading type");
422 }
423}
424
Vikash Chandola1f847972022-09-28 09:47:32 +0000425void IpmbSensor::ipmbRequestCompletionCb(const boost::system::error_code& ec,
426 const IpmbMethodType& response)
427{
428 const int& status = std::get<0>(response);
429 if (ec || (status != 0))
430 {
431 incrementError();
432 read();
433 return;
434 }
435 const std::vector<uint8_t>& data = std::get<5>(response);
436 if constexpr (debug)
437 {
George Liu73f6cdc2025-02-20 15:15:19 +0800438 std::ostringstream tempStream;
439 for (int d : data)
Vikash Chandola1f847972022-09-28 09:47:32 +0000440 {
George Liu73f6cdc2025-02-20 15:15:19 +0800441 tempStream << std::setfill('0') << std::setw(2) << std::hex << d
442 << " ";
Vikash Chandola1f847972022-09-28 09:47:32 +0000443 }
George Liu73f6cdc2025-02-20 15:15:19 +0800444 lg2::info("'{NAME}': '{DATA}'", "NAME", name, "DATA", tempStream.str());
Vikash Chandola1f847972022-09-28 09:47:32 +0000445 }
446 if (data.empty())
447 {
448 incrementError();
449 read();
450 return;
451 }
452
453 double value = 0;
454
Ed Tanous828c5a62024-02-09 16:59:22 -0800455 if (!processReading(readingFormat, command, data, value, errCount))
Vikash Chandola1f847972022-09-28 09:47:32 +0000456 {
457 incrementError();
458 read();
459 return;
460 }
461
462 // rawValue only used in debug logging
463 // up to 5th byte in data are used to derive value
464 size_t end = std::min(sizeof(uint64_t), data.size());
465 uint64_t rawData = 0;
466 for (size_t i = 0; i < end; i++)
467 {
468 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
469 reinterpret_cast<uint8_t*>(&rawData)[i] = data[i];
470 }
471 rawValue = static_cast<double>(rawData);
472
473 /* Adjust value as per scale and offset */
474 value = (value * scaleVal) + offsetVal;
475 updateValue(value);
476 read();
477}
478
Ed Tanous201a1012024-04-03 18:07:28 -0700479void IpmbSensor::read()
James Feist6ef20402019-01-07 16:45:08 -0800480{
Ed Tanous83db50c2023-03-01 10:20:24 -0800481 waitTimer.expires_after(std::chrono::milliseconds(sensorPollMs));
Vikash Chandola1f847972022-09-28 09:47:32 +0000482 waitTimer.async_wait(
483 [weakRef{weak_from_this()}](const boost::system::error_code& ec) {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400484 if (ec == boost::asio::error::operation_aborted)
485 {
486 return; // we're being canceled
487 }
488 std::shared_ptr<IpmbSensor> self = weakRef.lock();
489 if (!self)
490 {
491 return;
492 }
493 self->sendIpmbRequest();
494 });
James Feist6ef20402019-01-07 16:45:08 -0800495}
Jayashree Dhanapal84189752022-03-07 12:51:54 +0530496
Vikash Chandola1f847972022-09-28 09:47:32 +0000497void IpmbSensor::sendIpmbRequest()
498{
499 if (!readingStateGood())
500 {
501 updateValue(std::numeric_limits<double>::quiet_NaN());
502 read();
503 return;
504 }
505 dbusConnection->async_method_call(
506 [weakRef{weak_from_this()}](boost::system::error_code ec,
507 const IpmbMethodType& response) {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400508 std::shared_ptr<IpmbSensor> self = weakRef.lock();
509 if (!self)
510 {
511 return;
512 }
513 self->ipmbRequestCompletionCb(ec, response);
514 },
Vikash Chandola1f847972022-09-28 09:47:32 +0000515 "xyz.openbmc_project.Ipmi.Channel.Ipmb",
516 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb",
517 "sendRequest", commandAddress, netfn, lun, command, commandData);
518}
519
Jayashree Dhanapal84189752022-03-07 12:51:54 +0530520bool IpmbSensor::sensorClassType(const std::string& sensorClass)
521{
522 if (sensorClass == "PxeBridgeTemp")
523 {
524 type = IpmbType::PXE1410CVR;
525 }
526 else if (sensorClass == "IRBridgeTemp")
527 {
528 type = IpmbType::IR38363VR;
529 }
530 else if (sensorClass == "HSCBridge")
531 {
532 type = IpmbType::ADM1278HSC;
533 }
534 else if (sensorClass == "MpsBridgeTemp")
535 {
536 type = IpmbType::mpsVR;
537 }
538 else if (sensorClass == "METemp" || sensorClass == "MESensor")
539 {
540 type = IpmbType::meSensor;
541 }
Rebecca Cran394f0c52023-12-17 20:08:55 -0700542 else if (sensorClass == "SMPro")
543 {
544 type = IpmbType::SMPro;
545 }
Jayashree Dhanapal84189752022-03-07 12:51:54 +0530546 else
547 {
George Liu73f6cdc2025-02-20 15:15:19 +0800548 lg2::error("Invalid class '{SENSOR}'", "SENSOR", sensorClass);
Jayashree Dhanapal84189752022-03-07 12:51:54 +0530549 return false;
550 }
551 return true;
552}
553
554void IpmbSensor::sensorSubType(const std::string& sensorTypeName)
555{
556 if (sensorTypeName == "voltage")
557 {
558 subType = IpmbSubType::volt;
559 }
560 else if (sensorTypeName == "power")
561 {
562 subType = IpmbSubType::power;
563 }
564 else if (sensorTypeName == "current")
565 {
566 subType = IpmbSubType::curr;
567 }
568 else if (sensorTypeName == "utilization")
569 {
570 subType = IpmbSubType::util;
571 }
572 else
573 {
574 subType = IpmbSubType::temp;
575 }
576}
577
578void IpmbSensor::parseConfigValues(const SensorBaseConfigMap& entry)
579{
580 auto findScaleVal = entry.find("ScaleValue");
581 if (findScaleVal != entry.end())
582 {
583 scaleVal = std::visit(VariantToDoubleVisitor(), findScaleVal->second);
584 }
585
586 auto findOffsetVal = entry.find("OffsetValue");
587 if (findOffsetVal != entry.end())
588 {
589 offsetVal = std::visit(VariantToDoubleVisitor(), findOffsetVal->second);
590 }
591
Zev Weissa4d27682022-07-19 15:30:36 -0700592 readState = getPowerState(entry);
Jayashree Dhanapal84189752022-03-07 12:51:54 +0530593}
594
James Feist6ef20402019-01-07 16:45:08 -0800595void createSensors(
Ed Tanous1f978632023-02-28 18:16:39 -0800596 boost::asio::io_context& io, sdbusplus::asio::object_server& objectServer,
Vikash Chandola1f847972022-09-28 09:47:32 +0000597 boost::container::flat_map<std::string, std::shared_ptr<IpmbSensor>>&
James Feist6ef20402019-01-07 16:45:08 -0800598 sensors,
599 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection)
600{
601 if (!dbusConnection)
602 {
George Liu73f6cdc2025-02-20 15:15:19 +0800603 lg2::error("Connection not created");
James Feist6ef20402019-01-07 16:45:08 -0800604 return;
605 }
606 dbusConnection->async_method_call(
607 [&](boost::system::error_code ec, const ManagedObjectType& resp) {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400608 if (ec)
James Feist6ef20402019-01-07 16:45:08 -0800609 {
George Liu73f6cdc2025-02-20 15:15:19 +0800610 lg2::error("Error contacting entity manager");
Patrick Williams2aaf7172024-08-16 15:20:40 -0400611 return;
James Feist6ef20402019-01-07 16:45:08 -0800612 }
Patrick Williams2aaf7172024-08-16 15:20:40 -0400613 for (const auto& [path, interfaces] : resp)
614 {
615 for (const auto& [intf, cfg] : interfaces)
616 {
617 if (intf != configInterfaceName(sensorType))
618 {
619 continue;
620 }
621 std::string name = loadVariant<std::string>(cfg, "Name");
622
623 std::vector<thresholds::Threshold> sensorThresholds;
624 if (!parseThresholdsFromConfig(interfaces,
625 sensorThresholds))
626 {
George Liu73f6cdc2025-02-20 15:15:19 +0800627 lg2::error("error populating thresholds '{NAME}'",
628 "NAME", name);
Patrick Williams2aaf7172024-08-16 15:20:40 -0400629 }
630 uint8_t deviceAddress =
631 loadVariant<uint8_t>(cfg, "Address");
632
633 std::string sensorClass =
634 loadVariant<std::string>(cfg, "Class");
635
636 uint8_t hostSMbusIndex = hostSMbusIndexDefault;
637 auto findSmType = cfg.find("HostSMbusIndex");
638 if (findSmType != cfg.end())
639 {
640 hostSMbusIndex = std::visit(
641 VariantToUnsignedIntVisitor(), findSmType->second);
642 }
643
644 float pollRate = getPollRate(cfg, pollRateDefault);
645
646 uint8_t ipmbBusIndex = ipmbBusIndexDefault;
647 auto findBusType = cfg.find("Bus");
648 if (findBusType != cfg.end())
649 {
650 ipmbBusIndex = std::visit(VariantToUnsignedIntVisitor(),
651 findBusType->second);
George Liu73f6cdc2025-02-20 15:15:19 +0800652 lg2::error("Ipmb Bus Index for '{NAME}' is '{INDEX}'",
653 "NAME", name, "INDEX", ipmbBusIndex);
Patrick Williams2aaf7172024-08-16 15:20:40 -0400654 }
655
656 /* Default sensor type is "temperature" */
657 std::string sensorTypeName = "temperature";
658 auto findType = cfg.find("SensorType");
659 if (findType != cfg.end())
660 {
661 sensorTypeName = std::visit(VariantToStringVisitor(),
662 findType->second);
663 }
664
665 auto& sensor = sensors[name];
666 sensor = nullptr;
667 sensor = std::make_shared<IpmbSensor>(
668 dbusConnection, io, name, path, objectServer,
669 std::move(sensorThresholds), deviceAddress,
670 hostSMbusIndex, pollRate, sensorTypeName);
671
672 sensor->parseConfigValues(cfg);
673 if (!(sensor->sensorClassType(sensorClass)))
674 {
675 continue;
676 }
677 sensor->sensorSubType(sensorTypeName);
678 sensor->init();
679 }
680 }
681 },
JeffLin2c5a1f22022-10-05 15:19:09 +0800682 entityManagerName, "/xyz/openbmc_project/inventory",
683 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
James Feist6ef20402019-01-07 16:45:08 -0800684}
685
Kumar Thangavel5d032bc2022-11-30 20:24:47 +0530686void interfaceRemoved(
687 sdbusplus::message_t& message,
688 boost::container::flat_map<std::string, std::shared_ptr<IpmbSensor>>&
689 sensors)
690{
691 if (message.is_method_error())
692 {
George Liu73f6cdc2025-02-20 15:15:19 +0800693 lg2::error("interfacesRemoved callback method error");
Kumar Thangavel5d032bc2022-11-30 20:24:47 +0530694 return;
695 }
696
697 sdbusplus::message::object_path removedPath;
698 std::vector<std::string> interfaces;
699
700 message.read(removedPath, interfaces);
701
702 // If the xyz.openbmc_project.Confguration.X interface was removed
703 // for one or more sensors, delete those sensor objects.
704 auto sensorIt = sensors.begin();
705 while (sensorIt != sensors.end())
706 {
707 if ((sensorIt->second->configurationPath == removedPath) &&
708 (std::find(interfaces.begin(), interfaces.end(),
709 configInterfaceName(sdrInterface)) != interfaces.end()))
710 {
711 sensorIt = sensors.erase(sensorIt);
712 }
713 else
714 {
715 sensorIt++;
716 }
717 }
718}