blob: b963a534e2d1b7ac0c9e81618b85633deac52863 [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"},
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:
110 SystemPCIeDevice(CrowApp &app) :
111 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:
124 void doGet(crow::Response &res, const crow::Request &req,
125 const std::vector<std::string> &params) override
126 {
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 }
133 const std::string &device = params[0];
134
135 auto getPCIeDeviceCallback =
136 [asyncResp,
137 device](const boost::system::error_code ec,
138 boost::container::flat_map<
139 std::string, sdbusplus::message::variant<std::string>>
140 &pcieDevProperties) {
141 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
166 if (std::string *property =
167 sdbusplus::message::variant_ns::get_if<std::string>(
168 &pcieDevProperties["Manufacturer"]);
169 property)
170 {
171 asyncResp->res.jsonValue["Manufacturer"] = *property;
172 }
173
174 if (std::string *property =
175 sdbusplus::message::variant_ns::get_if<std::string>(
176 &pcieDevProperties["DeviceType"]);
177 property)
178 {
179 asyncResp->res.jsonValue["DeviceType"] = *property;
180 }
181
Jason M. Billsdede6a92019-10-14 15:41:30 -0700182 asyncResp->res.jsonValue["PCIeFunctions"] = {
183 {"@odata.id", "/redfish/v1/Systems/system/PCIeDevices/" +
184 device + "/PCIeFunctions"}};
185 };
186 std::string escapedPath = std::string(pciePath) + "/" + device;
187 dbus::utility::escapePathForDbus(escapedPath);
188 crow::connections::systemBus->async_method_call(
189 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
190 "org.freedesktop.DBus.Properties", "GetAll", pcieDeviceInterface);
191 }
192};
193
194class SystemPCIeFunctionCollection : public Node
195{
196 public:
197 template <typename CrowApp>
198 SystemPCIeFunctionCollection(CrowApp &app) :
199 Node(app, "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/",
200 std::string())
201 {
202 entityPrivileges = {
203 {boost::beast::http::verb::get, {{"Login"}}},
204 {boost::beast::http::verb::head, {{"Login"}}},
205 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
206 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
207 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
208 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
209 }
210
211 private:
212 /**
213 * Functions triggers appropriate requests on DBus
214 */
215 void doGet(crow::Response &res, const crow::Request &req,
216 const std::vector<std::string> &params) override
217 {
218 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
219 if (params.size() != 1)
220 {
221 messages::internalError(asyncResp->res);
222 return;
223 }
224 const std::string &device = params[0];
225 asyncResp->res.jsonValue = {
226 {"@odata.type", "#PCIeFunctionCollection.PCIeFunctionCollection"},
Jason M. Billsdede6a92019-10-14 15:41:30 -0700227 {"@odata.id", "/redfish/v1/Systems/system/PCIeDevices/" + device +
228 "/PCIeFunctions"},
229 {"Name", "PCIe Function Collection"},
230 {"Description",
231 "Collection of PCIe Functions for PCIe Device " + device}};
232
233 auto getPCIeDeviceCallback =
234 [asyncResp,
235 device](const boost::system::error_code ec,
236 boost::container::flat_map<
237 std::string, sdbusplus::message::variant<std::string>>
238 &pcieDevProperties) {
239 if (ec)
240 {
241 BMCWEB_LOG_DEBUG
242 << "failed to get PCIe Device properties ec: "
243 << ec.value() << ": " << ec.message();
244 if (ec.value() ==
245 boost::system::linux_error::bad_request_descriptor)
246 {
247 messages::resourceNotFound(asyncResp->res, "PCIeDevice",
248 device);
249 }
250 else
251 {
252 messages::internalError(asyncResp->res);
253 }
254 return;
255 }
256
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800257 nlohmann::json &pcieFunctionList =
Jason M. Billsdede6a92019-10-14 15:41:30 -0700258 asyncResp->res.jsonValue["Members"];
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800259 pcieFunctionList = nlohmann::json::array();
260 static constexpr const int maxPciFunctionNum = 8;
261 for (int functionNum = 0; functionNum < maxPciFunctionNum;
262 functionNum++)
263 {
264 // Check if this function exists by looking for a device ID
265 std::string devIDProperty =
266 "Function" + std::to_string(functionNum) + "DeviceId";
Jason M. Billsdede6a92019-10-14 15:41:30 -0700267 std::string *property =
268 sdbusplus::message::variant_ns::get_if<std::string>(
269 &pcieDevProperties[devIDProperty]);
270 if (property && !property->empty())
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800271 {
272 pcieFunctionList.push_back(
273 {{"@odata.id",
274 "/redfish/v1/Systems/system/PCIeDevices/" +
275 device + "/PCIeFunctions/" +
276 std::to_string(functionNum)}});
277 }
278 }
Jason M. Billsdede6a92019-10-14 15:41:30 -0700279 asyncResp->res.jsonValue["PCIeFunctions@odata.count"] =
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800280 pcieFunctionList.size();
281 };
282 std::string escapedPath = std::string(pciePath) + "/" + device;
283 dbus::utility::escapePathForDbus(escapedPath);
284 crow::connections::systemBus->async_method_call(
285 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
286 "org.freedesktop.DBus.Properties", "GetAll", pcieDeviceInterface);
287 }
288};
289
290class SystemPCIeFunction : public Node
291{
292 public:
293 SystemPCIeFunction(CrowApp &app) :
294 Node(
295 app,
296 "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/<str>/",
297 std::string(), std::string())
298 {
299 entityPrivileges = {
300 {boost::beast::http::verb::get, {{"Login"}}},
301 {boost::beast::http::verb::head, {{"Login"}}},
302 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
303 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
304 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
305 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
306 }
307
308 private:
309 void doGet(crow::Response &res, const crow::Request &req,
310 const std::vector<std::string> &params) override
311 {
312 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
313 if (params.size() != 2)
314 {
315 messages::internalError(asyncResp->res);
316 return;
317 }
318 const std::string &device = params[0];
319 const std::string &function = params[1];
320
321 auto getPCIeDeviceCallback =
322 [asyncResp, device, function](
323 const boost::system::error_code ec,
324 boost::container::flat_map<
325 std::string, sdbusplus::message::variant<std::string>>
326 &pcieDevProperties) {
327 if (ec)
328 {
329 BMCWEB_LOG_DEBUG
330 << "failed to get PCIe Device properties ec: "
Ed Tanous271584a2019-07-09 16:24:22 -0700331 << ec.value() << ": " << ec.message();
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800332 if (ec.value() ==
333 boost::system::linux_error::bad_request_descriptor)
334 {
335 messages::resourceNotFound(asyncResp->res, "PCIeDevice",
336 device);
337 }
338 else
339 {
340 messages::internalError(asyncResp->res);
341 }
342 return;
343 }
344
345 // Check if this function exists by looking for a device ID
346 std::string devIDProperty = "Function" + function + "DeviceId";
347 if (std::string *property =
348 sdbusplus::message::variant_ns::get_if<std::string>(
349 &pcieDevProperties[devIDProperty]);
350 property && property->empty())
351 {
352 messages::resourceNotFound(asyncResp->res, "PCIeFunction",
353 function);
354 return;
355 }
356
357 asyncResp->res.jsonValue = {
358 {"@odata.type", "#PCIeFunction.v1_2_0.PCIeFunction"},
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800359 {"@odata.id", "/redfish/v1/Systems/system/PCIeDevices/" +
360 device + "/PCIeFunctions/" + function},
361 {"Name", "PCIe Function"},
362 {"Id", function},
363 {"FunctionId", std::stoi(function)},
364 {"Links",
365 {{"PCIeDevice",
366 {{"@odata.id",
367 "/redfish/v1/Systems/system/PCIeDevices/" +
368 device}}}}}};
369
370 if (std::string *property =
371 sdbusplus::message::variant_ns::get_if<std::string>(
372 &pcieDevProperties["Function" + function +
373 "DeviceId"]);
374 property)
375 {
376 asyncResp->res.jsonValue["DeviceId"] = *property;
377 }
378
379 if (std::string *property =
380 sdbusplus::message::variant_ns::get_if<std::string>(
381 &pcieDevProperties["Function" + function +
382 "VendorId"]);
383 property)
384 {
385 asyncResp->res.jsonValue["VendorId"] = *property;
386 }
387
388 if (std::string *property =
389 sdbusplus::message::variant_ns::get_if<std::string>(
390 &pcieDevProperties["Function" + function +
391 "FunctionType"]);
392 property)
393 {
394 asyncResp->res.jsonValue["FunctionType"] = *property;
395 }
396
397 if (std::string *property =
398 sdbusplus::message::variant_ns::get_if<std::string>(
399 &pcieDevProperties["Function" + function +
400 "DeviceClass"]);
401 property)
402 {
403 asyncResp->res.jsonValue["DeviceClass"] = *property;
404 }
405
406 if (std::string *property =
407 sdbusplus::message::variant_ns::get_if<std::string>(
408 &pcieDevProperties["Function" + function +
409 "ClassCode"]);
410 property)
411 {
412 asyncResp->res.jsonValue["ClassCode"] = *property;
413 }
414
415 if (std::string *property =
416 sdbusplus::message::variant_ns::get_if<std::string>(
417 &pcieDevProperties["Function" + function +
418 "RevisionId"]);
419 property)
420 {
421 asyncResp->res.jsonValue["RevisionId"] = *property;
422 }
423
424 if (std::string *property =
425 sdbusplus::message::variant_ns::get_if<std::string>(
426 &pcieDevProperties["Function" + function +
427 "SubsystemId"]);
428 property)
429 {
430 asyncResp->res.jsonValue["SubsystemId"] = *property;
431 }
432
433 if (std::string *property =
434 sdbusplus::message::variant_ns::get_if<std::string>(
435 &pcieDevProperties["Function" + function +
436 "SubsystemVendorId"]);
437 property)
438 {
439 asyncResp->res.jsonValue["SubsystemVendorId"] = *property;
440 }
441 };
442 std::string escapedPath = std::string(pciePath) + "/" + device;
443 dbus::utility::escapePathForDbus(escapedPath);
444 crow::connections::systemBus->async_method_call(
445 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
446 "org.freedesktop.DBus.Properties", "GetAll", pcieDeviceInterface);
447 }
448};
449
450} // namespace redfish