blob: fdc2af24d4c785e96fcb6d555f14acf5f9689b52 [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 == "DeviceType")
212 {
213 if (propertyString == nullptr)
214 {
215 messages::internalError(asyncResp->res);
216 return;
217 }
218 asyncResp->res.jsonValue["DeviceType"] =
219 *propertyString;
220 }
221 if (property.first == "GenerationInUse")
222 {
223 if (propertyString == nullptr)
224 {
225 messages::internalError(asyncResp->res);
226 return;
227 }
228 std::optional<std::string> generationInUse =
229 redfishPcieGenerationFromDbus(*propertyString);
230 if (!generationInUse)
231 {
232 messages::internalError(asyncResp->res);
233 return;
234 }
235 if (generationInUse->empty())
236 {
237 // unknown, no need to handle
238 return;
239 }
240 asyncResp->res
241 .jsonValue["PCIeInterface"]["PCIeType"] =
242 *generationInUse;
243 }
244 }
245 };
246 std::string escapedPath = std::string(pciePath) + "/" + device;
247 dbus::utility::escapePathForDbus(escapedPath);
248 crow::connections::systemBus->async_method_call(
249 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
250 "org.freedesktop.DBus.Properties", "GetAll",
251 pcieDeviceInterface);
252 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700253}
254
255inline void requestRoutesSystemPCIeFunctionCollection(App& app)
256{
257 /**
258 * Functions triggers appropriate requests on DBus
259 */
260 BMCWEB_ROUTE(app,
261 "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/")
Ed Tanoused398212021-06-09 17:05:54 -0700262 .privileges(redfish::privileges::getPCIeFunctionCollection)
Ed Tanous45ca1b82022-03-25 13:07:27 -0700263 .methods(
264 boost::beast::http::verb::
265 get)([&app](const crow::Request& req,
266 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
267 const std::string& device) {
268 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700269 {
Ed Tanous45ca1b82022-03-25 13:07:27 -0700270 return;
271 }
272 asyncResp->res.jsonValue = {
273 {"@odata.type",
274 "#PCIeFunctionCollection.PCIeFunctionCollection"},
275 {"@odata.id", "/redfish/v1/Systems/system/PCIeDevices/" +
276 device + "/PCIeFunctions"},
277 {"Name", "PCIe Function Collection"},
278 {"Description",
279 "Collection of PCIe Functions for PCIe Device " + device}};
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700280
Ed Tanous45ca1b82022-03-25 13:07:27 -0700281 auto getPCIeDeviceCallback =
282 [asyncResp, device](
283 const boost::system::error_code ec,
284 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
285 if (ec)
286 {
287 BMCWEB_LOG_DEBUG
288 << "failed to get PCIe Device properties ec: "
289 << ec.value() << ": " << ec.message();
290 if (ec.value() ==
291 boost::system::linux_error::bad_request_descriptor)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700292 {
Ed Tanous45ca1b82022-03-25 13:07:27 -0700293 messages::resourceNotFound(asyncResp->res,
294 "PCIeDevice", device);
295 }
296 else
297 {
298 messages::internalError(asyncResp->res);
299 }
300 return;
301 }
302
303 nlohmann::json& pcieFunctionList =
304 asyncResp->res.jsonValue["Members"];
305 pcieFunctionList = nlohmann::json::array();
306 static constexpr const int maxPciFunctionNum = 8;
307 for (int functionNum = 0; functionNum < maxPciFunctionNum;
308 functionNum++)
309 {
310 // Check if this function exists by looking for a
311 // device ID
312 std::string devIDProperty =
313 "Function" + std::to_string(functionNum) +
314 "DeviceId";
315 const std::string* property = nullptr;
316 for (const auto& propEntry : pcieDevProperties)
317 {
318 if (propEntry.first == devIDProperty)
Ed Tanousb9d36b42022-02-26 21:42:46 -0800319 {
Ed Tanous45ca1b82022-03-25 13:07:27 -0700320 property =
321 std::get_if<std::string>(&propEntry.second);
Ed Tanousb9d36b42022-02-26 21:42:46 -0800322 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700323 }
324 if (property == nullptr || !property->empty())
325 {
Ed Tanousb9d36b42022-02-26 21:42:46 -0800326 return;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700327 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700328 pcieFunctionList.push_back(
329 {{"@odata.id",
330 "/redfish/v1/Systems/system/PCIeDevices/" +
331 device + "/PCIeFunctions/" +
332 std::to_string(functionNum)}});
333 }
334 asyncResp->res.jsonValue["Members@odata.count"] =
335 pcieFunctionList.size();
336 };
337 std::string escapedPath = std::string(pciePath) + "/" + device;
338 dbus::utility::escapePathForDbus(escapedPath);
339 crow::connections::systemBus->async_method_call(
340 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
341 "org.freedesktop.DBus.Properties", "GetAll",
342 pcieDeviceInterface);
343 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700344}
345
346inline void requestRoutesSystemPCIeFunction(App& app)
347{
348 BMCWEB_ROUTE(
349 app,
350 "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700351 .privileges(redfish::privileges::getPCIeFunction)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700352 .methods(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700353 boost::beast::http::verb::
354 get)([&app](const crow::Request& req,
355 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
356 const std::string& device,
357 const std::string& function) {
358 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
359 {
360 return;
361 }
Ed Tanous168e20c2021-12-13 14:39:53 -0800362 auto getPCIeDeviceCallback =
363 [asyncResp, device, function](
364 const boost::system::error_code ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800365 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
Ed Tanous168e20c2021-12-13 14:39:53 -0800366 if (ec)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800367 {
Ed Tanous168e20c2021-12-13 14:39:53 -0800368 BMCWEB_LOG_DEBUG
369 << "failed to get PCIe Device properties ec: "
370 << ec.value() << ": " << ec.message();
371 if (ec.value() ==
372 boost::system::linux_error::bad_request_descriptor)
373 {
374 messages::resourceNotFound(asyncResp->res,
375 "PCIeDevice", device);
376 }
377 else
378 {
379 messages::internalError(asyncResp->res);
380 }
381 return;
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800382 }
Ed Tanous168e20c2021-12-13 14:39:53 -0800383
384 // Check if this function exists by looking for a device ID
Ed Tanousb9d36b42022-02-26 21:42:46 -0800385 std::string functionName = "Function" + function;
386 std::string devIDProperty = functionName + "DeviceId";
387
388 const std::string* devIdProperty = nullptr;
389 for (const auto& property : pcieDevProperties)
390 {
391 if (property.first == devIDProperty)
392 {
393 devIdProperty =
394 std::get_if<std::string>(&property.second);
395 continue;
396 }
397 }
398 if (devIdProperty == nullptr || !devIdProperty->empty())
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800399 {
Ed Tanous168e20c2021-12-13 14:39:53 -0800400 messages::resourceNotFound(asyncResp->res,
401 "PCIeFunction", function);
402 return;
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800403 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800404
Ed Tanous168e20c2021-12-13 14:39:53 -0800405 asyncResp->res.jsonValue = {
406 {"@odata.type", "#PCIeFunction.v1_2_0.PCIeFunction"},
407 {"@odata.id",
408 "/redfish/v1/Systems/system/PCIeDevices/" + device +
409 "/PCIeFunctions/" + function},
410 {"Name", "PCIe Function"},
411 {"Id", function},
412 {"FunctionId", std::stoi(function)},
413 {"Links",
414 {{"PCIeDevice",
415 {{"@odata.id",
416 "/redfish/v1/Systems/system/PCIeDevices/" +
417 device}}}}}};
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700418
Ed Tanousb9d36b42022-02-26 21:42:46 -0800419 for (const auto& property : pcieDevProperties)
Ed Tanous168e20c2021-12-13 14:39:53 -0800420 {
Ed Tanousb9d36b42022-02-26 21:42:46 -0800421 const std::string* strProperty =
422 std::get_if<std::string>(&property.second);
423 if (property.first == functionName + "DeviceId")
424 {
425 asyncResp->res.jsonValue["DeviceId"] = *strProperty;
426 }
427 if (property.first == functionName + "VendorId")
428 {
429 asyncResp->res.jsonValue["VendorId"] = *strProperty;
430 }
431 if (property.first == functionName + "FunctionType")
432 {
433 asyncResp->res.jsonValue["FunctionType"] =
434 *strProperty;
435 }
436 if (property.first == functionName + "DeviceClass")
437 {
438 asyncResp->res.jsonValue["DeviceClass"] =
439 *strProperty;
440 }
441 if (property.first == functionName + "ClassCode")
442 {
443 asyncResp->res.jsonValue["ClassCode"] =
444 *strProperty;
445 }
446 if (property.first == functionName + "RevisionId")
447 {
448 asyncResp->res.jsonValue["RevisionId"] =
449 *strProperty;
450 }
451 if (property.first == functionName + "SubsystemId")
452 {
453 asyncResp->res.jsonValue["SubsystemId"] =
454 *strProperty;
455 }
456 if (property.first ==
457 functionName + "SubsystemVendorId")
458 {
459 asyncResp->res.jsonValue["SubsystemVendorId"] =
460 *strProperty;
461 }
Ed Tanous168e20c2021-12-13 14:39:53 -0800462 }
463 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700464 std::string escapedPath = std::string(pciePath) + "/" + device;
465 dbus::utility::escapePathForDbus(escapedPath);
466 crow::connections::systemBus->async_method_call(
467 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
468 "org.freedesktop.DBus.Properties", "GetAll",
469 pcieDeviceInterface);
470 });
471}
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800472
473} // namespace redfish