blob: 8437f501fce35b8bcf0487e6b82eb123480fc5f2 [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>
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080024
25namespace redfish
26{
27
Gunnar Mills1214b7e2020-06-04 10:11:30 -050028static constexpr char const* pcieService = "xyz.openbmc_project.PCIe";
29static constexpr char const* pciePath = "/xyz/openbmc_project/PCIe";
30static constexpr char const* pcieDeviceInterface =
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080031 "xyz.openbmc_project.PCIe.Device";
32
Ed Tanousb5a76932020-09-29 16:16:58 -070033static inline void
zhanghch058d1b46d2021-04-01 11:18:24 +080034 getPCIeDeviceList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanousb5a76932020-09-29 16:16:58 -070035 const std::string& name)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080036{
Ed Tanousb9d36b42022-02-26 21:42:46 -080037 auto getPCIeMapCallback =
38 [asyncResp, name](const boost::system::error_code ec,
39 const dbus::utility::MapperGetSubTreePathsResponse&
40 pcieDevicePaths) {
Ed Tanous002d39b2022-05-31 08:59:27 -070041 if (ec)
42 {
43 BMCWEB_LOG_DEBUG << "no PCIe device paths found ec: "
44 << ec.message();
45 // Not an error, system just doesn't have PCIe info
46 return;
47 }
48 nlohmann::json& pcieDeviceList = asyncResp->res.jsonValue[name];
49 pcieDeviceList = nlohmann::json::array();
50 for (const std::string& pcieDevicePath : pcieDevicePaths)
51 {
52 size_t devStart = pcieDevicePath.rfind('/');
53 if (devStart == std::string::npos)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080054 {
Ed Tanous002d39b2022-05-31 08:59:27 -070055 continue;
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080056 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080057
Ed Tanous002d39b2022-05-31 08:59:27 -070058 std::string devName = pcieDevicePath.substr(devStart + 1);
59 if (devName.empty())
60 {
61 continue;
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080062 }
Ed Tanous002d39b2022-05-31 08:59:27 -070063 nlohmann::json::object_t pcieDevice;
64 pcieDevice["@odata.id"] =
65 "/redfish/v1/Systems/system/PCIeDevices/" + devName;
66 pcieDeviceList.push_back(std::move(pcieDevice));
67 }
68 asyncResp->res.jsonValue[name + "@odata.count"] = pcieDeviceList.size();
69 };
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080070 crow::connections::systemBus->async_method_call(
71 std::move(getPCIeMapCallback), "xyz.openbmc_project.ObjectMapper",
72 "/xyz/openbmc_project/object_mapper",
73 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
74 std::string(pciePath) + "/", 1, std::array<std::string, 0>());
75}
76
John Edward Broadbent7e860f12021-04-08 15:57:16 -070077inline void requestRoutesSystemPCIeDeviceCollection(App& app)
Jason M. Billsadbe1922019-10-14 15:44:35 -070078{
Jason M. Billsadbe1922019-10-14 15:44:35 -070079 /**
80 * Functions triggers appropriate requests on DBus
81 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -070082 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/PCIeDevices/")
Ed Tanoused398212021-06-09 17:05:54 -070083 .privileges(redfish::privileges::getPCIeDeviceCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -070084 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -070085 [&app](const crow::Request& req,
86 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +000087 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -070088 {
89 return;
90 }
Ed Tanous14766872022-03-15 10:44:42 -070091
Ed Tanous002d39b2022-05-31 08:59:27 -070092 asyncResp->res.jsonValue["@odata.type"] =
93 "#PCIeDeviceCollection.PCIeDeviceCollection";
94 asyncResp->res.jsonValue["@odata.id"] =
95 "/redfish/v1/Systems/system/PCIeDevices";
96 asyncResp->res.jsonValue["Name"] = "PCIe Device Collection";
97 asyncResp->res.jsonValue["Description"] = "Collection of PCIe Devices";
98 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
99 asyncResp->res.jsonValue["Members@odata.count"] = 0;
100 getPCIeDeviceList(asyncResp, "Members");
101 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700102}
103
Spencer Ku62cd45a2021-11-22 16:41:25 +0800104inline std::optional<std::string>
105 redfishPcieGenerationFromDbus(const std::string& generationInUse)
106{
107 if (generationInUse ==
108 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen1")
109 {
110 return "Gen1";
111 }
112 if (generationInUse ==
113 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen2")
114 {
115 return "Gen2";
116 }
117 if (generationInUse ==
118 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen3")
119 {
120 return "Gen3";
121 }
122 if (generationInUse ==
123 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen4")
124 {
125 return "Gen4";
126 }
127 if (generationInUse ==
128 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen5")
129 {
130 return "Gen5";
131 }
Chicago Duan7691cc22021-01-25 19:52:35 +0800132 if (generationInUse ==
133 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Unknown")
Spencer Ku62cd45a2021-11-22 16:41:25 +0800134 {
135 return "";
136 }
137
138 // The value is not unknown or Gen1-5, need return an internal error.
139 return std::nullopt;
140}
141
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700142inline void requestRoutesSystemPCIeDevice(App& app)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800143{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700144 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/PCIeDevices/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700145 .privileges(redfish::privileges::getPCIeDevice)
Ed Tanous002d39b2022-05-31 08:59:27 -0700146 .methods(boost::beast::http::verb::get)(
147 [&app](const crow::Request& req,
148 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
149 const std::string& device) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000150 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700151 {
152 return;
153 }
154 auto getPCIeDeviceCallback =
155 [asyncResp, device](
156 const boost::system::error_code ec,
157 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
158 if (ec)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700159 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700160 BMCWEB_LOG_DEBUG
161 << "failed to get PCIe Device properties ec: " << ec.value()
162 << ": " << ec.message();
163 if (ec.value() ==
164 boost::system::linux_error::bad_request_descriptor)
165 {
166 messages::resourceNotFound(asyncResp->res, "PCIeDevice",
167 device);
168 }
169 else
170 {
171 messages::internalError(asyncResp->res);
172 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700173 return;
174 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700175
176 asyncResp->res.jsonValue["@odata.type"] =
177 "#PCIeDevice.v1_4_0.PCIeDevice";
178 asyncResp->res.jsonValue["@odata.id"] =
179 "/redfish/v1/Systems/system/PCIeDevices/" + device;
180 asyncResp->res.jsonValue["Name"] = "PCIe Device";
181 asyncResp->res.jsonValue["Id"] = device;
182
183 asyncResp->res.jsonValue["PCIeFunctions"]["@odata.id"] =
184 "/redfish/v1/Systems/system/PCIeDevices/" + device +
185 "/PCIeFunctions";
186 for (const auto& property : pcieDevProperties)
187 {
188 const std::string* propertyString =
189 std::get_if<std::string>(&property.second);
190 if (property.first == "Manufacturer")
191 {
192 if (propertyString == nullptr)
Ed Tanous45ca1b82022-03-25 13:07:27 -0700193 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700194 messages::internalError(asyncResp->res);
Ed Tanous45ca1b82022-03-25 13:07:27 -0700195 return;
196 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700197 asyncResp->res.jsonValue["Manufacturer"] = *propertyString;
198 }
199 if (property.first == "DeviceType")
200 {
201 if (propertyString == nullptr)
Ed Tanous45ca1b82022-03-25 13:07:27 -0700202 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700203 messages::internalError(asyncResp->res);
204 return;
Ed Tanous45ca1b82022-03-25 13:07:27 -0700205 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700206 asyncResp->res.jsonValue["DeviceType"] = *propertyString;
207 }
208 if (property.first == "GenerationInUse")
209 {
210 if (propertyString == nullptr)
211 {
212 messages::internalError(asyncResp->res);
213 return;
214 }
215 std::optional<std::string> generationInUse =
216 redfishPcieGenerationFromDbus(*propertyString);
217 if (!generationInUse)
218 {
219 messages::internalError(asyncResp->res);
220 return;
221 }
222 if (generationInUse->empty())
223 {
224 // unknown, no need to handle
225 return;
226 }
227 asyncResp->res.jsonValue["PCIeInterface"]["PCIeType"] =
228 *generationInUse;
229 }
230 }
231 };
232 std::string escapedPath = std::string(pciePath) + "/" + device;
233 dbus::utility::escapePathForDbus(escapedPath);
234 crow::connections::systemBus->async_method_call(
235 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
236 "org.freedesktop.DBus.Properties", "GetAll", pcieDeviceInterface);
Ed Tanous45ca1b82022-03-25 13:07:27 -0700237 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700238}
239
240inline void requestRoutesSystemPCIeFunctionCollection(App& app)
241{
242 /**
243 * Functions triggers appropriate requests on DBus
244 */
245 BMCWEB_ROUTE(app,
246 "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/")
Ed Tanoused398212021-06-09 17:05:54 -0700247 .privileges(redfish::privileges::getPCIeFunctionCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -0700248 .methods(boost::beast::http::verb::get)(
249 [&app](const crow::Request& req,
250 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
251 const std::string& device) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000252 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700253 {
254 return;
255 }
256
257 asyncResp->res.jsonValue["@odata.type"] =
258 "#PCIeFunctionCollection.PCIeFunctionCollection";
259 asyncResp->res.jsonValue["@odata.id"] =
260 "/redfish/v1/Systems/system/PCIeDevices/" + device +
261 "/PCIeFunctions";
262 asyncResp->res.jsonValue["Name"] = "PCIe Function Collection";
263 asyncResp->res.jsonValue["Description"] =
264 "Collection of PCIe Functions for PCIe Device " + device;
265
266 auto getPCIeDeviceCallback =
267 [asyncResp, device](
268 const boost::system::error_code ec,
269 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
270 if (ec)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700271 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700272 BMCWEB_LOG_DEBUG
273 << "failed to get PCIe Device properties ec: " << ec.value()
274 << ": " << ec.message();
275 if (ec.value() ==
276 boost::system::linux_error::bad_request_descriptor)
277 {
278 messages::resourceNotFound(asyncResp->res, "PCIeDevice",
279 device);
280 }
281 else
282 {
283 messages::internalError(asyncResp->res);
284 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700285 return;
286 }
Ed Tanous14766872022-03-15 10:44:42 -0700287
Ed Tanous002d39b2022-05-31 08:59:27 -0700288 nlohmann::json& pcieFunctionList =
289 asyncResp->res.jsonValue["Members"];
290 pcieFunctionList = nlohmann::json::array();
291 static constexpr const int maxPciFunctionNum = 8;
292 for (int functionNum = 0; functionNum < maxPciFunctionNum;
293 functionNum++)
294 {
295 // Check if this function exists by looking for a
296 // device ID
297 std::string devIDProperty =
298 "Function" + std::to_string(functionNum) + "DeviceId";
299 const std::string* property = nullptr;
300 for (const auto& propEntry : pcieDevProperties)
301 {
302 if (propEntry.first == devIDProperty)
Ed Tanous45ca1b82022-03-25 13:07:27 -0700303 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700304 property = std::get_if<std::string>(&propEntry.second);
Ed Tanous45ca1b82022-03-25 13:07:27 -0700305 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700306 }
307 if (property == nullptr || !property->empty())
308 {
309 return;
310 }
311 nlohmann::json::object_t pcieFunction;
312 pcieFunction["@odata.id"] =
313 "/redfish/v1/Systems/system/PCIeDevices/" + device +
314 "/PCIeFunctions/" + std::to_string(functionNum);
315 pcieFunctionList.push_back(std::move(pcieFunction));
316 }
317 asyncResp->res.jsonValue["Members@odata.count"] =
318 pcieFunctionList.size();
319 };
320 std::string escapedPath = std::string(pciePath) + "/" + device;
321 dbus::utility::escapePathForDbus(escapedPath);
322 crow::connections::systemBus->async_method_call(
323 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
324 "org.freedesktop.DBus.Properties", "GetAll", pcieDeviceInterface);
Ed Tanous45ca1b82022-03-25 13:07:27 -0700325 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700326}
327
328inline void requestRoutesSystemPCIeFunction(App& app)
329{
330 BMCWEB_ROUTE(
331 app,
332 "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700333 .privileges(redfish::privileges::getPCIeFunction)
Ed Tanous002d39b2022-05-31 08:59:27 -0700334 .methods(boost::beast::http::verb::get)(
335 [&app](const crow::Request& req,
336 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
337 const std::string& device, const std::string& function) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000338 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700339 {
340 return;
341 }
342 auto getPCIeDeviceCallback =
343 [asyncResp, device, function](
344 const boost::system::error_code ec,
345 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
346 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -0700347 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700348 BMCWEB_LOG_DEBUG
349 << "failed to get PCIe Device properties ec: " << ec.value()
350 << ": " << ec.message();
351 if (ec.value() ==
352 boost::system::linux_error::bad_request_descriptor)
353 {
354 messages::resourceNotFound(asyncResp->res, "PCIeDevice",
355 device);
356 }
357 else
358 {
359 messages::internalError(asyncResp->res);
360 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700361 return;
362 }
Ed Tanous168e20c2021-12-13 14:39:53 -0800363
Ed Tanous002d39b2022-05-31 08:59:27 -0700364 // Check if this function exists by looking for a device
365 // ID
366 std::string functionName = "Function" + function;
367 std::string devIDProperty = functionName + "DeviceId";
Ed Tanousb9d36b42022-02-26 21:42:46 -0800368
Ed Tanous002d39b2022-05-31 08:59:27 -0700369 const std::string* devIdProperty = nullptr;
370 for (const auto& property : pcieDevProperties)
371 {
372 if (property.first == devIDProperty)
373 {
374 devIdProperty = std::get_if<std::string>(&property.second);
375 continue;
376 }
377 }
378 if (devIdProperty == nullptr || !devIdProperty->empty())
379 {
380 messages::resourceNotFound(asyncResp->res, "PCIeFunction",
381 function);
382 return;
383 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800384
Ed Tanous002d39b2022-05-31 08:59:27 -0700385 asyncResp->res.jsonValue["@odata.type"] =
386 "#PCIeFunction.v1_2_0.PCIeFunction";
387 asyncResp->res.jsonValue["@odata.id"] =
388 "/redfish/v1/Systems/system/PCIeDevices/" + device +
389 "/PCIeFunctions/" + function;
390 asyncResp->res.jsonValue["Name"] = "PCIe Function";
391 asyncResp->res.jsonValue["Id"] = function;
392 asyncResp->res.jsonValue["FunctionId"] = std::stoi(function);
393 asyncResp->res.jsonValue["Links"]["PCIeDevice"]["@odata.id"] =
394 "/redfish/v1/Systems/system/PCIeDevices/" + device;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700395
Ed Tanous002d39b2022-05-31 08:59:27 -0700396 for (const auto& property : pcieDevProperties)
397 {
398 const std::string* strProperty =
399 std::get_if<std::string>(&property.second);
400 if (property.first == functionName + "DeviceId")
401 {
402 asyncResp->res.jsonValue["DeviceId"] = *strProperty;
403 }
404 if (property.first == functionName + "VendorId")
405 {
406 asyncResp->res.jsonValue["VendorId"] = *strProperty;
407 }
408 if (property.first == functionName + "FunctionType")
409 {
410 asyncResp->res.jsonValue["FunctionType"] = *strProperty;
411 }
412 if (property.first == functionName + "DeviceClass")
413 {
414 asyncResp->res.jsonValue["DeviceClass"] = *strProperty;
415 }
416 if (property.first == functionName + "ClassCode")
417 {
418 asyncResp->res.jsonValue["ClassCode"] = *strProperty;
419 }
420 if (property.first == functionName + "RevisionId")
421 {
422 asyncResp->res.jsonValue["RevisionId"] = *strProperty;
423 }
424 if (property.first == functionName + "SubsystemId")
425 {
426 asyncResp->res.jsonValue["SubsystemId"] = *strProperty;
427 }
428 if (property.first == functionName + "SubsystemVendorId")
429 {
430 asyncResp->res.jsonValue["SubsystemVendorId"] =
431 *strProperty;
432 }
433 }
434 };
435 std::string escapedPath = std::string(pciePath) + "/" + device;
436 dbus::utility::escapePathForDbus(escapedPath);
437 crow::connections::systemBus->async_method_call(
438 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
439 "org.freedesktop.DBus.Properties", "GetAll", pcieDeviceInterface);
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700440 });
441}
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800442
443} // namespace redfish