[SCSI] lpfc 8.3.3 : FC/FCOE discovery fixes

Contains the following changes:
- Force vport to send LOGO to fabric controller when deleting vport
- Fixed driver failing to register login when a PLOGI is received
- Fixes for FIP discovery
- Added stricter checks for FCF addressing mode
- Added code to send only FLOGI, FDISC and LOGO to Fabric controller as FIP
- Fixed handling of LOGO from Fabric port
- Fixed consecutive link up events skipped link_down processing

Signed-off-by: James Smart <James.Smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 2aabaf9..f72fdf2 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -168,6 +168,19 @@
 	if (elsiocb == NULL)
 		return NULL;
 
+	/*
+	 * If this command is for fabric controller and HBA running
+	 * in FIP mode send FLOGI, FDISC and LOGO as FIP frames.
+	 */
+	if ((did == Fabric_DID) &&
+		bf_get(lpfc_fip_flag, &phba->sli4_hba.sli4_flags) &&
+		((elscmd == ELS_CMD_FLOGI) ||
+		 (elscmd == ELS_CMD_FDISC) ||
+		 (elscmd == ELS_CMD_LOGO)))
+		elsiocb->iocb_flag |= LPFC_FIP_ELS;
+	else
+		elsiocb->iocb_flag &= ~LPFC_FIP_ELS;
+
 	icmd = &elsiocb->iocb;
 
 	/* fill in BDEs for command */
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index 35c41ae..ed46b24 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -1197,6 +1197,11 @@
 {
 	struct lpfc_fcf_conn_entry *conn_entry;
 
+	/* If FCF not available return 0 */
+	if (!bf_get(lpfc_fcf_record_fcf_avail, new_fcf_record) ||
+		!bf_get(lpfc_fcf_record_fcf_valid, new_fcf_record))
+		return 0;
+
 	if (!phba->cfg_enable_fip) {
 		*boot_flag = 0;
 		*addr_mode = bf_get(lpfc_fcf_record_mac_addr_prov,
@@ -1216,6 +1221,14 @@
 		*boot_flag = 0;
 		*addr_mode = bf_get(lpfc_fcf_record_mac_addr_prov,
 			new_fcf_record);
+
+		/*
+		 * When there are no FCF connect entries, use driver's default
+		 * addressing mode - FPMA.
+		 */
+		if (*addr_mode & LPFC_FCF_FPMA)
+			*addr_mode = LPFC_FCF_FPMA;
+
 		*vlan_id = 0xFFFF;
 		return 1;
 	}
@@ -1241,6 +1254,14 @@
 		}
 
 		/*
+		 * If connection record does not support any addressing mode,
+		 * skip the FCF record.
+		 */
+		if (!(bf_get(lpfc_fcf_record_mac_addr_prov, new_fcf_record)
+			& (LPFC_FCF_FPMA | LPFC_FCF_SPMA)))
+			continue;
+
+		/*
 		 * Check if the connection record specifies a required
 		 * addressing mode.
 		 */
@@ -1272,6 +1293,11 @@
 		else
 			*boot_flag = 0;
 
+		/*
+		 * If user did not specify any addressing mode, or if the
+		 * prefered addressing mode specified by user is not supported
+		 * by FCF, allow fabric to pick the addressing mode.
+		 */
 		*addr_mode = bf_get(lpfc_fcf_record_mac_addr_prov,
 				new_fcf_record);
 		/*
@@ -1297,12 +1323,6 @@
 			!(conn_entry->conn_rec.flags & FCFCNCT_AM_SPMA) &&
 			(*addr_mode & LPFC_FCF_FPMA))
 				*addr_mode = LPFC_FCF_FPMA;
-		/*
-		 * If user did not specify any addressing mode, use FPMA if
-		 * possible else use SPMA.
-		 */
-		else if (*addr_mode & LPFC_FCF_FPMA)
-			*addr_mode = LPFC_FCF_FPMA;
 
 		if (conn_entry->conn_rec.flags & FCFCNCT_VLAN_VALID)
 			*vlan_id = conn_entry->conn_rec.vlan_tag;
@@ -1864,7 +1884,7 @@
 		vport->fc_flag &= ~FC_BYPASSED_MODE;
 	spin_unlock_irq(shost->host_lock);
 
-	if (((phba->fc_eventTag + 1) < la->eventTag) ||
+	if ((phba->fc_eventTag  < la->eventTag) ||
 	    (phba->fc_eventTag == la->eventTag)) {
 		phba->fc_stat.LinkMultiEvent++;
 		if (la->attType == AT_LINK_UP)
@@ -2925,6 +2945,7 @@
 		lpfc_no_rpi(phba, ndlp);
 		ndlp->nlp_rpi = 0;
 		ndlp->nlp_flag &= ~NLP_RPI_VALID;
+		ndlp->nlp_flag &= ~NLP_NPR_ADISC;
 		return 1;
 	}
 	return 0;
diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h
index 749811a..2995d12 100644
--- a/drivers/scsi/lpfc/lpfc_hw4.h
+++ b/drivers/scsi/lpfc/lpfc_hw4.h
@@ -1128,7 +1128,7 @@
 #define lpfc_fcf_record_mac_5_WORD		word4
 #define lpfc_fcf_record_fcf_avail_SHIFT		16
 #define lpfc_fcf_record_fcf_avail_MASK		0x000000FF
-#define lpfc_fcf_record_fc_avail_WORD		word4
+#define lpfc_fcf_record_fcf_avail_WORD		word4
 #define lpfc_fcf_record_mac_addr_prov_SHIFT	24
 #define lpfc_fcf_record_mac_addr_prov_MASK	0x000000FF
 #define lpfc_fcf_record_mac_addr_prov_WORD	word4
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
index b9b451c..bb3dc1d 100644
--- a/drivers/scsi/lpfc/lpfc_mbox.c
+++ b/drivers/scsi/lpfc/lpfc_mbox.c
@@ -1715,8 +1715,10 @@
 	/* Set up host requested features. */
 	bf_set(lpfc_mbx_rq_ftr_rq_fcpi, &mboxq->u.mqe.un.req_ftrs, 1);
 
-	/* Virtual fabrics and FIPs are not supported yet. */
-	bf_set(lpfc_mbx_rq_ftr_rq_ifip, &mboxq->u.mqe.un.req_ftrs, 0);
+	if (phba->cfg_enable_fip)
+		bf_set(lpfc_mbx_rq_ftr_rq_ifip, &mboxq->u.mqe.un.req_ftrs, 0);
+	else
+		bf_set(lpfc_mbx_rq_ftr_rq_ifip, &mboxq->u.mqe.un.req_ftrs, 1);
 
 	/* Enable DIF (block guard) only if configured to do so. */
 	if (phba->cfg_enable_bg)
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index 09f659f..3e74136 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -497,7 +497,7 @@
 		lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL);
 	else
 		lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
-	if ((ndlp->nlp_type & NLP_FABRIC) &&
+	if ((ndlp->nlp_DID == Fabric_DID) &&
 		vport->port_type == LPFC_NPIV_PORT) {
 		lpfc_linkdown_port(vport);
 		mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1);
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index b8cf0a1..ba698d5 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -4491,8 +4491,10 @@
 		rc = -ENODEV;
 		goto out_free_vpd;
 	}
-	/* Temporary initialization of lpfc_fip_flag to non-fip */
-	bf_set(lpfc_fip_flag, &phba->sli4_hba.sli4_flags, 0);
+	if (phba->cfg_enable_fip)
+		bf_set(lpfc_fip_flag, &phba->sli4_hba.sli4_flags, 1);
+	else
+		bf_set(lpfc_fip_flag, &phba->sli4_hba.sli4_flags, 0);
 
 	/* Set up all the queues to the device */
 	rc = lpfc_sli4_queue_setup(phba);
@@ -5856,18 +5858,13 @@
 
 	fip = bf_get(lpfc_fip_flag, &phba->sli4_hba.sli4_flags);
 	/* The fcp commands will set command type */
-	if ((!(iocbq->iocb_flag &  LPFC_IO_FCP)) && (!fip))
-		command_type = ELS_COMMAND_NON_FIP;
-	else if (!(iocbq->iocb_flag &  LPFC_IO_FCP))
-		command_type = ELS_COMMAND_FIP;
-	else if (iocbq->iocb_flag &  LPFC_IO_FCP)
+	if (iocbq->iocb_flag &  LPFC_IO_FCP)
 		command_type = FCP_COMMAND;
-	else {
-		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
-			"2019 Invalid cmd 0x%x\n",
-			iocbq->iocb.ulpCommand);
-		return IOCB_ERROR;
-	}
+	else if (fip && (iocbq->iocb_flag & LPFC_FIP_ELS))
+		command_type = ELS_COMMAND_FIP;
+	else
+		command_type = ELS_COMMAND_NON_FIP;
+
 	/* Some of the fields are in the right position already */
 	memcpy(wqe, &iocbq->iocb, sizeof(union lpfc_wqe));
 	abort_tag = (uint32_t) iocbq->iotag;
