Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

James Smart and committed by
James Bottomley
977b5a0a b522d7d4

+85
+6
drivers/scsi/lpfc/lpfc.h
··· 34 34 #define LPFC_IOCB_LIST_CNT 2250 /* list of IOCBs for fast-path usage. */ 35 35 #define LPFC_Q_RAMP_UP_INTERVAL 120 /* lun q_depth ramp up interval */ 36 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 44 * Following time intervals are used of adjusting SCSI device ··· 368 363 uint32_t cfg_log_verbose; 369 364 uint32_t cfg_max_luns; 370 365 uint32_t cfg_enable_da_id; 366 + uint32_t cfg_max_scsicmpl_time; 371 367 372 368 uint32_t dev_loss_tmo_changed; 373 369
+44
drivers/scsi/lpfc/lpfc_attr.c
··· 2297 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 + */ 2307 + static int lpfc_max_scsicmpl_time; 2308 + module_param(lpfc_max_scsicmpl_time, int, 0); 2309 + MODULE_PARM_DESC(lpfc_max_scsicmpl_time, 2310 + "Use command completion time to control queue depth"); 2311 + lpfc_vport_param_show(max_scsicmpl_time); 2312 + lpfc_vport_param_init(max_scsicmpl_time, 0, 0, 60000); 2313 + static int 2314 + lpfc_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 + } 2336 + lpfc_vport_param_store(max_scsicmpl_time); 2337 + static 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 2342 # lpfc_ack0: Use ACK0, instead of ACK1 for class 2 acknowledgement. Value 2301 2343 # range is [0,1]. Default value is 0. 2302 2344 */ ··· 2501 2459 &dev_attr_lpfc_enable_hba_reset, 2502 2460 &dev_attr_lpfc_enable_hba_heartbeat, 2503 2461 &dev_attr_lpfc_sg_seg_cnt, 2462 + &dev_attr_lpfc_max_scsicmpl_time, 2504 2463 NULL, 2505 2464 }; 2506 2465 ··· 3623 3580 lpfc_restrict_login_init(vport, lpfc_restrict_login); 3624 3581 lpfc_fcp_class_init(vport, lpfc_fcp_class); 3625 3582 lpfc_use_adisc_init(vport, lpfc_use_adisc); 3583 + lpfc_max_scsicmpl_time_init(vport, lpfc_max_scsicmpl_time); 3626 3584 lpfc_fdmi_on_init(vport, lpfc_fdmi_on); 3627 3585 lpfc_discovery_threads_init(vport, lpfc_discovery_threads); 3628 3586 lpfc_max_luns_init(vport, lpfc_max_luns);
+3
drivers/scsi/lpfc/lpfc_disc.h
··· 88 88 unsigned long last_ramp_up_time; /* jiffy of last ramp up */ 89 89 unsigned long last_q_full_time; /* jiffy of last queue full */ 90 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 96 /* Defines for nlp_flag (uint32) */
+2
drivers/scsi/lpfc/lpfc_hbadisc.c
··· 2988 2988 INIT_LIST_HEAD(&ndlp->nlp_listp); 2989 2989 kref_init(&ndlp->kref); 2990 2990 NLP_INT_NODE_ACT(ndlp); 2991 + atomic_set(&ndlp->cmd_pending, 0); 2992 + ndlp->cmd_qdepth = LPFC_MAX_TGT_QDEPTH; 2991 2993 2992 2994 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE, 2993 2995 "node init: did:x%x",
+29
drivers/scsi/lpfc/lpfc_scsi.c
··· 628 628 629 629 lpfc_cmd->result = pIocbOut->iocb.un.ulpWord[4]; 630 630 lpfc_cmd->status = pIocbOut->iocb.ulpStatus; 631 + atomic_dec(&pnode->cmd_pending); 631 632 632 633 if (lpfc_cmd->status) { 633 634 if (lpfc_cmd->status == IOSTAT_LOCAL_REJECT && ··· 689 688 690 689 result = cmd->result; 691 690 sdev = cmd->device; 691 + if (vport->cfg_max_scsicmpl_time && 692 + time_after(jiffies, lpfc_cmd->start_time + 693 + msecs_to_jiffies(vport->cfg_max_scsicmpl_time))) { 694 + spin_lock_irqsave(sdev->host->host_lock, flags); 695 + if ((pnode->cmd_qdepth > atomic_read(&pnode->cmd_pending) && 696 + (atomic_read(&pnode->cmd_pending) > LPFC_MIN_TGT_QDEPTH) && 697 + ((cmd->cmnd[0] == READ_10) || (cmd->cmnd[0] == WRITE_10)))) 698 + pnode->cmd_qdepth = atomic_read(&pnode->cmd_pending); 699 + 700 + pnode->last_change_time = jiffies; 701 + spin_unlock_irqrestore(sdev->host->host_lock, flags); 702 + } else if ((pnode->cmd_qdepth < LPFC_MAX_TGT_QDEPTH) && 703 + time_after(jiffies, pnode->last_change_time + 704 + msecs_to_jiffies(LPFC_TGTQ_INTERVAL))) { 705 + spin_lock_irqsave(sdev->host->host_lock, flags); 706 + pnode->cmd_qdepth += pnode->cmd_qdepth * 707 + LPFC_TGTQ_RAMPUP_PCENT / 100; 708 + if (pnode->cmd_qdepth > LPFC_MAX_TGT_QDEPTH) 709 + pnode->cmd_qdepth = LPFC_MAX_TGT_QDEPTH; 710 + pnode->last_change_time = jiffies; 711 + spin_unlock_irqrestore(sdev->host->host_lock, flags); 712 + } 713 + 692 714 lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd); 693 715 cmd->scsi_done(cmd); 694 716 ··· 1099 1075 cmnd->result = ScsiResult(DID_TRANSPORT_DISRUPTED, 0); 1100 1076 goto out_fail_command; 1101 1077 } 1078 + if (atomic_read(&ndlp->cmd_pending) >= ndlp->cmd_qdepth) 1079 + goto out_host_busy; 1102 1080 1103 1081 lpfc_cmd = lpfc_get_scsi_buf(phba); 1104 1082 if (lpfc_cmd == NULL) { ··· 1119 1093 lpfc_cmd->pCmd = cmnd; 1120 1094 lpfc_cmd->rdata = rdata; 1121 1095 lpfc_cmd->timeout = 0; 1096 + lpfc_cmd->start_time = jiffies; 1122 1097 cmnd->host_scribble = (unsigned char *)lpfc_cmd; 1123 1098 cmnd->scsi_done = done; 1124 1099 ··· 1129 1102 1130 1103 lpfc_scsi_prep_cmnd(vport, lpfc_cmd, ndlp); 1131 1104 1105 + atomic_inc(&ndlp->cmd_pending); 1132 1106 err = lpfc_sli_issue_iocb(phba, &phba->sli.ring[psli->fcp_ring], 1133 1107 &lpfc_cmd->cur_iocbq, SLI_IOCB_RET_IOCB); 1134 1108 if (err) ··· 1144 1116 return 0; 1145 1117 1146 1118 out_host_busy_free_buf: 1119 + atomic_dec(&ndlp->cmd_pending); 1147 1120 lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd); 1148 1121 lpfc_release_scsi_buf(phba, lpfc_cmd); 1149 1122 out_host_busy:
+1
drivers/scsi/lpfc/lpfc_scsi.h
··· 139 139 */ 140 140 struct lpfc_iocbq cur_iocbq; 141 141 wait_queue_head_t *waitq; 142 + unsigned long start_time; 142 143 }; 143 144 144 145 #define LPFC_SCSI_DMA_EXT_SIZE 264