blob: a6796b99135b6d66011f4f862ebbf67df4688c9c [file] [log] [blame]
#pragma once
#include "app.hpp"
#include "dbus_utility.hpp"
#include "error_messages.hpp"
#include "generated/enums/pcie_slots.hpp"
#include "query.hpp"
#include "registries/privilege_registry.hpp"
#include "utility.hpp"
#include "utils/dbus_utils.hpp"
#include "utils/json_utils.hpp"
#include "utils/pcie_util.hpp"
#include <boost/system/error_code.hpp>
#include <boost/url/format.hpp>
#include <sdbusplus/asio/property.hpp>
#include <sdbusplus/unpack_properties.hpp>
#include <array>
#include <string_view>
namespace redfish
{
inline void
onPcieSlotGetAllDone(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
const boost::system::error_code& ec,
const dbus::utility::DBusPropertiesMap& propertiesList)
{
if (ec)
{
BMCWEB_LOG_ERROR("Can't get PCIeSlot properties!");
messages::internalError(asyncResp->res);
return;
}
nlohmann::json& slots = asyncResp->res.jsonValue["Slots"];
nlohmann::json::array_t* slotsPtr =
slots.get_ptr<nlohmann::json::array_t*>();
if (slotsPtr == nullptr)
{
BMCWEB_LOG_ERROR("Slots key isn't an array???");
messages::internalError(asyncResp->res);
return;
}
nlohmann::json::object_t slot;
const std::string* generation = nullptr;
const size_t* lanes = nullptr;
const std::string* slotType = nullptr;
const bool* hotPluggable = nullptr;
const bool success = sdbusplus::unpackPropertiesNoThrow(
dbus_utils::UnpackErrorPrinter(), propertiesList, "Generation",
generation, "Lanes", lanes, "SlotType", slotType, "HotPluggable",
hotPluggable);
if (!success)
{
messages::internalError(asyncResp->res);
return;
}
if (generation != nullptr)
{
std::optional<pcie_device::PCIeTypes> pcieType =
pcie_util::redfishPcieGenerationFromDbus(*generation);
if (!pcieType)
{
BMCWEB_LOG_WARNING("Unknown PCIe Slot Generation: {}", *generation);
}
else
{
if (*pcieType == pcie_device::PCIeTypes::Invalid)
{
messages::internalError(asyncResp->res);
return;
}
slot["PCIeType"] = *pcieType;
}
}
if (lanes != nullptr && *lanes != 0)
{
slot["Lanes"] = *lanes;
}
if (slotType != nullptr)
{
std::optional<pcie_slots::SlotTypes> redfishSlotType =
pcie_util::dbusSlotTypeToRf(*slotType);
if (!redfishSlotType)
{
BMCWEB_LOG_WARNING("Unknown PCIe Slot Type: {}", *slotType);
}
else
{
if (*redfishSlotType == pcie_slots::SlotTypes::Invalid)
{
BMCWEB_LOG_ERROR("Unknown PCIe Slot Type: {}", *slotType);
messages::internalError(asyncResp->res);
return;
}
slot["SlotType"] = *redfishSlotType;
}
}
if (hotPluggable != nullptr)
{
slot["HotPluggable"] = *hotPluggable;
}
slots.emplace_back(std::move(slot));
}
inline void onMapperAssociationDone(
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
const std::string& chassisID, const std::string& pcieSlotPath,
const std::string& connectionName, const boost::system::error_code& ec,
const dbus::utility::MapperEndPoints& pcieSlotChassis)
{
if (ec)
{
if (ec.value() == EBADR)
{
// This PCIeSlot have no chassis association.
return;
}
BMCWEB_LOG_ERROR("DBUS response error");
messages::internalError(asyncResp->res);
return;
}
if (pcieSlotChassis.size() != 1)
{
BMCWEB_LOG_ERROR("PCIe Slot association error! ");
messages::internalError(asyncResp->res);
return;
}
sdbusplus::message::object_path path(pcieSlotChassis[0]);
std::string chassisName = path.filename();
if (chassisName != chassisID)
{
// The pcie slot doesn't belong to the chassisID
return;
}
sdbusplus::asio::getAllProperties(
*crow::connections::systemBus, connectionName, pcieSlotPath,
"xyz.openbmc_project.Inventory.Item.PCIeSlot",
[asyncResp](const boost::system::error_code& ec2,
const dbus::utility::DBusPropertiesMap& propertiesList) {
onPcieSlotGetAllDone(asyncResp, ec2, propertiesList);
});
}
inline void onMapperSubtreeDone(
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
const std::string& chassisID, const boost::system::error_code& ec,
const dbus::utility::MapperGetSubTreeResponse& subtree)
{
if (ec)
{
BMCWEB_LOG_ERROR("D-Bus response error on GetSubTree {}", ec);
messages::internalError(asyncResp->res);
return;
}
if (subtree.empty())
{
messages::resourceNotFound(asyncResp->res, "Chassis", chassisID);
return;
}
BMCWEB_LOG_DEBUG("Get properties for PCIeSlots associated to chassis = {}",
chassisID);
asyncResp->res.jsonValue["@odata.type"] = "#PCIeSlots.v1_4_1.PCIeSlots";
asyncResp->res.jsonValue["Name"] = "PCIe Slot Information";
asyncResp->res.jsonValue["@odata.id"] =
boost::urls::format("/redfish/v1/Chassis/{}/PCIeSlots", chassisID);
asyncResp->res.jsonValue["Id"] = "1";
asyncResp->res.jsonValue["Slots"] = nlohmann::json::array();
for (const auto& pathServicePair : subtree)
{
const std::string& pcieSlotPath = pathServicePair.first;
for (const auto& connectionInterfacePair : pathServicePair.second)
{
const std::string& connectionName = connectionInterfacePair.first;
sdbusplus::message::object_path pcieSlotAssociationPath(
pcieSlotPath);
pcieSlotAssociationPath /= "chassis";
// The association of this PCIeSlot is used to determine whether
// it belongs to this ChassisID
dbus::utility::getAssociationEndPoints(
std::string{pcieSlotAssociationPath},
[asyncResp, chassisID, pcieSlotPath, connectionName](
const boost::system::error_code& ec2,
const dbus::utility::MapperEndPoints& endpoints) {
onMapperAssociationDone(asyncResp, chassisID, pcieSlotPath,
connectionName, ec2, endpoints);
});
}
}
}
inline void handlePCIeSlotCollectionGet(
crow::App& app, const crow::Request& req,
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
const std::string& chassisID)
{
if (!redfish::setUpRedfishRoute(app, req, asyncResp))
{
return;
}
constexpr std::array<std::string_view, 1> interfaces = {
"xyz.openbmc_project.Inventory.Item.PCIeSlot"};
dbus::utility::getSubTree(
"/xyz/openbmc_project/inventory", 0, interfaces,
[asyncResp,
chassisID](const boost::system::error_code& ec,
const dbus::utility::MapperGetSubTreeResponse& subtree) {
onMapperSubtreeDone(asyncResp, chassisID, ec, subtree);
});
}
inline void requestRoutesPCIeSlots(App& app)
{
BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/PCIeSlots/")
.privileges(redfish::privileges::getPCIeSlots)
.methods(boost::beast::http::verb::get)(
std::bind_front(handlePCIeSlotCollectionGet, std::ref(app)));
}
} // namespace redfish