[SCSI] libiscsi: fix cmds_max setting
Mike Christie [Wed, 21 May 2008 20:54:17 +0000 (15:54 -0500)]
Drivers expect that the cmds_max value they pass to the iscsi layer
is the max scsi commands  + mgmt tasks. This patch implements that
and fixes some checks for nr cmd limits.

Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>

drivers/scsi/libiscsi.c
include/scsi/libiscsi.h

index c1af2aa..c723e60 100644 (file)
@@ -1893,29 +1893,48 @@ EXPORT_SYMBOL_GPL(iscsi_host_free);
  *
  * This can be used by software iscsi_transports that allocate
  * a session per scsi host.
+ *
+ * Callers should set cmds_max to the largest total numer (mgmt + scsi) of
+ * tasks they support. The iscsi layer reserves ISCSI_MGMT_CMDS_MAX tasks
+ * for nop handling and login/logout requests.
  */
 struct iscsi_cls_session *
 iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
-                   uint16_t scsi_cmds_max, int cmd_task_size,
+                   uint16_t cmds_max, int cmd_task_size,
                    uint32_t initial_cmdsn, unsigned int id)
 {
        struct iscsi_session *session;
        struct iscsi_cls_session *cls_session;
-       int cmd_i, cmds_max;
-
+       int cmd_i, scsi_cmds, total_cmds = cmds_max;
        /*
-        * The iscsi layer needs some tasks for nop handling and tmfs.
+        * The iscsi layer needs some tasks for nop handling and tmfs,
+        * so the cmds_max must at least be greater than ISCSI_MGMT_CMDS_MAX
+        * + 1 command for scsi IO.
         */
-       if (scsi_cmds_max < 1)
-               scsi_cmds_max = ISCSI_MGMT_CMDS_MAX;
-       if ((scsi_cmds_max + ISCSI_MGMT_CMDS_MAX) >= ISCSI_MGMT_ITT_OFFSET) {
-               printk(KERN_ERR "iscsi: invalid can_queue of %d. "
-                      "can_queue must be less than %d.\n",
-                      scsi_cmds_max,
-                      ISCSI_MGMT_ITT_OFFSET - ISCSI_MGMT_CMDS_MAX);
-               scsi_cmds_max = ISCSI_DEF_XMIT_CMDS_MAX;
+       if (total_cmds < ISCSI_TOTAL_CMDS_MIN) {
+               printk(KERN_ERR "iscsi: invalid can_queue of %d. can_queue "
+                      "must be a power of two that is at least %d.\n",
+                      total_cmds, ISCSI_TOTAL_CMDS_MIN);
+               return NULL;
+       }
+
+       if (total_cmds > ISCSI_TOTAL_CMDS_MAX) {
+               printk(KERN_ERR "iscsi: invalid can_queue of %d. can_queue "
+                      "must be a power of 2 less than or equal to %d.\n",
+                      cmds_max, ISCSI_TOTAL_CMDS_MAX);
+               total_cmds = ISCSI_TOTAL_CMDS_MAX;
+       }
+
+       if (!is_power_of_2(total_cmds)) {
+               printk(KERN_ERR "iscsi: invalid can_queue of %d. can_queue "
+                      "must be a power of 2.\n", total_cmds);
+               total_cmds = rounddown_pow_of_two(total_cmds);
+               if (total_cmds < ISCSI_TOTAL_CMDS_MIN)
+                       return NULL;
+               printk(KERN_INFO "iscsi: Rounding can_queue to %d.\n",
+                      total_cmds);
        }
-       cmds_max = roundup_pow_of_two(scsi_cmds_max + ISCSI_MGMT_CMDS_MAX);
+       scsi_cmds = total_cmds - ISCSI_MGMT_CMDS_MAX;
 
        cls_session = iscsi_alloc_session(shost, iscsit,
                                          sizeof(struct iscsi_session));
@@ -1928,8 +1947,8 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
        session->fast_abort = 1;
        session->lu_reset_timeout = 15;
        session->abort_timeout = 10;
-       session->scsi_cmds_max = scsi_cmds_max;
-       session->cmds_max = cmds_max;
+       session->scsi_cmds_max = scsi_cmds;
+       session->cmds_max = total_cmds;
        session->queued_cmdsn = session->cmdsn = initial_cmdsn;
        session->exp_cmdsn = initial_cmdsn + 1;
        session->max_cmdsn = initial_cmdsn + 1;
index 21cfb1d..5bf0187 100644 (file)
@@ -52,9 +52,7 @@ struct device;
 #endif
 
 #define ISCSI_DEF_XMIT_CMDS_MAX        128     /* must be power of 2 */
-#define ISCSI_MGMT_CMDS_MAX    16      /* must be power of 2 */
-
-#define ISCSI_MGMT_ITT_OFFSET  0xa00
+#define ISCSI_MGMT_CMDS_MAX    15
 
 #define ISCSI_DEF_CMD_PER_LUN          32
 #define ISCSI_MAX_CMD_PER_LUN          128
@@ -72,7 +70,10 @@ enum {
 /* Connection suspend "bit" */
 #define ISCSI_SUSPEND_BIT              1
 
-#define ISCSI_ITT_MASK                 (0xfff)
+#define ISCSI_ITT_MASK                 (0x1fff)
+#define ISCSI_TOTAL_CMDS_MAX           4096
+/* this must be a power of two greater than ISCSI_MGMT_CMDS_MAX */
+#define ISCSI_TOTAL_CMDS_MIN           16
 #define ISCSI_AGE_SHIFT                        28
 #define ISCSI_AGE_MASK                 (0xf << ISCSI_AGE_SHIFT)