Skip to contentSkip to conversation

New SCSI command timeout handler

PATCH Superseded Hannes Reinecke 8 participants 30 messages Jun 10, 2013 – Jun 13, 2013

Subsystems (5)

v2 of 11 Superseded Latest is v11 →

lore
Share & tools
lore
#0 lore raw

v2 cover New SCSI command timeout handler

this is the first step towards a new non-blocking error handler. This patch implements a new command timeout handler which will be sending command aborts inline without engaging SCSI EH.

In addition the commands will be returned directly if the command abort succeeded, cutting down recovery times dramatically.

With the original scsi error recovery I got:

# time dd if=/dev/zero of=/mnt/test.blk bs=512 count=2048 oflag=sync
2048+0 records in
2048+0 records out
1048576 bytes (1.0 MB) copied, 3.72732 s, 281 kB/s

real 2m14.475s
user 0m0.000s
sys 0m0.104s

with this patchset I got:

# time dd if=/dev/zero of=/mnt/test.blk bs=512 count=2048 oflag=sync
2048+0 records in
2048+0 records out
1048576 bytes (1.0 MB) copied, 31.5151 s, 33.3 kB/s

real 0m31.519s
user 0m0.000s
sys 0m0.088s

Test was to disable RSCN on the target port, disable the target port, and then start the 'dd' command as indicated.

As a proof-of-concept I've also enabled the new timeout handler for virtio, so that things can be tested out more easily.
As requested I've also hooked in the new SCSI timeout handler to SAS.

Changes to the original version:
- Use a private list in scsi_eh_abort_handler to avoid list starvation (pointed out by Joern Engel)
- Terminate command aborts when the first abort fails
- Do not attempt command aborts if the host is already in recovery or if the device is removed.
- Flush abort workqueue if the device is removed.

Comments etc are welcome.

Hannes Reinecke (9):
scsi: move initialization of scmd->eh_entry
blk-timeout: add BLK_EH_SCHEDULED return code
scsi: improved eh timeout handler
virtio_scsi: Enable new EH timeout handler
virtio-scsi: Implement TMF timeout
libsas: Enable new EH timeout handler
mptsas: Enable new EH timeout handler
mpt2sas: Enable new EH timeout handler
mpt3sas: Enable new EH timeout handler

 drivers/message/fusion/mptsas.c      |   1 +
 drivers/message/fusion/mptscsih.c    |   7 ++
 drivers/message/fusion/mptscsih.h    |   1 +
 drivers/scsi/libsas/sas_scsi_host.c  |   2 +-
 drivers/scsi/mpt2sas/mpt2sas_scsih.c |  11 +++
 drivers/scsi/mpt3sas/mpt3sas_scsih.c |  11 +++
 drivers/scsi/scsi_error.c            | 126 ++++++++++++++++++++++++++++++++++-
 drivers/scsi/scsi_lib.c              |   4 +-
 drivers/scsi/scsi_scan.c             |   3 +
 drivers/scsi/scsi_sysfs.c            |   5 ++
 drivers/scsi/scsi_transport_fc.c     |   2 +-
 drivers/scsi/virtio_scsi.c           |  14 +++-
 include/linux/blkdev.h               |   1 +
 include/scsi/scsi_cmnd.h             |   1 +
 include/scsi/scsi_device.h           |   2 +
 15 files changed, 184 insertions(+), 7 deletions(-)
Signature · 1 line
1.7.12.4
#1 lore raw

PATCH v2 1/9 scsi: move initialization of scmd->eh_entry

The 'eh_entry' list might be used even before scsi_softirq_done() is called. Hence we should rather initialize it together with the other eh-related variables.

---
 drivers/scsi/scsi_lib.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/scsi/scsi_lib.c +2 -2
index 86d5220..c1774de 100644
@@ -317,6 +317,8 @@ static void scsi_init_cmd_errh(struct scsi_cmnd *cmd)
 	memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
 	if (cmd->cmd_len == 0)
 		cmd->cmd_len = scsi_command_size(cmd->cmnd);
+	INIT_LIST_HEAD(&cmd->eh_entry);
+	cmd->eh_eflags = 0;
 }
 
 void scsi_device_unbusy(struct scsi_device *sdev)
@@ -1482,8 +1484,6 @@ static void scsi_softirq_done(struct request *rq)
 	unsigned long wait_for = (cmd->allowed + 1) * rq->timeout;
 	int disposition;
 
-	INIT_LIST_HEAD(&cmd->eh_entry);
-
 	atomic_inc(&cmd->device->iodone_cnt);
 	if (cmd->result)
 		atomic_inc(&cmd->device->ioerr_cnt);
Signature · 1 line
1.7.12.4
#2 lore raw

Re: [PATCH 1/9] scsi: move initialization of scmd->eh_entry

Quoted 3 lines · Hannes Reinecke

The 'eh_entry' list might be used even before scsi_softirq_done() is called. Hence we should rather initialize it together with the other eh-related variables.

As mentioned earlier I don't think moving the initialization from one random point in the middle of the lifetime of the command to another is a good idea. If we initialize it it should be when it is allocated.

But looking at the code I can't see why it needs to be initialized at all. eh_entry is not used as the head of a list but just as the list link, and it's never tested for emptyness either, which shouldn't require it to be initialized at all.

#3 lore raw

PATCH v2 2/9 blk-timeout: add BLK_EH_SCHEDULED return code

In reply to Hannes Reinecke

Add a 'BLK_EH_SCHEDULED' return code for blk-timeout to indicate that a delayed error recovery has been initiated.

---
 drivers/scsi/scsi_error.c | 3 +++
 include/linux/blkdev.h    | 1 +
 2 files changed, 4 insertions(+)
drivers/scsi/scsi_error.c +3 -0
index f43de1e..96b4bb6 100644
@@ -146,6 +146,9 @@ enum blk_eh_timer_return scsi_times_out(struct request *req)
 		rtn = host->hostt->eh_timed_out(scmd);
 
 	scmd->result |= DID_TIME_OUT << 16;
+	/* Check for delayed EH scheduling */
+	if (rtn == BLK_EH_SCHEDULED)
+		return BLK_EH_NOT_HANDLED;
 
 	if (unlikely(rtn == BLK_EH_NOT_HANDLED &&
 		     !scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD)))
include/linux/blkdev.h +1 -0
index 2fdb4a4..d846e2b 100644
@@ -238,6 +238,7 @@ enum blk_eh_timer_return {
 	BLK_EH_NOT_HANDLED,
 	BLK_EH_HANDLED,
 	BLK_EH_RESET_TIMER,
+	BLK_EH_SCHEDULED,
 };
 
 typedef enum blk_eh_timer_return (rq_timed_out_fn)(struct request *);
Signature · 1 line
1.7.12.4
#4 lore raw

PATCH v2 3/9 scsi: improved eh timeout handler

In reply to Hannes Reinecke

When a command runs into a timeout we need to send an 'ABORT TASK' TMF. This is typically done by the 'eh_abort_handler' LLDD callback.

Conceptually, however, this function is a normal SCSI command, so there is no need to enter the error handler.

This patch implements a new scsi_abort_command() function which invokes an asynchronous function scsi_eh_abort_handler() to abort the commands via 'eh_abort_handler'.

If the 'eh_abort_handler' returns SUCCESS or FAST_IO_FAIL the command will be retried if possible. If no retries are allowed the command will be returned immediately, as we have to assume the TMF succeeded and the command is completed with the LLDD. If the TMF fails the command will be pushed back onto the list of failed commands and the SCSI EH handler will be called immediately for all timed-out commands.

