summaryrefslogtreecommitdiff
path: root/drivers/scsi/qedf/qedf_main.c
diff options
context:
space:
mode:
authorSaurav Kashyap <skashyap@marvell.com>2019-03-26 10:38:38 +0300
committerMartin K. Petersen <martin.petersen@oracle.com>2019-03-28 04:54:52 +0300
commit69ef2c692510d5154c613569caeeed3c74806231 (patch)
tree5a9e9b0ee3ecfe4d1c0eacaa4067e76769ac422b /drivers/scsi/qedf/qedf_main.c
parent5d5e55659b375a39a42dad988869cd9966d20255 (diff)
downloadlinux-69ef2c692510d5154c613569caeeed3c74806231.tar.xz
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_main.c')
-rw-r--r--drivers/scsi/qedf/qedf_main.c124
1 files changed, 90 insertions, 34 deletions
diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c
index a13b158df492..5bef6641dea0 100644
--- a/drivers/scsi/qedf/qedf_main.c
+++ b/drivers/scsi/qedf/qedf_main.c
@@ -615,50 +615,113 @@ static struct scsi_transport_template *qedf_fc_vport_transport_template;
static int qedf_eh_abort(struct scsi_cmnd *sc_cmd)
{
struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device));
- struct fc_rport_libfc_priv *rp = rport->dd_data;
- struct qedf_rport *fcport;
struct fc_lport *lport;
struct qedf_ctx *qedf;
struct qedf_ioreq *io_req;
+ struct fc_rport_libfc_priv *rp = rport->dd_data;
+ struct fc_rport_priv *rdata;
+ struct qedf_rport *fcport = NULL;
int rc = FAILED;
+ int wait_count = 100;
+ int refcount = 0;
int rval;
-
- if (fc_remote_port_chkready(rport)) {
- QEDF_ERR(NULL, "rport not ready\n");
- goto out;
- }
+ int got_ref = 0;
lport = shost_priv(sc_cmd->device->host);
qedf = (struct qedf_ctx *)lport_priv(lport);
- if ((lport->state != LPORT_ST_READY) || !(lport->link_up)) {
- QEDF_ERR(&(qedf->dbg_ctx), "link not ready.\n");
+ /* rport and tgt are allocated together, so tgt should be non-NULL */
+ fcport = (struct qedf_rport *)&rp[1];
+ rdata = fcport->rdata;
+ if (!rdata || !kref_get_unless_zero(&rdata->kref)) {
+ QEDF_ERR(&qedf->dbg_ctx, "stale rport, sc_cmd=%p\n", sc_cmd);
+ rc = 1;
goto out;
}
- fcport = (struct qedf_rport *)&rp[1];
io_req = (struct qedf_ioreq *)sc_cmd->SCp.ptr;
if (!io_req) {
- QEDF_ERR(&(qedf->dbg_ctx), "io_req is NULL.\n");
+ QEDF_ERR(&qedf->dbg_ctx,
+ "sc_cmd not queued with lld, sc_cmd=%p op=0x%02x, port_id=%06x\n",
+ sc_cmd, sc_cmd->cmnd[0],
+ rdata->ids.port_id);
rc = SUCCESS;
- goto out;
+ goto drop_rdata_kref;
}
- QEDF_ERR(&(qedf->dbg_ctx), "Aborting io_req sc_cmd=%p xid=0x%x "
- "fp_idx=%d.\n", sc_cmd, io_req->xid, io_req->fp_idx);
+ rval = kref_get_unless_zero(&io_req->refcount); /* ID: 005 */
+ if (rval)
+ got_ref = 1;
+
+ /* If we got a valid io_req, confirm it belongs to this sc_cmd. */
+ if (!rval || io_req->sc_cmd != sc_cmd) {
+ QEDF_ERR(&qedf->dbg_ctx,
+ "Freed/Incorrect io_req, io_req->sc_cmd=%p, sc_cmd=%p, port_id=%06x, bailing out.\n",
+ io_req->sc_cmd, sc_cmd, rdata->ids.port_id);
+
+ goto drop_rdata_kref;
+ }
+
+ if (fc_remote_port_chkready(rport)) {
+ refcount = kref_read(&io_req->refcount);
+ QEDF_ERR(&qedf->dbg_ctx,
+ "rport not ready, io_req=%p, xid=0x%x sc_cmd=%p op=0x%02x, refcount=%d, port_id=%06x\n",
+ io_req, io_req->xid, sc_cmd, sc_cmd->cmnd[0],
+ refcount, rdata->ids.port_id);
+
+ goto drop_rdata_kref;
+ }
+
+ rc = fc_block_scsi_eh(sc_cmd);
+ if (rc)
+ goto drop_rdata_kref;
+
+ if (test_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags)) {
+ QEDF_ERR(&qedf->dbg_ctx,
+ "Connection uploading, xid=0x%x., port_id=%06x\n",
+ io_req->xid, rdata->ids.port_id);
+ while (io_req->sc_cmd && (wait_count != 0)) {
+ msleep(100);
+ wait_count--;
+ }
+ if (wait_count) {
+ QEDF_ERR(&qedf->dbg_ctx, "ABTS succeeded\n");
+ rc = SUCCESS;
+ } else {
+ QEDF_ERR(&qedf->dbg_ctx, "ABTS failed\n");
+ rc = FAILED;
+ }
+ goto drop_rdata_kref;
+ }
+
+ if (lport->state != LPORT_ST_READY || !(lport->link_up)) {
+ QEDF_ERR(&qedf->dbg_ctx, "link not ready.\n");
+ goto drop_rdata_kref;
+ }
+
+ QEDF_ERR(&qedf->dbg_ctx,
+ "Aborting io_req=%p sc_cmd=%p xid=0x%x fp_idx=%d, port_id=%06x.\n",
+ io_req, sc_cmd, io_req->xid, io_req->fp_idx,
+ rdata->ids.port_id);
if (qedf->stop_io_on_error) {
qedf_stop_all_io(qedf);
rc = SUCCESS;
- goto out;
+ goto drop_rdata_kref;
}
init_completion(&io_req->abts_done);
rval = qedf_initiate_abts(io_req, true);
if (rval) {
QEDF_ERR(&(qedf->dbg_ctx), "Failed to queue ABTS.\n");
- goto out;
+ /*
+ * If we fail to queue the ABTS then return this command to
+ * the SCSI layer as it will own and free the xid
+ */
+ rc = SUCCESS;
+ qedf_scsi_done(qedf, io_req, DID_ERROR);
+ goto drop_rdata_kref;
}
wait_for_completion(&io_req->abts_done);
@@ -684,19 +747,27 @@ static int qedf_eh_abort(struct scsi_cmnd *sc_cmd)
QEDF_ERR(&(qedf->dbg_ctx), "ABTS failed, xid=0x%x.\n",
io_req->xid);
+drop_rdata_kref:
+ kref_put(&rdata->kref, fc_rport_destroy);
out:
+ if (got_ref)
+ kref_put(&io_req->refcount, qedf_release_cmd);
return rc;
}
static int qedf_eh_target_reset(struct scsi_cmnd *sc_cmd)
{
- QEDF_ERR(NULL, "TARGET RESET Issued...");
+ QEDF_ERR(NULL, "%d:0:%d:%lld: TARGET RESET Issued...",
+ sc_cmd->device->host->host_no, sc_cmd->device->id,
+ sc_cmd->device->lun);
return qedf_initiate_tmf(sc_cmd, FCP_TMF_TGT_RESET);
}
static int qedf_eh_device_reset(struct scsi_cmnd *sc_cmd)
{
- QEDF_ERR(NULL, "LUN RESET Issued...\n");
+ QEDF_ERR(NULL, "%d:0:%d:%lld: LUN RESET Issued... ",
+ sc_cmd->device->host->host_no, sc_cmd->device->id,
+ sc_cmd->device->lun);
return qedf_initiate_tmf(sc_cmd, FCP_TMF_LUN_RESET);
}
@@ -740,22 +811,6 @@ static int qedf_eh_host_reset(struct scsi_cmnd *sc_cmd)
{
struct fc_lport *lport;
struct qedf_ctx *qedf;
- struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device));
- struct fc_rport_libfc_priv *rp = rport->dd_data;
- struct qedf_rport *fcport = (struct qedf_rport *)&rp[1];
- int rval;
-
- rval = fc_remote_port_chkready(rport);
-
- if (rval) {
- QEDF_ERR(NULL, "device_reset rport not ready\n");
- return FAILED;
- }
-
- if (fcport == NULL) {
- QEDF_ERR(NULL, "device_reset: rport is NULL\n");
- return FAILED;
- }
lport = shost_priv(sc_cmd->device->host);
qedf = lport_priv(lport);
@@ -3007,6 +3062,7 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)
pci_set_drvdata(pdev, qedf);
init_completion(&qedf->fipvlan_compl);
mutex_init(&qedf->stats_mutex);
+ mutex_init(&qedf->flush_mutex);
QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_INFO,
"QLogic FastLinQ FCoE Module qedf %s, "