Daniel Wagner cc5f26
From: James Smart <jsmart2021@gmail.com>
Daniel Wagner cc5f26
Date: Fri, 3 Dec 2021 16:26:40 -0800
Daniel Wagner cc5f26
Subject: scsi: lpfc: Trigger SLI4 firmware dump before doing driver cleanup
Daniel Wagner cc5f26
Patch-mainline: Queued in subsystem maintainer repository
Daniel Wagner cc5f26
Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi.git
Daniel Wagner cc5f26
Git-commit: 7dd2e2a923173d637c272e483966be8e96a72b64
Daniel Wagner cc5f26
References: bsc1192145
Daniel Wagner cc5f26
Daniel Wagner cc5f26
Extraneous teardown routines are present in the firmware dump path causing
Daniel Wagner cc5f26
altered states in firmware captures.
Daniel Wagner cc5f26
Daniel Wagner cc5f26
When a firmware dump is requested via sysfs, trigger the dump immediately
Daniel Wagner cc5f26
without tearing down structures and changing adapter state.
Daniel Wagner cc5f26
Daniel Wagner cc5f26
The driver shall rely on pre-existing firmware error state clean up
Daniel Wagner cc5f26
handlers to restore the adapter.
Daniel Wagner cc5f26
Daniel Wagner cc5f26
Link: https://lore.kernel.org/r/20211204002644.116455-6-jsmart2021@gmail.com
Daniel Wagner cc5f26
Co-developed-by: Justin Tee <justin.tee@broadcom.com>
Daniel Wagner cc5f26
Signed-off-by: Justin Tee <justin.tee@broadcom.com>
Daniel Wagner cc5f26
Signed-off-by: James Smart <jsmart2021@gmail.com>
Daniel Wagner cc5f26
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Daniel Wagner cc5f26
Acked-by: Daniel Wagner <dwagner@suse.de>
Daniel Wagner cc5f26
---
Daniel Wagner cc5f26
 drivers/scsi/lpfc/lpfc.h         |    2 -
Daniel Wagner cc5f26
 drivers/scsi/lpfc/lpfc_attr.c    |   62 +++++++++++++++++++++++++--------------
Daniel Wagner cc5f26
 drivers/scsi/lpfc/lpfc_hbadisc.c |    8 ++++-
Daniel Wagner cc5f26
 drivers/scsi/lpfc/lpfc_sli.c     |    6 ---
Daniel Wagner cc5f26
 4 files changed, 48 insertions(+), 30 deletions(-)
