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