blob: 47c5c91bac84dcd5f94851ca204c10a83115ce91 [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 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -070085 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/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,
89 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +000090 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -070091 {
92 return;
93 }
Ed Tanous14766872022-03-15 10:44:42 -070094
Ed Tanous002d39b2022-05-31 08:59:27 -070095 asyncResp->res.jsonValue["@odata.type"] =
96 "#PCIeDeviceCollection.PCIeDeviceCollection";
97 asyncResp->res.jsonValue["@odata.id"] =
98 "/redfish/v1/Systems/system/PCIeDevices";
99 asyncResp->res.jsonValue["Name"] = "PCIe Device Collection";
100 asyncResp->res.jsonValue["Description"] = "Collection of PCIe Devices";
101 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
102 asyncResp->res.jsonValue["Members@odata.count"] = 0;
103 getPCIeDeviceList(asyncResp, "Members");
104 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700105}
106
Spencer Ku62cd45a2021-11-22 16:41:25 +0800107inline std::optional<std::string>
108 redfishPcieGenerationFromDbus(const std::string& generationInUse)
109{
110 if (generationInUse ==
111 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen1")
112 {
113 return "Gen1";
114 }
115 if (generationInUse ==
116 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen2")
117 {
118 return "Gen2";
119 }
120 if (generationInUse ==
121 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen3")
122 {
123 return "Gen3";
124 }
125 if (generationInUse ==
126 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen4")
127 {
128 return "Gen4";
129 }
130 if (generationInUse ==
131 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Gen5")
132 {
133 return "Gen5";
134 }
Ed Tanouse825cbc2022-06-17 11:39:22 -0700135 if (generationInUse.empty() ||
136 generationInUse ==
137 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Unknown")
Spencer Ku62cd45a2021-11-22 16:41:25 +0800138 {
139 return "";
140 }
141
142 // The value is not unknown or Gen1-5, need return an internal error.
143 return std::nullopt;
144}
145
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700146inline void requestRoutesSystemPCIeDevice(App& app)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800147{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700148 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/PCIeDevices/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700149 .privileges(redfish::privileges::getPCIeDevice)
Ed Tanous002d39b2022-05-31 08:59:27 -0700150 .methods(boost::beast::http::verb::get)(
151 [&app](const crow::Request& req,
152 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
153 const std::string& device) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000154 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700155 {
156 return;
157 }
158 auto getPCIeDeviceCallback =
159 [asyncResp, device](
160 const boost::system::error_code ec,
161 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
162 if (ec)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700163 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700164 BMCWEB_LOG_DEBUG
165 << "failed to get PCIe Device properties ec: " << ec.value()
166 << ": " << ec.message();
167 if (ec.value() ==
168 boost::system::linux_error::bad_request_descriptor)
169 {
170 messages::resourceNotFound(asyncResp->res, "PCIeDevice",
171 device);
172 }
173 else
174 {
175 messages::internalError(asyncResp->res);
176 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700177 return;
178 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700179
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200180 const std::string* manufacturer = nullptr;
181 const std::string* deviceType = nullptr;
182 const std::string* generationInUse = nullptr;
183
184 const bool success = sdbusplus::unpackPropertiesNoThrow(
185 dbus_utils::UnpackErrorPrinter(), pcieDevProperties,
186 "Manufacturer", manufacturer, "DeviceType", deviceType,
187 "GenerationInUse", generationInUse);
188
189 if (!success)
190 {
191 messages::internalError(asyncResp->res);
192 return;
193 }
194
195 if (generationInUse != nullptr)
196 {
197 std::optional<std::string> redfishGenerationInUse =
198 redfishPcieGenerationFromDbus(*generationInUse);
199 if (!redfishGenerationInUse)
200 {
201 messages::internalError(asyncResp->res);
202 return;
203 }
204 if (redfishGenerationInUse->empty())
205 {
206 // unknown, no need to handle
207 return;
208 }
209 asyncResp->res.jsonValue["PCIeInterface"]["PCIeType"] =
210 *redfishGenerationInUse;
211 }
212
213 if (manufacturer != nullptr)
214 {
215 asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
216 }
217
218 if (deviceType != nullptr)
219 {
220 asyncResp->res.jsonValue["DeviceType"] = *deviceType;
221 }
222
Ed Tanous002d39b2022-05-31 08:59:27 -0700223 asyncResp->res.jsonValue["@odata.type"] =
224 "#PCIeDevice.v1_4_0.PCIeDevice";
225 asyncResp->res.jsonValue["@odata.id"] =
226 "/redfish/v1/Systems/system/PCIeDevices/" + device;
227 asyncResp->res.jsonValue["Name"] = "PCIe Device";
228 asyncResp->res.jsonValue["Id"] = device;
229
230 asyncResp->res.jsonValue["PCIeFunctions"]["@odata.id"] =
231 "/redfish/v1/Systems/system/PCIeDevices/" + device +
232 "/PCIeFunctions";
Ed Tanous002d39b2022-05-31 08:59:27 -0700233 };
234 std::string escapedPath = std::string(pciePath) + "/" + device;
235 dbus::utility::escapePathForDbus(escapedPath);
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200236 sdbusplus::asio::getAllProperties(
237 *crow::connections::systemBus, pcieService, escapedPath,
238 pcieDeviceInterface, std::move(getPCIeDeviceCallback));
Ed Tanous45ca1b82022-03-25 13:07:27 -0700239 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700240}
241
242inline void requestRoutesSystemPCIeFunctionCollection(App& app)
243{
244 /**
245 * Functions triggers appropriate requests on DBus
246 */
247 BMCWEB_ROUTE(app,
248 "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/")
Ed Tanoused398212021-06-09 17:05:54 -0700249 .privileges(redfish::privileges::getPCIeFunctionCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -0700250 .methods(boost::beast::http::verb::get)(
251 [&app](const crow::Request& req,
252 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
253 const std::string& device) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000254 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700255 {
256 return;
257 }
258
259 asyncResp->res.jsonValue["@odata.type"] =
260 "#PCIeFunctionCollection.PCIeFunctionCollection";
261 asyncResp->res.jsonValue["@odata.id"] =
262 "/redfish/v1/Systems/system/PCIeDevices/" + device +
263 "/PCIeFunctions";
264 asyncResp->res.jsonValue["Name"] = "PCIe Function Collection";
265 asyncResp->res.jsonValue["Description"] =
266 "Collection of PCIe Functions for PCIe Device " + device;
267
268 auto getPCIeDeviceCallback =
269 [asyncResp, device](
270 const boost::system::error_code ec,
271 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
272 if (ec)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700273 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700274 BMCWEB_LOG_DEBUG
275 << "failed to get PCIe Device properties ec: " << ec.value()
276 << ": " << ec.message();
277 if (ec.value() ==
278 boost::system::linux_error::bad_request_descriptor)
279 {
280 messages::resourceNotFound(asyncResp->res, "PCIeDevice",
281 device);
282 }
283 else
284 {
285 messages::internalError(asyncResp->res);
286 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700287 return;
288 }
Ed Tanous14766872022-03-15 10:44:42 -0700289
Ed Tanous002d39b2022-05-31 08:59:27 -0700290 nlohmann::json& pcieFunctionList =
291 asyncResp->res.jsonValue["Members"];
292 pcieFunctionList = nlohmann::json::array();
293 static constexpr const int maxPciFunctionNum = 8;
294 for (int functionNum = 0; functionNum < maxPciFunctionNum;
295 functionNum++)
296 {
297 // Check if this function exists by looking for a
298 // device ID
299 std::string devIDProperty =
300 "Function" + std::to_string(functionNum) + "DeviceId";
301 const std::string* property = nullptr;
302 for (const auto& propEntry : pcieDevProperties)
303 {
304 if (propEntry.first == devIDProperty)
Ed Tanous45ca1b82022-03-25 13:07:27 -0700305 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700306 property = std::get_if<std::string>(&propEntry.second);
Ed Tanous45ca1b82022-03-25 13:07:27 -0700307 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700308 }
309 if (property == nullptr || !property->empty())
310 {
311 return;
312 }
313 nlohmann::json::object_t pcieFunction;
314 pcieFunction["@odata.id"] =
315 "/redfish/v1/Systems/system/PCIeDevices/" + device +
316 "/PCIeFunctions/" + std::to_string(functionNum);
317 pcieFunctionList.push_back(std::move(pcieFunction));
318 }
319 asyncResp->res.jsonValue["Members@odata.count"] =
320 pcieFunctionList.size();
321 };
322 std::string escapedPath = std::string(pciePath) + "/" + device;
323 dbus::utility::escapePathForDbus(escapedPath);
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200324 sdbusplus::asio::getAllProperties(
325 *crow::connections::systemBus, pcieService, escapedPath,
326 pcieDeviceInterface, std::move(getPCIeDeviceCallback));
Ed Tanous45ca1b82022-03-25 13:07:27 -0700327 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700328}
329
330inline void requestRoutesSystemPCIeFunction(App& app)
331{
332 BMCWEB_ROUTE(
333 app,
334 "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700335 .privileges(redfish::privileges::getPCIeFunction)
Ed Tanous002d39b2022-05-31 08:59:27 -0700336 .methods(boost::beast::http::verb::get)(
337 [&app](const crow::Request& req,
338 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
339 const std::string& device, const std::string& function) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000340 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700341 {
342 return;
343 }
344 auto getPCIeDeviceCallback =
345 [asyncResp, device, function](
346 const boost::system::error_code ec,
347 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
348 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -0700349 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700350 BMCWEB_LOG_DEBUG
351 << "failed to get PCIe Device properties ec: " << ec.value()
352 << ": " << ec.message();
353 if (ec.value() ==
354 boost::system::linux_error::bad_request_descriptor)
355 {
356 messages::resourceNotFound(asyncResp->res, "PCIeDevice",
357 device);
358 }
359 else
360 {
361 messages::internalError(asyncResp->res);
362 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700363 return;
364 }
Ed Tanous168e20c2021-12-13 14:39:53 -0800365
Ed Tanous002d39b2022-05-31 08:59:27 -0700366 // Check if this function exists by looking for a device
367 // ID
368 std::string functionName = "Function" + function;
369 std::string devIDProperty = functionName + "DeviceId";
Ed Tanousb9d36b42022-02-26 21:42:46 -0800370
Ed Tanous002d39b2022-05-31 08:59:27 -0700371 const std::string* devIdProperty = nullptr;
372 for (const auto& property : pcieDevProperties)
373 {
374 if (property.first == devIDProperty)
375 {
376 devIdProperty = std::get_if<std::string>(&property.second);
377 continue;
378 }
379 }
380 if (devIdProperty == nullptr || !devIdProperty->empty())
381 {
382 messages::resourceNotFound(asyncResp->res, "PCIeFunction",
383 function);
384 return;
385 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800386
Ed Tanous002d39b2022-05-31 08:59:27 -0700387 asyncResp->res.jsonValue["@odata.type"] =
388 "#PCIeFunction.v1_2_0.PCIeFunction";
389 asyncResp->res.jsonValue["@odata.id"] =
390 "/redfish/v1/Systems/system/PCIeDevices/" + device +
391 "/PCIeFunctions/" + function;
392 asyncResp->res.jsonValue["Name"] = "PCIe Function";
393 asyncResp->res.jsonValue["Id"] = function;
394 asyncResp->res.jsonValue["FunctionId"] = std::stoi(function);
395 asyncResp->res.jsonValue["Links"]["PCIeDevice"]["@odata.id"] =
396 "/redfish/v1/Systems/system/PCIeDevices/" + device;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700397
Ed Tanous002d39b2022-05-31 08:59:27 -0700398 for (const auto& property : pcieDevProperties)
399 {
400 const std::string* strProperty =
401 std::get_if<std::string>(&property.second);
402 if (property.first == functionName + "DeviceId")
403 {
404 asyncResp->res.jsonValue["DeviceId"] = *strProperty;
405 }
406 if (property.first == functionName + "VendorId")
407 {
408 asyncResp->res.jsonValue["VendorId"] = *strProperty;
409 }
410 if (property.first == functionName + "FunctionType")
411 {
412 asyncResp->res.jsonValue["FunctionType"] = *strProperty;
413 }
414 if (property.first == functionName + "DeviceClass")
415 {
416 asyncResp->res.jsonValue["DeviceClass"] = *strProperty;
417 }
418 if (property.first == functionName + "ClassCode")
419 {
420 asyncResp->res.jsonValue["ClassCode"] = *strProperty;
421 }
422 if (property.first == functionName + "RevisionId")
423 {
424 asyncResp->res.jsonValue["RevisionId"] = *strProperty;
425 }
426 if (property.first == functionName + "SubsystemId")
427 {
428 asyncResp->res.jsonValue["SubsystemId"] = *strProperty;
429 }
430 if (property.first == functionName + "SubsystemVendorId")
431 {
432 asyncResp->res.jsonValue["SubsystemVendorId"] =
433 *strProperty;
434 }
435 }
436 };
437 std::string escapedPath = std::string(pciePath) + "/" + device;
438 dbus::utility::escapePathForDbus(escapedPath);
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200439 sdbusplus::asio::getAllProperties(
440 *crow::connections::systemBus, pcieService, escapedPath,
441 pcieDeviceInterface, std::move(getPCIeDeviceCallback));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700442 });
443}
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800444
445} // namespace redfish