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

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

[SCSI] lpfc 8.3.42: Fixed race condition between BSG I/O dispatch and timeout handling

parent 9a86ed48
Loading
Loading
Loading
Loading
+70 −16
Original line number Diff line number Diff line
@@ -317,6 +317,11 @@ lpfc_bsg_send_mgmt_cmd_cmp(struct lpfc_hba *phba,
	}
	spin_unlock_irqrestore(&phba->ct_ev_lock, flags);

	/* Close the timeout handler abort window */
	spin_lock_irqsave(&phba->hbalock, flags);
	cmdiocbq->iocb_aux_flag &= ~LPFC_IO_CMD_OUTSTANDING;
	spin_unlock_irqrestore(&phba->hbalock, flags);

	iocb = &dd_data->context_un.iocb;
	ndlp = iocb->ndlp;
	rmp = iocb->rmp;
@@ -387,6 +392,7 @@ lpfc_bsg_send_mgmt_cmd(struct fc_bsg_job *job)
	int request_nseg;
	int reply_nseg;
	struct bsg_job_data *dd_data;
	unsigned long flags;
	uint32_t creg_val;
	int rc = 0;
	int iocb_stat;
@@ -501,14 +507,24 @@ lpfc_bsg_send_mgmt_cmd(struct fc_bsg_job *job)
	}

	iocb_stat = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0);
	if (iocb_stat == IOCB_SUCCESS)

	if (iocb_stat == IOCB_SUCCESS) {
		spin_lock_irqsave(&phba->hbalock, flags);
		/* make sure the I/O had not been completed yet */
		if (cmdiocbq->iocb_flag & LPFC_IO_LIBDFC) {
			/* open up abort window to timeout handler */
			cmdiocbq->iocb_aux_flag |= LPFC_IO_CMD_OUTSTANDING;
		}
		spin_unlock_irqrestore(&phba->hbalock, flags);
		return 0; /* done for now */
	else if (iocb_stat == IOCB_BUSY)
	} else if (iocb_stat == IOCB_BUSY) {
		rc = -EAGAIN;
	else
	} else {
		rc = -EIO;
	}

	/* iocb failed so cleanup */
	job->dd_data = NULL;

free_rmp:
	lpfc_free_bsg_buffers(phba, rmp);
@@ -577,6 +593,11 @@ lpfc_bsg_rport_els_cmp(struct lpfc_hba *phba,
	}
	spin_unlock_irqrestore(&phba->ct_ev_lock, flags);

	/* Close the timeout handler abort window */
	spin_lock_irqsave(&phba->hbalock, flags);
	cmdiocbq->iocb_aux_flag &= ~LPFC_IO_CMD_OUTSTANDING;
	spin_unlock_irqrestore(&phba->hbalock, flags);

	rsp = &rspiocbq->iocb;
	pcmd = (struct lpfc_dmabuf *)cmdiocbq->context2;
	prsp = (struct lpfc_dmabuf *)pcmd->list.next;
@@ -639,6 +660,7 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job)
	struct lpfc_iocbq *cmdiocbq;
	uint16_t rpi = 0;
	struct bsg_job_data *dd_data;
	unsigned long flags;
	uint32_t creg_val;
	int rc = 0;

@@ -721,15 +743,25 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job)

	rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0);

	if (rc == IOCB_SUCCESS)
	if (rc == IOCB_SUCCESS) {
		spin_lock_irqsave(&phba->hbalock, flags);
		/* make sure the I/O had not been completed/released */
		if (cmdiocbq->iocb_flag & LPFC_IO_LIBDFC) {
			/* open up abort window to timeout handler */
			cmdiocbq->iocb_aux_flag |= LPFC_IO_CMD_OUTSTANDING;
		}
		spin_unlock_irqrestore(&phba->hbalock, flags);
		return 0; /* done for now */
	else if (rc == IOCB_BUSY)
	} else if (rc == IOCB_BUSY) {
		rc = -EAGAIN;
	else
	} else {
		rc = -EIO;
	}

linkdown_err:
	/* iocb failed so cleanup */
	job->dd_data = NULL;

linkdown_err:
	cmdiocbq->context1 = ndlp;
	lpfc_els_free_iocb(phba, cmdiocbq);