---
 drivers/scsi/scsi_error.c        | 123 ++++++++++++++++++++++++++++++++++++++-
 drivers/scsi/scsi_scan.c         |   3 +
 drivers/scsi/scsi_sysfs.c        |   5 ++
 drivers/scsi/scsi_transport_fc.c |   2 +-
 include/scsi/scsi_cmnd.h         |   1 +
 include/scsi/scsi_device.h       |   2 +
 6 files changed, 134 insertions(+), 2 deletions(-)
drivers/scsi/scsi_error.c +122 -1
index 96b4bb6..467cb3c 100644
@@ -55,6 +55,8 @@ static void scsi_eh_done(struct scsi_cmnd *scmd);
 #define HOST_RESET_SETTLE_TIME  (10)
 
 static int scsi_eh_try_stu(struct scsi_cmnd *scmd);
+static int scsi_try_to_abort_cmd(struct scsi_host_template *hostt,
+				 struct scsi_cmnd *scmd);
 
 /* called with shost->host_lock held */
 void scsi_eh_wakeup(struct Scsi_Host *shost)
@@ -90,6 +92,125 @@ void scsi_schedule_eh(struct Scsi_Host *shost)
 EXPORT_SYMBOL_GPL(scsi_schedule_eh);
 
 /**
+ * scsi_eh_abort_handler - Handle command aborts
+ * @work:	sdev on which commands should be aborted.
+ */
+void
+scsi_eh_abort_handler(struct work_struct *work)
+{
+	struct scsi_device *sdev =
+		container_of(work, struct scsi_device, abort_work);
+	struct scsi_cmnd *scmd, *tmp;
+	LIST_HEAD(abort_list);
+	unsigned long flags;
+	int rtn;
+
+	spin_lock_irqsave(&sdev->list_lock, flags);
+	list_splice_init(&sdev->eh_abort_list, &abort_list);
+	spin_unlock_irqrestore(&sdev->list_lock, flags);
+
+	list_for_each_entry_safe(scmd, tmp, &abort_list, eh_entry) {
+		list_del_init(&scmd->eh_entry);
+		if (sdev->sdev_state == SDEV_CANCEL) {
+			SCSI_LOG_ERROR_RECOVERY(3,
+				scmd_printk(KERN_INFO, scmd,
+				    "terminate, device removed\n"));
+			scmd->result |= DID_NO_CONNECT << 16;
+			scsi_finish_command(scmd);
+			continue;
+		}
+		SCSI_LOG_ERROR_RECOVERY(3,
+			scmd_printk(KERN_INFO, scmd,
+				    "aborting command %p\n", scmd));
+		rtn = scsi_try_to_abort_cmd(sdev->host->hostt, scmd);
+		if (rtn == FAILED) {
+			SCSI_LOG_ERROR_RECOVERY(3,
+				scmd_printk(KERN_INFO, scmd,
+					     "abort command failed\n"));
+			list_move_tail(&scmd->eh_entry, &abort_list);
+			goto start_eh;
+		}
+		if (!(scmd->request->cmd_flags & REQ_FAILFAST_DEV) &&
+		    (scmd->request->cmd_type != REQ_TYPE_BLOCK_PC) &&
+		    (++scmd->retries <= scmd->allowed)) {
+			SCSI_LOG_ERROR_RECOVERY(3,
+				scmd_printk(KERN_WARNING, scmd,
+					    "retry aborted command\n"));
+
+			scsi_queue_insert(scmd, SCSI_MLQUEUE_EH_RETRY);
+		} else {
+			SCSI_LOG_ERROR_RECOVERY(3,
+				scmd_printk(KERN_WARNING, scmd,
+					    "fast fail aborted command\n"));
+			scmd->result |= DID_TRANSPORT_FAILFAST << 16;
+			scsi_finish_command(scmd);
+		}
+	}
+
+	if (list_empty(&abort_list))
+		return;
+
+start_eh:
+	list_for_each_entry_safe(scmd, tmp, &abort_list, eh_entry) {
+		scmd->result |= DID_TIME_OUT << 16;
+		if (!scsi_eh_scmd_add(scmd, 0)) {
+			SCSI_LOG_ERROR_RECOVERY(3,
+				scmd_printk(KERN_WARNING, scmd,
+					    "terminate aborted command\n"));
+			scsi_finish_command(scmd);
+		}
+	}
+}
+
+/**
+ * scsi_abort_command - schedule a command abort
+ * @scmd:	scmd to abort.
+ *
+ * We only need to abort commands after a command timeout
+ */
+enum blk_eh_timer_return
+scsi_abort_command(struct scsi_cmnd *scmd)
+{
+	unsigned long flags;
+	int kick_worker = 0;
+	struct scsi_device *sdev = scmd->device;
+
+	/*
+	 * Do not try a command abort if
+	 * SCSI EH has already started.
+	 */
+	if (scsi_host_in_recovery(sdev->host)) {
+		SCSI_LOG_ERROR_RECOVERY(3,
+			scmd_printk(KERN_INFO, scmd,
+				    "host in recovery, not aborting\n"));
+		scmd->result |= DID_TIME_OUT << 16;
+		scsi_eh_scmd_add(scmd, 0);
+		return BLK_EH_SCHEDULED;
+	}
+	if (sdev->sdev_state == SDEV_CANCEL ||
+	    sdev->sdev_state == SDEV_OFFLINE) {
+		SCSI_LOG_ERROR_RECOVERY(3,
+			scmd_printk(KERN_INFO, scmd,
+				    "device removed, terminating command\n"));
+		scmd->result |= DID_NO_CONNECT << 16;
+		scsi_finish_command(scmd);
+		return BLK_EH_SCHEDULED;
+	}
+
+	spin_lock_irqsave(&sdev->list_lock, flags);
+	if (list_empty(&sdev->eh_abort_list))
+		kick_worker = 1;
+	list_add(&scmd->eh_entry, &sdev->eh_abort_list);
+	spin_unlock_irqrestore(&sdev->list_lock, flags);
+	SCSI_LOG_ERROR_RECOVERY(3,
+		scmd_printk(KERN_INFO, scmd, "adding to eh_abort_list\n"));
+	if (kick_worker)
+		schedule_work(&sdev->abort_work);
+	return BLK_EH_SCHEDULED;
+}
+EXPORT_SYMBOL_GPL(scsi_abort_command);
+
+/**
  * scsi_eh_scmd_add - add scsi cmd to error handling.
  * @scmd:	scmd to run eh on.
  * @eh_flag:	optional SCSI_EH flag.
@@ -145,11 +266,11 @@ enum blk_eh_timer_return scsi_times_out(struct request *req)
 	else if (host->hostt->eh_timed_out)
 		rtn = host->hostt->eh_timed_out(scmd);
 
-	scmd->result |= DID_TIME_OUT << 16;
 	/* Check for delayed EH scheduling */
 	if (rtn == BLK_EH_SCHEDULED)
 		return BLK_EH_NOT_HANDLED;
 
+	scmd->result |= DID_TIME_OUT << 16;
 	if (unlikely(rtn == BLK_EH_NOT_HANDLED &&
 		     !scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD)))
 		rtn = BLK_EH_HANDLED;
drivers/scsi/scsi_scan.c +3 -0
index 3e58b22..f9cc6fc 100644
@@ -231,6 +231,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
 	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
 	extern void scsi_evt_thread(struct work_struct *work);
 	extern void scsi_requeue_run_queue(struct work_struct *work);
