aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/lpfc/lpfc_scsi.c
diff options
context:
space:
mode:
authorJames.Smart@Emulex.Com <James.Smart@Emulex.Com>2005-11-29 16:32:13 -0500
committerJames Bottomley <jejb@mulgrave.(none)>2005-12-13 20:34:14 -0500
commit875fbdfe9b1b4c8f12622a8d8d81428ff0984875 (patch)
tree63c787cb9a7d4a92eaedcc9f8a89a00d5d8f6603 /drivers/scsi/lpfc/lpfc_scsi.c
parent5cc36b3cd0e3610ad7c7e2514160998276798fc0 (diff)
[SCSI] lpfc 8.1.1 : Add polled-mode support
- Add functionality to run in polled mode only. Includes run time attribute to enable mode. - Enable runtime writable hba settings for coallescing and delay parameters Customers have requested a mode in the driver to run strictly polled. This is generally to support an environment where the server is extremely loaded and is looking to reclaim some cpu cycles from adapter interrupt handling. This patch adds a new "poll" attribute, and the following behavior: if value is 0 (default): The driver uses the normal method for i/o completion. It uses the firmware feature of interrupt coalesing. The firmware allows a minimum number of i/o completions before an interrupt, or a maximum time delay between interrupts. By default, the driver sets these to no delay (disabled) or 1 i/o - meaning coalescing is disabled. Attributes were provided to change the coalescing values, but it was a module-load time only and global across all adapters. This patch allows them to be writable on a per-adapter basis. if value is 1 : Interrupts are left enabled, expecting that the user has tuned the interrupt coalescing values. When this setting is enabled, the driver will attempt to service completed i/o whenever new i/o is submitted to the adapter. If the coalescing values are large, and the i/o generation rate steady, an interrupt will be avoided by servicing completed i/o prior to the coalescing thresholds kicking in. However, if the i/o completion load is high enough or i/o generation slow, the coalescion values will ensure that completed i/o is serviced in a timely fashion. if value is 3 : Turns off FCP i/o interrupts altogether. The coalescing values now have no effect. A new attribute "poll_tmo" (default 10ms) exists to set the polling interval for i/o completion. When this setting is enabled, the driver will attempt to service completed i/o and restart the interval timer whenever new i/o is submitted. This behavior allows for servicing of completed i/o sooner than the interval timer, but ensures that if no i/o is being issued, then the interval timer will kick in to service the outstanding i/o. Signed-off-by: James Smart <James.Smart@emulex.com> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_scsi.c')
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c72
1 files changed, 62 insertions, 10 deletions
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index 7dc7810b7482..c422220db0ae 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -151,18 +151,22 @@ lpfc_new_scsi_buf(struct lpfc_hba * phba)
151} 151}
152 152
153struct lpfc_scsi_buf* 153struct lpfc_scsi_buf*
154lpfc_sli_get_scsi_buf(struct lpfc_hba * phba) 154lpfc_get_scsi_buf(struct lpfc_hba * phba)
155{ 155{
156 struct lpfc_scsi_buf * lpfc_cmd = NULL; 156 struct lpfc_scsi_buf * lpfc_cmd = NULL;
157 struct list_head *scsi_buf_list = &phba->lpfc_scsi_buf_list; 157 struct list_head *scsi_buf_list = &phba->lpfc_scsi_buf_list;
158 unsigned long iflag = 0;
158 159
160 spin_lock_irqsave(&phba->scsi_buf_list_lock, iflag);
159 list_remove_head(scsi_buf_list, lpfc_cmd, struct lpfc_scsi_buf, list); 161 list_remove_head(scsi_buf_list, lpfc_cmd, struct lpfc_scsi_buf, list);
162 spin_unlock_irqrestore(&phba->scsi_buf_list_lock, iflag);
160 return lpfc_cmd; 163 return lpfc_cmd;
161} 164}
162 165
163static void 166static void
164lpfc_release_scsi_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * psb) 167lpfc_release_scsi_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * psb)
165{ 168{
169 unsigned long iflag = 0;
166 /* 170 /*
167 * There are only two special cases to consider. (1) the scsi command 171 * There are only two special cases to consider. (1) the scsi command
168 * requested scatter-gather usage or (2) the scsi command allocated 172 * requested scatter-gather usage or (2) the scsi command allocated
@@ -180,8 +184,10 @@ lpfc_release_scsi_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * psb)
180 } 184 }
181 } 185 }
182 186
187 spin_lock_irqsave(&phba->scsi_buf_list_lock, iflag);
183 psb->pCmd = NULL; 188 psb->pCmd = NULL;
184 list_add_tail(&psb->list, &phba->lpfc_scsi_buf_list); 189 list_add_tail(&psb->list, &phba->lpfc_scsi_buf_list);
190 spin_unlock_irqrestore(&phba->scsi_buf_list_lock, iflag);
185} 191}
186 192
187static int 193static int
@@ -403,7 +409,6 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
403 struct lpfc_rport_data *rdata = lpfc_cmd->rdata; 409 struct lpfc_rport_data *rdata = lpfc_cmd->rdata;
404 struct lpfc_nodelist *pnode = rdata->pnode; 410 struct lpfc_nodelist *pnode = rdata->pnode;
405 struct scsi_cmnd *cmd = lpfc_cmd->pCmd; 411 struct scsi_cmnd *cmd = lpfc_cmd->pCmd;
406 unsigned long iflag;
407 412
408 lpfc_cmd->result = pIocbOut->iocb.un.ulpWord[4]; 413 lpfc_cmd->result = pIocbOut->iocb.un.ulpWord[4];
409 lpfc_cmd->status = pIocbOut->iocb.ulpStatus; 414 lpfc_cmd->status = pIocbOut->iocb.ulpStatus;
@@ -457,9 +462,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
457 462
458 cmd->scsi_done(cmd); 463 cmd->scsi_done(cmd);
459 464
460 spin_lock_irqsave(phba->host->host_lock, iflag);
461 lpfc_release_scsi_buf(phba, lpfc_cmd); 465 lpfc_release_scsi_buf(phba, lpfc_cmd);
462 spin_unlock_irqrestore(phba->host->host_lock, iflag);
463} 466}
464 467
465static void 468static void
@@ -707,6 +710,37 @@ lpfc_info(struct Scsi_Host *host)
707 return lpfcinfobuf; 710 return lpfcinfobuf;
708} 711}
709 712
713static __inline__ void lpfc_poll_rearm_timer(struct lpfc_hba * phba)
714{
715 unsigned long poll_tmo_expires =
716 (jiffies + msecs_to_jiffies(phba->cfg_poll_tmo));
717
718 if (phba->sli.ring[LPFC_FCP_RING].txcmplq_cnt)
719 mod_timer(&phba->fcp_poll_timer,
720 poll_tmo_expires);
721}
722
723void lpfc_poll_start_timer(struct lpfc_hba * phba)
724{
725 lpfc_poll_rearm_timer(phba);
726}
727
728void lpfc_poll_timeout(unsigned long ptr)
729{
730 struct lpfc_hba *phba = (struct lpfc_hba *)ptr;
731 unsigned long iflag;
732
733 spin_lock_irqsave(phba->host->host_lock, iflag);
734
735 if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) {
736 lpfc_sli_poll_fcp_ring (phba);
737 if (phba->cfg_poll & DISABLE_FCP_RING_INT)
738 lpfc_poll_rearm_timer(phba);
739 }
740
741 spin_unlock_irqrestore(phba->host->host_lock, iflag);
742}
743
710static int 744static int
711lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) 745lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
712{ 746{
@@ -733,7 +767,7 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
733 cmnd->result = ScsiResult(DID_BUS_BUSY, 0); 767 cmnd->result = ScsiResult(DID_BUS_BUSY, 0);
734 goto out_fail_command; 768 goto out_fail_command;
735 } 769 }
736 lpfc_cmd = lpfc_sli_get_scsi_buf (phba); 770 lpfc_cmd = lpfc_get_scsi_buf (phba);
737 if (lpfc_cmd == NULL) { 771 if (lpfc_cmd == NULL) {
738 lpfc_printf_log(phba, KERN_INFO, LOG_FCP, 772 lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
739 "%d:0707 driver's buffer pool is empty, " 773 "%d:0707 driver's buffer pool is empty, "
@@ -761,11 +795,17 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
761 &lpfc_cmd->cur_iocbq, SLI_IOCB_RET_IOCB); 795 &lpfc_cmd->cur_iocbq, SLI_IOCB_RET_IOCB);
762 if (err) 796 if (err)
763 goto out_host_busy_free_buf; 797 goto out_host_busy_free_buf;
798
799 if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) {
800 lpfc_sli_poll_fcp_ring(phba);
801 if (phba->cfg_poll & DISABLE_FCP_RING_INT)
802 lpfc_poll_rearm_timer(phba);
803 }
804
764 return 0; 805 return 0;
765 806
766 out_host_busy_free_buf: 807 out_host_busy_free_buf:
767 lpfc_release_scsi_buf(phba, lpfc_cmd); 808 lpfc_release_scsi_buf(phba, lpfc_cmd);
768 cmnd->host_scribble = NULL;
769 out_host_busy: 809 out_host_busy:
770 return SCSI_MLQUEUE_HOST_BUSY; 810 return SCSI_MLQUEUE_HOST_BUSY;
771 811
@@ -839,9 +879,15 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
839 goto out; 879 goto out;
840 } 880 }
841 881
882 if (phba->cfg_poll & DISABLE_FCP_RING_INT)
883 lpfc_sli_poll_fcp_ring (phba);
884
842 /* Wait for abort to complete */ 885 /* Wait for abort to complete */
843 while (lpfc_cmd->pCmd == cmnd) 886 while (lpfc_cmd->pCmd == cmnd)
844 { 887 {
888 if (phba->cfg_poll & DISABLE_FCP_RING_INT)
889 lpfc_sli_poll_fcp_ring (phba);
890
845 spin_unlock_irq(phba->host->host_lock); 891 spin_unlock_irq(phba->host->host_lock);
846 schedule_timeout_uninterruptible(LPFC_ABORT_WAIT*HZ); 892 schedule_timeout_uninterruptible(LPFC_ABORT_WAIT*HZ);
847 spin_lock_irq(phba->host->host_lock); 893 spin_lock_irq(phba->host->host_lock);
@@ -905,7 +951,7 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
905 break; 951 break;
906 } 952 }
907 953
908 lpfc_cmd = lpfc_sli_get_scsi_buf (phba); 954 lpfc_cmd = lpfc_get_scsi_buf (phba);
909 if (lpfc_cmd == NULL) 955 if (lpfc_cmd == NULL)
910 goto out; 956 goto out;
911 957
@@ -1001,7 +1047,7 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd)
1001 lpfc_block_requests(phba); 1047 lpfc_block_requests(phba);
1002 spin_lock_irq(shost->host_lock); 1048 spin_lock_irq(shost->host_lock);
1003 1049
1004 lpfc_cmd = lpfc_sli_get_scsi_buf (phba); 1050 lpfc_cmd = lpfc_get_scsi_buf(phba);
1005 if (lpfc_cmd == NULL) 1051 if (lpfc_cmd == NULL)
1006 goto out; 1052 goto out;
1007 1053
@@ -1136,10 +1182,10 @@ lpfc_slave_alloc(struct scsi_device *sdev)
1136 break; 1182 break;
1137 } 1183 }
1138 1184
1139 spin_lock_irqsave(phba->host->host_lock, flags); 1185 spin_lock_irqsave(&phba->scsi_buf_list_lock, flags);
1140 phba->total_scsi_bufs++; 1186 phba->total_scsi_bufs++;
1141 list_add_tail(&scsi_buf->list, &phba->lpfc_scsi_buf_list); 1187 list_add_tail(&scsi_buf->list, &phba->lpfc_scsi_buf_list);
1142 spin_unlock_irqrestore(phba->host->host_lock, flags); 1188 spin_unlock_irqrestore(&phba->scsi_buf_list_lock, flags);
1143 } 1189 }
1144 return 0; 1190 return 0;
1145} 1191}
@@ -1163,6 +1209,12 @@ lpfc_slave_configure(struct scsi_device *sdev)
1163 */ 1209 */
1164 rport->dev_loss_tmo = phba->cfg_nodev_tmo + 5; 1210 rport->dev_loss_tmo = phba->cfg_nodev_tmo + 5;
1165 1211
1212 if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) {
1213 lpfc_sli_poll_fcp_ring(phba);
1214 if (phba->cfg_poll & DISABLE_FCP_RING_INT)
1215 lpfc_poll_rearm_timer(phba);
1216 }
1217
1166 return 0; 1218 return 0;
1167} 1219}
1168 1220