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

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

Signed-off-by: default avatarJames Smart <james.smart@emulex.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent 9a86ed48
...@@ -317,6 +317,11 @@ lpfc_bsg_send_mgmt_cmd_cmp(struct lpfc_hba *phba, ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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;
}
linkdown_err: /* iocb failed so cleanup */
job->dd_data = NULL;
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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 { ...@@ -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 */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment