Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 695a814e authored by James Smart's avatar James Smart Committed by James Bottomley
Browse files

[SCSI] lpfc 8.3.8: BugFixes: Discovery relates changes



Discovery relates changes:
- Separated VPI_REGISTERED state of physical port into VFI_REGISTERED and
  VPI_REGISTERED state so that driver can unregister physical port VPI
  independent of VFI.
- Add code to unregister, re-init and re-register physical port VPI
  when physical port NportID change.
- Add code to unregister and re-register VPI of a vport when its Nport
  ID change.
- Add code in FDISC completion path to re-start FLOGI discovery when
  a FDISC complete with LOGIN_REQUIRED reason code.
- Fix a memory leak in lpfc_init_vpi_cmpl
- Add code to start a timer for vport to retry FDISC when CVL is received
  by a vport or physical port. If all Nports receive CVLs, then all timers
  are cancelled and a logical link level discovery will be started after
  one second.
- Flush ELS commands after killing all delayed ELS commands.

Signed-off-by: default avatarJames Smart <james.smart@emulex.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@suse.de>
parent 341af102
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -315,6 +315,9 @@ struct lpfc_vport {
#define FC_VPORT_NEEDS_REG_VPI	0x80000  /* Needs to have its vpi registered */
#define FC_RSCN_DEFERRED	0x100000 /* A deferred RSCN being processed */
#define FC_VPORT_NEEDS_INIT_VPI 0x200000 /* Need to INIT_VPI before FDISC */
#define FC_VPORT_CVL_RCVD	0x400000 /* VLink failed due to CVL	 */
#define FC_VFI_REGISTERED	0x800000 /* VFI is registered */
#define FC_FDISC_COMPLETED	0x1000000/* FDISC completed */

	uint32_t ct_flags;
#define FC_CT_RFF_ID		0x1	 /* RFF_ID accepted by switch */
+5 −0
Original line number Diff line number Diff line
@@ -44,6 +44,8 @@ int lpfc_reg_rpi(struct lpfc_hba *, uint16_t, uint32_t, uint8_t *,
void lpfc_unreg_login(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *);
void lpfc_unreg_did(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *);
void lpfc_reg_vpi(struct lpfc_vport *, LPFC_MBOXQ_t *);
void lpfc_register_new_vport(struct lpfc_hba *, struct lpfc_vport *,
			struct lpfc_nodelist *);
void lpfc_unreg_vpi(struct lpfc_hba *, uint16_t, LPFC_MBOXQ_t *);
void lpfc_init_link(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t);
void lpfc_request_features(struct lpfc_hba *, struct lpfcMboxq *);
@@ -52,10 +54,13 @@ struct lpfc_vport *lpfc_find_vport_by_did(struct lpfc_hba *, uint32_t);
void lpfc_cleanup_rcv_buffers(struct lpfc_vport *);
void lpfc_rcv_seq_check_edtov(struct lpfc_vport *);
void lpfc_cleanup_rpis(struct lpfc_vport *, int);
void lpfc_cleanup_pending_mbox(struct lpfc_vport *);
int lpfc_linkdown(struct lpfc_hba *);
void lpfc_linkdown_port(struct lpfc_vport *);
void lpfc_port_link_failure(struct lpfc_vport *);
void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_init_vpi_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_retry_pport_discovery(struct lpfc_hba *);

void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *, LPFC_MBOXQ_t *);
+118 −11
Original line number Diff line number Diff line
@@ -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;

@@ -604,10 +601,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_register_new_vport(phba, vport, ndlp);
		else
			lpfc_issue_reg_vfi(vport);
	}
	return 0;
@@ -804,6 +804,9 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
				 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
@@ -2720,7 +2723,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 */
@@ -5915,6 +5918,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 +5940,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 +5973,17 @@ 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 {
				lpfc_start_fdiscs(phba);
				lpfc_do_scr_ns_plogi(phba, vport);
			}
		} else
			lpfc_do_scr_ns_plogi(phba, vport);
	}

@@ -5977,7 +6005,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)
{
@@ -6017,6 +6045,78 @@ mbox_err_exit:
	return;
}

/**
 * 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_vport **vports;
	struct lpfc_nodelist *ndlp;
	struct Scsi_Host  *shost;
	int i;
	uint32_t link_state;

	/* 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);
	}

	/* 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.
@@ -6066,6 +6166,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 +6182,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;
+35 −1
Original line number Diff line number Diff line
@@ -706,6 +706,8 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove)
void
lpfc_port_link_failure(struct lpfc_vport *vport)
{
	lpfc_vport_set_state(vport, FC_VPORT_LINKDOWN);

	/* Cleanup any outstanding received buffers */
	lpfc_cleanup_rcv_buffers(vport);

@@ -1695,10 +1697,11 @@ out:
 *
 * This function handles completion of init vpi mailbox command.
 */
