[SCSI] lpfc 8.3.10: Fix Discovery issues

- Prevent Vport discovery after reg_new_vport completes when physical
  logged in using FDISC.
- Remove fast FCF failover fabric name matching. Allow failover to FCFs
  connected to different fabrics.
- Added fast FCF failover in response to FCF DEAD event on current
  FCF record.

Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
This commit is contained in:
James Smart
2010-02-26 14:15:29 -05:00
committed by James Bottomley
parent e2aed29f29
commit fc2b989be9
6 changed files with 186 additions and 51 deletions

View File

@@ -2199,8 +2199,10 @@ lpfc_stop_vport_timers(struct lpfc_vport *vport)
void
__lpfc_sli4_stop_fcf_redisc_wait_timer(struct lpfc_hba *phba)
{
/* Clear pending FCF rediscovery wait timer */
phba->fcf.fcf_flag &= ~FCF_REDISC_PEND;
/* Clear pending FCF rediscovery wait and failover in progress flags */
phba->fcf.fcf_flag &= ~(FCF_REDISC_PEND |
FCF_DEAD_FOVER |
FCF_CVL_FOVER);
/* Now, try to stop the timer */
del_timer(&phba->fcf.redisc_wait);
}
@@ -3211,6 +3213,68 @@ out_free_pmb:
mempool_free(pmb, phba->mbox_mem_pool);
}
/**
* lpfc_sli4_perform_vport_cvl - Perform clear virtual link on a vport
* @vport: pointer to vport data structure.
*
* This routine is to perform Clear Virtual Link (CVL) on a vport in
* response to a CVL event.
*
* Return the pointer to the ndlp with the vport if successful, otherwise
* return NULL.
**/
static struct lpfc_nodelist *
lpfc_sli4_perform_vport_cvl(struct lpfc_vport *vport)
{
struct lpfc_nodelist *ndlp;
struct Scsi_Host *shost;
struct lpfc_hba *phba;
if (!vport)
return NULL;
ndlp = lpfc_findnode_did(vport, Fabric_DID);
if (!ndlp)
return NULL;
phba = vport->phba;
if (!phba)
return NULL;
if (phba->pport->port_state <= LPFC_FLOGI)
return NULL;
/* If virtual link is not yet instantiated ignore CVL */
if (vport->port_state <= LPFC_FDISC)
return NULL;
shost = lpfc_shost_from_vport(vport);
if (!shost)
return NULL;
lpfc_linkdown_port(vport);
lpfc_cleanup_pending_mbox(vport);
spin_lock_irq(shost->host_lock);
vport->fc_flag |= FC_VPORT_CVL_RCVD;
spin_unlock_irq(shost->host_lock);
return ndlp;
}
/**
* lpfc_sli4_perform_all_vport_cvl - Perform clear virtual link on all vports
* @vport: pointer to lpfc hba data structure.
*
* This routine is to perform Clear Virtual Link (CVL) on all vports in
* response to a FCF dead event.
**/
static void
lpfc_sli4_perform_all_vport_cvl(struct lpfc_hba *phba)
{
struct lpfc_vport **vports;
int i;
vports = lpfc_create_vport_work_array(phba);
if (vports)
for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++)
lpfc_sli4_perform_vport_cvl(vports[i]);
lpfc_destroy_vport_work_array(phba, vports);
}
/**
* lpfc_sli4_async_fcoe_evt - Process the asynchronous fcoe event
* @phba: pointer to lpfc hba data structure.
@@ -3227,7 +3291,6 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
struct lpfc_vport *vport;
struct lpfc_nodelist *ndlp;
struct Scsi_Host *shost;
uint32_t link_state;
int active_vlink_present;
struct lpfc_vport **vports;
int i;
@@ -3284,16 +3347,35 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
/* If the event is not for currently used fcf do nothing */
if (phba->fcf.current_rec.fcf_indx != acqe_fcoe->index)
break;
/*
* Currently, driver support only one FCF - so treat this as
* a link down, but save the link state because we don't want
* it to be changed to Link Down unless it is already down.
/* We request port to rediscover the entire FCF table for
* a fast recovery from case that the current FCF record
* is no longer valid if the last CVL event hasn't already
* triggered process.
*/
link_state = phba->link_state;
lpfc_linkdown(phba);
phba->link_state = link_state;
/* Unregister FCF if no devices connected to it */
lpfc_unregister_unused_fcf(phba);
spin_lock_irq(&phba->hbalock);
if (phba->fcf.fcf_flag & FCF_CVL_FOVER) {
spin_unlock_irq(&phba->hbalock);
break;
}
/* Mark the fast failover process in progress */
phba->fcf.fcf_flag |= FCF_DEAD_FOVER;
spin_unlock_irq(&phba->hbalock);
rc = lpfc_sli4_redisc_fcf_table(phba);
if (rc) {
spin_lock_irq(&phba->hbalock);
phba->fcf.fcf_flag &= ~FCF_DEAD_FOVER;
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
/* 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_FCOE_EVENT_TYPE_CVL:
lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
@@ -3301,23 +3383,9 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
" tag 0x%x\n", acqe_fcoe->index, acqe_fcoe->event_tag);
vport = lpfc_find_vport_by_vpid(phba,
acqe_fcoe->index - phba->vpi_base);
if (!vport)
break;
ndlp = lpfc_findnode_did(vport, Fabric_DID);
ndlp = lpfc_sli4_perform_vport_cvl(vport);
if (!ndlp)
break;
shost = lpfc_shost_from_vport(vport);
if (phba->pport->port_state <= LPFC_FLOGI)
break;
/* If virtual link is not yet instantiated ignore CVL */
if (vport->port_state <= LPFC_FDISC)
break;
lpfc_linkdown_port(vport);
lpfc_cleanup_pending_mbox(vport);
spin_lock_irq(shost->host_lock);
vport->fc_flag |= FC_VPORT_CVL_RCVD;
spin_unlock_irq(shost->host_lock);
active_vlink_present = 0;
vports = lpfc_create_vport_work_array(phba);
@@ -3340,6 +3408,7 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
* re-instantiate the Vlink using FDISC.
*/
mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ);
shost = lpfc_shost_from_vport(vport);
spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_DELAY_TMO;
spin_unlock_irq(shost->host_lock);
@@ -3350,15 +3419,28 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
* Otherwise, we request port to rediscover
* the entire FCF table for a fast recovery
* from possible case that the current FCF
* is no longer valid.
* is no longer valid if the FCF_DEAD event
* hasn't already triggered process.
*/
spin_lock_irq(&phba->hbalock);
if (phba->fcf.fcf_flag & FCF_DEAD_FOVER) {
spin_unlock_irq(&phba->hbalock);
break;
}
/* Mark the fast failover process in progress */
phba->fcf.fcf_flag |= FCF_CVL_FOVER;
spin_unlock_irq(&phba->hbalock);
rc = lpfc_sli4_redisc_fcf_table(phba);
if (rc)
if (rc) {
spin_lock_irq(&phba->hbalock);
phba->fcf.fcf_flag &= ~FCF_CVL_FOVER;
spin_unlock_irq(&phba->hbalock);
/*
* Last resort will be re-try on the
* the current registered FCF entry.
*/
lpfc_retry_pport_discovery(phba);
}
}
break;
default: