NVMed: Enable primary controller when SC is empty
Tested: Manually tested
Patch Tracking Bug: b/284486810
Change-Id: Iae93dfd392f29c0cb4da719dff38480231fbc05e
Signed-off-by: Muhammad Usama <muhammadusama@google.com>
diff --git a/recipes-phosphor/sensors/dbus-sensors/0047-NVMed-Enable-Primary-controller-when-SC-is-empty.patch b/recipes-phosphor/sensors/dbus-sensors/0047-NVMed-Enable-Primary-controller-when-SC-is-empty.patch
new file mode 100644
index 0000000..19c0eb7
--- /dev/null
+++ b/recipes-phosphor/sensors/dbus-sensors/0047-NVMed-Enable-Primary-controller-when-SC-is-empty.patch
@@ -0,0 +1,221 @@
+From dd139577f132ddbac93d6a4ab6883d390583d3d3 Mon Sep 17 00:00:00 2001
+From: Muhammad Usama <muhammadusama@google.com>
+Date: Thu, 20 Jul 2023 05:23:05 +0000
+Subject: [PATCH] NVMed: Enable Primary controller when SC is empty
+
+NVMe device can have no secondary controller. Currently, if
+the secondary list is empty. The primary controller is not
+enable.
+
+Patch Tracking Bug: b/284486810
+Upstream info / review: https://gerrit.openbmc.org/c/openbmc/dbus-sensors/+/63777
+Upstream-Status: Submitted
+Justification: Depends on other patches
+
+Signed-off-by: Muhammad Usama <muhammadusama@google.com>
+
+%% original patch: 0047-NVMed-Enable-Primary-controller-when-SC-is-empty.patch
+---
+ src/NVMeSubsys.cpp | 144 +++++++++++++++++++++++++--------------------
+ src/NVMeSubsys.hpp | 3 +
+ 2 files changed, 84 insertions(+), 63 deletions(-)
+
+diff --git a/src/NVMeSubsys.cpp b/src/NVMeSubsys.cpp
+index 07370e0..00142f9 100644
+--- a/src/NVMeSubsys.cpp
++++ b/src/NVMeSubsys.cpp
+@@ -99,6 +99,69 @@ NVMeSubsystem::~NVMeSubsystem()
+ objServer.remove_interface(assocIntf);
+ }
+
++void NVMeSubsystem::processSecondaryControllerList(nvme_secondary_ctrl_list* secCntlrList)
++{
++ auto findPrimary = controllers.begin();
++ int secCntlrCount = 0;
++ if (secCntlrList != nullptr)
++ {
++ // all sc_entry pointing to a single pcid, so we only check
++ // the first entry.
++ findPrimary = controllers.find(secCntlrList->sc_entry[0].pcid);
++ if (findPrimary == controllers.end())
++ {
++ std::cerr << "fail to match primary controller from "
++ "identify sencondary cntrl list" << std::endl;
++ status = Status::Stop;
++ markFunctional(false);
++ markAvailable(false);
++ return;
++ }
++ secCntlrCount = secCntlrList->num;
++ }
++
++ // Enable primary controller since they are required to work
++ auto& primaryController = findPrimary->second.first;
++ primaryController =
++ NVMeControllerEnabled::create(std::move(*primaryController.get()));
++
++ std::vector<std::shared_ptr<NVMeController>> secCntrls;
++ for (int i = 0; i < secCntlrCount; i++)
++ {
++ auto findSecondary = controllers.find(secCntlrList->sc_entry[i].scid);
++ if (findSecondary == controllers.end())
++ {
++ std::cerr << "fail to match secondary controller from "
++ "identify sencondary cntrl list"
++ << std::endl;
++ break;
++ }
++
++ auto& secondaryController = findSecondary->second.first;
++
++ // Check Secondary Controller State
++ if (secCntlrList->sc_entry[i].scs != 0)
++ {
++ secondaryController = NVMeControllerEnabled::create(
++ std::move(*secondaryController.get()));
++ }
++ secCntrls.push_back(secondaryController);
++ }
++ primaryController->setSecAssoc(secCntrls);
++
++ // start controller
++ for (auto& [_, pair] : controllers)
++ {
++ pair.first->start(pair.second);
++ }
++ // start plugin
++ if (plugin)
++ {
++ plugin->start();
++ }
++ status = Status::Start;
++}
++
+ void NVMeSubsystem::markFunctional(bool toggle)
+ {
+ if (ctemp)
+@@ -214,7 +277,20 @@ void NVMeSubsystem::markFunctional(bool toggle)
+ The controller is SR-IOV, meaning all controllers (within a
+ subsystem) are pointing to a single primary controller. So we
+ only need to do identify on an arbatary controller.
++ If the controller list contains a single controller. Skip
++ identifying the secondary controller list. It will be the primary
++ controller.
+ */
++ if (ctrlList.size() == 1)
++ {
++ // Remove all associations
++ for (const auto& [_, pair] : self->controllers)
++ {
++ pair.first->setSecAssoc();
++ }
++ self->processSecondaryControllerList(nullptr);
++ return;
++ }
+ auto ctrl = ctrlList.back();
+ nvme->adminIdentify(
+ ctrl, nvme_identify_cns::NVME_IDENTIFY_CNS_SECONDARY_CTRL_LIST,
+@@ -230,8 +306,8 @@ void NVMeSubsystem::markFunctional(bool toggle)
+ self->markAvailable(false);
+ return;
+ }
+- nvme_secondary_ctrl_list& listHdr =
+- *reinterpret_cast<nvme_secondary_ctrl_list*>(data.data());
++ nvme_secondary_ctrl_list* listHdr =
++ reinterpret_cast<nvme_secondary_ctrl_list*>(data.data());
+
+ // Remove all associations
+ for (const auto& [_, pair] : self->controllers)
+@@ -239,7 +315,7 @@ void NVMeSubsystem::markFunctional(bool toggle)
+ pair.first->setSecAssoc();
+ }
+
+- if (listHdr.num == 0)
++ if (listHdr->num == 0)
+ {
+ std::cerr << "empty identify secondary controller list"
+ << std::endl;
+@@ -248,66 +324,8 @@ void NVMeSubsystem::markFunctional(bool toggle)
+ self->markAvailable(false);
+ return;
+ }
+-
+- // all sc_entry pointing to a single pcid, so we only check
+- // the first entry.
+- auto findPrimary =
+- self->controllers.find(listHdr.sc_entry[0].pcid);
+- if (findPrimary == self->controllers.end())
+- {
+- std::cerr << "fail to match primary controller from "
+- "identify sencondary cntrl list"
+- << std::endl;
+- self->status = Status::Stop;
+- self->markFunctional(false);
+- self->markAvailable(false);
+- return;
+- }
+-
+- // Enable primary controller since they are required to work
+- auto& primaryController = findPrimary->second.first;
+- primaryController = NVMeControllerEnabled::create(
+- std::move(*primaryController.get()));
+-
+- std::vector<std::shared_ptr<NVMeController>> secCntrls;
+- for (int i = 0; i < listHdr.num; i++)
+- {
+- auto findSecondary =
+- self->controllers.find(listHdr.sc_entry[i].scid);
+- if (findSecondary == self->controllers.end())
+- {
+- std::cerr << "fail to match secondary controller from "
+- "identify sencondary cntrl list"
+- << std::endl;
+- break;
+- }
+-
+- auto& secondaryController = findSecondary->second.first;
+-
+- // Check Secondary Controller State
+- if (listHdr.sc_entry[i].scs != 0)
+- {
+- secondaryController = NVMeControllerEnabled::create(
+- std::move(*secondaryController.get()));
+- }
+- secCntrls.push_back(secondaryController);
+- }
+- primaryController->setSecAssoc(secCntrls);
+-
+- // start controller
+- for (auto& [_, pair] : self->controllers)
+- {
+- pair.first->start(pair.second);
+- }
+-
+- // start plugin
+- if (self->plugin)
+- {
+- self->plugin->start();
+- }
+-
+- self->status = Status::Start;
+- });
++ self->processSecondaryControllerList(listHdr);
++ });
+ });
+ }
+ }
+diff --git a/src/NVMeSubsys.hpp b/src/NVMeSubsys.hpp
+index dd9dbfa..a86710f 100644
+--- a/src/NVMeSubsys.hpp
++++ b/src/NVMeSubsys.hpp
+@@ -81,4 +81,7 @@ class NVMeSubsystem : public std::enable_shared_from_this<NVMeSubsystem>
+ // a counter to skip health poll when NVMe subsystem becomes Unavailable
+ unsigned UnavailableCount = 0;
+ static constexpr unsigned UnavailableMaxCount = 60;
++
++ // process Secondary controller and start controllers and the associated Plugin
++ void processSecondaryControllerList(nvme_secondary_ctrl_list* secCntlrList);
+ };
+--
+2.41.0.487.g6d72f3e995-goog
+
diff --git a/recipes-phosphor/sensors/dbus-sensors_%.bbappend b/recipes-phosphor/sensors/dbus-sensors_%.bbappend
index 8bed015..7da9773 100644
--- a/recipes-phosphor/sensors/dbus-sensors_%.bbappend
+++ b/recipes-phosphor/sensors/dbus-sensors_%.bbappend
@@ -60,6 +60,7 @@
file://0044-nvmesensor-add-markAvailable-with-adaptive-timer.patch \
file://0045-nvmesensor-improve-handling-of-config-change.patch \
file://0046-nvmesensor-release-resources-when-exit-poll.patch \
+ file://0047-NVMed-Enable-Primary-controller-when-SC-is-empty.patch \
file://0048-NVMe-Add-the-NVMe-Admin-interface-within-the-repo.patch \
"
PACKAGECONFIG[nvmesensor] = "-Dnvme=enabled, -Dnvme=disabled, libnvme"