|
@@ -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 */
|