git: 6f308bcf5724 - main - ctl: Support NVMe requests in debug trace functions

From: John Baldwin <jhb_at_FreeBSD.org>
Date: Fri, 03 May 2024 00:15:57 UTC
The branch main has been updated by jhb:

URL: https://cgit.FreeBSD.org/src/commit/?id=6f308bcf572467c0884db833e169d9f14b7b49b2

commit 6f308bcf572467c0884db833e169d9f14b7b49b2
Author:     John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2024-05-02 23:31:34 +0000
Commit:     John Baldwin <jhb@FreeBSD.org>
CommitDate: 2024-05-02 23:31:34 +0000

    ctl: Support NVMe requests in debug trace functions
    
    Reviewed by:    imp
    Sponsored by:   Chelsio Communications
    Differential Revision:  https://reviews.freebsd.org/D44719
---
 sys/cam/ctl/ctl_nvme_all.c | 244 +++++++++++++++++++++++++++++++++++++++++++++
 sys/cam/ctl/ctl_nvme_all.h |  17 ++++
 sys/cam/ctl/ctl_util.c     |  55 +++++++---
 sys/conf/files             |   1 +
 sys/modules/ctl/Makefile   |   1 +
 usr.sbin/bhyve/Makefile    |   1 +
 usr.sbin/ctladm/Makefile   |   2 +-
 7 files changed, 308 insertions(+), 13 deletions(-)

