Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 115451
b: refs/heads/master
c: 90160e0
h: refs/heads/master
i:
  115449: e8f76e1
  115447: d7b6057
v: v3
  • Loading branch information
James Smart authored and James Bottomley committed Oct 13, 2008
1 parent e370e97 commit 99863d6
Show file tree
Hide file tree
Showing 5 changed files with 173 additions and 111 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: e59058c44025d71c9b7f260076a932935d3bba95
refs/heads/master: 90160e010b6f3a91a9bb044bbe6723731e6f366c
186 changes: 97 additions & 89 deletions trunk/drivers/scsi/lpfc/lpfc_els.c
Original file line number Diff line number Diff line change
Expand Up @@ -1555,6 +1555,83 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
return 0;
}

/**
* lpfc_rscn_disc: Perform rscn discovery for a vport.
* @vport: pointer to a host virtual N_Port data structure.
*
* This routine performs Registration State Change Notification (RSCN)
* discovery for a @vport. If the @vport's node port recovery count is not
* zero, it will invoke the lpfc_els_disc_plogi() to perform PLOGI for all
* the nodes that need recovery. If none of the PLOGI were needed through
* the lpfc_els_disc_plogi() routine, the lpfc_end_rscn() routine shall be
* invoked to check and handle possible more RSCN came in during the period
* of processing the current ones.
**/
static void
lpfc_rscn_disc(struct lpfc_vport *vport)
{
lpfc_can_disctmo(vport);

/* RSCN discovery */
/* go thru NPR nodes and issue ELS PLOGIs */
if (vport->fc_npr_cnt)
if (lpfc_els_disc_plogi(vport))
return;

lpfc_end_rscn(vport);
}

/**
* lpfc_adisc_done: Complete the adisc phase of discovery.
* @vport: pointer to lpfc_vport hba data structure that finished all ADISCs.
*
* This function is called when the final ADISC is completed during discovery.
* This function handles clearing link attention or issuing reg_vpi depending
* on whether npiv is enabled. This function also kicks off the PLOGI phase of
* discovery.
* This function is called with no locks held.
**/
static void
lpfc_adisc_done(struct lpfc_vport *vport)
{
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
struct lpfc_hba *phba = vport->phba;

/*
* For NPIV, cmpl_reg_vpi will set port_state to READY,
* and continue discovery.
*/
if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
!(vport->fc_flag & FC_RSCN_MODE)) {
lpfc_issue_reg_vpi(phba, vport);
return;
}
/*
* For SLI2, we need to set port_state to READY
* and continue discovery.
*/
if (vport->port_state < LPFC_VPORT_READY) {
/* If we get here, there is nothing to ADISC */
if (vport->port_type == LPFC_PHYSICAL_PORT)
lpfc_issue_clear_la(phba, vport);
if (!(vport->fc_flag & FC_ABORT_DISCOVERY)) {
vport->num_disc_nodes = 0;
/* go thru NPR list, issue ELS PLOGIs */
if (vport->fc_npr_cnt)
lpfc_els_disc_plogi(vport);
if (!vport->num_disc_nodes) {
spin_lock_irq(shost->host_lock);
vport->fc_flag &= ~FC_NDISC_ACTIVE;
spin_unlock_irq(shost->host_lock);
lpfc_can_disctmo(vport);
lpfc_end_rscn(vport);
}
}
vport->port_state = LPFC_VPORT_READY;
} else
lpfc_rscn_disc(vport);
}

/**
* lpfc_more_adisc: Issue more adisc as needed.
* @vport: pointer to a host virtual N_Port data structure.
Expand Down Expand Up @@ -1583,35 +1660,11 @@ lpfc_more_adisc(struct lpfc_vport *vport)
/* go thru NPR nodes and issue any remaining ELS ADISCs */
sentadisc = lpfc_els_disc_adisc(vport);
}
if (!vport->num_disc_nodes)
lpfc_adisc_done(vport);
return;
}

/**
* lpfc_rscn_disc: Perform rscn discovery for a vport.
* @vport: pointer to a host virtual N_Port data structure.
*
* This routine performs Registration State Change Notification (RSCN)
* discovery for a @vport. If the @vport's node port recovery count is not
* zero, it will invoke the lpfc_els_disc_plogi() to perform PLOGI for all
* the nodes that need recovery. If none of the PLOGI were needed through
* the lpfc_els_disc_plogi() routine, the lpfc_end_rscn() routine shall be
* invoked to check and handle possible more RSCN came in during the period
* of processing the current ones.
**/
static void
lpfc_rscn_disc(struct lpfc_vport *vport)
{
lpfc_can_disctmo(vport);

/* RSCN discovery */
/* go thru NPR nodes and issue ELS PLOGIs */
if (vport->fc_npr_cnt)
if (lpfc_els_disc_plogi(vport))
return;

lpfc_end_rscn(vport);
}

/**
* lpfc_cmpl_els_adisc: Completion callback function for adisc.
* @phba: pointer to lpfc hba data structure.
Expand Down Expand Up @@ -1692,52 +1745,9 @@ lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
lpfc_disc_state_machine(vport, ndlp, cmdiocb,
NLP_EVT_CMPL_ADISC);

if (disc && vport->num_disc_nodes) {
/* Check to see if there are more ADISCs to be sent */
/* Check to see if there are more ADISCs to be sent */
if (disc && vport->num_disc_nodes)
lpfc_more_adisc(vport);

