diff options
author | Jeff Skirvin <jeffrey.d.skirvin@intel.com> | 2012-03-09 07:41:54 +0100 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2012-05-17 23:33:38 +0200 |
commit | 14aaa9f0a318bd04cbb9d822524b817e95d8b343 (patch) | |
tree | 5f6292ec671d0993c1df51586dea4fb7750d1cd9 /drivers/scsi/isci/host.c | |
parent | isci: Escalate to I_T_Nexus_Reset when the device is gone. (diff) | |
download | linux-14aaa9f0a318bd04cbb9d822524b817e95d8b343.tar.xz linux-14aaa9f0a318bd04cbb9d822524b817e95d8b343.zip |
isci: Redesign device suspension, abort, cleanup.
This commit changes the means by which outstanding I/Os are handled
for cleanup.
The likelihood is that this commit will be broken into smaller pieces,
however that will be a later revision. Among the changes:
- All completion structures have been removed from the tmf and
abort paths.
- Now using one completed I/O list, with the I/O completed in host bit being
used to select error or normal callback paths.
Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/scsi/isci/host.c')
-rw-r--r-- | drivers/scsi/isci/host.c | 86 |
1 files changed, 26 insertions, 60 deletions
diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c index d241b5722eb3..25d537e2f5c4 100644 --- a/drivers/scsi/isci/host.c +++ b/drivers/scsi/isci/host.c @@ -1089,33 +1089,25 @@ void isci_host_completion_routine(unsigned long data) { struct isci_host *ihost = (struct isci_host *)data; 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; u16 active; INIT_LIST_HEAD(&completed_request_list); - INIT_LIST_HEAD(&errored_request_list); spin_lock_irq(&ihost->scic_lock); sci_controller_completion_handler(ihost); /* Take the lists of completed I/Os from the host. */ - list_splice_init(&ihost->requests_to_complete, &completed_request_list); - /* Take the list of errored I/Os from the host. */ - list_splice_init(&ihost->requests_to_errorback, - &errored_request_list); - spin_unlock_irq(&ihost->scic_lock); - /* Process any completions in the lists. */ + /* Process any completions in the list. */ list_for_each_safe(current_position, next_position, &completed_request_list) { @@ -1123,23 +1115,30 @@ void isci_host_completion_routine(unsigned long data) completed_node); task = isci_request_access_task(request); - /* Normal notification (task_done) */ - dev_dbg(&ihost->pdev->dev, - "%s: Normal - request/task = %p/%p\n", - __func__, - request, - task); /* 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); + if (!test_bit(IREQ_ABORT_PATH_ACTIVE, &request->flags) && + !(task->task_state_flags & SAS_TASK_STATE_ABORTED)) { + if (test_bit(IREQ_COMPLETE_IN_TARGET, + &request->flags)) { + + /* Normal notification (task_done) */ + dev_dbg(&ihost->pdev->dev, "%s: Normal" + " - request/task = %p/%p\n", + __func__, request, task); + + task->task_done(task); + } else { + dev_warn(&ihost->pdev->dev, + "%s: Error - request/task" + " = %p/%p\n", + __func__, request, task); + + sas_task_abort(task); + } } } @@ -1147,44 +1146,6 @@ void isci_host_completion_routine(unsigned long data) isci_free_tag(ihost, request->io_tag); spin_unlock_irq(&ihost->scic_lock); } - list_for_each_entry_safe(request, next_request, &errored_request_list, - completed_node) { - - task = isci_request_access_task(request); - - /* Use sas_task_abort */ - dev_warn(&ihost->pdev->dev, - "%s: Error - request/task = %p/%p\n", - __func__, - request, - 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(&ihost->scic_lock); - /* Remove the request from the remote device's list - * of pending requests. - */ - list_del_init(&request->dev_node); - isci_free_tag(ihost, request->io_tag); - spin_unlock_irq(&ihost->scic_lock); - } - } /* the coalesence timeout doubles at each encoding step, so * update it based on the ilog2 value of the outstanding requests @@ -2345,7 +2306,6 @@ static int sci_controller_dma_alloc(struct isci_host *ihost) ireq->tc = &ihost->task_context_table[i]; ireq->owning_controller = ihost; - spin_lock_init(&ireq->state_lock); ireq->request_daddr = dma; ireq->isci_host = ihost; ihost->reqs[i] = ireq; @@ -2697,6 +2657,10 @@ enum sci_status sci_controller_terminate_request(struct isci_host *ihost, return SCI_FAILURE_INVALID_STATE; } status = sci_io_request_terminate(ireq); + + dev_dbg(&ihost->pdev->dev, "%s: status=%d; ireq=%p; flags=%lx\n", + __func__, status, ireq, ireq->flags); + if ((status == SCI_SUCCESS) && !test_bit(IREQ_PENDING_ABORT, &ireq->flags) && !test_and_set_bit(IREQ_TC_ABORT_POSTED, &ireq->flags)) { @@ -2739,6 +2703,8 @@ enum sci_status sci_controller_complete_io(struct isci_host *ihost, index = ISCI_TAG_TCI(ireq->io_tag); clear_bit(IREQ_ACTIVE, &ireq->flags); + if (test_bit(IREQ_ABORT_PATH_ACTIVE, &ireq->flags)) + wake_up_all(&ihost->eventq); return SCI_SUCCESS; default: dev_warn(&ihost->pdev->dev, "%s invalid state: %d\n", |