nvmesensor: Update MTU and frequency for MI ports

This CL adds the support to change the local and remote MTU
to maximum supported by the endpoint. Also, change the frequency to
400kHz.

Tested: https://paste.googleplex.com/5801515456397312
Google-Bug-Id: 272527823

Change-Id: Iecd944c8c1ffa811d1c41be90d21ad2d3d7fb7fd
Signed-off-by: Muhammad Usama <muhammadusama@google.com>
diff --git a/recipes-phosphor/sensors/dbus-sensors/0053-nvmesensor-Update-MTU-and-frequency-for-MI-ports.patch b/recipes-phosphor/sensors/dbus-sensors/0053-nvmesensor-Update-MTU-and-frequency-for-MI-ports.patch
new file mode 100644
index 0000000..267194f
--- /dev/null
+++ b/recipes-phosphor/sensors/dbus-sensors/0053-nvmesensor-Update-MTU-and-frequency-for-MI-ports.patch
@@ -0,0 +1,836 @@
+From 82fd2fce97aac275934d8dd60d858cf09138ad8a Mon Sep 17 00:00:00 2001
+From: Muhammad Usama <muhammadusama@google.com>
+Date: Tue, 7 Nov 2023 21:16:50 +0000
+Subject: [PATCH] nvmesensor: Update MTU and frequency for MI ports
+
+This CL adds the support to change the local and remote MTU
+to maximum supported by the endpoint. Also, change the frequency to
+400kHz.
+
+Signed-off-by: Muhammad Usama <muhammadusama@google.com>
+---
+ src/NVMeIntf.hpp       |  11 +-
+ src/NVMeMi.cpp         | 500 +++++++++++++++++++++++++++++++++--------
+ src/NVMeMi.hpp         |  47 +++-
+ src/NVMeSensorMain.cpp |   3 +
+ 4 files changed, 453 insertions(+), 108 deletions(-)
+
+diff --git a/src/NVMeIntf.hpp b/src/NVMeIntf.hpp
+index 20ffda7..2a17106 100644
+--- a/src/NVMeIntf.hpp
++++ b/src/NVMeIntf.hpp
+@@ -167,6 +167,8 @@ class NVMeMiIntf
+                                       const std::vector<nvme_mi_ctrl_t>&)>
+                        cb) = 0;
+ 
++    virtual void initMCTP() = 0;
++
+     virtual ~NVMeMiIntf() = default;
+ 
+     virtual void adminIdentify(
+@@ -184,9 +186,10 @@ class NVMeMiIntf
+                                std::function<void(const std::error_code&,
+                                                   nvme_status_field)>&& cb) = 0;
+ 
+-    virtual void adminFwDownload(nvme_mi_ctrl_t ctrl, std::string firmwarefile,
+-                               std::function<void(const std::error_code&,
+-                                                  nvme_status_field)>&& cb) = 0;
++    virtual void adminFwDownload(
++        nvme_mi_ctrl_t ctrl, std::string firmwarefile,
++        std::function<void(const std::error_code&, nvme_status_field)>&&
++            cb) = 0;
+ 
+     virtual void adminSecuritySend(
+         nvme_mi_ctrl_t ctrl, uint8_t proto, uint16_t proto_specific,
+@@ -198,7 +201,7 @@ class NVMeMiIntf
+         uint32_t transfer_length,
+         std::function<void(const std::error_code&, int nvme_status,
+                            const std::span<uint8_t> data)>&& cb) = 0;
+-    
++
+     virtual void adminNonDataCmd(
+         nvme_mi_ctrl_t ctrl, uint8_t opcode, uint32_t cdw1, uint32_t cdw2,
+         uint32_t cdw3, uint32_t cdw10, uint32_t cdw11, uint32_t cdw12,
+diff --git a/src/NVMeMi.cpp b/src/NVMeMi.cpp
+index a8b56ed..bff9fdb 100644
+--- a/src/NVMeMi.cpp
++++ b/src/NVMeMi.cpp
+@@ -19,14 +19,16 @@ constexpr int tcgDefaultTimeoutMS = 20 * 1000;
+ NVMeMi::NVMeMi(boost::asio::io_context& io,
+                std::shared_ptr<sdbusplus::asio::connection> conn, int bus,
+                int addr, bool singleThreadMode, PowerState readState) :
+-    io(io),
+-    conn(conn), dbus(*conn.get()), bus(bus), addr(addr), readState(readState)
++    io(io), conn(conn), dbus(*conn.get()), bus(bus), addr(addr),
++    readState(readState)
+ {
+     // reset to unassigned nid/eid and endpoint
+     nid = -1;
+     eid = 0;
++    mtu = 64;
+     mctpPath.erase();
+     nvmeEP = nullptr;
++    mctpStatus = Status::Reset;
+ 
+     // set update the worker thread
+     if (!nvmeRoot)
+@@ -76,89 +78,123 @@ NVMeMi::NVMeMi(boost::asio::io_context& io,
+             }
+         });
+     }
+-
+-    // TODO: check the powerstate.
+-    initMCTP();
+ }
+ 
+ void NVMeMi::initMCTP()
+ {
+-    // already initiated
+-    if (isMCTPconnect())
++    // already established
++    if (mctpStatus == Status::Connected)
+     {
+         return;
+     }
+ 
+-    // 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++)
++    if (mctpStatus == Status::Reset)
+     {
+-        try
++        // 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++)
+         {
+-            auto msg = dbus.new_method_call(
+-                "xyz.openbmc_project.MCTP", "/xyz/openbmc_project/mctp",
+-                "au.com.CodeConstruct.MCTP", "SetupEndpoint");
++            try
++            {
++                auto msg = dbus.new_method_call(
++                    "xyz.openbmc_project.MCTP", "/xyz/openbmc_project/mctp",
++                    "au.com.CodeConstruct.MCTP", "SetupEndpoint");
+ 
+-            msg.append("mctpi2c" + std::to_string(bus));
+-            msg.append(std::vector<uint8_t>{static_cast<uint8_t>(addr)});
+-            auto reply = msg.call(); // throw SdBusError
++                msg.append("mctpi2c" + std::to_string(bus));
++                msg.append(std::vector<uint8_t>{static_cast<uint8_t>(addr)});
++                auto reply = msg.call(); // throw SdBusError
+ 
+-            reply.read(eid);
+-            reply.read(nid);
+-            reply.read(mctpPath);
+-            break;
+-        }
+-        catch (const std::exception& e)
+-        {
+-            if (i < 5)
+-            {
+-                std::cerr << "[bus: " << bus << ", addr: " << addr << "]"
+-                          << "retry to SetupEndpoint: " << e.what()
+-                          << std::endl;
++                reply.read(eid);
++                reply.read(nid);
++                reply.read(mctpPath);
++                break;
+             }
+-            else
++            catch (const std::exception& e)
+             {
+-                nid = -1;
+-                eid = 0;
+-                mctpPath.erase();
+-                nvmeEP = nullptr;
+-                std::cerr << "[bus: " << bus << ", addr: " << addr << "]"
+-                          << "fail to init MCTP endpoint: " << e.what()
+-                          << std::endl;
+-                return;
++                if (i < 5)
++                {
++                    std::cerr << "[bus: " << bus << ", addr: " << addr << "]"
++                              << "retry to SetupEndpoint: " << e.what()
++                              << std::endl;
++                }
++                else
++                {
++                    nid = -1;
++                    eid = 0;
++                    mtu = 64;
++                    mctpPath.erase();
++                    nvmeEP = nullptr;
++                    std::cerr << "[bus: " << bus << ", addr: " << addr << "]"
++                              << "fail to init MCTP endpoint: " << e.what()
++                              << std::endl;
++                    return;
++                }
+             }
+         }
++
++        // open mctp endpoint
++        nvmeEP = nvme_mi_open_mctp(nvmeRoot, nid, eid);
++        if (nvmeEP == nullptr)
++        {
++            nid = -1;
++            eid = 0;
++            mtu = 64;
++            // MCTPd won't expect to delete the ep object, just to erase the
++            // record here.
++            mctpPath.erase();
++            nvmeEP = nullptr;
++            std::cerr << "[bus: " << bus << ", addr: " << addr << "]"
++                      << "can't open MCTP endpoint "
++                      << std::to_string(nid) + ":" + std::to_string(eid)
++                      << std::endl;
++            return;
++        }
++        // 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.
++        mctpStatus = Status::Initiated;
+     }
+ 
+-    // open mctp endpoint
+-    nvmeEP = nvme_mi_open_mctp(nvmeRoot, nid, eid);
+-    if (nvmeEP == nullptr)
++    if (mctpStatus == Status::Initiated)
+     {
+-        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 << "[bus: " << bus << ", addr: " << addr << "]"
+-                  << "can't open MCTP endpoint "
+-                  << std::to_string(nid) + ":" + std::to_string(eid)
+-                  << std::endl;
++        auto timer = std::make_shared<boost::asio::steady_timer>(
++            io, std::chrono::milliseconds(500));
++        timer->async_wait([this, timer](boost::system::error_code ec) {
++            if (ec)
++            {
++                return;
++            }
++            miSetMCTPConfiguration(
++                [self{shared_from_this()}](const std::error_code& ec) {
++                if (ec)
++                {
++                    std::cerr << "[bus: " << self->bus
++                              << ", addr: " << self->addr << "]"
++                              << "Failed setting up MTU for the MCTP endpoint. "
++                              << std::to_string(self->nid) + ":" +
++                                     std::to_string(self->eid)
++                              << std::endl;
++                    self->initMCTP();
++                    return;
++                }
++                auto rc = self->miConfigureLocalRouteMtu();
++                if (rc)
++                {
++                    self->initMCTP();
++                    return;
++                }
++                self->mctpStatus = Status::Connected;
++            });
++        });
+     }
+-    // 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;
+ }
+ 
+ void NVMeMi::closeMCTP()
+ {
+-    if (!isMCTPconnect())
++    if (mctpStatus == Status::Reset)
+     {
+         return;
+     }
+@@ -175,15 +211,17 @@ void NVMeMi::closeMCTP()
+ 
+     nid = -1;
+     eid = 0;
++    mtu = 64;
+     mctpPath.erase();
+     nvmeEP = nullptr;
++    mctpStatus = Status::Reset;
+     std::cerr << "[bus: " << bus << ", addr: " << addr << "]"
+               << "finish MCTP closure." << std::endl;
+ }
+ 
+ bool NVMeMi::isMCTPconnect() const
+ {
+-    return nid >= 0 && !mctpPath.empty() && nvmeEP != nullptr;
++    return mctpStatus == Status::Connected;
+ }
+ 
+ NVMeMi::Worker::Worker()
+@@ -268,16 +306,285 @@ std::error_code NVMeMi::try_post(std::function<void(void)>&& func)
+     return std::error_code();
+ }
+ 
+-void NVMeMi::miSubsystemHealthStatusPoll(
+-    std::function<void(const std::error_code&, nvme_mi_nvm_ss_health_status*)>&&
+-        cb)
++void NVMeMi::miReadDataPort(uint8_t port_id, uint8_t num_ports,
++                            std::function<void(const std::error_code&)>&& cb)
+ {
+     if (!nvmeEP)
+     {
+         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));
++        });
++        mctpStatus = Status::Reset;
++        return;
++    }
++    try
++    {
++        post([port_id, num_ports, self{shared_from_this()},
++              cb{std::move(cb)}]() mutable {
++            struct nvme_mi_read_port_info portInfo;
++            auto rc = nvme_mi_mi_read_mi_data_port(self->nvmeEP, port_id,
++                                                   &portInfo);
++            if (rc)
++            {
++                /* PCIe port might not be present right after DC cycle. */
++                std::cerr << "[bus: " << self->bus << ", addr: " << self->addr
++                          << ", eid: " << static_cast<int>(self->eid)
++                          << "] failed reading port info for port_id: "
++                          << unsigned(port_id) << std::endl;
++            }
++            // SMBus ports = 0x2
++            else if (portInfo.portt == 0x2)
++            {
++                uint16_t supportedMtu = portInfo.mmctptus;
++                uint8_t supportedFreq = portInfo.smb.mme_freq;
++                self->miConfigureRemoteMCTP(port_id, supportedMtu,
++                                            supportedFreq, std::move(cb));
++                return;
++            }
++
++            if (port_id < num_ports)
++            {
++                port_id++;
++                self->miReadDataPort(port_id, num_ports, std::move(cb));
++                return;
++            }
++
++            std::cerr << "[bus: " << self->bus << ", addr: " << self->addr
++                      << ", eid: " << static_cast<int>(self->eid)
++                      << "] did not have any SMBus port\n";
+ 
++            self->io.post([cb{std::move(cb)}]() {
++                cb(std::make_error_code(std::errc::no_such_device));
++            });
++        });
++    }
++    catch (const std::runtime_error& e)
++    {
++        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));
++        });
++        return;
++    }
++}
++
++void NVMeMi::miConfigureSMBusFrequency(
++    uint8_t port_id, uint8_t max_supported_freq,
++    std::function<void(const std::error_code&)>&& cb)
++{
++    if (!nvmeEP)
++    {
++        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));
++        });
++        mctpStatus = Status::Reset;
++        return;
++    }
++    try
++    {
++        post([port_id, max_supported_freq, self{shared_from_this()},
++              cb{std::move(cb)}]() mutable {
++            enum nvme_mi_config_smbus_freq smbusFreq;
++            auto rc = nvme_mi_mi_config_get_smbus_freq(self->nvmeEP, port_id,
++                                                       &smbusFreq);
++            if (rc)
++            {
++                std::cerr << "[bus: " << self->bus << ", addr: " << self->addr
++                          << ", eid: " << static_cast<int>(self->eid)
++                          << "] failed to get the SMBus frequency "
++                          << std::endl;
++            }
++            else if (smbusFreq == NVME_MI_CONFIG_SMBUS_FREQ_100kHz)
++            {
++                std::cerr << "[bus: " << self->bus << ", addr: " << self->addr
++                          << ", eid: " << static_cast<int>(self->eid)
++                          << "] Setting the SMBus frequency to 400kHz\n";
++                rc = nvme_mi_mi_config_set_smbus_freq(
++                    self->nvmeEP, port_id, NVME_MI_CONFIG_SMBUS_FREQ_400kHz);
++                if (rc)
++                {
++                    std::cerr << "[bus: " << self->bus
++                              << ", addr: " << self->addr
++                              << ", eid: " << static_cast<int>(self->eid)
++                              << "] failed to set the SMBus frequency\n";
++                }
++            }
++
++            if (rc)
++            {
++                self->io.post([cb{std::move(cb)}]() {
++                    cb(std::make_error_code(std::errc::bad_message));
++                });
++                return;
++            }
++            self->io.post([cb{std::move(cb)}]() { cb({}); });
++        });
++    }
++    catch (const std::runtime_error& e)
++    {
++        std::cerr << "[bus: " << bus << ", addr: " << addr
++                  << ", eid: " << static_cast<int>(eid) << "]" << e.what()
++                  << std::endl;
++        return;
++    }
++}
++
++void NVMeMi::miConfigureRemoteMCTP(
++    uint8_t port, uint16_t mtu, uint8_t max_supported_freq,
++    std::function<void(const std::error_code&)>&& cb)
++{
++    if (!nvmeEP)
++    {
++        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));
++        });
++        mctpStatus = Status::Reset;
++        return;
++    }
++    try
++    {
++        post([port, mtu, max_supported_freq, self{shared_from_this()},
++              cb{std::move(cb)}]() mutable {
++            auto rc = nvme_mi_mi_config_set_mctp_mtu(self->nvmeEP, port, mtu);
++            if (rc)
++            {
++                std::cerr << "[bus: " << self->bus << ", addr: " << self->addr
++                          << ", eid: " << static_cast<int>(self->eid) << "]"
++                          << " failed to set remote MCTP MTU for port :"
++                          << unsigned(port) << std::endl;
++                self->io.post([cb{std::move(cb)}]() {
++                    cb(std::make_error_code(std::errc::bad_message));
++                });
++                return;
++            }
++            self->mtu = mtu;
++            if (max_supported_freq >= 2)
++            {
++                self->miConfigureSMBusFrequency(port, max_supported_freq,
++                                                std::move(cb));
++                return;
++            }
++            self->io.post([cb{std::move(cb)}]() { cb({}); });
++        });
++    }
++    catch (const std::runtime_error& e)
++    {
++        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));
++        });
++        return;
++    }
++}
++
++void NVMeMi::miSetMCTPConfiguration(
++    std::function<void(const std::error_code&)>&& cb)
++{
++    if (!nvmeEP)
++    {
++        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));
++        });
++        mctpStatus = Status::Reset;
++        return;
++    }
++    try
++    {
++        post([cb{std::move(cb)}, self{shared_from_this()}]() mutable {
++            struct nvme_mi_read_nvm_ss_info ssInfo;
++            auto rc = nvme_mi_mi_read_mi_data_subsys(self->nvmeEP, &ssInfo);
++            if (rc)
++            {
++                std::cerr << "[bus: " << self->bus << ", addr: " << self->addr
++                          << ", eid: " << static_cast<int>(self->eid) << "]"
++                          << " Failed reading subsystem info " << std::endl;
++                self->io.post([cb{std::move(cb)}]() {
++                    cb(std::make_error_code(std::errc::bad_message));
++                });
++                return;
++            }
++            self->miReadDataPort(0, ssInfo.nump, std::move(cb));
++        });
++    }
++    catch (const std::runtime_error& e)
++    {
++        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));
++        });
++        return;
++    }
++}
++
++int NVMeMi::miConfigureLocalRouteMtu()
++{
++    int i = 0;
++    for (;; i++)
++    {
++        try
++        {
++            auto path = std::string("/xyz/openbmc_project/mctp/") +
++                        std::to_string(nid) + "/" + std::to_string(eid);
++            auto msg = dbus.new_method_call(
++                "xyz.openbmc_project.MCTP", path.c_str(),
++                "au.com.CodeConstruct.MCTP.Endpoint", "SetMTU");
++
++            // 4 bytes for the MCTP header
++            uint32_t mctpMtu = mtu + 4;
++            msg.append(mctpMtu);
++            auto reply = msg.call();
++            std::cerr << "[bus: " << bus << ", addr: " << addr
++                      << ", eid: " << std::to_string(eid)
++                      << "] finished MCTP initialization. MTU: " << mtu
++                      << std::endl;
++            return 0;
++        }
++        catch (const std::exception& e)
++        {
++            if (i < 5)
++            {
++                std::cerr << "[bus: " << bus << ", addr: " << addr << ", eid: "
++                          << "] retry to set MCTP route MTU : " << e.what()
++                          << std::endl;
++            }
++            else
++            {
++                std::cerr << "[bus: " << bus << ", addr: " << addr << ", eid: "
++                          << "] failed to set MCTP route MTU : " << e.what()
++                          << std::endl;
++                return -1;
++            }
++        }
++    }
++}
++
++void NVMeMi::miSubsystemHealthStatusPoll(
++    std::function<void(const std::error_code&, nvme_mi_nvm_ss_health_status*)>&&
++        cb)
++{
++    if (mctpStatus != Status::Connected)
++    {
++        std::cerr << "[bus: " << bus << ", addr: " << addr
++                  << ", eid: " << static_cast<int>(eid) << "]"
++                  << " MCTP connection is not established" << std::endl;
+         io.post([cb{std::move(cb)}]() {
+             cb(std::make_error_code(std::errc::no_such_device), nullptr);
+         });
+@@ -338,16 +645,17 @@ void NVMeMi::miScanCtrl(std::function<void(const std::error_code&,
+                                            const std::vector<nvme_mi_ctrl_t>&)>
+                             cb)
+ {
+-    if (!nvmeEP)
++    if (mctpStatus != Status::Connected)
+     {
+-        std::cerr << "nvme endpoint is invalid" << std::endl;
++        std::cerr << "[bus: " << bus << ", addr: " << addr
++                  << ", eid: " << static_cast<int>(eid) << "]"
++                  << " MCTP connection is not established" << std::endl;
+ 
+         io.post([cb{std::move(cb)}]() {
+-            cb(std::make_error_code(std::errc::no_such_device), {});
++            cb(std::make_error_code(std::errc::not_connected), {});
+         });
+         return;
+     }
+-
+     try
+     {
+         post([self{shared_from_this()}, cb{std::move(cb)}]() {
+@@ -404,11 +712,13 @@ void NVMeMi::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)
+ {
+-    if (!nvmeEP)
++    if (mctpStatus != Status::Connected)
+     {
+-        std::cerr << "nvme endpoint is invalid" << std::endl;
++        std::cerr << "[bus: " << bus << ", addr: " << addr
++                  << ", eid: " << static_cast<int>(eid) << "]"
++                  << " MCTP connection is not established" << std::endl;
+         io.post([cb{std::move(cb)}]() {
+-            cb(std::make_error_code(std::errc::no_such_device), {});
++            cb(std::make_error_code(std::errc::not_connected), {});
+         });
+         return;
+     }
+@@ -635,17 +945,16 @@ void NVMeMi::adminGetLogPage(
+     uint16_t lsi,
+     std::function<void(const std::error_code&, std::span<uint8_t>)>&& cb)
+ {
+-    if (!nvmeEP)
++    if (mctpStatus != Status::Connected)
+     {
+         std::cerr << "[bus: " << bus << ", addr: " << addr
+                   << ", eid: " << static_cast<int>(eid) << "]"
+-                  << "nvme endpoint is invalid" << std::endl;
++                  << " MCTP connection is not established" << std::endl;
+         io.post([cb{std::move(cb)}]() {
+-            cb(std::make_error_code(std::errc::no_such_device), {});
++            cb(std::make_error_code(std::errc::not_connected), {});
+         });
+         return;
+     }
+-
+     try
+     {
+         post([ctrl, nsid, lid, lsp, lsi, self{shared_from_this()},
+@@ -885,13 +1194,13 @@ void NVMeMi::adminXfer(
+     std::function<void(const std::error_code&, const nvme_mi_admin_resp_hdr&,
+                        std::span<uint8_t>)>&& cb)
+ {
+-    if (!nvmeEP)
++    if (mctpStatus != Status::Connected)
+     {
+         std::cerr << "[bus: " << bus << ", addr: " << addr
+                   << ", eid: " << static_cast<int>(eid) << "]"
+-                  << "nvme endpoint is invalid" << std::endl;
++                  << " MCTP connection is not established" << std::endl;
+         io.post([cb{std::move(cb)}]() {
+-            cb(std::make_error_code(std::errc::no_such_device), {}, {});
++            cb(std::make_error_code(std::errc::not_connected), {}, {});
+         });
+         return;
+     }
+@@ -968,13 +1277,13 @@ void NVMeMi::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)
+ {
+-    if (!nvmeEP)
++    if (mctpStatus != Status::Connected)
+     {
+         std::cerr << "[bus: " << bus << ", addr: " << addr
+                   << ", eid: " << static_cast<int>(eid) << "]"
+-                  << "nvme endpoint is invalid" << std::endl;
++                  << " MCTP connection is not established" << std::endl;
+         io.post([cb{std::move(cb)}]() {
+-            cb(std::make_error_code(std::errc::no_such_device),
++            cb(std::make_error_code(std::errc::not_connected),
+                nvme_status_field::NVME_SC_MASK);
+         });
+         return;
+@@ -1047,11 +1356,13 @@ void NVMeMi::adminFwDownloadChunk(
+     int attempt_count,
+     std::function<void(const std::error_code&, nvme_status_field)>&& cb)
+ {
+-    if (!nvmeEP)
++    if (mctpStatus != Status::Connected)
+     {
+-        std::cerr << "nvme endpoint is invalid" << std::endl;
++        std::cerr << "[bus: " << bus << ", addr: " << addr
++                  << ", eid: " << static_cast<int>(eid) << "]"
++                  << " MCTP connection is not established" << std::endl;
+         io.post([cb{std::move(cb)}]() {
+-            cb(std::make_error_code(std::errc::no_such_device),
++            cb(std::make_error_code(std::errc::not_connected),
+                nvme_status_field::NVME_SC_MASK);
+         });
+         return;
+@@ -1258,20 +1569,20 @@ void NVMeMi::adminSecurityReceive(
+ 
+ void NVMeMi::adminNonDataCmd(
+     nvme_mi_ctrl_t ctrl, uint8_t opcode, uint32_t cdw1, uint32_t cdw2,
+-    uint32_t cdw3, uint32_t cdw10, uint32_t cdw11,
+-    uint32_t cdw12, uint32_t cdw13, uint32_t cdw14, uint32_t cdw15,
++    uint32_t cdw3, uint32_t cdw10, uint32_t cdw11, uint32_t cdw12,
++    uint32_t cdw13, uint32_t cdw14, uint32_t cdw15,
+     std::function<void(const std::error_code&, int nvme_status,
+                        uint32_t comption_dw0)>&& cb)
+ {
+-    std::error_code post_err =
+-        try_post([self{shared_from_this()}, ctrl, opcode, cdw1, cdw2, cdw3,
+-             cdw10, cdw11, cdw12, cdw13, cdw14, cdw15, cb{std::move(cb)}]() {
++    std::error_code post_err = try_post(
++        [self{shared_from_this()}, ctrl, opcode, cdw1, cdw2, cdw3, cdw10, cdw11,
++         cdw12, cdw13, cdw14, cdw15, cb{std::move(cb)}]() {
+         uint32_t comption_dw0 = 0;
+         int nvme_status = nvme_mi_admin_admin_passthru(
+             ctrl, opcode, 0, 0, cdw1, cdw2, cdw3, cdw10, cdw11, cdw12, cdw13,
+-            cdw14, cdw15, 0, nullptr, 0, nullptr, 10*1000, &comption_dw0);
+-        self->io.post(
+-            [cb{std::move(cb)}, nvme_errno{errno}, nvme_status, comption_dw0]() mutable {
++            cdw14, cdw15, 0, nullptr, 0, nullptr, 10 * 1000, &comption_dw0);
++        self->io.post([cb{std::move(cb)}, nvme_errno{errno}, nvme_status,
++                       comption_dw0]() mutable {
+             auto err = std::make_error_code(static_cast<std::errc>(nvme_errno));
+             cb(err, nvme_status, comption_dw0);
+         });
+@@ -1280,8 +1591,7 @@ void NVMeMi::adminNonDataCmd(
+     {
+         std::cerr << "[bus: " << bus << ", addr: " << addr
+                   << ", eid: " << static_cast<int>(eid) << "]"
+-                  << "adminNonDataCmd post failed: " << post_err
+-                  << std::endl;
++                  << "adminNonDataCmd post failed: " << post_err << std::endl;
+         io.post([cb{std::move(cb)}, post_err]() { cb(post_err, -1, 0); });
+     }
+ }
+diff --git a/src/NVMeMi.hpp b/src/NVMeMi.hpp
+index 59b48d4..d27d39b 100644
+--- a/src/NVMeMi.hpp
++++ b/src/NVMeMi.hpp
+@@ -9,8 +9,9 @@
+ class NVMeMi : public NVMeMiIntf, public std::enable_shared_from_this<NVMeMi>
+ {
+   public:
+-    NVMeMi(boost::asio::io_context& io, std::shared_ptr<sdbusplus::asio::connection> conn, 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;
+ 
+@@ -43,8 +44,8 @@ class NVMeMi : public NVMeMiIntf, public std::enable_shared_from_this<NVMeMi>
+         override;
+ 
+     void adminFwDownload(nvme_mi_ctrl_t ctrl, std::string firmwarefile,
+-        std::function<void(const std::error_code&, nvme_status_field)>&& cb)
+-        override;
++                         std::function<void(const std::error_code&,
++                                            nvme_status_field)>&& cb) override;
+ 
+     void adminXfer(nvme_mi_ctrl_t ctrl, const nvme_mi_admin_req_hdr& admin_req,
+                    std::span<uint8_t> data, unsigned int timeout_ms,
+@@ -70,6 +71,8 @@ class NVMeMi : public NVMeMiIntf, public std::enable_shared_from_this<NVMeMi>
+         std::function<void(const std::error_code&, int nvme_status,
+                            uint32_t comption_dw0)>&& cb);
+ 
++    void initMCTP() override;
++
+   private:
+     // the transfer size for nvme mi messages.
+     // define in github.com/linux-nvme/libnvme/blob/master/src/nvme/mi.c
+@@ -94,6 +97,7 @@ class NVMeMi : public NVMeMiIntf, public std::enable_shared_from_this<NVMeMi>
+ 
+     int nid;
+     uint8_t eid;
++    uint16_t mtu;
+     std::string mctpPath;
+ 
+     std::mutex mctpMtx;
+@@ -115,6 +119,15 @@ class NVMeMi : public NVMeMiIntf, public std::enable_shared_from_this<NVMeMi>
+         void post(std::function<void(void)>&& func);
+     };
+ 
++    enum class Status
++    {
++        Reset,
++        Initiated,
++        Connected,
++    };
++
++    Status mctpStatus;
++
+     // A map from root bus number to the Worker
+     // This map means to reuse the same worker for all NVMe EP under the same
+     // I2C root bus. There is no real physical concurrency among the i2c/mctp
+@@ -126,10 +139,25 @@ class NVMeMi : public NVMeMiIntf, public std::enable_shared_from_this<NVMeMi>
+     std::shared_ptr<Worker> worker;
+     void post(std::function<void(void)>&& func);
+ 
+-    void initMCTP();
+-
+     void closeMCTP();
+ 
++    void
++        miConfigureRemoteMCTP(uint8_t port, uint16_t mtu,
++                              uint8_t max_supported_freq,
++                              std::function<void(const std::error_code&)>&& cb);
++
++    void miReadDataPort(uint8_t port, uint8_t num_ports,
++                        std::function<void(const std::error_code&)>&& cb);
++
++    void miConfigureSMBusFrequency(
++        uint8_t port_id, uint8_t max_supported_freq,
++        std::function<void(const std::error_code&)>&& cb);
++
++    void miSetMCTPConfiguration(
++        std::function<void(const std::error_code&)>&& cb);
++
++    int miConfigureLocalRouteMtu();
++
+     bool isMCTPconnect() const;
+ 
+     bool readingStateGood() const
+@@ -139,9 +167,10 @@ class NVMeMi : public NVMeMiIntf, public std::enable_shared_from_this<NVMeMi>
+ 
+     std::error_code try_post(std::function<void(void)>&& func);
+ 
+-    void adminFwDownloadChunk(nvme_mi_ctrl_t ctrl, std::string firmwarefile, size_t size,
+-                              size_t offset, int attempt_count,
+-                              std::function<void(const std::error_code&, nvme_status_field)>&& cb);
++    void adminFwDownloadChunk(
++        nvme_mi_ctrl_t ctrl, std::string firmwarefile, size_t size,
++        size_t offset, int attempt_count,
++        std::function<void(const std::error_code&, nvme_status_field)>&& cb);
+ 
+     void getTelemetryLogChuck(
+         nvme_mi_ctrl_t ctrl, bool host, uint64_t offset,
+diff --git a/src/NVMeSensorMain.cpp b/src/NVMeSensorMain.cpp
+index d43f1a1..3874121 100644
+--- a/src/NVMeSensorMain.cpp
++++ b/src/NVMeSensorMain.cpp
+@@ -217,6 +217,9 @@ static void handleConfigurations(
+                     io, dbusConnection, *busNumber, *address, singleThreadMode,
+                     powerState);
+ 
++                auto nvme = std::get<std::shared_ptr<NVMeMiIntf>>(nvmeMi.getInferface());
++                nvme->initMCTP();
++
+                 nvmeInterfaces.emplace(interfacePath, nvmeMi);
+             }
+             catch (std::exception& ex)
+-- 
+2.42.0.869.gea05f2083d-goog
+
diff --git a/recipes-phosphor/sensors/dbus-sensors_%.bbappend b/recipes-phosphor/sensors/dbus-sensors_%.bbappend
index b58e0a4..723f70b 100644
--- a/recipes-phosphor/sensors/dbus-sensors_%.bbappend
+++ b/recipes-phosphor/sensors/dbus-sensors_%.bbappend
@@ -69,6 +69,7 @@
   file://0050-nvmesensor-Add-FirmwareDownload-for-NVMe-devices.patch \
   file://0051-nvmesensor-remove-duplicate-chassis-prefix-in-sensor.patch \
   file://0052-nvmesensor-add-Admin-non-data-command-passthru-DBus-.patch \
+  file://0053-nvmesensor-Update-MTU-and-frequency-for-MI-ports.patch \
 "
 PACKAGECONFIG[nvmesensor] = "-Dnvme=enabled, -Dnvme=disabled, libnvme"
 SYSTEMD_SERVICE:${PN} += "${@bb.utils.contains('PACKAGECONFIG', 'nvmesensor', \