Commit 8e9a3250 authored by James Smart's avatar James Smart Committed by Martin K. Petersen
Browse files

scsi: lpfc: Fix use after free in lpfc_els_free_iocb

There are several code paths where the following sequence occurs:

 - An ndlp pointer is assigned to an iocb via a nlp_get()

 - An attempt is made to issue the iocb, but it fails

 - The failure case does a put on the ndlp then calls lpfc_els_free_iocb()

The put may free the ndlp structure, but the els_free_iocb may reference
the now-stale ndlp pointer and cause a crash.

Fix by ensuring that the lpfc_els_free_iocb() occurs before the
lpfc_nlp_put().

While fixing, refactor the code to better ensure this calling sequence.

Link: https://lore.kernel.org/r/20210301171821.3427-11-jsmart2021@gmail.com


Co-developed-by: default avatarDick Kennedy <dick.kennedy@broadcom.com>
Signed-off-by: default avatarDick Kennedy <dick.kennedy@broadcom.com>
Signed-off-by: default avatarJames Smart <jsmart2021@gmail.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 8dd1c125
Loading
Loading
Loading
Loading
+177 −171
Original line number Diff line number Diff line
@@ -1342,12 +1342,17 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
		phba->sli3_options, 0, 0);

	elsiocb->context1 = lpfc_nlp_get(ndlp);
	if (!elsiocb->context1)
		goto out;
	if (!elsiocb->context1) {
		lpfc_els_free_iocb(phba, elsiocb);
		return 1;
	}

	rc = lpfc_issue_fabric_iocb(phba, elsiocb);
	if (rc == IOCB_ERROR)
	if (rc == IOCB_ERROR) {
		lpfc_els_free_iocb(phba, elsiocb);
		lpfc_nlp_put(ndlp);
		return 1;
	}

	phba->hba_flag |= HBA_FLOGI_ISSUED;

@@ -1377,11 +1382,7 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
		vport->fc_myDID = did;
	}

	if (!rc)
	return 0;
 out:
	lpfc_els_free_iocb(phba, elsiocb);
	return 1;
}

