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

Commit 98c9ea5c authored by James Smart's avatar James Smart Committed by James Bottomley
Browse files

[SCSI] lpfc 8.2.3 : Miscellaneous Small Fixes - part 1



Miscellaneous Small Fixes - part 1
- Fix typo kmzlloc -> kzalloc
- Fix discovery ndlp use after free panic
- Fix link event causing flood of 0108 messages
- Relieve some mbox congestion on link up with 100 vports
- Fix broken vport parameters
- Prevent lock recursion in logo_reglogin_issue
- Split uses of error variable in lpfc_pci_probe_one into retval and error
- Remove completion code related to dev_loss_tmo
- Remove unused LPFC_MAX_HBQ #define
- Don't compare pointers to 0 for sparse
- Make 2 functions static for sparse
- Fix default rpi cleanup code causing rogue ndlps to remain on the NPR list
- Remove annoying ELS messages when driver is unloaded
- Fix Cannot issue Register Fabric login problems on link up
- Remove LPFC_EVT_DEV_LOSS_DELAY
- Fix FC port swap test leads to device going offline
- Fix vport CT flags to only be set when accepted
- Add code to handle signals during vport_create
- Fix too many retries in FC-AL mode
- Pull lpfc_port_link_failure out of lpfc_linkdown_port

Signed-off-by: default avatarJames Smart <James.Smart@emulex.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@HansenPartnership.com>
parent 0b727fea
Loading
Loading
Loading
Loading
+58 −4
Original line number Original line Diff line number Diff line
@@ -2363,13 +2363,67 @@ struct fc_function_template lpfc_transport_functions = {
	.dev_loss_tmo_callbk = lpfc_dev_loss_tmo_callbk,
	.dev_loss_tmo_callbk = lpfc_dev_loss_tmo_callbk,
	.terminate_rport_io = lpfc_terminate_rport_io,
	.terminate_rport_io = lpfc_terminate_rport_io,


	/* Vport fields are filled in at runtime based on enable_npiv */
	.vport_create = NULL,
	.vport_delete = NULL,
	.vport_disable = NULL,
	.dd_fcvport_size = sizeof(struct lpfc_vport *),
	.dd_fcvport_size = sizeof(struct lpfc_vport *),
};
};


struct fc_function_template lpfc_vport_transport_functions = {
	/* fixed attributes the driver supports */
	.show_host_node_name = 1,
	.show_host_port_name = 1,
	.show_host_supported_classes = 1,
	.show_host_supported_fc4s = 1,
	.show_host_supported_speeds = 1,
	.show_host_maxframe_size = 1,

	/* dynamic attributes the driver supports */
	.get_host_port_id = lpfc_get_host_port_id,
	.show_host_port_id = 1,

	.get_host_port_type = lpfc_get_host_port_type,
	.show_host_port_type = 1,

	.get_host_port_state = lpfc_get_host_port_state,
	.show_host_port_state = 1,

	/* active_fc4s is shown but doesn't change (thus no get function) */
	.show_host_active_fc4s = 1,

	.get_host_speed = lpfc_get_host_speed,
	.show_host_speed = 1,

	.get_host_fabric_name = lpfc_get_host_fabric_name,
	.show_host_fabric_name = 1,

	/*
	 * The LPFC driver treats linkdown handling as target loss events
	 * so there are no sysfs handlers for link_down_tmo.
	 */

	.get_fc_host_stats = lpfc_get_stats,
	.reset_fc_host_stats = lpfc_reset_stats,

	.dd_fcrport_size = sizeof(struct lpfc_rport_data),
	.show_rport_maxframe_size = 1,
	.show_rport_supported_classes = 1,

	.set_rport_dev_loss_tmo = lpfc_set_rport_loss_tmo,
	.show_rport_dev_loss_tmo = 1,

	.get_starget_port_id  = lpfc_get_starget_port_id,
	.show_starget_port_id = 1,

	.get_starget_node_name = lpfc_get_starget_node_name,
	.show_starget_node_name = 1,

	.get_starget_port_name = lpfc_get_starget_port_name,
	.show_starget_port_name = 1,

	.dev_loss_tmo_callbk = lpfc_dev_loss_tmo_callbk,
	.terminate_rport_io = lpfc_terminate_rport_io,

	.vport_disable = lpfc_vport_disable,
};