@@ -11467,6 +11464,7 @@
 	bf_set(lpfc_fcf_record_fc_map_1, fcf_record, phba->fc_map[1]);
 	bf_set(lpfc_fcf_record_fc_map_2, fcf_record, phba->fc_map[2]);
 	bf_set(lpfc_fcf_record_fcf_valid, fcf_record, 1);
+	bf_set(lpfc_fcf_record_fcf_avail, fcf_record, 1);
 	bf_set(lpfc_fcf_record_fcf_index, fcf_record, fcf_index);
 	bf_set(lpfc_fcf_record_mac_addr_prov, fcf_record,
 		LPFC_FCF_FPMA | LPFC_FCF_SPMA);
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h
index 7d37eb7..3c53316 100644
--- a/drivers/scsi/lpfc/lpfc_sli.h
+++ b/drivers/scsi/lpfc/lpfc_sli.h
@@ -56,6 +56,7 @@
 #define LPFC_DRIVER_ABORTED	8	/* driver aborted this request */
 #define LPFC_IO_FABRIC		0x10	/* Iocb send using fabric scheduler */
 #define LPFC_DELAY_MEM_FREE	0x20    /* Defer free'ing of FC data */
+#define LPFC_FIP_ELS		0x40
 
 	uint8_t abort_count;
 	uint8_t rsvd2;
diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c
index a6313ee..e0b4992 100644
--- a/drivers/scsi/lpfc/lpfc_vport.c
+++ b/drivers/scsi/lpfc/lpfc_vport.c
@@ -695,8 +695,6 @@
 		}
 		vport->unreg_vpi_cmpl = VPORT_INVAL;
 		timeout = msecs_to_jiffies(phba->fc_ratov * 2000);
-		if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
-			goto skip_logo;
 		if (!lpfc_issue_els_npiv_logo(vport, ndlp))
 			while (vport->unreg_vpi_cmpl == VPORT_INVAL && timeout)
 				timeout = schedule_timeout(timeout);