aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sbin/nvmecontrol/resv.c9
-rw-r--r--sys/dev/nvme/nvme.h186
-rw-r--r--sys/dev/nvme/nvme_ctrlr.c17
-rw-r--r--sys/dev/nvme/nvme_ctrlr_cmd.c37
-rw-r--r--sys/dev/nvme/nvme_util.c15
5 files changed, 219 insertions, 45 deletions
diff --git a/sbin/nvmecontrol/resv.c b/sbin/nvmecontrol/resv.c
index d607b0b015e6..33561d0f8ae4 100644
--- a/sbin/nvmecontrol/resv.c
+++ b/sbin/nvmecontrol/resv.c
@@ -417,8 +417,9 @@ resvreport(const struct cmd *f, int argc, char *argv[])
e->ctrlr[i].rcsts);
printf(" Reservation Key: 0x%08jx\n",
e->ctrlr[i].rkey);
- printf(" Host Identifier: 0x%08jx%08jx\n",
- e->ctrlr[i].hostid[0], e->ctrlr[i].hostid[1]);
+ printf(" Host Identifier: 0x%016jx%016jx\n",
+ le64toh(e->ctrlr[i].hostid[1]),
+ le64toh(e->ctrlr[i].hostid[0]));
}
} else {
n = MIN(n, (sizeof(data) - sizeof(s)) / sizeof(s->ctrlr[0]));
@@ -427,8 +428,8 @@ resvreport(const struct cmd *f, int argc, char *argv[])
s->ctrlr[i].ctrlr_id);
printf(" Reservation Status: %u\n",
s->ctrlr[i].rcsts);
- printf(" Host Identifier: 0x%08jx\n",
- s->ctrlr[i].hostid);
+ printf(" Host Identifier: 0x%016jx\n",
+ le64toh(s->ctrlr[i].hostid));
printf(" Reservation Key: 0x%08jx\n",
s->ctrlr[i].rkey);
}
diff --git a/sys/dev/nvme/nvme.h b/sys/dev/nvme/nvme.h
index 98caf9a860d0..ca87cdd25abe 100644
--- a/sys/dev/nvme/nvme.h
+++ b/sys/dev/nvme/nvme.h
@@ -1205,6 +1205,68 @@ _Static_assert(sizeof(struct nvme_timestamp_data) == 8,
#define NVME_TIMESTAMP_ORIGIN_RESET (0x0)
#define NVME_TIMESTAMP_ORIGIN_SET_FEATURES (0x1)
+enum nvme_format_ses {
+ NVME_FORMAT_SES_NONE = 0x00,
+ NVME_FORMAT_SES_USER = 0x01,
+ NVME_FORMAT_SES_CRYPTO = 0x02
+};
+
+/*
+ * Ignore Existing Key
+ */
+#define NVME_RESV_IEKEY_MASK 0x01
+
+/*
+ * Actions for Reservation Acquire
+ */
+#define NVME_RESV_ACQUIRE_MASK 0x07
+enum nvme_resv_acquire_action {
+ NVME_RESV_ACQUIRE_ACQUIRE = 0x00,
+ NVME_RESV_ACQUIRE_PREEMPT = 0x01,
+ NVME_RESV_ACQUIRE_PREEMPT_ABT = 0x02
+};
+
+/*
+ * Reservation types for Reservation Acquire.
+ */
+enum nvme_resv_type {
+ NVME_RESV_TYPE_WR_EX = 0x01,
+ NVME_RESV_TYPE_EX_AC = 0x02,
+ NVME_RESV_TYPE_WR_EX_RO = 0x03,
+ NVME_RESV_TYPE_EX_AC_RO = 0x04,
+ NVME_RESV_TYPE_WR_EX_AR = 0x05,
+ NVME_RESV_TYPE_EX_AC_AR = 0x06
+};
+
+
+/*
+ * Values for Reservation Register Change Persist Through Power Loss State
+ */
+#define NVME_RESV_CPTPL_MASK 0x03
+enum nvme_resv_cptpl {
+ NVME_RESV_CPTPL_NOCHANGE = 0x00,
+ NVME_RESV_CPTPL_0 = 0x02,
+ NVME_RESV_CPTPL_1 = 0x03
+};
+
+/*
+ * Actions for Reservation Register
+ */
+#define NVME_RESV_REG_MASK 0x07
+enum nvme_resv_register_action {
+ NVME_RESV_REG_REGISTER = 0x00,
+ NVME_RESV_REG_UNREGISTER = 0x01,
+ NVME_RESV_REG_REPLACE = 0x02
+};
+
+/*
+ * Actions for Reservation Release
+ */
+enum nvme_resv_release_action {
+ NVME_RESV_REL_RELEASE = 0x00,
+ NVME_RESV_REL_CLEAR = 0x01
+};
+
struct nvme_power_state {
/** Maximum Power */
uint16_t mp; /* Maximum Power */
@@ -1259,6 +1321,10 @@ struct nvme_controller_data {
uint8_t ieee[3];
/** multi-interface capabilities */
+#define NVME_CD_MIC_MPORT 0x01
+#define NVME_CD_MIC_MCTRL 0x02
+#define NVME_CD_MIC_SRIOV 0x04
+#define NVME_CD_MIC_ANAR 0x08
uint8_t mic;
/** maximum data transfer size */
@@ -1280,7 +1346,17 @@ struct nvme_controller_data {
uint32_t oaes; /* bitfield really */
/** Controller Attributes */
- uint32_t ctratt; /* bitfield really */
+#define NVME_CD_CTRATT_EXHID 0x001
+#define NVME_CD_CTRATT_NOPSPM 0x002
+#define NVME_CD_CTRATT_NVMSETS 0x004
+#define NVME_CD_CTRATT_RRLVLS 0x008
+#define NVME_CD_CTRATT_ENDGRPS 0x010
+#define NVME_CD_CTRATT_PREDLM 0x020
+#define NVME_CD_CTRATT_TBKAS 0x040
+#define NVME_CD_CTRATT_NSGRAN 0x080
+#define NVME_CD_CTRATT_SQASSOC 0x100
+#define NVME_CD_CTRATT_UUIDLIST 0x200
+ uint32_t ctratt;
/** Read Recovery Levels Supported */
uint16_t rrls;
@@ -1865,11 +1941,25 @@ struct intel_log_temp_stats {
_Static_assert(sizeof(struct intel_log_temp_stats) == 13 * 8, "bad size for intel_log_temp_stats");
+struct nvme_resv_acq_data {
+ uint64_t crkey;
+ uint64_t prkey;
+} __packed __aligned(4);
+
+_Static_assert(sizeof(struct nvme_resv_acq_data) == 2 * 8, "bad size for nvme_resv_acq_data");
+
+struct nvme_resv_reg_data {
+ uint64_t crkey;
+ uint64_t nrkey;
+} __packed __aligned(4);
+
+_Static_assert(sizeof(struct nvme_resv_reg_data) == 2 * 8, "bad size for nvme_resv_reg_data");
+
struct nvme_resv_reg_ctrlr {
uint16_t ctrlr_id; /* Controller ID */
uint8_t rcsts; /* Reservation Status */
uint8_t reserved3[5];
- uint64_t hostid; /* Host Identifier */
+ uint64_t hostid; /* Host Identifier (little endian) */
uint64_t rkey; /* Reservation Key */
} __packed __aligned(4);
@@ -1880,7 +1970,7 @@ struct nvme_resv_reg_ctrlr_ext {
uint8_t rcsts; /* Reservation Status */
uint8_t reserved3[5];
uint64_t rkey; /* Reservation Key */
- uint64_t hostid[2]; /* Host Identifier */
+ uint64_t hostid[2]; /* Host Identifier (little endian) */
uint8_t reserved32[32];
} __packed __aligned(4);
@@ -1998,6 +2088,7 @@ struct nvme_hmb_desc {
(NVME_STATUS_GET_SC((cpl)->status) != 0 || NVME_STATUS_GET_SCT((cpl)->status) != 0)
void nvme_cpl_sbuf(const struct nvme_completion *cpl, struct sbuf *sbuf);
+void nvme_hostid_sbuf(struct sbuf *sb, const uint8_t *hostid, bool exhid);
void nvme_opcode_sbuf(bool admin, uint8_t opc, struct sbuf *sb);
void nvme_sc_sbuf(const struct nvme_completion *cpl, struct sbuf *sbuf);
void nvme_strvis(uint8_t *dst, const uint8_t *src, int dstlen, int srclen);
@@ -2031,13 +2122,13 @@ int nvme_ctrlr_linux_passthru_cmd(struct nvme_controller *ctrlr,
bool is_admin);
/* Admin functions */
-void nvme_ctrlr_cmd_set_feature(struct nvme_controller *ctrlr,
- uint8_t feature, uint32_t cdw11,
+void nvme_ctrlr_cmd_set_feature(struct nvme_controller *ctrlr, uint32_t nsid,
+ int sv, uint8_t feature, uint32_t cdw11,
uint32_t cdw12, uint32_t cdw13,
uint32_t cdw14, uint32_t cdw15,
void *payload, uint32_t payload_size,
nvme_cb_fn_t cb_fn, void *cb_arg);
-void nvme_ctrlr_cmd_get_feature(struct nvme_controller *ctrlr,
+void nvme_ctrlr_cmd_get_feature(struct nvme_controller *ctrlr, uint32_t nsid,
uint8_t feature, uint32_t cdw11,
void *payload, uint32_t payload_size,
nvme_cb_fn_t cb_fn, void *cb_arg);
@@ -2177,6 +2268,83 @@ nvme_ns_data_format_index(const struct nvme_namespace_data *nsdata)
return (fmt);
}
+static inline
+void nvme_ns_resv_report_cmd(struct nvme_command *cmd, uint32_t nsid,
+ uint32_t length, uint32_t report_type)
+{
+ cmd->opc = NVME_OPC_RESERVATION_REPORT;
+ cmd->nsid = htole32(nsid);
+ cmd->cdw10 = htole32(length);
+ cmd->cdw11 = htole32(report_type);
+}
+
+static inline
+void nvme_ns_resv_register_cmd(struct nvme_command *cmd, uint32_t nsid,
+ int cptpl, int iekey, int rrega)
+{
+ cmd->opc = NVME_OPC_RESERVATION_REGISTER;
+ cmd->nsid = htole32(nsid);
+ cmd->cdw10 = htole32((rrega & NVME_RESV_REG_MASK) | ((iekey & NVME_RESV_IEKEY_MASK) << 3) |
+ ((cptpl & NVME_RESV_CPTPL_MASK) << 30));
+}
+
+static inline
+void nvme_ns_resv_acquire_cmd(struct nvme_command *cmd, uint32_t nsid,
+ int rtype, int iekey, int racqa)
+{
+ cmd->opc = NVME_OPC_RESERVATION_ACQUIRE;
+ cmd->nsid = htole32(nsid);
+ cmd->cdw10 = htole32(((rtype & 0x0f) << 8) | ((iekey & NVME_RESV_IEKEY_MASK) << 3) |
+ (racqa & NVME_RESV_ACQUIRE_MASK));
+}
+
+static inline
+void nvme_ns_resv_release_cmd(struct nvme_command *cmd, uint32_t nsid,
+ int rtype, int iekey, int rrela)
+{
+ cmd->opc = NVME_OPC_RESERVATION_RELEASE;
+ cmd->nsid = htole32(nsid);
+ cmd->cdw10 = htole32(((rtype & 0x0f) << 8) | ((iekey & NVME_RESV_IEKEY_MASK) << 3) |
+ (rrela & 0x07));
+}
+
+
+static inline
+void nvme_admin_format_cmd(struct nvme_command *cmd, uint32_t nsid,
+ int ses, int pil, int pi, int mset, int lbaf)
+{
+ cmd->opc = NVME_OPC_FORMAT_NVM;
+ cmd->nsid = htole32(nsid);
+ cmd->cdw10 = htole32((ses << 9) | (pil << 8) | (pi << 5) | (mset << 4) |
+ lbaf);
+}
+
+static inline
+void nvme_admin_get_feature_cmd(struct nvme_command *cmd, uint32_t nsid,
+ int sel, uint8_t feature, uint32_t cdw11, int uuid_idx) {
+ cmd->opc = NVME_OPC_GET_FEATURES;
+ cmd->nsid = nsid;
+ cmd->cdw10 = htole32(((sel & 0x7) << 8) | feature);
+ cmd->cdw11 = htole32(cdw11);
+ cmd->cdw14 = htole32(uuid_idx & 0x7f);
+}
+
+
+static inline
+void nvme_admin_set_feature_cmd(struct nvme_command *cmd, uint32_t nsid,
+ int sv, uint8_t feature, uint32_t cdw11, uint32_t cdw12,
+ uint32_t cdw13, uint32_t cdw14, uint32_t cdw15)
+{
+ cmd->opc = NVME_OPC_SET_FEATURES;
+ cmd->nsid = nsid;
+ cmd->cdw10 = htole32(((sv & 0x1) << 31) | feature);
+ cmd->cdw11 = htole32(cdw11);
+ cmd->cdw12 = htole32(cdw12);
+ cmd->cdw13 = htole32(cdw13);
+ cmd->cdw14 = htole32(cdw14);
+ cmd->cdw15 = htole32(cdw15);
+}
+
/* Endianess conversion functions for NVMe structs */
static inline
void nvme_completion_swapbytes(struct nvme_completion *s __unused)
@@ -2413,10 +2581,9 @@ void nvme_resv_status_swapbytes(struct nvme_resv_status *s __unused,
s->gen = le32toh(s->gen);
n = (s->regctl[1] << 8) | s->regctl[0];
- n = MIN(n, (size - sizeof(s)) / sizeof(s->ctrlr[0]));
+ n = MIN(n, (size - sizeof(*s)) / sizeof(s->ctrlr[0]));
for (i = 0; i < n; i++) {
s->ctrlr[i].ctrlr_id = le16toh(s->ctrlr[i].ctrlr_id);
- s->ctrlr[i].hostid = le64toh(s->ctrlr[i].hostid);
s->ctrlr[i].rkey = le64toh(s->ctrlr[i].rkey);
}
#endif
@@ -2431,11 +2598,10 @@ void nvme_resv_status_ext_swapbytes(struct nvme_resv_status_ext *s __unused,
s->gen = le32toh(s->gen);
n = (s->regctl[1] << 8) | s->regctl[0];
- n = MIN(n, (size - sizeof(s)) / sizeof(s->ctrlr[0]));
+ n = MIN(n, (size - sizeof(*s)) / sizeof(s->ctrlr[0]));
for (i = 0; i < n; i++) {
s->ctrlr[i].ctrlr_id = le16toh(s->ctrlr[i].ctrlr_id);
s->ctrlr[i].rkey = le64toh(s->ctrlr[i].rkey);
- nvme_le128toh((void *)s->ctrlr[i].hostid);
}
#endif
}
diff --git a/sys/dev/nvme/nvme_ctrlr.c b/sys/dev/nvme/nvme_ctrlr.c
index 16deec4c1bb8..6eff9af77aac 100644
--- a/sys/dev/nvme/nvme_ctrlr.c
+++ b/sys/dev/nvme/nvme_ctrlr.c
@@ -852,7 +852,7 @@ nvme_ctrlr_configure_aer(struct nvme_controller *ctrlr)
NVME_ASYNC_EVENT_FW_ACTIVATE);
status.done = 0;
- nvme_ctrlr_cmd_get_feature(ctrlr, NVME_FEAT_TEMPERATURE_THRESHOLD,
+ nvme_ctrlr_cmd_get_feature(ctrlr, 0, NVME_FEAT_TEMPERATURE_THRESHOLD,
0, NULL, 0, nvme_completion_poll_cb, &status);
nvme_completion_poll(&status);
if (nvme_completion_is_error(&status.cpl) ||
@@ -895,7 +895,7 @@ nvme_ctrlr_configure_apst(struct nvme_controller *ctrlr)
data[i] = htole64(data[i]);
} else {
status.done = 0;
- nvme_ctrlr_cmd_get_feature(ctrlr,
+ nvme_ctrlr_cmd_get_feature(ctrlr, 0,
NVME_FEAT_AUTONOMOUS_POWER_STATE_TRANSITION, 0,
data, data_size, nvme_completion_poll_cb, &status);
nvme_completion_poll(&status);
@@ -904,7 +904,7 @@ nvme_ctrlr_configure_apst(struct nvme_controller *ctrlr)
}
status.done = 0;
- nvme_ctrlr_cmd_set_feature(ctrlr,
+ nvme_ctrlr_cmd_set_feature(ctrlr, 0, 0,
NVME_FEAT_AUTONOMOUS_POWER_STATE_TRANSITION, enable, 0, 0,
0, 0, data, data_size, nvme_completion_poll_cb, &status);
nvme_completion_poll(&status);
@@ -932,8 +932,8 @@ nvme_ctrlr_set_timestamp(struct nvme_controller *ctrlr)
ts->tstmp[i] = (ms >> (i * 8)) & 0xff;
status.done = 0;
- nvme_ctrlr_cmd_set_feature(ctrlr, NVME_FEAT_TIMESTAMP, 0, 0, 0, 0, 0,
- ts, sizeof(*ts), nvme_completion_poll_cb, &status);
+ nvme_ctrlr_cmd_set_feature(ctrlr, 0, 0, NVME_FEAT_TIMESTAMP, 0, 0, 0,
+ 0, 0, ts, sizeof(*ts), nvme_completion_poll_cb, &status);
nvme_completion_poll(&status);
if (nvme_completion_is_error(&status.cpl) && bootverbose)
nvme_printf(ctrlr, "failed to set the timestamp\n");
@@ -1179,11 +1179,10 @@ nvme_ctrlr_hmb_enable(struct nvme_controller *ctrlr, bool enable, bool memret)
if (memret)
cdw11 |= 2;
status.done = 0;
- nvme_ctrlr_cmd_set_feature(ctrlr, NVME_FEAT_HOST_MEMORY_BUFFER, cdw11,
- ctrlr->hmb_nchunks * ctrlr->hmb_chunk / ctrlr->page_size,
+ nvme_ctrlr_cmd_set_feature(ctrlr, 0, 0, NVME_FEAT_HOST_MEMORY_BUFFER,
+ cdw11, ctrlr->hmb_nchunks * ctrlr->hmb_chunk / 4096,
ctrlr->hmb_desc_paddr, ctrlr->hmb_desc_paddr >> 32,
- ctrlr->hmb_nchunks, NULL, 0,
- nvme_completion_poll_cb, &status);
+ ctrlr->hmb_nchunks, NULL, 0, nvme_completion_poll_cb, &status);
nvme_completion_poll(&status);
if (nvme_completion_is_error(&status.cpl))
nvme_printf(ctrlr, "nvme_ctrlr_hmb_enable failed!\n");
diff --git a/sys/dev/nvme/nvme_ctrlr_cmd.c b/sys/dev/nvme/nvme_ctrlr_cmd.c
index b9a60e10cb72..3bd9434268d0 100644
--- a/sys/dev/nvme/nvme_ctrlr_cmd.c
+++ b/sys/dev/nvme/nvme_ctrlr_cmd.c
@@ -158,9 +158,9 @@ nvme_ctrlr_cmd_delete_io_sq(struct nvme_controller *ctrlr,
}
void
-nvme_ctrlr_cmd_set_feature(struct nvme_controller *ctrlr, uint8_t feature,
- uint32_t cdw11, uint32_t cdw12, uint32_t cdw13, uint32_t cdw14,
- uint32_t cdw15, void *payload, uint32_t payload_size,
+nvme_ctrlr_cmd_set_feature(struct nvme_controller *ctrlr, uint32_t nsid, int sv,
+ uint8_t feature, uint32_t cdw11, uint32_t cdw12, uint32_t cdw13,
+ uint32_t cdw14, uint32_t cdw15, void *payload, uint32_t payload_size,
nvme_cb_fn_t cb_fn, void *cb_arg)
{
struct nvme_request *req;
@@ -173,20 +173,15 @@ nvme_ctrlr_cmd_set_feature(struct nvme_controller *ctrlr, uint8_t feature,
req = nvme_allocate_request_null(M_WAITOK, cb_fn, cb_arg);
cmd = &req->cmd;
- cmd->opc = NVME_OPC_SET_FEATURES;
- cmd->cdw10 = htole32(feature);
- cmd->cdw11 = htole32(cdw11);
- cmd->cdw12 = htole32(cdw12);
- cmd->cdw13 = htole32(cdw13);
- cmd->cdw14 = htole32(cdw14);
- cmd->cdw15 = htole32(cdw15);
+ nvme_admin_set_feature_cmd(cmd, nsid, sv, feature, cdw11, cdw12, cdw13,
+ cdw14, cdw15);
nvme_ctrlr_submit_admin_request(ctrlr, req);
}
void
-nvme_ctrlr_cmd_get_feature(struct nvme_controller *ctrlr, uint8_t feature,
- uint32_t cdw11, void *payload, uint32_t payload_size,
+nvme_ctrlr_cmd_get_feature(struct nvme_controller *ctrlr, uint32_t nsid,
+ uint8_t feature, uint32_t cdw11, void *payload, uint32_t payload_size,
nvme_cb_fn_t cb_fn, void *cb_arg)
{
struct nvme_request *req;
@@ -199,9 +194,7 @@ nvme_ctrlr_cmd_get_feature(struct nvme_controller *ctrlr, uint8_t feature,
req = nvme_allocate_request_null(M_WAITOK, cb_fn, cb_arg);
cmd = &req->cmd;
- cmd->opc = NVME_OPC_GET_FEATURES;
- cmd->cdw10 = htole32(feature);
- cmd->cdw11 = htole32(cdw11);
+ nvme_admin_get_feature_cmd(cmd, nsid, 0, feature, cdw11, 0);
nvme_ctrlr_submit_admin_request(ctrlr, req);
}
@@ -213,8 +206,8 @@ nvme_ctrlr_cmd_set_num_queues(struct nvme_controller *ctrlr,
uint32_t cdw11;
cdw11 = ((num_queues - 1) << 16) | (num_queues - 1);
- nvme_ctrlr_cmd_set_feature(ctrlr, NVME_FEAT_NUMBER_OF_QUEUES, cdw11,
- 0, 0, 0, 0, NULL, 0, cb_fn, cb_arg);
+ nvme_ctrlr_cmd_set_feature(ctrlr, 0, 0, NVME_FEAT_NUMBER_OF_QUEUES,
+ cdw11, 0, 0, 0, 0, NULL, 0, cb_fn, cb_arg);
}
void
@@ -224,7 +217,7 @@ nvme_ctrlr_cmd_set_async_event_config(struct nvme_controller *ctrlr,
uint32_t cdw11;
cdw11 = state;
- nvme_ctrlr_cmd_set_feature(ctrlr,
+ nvme_ctrlr_cmd_set_feature(ctrlr, 0, 0,
NVME_FEAT_ASYNC_EVENT_CONFIGURATION, cdw11, 0, 0, 0, 0, NULL, 0,
cb_fn, cb_arg);
}
@@ -250,8 +243,8 @@ nvme_ctrlr_cmd_set_interrupt_coalescing(struct nvme_controller *ctrlr,
}
cdw11 = ((microseconds/100) << 8) | threshold;
- nvme_ctrlr_cmd_set_feature(ctrlr, NVME_FEAT_INTERRUPT_COALESCING, cdw11,
- 0, 0, 0, 0, NULL, 0, cb_fn, cb_arg);
+ nvme_ctrlr_cmd_set_feature(ctrlr, 0, 0, NVME_FEAT_INTERRUPT_COALESCING,
+ cdw11, 0, 0, 0, 0, NULL, 0, cb_fn, cb_arg);
}
void
@@ -259,8 +252,8 @@ nvme_ctrlr_cmd_set_arbitration(struct nvme_controller *ctrlr,
uint32_t cdw11, nvme_cb_fn_t cb_fn, void *cb_arg)
{
- nvme_ctrlr_cmd_set_feature(ctrlr, NVME_FEAT_ARBITRATION, cdw11,
- 0, 0, 0, 0, NULL, 0, cb_fn, cb_arg);
+ nvme_ctrlr_cmd_set_feature(ctrlr, 0, 0, NVME_FEAT_ARBITRATION,
+ cdw11, 0, 0, 0, 0, NULL, 0, cb_fn, cb_arg);
}
void
diff --git a/sys/dev/nvme/nvme_util.c b/sys/dev/nvme/nvme_util.c
index cb0ba729ac96..6b1a0ccb4bec 100644
--- a/sys/dev/nvme/nvme_util.c
+++ b/sys/dev/nvme/nvme_util.c
@@ -268,6 +268,21 @@ nvme_cpl_sbuf(const struct nvme_completion *cpl, struct sbuf *sb)
sbuf_printf(sb, " DNR");
}
+/*
+ * Append an 8 or 16 byte hostid as an integer value in base 16 to an sbuf.
+ * The hostid is in the little-endian byte order the device returns it in,
+ * so print it most significant byte first.
+ */
+void
+nvme_hostid_sbuf(struct sbuf *sb, const uint8_t *hostid, bool exhid)
+{
+ int i;
+
+ sbuf_cat(sb, "0x");
+ for (i = (exhid ? 16 : 8) - 1; i >= 0; i--)
+ sbuf_printf(sb, "%02x", hostid[i]);
+}
+
void
nvme_strvis(uint8_t *dst, const uint8_t *src, int dstlen, int srclen)
{