void
void
lpfc_get_cfgparam(struct lpfc_hba *phba)
lpfc_get_cfgparam(struct lpfc_hba *phba)
{
{
+2 −0
Original line number Original line Diff line number Diff line
@@ -68,6 +68,7 @@ int lpfc_check_sli_ndlp(struct lpfc_hba *, struct lpfc_sli_ring *,
void lpfc_nlp_init(struct lpfc_vport *, struct lpfc_nodelist *, uint32_t);
void lpfc_nlp_init(struct lpfc_vport *, struct lpfc_nodelist *, uint32_t);
struct lpfc_nodelist *lpfc_nlp_get(struct lpfc_nodelist *);
struct lpfc_nodelist *lpfc_nlp_get(struct lpfc_nodelist *);
int  lpfc_nlp_put(struct lpfc_nodelist *);
int  lpfc_nlp_put(struct lpfc_nodelist *);
int  lpfc_nlp_not_used(struct lpfc_nodelist *ndlp);
struct lpfc_nodelist *lpfc_setup_disc_node(struct lpfc_vport *, uint32_t);
struct lpfc_nodelist *lpfc_setup_disc_node(struct lpfc_vport *, uint32_t);
void lpfc_disc_list_loopmap(struct lpfc_vport *);
void lpfc_disc_list_loopmap(struct lpfc_vport *);
void lpfc_disc_start(struct lpfc_vport *);
void lpfc_disc_start(struct lpfc_vport *);
@@ -260,6 +261,7 @@ extern struct class_device_attribute *lpfc_vport_attrs[];
extern struct scsi_host_template lpfc_template;
extern struct scsi_host_template lpfc_template;
extern struct scsi_host_template lpfc_vport_template;
extern struct scsi_host_template lpfc_vport_template;
extern struct fc_function_template lpfc_transport_functions;
extern struct fc_function_template lpfc_transport_functions;
extern struct fc_function_template lpfc_vport_transport_functions;
extern int lpfc_sli_mode;
extern int lpfc_sli_mode;
extern int lpfc_enable_npiv;
extern int lpfc_enable_npiv;


+51 −11
Original line number Original line Diff line number Diff line
@@ -458,7 +458,7 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
			    ((lpfc_find_vport_by_did(phba, Did) == NULL) ||
			    ((lpfc_find_vport_by_did(phba, Did) == NULL) ||
			     vport->cfg_peer_port_login)) {
			     vport->cfg_peer_port_login)) {
				if ((vport->port_type != LPFC_NPIV_PORT) ||
				if ((vport->port_type != LPFC_NPIV_PORT) ||
				    (!vport->ct_flags & FC_CT_RFF_ID) ||
				    (!(vport->ct_flags & FC_CT_RFF_ID)) ||
				    (!vport->cfg_restrict_login)) {
				    (!vport->cfg_restrict_login)) {
					ndlp = lpfc_setup_disc_node(vport, Did);
					ndlp = lpfc_setup_disc_node(vport, Did);
					if (ndlp) {
					if (ndlp) {
@@ -854,8 +854,16 @@ lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
	IOCB_t *irsp = &rspiocb->iocb;
	IOCB_t *irsp = &rspiocb->iocb;
	struct lpfc_vport *vport = cmdiocb->vport;
	struct lpfc_vport *vport = cmdiocb->vport;


	if (irsp->ulpStatus == IOSTAT_SUCCESS)
	if (irsp->ulpStatus == IOSTAT_SUCCESS) {
		struct lpfc_dmabuf *outp;
		struct lpfc_sli_ct_request *CTrsp;

		outp = (struct lpfc_dmabuf *) cmdiocb->context2;
		CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
		if (CTrsp->CommandResponse.bits.CmdRsp ==
		    be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
			vport->ct_flags |= FC_CT_RFT_ID;
			vport->ct_flags |= FC_CT_RFT_ID;
	}
	lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
	lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
	return;
	return;
}
}
@@ -867,8 +875,16 @@ lpfc_cmpl_ct_cmd_rnn_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
	IOCB_t *irsp = &rspiocb->iocb;
	IOCB_t *irsp = &rspiocb->iocb;
	struct lpfc_vport *vport = cmdiocb->vport;
	struct lpfc_vport *vport = cmdiocb->vport;


	if (irsp->ulpStatus == IOSTAT_SUCCESS)
	if (irsp->ulpStatus == IOSTAT_SUCCESS) {
		struct lpfc_dmabuf *outp;
		struct lpfc_sli_ct_request *CTrsp;

		outp = (struct lpfc_dmabuf *) cmdiocb->context2;
		CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
		if (CTrsp->CommandResponse.bits.CmdRsp ==
		    be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
			vport->ct_flags |= FC_CT_RNN_ID;
			vport->ct_flags |= FC_CT_RNN_ID;
	}
	lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
	lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
	return;
	return;
}
}
@@ -880,8 +896,16 @@ lpfc_cmpl_ct_cmd_rspn_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
	IOCB_t *irsp = &rspiocb->iocb;
	IOCB_t *irsp = &rspiocb->iocb;
	struct lpfc_vport *vport = cmdiocb->vport;
	struct lpfc_vport *vport = cmdiocb->vport;


	if (irsp->ulpStatus == IOSTAT_SUCCESS)
	if (irsp->ulpStatus == IOSTAT_SUCCESS) {
		struct lpfc_dmabuf *outp;
		struct lpfc_sli_ct_request *CTrsp;

		outp = (struct lpfc_dmabuf *) cmdiocb->context2;
		CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
		if (CTrsp->CommandResponse.bits.CmdRsp ==
		    be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
			vport->ct_flags |= FC_CT_RSPN_ID;
			vport->ct_flags |= FC_CT_RSPN_ID;
	}
	lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
	lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
	return;
	return;
}
}
@@ -893,8 +917,16 @@ lpfc_cmpl_ct_cmd_rsnn_nn(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
	IOCB_t *irsp = &rspiocb->iocb;
	IOCB_t *irsp = &rspiocb->iocb;
	struct lpfc_vport *vport = cmdiocb->vport;
	struct lpfc_vport *vport = cmdiocb->vport;


	if (irsp->ulpStatus == IOSTAT_SUCCESS)
	if (irsp->ulpStatus == IOSTAT_SUCCESS) {
		struct lpfc_dmabuf *outp;
		struct lpfc_sli_ct_request *CTrsp;

		outp = (struct lpfc_dmabuf *) cmdiocb->context2;
		CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
		if (CTrsp->CommandResponse.bits.CmdRsp ==
		    be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
			vport->ct_flags |= FC_CT_RSNN_NN;
			vport->ct_flags |= FC_CT_RSNN_NN;
	}
	lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
	lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
	return;
	return;
}
}
@@ -918,8 +950,16 @@ lpfc_cmpl_ct_cmd_rff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
	IOCB_t *irsp = &rspiocb->iocb;
	IOCB_t *irsp = &rspiocb->iocb;
	struct lpfc_vport *vport = cmdiocb->vport;
	struct lpfc_vport *vport = cmdiocb->vport;


	if (irsp->ulpStatus == IOSTAT_SUCCESS)
	if (irsp->ulpStatus == IOSTAT_SUCCESS) {
		struct lpfc_dmabuf *outp;
		struct lpfc_sli_ct_request *CTrsp;

		outp = (struct lpfc_dmabuf *) cmdiocb->context2;
		CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
		if (CTrsp->CommandResponse.bits.CmdRsp ==
		    be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
			vport->ct_flags |= FC_CT_RFF_ID;
			vport->ct_flags |= FC_CT_RFF_ID;
	}
	lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
	lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
	return;
	return;
}
}
+1 −1
Original line number Original line Diff line number Diff line
@@ -36,7 +36,6 @@ enum lpfc_work_type {
	LPFC_EVT_WARM_START,
	LPFC_EVT_WARM_START,
	LPFC_EVT_KILL,
	LPFC_EVT_KILL,
	LPFC_EVT_ELS_RETRY,
	LPFC_EVT_ELS_RETRY,
	LPFC_EVT_DEV_LOSS_DELAY,
	LPFC_EVT_DEV_LOSS,
	LPFC_EVT_DEV_LOSS,
};
};


@@ -104,6 +103,7 @@ 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
+114 −40
Original line number Original line Diff line number Diff line
@@ -109,9 +109,10 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,


	/* fill in BDEs for command */
	/* fill in BDEs for command */
	/* Allocate buffer for command payload */
	/* Allocate buffer for command payload */
	if (((pcmd = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL)) == 0) ||
	pcmd = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
	    ((pcmd->virt = lpfc_mbuf_alloc(phba,
	if (pcmd)
					   MEM_PRI, &(pcmd->phys))) == 0)) {
		pcmd->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &pcmd->phys);
	if (!pcmd || !pcmd->virt) {
		kfree(pcmd);
		kfree(pcmd);


		lpfc_sli_release_iocbq(phba, elsiocb);
		lpfc_sli_release_iocbq(phba, elsiocb);
@@ -126,7 +127,7 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
		if (prsp)
		if (prsp)
			prsp->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
			prsp->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
						     &prsp->phys);
						     &prsp->phys);
		if (prsp == 0 || prsp->virt == 0) {
		if (!prsp || !prsp->virt) {
			kfree(prsp);
			kfree(prsp);
			lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
			lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
			kfree(pcmd);
			kfree(pcmd);
@@ -143,7 +144,7 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
	if (pbuflist)
	if (pbuflist)
		pbuflist->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
		pbuflist->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
						 &pbuflist->phys);
						 &pbuflist->phys);
	if (pbuflist == 0 || pbuflist->virt == 0) {
	if (!pbuflist || !pbuflist->virt) {
		lpfc_sli_release_iocbq(phba, elsiocb);
		lpfc_sli_release_iocbq(phba, elsiocb);
		lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
		lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
		lpfc_mbuf_free(phba, prsp->virt, prsp->phys);
		lpfc_mbuf_free(phba, prsp->virt, prsp->phys);
@@ -234,15 +235,20 @@ lpfc_issue_fabric_reglogin(struct lpfc_vport *vport)
	struct lpfc_nodelist *ndlp;
	struct lpfc_nodelist *ndlp;
	struct serv_parm *sp;
	struct serv_parm *sp;
	int rc;
	int rc;
	int err = 0;


	sp = &phba->fc_fabparam;
	sp = &phba->fc_fabparam;
	ndlp = lpfc_findnode_did(vport, Fabric_DID);
	ndlp = lpfc_findnode_did(vport, Fabric_DID);
	if (!ndlp)
	if (!ndlp) {
		err = 1;
		goto fail;
		goto fail;
	}


	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
	if (!mbox)
	if (!mbox) {
		err = 2;
		goto fail;
		goto fail;
	}


	vport->port_state = LPFC_FABRIC_CFG_LINK;
	vport->port_state = LPFC_FABRIC_CFG_LINK;
	lpfc_config_link(phba, mbox);
	lpfc_config_link(phba, mbox);
@@ -250,24 +256,32 @@ lpfc_issue_fabric_reglogin(struct lpfc_vport *vport)
	mbox->vport = vport;
	mbox->vport = vport;


	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
	if (rc == MBX_NOT_FINISHED)
	if (rc == MBX_NOT_FINISHED) {
		err = 3;
		goto fail_free_mbox;
		goto fail_free_mbox;
	}


	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
	if (!mbox)
	if (!mbox) {
		err = 4;
		goto fail;
		goto fail;
	}
	rc = lpfc_reg_login(phba, vport->vpi, Fabric_DID, (uint8_t *)sp, mbox,
	rc = lpfc_reg_login(phba, vport->vpi, Fabric_DID, (uint8_t *)sp, mbox,
			    0);
			    0);
	if (rc)
	if (rc) {
		err = 5;
		goto fail_free_mbox;
		goto fail_free_mbox;
	}


	mbox->mbox_cmpl = lpfc_mbx_cmpl_fabric_reg_login;
	mbox->mbox_cmpl = lpfc_mbx_cmpl_fabric_reg_login;
	mbox->vport = vport;
	mbox->vport = vport;
	mbox->context2 = lpfc_nlp_get(ndlp);
	mbox->context2 = lpfc_nlp_get(ndlp);


	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
	if (rc == MBX_NOT_FINISHED)
	if (rc == MBX_NOT_FINISHED) {
		err = 6;
		goto fail_issue_reg_login;
		goto fail_issue_reg_login;
	}


	return 0;
	return 0;


@@ -282,7 +296,7 @@ fail_free_mbox:
fail:
fail:
	lpfc_vport_set_state(vport, FC_VPORT_FAILED);
	lpfc_vport_set_state(vport, FC_VPORT_FAILED);
	lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
	lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
		"0249 Cannot issue Register Fabric login\n");
		"0249 Cannot issue Register Fabric login: Err %d\n", err);
	return -ENXIO;
	return -ENXIO;
}
}


