From 2e36f0c10ab284f974e7018ed32dd4aca3fe3308 Mon Sep 17 00:00:00 2001 From: np Date: Thu, 25 Aug 2016 05:22:53 +0000 Subject: [PATCH] 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 --- sys/cam/ctl/ctl_frontend_iscsi.c | 36 ++++++++++------ sys/cam/ctl/ctl_frontend_iscsi.h | 7 ++-- sys/cam/ctl/ctl_ioctl.h | 24 ++++++----- sys/dev/cxgbe/cxgbei/icl_cxgbei.c | 7 +++- sys/dev/iscsi/icl.c | 37 ++++++++++++++-- sys/dev/iscsi/icl.h | 14 +++++-- sys/dev/iscsi/icl_soft.c | 4 +- sys/dev/iscsi/iscsi.c | 46 ++++++++++++-------- sys/dev/iscsi/iscsi.h | 7 ++-- sys/dev/iscsi/iscsi_ioctl.h | 22 ++++++---- sys/dev/iser/icl_iser.c | 4 +- usr.bin/iscsictl/iscsictl.c | 54 +++++++++++++----------- usr.sbin/ctladm/ctladm.c | 39 +++++++++-------- usr.sbin/ctld/ctld.c | 3 +- usr.sbin/ctld/ctld.h | 13 +++--- usr.sbin/ctld/kernel.c | 49 ++++++++++++++++------ usr.sbin/ctld/login.c | 69 +++++++++++++++++++++++------- usr.sbin/ctld/pdu.c | 19 +++++---- usr.sbin/iscsid/iscsid.c | 47 ++++++++++++++++++--- usr.sbin/iscsid/iscsid.h | 7 ++-- usr.sbin/iscsid/login.c | 70 ++++++++++++++++++------------- 21 files changed, 387 insertions(+), 191 deletions(-) diff --git a/sys/cam/ctl/ctl_frontend_iscsi.c b/sys/cam/ctl/ctl_frontend_iscsi.c index 70de5fa79b0..98e33faa62c 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) "%u" "%s" "%s" - "%zd" - "%zd" - "%zd" + "%d" + "%d" + "%d" + "%d" "%d" "%d" "%s" @@ -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 d24f193cbbe..caef7d919fe 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 40bd1838725..2872d7727c5 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 8f29452196f..288e8e692a9 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 2823074f210..9a20b54a1f8 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 292fa600665..0a1ee9414e4 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 4efae9fd971..230a4145679 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 5364584816c..57b60bb8423 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 3225649cc46..d5bd79ab414 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 a494cd558ed..3767c45f99d 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 a7c29d76103..0ebaee5977b 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); } diff --git a/usr.bin/iscsictl/iscsictl.c b/usr.bin/iscsictl/iscsictl.c index 71a1abedced..c283550f511 100644 --- a/usr.bin/iscsictl/iscsictl.c +++ b/usr.bin/iscsictl/iscsictl.c @@ -514,70 +514,74 @@ kernel_list(int iscsi_fd, const struct target *targ __unused, * Display-only modifier as this information * is also present within the 'session' container */ - xo_emit("{L:/%-18s}{V:sessionId/%u}\n", + xo_emit("{L:/%-25s}{V:sessionId/%u}\n", "Session ID:", state->iss_id); xo_open_container("initiator"); - xo_emit("{L:/%-18s}{V:name/%s}\n", + xo_emit("{L:/%-25s}{V:name/%s}\n", "Initiator name:", conf->isc_initiator); - xo_emit("{L:/%-18s}{V:portal/%s}\n", + xo_emit("{L:/%-25s}{V:portal/%s}\n", "Initiator portal:", conf->isc_initiator_addr); - xo_emit("{L:/%-18s}{V:alias/%s}\n", + xo_emit("{L:/%-25s}{V:alias/%s}\n", "Initiator alias:", conf->isc_initiator_alias); xo_close_container("initiator"); xo_open_container("target"); - xo_emit("{L:/%-18s}{V:name/%s}\n", + xo_emit("{L:/%-25s}{V:name/%s}\n", "Target name:", conf->isc_target); - xo_emit("{L:/%-18s}{V:portal/%s}\n", + xo_emit("{L:/%-25s}{V:portal/%s}\n", "Target portal:", conf->isc_target_addr); - xo_emit("{L:/%-18s}{V:alias/%s}\n", + xo_emit("{L:/%-25s}{V:alias/%s}\n", "Target alias:", state->iss_target_alias); xo_close_container("target"); xo_open_container("auth"); - xo_emit("{L:/%-18s}{V:user/%s}\n", + xo_emit("{L:/%-25s}{V:user/%s}\n", "User:", conf->isc_user); - xo_emit("{L:/%-18s}{V:secret/%s}\n", + xo_emit("{L:/%-25s}{V:secret/%s}\n", "Secret:", conf->isc_secret); - xo_emit("{L:/%-18s}{V:mutualUser/%s}\n", + xo_emit("{L:/%-25s}{V:mutualUser/%s}\n", "Mutual user:", conf->isc_mutual_user); - xo_emit("{L:/%-18s}{V:mutualSecret/%s}\n", + xo_emit("{L:/%-25s}{V:mutualSecret/%s}\n", "Mutual secret:", conf->isc_mutual_secret); xo_close_container("auth"); - xo_emit("{L:/%-18s}{V:type/%s}\n", + xo_emit("{L:/%-25s}{V:type/%s}\n", "Session type:", conf->isc_discovery ? "Discovery" : "Normal"); - xo_emit("{L:/%-18s}{V:enable/%s}\n", + xo_emit("{L:/%-25s}{V:enable/%s}\n", "Enable:", conf->isc_enable ? "Yes" : "No"); - xo_emit("{L:/%-18s}{V:state/%s}\n", + xo_emit("{L:/%-25s}{V:state/%s}\n", "Session state:", state->iss_connected ? "Connected" : "Disconnected"); - xo_emit("{L:/%-18s}{V:failureReason/%s}\n", + xo_emit("{L:/%-25s}{V:failureReason/%s}\n", "Failure reason:", state->iss_reason); - xo_emit("{L:/%-18s}{V:headerDigest/%s}\n", + xo_emit("{L:/%-25s}{V:headerDigest/%s}\n", "Header digest:", state->iss_header_digest == ISCSI_DIGEST_CRC32C ? "CRC32C" : "None"); - xo_emit("{L:/%-18s}{V:dataDigest/%s}\n", + xo_emit("{L:/%-25s}{V:dataDigest/%s}\n", "Data digest:", state->iss_data_digest == ISCSI_DIGEST_CRC32C ? "CRC32C" : "None"); - xo_emit("{L:/%-18s}{V:dataSegmentLen/%d}\n", - "DataSegmentLen:", state->iss_max_data_segment_length); - xo_emit("{L:/%-18s}{V:maxBurstLen/%d}\n", + xo_emit("{L:/%-25s}{V:recvDataSegmentLen/%d}\n", + "MaxRecvDataSegmentLength:", + state->iss_max_recv_data_segment_length); + xo_emit("{L:/%-25s}{V:sendDataSegmentLen/%d}\n", + "MaxSendDataSegmentLength:", + state->iss_max_send_data_segment_length); + xo_emit("{L:/%-25s}{V:maxBurstLen/%d}\n", "MaxBurstLen:", state->iss_max_burst_length); - xo_emit("{L:/%-18s}{V:firstBurstLen/%d}\n", + xo_emit("{L:/%-25s}{V:firstBurstLen/%d}\n", "FirstBurstLen:", state->iss_first_burst_length); - xo_emit("{L:/%-18s}{V:immediateData/%s}\n", + xo_emit("{L:/%-25s}{V:immediateData/%s}\n", "ImmediateData:", state->iss_immediate_data ? "Yes" : "No"); - xo_emit("{L:/%-18s}{V:iSER/%s}\n", + xo_emit("{L:/%-25s}{V:iSER/%s}\n", "iSER (RDMA):", conf->isc_iser ? "Yes" : "No"); - xo_emit("{L:/%-18s}{V:offloadDriver/%s}\n", + xo_emit("{L:/%-25s}{V:offloadDriver/%s}\n", "Offload driver:", state->iss_offload); - xo_emit("{L:/%-18s}", + xo_emit("{L:/%-25s}", "Device nodes:"); print_periphs(state->iss_id); xo_emit("\n\n"); diff --git a/usr.sbin/ctladm/ctladm.c b/usr.sbin/ctladm/ctladm.c index fe4caaea9ed..3e163fe5844 100644 --- a/usr.sbin/ctladm/ctladm.c +++ b/usr.sbin/ctladm/ctladm.c @@ -2794,7 +2794,8 @@ struct cctl_islist_conn { char *target_alias; char *header_digest; char *data_digest; - char *max_data_segment_length; + char *max_recv_data_segment_length; + char *max_send_data_segment_length; char *max_burst_length; char *first_burst_length; char *offload; @@ -2908,8 +2909,11 @@ cctl_islist_end_element(void *user_data, const char *name) } else if (strcmp(name, "data_digest") == 0) { cur_conn->data_digest = str; str = NULL; - } else if (strcmp(name, "max_data_segment_length") == 0) { - cur_conn->max_data_segment_length = str; + } else if (strcmp(name, "max_recv_data_segment_length") == 0) { + cur_conn->max_recv_data_segment_length = str; + str = NULL; + } else if (strcmp(name, "max_send_data_segment_length") == 0) { + cur_conn->max_send_data_segment_length = str; str = NULL; } else if (strcmp(name, "max_burst_length") == 0) { cur_conn->max_burst_length = str; @@ -3030,20 +3034,21 @@ cctl_islist(int fd, int argc, char **argv, char *combinedopt) if (verbose != 0) { STAILQ_FOREACH(conn, &islist.conn_list, links) { - printf("Session ID: %d\n", conn->connection_id); - printf("Initiator name: %s\n", conn->initiator); - printf("Initiator portal: %s\n", conn->initiator_addr); - printf("Initiator alias: %s\n", conn->initiator_alias); - printf("Target name: %s\n", conn->target); - printf("Target alias: %s\n", conn->target_alias); - printf("Header digest: %s\n", conn->header_digest); - printf("Data digest: %s\n", conn->data_digest); - printf("DataSegmentLen: %s\n", conn->max_data_segment_length); - printf("MaxBurstLen: %s\n", conn->max_burst_length); - printf("FirstBurstLen: %s\n", conn->first_burst_length); - printf("ImmediateData: %s\n", conn->immediate_data ? "Yes" : "No"); - printf("iSER (RDMA): %s\n", conn->iser ? "Yes" : "No"); - printf("Offload driver: %s\n", conn->offload); + printf("%-25s %d\n", "Session ID:", conn->connection_id); + printf("%-25s %s\n", "Initiator name:", conn->initiator); + printf("%-25s %s\n", "Initiator portal:", conn->initiator_addr); + printf("%-25s %s\n", "Initiator alias:", conn->initiator_alias); + printf("%-25s %s\n", "Target name:", conn->target); + printf("%-25s %s\n", "Target alias:", conn->target_alias); + printf("%-25s %s\n", "Header digest:", conn->header_digest); + printf("%-25s %s\n", "Data digest:", conn->data_digest); + printf("%-25s %s\n", "MaxRecvDataSegmentLength:", conn->max_recv_data_segment_length); + printf("%-25s %s\n", "MaxSendDataSegmentLength:", conn->max_send_data_segment_length); + printf("%-25s %s\n", "MaxBurstLen:", conn->max_burst_length); + printf("%-25s %s\n", "FirstBurstLen:", conn->first_burst_length); + printf("%-25s %s\n", "ImmediateData:", conn->immediate_data ? "Yes" : "No"); + printf("%-25s %s\n", "iSER (RDMA):", conn->iser ? "Yes" : "No"); + printf("%-25s %s\n", "Offload driver:", conn->offload); printf("\n"); } } else { diff --git a/usr.sbin/ctld/ctld.c b/usr.sbin/ctld/ctld.c index 6ee6f74fb87..82bd88a4608 100644 --- a/usr.sbin/ctld/ctld.c +++ b/usr.sbin/ctld/ctld.c @@ -1578,8 +1578,9 @@ connection_new(struct portal *portal, int fd, const char *host, /* * Default values, from RFC 3720, section 12. */ - conn->conn_max_data_segment_length = 8192; + conn->conn_max_recv_data_segment_length = 8192; conn->conn_max_burst_length = 262144; + conn->conn_first_burst_length = 65536; conn->conn_immediate_data = true; return (conn); diff --git a/usr.sbin/ctld/ctld.h b/usr.sbin/ctld/ctld.h index 20864a71f57..85cbd324507 100644 --- a/usr.sbin/ctld/ctld.h +++ b/usr.sbin/ctld/ctld.h @@ -242,10 +242,10 @@ struct connection { struct sockaddr_storage conn_initiator_sa; uint32_t conn_cmdsn; uint32_t conn_statsn; - size_t conn_data_segment_limit; - size_t conn_max_data_segment_length; - size_t conn_max_burst_length; - size_t conn_first_burst_length; + int conn_max_recv_data_segment_length; + int conn_max_send_data_segment_length; + int conn_max_burst_length; + int conn_first_burst_length; int conn_immediate_data; int conn_header_digest; int conn_data_digest; @@ -404,7 +404,10 @@ int kernel_lun_modify(struct lun *lun); int kernel_lun_remove(struct lun *lun); void kernel_handoff(struct connection *conn); void kernel_limits(const char *offload, - size_t *max_data_segment_length); + int *max_recv_data_segment_length, + int *max_send_data_segment_length, + int *max_burst_length, + int *first_burst_length); int kernel_port_add(struct port *port); int kernel_port_update(struct port *port, struct port *old); int kernel_port_remove(struct port *port); diff --git a/usr.sbin/ctld/kernel.c b/usr.sbin/ctld/kernel.c index 40ef6829892..847024b6287 100644 --- a/usr.sbin/ctld/kernel.c +++ b/usr.sbin/ctld/kernel.c @@ -898,7 +898,9 @@ kernel_handoff(struct connection *conn) req.data.handoff.cmdsn = conn->conn_cmdsn; req.data.handoff.statsn = conn->conn_statsn; req.data.handoff.max_recv_data_segment_length = - conn->conn_max_data_segment_length; + conn->conn_max_recv_data_segment_length; + req.data.handoff.max_send_data_segment_length = + conn->conn_max_send_data_segment_length; req.data.handoff.max_burst_length = conn->conn_max_burst_length; req.data.handoff.first_burst_length = conn->conn_first_burst_length; req.data.handoff.immediate_data = conn->conn_immediate_data; @@ -915,16 +917,18 @@ kernel_handoff(struct connection *conn) } void -kernel_limits(const char *offload, size_t *max_data_segment_length) +kernel_limits(const char *offload, int *max_recv_dsl, int *max_send_dsl, + int *max_burst_length, int *first_burst_length) { struct ctl_iscsi req; + struct ctl_iscsi_limits_params *cilp; bzero(&req, sizeof(req)); req.type = CTL_ISCSI_LIMITS; + cilp = (struct ctl_iscsi_limits_params *)&(req.data.limits); if (offload != NULL) { - strlcpy(req.data.limits.offload, offload, - sizeof(req.data.limits.offload)); + strlcpy(cilp->offload, offload, sizeof(cilp->offload)); } if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) { @@ -937,13 +941,31 @@ kernel_limits(const char *offload, size_t *max_data_segment_length) "%s; dropping connection", req.error_str); } - *max_data_segment_length = req.data.limits.data_segment_limit; + if (cilp->max_recv_data_segment_length != 0) { + *max_recv_dsl = cilp->max_recv_data_segment_length; + *max_send_dsl = cilp->max_recv_data_segment_length; + } + if (cilp->max_send_data_segment_length != 0) + *max_send_dsl = cilp->max_send_data_segment_length; + if (cilp->max_burst_length != 0) + *max_burst_length = cilp->max_burst_length; + if (cilp->first_burst_length != 0) + *first_burst_length = cilp->first_burst_length; + if (*max_burst_length < *first_burst_length) + *first_burst_length = *max_burst_length; + if (offload != NULL) { - log_debugx("MaxRecvDataSegment kernel limit for offload " - "\"%s\" is %zd", offload, *max_data_segment_length); + log_debugx("Kernel limits for offload \"%s\" are " + "MaxRecvDataSegment=%d, max_send_dsl=%d, " + "MaxBurstLength=%d, FirstBurstLength=%d", + offload, *max_recv_dsl, *max_send_dsl, *max_burst_length, + *first_burst_length); } else { - log_debugx("MaxRecvDataSegment kernel limit is %zd", - *max_data_segment_length); + log_debugx("Kernel limits are " + "MaxRecvDataSegment=%d, max_send_dsl=%d, " + "MaxBurstLength=%d, FirstBurstLength=%d", + *max_recv_dsl, *max_send_dsl, *max_burst_length, + *first_burst_length); } } @@ -1217,18 +1239,21 @@ kernel_send(struct pdu *pdu) void kernel_receive(struct pdu *pdu) { + struct connection *conn; struct ctl_iscsi req; - pdu->pdu_data = malloc(MAX_DATA_SEGMENT_LENGTH); + conn = pdu->pdu_connection; + pdu->pdu_data = malloc(conn->conn_max_recv_data_segment_length); if (pdu->pdu_data == NULL) log_err(1, "malloc"); bzero(&req, sizeof(req)); req.type = CTL_ISCSI_RECEIVE; - req.data.receive.connection_id = pdu->pdu_connection->conn_socket; + req.data.receive.connection_id = conn->conn_socket; req.data.receive.bhs = pdu->pdu_bhs; - req.data.receive.data_segment_len = MAX_DATA_SEGMENT_LENGTH; + req.data.receive.data_segment_len = + conn->conn_max_recv_data_segment_length; req.data.receive.data_segment = pdu->pdu_data; if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) { diff --git a/usr.sbin/ctld/login.c b/usr.sbin/ctld/login.c index 5216c7e8f85..5c3586821b2 100644 --- a/usr.sbin/ctld/login.c +++ b/usr.sbin/ctld/login.c @@ -550,23 +550,32 @@ login_negotiate_key(struct pdu *request, const char *name, log_errx(1, "received invalid " "MaxRecvDataSegmentLength"); } - if (tmp > conn->conn_data_segment_limit) { - log_debugx("capping MaxRecvDataSegmentLength " - "from %zd to %zd", tmp, conn->conn_data_segment_limit); - tmp = conn->conn_data_segment_limit; + + /* + * MaxRecvDataSegmentLength is a direction-specific parameter. + * We'll limit our _send_ to what the initiator can handle but + * our MaxRecvDataSegmentLength is not influenced by the + * initiator in any way. + */ + if ((int)tmp > conn->conn_max_send_data_segment_length) { + log_debugx("capping max_send_data_segment_length " + "from %zd to %d", tmp, + conn->conn_max_send_data_segment_length); + tmp = conn->conn_max_send_data_segment_length; } - conn->conn_max_data_segment_length = tmp; - keys_add_int(response_keys, name, conn->conn_data_segment_limit); + conn->conn_max_send_data_segment_length = tmp; + keys_add_int(response_keys, name, + conn->conn_max_recv_data_segment_length); } else if (strcmp(name, "MaxBurstLength") == 0) { tmp = strtoul(value, NULL, 10); if (tmp <= 0) { login_send_error(request, 0x02, 0x00); log_errx(1, "received invalid MaxBurstLength"); } - if (tmp > MAX_BURST_LENGTH) { + if ((int)tmp > conn->conn_max_burst_length) { log_debugx("capping MaxBurstLength from %zd to %d", - tmp, MAX_BURST_LENGTH); - tmp = MAX_BURST_LENGTH; + tmp, conn->conn_max_burst_length); + tmp = conn->conn_max_burst_length; } conn->conn_max_burst_length = tmp; keys_add_int(response_keys, name, tmp); @@ -576,10 +585,10 @@ login_negotiate_key(struct pdu *request, const char *name, login_send_error(request, 0x02, 0x00); log_errx(1, "received invalid FirstBurstLength"); } - if (tmp > FIRST_BURST_LENGTH) { + if ((int)tmp > conn->conn_first_burst_length) { log_debugx("capping FirstBurstLength from %zd to %d", - tmp, FIRST_BURST_LENGTH); - tmp = FIRST_BURST_LENGTH; + tmp, conn->conn_first_burst_length); + tmp = conn->conn_first_burst_length; } conn->conn_first_burst_length = tmp; keys_add_int(response_keys, name, tmp); @@ -681,14 +690,30 @@ login_negotiate(struct connection *conn, struct pdu *request) if (conn->conn_session_type == CONN_SESSION_TYPE_NORMAL) { /* - * Query the kernel for MaxDataSegmentLength it can handle. - * In case of offload, it depends on hardware capabilities. + * Query the kernel for various size limits. In case of + * offload, it depends on hardware capabilities. */ assert(conn->conn_target != NULL); kernel_limits(conn->conn_portal->p_portal_group->pg_offload, - &conn->conn_data_segment_limit); + &conn->conn_max_recv_data_segment_length, + &conn->conn_max_send_data_segment_length, + &conn->conn_max_burst_length, + &conn->conn_first_burst_length); + + /* We expect legal, usable values at this point. */ + assert(conn->conn_max_recv_data_segment_length >= 512); + assert(conn->conn_max_recv_data_segment_length < (1 << 24)); + assert(conn->conn_max_burst_length >= 512); + assert(conn->conn_max_burst_length < (1 << 24)); + assert(conn->conn_first_burst_length >= 512); + assert(conn->conn_first_burst_length < (1 << 24)); + assert(conn->conn_first_burst_length <= + conn->conn_max_burst_length); } else { - conn->conn_data_segment_limit = MAX_DATA_SEGMENT_LENGTH; + conn->conn_max_recv_data_segment_length = + MAX_DATA_SEGMENT_LENGTH; + conn->conn_max_send_data_segment_length = + MAX_DATA_SEGMENT_LENGTH; } if (request == NULL) { @@ -739,6 +764,18 @@ login_negotiate(struct connection *conn, struct pdu *request) response_keys); } + /* + * We'd started with usable values at our end. But a bad initiator + * could have presented a large FirstBurstLength and then a smaller + * MaxBurstLength (in that order) and because we process the key/value + * pairs in the order they are in the request we might have ended up + * with illegal values here. + */ + if (conn->conn_session_type == CONN_SESSION_TYPE_NORMAL && + conn->conn_first_burst_length > conn->conn_max_burst_length) { + log_errx(1, "initiator sent FirstBurstLength > MaxBurstLength"); + } + log_debugx("operational parameter negotiation done; " "transitioning to Full Feature Phase"); diff --git a/usr.sbin/ctld/pdu.c b/usr.sbin/ctld/pdu.c index 2d4fcc60fb3..77b9526d420 100644 --- a/usr.sbin/ctld/pdu.c +++ b/usr.sbin/ctld/pdu.c @@ -117,7 +117,7 @@ pdu_receive_proxy(struct pdu *pdu) log_errx(1, "protocol error: non-empty AHS"); len = pdu_data_segment_length(pdu); - assert(len <= MAX_DATA_SEGMENT_LENGTH); + assert(len <= pdu->pdu_connection->conn_max_recv_data_segment_length); pdu->pdu_data_len = len; } @@ -164,6 +164,7 @@ pdu_read(int fd, char *data, size_t len) void pdu_receive(struct pdu *pdu) { + struct connection *conn; size_t len, padding; char dummy[4]; @@ -173,9 +174,10 @@ pdu_receive(struct pdu *pdu) #endif assert(proxy_mode == false); + conn = pdu->pdu_connection; - pdu_read(pdu->pdu_connection->conn_socket, - (char *)pdu->pdu_bhs, sizeof(*pdu->pdu_bhs)); + pdu_read(conn->conn_socket, (char *)pdu->pdu_bhs, + sizeof(*pdu->pdu_bhs)); len = pdu_ahs_length(pdu); if (len > 0) @@ -183,10 +185,10 @@ pdu_receive(struct pdu *pdu) len = pdu_data_segment_length(pdu); if (len > 0) { - if (len > MAX_DATA_SEGMENT_LENGTH) { + if ((int)len > conn->conn_max_recv_data_segment_length) { log_errx(1, "protocol error: received PDU " "with DataSegmentLength exceeding %d", - MAX_DATA_SEGMENT_LENGTH); + conn->conn_max_recv_data_segment_length); } pdu->pdu_data_len = len; @@ -194,14 +196,13 @@ pdu_receive(struct pdu *pdu) if (pdu->pdu_data == NULL) log_err(1, "malloc"); - pdu_read(pdu->pdu_connection->conn_socket, - (char *)pdu->pdu_data, pdu->pdu_data_len); + pdu_read(conn->conn_socket, (char *)pdu->pdu_data, + pdu->pdu_data_len); padding = pdu_padding(pdu); if (padding != 0) { assert(padding < sizeof(dummy)); - pdu_read(pdu->pdu_connection->conn_socket, - (char *)dummy, padding); + pdu_read(conn->conn_socket, (char *)dummy, padding); } } } diff --git a/usr.sbin/iscsid/iscsid.c b/usr.sbin/iscsid/iscsid.c index 5be7a44ce58..8e94c8a430c 100644 --- a/usr.sbin/iscsid/iscsid.c +++ b/usr.sbin/iscsid/iscsid.c @@ -153,6 +153,7 @@ static struct connection * connection_new(int iscsi_fd, const struct iscsi_daemon_request *request) { struct connection *conn; + struct iscsi_session_limits *isl; struct addrinfo *from_ai, *to_ai; const char *from_addr, *to_addr; #ifdef ICL_KERNEL_PROXY @@ -171,16 +172,49 @@ connection_new(int iscsi_fd, const struct iscsi_daemon_request *request) conn->conn_data_digest = CONN_DIGEST_NONE; conn->conn_initial_r2t = true; conn->conn_immediate_data = true; - conn->conn_max_data_segment_length = 8192; - conn->conn_max_burst_length = 262144; - conn->conn_first_burst_length = 65536; + conn->conn_max_burst_length = MAX_BURST_LENGTH; + conn->conn_first_burst_length = FIRST_BURST_LENGTH; conn->conn_iscsi_fd = iscsi_fd; conn->conn_session_id = request->idr_session_id; memcpy(&conn->conn_conf, &request->idr_conf, sizeof(conn->conn_conf)); memcpy(&conn->conn_isid, &request->idr_isid, sizeof(conn->conn_isid)); conn->conn_tsih = request->idr_tsih; - memcpy(&conn->conn_limits, &request->idr_limits, sizeof(conn->conn_limits)); + + /* + * Read the driver limits and provide reasonable defaults for the ones + * the driver doesn't care about. If a max_snd_dsl is not explicitly + * provided by the driver then we'll make sure both conn->max_snd_dsl + * and isl->max_snd_dsl are set to the rcv_dsl. This preserves historic + * behavior. + */ + isl = &conn->conn_limits; + memcpy(isl, &request->idr_limits, sizeof(*isl)); + if (isl->isl_max_recv_data_segment_length == 0) { + conn->conn_max_recv_data_segment_length = 8192; + conn->conn_max_send_data_segment_length = 8192; + isl->isl_max_recv_data_segment_length = 8192; + } else { + conn->conn_max_recv_data_segment_length = + isl->isl_max_recv_data_segment_length; + conn->conn_max_send_data_segment_length = + isl->isl_max_recv_data_segment_length; + } + if (isl->isl_max_send_data_segment_length == 0) { + isl->isl_max_send_data_segment_length = + isl->isl_max_recv_data_segment_length; + } else { + conn->conn_max_send_data_segment_length = + isl->isl_max_send_data_segment_length; + } + if (isl->isl_max_burst_length == 0) + isl->isl_max_burst_length = conn->conn_max_burst_length; + if (isl->isl_first_burst_length == 0) { + if (isl->isl_max_burst_length < (int)conn->conn_first_burst_length) + isl->isl_first_burst_length = isl->isl_max_burst_length; + else + isl->isl_first_burst_length = conn->conn_first_burst_length; + } from_addr = conn->conn_conf.isc_initiator_addr; to_addr = conn->conn_conf.isc_target_addr; @@ -277,7 +311,10 @@ handoff(struct connection *conn) idh.idh_data_digest = conn->conn_data_digest; idh.idh_initial_r2t = conn->conn_initial_r2t; idh.idh_immediate_data = conn->conn_immediate_data; - idh.idh_max_data_segment_length = conn->conn_max_data_segment_length; + idh.idh_max_recv_data_segment_length = + conn->conn_max_recv_data_segment_length; + idh.idh_max_send_data_segment_length = + conn->conn_max_send_data_segment_length; idh.idh_max_burst_length = conn->conn_max_burst_length; idh.idh_first_burst_length = conn->conn_first_burst_length; diff --git a/usr.sbin/iscsid/iscsid.h b/usr.sbin/iscsid/iscsid.h index df4b8ec9ff4..6a4e6cd2fbc 100644 --- a/usr.sbin/iscsid/iscsid.h +++ b/usr.sbin/iscsid/iscsid.h @@ -61,9 +61,10 @@ struct connection { int conn_data_digest; bool conn_initial_r2t; bool conn_immediate_data; - size_t conn_max_data_segment_length; - size_t conn_max_burst_length; - size_t conn_first_burst_length; + int conn_max_recv_data_segment_length; + int conn_max_send_data_segment_length; + int conn_max_burst_length; + int conn_first_burst_length; struct chap *conn_mutual_chap; }; diff --git a/usr.sbin/iscsid/login.c b/usr.sbin/iscsid/login.c index c2a8e065884..0b2d994c1be 100644 --- a/usr.sbin/iscsid/login.c +++ b/usr.sbin/iscsid/login.c @@ -330,8 +330,10 @@ static void login_negotiate_key(struct connection *conn, const char *name, const char *value) { + struct iscsi_session_limits *isl; int which, tmp; + isl = &conn->conn_limits; if (strcmp(name, "TargetAlias") == 0) { strlcpy(conn->conn_target_alias, value, sizeof(conn->conn_target_alias)); @@ -388,30 +390,31 @@ login_negotiate_key(struct connection *conn, const char *name, if (tmp <= 0) log_errx(1, "received invalid " "MaxRecvDataSegmentLength"); - if (tmp > ISCSI_MAX_DATA_SEGMENT_LENGTH) { - log_debugx("capping MaxRecvDataSegmentLength " - "from %d to %d", tmp, ISCSI_MAX_DATA_SEGMENT_LENGTH); - tmp = ISCSI_MAX_DATA_SEGMENT_LENGTH; + if (tmp > isl->isl_max_send_data_segment_length) { + log_debugx("capping max_send_data_segment_length " + "from %d to %d", tmp, + isl->isl_max_send_data_segment_length); + tmp = isl->isl_max_send_data_segment_length; } - conn->conn_max_data_segment_length = tmp; + conn->conn_max_send_data_segment_length = tmp; } else if (strcmp(name, "MaxBurstLength") == 0) { tmp = strtoul(value, NULL, 10); if (tmp <= 0) log_errx(1, "received invalid MaxBurstLength"); - if (tmp > MAX_BURST_LENGTH) { + if (tmp > isl->isl_max_burst_length) { log_debugx("capping MaxBurstLength " - "from %d to %d", tmp, MAX_BURST_LENGTH); - tmp = MAX_BURST_LENGTH; + "from %d to %d", tmp, isl->isl_max_burst_length); + tmp = isl->isl_max_burst_length; } conn->conn_max_burst_length = tmp; } else if (strcmp(name, "FirstBurstLength") == 0) { tmp = strtoul(value, NULL, 10); if (tmp <= 0) log_errx(1, "received invalid FirstBurstLength"); - if (tmp > FIRST_BURST_LENGTH) { + if (tmp > isl->isl_first_burst_length) { log_debugx("capping FirstBurstLength " - "from %d to %d", tmp, FIRST_BURST_LENGTH); - tmp = FIRST_BURST_LENGTH; + "from %d to %d", tmp, isl->isl_first_burst_length); + tmp = isl->isl_first_burst_length; } conn->conn_first_burst_length = tmp; } else if (strcmp(name, "DefaultTime2Wait") == 0) { @@ -440,13 +443,13 @@ login_negotiate_key(struct connection *conn, const char *name, if (tmp <= 0) log_errx(1, "received invalid " "InitiatorRecvDataSegmentLength"); - if ((size_t)tmp > conn->conn_limits.isl_max_data_segment_length) { + if ((int)tmp > isl->isl_max_recv_data_segment_length) { log_debugx("capping InitiatorRecvDataSegmentLength " - "from %d to %zd", tmp, - conn->conn_limits.isl_max_data_segment_length); - tmp = conn->conn_limits.isl_max_data_segment_length; + "from %d to %d", tmp, + isl->isl_max_recv_data_segment_length); + tmp = isl->isl_max_recv_data_segment_length; } - conn->conn_max_data_segment_length = tmp; + conn->conn_max_recv_data_segment_length = tmp; } else if (strcmp(name, "TargetPortalGroupTag") == 0) { /* Ignore */ } else if (strcmp(name, "TargetRecvDataSegmentLength") == 0) { @@ -455,13 +458,13 @@ login_negotiate_key(struct connection *conn, const char *name, log_errx(1, "received invalid TargetRecvDataSegmentLength"); } - if ((size_t)tmp > conn->conn_limits.isl_max_data_segment_length) { + if (tmp > isl->isl_max_send_data_segment_length) { log_debugx("capping TargetRecvDataSegmentLength " - "from %d to %zd", tmp, - conn->conn_limits.isl_max_data_segment_length); - tmp = conn->conn_limits.isl_max_data_segment_length; + "from %d to %d", tmp, + isl->isl_max_send_data_segment_length); + tmp = isl->isl_max_send_data_segment_length; } - conn->conn_max_data_segment_length = tmp; + conn->conn_max_send_data_segment_length = tmp; } else { log_debugx("unknown key \"%s\"; ignoring", name); } @@ -474,14 +477,19 @@ login_negotiate(struct connection *conn) struct keys *request_keys, *response_keys; struct iscsi_bhs_login_response *bhslr; int i, nrequests = 0; + struct iscsi_session_limits *isl; log_debugx("beginning operational parameter negotiation"); request = login_new_request(conn, BHSLR_STAGE_OPERATIONAL_NEGOTIATION); request_keys = keys_new(); - log_debugx("offload \"%s\" limits MaxRecvDataSegmentLength to %zd", - conn->conn_conf.isc_offload, - conn->conn_limits.isl_max_data_segment_length); + isl = &conn->conn_limits; + log_debugx("Limits for offload \"%s\" are " + "MaxRecvDataSegment=%d, max_send_dsl=%d, " + "MaxBurstLength=%d, FirstBurstLength=%d", + conn->conn_conf.isc_offload, isl->isl_max_recv_data_segment_length, + isl->isl_max_send_data_segment_length, isl->isl_max_burst_length, + isl->isl_first_burst_length); /* * The following keys are irrelevant for discovery sessions. @@ -497,25 +505,27 @@ login_negotiate(struct connection *conn) keys_add(request_keys, "DataDigest", "None"); keys_add(request_keys, "ImmediateData", "Yes"); - keys_add_int(request_keys, "MaxBurstLength", MAX_BURST_LENGTH); - keys_add_int(request_keys, "FirstBurstLength", FIRST_BURST_LENGTH); + keys_add_int(request_keys, "MaxBurstLength", + isl->isl_max_burst_length); + keys_add_int(request_keys, "FirstBurstLength", + isl->isl_first_burst_length); keys_add(request_keys, "InitialR2T", "Yes"); keys_add(request_keys, "MaxOutstandingR2T", "1"); if (conn->conn_conf.isc_iser == 1) { keys_add_int(request_keys, "InitiatorRecvDataSegmentLength", - conn->conn_limits.isl_max_data_segment_length); + isl->isl_max_recv_data_segment_length); keys_add_int(request_keys, "TargetRecvDataSegmentLength", - conn->conn_limits.isl_max_data_segment_length); + isl->isl_max_send_data_segment_length); keys_add(request_keys, "RDMAExtensions", "Yes"); } else { keys_add_int(request_keys, "MaxRecvDataSegmentLength", - conn->conn_limits.isl_max_data_segment_length); + isl->isl_max_recv_data_segment_length); } } else { keys_add(request_keys, "HeaderDigest", "None"); keys_add(request_keys, "DataDigest", "None"); keys_add_int(request_keys, "MaxRecvDataSegmentLength", - conn->conn_limits.isl_max_data_segment_length); + isl->isl_max_recv_data_segment_length); } keys_add(request_keys, "DefaultTime2Wait", "0"); -- 2.45.0