blob: b4d64332b50da7097c5fded6f237ee5bba43eab1 [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 }
Ed Tanouse825cbc2022-06-17 11:39:22 -0700132 if (generationInUse.empty() ||
133 generationInUse ==
134 "xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations.Unknown")
Spencer Ku62cd45a2021-11-22 16:41:25 +0800135 {
136 return "";
137 }
138
139 // The value is not unknown or Gen1-5, need return an internal error.
140 return std::nullopt;
141}
142
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700143inline void requestRoutesSystemPCIeDevice(App& app)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800144{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700145 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/PCIeDevices/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700146 .privileges(redfish::privileges::getPCIeDevice)
Ed Tanous002d39b2022-05-31 08:59:27 -0700147 .methods(boost::beast::http::verb::get)(
148 [&app](const crow::Request& req,
149 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
150 const std::string& device) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000151 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700152 {
153 return;
154 }
155 auto getPCIeDeviceCallback =
156 [asyncResp, device](
157 const boost::system::error_code ec,
158 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
159 if (ec)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700160 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700161 BMCWEB_LOG_DEBUG
162 << "failed to get PCIe Device properties ec: " << ec.value()
163 << ": " << ec.message();
164 if (ec.value() ==
165 boost::system::linux_error::bad_request_descriptor)
166 {
167 messages::resourceNotFound(asyncResp->res, "PCIeDevice",
168 device);
169 }
170 else
171 {
172 messages::internalError(asyncResp->res);
173 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700174 return;
175 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700176
177 asyncResp->res.jsonValue["@odata.type"] =
178 "#PCIeDevice.v1_4_0.PCIeDevice";
179 asyncResp->res.jsonValue["@odata.id"] =
180 "/redfish/v1/Systems/system/PCIeDevices/" + device;
181 asyncResp->res.jsonValue["Name"] = "PCIe Device";
182 asyncResp->res.jsonValue["Id"] = device;
183
184 asyncResp->res.jsonValue["PCIeFunctions"]["@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 Tanous45ca1b82022-03-25 13:07:27 -0700194 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700195 messages::internalError(asyncResp->res);
Ed Tanous45ca1b82022-03-25 13:07:27 -0700196 return;
197 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700198 asyncResp->res.jsonValue["Manufacturer"] = *propertyString;
199 }
200 if (property.first == "DeviceType")
201 {
202 if (propertyString == nullptr)
Ed Tanous45ca1b82022-03-25 13:07:27 -0700203 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700204 messages::internalError(asyncResp->res);
205 return;
Ed Tanous45ca1b82022-03-25 13:07:27 -0700206 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700207 asyncResp->res.jsonValue["DeviceType"] = *propertyString;
208 }
209 if (property.first == "GenerationInUse")
210 {
211 if (propertyString == nullptr)
212 {
213 messages::internalError(asyncResp->res);
214 return;
215 }
216 std::optional<std::string> generationInUse =
217 redfishPcieGenerationFromDbus(*propertyString);
218 if (!generationInUse)
219 {
220 messages::internalError(asyncResp->res);
221 return;
222 }
223 if (generationInUse->empty())
224 {
225 // unknown, no need to handle
226 return;
227 }
228 asyncResp->res.jsonValue["PCIeInterface"]["PCIeType"] =
229 *generationInUse;
230 }
231 }
232 };
233 std::string escapedPath = std::string(pciePath) + "/" + device;
234 dbus::utility::escapePathForDbus(escapedPath);
235 crow::connections::systemBus->async_method_call(
236 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
237 "org.freedesktop.DBus.Properties", "GetAll", pcieDeviceInterface);
Ed Tanous45ca1b82022-03-25 13:07:27 -0700238 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700239}
240
241inline void requestRoutesSystemPCIeFunctionCollection(App& app)
242{
243 /**
244 * Functions triggers appropriate requests on DBus
245 */
246 BMCWEB_ROUTE(app,
247 "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/")
Ed Tanoused398212021-06-09 17:05:54 -0700248 .privileges(redfish::privileges::getPCIeFunctionCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -0700249 .methods(boost::beast::http::verb::get)(
250 [&app](const crow::Request& req,
251 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
252 const std::string& device) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000253 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700254 {
255 return;
256 }
257
258 asyncResp->res.jsonValue["@odata.type"] =
259 "#PCIeFunctionCollection.PCIeFunctionCollection";
260 asyncResp->res.jsonValue["@odata.id"] =
261 "/redfish/v1/Systems/system/PCIeDevices/" + device +
262 "/PCIeFunctions";
263 asyncResp->res.jsonValue["Name"] = "PCIe Function Collection";
264 asyncResp->res.jsonValue["Description"] =
265 "Collection of PCIe Functions for PCIe Device " + device;
266
267 auto getPCIeDeviceCallback =
268 [asyncResp, device](
269 const boost::system::error_code ec,
270 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
271 if (ec)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700272 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700273 BMCWEB_LOG_DEBUG
274 << "failed to get PCIe Device properties ec: " << ec.value()
275 << ": " << ec.message();
276 if (ec.value() ==
277 boost::system::linux_error::bad_request_descriptor)
278 {
279 messages::resourceNotFound(asyncResp->res, "PCIeDevice",
280 device);
281 }
282 else
283 {
284 messages::internalError(asyncResp->res);
285 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700286 return;
287 }
Ed Tanous14766872022-03-15 10:44:42 -0700288
Ed Tanous002d39b2022-05-31 08:59:27 -0700289 nlohmann::json& pcieFunctionList =
290 asyncResp->res.jsonValue["Members"];
291 pcieFunctionList = nlohmann::json::array();
292 static constexpr const int maxPciFunctionNum = 8;
293 for (int functionNum = 0; functionNum < maxPciFunctionNum;
294 functionNum++)
295 {
296 // Check if this function exists by looking for a
297 // device ID
298 std::string devIDProperty =
299 "Function" + std::to_string(functionNum) + "DeviceId";
300 const std::string* property = nullptr;
301 for (const auto& propEntry : pcieDevProperties)
302 {
303 if (propEntry.first == devIDProperty)
Ed Tanous45ca1b82022-03-25 13:07:27 -0700304 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700305 property = std::get_if<std::string>(&propEntry.second);
Ed Tanous45ca1b82022-03-25 13:07:27 -0700306 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700307 }
308 if (property == nullptr || !property->empty())
309 {
310 return;
311 }
312 nlohmann::json::object_t pcieFunction;
313 pcieFunction["@odata.id"] =
314 "/redfish/v1/Systems/system/PCIeDevices/" + device +
315 "/PCIeFunctions/" + std::to_string(functionNum);
316 pcieFunctionList.push_back(std::move(pcieFunction));
317 }
318 asyncResp->res.jsonValue["Members@odata.count"] =
319 pcieFunctionList.size();
320 };
321 std::string escapedPath = std::string(pciePath) + "/" + device;
322 dbus::utility::escapePathForDbus(escapedPath);
323 crow::connections::systemBus->async_method_call(
324 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
325 "org.freedesktop.DBus.Properties", "GetAll", pcieDeviceInterface);
Ed Tanous45ca1b82022-03-25 13:07:27 -0700326 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700327}
328
329inline void requestRoutesSystemPCIeFunction(App& app)
330{
331 BMCWEB_ROUTE(
332 app,
333 "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700334 .privileges(redfish::privileges::getPCIeFunction)
Ed Tanous002d39b2022-05-31 08:59:27 -0700335 .methods(boost::beast::http::verb::get)(
336 [&app](const crow::Request& req,
337 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
338 const std::string& device, const std::string& function) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000339 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700340 {
341 return;
342 }
343 auto getPCIeDeviceCallback =
344 [asyncResp, device, function](
345 const boost::system::error_code ec,
346 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
347 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -0700348 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700349 BMCWEB_LOG_DEBUG
350 << "failed to get PCIe Device properties ec: " << ec.value()
351 << ": " << ec.message();
352 if (ec.value() ==
353 boost::system::linux_error::bad_request_descriptor)
354 {
355 messages::resourceNotFound(asyncResp->res, "PCIeDevice",
356 device);
357 }
358 else
359 {
360 messages::internalError(asyncResp->res);
361 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700362 return;
363 }
Ed Tanous168e20c2021-12-13 14:39:53 -0800364
Ed Tanous002d39b2022-05-31 08:59:27 -0700365 // Check if this function exists by looking for a device
366 // ID
367 std::string functionName = "Function" + function;
368 std::string devIDProperty = functionName + "DeviceId";
Ed Tanousb9d36b42022-02-26 21:42:46 -0800369
Ed Tanous002d39b2022-05-31 08:59:27 -0700370 const std::string* devIdProperty = nullptr;
371 for (const auto& property : pcieDevProperties)
372 {
373 if (property.first == devIDProperty)
374 {
375 devIdProperty = std::get_if<std::string>(&property.second);
376 continue;
377 }
378 }
379 if (devIdProperty == nullptr || !devIdProperty->empty())
380 {
381 messages::resourceNotFound(asyncResp->res, "PCIeFunction",
382 function);
383 return;
384 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800385
Ed Tanous002d39b2022-05-31 08:59:27 -0700386 asyncResp->res.jsonValue["@odata.type"] =
387 "#PCIeFunction.v1_2_0.PCIeFunction";
388 asyncResp->res.jsonValue["@odata.id"] =
389 "/redfish/v1/Systems/system/PCIeDevices/" + device +
390 "/PCIeFunctions/" + function;
391 asyncResp->res.jsonValue["Name"] = "PCIe Function";
392 asyncResp->res.jsonValue["Id"] = function;
393 asyncResp->res.jsonValue["FunctionId"] = std::stoi(function);
394 asyncResp->res.jsonValue["Links"]["PCIeDevice"]["@odata.id"] =
395 "/redfish/v1/Systems/system/PCIeDevices/" + device;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700396
Ed Tanous002d39b2022-05-31 08:59:27 -0700397 for (const auto& property : pcieDevProperties)
398 {
399 const std::string* strProperty =
400 std::get_if<std::string>(&property.second);
401 if (property.first == functionName + "DeviceId")
402 {
403 asyncResp->res.jsonValue["DeviceId"] = *strProperty;
404 }
405 if (property.first == functionName + "VendorId")
406 {
407 asyncResp->res.jsonValue["VendorId"] = *strProperty;
408 }
409 if (property.first == functionName + "FunctionType")
410 {
411 asyncResp->res.jsonValue["FunctionType"] = *strProperty;
412 }
413 if (property.first == functionName + "DeviceClass")
414 {
415 asyncResp->res.jsonValue["DeviceClass"] = *strProperty;
416 }
417 if (property.first == functionName + "ClassCode")
418 {
419 asyncResp->res.jsonValue["ClassCode"] = *strProperty;
420 }
421 if (property.first == functionName + "RevisionId")
422 {
423 asyncResp->res.jsonValue["RevisionId"] = *strProperty;
424 }
425 if (property.first == functionName + "SubsystemId")
426 {
427 asyncResp->res.jsonValue["SubsystemId"] = *strProperty;
428 }
429 if (property.first == functionName + "SubsystemVendorId")
430 {
431 asyncResp->res.jsonValue["SubsystemVendorId"] =
432 *strProperty;
433 }
434 }
435 };
436 std::string escapedPath = std::string(pciePath) + "/" + device;
437 dbus::utility::escapePathForDbus(escapedPath);
438 crow::connections::systemBus->async_method_call(
439 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
440 "org.freedesktop.DBus.Properties", "GetAll", pcieDeviceInterface);
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700441 });
442}
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800443
444} // namespace redfish