blob: 135145685d18c722c60ba2d26596cb426b744a93 [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 Jefferye3e3c972021-05-26 14:37:07 +093017#include <NVMeBasicContext.hpp>
Andrew Jefferydae6e182021-05-21 16:23:07 +093018#include <NVMeContext.hpp>
Ed Tanous8a57ec02020-10-09 12:46:52 -070019#include <NVMeSensor.hpp>
Ed Tanous9b4a20e2022-09-06 08:47:11 -070020#include <boost/asio/steady_timer.hpp>
James Feist38fb5982020-05-28 10:09:54 -070021
Andrew Jeffery34123562021-12-02 14:38:41 +103022#include <optional>
Nikhil Potadeb669b6b2019-03-13 10:52:21 -070023#include <regex>
24
Nikhil Potadeb669b6b2019-03-13 10:52:21 -070025static NVMEMap nvmeDeviceMap;
26
Nikhil Potadeb669b6b2019-03-13 10:52:21 -070027NVMEMap& getNVMEMap()
28{
29 return nvmeDeviceMap;
30}
31
Andrew Jeffery34123562021-12-02 14:38:41 +103032static std::optional<int>
33 extractBusNumber(const std::string& path,
34 const SensorBaseConfigMap& properties)
35{
36 auto findBus = properties.find("Bus");
37 if (findBus == properties.end())
38 {
39 std::cerr << "could not determine bus number for " << path << "\n";
40 return std::nullopt;
41 }
42
43 return std::visit(VariantToIntVisitor(), findBus->second);
44}
45
Andrew Jefferye671f052021-12-02 14:47:20 +103046static std::optional<std::string>
47 extractSensorName(const std::string& path,
48 const SensorBaseConfigMap& properties)
49{
50 auto findSensorName = properties.find("Name");
51 if (findSensorName == properties.end())
52 {
53 std::cerr << "could not determine configuration name for " << path
54 << "\n";
55 return std::nullopt;
56 }
57
58 return std::get<std::string>(findSensorName->second);
59}
60
Andrew Jeffery710562a2021-12-02 14:55:55 +103061static std::filesystem::path deriveRootBusPath(int busNumber)
62{
63 return "/sys/bus/i2c/devices/i2c-" + std::to_string(busNumber) +
64 "/mux_device";
65}
66
Andrew Jeffery66ab8402021-12-02 15:03:51 +103067static std::optional<int> deriveRootBus(std::optional<int> busNumber)
68{
69 if (!busNumber)
70 {
71 return std::nullopt;
72 }
73
74 std::filesystem::path muxPath = deriveRootBusPath(*busNumber);
75
76 if (!std::filesystem::is_symlink(muxPath))
77 {
78 return *busNumber;
79 }
80
81 std::string rootName = std::filesystem::read_symlink(muxPath).filename();
82 size_t dash = rootName.find('-');
83 if (dash == std::string::npos)
84 {
85 std::cerr << "Error finding root bus for " << rootName << "\n";
86 return std::nullopt;
87 }
88
89 return std::stoi(rootName.substr(0, dash));
90}
91
Andrew Jefferyc7a89e52021-12-02 15:10:23 +103092static std::shared_ptr<NVMeContext>
93 provideRootBusContext(boost::asio::io_service& io, NVMEMap& map,
94 int rootBus)
95{
96 auto findRoot = map.find(rootBus);
97 if (findRoot != map.end())
98 {
99 return findRoot->second;
100 }
101
102 std::shared_ptr<NVMeContext> context =
Andrew Jefferyc7a89e52021-12-02 15:10:23 +1030103 std::make_shared<NVMeBasicContext>(io, rootBus);
Andrew Jefferyc7a89e52021-12-02 15:10:23 +1030104 map[rootBus] = context;
105
106 return context;
107}
108
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030109static void handleSensorConfigurations(
110 boost::asio::io_service& io, sdbusplus::asio::object_server& objectServer,
111 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
112 const ManagedObjectType& sensorConfigurations)
113{
114 // todo: it'd be better to only update the ones we care about
115 for (const auto& [_, nvmeContextPtr] : nvmeDeviceMap)
116 {
117 if (nvmeContextPtr)
118 {
119 nvmeContextPtr->close();
120 }
121 }
122 nvmeDeviceMap.clear();
123
124 // iterate through all found configurations
Andrew Jefferyee164342021-12-02 16:02:19 +1030125 for (const auto& [interfacePath, sensorData] : sensorConfigurations)
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030126 {
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030127 // find base configuration
Zev Weiss054aad82022-08-18 01:37:34 -0700128 auto sensorBase =
129 sensorData.find(configInterfaceName(NVMeSensor::sensorType));
Zev Weissefae44c2022-08-16 15:39:20 -0700130 if (sensorBase == sensorData.end())
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030131 {
Zev Weissefae44c2022-08-16 15:39:20 -0700132 continue;
133 }
Andrew Jefferyee164342021-12-02 16:02:19 +1030134
Zev Weissefae44c2022-08-16 15:39:20 -0700135 const SensorBaseConfigMap& sensorConfig = sensorBase->second;
136 std::optional<int> busNumber =
137 extractBusNumber(interfacePath, sensorConfig);
138 std::optional<std::string> sensorName =
139 extractSensorName(interfacePath, sensorConfig);
140 std::optional<int> rootBus = deriveRootBus(busNumber);
Andrew Jefferyee164342021-12-02 16:02:19 +1030141
Zev Weissefae44c2022-08-16 15:39:20 -0700142 if (!(busNumber && sensorName && rootBus))
143 {
144 continue;
145 }
Andrew Jefferyee164342021-12-02 16:02:19 +1030146
Zev Weissefae44c2022-08-16 15:39:20 -0700147 std::vector<thresholds::Threshold> sensorThresholds;
148 if (!parseThresholdsFromConfig(sensorData, sensorThresholds))
149 {
150 std::cerr << "error populating thresholds for " << *sensorName
151 << "\n";
152 }
Andrew Jefferyee164342021-12-02 16:02:19 +1030153
Zev Weissefae44c2022-08-16 15:39:20 -0700154 try
155 {
156 // May throw for an invalid rootBus
157 std::shared_ptr<NVMeContext> context =
158 provideRootBusContext(io, nvmeDeviceMap, *rootBus);
Andrew Jeffery25e20bd2022-03-15 22:26:04 +1030159
Zev Weissefae44c2022-08-16 15:39:20 -0700160 // Construct the sensor after grabbing the context so we don't
161 // glitch D-Bus May throw for an invalid busNumber
162 std::shared_ptr<NVMeSensor> sensorPtr =
163 std::make_shared<NVMeSensor>(
164 objectServer, io, dbusConnection, *sensorName,
165 std::move(sensorThresholds), interfacePath, *busNumber);
166
167 context->addSensor(sensorPtr);
168 }
169 catch (const std::invalid_argument& ex)
170 {
171 std::cerr << "Failed to add sensor for "
172 << std::string(interfacePath) << ": " << ex.what()
173 << "\n";
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030174 }
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030175 }
176 for (const auto& [_, context] : nvmeDeviceMap)
177 {
178 context->pollNVMeDevices();
179 }
180}
181
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700182void createSensors(boost::asio::io_service& io,
183 sdbusplus::asio::object_server& objectServer,
184 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection)
185{
186
187 auto getter = std::make_shared<GetSensorConfiguration>(
Ed Tanous86d83012022-02-18 09:51:47 -0800188 dbusConnection, [&io, &objectServer, &dbusConnection](
189 const ManagedObjectType& sensorConfigurations) {
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030190 handleSensorConfigurations(io, objectServer, dbusConnection,
191 sensorConfigurations);
Ed Tanous86d83012022-02-18 09:51:47 -0800192 });
Zev Weiss054aad82022-08-18 01:37:34 -0700193 getter->getConfiguration(std::vector<std::string>{NVMeSensor::sensorType});
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700194}
195
Patrick Williams92f8f512022-07-22 19:26:55 -0500196static void interfaceRemoved(sdbusplus::message_t& message, NVMEMap& contexts)
Andrew Jefferyafd55b92021-12-08 10:58:17 +1030197{
198 if (message.is_method_error())
199 {
200 std::cerr << "interfacesRemoved callback method error\n";
201 return;
202 }
203
204 sdbusplus::message::object_path path;
205 std::vector<std::string> interfaces;
206
207 message.read(path, interfaces);
208
209 for (auto& [_, context] : contexts)
210 {
211 std::optional<std::shared_ptr<NVMeSensor>> sensor =
212 context->getSensorAtPath(path);
213 if (!sensor)
214 {
215 continue;
216 }
217
218 auto interface = std::find(interfaces.begin(), interfaces.end(),
219 (*sensor)->objectType);
220 if (interface == interfaces.end())
221 {
222 continue;
223 }
224
225 context->removeSensor(sensor.value());
226 }
227}
228
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700229int main()
230{
231 boost::asio::io_service io;
232 auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
233 systemBus->request_name("xyz.openbmc_project.NVMeSensor");
Johnathan Mantey661d4372022-10-27 09:00:59 -0700234 sdbusplus::asio::object_server objectServer(systemBus, true);
235 objectServer.add_manager("/xyz/openbmc_project/sensors/");
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700236
237 io.post([&]() { createSensors(io, objectServer, systemBus); });
238
Ed Tanous9b4a20e2022-09-06 08:47:11 -0700239 boost::asio::steady_timer filterTimer(io);
Patrick Williams92f8f512022-07-22 19:26:55 -0500240 std::function<void(sdbusplus::message_t&)> eventHandler =
241 [&filterTimer, &io, &objectServer, &systemBus](sdbusplus::message_t&) {
Ed Tanousbb679322022-05-16 16:10:00 -0700242 // this implicitly cancels the timer
Ed Tanous9b4a20e2022-09-06 08:47:11 -0700243 filterTimer.expires_from_now(std::chrono::seconds(1));
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700244
Ed Tanousbb679322022-05-16 16:10:00 -0700245 filterTimer.async_wait([&](const boost::system::error_code& ec) {
246 if (ec == boost::asio::error::operation_aborted)
247 {
248 return; // we're being canceled
249 }
Andrew Jeffery7279f932021-05-25 13:35:27 +0930250
Ed Tanousbb679322022-05-16 16:10:00 -0700251 if (ec)
252 {
253 std::cerr << "Error: " << ec.message() << "\n";
254 return;
255 }
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700256
Ed Tanousbb679322022-05-16 16:10:00 -0700257 createSensors(io, objectServer, systemBus);
258 });
259 };
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700260
Zev Weiss214d9712022-08-12 12:54:31 -0700261 std::vector<std::unique_ptr<sdbusplus::bus::match_t>> matches =
262 setupPropertiesChangedMatches(
Zev Weiss054aad82022-08-18 01:37:34 -0700263 *systemBus, std::to_array<const char*>({NVMeSensor::sensorType}),
Zev Weiss214d9712022-08-12 12:54:31 -0700264 eventHandler);
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700265
Andrew Jefferyafd55b92021-12-08 10:58:17 +1030266 // Watch for entity-manager to remove configuration interfaces
267 // so the corresponding sensors can be removed.
Patrick Williams92f8f512022-07-22 19:26:55 -0500268 auto ifaceRemovedMatch = std::make_unique<sdbusplus::bus::match_t>(
269 static_cast<sdbusplus::bus_t&>(*systemBus),
Andrew Jefferyafd55b92021-12-08 10:58:17 +1030270 "type='signal',member='InterfacesRemoved',arg0path='" +
271 std::string(inventoryPath) + "/'",
Patrick Williams92f8f512022-07-22 19:26:55 -0500272 [](sdbusplus::message_t& msg) {
Ed Tanousbb679322022-05-16 16:10:00 -0700273 interfaceRemoved(msg, nvmeDeviceMap);
Andrew Jefferyafd55b92021-12-08 10:58:17 +1030274 });
275
Bruce Lee1263c3d2021-06-04 15:16:33 +0800276 setupManufacturingModeMatch(*systemBus);
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700277 io.run();
278}