/* Check to see if we are done with ADISC authentication */
if (vport->num_disc_nodes == 0) {
/* If we get here, there is nothing left to ADISC */
/*
* For NPIV, cmpl_reg_vpi will set port_state to READY,
* and continue discovery.
*/
if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
!(vport->fc_flag & FC_RSCN_MODE)) {
lpfc_issue_reg_vpi(phba, vport);
goto out;
}
/*
* For SLI2, we need to set port_state to READY
* and continue discovery.
*/
if (vport->port_state < LPFC_VPORT_READY) {
/* If we get here, there is nothing to ADISC */
if (vport->port_type == LPFC_PHYSICAL_PORT)
lpfc_issue_clear_la(phba, vport);

if (!(vport->fc_flag & FC_ABORT_DISCOVERY)) {
vport->num_disc_nodes = 0;
/* go thru NPR list, issue ELS PLOGIs */
if (vport->fc_npr_cnt)
lpfc_els_disc_plogi(vport);

if (!vport->num_disc_nodes) {
spin_lock_irq(shost->host_lock);
vport->fc_flag &=
~FC_NDISC_ACTIVE;
spin_unlock_irq(
shost->host_lock);
lpfc_can_disctmo(vport);
}
}
vport->port_state = LPFC_VPORT_READY;
} else {
lpfc_rscn_disc(vport);
}
}
}
out:
lpfc_els_free_iocb(phba, cmdiocb);
return;
Expand Down Expand Up @@ -2258,19 +2268,16 @@ lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp)
if (vport->port_state < LPFC_VPORT_READY) {
/* Check if there are more ADISCs to be sent */
lpfc_more_adisc(vport);
if ((vport->num_disc_nodes == 0) &&
(vport->fc_npr_cnt))
lpfc_els_disc_plogi(vport);
} else {
/* Check if there are more PLOGIs to be sent */
lpfc_more_plogi(vport);
}
if (vport->num_disc_nodes == 0) {
spin_lock_irq(shost->host_lock);
vport->fc_flag &= ~FC_NDISC_ACTIVE;
spin_unlock_irq(shost->host_lock);
lpfc_can_disctmo(vport);
lpfc_end_rscn(vport);
if (vport->num_disc_nodes == 0) {
spin_lock_irq(shost->host_lock);
vport->fc_flag &= ~FC_NDISC_ACTIVE;
spin_unlock_irq(shost->host_lock);
lpfc_can_disctmo(vport);
lpfc_end_rscn(vport);
}
}
}
}
Expand Down Expand Up @@ -4480,14 +4487,9 @@ lpfc_els_rcv_rps(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
struct ls_rjt stat;

if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) &&
(ndlp->nlp_state != NLP_STE_MAPPED_NODE)) {
stat.un.b.lsRjtRsvd0 = 0;
stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
stat.un.b.vendorUnique = 0;
lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
NULL);
}
(ndlp->nlp_state != NLP_STE_MAPPED_NODE))
/* reject the unsolicited RPS request and done with it */
goto reject_out;

pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
lp = (uint32_t *) pcmd->virt;
Expand Down Expand Up @@ -4520,6 +4522,9 @@ lpfc_els_rcv_rps(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
mempool_free(mbox, phba->mbox_mem_pool);
}
}

reject_out:
/* issue rejection response */
stat.un.b.lsRjtRsvd0 = 0;
stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
Expand Down Expand Up @@ -4629,12 +4634,15 @@ lpfc_els_rcv_rpl(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,

if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) &&
(ndlp->nlp_state != NLP_STE_MAPPED_NODE)) {
/* issue rejection response */
stat.un.b.lsRjtRsvd0 = 0;
stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
stat.un.b.vendorUnique = 0;
lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
NULL);
/* rejected the unsolicited RPL request and done with it */
return 0;
}

pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
Expand Down
8 changes: 0 additions & 8 deletions trunk/drivers/scsi/lpfc/lpfc_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -1580,14 +1580,6 @@ lpfc_cleanup(struct lpfc_vport *vport)
lpfc_disc_state_machine(vport, ndlp, NULL,
NLP_EVT_DEVICE_RM);

/* nlp_type zero is not defined, nlp_flag zero also not defined,
* nlp_state is unused, this happens when
* an initiator has logged
* into us so cleanup this ndlp.
*/
if ((ndlp->nlp_type == 0) && (ndlp->nlp_flag == 0) &&
(ndlp->nlp_state == 0))
lpfc_nlp_put(ndlp);
}

/* At this point, ALL ndlp's should be gone
Expand Down
14 changes: 1 addition & 13 deletions trunk/drivers/scsi/lpfc/lpfc_nportdisc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1003,20 +1003,8 @@ lpfc_rcv_plogi_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
spin_unlock_irq(shost->host_lock);

if (vport->num_disc_nodes) {
if (vport->num_disc_nodes)
lpfc_more_adisc(vport);
if ((vport->num_disc_nodes == 0) &&
(vport->fc_npr_cnt))
lpfc_els_disc_plogi(vport);
if (vport->num_disc_nodes == 0) {
spin_lock_irq(shost->host_lock);
vport->fc_flag &= ~FC_NDISC_ACTIVE;
spin_unlock_irq(shost->host_lock);
lpfc_can_disctmo(vport);
lpfc_end_rscn(vport);
}
}
}
return ndlp->nlp_state;
}
Expand Down
74 changes: 74 additions & 0 deletions trunk/drivers/scsi/lpfc/lpfc_vport.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 99863d6

Please sign in to comment.