aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorNavdeep Parhar <np@FreeBSD.org>2016-08-25 05:22:53 +0000
committerNavdeep Parhar <np@FreeBSD.org>2016-08-25 05:22:53 +0000
commit97b84d344d4a7bb9e34703948e31be5247318a71 (patch)
tree956a2021fa5a85180b18e0c435a8cdcba6356718 /sys
parent02d99265593c8c13ae08eaa7a962531bcd9889a0 (diff)
downloadsrc-97b84d344d4a7bb9e34703948e31be5247318a71.tar.gz
src-97b84d344d4a7bb9e34703948e31be5247318a71.zip
Make the iSCSI parameter negotiation more flexible.
Decouple the send and receive limits on the amount of data in a single iSCSI PDU. MaxRecvDataSegmentLength is declarative, not negotiated, and is direction-specific so there is no reason for both ends to limit themselves to the same min(initiator, target) value in both directions. Allow iSCSI drivers to report their send, receive, first burst, and max burst limits explicitly instead of using hardcoded values or trying to derive all of them from the receive limit (which was the only limit reported by the drivers prior to this change). Display the send and receive limits separately in the userspace iSCSI utilities. Reviewed by: jpaetzel@ (earlier version), trasz@ Sponsored by: Chelsio Communications Differential Revision: https://reviews.freebsd.org/D7279
Notes
Notes: svn path=/head/; revision=304787
Diffstat (limited to 'sys')
-rw-r--r--sys/cam/ctl/ctl_frontend_iscsi.c36
-rw-r--r--sys/cam/ctl/ctl_frontend_iscsi.h7
-rw-r--r--sys/cam/ctl/ctl_ioctl.h24
-rw-r--r--sys/dev/cxgbe/cxgbei/icl_cxgbei.c7
-rw-r--r--sys/dev/iscsi/icl.c37
-rw-r--r--sys/dev/iscsi/icl.h14
-rw-r--r--sys/dev/iscsi/icl_soft.c4
-rw-r--r--sys/dev/iscsi/iscsi.c46
-rw-r--r--sys/dev/iscsi/iscsi.h7
-rw-r--r--sys/dev/iscsi/iscsi_ioctl.h22
-rw-r--r--sys/dev/iser/icl_iser.c4
11 files changed, 140 insertions, 68 deletions
diff --git a/sys/cam/ctl/ctl_frontend_iscsi.c b/sys/cam/ctl/ctl_frontend_iscsi.c
index 70de5fa79b0f..98e33faa62c0 100644
--- a/sys/cam/ctl/ctl_frontend_iscsi.c
+++ b/sys/cam/ctl/ctl_frontend_iscsi.c
@@ -1512,7 +1512,8 @@ cfiscsi_ioctl_handoff(struct ctl_iscsi *ci)
*/
cs->cs_cmdsn = cihp->cmdsn;
cs->cs_statsn = cihp->statsn;
- cs->cs_max_data_segment_length = cihp->max_recv_data_segment_length;
+ cs->cs_max_recv_data_segment_length = cihp->max_recv_data_segment_length;
+ cs->cs_max_send_data_segment_length = cihp->max_send_data_segment_length;
cs->cs_max_burst_length = cihp->max_burst_length;
cs->cs_first_burst_length = cihp->first_burst_length;
cs->cs_immediate_data = !!cihp->immediate_data;
@@ -1652,9 +1653,10 @@ cfiscsi_ioctl_list(struct ctl_iscsi *ci)
"<target_portal_group_tag>%u</target_portal_group_tag>"
"<header_digest>%s</header_digest>"
"<data_digest>%s</data_digest>"
- "<max_data_segment_length>%zd</max_data_segment_length>"
- "<max_burst_length>%zd</max_burst_length>"
- "<first_burst_length>%zd</first_burst_length>"
+ "<max_recv_data_segment_length>%d</max_recv_data_segment_length>"
+ "<max_send_data_segment_length>%d</max_send_data_segment_length>"
+ "<max_burst_length>%d</max_burst_length>"
+ "<first_burst_length>%d</first_burst_length>"
"<immediate_data>%d</immediate_data>"
"<iser>%d</iser>"
"<offload>%s</offload>"
@@ -1665,7 +1667,8 @@ cfiscsi_ioctl_list(struct ctl_iscsi *ci)
cs->cs_target->ct_tag,
cs->cs_conn->ic_header_crc32c ? "CRC32C" : "None",
cs->cs_conn->ic_data_crc32c ? "CRC32C" : "None",
- cs->cs_max_data_segment_length,
+ cs->cs_max_recv_data_segment_length,
+ cs->cs_max_send_data_segment_length,
cs->cs_max_burst_length,
cs->cs_first_burst_length,
cs->cs_immediate_data,
@@ -1794,12 +1797,12 @@ static void
cfiscsi_ioctl_limits(struct ctl_iscsi *ci)
{
struct ctl_iscsi_limits_params *cilp;
+ struct icl_drv_limits idl;
int error;
cilp = (struct ctl_iscsi_limits_params *)&(ci->data);
- error = icl_limits(cilp->offload, false,
- &cilp->data_segment_limit);
+ error = icl_limits(cilp->offload, false, &idl);
if (error != 0) {
ci->status = CTL_ISCSI_ERROR;
snprintf(ci->error_str, sizeof(ci->error_str),
@@ -1808,6 +1811,13 @@ cfiscsi_ioctl_limits(struct ctl_iscsi *ci)
return;
}
+ cilp->max_recv_data_segment_length =
+ idl.idl_max_recv_data_segment_length;
+ cilp->max_send_data_segment_length =
+ idl.idl_max_send_data_segment_length;
+ cilp->max_burst_length = idl.idl_max_burst_length;
+ cilp->first_burst_length = idl.idl_first_burst_length;
+
ci->status = CTL_ISCSI_OK;
}
@@ -2466,12 +2476,12 @@ cfiscsi_datamove_in(union ctl_io *io)
/*
* Truncate to maximum data segment length.
*/
- KASSERT(response->ip_data_len < cs->cs_max_data_segment_length,
- ("ip_data_len %zd >= max_data_segment_length %zd",
- response->ip_data_len, cs->cs_max_data_segment_length));
+ KASSERT(response->ip_data_len < cs->cs_max_send_data_segment_length,
+ ("ip_data_len %zd >= max_send_data_segment_length %d",
+ response->ip_data_len, cs->cs_max_send_data_segment_length));
if (response->ip_data_len + len >
- cs->cs_max_data_segment_length) {
- len = cs->cs_max_data_segment_length -
+ cs->cs_max_send_data_segment_length) {
+ len = cs->cs_max_send_data_segment_length -
response->ip_data_len;
KASSERT(len <= sg_len, ("len %zd > sg_len %zd",
len, sg_len));
@@ -2529,7 +2539,7 @@ cfiscsi_datamove_in(union ctl_io *io)
i++;
}
- if (response->ip_data_len == cs->cs_max_data_segment_length) {
+ if (response->ip_data_len == cs->cs_max_send_data_segment_length) {
/*
* Can't stuff more data into the current PDU;
* queue it. Note that's not enough to check
diff --git a/sys/cam/ctl/ctl_frontend_iscsi.h b/sys/cam/ctl/ctl_frontend_iscsi.h
index d24f193cbbef..caef7d919fe7 100644
--- a/sys/cam/ctl/ctl_frontend_iscsi.h
+++ b/sys/cam/ctl/ctl_frontend_iscsi.h
@@ -84,9 +84,10 @@ struct cfiscsi_session {
struct cv cs_maintenance_cv;
bool cs_terminating;
bool cs_tasks_aborted;
- size_t cs_max_data_segment_length;
- size_t cs_max_burst_length;
- size_t cs_first_burst_length;
+ int cs_max_recv_data_segment_length;
+ int cs_max_send_data_segment_length;
+ int cs_max_burst_length;
+ int cs_first_burst_length;
bool cs_immediate_data;
char cs_initiator_name[CTL_ISCSI_NAME_LEN];
char cs_initiator_addr[CTL_ISCSI_ADDR_LEN];
diff --git a/sys/cam/ctl/ctl_ioctl.h b/sys/cam/ctl/ctl_ioctl.h
index 40bd1838725c..2872d7727c5b 100644
--- a/sys/cam/ctl/ctl_ioctl.h
+++ b/sys/cam/ctl/ctl_ioctl.h
@@ -622,7 +622,7 @@ struct ctl_iscsi_handoff_params {
char target_name[CTL_ISCSI_NAME_LEN];
int socket;
int portal_group_tag;
-
+
/*
* Connection parameters negotiated by ctld(8).
*/
@@ -630,17 +630,17 @@ struct ctl_iscsi_handoff_params {
ctl_iscsi_digest data_digest;
uint32_t cmdsn;
uint32_t statsn;
- uint32_t max_recv_data_segment_length;
- uint32_t max_burst_length;
- uint32_t first_burst_length;
+ int max_recv_data_segment_length;
+ int max_burst_length;
+ int first_burst_length;
uint32_t immediate_data;
char offload[CTL_ISCSI_OFFLOAD_LEN];
#ifdef ICL_KERNEL_PROXY
int connection_id;
- int spare[1];
#else
- int spare[2];
+ int spare;
#endif
+ int max_send_data_segment_length;
};
struct ctl_iscsi_list_params {
@@ -671,11 +671,15 @@ struct ctl_iscsi_terminate_params {
};
struct ctl_iscsi_limits_params {
+ /* passed to kernel */
char offload[CTL_ISCSI_OFFLOAD_LEN];
- /* passed to kernel */
- size_t data_segment_limit;
- /* passed to userland */
- int spare[4];
+
+ /* passed to userland */
+ size_t spare;
+ int max_recv_data_segment_length;
+ int max_send_data_segment_length;
+ int max_burst_length;
+ int first_burst_length;
};
#ifdef ICL_KERNEL_PROXY
diff --git a/sys/dev/cxgbe/cxgbei/icl_cxgbei.c b/sys/dev/cxgbe/cxgbei/icl_cxgbei.c
index 8f29452196fe..288e8e692a9b 100644
--- a/sys/dev/cxgbe/cxgbei/icl_cxgbei.c
+++ b/sys/dev/cxgbe/cxgbei/icl_cxgbei.c
@@ -832,10 +832,13 @@ icl_cxgbei_conn_transfer_done(struct icl_conn *ic, void *prv)
}
static int
-icl_cxgbei_limits(size_t *limitp)
+icl_cxgbei_limits(struct icl_drv_limits *idl)
{
- *limitp = CXGBEI_MAX_DSL;
+ idl->idl_max_recv_data_segment_length = CXGBEI_MAX_DSL;
+ idl->idl_max_send_data_segment_length = CXGBEI_MAX_DSL;
+ idl->idl_max_burst_length = 2 * 1024 * 1024;
+ idl->idl_first_burst_length = CXGBEI_MAX_DSL;
return (0);
}
diff --git a/sys/dev/iscsi/icl.c b/sys/dev/iscsi/icl.c
index 2823074f2104..9a20b54a1f83 100644
--- a/sys/dev/iscsi/icl.c
+++ b/sys/dev/iscsi/icl.c
@@ -59,7 +59,7 @@ struct icl_module {
char *im_name;
bool im_iser;
int im_priority;
- int (*im_limits)(size_t *limitp);
+ int (*im_limits)(struct icl_drv_limits *idl);
struct icl_conn *(*im_new_conn)(const char *name,
struct mtx *lock);
};
@@ -182,11 +182,12 @@ icl_new_conn(const char *offload, bool iser, const char *name, struct mtx *lock)
}
int
-icl_limits(const char *offload, bool iser, size_t *limitp)
+icl_limits(const char *offload, bool iser, struct icl_drv_limits *idl)
{
struct icl_module *im;
int error;
+ bzero(idl, sizeof(*idl));
sx_slock(&sc->sc_lock);
im = icl_find(offload, iser, false);
if (im == NULL) {
@@ -194,14 +195,42 @@ icl_limits(const char *offload, bool iser, size_t *limitp)
return (ENXIO);
}
- error = im->im_limits(limitp);
+ error = im->im_limits(idl);
sx_sunlock(&sc->sc_lock);
+ /*
+ * Validate the limits provided by the driver against values allowed by
+ * the iSCSI RFC. 0 means iscsid/ctld should pick a reasonable value.
+ *
+ * Note that max_send_dsl is an internal implementation detail and not
+ * part of the RFC.
+ */
+#define OUT_OF_RANGE(x, lo, hi) ((x) != 0 && ((x) < (lo) || (x) > (hi)))
+ if (error == 0 &&
+ (OUT_OF_RANGE(idl->idl_max_recv_data_segment_length, 512, 16777215) ||
+ OUT_OF_RANGE(idl->idl_max_send_data_segment_length, 512, 16777215) ||
+ OUT_OF_RANGE(idl->idl_max_burst_length, 512, 16777215) ||
+ OUT_OF_RANGE(idl->idl_first_burst_length, 512, 16777215))) {
+ error = EINVAL;
+ }
+#undef OUT_OF_RANGE
+
+ /*
+ * If both first_burst and max_burst are provided then first_burst must
+ * not exceed max_burst.
+ */
+ if (error == 0 && idl->idl_first_burst_length > 0 &&
+ idl->idl_max_burst_length > 0 &&
+ idl->idl_first_burst_length > idl->idl_max_burst_length) {
+ error = EINVAL;
+ }
+
return (error);
}
int
-icl_register(const char *offload, bool iser, int priority, int (*limits)(size_t *),
+icl_register(const char *offload, bool iser, int priority,
+ int (*limits)(struct icl_drv_limits *),
struct icl_conn *(*new_conn)(const char *, struct mtx *))
{
struct icl_module *im;
diff --git a/sys/dev/iscsi/icl.h b/sys/dev/iscsi/icl.h
index 292fa6006657..0a1ee9414e4f 100644
--- a/sys/dev/iscsi/icl.h
+++ b/sys/dev/iscsi/icl.h
@@ -126,12 +126,20 @@ struct icl_conn {
void *ic_prv0;
};
+struct icl_drv_limits {
+ int idl_max_recv_data_segment_length;
+ int idl_max_send_data_segment_length;
+ int idl_max_burst_length;
+ int idl_first_burst_length;
+ int spare[4];
+};
+
struct icl_conn *icl_new_conn(const char *offload, bool iser, const char *name,
struct mtx *lock);
-int icl_limits(const char *offload, bool iser, size_t *limitp);
-
+int icl_limits(const char *offload, bool iser,
+ struct icl_drv_limits *idl);
int icl_register(const char *offload, bool iser, int priority,
- int (*limits)(size_t *),
+ int (*limits)(struct icl_drv_limits *),
struct icl_conn *(*new_conn)(const char *, struct mtx *));
int icl_unregister(const char *offload, bool rdma);
diff --git a/sys/dev/iscsi/icl_soft.c b/sys/dev/iscsi/icl_soft.c
index 4efae9fd9712..230a41456796 100644
--- a/sys/dev/iscsi/icl_soft.c
+++ b/sys/dev/iscsi/icl_soft.c
@@ -1474,10 +1474,10 @@ icl_soft_conn_transfer_done(struct icl_conn *ic, void *prv)
}
static int
-icl_soft_limits(size_t *limitp)
+icl_soft_limits(struct icl_drv_limits *idl)
{
- *limitp = 128 * 1024;
+ idl->idl_max_recv_data_segment_length = 128 * 1024;
return (0);
}
diff --git a/sys/dev/iscsi/iscsi.c b/sys/dev/iscsi/iscsi.c
index 5364584816c2..57b60bb8423f 100644
--- a/sys/dev/iscsi/iscsi.c
+++ b/sys/dev/iscsi/iscsi.c
@@ -1204,8 +1204,8 @@ iscsi_pdu_handle_r2t(struct icl_pdu *response)
for (;;) {
len = total_len;
- if (len > is->is_max_data_segment_length)
- len = is->is_max_data_segment_length;
+ if (len > is->is_max_send_data_segment_length)
+ len = is->is_max_send_data_segment_length;
if (off + len > csio->dxfer_len) {
ISCSI_SESSION_WARN(is, "target requested invalid "
@@ -1313,6 +1313,7 @@ iscsi_ioctl_daemon_wait(struct iscsi_softc *sc,
struct iscsi_daemon_request *request)
{
struct iscsi_session *is;
+ struct icl_drv_limits idl;
int error;
sx_slock(&sc->sc_lock);
@@ -1352,10 +1353,9 @@ iscsi_ioctl_daemon_wait(struct iscsi_softc *sc,
request->idr_tsih = 0; /* New or reinstated session. */
memcpy(&request->idr_conf, &is->is_conf,
sizeof(request->idr_conf));
-
+
error = icl_limits(is->is_conf.isc_offload,
- is->is_conf.isc_iser,
- &request->idr_limits.isl_max_data_segment_length);
+ is->is_conf.isc_iser, &idl);
if (error != 0) {
ISCSI_SESSION_WARN(is, "icl_limits for offload \"%s\" "
"failed with error %d", is->is_conf.isc_offload,
@@ -1363,6 +1363,14 @@ iscsi_ioctl_daemon_wait(struct iscsi_softc *sc,
sx_sunlock(&sc->sc_lock);
return (error);
}
+ request->idr_limits.isl_max_recv_data_segment_length =
+ idl.idl_max_recv_data_segment_length;
+ request->idr_limits.isl_max_send_data_segment_length =
+ idl.idl_max_recv_data_segment_length;
+ request->idr_limits.isl_max_burst_length =
+ idl.idl_max_burst_length;
+ request->idr_limits.isl_first_burst_length =
+ idl.idl_first_burst_length;
sx_sunlock(&sc->sc_lock);
return (0);
@@ -1417,12 +1425,10 @@ iscsi_ioctl_daemon_handoff(struct iscsi_softc *sc,
is->is_initial_r2t = handoff->idh_initial_r2t;
is->is_immediate_data = handoff->idh_immediate_data;
- /*
- * Cap MaxRecvDataSegmentLength obtained from the target to the maximum
- * size supported by our ICL module.
- */
- is->is_max_data_segment_length = min(ic->ic_max_data_segment_length,
- handoff->idh_max_data_segment_length);
+ is->is_max_recv_data_segment_length =
+ handoff->idh_max_recv_data_segment_length;
+ is->is_max_send_data_segment_length =
+ handoff->idh_max_send_data_segment_length;
is->is_max_burst_length = handoff->idh_max_burst_length;
is->is_first_burst_length = handoff->idh_first_burst_length;
@@ -1634,7 +1640,7 @@ iscsi_ioctl_daemon_send(struct iscsi_softc *sc,
return (EIO);
datalen = ids->ids_data_segment_len;
- if (datalen > ISCSI_MAX_DATA_SEGMENT_LENGTH)
+ if (datalen > is->is_max_send_data_segment_length)
return (EINVAL);
if (datalen > 0) {
data = malloc(datalen, M_ISCSI, M_WAITOK);
@@ -1933,12 +1939,15 @@ iscsi_ioctl_session_list(struct iscsi_softc *sc, struct iscsi_session_list *isl)
else
iss.iss_data_digest = ISCSI_DIGEST_NONE;
- iss.iss_max_data_segment_length = is->is_max_data_segment_length;
+ iss.iss_max_send_data_segment_length =
+ is->is_max_send_data_segment_length;
+ iss.iss_max_recv_data_segment_length =
+ is->is_max_recv_data_segment_length;
iss.iss_max_burst_length = is->is_max_burst_length;
iss.iss_first_burst_length = is->is_first_burst_length;
iss.iss_immediate_data = is->is_immediate_data;
iss.iss_connected = is->is_connected;
-
+
error = copyout(&iss, isl->isl_pstates + i, sizeof(iss));
if (error != 0) {
sx_sunlock(&sc->sc_lock);
@@ -2259,12 +2268,13 @@ iscsi_action_scsiio(struct iscsi_session *is, union ccb *ccb)
len = csio->dxfer_len;
//ISCSI_SESSION_DEBUG(is, "adding %zd of immediate data", len);
if (len > is->is_first_burst_length) {
- ISCSI_SESSION_DEBUG(is, "len %zd -> %zd", len, is->is_first_burst_length);
+ ISCSI_SESSION_DEBUG(is, "len %zd -> %d", len, is->is_first_burst_length);
len = is->is_first_burst_length;
}
- if (len > is->is_max_data_segment_length) {
- ISCSI_SESSION_DEBUG(is, "len %zd -> %zd", len, is->is_max_data_segment_length);
- len = is->is_max_data_segment_length;
+ if (len > is->is_max_send_data_segment_length) {
+ ISCSI_SESSION_DEBUG(is, "len %zd -> %d", len,
+ is->is_max_send_data_segment_length);
+ len = is->is_max_send_data_segment_length;
}
error = icl_pdu_append_data(request, csio->data_ptr, len, M_NOWAIT);
diff --git a/sys/dev/iscsi/iscsi.h b/sys/dev/iscsi/iscsi.h
index 3225649cc464..d5bd79ab4140 100644
--- a/sys/dev/iscsi/iscsi.h
+++ b/sys/dev/iscsi/iscsi.h
@@ -62,12 +62,13 @@ struct iscsi_session {
int is_header_digest;
int is_data_digest;
int is_initial_r2t;
- size_t is_max_burst_length;
- size_t is_first_burst_length;
+ int is_max_burst_length;
+ int is_first_burst_length;
uint8_t is_isid[6];
uint16_t is_tsih;
bool is_immediate_data;
- size_t is_max_data_segment_length;
+ int is_max_recv_data_segment_length;
+ int is_max_send_data_segment_length;
char is_target_alias[ISCSI_ALIAS_LEN];
TAILQ_HEAD(, iscsi_outstanding) is_outstanding;
diff --git a/sys/dev/iscsi/iscsi_ioctl.h b/sys/dev/iscsi/iscsi_ioctl.h
index a494cd558ed1..3767c45f99df 100644
--- a/sys/dev/iscsi/iscsi_ioctl.h
+++ b/sys/dev/iscsi/iscsi_ioctl.h
@@ -76,8 +76,12 @@ struct iscsi_session_conf {
* iscsid(8) must obey those when negotiating operational parameters.
*/
struct iscsi_session_limits {
- size_t isl_max_data_segment_length;
- int isl_spare[8];
+ size_t isl_spare0;
+ int isl_max_recv_data_segment_length;
+ int isl_max_send_data_segment_length;
+ int isl_max_burst_length;
+ int isl_first_burst_length;
+ int isl_spare[4];
};
/*
@@ -89,14 +93,15 @@ struct iscsi_session_state {
char iss_target_alias[ISCSI_ALIAS_LEN];
int iss_header_digest;
int iss_data_digest;
- int iss_max_data_segment_length;
+ int iss_max_recv_data_segment_length;
int iss_max_burst_length;
int iss_first_burst_length;
int iss_immediate_data;
int iss_connected;
char iss_reason[ISCSI_REASON_LEN];
char iss_offload[ISCSI_OFFLOAD_LEN];
- int iss_spare[4];
+ int iss_max_send_data_segment_length;
+ int iss_spare[3];
};
/*
@@ -122,12 +127,13 @@ struct iscsi_daemon_handoff {
uint32_t idh_statsn;
int idh_header_digest;
int idh_data_digest;
- size_t idh_max_data_segment_length;
- size_t idh_max_burst_length;
- size_t idh_first_burst_length;
+ size_t spare[3];
int idh_immediate_data;
int idh_initial_r2t;
- int idh_spare[4];
+ int idh_max_recv_data_segment_length;
+ int idh_max_send_data_segment_length;
+ int idh_max_burst_length;
+ int idh_first_burst_length;
};
struct iscsi_daemon_fail {
diff --git a/sys/dev/iser/icl_iser.c b/sys/dev/iser/icl_iser.c
index a7c29d761035..0ebaee5977b0 100644
--- a/sys/dev/iser/icl_iser.c
+++ b/sys/dev/iser/icl_iser.c
@@ -483,9 +483,9 @@ iser_conn_task_done(struct icl_conn *ic, void *prv)
}
static int
-iser_limits(size_t *limitp)
+iser_limits(struct icl_drv_limits *idl)
{
- *limitp = 128 * 1024;
+ idl->idl_max_recv_data_segment_length = 128 * 1024;
return (0);
}