@@ -684,6 +698,9 @@ lpfc_initial_flogi(struct lpfc_vport *vport)
	struct lpfc_hba *phba = vport->phba;
	struct lpfc_hba *phba = vport->phba;
	struct lpfc_nodelist *ndlp;
	struct lpfc_nodelist *ndlp;


	vport->port_state = LPFC_FLOGI;
	lpfc_set_disctmo(vport);

	/* First look for the Fabric ndlp */
	/* First look for the Fabric ndlp */
	ndlp = lpfc_findnode_did(vport, Fabric_DID);
	ndlp = lpfc_findnode_did(vport, Fabric_DID);
	if (!ndlp) {
	if (!ndlp) {
@@ -694,6 +711,12 @@ 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);
@@ -932,6 +955,7 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry)
	struct lpfc_hba  *phba = vport->phba;
	struct lpfc_hba  *phba = vport->phba;
	struct serv_parm *sp;
	struct serv_parm *sp;
	IOCB_t *icmd;
	IOCB_t *icmd;
	struct lpfc_nodelist *ndlp;
	struct lpfc_iocbq *elsiocb;
	struct lpfc_iocbq *elsiocb;
	struct lpfc_sli_ring *pring;
	struct lpfc_sli_ring *pring;
	struct lpfc_sli *psli;
	struct lpfc_sli *psli;
