diff options
author | Jeff Skirvin <jeffrey.d.skirvin@intel.com> | 2011-03-05 01:06:44 +0300 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2011-07-03 14:55:29 +0400 |
commit | ec6c9638b0d0537430f78a3e20503b5e68a537b6 (patch) | |
tree | b6d05437adb1c8bc40a02e2fa82ff67df57aef6d | |
parent | a5fde225364df30507ba1a5aafeec85e595000d3 (diff) | |
download | linux-ec6c9638b0d0537430f78a3e20503b5e68a537b6.tar.xz |
isci: Any reset indicated on an I/O completion escalates it to the error path.
If there is a pending device reset, the I/O is used to accomplish the reset by setting the
RESET bit in the task status, and then putting the task into the error handler
path using sas abort task.
Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Jacek Danecki <Jacek.Danecki@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
-rw-r--r-- | drivers/scsi/isci/host.c | 11 | ||||
-rw-r--r-- | drivers/scsi/isci/request.c | 9 | ||||
-rw-r--r-- | drivers/scsi/isci/task.h | 53 |
3 files changed, 46 insertions, 27 deletions
diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c index 153f419f1618..dc231c22ea93 100644 --- a/drivers/scsi/isci/host.c +++ b/drivers/scsi/isci/host.c @@ -290,17 +290,6 @@ static void isci_host_completion_routine(unsigned long data) list_splice_init(&isci_host->requests_to_complete, &completed_request_list); - /* While holding the scic_lock take all of the normally completed - * I/Os off of the device's pending lists. - */ - list_for_each_entry(request, &completed_request_list, completed_node) { - - /* Remove the request from the remote device's list - * of pending requests. - */ - list_del_init(&request->dev_node); - } - /* Take the list of errored I/Os from the host. */ list_splice_init(&isci_host->requests_to_errorback, &errored_request_list); diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c index c88e270b2b40..6cd80bbdae15 100644 --- a/drivers/scsi/isci/request.c +++ b/drivers/scsi/isci/request.c @@ -790,9 +790,9 @@ static void isci_task_save_for_upper_layer_completion( { struct sas_task *task = isci_request_access_task(request); - isci_task_set_completion_status(task, response, status, - task_notification_selection); - + task_notification_selection + = isci_task_set_completion_status(task, response, status, + task_notification_selection); /* Tasks aborted specifically by a call to the lldd_abort_task * function should not be completed to the host in the regular path. @@ -811,6 +811,9 @@ static void isci_task_save_for_upper_layer_completion( /* Add to the completed list. */ list_add(&request->completed_node, &host->requests_to_complete); + + /* Take the request off the device's pending request list. */ + list_del_init(&request->dev_node); break; case isci_perform_aborted_io_completion: diff --git a/drivers/scsi/isci/task.h b/drivers/scsi/isci/task.h index ced6a8be1b31..68d8e5e65a73 100644 --- a/drivers/scsi/isci/task.h +++ b/drivers/scsi/isci/task.h @@ -280,9 +280,10 @@ static inline void isci_task_all_done( * @response: This parameter is the response code for the completed task. * @status: This parameter is the status code for the completed task. * - * none. - */ -static inline void isci_task_set_completion_status( +* @return The new notification mode for the request. +*/ +static inline enum isci_completion_selection +isci_task_set_completion_status( struct sas_task *task, enum service_response response, enum exec_status status, @@ -295,15 +296,41 @@ static inline void isci_task_set_completion_status( task->task_status.resp = response; task->task_status.stat = status; - /* Don't set DONE (or clear AT_INITIATOR) for any task going into the - * error path, because the EH interprets that as a handled error condition. - * Also don't take action if there is a reset pending. - */ - if ((task_notification_selection != isci_perform_error_io_completion) - && !(task->task_state_flags & SAS_TASK_NEED_DEV_RESET)) - isci_set_task_doneflags(task); + /* If a device reset is being indicated, make sure the I/O + * is in the error path. + */ + if (task->task_state_flags & SAS_TASK_NEED_DEV_RESET) + task_notification_selection = isci_perform_error_io_completion; + + switch (task_notification_selection) { + + case isci_perform_aborted_io_completion: + /* This path can occur with task-managed requests as well as + * requests terminated because of LUN or device resets. + */ + /* Fall through to the normal case... */ + + case isci_perform_normal_io_completion: + /* Normal notification (task_done) */ + isci_set_task_doneflags(task); + break; + + default: + WARN_ON(FALSE); + /* Fall through to the error case... */ + + case isci_perform_error_io_completion: + /* Use sas_task_abort */ + /* Leave SAS_TASK_STATE_DONE clear + * Leave SAS_TASK_AT_INITIATOR set. + */ + break; + } spin_unlock_irqrestore(&task->task_state_lock, flags); + + return task_notification_selection; + } /** * isci_task_complete_for_upper_layer() - This function completes the request @@ -322,9 +349,9 @@ static inline void isci_task_complete_for_upper_layer( enum exec_status status, enum isci_completion_selection task_notification_selection) { - isci_task_set_completion_status(task, response, status, - task_notification_selection); - + task_notification_selection + = isci_task_set_completion_status(task, response, status, + task_notification_selection); /* Tasks aborted specifically by a call to the lldd_abort_task * function should not be completed to the host in the regular path. |