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

Commit 87af33fe authored by James Smart's avatar James Smart Committed by James Bottomley
Browse files

[SCSI] lpfc 8.2.3 : FC Discovery Fixes



FC Discovery Fixes:
- Fix up lpfc_drop_node() vs lpfc_nlp_not_used() usage
- Clear ADISC flag when unregistering RPI and REMOVE ndlps if in recovery.
- Fix usage of UNUSED list and ndlps
- Fix PLOGI race conditions
- Reset link if NameServer PLOGI errors occur
- Synchronize GID_FT queries with PLOGI receptions

Signed-off-by: default avatarJames Smart <James.Smart@emulex.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@HansenPartnership.com>
parent 98c9ea5c
Loading
Loading
Loading
Loading
+4 −0
Original line number Original line Diff line number Diff line
@@ -45,6 +45,7 @@ void lpfc_init_link(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t);
struct lpfc_vport *lpfc_find_vport_by_did(struct lpfc_hba *, uint32_t);
struct lpfc_vport *lpfc_find_vport_by_did(struct lpfc_hba *, uint32_t);
void lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove);
void lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove);
int lpfc_linkdown(struct lpfc_hba *);
int lpfc_linkdown(struct lpfc_hba *);
void lpfc_port_link_failure(struct lpfc_vport *);
void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *);


void lpfc_mbx_cmpl_clear_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_clear_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
@@ -74,6 +75,7 @@ void lpfc_disc_list_loopmap(struct lpfc_vport *);
void lpfc_disc_start(struct lpfc_vport *);
void lpfc_disc_start(struct lpfc_vport *);
void lpfc_disc_flush_list(struct lpfc_vport *);
void lpfc_disc_flush_list(struct lpfc_vport *);
void lpfc_cleanup_discovery_resources(struct lpfc_vport *);
void lpfc_cleanup_discovery_resources(struct lpfc_vport *);
void lpfc_cleanup(struct lpfc_vport *);
void lpfc_disc_timeout(unsigned long);
void lpfc_disc_timeout(unsigned long);


struct lpfc_nodelist *__lpfc_findnode_rpi(struct lpfc_vport *, uint16_t);
struct lpfc_nodelist *__lpfc_findnode_rpi(struct lpfc_vport *, uint16_t);
@@ -91,6 +93,8 @@ void lpfc_do_scr_ns_plogi(struct lpfc_hba *, struct lpfc_vport *);
int lpfc_check_sparm(struct lpfc_vport *, struct lpfc_nodelist *,
int lpfc_check_sparm(struct lpfc_vport *, struct lpfc_nodelist *,
		     struct serv_parm *, uint32_t);
		     struct serv_parm *, uint32_t);
int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist *);
int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist *);
void lpfc_more_plogi(struct lpfc_vport *);
void lpfc_end_rscn(struct lpfc_vport *);
int lpfc_els_chk_latt(struct lpfc_vport *);
int lpfc_els_chk_latt(struct lpfc_vport *);
int lpfc_els_abort_flogi(struct lpfc_hba *);
int lpfc_els_abort_flogi(struct lpfc_hba *);
int lpfc_initial_flogi(struct lpfc_vport *);
int lpfc_initial_flogi(struct lpfc_vport *);
+0 −1
Original line number Original line Diff line number Diff line
@@ -103,7 +103,6 @@ struct lpfc_nodelist {
#define NLP_RM_DFLT_RPI    0x4000000	/* need to remove leftover dflt RPI */
#define NLP_RM_DFLT_RPI    0x4000000	/* need to remove leftover dflt RPI */
#define NLP_NODEV_REMOVE   0x8000000	/* Defer removal till discovery ends */
#define NLP_NODEV_REMOVE   0x8000000	/* Defer removal till discovery ends */
#define NLP_TARGET_REMOVE  0x10000000   /* Target remove in process */
#define NLP_TARGET_REMOVE  0x10000000   /* Target remove in process */
#define NLP_DELAYED_RM     0x20000000   /* Defer UNUSED List removal */


/* There are 4 different double linked lists nodelist entries can reside on.
/* There are 4 different double linked lists nodelist entries can reside on.
 * The Port Login (PLOGI) list and Address Discovery (ADISC) list are used
 * The Port Login (PLOGI) list and Address Discovery (ADISC) list are used
+123 −108
Original line number Original line Diff line number Diff line
@@ -575,8 +575,13 @@ flogifail:


		/* Start discovery */
		/* Start discovery */
		lpfc_disc_start(vport);
		lpfc_disc_start(vport);
	} else if (((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) ||
			((irsp->un.ulpWord[4] != IOERR_SLI_ABORTED) &&
			(irsp->un.ulpWord[4] != IOERR_SLI_DOWN))) &&
			(phba->link_state != LPFC_CLEAR_LA)) {
		/* If FLOGI failed enable link interrupt. */
		lpfc_issue_clear_la(phba, vport);
	}
	}