@@ -942,8 +966,11 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry)
	psli = &phba->sli;
	psli = &phba->sli;
	pring = &psli->ring[LPFC_ELS_RING];	/* ELS ring */
	pring = &psli->ring[LPFC_ELS_RING];	/* ELS ring */


	ndlp = lpfc_findnode_did(vport, did);
	/* If ndlp if not NULL, we will bump the reference count on it */

	cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm));
	cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm));
	elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, NULL, did,
	elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, did,
				     ELS_CMD_PLOGI);
				     ELS_CMD_PLOGI);
	if (!elsiocb)
	if (!elsiocb)
		return 1;
		return 1;
@@ -1412,6 +1439,13 @@ lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
	psli = &phba->sli;
	psli = &phba->sli;
	pring = &psli->ring[LPFC_ELS_RING];
	pring = &psli->ring[LPFC_ELS_RING];


	spin_lock_irq(shost->host_lock);
	if (ndlp->nlp_flag & NLP_LOGO_SND) {
		spin_unlock_irq(shost->host_lock);
		return 0;
	}
	spin_unlock_irq(shost->host_lock);

	cmdsize = (2 * sizeof(uint32_t)) + sizeof(struct lpfc_name);
	cmdsize = (2 * sizeof(uint32_t)) + sizeof(struct lpfc_name);
	elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
	elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
				     ndlp->nlp_DID, ELS_CMD_LOGO);
				     ndlp->nlp_DID, ELS_CMD_LOGO);
