dbus-sensors: Refresh the nvmesensor patches
Adding new features for nvmesensor:
* warm reboot
** health poll based enumeration
** host power signal handling
* nvme telemetry log chuck fetch
Tested:
* Warm reboot: b/267654194#comment20 ~ comment#22
* telemetry log: as part of nvme CBTRM: b/267654194#comment23
Google-Bug-Id: 267654194
Google-Bug-Id: 289134789
Change-Id: I984347cbfe2907565d7d2da41ef2766020d13255
Signed-off-by: Hao Jiang <jianghao@google.com>
diff --git a/recipes-phosphor/sensors/dbus-sensors/0001-nvmesensor-rename-the-files.patch b/recipes-phosphor/sensors/dbus-sensors/0001-nvmesensor-rename-the-files.patch
new file mode 100644
index 0000000..9dbde16
--- /dev/null
+++ b/recipes-phosphor/sensors/dbus-sensors/0001-nvmesensor-rename-the-files.patch
@@ -0,0 +1,99 @@
+From abe940aab4c575f542facb0b165db3387f334d14 Mon Sep 17 00:00:00 2001
+From: Hao Jiang <jianghao@google.com>
+Date: Tue, 9 May 2023 01:25:12 +0000
+Subject: [PATCH 01/44] nvmesensor: rename the files
+
+Get prepared for the code refactor of supporting both NVMe Basic and
+NVMe-Mi protocol.
+
+The NVMeContext is renamed to NVMeIntf which will be the common
+interface for both protocols.
+
+Context is removed from the naming and its functinality will be moved
+into NVMe subsystem, which provide the full OOB management beyond the
+thermal reading. The naming will be more consitant with the nvme spec.
+
+NVMeBasicContext is also renamed to NVMeBasic which is the
+implementation of NVMeIntf for NVMe Basic protocol.
+
+Signed-off-by: Hao Jiang <jianghao@google.com>
+Change-Id: I76a8544297e87a4e8f2e4483bd09dd9e3889d4c5
+---
+ src/{NVMeBasicContext.cpp => NVMeBasic.cpp} | 2 +-
+ src/{NVMeBasicContext.hpp => NVMeBasic.hpp} | 2 +-
+ src/{NVMeContext.hpp => NVMeIntf.hpp} | 0
+ src/NVMeSensorMain.cpp | 4 ++--
+ src/meson.build | 7 +++++--
+ 5 files changed, 9 insertions(+), 6 deletions(-)
+ rename src/{NVMeBasicContext.cpp => NVMeBasic.cpp} (99%)
+ rename src/{NVMeBasicContext.hpp => NVMeBasic.hpp} (98%)
+ rename src/{NVMeContext.hpp => NVMeIntf.hpp} (100%)
+
+diff --git a/src/NVMeBasicContext.cpp b/src/NVMeBasic.cpp
+similarity index 99%
+rename from src/NVMeBasicContext.cpp
+rename to src/NVMeBasic.cpp
+index 0bc2252..29407e8 100644
+--- a/src/NVMeBasicContext.cpp
++++ b/src/NVMeBasic.cpp
+@@ -1,4 +1,4 @@
+-#include "NVMeBasicContext.hpp"
++#include "NVMeBasic.hpp"
+
+ #include <endian.h>
+ #include <sys/ioctl.h>
+diff --git a/src/NVMeBasicContext.hpp b/src/NVMeBasic.hpp
+similarity index 98%
+rename from src/NVMeBasicContext.hpp
+rename to src/NVMeBasic.hpp
+index 52b6a09..a443d8c 100644
+--- a/src/NVMeBasicContext.hpp
++++ b/src/NVMeBasic.hpp
+@@ -1,6 +1,6 @@
+ #pragma once
+
+-#include "NVMeContext.hpp"
++#include "NVMeIntf.hpp"
+
+ #include <boost/asio/io_context.hpp>
+ #include <boost/asio/posix/stream_descriptor.hpp>
+diff --git a/src/NVMeContext.hpp b/src/NVMeIntf.hpp
+similarity index 100%
+rename from src/NVMeContext.hpp
+rename to src/NVMeIntf.hpp
+diff --git a/src/NVMeSensorMain.cpp b/src/NVMeSensorMain.cpp
+index ef1abbe..8854662 100644
+--- a/src/NVMeSensorMain.cpp
++++ b/src/NVMeSensorMain.cpp
+@@ -14,8 +14,8 @@
+ // limitations under the License.
+ */
+
+-#include "NVMeBasicContext.hpp"
+-#include "NVMeContext.hpp"
++#include "NVMeBasic.hpp"
++#include "NVMeIntf.hpp"
+ #include "NVMeSensor.hpp"
+
+ #include <boost/asio/steady_timer.hpp>
+diff --git a/src/meson.build b/src/meson.build
+index 665517a..093ae1f 100644
+--- a/src/meson.build
++++ b/src/meson.build
+@@ -186,8 +186,11 @@ if get_option('mcu').enabled()
+ endif
+
+ if get_option('nvme').enabled()
+- nvme_srcs = files('NVMeSensorMain.cpp', 'NVMeSensor.cpp')
+- nvme_srcs += files('NVMeBasicContext.cpp')
++ nvme_srcs = [
++ 'NVMeSensorMain.cpp',
++ 'NVMeSensor.cpp',
++ 'NVMeBasic.cpp'
++ ]
+
+ nvme_deps = [ default_deps, i2c, thresholds_dep, utils_dep, threads ]
+
+--
+2.34.1
+
diff --git a/recipes-phosphor/sensors/dbus-sensors/0001-nvme-sensor-refactor-the-code.patch b/recipes-phosphor/sensors/dbus-sensors/0002-nvme-sensor-refactor-the-code.patch
similarity index 89%
rename from recipes-phosphor/sensors/dbus-sensors/0001-nvme-sensor-refactor-the-code.patch
rename to recipes-phosphor/sensors/dbus-sensors/0002-nvme-sensor-refactor-the-code.patch
index c31605e..2887ac3 100644
--- a/recipes-phosphor/sensors/dbus-sensors/0001-nvme-sensor-refactor-the-code.patch
+++ b/recipes-phosphor/sensors/dbus-sensors/0002-nvme-sensor-refactor-the-code.patch
@@ -1,11 +1,11 @@
-From 2d40f5d5454621f313e07ee25243c4ba961bd831 Mon Sep 17 00:00:00 2001
+From 9ceb1c6b68ef8123344729b7c2bf6b1eab7d5831 Mon Sep 17 00:00:00 2001
From: Hao Jiang <jianghao@google.com>
Date: Mon, 29 Aug 2022 17:21:06 +0000
-Subject: [PATCH 01/34] nvme sensor: refactor the code
+Subject: [PATCH 02/44] nvme sensor: refactor the code
Refactor the code in order to adapt to the hierachy of the NVMe
subsystem exposed by NVMe-MI spec. The new design is documented at:
-https://github.com/openbmc/docs/blob/628472ab74a0803ed7d726e6a95b00e0767790b9/designs/nvmed.md
+https://gerrit.openbmc.org/plugins/gitiles/openbmc/docs/+/10f2d00fbcfb97cfb02a1ee4005d82f237783668/designs/nvmed.md
The refactor follows the design pattern of MVC (Model-View-Controller).
@@ -20,9 +20,6 @@
together. It schedules the data retrieve from Model and update the
corresponding View in the heirachy.
-Undefine `BOOST_ASIO_NO_DEPRECATED` temporarily until all nvme mi
-patches are merged. An all-in-one fix will be applied.
-
Tested:
Nuvoton with Samsung PM1733V5TLC
@@ -123,36 +120,25 @@
Signed-off-by: Hao Jiang <jianghao@google.com>
Change-Id: Ib99f3c1ab6d65533cb80804abd119f0d4a9f0f8a
---
- src/{NVMeBasicContext.cpp => NVMeBasic.cpp} | 193 ++++++++---------
- src/NVMeBasic.hpp | 50 +++++
- src/NVMeBasicContext.hpp | 48 -----
- src/NVMeContext.hpp | 109 ----------
- src/NVMeIntf.hpp | 43 ++++
- src/NVMeSensor.cpp | 9 +-
- src/NVMeSensor.hpp | 4 +-
- src/NVMeSensorMain.cpp | 219 +++++++++-----------
- src/NVMeSubsys.cpp | 215 +++++++++++++++++++
- src/NVMeSubsys.hpp | 70 +++++++
- src/meson.build | 11 +-
- 11 files changed, 569 insertions(+), 402 deletions(-)
- rename src/{NVMeBasicContext.cpp => NVMeBasic.cpp} (71%)
- create mode 100644 src/NVMeBasic.hpp
- delete mode 100644 src/NVMeBasicContext.hpp
- delete mode 100644 src/NVMeContext.hpp
- create mode 100644 src/NVMeIntf.hpp
+ src/NVMeBasic.cpp | 192 ++++++++++++++++-------------------
+ src/NVMeBasic.hpp | 64 ++++++------
+ src/NVMeIntf.hpp | 149 ++++++++++++---------------
+ src/NVMeSensor.cpp | 9 +-
+ src/NVMeSensor.hpp | 4 +-
+ src/NVMeSensorMain.cpp | 212 +++++++++++++++++----------------------
+ src/NVMeSubsys.cpp | 223 +++++++++++++++++++++++++++++++++++++++++
+ src/NVMeSubsys.hpp | 69 +++++++++++++
+ src/meson.build | 6 +-
+ 9 files changed, 573 insertions(+), 355 deletions(-)
create mode 100644 src/NVMeSubsys.cpp
create mode 100644 src/NVMeSubsys.hpp
-diff --git a/src/NVMeBasicContext.cpp b/src/NVMeBasic.cpp
-similarity index 71%
-rename from src/NVMeBasicContext.cpp
-rename to src/NVMeBasic.cpp
-index 0bc2252..b2cb44e 100644
---- a/src/NVMeBasicContext.cpp
+diff --git a/src/NVMeBasic.cpp b/src/NVMeBasic.cpp
+index 29407e8..8390452 100644
+--- a/src/NVMeBasic.cpp
+++ b/src/NVMeBasic.cpp
@@ -1,20 +1,15 @@
--#include "NVMeBasicContext.hpp"
-+#include "NVMeBasic.hpp"
+ #include "NVMeBasic.hpp"
#include <endian.h>
-#include <sys/ioctl.h>
@@ -323,7 +309,7 @@
return;
}
-@@ -336,81 +366,30 @@ void NVMeBasicContext::readAndProcessNVMeSensor()
+@@ -336,81 +366,31 @@ void NVMeBasicContext::readAndProcessNVMeSensor()
/* Deserialise the response */
response->consume(1); /* Drop the length byte */
std::istream is(response.get());
@@ -379,6 +365,7 @@
- {
- self->readAndProcessNVMeSensor();
+ data->erase(data->begin());
++ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ cb({}, reinterpret_cast<DriveStatus*>(data->data()));
+ });
}
@@ -427,87 +414,38 @@
- sensor->updateValue(value);
-}
diff --git a/src/NVMeBasic.hpp b/src/NVMeBasic.hpp
-new file mode 100644
-index 0000000..0a54a55
---- /dev/null
+index a443d8c..3be3051 100644
+--- a/src/NVMeBasic.hpp
+++ b/src/NVMeBasic.hpp
-@@ -0,0 +1,50 @@
-+#pragma once
-+
+@@ -1,48 +1,50 @@
+ #pragma once
+
+#include "FileHandle.hpp"
-+#include "NVMeIntf.hpp"
-+
-+#include <boost/asio.hpp>
-+#include <boost/asio/posix/stream_descriptor.hpp>
-+
-+#include <thread>
-+
-+class NVMeBasicIO
-+{
-+ public:
-+ NVMeBasicIO(
-+ boost::asio::io_context& io,
-+ std::function<ssize_t(FileHandle& in, FileHandle& out)>&& procFunc);
-+ boost::asio::posix::stream_descriptor reqStream;
-+ boost::asio::posix::stream_descriptor respStream;
-+
-+ private:
-+ std::jthread thread;
-+};
-+
-+// NVMe Basic Management Command
-+// NVMe MI Spec Appendix A.
-+class NVMeBasic :
-+ public NVMeBasicIntf,
-+ public std::enable_shared_from_this<NVMeBasic>
-+{
-+ public:
-+ NVMeBasic(boost::asio::io_context& io, int bus, int addr);
-+
-+ int getBus() const override
-+ {
-+ return bus;
-+ }
-+ int getAddr() const override
-+ {
-+ return addr;
-+ }
-+ void getStatus(std::function<void(const std::error_code&, DriveStatus*)>&&
-+ cb) override;
-+ ~NVMeBasic() override = default;
-+
-+ private:
-+ boost::asio::io_context& io;
-+ int bus;
-+ int addr;
-+ std::shared_ptr<NVMeBasicIO> basicIO;
-+};
-diff --git a/src/NVMeBasicContext.hpp b/src/NVMeBasicContext.hpp
-deleted file mode 100644
-index 52b6a09..0000000
---- a/src/NVMeBasicContext.hpp
-+++ /dev/null
-@@ -1,48 +0,0 @@
--#pragma once
--
--#include "NVMeContext.hpp"
--
+ #include "NVMeIntf.hpp"
+
-#include <boost/asio/io_context.hpp>
--#include <boost/asio/posix/stream_descriptor.hpp>
--
--#include <thread>
--
++#include <boost/asio.hpp>
+ #include <boost/asio/posix/stream_descriptor.hpp>
+
+ #include <thread>
+
-class NVMeBasicContext : public NVMeContext
--{
-- public:
++class NVMeBasicIO
+ {
+ public:
- NVMeBasicContext(boost::asio::io_context& io, int rootBus);
- ~NVMeBasicContext() override = default;
- void pollNVMeDevices() override;
- void readAndProcessNVMeSensor() override;
- void processResponse(std::shared_ptr<NVMeSensor>& sensor, void* msg,
- size_t len) override;
--
-- private:
++ NVMeBasicIO(
++ boost::asio::io_context& io,
++ std::function<ssize_t(FileHandle& in, FileHandle& out)>&& procFunc);
++ boost::asio::posix::stream_descriptor reqStream;
++ boost::asio::posix::stream_descriptor respStream;
+
+ private:
- NVMeBasicContext(boost::asio::io_context& io, int rootBus, int cmdOut,
- int streamIn, int streamOut, int cmdIn);
- boost::asio::io_context& io;
@@ -521,57 +459,97 @@
- // on the pipes associated with reqStream and respStream. Rather than trying
- // to force a stop, rely on read()/write() failures from closed pipes to
- // coerce it to exit and thus allow completion of the join().
-- std::jthread thread;
--
+ std::jthread thread;
++};
+
- // Destruction of the stream descriptors has the effect of issuing cancel(),
- // destroying the closure of the callback where we might be carrying
- // weak_ptrs to `this`.
- // https://www.boost.org/doc/libs/1_79_0/doc/html/boost_asio/reference/posix__basic_descriptor/_basic_descriptor.html
- boost::asio::posix::stream_descriptor reqStream;
- boost::asio::posix::stream_descriptor respStream;
--
++// NVMe Basic Management Command
++// NVMe MI Spec Appendix A.
++class NVMeBasic :
++ public NVMeBasicIntf,
++ public std::enable_shared_from_this<NVMeBasic>
++{
++ public:
++ NVMeBasic(boost::asio::io_context& io, int bus, int addr);
+
- enum
-- {
++ int getBus() const override
++ {
++ return bus;
++ }
++ int getAddress() const override
+ {
- NVME_MI_BASIC_SFLGS_DRIVE_NOT_READY = 0x40,
- NVME_MI_BASIC_SFLGS_DRIVE_FUNCTIONAL = 0x20,
- };
--};
-diff --git a/src/NVMeContext.hpp b/src/NVMeContext.hpp
-deleted file mode 100644
-index 14e38a1..0000000
---- a/src/NVMeContext.hpp
-+++ /dev/null
-@@ -1,109 +0,0 @@
--#pragma once
++ return addr;
++ }
++ void getStatus(std::function<void(const std::error_code&, DriveStatus*)>&&
++ cb) override;
++ ~NVMeBasic() override = default;
++
++ private:
++ boost::asio::io_context& io;
++ int bus;
++ int addr;
++ std::shared_ptr<NVMeBasicIO> basicIO;
+ };
+diff --git a/src/NVMeIntf.hpp b/src/NVMeIntf.hpp
+index 14e38a1..6699bae 100644
+--- a/src/NVMeIntf.hpp
++++ b/src/NVMeIntf.hpp
+@@ -1,109 +1,88 @@
+ #pragma once
-
-#include "NVMeSensor.hpp"
-
-#include <boost/asio/io_context.hpp>
-#include <boost/asio/steady_timer.hpp>
-
--#include <memory>
++#include <functional>
+ #include <memory>
-#include <stdexcept>
-
-class NVMeContext : public std::enable_shared_from_this<NVMeContext>
--{
-- public:
++#include <variant>
++
++class NVMeBasicIntf;
++/**
++ * @brief a container class to hold smart ptr to NVMe Basic or NVMe MI
++ * implementation instance
++ */
++class NVMeIntf
+ {
+ public:
- NVMeContext(boost::asio::io_context& io, int rootBus) :
- scanTimer(io), rootBus(rootBus), pollCursor(sensors.end())
-- {
++ enum class Protocol
+ {
- if (rootBus < 0)
- {
- throw std::invalid_argument(
- "Invalid root bus: Bus ID must not be negative");
- }
- }
--
++ NVMeBasic,
++ NVMeMI,
++ };
+
- virtual ~NVMeContext()
- {
- scanTimer.cancel();
- }
--
++ NVMeIntf() = default;
+
- void addSensor(const std::shared_ptr<NVMeSensor>& sensor)
-- {
++ template <class IntfImpl, class... Args>
++ static NVMeIntf create(Args&&... args)
+ {
- sensors.emplace_back(sensor);
- }
-
@@ -579,20 +557,27 @@
- getSensorAtPath(const std::string& path)
- {
- for (auto& sensor : sensors)
-- {
++ NVMeIntf nvmeIntf;
++ if constexpr (std::is_base_of_v<NVMeBasicIntf, IntfImpl>)
+ {
- if (sensor->configurationPath == path)
- {
- return sensor;
- }
-- }
++ nvmeIntf.interface =
++ std::make_shared<IntfImpl>(std::forward<Args>(args)...);
++ return nvmeIntf;
+ }
-
- return std::nullopt;
-- }
--
++ throw std::runtime_error("Unsupported NVMe interface");
+ }
+
- // Post-condition: The sensor list does not contain the provided sensor
- // Post-condition: pollCursor is a valid iterator for the sensor list
- void removeSensor(const std::shared_ptr<NVMeSensor>& sensor)
-- {
++ auto getInferface()
+ {
- // Locate the sensor that we're removing in the sensor list
- auto found = std::find(sensors.begin(), sensors.end(), sensor);
-
@@ -613,67 +598,46 @@
- }
-
- // We're actively polling the sensor list
--
++ return interface;
++ }
+
- // If we're not polling the specific sensor that has been removed, then
- // remove the sensor
- if (*pollCursor != *found)
-- {
++ Protocol getProtocol()
++ {
++ if (std::holds_alternative<std::shared_ptr<NVMeBasicIntf>>(interface))
+ {
- sensors.erase(found);
- return;
-- }
++ return Protocol::NVMeBasic;
+ }
-
- // We're polling the sensor that is being removed
-
- // Remove the sensor and update the poll cursor so the cursor remains
- // valid
- pollCursor = sensors.erase(found);
-- }
--
++ throw std::runtime_error("uninitiated NVMeIntf");
+ }
+
- virtual void close()
-- {
-- scanTimer.cancel();
-- }
--
-- virtual void pollNVMeDevices() = 0;
--
-- virtual void readAndProcessNVMeSensor() = 0;
--
-- virtual void processResponse(std::shared_ptr<NVMeSensor>& sensor, void* msg,
-- size_t len) = 0;
--
-- protected:
-- boost::asio::steady_timer scanTimer;
-- int rootBus; // Root bus for this drive
-- std::list<std::shared_ptr<NVMeSensor>> sensors;
-- std::list<std::shared_ptr<NVMeSensor>>::iterator pollCursor;
--};
--
--using NVMEMap = boost::container::flat_map<int, std::shared_ptr<NVMeContext>>;
--
--NVMEMap& getNVMEMap(void);
-diff --git a/src/NVMeIntf.hpp b/src/NVMeIntf.hpp
-new file mode 100644
-index 0000000..1531eb6
---- /dev/null
-+++ b/src/NVMeIntf.hpp
-@@ -0,0 +1,43 @@
-+#pragma once
-+#include <functional>
-+#include <memory>
-+
-+class NVMeIntf
-+{
-+ public:
-+ NVMeIntf() = default;
-+ virtual ~NVMeIntf() = default;
++ private:
++ std::variant<std::shared_ptr<NVMeBasicIntf>> interface;
+};
+
-+// Interface to get information via NVMe MI Basic CMD protocol.
-+class NVMeBasicIntf : public NVMeIntf
++/**
++ * @brief Interface to get information via NVMe MI Basic CMD protocol.
++ *
++ * Can be used for implementation or mockup
++ */
++class NVMeBasicIntf
+{
+ public:
+ struct DriveStatus
-+ {
+ {
+- scanTimer.cancel();
+- }
+ uint8_t SmartWarnings;
+ uint8_t Temp;
+ uint8_t DriveLifeUsed;
@@ -686,20 +650,33 @@
+ NVME_MI_BASIC_SFLGS_DRIVE_NOT_READY = 0x40,
+ NVME_MI_BASIC_SFLGS_DRIVE_FUNCTIONAL = 0x20,
+ };
-+
+
+- virtual void pollNVMeDevices() = 0;
+ NVMeBasicIntf() = default;
-+
+
+- virtual void readAndProcessNVMeSensor() = 0;
+ // The i2c bus number
+ virtual int getBus() const = 0;
+ // The i2c address for NVMe Basic
-+ virtual int getAddr() const = 0;
-+
++ virtual int getAddress() const = 0;
+
+- virtual void processResponse(std::shared_ptr<NVMeSensor>& sensor, void* msg,
+- size_t len) = 0;
+ // Get NVMe drive status, data address is from 00h~07h
+ virtual void getStatus(
+ std::function<void(const std::error_code&, DriveStatus*)>&& cb) = 0;
-+
-+ ~NVMeBasicIntf() override = default;
-+};
+
+- protected:
+- boost::asio::steady_timer scanTimer;
+- int rootBus; // Root bus for this drive
+- std::list<std::shared_ptr<NVMeSensor>> sensors;
+- std::list<std::shared_ptr<NVMeSensor>>::iterator pollCursor;
++ virtual ~NVMeBasicIntf() = default;
+ };
+-
+-using NVMEMap = boost::container::flat_map<int, std::shared_ptr<NVMeContext>>;
+-
+-NVMEMap& getNVMEMap(void);
diff --git a/src/NVMeSensor.cpp b/src/NVMeSensor.cpp
index e11fae7..3bd743f 100644
--- a/src/NVMeSensor.cpp
@@ -746,19 +723,17 @@
const unsigned int scanDelayTicks = 5 * 60;
sdbusplus::asio::object_server& objServer;
diff --git a/src/NVMeSensorMain.cpp b/src/NVMeSensorMain.cpp
-index ef1abbe..0a72a7a 100644
+index 8854662..01d997b 100644
--- a/src/NVMeSensorMain.cpp
+++ b/src/NVMeSensorMain.cpp
-@@ -14,21 +14,16 @@
- // limitations under the License.
+@@ -15,20 +15,16 @@
*/
--#include "NVMeBasicContext.hpp"
--#include "NVMeContext.hpp"
+ #include "NVMeBasic.hpp"
+-#include "NVMeIntf.hpp"
-#include "NVMeSensor.hpp"
--
-+#include "NVMeBasic.hpp"
+#include "NVMeSubsys.hpp"
+
#include <boost/asio/steady_timer.hpp>
#include <optional>
@@ -776,7 +751,7 @@
static std::optional<int>
extractBusNumber(const std::string& path,
-@@ -44,91 +39,67 @@ static std::optional<int>
+@@ -44,91 +40,68 @@ static std::optional<int>
return std::visit(VariantToIntVisitor(), findBus->second);
}
@@ -812,14 +787,10 @@
+ extractName(const std::string& path, const SensorBaseConfigMap& properties)
{
- if (!busNumber)
-+ auto findName = properties.find("Name");
-+ if (findName == properties.end())
- {
-+ std::cerr << "could not determine configuration name for " << path
-+ << "\n";
- return std::nullopt;
- }
-
+- {
+- return std::nullopt;
+- }
+-
- std::filesystem::path muxPath = deriveRootBusPath(*busNumber);
-
- if (!std::filesystem::is_symlink(muxPath))
@@ -830,11 +801,15 @@
- std::string rootName = std::filesystem::read_symlink(muxPath).filename();
- size_t dash = rootName.find('-');
- if (dash == std::string::npos)
-- {
++ auto findName = properties.find("Name");
++ if (findName == properties.end())
+ {
- std::cerr << "Error finding root bus for " << rootName << "\n";
-- return std::nullopt;
-- }
--
++ std::cerr << "could not determine configuration name for " << path
++ << "\n";
+ return std::nullopt;
+ }
+
- return std::stoi(rootName.substr(0, dash));
+ return std::get<std::string>(findName->second);
}
@@ -865,9 +840,8 @@
}
-static void handleSensorConfigurations(
-- boost::asio::io_context& io, sdbusplus::asio::object_server& objectServer,
+static void handleConfigurations(
-+ boost::asio::io_service& io, sdbusplus::asio::object_server& objectServer,
+ boost::asio::io_context& io, sdbusplus::asio::object_server& objectServer,
std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
- const ManagedObjectType& sensorConfigurations)
+ const ManagedObjectType& nvmeConfigurations)
@@ -891,15 +865,15 @@
+ for (const auto& [interfacePath, configData] : nvmeConfigurations)
{
// find base configuration
-- auto sensorBase =
+ auto sensorBase =
- sensorData.find(configInterfaceName(NVMeSensor::sensorType));
- if (sensorBase == sensorData.end())
-+ auto sensorBase = configData.find(configInterfaceName(NVMeSubsystem::sensorType));
++ configData.find(configInterfaceName(NVMeSubsystem::sensorType));
+ if (sensorBase == configData.end())
{
continue;
}
-@@ -136,65 +107,68 @@ static void handleSensorConfigurations(
+@@ -136,65 +109,68 @@ static void handleSensorConfigurations(
const SensorBaseConfigMap& sensorConfig = sensorBase->second;
std::optional<int> busNumber =
extractBusNumber(interfacePath, sensorConfig);
@@ -956,12 +930,12 @@
+ }
+ try
+ {
-+ std::shared_ptr<NVMeIntf> nvmeBasic{
-+ new NVMeBasic(io, *busNumber, *address)};
++ NVMeIntf nvmeBasic =
++ NVMeIntf::create<NVMeBasic>(io, *busNumber, *address);
+
+ auto nvmeSubsys = std::make_shared<NVMeSubsystem>(
+ io, objectServer, dbusConnection, interfacePath,
-+ *sensorName, configData, nvmeBasic);
++ *sensorName, configData, std::move(nvmeBasic));
+ nvmeSubsysMap.emplace(interfacePath, nvmeSubsys);
+ nvmeSubsys->start();
+ }
@@ -984,7 +958,7 @@
- sdbusplus::asio::object_server& objectServer,
- std::shared_ptr<sdbusplus::asio::connection>& dbusConnection)
+void createNVMeSubsystems(
-+ boost::asio::io_service& io, sdbusplus::asio::object_server& objectServer,
++ boost::asio::io_context& io, sdbusplus::asio::object_server& objectServer,
+ std::shared_ptr<sdbusplus::asio::connection>& dbusConnection)
{
@@ -1007,7 +981,7 @@
{
if (message.is_method_error())
{
-@@ -207,36 +181,33 @@ static void interfaceRemoved(sdbusplus::message_t& message, NVMEMap& contexts)
+@@ -207,36 +183,32 @@ static void interfaceRemoved(sdbusplus::message_t& message, NVMEMap& contexts)
message.read(path, interfaces);
@@ -1051,7 +1025,6 @@
+ systemBus->request_name("xyz.openbmc_project.NVMe");
sdbusplus::asio::object_server objectServer(systemBus, true);
objectServer.add_manager("/xyz/openbmc_project/sensors");
-+ objectServer.add_manager("/xyz/openbmc_project/sensors");
- boost::asio::post(io,
- [&]() { createSensors(io, objectServer, systemBus); });
@@ -1059,7 +1032,7 @@
boost::asio::steady_timer filterTimer(io);
std::function<void(sdbusplus::message_t&)> eventHandler =
-@@ -256,7 +227,7 @@ int main()
+@@ -256,7 +228,7 @@ int main()
return;
}
@@ -1068,7 +1041,7 @@
});
};
-@@ -272,7 +243,7 @@ int main()
+@@ -272,7 +244,7 @@ int main()
"type='signal',member='InterfacesRemoved',arg0path='" +
std::string(inventoryPath) + "/'",
[](sdbusplus::message_t& msg) {
@@ -1079,10 +1052,10 @@
setupManufacturingModeMatch(*systemBus);
diff --git a/src/NVMeSubsys.cpp b/src/NVMeSubsys.cpp
new file mode 100644
-index 0000000..0f02d16
+index 0000000..e4cc768
--- /dev/null
+++ b/src/NVMeSubsys.cpp
-@@ -0,0 +1,215 @@
+@@ -0,0 +1,223 @@
+#include "NVMeSubsys.hpp"
+
+#include "Thresholds.hpp"
@@ -1155,21 +1128,26 @@
+ return reading;
+}
+
-+NVMeSubsystem::NVMeSubsystem(boost::asio::io_context& io,
-+ sdbusplus::asio::object_server& objServer,
++NVMeSubsystem::NVMeSubsystem(boost::asio::io_context& asio,
++ sdbusplus::asio::object_server& server,
+ std::shared_ptr<sdbusplus::asio::connection> conn,
+ const std::string& path, const std::string& name,
-+ const SensorData& configData,
-+ const std::shared_ptr<NVMeIntf>& intf) :
-+ io(io),
-+ objServer(objServer), conn(conn), path(path), name(name), nvmeIntf(intf),
-+ ctempTimer(io)
++ const SensorData& configData, NVMeIntf intf) :
++ io(asio),
++ objServer(server), conn(conn), path(path), name(name),
++ nvmeIntf(std::move(intf)), ctempTimer(io)
+{
-+ if (!intf)
++ NVMeIntf::Protocol protocol{NVMeIntf::Protocol::NVMeBasic};
++ try
++ {
++ protocol = nvmeIntf.getProtocol();
++ }
++ catch (const std::runtime_error&)
+ {
+ throw std::runtime_error("NVMe interface is null");
+ }
-+ if (dynamic_cast<NVMeBasicIntf*>(nvmeIntf.get()) != nullptr)
++
++ if (protocol == NVMeIntf::Protocol::NVMeBasic)
+ {
+ std::optional<std::string> sensorName = createSensorNameFromPath(path);
+ if (!sensorName)
@@ -1199,8 +1177,11 @@
+void NVMeSubsystem::start()
+{
+ // start to poll value for CTEMP sensor.
-+ if (auto intf = std::dynamic_pointer_cast<NVMeBasicIntf>(nvmeIntf))
++ if (nvmeIntf.getProtocol() == NVMeIntf::Protocol::NVMeBasic)
++
+ {
++ auto intf =
++ std::get<std::shared_ptr<NVMeBasicIntf>>(nvmeIntf.getInferface());
+ ctemp_fetcher_t<NVMeBasicIntf::DriveStatus*> dataFether =
+ [intf](std::function<void(const std::error_code&,
+ NVMeBasicIntf::DriveStatus*)>&& cb) {
@@ -1300,10 +1281,10 @@
+}
diff --git a/src/NVMeSubsys.hpp b/src/NVMeSubsys.hpp
new file mode 100644
-index 0000000..fa741b7
+index 0000000..9fdbeb2
--- /dev/null
+++ b/src/NVMeSubsys.hpp
-@@ -0,0 +1,70 @@
+@@ -0,0 +1,69 @@
+#include "NVMeBasic.hpp"
+#include "NVMeSensor.hpp"
+#include "Utils.hpp"
@@ -1317,8 +1298,7 @@
+ sdbusplus::asio::object_server& objServer,
+ std::shared_ptr<sdbusplus::asio::connection> conn,
+ const std::string& path, const std::string& name,
-+ const SensorData& configData,
-+ const std::shared_ptr<NVMeIntf>& intf);
++ const SensorData& configData, NVMeIntf intf);
+
+ void start();
+
@@ -1334,13 +1314,13 @@
+ std::string path;
+ std::string name;
+
-+ std::shared_ptr<NVMeIntf> nvmeIntf;
++ NVMeIntf nvmeIntf;
+
+ /* thermal sensor for the subsystem */
+ std::optional<NVMeSensor> ctemp;
+ boost::asio::steady_timer ctempTimer;
+
-+ // Function type for fetching ctemp which incaplucated in a structure of T.
++ // Function type for fetching ctemp which encaplucated in a structure of T.
+ // The fetcher function take a callback as input to process the result.
+ template <class T>
+ using ctemp_fetcher_t =
@@ -1375,22 +1355,18 @@
+ };
+};
diff --git a/src/meson.build b/src/meson.build
-index 665517a..90a3c6f 100644
+index 093ae1f..ceace5f 100644
--- a/src/meson.build
+++ b/src/meson.build
-@@ -186,16 +186,19 @@ if get_option('mcu').enabled()
- endif
-
- if get_option('nvme').enabled()
-- nvme_srcs = files('NVMeSensorMain.cpp', 'NVMeSensor.cpp')
-- nvme_srcs += files('NVMeBasicContext.cpp')
--
-+ nvme_srcs = [
-+ 'NVMeSensorMain.cpp',
-+ 'NVMeSensor.cpp',
+@@ -189,16 +189,16 @@ if get_option('nvme').enabled()
+ nvme_srcs = [
+ 'NVMeSensorMain.cpp',
+ 'NVMeSensor.cpp',
+- 'NVMeBasic.cpp'
+ 'NVMeBasic.cpp',
+ 'NVMeSubsys.cpp'
-+ ]
+ ]
+-
nvme_deps = [ default_deps, i2c, thresholds_dep, utils_dep, threads ]
executable(
@@ -1398,7 +1374,7 @@
sources: nvme_srcs,
dependencies: nvme_deps,
- cpp_args: uring_args,
-+ cpp_args: [uring_args, '-frtti', '-UBOOST_ASIO_NO_DEPRECATED'],
++ cpp_args: [uring_args, '-UBOOST_ASIO_NO_DEPRECATED'],
install: true,
)
endif
diff --git a/recipes-phosphor/sensors/dbus-sensors/0002-NVMe-sensor-add-Storage-and-Drive-interface.patch b/recipes-phosphor/sensors/dbus-sensors/0003-NVMe-sensor-add-Storage-and-Drive-interface.patch
similarity index 84%
rename from recipes-phosphor/sensors/dbus-sensors/0002-NVMe-sensor-add-Storage-and-Drive-interface.patch
rename to recipes-phosphor/sensors/dbus-sensors/0003-NVMe-sensor-add-Storage-and-Drive-interface.patch
index ba713ca..7d5f578 100644
--- a/recipes-phosphor/sensors/dbus-sensors/0002-NVMe-sensor-add-Storage-and-Drive-interface.patch
+++ b/recipes-phosphor/sensors/dbus-sensors/0003-NVMe-sensor-add-Storage-and-Drive-interface.patch
@@ -1,7 +1,7 @@
-From 97215d05ee8506cc2f4dc85ae701307bfb887ed1 Mon Sep 17 00:00:00 2001
+From e6011f504b61528918e61d24141af2f8a67b09ed Mon Sep 17 00:00:00 2001
From: Hao Jiang <jianghao@google.com>
Date: Thu, 8 Sep 2022 16:43:59 -0700
-Subject: [PATCH 02/34] NVMe sensor: add Storage and Drive interface
+Subject: [PATCH 03/44] NVMe sensor: add Storage and Drive interface
Add xyz.openbmc_project.Inventory.Item.Drive and
xyz.openbmc_project.Inventory.Item.Storage interfaces to the nvme
@@ -14,12 +14,12 @@
Change-Id: Iaa2615f519f5a95dd0cdf3678ca1774b5285f469
---
src/NVMeDrive.hpp | 16 ++++++++++++++++
- src/NVMeSensorMain.cpp | 2 +-
+ src/NVMeSensorMain.cpp | 1 +
src/NVMeStorage.hpp | 17 +++++++++++++++++
src/NVMeSubsys.cpp | 37 ++++++++++++++++++++++++++++++++++++-
src/NVMeSubsys.hpp | 12 ++++++++++++
src/meson.build | 7 ++++++-
- 6 files changed, 88 insertions(+), 3 deletions(-)
+ 6 files changed, 88 insertions(+), 2 deletions(-)
create mode 100644 src/NVMeDrive.hpp
create mode 100644 src/NVMeStorage.hpp
@@ -46,14 +46,13 @@
+ }
+};
diff --git a/src/NVMeSensorMain.cpp b/src/NVMeSensorMain.cpp
-index 0a72a7a..4e5cfc9 100644
+index 01d997b..a7214a4 100644
--- a/src/NVMeSensorMain.cpp
+++ b/src/NVMeSensorMain.cpp
-@@ -205,7 +205,7 @@ int main()
+@@ -207,6 +207,7 @@ int main()
systemBus->request_name("xyz.openbmc_project.NVMe");
sdbusplus::asio::object_server objectServer(systemBus, true);
objectServer.add_manager("/xyz/openbmc_project/sensors");
-- objectServer.add_manager("/xyz/openbmc_project/sensors");
+ objectServer.add_manager("/xyz/openbmc_project/inventory");
io.post([&]() { createNVMeSubsystems(io, objectServer, systemBus); });
@@ -82,7 +81,7 @@
+ }
+};
diff --git a/src/NVMeSubsys.cpp b/src/NVMeSubsys.cpp
-index 0f02d16..d0e41a5 100644
+index e4cc768..bdce4a2 100644
--- a/src/NVMeSubsys.cpp
+++ b/src/NVMeSubsys.cpp
@@ -2,6 +2,8 @@
@@ -117,25 +116,27 @@
// get temporature from a NVMe Basic reading.
static double getTemperatureReading(int8_t reading)
{
-@@ -78,12 +96,16 @@ NVMeSubsystem::NVMeSubsystem(boost::asio::io_context& io,
- const std::shared_ptr<NVMeIntf>& intf) :
- io(io),
- objServer(objServer), conn(conn), path(path), name(name), nvmeIntf(intf),
-- ctempTimer(io)
-+ ctempTimer(io),
+@@ -77,7 +95,9 @@ NVMeSubsystem::NVMeSubsystem(boost::asio::io_context& asio,
+ const SensorData& configData, NVMeIntf intf) :
+ io(asio),
+ objServer(server), conn(conn), path(path), name(name),
+- nvmeIntf(std::move(intf)), ctempTimer(io)
++ nvmeIntf(std::move(intf)), ctempTimer(io),
+ storage(*dynamic_cast<sdbusplus::bus_t*>(conn.get()), path.c_str()),
+ drive(*dynamic_cast<sdbusplus::bus_t*>(conn.get()), path.c_str())
{
- if (!intf)
- {
+ NVMeIntf::Protocol protocol{NVMeIntf::Protocol::NVMeBasic};
+ try
+@@ -89,6 +109,8 @@ NVMeSubsystem::NVMeSubsystem(boost::asio::io_context& asio,
throw std::runtime_error("NVMe interface is null");
}
+
+
+ // initiate the common interfaces (thermal sensor, Drive and Storage)
- if (dynamic_cast<NVMeBasicIntf*>(nvmeIntf.get()) != nullptr)
+ if (protocol == NVMeIntf::Protocol::NVMeBasic)
{
std::optional<std::string> sensorName = createSensorNameFromPath(path);
-@@ -104,6 +126,17 @@ NVMeSubsystem::NVMeSubsystem(boost::asio::io_context& io,
+@@ -109,6 +131,17 @@ NVMeSubsystem::NVMeSubsystem(boost::asio::io_context& asio,
ctemp.emplace(objServer, io, conn, *sensorName,
std::move(sensorThresholds), path);
@@ -153,7 +154,7 @@
}
else
{
-@@ -131,6 +164,8 @@ void NVMeSubsystem::start()
+@@ -139,6 +172,8 @@ void NVMeSubsystem::start()
};
pollCtemp(dataFether, dataParser);
}
@@ -163,7 +164,7 @@
template <class T>
diff --git a/src/NVMeSubsys.hpp b/src/NVMeSubsys.hpp
-index fa741b7..f4b2cc2 100644
+index 9fdbeb2..3e6f1a5 100644
--- a/src/NVMeSubsys.hpp
+++ b/src/NVMeSubsys.hpp
@@ -1,5 +1,7 @@
@@ -174,7 +175,7 @@
#include "Utils.hpp"
class NVMeSubsystem : public std::enable_shared_from_this<NVMeSubsystem>
-@@ -49,6 +51,16 @@ class NVMeSubsystem : public std::enable_shared_from_this<NVMeSubsystem>
+@@ -48,6 +50,16 @@ class NVMeSubsystem : public std::enable_shared_from_this<NVMeSubsystem>
void pollCtemp(const ctemp_fetcher_t<T>& dataFetcher,
const ctemp_parser_t<T>& dataParser);
@@ -192,7 +193,7 @@
// It should contain only static function and using binding to the
// NVMeSubsystem instances. The detail is defined to claim the accessibility
diff --git a/src/meson.build b/src/meson.build
-index 90a3c6f..788cc6b 100644
+index ceace5f..2ec80ce 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -192,7 +192,12 @@ if get_option('nvme').enabled()
diff --git a/recipes-phosphor/sensors/dbus-sensors/0003-nvmesensor-Add-NVMe-MI-protocol-and-controller.patch b/recipes-phosphor/sensors/dbus-sensors/0004-nvmesensor-Add-NVMe-MI-protocol-and-controller.patch
similarity index 86%
rename from recipes-phosphor/sensors/dbus-sensors/0003-nvmesensor-Add-NVMe-MI-protocol-and-controller.patch
rename to recipes-phosphor/sensors/dbus-sensors/0004-nvmesensor-Add-NVMe-MI-protocol-and-controller.patch
index aca0cd7..08e31ec 100644
--- a/recipes-phosphor/sensors/dbus-sensors/0003-nvmesensor-Add-NVMe-MI-protocol-and-controller.patch
+++ b/recipes-phosphor/sensors/dbus-sensors/0004-nvmesensor-Add-NVMe-MI-protocol-and-controller.patch
@@ -1,7 +1,7 @@
-From 4dd8224171dcde2f8efe912236eab9b54ac2f2af Mon Sep 17 00:00:00 2001
+From 5cea63d013d451b7de9f0662a5a9952b9c5c3e36 Mon Sep 17 00:00:00 2001
From: Hao Jiang <jianghao@google.com>
Date: Fri, 16 Sep 2022 18:52:55 -0700
-Subject: [PATCH 03/34] nvmesensor: Add NVMe-MI protocol and controller
+Subject: [PATCH 04/44] nvmesensor: Add NVMe-MI protocol and controller
NVMeMiIntf will expose NVMe-MI and NVMe-MI admin interface in the async
style. NVMeMi class is a implementation of the NVMeMiIntf. It is based
@@ -20,15 +20,15 @@
Change-Id: I2b8d172ed826ca0798b472a8c0bb95c8677e60bb
---
src/NVMeController.hpp | 47 +++++++++
- src/NVMeIntf.hpp | 16 +++
+ src/NVMeIntf.hpp | 35 ++++++-
src/NVMeMi.cpp | 212 +++++++++++++++++++++++++++++++++++++++
src/NVMeMi.hpp | 48 +++++++++
- src/NVMeSensorMain.cpp | 29 ++++++
- src/NVMeSubsys.cpp | 38 ++++++-
+ src/NVMeSensorMain.cpp | 28 ++++++
+ src/NVMeSubsys.cpp | 39 ++++++-
src/NVMeSubsys.hpp | 4 +
src/meson.build | 20 +++-
subprojects/libnvme.wrap | 6 ++
- 9 files changed, 414 insertions(+), 6 deletions(-)
+ 9 files changed, 432 insertions(+), 7 deletions(-)
create mode 100644 src/NVMeController.hpp
create mode 100644 src/NVMeMi.cpp
create mode 100644 src/NVMeMi.hpp
@@ -88,22 +88,62 @@
+ nvme_mi_ctrl_t nvmeCtrl;
+};
diff --git a/src/NVMeIntf.hpp b/src/NVMeIntf.hpp
-index 1531eb6..0fed5fd 100644
+index 6699bae..cb0e0a7 100644
--- a/src/NVMeIntf.hpp
+++ b/src/NVMeIntf.hpp
-@@ -1,4 +1,6 @@
+@@ -1,9 +1,12 @@
#pragma once
+#include <libnvme-mi.h>
+
#include <functional>
#include <memory>
+ #include <variant>
-@@ -41,3 +43,17 @@ class NVMeBasicIntf : public NVMeIntf
+ class NVMeBasicIntf;
++class NVMeMiIntf;
+ /**
+ * @brief a container class to hold smart ptr to NVMe Basic or NVMe MI
+ * implementation instance
+@@ -29,6 +32,14 @@ class NVMeIntf
+ std::make_shared<IntfImpl>(std::forward<Args>(args)...);
+ return nvmeIntf;
+ }
++
++ if constexpr (std::is_base_of_v<NVMeMiIntf, IntfImpl>)
++ {
++ nvmeIntf.interface =
++ std::make_shared<IntfImpl>(std::forward<Args>(args)...);
++ return nvmeIntf;
++ }
++
+ throw std::runtime_error("Unsupported NVMe interface");
+ }
- ~NVMeBasicIntf() override = default;
+@@ -43,11 +54,17 @@ class NVMeIntf
+ {
+ return Protocol::NVMeBasic;
+ }
++ else if (std::holds_alternative<std::shared_ptr<NVMeMiIntf>>(interface))
++ {
++ return Protocol::NVMeMI;
++ }
++
+ throw std::runtime_error("uninitiated NVMeIntf");
+ }
+
+ private:
+- std::variant<std::shared_ptr<NVMeBasicIntf>> interface;
++ std::variant<std::shared_ptr<NVMeBasicIntf>, std::shared_ptr<NVMeMiIntf>>
++ interface;
+ };
+
+ /**
+@@ -86,3 +103,19 @@ class NVMeBasicIntf
+
+ virtual ~NVMeBasicIntf() = default;
};
+
-+class NVMeMiIntf : public NVMeIntf
++class NVMeMiIntf
+{
+ public:
+ virtual int getNID() const = 0;
@@ -115,6 +155,8 @@
+ miScanCtrl(std::function<void(const std::error_code&,
+ const std::vector<nvme_mi_ctrl_t>&)>
+ cb) = 0;
++
++ virtual ~NVMeMiIntf() = default;
+};
diff --git a/src/NVMeMi.cpp b/src/NVMeMi.cpp
new file mode 100644
@@ -389,20 +431,18 @@
+ void post(std::function<void(void)>&& func);
+};
diff --git a/src/NVMeSensorMain.cpp b/src/NVMeSensorMain.cpp
-index 4e5cfc9..d85dac7 100644
+index a7214a4..d0e5274 100644
--- a/src/NVMeSensorMain.cpp
+++ b/src/NVMeSensorMain.cpp
-@@ -15,7 +15,9 @@
+@@ -15,6 +15,7 @@
*/
#include "NVMeBasic.hpp"
+#include "NVMeMi.hpp"
#include "NVMeSubsys.hpp"
-+
- #include <boost/asio/steady_timer.hpp>
- #include <optional>
-@@ -150,6 +152,33 @@ static void handleConfigurations(
+ #include <boost/asio/steady_timer.hpp>
+@@ -152,6 +153,33 @@ static void handleConfigurations(
continue;
}
}
@@ -415,13 +455,13 @@
+ }
+ try
+ {
-+ std::shared_ptr<NVMeIntf> nvmeMi{new NVMeMi(
++ NVMeIntf nvmeMi = NVMeIntf::create<NVMeMi>(
+ io, dynamic_cast<sdbusplus::bus_t&>(*dbusConnection),
-+ *busNumber, *address)};
++ *busNumber, *address);
+
+ auto nvmeSubsys = std::make_shared<NVMeSubsystem>(
+ io, objectServer, dbusConnection, interfacePath,
-+ *sensorName, configData, nvmeMi);
++ *sensorName, configData, std::move(nvmeMi));
+ nvmeSubsysMap.emplace(interfacePath, nvmeSubsys);
+ nvmeSubsys->start();
+ }
@@ -437,29 +477,30 @@
}
diff --git a/src/NVMeSubsys.cpp b/src/NVMeSubsys.cpp
-index d0e41a5..7900295 100644
+index bdce4a2..0ab0653 100644
--- a/src/NVMeSubsys.cpp
+++ b/src/NVMeSubsys.cpp
-@@ -104,9 +104,10 @@ NVMeSubsystem::NVMeSubsystem(boost::asio::io_context& io,
- {
+@@ -109,9 +109,9 @@ NVMeSubsystem::NVMeSubsystem(boost::asio::io_context& asio,
throw std::runtime_error("NVMe interface is null");
}
+
-
-+
// initiate the common interfaces (thermal sensor, Drive and Storage)
-- if (dynamic_cast<NVMeBasicIntf*>(nvmeIntf.get()) != nullptr)
-+ if (dynamic_cast<NVMeBasicIntf*>(nvmeIntf.get()) != nullptr ||
-+ dynamic_cast<NVMeMiIntf*>(nvmeIntf.get()) != nullptr)
+- if (protocol == NVMeIntf::Protocol::NVMeBasic)
++ if (protocol == NVMeIntf::Protocol::NVMeBasic ||
++ protocol == NVMeIntf::Protocol::NVMeMI)
{
std::optional<std::string> sensorName = createSensorNameFromPath(path);
if (!sensorName)
-@@ -146,6 +147,39 @@ NVMeSubsystem::NVMeSubsystem(boost::asio::io_context& io,
+@@ -151,6 +151,41 @@ NVMeSubsystem::NVMeSubsystem(boost::asio::io_context& asio,
void NVMeSubsystem::start()
{
+ // add controllers for the subsystem
-+ if (auto nvme = std::dynamic_pointer_cast<NVMeMiIntf>(nvmeIntf))
++ if (nvmeIntf.getProtocol() == NVMeIntf::Protocol::NVMeMI)
+ {
++ auto nvme =
++ std::get<std::shared_ptr<NVMeMiIntf>>(nvmeIntf.getInferface());
+ nvme->miScanCtrl(
+ [self{shared_from_this()},
+ nvme](const std::error_code& ec,
@@ -491,10 +532,10 @@
+ }
+
// start to poll value for CTEMP sensor.
- if (auto intf = std::dynamic_pointer_cast<NVMeBasicIntf>(nvmeIntf))
- {
+ if (nvmeIntf.getProtocol() == NVMeIntf::Protocol::NVMeBasic)
+
diff --git a/src/NVMeSubsys.hpp b/src/NVMeSubsys.hpp
-index f4b2cc2..1d51cec 100644
+index 3e6f1a5..0a3e8ce 100644
--- a/src/NVMeSubsys.hpp
+++ b/src/NVMeSubsys.hpp
@@ -1,4 +1,5 @@
@@ -503,7 +544,7 @@
#include "NVMeDrive.hpp"
#include "NVMeSensor.hpp"
#include "NVMeStorage.hpp"
-@@ -61,6 +62,9 @@ class NVMeSubsystem : public std::enable_shared_from_this<NVMeSubsystem>
+@@ -60,6 +61,9 @@ class NVMeSubsystem : public std::enable_shared_from_this<NVMeSubsystem>
*/
NVMeDrive drive;
@@ -514,7 +555,7 @@
// It should contain only static function and using binding to the
// NVMeSubsystem instances. The detail is defined to claim the accessibility
diff --git a/src/meson.build b/src/meson.build
-index 788cc6b..9f37585 100644
+index 2ec80ce..4565c01 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -190,13 +190,25 @@ if get_option('nvme').enabled()
diff --git a/recipes-phosphor/sensors/dbus-sensors/0004-Enable-ctemp-sensor-for-nvme-mi.patch b/recipes-phosphor/sensors/dbus-sensors/0005-Enable-ctemp-sensor-for-nvme-mi.patch
similarity index 63%
rename from recipes-phosphor/sensors/dbus-sensors/0004-Enable-ctemp-sensor-for-nvme-mi.patch
rename to recipes-phosphor/sensors/dbus-sensors/0005-Enable-ctemp-sensor-for-nvme-mi.patch
index 50a4656..fa9900a 100644
--- a/recipes-phosphor/sensors/dbus-sensors/0004-Enable-ctemp-sensor-for-nvme-mi.patch
+++ b/recipes-phosphor/sensors/dbus-sensors/0005-Enable-ctemp-sensor-for-nvme-mi.patch
@@ -1,26 +1,37 @@
-From 80a8495e87cba923ffddb19ffe370c07c11c79ab Mon Sep 17 00:00:00 2001
+From 59880f9f6a4277f5e9b2fdb27ded379532cb0d88 Mon Sep 17 00:00:00 2001
From: Hao Jiang <jianghao@google.com>
Date: Wed, 21 Sep 2022 05:49:20 +0000
-Subject: [PATCH 04/34] Enable ctemp sensor for nvme mi
+Subject: [PATCH 05/44] Enable ctemp sensor for nvme mi
polling ctemp from miSubsystemHealthStatusPoll and update the sensor
Signed-off-by: Hao Jiang <jianghao@google.com>
Change-Id: I03601646db8a66d4b7ff687185a4c7fb7d4c6f8e
---
- src/NVMeSubsys.cpp | 22 ++++++++++++++++++++++
- 1 file changed, 22 insertions(+)
+ src/NVMeSubsys.cpp | 26 +++++++++++++++++++++++++-
+ 1 file changed, 25 insertions(+), 1 deletion(-)
diff --git a/src/NVMeSubsys.cpp b/src/NVMeSubsys.cpp
-index 7900295..57668fa 100644
+index 0ab0653..f420282 100644
--- a/src/NVMeSubsys.cpp
+++ b/src/NVMeSubsys.cpp
-@@ -198,6 +198,28 @@ void NVMeSubsystem::start()
+@@ -188,7 +188,6 @@ void NVMeSubsystem::start()
+
+ // start to poll value for CTEMP sensor.
+ if (nvmeIntf.getProtocol() == NVMeIntf::Protocol::NVMeBasic)
+-
+ {
+ auto intf =
+ std::get<std::shared_ptr<NVMeBasicIntf>>(nvmeIntf.getInferface());
+@@ -207,6 +206,31 @@ void NVMeSubsystem::start()
};
pollCtemp(dataFether, dataParser);
}
-+ else if (auto intf = std::dynamic_pointer_cast<NVMeMiIntf>(nvmeIntf))
++ else if (nvmeIntf.getProtocol() == NVMeIntf::Protocol::NVMeMI)
+ {
++ auto intf =
++ std::get<std::shared_ptr<NVMeMiIntf>>(nvmeIntf.getInferface());
++
+ ctemp_fetcher_t<nvme_mi_nvm_ss_health_status*>
+ dataFether =
+ [intf](
diff --git a/recipes-phosphor/sensors/dbus-sensors/0005-nvmesensor-Add-Identify-and-cntrl-association.patch b/recipes-phosphor/sensors/dbus-sensors/0006-nvmesensor-Add-Identify-and-cntrl-association.patch
similarity index 95%
rename from recipes-phosphor/sensors/dbus-sensors/0005-nvmesensor-Add-Identify-and-cntrl-association.patch
rename to recipes-phosphor/sensors/dbus-sensors/0006-nvmesensor-Add-Identify-and-cntrl-association.patch
index 061cbae..75f7328 100644
--- a/recipes-phosphor/sensors/dbus-sensors/0005-nvmesensor-Add-Identify-and-cntrl-association.patch
+++ b/recipes-phosphor/sensors/dbus-sensors/0006-nvmesensor-Add-Identify-and-cntrl-association.patch
@@ -1,7 +1,7 @@
-From fe3d552e865877e326b03fd02bc1cda26f0cd8b4 Mon Sep 17 00:00:00 2001
+From 0d88ee217fadfcdd1583fa662cc07754024ab5c6 Mon Sep 17 00:00:00 2001
From: Hao Jiang <jianghao@google.com>
Date: Fri, 16 Sep 2022 19:26:38 -0700
-Subject: [PATCH 05/34] nvmesensor: Add Identify and cntrl association
+Subject: [PATCH 06/44] nvmesensor: Add Identify and cntrl association
Add Identify to NVMeMi. The NVMeSubsys will identify the primary
controllers and their corresponding secondary controllers. It will
@@ -12,12 +12,12 @@
---
src/NVMeController.cpp | 29 ++++++++++++++
src/NVMeController.hpp | 14 +++++++
- src/NVMeIntf.hpp | 6 +++
+ src/NVMeIntf.hpp | 7 ++++
src/NVMeMi.cpp | 86 ++++++++++++++++++++++++++++++++++++++++++
src/NVMeMi.hpp | 4 ++
src/NVMeSubsys.cpp | 85 ++++++++++++++++++++++++++++++++++++++---
src/meson.build | 9 +++--
- 7 files changed, 223 insertions(+), 10 deletions(-)
+ 7 files changed, 224 insertions(+), 10 deletions(-)
create mode 100644 src/NVMeController.cpp
diff --git a/src/NVMeController.cpp b/src/NVMeController.cpp
@@ -86,7 +86,7 @@
+ std::shared_ptr<sdbusplus::asio::dbus_interface> secAssoc;
};
diff --git a/src/NVMeIntf.hpp b/src/NVMeIntf.hpp
-index 0fed5fd..389289b 100644
+index cb0e0a7..b929ca4 100644
--- a/src/NVMeIntf.hpp
+++ b/src/NVMeIntf.hpp
@@ -3,6 +3,7 @@
@@ -94,13 +94,14 @@
#include <functional>
#include <memory>
+#include <span>
+ #include <variant>
- class NVMeIntf
- {
-@@ -56,4 +57,9 @@ class NVMeMiIntf : public NVMeIntf
- miScanCtrl(std::function<void(const std::error_code&,
- const std::vector<nvme_mi_ctrl_t>&)>
+ class NVMeBasicIntf;
+@@ -118,4 +119,10 @@ class NVMeMiIntf
cb) = 0;
+
+ virtual ~NVMeMiIntf() = default;
++
+ virtual void adminIdentify(
+ nvme_mi_ctrl_t ctrl, nvme_identify_cns cns, uint32_t nsid,
+ uint16_t cntid,
@@ -217,10 +218,10 @@
private:
static nvme_root_t nvmeRoot;
diff --git a/src/NVMeSubsys.cpp b/src/NVMeSubsys.cpp
-index 57668fa..b49743f 100644
+index f420282..426c46d 100644
--- a/src/NVMeSubsys.cpp
+++ b/src/NVMeSubsys.cpp
-@@ -162,21 +162,94 @@ void NVMeSubsystem::start()
+@@ -168,21 +168,94 @@ void NVMeSubsystem::start()
return;
}
@@ -322,7 +323,7 @@
}
diff --git a/src/meson.build b/src/meson.build
-index 9f37585..740fdd5 100644
+index 4565c01..a98fb4f 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -186,13 +186,14 @@ if get_option('mcu').enabled()
diff --git a/recipes-phosphor/sensors/dbus-sensors/0006-Add-NVMeAdmin-intf-with-GetLogPage.patch b/recipes-phosphor/sensors/dbus-sensors/0007-Add-NVMeAdmin-intf-with-GetLogPage.patch
similarity index 98%
rename from recipes-phosphor/sensors/dbus-sensors/0006-Add-NVMeAdmin-intf-with-GetLogPage.patch
rename to recipes-phosphor/sensors/dbus-sensors/0007-Add-NVMeAdmin-intf-with-GetLogPage.patch
index e681fdb..13ed473 100644
--- a/recipes-phosphor/sensors/dbus-sensors/0006-Add-NVMeAdmin-intf-with-GetLogPage.patch
+++ b/recipes-phosphor/sensors/dbus-sensors/0007-Add-NVMeAdmin-intf-with-GetLogPage.patch
@@ -1,7 +1,7 @@
-From 9df967c6ea11a48371336aa78ac967b6eae03ea2 Mon Sep 17 00:00:00 2001
+From 8c190e17acc59dc51fce5f613638fdd7182e9503 Mon Sep 17 00:00:00 2001
From: Hao Jiang <jianghao@google.com>
Date: Tue, 20 Sep 2022 18:36:16 +0000
-Subject: [PATCH 06/34] Add NVMeAdmin intf with GetLogPage
+Subject: [PATCH 07/44] Add NVMeAdmin intf with GetLogPage
xyz.openbmc_project.Nvme.NVMeAdmin interface is used to NVMe spec ADMIN
API to the NVMe devices.
@@ -135,10 +135,10 @@
+ std::shared_ptr<sdbusplus::asio::dbus_interface> adminIntf;
};
diff --git a/src/NVMeIntf.hpp b/src/NVMeIntf.hpp
-index 389289b..0080b3b 100644
+index b929ca4..07b1df6 100644
--- a/src/NVMeIntf.hpp
+++ b/src/NVMeIntf.hpp
-@@ -62,4 +62,9 @@ class NVMeMiIntf : public NVMeIntf
+@@ -125,4 +125,9 @@ class NVMeMiIntf
uint16_t cntid,
std::function<void(const std::error_code&, std::span<uint8_t>)>&&
cb) = 0;
diff --git a/recipes-phosphor/sensors/dbus-sensors/0007-Add-more-logs-to-NVMe-daemon.patch b/recipes-phosphor/sensors/dbus-sensors/0008-Add-more-logs-to-NVMe-daemon.patch
similarity index 99%
rename from recipes-phosphor/sensors/dbus-sensors/0007-Add-more-logs-to-NVMe-daemon.patch
rename to recipes-phosphor/sensors/dbus-sensors/0008-Add-more-logs-to-NVMe-daemon.patch
index f2837dc..21cf49b 100644
--- a/recipes-phosphor/sensors/dbus-sensors/0007-Add-more-logs-to-NVMe-daemon.patch
+++ b/recipes-phosphor/sensors/dbus-sensors/0008-Add-more-logs-to-NVMe-daemon.patch
@@ -1,7 +1,7 @@
-From 68db54ddb4a01d87c1a70d959c260f7e990f633b Mon Sep 17 00:00:00 2001
+From ac7745c38854c78697bcb5374c0734bdc921dfad Mon Sep 17 00:00:00 2001
From: Hao Jiang <jianghao@google.com>
Date: Mon, 26 Sep 2022 06:07:46 +0000
-Subject: [PATCH 07/34] Add more logs to NVMe daemon
+Subject: [PATCH 08/44] Add more logs to NVMe daemon
The following logs are now supported via GetLogPage:
* NVME_LOG_LID_ERROR
diff --git a/recipes-phosphor/sensors/dbus-sensors/0008-Add-Identify-method-to-NVMeAdmin-interface.patch b/recipes-phosphor/sensors/dbus-sensors/0009-Add-Identify-method-to-NVMeAdmin-interface.patch
similarity index 93%
rename from recipes-phosphor/sensors/dbus-sensors/0008-Add-Identify-method-to-NVMeAdmin-interface.patch
rename to recipes-phosphor/sensors/dbus-sensors/0009-Add-Identify-method-to-NVMeAdmin-interface.patch
index bfa3b85..5ca69ac 100644
--- a/recipes-phosphor/sensors/dbus-sensors/0008-Add-Identify-method-to-NVMeAdmin-interface.patch
+++ b/recipes-phosphor/sensors/dbus-sensors/0009-Add-Identify-method-to-NVMeAdmin-interface.patch
@@ -1,7 +1,7 @@
-From 3c9556e7a6c93af2665cb3face5e4bf01a6c7ff8 Mon Sep 17 00:00:00 2001
+From 7bf1e5702c953531e1a1aaa22519216a12c6b4c4 Mon Sep 17 00:00:00 2001
From: Hao Jiang <jianghao@google.com>
Date: Thu, 29 Sep 2022 18:47:09 +0000
-Subject: [PATCH 08/34] Add Identify method to NVMeAdmin interface
+Subject: [PATCH 09/44] Add Identify method to NVMeAdmin interface
This method is used to send NVMe admin command `Identify` to the target
controller. It will return a fd to read the raw data field of the
diff --git a/recipes-phosphor/sensors/dbus-sensors/0009-nvmesensor-add-adminXfer-for-MI-interface.patch b/recipes-phosphor/sensors/dbus-sensors/0010-nvmesensor-add-adminXfer-for-MI-interface.patch
similarity index 96%
rename from recipes-phosphor/sensors/dbus-sensors/0009-nvmesensor-add-adminXfer-for-MI-interface.patch
rename to recipes-phosphor/sensors/dbus-sensors/0010-nvmesensor-add-adminXfer-for-MI-interface.patch
index 9bf521e..142e524 100644
--- a/recipes-phosphor/sensors/dbus-sensors/0009-nvmesensor-add-adminXfer-for-MI-interface.patch
+++ b/recipes-phosphor/sensors/dbus-sensors/0010-nvmesensor-add-adminXfer-for-MI-interface.patch
@@ -1,7 +1,7 @@
-From 83360adff6ffe99e383f514a3b890898549f344e Mon Sep 17 00:00:00 2001
+From 900fb7de218c3d25b5ecf8859970ee42a27f0938 Mon Sep 17 00:00:00 2001
From: Hao Jiang <jianghao@google.com>
Date: Tue, 27 Sep 2022 14:09:24 -0700
-Subject: [PATCH 09/34] nvmesensor: add adminXfer for MI interface
+Subject: [PATCH 10/44] nvmesensor: add adminXfer for MI interface
The adminXfer is used to transfer arbitrary NVMe-MI admin commands. It
can be used for any vendor specify commands.
@@ -15,10 +15,10 @@
3 files changed, 113 insertions(+)
diff --git a/src/NVMeIntf.hpp b/src/NVMeIntf.hpp
-index 0080b3b..9e7b3a4 100644
+index 07b1df6..0a745f1 100644
--- a/src/NVMeIntf.hpp
+++ b/src/NVMeIntf.hpp
-@@ -67,4 +67,39 @@ class NVMeMiIntf : public NVMeIntf
+@@ -130,4 +130,39 @@ class NVMeMiIntf
uint8_t lsp, uint16_t lsi,
std::function<void(const std::error_code&, std::span<uint8_t>)>&&
cb) = 0;
diff --git a/recipes-phosphor/sensors/dbus-sensors/0010-nvmesensor-handle-libnvme-mi-status-return-code.patch b/recipes-phosphor/sensors/dbus-sensors/0011-nvmesensor-handle-libnvme-mi-status-return-code.patch
similarity index 98%
rename from recipes-phosphor/sensors/dbus-sensors/0010-nvmesensor-handle-libnvme-mi-status-return-code.patch
rename to recipes-phosphor/sensors/dbus-sensors/0011-nvmesensor-handle-libnvme-mi-status-return-code.patch
index 660af01..de0c592 100644
--- a/recipes-phosphor/sensors/dbus-sensors/0010-nvmesensor-handle-libnvme-mi-status-return-code.patch
+++ b/recipes-phosphor/sensors/dbus-sensors/0011-nvmesensor-handle-libnvme-mi-status-return-code.patch
@@ -1,7 +1,7 @@
-From 41c8ceecc86d720635b18ecf03af60a9294caabb Mon Sep 17 00:00:00 2001
+From 1b5cb7d4950e914a41c6462243cf4da5267dc467 Mon Sep 17 00:00:00 2001
From: Hao Jiang <jianghao@google.com>
Date: Wed, 28 Sep 2022 18:23:29 +0000
-Subject: [PATCH 10/34] nvmesensor: handle libnvme-mi status return code
+Subject: [PATCH 11/44] nvmesensor: handle libnvme-mi status return code
libnvme-mi return status by returning a positive rc. Previously it only
handles the negitive rc with errno.
@@ -14,11 +14,11 @@
2 files changed, 257 insertions(+), 178 deletions(-)
diff --git a/src/NVMeIntf.hpp b/src/NVMeIntf.hpp
-index 9e7b3a4..d34ac3e 100644
+index 0a745f1..a8cbfad 100644
--- a/src/NVMeIntf.hpp
+++ b/src/NVMeIntf.hpp
-@@ -48,6 +48,54 @@ class NVMeBasicIntf : public NVMeIntf
- class NVMeMiIntf : public NVMeIntf
+@@ -108,6 +108,54 @@ class NVMeBasicIntf
+ class NVMeMiIntf
{
public:
+ constexpr static std::string_view statusToString(nvme_mi_resp_status status)
diff --git a/recipes-phosphor/sensors/dbus-sensors/0011-nvmesensor-handle-the-broken-pipe-signal.patch b/recipes-phosphor/sensors/dbus-sensors/0012-nvmesensor-handle-the-broken-pipe-signal.patch
similarity index 84%
rename from recipes-phosphor/sensors/dbus-sensors/0011-nvmesensor-handle-the-broken-pipe-signal.patch
rename to recipes-phosphor/sensors/dbus-sensors/0012-nvmesensor-handle-the-broken-pipe-signal.patch
index 290bf37..3aa375e 100644
--- a/recipes-phosphor/sensors/dbus-sensors/0011-nvmesensor-handle-the-broken-pipe-signal.patch
+++ b/recipes-phosphor/sensors/dbus-sensors/0012-nvmesensor-handle-the-broken-pipe-signal.patch
@@ -1,7 +1,7 @@
-From bd0fc8a47f7ab381d4368d9ea68ab1bfc45bd43e Mon Sep 17 00:00:00 2001
+From d8203b2a8907a44c874ecab4f35c0efd31c4e3de Mon Sep 17 00:00:00 2001
From: Hao Jiang <jianghao@google.com>
Date: Mon, 28 Nov 2022 23:28:16 +0000
-Subject: [PATCH 11/34] nvmesensor: handle the broken pipe signal
+Subject: [PATCH 12/44] nvmesensor: handle the broken pipe signal
The NVMe controller uses pipe to transfer raw data. The pipe could
be closed by the client. It should not be considered as an error.
@@ -13,10 +13,10 @@
1 file changed, 9 insertions(+)
diff --git a/src/NVMeSensorMain.cpp b/src/NVMeSensorMain.cpp
-index d85dac7..d04d3e5 100644
+index d0e5274..16c9901 100644
--- a/src/NVMeSensorMain.cpp
+++ b/src/NVMeSensorMain.cpp
-@@ -276,5 +276,14 @@ int main()
+@@ -277,5 +277,14 @@ int main()
});
setupManufacturingModeMatch(*systemBus);
diff --git a/recipes-phosphor/sensors/dbus-sensors/0012-nvmesensor-Add-FirmwareCommit-to-nvme-daemon.patch b/recipes-phosphor/sensors/dbus-sensors/0013-nvmesensor-Add-FirmwareCommit-to-nvme-daemon.patch
similarity index 97%
rename from recipes-phosphor/sensors/dbus-sensors/0012-nvmesensor-Add-FirmwareCommit-to-nvme-daemon.patch
rename to recipes-phosphor/sensors/dbus-sensors/0013-nvmesensor-Add-FirmwareCommit-to-nvme-daemon.patch
index 47c1dd4..c7968be 100644
--- a/recipes-phosphor/sensors/dbus-sensors/0012-nvmesensor-Add-FirmwareCommit-to-nvme-daemon.patch
+++ b/recipes-phosphor/sensors/dbus-sensors/0013-nvmesensor-Add-FirmwareCommit-to-nvme-daemon.patch
@@ -1,7 +1,7 @@
-From 9695c31c9d0c9261cdaafaad0027c3c5a80cd95e Mon Sep 17 00:00:00 2001
+From 643ff1844fef8ff814d3f9ee33bc4afc14534ce5 Mon Sep 17 00:00:00 2001
From: Hao Jiang <jianghao@google.com>
Date: Fri, 21 Oct 2022 23:25:15 +0000
-Subject: [PATCH 12/34] nvmesensor: Add FirmwareCommit to nvme daemon
+Subject: [PATCH 13/44] nvmesensor: Add FirmwareCommit to nvme daemon
The FirmwareCommit is to send nvme_mi_admin_fw_commit cmd to nvme
device. The attribute "FirmwareCommitStatus" show the progress stauts of
@@ -161,10 +161,10 @@
+ FwCommitStatus commitStatus;
};
diff --git a/src/NVMeIntf.hpp b/src/NVMeIntf.hpp
-index d34ac3e..e9060ab 100644
+index a8cbfad..7c639c6 100644
--- a/src/NVMeIntf.hpp
+++ b/src/NVMeIntf.hpp
-@@ -115,6 +115,10 @@ class NVMeMiIntf : public NVMeIntf
+@@ -178,6 +178,10 @@ class NVMeMiIntf
uint8_t lsp, uint16_t lsi,
std::function<void(const std::error_code&, std::span<uint8_t>)>&&
cb) = 0;
diff --git a/recipes-phosphor/sensors/dbus-sensors/0013-nvmesensor-Using-generated-controller-server.patch b/recipes-phosphor/sensors/dbus-sensors/0014-nvmesensor-Using-generated-controller-server.patch
similarity index 97%
rename from recipes-phosphor/sensors/dbus-sensors/0013-nvmesensor-Using-generated-controller-server.patch
rename to recipes-phosphor/sensors/dbus-sensors/0014-nvmesensor-Using-generated-controller-server.patch
index 9bfb26b..f7e729b 100644
--- a/recipes-phosphor/sensors/dbus-sensors/0013-nvmesensor-Using-generated-controller-server.patch
+++ b/recipes-phosphor/sensors/dbus-sensors/0014-nvmesensor-Using-generated-controller-server.patch
@@ -1,9 +1,9 @@
-From 4ed719b22cf47f677412e2ca40cc10e69dc9dba3 Mon Sep 17 00:00:00 2001
+From a9eeb97934b9afce0c3572040813fee7a5c0930d Mon Sep 17 00:00:00 2001
From: Hao Jiang <jianghao@google.com>
Date: Tue, 29 Nov 2022 01:48:52 +0000
-Subject: [PATCH 13/34] nvmesensor: Using generated controller server
+Subject: [PATCH 14/44] nvmesensor: Using generated controller server
-libnvme-vu include the yaml file for the definition of
+libnvme-vu includes the yaml file for the definition of
xyz.openbmc_project.NVMe.NVMeAdmin. The server.hpp and server.cpp
will be gerenated from the yaml. Move the functionility from dynamic
insertion of sdbusplus::asio to the inheretence of the generated
@@ -13,8 +13,8 @@
* a more clear structure by distributing the functions into the
overloading instead of a bit chunck of constructor.
* DBus interface sharing across the server and the client.
-* Get prepared for the future plug-in style functions by
- splitting the Plug-in class out of NVMeController.
+* Get prepared for the future plug-in style knuckle functions by
+ splitting the knuckle class out of NVMeController.
Signed-off-by: Hao Jiang <jianghao@google.com>
Change-Id: I13d6f6b639f892faf27ee1f3170a21c8793be3a6
@@ -419,7 +419,7 @@
+ bool bpid) override;
};
diff --git a/src/meson.build b/src/meson.build
-index 740fdd5..5214ebd 100644
+index a98fb4f..6d822d5 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -207,9 +207,16 @@ if get_option('nvme').enabled()
diff --git a/recipes-phosphor/sensors/dbus-sensors/0014-nvmesensor-Add-NVMePlugin.patch b/recipes-phosphor/sensors/dbus-sensors/0015-nvmesensor-Add-NVMePlugin.patch
similarity index 95%
rename from recipes-phosphor/sensors/dbus-sensors/0014-nvmesensor-Add-NVMePlugin.patch
rename to recipes-phosphor/sensors/dbus-sensors/0015-nvmesensor-Add-NVMePlugin.patch
index 9872f30..e458bfb 100644
--- a/recipes-phosphor/sensors/dbus-sensors/0014-nvmesensor-Add-NVMePlugin.patch
+++ b/recipes-phosphor/sensors/dbus-sensors/0015-nvmesensor-Add-NVMePlugin.patch
@@ -1,7 +1,7 @@
-From 9e3da3bb6496d7745caac537a8d117210667d549 Mon Sep 17 00:00:00 2001
+From 1c0ca7d33b1a749c4f40c0c09dffec006e364a60 Mon Sep 17 00:00:00 2001
From: Hao Jiang <jianghao@google.com>
Date: Mon, 28 Nov 2022 23:54:58 +0000
-Subject: [PATCH 14/34] nvmesensor: Add NVMePlugin
+Subject: [PATCH 15/44] nvmesensor: Add NVMePlugin
The NVmePlugin is used to define vendor unique commands or fields(such
as VU LogPage ID).
@@ -200,7 +200,7 @@
+ std::shared_ptr<NVMeController> nvmeController;
+};
diff --git a/src/NVMeSubsys.cpp b/src/NVMeSubsys.cpp
-index b49743f..7b86fb6 100644
+index 426c46d..15f76e3 100644
--- a/src/NVMeSubsys.cpp
+++ b/src/NVMeSubsys.cpp
@@ -1,5 +1,6 @@
@@ -210,7 +210,7 @@
#include "Thresholds.hpp"
#include <filesystem>
-@@ -180,11 +181,12 @@ void NVMeSubsystem::start()
+@@ -186,11 +187,12 @@ void NVMeSubsystem::start()
std::filesystem::path path = std::filesystem::path(self->path) /
"controllers" /
std::to_string(*index);
@@ -228,7 +228,7 @@
index++;
}
-@@ -211,9 +213,9 @@ void NVMeSubsystem::start()
+@@ -217,9 +219,9 @@ void NVMeSubsystem::start()
*reinterpret_cast<nvme_secondary_ctrl_list*>(data.data());
// Remove all associations
@@ -240,7 +240,7 @@
}
if (listHdr.num == 0)
-@@ -246,9 +248,9 @@ void NVMeSubsystem::start()
+@@ -252,9 +254,9 @@ void NVMeSubsystem::start()
<< std::endl;
break;
}
@@ -253,7 +253,7 @@
});
}
diff --git a/src/NVMeSubsys.hpp b/src/NVMeSubsys.hpp
-index 1d51cec..b0c7efa 100644
+index 0a3e8ce..6e5b5f0 100644
--- a/src/NVMeSubsys.hpp
+++ b/src/NVMeSubsys.hpp
@@ -1,6 +1,7 @@
@@ -264,7 +264,7 @@
#include "NVMeSensor.hpp"
#include "NVMeStorage.hpp"
#include "Utils.hpp"
-@@ -62,8 +63,10 @@ class NVMeSubsystem : public std::enable_shared_from_this<NVMeSubsystem>
+@@ -61,8 +62,10 @@ class NVMeSubsystem : public std::enable_shared_from_this<NVMeSubsystem>
*/
NVMeDrive drive;
diff --git a/recipes-phosphor/sensors/dbus-sensors/0015-nvmesensor-add-associations.patch b/recipes-phosphor/sensors/dbus-sensors/0016-nvmesensor-add-associations.patch
similarity index 89%
rename from recipes-phosphor/sensors/dbus-sensors/0015-nvmesensor-add-associations.patch
rename to recipes-phosphor/sensors/dbus-sensors/0016-nvmesensor-add-associations.patch
index 940a773..7d09cb3 100644
--- a/recipes-phosphor/sensors/dbus-sensors/0015-nvmesensor-add-associations.patch
+++ b/recipes-phosphor/sensors/dbus-sensors/0016-nvmesensor-add-associations.patch
@@ -1,7 +1,7 @@
-From 38977ae061e05d1b68da2e313519810c026d53c2 Mon Sep 17 00:00:00 2001
+From ed2364138f22b04e780dfcf49aca78df2f921f5d Mon Sep 17 00:00:00 2001
From: Willy Tu <wltu@google.com>
Date: Tue, 6 Dec 2022 14:16:32 -0800
-Subject: [PATCH 15/34] nvmesensor: add associations
+Subject: [PATCH 16/44] nvmesensor: add associations
The BMCWeb uses the associations between
Chassic/Storage/Drive/StorageController to create the link between
@@ -15,7 +15,7 @@
2 files changed, 61 insertions(+), 54 deletions(-)
diff --git a/src/NVMeSubsys.cpp b/src/NVMeSubsys.cpp
-index 7b86fb6..0d5af8b 100644
+index 15f76e3..cf364ab 100644
--- a/src/NVMeSubsys.cpp
+++ b/src/NVMeSubsys.cpp
@@ -59,20 +59,23 @@ std::optional<std::string> createSensorNameFromPath(const std::string& path)
@@ -55,14 +55,14 @@
}
// get temporature from a NVMe Basic reading.
-@@ -107,43 +110,41 @@ NVMeSubsystem::NVMeSubsystem(boost::asio::io_context& io,
+@@ -111,43 +114,41 @@ NVMeSubsystem::NVMeSubsystem(boost::asio::io_context& asio,
}
// initiate the common interfaces (thermal sensor, Drive and Storage)
-- if (dynamic_cast<NVMeBasicIntf*>(nvmeIntf.get()) != nullptr ||
-- dynamic_cast<NVMeMiIntf*>(nvmeIntf.get()) != nullptr)
-+ if (dynamic_cast<NVMeBasicIntf*>(nvmeIntf.get()) == nullptr &&
-+ dynamic_cast<NVMeMiIntf*>(nvmeIntf.get()) == nullptr)
+- if (protocol == NVMeIntf::Protocol::NVMeBasic ||
+- protocol == NVMeIntf::Protocol::NVMeMI)
++ if (protocol != NVMeIntf::Protocol::NVMeBasic &&
++ protocol != NVMeIntf::Protocol::NVMeMI)
{
- std::optional<std::string> sensorName = createSensorNameFromPath(path);
- if (!sensorName)
@@ -130,7 +130,7 @@
}
void NVMeSubsystem::start()
-@@ -160,6 +161,7 @@ void NVMeSubsystem::start()
+@@ -166,6 +167,7 @@ void NVMeSubsystem::start()
// TODO: mark the subsystem invalid and reschedule refresh
std::cerr << "fail to scan controllers for the nvme subsystem"
<< (ec ? ": " + ec.message() : "") << std::endl;
@@ -138,7 +138,7 @@
return;
}
-@@ -188,8 +190,13 @@ void NVMeSubsystem::start()
+@@ -194,8 +196,13 @@ void NVMeSubsystem::start()
self->controllers.insert({*index, {nvmeController, plugin}});
nvmeController->start(plugin);
@@ -152,10 +152,10 @@
/*
find primary controller and make association
-@@ -275,16 +282,13 @@ void NVMeSubsystem::start()
- }
- else if (auto intf = std::dynamic_pointer_cast<NVMeMiIntf>(nvmeIntf))
- {
+@@ -286,16 +293,13 @@ void NVMeSubsystem::start()
+ auto intf =
+ std::get<std::shared_ptr<NVMeMiIntf>>(nvmeIntf.getInferface());
+
- ctemp_fetcher_t<nvme_mi_nvm_ss_health_status*>
- dataFether =
- [intf](
@@ -175,10 +175,10 @@
bool df = status->nss & 0x20;
if (!df)
diff --git a/src/NVMeSubsys.hpp b/src/NVMeSubsys.hpp
-index b0c7efa..3b654fc 100644
+index 6e5b5f0..0f24380 100644
--- a/src/NVMeSubsys.hpp
+++ b/src/NVMeSubsys.hpp
-@@ -86,4 +86,7 @@ class NVMeSubsystem : public std::enable_shared_from_this<NVMeSubsystem>
+@@ -85,4 +85,7 @@ class NVMeSubsystem : public std::enable_shared_from_this<NVMeSubsystem>
ctemp_fetcher_t<T> dataFetcher,
boost::system::error_code errorCode, T data);
};
diff --git a/recipes-phosphor/sensors/dbus-sensors/0016-nvmesensor-Create-thermal-sensor-in-start.patch b/recipes-phosphor/sensors/dbus-sensors/0017-nvmesensor-Create-thermal-sensor-in-start.patch
similarity index 70%
rename from recipes-phosphor/sensors/dbus-sensors/0016-nvmesensor-Create-thermal-sensor-in-start.patch
rename to recipes-phosphor/sensors/dbus-sensors/0017-nvmesensor-Create-thermal-sensor-in-start.patch
index da1aaa4..9ba89af 100644
--- a/recipes-phosphor/sensors/dbus-sensors/0016-nvmesensor-Create-thermal-sensor-in-start.patch
+++ b/recipes-phosphor/sensors/dbus-sensors/0017-nvmesensor-Create-thermal-sensor-in-start.patch
@@ -1,7 +1,7 @@
-From 68c6f26bd4df63fcfdc5fd142dad21535a05eb1b Mon Sep 17 00:00:00 2001
+From 908941f8a92c2385b4fefd19e982865482da2d7a Mon Sep 17 00:00:00 2001
From: Hao Jiang <jianghao@google.com>
Date: Tue, 20 Dec 2022 01:58:11 +0000
-Subject: [PATCH 16/34] nvmesensor: Create thermal sensor in start()
+Subject: [PATCH 17/44] nvmesensor: Create thermal sensor in start()
Move the thermal sensor creation from NVMeSubsys constructor to start().
This is to align with the other sublayer construction, e.g. Controllers.
@@ -11,32 +11,32 @@
Change-Id: Iccc45fc0d99777763a67995fb6ca6ce3d0e52f7c
---
src/NVMeSensorMain.cpp | 8 ++++----
- src/NVMeSubsys.cpp | 40 ++++++++++++++++++++--------------------
- src/NVMeSubsys.hpp | 3 +--
- 3 files changed, 25 insertions(+), 26 deletions(-)
+ src/NVMeSubsys.cpp | 41 +++++++++++++++++++++--------------------
+ src/NVMeSubsys.hpp | 4 ++--
+ 3 files changed, 27 insertions(+), 26 deletions(-)
diff --git a/src/NVMeSensorMain.cpp b/src/NVMeSensorMain.cpp
-index d04d3e5..0656d2c 100644
+index 16c9901..225b05e 100644
--- a/src/NVMeSensorMain.cpp
+++ b/src/NVMeSensorMain.cpp
-@@ -140,9 +140,9 @@ static void handleConfigurations(
+@@ -141,9 +141,9 @@ static void handleConfigurations(
auto nvmeSubsys = std::make_shared<NVMeSubsystem>(
io, objectServer, dbusConnection, interfacePath,
-- *sensorName, configData, nvmeBasic);
-+ *sensorName, nvmeBasic);
+- *sensorName, configData, std::move(nvmeBasic));
++ *sensorName, std::move(nvmeBasic));
nvmeSubsysMap.emplace(interfacePath, nvmeSubsys);
- nvmeSubsys->start();
+ nvmeSubsys->start(configData);
}
catch (std::exception& ex)
{
-@@ -167,9 +167,9 @@ static void handleConfigurations(
+@@ -168,9 +168,9 @@ static void handleConfigurations(
auto nvmeSubsys = std::make_shared<NVMeSubsystem>(
io, objectServer, dbusConnection, interfacePath,
-- *sensorName, configData, nvmeMi);
-+ *sensorName, nvmeMi);
+- *sensorName, configData, std::move(nvmeMi));
++ *sensorName, std::move(nvmeMi));
nvmeSubsysMap.emplace(interfacePath, nvmeSubsys);
- nvmeSubsys->start();
+ nvmeSubsys->start(configData);
@@ -44,18 +44,19 @@
catch (std::exception& ex)
{
diff --git a/src/NVMeSubsys.cpp b/src/NVMeSubsys.cpp
-index 0d5af8b..f718681 100644
+index cf364ab..17f3daa 100644
--- a/src/NVMeSubsys.cpp
+++ b/src/NVMeSubsys.cpp
-@@ -96,7 +96,6 @@ NVMeSubsystem::NVMeSubsystem(boost::asio::io_context& io,
- sdbusplus::asio::object_server& objServer,
+@@ -96,7 +96,7 @@ NVMeSubsystem::NVMeSubsystem(boost::asio::io_context& asio,
+ sdbusplus::asio::object_server& server,
std::shared_ptr<sdbusplus::asio::connection> conn,
const std::string& path, const std::string& name,
-- const SensorData& configData,
- const std::shared_ptr<NVMeIntf>& intf) :
- io(io),
- objServer(objServer), conn(conn), path(path), name(name), nvmeIntf(intf),
-@@ -116,24 +115,6 @@ NVMeSubsystem::NVMeSubsystem(boost::asio::io_context& io,
+- const SensorData& configData, NVMeIntf intf) :
++ NVMeIntf intf) :
+ io(asio),
+ objServer(server), conn(conn), path(path), name(name),
+ nvmeIntf(std::move(intf)), ctempTimer(io),
+@@ -120,24 +120,6 @@ NVMeSubsystem::NVMeSubsystem(boost::asio::io_context& asio,
throw std::runtime_error("Unsupported NVMe interface");
}
@@ -80,7 +81,7 @@
/* xyz.openbmc_project.Inventory.Item.Drive */
drive.protocol(NVMeDrive::DriveProtocol::NVMe);
drive.type(NVMeDrive::DriveType::SSD);
-@@ -147,7 +128,7 @@ NVMeSubsystem::NVMeSubsystem(boost::asio::io_context& io,
+@@ -151,7 +133,7 @@ NVMeSubsystem::NVMeSubsystem(boost::asio::io_context& asio,
associations.emplace_back("drive", "storage", path);
}
@@ -88,8 +89,8 @@
+void NVMeSubsystem::start(const SensorData& configData)
{
// add controllers for the subsystem
- if (auto nvme = std::dynamic_pointer_cast<NVMeMiIntf>(nvmeIntf))
-@@ -262,6 +243,25 @@ void NVMeSubsystem::start()
+ if (nvmeIntf.getProtocol() == NVMeIntf::Protocol::NVMeMI)
+@@ -268,6 +250,25 @@ void NVMeSubsystem::start()
});
}
@@ -113,18 +114,18 @@
+ path);
+
// start to poll value for CTEMP sensor.
- if (auto intf = std::dynamic_pointer_cast<NVMeBasicIntf>(nvmeIntf))
+ if (nvmeIntf.getProtocol() == NVMeIntf::Protocol::NVMeBasic)
{
diff --git a/src/NVMeSubsys.hpp b/src/NVMeSubsys.hpp
-index 3b654fc..eb10b47 100644
+index 0f24380..403b5f7 100644
--- a/src/NVMeSubsys.hpp
+++ b/src/NVMeSubsys.hpp
-@@ -15,10 +15,9 @@ class NVMeSubsystem : public std::enable_shared_from_this<NVMeSubsystem>
+@@ -15,9 +15,9 @@ class NVMeSubsystem : public std::enable_shared_from_this<NVMeSubsystem>
sdbusplus::asio::object_server& objServer,
std::shared_ptr<sdbusplus::asio::connection> conn,
const std::string& path, const std::string& name,
-- const SensorData& configData,
- const std::shared_ptr<NVMeIntf>& intf);
+- const SensorData& configData, NVMeIntf intf);
++ NVMeIntf intf);
- void start();
+ void start(const SensorData& configData);
diff --git a/recipes-phosphor/sensors/dbus-sensors/0017-nvmesensor-Move-temp-sensor-function-to-NVMeUtil.patch b/recipes-phosphor/sensors/dbus-sensors/0018-nvmesensor-Move-temp-sensor-function-to-NVMeUtil.patch
similarity index 93%
rename from recipes-phosphor/sensors/dbus-sensors/0017-nvmesensor-Move-temp-sensor-function-to-NVMeUtil.patch
rename to recipes-phosphor/sensors/dbus-sensors/0018-nvmesensor-Move-temp-sensor-function-to-NVMeUtil.patch
index 8eb320a..30a5575 100644
--- a/recipes-phosphor/sensors/dbus-sensors/0017-nvmesensor-Move-temp-sensor-function-to-NVMeUtil.patch
+++ b/recipes-phosphor/sensors/dbus-sensors/0018-nvmesensor-Move-temp-sensor-function-to-NVMeUtil.patch
@@ -1,7 +1,7 @@
-From 5e59fcefac0a370b7e0e1a4660f9ee2a1260980b Mon Sep 17 00:00:00 2001
+From d5d4f6874189cb526ffcd04ad767891d3e1a6b99 Mon Sep 17 00:00:00 2001
From: Hao Jiang <jianghao@google.com>
Date: Thu, 22 Dec 2022 00:48:57 +0000
-Subject: [PATCH 17/34] nvmesensor: Move temp sensor function to NVMeUtil
+Subject: [PATCH 18/44] nvmesensor: Move temp sensor function to NVMeUtil
The temp sensor can not only be used for NVMe subsystem. E.g. Each NVMe
controller can have its individual cTEMP reporting from controller level
@@ -18,15 +18,13 @@
create mode 100644 src/NVMeUtil.hpp
diff --git a/src/NVMeSubsys.cpp b/src/NVMeSubsys.cpp
-index f718681..1b0aef5 100644
+index 17f3daa..d6c937d 100644
--- a/src/NVMeSubsys.cpp
+++ b/src/NVMeSubsys.cpp
-@@ -3,61 +3,8 @@
- #include "NVMePlugin.hpp"
- #include "Thresholds.hpp"
+@@ -5,60 +5,6 @@
--#include <filesystem>
--
+ #include <filesystem>
+
-std::optional<std::string>
- extractOneFromTail(std::string::const_reverse_iterator& rbegin,
- const std::string::const_reverse_iterator& rend)
@@ -56,7 +54,7 @@
- name.append(rbegin.base(), curr.base());
- return {name};
-}
-
+-
-// a path of "/xyz/openbmc_project/inventory/system/board/{prod}/{nvme}" will
-// generates a sensor name {prod}_{nvme}
-std::optional<std::string> createSensorNameFromPath(const std::string& path)
@@ -80,19 +78,20 @@
- name.append(*nvme);
- return name;
-}
-+#include <filesystem>
-
+-
void NVMeSubsystem::createStorageAssociation()
{
-@@ -99,7 +46,6 @@ NVMeSubsystem::NVMeSubsystem(boost::asio::io_context& io,
- const std::shared_ptr<NVMeIntf>& intf) :
- io(io),
- objServer(objServer), conn(conn), path(path), name(name), nvmeIntf(intf),
-- ctempTimer(io),
+ auto storageAssociation =
+@@ -99,7 +45,7 @@ NVMeSubsystem::NVMeSubsystem(boost::asio::io_context& asio,
+ NVMeIntf intf) :
+ io(asio),
+ objServer(server), conn(conn), path(path), name(name),
+- nvmeIntf(std::move(intf)), ctempTimer(io),
++ nvmeIntf(std::move(intf)),
storage(*dynamic_cast<sdbusplus::bus_t*>(conn.get()), path.c_str()),
drive(*dynamic_cast<sdbusplus::bus_t*>(conn.get()), path.c_str())
{
-@@ -259,8 +205,9 @@ void NVMeSubsystem::start(const SensorData& configData)
+@@ -266,8 +212,9 @@ void NVMeSubsystem::start(const SensorData& configData)
*sensorName);
}
@@ -103,17 +102,17 @@
+ ctempTimer = std::make_shared<boost::asio::steady_timer>(io);
// start to poll value for CTEMP sensor.
- if (auto intf = std::dynamic_pointer_cast<NVMeBasicIntf>(nvmeIntf))
-@@ -278,7 +225,7 @@ void NVMeSubsystem::start(const SensorData& configData)
+ if (nvmeIntf.getProtocol() == NVMeIntf::Protocol::NVMeBasic)
+@@ -287,7 +234,7 @@ void NVMeSubsystem::start(const SensorData& configData)
}
return {getTemperatureReading(status->Temp)};
};
- pollCtemp(dataFether, dataParser);
+ pollCtemp(this->ctempTimer, this->ctemp, dataFether, dataParser);
}
- else if (auto intf = std::dynamic_pointer_cast<NVMeMiIntf>(nvmeIntf))
+ else if (nvmeIntf.getProtocol() == NVMeIntf::Protocol::NVMeMI)
{
-@@ -297,89 +244,8 @@ void NVMeSubsystem::start(const SensorData& configData)
+@@ -309,89 +256,8 @@ void NVMeSubsystem::start(const SensorData& configData)
}
return {getTemperatureReading(status->ctemp)};
};
@@ -205,7 +204,7 @@
- self->pollCtemp(dataFetcher, dataParser);
-}
diff --git a/src/NVMeSubsys.hpp b/src/NVMeSubsys.hpp
-index eb10b47..db9f228 100644
+index 403b5f7..d9c7a78 100644
--- a/src/NVMeSubsys.hpp
+++ b/src/NVMeSubsys.hpp
@@ -1,9 +1,11 @@
@@ -231,13 +230,13 @@
private:
@@ -33,24 +35,10 @@ class NVMeSubsystem : public std::enable_shared_from_this<NVMeSubsystem>
- std::shared_ptr<NVMeIntf> nvmeIntf;
+ NVMeIntf nvmeIntf;
- /* thermal sensor for the subsystem */
- std::optional<NVMeSensor> ctemp;
- boost::asio::steady_timer ctempTimer;
-
-- // Function type for fetching ctemp which incaplucated in a structure of T.
+- // Function type for fetching ctemp which encaplucated in a structure of T.
- // The fetcher function take a callback as input to process the result.
- template <class T>
- using ctemp_fetcher_t =
@@ -285,7 +284,7 @@
};
diff --git a/src/NVMeUtil.hpp b/src/NVMeUtil.hpp
new file mode 100644
-index 0000000..3b6e73a
+index 0000000..16fe291
--- /dev/null
+++ b/src/NVMeUtil.hpp
@@ -0,0 +1,219 @@
@@ -392,7 +391,7 @@
+
+// Function to update NVMe temp sensor
+
-+// Function type for fetching ctemp which incaplucated in a structure of T.
++// Function type for fetching ctemp which encaplucated in a structure of T.
+// The fetcher function take a callback as input to process the result.
+template <class T>
+using ctemp_fetcher_t =
diff --git a/recipes-phosphor/sensors/dbus-sensors/0018-nvmesensor-Change-the-plugin-log-handler.patch b/recipes-phosphor/sensors/dbus-sensors/0019-nvmesensor-Change-the-plugin-log-handler.patch
similarity index 95%
rename from recipes-phosphor/sensors/dbus-sensors/0018-nvmesensor-Change-the-plugin-log-handler.patch
rename to recipes-phosphor/sensors/dbus-sensors/0019-nvmesensor-Change-the-plugin-log-handler.patch
index bec85b0..fb334c3 100644
--- a/recipes-phosphor/sensors/dbus-sensors/0018-nvmesensor-Change-the-plugin-log-handler.patch
+++ b/recipes-phosphor/sensors/dbus-sensors/0019-nvmesensor-Change-the-plugin-log-handler.patch
@@ -1,7 +1,7 @@
-From 2c76fcabed53855b515d33cf80afb8eb82cd9ebd Mon Sep 17 00:00:00 2001
+From c323d7ab2beaaf0342894d79efc3e83196ce2f09 Mon Sep 17 00:00:00 2001
From: Hao Jiang <jianghao@google.com>
Date: Thu, 22 Dec 2022 19:35:32 +0000
-Subject: [PATCH 18/34] nvmesensor: Change the plugin log handler
+Subject: [PATCH 19/44] nvmesensor: Change the plugin log handler
Align the logpage handler type definition to the standard NVMe-MI
logpage function(A.K.A adminGetLogPage). This is because the plugin
diff --git a/recipes-phosphor/sensors/dbus-sensors/0019-nvmesensor-Add-nvme-controller-plugin.patch b/recipes-phosphor/sensors/dbus-sensors/0020-nvmesensor-Add-nvme-controller-plugin.patch
similarity index 94%
rename from recipes-phosphor/sensors/dbus-sensors/0019-nvmesensor-Add-nvme-controller-plugin.patch
rename to recipes-phosphor/sensors/dbus-sensors/0020-nvmesensor-Add-nvme-controller-plugin.patch
index 3c2f1fd..5887d23 100644
--- a/recipes-phosphor/sensors/dbus-sensors/0019-nvmesensor-Add-nvme-controller-plugin.patch
+++ b/recipes-phosphor/sensors/dbus-sensors/0020-nvmesensor-Add-nvme-controller-plugin.patch
@@ -1,7 +1,7 @@
-From f90edf75d2bf6a9d3375fadad5e6ec2e5b3f9913 Mon Sep 17 00:00:00 2001
+From 21d908371df619878d2c2afb303c963e320c81d8 Mon Sep 17 00:00:00 2001
From: Hao Jiang <jianghao@google.com>
Date: Tue, 3 Jan 2023 19:45:03 +0000
-Subject: [PATCH 19/34] nvmesensor: Add nvme/controller plugin
+Subject: [PATCH 20/44] nvmesensor: Add nvme/controller plugin
Rename the NVMePlugin to NVMeControllerPlugin. And add NVMePlugin for
NVMe subsystem.
@@ -21,9 +21,9 @@
src/NVMeController.cpp | 2 +-
src/NVMeController.hpp | 20 +++++--
src/NVMePlugin.hpp | 122 ++++++++++++++++++++++++++++++++++++-----
- src/NVMeSubsys.cpp | 58 +++++++++++++++-----
+ src/NVMeSubsys.cpp | 57 +++++++++++++++----
src/NVMeSubsys.hpp | 14 +++--
- 5 files changed, 178 insertions(+), 38 deletions(-)
+ 5 files changed, 178 insertions(+), 37 deletions(-)
diff --git a/src/NVMeController.cpp b/src/NVMeController.cpp
index 46f84cb..c5333e1 100644
@@ -258,20 +258,12 @@
+ std::shared_ptr<NVMeSubsystem> subsystem;
+};
diff --git a/src/NVMeSubsys.cpp b/src/NVMeSubsys.cpp
-index 1b0aef5..90bad81 100644
+index d6c937d..e45db4f 100644
--- a/src/NVMeSubsys.cpp
+++ b/src/NVMeSubsys.cpp
-@@ -3,7 +3,6 @@
- #include "NVMePlugin.hpp"
- #include "Thresholds.hpp"
-
--
- #include <filesystem>
-
- void NVMeSubsystem::createStorageAssociation()
-@@ -80,9 +79,9 @@ void NVMeSubsystem::start(const SensorData& configData)
- if (auto nvme = std::dynamic_pointer_cast<NVMeMiIntf>(nvmeIntf))
- {
+@@ -87,9 +87,9 @@ void NVMeSubsystem::start(const SensorData& configData)
+ auto nvme =
+ std::get<std::shared_ptr<NVMeMiIntf>>(nvmeIntf.getInferface());
nvme->miScanCtrl(
- [self{shared_from_this()},
- nvme](const std::error_code& ec,
@@ -282,7 +274,7 @@
if (ec || ctrlList.size() == 0)
{
// TODO: mark the subsystem invalid and reschedule refresh
-@@ -110,16 +109,36 @@ void NVMeSubsystem::start(const SensorData& configData)
+@@ -117,16 +117,36 @@ void NVMeSubsystem::start(const SensorData& configData)
std::filesystem::path path = std::filesystem::path(self->path) /
"controllers" /
std::to_string(*index);
@@ -328,7 +320,7 @@
index++;
}
-@@ -248,4 +267,17 @@ void NVMeSubsystem::start(const SensorData& configData)
+@@ -260,4 +280,17 @@ void NVMeSubsystem::start(const SensorData& configData)
}
// TODO: start to poll Drive status.
@@ -347,7 +339,7 @@
+ ctempTimer->cancel();
}
diff --git a/src/NVMeSubsys.hpp b/src/NVMeSubsys.hpp
-index db9f228..8af2497 100644
+index d9c7a78..ced3dc1 100644
--- a/src/NVMeSubsys.hpp
+++ b/src/NVMeSubsys.hpp
@@ -2,12 +2,14 @@
@@ -383,7 +375,7 @@
std::shared_ptr<sdbusplus::asio::connection> conn;
@@ -35,6 +35,8 @@ class NVMeSubsystem : public std::enable_shared_from_this<NVMeSubsystem>
- std::shared_ptr<NVMeIntf> nvmeIntf;
+ NVMeIntf nvmeIntf;
+ // plugin
+ std::shared_ptr<NVMePlugin> plugin;
diff --git a/recipes-phosphor/sensors/dbus-sensors/0020-nvmesensor-add-timeout-for-xfer.patch b/recipes-phosphor/sensors/dbus-sensors/0021-nvmesensor-add-timeout-for-xfer.patch
similarity index 95%
rename from recipes-phosphor/sensors/dbus-sensors/0020-nvmesensor-add-timeout-for-xfer.patch
rename to recipes-phosphor/sensors/dbus-sensors/0021-nvmesensor-add-timeout-for-xfer.patch
index ced5672..440d8b4 100644
--- a/recipes-phosphor/sensors/dbus-sensors/0020-nvmesensor-add-timeout-for-xfer.patch
+++ b/recipes-phosphor/sensors/dbus-sensors/0021-nvmesensor-add-timeout-for-xfer.patch
@@ -1,7 +1,7 @@
-From d4b11f261a5a8da134e8a354e31d103de8ffe817 Mon Sep 17 00:00:00 2001
+From 2b330a663d6688096a00d3259a2e3ace2e851021 Mon Sep 17 00:00:00 2001
From: Hao Jiang <jianghao@google.com>
Date: Tue, 10 Jan 2023 01:24:00 +0000
-Subject: [PATCH 20/34] nvmesensor: add timeout for xfer
+Subject: [PATCH 21/44] nvmesensor: add timeout for xfer
The xfer which is used by plugins or others may share a different timeout
setting, since the VU command could take time for processing. So added
@@ -18,10 +18,10 @@
4 files changed, 14 insertions(+), 6 deletions(-)
diff --git a/src/NVMeIntf.hpp b/src/NVMeIntf.hpp
-index e9060ab..e7ba3cf 100644
+index 7c639c6..e52a700 100644
--- a/src/NVMeIntf.hpp
+++ b/src/NVMeIntf.hpp
-@@ -125,6 +125,7 @@ class NVMeMiIntf : public NVMeIntf
+@@ -188,6 +188,7 @@ class NVMeMiIntf
* @ctrl: controller to send the admin command to
* @admin_req: request header
* @data: request data payload
@@ -29,7 +29,7 @@
* @resp_data_offset: offset into request data to retrieve from controller
* @cb: callback function after the response received.
* @ec: error code
-@@ -150,7 +151,7 @@ class NVMeMiIntf : public NVMeIntf
+@@ -213,7 +214,7 @@ class NVMeMiIntf
*/
virtual void
adminXfer(nvme_mi_ctrl_t ctrl, const nvme_mi_admin_req_hdr& admin_req,
diff --git a/recipes-phosphor/sensors/dbus-sensors/0021-nvmesensor-segmentation-fault-workaround-and-fix.patch b/recipes-phosphor/sensors/dbus-sensors/0022-nvmesensor-segmentation-fault-workaround-and-fix.patch
similarity index 89%
rename from recipes-phosphor/sensors/dbus-sensors/0021-nvmesensor-segmentation-fault-workaround-and-fix.patch
rename to recipes-phosphor/sensors/dbus-sensors/0022-nvmesensor-segmentation-fault-workaround-and-fix.patch
index 6b3c8fc..0abb888 100644
--- a/recipes-phosphor/sensors/dbus-sensors/0021-nvmesensor-segmentation-fault-workaround-and-fix.patch
+++ b/recipes-phosphor/sensors/dbus-sensors/0022-nvmesensor-segmentation-fault-workaround-and-fix.patch
@@ -1,7 +1,7 @@
-From d02dacecc061ae16457943969885ac677034f294 Mon Sep 17 00:00:00 2001
+From d4a8352c714a94a821928c98063582b881cb6e3e Mon Sep 17 00:00:00 2001
From: Jinliang Wang <jinliangw@google.com>
Date: Fri, 20 Jan 2023 11:53:54 -0800
-Subject: [PATCH 21/34] nvmesensor: segmentation fault workaround and fix
+Subject: [PATCH 22/44] nvmesensor: segmentation fault workaround and fix
1) undefine BOOST_ASIO_DISABLE_THREADS and BOOST_ASIO_HAS_IO_URING
to work around segmentation fault during boost asio mutithreading
@@ -13,8 +13,8 @@
Change-Id: I25695cb0c2ac0e76b493ed48235370e041287b96
---
src/NVMeMi.cpp | 24 ++++++++++++------------
- src/meson.build | 3 ++-
- 2 files changed, 14 insertions(+), 13 deletions(-)
+ src/meson.build | 2 +-
+ 2 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/src/NVMeMi.cpp b/src/NVMeMi.cpp
index c8579a7..dd083b2 100644
@@ -87,16 +87,15 @@
});
return;
diff --git a/src/meson.build b/src/meson.build
-index 5214ebd..64200f3 100644
+index 6d822d5..7d16d17 100644
--- a/src/meson.build
+++ b/src/meson.build
-@@ -223,7 +223,8 @@ if get_option('nvme').enabled()
+@@ -223,7 +223,7 @@ if get_option('nvme').enabled()
'nvmesensor',
sources: nvme_srcs,
dependencies: nvme_deps,
-- cpp_args: [uring_args, '-frtti', '-UBOOST_ASIO_NO_DEPRECATED'],
-+ cpp_args: [uring_args, '-frtti', '-UBOOST_ASIO_NO_DEPRECATED',
-+ '-UBOOST_ASIO_DISABLE_THREADS', '-UBOOST_ASIO_HAS_IO_URING'],
+- cpp_args: [uring_args, '-UBOOST_ASIO_NO_DEPRECATED'],
++ cpp_args: uring_args + ['-frtti', '-UBOOST_ASIO_NO_DEPRECATED', '-UBOOST_ASIO_DISABLE_THREADS', '-UBOOST_ASIO_HAS_IO_URING'],
install: true,
)
endif
diff --git a/recipes-phosphor/sensors/dbus-sensors/0022-nvmesensor-spin-out-the-worker-for-NVMeMi.patch b/recipes-phosphor/sensors/dbus-sensors/0023-nvmesensor-spin-out-the-worker-for-NVMeMi.patch
similarity index 97%
rename from recipes-phosphor/sensors/dbus-sensors/0022-nvmesensor-spin-out-the-worker-for-NVMeMi.patch
rename to recipes-phosphor/sensors/dbus-sensors/0023-nvmesensor-spin-out-the-worker-for-NVMeMi.patch
index 4820b49..2865dd5 100644
--- a/recipes-phosphor/sensors/dbus-sensors/0022-nvmesensor-spin-out-the-worker-for-NVMeMi.patch
+++ b/recipes-phosphor/sensors/dbus-sensors/0023-nvmesensor-spin-out-the-worker-for-NVMeMi.patch
@@ -1,7 +1,7 @@
-From 5e01aaf1ac207acd3c18020d256d690e18bb18ba Mon Sep 17 00:00:00 2001
+From 5eefe6af535cde59d619ece9f31b88c9c541e497 Mon Sep 17 00:00:00 2001
From: Hao Jiang <jianghao@google.com>
Date: Mon, 12 Dec 2022 22:51:29 +0000
-Subject: [PATCH 22/34] nvmesensor: spin out the worker for NVMeMi
+Subject: [PATCH 23/44] nvmesensor: spin out the worker for NVMeMi
Created the worker class for NVMeMi. The MCTP endpoint under the same
i2c bus will share the same worker thread, similar to NVMeBasic.
@@ -22,7 +22,7 @@
3 files changed, 63 insertions(+), 41 deletions(-)
diff --git a/src/NVMeBasic.cpp b/src/NVMeBasic.cpp
-index b2cb44e..2211088 100644
+index 8390452..3a2d4ca 100644
--- a/src/NVMeBasic.cpp
+++ b/src/NVMeBasic.cpp
@@ -1,5 +1,7 @@
diff --git a/recipes-phosphor/sensors/dbus-sensors/0023-nvmesensor-delay-subsystem-creation.patch b/recipes-phosphor/sensors/dbus-sensors/0024-nvmesensor-delay-subsystem-creation.patch
similarity index 81%
rename from recipes-phosphor/sensors/dbus-sensors/0023-nvmesensor-delay-subsystem-creation.patch
rename to recipes-phosphor/sensors/dbus-sensors/0024-nvmesensor-delay-subsystem-creation.patch
index a0632dd..d2ff1a5 100644
--- a/recipes-phosphor/sensors/dbus-sensors/0023-nvmesensor-delay-subsystem-creation.patch
+++ b/recipes-phosphor/sensors/dbus-sensors/0024-nvmesensor-delay-subsystem-creation.patch
@@ -1,7 +1,7 @@
-From 8fc4305b3d5188170615c7fbbf05704e021b8d17 Mon Sep 17 00:00:00 2001
+From ce2cae25e12c935c637c9f4c0bd426145c99be6f Mon Sep 17 00:00:00 2001
From: Hao Jiang <jianghao@google.com>
Date: Thu, 23 Feb 2023 00:55:46 +0000
-Subject: [PATCH 23/34] nvmesensor: delay subsystem creation
+Subject: [PATCH 24/44] nvmesensor: delay subsystem creation
Put the subsystem creation into a second loop. So all NVMeIntf should be
initiated ahead of the subsystem. It is due to the timing requirement
@@ -10,11 +10,11 @@
Signed-off-by: Hao Jiang <jianghao@google.com>
Change-Id: Ia210c143722259486bbd6d23be6eec63438060b4
---
- src/NVMeSensorMain.cpp | 63 ++++++++++++++++++++++++++++++++----------
- 1 file changed, 48 insertions(+), 15 deletions(-)
+ src/NVMeSensorMain.cpp | 61 +++++++++++++++++++++++++++++++++---------
+ 1 file changed, 48 insertions(+), 13 deletions(-)
diff --git a/src/NVMeSensorMain.cpp b/src/NVMeSensorMain.cpp
-index 0656d2c..3f8797f 100644
+index 225b05e..3c64eee 100644
--- a/src/NVMeSensorMain.cpp
+++ b/src/NVMeSensorMain.cpp
@@ -96,7 +96,15 @@ static void handleConfigurations(
@@ -30,21 +30,20 @@
+ * short and should not be delayed by NVMe-MI protocol msg from NVMe
+ * subsystem.
+ */
-+ std::map<std::string, std::shared_ptr<NVMeIntf>> nvmeInterfaces;
++ std::map<std::string, NVMeIntf> nvmeInterfaces;
for (const auto& [interfacePath, configData] : nvmeConfigurations)
{
// find base configuration
-@@ -137,16 +145,11 @@ static void handleConfigurations(
- {
- std::shared_ptr<NVMeIntf> nvmeBasic{
- new NVMeBasic(io, *busNumber, *address)};
--
+@@ -139,15 +147,11 @@ static void handleConfigurations(
+ NVMeIntf nvmeBasic =
+ NVMeIntf::create<NVMeBasic>(io, *busNumber, *address);
+
- auto nvmeSubsys = std::make_shared<NVMeSubsystem>(
- io, objectServer, dbusConnection, interfacePath,
-- *sensorName, nvmeBasic);
+- *sensorName, std::move(nvmeBasic));
- nvmeSubsysMap.emplace(interfacePath, nvmeSubsys);
- nvmeSubsys->start(configData);
-+ nvmeInterfaces.emplace(interfacePath, nvmeBasic);
++ nvmeInterfaces.emplace(interfacePath, std::move(nvmeBasic));
}
catch (std::exception& ex)
{
@@ -53,14 +52,13 @@
<< std::string(interfacePath) << ": " << ex.what()
<< "\n";
continue;
-@@ -164,22 +167,52 @@ static void handleConfigurations(
- std::shared_ptr<NVMeIntf> nvmeMi{new NVMeMi(
+@@ -166,21 +170,52 @@ static void handleConfigurations(
io, dynamic_cast<sdbusplus::bus_t&>(*dbusConnection),
- *busNumber, *address)};
--
+ *busNumber, *address);
+
- auto nvmeSubsys = std::make_shared<NVMeSubsystem>(
- io, objectServer, dbusConnection, interfacePath,
-- *sensorName, nvmeMi);
+- *sensorName, std::move(nvmeMi));
- nvmeSubsysMap.emplace(interfacePath, nvmeSubsys);
- nvmeSubsys->start(configData);
+ nvmeInterfaces.emplace(interfacePath, nvmeMi);
@@ -75,7 +73,7 @@
}
}
}
-+
++
+ for (const auto& [interfacePath, configData] : nvmeConfigurations)
+ {
+ // find base configuration
diff --git a/recipes-phosphor/sensors/dbus-sensors/0024-nvmesensor-clean-up-the-association.patch b/recipes-phosphor/sensors/dbus-sensors/0025-nvmesensor-clean-up-the-association.patch
similarity index 93%
rename from recipes-phosphor/sensors/dbus-sensors/0024-nvmesensor-clean-up-the-association.patch
rename to recipes-phosphor/sensors/dbus-sensors/0025-nvmesensor-clean-up-the-association.patch
index 599e1b6..be4a538 100644
--- a/recipes-phosphor/sensors/dbus-sensors/0024-nvmesensor-clean-up-the-association.patch
+++ b/recipes-phosphor/sensors/dbus-sensors/0025-nvmesensor-clean-up-the-association.patch
@@ -1,7 +1,7 @@
-From c6460b06d61e06229061d85041424b7f280594a8 Mon Sep 17 00:00:00 2001
+From d0a812c56d664feb1166c81ed64655c856fb5884 Mon Sep 17 00:00:00 2001
From: Hao Jiang <jianghao@google.com>
Date: Fri, 31 Mar 2023 17:32:34 +0000
-Subject: [PATCH 24/34] nvmesensor: clean up the association
+Subject: [PATCH 25/44] nvmesensor: clean up the association
The association now belonges to the child component:
* subsystem: association to chassis and between storage/drive
@@ -139,7 +139,7 @@
// NVMe Plug-in for vendor defined command/field
std::weak_ptr<NVMeControllerPlugin> plugin;
diff --git a/src/NVMeSubsys.cpp b/src/NVMeSubsys.cpp
-index 90bad81..6fd78b0 100644
+index e45db4f..68c3bac 100644
--- a/src/NVMeSubsys.cpp
+++ b/src/NVMeSubsys.cpp
@@ -7,21 +7,18 @@
@@ -174,7 +174,7 @@
}
// get temporature from a NVMe Basic reading.
-@@ -67,10 +64,12 @@ NVMeSubsystem::NVMeSubsystem(boost::asio::io_context& io,
+@@ -73,10 +70,12 @@ NVMeSubsystem::NVMeSubsystem(boost::asio::io_context& asio,
/* xyz.openbmc_project.Inventory.Item.Storage */
// make association for Drive/Storage/Chassis
@@ -191,7 +191,7 @@
}
void NVMeSubsystem::start(const SensorData& configData)
-@@ -87,7 +86,7 @@ void NVMeSubsystem::start(const SensorData& configData)
+@@ -95,7 +94,7 @@ void NVMeSubsystem::start(const SensorData& configData)
// TODO: mark the subsystem invalid and reschedule refresh
std::cerr << "fail to scan controllers for the nvme subsystem"
<< (ec ? ": " + ec.message() : "") << std::endl;
@@ -200,7 +200,7 @@
return;
}
-@@ -121,6 +120,9 @@ void NVMeSubsystem::start(const SensorData& configData)
+@@ -129,6 +128,9 @@ void NVMeSubsystem::start(const SensorData& configData)
{*index, {nvmeController, {}}});
auto& ctrlPlugin = iter->second.second;
@@ -210,7 +210,7 @@
// creat controller plugin
if (self->plugin)
{
-@@ -128,10 +130,6 @@ void NVMeSubsystem::start(const SensorData& configData)
+@@ -136,10 +138,6 @@ void NVMeSubsystem::start(const SensorData& configData)
*nvmeController, configData);
}
nvmeController->start(ctrlPlugin);
@@ -221,7 +221,7 @@
}
catch (const std::exception& e)
{
-@@ -142,7 +140,7 @@ void NVMeSubsystem::start(const SensorData& configData)
+@@ -150,7 +148,7 @@ void NVMeSubsystem::start(const SensorData& configData)
index++;
}
@@ -231,12 +231,12 @@
/*
find primary controller and make association
diff --git a/src/NVMeSubsys.hpp b/src/NVMeSubsys.hpp
-index 8af2497..0c95318 100644
+index ced3dc1..3944fe7 100644
--- a/src/NVMeSubsys.hpp
+++ b/src/NVMeSubsys.hpp
@@ -21,6 +21,8 @@ class NVMeSubsystem : public std::enable_shared_from_this<NVMeSubsystem>
const std::string& path, const std::string& name,
- const std::shared_ptr<NVMeIntf>& intf);
+ NVMeIntf intf);
+ ~NVMeSubsystem();
+
diff --git a/recipes-phosphor/sensors/dbus-sensors/0025-nvmesensor-change-the-controller-init-sequence.patch b/recipes-phosphor/sensors/dbus-sensors/0026-nvmesensor-change-the-controller-init-sequence.patch
similarity index 87%
rename from recipes-phosphor/sensors/dbus-sensors/0025-nvmesensor-change-the-controller-init-sequence.patch
rename to recipes-phosphor/sensors/dbus-sensors/0026-nvmesensor-change-the-controller-init-sequence.patch
index c98b4f9..f39a782 100644
--- a/recipes-phosphor/sensors/dbus-sensors/0025-nvmesensor-change-the-controller-init-sequence.patch
+++ b/recipes-phosphor/sensors/dbus-sensors/0026-nvmesensor-change-the-controller-init-sequence.patch
@@ -1,7 +1,7 @@
-From b0cdd9da9ad7ecc2379c4c79aeb66dac07030e14 Mon Sep 17 00:00:00 2001
+From 56508685439014c303fbc38264465814dc6c6fb6 Mon Sep 17 00:00:00 2001
From: Hao Jiang <jianghao@google.com>
Date: Thu, 6 Apr 2023 23:49:17 +0000
-Subject: [PATCH 25/34] nvmesensor: change the controller init sequence
+Subject: [PATCH 26/44] nvmesensor: change the controller init sequence
The start should be the last step for controller initialization process.
Since the start may depend on the info from intialization.
@@ -13,10 +13,10 @@
1 file changed, 12 insertions(+), 7 deletions(-)
diff --git a/src/NVMeSubsys.cpp b/src/NVMeSubsys.cpp
-index 6fd78b0..42d9717 100644
+index 68c3bac..90db473 100644
--- a/src/NVMeSubsys.cpp
+++ b/src/NVMeSubsys.cpp
-@@ -108,7 +108,7 @@ void NVMeSubsystem::start(const SensorData& configData)
+@@ -116,7 +116,7 @@ void NVMeSubsystem::start(const SensorData& configData)
std::filesystem::path path = std::filesystem::path(self->path) /
"controllers" /
std::to_string(*index);
@@ -25,7 +25,7 @@
try
{
auto nvmeController = std::make_shared<NVMeController>(
-@@ -118,18 +118,17 @@ void NVMeSubsystem::start(const SensorData& configData)
+@@ -126,18 +126,17 @@ void NVMeSubsystem::start(const SensorData& configData)
// insert the controllers with empty plugin
auto [iter, _] = self->controllers.insert(
{*index, {nvmeController, {}}});
@@ -49,7 +49,7 @@
}
catch (const std::exception& e)
{
-@@ -202,6 +201,12 @@ void NVMeSubsystem::start(const SensorData& configData)
+@@ -210,6 +209,12 @@ void NVMeSubsystem::start(const SensorData& configData)
secCntrls.push_back(findSecondary->second.first);
}
findPrimary->second.first->setSecAssoc(secCntrls);
diff --git a/recipes-phosphor/sensors/dbus-sensors/0026-nvmesensor-Check-SCS-for-secondary-controllers.patch b/recipes-phosphor/sensors/dbus-sensors/0027-nvmesensor-Check-SCS-for-secondary-controllers.patch
similarity index 97%
rename from recipes-phosphor/sensors/dbus-sensors/0026-nvmesensor-Check-SCS-for-secondary-controllers.patch
rename to recipes-phosphor/sensors/dbus-sensors/0027-nvmesensor-Check-SCS-for-secondary-controllers.patch
index 1736075..fdf9d8d 100644
--- a/recipes-phosphor/sensors/dbus-sensors/0026-nvmesensor-Check-SCS-for-secondary-controllers.patch
+++ b/recipes-phosphor/sensors/dbus-sensors/0027-nvmesensor-Check-SCS-for-secondary-controllers.patch
@@ -1,7 +1,7 @@
-From 0d458922aa59bed85f2dbfe10db4f4d0d380ae57 Mon Sep 17 00:00:00 2001
+From c76bd9e41b07253efa28e034cce42d4d48b756ba Mon Sep 17 00:00:00 2001
From: Hao Jiang <jianghao@google.com>
Date: Fri, 7 Apr 2023 23:51:14 +0000
-Subject: [PATCH 26/34] nvmesensor: Check SCS for secondary controllers
+Subject: [PATCH 27/44] nvmesensor: Check SCS for secondary controllers
The Secondary Controller State indicates if the secondary controller has
been enabled by CC.EN. For disabled controllers, the StorageController
@@ -285,10 +285,10 @@
/** @brief Implementation for GetLogPage
diff --git a/src/NVMeSubsys.cpp b/src/NVMeSubsys.cpp
-index 42d9717..e9ad699 100644
+index 90db473..aebfd14 100644
--- a/src/NVMeSubsys.cpp
+++ b/src/NVMeSubsys.cpp
-@@ -186,6 +186,12 @@ void NVMeSubsystem::start(const SensorData& configData)
+@@ -194,6 +194,12 @@ void NVMeSubsystem::start(const SensorData& configData)
<< std::endl;
return;
}
@@ -301,7 +301,7 @@
std::vector<std::shared_ptr<NVMeController>> secCntrls;
for (int i = 0; i < listHdr.num; i++)
{
-@@ -198,9 +204,18 @@ void NVMeSubsystem::start(const SensorData& configData)
+@@ -206,9 +212,18 @@ void NVMeSubsystem::start(const SensorData& configData)
<< std::endl;
break;
}
diff --git a/recipes-phosphor/sensors/dbus-sensors/0033-nvmesensor-Add-toggle-for-single-thread-mode.patch b/recipes-phosphor/sensors/dbus-sensors/0028-nvmesensor-Add-toggle-for-single-thread-mode.patch
similarity index 85%
rename from recipes-phosphor/sensors/dbus-sensors/0033-nvmesensor-Add-toggle-for-single-thread-mode.patch
rename to recipes-phosphor/sensors/dbus-sensors/0028-nvmesensor-Add-toggle-for-single-thread-mode.patch
index 4b5a16d..17a936b 100644
--- a/recipes-phosphor/sensors/dbus-sensors/0033-nvmesensor-Add-toggle-for-single-thread-mode.patch
+++ b/recipes-phosphor/sensors/dbus-sensors/0028-nvmesensor-Add-toggle-for-single-thread-mode.patch
@@ -1,7 +1,7 @@
-From b2254dc06d0c96b3783d4620dd6c14a3e6dad973 Mon Sep 17 00:00:00 2001
+From 0d9a0a81943f30f7d4df23ef9090a6eb2560c98b Mon Sep 17 00:00:00 2001
From: Hao Jiang <jianghao@google.com>
Date: Wed, 19 Apr 2023 17:26:09 +0000
-Subject: [PATCH 33/34] nvmesensor: Add toggle for single thread mode
+Subject: [PATCH 28/44] nvmesensor: Add toggle for single thread mode
Add a flag to NVMeMi class to turn off the single thread mode. The
single thread mode is to aggregate the communicate to the devices under
@@ -20,11 +20,11 @@
2 files changed, 24 insertions(+), 17 deletions(-)
diff --git a/src/NVMeMi.cpp b/src/NVMeMi.cpp
-index 106413d..f0a2dcf 100644
+index 59ba3a5..28d864e 100644
--- a/src/NVMeMi.cpp
+++ b/src/NVMeMi.cpp
-@@ -16,7 +16,7 @@ constexpr size_t maxNVMeMILength = 4096;
- constexpr int tcgDefaultTimeoutMS = 20*1000;
+@@ -13,7 +13,7 @@ std::map<int, std::weak_ptr<NVMeMi::Worker>> NVMeMi::workerMap{};
+ nvme_root_t NVMeMi::nvmeRoot = nvme_mi_create_root(stderr, DEFAULT_LOGLEVEL);
NVMeMi::NVMeMi(boost::asio::io_context& io, sdbusplus::bus_t& dbus, int bus,
- int addr) :
@@ -32,7 +32,7 @@
io(io),
dbus(dbus)
{
-@@ -25,11 +25,30 @@ NVMeMi::NVMeMi(boost::asio::io_context& io, sdbusplus::bus_t& dbus, int bus,
+@@ -22,11 +22,30 @@ NVMeMi::NVMeMi(boost::asio::io_context& io, sdbusplus::bus_t& dbus, int bus,
throw std::runtime_error("invalid NVMe root");
}
@@ -66,7 +66,7 @@
}
// init mctp ep via mctpd
-@@ -73,18 +92,6 @@ NVMeMi::NVMeMi(boost::asio::io_context& io, sdbusplus::bus_t& dbus, int bus,
+@@ -70,18 +89,6 @@ NVMeMi::NVMeMi(boost::asio::io_context& io, sdbusplus::bus_t& dbus, int bus,
std::to_string(nid) + ":" +
std::to_string(eid));
}
@@ -86,7 +86,7 @@
NVMeMi::Worker::Worker()
diff --git a/src/NVMeMi.hpp b/src/NVMeMi.hpp
-index 6a57b6e..2aa6636 100644
+index 3071596..4f1a483 100644
--- a/src/NVMeMi.hpp
+++ b/src/NVMeMi.hpp
@@ -9,7 +9,7 @@ class NVMeMi : public NVMeMiIntf, public std::enable_shared_from_this<NVMeMi>
diff --git a/recipes-phosphor/sensors/dbus-sensors/0029-nvmesensor-Add-Fake-for-NVMeMi.patch b/recipes-phosphor/sensors/dbus-sensors/0029-nvmesensor-Add-Fake-for-NVMeMi.patch
new file mode 100644
index 0000000..504729a
--- /dev/null
+++ b/recipes-phosphor/sensors/dbus-sensors/0029-nvmesensor-Add-Fake-for-NVMeMi.patch
@@ -0,0 +1,470 @@
+From b6689d0733b09d1f7bef9bb673ffa27b43bd88f4 Mon Sep 17 00:00:00 2001
+From: Hao Jiang <jianghao@google.com>
+Date: Wed, 19 Apr 2023 21:30:59 +0000
+Subject: [PATCH 29/44] nvmesensor: Add Fake for NVMeMi
+
+Adding a fake class for NVMeMi implementation. The fake class will
+return predefined nvme response with a 100ms designated delay to mimic
+the transfer and processing time.
+
+Signed-off-by: Hao Jiang <jianghao@google.com>
+Change-Id: I83fb444890cf9faa7006c6cb0d645b9075c8856b
+---
+ src/NVMeMiFake.hpp | 445 +++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 445 insertions(+)
+ create mode 100644 src/NVMeMiFake.hpp
+
+diff --git a/src/NVMeMiFake.hpp b/src/NVMeMiFake.hpp
+new file mode 100644
+index 0000000..05eafed
+--- /dev/null
++++ b/src/NVMeMiFake.hpp
+@@ -0,0 +1,445 @@
++#include "NVMeIntf.hpp"
++
++#include <boost/asio.hpp>
++#include <boost/endian.hpp>
++
++#include <iostream>
++#include <thread>
++
++struct list_node
++{
++ list_node *next, *prev;
++};
++
++struct nvme_mi_ctrl
++{
++ void* ep;
++ __u16 id;
++ list_node ep_entry;
++};
++
++class NVMeMiFake :
++ public NVMeMiIntf,
++ public std::enable_shared_from_this<NVMeMiFake>
++{
++ public:
++ NVMeMiFake(boost::asio::io_context& io) :
++ io(io), valid(true) /*, worker(workerIO.get_executor())*/
++ {
++
++ // start worker thread
++ workerStop = false;
++ thread = std::thread([&io = workerIO, &stop = workerStop,
++ &mtx = workerMtx, &cv = workerCv]() {
++ std::cerr << "NVMeMiFake worker thread started: " << io.stopped()
++ << std::endl;
++ // With BOOST_ASIO_DISABLE_THREADS, boost::asio::executor_work_guard
++ // issues null_event across the thread, which caused invalid
++ // invokation. We implement a simple invoke machenism based
++ // std::condition_variable.
++ io.stop();
++ io.restart();
++ while (1)
++ {
++ // mimik the communication delay.
++ std::this_thread::sleep_for(std::chrono::milliseconds(100));
++ io.run();
++ io.restart();
++ std::cerr << "job done" << std::endl;
++ {
++ std::unique_lock<std::mutex> lock(mtx);
++ cv.wait(lock);
++ if (stop)
++ {
++ // exhaust all tasks and exit
++ io.run();
++ break;
++ }
++ }
++ }
++ std::cerr << "NVMeMi worker this line should not be reached"
++ << std::endl;
++ });
++
++ std::cerr << "NVMeMiFake constructor" << std::endl;
++ }
++
++ ~NVMeMiFake() override
++ {
++ if (valid)
++ {
++ std::cerr << "NVMeMiFake destroyer" << std::endl;
++ }
++ else
++ {
++ std::cerr << "NVMeMiFake default destroyer" << std::endl;
++ }
++
++ // close worker
++ workerStop = true;
++ {
++ std::unique_lock<std::mutex> lock(workerMtx);
++ workerCv.notify_all();
++ }
++ thread.join();
++ }
++
++ int getNID() const override
++ {
++ return 0;
++ }
++
++ int getEID() const override
++ {
++ return 0;
++ }
++
++ void miSubsystemHealthStatusPoll(
++ std::function<void(const std::error_code&,
++ nvme_mi_nvm_ss_health_status*)>&& cb) override
++ {
++ io.post([cb{std::move(cb)}]() {
++ nvme_mi_nvm_ss_health_status status;
++ status.nss = 1 << 5;
++ status.ctemp = 24;
++ cb({}, &status);
++ });
++ }
++
++ void miScanCtrl(std::function<void(const std::error_code&,
++ const std::vector<nvme_mi_ctrl_t>&)>
++ cb) override
++ {
++ if (workerStop)
++ {
++
++ std::cerr << "worker thread for nvme endpoint is stopped"
++ << std::endl;
++
++ io.post([cb{std::move(cb)}]() {
++ cb(std::make_error_code(std::errc::no_such_device), {});
++ });
++ return;
++ }
++
++ post([self{shared_from_this()}, cb = std::move(cb)] {
++ std::cerr << "libnvme: scan" << std::endl;
++ self->io.post([cb{std::move(cb)}]() {
++ auto ctrl1 = new nvme_mi_ctrl;
++ auto ctrl2 = new nvme_mi_ctrl;
++ auto ctrl3 = new nvme_mi_ctrl;
++ ctrl1->id = 0;
++ ctrl2->id = 1;
++ ctrl3->id = 2;
++ std::vector<nvme_mi_ctrl_t> list{ctrl1, ctrl2, ctrl3};
++ cb({}, list);
++ });
++ });
++ }
++
++ void adminIdentify(
++ nvme_mi_ctrl_t, nvme_identify_cns cns, uint32_t, uint16_t,
++ std::function<void(const std::error_code&, std::span<uint8_t>)>&& cb)
++ override
++ {
++ std::cerr << "identify" << std::endl;
++ post([self{shared_from_this()}, cb = std::move(cb), cns]() {
++ std::cerr << "libnvme: identify" << std::endl;
++ self->io.post([cb{std::move(cb)}, cns]() {
++ std::vector<uint8_t> data;
++ switch (cns)
++ {
++ case NVME_IDENTIFY_CNS_SECONDARY_CTRL_LIST:
++ {
++ nvme_secondary_ctrl_list list;
++ list.num = 2;
++ list.sc_entry[0].pcid = 0;
++ list.sc_entry[0].scid = 1;
++ list.sc_entry[0].scs = 1;
++ list.sc_entry[1].pcid = 0;
++ list.sc_entry[1].scid = 2;
++ list.sc_entry[1].scs = 0;
++ data.resize(sizeof(nvme_secondary_ctrl_list));
++ memcpy(data.data(), &list, data.size());
++ break;
++ }
++ default:
++ data.resize(NVME_IDENTIFY_DATA_SIZE);
++ }
++ cb({}, std::span<uint8_t>(data.begin(), data.size()));
++ });
++ });
++ }
++
++ void adminGetLogPage(nvme_mi_ctrl_t ctrl, nvme_cmd_get_log_lid lid,
++ uint32_t nsid, uint8_t lsp, uint16_t lsi,
++ std::function<void(const std::error_code&,
++ std::span<uint8_t>)>&& cb) override
++ {
++ try
++ {
++ post([ctrl, lid, nsid, lsp, lsi, self{shared_from_this()},
++ cb{std::move(cb)}]() {
++ int rc = 0;
++ std::vector<uint8_t> data;
++ try
++ {
++ switch (lid)
++ {
++ case NVME_LOG_LID_TELEMETRY_HOST:
++ {
++ data.resize(sizeof(nvme_telemetry_log));
++ nvme_telemetry_log& log =
++ *reinterpret_cast<nvme_telemetry_log*>(
++ data.data());
++ if (lsp == NVME_LOG_TELEM_HOST_LSP_CREATE)
++ {
++ log.lpi = 0x07;
++ if (rc)
++ {
++ std::cerr
++ << "failed to create telemetry host log"
++ << std::endl;
++ throw std::system_error(
++ errno, std::generic_category());
++ }
++ }
++ else if (lsp == NVME_LOG_TELEM_HOST_LSP_RETAIN)
++ {
++ // nvme rev 1.3 only applies upto Area 3
++ log.dalb1 = 512;
++ log.dalb2 = 512;
++ log.dalb3 = 512;
++ data.resize(sizeof(nvme_telemetry_log) + 512);
++ std::string str = "hello world";
++ for (std::size_t i = 0; i < str.size(); i++)
++ {
++ data[sizeof(nvme_telemetry_log) + i] =
++ static_cast<uint8_t>(str[i]);
++ }
++
++ if (rc)
++ {
++ std::cerr
++ << "failed to retain telemetry host "
++ "log full log"
++ << std::endl;
++ throw std::system_error(
++ errno, std::generic_category());
++ }
++ }
++ else
++ {
++ throw std::system_error(std::make_error_code(
++ std::errc::invalid_argument));
++ }
++ }
++ break;
++ case NVME_LOG_LID_SMART:
++ {
++ data.resize(sizeof(nvme_smart_log));
++ nvme_smart_log& log =
++ *reinterpret_cast<nvme_smart_log*>(data.data());
++ uint8_t temp = 40;
++ log.temperature[0] = temp;
++ log.temperature[1] = 1;
++ break;
++ }
++
++ default:
++ {
++ std::cerr << "unknown lid for GetLogPage"
++ << std::endl;
++ throw std::system_error(std::make_error_code(
++ std::errc::invalid_argument));
++ }
++ }
++ }
++ catch (const ::std::system_error& e)
++ {
++ self->io.post(
++ [cb{std::move(cb)}, ec = e.code()]() { cb(ec, {}); });
++ }
++ self->io.post(
++ [cb{std::move(cb)}, data{std::move(data)}]() mutable {
++ std::span<uint8_t> span{data.data(), data.size()};
++ cb({}, span);
++ });
++ });
++ }
++ catch (const std::runtime_error& e)
++ {
++ std::cerr << e.what() << std::endl;
++ io.post([cb{std::move(cb)}]() {
++ cb(std::make_error_code(std::errc::no_such_device), {});
++ });
++ return;
++ }
++ }
++ void adminFwCommit(
++ nvme_mi_ctrl_t ctrl, nvme_fw_commit_ca action, uint8_t slot, bool bpid,
++ std::function<void(const std::error_code&, nvme_status_field)>&& cb)
++ override
++ {
++ try
++ {
++ nvme_fw_commit_args args;
++ memset(&args, 0, sizeof(args));
++ args.action = action;
++ args.slot = slot;
++ args.bpid = bpid;
++ io.post([ctrl, args, cb{std::move(cb)},
++ self{shared_from_this()}]() mutable {
++ // int rc = nvme_mi_admin_fw_commit(ctrl, &args);
++ int rc = 1;
++ if (rc < 0)
++ {
++
++ std::cerr << "fail to subsystem_health_status_poll: "
++ << std::strerror(errno) << std::endl;
++ self->io.post([cb{std::move(cb)}]() {
++ cb(std::make_error_code(static_cast<std::errc>(errno)),
++ nvme_status_field::NVME_SC_MASK);
++ });
++ return;
++ }
++ else if (rc > 0)
++ {
++ switch (rc & 0x7ff)
++ {
++ case NVME_SC_FW_NEEDS_CONV_RESET:
++ case NVME_SC_FW_NEEDS_SUBSYS_RESET:
++ case NVME_SC_FW_NEEDS_RESET:
++ self->io.post([rc, cb{std::move(cb)}]() {
++ cb({}, static_cast<nvme_status_field>(rc));
++ });
++ break;
++ default:
++ std::string_view errMsg = statusToString(
++ static_cast<nvme_mi_resp_status>(rc));
++ std::cerr
++ << "fail to subsystem_health_status_poll: "
++ << errMsg << std::endl;
++ self->io.post([rc, cb{std::move(cb)}]() {
++ cb(std::make_error_code(std::errc::bad_message),
++ static_cast<nvme_status_field>(rc));
++ });
++ }
++ return;
++ }
++ });
++ }
++ catch (const std::runtime_error& e)
++ {
++ std::cerr << e.what() << std::endl;
++ io.post([cb{std::move(cb)}]() {
++ cb(std::make_error_code(std::errc::no_such_device),
++ nvme_status_field::NVME_SC_MASK);
++ });
++ return;
++ }
++ }
++
++ void adminXfer(nvme_mi_ctrl_t ctrl, const nvme_mi_admin_req_hdr& admin_req,
++ std::span<uint8_t> data, unsigned int /*timeout_ms*/,
++ std::function<void(const std::error_code&,
++ const nvme_mi_admin_resp_hdr&,
++ std::span<uint8_t>)>&& cb) override
++ {
++ try
++ {
++ std::vector<uint8_t> req(sizeof(nvme_mi_admin_req_hdr) +
++ data.size());
++ memcpy(req.data(), &admin_req, sizeof(nvme_mi_admin_req_hdr));
++ memcpy(req.data() + sizeof(nvme_mi_admin_req_hdr), data.data(),
++ data.size());
++ post([ctrl, req{std::move(req)}, self{shared_from_this()},
++ cb{std::move(cb)}]() mutable {
++ int rc = 0;
++
++ nvme_mi_admin_req_hdr* reqHeader =
++ reinterpret_cast<nvme_mi_admin_req_hdr*>(req.data());
++
++ size_t respDataSize =
++ boost::endian::little_to_native<size_t>(reqHeader->dlen);
++ // off_t respDataOffset =
++ // boost::endian::little_to_native<off_t>(reqHeader->doff);
++ size_t bufSize = sizeof(nvme_mi_admin_resp_hdr) + respDataSize;
++ std::vector<uint8_t> buf(bufSize);
++ nvme_mi_admin_resp_hdr* respHeader =
++ reinterpret_cast<nvme_mi_admin_resp_hdr*>(buf.data());
++ (void)respHeader;
++ // rc = nvme_mi_admin_xfer(
++ // ctrl, reqHeader, req.size() -
++ // sizeof(nvme_mi_admin_req_hdr), respHeader,
++ // respDataOffset, &respDataSize);
++
++ if (rc < 0)
++ {
++ std::cerr << "failed to nvme_mi_admin_xfer" << std::endl;
++ self->io.post([cb{std::move(cb)}]() {
++ cb(std::make_error_code(static_cast<std::errc>(errno)),
++ {}, {});
++ });
++ return;
++ }
++ // the MI interface will only consume protocol/io errors
++ // The client will take the reponsibility to deal with nvme-mi
++ // status flag and nvme status field(cwd3). cmd specific return
++ // value (cdw0) is also client's job.
++
++ buf.resize(sizeof(nvme_mi_admin_resp_hdr) + respDataSize);
++ self->io.post(
++ [cb{std::move(cb)}, data{std::move(buf)}]() mutable {
++ std::span<uint8_t> span(data.begin() +
++ sizeof(nvme_mi_admin_resp_hdr),
++ data.end());
++ nvme_smart_log& log =
++ *reinterpret_cast<nvme_smart_log*>(span.data());
++ uint8_t temp = 40;
++ log.temperature[0] = temp;
++ log.temperature[1] = 1;
++ cb({},
++ *reinterpret_cast<nvme_mi_admin_resp_hdr*>(data.data()),
++ span);
++ });
++ });
++ }
++ catch (const std::runtime_error& e)
++ {
++ std::cerr << e.what() << std::endl;
++ io.post([cb{std::move(cb)}]() {
++ cb(std::make_error_code(std::errc::no_such_device), {}, {});
++ });
++ return;
++ }
++ }
++
++ private:
++ boost::asio::io_context& io;
++ bool valid = false;
++
++ bool workerStop;
++ std::mutex workerMtx;
++ std::condition_variable workerCv;
++ boost::asio::io_context workerIO;
++ std::thread thread;
++
++ void post(std::function<void(void)>&& func);
++};
++
++void NVMeMiFake::post(std::function<void(void)>&& func)
++{
++ if (!workerStop)
++ {
++ std::unique_lock<std::mutex> lock(workerMtx);
++ if (!workerStop)
++ {
++ std::cerr << "do post" << std::endl;
++ workerIO.post(std::move(func));
++ workerCv.notify_all();
++ return;
++ }
++ }
++ throw std::runtime_error("NVMeMi has been stopped");
++}
+--
+2.34.1
+
diff --git a/recipes-phosphor/sensors/dbus-sensors/0030-nvmesensor-add-unit-test.patch b/recipes-phosphor/sensors/dbus-sensors/0030-nvmesensor-add-unit-test.patch
new file mode 100644
index 0000000..49d96fa
--- /dev/null
+++ b/recipes-phosphor/sensors/dbus-sensors/0030-nvmesensor-add-unit-test.patch
@@ -0,0 +1,125 @@
+From 6ca3e2940dc59ce0feac6372abaff71107d8d2d6 Mon Sep 17 00:00:00 2001
+From: Hao Jiang <jianghao@google.com>
+Date: Mon, 17 Apr 2023 21:28:48 +0000
+Subject: [PATCH 30/44] nvmesensor: add unit test
+
+Add a nvme_start_stop unit test for nvme subsystem. The unit test will
+check the correct number of storage controllers are created and
+destructed upon the start and stop.
+
+The test and nvme subsystem requires ObjectMapper to work.
+
+Signed-off-by: Hao Jiang <jianghao@google.com>
+Change-Id: I7e93020a9dc838708a0184df69da9da0da78f9df
+---
+ tests/meson.build | 17 ++++++++++
+ tests/test_nvme_mi.cpp | 72 ++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 89 insertions(+)
+ create mode 100644 tests/test_nvme_mi.cpp
+
+diff --git a/tests/meson.build b/tests/meson.build
+index 28915d6..cc7fd53 100644
+--- a/tests/meson.build
++++ b/tests/meson.build
+@@ -36,3 +36,20 @@ test(
+ include_directories: '../src',
+ )
+ )
++
++if run_command('/usr/bin/bash', '-c', 'busctl tree xyz.openbmc_project.ObjectMapper').returncode() == 0
++ test(
++ 'test_nvme',
++ executable(
++ 'test_nvme',
++ 'test_nvme_mi.cpp',
++ '../src/NVMeSensor.cpp',
++ '../src/NVMeSubsys.cpp',
++ '../src/NVMeController.cpp',
++ cpp_args: uring_args + ['-UBOOST_ASIO_NO_DEPRECATED', '-UBOOST_ASIO_DISABLE_THREADS', '-UBOOST_ASIO_HAS_IO_URING'],
++ dependencies: [ut_deps_list, nvme_deps],
++ implicit_include_directories: false,
++ include_directories: '../src',
++ )
++ )
++endif
+diff --git a/tests/test_nvme_mi.cpp b/tests/test_nvme_mi.cpp
+new file mode 100644
+index 0000000..f8e4a01
+--- /dev/null
++++ b/tests/test_nvme_mi.cpp
+@@ -0,0 +1,72 @@
++#include "NVMeMiFake.hpp"
++#include "NVMeSubsys.hpp"
++
++#include <sdbusplus/asio/connection.hpp>
++
++#include <gtest/gtest.h>
++
++class NVMeTest : public ::testing::Test
++{
++ protected:
++ NVMeTest() :
++ system_bus(std::make_shared<sdbusplus::asio::connection>(io)),
++ object_server(system_bus),
++ subsys(std::make_shared<NVMeSubsystem>(
++ io, object_server, system_bus, subsys_path, "NVMe_1",
++ std::move(NVMeIntf::create<NVMeMiFake>(io))))
++ {}
++ void SetUp() override
++ {
++ system_bus->request_name("xyz.openbmc_project.NVMeTest");
++ subsys->start(SensorData{});
++ }
++
++ static constexpr char subsys_path[] =
++ "/xyz/openbmc_project/inventory/Test_Chassis/Test_NVMe";
++
++ boost::asio::io_service io;
++ std::shared_ptr<sdbusplus::asio::connection> system_bus;
++ sdbusplus::asio::object_server object_server;
++
++ std::shared_ptr<NVMeSubsystem> subsys;
++};
++
++TEST_F(NVMeTest, TestSubsystemStartStop)
++{
++ boost::asio::steady_timer timer(io);
++
++ // wait for subsystem initialization
++ timer.expires_after(std::chrono::seconds(2));
++ timer.async_wait([&](boost::system::error_code) {
++ system_bus->async_method_call(
++ [&, this](boost::system::error_code, const GetSubTreeType& result) {
++ // Only PF and the enabled VF should be listed
++ EXPECT_EQ(result.size(), 2);
++ subsys->stop();
++
++ // wait for storage controller destruction.
++ timer.expires_after(std::chrono::seconds(1));
++ timer.async_wait([&](boost::system::error_code) {
++ system_bus->async_method_call(
++ [&](boost::system::error_code,
++ const GetSubTreeType& result) {
++ // not storage controller should be listed.
++ EXPECT_EQ(result.size(), 0);
++ io.stop();
++ },
++ "xyz.openbmc_project.ObjectMapper",
++ "/xyz/openbmc_project/object_mapper",
++ "xyz.openbmc_project.ObjectMapper", "GetSubTree",
++ subsys_path, 0,
++ std::vector<std::string>{"xyz.openbmc_project.Inventory."
++ "Item.StorageController"});
++ });
++ },
++ "xyz.openbmc_project.ObjectMapper",
++ "/xyz/openbmc_project/object_mapper",
++ "xyz.openbmc_project.ObjectMapper", "GetSubTree", subsys_path, 0,
++ std::vector<std::string>{
++ "xyz.openbmc_project.Inventory.Item.StorageController"});
++ });
++ io.run();
++}
+--
+2.34.1
+
diff --git a/recipes-phosphor/sensors/dbus-sensors/0030-nvmesensor-always-create-host-telemetry-log-page.patch b/recipes-phosphor/sensors/dbus-sensors/0030-nvmesensor-always-create-host-telemetry-log-page.patch
deleted file mode 100644
index 3340496..0000000
--- a/recipes-phosphor/sensors/dbus-sensors/0030-nvmesensor-always-create-host-telemetry-log-page.patch
+++ /dev/null
@@ -1,93 +0,0 @@
-From 7a53e6ef38c992a8ebf5c38ad969430eb5aa2506 Mon Sep 17 00:00:00 2001
-From: Jinliang Wang <jinliangw@google.com>
-Date: Mon, 17 Apr 2023 13:49:16 -0700
-Subject: [PATCH 30/34] nvmesensor: always create host telemetry log page
-
-According to our use case, it's easier for client to get fresh
-host telemetry log page on every request. So we are going to deprecate
-the LSP paremeter in future, and always create host telemetry log.
-
-Change-Id: Ibeafe5f8f511363435b7c9947baaf2153ca12da4
-Signed-off-by: Jinliang Wang <jinliangw@google.com>
----
- src/NVMeMi.cpp | 48 ++++++++++++------------------------------------
- 1 file changed, 12 insertions(+), 36 deletions(-)
-
-diff --git a/src/NVMeMi.cpp b/src/NVMeMi.cpp
-index fabc0b5..8f73aed 100644
---- a/src/NVMeMi.cpp
-+++ b/src/NVMeMi.cpp
-@@ -386,7 +386,7 @@ static int nvme_mi_admin_get_log_telemetry_host_rae(nvme_mi_ctrl_t ctrl,
-
- // Get Temetery Log header and return the size for hdr + data area (Area 1, 2,
- // 3, or maybe 4)
--int getTelemetryLog(nvme_mi_ctrl_t ctrl, bool host, bool create,
-+static int getTelemetryLog(nvme_mi_ctrl_t ctrl, bool host, bool create,
- std::vector<uint8_t>& data)
- {
- int rc = 0;
-@@ -405,16 +405,16 @@ int getTelemetryLog(nvme_mi_ctrl_t ctrl, bool host, bool create,
- std::cerr << "failed to create telemetry host log" << std::endl;
- return rc;
- }
-- return 0;
- }
--
-- rc = func(ctrl, false, 0, sizeof(log), &log);
--
-- if (rc)
-+ else
- {
-- std::cerr << "failed to retain telemetry log for "
-- << (host ? "host" : "ctrl") << std::endl;
-- return rc;
-+ rc = func(ctrl, false, 0, sizeof(log), &log);
-+ if (rc)
-+ {
-+ std::cerr << "failed to retain telemetry log header for "
-+ << (host ? "host" : "ctrl") << std::endl;
-+ return rc;
-+ }
- }
-
- long size =
-@@ -551,33 +551,9 @@ void NVMeMi::adminGetLogPage(
- // fall through to NVME_LOG_LID_TELEMETRY_CTRL
- case NVME_LOG_LID_TELEMETRY_CTRL:
- {
-- bool host = false;
-- bool create = false;
-- if (lid == NVME_LOG_LID_TELEMETRY_HOST)
-- {
-- host = true;
-- if (lsp == NVME_LOG_TELEM_HOST_LSP_CREATE)
-- {
-- create = true;
-- }
-- else if (lsp == NVME_LOG_TELEM_HOST_LSP_RETAIN)
-- {
-- create = false;
-- }
-- else
-- {
-- std::cerr << "invalid lsp for telemetry host log"
-- << std::endl;
-- rc = -1;
-- errno = EINVAL;
-- break;
-- }
-- }
-- else
-- {
-- host = false;
-- }
--
-+ bool host = (lid == NVME_LOG_LID_TELEMETRY_HOST);
-+ // We always create host telemetry regardless LSP
-+ bool create = host && true;
- rc = getTelemetryLog(ctrl, host, create, data);
- }
- break;
---
-2.34.1
-
diff --git a/recipes-phosphor/sensors/dbus-sensors/0031-nvmesensor-enable-disable-subsys-according-to-DF.patch b/recipes-phosphor/sensors/dbus-sensors/0031-nvmesensor-enable-disable-subsys-according-to-DF.patch
new file mode 100644
index 0000000..0f633f3
--- /dev/null
+++ b/recipes-phosphor/sensors/dbus-sensors/0031-nvmesensor-enable-disable-subsys-according-to-DF.patch
@@ -0,0 +1,593 @@
+From 7c097551eee4daeb6b8b18e10a654a0ab0569de6 Mon Sep 17 00:00:00 2001
+From: Hao Jiang <jianghao@google.com>
+Date: Wed, 19 Apr 2023 00:59:40 +0000
+Subject: [PATCH 31/44] nvmesensor: enable/disable subsys according to DF
+
+NSHDS.NSS.DF(Drive Functional) bit will indicate the NVMe subsystem's
+working status. The NVMeSubsys class should change its functional status
+based on the status bit. It should also remove all the substructure
+(controllers/namspaces, etc) when subsystem is disabled.
+
+Add a mockup upon NVMeMiFake for unit test as well. The unit test mimik
+the process of DF disable and re-enable process.
+
+Signed-off-by: Hao Jiang <jianghao@google.com>
+Change-Id: I907c669eb6cc7f5eafe09c38712c4e681d9efc2d
+---
+ src/NVMeSensorMain.cpp | 4 +-
+ src/NVMeSubsys.cpp | 112 +++++++++++++++----
+ src/NVMeSubsys.hpp | 18 ++-
+ tests/meson.build | 1 +
+ tests/test_nvme_mi.cpp | 245 +++++++++++++++++++++++++++++++++++++++--
+ 5 files changed, 346 insertions(+), 34 deletions(-)
+
+diff --git a/src/NVMeSensorMain.cpp b/src/NVMeSensorMain.cpp
+index 3c64eee..950988d 100644
+--- a/src/NVMeSensorMain.cpp
++++ b/src/NVMeSensorMain.cpp
+@@ -204,9 +204,9 @@ static void handleConfigurations(
+ {
+ auto nvmeSubsys = std::make_shared<NVMeSubsystem>(
+ io, objectServer, dbusConnection, interfacePath, *sensorName,
+- std::move(find->second));
++ configData, std::move(find->second));
+ nvmeSubsysMap.emplace(interfacePath, nvmeSubsys);
+- nvmeSubsys->start(configData);
++ nvmeSubsys->start();
+ }
+ catch (std::exception& ex)
+ {
+diff --git a/src/NVMeSubsys.cpp b/src/NVMeSubsys.cpp
+index aebfd14..10b360d 100644
+--- a/src/NVMeSubsys.cpp
++++ b/src/NVMeSubsys.cpp
+@@ -39,10 +39,10 @@ NVMeSubsystem::NVMeSubsystem(boost::asio::io_context& asio,
+ sdbusplus::asio::object_server& server,
+ std::shared_ptr<sdbusplus::asio::connection> conn,
+ const std::string& path, const std::string& name,
+- NVMeIntf intf) :
++ const SensorData& configData, NVMeIntf intf) :
+ io(asio),
+- objServer(server), conn(conn), path(path), name(name),
+- nvmeIntf(std::move(intf)),
++ objServer(server), conn(conn), path(path), name(name), config(configData),
++ nvmeIntf(std::move(intf)), status(Status::Stop),
+ storage(*dynamic_cast<sdbusplus::bus_t*>(conn.get()), path.c_str()),
+ drive(*dynamic_cast<sdbusplus::bus_t*>(conn.get()), path.c_str())
+ {
+@@ -78,23 +78,50 @@ NVMeSubsystem::~NVMeSubsystem()
+ objServer.remove_interface(assocIntf);
+ }
+
+-void NVMeSubsystem::start(const SensorData& configData)
++void NVMeSubsystem::markFunctional(bool toggle)
+ {
++ // disable the subsystem
++ if (!toggle)
++ {
++ if (status == Status::Intiatilzing)
++ {
++ throw std::runtime_error(
++ "cannot stop: the subsystem is intiatilzing");
++ }
++ status = Status::Stop;
++ if (plugin)
++ {
++ plugin->stop();
++ }
++ // TODO: the controller should be stopped after controller level polling
++ // is enabled
++
++ controllers.clear();
++ plugin.reset();
++ return;
++ }
++ if (status == Status::Intiatilzing)
++ {
++ throw std::runtime_error("cannot start: the subsystem is intiatilzing");
++ }
++ status = Status::Intiatilzing;
++
+ // add controllers for the subsystem
+ if (nvmeIntf.getProtocol() == NVMeIntf::Protocol::NVMeMI)
+ {
+ auto nvme =
+ std::get<std::shared_ptr<NVMeMiIntf>>(nvmeIntf.getInferface());
+ nvme->miScanCtrl(
+- [self{shared_from_this()}, nvme,
+- configData](const std::error_code& ec,
+- const std::vector<nvme_mi_ctrl_t>& ctrlList) mutable {
++ [self{shared_from_this()},
++ nvme](const std::error_code& ec,
++ const std::vector<nvme_mi_ctrl_t>& ctrlList) mutable {
+ if (ec || ctrlList.size() == 0)
+ {
+ // TODO: mark the subsystem invalid and reschedule refresh
+ std::cerr << "fail to scan controllers for the nvme subsystem"
+ << (ec ? ": " + ec.message() : "") << std::endl;
+- // self->createStorageAssociation();
++ self->status = Status::Stop;
++ self->markFunctional(false);
+ return;
+ }
+
+@@ -132,7 +159,7 @@ void NVMeSubsystem::start(const SensorData& configData)
+ {
+ auto& ctrlPlugin = iter->second.second;
+ ctrlPlugin = self->plugin->createControllerPlugin(
+- *nvmeController, configData);
++ *nvmeController, self->config);
+ }
+
+ // set StorageController Association
+@@ -165,6 +192,8 @@ void NVMeSubsystem::start(const SensorData& configData)
+ {
+ std::cerr << "fail to identify secondary controller list"
+ << std::endl;
++ self->status = Status::Stop;
++ self->markFunctional(false);
+ return;
+ }
+ nvme_secondary_ctrl_list& listHdr =
+@@ -180,6 +209,8 @@ void NVMeSubsystem::start(const SensorData& configData)
+ {
+ std::cerr << "empty identify secondary controller list"
+ << std::endl;
++ self->status = Status::Stop;
++ self->markFunctional(false);
+ return;
+ }
+
+@@ -192,6 +223,8 @@ void NVMeSubsystem::start(const SensorData& configData)
+ std::cerr << "fail to match primary controller from "
+ "identify sencondary cntrl list"
+ << std::endl;
++ self->status = Status::Stop;
++ self->markFunctional(false);
+ return;
+ }
+
+@@ -230,10 +263,21 @@ void NVMeSubsystem::start(const SensorData& configData)
+ {
+ pair.first->start(pair.second);
+ }
++
++ // start plugin
++ if (self->plugin)
++ {
++ self->plugin->start();
++ }
++
++ self->status = Status::Start;
+ });
+ });
+ }
++}
+
++void NVMeSubsystem::start()
++{
+ // add thermal sensor for the subsystem
+ std::optional<std::string> sensorName = createSensorNameFromPath(path);
+ if (!sensorName)
+@@ -243,7 +287,7 @@ void NVMeSubsystem::start(const SensorData& configData)
+ }
+
+ std::vector<thresholds::Threshold> sensorThresholds;
+- if (!parseThresholdsFromConfig(configData, sensorThresholds))
++ if (!parseThresholdsFromConfig(config, sensorThresholds))
+ {
+ std::cerr << "error populating thresholds for " << *sensorName << "\n";
+ throw std::runtime_error("error populating thresholds for " +
+@@ -285,30 +329,56 @@ void NVMeSubsystem::start(const SensorData& configData)
+ intf->miSubsystemHealthStatusPoll(std::move(cb));
+ };
+ ctemp_parser_t<nvme_mi_nvm_ss_health_status*> dataParser =
+- [](nvme_mi_nvm_ss_health_status* status) -> std::optional<double> {
++ [self{shared_from_this()}](
++ nvme_mi_nvm_ss_health_status* status) -> std::optional<double> {
+ // Drive Functional
+ bool df = status->nss & 0x20;
+ if (!df)
+ {
++ // stop the subsystem
++ try
++ {
++ self->markFunctional(false);
++ self->ctemp->markFunctional(false);
++ }
++ catch (const std::runtime_error& e)
++ {
++ std::cerr << e.what() << std::endl;
++ }
+ return std::nullopt;
+ }
++
++ // restart the subsystem
++ if (self->status == Status::Stop)
++ {
++ self->markFunctional(true);
++ self->ctemp->markFunctional(true);
++ }
+ return {getTemperatureReading(status->ctemp)};
+ };
+ pollCtemp(ctempTimer, ctemp, dataFether, dataParser);
+ }
+-
+- // TODO: start to poll Drive status.
+-
+- if (plugin)
+- {
+- plugin->start();
+- }
+ }
+ void NVMeSubsystem::stop()
+ {
+- if (plugin)
++ ctempTimer->cancel();
++ if (status == Status::Start)
+ {
+- plugin->stop();
++ std::cerr << "status start" << std::endl;
++ markFunctional(false);
++ ctemp->markFunctional(false);
++ }
++ else if (status == Status::Intiatilzing)
++ {
++ std::cerr << "status init" << std::endl;
++ ctempTimer->expires_after(std::chrono::milliseconds(100));
++ ctempTimer->async_wait(
++ [self{shared_from_this()}](boost::system::error_code ec) {
++ if (ec)
++ {
++ return;
++ }
++ self->stop();
++ });
+ }
+- ctempTimer->cancel();
+ }
+diff --git a/src/NVMeSubsys.hpp b/src/NVMeSubsys.hpp
+index 3944fe7..e5db58a 100644
+--- a/src/NVMeSubsys.hpp
++++ b/src/NVMeSubsys.hpp
+@@ -19,11 +19,11 @@ class NVMeSubsystem : public std::enable_shared_from_this<NVMeSubsystem>
+ sdbusplus::asio::object_server& objServer,
+ std::shared_ptr<sdbusplus::asio::connection> conn,
+ const std::string& path, const std::string& name,
+- NVMeIntf intf);
++ const SensorData& configData, NVMeIntf intf);
+
+ ~NVMeSubsystem();
+
+- void start(const SensorData& configData);
++ void start();
+
+ void stop();
+
+@@ -34,9 +34,19 @@ class NVMeSubsystem : public std::enable_shared_from_this<NVMeSubsystem>
+ std::shared_ptr<sdbusplus::asio::connection> conn;
+ std::string path;
+ std::string name;
++ SensorData config;
+
+ NVMeIntf nvmeIntf;
+
++ enum class Status
++ {
++ Stop,
++ Intiatilzing,
++ Start,
++ };
++
++ Status status;
++
+ // plugin
+ std::shared_ptr<NVMePlugin> plugin;
+
+@@ -61,4 +71,8 @@ class NVMeSubsystem : public std::enable_shared_from_this<NVMeSubsystem>
+
+ std::shared_ptr<sdbusplus::asio::dbus_interface> assocIntf;
+ void createStorageAssociation();
++
++ // make the subsystem functional/functional be enabling/disabling the
++ // storage controller, namespaces and thermal sensors.
++ void markFunctional(bool toggle);
+ };
+diff --git a/tests/meson.build b/tests/meson.build
+index cc7fd53..4195434 100644
+--- a/tests/meson.build
++++ b/tests/meson.build
+@@ -21,6 +21,7 @@ endif
+
+ ut_deps_list = [
+ gtest_dep,
++ gmock_dep,
+ ]
+
+ ut_deps_list += default_deps
+diff --git a/tests/test_nvme_mi.cpp b/tests/test_nvme_mi.cpp
+index f8e4a01..581f20b 100644
+--- a/tests/test_nvme_mi.cpp
++++ b/tests/test_nvme_mi.cpp
+@@ -3,38 +3,167 @@
+
+ #include <sdbusplus/asio/connection.hpp>
+
++#include <gmock/gmock.h>
+ #include <gtest/gtest.h>
+
++class NVMeMiMock :
++ public NVMeMiIntf,
++ public std::enable_shared_from_this<NVMeMiMock>
++{
++ public:
++ NVMeMiMock(boost::asio::io_service& io) :
++ fake(std::move(std::make_shared<NVMeMiFake>(io)))
++ {
++ ON_CALL(*this, getNID).WillByDefault([]() { return 0; });
++ ON_CALL(*this, getEID).WillByDefault([]() { return 0; });
++ ON_CALL(*this, miSubsystemHealthStatusPoll)
++ .WillByDefault(
++ [this](
++ std::function<void(const std::error_code&,
++ nvme_mi_nvm_ss_health_status*)>&& cb) {
++ return fake->miSubsystemHealthStatusPoll(std::move(cb));
++ });
++ ON_CALL(*this, miScanCtrl)
++ .WillByDefault(
++ [this](
++ std::function<void(const std::error_code& ec,
++ const std::vector<nvme_mi_ctrl_t>& list)>
++ cb) { return fake->miScanCtrl(std::move(cb)); });
++ ON_CALL(*this, adminIdentify)
++ .WillByDefault(
++ [this](nvme_mi_ctrl_t ctrl, nvme_identify_cns cns,
++ uint32_t nsid, uint16_t cntid,
++ std::function<void(const std::error_code&,
++ std::span<uint8_t>)>&& cb) {
++ return fake->adminIdentify(ctrl, cns, nsid, cntid, std::move(cb));
++ });
++ ON_CALL(*this, adminGetLogPage)
++ .WillByDefault(
++ [this](nvme_mi_ctrl_t ctrl, nvme_cmd_get_log_lid lid,
++ uint32_t nsid, uint8_t lsp, uint16_t lsi,
++ std::function<void(const std::error_code&,
++ std::span<uint8_t>)>&& cb) {
++ return fake->adminGetLogPage(ctrl, lid, nsid, lsp, lsi,
++ std::move(cb));
++ });
++ ON_CALL(*this, adminFwCommit)
++ .WillByDefault([this](nvme_mi_ctrl_t ctrl, nvme_fw_commit_ca action,
++ uint8_t slot, bool bpid,
++ std::function<void(const std::error_code&,
++ nvme_status_field)>&& cb) {
++ return fake->adminFwCommit(ctrl, action, slot, bpid,
++ std::move(cb));
++ });
++ ON_CALL(*this, adminXfer)
++ .WillByDefault(
++ [this](
++ nvme_mi_ctrl_t ctrl, const nvme_mi_admin_req_hdr& admin_req,
++ std::span<uint8_t> data, unsigned int timeout_ms,
++ std::function<void(const std::error_code& ec,
++ const nvme_mi_admin_resp_hdr& admin_resp,
++ std::span<uint8_t> resp_data)>&& cb) {
++ return fake->adminXfer(ctrl, admin_req, data, timeout_ms,
++ std::move(cb));
++ });
++ }
++
++ MOCK_METHOD(int, getNID, (), (const override));
++ MOCK_METHOD(int, getEID, (), (const override));
++ MOCK_METHOD(void, miSubsystemHealthStatusPoll,
++ (std::function<void(const std::error_code&,
++ nvme_mi_nvm_ss_health_status*)> &&),
++ (override));
++ MOCK_METHOD(void, miScanCtrl,
++ (std::function<void(const std::error_code&,
++ const std::vector<nvme_mi_ctrl_t>&)>),
++ (override));
++ MOCK_METHOD(
++ void, adminIdentify,
++ (nvme_mi_ctrl_t ctrl, nvme_identify_cns cns, uint32_t nsid,
++ uint16_t cntid,
++ std::function<void(const std::error_code&, std::span<uint8_t>)>&& cb),
++ (override));
++ MOCK_METHOD(
++ void, adminGetLogPage,
++ (nvme_mi_ctrl_t ctrl, nvme_cmd_get_log_lid lid, uint32_t nsid,
++ uint8_t lsp, uint16_t lsi,
++ std::function<void(const std::error_code&, std::span<uint8_t>)>&& cb),
++ (override));
++ MOCK_METHOD(
++ void, adminFwCommit,
++ (nvme_mi_ctrl_t ctrl, nvme_fw_commit_ca action, uint8_t slot, bool bpid,
++ std::function<void(const std::error_code&, nvme_status_field)>&& cb),
++ (override));
++ MOCK_METHOD(void, adminXfer,
++ (nvme_mi_ctrl_t ctrl, const nvme_mi_admin_req_hdr& admin_req,
++ std::span<uint8_t> data, unsigned int timeout_ms,
++ std::function<void(const std::error_code& ec,
++ const nvme_mi_admin_resp_hdr& admin_resp,
++ std::span<uint8_t> resp_data)>&& cb),
++ (override));
++
++ std::shared_ptr<NVMeMiFake> fake;
++};
++
+ class NVMeTest : public ::testing::Test
+ {
+ protected:
+ NVMeTest() :
+- system_bus(std::make_shared<sdbusplus::asio::connection>(io)),
+- object_server(system_bus),
+- subsys(std::make_shared<NVMeSubsystem>(
+- io, object_server, system_bus, subsys_path, "NVMe_1",
+- std::move(NVMeIntf::create<NVMeMiFake>(io))))
++ object_server(system_bus), nvme_intf(NVMeIntf::create<NVMeMiMock>(io)),
++ mock(*std::dynamic_pointer_cast<NVMeMiMock>(
++ std::get<std::shared_ptr<NVMeMiIntf>>(
++ nvme_intf.getInferface()))
++ .get()),
++ subsys(std::make_shared<NVMeSubsystem>(io, object_server, system_bus,
++ subsys_path, "NVMe_1",
++ SensorData{}, nvme_intf))
+ {}
+- void SetUp() override
++
++ static void SetUpTestSuite()
+ {
++ system_bus =
++ std::make_shared<sdbusplus::asio::connection>(NVMeTest::io);
+ system_bus->request_name("xyz.openbmc_project.NVMeTest");
+- subsys->start(SensorData{});
++ }
++
++ void SetUp() override
++ {
++ subsys->start();
++ }
++
++ void TearDown() override
++ {
++ io.restart();
+ }
+
+ static constexpr char subsys_path[] =
+ "/xyz/openbmc_project/inventory/Test_Chassis/Test_NVMe";
+
+- boost::asio::io_service io;
+- std::shared_ptr<sdbusplus::asio::connection> system_bus;
++ static boost::asio::io_service io;
++ static std::shared_ptr<sdbusplus::asio::connection> system_bus;
+ sdbusplus::asio::object_server object_server;
+
++ NVMeIntf nvme_intf;
++ NVMeMiMock& mock;
+ std::shared_ptr<NVMeSubsystem> subsys;
+ };
+
++boost::asio::io_service NVMeTest::io;
++std::shared_ptr<sdbusplus::asio::connection> NVMeTest::system_bus;
++
++/**
++ * @brief Test start and stop function of NVMeSubsystem
++ *
++ */
+ TEST_F(NVMeTest, TestSubsystemStartStop)
+ {
++ using ::testing::AtLeast;
+ boost::asio::steady_timer timer(io);
+
++ EXPECT_CALL(mock, miSubsystemHealthStatusPoll).Times(AtLeast(1));
++ EXPECT_CALL(mock, adminIdentify).Times(AtLeast(1));
++ EXPECT_CALL(mock, miScanCtrl).Times(AtLeast(1));
++
+ // wait for subsystem initialization
+ timer.expires_after(std::chrono::seconds(2));
+ timer.async_wait([&](boost::system::error_code) {
+@@ -70,3 +199,101 @@ TEST_F(NVMeTest, TestSubsystemStartStop)
+ });
+ io.run();
+ }
++
++/**
++ * @brief Test NVMeMi return DriveFunctional(NSHDS.NSS.DF) = 0
++ *
++ */
++TEST_F(NVMeTest, TestDriveFunctional)
++{
++
++ using ::testing::AtLeast;
++ boost::asio::steady_timer timer(io);
++
++ EXPECT_CALL(mock, miSubsystemHealthStatusPoll).Times(AtLeast(1));
++ EXPECT_CALL(mock, adminIdentify).Times(AtLeast(1));
++ EXPECT_CALL(mock, miScanCtrl).Times(AtLeast(1));
++
++ // wait for subsystem initialization
++ timer.expires_after(std::chrono::seconds(2));
++ timer.async_wait([&](boost::system::error_code) {
++ system_bus->async_method_call(
++ [&](boost::system::error_code, const GetSubTreeType& result) {
++ // Only PF and the enabled VF should be listed
++ EXPECT_EQ(result.size(), 2);
++
++ // mimik communication error of NVMeMI request
++ ON_CALL(mock, miSubsystemHealthStatusPoll)
++ .WillByDefault(
++ [&](std::function<void(const std::error_code&,
++ nvme_mi_nvm_ss_health_status*)>&&
++ cb) {
++ std::cerr << "mock health poll" << std::endl;
++ // return status.nss.df = 0
++ return io.post([cb = std::move(cb)]() {
++ nvme_mi_nvm_ss_health_status status;
++ status.nss = 0;
++ cb({}, &status);
++ });
++ });
++
++ // wait for storage controller destruction.
++ timer.expires_after(std::chrono::seconds(2));
++ timer.async_wait([&](boost::system::error_code) {
++ system_bus->async_method_call(
++ [&](boost::system::error_code,
++ const GetSubTreeType& result) {
++ // no storage controller should be listed.
++ EXPECT_EQ(result.size(), 0);
++
++ // restart sending DF = 1
++ ON_CALL(mock, miSubsystemHealthStatusPoll)
++ .WillByDefault(
++ [&](std::function<void(
++ const std::error_code&,
++ nvme_mi_nvm_ss_health_status*)>&& cb) {
++ return mock.fake->miSubsystemHealthStatusPoll(
++ std::move(cb));
++ });
++ timer.expires_after(std::chrono::seconds(2));
++ timer.async_wait([&](boost::system::error_code) {
++ system_bus->async_method_call(
++ [&](boost::system::error_code,
++ const GetSubTreeType& result) {
++ // storage controller should be restored.
++ EXPECT_EQ(result.size(), 2);
++
++ subsys->stop();
++ io.stop();
++ },
++ "xyz.openbmc_project.ObjectMapper",
++ "/xyz/openbmc_project/object_mapper",
++ "xyz.openbmc_project.ObjectMapper", "GetSubTree",
++ subsys_path, 0,
++ std::vector<std::string>{
++ "xyz.openbmc_project.Inventory."
++ "Item.StorageController"});
++ });
++ },
++ "xyz.openbmc_project.ObjectMapper",
++ "/xyz/openbmc_project/object_mapper",
++ "xyz.openbmc_project.ObjectMapper", "GetSubTree",
++ subsys_path, 0,
++ std::vector<std::string>{"xyz.openbmc_project.Inventory."
++ "Item.StorageController"});
++ });
++ },
++ "xyz.openbmc_project.ObjectMapper",
++ "/xyz/openbmc_project/object_mapper",
++ "xyz.openbmc_project.ObjectMapper", "GetSubTree", subsys_path, 0,
++ std::vector<std::string>{
++ "xyz.openbmc_project.Inventory.Item.StorageController"});
++ });
++ io.run();
++}
++
++int main(int argc, char** argv)
++{
++ ::testing::InitGoogleTest(&argc, argv);
++ return RUN_ALL_TESTS();
++}
+--
+2.34.1
+
diff --git a/recipes-phosphor/sensors/dbus-sensors/0032-nvmesensor-subsystem-poll-supports-absence.patch b/recipes-phosphor/sensors/dbus-sensors/0032-nvmesensor-subsystem-poll-supports-absence.patch
new file mode 100644
index 0000000..7325df9
--- /dev/null
+++ b/recipes-phosphor/sensors/dbus-sensors/0032-nvmesensor-subsystem-poll-supports-absence.patch
@@ -0,0 +1,544 @@
+From f89349b1a54b3e5bb6dcb3ddd027f90543c9a46e Mon Sep 17 00:00:00 2001
+From: Hao Jiang <jianghao@google.com>
+Date: Thu, 20 Apr 2023 20:48:54 +0000
+Subject: [PATCH 32/44] nvmesensor: subsystem poll supports absence
+
+Enhance the polling function to support more symptoms. For example, the
+endpoint absence. The signal comes from NVMeMi class because the
+absence detection was done by transporation layer(mctp or i2c binding),
+instead of the NVMe-MI protocol layer.
+
+The enhancement will be furthur utilized by other symptoms provided by
+NSHDS (NVM Subsystem Health Data Structure), including but not limited
+to SW, CCS.CSTS, CCS.NAC, etc.
+
+Tested: passed the unit test of TestDriveAbsent with increase polling
+rate of 50 ms.
+
+Signed-off-by: Hao Jiang <jianghao@google.com>
+Change-Id: I5efe7c07e07630064b5e6e7fd707f3c286673bba
+---
+ src/NVMeBasic.cpp | 13 +---
+ src/NVMeIntf.hpp | 1 +
+ src/NVMeSubsys.cpp | 146 +++++++++++++++++++++++++++++++++--------
+ src/NVMeSubsys.hpp | 1 -
+ src/NVMeUtil.hpp | 92 ++++++++------------------
+ tests/test_nvme_mi.cpp | 95 ++++++++++++++++++++++++++-
+ 6 files changed, 242 insertions(+), 106 deletions(-)
+
+diff --git a/src/NVMeBasic.cpp b/src/NVMeBasic.cpp
+index 3a2d4ca..d18aed4 100644
+--- a/src/NVMeBasic.cpp
++++ b/src/NVMeBasic.cpp
+@@ -342,23 +342,12 @@ void NVMeBasic::getStatus(
+
+ /* Process the callback */
+ self->io.post([data, cb{std::move(cb)}]() {
+- if (data->size() <
+- sizeof(DriveStatus) + 1) // The first byte is status flags
++ if (data->size() < sizeof(DriveStatus))
+ {
+ cb(std::make_error_code(std::errc::message_size), nullptr);
+ return;
+ }
+
+- uint8_t flags = static_cast<uint8_t>(data->front());
+- if (((flags & NVME_MI_BASIC_SFLGS_DRIVE_NOT_READY) != 0) ||
+- ((flags & NVME_MI_BASIC_SFLGS_DRIVE_FUNCTIONAL) == 0))
+- {
+- cb(std::make_error_code(std::errc::no_such_device),
+- nullptr);
+- return;
+- }
+-
+- data->erase(data->begin());
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+ cb({}, reinterpret_cast<DriveStatus*>(data->data()));
+ });
+diff --git a/src/NVMeIntf.hpp b/src/NVMeIntf.hpp
+index e52a700..f87b536 100644
+--- a/src/NVMeIntf.hpp
++++ b/src/NVMeIntf.hpp
+@@ -78,6 +78,7 @@ class NVMeBasicIntf
+ public:
+ struct DriveStatus
+ {
++ uint8_t Status;
+ uint8_t SmartWarnings;
+ uint8_t Temp;
+ uint8_t DriveLifeUsed;
+diff --git a/src/NVMeSubsys.cpp b/src/NVMeSubsys.cpp
+index 10b360d..c605e30 100644
+--- a/src/NVMeSubsys.cpp
++++ b/src/NVMeSubsys.cpp
+@@ -1,6 +1,7 @@
+ #include "NVMeSubsys.hpp"
+
+ #include "NVMePlugin.hpp"
++#include "NVMeUtil.hpp"
+ #include "Thresholds.hpp"
+
+ #include <filesystem>
+@@ -303,60 +304,153 @@ void NVMeSubsystem::start()
+ {
+ auto intf =
+ std::get<std::shared_ptr<NVMeBasicIntf>>(nvmeIntf.getInferface());
+- ctemp_fetcher_t<NVMeBasicIntf::DriveStatus*> dataFether =
+- [intf](std::function<void(const std::error_code&,
+- NVMeBasicIntf::DriveStatus*)>&& cb) {
++ ctemp_fetch_t<NVMeBasicIntf::DriveStatus*> dataFether =
++ [intf, self{std::move(shared_from_this())}](
++ std::function<void(const std::error_code&,
++ NVMeBasicIntf::DriveStatus*)>&& cb) {
++ /* Potentially defer sampling the sensor sensor if it is in error */
++ if (!self->ctemp->sample())
++ {
++ cb(std::make_error_code(std::errc::operation_canceled),
++ nullptr);
++ return;
++ }
++
+ intf->getStatus(std::move(cb));
+ };
+- ctemp_parser_t<NVMeBasicIntf::DriveStatus*> dataParser =
+- [](NVMeBasicIntf::DriveStatus* status) -> std::optional<double> {
++ ctemp_process_t<NVMeBasicIntf::DriveStatus*> dataProcessor =
++ [self{shared_from_this()}](const std::error_code& error,
++ NVMeBasicIntf::DriveStatus* status) {
++ // deferred sampling
++ if (error == std::errc::operation_canceled)
++ {
++ return;
++ }
++ // The device is physically absent
++ else if (error == std::errc::no_such_device)
++ {
++ std::cerr << "error reading ctemp from subsystem"
++ << ", reason:" << error.message() << "\n";
++ self->ctemp->markFunctional(false);
++ self->ctemp->markAvailable(false);
++ return;
++ }
++ // other communication errors
++ else if (error)
++ {
++ std::cerr << "error reading ctemp from subsystem"
++ << ", reason:" << error.message() << "\n";
++ self->ctemp->incrementError();
++ return;
++ }
++
+ if (status == nullptr)
+ {
+- return std::nullopt;
++ std::cerr << "empty data returned by data fetcher" << std::endl;
++ self->ctemp->markFunctional(false);
++ return;
+ }
+- return {getTemperatureReading(status->Temp)};
++
++ uint8_t flags = status->Status;
++ if (((flags & NVMeBasicIntf::StatusFlags::
++ NVME_MI_BASIC_SFLGS_DRIVE_NOT_READY) != 0) ||
++ ((flags & NVMeBasicIntf::StatusFlags::
++ NVME_MI_BASIC_SFLGS_DRIVE_FUNCTIONAL) == 0))
++ {
++ self->ctemp->markFunctional(false);
++ return;
++ }
++ self->ctemp->updateValue(getTemperatureReading(status->Temp));
+ };
+- pollCtemp(this->ctempTimer, this->ctemp, dataFether, dataParser);
++
++ pollCtemp(ctempTimer, std::chrono::seconds(1), dataFether,
++ dataProcessor);
+ }
+ else if (nvmeIntf.getProtocol() == NVMeIntf::Protocol::NVMeMI)
+ {
+ auto intf =
+ std::get<std::shared_ptr<NVMeMiIntf>>(nvmeIntf.getInferface());
+
+- ctemp_fetcher_t<nvme_mi_nvm_ss_health_status*> dataFether =
+- [intf](std::function<void(const std::error_code&,
+- nvme_mi_nvm_ss_health_status*)>&& cb) {
++ ctemp_fetch_t<nvme_mi_nvm_ss_health_status*> dataFether =
++ [intf, self{std::move(shared_from_this())}](
++ std::function<void(const std::error_code&,
++ nvme_mi_nvm_ss_health_status*)>&& cb) {
++ // do not poll the health status if the subsystem is intiatilzing
++ if (self->status == Status::Intiatilzing)
++ {
++ std::cerr << "subsystem is intiatilzing, cancel the health poll"
++ << std::endl;
++ cb(std::make_error_code(std::errc::operation_canceled),
++ nullptr);
++ return;
++ }
+ intf->miSubsystemHealthStatusPoll(std::move(cb));
+ };
+- ctemp_parser_t<nvme_mi_nvm_ss_health_status*> dataParser =
+- [self{shared_from_this()}](
+- nvme_mi_nvm_ss_health_status* status) -> std::optional<double> {
+- // Drive Functional
+- bool df = status->nss & 0x20;
+- if (!df)
++ ctemp_process_t<nvme_mi_nvm_ss_health_status*> dataProcessor =
++ [self{shared_from_this()}](const std::error_code& error,
++ nvme_mi_nvm_ss_health_status* status) {
++ if (error == std::errc::operation_canceled ||
++ self->status == Status::Intiatilzing)
+ {
++ // on initialization, the subsystem will not update the status.
++ std::cerr
++ << "subsystem is intiatilzing, do not process the status"
++ << std::endl;
++ return;
++ }
++
++ if (error == std::errc::no_such_device)
++ {
++ std::cerr << "error reading ctemp "
++ "from subsystem"
++ << ", reason:" << error.message() << "\n";
+ // stop the subsystem
+- try
++ self->markFunctional(false);
++ self->ctemp->markFunctional(false);
++ self->ctemp->markAvailable(false);
++
++ return;
++ }
++ else if (error)
++ {
++ std::cerr << "error reading ctemp "
++ "from subsystem"
++ << ", reason:" << error.message() << "\n";
++ self->ctemp->incrementError();
++ if (self->ctemp->inError())
+ {
+ self->markFunctional(false);
+ self->ctemp->markFunctional(false);
+ }
+- catch (const std::runtime_error& e)
+- {
+- std::cerr << e.what() << std::endl;
+- }
+- return std::nullopt;
++ return;
++ }
++
++ // Drive Functional
++ bool df = status->nss & 0x20;
++ if (!df)
++ {
++ // stop the subsystem
++
++ self->markFunctional(false);
++ self->ctemp->markFunctional(false);
++
++ return;
+ }
+
+ // restart the subsystem
+ if (self->status == Status::Stop)
+ {
+ self->markFunctional(true);
+- self->ctemp->markFunctional(true);
+ }
+- return {getTemperatureReading(status->ctemp)};
++
++ // TODO: update the drive interface
++
++ self->ctemp->updateValue(getTemperatureReading(status->ctemp));
++ return;
+ };
+- pollCtemp(ctempTimer, ctemp, dataFether, dataParser);
++
++ pollCtemp(ctempTimer, std::chrono::seconds(1), dataFether,
++ dataProcessor);
+ }
+ }
+ void NVMeSubsystem::stop()
+diff --git a/src/NVMeSubsys.hpp b/src/NVMeSubsys.hpp
+index e5db58a..6bd8b62 100644
+--- a/src/NVMeSubsys.hpp
++++ b/src/NVMeSubsys.hpp
+@@ -4,7 +4,6 @@
+ #include "NVMeDrive.hpp"
+ #include "NVMeSensor.hpp"
+ #include "NVMeStorage.hpp"
+-#include "NVMeUtil.hpp"
+ #include "Utils.hpp"
+
+ class NVMeControllerPlugin;
+diff --git a/src/NVMeUtil.hpp b/src/NVMeUtil.hpp
+index 16fe291..8639113 100644
+--- a/src/NVMeUtil.hpp
++++ b/src/NVMeUtil.hpp
+@@ -7,6 +7,7 @@
+ #include <filesystem>
+ #include <iostream>
+ #include <optional>
++#include <system_error>
+
+ inline std::filesystem::path deriveRootBusPath(int busNumber)
+ {
+@@ -104,60 +105,43 @@ inline std::optional<std::string>
+ // Function type for fetching ctemp which encaplucated in a structure of T.
+ // The fetcher function take a callback as input to process the result.
+ template <class T>
+-using ctemp_fetcher_t =
++using ctemp_fetch_t =
+ std::function<void(std::function<void(const std::error_code&, T)>&&)>;
+
+-// Function type for parsing ctemp out the structure of type T.
+-// The parser function will return the value of ctemp or nullopt on failure.
++// Function type for processing ctemp out the structure of type T.
++// The process function will update the properties based on input data.
+ template <class T>
+-using ctemp_parser_t = std::function<std::optional<double>(T data)>;
++using ctemp_process_t =
++ std::function<void(const std::error_code& error, T data)>;
+
+ template <class T>
+ void pollCtemp(
+ std::shared_ptr<boost::asio::steady_timer> timer,
+- std::shared_ptr<NVMeSensor> sensor,
++ std::chrono::duration<double, std::milli> delay,
+ const std::function<void(std::function<void(const std::error_code&, T)>&&)>&
+ dataFetcher,
+- const std::function<std::optional<double>(T data)>& dataParser);
++ const std::function<void(const std::error_code& error, T data)>&
++ dataProcessor);
+
+ namespace detail
+ {
+
+ template <class T>
+ void updateCtemp(std::shared_ptr<boost::asio::steady_timer> timer,
+- std::shared_ptr<NVMeSensor> sensor,
+- ctemp_parser_t<T> dataParser, ctemp_fetcher_t<T> dataFetcher,
+- const boost::system::error_code error, T data)
++ std::chrono::duration<double, std::milli> delay,
++ ctemp_process_t<T> dataProcessor, ctemp_fetch_t<T> dataFetcher,
++ const std::error_code& error, T data)
+ {
+- if (error)
+- {
+- std::cerr << "error reading ctemp from subsystem"
+- << ", reason:" << error.message() << "\n";
+- sensor->markFunctional(false);
+- ::pollCtemp(std::move(timer), std::move(sensor), dataFetcher,
+- dataParser);
+- return;
+- }
+- auto value = dataParser(data);
+- if (!value)
+- {
+- sensor->incrementError();
+- ::pollCtemp(std::move(timer), std::move(sensor), dataFetcher,
+- dataParser);
+- return;
+- }
+-
+- sensor->updateValue(*value);
+- ::pollCtemp(std::move(timer), std::move(sensor), dataFetcher, dataParser);
++ dataProcessor(error, data);
++ ::pollCtemp(std::move(timer), std::move(delay), dataFetcher, dataProcessor);
+ }
+
+ template <class T>
+ void pollCtemp(std::shared_ptr<boost::asio::steady_timer> timer,
+- std::shared_ptr<NVMeSensor> sensor,
+- ctemp_fetcher_t<T> dataFetcher, ctemp_parser_t<T> dataParser,
++ std::chrono::duration<double, std::milli> delay,
++ ctemp_fetch_t<T> dataFetcher, ctemp_process_t<T> dataProcessor,
+ const boost::system::error_code errorCode)
+ {
+-
+ if (errorCode == boost::asio::error::operation_aborted)
+ {
+ return;
+@@ -165,37 +149,13 @@ void pollCtemp(std::shared_ptr<boost::asio::steady_timer> timer,
+ if (errorCode)
+ {
+ std::cerr << errorCode.message() << "\n";
+- ::pollCtemp(std::move(timer), std::move(sensor), dataFetcher,
+- dataParser);
+- return;
+- }
+-
+- if (!sensor)
+- {
+- ::pollCtemp(std::move(timer), std::move(sensor), dataFetcher,
+- dataParser);
+- return;
+- }
+-
+- if (!sensor->readingStateGood())
+- {
+- sensor->markAvailable(false);
+- sensor->updateValue(std::numeric_limits<double>::quiet_NaN());
+- ::pollCtemp(std::move(timer), std::move(sensor), dataFetcher,
+- dataParser);
+- return;
+- }
+-
+- /* Potentially defer sampling the sensor sensor if it is in error */
+- if (!sensor->sample())
+- {
+- ::pollCtemp(std::move(timer), std::move(sensor), dataFetcher,
+- dataParser);
++ ::pollCtemp(std::move(timer), std::move(delay), dataFetcher,
++ dataProcessor);
+ return;
+ }
+
+ dataFetcher(std::bind_front(detail::updateCtemp<T>, std::move(timer),
+- std::move(sensor), dataParser, dataFetcher));
++ std::move(delay), dataProcessor, dataFetcher));
+ }
+
+ } // namespace detail
+@@ -203,17 +163,19 @@ void pollCtemp(std::shared_ptr<boost::asio::steady_timer> timer,
+ template <class T>
+ void pollCtemp(
+ std::shared_ptr<boost::asio::steady_timer> timer,
+- std::shared_ptr<NVMeSensor> sensor,
++ std::chrono::duration<double, std::milli> delay,
+ const std::function<void(std::function<void(const std::error_code&, T)>&&)>&
+ dataFetcher,
+- const std::function<std::optional<double>(T data)>& dataParser)
++ const std::function<void(const std::error_code& error, T data)>&
++ dataProcessor)
+ {
+- if (!timer && !sensor)
++ if (!timer)
+ {
+ return;
+ }
+- timer->expires_from_now(std::chrono::seconds(1));
++ timer->expires_from_now(
++ std::chrono::duration_cast<std::chrono::milliseconds>(delay));
+ timer->async_wait(std::bind_front(detail::pollCtemp<T>, std::move(timer),
+- std::move(sensor), dataFetcher,
+- dataParser));
++ std::move(delay), dataFetcher,
++ dataProcessor));
+ }
+diff --git a/tests/test_nvme_mi.cpp b/tests/test_nvme_mi.cpp
+index 581f20b..8462d5e 100644
+--- a/tests/test_nvme_mi.cpp
++++ b/tests/test_nvme_mi.cpp
+@@ -228,7 +228,8 @@ TEST_F(NVMeTest, TestDriveFunctional)
+ [&](std::function<void(const std::error_code&,
+ nvme_mi_nvm_ss_health_status*)>&&
+ cb) {
+- std::cerr << "mock health poll" << std::endl;
++ std::cerr << "mock device not functional health poll"
++ << std::endl;
+ // return status.nss.df = 0
+ return io.post([cb = std::move(cb)]() {
+ nvme_mi_nvm_ss_health_status status;
+@@ -264,7 +265,97 @@ TEST_F(NVMeTest, TestDriveFunctional)
+ EXPECT_EQ(result.size(), 2);
+
+ subsys->stop();
+- io.stop();
++ io.post([&]() { io.stop(); });
++ },
++ "xyz.openbmc_project.ObjectMapper",
++ "/xyz/openbmc_project/object_mapper",
++ "xyz.openbmc_project.ObjectMapper", "GetSubTree",
++ subsys_path, 0,
++ std::vector<std::string>{
++ "xyz.openbmc_project.Inventory."
++ "Item.StorageController"});
++ });
++ },
++ "xyz.openbmc_project.ObjectMapper",
++ "/xyz/openbmc_project/object_mapper",
++ "xyz.openbmc_project.ObjectMapper", "GetSubTree",
++ subsys_path, 0,
++ std::vector<std::string>{"xyz.openbmc_project.Inventory."
++ "Item.StorageController"});
++ });
++ },
++ "xyz.openbmc_project.ObjectMapper",
++ "/xyz/openbmc_project/object_mapper",
++ "xyz.openbmc_project.ObjectMapper", "GetSubTree", subsys_path, 0,
++ std::vector<std::string>{
++ "xyz.openbmc_project.Inventory.Item.StorageController"});
++ });
++ io.run();
++}
++
++/**
++ * @brief Test NVMeMi returns Drive is absent (ec = no_such_device)
++ *
++ */
++TEST_F(NVMeTest, TestDriveAbsent)
++{
++ using ::testing::AtLeast;
++ boost::asio::steady_timer timer(io);
++
++ EXPECT_CALL(mock, miSubsystemHealthStatusPoll).Times(AtLeast(1));
++ EXPECT_CALL(mock, adminIdentify).Times(AtLeast(1));
++ EXPECT_CALL(mock, miScanCtrl).Times(AtLeast(1));
++
++ // wait for subsystem initialization
++ timer.expires_after(std::chrono::seconds(2));
++ timer.async_wait([&](boost::system::error_code) {
++ system_bus->async_method_call(
++ [&](boost::system::error_code, const GetSubTreeType& result) {
++ // Only PF and the enabled VF should be listed
++ EXPECT_EQ(result.size(), 2);
++
++ // mimik communication error of NVMeMI request
++ ON_CALL(mock, miSubsystemHealthStatusPoll)
++ .WillByDefault(
++ [&](std::function<void(const std::error_code&,
++ nvme_mi_nvm_ss_health_status*)>&&
++ cb) {
++ std::cerr << "mock device absent health poll" << std::endl;
++ // return no_such_device
++ return io.post([cb = std::move(cb)]() {
++ cb(std::make_error_code(std::errc::no_such_device),
++ nullptr);
++ });
++ });
++
++ // wait for storage controller destruction.
++ timer.expires_after(std::chrono::seconds(2));
++ timer.async_wait([&](boost::system::error_code) {
++ system_bus->async_method_call(
++ [&](boost::system::error_code,
++ const GetSubTreeType& result) {
++ // no storage controller should be listed.
++ EXPECT_EQ(result.size(), 0);
++
++ // restart sending normal polling result
++ ON_CALL(mock, miSubsystemHealthStatusPoll)
++ .WillByDefault(
++ [&](std::function<void(
++ const std::error_code&,
++ nvme_mi_nvm_ss_health_status*)>&& cb) {
++ return mock.fake->miSubsystemHealthStatusPoll(
++ std::move(cb));
++ });
++ timer.expires_after(std::chrono::seconds(2));
++ timer.async_wait([&](boost::system::error_code) {
++ system_bus->async_method_call(
++ [&](boost::system::error_code,
++ const GetSubTreeType& result) {
++ // storage controller should be restored.
++ EXPECT_EQ(result.size(), 2);
++
++ subsys->stop();
++ io.post([&]() { io.stop(); });
+ },
+ "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+--
+2.34.1
+
diff --git a/recipes-phosphor/sensors/dbus-sensors/0027-Enable-asio-threads-and-boost-coroutine.patch b/recipes-phosphor/sensors/dbus-sensors/0033-Enable-asio-threads-and-boost-coroutine.patch
similarity index 91%
rename from recipes-phosphor/sensors/dbus-sensors/0027-Enable-asio-threads-and-boost-coroutine.patch
rename to recipes-phosphor/sensors/dbus-sensors/0033-Enable-asio-threads-and-boost-coroutine.patch
index 6d18ad3..cf5533b 100644
--- a/recipes-phosphor/sensors/dbus-sensors/0027-Enable-asio-threads-and-boost-coroutine.patch
+++ b/recipes-phosphor/sensors/dbus-sensors/0033-Enable-asio-threads-and-boost-coroutine.patch
@@ -1,7 +1,7 @@
-From af7572953ba58aa5adcb7f77c69594cfdd6453ec Mon Sep 17 00:00:00 2001
+From 6639b4b4e59806b654d468e8e76776366afacf7c Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@codeconstruct.com.au>
Date: Wed, 18 Jan 2023 15:53:54 +0800
-Subject: [PATCH 27/34] Enable asio threads and boost coroutine
+Subject: [PATCH 33/44] Enable asio threads and boost coroutine
ASIO thread support is required to use a worker thread pool,
coroutines will be used for asynchronous dbus method handlers.
diff --git a/recipes-phosphor/sensors/dbus-sensors/0028-nvmesensor-Split-constructor-for-shared_from_this.patch b/recipes-phosphor/sensors/dbus-sensors/0034-nvmesensor-Split-constructor-for-shared_from_this.patch
similarity index 94%
rename from recipes-phosphor/sensors/dbus-sensors/0028-nvmesensor-Split-constructor-for-shared_from_this.patch
rename to recipes-phosphor/sensors/dbus-sensors/0034-nvmesensor-Split-constructor-for-shared_from_this.patch
index 97121ff..b5ca898 100644
--- a/recipes-phosphor/sensors/dbus-sensors/0028-nvmesensor-Split-constructor-for-shared_from_this.patch
+++ b/recipes-phosphor/sensors/dbus-sensors/0034-nvmesensor-Split-constructor-for-shared_from_this.patch
@@ -1,7 +1,7 @@
-From abcfdf873fce129504fb009b84615e91abeeabe2 Mon Sep 17 00:00:00 2001
+From 005696ecd326eb3982764171db38f892963c943a Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@codeconstruct.com.au>
Date: Wed, 18 Jan 2023 16:06:41 +0800
-Subject: [PATCH 28/34] nvmesensor: Split constructor for shared_from_this
+Subject: [PATCH 34/44] nvmesensor: Split constructor for shared_from_this
This allows using shared_from_this during initialisation
@@ -122,10 +122,10 @@
/** @brief Implementation for GetLogPage
diff --git a/src/NVMeSubsys.cpp b/src/NVMeSubsys.cpp
-index e9ad699..97e879e 100644
+index c605e30..cd10a75 100644
--- a/src/NVMeSubsys.cpp
+++ b/src/NVMeSubsys.cpp
-@@ -189,8 +189,8 @@ void NVMeSubsystem::start(const SensorData& configData)
+@@ -231,8 +231,8 @@ void NVMeSubsystem::markFunctional(bool toggle)
// Enable primary controller since they are required to work
auto& primaryController = findPrimary->second.first;
@@ -136,7 +136,7 @@
std::vector<std::shared_ptr<NVMeController>> secCntrls;
for (int i = 0; i < listHdr.num; i++)
-@@ -210,8 +210,8 @@ void NVMeSubsystem::start(const SensorData& configData)
+@@ -252,8 +252,8 @@ void NVMeSubsystem::markFunctional(bool toggle)
// Check Secondary Controller State
if (listHdr.sc_entry[i].scs != 0)
{
diff --git a/recipes-phosphor/sensors/dbus-sensors/0029-nvmesensor-Add-SecuritySend-and-SecurityReceive.patch b/recipes-phosphor/sensors/dbus-sensors/0035-nvmesensor-Add-SecuritySend-and-SecurityReceive.patch
similarity index 87%
rename from recipes-phosphor/sensors/dbus-sensors/0029-nvmesensor-Add-SecuritySend-and-SecurityReceive.patch
rename to recipes-phosphor/sensors/dbus-sensors/0035-nvmesensor-Add-SecuritySend-and-SecurityReceive.patch
index b151659..cce12f5 100644
--- a/recipes-phosphor/sensors/dbus-sensors/0029-nvmesensor-Add-SecuritySend-and-SecurityReceive.patch
+++ b/recipes-phosphor/sensors/dbus-sensors/0035-nvmesensor-Add-SecuritySend-and-SecurityReceive.patch
@@ -1,7 +1,7 @@
-From d902af64fba515d7250ba5ec74924d0e41900d87 Mon Sep 17 00:00:00 2001
+From 5757a885b75fdebdb150530137f49bd3b4c89fb0 Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@codeconstruct.com.au>
Date: Wed, 18 Jan 2023 16:33:24 +0800
-Subject: [PATCH 29/34] nvmesensor: Add SecuritySend and SecurityReceive
+Subject: [PATCH 35/44] nvmesensor: Add SecuritySend and SecurityReceive
The dbus interface is manually implemented to allow
an asynchronous method handler.
@@ -12,13 +12,13 @@
Signed-off-by: Matt Johnston <matt@codeconstruct.com.au>
Change-Id: Ic5acd45b6ade2651927b0abbfde35551e139d996
---
- src/AsioHelper.hpp | 40 ++++++++++++
- src/NVMeController.cpp | 134 +++++++++++++++++++++++++++++++++++++++++
- src/NVMeController.hpp | 14 +++++
- src/NVMeIntf.hpp | 11 ++++
- src/NVMeMi.cpp | 102 +++++++++++++++++++++++++++++++
+ src/AsioHelper.hpp | 40 +++++++++++
+ src/NVMeController.cpp | 147 +++++++++++++++++++++++++++++++++++++++++
+ src/NVMeController.hpp | 14 ++++
+ src/NVMeIntf.hpp | 11 +++
+ src/NVMeMi.cpp | 102 ++++++++++++++++++++++++++++
src/NVMeMi.hpp | 13 ++++
- 6 files changed, 314 insertions(+)
+ 6 files changed, 327 insertions(+)
create mode 100644 src/AsioHelper.hpp
diff --git a/src/AsioHelper.hpp b/src/AsioHelper.hpp
@@ -68,7 +68,7 @@
+
+} // namespace asio_helper
diff --git a/src/NVMeController.cpp b/src/NVMeController.cpp
-index cec6664..1c34a58 100644
+index cec6664..5553859 100644
--- a/src/NVMeController.cpp
+++ b/src/NVMeController.cpp
@@ -1,7 +1,9 @@
@@ -81,7 +81,7 @@
#include <sdbusplus/message/native_types.hpp>
#include <xyz/openbmc_project/Common/File/error.hpp>
#include <xyz/openbmc_project/Common/error.hpp>
-@@ -76,6 +78,27 @@ void NVMeControllerEnabled::init()
+@@ -76,6 +78,40 @@ void NVMeControllerEnabled::init()
assocIntf->register_property("Associations", associations);
assocIntf->initialize();
@@ -90,18 +90,31 @@
+ path, "xyz.openbmc_project.Inventory.Item.StorageControllerSecurity");
+ securityInterface->register_method(
+ "SecuritySend",
-+ [self{shared_from_this()}](boost::asio::yield_context yield,
-+ uint8_t proto, uint16_t proto_specific,
-+ std::vector<uint8_t> data) {
-+ return self->securitySendMethod(yield, proto, proto_specific, data);
++ [selfWeak{weak_from_this()}](boost::asio::yield_context yield,
++ uint8_t proto, uint16_t proto_specific,
++ std::vector<uint8_t> data) {
++ if (selfWeak.expired())
++ {
++ checkLibNVMeError(std::make_error_code(std::errc::no_such_device),
++ -1, "SecuritySend");
++ return;
++ }
++ return selfWeak.lock()->securitySendMethod(yield, proto, proto_specific,
++ data);
+ });
+ securityInterface->register_method(
+ "SecurityReceive",
-+ [self{shared_from_this()}](boost::asio::yield_context yield,
-+ uint8_t proto, uint16_t proto_specific,
-+ uint32_t transfer_length) {
-+ return self->securityReceiveMethod(yield, proto, proto_specific,
-+ transfer_length);
++ [selfWeak{weak_from_this()}](boost::asio::yield_context yield,
++ uint8_t proto, uint16_t proto_specific,
++ uint32_t transfer_length) {
++ if (selfWeak.expired())
++ {
++ checkLibNVMeError(std::make_error_code(std::errc::no_such_device),
++ -1, "SecurityReceive");
++ return std::vector<uint8_t>{};
++ }
++ return selfWeak.lock()->securityReceiveMethod(
++ yield, proto, proto_specific, transfer_length);
+ });
+
+ securityInterface->initialize();
@@ -109,7 +122,7 @@
StorageController::emit_added();
NVMeAdmin::emit_added();
}
-@@ -246,6 +269,7 @@ void NVMeControllerEnabled::firmwareCommitAsync(uint8_t commitAction,
+@@ -246,6 +282,7 @@ void NVMeControllerEnabled::firmwareCommitAsync(uint8_t commitAction,
NVMeControllerEnabled::~NVMeControllerEnabled()
{
@@ -117,7 +130,7 @@
NVMeAdmin::emit_removed();
StorageController::emit_removed();
}
-@@ -321,3 +345,113 @@ void NVMeController::addSubsystemAssociation(const std::string& subsysPath)
+@@ -321,3 +358,113 @@ void NVMeController::addSubsystemAssociation(const std::string& subsysPath)
assocIntf->set_property("Associations", associations);
}
}
@@ -269,10 +282,10 @@
+
};
diff --git a/src/NVMeIntf.hpp b/src/NVMeIntf.hpp
-index e7ba3cf..fc8776d 100644
+index f87b536..3a2fa32 100644
--- a/src/NVMeIntf.hpp
+++ b/src/NVMeIntf.hpp
-@@ -120,6 +120,17 @@ class NVMeMiIntf : public NVMeIntf
+@@ -184,6 +184,17 @@ class NVMeMiIntf
std::function<void(const std::error_code&,
nvme_status_field)>&& cb) = 0;
@@ -291,7 +304,7 @@
* adminXfer() - Raw admin transfer interface.
* @ctrl: controller to send the admin command to
diff --git a/src/NVMeMi.cpp b/src/NVMeMi.cpp
-index 59ba3a5..fabc0b5 100644
+index 28d864e..2cdf1d6 100644
--- a/src/NVMeMi.cpp
+++ b/src/NVMeMi.cpp
@@ -12,6 +12,8 @@ std::map<int, std::weak_ptr<NVMeMi::Worker>> NVMeMi::workerMap{};
@@ -301,9 +314,9 @@
+constexpr size_t maxNVMeMILength = 4096;
+
NVMeMi::NVMeMi(boost::asio::io_context& io, sdbusplus::bus_t& dbus, int bus,
- int addr) :
+ int addr, bool singleThreadMode) :
io(io),
-@@ -146,6 +148,21 @@ void NVMeMi::Worker::post(std::function<void(void)>&& func)
+@@ -153,6 +155,21 @@ void NVMeMi::Worker::post(std::function<void(void)>&& func)
throw std::runtime_error("NVMeMi has been stopped");
}
@@ -325,7 +338,7 @@
void NVMeMi::miSubsystemHealthStatusPoll(
std::function<void(const std::error_code&, nvme_mi_nvm_ss_health_status*)>&&
cb)
-@@ -792,3 +809,88 @@ void NVMeMi::adminFwCommit(
+@@ -799,3 +816,88 @@ void NVMeMi::adminFwCommit(
return;
}
}
@@ -415,7 +428,7 @@
+ }
+}
diff --git a/src/NVMeMi.hpp b/src/NVMeMi.hpp
-index 3071596..6a57b6e 100644
+index 4f1a483..2aa6636 100644
--- a/src/NVMeMi.hpp
+++ b/src/NVMeMi.hpp
@@ -46,6 +46,17 @@ class NVMeMi : public NVMeMiIntf, public std::enable_shared_from_this<NVMeMi>
diff --git a/recipes-phosphor/sensors/dbus-sensors/0031-nvmesensor-set-default-timeout-to-20-seconds-for-Sec.patch b/recipes-phosphor/sensors/dbus-sensors/0036-nvmesensor-set-default-timeout-to-20-seconds-for-Sec.patch
similarity index 86%
rename from recipes-phosphor/sensors/dbus-sensors/0031-nvmesensor-set-default-timeout-to-20-seconds-for-Sec.patch
rename to recipes-phosphor/sensors/dbus-sensors/0036-nvmesensor-set-default-timeout-to-20-seconds-for-Sec.patch
index df23f7a..46e15e3 100644
--- a/recipes-phosphor/sensors/dbus-sensors/0031-nvmesensor-set-default-timeout-to-20-seconds-for-Sec.patch
+++ b/recipes-phosphor/sensors/dbus-sensors/0036-nvmesensor-set-default-timeout-to-20-seconds-for-Sec.patch
@@ -1,7 +1,7 @@
-From 46da5fcb52c7751d0ec8bde97e8f8295af0bdddb Mon Sep 17 00:00:00 2001
+From 132f082370706d00b74e99ebbb78342f7be200a0 Mon Sep 17 00:00:00 2001
From: Jinliang Wang <jinliangw@google.com>
Date: Tue, 18 Apr 2023 16:18:37 -0700
-Subject: [PATCH 31/34] nvmesensor: set default timeout to 20 seconds for
+Subject: [PATCH 36/44] nvmesensor: set default timeout to 20 seconds for
Security Send and Receive
TCG commands (through Security Send and Receive) may take quite long to
@@ -15,7 +15,7 @@
1 file changed, 9 insertions(+)
diff --git a/src/NVMeMi.cpp b/src/NVMeMi.cpp
-index 8f73aed..106413d 100644
+index 2cdf1d6..6b93191 100644
--- a/src/NVMeMi.cpp
+++ b/src/NVMeMi.cpp
@@ -13,6 +13,7 @@ std::map<int, std::weak_ptr<NVMeMi::Worker>> NVMeMi::workerMap{};
@@ -25,8 +25,8 @@
+constexpr int tcgDefaultTimeoutMS = 20*1000;
NVMeMi::NVMeMi(boost::asio::io_context& io, sdbusplus::bus_t& dbus, int bus,
- int addr) :
-@@ -804,7 +805,11 @@ void NVMeMi::adminSecuritySend(
+ int addr, bool singleThreadMode) :
+@@ -835,7 +836,11 @@ void NVMeMi::adminSecuritySend(
args.data_len = data.size_bytes();
args.args_size = sizeof(struct nvme_security_send_args);
@@ -38,7 +38,7 @@
self->io.post([cb{std::move(cb)}, nvme_errno{errno}, status]() {
auto err = std::make_error_code(static_cast<std::errc>(nvme_errno));
cb(err, status);
-@@ -844,7 +849,11 @@ void NVMeMi::adminSecurityReceive(
+@@ -875,7 +880,11 @@ void NVMeMi::adminSecurityReceive(
args.data_len = data.size();
args.args_size = sizeof(struct nvme_security_receive_args);
diff --git a/recipes-phosphor/sensors/dbus-sensors/0032-nvmesensor-close-pipe-file-descriptor-before-excepti.patch b/recipes-phosphor/sensors/dbus-sensors/0037-nvmesensor-close-pipe-file-descriptor-before-excepti.patch
similarity index 82%
rename from recipes-phosphor/sensors/dbus-sensors/0032-nvmesensor-close-pipe-file-descriptor-before-excepti.patch
rename to recipes-phosphor/sensors/dbus-sensors/0037-nvmesensor-close-pipe-file-descriptor-before-excepti.patch
index fd36056..1526390 100644
--- a/recipes-phosphor/sensors/dbus-sensors/0032-nvmesensor-close-pipe-file-descriptor-before-excepti.patch
+++ b/recipes-phosphor/sensors/dbus-sensors/0037-nvmesensor-close-pipe-file-descriptor-before-excepti.patch
@@ -1,7 +1,7 @@
-From 0636c36ff896efde95a0f17fcf39b034e0dadfbd Mon Sep 17 00:00:00 2001
+From 5876fc43d78c6210c4e56bc1c87344cf4ab76a9f Mon Sep 17 00:00:00 2001
From: Jinliang Wang <jinliangw@google.com>
Date: Tue, 18 Apr 2023 16:24:38 -0700
-Subject: [PATCH 32/34] nvmesensor: close pipe file descriptor before exception
+Subject: [PATCH 37/44] nvmesensor: close pipe file descriptor before exception
Close pipe file descriptors before throwing exception to prevent
the potential leak of file desctriptor.
@@ -13,10 +13,10 @@
1 file changed, 4 insertions(+)
diff --git a/src/NVMeController.cpp b/src/NVMeController.cpp
-index 1c34a58..d534532 100644
+index 5553859..1297bb4 100644
--- a/src/NVMeController.cpp
+++ b/src/NVMeController.cpp
-@@ -180,12 +180,16 @@ sdbusplus::message::unix_fd NVMeControllerEnabled::getLogPage(uint8_t lid,
+@@ -193,12 +193,16 @@ sdbusplus::message::unix_fd NVMeControllerEnabled::getLogPage(uint8_t lid,
}
else // No VU LogPage handler
{
diff --git a/recipes-phosphor/sensors/dbus-sensors/0038-nvmesensor-add-Mock-and-Fake-for-SecuSend-Recv.patch b/recipes-phosphor/sensors/dbus-sensors/0038-nvmesensor-add-Mock-and-Fake-for-SecuSend-Recv.patch
new file mode 100644
index 0000000..7017620
--- /dev/null
+++ b/recipes-phosphor/sensors/dbus-sensors/0038-nvmesensor-add-Mock-and-Fake-for-SecuSend-Recv.patch
@@ -0,0 +1,78 @@
+From db1a16ddc6aa943c3b71ab529400cb54c418e44b Mon Sep 17 00:00:00 2001
+From: Hao Jiang <jianghao@google.com>
+Date: Wed, 3 May 2023 01:20:14 +0000
+Subject: [PATCH 38/44] nvmesensor: add Mock and Fake for SecuSend/Recv
+
+Signed-off-by: Hao Jiang <jianghao@google.com>
+Change-Id: Ia990447360e39e10932170dc63086b7f301844a5
+---
+ src/NVMeMiFake.hpp | 19 +++++++++++++++++++
+ tests/test_nvme_mi.cpp | 15 +++++++++++++++
+ 2 files changed, 34 insertions(+)
+
+diff --git a/src/NVMeMiFake.hpp b/src/NVMeMiFake.hpp
+index 05eafed..989649e 100644
+--- a/src/NVMeMiFake.hpp
++++ b/src/NVMeMiFake.hpp
+@@ -415,6 +415,25 @@ class NVMeMiFake :
+ }
+ }
+
++ void adminSecuritySend(
++ [[maybe_unused]] nvme_mi_ctrl_t ctrl, [[maybe_unused]] uint8_t proto,
++ [[maybe_unused]] uint16_t proto_specific,
++ [[maybe_unused]] std::span<uint8_t> data,
++ std::function<void(const std::error_code&, int nvme_status)>&& cb)
++ override
++ {
++ cb(std::make_error_code(std::errc::not_supported), 0);
++ }
++ void adminSecurityReceive(
++ [[maybe_unused]] nvme_mi_ctrl_t ctrl, [[maybe_unused]] uint8_t proto,
++ [[maybe_unused]] uint16_t proto_specific,
++ [[maybe_unused]] uint32_t transfer_length,
++ std::function<void(const std::error_code&, int nvme_status,
++ const std::span<uint8_t> data)>&& cb) override
++ {
++ cb(std::make_error_code(std::errc::not_supported), 0, {});
++ }
++
+ private:
+ boost::asio::io_context& io;
+ bool valid = false;
+diff --git a/tests/test_nvme_mi.cpp b/tests/test_nvme_mi.cpp
+index 8462d5e..ca3bb15 100644
+--- a/tests/test_nvme_mi.cpp
++++ b/tests/test_nvme_mi.cpp
+@@ -65,6 +65,8 @@ class NVMeMiMock :
+ return fake->adminXfer(ctrl, admin_req, data, timeout_ms,
+ std::move(cb));
+ });
++ ON_CALL(*this, adminSecuritySend).WillByDefault([]() { return; });
++ ON_CALL(*this, adminSecurityReceive).WillByDefault([]() { return; });
+ }
+
+ MOCK_METHOD(int, getNID, (), (const override));
+@@ -102,6 +104,19 @@ class NVMeMiMock :
+ std::span<uint8_t> resp_data)>&& cb),
+ (override));
+
++ MOCK_METHOD(
++ void, adminSecuritySend,
++ (nvme_mi_ctrl_t ctrl, uint8_t proto, uint16_t proto_specific,
++ std::span<uint8_t> data,
++ std::function<void(const std::error_code&, int nvme_status)>&& cb),
++ (override));
++ MOCK_METHOD(void, adminSecurityReceive,
++ (nvme_mi_ctrl_t ctrl, uint8_t proto, uint16_t proto_specific,
++ uint32_t transfer_length,
++ std::function<void(const std::error_code&, int nvme_status,
++ const std::span<uint8_t> data)>&& cb),
++ (override));
++
+ std::shared_ptr<NVMeMiFake> fake;
+ };
+
+--
+2.34.1
+
diff --git a/recipes-phosphor/sensors/dbus-sensors/0039-utils-add-PowerCallbackEntry-for-PowerMatch.patch b/recipes-phosphor/sensors/dbus-sensors/0039-utils-add-PowerCallbackEntry-for-PowerMatch.patch
new file mode 100644
index 0000000..336e45b
--- /dev/null
+++ b/recipes-phosphor/sensors/dbus-sensors/0039-utils-add-PowerCallbackEntry-for-PowerMatch.patch
@@ -0,0 +1,250 @@
+From 72cd17a9c6c747cf45dc7ca4946c489113c6e2c5 Mon Sep 17 00:00:00 2001
+From: Hao Jiang <jianghao@google.com>
+Date: Mon, 1 May 2023 21:00:27 +0000
+Subject: [PATCH 39/44] utils: add PowerCallbackEntry for PowerMatch
+
+The PowerMatch callback could be different from intances. For example,
+some nvme vendor links the OOB connectivity to inband Host signal,
+nevertheless other vendor has abolute independent inband and oob
+NVMe connectivity. Thus requires mulitple callback funcitons for
+PowerMatch.
+
+PowerCallbackEntry is the class to manage the callback functions to
+PowerMatch. It is created from setupPowerMatchCallback and unregister
+itself upon deconstruction.
+
+This class is not thread-safe so it should be managed within a single
+thread.
+
+Signed-off-by: Hao Jiang <jianghao@google.com>
+Change-Id: Id33a9c18c18168258c3dfda95db6fed56953bd01
+---
+ src/HwmonTempMain.cpp | 2 +-
+ src/Utils.cpp | 62 +++++++++++++++++++++++++++++++++----------
+ src/Utils.hpp | 36 ++++++++++++++++++++++++-
+ 3 files changed, 84 insertions(+), 16 deletions(-)
+
+diff --git a/src/HwmonTempMain.cpp b/src/HwmonTempMain.cpp
+index 340bf11..da26196 100644
+--- a/src/HwmonTempMain.cpp
++++ b/src/HwmonTempMain.cpp
+@@ -661,7 +661,7 @@ int main()
+ &systemBus](PowerState type, bool state) {
+ powerStateChanged(type, state, sensors, io, objectServer, systemBus);
+ };
+- setupPowerMatchCallback(systemBus, powerCallBack);
++ auto powerCallBackEntry = setupPowerMatchCallback(systemBus, powerCallBack);
+
+ boost::asio::post(io, [&]() {
+ createSensors(io, objectServer, sensors, systemBus, nullptr, false);
+diff --git a/src/Utils.cpp b/src/Utils.cpp
+index d659d37..866f05b 100644
+--- a/src/Utils.cpp
++++ b/src/Utils.cpp
+@@ -46,6 +46,8 @@ static std::unique_ptr<sdbusplus::bus::match_t> powerMatch = nullptr;
+ static std::unique_ptr<sdbusplus::bus::match_t> postMatch = nullptr;
+ static std::unique_ptr<sdbusplus::bus::match_t> chassisMatch = nullptr;
+
++std::list<PowerCallbackEntry::callback_t> PowerCallbackEntry::list;
++
+ /**
+ * return the contents of a file
+ * @param[in] hwmonFile - the path to the file to read
+@@ -433,17 +435,20 @@ static void
+ chassis::interface, chassis::property);
+ }
+
+-void setupPowerMatchCallback(
++std::unique_ptr<PowerCallbackEntry> setupPowerMatchCallback(
+ const std::shared_ptr<sdbusplus::asio::connection>& conn,
+ std::function<void(PowerState type, bool state)>&& hostStatusCallback)
+ {
+ static boost::asio::steady_timer timer(conn->get_io_context());
+ static boost::asio::steady_timer timerChassisOn(conn->get_io_context());
++
++ auto entry = std::make_unique<PowerCallbackEntry>(std::move(hostStatusCallback));
++
+ // create a match for powergood changes, first time do a method call to
+ // cache the correct value
+ if (powerMatch)
+ {
+- return;
++ return entry;
+ }
+
+ powerMatch = std::make_unique<sdbusplus::bus::match_t>(
+@@ -451,7 +456,7 @@ void setupPowerMatchCallback(
+ "type='signal',interface='" + std::string(properties::interface) +
+ "',path='" + std::string(power::path) + "',arg0='" +
+ std::string(power::interface) + "'",
+- [hostStatusCallback](sdbusplus::message_t& message) {
++ [](sdbusplus::message_t& message) {
+ std::string objectName;
+ boost::container::flat_map<std::string, std::variant<std::string>>
+ values;
+@@ -465,13 +470,18 @@ void setupPowerMatchCallback(
+ {
+ timer.cancel();
+ powerStatusOn = false;
+- hostStatusCallback(PowerState::on, powerStatusOn);
++ for (const auto& cb : PowerCallbackEntry::list)
++ {
++ if (cb)
++ {
++ cb(PowerState::on, powerStatusOn);
++ }
++ }
+ return;
+ }
+ // on comes too quickly
+ timer.expires_after(std::chrono::seconds(10));
+- timer.async_wait(
+- [hostStatusCallback](boost::system::error_code ec) {
++ timer.async_wait([](boost::system::error_code ec) {
+ if (ec == boost::asio::error::operation_aborted)
+ {
+ return;
+@@ -482,7 +492,13 @@ void setupPowerMatchCallback(
+ return;
+ }
+ powerStatusOn = true;
+- hostStatusCallback(PowerState::on, powerStatusOn);
++ for (const auto& cb : PowerCallbackEntry::list)
++ {
++ if (cb)
++ {
++ cb(PowerState::on, powerStatusOn);
++ }
++ }
+ });
+ }
+ });
+@@ -492,7 +508,7 @@ void setupPowerMatchCallback(
+ "type='signal',interface='" + std::string(properties::interface) +
+ "',path='" + std::string(post::path) + "',arg0='" +
+ std::string(post::interface) + "'",
+- [hostStatusCallback](sdbusplus::message_t& message) {
++ [](sdbusplus::message_t& message) {
+ std::string objectName;
+ boost::container::flat_map<std::string, std::variant<std::string>>
+ values;
+@@ -504,7 +520,13 @@ void setupPowerMatchCallback(
+ biosHasPost = (value != "Inactive") &&
+ (value != "xyz.openbmc_project.State.OperatingSystem."
+ "Status.OSStatus.Inactive");
+- hostStatusCallback(PowerState::biosPost, biosHasPost);
++ for (const auto& cb : PowerCallbackEntry::list)
++ {
++ if (cb)
++ {
++ cb(PowerState::biosPost, biosHasPost);
++ }
++ }
+ }
+ });
+
+@@ -513,7 +535,7 @@ void setupPowerMatchCallback(
+ "type='signal',interface='" + std::string(properties::interface) +
+ "',path='" + std::string(chassis::path) + "',arg0='" +
+ std::string(chassis::interface) + "'",
+- [hostStatusCallback](sdbusplus::message_t& message) {
++ [](sdbusplus::message_t& message) {
+ std::string objectName;
+ boost::container::flat_map<std::string, std::variant<std::string>>
+ values;
+@@ -527,13 +549,18 @@ void setupPowerMatchCallback(
+ {
+ timerChassisOn.cancel();
+ chassisStatusOn = false;
+- hostStatusCallback(PowerState::chassisOn, chassisStatusOn);
++ for (const auto& cb : PowerCallbackEntry::list)
++ {
++ if (cb)
++ {
++ cb(PowerState::chassisOn, chassisStatusOn);
++ }
++ }
+ return;
+ }
+ // on comes too quickly
+ timerChassisOn.expires_after(std::chrono::seconds(10));
+- timerChassisOn.async_wait(
+- [hostStatusCallback](boost::system::error_code ec) {
++ timerChassisOn.async_wait([](boost::system::error_code ec) {
+ if (ec == boost::asio::error::operation_aborted)
+ {
+ return;
+@@ -544,13 +571,20 @@ void setupPowerMatchCallback(
+ return;
+ }
+ chassisStatusOn = true;
+- hostStatusCallback(PowerState::chassisOn, chassisStatusOn);
++ for (const auto& cb : PowerCallbackEntry::list)
++ {
++ if (cb)
++ {
++ cb(PowerState::chassisOn, chassisStatusOn);
++ }
++ }
+ });
+ }
+ });
+ getPowerStatus(conn);
+ getPostStatus(conn);
+ getChassisStatus(conn);
++ return entry;
+ }
+
+ void setupPowerMatch(const std::shared_ptr<sdbusplus::asio::connection>& conn)
+diff --git a/src/Utils.hpp b/src/Utils.hpp
+index 444030c..ea4c241 100644
+--- a/src/Utils.hpp
++++ b/src/Utils.hpp
+@@ -71,9 +71,43 @@ bool findFiles(const std::filesystem::path& dirPath,
+ bool isPowerOn(void);
+ bool hasBiosPost(void);
+ bool isChassisOn(void);
+-void setupPowerMatchCallback(
++
++class PowerCallbackEntry;
++
++std::unique_ptr<PowerCallbackEntry> setupPowerMatchCallback(
+ const std::shared_ptr<sdbusplus::asio::connection>& conn,
+ std::function<void(PowerState type, bool state)>&& callback);
++class PowerCallbackEntry
++{
++ public:
++ using callback_t = std::function<void(PowerState type, bool state)>;
++
++ PowerCallbackEntry()
++ {
++ current = list.insert(list.end(), callback_t{});
++ }
++
++ PowerCallbackEntry(const PowerCallbackEntry&) = delete;
++
++ explicit PowerCallbackEntry(callback_t&& cb)
++ {
++ current = list.insert(list.end(), std::move(cb));
++ }
++
++ ~PowerCallbackEntry()
++ {
++ list.erase(current);
++ }
++
++ private:
++ friend std::unique_ptr<PowerCallbackEntry> setupPowerMatchCallback(
++ const std::shared_ptr<sdbusplus::asio::connection>& conn,
++ std::function<void(PowerState type, bool state)>&& callback);
++
++ static std::list<callback_t> list;
++ decltype(list)::iterator current;
++};
++
+ void setupPowerMatch(const std::shared_ptr<sdbusplus::asio::connection>& conn);
+ bool getSensorConfiguration(
+ const std::string& type,
+--
+2.34.1
+
diff --git a/recipes-phosphor/sensors/dbus-sensors/0040-nvmesensor-add-PowerState-to-NVMeMi.patch b/recipes-phosphor/sensors/dbus-sensors/0040-nvmesensor-add-PowerState-to-NVMeMi.patch
new file mode 100644
index 0000000..c0f61db
--- /dev/null
+++ b/recipes-phosphor/sensors/dbus-sensors/0040-nvmesensor-add-PowerState-to-NVMeMi.patch
@@ -0,0 +1,347 @@
+From f13c93e13c8676066fed10c2f122c9923077f39e Mon Sep 17 00:00:00 2001
+From: Hao Jiang <jianghao@google.com>
+Date: Mon, 1 May 2023 21:13:20 +0000
+Subject: [PATCH 40/44] nvmesensor: add PowerState to NVMeMi
+
+Some NVMe vendor implementation link the OOB NVMe-MI connectivity to the
+inband signal. For example, there will be MCTP level reset when inband
+PERST is issued.
+
+The proposed solution is to NVMeMi will close the MCTP ep upon
+PowerState down, and re-init the MCTP when PowerState comes back up.
+
+Configuration for PowerState of each NVMeMi MCTP endpoint is via E-M
+configuration of "PowerState". The default value is always, and the
+configu value is case insensitive.
+
+Signed-off-by: Hao Jiang <jianghao@google.com>
+Change-Id: I7e4c84415fb3568226bc51a03279aeec32a5c612
+---
+ src/NVMeMi.cpp | 111 +++++++++++++++++++++++++++++++++++------
+ src/NVMeMi.hpp | 31 ++++++++++--
+ src/NVMeSensorMain.cpp | 48 +++++++++++++++++-
+ 3 files changed, 169 insertions(+), 21 deletions(-)
+
+diff --git a/src/NVMeMi.cpp b/src/NVMeMi.cpp
+index 6b93191..4f0ef12 100644
+--- a/src/NVMeMi.cpp
++++ b/src/NVMeMi.cpp
+@@ -15,11 +15,19 @@ nvme_root_t NVMeMi::nvmeRoot = nvme_mi_create_root(stderr, DEFAULT_LOGLEVEL);
+ constexpr size_t maxNVMeMILength = 4096;
+ constexpr int tcgDefaultTimeoutMS = 20*1000;
+
+-NVMeMi::NVMeMi(boost::asio::io_context& io, sdbusplus::bus_t& dbus, int bus,
+- int addr, bool singleThreadMode) :
++NVMeMi::NVMeMi(boost::asio::io_context& io,
++ std::shared_ptr<sdbusplus::asio::connection> conn, int bus,
++ int addr, bool singleThreadMode, PowerState readState) :
+ io(io),
+- dbus(dbus)
++ conn(conn), dbus(*conn.get()), bus(bus), addr(addr), readState(readState)
+ {
++ // reset to unassigned nid/eid and endpoint
++ nid = -1;
++ eid = 0;
++ mctpPath.erase();
++ nvmeEP = nullptr;
++
++ // set update the worker thread
+ if (!nvmeRoot)
+ {
+ throw std::runtime_error("invalid NVMe root");
+@@ -51,7 +59,38 @@ NVMeMi::NVMeMi(boost::asio::io_context& io, sdbusplus::bus_t& dbus, int bus,
+ worker = std::make_shared<Worker>();
+ }
+
++ // setup the power state
++ if (readState == PowerState::on || readState == PowerState::biosPost ||
++ readState == PowerState::chassisOn)
++ {
++ // life time of the callback is binding to the NVMeMi instance, so only
++ // this capture is required.
++ powerCallback = setupPowerMatchCallback(conn, [this](PowerState, bool) {
++ if (::readingStateGood(this->readState))
++ {
++ initMCTP();
++ }
++ else
++ {
++ closeMCTP();
++ }
++ });
++ }
++
++ // TODO: check the powerstate.
++ initMCTP();
++}
++
++void NVMeMi::initMCTP()
++{
++ // already initiated
++ if (isMCTPconnect())
++ {
++ return;
++ }
++
+ // init mctp ep via mctpd
++ std::unique_lock<std::mutex> lock(mctpMtx);
+ int i = 0;
+ for (;; i++)
+ {
+@@ -79,19 +118,58 @@ NVMeMi::NVMeMi(boost::asio::io_context& io, sdbusplus::bus_t& dbus, int bus,
+ }
+ else
+ {
+- throw std::runtime_error(e.what());
++ nid = -1;
++ eid = 0;
++ mctpPath.erase();
++ nvmeEP = nullptr;
++ std::cerr << "fail to init MCTP endpoint: " << e.what()
++ << std::endl;
++ return;
+ }
+ }
+ }
+
+ // open mctp endpoint
+ nvmeEP = nvme_mi_open_mctp(nvmeRoot, nid, eid);
+- if (!nvmeEP)
++ if (nvmeEP == nullptr)
++ {
++ nid = -1;
++ eid = 0;
++ // MCTPd won't expect to delete the ep object, just to erase the record
++ // here.
++ mctpPath.erase();
++ nvmeEP = nullptr;
++ std::cerr << "can't open MCTP endpoint "
++ << std::to_string(nid) + ":" + std::to_string(eid)
++ << std::endl;
++ }
++}
++
++void NVMeMi::closeMCTP()
++{
++ // MCTP is disconnected
++ if (!isMCTPconnect())
+ {
+- throw std::runtime_error("can't open MCTP endpoint " +
+- std::to_string(nid) + ":" +
+- std::to_string(eid));
++ return;
+ }
++ // each nvme mi message transaction should take relatively short time
++ // (typically <= 200 ms). So the blocking time should be short
++ std::unique_lock<std::mutex> lock(mctpMtx);
++
++ nvme_mi_close(nvmeEP);
++
++ // Note: No need to remove MCTP ep from MCTPd since the routing table will
++ // re-establish on the next init
++
++ nid = -1;
++ eid = 0;
++ mctpPath.erase();
++ nvmeEP = nullptr;
++}
++
++bool NVMeMi::isMCTPconnect() const
++{
++ return nid >= 0 && !mctpPath.empty() && nvmeEP != nullptr;
+ }
+
+ NVMeMi::Worker::Worker()
+@@ -132,13 +210,7 @@ NVMeMi::Worker::~Worker()
+ }
+ NVMeMi::~NVMeMi()
+ {
+- // close EP
+- if (nvmeEP)
+- {
+- nvme_mi_close(nvmeEP);
+- }
+-
+- // TODO: delete mctp ep from mctpd
++ closeMCTP();
+ }
+
+ void NVMeMi::Worker::post(std::function<void(void)>&& func)
+@@ -156,6 +228,15 @@ void NVMeMi::Worker::post(std::function<void(void)>&& func)
+ throw std::runtime_error("NVMeMi has been stopped");
+ }
+
++void NVMeMi::post(std::function<void(void)>&& func)
++{
++ worker->post(
++ [self{std::move(shared_from_this())}, func{std::move(func)}]() {
++ std::unique_lock<std::mutex> lock(self->mctpMtx);
++ func();
++ });
++}
++
+ // Calls .post(), catching runtime_error and returning an error code on failure.
+ std::error_code NVMeMi::try_post(std::function<void(void)>&& func)
+ {
+diff --git a/src/NVMeMi.hpp b/src/NVMeMi.hpp
+index 2aa6636..db91bfd 100644
+--- a/src/NVMeMi.hpp
++++ b/src/NVMeMi.hpp
+@@ -1,4 +1,5 @@
+ #include "NVMeIntf.hpp"
++#include "Utils.hpp"
+
+ #include <boost/asio.hpp>
+ #include <sdbusplus/bus.hpp>
+@@ -8,8 +9,9 @@
+ class NVMeMi : public NVMeMiIntf, public std::enable_shared_from_this<NVMeMi>
+ {
+ public:
+- NVMeMi(boost::asio::io_context& io, sdbusplus::bus_t& dbus, int bus,
+- int addr, bool singleThreadMode = false);
++ NVMeMi(boost::asio::io_context& io, std::shared_ptr<sdbusplus::asio::connection> conn, int bus,
++ int addr, bool singleThreadMode = false,
++ PowerState readState = PowerState::always);
+ ~NVMeMi() override;
+
+ int getNID() const override
+@@ -65,13 +67,26 @@ class NVMeMi : public NVMeMiIntf, public std::enable_shared_from_this<NVMeMi>
+ static nvme_root_t nvmeRoot;
+
+ boost::asio::io_context& io;
++ std::shared_ptr<sdbusplus::asio::connection> conn;
+ sdbusplus::bus_t& dbus;
++
++ // I2C info
++ int bus;
++ int addr;
++
++ // power state
++ std::unique_ptr<PowerCallbackEntry> powerCallback;
++ PowerState readState;
++
++ // mctp connection
+ nvme_mi_ep_t nvmeEP;
+
+ int nid;
+ uint8_t eid;
+ std::string mctpPath;
+
++ std::mutex mctpMtx;
++
+ // A worker thread for calling NVMeMI cmd.
+ class Worker
+ {
+@@ -98,9 +113,17 @@ class NVMeMi : public NVMeMiIntf, public std::enable_shared_from_this<NVMeMi>
+ static std::map<int, std::weak_ptr<Worker>> workerMap;
+
+ std::shared_ptr<Worker> worker;
+- void post(std::function<void(void)>&& func)
++ void post(std::function<void(void)>&& func);
++
++ void initMCTP();
++
++ void closeMCTP();
++
++ bool isMCTPconnect() const;
++
++ bool readingStateGood() const
+ {
+- worker->post(std::move(func));
++ return isMCTPconnect() && ::readingStateGood(readState);
+ }
+
+ std::error_code try_post(std::function<void(void)>&& func);
+diff --git a/src/NVMeSensorMain.cpp b/src/NVMeSensorMain.cpp
+index 950988d..d6612f6 100644
+--- a/src/NVMeSensorMain.cpp
++++ b/src/NVMeSensorMain.cpp
+@@ -18,6 +18,7 @@
+ #include "NVMeMi.hpp"
+ #include "NVMeSubsys.hpp"
+
++#include <boost/algorithm/string.hpp>
+ #include <boost/asio/steady_timer.hpp>
+
+ #include <optional>
+@@ -27,6 +28,9 @@
+ using NVMEMap = std::map<std::string, std::shared_ptr<NVMeSubsystem>>;
+ static NVMEMap nvmeSubsysMap;
+
++// flag to set a single worker thread for all nvme eps under the same i2c bus
++static bool singleThreadMode = false;
++
+ static std::optional<int>
+ extractBusNumber(const std::string& path,
+ const SensorBaseConfigMap& properties)
+@@ -81,6 +85,40 @@ static std::optional<std::string>
+ return std::get<std::string>(findProtocol->second);
+ }
+
++static PowerState extractPowerState(const std::string& path,
++ const SensorBaseConfigMap& properties)
++{
++ auto find = properties.find("PowerState");
++ if (find == properties.end())
++ {
++ std::cerr << "could not determine configuration of PowerState for "
++ << path << ", using default\n";
++ // default to always
++ return PowerState::always;
++ }
++ auto res = std::get<std::string>(find->second);
++ if (boost::iequals(res, "on"))
++ {
++ return PowerState::on;
++ }
++ else if (boost::iequals(res, "biosPost"))
++ {
++ return PowerState::biosPost;
++ }
++ else if (boost::iequals(res, "always"))
++ {
++ return PowerState::always;
++ }
++ else if (boost::iequals(res, "chassisOn"))
++ {
++ return PowerState::chassisOn;
++ }
++ // default to always
++ std::cerr << "could not determine config value for PowerState for " << path
++ << ", using default\n";
++ return PowerState::always;
++}
++
+ static void handleConfigurations(
+ boost::asio::io_context& io, sdbusplus::asio::object_server& objectServer,
+ std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
+@@ -164,11 +202,15 @@ static void handleConfigurations(
+ {
+ address.emplace(0x1d);
+ }
++
++ PowerState powerState =
++ extractPowerState(interfacePath, sensorConfig);
++
+ try
+ {
+ NVMeIntf nvmeMi = NVMeIntf::create<NVMeMi>(
+- io, dynamic_cast<sdbusplus::bus_t&>(*dbusConnection),
+- *busNumber, *address);
++ io, dbusConnection, *busNumber, *address, singleThreadMode,
++ powerState);
+
+ nvmeInterfaces.emplace(interfacePath, nvmeMi);
+ }
+@@ -265,6 +307,8 @@ static void interfaceRemoved(sdbusplus::message_t& message, NVMEMap& subsystems)
+
+ int main()
+ {
++ // TODO: set single thread mode according to input parameters
++
+ boost::asio::io_context io;
+ auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
+ systemBus->request_name("xyz.openbmc_project.NVMe");
+--
+2.34.1
+
diff --git a/recipes-phosphor/sensors/dbus-sensors/0041-nvmesensor-Add-print-info-to-NVMeMi.patch b/recipes-phosphor/sensors/dbus-sensors/0041-nvmesensor-Add-print-info-to-NVMeMi.patch
new file mode 100644
index 0000000..bac9f1a
--- /dev/null
+++ b/recipes-phosphor/sensors/dbus-sensors/0041-nvmesensor-Add-print-info-to-NVMeMi.patch
@@ -0,0 +1,482 @@
+From 4bc12cf43841e886b813c039eae9281259fdb3e6 Mon Sep 17 00:00:00 2001
+From: Hao Jiang <jianghao@google.com>
+Date: Tue, 2 May 2023 18:41:24 +0000
+Subject: [PATCH 41/44] nvmesensor: Add print info to NVMeMi
+
+The print info will include the MCTP information so it will be easier to
+debug which MCTP ep NVMe-MI node prints these information.
+
+Signed-off-by: Hao Jiang <jianghao@google.com>
+Change-Id: I9be103b53ed76d33c2185323df60310b877ef557
+---
+ src/NVMeMi.cpp | 175 ++++++++++++++++++++++++++++++++++++-------------
+ 1 file changed, 131 insertions(+), 44 deletions(-)
+
+diff --git a/src/NVMeMi.cpp b/src/NVMeMi.cpp
+index 4f0ef12..10d57a3 100644
+--- a/src/NVMeMi.cpp
++++ b/src/NVMeMi.cpp
+@@ -91,6 +91,8 @@ void NVMeMi::initMCTP()
+
+ // init mctp ep via mctpd
+ std::unique_lock<std::mutex> lock(mctpMtx);
++ std::cerr << "[bus: " << bus << ", addr: " << addr << "]"
++ << "start MCTP initialization" << std::endl;
+ int i = 0;
+ for (;; i++)
+ {
+@@ -113,7 +115,8 @@ void NVMeMi::initMCTP()
+ {
+ if (i < 5)
+ {
+- std::cerr << "retry to SetupEndpoint: " << e.what()
++ std::cerr << "[bus: " << bus << ", addr: " << addr << "]"
++ << "retry to SetupEndpoint: " << e.what()
+ << std::endl;
+ }
+ else
+@@ -122,7 +125,8 @@ void NVMeMi::initMCTP()
+ eid = 0;
+ mctpPath.erase();
+ nvmeEP = nullptr;
+- std::cerr << "fail to init MCTP endpoint: " << e.what()
++ std::cerr << "[bus: " << bus << ", addr: " << addr << "]"
++ << "fail to init MCTP endpoint: " << e.what()
+ << std::endl;
+ return;
+ }
+@@ -139,15 +143,18 @@ void NVMeMi::initMCTP()
+ // here.
+ mctpPath.erase();
+ nvmeEP = nullptr;
+- std::cerr << "can't open MCTP endpoint "
++ std::cerr << "[bus: " << bus << ", addr: " << addr << "]"
++ << "can't open MCTP endpoint "
+ << std::to_string(nid) + ":" + std::to_string(eid)
+ << std::endl;
+ }
++ std::cerr << "[bus: " << bus << ", addr: " << addr << "]"
++ << "finish MCTP initialization. "
++ << std::to_string(nid) + ":" + std::to_string(eid) << std::endl;
+ }
+
+ void NVMeMi::closeMCTP()
+ {
+- // MCTP is disconnected
+ if (!isMCTPconnect())
+ {
+ return;
+@@ -155,6 +162,8 @@ void NVMeMi::closeMCTP()
+ // each nvme mi message transaction should take relatively short time
+ // (typically <= 200 ms). So the blocking time should be short
+ std::unique_lock<std::mutex> lock(mctpMtx);
++ std::cerr << "[bus: " << bus << ", addr: " << addr << "]"
++ << "start MCTP closure" << std::endl;
+
+ nvme_mi_close(nvmeEP);
+
+@@ -165,6 +174,8 @@ void NVMeMi::closeMCTP()
+ eid = 0;
+ mctpPath.erase();
+ nvmeEP = nullptr;
++ std::cerr << "[bus: " << bus << ", addr: " << addr << "]"
++ << "finish MCTP closure." << std::endl;
+ }
+
+ bool NVMeMi::isMCTPconnect() const
+@@ -246,7 +257,9 @@ std::error_code NVMeMi::try_post(std::function<void(void)>&& func)
+ }
+ catch (const std::runtime_error& e)
+ {
+- std::cerr << e.what() << std::endl;
++ std::cerr << "[bus: " << bus << ", addr: " << addr
++ << ", eid: " << static_cast<int>(eid) << "]" << e.what()
++ << std::endl;
+ return std::make_error_code(std::errc::no_such_device);
+ }
+ return std::error_code();
+@@ -258,7 +271,9 @@ void NVMeMi::miSubsystemHealthStatusPoll(
+ {
+ if (!nvmeEP)
+ {
+- std::cerr << "nvme endpoint is invalid" << std::endl;
++ std::cerr << "[bus: " << bus << ", addr: " << addr
++ << ", eid: " << static_cast<int>(eid) << "]"
++ << "nvme endpoint is invalid" << std::endl;
+
+ io.post([cb{std::move(cb)}]() {
+ cb(std::make_error_code(std::errc::no_such_device), nullptr);
+@@ -275,7 +290,9 @@ void NVMeMi::miSubsystemHealthStatusPoll(
+ if (rc < 0)
+ {
+
+- std::cerr << "fail to subsystem_health_status_poll: "
++ std::cerr << "[bus: " << self->bus << ", addr: " << self->addr
++ << ", eid: " << static_cast<int>(self->eid) << "]"
++ << "fail to subsystem_health_status_poll: "
+ << std::strerror(errno) << std::endl;
+ self->io.post([cb{std::move(cb)}, last_errno{errno}]() {
+ cb(std::make_error_code(static_cast<std::errc>(last_errno)),
+@@ -287,7 +304,9 @@ void NVMeMi::miSubsystemHealthStatusPoll(
+ {
+ std::string_view errMsg =
+ statusToString(static_cast<nvme_mi_resp_status>(rc));
+- std::cerr << "fail to subsystem_health_status_poll: " << errMsg
++ std::cerr << "[bus: " << self->bus << ", addr: " << self->addr
++ << ", eid: " << static_cast<int>(self->eid) << "]"
++ << "fail to subsystem_health_status_poll: " << errMsg
+ << std::endl;
+ self->io.post([cb{std::move(cb)}]() {
+ cb(std::make_error_code(std::errc::bad_message), nullptr);
+@@ -303,7 +322,9 @@ void NVMeMi::miSubsystemHealthStatusPoll(
+ }
+ catch (const std::runtime_error& e)
+ {
+- std::cerr << e.what() << std::endl;
++ std::cerr << "[bus: " << bus << ", addr: " << addr
++ << ", eid: " << static_cast<int>(eid) << "]" << e.what()
++ << std::endl;
+ io.post([cb{std::move(cb)}]() {
+ cb(std::make_error_code(std::errc::no_such_device), {});
+ });
+@@ -331,7 +352,9 @@ void NVMeMi::miScanCtrl(std::function<void(const std::error_code&,
+ int rc = nvme_mi_scan_ep(self->nvmeEP, true);
+ if (rc < 0)
+ {
+- std::cerr << "fail to scan controllers: "
++ std::cerr << "[bus: " << self->bus << ", addr: " << self->addr
++ << ", eid: " << static_cast<int>(self->eid) << "]"
++ << "fail to scan controllers: "
+ << std::strerror(errno) << std::endl;
+ self->io.post([cb{std::move(cb)}, last_errno{errno}]() {
+ cb(std::make_error_code(static_cast<std::errc>(last_errno)), {});
+@@ -342,7 +365,9 @@ void NVMeMi::miScanCtrl(std::function<void(const std::error_code&,
+ {
+ std::string_view errMsg =
+ statusToString(static_cast<nvme_mi_resp_status>(rc));
+- std::cerr << "fail to scan controllers: " << errMsg
++ std::cerr << "[bus: " << self->bus << ", addr: " << self->addr
++ << ", eid: " << static_cast<int>(self->eid) << "]"
++ << "fail to scan controllers: " << errMsg
+ << std::endl;
+ self->io.post([cb{std::move(cb)}]() {
+ cb(std::make_error_code(std::errc::bad_message), {});
+@@ -362,7 +387,9 @@ void NVMeMi::miScanCtrl(std::function<void(const std::error_code&,
+ }
+ catch (const std::runtime_error& e)
+ {
+- std::cerr << e.what() << std::endl;
++ std::cerr << "[bus: " << bus << ", addr: " << addr
++ << ", eid: " << static_cast<int>(eid) << "]" << e.what()
++ << std::endl;
+ io.post([cb{std::move(cb)}]() {
+ cb(std::make_error_code(std::errc::no_such_device), {});
+ });
+@@ -431,7 +458,9 @@ void NVMeMi::adminIdentify(
+ }
+ if (rc < 0)
+ {
+- std::cerr << "fail to do nvme identify: "
++ std::cerr << "[bus: " << self->bus << ", addr: " << self->addr
++ << ", eid: " << static_cast<int>(self->eid) << "]"
++ << "fail to do nvme identify: "
+ << std::strerror(errno) << std::endl;
+ self->io.post([cb{std::move(cb)}, last_errno{errno}]() {
+ cb(std::make_error_code(static_cast<std::errc>(last_errno)), {});
+@@ -442,7 +471,9 @@ void NVMeMi::adminIdentify(
+ {
+ std::string_view errMsg =
+ statusToString(static_cast<nvme_mi_resp_status>(rc));
+- std::cerr << "fail to do nvme identify: " << errMsg
++ std::cerr << "[bus: " << self->bus << ", addr: " << self->addr
++ << ", eid: " << static_cast<int>(self->eid) << "]"
++ << "fail to do nvme identify: " << errMsg
+ << std::endl;
+ self->io.post([cb{std::move(cb)}]() {
+ cb(std::make_error_code(std::errc::bad_message), {});
+@@ -458,7 +489,9 @@ void NVMeMi::adminIdentify(
+ }
+ catch (const std::runtime_error& e)
+ {
+- std::cerr << e.what() << std::endl;
++ std::cerr << "[bus: " << bus << ", addr: " << addr
++ << ", eid: " << static_cast<int>(eid) << "]" << e.what()
++ << std::endl;
+ io.post([cb{std::move(cb)}]() {
+ cb(std::make_error_code(std::errc::no_such_device), {});
+ });
+@@ -528,7 +561,9 @@ void NVMeMi::adminGetLogPage(
+ {
+ if (!nvmeEP)
+ {
+- std::cerr << "nvme endpoint is invalid" << std::endl;
++ std::cerr << "[bus: " << bus << ", addr: " << addr
++ << ", eid: " << static_cast<int>(eid) << "]"
++ << "nvme endpoint is invalid" << std::endl;
+ io.post([cb{std::move(cb)}]() {
+ cb(std::make_error_code(std::errc::no_such_device), {});
+ });
+@@ -558,7 +593,10 @@ void NVMeMi::adminGetLogPage(
+ rc = nvme_mi_admin_get_log_error(ctrl, num, false, log);
+ if (rc)
+ {
+- std::cerr << "fail to get error log" << std::endl;
++ std::cerr
++ << "[bus: " << self->bus << ", addr: " << self->addr
++ << ", eid: " << static_cast<int>(self->eid) << "]"
++ << "fail to get error log" << std::endl;
+ break;
+ }
+ }
+@@ -571,7 +609,10 @@ void NVMeMi::adminGetLogPage(
+ rc = nvme_mi_admin_get_log_smart(ctrl, nsid, false, log);
+ if (rc)
+ {
+- std::cerr << "fail to get smart log" << std::endl;
++ std::cerr
++ << "[bus: " << self->bus << ", addr: " << self->addr
++ << ", eid: " << static_cast<int>(self->eid) << "]"
++ << "fail to get smart log" << std::endl;
+ break;
+ }
+ }
+@@ -584,7 +625,10 @@ void NVMeMi::adminGetLogPage(
+ rc = nvme_mi_admin_get_log_fw_slot(ctrl, false, log);
+ if (rc)
+ {
+- std::cerr << "fail to get firmware slot" << std::endl;
++ std::cerr
++ << "[bus: " << self->bus << ", addr: " << self->addr
++ << ", eid: " << static_cast<int>(self->eid) << "]"
++ << "fail to get firmware slot" << std::endl;
+ break;
+ }
+ }
+@@ -601,8 +645,11 @@ void NVMeMi::adminGetLogPage(
+ log);
+ if (rc)
+ {
+- std::cerr << "fail to get cmd supported and effects log"
+- << std::endl;
++ std::cerr
++ << "[bus: " << self->bus << ", addr: " << self->addr
++ << ", eid: " << static_cast<int>(self->eid) << "]"
++ << "fail to get cmd supported and effects log"
++ << std::endl;
+ break;
+ }
+ }
+@@ -615,8 +662,10 @@ void NVMeMi::adminGetLogPage(
+ rc = nvme_mi_admin_get_log_device_self_test(ctrl, log);
+ if (rc)
+ {
+- std::cerr << "fail to get device self test log"
+- << std::endl;
++ std::cerr
++ << "[bus: " << self->bus << ", addr: " << self->addr
++ << ", eid: " << static_cast<int>(self->eid) << "]"
++ << "fail to get device self test log" << std::endl;
+ break;
+ }
+ }
+@@ -630,8 +679,11 @@ void NVMeMi::adminGetLogPage(
+ nvme_mi_admin_get_log_changed_ns_list(ctrl, false, log);
+ if (rc)
+ {
+- std::cerr << "fail to get changed namespace list"
+- << std::endl;
++ std::cerr
++ << "[bus: " << self->bus << ", addr: " << self->addr
++ << ", eid: " << static_cast<int>(self->eid) << "]"
++ << "fail to get changed namespace list"
++ << std::endl;
+ break;
+ }
+ }
+@@ -655,7 +707,10 @@ void NVMeMi::adminGetLogPage(
+ }
+ else
+ {
+- std::cerr << "invalid lsp for telemetry host log"
++ std::cerr << "[bus: " << self->bus
++ << ", addr: " << self->addr << ", eid: "
++ << static_cast<int>(self->eid) << "]"
++ << "invalid lsp for telemetry host log"
+ << std::endl;
+ rc = -1;
+ errno = EINVAL;
+@@ -681,9 +736,12 @@ void NVMeMi::adminGetLogPage(
+ nvme_mi_admin_get_log_reservation(ctrl, false, log);
+ if (rc)
+ {
+- std::cerr << "fail to get reservation "
+- "notification log"
+- << std::endl;
++ std::cerr
++ << "[bus: " << self->bus << ", addr: " << self->addr
++ << ", eid: " << static_cast<int>(self->eid) << "]"
++ << "fail to get reservation "
++ "notification log"
++ << std::endl;
+ break;
+ }
+ }
+@@ -697,15 +755,20 @@ void NVMeMi::adminGetLogPage(
+ int rc = nvme_mi_admin_get_log_sanitize(ctrl, false, log);
+ if (rc)
+ {
+- std::cerr << "fail to get sanitize status log"
+- << std::endl;
++ std::cerr
++ << "[bus: " << self->bus << ", addr: " << self->addr
++ << ", eid: " << static_cast<int>(self->eid) << "]"
++ << "fail to get sanitize status log" << std::endl;
+ break;
+ }
+ }
+ break;
+ default:
+ {
+- std::cerr << "unknown lid for GetLogPage" << std::endl;
++ std::cerr << "[bus: " << self->bus
++ << ", addr: " << self->addr
++ << ", eid: " << static_cast<int>(self->eid) << "]"
++ << "unknown lid for GetLogPage" << std::endl;
+ rc = -1;
+ errno = EINVAL;
+ }
+@@ -713,7 +776,9 @@ void NVMeMi::adminGetLogPage(
+
+ if (rc < 0)
+ {
+- std::cerr << "fail to get log page: " << std::strerror(errno)
++ std::cerr << "[bus: " << self->bus << ", addr: " << self->addr
++ << ", eid: " << static_cast<int>(self->eid) << "]"
++ << "fail to get log page: " << std::strerror(errno)
+ << std::endl;
+ self->io.post([cb{std::move(cb)}, last_errno{errno}]() {
+ cb(std::make_error_code(static_cast<std::errc>(last_errno)), {});
+@@ -724,7 +789,9 @@ void NVMeMi::adminGetLogPage(
+ {
+ std::string_view errMsg =
+ statusToString(static_cast<nvme_mi_resp_status>(rc));
+- std::cerr << "fail to get log pag: " << errMsg << std::endl;
++ std::cerr << "[bus: " << self->bus << ", addr: " << self->addr
++ << ", eid: " << static_cast<int>(self->eid) << "]"
++ << "fail to get log pag: " << errMsg << std::endl;
+ self->io.post([cb{std::move(cb)}]() {
+ cb(std::make_error_code(std::errc::bad_message), {});
+ return;
+@@ -739,7 +806,9 @@ void NVMeMi::adminGetLogPage(
+ }
+ catch (const std::runtime_error& e)
+ {
+- std::cerr << "NVMeMi adminGetLogPage throws: " << e.what() << std::endl;
++ std::cerr << "[bus: " << bus << ", addr: " << addr
++ << ", eid: " << static_cast<int>(eid) << "]"
++ << "NVMeMi adminGetLogPage throws: " << e.what() << std::endl;
+ io.post([cb{std::move(cb)}]() {
+ cb(std::make_error_code(std::errc::no_such_device), {});
+ });
+@@ -755,7 +824,9 @@ void NVMeMi::adminXfer(
+ {
+ if (!nvmeEP)
+ {
+- std::cerr << "nvme endpoint is invalid" << std::endl;
++ std::cerr << "[bus: " << bus << ", addr: " << addr
++ << ", eid: " << static_cast<int>(eid) << "]"
++ << "nvme endpoint is invalid" << std::endl;
+ io.post([cb{std::move(cb)}]() {
+ cb(std::make_error_code(std::errc::no_such_device), {}, {});
+ });
+@@ -795,7 +866,9 @@ void NVMeMi::adminXfer(
+
+ if (rc < 0)
+ {
+- std::cerr << "failed to nvme_mi_admin_xfer" << std::endl;
++ std::cerr << "[bus: " << self->bus << ", addr: " << self->addr
++ << ", eid: " << static_cast<int>(self->eid) << "]"
++ << "failed to nvme_mi_admin_xfer" << std::endl;
+ self->io.post([cb{std::move(cb)}, last_errno{errno}]() {
+ cb(std::make_error_code(static_cast<std::errc>(last_errno)), {},
+ {});
+@@ -818,7 +891,9 @@ void NVMeMi::adminXfer(
+ }
+ catch (const std::runtime_error& e)
+ {
+- std::cerr << e.what() << std::endl;
++ std::cerr << "[bus: " << bus << ", addr: " << addr
++ << ", eid: " << static_cast<int>(eid) << "]" << e.what()
++ << std::endl;
+ io.post([cb{std::move(cb)}]() {
+ cb(std::make_error_code(std::errc::no_such_device), {}, {});
+ });
+@@ -832,7 +907,9 @@ void NVMeMi::adminFwCommit(
+ {
+ if (!nvmeEP)
+ {
+- std::cerr << "nvme endpoint is invalid" << std::endl;
++ std::cerr << "[bus: " << bus << ", addr: " << addr
++ << ", eid: " << static_cast<int>(eid) << "]"
++ << "nvme endpoint is invalid" << std::endl;
+ io.post([cb{std::move(cb)}]() {
+ cb(std::make_error_code(std::errc::no_such_device),
+ nvme_status_field::NVME_SC_MASK);
+@@ -853,7 +930,9 @@ void NVMeMi::adminFwCommit(
+ if (rc < 0)
+ {
+
+- std::cerr << "fail to nvme_mi_admin_fw_commit: "
++ std::cerr << "[bus: " << self->bus << ", addr: " << self->addr
++ << ", eid: " << static_cast<int>(self->eid) << "]"
++ << "fail to nvme_mi_admin_fw_commit: "
+ << std::strerror(errno) << std::endl;
+ self->io.post([cb{std::move(cb)}, last_errno{errno}]() {
+ cb(std::make_error_code(static_cast<std::errc>(last_errno)),
+@@ -890,7 +969,9 @@ void NVMeMi::adminFwCommit(
+ }
+ catch (const std::runtime_error& e)
+ {
+- std::cerr << e.what() << std::endl;
++ std::cerr << "[bus: " << bus << ", addr: " << addr
++ << ", eid: " << static_cast<int>(eid) << "]" << e.what()
++ << std::endl;
+ io.post([cb{std::move(cb)}]() {
+ cb(std::make_error_code(std::errc::no_such_device),
+ nvme_status_field::NVME_SC_MASK);
+@@ -929,7 +1010,9 @@ void NVMeMi::adminSecuritySend(
+ });
+ if (post_err)
+ {
+- std::cerr << "adminSecuritySend post failed: " << post_err << std::endl;
++ std::cerr << "[bus: " << bus << ", addr: " << addr
++ << ", eid: " << static_cast<int>(eid) << "]"
++ << "adminSecuritySend post failed: " << post_err << std::endl;
+ io.post([cb{std::move(cb)}, post_err]() { cb(post_err, -1); });
+ }
+ }
+@@ -968,7 +1051,9 @@ void NVMeMi::adminSecurityReceive(
+
+ if (args.data_len > maxNVMeMILength)
+ {
+- std::cerr << "nvme_mi_admin_security_send returned excess data, "
++ std::cerr << "[bus: " << self->bus << ", addr: " << self->addr
++ << ", eid: " << static_cast<int>(self->eid) << "]"
++ << "nvme_mi_admin_security_send returned excess data, "
+ << args.data_len << std::endl;
+ self->io.post([cb]() {
+ cb(std::make_error_code(std::errc::protocol_error), -1, {});
+@@ -986,7 +1071,9 @@ void NVMeMi::adminSecurityReceive(
+ });
+ if (post_err)
+ {
+- std::cerr << "adminSecurityReceive post failed: " << post_err
++ std::cerr << "[bus: " << bus << ", addr: " << addr
++ << ", eid: " << static_cast<int>(eid) << "]"
++ << "adminSecurityReceive post failed: " << post_err
+ << std::endl;
+ io.post([cb{std::move(cb)}, post_err]() { cb(post_err, -1, {}); });
+ }
+--
+2.34.1
+
diff --git a/recipes-phosphor/sensors/dbus-sensors/0042-nvmesensor-chuck-fetch-for-telemetry-logs.patch b/recipes-phosphor/sensors/dbus-sensors/0042-nvmesensor-chuck-fetch-for-telemetry-logs.patch
new file mode 100644
index 0000000..db3dc27
--- /dev/null
+++ b/recipes-phosphor/sensors/dbus-sensors/0042-nvmesensor-chuck-fetch-for-telemetry-logs.patch
@@ -0,0 +1,294 @@
+From 3d9e8f7a030d6a3b1baa397b391d3c763919ed5d Mon Sep 17 00:00:00 2001
+From: Hao Jiang <jianghao@google.com>
+Date: Fri, 2 Jun 2023 23:29:45 +0000
+Subject: [PATCH 42/44] nvmesensor: chuck fetch for telemetry logs
+
+The telemetry logs could be larger than megabytes so fetch the whole log
+at one shot could block the other transactions on the same bus.
+
+This change slices the transaction into 4kB chucks and repush the
+remaining tasks into the worker thread so other tasks (such as health
+poll) can be scheduled in the middle.
+
+Signed-off-by: Hao Jiang <jianghao@google.com>
+Change-Id: I4f5e88b73cbb850954ea39fde185bb4016b8e25c
+---
+ src/NVMeMi.cpp | 174 +++++++++++++++++++++++++++++++++----------------
+ src/NVMeMi.hpp | 7 +-
+ 2 files changed, 123 insertions(+), 58 deletions(-)
+
+diff --git a/src/NVMeMi.cpp b/src/NVMeMi.cpp
+index 10d57a3..60595e8 100644
+--- a/src/NVMeMi.cpp
++++ b/src/NVMeMi.cpp
+@@ -148,6 +148,9 @@ void NVMeMi::initMCTP()
+ << std::to_string(nid) + ":" + std::to_string(eid)
+ << std::endl;
+ }
++ // TODO: make a flag to indicate the next health poll should return
++ // no_such_device error. This is to inform the subsystem that the connected
++ // has been reset or hot-swapped.
+ std::cerr << "[bus: " << bus << ", addr: " << addr << "]"
+ << "finish MCTP initialization. "
+ << std::to_string(nid) + ":" + std::to_string(eid) << std::endl;
+@@ -508,18 +511,15 @@ static int nvme_mi_admin_get_log_telemetry_host_rae(nvme_mi_ctrl_t ctrl,
+
+ // Get Temetery Log header and return the size for hdr + data area (Area 1, 2,
+ // 3, or maybe 4)
+-int getTelemetryLog(nvme_mi_ctrl_t ctrl, bool host, bool create,
+- std::vector<uint8_t>& data)
++int getTelemetryLogSize(nvme_mi_ctrl_t ctrl, bool host, uint32_t& size)
+ {
+ int rc = 0;
+- data.resize(sizeof(nvme_telemetry_log));
+- nvme_telemetry_log& log =
+- *reinterpret_cast<nvme_telemetry_log*>(data.data());
++ nvme_telemetry_log log;
+ auto func = host ? nvme_mi_admin_get_log_telemetry_host_rae
+ : nvme_mi_admin_get_log_telemetry_ctrl;
+
+ // Only host telemetry log requires create.
+- if (host && create)
++ if (host)
+ {
+ rc = nvme_mi_admin_get_log_create_telemetry_host(ctrl, &log);
+ if (rc)
+@@ -527,7 +527,6 @@ int getTelemetryLog(nvme_mi_ctrl_t ctrl, bool host, bool create,
+ std::cerr << "failed to create telemetry host log" << std::endl;
+ return rc;
+ }
+- return 0;
+ }
+
+ rc = func(ctrl, false, 0, sizeof(log), &log);
+@@ -539,19 +538,93 @@ int getTelemetryLog(nvme_mi_ctrl_t ctrl, bool host, bool create,
+ return rc;
+ }
+
+- long size =
+- static_cast<long>((boost::endian::little_to_native(log.dalb3) + 1)) *
+- NVME_LOG_TELEM_BLOCK_SIZE;
++ size = static_cast<uint32_t>(
++ (boost::endian::little_to_native(log.dalb3) + 1)) *
++ NVME_LOG_TELEM_BLOCK_SIZE;
++ return rc;
++}
+
+- data.resize(size);
+- rc = func(ctrl, false, 0, data.size(), data.data());
+- if (rc)
++void NVMeMi::getTelemetryLogChuck(
++ nvme_mi_ctrl_t ctrl, bool host, uint64_t offset,
++ std::vector<uint8_t>&& data,
++ std::function<void(const std::error_code&, std::span<uint8_t>)>&& cb)
++{
++
++ if (offset >= data.size())
+ {
+- std::cerr << "failed to get full telemetry log for "
+- << (host ? "host" : "ctrl") << std::endl;
+- return rc;
++
++ std::cerr << "[bus: " << bus << ", addr: " << addr
++ << ", eid: " << static_cast<int>(eid) << "]"
++ << "get telemetry log: offset exceed the log size. "
++ << "offset: " << offset << ", size: " << data.size()
++ << std::endl;
++ cb(std::make_error_code(std::errc::invalid_argument), {});
++ return;
+ }
+- return 0;
++
++ post([self{shared_from_this()}, ctrl, host, offset, data{std::move(data)},
++ cb{std::move(cb)}]() mutable {
++ int rc = 0;
++ bool rae = 1;
++ auto func = host ? nvme_mi_admin_get_log_telemetry_host_rae
++ : nvme_mi_admin_get_log_telemetry_ctrl;
++ uint32_t size = 0;
++
++ // final transaction
++ if (offset + nvme_mi_xfer_size >= data.size())
++ {
++ rae = 0;
++ }
++ size = std::min(static_cast<uint32_t>(nvme_mi_xfer_size),
++ static_cast<uint32_t>(data.size() - offset));
++
++ rc = func(ctrl, rae, offset, size, data.data() + offset);
++
++ if (rc < 0)
++ {
++ std::cerr << "[bus: " << self->bus << ", addr: " << self->addr
++ << ", eid: " << static_cast<int>(self->eid) << "]"
++ << "fail to get chuck for telemetry log: "
++ << std::strerror(errno) << std::endl;
++ boost::asio::post(self->io,
++ [cb{std::move(cb)}, last_errno{errno}]() {
++ cb(std::make_error_code(static_cast<std::errc>(last_errno)),
++ {});
++ });
++ return;
++ }
++ else if (rc > 0)
++ {
++ std::string_view errMsg =
++ statusToString(static_cast<nvme_mi_resp_status>(rc));
++ std::cerr << "[bus: " << self->bus << ", addr: " << self->addr
++ << ", eid: " << static_cast<int>(self->eid) << "]"
++ << "fail to get chuck for telemetry log: " << errMsg
++ << std::endl;
++ boost::asio::post(self->io, [cb{std::move(cb)}]() {
++ cb(std::make_error_code(std::errc::bad_message), {});
++ });
++ return;
++ }
++
++ if (rae == 0)
++ {
++ boost::asio::post(
++ self->io, [cb{std::move(cb)}, data{std::move(data)}]() mutable {
++ std::span<uint8_t> span{data.data(), data.size()};
++ cb({}, span);
++ });
++ return;
++ }
++
++ offset += size;
++ boost::asio::post(self->io,
++ [self, ctrl, host, offset, data{std::move(data)},
++ cb{std::move(cb)}]() mutable {
++ self->getTelemetryLogChuck(ctrl, host, offset, std::move(data),
++ std::move(cb));
++ });
++ });
+ }
+
+ void NVMeMi::adminGetLogPage(
+@@ -575,7 +648,7 @@ void NVMeMi::adminGetLogPage(
+ post([ctrl, nsid, lid, lsp, lsi, self{shared_from_this()},
+ cb{std::move(cb)}]() {
+ std::vector<uint8_t> data;
+-
++ std::function<void(void)> logHandler;
+ int rc = 0;
+ switch (lid)
+ {
+@@ -692,37 +765,20 @@ void NVMeMi::adminGetLogPage(
+ // fall through to NVME_LOG_LID_TELEMETRY_CTRL
+ case NVME_LOG_LID_TELEMETRY_CTRL:
+ {
+- bool host = false;
+- bool create = false;
+- if (lid == NVME_LOG_LID_TELEMETRY_HOST)
+- {
+- host = true;
+- if (lsp == NVME_LOG_TELEM_HOST_LSP_CREATE)
+- {
+- create = true;
+- }
+- else if (lsp == NVME_LOG_TELEM_HOST_LSP_RETAIN)
+- {
+- create = false;
+- }
+- else
+- {
+- std::cerr << "[bus: " << self->bus
+- << ", addr: " << self->addr << ", eid: "
+- << static_cast<int>(self->eid) << "]"
+- << "invalid lsp for telemetry host log"
+- << std::endl;
+- rc = -1;
+- errno = EINVAL;
+- break;
+- }
+- }
+- else
++ bool host =
++ (lid == NVME_LOG_LID_TELEMETRY_HOST) ? true : false;
++
++ uint32_t size = 0;
++ rc = getTelemetryLogSize(ctrl, host, size);
++ if (rc == 0)
+ {
+- host = false;
++ data.resize(size);
++ logHandler = [self, ctrl, host, data{std::move(data)},
++ cb{std::move(cb)}]() mutable {
++ self->getTelemetryLogChuck(
++ ctrl, host, 0, std::move(data), std::move(cb));
++ };
+ }
+-
+- rc = getTelemetryLog(ctrl, host, create, data);
+ }
+ break;
+ case NVME_LOG_LID_RESERVATION:
+@@ -780,10 +836,9 @@ void NVMeMi::adminGetLogPage(
+ << ", eid: " << static_cast<int>(self->eid) << "]"
+ << "fail to get log page: " << std::strerror(errno)
+ << std::endl;
+- self->io.post([cb{std::move(cb)}, last_errno{errno}]() {
++ logHandler = [cb{std::move(cb)}, last_errno{errno}]() {
+ cb(std::make_error_code(static_cast<std::errc>(last_errno)), {});
+- });
+- return;
++ };
+ }
+ else if (rc > 0)
+ {
+@@ -792,16 +847,21 @@ void NVMeMi::adminGetLogPage(
+ std::cerr << "[bus: " << self->bus << ", addr: " << self->addr
+ << ", eid: " << static_cast<int>(self->eid) << "]"
+ << "fail to get log pag: " << errMsg << std::endl;
+- self->io.post([cb{std::move(cb)}]() {
++ logHandler = [cb{std::move(cb)}]() {
+ cb(std::make_error_code(std::errc::bad_message), {});
+- return;
+- });
++ };
+ }
+
+- self->io.post([cb{std::move(cb)}, data{std::move(data)}]() mutable {
+- std::span<uint8_t> span{data.data(), data.size()};
+- cb({}, span);
+- });
++ if (!logHandler)
++ {
++ logHandler =
++ [cb{std::move(cb)}, data{std::move(data)}]() mutable {
++ std::span<uint8_t> span{data.data(), data.size()};
++ cb({}, span);
++ };
++ }
++ boost::asio::post(self->io, logHandler);
++
+ });
+ }
+ catch (const std::runtime_error& e)
+diff --git a/src/NVMeMi.hpp b/src/NVMeMi.hpp
+index db91bfd..0a86dcf 100644
+--- a/src/NVMeMi.hpp
++++ b/src/NVMeMi.hpp
+@@ -62,7 +62,7 @@ class NVMeMi : public NVMeMiIntf, public std::enable_shared_from_this<NVMeMi>
+ private:
+ // the transfer size for nvme mi messages.
+ // define in github.com/linux-nvme/libnvme/blob/master/src/nvme/mi.c
+- static constexpr int nvme_mi_xfer_size = 4096;
++ static constexpr size_t nvme_mi_xfer_size = 4096;
+
+ static nvme_root_t nvmeRoot;
+
+@@ -127,4 +127,9 @@ class NVMeMi : public NVMeMiIntf, public std::enable_shared_from_this<NVMeMi>
+ }
+
+ std::error_code try_post(std::function<void(void)>&& func);
++
++ void getTelemetryLogChuck(
++ nvme_mi_ctrl_t ctrl, bool host, uint64_t offset,
++ std::vector<uint8_t>&& data,
++ std::function<void(const std::error_code&, std::span<uint8_t>)>&& cb);
+ };
+--
+2.34.1
+
diff --git a/recipes-phosphor/sensors/dbus-sensors/0043-nvmesensor-fix-plugin-issue.patch b/recipes-phosphor/sensors/dbus-sensors/0043-nvmesensor-fix-plugin-issue.patch
new file mode 100644
index 0000000..4e17759
--- /dev/null
+++ b/recipes-phosphor/sensors/dbus-sensors/0043-nvmesensor-fix-plugin-issue.patch
@@ -0,0 +1,32 @@
+From a4eab6069de0aa5764e942e17ed37f9a8f2da1f3 Mon Sep 17 00:00:00 2001
+From: Hao Jiang <jianghao@google.com>
+Date: Fri, 23 Jun 2023 23:50:14 +0000
+Subject: [PATCH 43/44] nvmesensor: fix plugin issue
+
+The plugin should not be reset when the NVMeSubsystem is marked as not
+functional. Given the plugin is only created with NVMeSubsystem, so the
+lifetime of plugin should be same as NVMeSubsystem or start to recycle
+with NVMeSubsystem destructor.
+
+Signed-off-by: Hao Jiang <jianghao@google.com>
+Change-Id: I4b2abc9b534adf9a96747a478f4351b349fa138b
+---
+ src/NVMeSubsys.cpp | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/NVMeSubsys.cpp b/src/NVMeSubsys.cpp
+index cd10a75..2499fb7 100644
+--- a/src/NVMeSubsys.cpp
++++ b/src/NVMeSubsys.cpp
+@@ -98,7 +98,7 @@ void NVMeSubsystem::markFunctional(bool toggle)
+ // is enabled
+
+ controllers.clear();
+- plugin.reset();
++ // plugin.reset();
+ return;
+ }
+ if (status == Status::Intiatilzing)
+--
+2.34.1
+
diff --git a/recipes-phosphor/sensors/dbus-sensors/0044-nvmesensor-add-markAvailable-with-adaptive-timer.patch b/recipes-phosphor/sensors/dbus-sensors/0044-nvmesensor-add-markAvailable-with-adaptive-timer.patch
new file mode 100644
index 0000000..54263da
--- /dev/null
+++ b/recipes-phosphor/sensors/dbus-sensors/0044-nvmesensor-add-markAvailable-with-adaptive-timer.patch
@@ -0,0 +1,227 @@
+From e2961d04d4ba202047d1e53fc4b52a3c6483d406 Mon Sep 17 00:00:00 2001
+From: Hao Jiang <jianghao@google.com>
+Date: Sat, 24 Jun 2023 05:29:07 +0000
+Subject: [PATCH 44/44] nvmesensor: add markAvailable with adaptive timer
+
+Added markAvailable() function for NVMeSubsys. When the subsystem health
+poll detects the device absence due to various reasons. The subsystem
+can be marked as unavailable.
+
+Current function during subsystem unavaibility is to reducing the
+polling cadence, because an absent device can no longer report the
+health data and it usually takes time for the communication/NVMe device
+to recovery from absence.
+
+Furthur task for markAvailable() will include a dbus interface to inform
+the status of NVMe device (subsystem).
+
+Signed-off-by: Hao Jiang <jianghao@google.com>
+Change-Id: Ie69b0dee23685d4cf9f712894d396f975c3419b0
+---
+ src/NVMeSubsys.cpp | 67 ++++++++++++++++++++++++++++++++++++++--------
+ src/NVMeSubsys.hpp | 7 +++++
+ 2 files changed, 63 insertions(+), 11 deletions(-)
+
+diff --git a/src/NVMeSubsys.cpp b/src/NVMeSubsys.cpp
+index 2499fb7..63e3426 100644
+--- a/src/NVMeSubsys.cpp
++++ b/src/NVMeSubsys.cpp
+@@ -81,6 +81,16 @@ NVMeSubsystem::~NVMeSubsystem()
+
+ void NVMeSubsystem::markFunctional(bool toggle)
+ {
++ if (ctemp)
++ {
++ ctemp->markFunctional(toggle);
++ }
++
++ if (nvmeIntf.getProtocol() == NVMeIntf::Protocol::NVMeBasic)
++ {
++ return;
++ }
++
+ // disable the subsystem
+ if (!toggle)
+ {
+@@ -106,6 +116,7 @@ void NVMeSubsystem::markFunctional(bool toggle)
+ throw std::runtime_error("cannot start: the subsystem is intiatilzing");
+ }
+ status = Status::Intiatilzing;
++ markAvailable(toggle);
+
+ // add controllers for the subsystem
+ if (nvmeIntf.getProtocol() == NVMeIntf::Protocol::NVMeMI)
+@@ -123,6 +134,7 @@ void NVMeSubsystem::markFunctional(bool toggle)
+ << (ec ? ": " + ec.message() : "") << std::endl;
+ self->status = Status::Stop;
+ self->markFunctional(false);
++ self->markAvailable(false);
+ return;
+ }
+
+@@ -195,6 +207,7 @@ void NVMeSubsystem::markFunctional(bool toggle)
+ << std::endl;
+ self->status = Status::Stop;
+ self->markFunctional(false);
++ self->markAvailable(false);
+ return;
+ }
+ nvme_secondary_ctrl_list& listHdr =
+@@ -212,6 +225,7 @@ void NVMeSubsystem::markFunctional(bool toggle)
+ << std::endl;
+ self->status = Status::Stop;
+ self->markFunctional(false);
++ self->markAvailable(false);
+ return;
+ }
+
+@@ -226,6 +240,7 @@ void NVMeSubsystem::markFunctional(bool toggle)
+ << std::endl;
+ self->status = Status::Stop;
+ self->markFunctional(false);
++ self->markAvailable(false);
+ return;
+ }
+
+@@ -277,6 +292,27 @@ void NVMeSubsystem::markFunctional(bool toggle)
+ }
+ }
+
++void NVMeSubsystem::markAvailable(bool toggle)
++{
++ if (ctemp)
++ {
++ ctemp->markAvailable(toggle);
++ }
++
++ if (nvmeIntf.getProtocol() == NVMeIntf::Protocol::NVMeBasic)
++ {
++ return;
++ }
++
++ if (toggle)
++ {
++ // TODO: make the Available interface true
++ UnavailableCount = 0;
++ return;
++ }
++ // TODO: make the Available interface false
++ UnavailableCount = UnavailableMaxCount;
++}
+ void NVMeSubsystem::start()
+ {
+ // add thermal sensor for the subsystem
+@@ -331,8 +367,8 @@ void NVMeSubsystem::start()
+ {
+ std::cerr << "error reading ctemp from subsystem"
+ << ", reason:" << error.message() << "\n";
+- self->ctemp->markFunctional(false);
+- self->ctemp->markAvailable(false);
++ self->markFunctional(false);
++ self->markAvailable(false);
+ return;
+ }
+ // other communication errors
+@@ -347,7 +383,7 @@ void NVMeSubsystem::start()
+ if (status == nullptr)
+ {
+ std::cerr << "empty data returned by data fetcher" << std::endl;
+- self->ctemp->markFunctional(false);
++ self->markFunctional(false);
+ return;
+ }
+
+@@ -357,7 +393,7 @@ void NVMeSubsystem::start()
+ ((flags & NVMeBasicIntf::StatusFlags::
+ NVME_MI_BASIC_SFLGS_DRIVE_FUNCTIONAL) == 0))
+ {
+- self->ctemp->markFunctional(false);
++ self->markFunctional(false);
+ return;
+ }
+ self->ctemp->updateValue(getTemperatureReading(status->Temp));
+@@ -375,6 +411,14 @@ void NVMeSubsystem::start()
+ [intf, self{std::move(shared_from_this())}](
+ std::function<void(const std::error_code&,
+ nvme_mi_nvm_ss_health_status*)>&& cb) {
++ // do not poll the health status if subsystem is in cooldown
++ if (self->UnavailableCount > 0)
++ {
++ cb(std::make_error_code(std::errc::operation_canceled),
++ nullptr);
++ return;
++ }
++
+ // do not poll the health status if the subsystem is intiatilzing
+ if (self->status == Status::Intiatilzing)
+ {
+@@ -389,6 +433,12 @@ void NVMeSubsystem::start()
+ ctemp_process_t<nvme_mi_nvm_ss_health_status*> dataProcessor =
+ [self{shared_from_this()}](const std::error_code& error,
+ nvme_mi_nvm_ss_health_status* status) {
++ if (self->UnavailableCount > 0)
++ {
++ self->UnavailableCount--;
++ return;
++ }
++
+ if (error == std::errc::operation_canceled ||
+ self->status == Status::Intiatilzing)
+ {
+@@ -406,8 +456,7 @@ void NVMeSubsystem::start()
+ << ", reason:" << error.message() << "\n";
+ // stop the subsystem
+ self->markFunctional(false);
+- self->ctemp->markFunctional(false);
+- self->ctemp->markAvailable(false);
++ self->markAvailable(false);
+
+ return;
+ }
+@@ -420,7 +469,7 @@ void NVMeSubsystem::start()
+ if (self->ctemp->inError())
+ {
+ self->markFunctional(false);
+- self->ctemp->markFunctional(false);
++ self->markAvailable(false);
+ }
+ return;
+ }
+@@ -430,10 +479,7 @@ void NVMeSubsystem::start()
+ if (!df)
+ {
+ // stop the subsystem
+-
+ self->markFunctional(false);
+- self->ctemp->markFunctional(false);
+-
+ return;
+ }
+
+@@ -460,7 +506,6 @@ void NVMeSubsystem::stop()
+ {
+ std::cerr << "status start" << std::endl;
+ markFunctional(false);
+- ctemp->markFunctional(false);
+ }
+ else if (status == Status::Intiatilzing)
+ {
+diff --git a/src/NVMeSubsys.hpp b/src/NVMeSubsys.hpp
+index 6bd8b62..dd9dbfa 100644
+--- a/src/NVMeSubsys.hpp
++++ b/src/NVMeSubsys.hpp
+@@ -74,4 +74,11 @@ class NVMeSubsystem : public std::enable_shared_from_this<NVMeSubsystem>
+ // make the subsystem functional/functional be enabling/disabling the
+ // storage controller, namespaces and thermal sensors.
+ void markFunctional(bool toggle);
++
++ // mark the availability of the Storage device.
++ void markAvailable(bool toggle);
++
++ // a counter to skip health poll when NVMe subsystem becomes Unavailable
++ unsigned UnavailableCount = 0;
++ static constexpr unsigned UnavailableMaxCount = 60;
+ };
+--
+2.34.1
+
diff --git a/recipes-phosphor/sensors/dbus-sensors_%.bbappend b/recipes-phosphor/sensors/dbus-sensors_%.bbappend
index 2324763..e1f0cf0 100644
--- a/recipes-phosphor/sensors/dbus-sensors_%.bbappend
+++ b/recipes-phosphor/sensors/dbus-sensors_%.bbappend
@@ -14,39 +14,50 @@
# gBMC NVMe-MI support begins
nvmesensor_patches = " \
- file://0001-nvme-sensor-refactor-the-code.patch \
- file://0002-NVMe-sensor-add-Storage-and-Drive-interface.patch \
- file://0003-nvmesensor-Add-NVMe-MI-protocol-and-controller.patch \
- file://0004-Enable-ctemp-sensor-for-nvme-mi.patch \
- file://0005-nvmesensor-Add-Identify-and-cntrl-association.patch \
- file://0006-Add-NVMeAdmin-intf-with-GetLogPage.patch \
- file://0007-Add-more-logs-to-NVMe-daemon.patch \
- file://0008-Add-Identify-method-to-NVMeAdmin-interface.patch \
- file://0009-nvmesensor-add-adminXfer-for-MI-interface.patch \
- file://0010-nvmesensor-handle-libnvme-mi-status-return-code.patch \
- file://0011-nvmesensor-handle-the-broken-pipe-signal.patch \
- file://0012-nvmesensor-Add-FirmwareCommit-to-nvme-daemon.patch \
- file://0013-nvmesensor-Using-generated-controller-server.patch \
- file://0014-nvmesensor-Add-NVMePlugin.patch \
- file://0015-nvmesensor-add-associations.patch \
- file://0016-nvmesensor-Create-thermal-sensor-in-start.patch \
- file://0017-nvmesensor-Move-temp-sensor-function-to-NVMeUtil.patch \
- file://0018-nvmesensor-Change-the-plugin-log-handler.patch \
- file://0019-nvmesensor-Add-nvme-controller-plugin.patch \
- file://0020-nvmesensor-add-timeout-for-xfer.patch \
- file://0021-nvmesensor-segmentation-fault-workaround-and-fix.patch \
- file://0022-nvmesensor-spin-out-the-worker-for-NVMeMi.patch \
- file://0023-nvmesensor-delay-subsystem-creation.patch \
- file://0024-nvmesensor-clean-up-the-association.patch \
- file://0025-nvmesensor-change-the-controller-init-sequence.patch \
- file://0026-nvmesensor-Check-SCS-for-secondary-controllers.patch \
- file://0027-Enable-asio-threads-and-boost-coroutine.patch \
- file://0028-nvmesensor-Split-constructor-for-shared_from_this.patch \
- file://0029-nvmesensor-Add-SecuritySend-and-SecurityReceive.patch \
- file://0030-nvmesensor-always-create-host-telemetry-log-page.patch \
- file://0031-nvmesensor-set-default-timeout-to-20-seconds-for-Sec.patch \
- file://0032-nvmesensor-close-pipe-file-descriptor-before-excepti.patch \
- file://0033-nvmesensor-Add-toggle-for-single-thread-mode.patch \
+ file://0001-nvmesensor-rename-the-files.patch \
+ file://0002-nvme-sensor-refactor-the-code.patch \
+ file://0003-NVMe-sensor-add-Storage-and-Drive-interface.patch \
+ file://0004-nvmesensor-Add-NVMe-MI-protocol-and-controller.patch \
+ file://0005-Enable-ctemp-sensor-for-nvme-mi.patch \
+ file://0006-nvmesensor-Add-Identify-and-cntrl-association.patch \
+ file://0007-Add-NVMeAdmin-intf-with-GetLogPage.patch \
+ file://0008-Add-more-logs-to-NVMe-daemon.patch \
+ file://0009-Add-Identify-method-to-NVMeAdmin-interface.patch \
+ file://0010-nvmesensor-add-adminXfer-for-MI-interface.patch \
+ file://0011-nvmesensor-handle-libnvme-mi-status-return-code.patch \
+ file://0012-nvmesensor-handle-the-broken-pipe-signal.patch \
+ file://0013-nvmesensor-Add-FirmwareCommit-to-nvme-daemon.patch \
+ file://0014-nvmesensor-Using-generated-controller-server.patch \
+ file://0015-nvmesensor-Add-NVMePlugin.patch \
+ file://0016-nvmesensor-add-associations.patch \
+ file://0017-nvmesensor-Create-thermal-sensor-in-start.patch \
+ file://0018-nvmesensor-Move-temp-sensor-function-to-NVMeUtil.patch \
+ file://0019-nvmesensor-Change-the-plugin-log-handler.patch \
+ file://0020-nvmesensor-Add-nvme-controller-plugin.patch \
+ file://0021-nvmesensor-add-timeout-for-xfer.patch \
+ file://0022-nvmesensor-segmentation-fault-workaround-and-fix.patch \
+ file://0023-nvmesensor-spin-out-the-worker-for-NVMeMi.patch \
+ file://0024-nvmesensor-delay-subsystem-creation.patch \
+ file://0025-nvmesensor-clean-up-the-association.patch \
+ file://0026-nvmesensor-change-the-controller-init-sequence.patch \
+ file://0027-nvmesensor-Check-SCS-for-secondary-controllers.patch \
+ file://0028-nvmesensor-Add-toggle-for-single-thread-mode.patch \
+ file://0029-nvmesensor-Add-Fake-for-NVMeMi.patch \
+ file://0030-nvmesensor-add-unit-test.patch \
+ file://0031-nvmesensor-enable-disable-subsys-according-to-DF.patch \
+ file://0032-nvmesensor-subsystem-poll-supports-absence.patch \
+ file://0033-Enable-asio-threads-and-boost-coroutine.patch \
+ file://0034-nvmesensor-Split-constructor-for-shared_from_this.patch \
+ file://0035-nvmesensor-Add-SecuritySend-and-SecurityReceive.patch \
+ file://0036-nvmesensor-set-default-timeout-to-20-seconds-for-Sec.patch \
+ file://0037-nvmesensor-close-pipe-file-descriptor-before-excepti.patch \
+ file://0038-nvmesensor-add-Mock-and-Fake-for-SecuSend-Recv.patch \
+ file://0039-utils-add-PowerCallbackEntry-for-PowerMatch.patch \
+ file://0040-nvmesensor-add-PowerState-to-NVMeMi.patch \
+ file://0041-nvmesensor-Add-print-info-to-NVMeMi.patch \
+ file://0042-nvmesensor-chuck-fetch-for-telemetry-logs.patch \
+ file://0043-nvmesensor-fix-plugin-issue.patch \
+ file://0044-nvmesensor-add-markAvailable-with-adaptive-timer.patch \
"
PACKAGECONFIG[nvmesensor] = "-Dnvme=enabled, -Dnvme=disabled, libnvme libnvme-vu"
SYSTEMD_SERVICE:${PN} += "${@bb.utils.contains('PACKAGECONFIG', 'nvmesensor', \