|
@@ -2385,6 +2385,8 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|
|
IOCB_t *irsp;
|
|
|
struct lpfc_sli *psli;
|
|
|
struct lpfcMboxq *mbox;
|
|
|
+ unsigned long flags;
|
|
|
+ uint32_t skip_recovery = 0;
|
|
|
|
|
|
psli = &phba->sli;
|
|
|
/* we pass cmdiocb to state machine which needs rspiocb as well */
|
|
@@ -2399,47 +2401,52 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|
|
"LOGO cmpl: status:x%x/x%x did:x%x",
|
|
|
irsp->ulpStatus, irsp->un.ulpWord[4],
|
|
|
ndlp->nlp_DID);
|
|
|
+
|
|
|
/* LOGO completes to NPort <nlp_DID> */
|
|
|
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
|
|
|
"0105 LOGO completes to NPort x%x "
|
|
|
"Data: x%x x%x x%x x%x\n",
|
|
|
ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4],
|
|
|
irsp->ulpTimeout, vport->num_disc_nodes);
|
|
|
- /* Check to see if link went down during discovery */
|
|
|
- if (lpfc_els_chk_latt(vport))
|
|
|
+
|
|
|
+ if (lpfc_els_chk_latt(vport)) {
|
|
|
+ skip_recovery = 1;
|
|
|
goto out;
|
|
|
+ }
|
|
|
|
|
|
+ /* Check to see if link went down during discovery */
|
|
|
if (ndlp->nlp_flag & NLP_TARGET_REMOVE) {
|
|
|
/* NLP_EVT_DEVICE_RM should unregister the RPI
|
|
|
* which should abort all outstanding IOs.
|
|
|
*/
|
|
|
lpfc_disc_state_machine(vport, ndlp, cmdiocb,
|
|
|
NLP_EVT_DEVICE_RM);
|
|
|
+ skip_recovery = 1;
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
if (irsp->ulpStatus) {
|
|
|
/* Check for retry */
|
|
|
- if (lpfc_els_retry(phba, cmdiocb, rspiocb))
|
|
|
+ if (lpfc_els_retry(phba, cmdiocb, rspiocb)) {
|
|
|
/* ELS command is being retried */
|
|
|
+ skip_recovery = 1;
|
|
|
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))
|
|
|
+ if (lpfc_error_lost_link(irsp)) {
|
|
|
+ skip_recovery = 1;
|
|
|
goto out;
|
|
|
- else
|
|
|
- lpfc_disc_state_machine(vport, ndlp, cmdiocb,
|
|
|
- NLP_EVT_CMPL_LOGO);
|
|
|
- } else
|
|
|
- /* Good status, call state machine.
|
|
|
- * This will unregister the rpi if needed.
|
|
|
- */
|
|
|
- lpfc_disc_state_machine(vport, ndlp, cmdiocb,
|
|
|
- NLP_EVT_CMPL_LOGO);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Call state machine. This will unregister the rpi if needed. */
|
|
|
+ lpfc_disc_state_machine(vport, ndlp, cmdiocb, NLP_EVT_CMPL_LOGO);
|
|
|
+
|
|
|
out:
|
|
|
lpfc_els_free_iocb(phba, cmdiocb);
|
|
|
/* If we are in pt2pt mode, we could rcv new S_ID on PLOGI */
|
|
@@ -2454,9 +2461,30 @@ out:
|
|
|
if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT) ==
|
|
|
MBX_NOT_FINISHED) {
|
|
|
mempool_free(mbox, phba->mbox_mem_pool);
|
|
|
+ skip_recovery = 1;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If the node is a target, the handling attempts to recover the port.
|
|
|
+ * For any other port type, the rpi is unregistered as an implicit
|
|
|
+ * LOGO.
|
|
|
+ */
|
|
|
+ if ((ndlp->nlp_type & NLP_FCP_TARGET) && (skip_recovery == 0)) {
|
|
|
+ lpfc_cancel_retry_delay_tmo(vport, ndlp);
|
|
|
+ spin_lock_irqsave(shost->host_lock, flags);
|
|
|
+ ndlp->nlp_flag |= NLP_NPR_2B_DISC;
|
|
|
+ spin_unlock_irqrestore(shost->host_lock, flags);
|
|
|
+
|
|
|
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
|
|
|
+ "3187 LOGO completes to NPort x%x: Start "
|
|
|
+ "Recovery Data: x%x x%x x%x x%x\n",
|
|
|
+ ndlp->nlp_DID, irsp->ulpStatus,
|
|
|
+ irsp->un.ulpWord[4], irsp->ulpTimeout,
|
|
|
+ vport->num_disc_nodes);
|
|
|
+ lpfc_disc_start(vport);
|
|
|
+ }
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -2519,10 +2547,27 @@ lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
|
|
|
"Issue LOGO: did:x%x",
|
|
|
ndlp->nlp_DID, 0, 0);
|
|
|
|
|
|
+ /*
|
|
|
+ * If we are issuing a LOGO, we may try to recover the remote NPort
|
|
|
+ * by issuing a PLOGI later. Even though we issue ELS cmds by the
|
|
|
+ * VPI, if we have a valid RPI, and that RPI gets unreg'ed while
|
|
|
+ * that ELS command is in-flight, the HBA returns a IOERR_INVALID_RPI
|
|
|
+ * for that ELS cmd. To avoid this situation, lets get rid of the
|
|
|
+ * RPI right now, before any ELS cmds are sent.
|
|
|
+ */
|
|
|
+ spin_lock_irq(shost->host_lock);
|
|
|
+ ndlp->nlp_flag |= NLP_ISSUE_LOGO;
|
|
|
+ spin_unlock_irq(shost->host_lock);
|
|
|
+ if (lpfc_unreg_rpi(vport, ndlp)) {
|
|
|
+ lpfc_els_free_iocb(phba, elsiocb);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
phba->fc_stat.elsXmitLOGO++;
|
|
|
elsiocb->iocb_cmpl = lpfc_cmpl_els_logo;
|
|
|
spin_lock_irq(shost->host_lock);
|
|
|
ndlp->nlp_flag |= NLP_LOGO_SND;
|
|
|
+ ndlp->nlp_flag &= ~NLP_ISSUE_LOGO;
|
|
|
spin_unlock_irq(shost->host_lock);
|
|
|
rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
|
|
|
|
|
@@ -2938,7 +2983,7 @@ lpfc_els_retry_delay_handler(struct lpfc_nodelist *ndlp)
|
|
|
case ELS_CMD_LOGO:
|
|
|
if (!lpfc_issue_els_logo(vport, ndlp, retry)) {
|
|
|
ndlp->nlp_prev_state = ndlp->nlp_state;
|
|
|
- lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
|
|
|
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_LOGO_ISSUE);
|
|
|
}
|
|
|
break;
|
|
|
case ELS_CMD_FDISC:
|
|
@@ -3291,7 +3336,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
|
|
|
return 1;
|
|
|
case ELS_CMD_LOGO:
|
|
|
ndlp->nlp_prev_state = ndlp->nlp_state;
|
|
|
- lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
|
|
|
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_LOGO_ISSUE);
|
|
|
lpfc_issue_els_logo(vport, ndlp, cmdiocb->retry);
|
|
|
return 1;
|
|
|
}
|
|
@@ -3551,13 +3596,17 @@ lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
|
|
|
lpfc_mbuf_free(phba, mp->virt, mp->phys);
|
|
|
kfree(mp);
|
|
|
mempool_free(pmb, phba->mbox_mem_pool);
|
|
|
- if (ndlp && NLP_CHK_NODE_ACT(ndlp)) {
|
|
|
- lpfc_nlp_put(ndlp);
|
|
|
- /* This is the end of the default RPI cleanup logic for this
|
|
|
- * ndlp. If no other discovery threads are using this ndlp.
|
|
|
- * we should free all resources associated with it.
|
|
|
- */
|
|
|
- lpfc_nlp_not_used(ndlp);
|
|
|
+ if (ndlp) {
|
|
|
+ if (NLP_CHK_NODE_ACT(ndlp)) {
|
|
|
+ lpfc_nlp_put(ndlp);
|
|
|
+ /* This is the end of the default RPI cleanup logic for
|
|
|
+ * this ndlp. If no other discovery threads are using
|
|
|
+ * this ndlp, free all resources associated with it.
|
|
|
+ */
|
|
|
+ lpfc_nlp_not_used(ndlp);
|
|
|
+ } else {
|
|
|
+ lpfc_drop_node(ndlp->vport, ndlp);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
return;
|
|
@@ -8003,3 +8052,47 @@ lpfc_sli4_els_xri_aborted(struct lpfc_hba *phba,
|
|
|
spin_unlock_irqrestore(&phba->hbalock, iflag);
|
|
|
return;
|
|
|
}
|
|
|
+
|
|
|
+/* lpfc_sli_abts_recover_port - Recover a port that failed a BLS_ABORT req.
|
|
|
+ * @vport: pointer to virtual port object.
|
|
|
+ * @ndlp: nodelist pointer for the impacted node.
|
|
|
+ *
|
|
|
+ * The driver calls this routine in response to an SLI4 XRI ABORT CQE
|
|
|
+ * or an SLI3 ASYNC_STATUS_CN event from the port. For either event,
|
|
|
+ * the driver is required to send a LOGO to the remote node before it
|
|
|
+ * attempts to recover its login to the remote node.
|
|
|
+ */
|
|
|
+void
|
|
|
+lpfc_sli_abts_recover_port(struct lpfc_vport *vport,
|
|
|
+ struct lpfc_nodelist *ndlp)
|
|
|
+{
|
|
|
+ struct Scsi_Host *shost;
|
|
|
+ struct lpfc_hba *phba;
|
|
|
+ unsigned long flags = 0;
|
|
|
+
|
|
|
+ shost = lpfc_shost_from_vport(vport);
|
|
|
+ phba = vport->phba;
|
|
|
+ if (ndlp->nlp_state != NLP_STE_MAPPED_NODE) {
|
|
|
+ lpfc_printf_log(phba, KERN_INFO,
|
|
|
+ LOG_SLI, "3093 No rport recovery needed. "
|
|
|
+ "rport in state 0x%x\n", ndlp->nlp_state);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
|
|
|
+ "3094 Start rport recovery on shost id 0x%x "
|
|
|
+ "fc_id 0x%06x vpi 0x%x rpi 0x%x state 0x%x "
|
|
|
+ "flags 0x%x\n",
|
|
|
+ shost->host_no, ndlp->nlp_DID,
|
|
|
+ vport->vpi, ndlp->nlp_rpi, ndlp->nlp_state,
|
|
|
+ ndlp->nlp_flag);
|
|
|
+ /*
|
|
|
+ * The rport is not responding. Remove the FCP-2 flag to prevent
|
|
|
+ * an ADISC in the follow-up recovery code.
|
|
|
+ */
|
|
|
+ spin_lock_irqsave(shost->host_lock, flags);
|
|
|
+ ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE;
|
|
|
+ spin_unlock_irqrestore(shost->host_lock, flags);
|
|
|
+ lpfc_issue_els_logo(vport, ndlp, 0);
|
|
|
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_LOGO_ISSUE);
|
|
|
+}
|
|
|
+
|