New EH command timeout handler
Subsystems (2)
v10 cover New EH command timeout handler
Hi all,
this patchset implements a new SCSI EH command timeout handler which will be sending command aborts inline without actually engaging SCSI EH.
SCSI EH will only be invoked if command abort fails.
In addition the commands will be returned directly if the command abort succeeded, cutting down recovery times dramatically.
With the original SCSI EH I got:
# time dd if=/dev/zero of=/dev/dm-2 bs=4k count=4k oflag=direct 4096+0 records in 4096+0 records out 16777216 bytes (17 MB) copied, 142.652 s, 118 kB/s
real 2m22.657s
user 0m0.013s
sys 0m0.145s
With this patchset I got:
# time dd if=/dev/zero of=/dev/dm-2 bs=4k count=4k oflag=direct 4096+0 records in 4096+0 records out 16777216 bytes (17 MB) copied, 52.1579 s, 322 kB/s
real 0m52.163s
user 0m0.012s
sys 0m0.145s
Test was to disable RSCN on the target port, disable the target port, and then start the 'dd' command as indicated.
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.
Changes to v2:
- Removed eh_entry initialisation
- Convert to per-command workqueue
Changes to v3:
- Use delayed_work
- Enable new eh timeout handler for virtio, SAS, and FC
- Modify logging messages to include scmd pointer
Changes to v4:
- Remove stubs when enabling new eh timeout handler for other drivers
Changes to v5:
- Enable new eh timeout handler per default
- Update documentation
Changes to v6:
- Include changes from James Bottomley for erratic device offline patch
- Rearrange patches
- Update SCSI midlayer documentation
Changes to v7:
- Merge obsolete patch
Changes to v8:
- Include fixes from hch
- Include patch from Ren Mingxin to set eh_deadline to '0'
Changes to v9:
- Unlock accesses to eh_deadline
Hannes Reinecke (3):
scsi: improved eh timeout handler
scsi: Unlock accesses to eh_deadline
scsi: Update documentation
James Bottomley (1):
scsi: Fix erratic device offline during EH
Ren Mingxin (1):
scsi: Set the minimum valid value of 'eh_deadline' as 0
Documentation/scsi/scsi_eh.txt | 69 +++++----- Documentation/scsi/scsi_mid_low_api.txt | 9 +- drivers/scsi/hosts.c | 16 ++- drivers/scsi/scsi.c | 9 +- drivers/scsi/scsi_error.c | 229 ++++++++++++++++++++++++-------- drivers/scsi/scsi_priv.h | 2 + drivers/scsi/scsi_sysfs.c | 36 +++-- drivers/scsi/sd.c | 26 ++-- include/scsi/scsi_cmnd.h | 1 + include/scsi/scsi_driver.h | 2 +- include/scsi/scsi_host.h | 5 + 11 files changed, 281 insertions(+), 123 deletions(-)
Signature · 1 line
1.7.12.4
PATCH v10 1/5 scsi: Fix erratic device offline during EH
From: James Bottomley <[email protected]>
Commit 18a4d0a22ed6c54b67af7718c305cd010f09ddf8
(Handle disk devices which can not process medium access commands) was introduced to offline any device which cannot process medium access commands.
However, commit 3eef6257de48ff84a5d98ca533685df8a3beaeb8 (Reduce error recovery time by reducing use of TURs) reduced the number of TURs by sending it only on the first failing command, which might or might not be a medium access command. So in combination this results in an erratic device offlining during EH; if the command where the TUR was sent upon happens to be a medium access command the device will be set offline, if not everything proceeds as normal.
This patch moves the check to the final test, eliminating this problem.
--- drivers/scsi/scsi_error.c | 26 +++++++++++++++++--------- drivers/scsi/sd.c | 26 ++++++++++++-------------- include/scsi/scsi_driver.h | 2 +- 3 files changed, 30 insertions(+), 24 deletions(-)
drivers/scsi/scsi_error.c +17 -9
@@ -941,12 +941,6 @@ retry:scsi_eh_restore_cmnd (scmd, &ses); -if (scmd->request->cmd_type !=REQ_TYPE_BLOCK_PC ) { -struct scsi_driver *sdrv =scsi_cmd_to_driver (scmd); -if (sdrv->eh_action) - rtn = sdrv->eh_action (scmd, cmnd, cmnd_size, rtn); - } -return rtn; }
@@ -964,6 +958,16 @@ static int scsi_request_sense(struct scsi_cmnd *scmd)return scsi_send_eh_cmnd (scmd,NULL ,0 , scmd->device->eh_timeout, ~0 ); } +static int scsi_eh_action (struct scsi_cmnd *scmd,int rtn) +{ +if (scmd->request->cmd_type !=REQ_TYPE_BLOCK_PC ) { +struct scsi_driver *sdrv =scsi_cmd_to_driver (scmd); +if (sdrv->eh_action) + rtn = sdrv->eh_action (scmd, rtn); + } +return rtn; +} +/** * scsi_eh_finish_cmd - Handle a cmd that eh is finished with. * @scmd: Original SCSI cmd that eh has finished.
@@ -1142,7 +1146,9 @@ static int scsi_eh_test_devices(struct list_head *cmd_list,list_for_each_entry_safe (scmd, next, cmd_list, eh_entry)if (scmd->device == sdev) { -if (finish_cmds) +if (finish_cmds && + (try_stu || +scsi_eh_action (scmd,SUCCESS ) ==SUCCESS ))scsi_eh_finish_cmd (scmd, done_q);else list_move_tail (&scmd->eh_entry, work_q);
@@ -1283,7 +1289,8 @@ static int scsi_eh_stu(struct Scsi_Host *shost, !scsi_eh_tur(stu_scmd)) {list_for_each_entry_safe (scmd, next, work_q, eh_entry) { -if (scmd->device == sdev) +if (scmd->device == sdev && +scsi_eh_action (scmd,SUCCESS ) ==SUCCESS )scsi_eh_finish_cmd (scmd, done_q); } }
@@ -1350,7 +1357,8 @@ static int scsi_eh_bus_device_reset(struct Scsi_Host *shost, !scsi_eh_tur(bdr_scmd)) {list_for_each_entry_safe (scmd, next, work_q, eh_entry) { -if (scmd->device == sdev) +if (scmd->device == sdev && +scsi_eh_action (scmd, rtn) !=FAILED )scsi_eh_finish_cmd (scmd, done_q); }
drivers/scsi/sd.c +12 -14
@@ -110,7 +110,7 @@ static int sd_suspend_runtime(struct device *);static int sd_resume (struct device *);static void sd_rescan (struct device *);static int sd_done (struct scsi_cmnd *); -static int sd_eh_action (struct scsi_cmnd *,unsigned char *,int ,int ); +static int sd_eh_action (struct scsi_cmnd *,int );static void sd_read_capacity (struct scsi_disk *sdkp,unsigned char *buffer);static void scsi_disk_release (struct device *cdev);static void sd_print_sense_hdr (struct scsi_disk *,struct scsi_sense_hdr *);
@@ -1551,23 +1551,23 @@ static const struct block_device_operations sd_fops = {/** * sd_eh_action - error handling callback * @scmd: sd-issued command that has failed -* @eh_cmnd: The command that was sent during error handling -* @eh_cmnd_len: Length of eh_cmnd in bytes * @eh_disp: The recovery disposition suggested by the midlayer * -* This function is called by the SCSI midlayer upon completion of -* an error handling command (TEST UNIT READY, START STOP UNIT, -* etc.) The command sent to the device by the error handler is -* stored in eh_cmnd. The result of sending the eh command is -* passed in eh_disp. +* This function is called by the SCSI midlayer upon completion of an +* error test command (currently TEST UNIT READY). The result of sending +* the eh command is passed in eh_disp. We're looking for devices that +* fail medium access commands but are OK with non access commands like +* test unit ready (so wrongly see the device as having a successful +* recovery) **/ -static int sd_eh_action (struct scsi_cmnd *scmd,unsigned char *eh_cmnd, -int eh_cmnd_len,int eh_disp) +static int sd_eh_action (struct scsi_cmnd *scmd,int eh_disp) {struct scsi_disk *sdkp =scsi_disk (scmd->request->rq_disk);if (!scsi_device_online (scmd->device) || - !scsi_medium_access_command (scmd)) + !scsi_medium_access_command (scmd) || +host_byte (scmd->result) !=DID_TIME_OUT || + eh_disp !=SUCCESS )return eh_disp;/*
@@ -1577,9 +1577,7 @@ static int sd_eh_action(struct scsi_cmnd *scmd, unsigned char *eh_cmnd,* process of recovering or has it suffered an internal failure * that prevents access to the storage medium. */ -if (host_byte (scmd->result) ==DID_TIME_OUT && eh_disp ==SUCCESS && - eh_cmnd_len && eh_cmnd[0 ] ==TEST_UNIT_READY ) - sdkp->medium_access_timed_out++; + sdkp->medium_access_timed_out++;/* * If the device keeps failing read/write commands but TEST UNIT
include/scsi/scsi_driver.h +1 -1
@@ -16,7 +16,7 @@ struct scsi_driver {void (*rescan)(struct device *);int (*done)(struct scsi_cmnd *); -int (*eh_action)(struct scsi_cmnd *,unsigned char *,int ,int ); +int (*eh_action)(struct scsi_cmnd *,int ); };#define to_scsi_driver (drv) \ container_of((drv), struct scsi_driver, gendrv)
Signature · 1 line
1.7.12.4
PATCH v10 2/5 scsi: improved eh timeout handler
In reply to Hannes ReineckeWhen 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 the usual 'eh_abort_handler'.
If abort succeeds the command is either retried or terminated, depending on the number of allowed retries. However, 'eh_eflags' records the abort, so if the retry would fail again the command is pushed onto the error handler without trying to abort it (again); it'll be cleared up from SCSI EH.
--- drivers/scsi/scsi.c | 3 + drivers/scsi/scsi_error.c | 151 ++++++++++++++++++++++++++++++++++++++++++---- drivers/scsi/scsi_priv.h | 2 + include/scsi/scsi_cmnd.h | 1 + include/scsi/scsi_host.h | 5 ++ 5 files changed, 149 insertions(+), 13 deletions(-)
drivers/scsi/scsi.c +3 -0
@@ -297,6 +297,7 @@ struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, gfp_t gfp_mask) cmd->device = dev;INIT_LIST_HEAD (&cmd->list); +INIT_DELAYED_WORK (&cmd->abort_work, scmd_eh_abort_handler);spin_lock_irqsave (&dev->list_lock, flags);list_add_tail (&cmd->list, &dev->cmd_list);spin_unlock_irqrestore (&dev->list_lock, flags);
@@ -353,6 +354,8 @@ void scsi_put_command(struct scsi_cmnd *cmd)list_del_init (&cmd->list);spin_unlock_irqrestore (&cmd->device->list_lock, flags); +cancel_delayed_work (&cmd->abort_work); +__scsi_put_command (cmd->device->host, cmd, &sdev->sdev_gendev); }EXPORT_SYMBOL (scsi_put_command);
drivers/scsi/scsi_error.c +138 -13
202 lines not on this page · raw message
drivers/scsi/scsi_priv.h +2 -0
@@ -19,6 +19,7 @@ struct scsi_nl_hdr;* Scsi Error Handler Flags */ #define SCSI_EH_CANCEL_CMD 0x0001/* Cancel this cmd */ +#define SCSI_EH_ABORT_SCHEDULED 0x0002/* Abort has been scheduled */ #define SCSI_SENSE_VALID (scmd) \ (((scmd)->sense_buffer[0] & 0x70) == 0x70)
@@ -66,6 +67,7 @@ extern int __init scsi_init_devinfo(void);extern void scsi_exit_devinfo (void );/* scsi_error.c */ +extern void scmd_eh_abort_handler (struct work_struct *work);extern enum blk_eh_timer_return scsi_times_out (struct request *req);extern int scsi_error_handler (void *host);extern int scsi_decide_disposition (struct scsi_cmnd *cmd);
include/scsi/scsi_cmnd.h +1 -0
@@ -55,6 +55,7 @@ struct scsi_cmnd {struct scsi_device *device;struct list_head list;/* scsi_cmnd participates in queue lists */ struct list_head eh_entry;/* entry for the host eh_cmd_q */ +struct delayed_work abort_work;int eh_eflags;/* Used by error handlr */ /*
include/scsi/scsi_host.h +5 -0
@@ -476,6 +476,11 @@ struct scsi_host_template { unsigned ordered_tag:1;/* +* True if asynchronous aborts are not supported +*/ + unsigned no_async_abort:1; + +/* * Countdown for host blocking with no commands outstanding. */ unsigned int max_host_blocked;
Signature · 1 line
1.7.12.4
Re: [PATCH 2/5] scsi: improved eh timeout handler
drivers/scsi/scsi_error.c static int scsi_host_eh_past_deadline(struct Scsi_Host *shost) · line 212
Quoted 8 lines · Hannes Reinecke
drivers/scsi/scsi_error.c +8
-0+ + scmd->eh_eflags |=SCSI_EH_ABORT_SCHEDULED ; +SCSI_LOG_ERROR_RECOVERY (3 , +scmd_printk (KERN_INFO , scmd, +"scmd %p abort scheduled\n" , scmd)); +schedule_delayed_work (&scmd->abort_work,HZ /100 ); +return SUCCESS ; +}
Do we want to use our own workqueue_struct with WQ_MEM_RECLAIM set?
Re: [PATCH 2/5] scsi: improved eh timeout handler
Quoted 12 lines · Mike Christie
drivers/scsi/scsi_error.c static int scsi_host_eh_past_deadline(struct Scsi_Host *shost) · line 212
Quoted 8 lines · Hannes Reinecke
drivers/scsi/scsi_error.c +8
-0+ + scmd->eh_eflags |=SCSI_EH_ABORT_SCHEDULED ; +SCSI_LOG_ERROR_RECOVERY (3 , +scmd_printk (KERN_INFO , scmd, +"scmd %p abort scheduled\n" , scmd)); +schedule_delayed_work (&scmd->abort_work,HZ /100 ); +return SUCCESS ; +}Do we want to use our own
workqueue_structwithWQ_MEM_RECLAIMset?
Errm. Yes, why?
I must admit I'm not _that_ familiar with workqueues ... Care to explain?
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
Re: [PATCH 2/5] scsi: improved eh timeout handler
Quoted 13 lines · Hannes Reinecke
Quoted 12 lines · Mike Christie
drivers/scsi/scsi_error.c static int scsi_host_eh_past_deadline(struct Scsi_Host *shost) · line 212
Quoted 8 lines · Hannes Reinecke
drivers/scsi/scsi_error.c +8
-0+ + scmd->eh_eflags |=SCSI_EH_ABORT_SCHEDULED ; +SCSI_LOG_ERROR_RECOVERY (3 , +scmd_printk (KERN_INFO , scmd, +"scmd %p abort scheduled\n" , scmd)); +schedule_delayed_work (&scmd->abort_work,HZ /100 ); +return SUCCESS ; +}Do we want to use our own
workqueue_structwithWQ_MEM_RECLAIMset?
Quoted 5 lines
Errm. Yes, why?
I must admit I'm not _that_ familiar with workqueues ... Care to explain?
We all share the above workqueue_structs pool of threads, so if we get stuck behind code doing GFP_KERNEL allocs that end up needing to write data to the disk we are now trying to aborts on, then we could get stuck. With WQ_MEM_RECLAIM, we have our own backup thread that gets created at workqueue_struct create time which can get used in cases like that so we can always make forward progress.
Re: [PATCH 2/5] scsi: improved eh timeout handler
Quoted 20 lines · Mike Christie
Quoted 13 lines · Hannes Reinecke
Quoted 12 lines · Mike Christie
drivers/scsi/scsi_error.c static int scsi_host_eh_past_deadline(struct Scsi_Host *shost) · line 212
Quoted 8 lines · Hannes Reinecke
drivers/scsi/scsi_error.c +8
-0+ + scmd->eh_eflags |=SCSI_EH_ABORT_SCHEDULED ; +SCSI_LOG_ERROR_RECOVERY (3 , +scmd_printk (KERN_INFO , scmd, +"scmd %p abort scheduled\n" , scmd)); +schedule_delayed_work (&scmd->abort_work,HZ /100 ); +return SUCCESS ; +}Do we want to use our own
workqueue_structwithWQ_MEM_RECLAIMset?Quoted 5 lines
Errm. Yes, why?
I must admit I'm not _that_ familiar with workqueues ... Care to explain?
Quoted 7 lines
We all share the above
workqueue_structspool of threads, so if we get stuck behind code doingGFP_KERNELallocs that end up needing to write data to the disk we are now trying to aborts on, then we could get stuck. WithWQ_MEM_RECLAIM, we have our own backup thread that gets created atworkqueue_structcreate time which can get used in cases like that so we can always make forward progress.
Ah. Right. Yes, that makes sense.
I guess I'll have to redo the patches _yet again_.
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
Re: [PATCH 2/5] scsi: improved eh timeout handler
Quoted 28 lines · Hannes Reinecke
Quoted 20 lines · Mike Christie
Quoted 13 lines · Hannes Reinecke
Quoted 12 lines · Mike Christie
drivers/scsi/scsi_error.c static int scsi_host_eh_past_deadline(struct Scsi_Host *shost) · line 212
Quoted 8 lines · Hannes Reinecke
drivers/scsi/scsi_error.c +8
-0+ + scmd->eh_eflags |=SCSI_EH_ABORT_SCHEDULED ; +SCSI_LOG_ERROR_RECOVERY (3 , +scmd_printk (KERN_INFO , scmd, +"scmd %p abort scheduled\n" , scmd)); +schedule_delayed_work (&scmd->abort_work,HZ /100 ); +return SUCCESS ; +}Do we want to use our own
workqueue_structwithWQ_MEM_RECLAIMset?Quoted 5 lines
Errm. Yes, why?
I must admit I'm not _that_ familiar with workqueues ... Care to explain?
Quoted 7 lines
We all share the above
workqueue_structspool of threads, so if we get stuck behind code doingGFP_KERNELallocs that end up needing to write data to the disk we are now trying to aborts on, then we could get stuck. WithWQ_MEM_RECLAIM, we have our own backup thread that gets created atworkqueue_structcreate time which can get used in cases like that so we can always make forward progress.
Quoted 3 lines
Ah. Right. Yes, that makes sense.
I guess I'll have to redo the patches
_yetagain_.
I wonder if it might be useful to flag a LU (disk) with "try really hard to recover me, perhaps at the expense of other LUs". Seems like a LU containing the rootfs or swap might qualify for setting such a flag. And LUs that have this flag cleared could be assumed to not get wedged in the fashion that Mike pointed out.
Doug Gilbert
Re: [PATCH 2/5] scsi: improved eh timeout handler
Quoted 35 lines · Douglas Gilbert
Quoted 34 lines · Hannes Reinecke
Quoted 21 lines · Mike Christie
Quoted 14 lines · Hannes Reinecke
Quoted 13 lines · Mike Christie
drivers/scsi/scsi_error.c static int scsi_host_eh_past_deadline(struct Scsi_Host *shost) · line 212
Quoted 8 lines · Hannes Reinecke
drivers/scsi/scsi_error.c +8
-0+ + scmd->eh_eflags |=SCSI_EH_ABORT_SCHEDULED ; +SCSI_LOG_ERROR_RECOVERY (3 , +scmd_printk (KERN_INFO , scmd, +"scmd %p abort scheduled\n" , scmd)); +schedule_delayed_work (&scmd->abort_work,HZ /100 ); +return SUCCESS ; +}Do we want to use our own
workqueue_structwithWQ_MEM_RECLAIMset?Quoted 5 lines
Errm. Yes, why?
I must admit I'm not _that_ familiar with workqueues ... Care to explain?
Quoted 10 lines
We all share the above
workqueue_structspool of threads, so if we get
stuck behind code doingGFP_KERNELallocs that end up needing to write
data to the disk we are now trying to aborts on, then we could get stuck. WithWQ_MEM_RECLAIM, we have our own backup thread that gets created atworkqueue_structcreate time which can get used in cases like
that so we can always make forward progress.Ah. Right. Yes, that makes sense.
Quoted 9 lines
Quoted 1 line
I guess I'll have to redo the patches
_yetagain_.I wonder if it might be useful to flag a LU (disk) with "try really hard to recover me, perhaps at the expense of other LUs". Seems like a LU containing the rootfs or swap might qualify for setting such a flag. And LUs that have this flag cleared could be assumed to not get wedged in the fashion that Mike pointed out.
While this would be a good idea in general, I would _very much_ see to have this patch accepted first. Without that proviso any discussion is pretty much moot anyway.
So I would like to defer that until the patch has been accepted.
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
Re: [PATCH 2/5] scsi: improved eh timeout handler
In reply to Hannes ReineckeQuoted 28 lines · Hannes Reinecke
Quoted 20 lines · Mike Christie
Quoted 13 lines · Hannes Reinecke
Quoted 12 lines · Mike Christie
drivers/scsi/scsi_error.c static int scsi_host_eh_past_deadline(struct Scsi_Host *shost) · line 212
Quoted 8 lines · Hannes Reinecke
drivers/scsi/scsi_error.c +8
-0+ + scmd->eh_eflags |=SCSI_EH_ABORT_SCHEDULED ; +SCSI_LOG_ERROR_RECOVERY (3 , +scmd_printk (KERN_INFO , scmd, +"scmd %p abort scheduled\n" , scmd)); +schedule_delayed_work (&scmd->abort_work,HZ /100 ); +return SUCCESS ; +}Do we want to use our own
workqueue_structwithWQ_MEM_RECLAIMset?Quoted 5 lines
Errm. Yes, why?
I must admit I'm not _that_ familiar with workqueues ... Care to explain?
Quoted 7 lines
We all share the above
workqueue_structspool of threads, so if we get stuck behind code doingGFP_KERNELallocs that end up needing to write data to the disk we are now trying to aborts on, then we could get stuck. WithWQ_MEM_RECLAIM, we have our own backup thread that gets created atworkqueue_structcreate time which can get used in cases like that so we can always make forward progress.
Quoted 3 lines
Ah. Right. Yes, that makes sense.
I guess I'll have to redo the patches
_yetagain_.
So when were you going to send the redo? The merge window is now open and Linus was shirty with me about a late merge last time ...
James
Re: [PATCH 2/5] scsi: improved eh timeout handler
Quoted 29 lines · James Bottomley
Quoted 28 lines · Hannes Reinecke
Quoted 27 lines · Mike Christie
Quoted 13 lines · Hannes Reinecke
Quoted 12 lines · Mike Christie
drivers/scsi/scsi_error.c static int scsi_host_eh_past_deadline(struct Scsi_Host *shost) · line 212
Quoted 8 lines · Hannes Reinecke
drivers/scsi/scsi_error.c +8
-0+ + scmd->eh_eflags |=SCSI_EH_ABORT_SCHEDULED ; +SCSI_LOG_ERROR_RECOVERY (3 , +scmd_printk (KERN_INFO , scmd, +"scmd %p abort scheduled\n" , scmd)); +schedule_delayed_work (&scmd->abort_work,HZ /100 ); +return SUCCESS ; +}Do we want to use our own
workqueue_structwithWQ_MEM_RECLAIMset?Quoted 5 lines
Errm. Yes, why?
I must admit I'm not _that_ familiar with workqueues ... Care to explain?
We all share the above
workqueue_structspool of threads, so if we get stuck behind code doingGFP_KERNELallocs that end up needing to write data to the disk we are now trying to aborts on, then we could get stuck. WithWQ_MEM_RECLAIM, we have our own backup thread that gets created atworkqueue_structcreate time which can get used in cases like that so we can always make forward progress.
Quoted 7 lines
Quoted 3 lines
Ah. Right. Yes, that makes sense.
I guess I'll have to redo the patches
_yetagain_.So when were you going to send the redo? The merge window is now open and Linus was shirty with me about a late merge last time ...
Patch is prepared, I'll just have to run a verification on it. Will be sending the updated patchset on Monday.
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
Re: [PATCH 2/5] scsi: improved eh timeout handler
In reply to Mike ChristieQuoted 9 lines · Mike Christie
drivers/scsi/scsi_error.c static int scsi_host_eh_past_deadline(struct Scsi_Host *shost) · line 212
Quoted 7 lines
drivers/scsi/scsi_error.c +7
-0+ scmd->eh_eflags |=SCSI_EH_ABORT_SCHEDULED ; +SCSI_LOG_ERROR_RECOVERY (3 , +scmd_printk (KERN_INFO , scmd, +"scmd %p abort scheduled\n" , scmd)); +schedule_delayed_work (&scmd->abort_work,HZ /100 ); +return SUCCESS ; +}Do we want to use our own
workqueue_structwithWQ_MEM_RECLAIMset?
That's probably required, I can think of all kinds of issues otherwise.
Not in this patch series, but in the near future it might make sense to convert the whole EH thread to that workqueue.
Re: [PATCH 2/5] scsi: improved eh timeout handler
Quoted 11 lines · Christoph Hellwig
Quoted 9 lines · Mike Christie
drivers/scsi/scsi_error.c static int scsi_host_eh_past_deadline(struct Scsi_Host *shost) · line 212
Quoted 7 lines
drivers/scsi/scsi_error.c +7
-0+ scmd->eh_eflags |=SCSI_EH_ABORT_SCHEDULED ; +SCSI_LOG_ERROR_RECOVERY (3 , +scmd_printk (KERN_INFO , scmd, +"scmd %p abort scheduled\n" , scmd)); +schedule_delayed_work (&scmd->abort_work,HZ /100 ); +return SUCCESS ; +}Do we want to use our own
workqueue_structwithWQ_MEM_RECLAIMset?
Quoted 5 lines
That's probably required, I can think of all kinds of issues otherwise.
Not in this patch series, but in the near future it might make sense to convert the whole EH thread to that workqueue.
And given the recent issues we had with RT scheduling I guess this is the way to go.
_After_ this patchset gets in, that is ...
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
PATCH v10 3/5 scsi: Unlock accesses to eh_deadline
In reply to Hannes Reinecke32bit accesses are guaranteed to be atomic, so we can remove the spinlock when checking for eh_deadline. We only need to make sure to catch any updates which might happened during the call to time_before(); if so we just recheck with the correct value.
--- drivers/scsi/scsi_error.c | 44 +++++++++----------------------------------- 1 file changed, 9 insertions(+), 35 deletions(-)
drivers/scsi/scsi_error.c +9 -35
@@ -94,8 +94,15 @@ static int scsi_host_eh_past_deadline(struct Scsi_Host *shost)if (!shost->last_reset || !shost->eh_deadline)return 0 ; -if (time_before (jiffies, - shost->last_reset + shost->eh_deadline)) +/* +* 32bit accesses are guaranteed to be atomic +* (on all supported architectures), so instead +* of using a spinlock we can as well double check +* if eh_deadline has been unset during the +* time_before call. +*/ +if (time_before (jiffies, shost->last_reset + shost->eh_deadline) && + shost->eh_deadline !=0 )return 0 ;return 1 ;
@@ -111,18 +118,14 @@ scmd_eh_abort_handler(struct work_struct *work)struct scsi_cmnd *scmd = container_of(work, struct scsi_cmnd, abort_work.work);struct scsi_device *sdev = scmd->device; -unsigned long flags;int rtn; -spin_lock_irqsave (sdev->host->host_lock, flags);if (scsi_host_eh_past_deadline (sdev->host)) { -spin_unlock_irqrestore (sdev->host->host_lock, flags);SCSI_LOG_ERROR_RECOVERY (3 ,scmd_printk (KERN_INFO , scmd,"scmd %p eh timeout, not aborting\n" , scmd)); }else { -spin_unlock_irqrestore (sdev->host->host_lock, flags);SCSI_LOG_ERROR_RECOVERY (3 ,scmd_printk (KERN_INFO , scmd,"aborting command %p\n" , scmd));
@@ -1132,7 +1135,6 @@ int scsi_eh_get_sense(struct list_head *work_q,struct scsi_cmnd *scmd, *next;struct Scsi_Host *shost;int rtn; -unsigned long flags;list_for_each_entry_safe (scmd, next, work_q, eh_entry) { if ((scmd->eh_eflags & SCSI_EH_CANCEL_CMD) ||
@@ -1140,16 +1142,13 @@ int scsi_eh_get_sense(struct list_head *work_q,continue ; shost = scmd->device->host; -spin_lock_irqsave (shost->host_lock, flags);if (scsi_host_eh_past_deadline (shost)) { -spin_unlock_irqrestore (shost->host_lock, flags);SCSI_LOG_ERROR_RECOVERY (3 ,shost_printk (KERN_INFO , shost,"skip %s, past eh deadline\n" , __func__));break ; } -spin_unlock_irqrestore (shost->host_lock, flags);SCSI_LOG_ERROR_RECOVERY (2 ,scmd_printk (KERN_INFO , scmd,"%s: requesting sense\n" , current->comm));
@@ -1235,26 +1234,21 @@ static int scsi_eh_test_devices(struct list_head *cmd_list,struct scsi_cmnd *scmd, *next;struct scsi_device *sdev;int finish_cmds; -unsigned long flags;while (!list_empty (cmd_list)) { scmd = list_entry(cmd_list->next, struct scsi_cmnd, eh_entry); sdev = scmd->device;if (!try_stu) { -spin_lock_irqsave (sdev->host->host_lock, flags);if (scsi_host_eh_past_deadline (sdev->host)) {/* Push items back onto work_q */ list_splice_init (cmd_list, work_q); -spin_unlock_irqrestore (sdev->host->host_lock, - flags);SCSI_LOG_ERROR_RECOVERY (3 ,shost_printk (KERN_INFO , sdev->host,"skip %s, past eh deadline" , __func__));break ; } -spin_unlock_irqrestore (sdev->host->host_lock, flags); } finish_cmds = !scsi_device_online(scmd->device) ||
@@ -1295,15 +1289,12 @@ static int scsi_eh_abort_cmds(struct list_head *work_q,LIST_HEAD (check_list);int rtn;struct Scsi_Host *shost; -unsigned long flags;list_for_each_entry_safe (scmd, next, work_q, eh_entry) {if (!(scmd->eh_eflags &SCSI_EH_CANCEL_CMD ))continue ; shost = scmd->device->host; -spin_lock_irqsave (shost->host_lock, flags);if (scsi_host_eh_past_deadline (shost)) { -spin_unlock_irqrestore (shost->host_lock, flags);list_splice_init (&check_list, work_q); SCSI_LOG_ERROR_RECOVERY(3, shost_printk(KERN_INFO, shost,
@@ -1311,7 +1302,6 @@ static int scsi_eh_abort_cmds(struct list_head *work_q, __func__));return list_empty (work_q); } -spin_unlock_irqrestore (shost->host_lock, flags);SCSI_LOG_ERROR_RECOVERY (3 ,printk ("%s: aborting cmd:" "0x%p\n" , current->comm, scmd));
@@ -1375,19 +1365,15 @@ static int scsi_eh_stu(struct Scsi_Host *shost, {struct scsi_cmnd *scmd, *stu_scmd, *next;struct scsi_device *sdev; -unsigned long flags;shost_for_each_device (sdev, shost) { -spin_lock_irqsave (shost->host_lock, flags);if (scsi_host_eh_past_deadline (shost)) { -spin_unlock_irqrestore (shost->host_lock, flags);SCSI_LOG_ERROR_RECOVERY (3 ,shost_printk (KERN_INFO , shost,"skip %s, past eh deadline\n" , __func__));break ; } -spin_unlock_irqrestore (shost->host_lock, flags); stu_scmd =NULL ;list_for_each_entry (scmd, work_q, eh_entry) if (scmd->device == sdev && SCSI_SENSE_VALID(scmd) &&
@@ -1441,20 +1427,16 @@ static int scsi_eh_bus_device_reset(struct Scsi_Host *shost, {struct scsi_cmnd *scmd, *bdr_scmd, *next;struct scsi_device *sdev; -unsigned long flags;int rtn;shost_for_each_device (sdev, shost) { -spin_lock_irqsave (shost->host_lock, flags);if (scsi_host_eh_past_deadline (shost)) { -spin_unlock_irqrestore (shost->host_lock, flags);SCSI_LOG_ERROR_RECOVERY (3 ,shost_printk (KERN_INFO , shost,"skip %s, past eh deadline\n" , __func__));break ; } -spin_unlock_irqrestore (shost->host_lock, flags); bdr_scmd =NULL ;list_for_each_entry (scmd, work_q, eh_entry)if (scmd->device == sdev) {
@@ -1515,11 +1497,8 @@ static int scsi_eh_target_reset(struct Scsi_Host *shost,struct scsi_cmnd *next, *scmd;int rtn;unsigned int id; -unsigned long flags; -spin_lock_irqsave (shost->host_lock, flags);if (scsi_host_eh_past_deadline (shost)) { -spin_unlock_irqrestore (shost->host_lock, flags);/* push back on work queue for further processing */ list_splice_init (&check_list, work_q);list_splice_init (&tmp_list, work_q);
@@ -1529,7 +1508,6 @@ static int scsi_eh_target_reset(struct Scsi_Host *shost, __func__));return list_empty (work_q); } -spin_unlock_irqrestore (shost->host_lock, flags); scmd = list_entry(tmp_list.next, struct scsi_cmnd, eh_entry); id =scmd_id (scmd);
@@ -1574,7 +1552,6 @@ static int scsi_eh_bus_reset(struct Scsi_Host *shost,LIST_HEAD (check_list);unsigned int channel;int rtn; -unsigned long flags;/* * we really want to loop over the various channels, and do this on
@@ -1584,9 +1561,7 @@ static int scsi_eh_bus_reset(struct Scsi_Host *shost,*/ for (channel =0 ; channel <= shost->max_channel; channel++) { -spin_lock_irqsave (shost->host_lock, flags);if (scsi_host_eh_past_deadline (shost)) { -spin_unlock_irqrestore (shost->host_lock, flags);list_splice_init (&check_list, work_q); SCSI_LOG_ERROR_RECOVERY(3, shost_printk(KERN_INFO, shost,
@@ -1594,7 +1569,6 @@ static int scsi_eh_bus_reset(struct Scsi_Host *shost, __func__));return list_empty (work_q); } -spin_unlock_irqrestore (shost->host_lock, flags); chan_scmd =NULL ;list_for_each_entry (scmd, work_q, eh_entry) {
Signature · 1 line
1.7.12.4
PATCH v10 4/5 scsi: Set the minimum valid value of 'eh_deadline' as 0
In reply to Hannes ReineckeFrom: Ren Mingxin <[email protected]>
The former minimum valid value of 'eh_deadline' is 1s, which means the earliest occasion to shorten EH is 1 second later since a command is failed or timed out. But if we want to skip EH steps ASAP, we have to wait until the first EH step is finished. If the duration of the first EH step is long, this waiting time is excruciating. So, it is necessary to accept 0 as the minimum valid value for 'eh_deadline'.
According to my test, with Hannes' patchset 'New EH command timeout handler' as well, the minimum IO time is improved from 73s (eh_deadline = 1) to 43s(eh_deadline = 0) when commands are timed out by disabling RSCN and target port.
--- drivers/scsi/hosts.c | 16 ++++++++++++---- drivers/scsi/scsi_error.c | 34 +++++++++++++++++++++------------- drivers/scsi/scsi_sysfs.c | 36 +++++++++++++++++++++++++----------- 3 files changed, 58 insertions(+), 28 deletions(-)
drivers/scsi/hosts.c +12 -4
@@ -316,11 +316,11 @@ static void scsi_host_dev_release(struct device *dev)kfree (shost); } -static unsigned int shost_eh_deadline; +static int shost_eh_deadline =-1 ; -module_param_named (eh_deadline, shost_eh_deadline, uint,S_IRUGO |S_IWUSR ); +module_param_named (eh_deadline, shost_eh_deadline, int,S_IRUGO |S_IWUSR );MODULE_PARM_DESC (eh_deadline, -"SCSI EH timeout in seconds (should be between 1 and 2^32-1)" ); +"SCSI EH timeout in seconds (should be between 0 and 2^31-1)" );static struct device_type scsi_host_type = { .name ="scsi_host" ,
@@ -394,7 +394,15 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) shost->unchecked_isa_dma = sht->unchecked_isa_dma; shost->use_clustering = sht->use_clustering; shost->ordered_tag = sht->ordered_tag; - shost->eh_deadline = shost_eh_deadline *HZ ; +if (shost_eh_deadline ==-1 ) + shost->eh_deadline =-1 ; +else if ((ulong ) shost_eh_deadline *HZ >INT_MAX ) { +shost_printk (KERN_WARNING , shost, +"eh_deadline %u too large, setting to %u\n" , + shost_eh_deadline,INT_MAX /HZ ); + shost->eh_deadline =INT_MAX ; + }else + shost->eh_deadline = shost_eh_deadline *HZ ;if (sht->supported_mode ==MODE_UNKNOWN )/* means we didn't set it ... default to INITIATOR */
drivers/scsi/scsi_error.c +21 -13
@@ -91,18 +91,18 @@ EXPORT_SYMBOL_GPL(scsi_schedule_eh);static int scsi_host_eh_past_deadline (struct Scsi_Host *shost) { -if (!shost->last_reset || !shost->eh_deadline) +if (!shost->last_reset || shost->eh_deadline ==-1 )return 0 ;/* * 32bit accesses are guaranteed to be atomic * (on all supported architectures), so instead * of using a spinlock we can as well double check -* if eh_deadline has been unset during the +* if eh_deadline has been set to 'off' during the * time_before call. */ if (time_before (jiffies, shost->last_reset + shost->eh_deadline) && - shost->eh_deadline !=0 ) + shost->eh_deadline >-1 )return 0 ;return 1 ;
@@ -132,26 +132,34 @@ scmd_eh_abort_handler(struct work_struct *work) rtn =scsi_try_to_abort_cmd (sdev->host->hostt, scmd);if (rtn ==SUCCESS ) { scmd->result |=DID_TIME_OUT <<16 ; -if (!scsi_noretry_cmd (scmd) && +if (scsi_host_eh_past_deadline (sdev->host)) { +SCSI_LOG_ERROR_RECOVERY (3 , +scmd_printk (KERN_INFO , scmd, +"scmd %p eh timeout, " +"not retrying aborted " +"command\n" , scmd)); + }else if (!scsi_noretry_cmd (scmd) && (++scmd->retries <= scmd->allowed)) {SCSI_LOG_ERROR_RECOVERY (3 ,scmd_printk (KERN_WARNING , scmd,"scmd %p retry " "aborted command\n" , scmd));scsi_queue_insert (scmd,SCSI_MLQUEUE_EH_RETRY ); +return ; }else {SCSI_LOG_ERROR_RECOVERY (3 ,scmd_printk (KERN_WARNING , scmd,"scmd %p finish " "aborted command\n" , scmd));scsi_finish_command (scmd); +return ; } -return ; + }else { +SCSI_LOG_ERROR_RECOVERY (3 , +scmd_printk (KERN_INFO , scmd, +"scmd %p abort failed, rtn %d\n" , + scmd, rtn)); } -SCSI_LOG_ERROR_RECOVERY (3 , -scmd_printk (KERN_INFO , scmd, -"scmd %p abort failed, rtn %d\n" , - scmd, rtn)); }if (!scsi_eh_scmd_add (scmd,0 )) {
@@ -202,7 +210,7 @@ scsi_abort_command(struct scsi_cmnd *scmd)return FAILED ; } -if (shost->eh_deadline && !shost->last_reset) +if (shost->eh_deadline !=-1 && !shost->last_reset) shost->last_reset = jiffies;spin_unlock_irqrestore (shost->host_lock, flags);
@@ -236,7 +244,7 @@ int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag)if (scsi_host_set_state (shost,SHOST_CANCEL_RECOVERY )) goto out_unlock; -if (shost->eh_deadline && !shost->last_reset) +if (shost->eh_deadline !=-1 && !shost->last_reset) shost->last_reset = jiffies; ret =1 ;
@@ -270,7 +278,7 @@ enum blk_eh_timer_return scsi_times_out(struct request *req)trace_scsi_dispatch_cmd_timeout (scmd);scsi_log_completion (scmd,TIMEOUT_ERROR ); -if (host->eh_deadline && !host->last_reset) +if (host->eh_deadline !=-1 && !host->last_reset) host->last_reset = jiffies;if (host->transportt->eh_timed_out)
@@ -2106,7 +2114,7 @@ static void scsi_unjam_host(struct Scsi_Host *shost)scsi_eh_ready_devs (shost, &eh_work_q, &eh_done_q);spin_lock_irqsave (shost->host_lock, flags); -if (shost->eh_deadline) +if (shost->eh_deadline !=-1 ) shost->last_reset =0 ;spin_unlock_irqrestore (shost->host_lock, flags);scsi_eh_flush_done_q (&eh_done_q);
drivers/scsi/scsi_sysfs.c +25 -11
@@ -287,7 +287,9 @@ show_shost_eh_deadline(struct device *dev, {struct Scsi_Host *shost =class_to_shost (dev); -return sprintf (buf,"%d\n" , shost->eh_deadline /HZ ); +if (shost->eh_deadline ==-1 ) +return snprintf (buf,strlen ("off" ) +2 ,"off\n" ); +return sprintf (buf,"%u\n" , shost->eh_deadline /HZ ); } static ssize_t
@@ -296,22 +298,34 @@ store_shost_eh_deadline(struct device *dev, struct device_attribute *attr, {struct Scsi_Host *shost =class_to_shost (dev);int ret = -EINVAL ; -int deadline; -unsigned long flags; +unsigned long deadline, flags;if (shost->transportt && shost->transportt->eh_strategy_handler)return ret; -if (sscanf (buf,"%d\n" , &deadline) ==1 ) { -spin_lock_irqsave (shost->host_lock, flags); -if (scsi_host_in_recovery (shost)) - ret = -EBUSY ; -else { +if (!strncmp (buf,"off" ,strlen ("off" ))) + deadline =-1 ; +else { + ret =kstrtoul (buf,10 , &deadline); +if (ret) +return ret; +if (deadline *HZ >UINT_MAX ) +return -EINVAL ; + } + +spin_lock_irqsave (shost->host_lock, flags); +if (scsi_host_in_recovery (shost)) + ret = -EBUSY ; +else { +if (deadline ==-1 ) + shost->eh_deadline =-1 ; +else shost->eh_deadline = deadline *HZ ; - ret = count; - } -spin_unlock_irqrestore (shost->host_lock, flags); + + ret = count; } +spin_unlock_irqrestore (shost->host_lock, flags); +return ret; }
Signature · 1 line
1.7.12.4
PATCH v10 5/5 scsi: Update documentation
In reply to Hannes ReineckeThe documentation has gone out-of-sync, so update it to the current status.
--- Documentation/scsi/scsi_eh.txt | 69 +++++++++++++++++++-------------- Documentation/scsi/scsi_mid_low_api.txt | 9 ++++- drivers/scsi/scsi.c | 6 +-- 3 files changed, 48 insertions(+), 36 deletions(-)
Documentation/scsi/scsi_eh.txt +39 -30
@@ -42,20 +42,14 @@ discussion. Once LLDD gets hold of a scmd, either the LLDD will complete the command by calling scsi_done callback passed from midlayer when -invoking hostt->queuecommand() or SCSI midlayer will time it out. +invoking hostt->queuecommand() or the block layer will time it out. [1-2-1] Completing a scmd w/ scsi_done For all non-EH commands, scsi_done() is the completion callback. It -does the following. - - 1. Delete timeout timer. If it fails, it means that timeout timer - has expired and is going to finish the command. Just return. - - 2. Link scmd to per-cpu scsi_done_q using scmd->en_entry - - 3. Raise SCSI_SOFTIRQ +just calls blk_complete_request() to delete the block layer timer and +raise SCSI_SOFTIRQ SCSI_SOFTIRQ handler scsi_softirq calls scsi_decide_disposition() to determine what to do with the command. scsi_decide_disposition()
@@ -64,10 +58,12 @@ with the command. - SUCCESS scsi_finish_command() is invoked for the command. The - function does some maintenance choirs and notify completion by - calling scmd->done() callback, which, for fs requests, would - be HLD completion callback - sd:sd_rw_intr, sr:rw_intr, - st:st_intr. + function does some maintenance chores and then calls + scsi_io_completion() to finish the I/O. + scsi_io_completion() then notifies the block layer on + the completed request by calling blk_end_request and + friends or figures out what to do with the remainder + of the data in case of an error. - NEEDS_RETRY - ADD_TO_MLQUEUE
@@ -86,33 +82,45 @@ function 1. invokes optional hostt->eh_timed_out() callback. Return value can be one of - - EH_HANDLED - This indicates that eh_timed_out() dealt with the timeout. The - scmd is passed to __scsi_done() and thus linked into per-cpu - scsi_done_q. Normal command completion described in [1-2-1] - follows. + - BLK_EH_HANDLED + This indicates that eh_timed_out() dealt with the timeout. + The command is passed back to the block layer and completed + via __blk_complete_requests(). + + *NOTE* After returning BLK_EH_HANDLED the SCSI layer is + assumed to be finished with the command, and no other + functions from the SCSI layer will be called. So this + should typically only be returned if the eh_timed_out() + handler raced with normal completion. - - EH_RESET_TIMER + - BLK_EH_RESET_TIMER This indicates that more time is required to finish the command. Timer is restarted. This action is counted as a retry and only allowed scmd->allowed + 1(!) times. Once the - limit is reached, action for EH_NOT_HANDLED is taken instead. + limit is reached, action for BLK_EH_NOT_HANDLED is taken instead. - *NOTE* This action is racy as the LLDD could finish the scmd - after the timeout has expired but before it's added back. In - such cases, scsi_done() would think that timeout has occurred - and return without doing anything. We lose completion and the - command will time out again. - - - EH_NOT_HANDLED - This is the same as when eh_timed_out() callback doesn't exist. + - BLK_EH_NOT_HANDLED + eh_timed_out() callback did not handle the command. Step #2 is taken. + 2. If the host supports asynchronous completion (as indicated by the + no_async_abort setting in the host template) scsi_abort_command() + is invoked to schedule an asynchrous abort. If that fails + Step #3 is taken. + 2. scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD) is invoked for the command. See [1-3] for more information. +[1-3] Asynchronous command aborts + + After a timeout occurs a command abort is scheduled from + scsi_abort_command(). If the abort is successful the command + will either be retried (if the number of retries is not exhausted) + or terminated with DID_TIME_OUT. + Otherwise scsi_eh_scmd_add() is invoked for the command. + See [1-4] for more information. -[1-3] How EH takes over +[1-4] How EH takes over scmds enter EH via scsi_eh_scmd_add(), which does the following.
@@ -320,7 +328,8 @@ scmd->allowed. <<scsi_eh_abort_cmds>> - This action is taken for each timed out command. + This action is taken for each timed out command when + no_async_abort is enabled in the host template. hostt->eh_abort_handler() is invoked for each scmd. The handler returns SUCCESS if it has succeeded to make LLDD and all related hardware forget about the scmd.
Documentation/scsi/scsi_mid_low_api.txt +7 -2
@@ -882,8 +882,11 @@ Details: * * Calling context: kernel thread * - * Notes: Invoked from scsi_eh thread. No other commands will be - * queued on current host during eh. + * Notes: If 'no_async_abort' is defined this callback + * will be invoked from scsi_eh thread. No other commands + * will then be queued on current host during eh. + * Otherwise it will be called whenever scsi_times_out() + * is called due to a command timeout. * * Optionally defined in: LLD **/
@@ -1257,6 +1260,8 @@ of interest: address space use_clustering - 1=>SCSI commands in mid level's queue can be merged, 0=>disallow SCSI command merging + no_async_abort - 1=>Asynchronous aborts are not supported + 0=>Timed-out commands will be aborted asynchronously hostt - pointer to driver's struct scsi_host_template from which this struct Scsi_Host instance was spawned hostt->proc_name - name of LLD. This is the driver name that sysfs uses
drivers/scsi/scsi.c +2 -4
@@ -745,15 +745,13 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd) }/** -* scsi_done - Enqueue the finished SCSI command into the done queue. +* scsi_done - Invoke completion on finished SCSI command. * @cmd: The SCSI Command for which a low-level device driver (LLDD) gives * ownership back to SCSI Core -- i.e. the LLDD has finished with it. * * Description: This function is the mid-level's (SCSI Core) interrupt routine, * which regains ownership of the SCSI command (de facto) from a LLDD, and -* enqueues the command to the done queue for further processing. -* -* This is the producer of the done queue who enqueues at the tail. +* calls blk_complete_request() for further processing. * * This function is interrupt context safe. */
Signature · 1 line
1.7.12.4