scsi: core: Change the return type of .eh_timed_out()
authorBart Van Assche <bvanassche@acm.org>
Tue, 18 Oct 2022 20:29:50 +0000 (13:29 -0700)
committerMartin K. Petersen <martin.petersen@oracle.com>
Sat, 22 Oct 2022 03:25:59 +0000 (03:25 +0000)
Commit 6600593cbd93 ("block: rename BLK_EH_NOT_HANDLED to BLK_EH_DONE")
made it impossible for .eh_timed_out() implementations to call
scsi_done() without causing a crash.

Restore support for SCSI timeout handlers to call scsi_done() as follows:

 * Change all .eh_timed_out() handlers as follows:

   - Change the return type into enum scsi_timeout_action.
   - Change BLK_EH_RESET_TIMER into SCSI_EH_RESET_TIMER.
   - Change BLK_EH_DONE into SCSI_EH_NOT_HANDLED.

 * In scsi_timeout(), convert the SCSI_EH_* values into BLK_EH_* values.

Reviewed-by: Lee Duncan <lduncan@suse.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Ming Lei <ming.lei@redhat.com>
Cc: John Garry <john.garry@huawei.com>
Cc: Mike Christie <michael.christie@oracle.com>
Cc: Hannes Reinecke <hare@suse.de>
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
Link: https://lore.kernel.org/r/20221018202958.1902564-3-bvanassche@acm.org
Reviewed-by: Mike Christie <michael.christie@oracle.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
15 files changed:
Documentation/scsi/scsi_eh.rst
drivers/message/fusion/mptsas.c
drivers/scsi/libiscsi.c
drivers/scsi/megaraid/megaraid_sas_base.c
drivers/scsi/mvumi.c
drivers/scsi/qla4xxx/ql4_os.c
drivers/scsi/scsi_error.c
drivers/scsi/scsi_transport_fc.c
drivers/scsi/scsi_transport_srp.c
drivers/scsi/storvsc_drv.c
drivers/scsi/virtio_scsi.c
include/scsi/libiscsi.h
include/scsi/scsi_host.h
include/scsi/scsi_transport_fc.h
include/scsi/scsi_transport_srp.h

index bad624f..104d09e 100644 (file)
@@ -92,14 +92,17 @@ The timeout handler is scsi_timeout().  When a timeout occurs, this function
  1. invokes optional hostt->eh_timed_out() callback.  Return value can
     be one of
 
-    - BLK_EH_RESET_TIMER
+    - SCSI_EH_RESET_TIMER
        This indicates that more time is required to finish the
        command.  Timer is restarted.
 
-    - BLK_EH_DONE
+    - SCSI_EH_NOT_HANDLED
         eh_timed_out() callback did not handle the command.
        Step #2 is taken.
 
+    - SCSI_EH_DONE
+        eh_timed_out() completed the command.
+
  2. scsi_abort_command() is invoked to schedule an asynchronous abort which may
     issue a retry scmd->allowed + 1 times.  Asynchronous aborts are not invoked
     for commands for which the SCSI_EH_ABORT_SCHEDULED flag is set (this
index 34901bc..88fe4a8 100644 (file)
@@ -1952,12 +1952,12 @@ mptsas_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *SCpnt)
  *     @sc: scsi command that the midlayer is about to time out
  *
  **/
