blob: f64609a25eec9eaec1fbd5f2ffd824f90389c131 [file] [log] [blame]
Matt Spinler711d51d2019-11-06 09:36:51 -06001/**
2 * Copyright © 2019 IBM 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 */
Matt Spinlercad9c2b2019-12-02 15:42:01 -060016#include "config.h"
17
Matt Spinlerc8705e22019-09-11 12:36:07 -050018#include "data_interface.hpp"
19
Matt Spinlercad9c2b2019-12-02 15:42:01 -060020#include <fstream>
Matt Spinlera7d9d962019-11-06 15:01:25 -060021#include <xyz/openbmc_project/State/OperatingSystem/Status/server.hpp>
22
Matt Spinlerc8705e22019-09-11 12:36:07 -050023namespace openpower
24{
25namespace pels
26{
27
28namespace service_name
29{
30constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper";
31} // namespace service_name
32
33namespace object_path
34{
35constexpr auto objectMapper = "/xyz/openbmc_project/object_mapper";
36constexpr auto systemInv = "/xyz/openbmc_project/inventory/system";
Matt Spinlerb3d488f2020-02-21 15:30:46 -060037constexpr auto baseInv = "/xyz/openbmc_project/inventory";
Matt Spinler4aa23a12020-02-03 15:05:09 -060038constexpr auto bmcState = "/xyz/openbmc_project/state/bmc0";
39constexpr auto chassisState = "/xyz/openbmc_project/state/chassis0";
Matt Spinlera7d9d962019-11-06 15:01:25 -060040constexpr auto hostState = "/xyz/openbmc_project/state/host0";
Matt Spinlerb3f51862019-12-09 13:55:10 -060041constexpr auto pldm = "/xyz/openbmc_project/pldm";
Matt Spinler9cf3cfd2020-02-03 14:41:55 -060042constexpr auto enableHostPELs =
43 "/xyz/openbmc_project/logging/send_event_logs_to_host";
Matt Spinlerc8705e22019-09-11 12:36:07 -050044} // namespace object_path
45
46namespace interface
47{
48constexpr auto dbusProperty = "org.freedesktop.DBus.Properties";
49constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper";
50constexpr auto invAsset = "xyz.openbmc_project.Inventory.Decorator.Asset";
Matt Spinlera7d9d962019-11-06 15:01:25 -060051constexpr auto osStatus = "xyz.openbmc_project.State.OperatingSystem.Status";
Matt Spinlerb3f51862019-12-09 13:55:10 -060052constexpr auto pldmRequester = "xyz.openbmc_project.PLDM.Requester";
Matt Spinler9cf3cfd2020-02-03 14:41:55 -060053constexpr auto enable = "xyz.openbmc_project.Object.Enable";
Matt Spinler4aa23a12020-02-03 15:05:09 -060054constexpr auto bmcState = "xyz.openbmc_project.State.BMC";
55constexpr auto chassisState = "xyz.openbmc_project.State.Chassis";
56constexpr auto hostState = "xyz.openbmc_project.State.Host";
Matt Spinlerb3d488f2020-02-21 15:30:46 -060057constexpr auto invMotherboard =
58 "xyz.openbmc_project.Inventory.Item.Board.Motherboard";
59constexpr auto viniRecordVPD = "com.ibm.ipzvpd.VINI";
Matt Spinlerc8705e22019-09-11 12:36:07 -050060} // namespace interface
61
Matt Spinlera7d9d962019-11-06 15:01:25 -060062using namespace sdbusplus::xyz::openbmc_project::State::OperatingSystem::server;
Matt Spinlerb3d488f2020-02-21 15:30:46 -060063using sdbusplus::exception::SdBusError;
Matt Spinlera7d9d962019-11-06 15:01:25 -060064
Matt Spinlerc8705e22019-09-11 12:36:07 -050065DataInterface::DataInterface(sdbusplus::bus::bus& bus) : _bus(bus)
66{
Matt Spinlercad9c2b2019-12-02 15:42:01 -060067 readBMCFWVersion();
68 readServerFWVersion();
Matt Spinler677381b2020-01-23 10:04:29 -060069 readBMCFWVersionID();
Matt Spinlerb3d488f2020-02-21 15:30:46 -060070 readMotherboardCCIN();
Matt Spinler2a28c932020-02-03 14:23:40 -060071
72 // Watch both the Model and SN properties on the system's Asset iface
73 _properties.emplace_back(std::make_unique<InterfaceWatcher<DataInterface>>(
74 bus, object_path::systemInv, interface::invAsset, *this,
75 [this](const auto& properties) {
76 auto model = properties.find("Model");
77 if (model != properties.end())
78 {
79 this->_machineTypeModel = std::get<std::string>(model->second);
80 }
81
82 auto sn = properties.find("SerialNumber");
83 if (sn != properties.end())
84 {
85 this->_machineSerialNumber = std::get<std::string>(sn->second);
86 }
87 }));
88
89 // Watch the OperatingSystemState property
90 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
91 bus, object_path::hostState, interface::osStatus,
92 "OperatingSystemState", *this, [this](const auto& value) {
93 auto status =
94 Status::convertOSStatusFromString(std::get<std::string>(value));
95
96 if ((status == Status::OSStatus::BootComplete) ||
97 (status == Status::OSStatus::Standby))
98 {
Matt Spinler4aa23a12020-02-03 15:05:09 -060099 setHostUp(true);
Matt Spinler2a28c932020-02-03 14:23:40 -0600100 }
101 else
102 {
Matt Spinler4aa23a12020-02-03 15:05:09 -0600103 setHostUp(false);
Matt Spinler2a28c932020-02-03 14:23:40 -0600104 }
105 }));
Matt Spinler9cf3cfd2020-02-03 14:41:55 -0600106
107 // Watch the host PEL enable property
108 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
109 bus, object_path::enableHostPELs, interface::enable, "Enabled", *this,
110 [this](const auto& value) {
111 this->_sendPELsToHost = std::get<bool>(value);
112 }));
Matt Spinler4aa23a12020-02-03 15:05:09 -0600113
114 // Watch the BMCState property
115 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
116 bus, object_path::bmcState, interface::bmcState, "CurrentBMCState",
117 *this, [this](const auto& value) {
118 this->_bmcState = std::get<std::string>(value);
119 }));
120
121 // Watch the chassis current and requested power state properties
122 _properties.emplace_back(std::make_unique<InterfaceWatcher<DataInterface>>(
123 bus, object_path::chassisState, interface::chassisState, *this,
124 [this](const auto& properties) {
125 auto state = properties.find("CurrentPowerState");
126 if (state != properties.end())
127 {
128 this->_chassisState = std::get<std::string>(state->second);
129 }
130
131 auto trans = properties.find("RequestedPowerTransition");
132 if (trans != properties.end())
133 {
134 this->_chassisTransition = std::get<std::string>(trans->second);
135 }
136 }));
137
138 // Watch the CurrentHostState property
139 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
140 bus, object_path::hostState, interface::hostState, "CurrentHostState",
141 *this, [this](const auto& value) {
142 this->_hostState = std::get<std::string>(value);
143 }));
Matt Spinlerc8705e22019-09-11 12:36:07 -0500144}
145
Matt Spinler2a28c932020-02-03 14:23:40 -0600146DBusPropertyMap
147 DataInterface::getAllProperties(const std::string& service,
148 const std::string& objectPath,
149 const std::string& interface) const
Matt Spinlerc8705e22019-09-11 12:36:07 -0500150{
151 DBusPropertyMap properties;
152
153 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
154 interface::dbusProperty, "GetAll");
155 method.append(interface);
156 auto reply = _bus.call(method);
157
158 reply.read(properties);
159
160 return properties;
161}
162
Matt Spinlera7d9d962019-11-06 15:01:25 -0600163void DataInterface::getProperty(const std::string& service,
164 const std::string& objectPath,
165 const std::string& interface,
Matt Spinler2a28c932020-02-03 14:23:40 -0600166 const std::string& property,
167 DBusValue& value) const
Matt Spinlera7d9d962019-11-06 15:01:25 -0600168{
169
170 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
171 interface::dbusProperty, "Get");
172 method.append(interface, property);
173 auto reply = _bus.call(method);
174
175 reply.read(value);
176}
177
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600178DBusPathList DataInterface::getPaths(const DBusInterfaceList& interfaces) const
179{
180
181 auto method = _bus.new_method_call(
182 service_name::objectMapper, object_path::objectMapper,
183 interface::objectMapper, "GetSubTreePaths");
184
185 method.append(std::string{"/"}, 0, interfaces);
186
187 auto reply = _bus.call(method);
188
189 DBusPathList paths;
190 reply.read(paths);
191
192 return paths;
193}
194
Matt Spinlerc8705e22019-09-11 12:36:07 -0500195DBusService DataInterface::getService(const std::string& objectPath,
Matt Spinlerb3f51862019-12-09 13:55:10 -0600196 const std::string& interface) const
Matt Spinlerc8705e22019-09-11 12:36:07 -0500197{
198 auto method = _bus.new_method_call(service_name::objectMapper,
199 object_path::objectMapper,
200 interface::objectMapper, "GetObject");
201
202 method.append(objectPath, std::vector<std::string>({interface}));
203
204 auto reply = _bus.call(method);
205
206 std::map<DBusService, DBusInterfaceList> response;
207 reply.read(response);
208
209 if (!response.empty())
210 {
211 return response.begin()->first;
212 }
213
214 return std::string{};
215}
Matt Spinlera7d9d962019-11-06 15:01:25 -0600216
Matt Spinlerb3f51862019-12-09 13:55:10 -0600217uint8_t DataInterface::getPLDMInstanceID(uint8_t eid) const
218{
219 return 0;
220// Don't use until PLDM switches to async D-Bus.
221#if 0
222 auto service = getService(object_path::pldm, interface::pldmRequester);
223
224 auto method =
225 _bus.new_method_call(service.c_str(), object_path::pldm,
226 interface::pldmRequester, "GetInstanceId");
227 method.append(eid);
228 auto reply = _bus.call(method);
229
230 uint8_t instanceID = 0;
231 reply.read(instanceID);
232
233 return instanceID;
234#endif
235}
236
Matt Spinler677381b2020-01-23 10:04:29 -0600237/**
238 * @brief Return a value found in the /etc/os-release file
239 *
240 * @param[in] key - The key name, like "VERSION"
241 *
242 * @return std::optional<std::string> - The value
243 */
244std::optional<std::string> getOSReleaseValue(const std::string& key)
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600245{
246 std::ifstream versionFile{BMC_VERSION_FILE};
247 std::string line;
Matt Spinler677381b2020-01-23 10:04:29 -0600248 std::string keyPattern{key + '='};
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600249
250 while (std::getline(versionFile, line))
251 {
Matt Spinler677381b2020-01-23 10:04:29 -0600252 if (line.find(keyPattern) != std::string::npos)
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600253 {
254 auto pos = line.find_first_of('"') + 1;
Matt Spinler677381b2020-01-23 10:04:29 -0600255 auto value = line.substr(pos, line.find_last_of('"') - pos);
256 return value;
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600257 }
258 }
Matt Spinler677381b2020-01-23 10:04:29 -0600259
260 return std::nullopt;
261}
262
263void DataInterface::readBMCFWVersion()
264{
265 _bmcFWVersion = getOSReleaseValue("VERSION").value_or("");
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600266}
267
268void DataInterface::readServerFWVersion()
269{
270 // Not available yet
271}
272
Matt Spinler677381b2020-01-23 10:04:29 -0600273void DataInterface::readBMCFWVersionID()
274{
275 _bmcFWVersionID = getOSReleaseValue("VERSION_ID").value_or("");
276}
277
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600278void DataInterface::readMotherboardCCIN()
279{
280 try
281 {
282 // First, try to find the motherboard
283 auto motherboards = getPaths({interface::invMotherboard});
284 if (motherboards.empty())
285 {
286 throw std::runtime_error("No motherboards yet");
287 }
288
289 // Found it, so now get the CCIN
290 _properties.emplace_back(
291 std::make_unique<PropertyWatcher<DataInterface>>(
292 _bus, motherboards.front(), interface::viniRecordVPD, "CC",
293 *this,
294 [this](const auto& ccin) { this->setMotherboardCCIN(ccin); }));
295 }
296 catch (const std::exception& e)
297 {
298 // No motherboard in the inventory yet - watch for it
299 _inventoryIfacesAddedMatch = std::make_unique<sdbusplus::bus::match_t>(
300 _bus, match_rules::interfacesAdded(object_path::baseInv),
301 std::bind(std::mem_fn(&DataInterface::motherboardIfaceAdded), this,
302 std::placeholders::_1));
303 }
304}
305
306void DataInterface::motherboardIfaceAdded(sdbusplus::message::message& msg)
307{
308 sdbusplus::message::object_path path;
309 DBusInterfaceMap interfaces;
310
311 msg.read(path, interfaces);
312
313 // This is watching the whole inventory, so check if it's what we want
314 if (interfaces.find(interface::invMotherboard) == interfaces.end())
315 {
316 return;
317 }
318
319 // Done watching for any new inventory interfaces
320 _inventoryIfacesAddedMatch.reset();
321
322 // Watch the motherboard CCIN, using the service from this signal
323 // for the initial property read.
324 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
325 _bus, path, interface::viniRecordVPD, "CC", msg.get_sender(), *this,
326 [this](const auto& ccin) { this->setMotherboardCCIN(ccin); }));
327}
328
Matt Spinlerc8705e22019-09-11 12:36:07 -0500329} // namespace pels
330} // namespace openpower