blob: e10ba64643f0679a2f11c8bbd83439d5d5ce10b3 [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
193 res.jsonValue["Slot"]["Lanes"] = lanes;
194
195 std::optional<pcie_slots::SlotTypes> redfishSlotType =
196 pcie_util::dbusSlotTypeToRf(slotType);
197 if (!redfishSlotType)
198 {
199 BMCWEB_LOG_WARNING << "Unknown PCIeSlot Type: " << slotType;
200 }
201 else
202 {
203 if (*redfishSlotType == pcie_slots::SlotTypes::Invalid)
204 {
205 BMCWEB_LOG_ERROR << "Invalid PCIeSlot type: " << slotType;
206 messages::internalError(res);
207 return;
208 }
209 res.jsonValue["Slot"]["SlotType"] = *redfishSlotType;
210 }
211}
212
213inline void getPCIeDeviceSlotPath(
214 const std::string& pcieDevicePath,
215 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
216 std::function<void(const std::string& pcieDeviceSlot)>&& callback)
217{
218 std::string associationPath = pcieDevicePath + "/contained_by";
219 dbus::utility::getAssociatedSubTreePaths(
220 associationPath, sdbusplus::message::object_path(inventoryPath), 0,
221 pcieSlotInterface,
222 [callback, asyncResp, pcieDevicePath](
223 const boost::system::error_code& ec,
224 const dbus::utility::MapperGetSubTreePathsResponse& endpoints) {
225 if (ec)
226 {
227 if (ec.value() == EBADR)
228 {
229 // Missing association is not an error
230 return;
231 }
232 BMCWEB_LOG_ERROR
233 << "DBUS response error for getAssociatedSubTreePaths "
234 << ec.value();
235 messages::internalError(asyncResp->res);
236 return;
237 }
238 if (endpoints.size() > 1)
239 {
240 BMCWEB_LOG_ERROR
241 << "PCIeDevice is associated with more than one PCIeSlot: "
242 << endpoints.size();
243 messages::internalError(asyncResp->res);
244 return;
245 }
246 if (endpoints.empty())
247 {
248 // If the device doesn't have an association, return without PCIe
249 // Slot properties
250 BMCWEB_LOG_DEBUG << "PCIeDevice is not associated with PCIeSlot";
251 return;
252 }
253 callback(endpoints[0]);
254 });
255}
256
257inline void
258 afterGetDbusObject(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
259 const std::string& pcieDeviceSlot,
260 const boost::system::error_code& ec,
261 const dbus::utility::MapperGetObject& object)
262{
263 if (ec || object.empty())
264 {
265 BMCWEB_LOG_ERROR << "DBUS response error for getDbusObject "
266 << ec.value();
267 messages::internalError(asyncResp->res);
268 return;
269 }
270 sdbusplus::asio::getAllProperties(
271 *crow::connections::systemBus, object.begin()->first, pcieDeviceSlot,
272 "xyz.openbmc_project.Inventory.Item.PCIeSlot",
273 [asyncResp](
274 const boost::system::error_code& ec2,
275 const dbus::utility::DBusPropertiesMap& pcieSlotProperties) {
276 addPCIeSlotProperties(asyncResp->res, ec2, pcieSlotProperties);
277 });
278}
279
280inline void afterGetPCIeDeviceSlotPath(
281 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
282 const std::string& pcieDeviceSlot)
283{
284 dbus::utility::getDbusObject(
285 pcieDeviceSlot, pcieSlotInterface,
286 [asyncResp,
287 pcieDeviceSlot](const boost::system::error_code& ec,
288 const dbus::utility::MapperGetObject& object) {
289 afterGetDbusObject(asyncResp, pcieDeviceSlot, ec, object);
290 });
291}
292
Ed Tanousac106bf2023-06-07 09:24:59 -0700293inline void
Lakshmi Yadlapatie164f1b2023-04-12 17:01:34 -0500294 getPCIeDeviceHealth(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
295 const std::string& pcieDevicePath,
296 const std::string& service)
297{
298 sdbusplus::asio::getProperty<bool>(
299 *crow::connections::systemBus, service, pcieDevicePath,
300 "xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional",
301 [asyncResp](const boost::system::error_code& ec, const bool value) {
302 if (ec)
303 {
304 if (ec.value() != EBADR)
305 {
306 BMCWEB_LOG_ERROR << "DBUS response error for Health "
307 << ec.value();
308 messages::internalError(asyncResp->res);
309 }
310 return;
311 }
312
313 if (!value)
314 {
315 asyncResp->res.jsonValue["Status"]["Health"] = "Critical";
316 }
317 });
318}
319
320inline void
Ed Tanousac106bf2023-06-07 09:24:59 -0700321 getPCIeDeviceState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
322 const std::string& pcieDevicePath,
323 const std::string& service)
Lakshmi Yadlapatic6bb3282023-04-12 16:56:49 -0500324{
325 sdbusplus::asio::getProperty<bool>(
326 *crow::connections::systemBus, service, pcieDevicePath,
327 "xyz.openbmc_project.Inventory.Item", "Present",
Lakshmi Yadlapatia5409992023-04-20 16:53:59 -0500328 [asyncResp](const boost::system::error_code& ec, bool value) {
Lakshmi Yadlapatic6bb3282023-04-12 16:56:49 -0500329 if (ec)
330 {
331 if (ec.value() != EBADR)
332 {
333 BMCWEB_LOG_ERROR << "DBUS response error for State";
Ed Tanousac106bf2023-06-07 09:24:59 -0700334 messages::internalError(asyncResp->res);
Lakshmi Yadlapatic6bb3282023-04-12 16:56:49 -0500335 }
336 return;
337 }
338
339 if (!value)
340 {
Ed Tanousac106bf2023-06-07 09:24:59 -0700341 asyncResp->res.jsonValue["Status"]["State"] = "Absent";
Lakshmi Yadlapatic6bb3282023-04-12 16:56:49 -0500342 }
343 });
344}
345
Ed Tanousac106bf2023-06-07 09:24:59 -0700346inline void
347 getPCIeDeviceAsset(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
348 const std::string& pcieDevicePath,
349 const std::string& service)
SunnySrivastava1984913e7732021-01-27 06:23:24 -0600350{
351 sdbusplus::asio::getAllProperties(
352 *crow::connections::systemBus, service, pcieDevicePath,
353 "xyz.openbmc_project.Inventory.Decorator.Asset",
Ed Tanousac106bf2023-06-07 09:24:59 -0700354 [pcieDevicePath, asyncResp{asyncResp}](
355 const boost::system::error_code& ec,
356 const dbus::utility::DBusPropertiesMap& assetList) {
SunnySrivastava1984913e7732021-01-27 06:23:24 -0600357 if (ec)
358 {
359 if (ec.value() != EBADR)
360 {
361 BMCWEB_LOG_ERROR << "DBUS response error for Properties"
362 << ec.value();
Ed Tanousac106bf2023-06-07 09:24:59 -0700363 messages::internalError(asyncResp->res);
SunnySrivastava1984913e7732021-01-27 06:23:24 -0600364 }
365 return;
366 }
367
368 const std::string* manufacturer = nullptr;
369 const std::string* model = nullptr;
370 const std::string* partNumber = nullptr;
371 const std::string* serialNumber = nullptr;
372 const std::string* sparePartNumber = nullptr;
373
374 const bool success = sdbusplus::unpackPropertiesNoThrow(
375 dbus_utils::UnpackErrorPrinter(), assetList, "Manufacturer",
376 manufacturer, "Model", model, "PartNumber", partNumber,
377 "SerialNumber", serialNumber, "SparePartNumber", sparePartNumber);
378
379 if (!success)
380 {
Ed Tanousac106bf2023-06-07 09:24:59 -0700381 messages::internalError(asyncResp->res);
SunnySrivastava1984913e7732021-01-27 06:23:24 -0600382 return;
383 }
384
385 if (manufacturer != nullptr)
386 {
Ed Tanousac106bf2023-06-07 09:24:59 -0700387 asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
SunnySrivastava1984913e7732021-01-27 06:23:24 -0600388 }
389 if (model != nullptr)
390 {
Ed Tanousac106bf2023-06-07 09:24:59 -0700391 asyncResp->res.jsonValue["Model"] = *model;
SunnySrivastava1984913e7732021-01-27 06:23:24 -0600392 }
393
394 if (partNumber != nullptr)
395 {
Ed Tanousac106bf2023-06-07 09:24:59 -0700396 asyncResp->res.jsonValue["PartNumber"] = *partNumber;
SunnySrivastava1984913e7732021-01-27 06:23:24 -0600397 }
398
399 if (serialNumber != nullptr)
400 {
Ed Tanousac106bf2023-06-07 09:24:59 -0700401 asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
SunnySrivastava1984913e7732021-01-27 06:23:24 -0600402 }
403
404 if (sparePartNumber != nullptr && !sparePartNumber->empty())
405 {
Ed Tanousac106bf2023-06-07 09:24:59 -0700406 asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
SunnySrivastava1984913e7732021-01-27 06:23:24 -0600407 }
408 });
409}
410
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600411inline void addPCIeDeviceProperties(
Lakshmi Yadlapatia5409992023-04-20 16:53:59 -0500412 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
413 const std::string& pcieDeviceId,
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600414 const dbus::utility::DBusPropertiesMap& pcieDevProperties)
415{
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600416 const std::string* deviceType = nullptr;
417 const std::string* generationInUse = nullptr;
418 const int64_t* lanesInUse = nullptr;
419
420 const bool success = sdbusplus::unpackPropertiesNoThrow(
421 dbus_utils::UnpackErrorPrinter(), pcieDevProperties, "DeviceType",
422 deviceType, "GenerationInUse", generationInUse, "LanesInUse",
Lakshmi Yadlapatibad2c4a2023-04-07 09:14:37 -0500423 lanesInUse);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600424
425 if (!success)
426 {
Lakshmi Yadlapatia5409992023-04-20 16:53:59 -0500427 messages::internalError(asyncResp->res);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600428 return;
429 }
430
431 if (deviceType != nullptr && !deviceType->empty())
432 {
Lakshmi Yadlapatia5409992023-04-20 16:53:59 -0500433 asyncResp->res.jsonValue["PCIeInterface"]["DeviceType"] = *deviceType;
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600434 }
435
436 if (generationInUse != nullptr)
437 {
438 std::optional<pcie_device::PCIeTypes> redfishGenerationInUse =
Lakshmi Yadlapatic49c3292023-04-19 16:42:35 -0500439 pcie_util::redfishPcieGenerationFromDbus(*generationInUse);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600440
441 if (!redfishGenerationInUse)
442 {
Lakshmi Yadlapaticf3b4842023-06-27 02:36:53 -0500443 BMCWEB_LOG_WARNING << "Unknown PCIe Device Generation: "
444 << *generationInUse;
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600445 }
Lakshmi Yadlapaticf3b4842023-06-27 02:36:53 -0500446 else
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600447 {
Lakshmi Yadlapaticf3b4842023-06-27 02:36:53 -0500448 if (*redfishGenerationInUse == pcie_device::PCIeTypes::Invalid)
449 {
450 BMCWEB_LOG_ERROR << "Invalid PCIe Device Generation: "
451 << *generationInUse;
Lakshmi Yadlapatia5409992023-04-20 16:53:59 -0500452 messages::internalError(asyncResp->res);
Lakshmi Yadlapaticf3b4842023-06-27 02:36:53 -0500453 return;
454 }
Lakshmi Yadlapatia5409992023-04-20 16:53:59 -0500455 asyncResp->res.jsonValue["PCIeInterface"]["PCIeType"] =
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600456 *redfishGenerationInUse;
457 }
458 }
459
460 // The default value of LanesInUse is 0, and the field will be
461 // left as off if it is a default value.
462 if (lanesInUse != nullptr && *lanesInUse != 0)
463 {
Lakshmi Yadlapatia5409992023-04-20 16:53:59 -0500464 asyncResp->res.jsonValue["PCIeInterface"]["LanesInUse"] = *lanesInUse;
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600465 }
466
Lakshmi Yadlapatia5409992023-04-20 16:53:59 -0500467 asyncResp->res.jsonValue["PCIeFunctions"]["@odata.id"] =
468 boost::urls::format(
469 "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions",
470 pcieDeviceId);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600471}
472
473inline void getPCIeDeviceProperties(
Ed Tanousac106bf2023-06-07 09:24:59 -0700474 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600475 const std::string& pcieDevicePath, const std::string& service,
476 const std::function<void(
477 const dbus::utility::DBusPropertiesMap& pcieDevProperties)>&& callback)
478{
479 sdbusplus::asio::getAllProperties(
480 *crow::connections::systemBus, service, pcieDevicePath,
481 "xyz.openbmc_project.Inventory.Item.PCIeDevice",
Ed Tanousac106bf2023-06-07 09:24:59 -0700482 [asyncResp,
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600483 callback](const boost::system::error_code& ec,
484 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
485 if (ec)
486 {
487 if (ec.value() != EBADR)
488 {
489 BMCWEB_LOG_ERROR << "DBUS response error for Properties";
Ed Tanousac106bf2023-06-07 09:24:59 -0700490 messages::internalError(asyncResp->res);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600491 }
492 return;
493 }
494 callback(pcieDevProperties);
495 });
496}
497
498inline void addPCIeDeviceCommonProperties(
Ed Tanousac106bf2023-06-07 09:24:59 -0700499 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600500 const std::string& pcieDeviceId)
501{
Ed Tanousac106bf2023-06-07 09:24:59 -0700502 asyncResp->res.addHeader(
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600503 boost::beast::http::field::link,
504 "</redfish/v1/JsonSchemas/PCIeDevice/PCIeDevice.json>; rel=describedby");
Ed Tanousac106bf2023-06-07 09:24:59 -0700505 asyncResp->res.jsonValue["@odata.type"] = "#PCIeDevice.v1_9_0.PCIeDevice";
506 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
Ed Tanousef4c65b2023-04-24 15:28:50 -0700507 "/redfish/v1/Systems/system/PCIeDevices/{}", pcieDeviceId);
Ed Tanousac106bf2023-06-07 09:24:59 -0700508 asyncResp->res.jsonValue["Name"] = "PCIe Device";
509 asyncResp->res.jsonValue["Id"] = pcieDeviceId;
510 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
Lakshmi Yadlapatie164f1b2023-04-12 17:01:34 -0500511 asyncResp->res.jsonValue["Status"]["Health"] = "OK";
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600512}
513
Lakshmi Yadlapatia5409992023-04-20 16:53:59 -0500514inline void afterGetValidPcieDevicePath(
515 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
516 const std::string& pcieDeviceId, const std::string& pcieDevicePath,
517 const std::string& service)
518{
519 addPCIeDeviceCommonProperties(asyncResp, pcieDeviceId);
520 getPCIeDeviceAsset(asyncResp, pcieDevicePath, service);
521 getPCIeDeviceState(asyncResp, pcieDevicePath, service);
522 getPCIeDeviceHealth(asyncResp, pcieDevicePath, service);
523 getPCIeDeviceProperties(
524 asyncResp, pcieDevicePath, service,
525 std::bind_front(addPCIeDeviceProperties, asyncResp, pcieDeviceId));
526 getPCIeDeviceSlotPath(
527 pcieDevicePath, asyncResp,
528 std::bind_front(afterGetPCIeDeviceSlotPath, asyncResp));
529}
530
Ed Tanousac106bf2023-06-07 09:24:59 -0700531inline void
532 handlePCIeDeviceGet(App& app, const crow::Request& req,
533 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
534 const std::string& systemName,
535 const std::string& pcieDeviceId)
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600536{
Ed Tanousac106bf2023-06-07 09:24:59 -0700537 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600538 {
539 return;
540 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -0800541 if constexpr (bmcwebEnableMultiHost)
542 {
543 // Option currently returns no systems. TBD
544 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
545 systemName);
546 return;
547 }
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600548 if (systemName != "system")
549 {
Ed Tanousac106bf2023-06-07 09:24:59 -0700550 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
551 systemName);
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600552 return;
553 }
554
555 getValidPCIeDevicePath(
Ed Tanousac106bf2023-06-07 09:24:59 -0700556 pcieDeviceId, asyncResp,
Lakshmi Yadlapatia5409992023-04-20 16:53:59 -0500557 std::bind_front(afterGetValidPcieDevicePath, asyncResp, pcieDeviceId));
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600558}
559
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700560inline void requestRoutesSystemPCIeDevice(App& app)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800561{
Ed Tanous22d268c2022-05-19 09:39:07 -0700562 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700563 .privileges(redfish::privileges::getPCIeDevice)
Ed Tanous002d39b2022-05-31 08:59:27 -0700564 .methods(boost::beast::http::verb::get)(
Lakshmi Yadlapati543f9a72023-03-10 17:06:05 -0600565 std::bind_front(handlePCIeDeviceGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700566}
567
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600568inline void addPCIeFunctionList(
569 crow::Response& res, const std::string& pcieDeviceId,
570 const dbus::utility::DBusPropertiesMap& pcieDevProperties)
571{
572 nlohmann::json& pcieFunctionList = res.jsonValue["Members"];
573 pcieFunctionList = nlohmann::json::array();
574 static constexpr const int maxPciFunctionNum = 8;
575
576 for (int functionNum = 0; functionNum < maxPciFunctionNum; functionNum++)
577 {
578 // Check if this function exists by
579 // looking for a device ID
Patrick Williams89492a12023-05-10 07:51:34 -0500580 std::string devIDProperty = "Function" + std::to_string(functionNum) +
581 "DeviceId";
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600582 const std::string* property = nullptr;
583 for (const auto& propEntry : pcieDevProperties)
584 {
585 if (propEntry.first == devIDProperty)
586 {
587 property = std::get_if<std::string>(&propEntry.second);
588 break;
589 }
590 }
591 if (property == nullptr || property->empty())
592 {
593 continue;
594 }
595
596 nlohmann::json::object_t pcieFunction;
Ed Tanousef4c65b2023-04-24 15:28:50 -0700597 pcieFunction["@odata.id"] = boost::urls::format(
598 "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions/{}",
599 pcieDeviceId, std::to_string(functionNum));
Patrick Williamsb2ba3072023-05-12 10:27:39 -0500600 pcieFunctionList.emplace_back(std::move(pcieFunction));
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600601 }
602 res.jsonValue["PCIeFunctions@odata.count"] = pcieFunctionList.size();
603}
604
605inline void handlePCIeFunctionCollectionGet(
606 App& app, const crow::Request& req,
Ed Tanousac106bf2023-06-07 09:24:59 -0700607 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous7f3e84a2022-12-28 16:22:54 -0800608 const std::string& systemName, const std::string& pcieDeviceId)
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600609{
Ed Tanousac106bf2023-06-07 09:24:59 -0700610 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600611 {
612 return;
613 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -0800614 if constexpr (bmcwebEnableMultiHost)
615 {
616 // Option currently returns no systems. TBD
617 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
618 systemName);
619 return;
620 }
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600621
622 getValidPCIeDevicePath(
Ed Tanousac106bf2023-06-07 09:24:59 -0700623 pcieDeviceId, asyncResp,
624 [asyncResp, pcieDeviceId](const std::string& pcieDevicePath,
625 const std::string& service) {
626 asyncResp->res.addHeader(
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600627 boost::beast::http::field::link,
628 "</redfish/v1/JsonSchemas/PCIeFunctionCollection/PCIeFunctionCollection.json>; rel=describedby");
Ed Tanousac106bf2023-06-07 09:24:59 -0700629 asyncResp->res.jsonValue["@odata.type"] =
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600630 "#PCIeFunctionCollection.PCIeFunctionCollection";
Ed Tanousac106bf2023-06-07 09:24:59 -0700631 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
Ed Tanousef4c65b2023-04-24 15:28:50 -0700632 "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions",
633 pcieDeviceId);
Ed Tanousac106bf2023-06-07 09:24:59 -0700634 asyncResp->res.jsonValue["Name"] = "PCIe Function Collection";
635 asyncResp->res.jsonValue["Description"] =
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600636 "Collection of PCIe Functions for PCIe Device " + pcieDeviceId;
637 getPCIeDeviceProperties(
Ed Tanousac106bf2023-06-07 09:24:59 -0700638 asyncResp, pcieDevicePath, service,
639 [asyncResp, pcieDeviceId](
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600640 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
Ed Tanousac106bf2023-06-07 09:24:59 -0700641 addPCIeFunctionList(asyncResp->res, pcieDeviceId,
642 pcieDevProperties);
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600643 });
644 });
645}
646
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700647inline void requestRoutesSystemPCIeFunctionCollection(App& app)
648{
649 /**
650 * Functions triggers appropriate requests on DBus
651 */
652 BMCWEB_ROUTE(app,
Ed Tanous7f3e84a2022-12-28 16:22:54 -0800653 "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/")
Ed Tanoused398212021-06-09 17:05:54 -0700654 .privileges(redfish::privileges::getPCIeFunctionCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -0700655 .methods(boost::beast::http::verb::get)(
Lakshmi Yadlapati35ad6132023-03-10 22:31:49 -0600656 std::bind_front(handlePCIeFunctionCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700657}
658
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600659inline bool validatePCIeFunctionId(
Myung Baed5e74b82023-05-31 11:28:02 -0500660 uint64_t pcieFunctionId,
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600661 const dbus::utility::DBusPropertiesMap& pcieDevProperties)
662{
Myung Baed5e74b82023-05-31 11:28:02 -0500663 std::string functionName = "Function" + std::to_string(pcieFunctionId);
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600664 std::string devIDProperty = functionName + "DeviceId";
665
666 const std::string* devIdProperty = nullptr;
667 for (const auto& property : pcieDevProperties)
668 {
669 if (property.first == devIDProperty)
670 {
671 devIdProperty = std::get_if<std::string>(&property.second);
672 break;
673 }
674 }
675 return (devIdProperty != nullptr && !devIdProperty->empty());
676}
677
678inline void addPCIeFunctionProperties(
Ed Tanouse14742c2023-05-31 10:27:49 -0700679 crow::Response& resp, uint64_t pcieFunctionId,
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600680 const dbus::utility::DBusPropertiesMap& pcieDevProperties)
681{
Ed Tanouse14742c2023-05-31 10:27:49 -0700682 std::string functionName = "Function" + std::to_string(pcieFunctionId);
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600683 for (const auto& property : pcieDevProperties)
684 {
685 const std::string* strProperty =
686 std::get_if<std::string>(&property.second);
687
688 if (property.first == functionName + "DeviceId")
689 {
690 resp.jsonValue["DeviceId"] = *strProperty;
691 }
692 if (property.first == functionName + "VendorId")
693 {
694 resp.jsonValue["VendorId"] = *strProperty;
695 }
696 // TODO: FunctionType and DeviceClass are Redfish enums. The D-Bus
697 // property strings should be mapped correctly to ensure these
698 // strings are Redfish enum values. For now just check for empty.
699 if (property.first == functionName + "FunctionType")
700 {
701 if (!strProperty->empty())
702 {
703 resp.jsonValue["FunctionType"] = *strProperty;
704 }
705 }
706 if (property.first == functionName + "DeviceClass")
707 {
708 if (!strProperty->empty())
709 {
710 resp.jsonValue["DeviceClass"] = *strProperty;
711 }
712 }
713 if (property.first == functionName + "ClassCode")
714 {
715 resp.jsonValue["ClassCode"] = *strProperty;
716 }
717 if (property.first == functionName + "RevisionId")
718 {
719 resp.jsonValue["RevisionId"] = *strProperty;
720 }
721 if (property.first == functionName + "SubsystemId")
722 {
723 resp.jsonValue["SubsystemId"] = *strProperty;
724 }
725 if (property.first == functionName + "SubsystemVendorId")
726 {
727 resp.jsonValue["SubsystemVendorId"] = *strProperty;
728 }
729 }
730}
731
732inline void addPCIeFunctionCommonProperties(crow::Response& resp,
733 const std::string& pcieDeviceId,
Ed Tanouse14742c2023-05-31 10:27:49 -0700734 uint64_t pcieFunctionId)
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600735{
736 resp.addHeader(
737 boost::beast::http::field::link,
738 "</redfish/v1/JsonSchemas/PCIeFunction/PCIeFunction.json>; rel=describedby");
739 resp.jsonValue["@odata.type"] = "#PCIeFunction.v1_2_3.PCIeFunction";
Ed Tanousef4c65b2023-04-24 15:28:50 -0700740 resp.jsonValue["@odata.id"] = boost::urls::format(
741 "/redfish/v1/Systems/system/PCIeDevices/{}/PCIeFunctions/{}",
Lakshmi Yadlapati768a1432023-06-14 12:45:54 -0500742 pcieDeviceId, std::to_string(pcieFunctionId));
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600743 resp.jsonValue["Name"] = "PCIe Function";
Ed Tanouse14742c2023-05-31 10:27:49 -0700744 resp.jsonValue["Id"] = std::to_string(pcieFunctionId);
745 resp.jsonValue["FunctionId"] = pcieFunctionId;
Ed Tanousef4c65b2023-04-24 15:28:50 -0700746 resp.jsonValue["Links"]["PCIeDevice"]["@odata.id"] = boost::urls::format(
747 "/redfish/v1/Systems/system/PCIeDevices/{}", pcieDeviceId);
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600748}
749
750inline void
751 handlePCIeFunctionGet(App& app, const crow::Request& req,
Ed Tanousac106bf2023-06-07 09:24:59 -0700752 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous7f3e84a2022-12-28 16:22:54 -0800753 const std::string& systemName,
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600754 const std::string& pcieDeviceId,
Ed Tanouse14742c2023-05-31 10:27:49 -0700755 const std::string& pcieFunctionIdStr)
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600756{
Ed Tanousac106bf2023-06-07 09:24:59 -0700757 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600758 {
759 return;
760 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -0800761 if constexpr (bmcwebEnableMultiHost)
762 {
763 // Option currently returns no systems. TBD
764 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
765 systemName);
766 return;
767 }
768 if (systemName != "system")
769 {
770 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
771 systemName);
772 return;
773 }
774
Ed Tanouse14742c2023-05-31 10:27:49 -0700775 uint64_t pcieFunctionId = 0;
776 std::from_chars_result result = std::from_chars(
777 &*pcieFunctionIdStr.begin(), &*pcieFunctionIdStr.end(), pcieFunctionId);
778 if (result.ec != std::errc{} || result.ptr != &*pcieFunctionIdStr.end())
779 {
Ed Tanousac106bf2023-06-07 09:24:59 -0700780 messages::resourceNotFound(asyncResp->res, "PCIeFunction",
Ed Tanouse14742c2023-05-31 10:27:49 -0700781 pcieFunctionIdStr);
782 return;
783 }
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600784
Ed Tanousac106bf2023-06-07 09:24:59 -0700785 getValidPCIeDevicePath(pcieDeviceId, asyncResp,
786 [asyncResp, pcieDeviceId,
787 pcieFunctionId](const std::string& pcieDevicePath,
788 const std::string& service) {
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600789 getPCIeDeviceProperties(
Ed Tanousac106bf2023-06-07 09:24:59 -0700790 asyncResp, pcieDevicePath, service,
791 [asyncResp, pcieDeviceId, pcieFunctionId](
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600792 const dbus::utility::DBusPropertiesMap& pcieDevProperties) {
Ed Tanousac106bf2023-06-07 09:24:59 -0700793 addPCIeFunctionCommonProperties(asyncResp->res, pcieDeviceId,
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600794 pcieFunctionId);
Ed Tanousac106bf2023-06-07 09:24:59 -0700795 addPCIeFunctionProperties(asyncResp->res, pcieFunctionId,
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600796 pcieDevProperties);
797 });
Ed Tanousac106bf2023-06-07 09:24:59 -0700798 });
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600799}
800
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700801inline void requestRoutesSystemPCIeFunction(App& app)
802{
803 BMCWEB_ROUTE(
Ed Tanous7f3e84a2022-12-28 16:22:54 -0800804 app, "/redfish/v1/Systems/<str>/PCIeDevices/<str>/PCIeFunctions/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700805 .privileges(redfish::privileges::getPCIeFunction)
Ed Tanous002d39b2022-05-31 08:59:27 -0700806 .methods(boost::beast::http::verb::get)(
Lakshmi Yadlapati727a0462023-03-10 23:49:00 -0600807 std::bind_front(handlePCIeFunctionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700808}
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800809
810} // namespace redfish