out:
out:
	lpfc_els_free_iocb(phba, cmdiocb);
	lpfc_els_free_iocb(phba, cmdiocb);
}
}
@@ -711,13 +716,8 @@ lpfc_initial_flogi(struct lpfc_vport *vport)
		lpfc_nlp_init(vport, ndlp, Fabric_DID);
		lpfc_nlp_init(vport, ndlp, Fabric_DID);
	} else {
	} else {
		lpfc_dequeue_node(vport, ndlp);
		lpfc_dequeue_node(vport, ndlp);

		/* If we go thru this path, Fabric_DID ndlp is in the process
		 * of being removed. We need to bump the reference count by 1
		 * so it stays around all through this link up period.
		 */
		lpfc_nlp_get(ndlp);
	}
	}

	if (lpfc_issue_els_flogi(vport, ndlp, 0)) {
	if (lpfc_issue_els_flogi(vport, ndlp, 0)) {
		lpfc_nlp_put(ndlp);
		lpfc_nlp_put(ndlp);
	}
	}
@@ -746,7 +746,8 @@ lpfc_initial_fdisc(struct lpfc_vport *vport)
	}
	}
	return 1;
	return 1;
}
}
static void

void
lpfc_more_plogi(struct lpfc_vport *vport)
lpfc_more_plogi(struct lpfc_vport *vport)
{
{
	int sentplogi;
	int sentplogi;
@@ -813,8 +814,12 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
	lpfc_nlp_set_state(vport, new_ndlp, ndlp->nlp_state);
	lpfc_nlp_set_state(vport, new_ndlp, ndlp->nlp_state);


	/* Move this back to NPR state */
	/* Move this back to NPR state */
	if (memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)) == 0)
	if (memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)) == 0) {
		/* The new_ndlp is replacing ndlp totally, so we need
		 * to put ndlp on UNUSED list and try to free it.
		 */
		lpfc_drop_node(vport, ndlp);
		lpfc_drop_node(vport, ndlp);
	}
	else {
	else {
		lpfc_unreg_rpi(vport, ndlp);
		lpfc_unreg_rpi(vport, ndlp);
		ndlp->nlp_DID = 0; /* Two ndlps cannot have the same did */
		ndlp->nlp_DID = 0; /* Two ndlps cannot have the same did */
@@ -823,6 +828,27 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
	return new_ndlp;
	return new_ndlp;
}
}


void
lpfc_end_rscn(struct lpfc_vport *vport)
{
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);

	if (vport->fc_flag & FC_RSCN_MODE) {
		/*
		 * Check to see if more RSCNs came in while we were
		 * processing this one.
		 */
		if (vport->fc_rscn_id_cnt ||
		    (vport->fc_flag & FC_RSCN_DISCOVERY) != 0)
			lpfc_els_handle_rscn(vport);
		else {
			spin_lock_irq(shost->host_lock);
			vport->fc_flag &= ~FC_RSCN_MODE;
			spin_unlock_irq(shost->host_lock);
		}
	}
}

static void
static void
lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
		    struct lpfc_iocbq *rspiocb)
		    struct lpfc_iocbq *rspiocb)
@@ -893,13 +919,6 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
			goto out;
			goto out;
		}
		}
		/* PLOGI failed */
		/* PLOGI failed */
		if (ndlp->nlp_DID == NameServer_DID) {
			lpfc_vport_set_state(vport, FC_VPORT_FAILED);
			lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
					 "0250 Nameserver login error: "
					 "0x%x / 0x%x\n",
					 irsp->ulpStatus, irsp->un.ulpWord[4]);
		}
		/* Do not call DSM for lpfc_els_abort'ed ELS cmds */
		/* Do not call DSM for lpfc_els_abort'ed ELS cmds */
		if (lpfc_error_lost_link(irsp)) {
		if (lpfc_error_lost_link(irsp)) {
			rc = NLP_STE_FREED_NODE;
			rc = NLP_STE_FREED_NODE;
@@ -927,20 +946,7 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
			spin_unlock_irq(shost->host_lock);
			spin_unlock_irq(shost->host_lock);


			lpfc_can_disctmo(vport);
			lpfc_can_disctmo(vport);
			if (vport->fc_flag & FC_RSCN_MODE) {
			lpfc_end_rscn(vport);
				/*
				 * Check to see if more RSCNs came in while
				 * we were processing this one.
				 */
				if ((vport->fc_rscn_id_cnt == 0) &&
				    (!(vport->fc_flag & FC_RSCN_DISCOVERY))) {
					spin_lock_irq(shost->host_lock);
					vport->fc_flag &= ~FC_RSCN_MODE;
					spin_unlock_irq(shost->host_lock);
				} else {
					lpfc_els_handle_rscn(vport);
				}
			}
		}
		}
	}
	}


@@ -1160,8 +1166,6 @@ lpfc_more_adisc(struct lpfc_vport *vport)
static void
static void
lpfc_rscn_disc(struct lpfc_vport *vport)
lpfc_rscn_disc(struct lpfc_vport *vport)
{
{
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);

	lpfc_can_disctmo(vport);
	lpfc_can_disctmo(vport);


	/* RSCN discovery */
	/* RSCN discovery */
@@ -1170,19 +1174,7 @@ lpfc_rscn_disc(struct lpfc_vport *vport)
		if (lpfc_els_disc_plogi(vport))
		if (lpfc_els_disc_plogi(vport))
			return;
			return;


	if (vport->fc_flag & FC_RSCN_MODE) {
	lpfc_end_rscn(vport);
		/* Check to see if more RSCNs came in while we were
		 * processing this one.
		 */
		if ((vport->fc_rscn_id_cnt == 0) &&
		    (!(vport->fc_flag & FC_RSCN_DISCOVERY))) {
			spin_lock_irq(shost->host_lock);
			vport->fc_flag &= ~FC_RSCN_MODE;
			spin_unlock_irq(shost->host_lock);
		} else {
			lpfc_els_handle_rscn(vport);
		}
	}
}
}


