[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>
This commit is contained in:
committed by
James Bottomley
parent
b522d7d42d
commit
977b5a0af6
@@ -34,6 +34,11 @@ struct lpfc_sli2_slim;
|
|||||||
#define LPFC_IOCB_LIST_CNT 2250 /* list of IOCBs for fast-path usage. */
|
#define LPFC_IOCB_LIST_CNT 2250 /* list of IOCBs for fast-path usage. */
|
||||||
#define LPFC_Q_RAMP_UP_INTERVAL 120 /* lun q_depth ramp up interval */
|
#define LPFC_Q_RAMP_UP_INTERVAL 120 /* lun q_depth ramp up interval */
|
||||||
#define LPFC_VNAME_LEN 100 /* vport symbolic name length */
|
#define LPFC_VNAME_LEN 100 /* vport symbolic name length */
|
||||||
|
#define LPFC_TGTQ_INTERVAL 40000 /* Min amount of time between tgt
|
||||||
|
queue depth change in millisecs */
|
||||||
|
#define LPFC_TGTQ_RAMPUP_PCENT 5 /* Target queue rampup in percentage */
|
||||||
|
#define LPFC_MIN_TGT_QDEPTH 100
|
||||||
|
#define LPFC_MAX_TGT_QDEPTH 0xFFFF
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Following time intervals are used of adjusting SCSI device
|
* Following time intervals are used of adjusting SCSI device
|
||||||
@@ -363,6 +368,7 @@ struct lpfc_vport {
|
|||||||
uint32_t cfg_log_verbose;
|
uint32_t cfg_log_verbose;
|
||||||
uint32_t cfg_max_luns;
|
uint32_t cfg_max_luns;
|
||||||
uint32_t cfg_enable_da_id;
|
uint32_t cfg_enable_da_id;
|
||||||
|
uint32_t cfg_max_scsicmpl_time;
|
||||||
|
|
||||||
uint32_t dev_loss_tmo_changed;
|
uint32_t dev_loss_tmo_changed;
|
||||||
|
|
||||||
|
@@ -2296,6 +2296,48 @@ LPFC_VPORT_ATTR_R(fcp_class, 3, 2, 3,
|
|||||||
LPFC_VPORT_ATTR_RW(use_adisc, 0, 0, 1,
|
LPFC_VPORT_ATTR_RW(use_adisc, 0, 0, 1,
|
||||||
"Use ADISC on rediscovery to authenticate FCP devices");
|
"Use ADISC on rediscovery to authenticate FCP devices");
|
||||||
|
|
||||||
|
/*
|
||||||
|
# lpfc_max_scsicmpl_time: Use scsi command completion time to control I/O queue
|
||||||
|
# depth. Default value is 0. When the value of this parameter is zero the
|
||||||
|
# SCSI command completion time is not used for controlling I/O queue depth. When
|
||||||
|
# the parameter is set to a non-zero value, the I/O queue depth is controlled
|
||||||
|
# to limit the I/O completion time to the parameter value.
|
||||||
|
# The value is set in milliseconds.
|
||||||
|
*/
|
||||||
|
static int lpfc_max_scsicmpl_time;
|
||||||
|
module_param(lpfc_max_scsicmpl_time, int, 0);
|
||||||
|
MODULE_PARM_DESC(lpfc_max_scsicmpl_time,
|
||||||
|
"Use command completion time to control queue depth");
|
||||||
|
lpfc_vport_param_show(max_scsicmpl_time);
|
||||||
|
lpfc_vport_param_init(max_scsicmpl_time, 0, 0, 60000);
|
||||||
|
static int
|
||||||
|
lpfc_max_scsicmpl_time_set(struct lpfc_vport *vport, int val)
|
||||||
|
{
|
||||||
|
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
|
||||||
|
struct lpfc_nodelist *ndlp, *next_ndlp;
|
||||||
|
|
||||||
|
if (val == vport->cfg_max_scsicmpl_time)
|
||||||
|
return 0;
|
||||||
|
if ((val < 0) || (val > 60000))
|
||||||
|
return -EINVAL;
|
||||||
|
vport->cfg_max_scsicmpl_time = val;
|
||||||
|
|
||||||
|
spin_lock_irq(shost->host_lock);
|
||||||
|
list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
|
||||||
|
if (!NLP_CHK_NODE_ACT(ndlp))
|
||||||
|
continue;
|
||||||
|
if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
|
||||||
|
continue;
|
||||||
|
ndlp->cmd_qdepth = LPFC_MAX_TGT_QDEPTH;
|
||||||
|
}
|
||||||
|
spin_unlock_irq(shost->host_lock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
lpfc_vport_param_store(max_scsicmpl_time);
|
||||||
|
static DEVICE_ATTR(lpfc_max_scsicmpl_time, S_IRUGO | S_IWUSR,
|
||||||
|
lpfc_max_scsicmpl_time_show,
|
||||||
|
lpfc_max_scsicmpl_time_store);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
# lpfc_ack0: Use ACK0, instead of ACK1 for class 2 acknowledgement. Value
|
# lpfc_ack0: Use ACK0, instead of ACK1 for class 2 acknowledgement. Value
|
||||||
# range is [0,1]. Default value is 0.
|
# range is [0,1]. Default value is 0.
|
||||||
@@ -2459,6 +2501,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
|
|||||||
&dev_attr_lpfc_enable_hba_reset,
|
&dev_attr_lpfc_enable_hba_reset,
|
||||||
&dev_attr_lpfc_enable_hba_heartbeat,
|
&dev_attr_lpfc_enable_hba_heartbeat,
|
||||||
&dev_attr_lpfc_sg_seg_cnt,
|
&dev_attr_lpfc_sg_seg_cnt,
|
||||||
|
&dev_attr_lpfc_max_scsicmpl_time,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -3580,6 +3623,7 @@ lpfc_get_vport_cfgparam(struct lpfc_vport *vport)
|
|||||||
lpfc_restrict_login_init(vport, lpfc_restrict_login);
|
lpfc_restrict_login_init(vport, lpfc_restrict_login);
|
||||||
lpfc_fcp_class_init(vport, lpfc_fcp_class);
|
lpfc_fcp_class_init(vport, lpfc_fcp_class);
|
||||||
lpfc_use_adisc_init(vport, lpfc_use_adisc);
|
lpfc_use_adisc_init(vport, lpfc_use_adisc);
|
||||||
|
lpfc_max_scsicmpl_time_init(vport, lpfc_max_scsicmpl_time);
|
||||||
lpfc_fdmi_on_init(vport, lpfc_fdmi_on);
|
lpfc_fdmi_on_init(vport, lpfc_fdmi_on);
|
||||||
lpfc_discovery_threads_init(vport, lpfc_discovery_threads);
|
lpfc_discovery_threads_init(vport, lpfc_discovery_threads);
|
||||||
lpfc_max_luns_init(vport, lpfc_max_luns);
|
lpfc_max_luns_init(vport, lpfc_max_luns);
|
||||||
|
@@ -88,6 +88,9 @@ struct lpfc_nodelist {
|
|||||||
unsigned long last_ramp_up_time; /* jiffy of last ramp up */
|
unsigned long last_ramp_up_time; /* jiffy of last ramp up */
|
||||||
unsigned long last_q_full_time; /* jiffy of last queue full */
|
unsigned long last_q_full_time; /* jiffy of last queue full */
|
||||||
struct kref kref;
|
struct kref kref;
|
||||||
|
atomic_t cmd_pending;
|
||||||
|
uint32_t cmd_qdepth;
|
||||||
|
unsigned long last_change_time;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Defines for nlp_flag (uint32) */
|
/* Defines for nlp_flag (uint32) */
|
||||||
|
@@ -2988,6 +2988,8 @@ lpfc_nlp_init(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
|
|||||||
INIT_LIST_HEAD(&ndlp->nlp_listp);
|
INIT_LIST_HEAD(&ndlp->nlp_listp);
|
||||||
kref_init(&ndlp->kref);
|
kref_init(&ndlp->kref);
|
||||||
NLP_INT_NODE_ACT(ndlp);
|
NLP_INT_NODE_ACT(ndlp);
|
||||||
|
atomic_set(&ndlp->cmd_pending, 0);
|
||||||
|
ndlp->cmd_qdepth = LPFC_MAX_TGT_QDEPTH;
|
||||||
|
|
||||||
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE,
|
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE,
|
||||||
"node init: did:x%x",
|
"node init: did:x%x",
|
||||||
|
@@ -628,6 +628,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
|
|||||||
|
|
||||||
lpfc_cmd->result = pIocbOut->iocb.un.ulpWord[4];
|
lpfc_cmd->result = pIocbOut->iocb.un.ulpWord[4];
|
||||||
lpfc_cmd->status = pIocbOut->iocb.ulpStatus;
|
lpfc_cmd->status = pIocbOut->iocb.ulpStatus;
|
||||||
|
atomic_dec(&pnode->cmd_pending);
|
||||||
|
|
||||||
if (lpfc_cmd->status) {
|
if (lpfc_cmd->status) {
|
||||||
if (lpfc_cmd->status == IOSTAT_LOCAL_REJECT &&
|
if (lpfc_cmd->status == IOSTAT_LOCAL_REJECT &&
|
||||||
@@ -688,6 +689,29 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
|
|||||||
|
|
||||||
result = cmd->result;
|
result = cmd->result;
|
||||||
sdev = cmd->device;
|
sdev = cmd->device;
|
||||||
|
if (vport->cfg_max_scsicmpl_time &&
|
||||||
|
time_after(jiffies, lpfc_cmd->start_time +
|
||||||
|
msecs_to_jiffies(vport->cfg_max_scsicmpl_time))) {
|
||||||
|
spin_lock_irqsave(sdev->host->host_lock, flags);
|
||||||
|
if ((pnode->cmd_qdepth > atomic_read(&pnode->cmd_pending) &&
|
||||||
|
(atomic_read(&pnode->cmd_pending) > LPFC_MIN_TGT_QDEPTH) &&
|
||||||
|
((cmd->cmnd[0] == READ_10) || (cmd->cmnd[0] == WRITE_10))))
|
||||||
|
pnode->cmd_qdepth = atomic_read(&pnode->cmd_pending);
|
||||||
|
|
||||||
|
pnode->last_change_time = jiffies;
|
||||||
|
spin_unlock_irqrestore(sdev->host->host_lock, flags);
|
||||||
|
} else if ((pnode->cmd_qdepth < LPFC_MAX_TGT_QDEPTH) &&
|
||||||
|
time_after(jiffies, pnode->last_change_time +
|
||||||
|
msecs_to_jiffies(LPFC_TGTQ_INTERVAL))) {
|
||||||
|
spin_lock_irqsave(sdev->host->host_lock, flags);
|
||||||
|
pnode->cmd_qdepth += pnode->cmd_qdepth *
|
||||||
|
LPFC_TGTQ_RAMPUP_PCENT / 100;
|
||||||
|
if (pnode->cmd_qdepth > LPFC_MAX_TGT_QDEPTH)
|
||||||
|
pnode->cmd_qdepth = LPFC_MAX_TGT_QDEPTH;
|
||||||
|
pnode->last_change_time = jiffies;
|
||||||
|
spin_unlock_irqrestore(sdev->host->host_lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd);
|
lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd);
|
||||||
cmd->scsi_done(cmd);
|
cmd->scsi_done(cmd);
|
||||||
|
|
||||||
@@ -1075,6 +1099,8 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
|
|||||||
cmnd->result = ScsiResult(DID_TRANSPORT_DISRUPTED, 0);
|
cmnd->result = ScsiResult(DID_TRANSPORT_DISRUPTED, 0);
|
||||||
goto out_fail_command;
|
goto out_fail_command;
|
||||||
}
|
}
|
||||||
|
if (atomic_read(&ndlp->cmd_pending) >= ndlp->cmd_qdepth)
|
||||||
|
goto out_host_busy;
|
||||||
|
|
||||||
lpfc_cmd = lpfc_get_scsi_buf(phba);
|
lpfc_cmd = lpfc_get_scsi_buf(phba);
|
||||||
if (lpfc_cmd == NULL) {
|
if (lpfc_cmd == NULL) {
|
||||||
@@ -1093,6 +1119,7 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
|
|||||||
lpfc_cmd->pCmd = cmnd;
|
lpfc_cmd->pCmd = cmnd;
|
||||||
lpfc_cmd->rdata = rdata;
|
lpfc_cmd->rdata = rdata;
|
||||||
lpfc_cmd->timeout = 0;
|
lpfc_cmd->timeout = 0;
|
||||||
|
lpfc_cmd->start_time = jiffies;
|
||||||
cmnd->host_scribble = (unsigned char *)lpfc_cmd;
|
cmnd->host_scribble = (unsigned char *)lpfc_cmd;
|
||||||
cmnd->scsi_done = done;
|
cmnd->scsi_done = done;
|
||||||
|
|
||||||
@@ -1102,6 +1129,7 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
|
|||||||
|
|
||||||
lpfc_scsi_prep_cmnd(vport, lpfc_cmd, ndlp);
|
lpfc_scsi_prep_cmnd(vport, lpfc_cmd, ndlp);
|
||||||
|
|
||||||
|
atomic_inc(&ndlp->cmd_pending);
|
||||||
err = lpfc_sli_issue_iocb(phba, &phba->sli.ring[psli->fcp_ring],
|
err = lpfc_sli_issue_iocb(phba, &phba->sli.ring[psli->fcp_ring],
|
||||||
&lpfc_cmd->cur_iocbq, SLI_IOCB_RET_IOCB);
|
&lpfc_cmd->cur_iocbq, SLI_IOCB_RET_IOCB);
|
||||||
if (err)
|
if (err)
|
||||||
@@ -1116,6 +1144,7 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_host_busy_free_buf:
|
out_host_busy_free_buf:
|
||||||
|
atomic_dec(&ndlp->cmd_pending);
|
||||||
lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd);
|
lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd);
|
||||||
lpfc_release_scsi_buf(phba, lpfc_cmd);
|
lpfc_release_scsi_buf(phba, lpfc_cmd);
|
||||||
out_host_busy:
|
out_host_busy:
|
||||||
|
@@ -139,6 +139,7 @@ struct lpfc_scsi_buf {
|
|||||||
*/
|
*/
|
||||||
struct lpfc_iocbq cur_iocbq;
|
struct lpfc_iocbq cur_iocbq;
|
||||||
wait_queue_head_t *waitq;
|
wait_queue_head_t *waitq;
|
||||||
|
unsigned long start_time;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define LPFC_SCSI_DMA_EXT_SIZE 264
|
#define LPFC_SCSI_DMA_EXT_SIZE 264
|
||||||
|
Reference in New Issue
Block a user