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

Commit 2534ba75 authored by James Smart's avatar James Smart Committed by James Bottomley
Browse files

[SCSI] lpfc 8.1.12 : Fix unlock inside list traversal



Fix unlock inside list traversal.

Signed-off-by: default avatarJames Smart <James.Smart@emulex.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent 46fa311e
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@ void lpfc_disc_start(struct lpfc_hba *);
void lpfc_disc_flush_list(struct lpfc_hba *);
void lpfc_disc_timeout(unsigned long);

struct lpfc_nodelist *__lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi);
struct lpfc_nodelist *lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi);

int lpfc_workq_post_event(struct lpfc_hba *, void *, void *, uint32_t);
+17 −13
Original line number Diff line number Diff line
@@ -3272,9 +3272,7 @@ lpfc_els_timeout_handler(struct lpfc_hba *phba)

		if (cmd->ulpCommand == CMD_GEN_REQUEST64_CR) {
			struct lpfc_nodelist *ndlp;
			spin_unlock_irq(phba->host->host_lock);
			ndlp = lpfc_findnode_rpi(phba, cmd->ulpContext);
			spin_lock_irq(phba->host->host_lock);
			ndlp = __lpfc_findnode_rpi(phba, cmd->ulpContext);
			remote_ID = ndlp->nlp_DID;
		} else {
			remote_ID = cmd->un.elsreq64.remoteID;
@@ -3298,6 +3296,7 @@ lpfc_els_timeout_handler(struct lpfc_hba *phba)
void
lpfc_els_flush_cmd(struct lpfc_hba * phba)
{
	LIST_HEAD(completions);
	struct lpfc_sli_ring *pring;
	struct lpfc_iocbq *tmp_iocb, *piocb;
	IOCB_t *cmd = NULL;
@@ -3319,18 +3318,9 @@ lpfc_els_flush_cmd(struct lpfc_hba * phba)
			continue;
		}

		list_del(&piocb->list);
		list_move_tail(&piocb->list, &completions);
		pring->txq_cnt--;

		cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
		cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;

		if (piocb->iocb_cmpl) {
			spin_unlock_irq(phba->host->host_lock);
			(piocb->iocb_cmpl) (phba, piocb, piocb);
			spin_lock_irq(phba->host->host_lock);
		} else
			lpfc_sli_release_iocbq(phba, piocb);
	}

	list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
@@ -3343,6 +3333,20 @@ lpfc_els_flush_cmd(struct lpfc_hba * phba)
		lpfc_sli_issue_abort_iotag(phba, pring, piocb);
	}
	spin_unlock_irq(phba->host->host_lock);

	while(!list_empty(&completions)) {
		piocb = list_get_first(&completions, struct lpfc_iocbq, list);
		cmd = &piocb->iocb;
		list_del(&piocb->list);

		if (piocb->iocb_cmpl) {
			cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
			cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
			(piocb->iocb_cmpl) (phba, piocb, piocb);
		} else
			lpfc_sli_release_iocbq(phba, piocb);
	}

	return;
}

+46 −58
Original line number Diff line number Diff line
@@ -1473,6 +1473,7 @@ lpfc_check_sli_ndlp(struct lpfc_hba * phba,
static int
lpfc_no_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
{
	LIST_HEAD(completions);
	struct lpfc_sli *psli;
	struct lpfc_sli_ring *pring;
	struct lpfc_iocbq *iocb, *next_iocb;
@@ -1501,29 +1502,29 @@ lpfc_no_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
				     (phba, pring, iocb, ndlp))) {
					/* It matches, so deque and call compl
					   with an error */
					list_del(&iocb->list);
					list_move_tail(&iocb->list,
						       &completions);
					pring->txq_cnt--;
					if (iocb->iocb_cmpl) {
						icmd = &iocb->iocb;
						icmd->ulpStatus =
						    IOSTAT_LOCAL_REJECT;
						icmd->un.ulpWord[4] =
						    IOERR_SLI_ABORTED;
						spin_unlock_irq(phba->host->
								host_lock);
						(iocb->iocb_cmpl) (phba,
								   iocb, iocb);
						spin_lock_irq(phba->host->
							      host_lock);
					} else
						lpfc_sli_release_iocbq(phba,
								       iocb);
				}
			}
			spin_unlock_irq(phba->host->host_lock);

		}
	}

	while (!list_empty(&completions)) {
		iocb = list_get_first(&completions, struct lpfc_iocbq, list);
		list_del(&iocb->list);

		if (iocb->iocb_cmpl) {
			icmd = &iocb->iocb;
			icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
			icmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
			(iocb->iocb_cmpl) (phba, iocb, iocb);
		} else
			lpfc_sli_release_iocbq(phba, iocb);
	}

	return 0;
}

