From c2b9712edd32967d84befe8628270a85f1b7e5a6 Mon Sep 17 00:00:00 2001
From: James Smart <james.smart@emulex.com>
Date: Fri, 31 May 2013 17:05:36 -0400
Subject: [PATCH] [SCSI] lpfc 8.3.40: Fixed a race condition between SLI host
 and port failed FCF rediscovery

Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
---
 drivers/scsi/lpfc/lpfc_init.c | 97 +++++++++++++----------------------
 1 file changed, 35 insertions(+), 62 deletions(-)

diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 7e5a2b16521fce..cba2d955777b20 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -4049,52 +4049,6 @@ lpfc_sli4_perform_all_vport_cvl(struct lpfc_hba *phba)
 	lpfc_destroy_vport_work_array(phba, vports);
 }
 
-/**
- * lpfc_sli4_perform_inuse_fcf_recovery - Perform inuse fcf recovery
- * @vport: pointer to lpfc hba data structure.
- *
- * This routine is to perform FCF recovery when the in-use FCF either dead or
- * got modified.
- **/
-static void
-lpfc_sli4_perform_inuse_fcf_recovery(struct lpfc_hba *phba,
-				     struct lpfc_acqe_fip *acqe_fip)
-{
-	int rc;
-
-	spin_lock_irq(&phba->hbalock);
-	/* Mark the fast failover process in progress */
-	phba->fcf.fcf_flag |= FCF_DEAD_DISC;
-	spin_unlock_irq(&phba->hbalock);
-
-	lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY,
-			"2771 Start FCF fast failover process due to in-use "
-			"FCF DEAD/MODIFIED event: evt_tag:x%x, index:x%x\n",
-			acqe_fip->event_tag, acqe_fip->index);
-	rc = lpfc_sli4_redisc_fcf_table(phba);
-	if (rc) {
-		lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_DISCOVERY,
-				"2772 Issue FCF rediscover mabilbox command "
-				"failed, fail through to FCF dead event\n");
-		spin_lock_irq(&phba->hbalock);
-		phba->fcf.fcf_flag &= ~FCF_DEAD_DISC;
-		spin_unlock_irq(&phba->hbalock);
-		/*
-		 * Last resort will fail over by treating this as a link
-		 * down to FCF registration.
-		 */
-		lpfc_sli4_fcf_dead_failthrough(phba);
-	} else {
-		/* Reset FCF roundrobin bmask for new discovery */
-		lpfc_sli4_clear_fcf_rr_bmask(phba);
-		/*
-		 * Handling fast FCF failover to a DEAD FCF event is
-		 * considered equalivant to receiving CVL to all vports.
-		 */
-		lpfc_sli4_perform_all_vport_cvl(phba);
-	}
-}
-
 /**
  * lpfc_sli4_async_fip_evt - Process the asynchronous FCoE FIP event
  * @phba: pointer to lpfc hba data structure.
@@ -4160,22 +4114,9 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba,
 			break;
 		}
 
-		/* If FCF has been in discovered state, perform rediscovery
-		 * only if the FCF with the same index of the in-use FCF got
-		 * modified during normal operation. Otherwise, do nothing.
-		 */
-		if (phba->pport->port_state > LPFC_FLOGI) {
+		/* If the FCF has been in discovered state, do nothing. */
+		if (phba->fcf.fcf_flag & FCF_SCAN_DONE) {
 			spin_unlock_irq(&phba->hbalock);
-			if (phba->fcf.current_rec.fcf_indx ==
-			    acqe_fip->index) {
-				lpfc_printf_log(phba, KERN_ERR, LOG_FIP,
-						"3300 In-use FCF (%d) "
-						"modified, perform FCF "
-						"rediscovery\n",
-						acqe_fip->index);
-				lpfc_sli4_perform_inuse_fcf_recovery(phba,
-								     acqe_fip);
-			}
 			break;
 		}
 		spin_unlock_irq(&phba->hbalock);
@@ -4228,7 +4169,39 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba,
 		 * is no longer valid as we are not in the middle of FCF
 		 * failover process already.
 		 */
-		lpfc_sli4_perform_inuse_fcf_recovery(phba, acqe_fip);
+		spin_lock_irq(&phba->hbalock);
+		/* Mark the fast failover process in progress */
+		phba->fcf.fcf_flag |= FCF_DEAD_DISC;
+		spin_unlock_irq(&phba->hbalock);
+
+		lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY,
+				"2771 Start FCF fast failover process due to "
+				"FCF DEAD event: evt_tag:x%x, fcf_index:x%x "
+				"\n", acqe_fip->event_tag, acqe_fip->index);
+		rc = lpfc_sli4_redisc_fcf_table(phba);
+		if (rc) {
+			lpfc_printf_log(phba, KERN_ERR, LOG_FIP |
+					LOG_DISCOVERY,
+					"2772 Issue FCF rediscover mabilbox "
+					"command failed, fail through to FCF "
+					"dead event\n");
+			spin_lock_irq(&phba->hbalock);
+			phba->fcf.fcf_flag &= ~FCF_DEAD_DISC;
+			spin_unlock_irq(&phba->hbalock);
+			/*
+			 * Last resort will fail over by treating this
+			 * as a link down to FCF registration.
+			 */
+			lpfc_sli4_fcf_dead_failthrough(phba);
+		} else {
+			/* Reset FCF roundrobin bmask for new discovery */
+			lpfc_sli4_clear_fcf_rr_bmask(phba);
+			/*
+			 * Handling fast FCF failover to a DEAD FCF event is
+			 * considered equalivant to receiving CVL to all vports.
+			 */
+			lpfc_sli4_perform_all_vport_cvl(phba);
+		}
 		break;
 	case LPFC_FIP_EVENT_TYPE_CVL:
 		phba->fcoe_cvl_eventtag = acqe_fip->event_tag;
-- 
GitLab