Commit c1bb4f33 authored by Bhanu Prakash Gollapudi's avatar Bhanu Prakash Gollapudi Committed by James Bottomley

[SCSI] bnx2fc: Decrememnt io ref count when abort times out

When IO abort times out during eh_abort or a flush operation is performed while
abort is pending, the driver is not cleaning up the IO and thus not reducing
the IO reference count. With this change, as part of explicit logout, the IO is
cleaned up.
Signed-off-by: default avatarBhanu Prakash Gollapudi <bprakash@broadcom.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent de9c05fa
...@@ -1089,6 +1089,48 @@ int bnx2fc_eh_device_reset(struct scsi_cmnd *sc_cmd) ...@@ -1089,6 +1089,48 @@ int bnx2fc_eh_device_reset(struct scsi_cmnd *sc_cmd)
return bnx2fc_initiate_tmf(sc_cmd, FCP_TMF_LUN_RESET); return bnx2fc_initiate_tmf(sc_cmd, FCP_TMF_LUN_RESET);
} }
int bnx2fc_expl_logo(struct fc_lport *lport, struct bnx2fc_cmd *io_req)
{
struct bnx2fc_rport *tgt = io_req->tgt;
struct fc_rport_priv *rdata = tgt->rdata;
int logo_issued;
int rc = SUCCESS;
int wait_cnt = 0;
BNX2FC_IO_DBG(io_req, "Expl logo - tgt flags = 0x%lx\n",
tgt->flags);
logo_issued = test_and_set_bit(BNX2FC_FLAG_EXPL_LOGO,
&tgt->flags);
io_req->wait_for_comp = 1;
bnx2fc_initiate_cleanup(io_req);
spin_unlock_bh(&tgt->tgt_lock);
wait_for_completion(&io_req->tm_done);
io_req->wait_for_comp = 0;
/*
* release the reference taken in eh_abort to allow the
* target to re-login after flushing IOs
*/
kref_put(&io_req->refcount, bnx2fc_cmd_release);
if (!logo_issued) {
clear_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags);
mutex_lock(&lport->disc.disc_mutex);
lport->tt.rport_logoff(rdata);
mutex_unlock(&lport->disc.disc_mutex);
do {
msleep(BNX2FC_RELOGIN_WAIT_TIME);
if (wait_cnt++ > BNX2FC_RELOGIN_WAIT_CNT) {
rc = FAILED;
break;
}
} while (!test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags));
}
spin_lock_bh(&tgt->tgt_lock);
return rc;
}
/** /**
* bnx2fc_eh_abort - eh_abort_handler api to abort an outstanding * bnx2fc_eh_abort - eh_abort_handler api to abort an outstanding
* SCSI command * SCSI command
...@@ -1103,10 +1145,7 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd) ...@@ -1103,10 +1145,7 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd)
struct fc_rport_libfc_priv *rp = rport->dd_data; struct fc_rport_libfc_priv *rp = rport->dd_data;
struct bnx2fc_cmd *io_req; struct bnx2fc_cmd *io_req;
struct fc_lport *lport; struct fc_lport *lport;
struct fc_rport_priv *rdata;
struct bnx2fc_rport *tgt; struct bnx2fc_rport *tgt;
int logo_issued;
int wait_cnt = 0;
int rc = FAILED; int rc = FAILED;
...@@ -1183,58 +1222,31 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd) ...@@ -1183,58 +1222,31 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd)
list_add_tail(&io_req->link, &tgt->io_retire_queue); list_add_tail(&io_req->link, &tgt->io_retire_queue);
init_completion(&io_req->tm_done); init_completion(&io_req->tm_done);
io_req->wait_for_comp = 1;
if (!test_and_set_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags)) { if (test_and_set_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags)) {
/* Cancel the current timer running on this io_req */
if (cancel_delayed_work(&io_req->timeout_work))
kref_put(&io_req->refcount,
bnx2fc_cmd_release); /* drop timer hold */
set_bit(BNX2FC_FLAG_EH_ABORT, &io_req->req_flags);
rc = bnx2fc_initiate_abts(io_req);
} else {
printk(KERN_ERR PFX "eh_abort: io_req (xid = 0x%x) " printk(KERN_ERR PFX "eh_abort: io_req (xid = 0x%x) "
"already in abts processing\n", io_req->xid); "already in abts processing\n", io_req->xid);
if (cancel_delayed_work(&io_req->timeout_work)) if (cancel_delayed_work(&io_req->timeout_work))
kref_put(&io_req->refcount, kref_put(&io_req->refcount,
bnx2fc_cmd_release); /* drop timer hold */ bnx2fc_cmd_release); /* drop timer hold */
bnx2fc_initiate_cleanup(io_req); rc = bnx2fc_expl_logo(lport, io_req);
goto out;
}
/* Cancel the current timer running on this io_req */
if (cancel_delayed_work(&io_req->timeout_work))
kref_put(&io_req->refcount,
bnx2fc_cmd_release); /* drop timer hold */
set_bit(BNX2FC_FLAG_EH_ABORT, &io_req->req_flags);
io_req->wait_for_comp = 1;
rc = bnx2fc_initiate_abts(io_req);
if (rc == FAILED) {
bnx2fc_initiate_cleanup(io_req);
spin_unlock_bh(&tgt->tgt_lock); spin_unlock_bh(&tgt->tgt_lock);
wait_for_completion(&io_req->tm_done); wait_for_completion(&io_req->tm_done);
spin_lock_bh(&tgt->tgt_lock); spin_lock_bh(&tgt->tgt_lock);
io_req->wait_for_comp = 0; io_req->wait_for_comp = 0;
rdata = io_req->tgt->rdata; goto done;
logo_issued = test_and_set_bit(BNX2FC_FLAG_EXPL_LOGO,
&tgt->flags);
kref_put(&io_req->refcount, bnx2fc_cmd_release);
spin_unlock_bh(&tgt->tgt_lock);
if (!logo_issued) {
BNX2FC_IO_DBG(io_req, "Expl logo - tgt flags = 0x%lx\n",
tgt->flags);
mutex_lock(&lport->disc.disc_mutex);
lport->tt.rport_logoff(rdata);
mutex_unlock(&lport->disc.disc_mutex);
do {
msleep(BNX2FC_RELOGIN_WAIT_TIME);
/*
* If session not recovered, let SCSI-ml
* escalate error recovery.
*/
if (wait_cnt++ > BNX2FC_RELOGIN_WAIT_CNT)
return FAILED;
} while (!test_bit(BNX2FC_FLAG_SESSION_READY,
&tgt->flags));
}
return SUCCESS;
}
if (rc == FAILED) {
kref_put(&io_req->refcount, bnx2fc_cmd_release);
spin_unlock_bh(&tgt->tgt_lock);
return rc;
} }
spin_unlock_bh(&tgt->tgt_lock); spin_unlock_bh(&tgt->tgt_lock);
...@@ -1247,7 +1259,8 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd) ...@@ -1247,7 +1259,8 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd)
/* Let the scsi-ml try to recover this command */ /* Let the scsi-ml try to recover this command */
printk(KERN_ERR PFX "abort failed, xid = 0x%x\n", printk(KERN_ERR PFX "abort failed, xid = 0x%x\n",
io_req->xid); io_req->xid);
rc = FAILED; rc = bnx2fc_expl_logo(lport, io_req);
goto out;
} else { } else {
/* /*
* We come here even when there was a race condition * We come here even when there was a race condition
...@@ -1259,9 +1272,10 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd) ...@@ -1259,9 +1272,10 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd)
bnx2fc_scsi_done(io_req, DID_ABORT); bnx2fc_scsi_done(io_req, DID_ABORT);
kref_put(&io_req->refcount, bnx2fc_cmd_release); kref_put(&io_req->refcount, bnx2fc_cmd_release);
} }
done:
/* release the reference taken in eh_abort */ /* release the reference taken in eh_abort */
kref_put(&io_req->refcount, bnx2fc_cmd_release); kref_put(&io_req->refcount, bnx2fc_cmd_release);
out:
spin_unlock_bh(&tgt->tgt_lock); spin_unlock_bh(&tgt->tgt_lock);
return rc; return rc;
} }
......
...@@ -213,8 +213,17 @@ void bnx2fc_flush_active_ios(struct bnx2fc_rport *tgt) ...@@ -213,8 +213,17 @@ void bnx2fc_flush_active_ios(struct bnx2fc_rport *tgt)
BNX2FC_IO_DBG(io_req, "retire_queue flush\n"); BNX2FC_IO_DBG(io_req, "retire_queue flush\n");
if (cancel_delayed_work(&io_req->timeout_work)) if (cancel_delayed_work(&io_req->timeout_work)) {
if (test_and_clear_bit(BNX2FC_FLAG_EH_ABORT,
&io_req->req_flags)) {
/* Handle eh_abort timeout */
BNX2FC_IO_DBG(io_req, "eh_abort for IO "
"in retire_q\n");
if (io_req->wait_for_comp)
complete(&io_req->tm_done);
}
kref_put(&io_req->refcount, bnx2fc_cmd_release); kref_put(&io_req->refcount, bnx2fc_cmd_release);
}
clear_bit(BNX2FC_FLAG_ISSUE_RRQ, &io_req->req_flags); clear_bit(BNX2FC_FLAG_ISSUE_RRQ, &io_req->req_flags);
} }
......
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