@@ -1758,6 +1792,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
	uint32_t *elscmd;
	uint32_t *elscmd;
	struct ls_rjt stat;
	struct ls_rjt stat;
	int retry = 0, maxretry = lpfc_max_els_tries, delay = 0;
	int retry = 0, maxretry = lpfc_max_els_tries, delay = 0;
	int logerr = 0;
	uint32_t cmd = 0;
	uint32_t cmd = 0;
	uint32_t did;
	uint32_t did;


@@ -1814,6 +1849,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
			break;
			break;


		case IOERR_NO_RESOURCES:
		case IOERR_NO_RESOURCES:
			logerr = 1; /* HBA out of resources */
			retry = 1;
			retry = 1;
			if (cmdiocb->retry > 100)
			if (cmdiocb->retry > 100)
				delay = 100;
				delay = 100;
@@ -1842,6 +1878,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,


	case IOSTAT_NPORT_BSY:
	case IOSTAT_NPORT_BSY:
	case IOSTAT_FABRIC_BSY:
	case IOSTAT_FABRIC_BSY:
		logerr = 1; /* Fabric / Remote NPort out of resources */
		retry = 1;
		retry = 1;
		break;
		break;


@@ -1922,6 +1959,15 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
	if (did == FDMI_DID)
	if (did == FDMI_DID)
		retry = 1;
		retry = 1;


	if ((cmd == ELS_CMD_FLOGI) &&
	    (phba->fc_topology != TOPOLOGY_LOOP)) {
		/* FLOGI retry policy */
		retry = 1;
		maxretry = 48;
		if (cmdiocb->retry >= 32)
			delay = 1000;
	}

	if ((++cmdiocb->retry) >= maxretry) {
	if ((++cmdiocb->retry) >= maxretry) {
		phba->fc_stat.elsRetryExceeded++;
		phba->fc_stat.elsRetryExceeded++;
		retry = 0;
		retry = 0;
@@ -2005,11 +2051,20 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
		}
		}
	}
	}
	/* No retry ELS command <elsCmd> to remote NPORT <did> */
	/* No retry ELS command <elsCmd> to remote NPORT <did> */
	if (logerr) {
		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
			 "0137 No retry ELS command x%x to remote "
			 "NPORT x%x: Out of Resources: Error:x%x/%x\n",
			 cmd, did, irsp->ulpStatus,
			 irsp->un.ulpWord[4]);
	}
	else {
		lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
			 "0108 No retry ELS command x%x to remote "
			 "0108 No retry ELS command x%x to remote "
			 "NPORT x%x Retried:%d Error:x%x/%x\n",
			 "NPORT x%x Retried:%d Error:x%x/%x\n",
			 cmd, did, cmdiocb->retry, irsp->ulpStatus,
			 cmd, did, cmdiocb->retry, irsp->ulpStatus,
			 irsp->un.ulpWord[4]);
			 irsp->un.ulpWord[4]);
	}
	return 0;
	return 0;
}
}