+	extern void scsi_eh_abort_handler(struct work_struct *work);
 
 	sdev = kzalloc(sizeof(*sdev) + shost->transportt->device_size,
 		       GFP_ATOMIC);
@@ -251,9 +252,11 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
 	INIT_LIST_HEAD(&sdev->cmd_list);
 	INIT_LIST_HEAD(&sdev->starved_entry);
 	INIT_LIST_HEAD(&sdev->event_list);
+	INIT_LIST_HEAD(&sdev->eh_abort_list);
 	spin_lock_init(&sdev->list_lock);
 	INIT_WORK(&sdev->event_work, scsi_evt_thread);
 	INIT_WORK(&sdev->requeue_work, scsi_requeue_run_queue);
+	INIT_WORK(&sdev->abort_work, scsi_eh_abort_handler);
 
 	sdev->sdev_gendev.parent = get_device(&starget->dev);
 	sdev->sdev_target = starget;
drivers/scsi/scsi_sysfs.c +5 -0
index 931a7d9..af64c1c 100644
@@ -966,6 +966,11 @@ void __scsi_remove_device(struct scsi_device *sdev)
 		put_device(&sdev->sdev_dev);
 
 	/*
+	 * Terminate timed-out commands
+	 */
+	flush_work(&sdev->abort_work);
+
+	/*
 	 * Stop accepting new requests and wait until all queuecommand() and
 	 * scsi_run_queue() invocations have finished before tearing down the
 	 * device.
drivers/scsi/scsi_transport_fc.c +1 -1
index e106c27..1e1de9f 100644
@@ -2079,7 +2079,7 @@ fc_timed_out(struct scsi_cmnd *scmd)
 	if (rport->port_state == FC_PORTSTATE_BLOCKED)
 		return BLK_EH_RESET_TIMER;
 
-	return BLK_EH_NOT_HANDLED;
+	return scsi_abort_command(scmd);
 }
 
 /*
include/scsi/scsi_cmnd.h +1 -0
index de5f5d8..d521694 100644
@@ -144,6 +144,7 @@ extern void scsi_put_command(struct scsi_cmnd *);
 extern void __scsi_put_command(struct Scsi_Host *, struct scsi_cmnd *,
 			       struct device *);
 extern void scsi_finish_command(struct scsi_cmnd *cmd);
+extern enum blk_eh_timer_return scsi_abort_command(struct scsi_cmnd *cmd);
 
 extern void *scsi_kmap_atomic_sg(struct scatterlist *sg, int sg_count,
 				 size_t *offset, size_t *len);
include/scsi/scsi_device.h +2 -0
index cc64587..e03d379 100644
@@ -80,6 +80,7 @@ struct scsi_device {
 	spinlock_t list_lock;
 	struct list_head cmd_list;	/* queue of in use SCSI Command structures */
 	struct list_head starved_entry;
+	struct list_head eh_abort_list;
 	struct scsi_cmnd *current_cmnd;	/* currently active command */
 	unsigned short queue_depth;	/* How deep of a queue we want */
 	unsigned short max_queue_depth;	/* max queue depth */
@@ -180,6 +181,7 @@ struct scsi_device {
 
 	struct execute_work	ew; /* used to get process context on put */
 	struct work_struct	requeue_work;
+	struct work_struct	abort_work;
 
 	struct scsi_dh_data	*scsi_dh_data;
 	enum scsi_device_state sdev_state;
Signature · 1 line
1.7.12.4
#5 lore raw

Re: [PATCH 3/9] scsi: improved eh timeout handler

Quoted 10 lines · Hannes Reinecke

When a command runs into a timeout we need to send an 'ABORT TASK' TMF. This is typically done by the 'eh_abort_handler' LLDD callback.

Conceptually, however, this function is a normal SCSI command, so there is no need to enter the error handler.

This patch implements a new scsi_abort_command() function which invokes an asynchronous function scsi_eh_abort_handler() to abort the commands via 'eh_abort_handler'.

Quoted 7 lines

If the 'eh_abort_handler' returns SUCCESS or FAST_IO_FAIL the command will be retried if possible. If no retries are allowed the command will be returned immediately, as we have to assume the TMF succeeded and the command is completed with the LLDD. If the TMF fails the command will be pushed back onto the list of failed commands and the SCSI EH handler will be called immediately for all timed-out commands.

Why can't we use a work item per command? Linking things into a list just to queue it up to workqueues missed half of the point of the workqueue infrastructure.

#6 lore raw

Re: [PATCH 3/9] scsi: improved eh timeout handler

Quoted 19 lines · Christoph Hellwig
Quoted 10 lines · Hannes Reinecke

When a command runs into a timeout we need to send an 'ABORT TASK' TMF. This is typically done by the 'eh_abort_handler' LLDD callback.

Conceptually, however, this function is a normal SCSI command, so there is no need to enter the error handler.

This patch implements a new scsi_abort_command() function which invokes an asynchronous function scsi_eh_abort_handler() to abort the commands via 'eh_abort_handler'.

Quoted 7 lines

If the 'eh_abort_handler' returns SUCCESS or FAST_IO_FAIL the command will be retried if possible. If no retries are allowed the command will be returned immediately, as we have to assume the TMF succeeded and the command is completed with the LLDD. If the TMF fails the command will be pushed back onto the list of failed commands and the SCSI EH handler will be called immediately for all timed-out commands.

Quoted 4 lines

Why can't we use a work item per command? Linking things into a list just to queue it up to workqueues missed half of the point of the workqueue infrastructure.

Hmm. I felt that using a per command workqueue might be a bit excessive. Also the current semantics call for a synchronous command abort. So even using a per command workqueue won't buy us anything as the workqueue item would have to wait for the command abort to complete, which again is quite a waste.
And concurrency would be hell; you'd have to flush the workqueue items for all outstanding if a device reset should attempted. And hope that no completion arrives at the time you're attempting to flush them. etc.

I've been planning for asynchronous command aborts eventually, where using a per-command workqueue item comes in useful. Gut for now using existing callbacks makes life so much easier. And per-command workqueues will just complicate matters.

Cheers,

Hannes

Signature · 8 lines
Dr. Hannes Reinecke		      zSeries & Storage
[email protected]			      +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#7 lore raw

Re: [PATCH 3/9] scsi: improved eh timeout handler

Quoted 11 lines · Hannes Reinecke
Quoted 5 lines · Christoph Hellwig

Why can't we use a work item per command? Linking things into a list just to queue it up to workqueues missed half of the point of the workqueue infrastructure.

Hmm. I felt that using a per command workqueue might be a bit excessive. Also the current semantics call for a synchronous command abort. So even using a per command workqueue won't buy us anything as the workqueue item would have to wait for the command abort to complete, which again is quite a waste.

Not sure if you confuse workqueue with workitem. Either way, using a single work item to handle a queue of commands does not fly and we either have to use per-command work items or abandon work queues and use a kernel thread. The middle ground is either racy or useless.

I don't care too much whether we use per-command work items or a single system-global thread. This shouldn't ever become a hot path or the system is screwed anyway. The only problem with our current error handling is that even rare errors can effectively break the system.

Jörn

--
Victory in war is not repetitious.
-- Sun Tzu
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#8 lore raw

Re: [PATCH 3/9] scsi: improved eh timeout handler

Quoted 3 lines · Jörn Engel

I don't care too much whether we use per-command work items or a single system-global thread.

Actually, I do care. We have to abort the commands in parallel, as a fairly large number of abort can queue up and individual aborts can take 20s on hardware I care about.

20s for an abort is pretty bad, but given today's reality there is no need to make things worse by serializing.

Jörn

--
A defeated army first battles and then seeks victory.
-- Sun Tzu
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#9 lore raw

Re: [PATCH 3/9] scsi: improved eh timeout handler

Quoted 5 lines · Jörn Engel
Quoted 3 lines · Jörn Engel

I don't care too much whether we use per-command work items or a single system-global thread.

Quoted 7 lines

Actually, I do care. We have to abort the commands in parallel, as a fairly large number of abort can queue up and individual aborts can take 20s on hardware I care about.

20s for an abort is pretty bad, but given today's reality there is no need to make things worse by serializing.

We're only serializing aborts per LUN, so this is a _big_ improvement as the original, where we would be serializing per _host_.
Also, upon the first abort failure EH will be escalating to LUN reset, so we won't have to wait for all aborts to time out.

More importantly, the current synchronous implementation of command aborts does not allow for complete de-serialisation:
- There is no way to abort a running command abort, so we have to wait for it to complete, with the chance of running into a timeout.
- We will have to sent command aborts in parallel, and can only stop sending aborts once the first returns an error.
- After we've received an error we have to wait for the outstanding aborts to complete.
-> So the max wait-time will be 2 times the abort timeout.
Not much of a gain here :-)

