blob: b017bcacd208a771cf485e3b113bb06eda3ebe4e [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
Nikhil Potadeb669b6b2019-03-13 10:52:21 -070023#include <regex>
24
25static constexpr const char* sensorType =
26 "xyz.openbmc_project.Configuration.NVME1000";
27
28static NVMEMap nvmeDeviceMap;
29
Ed Tanous8a57ec02020-10-09 12:46:52 -070030static constexpr bool debug = false;
Nikhil Potadeb669b6b2019-03-13 10:52:21 -070031
32NVMEMap& getNVMEMap()
33{
34 return nvmeDeviceMap;
35}
36
Andrew Jefferyf690f0c2021-12-02 11:42:58 +103037static void handleSensorConfigurations(
38 boost::asio::io_service& io, sdbusplus::asio::object_server& objectServer,
39 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
40 const ManagedObjectType& sensorConfigurations)
41{
42 // todo: it'd be better to only update the ones we care about
43 for (const auto& [_, nvmeContextPtr] : nvmeDeviceMap)
44 {
45 if (nvmeContextPtr)
46 {
47 nvmeContextPtr->close();
48 }
49 }
50 nvmeDeviceMap.clear();
51
52 // iterate through all found configurations
53 for (const std::pair<sdbusplus::message::object_path, SensorData>& sensor :
54 sensorConfigurations)
55 {
56 const SensorData& sensorData = sensor.second;
57 const std::string& interfacePath = sensor.first.str;
58 const std::pair<std::string, boost::container::flat_map<
59 std::string, BasicVariantType>>*
60 baseConfiguration = nullptr;
61
62 // find base configuration
63 auto sensorBase = sensor.second.find(sensorType);
64 if (sensorBase != sensor.second.end())
65 {
66 baseConfiguration = &(*sensorBase);
67 }
68
69 if (baseConfiguration == nullptr)
70 {
71 continue;
72 }
73 auto findBus = baseConfiguration->second.find("Bus");
74 if (findBus == baseConfiguration->second.end())
75 {
76 continue;
77 }
78
79 int busNumber = std::visit(VariantToIntVisitor(), findBus->second);
80
81 auto findSensorName = baseConfiguration->second.find("Name");
82 if (findSensorName == baseConfiguration->second.end())
83 {
84 std::cerr << "could not determine configuration name for "
85 << interfacePath << "\n";
86 continue;
87 }
88 std::string sensorName = std::get<std::string>(findSensorName->second);
89
90 std::vector<thresholds::Threshold> sensorThresholds;
91
92 if (!parseThresholdsFromConfig(sensorData, sensorThresholds))
93 {
94 std::cerr << "error populating thresholds for " << sensorName
95 << "\n";
96 }
97
98 int rootBus = busNumber;
99
100 std::string muxPath = "/sys/bus/i2c/devices/i2c-" +
101 std::to_string(busNumber) + "/mux_device";
102
103 if (std::filesystem::is_symlink(muxPath))
104 {
105 std::string rootName =
106 std::filesystem::read_symlink(muxPath).filename();
107 size_t dash = rootName.find('-');
108 if (dash == std::string::npos)
109 {
110 std::cerr << "Error finding root bus for " << rootName << "\n";
111 continue;
112 }
113 rootBus = std::stoi(rootName.substr(0, dash));
114 }
115
116 std::shared_ptr<NVMeContext> context;
117 auto findRoot = nvmeDeviceMap.find(rootBus);
118 if (findRoot != nvmeDeviceMap.end())
119 {
120 context = findRoot->second;
121 }
122 else
123 {
124#if HAVE_NVME_MI_MCTP
125 context = std::make_shared<NVMeMCTPContext>(io, rootBus);
126#else
127 context = std::make_shared<NVMeBasicContext>(io, rootBus);
128#endif
129 nvmeDeviceMap[rootBus] = context;
130 }
131
132 std::shared_ptr<NVMeSensor> sensorPtr = std::make_shared<NVMeSensor>(
133 objectServer, io, dbusConnection, sensorName,
134 std::move(sensorThresholds), interfacePath, busNumber);
135
136 context->addSensor(sensorPtr);
137 }
138 for (const auto& [_, context] : nvmeDeviceMap)
139 {
140 context->pollNVMeDevices();
141 }
142}
143
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700144void createSensors(boost::asio::io_service& io,
145 sdbusplus::asio::object_server& objectServer,
146 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection)
147{
148
149 auto getter = std::make_shared<GetSensorConfiguration>(
150 dbusConnection,
151 std::move([&io, &objectServer, &dbusConnection](
152 const ManagedObjectType& sensorConfigurations) {
Andrew Jefferyf690f0c2021-12-02 11:42:58 +1030153 handleSensorConfigurations(io, objectServer, dbusConnection,
154 sensorConfigurations);
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700155 }));
156 getter->getConfiguration(std::vector<std::string>{sensorType});
157}
158
159int main()
160{
161 boost::asio::io_service io;
162 auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
163 systemBus->request_name("xyz.openbmc_project.NVMeSensor");
164 sdbusplus::asio::object_server objectServer(systemBus);
Andrew Jeffery6f25e7e2021-05-24 12:52:53 +0930165#if HAVE_NVME_MI_MCTP
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700166 nvmeMCTP::init();
Andrew Jeffery6f25e7e2021-05-24 12:52:53 +0930167#endif
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700168
169 io.post([&]() { createSensors(io, objectServer, systemBus); });
170
171 boost::asio::deadline_timer filterTimer(io);
172 std::function<void(sdbusplus::message::message&)> eventHandler =
173 [&filterTimer, &io, &objectServer,
James Feist7d7579f2020-09-02 14:13:08 -0700174 &systemBus](sdbusplus::message::message&) {
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700175 // this implicitly cancels the timer
176 filterTimer.expires_from_now(boost::posix_time::seconds(1));
177
178 filterTimer.async_wait([&](const boost::system::error_code& ec) {
179 if (ec == boost::asio::error::operation_aborted)
180 {
181 return; // we're being canceled
182 }
Andrew Jeffery7279f932021-05-25 13:35:27 +0930183
184 if (ec)
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700185 {
186 std::cerr << "Error: " << ec.message() << "\n";
187 return;
188 }
189
190 createSensors(io, objectServer, systemBus);
191 });
192 };
193
194 sdbusplus::bus::match::match configMatch(
195 static_cast<sdbusplus::bus::bus&>(*systemBus),
196 "type='signal',member='PropertiesChanged',path_namespace='" +
197 std::string(inventoryPath) + "',arg0namespace='" +
198 std::string(sensorType) + "'",
199 eventHandler);
200
Bruce Lee1263c3d2021-06-04 15:16:33 +0800201 setupManufacturingModeMatch(*systemBus);
Nikhil Potadeb669b6b2019-03-13 10:52:21 -0700202 io.run();
203}