@@ -2089,6 +2144,12 @@ lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
	kfree(mp);
	kfree(mp);
	mempool_free(pmb, phba->mbox_mem_pool);
	mempool_free(pmb, phba->mbox_mem_pool);
	lpfc_nlp_put(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);
	return;
	return;
}
}


@@ -2118,6 +2179,9 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
			}
			}
			mempool_free(mbox, phba->mbox_mem_pool);
			mempool_free(mbox, phba->mbox_mem_pool);
		}
		}
		if (ndlp && (ndlp->nlp_flag & NLP_RM_DFLT_RPI))
			if (lpfc_nlp_not_used(ndlp))
				ndlp = NULL;
		goto out;
		goto out;
	}
	}


@@ -2153,14 +2217,21 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
			    != MBX_NOT_FINISHED) {
			    != MBX_NOT_FINISHED) {
				goto out;
				goto out;
			}
			}
			lpfc_nlp_put(ndlp);

			/* NOTE: we should have messages for unsuccessful
			/* ELS rsp: Cannot issue reg_login for <NPortid> */
			   reglogin */
			lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
				"0138 ELS rsp: Cannot issue reg_login for x%x "
				"Data: x%x x%x x%x\n",
				ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
				ndlp->nlp_rpi);

			if (lpfc_nlp_not_used(ndlp))
				ndlp = NULL;
		} else {
		} else {
			/* Do not drop node for lpfc_els_abort'ed ELS cmds */
			/* Do not drop node for lpfc_els_abort'ed ELS cmds */
			if (!lpfc_error_lost_link(irsp) &&
			if (!lpfc_error_lost_link(irsp) &&
			    ndlp->nlp_flag & NLP_ACC_REGLOGIN) {
			    ndlp->nlp_flag & NLP_ACC_REGLOGIN) {
				lpfc_drop_node(vport, ndlp);
				if (lpfc_nlp_not_used(ndlp))
					ndlp = NULL;
					ndlp = NULL;
			}
			}
		}
		}