static void
static void
@@ -1632,27 +1624,6 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
	return 0;
	return 0;
}
}


static void
lpfc_end_rscn(struct lpfc_vport *vport)
{
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);

	if (vport->fc_flag & FC_RSCN_MODE) {
		/*
		 * Check to see if more RSCNs came in while we were
		 * processing this one.
		 */
		if (vport->fc_rscn_id_cnt ||
		    (vport->fc_flag & FC_RSCN_DISCOVERY) != 0)
			lpfc_els_handle_rscn(vport);
		else {
			spin_lock_irq(shost->host_lock);
			vport->fc_flag &= ~FC_RSCN_MODE;
			spin_unlock_irq(shost->host_lock);
		}
	}
}

void
void
lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp)
lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp)
{
{
@@ -2069,17 +2040,10 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
}
}


int
int
lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb)
lpfc_els_free_data(struct lpfc_hba *phba, struct lpfc_dmabuf *buf_ptr1)
{
{
	struct lpfc_dmabuf *buf_ptr, *buf_ptr1;
	struct lpfc_dmabuf *buf_ptr;


	if (elsiocb->context1) {
		lpfc_nlp_put(elsiocb->context1);
		elsiocb->context1 = NULL;
	}
	/* context2  = cmd,  context2->next = rsp, context3 = bpl */
	if (elsiocb->context2) {
		buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2;
	/* Free the response before processing the command.  */
	/* Free the response before processing the command.  */
	if (!list_empty(&buf_ptr1->list)) {
	if (!list_empty(&buf_ptr1->list)) {
		list_remove_head(&buf_ptr1->list, buf_ptr,
		list_remove_head(&buf_ptr1->list, buf_ptr,
@@ -2090,12 +2054,35 @@ lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb)
	}
	}
	lpfc_mbuf_free(phba, buf_ptr1->virt, buf_ptr1->phys);
	lpfc_mbuf_free(phba, buf_ptr1->virt, buf_ptr1->phys);
	kfree(buf_ptr1);
	kfree(buf_ptr1);
	return 0;
}
}


	if (elsiocb->context3) {
int
		buf_ptr = (struct lpfc_dmabuf *) elsiocb->context3;
lpfc_els_free_bpl(struct lpfc_hba *phba, struct lpfc_dmabuf *buf_ptr)
{
	lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
	lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
	kfree(buf_ptr);
	kfree(buf_ptr);
	return 0;
}

int
lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb)
{
	struct lpfc_dmabuf *buf_ptr, *buf_ptr1;

	if (elsiocb->context1) {
		lpfc_nlp_put(elsiocb->context1);
		elsiocb->context1 = NULL;
	}
	/* context2  = cmd,  context2->next = rsp, context3 = bpl */
	if (elsiocb->context2) {
		buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2;
		lpfc_els_free_data(phba, buf_ptr1);
	}

	if (elsiocb->context3) {
		buf_ptr = (struct lpfc_dmabuf *) elsiocb->context3;
		lpfc_els_free_bpl(phba, buf_ptr);
	}
	}
	lpfc_sli_release_iocbq(phba, elsiocb);
	lpfc_sli_release_iocbq(phba, elsiocb);
	return 0;
	return 0;
@@ -2119,15 +2106,15 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
			 "Data: x%x x%x x%x\n",
			 "Data: x%x x%x x%x\n",
			 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
			 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
			 ndlp->nlp_rpi);
			 ndlp->nlp_rpi);
	switch (ndlp->nlp_state) {

	case NLP_STE_UNUSED_NODE:	/* node is just allocated */
	if (ndlp->nlp_state == NLP_STE_NPR_NODE) {
		lpfc_drop_node(vport, ndlp);
		/* NPort Recovery mode or node is just allocated */
		break;
		if (!lpfc_nlp_not_used(ndlp)) {
	case NLP_STE_NPR_NODE:		/* NPort Recovery mode */
			/* If the ndlp is being used by another discovery
			 * thread, just unregister the RPI.
			 */
			lpfc_unreg_rpi(vport, ndlp);
			lpfc_unreg_rpi(vport, ndlp);
		break;
		}
	default:
		break;
	}
	}
	lpfc_els_free_iocb(phba, cmdiocb);
	lpfc_els_free_iocb(phba, cmdiocb);
	return;
	return;
