blob: be5981112c33a781c5d4e3a064b76a897f884b19 [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) {
41 if (ec)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080042 {
Ed Tanousb9d36b42022-02-26 21:42:46 -080043 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;
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080047 }
Ed Tanousb9d36b42022-02-26 21:42:46 -080048 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)
54 {
55 continue;
56 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080057
Ed Tanousb9d36b42022-02-26 21:42:46 -080058 std::string devName = pcieDevicePath.substr(devStart + 1);
59 if (devName.empty())
60 {
61 continue;
62 }
63 pcieDeviceList.push_back(
64 {{"@odata.id",
65 "/redfish/v1/Systems/system/PCIeDevices/" + devName}});
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080066 }
Ed Tanousb9d36b42022-02-26 21:42:46 -080067 asyncResp->res.jsonValue[name + "@odata.count"] =
68 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) {
87 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
88 {
89 return;
90 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -070091 asyncResp->res.jsonValue = {
92 {"@odata.type",
93 "#PCIeDeviceCollection.PCIeDeviceCollection"},
94 {"@odata.id", "/redfish/v1/Systems/system/PCIeDevices"},
95 {"Name", "PCIe Device Collection"},
96 {"Description", "Collection of PCIe Devices"},
97 {"Members", nlohmann::json::array()},
98 {"Members@odata.count", 0}};
99 getPCIeDeviceList(asyncResp, "Members");
100 });
101}
102
Spencer Ku62cd45a2021-11-22 16:41:25 +0800103inline std::optional<std::string>
104 redfishPcieGenerationFromDbus(const std::string& generationInUse)
105{
106 if (generationInUse ==
107 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen1")
108 {
109 return "Gen1";
110 }
111 if (generationInUse ==
112 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen2")
113 {
114 return "Gen2";
115 }
116 if (generationInUse ==
117 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen3")
118 {
119 return "Gen3";
120 }
121 if (generationInUse ==
122 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen4")
123 {
124 return "Gen4";
125 }
126 if (generationInUse ==
127 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen5")
128 {
129 return "Gen5";
130 }
131 if (generationInUse.empty() ||
132 generationInUse ==
133 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Unknown")
134 {
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 Tanous45ca1b82022-03-25 13:07:27 -0700146 .methods(
147 boost::beast::http::verb::
148 get)([&app](const crow::Request& req,
149 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
150 const std::string& device) {
151 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700152 {
Ed Tanous45ca1b82022-03-25 13:07:27 -0700153 return;
154 }
155 auto getPCIeDeviceCallback =
156 [asyncResp, device](
157 const boost::system::error_code ec,
158 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
159 if (ec)
160 {
161 BMCWEB_LOG_DEBUG
162 << "failed to get PCIe Device properties ec: "
163 << ec.value() << ": " << ec.message();
164 if (ec.value() ==
165 boost::system::linux_error::bad_request_descriptor)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700166 {
Ed Tanous45ca1b82022-03-25 13:07:27 -0700167 messages::resourceNotFound(asyncResp->res,
168 "PCIeDevice", device);
169 }
170 else
171 {
172 messages::internalError(asyncResp->res);
173 }
174 return;
175 }
176
177 asyncResp->res.jsonValue = {
178 {"@odata.type", "#PCIeDevice.v1_4_0.PCIeDevice"},
179 {"@odata.id",
180 "/redfish/v1/Systems/system/PCIeDevices/" + device},
181 {"Name", "PCIe Device"},
182 {"Id", device}};
183 asyncResp->res.jsonValue["PCIeFunctions"] = {
184 {"@odata.id",
185 "/redfish/v1/Systems/system/PCIeDevices/" + device +
186 "/PCIeFunctions"}};
187 for (const auto& property : pcieDevProperties)
188 {
189 const std::string* propertyString =
190 std::get_if<std::string>(&property.second);
191 if (property.first == "Manufacturer")
192 {
193 if (propertyString == nullptr)
Ed Tanous168e20c2021-12-13 14:39:53 -0800194 {
195 messages::internalError(asyncResp->res);
Ed Tanous45ca1b82022-03-25 13:07:27 -0700196 return;
Ed Tanous168e20c2021-12-13 14:39:53 -0800197 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700198 asyncResp->res.jsonValue["Manufacturer"] =
199 *propertyString;
Spencer Ku62cd45a2021-11-22 16:41:25 +0800200 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700201 if (property.first == "DeviceType")
Ed Tanousb9d36b42022-02-26 21:42:46 -0800202 {
Ed Tanous45ca1b82022-03-25 13:07:27 -0700203 if (propertyString == nullptr)
Ed Tanousb9d36b42022-02-26 21:42:46 -0800204 {
Ed Tanous45ca1b82022-03-25 13:07:27 -0700205 messages::internalError(asyncResp->res);
206 return;
Ed Tanousb9d36b42022-02-26 21:42:46 -0800207 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700208 asyncResp->res.jsonValue["DeviceType"] =
209 *propertyString;
Ed Tanousb9d36b42022-02-26 21:42:46 -0800210 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700211 if (property.first == "GenerationInUse")
212 {
213 if (propertyString == nullptr)
214 {
215 messages::internalError(asyncResp->res);
216 return;
217 }
218 std::optional<std::string> generationInUse =
219 redfishPcieGenerationFromDbus(*propertyString);
220 if (!generationInUse)
221 {
222 messages::internalError(asyncResp->res);
223 return;
224 }
225 if (generationInUse->empty())
226 {
227 // unknown, no need to handle
228 return;
229 }
230 asyncResp->res
231 .jsonValue["PCIeInterface"]["PCIeType"] =
232 *generationInUse;
233 }
234 }
235 };
236 std::string escapedPath = std::string(pciePath) + "/" + device;
237 dbus::utility::escapePathForDbus(escapedPath);
238 crow::connections::systemBus->async_method_call(
239 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
240 "org.freedesktop.DBus.Properties", "GetAll",
241 pcieDeviceInterface);
242 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700243}
244
245inline void requestRoutesSystemPCIeFunctionCollection(App& app)
246{
247 /**
248 * Functions triggers appropriate requests on DBus
249 */
250 BMCWEB_ROUTE(app,
251 "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/")
Ed Tanoused398212021-06-09 17:05:54 -0700252 .privileges(redfish::privileges::getPCIeFunctionCollection)
Ed Tanous45ca1b82022-03-25 13:07:27 -0700253 .methods(
254 boost::beast::http::verb::
255 get)([&app](const crow::Request& req,
256 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
257 const std::string& device) {
258 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700259 {
Ed Tanous45ca1b82022-03-25 13:07:27 -0700260 return;
261 }
262 asyncResp->res.jsonValue = {
263 {"@odata.type",
264 "#PCIeFunctionCollection.PCIeFunctionCollection"},
265 {"@odata.id", "/redfish/v1/Systems/system/PCIeDevices/" +
266 device + "/PCIeFunctions"},
267 {"Name", "PCIe Function Collection"},
268 {"Description",
269 "Collection of PCIe Functions for PCIe Device " + device}};
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700270
Ed Tanous45ca1b82022-03-25 13:07:27 -0700271 auto getPCIeDeviceCallback =
272 [asyncResp, device](
273 const boost::system::error_code ec,
274 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
275 if (ec)
276 {
277 BMCWEB_LOG_DEBUG
278 << "failed to get PCIe Device properties ec: "
279 << ec.value() << ": " << ec.message();
280 if (ec.value() ==
281 boost::system::linux_error::bad_request_descriptor)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700282 {
Ed Tanous45ca1b82022-03-25 13:07:27 -0700283 messages::resourceNotFound(asyncResp->res,
284 "PCIeDevice", device);
285 }
286 else
287 {
288 messages::internalError(asyncResp->res);
289 }
290 return;
291 }
292
293 nlohmann::json& pcieFunctionList =
294 asyncResp->res.jsonValue["Members"];
295 pcieFunctionList = nlohmann::json::array();
296 static constexpr const int maxPciFunctionNum = 8;
297 for (int functionNum = 0; functionNum < maxPciFunctionNum;
298 functionNum++)
299 {
300 // Check if this function exists by looking for a
301 // device ID
302 std::string devIDProperty =
303 "Function" + std::to_string(functionNum) +
304 "DeviceId";
305 const std::string* property = nullptr;
306 for (const auto& propEntry : pcieDevProperties)
307 {
308 if (propEntry.first == devIDProperty)
Ed Tanousb9d36b42022-02-26 21:42:46 -0800309 {
Ed Tanous45ca1b82022-03-25 13:07:27 -0700310 property =
311 std::get_if<std::string>(&propEntry.second);
Ed Tanousb9d36b42022-02-26 21:42:46 -0800312 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700313 }
314 if (property == nullptr || !property->empty())
315 {
Ed Tanousb9d36b42022-02-26 21:42:46 -0800316 return;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700317 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700318 pcieFunctionList.push_back(
319 {{"@odata.id",
320 "/redfish/v1/Systems/system/PCIeDevices/" +
321 device + "/PCIeFunctions/" +
322 std::to_string(functionNum)}});
323 }
324 asyncResp->res.jsonValue["Members@odata.count"] =
325 pcieFunctionList.size();
326 };
327 std::string escapedPath = std::string(pciePath) + "/" + device;
328 dbus::utility::escapePathForDbus(escapedPath);
329 crow::connections::systemBus->async_method_call(
330 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
331 "org.freedesktop.DBus.Properties", "GetAll",
332 pcieDeviceInterface);
333 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700334}
335
336inline void requestRoutesSystemPCIeFunction(App& app)
337{
338 BMCWEB_ROUTE(
339 app,
340 "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700341 .privileges(redfish::privileges::getPCIeFunction)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700342 .methods(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700343 boost::beast::http::verb::
344 get)([&app](const crow::Request& req,
345 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
346 const std::string& device,
347 const std::string& function) {
348 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
349 {
350 return;
351 }
Ed Tanous168e20c2021-12-13 14:39:53 -0800352 auto getPCIeDeviceCallback =
353 [asyncResp, device, function](
354 const boost::system::error_code ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800355 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
Ed Tanous168e20c2021-12-13 14:39:53 -0800356 if (ec)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800357 {
Ed Tanous168e20c2021-12-13 14:39:53 -0800358 BMCWEB_LOG_DEBUG
359 << "failed to get PCIe Device properties ec: "
360 << ec.value() << ": " << ec.message();
361 if (ec.value() ==
362 boost::system::linux_error::bad_request_descriptor)
363 {
364 messages::resourceNotFound(asyncResp->res,
365 "PCIeDevice", device);
366 }
367 else
368 {
369 messages::internalError(asyncResp->res);
370 }
371 return;
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800372 }
Ed Tanous168e20c2021-12-13 14:39:53 -0800373
374 // Check if this function exists by looking for a device ID
Ed Tanousb9d36b42022-02-26 21:42:46 -0800375 std::string functionName = "Function" + function;
376 std::string devIDProperty = functionName + "DeviceId";
377
378 const std::string* devIdProperty = nullptr;
379 for (const auto& property : pcieDevProperties)
380 {
381 if (property.first == devIDProperty)
382 {
383 devIdProperty =
384 std::get_if<std::string>(&property.second);
385 continue;
386 }
387 }
388 if (devIdProperty == nullptr || !devIdProperty->empty())
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800389 {
Ed Tanous168e20c2021-12-13 14:39:53 -0800390 messages::resourceNotFound(asyncResp->res,
391 "PCIeFunction", function);
392 return;
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800393 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800394
Ed Tanous168e20c2021-12-13 14:39:53 -0800395 asyncResp->res.jsonValue = {
396 {"@odata.type", "#PCIeFunction.v1_2_0.PCIeFunction"},
397 {"@odata.id",
398 "/redfish/v1/Systems/system/PCIeDevices/" + device +
399 "/PCIeFunctions/" + function},
400 {"Name", "PCIe Function"},
401 {"Id", function},
402 {"FunctionId", std::stoi(function)},
403 {"Links",
404 {{"PCIeDevice",
405 {{"@odata.id",
406 "/redfish/v1/Systems/system/PCIeDevices/" +
407 device}}}}}};
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700408
Ed Tanousb9d36b42022-02-26 21:42:46 -0800409 for (const auto& property : pcieDevProperties)
Ed Tanous168e20c2021-12-13 14:39:53 -0800410 {
Ed Tanousb9d36b42022-02-26 21:42:46 -0800411 const std::string* strProperty =
412 std::get_if<std::string>(&property.second);
413 if (property.first == functionName + "DeviceId")
414 {
415 asyncResp->res.jsonValue["DeviceId"] = *strProperty;
416 }
417 if (property.first == functionName + "VendorId")
418 {
419 asyncResp->res.jsonValue["VendorId"] = *strProperty;
420 }
421 if (property.first == functionName + "FunctionType")
422 {
423 asyncResp->res.jsonValue["FunctionType"] =
424 *strProperty;
425 }
426 if (property.first == functionName + "DeviceClass")
427 {
428 asyncResp->res.jsonValue["DeviceClass"] =
429 *strProperty;
430 }
431 if (property.first == functionName + "ClassCode")
432 {
433 asyncResp->res.jsonValue["ClassCode"] =
434 *strProperty;
435 }
436 if (property.first == functionName + "RevisionId")
437 {
438 asyncResp->res.jsonValue["RevisionId"] =
439 *strProperty;
440 }
441 if (property.first == functionName + "SubsystemId")
442 {
443 asyncResp->res.jsonValue["SubsystemId"] =
444 *strProperty;
445 }
446 if (property.first ==
447 functionName + "SubsystemVendorId")
448 {
449 asyncResp->res.jsonValue["SubsystemVendorId"] =
450 *strProperty;
451 }
Ed Tanous168e20c2021-12-13 14:39:53 -0800452 }
453 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700454 std::string escapedPath = std::string(pciePath) + "/" + device;
455 dbus::utility::escapePathForDbus(escapedPath);
456 crow::connections::systemBus->async_method_call(
457 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
458 "org.freedesktop.DBus.Properties", "GetAll",
459 pcieDeviceInterface);
460 });
461}
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800462
463} // namespace redfish