summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/lpfc/lpfc_ct.c
diff options
context:
space:
mode:
authorJames Smart <jsmart2021@gmail.com>2022-05-05 20:55:16 -0700
committerMartin K. Petersen <martin.petersen@oracle.com>2022-05-10 22:12:04 -0400
commitde3ec318fee32313092b609f88475f86e58f3fe5 (patch)
treeec9648e157e73392670f24f0164f30f4645fdd70 /drivers/scsi/lpfc/lpfc_ct.c
parent5099478e436f0acd8c76495590c105668f2d8afc (diff)
downloadlinux-stable-de3ec318fee32313092b609f88475f86e58f3fe5.tar.gz
linux-stable-de3ec318fee32313092b609f88475f86e58f3fe5.tar.bz2
linux-stable-de3ec318fee32313092b609f88475f86e58f3fe5.zip
scsi: lpfc: Rework FDMI initialization after link up
After a link up, it's possible for the switch to change FDMI support (e.g. FDMI1 vs FDMI2 vs SmartSAN). If the switch reverts to FDMI1, then the revert is currently not detected. Additionally, when NPIV is configured, it's possible the physical port's RHBA is unprocessed by the switch before reciept of an NPIV port issued RPRT. This causes some switches vendors to reject the NPIV's RPRT. Fix by reinitializing base FDMI mode on link up, and defer FDMI vport RPRT submission until after confirming physical port's RHBA is completed. Link: https://lore.kernel.org/r/20220506035519.50908-10-jsmart2021@gmail.com Co-developed-by: Justin Tee <justin.tee@broadcom.com> Signed-off-by: Justin Tee <justin.tee@broadcom.com> Signed-off-by: James Smart <jsmart2021@gmail.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_ct.c')
-rw-r--r--drivers/scsi/lpfc/lpfc_ct.c98
1 files changed, 91 insertions, 7 deletions
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index 094199d1006a..9d36b20fb878 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -2168,6 +2168,41 @@ ns_cmd_exit:
}
/**
+ * lpfc_fdmi_rprt_defer - Check for any deferred FDMI RPRT commands
+ * @phba: Pointer to HBA context object.
+ * @mask: Initial port attributes mask
+ *
+ * This function checks to see if any vports have deferred their FDMI RPRT.
+ * A vports RPRT may be deferred if it is issued before the primary ports
+ * RHBA completes.
+ */
+static void
+lpfc_fdmi_rprt_defer(struct lpfc_hba *phba, uint32_t mask)
+{
+ struct lpfc_vport **vports;
+ struct lpfc_vport *vport;
+ struct lpfc_nodelist *ndlp;
+ int i;
+
+ phba->hba_flag |= HBA_RHBA_CMPL;
+ vports = lpfc_create_vport_work_array(phba);
+ if (vports) {
+ for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
+ vport = vports[i];
+ ndlp = lpfc_findnode_did(phba->pport, FDMI_DID);
+ if (!ndlp)
+ continue;
+ if (vport->ct_flags & FC_CT_RPRT_DEFER) {
+ vport->ct_flags &= ~FC_CT_RPRT_DEFER;
+ vport->fdmi_port_mask = mask;
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPRT, 0);
+ }
+ }
+ }
+ lpfc_destroy_vport_work_array(phba, vports);
+}
+
+/**
* lpfc_cmpl_ct_disc_fdmi - Handle a discovery FDMI completion
* @phba: Pointer to HBA context object.
* @cmdiocb: Pointer to the command IOCBQ.
@@ -2255,8 +2290,12 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
switch (cmd) {
case SLI_MGMT_RHBA:
if (vport->fdmi_hba_mask == LPFC_FDMI2_HBA_ATTR) {
- /* Fallback to FDMI-1 */
+ /* Fallback to FDMI-1 for HBA attributes */
vport->fdmi_hba_mask = LPFC_FDMI1_HBA_ATTR;
+
+ /* If HBA attributes are FDMI1, so should
+ * port attributes be for consistency.
+ */
vport->fdmi_port_mask = LPFC_FDMI1_PORT_ATTR;
/* Start over */
lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA, 0);
@@ -2264,6 +2303,11 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
return;
case SLI_MGMT_RPRT:
+ if (vport->port_type != LPFC_PHYSICAL_PORT) {
+ ndlp = lpfc_findnode_did(phba->pport, FDMI_DID);
+ if (!ndlp)
+ return;
+ }
if (vport->fdmi_port_mask == LPFC_FDMI2_PORT_ATTR) {
/* Fallback to FDMI-1 */
vport->fdmi_port_mask = LPFC_FDMI1_PORT_ATTR;
@@ -2313,6 +2357,9 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
*/
switch (cmd) {
case SLI_MGMT_RHBA:
+ /* Check for any RPRTs deferred till after RHBA completes */
+ lpfc_fdmi_rprt_defer(phba, vport->fdmi_port_mask);
+
lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPA, 0);
break;
@@ -2321,10 +2368,26 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
break;
case SLI_MGMT_DPRT:
- if (vport->port_type == LPFC_PHYSICAL_PORT)
+ if (vport->port_type == LPFC_PHYSICAL_PORT) {
lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RHBA, 0);
- else
- lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPRT, 0);
+ } else {
+ ndlp = lpfc_findnode_did(phba->pport, FDMI_DID);
+ if (!ndlp)
+ return;
+
+ /* Only issue a RPRT for the vport if the RHBA
+ * for the physical port completes successfully.
+ * We may have to defer the RPRT accordingly.
+ */
+ if (phba->hba_flag & HBA_RHBA_CMPL) {
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPRT, 0);
+ } else {
+ lpfc_printf_vlog(vport, KERN_INFO,
+ LOG_DISCOVERY,
+ "6078 RPRT deferred\n");
+ vport->ct_flags |= FC_CT_RPRT_DEFER;
+ }
+ }
break;
case SLI_MGMT_RPA:
if (vport->port_type == LPFC_PHYSICAL_PORT &&
@@ -2339,7 +2402,8 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
break;
}
- lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT,
+ lpfc_printf_log(phba, KERN_INFO,
+ LOG_DISCOVERY | LOG_CGN_MGMT,
"6210 Issue Vendor MI FDMI %x\n",
phba->sli4_hba.pc_sli4_params.mi_ver);
@@ -2408,6 +2472,9 @@ lpfc_fdmi_change_check(struct lpfc_vport *vport)
phba->link_flag &= ~LS_CT_VEN_RPA;
lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA, 0);
} else {
+ ndlp = lpfc_findnode_did(phba->pport, FDMI_DID);
+ if (!ndlp)
+ return;
lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DPRT, 0);
}
@@ -2429,6 +2496,9 @@ lpfc_fdmi_change_check(struct lpfc_vport *vport)
lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPA,
LPFC_FDMI_PORT_ATTR_num_disc);
} else {
+ ndlp = lpfc_findnode_did(phba->pport, FDMI_DID);
+ if (!ndlp)
+ return;
lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPRT,
LPFC_FDMI_PORT_ATTR_num_disc);
}
@@ -3501,8 +3571,10 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
/* FDMI request */
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
- "0218 FDMI Request Data: x%x x%x x%x\n",
- vport->fc_flag, vport->port_state, cmdcode);
+ "0218 FDMI Request x%x mask x%x Data: x%x x%x x%x\n",
+ cmdcode, new_mask, vport->fdmi_port_mask,
+ vport->fc_flag, vport->port_state);
+
CtReq = (struct lpfc_sli_ct_request *)mp->virt;
/* First populate the CT_IU preamble */
@@ -3571,6 +3643,12 @@ hba_out:
break;
case SLI_MGMT_RPRT:
+ if (vport->port_type != LPFC_PHYSICAL_PORT) {
+ ndlp = lpfc_findnode_did(phba->pport, FDMI_DID);
+ if (!ndlp)
+ return 0;
+ }
+ fallthrough;
case SLI_MGMT_RPA:
pab = (struct lpfc_fdmi_reg_portattr *)&CtReq->un.PortID;
if (cmdcode == SLI_MGMT_RPRT) {
@@ -3635,6 +3713,12 @@ port_out:
rsp_size = FC_MAX_NS_RSP;
fallthrough;
case SLI_MGMT_DPRT:
+ if (vport->port_type != LPFC_PHYSICAL_PORT) {
+ ndlp = lpfc_findnode_did(phba->pport, FDMI_DID);
+ if (!ndlp)
+ return 0;
+ }
+ fallthrough;
case SLI_MGMT_DPA:
pe = (struct lpfc_fdmi_port_entry *)&CtReq->un.PortID;
memcpy((uint8_t *)&pe->PortName,