blob: 81be2eb2fb4c21b72ccd8531447ee92d7b15ba4b [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"
20
Ed Tanous9b4a20e2022-09-06 08:47:11 -070021#include <boost/asio/steady_timer.hpp>
James Feist38fb5982020-05-28 10:09:54 -070022
Andrew Jeffery34123562021-12-02 14:38:41 +103023#include <optional>
Nikhil Potadeb669b6b2019-03-13 10:52:21 -070024#include <regex>
25
Nnamdi Ajah06cd9882023-02-15 13:21:32 +010026static constexpr uint8_t nvmeMiDefaultSlaveAddr = 0x6A;
27
Nikhil Potadeb669b6b2019-03-13 10:52:21 -070028static NVMEMap nvmeDeviceMap;
29
Nikhil Potadeb669b6b2019-03-13 10:52:21 -070030NVMEMap& getNVMEMap()
31{
32 return nvmeDeviceMap;
33}
34
Andrew Jeffery34123562021-12-02 14:38:41 +103035static std::optional<int>
36 extractBusNumber(const std::string& path,
37 const SensorBaseConfigMap& properties)
38{
39 auto findBus = properties.find("Bus");
40 if (findBus == properties.end())
41 {
42 std::cerr << "could not determine bus number for " << path << "\n";
43 return std::nullopt;
44 }
45
46 return std::visit(VariantToIntVisitor(), findBus->second);
47}
48
Nnamdi Ajah06cd9882023-02-15 13:21:32 +010049static uint8_t extractSlaveAddr(const std::string& path,
50 const SensorBaseConfigMap& properties)
51{
52 auto findSlaveAddr = properties.find("Address");
53 if (findSlaveAddr == properties.end())
54 {
55 std::cerr << "could not determine slave address for " << path << "\n"
56 << "using default as specified in nvme-mi"
57 << "\n";
58 return nvmeMiDefaultSlaveAddr;
59 }
60
61 return std::visit(VariantToUnsignedIntVisitor(), findSlaveAddr->second);
62}
63
Andrew Jefferye671f052021-12-02 14:47:20 +103064static std::optional<std::string>
65 extractSensorName(const std::string& path,
66 const SensorBaseConfigMap& properties)
67{
68 auto findSensorName = properties.find("Name");
69 if (findSensorName == properties.end())
70 {
71 std::cerr << "could not determine configuration name for " << path
72 << "\n";
73 return std::nullopt;
74 }
75
76 return std::get<std::string>(findSensorName->second);
77}
78
Andrew Jeffery710562a2021-12-02 14:55:55 +103079static std::filesystem::path deriveRootBusPath(int busNumber)
80{
81 return "/sys/bus/i2c/devices/i2c-" + std::to_string(busNumber) +
82 "/mux_device";
83}
84
Andrew Jeffery66ab8402021-12-02 15:03:51 +103085static std::optional<int> deriveRootBus(std::optional<int> busNumber)
86{
87 if (!busNumber)
88 {
89 return std::nullopt;
90 }
91
92 std::filesystem::path muxPath = deriveRootBusPath(*busNumber);
93
94 if (!std::filesystem::is_symlink(muxPath))
95 {
Ed Tanousb0745282024-04-03 18:57:45 -070096 return busNumber;
Andrew Jeffery66ab8402021-12-02 15:03:51 +103097 }
98
99 std::string rootName = std::filesystem::read_symlink(muxPath).filename();
100 size_t dash = rootName.find('-');
101 if (dash == std::string::npos)
102 {
103 std::cerr << "Error finding root bus for " << rootName << "\n";
104 return std::nullopt;
105 }
106
107 return std::stoi(rootName.substr(0, dash));
108}
109
Andrew Jefferyc7a89e52021-12-02 15:10:23 +1030110static std::shared_ptr<NVMeContext>
Ed Tanous1f978632023-02-28 18:16:39 -0800111 provideRootBusContext(boost::asio::io_context& io, NVMEMap& map,
Andrew Jefferyc7a89e52021-12-02 15:10:23 +1030112 int rootBus)
113{
114 auto findRoot = map.find(rootBus);
115 if (findRoot != map.end())
116 {
117 return findRoot->second;
118 }
119
120 std::shared_ptr<NVMeContext> context =
Andrew Jefferyc7a89e52021-12-02 15:10:23 +1030121 std::make_shared<NVMeBasicContext>(io, rootBus);
Andrew Jefferyc7a89e52021-12-02 15:10:23 +1030122 map[rootBus] = context;
123
124 return context;
125}
126
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030127static void handleSensorConfigurations(
Ed Tanous1f978632023-02-28 18:16:39 -0800128 boost::asio::io_context& io, sdbusplus::asio::object_server& objectServer,
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030129 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
130 const ManagedObjectType& sensorConfigurations)
131{
132 // todo: it'd be better to only update the ones we care about
133 for (const auto& [_, nvmeContextPtr] : nvmeDeviceMap)
134 {
135 if (nvmeContextPtr)
136 {
137 nvmeContextPtr->close();
138 }
139 }
140 nvmeDeviceMap.clear();
141
142 // iterate through all found configurations
Andrew Jefferyee164342021-12-02 16:02:19 +1030143 for (const auto& [interfacePath, sensorData] : sensorConfigurations)
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030144 {
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030145 // find base configuration
Zev Weiss054aad82022-08-18 01:37:34 -0700146 auto sensorBase =
147 sensorData.find(configInterfaceName(NVMeSensor::sensorType));
Zev Weissefae44c2022-08-16 15:39:20 -0700148 if (sensorBase == sensorData.end())
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030149 {
Zev Weissefae44c2022-08-16 15:39:20 -0700150 continue;
151 }
Andrew Jefferyee164342021-12-02 16:02:19 +1030152
Zev Weissefae44c2022-08-16 15:39:20 -0700153 const SensorBaseConfigMap& sensorConfig = sensorBase->second;
Patrick Williams779c96a2023-05-10 07:50:42 -0500154 std::optional<int> busNumber = extractBusNumber(interfacePath,
155 sensorConfig);
156 std::optional<std::string> sensorName = extractSensorName(interfacePath,
157 sensorConfig);
Nnamdi Ajah06cd9882023-02-15 13:21:32 +0100158 uint8_t slaveAddr = extractSlaveAddr(interfacePath, sensorConfig);
Zev Weissefae44c2022-08-16 15:39:20 -0700159 std::optional<int> rootBus = deriveRootBus(busNumber);
Andrew Jefferyee164342021-12-02 16:02:19 +1030160
Zev Weissefae44c2022-08-16 15:39:20 -0700161 if (!(busNumber && sensorName && rootBus))
162 {
163 continue;
164 }
Andrew Jefferyee164342021-12-02 16:02:19 +1030165
Zev Weissefae44c2022-08-16 15:39:20 -0700166 std::vector<thresholds::Threshold> sensorThresholds;
167 if (!parseThresholdsFromConfig(sensorData, sensorThresholds))
168 {
169 std::cerr << "error populating thresholds for " << *sensorName
170 << "\n";
171 }
Andrew Jefferyee164342021-12-02 16:02:19 +1030172
Zev Weissefae44c2022-08-16 15:39:20 -0700173 try
174 {
175 // May throw for an invalid rootBus
176 std::shared_ptr<NVMeContext> context =
177 provideRootBusContext(io, nvmeDeviceMap, *rootBus);
Andrew Jeffery25e20bd2022-03-15 22:26:04 +1030178
Zev Weissefae44c2022-08-16 15:39:20 -0700179 // Construct the sensor after grabbing the context so we don't
180 // glitch D-Bus May throw for an invalid busNumber
181 std::shared_ptr<NVMeSensor> sensorPtr =
182 std::make_shared<NVMeSensor>(
183 objectServer, io, dbusConnection, *sensorName,
Nnamdi Ajah06cd9882023-02-15 13:21:32 +0100184 std::move(sensorThresholds), interfacePath, *busNumber,
185 slaveAddr);
Zev Weissefae44c2022-08-16 15:39:20 -0700186
187 context->addSensor(sensorPtr);
188 }
189 catch (const std::invalid_argument& ex)
190 {
191 std::cerr << "Failed to add sensor for "
192 << std::string(interfacePath) << ": " << ex.what()
193 << "\n";
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030194 }
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030195 }
196 for (const auto& [_, context] : nvmeDeviceMap)
197 {
198 context->pollNVMeDevices();
199 }
200}
201
Ed Tanous1f978632023-02-28 18:16:39 -0800202void createSensors(boost::asio::io_context& io,
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700203 sdbusplus::asio::object_server& objectServer,
204 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection)
205{
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700206 auto getter = std::make_shared<GetSensorConfiguration>(
Ed Tanous86d83012022-02-18 09:51:47 -0800207 dbusConnection, [&io, &objectServer, &dbusConnection](
208 const ManagedObjectType& sensorConfigurations) {
Patrick Williams597e8422023-10-20 11:19:01 -0500209 handleSensorConfigurations(io, objectServer, dbusConnection,
210 sensorConfigurations);
211 });
Zev Weiss054aad82022-08-18 01:37:34 -0700212 getter->getConfiguration(std::vector<std::string>{NVMeSensor::sensorType});
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700213}
214
Patrick Williams92f8f512022-07-22 19:26:55 -0500215static void interfaceRemoved(sdbusplus::message_t& message, NVMEMap& contexts)
Andrew Jefferyafd55b92021-12-08 10:58:17 +1030216{
217 if (message.is_method_error())
218 {
219 std::cerr << "interfacesRemoved callback method error\n";
220 return;
221 }
222
223 sdbusplus::message::object_path path;
224 std::vector<std::string> interfaces;
225
226 message.read(path, interfaces);
227
228 for (auto& [_, context] : contexts)
229 {
230 std::optional<std::shared_ptr<NVMeSensor>> sensor =
231 context->getSensorAtPath(path);
232 if (!sensor)
233 {
234 continue;
235 }
236
237 auto interface = std::find(interfaces.begin(), interfaces.end(),
Matt Spinler55832f32023-06-07 10:24:00 -0500238 (*sensor)->configInterface);
Andrew Jefferyafd55b92021-12-08 10:58:17 +1030239 if (interface == interfaces.end())
240 {
241 continue;
242 }
243
244 context->removeSensor(sensor.value());
245 }
246}
247
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700248int main()
249{
Ed Tanous1f978632023-02-28 18:16:39 -0800250 boost::asio::io_context io;
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700251 auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
252 systemBus->request_name("xyz.openbmc_project.NVMeSensor");
Johnathan Mantey661d4372022-10-27 09:00:59 -0700253 sdbusplus::asio::object_server objectServer(systemBus, true);
Andrew Jefferyea148ec2023-01-17 15:43:33 +1030254 objectServer.add_manager("/xyz/openbmc_project/sensors");
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700255
Ed Tanous83db50c2023-03-01 10:20:24 -0800256 boost::asio::post(io,
257 [&]() { createSensors(io, objectServer, systemBus); });
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700258
Ed Tanous9b4a20e2022-09-06 08:47:11 -0700259 boost::asio::steady_timer filterTimer(io);
Patrick Williams92f8f512022-07-22 19:26:55 -0500260 std::function<void(sdbusplus::message_t&)> eventHandler =
261 [&filterTimer, &io, &objectServer, &systemBus](sdbusplus::message_t&) {
Ed Tanousbb679322022-05-16 16:10:00 -0700262 // this implicitly cancels the timer
Ed Tanous83db50c2023-03-01 10:20:24 -0800263 filterTimer.expires_after(std::chrono::seconds(1));
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700264
Ed Tanousbb679322022-05-16 16:10:00 -0700265 filterTimer.async_wait([&](const boost::system::error_code& ec) {
266 if (ec == boost::asio::error::operation_aborted)
267 {
268 return; // we're being canceled
269 }
Andrew Jeffery7279f932021-05-25 13:35:27 +0930270
Ed Tanousbb679322022-05-16 16:10:00 -0700271 if (ec)
272 {
273 std::cerr << "Error: " << ec.message() << "\n";
274 return;
275 }
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700276
Ed Tanousbb679322022-05-16 16:10:00 -0700277 createSensors(io, objectServer, systemBus);
278 });
279 };
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700280
Zev Weiss214d9712022-08-12 12:54:31 -0700281 std::vector<std::unique_ptr<sdbusplus::bus::match_t>> matches =
282 setupPropertiesChangedMatches(
Zev Weiss054aad82022-08-18 01:37:34 -0700283 *systemBus, std::to_array<const char*>({NVMeSensor::sensorType}),
Zev Weiss214d9712022-08-12 12:54:31 -0700284 eventHandler);
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700285
Andrew Jefferyafd55b92021-12-08 10:58:17 +1030286 // Watch for entity-manager to remove configuration interfaces
287 // so the corresponding sensors can be removed.
Patrick Williams92f8f512022-07-22 19:26:55 -0500288 auto ifaceRemovedMatch = std::make_unique<sdbusplus::bus::match_t>(
289 static_cast<sdbusplus::bus_t&>(*systemBus),
Andrew Jefferyafd55b92021-12-08 10:58:17 +1030290 "type='signal',member='InterfacesRemoved',arg0path='" +
291 std::string(inventoryPath) + "/'",
Patrick Williams92f8f512022-07-22 19:26:55 -0500292 [](sdbusplus::message_t& msg) {
Ed Tanousbb679322022-05-16 16:10:00 -0700293 interfaceRemoved(msg, nvmeDeviceMap);
Patrick Williams597e8422023-10-20 11:19:01 -0500294 });
Andrew Jefferyafd55b92021-12-08 10:58:17 +1030295
Bruce Lee1263c3d2021-06-04 15:16:33 +0800296 setupManufacturingModeMatch(*systemBus);
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700297 io.run();
298}