Commit 5a0916b4 authored by James Smart's avatar James Smart Committed by James Bottomley

[SCSI] lpfc 8.3.41: Fixed freeing of iocb when internal loopback times out

Signed-off-by: default avatarJames Smart <james.smart@emulex.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent b56a15d1
...@@ -2498,7 +2498,7 @@ static int lpfcdiag_loop_get_xri(struct lpfc_hba *phba, uint16_t rpi, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job) ...@@ -3209,7 +3211,7 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job)
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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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)) {
/*
* IOCB timed out. Inform the wake iocb wait
* completion function and set local status
*/
if (piocb->iocb_flag & LPFC_IO_WAKE) { 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 { ...@@ -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 { ...@@ -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 *);
}; };
......
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