/**
@@ -2152,19 +2153,19 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry)
			      "Issue PLOGI:     did:x%x refcnt %d",
			      did, kref_read(&ndlp->kref), 0);
	elsiocb->context1 = lpfc_nlp_get(ndlp);
	if (!elsiocb->context1)
		goto io_err;
	if (!elsiocb->context1) {
		lpfc_els_free_iocb(phba, elsiocb);
		return 1;
	}

	ret = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
	if (ret) {
		lpfc_els_free_iocb(phba, elsiocb);
		lpfc_nlp_put(ndlp);
		goto io_err;
		return 1;
	}
	return 0;

 io_err:
	lpfc_els_free_iocb(phba, elsiocb);
	return 1;
	return 0;
}

/**
@@ -2458,12 +2459,17 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			      "Issue PRLI:  did:x%x refcnt %d",
			      ndlp->nlp_DID, kref_read(&ndlp->kref), 0);
	elsiocb->context1 = lpfc_nlp_get(ndlp);
	if (!elsiocb->context1)
		goto io_err;
	if (!elsiocb->context1) {
		lpfc_els_free_iocb(phba, elsiocb);
		goto err;
	}

	rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
	if (rc == IOCB_ERROR)
		goto node_err;
	if (rc == IOCB_ERROR) {
		lpfc_els_free_iocb(phba, elsiocb);
		lpfc_nlp_put(ndlp);
		goto err;
	}


	/* The driver supports 2 FC4 types.  Make sure
@@ -2475,13 +2481,10 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
	else
		return 0;

 node_err:
	lpfc_nlp_put(ndlp);
 io_err:
err:
	spin_lock_irq(&ndlp->lock);
	ndlp->nlp_flag &= ~NLP_PRLI_SND;
	spin_unlock_irq(&ndlp->lock);
	lpfc_els_free_iocb(phba, elsiocb);
	return 1;
}

@@ -2765,24 +2768,27 @@ lpfc_issue_els_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
	ndlp->nlp_flag |= NLP_ADISC_SND;
	spin_unlock_irq(&ndlp->lock);
	elsiocb->context1 = lpfc_nlp_get(ndlp);
	if (!elsiocb->context1)
		goto node_err;
	if (!elsiocb->context1) {
		lpfc_els_free_iocb(phba, elsiocb);
		goto err;
	}

	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
			      "Issue ADISC:   did:x%x refcnt %d",
			      ndlp->nlp_DID, kref_read(&ndlp->kref), 0);
	rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
	if (rc == IOCB_ERROR)
		goto io_err;
	if (rc == IOCB_ERROR) {
		lpfc_els_free_iocb(phba, elsiocb);
		lpfc_nlp_put(ndlp);
		goto err;
	}

	return 0;

 io_err:
	lpfc_nlp_put(ndlp);
 node_err:
err:
	spin_lock_irq(&ndlp->lock);
	ndlp->nlp_flag &= ~NLP_ADISC_SND;
	spin_unlock_irq(&ndlp->lock);
	lpfc_els_free_iocb(phba, elsiocb);
	return 1;
}

@@ -2983,15 +2989,20 @@ lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
	ndlp->nlp_flag &= ~NLP_ISSUE_LOGO;
	spin_unlock_irq(&ndlp->lock);
	elsiocb->context1 = lpfc_nlp_get(ndlp);
	if (!elsiocb->context1)
		goto node_err;
	if (!elsiocb->context1) {
		lpfc_els_free_iocb(phba, elsiocb);
		goto err;
	}

	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
			      "Issue LOGO:      did:x%x refcnt %d",
			      ndlp->nlp_DID, kref_read(&ndlp->kref), 0);
	rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
	if (rc == IOCB_ERROR)
		goto io_err;
	if (rc == IOCB_ERROR) {
		lpfc_els_free_iocb(phba, elsiocb);
		lpfc_nlp_put(ndlp);
		goto err;
	}

	spin_lock_irq(&ndlp->lock);
	ndlp->nlp_prev_state = ndlp->nlp_state;
@@ -2999,13 +3010,10 @@ lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
	lpfc_nlp_set_state(vport, ndlp, NLP_STE_LOGO_ISSUE);
	return 0;

 io_err:
	lpfc_nlp_put(ndlp);
 node_err:
err:
	spin_lock_irq(&ndlp->lock);
	ndlp->nlp_flag &= ~NLP_LOGO_SND;
	spin_unlock_irq(&ndlp->lock);
	lpfc_els_free_iocb(phba, elsiocb);
	return 1;
}

@@ -3221,25 +3229,24 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint8_t retry)
	phba->fc_stat.elsXmitSCR++;
	elsiocb->iocb_cmpl = lpfc_cmpl_els_disc_cmd;
	elsiocb->context1 = lpfc_nlp_get(ndlp);
	if (!elsiocb->context1)
		goto node_err;
	if (!elsiocb->context1) {
		lpfc_els_free_iocb(phba, elsiocb);
		return 1;
	}

	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
			      "Issue SCR:     did:x%x refcnt %d",
			      ndlp->nlp_DID, kref_read(&ndlp->kref), 0);

	rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
	if (rc == IOCB_ERROR)
		goto io_err;
	if (rc == IOCB_ERROR) {
		lpfc_els_free_iocb(phba, elsiocb);
		lpfc_nlp_put(ndlp);
		return 1;
	}

	/* Keep the ndlp just in case RDF is being sent */
	return 0;

 io_err:
	lpfc_nlp_put(ndlp);
 node_err:
	lpfc_els_free_iocb(phba, elsiocb);
	return 1;
}

