blob: 195ec8727a7a6e9b5f7bc71dd48616d4c63d74f1 [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
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080019#include "app.hpp"
George Liu7a1dbc42022-12-07 16:03:22 +080020#include "dbus_utility.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080021#include "query.hpp"
22#include "registries/privilege_registry.hpp"
Lakshmi Yadlapatib38fa2a2023-03-10 16:19:46 -060023#include "utils/collection.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080024#include "utils/dbus_utils.hpp"
Lakshmi Yadlapatic49c3292023-04-19 16:42:35 -050025#include "utils/pcie_util.hpp"
Ed Tanous0ec8b832022-03-14 14:56:47 -070026
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080027#include <boost/system/linux_error.hpp>
Ed Tanousef4c65b2023-04-24 15:28:50 -070028#include <boost/url/format.hpp>
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +020029#include <sdbusplus/asio/property.hpp>
30#include <sdbusplus/unpack_properties.hpp>
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080031
32namespace redfish
33{
34
Patrick Williams89492a12023-05-10 07:51:34 -050035static constexpr const char* inventoryPath = "/xyz/openbmc_project/inventory";
Lakshmi Yadlapati94c3a102023-04-05 18:11:22 -050036static constexpr std::array<std::string_view, 1> pcieDeviceInterface = {
37 "xyz.openbmc_project.Inventory.Item.PCIeDevice"};
Lakshmi Yadlapatia5409992023-04-20 16:53:59 -050038static constexpr std::array<std::string_view, 1> pcieSlotInterface = {
39 "xyz.openbmc_project.Inventory.Item.PCIeSlot"};
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080040
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -060041static inline void handlePCIeDevicePath(
42 const std::string& pcieDeviceId,
Ed Tanousac106bf2023-06-07 09:24:59 -070043 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -060044 const dbus::utility::MapperGetSubTreePathsResponse& pcieDevicePaths,
45 const std::function<void(const std::string& pcieDevicePath,
46 const std::string& service)>& callback)
47
48{
49 for (const std::string& pcieDevicePath : pcieDevicePaths)
50 {
51 std::string pciecDeviceName =
52 sdbusplus::message::object_path(pcieDevicePath).filename();
53 if (pciecDeviceName.empty() || pciecDeviceName != pcieDeviceId)
54 {
55 continue;
56 }
57
58 dbus::utility::getDbusObject(
59 pcieDevicePath, {},
Ed Tanousac106bf2023-06-07 09:24:59 -070060 [pcieDevicePath, asyncResp,
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -060061 callback](const boost::system::error_code& ec,
62 const dbus::utility::MapperGetObject& object) {
63 if (ec || object.empty())
64 {
65 BMCWEB_LOG_ERROR << "DBUS response error " << ec;
Ed Tanousac106bf2023-06-07 09:24:59 -070066 messages::internalError(asyncResp->res);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -060067 return;
68 }
69 callback(pcieDevicePath, object.begin()->first);
70 });
71 return;
72 }
73
74 BMCWEB_LOG_WARNING << "PCIe Device not found";
Ed Tanousac106bf2023-06-07 09:24:59 -070075 messages::resourceNotFound(asyncResp->res, "PCIeDevice", pcieDeviceId);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -060076}
77
78static inline void getValidPCIeDevicePath(
79 const std::string& pcieDeviceId,
Ed Tanousac106bf2023-06-07 09:24:59 -070080 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -060081 const std::function<void(const std::string& pcieDevicePath,
82 const std::string& service)>& callback)
83{
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -060084 dbus::utility::getSubTreePaths(
Lakshmi Yadlapati94c3a102023-04-05 18:11:22 -050085 inventoryPath, 0, pcieDeviceInterface,
Ed Tanousac106bf2023-06-07 09:24:59 -070086 [pcieDeviceId, asyncResp,
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -060087 callback](const boost::system::error_code& ec,
88 const dbus::utility::MapperGetSubTreePathsResponse&
89 pcieDevicePaths) {
90 if (ec)
91 {
92 BMCWEB_LOG_ERROR << "D-Bus response error on GetSubTree " << ec;
Ed Tanousac106bf2023-06-07 09:24:59 -070093 messages::internalError(asyncResp->res);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -060094 return;
95 }
Ed Tanousac106bf2023-06-07 09:24:59 -070096 handlePCIeDevicePath(pcieDeviceId, asyncResp, pcieDevicePaths,
97 callback);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -060098 return;
99 });
100}
101
Lakshmi Yadlapatib38fa2a2023-03-10 16:19:46 -0600102static inline void handlePCIeDeviceCollectionGet(
103 crow::App& app, const crow::Request& req,
Ed Tanousac106bf2023-06-07 09:24:59 -0700104 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Lakshmi Yadlapatib38fa2a2023-03-10 16:19:46 -0600105 const std::string& systemName)
106{
Ed Tanousac106bf2023-06-07 09:24:59 -0700107 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Lakshmi Yadlapatib38fa2a2023-03-10 16:19:46 -0600108 {
109 return;
110 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -0800111 if constexpr (bmcwebEnableMultiHost)
112 {
113 // Option currently returns no systems. TBD
114 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
115 systemName);
116 return;
117 }
Lakshmi Yadlapatib38fa2a2023-03-10 16:19:46 -0600118 if (systemName != "system")
119 {
Ed Tanousac106bf2023-06-07 09:24:59 -0700120 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
121 systemName);
Lakshmi Yadlapatib38fa2a2023-03-10 16:19:46 -0600122 return;
123 }
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600124
Ed Tanousac106bf2023-06-07 09:24:59 -0700125 asyncResp->res.addHeader(boost::beast::http::field::link,
126 "</redfish/v1/JsonSchemas/PCIeDeviceCollection/"
127 "PCIeDeviceCollection.json>; rel=describedby");
128 asyncResp->res.jsonValue["@odata.type"] =
Lakshmi Yadlapatib38fa2a2023-03-10 16:19:46 -0600129 "#PCIeDeviceCollection.PCIeDeviceCollection";
Ed Tanousac106bf2023-06-07 09:24:59 -0700130 asyncResp->res.jsonValue["@odata.id"] =
Lakshmi Yadlapatib38fa2a2023-03-10 16:19:46 -0600131 "/redfish/v1/Systems/system/PCIeDevices";
Ed Tanousac106bf2023-06-07 09:24:59 -0700132 asyncResp->res.jsonValue["Name"] = "PCIe Device Collection";
133 asyncResp->res.jsonValue["Description"] = "Collection of PCIe Devices";
134 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
135 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Lakshmi Yadlapatib38fa2a2023-03-10 16:19:46 -0600136
Lakshmi Yadlapati9e9325e2023-05-02 10:30:44 -0500137 pcie_util::getPCIeDeviceList(asyncResp, "Members");
Lakshmi Yadlapatib38fa2a2023-03-10 16:19:46 -0600138}
139
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700140inline void requestRoutesSystemPCIeDeviceCollection(App& app)
Jason M. Billsadbe1922019-10-14 15:44:35 -0700141{
Jason M. Billsadbe1922019-10-14 15:44:35 -0700142 /**
143 * Functions triggers appropriate requests on DBus
144 */
Ed Tanous22d268c2022-05-19 09:39:07 -0700145 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/")
Ed Tanoused398212021-06-09 17:05:54 -0700146 .privileges(redfish::privileges::getPCIeDeviceCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700147 .methods(boost::beast::http::verb::get)(
Lakshmi Yadlapatib38fa2a2023-03-10 16:19:46 -0600148 std::bind_front(handlePCIeDeviceCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700149}
150
Lakshmi Yadlapatia5409992023-04-20 16:53:59 -0500151inline void addPCIeSlotProperties(
152 crow::Response& res, const boost::system::error_code& ec,
153 const dbus::utility::DBusPropertiesMap& pcieSlotProperties)
154{
155 if (ec)
156 {
157 BMCWEB_LOG_ERROR << "DBUS response error for getAllProperties"
158 << ec.value();
159 messages::internalError(res);
160 return;
161 }
162 std::string generation;
163 size_t lanes = 0;
164 std::string slotType;
165
166 bool success = sdbusplus::unpackPropertiesNoThrow(
167 dbus_utils::UnpackErrorPrinter(), pcieSlotProperties, "Generation",
168 generation, "Lanes", lanes, "SlotType", slotType);
169
170 if (!success)
171 {
172 messages::internalError(res);
173 return;
174 }
175
176 std::optional<pcie_device::PCIeTypes> pcieType =
177 pcie_util::redfishPcieGenerationFromDbus(generation);
178 if (!pcieType)
179 {
180 BMCWEB_LOG_WARNING << "Unknown PCIeType: " << generation;
181 }
182 else
183 {
184 if (*pcieType == pcie_device::PCIeTypes::Invalid)
185 {
186 BMCWEB_LOG_ERROR << "Invalid PCIeType: " << generation;
187 messages::internalError(res);
188 return;
189 }
190 res.jsonValue["Slot"]["PCIeType"] = *pcieType;
191 }
192
Konstantin Aladyshev82f80322023-07-10 15:00:38 +0300193 if (lanes != 0)
194 {
195 res.jsonValue["Slot"]["Lanes"] = lanes;
196 }
Lakshmi Yadlapatia5409992023-04-20 16:53:59 -0500197
198 std::optional<pcie_slots::SlotTypes> redfishSlotType =
199 pcie_util::dbusSlotTypeToRf(slotType);
200 if (!redfishSlotType)
201 {
202 BMCWEB_LOG_WARNING << "Unknown PCIeSlot Type: " << slotType;
203 }
204 else
205 {
206 if (*redfishSlotType == pcie_slots::SlotTypes::Invalid)
207 {
208 BMCWEB_LOG_ERROR << "Invalid PCIeSlot type: " << slotType;
209 messages::internalError(res);
210 return;
211 }
212 res.jsonValue["Slot"]["SlotType"] = *redfishSlotType;
213 }
214}
215
216inline void getPCIeDeviceSlotPath(
217 const std::string& pcieDevicePath,
218 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
219 std::function<void(const std::string& pcieDeviceSlot)>&& callback)
220{
221 std::string associationPath = pcieDevicePath + "/contained_by";
222 dbus::utility::getAssociatedSubTreePaths(
223 associationPath, sdbusplus::message::object_path(inventoryPath), 0,
224 pcieSlotInterface,
225 [callback, asyncResp, pcieDevicePath](
226 const boost::system::error_code& ec,
227 const dbus::utility::MapperGetSubTreePathsResponse& endpoints) {
228 if (ec)
229 {
230 if (ec.value() == EBADR)
231 {
232 // Missing association is not an error
233 return;
234 }
235 BMCWEB_LOG_ERROR
236 << "DBUS response error for getAssociatedSubTreePaths "
237 << ec.value();
238 messages::internalError(asyncResp->res);
239 return;
240 }
241 if (endpoints.size() > 1)
242 {
243 BMCWEB_LOG_ERROR
244 << "PCIeDevice is associated with more than one PCIeSlot: "
245 << endpoints.size();
246 messages::internalError(asyncResp->res);
247 return;
248 }
249 if (endpoints.empty())
250 {
251 // If the device doesn't have an association, return without PCIe
252 // Slot properties
253 BMCWEB_LOG_DEBUG << "PCIeDevice is not associated with PCIeSlot";
254 return;
255 }
256 callback(endpoints[0]);
257 });
258}
259
260inline void
261 afterGetDbusObject(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
262 const std::string& pcieDeviceSlot,
263 const boost::system::error_code& ec,
264 const dbus::utility::MapperGetObject& object)
265{
266 if (ec || object.empty())
267 {
268 BMCWEB_LOG_ERROR << "DBUS response error for getDbusObject "
269 << ec.value();
270 messages::internalError(asyncResp->res);
271 return;
272 }
273 sdbusplus::asio::getAllProperties(
274 *crow::connections::systemBus, object.begin()->first, pcieDeviceSlot,
275 "xyz.openbmc_project.Inventory.Item.PCIeSlot",
276 [asyncResp](
277 const boost::system::error_code& ec2,
278 const dbus::utility::DBusPropertiesMap& pcieSlotProperties) {
279 addPCIeSlotProperties(asyncResp->res, ec2, pcieSlotProperties);
280 });
281}
282
283inline void afterGetPCIeDeviceSlotPath(
284 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
285 const std::string& pcieDeviceSlot)
286{
287 dbus::utility::getDbusObject(
288 pcieDeviceSlot, pcieSlotInterface,
289 [asyncResp,
290 pcieDeviceSlot](const boost::system::error_code& ec,
291 const dbus::utility::MapperGetObject& object) {
292 afterGetDbusObject(asyncResp, pcieDeviceSlot, ec, object);
293 });
294}
295
Ed Tanousac106bf2023-06-07 09:24:59 -0700296inline void
Lakshmi Yadlapatie164f1b2023-04-12 17:01:34 -0500297 getPCIeDeviceHealth(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
298 const std::string& pcieDevicePath,
299 const std::string& service)
300{
301 sdbusplus::asio::getProperty<bool>(
302 *crow::connections::systemBus, service, pcieDevicePath,
303 "xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional",
304 [asyncResp](const boost::system::error_code& ec, const bool value) {
305 if (ec)
306 {
307 if (ec.value() != EBADR)
308 {
309 BMCWEB_LOG_ERROR << "DBUS response error for Health "
310 << ec.value();
311 messages::internalError(asyncResp->res);
312 }
313 return;
314 }
315
316 if (!value)
317 {
318 asyncResp->res.jsonValue["Status"]["Health"] = "Critical";
319 }
320 });
321}
322
323inline void
Ed Tanousac106bf2023-06-07 09:24:59 -0700324 getPCIeDeviceState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
325 const std::string& pcieDevicePath,
326 const std::string& service)
Lakshmi Yadlapatic6bb3282023-04-12 16:56:49 -0500327{
328 sdbusplus::asio::getProperty<bool>(
329 *crow::connections::systemBus, service, pcieDevicePath,
330 "xyz.openbmc_project.Inventory.Item", "Present",
Lakshmi Yadlapatia5409992023-04-20 16:53:59 -0500331 [asyncResp](const boost::system::error_code& ec, bool value) {
Lakshmi Yadlapatic6bb3282023-04-12 16:56:49 -0500332 if (ec)
333 {
334 if (ec.value() != EBADR)
335 {
336 BMCWEB_LOG_ERROR << "DBUS response error for State";
Ed Tanousac106bf2023-06-07 09:24:59 -0700337 messages::internalError(asyncResp->res);
Lakshmi Yadlapatic6bb3282023-04-12 16:56:49 -0500338 }
339 return;
340 }
341
342 if (!value)
343 {
Ed Tanousac106bf2023-06-07 09:24:59 -0700344 asyncResp->res.jsonValue["Status"]["State"] = "Absent";
Lakshmi Yadlapatic6bb3282023-04-12 16:56:49 -0500345 }
346 });
347}
348
Ed Tanousac106bf2023-06-07 09:24:59 -0700349inline void
350 getPCIeDeviceAsset(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
351 const std::string& pcieDevicePath,
352 const std::string& service)
SunnySrivastava1984913e7732021-01-27 06:23:24 -0600353{
354 sdbusplus::asio::getAllProperties(
355 *crow::connections::systemBus, service, pcieDevicePath,
356 "xyz.openbmc_project.Inventory.Decorator.Asset",
Ed Tanousac106bf2023-06-07 09:24:59 -0700357 [pcieDevicePath, asyncResp{asyncResp}](
358 const boost::system::error_code& ec,
359 const dbus::utility::DBusPropertiesMap& assetList) {
SunnySrivastava1984913e7732021-01-27 06:23:24 -0600360 if (ec)
361 {
362 if (ec.value() != EBADR)
363 {
364 BMCWEB_LOG_ERROR << "DBUS response error for Properties"
365 << ec.value();
Ed Tanousac106bf2023-06-07 09:24:59 -0700366 messages::internalError(asyncResp->res);
SunnySrivastava1984913e7732021-01-27 06:23:24 -0600367 }
368 return;
369 }
370
371 const std::string* manufacturer = nullptr;
372 const std::string* model = nullptr;
373 const std::string* partNumber = nullptr;
374 const std::string* serialNumber = nullptr;
375 const std::string* sparePartNumber = nullptr;
376
377 const bool success = sdbusplus::unpackPropertiesNoThrow(
378 dbus_utils::UnpackErrorPrinter(), assetList, "Manufacturer",
379 manufacturer, "Model", model, "PartNumber", partNumber,
380 "SerialNumber", serialNumber, "SparePartNumber", sparePartNumber);
381
382 if (!success)
383 {
Ed Tanousac106bf2023-06-07 09:24:59 -0700384 messages::internalError(asyncResp->res);
SunnySrivastava1984913e7732021-01-27 06:23:24 -0600385 return;
386 }
387
388 if (manufacturer != nullptr)
389 {
Ed Tanousac106bf2023-06-07 09:24:59 -0700390 asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
SunnySrivastava1984913e7732021-01-27 06:23:24 -0600391 }
392 if (model != nullptr)
393 {
Ed Tanousac106bf2023-06-07 09:24:59 -0700394 asyncResp->res.jsonValue["Model"] = *model;
SunnySrivastava1984913e7732021-01-27 06:23:24 -0600395 }
396
397 if (partNumber != nullptr)
398 {
Ed Tanousac106bf2023-06-07 09:24:59 -0700399 asyncResp->res.jsonValue["PartNumber"] = *partNumber;
SunnySrivastava1984913e7732021-01-27 06:23:24 -0600400 }
401
402 if (serialNumber != nullptr)
403 {
Ed Tanousac106bf2023-06-07 09:24:59 -0700404 asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
SunnySrivastava1984913e7732021-01-27 06:23:24 -0600405 }
406
407 if (sparePartNumber != nullptr && !sparePartNumber->empty())
408 {
Ed Tanousac106bf2023-06-07 09:24:59 -0700409 asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
SunnySrivastava1984913e7732021-01-27 06:23:24 -0600410 }
411 });
412}
413
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600414inline void addPCIeDeviceProperties(
Lakshmi Yadlapatia5409992023-04-20 16:53:59 -0500415 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
416 const std::string& pcieDeviceId,
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600417 const dbus::utility::DBusPropertiesMap& pcieDevProperties)
418{
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600419 const std::string* deviceType = nullptr;
420 const std::string* generationInUse = nullptr;
Konstantin Aladyshev814bf202023-07-04 16:30:10 +0300421 const std::string* generationSupported = nullptr;
Konstantin Aladyshev9bb0a7f2023-07-04 12:59:34 +0300422 const size_t* lanesInUse = nullptr;
Konstantin Aladyshev814bf202023-07-04 16:30:10 +0300423 const size_t* maxLanes = nullptr;
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600424
425 const bool success = sdbusplus::unpackPropertiesNoThrow(
426 dbus_utils::UnpackErrorPrinter(), pcieDevProperties, "DeviceType",
Konstantin Aladyshev814bf202023-07-04 16:30:10 +0300427 deviceType, "GenerationInUse", generationInUse, "GenerationSupported",
428 generationSupported, "LanesInUse", lanesInUse, "MaxLanes", maxLanes);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600429
430 if (!success)
431 {
Lakshmi Yadlapatia5409992023-04-20 16:53:59 -0500432 messages::internalError(asyncResp->res);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600433 return;
434 }
435
436 if (deviceType != nullptr && !deviceType->empty())
437 {
Lakshmi Yadlapatia5409992023-04-20 16:53:59 -0500438 asyncResp->res.jsonValue["PCIeInterface"]["DeviceType"] = *deviceType;
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600439 }
440
441 if (generationInUse != nullptr)
442 {
443 std::optional<pcie_device::PCIeTypes> redfishGenerationInUse =
Lakshmi Yadlapatic49c3292023-04-19 16:42:35 -0500444 pcie_util::redfishPcieGenerationFromDbus(*generationInUse);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600445
446 if (!redfishGenerationInUse)
447 {
Lakshmi Yadlapaticf3b4842023-06-27 02:36:53 -0500448 BMCWEB_LOG_WARNING << "Unknown PCIe Device Generation: "
449 << *generationInUse;
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600450 }
Lakshmi Yadlapaticf3b4842023-06-27 02:36:53 -0500451 else
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600452 {
Lakshmi Yadlapaticf3b4842023-06-27 02:36:53 -0500453 if (*redfishGenerationInUse == pcie_device::PCIeTypes::Invalid)
454 {
455 BMCWEB_LOG_ERROR << "Invalid PCIe Device Generation: "
456 << *generationInUse;
Lakshmi Yadlapatia5409992023-04-20 16:53:59 -0500457 messages::internalError(asyncResp->res);
Lakshmi Yadlapaticf3b4842023-06-27 02:36:53 -0500458 return;
459 }
Lakshmi Yadlapatia5409992023-04-20 16:53:59 -0500460 asyncResp->res.jsonValue["PCIeInterface"]["PCIeType"] =
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600461 *redfishGenerationInUse;
462 }
463 }
464
Konstantin Aladyshev814bf202023-07-04 16:30:10 +0300465 if (generationSupported != nullptr)
466 {
467 std::optional<pcie_device::PCIeTypes> redfishGenerationSupported =
468 pcie_util::redfishPcieGenerationFromDbus(*generationSupported);
469
470 if (!redfishGenerationSupported)
471 {
472 BMCWEB_LOG_WARNING << "Unknown PCIe Device Generation: "
473 << *generationSupported;
474 }
475 else
476 {
477 if (*redfishGenerationSupported == pcie_device::PCIeTypes::Invalid)
478 {
479 BMCWEB_LOG_ERROR << "Invalid PCIe Device Generation: "
480 << *generationSupported;
481 messages::internalError(asyncResp->res);
482 return;
483 }
484 asyncResp->res.jsonValue["PCIeInterface"]["MaxPCIeType"] =
485 *redfishGenerationSupported;
486 }
487 }
488
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600489 // The default value of LanesInUse is 0, and the field will be
490 // left as off if it is a default value.
491 if (lanesInUse != nullptr && *lanesInUse != 0)
492 {
Lakshmi Yadlapatia5409992023-04-20 16:53:59 -0500493 asyncResp->res.jsonValue["PCIeInterface"]["LanesInUse"] = *lanesInUse;
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600494 }
Konstantin Aladyshev814bf202023-07-04 16:30:10 +0300495 // The default value of MaxLanes is 0, and the field will be
496 // left as off if it is a default value.
497 if (maxLanes != nullptr && *maxLanes != 0)
498 {
499 asyncResp->res.jsonValue["PCIeInterface"]["MaxLanes"] = *maxLanes;
500 }
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600501
Lakshmi Yadlapatia5409992023-04-20 16:53:59 -0500502 asyncResp->res.jsonValue["PCIeFunctions"]["@odata.id"] =
503 boost::urls::format(
504 "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions",
505 pcieDeviceId);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600506}
507
508inline void getPCIeDeviceProperties(
Ed Tanousac106bf2023-06-07 09:24:59 -0700509 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600510 const std::string& pcieDevicePath, const std::string& service,
511 const std::function<void(
512 const dbus::utility::DBusPropertiesMap& pcieDevProperties)>&& callback)
513{
514 sdbusplus::asio::getAllProperties(
515 *crow::connections::systemBus, service, pcieDevicePath,
516 "xyz.openbmc_project.Inventory.Item.PCIeDevice",
Ed Tanousac106bf2023-06-07 09:24:59 -0700517 [asyncResp,
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600518 callback](const boost::system::error_code& ec,
519 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
520 if (ec)
521 {
522 if (ec.value() != EBADR)
523 {
524 BMCWEB_LOG_ERROR << "DBUS response error for Properties";
Ed Tanousac106bf2023-06-07 09:24:59 -0700525 messages::internalError(asyncResp->res);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600526 }
527 return;
528 }
529 callback(pcieDevProperties);
530 });
531}
532
533inline void addPCIeDeviceCommonProperties(
Ed Tanousac106bf2023-06-07 09:24:59 -0700534 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600535 const std::string& pcieDeviceId)
536{
Ed Tanousac106bf2023-06-07 09:24:59 -0700537 asyncResp->res.addHeader(
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600538 boost::beast::http::field::link,
539 "</redfish/v1/JsonSchemas/PCIeDevice/PCIeDevice.json>; rel=describedby");
Ed Tanousac106bf2023-06-07 09:24:59 -0700540 asyncResp->res.jsonValue["@odata.type"] = "#PCIeDevice.v1_9_0.PCIeDevice";
541 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
Ed Tanousef4c65b2023-04-24 15:28:50 -0700542 "/redfish/v1/Systems/system/PCIeDevices/{}", pcieDeviceId);
Ed Tanousac106bf2023-06-07 09:24:59 -0700543 asyncResp->res.jsonValue["Name"] = "PCIe Device";
544 asyncResp->res.jsonValue["Id"] = pcieDeviceId;
545 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
Lakshmi Yadlapatie164f1b2023-04-12 17:01:34 -0500546 asyncResp->res.jsonValue["Status"]["Health"] = "OK";
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600547}
548
Lakshmi Yadlapatia5409992023-04-20 16:53:59 -0500549inline void afterGetValidPcieDevicePath(
550 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
551 const std::string& pcieDeviceId, const std::string& pcieDevicePath,
552 const std::string& service)
553{
554 addPCIeDeviceCommonProperties(asyncResp, pcieDeviceId);
555 getPCIeDeviceAsset(asyncResp, pcieDevicePath, service);
556 getPCIeDeviceState(asyncResp, pcieDevicePath, service);
557 getPCIeDeviceHealth(asyncResp, pcieDevicePath, service);
558 getPCIeDeviceProperties(
559 asyncResp, pcieDevicePath, service,
560 std::bind_front(addPCIeDeviceProperties, asyncResp, pcieDeviceId));
561 getPCIeDeviceSlotPath(
562 pcieDevicePath, asyncResp,
563 std::bind_front(afterGetPCIeDeviceSlotPath, asyncResp));
564}
565
Ed Tanousac106bf2023-06-07 09:24:59 -0700566inline void
567 handlePCIeDeviceGet(App& app, const crow::Request& req,
568 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
569 const std::string& systemName,
570 const std::string& pcieDeviceId)
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600571{
Ed Tanousac106bf2023-06-07 09:24:59 -0700572 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600573 {
574 return;
575 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -0800576 if constexpr (bmcwebEnableMultiHost)
577 {
578 // Option currently returns no systems. TBD
579 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
580 systemName);
581 return;
582 }
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600583 if (systemName != "system")
584 {
Ed Tanousac106bf2023-06-07 09:24:59 -0700585 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
586 systemName);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600587 return;
588 }
589
590 getValidPCIeDevicePath(
Ed Tanousac106bf2023-06-07 09:24:59 -0700591 pcieDeviceId, asyncResp,
Lakshmi Yadlapatia5409992023-04-20 16:53:59 -0500592 std::bind_front(afterGetValidPcieDevicePath, asyncResp, pcieDeviceId));
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600593}
594
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700595inline void requestRoutesSystemPCIeDevice(App& app)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800596{
Ed Tanous22d268c2022-05-19 09:39:07 -0700597 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700598 .privileges(redfish::privileges::getPCIeDevice)
Ed Tanous002d39b2022-05-31 08:59:27 -0700599 .methods(boost::beast::http::verb::get)(
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600600 std::bind_front(handlePCIeDeviceGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700601}
602
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600603inline void addPCIeFunctionList(
604 crow::Response& res, const std::string& pcieDeviceId,
605 const dbus::utility::DBusPropertiesMap& pcieDevProperties)
606{
607 nlohmann::json& pcieFunctionList = res.jsonValue["Members"];
608 pcieFunctionList = nlohmann::json::array();
609 static constexpr const int maxPciFunctionNum = 8;
610
611 for (int functionNum = 0; functionNum < maxPciFunctionNum; functionNum++)
612 {
613 // Check if this function exists by
614 // looking for a device ID
Patrick Williams89492a12023-05-10 07:51:34 -0500615 std::string devIDProperty = "Function" + std::to_string(functionNum) +
616 "DeviceId";
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600617 const std::string* property = nullptr;
618 for (const auto& propEntry : pcieDevProperties)
619 {
620 if (propEntry.first == devIDProperty)
621 {
622 property = std::get_if<std::string>(&propEntry.second);
623 break;
624 }
625 }
626 if (property == nullptr || property->empty())
627 {
628 continue;
629 }
630
631 nlohmann::json::object_t pcieFunction;
Ed Tanousef4c65b2023-04-24 15:28:50 -0700632 pcieFunction["@odata.id"] = boost::urls::format(
633 "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions/{}",
634 pcieDeviceId, std::to_string(functionNum));
Patrick Williamsb2ba3072023-05-12 10:27:39 -0500635 pcieFunctionList.emplace_back(std::move(pcieFunction));
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600636 }
637 res.jsonValue["PCIeFunctions@odata.count"] = pcieFunctionList.size();
638}
639
640inline void handlePCIeFunctionCollectionGet(
641 App& app, const crow::Request& req,
Ed Tanousac106bf2023-06-07 09:24:59 -0700642 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous7f3e84a2022-12-28 16:22:54 -0800643 const std::string& systemName, const std::string& pcieDeviceId)
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600644{
Ed Tanousac106bf2023-06-07 09:24:59 -0700645 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600646 {
647 return;
648 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -0800649 if constexpr (bmcwebEnableMultiHost)
650 {
651 // Option currently returns no systems. TBD
652 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
653 systemName);
654 return;
655 }
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600656
657 getValidPCIeDevicePath(
Ed Tanousac106bf2023-06-07 09:24:59 -0700658 pcieDeviceId, asyncResp,
659 [asyncResp, pcieDeviceId](const std::string& pcieDevicePath,
660 const std::string& service) {
661 asyncResp->res.addHeader(
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600662 boost::beast::http::field::link,
663 "</redfish/v1/JsonSchemas/PCIeFunctionCollection/PCIeFunctionCollection.json>; rel=describedby");
Ed Tanousac106bf2023-06-07 09:24:59 -0700664 asyncResp->res.jsonValue["@odata.type"] =
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600665 "#PCIeFunctionCollection.PCIeFunctionCollection";
Ed Tanousac106bf2023-06-07 09:24:59 -0700666 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
Ed Tanousef4c65b2023-04-24 15:28:50 -0700667 "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions",
668 pcieDeviceId);
Ed Tanousac106bf2023-06-07 09:24:59 -0700669 asyncResp->res.jsonValue["Name"] = "PCIe Function Collection";
670 asyncResp->res.jsonValue["Description"] =
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600671 "Collection of PCIe Functions for PCIe Device " + pcieDeviceId;
672 getPCIeDeviceProperties(
Ed Tanousac106bf2023-06-07 09:24:59 -0700673 asyncResp, pcieDevicePath, service,
674 [asyncResp, pcieDeviceId](
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600675 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
Ed Tanousac106bf2023-06-07 09:24:59 -0700676 addPCIeFunctionList(asyncResp->res, pcieDeviceId,
677 pcieDevProperties);
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600678 });
679 });
680}
681
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700682inline void requestRoutesSystemPCIeFunctionCollection(App& app)
683{
684 /**
685 * Functions triggers appropriate requests on DBus
686 */
687 BMCWEB_ROUTE(app,
Ed Tanous7f3e84a2022-12-28 16:22:54 -0800688 "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/")
Ed Tanoused398212021-06-09 17:05:54 -0700689 .privileges(redfish::privileges::getPCIeFunctionCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -0700690 .methods(boost::beast::http::verb::get)(
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600691 std::bind_front(handlePCIeFunctionCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700692}
693
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600694inline bool validatePCIeFunctionId(
Myung Baed5e74b82023-05-31 11:28:02 -0500695 uint64_t pcieFunctionId,
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600696 const dbus::utility::DBusPropertiesMap& pcieDevProperties)
697{
Myung Baed5e74b82023-05-31 11:28:02 -0500698 std::string functionName = "Function" + std::to_string(pcieFunctionId);
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600699 std::string devIDProperty = functionName + "DeviceId";
700
701 const std::string* devIdProperty = nullptr;
702 for (const auto& property : pcieDevProperties)
703 {
704 if (property.first == devIDProperty)
705 {
706 devIdProperty = std::get_if<std::string>(&property.second);
707 break;
708 }
709 }
710 return (devIdProperty != nullptr && !devIdProperty->empty());
711}
712
713inline void addPCIeFunctionProperties(
Ed Tanouse14742c2023-05-31 10:27:49 -0700714 crow::Response& resp, uint64_t pcieFunctionId,
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600715 const dbus::utility::DBusPropertiesMap& pcieDevProperties)
716{
Ed Tanouse14742c2023-05-31 10:27:49 -0700717 std::string functionName = "Function" + std::to_string(pcieFunctionId);
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600718 for (const auto& property : pcieDevProperties)
719 {
720 const std::string* strProperty =
721 std::get_if<std::string>(&property.second);
722
723 if (property.first == functionName + "DeviceId")
724 {
725 resp.jsonValue["DeviceId"] = *strProperty;
726 }
727 if (property.first == functionName + "VendorId")
728 {
729 resp.jsonValue["VendorId"] = *strProperty;
730 }
731 // TODO: FunctionType and DeviceClass are Redfish enums. The D-Bus
732 // property strings should be mapped correctly to ensure these
733 // strings are Redfish enum values. For now just check for empty.
734 if (property.first == functionName + "FunctionType")
735 {
736 if (!strProperty->empty())
737 {
738 resp.jsonValue["FunctionType"] = *strProperty;
739 }
740 }
741 if (property.first == functionName + "DeviceClass")
742 {
743 if (!strProperty->empty())
744 {
745 resp.jsonValue["DeviceClass"] = *strProperty;
746 }
747 }
748 if (property.first == functionName + "ClassCode")
749 {
750 resp.jsonValue["ClassCode"] = *strProperty;
751 }
752 if (property.first == functionName + "RevisionId")
753 {
754 resp.jsonValue["RevisionId"] = *strProperty;
755 }
756 if (property.first == functionName + "SubsystemId")
757 {
758 resp.jsonValue["SubsystemId"] = *strProperty;
759 }
760 if (property.first == functionName + "SubsystemVendorId")
761 {
762 resp.jsonValue["SubsystemVendorId"] = *strProperty;
763 }
764 }
765}
766
767inline void addPCIeFunctionCommonProperties(crow::Response& resp,
768 const std::string& pcieDeviceId,
Ed Tanouse14742c2023-05-31 10:27:49 -0700769 uint64_t pcieFunctionId)
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600770{
771 resp.addHeader(
772 boost::beast::http::field::link,
773 "</redfish/v1/JsonSchemas/PCIeFunction/PCIeFunction.json>; rel=describedby");
774 resp.jsonValue["@odata.type"] = "#PCIeFunction.v1_2_3.PCIeFunction";
Ed Tanousef4c65b2023-04-24 15:28:50 -0700775 resp.jsonValue["@odata.id"] = boost::urls::format(
776 "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions/{}",
Lakshmi Yadlapati768a1432023-06-14 12:45:54 -0500777 pcieDeviceId, std::to_string(pcieFunctionId));
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600778 resp.jsonValue["Name"] = "PCIe Function";
Ed Tanouse14742c2023-05-31 10:27:49 -0700779 resp.jsonValue["Id"] = std::to_string(pcieFunctionId);
780 resp.jsonValue["FunctionId"] = pcieFunctionId;
Ed Tanousef4c65b2023-04-24 15:28:50 -0700781 resp.jsonValue["Links"]["PCIeDevice"]["@odata.id"] = boost::urls::format(
782 "/redfish/v1/Systems/system/PCIeDevices/{}", pcieDeviceId);
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600783}
784
785inline void
786 handlePCIeFunctionGet(App& app, const crow::Request& req,
Ed Tanousac106bf2023-06-07 09:24:59 -0700787 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous7f3e84a2022-12-28 16:22:54 -0800788 const std::string& systemName,
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600789 const std::string& pcieDeviceId,
Ed Tanouse14742c2023-05-31 10:27:49 -0700790 const std::string& pcieFunctionIdStr)
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600791{
Ed Tanousac106bf2023-06-07 09:24:59 -0700792 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600793 {
794 return;
795 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -0800796 if constexpr (bmcwebEnableMultiHost)
797 {
798 // Option currently returns no systems. TBD
799 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
800 systemName);
801 return;
802 }
803 if (systemName != "system")
804 {
805 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
806 systemName);
807 return;
808 }
809
Ed Tanouse14742c2023-05-31 10:27:49 -0700810 uint64_t pcieFunctionId = 0;
811 std::from_chars_result result = std::from_chars(
812 &*pcieFunctionIdStr.begin(), &*pcieFunctionIdStr.end(), pcieFunctionId);
813 if (result.ec != std::errc{} || result.ptr != &*pcieFunctionIdStr.end())
814 {
Ed Tanousac106bf2023-06-07 09:24:59 -0700815 messages::resourceNotFound(asyncResp->res, "PCIeFunction",
Ed Tanouse14742c2023-05-31 10:27:49 -0700816 pcieFunctionIdStr);
817 return;
818 }
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600819
Ed Tanousac106bf2023-06-07 09:24:59 -0700820 getValidPCIeDevicePath(pcieDeviceId, asyncResp,
821 [asyncResp, pcieDeviceId,
822 pcieFunctionId](const std::string& pcieDevicePath,
823 const std::string& service) {
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600824 getPCIeDeviceProperties(
Ed Tanousac106bf2023-06-07 09:24:59 -0700825 asyncResp, pcieDevicePath, service,
826 [asyncResp, pcieDeviceId, pcieFunctionId](
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600827 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
Ed Tanousac106bf2023-06-07 09:24:59 -0700828 addPCIeFunctionCommonProperties(asyncResp->res, pcieDeviceId,
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600829 pcieFunctionId);
Ed Tanousac106bf2023-06-07 09:24:59 -0700830 addPCIeFunctionProperties(asyncResp->res, pcieFunctionId,
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600831 pcieDevProperties);
832 });
Ed Tanousac106bf2023-06-07 09:24:59 -0700833 });
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600834}
835
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700836inline void requestRoutesSystemPCIeFunction(App& app)
837{
838 BMCWEB_ROUTE(
Ed Tanous7f3e84a2022-12-28 16:22:54 -0800839 app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700840 .privileges(redfish::privileges::getPCIeFunction)
Ed Tanous002d39b2022-05-31 08:59:27 -0700841 .methods(boost::beast::http::verb::get)(
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600842 std::bind_front(handlePCIeFunctionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700843}
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800844
845} // namespace redfish