@@ -2161,14 +2148,26 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
	struct lpfc_vport *vport = ndlp ? ndlp->vport : NULL;
	struct lpfc_vport *vport = ndlp ? ndlp->vport : NULL;
	struct Scsi_Host  *shost = vport ? lpfc_shost_from_vport(vport) : NULL;
	struct Scsi_Host  *shost = vport ? lpfc_shost_from_vport(vport) : NULL;
	IOCB_t  *irsp;
	IOCB_t  *irsp;
	uint8_t *pcmd;
	LPFC_MBOXQ_t *mbox = NULL;
	LPFC_MBOXQ_t *mbox = NULL;
	struct lpfc_dmabuf *mp = NULL;
	struct lpfc_dmabuf *mp = NULL;
	uint32_t ls_rjt = 0;


	irsp = &rspiocb->iocb;
	irsp = &rspiocb->iocb;


	if (cmdiocb->context_un.mbox)
	if (cmdiocb->context_un.mbox)
		mbox = cmdiocb->context_un.mbox;
		mbox = cmdiocb->context_un.mbox;


	/* First determine if this is a LS_RJT cmpl */
	pcmd = (uint8_t *) (((struct lpfc_dmabuf *) cmdiocb->context2)->virt);
	if (*((uint32_t *) (pcmd)) == ELS_CMD_LS_RJT) {
		/* A LS_RJT associated with Default RPI cleanup
		 * has its own seperate code path.
		 */
		if (!(ndlp->nlp_flag & NLP_RM_DFLT_RPI))
			ls_rjt = 1;
	}

	/* Check to see if link went down during discovery */
	/* Check to see if link went down during discovery */
	if (!ndlp || lpfc_els_chk_latt(vport)) {
	if (!ndlp || lpfc_els_chk_latt(vport)) {
		if (mbox) {
		if (mbox) {
@@ -2247,7 +2246,16 @@ out:
		spin_lock_irq(shost->host_lock);
		spin_lock_irq(shost->host_lock);
		ndlp->nlp_flag &= ~(NLP_ACC_REGLOGIN | NLP_RM_DFLT_RPI);
		ndlp->nlp_flag &= ~(NLP_ACC_REGLOGIN | NLP_RM_DFLT_RPI);
		spin_unlock_irq(shost->host_lock);
		spin_unlock_irq(shost->host_lock);

		/* If the node is not being used by another discovery thread,
		 * and we are sending a reject, we are done with it.
		 * Release driver reference count here and free associated
		 * resources.
		 */
		if (ls_rjt)
			lpfc_nlp_not_used(ndlp);
	}
	}

	lpfc_els_free_iocb(phba, cmdiocb);
	lpfc_els_free_iocb(phba, cmdiocb);
	return;
	return;
}
}
@@ -2418,18 +2426,6 @@ lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError,
	elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
	elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
	rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
	rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);


	/* If the node is in the UNUSED state, and we are sending
	 * a reject, we are done with it.  Release driver reference
	 * count here.  The outstanding els will release its reference on
	 * completion, as long as the ndlp stays in the UNUSED list,
	 * and the node can be freed then.
	 */
	if ((ndlp->nlp_state == NLP_STE_UNUSED_NODE) &&
		!(ndlp->nlp_flag & NLP_DELAYED_RM)) {
		ndlp->nlp_flag |= NLP_DELAYED_RM;
		lpfc_nlp_put(ndlp);
	}

	if (rc == IOCB_ERROR) {
	if (rc == IOCB_ERROR) {
		lpfc_els_free_iocb(phba, elsiocb);
		lpfc_els_free_iocb(phba, elsiocb);
		return 1;
		return 1;
@@ -2715,7 +2711,10 @@ lpfc_els_disc_plogi(struct lpfc_vport *vport)
			}
			}
		}
		}
	}
	}
	if (sentplogi == 0) {
	if (sentplogi) {
		lpfc_set_disctmo(vport);
	}
	else {
		spin_lock_irq(shost->host_lock);
		spin_lock_irq(shost->host_lock);
		vport->fc_flag &= ~FC_NLP_MORE;
		vport->fc_flag &= ~FC_NLP_MORE;
		spin_unlock_irq(shost->host_lock);
		spin_unlock_irq(shost->host_lock);
@@ -3533,6 +3532,7 @@ lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
					 * other NLP_FABRIC logins
					 * other NLP_FABRIC logins
					 */
					 */
					lpfc_drop_node(vport, ndlp);
					lpfc_drop_node(vport, ndlp);

				} else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
				} else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
					/* Fail outstanding I/O now since this
					/* Fail outstanding I/O now since this
					 * device is marked for PLOGI
					 * device is marked for PLOGI
@@ -3781,6 +3781,7 @@ static void
lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
		      struct lpfc_vport *vport, struct lpfc_iocbq *elsiocb)
		      struct lpfc_vport *vport, struct lpfc_iocbq *elsiocb)
{
{
	struct Scsi_Host  *shost;
	struct lpfc_nodelist *ndlp;
	struct lpfc_nodelist *ndlp;
	struct ls_rjt stat;
	struct ls_rjt stat;
	uint32_t *payload;
	uint32_t *payload;
@@ -3826,6 +3827,14 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
			ndlp->nlp_type |= NLP_FABRIC;
			ndlp->nlp_type |= NLP_FABRIC;
		}
		}
	}
	}
	else {
		if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) {
			/* This is simular to the new node path */
			lpfc_nlp_get(ndlp);
			lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
			newnode = 1;
		}
	}


	phba->fc_stat.elsRcvFrame++;
	phba->fc_stat.elsRcvFrame++;
	if (elsiocb->context1)
	if (elsiocb->context1)