The _correct_ way of handling asynchronous aborts would be to mandate that the LLDD has to send a command completion on the original command once an abort has been issued. Then we could just kick off the TMF and rearm the request timer. Everything else would then be handled via normal I/O paths.

However, this would mean to implement new callouts into each and every driver. And the actual gain would be dubious, as the several IHVs indicated that a command abort might be handled lazily, ie the target will return a good status, but abort the command only at a later time. Other vendors treat a command abort as a best bet, and rely on the LUN reset to clear up things.

So overall I doubt we'd be gaining much from a fully asynchronous command abort. I'd rather concentrate on getting the remaining bits like LUN reset working correctly.

Cheers,

Hannes

Signature · 8 lines
Dr. Hannes Reinecke		      zSeries & Storage
[email protected]			      +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#10 lore raw

Re: [PATCH 3/9] scsi: improved eh timeout handler

Quoted 10 lines · Hannes Reinecke
Quoted 9 lines · Jörn Engel
Quoted 3 lines · Jörn Engel

I don't care too much whether we use per-command work items or a single system-global thread.

Actually, I do care. We have to abort the commands in parallel, as a fairly large number of abort can queue up and individual aborts can take 20s on hardware I care about.

Quoted 6 lines
Quoted 3 lines

20s for an abort is pretty bad, but given today's reality there is no need to make things worse by serializing.

We're only serializing aborts per LUN, so this is a _big_ improvement as the original, where we would be serializing per _host_.

I agree it is a big improvement. But I also have some evidence indicating it may not be enough. So let me change my private patch to do parallel aborts and see how it fares.

Quoted 2 lines

Also, upon the first abort failure EH will be escalating to LUN reset, so we won't have to wait for all aborts to time out.

The case I saw was a successful abort taking 20s.

Quoted 11 lines

More importantly, the current synchronous implementation of command aborts does not allow for complete de-serialisation:
- There is no way to abort a running command abort, so we have to wait for it to complete, with the chance of running into a timeout.
- We will have to sent command aborts in parallel, and can only stop sending aborts once the first returns an error.
- After we've received an error we have to wait for the outstanding aborts to complete.
-> So the max wait-time will be 2 times the abort timeout.
Not much of a gain here :-)

I have seen 10 commands get queued for aborts. Assuming the 20s above are the worst case, it will make the difference between 200s and 40s.

Granted, 40s is still horrible. The command in question has just timed out and the kernel should inform userspace about this asap. If a command with a 10s timeout takes 50s to complete, userspace will have to add another layer of timeouts. That should never be necessary.

Quoted 15 lines

The _correct_ way of handling asynchronous aborts would be to mandate that the LLDD has to send a command completion on the original command once an abort has been issued. Then we could just kick off the TMF and rearm the request timer. Everything else would then be handled via normal I/O paths.

However, this would mean to implement new callouts into each and every driver. And the actual gain would be dubious, as the several IHVs indicated that a command abort might be handled lazily, ie the target will return a good status, but abort the command only at a later time. Other vendors treat a command abort as a best bet, and rely on the LUN reset to clear up things.

Quoted 4 lines

So overall I doubt we'd be gaining much from a fully asynchronous command abort. I'd rather concentrate on getting the remaining bits like LUN reset working correctly.

Fair approach. Again, let me play with it and don't let this stop you from making other improvements.

Jörn

--
There's nothing that will change someone's moral outlook quicker than cash in large sums.
-- Larry Flynt
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#11 lore raw

Re: [PATCH 3/9] scsi: improved eh timeout handler

In reply to Christoph Hellwig
Quoted 19 lines · Christoph Hellwig
Quoted 10 lines · Hannes Reinecke

When a command runs into a timeout we need to send an 'ABORT TASK' TMF. This is typically done by the 'eh_abort_handler' LLDD callback.

Conceptually, however, this function is a normal SCSI command, so there is no need to enter the error handler.

This patch implements a new scsi_abort_command() function which invokes an asynchronous function scsi_eh_abort_handler() to abort the commands via 'eh_abort_handler'.

Quoted 7 lines

If the 'eh_abort_handler' returns SUCCESS or FAST_IO_FAIL the command will be retried if possible. If no retries are allowed the command will be returned immediately, as we have to assume the TMF succeeded and the command is completed with the LLDD. If the TMF fails the command will be pushed back onto the list of failed commands and the SCSI EH handler will be called immediately for all timed-out commands.

Quoted 3 lines

Why can't we use a work item per command? Linking things into a list just to queue it up to workqueues missed half of the point of the workqueue infrastructure.

Actually, I think we can dump the workqueue altogether. The only reason we need it is because the current abort handlers wait for the command and return the completion state. However, all LLDs are capable of emitting TMFs at interrupt level, so if we separated the emit from the wait, we could simply do this sequence:

on timeout, fire the abort from interrupt and mark the command as having an abort issued (possibly by adding a pointer to the abort task), return BLK_EH_RESET_TIMER.

Now if the timeout fires again, assume the abort was unsucessful and escalate to LUN reset.

This is fully asynchronous, fully tracked and doesn't rely on work queues.

The necessary additions for something like this are the from interrupt issue abort and LUN reset, which could just be additional callbacks in the host template.

James

#12 lore raw

Re: [PATCH 3/9] scsi: improved eh timeout handler

Quoted 30 lines · James Bottomley
Quoted 19 lines · Christoph Hellwig
Quoted 10 lines · Hannes Reinecke

When a command runs into a timeout we need to send an 'ABORT TASK' TMF. This is typically done by the 'eh_abort_handler' LLDD callback.

Conceptually, however, this function is a normal SCSI command, so there is no need to enter the error handler.

This patch implements a new scsi_abort_command() function which invokes an asynchronous function scsi_eh_abort_handler() to abort the commands via 'eh_abort_handler'.

Quoted 7 lines

If the 'eh_abort_handler' returns SUCCESS or FAST_IO_FAIL the command will be retried if possible. If no retries are allowed the command will be returned immediately, as we have to assume the TMF succeeded and the command is completed with the LLDD. If the TMF fails the command will be pushed back onto the list of failed commands and the SCSI EH handler will be called immediately for all timed-out commands.

Quoted 3 lines

