blob: 64ccdb2d8e9c732e902fa4e41bc1f78ee2f4f8e6 [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
31static inline void getPCIeDeviceList(std::shared_ptr<AsyncResp> asyncResp)
32{
33 auto getPCIeMapCallback =
34 [asyncResp](const boost::system::error_code ec,
35 std::vector<std::string> &pcieDevicePaths) {
36 if (ec)
37 {
Andrew Geisslera2730f02019-07-12 07:48:50 -050038 BMCWEB_LOG_DEBUG << "no PCIe device paths found ec: "
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080039 << ec.message();
Andrew Geisslera2730f02019-07-12 07:48:50 -050040 // Not an error, system just doesn't have PCIe info
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -080041 return;
42 }
43 nlohmann::json &pcieDeviceList =
44 asyncResp->res.jsonValue["PCIeDevices"];
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)
50 {
51 continue;
52 }
53
54 std::string devName = pcieDevicePath.substr(devStart + 1);
55 if (devName.empty())
56 {
57 continue;
58 }
59 pcieDeviceList.push_back(
60 {{"@odata.id",
61 "/redfish/v1/Systems/system/PCIeDevices/" + devName}});
62 }
63 asyncResp->res.jsonValue["PCIeDevices@odata.count"] =
64 pcieDeviceList.size();
65 };
66 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
73class SystemPCIeDevice : public Node
74{
75 public:
76 SystemPCIeDevice(CrowApp &app) :
77 Node(app, "/redfish/v1/Systems/system/PCIeDevices/<str>/",
78 std::string())
79 {
80 entityPrivileges = {
81 {boost::beast::http::verb::get, {{"Login"}}},
82 {boost::beast::http::verb::head, {{"Login"}}},
83 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
84 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
85 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
86 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
87 }
88
89 private:
90 void doGet(crow::Response &res, const crow::Request &req,
91 const std::vector<std::string> &params) override
92 {
93 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
94 if (params.size() != 1)
95 {
96 messages::internalError(asyncResp->res);
97 return;
98 }
99 const std::string &device = params[0];
100
101 auto getPCIeDeviceCallback =
102 [asyncResp,
103 device](const boost::system::error_code ec,
104 boost::container::flat_map<
105 std::string, sdbusplus::message::variant<std::string>>
106 &pcieDevProperties) {
107 if (ec)
108 {
109 BMCWEB_LOG_DEBUG
110 << "failed to get PCIe Device properties ec: "
Ed Tanous271584a2019-07-09 16:24:22 -0700111 << ec.value() << ": " << ec.message();
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800112 if (ec.value() ==
113 boost::system::linux_error::bad_request_descriptor)
114 {
115 messages::resourceNotFound(asyncResp->res, "PCIeDevice",
116 device);
117 }
118 else
119 {
120 messages::internalError(asyncResp->res);
121 }
122 return;
123 }
124
125 asyncResp->res.jsonValue = {
Jason M. Billsdede6a92019-10-14 15:41:30 -0700126 {"@odata.type", "#PCIeDevice.v1_4_0.PCIeDevice"},
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800127 {"@odata.context",
Jason M. Billsdede6a92019-10-14 15:41:30 -0700128 "/redfish/v1/$metadata#PCIeDevice.v1_4_0.PCIeDevice"},
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800129 {"@odata.id",
130 "/redfish/v1/Systems/system/PCIeDevices/" + device},
131 {"Name", "PCIe Device"},
132 {"Id", device}};
133
134 if (std::string *property =
135 sdbusplus::message::variant_ns::get_if<std::string>(
136 &pcieDevProperties["Manufacturer"]);
137 property)
138 {
139 asyncResp->res.jsonValue["Manufacturer"] = *property;
140 }
141
142 if (std::string *property =
143 sdbusplus::message::variant_ns::get_if<std::string>(
144 &pcieDevProperties["DeviceType"]);
145 property)
146 {
147 asyncResp->res.jsonValue["DeviceType"] = *property;
148 }
149
Jason M. Billsdede6a92019-10-14 15:41:30 -0700150 asyncResp->res.jsonValue["PCIeFunctions"] = {
151 {"@odata.id", "/redfish/v1/Systems/system/PCIeDevices/" +
152 device + "/PCIeFunctions"}};
153 };
154 std::string escapedPath = std::string(pciePath) + "/" + device;
155 dbus::utility::escapePathForDbus(escapedPath);
156 crow::connections::systemBus->async_method_call(
157 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
158 "org.freedesktop.DBus.Properties", "GetAll", pcieDeviceInterface);
159 }
160};
161
162class SystemPCIeFunctionCollection : public Node
163{
164 public:
165 template <typename CrowApp>
166 SystemPCIeFunctionCollection(CrowApp &app) :
167 Node(app, "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/",
168 std::string())
169 {
170 entityPrivileges = {
171 {boost::beast::http::verb::get, {{"Login"}}},
172 {boost::beast::http::verb::head, {{"Login"}}},
173 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
174 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
175 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
176 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
177 }
178
179 private:
180 /**
181 * Functions triggers appropriate requests on DBus
182 */
183 void doGet(crow::Response &res, const crow::Request &req,
184 const std::vector<std::string> &params) override
185 {
186 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
187 if (params.size() != 1)
188 {
189 messages::internalError(asyncResp->res);
190 return;
191 }
192 const std::string &device = params[0];
193 asyncResp->res.jsonValue = {
194 {"@odata.type", "#PCIeFunctionCollection.PCIeFunctionCollection"},
195 {"@odata.context",
196 "/redfish/v1/"
197 "$metadata#PCIeFunctionCollection.PCIeFunctionCollection"},
198 {"@odata.id", "/redfish/v1/Systems/system/PCIeDevices/" + device +
199 "/PCIeFunctions"},
200 {"Name", "PCIe Function Collection"},
201 {"Description",
202 "Collection of PCIe Functions for PCIe Device " + device}};
203
204 auto getPCIeDeviceCallback =
205 [asyncResp,
206 device](const boost::system::error_code ec,
207 boost::container::flat_map<
208 std::string, sdbusplus::message::variant<std::string>>
209 &pcieDevProperties) {
210 if (ec)
211 {
212 BMCWEB_LOG_DEBUG
213 << "failed to get PCIe Device properties ec: "
214 << ec.value() << ": " << ec.message();
215 if (ec.value() ==
216 boost::system::linux_error::bad_request_descriptor)
217 {
218 messages::resourceNotFound(asyncResp->res, "PCIeDevice",
219 device);
220 }
221 else
222 {
223 messages::internalError(asyncResp->res);
224 }
225 return;
226 }
227
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800228 nlohmann::json &pcieFunctionList =
Jason M. Billsdede6a92019-10-14 15:41:30 -0700229 asyncResp->res.jsonValue["Members"];
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800230 pcieFunctionList = nlohmann::json::array();
231 static constexpr const int maxPciFunctionNum = 8;
232 for (int functionNum = 0; functionNum < maxPciFunctionNum;
233 functionNum++)
234 {
235 // Check if this function exists by looking for a device ID
236 std::string devIDProperty =
237 "Function" + std::to_string(functionNum) + "DeviceId";
Jason M. Billsdede6a92019-10-14 15:41:30 -0700238 std::string *property =
239 sdbusplus::message::variant_ns::get_if<std::string>(
240 &pcieDevProperties[devIDProperty]);
241 if (property && !property->empty())
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800242 {
243 pcieFunctionList.push_back(
244 {{"@odata.id",
245 "/redfish/v1/Systems/system/PCIeDevices/" +
246 device + "/PCIeFunctions/" +
247 std::to_string(functionNum)}});
248 }
249 }
Jason M. Billsdede6a92019-10-14 15:41:30 -0700250 asyncResp->res.jsonValue["PCIeFunctions@odata.count"] =
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800251 pcieFunctionList.size();
252 };
253 std::string escapedPath = std::string(pciePath) + "/" + device;
254 dbus::utility::escapePathForDbus(escapedPath);
255 crow::connections::systemBus->async_method_call(
256 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
257 "org.freedesktop.DBus.Properties", "GetAll", pcieDeviceInterface);
258 }
259};
260
261class SystemPCIeFunction : public Node
262{
263 public:
264 SystemPCIeFunction(CrowApp &app) :
265 Node(
266 app,
267 "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/<str>/",
268 std::string(), std::string())
269 {
270 entityPrivileges = {
271 {boost::beast::http::verb::get, {{"Login"}}},
272 {boost::beast::http::verb::head, {{"Login"}}},
273 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
274 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
275 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
276 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
277 }
278
279 private:
280 void doGet(crow::Response &res, const crow::Request &req,
281 const std::vector<std::string> &params) override
282 {
283 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
284 if (params.size() != 2)
285 {
286 messages::internalError(asyncResp->res);
287 return;
288 }
289 const std::string &device = params[0];
290 const std::string &function = params[1];
291
292 auto getPCIeDeviceCallback =
293 [asyncResp, device, function](
294 const boost::system::error_code ec,
295 boost::container::flat_map<
296 std::string, sdbusplus::message::variant<std::string>>
297 &pcieDevProperties) {
298 if (ec)
299 {
300 BMCWEB_LOG_DEBUG
301 << "failed to get PCIe Device properties ec: "
Ed Tanous271584a2019-07-09 16:24:22 -0700302 << ec.value() << ": " << ec.message();
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800303 if (ec.value() ==
304 boost::system::linux_error::bad_request_descriptor)
305 {
306 messages::resourceNotFound(asyncResp->res, "PCIeDevice",
307 device);
308 }
309 else
310 {
311 messages::internalError(asyncResp->res);
312 }
313 return;
314 }
315
316 // Check if this function exists by looking for a device ID
317 std::string devIDProperty = "Function" + function + "DeviceId";
318 if (std::string *property =
319 sdbusplus::message::variant_ns::get_if<std::string>(
320 &pcieDevProperties[devIDProperty]);
321 property && property->empty())
322 {
323 messages::resourceNotFound(asyncResp->res, "PCIeFunction",
324 function);
325 return;
326 }
327
328 asyncResp->res.jsonValue = {
329 {"@odata.type", "#PCIeFunction.v1_2_0.PCIeFunction"},
330 {"@odata.context",
331 "/redfish/v1/$metadata#PCIeFunction.PCIeFunction"},
332 {"@odata.id", "/redfish/v1/Systems/system/PCIeDevices/" +
333 device + "/PCIeFunctions/" + function},
334 {"Name", "PCIe Function"},
335 {"Id", function},
336 {"FunctionId", std::stoi(function)},
337 {"Links",
338 {{"PCIeDevice",
339 {{"@odata.id",
340 "/redfish/v1/Systems/system/PCIeDevices/" +
341 device}}}}}};
342
343 if (std::string *property =
344 sdbusplus::message::variant_ns::get_if<std::string>(
345 &pcieDevProperties["Function" + function +
346 "DeviceId"]);
347 property)
348 {
349 asyncResp->res.jsonValue["DeviceId"] = *property;
350 }
351
352 if (std::string *property =
353 sdbusplus::message::variant_ns::get_if<std::string>(
354 &pcieDevProperties["Function" + function +
355 "VendorId"]);
356 property)
357 {
358 asyncResp->res.jsonValue["VendorId"] = *property;
359 }
360
361 if (std::string *property =
362 sdbusplus::message::variant_ns::get_if<std::string>(
363 &pcieDevProperties["Function" + function +
364 "FunctionType"]);
365 property)
366 {
367 asyncResp->res.jsonValue["FunctionType"] = *property;
368 }
369
370 if (std::string *property =
371 sdbusplus::message::variant_ns::get_if<std::string>(
372 &pcieDevProperties["Function" + function +
373 "DeviceClass"]);
374 property)
375 {
376 asyncResp->res.jsonValue["DeviceClass"] = *property;
377 }
378
379 if (std::string *property =
380 sdbusplus::message::variant_ns::get_if<std::string>(
381 &pcieDevProperties["Function" + function +
382 "ClassCode"]);
383 property)
384 {
385 asyncResp->res.jsonValue["ClassCode"] = *property;
386 }
387
388 if (std::string *property =
389 sdbusplus::message::variant_ns::get_if<std::string>(
390 &pcieDevProperties["Function" + function +
391 "RevisionId"]);
392 property)
393 {
394 asyncResp->res.jsonValue["RevisionId"] = *property;
395 }
396
397 if (std::string *property =
398 sdbusplus::message::variant_ns::get_if<std::string>(
399 &pcieDevProperties["Function" + function +
400 "SubsystemId"]);
401 property)
402 {
403 asyncResp->res.jsonValue["SubsystemId"] = *property;
404 }
405
406 if (std::string *property =
407 sdbusplus::message::variant_ns::get_if<std::string>(
408 &pcieDevProperties["Function" + function +
409 "SubsystemVendorId"]);
410 property)
411 {
412 asyncResp->res.jsonValue["SubsystemVendorId"] = *property;
413 }
414 };
415 std::string escapedPath = std::string(pciePath) + "/" + device;
416 dbus::utility::escapePathForDbus(escapedPath);
417 crow::connections::systemBus->async_method_call(
418 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
419 "org.freedesktop.DBus.Properties", "GetAll", pcieDeviceInterface);
420 }
421};
422
423} // namespace redfish