提交 14aaa9f0 编写于 作者: J Jeff Skirvin 提交者: Dan Williams

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: NJeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: NDan Williams <dan.j.williams@intel.com>
上级 d80ecd57
......@@ -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,68 +1115,37 @@ 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 (!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)) {
/* If the task is already in the abort path,
* the task_done callback cannot be called.
*/
task->task_done(task);
}
}
spin_lock_irq(&ihost->scic_lock);
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);
/* Normal notification (task_done) */
dev_dbg(&ihost->pdev->dev, "%s: Normal"
" - request/task = %p/%p\n",
__func__, request, task);
/* Use sas_task_abort */
task->task_done(task);
} else {
dev_warn(&ihost->pdev->dev,
"%s: Error - request/task = %p/%p\n",
__func__,
request,
task);
if (task != NULL) {
"%s: Error - request/task"
" = %p/%p\n",
__func__, request, task);
/* 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",
......
......@@ -205,7 +205,6 @@ struct isci_host {
wait_queue_head_t eventq;
struct tasklet_struct completion_tasklet;
struct list_head requests_to_complete;
struct list_head requests_to_errorback;
spinlock_t scic_lock;
struct isci_request *reqs[SCI_MAX_IO_REQUESTS];
struct isci_remote_device devices[SCI_MAX_REMOTE_DEVICES];
......
......@@ -556,7 +556,6 @@ static struct isci_host *isci_host_alloc(struct pci_dev *pdev, int id)
}
INIT_LIST_HEAD(&ihost->requests_to_complete);
INIT_LIST_HEAD(&ihost->requests_to_errorback);
for (i = 0; i < SCI_MAX_PORTS; i++) {
struct isci_port *iport = &ihost->ports[i];
......
......@@ -80,49 +80,6 @@ static enum sci_status sci_remote_device_suspend(struct isci_remote_device *idev
NULL, NULL);
}
/**
* isci_remote_device_not_ready() - This function is called by the ihost when
* the remote device is not ready. We mark the isci device as ready (not
* "ready_for_io") and signal the waiting proccess.
* @isci_host: This parameter specifies the isci host object.
* @isci_device: This parameter specifies the remote device
*
* sci_lock is held on entrance to this function.
*/
static void isci_remote_device_not_ready(struct isci_host *ihost,
struct isci_remote_device *idev, u32 reason)
{
struct isci_request *ireq;
dev_dbg(&ihost->pdev->dev,
"%s: isci_device = %p\n", __func__, idev);
switch (reason) {
case SCIC_REMOTE_DEVICE_NOT_READY_STOP_REQUESTED:
set_bit(IDEV_GONE, &idev->flags);
break;
case SCIC_REMOTE_DEVICE_NOT_READY_SATA_SDB_ERROR_FIS_RECEIVED:
set_bit(IDEV_IO_NCQERROR, &idev->flags);
/* Suspend the remote device so the I/O can be terminated. */
sci_remote_device_suspend(idev);
/* Kill all outstanding requests for the device. */
list_for_each_entry(ireq, &idev->reqs_in_process, dev_node) {
dev_dbg(&ihost->pdev->dev,
"%s: isci_device = %p request = %p\n",
__func__, idev, ireq);
sci_controller_terminate_request(ihost, idev, ireq);
}
/* Fall through into the default case... */
default:
clear_bit(IDEV_IO_READY, &idev->flags);
break;
}
}
/**
* isci_remote_device_ready() - This function is called by the ihost when the
* remote device is ready. We mark the isci device as ready and signal the
......@@ -142,49 +99,121 @@ static void isci_remote_device_ready(struct isci_host *ihost, struct isci_remote
wake_up(&ihost->eventq);
}
static int isci_remote_device_suspendcheck(struct isci_remote_device *idev)
static enum sci_status sci_remote_device_terminate_req(
struct isci_host *ihost,
struct isci_remote_device *idev,
int check_abort,
struct isci_request *ireq)
{
dev_dbg(&ihost->pdev->dev,
"%s: idev=%p; flags=%lx; req=%p; req target=%p\n",
__func__, idev, idev->flags, ireq, ireq->target_device);
if (!test_bit(IREQ_ACTIVE, &ireq->flags) ||
(ireq->target_device != idev) ||
(check_abort && !test_bit(IREQ_PENDING_ABORT, &ireq->flags)))
return SCI_SUCCESS;
set_bit(IREQ_ABORT_PATH_ACTIVE, &ireq->flags);
return sci_controller_terminate_request(ihost, idev, ireq);
}
static enum sci_status sci_remote_device_terminate_reqs_checkabort(
struct isci_remote_device *idev,
int chk)
{
return test_bit(IDEV_TXRX_SUSPENDED, &idev->flags)
|| !test_bit(IDEV_ALLOCATED, &idev->flags);
struct isci_host *ihost = idev->owning_port->owning_controller;
enum sci_status status = SCI_SUCCESS;
u32 i;
for (i = 0; i < SCI_MAX_IO_REQUESTS; i++) {
struct isci_request *ireq = ihost->reqs[i];
enum sci_status s;
s = sci_remote_device_terminate_req(ihost, idev, chk, ireq);
if (s != SCI_SUCCESS)
status = s;
}
return status;
}
enum sci_status isci_remote_device_suspend(
enum sci_status isci_remote_device_terminate_requests(
struct isci_host *ihost,
struct isci_remote_device *idev)
struct isci_remote_device *idev,
struct isci_request *ireq)
{
enum sci_status status;
enum sci_status status = SCI_SUCCESS;
unsigned long flags;
spin_lock_irqsave(&ihost->scic_lock, flags);
if (isci_get_device(idev->domain_dev) == NULL) {
if (isci_get_device(idev) == NULL) {
dev_dbg(&ihost->pdev->dev, "%s: failed isci_get_device(idev=%p)\n",
__func__, idev);
spin_unlock_irqrestore(&ihost->scic_lock, flags);
status = SCI_FAILURE;
} else {
status = sci_remote_device_suspend(idev);
spin_unlock_irqrestore(&ihost->scic_lock, flags);
if (status == SCI_SUCCESS) {
dev_dbg(&ihost->pdev->dev,
"%s: idev=%p, about to wait\n",
__func__, idev);
wait_event(ihost->eventq,
isci_remote_device_suspendcheck(idev));
status = test_bit(IDEV_TXRX_SUSPENDED, &idev->flags)
? SCI_SUCCESS : SCI_FAILURE;
dev_dbg(&ihost->pdev->dev,
"%s: idev=%p, wait done, device is %s\n",
__func__, idev,
test_bit(IDEV_TXRX_SUSPENDED, &idev->flags)
? "<suspended>" : "<deallocated!>");
"%s: idev=%p, ireq=%p; started_request_count=%d, "
"about to wait\n",
__func__, idev, ireq, idev->started_request_count);
if (ireq) {
/* Terminate a specific TC. */
sci_remote_device_terminate_req(ihost, idev, 0, ireq);
spin_unlock_irqrestore(&ihost->scic_lock, flags);
wait_event(ihost->eventq, !test_bit(IREQ_ACTIVE,
&ireq->flags));
} else
dev_dbg(scirdev_to_dev(idev),
"%s: sci_remote_device_suspend failed, "
"status = %d\n", __func__, status);
} else {
/* Terminate all TCs. */
sci_remote_device_terminate_requests(idev);
spin_unlock_irqrestore(&ihost->scic_lock, flags);
wait_event(ihost->eventq,
idev->started_request_count == 0);
}
dev_dbg(&ihost->pdev->dev, "%s: idev=%p, wait done\n",
__func__, idev);
isci_put_device(idev);
}
return status;
}
/**
* isci_remote_device_not_ready() - This function is called by the ihost when
* the remote device is not ready. We mark the isci device as ready (not
* "ready_for_io") and signal the waiting proccess.
* @isci_host: This parameter specifies the isci host object.
* @isci_device: This parameter specifies the remote device
*
* sci_lock is held on entrance to this function.
*/
static void isci_remote_device_not_ready(struct isci_host *ihost,
struct isci_remote_device *idev,
u32 reason)
{
dev_dbg(&ihost->pdev->dev,
"%s: isci_device = %p\n", __func__, idev);
switch (reason) {
case SCIC_REMOTE_DEVICE_NOT_READY_STOP_REQUESTED:
set_bit(IDEV_GONE, &idev->flags);
break;
case SCIC_REMOTE_DEVICE_NOT_READY_SATA_SDB_ERROR_FIS_RECEIVED:
set_bit(IDEV_IO_NCQERROR, &idev->flags);
/* Suspend the remote device so the I/O can be terminated. */
sci_remote_device_suspend(idev);
/* Kill all outstanding requests for the device. */
sci_remote_device_terminate_requests(idev);
/* Fall through into the default case... */
default:
clear_bit(IDEV_IO_READY, &idev->flags);
break;
}
}
/* called once the remote node context is ready to be freed.
* The remote device can now report that its stop operation is complete. none
*/
......@@ -196,36 +225,10 @@ static void rnc_destruct_done(void *_dev)
sci_change_state(&idev->sm, SCI_DEV_STOPPED);
}
static enum sci_status sci_remote_device_terminate_requests_checkabort(
struct isci_remote_device *idev,
int check_abort_pending)
{
struct isci_host *ihost = idev->owning_port->owning_controller;
enum sci_status status = SCI_SUCCESS;
u32 i;
for (i = 0; i < SCI_MAX_IO_REQUESTS; i++) {
struct isci_request *ireq = ihost->reqs[i];
enum sci_status s;
if (!test_bit(IREQ_ACTIVE, &ireq->flags) ||
(ireq->target_device != idev) ||
(check_abort_pending && !test_bit(IREQ_PENDING_ABORT,
&ireq->flags)))
continue;
s = sci_controller_terminate_request(ihost, idev, ireq);
if (s != SCI_SUCCESS)
status = s;
}
return status;
}
enum sci_status sci_remote_device_terminate_requests(
struct isci_remote_device *idev)
{
return sci_remote_device_terminate_requests_checkabort(idev, 0);
return sci_remote_device_terminate_reqs_checkabort(idev, 0);
}
enum sci_status sci_remote_device_stop(struct isci_remote_device *idev,
......@@ -771,10 +774,6 @@ enum sci_status sci_remote_device_start_task(struct isci_host *ihost,
if (status != SCI_SUCCESS)
return status;
status = sci_remote_node_context_start_task(&idev->rnc, ireq);
if (status != SCI_SUCCESS)
goto out;
status = sci_request_start(ireq);
if (status != SCI_SUCCESS)
goto out;
......@@ -796,8 +795,9 @@ enum sci_status sci_remote_device_start_task(struct isci_host *ihost,
sci_remote_node_context_suspend(
&idev->rnc, SCI_SOFTWARE_SUSPENSION,
SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT, NULL, NULL);
sci_remote_node_context_resume(
&idev->rnc, sci_remote_device_continue_request, idev);
status = sci_remote_node_context_start_task(&idev->rnc, ireq,
sci_remote_device_continue_request, idev);
out:
sci_remote_device_start_request(idev, ireq, status);
......@@ -811,7 +811,9 @@ enum sci_status sci_remote_device_start_task(struct isci_host *ihost,
if (status != SCI_SUCCESS)
return status;
status = sci_remote_node_context_start_task(&idev->rnc, ireq);
/* Resume the RNC as needed: */
status = sci_remote_node_context_start_task(&idev->rnc, ireq,
NULL, NULL);
if (status != SCI_SUCCESS)
break;
......@@ -1322,20 +1324,6 @@ static enum sci_status isci_remote_device_construct(struct isci_port *iport,
return status;
}
void isci_remote_device_nuke_requests(struct isci_host *ihost, struct isci_remote_device *idev)
{
DECLARE_COMPLETION_ONSTACK(aborted_task_completion);
dev_dbg(&ihost->pdev->dev,
"%s: idev = %p\n", __func__, idev);
/* Cleanup all requests pending for this device. */
isci_terminate_pending_requests(ihost, idev);
dev_dbg(&ihost->pdev->dev,
"%s: idev = %p, done\n", __func__, idev);
}
/**
* This function builds the isci_remote_device when a libsas dev_found message
* is received.
......@@ -1495,32 +1483,28 @@ int isci_remote_device_found(struct domain_device *dev)
return status == SCI_SUCCESS ? 0 : -ENODEV;
}
enum sci_status isci_remote_device_reset(
enum sci_status isci_remote_device_suspend_terminate(
struct isci_host *ihost,
struct isci_remote_device *idev)
struct isci_remote_device *idev,
struct isci_request *ireq)
{
unsigned long flags;
enum sci_status status;
/* Put the device into a reset state so the suspension will not
* automatically resume.
*/
/* Put the device into suspension. */
spin_lock_irqsave(&ihost->scic_lock, flags);
status = sci_remote_device_reset(idev);
sci_remote_device_suspend(idev);
spin_unlock_irqrestore(&ihost->scic_lock, flags);
if (status != SCI_SUCCESS) {
dev_dbg(&ihost->pdev->dev,
"%s: sci_remote_device_reset(%p) returned %d!\n",
__func__, idev, status);
return status;
}
/* Wait for the device suspend. */
status = isci_remote_device_suspend(ihost, idev);
if (status != SCI_SUCCESS) {
/* Terminate and wait for the completions. */
status = isci_remote_device_terminate_requests(ihost, idev, ireq);
if (status != SCI_SUCCESS)
dev_dbg(&ihost->pdev->dev,
"%s: isci_remote_device_suspend(%p) returned %d!\n",
"%s: isci_remote_device_terminate_requests(%p) "
"returned %d!\n",
__func__, idev, status);
}
/* NOTE: RNC resumption is left to the caller! */
return status;
}
......@@ -1533,7 +1517,7 @@ int isci_remote_device_is_safe_to_abort(
enum sci_status sci_remote_device_abort_requests_pending_abort(
struct isci_remote_device *idev)
{
return sci_remote_device_terminate_requests_checkabort(idev, 1);
return sci_remote_device_terminate_reqs_checkabort(idev, 1);
}
enum sci_status isci_remote_device_reset_complete(
......@@ -1545,7 +1529,6 @@ enum sci_status isci_remote_device_reset_complete(
spin_lock_irqsave(&ihost->scic_lock, flags);
status = sci_remote_device_reset_complete(idev);
sci_remote_device_resume(idev, NULL, NULL);
spin_unlock_irqrestore(&ihost->scic_lock, flags);
return status;
......
......@@ -85,7 +85,6 @@ struct isci_remote_device {
#define IDEV_GONE 3
#define IDEV_IO_READY 4
#define IDEV_IO_NCQERROR 5
#define IDEV_TXRX_SUSPENDED 6
unsigned long flags;
struct kref kref;
struct isci_port *isci_port;
......@@ -107,10 +106,8 @@ struct isci_remote_device {
/* device reference routines must be called under sci_lock */
static inline struct isci_remote_device *isci_get_device(
struct domain_device *dev)
struct isci_remote_device *idev)
{
struct isci_remote_device *idev = dev->lldd_dev;
if (idev)
kref_get(&idev->kref);
return idev;
......@@ -378,4 +375,14 @@ enum sci_status isci_remote_device_reset(
enum sci_status isci_remote_device_reset_complete(
struct isci_host *ihost,
struct isci_remote_device *idev);
enum sci_status isci_remote_device_suspend_terminate(
struct isci_host *ihost,
struct isci_remote_device *idev,
struct isci_request *ireq);
enum sci_status isci_remote_device_terminate_requests(
struct isci_host *ihost,
struct isci_remote_device *idev,
struct isci_request *ireq);
#endif /* !defined(_ISCI_REMOTE_DEVICE_H_) */
......@@ -317,8 +317,6 @@ static void sci_remote_node_context_tx_rx_suspended_state_enter(struct sci_base_
struct isci_remote_device *idev = rnc_to_dev(rnc);
struct isci_host *ihost = idev->owning_port->owning_controller;
set_bit(IDEV_TXRX_SUSPENDED, &idev->flags);
/* Terminate outstanding requests pending abort. */
sci_remote_device_abort_requests_pending_abort(idev);
......@@ -326,16 +324,6 @@ static void sci_remote_node_context_tx_rx_suspended_state_enter(struct sci_base_
sci_remote_node_context_continue_state_transitions(rnc);
}
static void sci_remote_node_context_tx_rx_suspended_state_exit(
struct sci_base_state_machine *sm)
{
struct sci_remote_node_context *rnc
= container_of(sm, typeof(*rnc), sm);
struct isci_remote_device *idev = rnc_to_dev(rnc);
clear_bit(IDEV_TXRX_SUSPENDED, &idev->flags);
}
static void sci_remote_node_context_await_suspend_state_exit(
struct sci_base_state_machine *sm)
{
......@@ -366,8 +354,6 @@ static const struct sci_base_state sci_remote_node_context_state_table[] = {
},
[SCI_RNC_TX_RX_SUSPENDED] = {
.enter_state = sci_remote_node_context_tx_rx_suspended_state_enter,
.exit_state
= sci_remote_node_context_tx_rx_suspended_state_exit,
},
[SCI_RNC_AWAIT_SUSPENSION] = {
.exit_state = sci_remote_node_context_await_suspend_state_exit,
......@@ -671,8 +657,11 @@ enum sci_status sci_remote_node_context_start_io(struct sci_remote_node_context
}
}
enum sci_status sci_remote_node_context_start_task(struct sci_remote_node_context *sci_rnc,
struct isci_request *ireq)
enum sci_status sci_remote_node_context_start_task(
struct sci_remote_node_context *sci_rnc,
struct isci_request *ireq,
scics_sds_remote_node_context_callback cb_fn,
void *cb_p)
{
enum scis_sds_remote_node_context_states state;
......@@ -684,7 +673,7 @@ enum sci_status sci_remote_node_context_start_task(struct sci_remote_node_contex
return SCI_SUCCESS;
case SCI_RNC_TX_SUSPENDED:
case SCI_RNC_TX_RX_SUSPENDED:
sci_remote_node_context_resume(sci_rnc, NULL, NULL);
sci_remote_node_context_resume(sci_rnc, cb_fn, cb_p);
return SCI_SUCCESS;
default:
dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
......
......@@ -211,7 +211,9 @@ enum sci_status sci_remote_node_context_resume(struct sci_remote_node_context *s
scics_sds_remote_node_context_callback cb_fn,
void *cb_p);
enum sci_status sci_remote_node_context_start_task(struct sci_remote_node_context *sci_rnc,
struct isci_request *ireq);
struct isci_request *ireq,
scics_sds_remote_node_context_callback cb_fn,
void *cb_p);
enum sci_status sci_remote_node_context_start_io(struct sci_remote_node_context *sci_rnc,
struct isci_request *ireq);
int sci_remote_node_context_is_safe_to_abort(
......
......@@ -2491,9 +2491,6 @@ static void isci_request_process_response_iu(
* @request: This parameter is the completed isci_request object.
* @response_ptr: This parameter specifies the service response for the I/O.
* @status_ptr: This parameter specifies the exec status for the I/O.
* @complete_to_host_ptr: This parameter specifies the action to be taken by
* the LLDD with respect to completing this request or forcing an abort
* condition on the I/O.
* @open_rej_reason: This parameter specifies the encoded reason for the
* abandon-class reject.
*
......@@ -2504,14 +2501,12 @@ static void isci_request_set_open_reject_status(
struct sas_task *task,
enum service_response *response_ptr,
enum exec_status *status_ptr,
enum isci_completion_selection *complete_to_host_ptr,
enum sas_open_rej_reason open_rej_reason)
{
/* Task in the target is done. */
set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
*response_ptr = SAS_TASK_UNDELIVERED;
*status_ptr = SAS_OPEN_REJECT;
*complete_to_host_ptr = isci_perform_normal_io_completion;
task->task_status.open_rej_reason = open_rej_reason;
}
......@@ -2521,9 +2516,6 @@ static void isci_request_set_open_reject_status(
* @request: This parameter is the completed isci_request object.
* @response_ptr: This parameter specifies the service response for the I/O.
* @status_ptr: This parameter specifies the exec status for the I/O.
* @complete_to_host_ptr: This parameter specifies the action to be taken by
* the LLDD with respect to completing this request or forcing an abort
* condition on the I/O.
*
* none.
*/
......@@ -2532,8 +2524,7 @@ static void isci_request_handle_controller_specific_errors(
struct isci_request *request,
struct sas_task *task,
enum service_response *response_ptr,
enum exec_status *status_ptr,
enum isci_completion_selection *complete_to_host_ptr)
enum exec_status *status_ptr)
{
unsigned int cstatus;
......@@ -2574,9 +2565,6 @@ static void isci_request_handle_controller_specific_errors(
*status_ptr = SAS_ABORTED_TASK;
set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
*complete_to_host_ptr =
isci_perform_normal_io_completion;
} else {
/* Task in the target is not done. */
*response_ptr = SAS_TASK_UNDELIVERED;
......@@ -2587,9 +2575,6 @@ static void isci_request_handle_controller_specific_errors(
*status_ptr = SAM_STAT_TASK_ABORTED;
clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
*complete_to_host_ptr =
isci_perform_error_io_completion;
}
break;
......@@ -2618,8 +2603,6 @@ static void isci_request_handle_controller_specific_errors(
*status_ptr = SAS_ABORTED_TASK;
set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
*complete_to_host_ptr = isci_perform_normal_io_completion;
break;
......@@ -2630,7 +2613,7 @@ static void isci_request_handle_controller_specific_errors(
isci_request_set_open_reject_status(
request, task, response_ptr, status_ptr,
complete_to_host_ptr, SAS_OREJ_WRONG_DEST);
SAS_OREJ_WRONG_DEST);
break;
case SCU_TASK_OPEN_REJECT_ZONE_VIOLATION:
......@@ -2640,56 +2623,56 @@ static void isci_request_handle_controller_specific_errors(
*/
isci_request_set_open_reject_status(
request, task, response_ptr, status_ptr,
complete_to_host_ptr, SAS_OREJ_RESV_AB0);
SAS_OREJ_RESV_AB0);
break;
case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_1:
isci_request_set_open_reject_status(
request, task, response_ptr, status_ptr,
complete_to_host_ptr, SAS_OREJ_RESV_AB1);
SAS_OREJ_RESV_AB1);
break;
case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_2:
isci_request_set_open_reject_status(
request, task, response_ptr, status_ptr,
complete_to_host_ptr, SAS_OREJ_RESV_AB2);
SAS_OREJ_RESV_AB2);
break;
case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_3:
isci_request_set_open_reject_status(
request, task, response_ptr, status_ptr,
complete_to_host_ptr, SAS_OREJ_RESV_AB3);
SAS_OREJ_RESV_AB3);
break;
case SCU_TASK_OPEN_REJECT_BAD_DESTINATION:
isci_request_set_open_reject_status(
request, task, response_ptr, status_ptr,
complete_to_host_ptr, SAS_OREJ_BAD_DEST);
SAS_OREJ_BAD_DEST);
break;
case SCU_TASK_OPEN_REJECT_STP_RESOURCES_BUSY:
isci_request_set_open_reject_status(
request, task, response_ptr, status_ptr,
complete_to_host_ptr, SAS_OREJ_STP_NORES);
SAS_OREJ_STP_NORES);
break;
case SCU_TASK_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED:
isci_request_set_open_reject_status(
request, task, response_ptr, status_ptr,
complete_to_host_ptr, SAS_OREJ_EPROTO);
SAS_OREJ_EPROTO);
break;
case SCU_TASK_OPEN_REJECT_CONNECTION_RATE_NOT_SUPPORTED:
isci_request_set_open_reject_status(
request, task, response_ptr, status_ptr,
complete_to_host_ptr, SAS_OREJ_CONN_RATE);
SAS_OREJ_CONN_RATE);
break;
case SCU_TASK_DONE_LL_R_ERR:
......@@ -2721,95 +2704,12 @@ static void isci_request_handle_controller_specific_errors(
*response_ptr = SAS_TASK_UNDELIVERED;
*status_ptr = SAM_STAT_TASK_ABORTED;
if (task->task_proto == SAS_PROTOCOL_SMP) {
if (task->task_proto == SAS_PROTOCOL_SMP)
set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
*complete_to_host_ptr = isci_perform_normal_io_completion;
} else {
else
clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
*complete_to_host_ptr = isci_perform_error_io_completion;
}
break;
}
}
/**
* isci_task_save_for_upper_layer_completion() - This function saves the
* request for later completion to the upper layer driver.
* @host: This parameter is a pointer to the host on which the the request
* should be queued (either as an error or success).
* @request: This parameter is the completed request.
* @response: This parameter is the response code for the completed task.
* @status: This parameter is the status code for the completed task.
*
* none.
*/
static void isci_task_save_for_upper_layer_completion(
struct isci_host *host,
struct isci_request *request,
enum service_response response,
enum exec_status status,
enum isci_completion_selection task_notification_selection)
{
struct sas_task *task = isci_request_access_task(request);
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.
*/
switch (task_notification_selection) {
case isci_perform_normal_io_completion:
/* Normal notification (task_done) */
/* 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:
/* No notification to libsas because this request is
* already in the abort path.
*/
/* Wake up whatever process was waiting for this
* request to complete.
*/
WARN_ON(request->io_request_completion == NULL);
if (request->io_request_completion != NULL) {
/* Signal whoever is waiting that this
* request is complete.
*/
complete(request->io_request_completion);
}
break;
case isci_perform_error_io_completion:
/* Use sas_task_abort */
/* Add to the aborted list. */
list_add(&request->completed_node,
&host->requests_to_errorback);
break;
default:
/* Add to the error to libsas list. */
list_add(&request->completed_node,
&host->requests_to_errorback);
break;
}
dev_dbg(&host->pdev->dev,
"%s: %d - task = %p, response=%d (%d), status=%d (%d)\n",
__func__, task_notification_selection, task,
(task) ? task->task_status.resp : 0, response,
(task) ? task->task_status.stat : 0, status);
}
static void isci_process_stp_response(struct sas_task *task, struct dev_to_host_fis *fis)
......@@ -2844,9 +2744,6 @@ static void isci_request_io_request_complete(struct isci_host *ihost,
struct isci_remote_device *idev = request->target_device;
enum service_response response = SAS_TASK_UNDELIVERED;
enum exec_status status = SAS_ABORTED_TASK;
enum isci_request_status request_status;
enum isci_completion_selection complete_to_host
= isci_perform_normal_io_completion;
dev_dbg(&ihost->pdev->dev,
"%s: request = %p, task = %p,\n"
......@@ -2857,113 +2754,7 @@ static void isci_request_io_request_complete(struct isci_host *ihost,
task->data_dir,
completion_status);
spin_lock(&request->state_lock);
request_status = request->status;
/* Decode the request status. Note that if the request has been
* aborted by a task management function, we don't care
* what the status is.
*/
switch (request_status) {
case aborted:
/* "aborted" indicates that the request was aborted by a task
* management function, since once a task management request is
* perfomed by the device, the request only completes because
* of the subsequent driver terminate.
*
* Aborted also means an external thread is explicitly managing
* this request, so that we do not complete it up the stack.
*
* The target is still there (since the TMF was successful).
*/
set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
response = SAS_TASK_COMPLETE;
/* See if the device has been/is being stopped. Note
* that we ignore the quiesce state, since we are
* concerned about the actual device state.
*/
if (!idev)
status = SAS_DEVICE_UNKNOWN;
else
status = SAS_ABORTED_TASK;
complete_to_host = isci_perform_aborted_io_completion;
/* This was an aborted request. */
spin_unlock(&request->state_lock);
break;
case aborting:
/* aborting means that the task management function tried and
* failed to abort the request. We need to note the request
* as SAS_TASK_UNDELIVERED, so that the scsi mid layer marks the
* target as down.
*
* Aborting also means an external thread is explicitly managing
* this request, so that we do not complete it up the stack.
*/
set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
response = SAS_TASK_UNDELIVERED;
if (!idev)
/* The device has been /is being stopped. Note that
* we ignore the quiesce state, since we are
* concerned about the actual device state.
*/
status = SAS_DEVICE_UNKNOWN;
else
status = SAS_PHY_DOWN;
complete_to_host = isci_perform_aborted_io_completion;
/* This was an aborted request. */
spin_unlock(&request->state_lock);
break;
case terminating:
/* This was an terminated request. This happens when
* the I/O is being terminated because of an action on
* the device (reset, tear down, etc.), and the I/O needs
* to be completed up the stack.
*/
set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
response = SAS_TASK_UNDELIVERED;
/* See if the device has been/is being stopped. Note
* that we ignore the quiesce state, since we are
* concerned about the actual device state.
*/
if (!idev)
status = SAS_DEVICE_UNKNOWN;
else
status = SAS_ABORTED_TASK;
complete_to_host = isci_perform_aborted_io_completion;
/* This was a terminated request. */
spin_unlock(&request->state_lock);
break;
case dead:
/* This was a terminated request that timed-out during the
* termination process. There is no task to complete to
* libsas.
*/
complete_to_host = isci_perform_normal_io_completion;
spin_unlock(&request->state_lock);
break;
default:
/* The request is done from an SCU HW perspective. */
request->status = completed;
spin_unlock(&request->state_lock);
/* This is an active request being completed from the core. */
switch (completion_status) {
......@@ -2971,9 +2762,7 @@ static void isci_request_io_request_complete(struct isci_host *ihost,
case SCI_IO_FAILURE_RESPONSE_VALID:
dev_dbg(&ihost->pdev->dev,
"%s: SCI_IO_FAILURE_RESPONSE_VALID (%p/%p)\n",
__func__,
request,
task);
__func__, request, task);
if (sas_protocol_ata(task->task_proto)) {
isci_process_stp_response(task, &request->stp.rsp);
......@@ -3029,27 +2818,21 @@ static void isci_request_io_request_complete(struct isci_host *ihost,
dev_dbg(&ihost->pdev->dev,
"%s: SCI_IO_SUCCESS_IO_DONE_EARLY %d\n",
__func__,
status);
__func__, status);
} else
dev_dbg(&ihost->pdev->dev,
"%s: SCI_IO_SUCCESS\n",
dev_dbg(&ihost->pdev->dev, "%s: SCI_IO_SUCCESS\n",
__func__);
break;
case SCI_IO_FAILURE_TERMINATED:
dev_dbg(&ihost->pdev->dev,
"%s: SCI_IO_FAILURE_TERMINATED (%p/%p)\n",
__func__,
request,
task);
__func__, request, task);
/* The request was terminated explicitly. No handling
* is needed in the SCSI error handler path.
*/
set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
/* The request was terminated explicitly. */
clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
response = SAS_TASK_UNDELIVERED;
/* See if the device has been/is being stopped. Note
......@@ -3060,16 +2843,13 @@ static void isci_request_io_request_complete(struct isci_host *ihost,
status = SAS_DEVICE_UNKNOWN;
else
status = SAS_ABORTED_TASK;
complete_to_host = isci_perform_normal_io_completion;
break;
case SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR:
isci_request_handle_controller_specific_errors(
idev, request, task, &response, &status,
&complete_to_host);
isci_request_handle_controller_specific_errors(idev, request,
task, &response,
&status);
break;
case SCI_IO_FAILURE_REMOTE_DEVICE_RESET_REQUIRED:
......@@ -3088,7 +2868,6 @@ static void isci_request_io_request_complete(struct isci_host *ihost,
response = SAS_TASK_UNDELIVERED;
status = SAM_STAT_TASK_ABORTED;
complete_to_host = isci_perform_error_io_completion;
clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
break;
......@@ -3101,7 +2880,6 @@ static void isci_request_io_request_complete(struct isci_host *ihost,
else
status = SAS_ABORTED_TASK;
complete_to_host = isci_perform_normal_io_completion;
set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
break;
......@@ -3124,15 +2902,10 @@ static void isci_request_io_request_complete(struct isci_host *ihost,
else
status = SAS_ABORTED_TASK;
if (SAS_PROTOCOL_SMP == task->task_proto) {
if (SAS_PROTOCOL_SMP == task->task_proto)
set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
complete_to_host = isci_perform_normal_io_completion;
} else {
else
clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
complete_to_host = isci_perform_error_io_completion;
}
break;
}
break;
}
......@@ -3167,10 +2940,24 @@ static void isci_request_io_request_complete(struct isci_host *ihost,
break;
}
/* Put the completed request on the correct list */
isci_task_save_for_upper_layer_completion(ihost, request, response,
status, complete_to_host
);
spin_lock_irqsave(&task->task_state_lock, task_flags);
task->task_status.resp = response;
task->task_status.stat = status;
if (test_bit(IREQ_COMPLETE_IN_TARGET, &request->flags)) {
/* Normal notification (task_done) */
task->task_state_flags |= SAS_TASK_STATE_DONE;
task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR |
SAS_TASK_STATE_PENDING);
}
spin_unlock_irqrestore(&task->task_state_lock, task_flags);
/* Add to the completed list. */
list_add(&request->completed_node, &ihost->requests_to_complete);
/* Take the request off the device's pending request list. */
list_del_init(&request->dev_node);
/* complete the io request to the core. */
sci_controller_complete_io(ihost, request->target_device, request);
......@@ -3626,7 +3413,6 @@ static struct isci_request *isci_request_from_tag(struct isci_host *ihost, u16 t
ireq->num_sg_entries = 0;
INIT_LIST_HEAD(&ireq->completed_node);
INIT_LIST_HEAD(&ireq->dev_node);
isci_request_change_state(ireq, allocated);
return ireq;
}
......@@ -3721,15 +3507,12 @@ int isci_request_execute(struct isci_host *ihost, struct isci_remote_device *ide
*/
list_add(&ireq->dev_node, &idev->reqs_in_process);
if (status == SCI_SUCCESS) {
isci_request_change_state(ireq, started);
} else {
if (status != SCI_SUCCESS) {
/* The request did not really start in the
* hardware, so clear the request handle
* here so no terminations will be done.
*/
set_bit(IREQ_TERMINATED, &ireq->flags);
isci_request_change_state(ireq, completed);
}
spin_unlock_irqrestore(&ihost->scic_lock, flags);
......
......@@ -60,23 +60,6 @@
#include "host.h"
#include "scu_task_context.h"
/**
* struct isci_request_status - This enum defines the possible states of an I/O
* request.
*
*
*/
enum isci_request_status {
unallocated = 0x00,
allocated = 0x01,
started = 0x02,
completed = 0x03,
aborting = 0x04,
aborted = 0x05,
terminating = 0x06,
dead = 0x07
};
/**
* isci_stp_request - extra request infrastructure to handle pio/atapi protocol
* @pio_len - number of bytes requested at PIO setup
......@@ -97,13 +80,13 @@ struct isci_stp_request {
};
struct isci_request {
enum isci_request_status status;
#define IREQ_COMPLETE_IN_TARGET 0
#define IREQ_TERMINATED 1
#define IREQ_TMF 2
#define IREQ_ACTIVE 3
#define IREQ_PENDING_ABORT 4 /* Set == device was not suspended yet */
#define IREQ_TC_ABORT_POSTED 5
#define IREQ_ABORT_PATH_ACTIVE 6
unsigned long flags;
/* XXX kill ttype and ttype_ptr, allocate full sas_task */
union ttype_ptr_union {
......@@ -115,7 +98,6 @@ struct isci_request {
struct list_head completed_node;
/* For use in the reqs_in_process list: */
struct list_head dev_node;
spinlock_t state_lock;
dma_addr_t request_daddr;
dma_addr_t zero_scatter_daddr;
unsigned int num_sg_entries;
......@@ -304,92 +286,6 @@ sci_io_request_get_dma_addr(struct isci_request *ireq, void *virt_addr)
return ireq->request_daddr + (requested_addr - base_addr);
}
/**
* isci_request_change_state() - This function sets the status of the request
* object.
* @request: This parameter points to the isci_request object
* @status: This Parameter is the new status of the object
*
*/
static inline enum isci_request_status
isci_request_change_state(struct isci_request *isci_request,
enum isci_request_status status)
{
enum isci_request_status old_state;
unsigned long flags;
dev_dbg(&isci_request->isci_host->pdev->dev,
"%s: isci_request = %p, state = 0x%x\n",
__func__,
isci_request,
status);
BUG_ON(isci_request == NULL);
spin_lock_irqsave(&isci_request->state_lock, flags);
old_state = isci_request->status;
isci_request->status = status;
spin_unlock_irqrestore(&isci_request->state_lock, flags);
return old_state;
}
/**
* isci_request_change_started_to_newstate() - This function sets the status of
* the request object.
* @request: This parameter points to the isci_request object
* @status: This Parameter is the new status of the object
*
* state previous to any change.
*/
static inline enum isci_request_status
isci_request_change_started_to_newstate(struct isci_request *isci_request,
struct completion *completion_ptr,
enum isci_request_status newstate)
{
enum isci_request_status old_state;
unsigned long flags;
spin_lock_irqsave(&isci_request->state_lock, flags);
old_state = isci_request->status;
if (old_state == started || old_state == aborting) {
BUG_ON(isci_request->io_request_completion != NULL);
isci_request->io_request_completion = completion_ptr;
isci_request->status = newstate;
}
spin_unlock_irqrestore(&isci_request->state_lock, flags);
dev_dbg(&isci_request->isci_host->pdev->dev,
"%s: isci_request = %p, old_state = 0x%x\n",
__func__,
isci_request,
old_state);
return old_state;
}
/**
* isci_request_change_started_to_aborted() - This function sets the status of
* the request object.
* @request: This parameter points to the isci_request object
* @completion_ptr: This parameter is saved as the kernel completion structure
* signalled when the old request completes.
*
* state previous to any change.
*/
static inline enum isci_request_status
isci_request_change_started_to_aborted(struct isci_request *isci_request,
struct completion *completion_ptr)
{
return isci_request_change_started_to_newstate(isci_request,
completion_ptr,
aborted);
}
#define isci_request_access_task(req) ((req)->ttype_ptr.io_task_ptr)
#define isci_request_access_tmf(req) ((req)->ttype_ptr.tmf_task_ptr)
......@@ -399,8 +295,6 @@ struct isci_request *isci_tmf_request_from_tag(struct isci_host *ihost,
u16 tag);
int isci_request_execute(struct isci_host *ihost, struct isci_remote_device *idev,
struct sas_task *task, u16 tag);
void isci_terminate_pending_requests(struct isci_host *ihost,
struct isci_remote_device *idev);
enum sci_status
sci_task_request_construct(struct isci_host *ihost,
struct isci_remote_device *idev,
......
此差异已折叠。
......@@ -62,19 +62,6 @@
struct isci_request;
/**
* enum isci_tmf_cb_state - This enum defines the possible states in which the
* TMF callback function is invoked during the TMF execution process.
*
*
*/
enum isci_tmf_cb_state {
isci_tmf_init_state = 0,
isci_tmf_started,
isci_tmf_timed_out
};
/**
* enum isci_tmf_function_codes - This enum defines the possible preparations
* of task management requests.
......@@ -87,6 +74,7 @@ enum isci_tmf_function_codes {
isci_tmf_ssp_task_abort = TMF_ABORT_TASK,
isci_tmf_ssp_lun_reset = TMF_LU_RESET,
};
/**
* struct isci_tmf - This class represents the task management object which
* acts as an interface to libsas for processing task management requests
......@@ -106,15 +94,6 @@ struct isci_tmf {
u16 io_tag;
enum isci_tmf_function_codes tmf_code;
int status;
/* The optional callback function allows the user process to
* track the TMF transmit / timeout conditions.
*/
void (*cb_state_func)(
enum isci_tmf_cb_state,
struct isci_tmf *, void *);
void *cb_data;
};
static inline void isci_print_tmf(struct isci_host *ihost, struct isci_tmf *tmf)
......@@ -208,113 +187,4 @@ int isci_queuecommand(
struct scsi_cmnd *scsi_cmd,
void (*donefunc)(struct scsi_cmnd *));
/**
* enum isci_completion_selection - This enum defines the possible actions to
* take with respect to a given request's notification back to libsas.
*
*
*/
enum isci_completion_selection {
isci_perform_normal_io_completion, /* Normal notify (task_done) */
isci_perform_aborted_io_completion, /* No notification. */
isci_perform_error_io_completion /* Use sas_task_abort */
};
/**
* isci_task_set_completion_status() - This function sets the completion status
* for the request.
* @task: This parameter is the completed request.
* @response: This parameter is the response code for the completed task.
* @status: This parameter is the status code for the completed task.
*
* @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,
enum isci_completion_selection task_notification_selection)
{
unsigned long flags;
spin_lock_irqsave(&task->task_state_lock, flags);
/* 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) {
/* Fail the I/O to make sure it goes into the error path. */
response = SAS_TASK_UNDELIVERED;
status = SAM_STAT_TASK_ABORTED;
task_notification_selection = isci_perform_error_io_completion;
}
task->task_status.resp = response;
task->task_status.stat = status;
switch (task->task_proto) {
case SAS_PROTOCOL_SATA:
case SAS_PROTOCOL_STP:
case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
if (task_notification_selection
== isci_perform_error_io_completion) {
/* SATA/STP I/O has it's own means of scheduling device
* error handling on the normal path.
*/
task_notification_selection
= isci_perform_normal_io_completion;
}
break;
default:
break;
}
switch (task_notification_selection) {
case isci_perform_error_io_completion:
if (task->task_proto == SAS_PROTOCOL_SMP) {
/* There is no error escalation in the SMP case.
* Convert to a normal completion to avoid the
* timeout in the discovery path and to let the
* next action take place quickly.
*/
task_notification_selection
= isci_perform_normal_io_completion;
/* Fall through to the normal case... */
} else {
/* Use sas_task_abort */
/* Leave SAS_TASK_STATE_DONE clear
* Leave SAS_TASK_AT_INITIATOR set.
*/
break;
}
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) */
task->task_state_flags |= SAS_TASK_STATE_DONE;
task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR |
SAS_TASK_STATE_PENDING);
break;
default:
WARN_ONCE(1, "unknown task_notification_selection: %d\n",
task_notification_selection);
break;
}
spin_unlock_irqrestore(&task->task_state_lock, flags);
return task_notification_selection;
}
#endif /* !defined(_SCI_TASK_H_) */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册