*/
 struct rpc_xprt                *xprt_create_transport(struct xprt_create *args);
 void                   xprt_connect(struct rpc_task *task);
+unsigned long          xprt_reconnect_delay(const struct rpc_xprt *xprt);
+void                   xprt_reconnect_backoff(struct rpc_xprt *xprt,
+                                              unsigned long init_to);
 void                   xprt_reserve(struct rpc_task *task);
 void                   xprt_retry_reserve(struct rpc_task *task);
 int                    xprt_reserve_xprt(struct rpc_xprt *xprt, struct rpc_task *task);
 
 DEFINE_RXPRT_EVENT(xprtrdma_op_close);
 DEFINE_RXPRT_EVENT(xprtrdma_op_connect);
 
+TRACE_EVENT(xprtrdma_op_set_cto,
+       TP_PROTO(
+               const struct rpcrdma_xprt *r_xprt,
+               unsigned long connect,
+               unsigned long reconnect
+       ),
+
+       TP_ARGS(r_xprt, connect, reconnect),
+
+       TP_STRUCT__entry(
+               __field(const void *, r_xprt)
+               __field(unsigned long, connect)
+               __field(unsigned long, reconnect)
+               __string(addr, rpcrdma_addrstr(r_xprt))
+               __string(port, rpcrdma_portstr(r_xprt))
+       ),
+
+       TP_fast_assign(
+               __entry->r_xprt = r_xprt;
+               __entry->connect = connect;
+               __entry->reconnect = reconnect;
+               __assign_str(addr, rpcrdma_addrstr(r_xprt));
+               __assign_str(port, rpcrdma_portstr(r_xprt));
+       ),
+
+       TP_printk("peer=[%s]:%s r_xprt=%p: connect=%lu reconnect=%lu",
+               __get_str(addr), __get_str(port), __entry->r_xprt,
+               __entry->connect / HZ, __entry->reconnect / HZ
+       )
+);
+
 TRACE_EVENT(xprtrdma_qp_event,
        TP_PROTO(
                const struct rpcrdma_xprt *r_xprt,
 
  */
 struct workqueue_struct *rpciod_workqueue __read_mostly;
 struct workqueue_struct *xprtiod_workqueue __read_mostly;
+EXPORT_SYMBOL_GPL(xprtiod_workqueue);
 
 unsigned long
 rpc_task_timeout(const struct rpc_task *task)
 
        xprt_release_write(xprt, task);
 }
 
+/**
+ * xprt_reconnect_delay - compute the wait before scheduling a connect
+ * @xprt: transport instance
+ *
+ */
+unsigned long xprt_reconnect_delay(const struct rpc_xprt *xprt)
+{
+       unsigned long start, now = jiffies;
+
+       start = xprt->stat.connect_start + xprt->reestablish_timeout;
+       if (time_after(start, now))
+               return start - now;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(xprt_reconnect_delay);
+
+/**
+ * xprt_reconnect_backoff - compute the new re-establish timeout
+ * @xprt: transport instance
+ * @init_to: initial reestablish timeout
+ *
+ */
+void xprt_reconnect_backoff(struct rpc_xprt *xprt, unsigned long init_to)
+{
+       xprt->reestablish_timeout <<= 1;
+       if (xprt->reestablish_timeout > xprt->max_reconnect_timeout)
+               xprt->reestablish_timeout = xprt->max_reconnect_timeout;
+       if (xprt->reestablish_timeout < init_to)
+               xprt->reestablish_timeout = init_to;
+}
+EXPORT_SYMBOL_GPL(xprt_reconnect_backoff);
+
 enum xprt_xid_rb_cmp {
        XID_RB_EQUAL,
        XID_RB_LEFT,
 
        module_put(THIS_MODULE);
 }
 
+/* 60 second timeout, no retries */
 static const struct rpc_timeout xprt_rdma_default_timeout = {
        .to_initval = 60 * HZ,
        .to_maxval = 60 * HZ,
        if (!xprt)
                return ERR_PTR(-ENOMEM);
 
-       /* 60 second timeout, no retries */
        xprt->timeout = &xprt_rdma_default_timeout;
+       xprt->connect_timeout = xprt->timeout->to_initval;
+       xprt->max_reconnect_timeout = xprt->timeout->to_maxval;
        xprt->bind_timeout = RPCRDMA_BIND_TO;
        xprt->reestablish_timeout = RPCRDMA_INIT_REEST_TO;
        xprt->idle_timeout = RPCRDMA_IDLE_DISC_TO;
 }
 
 /**
- * xprt_rdma_connect - try to establish a transport connection
+ * xprt_rdma_set_connect_timeout - set timeouts for establishing a connection
+ * @xprt: controlling transport instance
+ * @connect_timeout: reconnect timeout after client disconnects
+ * @reconnect_timeout: reconnect timeout after server disconnects
+ *
+ */
+static void xprt_rdma_tcp_set_connect_timeout(struct rpc_xprt *xprt,
+                                             unsigned long connect_timeout,
+                                             unsigned long reconnect_timeout)
+{
+       struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
+
+       trace_xprtrdma_op_set_cto(r_xprt, connect_timeout, reconnect_timeout);
+
+       spin_lock(&xprt->transport_lock);
+
+       if (connect_timeout < xprt->connect_timeout) {
+               struct rpc_timeout to;
+               unsigned long initval;
+
+               to = *xprt->timeout;
+               initval = connect_timeout;
+               if (initval < RPCRDMA_INIT_REEST_TO << 1)
+                       initval = RPCRDMA_INIT_REEST_TO << 1;
+               to.to_initval = initval;
+               to.to_maxval = initval;
+               r_xprt->rx_timeout = to;
+               xprt->timeout = &r_xprt->rx_timeout;
+               xprt->connect_timeout = connect_timeout;
+       }
+
+       if (reconnect_timeout < xprt->max_reconnect_timeout)
+               xprt->max_reconnect_timeout = reconnect_timeout;
+
+       spin_unlock(&xprt->transport_lock);
+}
+
+/**
+ * xprt_rdma_connect - schedule an attempt to reconnect
  * @xprt: transport state
- * @task: RPC scheduler context
+ * @task: RPC scheduler context (unused)
  *
  */
 static void
 xprt_rdma_connect(struct rpc_xprt *xprt, struct rpc_task *task)
 {
        struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt);
+       unsigned long delay;
 
        trace_xprtrdma_op_connect(r_xprt);
+
+       delay = 0;
        if (r_xprt->rx_ep.rep_connected != 0) {
-               /* Reconnect */
-               schedule_delayed_work(&r_xprt->rx_connect_worker,
-                                     xprt->reestablish_timeout);
-               xprt->reestablish_timeout <<= 1;
-               if (xprt->reestablish_timeout > RPCRDMA_MAX_REEST_TO)
-                       xprt->reestablish_timeout = RPCRDMA_MAX_REEST_TO;
-               else if (xprt->reestablish_timeout < RPCRDMA_INIT_REEST_TO)
-                       xprt->reestablish_timeout = RPCRDMA_INIT_REEST_TO;
-       } else {
-               schedule_delayed_work(&r_xprt->rx_connect_worker, 0);
-               if (!RPC_IS_ASYNC(task))
-                       flush_delayed_work(&r_xprt->rx_connect_worker);
+               delay = xprt_reconnect_delay(xprt);
+               xprt_reconnect_backoff(xprt, RPCRDMA_INIT_REEST_TO);
        }
+       queue_delayed_work(xprtiod_workqueue, &r_xprt->rx_connect_worker,
+                          delay);
 }
 
 /**
        .send_request           = xprt_rdma_send_request,
        .close                  = xprt_rdma_close,
        .destroy                = xprt_rdma_destroy,
+       .set_connect_timeout    = xprt_rdma_tcp_set_connect_timeout,
        .print_stats            = xprt_rdma_print_stats,
        .enable_swap            = xprt_rdma_enable_swap,
        .disable_swap           = xprt_rdma_disable_swap,
 
        struct rpcrdma_ep       rx_ep;
        struct rpcrdma_buffer   rx_buf;
        struct delayed_work     rx_connect_worker;
+       struct rpc_timeout      rx_timeout;
        struct rpcrdma_stats    rx_stats;
 };
 
 
        xprt_wake_pending_tasks(xprt, status);
 }
 
-static unsigned long xs_reconnect_delay(const struct rpc_xprt *xprt)
-{
-       unsigned long start, now = jiffies;
-
-       start = xprt->stat.connect_start + xprt->reestablish_timeout;
-       if (time_after(start, now))
-               return start - now;
-       return 0;
-}
-
-static void xs_reconnect_backoff(struct rpc_xprt *xprt)
-{
-       xprt->reestablish_timeout <<= 1;
-       if (xprt->reestablish_timeout > xprt->max_reconnect_timeout)
-               xprt->reestablish_timeout = xprt->max_reconnect_timeout;
-       if (xprt->reestablish_timeout < XS_TCP_INIT_REEST_TO)
-               xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO;
-}
-
 /**
  * xs_connect - connect a socket to a remote endpoint
  * @xprt: pointer to transport structure
                /* Start by resetting any existing state */
                xs_reset_transport(transport);
 
-               delay = xs_reconnect_delay(xprt);
-               xs_reconnect_backoff(xprt);
+               delay = xprt_reconnect_delay(xprt);
+               xprt_reconnect_backoff(xprt, XS_TCP_INIT_REEST_TO);
 
        } else
                dprintk("RPC:       xs_connect scheduled xprt %p\n", xprt);