Fail SCSI commands if the QP between initiator and target is in the
error state. For connections monitored by the multipath software
the result is that multipathd doesn't have to wait until the SCSI
timeout has expired to find out that a path has failed.  Also,
introduce the function srp_handle_qp_err(), change the type of
qp_in_error from int into bool and move the initialization of that
variable from srp_reconnect_target() to srp_connect_target().

Signed-off-by: Bart Van Assche <[email protected]>
Cc: David Dillow <[email protected]>
Cc: Roland Dreier <[email protected]>
---
 drivers/infiniband/ulp/srp/ib_srp.c |   40
+++++++++++++++++++---------------
 drivers/infiniband/ulp/srp/ib_srp.h |    2 +-
 2 files changed, 23 insertions(+), 19 deletions(-)

diff --git a/drivers/infiniband/ulp/srp/ib_srp.c
b/drivers/infiniband/ulp/srp/ib_srp.c
index f333705..28a044e 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -515,6 +515,8 @@ static int srp_connect_target(struct srp_target_port
*target)
        int retries = 3;
        int ret;

+       target->qp_in_error = false;
+
        ret = srp_lookup_path(target);
        if (ret)
                return ret;
@@ -685,7 +687,6 @@ static int srp_reconnect_target(struct
srp_target_port *target)
        for (i = 0; i < SRP_SQ_SIZE; ++i)
                list_add(&target->tx_ring[i]->list, &target->free_tx);

-       target->qp_in_error = 0;
        ret = srp_connect_target(target);
        if (ret)
                goto err;
@@ -1256,6 +1257,15 @@ static void srp_handle_recv(struct
srp_target_port *target, struct ib_wc *wc)
                             PFX "Recv failed with error code %d\n", res);
 }

+static void srp_handle_qp_err(enum ib_wc_status wc_status,
+                             enum ib_wc_opcode wc_opcode,
+                             struct srp_target_port *target)
+{
+       shost_printk(KERN_ERR, target->scsi_host, PFX "failed %s status %d\n",
+                    wc_opcode & IB_WC_RECV ? "receive" : "send", wc_status);
+       target->qp_in_error = true;
+}
+
 static void srp_recv_completion(struct ib_cq *cq, void *target_ptr)
 {
        struct srp_target_port *target = target_ptr;
@@ -1263,15 +1273,12 @@ static void srp_recv_completion(struct ib_cq
*cq, void *target_ptr)

        ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);
        while (ib_poll_cq(cq, 1, &wc) > 0) {
-               if (wc.status) {
-                       shost_printk(KERN_ERR, target->scsi_host,
-                                    PFX "failed receive status %d\n",
-                                    wc.status);
-                       target->qp_in_error = 1;
+               if (likely(wc.status == IB_WC_SUCCESS)) {
+                       srp_handle_recv(target, &wc);
+               } else {
+                       srp_handle_qp_err(wc.status, wc.opcode, target);
                        break;
                }
-
-               srp_handle_recv(target, &wc);
        }
 }

@@ -1282,16 +1289,13 @@ static void srp_send_completion(struct ib_cq
*cq, void *target_ptr)
        struct srp_iu *iu;

        while (ib_poll_cq(cq, 1, &wc) > 0) {
-               if (wc.status) {
-                       shost_printk(KERN_ERR, target->scsi_host,
-                                    PFX "failed send status %d\n",
-                                    wc.status);
-                       target->qp_in_error = 1;
+               if (likely(wc.status == IB_WC_SUCCESS)) {
+                       iu = (struct srp_iu *) (uintptr_t) wc.wr_id;
+                       list_add(&iu->list, &target->free_tx);
+               } else {
+                       srp_handle_qp_err(wc.status, wc.opcode, target);
                        break;
                }
-
-               iu = (struct srp_iu *) (uintptr_t) wc.wr_id;
-               list_add(&iu->list, &target->free_tx);
        }
 }

@@ -1309,7 +1313,8 @@ static int srp_queuecommand(struct Scsi_Host
*shost, struct scsi_cmnd *scmnd)
                goto err;

        if (target->state == SRP_TARGET_DEAD ||
-           target->state == SRP_TARGET_REMOVED) {
+           target->state == SRP_TARGET_REMOVED ||
+           target->qp_in_error) {
                scmnd->result = DID_BAD_TARGET << 16;
                scmnd->scsi_done(scmnd);
                return 0;
@@ -2269,7 +2274,6 @@ static ssize_t srp_create_target(struct device *dev,
        if (ret)
                goto err_free_ib;

-       target->qp_in_error = 0;
        ret = srp_connect_target(target);
        if (ret) {
                shost_printk(KERN_ERR, target->scsi_host,
diff --git a/drivers/infiniband/ulp/srp/ib_srp.h
b/drivers/infiniband/ulp/srp/ib_srp.h
index e3a6304..f0daeb3 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.h
+++ b/drivers/infiniband/ulp/srp/ib_srp.h
@@ -180,7 +180,7 @@ struct srp_target_port {
        struct list_head        list;
        struct completion       done;
        int                     status;
-       int                     qp_in_error;
+       bool                    qp_in_error;

        struct completion       tsk_mgmt_done;
        u8                      tsk_mgmt_status;
-- 
1.7.7

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to