isci: Changes in isci_host_completion_routine
Changes to move management of the reqs_in_process entry for the request here.
Made changes to note when the task is already in the abort path and
cannot be completed through callbacks.
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>
diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c
index ae5d460..153f419 100644
--- a/drivers/scsi/isci/host.c
+++ b/drivers/scsi/isci/host.c
@@ -270,27 +270,40 @@
static void isci_host_completion_routine(unsigned long data)
{
struct isci_host *isci_host = (struct isci_host *)data;
- struct list_head completed_request_list;
- struct list_head aborted_request_list;
- struct list_head *current_position;
- struct list_head *next_position;
+ struct list_head completed_request_list;
+ struct list_head errored_request_list;
+ struct list_head *current_position;
+ struct list_head *next_position;
struct isci_request *request;
struct isci_request *next_request;
- struct sas_task *task;
+ struct sas_task *task;
INIT_LIST_HEAD(&completed_request_list);
- INIT_LIST_HEAD(&aborted_request_list);
+ INIT_LIST_HEAD(&errored_request_list);
spin_lock_irq(&isci_host->scic_lock);
scic_sds_controller_completion_handler(isci_host->core_controller);
/* Take the lists of completed I/Os from the host. */
+
list_splice_init(&isci_host->requests_to_complete,
&completed_request_list);
- list_splice_init(&isci_host->requests_to_abort,
- &aborted_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);
spin_unlock_irq(&isci_host->scic_lock);
@@ -309,13 +322,22 @@
request,
task);
- task->task_done(task);
- task->lldd_task = NULL;
+ /* Return the task to libsas */
+ if (task != NULL) {
+ task->lldd_task = NULL;
+ if (!(task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
+
+ /* If the task is already in the abort path,
+ * the task_done callback cannot be called.
+ */
+ task->task_done(task);
+ }
+ }
/* Free the request object. */
isci_request_free(isci_host, request);
}
- list_for_each_entry_safe(request, next_request, &aborted_request_list,
+ list_for_each_entry_safe(request, next_request, &errored_request_list,
completed_node) {
task = isci_request_access_task(request);
@@ -327,8 +349,33 @@
request,
task);
- /* Put the task into the abort path. */
- sas_task_abort(task);
+ if (task != NULL) {
+
+ /* Put the task into the abort path if it's not there
+ * already.
+ */
+ if (!(task->task_state_flags & SAS_TASK_STATE_ABORTED))
+ sas_task_abort(task);
+
+ } else {
+ /* This is a case where the request has completed with a
+ * status such that it needed further target servicing,
+ * but the sas_task reference has already been removed
+ * from the request. Since it was errored, it was not
+ * being aborted, so there is nothing to do except free
+ * it.
+ */
+
+ spin_lock_irq(&isci_host->scic_lock);
+ /* Remove the request from the remote device's list
+ * of pending requests.
+ */
+ list_del_init(&request->dev_node);
+ spin_unlock_irq(&isci_host->scic_lock);
+
+ /* Free the request object. */
+ isci_request_free(isci_host, request);
+ }
}
}
@@ -477,7 +524,7 @@
INIT_LIST_HEAD(&(isci_host->mdl_struct_list));
INIT_LIST_HEAD(&isci_host->requests_to_complete);
- INIT_LIST_HEAD(&isci_host->requests_to_abort);
+ INIT_LIST_HEAD(&isci_host->requests_to_errorback);
spin_lock_irq(&isci_host->scic_lock);
status = scic_controller_initialize(isci_host->core_controller);
diff --git a/drivers/scsi/isci/host.h b/drivers/scsi/isci/host.h
index 3c69f1f..889a785 100644
--- a/drivers/scsi/isci/host.h
+++ b/drivers/scsi/isci/host.h
@@ -116,7 +116,7 @@
struct tasklet_struct completion_tasklet;
struct list_head mdl_struct_list;
struct list_head requests_to_complete;
- struct list_head requests_to_abort;
+ struct list_head requests_to_errorback;
spinlock_t scic_lock;
/* careful only access this via idev_by_id */
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c
index 6b0863e..8039f1c 100644
--- a/drivers/scsi/isci/request.c
+++ b/drivers/scsi/isci/request.c
@@ -836,7 +836,7 @@
status);
/* Add to the aborted list. */
list_add(&request->completed_node,
- &host->requests_to_abort);
+ &host->requests_to_errorback);
break;
default:
@@ -849,7 +849,7 @@
/* Add to the aborted list. */
list_add(&request->completed_node,
- &host->requests_to_abort);
+ &host->requests_to_errorback);
break;
}
}
@@ -1185,14 +1185,6 @@
*/
request->sci_request_handle = NULL;
- /* Only remove the request from the remote device list
- * of pending requests if we have not requested error
- * handling on this request.
- */
- if (complete_to_host != isci_perform_error_io_completion)
- list_del_init(&request->dev_node);
-
-
/* Save possible completion ptr. */
io_request_completion = request->io_request_completion;