diff options
author | Dan Williams <dan.j.williams@intel.com> | 2011-03-11 21:13:51 +0300 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2011-07-03 14:55:30 +0400 |
commit | 1077a574103177bff22b7cdd155d960f46ac1e8f (patch) | |
tree | 4ccbb76979a661c240464d5a951fbd96893b5586 /drivers/scsi/isci/task.c | |
parent | 34cad85d18d6da1cc11e410046d7572e65b19fcf (diff) | |
download | linux-1077a574103177bff22b7cdd155d960f46ac1e8f.tar.xz |
isci: fix incorrect assumptions about task->dev and task->dev->port being NULL
A domain_device has the same lifetime as its related scsi_target. The
scsi_target is reference counted based on outstanding commands,
therefore it is safe to assume that if we have a valid sas_task that the
->dev pointer is also valid.
The asd_sas_port of a domain_device has the same lifetime as the driver
so it can also never be NULL as long as the sas_task is valid and the
driver is loaded.
This also cleans up isci_task_complete_for_upper_layer(), renames it to
isci_task_refuse() and notices that the isci_completion_selection
parameter was set to isci_perform_normal_io_completion by all callers.
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/scsi/isci/task.c')
-rw-r--r-- | drivers/scsi/isci/task.c | 168 |
1 files changed, 55 insertions, 113 deletions
diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index d00b4c97b85b..d48368002504 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -67,39 +67,36 @@ #include "task.h" /** -* isci_task_complete_for_upper_layer() - This function completes the request -* to the upper layer driver in the case where an I/O needs to be completed -* back in the submit path. -* @host: This parameter is a pointer to the host on which the the request -* should be queued (either as an error or success). -* @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. +* isci_task_refuse() - complete the request to the upper layer driver in +* the case where an I/O needs to be completed back in the submit path. +* @ihost: host on which the the request was queued +* @task: request to complete +* @response: response code for the completed task. +* @status: status code for the completed task. * -* none. */ -static void isci_task_complete_for_upper_layer(struct sas_task *task, - enum service_response response, - enum exec_status status, - enum isci_completion_selection task_notification_selection) +static void isci_task_refuse(struct isci_host *ihost, struct sas_task *task, + enum service_response response, + enum exec_status status) + { - unsigned long flags = 0; - struct Scsi_Host *host = NULL; + enum isci_completion_selection disposition; - task_notification_selection - = isci_task_set_completion_status(task, response, status, - task_notification_selection); + disposition = isci_perform_normal_io_completion; + disposition = isci_task_set_completion_status(task, response, status, + disposition); /* 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) { + * function should not be completed to the host in the regular path. + */ + switch (disposition) { case isci_perform_normal_io_completion: /* Normal notification (task_done) */ - dev_dbg(task->dev->port->ha->dev, + dev_dbg(&ihost->pdev->dev, "%s: Normal - task = %p, response=%d, status=%d\n", __func__, task, response, status); + task->lldd_task = NULL; if (dev_is_sata(task->dev)) { /* Since we are still in the submit path, and since * libsas takes the host lock on behalf of SATA @@ -107,44 +104,36 @@ static void isci_task_complete_for_upper_layer(struct sas_task *task, * before we can call back and report the I/O * submission error. */ - if (task->dev - && task->dev->port - && task->dev->port->ha) { + unsigned long flags; - host = task->dev->port->ha->core.shost; - raw_local_irq_save(flags); - spin_unlock(host->host_lock); - } + raw_local_irq_save(flags); + spin_unlock(ihost->shost->host_lock); task->task_done(task); - if (host) { - spin_lock(host->host_lock); - raw_local_irq_restore(flags); - } + spin_lock(ihost->shost->host_lock); + raw_local_irq_restore(flags); } else task->task_done(task); - - task->lldd_task = NULL; break; case isci_perform_aborted_io_completion: /* No notification because this request is already in the * abort path. */ - dev_warn(task->dev->port->ha->dev, + dev_warn(&ihost->pdev->dev, "%s: Aborted - task = %p, response=%d, status=%d\n", __func__, task, response, status); break; case isci_perform_error_io_completion: /* Use sas_task_abort */ - dev_warn(task->dev->port->ha->dev, + dev_warn(&ihost->pdev->dev, "%s: Error - task = %p, response=%d, status=%d\n", __func__, task, response, status); sas_task_abort(task); break; default: - dev_warn(task->dev->port->ha->dev, + dev_warn(&ihost->pdev->dev, "%s: isci task notification default case!", __func__); sas_task_abort(task); @@ -152,6 +141,10 @@ static void isci_task_complete_for_upper_layer(struct sas_task *task, } } +#define for_each_sas_task(num, task) \ + for (; num > 0; num--,\ + task = list_entry(task->list.next, struct sas_task, list)) + /** * isci_task_execute_task() - This function is one of the SAS Domain Template * functions. This function is called by libsas to send a task down to @@ -164,7 +157,7 @@ static void isci_task_complete_for_upper_layer(struct sas_task *task, */ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags) { - struct isci_host *isci_host; + struct isci_host *ihost = task->dev->port->ha->lldd_ha; struct isci_request *request = NULL; struct isci_remote_device *device; unsigned long flags; @@ -172,60 +165,23 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags) enum sci_status status; enum isci_status device_status; - dev_dbg(task->dev->port->ha->dev, "%s: num=%d\n", __func__, num); - - if ((task->dev == NULL) || (task->dev->port == NULL)) { - - /* Indicate SAS_TASK_UNDELIVERED, so that the scsi midlayer - * removes the target. - */ - isci_task_complete_for_upper_layer( - task, - SAS_TASK_UNDELIVERED, - SAS_DEVICE_UNKNOWN, - isci_perform_normal_io_completion - ); - return 0; /* The I/O was accepted (and failed). */ - } - isci_host = isci_host_from_sas_ha(task->dev->port->ha); + dev_dbg(&ihost->pdev->dev, "%s: num=%d\n", __func__, num); /* Check if we have room for more tasks */ - ret = isci_host_can_queue(isci_host, num); + ret = isci_host_can_queue(ihost, num); if (ret) { - dev_warn(task->dev->port->ha->dev, "%s: queue full\n", __func__); + dev_warn(&ihost->pdev->dev, "%s: queue full\n", __func__); return ret; } - do { - dev_dbg(task->dev->port->ha->dev, + for_each_sas_task(num, task) { + dev_dbg(&ihost->pdev->dev, "task = %p, num = %d; dev = %p; cmd = %p\n", task, num, task->dev, task->uldd_task); - if ((task->dev == NULL) || (task->dev->port == NULL)) { - dev_warn(task->dev->port->ha->dev, - "%s: task %p's port or dev == NULL!\n", - __func__, task); - - /* Indicate SAS_TASK_UNDELIVERED, so that the scsi - * midlayer removes the target. - */ - isci_task_complete_for_upper_layer( - task, - SAS_TASK_UNDELIVERED, - SAS_DEVICE_UNKNOWN, - isci_perform_normal_io_completion - ); - /* We don't have a valid host reference, so we - * can't control the host queueing condition. - */ - goto next_task; - } - device = isci_dev_from_domain_dev(task->dev); - isci_host = isci_host_from_sas_ha(task->dev->port->ha); - if (device) device_status = device->status; else @@ -239,34 +195,28 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags) if (device_status != isci_ready_for_io) { /* Forces a retry from scsi mid layer. */ - dev_warn(task->dev->port->ha->dev, + dev_warn(&ihost->pdev->dev, "%s: task %p: isci_host->status = %d, " "device = %p; device_status = 0x%x\n\n", __func__, task, - isci_host_get_state(isci_host), + isci_host_get_state(ihost), device, device_status); if (device_status == isci_ready) { /* Indicate QUEUE_FULL so that the scsi midlayer * retries. */ - isci_task_complete_for_upper_layer( - task, - SAS_TASK_COMPLETE, - SAS_QUEUE_FULL, - isci_perform_normal_io_completion - ); + isci_task_refuse(ihost, task, + SAS_TASK_COMPLETE, + SAS_QUEUE_FULL); } else { /* Else, the device is going down. */ - isci_task_complete_for_upper_layer( - task, - SAS_TASK_UNDELIVERED, - SAS_DEVICE_UNKNOWN, - isci_perform_normal_io_completion - ); + isci_task_refuse(ihost, task, + SAS_TASK_UNDELIVERED, + SAS_DEVICE_UNKNOWN); } - isci_host_can_dequeue(isci_host, 1); + isci_host_can_dequeue(ihost, 1); } else { /* There is a device and it's ready for I/O. */ spin_lock_irqsave(&task->task_state_lock, flags); @@ -276,12 +226,9 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags) spin_unlock_irqrestore(&task->task_state_lock, flags); - isci_task_complete_for_upper_layer( - task, - SAS_TASK_UNDELIVERED, - SAM_STAT_TASK_ABORTED, - isci_perform_normal_io_completion - ); + isci_task_refuse(ihost, task, + SAS_TASK_UNDELIVERED, + SAM_STAT_TASK_ABORTED); /* The I/O was aborted. */ @@ -290,7 +237,7 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags) spin_unlock_irqrestore(&task->task_state_lock, flags); /* build and send the request. */ - status = isci_request_execute(isci_host, task, &request, + status = isci_request_execute(ihost, task, &request, gfp_flags); if (status != SCI_SUCCESS) { @@ -307,19 +254,14 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags) * SAS_TASK_UNDELIVERED next time * through. */ - isci_task_complete_for_upper_layer( - task, - SAS_TASK_COMPLETE, - SAS_QUEUE_FULL, - isci_perform_normal_io_completion - ); - isci_host_can_dequeue(isci_host, 1); + isci_task_refuse(ihost, task, + SAS_TASK_COMPLETE, + SAS_QUEUE_FULL); + isci_host_can_dequeue(ihost, 1); } } } -next_task: - task = list_entry(task->list.next, struct sas_task, list); - } while (--num > 0); + } return 0; } |