| 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 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. |
| |
| Signed-off-by: Hao Jiang <jianghao@google.com> |
| Change-Id: I7d8f56751a4b8594ebadbef364309d5e9b8ff52f |
| --- |
| src/NVMeIntf.hpp | 48 ++++++ |
| src/NVMeMi.cpp | 387 +++++++++++++++++++++++++---------------------- |
| 2 files changed, 257 insertions(+), 178 deletions(-) |
| |
| diff --git a/src/NVMeIntf.hpp b/src/NVMeIntf.hpp |
| index 0a745f1..a8cbfad 100644 |
| --- a/src/NVMeIntf.hpp |
| +++ b/src/NVMeIntf.hpp |
| @@ -108,6 +108,54 @@ class NVMeBasicIntf |
| class NVMeMiIntf |
| { |
| public: |
| + constexpr static std::string_view statusToString(nvme_mi_resp_status status) |
| + { |
| + switch (status) |
| + { |
| + case NVME_MI_RESP_SUCCESS: |
| + return "success"; |
| + case NVME_MI_RESP_MPR: |
| + return "More Processing Required"; |
| + case NVME_MI_RESP_INTERNAL_ERR: |
| + return "Internal Error"; |
| + case NVME_MI_RESP_INVALID_OPCODE: |
| + return "Invalid command opcode"; |
| + case NVME_MI_RESP_INVALID_PARAM: |
| + return "Invalid command parameter"; |
| + case NVME_MI_RESP_INVALID_CMD_SIZE: |
| + return "Invalid command size"; |
| + case NVME_MI_RESP_INVALID_INPUT_SIZE: |
| + return "Invalid command input data size"; |
| + case NVME_MI_RESP_ACCESS_DENIED: |
| + return "Access Denied"; |
| + case NVME_MI_RESP_VPD_UPDATES_EXCEEDED: |
| + return "More VPD updates than allowed"; |
| + case NVME_MI_RESP_PCIE_INACCESSIBLE: |
| + return "PCIe functionality currently unavailable"; |
| + case NVME_MI_RESP_MEB_SANITIZED: |
| + return "MEB has been cleared due to sanitize"; |
| + case NVME_MI_RESP_ENC_SERV_FAILURE: |
| + return "Enclosure services process failed"; |
| + case NVME_MI_RESP_ENC_SERV_XFER_FAILURE: |
| + return "Transfer with enclosure services failed"; |
| + case NVME_MI_RESP_ENC_FAILURE: |
| + return "Unreoverable enclosure failure"; |
| + case NVME_MI_RESP_ENC_XFER_REFUSED: |
| + return "Enclosure services transfer refused"; |
| + case NVME_MI_RESP_ENC_FUNC_UNSUP: |
| + return "Unsupported enclosure services function"; |
| + case NVME_MI_RESP_ENC_SERV_UNAVAIL: |
| + return "Enclosure services unavailable"; |
| + case NVME_MI_RESP_ENC_DEGRADED: |
| + return "Noncritical failure detected by enc. services"; |
| + case NVME_MI_RESP_SANITIZE_IN_PROGRESS: |
| + return "Command prohibited during sanitize"; |
| + default: |
| + return ""; |
| + } |
| + return ""; |
| + } |
| + |
| virtual int getNID() const = 0; |
| virtual int getEID() const = 0; |
| virtual void miSubsystemHealthStatusPoll( |
| diff --git a/src/NVMeMi.cpp b/src/NVMeMi.cpp |
| index f66ec57..f597d8c 100644 |
| --- a/src/NVMeMi.cpp |
| +++ b/src/NVMeMi.cpp |
| @@ -80,7 +80,6 @@ NVMeMi::NVMeMi(boost::asio::io_context& io, sdbusplus::bus_t& dbus, int bus, |
| break; |
| } |
| } |
| - |
| } |
| }); |
| } |
| @@ -139,7 +138,7 @@ void NVMeMi::miSubsystemHealthStatusPoll( |
| nvme_mi_nvm_ss_health_status ss_health; |
| auto rc = nvme_mi_mi_subsystem_health_status_poll(self->nvmeEP, |
| true, &ss_health); |
| - if (rc) |
| + if (rc < 0) |
| { |
| |
| std::cerr << "fail to subsystem_health_status_poll: " |
| @@ -150,6 +149,18 @@ void NVMeMi::miSubsystemHealthStatusPoll( |
| }); |
| return; |
| } |
| + else if (rc > 0) |
| + { |
| + 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([cb{std::move(cb)}]() { |
| + cb(std::make_error_code(std::errc::bad_message), nullptr); |
| + }); |
| + return; |
| + } |
| + |
| self->io.post( |
| [cb{std::move(cb)}, ss_health{std::move(ss_health)}]() mutable { |
| cb({}, &ss_health); |
| @@ -184,9 +195,21 @@ void NVMeMi::miScanCtrl(std::function<void(const std::error_code&, |
| { |
| post([self{shared_from_this()}, cb{std::move(cb)}]() { |
| int rc = nvme_mi_scan_ep(self->nvmeEP, true); |
| - if (rc) |
| + if (rc < 0) |
| + { |
| + std::cerr << "fail to scan controllers: " |
| + << std::strerror(errno) << std::endl; |
| + self->io.post([cb{std::move(cb)}]() { |
| + cb(std::make_error_code(static_cast<std::errc>(errno)), {}); |
| + }); |
| + return; |
| + } |
| + else if (rc > 0) |
| { |
| - std::cerr << "fail to scan controllers" << std::endl; |
| + std::string_view errMsg = |
| + statusToString(static_cast<nvme_mi_resp_status>(rc)); |
| + std::cerr << "fail to scan controllers: " << errMsg |
| + << std::endl; |
| self->io.post([cb{std::move(cb)}]() { |
| cb(std::make_error_code(std::errc::bad_message), {}); |
| }); |
| @@ -272,7 +295,7 @@ void NVMeMi::adminIdentify( |
| rc = nvme_mi_admin_identify(ctrl, &args); |
| } |
| } |
| - if (rc) |
| + if (rc < 0) |
| { |
| std::cerr << "fail to do nvme identify: " |
| << std::strerror(errno) << std::endl; |
| @@ -281,6 +304,17 @@ void NVMeMi::adminIdentify( |
| }); |
| return; |
| } |
| + else if (rc > 0) |
| + { |
| + std::string_view errMsg = |
| + statusToString(static_cast<nvme_mi_resp_status>(rc)); |
| + std::cerr << "fail to do nvme identify: " << errMsg |
| + << std::endl; |
| + self->io.post([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()}; |
| @@ -307,8 +341,8 @@ 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) |
| -void getTelemetryLog(nvme_mi_ctrl_t ctrl, bool host, bool create, |
| - std::vector<uint8_t>& data) |
| +int getTelemetryLog(nvme_mi_ctrl_t ctrl, bool host, bool create, |
| + std::vector<uint8_t>& data) |
| { |
| int rc = 0; |
| data.resize(sizeof(nvme_telemetry_log)); |
| @@ -324,19 +358,18 @@ void getTelemetryLog(nvme_mi_ctrl_t ctrl, bool host, bool create, |
| if (rc) |
| { |
| std::cerr << "failed to create telemetry host log" << std::endl; |
| - throw std::system_error(errno, std::generic_category()); |
| + return rc; |
| } |
| - return; |
| - } |
| - else |
| - { |
| - rc = func(ctrl, false, 0, sizeof(log), &log); |
| + return 0; |
| } |
| + |
| + rc = func(ctrl, false, 0, sizeof(log), &log); |
| + |
| if (rc) |
| { |
| std::cerr << "failed to retain telemetry log for " |
| << (host ? "host" : "ctrl") << std::endl; |
| - throw std::system_error(errno, std::generic_category()); |
| + return rc; |
| } |
| |
| long size = |
| @@ -349,8 +382,9 @@ void getTelemetryLog(nvme_mi_ctrl_t ctrl, bool host, bool create, |
| { |
| std::cerr << "failed to get full telemetry log for " |
| << (host ? "host" : "ctrl") << std::endl; |
| - throw std::system_error(errno, std::generic_category()); |
| + return rc; |
| } |
| + return 0; |
| } |
| |
| void NVMeMi::adminGetLogPage( |
| @@ -372,200 +406,197 @@ void NVMeMi::adminGetLogPage( |
| post([ctrl, nsid, lid, lsp, lsi, self{shared_from_this()}, |
| cb{std::move(cb)}]() { |
| std::vector<uint8_t> data; |
| - try |
| + |
| + int rc = 0; |
| + switch (lid) |
| { |
| - switch (lid) |
| + case NVME_LOG_LID_ERROR: |
| { |
| - case NVME_LOG_LID_ERROR: |
| + data.resize(nvme_mi_xfer_size); |
| + // The number of entries for most recent error logs. |
| + // Currently we only do one nvme mi transfer for the |
| + // error log to avoid blocking other tasks |
| + static constexpr int num = |
| + nvme_mi_xfer_size / sizeof(nvme_error_log_page); |
| + nvme_error_log_page* log = |
| + reinterpret_cast<nvme_error_log_page*>(data.data()); |
| + |
| + rc = nvme_mi_admin_get_log_error(ctrl, num, false, log); |
| + if (rc) |
| { |
| - data.resize(nvme_mi_xfer_size); |
| - // The number of entries for most recent error logs. |
| - // Currently we only do one nvme mi transfer for the |
| - // error log to avoid blocking other tasks |
| - static constexpr int num = |
| - nvme_mi_xfer_size / sizeof(nvme_error_log_page); |
| - nvme_error_log_page* log = |
| - reinterpret_cast<nvme_error_log_page*>(data.data()); |
| - |
| - int rc = |
| - nvme_mi_admin_get_log_error(ctrl, num, false, log); |
| - if (rc) |
| - { |
| - std::cerr << "fail to get error log" << std::endl; |
| - throw std::system_error(std::make_error_code( |
| - std::errc::invalid_argument)); |
| - } |
| + std::cerr << "fail to get error log" << std::endl; |
| + break; |
| } |
| - break; |
| - case NVME_LOG_LID_SMART: |
| + } |
| + break; |
| + case NVME_LOG_LID_SMART: |
| + { |
| + data.resize(sizeof(nvme_smart_log)); |
| + nvme_smart_log* log = |
| + reinterpret_cast<nvme_smart_log*>(data.data()); |
| + rc = nvme_mi_admin_get_log_smart(ctrl, nsid, false, log); |
| + if (rc) |
| { |
| - data.resize(sizeof(nvme_smart_log)); |
| - nvme_smart_log* log = |
| - reinterpret_cast<nvme_smart_log*>(data.data()); |
| - int rc = |
| - nvme_mi_admin_get_log_smart(ctrl, nsid, false, log); |
| - if (rc) |
| - { |
| - std::cerr << "fail to get smart log" << std::endl; |
| - throw std::system_error(std::make_error_code( |
| - std::errc::invalid_argument)); |
| - } |
| + std::cerr << "fail to get smart log" << std::endl; |
| + break; |
| } |
| - break; |
| - case NVME_LOG_LID_FW_SLOT: |
| + } |
| + break; |
| + case NVME_LOG_LID_FW_SLOT: |
| + { |
| + data.resize(sizeof(nvme_firmware_slot)); |
| + nvme_firmware_slot* log = |
| + reinterpret_cast<nvme_firmware_slot*>(data.data()); |
| + rc = nvme_mi_admin_get_log_fw_slot(ctrl, false, log); |
| + if (rc) |
| { |
| - data.resize(sizeof(nvme_firmware_slot)); |
| - nvme_firmware_slot* log = |
| - reinterpret_cast<nvme_firmware_slot*>(data.data()); |
| - int rc = |
| - nvme_mi_admin_get_log_fw_slot(ctrl, false, log); |
| - if (rc) |
| - { |
| - std::cerr << "fail to get firmware slot" |
| - << std::endl; |
| - throw std::system_error(std::make_error_code( |
| - std::errc::invalid_argument)); |
| - } |
| + std::cerr << "fail to get firmware slot" << std::endl; |
| + break; |
| } |
| - break; |
| - case NVME_LOG_LID_CMD_EFFECTS: |
| + } |
| + break; |
| + case NVME_LOG_LID_CMD_EFFECTS: |
| + { |
| + data.resize(sizeof(nvme_cmd_effects_log)); |
| + nvme_cmd_effects_log* log = |
| + reinterpret_cast<nvme_cmd_effects_log*>(data.data()); |
| + |
| + // nvme rev 1.3 doesn't support csi, |
| + // set to default csi = NVME_CSI_NVM |
| + rc = nvme_mi_admin_get_log_cmd_effects(ctrl, NVME_CSI_NVM, |
| + log); |
| + if (rc) |
| { |
| - data.resize(sizeof(nvme_cmd_effects_log)); |
| - nvme_cmd_effects_log* log = |
| - reinterpret_cast<nvme_cmd_effects_log*>( |
| - data.data()); |
| - |
| - // nvme rev 1.3 doesn't support csi, |
| - // set to default csi = NVME_CSI_NVM |
| - int rc = nvme_mi_admin_get_log_cmd_effects( |
| - ctrl, NVME_CSI_NVM, log); |
| - if (rc) |
| - { |
| - std::cerr |
| - << "fail to get cmd supported and effects log" |
| - << std::endl; |
| - throw std::system_error(std::make_error_code( |
| - std::errc::invalid_argument)); |
| - } |
| + std::cerr << "fail to get cmd supported and effects log" |
| + << std::endl; |
| + break; |
| } |
| - break; |
| - case NVME_LOG_LID_DEVICE_SELF_TEST: |
| + } |
| + break; |
| + case NVME_LOG_LID_DEVICE_SELF_TEST: |
| + { |
| + data.resize(sizeof(nvme_self_test_log)); |
| + nvme_self_test_log* log = |
| + reinterpret_cast<nvme_self_test_log*>(data.data()); |
| + rc = nvme_mi_admin_get_log_device_self_test(ctrl, log); |
| + if (rc) |
| { |
| - data.resize(sizeof(nvme_self_test_log)); |
| - nvme_self_test_log* log = |
| - reinterpret_cast<nvme_self_test_log*>(data.data()); |
| - int rc = |
| - nvme_mi_admin_get_log_device_self_test(ctrl, log); |
| - if (rc) |
| - { |
| - std::cerr << "fail to get device self test log" |
| - << std::endl; |
| - throw std::system_error(std::make_error_code( |
| - std::errc::invalid_argument)); |
| - } |
| + std::cerr << "fail to get device self test log" |
| + << std::endl; |
| + break; |
| } |
| - break; |
| - case NVME_LOG_LID_CHANGED_NS: |
| + } |
| + break; |
| + case NVME_LOG_LID_CHANGED_NS: |
| + { |
| + data.resize(sizeof(nvme_ns_list)); |
| + nvme_ns_list* log = |
| + reinterpret_cast<nvme_ns_list*>(data.data()); |
| + rc = |
| + nvme_mi_admin_get_log_changed_ns_list(ctrl, false, log); |
| + if (rc) |
| { |
| - data.resize(sizeof(nvme_ns_list)); |
| - nvme_ns_list* log = |
| - reinterpret_cast<nvme_ns_list*>(data.data()); |
| - int rc = nvme_mi_admin_get_log_changed_ns_list( |
| - ctrl, false, log); |
| - if (rc) |
| - { |
| - std::cerr << "fail to get changed namespace list" |
| - << std::endl; |
| - throw std::system_error(std::make_error_code( |
| - std::errc::invalid_argument)); |
| - } |
| + std::cerr << "fail to get changed namespace list" |
| + << std::endl; |
| + break; |
| } |
| - break; |
| - case NVME_LOG_LID_TELEMETRY_HOST: |
| - // fall through to NVME_LOG_LID_TELEMETRY_CTRL |
| - case NVME_LOG_LID_TELEMETRY_CTRL: |
| + } |
| + break; |
| + case NVME_LOG_LID_TELEMETRY_HOST: |
| + // 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) |
| { |
| - bool host = false; |
| - bool create = false; |
| - if (lid == NVME_LOG_LID_TELEMETRY_HOST) |
| + host = true; |
| + if (lsp == NVME_LOG_TELEM_HOST_LSP_CREATE) |
| { |
| - 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; |
| - throw std::system_error(std::make_error_code( |
| - std::errc::invalid_argument)); |
| - } |
| + create = true; |
| } |
| - else |
| + else if (lsp == NVME_LOG_TELEM_HOST_LSP_RETAIN) |
| { |
| - host = false; |
| + create = false; |
| } |
| - |
| - getTelemetryLog(ctrl, host, create, data); |
| - } |
| - break; |
| - case NVME_LOG_LID_RESERVATION: |
| - { |
| - data.resize(sizeof(nvme_resv_notification_log)); |
| - nvme_resv_notification_log* log = |
| - reinterpret_cast<nvme_resv_notification_log*>( |
| - data.data()); |
| - |
| - int rc = |
| - nvme_mi_admin_get_log_reservation(ctrl, false, log); |
| - if (rc) |
| + else |
| { |
| - std::cerr << "fail to get reservation " |
| - "notification log" |
| + std::cerr << "invalid lsp for telemetry host log" |
| << std::endl; |
| - throw std::system_error(std::make_error_code( |
| - std::errc::invalid_argument)); |
| + rc = -1; |
| + errno = EINVAL; |
| + break; |
| } |
| } |
| - break; |
| - case NVME_LOG_LID_SANITIZE: |
| + else |
| { |
| - data.resize(sizeof(nvme_sanitize_log_page)); |
| - nvme_sanitize_log_page* log = |
| - reinterpret_cast<nvme_sanitize_log_page*>( |
| - data.data()); |
| - |
| - int rc = |
| - nvme_mi_admin_get_log_sanitize(ctrl, false, log); |
| - if (rc) |
| - { |
| - std::cerr << "fail to get sanitize status log" |
| - << std::endl; |
| - throw std::system_error(std::make_error_code( |
| - std::errc::invalid_argument)); |
| - } |
| + host = false; |
| } |
| - break; |
| - default: |
| + |
| + rc = getTelemetryLog(ctrl, host, create, data); |
| + } |
| + break; |
| + case NVME_LOG_LID_RESERVATION: |
| + { |
| + data.resize(sizeof(nvme_resv_notification_log)); |
| + nvme_resv_notification_log* log = |
| + reinterpret_cast<nvme_resv_notification_log*>( |
| + data.data()); |
| + |
| + int rc = |
| + nvme_mi_admin_get_log_reservation(ctrl, false, log); |
| + if (rc) |
| + { |
| + std::cerr << "fail to get reservation " |
| + "notification log" |
| + << std::endl; |
| + break; |
| + } |
| + } |
| + break; |
| + case NVME_LOG_LID_SANITIZE: |
| + { |
| + data.resize(sizeof(nvme_sanitize_log_page)); |
| + nvme_sanitize_log_page* log = |
| + reinterpret_cast<nvme_sanitize_log_page*>(data.data()); |
| + |
| + int rc = nvme_mi_admin_get_log_sanitize(ctrl, false, log); |
| + if (rc) |
| { |
| - std::cerr << "unknown lid for GetLogPage" << std::endl; |
| - throw std::system_error( |
| - std::make_error_code(std::errc::invalid_argument)); |
| + std::cerr << "fail to get sanitize status log" |
| + << std::endl; |
| + break; |
| } |
| } |
| + break; |
| + default: |
| + { |
| + std::cerr << "unknown lid for GetLogPage" << std::endl; |
| + rc = -1; |
| + errno = EINVAL; |
| + } |
| } |
| - catch (const std::system_error& e) |
| + |
| + if (rc < 0) |
| { |
| - self->io.post( |
| - [cb{std::move(cb)}, ec = e.code()]() { cb(ec, {}); }); |
| + std::cerr << "fail to get log page: " << std::strerror(errno) |
| + << std::endl; |
| + self->io.post([cb{std::move(cb)}]() { |
| + cb(std::make_error_code(static_cast<std::errc>(errno)), {}); |
| + }); |
| return; |
| } |
| + else if (rc > 0) |
| + { |
| + std::string_view errMsg = |
| + statusToString(static_cast<nvme_mi_resp_status>(rc)); |
| + std::cerr << "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; |
| + }); |
| + } |
| + |
| self->io.post([cb{std::move(cb)}, data{std::move(data)}]() mutable { |
| std::span<uint8_t> span{data.data(), data.size()}; |
| cb({}, span); |
| @@ -622,7 +653,7 @@ void NVMeMi::adminXfer( |
| req.size() - sizeof(nvme_mi_admin_req_hdr), |
| respHeader, respDataOffset, &respDataSize); |
| |
| - if (rc) |
| + if (rc < 0) |
| { |
| std::cerr << "failed to nvme_mi_admin_xfer" << std::endl; |
| self->io.post([cb{std::move(cb)}]() { |
| -- |
| 2.34.1 |
| |