blob: 71993d20766d949682fe1c0ebcecbc79da1ab91e [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>
Nikhil Potadeb669b6b2019-03-13 10:52:21 -070020#include <boost/asio/deadline_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
Ed Tanous74cffa82022-01-25 13:00:28 -0800128 auto sensorBase = sensorData.find(NVMeSensor::configType);
Zev Weissefae44c2022-08-16 15:39:20 -0700129 if (sensorBase == sensorData.end())
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030130 {
Zev Weissefae44c2022-08-16 15:39:20 -0700131 continue;
132 }
Andrew Jefferyee164342021-12-02 16:02:19 +1030133
Zev Weissefae44c2022-08-16 15:39:20 -0700134 const SensorBaseConfigMap& sensorConfig = sensorBase->second;
135 std::optional<int> busNumber =
136 extractBusNumber(interfacePath, sensorConfig);
137 std::optional<std::string> sensorName =
138 extractSensorName(interfacePath, sensorConfig);
139 std::optional<int> rootBus = deriveRootBus(busNumber);
Andrew Jefferyee164342021-12-02 16:02:19 +1030140
Zev Weissefae44c2022-08-16 15:39:20 -0700141 if (!(busNumber && sensorName && rootBus))
142 {
143 continue;
144 }
Andrew Jefferyee164342021-12-02 16:02:19 +1030145
Zev Weissefae44c2022-08-16 15:39:20 -0700146 std::vector<thresholds::Threshold> sensorThresholds;
147 if (!parseThresholdsFromConfig(sensorData, sensorThresholds))
148 {
149 std::cerr << "error populating thresholds for " << *sensorName
150 << "\n";
151 }
Andrew Jefferyee164342021-12-02 16:02:19 +1030152
Zev Weissefae44c2022-08-16 15:39:20 -0700153 try
154 {
155 // May throw for an invalid rootBus
156 std::shared_ptr<NVMeContext> context =
157 provideRootBusContext(io, nvmeDeviceMap, *rootBus);
Andrew Jeffery25e20bd2022-03-15 22:26:04 +1030158
Zev Weissefae44c2022-08-16 15:39:20 -0700159 // Construct the sensor after grabbing the context so we don't
160 // glitch D-Bus May throw for an invalid busNumber
161 std::shared_ptr<NVMeSensor> sensorPtr =
162 std::make_shared<NVMeSensor>(
163 objectServer, io, dbusConnection, *sensorName,
164 std::move(sensorThresholds), interfacePath, *busNumber);
165
166 context->addSensor(sensorPtr);
167 }
168 catch (const std::invalid_argument& ex)
169 {
170 std::cerr << "Failed to add sensor for "
171 << std::string(interfacePath) << ": " << ex.what()
172 << "\n";
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030173 }
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030174 }
175 for (const auto& [_, context] : nvmeDeviceMap)
176 {
177 context->pollNVMeDevices();
178 }
179}
180
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700181void createSensors(boost::asio::io_service& io,
182 sdbusplus::asio::object_server& objectServer,
183 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection)
184{
185
186 auto getter = std::make_shared<GetSensorConfiguration>(
Ed Tanous86d83012022-02-18 09:51:47 -0800187 dbusConnection, [&io, &objectServer, &dbusConnection](
188 const ManagedObjectType& sensorConfigurations) {
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030189 handleSensorConfigurations(io, objectServer, dbusConnection,
190 sensorConfigurations);
Ed Tanous86d83012022-02-18 09:51:47 -0800191 });
Ed Tanous74cffa82022-01-25 13:00:28 -0800192 getter->getConfiguration(std::vector<std::string>{NVMeSensor::configType});
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700193}
194
Patrick Williams92f8f512022-07-22 19:26:55 -0500195static void interfaceRemoved(sdbusplus::message_t& message, NVMEMap& contexts)
Andrew Jefferyafd55b92021-12-08 10:58:17 +1030196{
197 if (message.is_method_error())
198 {
199 std::cerr << "interfacesRemoved callback method error\n";
200 return;
201 }
202
203 sdbusplus::message::object_path path;
204 std::vector<std::string> interfaces;
205
206 message.read(path, interfaces);
207
208 for (auto& [_, context] : contexts)
209 {
210 std::optional<std::shared_ptr<NVMeSensor>> sensor =
211 context->getSensorAtPath(path);
212 if (!sensor)
213 {
214 continue;
215 }
216
217 auto interface = std::find(interfaces.begin(), interfaces.end(),
218 (*sensor)->objectType);
219 if (interface == interfaces.end())
220 {
221 continue;
222 }
223
224 context->removeSensor(sensor.value());
225 }
226}
227
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700228int main()
229{
230 boost::asio::io_service io;
231 auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
232 systemBus->request_name("xyz.openbmc_project.NVMeSensor");
233 sdbusplus::asio::object_server objectServer(systemBus);
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700234
235 io.post([&]() { createSensors(io, objectServer, systemBus); });
236
237 boost::asio::deadline_timer filterTimer(io);
Patrick Williams92f8f512022-07-22 19:26:55 -0500238 std::function<void(sdbusplus::message_t&)> eventHandler =
239 [&filterTimer, &io, &objectServer, &systemBus](sdbusplus::message_t&) {
Ed Tanousbb679322022-05-16 16:10:00 -0700240 // this implicitly cancels the timer
241 filterTimer.expires_from_now(boost::posix_time::seconds(1));
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700242
Ed Tanousbb679322022-05-16 16:10:00 -0700243 filterTimer.async_wait([&](const boost::system::error_code& ec) {
244 if (ec == boost::asio::error::operation_aborted)
245 {
246 return; // we're being canceled
247 }
Andrew Jeffery7279f932021-05-25 13:35:27 +0930248
Ed Tanousbb679322022-05-16 16:10:00 -0700249 if (ec)
250 {
251 std::cerr << "Error: " << ec.message() << "\n";
252 return;
253 }
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700254
Ed Tanousbb679322022-05-16 16:10:00 -0700255 createSensors(io, objectServer, systemBus);
256 });
257 };
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700258
Zev Weiss214d9712022-08-12 12:54:31 -0700259 std::vector<std::unique_ptr<sdbusplus::bus::match_t>> matches =
260 setupPropertiesChangedMatches(
261 *systemBus, std::to_array<const char*>({NVMeSensor::configType}),
262 eventHandler);
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700263
Andrew Jefferyafd55b92021-12-08 10:58:17 +1030264 // Watch for entity-manager to remove configuration interfaces
265 // so the corresponding sensors can be removed.
Patrick Williams92f8f512022-07-22 19:26:55 -0500266 auto ifaceRemovedMatch = std::make_unique<sdbusplus::bus::match_t>(
267 static_cast<sdbusplus::bus_t&>(*systemBus),
Andrew Jefferyafd55b92021-12-08 10:58:17 +1030268 "type='signal',member='InterfacesRemoved',arg0path='" +
269 std::string(inventoryPath) + "/'",
Patrick Williams92f8f512022-07-22 19:26:55 -0500270 [](sdbusplus::message_t& msg) {
Ed Tanousbb679322022-05-16 16:10:00 -0700271 interfaceRemoved(msg, nvmeDeviceMap);
Andrew Jefferyafd55b92021-12-08 10:58:17 +1030272 });
273
Bruce Lee1263c3d2021-06-04 15:16:33 +0800274 setupManufacturingModeMatch(*systemBus);
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700275 io.run();
276}