@@ -3853,6 +3862,12 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
			rjt_err = LSRJT_UNABLE_TPC;
			rjt_err = LSRJT_UNABLE_TPC;
			break;
			break;
		}
		}

		shost = lpfc_shost_from_vport(vport);
		spin_lock_irq(shost->host_lock);
		ndlp->nlp_flag &= ~NLP_TARGET_REMOVE;
		spin_unlock_irq(shost->host_lock);

		lpfc_disc_state_machine(vport, ndlp, elsiocb,
		lpfc_disc_state_machine(vport, ndlp, elsiocb,
					NLP_EVT_RCV_PLOGI);
					NLP_EVT_RCV_PLOGI);


@@ -3864,7 +3879,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,


		phba->fc_stat.elsRcvFLOGI++;
		phba->fc_stat.elsRcvFLOGI++;
		lpfc_els_rcv_flogi(vport, elsiocb, ndlp);
		lpfc_els_rcv_flogi(vport, elsiocb, ndlp);
		if (newnode && (!(ndlp->nlp_flag & NLP_DELAYED_RM)))
		if (newnode)
			lpfc_nlp_put(ndlp);
			lpfc_nlp_put(ndlp);
		break;
		break;
	case ELS_CMD_LOGO:
	case ELS_CMD_LOGO:
@@ -3894,7 +3909,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
	case ELS_CMD_RSCN:
	case ELS_CMD_RSCN:
		phba->fc_stat.elsRcvRSCN++;
		phba->fc_stat.elsRcvRSCN++;
		lpfc_els_rcv_rscn(vport, elsiocb, ndlp);
		lpfc_els_rcv_rscn(vport, elsiocb, ndlp);
		if (newnode && (!(ndlp->nlp_flag & NLP_DELAYED_RM)))
		if (newnode)
			lpfc_nlp_put(ndlp);
			lpfc_nlp_put(ndlp);
		break;
		break;
	case ELS_CMD_ADISC:
	case ELS_CMD_ADISC:
@@ -3966,7 +3981,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,


		phba->fc_stat.elsRcvLIRR++;
		phba->fc_stat.elsRcvLIRR++;
		lpfc_els_rcv_lirr(vport, elsiocb, ndlp);
		lpfc_els_rcv_lirr(vport, elsiocb, ndlp);
		if (newnode && (!(ndlp->nlp_flag & NLP_DELAYED_RM)))
		if (newnode)
			lpfc_nlp_put(ndlp);
			lpfc_nlp_put(ndlp);
		break;
		break;
	case ELS_CMD_RPS:
	case ELS_CMD_RPS:
@@ -3976,7 +3991,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,


		phba->fc_stat.elsRcvRPS++;
		phba->fc_stat.elsRcvRPS++;
		lpfc_els_rcv_rps(vport, elsiocb, ndlp);
		lpfc_els_rcv_rps(vport, elsiocb, ndlp);
		if (newnode && (!(ndlp->nlp_flag & NLP_DELAYED_RM)))
		if (newnode)
			lpfc_nlp_put(ndlp);
			lpfc_nlp_put(ndlp);
		break;
		break;
	case ELS_CMD_RPL:
	case ELS_CMD_RPL:
@@ -3986,7 +4001,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,


		phba->fc_stat.elsRcvRPL++;
		phba->fc_stat.elsRcvRPL++;
		lpfc_els_rcv_rpl(vport, elsiocb, ndlp);
		lpfc_els_rcv_rpl(vport, elsiocb, ndlp);
		if (newnode && (!(ndlp->nlp_flag & NLP_DELAYED_RM)))
		if (newnode)
			lpfc_nlp_put(ndlp);
			lpfc_nlp_put(ndlp);
		break;
		break;
	case ELS_CMD_RNID:
	case ELS_CMD_RNID:
@@ -3996,7 +4011,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,


		phba->fc_stat.elsRcvRNID++;
		phba->fc_stat.elsRcvRNID++;
		lpfc_els_rcv_rnid(vport, elsiocb, ndlp);
		lpfc_els_rcv_rnid(vport, elsiocb, ndlp);
		if (newnode && (!(ndlp->nlp_flag & NLP_DELAYED_RM)))
		if (newnode)
			lpfc_nlp_put(ndlp);
			lpfc_nlp_put(ndlp);
		break;
		break;
	default:
	default:
@@ -4011,7 +4026,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
				 "0115 Unknown ELS command x%x "
				 "0115 Unknown ELS command x%x "
				 "received from NPORT x%x\n", cmd, did);
				 "received from NPORT x%x\n", cmd, did);
		if (newnode && (!(ndlp->nlp_flag & NLP_DELAYED_RM)))
		if (newnode)
			lpfc_nlp_put(ndlp);
			lpfc_nlp_put(ndlp);
		break;
		break;
	}
	}
+45 −51
Original line number Original line Diff line number Diff line
@@ -157,6 +157,8 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
	struct lpfc_vport *vport;
	struct lpfc_vport *vport;
	struct lpfc_hba   *phba;
	struct lpfc_hba   *phba;
	uint8_t *name;
	uint8_t *name;
	int  put_node;
	int  put_rport;
	int warn_on = 0;
	int warn_on = 0;


	rport = ndlp->rport;
	rport = ndlp->rport;
