summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/lpfc/lpfc_els.c
diff options
context:
space:
mode:
authorDavid Woodhouse <David.Woodhouse@intel.com>2010-03-26 14:55:59 +0000
committerDavid Woodhouse <David.Woodhouse@intel.com>2010-03-26 14:55:59 +0000
commit329f9052dbadf6f4afe2231668bd00c579a4aa10 (patch)
treee080a5c70df40f3ae8cf28a95a3267757668ab97 /drivers/scsi/lpfc/lpfc_els.c
parent395b228858778d3c44f7c413693a6acaa8bb62dc (diff)
parent220bf991b0366cc50a94feede3d7341fa5710ee4 (diff)
downloadlinux-stable-329f9052dbadf6f4afe2231668bd00c579a4aa10.tar.gz
linux-stable-329f9052dbadf6f4afe2231668bd00c579a4aa10.tar.bz2
linux-stable-329f9052dbadf6f4afe2231668bd00c579a4aa10.zip
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Conflicts: drivers/mtd/nand/sh_flctl.c Maxim's patch to initialise sysfs attributes depends on the patch which actually adds sysfs_attr_init().
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_els.c')
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c271
1 files changed, 245 insertions, 26 deletions
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 2cc39684ce97..ee980bd66869 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -50,9 +50,6 @@ static int lpfc_issue_els_fdisc(struct lpfc_vport *vport,
struct lpfc_nodelist *ndlp, uint8_t retry);
static int lpfc_issue_fabric_iocb(struct lpfc_hba *phba,
struct lpfc_iocbq *iocb);
-static void lpfc_register_new_vport(struct lpfc_hba *phba,
- struct lpfc_vport *vport,
- struct lpfc_nodelist *ndlp);
static int lpfc_max_els_tries = 3;
@@ -592,6 +589,15 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
spin_unlock_irq(shost->host_lock);
}
+ /*
+ * If VPI is unreged, driver need to do INIT_VPI
+ * before re-registering
+ */
+ if (phba->sli_rev == LPFC_SLI_REV4) {
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_VPORT_NEEDS_INIT_VPI;
+ spin_unlock_irq(shost->host_lock);
+ }
}
if (phba->sli_rev < LPFC_SLI_REV4) {
@@ -604,10 +610,13 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
} else {
ndlp->nlp_type |= NLP_FABRIC;
lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
- if (vport->vpi_state & LPFC_VPI_REGISTERED) {
+ if ((!(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) &&
+ (vport->vpi_state & LPFC_VPI_REGISTERED)) {
lpfc_start_fdiscs(phba);
lpfc_do_scr_ns_plogi(phba, vport);
- } else
+ } else if (vport->fc_flag & FC_VFI_REGISTERED)
+ lpfc_issue_init_vpi(vport);
+ else
lpfc_issue_reg_vfi(vport);
}
return 0;
@@ -762,6 +771,7 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
struct lpfc_nodelist *ndlp = cmdiocb->context1;
struct lpfc_dmabuf *pcmd = cmdiocb->context2, *prsp;
struct serv_parm *sp;
+ uint16_t fcf_index;
int rc;
/* Check to see if link went down during discovery */
@@ -779,6 +789,54 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
vport->port_state);
if (irsp->ulpStatus) {
+ /*
+ * In case of FIP mode, perform round robin FCF failover
+ * due to new FCF discovery
+ */
+ if ((phba->hba_flag & HBA_FIP_SUPPORT) &&
+ (phba->fcf.fcf_flag & FCF_DISCOVERY)) {
+ lpfc_printf_log(phba, KERN_WARNING, LOG_FIP | LOG_ELS,
+ "2611 FLOGI failed on registered "
+ "FCF record fcf_index:%d, trying "
+ "to perform round robin failover\n",
+ phba->fcf.current_rec.fcf_indx);
+ fcf_index = lpfc_sli4_fcf_rr_next_index_get(phba);
+ if (fcf_index == LPFC_FCOE_FCF_NEXT_NONE) {
+ /*
+ * Exhausted the eligible FCF record list,
+ * fail through to retry FLOGI on current
+ * FCF record.
+ */
+ lpfc_printf_log(phba, KERN_WARNING,
+ LOG_FIP | LOG_ELS,
+ "2760 FLOGI exhausted FCF "
+ "round robin failover list, "
+ "retry FLOGI on the current "
+ "registered FCF index:%d\n",
+ phba->fcf.current_rec.fcf_indx);
+ spin_lock_irq(&phba->hbalock);
+ phba->fcf.fcf_flag &= ~FCF_DISCOVERY;
+ spin_unlock_irq(&phba->hbalock);
+ } else {
+ rc = lpfc_sli4_fcf_rr_read_fcf_rec(phba,
+ fcf_index);
+ if (rc) {
+ lpfc_printf_log(phba, KERN_WARNING,
+ LOG_FIP | LOG_ELS,
+ "2761 FLOGI round "
+ "robin FCF failover "
+ "read FCF failed "
+ "rc:x%x, fcf_index:"
+ "%d\n", rc,
+ phba->fcf.current_rec.fcf_indx);
+ spin_lock_irq(&phba->hbalock);
+ phba->fcf.fcf_flag &= ~FCF_DISCOVERY;
+ spin_unlock_irq(&phba->hbalock);
+ } else
+ goto out;
+ }
+ }
+
/* Check for retry */
if (lpfc_els_retry(phba, cmdiocb, rspiocb))
goto out;
@@ -797,13 +855,15 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
}
/* FLOGI failure */
- lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
- "0100 FLOGI failure Data: x%x x%x "
- "x%x\n",
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "0100 FLOGI failure Status:x%x/x%x TMO:x%x\n",
irsp->ulpStatus, irsp->un.ulpWord[4],
irsp->ulpTimeout);
goto flogifail;
}
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~FC_VPORT_CVL_RCVD;
+ spin_unlock_irq(shost->host_lock);
/*
* The FLogI succeeded. Sync the data for the CPU before
@@ -830,8 +890,18 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
else
rc = lpfc_cmpl_els_flogi_nport(vport, ndlp, sp);
- if (!rc)
+ if (!rc) {
+ /* Mark the FCF discovery process done */
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_FIP | LOG_ELS,
+ "2769 FLOGI successful on FCF record: "
+ "current_fcf_index:x%x, terminate FCF "
+ "round robin failover process\n",
+ phba->fcf.current_rec.fcf_indx);
+ spin_lock_irq(&phba->hbalock);
+ phba->fcf.fcf_flag &= ~FCF_DISCOVERY;
+ spin_unlock_irq(&phba->hbalock);
goto out;
+ }
}
flogifail:
@@ -969,7 +1039,7 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
* function returns, it does not guarantee all the IOCBs are actually aborted.
*
* Return code
- * 0 - Sucessfully issued abort iocb on all outstanding flogis (Always 0)
+ * 0 - Successfully issued abort iocb on all outstanding flogis (Always 0)
**/
int
lpfc_els_abort_flogi(struct lpfc_hba *phba)
@@ -1397,6 +1467,10 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
goto out;
}
/* PLOGI failed */
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "2753 PLOGI failure DID:%06X Status:x%x/x%x\n",
+ ndlp->nlp_DID, irsp->ulpStatus,
+ irsp->un.ulpWord[4]);
/* Do not call DSM for lpfc_els_abort'ed ELS cmds */
if (lpfc_error_lost_link(irsp))
rc = NLP_STE_FREED_NODE;
@@ -1565,6 +1639,10 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
goto out;
}
/* PRLI failed */
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "2754 PRLI failure DID:%06X Status:x%x/x%x\n",
+ ndlp->nlp_DID, irsp->ulpStatus,
+ irsp->un.ulpWord[4]);
/* Do not call DSM for lpfc_els_abort'ed ELS cmds */
if (lpfc_error_lost_link(irsp))
goto out;
@@ -1848,6 +1926,10 @@ lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
goto out;
}
/* ADISC failed */
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "2755 ADISC failure DID:%06X Status:x%x/x%x\n",
+ ndlp->nlp_DID, irsp->ulpStatus,
+ irsp->un.ulpWord[4]);
/* Do not call DSM for lpfc_els_abort'ed ELS cmds */
if (!lpfc_error_lost_link(irsp))
lpfc_disc_state_machine(vport, ndlp, cmdiocb,
@@ -1997,6 +2079,10 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
/* ELS command is being retried */
goto out;
/* LOGO failed */
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ "2756 LOGO failure DID:%06X Status:x%x/x%x\n",
+ ndlp->nlp_DID, irsp->ulpStatus,
+ irsp->un.ulpWord[4]);
/* Do not call DSM for lpfc_els_abort'ed ELS cmds */
if (lpfc_error_lost_link(irsp))
goto out;
@@ -2720,7 +2806,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
if (did == FDMI_DID)
retry = 1;
- if ((cmd == ELS_CMD_FLOGI) &&
+ if (((cmd == ELS_CMD_FLOGI) || (cmd == ELS_CMD_FDISC)) &&
(phba->fc_topology != TOPOLOGY_LOOP) &&
!lpfc_error_lost_link(irsp)) {
/* FLOGI retry policy */
@@ -3117,7 +3203,7 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
if (ndlp && NLP_CHK_NODE_ACT(ndlp) &&
(*((uint32_t *) (pcmd)) == ELS_CMD_LS_RJT)) {
/* A LS_RJT associated with Default RPI cleanup has its own
- * seperate code path.
+ * separate code path.
*/
if (!(ndlp->nlp_flag & NLP_RM_DFLT_RPI))
ls_rjt = 1;
@@ -4385,7 +4471,7 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
did = Fabric_DID;
- if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3))) {
+ if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3, 1))) {
/* For a FLOGI we accept, then if our portname is greater
* then the remote portname we initiate Nport login.
*/
@@ -5915,6 +6001,7 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
MAILBOX_t *mb = &pmb->u.mb;
+ int rc;
spin_lock_irq(shost->host_lock);
vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
@@ -5936,6 +6023,26 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
spin_unlock_irq(shost->host_lock);
lpfc_can_disctmo(vport);
break;
+ /* If reg_vpi fail with invalid VPI status, re-init VPI */
+ case 0x20:
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+ spin_unlock_irq(shost->host_lock);
+ lpfc_init_vpi(phba, pmb, vport->vpi);
+ pmb->vport = vport;
+ pmb->mbox_cmpl = lpfc_init_vpi_cmpl;
+ rc = lpfc_sli_issue_mbox(phba, pmb,
+ MBX_NOWAIT);
+ if (rc == MBX_NOT_FINISHED) {
+ lpfc_printf_vlog(vport,
+ KERN_ERR, LOG_MBOX,
+ "2732 Failed to issue INIT_VPI"
+ " mailbox command\n");
+ } else {
+ lpfc_nlp_put(ndlp);
+ return;
+ }
+
default:
/* Try to recover from this error */
lpfc_mbx_unreg_vpi(vport);
@@ -5949,13 +6056,22 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
break;
}
} else {
+ spin_lock_irq(shost->host_lock);
vport->vpi_state |= LPFC_VPI_REGISTERED;
- if (vport == phba->pport)
+ spin_unlock_irq(shost->host_lock);
+ if (vport == phba->pport) {
if (phba->sli_rev < LPFC_SLI_REV4)
lpfc_issue_fabric_reglogin(vport);
- else
- lpfc_issue_reg_vfi(vport);
- else
+ else {
+ /*
+ * If the physical port is instantiated using
+ * FDISC, do not start vport discovery.
+ */
+ if (vport->port_state != LPFC_FDISC)
+ lpfc_start_fdiscs(phba);
+ lpfc_do_scr_ns_plogi(phba, vport);
+ }
+ } else
lpfc_do_scr_ns_plogi(phba, vport);
}
@@ -5977,7 +6093,7 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
* This routine registers the @vport as a new virtual port with a HBA.
* It is done through a registering vpi mailbox command.
**/
-static void
+void
lpfc_register_new_vport(struct lpfc_hba *phba, struct lpfc_vport *vport,
struct lpfc_nodelist *ndlp)
{
@@ -6018,6 +6134,92 @@ mbox_err_exit:
}
/**
+ * lpfc_cancel_all_vport_retry_delay_timer - Cancel all vport retry delay timer
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine cancels the retry delay timers to all the vports.
+ **/
+void
+lpfc_cancel_all_vport_retry_delay_timer(struct lpfc_hba *phba)
+{
+ struct lpfc_vport **vports;
+ struct lpfc_nodelist *ndlp;
+ uint32_t link_state;
+ int i;
+
+ /* Treat this failure as linkdown for all vports */
+ link_state = phba->link_state;
+ lpfc_linkdown(phba);
+ phba->link_state = link_state;
+
+ vports = lpfc_create_vport_work_array(phba);
+
+ if (vports) {
+ for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
+ ndlp = lpfc_findnode_did(vports[i], Fabric_DID);
+ if (ndlp)
+ lpfc_cancel_retry_delay_tmo(vports[i], ndlp);
+ lpfc_els_flush_cmd(vports[i]);
+ }
+ lpfc_destroy_vport_work_array(phba, vports);
+ }
+}
+
+/**
+ * lpfc_retry_pport_discovery - Start timer to retry FLOGI.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine abort all pending discovery commands and
+ * start a timer to retry FLOGI for the physical port
+ * discovery.
+ **/
+void
+lpfc_retry_pport_discovery(struct lpfc_hba *phba)
+{
+ struct lpfc_nodelist *ndlp;
+ struct Scsi_Host *shost;
+
+ /* Cancel the all vports retry delay retry timers */
+ lpfc_cancel_all_vport_retry_delay_timer(phba);
+
+ /* If fabric require FLOGI, then re-instantiate physical login */
+ ndlp = lpfc_findnode_did(phba->pport, Fabric_DID);
+ if (!ndlp)
+ return;
+
+ shost = lpfc_shost_from_vport(phba->pport);
+ mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ);
+ spin_lock_irq(shost->host_lock);
+ ndlp->nlp_flag |= NLP_DELAY_TMO;
+ spin_unlock_irq(shost->host_lock);
+ ndlp->nlp_last_elscmd = ELS_CMD_FLOGI;
+ phba->pport->port_state = LPFC_FLOGI;
+ return;
+}
+
+/**
+ * lpfc_fabric_login_reqd - Check if FLOGI required.
+ * @phba: pointer to lpfc hba data structure.
+ * @cmdiocb: pointer to FDISC command iocb.
+ * @rspiocb: pointer to FDISC response iocb.
+ *
+ * This routine checks if a FLOGI is reguired for FDISC
+ * to succeed.
+ **/
+static int
+lpfc_fabric_login_reqd(struct lpfc_hba *phba,
+ struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
+{
+
+ if ((rspiocb->iocb.ulpStatus != IOSTAT_FABRIC_RJT) ||
+ (rspiocb->iocb.un.ulpWord[4] != RJT_LOGIN_REQUIRED))
+ return 0;
+ else
+ return 1;
+}
+
+/**
* lpfc_cmpl_els_fdisc - Completion function for fdisc iocb command
* @phba: pointer to lpfc hba data structure.
* @cmdiocb: pointer to lpfc command iocb data structure.
@@ -6066,6 +6268,12 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
irsp->ulpStatus, irsp->un.ulpWord[4], vport->fc_prevDID);
if (irsp->ulpStatus) {
+
+ if (lpfc_fabric_login_reqd(phba, cmdiocb, rspiocb)) {
+ lpfc_retry_pport_discovery(phba);
+ goto out;
+ }
+
/* Check for retry */
if (lpfc_els_retry(phba, cmdiocb, rspiocb))
goto out;
@@ -6076,6 +6284,7 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
goto fdisc_failed;
}
spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~FC_VPORT_CVL_RCVD;
vport->fc_flag |= FC_FABRIC;
if (vport->phba->fc_topology == TOPOLOGY_LOOP)
vport->fc_flag |= FC_PUBLIC_LOOP;
@@ -6103,10 +6312,14 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
lpfc_mbx_unreg_vpi(vport);
spin_lock_irq(shost->host_lock);
vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ vport->fc_flag |= FC_VPORT_NEEDS_INIT_VPI;
spin_unlock_irq(shost->host_lock);
}
- if (vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)
+ if (vport->fc_flag & FC_VPORT_NEEDS_INIT_VPI)
+ lpfc_issue_init_vpi(vport);
+ else if (vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)
lpfc_register_new_vport(phba, vport, ndlp);
else
lpfc_do_scr_ns_plogi(phba, vport);
@@ -6678,21 +6891,27 @@ lpfc_sli4_els_xri_aborted(struct lpfc_hba *phba,
struct lpfc_sglq *sglq_entry = NULL, *sglq_next = NULL;
unsigned long iflag = 0;
- spin_lock_irqsave(&phba->sli4_hba.abts_sgl_list_lock, iflag);
+ spin_lock_irqsave(&phba->hbalock, iflag);
+ spin_lock(&phba->sli4_hba.abts_sgl_list_lock);
list_for_each_entry_safe(sglq_entry, sglq_next,
&phba->sli4_hba.lpfc_abts_els_sgl_list, list) {
if (sglq_entry->sli4_xritag == xri) {
list_del(&sglq_entry->list);
- spin_unlock_irqrestore(
- &phba->sli4_hba.abts_sgl_list_lock,
- iflag);
- spin_lock_irqsave(&phba->hbalock, iflag);
-
list_add_tail(&sglq_entry->list,
&phba->sli4_hba.lpfc_sgl_list);
+ sglq_entry->state = SGL_FREED;
+ spin_unlock(&phba->sli4_hba.abts_sgl_list_lock);
spin_unlock_irqrestore(&phba->hbalock, iflag);
return;
}
}
- spin_unlock_irqrestore(&phba->sli4_hba.abts_sgl_list_lock, iflag);
+ spin_unlock(&phba->sli4_hba.abts_sgl_list_lock);
+ sglq_entry = __lpfc_get_active_sglq(phba, xri);
+ if (!sglq_entry || (sglq_entry->sli4_xritag != xri)) {
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
+ return;
+ }
+ sglq_entry->state = SGL_XRI_ABORTED;
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
+ return;
}