FeatureStore: Integrate into NVMe objects Instantiates and attaches FeatureStore to Controller, Subsystem, and Volume objects. Design-Doc: go/bmc-redfish-nvme-get-set-features Google-Bug-Id: 405609473 Change-Id: I88312cdc5061f3e3b8c3a022773921f9f5deef69 Signed-off-by: Guangzong Chen <guangzong@google.com>
diff --git a/src/NVMeController.cpp b/src/NVMeController.cpp index 5f2496e..f3aeeef 100644 --- a/src/NVMeController.cpp +++ b/src/NVMeController.cpp
@@ -410,6 +410,25 @@ }); } +void NVMeControllerEnabled::initializeFeatureStore() +{ + if (featureStore) + { + return; + } + + this->featureStore = + std::make_shared<FeatureStore>(io, objServer, conn, path, nvmeIntf, + nvmeCtrl, 0, FeatureScope::Controller); + + this->featureStore->init([](const std::error_code& ec) { + if (ec) + { + lg2::error("Failed to initialize feature store: {ERROR}", "ERROR", + ec.message()); + } + }); +} void NVMeControllerEnabled::start( const std::shared_ptr<NVMeControllerPlugin>& nvmePlugin) { @@ -420,6 +439,7 @@ if (isPrimary) { this->initializeMetricStore(); + this->initializeFeatureStore(); } } @@ -436,6 +456,7 @@ { discoverLogsRetryTimer->cancel(); } + this->featureStore.reset(); } void NVMeController::createAssociation()
diff --git a/src/NVMeController.hpp b/src/NVMeController.hpp index 1e3ead4..9867411 100644 --- a/src/NVMeController.hpp +++ b/src/NVMeController.hpp
@@ -1,6 +1,7 @@ #pragma once +#include "NVMeFeatureStore.hpp" #include "NVMeIntf.hpp" #include "NVMeMetricStore.hpp" #include "NVMePlugin.hpp" @@ -90,6 +91,10 @@ void setNvmeVersion(uint32_t version); + std::shared_ptr<NVMeMiIntf> getNvmeIntf() const + { + return nvmeIntf; + } /** * @brief Update association interface. * @@ -113,6 +118,7 @@ std::shared_ptr<sdbusplus::asio::dbus_interface> securityInterface; std::shared_ptr<sdbusplus::asio::dbus_interface> passthruInterface; std::shared_ptr<sdbusplus::asio::dbus_interface> lockdownInterface; + std::shared_ptr<sdbusplus::asio::dbus_interface> featureStoreIntf; std::shared_ptr<NVMeMiIntf> nvmeIntf; nvme_mi_ctrl_t nvmeCtrl; @@ -202,11 +208,16 @@ Status status = Status::Disabled; std::optional<MetricStore> metricStore; + std::shared_ptr<FeatureStore> featureStore; /** Create Metric store and load all the metric implementations */ void initializeMetricStore(); + /** Create Feature store and load all the feature implementations + */ + void initializeFeatureStore(); + explicit NVMeControllerEnabled(NVMeController&& nvmeController); void init();
diff --git a/src/NVMeFeatureStore.hpp b/src/NVMeFeatureStore.hpp index 49832c7..37f59a7 100644 --- a/src/NVMeFeatureStore.hpp +++ b/src/NVMeFeatureStore.hpp
@@ -28,7 +28,13 @@ std::shared_ptr<NVMeMiIntf> nvmeIntf, nvme_mi_ctrl_t ctrl, uint32_t nsid, FeatureScope scope); - virtual ~FeatureStore() = default; + virtual ~FeatureStore() + { + if (dbusIntf) + { + objServer.remove_interface(dbusIntf); + } + } // Initialize the feature collection by querying the device void init(std::function<void(const std::error_code&)>&& cb);
diff --git a/src/NVMeSubsys.cpp b/src/NVMeSubsys.cpp index 9c5b6cb..41715d7 100644 --- a/src/NVMeSubsys.cpp +++ b/src/NVMeSubsys.cpp
@@ -162,12 +162,47 @@ drive = std::make_shared<NVMeDrive>(io, conn, path, weak_from_this()); drive->protocol(NVMeDrive::DriveProtocol::NVMe); drive->type(NVMeDrive::DriveType::SSD); - // TODO: update capacity - - // make association for Drive/Storage/Chassis createAssociation(); } +void NVMeSubsystem::initializeFeatureStore() +{ + if (featureStore) + { + return; + } + + std::shared_ptr<NVMeControllerEnabled> ctrl; + try + { + ctrl = getPrimaryController(); + } + catch (const std::exception& e) + { + // Suppress error if no controller is available yet (e.g. during initial + // scan) + return; + } + + if (!ctrl) + { + return; + } + + this->featureStore = std::make_shared<FeatureStore>( + io, objServer, conn, path, ctrl->getNvmeIntf(), ctrl->getMiCtrl(), 0, + FeatureScope::Subsystem); + + this->featureStore->init([](const std::error_code& ec) { + if (ec) + { + lg2::error( + "Failed to initialize feature store for subsystem: {ERROR}", + "ERROR", ec.message()); + } + }); +} + NVMeSubsystem::~NVMeSubsystem() { objServer.remove_interface(assocIntf); @@ -224,6 +259,7 @@ secCntrls.push_back(secondaryController); } primaryController->setPrimary(secCntrls); + initializeFeatureStore(); (void)boost::asio::spawn(io, [self{shared_from_this()}]( const boost::asio::yield_context& yield) { @@ -852,6 +888,11 @@ { plugin.reset(); } + + if (featureStore) + { + featureStore.reset(); + } } sdbusplus::message::object_path
diff --git a/src/NVMeSubsys.hpp b/src/NVMeSubsys.hpp index 877a587..7ca9c47 100644 --- a/src/NVMeSubsys.hpp +++ b/src/NVMeSubsys.hpp
@@ -2,6 +2,7 @@ #include "NVMeBasic.hpp" #include "NVMeController.hpp" #include "NVMeDrive.hpp" +#include "NVMeFeatureStore.hpp" #include "NVMePlugin.hpp" #include "NVMeProgress.hpp" #include "NVMeSensor.hpp" @@ -96,6 +97,9 @@ friend class NVMeTest; #endif + // may throw NVMeError if no controller is available + std::shared_ptr<NVMeControllerEnabled> getPrimaryController() const; + private: friend class NVMePlugin; @@ -184,6 +188,10 @@ std::shared_ptr<sdbusplus::asio::dbus_interface> assocIntf; + std::shared_ptr<FeatureStore> featureStore; + + void initializeFeatureStore(); + void createAssociation(); void updateAssociation(); std::vector<Association> makeAssociation() const; @@ -195,9 +203,6 @@ // mark the availability of the Storage device. void markAvailable(bool toggle); - // may throw NVMeError if no controller is available - std::shared_ptr<NVMeControllerEnabled> getPrimaryController() const; - sdbusplus::message::object_path createVolume(boost::asio::yield_context yield, uint64_t size, size_t lbaFormat, bool metadataAtEnd) override;
diff --git a/src/NVMeVolume.cpp b/src/NVMeVolume.cpp index 82b2f20..4920fa2 100644 --- a/src/NVMeVolume.cpp +++ b/src/NVMeVolume.cpp
@@ -75,6 +75,7 @@ VolumeBase::emit_added(); NvmeVolumeBase::emit_added(); initializeMetricStore(); + initializeFeatureStore(); } std::shared_ptr<NVMeVolume> @@ -128,3 +129,47 @@ { 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( + "Failed to get primary controller for feature store: {ERROR}", + "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([](const std::error_code& ec) { + if (ec) + { + lg2::error("Failed to initialize feature store for volume: {ERROR}", + "ERROR", ec.message()); + } + }); +}
diff --git a/src/NVMeVolume.hpp b/src/NVMeVolume.hpp index 8922add..fbdafca 100644 --- a/src/NVMeVolume.hpp +++ b/src/NVMeVolume.hpp
@@ -69,7 +69,13 @@ std::optional<MetricStore> metricStore; + std::shared_ptr<FeatureStore> featureStore; + /** Create Metric store and load all the metric implementations */ void initializeMetricStore(); + + /** Create Feature store and load all the feature implementations + */ + void initializeFeatureStore(); };
diff --git a/tests/meson.build b/tests/meson.build index 266db3d..8e89d85 100644 --- a/tests/meson.build +++ b/tests/meson.build
@@ -81,6 +81,7 @@ '../src/NVMeSensor.cpp', '../src/NVMeSubsys.cpp', '../src/NVMeController.cpp', + '../src/NVMeFeatureStore.cpp', '../src/NVMeError.cpp', '../src/NVMeProgress.cpp', '../src/NVMeStorage.cpp',
diff --git a/tests/test_nvme_mi.cpp b/tests/test_nvme_mi.cpp index 240b4cf..6025d4b 100644 --- a/tests/test_nvme_mi.cpp +++ b/tests/test_nvme_mi.cpp
@@ -223,6 +223,14 @@ systemBus->request_name("xyz.openbmc_project.NVMeTest"); subsys->unavailableMaxCount = 1; subsys->pollingInterval = subsysPollTime; + + ON_CALL(mock, adminGetFeatures) + .WillByDefault([](nvme_mi_ctrl_t, + const NVMeMiIntf::GetFeaturesRequest&, + std::function<void(nvme_ex_ptr, uint32_t, + std::span<uint8_t>)>&& cb) { + cb(nullptr, 0, {}); + }); } static void SetUpTestSuite()