-static enum blk_eh_timer_return mptsas_eh_timed_out(struct scsi_cmnd *sc)
+static enum scsi_timeout_action mptsas_eh_timed_out(struct scsi_cmnd *sc)
 {
        MPT_SCSI_HOST *hd;
        MPT_ADAPTER   *ioc;
        VirtDevice    *vdevice;
-       enum blk_eh_timer_return rc = BLK_EH_DONE;
+       enum scsi_timeout_action rc = SCSI_EH_NOT_HANDLED;
 
        hd = shost_priv(sc->device->host);
        if (hd == NULL) {
@@ -1980,7 +1980,7 @@ static enum blk_eh_timer_return mptsas_eh_timed_out(struct scsi_cmnd *sc)
                dtmprintk(ioc, printk(MYIOC_s_WARN_FMT ": %s: ioc is in reset,"
                    "SML need to reset the timer (sc=%p)\n",
                    ioc->name, __func__, sc));
-               rc = BLK_EH_RESET_TIMER;
+               rc = SCSI_EH_RESET_TIMER;
        }
        vdevice = sc->device->hostdata;
        if (vdevice && vdevice->vtarget && (vdevice->vtarget->inDMD
@@ -1988,7 +1988,7 @@ static enum blk_eh_timer_return mptsas_eh_timed_out(struct scsi_cmnd *sc)
                dtmprintk(ioc, printk(MYIOC_s_WARN_FMT ": %s: target removed "
                    "or in device removal delay (sc=%p)\n",
                    ioc->name, __func__, sc));
-               rc = BLK_EH_RESET_TIMER;
+               rc = SCSI_EH_RESET_TIMER;
                goto done;
        }
 
index d95f4bc..ef2fc86 100644 (file)
@@ -2071,9 +2071,9 @@ static int iscsi_has_ping_timed_out(struct iscsi_conn *conn)
                return 0;
 }
 
-enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc)
+enum scsi_timeout_action iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc)
 {
-       enum blk_eh_timer_return rc = BLK_EH_DONE;
+       enum scsi_timeout_action rc = SCSI_EH_NOT_HANDLED;
        struct iscsi_task *task = NULL, *running_task;
        struct iscsi_cls_session *cls_session;
        struct iscsi_session *session;
@@ -2093,7 +2093,7 @@ enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc)
                 * Raced with completion. Blk layer has taken ownership
                 * so let timeout code complete it now.
                 */
-               rc = BLK_EH_DONE;
+               rc = SCSI_EH_NOT_HANDLED;
                spin_unlock(&session->back_lock);
                goto done;
        }
@@ -2102,7 +2102,7 @@ enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc)
                 * Racing with the completion path right now, so give it more
                 * time so that path can complete it like normal.
                 */
-               rc = BLK_EH_RESET_TIMER;
+               rc = SCSI_EH_RESET_TIMER;
                task = NULL;
                spin_unlock(&session->back_lock);
                goto done;
@@ -2120,21 +2120,21 @@ enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc)
                if (unlikely(system_state != SYSTEM_RUNNING)) {
                        sc->result = DID_NO_CONNECT << 16;
                        ISCSI_DBG_EH(session, "sc on shutdown, handled\n");
-                       rc = BLK_EH_DONE;
+                       rc = SCSI_EH_NOT_HANDLED;
                        goto done;
                }
                /*
                 * We are probably in the middle of iscsi recovery so let
                 * that complete and handle the error.
                 */
-               rc = BLK_EH_RESET_TIMER;
+               rc = SCSI_EH_RESET_TIMER;
                goto done;
        }
 
        conn = session->leadconn;
        if (!conn) {
                /* In the middle of shuting down */
-               rc = BLK_EH_RESET_TIMER;
+               rc = SCSI_EH_RESET_TIMER;
                goto done;
        }
 
@@ -2151,7 +2151,7 @@ enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc)
                             "Last data xfer at %lu. Last timeout was at "
                             "%lu\n.", task->last_xfer, task->last_timeout);
                task->have_checked_conn = false;
-               rc = BLK_EH_RESET_TIMER;
+               rc = SCSI_EH_RESET_TIMER;
                goto done;
        }
 
@@ -2162,7 +2162,7 @@ enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc)
         * and can let the iscsi eh handle it
         */
        if (iscsi_has_ping_timed_out(conn)) {
-               rc = BLK_EH_RESET_TIMER;
+               rc = SCSI_EH_RESET_TIMER;
                goto done;
        }
 
@@ -2200,7 +2200,7 @@ enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc)
                                     task->last_xfer, running_task->last_xfer,
                                     task->last_timeout);
                        spin_unlock(&session->back_lock);
-                       rc = BLK_EH_RESET_TIMER;
+                       rc = SCSI_EH_RESET_TIMER;
                        goto done;
                }
        }
@@ -2216,14 +2216,14 @@ enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc)
         */
        if (READ_ONCE(conn->ping_task)) {
                task->have_checked_conn = true;
-               rc = BLK_EH_RESET_TIMER;
+               rc = SCSI_EH_RESET_TIMER;
                goto done;
        }
 
        /* Make sure there is a transport check done */
        iscsi_send_nopout(conn, NULL);
        task->have_checked_conn = true;
-       rc = BLK_EH_RESET_TIMER;
+       rc = SCSI_EH_RESET_TIMER;
 
 done:
        spin_unlock_bh(&session->frwd_lock);