/**
@@ -3321,16 +3328,21 @@ lpfc_issue_els_rscn(struct lpfc_vport *vport, uint8_t retry)
	phba->fc_stat.elsXmitRSCN++;
	elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd;
	elsiocb->context1 = lpfc_nlp_get(ndlp);
	if (!elsiocb->context1)
		goto node_err;
	if (!elsiocb->context1) {
		lpfc_els_free_iocb(phba, elsiocb);
		return 1;
	}

	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
			      "Issue RSCN:       did:x%x",
			      ndlp->nlp_DID, 0, 0);

	rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
	if (rc == IOCB_ERROR)
		goto io_err;
	if (rc == IOCB_ERROR) {
		lpfc_els_free_iocb(phba, elsiocb);
		lpfc_nlp_put(ndlp);
		return 1;
	}

	/* This will cause the callback-function lpfc_cmpl_els_cmd to
	 * trigger the release of node.
@@ -3338,11 +3350,6 @@ lpfc_issue_els_rscn(struct lpfc_vport *vport, uint8_t retry)
	if (!(vport->fc_flag & FC_PT2PT))
		lpfc_nlp_put(ndlp);
	return 0;
io_err:
	lpfc_nlp_put(ndlp);
node_err:
	lpfc_els_free_iocb(phba, elsiocb);
	return 1;
}

/**
@@ -3437,8 +3444,8 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
		 * lpfc_els_free_iocb routine to trigger the release of
		 * the node.
		 */
		lpfc_nlp_put(ndlp);
		lpfc_els_free_iocb(phba, elsiocb);
		lpfc_nlp_put(ndlp);
		return 1;
	}
	/* This will cause the callback-function lpfc_cmpl_els_cmd to
@@ -3518,24 +3525,23 @@ lpfc_issue_els_rdf(struct lpfc_vport *vport, uint8_t retry)

	elsiocb->iocb_cmpl = lpfc_cmpl_els_disc_cmd;
	elsiocb->context1 = lpfc_nlp_get(ndlp);
	if (!elsiocb->context1)
		goto node_err;
	if (!elsiocb->context1) {
		lpfc_els_free_iocb(phba, elsiocb);
		return -EIO;
	}

	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
			      "Issue RDF:     did:x%x refcnt %d",
			      ndlp->nlp_DID, kref_read(&ndlp->kref), 0);

	rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
	if (rc == IOCB_ERROR)
		goto io_err;
	return 0;

 io_err:
	lpfc_nlp_put(ndlp);
 node_err:
	if (rc == IOCB_ERROR) {
		lpfc_els_free_iocb(phba, elsiocb);
		lpfc_nlp_put(ndlp);
		return -EIO;
	}
	return 0;
}

/**
 * lpfc_cancel_retry_delay_tmo - Cancel the timer with delayed iocb-cmd retry
@@ -4821,12 +4827,17 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,

	phba->fc_stat.elsXmitACC++;
	elsiocb->context1 = lpfc_nlp_get(ndlp);
	if (!elsiocb->context1)
		goto node_err;
	if (!elsiocb->context1) {
		lpfc_els_free_iocb(phba, elsiocb);
		return 1;
	}

	rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
	if (rc == IOCB_ERROR)
		goto io_err;
	if (rc == IOCB_ERROR) {
		lpfc_els_free_iocb(phba, elsiocb);
		lpfc_nlp_put(ndlp);
		return 1;
	}

	/* Xmit ELS ACC response tag <ulpIoTag> */
	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
@@ -4837,12 +4848,6 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
			 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
			 ndlp->nlp_rpi, vport->fc_flag);
	return 0;

io_err:
	lpfc_nlp_put(ndlp);
node_err:
	lpfc_els_free_iocb(phba, elsiocb);
	return 1;
}

/**
@@ -4914,22 +4919,21 @@ lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError,
	phba->fc_stat.elsXmitLSRJT++;
	elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
	elsiocb->context1 = lpfc_nlp_get(ndlp);
	if (!elsiocb->context1)
		goto node_err;
	if (!elsiocb->context1) {
		lpfc_els_free_iocb(phba, elsiocb);
		return 1;
	}

	rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
	if (rc == IOCB_ERROR)
		goto io_err;

	return 0;

 io_err:
	lpfc_nlp_put(ndlp);
 node_err:
	if (rc == IOCB_ERROR) {
		lpfc_els_free_iocb(phba, elsiocb);
		lpfc_nlp_put(ndlp);
		return 1;
	}

	return 0;
}

/**
 * lpfc_els_rsp_adisc_acc - Prepare and issue acc response to adisc iocb cmd
 * @vport: pointer to a virtual N_Port data structure.
@@ -4997,12 +5001,17 @@ lpfc_els_rsp_adisc_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,
	phba->fc_stat.elsXmitACC++;
	elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
	elsiocb->context1 = lpfc_nlp_get(ndlp);
	if (!elsiocb->context1)
		goto node_err;
	if (!elsiocb->context1) {
		lpfc_els_free_iocb(phba, elsiocb);
		return 1;
	}

	rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
	if (rc == IOCB_ERROR)
		goto io_err;
	if (rc == IOCB_ERROR) {
		lpfc_els_free_iocb(phba, elsiocb);
		lpfc_nlp_put(ndlp);
		return 1;
	}

	/* Xmit ELS ACC response tag <ulpIoTag> */
	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
@@ -5013,12 +5022,6 @@ lpfc_els_rsp_adisc_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,
			 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
			 ndlp->nlp_rpi, vport->fc_flag);
	return 0;

io_err:
	lpfc_nlp_put(ndlp);
node_err:
	lpfc_els_free_iocb(phba, elsiocb);
	return 1;
}

