IB/srp: Increase block layer timeout
[cascardo/linux.git] / drivers / infiniband / ulp / srp / ib_srp.c
index 1b5b0c7..5aa70e9 100644 (file)
@@ -638,9 +638,9 @@ static void srp_reset_req(struct srp_target_port *target, struct srp_request *re
        struct scsi_cmnd *scmnd = srp_claim_req(target, req, NULL);
 
        if (scmnd) {
+               srp_free_req(target, req, scmnd, 0);
                scmnd->result = DID_RESET << 16;
                scmnd->scsi_done(scmnd);
-               srp_free_req(target, req, scmnd, 0);
        }
 }
 
@@ -1419,6 +1419,33 @@ err:
        return -ENOMEM;
 }
 
+static uint32_t srp_compute_rq_tmo(struct ib_qp_attr *qp_attr, int attr_mask)
+{
+       uint64_t T_tr_ns, max_compl_time_ms;
+       uint32_t rq_tmo_jiffies;
+
+       /*
+        * According to section 11.2.4.2 in the IBTA spec (Modify Queue Pair,
+        * table 91), both the QP timeout and the retry count have to be set
+        * for RC QP's during the RTR to RTS transition.
+        */
+       WARN_ON_ONCE((attr_mask & (IB_QP_TIMEOUT | IB_QP_RETRY_CNT)) !=
+                    (IB_QP_TIMEOUT | IB_QP_RETRY_CNT));
+
+       /*
+        * Set target->rq_tmo_jiffies to one second more than the largest time
+        * it can take before an error completion is generated. See also
+        * C9-140..142 in the IBTA spec for more information about how to
+        * convert the QP Local ACK Timeout value to nanoseconds.
+        */
+       T_tr_ns = 4096 * (1ULL << qp_attr->timeout);
+       max_compl_time_ms = qp_attr->retry_cnt * 4 * T_tr_ns;
+       do_div(max_compl_time_ms, NSEC_PER_MSEC);
+       rq_tmo_jiffies = msecs_to_jiffies(max_compl_time_ms + 1000);
+
+       return rq_tmo_jiffies;
+}
+
 static void srp_cm_rep_handler(struct ib_cm_id *cm_id,
                               struct srp_login_rsp *lrsp,
                               struct srp_target_port *target)
@@ -1478,6 +1505,8 @@ static void srp_cm_rep_handler(struct ib_cm_id *cm_id,
        if (ret)
                goto error_free;
 
+       target->rq_tmo_jiffies = srp_compute_rq_tmo(qp_attr, attr_mask);
+
        ret = ib_modify_qp(target->qp, qp_attr, attr_mask);
        if (ret)
                goto error_free;
@@ -1687,6 +1716,7 @@ static int srp_abort(struct scsi_cmnd *scmnd)
                          SRP_TSK_ABORT_TASK);
        srp_free_req(target, req, scmnd, 0);
        scmnd->result = DID_ABORT << 16;
+       scmnd->scsi_done(scmnd);
 
        return SUCCESS;
 }
@@ -1728,6 +1758,21 @@ static int srp_reset_host(struct scsi_cmnd *scmnd)
        return ret;
 }
 
+static int srp_slave_configure(struct scsi_device *sdev)
+{
+       struct Scsi_Host *shost = sdev->host;
+       struct srp_target_port *target = host_to_target(shost);
+       struct request_queue *q = sdev->request_queue;
+       unsigned long timeout;
+
+       if (sdev->type == TYPE_DISK) {
+               timeout = max_t(unsigned, 30 * HZ, target->rq_tmo_jiffies);
+               blk_queue_rq_timeout(q, timeout);
+       }
+
+       return 0;
+}
+
 static ssize_t show_id_ext(struct device *dev, struct device_attribute *attr,
                           char *buf)
 {
@@ -1860,6 +1905,7 @@ static struct scsi_host_template srp_template = {
        .module                         = THIS_MODULE,
        .name                           = "InfiniBand SRP initiator",
        .proc_name                      = DRV_NAME,
+       .slave_configure                = srp_slave_configure,
        .info                           = srp_target_info,
        .queuecommand                   = srp_queuecommand,
        .eh_abort_handler               = srp_abort,