blob: db186da7ae6dc8999d24c43c98b074279254e092 [file] [log] [blame]
From be5e1a660fc1dc30b1c7c9921071b4b344bc020a Mon Sep 17 00:00:00 2001
From: James Smart <>
Date: Sat, 21 Sep 2019 20:58:53 -0700
Subject: [PATCH] scsi: lpfc: Fix locking on mailbox command completion
commit 07b8582430370097238b589f4e24da7613ca6dd3 upstream.
Symptoms were seen of the driver not having valid data for mailbox
commands. After debugging, the following sequence was found:
The driver maintains a port-wide pointer of the mailbox command that is
currently in execution. Once finished, the port-wide pointer is cleared
(done in lpfc_sli4_mq_release()). The next mailbox command issued will set
the next pointer and so on.
The mailbox response data is only copied if there is a valid port-wide
In the failing case, it was seen that a new mailbox command was being
attempted in parallel with the completion. The parallel path was seeing
the mailbox no long in use (flag check under lock) and thus set the port
pointer. The completion path had cleared the active flag under lock, but
had not touched the port pointer. The port pointer is cleared after the
lock is released. In this case, the completion path cleared the just-set
value by the parallel path.
Fix by making the calls that clear mbox state/port pointer while under
lock. Also slightly cleaned up the error path.
Signed-off-by: Dick Kennedy <>
Signed-off-by: James Smart <>
Signed-off-by: Martin K. Petersen <>
Signed-off-by: Paul Gortmaker <>
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index a1339f3f85f3..c4ae7658a4f3 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -13183,13 +13183,19 @@ lpfc_sli4_sp_handle_mbox_event(struct lpfc_hba *phba, struct lpfc_mcqe *mcqe)
phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
/* Setting active mailbox pointer need to be in sync to flag clear */
phba->sli.mbox_active = NULL;
+ if (bf_get(lpfc_trailer_consumed, mcqe))
+ lpfc_sli4_mq_release(phba->sli4_hba.mbx_wq);
spin_unlock_irqrestore(&phba->hbalock, iflags);
/* Wake up worker thread to post the next pending mailbox command */
+ return workposted;
+ spin_lock_irqsave(&phba->hbalock, iflags);
if (bf_get(lpfc_trailer_consumed, mcqe))
- return workposted;
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ return false;