@@ -1951,11 +1952,11 @@ lpfc_disc_start(struct lpfc_hba * phba)
static void
lpfc_free_tx(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
{
	LIST_HEAD(completions);
	struct lpfc_sli *psli;
	IOCB_t     *icmd;
	struct lpfc_iocbq    *iocb, *next_iocb;
	struct lpfc_sli_ring *pring;
	struct lpfc_dmabuf   *mp;

	psli = &phba->sli;
	pring = &psli->ring[LPFC_ELS_RING];
@@ -1963,6 +1964,7 @@ lpfc_free_tx(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
	/* Error matching iocb on txq or txcmplq
	 * First check the txq.
	 */
	spin_lock_irq(phba->host->host_lock);
	list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
		if (iocb->context1 != ndlp) {
			continue;
@@ -1971,9 +1973,8 @@ lpfc_free_tx(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
		if ((icmd->ulpCommand == CMD_ELS_REQUEST64_CR) ||
		    (icmd->ulpCommand == CMD_XMIT_ELS_RSP64_CX)) {

			list_del(&iocb->list);
			list_move_tail(&iocb->list, &completions);
			pring->txq_cnt--;
			lpfc_els_free_iocb(phba, iocb);
		}
	}

@@ -1985,43 +1986,22 @@ lpfc_free_tx(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
		icmd = &iocb->iocb;
		if ((icmd->ulpCommand == CMD_ELS_REQUEST64_CR) ||
		    (icmd->ulpCommand == CMD_XMIT_ELS_RSP64_CX)) {

			iocb->iocb_cmpl = NULL;
			/* context2 = cmd, context2->next = rsp, context3 =
			   bpl */
			if (iocb->context2) {
				/* Free the response IOCB before handling the
				   command. */

				mp = (struct lpfc_dmabuf *) (iocb->context2);
				mp = list_get_first(&mp->list,
						    struct lpfc_dmabuf,
						    list);
				if (mp) {
					/* Delay before releasing rsp buffer to
					 * give UNREG mbox a chance to take
					 * effect.
					 */
					list_add(&mp->list,
						&phba->freebufList);
			lpfc_sli_issue_abort_iotag(phba, pring, iocb);
		}
				lpfc_mbuf_free(phba,
					       ((struct lpfc_dmabuf *)
						iocb->context2)->virt,
					       ((struct lpfc_dmabuf *)
						iocb->context2)->phys);
				kfree(iocb->context2);
	}
	spin_unlock_irq(phba->host->host_lock);

			if (iocb->context3) {
				lpfc_mbuf_free(phba,
					       ((struct lpfc_dmabuf *)
						iocb->context3)->virt,
					       ((struct lpfc_dmabuf *)
						iocb->context3)->phys);
				kfree(iocb->context3);
			}
		}
	while (!list_empty(&completions)) {
		iocb = list_get_first(&completions, struct lpfc_iocbq, list);
		list_del(&iocb->list);

		if (iocb->iocb_cmpl) {
			icmd = &iocb->iocb;
			icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
			icmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
			(iocb->iocb_cmpl) (phba, iocb, iocb);
		} else
			lpfc_sli_release_iocbq(phba, iocb);
	}

	return;
@@ -2354,7 +2334,7 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 * else return NULL.
 */
struct lpfc_nodelist *
lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi)
__lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi)
{
	struct lpfc_nodelist *ndlp;
	struct list_head * lists[]={&phba->fc_nlpunmap_list,
@@ -2364,17 +2344,25 @@ lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi)
				    &phba->fc_reglogin_list};
	int i;

	spin_lock_irq(phba->host->host_lock);
	for (i = 0; i < ARRAY_SIZE(lists); i++ )
		list_for_each_entry(ndlp, lists[i], nlp_listp)
			if (ndlp->nlp_rpi == rpi) {
				spin_unlock_irq(phba->host->host_lock);
				return ndlp;
			}
	spin_unlock_irq(phba->host->host_lock);
	return NULL;
}

struct lpfc_nodelist *
lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi)
{
	struct lpfc_nodelist *ndlp;

	spin_lock_irq(phba->host->host_lock);
	ndlp = __lpfc_findnode_rpi(phba, rpi);
	spin_unlock_irq(phba->host->host_lock);
	return ndlp;
}

/*
 * This routine looks up the ndlp  lists
 * for the given WWPN. If WWPN found
+26 −31
Original line number Diff line number Diff line
@@ -170,11 +170,11 @@ lpfc_check_elscmpl_iocb(struct lpfc_hba * phba,
int
lpfc_els_abort(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
{
	LIST_HEAD(completions);
	struct lpfc_sli *psli;
	struct lpfc_sli_ring *pring;
	struct lpfc_iocbq *iocb, *next_iocb;
	IOCB_t *icmd;
	int    found = 0;
	IOCB_t *cmd;

	/* Abort outstanding I/O on NPort <nlp_DID> */
	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
@@ -187,45 +187,40 @@ lpfc_els_abort(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
	pring = &psli->ring[LPFC_ELS_RING];

	/* First check the txq */
	do {
		found = 0;
	spin_lock_irq(phba->host->host_lock);
	list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
		/* Check to see if iocb matches the nport we are looking
		   for */
			if ((lpfc_check_sli_ndlp(phba, pring, iocb, ndlp))) {
				found = 1;
		if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) {
			/* It matches, so deque and call compl with an
			   error */
				list_del(&iocb->list);
			list_move_tail(&iocb->list, &completions);
			pring->txq_cnt--;
				if (iocb->iocb_cmpl) {
					icmd = &iocb->iocb;
					icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
					icmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
					spin_unlock_irq(phba->host->host_lock);
					(iocb->iocb_cmpl) (phba, iocb, iocb);
					spin_lock_irq(phba->host->host_lock);
				} else
					lpfc_sli_release_iocbq(phba, iocb);
				break;
		}
	}
		spin_unlock_irq(phba->host->host_lock);
	} while (found);

	/* Next check the txcmplq */
	spin_lock_irq(phba->host->host_lock);
	list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
		/* Check to see if iocb matches the nport we are looking
		   for */
		if ((lpfc_check_sli_ndlp (phba, pring, iocb, ndlp))) {
			icmd = &iocb->iocb;
		if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp))
			lpfc_sli_issue_abort_iotag(phba, pring, iocb);
	}
	}
	spin_unlock_irq(phba->host->host_lock);

	while (!list_empty(&completions)) {
		iocb = list_get_first(&completions, struct lpfc_iocbq, list);
		cmd = &iocb->iocb;
		list_del(&iocb->list);

		if (iocb->iocb_cmpl) {
			cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
			cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
			(iocb->iocb_cmpl) (phba, iocb, iocb);
		} else
			lpfc_sli_release_iocbq(phba, iocb);
	}

	/* If we are delaying issuing an ELS command, cancel it */
	if (ndlp->nlp_flag & NLP_DELAY_TMO)
		lpfc_cancel_retry_delay_tmo(phba, ndlp);