@@ -178,9 +180,6 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
		return;
		return;


	if (ndlp->nlp_type & NLP_FABRIC) {
	if (ndlp->nlp_type & NLP_FABRIC) {
		int  put_node;
		int  put_rport;

		/* We will clean up these Nodes in linkup */
		/* We will clean up these Nodes in linkup */
		put_node = rdata->pnode != NULL;
		put_node = rdata->pnode != NULL;
		put_rport = ndlp->rport != NULL;
		put_rport = ndlp->rport != NULL;
@@ -222,15 +221,6 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
				 ndlp->nlp_state, ndlp->nlp_rpi);
				 ndlp->nlp_state, ndlp->nlp_rpi);
	}
	}


	if (!(vport->load_flag & FC_UNLOADING) &&
	    !(ndlp->nlp_flag & NLP_DELAY_TMO) &&
	    !(ndlp->nlp_flag & NLP_NPR_2B_DISC) &&
	    (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE))
		lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM);
	else {
		int  put_node;
		int  put_rport;

	put_node = rdata->pnode != NULL;
	put_node = rdata->pnode != NULL;
	put_rport = ndlp->rport != NULL;
	put_rport = ndlp->rport != NULL;
	rdata->pnode = NULL;
	rdata->pnode = NULL;
@@ -239,6 +229,12 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
		lpfc_nlp_put(ndlp);
		lpfc_nlp_put(ndlp);
	if (put_rport)
	if (put_rport)
		put_device(&rport->dev);
		put_device(&rport->dev);

	if (!(vport->load_flag & FC_UNLOADING) &&
	    !(ndlp->nlp_flag & NLP_DELAY_TMO) &&
	    !(ndlp->nlp_flag & NLP_NPR_2B_DISC) &&
	    (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE)) {
		lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM);
	}
	}
}
}


@@ -546,11 +542,9 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove)
	}
	}
}
}


static void
void
lpfc_port_link_failure(struct lpfc_vport *vport)
lpfc_port_link_failure(struct lpfc_vport *vport)
{
{
	struct lpfc_nodelist *ndlp, *next_ndlp;

	/* Cleanup any outstanding RSCN activity */
	/* Cleanup any outstanding RSCN activity */
	lpfc_els_flush_rscn(vport);
	lpfc_els_flush_rscn(vport);


@@ -559,11 +553,6 @@ lpfc_port_link_failure(struct lpfc_vport *vport)


	lpfc_cleanup_rpis(vport, 0);
	lpfc_cleanup_rpis(vport, 0);


	/* free any ndlp's on unused list */
	list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp)
		if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
			lpfc_drop_node(vport, ndlp);

	/* Turn off discovery timer if its running */
	/* Turn off discovery timer if its running */
	lpfc_can_disctmo(vport);
	lpfc_can_disctmo(vport);
}
}
@@ -670,7 +659,6 @@ static void
lpfc_linkup_port(struct lpfc_vport *vport)
lpfc_linkup_port(struct lpfc_vport *vport)
{
{
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
	struct lpfc_nodelist *ndlp, *next_ndlp;
	struct lpfc_hba  *phba = vport->phba;
	struct lpfc_hba  *phba = vport->phba;


	if ((vport->load_flag & FC_UNLOADING) != 0)
	if ((vport->load_flag & FC_UNLOADING) != 0)
@@ -697,11 +685,6 @@ lpfc_linkup_port(struct lpfc_vport *vport)
	if (vport->fc_flag & FC_LBIT)
	if (vport->fc_flag & FC_LBIT)
		lpfc_linkup_cleanup_nodes(vport);
		lpfc_linkup_cleanup_nodes(vport);


				/* free any ndlp's in unused state */
	list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes,
				 nlp_listp)
		if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
			lpfc_drop_node(vport, ndlp);
}
}


