blob: 36248a1ad7e165362cf252dc6d1a6d74cf123f60 [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
26static constexpr char const *pcieService = "xyz.openbmc_project.PCIe";
27static constexpr char const *pciePath = "/xyz/openbmc_project/PCIe";
28static constexpr char const *pcieDeviceInterface =
29 "xyz.openbmc_project.PCIe.Device";
30
Jason M. Billsadbe1922019-10-14 15:44:35 -070031static inline void getPCIeDeviceList(std::shared_ptr<AsyncResp> asyncResp,
32 const std::string &name)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080033{
Jason M. Billsadbe1922019-10-14 15:44:35 -070034 auto getPCIeMapCallback = [asyncResp, name](
35 const boost::system::error_code ec,
36 std::vector<std::string> &pcieDevicePaths) {
37 if (ec)
38 {
39 BMCWEB_LOG_DEBUG << "no PCIe device paths found ec: "
40 << ec.message();
41 // Not an error, system just doesn't have PCIe info
42 return;
43 }
44 nlohmann::json &pcieDeviceList = asyncResp->res.jsonValue[name];
45 pcieDeviceList = nlohmann::json::array();
46 for (const std::string &pcieDevicePath : pcieDevicePaths)
47 {
48 size_t devStart = pcieDevicePath.rfind("/");
49 if (devStart == std::string::npos)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080050 {
Jason M. Billsadbe1922019-10-14 15:44:35 -070051 continue;
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080052 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080053
Jason M. Billsadbe1922019-10-14 15:44:35 -070054 std::string devName = pcieDevicePath.substr(devStart + 1);
55 if (devName.empty())
56 {
57 continue;
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080058 }
Jason M. Billsadbe1922019-10-14 15:44:35 -070059 pcieDeviceList.push_back(
60 {{"@odata.id",
61 "/redfish/v1/Systems/system/PCIeDevices/" + devName}});
62 }
63 asyncResp->res.jsonValue[name + "@odata.count"] = pcieDeviceList.size();
64 };
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080065 crow::connections::systemBus->async_method_call(
66 std::move(getPCIeMapCallback), "xyz.openbmc_project.ObjectMapper",
67 "/xyz/openbmc_project/object_mapper",
68 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
69 std::string(pciePath) + "/", 1, std::array<std::string, 0>());
70}
71
Jason M. Billsadbe1922019-10-14 15:44:35 -070072class SystemPCIeDeviceCollection : public Node
73{
74 public:
75 template <typename CrowApp>
76 SystemPCIeDeviceCollection(CrowApp &app) :
77 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 */
92 void doGet(crow::Response &res, const crow::Request &req,
93 const std::vector<std::string> &params) override
94 {
95 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
96 asyncResp->res.jsonValue = {
97 {"@odata.type", "#PCIeDeviceCollection.PCIeDeviceCollection"},
98 {"@odata.context",
99 "/redfish/v1/"
100 "$metadata#PCIeDeviceCollection.PCIeDeviceCollection"},
101 {"@odata.id", "/redfish/v1/Systems/system/PCIeDevices"},
102 {"Name", "PCIe Device Collection"},
103 {"Description", "Collection of PCIe Devices"},
104 {"Members", nlohmann::json::array()},
105 {"Members@odata.count", 0}};
106 getPCIeDeviceList(asyncResp, "Members");
107 }
108};
109
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800110class SystemPCIeDevice : public Node
111{
112 public:
113 SystemPCIeDevice(CrowApp &app) :
114 Node(app, "/redfish/v1/Systems/system/PCIeDevices/<str>/",
115 std::string())
116 {
117 entityPrivileges = {
118 {boost::beast::http::verb::get, {{"Login"}}},
119 {boost::beast::http::verb::head, {{"Login"}}},
120 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
121 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
122 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
123 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
124 }
125
126 private:
127 void doGet(crow::Response &res, const crow::Request &req,
128 const std::vector<std::string> &params) override
129 {
130 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
131 if (params.size() != 1)
132 {
133 messages::internalError(asyncResp->res);
134 return;
135 }
136 const std::string &device = params[0];
137
138 auto getPCIeDeviceCallback =
139 [asyncResp,
140 device](const boost::system::error_code ec,
141 boost::container::flat_map<
142 std::string, sdbusplus::message::variant<std::string>>
143 &pcieDevProperties) {
144 if (ec)
145 {
146 BMCWEB_LOG_DEBUG
147 << "failed to get PCIe Device properties ec: "
Ed Tanous271584a2019-07-09 16:24:22 -0700148 << ec.value() << ": " << ec.message();
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800149 if (ec.value() ==
150 boost::system::linux_error::bad_request_descriptor)
151 {
152 messages::resourceNotFound(asyncResp->res, "PCIeDevice",
153 device);
154 }
155 else
156 {
157 messages::internalError(asyncResp->res);
158 }
159 return;
160 }
161
162 asyncResp->res.jsonValue = {
Jason M. Billsdede6a92019-10-14 15:41:30 -0700163 {"@odata.type", "#PCIeDevice.v1_4_0.PCIeDevice"},
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800164 {"@odata.context",
Jason M. Billsdede6a92019-10-14 15:41:30 -0700165 "/redfish/v1/$metadata#PCIeDevice.v1_4_0.PCIeDevice"},
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800166 {"@odata.id",
167 "/redfish/v1/Systems/system/PCIeDevices/" + device},
168 {"Name", "PCIe Device"},
169 {"Id", device}};
170
171 if (std::string *property =
172 sdbusplus::message::variant_ns::get_if<std::string>(
173 &pcieDevProperties["Manufacturer"]);
174 property)
175 {
176 asyncResp->res.jsonValue["Manufacturer"] = *property;
177 }
178
179 if (std::string *property =
180 sdbusplus::message::variant_ns::get_if<std::string>(
181 &pcieDevProperties["DeviceType"]);
182 property)
183 {
184 asyncResp->res.jsonValue["DeviceType"] = *property;
185 }
186
Jason M. Billsdede6a92019-10-14 15:41:30 -0700187 asyncResp->res.jsonValue["PCIeFunctions"] = {
188 {"@odata.id", "/redfish/v1/Systems/system/PCIeDevices/" +
189 device + "/PCIeFunctions"}};
190 };
191 std::string escapedPath = std::string(pciePath) + "/" + device;
192 dbus::utility::escapePathForDbus(escapedPath);
193 crow::connections::systemBus->async_method_call(
194 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
195 "org.freedesktop.DBus.Properties", "GetAll", pcieDeviceInterface);
196 }
197};
198
199class SystemPCIeFunctionCollection : public Node
200{
201 public:
202 template <typename CrowApp>
203 SystemPCIeFunctionCollection(CrowApp &app) :
204 Node(app, "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/",
205 std::string())
206 {
207 entityPrivileges = {
208 {boost::beast::http::verb::get, {{"Login"}}},
209 {boost::beast::http::verb::head, {{"Login"}}},
210 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
211 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
212 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
213 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
214 }
215
216 private:
217 /**
218 * Functions triggers appropriate requests on DBus
219 */
220 void doGet(crow::Response &res, const crow::Request &req,
221 const std::vector<std::string> &params) override
222 {
223 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
224 if (params.size() != 1)
225 {
226 messages::internalError(asyncResp->res);
227 return;
228 }
229 const std::string &device = params[0];
230 asyncResp->res.jsonValue = {
231 {"@odata.type", "#PCIeFunctionCollection.PCIeFunctionCollection"},
232 {"@odata.context",
233 "/redfish/v1/"
234 "$metadata#PCIeFunctionCollection.PCIeFunctionCollection"},
235 {"@odata.id", "/redfish/v1/Systems/system/PCIeDevices/" + device +
236 "/PCIeFunctions"},
237 {"Name", "PCIe Function Collection"},
238 {"Description",
239 "Collection of PCIe Functions for PCIe Device " + device}};
240
241 auto getPCIeDeviceCallback =
242 [asyncResp,
243 device](const boost::system::error_code ec,
244 boost::container::flat_map<
245 std::string, sdbusplus::message::variant<std::string>>
246 &pcieDevProperties) {
247 if (ec)
248 {
249 BMCWEB_LOG_DEBUG
250 << "failed to get PCIe Device properties ec: "
251 << ec.value() << ": " << ec.message();
252 if (ec.value() ==
253 boost::system::linux_error::bad_request_descriptor)
254 {
255 messages::resourceNotFound(asyncResp->res, "PCIeDevice",
256 device);
257 }
258 else
259 {
260 messages::internalError(asyncResp->res);
261 }
262 return;
263 }
264
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800265 nlohmann::json &pcieFunctionList =
Jason M. Billsdede6a92019-10-14 15:41:30 -0700266 asyncResp->res.jsonValue["Members"];
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800267 pcieFunctionList = nlohmann::json::array();
268 static constexpr const int maxPciFunctionNum = 8;
269 for (int functionNum = 0; functionNum < maxPciFunctionNum;
270 functionNum++)
271 {
272 // Check if this function exists by looking for a device ID
273 std::string devIDProperty =
274 "Function" + std::to_string(functionNum) + "DeviceId";
Jason M. Billsdede6a92019-10-14 15:41:30 -0700275 std::string *property =
276 sdbusplus::message::variant_ns::get_if<std::string>(
277 &pcieDevProperties[devIDProperty]);
278 if (property && !property->empty())
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800279 {
280 pcieFunctionList.push_back(
281 {{"@odata.id",
282 "/redfish/v1/Systems/system/PCIeDevices/" +
283 device + "/PCIeFunctions/" +
284 std::to_string(functionNum)}});
285 }
286 }
Jason M. Billsdede6a92019-10-14 15:41:30 -0700287 asyncResp->res.jsonValue["PCIeFunctions@odata.count"] =
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800288 pcieFunctionList.size();
289 };
290 std::string escapedPath = std::string(pciePath) + "/" + device;
291 dbus::utility::escapePathForDbus(escapedPath);
292 crow::connections::systemBus->async_method_call(
293 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
294 "org.freedesktop.DBus.Properties", "GetAll", pcieDeviceInterface);
295 }
296};
297
298class SystemPCIeFunction : public Node
299{
300 public:
301 SystemPCIeFunction(CrowApp &app) :
302 Node(
303 app,
304 "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/<str>/",
305 std::string(), std::string())
306 {
307 entityPrivileges = {
308 {boost::beast::http::verb::get, {{"Login"}}},
309 {boost::beast::http::verb::head, {{"Login"}}},
310 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
311 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
312 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
313 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
314 }
315
316 private:
317 void doGet(crow::Response &res, const crow::Request &req,
318 const std::vector<std::string> &params) override
319 {
320 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
321 if (params.size() != 2)
322 {
323 messages::internalError(asyncResp->res);
324 return;
325 }
326 const std::string &device = params[0];
327 const std::string &function = params[1];
328
329 auto getPCIeDeviceCallback =
330 [asyncResp, device, function](
331 const boost::system::error_code ec,
332 boost::container::flat_map<
333 std::string, sdbusplus::message::variant<std::string>>
334 &pcieDevProperties) {
335 if (ec)
336 {
337 BMCWEB_LOG_DEBUG
338 << "failed to get PCIe Device properties ec: "
Ed Tanous271584a2019-07-09 16:24:22 -0700339 << ec.value() << ": " << ec.message();
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800340 if (ec.value() ==
341 boost::system::linux_error::bad_request_descriptor)
342 {
343 messages::resourceNotFound(asyncResp->res, "PCIeDevice",
344 device);
345 }
346 else
347 {
348 messages::internalError(asyncResp->res);
349 }
350 return;
351 }
352
353 // Check if this function exists by looking for a device ID
354 std::string devIDProperty = "Function" + function + "DeviceId";
355 if (std::string *property =
356 sdbusplus::message::variant_ns::get_if<std::string>(
357 &pcieDevProperties[devIDProperty]);
358 property && property->empty())
359 {
360 messages::resourceNotFound(asyncResp->res, "PCIeFunction",
361 function);
362 return;
363 }
364
365 asyncResp->res.jsonValue = {
366 {"@odata.type", "#PCIeFunction.v1_2_0.PCIeFunction"},
367 {"@odata.context",
368 "/redfish/v1/$metadata#PCIeFunction.PCIeFunction"},
369 {"@odata.id", "/redfish/v1/Systems/system/PCIeDevices/" +
370 device + "/PCIeFunctions/" + function},
371 {"Name", "PCIe Function"},
372 {"Id", function},
373 {"FunctionId", std::stoi(function)},
374 {"Links",
375 {{"PCIeDevice",
376 {{"@odata.id",
377 "/redfish/v1/Systems/system/PCIeDevices/" +
378 device}}}}}};
379
380 if (std::string *property =
381 sdbusplus::message::variant_ns::get_if<std::string>(
382 &pcieDevProperties["Function" + function +
383 "DeviceId"]);
384 property)
385 {
386 asyncResp->res.jsonValue["DeviceId"] = *property;
387 }
388
389 if (std::string *property =
390 sdbusplus::message::variant_ns::get_if<std::string>(
391 &pcieDevProperties["Function" + function +
392 "VendorId"]);
393 property)
394 {
395 asyncResp->res.jsonValue["VendorId"] = *property;
396 }
397
398 if (std::string *property =
399 sdbusplus::message::variant_ns::get_if<std::string>(
400 &pcieDevProperties["Function" + function +
401 "FunctionType"]);
402 property)
403 {
404 asyncResp->res.jsonValue["FunctionType"] = *property;
405 }
406
407 if (std::string *property =
408 sdbusplus::message::variant_ns::get_if<std::string>(
409 &pcieDevProperties["Function" + function +
410 "DeviceClass"]);
411 property)
412 {
413 asyncResp->res.jsonValue["DeviceClass"] = *property;
414 }
415
416 if (std::string *property =
417 sdbusplus::message::variant_ns::get_if<std::string>(
418 &pcieDevProperties["Function" + function +
419 "ClassCode"]);
420 property)
421 {
422 asyncResp->res.jsonValue["ClassCode"] = *property;
423 }
424
425 if (std::string *property =
426 sdbusplus::message::variant_ns::get_if<std::string>(
427 &pcieDevProperties["Function" + function +
428 "RevisionId"]);
429 property)
430 {
431 asyncResp->res.jsonValue["RevisionId"] = *property;
432 }
433
434 if (std::string *property =
435 sdbusplus::message::variant_ns::get_if<std::string>(
436 &pcieDevProperties["Function" + function +
437 "SubsystemId"]);
438 property)
439 {
440 asyncResp->res.jsonValue["SubsystemId"] = *property;
441 }
442
443 if (std::string *property =
444 sdbusplus::message::variant_ns::get_if<std::string>(
445 &pcieDevProperties["Function" + function +
446 "SubsystemVendorId"]);
447 property)
448 {
449 asyncResp->res.jsonValue["SubsystemVendorId"] = *property;
450 }
451 };
452 std::string escapedPath = std::string(pciePath) + "/" + device;
453 dbus::utility::escapePathForDbus(escapedPath);
454 crow::connections::systemBus->async_method_call(
455 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
456 "org.freedesktop.DBus.Properties", "GetAll", pcieDeviceInterface);
457 }
458};
459
460} // namespace redfish