@@ -2350,10 +2421,14 @@ lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError,
	/* If the node is in the UNUSED state, and we are sending
	/* If the node is in the UNUSED state, and we are sending
	 * a reject, we are done with it.  Release driver reference
	 * a reject, we are done with it.  Release driver reference
	 * count here.  The outstanding els will release its reference on
	 * count here.  The outstanding els will release its reference on
	 * completion and the node can be freed then.
	 * 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)
	if ((ndlp->nlp_state == NLP_STE_UNUSED_NODE) &&
		!(ndlp->nlp_flag & NLP_DELAYED_RM)) {
		ndlp->nlp_flag |= NLP_DELAYED_RM;
		lpfc_nlp_put(ndlp);
		lpfc_nlp_put(ndlp);
	}


	if (rc == IOCB_ERROR) {
	if (rc == IOCB_ERROR) {
		lpfc_els_free_iocb(phba, elsiocb);
		lpfc_els_free_iocb(phba, elsiocb);
@@ -3466,8 +3541,6 @@ lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
				}
				}
			}
			}


			vport->port_state = LPFC_FLOGI;
			lpfc_set_disctmo(vport);
			lpfc_initial_flogi(vport);
			lpfc_initial_flogi(vport);
			return 0;
			return 0;
		}
		}
@@ -3747,11 +3820,11 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
			goto dropit;
			goto dropit;


		lpfc_nlp_init(vport, ndlp, did);
		lpfc_nlp_init(vport, ndlp, did);
		lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
		newnode = 1;
		newnode = 1;
		if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) {
		if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) {
			ndlp->nlp_type |= NLP_FABRIC;
			ndlp->nlp_type |= NLP_FABRIC;
		}
		}
		lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
	}
	}


	phba->fc_stat.elsRcvFrame++;
	phba->fc_stat.elsRcvFrame++;
@@ -3791,8 +3864,8 @@ 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)
		if (newnode && (!(ndlp->nlp_flag & NLP_DELAYED_RM)))
			lpfc_drop_node(vport, ndlp);
			lpfc_nlp_put(ndlp);
		break;
		break;
	case ELS_CMD_LOGO:
	case ELS_CMD_LOGO:
		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
@@ -3821,8 +3894,8 @@ 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)
		if (newnode && (!(ndlp->nlp_flag & NLP_DELAYED_RM)))
			lpfc_drop_node(vport, ndlp);
			lpfc_nlp_put(ndlp);
		break;
		break;
	case ELS_CMD_ADISC:
	case ELS_CMD_ADISC:
		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
@@ -3893,8 +3966,8 @@ 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)
		if (newnode && (!(ndlp->nlp_flag & NLP_DELAYED_RM)))
			lpfc_drop_node(vport, ndlp);
			lpfc_nlp_put(ndlp);
		break;
		break;
	case ELS_CMD_RPS:
	case ELS_CMD_RPS:
		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
@@ -3903,8 +3976,8 @@ 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)
		if (newnode && (!(ndlp->nlp_flag & NLP_DELAYED_RM)))
			lpfc_drop_node(vport, ndlp);
			lpfc_nlp_put(ndlp);
		break;
		break;
	case ELS_CMD_RPL:
	case ELS_CMD_RPL:
		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
@@ -3913,8 +3986,8 @@ 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)
		if (newnode && (!(ndlp->nlp_flag & NLP_DELAYED_RM)))
			lpfc_drop_node(vport, ndlp);
			lpfc_nlp_put(ndlp);
		break;
		break;
	case ELS_CMD_RNID:
	case ELS_CMD_RNID:
		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
@@ -3923,8 +3996,8 @@ 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)
		if (newnode && (!(ndlp->nlp_flag & NLP_DELAYED_RM)))
			lpfc_drop_node(vport, ndlp);
			lpfc_nlp_put(ndlp);
		break;
		break;
	default:
	default:
		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
@@ -3938,8 +4011,8 @@ 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)
		if (newnode && (!(ndlp->nlp_flag & NLP_DELAYED_RM)))
			lpfc_drop_node(vport, ndlp);
			lpfc_nlp_put(ndlp);
		break;
		break;
	}
	}


@@ -3955,10 +4028,11 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
	return;
	return;


dropit:
dropit:
	if (vport && !(vport->load_flag & FC_UNLOADING))
		lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
		lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
			"(%d):0111 Dropping received ELS cmd "
			"(%d):0111 Dropping received ELS cmd "
			"Data: x%x x%x x%x\n",
			"Data: x%x x%x x%x\n",
			vport ? vport->vpi : 0xffff, icmd->ulpStatus,
			vport->vpi, icmd->ulpStatus,
			icmd->un.ulpWord[4], icmd->ulpTimeout);
			icmd->un.ulpWord[4], icmd->ulpTimeout);
	phba->fc_stat.elsRcvDrop++;
	phba->fc_stat.elsRcvDrop++;
}
}
Loading