blob: 1fca19bb379be51002f987ce496c6f2f67013428 [file] [log] [blame]
#pragma once
#include "NVMeIntf.hpp"
#include "NVMeMetricStore.hpp"
#include "NVMePlugin.hpp"
#include "Utils.hpp"
#include <boost/asio.hpp>
#include <sdbusplus/asio/connection.hpp>
#include <sdbusplus/asio/object_server.hpp>
#include <xyz/openbmc_project/Inventory/Item/StorageController/server.hpp>
#include <xyz/openbmc_project/NVMe/NVMeAdmin/server.hpp>
#include <xyz/openbmc_project/Software/ExtendedVersion/server.hpp>
#include <xyz/openbmc_project/Software/Version/server.hpp>
#include <utility>
using SoftwareVersion =
sdbusplus::xyz::openbmc_project::Software::server::Version;
using SoftwareExtVersion =
sdbusplus::xyz::openbmc_project::Software::server::ExtendedVersion;
class NVMeSubsystem;
/**
* @brief A class to represent the NVMeController has not been enabled (CC.EN =
* 0)
*
* The disabled controllers still have cntrl_id and are listed in the
* cntrl_list. However the functionility has been disabled so neither
* StorageController nor NVMeAdmin interface should be exposed for the disabled
* controllers.
*
*/
class NVMeController
{
public:
NVMeController(boost::asio::io_context& io,
sdbusplus::asio::object_server& objServer,
std::shared_ptr<sdbusplus::asio::connection> conn,
std::string path, const SensorData& configData,
std::shared_ptr<NVMeMiIntf> nvmeIntf, nvme_mi_ctrl_t ctrl,
std::weak_ptr<NVMeSubsystem> subsys);
virtual ~NVMeController();
virtual void start(const std::shared_ptr<NVMeControllerPlugin>& nvmePlugin);
virtual void stop();
// set the target as a primary controller with secondary controller list
// with it
inline void setPrimary(
const std::vector<std::shared_ptr<NVMeController>>& secCntrls)
{
isPrimary = true;
setSecAssoc(secCntrls);
}
// set the target as a secondary controller
inline void setSecondary()
{
isPrimary = false;
setSecAssoc({});
}
/**
* @brief Get cntrl_id for the binded NVMe controller
*
* @return cntrl_id
*/
// TODO: replace this with something from libnvme?
uint16_t getCntrlId() const
{
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
return *reinterpret_cast<uint16_t*>(
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
(reinterpret_cast<uint8_t*>(nvmeCtrl) +
std::max(sizeof(uint16_t), sizeof(void*))));
}
/**
* @brief Get the NVMe controller handle
*/
nvme_mi_ctrl_t getMiCtrl() const
{
return nvmeCtrl;
}
/**
* @brief Update association interface.
*
* May be called externally when attached volumes change.
**/
void updateAssociation();
protected:
friend class NVMeControllerPlugin;
bool isPrimary;
boost::asio::io_context& io;
sdbusplus::asio::object_server& objServer;
std::shared_ptr<sdbusplus::asio::connection> conn;
std::string path;
SensorData config;
std::shared_ptr<sdbusplus::asio::dbus_interface> ctrlInterface;
std::shared_ptr<sdbusplus::asio::dbus_interface> securityInterface;
std::shared_ptr<sdbusplus::asio::dbus_interface> passthruInterface;
std::shared_ptr<NVMeMiIntf> nvmeIntf;
nvme_mi_ctrl_t nvmeCtrl;
std::shared_ptr<sdbusplus::asio::dbus_interface> assocIntf;
void createAssociation();
std::vector<Association> makeAssociation() const;
// The association to secondary controllers from a primary controller
std::vector<std::string> secondaryControllers;
// The parent subsystem
std::weak_ptr<NVMeSubsystem> subsys;
// NVMe Plug-in for vendor defined command/field
std::weak_ptr<NVMeControllerPlugin> plugin;
private:
void setSecAssoc(
const std::vector<std::shared_ptr<NVMeController>>& secCntrls);
};
/**
* Forward declaration for metrics
*/
template <nvme_cmd_get_log_lid LID, class ClockType = std::chrono::steady_clock>
class ControllerLogPageMetric;
template <nvme_identify_cns CNS, class ClockType>
class IdentifyMetric;
/**
* @brief A class for the NVMe controller that has been enabled (CC.EN = 1)
*
* The premitted NVMe Admin cmds should be anable to processed via the enabled
* controller (e.g reading the temletries or other admin tasks). Thus the
* NVMeAmin and StorageController Dbus interface will be exposed via this class.
*
*/
class NVMeControllerEnabled :
public NVMeController,
// StorageController interface will be used from PDI once coroutine
// sdbusplus methods are added. In the interim it is implemented manually.
// private sdbusplus::xyz::openbmc_project::Inventory::Item::server::
// StorageController,
private sdbusplus::xyz::openbmc_project::NVMe::server::NVMeAdmin,
public SoftwareExtVersion,
public SoftwareVersion,
public std::enable_shared_from_this<NVMeControllerEnabled>
{
public:
static std::shared_ptr<NVMeControllerEnabled>
create(NVMeController&& nvmeController);
~NVMeControllerEnabled() override;
void
start(const std::shared_ptr<NVMeControllerPlugin>& nvmePlugin) override;
void stop() override;
private:
template <nvme_cmd_get_log_lid LID, class ClockType>
friend class ControllerLogPageMetric;
template <nvme_identify_cns CNS, class ClockType>
friend class IdentifyMetric;
enum class Status : uint8_t
{
Disabled = 0, // the controller is not ready to serve
// DBus calls
Enabled = 1, // the controller is ready to serve DBus calls
};
Status status = Status::Disabled;
std::optional<MetricStore> metricStore;
explicit NVMeControllerEnabled(NVMeController&& nvmeController);
void init();
/* NVMeAdmin method overload */
/** @brief Implementation for GetLogPage
* Send GetLogPage command to NVMe device
*
* @param[in] lid - Log Page Identifier
* @param[in] nsid - Namespace Identifier
* @param[in] lsp - Log Specific Field
* @param[in] lsi - Log Specific Identifier
*
* @return log[sdbusplus::message::unix_fd] - Returned Log
* Page
*/
sdbusplus::message::unix_fd getLogPage(uint8_t lid, uint32_t nsid,
uint8_t lsp, uint16_t lsi) override;
/** @brief Implementation for Identify
* Send Identify command to NVMe device
*
* @param[in] cns - Controller or Namespace Structure
* @param[in] nsid - Namespace Identifier
* @param[in] cntid - Controller Identifier
*
* @return data[sdbusplus::message::unix_fd] - Identify
* Data
*/
sdbusplus::message::unix_fd identify(uint8_t cns, uint32_t nsid,
uint16_t cntid) override;
/** Set value of FirmwareCommitStatus
* Used to reset the the status back to ready if the commit
* is not in process.
*/
NVMeAdmin::FwCommitStatus
firmwareCommitStatus(NVMeAdmin::FwCommitStatus commitStatus) override;
/** @brief Implementation for FirmwareCommitAsync
* Send Firmware Commit command to NVMe device
*
* @param[in] commitAction - Commit Action defined by NVMe
* base spec (Figure 175 of rev 1.4)
* @param[in] firmwareSlot - Firmware Slot
* @param[in] bpid - Boot Partition ID
*/
void firmwareCommitAsync(uint8_t commitAction, uint8_t firmwareSlot,
bool bpid) override;
/** Set value of FirmwareDownloadStatus
* Used to reset the the status back to ready if the
* download is not in process.
*/
NVMeAdmin::FwDownloadStatus firmwareDownloadStatus(
NVMeAdmin::FwDownloadStatus downloadStatus) override;
/** @brief Implementation for FirmwareDownloadAsync
* Send Firmware Image to the NVMe device
*
* @param[in] pathToImage - Path to the firmware image
*/
void firmwareDownloadAsync(std::string pathToImage) override;
void securitySendMethod(boost::asio::yield_context yield, uint8_t proto,
uint16_t protoSpecific, std::span<uint8_t> data);
std::vector<uint8_t> securityReceiveMethod(boost::asio::yield_context yield,
uint8_t proto,
uint16_t protoSpecific,
uint32_t transferLength);
std::tuple<uint32_t, uint32_t, uint32_t>
adminNonDataCmdMethod(boost::asio::yield_context yield, uint8_t opcode,
uint32_t cdw1, uint32_t cdw2, uint32_t cdw3,
uint32_t cdw10, uint32_t cdw11, uint32_t cdw12,
uint32_t cdw13, uint32_t cdw14, uint32_t cdw15);
void attachVolume(boost::asio::yield_context yield,
const sdbusplus::message::object_path& volumePath);
void detachVolume(boost::asio::yield_context yield,
const sdbusplus::message::object_path& volumePath);
};