blob: 88ed189698e5f051d43b40efae3ef44f9ecc892a [file] [log] [blame]
#pragma once
#include "NVMeCache.hpp"
#include "Utils.hpp"
#include <libnvme-mi.h>
#include <functional>
#include <memory>
#include <span>
#include <string>
#include <unordered_map>
class NVMeSubsystem;
class NVMeController;
class NVMePlugin;
class NVMeControllerPlugin;
// A map from library name to the dlopen() pointer
extern std::unordered_map<std::string, void*> pluginLibMap;
// entry function for plugin library to create the plugin instance
using createplugin_t = std::shared_ptr<NVMePlugin> (*)(
std::shared_ptr<NVMeSubsystem> subsys, const SensorData& config);
class NVMeControllerPlugin
{
public:
using getlogpage_t = std::function<void(
uint8_t lid, uint32_t nsid, uint8_t lsp, uint16_t lsi,
std::function<void(const std::error_code&, std::span<uint8_t>)>&& cb)>;
// The controller plugin can only be created from NVMePlugin
NVMeControllerPlugin(std::shared_ptr<NVMeController> cntl,
[[maybe_unused]] const SensorData& cfg) :
nvmeController(std::move(cntl))
{}
virtual ~NVMeControllerPlugin() = default;
virtual getlogpage_t getGetLogPageHandler()
{
return {};
}
protected:
const std::string& getPath() const;
sdbusplus::asio::object_server& getDbusServer();
std::shared_ptr<sdbusplus::asio::connection> getDbusConnection();
boost::asio::io_context& getIOContext();
bool isPrimary() const;
/**
* adminXfer() - transfer Raw admin cmd to the binded conntroller
* @admin_req: request header
* @data: request data payload
* @timeout_ms: timeout in ms
* @resp_data_offset: offset into request data to retrieve from controller
* @cb: callback function after the response received.
* @ec: error code
* @admin_resp: response header
* @resp_data: response data payload
*
* Performs an arbitrary NVMe Admin command, using the provided request
* header, in @admin_req. The requested data is attached by @data, if any.
*
* On success, @cb will be called and response header and data are stored
* in
* @admin_resp and @resp_data, which has an optional appended payload
* buffer. The response data does not include the Admin request header, so
* 0 represents no payload.
*
* As with all Admin commands, we can request partial data from the Admin
* Response payload, offset by @resp_data_offset. In case of resp_data
* contains only partial data of the caller's requirement, a follow-up
* call to adminXfer with offset is required.
*
* See: &struct nvme_mi_admin_req_hdr and &struct nvme_mi_admin_resp_hdr.
*
* @ec will be returned on failure.
*/
void adminXfer(const nvme_mi_admin_req_hdr& adminReq,
std::span<uint8_t> data, unsigned int timeoutMs,
std::function<void(const std::error_code& ec,
const nvme_mi_admin_resp_hdr& adminResp,
std::span<uint8_t> respData)>&& cb);
/**
* @brief Get cntrl_id for the binded NVMe controller
*
* @return cntrl_id
*/
uint16_t getCntrlId() const;
private:
std::shared_ptr<NVMeController> nvmeController;
};
class NVMePlugin
{
public:
NVMePlugin(std::shared_ptr<NVMeSubsystem> subsys, const SensorData& config);
virtual ~NVMePlugin();
std::shared_ptr<NVMeControllerPlugin>
createControllerPlugin(const NVMeController& controller,
const SensorData& config);
// the NVMe subsystem will start the plugin after NVMesubsystem finished
// intialization and started.
virtual void start() {}
// the NVMe subsystem will stop the plugin before NVMe subsystem stop
// itself.
virtual void stop() {}
// get Vendor Metric for given path
virtual std::vector<std::shared_ptr<MetricBase<>>>
getMetric(const std::string& /*path*/) noexcept
{
return {};
}
static constexpr const char* libraryPath = "/usr/lib/nvmed/";
protected:
const std::string& getPath() const;
const std::string& getName() const;
boost::asio::io_context& getIOContext();
sdbusplus::asio::object_server& getDbusServer();
std::shared_ptr<sdbusplus::asio::connection> getDbusConnection();
const std::map<uint16_t, std::pair<std::shared_ptr<NVMeController>,
std::shared_ptr<NVMeControllerPlugin>>>&
getControllers();
// The nvme plugin implemenation need to overload the function to create a
// derived controller plugin.
virtual std::shared_ptr<NVMeControllerPlugin>
makeController(std::shared_ptr<NVMeController> cntl,
const SensorData&) = 0;
private:
std::shared_ptr<NVMeSubsystem> subsystem;
};