blob: 5b4f5c506585550b836338966b23a94551a0be1c [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 = {
126 {"@odata.type", "#PCIeDevice.v1_2_0.PCIeDevice"},
127 {"@odata.context",
128 "/redfish/v1/$metadata#PCIeDevice.v1_2_0.PCIeDevice"},
129 {"@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
150 nlohmann::json &pcieFunctionList =
151 asyncResp->res.jsonValue["Links"]["PCIeFunctions"];
152 pcieFunctionList = nlohmann::json::array();
153 static constexpr const int maxPciFunctionNum = 8;
154 for (int functionNum = 0; functionNum < maxPciFunctionNum;
155 functionNum++)
156 {
157 // Check if this function exists by looking for a device ID
158 std::string devIDProperty =
159 "Function" + std::to_string(functionNum) + "DeviceId";
160 if (std::string *property =
161 sdbusplus::message::variant_ns::get_if<std::string>(
162 &pcieDevProperties[devIDProperty]);
163 property && !property->empty())
164 {
165 pcieFunctionList.push_back(
166 {{"@odata.id",
167 "/redfish/v1/Systems/system/PCIeDevices/" +
168 device + "/PCIeFunctions/" +
169 std::to_string(functionNum)}});
170 }
171 }
172 asyncResp->res.jsonValue["Links"]["PCIeFunctions@odata.count"] =
173 pcieFunctionList.size();
174 };
175 std::string escapedPath = std::string(pciePath) + "/" + device;
176 dbus::utility::escapePathForDbus(escapedPath);
177 crow::connections::systemBus->async_method_call(
178 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
179 "org.freedesktop.DBus.Properties", "GetAll", pcieDeviceInterface);
180 }
181};
182
183class SystemPCIeFunction : public Node
184{
185 public:
186 SystemPCIeFunction(CrowApp &app) :
187 Node(
188 app,
189 "/redfish/v1/Systems/system/PCIeDevices/<str>/PCIeFunctions/<str>/",
190 std::string(), std::string())
191 {
192 entityPrivileges = {
193 {boost::beast::http::verb::get, {{"Login"}}},
194 {boost::beast::http::verb::head, {{"Login"}}},
195 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
196 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
197 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
198 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
199 }
200
201 private:
202 void doGet(crow::Response &res, const crow::Request &req,
203 const std::vector<std::string> &params) override
204 {
205 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
206 if (params.size() != 2)
207 {
208 messages::internalError(asyncResp->res);
209 return;
210 }
211 const std::string &device = params[0];
212 const std::string &function = params[1];
213
214 auto getPCIeDeviceCallback =
215 [asyncResp, device, function](
216 const boost::system::error_code ec,
217 boost::container::flat_map<
218 std::string, sdbusplus::message::variant<std::string>>
219 &pcieDevProperties) {
220 if (ec)
221 {
222 BMCWEB_LOG_DEBUG
223 << "failed to get PCIe Device properties ec: "
Ed Tanous271584a2019-07-09 16:24:22 -0700224 << ec.value() << ": " << ec.message();
Jason M. Billsf5c9f8b2018-12-18 16:51:18 -0800225 if (ec.value() ==
226 boost::system::linux_error::bad_request_descriptor)
227 {
228 messages::resourceNotFound(asyncResp->res, "PCIeDevice",
229 device);
230 }
231 else
232 {
233 messages::internalError(asyncResp->res);
234 }
235 return;
236 }
237
238 // Check if this function exists by looking for a device ID
239 std::string devIDProperty = "Function" + function + "DeviceId";
240 if (std::string *property =
241 sdbusplus::message::variant_ns::get_if<std::string>(
242 &pcieDevProperties[devIDProperty]);
243 property && property->empty())
244 {
245 messages::resourceNotFound(asyncResp->res, "PCIeFunction",
246 function);
247 return;
248 }
249
250 asyncResp->res.jsonValue = {
251 {"@odata.type", "#PCIeFunction.v1_2_0.PCIeFunction"},
252 {"@odata.context",
253 "/redfish/v1/$metadata#PCIeFunction.PCIeFunction"},
254 {"@odata.id", "/redfish/v1/Systems/system/PCIeDevices/" +
255 device + "/PCIeFunctions/" + function},
256 {"Name", "PCIe Function"},
257 {"Id", function},
258 {"FunctionId", std::stoi(function)},
259 {"Links",
260 {{"PCIeDevice",
261 {{"@odata.id",
262 "/redfish/v1/Systems/system/PCIeDevices/" +
263 device}}}}}};
264
265 if (std::string *property =
266 sdbusplus::message::variant_ns::get_if<std::string>(
267 &pcieDevProperties["Function" + function +
268 "DeviceId"]);
269 property)
270 {
271 asyncResp->res.jsonValue["DeviceId"] = *property;
272 }
273
274 if (std::string *property =
275 sdbusplus::message::variant_ns::get_if<std::string>(
276 &pcieDevProperties["Function" + function +
277 "VendorId"]);
278 property)
279 {
280 asyncResp->res.jsonValue["VendorId"] = *property;
281 }
282
283 if (std::string *property =
284 sdbusplus::message::variant_ns::get_if<std::string>(
285 &pcieDevProperties["Function" + function +
286 "FunctionType"]);
287 property)
288 {
289 asyncResp->res.jsonValue["FunctionType"] = *property;
290 }
291
292 if (std::string *property =
293 sdbusplus::message::variant_ns::get_if<std::string>(
294 &pcieDevProperties["Function" + function +
295 "DeviceClass"]);
296 property)
297 {
298 asyncResp->res.jsonValue["DeviceClass"] = *property;
299 }
300
301 if (std::string *property =
302 sdbusplus::message::variant_ns::get_if<std::string>(
303 &pcieDevProperties["Function" + function +
304 "ClassCode"]);
305 property)
306 {
307 asyncResp->res.jsonValue["ClassCode"] = *property;
308 }
309
310 if (std::string *property =
311 sdbusplus::message::variant_ns::get_if<std::string>(
312 &pcieDevProperties["Function" + function +
313 "RevisionId"]);
314 property)
315 {
316 asyncResp->res.jsonValue["RevisionId"] = *property;
317 }
318
319 if (std::string *property =
320 sdbusplus::message::variant_ns::get_if<std::string>(
321 &pcieDevProperties["Function" + function +
322 "SubsystemId"]);
323 property)
324 {
325 asyncResp->res.jsonValue["SubsystemId"] = *property;
326 }
327
328 if (std::string *property =
329 sdbusplus::message::variant_ns::get_if<std::string>(
330 &pcieDevProperties["Function" + function +
331 "SubsystemVendorId"]);
332 property)
333 {
334 asyncResp->res.jsonValue["SubsystemVendorId"] = *property;
335 }
336 };
337 std::string escapedPath = std::string(pciePath) + "/" + device;
338 dbus::utility::escapePathForDbus(escapedPath);
339 crow::connections::systemBus->async_method_call(
340 std::move(getPCIeDeviceCallback), pcieService, escapedPath,
341 "org.freedesktop.DBus.Properties", "GetAll", pcieDeviceInterface);
342 }
343};
344
345} // namespace redfish