| #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); |
| } |
| } |