diff --git a/sys/cam/ctl/ctl_nvme_all.c b/sys/cam/ctl/ctl_nvme_all.c
new file mode 100644
index 000000000000..739efadf5614
--- /dev/null
+++ b/sys/cam/ctl/ctl_nvme_all.c
@@ -0,0 +1,244 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (C) 2012-2014 Intel Corporation
+ * All rights reserved.
+ *
+ * Copyright (c) 2023 Chelsio Communications, Inc.
+ */
+
+#include <sys/types.h>
+#include <sys/sbuf.h>
+#ifndef _KERNEL
+#include <sys/time.h>
+#include <stdio.h>
+#endif
+
+#include <dev/nvme/nvme.h>
+
+#include <cam/ctl/ctl_io.h>
+#include <cam/ctl/ctl_nvme_all.h>
+
+/* XXX: This duplicates lists in nvme_qpair.c. */
+
+#define OPC_ENTRY(x)		[NVME_OPC_ ## x] = #x
+
+static const char *admin_opcode[256] = {
+	OPC_ENTRY(DELETE_IO_SQ),
+	OPC_ENTRY(CREATE_IO_SQ),
+	OPC_ENTRY(GET_LOG_PAGE),
+	OPC_ENTRY(DELETE_IO_CQ),
+	OPC_ENTRY(CREATE_IO_CQ),
+	OPC_ENTRY(IDENTIFY),
+	OPC_ENTRY(ABORT),
+	OPC_ENTRY(SET_FEATURES),
+	OPC_ENTRY(GET_FEATURES),
+	OPC_ENTRY(ASYNC_EVENT_REQUEST),
+	OPC_ENTRY(NAMESPACE_MANAGEMENT),
+	OPC_ENTRY(FIRMWARE_ACTIVATE),
+	OPC_ENTRY(FIRMWARE_IMAGE_DOWNLOAD),
+	OPC_ENTRY(DEVICE_SELF_TEST),
+	OPC_ENTRY(NAMESPACE_ATTACHMENT),
+	OPC_ENTRY(KEEP_ALIVE),
+	OPC_ENTRY(DIRECTIVE_SEND),
+	OPC_ENTRY(DIRECTIVE_RECEIVE),
+	OPC_ENTRY(VIRTUALIZATION_MANAGEMENT),
+	OPC_ENTRY(NVME_MI_SEND),
+	OPC_ENTRY(NVME_MI_RECEIVE),
+	OPC_ENTRY(CAPACITY_MANAGEMENT),
+	OPC_ENTRY(LOCKDOWN),
+	OPC_ENTRY(DOORBELL_BUFFER_CONFIG),
+	OPC_ENTRY(FABRICS_COMMANDS),
+	OPC_ENTRY(FORMAT_NVM),
+	OPC_ENTRY(SECURITY_SEND),
+	OPC_ENTRY(SECURITY_RECEIVE),
+	OPC_ENTRY(SANITIZE),
+	OPC_ENTRY(GET_LBA_STATUS),
+};
+
+static const char *nvm_opcode[256] = {
+	OPC_ENTRY(FLUSH),
+	OPC_ENTRY(WRITE),
+	OPC_ENTRY(READ),
+	OPC_ENTRY(WRITE_UNCORRECTABLE),
+	OPC_ENTRY(COMPARE),
+	OPC_ENTRY(WRITE_ZEROES),
+	OPC_ENTRY(DATASET_MANAGEMENT),
+	OPC_ENTRY(VERIFY),
+	OPC_ENTRY(RESERVATION_REGISTER),
+	OPC_ENTRY(RESERVATION_REPORT),
+	OPC_ENTRY(RESERVATION_ACQUIRE),
+	OPC_ENTRY(RESERVATION_RELEASE),
+	OPC_ENTRY(COPY),
+};
+
+void
+ctl_nvme_command_string(struct ctl_nvmeio *ctnio, struct sbuf *sb)
+{
+	const char *s, *type;
+
+	if (ctnio->io_hdr.io_type == CTL_IO_NVME_ADMIN) {
+		s = admin_opcode[ctnio->cmd.opc];
+		type = "ADMIN";
+	} else {
+		s = nvm_opcode[ctnio->cmd.opc];
+		type = "NVM";
+	}
+	if (s == NULL)
+		sbuf_printf(sb, "%s:0x%02x", type, ctnio->cmd.opc);
+	else
+		sbuf_printf(sb, "%s", s);
+}
+
+#define SC_ENTRY(x)		[NVME_SC_ ## x] = #x
+
+static const char *generic_status[256] = {
+	SC_ENTRY(SUCCESS),
+	SC_ENTRY(INVALID_OPCODE),
+	SC_ENTRY(INVALID_FIELD),
+	SC_ENTRY(COMMAND_ID_CONFLICT),
+	SC_ENTRY(DATA_TRANSFER_ERROR),
+	SC_ENTRY(ABORTED_POWER_LOSS),
+	SC_ENTRY(INTERNAL_DEVICE_ERROR),
+	SC_ENTRY(ABORTED_BY_REQUEST),
+	SC_ENTRY(ABORTED_SQ_DELETION),
+	SC_ENTRY(ABORTED_FAILED_FUSED),
+	SC_ENTRY(ABORTED_MISSING_FUSED),
+	SC_ENTRY(INVALID_NAMESPACE_OR_FORMAT),
+	SC_ENTRY(COMMAND_SEQUENCE_ERROR),
+	SC_ENTRY(INVALID_SGL_SEGMENT_DESCR),
+	SC_ENTRY(INVALID_NUMBER_OF_SGL_DESCR),
+	SC_ENTRY(DATA_SGL_LENGTH_INVALID),
+	SC_ENTRY(METADATA_SGL_LENGTH_INVALID),
+	SC_ENTRY(SGL_DESCRIPTOR_TYPE_INVALID),
+	SC_ENTRY(INVALID_USE_OF_CMB),
+	SC_ENTRY(PRP_OFFET_INVALID),
+	SC_ENTRY(ATOMIC_WRITE_UNIT_EXCEEDED),
+	SC_ENTRY(OPERATION_DENIED),
+	SC_ENTRY(SGL_OFFSET_INVALID),
+	SC_ENTRY(HOST_ID_INCONSISTENT_FORMAT),
+	SC_ENTRY(KEEP_ALIVE_TIMEOUT_EXPIRED),
+	SC_ENTRY(KEEP_ALIVE_TIMEOUT_INVALID),
+	SC_ENTRY(ABORTED_DUE_TO_PREEMPT),
+	SC_ENTRY(SANITIZE_FAILED),
+	SC_ENTRY(SANITIZE_IN_PROGRESS),
+	SC_ENTRY(SGL_DATA_BLOCK_GRAN_INVALID),
+	SC_ENTRY(NOT_SUPPORTED_IN_CMB),
+	SC_ENTRY(NAMESPACE_IS_WRITE_PROTECTED),
+	SC_ENTRY(COMMAND_INTERRUPTED),
+	SC_ENTRY(TRANSIENT_TRANSPORT_ERROR),
+
+	SC_ENTRY(LBA_OUT_OF_RANGE),
+	SC_ENTRY(CAPACITY_EXCEEDED),
+	SC_ENTRY(NAMESPACE_NOT_READY),
+	SC_ENTRY(RESERVATION_CONFLICT),
+	SC_ENTRY(FORMAT_IN_PROGRESS),
+};
+
+static const char *command_specific_status[256] = {
+	SC_ENTRY(COMPLETION_QUEUE_INVALID),
+	SC_ENTRY(INVALID_QUEUE_IDENTIFIER),
+	SC_ENTRY(MAXIMUM_QUEUE_SIZE_EXCEEDED),
+	SC_ENTRY(ABORT_COMMAND_LIMIT_EXCEEDED),
+	SC_ENTRY(ASYNC_EVENT_REQUEST_LIMIT_EXCEEDED),
+	SC_ENTRY(INVALID_FIRMWARE_SLOT),
+	SC_ENTRY(INVALID_FIRMWARE_IMAGE),
+	SC_ENTRY(INVALID_INTERRUPT_VECTOR),
+	SC_ENTRY(INVALID_LOG_PAGE),
+	SC_ENTRY(INVALID_FORMAT),
+	SC_ENTRY(FIRMWARE_REQUIRES_RESET),
+	SC_ENTRY(INVALID_QUEUE_DELETION),
+	SC_ENTRY(FEATURE_NOT_SAVEABLE),
+	SC_ENTRY(FEATURE_NOT_CHANGEABLE),
+	SC_ENTRY(FEATURE_NOT_NS_SPECIFIC),
+	SC_ENTRY(FW_ACT_REQUIRES_NVMS_RESET),
+	SC_ENTRY(FW_ACT_REQUIRES_RESET),
+	SC_ENTRY(FW_ACT_REQUIRES_TIME),
+	SC_ENTRY(FW_ACT_PROHIBITED),
+	SC_ENTRY(OVERLAPPING_RANGE),
+	SC_ENTRY(NS_INSUFFICIENT_CAPACITY),
+	SC_ENTRY(NS_ID_UNAVAILABLE),
+	SC_ENTRY(NS_ALREADY_ATTACHED),
+	SC_ENTRY(NS_IS_PRIVATE),
+	SC_ENTRY(NS_NOT_ATTACHED),
+	SC_ENTRY(THIN_PROV_NOT_SUPPORTED),
+	SC_ENTRY(CTRLR_LIST_INVALID),
+	SC_ENTRY(SELF_TEST_IN_PROGRESS),
+	SC_ENTRY(BOOT_PART_WRITE_PROHIB),
+	SC_ENTRY(INVALID_CTRLR_ID),
+	SC_ENTRY(INVALID_SEC_CTRLR_STATE),
+	SC_ENTRY(INVALID_NUM_OF_CTRLR_RESRC),
+	SC_ENTRY(INVALID_RESOURCE_ID),
+	SC_ENTRY(SANITIZE_PROHIBITED_WPMRE),
+	SC_ENTRY(ANA_GROUP_ID_INVALID),
+	SC_ENTRY(ANA_ATTACH_FAILED),
+
+	SC_ENTRY(CONFLICTING_ATTRIBUTES),
+	SC_ENTRY(INVALID_PROTECTION_INFO),
+	SC_ENTRY(ATTEMPTED_WRITE_TO_RO_PAGE),
+};
+
+static const char *media_error_status[256] = {
+	SC_ENTRY(WRITE_FAULTS),
+	SC_ENTRY(UNRECOVERED_READ_ERROR),
+	SC_ENTRY(GUARD_CHECK_ERROR),
+	SC_ENTRY(APPLICATION_TAG_CHECK_ERROR),
+	SC_ENTRY(REFERENCE_TAG_CHECK_ERROR),
+	SC_ENTRY(COMPARE_FAILURE),
+	SC_ENTRY(ACCESS_DENIED),
+	SC_ENTRY(DEALLOCATED_OR_UNWRITTEN),
+};
+
+static const char *path_related_status[256] = {
+	SC_ENTRY(INTERNAL_PATH_ERROR),
+	SC_ENTRY(ASYMMETRIC_ACCESS_PERSISTENT_LOSS),
+	SC_ENTRY(ASYMMETRIC_ACCESS_INACCESSIBLE),
+	SC_ENTRY(ASYMMETRIC_ACCESS_TRANSITION),
+	SC_ENTRY(CONTROLLER_PATHING_ERROR),
+	SC_ENTRY(HOST_PATHING_ERROR),
+	SC_ENTRY(COMMAND_ABORTED_BY_HOST),
+};
+
+void
+ctl_nvme_status_string(struct ctl_nvmeio *ctnio, struct sbuf *sb)
+{
+	const char *s, *type;
+	uint16_t status;
+
+	status = le16toh(ctnio->cpl.status);
+	switch (NVME_STATUS_GET_SCT(status)) {
+	case NVME_SCT_GENERIC:
+		s = generic_status[NVME_STATUS_GET_SC(status)];
+		type = "GENERIC";
+		break;
+	case NVME_SCT_COMMAND_SPECIFIC:
+		s = command_specific_status[NVME_STATUS_GET_SC(status)];
+		type = "COMMAND SPECIFIC";
+		break;
+	case NVME_SCT_MEDIA_ERROR:
+		s = media_error_status[NVME_STATUS_GET_SC(status)];
+		type = "MEDIA ERROR";
+		break;
+	case NVME_SCT_PATH_RELATED:
+		s = path_related_status[NVME_STATUS_GET_SC(status)];
+		type = "PATH RELATED";
+		break;
+	case NVME_SCT_VENDOR_SPECIFIC:
+		s = NULL;
+		type = "VENDOR SPECIFIC";
+		break;
+	default:
+		s = "RESERVED";
+		type = NULL;
+		break;
+	}
+
+	if (s == NULL)
+		sbuf_printf(sb, "%s:0x%02x", type, NVME_STATUS_GET_SC(status));
+	else
+		sbuf_printf(sb, "%s", s);
+	if (NVME_STATUS_GET_M(status) != 0)
+		sbuf_printf(sb, " M");
+	if (NVME_STATUS_GET_DNR(status) != 0)
+		sbuf_printf(sb, " DNR");
+}
diff --git a/sys/cam/ctl/ctl_nvme_all.h b/sys/cam/ctl/ctl_nvme_all.h
new file mode 100644
index 000000000000..df0bf585c3ae
--- /dev/null
+++ b/sys/cam/ctl/ctl_nvme_all.h
@@ -0,0 +1,17 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Chelsio Communications, Inc.
+ */
+
+#ifndef __CTL_NVME_ALL_H__
+#define	__CTL_NVME_ALL_H__
+
+__BEGIN_DECLS
+
+void	ctl_nvme_command_string(struct ctl_nvmeio *ctnio, struct sbuf *sb);
+void	ctl_nvme_status_string(struct ctl_nvmeio *ctnio, struct sbuf *sb);
+
+__END_DECLS
+
+#endif /* !__CTL_NVME_ALL_H__ */
diff --git a/sys/cam/ctl/ctl_util.c b/sys/cam/ctl/ctl_util.c
index d039e3f6fe6e..3174c3c7cf40 100644
--- a/sys/cam/ctl/ctl_util.c
+++ b/sys/cam/ctl/ctl_util.c
@@ -56,6 +56,7 @@
 #include <sys/callout.h>
 #include <cam/scsi/scsi_all.h>
 #include <cam/ctl/ctl_io.h>
