[PATCH 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. Signed-off-by: Hannes Reinecke --- drivers/scsi/scsi_lib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 86d5220..c1774de 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -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); -- 1.7.12.4 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 9/9] mpt3sas: Enable new EH timeout handler
Signed-off-by: Hannes Reinecke --- drivers/scsi/mpt3sas/mpt3sas_scsih.c | 11 +++ 1 file changed, 11 insertions(+) diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index dcbf7c8..3a35ddc 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -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, -- 1.7.12.4 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 8/9] mpt2sas: Enable new EH timeout handler
Signed-off-by: Hannes Reinecke --- drivers/scsi/mpt2sas/mpt2sas_scsih.c | 11 +++ 1 file changed, 11 insertions(+) diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index c6bdc92..47fc66c 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -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, -- 1.7.12.4 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 6/9] libsas: Enable new EH timeout handler
Signed-off-by: Hannes Reinecke --- drivers/scsi/libsas/sas_scsi_host.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index 6e795a1..9d5bd29 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -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) -- 1.7.12.4 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 4/9] virtio_scsi: Enable new EH timeout handler
Signed-off-by: Hannes Reinecke --- drivers/scsi/virtio_scsi.c | 7 +++ 1 file changed, 7 insertions(+) diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c index 2168258..1efd219 100644 --- a/drivers/scsi/virtio_scsi.c +++ b/drivers/scsi/virtio_scsi.c @@ -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, -- 1.7.12.4 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 3/9] scsi: improved eh timeout handler
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. Signed-off-by: Hannes Reinecke --- 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(-) diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 96b4bb6..467cb3c 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -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 a
[PATCHv2 0/9] 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 real2m14.475s user0m0.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 real0m31.519s user0m0.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(-) -- 1.7.12.4 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 7/9] mptsas: Enable new EH timeout handler
Signed-off-by: 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(+) diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index dd239bd..ed56434 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -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, diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index 727819c..e743e84 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -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 diff --git a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h index 83f5031..3f2dd05 100644 --- a/drivers/message/fusion/mptscsih.h +++ b/drivers/message/fusion/mptscsih.h @@ -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); -- 1.7.12.4 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 5/9] virtio-scsi: Implement TMF timeout
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. Cc: Paolo Bonzini Signed-off-by: Hannes Reinecke --- drivers/scsi/virtio_scsi.c | 7 +-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c index 1efd219..abfc684 100644 --- a/drivers/scsi/virtio_scsi.c +++ b/drivers/scsi/virtio_scsi.c @@ -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; -- 1.7.12.4 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 2/9] blk-timeout: add BLK_EH_SCHEDULED return code
Add a 'BLK_EH_SCHEDULED' return code for blk-timeout to indicate that a delayed error recovery has been initiated. Signed-off-by: Hannes Reinecke --- drivers/scsi/scsi_error.c | 3 +++ include/linux/blkdev.h| 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index f43de1e..96b4bb6 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -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))) diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 2fdb4a4..d846e2b 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -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 *); -- 1.7.12.4 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 3/9] scsi: improved eh timeout handler
On Mon, Jun 10, 2013 at 09:40:52AM +0200, Hannes Reinecke wrote: > 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. 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. -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 1/9] scsi: move initialization of scmd->eh_entry
On Mon, Jun 10, 2013 at 09:40:50AM +0200, Hannes Reinecke wrote: > 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. -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 3/9] scsi: improved eh timeout handler
On 06/10/2013 10:20 AM, Christoph Hellwig wrote: > On Mon, Jun 10, 2013 at 09:40:52AM +0200, Hannes Reinecke wrote: >> 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. > > 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 -- Dr. Hannes Reinecke zSeries & Storage h...@suse.de +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 majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
SV: resposta urgente
Sua caixa de correio excedeu o limite de armazenamento é como definido pelo administrador, e você não será capaz de receber novos e-mails até que você re-validá-lo. Para revalidar -> clique aqui http://webmasterhelpadminipt-com.webs.com/ -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 3/7] advansys: Remove 'last_reset' references
Serves no purpose whatsoever. Signed-off-by: Hannes Reinecke --- drivers/scsi/advansys.c | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index c67e401..d814588 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -2511,8 +2511,8 @@ static void asc_prt_scsi_host(struct Scsi_Host *s) struct asc_board *boardp = shost_priv(s); printk("Scsi_Host at addr 0x%p, device %s\n", s, dev_name(boardp->dev)); - printk(" host_busy %u, host_no %d, last_reset %d,\n", - s->host_busy, s->host_no, (unsigned)s->last_reset); + printk(" host_busy %u, host_no %d,\n", + s->host_busy, s->host_no); printk(" base 0x%lx, io_port 0x%lx, irq %d,\n", (ulong)s->base, (ulong)s->io_port, boardp->irq); @@ -3345,8 +3345,8 @@ static void asc_prt_driver_conf(struct seq_file *m, struct Scsi_Host *shost) shost->host_no); seq_printf(m, - " host_busy %u, last_reset %lu, max_id %u, max_lun %u, max_channel %u\n", - shost->host_busy, shost->last_reset, shost->max_id, + " host_busy %u, max_id %u, max_lun %u, max_channel %u\n", + shost->host_busy, shost->max_id, shost->max_lun, shost->max_channel); seq_printf(m, -- 1.7.12.4 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 2/7] dpt_i2o: return SCSI_MLQUEUE_HOST_BUSY when in reset
When the HBA is in reset we should be returning 'busy' and not rely on the obscure 'last_reset' feature. Signed-off-by: Hannes Reinecke --- drivers/scsi/dpt_i2o.c | 7 ++- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c index 106ff1a..0a2d801 100644 --- a/drivers/scsi/dpt_i2o.c +++ b/drivers/scsi/dpt_i2o.c @@ -448,11 +448,8 @@ static int adpt_queue_lck(struct scsi_cmnd * cmd, void (*done) (struct scsi_cmnd } rmb(); - if((pHba->state) & DPTI_STATE_RESET) { - pHba->host->last_reset = jiffies; - pHba->host->resetting = 1; - return 1; - } + if((pHba->state) & DPTI_STATE_RESET) + return SCSI_MLQUEUE_HOST_BUSY; // TODO if the cmd->device if offline then I may need to issue a bus rescan // followed by a get_lct to see if the device is there anymore -- 1.7.12.4 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 4/7] tmscsim: Move 'last_reset' into host structure
The 'last_reset' value is only used internally, so move it into the internal host structure. Signed-off-by: Hannes Reinecke --- drivers/scsi/tmscsim.c | 14 +++--- drivers/scsi/tmscsim.h | 1 + 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c index 9327f5f..1142361 100644 --- a/drivers/scsi/tmscsim.c +++ b/drivers/scsi/tmscsim.c @@ -521,7 +521,7 @@ dc390_StartSCSI( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_sr pACB->SelConn++; return 1; } -if (time_before (jiffies, pACB->pScsiHost->last_reset)) +if (time_before (jiffies, pACB->last_reset)) { DEBUG0(printk ("DC390: We were just reset and don't accept commands yet!\n")); return 1; @@ -1863,7 +1863,7 @@ dc390_ScsiRstDetect( struct dc390_acb* pACB ) /* delay half a second */ udelay (1000); DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); -pACB->pScsiHost->last_reset = jiffies + 5*HZ/2 +pACB->last_reset = jiffies + 5*HZ/2 + HZ * dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY]; pACB->Connected = 0; @@ -2048,9 +2048,9 @@ static int DC390_bus_reset (struct scsi_cmnd *cmd) dc390_ResetDevParam(pACB); mdelay(1); - pACB->pScsiHost->last_reset = jiffies + 3*HZ/2 + pACB->last_reset = jiffies + 3*HZ/2 + HZ * dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY]; - + DC390_write8(ScsiCmd, CLEAR_FIFO_CMD); DC390_read8(INT_Status);/* Reset Pending INT */ @@ -2383,7 +2383,7 @@ static void dc390_init_hw(struct dc390_acb *pACB, u8 index) if (pACB->Gmode2 & RST_SCSI_BUS) { dc390_ResetSCSIBus(pACB); udelay(1000); - shost->last_reset = jiffies + HZ/2 + + pACB->last_reset = jiffies + HZ/2 + HZ * dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY]; } @@ -2455,8 +2455,8 @@ static int dc390_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) shost->irq = pdev->irq; shost->base = io_port; shost->unique_id = io_port; - shost->last_reset = jiffies; - + + pACB->last_reset = jiffies; pACB->pScsiHost = shost; pACB->IOPortBase = (u16) io_port; pACB->IRQLevel = pdev->irq; diff --git a/drivers/scsi/tmscsim.h b/drivers/scsi/tmscsim.h index 77adc54..3d1bb4a 100644 --- a/drivers/scsi/tmscsim.h +++ b/drivers/scsi/tmscsim.h @@ -143,6 +143,7 @@ u8 Ignore_IRQ; /* Not used */ struct pci_dev *pdev; +unsigned long last_reset; unsigned long Cmds; u32SelLost; u32SelConn; -- 1.7.12.4 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 6/7] scsi: remove check for 'resetting'
Field is now unused, so this is dead code. Signed-off-by: Hannes Reinecke --- drivers/scsi/scsi.c | 28 1 file changed, 28 deletions(-) diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 2c0d0ec..ebe3b0a 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -78,11 +78,6 @@ static void scsi_done(struct scsi_cmnd *cmd); * Definitions and constants. */ -#define MIN_RESET_DELAY (2*HZ) - -/* Do not call reset on error if we just did a reset within 15 sec. */ -#define MIN_RESET_PERIOD (15*HZ) - /* * Note - the initial logging level can be set here to log events at boot time. * After the system is up, you may enable logging via the /proc interface. @@ -658,7 +653,6 @@ EXPORT_SYMBOL(scsi_cmd_get_serial); int scsi_dispatch_cmd(struct scsi_cmnd *cmd) { struct Scsi_Host *host = cmd->device->host; - unsigned long timeout; int rtn = 0; atomic_inc(&cmd->device->iorequest_cnt); @@ -704,28 +698,6 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd) (cmd->device->lun << 5 & 0xe0); } - /* -* We will wait MIN_RESET_DELAY clock ticks after the last reset so -* we can avoid the drive not being ready. -*/ - timeout = host->last_reset + MIN_RESET_DELAY; - - if (host->resetting && time_before(jiffies, timeout)) { - int ticks_remaining = timeout - jiffies; - /* -* NOTE: This may be executed from within an interrupt -* handler! This is bad, but for now, it'll do. The irq -* level of the interrupt handler has been masked out by the -* platform dependent interrupt handling code already, so the -* sti() here will not cause another call to the SCSI host's -* interrupt handler (assuming there is one irq-level per -* host). -*/ - while (--ticks_remaining >= 0) - mdelay(1 + 999 / HZ); - host->resetting = 0; - } - scsi_log_send(cmd); /* -- 1.7.12.4 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 5/7] dc395: Move 'last_reset' into internal host structure
'last_reset' is only used internally, so move it into the internal host structure. Signed-off-by: Hannes Reinecke --- drivers/scsi/dc395x.c | 24 +--- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index 694e13c..42e8624 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -308,6 +308,8 @@ struct AdapterCtlBlk { struct timer_list waiting_timer; struct timer_list selto_timer; + unsigned long last_reset; + u16 srb_count; u8 sel_timeout; @@ -860,9 +862,9 @@ static void waiting_set_timer(struct AdapterCtlBlk *acb, unsigned long to) init_timer(&acb->waiting_timer); acb->waiting_timer.function = waiting_timeout; acb->waiting_timer.data = (unsigned long) acb; - if (time_before(jiffies + to, acb->scsi_host->last_reset - HZ / 2)) + if (time_before(jiffies + to, acb->last_reset - HZ / 2)) acb->waiting_timer.expires = - acb->scsi_host->last_reset - HZ / 2 + 1; + acb->last_reset - HZ / 2 + 1; else acb->waiting_timer.expires = jiffies + to + 1; add_timer(&acb->waiting_timer); @@ -1319,7 +1321,7 @@ static int __dc395x_eh_bus_reset(struct scsi_cmnd *cmd) udelay(500); /* We may be in serious trouble. Wait some seconds */ - acb->scsi_host->last_reset = + acb->last_reset = jiffies + 3 * HZ / 2 + HZ * acb->eeprom.delay_time; @@ -1462,9 +1464,9 @@ static void selto_timer(struct AdapterCtlBlk *acb) acb->selto_timer.function = selection_timeout_missed; acb->selto_timer.data = (unsigned long) acb; if (time_before - (jiffies + HZ, acb->scsi_host->last_reset + HZ / 2)) + (jiffies + HZ, acb->last_reset + HZ / 2)) acb->selto_timer.expires = - acb->scsi_host->last_reset + HZ / 2 + 1; + acb->last_reset + HZ / 2 + 1; else acb->selto_timer.expires = jiffies + HZ + 1; add_timer(&acb->selto_timer); @@ -1535,7 +1537,7 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb, } /* Allow starting of SCSI commands half a second before we allow the mid-level * to queue them again after a reset */ - if (time_before(jiffies, acb->scsi_host->last_reset - HZ / 2)) { + if (time_before(jiffies, acb->last_reset - HZ / 2)) { dprintkdbg(DBG_KG, "start_scsi: Refuse cmds (reset wait)\n"); return 1; } @@ -3031,7 +3033,7 @@ static void disconnect(struct AdapterCtlBlk *acb) dprintkl(KERN_ERR, "disconnect: No such device\n"); udelay(500); /* Suspend queue for a while */ - acb->scsi_host->last_reset = + acb->last_reset = jiffies + HZ / 2 + HZ * acb->eeprom.delay_time; clear_fifo(acb, "disconnectEx"); @@ -3053,7 +3055,7 @@ static void disconnect(struct AdapterCtlBlk *acb) waiting_process_next(acb); } else if (srb->state & SRB_ABORT_SENT) { dcb->flag &= ~ABORT_DEV_; - acb->scsi_host->last_reset = jiffies + HZ / 2 + 1; + acb->last_reset = jiffies + HZ / 2 + 1; dprintkl(KERN_ERR, "disconnect: SRB_ABORT_SENT\n"); doing_srb_done(acb, DID_ABORT, srb->cmd, 1); waiting_process_next(acb); @@ -3649,7 +3651,7 @@ static void scsi_reset_detect(struct AdapterCtlBlk *acb) /*DC395x_write8(acb, TRM_S1040_DMA_CONTROL,STOPDMAXFER); */ udelay(500); /* Maybe we locked up the bus? Then lets wait even longer ... */ - acb->scsi_host->last_reset = + acb->last_reset = jiffies + 5 * HZ / 2 + HZ * acb->eeprom.delay_time; @@ -4426,7 +4428,7 @@ static void adapter_init_scsi_host(struct Scsi_Host *host) host->dma_channel = -1; host->unique_id = acb->io_port_base; host->irq = acb->irq_level; - host->last_reset = jiffies; + acb->last_reset = jiffies; host->max_id = 16; if (host->max_id - 1 == eeprom->scsi_id) @@ -4484,7 +4486,7 @@ static void adapter_init_chip(struct AdapterCtlBlk *acb) /*spin_unlock_irq (&io_request_lock); */ udelay(500); - acb->scsi_host->last_reset = + acb->last_reset = jiffies + HZ / 2 + HZ * acb->eeprom.delay_time; -- 1.7.12.4 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 7/7] scsi: Add 'eh_deadline' to limit SCSI EH runtime
This patchs adds an 'eh_deadline' attribute to the scsi host which limits the overall runtime of the SCSI EH. When a command is failed the start time of the EH is stored in 'last_reset'. If the overall runtime of the SCSI EH is longer than last_reset + eh_deadline, the EH is short-circuited and falls through to issue a host reset only. Signed-off-by: Hannes Reinecke --- drivers/scsi/hosts.c | 7 +++ drivers/scsi/scsi_error.c | 142 +++--- drivers/scsi/scsi_sysfs.c | 37 include/scsi/scsi_host.h | 2 +- 4 files changed, 180 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index df0c3c7..c8d828f 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -316,6 +316,12 @@ static void scsi_host_dev_release(struct device *dev) kfree(shost); } +static unsigned int shost_eh_deadline; + +module_param_named(eh_deadline, shost_eh_deadline, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(eh_deadline, +"SCSI EH deadline in seconds (should be between 1 and 2^32-1)"); + static struct device_type scsi_host_type = { .name = "scsi_host", .release = scsi_host_dev_release, @@ -388,6 +394,7 @@ 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; if (sht->supported_mode == MODE_UNKNOWN) /* means we didn't set it ... default to INITIATOR */ diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 467cb3c..cf30475 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -91,6 +91,31 @@ void scsi_schedule_eh(struct Scsi_Host *shost) } EXPORT_SYMBOL_GPL(scsi_schedule_eh); +static int sdev_eh_deadline(struct Scsi_Host *shost, + unsigned long eh_start) +{ + if (!shost->eh_deadline) + return 0; + + if (shost->last_reset != 0 && + time_before(shost->last_reset, eh_start)) + eh_start = shost->last_reset; + + if (time_before(jiffies, + eh_start + shost->eh_deadline)) + return 0; + + return 1; +} + +static int scsi_host_eh_deadline(struct Scsi_Host *shost) +{ + if (!shost->last_reset) + return 0; + + return sdev_eh_deadline(shost, shost->last_reset); +} + /** * scsi_eh_abort_handler - Handle command aborts * @work: sdev on which commands should be aborted. @@ -102,13 +127,15 @@ scsi_eh_abort_handler(struct work_struct *work) container_of(work, struct scsi_device, abort_work); struct scsi_cmnd *scmd, *tmp; LIST_HEAD(abort_list); - unsigned long flags; + unsigned long flags, eh_start; 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); + eh_start = jiffies; + list_for_each_entry_safe(scmd, tmp, &abort_list, eh_entry) { list_del_init(&scmd->eh_entry); if (sdev->sdev_state == SDEV_CANCEL) { @@ -119,6 +146,13 @@ scsi_eh_abort_handler(struct work_struct *work) scsi_finish_command(scmd); continue; } + if (sdev_eh_deadline(sdev->host, eh_start)) { + SCSI_LOG_ERROR_RECOVERY(3, + scmd_printk(KERN_INFO, scmd, +"eh timeout, not aborting\n")); + list_move_tail(&scmd->eh_entry, &abort_list); + goto start_eh; + } SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd, "aborting command %p\n", scmd)); @@ -151,6 +185,12 @@ scsi_eh_abort_handler(struct work_struct *work) return; start_eh: + spin_lock_irqsave(sdev->host->host_lock, flags); + if (sdev->host->eh_deadline && + (!sdev->host->last_reset || +time_before(eh_start, sdev->host->last_reset))) + sdev->host->last_reset = eh_start; + spin_unlock_irqrestore(sdev->host->host_lock, flags); list_for_each_entry_safe(scmd, tmp, &abort_list, eh_entry) { scmd->result |= DID_TIME_OUT << 16; if (!scsi_eh_scmd_add(scmd, 0)) { @@ -232,6 +272,9 @@ 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 (sdev->eh_deadline && !shost->last_reset) + shost->last_reset = jiffies; + ret = 1; scmd->eh_eflags |= eh_flag;
[PATCH 0/7] Limit overall SCSI EH runtime
This patchset implements a new 'eh_deadline' attribute to the SCSI host. It will limit the overall SCSI EH runtime by a given timeout. If the timeout expires all intermediate steps will be skipped and host reset will be scheduled immediately. For this patch I've re-used the existing 'last_reset' field of the SCSI host to store the initial time SCSI EH started. Also the field 'resetting' has been removed as it never has been used as intended. As 'last_reset' might be in use by transport-specific EH implementation I've disallowed eh_deadline setting there. Patchset is incremental to my earlier patchset 'scsi: improved eh timeout handler'. As usual, comments etc are welcome. Hannes Reinecke (7): dpt_i2o: Remove DPTI_STATE_IOCTL dpt_i2o: return SCSI_MLQUEUE_HOST_BUSY when in reset advansys: Remove 'last_reset' references tmscsim: Move 'last_reset' into host structure dc395: Move 'last_reset' into internal host structure scsi: remove check for 'resetting' scsi: Add 'eh_deadline' to limit SCSI EH runtime drivers/scsi/advansys.c | 8 +-- drivers/scsi/dc395x.c | 24 drivers/scsi/dpt_i2o.c| 35 +--- drivers/scsi/dpti.h | 1 - drivers/scsi/hosts.c | 7 +++ drivers/scsi/scsi.c | 28 - drivers/scsi/scsi_error.c | 142 +++--- drivers/scsi/scsi_sysfs.c | 37 drivers/scsi/tmscsim.c| 14 ++--- drivers/scsi/tmscsim.h| 1 + include/scsi/scsi_host.h | 2 +- 11 files changed, 218 insertions(+), 81 deletions(-) -- 1.7.12.4 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 1/7] dpt_i2o: Remove DPTI_STATE_IOCTL
scsi_block_host/scsi_unlock_host provides the required functionality. Signed-off-by: Hannes Reinecke --- drivers/scsi/dpt_i2o.c | 30 -- drivers/scsi/dpti.h| 1 - 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c index 19e1b42..106ff1a 100644 --- a/drivers/scsi/dpt_i2o.c +++ b/drivers/scsi/dpt_i2o.c @@ -448,15 +448,7 @@ static int adpt_queue_lck(struct scsi_cmnd * cmd, void (*done) (struct scsi_cmnd } rmb(); - /* -* TODO: I need to block here if I am processing ioctl cmds -* but if the outstanding cmds all finish before the ioctl, -* the scsi-core will not know to start sending cmds to me again. -* I need to a way to restart the scsi-cores queues or should I block -* calling scsi_done on the outstanding cmds instead -* for now we don't set the IOCTL state -*/ - if(((pHba->state) & DPTI_STATE_IOCTL) || ((pHba->state) & DPTI_STATE_RESET)) { + if((pHba->state) & DPTI_STATE_RESET) { pHba->host->last_reset = jiffies; pHba->host->resetting = 1; return 1; @@ -1811,21 +1803,23 @@ static int adpt_i2o_passthru(adpt_hba* pHba, u32 __user *arg) } do { - if(pHba->host) + /* +* Stop any new commands from enterring the +* controller while processing the ioctl +*/ + if(pHba->host) { + scsi_block_requests(pHba->host); spin_lock_irqsave(pHba->host->host_lock, flags); - // This state stops any new commands from enterring the - // controller while processing the ioctl -// pHba->state |= DPTI_STATE_IOCTL; -// We can't set this now - The scsi subsystem sets host_blocked and -// the queue empties and stops. We need a way to restart the queue + } rcode = adpt_i2o_post_wait(pHba, msg, size, FOREVER); if (rcode != 0) printk("adpt_i2o_passthru: post wait failed %d %p\n", rcode, reply); -// pHba->state &= ~DPTI_STATE_IOCTL; - if(pHba->host) + if(pHba->host) { spin_unlock_irqrestore(pHba->host->host_lock, flags); - } while(rcode == -ETIMEDOUT); + scsi_unblock_requests(pHba->host); + } + } while(rcode == -ETIMEDOUT); if(rcode){ goto cleanup; diff --git a/drivers/scsi/dpti.h b/drivers/scsi/dpti.h index beded71..aeb0461 100644 --- a/drivers/scsi/dpti.h +++ b/drivers/scsi/dpti.h @@ -202,7 +202,6 @@ struct adpt_channel { // HBA state flags #define DPTI_STATE_RESET (0x01) -#define DPTI_STATE_IOCTL (0x02) typedef struct _adpt_hba { struct _adpt_hba *next; -- 1.7.12.4 -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 0/2]
Those patches replace the previous Query Request and NOP patches: [PATCH 1/8] scsi: ufs: add support for query [PATCH 7/8] scsi: ufs: Set fDeviceInit flag to initiate device initialization [PATCH 8/8] scsi: ufs: Fix the response UPIU length setting And depends on: [PATCH 2/8] scsi: ufs: wrap the i/o access operations [PATCH 3/8] scsi: ufs: amend interrupt configuration [PATCH 4/8] scsi: ufs: remove version check before IS reg clear [PATCH 5/8] scsi: ufs: rework link start-up process Sending the query request via the SCSI vendor specific command can cause a deadlock in case the SCSI command queue is blocked and we would like to send a query request (for example fDeviceInit in case of re-initialization). In addition, usage of a vendor specific SCSI command for UFS can cause future conflicts if this vendor specific command will be allocated for a different usage. The below patches allocate an internal tag for NOP and query requests and do not involve the SCSI layer in UFS specific requests transfers. This design also resolves the possible deadlock mentioned above. Dolev Raviv (1): scsi: ufs: Set fDeviceInit flag to initiate device initialization Sujit Reddy Thumma (1): scsi: ufs: Add support for sending NOP OUT UPIU drivers/scsi/ufs/ufs.h| 127 +++- drivers/scsi/ufs/ufshcd.c | 802 ++-- drivers/scsi/ufs/ufshcd.h | 40 +++- drivers/scsi/ufs/ufshci.h |2 +- 4 files changed, 849 insertions(+), 122 deletions(-) -- 1.7.6 -- QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 1/2] scsi: ufs: Add support for sending NOP OUT UPIU
From: Sujit Reddy Thumma As part of device initialization sequence, sending NOP OUT UPIU and waiting for NOP IN UPIU response is mandatory. This confirms that the device UFS Transport (UTP) layer is functional and the host can configure the device with further commands. Add support for sending NOP OUT UPIU to check the device connection path and test whether the UTP layer on the device side is functional during initialization. In order to send a UPIU request a UPIU request tag is required. Since internal request is not scheduled via the block layer, a special tag is reserved. The reserved tag is the last queuing tag (usually 31). To avoid collisions with SCSI commands receiving a dynamic allocated tags, the SCSI command queue depth is shorten by one. In such way the last tag will never be used by other SCSI commands and will remain available for internal commands. This design allows us sending maintenance commands before the queue was initialized or when its blocked. For example initiating urgent background operations which requires to block all incoming SCSI requests. Signed-off-by: Sujit Reddy Thumma Signed-off-by: Dolev Raviv diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h index 139bc06..69c0328 100644 --- a/drivers/scsi/ufs/ufs.h +++ b/drivers/scsi/ufs/ufs.h @@ -36,10 +36,16 @@ #ifndef _UFS_H #define _UFS_H +#include +#include + #define MAX_CDB_SIZE 16 +#define GENERAL_UPIU_REQUEST_SIZE 32 +#define UPIU_HEADER_DATA_SEGMENT_MAX_SIZE ((ALIGNED_UPIU_SIZE) - \ + (GENERAL_UPIU_REQUEST_SIZE)) #define UPIU_HEADER_DWORD(byte3, byte2, byte1, byte0)\ - ((byte3 << 24) | (byte2 << 16) |\ + cpu_to_be32((byte3 << 24) | (byte2 << 16) |\ (byte1 << 8) | (byte0)) /* @@ -73,6 +79,7 @@ enum { UPIU_TRANSACTION_TASK_RSP = 0x24, UPIU_TRANSACTION_READY_XFER = 0x31, UPIU_TRANSACTION_QUERY_RSP = 0x36, + UPIU_TRANSACTION_REJECT_UPIU= 0x3F, }; /* UPIU Read/Write flags */ @@ -110,6 +117,12 @@ enum { UPIU_COMMAND_SET_TYPE_QUERY = 0x2, }; +/* UTP Transfer Request Command Offset */ +#define UPIU_COMMAND_TYPE_OFFSET 28 + +/* Offset of the response code in the UPIU header */ +#define UPIU_RSP_CODE_OFFSET 8 + enum { MASK_SCSI_STATUS= 0xFF, MASK_TASK_RESPONSE = 0xFF00, @@ -138,26 +151,32 @@ struct utp_upiu_header { /** * struct utp_upiu_cmd - Command UPIU structure - * @header: UPIU header structure DW-0 to DW-2 * @data_transfer_len: Data Transfer Length DW-3 * @cdb: Command Descriptor Block CDB DW-4 to DW-7 */ struct utp_upiu_cmd { - struct utp_upiu_header header; u32 exp_data_transfer_len; u8 cdb[MAX_CDB_SIZE]; }; /** - * struct utp_upiu_rsp - Response UPIU structure - * @header: UPIU header DW-0 to DW-2 + * struct utp_upiu_req - general upiu request structure + * @header:UPIU header structure DW-0 to DW-2 + * @sc: fields structure for scsi command + */ +struct utp_upiu_req { + struct utp_upiu_header header; + struct utp_upiu_cmd sc; +}; + +/** + * struct utp_cmd_rsp - Response UPIU structure * @residual_transfer_count: Residual transfer count DW-3 * @reserved: Reserved double words DW-4 to DW-7 * @sense_data_len: Sense data length DW-8 U16 * @sense_data: Sense data field DW-8 to DW-12 */ -struct utp_upiu_rsp { - struct utp_upiu_header header; +struct utp_cmd_rsp { u32 residual_transfer_count; u32 reserved[4]; u16 sense_data_len; @@ -165,6 +184,16 @@ struct utp_upiu_rsp { }; /** + * struct utp_upiu_rsp - general upiu response structure + * @header: UPIU header structure DW-0 to DW-2 + * @sc: fields structure for scsi command + */ +struct utp_upiu_rsp { + struct utp_upiu_header header; + struct utp_cmd_rsp sc; +}; + +/** * struct utp_upiu_task_req - Task request UPIU structure * @header - UPIU header structure DW0 to DW-2 * @input_param1: Input parameter 1 DW-3 diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 48a7645..d534c50 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -43,6 +43,15 @@ /* UIC command timeout, unit: ms */ #define UIC_CMD_TIMEOUT500 +/* NOP OUT retries waiting for NOP IN response */ +#define NOP_OUT_RETRIES10 +/* Timeout after 30 msecs if NOP OUT hangs without response */ +#define NOP_OUT_TIMEOUT30 /* msecs */ + +#define SCSI_CMD_QUEUE_SIZE (hba->nutrs - 1) +/* Reserved tag for internal commands */ +#define INTERNAL_CMD_TAG (hba->nutrs - 1) + enum { UFSHCD_MAX_CHANNEL = 0, UFSHCD_MAX_ID = 1, @@ -71,6 +80,41 @@ enum { INT_AGGR_CONFIG, }; +/* + * ufshcd_wait_for_register - wait for register value to change + * @hba - per-adapter interface + * @reg - mmio register offset + * @mask - mask to apply to read register value + * @val - wait conditio
[PATCH 2/2] scsi: ufs: Set fDeviceInit flag to initiate device initialization
Allow UFS device to complete its initialization and accept SCSI commands by setting fDeviceInit flag. The device may take time for this operation and hence the host should poll until fDeviceInit flag is toggled to zero. This step is mandated by UFS device specification for device initialization completion. Signed-off-by: Dolev Raviv Signed-off-by: Sujit Reddy Thumma diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h index 69c0328..6ce99b0 100644 --- a/drivers/scsi/ufs/ufs.h +++ b/drivers/scsi/ufs/ufs.h @@ -43,6 +43,8 @@ #define GENERAL_UPIU_REQUEST_SIZE 32 #define UPIU_HEADER_DATA_SEGMENT_MAX_SIZE ((ALIGNED_UPIU_SIZE) - \ (GENERAL_UPIU_REQUEST_SIZE)) +#define QUERY_OSF_SIZE ((GENERAL_UPIU_REQUEST_SIZE) - \ + (sizeof(struct utp_upiu_header))) #define UPIU_HEADER_DWORD(byte3, byte2, byte1, byte0)\ cpu_to_be32((byte3 << 24) | (byte2 << 16) |\ @@ -68,7 +70,7 @@ enum { UPIU_TRANSACTION_COMMAND= 0x01, UPIU_TRANSACTION_DATA_OUT = 0x02, UPIU_TRANSACTION_TASK_REQ = 0x04, - UPIU_TRANSACTION_QUERY_REQ = 0x26, + UPIU_TRANSACTION_QUERY_REQ = 0x16, }; /* UTP UPIU Transaction Codes Target to Initiator */ @@ -97,8 +99,19 @@ enum { UPIU_TASK_ATTR_ACA = 0x03, }; -/* UTP QUERY Transaction Specific Fields OpCode */ +/* UPIU Query request function */ enum { + UPIU_QUERY_FUNC_STANDARD_READ_REQUEST = 0x01, + UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST = 0x81, +}; + +/* Flag idn for Query Requests*/ +enum flag_idn { + QUERY_FLAG_IDN_FDEVICEINIT = 0x01, +}; + +/* UTP QUERY Transaction Specific Fields OpCode */ +enum query_opcode { UPIU_QUERY_OPCODE_NOP = 0x0, UPIU_QUERY_OPCODE_READ_DESC = 0x1, UPIU_QUERY_OPCODE_WRITE_DESC= 0x2, @@ -110,6 +123,21 @@ enum { UPIU_QUERY_OPCODE_TOGGLE_FLAG = 0x8, }; +/* Query response result code */ +enum { + QUERY_RESULT_SUCCESS= 0x00, + QUERY_RESULT_NOT_READABLE = 0xF6, + QUERY_RESULT_NOT_WRITEABLE = 0xF7, + QUERY_RESULT_ALREADY_WRITTEN= 0xF8, + QUERY_RESULT_INVALID_LENGTH = 0xF9, + QUERY_RESULT_INVALID_VALUE = 0xFA, + QUERY_RESULT_INVALID_SELECTOR = 0xFB, + QUERY_RESULT_INVALID_INDEX = 0xFC, + QUERY_RESULT_INVALID_IDN= 0xFD, + QUERY_RESULT_INVALID_OPCODE = 0xFE, + QUERY_RESULT_GENERAL_FAILURE= 0xFF, +}; + /* UTP Transfer Request Command Type (CT) */ enum { UPIU_COMMAND_SET_TYPE_SCSI = 0x0, @@ -127,6 +155,7 @@ enum { MASK_SCSI_STATUS= 0xFF, MASK_TASK_RESPONSE = 0xFF00, MASK_RSP_UPIU_RESULT= 0x, + MASK_QUERY_DATA_SEG_LEN = 0x, }; /* Task management service response */ @@ -160,13 +189,40 @@ struct utp_upiu_cmd { }; /** + * struct utp_upiu_query - upiu request buffer structure for + * query request. + * @opcode: command to perform B-0 + * @idn: a value that indicates the particular type of data B-1 + * @index: Index to further identify data B-2 + * @selector: Index to further identify data B-3 + * @reserved_osf: spec reserved field B-4,5 + * @length: number of descriptor bytes to read/write B-6,7 + * @value: Attribute value to be written DW-6 + * @reserved: spec reserved DW-7,8 + */ +struct utp_upiu_query { + u8 opcode; + u8 idn; + u8 index; + u8 selector; + u16 reserved_osf; + u16 length; + u32 value; + u32 reserved[2]; +}; + +/** * struct utp_upiu_req - general upiu request structure * @header:UPIU header structure DW-0 to DW-2 * @sc: fields structure for scsi command + * @qr: fields structure for query request */ struct utp_upiu_req { struct utp_upiu_header header; - struct utp_upiu_cmd sc; + union { + struct utp_upiu_cmd sc; + struct utp_upiu_query qr; + }; }; /** @@ -187,10 +243,14 @@ struct utp_cmd_rsp { * struct utp_upiu_rsp - general upiu response structure * @header: UPIU header structure DW-0 to DW-2 * @sc: fields structure for scsi command + * @qr: fields structure for query request */ struct utp_upiu_rsp { struct utp_upiu_header header; - struct utp_cmd_rsp sc; + union { + struct utp_cmd_rsp sc; + struct utp_upiu_query qr; + }; }; /** @@ -223,4 +283,24 @@ struct utp_upiu_task_rsp { u32 reserved[3]; }; +/** + * struct ufs_query_req - parameters for building a query request + * @query_func: UPIU header query function + * @upiu_req: the query request data + */ +struct ufs_query_req { + u8 query_func; + struct utp_upiu_query upiu_req; +}; + +/** + * struct ufs_query_resp - UPIU QUERY + * @response: device response cod
[PATCH 0/2] Add suport for internal request (NOP and Query Request)
Those patches replace the previous Query Request and NOP patches: [PATCH 1/8] scsi: ufs: add support for query [PATCH 7/8] scsi: ufs: Set fDeviceInit flag to initiate device initialization [PATCH 8/8] scsi: ufs: Fix the response UPIU length setting And depends on: [PATCH 2/8] scsi: ufs: wrap the i/o access operations [PATCH 3/8] scsi: ufs: amend interrupt configuration [PATCH 4/8] scsi: ufs: remove version check before IS reg clear [PATCH 5/8] scsi: ufs: rework link start-up process Sending the query request via the SCSI vendor specific command can cause a deadlock in case the SCSI command queue is blocked and we would like to send a query request (for example fDeviceInit in case of re-initialization). In addition, usage of a vendor specific SCSI command for UFS can cause future conflicts if this vendor specific command will be allocated for a different usage. The below patches allocate an internal tag for NOP and query requests and do not involve the SCSI layer in UFS specific requests transfers. This design also resolves the possible deadlock mentioned above. Dolev Raviv (1): scsi: ufs: Set fDeviceInit flag to initiate device initialization Sujit Reddy Thumma (1): scsi: ufs: Add support for sending NOP OUT UPIU drivers/scsi/ufs/ufs.h| 127 +++- drivers/scsi/ufs/ufshcd.c | 802 ++-- drivers/scsi/ufs/ufshcd.h | 40 +++- drivers/scsi/ufs/ufshci.h |2 +- 4 files changed, 849 insertions(+), 122 deletions(-) -- 1.7.6 -- QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 1/2] scsi: ufs: Add support for sending NOP OUT UPIU
From: Sujit Reddy Thumma As part of device initialization sequence, sending NOP OUT UPIU and waiting for NOP IN UPIU response is mandatory. This confirms that the device UFS Transport (UTP) layer is functional and the host can configure the device with further commands. Add support for sending NOP OUT UPIU to check the device connection path and test whether the UTP layer on the device side is functional during initialization. In order to send a UPIU request a UPIU request tag is required. Since internal request is not scheduled via the block layer, a special tag is reserved. The reserved tag is the last queuing tag (usually 31). To avoid collisions with SCSI commands receiving a dynamic allocated tags, the SCSI command queue depth is shorten by one. In such way the last tag will never be used by other SCSI commands and will remain available for internal commands. This design allows us sending maintenance commands before the queue was initialized or when its blocked. For example initiating urgent background operations which requires to block all incoming SCSI requests. Signed-off-by: Sujit Reddy Thumma Signed-off-by: Dolev Raviv diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h index 139bc06..69c0328 100644 --- a/drivers/scsi/ufs/ufs.h +++ b/drivers/scsi/ufs/ufs.h @@ -36,10 +36,16 @@ #ifndef _UFS_H #define _UFS_H +#include +#include + #define MAX_CDB_SIZE 16 +#define GENERAL_UPIU_REQUEST_SIZE 32 +#define UPIU_HEADER_DATA_SEGMENT_MAX_SIZE ((ALIGNED_UPIU_SIZE) - \ + (GENERAL_UPIU_REQUEST_SIZE)) #define UPIU_HEADER_DWORD(byte3, byte2, byte1, byte0)\ - ((byte3 << 24) | (byte2 << 16) |\ + cpu_to_be32((byte3 << 24) | (byte2 << 16) |\ (byte1 << 8) | (byte0)) /* @@ -73,6 +79,7 @@ enum { UPIU_TRANSACTION_TASK_RSP = 0x24, UPIU_TRANSACTION_READY_XFER = 0x31, UPIU_TRANSACTION_QUERY_RSP = 0x36, + UPIU_TRANSACTION_REJECT_UPIU= 0x3F, }; /* UPIU Read/Write flags */ @@ -110,6 +117,12 @@ enum { UPIU_COMMAND_SET_TYPE_QUERY = 0x2, }; +/* UTP Transfer Request Command Offset */ +#define UPIU_COMMAND_TYPE_OFFSET 28 + +/* Offset of the response code in the UPIU header */ +#define UPIU_RSP_CODE_OFFSET 8 + enum { MASK_SCSI_STATUS= 0xFF, MASK_TASK_RESPONSE = 0xFF00, @@ -138,26 +151,32 @@ struct utp_upiu_header { /** * struct utp_upiu_cmd - Command UPIU structure - * @header: UPIU header structure DW-0 to DW-2 * @data_transfer_len: Data Transfer Length DW-3 * @cdb: Command Descriptor Block CDB DW-4 to DW-7 */ struct utp_upiu_cmd { - struct utp_upiu_header header; u32 exp_data_transfer_len; u8 cdb[MAX_CDB_SIZE]; }; /** - * struct utp_upiu_rsp - Response UPIU structure - * @header: UPIU header DW-0 to DW-2 + * struct utp_upiu_req - general upiu request structure + * @header:UPIU header structure DW-0 to DW-2 + * @sc: fields structure for scsi command + */ +struct utp_upiu_req { + struct utp_upiu_header header; + struct utp_upiu_cmd sc; +}; + +/** + * struct utp_cmd_rsp - Response UPIU structure * @residual_transfer_count: Residual transfer count DW-3 * @reserved: Reserved double words DW-4 to DW-7 * @sense_data_len: Sense data length DW-8 U16 * @sense_data: Sense data field DW-8 to DW-12 */ -struct utp_upiu_rsp { - struct utp_upiu_header header; +struct utp_cmd_rsp { u32 residual_transfer_count; u32 reserved[4]; u16 sense_data_len; @@ -165,6 +184,16 @@ struct utp_upiu_rsp { }; /** + * struct utp_upiu_rsp - general upiu response structure + * @header: UPIU header structure DW-0 to DW-2 + * @sc: fields structure for scsi command + */ +struct utp_upiu_rsp { + struct utp_upiu_header header; + struct utp_cmd_rsp sc; +}; + +/** * struct utp_upiu_task_req - Task request UPIU structure * @header - UPIU header structure DW0 to DW-2 * @input_param1: Input parameter 1 DW-3 diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 48a7645..d534c50 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -43,6 +43,15 @@ /* UIC command timeout, unit: ms */ #define UIC_CMD_TIMEOUT500 +/* NOP OUT retries waiting for NOP IN response */ +#define NOP_OUT_RETRIES10 +/* Timeout after 30 msecs if NOP OUT hangs without response */ +#define NOP_OUT_TIMEOUT30 /* msecs */ + +#define SCSI_CMD_QUEUE_SIZE (hba->nutrs - 1) +/* Reserved tag for internal commands */ +#define INTERNAL_CMD_TAG (hba->nutrs - 1) + enum { UFSHCD_MAX_CHANNEL = 0, UFSHCD_MAX_ID = 1, @@ -71,6 +80,41 @@ enum { INT_AGGR_CONFIG, }; +/* + * ufshcd_wait_for_register - wait for register value to change + * @hba - per-adapter interface + * @reg - mmio register offset + * @mask - mask to apply to read register value + * @val - wait conditio
[PATCH 2/2] scsi: ufs: Set fDeviceInit flag to initiate device initialization
Allow UFS device to complete its initialization and accept SCSI commands by setting fDeviceInit flag. The device may take time for this operation and hence the host should poll until fDeviceInit flag is toggled to zero. This step is mandated by UFS device specification for device initialization completion. Signed-off-by: Dolev Raviv Signed-off-by: Sujit Reddy Thumma diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h index 69c0328..6ce99b0 100644 --- a/drivers/scsi/ufs/ufs.h +++ b/drivers/scsi/ufs/ufs.h @@ -43,6 +43,8 @@ #define GENERAL_UPIU_REQUEST_SIZE 32 #define UPIU_HEADER_DATA_SEGMENT_MAX_SIZE ((ALIGNED_UPIU_SIZE) - \ (GENERAL_UPIU_REQUEST_SIZE)) +#define QUERY_OSF_SIZE ((GENERAL_UPIU_REQUEST_SIZE) - \ + (sizeof(struct utp_upiu_header))) #define UPIU_HEADER_DWORD(byte3, byte2, byte1, byte0)\ cpu_to_be32((byte3 << 24) | (byte2 << 16) |\ @@ -68,7 +70,7 @@ enum { UPIU_TRANSACTION_COMMAND= 0x01, UPIU_TRANSACTION_DATA_OUT = 0x02, UPIU_TRANSACTION_TASK_REQ = 0x04, - UPIU_TRANSACTION_QUERY_REQ = 0x26, + UPIU_TRANSACTION_QUERY_REQ = 0x16, }; /* UTP UPIU Transaction Codes Target to Initiator */ @@ -97,8 +99,19 @@ enum { UPIU_TASK_ATTR_ACA = 0x03, }; -/* UTP QUERY Transaction Specific Fields OpCode */ +/* UPIU Query request function */ enum { + UPIU_QUERY_FUNC_STANDARD_READ_REQUEST = 0x01, + UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST = 0x81, +}; + +/* Flag idn for Query Requests*/ +enum flag_idn { + QUERY_FLAG_IDN_FDEVICEINIT = 0x01, +}; + +/* UTP QUERY Transaction Specific Fields OpCode */ +enum query_opcode { UPIU_QUERY_OPCODE_NOP = 0x0, UPIU_QUERY_OPCODE_READ_DESC = 0x1, UPIU_QUERY_OPCODE_WRITE_DESC= 0x2, @@ -110,6 +123,21 @@ enum { UPIU_QUERY_OPCODE_TOGGLE_FLAG = 0x8, }; +/* Query response result code */ +enum { + QUERY_RESULT_SUCCESS= 0x00, + QUERY_RESULT_NOT_READABLE = 0xF6, + QUERY_RESULT_NOT_WRITEABLE = 0xF7, + QUERY_RESULT_ALREADY_WRITTEN= 0xF8, + QUERY_RESULT_INVALID_LENGTH = 0xF9, + QUERY_RESULT_INVALID_VALUE = 0xFA, + QUERY_RESULT_INVALID_SELECTOR = 0xFB, + QUERY_RESULT_INVALID_INDEX = 0xFC, + QUERY_RESULT_INVALID_IDN= 0xFD, + QUERY_RESULT_INVALID_OPCODE = 0xFE, + QUERY_RESULT_GENERAL_FAILURE= 0xFF, +}; + /* UTP Transfer Request Command Type (CT) */ enum { UPIU_COMMAND_SET_TYPE_SCSI = 0x0, @@ -127,6 +155,7 @@ enum { MASK_SCSI_STATUS= 0xFF, MASK_TASK_RESPONSE = 0xFF00, MASK_RSP_UPIU_RESULT= 0x, + MASK_QUERY_DATA_SEG_LEN = 0x, }; /* Task management service response */ @@ -160,13 +189,40 @@ struct utp_upiu_cmd { }; /** + * struct utp_upiu_query - upiu request buffer structure for + * query request. + * @opcode: command to perform B-0 + * @idn: a value that indicates the particular type of data B-1 + * @index: Index to further identify data B-2 + * @selector: Index to further identify data B-3 + * @reserved_osf: spec reserved field B-4,5 + * @length: number of descriptor bytes to read/write B-6,7 + * @value: Attribute value to be written DW-6 + * @reserved: spec reserved DW-7,8 + */ +struct utp_upiu_query { + u8 opcode; + u8 idn; + u8 index; + u8 selector; + u16 reserved_osf; + u16 length; + u32 value; + u32 reserved[2]; +}; + +/** * struct utp_upiu_req - general upiu request structure * @header:UPIU header structure DW-0 to DW-2 * @sc: fields structure for scsi command + * @qr: fields structure for query request */ struct utp_upiu_req { struct utp_upiu_header header; - struct utp_upiu_cmd sc; + union { + struct utp_upiu_cmd sc; + struct utp_upiu_query qr; + }; }; /** @@ -187,10 +243,14 @@ struct utp_cmd_rsp { * struct utp_upiu_rsp - general upiu response structure * @header: UPIU header structure DW-0 to DW-2 * @sc: fields structure for scsi command + * @qr: fields structure for query request */ struct utp_upiu_rsp { struct utp_upiu_header header; - struct utp_cmd_rsp sc; + union { + struct utp_cmd_rsp sc; + struct utp_upiu_query qr; + }; }; /** @@ -223,4 +283,24 @@ struct utp_upiu_task_rsp { u32 reserved[3]; }; +/** + * struct ufs_query_req - parameters for building a query request + * @query_func: UPIU header query function + * @upiu_req: the query request data + */ +struct ufs_query_req { + u8 query_func; + struct utp_upiu_query upiu_req; +}; + +/** + * struct ufs_query_resp - UPIU QUERY + * @response: device response cod
Re: [PATCH 3/9] scsi: improved eh timeout handler
On Mon, 10 June 2013 11:00:49 +0200, Hannes Reinecke wrote: > On 06/10/2013 10:20 AM, Christoph Hellwig wrote: > > > > 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 majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 8/9] mpt2sas: Enable new EH timeout handler
On Mon, 10 June 2013 09:40:57 +0200, Hannes Reinecke wrote: > > Signed-off-by: Hannes Reinecke > --- > drivers/scsi/mpt2sas/mpt2sas_scsih.c | 11 +++ > 1 file changed, 11 insertions(+) > > diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c > b/drivers/scsi/mpt2sas/mpt2sas_scsih.c > index c6bdc92..47fc66c 100644 > --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c > +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c > @@ -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); > +} Why did you create this function and not do the following? + .eh_timed_out = scsi_abort_command, > +/** > * _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, > -- > 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 majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 3/9] scsi: improved eh timeout handler
On Mon, 10 June 2013 09:40:52 +0200, Hannes Reinecke wrote: > + > + 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 majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH RESEND] scsi: Introduce a help function local_time_seconds() to simplify the getting time stamp operation
On Mon, 2013-06-10 at 09:57 +0800, Gu Zheng wrote: > diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h > index 66216c1..f3377ca 100644 > --- a/include/scsi/scsi.h > +++ b/include/scsi/scsi.h > @@ -574,4 +574,13 @@ static inline __u32 scsi_to_u32(__u8 *ptr) > return (ptr[0]<<24) + (ptr[1]<<16) + (ptr[2]<<8) + ptr[3]; > } > > +/* > + * Convert system time in UTC to local time seconds. > + */ > +static inline u32 local_time_seconds(void) > +{ > + struct timeval utc; > + do_gettimeofday(&utc); > + return (u32)(utc.tv_sec - (sys_tz.tz_minuteswest * 60)); > +} > #endif /* _SCSI_SCSI_H */ This doesn't belong in SCSI. It's not a common pattern, so just leave it open coded in the 3ware drivers. If there's a need for it to be a common pattern, John Stultz will add it to the timer code, but at the moment, he doesn't seem to see the need. James -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] LIBISCSI: Added new boot entries in the session sysfs
This is the kernel part of the modification to extract the net params from the ibft sysfs to the iface struct used for the connection request upon sync_session in the open-iscsi util. Three new session sysfs params are defined: boot_root - holds the name of the /sys/firmware/ibft or iscsi_rootN boot_nic - holds the ethernetN name boot_target - holds the targetN name Signed-off-by: Eddie Wai --- drivers/scsi/libiscsi.c | 18 ++ drivers/scsi/scsi_transport_iscsi.c | 12 include/scsi/iscsi_if.h |4 include/scsi/libiscsi.h |4 4 files changed, 38 insertions(+), 0 deletions(-) diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 5de9469..ae69dfc 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -2808,6 +2808,9 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session) kfree(session->targetname); kfree(session->targetalias); kfree(session->initiatorname); + kfree(session->boot_root); + kfree(session->boot_nic); + kfree(session->boot_target); kfree(session->ifacename); iscsi_destroy_session(cls_session); @@ -3248,6 +3251,12 @@ int iscsi_set_param(struct iscsi_cls_conn *cls_conn, return iscsi_switch_str_param(&session->ifacename, buf); case ISCSI_PARAM_INITIATOR_NAME: return iscsi_switch_str_param(&session->initiatorname, buf); + case ISCSI_PARAM_BOOT_ROOT: + return iscsi_switch_str_param(&session->boot_root, buf); + case ISCSI_PARAM_BOOT_NIC: + return iscsi_switch_str_param(&session->boot_nic, buf); + case ISCSI_PARAM_BOOT_TARGET: + return iscsi_switch_str_param(&session->boot_target, buf); default: return -ENOSYS; } @@ -3326,6 +3335,15 @@ int iscsi_session_get_param(struct iscsi_cls_session *cls_session, case ISCSI_PARAM_INITIATOR_NAME: len = sprintf(buf, "%s\n", session->initiatorname); break; + case ISCSI_PARAM_BOOT_ROOT: + len = sprintf(buf, "%s\n", session->boot_root); + break; + case ISCSI_PARAM_BOOT_NIC: + len = sprintf(buf, "%s\n", session->boot_nic); + break; + case ISCSI_PARAM_BOOT_TARGET: + len = sprintf(buf, "%s\n", session->boot_target); + break; default: return -ENOSYS; } diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 133926b..abf7c40 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -3473,6 +3473,9 @@ iscsi_session_attr(tgt_reset_tmo, ISCSI_PARAM_TGT_RESET_TMO, 0); iscsi_session_attr(ifacename, ISCSI_PARAM_IFACE_NAME, 0); iscsi_session_attr(initiatorname, ISCSI_PARAM_INITIATOR_NAME, 0); iscsi_session_attr(targetalias, ISCSI_PARAM_TARGET_ALIAS, 0); +iscsi_session_attr(boot_root, ISCSI_PARAM_BOOT_ROOT, 0); +iscsi_session_attr(boot_nic, ISCSI_PARAM_BOOT_NIC, 0); +iscsi_session_attr(boot_target, ISCSI_PARAM_BOOT_TARGET, 0); static ssize_t show_priv_session_state(struct device *dev, struct device_attribute *attr, @@ -3568,6 +3571,9 @@ static struct attribute *iscsi_session_attrs[] = { &dev_attr_sess_ifacename.attr, &dev_attr_sess_initiatorname.attr, &dev_attr_sess_targetalias.attr, + &dev_attr_sess_boot_root.attr, + &dev_attr_sess_boot_nic.attr, + &dev_attr_sess_boot_target.attr, &dev_attr_priv_sess_recovery_tmo.attr, &dev_attr_priv_sess_state.attr, &dev_attr_priv_sess_creator.attr, @@ -3631,6 +3637,12 @@ static umode_t iscsi_session_attr_is_visible(struct kobject *kobj, param = ISCSI_PARAM_INITIATOR_NAME; else if (attr == &dev_attr_sess_targetalias.attr) param = ISCSI_PARAM_TARGET_ALIAS; + else if (attr == &dev_attr_sess_boot_root.attr) + param = ISCSI_PARAM_BOOT_ROOT; + else if (attr == &dev_attr_sess_boot_nic.attr) + param = ISCSI_PARAM_BOOT_NIC; + else if (attr == &dev_attr_sess_boot_target.attr) + param = ISCSI_PARAM_BOOT_TARGET; else if (attr == &dev_attr_priv_sess_recovery_tmo.attr) return S_IRUGO | S_IWUSR; else if (attr == &dev_attr_priv_sess_state.attr) diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h index fe7f06c..f9cc89b 100644 --- a/include/scsi/iscsi_if.h +++ b/include/scsi/iscsi_if.h @@ -487,6 +487,10 @@ enum iscsi_param { ISCSI_PARAM_TGT_RESET_TMO, ISCSI_PARAM_TARGET_ALIAS, + ISCSI_PARAM_BOOT_ROOT, + ISCSI_PARAM_BOOT_NIC, + ISCSI_PARAM_BOOT_TARGET, + ISCSI_PARAM_CHAP_IN_IDX, ISCSI_PARAM_CHAP_OUT_IDX, /* must always be last */ diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h index 09c041e..4265a4b 100644 --- a/
Re: [PATCH 3/9] scsi: improved eh timeout handler
On Mon, 10 June 2013 11:19:16 -0400, Jörn Engel wrote: > > 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 majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH RESEND] scsi: Introduce a help function local_time_seconds() to simplify the getting time stamp operation
On 06/11/2013 01:47 AM, James Bottomley wrote: > On Mon, 2013-06-10 at 09:57 +0800, Gu Zheng wrote: >> diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h >> index 66216c1..f3377ca 100644 >> --- a/include/scsi/scsi.h >> +++ b/include/scsi/scsi.h >> @@ -574,4 +574,13 @@ static inline __u32 scsi_to_u32(__u8 *ptr) >> return (ptr[0]<<24) + (ptr[1]<<16) + (ptr[2]<<8) + ptr[3]; >> } >> >> +/* >> + * Convert system time in UTC to local time seconds. >> + */ >> +static inline u32 local_time_seconds(void) >> +{ >> + struct timeval utc; >> + do_gettimeofday(&utc); >> + return (u32)(utc.tv_sec - (sys_tz.tz_minuteswest * 60)); >> +} >> #endif /* _SCSI_SCSI_H */ > > This doesn't belong in SCSI. > > It's not a common pattern, so just leave it open coded in the 3ware > drivers. If there's a need for it to be a common pattern, John Stultz > will add it to the timer code, but at the moment, he doesn't seem to see > the need. Hi James, OK...Thanks for your reminder. As you mentioned in an old thread, what about using "jiffies to seconds" to replace the existed timestamps? Best regards, Gu > > James > > > -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 8/9] mpt2sas: Enable new EH timeout handler
On 06/10/2013 05:31 PM, Jörn Engel wrote: > On Mon, 10 June 2013 09:40:57 +0200, Hannes Reinecke wrote: >> >> Signed-off-by: Hannes Reinecke >> --- >> drivers/scsi/mpt2sas/mpt2sas_scsih.c | 11 +++ >> 1 file changed, 11 insertions(+) >> >> diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c >> b/drivers/scsi/mpt2sas/mpt2sas_scsih.c >> index c6bdc92..47fc66c 100644 >> --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c >> +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c >> @@ -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); >> +} > > Why did you create this function and not do the following? > + .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 -- Dr. Hannes Reinecke zSeries & Storage h...@suse.de +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 majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 3/9] scsi: improved eh timeout handler
On 06/11/2013 01:24 AM, Jörn Engel wrote: > On Mon, 10 June 2013 11:19:16 -0400, Jörn Engel wrote: >> >> 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. > 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 -- Dr. Hannes Reinecke zSeries & Storage h...@suse.de +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 majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html