diff options
author | Chad Dupuis <chad.dupuis@cavium.com> | 2018-04-25 06:09:03 -0700 |
---|---|---|
committer | Martin K. Petersen <martin.petersen@oracle.com> | 2018-05-08 00:57:11 -0400 |
commit | f3690a89f918031a5eed17da78af51c329efe93a (patch) | |
tree | ea976faae5dcab27e73c177653f73c291d1509e6 /drivers/scsi/qedf/qedf_io.c | |
parent | 4f4616ceebaf045c59e8a6aa01f08826d18d5c63 (diff) | |
download | linux-f3690a89f918031a5eed17da78af51c329efe93a.tar.gz linux-f3690a89f918031a5eed17da78af51c329efe93a.tar.bz2 linux-f3690a89f918031a5eed17da78af51c329efe93a.zip |
scsi: qedf: Add more defensive checks for concurrent error conditions
During an uplink toggle test all error handling is done via timeout and
firmware error conditions which can occur concurrently:
- SCSI layer timeouts
- Error detect CQEs
- Firmware detected underruns
- ABTS timeouts
All these concurrent events require more defensive checks in the driver
including:
- Check both internally and externally generated aborts to make sure the
xid is not already been aborted in another context or in cleanup.
- Check back pointers in qedf_cmd_timeout to verify the context of the
io_req, fcport and qedf_ctx
- Check rport state in host reset handler to not reset the whole host
if the rport is already uploaded or in the process of relogin
- Check to state for an fcport before initiating a middle path ELS
request
Signed-off-by: Chad Dupuis <chad.dupuis@cavium.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'drivers/scsi/qedf/qedf_io.c')
-rw-r--r-- | drivers/scsi/qedf/qedf_io.c | 33 |
1 files changed, 31 insertions, 2 deletions
diff --git a/drivers/scsi/qedf/qedf_io.c b/drivers/scsi/qedf/qedf_io.c index f669df03f37d..07925f8e65bf 100644 --- a/drivers/scsi/qedf/qedf_io.c +++ b/drivers/scsi/qedf/qedf_io.c @@ -23,12 +23,31 @@ static void qedf_cmd_timeout(struct work_struct *work) struct qedf_ioreq *io_req = container_of(work, struct qedf_ioreq, timeout_work.work); - struct qedf_ctx *qedf = io_req->fcport->qedf; - struct qedf_rport *fcport = io_req->fcport; + struct qedf_ctx *qedf; + struct qedf_rport *fcport; u8 op = 0; + if (io_req == NULL) { + QEDF_INFO(NULL, QEDF_LOG_IO, "io_req is NULL.\n"); + return; + } + + fcport = io_req->fcport; + if (io_req->fcport == NULL) { + QEDF_INFO(NULL, QEDF_LOG_IO, "fcport is NULL.\n"); + return; + } + + qedf = fcport->qedf; + switch (io_req->cmd_type) { case QEDF_ABTS: + if (qedf == NULL) { + QEDF_INFO(NULL, QEDF_LOG_IO, "qedf is NULL for xid=0x%x.\n", + io_req->xid); + return; + } + QEDF_ERR((&qedf->dbg_ctx), "ABTS timeout, xid=0x%x.\n", io_req->xid); /* Cleanup timed out ABTS */ @@ -1565,6 +1584,16 @@ int qedf_initiate_abts(struct qedf_ioreq *io_req, bool return_scsi_cmd_on_abts) goto out; } + if (!test_bit(QEDF_CMD_OUTSTANDING, &io_req->flags) || + test_bit(QEDF_CMD_IN_CLEANUP, &io_req->flags) || + test_bit(QEDF_CMD_IN_ABORT, &io_req->flags)) { + QEDF_ERR(&(qedf->dbg_ctx), "io_req xid=0x%x already in " + "cleanup or abort processing or already " + "completed.\n", io_req->xid); + rc = 1; + goto out; + } + kref_get(&io_req->refcount); xid = io_req->xid; |