@@ -1370,6 +1402,11 @@ lpfc_issue_ct_rsp_cmp(struct lpfc_hba *phba,
	}
	spin_unlock_irqrestore(&phba->ct_ev_lock, flags);

	/* Close the timeout handler abort window */
	spin_lock_irqsave(&phba->hbalock, flags);
	cmdiocbq->iocb_aux_flag &= ~LPFC_IO_CMD_OUTSTANDING;
	spin_unlock_irqrestore(&phba->hbalock, flags);

	ndlp = dd_data->context_un.iocb.ndlp;
	cmp = cmdiocbq->context2;
	bmp = cmdiocbq->context3;
@@ -1433,6 +1470,7 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t tag,
	int rc = 0;
	struct lpfc_nodelist *ndlp = NULL;
	struct bsg_job_data *dd_data;
	unsigned long flags;
	uint32_t creg_val;

	/* allocate our bsg tracking structure */
@@ -1542,8 +1580,19 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t tag,

	rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, ctiocb, 0);

	if (rc == IOCB_SUCCESS)
	if (rc == IOCB_SUCCESS) {
		spin_lock_irqsave(&phba->hbalock, flags);
		/* make sure the I/O had not been completed/released */
		if (ctiocb->iocb_flag & LPFC_IO_LIBDFC) {
			/* open up abort window to timeout handler */
			ctiocb->iocb_aux_flag |= LPFC_IO_CMD_OUTSTANDING;
		}
		spin_unlock_irqrestore(&phba->hbalock, flags);
		return 0; /* done for now */
	}

	/* iocb failed so cleanup */
	job->dd_data = NULL;

issue_ct_rsp_exit:
	lpfc_sli_release_iocbq(phba, ctiocb);
@@ -5284,9 +5333,15 @@ lpfc_bsg_timeout(struct fc_bsg_job *job)
		 * remove it from the txq queue and call cancel iocbs.
		 * Otherwise, call abort iotag
		 */

		cmdiocb = dd_data->context_un.iocb.cmdiocbq;
		spin_lock_irq(&phba->hbalock);
		spin_unlock_irqrestore(&phba->ct_ev_lock, flags);

		spin_lock_irqsave(&phba->hbalock, flags);
		/* make sure the I/O abort window is still open */
		if (!(cmdiocb->iocb_aux_flag & LPFC_IO_CMD_OUTSTANDING)) {
			spin_unlock_irqrestore(&phba->hbalock, flags);
			return -EAGAIN;
		}
		list_for_each_entry_safe(check_iocb, next_iocb, &pring->txq,
					 list) {
			if (check_iocb == cmdiocb) {
@@ -5296,8 +5351,7 @@ lpfc_bsg_timeout(struct fc_bsg_job *job)
		}
		if (list_empty(&completions))
			lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb);
		spin_unlock_irq(&phba->hbalock);
		spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
		spin_unlock_irqrestore(&phba->hbalock, flags);
		if (!list_empty(&completions)) {
			lpfc_sli_cancel_iocbs(phba, &completions,
					      IOSTAT_LOCAL_REJECT,
@@ -5321,9 +5375,10 @@ lpfc_bsg_timeout(struct fc_bsg_job *job)
		 * remove it from the txq queue and call cancel iocbs.
		 * Otherwise, call abort iotag.
		 */

		cmdiocb = dd_data->context_un.menlo.cmdiocbq;
		spin_lock_irq(&phba->hbalock);
		spin_unlock_irqrestore(&phba->ct_ev_lock, flags);

		spin_lock_irqsave(&phba->hbalock, flags);
		list_for_each_entry_safe(check_iocb, next_iocb, &pring->txq,
					 list) {
			if (check_iocb == cmdiocb) {
@@ -5333,8 +5388,7 @@ lpfc_bsg_timeout(struct fc_bsg_job *job)
		}
		if (list_empty(&completions))
			lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb);
		spin_unlock_irq(&phba->hbalock);
		spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
		spin_unlock_irqrestore(&phba->hbalock, flags);
		if (!list_empty(&completions)) {
			lpfc_sli_cancel_iocbs(phba, &completions,
					      IOSTAT_LOCAL_REJECT,
+2 −1
Original line number Diff line number Diff line
@@ -77,7 +77,8 @@ struct lpfc_iocbq {
#define LPFC_FIP_ELS_ID_MASK	0xc000	/* ELS_ID range 0-3, non-shifted mask */
#define LPFC_FIP_ELS_ID_SHIFT	14

	uint8_t rsvd2;
	uint8_t iocb_aux_flag;
#define LPFC_IO_CMD_OUTSTANDING	0x01 /* timeout handler abort window */
	uint32_t drvrTimeout;	/* driver timeout in seconds */
	uint32_t fcp_wqidx;	/* index to FCP work queue */
	struct lpfc_vport *vport;/* virtual port pointer */