aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/nvmf
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/nvmf')
-rw-r--r--sys/dev/nvmf/controller/nvmft_controller.c16
-rw-r--r--sys/dev/nvmf/controller/nvmft_qpair.c6
-rw-r--r--sys/dev/nvmf/controller/nvmft_var.h1
-rw-r--r--sys/dev/nvmf/host/nvmf.c16
-rw-r--r--sys/dev/nvmf/host/nvmf_ns.c3
-rw-r--r--sys/dev/nvmf/host/nvmf_qpair.c6
-rw-r--r--sys/dev/nvmf/host/nvmf_var.h1
-rw-r--r--sys/dev/nvmf/nvmf_tcp.c14
-rw-r--r--sys/dev/nvmf/nvmf_transport.c12
-rw-r--r--sys/dev/nvmf/nvmf_transport.h14
-rw-r--r--sys/dev/nvmf/nvmf_transport_internal.h6
11 files changed, 91 insertions, 4 deletions
diff --git a/sys/dev/nvmf/controller/nvmft_controller.c b/sys/dev/nvmf/controller/nvmft_controller.c
index 390467534ca2..1618c1f96dac 100644
--- a/sys/dev/nvmf/controller/nvmft_controller.c
+++ b/sys/dev/nvmf/controller/nvmft_controller.c
@@ -31,7 +31,7 @@ nvmft_printf(struct nvmft_controller *ctrlr, const char *fmt, ...)
va_list ap;
size_t retval;
- sbuf_new(&sb, buf, sizeof(buf), SBUF_FIXEDLEN);
+ sbuf_new(&sb, buf, sizeof(buf), SBUF_FIXEDLEN | SBUF_INCLUDENUL);
sbuf_set_drain(&sb, sbuf_printf_drain, &retval);
sbuf_printf(&sb, "nvmft%u: ", ctrlr->cntlid);
@@ -103,6 +103,19 @@ nvmft_keep_alive_timer(void *arg)
callout_schedule_sbt(&ctrlr->ka_timer, ctrlr->ka_sbt, 0, C_HARDCLOCK);
}
+static void
+nvmft_update_cdata(struct nvmft_controller *ctrlr)
+{
+ uint32_t ioccsz, val;
+
+ val = nvmft_max_ioccsz(ctrlr->admin);
+ if (val != 0) {
+ ioccsz = le32toh(ctrlr->cdata.ioccsz) * 16;
+ if (val < ioccsz)
+ ctrlr->cdata.ioccsz = htole32(val / 16);
+ }
+}
+
int
nvmft_handoff_admin_queue(struct nvmft_port *np, enum nvmf_trtype trtype,
const nvlist_t *params, const struct nvmf_fabric_connect_cmd *cmd,
@@ -160,6 +173,7 @@ nvmft_handoff_admin_queue(struct nvmft_port *np, enum nvmf_trtype trtype,
(int)sizeof(data->hostnqn), data->hostnqn);
ctrlr->admin = qp;
ctrlr->trtype = trtype;
+ nvmft_update_cdata(ctrlr);
/*
* The spec requires a non-zero KeepAlive timer, but allow a
diff --git a/sys/dev/nvmf/controller/nvmft_qpair.c b/sys/dev/nvmf/controller/nvmft_qpair.c
index 73c7bb280780..1300c9ec91fc 100644
--- a/sys/dev/nvmf/controller/nvmft_qpair.c
+++ b/sys/dev/nvmf/controller/nvmft_qpair.c
@@ -182,6 +182,12 @@ nvmft_qpair_name(struct nvmft_qpair *qp)
return (qp->name);
}
+uint32_t
+nvmft_max_ioccsz(struct nvmft_qpair *qp)
+{
+ return (nvmf_max_ioccsz(qp->qp));
+}
+
static int
_nvmft_send_response(struct nvmft_qpair *qp, const void *cqe)
{
diff --git a/sys/dev/nvmf/controller/nvmft_var.h b/sys/dev/nvmf/controller/nvmft_var.h
index 85032b2dc55f..b3a5278a639c 100644
--- a/sys/dev/nvmf/controller/nvmft_var.h
+++ b/sys/dev/nvmf/controller/nvmft_var.h
@@ -145,6 +145,7 @@ struct nvmft_controller *nvmft_qpair_ctrlr(struct nvmft_qpair *qp);
void nvmft_qpair_datamove(struct nvmft_qpair *qp, union ctl_io *io);
uint16_t nvmft_qpair_id(struct nvmft_qpair *qp);
const char *nvmft_qpair_name(struct nvmft_qpair *qp);
+uint32_t nvmft_max_ioccsz(struct nvmft_qpair *qp);
void nvmft_command_completed(struct nvmft_qpair *qp,
struct nvmf_capsule *nc);
int nvmft_send_response(struct nvmft_qpair *qp, const void *cqe);
diff --git a/sys/dev/nvmf/host/nvmf.c b/sys/dev/nvmf/host/nvmf.c
index 1ac0d142443b..8ed801524089 100644
--- a/sys/dev/nvmf/host/nvmf.c
+++ b/sys/dev/nvmf/host/nvmf.c
@@ -498,7 +498,7 @@ nvmf_attach(device_t dev)
nvlist_t *nvl = device_get_ivars(dev);
const nvlist_t * const *io;
struct sysctl_oid *oid;
- uint64_t val;
+ uint64_t mpsmin, val;
u_int i;
int error;
@@ -545,13 +545,20 @@ nvmf_attach(device_t dev)
sc->vs = val;
/* Honor MDTS if it is set. */
+ mpsmin = (uint64_t)1 << (NVME_MPS_SHIFT +
+ NVME_CAP_HI_MPSMIN(sc->cap >> 32));
sc->max_xfer_size = maxphys;
if (sc->cdata->mdts != 0) {
sc->max_xfer_size = ulmin(sc->max_xfer_size,
- 1 << (sc->cdata->mdts + NVME_MPS_SHIFT +
- NVME_CAP_HI_MPSMIN(sc->cap >> 32)));
+ mpsmin << sc->cdata->mdts);
}
+ /* Honor any transfer size restriction imposed by the transport. */
+ val = nvmf_max_xfer_size_qp(sc->io[0]);
+ if (val >= mpsmin)
+ sc->max_xfer_size = ulmin(sc->max_xfer_size,
+ rounddown2(val, mpsmin));
+
io = nvlist_get_nvlist_array(nvl, "io", NULL);
sc->max_pending_io = nvlist_get_number(io[0], "qsize") *
sc->num_io_queues;
@@ -1230,6 +1237,9 @@ nvmf_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int flag,
case NVME_GET_CONTROLLER_DATA:
memcpy(arg, sc->cdata, sizeof(*sc->cdata));
return (0);
+ case DIOCGIDENT:
+ nvme_cdata_get_disk_ident(sc->cdata, (uint8_t *)arg);
+ return (0);
case NVMF_RECONNECT_PARAMS:
nv = (struct nvmf_ioc_nv *)arg;
return (nvmf_reconnect_params(sc, nv));
diff --git a/sys/dev/nvmf/host/nvmf_ns.c b/sys/dev/nvmf/host/nvmf_ns.c
index 4215c8295d2e..d57280e19d41 100644
--- a/sys/dev/nvmf/host/nvmf_ns.c
+++ b/sys/dev/nvmf/host/nvmf_ns.c
@@ -278,6 +278,9 @@ nvmf_ns_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag,
sizeof(gnsid->cdev));
gnsid->nsid = ns->id;
return (0);
+ case DIOCGIDENT:
+ nvme_cdata_get_disk_ident(ns->sc->cdata, (uint8_t *)arg);
+ return (0);
case DIOCGMEDIASIZE:
*(off_t *)arg = ns->size;
return (0);
diff --git a/sys/dev/nvmf/host/nvmf_qpair.c b/sys/dev/nvmf/host/nvmf_qpair.c
index 2f511cf0406d..adb57e52d002 100644
--- a/sys/dev/nvmf/host/nvmf_qpair.c
+++ b/sys/dev/nvmf/host/nvmf_qpair.c
@@ -416,6 +416,12 @@ nvmf_destroy_qp(struct nvmf_host_qpair *qp)
free(qp, M_NVMF);
}
+uint64_t
+nvmf_max_xfer_size_qp(struct nvmf_host_qpair *qp)
+{
+ return (nvmf_max_xfer_size(qp->qp));
+}
+
void
nvmf_submit_request(struct nvmf_request *req)
{
diff --git a/sys/dev/nvmf/host/nvmf_var.h b/sys/dev/nvmf/host/nvmf_var.h
index 606245b3969c..9190da300d85 100644
--- a/sys/dev/nvmf/host/nvmf_var.h
+++ b/sys/dev/nvmf/host/nvmf_var.h
@@ -210,6 +210,7 @@ struct nvmf_host_qpair *nvmf_init_qp(struct nvmf_softc *sc,
enum nvmf_trtype trtype, const nvlist_t *nvl, const char *name, u_int qid);
void nvmf_shutdown_qp(struct nvmf_host_qpair *qp);
void nvmf_destroy_qp(struct nvmf_host_qpair *qp);
+uint64_t nvmf_max_xfer_size_qp(struct nvmf_host_qpair *qp);
struct nvmf_request *nvmf_allocate_request(struct nvmf_host_qpair *qp,
void *sqe, nvmf_request_complete_t *cb, void *cb_arg, int how);
void nvmf_submit_request(struct nvmf_request *req);
diff --git a/sys/dev/nvmf/nvmf_tcp.c b/sys/dev/nvmf/nvmf_tcp.c
index e50d7ff48d2b..481c769cedcb 100644
--- a/sys/dev/nvmf/nvmf_tcp.c
+++ b/sys/dev/nvmf/nvmf_tcp.c
@@ -1602,6 +1602,18 @@ tcp_free_qpair(struct nvmf_qpair *nq)
tcp_release_qpair(qp);
}
+static uint32_t
+tcp_max_ioccsz(struct nvmf_qpair *nq)
+{
+ return (0);
+}
+
+static uint64_t
+tcp_max_xfer_size(struct nvmf_qpair *nq)
+{
+ return (0);
+}
+
static struct nvmf_capsule *
tcp_allocate_capsule(struct nvmf_qpair *nq, int how)
{
@@ -1872,6 +1884,8 @@ tcp_send_controller_data(struct nvmf_capsule *nc, uint32_t data_offset,
struct nvmf_transport_ops tcp_ops = {
.allocate_qpair = tcp_allocate_qpair,
.free_qpair = tcp_free_qpair,
+ .max_ioccsz = tcp_max_ioccsz,
+ .max_xfer_size = tcp_max_xfer_size,
.allocate_capsule = tcp_allocate_capsule,
.free_capsule = tcp_free_capsule,
.transmit_capsule = tcp_transmit_capsule,
diff --git a/sys/dev/nvmf/nvmf_transport.c b/sys/dev/nvmf/nvmf_transport.c
index 1d3f5ea4cf69..92d71d1b13fd 100644
--- a/sys/dev/nvmf/nvmf_transport.c
+++ b/sys/dev/nvmf/nvmf_transport.c
@@ -188,6 +188,18 @@ nvmf_sqhd_valid(struct nvmf_capsule *nc)
return (nc->nc_sqhd_valid);
}
+uint64_t
+nvmf_max_xfer_size(struct nvmf_qpair *qp)
+{
+ return (qp->nq_ops->max_xfer_size(qp));
+}
+
+uint32_t
+nvmf_max_ioccsz(struct nvmf_qpair *qp)
+{
+ return (qp->nq_ops->max_ioccsz(qp));
+}
+
uint8_t
nvmf_validate_command_capsule(struct nvmf_capsule *nc)
{
diff --git a/sys/dev/nvmf/nvmf_transport.h b/sys/dev/nvmf/nvmf_transport.h
index b192baeaccc1..495e0dbc8c37 100644
--- a/sys/dev/nvmf/nvmf_transport.h
+++ b/sys/dev/nvmf/nvmf_transport.h
@@ -81,9 +81,23 @@ void *nvmf_capsule_sqe(struct nvmf_capsule *nc);
void *nvmf_capsule_cqe(struct nvmf_capsule *nc);
bool nvmf_sqhd_valid(struct nvmf_capsule *nc);
+/* Host-specific APIs. */
+
+/*
+ * Largest I/O request size for a single command supported by the
+ * transport. If the transport does not have a limit, returns 0.
+ */
+uint64_t nvmf_max_xfer_size(struct nvmf_qpair *qp);
+
/* Controller-specific APIs. */
/*
+ * Largest I/O command capsule size (IOCCSZ) supported by the
+ * transport. If the transport does not have a limit, returns 0.
+ */
+uint32_t nvmf_max_ioccsz(struct nvmf_qpair *qp);
+
+/*
* A controller calls this function to check for any
* transport-specific errors (invalid fields) in a received command
* capsule. The callback returns a generic command status value:
diff --git a/sys/dev/nvmf/nvmf_transport_internal.h b/sys/dev/nvmf/nvmf_transport_internal.h
index eb819a5c83b9..9b459716168a 100644
--- a/sys/dev/nvmf/nvmf_transport_internal.h
+++ b/sys/dev/nvmf/nvmf_transport_internal.h
@@ -25,6 +25,12 @@ struct nvmf_transport_ops {
const nvlist_t *nvl);
void (*free_qpair)(struct nvmf_qpair *qp);
+ /* Limit on I/O command capsule size. */
+ uint32_t (*max_ioccsz)(struct nvmf_qpair *qp);
+
+ /* Limit on transfer size. */
+ uint64_t (*max_xfer_size)(struct nvmf_qpair *qp);
+
/* Capsule operations. */
struct nvmf_capsule *(*allocate_capsule)(struct nvmf_qpair *qp,
int how);