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