IB/srp: Respect target credit limit
authorDavid Dillow <dillowda@ornl.gov>
Wed, 19 Dec 2007 22:08:43 +0000 (17:08 -0500)
committerRoland Dreier <rolandd@cisco.com>
Fri, 25 Jan 2008 22:15:37 +0000 (14:15 -0800)
The current SRP initiator will send requests even if it has no credits
available.  The results of sending extra requests are vendor specific,
but on some devices, overrunning credits will cost 85% of peak
performance -- e.g. 100 MB/s vs 720 MB/s.  Other devices may just drop
the requests.

This patch will tell the SCSI midlayer to queue requests if there are
fewer than two credits remaining, and will not issue a task management
request if there are no credits remaining.  The mid-layer will retry
the queued command once an outstanding command completes.

The patch also removes the unlikely() in __srp_get_tx_iu(), as it is
not at all unlikely to hit this limit under heavy load.

Signed-off-by: David Dillow <dillowda@ornl.gov>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
drivers/infiniband/ulp/srp/ib_srp.c
drivers/infiniband/ulp/srp/ib_srp.h

index bdb6f8517401d5950872c05e47aa64685e8287c6..e98d0612d7ace75915cffdabab2e799ed3a00798 100644 (file)
@@ -930,13 +930,18 @@ static int srp_post_recv(struct srp_target_port *target)
  * req_lim and tx_head.  Lock cannot be dropped between call here and
  * call to __srp_post_send().
  */
-static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target)
+static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target,
+                                       enum srp_request_type req_type)
 {
+       s32 min = (req_type == SRP_REQ_TASK_MGMT) ? 1 : 2;
+
        if (target->tx_head - target->tx_tail >= SRP_SQ_SIZE)
                return NULL;
 
-       if (unlikely(target->req_lim < 1))
+       if (target->req_lim < min) {
                ++target->zero_req_lim;
+               return NULL;
+       }
 
        return target->tx_ring[target->tx_head & SRP_SQ_SIZE];
 }
@@ -993,7 +998,7 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
                return 0;
        }
 
-       iu = __srp_get_tx_iu(target);
+       iu = __srp_get_tx_iu(target, SRP_REQ_NORMAL);
        if (!iu)
                goto err;
 
@@ -1283,7 +1288,7 @@ static int srp_send_tsk_mgmt(struct srp_target_port *target,
 
        init_completion(&req->done);
 
-       iu = __srp_get_tx_iu(target);
+       iu = __srp_get_tx_iu(target, SRP_REQ_TASK_MGMT);
        if (!iu)
                goto out;
 
index e3573e7038c4ea7089f5e257964d75c3f0dbf043..4a3c1f37e4c206bea4674e76576596ac5a851bca 100644 (file)
@@ -79,6 +79,11 @@ enum srp_target_state {
        SRP_TARGET_REMOVED
 };
 
+enum srp_request_type {
+       SRP_REQ_NORMAL,
+       SRP_REQ_TASK_MGMT,
+};
+
 struct srp_device {
        struct list_head        dev_list;
        struct ib_device       *dev;