diff options
author | James Smart <james.smart@emulex.com> | 2012-08-03 20:36:52 +0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2012-09-14 17:44:39 +0400 |
commit | ba20c8536fa039ac3bfc32e0a0f0450134dee8c1 (patch) | |
tree | 0293b8915bce3638fc9095857bc230f76c6c80ee /drivers/scsi/lpfc/lpfc_sli.c | |
parent | 49aa143da98cac07f56096de0d099cb00ccd1582 (diff) | |
download | linux-ba20c8536fa039ac3bfc32e0a0f0450134dee8c1.tar.xz |
[SCSI] lpfc 8.3.33: Add lpfc_fcp_look_ahead module parameter
Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_sli.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.c | 88 |
1 files changed, 84 insertions, 4 deletions
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index d8dbe403c37e..b0fe153452aa 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -69,6 +69,8 @@ static int lpfc_sli4_fp_handle_wcqe(struct lpfc_hba *, struct lpfc_queue *, struct lpfc_cqe *); static int lpfc_sli4_post_els_sgl_list(struct lpfc_hba *, struct list_head *, int); +static void lpfc_sli4_hba_handle_eqe(struct lpfc_hba *, struct lpfc_eqe *, + uint32_t); static IOCB_t * lpfc_get_iocb_from_iocbq(struct lpfc_iocbq *iocbq) @@ -258,6 +260,25 @@ lpfc_sli4_eq_get(struct lpfc_queue *q) } /** + * lpfc_sli4_eq_clr_intr - Turn off interrupts from this EQ + * @q: The Event Queue to disable interrupts + * + **/ +static inline void +lpfc_sli4_eq_clr_intr(struct lpfc_queue *q) +{ + struct lpfc_register doorbell; + + doorbell.word0 = 0; + bf_set(lpfc_eqcq_doorbell_eqci, &doorbell, 1); + bf_set(lpfc_eqcq_doorbell_qt, &doorbell, LPFC_QUEUE_TYPE_EVENT); + bf_set(lpfc_eqcq_doorbell_eqid_hi, &doorbell, + (q->queue_id >> LPFC_EQID_HI_FIELD_SHIFT)); + bf_set(lpfc_eqcq_doorbell_eqid_lo, &doorbell, q->queue_id); + writel(doorbell.word0, q->phba->sli4_hba.EQCQDBregaddr); +} + +/** * lpfc_sli4_eq_release - Indicates the host has finished processing an EQ * @q: The Event Queue that the host has completed processing for. * @arm: Indicates whether the host wants to arms this CQ. @@ -8422,7 +8443,10 @@ int lpfc_sli_issue_iocb(struct lpfc_hba *phba, uint32_t ring_number, struct lpfc_iocbq *piocb, uint32_t flag) { + struct lpfc_fcp_eq_hdl *fcp_eq_hdl; struct lpfc_sli_ring *pring; + struct lpfc_queue *fpeq; + struct lpfc_eqe *eqe; unsigned long iflags; int rc, idx; @@ -8433,11 +8457,48 @@ lpfc_sli_issue_iocb(struct lpfc_hba *phba, uint32_t ring_number, idx = lpfc_sli4_scmd_to_wqidx_distr(phba); piocb->fcp_wqidx = idx; ring_number = MAX_SLI3_CONFIGURED_RINGS + idx; + + pring = &phba->sli.ring[ring_number]; + spin_lock_irqsave(&pring->ring_lock, iflags); + rc = __lpfc_sli_issue_iocb(phba, ring_number, piocb, + flag); + spin_unlock_irqrestore(&pring->ring_lock, iflags); + + if (lpfc_fcp_look_ahead) { + fcp_eq_hdl = &phba->sli4_hba.fcp_eq_hdl[idx]; + + if (atomic_dec_and_test(&fcp_eq_hdl-> + fcp_eq_in_use)) { + + /* Get associated EQ with this index */ + fpeq = phba->sli4_hba.hba_eq[idx]; + + /* Turn off interrupts from this EQ */ + lpfc_sli4_eq_clr_intr(fpeq); + + /* + * Process all the events on FCP EQ + */ + while ((eqe = lpfc_sli4_eq_get(fpeq))) { + lpfc_sli4_hba_handle_eqe(phba, + eqe, idx); + fpeq->EQ_processed++; + } + + /* Always clear and re-arm the EQ */ + lpfc_sli4_eq_release(fpeq, + LPFC_QUEUE_REARM); + } + atomic_inc(&fcp_eq_hdl->fcp_eq_in_use); + } + } else { + pring = &phba->sli.ring[ring_number]; + spin_lock_irqsave(&pring->ring_lock, iflags); + rc = __lpfc_sli_issue_iocb(phba, ring_number, piocb, + flag); + spin_unlock_irqrestore(&pring->ring_lock, iflags); + } - pring = &phba->sli.ring[ring_number]; - spin_lock_irqsave(&pring->ring_lock, iflags); - rc = __lpfc_sli_issue_iocb(phba, ring_number, piocb, flag); - spin_unlock_irqrestore(&pring->ring_lock, iflags); } else { /* For now, SLI2/3 will still use hbalock */ spin_lock_irqsave(&phba->hbalock, iflags); @@ -11854,6 +11915,15 @@ lpfc_sli4_hba_intr_handler(int irq, void *dev_id) if (unlikely(!fpeq)) return IRQ_NONE; + if (lpfc_fcp_look_ahead) { + if (atomic_dec_and_test(&fcp_eq_hdl->fcp_eq_in_use)) + lpfc_sli4_eq_clr_intr(fpeq); + else { + atomic_inc(&fcp_eq_hdl->fcp_eq_in_use); + return IRQ_NONE; + } + } + /* Check device state for handling interrupt */ if (unlikely(lpfc_intr_state_check(phba))) { fpeq->EQ_badstate++; @@ -11863,6 +11933,8 @@ lpfc_sli4_hba_intr_handler(int irq, void *dev_id) /* Flush, clear interrupt, and rearm the EQ */ lpfc_sli4_eq_flush(phba, fpeq); spin_unlock_irqrestore(&phba->hbalock, iflag); + if (lpfc_fcp_look_ahead) + atomic_inc(&fcp_eq_hdl->fcp_eq_in_use); return IRQ_NONE; } @@ -11885,6 +11957,12 @@ lpfc_sli4_hba_intr_handler(int irq, void *dev_id) if (unlikely(ecount == 0)) { fpeq->EQ_no_entry++; + + if (lpfc_fcp_look_ahead) { + atomic_inc(&fcp_eq_hdl->fcp_eq_in_use); + return IRQ_NONE; + } + if (phba->intr_type == MSIX) /* MSI-X treated interrupt served as no EQ share INT */ lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, @@ -11894,6 +11972,8 @@ lpfc_sli4_hba_intr_handler(int irq, void *dev_id) return IRQ_NONE; } + if (lpfc_fcp_look_ahead) + atomic_inc(&fcp_eq_hdl->fcp_eq_in_use); return IRQ_HANDLED; } /* lpfc_sli4_fp_intr_handler */ |