+26 −46
Original line number Diff line number Diff line
@@ -1455,8 +1455,9 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba,
int
lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
{
	LIST_HEAD(completions);
	struct lpfc_iocbq *iocb, *next_iocb;
	IOCB_t *icmd = NULL, *cmd = NULL;
	IOCB_t *cmd = NULL;
	int errcnt;

	errcnt = 0;
@@ -1465,46 +1466,28 @@ lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
	 * First do the txq.
	 */
	spin_lock_irq(phba->host->host_lock);
	list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
		list_del_init(&iocb->list);
		if (iocb->iocb_cmpl) {
			icmd = &iocb->iocb;
			icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
			icmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
			spin_unlock_irq(phba->host->host_lock);
			(iocb->iocb_cmpl) (phba, iocb, iocb);
			spin_lock_irq(phba->host->host_lock);
		} else
			lpfc_sli_release_iocbq(phba, iocb);
	}
	list_splice_init(&pring->txq, &completions);
	pring->txq_cnt = 0;
	INIT_LIST_HEAD(&(pring->txq));

	/* Next issue ABTS for everything on the txcmplq */
	list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
		cmd = &iocb->iocb;
	list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list)
		lpfc_sli_issue_abort_iotag(phba, pring, iocb);

		/*
		 * Imediate abort of IOCB, deque and call compl
		 */
	spin_unlock_irq(phba->host->host_lock);

		list_del_init(&iocb->list);
		pring->txcmplq_cnt--;
	while (!list_empty(&completions)) {
		iocb = list_get_first(&completions, struct lpfc_iocbq, list);
		cmd = &iocb->iocb;
		list_del(&iocb->list);

		if (iocb->iocb_cmpl) {
			cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
			cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
			spin_unlock_irq(phba->host->host_lock);
			(iocb->iocb_cmpl) (phba, iocb, iocb);
			spin_lock_irq(phba->host->host_lock);
		} else
			lpfc_sli_release_iocbq(phba, iocb);
	}

	INIT_LIST_HEAD(&pring->txcmplq);
	pring->txcmplq_cnt = 0;
	spin_unlock_irq(phba->host->host_lock);

	return errcnt;
}

