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