Daniel Wagner cc5f26
Daniel Wagner cc5f26
--- a/drivers/scsi/lpfc/lpfc.h
Daniel Wagner cc5f26
+++ b/drivers/scsi/lpfc/lpfc.h
Daniel Wagner cc5f26
@@ -930,7 +930,6 @@ struct lpfc_hba {
Daniel Wagner cc5f26
 #define HBA_DEVLOSS_TMO         0x2000 /* HBA in devloss timeout */
Daniel Wagner cc5f26
 #define HBA_RRQ_ACTIVE		0x4000 /* process the rrq active list */
Daniel Wagner cc5f26
 #define HBA_IOQ_FLUSH		0x8000 /* FCP/NVME I/O queues being flushed */
Daniel Wagner cc5f26
-#define HBA_FW_DUMP_OP		0x10000 /* Skips fn reset before FW dump */
Daniel Wagner cc5f26
 #define HBA_RECOVERABLE_UE	0x20000 /* Firmware supports recoverable UE */
Daniel Wagner cc5f26
 #define HBA_FORCED_LINK_SPEED	0x40000 /*
Daniel Wagner cc5f26
 					 * Firmware supports Forced Link Speed
Daniel Wagner cc5f26
@@ -947,6 +946,7 @@ struct lpfc_hba {
Daniel Wagner cc5f26
 #define HBA_HBEAT_TMO		0x8000000 /* HBEAT initiated after timeout */
Daniel Wagner cc5f26
 #define HBA_FLOGI_OUTSTANDING	0x10000000 /* FLOGI is outstanding */
Daniel Wagner cc5f26
 
Daniel Wagner cc5f26
+	struct completion *fw_dump_cmpl; /* cmpl event tracker for fw_dump */
Daniel Wagner cc5f26
 	uint32_t fcp_ring_in_use; /* When polling test if intr-hndlr active*/
Daniel Wagner cc5f26
 	struct lpfc_dmabuf slim2p;
Daniel Wagner cc5f26
 
Daniel Wagner cc5f26
--- a/drivers/scsi/lpfc/lpfc_attr.c
Daniel Wagner cc5f26
+++ b/drivers/scsi/lpfc/lpfc_attr.c
Daniel Wagner cc5f26
@@ -1712,25 +1712,25 @@ lpfc_sli4_pdev_reg_request(struct lpfc_h
Daniel Wagner cc5f26
 	before_fc_flag = phba->pport->fc_flag;
Daniel Wagner cc5f26
 	sriov_nr_virtfn = phba->cfg_sriov_nr_virtfn;
Daniel Wagner cc5f26
 
Daniel Wagner cc5f26
-	/* Disable SR-IOV virtual functions if enabled */
Daniel Wagner cc5f26
-	if (phba->cfg_sriov_nr_virtfn) {
Daniel Wagner cc5f26
-		pci_disable_sriov(pdev);
Daniel Wagner cc5f26
-		phba->cfg_sriov_nr_virtfn = 0;
Daniel Wagner cc5f26
-	}
Daniel Wagner cc5f26
+	if (opcode == LPFC_FW_DUMP) {
Daniel Wagner cc5f26
+		init_completion(&online_compl);
Daniel Wagner cc5f26
+		phba->fw_dump_cmpl = &online_compl;
Daniel Wagner cc5f26
+	} else {
Daniel Wagner cc5f26
+		/* Disable SR-IOV virtual functions if enabled */
Daniel Wagner cc5f26
+		if (phba->cfg_sriov_nr_virtfn) {
Daniel Wagner cc5f26
+			pci_disable_sriov(pdev);
Daniel Wagner cc5f26
+			phba->cfg_sriov_nr_virtfn = 0;
Daniel Wagner cc5f26
+		}
Daniel Wagner cc5f26
 
Daniel Wagner cc5f26
-	if (opcode == LPFC_FW_DUMP)
Daniel Wagner cc5f26
-		phba->hba_flag |= HBA_FW_DUMP_OP;
Daniel Wagner cc5f26
+		status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);
Daniel Wagner cc5f26
 
Daniel Wagner cc5f26
-	status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);
Daniel Wagner cc5f26
+		if (status != 0)
Daniel Wagner cc5f26
+			return status;
Daniel Wagner cc5f26
 
Daniel Wagner cc5f26
-	if (status != 0) {
Daniel Wagner cc5f26
-		phba->hba_flag &= ~HBA_FW_DUMP_OP;
Daniel Wagner cc5f26
-		return status;
Daniel Wagner cc5f26
+		/* wait for the device to be quiesced before firmware reset */
Daniel Wagner cc5f26
+		msleep(100);
Daniel Wagner cc5f26
 	}
Daniel Wagner cc5f26
 
Daniel Wagner cc5f26
-	/* wait for the device to be quiesced before firmware reset */
Daniel Wagner cc5f26
-	msleep(100);
Daniel Wagner cc5f26
-
Daniel Wagner cc5f26
 	reg_val = readl(phba->sli4_hba.conf_regs_memmap_p +
Daniel Wagner cc5f26
 			LPFC_CTL_PDEV_CTL_OFFSET);
Daniel Wagner cc5f26
 
Daniel Wagner cc5f26
@@ -1759,24 +1759,42 @@ lpfc_sli4_pdev_reg_request(struct lpfc_h
Daniel Wagner cc5f26
 		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
Daniel Wagner cc5f26
 				"3153 Fail to perform the requested "
Daniel Wagner cc5f26
 				"access: x%x\n", reg_val);
Daniel Wagner cc5f26
+		if (phba->fw_dump_cmpl)
Daniel Wagner cc5f26
+			phba->fw_dump_cmpl = NULL;
Daniel Wagner cc5f26
 		return rc;
Daniel Wagner cc5f26
 	}
Daniel Wagner cc5f26
 
Daniel Wagner cc5f26
 	/* keep the original port state */
Daniel Wagner cc5f26
-	if (before_fc_flag & FC_OFFLINE_MODE)
Daniel Wagner cc5f26
-		goto out;
Daniel Wagner cc5f26
-
Daniel Wagner cc5f26
-	init_completion(&online_compl);
Daniel Wagner cc5f26
-	job_posted = lpfc_workq_post_event(phba, &status, &online_compl,
Daniel Wagner cc5f26
-					   LPFC_EVT_ONLINE);
Daniel Wagner cc5f26
-	if (!job_posted)
Daniel Wagner cc5f26
+	if (before_fc_flag & FC_OFFLINE_MODE) {
Daniel Wagner cc5f26
+		if (phba->fw_dump_cmpl)
Daniel Wagner cc5f26
+			phba->fw_dump_cmpl = NULL;
Daniel Wagner cc5f26
 		goto out;
Daniel Wagner cc5f26
+	}
Daniel Wagner cc5f26
 
Daniel Wagner cc5f26
-	wait_for_completion(&online_compl);
Daniel Wagner cc5f26
+	/* Firmware dump will trigger an HA_ERATT event, and
Daniel Wagner cc5f26
+	 * lpfc_handle_eratt_s4 routine already handles bringing the port back
Daniel Wagner cc5f26
+	 * online.
Daniel Wagner cc5f26
+	 */
Daniel Wagner cc5f26
+	if (opcode == LPFC_FW_DUMP) {
Daniel Wagner cc5f26
+		wait_for_completion(phba->fw_dump_cmpl);
Daniel Wagner cc5f26
+	} else  {
Daniel Wagner cc5f26
+		init_completion(&online_compl);
Daniel Wagner cc5f26
+		job_posted = lpfc_workq_post_event(phba, &status, &online_compl,
Daniel Wagner cc5f26
+						   LPFC_EVT_ONLINE);
Daniel Wagner cc5f26
+		if (!job_posted)
Daniel Wagner cc5f26
+			goto out;
Daniel Wagner cc5f26
 
Daniel Wagner cc5f26
+		wait_for_completion(&online_compl);
Daniel Wagner cc5f26
+	}
Daniel Wagner cc5f26
 out:
Daniel Wagner cc5f26
 	/* in any case, restore the virtual functions enabled as before */
Daniel Wagner cc5f26
 	if (sriov_nr_virtfn) {
Daniel Wagner cc5f26
+		/* If fw_dump was performed, first disable to clean up */
Daniel Wagner cc5f26
+		if (opcode == LPFC_FW_DUMP) {
Daniel Wagner cc5f26
+			pci_disable_sriov(pdev);
Daniel Wagner cc5f26
+			phba->cfg_sriov_nr_virtfn = 0;
Daniel Wagner cc5f26
+		}
Daniel Wagner cc5f26
+
Daniel Wagner cc5f26
 		sriov_err =
Daniel Wagner cc5f26
 			lpfc_sli_probe_sriov_nr_virtfn(phba, sriov_nr_virtfn);
Daniel Wagner cc5f26
 		if (!sriov_err)
Daniel Wagner cc5f26
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
Daniel Wagner cc5f26
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
Daniel Wagner cc5f26
@@ -739,10 +739,16 @@ lpfc_work_done(struct lpfc_hba *phba)
Daniel Wagner cc5f26
 	if (phba->pci_dev_grp == LPFC_PCI_DEV_OC)
Daniel Wagner cc5f26
 		lpfc_sli4_post_async_mbox(phba);
Daniel Wagner cc5f26
 
Daniel Wagner cc5f26
-	if (ha_copy & HA_ERATT)
Daniel Wagner cc5f26
+	if (ha_copy & HA_ERATT) {
Daniel Wagner cc5f26
 		/* Handle the error attention event */
Daniel Wagner cc5f26
 		lpfc_handle_eratt(phba);
Daniel Wagner cc5f26
 
Daniel Wagner cc5f26
+		if (phba->fw_dump_cmpl) {
Daniel Wagner cc5f26
+			complete(phba->fw_dump_cmpl);
Daniel Wagner cc5f26
+			phba->fw_dump_cmpl = NULL;
Daniel Wagner cc5f26
+		}
Daniel Wagner cc5f26
+	}
Daniel Wagner cc5f26
+
Daniel Wagner cc5f26
 	if (ha_copy & HA_MBATT)
Daniel Wagner cc5f26
 		lpfc_sli_handle_mb_event(phba);
Daniel Wagner cc5f26
 
Daniel Wagner cc5f26
--- a/drivers/scsi/lpfc/lpfc_sli.c
Daniel Wagner cc5f26
+++ b/drivers/scsi/lpfc/lpfc_sli.c
Daniel Wagner cc5f26
@@ -4911,12 +4911,6 @@ lpfc_sli4_brdreset(struct lpfc_hba *phba
Daniel Wagner cc5f26
 	phba->fcf.fcf_flag = 0;
Daniel Wagner cc5f26
 	spin_unlock_irq(&phba->hbalock);
Daniel Wagner cc5f26
 
Daniel Wagner cc5f26
-	/* SLI4 INTF 2: if FW dump is being taken skip INIT_PORT */
Daniel Wagner cc5f26
-	if (phba->hba_flag & HBA_FW_DUMP_OP) {
Daniel Wagner cc5f26
-		phba->hba_flag &= ~HBA_FW_DUMP_OP;
Daniel Wagner cc5f26
-		return rc;
Daniel Wagner cc5f26
-	}
Daniel Wagner cc5f26
-
Daniel Wagner cc5f26
 	/* Now physically reset the device */
Daniel Wagner cc5f26
 	lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
Daniel Wagner cc5f26
 			"0389 Performing PCI function reset!\n");