blob: 9db6df8266d721f70fe8215adbcdf2ea9390589e [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 Spinlerf61f2922020-06-23 11:32:49 -050020#include "util.hpp"
21
Matt Spinlercad9c2b2019-12-02 15:42:01 -060022#include <fstream>
Matt Spinlera7d9d962019-11-06 15:01:25 -060023#include <xyz/openbmc_project/State/OperatingSystem/Status/server.hpp>
24
Matt Spinlerc8705e22019-09-11 12:36:07 -050025namespace openpower
26{
27namespace pels
28{
29
30namespace service_name
31{
32constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper";
33} // namespace service_name
34
35namespace object_path
36{
37constexpr auto objectMapper = "/xyz/openbmc_project/object_mapper";
38constexpr auto systemInv = "/xyz/openbmc_project/inventory/system";
Matt Spinler6ea4d5f2020-05-20 13:31:07 -050039constexpr auto chassisInv = "/xyz/openbmc_project/inventory/system/chassis";
Matt Spinlerb3d488f2020-02-21 15:30:46 -060040constexpr auto baseInv = "/xyz/openbmc_project/inventory";
Matt Spinler4aa23a12020-02-03 15:05:09 -060041constexpr auto bmcState = "/xyz/openbmc_project/state/bmc0";
42constexpr auto chassisState = "/xyz/openbmc_project/state/chassis0";
Matt Spinlera7d9d962019-11-06 15:01:25 -060043constexpr auto hostState = "/xyz/openbmc_project/state/host0";
Matt Spinlerb3f51862019-12-09 13:55:10 -060044constexpr auto pldm = "/xyz/openbmc_project/pldm";
Matt Spinler9cf3cfd2020-02-03 14:41:55 -060045constexpr auto enableHostPELs =
46 "/xyz/openbmc_project/logging/send_event_logs_to_host";
Matt Spinlerc8705e22019-09-11 12:36:07 -050047} // namespace object_path
48
49namespace interface
50{
51constexpr auto dbusProperty = "org.freedesktop.DBus.Properties";
52constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper";
53constexpr auto invAsset = "xyz.openbmc_project.Inventory.Decorator.Asset";
Matt Spinlera7d9d962019-11-06 15:01:25 -060054constexpr auto osStatus = "xyz.openbmc_project.State.OperatingSystem.Status";
Matt Spinlerb3f51862019-12-09 13:55:10 -060055constexpr auto pldmRequester = "xyz.openbmc_project.PLDM.Requester";
Matt Spinler9cf3cfd2020-02-03 14:41:55 -060056constexpr auto enable = "xyz.openbmc_project.Object.Enable";
Matt Spinler4aa23a12020-02-03 15:05:09 -060057constexpr auto bmcState = "xyz.openbmc_project.State.BMC";
58constexpr auto chassisState = "xyz.openbmc_project.State.Chassis";
59constexpr auto hostState = "xyz.openbmc_project.State.Host";
Matt Spinlerb3d488f2020-02-21 15:30:46 -060060constexpr auto invMotherboard =
61 "xyz.openbmc_project.Inventory.Item.Board.Motherboard";
62constexpr auto viniRecordVPD = "com.ibm.ipzvpd.VINI";
Matt Spinler60c4e792020-03-13 13:45:36 -050063constexpr auto locCode = "com.ibm.ipzvpd.Location";
Matt Spinler6ea4d5f2020-05-20 13:31:07 -050064constexpr auto invCompatible =
65 "xyz.openbmc_project.Inventory.Decorator.Compatible";
Matt Spinlerc8705e22019-09-11 12:36:07 -050066} // namespace interface
67
Matt Spinlera7d9d962019-11-06 15:01:25 -060068using namespace sdbusplus::xyz::openbmc_project::State::OperatingSystem::server;
Matt Spinlerb3d488f2020-02-21 15:30:46 -060069using sdbusplus::exception::SdBusError;
Matt Spinlera7d9d962019-11-06 15:01:25 -060070
Matt Spinlerc8705e22019-09-11 12:36:07 -050071DataInterface::DataInterface(sdbusplus::bus::bus& bus) : _bus(bus)
72{
Matt Spinlercad9c2b2019-12-02 15:42:01 -060073 readBMCFWVersion();
74 readServerFWVersion();
Matt Spinler677381b2020-01-23 10:04:29 -060075 readBMCFWVersionID();
Matt Spinlerb3d488f2020-02-21 15:30:46 -060076 readMotherboardCCIN();
Matt Spinler2a28c932020-02-03 14:23:40 -060077
78 // Watch both the Model and SN properties on the system's Asset iface
79 _properties.emplace_back(std::make_unique<InterfaceWatcher<DataInterface>>(
80 bus, object_path::systemInv, interface::invAsset, *this,
81 [this](const auto& properties) {
82 auto model = properties.find("Model");
83 if (model != properties.end())
84 {
85 this->_machineTypeModel = std::get<std::string>(model->second);
86 }
87
88 auto sn = properties.find("SerialNumber");
89 if (sn != properties.end())
90 {
91 this->_machineSerialNumber = std::get<std::string>(sn->second);
92 }
93 }));
94
95 // Watch the OperatingSystemState property
96 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
97 bus, object_path::hostState, interface::osStatus,
98 "OperatingSystemState", *this, [this](const auto& value) {
99 auto status =
100 Status::convertOSStatusFromString(std::get<std::string>(value));
101
102 if ((status == Status::OSStatus::BootComplete) ||
103 (status == Status::OSStatus::Standby))
104 {
Matt Spinler4aa23a12020-02-03 15:05:09 -0600105 setHostUp(true);
Matt Spinler2a28c932020-02-03 14:23:40 -0600106 }
107 else
108 {
Matt Spinler4aa23a12020-02-03 15:05:09 -0600109 setHostUp(false);
Matt Spinler2a28c932020-02-03 14:23:40 -0600110 }
111 }));
Matt Spinler9cf3cfd2020-02-03 14:41:55 -0600112
113 // Watch the host PEL enable property
114 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
115 bus, object_path::enableHostPELs, interface::enable, "Enabled", *this,
116 [this](const auto& value) {
117 this->_sendPELsToHost = std::get<bool>(value);
118 }));
Matt Spinler4aa23a12020-02-03 15:05:09 -0600119
120 // Watch the BMCState property
121 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
122 bus, object_path::bmcState, interface::bmcState, "CurrentBMCState",
123 *this, [this](const auto& value) {
124 this->_bmcState = std::get<std::string>(value);
125 }));
126
127 // Watch the chassis current and requested power state properties
128 _properties.emplace_back(std::make_unique<InterfaceWatcher<DataInterface>>(
129 bus, object_path::chassisState, interface::chassisState, *this,
130 [this](const auto& properties) {
131 auto state = properties.find("CurrentPowerState");
132 if (state != properties.end())
133 {
134 this->_chassisState = std::get<std::string>(state->second);
135 }
136
137 auto trans = properties.find("RequestedPowerTransition");
138 if (trans != properties.end())
139 {
140 this->_chassisTransition = std::get<std::string>(trans->second);
141 }
142 }));
143
144 // Watch the CurrentHostState property
145 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
146 bus, object_path::hostState, interface::hostState, "CurrentHostState",
147 *this, [this](const auto& value) {
148 this->_hostState = std::get<std::string>(value);
149 }));
Matt Spinler6ea4d5f2020-05-20 13:31:07 -0500150
151 // Watch the compatible system names property
152 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
153 bus, object_path::chassisInv, interface::invCompatible, "Names", *this,
154 [this](const auto& value) {
155 this->_systemNames = std::get<std::vector<std::string>>(value);
156 }));
Matt Spinlerc8705e22019-09-11 12:36:07 -0500157}
158
Matt Spinler2a28c932020-02-03 14:23:40 -0600159DBusPropertyMap
160 DataInterface::getAllProperties(const std::string& service,
161 const std::string& objectPath,
162 const std::string& interface) const
Matt Spinlerc8705e22019-09-11 12:36:07 -0500163{
164 DBusPropertyMap properties;
165
166 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
167 interface::dbusProperty, "GetAll");
168 method.append(interface);
169 auto reply = _bus.call(method);
170
171 reply.read(properties);
172
173 return properties;
174}
175
Matt Spinlera7d9d962019-11-06 15:01:25 -0600176void DataInterface::getProperty(const std::string& service,
177 const std::string& objectPath,
178 const std::string& interface,
Matt Spinler2a28c932020-02-03 14:23:40 -0600179 const std::string& property,
180 DBusValue& value) const
Matt Spinlera7d9d962019-11-06 15:01:25 -0600181{
182
183 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
184 interface::dbusProperty, "Get");
185 method.append(interface, property);
186 auto reply = _bus.call(method);
187
188 reply.read(value);
189}
190
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600191DBusPathList DataInterface::getPaths(const DBusInterfaceList& interfaces) const
192{
193
194 auto method = _bus.new_method_call(
195 service_name::objectMapper, object_path::objectMapper,
196 interface::objectMapper, "GetSubTreePaths");
197
198 method.append(std::string{"/"}, 0, interfaces);
199
200 auto reply = _bus.call(method);
201
202 DBusPathList paths;
203 reply.read(paths);
204
205 return paths;
206}
207
Matt Spinlerc8705e22019-09-11 12:36:07 -0500208DBusService DataInterface::getService(const std::string& objectPath,
Matt Spinlerb3f51862019-12-09 13:55:10 -0600209 const std::string& interface) const
Matt Spinlerc8705e22019-09-11 12:36:07 -0500210{
211 auto method = _bus.new_method_call(service_name::objectMapper,
212 object_path::objectMapper,
213 interface::objectMapper, "GetObject");
214
215 method.append(objectPath, std::vector<std::string>({interface}));
216
217 auto reply = _bus.call(method);
218
219 std::map<DBusService, DBusInterfaceList> response;
220 reply.read(response);
221
222 if (!response.empty())
223 {
224 return response.begin()->first;
225 }
226
227 return std::string{};
228}
Matt Spinlera7d9d962019-11-06 15:01:25 -0600229
Matt Spinler677381b2020-01-23 10:04:29 -0600230void DataInterface::readBMCFWVersion()
231{
Matt Spinlerf61f2922020-06-23 11:32:49 -0500232 _bmcFWVersion =
233 phosphor::logging::util::getOSReleaseValue("VERSION").value_or("");
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600234}
235
236void DataInterface::readServerFWVersion()
237{
238 // Not available yet
239}
240
Matt Spinler677381b2020-01-23 10:04:29 -0600241void DataInterface::readBMCFWVersionID()
242{
Matt Spinlerf61f2922020-06-23 11:32:49 -0500243 _bmcFWVersionID =
244 phosphor::logging::util::getOSReleaseValue("VERSION_ID").value_or("");
Matt Spinler677381b2020-01-23 10:04:29 -0600245}
246
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600247void DataInterface::readMotherboardCCIN()
248{
249 try
250 {
251 // First, try to find the motherboard
252 auto motherboards = getPaths({interface::invMotherboard});
253 if (motherboards.empty())
254 {
255 throw std::runtime_error("No motherboards yet");
256 }
257
258 // Found it, so now get the CCIN
259 _properties.emplace_back(
260 std::make_unique<PropertyWatcher<DataInterface>>(
261 _bus, motherboards.front(), interface::viniRecordVPD, "CC",
262 *this,
263 [this](const auto& ccin) { this->setMotherboardCCIN(ccin); }));
264 }
265 catch (const std::exception& e)
266 {
267 // No motherboard in the inventory yet - watch for it
268 _inventoryIfacesAddedMatch = std::make_unique<sdbusplus::bus::match_t>(
269 _bus, match_rules::interfacesAdded(object_path::baseInv),
270 std::bind(std::mem_fn(&DataInterface::motherboardIfaceAdded), this,
271 std::placeholders::_1));
272 }
273}
274
275void DataInterface::motherboardIfaceAdded(sdbusplus::message::message& msg)
276{
277 sdbusplus::message::object_path path;
278 DBusInterfaceMap interfaces;
279
280 msg.read(path, interfaces);
281
282 // This is watching the whole inventory, so check if it's what we want
283 if (interfaces.find(interface::invMotherboard) == interfaces.end())
284 {
285 return;
286 }
287
288 // Done watching for any new inventory interfaces
289 _inventoryIfacesAddedMatch.reset();
290
291 // Watch the motherboard CCIN, using the service from this signal
292 // for the initial property read.
293 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
294 _bus, path, interface::viniRecordVPD, "CC", msg.get_sender(), *this,
295 [this](const auto& ccin) { this->setMotherboardCCIN(ccin); }));
296}
297
Matt Spinler60c4e792020-03-13 13:45:36 -0500298void DataInterface::getHWCalloutFields(const std::string& inventoryPath,
Matt Spinler60c4e792020-03-13 13:45:36 -0500299 std::string& fruPartNumber,
300 std::string& ccin,
301 std::string& serialNumber) const
302{
303 // For now, attempt to get all of the properties directly on the path
304 // passed in. In the future, may need to make use of an algorithm
305 // to figure out which inventory objects actually hold these
306 // interfaces in the case of non FRUs, or possibly another service
307 // will provide this info. Any missing interfaces will result
308 // in exceptions being thrown.
309
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500310 auto service = getService(inventoryPath, interface::viniRecordVPD);
Matt Spinler60c4e792020-03-13 13:45:36 -0500311
312 auto properties =
313 getAllProperties(service, inventoryPath, interface::viniRecordVPD);
314
315 auto value = std::get<std::vector<uint8_t>>(properties["FN"]);
316 fruPartNumber = std::string{value.begin(), value.end()};
317
318 value = std::get<std::vector<uint8_t>>(properties["CC"]);
319 ccin = std::string{value.begin(), value.end()};
320
321 value = std::get<std::vector<uint8_t>>(properties["SN"]);
322 serialNumber = std::string{value.begin(), value.end()};
323}
324
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500325std::string
326 DataInterface::getLocationCode(const std::string& inventoryPath) const
327{
328 auto service = getService(inventoryPath, interface::locCode);
329
330 DBusValue locCode;
331 getProperty(service, inventoryPath, interface::locCode, "LocationCode",
332 locCode);
333
334 return std::get<std::string>(locCode);
335}
336
Matt Spinler5fb24c12020-06-04 11:21:33 -0500337std::string
338 DataInterface::addLocationCodePrefix(const std::string& locationCode)
339{
340 static const std::string locationCodePrefix{"Ufcs-"};
341
342 if (locationCode.find(locationCodePrefix) == std::string::npos)
343 {
344 return locationCodePrefix + locationCode;
345 }
346
347 return locationCode;
348}
349
350std::string DataInterface::expandLocationCode(const std::string& locationCode,
351 uint16_t node) const
352{
353 // TODO: fill in when that API is available
354 return addLocationCodePrefix(locationCode);
355}
356
357std::string DataInterface::getInventoryFromLocCode(
358 const std::string& unexpandedLocationCode, uint16_t node) const
359{
360 // TODO: fill in when that API is available and call on
361 // addLocationCodePrefix(unexpandedLocationCode);
362 return {};
363}
364
Matt Spinlerc8705e22019-09-11 12:36:07 -0500365} // namespace pels
366} // namespace openpower