blob: ece84a31778797411a66b97cc52a9ab4bdc2dae1 [file] [log] [blame]
#pragma once
#include "app.hpp"
#include "dbus_utility.hpp"
#include "error_messages.hpp"
#include "generated/enums/pcie_slots.hpp"
#include "pcie.hpp"
#include "registries/privilege_registry.hpp"
#include "utility.hpp"
#include "utils/dbus_utils.hpp"
#include "utils/json_utils.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 pcie_slots::SlotTypes dbusSlotTypeToRf(const std::string& slotType)
{
if (slotType ==
"xyz.openbmc_project.Inventory.Item.PCIeSlot.SlotTypes.FullLength")
{
return pcie_slots::SlotTypes::FullLength;
}
if (slotType ==
"xyz.openbmc_project.Inventory.Item.PCIeSlot.SlotTypes.HalfLength")
{
return pcie_slots::SlotTypes::HalfLength;
}
if (slotType ==
"xyz.openbmc_project.Inventory.Item.PCIeSlot.SlotTypes.LowProfile")
{
return pcie_slots::SlotTypes::LowProfile;
}
if (slotType ==
"xyz.openbmc_project.Inventory.Item.PCIeSlot.SlotTypes.Mini")
{
return pcie_slots::SlotTypes::Mini;
}
if (slotType == "xyz.openbmc_project.Inventory.Item.PCIeSlot.SlotTypes.M_2")
{
return pcie_slots::SlotTypes::M2;
}
if (slotType == "xyz.openbmc_project.Inventory.Item.PCIeSlot.SlotTypes.OEM")
{
return pcie_slots::SlotTypes::OEM;
}
if (slotType ==
"xyz.openbmc_project.Inventory.Item.PCIeSlot.SlotTypes.OCP3Small")
{
return pcie_slots::SlotTypes::OCP3Small;
}
if (slotType ==
"xyz.openbmc_project.Inventory.Item.PCIeSlot.SlotTypes.OCP3Large")
{
return pcie_slots::SlotTypes::OCP3Large;
}
if (slotType == "xyz.openbmc_project.Inventory.Item.PCIeSlot.SlotTypes.U_2")
{
return pcie_slots::SlotTypes::U2;
}
// Unknown or others
return pcie_slots::SlotTypes::Invalid;
}
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 =
redfishPcieGenerationFromDbus(*generation);
if (!pcieType)
{
messages::internalError(asyncResp->res);
return;
}
if (*pcieType != pcie_device::PCIeTypes::Invalid)
{
slot["PCIeType"] = *pcieType;
}
}
if (lanes != nullptr)
{
slot["Lanes"] = *lanes;
}
if (slotType != nullptr)
{
pcie_slots::SlotTypes redfishSlotType = dbusSlotTypeToRf(*slotType);
if (redfishSlotType == pcie_slots::SlotTypes::Invalid)
{
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