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