]> Pileus Git - ~andy/linux/commitdiff
[SCSI] lpfc 8.3.43: Fixed invalid mailbox timeouts
authorJames Smart <james.smart@emulex.com>
Thu, 10 Oct 2013 16:21:30 +0000 (12:21 -0400)
committerJames Bottomley <JBottomley@Parallels.com>
Fri, 25 Oct 2013 08:58:17 +0000 (09:58 +0100)
Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
drivers/scsi/lpfc/lpfc_sli.c

index 5efe12e87a159653e3566c5daed11f6e232417a5..b48c5504f5739b11a2692aa903a364e4fd739704 100644 (file)
@@ -71,6 +71,8 @@ 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 bool lpfc_sli4_mbox_completions_pending(struct lpfc_hba *phba);
+static bool lpfc_sli4_process_missed_mbox_completions(struct lpfc_hba *phba);
 
 static IOCB_t *
 lpfc_get_iocb_from_iocbq(struct lpfc_iocbq *iocbq)
@@ -6566,6 +6568,108 @@ lpfc_mbox_timeout(unsigned long ptr)
        return;
 }
 
+/**
+ * lpfc_sli4_mbox_completions_pending - check to see if any mailbox completions
+ *                                    are pending
+ * @phba: Pointer to HBA context object.
+ *
+ * This function checks if any mailbox completions are present on the mailbox
+ * completion queue.
+ **/
+bool
+lpfc_sli4_mbox_completions_pending(struct lpfc_hba *phba)
+{
+
+       uint32_t idx;
+       struct lpfc_queue *mcq;
+       struct lpfc_mcqe *mcqe;
+       bool pending_completions = false;
+
+       if (unlikely(!phba) || (phba->sli_rev != LPFC_SLI_REV4))
+               return false;
+
+       /* Check for completions on mailbox completion queue */
+
+       mcq = phba->sli4_hba.mbx_cq;
+       idx = mcq->hba_index;
+       while (bf_get_le32(lpfc_cqe_valid, mcq->qe[idx].cqe)) {
+               mcqe = (struct lpfc_mcqe *)mcq->qe[idx].cqe;
+               if (bf_get_le32(lpfc_trailer_completed, mcqe) &&
+                   (!bf_get_le32(lpfc_trailer_async, mcqe))) {
+                       pending_completions = true;
+                       break;
+               }
+               idx = (idx + 1) % mcq->entry_count;
+               if (mcq->hba_index == idx)
+                       break;
+       }
+       return pending_completions;
+
+}
+
+/**
+ * lpfc_sli4_process_missed_mbox_completions - process mbox completions
+ *                                           that were missed.
+ * @phba: Pointer to HBA context object.
+ *
+ * For sli4, it is possible to miss an interrupt. As such mbox completions
+ * maybe missed causing erroneous mailbox timeouts to occur. This function
+ * checks to see if mbox completions are on the mailbox completion queue
+ * and will process all the completions associated with the eq for the
+ * mailbox completion queue.
+ **/
+bool
+lpfc_sli4_process_missed_mbox_completions(struct lpfc_hba *phba)
+{
+
+       uint32_t eqidx;
+       struct lpfc_queue *fpeq = NULL;
+       struct lpfc_eqe *eqe;
+       bool mbox_pending;
+
+       if (unlikely(!phba) || (phba->sli_rev != LPFC_SLI_REV4))
+               return false;
+
+       /* Find the eq associated with the mcq */
+
+       if (phba->sli4_hba.hba_eq)
+               for (eqidx = 0; eqidx < phba->cfg_fcp_io_channel; eqidx++)
+                       if (phba->sli4_hba.hba_eq[eqidx]->queue_id ==
+                           phba->sli4_hba.mbx_cq->assoc_qid) {
+                               fpeq = phba->sli4_hba.hba_eq[eqidx];
+                               break;
+                       }
+       if (!fpeq)
+               return false;
+
+       /* Turn off interrupts from this EQ */
+
+       lpfc_sli4_eq_clr_intr(fpeq);
+
+       /* Check to see if a mbox completion is pending */
+
+       mbox_pending = lpfc_sli4_mbox_completions_pending(phba);
+
+       /*
+        * If a mbox completion is pending, process all the events on EQ
+        * associated with the mbox completion queue (this could include
+        * mailbox commands, async events, els commands, receive queue data
+        * and fcp commands)
+        */
+
+       if (mbox_pending)
+               while ((eqe = lpfc_sli4_eq_get(fpeq))) {
+                       lpfc_sli4_hba_handle_eqe(phba, eqe, eqidx);
+                       fpeq->EQ_processed++;
+               }
+
+       /* Always clear and re-arm the EQ */
+
+       lpfc_sli4_eq_release(fpeq, LPFC_QUEUE_REARM);
+
+       return mbox_pending;
+
+}
 
 /**
  * lpfc_mbox_timeout_handler - Worker thread function to handle mailbox timeout
@@ -6583,6 +6687,10 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba)
        struct lpfc_sli *psli = &phba->sli;
        struct lpfc_sli_ring *pring;
 
+       /* If the mailbox completed, process the completion and return */
+       if (lpfc_sli4_process_missed_mbox_completions(phba))
+               return;
+
        /* Check the pmbox pointer first.  There is a race condition
         * between the mbox timeout handler getting executed in the
         * worklist and the mailbox actually completing. When this
@@ -7077,6 +7185,10 @@ lpfc_sli4_async_mbox_block(struct lpfc_hba *phba)
                                                1000) + jiffies;
        spin_unlock_irq(&phba->hbalock);
 
+       /* Make sure the mailbox is really active */
+       if (timeout)
+               lpfc_sli4_process_missed_mbox_completions(phba);
+
        /* Wait for the outstnading mailbox command to complete */
        while (phba->sli.mbox_active) {
                /* Check active mailbox complete status every 2ms */