blob: 96f42c901d7a41957d02532720efe06144a6b072 [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 Jefferyf690f0c2021-12-02 11:42:58 +103052static void handleSensorConfigurations(
53 boost::asio::io_service& io, sdbusplus::asio::object_server& objectServer,
54 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
55 const ManagedObjectType& sensorConfigurations)
56{
57 // todo: it'd be better to only update the ones we care about
58 for (const auto& [_, nvmeContextPtr] : nvmeDeviceMap)
59 {
60 if (nvmeContextPtr)
61 {
62 nvmeContextPtr->close();
63 }
64 }
65 nvmeDeviceMap.clear();
66
67 // iterate through all found configurations
68 for (const std::pair<sdbusplus::message::object_path, SensorData>& sensor :
69 sensorConfigurations)
70 {
71 const SensorData& sensorData = sensor.second;
72 const std::string& interfacePath = sensor.first.str;
73 const std::pair<std::string, boost::container::flat_map<
74 std::string, BasicVariantType>>*
75 baseConfiguration = nullptr;
76
77 // find base configuration
78 auto sensorBase = sensor.second.find(sensorType);
79 if (sensorBase != sensor.second.end())
80 {
81 baseConfiguration = &(*sensorBase);
82 }
83
84 if (baseConfiguration == nullptr)
85 {
86 continue;
87 }
Andrew Jeffery34123562021-12-02 14:38:41 +103088
89 std::optional<int> busNumber =
90 extractBusNumber(sensor.first, baseConfiguration->second);
91 if (!busNumber)
Andrew Jefferyf690f0c2021-12-02 11:42:58 +103092 {
93 continue;
94 }
95
Andrew Jefferyf690f0c2021-12-02 11:42:58 +103096 auto findSensorName = baseConfiguration->second.find("Name");
97 if (findSensorName == baseConfiguration->second.end())
98 {
99 std::cerr << "could not determine configuration name for "
100 << interfacePath << "\n";
101 continue;
102 }
103 std::string sensorName = std::get<std::string>(findSensorName->second);
104
105 std::vector<thresholds::Threshold> sensorThresholds;
106
107 if (!parseThresholdsFromConfig(sensorData, sensorThresholds))
108 {
109 std::cerr << "error populating thresholds for " << sensorName
110 << "\n";
111 }
112
Andrew Jeffery34123562021-12-02 14:38:41 +1030113 int rootBus = *busNumber;
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030114
115 std::string muxPath = "/sys/bus/i2c/devices/i2c-" +
Andrew Jeffery34123562021-12-02 14:38:41 +1030116 std::to_string(*busNumber) + "/mux_device";
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030117
118 if (std::filesystem::is_symlink(muxPath))
119 {
120 std::string rootName =
121 std::filesystem::read_symlink(muxPath).filename();
122 size_t dash = rootName.find('-');
123 if (dash == std::string::npos)
124 {
125 std::cerr << "Error finding root bus for " << rootName << "\n";
126 continue;
127 }
128 rootBus = std::stoi(rootName.substr(0, dash));
129 }
130
131 std::shared_ptr<NVMeContext> context;
132 auto findRoot = nvmeDeviceMap.find(rootBus);
133 if (findRoot != nvmeDeviceMap.end())
134 {
135 context = findRoot->second;
136 }
137 else
138 {
139#if HAVE_NVME_MI_MCTP
140 context = std::make_shared<NVMeMCTPContext>(io, rootBus);
141#else
142 context = std::make_shared<NVMeBasicContext>(io, rootBus);
143#endif
144 nvmeDeviceMap[rootBus] = context;
145 }
146
147 std::shared_ptr<NVMeSensor> sensorPtr = std::make_shared<NVMeSensor>(
148 objectServer, io, dbusConnection, sensorName,
Andrew Jeffery34123562021-12-02 14:38:41 +1030149 std::move(sensorThresholds), interfacePath, *busNumber);
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030150
151 context->addSensor(sensorPtr);
152 }
153 for (const auto& [_, context] : nvmeDeviceMap)
154 {
155 context->pollNVMeDevices();
156 }
157}
158
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700159void createSensors(boost::asio::io_service& io,
160 sdbusplus::asio::object_server& objectServer,
161 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection)
162{
163
164 auto getter = std::make_shared<GetSensorConfiguration>(
165 dbusConnection,
166 std::move([&io, &objectServer, &dbusConnection](
167 const ManagedObjectType& sensorConfigurations) {
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030168 handleSensorConfigurations(io, objectServer, dbusConnection,
169 sensorConfigurations);
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700170 }));
171 getter->getConfiguration(std::vector<std::string>{sensorType});
172}
173
174int main()
175{
176 boost::asio::io_service io;
177 auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
178 systemBus->request_name("xyz.openbmc_project.NVMeSensor");
179 sdbusplus::asio::object_server objectServer(systemBus);
Andrew Jeffery6f25e7e2021-05-24 12:52:53 +0930180#if HAVE_NVME_MI_MCTP
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700181 nvmeMCTP::init();
Andrew Jeffery6f25e7e2021-05-24 12:52:53 +0930182#endif
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700183
184 io.post([&]() { createSensors(io, objectServer, systemBus); });
185
186 boost::asio::deadline_timer filterTimer(io);
187 std::function<void(sdbusplus::message::message&)> eventHandler =
188 [&filterTimer, &io, &objectServer,
James Feist7d7579f2020-09-02 14:13:08 -0700189 &systemBus](sdbusplus::message::message&) {
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700190 // this implicitly cancels the timer
191 filterTimer.expires_from_now(boost::posix_time::seconds(1));
192
193 filterTimer.async_wait([&](const boost::system::error_code& ec) {
194 if (ec == boost::asio::error::operation_aborted)
195 {
196 return; // we're being canceled
197 }
Andrew Jeffery7279f932021-05-25 13:35:27 +0930198
199 if (ec)
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700200 {
201 std::cerr << "Error: " << ec.message() << "\n";
202 return;
203 }
204
205 createSensors(io, objectServer, systemBus);
206 });
207 };
208
209 sdbusplus::bus::match::match configMatch(
210 static_cast<sdbusplus::bus::bus&>(*systemBus),
211 "type='signal',member='PropertiesChanged',path_namespace='" +
212 std::string(inventoryPath) + "',arg0namespace='" +
213 std::string(sensorType) + "'",
214 eventHandler);
215
Bruce Lee1263c3d2021-06-04 15:16:33 +0800216 setupManufacturingModeMatch(*systemBus);
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700217 io.run();
218}