@@ -2232,7 +2232,7 @@ done:
                task->last_timeout = jiffies;
                iscsi_put_task(task);
        }
-       ISCSI_DBG_EH(session, "return %s\n", rc == BLK_EH_RESET_TIMER ?
+       ISCSI_DBG_EH(session, "return %s\n", rc == SCSI_EH_RESET_TIMER ?
                     "timer reset" : "shutdown or nh");
        return rc;
 }
index 9be4ba6..6940043 100644 (file)
@@ -2927,15 +2927,14 @@ static int megasas_generic_reset(struct scsi_cmnd *scmd)
  * Sets the FW busy flag and reduces the host->can_queue if the
  * cmd has not been completed within the timeout period.
  */
-static enum
-blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
+static enum scsi_timeout_action megasas_reset_timer(struct scsi_cmnd *scmd)
 {
        struct megasas_instance *instance;
        unsigned long flags;
 
        if (time_after(jiffies, scmd->jiffies_at_alloc +
                                (scmd_timeout * 2) * HZ)) {
-               return BLK_EH_DONE;
+               return SCSI_EH_NOT_HANDLED;
        }
 
        instance = (struct megasas_instance *)scmd->device->host->hostdata;
@@ -2949,7 +2948,7 @@ blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
 
                spin_unlock_irqrestore(instance->host->host_lock, flags);
        }
-       return BLK_EH_RESET_TIMER;
+       return SCSI_EH_RESET_TIMER;
 }
 
 /**
index 05d3ce9..b3dcb89 100644 (file)
@@ -2109,7 +2109,7 @@ out_return_cmd:
        return 0;
 }
 
-static enum blk_eh_timer_return mvumi_timed_out(struct scsi_cmnd *scmd)
+static enum scsi_timeout_action mvumi_timed_out(struct scsi_cmnd *scmd)
 {
        struct mvumi_cmd *cmd = mvumi_priv(scmd)->cmd_priv;
        struct Scsi_Host *host = scmd->device->host;
@@ -2137,7 +2137,7 @@ static enum blk_eh_timer_return mvumi_timed_out(struct scsi_cmnd *scmd)
        mvumi_return_cmd(mhba, cmd);
        spin_unlock_irqrestore(mhba->shost->host_lock, flags);
 
-       return BLK_EH_DONE;
+       return SCSI_EH_NOT_HANDLED;
 }
 
 static int
index 9e849f6..0055021 100644 (file)
@@ -116,7 +116,7 @@ static int qla4xxx_iface_set_param(struct Scsi_Host *shost, void *data,
 static int qla4xxx_get_iface_param(struct iscsi_iface *iface,
                                   enum iscsi_param_type param_type,
                                   int param, char *buf);
-static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc);
+static enum scsi_timeout_action qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc);
 static struct iscsi_endpoint *qla4xxx_ep_connect(struct Scsi_Host *shost,
                                                 struct sockaddr *dst_addr,
                                                 int non_blocking);
@@ -1871,17 +1871,17 @@ exit_get_stats:
        return;
 }
 
-static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc)
+static enum scsi_timeout_action qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc)
 {
        struct iscsi_cls_session *session;
        unsigned long flags;
-       enum blk_eh_timer_return ret = BLK_EH_DONE;
+       enum scsi_timeout_action ret = SCSI_EH_NOT_HANDLED;
 
        session = starget_to_session(scsi_target(sc->device));
 
        spin_lock_irqsave(&session->lock, flags);
        if (session->state == ISCSI_SESSION_FAILED)
-               ret = BLK_EH_RESET_TIMER;
+               ret = SCSI_EH_RESET_TIMER;
        spin_unlock_irqrestore(&session->lock, flags);
 
        return ret;
index 02520f9..be2a70c 100644 (file)
@@ -328,7 +328,6 @@ void scsi_eh_scmd_add(struct scsi_cmnd *scmd)
 enum blk_eh_timer_return scsi_timeout(struct request *req)
 {
        struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(req);
-       enum blk_eh_timer_return rtn = BLK_EH_DONE;
        struct Scsi_Host *host = scmd->device->host;
 
        trace_scsi_dispatch_cmd_timeout(scmd);
@@ -338,23 +337,29 @@ enum blk_eh_timer_return scsi_timeout(struct request *req)
        if (host->eh_deadline != -1 && !host->last_reset)
                host->last_reset = jiffies;
 
-       if (host->hostt->eh_timed_out)
-               rtn = host->hostt->eh_timed_out(scmd);
-
-       if (rtn == BLK_EH_DONE) {
-               /*
-                * If scsi_done() has already set SCMD_STATE_COMPLETE, do not
-                * modify *scmd.
-                */
-               if (test_and_set_bit(SCMD_STATE_COMPLETE, &scmd->state))
+       if (host->hostt->eh_timed_out) {
+               switch (host->hostt->eh_timed_out(scmd)) {
+               case SCSI_EH_DONE:
                        return BLK_EH_DONE;
-               if (scsi_abort_command(scmd) != SUCCESS) {
-                       set_host_byte(scmd, DID_TIME_OUT);
-                       scsi_eh_scmd_add(scmd);
+               case SCSI_EH_RESET_TIMER:
+                       return BLK_EH_RESET_TIMER;
+               case SCSI_EH_NOT_HANDLED:
+                       break;
                }
        }
 
-       return rtn;
+       /*
+        * If scsi_done() has already set SCMD_STATE_COMPLETE, do not modify
+        * *scmd.
+        */
+       if (test_and_set_bit(SCMD_STATE_COMPLETE, &scmd->state))
+               return BLK_EH_DONE;
+       if (scsi_abort_command(scmd) != SUCCESS) {
+               set_host_byte(scmd, DID_TIME_OUT);
+               scsi_eh_scmd_add(scmd);
+       }
+
+       return BLK_EH_DONE;
 }
 
 /**
index 8934160..0965f8a 100644 (file)
@@ -2530,15 +2530,14 @@ static int fc_vport_match(struct attribute_container *cont,
  * Notes:
  *     This routine assumes no locks are held on entry.
  */
