mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-18 22:14:16 +00:00
[SCSI] lpfc 8.3.41: Fixed freeing of iocb when internal loopback times out
Signed-off-by: James Smart <james.smart@emulex.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
This commit is contained in:
parent
b56a15d146
commit
5a0916b4d2
4 changed files with 55 additions and 11 deletions
|
@ -2498,7 +2498,7 @@ static int lpfcdiag_loop_get_xri(struct lpfc_hba *phba, uint16_t rpi,
|
||||||
struct lpfc_sli_ct_request *ctreq = NULL;
|
struct lpfc_sli_ct_request *ctreq = NULL;
|
||||||
int ret_val = 0;
|
int ret_val = 0;
|
||||||
int time_left;
|
int time_left;
|
||||||
int iocb_stat = 0;
|
int iocb_stat = IOCB_SUCCESS;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
*txxri = 0;
|
*txxri = 0;
|
||||||
|
@ -2574,6 +2574,7 @@ static int lpfcdiag_loop_get_xri(struct lpfc_hba *phba, uint16_t rpi,
|
||||||
|
|
||||||
cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC;
|
cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC;
|
||||||
cmdiocbq->vport = phba->pport;
|
cmdiocbq->vport = phba->pport;
|
||||||
|
cmdiocbq->iocb_cmpl = NULL;
|
||||||
|
|
||||||
iocb_stat = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq,
|
iocb_stat = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq,
|
||||||
rspiocbq,
|
rspiocbq,
|
||||||
|
@ -2963,7 +2964,7 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job)
|
||||||
uint8_t *ptr = NULL, *rx_databuf = NULL;
|
uint8_t *ptr = NULL, *rx_databuf = NULL;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
int time_left;
|
int time_left;
|
||||||
int iocb_stat;
|
int iocb_stat = IOCB_SUCCESS;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
void *dataout = NULL;
|
void *dataout = NULL;
|
||||||
uint32_t total_mem;
|
uint32_t total_mem;
|
||||||
|
@ -3149,6 +3150,7 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job)
|
||||||
}
|
}
|
||||||
cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC;
|
cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC;
|
||||||
cmdiocbq->vport = phba->pport;
|
cmdiocbq->vport = phba->pport;
|
||||||
|
cmdiocbq->iocb_cmpl = NULL;
|
||||||
iocb_stat = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq,
|
iocb_stat = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq,
|
||||||
rspiocbq, (phba->fc_ratov * 2) +
|
rspiocbq, (phba->fc_ratov * 2) +
|
||||||
LPFC_DRVR_TIMEOUT);
|
LPFC_DRVR_TIMEOUT);
|
||||||
|
@ -3209,7 +3211,7 @@ err_loopback_test_exit:
|
||||||
lpfc_bsg_event_unref(evt); /* delete */
|
lpfc_bsg_event_unref(evt); /* delete */
|
||||||
spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
|
spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
|
||||||
|
|
||||||
if (cmdiocbq != NULL)
|
if ((cmdiocbq != NULL) && (iocb_stat != IOCB_TIMEDOUT))
|
||||||
lpfc_sli_release_iocbq(phba, cmdiocbq);
|
lpfc_sli_release_iocbq(phba, cmdiocbq);
|
||||||
|
|
||||||
if (rspiocbq != NULL)
|
if (rspiocbq != NULL)
|
||||||
|
|
|
@ -5022,6 +5022,7 @@ lpfc_send_taskmgmt(struct lpfc_vport *vport, struct lpfc_rport_data *rdata,
|
||||||
lpfc_release_scsi_buf(phba, lpfc_cmd);
|
lpfc_release_scsi_buf(phba, lpfc_cmd);
|
||||||
return FAILED;
|
return FAILED;
|
||||||
}
|
}
|
||||||
|
iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl;
|
||||||
|
|
||||||
lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
|
lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
|
||||||
"0702 Issue %s to TGT %d LUN %d "
|
"0702 Issue %s to TGT %d LUN %d "
|
||||||
|
@ -5034,7 +5035,6 @@ lpfc_send_taskmgmt(struct lpfc_vport *vport, struct lpfc_rport_data *rdata,
|
||||||
iocbq, iocbqrsp, lpfc_cmd->timeout);
|
iocbq, iocbqrsp, lpfc_cmd->timeout);
|
||||||
if (status != IOCB_SUCCESS) {
|
if (status != IOCB_SUCCESS) {
|
||||||
if (status == IOCB_TIMEDOUT) {
|
if (status == IOCB_TIMEDOUT) {
|
||||||
iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl;
|
|
||||||
ret = TIMEOUT_ERROR;
|
ret = TIMEOUT_ERROR;
|
||||||
} else
|
} else
|
||||||
ret = FAILED;
|
ret = FAILED;
|
||||||
|
|
|
@ -9889,6 +9889,24 @@ lpfc_sli_wake_iocb_wait(struct lpfc_hba *phba,
|
||||||
struct lpfc_scsi_buf *lpfc_cmd;
|
struct lpfc_scsi_buf *lpfc_cmd;
|
||||||
|
|
||||||
spin_lock_irqsave(&phba->hbalock, iflags);
|
spin_lock_irqsave(&phba->hbalock, iflags);
|
||||||
|
if (cmdiocbq->iocb_flag & LPFC_IO_WAKE_TMO) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A time out has occurred for the iocb. If a time out
|
||||||
|
* completion handler has been supplied, call it. Otherwise,
|
||||||
|
* just free the iocbq.
|
||||||
|
*/
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&phba->hbalock, iflags);
|
||||||
|
cmdiocbq->iocb_cmpl = cmdiocbq->wait_iocb_cmpl;
|
||||||
|
cmdiocbq->wait_iocb_cmpl = NULL;
|
||||||
|
if (cmdiocbq->iocb_cmpl)
|
||||||
|
(cmdiocbq->iocb_cmpl)(phba, cmdiocbq, NULL);
|
||||||
|
else
|
||||||
|
lpfc_sli_release_iocbq(phba, cmdiocbq);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
cmdiocbq->iocb_flag |= LPFC_IO_WAKE;
|
cmdiocbq->iocb_flag |= LPFC_IO_WAKE;
|
||||||
if (cmdiocbq->context2 && rspiocbq)
|
if (cmdiocbq->context2 && rspiocbq)
|
||||||
memcpy(&((struct lpfc_iocbq *)cmdiocbq->context2)->iocb,
|
memcpy(&((struct lpfc_iocbq *)cmdiocbq->context2)->iocb,
|
||||||
|
@ -9944,10 +9962,16 @@ lpfc_chk_iocb_flg(struct lpfc_hba *phba,
|
||||||
* @timeout: Timeout in number of seconds.
|
* @timeout: Timeout in number of seconds.
|
||||||
*
|
*
|
||||||
* This function issues the iocb to firmware and waits for the
|
* This function issues the iocb to firmware and waits for the
|
||||||
* iocb to complete. If the iocb command is not
|
* iocb to complete. The iocb_cmpl field of the shall be used
|
||||||
* completed within timeout seconds, it returns IOCB_TIMEDOUT.
|
* to handle iocbs which time out. If the field is NULL, the
|
||||||
* Caller should not free the iocb resources if this function
|
* function shall free the iocbq structure. If more clean up is
|
||||||
* returns IOCB_TIMEDOUT.
|
* needed, the caller is expected to provide a completion function
|
||||||
|
* that will provide the needed clean up. If the iocb command is
|
||||||
|
* not completed within timeout seconds, the function will either
|
||||||
|
* free the iocbq structure (if iocb_cmpl == NULL) or execute the
|
||||||
|
* completion function set in the iocb_cmpl field and then return
|
||||||
|
* a status of IOCB_TIMEDOUT. The caller should not free the iocb
|
||||||
|
* resources if this function returns IOCB_TIMEDOUT.
|
||||||
* The function waits for the iocb completion using an
|
* The function waits for the iocb completion using an
|
||||||
* non-interruptible wait.
|
* non-interruptible wait.
|
||||||
* This function will sleep while waiting for iocb completion.
|
* This function will sleep while waiting for iocb completion.
|
||||||
|
@ -9980,6 +10004,9 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba,
|
||||||
int txq_cnt = 0;
|
int txq_cnt = 0;
|
||||||
int txcmplq_cnt = 0;
|
int txcmplq_cnt = 0;
|
||||||
struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
|
struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
|
||||||
|
unsigned long iflags;
|
||||||
|
bool iocb_completed = true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the caller has provided a response iocbq buffer, then context2
|
* If the caller has provided a response iocbq buffer, then context2
|
||||||
* is NULL or its an error.
|
* is NULL or its an error.
|
||||||
|
@ -9990,9 +10017,10 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba,
|
||||||
piocb->context2 = prspiocbq;
|
piocb->context2 = prspiocbq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
piocb->wait_iocb_cmpl = piocb->iocb_cmpl;
|
||||||
piocb->iocb_cmpl = lpfc_sli_wake_iocb_wait;
|
piocb->iocb_cmpl = lpfc_sli_wake_iocb_wait;
|
||||||
piocb->context_un.wait_queue = &done_q;
|
piocb->context_un.wait_queue = &done_q;
|
||||||
piocb->iocb_flag &= ~LPFC_IO_WAKE;
|
piocb->iocb_flag &= ~(LPFC_IO_WAKE | LPFC_IO_WAKE_TMO);
|
||||||
|
|
||||||
if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
|
if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
|
||||||
if (lpfc_readl(phba->HCregaddr, &creg_val))
|
if (lpfc_readl(phba->HCregaddr, &creg_val))
|
||||||
|
@ -10009,8 +10037,19 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba,
|
||||||
timeleft = wait_event_timeout(done_q,
|
timeleft = wait_event_timeout(done_q,
|
||||||
lpfc_chk_iocb_flg(phba, piocb, LPFC_IO_WAKE),
|
lpfc_chk_iocb_flg(phba, piocb, LPFC_IO_WAKE),
|
||||||
timeout_req);
|
timeout_req);
|
||||||
|
spin_lock_irqsave(&phba->hbalock, iflags);
|
||||||
|
if (!(piocb->iocb_flag & LPFC_IO_WAKE)) {
|
||||||
|
|
||||||
if (piocb->iocb_flag & LPFC_IO_WAKE) {
|
/*
|
||||||
|
* IOCB timed out. Inform the wake iocb wait
|
||||||
|
* completion function and set local status
|
||||||
|
*/
|
||||||
|
|
||||||
|
iocb_completed = false;
|
||||||
|
piocb->iocb_flag |= LPFC_IO_WAKE_TMO;
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&phba->hbalock, iflags);
|
||||||
|
if (iocb_completed) {
|
||||||
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
|
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
|
||||||
"0331 IOCB wake signaled\n");
|
"0331 IOCB wake signaled\n");
|
||||||
} else if (timeleft == 0) {
|
} else if (timeleft == 0) {
|
||||||
|
|
|
@ -60,7 +60,8 @@ struct lpfc_iocbq {
|
||||||
uint8_t retry; /* retry counter for IOCB cmd - if needed */
|
uint8_t retry; /* retry counter for IOCB cmd - if needed */
|
||||||
uint16_t iocb_flag;
|
uint16_t iocb_flag;
|
||||||
#define LPFC_IO_LIBDFC 1 /* libdfc iocb */
|
#define LPFC_IO_LIBDFC 1 /* libdfc iocb */
|
||||||
#define LPFC_IO_WAKE 2 /* High Priority Queue signal flag */
|
#define LPFC_IO_WAKE 2 /* Synchronous I/O completed */
|
||||||
|
#define LPFC_IO_WAKE_TMO LPFC_IO_WAKE /* Synchronous I/O timed out */
|
||||||
#define LPFC_IO_FCP 4 /* FCP command -- iocbq in scsi_buf */
|
#define LPFC_IO_FCP 4 /* FCP command -- iocbq in scsi_buf */
|
||||||
#define LPFC_DRIVER_ABORTED 8 /* driver aborted this request */
|
#define LPFC_DRIVER_ABORTED 8 /* driver aborted this request */
|
||||||
#define LPFC_IO_FABRIC 0x10 /* Iocb send using fabric scheduler */
|
#define LPFC_IO_FABRIC 0x10 /* Iocb send using fabric scheduler */
|
||||||
|
@ -93,6 +94,8 @@ struct lpfc_iocbq {
|
||||||
|
|
||||||
void (*fabric_iocb_cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
|
void (*fabric_iocb_cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
|
||||||
struct lpfc_iocbq *);
|
struct lpfc_iocbq *);
|
||||||
|
void (*wait_iocb_cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
|
||||||
|
struct lpfc_iocbq *);
|
||||||
void (*iocb_cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
|
void (*iocb_cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
|
||||||
struct lpfc_iocbq *);
|
struct lpfc_iocbq *);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Reference in a new issue