blob: cae7eb35627065d8ee36d3651f157a7d24ff1b51 [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
26static constexpr const char* sensorType =
27 "xyz.openbmc_project.Configuration.NVME1000";
28
29static NVMEMap nvmeDeviceMap;
30
Ed Tanous8a57ec02020-10-09 12:46:52 -070031static constexpr bool debug = false;
Nikhil Potadeb669b6b2019-03-13 10:52:21 -070032
33NVMEMap& getNVMEMap()
34{
35 return nvmeDeviceMap;
36}
37
Andrew Jeffery34123562021-12-02 14:38:41 +103038static std::optional<int>
39 extractBusNumber(const std::string& path,
40 const SensorBaseConfigMap& properties)
41{
42 auto findBus = properties.find("Bus");
43 if (findBus == properties.end())
44 {
45 std::cerr << "could not determine bus number for " << path << "\n";
46 return std::nullopt;
47 }
48
49 return std::visit(VariantToIntVisitor(), findBus->second);
50}
51
Andrew Jefferye671f052021-12-02 14:47:20 +103052static std::optional<std::string>
53 extractSensorName(const std::string& path,
54 const SensorBaseConfigMap& properties)
55{
56 auto findSensorName = properties.find("Name");
57 if (findSensorName == properties.end())
58 {
59 std::cerr << "could not determine configuration name for " << path
60 << "\n";
61 return std::nullopt;
62 }
63
64 return std::get<std::string>(findSensorName->second);
65}
66
Andrew Jeffery710562a2021-12-02 14:55:55 +103067static std::filesystem::path deriveRootBusPath(int busNumber)
68{
69 return "/sys/bus/i2c/devices/i2c-" + std::to_string(busNumber) +
70 "/mux_device";
71}
72
Andrew Jeffery66ab8402021-12-02 15:03:51 +103073static std::optional<int> deriveRootBus(std::optional<int> busNumber)
74{
75 if (!busNumber)
76 {
77 return std::nullopt;
78 }
79
80 std::filesystem::path muxPath = deriveRootBusPath(*busNumber);
81
82 if (!std::filesystem::is_symlink(muxPath))
83 {
84 return *busNumber;
85 }
86
87 std::string rootName = std::filesystem::read_symlink(muxPath).filename();
88 size_t dash = rootName.find('-');
89 if (dash == std::string::npos)
90 {
91 std::cerr << "Error finding root bus for " << rootName << "\n";
92 return std::nullopt;
93 }
94
95 return std::stoi(rootName.substr(0, dash));
96}
97
Andrew Jefferyc7a89e52021-12-02 15:10:23 +103098static std::shared_ptr<NVMeContext>
99 provideRootBusContext(boost::asio::io_service& io, NVMEMap& map,
100 int rootBus)
101{
102 auto findRoot = map.find(rootBus);
103 if (findRoot != map.end())
104 {
105 return findRoot->second;
106 }
107
108 std::shared_ptr<NVMeContext> context =
109#if HAVE_NVME_MI_MCTP
110 std::make_shared<NVMeMCTPContext>(io, rootBus);
111#else
112 std::make_shared<NVMeBasicContext>(io, rootBus);
113#endif
114 map[rootBus] = context;
115
116 return context;
117}
118
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030119static void handleSensorConfigurations(
120 boost::asio::io_service& io, sdbusplus::asio::object_server& objectServer,
121 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
122 const ManagedObjectType& sensorConfigurations)
123{
124 // todo: it'd be better to only update the ones we care about
125 for (const auto& [_, nvmeContextPtr] : nvmeDeviceMap)
126 {
127 if (nvmeContextPtr)
128 {
129 nvmeContextPtr->close();
130 }
131 }
132 nvmeDeviceMap.clear();
133
134 // iterate through all found configurations
135 for (const std::pair<sdbusplus::message::object_path, SensorData>& sensor :
136 sensorConfigurations)
137 {
138 const SensorData& sensorData = sensor.second;
139 const std::string& interfacePath = sensor.first.str;
140 const std::pair<std::string, boost::container::flat_map<
141 std::string, BasicVariantType>>*
142 baseConfiguration = nullptr;
143
144 // find base configuration
145 auto sensorBase = sensor.second.find(sensorType);
146 if (sensorBase != sensor.second.end())
147 {
148 baseConfiguration = &(*sensorBase);
149 }
150
151 if (baseConfiguration == nullptr)
152 {
153 continue;
154 }
Andrew Jeffery34123562021-12-02 14:38:41 +1030155
156 std::optional<int> busNumber =
157 extractBusNumber(sensor.first, baseConfiguration->second);
158 if (!busNumber)
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030159 {
160 continue;
161 }
162
Andrew Jefferye671f052021-12-02 14:47:20 +1030163 std::optional<std::string> sensorName =
164 extractSensorName(sensor.first, baseConfiguration->second);
165 if (!sensorName)
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030166 {
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030167 continue;
168 }
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030169
170 std::vector<thresholds::Threshold> sensorThresholds;
171
172 if (!parseThresholdsFromConfig(sensorData, sensorThresholds))
173 {
Andrew Jefferye671f052021-12-02 14:47:20 +1030174 std::cerr << "error populating thresholds for " << *sensorName
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030175 << "\n";
176 }
177
Andrew Jeffery66ab8402021-12-02 15:03:51 +1030178 std::optional<int> rootBus = deriveRootBus(busNumber);
179 if (!rootBus)
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030180 {
Andrew Jeffery66ab8402021-12-02 15:03:51 +1030181 continue;
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030182 }
183
Andrew Jefferyc7a89e52021-12-02 15:10:23 +1030184 std::shared_ptr<NVMeContext> context =
185 provideRootBusContext(io, nvmeDeviceMap, *rootBus);
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030186
187 std::shared_ptr<NVMeSensor> sensorPtr = std::make_shared<NVMeSensor>(
Andrew Jefferye671f052021-12-02 14:47:20 +1030188 objectServer, io, dbusConnection, *sensorName,
Andrew Jeffery34123562021-12-02 14:38:41 +1030189 std::move(sensorThresholds), interfacePath, *busNumber);
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030190
191 context->addSensor(sensorPtr);
192 }
193 for (const auto& [_, context] : nvmeDeviceMap)
194 {
195 context->pollNVMeDevices();
196 }
197}
198
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700199void createSensors(boost::asio::io_service& io,
200 sdbusplus::asio::object_server& objectServer,
201 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection)
202{
203
204 auto getter = std::make_shared<GetSensorConfiguration>(
205 dbusConnection,
206 std::move([&io, &objectServer, &dbusConnection](
207 const ManagedObjectType& sensorConfigurations) {
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030208 handleSensorConfigurations(io, objectServer, dbusConnection,
209 sensorConfigurations);
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700210 }));
211 getter->getConfiguration(std::vector<std::string>{sensorType});
212}
213
214int main()
215{
216 boost::asio::io_service io;
217 auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
218 systemBus->request_name("xyz.openbmc_project.NVMeSensor");
219 sdbusplus::asio::object_server objectServer(systemBus);
Andrew Jeffery6f25e7e2021-05-24 12:52:53 +0930220#if HAVE_NVME_MI_MCTP
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700221 nvmeMCTP::init();
Andrew Jeffery6f25e7e2021-05-24 12:52:53 +0930222#endif
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700223
224 io.post([&]() { createSensors(io, objectServer, systemBus); });
225
226 boost::asio::deadline_timer filterTimer(io);
227 std::function<void(sdbusplus::message::message&)> eventHandler =
228 [&filterTimer, &io, &objectServer,
James Feist7d7579f2020-09-02 14:13:08 -0700229 &systemBus](sdbusplus::message::message&) {
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700230 // this implicitly cancels the timer
231 filterTimer.expires_from_now(boost::posix_time::seconds(1));
232
233 filterTimer.async_wait([&](const boost::system::error_code& ec) {
234 if (ec == boost::asio::error::operation_aborted)
235 {
236 return; // we're being canceled
237 }
Andrew Jeffery7279f932021-05-25 13:35:27 +0930238
239 if (ec)
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700240 {
241 std::cerr << "Error: " << ec.message() << "\n";
242 return;
243 }
244
245 createSensors(io, objectServer, systemBus);
246 });
247 };
248
249 sdbusplus::bus::match::match configMatch(
250 static_cast<sdbusplus::bus::bus&>(*systemBus),
251 "type='signal',member='PropertiesChanged',path_namespace='" +
252 std::string(inventoryPath) + "',arg0namespace='" +
253 std::string(sensorType) + "'",
254 eventHandler);
255
Bruce Lee1263c3d2021-06-04 15:16:33 +0800256 setupManufacturingModeMatch(*systemBus);
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700257 io.run();
258}