-enum blk_eh_timer_return
-fc_eh_timed_out(struct scsi_cmnd *scmd)
+enum scsi_timeout_action fc_eh_timed_out(struct scsi_cmnd *scmd)
 {
        struct fc_rport *rport = starget_to_rport(scsi_target(scmd->device));
 
        if (rport->port_state == FC_PORTSTATE_BLOCKED)
-               return BLK_EH_RESET_TIMER;
+               return SCSI_EH_RESET_TIMER;
 
-       return BLK_EH_DONE;
+       return SCSI_EH_NOT_HANDLED;
 }
 EXPORT_SYMBOL(fc_eh_timed_out);
 
index 98a34ed..87d0fb8 100644 (file)
@@ -594,13 +594,13 @@ EXPORT_SYMBOL(srp_reconnect_rport);
  * @scmd: SCSI command.
  *
  * If a timeout occurs while an rport is in the blocked state, ask the SCSI
- * EH to continue waiting (BLK_EH_RESET_TIMER). Otherwise let the SCSI core
- * handle the timeout (BLK_EH_DONE).
+ * EH to continue waiting (SCSI_EH_RESET_TIMER). Otherwise let the SCSI core
+ * handle the timeout (SCSI_EH_NOT_HANDLED).
  *
  * Note: This function is called from soft-IRQ context and with the request
  * queue lock held.
  */
-enum blk_eh_timer_return srp_timed_out(struct scsi_cmnd *scmd)
+enum scsi_timeout_action srp_timed_out(struct scsi_cmnd *scmd)
 {
        struct scsi_device *sdev = scmd->device;
        struct Scsi_Host *shost = sdev->host;
@@ -611,7 +611,7 @@ enum blk_eh_timer_return srp_timed_out(struct scsi_cmnd *scmd)
        return rport && rport->fast_io_fail_tmo < 0 &&
                rport->dev_loss_tmo < 0 &&
                i->f->reset_timer_if_blocked && scsi_device_blocked(sdev) ?
-               BLK_EH_RESET_TIMER : BLK_EH_DONE;
+               SCSI_EH_RESET_TIMER : SCSI_EH_NOT_HANDLED;
 }
 EXPORT_SYMBOL(srp_timed_out);
 
index bc46721..a84194d 100644 (file)
@@ -1652,13 +1652,13 @@ static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd)
  * be unbounded on Azure.  Reset the timer unconditionally to give the host a
  * chance to perform EH.
  */
