The SRP initiator will currently send requests, even if we have no
credits available. The results of sending extra requests is
vendor-specific, but on some devices, overrunning our credits will cost
us 85% of peak performance -- e.g. 100 MB/s vs 720 MB/s. Other devices
may just drop them.

This patch will tell the SCSI mid-layer to queue requests if there are
less 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.

Also, it adds a queue length parameter to the target options, so that
the maximum number of commands the SCSI mid-layer will try to send can
be capped before it hits the credit limit.

Signed-off-by: David Dillow <[EMAIL PROTECTED]>
---

A cleanup would be to get rid of the zero_req_lim counter, as it should
never be hit now.

 ib_srp.c |   49 +++++++++++++++++++++++++++++++++++++++++++------
 ib_srp.h |    5 +++++
 2 files changed, 48 insertions(+), 6 deletions(-)

diff --git a/drivers/infiniband/ulp/srp/ib_srp.c 
b/drivers/infiniband/ulp/srp/ib_srp.c
index 950228f..18dbe89 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -925,6 +925,28 @@ static int srp_post_recv(struct srp_target_port *target)
        return ret;
 }
 
+/* Must be called with target->scsi_host->host_lock held to protect
+ * req_lim. Lock cannot be dropped between here and srp_use_credit().
+ */
+static int srp_check_credit(struct srp_target_port *target,
+                               enum srp_request_type req_type)
+{
+       /* Each request requires one credit, and we hold a credit in reserve
+        * so that we can send task management requests.
+        */
+       s32 min = (req_type == SRP_REQ_TASK_MGMT) ? 1 : 2;
+       return target->req_lim < min;
+}
+
+/* Must be called with target->scsi_host->host_lock held to protect
+ * req_lim. Lock cannot be dropped between the call to srp_check_credit()
+ * and the call to srp_use_credit()
+ */
+static void srp_use_credit(struct srp_target_port *target)
+{
+       target->req_lim--;
+}
+
 /*
  * Must be called with target->scsi_host->host_lock held to protect
  * req_lim and tx_head.  Lock cannot be dropped between call here and
@@ -965,10 +987,8 @@ static int __srp_post_send(struct srp_target_port *target,
 
        ret = ib_post_send(target->qp, &wr, &bad_wr);
 
-       if (!ret) {
+       if (!ret)
                ++target->tx_head;
-               --target->req_lim;
-       }
 
        return ret;
 }
@@ -993,6 +1013,9 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
                return 0;
        }
 
+       if (srp_check_credit(target, SRP_REQ_NORMAL))
+               goto err;
+
        iu = __srp_get_tx_iu(target);
        if (!iu)
                goto err;
@@ -1039,6 +1062,8 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
                goto err_unmap;
        }
 
+       srp_use_credit(target);
+
        list_move_tail(&req->list, &target->req_queue);
 
        return 0;
@@ -1180,9 +1205,6 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct 
ib_cm_event *event)
 
                        target->max_ti_iu_len = be32_to_cpu(rsp->max_ti_iu_len);
                        target->req_lim       = be32_to_cpu(rsp->req_lim_delta);
-
-                       target->scsi_host->can_queue = min(target->req_lim,
-                                                          
target->scsi_host->can_queue);
                } else {
                        printk(KERN_WARNING PFX "Unhandled RSP opcode %#x\n", 
opcode);
                        target->status = -ECONNRESET;
@@ -1283,6 +1305,9 @@ static int srp_send_tsk_mgmt(struct srp_target_port 
*target,
 
        init_completion(&req->done);
 
+       if (srp_check_credit(target, SRP_REQ_TASK_MGMT))
+               goto out;
+
        iu = __srp_get_tx_iu(target);
        if (!iu)
                goto out;
@@ -1300,6 +1325,7 @@ static int srp_send_tsk_mgmt(struct srp_target_port 
*target,
                goto out;
 
        req->tsk_mgmt = iu;
+       srp_use_credit(target);
 
        spin_unlock_irq(target->scsi_host->host_lock);
 
@@ -1540,6 +1566,7 @@ static struct scsi_host_template srp_template = {
        .eh_device_reset_handler        = srp_reset_device,
        .eh_host_reset_handler          = srp_reset_host,
        .can_queue                      = SRP_SQ_SIZE,
+       .max_host_blocked               = 1,
        .this_id                        = -1,
        .cmd_per_lun                    = SRP_SQ_SIZE,
        .use_clustering                 = ENABLE_CLUSTERING,
@@ -1610,6 +1637,7 @@ enum {
        SRP_OPT_MAX_CMD_PER_LUN = 1 << 6,
        SRP_OPT_IO_CLASS        = 1 << 7,
        SRP_OPT_INITIATOR_EXT   = 1 << 8,
+       SRP_OPT_QUEUE_LEN       = 1 << 9,
        SRP_OPT_ALL             = (SRP_OPT_ID_EXT       |
                                   SRP_OPT_IOC_GUID     |
                                   SRP_OPT_DGID         |
@@ -1627,6 +1655,7 @@ static match_table_t srp_opt_tokens = {
        { SRP_OPT_MAX_CMD_PER_LUN,      "max_cmd_per_lun=%d"    },
        { SRP_OPT_IO_CLASS,             "io_class=%x"           },
        { SRP_OPT_INITIATOR_EXT,        "initiator_ext=%s"      },
+       { SRP_OPT_QUEUE_LEN,            "queue_len=%d"          },
        { SRP_OPT_ERR,                  NULL                    }
 };
 
@@ -1754,6 +1783,14 @@ static int srp_parse_options(const char *buf, struct 
srp_target_port *target)
                        kfree(p);
                        break;
 
+               case SRP_OPT_QUEUE_LEN:
+                       if (match_int(args, &token)) {
+                               printk(KERN_WARNING PFX "bad queue_len 
parameter '%s'\n", p);
+                               goto out;
+                       }
+                       target->scsi_host->can_queue = min(token, SRP_SQ_SIZE);
+                       break;
+
                default:
                        printk(KERN_WARNING PFX "unknown parameter or missing 
value "
                               "'%s' in target creation request\n", p);
diff --git a/drivers/infiniband/ulp/srp/ib_srp.h 
b/drivers/infiniband/ulp/srp/ib_srp.h
index e3573e7..4a3c1f3 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.h
+++ b/drivers/infiniband/ulp/srp/ib_srp.h
@@ -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;


_______________________________________________
general mailing list
[email protected]
http://lists.openfabrics.org/cgi-bin/mailman/listinfo/general

To unsubscribe, please visit http://openib.org/mailman/listinfo/openib-general

Reply via email to