blob: f15f867761682288f714d6dcc4df5ee8c53de598 [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>
Andrew Jefferya9d15082021-05-24 13:55:12 +093019#include <NVMeMCTPContext.hpp>
Ed Tanous8a57ec02020-10-09 12:46:52 -070020#include <NVMeSensor.hpp>
Nikhil Potadeb669b6b2019-03-13 10:52:21 -070021#include <boost/asio/deadline_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
Nikhil Potadeb669b6b2019-03-13 10:52:21 -070026static NVMEMap nvmeDeviceMap;
27
Nikhil Potadeb669b6b2019-03-13 10:52:21 -070028NVMEMap& getNVMEMap()
29{
30 return nvmeDeviceMap;
31}
32
Andrew Jeffery34123562021-12-02 14:38:41 +103033static std::optional<int>
34 extractBusNumber(const std::string& path,
35 const SensorBaseConfigMap& properties)
36{
37 auto findBus = properties.find("Bus");
38 if (findBus == properties.end())
39 {
40 std::cerr << "could not determine bus number for " << path << "\n";
41 return std::nullopt;
42 }
43
44 return std::visit(VariantToIntVisitor(), findBus->second);
45}
46
Andrew Jefferye671f052021-12-02 14:47:20 +103047static std::optional<std::string>
48 extractSensorName(const std::string& path,
49 const SensorBaseConfigMap& properties)
50{
51 auto findSensorName = properties.find("Name");
52 if (findSensorName == properties.end())
53 {
54 std::cerr << "could not determine configuration name for " << path
55 << "\n";
56 return std::nullopt;
57 }
58
59 return std::get<std::string>(findSensorName->second);
60}
61
Andrew Jeffery710562a2021-12-02 14:55:55 +103062static std::filesystem::path deriveRootBusPath(int busNumber)
63{
64 return "/sys/bus/i2c/devices/i2c-" + std::to_string(busNumber) +
65 "/mux_device";
66}
67
Andrew Jeffery66ab8402021-12-02 15:03:51 +103068static std::optional<int> deriveRootBus(std::optional<int> busNumber)
69{
70 if (!busNumber)
71 {
72 return std::nullopt;
73 }
74
75 std::filesystem::path muxPath = deriveRootBusPath(*busNumber);
76
77 if (!std::filesystem::is_symlink(muxPath))
78 {
79 return *busNumber;
80 }
81
82 std::string rootName = std::filesystem::read_symlink(muxPath).filename();
83 size_t dash = rootName.find('-');
84 if (dash == std::string::npos)
85 {
86 std::cerr << "Error finding root bus for " << rootName << "\n";
87 return std::nullopt;
88 }
89
90 return std::stoi(rootName.substr(0, dash));
91}
92
Andrew Jefferyc7a89e52021-12-02 15:10:23 +103093static std::shared_ptr<NVMeContext>
94 provideRootBusContext(boost::asio::io_service& io, NVMEMap& map,
95 int rootBus)
96{
97 auto findRoot = map.find(rootBus);
98 if (findRoot != map.end())
99 {
100 return findRoot->second;
101 }
102
103 std::shared_ptr<NVMeContext> context =
104#if HAVE_NVME_MI_MCTP
105 std::make_shared<NVMeMCTPContext>(io, rootBus);
106#else
107 std::make_shared<NVMeBasicContext>(io, rootBus);
108#endif
109 map[rootBus] = context;
110
111 return context;
112}
113
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030114static void handleSensorConfigurations(
115 boost::asio::io_service& io, sdbusplus::asio::object_server& objectServer,
116 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
117 const ManagedObjectType& sensorConfigurations)
118{
119 // todo: it'd be better to only update the ones we care about
120 for (const auto& [_, nvmeContextPtr] : nvmeDeviceMap)
121 {
122 if (nvmeContextPtr)
123 {
124 nvmeContextPtr->close();
125 }
126 }
127 nvmeDeviceMap.clear();
128
129 // iterate through all found configurations
Andrew Jefferyee164342021-12-02 16:02:19 +1030130 for (const auto& [interfacePath, sensorData] : sensorConfigurations)
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030131 {
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030132 // find base configuration
Ed Tanous74cffa82022-01-25 13:00:28 -0800133 auto sensorBase = sensorData.find(NVMeSensor::configType);
Andrew Jefferyee164342021-12-02 16:02:19 +1030134 if (sensorBase != sensorData.end())
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030135 {
Andrew Jefferyee164342021-12-02 16:02:19 +1030136 const SensorBaseConfigMap& sensorConfig = sensorBase->second;
137 std::optional<int> busNumber =
138 extractBusNumber(interfacePath, sensorConfig);
139 std::optional<std::string> sensorName =
140 extractSensorName(interfacePath, sensorConfig);
141 std::optional<int> rootBus = deriveRootBus(busNumber);
142
143 if (!(busNumber && sensorName && rootBus))
144 {
145 continue;
146 }
147
148 std::vector<thresholds::Threshold> sensorThresholds;
149 if (!parseThresholdsFromConfig(sensorData, sensorThresholds))
150 {
151 std::cerr << "error populating thresholds for " << *sensorName
152 << "\n";
153 }
154
155 std::shared_ptr<NVMeSensor> sensorPtr =
156 std::make_shared<NVMeSensor>(
157 objectServer, io, dbusConnection, *sensorName,
158 std::move(sensorThresholds), interfacePath, *busNumber);
159
Andrew Jeffery57574ad2021-12-02 16:35:52 +1030160 provideRootBusContext(io, nvmeDeviceMap, *rootBus)
161 ->addSensor(sensorPtr);
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030162 }
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030163 }
164 for (const auto& [_, context] : nvmeDeviceMap)
165 {
166 context->pollNVMeDevices();
167 }
168}
169
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700170void createSensors(boost::asio::io_service& io,
171 sdbusplus::asio::object_server& objectServer,
172 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection)
173{
174
175 auto getter = std::make_shared<GetSensorConfiguration>(
Ed Tanous86d83012022-02-18 09:51:47 -0800176 dbusConnection, [&io, &objectServer, &dbusConnection](
177 const ManagedObjectType& sensorConfigurations) {
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030178 handleSensorConfigurations(io, objectServer, dbusConnection,
179 sensorConfigurations);
Ed Tanous86d83012022-02-18 09:51:47 -0800180 });
Ed Tanous74cffa82022-01-25 13:00:28 -0800181 getter->getConfiguration(std::vector<std::string>{NVMeSensor::configType});
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700182}
183
Andrew Jefferyafd55b92021-12-08 10:58:17 +1030184static void interfaceRemoved(sdbusplus::message::message& message,
185 NVMEMap& contexts)
186{
187 if (message.is_method_error())
188 {
189 std::cerr << "interfacesRemoved callback method error\n";
190 return;
191 }
192
193 sdbusplus::message::object_path path;
194 std::vector<std::string> interfaces;
195
196 message.read(path, interfaces);
197
198 for (auto& [_, context] : contexts)
199 {
200 std::optional<std::shared_ptr<NVMeSensor>> sensor =
201 context->getSensorAtPath(path);
202 if (!sensor)
203 {
204 continue;
205 }
206
207 auto interface = std::find(interfaces.begin(), interfaces.end(),
208 (*sensor)->objectType);
209 if (interface == interfaces.end())
210 {
211 continue;
212 }
213
214 context->removeSensor(sensor.value());
215 }
216}
217
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700218int main()
219{
220 boost::asio::io_service io;
221 auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
222 systemBus->request_name("xyz.openbmc_project.NVMeSensor");
223 sdbusplus::asio::object_server objectServer(systemBus);
Andrew Jeffery6f25e7e2021-05-24 12:52:53 +0930224#if HAVE_NVME_MI_MCTP
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700225 nvmeMCTP::init();
Andrew Jeffery6f25e7e2021-05-24 12:52:53 +0930226#endif
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700227
228 io.post([&]() { createSensors(io, objectServer, systemBus); });
229
230 boost::asio::deadline_timer filterTimer(io);
231 std::function<void(sdbusplus::message::message&)> eventHandler =
232 [&filterTimer, &io, &objectServer,
James Feist7d7579f2020-09-02 14:13:08 -0700233 &systemBus](sdbusplus::message::message&) {
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700234 // this implicitly cancels the timer
235 filterTimer.expires_from_now(boost::posix_time::seconds(1));
236
237 filterTimer.async_wait([&](const boost::system::error_code& ec) {
238 if (ec == boost::asio::error::operation_aborted)
239 {
240 return; // we're being canceled
241 }
Andrew Jeffery7279f932021-05-25 13:35:27 +0930242
243 if (ec)
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700244 {
245 std::cerr << "Error: " << ec.message() << "\n";
246 return;
247 }
248
249 createSensors(io, objectServer, systemBus);
250 });
251 };
252
253 sdbusplus::bus::match::match configMatch(
254 static_cast<sdbusplus::bus::bus&>(*systemBus),
255 "type='signal',member='PropertiesChanged',path_namespace='" +
256 std::string(inventoryPath) + "',arg0namespace='" +
Ed Tanous74cffa82022-01-25 13:00:28 -0800257 std::string(NVMeSensor::configType) + "'",
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700258 eventHandler);
259
Andrew Jefferyafd55b92021-12-08 10:58:17 +1030260 // Watch for entity-manager to remove configuration interfaces
261 // so the corresponding sensors can be removed.
262 auto ifaceRemovedMatch = std::make_unique<sdbusplus::bus::match::match>(
263 static_cast<sdbusplus::bus::bus&>(*systemBus),
264 "type='signal',member='InterfacesRemoved',arg0path='" +
265 std::string(inventoryPath) + "/'",
266 [](sdbusplus::message::message& msg) {
267 interfaceRemoved(msg, nvmeDeviceMap);
268 });
269
Bruce Lee1263c3d2021-06-04 15:16:33 +0800270 setupManufacturingModeMatch(*systemBus);
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700271 io.run();
272}