diff options
author | James Smart <James.Smart@Emulex.Com> | 2008-08-25 05:49:45 +0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-10-13 17:28:53 +0400 |
commit | 90160e010b6f3a91a9bb044bbe6723731e6f366c (patch) | |
tree | 8320400d5bed96f1976cef88adcad647fcb48f9e /drivers/scsi/lpfc/lpfc_vport.c | |
parent | e59058c44025d71c9b7f260076a932935d3bba95 (diff) | |
download | linux-90160e010b6f3a91a9bb044bbe6723731e6f366c.tar.xz |
[SCSI] lpfc 8.2.8 : Miscellaneous Discovery Fixes
Miscellaneous Discovery fixes:
- Fix rejection followed by acceptance in handling RPL and RPS
unsolicited events
- Fix for vport delete crash
- Fix PLOGI vs ADISC race condition
Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_vport.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_vport.c | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c index 109f89d98830..ad0f65313878 100644 --- a/drivers/scsi/lpfc/lpfc_vport.c +++ b/drivers/scsi/lpfc/lpfc_vport.c @@ -204,6 +204,77 @@ lpfc_unique_wwpn(struct lpfc_hba *phba, struct lpfc_vport *new_vport) return 1; } +/** + * lpfc_discovery_wait: Wait for driver discovery to quiesce. + * @vport: The virtual port for which this call is being executed. + * + * This driver calls this routine specifically from lpfc_vport_delete + * to enforce a synchronous execution of vport + * delete relative to discovery activities. The + * lpfc_vport_delete routine should not return until it + * can reasonably guarantee that discovery has quiesced. + * Post FDISC LOGO, the driver must wait until its SAN teardown is + * complete and all resources recovered before allowing + * cleanup. + * + * This routine does not require any locks held. + **/ +static void lpfc_discovery_wait(struct lpfc_vport *vport) +{ + struct lpfc_hba *phba = vport->phba; + uint32_t wait_flags = 0; + unsigned long wait_time_max; + unsigned long start_time; + + wait_flags = FC_RSCN_MODE | FC_RSCN_DISCOVERY | FC_NLP_MORE | + FC_RSCN_DEFERRED | FC_NDISC_ACTIVE | FC_DISC_TMO; + + /* + * The time constraint on this loop is a balance between the + * fabric RA_TOV value and dev_loss tmo. The driver's + * devloss_tmo is 10 giving this loop a 3x multiplier minimally. + */ + wait_time_max = msecs_to_jiffies(((phba->fc_ratov * 3) + 3) * 1000); + wait_time_max += jiffies; + start_time = jiffies; + while (time_before(jiffies, wait_time_max)) { + if ((vport->num_disc_nodes > 0) || + (vport->fc_flag & wait_flags) || + ((vport->port_state > LPFC_VPORT_FAILED) && + (vport->port_state < LPFC_VPORT_READY))) { + lpfc_printf_log(phba, KERN_INFO, LOG_VPORT, + "1833 Vport discovery quiesce Wait:" + " vpi x%x state x%x fc_flags x%x" + " num_nodes x%x, waiting 1000 msecs" + " total wait msecs x%x\n", + vport->vpi, vport->port_state, + vport->fc_flag, vport->num_disc_nodes, + jiffies_to_msecs(jiffies - start_time)); + msleep(1000); + } else { + /* Base case. Wait variants satisfied. Break out */ + lpfc_printf_log(phba, KERN_INFO, LOG_VPORT, + "1834 Vport discovery quiesced:" + " vpi x%x state x%x fc_flags x%x" + " wait msecs x%x\n", + vport->vpi, vport->port_state, + vport->fc_flag, + jiffies_to_msecs(jiffies + - start_time)); + break; + } + } + + if (time_after(jiffies, wait_time_max)) + lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, + "1835 Vport discovery quiesce failed:" + " vpi x%x state x%x fc_flags x%x" + " wait msecs x%x\n", + vport->vpi, vport->port_state, + vport->fc_flag, + jiffies_to_msecs(jiffies - start_time)); +} + int lpfc_vport_create(struct fc_vport *fc_vport, bool disable) { @@ -602,6 +673,9 @@ lpfc_vport_delete(struct fc_vport *fc_vport) timeout = schedule_timeout(timeout); } + if (!(phba->pport->load_flag & FC_UNLOADING)) + lpfc_discovery_wait(vport); + skip_logo: lpfc_cleanup(vport); lpfc_sli_host_down(vport); |