blob: 0a8aa981890afa92296419313bc6c6f2535fb20f [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
19#include "node.hpp"
20
21#include <boost/system/linux_error.hpp>
22
23namespace redfish
24{
25
Gunnar Mills1214b7e2020-06-04 10:11:30 -050026static constexpr char const* pcieService = "xyz.openbmc_project.PCIe";
27static constexpr char const* pciePath = "/xyz/openbmc_project/PCIe";
28static constexpr char const* pcieDeviceInterface =
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080029 "xyz.openbmc_project.PCIe.Device";
30
Ed Tanousb5a76932020-09-29 16:16:58 -070031static inline void
32 getPCIeDeviceList(const std::shared_ptr<AsyncResp>& asyncResp,
33 const std::string& name)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080034{
Jason M. Billsadbe1922019-10-14 15:44:35 -070035 auto getPCIeMapCallback = [asyncResp, name](
36 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -050037 std::vector<std::string>& pcieDevicePaths) {
Jason M. Billsadbe1922019-10-14 15:44:35 -070038 if (ec)
39 {
40 BMCWEB_LOG_DEBUG << "no PCIe device paths found ec: "
41 << ec.message();
42 // Not an error, system just doesn't have PCIe info
43 return;
44 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -050045 nlohmann::json& pcieDeviceList = asyncResp->res.jsonValue[name];
Jason M. Billsadbe1922019-10-14 15:44:35 -070046 pcieDeviceList = nlohmann::json::array();
Gunnar Mills1214b7e2020-06-04 10:11:30 -050047 for (const std::string& pcieDevicePath : pcieDevicePaths)
Jason M. Billsadbe1922019-10-14 15:44:35 -070048 {
Ed Tanous3174e4d2020-10-07 11:41:22 -070049 size_t devStart = pcieDevicePath.rfind('/');
Jason M. Billsadbe1922019-10-14 15:44:35 -070050 if (devStart == std::string::npos)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080051 {
Jason M. Billsadbe1922019-10-14 15:44:35 -070052 continue;
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080053 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080054
Jason M. Billsadbe1922019-10-14 15:44:35 -070055 std::string devName = pcieDevicePath.substr(devStart + 1);
56 if (devName.empty())
57 {
58 continue;
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080059 }
Jason M. Billsadbe1922019-10-14 15:44:35 -070060 pcieDeviceList.push_back(
61 {{"@odata.id",
62 "/redfish/v1/Systems/system/PCIeDevices/" + devName}});
63 }
64 asyncResp->res.jsonValue[name + "@odata.count"] = pcieDeviceList.size();
65 };
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080066 crow::connections::systemBus->async_method_call(
67 std::move(getPCIeMapCallback), "xyz.openbmc_project.ObjectMapper",
68 "/xyz/openbmc_project/object_mapper",
69 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
70 std::string(pciePath) + "/", 1, std::array<std::string, 0>());
71}
72
Jason M. Billsadbe1922019-10-14 15:44:35 -070073class SystemPCIeDeviceCollection : public Node
74{
75 public:
Ed Tanous52cc1122020-07-18 13:51:21 -070076 SystemPCIeDeviceCollection(App& app) :
Jason M. Billsadbe1922019-10-14 15:44:35 -070077 Node(app, "/redfish/v1/Systems/system/PCIeDevices/")
78 {
79 entityPrivileges = {
80 {boost::beast::http::verb::get, {{"Login"}}},
81 {boost::beast::http::verb::head, {{"Login"}}},
82 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
83 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
84 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
85 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
86 }
87
88 private:
89 /**
90 * Functions triggers appropriate requests on DBus
91 */
Ed Tanouscb13a392020-07-25 19:02:03 +000092 void doGet(crow::Response& res, const crow::Request&,
93 const std::vector<std::string>&) override
Jason M. Billsadbe1922019-10-14 15:44:35 -070094 {
95 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
96 asyncResp->res.jsonValue = {
97 {"@odata.type", "#PCIeDeviceCollection.PCIeDeviceCollection"},
Jason M. Billsadbe1922019-10-14 15:44:35 -070098 {"@odata.id", "/redfish/v1/Systems/system/PCIeDevices"},
99 {"Name", "PCIe Device Collection"},
100 {"Description", "Collection of PCIe Devices"},
101 {"Members", nlohmann::json::array()},
102 {"Members@odata.count", 0}};
103 getPCIeDeviceList(asyncResp, "Members");
104 }
105};
106
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800107class SystemPCIeDevice : public Node
108{
109 public:
Ed Tanous52cc1122020-07-18 13:51:21 -0700110 SystemPCIeDevice(App& app) :
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800111 Node(app, "/redfish/v1/Systems/system/PCIeDevices/<str>/",
112 std::string())
113 {
114 entityPrivileges = {
115 {boost::beast::http::verb::get, {{"Login"}}},
116 {boost::beast::http::verb::head, {{"Login"}}},
117 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
118 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
119 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
120 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
121 }
122
123 private:
Ed Tanouscb13a392020-07-25 19:02:03 +0000124 void doGet(crow::Response& res, const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500125 const std::vector<std::string>& params) override
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800126 {
127 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
128 if (params.size() != 1)
129 {
130 messages::internalError(asyncResp->res);
131 return;
132 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500133 const std::string& device = params[0];
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800134
135 auto getPCIeDeviceCallback =
136 [asyncResp,
137 device](const boost::system::error_code ec,
Patrick Williams19bd78d2020-05-13 17:38:24 -0500138 boost::container::flat_map<std::string,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500139 std::variant<std::string>>&
140 pcieDevProperties) {
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800141 if (ec)
142 {
143 BMCWEB_LOG_DEBUG
144 << "failed to get PCIe Device properties ec: "
Ed Tanous271584a2019-07-09 16:24:22 -0700145 << ec.value() << ": " << ec.message();
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800146 if (ec.value() ==
147 boost::system::linux_error::bad_request_descriptor)
148 {
149 messages::resourceNotFound(asyncResp->res, "PCIeDevice",
150 device);
151 }
152 else
153 {
154 messages::internalError(asyncResp->res);
155 }
156 return;
157 }
158
159 asyncResp->res.jsonValue = {
Jason M. Billsdede6a92019-10-14 15:41:30 -0700160 {"@odata.type", "#PCIeDevice.v1_4_0.PCIeDevice"},
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800161 {"@odata.id",
162 "/redfish/v1/Systems/system/PCIeDevices/" + device},
163 {"Name", "PCIe Device"},
164 {"Id", device}};
165
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500166 if (std::string* property = std::get_if<std::string>(
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500167 &pcieDevProperties["Manufacturer"]);
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800168 property)
169 {
170 asyncResp->res.jsonValue["Manufacturer"] = *property;
171 }
172
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500173 if (std::string* property = std::get_if<std::string>(
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500174 &pcieDevProperties["DeviceType"]);
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800175 property)
176 {
177 asyncResp->res.jsonValue["DeviceType"] = *property;
178 }
179
Jason M. Billsdede6a92019-10-14 15:41:30 -0700180 asyncResp->res.jsonValue["PCIeFunctions"] = {
181 {"@odata.id", "/redfish/v1/Systems/system/PCIeDevices/" +
182 device + "/PCIeFunctions"}};
183 };
184 std::string escapedPath = std::string(pciePath) + "/" + device;
185 dbus::utility::escapePathForDbus(escapedPath);
186 crow::connections::systemBus->async_method_call(
187 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
188 "org.freedesktop.DBus.Properties", "GetAll", pcieDeviceInterface);
189 }
190};
191
192class SystemPCIeFunctionCollection : public Node
193{
194 public:
Ed Tanous52cc1122020-07-18 13:51:21 -0700195 SystemPCIeFunctionCollection(App& app) :
Jason M. Billsdede6a92019-10-14 15:41:30 -0700196 Node(app, "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/",
197 std::string())
198 {
199 entityPrivileges = {
200 {boost::beast::http::verb::get, {{"Login"}}},
201 {boost::beast::http::verb::head, {{"Login"}}},
202 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
203 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
204 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
205 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
206 }
207
208 private:
209 /**
210 * Functions triggers appropriate requests on DBus
211 */
Ed Tanouscb13a392020-07-25 19:02:03 +0000212 void doGet(crow::Response& res, const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500213 const std::vector<std::string>& params) override
Jason M. Billsdede6a92019-10-14 15:41:30 -0700214 {
215 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
216 if (params.size() != 1)
217 {
218 messages::internalError(asyncResp->res);
219 return;
220 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500221 const std::string& device = params[0];
Jason M. Billsdede6a92019-10-14 15:41:30 -0700222 asyncResp->res.jsonValue = {
223 {"@odata.type", "#PCIeFunctionCollection.PCIeFunctionCollection"},
Jason M. Billsdede6a92019-10-14 15:41:30 -0700224 {"@odata.id", "/redfish/v1/Systems/system/PCIeDevices/" + device +
225 "/PCIeFunctions"},
226 {"Name", "PCIe Function Collection"},
227 {"Description",
228 "Collection of PCIe Functions for PCIe Device " + device}};
229
230 auto getPCIeDeviceCallback =
231 [asyncResp,
232 device](const boost::system::error_code ec,
Patrick Williams19bd78d2020-05-13 17:38:24 -0500233 boost::container::flat_map<std::string,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500234 std::variant<std::string>>&
235 pcieDevProperties) {
Jason M. Billsdede6a92019-10-14 15:41:30 -0700236 if (ec)
237 {
238 BMCWEB_LOG_DEBUG
239 << "failed to get PCIe Device properties ec: "
240 << ec.value() << ": " << ec.message();
241 if (ec.value() ==
242 boost::system::linux_error::bad_request_descriptor)
243 {
244 messages::resourceNotFound(asyncResp->res, "PCIeDevice",
245 device);
246 }
247 else
248 {
249 messages::internalError(asyncResp->res);
250 }
251 return;
252 }
253
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500254 nlohmann::json& pcieFunctionList =
Jason M. Billsdede6a92019-10-14 15:41:30 -0700255 asyncResp->res.jsonValue["Members"];
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800256 pcieFunctionList = nlohmann::json::array();
257 static constexpr const int maxPciFunctionNum = 8;
258 for (int functionNum = 0; functionNum < maxPciFunctionNum;
259 functionNum++)
260 {
261 // Check if this function exists by looking for a device ID
262 std::string devIDProperty =
263 "Function" + std::to_string(functionNum) + "DeviceId";
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500264 std::string* property = std::get_if<std::string>(
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500265 &pcieDevProperties[devIDProperty]);
Jason M. Billsdede6a92019-10-14 15:41:30 -0700266 if (property && !property->empty())
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800267 {
268 pcieFunctionList.push_back(
269 {{"@odata.id",
270 "/redfish/v1/Systems/system/PCIeDevices/" +
271 device + "/PCIeFunctions/" +
272 std::to_string(functionNum)}});
273 }
274 }
Jason M. Billsdede6a92019-10-14 15:41:30 -0700275 asyncResp->res.jsonValue["PCIeFunctions@odata.count"] =
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800276 pcieFunctionList.size();
277 };
278 std::string escapedPath = std::string(pciePath) + "/" + device;
279 dbus::utility::escapePathForDbus(escapedPath);
280 crow::connections::systemBus->async_method_call(
281 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
282 "org.freedesktop.DBus.Properties", "GetAll", pcieDeviceInterface);
283 }
284};
285
286class SystemPCIeFunction : public Node
287{
288 public:
Ed Tanous52cc1122020-07-18 13:51:21 -0700289 SystemPCIeFunction(App& app) :
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800290 Node(
291 app,
292 "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/<str>/",
293 std::string(), std::string())
294 {
295 entityPrivileges = {
296 {boost::beast::http::verb::get, {{"Login"}}},
297 {boost::beast::http::verb::head, {{"Login"}}},
298 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
299 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
300 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
301 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
302 }
303
304 private:
Ed Tanouscb13a392020-07-25 19:02:03 +0000305 void doGet(crow::Response& res, const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500306 const std::vector<std::string>& params) override
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800307 {
308 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
309 if (params.size() != 2)
310 {
311 messages::internalError(asyncResp->res);
312 return;
313 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500314 const std::string& device = params[0];
315 const std::string& function = params[1];
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800316
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500317 auto getPCIeDeviceCallback = [asyncResp, device, function](
318 const boost::system::error_code ec,
319 boost::container::flat_map<
320 std::string,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500321 std::variant<std::string>>&
322 pcieDevProperties) {
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500323 if (ec)
324 {
325 BMCWEB_LOG_DEBUG
326 << "failed to get PCIe Device properties ec: " << ec.value()
327 << ": " << ec.message();
328 if (ec.value() ==
329 boost::system::linux_error::bad_request_descriptor)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800330 {
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500331 messages::resourceNotFound(asyncResp->res, "PCIeDevice",
332 device);
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800333 }
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500334 else
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800335 {
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500336 messages::internalError(asyncResp->res);
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800337 }
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500338 return;
339 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800340
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500341 // Check if this function exists by looking for a device ID
342 std::string devIDProperty = "Function" + function + "DeviceId";
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500343 if (std::string* property =
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500344 std::get_if<std::string>(&pcieDevProperties[devIDProperty]);
345 property && property->empty())
346 {
347 messages::resourceNotFound(asyncResp->res, "PCIeFunction",
348 function);
349 return;
350 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800351
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500352 asyncResp->res.jsonValue = {
353 {"@odata.type", "#PCIeFunction.v1_2_0.PCIeFunction"},
354 {"@odata.id", "/redfish/v1/Systems/system/PCIeDevices/" +
355 device + "/PCIeFunctions/" + function},
356 {"Name", "PCIe Function"},
357 {"Id", function},
358 {"FunctionId", std::stoi(function)},
359 {"Links",
360 {{"PCIeDevice",
361 {{"@odata.id",
362 "/redfish/v1/Systems/system/PCIeDevices/" + device}}}}}};
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800363
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500364 if (std::string* property = std::get_if<std::string>(
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500365 &pcieDevProperties["Function" + function + "DeviceId"]);
366 property)
367 {
368 asyncResp->res.jsonValue["DeviceId"] = *property;
369 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800370
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500371 if (std::string* property = std::get_if<std::string>(
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500372 &pcieDevProperties["Function" + function + "VendorId"]);
373 property)
374 {
375 asyncResp->res.jsonValue["VendorId"] = *property;
376 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800377
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500378 if (std::string* property = std::get_if<std::string>(
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500379 &pcieDevProperties["Function" + function + "FunctionType"]);
380 property)
381 {
382 asyncResp->res.jsonValue["FunctionType"] = *property;
383 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800384
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500385 if (std::string* property = std::get_if<std::string>(
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500386 &pcieDevProperties["Function" + function + "DeviceClass"]);
387 property)
388 {
389 asyncResp->res.jsonValue["DeviceClass"] = *property;
390 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800391
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500392 if (std::string* property = std::get_if<std::string>(
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500393 &pcieDevProperties["Function" + function + "ClassCode"]);
394 property)
395 {
396 asyncResp->res.jsonValue["ClassCode"] = *property;
397 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800398
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500399 if (std::string* property = std::get_if<std::string>(
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500400 &pcieDevProperties["Function" + function + "RevisionId"]);
401 property)
402 {
403 asyncResp->res.jsonValue["RevisionId"] = *property;
404 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800405
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500406 if (std::string* property = std::get_if<std::string>(
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500407 &pcieDevProperties["Function" + function + "SubsystemId"]);
408 property)
409 {
410 asyncResp->res.jsonValue["SubsystemId"] = *property;
411 }
412
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500413 if (std::string* property = std::get_if<std::string>(
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500414 &pcieDevProperties["Function" + function +
415 "SubsystemVendorId"]);
416 property)
417 {
418 asyncResp->res.jsonValue["SubsystemVendorId"] = *property;
419 }
420 };
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800421 std::string escapedPath = std::string(pciePath) + "/" + device;
422 dbus::utility::escapePathForDbus(escapedPath);
423 crow::connections::systemBus->async_method_call(
424 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
425 "org.freedesktop.DBus.Properties", "GetAll", pcieDeviceInterface);
426 }
427};
428
429} // namespace redfish