static int
static int
@@ -1345,7 +1328,9 @@ out:
		lpfc_mbuf_free(phba, mp->virt, mp->phys);
		lpfc_mbuf_free(phba, mp->virt, mp->phys);
		kfree(mp);
		kfree(mp);
		mempool_free(pmb, phba->mbox_mem_pool);
		mempool_free(pmb, phba->mbox_mem_pool);
		lpfc_drop_node(vport, ndlp);

		/* If no other thread is using the ndlp, free it */
		lpfc_nlp_not_used(ndlp);


		if (phba->fc_topology == TOPOLOGY_LOOP) {
		if (phba->fc_topology == TOPOLOGY_LOOP) {
			/*
			/*
@@ -1605,16 +1590,6 @@ lpfc_nlp_set_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
		ndlp->nlp_type &= ~NLP_FC_NODE;
		ndlp->nlp_type &= ~NLP_FC_NODE;
	}
	}


	if ((old_state == NLP_STE_UNUSED_NODE) &&
	    (state != NLP_STE_UNUSED_NODE) &&
	    (ndlp->nlp_flag & NLP_DELAYED_RM)) {
		/* We are using the ndlp after all, so reverse
		 * the delayed removal of it.
		 */
		ndlp->nlp_flag &= ~NLP_DELAYED_RM;
		lpfc_nlp_get(ndlp);
	}

	if (list_empty(&ndlp->nlp_listp)) {
	if (list_empty(&ndlp->nlp_listp)) {
		spin_lock_irq(shost->host_lock);
		spin_lock_irq(shost->host_lock);
		list_add_tail(&ndlp->nlp_listp, &vport->fc_nodes);
		list_add_tail(&ndlp->nlp_listp, &vport->fc_nodes);
@@ -1646,8 +1621,15 @@ lpfc_dequeue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
void
void
lpfc_drop_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
lpfc_drop_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
{
{
	/*
	 * Use of lpfc_drop_node and UNUSED list. lpfc_drop_node should
	 * be used if we wish to issue the "last" lpfc_nlp_put() to remove
	 * the ndlp from the vport.  The ndlp resides on the UNUSED list
	 * until ALL other outstanding threads have completed. Thus, if a
	 * ndlp is on the UNUSED list already, we should never do another
	 * lpfc_drop_node() on it.
	 */
	lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
	lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
	if (!(ndlp->nlp_flag & NLP_DELAYED_RM))
	lpfc_nlp_put(ndlp);
	lpfc_nlp_put(ndlp);
	return;
	return;
}
}
@@ -2116,6 +2098,12 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did)
	}
	}
	if (vport->fc_flag & FC_RSCN_MODE) {
	if (vport->fc_flag & FC_RSCN_MODE) {
		if (lpfc_rscn_payload_check(vport, did)) {
		if (lpfc_rscn_payload_check(vport, did)) {
			/* If we've already recieved a PLOGI from this NPort
			 * we don't need to try to discover it again.
			 */
			if (ndlp->nlp_flag & NLP_RCV_PLOGI)
				return NULL;

			spin_lock_irq(shost->host_lock);
			spin_lock_irq(shost->host_lock);
			ndlp->nlp_flag |= NLP_NPR_2B_DISC;
			ndlp->nlp_flag |= NLP_NPR_2B_DISC;
			spin_unlock_irq(shost->host_lock);
			spin_unlock_irq(shost->host_lock);
@@ -2128,8 +2116,13 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did)
		} else
		} else
			ndlp = NULL;
			ndlp = NULL;
	} else {
	} else {
		/* If we've already recieved a PLOGI from this NPort,
		 * or we are already in the process of discovery on it,
		 * we don't need to try to discover it again.
		 */
		if (ndlp->nlp_state == NLP_STE_ADISC_ISSUE ||
		if (ndlp->nlp_state == NLP_STE_ADISC_ISSUE ||
		    ndlp->nlp_state == NLP_STE_PLOGI_ISSUE)
		    ndlp->nlp_state == NLP_STE_PLOGI_ISSUE ||
		    ndlp->nlp_flag & NLP_RCV_PLOGI)
			return NULL;
			return NULL;
		lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
		lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
		spin_lock_irq(shost->host_lock);
		spin_lock_irq(shost->host_lock);
@@ -2497,6 +2490,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
			if (ndlp->nlp_type & NLP_FABRIC) {
			if (ndlp->nlp_type & NLP_FABRIC) {
				/* Clean up the ndlp on Fabric connections */
				/* Clean up the ndlp on Fabric connections */
				lpfc_drop_node(vport, ndlp);
				lpfc_drop_node(vport, ndlp);

			} else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
			} else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
				/* Fail outstanding IO now since device
				/* Fail outstanding IO now since device
				 * is marked for PLOGI.
				 * is marked for PLOGI.
@@ -2515,7 +2509,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
		/* Initial FLOGI timeout */
		/* Initial FLOGI timeout */
		lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
		lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
				 "0222 Initial %s timeout\n",
				 "0222 Initial %s timeout\n",
				 vport->vpi ? "FLOGI" : "FDISC");
				 vport->vpi ? "FDISC" : "FLOGI");


		/* Assume no Fabric and go on with discovery.
		/* Assume no Fabric and go on with discovery.
		 * Check for outstanding ELS FLOGI to abort.
		 * Check for outstanding ELS FLOGI to abort.
@@ -2537,10 +2531,10 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
		/* Next look for NameServer ndlp */
		/* Next look for NameServer ndlp */
		ndlp = lpfc_findnode_did(vport, NameServer_DID);
		ndlp = lpfc_findnode_did(vport, NameServer_DID);
		if (ndlp)
		if (ndlp)
			lpfc_nlp_put(ndlp);
			lpfc_els_abort(phba, ndlp);
		/* Start discovery */

		lpfc_disc_start(vport);
		/* ReStart discovery */
		break;
		goto restart_disc;


	case LPFC_NS_QRY:
	case LPFC_NS_QRY:
	/* Check for wait for NameServer Rsp timeout */
	/* Check for wait for NameServer Rsp timeout */
@@ -2559,6 +2553,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
		}
		}
		vport->fc_ns_retry = 0;
		vport->fc_ns_retry = 0;


