blob: 0f1d9d5d6b18ea9bcece9615169ad005c98b598d [file] [log] [blame]
Nikhil Potadeb669b6b2019-03-13 10:52:21 -07001/*
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 "NVMeBasicContext.hpp"
18#include "NVMeContext.hpp"
19#include "NVMeSensor.hpp"
Ed Tanouseacbfdd2024-04-04 12:00:24 -070020#include "Thresholds.hpp"
21#include "Utils.hpp"
22#include "VariantVisitors.hpp"
Andrew Jefferye73bd0a2023-01-25 10:39:57 +103023
Ed Tanouseacbfdd2024-04-04 12:00:24 -070024#include <boost/asio/error.hpp>
25#include <boost/asio/io_context.hpp>
26#include <boost/asio/post.hpp>
Ed Tanous9b4a20e2022-09-06 08:47:11 -070027#include <boost/asio/steady_timer.hpp>
George Liu7201be42025-02-20 20:01:54 +080028#include <phosphor-logging/lg2.hpp>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070029#include <sdbusplus/asio/connection.hpp>
30#include <sdbusplus/asio/object_server.hpp>
31#include <sdbusplus/bus.hpp>
32#include <sdbusplus/bus/match.hpp>
33#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>
38#include <chrono>
39#include <cstddef>
40#include <cstdint>
41#include <filesystem>
42#include <functional>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070043#include <memory>
Andrew Jeffery34123562021-12-02 14:38:41 +103044#include <optional>
Ed Tanouseacbfdd2024-04-04 12:00:24 -070045#include <stdexcept>
46#include <string>
47#include <utility>
48#include <variant>
49#include <vector>
Nikhil Potadeb669b6b2019-03-13 10:52:21 -070050
Nnamdi Ajah06cd9882023-02-15 13:21:32 +010051static constexpr uint8_t nvmeMiDefaultSlaveAddr = 0x6A;
52
Nikhil Potadeb669b6b2019-03-13 10:52:21 -070053static NVMEMap nvmeDeviceMap;
54
Nikhil Potadeb669b6b2019-03-13 10:52:21 -070055NVMEMap& getNVMEMap()
56{
57 return nvmeDeviceMap;
58}
59
Patrick Williams2aaf7172024-08-16 15:20:40 -040060static std::optional<int> extractBusNumber(
61 const std::string& path, const SensorBaseConfigMap& properties)
Andrew Jeffery34123562021-12-02 14:38:41 +103062{
63 auto findBus = properties.find("Bus");
64 if (findBus == properties.end())
65 {
George Liu7201be42025-02-20 20:01:54 +080066 lg2::error("could not determine bus number for '{PATH}'", "PATH", path);
Andrew Jeffery34123562021-12-02 14:38:41 +103067 return std::nullopt;
68 }
69
70 return std::visit(VariantToIntVisitor(), findBus->second);
71}
72
Nnamdi Ajah06cd9882023-02-15 13:21:32 +010073static uint8_t extractSlaveAddr(const std::string& path,
74 const SensorBaseConfigMap& properties)
75{
76 auto findSlaveAddr = properties.find("Address");
77 if (findSlaveAddr == properties.end())
78 {
George Liu7201be42025-02-20 20:01:54 +080079 lg2::error(
80 "could not determine slave address for '{PATH} 'using default as "
81 "specified in nvme-mi",
82 "PATH", path);
Nnamdi Ajah06cd9882023-02-15 13:21:32 +010083 return nvmeMiDefaultSlaveAddr;
84 }
85
86 return std::visit(VariantToUnsignedIntVisitor(), findSlaveAddr->second);
87}
88
Patrick Williams2aaf7172024-08-16 15:20:40 -040089static std::optional<std::string> extractSensorName(
90 const std::string& path, const SensorBaseConfigMap& properties)
Andrew Jefferye671f052021-12-02 14:47:20 +103091{
92 auto findSensorName = properties.find("Name");
93 if (findSensorName == properties.end())
94 {
George Liu7201be42025-02-20 20:01:54 +080095 lg2::error("could not determine configuration name for '{PATH}'",
96 "PATH", path);
Andrew Jefferye671f052021-12-02 14:47:20 +103097 return std::nullopt;
98 }
99
100 return std::get<std::string>(findSensorName->second);
101}
102
Andrew Jeffery710562a2021-12-02 14:55:55 +1030103static std::filesystem::path deriveRootBusPath(int busNumber)
104{
105 return "/sys/bus/i2c/devices/i2c-" + std::to_string(busNumber) +
106 "/mux_device";
107}
108
Andrew Jeffery66ab8402021-12-02 15:03:51 +1030109static std::optional<int> deriveRootBus(std::optional<int> busNumber)
110{
111 if (!busNumber)
112 {
113 return std::nullopt;
114 }
115
116 std::filesystem::path muxPath = deriveRootBusPath(*busNumber);
117
118 if (!std::filesystem::is_symlink(muxPath))
119 {
Ed Tanousb0745282024-04-03 18:57:45 -0700120 return busNumber;
Andrew Jeffery66ab8402021-12-02 15:03:51 +1030121 }
122
123 std::string rootName = std::filesystem::read_symlink(muxPath).filename();
124 size_t dash = rootName.find('-');
125 if (dash == std::string::npos)
126 {
George Liu7201be42025-02-20 20:01:54 +0800127 lg2::error("Error finding root bus for '{NAME}'", "NAME", rootName);
Andrew Jeffery66ab8402021-12-02 15:03:51 +1030128 return std::nullopt;
129 }
130
131 return std::stoi(rootName.substr(0, dash));
132}
133
Patrick Williams2aaf7172024-08-16 15:20:40 -0400134static std::shared_ptr<NVMeContext> provideRootBusContext(
135 boost::asio::io_context& io, NVMEMap& map, int rootBus)
Andrew Jefferyc7a89e52021-12-02 15:10:23 +1030136{
137 auto findRoot = map.find(rootBus);
138 if (findRoot != map.end())
139 {
140 return findRoot->second;
141 }
142
143 std::shared_ptr<NVMeContext> context =
Andrew Jefferyc7a89e52021-12-02 15:10:23 +1030144 std::make_shared<NVMeBasicContext>(io, rootBus);
Andrew Jefferyc7a89e52021-12-02 15:10:23 +1030145 map[rootBus] = context;
146
147 return context;
148}
149
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030150static void handleSensorConfigurations(
Ed Tanous1f978632023-02-28 18:16:39 -0800151 boost::asio::io_context& io, sdbusplus::asio::object_server& objectServer,
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030152 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
153 const ManagedObjectType& sensorConfigurations)
154{
155 // todo: it'd be better to only update the ones we care about
156 for (const auto& [_, nvmeContextPtr] : nvmeDeviceMap)
157 {
158 if (nvmeContextPtr)
159 {
160 nvmeContextPtr->close();
161 }
162 }
163 nvmeDeviceMap.clear();
164
165 // iterate through all found configurations
Andrew Jefferyee164342021-12-02 16:02:19 +1030166 for (const auto& [interfacePath, sensorData] : sensorConfigurations)
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030167 {
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030168 // find base configuration
Zev Weiss054aad82022-08-18 01:37:34 -0700169 auto sensorBase =
170 sensorData.find(configInterfaceName(NVMeSensor::sensorType));
Zev Weissefae44c2022-08-16 15:39:20 -0700171 if (sensorBase == sensorData.end())
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030172 {
Zev Weissefae44c2022-08-16 15:39:20 -0700173 continue;
174 }
Andrew Jefferyee164342021-12-02 16:02:19 +1030175
Zev Weissefae44c2022-08-16 15:39:20 -0700176 const SensorBaseConfigMap& sensorConfig = sensorBase->second;
Patrick Williams2aaf7172024-08-16 15:20:40 -0400177 std::optional<int> busNumber =
178 extractBusNumber(interfacePath, sensorConfig);
179 std::optional<std::string> sensorName =
180 extractSensorName(interfacePath, sensorConfig);
Nnamdi Ajah06cd9882023-02-15 13:21:32 +0100181 uint8_t slaveAddr = extractSlaveAddr(interfacePath, sensorConfig);
Zev Weissefae44c2022-08-16 15:39:20 -0700182 std::optional<int> rootBus = deriveRootBus(busNumber);
Andrew Jefferyee164342021-12-02 16:02:19 +1030183
Zev Weissefae44c2022-08-16 15:39:20 -0700184 if (!(busNumber && sensorName && rootBus))
185 {
186 continue;
187 }
Andrew Jefferyee164342021-12-02 16:02:19 +1030188
Zev Weissefae44c2022-08-16 15:39:20 -0700189 std::vector<thresholds::Threshold> sensorThresholds;
190 if (!parseThresholdsFromConfig(sensorData, sensorThresholds))
191 {
George Liu7201be42025-02-20 20:01:54 +0800192 lg2::error("error populating thresholds for '{NAME}'", "NAME",
193 *sensorName);
Zev Weissefae44c2022-08-16 15:39:20 -0700194 }
Andrew Jefferyee164342021-12-02 16:02:19 +1030195
Zev Weissefae44c2022-08-16 15:39:20 -0700196 try
197 {
198 // May throw for an invalid rootBus
199 std::shared_ptr<NVMeContext> context =
200 provideRootBusContext(io, nvmeDeviceMap, *rootBus);
Andrew Jeffery25e20bd2022-03-15 22:26:04 +1030201
Zev Weissefae44c2022-08-16 15:39:20 -0700202 // Construct the sensor after grabbing the context so we don't
203 // glitch D-Bus May throw for an invalid busNumber
204 std::shared_ptr<NVMeSensor> sensorPtr =
205 std::make_shared<NVMeSensor>(
206 objectServer, io, dbusConnection, *sensorName,
Nnamdi Ajah06cd9882023-02-15 13:21:32 +0100207 std::move(sensorThresholds), interfacePath, *busNumber,
208 slaveAddr);
Zev Weissefae44c2022-08-16 15:39:20 -0700209
210 context->addSensor(sensorPtr);
211 }
212 catch (const std::invalid_argument& ex)
213 {
George Liu7201be42025-02-20 20:01:54 +0800214 lg2::error("Failed to add sensor for '{PATH}': '{ERROR}'", "PATH",
215 interfacePath.str, "ERROR", ex);
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030216 }
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030217 }
218 for (const auto& [_, context] : nvmeDeviceMap)
219 {
220 context->pollNVMeDevices();
221 }
222}
223
Ed Tanous1f978632023-02-28 18:16:39 -0800224void createSensors(boost::asio::io_context& io,
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700225 sdbusplus::asio::object_server& objectServer,
226 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection)
227{
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700228 auto getter = std::make_shared<GetSensorConfiguration>(
Ed Tanous86d83012022-02-18 09:51:47 -0800229 dbusConnection, [&io, &objectServer, &dbusConnection](
230 const ManagedObjectType& sensorConfigurations) {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400231 handleSensorConfigurations(io, objectServer, dbusConnection,
232 sensorConfigurations);
233 });
Zev Weiss054aad82022-08-18 01:37:34 -0700234 getter->getConfiguration(std::vector<std::string>{NVMeSensor::sensorType});
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700235}
236
Patrick Williams92f8f512022-07-22 19:26:55 -0500237static void interfaceRemoved(sdbusplus::message_t& message, NVMEMap& contexts)
Andrew Jefferyafd55b92021-12-08 10:58:17 +1030238{
239 if (message.is_method_error())
240 {
George Liu7201be42025-02-20 20:01:54 +0800241 lg2::error("interfacesRemoved callback method error");
Andrew Jefferyafd55b92021-12-08 10:58:17 +1030242 return;
243 }
244
245 sdbusplus::message::object_path path;
246 std::vector<std::string> interfaces;
247
248 message.read(path, interfaces);
249
250 for (auto& [_, context] : contexts)
251 {
252 std::optional<std::shared_ptr<NVMeSensor>> sensor =
253 context->getSensorAtPath(path);
254 if (!sensor)
255 {
256 continue;
257 }
258
259 auto interface = std::find(interfaces.begin(), interfaces.end(),
Matt Spinler55832f32023-06-07 10:24:00 -0500260 (*sensor)->configInterface);
Andrew Jefferyafd55b92021-12-08 10:58:17 +1030261 if (interface == interfaces.end())
262 {
263 continue;
264 }
265
266 context->removeSensor(sensor.value());
267 }
268}
269
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700270int main()
271{
Ed Tanous1f978632023-02-28 18:16:39 -0800272 boost::asio::io_context io;
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700273 auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
274 systemBus->request_name("xyz.openbmc_project.NVMeSensor");
Johnathan Mantey661d4372022-10-27 09:00:59 -0700275 sdbusplus::asio::object_server objectServer(systemBus, true);
Andrew Jefferyea148ec2023-01-17 15:43:33 +1030276 objectServer.add_manager("/xyz/openbmc_project/sensors");
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700277
Ed Tanous83db50c2023-03-01 10:20:24 -0800278 boost::asio::post(io,
279 [&]() { createSensors(io, objectServer, systemBus); });
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700280
Ed Tanous9b4a20e2022-09-06 08:47:11 -0700281 boost::asio::steady_timer filterTimer(io);
Patrick Williams92f8f512022-07-22 19:26:55 -0500282 std::function<void(sdbusplus::message_t&)> eventHandler =
283 [&filterTimer, &io, &objectServer, &systemBus](sdbusplus::message_t&) {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400284 // this implicitly cancels the timer
285 filterTimer.expires_after(std::chrono::seconds(1));
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700286
Patrick Williams2aaf7172024-08-16 15:20:40 -0400287 filterTimer.async_wait([&](const boost::system::error_code& ec) {
288 if (ec == boost::asio::error::operation_aborted)
289 {
290 return; // we're being canceled
291 }
Andrew Jeffery7279f932021-05-25 13:35:27 +0930292
Patrick Williams2aaf7172024-08-16 15:20:40 -0400293 if (ec)
294 {
George Liu7201be42025-02-20 20:01:54 +0800295 lg2::error("Error: '{ERROR_MESSAGE}'", "ERROR_MESSAGE",
296 ec.message());
Patrick Williams2aaf7172024-08-16 15:20:40 -0400297 return;
298 }
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700299
Patrick Williams2aaf7172024-08-16 15:20:40 -0400300 createSensors(io, objectServer, systemBus);
301 });
302 };
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700303
Zev Weiss214d9712022-08-12 12:54:31 -0700304 std::vector<std::unique_ptr<sdbusplus::bus::match_t>> matches =
305 setupPropertiesChangedMatches(
Zev Weiss054aad82022-08-18 01:37:34 -0700306 *systemBus, std::to_array<const char*>({NVMeSensor::sensorType}),
Zev Weiss214d9712022-08-12 12:54:31 -0700307 eventHandler);
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700308
Andrew Jefferyafd55b92021-12-08 10:58:17 +1030309 // Watch for entity-manager to remove configuration interfaces
310 // so the corresponding sensors can be removed.
Patrick Williams92f8f512022-07-22 19:26:55 -0500311 auto ifaceRemovedMatch = std::make_unique<sdbusplus::bus::match_t>(
312 static_cast<sdbusplus::bus_t&>(*systemBus),
Andrew Jefferyafd55b92021-12-08 10:58:17 +1030313 "type='signal',member='InterfacesRemoved',arg0path='" +
314 std::string(inventoryPath) + "/'",
Patrick Williams92f8f512022-07-22 19:26:55 -0500315 [](sdbusplus::message_t& msg) {
Patrick Williams2aaf7172024-08-16 15:20:40 -0400316 interfaceRemoved(msg, nvmeDeviceMap);
317 });
Andrew Jefferyafd55b92021-12-08 10:58:17 +1030318
Bruce Lee1263c3d2021-06-04 15:16:33 +0800319 setupManufacturingModeMatch(*systemBus);
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700320 io.run();
321}