[SCSI] lpfc 8.3.33: Add lpfc_fcp_look_ahead module parameter
authorJames Smart <james.smart@emulex.com>
Fri, 3 Aug 2012 16:36:52 +0000 (12:36 -0400)
committerJames Bottomley <JBottomley@Parallels.com>
Fri, 14 Sep 2012 13:44:39 +0000 (14:44 +0100)
Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
drivers/scsi/lpfc/lpfc.h
drivers/scsi/lpfc/lpfc_attr.c
drivers/scsi/lpfc/lpfc_crtn.h
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_sli.c
drivers/scsi/lpfc/lpfc_sli4.h

index 26bcbfb2a18b264476a321289bd99629e538cf10..a184c2443a6401132f2c7edb1614f29e75ad3b90 100644 (file)
@@ -73,6 +73,8 @@ struct lpfc_sli2_slim;
 #define LPFC_HB_MBOX_INTERVAL   5      /* Heart beat interval in seconds. */
 #define LPFC_HB_MBOX_TIMEOUT    30     /* Heart beat timeout  in seconds. */
 
+#define LPFC_LOOK_AHEAD_OFF    0       /* Look ahead logic is turned off */
+
 /* Error Attention event polling interval */
 #define LPFC_ERATT_POLL_INTERVAL       5 /* EATT poll interval in seconds */
 
index 2ab2b9f2bff5d8a3af70ab1a74024e0e0582d8a8..b032562aa0d9d32217487a3f7fb0a840c5e5580e 100644 (file)
@@ -3917,6 +3917,17 @@ LPFC_ATTR_R(enable_hba_heartbeat, 0, 0, 1, "Enable HBA Heartbeat.");
 */
 LPFC_ATTR_R(enable_bg, 0, 0, 1, "Enable BlockGuard Support");
 
+/*
+# lpfc_fcp_look_ahead: Look ahead for completions in FCP start routine
+#       0  = disabled (default)
+#       1  = enabled
+# Value range is [0,1]. Default value is 0.
+*/
+unsigned int lpfc_fcp_look_ahead = LPFC_LOOK_AHEAD_OFF;
+
+module_param(lpfc_fcp_look_ahead, uint, S_IRUGO);
+MODULE_PARM_DESC(lpfc_fcp_look_ahead, "Look ahead for completions");
+
 /*
 # lpfc_prot_mask: i
 #      - Bit mask of host protection capabilities used to register with the
index 08e3a9b60e45d70331455baf0e069d6877ef6df7..10429149f785bcc9d9df25572d3f0d1849ad71c0 100644 (file)
@@ -390,6 +390,7 @@ extern spinlock_t pgcnt_lock;
 extern unsigned int pgcnt;
 extern unsigned int lpfc_prot_mask;
 extern unsigned char lpfc_prot_guard;
+extern unsigned int lpfc_fcp_look_ahead;
 
 /* Interface exported by fabric iocb scheduler */
 void lpfc_fabric_abort_nport(struct lpfc_nodelist *);
index 538124b39767c35251a7a2e782f5b2b369215af1..cb2749a67c69b29dac2c14f1a92a659cd4cba053 100644 (file)
@@ -8111,6 +8111,7 @@ enable_msix_vectors:
 
                phba->sli4_hba.fcp_eq_hdl[index].idx = index;
                phba->sli4_hba.fcp_eq_hdl[index].phba = phba;
+               atomic_set(&phba->sli4_hba.fcp_eq_hdl[index].fcp_eq_in_use, 1);
                rc = request_irq(phba->sli4_hba.msix_entries[index].vector,
                                 &lpfc_sli4_hba_intr_handler, IRQF_SHARED,
                                 (char *)&phba->sli4_hba.handler_name[index],
@@ -8283,6 +8284,8 @@ lpfc_sli4_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode)
                             index++) {
                                phba->sli4_hba.fcp_eq_hdl[index].idx = index;
                                phba->sli4_hba.fcp_eq_hdl[index].phba = phba;
+                               atomic_set(&phba->sli4_hba.fcp_eq_hdl[index].
+                                       fcp_eq_in_use, 1);
                        }
                }
        }
index d8dbe403c37e6a2998baa92a82ff1b9d189c116c..b0fe153452aa38f8adf95c74c25824f6bec6e459 100644 (file)
@@ -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)
@@ -257,6 +259,25 @@ lpfc_sli4_eq_get(struct lpfc_queue *q)
        return eqe;
 }
 
+/**
+ * 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.
@@ -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 */
 
index c806e66be55b6edb6e3266ff26e8d9a866d03e57..bd4bc4342ae227b43824277985d1103b70a17695 100644 (file)
@@ -373,6 +373,7 @@ struct lpfc_hba;
 struct lpfc_fcp_eq_hdl {
        uint32_t idx;
        struct lpfc_hba *phba;
+       atomic_t fcp_eq_in_use;
 };
 
 /* Port Capabilities for SLI4 Parameters */