/**
@@ -5172,21 +5175,21 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,
	phba->fc_stat.elsXmitACC++;
	elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
	elsiocb->context1 =  lpfc_nlp_get(ndlp);
	if (!elsiocb->context1)
		goto node_err;
	if (!elsiocb->context1) {
		lpfc_els_free_iocb(phba, elsiocb);
		return 1;
	}

	rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
	if (rc == IOCB_ERROR)
		goto io_err;
	return 0;

 io_err:
	lpfc_nlp_put(ndlp);
 node_err:
	if (rc == IOCB_ERROR) {
		lpfc_els_free_iocb(phba, elsiocb);
		lpfc_nlp_put(ndlp);
		return 1;
	}

	return 0;
}

/**
 * lpfc_els_rsp_rnid_acc - Issue rnid acc response iocb command
 * @vport: pointer to a virtual N_Port data structure.
@@ -5279,22 +5282,21 @@ lpfc_els_rsp_rnid_acc(struct lpfc_vport *vport, uint8_t format,
	phba->fc_stat.elsXmitACC++;
	elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
	elsiocb->context1 = lpfc_nlp_get(ndlp);
	if (!elsiocb->context1)
		goto node_err;
	if (!elsiocb->context1) {
		lpfc_els_free_iocb(phba, elsiocb);
		return 1;
	}

	rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
	if (rc == IOCB_ERROR)
		goto io_err;

	return 0;

 io_err:
	lpfc_nlp_put(ndlp);
 node_err:
	if (rc == IOCB_ERROR) {
		lpfc_els_free_iocb(phba, elsiocb);
		lpfc_nlp_put(ndlp);
		return 1;
	}

	return 0;
}

/**
 * lpfc_els_clear_rrq - Clear the rq that this rrq describes.
 * @vport: pointer to a virtual N_Port data structure.
@@ -5394,21 +5396,21 @@ lpfc_els_rsp_echo_acc(struct lpfc_vport *vport, uint8_t *data,
	phba->fc_stat.elsXmitACC++;
	elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
	elsiocb->context1 =  lpfc_nlp_get(ndlp);
	if (!elsiocb->context1)
		goto node_err;
	if (!elsiocb->context1) {
		lpfc_els_free_iocb(phba, elsiocb);
		return 1;
	}

	rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
	if (rc == IOCB_ERROR)
		goto io_err;
	return 0;

 io_err:
	lpfc_nlp_put(ndlp);
 node_err:
	if (rc == IOCB_ERROR) {
		lpfc_els_free_iocb(phba, elsiocb);
		lpfc_nlp_put(ndlp);
		return 1;
	}

	return 0;
}

/**
 * lpfc_els_disc_adisc - Issue remaining adisc iocbs to npr nodes of a vport
 * @vport: pointer to a host virtual N_Port data structure.
@@ -6050,8 +6052,8 @@ lpfc_els_rdp_cmpl(struct lpfc_hba *phba, struct lpfc_rdp_context *rdp_context,

	rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
	if (rc == IOCB_ERROR) {
		lpfc_nlp_put(ndlp);
		lpfc_els_free_iocb(phba, elsiocb);
		lpfc_nlp_put(ndlp);
	}

	goto free_rdp_context;
@@ -6082,8 +6084,8 @@ lpfc_els_rdp_cmpl(struct lpfc_hba *phba, struct lpfc_rdp_context *rdp_context,

	rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
	if (rc == IOCB_ERROR) {
		lpfc_nlp_put(ndlp);
		lpfc_els_free_iocb(phba, elsiocb);
		lpfc_nlp_put(ndlp);
	}

free_rdp_context:
@@ -6295,16 +6297,16 @@ lpfc_els_lcb_rsp(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
	phba->fc_stat.elsXmitACC++;

	elsiocb->context1 = lpfc_nlp_get(ndlp);
	if (!elsiocb->context1)
		goto node_err;

	rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
	if (!rc)
	if (!elsiocb->context1) {
		lpfc_els_free_iocb(phba, elsiocb);
		goto out;
	}

	lpfc_nlp_put(ndlp);
 node_err:
	rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
	if (rc == IOCB_ERROR) {
		lpfc_els_free_iocb(phba, elsiocb);
		lpfc_nlp_put(ndlp);
	}
 out:
	kfree(lcb_context);
	return;
@@ -6340,8 +6342,8 @@ lpfc_els_lcb_rsp(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)

	rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
	if (rc == IOCB_ERROR) {
		lpfc_nlp_put(ndlp);
		lpfc_els_free_iocb(phba, elsiocb);
		lpfc_nlp_put(ndlp);
	}
free_lcb_context:
	kfree(lcb_context);
@@ -7407,18 +7409,17 @@ lpfc_els_rsp_rls_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
	elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
	phba->fc_stat.elsXmitACC++;
	elsiocb->context1 = lpfc_nlp_get(ndlp);
	if (!elsiocb->context1)
		goto node_err;

	rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
	if (rc == IOCB_ERROR)
		goto io_err;
	if (!elsiocb->context1) {
		lpfc_els_free_iocb(phba, elsiocb);
		return;
	}

 io_err:
	lpfc_nlp_put(ndlp);
 node_err:
	rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
	if (rc == IOCB_ERROR) {
		lpfc_els_free_iocb(phba, elsiocb);
		lpfc_nlp_put(ndlp);
	}
	return;
}

/**
@@ -7567,8 +7568,8 @@ lpfc_els_rcv_rtv(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,

	rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
	if (rc == IOCB_ERROR) {
		lpfc_nlp_put(ndlp);
		lpfc_els_free_iocb(phba, elsiocb);
		lpfc_nlp_put(ndlp);
	}
	return 0;

@@ -7645,8 +7646,8 @@ lpfc_issue_els_rrq(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
	return 0;

 io_err:
	lpfc_nlp_put(ndlp);
	lpfc_els_free_iocb(phba, elsiocb);
	lpfc_nlp_put(ndlp);
	return 1;
}

@@ -7743,21 +7744,21 @@ lpfc_els_rsp_rpl_acc(struct lpfc_vport *vport, uint16_t cmdsize,
	elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
	phba->fc_stat.elsXmitACC++;
	elsiocb->context1 = lpfc_nlp_get(ndlp);
	if (!elsiocb->context1)
		goto node_err;
	if (!elsiocb->context1) {
		lpfc_els_free_iocb(phba, elsiocb);
		return 1;
	}

	rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
	if (rc == IOCB_ERROR)
		goto io_err;
	return 0;

 io_err:
	lpfc_nlp_put(ndlp);
 node_err:
	if (rc == IOCB_ERROR) {
		lpfc_els_free_iocb(phba, elsiocb);
		lpfc_nlp_put(ndlp);
		return 1;
	}

	return 0;
}

/**
 * lpfc_els_rcv_rpl - Process an unsolicited rpl iocb
 * @vport: pointer to a host virtual N_Port data structure.
@@ -9661,11 +9662,14 @@ lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
		did, 0, 0);

	elsiocb->context1 = lpfc_nlp_get(ndlp);
	if (!elsiocb->context1)
	if (!elsiocb->context1) {
		lpfc_els_free_iocb(phba, elsiocb);
		goto err_out;
	}

	rc = lpfc_issue_fabric_iocb(phba, elsiocb);
	if (rc == IOCB_ERROR) {
		lpfc_els_free_iocb(phba, elsiocb);
		lpfc_nlp_put(ndlp);
		goto err_out;
	}
@@ -9674,7 +9678,6 @@ lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
	return 0;

 err_out:
	lpfc_els_free_iocb(phba, elsiocb);
	lpfc_vport_set_state(vport, FC_VPORT_FAILED);
	lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
			 "0256 Issue FDISC: Cannot send IOCB\n");
@@ -9782,20 +9785,23 @@ lpfc_issue_els_npiv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
	ndlp->nlp_flag |= NLP_LOGO_SND;
	spin_unlock_irq(&ndlp->lock);
	elsiocb->context1 = lpfc_nlp_get(ndlp);
	if (!elsiocb->context1)
		goto node_err;
	if (!elsiocb->context1) {
		lpfc_els_free_iocb(phba, elsiocb);
		goto err;
	}

	rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
	if (rc == IOCB_ERROR)
		goto io_err;
	if (rc == IOCB_ERROR) {
		lpfc_els_free_iocb(phba, elsiocb);
		lpfc_nlp_put(ndlp);
		goto err;
	}
	return 0;

 io_err:
	lpfc_nlp_put(ndlp);
 node_err:
err:
	spin_lock_irq(&ndlp->lock);
	ndlp->nlp_flag &= ~NLP_LOGO_SND;
	spin_unlock_irq(&ndlp->lock);
	lpfc_els_free_iocb(phba, elsiocb);
	return 1;
}