+#include <cam/ctl/ctl_nvme_all.h>
 #include <cam/ctl/ctl_scsi_all.h>
 #include <cam/ctl/ctl_util.h>
 
@@ -759,6 +760,12 @@ ctl_io_sbuf(union ctl_io *io, struct sbuf *sb)
 			break;
 		}
 		break;
+	case CTL_IO_NVME:
+	case CTL_IO_NVME_ADMIN:
+		sbuf_cat(sb, path_str);
+		ctl_nvme_command_string(&io->nvmeio, sb);
+		sbuf_printf(sb, " CID: 0x%x\n", le16toh(io->nvmeio.cmd.cid));
+		break;
 	default:
 		break;
 	}
@@ -793,15 +800,29 @@ ctl_io_error_sbuf(union ctl_io *io, struct scsi_inquiry_data *inq_data,
 	else
 		sbuf_printf(sb, "CTL Status: %s\n", status_desc->description);
 
-	if ((io->io_hdr.io_type == CTL_IO_SCSI)
-	 && ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SCSI_ERROR)) {
-		sbuf_cat(sb, path_str);
-		sbuf_printf(sb, "SCSI Status: %s\n",
+	switch (io->io_hdr.io_type) {
+	case CTL_IO_SCSI:
+		if ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SCSI_ERROR) {
+			sbuf_cat(sb, path_str);
+			sbuf_printf(sb, "SCSI Status: %s\n",
 			    ctl_scsi_status_string(&io->scsiio));
 
-		if (io->scsiio.scsi_status == SCSI_STATUS_CHECK_COND)
-			ctl_scsi_sense_sbuf(&io->scsiio, inq_data,
-					    sb, SSS_FLAG_NONE);
+			if (io->scsiio.scsi_status == SCSI_STATUS_CHECK_COND)
+				ctl_scsi_sense_sbuf(&io->scsiio, inq_data,
+				    sb, SSS_FLAG_NONE);
+		}
+		break;
+	case CTL_IO_NVME:
+	case CTL_IO_NVME_ADMIN:
+		if ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_NVME_ERROR) {
+			sbuf_cat(sb, path_str);
+			sbuf_printf(sb, "NVMe Status: ");
+			ctl_nvme_status_string(&io->nvmeio, sb);
+			sbuf_printf(sb, "\n");
+		}
+		break;
+	default:
+		break;
 	}
 }
 