Why can't we use a work item per command? Linking things into a list just to queue it up to workqueues missed half of the point of the workqueue infrastructure.

Actually, I think we can dump the workqueue altogether. The only reason we need it is because the current abort handlers wait for the command and return the completion state. However, all LLDs are capable of emitting TMFs at interrupt level, so if we separated the emit from the wait, we could simply do this sequence:

Quoted 3 lines

on timeout, fire the abort from interrupt and mark the command as having an abort issued (possibly by adding a pointer to the abort task), return BLK_EH_RESET_TIMER.

Doesn't this cause blk_rq_timed_out to reset the timer on the req to the original timeout value again? It seems like this would increase the time before any further attempted error handling. The default timeout is 30 seconds for sd, but it could be much longer (e.g. WRITE SAME, which was 120 seconds last I looked).

Quoted 12 lines

Now if the timeout fires again, assume the abort was unsucessful and escalate to LUN reset.

This is fully asynchronous, fully tracked and doesn't rely on work queues.

The necessary additions for something like this are the from interrupt issue abort and LUN reset, which could just be additional callbacks in the host template.

James

#13 lore raw

Re: [PATCH 3/9] scsi: improved eh timeout handler

Quoted 35 lines · Ewan Milne
Quoted 30 lines · James Bottomley
Quoted 19 lines · Christoph Hellwig
Quoted 10 lines · Hannes Reinecke

When a command runs into a timeout we need to send an 'ABORT TASK' TMF. This is typically done by the 'eh_abort_handler' LLDD callback.

Conceptually, however, this function is a normal SCSI command, so there is no need to enter the error handler.

This patch implements a new scsi_abort_command() function which invokes an asynchronous function scsi_eh_abort_handler() to abort the commands via 'eh_abort_handler'.

Quoted 7 lines

If the 'eh_abort_handler' returns SUCCESS or FAST_IO_FAIL the command will be retried if possible. If no retries are allowed the command will be returned immediately, as we have to assume the TMF succeeded and the command is completed with the LLDD. If the TMF fails the command will be pushed back onto the list of failed commands and the SCSI EH handler will be called immediately for all timed-out commands.

Quoted 3 lines

Why can't we use a work item per command? Linking things into a list just to queue it up to workqueues missed half of the point of the workqueue infrastructure.

Actually, I think we can dump the workqueue altogether. The only reason we need it is because the current abort handlers wait for the command and return the completion state. However, all LLDs are capable of emitting TMFs at interrupt level, so if we separated the emit from the wait, we could simply do this sequence:

Quoted 3 lines

on timeout, fire the abort from interrupt and mark the command as having an abort issued (possibly by adding a pointer to the abort task), return BLK_EH_RESET_TIMER.

Quoted 5 lines

Doesn't this cause blk_rq_timed_out to reset the timer on the req to the original timeout value again? It seems like this would increase the time before any further attempted error handling. The default timeout is 30 seconds for sd, but it could be much longer (e.g. WRITE SAME, which was 120 seconds last I looked).

It currently does, but that's fixable via a special return code.

James

#14 lore raw

Re: [PATCH 3/9] scsi: improved eh timeout handler

In reply to James Bottomley
Quoted 34 lines · James Bottomley
Quoted 19 lines · Christoph Hellwig
Quoted 10 lines · Hannes Reinecke

When a command runs into a timeout we need to send an 'ABORT TASK' TMF. This is typically done by the 'eh_abort_handler' LLDD callback.

Conceptually, however, this function is a normal SCSI command, so there is no need to enter the error handler.

This patch implements a new scsi_abort_command() function which invokes an asynchronous function scsi_eh_abort_handler() to abort the commands via 'eh_abort_handler'.

Quoted 7 lines

If the 'eh_abort_handler' returns SUCCESS or FAST_IO_FAIL the command will be retried if possible. If no retries are allowed the command will be returned immediately, as we have to assume the TMF succeeded and the command is completed with the LLDD. If the TMF fails the command will be pushed back onto the list of failed commands and the SCSI EH handler will be called immediately for all timed-out commands.

Quoted 3 lines

Why can't we use a work item per command? Linking things into a list just to queue it up to workqueues missed half of the point of the workqueue infrastructure.

Actually, I think we can dump the workqueue altogether. The only reason we need it is because the current abort handlers wait for the command and return the completion state. However, all LLDs are capable of emitting TMFs at interrupt level, so if we separated the emit from the wait, we could simply do this sequence:

on timeout, fire the abort from interrupt and mark the command as having an abort issued (possibly by adding a pointer to the abort task), return BLK_EH_RESET_TIMER.

Quoted 6 lines

Now if the timeout fires again, assume the abort was unsucessful and escalate to LUN reset.

This is fully asynchronous, fully tracked and doesn't rely on work queues.

Hehe. Been there, done that, doesn't work :-(
That was my original idea, too.

