Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 254367
b: refs/heads/master
c: 4dc043c
h: refs/heads/master
i:
  254365: 6e4d585
  254363: 207755b
  254359: 4781a55
  254351: 0f2eba0
  254335: db73d86
v: v3
  • Loading branch information
Jeff Skirvin authored and Dan Williams committed Jul 3, 2011
1 parent a955eee commit 1375e7e
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 94 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: cbb65c665b341e560b7a3b37cc616376031b3ee5
refs/heads/master: 4dc043c41037fc6e369270daaa626465a8766565
3 changes: 2 additions & 1 deletion trunk/drivers/scsi/isci/request.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ enum isci_request_status {
completed = 0x03,
aborting = 0x04,
aborted = 0x05,
terminating = 0x06
terminating = 0x06,
dead = 0x07
};

enum task_type {
Expand Down
233 changes: 141 additions & 92 deletions trunk/drivers/scsi/isci/task.c
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,59 @@ static void isci_request_cleanup_completed_loiterer(
}
isci_request_free(isci_host, isci_request);
}

/**
* @isci_termination_timed_out(): this function will deal with a request for
* which the wait for termination has timed-out.
*
* @isci_host This SCU.
* @isci_request The I/O request being terminated.
*/
static void
isci_termination_timed_out(
struct isci_host * host,
struct isci_request * request
)
{
unsigned long state_flags;

dev_warn(&host->pdev->dev,
"%s: host = %p; request = %p\n",
__func__, host, request);

/* At this point, the request to terminate
* has timed out. The best we can do is to
* have the request die a silent death
* if it ever completes.
*/
spin_lock_irqsave(&request->state_lock, state_flags);

if (request->status == started) {

/* Set the request state to "dead",
* and clear the task pointer so that an actual
* completion event callback doesn't do
* anything.
*/
request->status = dead;

/* Clear the timeout completion event pointer.*/
request->io_request_completion = NULL;

if (request->ttype == io_task) {

/* Break links with the sas_task. */
if (request->ttype_ptr.io_task_ptr != NULL) {

request->ttype_ptr.io_task_ptr->lldd_task = NULL;
request->ttype_ptr.io_task_ptr = NULL;
}
}
}
spin_unlock_irqrestore(&request->state_lock, state_flags);
}


/**
* isci_terminate_request_core() - This function will terminate the given
* request, and wait for it to complete. This function must only be called
Expand All @@ -684,35 +737,20 @@ static void isci_terminate_request_core(
bool needs_cleanup_handling = false;
enum isci_request_status request_status;
unsigned long flags;
unsigned long timeout_remaining;


dev_dbg(&isci_host->pdev->dev,
"%s: device = %p; request = %p\n",
__func__, isci_device, isci_request);

/* Peek at the current status of the request. This will tell
* us if there was special handling on the request such that it
* needs to be detached and freed here.
*/
spin_lock_irqsave(&isci_request->state_lock, flags);
request_status = isci_request_get_state(isci_request);

if ((isci_request->ttype == io_task) /* TMFs are in their own thread */
&& ((request_status == aborted)
|| (request_status == aborting)
|| (request_status == terminating)
|| (request_status == completed)
)
) {
spin_lock_irqsave(&isci_host->scic_lock, flags);

/* The completion routine won't free a request in
* the aborted/aborting/terminating state, so we do
* it here.
*/
needs_cleanup_handling = true;
}
spin_unlock_irqrestore(&isci_request->state_lock, flags);
/* Note that we are not going to control
* the target to abort the request.
*/
isci_request->complete_in_target = true;

spin_lock_irqsave(&isci_host->scic_lock, flags);
/* Make sure the request wasn't just sitting around signalling
* device condition (if the request handle is NULL, then the
* request completed but needed additional handling here).
Expand All @@ -733,35 +771,79 @@ static void isci_terminate_request_core(
* fail is when the io request is completed and
* being aborted.
*/
if (status != SCI_SUCCESS)
if (status != SCI_SUCCESS) {
dev_err(&isci_host->pdev->dev,
"%s: scic_controller_terminate_request"
" returned = 0x%x\n",
__func__,
status);
else {
/* Clear the completion pointer from the request. */
isci_request->io_request_completion = NULL;

} else {
if (was_terminated) {
dev_dbg(&isci_host->pdev->dev,
"%s: before completion wait (%p)\n",
__func__,
isci_request->io_request_completion);

/* Wait here for the request to complete. */
wait_for_completion(isci_request->io_request_completion);
#define TERMINATION_TIMEOUT_MSEC 50
timeout_remaining
= wait_for_completion_timeout(
isci_request->io_request_completion,
msecs_to_jiffies(TERMINATION_TIMEOUT_MSEC));

if (!timeout_remaining) {

isci_termination_timed_out(isci_host,
isci_request);

dev_err(&isci_host->pdev->dev,
"%s: *** Timeout waiting for "
"termination(%p/%p)\n",
__func__,
isci_request->io_request_completion,
isci_request);

} else
dev_dbg(&isci_host->pdev->dev,
"%s: after completion wait (%p)\n",
__func__,
isci_request->io_request_completion);
}
/* Clear the completion pointer from the request. */
isci_request->io_request_completion = NULL;

dev_dbg(&isci_host->pdev->dev,
"%s: after completion wait (%p)\n",
__func__,
isci_request->io_request_completion);
/* Peek at the status of the request. This will tell
* us if there was special handling on the request such that it
* needs to be detached and freed here.
*/
spin_lock_irqsave(&isci_request->state_lock, flags);
request_status = isci_request_get_state(isci_request);

if ((isci_request->ttype == io_task) /* TMFs are in their own thread */
&& ((request_status == aborted)
|| (request_status == aborting)
|| (request_status == terminating)
|| (request_status == completed)
|| (request_status == dead)
)
) {

/* The completion routine won't free a request in
* the aborted/aborting/etc. states, so we do
* it here.
*/
needs_cleanup_handling = true;
}
spin_unlock_irqrestore(&isci_request->state_lock, flags);

if (needs_cleanup_handling)
isci_request_cleanup_completed_loiterer(
isci_host, isci_device, isci_request
);
}
/* Clear the completion pointer from the request. */
isci_request->io_request_completion = NULL;
}