@@ -853,24 +874,34 @@ ctl_data_print(union ctl_io *io)
 	char str[128];
 	char path_str[64];
 	struct sbuf sb;
+	uintmax_t tag_num;
 	int i, j, len;
 
-	if (io->io_hdr.io_type != CTL_IO_SCSI)
+	switch (io->io_hdr.io_type) {
+	case CTL_IO_SCSI:
+		tag_num = io->scsiio.tag_num;
+		break;
+	case CTL_IO_NVME:
+	case CTL_IO_NVME_ADMIN:
+		tag_num = le16toh(io->nvmeio.cmd.cid);
+		break;
+	default:
 		return;
+	}
 	if (io->io_hdr.flags & CTL_FLAG_BUS_ADDR)
 		return;
-	if (io->scsiio.kern_sg_entries > 0)	/* XXX: Implement */
+	if (ctl_kern_sg_entries(io) > 0)	/* XXX: Implement */
 		return;
 	ctl_scsi_path_string(&io->io_hdr, path_str, sizeof(path_str));
-	len = min(io->scsiio.kern_data_len, 4096);
+	len = min(ctl_kern_data_len(io), 4096);
 	for (i = 0; i < len; ) {
 		sbuf_new(&sb, str, sizeof(str), SBUF_FIXEDLEN);
 		sbuf_cat(&sb, path_str);
-		sbuf_printf(&sb, " %#jx:%04x:", io->scsiio.tag_num, i);
+		sbuf_printf(&sb, " %#jx:%04x:", tag_num, i);
 		for (j = 0; j < 16 && i < len; i++, j++) {
 			if (j == 8)
 				sbuf_cat(&sb, " ");
-			sbuf_printf(&sb, " %02x", io->scsiio.kern_data_ptr[i]);
+			sbuf_printf(&sb, " %02x", ctl_kern_data_ptr(io)[i]);
 		}
 		sbuf_cat(&sb, "\n");
 		sbuf_finish(&sb);
diff --git a/sys/conf/files b/sys/conf/files
index 4a631d979c78..266018c5c70d 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -108,6 +108,7 @@ cam/ctl/ctl_frontend_cam_sim.c	optional ctl
 cam/ctl/ctl_frontend_ioctl.c	optional ctl
 cam/ctl/ctl_frontend_iscsi.c	optional ctl cfiscsi
 cam/ctl/ctl_ha.c		optional ctl
+cam/ctl/ctl_nvme_all.c		optional ctl
 cam/ctl/ctl_scsi_all.c		optional ctl
 cam/ctl/ctl_tpc.c		optional ctl
 cam/ctl/ctl_tpc_local.c		optional ctl
diff --git a/sys/modules/ctl/Makefile b/sys/modules/ctl/Makefile
index 960cd60bfa9a..32f150b41300 100644
--- a/sys/modules/ctl/Makefile
+++ b/sys/modules/ctl/Makefile
@@ -12,6 +12,7 @@ SRCS+=	ctl_frontend.c
 SRCS+=	ctl_frontend_cam_sim.c
 SRCS+=	ctl_frontend_ioctl.c
 SRCS+=	ctl_ha.c
+SRCS+=	ctl_nvme_all.c
 SRCS+=	ctl_scsi_all.c
 SRCS+=	ctl_tpc.c
 SRCS+=	ctl_tpc_local.c
diff --git a/usr.sbin/bhyve/Makefile b/usr.sbin/bhyve/Makefile
index d5d7dfc26ab9..8b6631de1519 100644
--- a/usr.sbin/bhyve/Makefile
+++ b/usr.sbin/bhyve/Makefile
@@ -27,6 +27,7 @@ SRCS=	\
 	config.c		\
 	console.c		\
 	crc16.c			\
+	ctl_nvme_all.c		\
 	ctl_scsi_all.c		\
 	ctl_util.c		\
 	hda_codec.c		\
diff --git a/usr.sbin/ctladm/Makefile b/usr.sbin/ctladm/Makefile
index f9ddd251f96c..5e0df8065cce 100644
--- a/usr.sbin/ctladm/Makefile
+++ b/usr.sbin/ctladm/Makefile
@@ -3,7 +3,7 @@
 
 PACKAGE=	iscsi
 PROG=		ctladm
-SRCS=		ctladm.c util.c ctl_util.c ctl_scsi_all.c
+SRCS=		ctladm.c util.c ctl_util.c ctl_nvme_all.c ctl_scsi_all.c
 .PATH:		${SRCTOP}/sys/cam/ctl
 SDIR=		${SRCTOP}/sys
 CFLAGS+=	-I${SDIR}