restart_disc:
		/*
		/*
		 * Discovery is over.
		 * Discovery is over.
		 * set port_state to PORT_READY if SLI2.
		 * set port_state to PORT_READY if SLI2.
@@ -2731,8 +2726,7 @@ __lpfc_find_node(struct lpfc_vport *vport, node_filter filter, void *param)
	struct lpfc_nodelist *ndlp;
	struct lpfc_nodelist *ndlp;


	list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
	list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
		if (ndlp->nlp_state != NLP_STE_UNUSED_NODE &&
		if (filter(ndlp, param))
		    filter(ndlp, param))
			return ndlp;
			return ndlp;
	}
	}
	return NULL;
	return NULL;
+55 −11
Original line number Original line Diff line number Diff line
@@ -1334,15 +1334,35 @@ lpfc_hba_init(struct lpfc_hba *phba, uint32_t *hbainit)
	kfree(HashWorking);
	kfree(HashWorking);
}
}


static void
void
lpfc_cleanup(struct lpfc_vport *vport)
lpfc_cleanup(struct lpfc_vport *vport)
{
{
	struct lpfc_hba   *phba = vport->phba;
	struct lpfc_nodelist *ndlp, *next_ndlp;
	struct lpfc_nodelist *ndlp, *next_ndlp;


	/* clean up phba - lpfc specific */
	if (phba->link_state > LPFC_LINK_DOWN)
	lpfc_can_disctmo(vport);
		lpfc_port_link_failure(vport);
	list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp)

		lpfc_nlp_put(ndlp);
	list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
		if (ndlp->nlp_type & NLP_FABRIC)
			lpfc_disc_state_machine(vport, ndlp, NULL,
					NLP_EVT_DEVICE_RECOVERY);
		lpfc_disc_state_machine(vport, ndlp, NULL,
					     NLP_EVT_DEVICE_RM);
	}

	/* At this point, ALL ndlp's should be gone */
	while (!list_empty(&vport->fc_nodes)) {

		list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes,
			nlp_listp) {
			lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
				"0233 Nodelist x%x not free: %d\n",
				ndlp->nlp_DID,
				atomic_read(&ndlp->kref.refcount));
			lpfc_drop_node(vport, ndlp);
		}
	}
	return;
	return;
}
}


@@ -1463,6 +1483,8 @@ lpfc_offline_prep(struct lpfc_hba * phba)
{
{
	struct lpfc_vport *vport = phba->pport;
	struct lpfc_vport *vport = phba->pport;
	struct lpfc_nodelist  *ndlp, *next_ndlp;
	struct lpfc_nodelist  *ndlp, *next_ndlp;
	struct lpfc_vport **vports;
	int i;


	if (vport->fc_flag & FC_OFFLINE_MODE)
	if (vport->fc_flag & FC_OFFLINE_MODE)
		return;
		return;
@@ -1471,10 +1493,32 @@ lpfc_offline_prep(struct lpfc_hba * phba)


	lpfc_linkdown(phba);
	lpfc_linkdown(phba);


	/* Issue an unreg_login to all nodes */
	/* Issue an unreg_login to all nodes on all vports */
	list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp)
	vports = lpfc_create_vport_work_array(phba);
		if (ndlp->nlp_state != NLP_STE_UNUSED_NODE)
	if (vports != NULL) {
			lpfc_unreg_rpi(vport, ndlp);
		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
			struct Scsi_Host *shost;

			shost =	lpfc_shost_from_vport(vports[i]);
			list_for_each_entry_safe(ndlp, next_ndlp,
						 &vports[i]->fc_nodes,
						 nlp_listp) {
				if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
					continue;
				if (ndlp->nlp_type & NLP_FABRIC) {
					lpfc_disc_state_machine(vports[i], ndlp,
						NULL, NLP_EVT_DEVICE_RECOVERY);
					lpfc_disc_state_machine(vports[i], ndlp,
						NULL, NLP_EVT_DEVICE_RM);
				}
				spin_lock_irq(shost->host_lock);
				ndlp->nlp_flag &= ~NLP_NPR_ADISC;
				spin_unlock_irq(shost->host_lock);
				lpfc_unreg_rpi(vports[i], ndlp);
			}
		}
	}
	lpfc_destroy_vport_work_array(vports);


	lpfc_sli_flush_mbox_queue(phba);
	lpfc_sli_flush_mbox_queue(phba);
}
}
@@ -1508,7 +1552,6 @@ lpfc_offline(struct lpfc_hba *phba)
	if (vports != NULL)
	if (vports != NULL)
		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
			shost = lpfc_shost_from_vport(vports[i]);
			shost = lpfc_shost_from_vport(vports[i]);
			lpfc_cleanup(vports[i]);
			spin_lock_irq(shost->host_lock);
			spin_lock_irq(shost->host_lock);
			vports[i]->work_port_events = 0;
			vports[i]->work_port_events = 0;
			vports[i]->fc_flag |= FC_OFFLINE_MODE;
			vports[i]->fc_flag |= FC_OFFLINE_MODE;
@@ -2061,6 +2104,8 @@ lpfc_pci_remove_one(struct pci_dev *pdev)


	fc_remove_host(shost);
	fc_remove_host(shost);
	scsi_remove_host(shost);
	scsi_remove_host(shost);
	lpfc_cleanup(vport);

	/*
	/*
	 * Bring down the SLI Layer. This step disable all interrupts,
	 * Bring down the SLI Layer. This step disable all interrupts,
	 * clears the rings, discards all mailbox commands, and resets
	 * clears the rings, discards all mailbox commands, and resets
@@ -2075,7 +2120,6 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
	spin_unlock_irq(&phba->hbalock);
	spin_unlock_irq(&phba->hbalock);


	lpfc_debugfs_terminate(vport);
	lpfc_debugfs_terminate(vport);
	lpfc_cleanup(vport);


	kthread_stop(phba->worker_thread);
	kthread_stop(phba->worker_thread);


Loading