-static enum blk_eh_timer_return storvsc_eh_timed_out(struct scsi_cmnd *scmnd)
+static enum scsi_timeout_action storvsc_eh_timed_out(struct scsi_cmnd *scmnd)
 {
 #if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
        if (scmnd->device->host->transportt == fc_transport_template)
                return fc_eh_timed_out(scmnd);
 #endif
-       return BLK_EH_RESET_TIMER;
+       return SCSI_EH_RESET_TIMER;
 }
 
 static bool storvsc_scsi_cmd_ok(struct scsi_cmnd *scmnd)
index 2a79ab1..d07d24c 100644 (file)
@@ -731,9 +731,9 @@ static void virtscsi_commit_rqs(struct Scsi_Host *shost, u16 hwq)
  * latencies might be higher than on bare metal.  Reset the timer
  * unconditionally to give the host a chance to perform EH.
  */
-static enum blk_eh_timer_return virtscsi_eh_timed_out(struct scsi_cmnd *scmnd)
+static enum scsi_timeout_action virtscsi_eh_timed_out(struct scsi_cmnd *scmnd)
 {
-       return BLK_EH_RESET_TIMER;
+       return SCSI_EH_RESET_TIMER;
 }
 
 static struct scsi_host_template virtscsi_host_template = {
index 654cc39..695eebc 100644 (file)
@@ -393,7 +393,7 @@ extern int iscsi_eh_recover_target(struct scsi_cmnd *sc);
 extern int iscsi_eh_session_reset(struct scsi_cmnd *sc);
 extern int iscsi_eh_device_reset(struct scsi_cmnd *sc);
 extern int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc);
-extern enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc);
+extern enum scsi_timeout_action iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc);
 
 /*
  * iSCSI host helpers.
index e714361..587cc76 100644 (file)
@@ -27,6 +27,18 @@ struct scsi_transport_template;
 #define MODE_INITIATOR 0x01
 #define MODE_TARGET 0x02
 
+/**
+ * enum scsi_timeout_action - How to handle a command that timed out.
+ * @SCSI_EH_DONE: The command has already been completed.
+ * @SCSI_EH_RESET_TIMER: Reset the timer and continue waiting for completion.
+ * @SCSI_EH_NOT_HANDLED: The command has not yet finished. Abort the command.
+ */
+enum scsi_timeout_action {
+       SCSI_EH_DONE,
+       SCSI_EH_RESET_TIMER,
+       SCSI_EH_NOT_HANDLED,
+};
+
 struct scsi_host_template {
        /*
         * Put fields referenced in IO submission path together in
@@ -331,7 +343,7 @@ struct scsi_host_template {
         *
         * Status: OPTIONAL
         */
-       enum blk_eh_timer_return (*eh_timed_out)(struct scsi_cmnd *);
+       enum scsi_timeout_action (*eh_timed_out)(struct scsi_cmnd *);
        /*
         * Optional routine that allows the transport to decide if a cmd
         * is retryable. Return true if the transport is in a state the
index e80a7c5..3dcda19 100644 (file)
@@ -862,7 +862,7 @@ struct fc_vport *fc_vport_create(struct Scsi_Host *shost, int channel,
 int fc_vport_terminate(struct fc_vport *vport);
 int fc_block_rport(struct fc_rport *rport);
 int fc_block_scsi_eh(struct scsi_cmnd *cmnd);
-enum blk_eh_timer_return fc_eh_timed_out(struct scsi_cmnd *scmd);
+enum scsi_timeout_action fc_eh_timed_out(struct scsi_cmnd *scmd);
 bool fc_eh_should_retry_cmd(struct scsi_cmnd *scmd);
 
 static inline struct Scsi_Host *fc_bsg_to_shost(struct bsg_job *job)
index d22df12..dfc78aa 100644 (file)
@@ -118,7 +118,7 @@ extern int srp_reconnect_rport(struct srp_rport *rport);
 extern void srp_start_tl_fail_timers(struct srp_rport *rport);
 extern void srp_remove_host(struct Scsi_Host *);
 extern void srp_stop_rport_timers(struct srp_rport *rport);
-enum blk_eh_timer_return srp_timed_out(struct scsi_cmnd *scmd);
+enum scsi_timeout_action srp_timed_out(struct scsi_cmnd *scmd);
 
 /**
  * srp_chkready() - evaluate the transport layer state before I/O