@@ -2605,11 +2588,12 @@ lpfc_sli_queue_setup(struct lpfc_hba * phba)
int
lpfc_sli_hba_down(struct lpfc_hba * phba)
{
	LIST_HEAD(completions);
	struct lpfc_sli *psli;
	struct lpfc_sli_ring *pring;
	LPFC_MBOXQ_t *pmb;
	struct lpfc_iocbq *iocb, *next_iocb;
	IOCB_t *icmd = NULL;
	struct lpfc_iocbq *iocb;
	IOCB_t *cmd = NULL;
	int i;
	unsigned long flags = 0;

@@ -2617,7 +2601,6 @@ lpfc_sli_hba_down(struct lpfc_hba * phba)
	lpfc_hba_down_prep(phba);

	spin_lock_irqsave(phba->host->host_lock, flags);

	for (i = 0; i < psli->num_rings; i++) {
		pring = &psli->ring[i];
		pring->flag |= LPFC_DEFERRED_RING_EVENT;
@@ -2626,28 +2609,25 @@ lpfc_sli_hba_down(struct lpfc_hba * phba)
		 * Error everything on the txq since these iocbs have not been
		 * given to the FW yet.
		 */
		list_splice_init(&pring->txq, &completions);
		pring->txq_cnt = 0;

		list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
			list_del_init(&iocb->list);
	}
	spin_unlock_irqrestore(phba->host->host_lock, flags);

	while (!list_empty(&completions)) {
		iocb = list_get_first(&completions, struct lpfc_iocbq, list);
		cmd = &iocb->iocb;
		list_del(&iocb->list);

		if (iocb->iocb_cmpl) {
				icmd = &iocb->iocb;
				icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
				icmd->un.ulpWord[4] = IOERR_SLI_DOWN;
				spin_unlock_irqrestore(phba->host->host_lock,
						       flags);
			cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
			cmd->un.ulpWord[4] = IOERR_SLI_DOWN;
			(iocb->iocb_cmpl) (phba, iocb, iocb);
				spin_lock_irqsave(phba->host->host_lock, flags);
		} else
			lpfc_sli_release_iocbq(phba, iocb);
	}

		INIT_LIST_HEAD(&(pring->txq));

	}

	spin_unlock_irqrestore(phba->host->host_lock, flags);

	/* Return any active mbox cmds */
	del_timer_sync(&psli->mbox_tmo);
	spin_lock_irqsave(phba->host->host_lock, flags);