Skip to content

Commit

Permalink
[SCSI] bnx2fc: Decrememnt io ref count when abort times out
Browse files Browse the repository at this point in the history
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: Bhanu Prakash Gollapudi <[email protected]>
Signed-off-by: James Bottomley <[email protected]>
  • Loading branch information
Bhanu Prakash Gollapudi authored and James Bottomley committed May 22, 2012
1 parent de9c05f commit c1bb4f3
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 47 deletions.
106 changes: 60 additions & 46 deletions drivers/scsi/bnx2fc/bnx2fc_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -1089,6 +1089,48 @@ int bnx2fc_eh_device_reset(struct scsi_cmnd *sc_cmd)
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
* SCSI command
Expand All @@ -1103,10 +1145,7 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd)
struct fc_rport_libfc_priv *rp = rport->dd_data;
struct bnx2fc_cmd *io_req;
struct fc_lport *lport;
struct fc_rport_priv *rdata;
struct bnx2fc_rport *tgt;
int logo_issued;
int wait_cnt = 0;
int rc = FAILED;


Expand Down Expand Up @@ -1183,58 +1222,31 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd)
list_add_tail(&io_req->link, &tgt->io_retire_queue);

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)) {
/* 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 {
if (test_and_set_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags)) {
printk(KERN_ERR PFX "eh_abort: io_req (xid = 0x%x) "
"already in abts processing\n", io_req->xid);
if (cancel_delayed_work(&io_req->timeout_work))
kref_put(&io_req->refcount,
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);

wait_for_completion(&io_req->tm_done);

spin_lock_bh(&tgt->tgt_lock);
io_req->wait_for_comp = 0;
rdata = io_req->tgt->rdata;
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;
goto done;
}
spin_unlock_bh(&tgt->tgt_lock);

Expand All @@ -1247,7 +1259,8 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd)
/* Let the scsi-ml try to recover this command */
printk(KERN_ERR PFX "abort failed, xid = 0x%x\n",
io_req->xid);
rc = FAILED;
rc = bnx2fc_expl_logo(lport, io_req);
goto out;
} else {
/*
* We come here even when there was a race condition
Expand All @@ -1259,9 +1272,10 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd)
bnx2fc_scsi_done(io_req, DID_ABORT);
kref_put(&io_req->refcount, bnx2fc_cmd_release);
}

done:
/* release the reference taken in eh_abort */
kref_put(&io_req->refcount, bnx2fc_cmd_release);
out:
spin_unlock_bh(&tgt->tgt_lock);
return rc;
}
Expand Down
11 changes: 10 additions & 1 deletion drivers/scsi/bnx2fc/bnx2fc_tgt.c
Original file line number Diff line number Diff line change
Expand Up @@ -213,8 +213,17 @@ void bnx2fc_flush_active_ios(struct bnx2fc_rport *tgt)

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);
}

clear_bit(BNX2FC_FLAG_ISSUE_RRQ, &io_req->req_flags);
}
Expand Down

0 comments on commit c1bb4f3

Please sign in to comment.