But some LLDDs send TMFs in a non-interrupt-safe way, so the only way to make it work was to use a workqueue.
(Eg qla2xxx has a parameter to send TMFs async, but this doesn't work on older firmware).

Quoted 4 lines

The necessary additions for something like this are the from interrupt issue abort and LUN reset, which could just be additional callbacks in the host template.

However, we could make that optional, so that LLDDs not capable of sending TMFs in an interrupt-safe manner will continue to use the original framework.

Ok, let's see whether this flies.

Cheers,

Hannes

Signature · 8 lines
Dr. Hannes Reinecke		      zSeries & Storage
[email protected]			      +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#15 lore raw

Re: [PATCH 3/9] scsi: improved eh timeout handler

In reply to James Bottomley
Quoted 13 lines · James Bottomley

Actually, I think we can dump the workqueue altogether. The only reason we need it is because the current abort handlers wait for the command and return the completion state. However, all LLDs are capable of emitting TMFs at interrupt level, so if we separated the emit from the wait, we could simply do this sequence:

on timeout, fire the abort from interrupt and mark the command as having an abort issued (possibly by adding a pointer to the abort task), return BLK_EH_RESET_TIMER.

Now if the timeout fires again, assume the abort was unsuccessful and escalate to LUN reset.

Quoted 6 lines

This is fully asynchronous, fully tracked and doesn't rely on work queues.

The necessary additions for something like this are the from interrupt issue abort and LUN reset, which could just be additional callbacks in the host template.

Do we really need a new callback in the host template for a command abort that does not wait ? Several LLDs already have their own internal data structures for keeping track of the request state and can use these data structures to set a flag "command has been aborted". If aborting a command fails and the command completes that flag can then be used to avoid a second invocation of scsi_done(). At least, that's what the SRP initiator already does today in srp_abort().

Bart.

#16 lore raw

Re: [PATCH 3/9] scsi: improved eh timeout handler

Quoted 27 lines · Bart Van Assche
Quoted 17 lines · James Bottomley

Actually, I think we can dump the workqueue altogether. The only reason
we need it is because the current abort handlers wait for the command and return the completion state. However, all LLDs are capable of emitting TMFs at interrupt level, so if we separated the emit from the
wait, we could simply do this sequence:

on timeout, fire the abort from interrupt and mark the command as having
an abort issued (possibly by adding a pointer to the abort task), return
BLK_EH_RESET_TIMER.

Now if the timeout fires again, assume the abort was unsuccessful and escalate to LUN reset.

Quoted 8 lines

This is fully asynchronous, fully tracked and doesn't rely on work queues.

The necessary additions for something like this are the from interrupt
issue abort and LUN reset, which could just be additional callbacks in
the host template.

Quoted 9 lines

Do we really need a new callback in the host template for a command abort that does not wait ? Several LLDs already have their own internal data structures for keeping track of the request state and can use these data structures to set a flag "command has been aborted". If aborting a command fails and the command completes that flag can then be used to avoid a second invocation of scsi_done(). At least, that's what the SRP initiator already does today in srp_abort().

Currently I'm playing around with this:

include/scsi/scsi_host.h +3 -0
index 4908480..498164a 100644
@@ -174,6 +174,9 @@ struct scsi_host_template {
        int (* eh_bus_reset_handler)(struct scsi_cmnd *);
        int (* eh_host_reset_handler)(struct scsi_cmnd *);
 
+       int (* eh_send_abort)(struct scsi_cmnd *);
+       void (* eh_cancel_abort)(struct scsi_cmnd *);
+
        /*
 

'eh_send_abort' sends the TMF asynchronously; it is the drivers responsibility to return the command to be aborted to the SCSI midlayer after calling this function.
The return value is 'SUCCESS' if the TMF was sent or 'FAILED' if sending the TMF failed. It does _not_ indicate the status of the TMF itself, as this is done implicitly by returning the command with an appropriate status.

'eh_cancel_abort' is optional, and can be called at any time after 'eh_send_abort' to cancel the TMF. After calling 'eh_cancel_abort' neither the TMF nor the command must be considered valid from the LLDD. 'eh_cancel_abort' is for LLDDs requiring cleanups when aborting TMFs. LLDDs not requiring any cleanup simply can not implement this callback.

Cheers,

Hannes

Signature · 8 lines
Dr. Hannes Reinecke		      zSeries & Storage
[email protected]			      +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#17 lore raw

Re: [PATCH 3/9] scsi: improved eh timeout handler

In reply to Hannes Reinecke

drivers/scsi/scsi_error.c void scsi_schedule_eh(struct Scsi_Host *shost) · line 208

Quoted 10 lines · Hannes Reinecke
drivers/scsi/scsi_error.c +10 -0
+
+	spin_lock_irqsave(&sdev->list_lock, flags);
+	if (list_empty(&sdev->eh_abort_list))
+		kick_worker = 1;
+	list_add(&scmd->eh_entry, &sdev->eh_abort_list);
+	spin_unlock_irqrestore(&sdev->list_lock, flags);
+	SCSI_LOG_ERROR_RECOVERY(3,
+		scmd_printk(KERN_INFO, scmd, "adding to eh_abort_list\n"));
+	if (kick_worker)
+		schedule_work(&sdev->abort_work);

You fixed the case with the non-empty list. But afaics the same workitem can still be called multiple times simultaneously, which will crash the system.

Jörn

--
The only real mistake is the one from which we learn nothing. -- John Powell
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#18 lore raw

PATCH v2 4/9 virtio_scsi: Enable new EH timeout handler

In reply to Hannes Reinecke
---
 drivers/scsi/virtio_scsi.c | 7 +++++++
 1 file changed, 7 insertions(+)
drivers/scsi/virtio_scsi.c +7 -0
index 2168258..1efd219 100644
@@ -654,6 +654,11 @@ static int virtscsi_abort(struct scsi_cmnd *sc)
 	return virtscsi_tmf(vscsi, cmd);
 }
 
+static enum blk_eh_timer_return virtscsi_timedout(struct scsi_cmnd *scmd)
+{
+	return scsi_abort_command(scmd);
+}
+
 static int virtscsi_target_alloc(struct scsi_target *starget)
 {
 	struct virtio_scsi_target_state *tgt =
@@ -683,6 +688,7 @@ static struct scsi_host_template virtscsi_host_template_single = {
 	.queuecommand = virtscsi_queuecommand_single,
 	.eh_abort_handler = virtscsi_abort,
 	.eh_device_reset_handler = virtscsi_device_reset,
+	.eh_timed_out = virtscsi_timedout,
 
 	.can_queue = 1024,
 	.dma_boundary = UINT_MAX,
@@ -699,6 +705,7 @@ static struct scsi_host_template virtscsi_host_template_multi = {
 	.queuecommand = virtscsi_queuecommand_multi,
 	.eh_abort_handler = virtscsi_abort,
 	.eh_device_reset_handler = virtscsi_device_reset,
+	.eh_timed_out = virtscsi_timedout,
 
 	.can_queue = 1024,
 	.dma_boundary = UINT_MAX,
Signature · 1 line
1.7.12.4
reviewer Acked-by on v2 4/9
#19 lore raw

Re: [PATCH 4/9] virtio_scsi: Enable new EH timeout handler

Il 10/06/2013 03:40, Hannes Reinecke ha scritto:

Quoted 31 lines
---
 drivers/scsi/virtio_scsi.c | 7 +++++++
 1 file changed, 7 insertions(+)
drivers/scsi/virtio_scsi.c +6 -0
index 2168258..1efd219 100644
@@ -654,6 +654,11 @@ static int virtscsi_abort(struct scsi_cmnd *sc)
 	return virtscsi_tmf(vscsi, cmd);
 }
 
+static enum blk_eh_timer_return virtscsi_timedout(struct scsi_cmnd *scmd)
+{
+	return scsi_abort_command(scmd);
+}
+
 static int virtscsi_target_alloc(struct scsi_target *starget)
 {
 	struct virtio_scsi_target_state *tgt =
@@ -683,6 +688,7 @@ static struct scsi_host_template virtscsi_host_template_single = {
 	.queuecommand = virtscsi_queuecommand_single,
 	.eh_abort_handler = virtscsi_abort,
 	.eh_device_reset_handler = virtscsi_device_reset,
+	.eh_timed_out = virtscsi_timedout,
 
 	.can_queue = 1024,
 	.dma_boundary = UINT_MAX,

drivers/scsi/virtio_scsi.c static struct scsi_host_template virtscsi_host_template_multi = { · line 711

Quoted 7 lines
drivers/scsi/virtio_scsi.c +1 -0
@@ -699,6 +705,7 @@ static struct scsi_host_template virtscsi_host_template_multi = {
 	.queuecommand = virtscsi_queuecommand_multi,
 	.eh_abort_handler = virtscsi_abort,
 	.eh_device_reset_handler = virtscsi_device_reset,
+	.eh_timed_out = virtscsi_timedout,
 
 	.can_queue = 1024,
 	.dma_boundary = UINT_MAX,
Reviewed-by on v2 4/9
#20 lore raw

Re: [PATCH 4/9] virtio_scsi: Enable new EH timeout handler

In reply to Hannes Reinecke
Quoted 1 line · Hannes Reinecke
Quoted 43 lines
---
 drivers/scsi/virtio_scsi.c | 7 +++++++
 1 file changed, 7 insertions(+)
drivers/scsi/virtio_scsi.c +7 -0
index 2168258..1efd219 100644
@@ -654,6 +654,11 @@ static int virtscsi_abort(struct scsi_cmnd *sc)
 	return virtscsi_tmf(vscsi, cmd);
 }
 
+static enum blk_eh_timer_return virtscsi_timedout(struct scsi_cmnd *scmd)
+{
+	return scsi_abort_command(scmd);
+}
+
 static int virtscsi_target_alloc(struct scsi_target *starget)
 {
 	struct virtio_scsi_target_state *tgt =
@@ -683,6 +688,7 @@ static struct scsi_host_template virtscsi_host_template_single = {
 	.queuecommand = virtscsi_queuecommand_single,
 	.eh_abort_handler = virtscsi_abort,
 	.eh_device_reset_handler = virtscsi_device_reset,
+	.eh_timed_out = virtscsi_timedout,
 
 	.can_queue = 1024,
 	.dma_boundary = UINT_MAX,
@@ -699,6 +705,7 @@ static struct scsi_host_template virtscsi_host_template_multi = {
 	.queuecommand = virtscsi_queuecommand_multi,
 	.eh_abort_handler = virtscsi_abort,
 	.eh_device_reset_handler = virtscsi_device_reset,
+	.eh_timed_out = virtscsi_timedout,
 
 	.can_queue = 1024,
 	.dma_boundary = UINT_MAX,
Signature · 6 lines
1.7.12.4

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Signature · 1 line
Asias
#21 lore raw

PATCH v2 5/9 virtio-scsi: Implement TMF timeout

In reply to Hannes Reinecke

Any TMF might be take longer as expected, or not return at all. So we need to use 'wait_for_completion_timeout' when sending a TMF to protect against these cases.

---
 drivers/scsi/virtio_scsi.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/scsi/virtio_scsi.c +5 -2
index 1efd219..abfc684 100644
@@ -30,6 +30,7 @@
 #define VIRTIO_SCSI_MEMPOOL_SZ 64
 #define VIRTIO_SCSI_EVENT_LEN 8
 #define VIRTIO_SCSI_VQ_BASE 2
+#define VIRTIO_SCSI_TMF_TIMEOUT 30
 
 /* Command queue element */
 struct virtio_scsi_cmd {
@@ -597,8 +598,10 @@ static int virtscsi_tmf(struct virtio_scsi *vscsi, struct virtio_scsi_cmd *cmd)
 			      GFP_NOIO) < 0)
 		goto out;
 
-	wait_for_completion(&comp);
-	if (cmd->resp.tmf.response == VIRTIO_SCSI_S_OK ||
+	if (wait_for_completion_timeout(&comp,
+					VIRTIO_SCSI_TMF_TIMEOUT * HZ) == 0)
+		ret = FAILED;
+	else if (cmd->resp.tmf.response == VIRTIO_SCSI_S_OK ||
 	    cmd->resp.tmf.response == VIRTIO_SCSI_S_FUNCTION_SUCCEEDED)
 		ret = SUCCESS;
 
Signature · 1 line
1.7.12.4
reviewer Acked-by on v2 5/9
#22 lore raw

Re: [PATCH 5/9] virtio-scsi: Implement TMF timeout

Il 10/06/2013 03:40, Hannes Reinecke ha scritto:

Quoted 26 lines

Any TMF might be take longer as expected, or not return at all. So we need to use 'wait_for_completion_timeout' when sending a TMF to protect against these cases.

---
 drivers/scsi/virtio_scsi.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/scsi/virtio_scsi.c +1 -0
index 1efd219..abfc684 100644
@@ -30,6 +30,7 @@
 #define VIRTIO_SCSI_MEMPOOL_SZ 64
 #define VIRTIO_SCSI_EVENT_LEN 8
 #define VIRTIO_SCSI_VQ_BASE 2
+#define VIRTIO_SCSI_TMF_TIMEOUT 30
 
 /* Command queue element */
 struct virtio_scsi_cmd {
@@ -597,8 +598,10 @@ static int virtscsi_tmf(struct virtio_scsi *vscsi, struct virtio_scsi_cmd *cmd)
 			      GFP_NOIO) < 0)
 		goto out;

drivers/scsi/virtio_scsi.c static int virtscsi_tmf(struct virtio_scsi *vscsi, struct virtio_scsi_cmd *cmd) · line 607

Quoted 10 lines
drivers/scsi/virtio_scsi.c +4 -2
 
-	wait_for_completion(&comp);
-	if (cmd->resp.tmf.response == VIRTIO_SCSI_S_OK ||
+	if (wait_for_completion_timeout(&comp,
+					VIRTIO_SCSI_TMF_TIMEOUT * HZ) == 0)
+		ret = FAILED;
+	else if (cmd->resp.tmf.response == VIRTIO_SCSI_S_OK ||
 	    cmd->resp.tmf.response == VIRTIO_SCSI_S_FUNCTION_SUCCEEDED)
 		ret = SUCCESS;
 
Reviewed-by on v2 5/9
#23 lore raw

Re: [PATCH 5/9] virtio-scsi: Implement TMF timeout

In reply to Hannes Reinecke
Quoted 6 lines · Hannes Reinecke

Any TMF might be take longer as expected, or not return at all. So we need to use 'wait_for_completion_timeout' when sending a TMF to protect against these cases.

Quoted 36 lines
---
 drivers/scsi/virtio_scsi.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/scsi/virtio_scsi.c +5 -2
index 1efd219..abfc684 100644
@@ -30,6 +30,7 @@
 #define VIRTIO_SCSI_MEMPOOL_SZ 64
 #define VIRTIO_SCSI_EVENT_LEN 8
 #define VIRTIO_SCSI_VQ_BASE 2
+#define VIRTIO_SCSI_TMF_TIMEOUT 30
 
 /* Command queue element */
 struct virtio_scsi_cmd {
@@ -597,8 +598,10 @@ static int virtscsi_tmf(struct virtio_scsi *vscsi, struct virtio_scsi_cmd *cmd)
 			      GFP_NOIO) < 0)
 		goto out;
 
-	wait_for_completion(&comp);
-	if (cmd->resp.tmf.response == VIRTIO_SCSI_S_OK ||
+	if (wait_for_completion_timeout(&comp,
+					VIRTIO_SCSI_TMF_TIMEOUT * HZ) == 0)
+		ret = FAILED;
+	else if (cmd->resp.tmf.response == VIRTIO_SCSI_S_OK ||
 	    cmd->resp.tmf.response == VIRTIO_SCSI_S_FUNCTION_SUCCEEDED)
 		ret = SUCCESS;
 
Signature · 6 lines
1.7.12.4

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Signature · 1 line
Asias
#24 lore raw

PATCH v2 6/9 libsas: Enable new EH timeout handler

In reply to Hannes Reinecke
---
 drivers/scsi/libsas/sas_scsi_host.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/scsi/libsas/sas_scsi_host.c +1 -1
index 6e795a1..9d5bd29 100644
@@ -864,7 +864,7 @@ enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
 {
 	scmd_printk(KERN_DEBUG, cmd, "command %p timed out\n", cmd);
 
-	return BLK_EH_NOT_HANDLED;
+	return scsi_abort_command(cmd);
 }
 
 int sas_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
Signature · 1 line
1.7.12.4
#25 lore raw

PATCH v2 7/9 mptsas: Enable new EH timeout handler

In reply to Hannes Reinecke
---
 drivers/message/fusion/mptsas.c   | 1 +
 drivers/message/fusion/mptscsih.c | 7 +++++++
 drivers/message/fusion/mptscsih.h | 1 +
 3 files changed, 9 insertions(+)
drivers/message/fusion/mptsas.c +1 -0
index dd239bd..ed56434 100644
@@ -1987,6 +1987,7 @@ static struct scsi_host_template mptsas_driver_template = {
 	.target_destroy			= mptsas_target_destroy,
 	.slave_destroy			= mptscsih_slave_destroy,
 	.change_queue_depth 		= mptscsih_change_queue_depth,
+	.eh_timed_out			= mptscsih_timed_out,
 	.eh_abort_handler		= mptscsih_abort,
 	.eh_device_reset_handler	= mptscsih_dev_reset,
 	.eh_host_reset_handler		= mptscsih_host_reset,
drivers/message/fusion/mptscsih.c +7 -0
index 727819c..e743e84 100644
@@ -1679,6 +1679,13 @@ mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
 	}
 }
 
+enum blk_eh_timer_return
+mptscsih_timed_out(struct scsi_cmnd *SCpnt)
+{
+	return scsi_abort_command(SCpnt);
+}
+EXPORT_SYMBOL(mptscsih_timed_out);
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *	mptscsih_abort - Abort linux scsi_cmnd routine, new_eh variant
drivers/message/fusion/mptscsih.h +1 -0
index 83f5031..3f2dd05 100644
@@ -118,6 +118,7 @@ extern int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel,
 	u8 id, int lun, int ctx2abort, ulong timeout);
 extern void mptscsih_slave_destroy(struct scsi_device *device);
 extern int mptscsih_slave_configure(struct scsi_device *device);
