summaryrefslogtreecommitdiff
path: root/drivers/scsi/qedf/qedf_els.c
diff options
context:
space:
mode:
authorSaurav Kashyap <skashyap@marvell.com>2019-03-26 00:38:38 -0700
committerMartin K. Petersen <martin.petersen@oracle.com>2019-03-27 21:54:52 -0400
commit69ef2c692510d5154c613569caeeed3c74806231 (patch)
tree5a9e9b0ee3ecfe4d1c0eacaa4067e76769ac422b /drivers/scsi/qedf/qedf_els.c
parent5d5e55659b375a39a42dad988869cd9966d20255 (diff)
downloadlinux-next-69ef2c692510d5154c613569caeeed3c74806231.tar.gz
scsi: qedf: Modify abort and tmf handler to handle edge condition and flush
An I/O can be in any state when flush is called, it can be in abort, waiting for abort, RRQ send and waiting or TMF send. - HZ can be different on different architecture, correctly set abort timeout value. - Flush can complete the I/Os prematurely, handle refcount for aborted I/Os and for which RRQ is pending. - Differentiate LUN/TARGET reset, as cleanup needs to be send to firmware accordingly. - Add flush mutex to sync cleanup call from abort and flush routine. - Clear abort/outstanding bit on timeout. Signed-off-by: Shyam Sundar <shyam.sundar@marvell.com> Signed-off-by: Chad Dupuis <cdupuis@marvell.com> Signed-off-by: Saurav Kashyap <skashyap@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'drivers/scsi/qedf/qedf_els.c')
-rw-r--r--drivers/scsi/qedf/qedf_els.c31
1 files changed, 29 insertions, 2 deletions
diff --git a/drivers/scsi/qedf/qedf_els.c b/drivers/scsi/qedf/qedf_els.c
index a60819b40eaf..ac2bfc26bcdb 100644
--- a/drivers/scsi/qedf/qedf_els.c
+++ b/drivers/scsi/qedf/qedf_els.c
@@ -201,8 +201,12 @@ static void qedf_rrq_compl(struct qedf_els_cb_arg *cb_arg)
" orig xid = 0x%x, rrq_xid = 0x%x, refcount=%d\n",
orig_io_req, orig_io_req->xid, rrq_req->xid, refcount);
- /* This should return the aborted io_req to the command pool */
- if (orig_io_req)
+ /*
+ * This should return the aborted io_req to the command pool. Note that
+ * we need to check the refcound in case the original request was
+ * flushed but we get a completion on this xid.
+ */
+ if (orig_io_req && refcount > 0)
kref_put(&orig_io_req->refcount, qedf_release_cmd);
out_free:
@@ -229,6 +233,7 @@ int qedf_send_rrq(struct qedf_ioreq *aborted_io_req)
uint32_t sid;
uint32_t r_a_tov;
int rc;
+ int refcount;
if (!aborted_io_req) {
QEDF_ERR(NULL, "abort_io_req is NULL.\n");
@@ -237,6 +242,15 @@ int qedf_send_rrq(struct qedf_ioreq *aborted_io_req)
fcport = aborted_io_req->fcport;
+ if (!fcport) {
+ refcount = kref_read(&aborted_io_req->refcount);
+ QEDF_ERR(NULL,
+ "RRQ work was queued prior to a flush xid=0x%x, refcount=%d.\n",
+ aborted_io_req->xid, refcount);
+ kref_put(&aborted_io_req->refcount, qedf_release_cmd);
+ return -EINVAL;
+ }
+
/* Check that fcport is still offloaded */
if (!test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags)) {
QEDF_ERR(NULL, "fcport is no longer offloaded.\n");
@@ -249,6 +263,19 @@ int qedf_send_rrq(struct qedf_ioreq *aborted_io_req)
}
qedf = fcport->qedf;
+
+ /*
+ * Sanity check that we can send a RRQ to make sure that refcount isn't
+ * 0
+ */
+ refcount = kref_read(&aborted_io_req->refcount);
+ if (refcount != 1) {
+ QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_ELS,
+ "refcount for xid=%x io_req=%p refcount=%d is not 1.\n",
+ aborted_io_req->xid, aborted_io_req, refcount);
+ return -EINVAL;
+ }
+
lport = qedf->lport;
sid = fcport->sid;
r_a_tov = lport->r_a_tov;