blob: b0afbe8eee30e1b032dbd8a8eee766a97e2a7488 [file]
#include "NVMeVolume.hpp"
#include "dbus-sensor_config.h"
#include "NVMeCacheImpl.hpp"
#include "Utils.hpp"
using SchedulerClockType = std::chrono::steady_clock;
NVMeVolume::NVMeVolume(sdbusplus::asio::object_server& objServer,
const std::shared_ptr<sdbusplus::asio::connection>& conn,
const std::shared_ptr<NVMeSubsystem>& subsys,
const NVMeNSIdentify& ns) :
VolumeBase(dynamic_cast<sdbusplus::bus_t&>(*conn),
subsys->volumePath(ns.namespaceId).c_str()),
path(subsys->volumePath(ns.namespaceId)), objServer(objServer), conn(conn),
subsys(subsys), nsIdentify(ns)
{
size(ns.size, false);
blockSize(ns.blockSize, false);
nvmeVolumeInterface =
objServer.add_interface(path, "xyz.openbmc_project.Nvme.Volume");
nvmeVolumeInterface->register_property("NamespaceId", ns.namespaceId);
nvmeVolumeInterface->register_property("LBAFormat",
static_cast<size_t>(ns.lbaFormat));
nvmeVolumeInterface->register_property("MetadataAtEnd", ns.metadataAtEnd);
// see init() for other initialisation
}
void NVMeVolume::initializeMetricStore()
{
// if metric store feature is disabled then create empty metric store
// the dbus interface will be there but with no metrics
if (!isMetricStoreEnabled())
{
metricStore.emplace(conn->get_io_context(), conn, path);
return;
}
auto scheduler = Scheduler<SchedulerClockType>::getScheduler(path);
using IdentifyMetric =
IdentifyMetric<NVME_IDENTIFY_CNS_NS, SchedulerClockType>;
auto identify = std::make_shared<IdentifyMetric>(
this->shared_from_this(), scheduler,
// Identify info is persist throughout the namespace
// lifecycle i.e. from start() to stop()
IdentifyMetric::ClockType::duration::max());
metricStore.emplace(conn->get_io_context(), conn, path,
std::move(identify));
}
void NVMeVolume::init()
{
deleteInterface =
objServer.add_interface(path, "xyz.openbmc_project.Object.Delete");
deleteInterface->register_method(
"Delete", [weak{weak_from_this()}](boost::asio::yield_context yield) {
auto self = weak.lock();
if (!self)
{
throw std::runtime_error("volume delete called twice?");
}
auto subsys = self->subsys.lock();
if (!subsys)
{
throw std::runtime_error("nvmesensor is shutting down");
}
subsys->deleteVolume(std::move(yield), self);
});
deleteInterface->initialize();
nvmeVolumeInterface->register_method(
"Format", [weak{weak_from_this()}](
boost::asio::yield_context yield, uint8_t lbaFormat,
sdbusplus::xyz::openbmc_project::NVMe::server::Format::
SecureEraseSetting secureEraseSetting,
sdbusplus::xyz::openbmc_project::NVMe::server::Format::
DataProtectionType dataProtectionType) {
auto self = weak.lock();
if (!self)
{
throw sdbusplus::xyz::openbmc_project::Common::Error::Unavailable();
}
self->format(std::move(yield), lbaFormat, secureEraseSetting,
dataProtectionType);
});
nvmeVolumeInterface->initialize();
VolumeBase::emit_added();
initializeMetricStore();
initializeFeatureStore();
}
std::shared_ptr<NVMeVolume>
NVMeVolume::create(sdbusplus::asio::object_server& objServer,
const std::shared_ptr<sdbusplus::asio::connection>& conn,
const std::shared_ptr<NVMeSubsystem>& subsys,
const NVMeNSIdentify& ns)
{
auto self = std::shared_ptr<NVMeVolume>(
new NVMeVolume(objServer, conn, subsys, ns));
self->init();
return self;
}
NVMeVolume::~NVMeVolume()
{
metricStore.reset();
VolumeBase::emit_removed();
objServer.remove_interface(deleteInterface);
objServer.remove_interface(nvmeVolumeInterface);
}
void NVMeVolume::erase(VolumeBase::EraseMethod eraseType)
{
(void)eraseType;
// TODO: will need dbus async method handling.
throw std::runtime_error("volume erase not yet implemented");
}
// Additional methods on Volume that are not relevant.
void NVMeVolume::formatLuks([[maybe_unused]] std::vector<uint8_t> password,
[[maybe_unused]] VolumeBase::FilesystemType type)
{
throw std::runtime_error("Method Not Supported");
}
void NVMeVolume::lock()
{
throw std::runtime_error("Method Not Supported");
}
void NVMeVolume::unlock([[maybe_unused]] std::vector<uint8_t> password)
{
throw std::runtime_error("Method Not Supported");
}
void NVMeVolume::changePassword(
[[maybe_unused]] std::vector<uint8_t> oldPassword,
[[maybe_unused]] std::vector<uint8_t> newPassword)
{
throw std::runtime_error("Method Not Supported");
}
void NVMeVolume::initializeFeatureStore()
{
if (featureStore)
{
return;
}
auto subsysPtr = subsys.lock();
if (!subsysPtr)
{
return;
}
std::shared_ptr<NVMeControllerEnabled> ctrl;
try
{
ctrl = subsysPtr->getPrimaryController();
}
catch (const std::exception& e)
{
lg2::error(
"[{PATH}]Failed to get primary controller for feature store: {ERROR}",
"PATH", path, "ERROR", e.what());
return;
}
if (!ctrl)
{
return;
}
this->featureStore = std::make_shared<FeatureStore>(
conn->get_io_context(), objServer, conn, path, ctrl->getNvmeIntf(),
ctrl->getMiCtrl(), namespaceId(), FeatureScope::Namespace);
this->featureStore->init([selfWeak{weak_from_this()},
path = this->path](const std::error_code& ec) {
if (ec)
{
if (ec == std::errc::no_such_device ||
ec == std::errc::not_supported)
{
lg2::info(
"[{PATH}]Feature store not supported for volume: {ERROR}",
"PATH", path, "ERROR", ec.message());
}
else
{
lg2::error(
"[{PATH}]Failed to initialize feature store for volume: {ERROR}",
"PATH", path, "ERROR", ec.message());
}
auto self = selfWeak.lock();
if (self)
{
self->featureStore.reset();
}
}
});
}
void NVMeVolume::format(
boost::asio::yield_context yield, uint8_t lbaFormat,
sdbusplus::xyz::openbmc_project::NVMe::server::Format::SecureEraseSetting
secureEraseSetting,
sdbusplus::xyz::openbmc_project::NVMe::server::Format::DataProtectionType
dataProtectionType)
{
if (auto s = subsys.lock())
{
s->formatNamespace(std::move(yield), lbaFormat, secureEraseSetting,
dataProtectionType, nsIdentify.namespaceId);
return;
}
throw sdbusplus::xyz::openbmc_project::Common::Error::Unavailable();
}
void NVMeVolume::updateNSIdentify(const NVMeNSIdentify& ns)
{
nsIdentify = ns;
size(ns.size);
blockSize(ns.blockSize);
if (nvmeVolumeInterface)
{
nvmeVolumeInterface->set_property("NamespaceId", ns.namespaceId);
nvmeVolumeInterface->set_property("LBAFormat",
static_cast<size_t>(ns.lbaFormat));
nvmeVolumeInterface->set_property("MetadataAtEnd", ns.metadataAtEnd);
}
}