+enum blk_eh_timer_return mptscsih_timed_out(struct scsi_cmnd *SCpnt);
 extern int mptscsih_abort(struct scsi_cmnd * SCpnt);
 extern int mptscsih_dev_reset(struct scsi_cmnd * SCpnt);
 extern int mptscsih_bus_reset(struct scsi_cmnd * SCpnt);
Signature · 1 line
1.7.12.4
#26 lore raw

PATCH v2 8/9 mpt2sas: Enable new EH timeout handler

In reply to Hannes Reinecke
---
 drivers/scsi/mpt2sas/mpt2sas_scsih.c | 11 +++++++++++
 1 file changed, 11 insertions(+)
drivers/scsi/mpt2sas/mpt2sas_scsih.c +11 -0
index c6bdc92..47fc66c 100644
@@ -2565,6 +2565,16 @@ _scsih_tm_display_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd)
 }
 
 /**
+ * _scsih_timed_out - eh timeout handler
+ * @scmd: pointer to scsi command object
+ */
+static enum blk_eh_timer_return
+_scsih_timed_out(struct scsi_cmnd *scmd)
+{
+	return scsi_abort_command(scmd);
+}
+
+/**
  * _scsih_abort - eh threads main abort routine
  * @scmd: pointer to scsi command object
  *
@@ -7515,6 +7525,7 @@ static struct scsi_host_template scsih_driver_template = {
 	.scan_start			= _scsih_scan_start,
 	.change_queue_depth 		= _scsih_change_queue_depth,
 	.change_queue_type		= _scsih_change_queue_type,
+	.eh_timed_out			= _scsih_timed_out,
 	.eh_abort_handler		= _scsih_abort,
 	.eh_device_reset_handler	= _scsih_dev_reset,
 	.eh_target_reset_handler	= _scsih_target_reset,
Signature · 1 line
1.7.12.4
#27 lore raw

Re: [PATCH 8/9] mpt2sas: Enable new EH timeout handler

Quoted 12 lines · Hannes Reinecke
---
 drivers/scsi/mpt2sas/mpt2sas_scsih.c | 11 +++++++++++
 1 file changed, 11 insertions(+)
drivers/scsi/mpt2sas/mpt2sas_scsih.c +0 -0
index c6bdc92..47fc66c 100644
@@ -2565,6 +2565,16 @@ _scsih_tm_display_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd)
 }

drivers/scsi/mpt2sas/mpt2sas_scsih.c _scsih_tm_display_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd) · line 2575

Quoted 10 lines
drivers/scsi/mpt2sas/mpt2sas_scsih.c +8 -0
 
 /**
+ * _scsih_timed_out - eh timeout handler
+ * @scmd: pointer to scsi command object
+ */
+static enum blk_eh_timer_return
+_scsih_timed_out(struct scsi_cmnd *scmd)
+{
+	return scsi_abort_command(scmd);
+}

