diff --git a/configure.ac b/configure.ac index a00782e..db8d6bf 100644 --- a/configure.ac +++ b/configure.ac @@ -152,6 +152,11 @@ if test x"$libiscsi_cv_HAVE_LINUX_ISER" = x"yes"; then fi AM_CONDITIONAL([HAVE_LINUX_ISER], [test $libiscsi_cv_HAVE_LINUX_ISER = yes]) +AC_TRY_COMPILE([ +#include ], +[return RDMA_OPTION_ID_ACK_TIMEOUT;], +[AC_DEFINE([HAVE_RDMA_ACK_TIMEOUT],[1],[Define to 1 if you have RDMA ack timeout support])],) + AC_CACHE_CHECK([whether libcunit is available], [ac_cv_have_cunit], [ac_save_CFLAGS="$CFLAGS" diff --git a/include/iscsi-private.h b/include/iscsi-private.h index 3442db6..178669c 100644 --- a/include/iscsi-private.h +++ b/include/iscsi-private.h @@ -109,6 +109,8 @@ struct iscsi_context { int tcp_syncnt; int tcp_nonblocking; + unsigned char rdma_ack_timeout; + int current_phase; int next_phase; #define ISCSI_LOGIN_SECNEG_PHASE_OFFER_CHAP 0 diff --git a/lib/init.c b/lib/init.c index a120e88..8b2c3df 100644 --- a/lib/init.c +++ b/lib/init.c @@ -280,6 +280,10 @@ iscsi_create_context(const char *initiator_name) iscsi_set_bind_interfaces(iscsi,getenv("LIBISCSI_BIND_INTERFACES")); } + if (getenv("LIBISCSI_RDMA_ACK_TIMEOUT") != NULL) { + iscsi->rdma_ack_timeout = (unsigned char)atoi(getenv("LIBISCSI_RDMA_ACK_TIMEOUT")); + } + /* iscsi->smalloc_size is the size for small allocations. this should be max(ISCSI_HEADER_SIZE, sizeof(struct iscsi_pdu), sizeof(struct iscsi_in_pdu)) rounded up to the next power of 2. */ @@ -617,6 +621,8 @@ iscsi_parse_url(struct iscsi_context *iscsi, const char *url, int full) #ifdef HAVE_LINUX_ISER } else if (!strcmp(key, "iser")) { is_iser = 1; + } else if (!strcmp(key, "LIBISCSI_RDMA_ACK_TIMEOUT")) { + iscsi->rdma_ack_timeout = (unsigned char)atoi(value); #endif } tmp = next; diff --git a/lib/iser.c b/lib/iser.c index 81f3687..eebb419 100644 --- a/lib/iser.c +++ b/lib/iser.c @@ -15,6 +15,10 @@ along with this program; if not, see . */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #include #include @@ -812,6 +816,40 @@ static int iser_create_iser_conn_res(struct iser_conn *iser_conn) { return ret; } +void iscsi_set_rdma_ack_timetout(struct iscsi_context *iscsi, unsigned char value) +{ + iscsi->rdma_ack_timeout = value; + ISCSI_LOG(iscsi, 2, "RDMA ACK TIMEOUT will be set to %d on next rdma qp creation", value); +} + +/* + * iser_rdma_set_option() - set rdma options + * currently support RDMA ack timeout. + * @cma_id: connection manager id + * @iscsi: iscsi context + */ +int iser_rdma_set_option(struct rdma_cm_id *cma_id, struct iscsi_context *iscsi) { + int ret = 0; + unsigned char timeout = iscsi->rdma_ack_timeout; + + if (timeout) { +#ifdef HAVE_RDMA_ACK_TIMEOUT + /* calculate according to the formula 4.096 * 2^(timeout) usec. + Ex, 8 means 1048.576 usec (0.00104 sec) */ + ret = rdma_set_option(cma_id, RDMA_OPTION_ID, RDMA_OPTION_ID_ACK_TIMEOUT, &timeout, sizeof(timeout)); + if (ret) { + ISCSI_LOG(iscsi, 1, "failed to set RDMA ACK TIMEOUT: %s", strerror(errno)); + } else { + ISCSI_LOG(iscsi, 3, "RDMA ACK TIMEOUT set to %d", timeout); + } +#else + ISCSI_LOG(iscsi, 1, "failed to set RDMA ACK TIMEOUT(%d) for cma_id(%p), please update your kernel&librdmacm", timeout, cma_id); +#endif + } + + return ret; +} + /* * iser_addr_handler() - handles RDMA_CM_EVENT_ADDR_RESOLVED * event in rdma_cm @@ -823,6 +861,8 @@ static int iser_addr_handler(struct rdma_cm_id *cma_id) { struct iser_conn *iser_conn = iscsi->opaque; int ret, flags; + iser_rdma_set_option(cma_id, iscsi); + ret = rdma_resolve_route(cma_id, 1000); if (ret) { iscsi_set_error(iscsi, "Failed resolving address\n");