blob: f8a5e2957c70a5da0cea79716e3132424b5cf17c [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,
Patrick Williams19bd78d2020-05-13 17:38:24 -0500138 boost::container::flat_map<std::string,
139 std::variant<std::string>>
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800140 &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,
Patrick Williams19bd78d2020-05-13 17:38:24 -0500234 boost::container::flat_map<std::string,
235 std::variant<std::string>>
Jason M. Billsdede6a92019-10-14 15:41:30 -0700236 &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,
Patrick Williams19bd78d2020-05-13 17:38:24 -0500322 std::variant<std::string>>
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500323 &pcieDevProperties) {
324 if (ec)
325 {
326 BMCWEB_LOG_DEBUG
327 << "failed to get PCIe Device properties ec: " << ec.value()
328 << ": " << ec.message();
329 if (ec.value() ==
330 boost::system::linux_error::bad_request_descriptor)
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800331 {
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500332 messages::resourceNotFound(asyncResp->res, "PCIeDevice",
333 device);
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800334 }
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500335 else
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800336 {
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500337 messages::internalError(asyncResp->res);
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800338 }
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500339 return;
340 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800341
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500342 // Check if this function exists by looking for a device ID
343 std::string devIDProperty = "Function" + function + "DeviceId";
344 if (std::string *property =
345 std::get_if<std::string>(&pcieDevProperties[devIDProperty]);
346 property && property->empty())
347 {
348 messages::resourceNotFound(asyncResp->res, "PCIeFunction",
349 function);
350 return;
351 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800352
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500353 asyncResp->res.jsonValue = {
354 {"@odata.type", "#PCIeFunction.v1_2_0.PCIeFunction"},
355 {"@odata.id", "/redfish/v1/Systems/system/PCIeDevices/" +
356 device + "/PCIeFunctions/" + function},
357 {"Name", "PCIe Function"},
358 {"Id", function},
359 {"FunctionId", std::stoi(function)},
360 {"Links",
361 {{"PCIeDevice",
362 {{"@odata.id",
363 "/redfish/v1/Systems/system/PCIeDevices/" + device}}}}}};
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800364
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500365 if (std::string *property = std::get_if<std::string>(
366 &pcieDevProperties["Function" + function + "DeviceId"]);
367 property)
368 {
369 asyncResp->res.jsonValue["DeviceId"] = *property;
370 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800371
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500372 if (std::string *property = std::get_if<std::string>(
373 &pcieDevProperties["Function" + function + "VendorId"]);
374 property)
375 {
376 asyncResp->res.jsonValue["VendorId"] = *property;
377 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800378
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500379 if (std::string *property = std::get_if<std::string>(
380 &pcieDevProperties["Function" + function + "FunctionType"]);
381 property)
382 {
383 asyncResp->res.jsonValue["FunctionType"] = *property;
384 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800385
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500386 if (std::string *property = std::get_if<std::string>(
387 &pcieDevProperties["Function" + function + "DeviceClass"]);
388 property)
389 {
390 asyncResp->res.jsonValue["DeviceClass"] = *property;
391 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800392
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500393 if (std::string *property = std::get_if<std::string>(
394 &pcieDevProperties["Function" + function + "ClassCode"]);
395 property)
396 {
397 asyncResp->res.jsonValue["ClassCode"] = *property;
398 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800399
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500400 if (std::string *property = std::get_if<std::string>(
401 &pcieDevProperties["Function" + function + "RevisionId"]);
402 property)
403 {
404 asyncResp->res.jsonValue["RevisionId"] = *property;
405 }
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800406
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500407 if (std::string *property = std::get_if<std::string>(
408 &pcieDevProperties["Function" + function + "SubsystemId"]);
409 property)
410 {
411 asyncResp->res.jsonValue["SubsystemId"] = *property;
412 }
413
414 if (std::string *property = std::get_if<std::string>(
415 &pcieDevProperties["Function" + function +
416 "SubsystemVendorId"]);
417 property)
418 {
419 asyncResp->res.jsonValue["SubsystemVendorId"] = *property;
420 }
421 };
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800422 std::string escapedPath = std::string(pciePath) + "/" + device;
423 dbus::utility::escapePathForDbus(escapedPath);
424 crow::connections::systemBus->async_method_call(
425 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
426 "org.freedesktop.DBus.Properties", "GetAll", pcieDeviceInterface);
427 }
428};
429
430} // namespace redfish