Why did you create this function and not do the following?
+ .eh_timed_out = scsi_abort_command,

Quoted 15 lines
drivers/scsi/mpt2sas/mpt2sas_scsih.c +2 -0
+/**
  * _scsih_abort - eh threads main abort routine
  * @scmd: pointer to scsi command object
  *
@@ -7515,6 +7525,7 @@ static struct scsi_host_template scsih_driver_template = {
 	.scan_start			= _scsih_scan_start,
 	.change_queue_depth 		= _scsih_change_queue_depth,
 	.change_queue_type		= _scsih_change_queue_type,
+	.eh_timed_out			= _scsih_timed_out,
 	.eh_abort_handler		= _scsih_abort,
 	.eh_device_reset_handler	= _scsih_dev_reset,
 	.eh_target_reset_handler	= _scsih_target_reset,
Signature · 1 line
1.7.12.4

Jörn

--
The cheapest, fastest and most reliable components of a computer system are those that aren't there.
-- Gordon Bell, DEC labratories
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#28 lore raw

Re: [PATCH 8/9] mpt2sas: Enable new EH timeout handler

Quoted 26 lines · Jörn Engel
Quoted 12 lines · Hannes Reinecke
---
 drivers/scsi/mpt2sas/mpt2sas_scsih.c | 11 +++++++++++
 1 file changed, 11 insertions(+)
drivers/scsi/mpt2sas/mpt2sas_scsih.c +0 -0
index c6bdc92..47fc66c 100644
@@ -2565,6 +2565,16 @@ _scsih_tm_display_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd)
 }

drivers/scsi/mpt2sas/mpt2sas_scsih.c _scsih_tm_display_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd) · line 2575

Quoted 10 lines
drivers/scsi/mpt2sas/mpt2sas_scsih.c +8 -0
 
 /**
+ * _scsih_timed_out - eh timeout handler
+ * @scmd: pointer to scsi command object
+ */
+static enum blk_eh_timer_return
+_scsih_timed_out(struct scsi_cmnd *scmd)
+{
+	return scsi_abort_command(scmd);
+}

Why did you create this function and not do the following?

Review

Quoted 1 line
(quoted diff) +1 -0
+	.eh_timed_out			= scsi_abort_command,

Good point.

That function was required for an earlier version (where I had 'void scsi_abort_command()').
So yeah, that function isn't required.

Cheers,

Hannes

Signature · 8 lines
Dr. Hannes Reinecke		      zSeries & Storage
[email protected]			      +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#29 lore raw

PATCH v2 9/9 mpt3sas: Enable new EH timeout handler

In reply to Hannes Reinecke
---
 drivers/scsi/mpt3sas/mpt3sas_scsih.c | 11 +++++++++++
 1 file changed, 11 insertions(+)
drivers/scsi/mpt3sas/mpt3sas_scsih.c +11 -0
index dcbf7c8..3a35ddc 100644
@@ -2228,6 +2228,16 @@ _scsih_tm_display_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd)
 }
 
 /**
+ * _scsih_timed_out - eh timeout handler
+ * @scmd: pointer to scsi command object
+ */
+static enum blk_eh_timer_return
+_scsih_timed_out(struct scsi_cmnd *scmd)
+{
+	return scsi_abort_command(scmd);
+}
+
+/**
  * _scsih_abort - eh threads main abort routine
  * @scmd: pointer to scsi command object
  *
@@ -7230,6 +7240,7 @@ static struct scsi_host_template scsih_driver_template = {
 	.scan_start			= _scsih_scan_start,
 	.change_queue_depth		= _scsih_change_queue_depth,
 	.change_queue_type		= _scsih_change_queue_type,
+	.eh_timed_out			= _scsih_timed_out,
 	.eh_abort_handler		= _scsih_abort,
 	.eh_device_reset_handler	= _scsih_dev_reset,
 	.eh_target_reset_handler	= _scsih_target_reset,
Signature · 1 line
1.7.12.4