static void isci_terminate_request(
Expand All @@ -771,11 +853,7 @@ static void isci_terminate_request(
enum isci_request_status new_request_state)
{
enum isci_request_status old_state;

DECLARE_COMPLETION_ONSTACK(request_completion);
unsigned long flags;

spin_lock_irqsave(&isci_host->scic_lock, flags);

/* Change state to "new_request_state" if it is currently "started" */
old_state = isci_request_change_started_to_newstate(
Expand Down Expand Up @@ -823,73 +901,44 @@ void isci_terminate_pending_requests(
struct isci_remote_device *isci_device,
enum isci_request_status new_request_state)
{
struct isci_request *isci_request;
struct sas_task *task;
bool done = false;
unsigned long flags;
struct isci_request *request;
struct isci_request *next_request;
unsigned long flags;
struct list_head aborted_request_list;

INIT_LIST_HEAD(&aborted_request_list);

dev_dbg(&isci_host->pdev->dev,
"%s: isci_device = %p (new request state = %d)\n",
__func__, isci_device, new_request_state);

#define ISCI_TERMINATE_SHOW_PENDING_REQUESTS
#ifdef ISCI_TERMINATE_SHOW_PENDING_REQUESTS
{
struct isci_request *request;

/* Only abort the task if it's in the
* device's request_in_process list
*/
list_for_each_entry(request,
&isci_device->reqs_in_process,
dev_node)
dev_dbg(&isci_host->pdev->dev,
"%s: isci_device = %p; request is on "
"reqs_in_process list: %p\n",
__func__, isci_device, request);
}
#endif /* ISCI_TERMINATE_SHOW_PENDING_REQUESTS */

/* Clean up all pending requests. */
do {
spin_lock_irqsave(&isci_host->scic_lock, flags);

if (list_empty(&isci_device->reqs_in_process)) {

done = true;
spin_unlock_irqrestore(&isci_host->scic_lock, flags);
spin_lock_irqsave(&isci_host->scic_lock, flags);

dev_dbg(&isci_host->pdev->dev,
"%s: isci_device = %p; done.\n",
__func__, isci_device);
} else {
/* The list was not empty - grab the first request. */
isci_request = list_first_entry(
&isci_device->reqs_in_process,
struct isci_request, dev_node
);
/* Note that we are not expecting to have to control
* the target to abort the request.
*/
isci_request->complete_in_target = true;
/* Move all of the pending requests off of the device list. */
list_splice_init(&isci_device->reqs_in_process,
&aborted_request_list);

spin_unlock_irqrestore(&isci_host->scic_lock, flags);
spin_unlock_irqrestore(&isci_host->scic_lock, flags);

/* Get the libsas task reference. */
task = isci_request_access_task(isci_request);
/* Iterate through the now-local list. */
list_for_each_entry_safe(request, next_request,
&aborted_request_list, dev_node) {

dev_dbg(&isci_host->pdev->dev,
"%s: isci_device=%p request=%p; task=%p\n",
__func__, isci_device, isci_request, task);
dev_warn(&isci_host->pdev->dev,
"%s: isci_device=%p request=%p; task=%p\n",
__func__,
isci_device, request,
((request->ttype == io_task)
? isci_request_access_task(request)
: NULL));

/* Mark all still pending I/O with the selected next
* state.
*/
isci_terminate_request(isci_host, isci_device,
isci_request, new_request_state
);
}
} while (!done);
/* Mark all still pending I/O with the selected next
* state, terminate and free it.
*/
isci_terminate_request(isci_host, isci_device,
request, new_request_state
);
}
}

/**
Expand Down

0 comments on commit 1375e7e

Please sign in to comment.