[SCSI] lpfc 8.3.42: Fixed race condition between BSG I/O dispatch and timeout handling
Signed-off-by: James Smart <james.smart@emulex.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
This commit is contained in:
parent
9a86ed4840
commit
b5a9b2dfe6
@ -317,6 +317,11 @@ lpfc_bsg_send_mgmt_cmd_cmp(struct lpfc_hba *phba,
|
|||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
|
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;
|
iocb = &dd_data->context_un.iocb;
|
||||||
ndlp = iocb->ndlp;
|
ndlp = iocb->ndlp;
|
||||||
rmp = iocb->rmp;
|
rmp = iocb->rmp;
|
||||||
@ -387,6 +392,7 @@ lpfc_bsg_send_mgmt_cmd(struct fc_bsg_job *job)
|
|||||||
int request_nseg;
|
int request_nseg;
|
||||||
int reply_nseg;
|
int reply_nseg;
|
||||||
struct bsg_job_data *dd_data;
|
struct bsg_job_data *dd_data;
|
||||||
|
unsigned long flags;
|
||||||
uint32_t creg_val;
|
uint32_t creg_val;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
int iocb_stat;
|
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);
|
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 */
|
return 0; /* done for now */
|
||||||
else if (iocb_stat == IOCB_BUSY)
|
} else if (iocb_stat == IOCB_BUSY) {
|
||||||
rc = -EAGAIN;
|
rc = -EAGAIN;
|
||||||
else
|
} else {
|
||||||
rc = -EIO;
|
rc = -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
/* iocb failed so cleanup */
|
/* iocb failed so cleanup */
|
||||||
|
job->dd_data = NULL;
|
||||||
|
|
||||||
free_rmp:
|
free_rmp:
|
||||||
lpfc_free_bsg_buffers(phba, 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);
|
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;
|
rsp = &rspiocbq->iocb;
|
||||||
pcmd = (struct lpfc_dmabuf *)cmdiocbq->context2;
|
pcmd = (struct lpfc_dmabuf *)cmdiocbq->context2;
|
||||||
prsp = (struct lpfc_dmabuf *)pcmd->list.next;
|
prsp = (struct lpfc_dmabuf *)pcmd->list.next;
|
||||||
@ -639,6 +660,7 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job)
|
|||||||
struct lpfc_iocbq *cmdiocbq;
|
struct lpfc_iocbq *cmdiocbq;
|
||||||
uint16_t rpi = 0;
|
uint16_t rpi = 0;
|
||||||
struct bsg_job_data *dd_data;
|
struct bsg_job_data *dd_data;
|
||||||
|
unsigned long flags;
|
||||||
uint32_t creg_val;
|
uint32_t creg_val;
|
||||||
int rc = 0;
|
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);
|
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 */
|
return 0; /* done for now */
|
||||||
else if (rc == IOCB_BUSY)
|
} else if (rc == IOCB_BUSY) {
|
||||||
rc = -EAGAIN;
|
rc = -EAGAIN;
|
||||||
else
|
} else {
|
||||||
rc = -EIO;
|
rc = -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* iocb failed so cleanup */
|
||||||
|
job->dd_data = NULL;
|
||||||
|
|
||||||
linkdown_err:
|
linkdown_err:
|
||||||
|
|
||||||
cmdiocbq->context1 = ndlp;
|
cmdiocbq->context1 = ndlp;
|
||||||
lpfc_els_free_iocb(phba, cmdiocbq);
|
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);
|
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;
|
ndlp = dd_data->context_un.iocb.ndlp;
|
||||||
cmp = cmdiocbq->context2;
|
cmp = cmdiocbq->context2;
|
||||||
bmp = cmdiocbq->context3;
|
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;
|
int rc = 0;
|
||||||
struct lpfc_nodelist *ndlp = NULL;
|
struct lpfc_nodelist *ndlp = NULL;
|
||||||
struct bsg_job_data *dd_data;
|
struct bsg_job_data *dd_data;
|
||||||
|
unsigned long flags;
|
||||||
uint32_t creg_val;
|
uint32_t creg_val;
|
||||||
|
|
||||||
/* allocate our bsg tracking structure */
|
/* 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);
|
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 */
|
return 0; /* done for now */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* iocb failed so cleanup */
|
||||||
|
job->dd_data = NULL;
|
||||||
|
|
||||||
issue_ct_rsp_exit:
|
issue_ct_rsp_exit:
|
||||||
lpfc_sli_release_iocbq(phba, ctiocb);
|
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.
|
* remove it from the txq queue and call cancel iocbs.
|
||||||
* Otherwise, call abort iotag
|
* Otherwise, call abort iotag
|
||||||
*/
|
*/
|
||||||
|
|
||||||
cmdiocb = dd_data->context_un.iocb.cmdiocbq;
|
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_for_each_entry_safe(check_iocb, next_iocb, &pring->txq,
|
||||||
list) {
|
list) {
|
||||||
if (check_iocb == cmdiocb) {
|
if (check_iocb == cmdiocb) {
|
||||||
@ -5296,8 +5351,7 @@ lpfc_bsg_timeout(struct fc_bsg_job *job)
|
|||||||
}
|
}
|
||||||
if (list_empty(&completions))
|
if (list_empty(&completions))
|
||||||
lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb);
|
lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb);
|
||||||
spin_unlock_irq(&phba->hbalock);
|
spin_unlock_irqrestore(&phba->hbalock, flags);
|
||||||
spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
|
|
||||||
if (!list_empty(&completions)) {
|
if (!list_empty(&completions)) {
|
||||||
lpfc_sli_cancel_iocbs(phba, &completions,
|
lpfc_sli_cancel_iocbs(phba, &completions,
|
||||||
IOSTAT_LOCAL_REJECT,
|
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.
|
* remove it from the txq queue and call cancel iocbs.
|
||||||
* Otherwise, call abort iotag.
|
* Otherwise, call abort iotag.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
cmdiocb = dd_data->context_un.menlo.cmdiocbq;
|
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_for_each_entry_safe(check_iocb, next_iocb, &pring->txq,
|
||||||
list) {
|
list) {
|
||||||
if (check_iocb == cmdiocb) {
|
if (check_iocb == cmdiocb) {
|
||||||
@ -5333,8 +5388,7 @@ lpfc_bsg_timeout(struct fc_bsg_job *job)
|
|||||||
}
|
}
|
||||||
if (list_empty(&completions))
|
if (list_empty(&completions))
|
||||||
lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb);
|
lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb);
|
||||||
spin_unlock_irq(&phba->hbalock);
|
spin_unlock_irqrestore(&phba->hbalock, flags);
|
||||||
spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
|
|
||||||
if (!list_empty(&completions)) {
|
if (!list_empty(&completions)) {
|
||||||
lpfc_sli_cancel_iocbs(phba, &completions,
|
lpfc_sli_cancel_iocbs(phba, &completions,
|
||||||
IOSTAT_LOCAL_REJECT,
|
IOSTAT_LOCAL_REJECT,
|
||||||
|
@ -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_MASK 0xc000 /* ELS_ID range 0-3, non-shifted mask */
|
||||||
#define LPFC_FIP_ELS_ID_SHIFT 14
|
#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 drvrTimeout; /* driver timeout in seconds */
|
||||||
uint32_t fcp_wqidx; /* index to FCP work queue */
|
uint32_t fcp_wqidx; /* index to FCP work queue */
|
||||||
struct lpfc_vport *vport;/* virtual port pointer */
|
struct lpfc_vport *vport;/* virtual port pointer */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user