blob: 33b88286717377d9c23fbb8d3432d268dca60239 [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
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500166 if (std::string *property = std::get_if<std::string>(
167 &pcieDevProperties["Manufacturer"]);
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800168 property)
169 {
170 asyncResp->res.jsonValue["Manufacturer"] = *property;
171 }
172
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500173 if (std::string *property = std::get_if<std::string>(
174 &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:
195 template <typename CrowApp>
196 SystemPCIeFunctionCollection(CrowApp &app) :
197 Node(app, "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/",
198 std::string())
199 {
200 entityPrivileges = {
201 {boost::beast::http::verb::get, {{"Login"}}},
202 {boost::beast::http::verb::head, {{"Login"}}},
203 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
204 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
205 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
206 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
207 }
208
209 private:
210 /**
211 * Functions triggers appropriate requests on DBus
212 */
213 void doGet(crow::Response &res, const crow::Request &req,
214 const std::vector<std::string> &params) override
215 {
216 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
217 if (params.size() != 1)
218 {
219 messages::internalError(asyncResp->res);
220 return;
221 }
222 const std::string &device = params[0];
223 asyncResp->res.jsonValue = {
224 {"@odata.type", "#PCIeFunctionCollection.PCIeFunctionCollection"},
Jason M. Billsdede6a92019-10-14 15:41:30 -0700225 {"@odata.id", "/redfish/v1/Systems/system/PCIeDevices/" + device +
226 "/PCIeFunctions"},
227 {"Name", "PCIe Function Collection"},
228 {"Description",
229 "Collection of PCIe Functions for PCIe Device " + device}};
230
231 auto getPCIeDeviceCallback =
232 [asyncResp,
233 device](const boost::system::error_code ec,
234 boost::container::flat_map<
235 std::string, sdbusplus::message::variant<std::string>>
236 &pcieDevProperties) {
237 if (ec)
238 {
239 BMCWEB_LOG_DEBUG
240 << "failed to get PCIe Device properties ec: "
241 << ec.value() << ": " << ec.message();
242 if (ec.value() ==
243 boost::system::linux_error::bad_request_descriptor)
244 {
245 messages::resourceNotFound(asyncResp->res, "PCIeDevice",
246 device);
247 }
248 else
249 {
250 messages::internalError(asyncResp->res);
251 }
252 return;
253 }
254
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800255 nlohmann::json &pcieFunctionList =
Jason M. Billsdede6a92019-10-14 15:41:30 -0700256 asyncResp->res.jsonValue["Members"];
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800257 pcieFunctionList = nlohmann::json::array();
258 static constexpr const int maxPciFunctionNum = 8;
259 for (int functionNum = 0; functionNum < maxPciFunctionNum;
260 functionNum++)
261 {
262 // Check if this function exists by looking for a device ID
263 std::string devIDProperty =
264 "Function" + std::to_string(functionNum) + "DeviceId";
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500265 std::string *property = std::get_if<std::string>(
266 &pcieDevProperties[devIDProperty]);
Jason M. Billsdede6a92019-10-14 15:41:30 -0700267 if (property && !property->empty())
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800268 {
269 pcieFunctionList.push_back(
270 {{"@odata.id",
271 "/redfish/v1/Systems/system/PCIeDevices/" +
272 device + "/PCIeFunctions/" +
273 std::to_string(functionNum)}});
274 }
275 }
Jason M. Billsdede6a92019-10-14 15:41:30 -0700276 asyncResp->res.jsonValue["PCIeFunctions@odata.count"] =
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800277 pcieFunctionList.size();
278 };
279 std::string escapedPath = std::string(pciePath) + "/" + device;
280 dbus::utility::escapePathForDbus(escapedPath);
281 crow::connections::systemBus->async_method_call(
282 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
283 "org.freedesktop.DBus.Properties", "GetAll", pcieDeviceInterface);
284 }
285};
286
287class SystemPCIeFunction : public Node
288{
289 public:
290 SystemPCIeFunction(CrowApp &app) :
291 Node(
292 app,
293 "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/<str>/",
294 std::string(), std::string())
295 {
296 entityPrivileges = {
297 {boost::beast::http::verb::get, {{"Login"}}},
298 {boost::beast::http::verb::head, {{"Login"}}},
299 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
300 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
301 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
302 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
303 }
304
305 private:
306 void doGet(crow::Response &res, const crow::Request &req,
307 const std::vector<std::string> &params) override
308 {
309 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
310 if (params.size() != 2)
311 {
312 messages::internalError(asyncResp->res);
313 return;
314 }
315 const std::string &device = params[0];
316 const std::string &function = params[1];
317
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500318 auto getPCIeDeviceCallback = [asyncResp, device, function](
319 const boost::system::error_code ec,
320 boost::container::flat_map<
321 std::string,
322 sdbusplus::message::variant<
323 std::string>>
324 &pcieDevProperties) {
325 if (ec)
326 {
327 BMCWEB_LOG_DEBUG
328 << "failed to get PCIe Device properties ec: " << ec.value()
329 << ": " << ec.message();
330 if (ec.value() ==
331 boost::system::linux_error::bad_request_descriptor)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800332 {
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500333 messages::resourceNotFound(asyncResp->res, "PCIeDevice",
334 device);
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800335 }
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500336 else
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800337 {
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500338 messages::internalError(asyncResp->res);
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800339 }
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500340 return;
341 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800342
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500343 // Check if this function exists by looking for a device ID
344 std::string devIDProperty = "Function" + function + "DeviceId";
345 if (std::string *property =
346 std::get_if<std::string>(&pcieDevProperties[devIDProperty]);
347 property && property->empty())
348 {
349 messages::resourceNotFound(asyncResp->res, "PCIeFunction",
350 function);
351 return;
352 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800353
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500354 asyncResp->res.jsonValue = {
355 {"@odata.type", "#PCIeFunction.v1_2_0.PCIeFunction"},
356 {"@odata.id", "/redfish/v1/Systems/system/PCIeDevices/" +
357 device + "/PCIeFunctions/" + function},
358 {"Name", "PCIe Function"},
359 {"Id", function},
360 {"FunctionId", std::stoi(function)},
361 {"Links",
362 {{"PCIeDevice",
363 {{"@odata.id",
364 "/redfish/v1/Systems/system/PCIeDevices/" + device}}}}}};
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800365
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500366 if (std::string *property = std::get_if<std::string>(
367 &pcieDevProperties["Function" + function + "DeviceId"]);
368 property)
369 {
370 asyncResp->res.jsonValue["DeviceId"] = *property;
371 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800372
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500373 if (std::string *property = std::get_if<std::string>(
374 &pcieDevProperties["Function" + function + "VendorId"]);
375 property)
376 {
377 asyncResp->res.jsonValue["VendorId"] = *property;
378 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800379
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500380 if (std::string *property = std::get_if<std::string>(
381 &pcieDevProperties["Function" + function + "FunctionType"]);
382 property)
383 {
384 asyncResp->res.jsonValue["FunctionType"] = *property;
385 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800386
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500387 if (std::string *property = std::get_if<std::string>(
388 &pcieDevProperties["Function" + function + "DeviceClass"]);
389 property)
390 {
391 asyncResp->res.jsonValue["DeviceClass"] = *property;
392 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800393
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500394 if (std::string *property = std::get_if<std::string>(
395 &pcieDevProperties["Function" + function + "ClassCode"]);
396 property)
397 {
398 asyncResp->res.jsonValue["ClassCode"] = *property;
399 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800400
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500401 if (std::string *property = std::get_if<std::string>(
402 &pcieDevProperties["Function" + function + "RevisionId"]);
403 property)
404 {
405 asyncResp->res.jsonValue["RevisionId"] = *property;
406 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800407
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500408 if (std::string *property = std::get_if<std::string>(
409 &pcieDevProperties["Function" + function + "SubsystemId"]);
410 property)
411 {
412 asyncResp->res.jsonValue["SubsystemId"] = *property;
413 }
414
415 if (std::string *property = std::get_if<std::string>(
416 &pcieDevProperties["Function" + function +
417 "SubsystemVendorId"]);
418 property)
419 {
420 asyncResp->res.jsonValue["SubsystemVendorId"] = *property;
421 }
422 };
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800423 std::string escapedPath = std::string(pciePath) + "/" + device;
424 dbus::utility::escapePathForDbus(escapedPath);
425 crow::connections::systemBus->async_method_call(
426 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
427 "org.freedesktop.DBus.Properties", "GetAll", pcieDeviceInterface);
428 }
429};
430
431} // namespace redfish