libnvme: Improve libnvme-mi debuggability
Tested:
Before this fix, we only have limited error message:
crc mismatch
After this fix, we have the net/eid/request/timing/rc/errno info:
[mctp: net 1 eid 12] crc mismatch
[mctp: net 1 eid 12] Admin op:0x02, cdw(1:0x0, 10:0x3ff80d8, 11:0x0, 12:0x200 13:0x0, 14:0x0, 15:0x0) T:5000ms, elapsed:333ms, rc:1, errno:0
[mctp: net 1 eid 13] crc mismatch
[mctp: net 1 eid 13] MI op:0x01, cdw0:0x0, cdw1:0x80000000 T:5000ms, elapsed:247ms, rc:1, errno:0
[network: 1, EID: 13 | bus: 8, address: 0x35] fail to subsystem_health_status_poll: More Processing Required
error reading ctemp from subsystem, reason:Bad message
[mctp: net 1 eid 13] Timeout on MCTP socket
[mctp: net 1 eid 13] Admin op:0x02, cdw(1:0x0, 10:0x3ff80d8, 11:0x0, 12:0x2200 13:0x0, 14:0x0, 15:0x0) T:5000ms, elapsed:5005ms, rc:-1, errno:110
[network: 1, EID: 13 | bus: 8, address: 0x35]failed to nvme_mi_admin_xfer
fail to GetLogPage: Connection timed out
Fusion-link: http://fusion2/15f61579-6b22-3afa-bb92-aac5e92dfe83
Google-Bug-Id: 339022737
Change-Id: I6a0bc1ec76a65276717b49cca7a738f11c81c24c
Signed-off-by: Jinliang Wang <jinliangw@google.com>
diff --git a/recipes-connectivity/libnvme/libnvme/0007-mi-check-and-print-OOB-NVMe-MI-command-execution-tim.patch b/recipes-connectivity/libnvme/libnvme/0007-mi-check-and-print-OOB-NVMe-MI-command-execution-tim.patch
deleted file mode 100644
index ecec32e..0000000
--- a/recipes-connectivity/libnvme/libnvme/0007-mi-check-and-print-OOB-NVMe-MI-command-execution-tim.patch
+++ /dev/null
@@ -1,106 +0,0 @@
-From e825dd67cd8bb02a1da8faefd244b2a50dc62dbc Mon Sep 17 00:00:00 2001
-From: Jinliang Wang <jinliangw@google.com>
-Date: Thu, 26 Oct 2023 15:49:34 -0700
-Subject: [PATCH] mi: check and print OOB NVMe-MI command execution time
-
-Check command execution time, if it exceeds WARNING_THRESHOLD
-(3 seconds), print a warning message about the command.
-
-Patch Tracking Bug: b/311315898
-Upstream info / review: N/A
-Upstream-Status: Pending
-Justification: Improve NVMe-MI debuggability
-
-Signed-off-by: Jinliang Wang <jinliangw@google.com>
----
- src/nvme/mi.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 61 insertions(+)
-
-diff --git a/src/nvme/mi.c b/src/nvme/mi.c
-index a41f786..4c5e5eb 100644
---- a/src/nvme/mi.c
-+++ b/src/nvme/mi.c
-@@ -378,10 +378,63 @@ static int nvme_mi_verify_resp_mic(struct nvme_mi_resp *resp)
- return resp->mic != ~crc;
- }
-
-+#define GET_MI_MSG_TYPE(x) ((x >> 3) & 0xF)
-+#define WARNING_THRESHOLD 3 /* seconds */
-+static void check_execution_time(nvme_mi_ep_t ep,
-+ const struct nvme_mi_req *req,
-+ const struct timespec *submit_time)
-+{
-+ struct timespec complete_time = {0, 0};
-+ struct timespec deta_time = {0, 0};
-+ struct nvme_mi_admin_req_hdr *admin_req_hdr = NULL;
-+ struct nvme_mi_mi_req_hdr *mi_req_hdr = NULL;
-+
-+ clock_gettime(CLOCK_MONOTONIC, &complete_time);
-+
-+ timespec_sub(&complete_time, submit_time, &deta_time);
-+ if (deta_time.tv_sec >= WARNING_THRESHOLD)
-+ {
-+ if (req->hdr->type == NVME_MI_MSGTYPE_NVME &&
-+ GET_MI_MSG_TYPE(req->hdr->nmp) == NVME_MI_MT_ADMIN)
-+ {
-+ admin_req_hdr = (struct nvme_mi_admin_req_hdr *)req->hdr;
-+ nvme_msg(ep->root, LOG_WARNING,
-+ "%s, Admin op:0x%02x, cdw(1:0x%x, 10:0x%x, 11:0x%x,"
-+ " 12:0x%x 13:0x%x, 14:0x%x, 15:0x%x) "
-+ "T:%dms, elapsed:%dms\n",
-+ nvme_mi_endpoint_desc(ep),
-+ admin_req_hdr->opcode,
-+ admin_req_hdr->cdw1,
-+ admin_req_hdr->cdw10,
-+ admin_req_hdr->cdw11,
-+ admin_req_hdr->cdw12,
-+ admin_req_hdr->cdw13,
-+ admin_req_hdr->cdw14,
-+ admin_req_hdr->cdw15,
-+ ep->timeout,
-+ (int)(deta_time.tv_sec * 1000 + deta_time.tv_nsec / 1000000));
-+ }
-+ else if (req->hdr->type == NVME_MI_MSGTYPE_NVME &&
-+ GET_MI_MSG_TYPE(req->hdr->nmp) == NVME_MI_MT_MI)
-+ {
-+ mi_req_hdr = (struct nvme_mi_mi_req_hdr *)req->hdr;
-+ nvme_msg(ep->root, LOG_WARNING,
-+ "%s, MI op:0x%02x, cdw0:0x%x, cdw1:0x%x T:%dms, elapsed:%dms\n",
-+ nvme_mi_endpoint_desc(ep),
-+ mi_req_hdr->opcode,
-+ mi_req_hdr->cdw0,
-+ mi_req_hdr->cdw1,
-+ ep->timeout,
-+ (int)(deta_time.tv_sec * 1000 + deta_time.tv_nsec / 1000000));
-+ }
-+ }
-+}
-+
- int nvme_mi_submit(nvme_mi_ep_t ep, struct nvme_mi_req *req,
- struct nvme_mi_resp *resp)
- {
- int rc;
-+ struct timespec submit_time = {0, 0};
-
- if (req->hdr_len < sizeof(struct nvme_mi_msg_hdr)) {
- errno = EINVAL;
-@@ -419,8 +472,16 @@ int nvme_mi_submit(nvme_mi_ep_t ep, struct nvme_mi_req *req,
- if (nvme_mi_ep_has_quirk(ep, NVME_QUIRK_MIN_INTER_COMMAND_TIME))
- nvme_mi_insert_delay(ep);
-
-+ clock_gettime(CLOCK_MONOTONIC, &submit_time);
-+
- rc = ep->transport->submit(ep, req, resp);
-
-+ if ((rc == 0) || (errno == ETIMEDOUT))
-+ {
-+ /* We are interested on commands which succeed or timed out*/
-+ check_execution_time(ep, req, &submit_time);
-+ }
-+
- if (nvme_mi_ep_has_quirk(ep, NVME_QUIRK_MIN_INTER_COMMAND_TIME))
- nvme_mi_record_resp_time(ep);
-
---
-2.43.0.rc0.421.g78406f8d94-goog
-
diff --git a/recipes-connectivity/libnvme/libnvme/0007-mi-use-more-reasonable-log-level.patch b/recipes-connectivity/libnvme/libnvme/0007-mi-use-more-reasonable-log-level.patch
new file mode 100644
index 0000000..2a1ec12
--- /dev/null
+++ b/recipes-connectivity/libnvme/libnvme/0007-mi-use-more-reasonable-log-level.patch
@@ -0,0 +1,140 @@
+From f5f926f50b026ecb65a5d076c5183a5d92d021d5 Mon Sep 17 00:00:00 2001
+From: Jinliang Wang <jinliangw@google.com>
+Date: Fri, 3 May 2024 14:41:18 -0700
+Subject: [PATCH] mi: use more reasonable log level
+
+Most of these conditions should belong to ERROR category.
+
+Patch Tracking Bug: b/311315898
+Upstream info / review: N/A
+Upstream-Status: Pending
+Justification: Improve NVMe-MI debuggability
+
+Signed-off-by: Jinliang Wang <jinliangw@google.com>
+---
+ src/nvme/mi-mctp.c | 10 +++++-----
+ src/nvme/mi.c | 16 ++++++++--------
+ 2 files changed, 13 insertions(+), 13 deletions(-)
+
+diff --git a/src/nvme/mi-mctp.c b/src/nvme/mi-mctp.c
+index a083157..cb77d0d 100644
+--- a/src/nvme/mi-mctp.c
++++ b/src/nvme/mi-mctp.c
+@@ -331,13 +331,13 @@ retry:
+ goto retry;
+ errno_save = errno;
+ nvme_msg(ep->root, LOG_ERR,
+- "Failed polling on MCTP socket: %m");
++ "Failed polling on MCTP socket: %m\n");
+ errno = errno_save;
+ goto out;
+ }
+
+ if (rc == 0) {
+- nvme_msg(ep->root, LOG_DEBUG, "Timeout on MCTP socket");
++ nvme_msg(ep->root, LOG_ERR, "Timeout on MCTP socket\n");
+ errno = ETIMEDOUT;
+ rc = -1;
+ goto out;
+@@ -356,7 +356,7 @@ retry:
+
+
+ if (len == 0) {
+- nvme_msg(ep->root, LOG_WARNING, "No data from MCTP endpoint\n");
++ nvme_msg(ep->root, LOG_ERR, "No data from MCTP endpoint\n");
+ errno = EIO;
+ goto out;
+ }
+@@ -378,7 +378,7 @@ retry:
+
+ /* We can't have header/payload data that isn't a multiple of 4 bytes */
+ if (len & 0x3) {
+- nvme_msg(ep->root, LOG_WARNING,
++ nvme_msg(ep->root, LOG_ERR,
+ "Response message has unaligned length (%zd)!\n",
+ len);
+ errno = EPROTO;
+@@ -391,7 +391,7 @@ retry:
+ * to keep the tag allocated and retry the recvmsg
+ */
+ if (nvme_mi_mctp_resp_is_mpr(resp, len, mic, &mpr_time)) {
+- nvme_msg(ep->root, LOG_DEBUG,
++ nvme_msg(ep->root, LOG_NOTICE,
+ "Received More Processing Required, waiting for response\n");
+
+ /* if the controller hasn't set MPRT, fall back to our command/
+diff --git a/src/nvme/mi.c b/src/nvme/mi.c
+index a41f786..aa79599 100644
+--- a/src/nvme/mi.c
++++ b/src/nvme/mi.c
+@@ -184,7 +184,7 @@ void nvme_mi_ep_probe(struct nvme_mi_ep *ep)
+ char tmp[sizeof(id.mn) + 1];
+
+ nvme_mi_format_mn(&id, tmp);
+- nvme_msg(ep->root, LOG_DEBUG,
++ nvme_msg(ep->root, LOG_NOTICE,
+ "device %02x:%s: applying quirks 0x%08lx\n",
+ id.vid, tmp, ep->quirks);
+ }
+@@ -432,35 +432,35 @@ int nvme_mi_submit(nvme_mi_ep_t ep, struct nvme_mi_req *req,
+ if (ep->transport->mic_enabled) {
+ rc = nvme_mi_verify_resp_mic(resp);
+ if (rc) {
+- nvme_msg(ep->root, LOG_WARNING, "crc mismatch\n");
++ nvme_msg(ep->root, LOG_ERR, "crc mismatch\n");
+ return rc;
+ }
+ }
+
+ /* basic response checks */
+ if (resp->hdr_len < sizeof(struct nvme_mi_msg_hdr)) {
+- nvme_msg(ep->root, LOG_DEBUG,
++ nvme_msg(ep->root, LOG_ERR,
+ "Bad response header len: %zd\n", resp->hdr_len);
+ errno = EPROTO;
+ return -1;
+ }
+
+ if (resp->hdr->type != NVME_MI_MSGTYPE_NVME) {
+- nvme_msg(ep->root, LOG_DEBUG,
++ nvme_msg(ep->root, LOG_ERR,
+ "Invalid message type 0x%02x\n", resp->hdr->type);
+ errno = EPROTO;
+ return -1;
+ }
+
+ if (!(resp->hdr->nmp & (NVME_MI_ROR_RSP << 7))) {
+- nvme_msg(ep->root, LOG_DEBUG,
++ nvme_msg(ep->root, LOG_ERR,
+ "ROR value in response indicates a request\n");
+ errno = EIO;
+ return -1;
+ }
+
+ if ((resp->hdr->nmp & 0x1) != (req->hdr->nmp & 0x1)) {
+- nvme_msg(ep->root, LOG_WARNING,
++ nvme_msg(ep->root, LOG_ERR,
+ "Command slot mismatch: req %d, resp %d\n",
+ req->hdr->nmp & 0x1,
+ resp->hdr->nmp & 0x1);
+@@ -1431,7 +1431,7 @@ int nvme_mi_mi_read_mi_data_subsys(nvme_mi_ep_t ep,
+ return rc;
+
+ if (len != sizeof(*s)) {
+- nvme_msg(ep->root, LOG_WARNING,
++ nvme_msg(ep->root, LOG_ERR,
+ "MI read data length mismatch: "
+ "got %zd bytes, expected %zd\n",
+ len, sizeof(*s));
+@@ -1537,7 +1537,7 @@ int nvme_mi_mi_subsystem_health_status_poll(nvme_mi_ep_t ep, bool clear,
+ return resp_hdr.status;
+
+ if (resp.data_len != sizeof(*sshs)) {
+- nvme_msg(ep->root, LOG_WARNING,
++ nvme_msg(ep->root, LOG_ERR,
+ "MI Subsystem Health Status length mismatch: "
+ "got %zd bytes, expected %zd\n",
+ resp.data_len, sizeof(*sshs));
+--
+2.45.0.rc1.225.g2a3ae87e7f-goog
+
diff --git a/recipes-connectivity/libnvme/libnvme/0008-mi-add-nvme_mi_msg-marco-to-print-MCTP-endpoint-desc.patch b/recipes-connectivity/libnvme/libnvme/0008-mi-add-nvme_mi_msg-marco-to-print-MCTP-endpoint-desc.patch
new file mode 100644
index 0000000..d50cdfd
--- /dev/null
+++ b/recipes-connectivity/libnvme/libnvme/0008-mi-add-nvme_mi_msg-marco-to-print-MCTP-endpoint-desc.patch
@@ -0,0 +1,104 @@
+From 82d0f27eeb36c71aa0cb7fc11d7e51cd5fcf026e Mon Sep 17 00:00:00 2001
+From: Jinliang Wang <jinliangw@google.com>
+Date: Fri, 3 May 2024 15:29:52 -0700
+Subject: [PATCH] mi: add nvme_mi_msg marco to print MCTP endpoint description
+
+Typical libnvme-mi application will open multiple MCTP endpoints, so
+it's necessary to know the debug or error message comes from which
+MCTP endpoint.
+
+Patch Tracking Bug: b/311315898
+Upstream info / review: N/A
+Upstream-Status: Pending
+Justification: Improve NVMe-MI debuggability
+
+Signed-off-by: Jinliang Wang <jinliangw@google.com>
+---
+ src/nvme/log.c | 16 +++++++++++++---
+ src/nvme/private.h | 16 +++++++++++++---
+ 2 files changed, 26 insertions(+), 6 deletions(-)
+
+diff --git a/src/nvme/log.c b/src/nvme/log.c
+index e4697df..9b2cb70 100644
+--- a/src/nvme/log.c
++++ b/src/nvme/log.c
+@@ -26,8 +26,8 @@
+ #define LOG_CLOCK CLOCK_MONOTONIC
+ #endif
+
+-void __attribute__((format(printf, 4, 5)))
+-__nvme_msg(nvme_root_t r, int lvl,
++void __attribute__((format(printf, 5, 6)))
++__nvme_msg(nvme_root_t r, nvme_mi_ep_t ep, int lvl,
+ const char *func, const char *format, ...)
+ {
+ FILE *fp = r ? r->fp : stderr;
+@@ -45,6 +45,7 @@ __nvme_msg(nvme_root_t r, int lvl,
+ "[%s] <%s> %s: ",
+ };
+ char *header __cleanup__(cleanup_charp) = NULL;
++ char *endpoint __cleanup__(cleanup_charp) = NULL;
+ char *message __cleanup__(cleanup_charp) = NULL;
+ int idx = 0;
+
+@@ -74,13 +75,22 @@ __nvme_msg(nvme_root_t r, int lvl,
+ timebuf, pidbuf, func ? func : "") == -1)
+ header = NULL;
+
++ if (ep)
++ {
++ if (asprintf(&endpoint, "[%s] ", nvme_mi_endpoint_desc(ep)) == -1)
++ {
++ endpoint = NULL;
++ }
++ }
++
+ va_start(ap, format);
+ if (vasprintf(&message, format, ap) == -1)
+ message = NULL;
+ va_end(ap);
+
+- fprintf(fp, "%s%s",
++ fprintf(fp, "%s%s%s",
+ header ? header : "<error>",
++ endpoint,
+ message ? message : "<error>");
+ }
+
+diff --git a/src/nvme/private.h b/src/nvme/private.h
+index fbaaaa4..a3d2003 100644
+--- a/src/nvme/private.h
++++ b/src/nvme/private.h
+@@ -147,16 +147,26 @@ nvme_ctrl_t __nvme_lookup_ctrl(nvme_subsystem_t s, const char *transport,
+ #define __nvme_log_func NULL
+ #endif
+
+-void __attribute__((format(printf, 4, 5)))
+-__nvme_msg(nvme_root_t r, int lvl, const char *func, const char *format, ...);
++void __attribute__((format(printf, 5, 6)))
++__nvme_msg(nvme_root_t r, nvme_mi_ep_t ep, int lvl, const char *func, const char *format, ...);
+
+ #define nvme_msg(r, lvl, format, ...) \
+ do { \
+ if ((lvl) <= MAX_LOGLEVEL) \
+- __nvme_msg(r, lvl, __nvme_log_func, \
++ __nvme_msg(r, NULL, lvl, __nvme_log_func, \
+ format, ##__VA_ARGS__); \
+ } while (0)
+
++#define nvme_mi_msg(ep, lvl, format, ...) \
++ do \
++ { \
++ if ((lvl) <= MAX_LOGLEVEL) \
++ { \
++ __nvme_msg(ep->root, ep, lvl, __nvme_log_func, format, \
++ ##__VA_ARGS__); \
++ } \
++ } while (0)
++
+ /* mi internal headers */
+
+ /* internal transport API */
+--
+2.45.0.rc1.225.g2a3ae87e7f-goog
+
diff --git a/recipes-connectivity/libnvme/libnvme/0009-mi-use-nvme_mi_msg-macro-for-nvme-mi-message.patch b/recipes-connectivity/libnvme/libnvme/0009-mi-use-nvme_mi_msg-macro-for-nvme-mi-message.patch
new file mode 100644
index 0000000..c389d41
--- /dev/null
+++ b/recipes-connectivity/libnvme/libnvme/0009-mi-use-nvme_mi_msg-macro-for-nvme-mi-message.patch
@@ -0,0 +1,262 @@
+From 936d1aa6c90a02c4ca07455359a6a0d7861c9073 Mon Sep 17 00:00:00 2001
+From: Jinliang Wang <jinliangw@google.com>
+Date: Fri, 3 May 2024 15:43:07 -0700
+Subject: [PATCH] mi: use nvme_mi_msg macro for nvme-mi message
+
+print endpoint info so we know which endpoint has problem.
+
+Patch Tracking Bug: b/311315898
+Upstream info / review: N/A
+Upstream-Status: Pending
+Justification: Improve NVMe-MI debuggability
+
+Signed-off-by: Jinliang Wang <jinliangw@google.com>
+---
+ src/nvme/mi-mctp.c | 18 +++++++++---------
+ src/nvme/mi.c | 36 ++++++++++++++++++------------------
+ 2 files changed, 27 insertions(+), 27 deletions(-)
+
+diff --git a/src/nvme/mi-mctp.c b/src/nvme/mi-mctp.c
+index cb77d0d..f7e45ab 100644
+--- a/src/nvme/mi-mctp.c
++++ b/src/nvme/mi-mctp.c
+@@ -121,7 +121,7 @@ static __u8 nvme_mi_mctp_tag_alloc(struct nvme_mi_ep *ep)
+ if (!logged) {
+ /* not necessarily fatal, just means we can't handle
+ * "more processing required" messages */
+- nvme_msg(ep->root, LOG_INFO,
++ nvme_mi_msg(ep, LOG_INFO,
+ "System does not support explicit tag allocation\n");
+ logged = true;
+ }
+@@ -153,7 +153,7 @@ static __u8 nvme_mi_mctp_tag_alloc(struct nvme_mi_ep *ep)
+ {
+ static bool logged;
+ if (!logged) {
+- nvme_msg(ep->root, LOG_INFO,
++ nvme_mi_msg(ep, LOG_INFO,
+ "Build does not support explicit tag allocation\n");
+ logged = true;
+ }
+@@ -299,7 +299,7 @@ static int nvme_mi_mctp_submit(struct nvme_mi_ep *ep,
+ len = ops.sendmsg(mctp->sd, &req_msg, 0);
+ if (len < 0) {
+ errno_save = errno;
+- nvme_msg(ep->root, LOG_ERR,
++ nvme_mi_msg(ep, LOG_ERR,
+ "Failure sending MCTP message: %m\n");
+ errno = errno_save;
+ rc = -1;
+@@ -337,7 +337,7 @@ retry:
+ }
+
+ if (rc == 0) {
+- nvme_msg(ep->root, LOG_ERR, "Timeout on MCTP socket\n");
++ nvme_mi_msg(ep, LOG_ERR, "Timeout on MCTP socket\n");
+ errno = ETIMEDOUT;
+ rc = -1;
+ goto out;
+@@ -348,7 +348,7 @@ retry:
+
+ if (len < 0) {
+ errno_save = errno;
+- nvme_msg(ep->root, LOG_ERR,
++ nvme_mi_msg(ep, LOG_ERR,
+ "Failure receiving MCTP message: %m\n");
+ errno = errno_save;
+ goto out;
+@@ -356,7 +356,7 @@ retry:
+
+
+ if (len == 0) {
+- nvme_msg(ep->root, LOG_ERR, "No data from MCTP endpoint\n");
++ nvme_mi_msg(ep, LOG_ERR, "No data from MCTP endpoint\n");
+ errno = EIO;
+ goto out;
+ }
+@@ -369,7 +369,7 @@ retry:
+ * plus four bytes of error data (excluding MIC). Ensure we have enough.
+ */
+ if (len < 8 + sizeof(mic)) {
+- nvme_msg(ep->root, LOG_ERR,
++ nvme_mi_msg(ep, LOG_ERR,
+ "Invalid MCTP response: too short (%zd bytes, needed %zd)\n",
+ len, 8 + sizeof(mic));
+ errno = EPROTO;
+@@ -378,7 +378,7 @@ retry:
+
+ /* We can't have header/payload data that isn't a multiple of 4 bytes */
+ if (len & 0x3) {
+- nvme_msg(ep->root, LOG_ERR,
++ nvme_mi_msg(ep, LOG_ERR,
+ "Response message has unaligned length (%zd)!\n",
+ len);
+ errno = EPROTO;
+@@ -391,7 +391,7 @@ retry:
+ * to keep the tag allocated and retry the recvmsg
+ */
+ if (nvme_mi_mctp_resp_is_mpr(resp, len, mic, &mpr_time)) {
+- nvme_msg(ep->root, LOG_NOTICE,
++ nvme_mi_msg(ep, LOG_NOTICE,
+ "Received More Processing Required, waiting for response\n");
+
+ /* if the controller hasn't set MPRT, fall back to our command/
+diff --git a/src/nvme/mi.c b/src/nvme/mi.c
+index aa79599..cd129be 100644
+--- a/src/nvme/mi.c
++++ b/src/nvme/mi.c
+@@ -88,7 +88,7 @@ static bool nvme_mi_compare_vid_mn(struct nvme_mi_ep *ep,
+
+ len = strlen(mn);
+ if (len >= sizeof(id->mn)) {
+- nvme_msg(ep->root, LOG_ERR,
++ nvme_mi_msg(ep, LOG_ERR,
+ "Internal error: invalid model number for %s\n",
+ __func__);
+ return false;
+@@ -160,7 +160,7 @@ void nvme_mi_ep_probe(struct nvme_mi_ep *ep)
+ rc = nvme_mi_admin_identify_partial(ctrl, &id_args, 0,
+ offsetof(struct nvme_id_ctrl, rab));
+ if (rc) {
+- nvme_msg(ep->root, LOG_WARNING,
++ nvme_mi_msg(ep, LOG_WARNING,
+ "Identify Controller failed, no quirks applied\n");
+ goto out_close;
+ }
+@@ -184,7 +184,7 @@ void nvme_mi_ep_probe(struct nvme_mi_ep *ep)
+ char tmp[sizeof(id.mn) + 1];
+
+ nvme_mi_format_mn(&id, tmp);
+- nvme_msg(ep->root, LOG_NOTICE,
++ nvme_mi_msg(ep, LOG_NOTICE,
+ "device %02x:%s: applying quirks 0x%08lx\n",
+ id.vid, tmp, ep->quirks);
+ }
+@@ -425,42 +425,42 @@ int nvme_mi_submit(nvme_mi_ep_t ep, struct nvme_mi_req *req,
+ nvme_mi_record_resp_time(ep);
+
+ if (rc) {
+- nvme_msg(ep->root, LOG_INFO, "transport failure\n");
++ nvme_mi_msg(ep, LOG_INFO, "transport failure\n");
+ return rc;
+ }
+
+ if (ep->transport->mic_enabled) {
+ rc = nvme_mi_verify_resp_mic(resp);
+ if (rc) {
+- nvme_msg(ep->root, LOG_ERR, "crc mismatch\n");
++ nvme_mi_msg(ep, LOG_ERR, "crc mismatch\n");
+ return rc;
+ }
+ }
+
+ /* basic response checks */
+ if (resp->hdr_len < sizeof(struct nvme_mi_msg_hdr)) {
+- nvme_msg(ep->root, LOG_ERR,
++ nvme_mi_msg(ep, LOG_ERR,
+ "Bad response header len: %zd\n", resp->hdr_len);
+ errno = EPROTO;
+ return -1;
+ }
+
+ if (resp->hdr->type != NVME_MI_MSGTYPE_NVME) {
+- nvme_msg(ep->root, LOG_ERR,
++ nvme_mi_msg(ep, LOG_ERR,
+ "Invalid message type 0x%02x\n", resp->hdr->type);
+ errno = EPROTO;
+ return -1;
+ }
+
+ if (!(resp->hdr->nmp & (NVME_MI_ROR_RSP << 7))) {
+- nvme_msg(ep->root, LOG_ERR,
++ nvme_mi_msg(ep, LOG_ERR,
+ "ROR value in response indicates a request\n");
+ errno = EIO;
+ return -1;
+ }
+
+ if ((resp->hdr->nmp & 0x1) != (req->hdr->nmp & 0x1)) {
+- nvme_msg(ep->root, LOG_ERR,
++ nvme_mi_msg(ep, LOG_ERR,
+ "Command slot mismatch: req %d, resp %d\n",
+ req->hdr->nmp & 0x1,
+ resp->hdr->nmp & 0x1);
+@@ -585,35 +585,35 @@ int nvme_mi_admin_xfer(nvme_mi_ctrl_t ctrl,
+ int direction = admin_req->opcode & 0x3;
+ if (direction == NVME_DATA_TFR_BIDIRECTIONAL || (req_data_size && *resp_data_size))
+ {
+- nvme_msg(ctrl->ep->root, LOG_ERR,
++ nvme_mi_msg(ctrl->ep, LOG_ERR,
+ "nvme_mi_admin_xfer doesn't support bidirectional commands\n");
+ errno = EINVAL;
+ return -1;
+ }
+ else if (direction == NVME_DATA_TFR_HOST_TO_CTRL && *resp_data_size)
+ {
+- nvme_msg(ctrl->ep->root, LOG_ERR,
++ nvme_mi_msg(ctrl->ep, LOG_ERR,
+ "nvme_mi_admin_xfer doesn't support response data on WRITE commands\n");
+ errno = EINVAL;
+ return -1;
+ }
+ else if (direction == NVME_DATA_TFR_CTRL_TO_HOST && req_data_size)
+ {
+- nvme_msg(ctrl->ep->root, LOG_ERR,
++ nvme_mi_msg(ctrl->ep, LOG_ERR,
+ "nvme_mi_admin_xfer doesn't support request data on READ commands\n");
+ errno = EINVAL;
+ return -1;
+ }
+ else if (resp_data_offset && (direction != NVME_DATA_TFR_CTRL_TO_HOST || !*resp_data_size))
+ {
+- nvme_msg(ctrl->ep->root, LOG_ERR,
++ nvme_mi_msg(ctrl->ep, LOG_ERR,
+ "nvme_mi_admin_xfer invalid offset value\n");
+ errno = EINVAL;
+ return -1;
+ }
+ else if (direction == NVME_DATA_TFR_NO_DATA_TFR && req_data_size && *resp_data_size)
+ {
+- nvme_msg(ctrl->ep->root, LOG_ERR,
++ nvme_mi_msg(ctrl->ep, LOG_ERR,
+ "nvme_mi_admin_xfer doesn't support data on NONE_DATA_TRANSFER commands\n");
+ errno = EINVAL;
+ return -1;
+@@ -703,14 +703,14 @@ int nvme_mi_admin_admin_passthru(nvme_mi_ctrl_t ctrl, __u8 opcode, __u8 flags,
+ bool has_read_data = false;
+
+ if (direction == NVME_DATA_TFR_BIDIRECTIONAL) {
+- nvme_msg(ctrl->ep->root, LOG_ERR,
++ nvme_mi_msg(ctrl->ep, LOG_ERR,
+ "nvme_mi_admin_admin_passthru doesn't support bidirectional commands\n");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (data_len > 4096) {
+- nvme_msg(ctrl->ep->root, LOG_ERR,
++ nvme_mi_msg(ctrl->ep, LOG_ERR,
+ "nvme_mi_admin_admin_passthru doesn't support data_len over 4096 bytes.\n");
+ errno = EINVAL;
+ return -1;
+@@ -1431,7 +1431,7 @@ int nvme_mi_mi_read_mi_data_subsys(nvme_mi_ep_t ep,
+ return rc;
+
+ if (len != sizeof(*s)) {
+- nvme_msg(ep->root, LOG_ERR,
++ nvme_mi_msg(ep, LOG_ERR,
+ "MI read data length mismatch: "
+ "got %zd bytes, expected %zd\n",
+ len, sizeof(*s));
+@@ -1537,7 +1537,7 @@ int nvme_mi_mi_subsystem_health_status_poll(nvme_mi_ep_t ep, bool clear,
+ return resp_hdr.status;
+
+ if (resp.data_len != sizeof(*sshs)) {
+- nvme_msg(ep->root, LOG_ERR,
++ nvme_mi_msg(ep, LOG_ERR,
+ "MI Subsystem Health Status length mismatch: "
+ "got %zd bytes, expected %zd\n",
+ resp.data_len, sizeof(*sshs));
+--
+2.45.0.rc1.225.g2a3ae87e7f-goog
+
diff --git a/recipes-connectivity/libnvme/libnvme/0010-mi-trace-NVMe-MI-command-request-after-failure.patch b/recipes-connectivity/libnvme/libnvme/0010-mi-trace-NVMe-MI-command-request-after-failure.patch
new file mode 100644
index 0000000..0668a05
--- /dev/null
+++ b/recipes-connectivity/libnvme/libnvme/0010-mi-trace-NVMe-MI-command-request-after-failure.patch
@@ -0,0 +1,157 @@
+From cc62162c773f0ba84840ddbd8c62bcd59defda1b Mon Sep 17 00:00:00 2001
+From: Jinliang Wang <jinliangw@google.com>
+Date: Thu, 26 Oct 2023 15:49:34 -0700
+Subject: [PATCH] mi: trace NVMe-MI command request after failure
+
+Print command request detail to help debug.
+
+Patch Tracking Bug: b/311315898
+Upstream info / review: N/A
+Upstream-Status: Pending
+Justification: Improve NVMe-MI debuggability
+
+Signed-off-by: Jinliang Wang <jinliangw@google.com>
+---
+ src/nvme/mi.c | 75 +++++++++++++++++++++++++++++++++++++++++++++------
+ 1 file changed, 67 insertions(+), 8 deletions(-)
+
+diff --git a/src/nvme/mi.c b/src/nvme/mi.c
+index cd129be..01f2a86 100644
+--- a/src/nvme/mi.c
++++ b/src/nvme/mi.c
+@@ -378,10 +378,61 @@ static int nvme_mi_verify_resp_mic(struct nvme_mi_resp *resp)
+ return resp->mic != ~crc;
+ }
+
++#define GET_MI_MSG_TYPE(x) ((x >> 3) & 0xF)
++static void nvme_mi_trace_request(nvme_mi_ep_t ep,
++ const struct nvme_mi_req *req, int rc,
++ int error_no, const struct timespec *submit_time)
++{
++ struct timespec complete_time = {0, 0};
++ struct timespec elapsed = {0, 0};
++ struct nvme_mi_admin_req_hdr *admin_req_hdr = NULL;
++ struct nvme_mi_mi_req_hdr *mi_req_hdr = NULL;
++
++ clock_gettime(CLOCK_MONOTONIC, &complete_time);
++
++ timespec_sub(&complete_time, submit_time, &elapsed);
++
++ if (req->hdr->type == NVME_MI_MSGTYPE_NVME &&
++ GET_MI_MSG_TYPE(req->hdr->nmp) == NVME_MI_MT_ADMIN)
++ {
++ admin_req_hdr = (struct nvme_mi_admin_req_hdr *)req->hdr;
++ nvme_mi_msg(ep, LOG_WARNING,
++ "Admin op:0x%02x, cdw(1:0x%x, 10:0x%x, 11:0x%x,"
++ " 12:0x%x 13:0x%x, 14:0x%x, 15:0x%x) "
++ "T:%dms, elapsed:%dms, rc:%d, errno:%d\n",
++ admin_req_hdr->opcode,
++ admin_req_hdr->cdw1,
++ admin_req_hdr->cdw10,
++ admin_req_hdr->cdw11,
++ admin_req_hdr->cdw12,
++ admin_req_hdr->cdw13,
++ admin_req_hdr->cdw14,
++ admin_req_hdr->cdw15,
++ ep->timeout,
++ (int)(elapsed.tv_sec * 1000 + elapsed.tv_nsec / 1000000),
++ rc, error_no);
++ }
++ else if (req->hdr->type == NVME_MI_MSGTYPE_NVME &&
++ GET_MI_MSG_TYPE(req->hdr->nmp) == NVME_MI_MT_MI)
++ {
++ mi_req_hdr = (struct nvme_mi_mi_req_hdr *)req->hdr;
++ nvme_mi_msg(ep, LOG_WARNING,
++ "MI op:0x%02x, cdw0:0x%x, cdw1:0x%x T:%dms, elapsed:%dms"
++ ", rc:%d, errno:%d\n",
++ mi_req_hdr->opcode,
++ mi_req_hdr->cdw0,
++ mi_req_hdr->cdw1,
++ ep->timeout,
++ (int)(elapsed.tv_sec * 1000 + elapsed.tv_nsec / 1000000),
++ rc, error_no);
++ }
++}
++
+ int nvme_mi_submit(nvme_mi_ep_t ep, struct nvme_mi_req *req,
+ struct nvme_mi_resp *resp)
+ {
+ int rc;
++ struct timespec submit_time = {0, 0};
+
+ if (req->hdr_len < sizeof(struct nvme_mi_msg_hdr)) {
+ errno = EINVAL;
+@@ -419,6 +470,8 @@ int nvme_mi_submit(nvme_mi_ep_t ep, struct nvme_mi_req *req,
+ if (nvme_mi_ep_has_quirk(ep, NVME_QUIRK_MIN_INTER_COMMAND_TIME))
+ nvme_mi_insert_delay(ep);
+
++ clock_gettime(CLOCK_MONOTONIC, &submit_time);
++
+ rc = ep->transport->submit(ep, req, resp);
+
+ if (nvme_mi_ep_has_quirk(ep, NVME_QUIRK_MIN_INTER_COMMAND_TIME))
+@@ -426,14 +479,14 @@ int nvme_mi_submit(nvme_mi_ep_t ep, struct nvme_mi_req *req,
+
+ if (rc) {
+ nvme_mi_msg(ep, LOG_INFO, "transport failure\n");
+- return rc;
++ goto submit_return;
+ }
+
+ if (ep->transport->mic_enabled) {
+ rc = nvme_mi_verify_resp_mic(resp);
+ if (rc) {
+ nvme_mi_msg(ep, LOG_ERR, "crc mismatch\n");
+- return rc;
++ goto submit_return;
+ }
+ }
+
+@@ -442,21 +495,24 @@ int nvme_mi_submit(nvme_mi_ep_t ep, struct nvme_mi_req *req,
+ nvme_mi_msg(ep, LOG_ERR,
+ "Bad response header len: %zd\n", resp->hdr_len);
+ errno = EPROTO;
+- return -1;
++ rc = -1;
++ goto submit_return;
+ }
+
+ if (resp->hdr->type != NVME_MI_MSGTYPE_NVME) {
+ nvme_mi_msg(ep, LOG_ERR,
+ "Invalid message type 0x%02x\n", resp->hdr->type);
+ errno = EPROTO;
+- return -1;
++ rc = -1;
++ goto submit_return;
+ }
+
+ if (!(resp->hdr->nmp & (NVME_MI_ROR_RSP << 7))) {
+ nvme_mi_msg(ep, LOG_ERR,
+ "ROR value in response indicates a request\n");
+ errno = EIO;
+- return -1;
++ rc = -1;
++ goto submit_return;
+ }
+
+ if ((resp->hdr->nmp & 0x1) != (req->hdr->nmp & 0x1)) {
+@@ -465,10 +521,13 @@ int nvme_mi_submit(nvme_mi_ep_t ep, struct nvme_mi_req *req,
+ req->hdr->nmp & 0x1,
+ resp->hdr->nmp & 0x1);
+ errno = EIO;
+- return -1;
++ rc = -1;
++ goto submit_return;
+ }
+-
+- return 0;
++submit_return:
++ if (rc)
++ nvme_mi_trace_request(ep, req, rc, errno, &submit_time);
++ return rc;
+ }
+
+ static void nvme_mi_admin_init_req(struct nvme_mi_req *req,
+--
+2.45.0.rc1.225.g2a3ae87e7f-goog
+
diff --git a/recipes-connectivity/libnvme/libnvme_git.bb b/recipes-connectivity/libnvme/libnvme_git.bb
index f1c4992..3ff5709 100644
--- a/recipes-connectivity/libnvme/libnvme_git.bb
+++ b/recipes-connectivity/libnvme/libnvme_git.bb
@@ -19,7 +19,10 @@
file://0004-mi-avoid-changing-default-ep-timeout-during-admin_pa.patch \
file://0005-libnvme-mi-add-timeout-functions-to-.map.patch \
file://0006-mi-don-t-return-from-mi_mctp_submit-with-a-tag-held.patch \
- file://0007-mi-check-and-print-OOB-NVMe-MI-command-execution-tim.patch \
+ file://0007-mi-use-more-reasonable-log-level.patch \
+ file://0008-mi-add-nvme_mi_msg-marco-to-print-MCTP-endpoint-desc.patch \
+ file://0009-mi-use-nvme_mi_msg-macro-for-nvme-mi-message.patch \
+ file://0010-mi-trace-NVMe-MI-command-request-after-failure.patch \
"
S = "${WORKDIR}/git"