static void
void
lpfc_init_vpi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
{
	struct lpfc_vport *vport = mboxq->vport;
	struct lpfc_nodelist *ndlp;
	if (mboxq->u.mb.mbxStatus) {
		lpfc_printf_vlog(vport, KERN_ERR,
				LOG_MBOX,
@@ -1712,6 +1715,20 @@ lpfc_init_vpi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
	vport->fc_flag &= ~FC_VPORT_NEEDS_INIT_VPI;
	spin_unlock_irq(&phba->hbalock);

	/* If this port is physical port or FDISC is done, do reg_vpi */
	if ((phba->pport == vport) || (vport->port_state == LPFC_FDISC)) {
			ndlp = lpfc_findnode_did(vport, Fabric_DID);
			if (!ndlp)
				lpfc_printf_vlog(vport, KERN_ERR,
					LOG_DISCOVERY,
					"2731 Cannot find fabric "
					"controller node\n");
			else
				lpfc_register_new_vport(phba, vport, ndlp);
			mempool_free(mboxq, phba->mbox_mem_pool);
			return;
	}

	if (phba->link_flag & LS_NPIV_FAB_SUPPORTED)
		lpfc_initial_fdisc(vport);
	else {
@@ -1719,6 +1736,7 @@ lpfc_init_vpi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
				 "2606 No NPIV Fabric support\n");
	}
	mempool_free(mboxq, phba->mbox_mem_pool);
	return;
}

@@ -1814,6 +1832,9 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
	}
	/* The VPI is implicitly registered when the VFI is registered */
	vport->vpi_state |= LPFC_VPI_REGISTERED;
	vport->fc_flag |= FC_VFI_REGISTERED;

	vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;

	if (vport->port_state == LPFC_FABRIC_CFG_LINK) {
		lpfc_start_fdiscs(phba);
@@ -2333,6 +2354,7 @@ lpfc_mbx_cmpl_reg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
	}

	vport->vpi_state |= LPFC_VPI_REGISTERED;
	vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
	vport->num_disc_nodes = 0;
	/* go thru NPR list and issue ELS PLOGIs */
	if (vport->fc_npr_cnt)
@@ -4462,6 +4484,7 @@ lpfc_unregister_unused_fcf(struct lpfc_hba *phba)
	int rc;
	struct lpfc_vport **vports;
	int i;
	struct lpfc_nodelist *ndlp;

	spin_lock_irq(&phba->hbalock);
	/*
@@ -4489,6 +4512,10 @@ lpfc_unregister_unused_fcf(struct lpfc_hba *phba)
	if (vports &&
		(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED))
		for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
			/* Stop FLOGI/FDISC retries */
			ndlp = lpfc_findnode_did(vports[i], Fabric_DID);
			if (ndlp)
				lpfc_cancel_retry_delay_tmo(vports[i], ndlp);
			lpfc_mbx_unreg_vpi(vports[i]);
			spin_lock_irq(&phba->hbalock);
			vports[i]->fc_flag |= FC_VPORT_NEEDS_INIT_VPI;
@@ -4497,6 +4524,9 @@ lpfc_unregister_unused_fcf(struct lpfc_hba *phba)
		}
	lpfc_destroy_vport_work_array(phba, vports);

	/* Cleanup any outstanding ELS commands */
	lpfc_els_flush_all_cmd(phba);

	/* Unregister VFI */
	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
	if (!mbox) {
@@ -4521,6 +4551,10 @@ lpfc_unregister_unused_fcf(struct lpfc_hba *phba)
		return;
	}

	spin_lock_irq(&phba->hbalock);
	phba->pport->fc_flag &= ~FC_VFI_REGISTERED;
	spin_unlock_irq(&phba->hbalock);

	/* Unregister FCF */
	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
	if (!mbox) {
+41 −3
Original line number Diff line number Diff line
@@ -2246,6 +2246,9 @@ lpfc_offline_prep(struct lpfc_hba * phba)
			if (vports[i]->load_flag & FC_UNLOADING)
				continue;
			vports[i]->vpi_state &= ~LPFC_VPI_REGISTERED;
			vports[i]->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
			vports[i]->fc_flag &= ~FC_VFI_REGISTERED;

			shost =	lpfc_shost_from_vport(vports[i]);
			list_for_each_entry_safe(ndlp, next_ndlp,
						 &vports[i]->fc_nodes,
@@ -3007,6 +3010,9 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
	struct lpfc_nodelist *ndlp;
	struct Scsi_Host  *shost;
	uint32_t link_state;
	int active_vlink_present;
	struct lpfc_vport **vports;
	int i;

	phba->fc_eventTag = acqe_fcoe->event_tag;
	phba->fcoe_eventtag = acqe_fcoe->event_tag;
@@ -3074,14 +3080,46 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
		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);
		if (vport->port_type != LPFC_NPIV_PORT) {
		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);
		if (vports) {
			for (i = 0; i <= phba->max_vports && vports[i] != NULL;
					i++) {
				if ((!(vports[i]->fc_flag &
					FC_VPORT_CVL_RCVD)) &&
					(vports[i]->port_state > LPFC_FDISC)) {
					active_vlink_present = 1;
					break;
				}
			}
			lpfc_destroy_vport_work_array(phba, vports);
		}

		if (active_vlink_present) {
			/*
			 * If there are other active VLinks present,
			 * re-instantiate the Vlink using FDISC.
			 */
			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;
			vport->port_state = LPFC_FLOGI;
			ndlp->nlp_last_elscmd = ELS_CMD_FDISC;
			vport->port_state = LPFC_FDISC;
		} else {
			lpfc_retry_pport_discovery(phba);
		}
		break;
	default:
Loading