aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Smart <James.Smart@Emulex.Com>2008-09-07 11:52:04 -0400
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-10-13 09:28:57 -0400
commit977b5a0af6d22a1a0170057c19cde37eeac68acd (patch)
tree247128ab00aa554eca5366ff8fb3505930729eaf
parentb522d7d42d7ce843885d4c6740c5bd50876a2971 (diff)
[SCSI] lpfc 8.2.8 v2 : Add sysfs control of target queue depth handling
Added new sysfs attribute lpfc_max_scsicmpl_time. Attribute, when enabled, will control target queue depth based on I/O completion time. Signed-off-by: James Smart <james.smart@emulex.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
-rw-r--r--drivers/scsi/lpfc/lpfc.h6
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c44
-rw-r--r--drivers/scsi/lpfc/lpfc_disc.h3
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c2
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c29
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.h1
6 files changed, 85 insertions, 0 deletions
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index 18153846611..3a500d68306 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -34,6 +34,11 @@ struct lpfc_sli2_slim;
34#define LPFC_IOCB_LIST_CNT 2250 /* list of IOCBs for fast-path usage. */ 34#define LPFC_IOCB_LIST_CNT 2250 /* list of IOCBs for fast-path usage. */
35#define LPFC_Q_RAMP_UP_INTERVAL 120 /* lun q_depth ramp up interval */ 35#define LPFC_Q_RAMP_UP_INTERVAL 120 /* lun q_depth ramp up interval */
36#define LPFC_VNAME_LEN 100 /* vport symbolic name length */ 36#define LPFC_VNAME_LEN 100 /* vport symbolic name length */
37#define LPFC_TGTQ_INTERVAL 40000 /* Min amount of time between tgt
38 queue depth change in millisecs */
39#define LPFC_TGTQ_RAMPUP_PCENT 5 /* Target queue rampup in percentage */
40#define LPFC_MIN_TGT_QDEPTH 100
41#define LPFC_MAX_TGT_QDEPTH 0xFFFF
37 42
38/* 43/*
39 * Following time intervals are used of adjusting SCSI device 44 * Following time intervals are used of adjusting SCSI device
@@ -363,6 +368,7 @@ struct lpfc_vport {
363 uint32_t cfg_log_verbose; 368 uint32_t cfg_log_verbose;
364 uint32_t cfg_max_luns; 369 uint32_t cfg_max_luns;
365 uint32_t cfg_enable_da_id; 370 uint32_t cfg_enable_da_id;
371 uint32_t cfg_max_scsicmpl_time;
366 372
367 uint32_t dev_loss_tmo_changed; 373 uint32_t dev_loss_tmo_changed;
368 374
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index 21397f37010..343b0b36ed2 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -2297,6 +2297,48 @@ LPFC_VPORT_ATTR_RW(use_adisc, 0, 0, 1,
2297 "Use ADISC on rediscovery to authenticate FCP devices"); 2297 "Use ADISC on rediscovery to authenticate FCP devices");
2298 2298
2299/* 2299/*
2300# lpfc_max_scsicmpl_time: Use scsi command completion time to control I/O queue
2301# depth. Default value is 0. When the value of this parameter is zero the
2302# SCSI command completion time is not used for controlling I/O queue depth. When
2303# the parameter is set to a non-zero value, the I/O queue depth is controlled
2304# to limit the I/O completion time to the parameter value.
2305# The value is set in milliseconds.
2306*/
2307static int lpfc_max_scsicmpl_time;
2308module_param(lpfc_max_scsicmpl_time, int, 0);
2309MODULE_PARM_DESC(lpfc_max_scsicmpl_time,
2310 "Use command completion time to control queue depth");
2311lpfc_vport_param_show(max_scsicmpl_time);
2312lpfc_vport_param_init(max_scsicmpl_time, 0, 0, 60000);
2313static int
2314lpfc_max_scsicmpl_time_set(struct lpfc_vport *vport, int val)
2315{
2316 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
2317 struct lpfc_nodelist *ndlp, *next_ndlp;
2318
2319 if (val == vport->cfg_max_scsicmpl_time)
2320 return 0;
2321 if ((val < 0) || (val > 60000))
2322 return -EINVAL;
2323 vport->cfg_max_scsicmpl_time = val;
2324
2325 spin_lock_irq(shost->host_lock);
2326 list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
2327 if (!NLP_CHK_NODE_ACT(ndlp))
2328 continue;
2329 if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
2330 continue;
2331 ndlp->cmd_qdepth = LPFC_MAX_TGT_QDEPTH;
2332 }
2333 spin_unlock_irq(shost->host_lock);
2334 return 0;
2335}
2336lpfc_vport_param_store(max_scsicmpl_time);
2337static DEVICE_ATTR(lpfc_max_scsicmpl_time, S_IRUGO | S_IWUSR,
2338 lpfc_max_scsicmpl_time_show,
2339 lpfc_max_scsicmpl_time_store);
2340
2341/*
2300# lpfc_ack0: Use ACK0, instead of ACK1 for class 2 acknowledgement. Value 2342# lpfc_ack0: Use ACK0, instead of ACK1 for class 2 acknowledgement. Value
2301# range is [0,1]. Default value is 0. 2343# range is [0,1]. Default value is 0.
2302*/ 2344*/
@@ -2459,6 +2501,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
2459 &dev_attr_lpfc_enable_hba_reset, 2501 &dev_attr_lpfc_enable_hba_reset,
2460 &dev_attr_lpfc_enable_hba_heartbeat, 2502 &dev_attr_lpfc_enable_hba_heartbeat,
2461 &dev_attr_lpfc_sg_seg_cnt, 2503 &dev_attr_lpfc_sg_seg_cnt,
2504 &dev_attr_lpfc_max_scsicmpl_time,
2462 NULL, 2505 NULL,
2463}; 2506};
2464 2507
@@ -3580,6 +3623,7 @@ lpfc_get_vport_cfgparam(struct lpfc_vport *vport)
3580 lpfc_restrict_login_init(vport, lpfc_restrict_login); 3623 lpfc_restrict_login_init(vport, lpfc_restrict_login);
3581 lpfc_fcp_class_init(vport, lpfc_fcp_class); 3624 lpfc_fcp_class_init(vport, lpfc_fcp_class);
3582 lpfc_use_adisc_init(vport, lpfc_use_adisc); 3625 lpfc_use_adisc_init(vport, lpfc_use_adisc);
3626 lpfc_max_scsicmpl_time_init(vport, lpfc_max_scsicmpl_time);
3583 lpfc_fdmi_on_init(vport, lpfc_fdmi_on); 3627 lpfc_fdmi_on_init(vport, lpfc_fdmi_on);
3584 lpfc_discovery_threads_init(vport, lpfc_discovery_threads); 3628 lpfc_discovery_threads_init(vport, lpfc_discovery_threads);
3585 lpfc_max_luns_init(vport, lpfc_max_luns); 3629 lpfc_max_luns_init(vport, lpfc_max_luns);
diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h
index 2db0b74b6fa..ccf8f41f345 100644
--- a/drivers/scsi/lpfc/lpfc_disc.h
+++ b/drivers/scsi/lpfc/lpfc_disc.h
@@ -88,6 +88,9 @@ struct lpfc_nodelist {
88 unsigned long last_ramp_up_time; /* jiffy of last ramp up */ 88 unsigned long last_ramp_up_time; /* jiffy of last ramp up */
89 unsigned long last_q_full_time; /* jiffy of last queue full */ 89 unsigned long last_q_full_time; /* jiffy of last queue full */
90 struct kref kref; 90 struct kref kref;
91 atomic_t cmd_pending;
92 uint32_t cmd_qdepth;
93 unsigned long last_change_time;
91}; 94};
92 95
93/* Defines for nlp_flag (uint32) */ 96/* Defines for nlp_flag (uint32) */
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index 3b00d9b86c7..887a5283605 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -2988,6 +2988,8 @@ lpfc_nlp_init(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
2988 INIT_LIST_HEAD(&ndlp->nlp_listp); 2988 INIT_LIST_HEAD(&ndlp->nlp_listp);
2989 kref_init(&ndlp->kref); 2989 kref_init(&ndlp->kref);
2990 NLP_INT_NODE_ACT(ndlp); 2990 NLP_INT_NODE_ACT(ndlp);
2991 atomic_set(&ndlp->cmd_pending, 0);
2992 ndlp->cmd_qdepth = LPFC_MAX_TGT_QDEPTH;
2991 2993
2992 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE, 2994 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE,
2993 "node init: did:x%x", 2995 "node init: did:x%x",
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index 72eef7e4a89..7b17f52660b 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -628,6 +628,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
628 628
629 lpfc_cmd->result = pIocbOut->iocb.un.ulpWord[4]; 629 lpfc_cmd->result = pIocbOut->iocb.un.ulpWord[4];
630 lpfc_cmd->status = pIocbOut->iocb.ulpStatus; 630 lpfc_cmd->status = pIocbOut->iocb.ulpStatus;
631 atomic_dec(&pnode->cmd_pending);
631 632
632 if (lpfc_cmd->status) { 633 if (lpfc_cmd->status) {
633 if (lpfc_cmd->status == IOSTAT_LOCAL_REJECT && 634 if (lpfc_cmd->status == IOSTAT_LOCAL_REJECT &&
@@ -688,6 +689,29 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
688 689
689 result = cmd->result; 690 result = cmd->result;
690 sdev = cmd->device; 691 sdev = cmd->device;
692 if (vport->cfg_max_scsicmpl_time &&
693 time_after(jiffies, lpfc_cmd->start_time +
694 msecs_to_jiffies(vport->cfg_max_scsicmpl_time))) {
695 spin_lock_irqsave(sdev->host->host_lock, flags);
696 if ((pnode->cmd_qdepth > atomic_read(&pnode->cmd_pending) &&
697 (atomic_read(&pnode->cmd_pending) > LPFC_MIN_TGT_QDEPTH) &&
698 ((cmd->cmnd[0] == READ_10) || (cmd->cmnd[0] == WRITE_10))))
699 pnode->cmd_qdepth = atomic_read(&pnode->cmd_pending);
700
701 pnode->last_change_time = jiffies;
702 spin_unlock_irqrestore(sdev->host->host_lock, flags);
703 } else if ((pnode->cmd_qdepth < LPFC_MAX_TGT_QDEPTH) &&
704 time_after(jiffies, pnode->last_change_time +
705 msecs_to_jiffies(LPFC_TGTQ_INTERVAL))) {
706 spin_lock_irqsave(sdev->host->host_lock, flags);
707 pnode->cmd_qdepth += pnode->cmd_qdepth *
708 LPFC_TGTQ_RAMPUP_PCENT / 100;
709 if (pnode->cmd_qdepth > LPFC_MAX_TGT_QDEPTH)
710 pnode->cmd_qdepth = LPFC_MAX_TGT_QDEPTH;
711 pnode->last_change_time = jiffies;
712 spin_unlock_irqrestore(sdev->host->host_lock, flags);
713 }
714
691 lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd); 715 lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd);
692 cmd->scsi_done(cmd); 716 cmd->scsi_done(cmd);
693 717
@@ -1075,6 +1099,8 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
1075 cmnd->result = ScsiResult(DID_TRANSPORT_DISRUPTED, 0); 1099 cmnd->result = ScsiResult(DID_TRANSPORT_DISRUPTED, 0);
1076 goto out_fail_command; 1100 goto out_fail_command;
1077 } 1101 }
1102 if (atomic_read(&ndlp->cmd_pending) >= ndlp->cmd_qdepth)
1103 goto out_host_busy;
1078 1104
1079 lpfc_cmd = lpfc_get_scsi_buf(phba); 1105 lpfc_cmd = lpfc_get_scsi_buf(phba);
1080 if (lpfc_cmd == NULL) { 1106 if (lpfc_cmd == NULL) {
@@ -1093,6 +1119,7 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
1093 lpfc_cmd->pCmd = cmnd; 1119 lpfc_cmd->pCmd = cmnd;
1094 lpfc_cmd->rdata = rdata; 1120 lpfc_cmd->rdata = rdata;
1095 lpfc_cmd->timeout = 0; 1121 lpfc_cmd->timeout = 0;
1122 lpfc_cmd->start_time = jiffies;
1096 cmnd->host_scribble = (unsigned char *)lpfc_cmd; 1123 cmnd->host_scribble = (unsigned char *)lpfc_cmd;
1097 cmnd->scsi_done = done; 1124 cmnd->scsi_done = done;
1098 1125
@@ -1102,6 +1129,7 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
1102 1129
1103 lpfc_scsi_prep_cmnd(vport, lpfc_cmd, ndlp); 1130 lpfc_scsi_prep_cmnd(vport, lpfc_cmd, ndlp);
1104 1131
1132 atomic_inc(&ndlp->cmd_pending);
1105 err = lpfc_sli_issue_iocb(phba, &phba->sli.ring[psli->fcp_ring], 1133 err = lpfc_sli_issue_iocb(phba, &phba->sli.ring[psli->fcp_ring],
1106 &lpfc_cmd->cur_iocbq, SLI_IOCB_RET_IOCB); 1134 &lpfc_cmd->cur_iocbq, SLI_IOCB_RET_IOCB);
1107 if (err) 1135 if (err)
@@ -1116,6 +1144,7 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
1116 return 0; 1144 return 0;
1117 1145
1118 out_host_busy_free_buf: 1146 out_host_busy_free_buf:
1147 atomic_dec(&ndlp->cmd_pending);
1119 lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd); 1148 lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd);
1120 lpfc_release_scsi_buf(phba, lpfc_cmd); 1149 lpfc_release_scsi_buf(phba, lpfc_cmd);
1121 out_host_busy: 1150 out_host_busy:
diff --git a/drivers/scsi/lpfc/lpfc_scsi.h b/drivers/scsi/lpfc/lpfc_scsi.h
index daba9237498..6737cabe9a7 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.h
+++ b/drivers/scsi/lpfc/lpfc_scsi.h
@@ -139,6 +139,7 @@ struct lpfc_scsi_buf {
139 */ 139 */
140 struct lpfc_iocbq cur_iocbq; 140 struct lpfc_iocbq cur_iocbq;
141 wait_queue_head_t *waitq; 141 wait_queue_head_t *waitq;
142 unsigned long start_time;
142}; 143};
143 144
144#define LPFC_SCSI_DMA_EXT_SIZE 264 145#define LPFC_SCSI_DMA_EXT_SIZE 264