blob: 64fe70e7a1ab6036468c003a747bcf731f561fae [file] [log] [blame]
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -08001/*
2// Copyright (c) 2018 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#pragma once
18
John Edward Broadbent7e860f12021-04-08 15:57:16 -070019#include <app.hpp>
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080020#include <boost/system/linux_error.hpp>
Ed Tanous168e20c2021-12-13 14:39:53 -080021#include <dbus_utility.hpp>
Ed Tanous45ca1b82022-03-25 13:07:27 -070022#include <query.hpp>
Ed Tanoused398212021-06-09 17:05:54 -070023#include <registries/privilege_registry.hpp>
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +020024#include <sdbusplus/asio/property.hpp>
25#include <sdbusplus/unpack_properties.hpp>
26#include <utils/dbus_utils.hpp>
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080027
28namespace redfish
29{
30
Gunnar Mills1214b7e2020-06-04 10:11:30 -050031static constexpr char const* pcieService = "xyz.openbmc_project.PCIe";
32static constexpr char const* pciePath = "/xyz/openbmc_project/PCIe";
33static constexpr char const* pcieDeviceInterface =
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080034 "xyz.openbmc_project.PCIe.Device";
35
Ed Tanousb5a76932020-09-29 16:16:58 -070036static inline void
zhanghch058d1b46d2021-04-01 11:18:24 +080037 getPCIeDeviceList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanousb5a76932020-09-29 16:16:58 -070038 const std::string& name)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080039{
Ed Tanousb9d36b42022-02-26 21:42:46 -080040 auto getPCIeMapCallback =
41 [asyncResp, name](const boost::system::error_code ec,
42 const dbus::utility::MapperGetSubTreePathsResponse&
43 pcieDevicePaths) {
Ed Tanous002d39b2022-05-31 08:59:27 -070044 if (ec)
45 {
46 BMCWEB_LOG_DEBUG << "no PCIe device paths found ec: "
47 << ec.message();
48 // Not an error, system just doesn't have PCIe info
49 return;
50 }
51 nlohmann::json& pcieDeviceList = asyncResp->res.jsonValue[name];
52 pcieDeviceList = nlohmann::json::array();
53 for (const std::string& pcieDevicePath : pcieDevicePaths)
54 {
55 size_t devStart = pcieDevicePath.rfind('/');
56 if (devStart == std::string::npos)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080057 {
Ed Tanous002d39b2022-05-31 08:59:27 -070058 continue;
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080059 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080060
Ed Tanous002d39b2022-05-31 08:59:27 -070061 std::string devName = pcieDevicePath.substr(devStart + 1);
62 if (devName.empty())
63 {
64 continue;
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080065 }
Ed Tanous002d39b2022-05-31 08:59:27 -070066 nlohmann::json::object_t pcieDevice;
67 pcieDevice["@odata.id"] =
68 "/redfish/v1/Systems/system/PCIeDevices/" + devName;
69 pcieDeviceList.push_back(std::move(pcieDevice));
70 }
71 asyncResp->res.jsonValue[name + "@odata.count"] = pcieDeviceList.size();
72 };
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080073 crow::connections::systemBus->async_method_call(
74 std::move(getPCIeMapCallback), "xyz.openbmc_project.ObjectMapper",
75 "/xyz/openbmc_project/object_mapper",
76 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
77 std::string(pciePath) + "/", 1, std::array<std::string, 0>());
78}
79
John Edward Broadbent7e860f12021-04-08 15:57:16 -070080inline void requestRoutesSystemPCIeDeviceCollection(App& app)
Jason M. Billsadbe1922019-10-14 15:44:35 -070081{
Jason M. Billsadbe1922019-10-14 15:44:35 -070082 /**
83 * Functions triggers appropriate requests on DBus
84 */
Ed Tanous22d268c2022-05-19 09:39:07 -070085 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/")
Ed Tanoused398212021-06-09 17:05:54 -070086 .privileges(redfish::privileges::getPCIeDeviceCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -070087 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -070088 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -070089 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
90 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +000091 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -070092 {
93 return;
94 }
Ed Tanous22d268c2022-05-19 09:39:07 -070095 if (systemName != "system")
96 {
97 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
98 systemName);
99 return;
100 }
Ed Tanous14766872022-03-15 10:44:42 -0700101
Ed Tanous002d39b2022-05-31 08:59:27 -0700102 asyncResp->res.jsonValue["@odata.type"] =
103 "#PCIeDeviceCollection.PCIeDeviceCollection";
104 asyncResp->res.jsonValue["@odata.id"] =
105 "/redfish/v1/Systems/system/PCIeDevices";
106 asyncResp->res.jsonValue["Name"] = "PCIe Device Collection";
107 asyncResp->res.jsonValue["Description"] = "Collection of PCIe Devices";
108 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
109 asyncResp->res.jsonValue["Members@odata.count"] = 0;
110 getPCIeDeviceList(asyncResp, "Members");
111 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700112}
113
Spencer Ku62cd45a2021-11-22 16:41:25 +0800114inline std::optional<std::string>
115 redfishPcieGenerationFromDbus(const std::string& generationInUse)
116{
117 if (generationInUse ==
118 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen1")
119 {
120 return "Gen1";
121 }
122 if (generationInUse ==
123 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen2")
124 {
125 return "Gen2";
126 }
127 if (generationInUse ==
128 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen3")
129 {
130 return "Gen3";
131 }
132 if (generationInUse ==
133 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen4")
134 {
135 return "Gen4";
136 }
137 if (generationInUse ==
138 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen5")
139 {
140 return "Gen5";
141 }
Ed Tanouse825cbc2022-06-17 11:39:22 -0700142 if (generationInUse.empty() ||
143 generationInUse ==
144 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Unknown")
Spencer Ku62cd45a2021-11-22 16:41:25 +0800145 {
146 return "";
147 }
148
149 // The value is not unknown or Gen1-5, need return an internal error.
150 return std::nullopt;
151}
152
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700153inline void requestRoutesSystemPCIeDevice(App& app)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800154{
Ed Tanous22d268c2022-05-19 09:39:07 -0700155 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700156 .privileges(redfish::privileges::getPCIeDevice)
Ed Tanous002d39b2022-05-31 08:59:27 -0700157 .methods(boost::beast::http::verb::get)(
158 [&app](const crow::Request& req,
159 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -0700160 const std::string& systemName, const std::string& device) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000161 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700162 {
163 return;
164 }
Ed Tanous22d268c2022-05-19 09:39:07 -0700165 if (systemName != "system")
166 {
167 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
168 systemName);
169 return;
170 }
171
Ed Tanous002d39b2022-05-31 08:59:27 -0700172 auto getPCIeDeviceCallback =
173 [asyncResp, device](
174 const boost::system::error_code ec,
175 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
176 if (ec)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700177 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700178 BMCWEB_LOG_DEBUG
179 << "failed to get PCIe Device properties ec: " << ec.value()
180 << ": " << ec.message();
181 if (ec.value() ==
182 boost::system::linux_error::bad_request_descriptor)
183 {
184 messages::resourceNotFound(asyncResp->res, "PCIeDevice",
185 device);
186 }
187 else
188 {
189 messages::internalError(asyncResp->res);
190 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700191 return;
192 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700193
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200194 const std::string* manufacturer = nullptr;
195 const std::string* deviceType = nullptr;
196 const std::string* generationInUse = nullptr;
197
198 const bool success = sdbusplus::unpackPropertiesNoThrow(
199 dbus_utils::UnpackErrorPrinter(), pcieDevProperties,
200 "Manufacturer", manufacturer, "DeviceType", deviceType,
201 "GenerationInUse", generationInUse);
202
203 if (!success)
204 {
205 messages::internalError(asyncResp->res);
206 return;
207 }
208
209 if (generationInUse != nullptr)
210 {
211 std::optional<std::string> redfishGenerationInUse =
212 redfishPcieGenerationFromDbus(*generationInUse);
213 if (!redfishGenerationInUse)
214 {
215 messages::internalError(asyncResp->res);
216 return;
217 }
Tony Leea9f68bb2022-10-20 19:35:38 +0800218 if (!redfishGenerationInUse->empty())
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200219 {
Tony Leea9f68bb2022-10-20 19:35:38 +0800220 asyncResp->res.jsonValue["PCIeInterface"]["PCIeType"] =
221 *redfishGenerationInUse;
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200222 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200223 }
224
225 if (manufacturer != nullptr)
226 {
227 asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
228 }
229
230 if (deviceType != nullptr)
231 {
232 asyncResp->res.jsonValue["DeviceType"] = *deviceType;
233 }
234
Ed Tanous002d39b2022-05-31 08:59:27 -0700235 asyncResp->res.jsonValue["@odata.type"] =
236 "#PCIeDevice.v1_4_0.PCIeDevice";
237 asyncResp->res.jsonValue["@odata.id"] =
238 "/redfish/v1/Systems/system/PCIeDevices/" + device;
239 asyncResp->res.jsonValue["Name"] = "PCIe Device";
240 asyncResp->res.jsonValue["Id"] = device;
241
242 asyncResp->res.jsonValue["PCIeFunctions"]["@odata.id"] =
243 "/redfish/v1/Systems/system/PCIeDevices/" + device +
244 "/PCIeFunctions";
Ed Tanous002d39b2022-05-31 08:59:27 -0700245 };
246 std::string escapedPath = std::string(pciePath) + "/" + device;
247 dbus::utility::escapePathForDbus(escapedPath);
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200248 sdbusplus::asio::getAllProperties(
249 *crow::connections::systemBus, pcieService, escapedPath,
250 pcieDeviceInterface, std::move(getPCIeDeviceCallback));
Ed Tanous45ca1b82022-03-25 13:07:27 -0700251 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700252}
253
254inline void requestRoutesSystemPCIeFunctionCollection(App& app)
255{
256 /**
257 * Functions triggers appropriate requests on DBus
258 */
259 BMCWEB_ROUTE(app,
260 "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/")
Ed Tanoused398212021-06-09 17:05:54 -0700261 .privileges(redfish::privileges::getPCIeFunctionCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -0700262 .methods(boost::beast::http::verb::get)(
263 [&app](const crow::Request& req,
264 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
265 const std::string& device) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000266 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700267 {
268 return;
269 }
270
271 asyncResp->res.jsonValue["@odata.type"] =
272 "#PCIeFunctionCollection.PCIeFunctionCollection";
273 asyncResp->res.jsonValue["@odata.id"] =
274 "/redfish/v1/Systems/system/PCIeDevices/" + device +
275 "/PCIeFunctions";
276 asyncResp->res.jsonValue["Name"] = "PCIe Function Collection";
277 asyncResp->res.jsonValue["Description"] =
278 "Collection of PCIe Functions for PCIe Device " + device;
279
280 auto getPCIeDeviceCallback =
281 [asyncResp, device](
282 const boost::system::error_code ec,
283 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
284 if (ec)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700285 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700286 BMCWEB_LOG_DEBUG
287 << "failed to get PCIe Device properties ec: " << ec.value()
288 << ": " << ec.message();
289 if (ec.value() ==
290 boost::system::linux_error::bad_request_descriptor)
291 {
292 messages::resourceNotFound(asyncResp->res, "PCIeDevice",
293 device);
294 }
295 else
296 {
297 messages::internalError(asyncResp->res);
298 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700299 return;
300 }
Ed Tanous14766872022-03-15 10:44:42 -0700301
Ed Tanous002d39b2022-05-31 08:59:27 -0700302 nlohmann::json& pcieFunctionList =
303 asyncResp->res.jsonValue["Members"];
304 pcieFunctionList = nlohmann::json::array();
305 static constexpr const int maxPciFunctionNum = 8;
306 for (int functionNum = 0; functionNum < maxPciFunctionNum;
307 functionNum++)
308 {
309 // Check if this function exists by looking for a
310 // device ID
311 std::string devIDProperty =
312 "Function" + std::to_string(functionNum) + "DeviceId";
313 const std::string* property = nullptr;
314 for (const auto& propEntry : pcieDevProperties)
315 {
316 if (propEntry.first == devIDProperty)
Ed Tanous45ca1b82022-03-25 13:07:27 -0700317 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700318 property = std::get_if<std::string>(&propEntry.second);
Ed Tanous45ca1b82022-03-25 13:07:27 -0700319 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700320 }
Nan Zhoufb0ecc32022-10-17 19:17:36 +0000321 if (property == nullptr || property->empty())
Ed Tanous002d39b2022-05-31 08:59:27 -0700322 {
Nan Zhoue28ce0e2022-10-13 22:28:36 +0000323 continue;
Ed Tanous002d39b2022-05-31 08:59:27 -0700324 }
325 nlohmann::json::object_t pcieFunction;
326 pcieFunction["@odata.id"] =
327 "/redfish/v1/Systems/system/PCIeDevices/" + device +
328 "/PCIeFunctions/" + std::to_string(functionNum);
329 pcieFunctionList.push_back(std::move(pcieFunction));
330 }
331 asyncResp->res.jsonValue["Members@odata.count"] =
332 pcieFunctionList.size();
333 };
334 std::string escapedPath = std::string(pciePath) + "/" + device;
335 dbus::utility::escapePathForDbus(escapedPath);
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200336 sdbusplus::asio::getAllProperties(
337 *crow::connections::systemBus, pcieService, escapedPath,
338 pcieDeviceInterface, std::move(getPCIeDeviceCallback));
Ed Tanous45ca1b82022-03-25 13:07:27 -0700339 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700340}
341
342inline void requestRoutesSystemPCIeFunction(App& app)
343{
344 BMCWEB_ROUTE(
345 app,
346 "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700347 .privileges(redfish::privileges::getPCIeFunction)
Ed Tanous002d39b2022-05-31 08:59:27 -0700348 .methods(boost::beast::http::verb::get)(
349 [&app](const crow::Request& req,
350 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
351 const std::string& device, const std::string& function) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000352 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700353 {
354 return;
355 }
356 auto getPCIeDeviceCallback =
357 [asyncResp, device, function](
358 const boost::system::error_code ec,
359 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
360 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -0700361 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700362 BMCWEB_LOG_DEBUG
363 << "failed to get PCIe Device properties ec: " << ec.value()
364 << ": " << ec.message();
365 if (ec.value() ==
366 boost::system::linux_error::bad_request_descriptor)
367 {
368 messages::resourceNotFound(asyncResp->res, "PCIeDevice",
369 device);
370 }
371 else
372 {
373 messages::internalError(asyncResp->res);
374 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700375 return;
376 }
Ed Tanous168e20c2021-12-13 14:39:53 -0800377
Ed Tanous002d39b2022-05-31 08:59:27 -0700378 // Check if this function exists by looking for a device
379 // ID
380 std::string functionName = "Function" + function;
381 std::string devIDProperty = functionName + "DeviceId";
Ed Tanousb9d36b42022-02-26 21:42:46 -0800382
Ed Tanous002d39b2022-05-31 08:59:27 -0700383 const std::string* devIdProperty = nullptr;
384 for (const auto& property : pcieDevProperties)
385 {
386 if (property.first == devIDProperty)
387 {
388 devIdProperty = std::get_if<std::string>(&property.second);
389 continue;
390 }
391 }
392 if (devIdProperty == nullptr || !devIdProperty->empty())
393 {
394 messages::resourceNotFound(asyncResp->res, "PCIeFunction",
395 function);
396 return;
397 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800398
Ed Tanous002d39b2022-05-31 08:59:27 -0700399 asyncResp->res.jsonValue["@odata.type"] =
400 "#PCIeFunction.v1_2_0.PCIeFunction";
401 asyncResp->res.jsonValue["@odata.id"] =
402 "/redfish/v1/Systems/system/PCIeDevices/" + device +
403 "/PCIeFunctions/" + function;
404 asyncResp->res.jsonValue["Name"] = "PCIe Function";
405 asyncResp->res.jsonValue["Id"] = function;
406 asyncResp->res.jsonValue["FunctionId"] = std::stoi(function);
407 asyncResp->res.jsonValue["Links"]["PCIeDevice"]["@odata.id"] =
408 "/redfish/v1/Systems/system/PCIeDevices/" + device;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700409
Ed Tanous002d39b2022-05-31 08:59:27 -0700410 for (const auto& property : pcieDevProperties)
411 {
412 const std::string* strProperty =
413 std::get_if<std::string>(&property.second);
414 if (property.first == functionName + "DeviceId")
415 {
416 asyncResp->res.jsonValue["DeviceId"] = *strProperty;
417 }
418 if (property.first == functionName + "VendorId")
419 {
420 asyncResp->res.jsonValue["VendorId"] = *strProperty;
421 }
422 if (property.first == functionName + "FunctionType")
423 {
424 asyncResp->res.jsonValue["FunctionType"] = *strProperty;
425 }
426 if (property.first == functionName + "DeviceClass")
427 {
428 asyncResp->res.jsonValue["DeviceClass"] = *strProperty;
429 }
430 if (property.first == functionName + "ClassCode")
431 {
432 asyncResp->res.jsonValue["ClassCode"] = *strProperty;
433 }
434 if (property.first == functionName + "RevisionId")
435 {
436 asyncResp->res.jsonValue["RevisionId"] = *strProperty;
437 }
438 if (property.first == functionName + "SubsystemId")
439 {
440 asyncResp->res.jsonValue["SubsystemId"] = *strProperty;
441 }
442 if (property.first == functionName + "SubsystemVendorId")
443 {
444 asyncResp->res.jsonValue["SubsystemVendorId"] =
445 *strProperty;
446 }
447 }
448 };
449 std::string escapedPath = std::string(pciePath) + "/" + device;
450 dbus::utility::escapePathForDbus(escapedPath);
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200451 sdbusplus::asio::getAllProperties(
452 *crow::connections::systemBus, pcieService, escapedPath,
453 pcieDeviceInterface, std::move(getPCIeDeviceCallback));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700454 });
455}
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800456
457} // namespace redfish