From 6f231dda68080759f1aed3769896e94c73099f0f Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sat, 2 Jul 2011 22:56:22 -0700 Subject: isci: Intel(R) C600 Series Chipset Storage Control Unit Driver Support for the up to 2x4-port 6Gb/s SAS controllers embedded in the chipset. This is a snapshot of the first publicly available version of the driver, commit 4c1db2d0 in the 'historical' branch. git://git.kernel.org/pub/scm/linux/kernel/git/djbw/isci.git historical Signed-off-by: Maciej Trela Signed-off-by: Dave Jiang Signed-off-by: Edmund Nadolski Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 1691 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1691 insertions(+) create mode 100644 drivers/scsi/isci/task.c (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c new file mode 100644 index 000000000000..5e6f55863407 --- /dev/null +++ b/drivers/scsi/isci/task.c @@ -0,0 +1,1691 @@ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * BSD LICENSE + * + * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include "scic_task_request.h" +#include "scic_remote_device.h" +#include "scic_io_request.h" +#include "scic_sds_remote_device.h" +#include "scic_sds_remote_node_context.h" +#include "isci.h" +#include "request.h" +#include "sata.h" +#include "task.h" + + +/** + * 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 + * hardware. + * @task: This parameter specifies the SAS task to send. + * @num: This parameter specifies the number of tasks to queue. + * @gfp_flags: This parameter specifies the context of this call. + * + * status, zero indicates success. + */ +int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags) +{ + struct isci_host *isci_host; + struct isci_request *request = NULL; + struct isci_remote_device *device; + unsigned long flags; + unsigned long quiesce_flags = 0; + int ret; + enum sci_status status; + + + dev_dbg(task->dev->port->ha->dev, "%s: num=%d\n", __func__, num); + + if (task->task_state_flags & SAS_TASK_STATE_ABORTED) { + + isci_task_complete_for_upper_layer( + task, + SAS_TASK_UNDELIVERED, + SAM_STAT_TASK_ABORTED, + isci_perform_normal_io_completion + ); + + return 0; /* The I/O was accepted (and failed). */ + } + 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); + + /* Check if we have room for more tasks */ + ret = isci_host_can_queue(isci_host, num); + + if (ret) { + dev_warn(task->dev->port->ha->dev, "%s: queue full\n", __func__); + return ret; + } + + do { + dev_dbg(task->dev->port->ha->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. + */ + continue; + } + + device = isci_dev_from_domain_dev(task->dev); + + isci_host = isci_host_from_sas_ha(task->dev->port->ha); + + /* check if the controller hasn't started or if the device + * is ready but not accepting IO. + */ + if (device) { + + spin_lock_irqsave(&device->host_quiesce_lock, + quiesce_flags); + } + /* From this point onward, any process that needs to guarantee + * that there is no kernel I/O being started will have to wait + * for the quiesce spinlock. + */ + + if (isci_host_get_state(isci_host) == isci_starting || + (device && ((isci_remote_device_get_state(device) == isci_ready) || + (isci_remote_device_get_state(device) == isci_host_quiesce)))) { + + /* Forces a retry from scsi mid layer. */ + dev_warn(task->dev->port->ha->dev, + "%s: task %p: isci_host->status = %d, " + "device = %p\n", + __func__, + task, + isci_host_get_state(isci_host), + device); + + if (device) + dev_dbg(task->dev->port->ha->dev, + "%s: device->status = 0x%x\n", + __func__, + isci_remote_device_get_state(device)); + + /* 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_host_can_dequeue(isci_host, 1); + } + /* the device is going down... */ + else if (!device || (isci_ready_for_io != isci_remote_device_get_state(device))) { + + dev_dbg(task->dev->port->ha->dev, + "%s: task %p: isci_host->status = %d, " + "device = %p\n", + __func__, + task, + isci_host_get_state(isci_host), + device); + + if (device) + dev_dbg(task->dev->port->ha->dev, + "%s: device->status = 0x%x\n", + __func__, + isci_remote_device_get_state(device)); + + /* 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 + ); + isci_host_can_dequeue(isci_host, 1); + + } else { + /* build and send the request. */ + status = isci_request_execute(isci_host, task, &request, + gfp_flags); + + if (status == SCI_SUCCESS) { + spin_lock_irqsave(&task->task_state_lock, flags); + task->task_state_flags |= SAS_TASK_AT_INITIATOR; + spin_unlock_irqrestore(&task->task_state_lock, flags); + } else { + /* Indicate QUEUE_FULL so that the scsi + * midlayer retries. if the request + * failed for remote device reasons, + * it gets returned as + * 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); + } + } + if (device) { + spin_unlock_irqrestore(&device->host_quiesce_lock, + quiesce_flags + ); + } + task = list_entry(task->list.next, struct sas_task, list); + } while (--num > 0); + return 0; +} + + + +/** + * isci_task_request_build() - This function builds the task request object. + * @isci_host: This parameter specifies the ISCI host object + * @request: This parameter points to the isci_request object allocated in the + * request construct function. + * @tmf: This parameter is the task management struct to be built + * + * SCI_SUCCESS on successfull completion, or specific failure code. + */ +static enum sci_status isci_task_request_build( + struct isci_host *isci_host, + struct isci_request **isci_request, + struct isci_tmf *isci_tmf) +{ + struct scic_sds_remote_device *sci_device; + enum sci_status status = SCI_FAILURE; + struct isci_request *request; + struct isci_remote_device *isci_device; +/* struct sci_sas_identify_address_frame_protocols dev_protocols; */ + struct smp_discover_response_protocols dev_protocols; + + + dev_dbg(&isci_host->pdev->dev, + "%s: isci_tmf = %p\n", __func__, isci_tmf); + + isci_device = isci_tmf->device; + sci_device = isci_device->sci_device_handle; + + /* do common allocation and init of request object. */ + status = isci_request_alloc_tmf( + isci_host, + isci_tmf, + &request, + isci_device, + GFP_ATOMIC + ); + + if (status != SCI_SUCCESS) + goto out; + + /* let the core do it's construct. */ + status = scic_task_request_construct( + isci_host->core_controller, + sci_device, + SCI_CONTROLLER_INVALID_IO_TAG, + request, + request->sci_request_mem_ptr, + &request->sci_request_handle + ); + + if (status != SCI_SUCCESS) { + dev_warn(&isci_host->pdev->dev, + "%s: scic_task_request_construct failed - " + "status = 0x%x\n", + __func__, + status); + goto errout; + } + + sci_object_set_association( + request->sci_request_handle, + request + ); + + scic_remote_device_get_protocols( + sci_device, + &dev_protocols + ); + + /* let the core do it's protocol + * specific construction. + */ + if (dev_protocols.u.bits.attached_ssp_target) { + + isci_tmf->proto = SAS_PROTOCOL_SSP; + status = scic_task_request_construct_ssp( + request->sci_request_handle + ); + if (status != SCI_SUCCESS) + goto errout; + } + + if (dev_protocols.u.bits.attached_stp_target) { + + isci_tmf->proto = SAS_PROTOCOL_SATA; + status = isci_sata_management_task_request_build(request); + + if (status != SCI_SUCCESS) + goto errout; + } + + goto out; + + errout: + + /* release the dma memory if we fail. */ + isci_request_free(isci_host, request); + request = NULL; + + out: + *isci_request = request; + return status; +} + +/** + * isci_tmf_timeout_cb() - This function is called as a kernel callback when + * the timeout period for the TMF has expired. + * + * + */ +static void isci_tmf_timeout_cb(void *tmf_request_arg) +{ + struct isci_request *request = (struct isci_request *)tmf_request_arg; + struct isci_tmf *tmf = isci_request_access_tmf(request); + enum sci_status status; + + BUG_ON(request->ttype != tmf_task); + + /* This task management request has timed-out. Terminate the request + * so that the request eventually completes to the requestor in the + * request completion callback path. + */ + /* Note - the timer callback function itself has provided spinlock + * exclusion from the start and completion paths. No need to take + * the request->isci_host->scic_lock here. + */ + + if (tmf->timeout_timer != NULL) { + /* Call the users callback, if any. */ + if (tmf->cb_state_func != NULL) + tmf->cb_state_func(isci_tmf_timed_out, tmf, + tmf->cb_data); + + /* Terminate the TMF transmit request. */ + status = scic_controller_terminate_request( + request->isci_host->core_controller, + request->isci_device->sci_device_handle, + request->sci_request_handle + ); + + dev_dbg(&request->isci_host->pdev->dev, + "%s: tmf_request = %p; tmf = %p; status = %d\n", + __func__, request, tmf, status); + } else + dev_dbg(&request->isci_host->pdev->dev, + "%s: timer already canceled! " + "tmf_request = %p; tmf = %p\n", + __func__, request, tmf); + + /* No need to unlock since the caller to this callback is doing it for + * us. + * request->isci_host->scic_lock + */ +} + +/** + * isci_task_execute_tmf() - This function builds and sends a task request, + * then waits for the completion. + * @isci_host: This parameter specifies the ISCI host object + * @tmf: This parameter is the pointer to the task management structure for + * this request. + * @timeout_ms: This parameter specifies the timeout period for the task + * management request. + * + * TMF_RESP_FUNC_COMPLETE on successful completion of the TMF (this includes + * error conditions reported in the IU status), or TMF_RESP_FUNC_FAILED. + */ +int isci_task_execute_tmf( + struct isci_host *isci_host, + struct isci_tmf *tmf, + unsigned long timeout_ms) +{ + DECLARE_COMPLETION_ONSTACK(completion); + enum sci_status status = SCI_FAILURE; + struct scic_sds_remote_device *sci_device; + struct isci_remote_device *isci_device = tmf->device; + struct isci_request *request; + int ret = TMF_RESP_FUNC_FAILED; + unsigned long flags; + + /* sanity check, return TMF_RESP_FUNC_FAILED + * if the device is not there and ready. + */ + if (!isci_device || + ((isci_ready_for_io != isci_remote_device_get_state(isci_device)) && + (isci_host_quiesce != isci_remote_device_get_state(isci_device)))) { + dev_dbg(&isci_host->pdev->dev, + "%s: isci_device = %p not ready (%d)\n", + __func__, + isci_device, + isci_remote_device_get_state(isci_device)); + return TMF_RESP_FUNC_FAILED; + } else + dev_dbg(&isci_host->pdev->dev, + "%s: isci_device = %p\n", + __func__, isci_device); + + sci_device = isci_device->sci_device_handle; + + /* Assign the pointer to the TMF's completion kernel wait structure. */ + tmf->complete = &completion; + + isci_task_request_build( + isci_host, + &request, + tmf + ); + + if (!request) { + dev_warn(&isci_host->pdev->dev, + "%s: isci_task_request_build failed\n", + __func__); + return TMF_RESP_FUNC_FAILED; + } + + /* Allocate the TMF timeout timer. */ + tmf->timeout_timer = isci_timer_create( + &isci_host->timer_list_struct, + isci_host, + request, + isci_tmf_timeout_cb + ); + + spin_lock_irqsave(&isci_host->scic_lock, flags); + + /* Start the timer. */ + if (tmf->timeout_timer) + isci_timer_start(tmf->timeout_timer, timeout_ms); + else + dev_warn(&isci_host->pdev->dev, + "%s: isci_timer_create failed!!!!\n", + __func__); + + /* start the TMF io. */ + status = scic_controller_start_task( + isci_host->core_controller, + sci_device, + request->sci_request_handle, + SCI_CONTROLLER_INVALID_IO_TAG + ); + + if (status != SCI_SUCCESS) { + dev_warn(&isci_host->pdev->dev, + "%s: start_io failed - status = 0x%x, request = %p\n", + __func__, + status, + request); + goto cleanup_request; + } + + /* Call the users callback, if any. */ + if (tmf->cb_state_func != NULL) + tmf->cb_state_func(isci_tmf_started, tmf, tmf->cb_data); + + /* Change the state of the TMF-bearing request to "started". */ + isci_request_change_state(request, started); + + /* add the request to the remote device request list. */ + list_add(&request->dev_node, &isci_device->reqs_in_process); + + spin_unlock_irqrestore(&isci_host->scic_lock, flags); + + /* Wait for the TMF to complete, or a timeout. */ + wait_for_completion(&completion); + + isci_print_tmf(tmf); + + if (tmf->status == SCI_SUCCESS) + ret = TMF_RESP_FUNC_COMPLETE; + else if (tmf->status == SCI_FAILURE_IO_RESPONSE_VALID) { + dev_dbg(&isci_host->pdev->dev, + "%s: tmf.status == " + "SCI_FAILURE_IO_RESPONSE_VALID\n", + __func__); + ret = TMF_RESP_FUNC_COMPLETE; + } + /* Else - leave the default "failed" status alone. */ + + dev_dbg(&isci_host->pdev->dev, + "%s: completed request = %p\n", + __func__, + request); + + if (request->io_request_completion != NULL) { + + /* The fact that this is non-NULL for a TMF request + * means there is a thread waiting for this TMF to + * finish. + */ + complete(request->io_request_completion); + } + + spin_lock_irqsave(&isci_host->scic_lock, flags); + + cleanup_request: + + /* Clean up the timer if needed. */ + if (tmf->timeout_timer) { + isci_timer_stop(tmf->timeout_timer); + isci_timer_free(&isci_host->timer_list_struct, + tmf->timeout_timer); + tmf->timeout_timer = NULL; + } + + spin_unlock_irqrestore(&isci_host->scic_lock, flags); + + isci_request_free(isci_host, request); + + return ret; +} + +void isci_task_build_tmf( + struct isci_tmf *tmf, + struct isci_remote_device *isci_device, + enum isci_tmf_function_codes code, + void (*tmf_sent_cb)(enum isci_tmf_cb_state, + struct isci_tmf *, + void *), + void *cb_data) +{ + dev_dbg(&isci_device->isci_port->isci_host->pdev->dev, + "%s: isci_device = %p\n", __func__, isci_device); + + memset(tmf, 0, sizeof(*tmf)); + + tmf->device = isci_device; + tmf->tmf_code = code; + tmf->timeout_timer = NULL; + tmf->cb_state_func = tmf_sent_cb; + tmf->cb_data = cb_data; +} + +static struct isci_request *isci_task_get_request_from_task( + struct sas_task *task, + struct isci_host **isci_host, + struct isci_remote_device **isci_device) +{ + + struct isci_request *request = NULL; + unsigned long flags; + + spin_lock_irqsave(&task->task_state_lock, flags); + + request = task->lldd_task; + + /* If task is already done, the request isn't valid */ + if (!(task->task_state_flags & SAS_TASK_STATE_DONE) && + (task->task_state_flags & SAS_TASK_AT_INITIATOR) && + (request != NULL)) { + + if (isci_host != NULL) + *isci_host = request->isci_host; + + if (isci_device != NULL) + *isci_device = request->isci_device; + } + + spin_unlock_irqrestore(&task->task_state_lock, flags); + + return request; +} + +/** + * isci_task_validate_request_to_abort() - This function checks the given I/O + * against the "started" state. If the request is still "started", it's + * state is changed to aborted. NOTE: isci_host->scic_lock MUST BE HELD + * BEFORE CALLING THIS FUNCTION. + * @isci_request: This parameter specifies the request object to control. + * @isci_host: This parameter specifies the ISCI host object + * @isci_device: This is the device to which the request is pending. + * @aborted_io_completion: This is a completion structure that will be added to + * the request in case it is changed to aborting; this completion is + * triggered when the request is fully completed. + * + * Either "started" on successful change of the task status to "aborted", or + * "unallocated" if the task cannot be controlled. + */ +static enum isci_request_status isci_task_validate_request_to_abort( + struct isci_request *isci_request, + struct isci_host *isci_host, + struct isci_remote_device *isci_device, + struct completion *aborted_io_completion) +{ + enum isci_request_status old_state = unallocated; + + /* Only abort the task if it's in the + * device's request_in_process list + */ + if (isci_request && !list_empty(&isci_request->dev_node)) { + old_state = isci_request_change_started_to_aborted( + isci_request, aborted_io_completion); + + /* Only abort requests in the started state. */ + if (old_state != started) + old_state = unallocated; + } + + return old_state; +} + +static void isci_request_cleanup_completed_loiterer( + struct isci_host *isci_host, + struct isci_remote_device *isci_device, + struct isci_request *isci_request) +{ + struct sas_task *task = isci_request_access_task(isci_request); + unsigned long flags; + + dev_dbg(&isci_host->pdev->dev, + "%s: isci_device=%p, request=%p, task=%p\n", + __func__, isci_device, isci_request, + isci_request->ttype_ptr.io_task_ptr); + + spin_lock_irqsave(&isci_host->scic_lock, flags); + list_del_init(&isci_request->dev_node); + if (task != NULL) + task->lldd_task = NULL; + spin_unlock_irqrestore(&isci_host->scic_lock, flags); + + isci_request_free(isci_host, isci_request); +} +/** + * isci_terminate_request_core() - This function will terminate the given + * request, and wait for it to complete. This function must only be called + * from a thread that can wait. Note that the request is terminated and + * completed (back to the host, if started there). + * @isci_host: This SCU. + * @isci_device: The target. + * @isci_request: The I/O request to be terminated. + * + * + */ +static void isci_terminate_request_core( + struct isci_host *isci_host, + struct isci_remote_device *isci_device, + struct isci_request *isci_request, + struct completion *request_completion) +{ + enum sci_status status = SCI_SUCCESS; + bool was_terminated = false; + bool needs_cleanup_handling = false; + enum isci_request_status request_status; + unsigned long flags; + + 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); + + /* TMFs are in their own thread */ + if ((isci_request->ttype == io_task) && + ((request_status == aborted) || + (request_status == aborting) || + (request_status == terminating))) + /* 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); + + 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). + */ + if (isci_request->sci_request_handle != NULL) { + was_terminated = true; + status = scic_controller_terminate_request( + isci_host->core_controller, + isci_device->sci_device_handle, + isci_request->sci_request_handle + ); + } + spin_unlock_irqrestore(&isci_host->scic_lock, flags); + + /* + * The only time the request to terminate will + * fail is when the io request is completed and + * being aborted. + */ + if (status != SCI_SUCCESS) + dev_err(&isci_host->pdev->dev, + "%s: scic_controller_terminate_request" + " returned = 0x%x\n", + __func__, + status); + else { + if (was_terminated) { + dev_dbg(&isci_host->pdev->dev, + "%s: before completion wait (%p)\n", + __func__, + request_completion); + + /* Wait here for the request to complete. */ + wait_for_completion(request_completion); + + dev_dbg(&isci_host->pdev->dev, + "%s: after completion wait (%p)\n", + __func__, + request_completion); + } + + if (needs_cleanup_handling) + isci_request_cleanup_completed_loiterer( + isci_host, isci_device, isci_request + ); + } +} +static void isci_terminate_request( + struct isci_host *isci_host, + struct isci_remote_device *isci_device, + struct isci_request *isci_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( + isci_request, + &request_completion, + new_request_state + ); + + spin_unlock_irqrestore(&isci_host->scic_lock, flags); + + if (old_state == started) + /* This request was not already being aborted. If it had been, + * then the aborting I/O (ie. the TMF request) would not be in + * the aborting state, and thus would be terminated here. Note + * that since the TMF completion's call to the kernel function + * "complete()" does not happen until the pending I/O request + * terminate fully completes, we do not have to implement a + * special wait here for already aborting requests - the + * termination of the TMF request will force the request + * to finish it's already started terminate. + */ + isci_terminate_request_core(isci_host, isci_device, + isci_request, &request_completion); +} + +/** + * isci_terminate_pending_requests() - This function will change the all of the + * requests on the given device's state to "aborting", will terminate the + * requests, and wait for them to complete. This function must only be + * called from a thread that can wait. Note that the requests are all + * terminated and completed (back to the host, if started there). + * @isci_host: This parameter specifies SCU. + * @isci_device: This parameter specifies the target. + * + * + */ +void isci_terminate_pending_requests( + struct isci_host *isci_host, + 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; + + 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); + + 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; + + spin_unlock_irqrestore(&isci_host->scic_lock, flags); + + /* Get the libsas task reference. */ + task = isci_request_access_task(isci_request); + + dev_dbg(&isci_host->pdev->dev, + "%s: isci_device=%p request=%p; task=%p\n", + __func__, isci_device, isci_request, task); + + /* Mark all still pending I/O with the selected next + * state. + */ + isci_terminate_request(isci_host, isci_device, + isci_request, new_request_state + ); + + /* Set the 'done' state on the task. */ + if (task) + isci_task_all_done(task); + } + } while (!done); +} + +/** + * isci_task_send_lu_reset_sas() - This function is called by of the SAS Domain + * Template functions. + * @lun: This parameter specifies the lun to be reset. + * + * status, zero indicates success. + */ +static int isci_task_send_lu_reset_sas( + struct isci_host *isci_host, + struct isci_remote_device *isci_device, + u8 *lun) +{ + struct isci_tmf tmf; + int ret = TMF_RESP_FUNC_FAILED; + + dev_dbg(&isci_host->pdev->dev, + "%s: isci_host = %p, isci_device = %p\n", + __func__, isci_host, isci_device); + /* Send the LUN reset to the target. By the time the call returns, + * the TMF has fully exected in the target (in which case the return + * value is "TMF_RESP_FUNC_COMPLETE", or the request timed-out (or + * was otherwise unable to be executed ("TMF_RESP_FUNC_FAILED"). + */ + isci_task_build_tmf(&tmf, isci_device, isci_tmf_ssp_lun_reset, NULL, + NULL); + + #define ISCI_LU_RESET_TIMEOUT_MS 2000 /* 2 second timeout. */ + ret = isci_task_execute_tmf(isci_host, &tmf, ISCI_LU_RESET_TIMEOUT_MS); + + if (ret == TMF_RESP_FUNC_COMPLETE) + dev_dbg(&isci_host->pdev->dev, + "%s: %p: TMF_LU_RESET passed\n", + __func__, isci_device); + else + dev_dbg(&isci_host->pdev->dev, + "%s: %p: TMF_LU_RESET failed (%x)\n", + __func__, isci_device, ret); + + return ret; +} + +/** + * isci_task_lu_reset() - This function is one of the SAS Domain Template + * functions. This is one of the Task Management functoins called by libsas, + * to reset the given lun. Note the assumption that while this call is + * executing, no I/O will be sent by the host to the device. + * @lun: This parameter specifies the lun to be reset. + * + * status, zero indicates success. + */ +int isci_task_lu_reset( + struct domain_device *domain_device, + u8 *lun) +{ + struct isci_host *isci_host = NULL; + struct isci_remote_device *isci_device = NULL; + int ret; + bool device_stopping = false; + + if (domain_device == NULL) { + pr_warn("%s: domain_device == NULL\n", __func__); + return TMF_RESP_FUNC_FAILED; + } + + isci_device = isci_dev_from_domain_dev(domain_device); + + if (domain_device->port != NULL) + isci_host = isci_host_from_sas_ha(domain_device->port->ha); + + pr_debug("%s: domain_device=%p, isci_host=%p; isci_device=%p\n", + __func__, domain_device, isci_host, isci_device); + + if (isci_device != NULL) + device_stopping = (isci_device->status == isci_stopping) + || (isci_device->status == isci_stopped); + + /* If there is a device reset pending on any request in the + * device's list, fail this LUN reset request in order to + * escalate to the device reset. + */ + if ((isci_device == NULL) || + (isci_host == NULL) || + ((isci_host != NULL) && + (isci_device != NULL) && + (device_stopping || + (isci_device_is_reset_pending(isci_host, isci_device))))) { + dev_warn(&isci_host->pdev->dev, + "%s: No dev (%p), no host (%p), or " + "RESET PENDING: domain_device=%p\n", + __func__, isci_device, isci_host, domain_device); + return TMF_RESP_FUNC_FAILED; + } + + /* Stop I/O to the remote device. */ + isci_device_set_host_quiesce_lock_state(isci_device, true); + + /* Send the task management part of the reset. */ + if (sas_protocol_ata(domain_device->tproto)) { + ret = isci_task_send_lu_reset_sata( + isci_host, isci_device, lun + ); + } else + ret = isci_task_send_lu_reset_sas(isci_host, isci_device, lun); + + /* If the LUN reset worked, all the I/O can now be terminated. */ + if (ret == TMF_RESP_FUNC_COMPLETE) + /* Terminate all I/O now. */ + isci_terminate_pending_requests(isci_host, + isci_device, + terminating); + + /* Resume I/O to the remote device. */ + isci_device_set_host_quiesce_lock_state(isci_device, false); + + return ret; +} + + +/* int (*lldd_clear_nexus_port)(struct asd_sas_port *); */ +int isci_task_clear_nexus_port(struct asd_sas_port *port) +{ + return TMF_RESP_FUNC_FAILED; +} + + + +int isci_task_clear_nexus_ha(struct sas_ha_struct *ha) +{ + return TMF_RESP_FUNC_FAILED; +} + +int isci_task_I_T_nexus_reset(struct domain_device *dev) +{ + return TMF_RESP_FUNC_FAILED; +} + + +/* Task Management Functions. Must be called from process context. */ + +/** + * isci_abort_task_process_cb() - This is a helper function for the abort task + * TMF command. It manages the request state with respect to the successful + * transmission / completion of the abort task request. + * @cb_state: This parameter specifies when this function was called - after + * the TMF request has been started and after it has timed-out. + * @tmf: This parameter specifies the TMF in progress. + * + * + */ +static void isci_abort_task_process_cb( + enum isci_tmf_cb_state cb_state, + struct isci_tmf *tmf, + void *cb_data) +{ + struct isci_request *old_request; + + old_request = (struct isci_request *)cb_data; + + dev_dbg(&old_request->isci_host->pdev->dev, + "%s: tmf=%p, old_request=%p\n", + __func__, tmf, old_request); + + switch (cb_state) { + + case isci_tmf_started: + /* The TMF has been started. Nothing to do here, since the + * request state was already set to "aborted" by the abort + * task function. + */ + BUG_ON(old_request->status != aborted); + break; + + case isci_tmf_timed_out: + + /* Set the task's state to "aborting", since the abort task + * function thread set it to "aborted" (above) in anticipation + * of the task management request working correctly. Since the + * timeout has now fired, the TMF request failed. We set the + * state such that the request completion will indicate the + * device is no longer present. + */ + isci_request_change_state(old_request, aborting); + break; + + default: + dev_err(&old_request->isci_host->pdev->dev, + "%s: Bad cb_state (%d): tmf=%p, old_request=%p\n", + __func__, cb_state, tmf, old_request); + break; + } +} + +/** + * isci_task_abort_task() - This function is one of the SAS Domain Template + * functions. This function is called by libsas to abort a specified task. + * @task: This parameter specifies the SAS task to abort. + * + * status, zero indicates success. + */ +int isci_task_abort_task(struct sas_task *task) +{ + DECLARE_COMPLETION_ONSTACK(aborted_io_completion); + struct isci_request *old_request = NULL; + struct isci_remote_device *isci_device = NULL; + struct isci_host *isci_host = NULL; + struct isci_tmf tmf; + int ret = TMF_RESP_FUNC_FAILED; + unsigned long flags; + bool any_dev_reset, device_stopping; + + /* Get the isci_request reference from the task. Note that + * this check does not depend on the pending request list + * in the device, because tasks driving resets may land here + * after completion in the core. + */ + old_request = isci_task_get_request_from_task(task, &isci_host, + &isci_device); + + dev_dbg(&isci_host->pdev->dev, + "%s: task = %p\n", __func__, task); + + /* Check if the device has been / is currently being removed. + * If so, no task management will be done, and the I/O will + * be terminated. + */ + device_stopping = (isci_device->status == isci_stopping) + || (isci_device->status == isci_stopped); + +#ifdef NOMORE + /* This abort task function is the first stop of the libsas error + * handler thread. Since libsas is executing in a thread with a + * referernce to the "task" parameter, that task cannot be completed + * directly back to the upper layers. In order to make sure that + * the task is managed correctly if this abort task fails, set the + * "SAS_TASK_STATE_ABORTED" bit now such that completions up the + * stack will be intercepted and only allowed to happen in the + * libsas SCSI error handler thread. + */ + spin_lock_irqsave(&task->task_state_lock, flags); + task->task_state_flags |= SAS_TASK_STATE_ABORTED; + spin_unlock_irqrestore(&task->task_state_lock, flags); +#endif /* NOMORE */ + + /* This version of the driver will fail abort requests for + * SATA/STP. Failing the abort request this way will cause the + * SCSI error handler thread to escalate to LUN reset + */ + if (sas_protocol_ata(task->task_proto) && !device_stopping) { + dev_warn(&isci_host->pdev->dev, + " task %p is for a STP/SATA device;" + " returning TMF_RESP_FUNC_FAILED\n" + " to cause a LUN reset...\n", task); + return TMF_RESP_FUNC_FAILED; + } + + dev_dbg(&isci_host->pdev->dev, + "%s: old_request == %p\n", __func__, old_request); + + spin_lock_irqsave(&task->task_state_lock, flags); + + /* Don't do resets to stopping devices. */ + if (device_stopping) + task->task_state_flags &= ~SAS_TASK_NEED_DEV_RESET; + + /* See if there is a pending device reset for this device. */ + any_dev_reset = task->task_state_flags & SAS_TASK_NEED_DEV_RESET; + + spin_unlock_irqrestore(&task->task_state_lock, flags); + + if ((isci_device != NULL) && !device_stopping) + any_dev_reset = any_dev_reset + || isci_device_is_reset_pending(isci_host, + isci_device + ); + + /* If the extraction of the request reference from the task + * failed, then the request has been completed (or if there is a + * pending reset then this abort request function must be failed + * in order to escalate to the target reset). + */ + if ((old_request == NULL) || + ((old_request != NULL) && + (old_request->sci_request_handle == NULL) && + (old_request->complete_in_target)) || + any_dev_reset) { + + spin_lock_irqsave(&task->task_state_lock, flags); + + /* If the device reset task flag is set, fail the task + * management request. Otherwise, the original request + * has completed. + */ + if (any_dev_reset) { + + /* Turn off the task's DONE to make sure this + * task is escalated to a target reset. + */ + task->task_state_flags &= ~SAS_TASK_STATE_DONE; + + /* Fail the task management request in order to + * escalate to the target reset. + */ + ret = TMF_RESP_FUNC_FAILED; + + dev_dbg(&isci_host->pdev->dev, + "%s: Failing task abort in order to " + "escalate to target reset because\n" + "SAS_TASK_NEED_DEV_RESET is set for " + "task %p on dev %p\n", + __func__, task, isci_device); + + } else { + ret = TMF_RESP_FUNC_COMPLETE; + + dev_dbg(&isci_host->pdev->dev, + "%s: abort task not needed for %p\n", + __func__, task); + + /* The request has already completed and there + * is nothing to do here other than to set the task + * done bit, and indicate that the task abort function + * was sucessful. + */ + isci_set_task_doneflags(task); + + /* Set the abort bit to make sure that libsas sticks the + * task in the completed task queue. + */ +/* task->task_state_flags |= SAS_TASK_STATE_ABORTED; */ + + /* Check for the situation where the request was + * left around on the device list but the + * request already completed. + */ + if (old_request && !old_request->sci_request_handle) { + + isci_request_cleanup_completed_loiterer( + isci_host, isci_device, old_request + ); + } + } + spin_unlock_irqrestore(&task->task_state_lock, flags); + + return ret; + } + + spin_lock_irqsave(&isci_host->scic_lock, flags); + + /* Sanity check the request status, and set the I/O kernel completion + * struct that will be triggered when the request completes. + */ + if (isci_task_validate_request_to_abort( + old_request, + isci_host, + isci_device, + &aborted_io_completion) + == unallocated) { + dev_dbg(&isci_host->pdev->dev, + "%s: old_request not valid for device = %p\n", + __func__, + isci_device); + old_request = NULL; + } + + if (!old_request) { + + /* There is no isci_request attached to the sas_task. + * It must have been completed and detached. + */ + dev_dbg(&isci_host->pdev->dev, + "%s: old_request == NULL\n", + __func__); + + spin_unlock_irqrestore(&isci_host->scic_lock, flags); + + /* Set the state on the task. */ + isci_task_all_done(task); + + return TMF_RESP_FUNC_COMPLETE; + } + if (task->task_proto == SAS_PROTOCOL_SMP || device_stopping) { + + if (device_stopping) + dev_dbg(&isci_host->pdev->dev, + "%s: device is stopping, thus no TMF\n", + __func__); + else + dev_dbg(&isci_host->pdev->dev, + "%s: request is SMP, thus no TMF\n", + __func__); + + old_request->complete_in_target = true; + + spin_unlock_irqrestore(&isci_host->scic_lock, flags); + + /* Set the state on the task. */ + isci_task_all_done(task); + + ret = TMF_RESP_FUNC_COMPLETE; + + /* Stopping and SMP devices are not sent a TMF, and are not + * reset, but the outstanding I/O request is terminated here. + * + * Clean up the request on our side, and wait for the aborted + * I/O to complete. + */ + isci_terminate_request_core(isci_host, isci_device, old_request, + &aborted_io_completion); + } else { + /* Fill in the tmf stucture */ + isci_task_build_tmf(&tmf, isci_device, isci_tmf_ssp_task_abort, + isci_abort_task_process_cb, old_request); + + tmf.io_tag = scic_io_request_get_io_tag( + old_request->sci_request_handle + ); + + spin_unlock_irqrestore(&isci_host->scic_lock, flags); + + #define ISCI_ABORT_TASK_TIMEOUT_MS 500 /* half second timeout. */ + ret = isci_task_execute_tmf(isci_host, &tmf, + ISCI_ABORT_TASK_TIMEOUT_MS); + + if (ret == TMF_RESP_FUNC_COMPLETE) { + old_request->complete_in_target = true; + + /* Clean up the request on our side, and wait for the aborted I/O to + * complete. + */ + isci_terminate_request_core(isci_host, isci_device, old_request, + &aborted_io_completion); + + /* Set the state on the task. */ + isci_task_all_done(task); + } else + dev_err(&isci_host->pdev->dev, + "%s: isci_task_send_tmf failed\n", + __func__); + } + + return ret; +} + +/** + * isci_task_abort_task_set() - This function is one of the SAS Domain Template + * functions. This is one of the Task Management functoins called by libsas, + * to abort all task for the given lun. + * @d_device: This parameter specifies the domain device associated with this + * request. + * @lun: This parameter specifies the lun associated with this request. + * + * status, zero indicates success. + */ +int isci_task_abort_task_set( + struct domain_device *d_device, + u8 *lun) +{ + return TMF_RESP_FUNC_FAILED; +} + + +/** + * isci_task_clear_aca() - This function is one of the SAS Domain Template + * functions. This is one of the Task Management functoins called by libsas. + * @d_device: This parameter specifies the domain device associated with this + * request. + * @lun: This parameter specifies the lun associated with this request. + * + * status, zero indicates success. + */ +int isci_task_clear_aca( + struct domain_device *d_device, + u8 *lun) +{ + return TMF_RESP_FUNC_FAILED; +} + + + +/** + * isci_task_clear_task_set() - This function is one of the SAS Domain Template + * functions. This is one of the Task Management functoins called by libsas. + * @d_device: This parameter specifies the domain device associated with this + * request. + * @lun: This parameter specifies the lun associated with this request. + * + * status, zero indicates success. + */ +int isci_task_clear_task_set( + struct domain_device *d_device, + u8 *lun) +{ + return TMF_RESP_FUNC_FAILED; +} + + +/** + * isci_task_query_task() - This function is implemented to cause libsas to + * correctly escalate the failed abort to a LUN or target reset (this is + * because sas_scsi_find_task libsas function does not correctly interpret + * all return codes from the abort task call). When TMF_RESP_FUNC_SUCC is + * returned, libsas turns this into a LUN reset; when FUNC_FAILED is + * returned, libsas will turn this into a target reset + * @task: This parameter specifies the sas task being queried. + * @lun: This parameter specifies the lun associated with this request. + * + * status, zero indicates success. + */ +int isci_task_query_task( + struct sas_task *task) +{ + /* See if there is a pending device reset for this device. */ + if (task->task_state_flags & SAS_TASK_NEED_DEV_RESET) + return TMF_RESP_FUNC_FAILED; + else + return TMF_RESP_FUNC_SUCC; +} + +/** + * isci_task_request_complete() - This function is called by the sci core when + * an task request completes. + * @isci_host: This parameter specifies the ISCI host object + * @request: This parameter is the completed isci_request object. + * @completion_status: This parameter specifies the completion status from the + * sci core. + * + * none. + */ +void isci_task_request_complete( + struct isci_host *isci_host, + struct isci_request *request, + enum sci_task_status completion_status) +{ + struct isci_remote_device *isci_device = request->isci_device; + enum isci_request_status old_state; + struct isci_tmf *tmf = isci_request_access_tmf(request); + struct completion *tmf_complete; + + dev_dbg(&isci_host->pdev->dev, + "%s: request = %p, status=%d\n", + __func__, request, completion_status); + + old_state = isci_request_change_state(request, completed); + + tmf->status = completion_status; + request->complete_in_target = true; + + if (SAS_PROTOCOL_SSP == tmf->proto) { + + memcpy(&tmf->resp.resp_iu, + scic_io_request_get_response_iu_address( + request->sci_request_handle + ), + sizeof(struct sci_ssp_response_iu)); + + } else if (SAS_PROTOCOL_SATA == tmf->proto) { + + memcpy(&tmf->resp.d2h_fis, + scic_stp_io_request_get_d2h_reg_address( + request->sci_request_handle + ), + sizeof(struct sata_fis_reg_d2h) + ); + } + + /* Manage the timer if it is still running. */ + if (tmf->timeout_timer) { + + isci_timer_stop(tmf->timeout_timer); + isci_timer_free(&isci_host->timer_list_struct, + tmf->timeout_timer); + tmf->timeout_timer = NULL; + } + + /* PRINT_TMF( ((struct isci_tmf *)request->task)); */ + tmf_complete = tmf->complete; + + scic_controller_complete_task( + isci_host->core_controller, + isci_device->sci_device_handle, + request->sci_request_handle + ); + /* NULL the request handle to make sure it cannot be terminated + * or completed again. + */ + request->sci_request_handle = NULL; + + isci_request_change_state(request, unallocated); + list_del_init(&request->dev_node); + + /* The task management part completes last. */ + complete(tmf_complete); +} + + +/** + * isci_task_ssp_request_get_lun() - This function is called by the sci core to + * retrieve the lun for a given task request. + * @request: This parameter is the isci_request object. + * + * lun for specified task request. + */ +u32 isci_task_ssp_request_get_lun(struct isci_request *request) +{ + struct isci_tmf *isci_tmf = isci_request_access_tmf(request); + + dev_dbg(&request->isci_host->pdev->dev, + "%s: lun = %d\n", __func__, isci_tmf->lun[0]); +/* @todo: build lun from array of bytes to 32 bit */ + return isci_tmf->lun[0]; +} + +/** + * isci_task_ssp_request_get_function() - This function is called by the sci + * core to retrieve the function for a given task request. + * @request: This parameter is the isci_request object. + * + * function code for specified task request. + */ +u8 isci_task_ssp_request_get_function(struct isci_request *request) +{ + struct isci_tmf *isci_tmf = isci_request_access_tmf(request); + + dev_dbg(&request->isci_host->pdev->dev, + "%s: func = %d\n", __func__, isci_tmf->tmf_code); + + return isci_tmf->tmf_code; +} + +/** + * isci_task_ssp_request_get_io_tag_to_manage() - This function is called by + * the sci core to retrieve the io tag for a given task request. + * @request: This parameter is the isci_request object. + * + * io tag for specified task request. + */ +u16 isci_task_ssp_request_get_io_tag_to_manage(struct isci_request *request) +{ + u16 io_tag = SCI_CONTROLLER_INVALID_IO_TAG; + + if (tmf_task == request->ttype) { + struct isci_tmf *tmf = isci_request_access_tmf(request); + io_tag = tmf->io_tag; + } + + dev_dbg(&request->isci_host->pdev->dev, + "%s: request = %p, io_tag = %d\n", + __func__, request, io_tag); + + return io_tag; +} + +/** + * isci_task_ssp_request_get_response_data_address() - This function is called + * by the sci core to retrieve the response data address for a given task + * request. + * @request: This parameter is the isci_request object. + * + * response data address for specified task request. + */ +void *isci_task_ssp_request_get_response_data_address( + struct isci_request *request) +{ + struct isci_tmf *isci_tmf = isci_request_access_tmf(request); + + return &isci_tmf->resp.resp_iu; +} + +/** + * isci_task_ssp_request_get_response_data_length() - This function is called + * by the sci core to retrieve the response data length for a given task + * request. + * @request: This parameter is the isci_request object. + * + * response data length for specified task request. + */ +u32 isci_task_ssp_request_get_response_data_length( + struct isci_request *request) +{ + struct isci_tmf *isci_tmf = isci_request_access_tmf(request); + + return sizeof(isci_tmf->resp.resp_iu); +} + +/** + * isci_bus_reset_handler() - This function performs a target reset of the + * device referenced by "cmd'. This function is exported through the + * "struct scsi_host_template" structure such that it is called when an I/O + * recovery process has escalated to a target reset. Note that this function + * is called from the scsi error handler event thread, so may block on calls. + * @scsi_cmd: This parameter specifies the target to be reset. + * + * SUCCESS if the reset process was successful, else FAILED. + */ +int isci_bus_reset_handler(struct scsi_cmnd *cmd) +{ + unsigned long flags = 0; + struct isci_host *isci_host = NULL; + enum sci_status status; + int base_status; + struct isci_remote_device *isci_dev + = isci_dev_from_domain_dev( + sdev_to_domain_dev(cmd->device)); + + dev_dbg(&cmd->device->sdev_gendev, + "%s: cmd %p, isci_dev %p\n", + __func__, cmd, isci_dev); + + if (!isci_dev) { + dev_warn(&cmd->device->sdev_gendev, + "%s: isci_dev is GONE!\n", + __func__); + + return TMF_RESP_FUNC_COMPLETE; /* Nothing to reset. */ + } + + if (isci_dev->isci_port != NULL) + isci_host = isci_dev->isci_port->isci_host; + + if (isci_host != NULL) + spin_lock_irqsave(&isci_host->scic_lock, flags); + + status = scic_remote_device_reset(isci_dev->sci_device_handle); + if (status != SCI_SUCCESS) { + + if (isci_host != NULL) + spin_unlock_irqrestore(&isci_host->scic_lock, flags); + + scmd_printk(KERN_WARNING, cmd, + "%s: scic_remote_device_reset(%p) returned %d!\n", + __func__, isci_dev, status); + + return TMF_RESP_FUNC_FAILED; + } + if (isci_host != NULL) + spin_unlock_irqrestore(&isci_host->scic_lock, flags); + + /* Stop I/O to the remote device. */ + isci_device_set_host_quiesce_lock_state(isci_dev, true); + + /* Make sure all pending requests are able to be fully terminated. */ + isci_device_clear_reset_pending(isci_dev); + + /* Terminate in-progress I/O now. */ + isci_remote_device_nuke_requests(isci_dev); + + /* Call into the libsas default handler (which calls sas_phy_reset). */ + base_status = sas_eh_bus_reset_handler(cmd); + + if (base_status != SUCCESS) { + + /* There can be cases where the resets to individual devices + * behind an expander will fail because of an unplug of the + * expander itself. + */ + scmd_printk(KERN_WARNING, cmd, + "%s: sas_eh_bus_reset_handler(%p) returned %d!\n", + __func__, cmd, base_status); + } + + /* WHAT TO DO HERE IF sas_phy_reset FAILS? */ + + if (isci_host != NULL) + spin_lock_irqsave(&isci_host->scic_lock, flags); + status + = scic_remote_device_reset_complete(isci_dev->sci_device_handle); + + if (isci_host != NULL) + spin_unlock_irqrestore(&isci_host->scic_lock, flags); + + if (status != SCI_SUCCESS) { + scmd_printk(KERN_WARNING, cmd, + "%s: scic_remote_device_reset_complete(%p) " + "returned %d!\n", + __func__, isci_dev, status); + } + /* WHAT TO DO HERE IF scic_remote_device_reset_complete FAILS? */ + + dev_dbg(&cmd->device->sdev_gendev, + "%s: cmd %p, isci_dev %p complete.\n", + __func__, cmd, isci_dev); + + /* Resume I/O to the remote device. */ + isci_device_set_host_quiesce_lock_state(isci_dev, false); + + return TMF_RESP_FUNC_COMPLETE; +} -- cgit v1.2.1 From 0cf89d1d27c1bdd0abf1714096f98ea44704dcff Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 18 Feb 2011 09:25:07 -0800 Subject: isci: cleanup "starting" state handling The lldd actively disallows requests in the "starting" state. Retrying or holding off commands in this state is sub-optimal: 1/ it adds another state check to the fast path 2/ retrying can cause libsas to give up However, isci's ->lldd_dev_found() routine already waits for controller start to complete before allowing further progress. Checking the "starting" state in isci_task_execute_task and the isr is redundant and misleading. Clean this up and introduce a controller-wide event queue to start reeling in "completion" proliferation in the driver. The "stopping" state cleanups are in a similar vein, rely on the the isr and other paths being precluded from occurring rather than implementing state checking logic. Reported-by: Christoph Hellwig Cc: Jeff Garzik Signed-off-by: Edmund Nadolski Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 5e6f55863407..6f98f6c74efb 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -164,8 +164,7 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags) * for the quiesce spinlock. */ - if (isci_host_get_state(isci_host) == isci_starting || - (device && ((isci_remote_device_get_state(device) == isci_ready) || + if ((device && ((isci_remote_device_get_state(device) == isci_ready) || (isci_remote_device_get_state(device) == isci_host_quiesce)))) { /* Forces a retry from scsi mid layer. */ -- cgit v1.2.1 From 7c40a8035815479c7c12ab0cdcea71e0f4c3a9c8 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 2 Mar 2011 11:49:26 -0800 Subject: isci: rework timer api Prepare the timer api for the arrival of dynamic creation and destruction events from the core. It pretended to do this previously but the core to date only used it in a static init-time only fashion. This is an interim fix until a cleaner event queue can be developed. 1/ make all locking external to the api (add WARN_ONCE to verify) 2/ add a timer_destroy interface (to be used by the core) 3/ use del_timer_sync() prior to deallocating timer data 4/ delete the "timer_list" indirection, we only have timers allocated for the isci_host 5/ fix detection of timer list allocation errors Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 6f98f6c74efb..232125eab523 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -475,14 +475,8 @@ int isci_task_execute_tmf( } /* Allocate the TMF timeout timer. */ - tmf->timeout_timer = isci_timer_create( - &isci_host->timer_list_struct, - isci_host, - request, - isci_tmf_timeout_cb - ); - spin_lock_irqsave(&isci_host->scic_lock, flags); + tmf->timeout_timer = isci_timer_create(isci_host, request, isci_tmf_timeout_cb); /* Start the timer. */ if (tmf->timeout_timer) @@ -557,9 +551,7 @@ int isci_task_execute_tmf( /* Clean up the timer if needed. */ if (tmf->timeout_timer) { - isci_timer_stop(tmf->timeout_timer); - isci_timer_free(&isci_host->timer_list_struct, - tmf->timeout_timer); + isci_del_timer(isci_host, tmf->timeout_timer); tmf->timeout_timer = NULL; } @@ -1468,10 +1460,7 @@ void isci_task_request_complete( /* Manage the timer if it is still running. */ if (tmf->timeout_timer) { - - isci_timer_stop(tmf->timeout_timer); - isci_timer_free(&isci_host->timer_list_struct, - tmf->timeout_timer); + isci_del_timer(isci_host, tmf->timeout_timer); tmf->timeout_timer = NULL; } -- cgit v1.2.1 From 3a97eec6d7876c541950e23811efd40e0bcd04a0 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 4 Mar 2011 11:51:43 -0800 Subject: isci: remove sci_device_handle It belies the fact that isci_remote_device and scic_sds_remote_device are one in same object with the same lifetime rules. Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 232125eab523..c637bbc215c6 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -285,7 +285,7 @@ static enum sci_status isci_task_request_build( "%s: isci_tmf = %p\n", __func__, isci_tmf); isci_device = isci_tmf->device; - sci_device = isci_device->sci_device_handle; + sci_device = to_sci_dev(isci_device); /* do common allocation and init of request object. */ status = isci_request_alloc_tmf( @@ -395,7 +395,7 @@ static void isci_tmf_timeout_cb(void *tmf_request_arg) /* Terminate the TMF transmit request. */ status = scic_controller_terminate_request( request->isci_host->core_controller, - request->isci_device->sci_device_handle, + to_sci_dev(request->isci_device), request->sci_request_handle ); @@ -456,7 +456,7 @@ int isci_task_execute_tmf( "%s: isci_device = %p\n", __func__, isci_device); - sci_device = isci_device->sci_device_handle; + sci_device = to_sci_dev(isci_device); /* Assign the pointer to the TMF's completion kernel wait structure. */ tmf->complete = &completion; @@ -728,7 +728,7 @@ static void isci_terminate_request_core( was_terminated = true; status = scic_controller_terminate_request( isci_host->core_controller, - isci_device->sci_device_handle, + to_sci_dev(isci_device), isci_request->sci_request_handle ); } @@ -1469,7 +1469,7 @@ void isci_task_request_complete( scic_controller_complete_task( isci_host->core_controller, - isci_device->sci_device_handle, + to_sci_dev(isci_device), request->sci_request_handle ); /* NULL the request handle to make sure it cannot be terminated @@ -1612,7 +1612,7 @@ int isci_bus_reset_handler(struct scsi_cmnd *cmd) if (isci_host != NULL) spin_lock_irqsave(&isci_host->scic_lock, flags); - status = scic_remote_device_reset(isci_dev->sci_device_handle); + status = scic_remote_device_reset(to_sci_dev(isci_dev)); if (status != SCI_SUCCESS) { if (isci_host != NULL) @@ -1654,8 +1654,7 @@ int isci_bus_reset_handler(struct scsi_cmnd *cmd) if (isci_host != NULL) spin_lock_irqsave(&isci_host->scic_lock, flags); - status - = scic_remote_device_reset_complete(isci_dev->sci_device_handle); + status = scic_remote_device_reset_complete(to_sci_dev(isci_dev)); if (isci_host != NULL) spin_unlock_irqrestore(&isci_host->scic_lock, flags); -- cgit v1.2.1 From 8acaec1593526f922ff46812d99abf9aab5c8b43 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 7 Mar 2011 14:47:35 -0800 Subject: isci: kill "host quiesce" mechanism The midlayer is already throttling i/o in the places where host_quiesce was trying to prevent further i/o to the device. It's also problematic in that it holds a lock over GFP_KERNEL allocations. Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 49 ++++++------------------------------------------ 1 file changed, 6 insertions(+), 43 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index c637bbc215c6..98204b031649 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -81,7 +81,6 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags) struct isci_request *request = NULL; struct isci_remote_device *device; unsigned long flags; - unsigned long quiesce_flags = 0; int ret; enum sci_status status; @@ -151,21 +150,7 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags) isci_host = isci_host_from_sas_ha(task->dev->port->ha); - /* check if the controller hasn't started or if the device - * is ready but not accepting IO. - */ - if (device) { - - spin_lock_irqsave(&device->host_quiesce_lock, - quiesce_flags); - } - /* From this point onward, any process that needs to guarantee - * that there is no kernel I/O being started will have to wait - * for the quiesce spinlock. - */ - - if ((device && ((isci_remote_device_get_state(device) == isci_ready) || - (isci_remote_device_get_state(device) == isci_host_quiesce)))) { + if (device && device->status == isci_ready) { /* Forces a retry from scsi mid layer. */ dev_warn(task->dev->port->ha->dev, @@ -179,8 +164,7 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags) if (device) dev_dbg(task->dev->port->ha->dev, "%s: device->status = 0x%x\n", - __func__, - isci_remote_device_get_state(device)); + __func__, device->status); /* Indicate QUEUE_FULL so that the scsi midlayer * retries. @@ -194,7 +178,7 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags) isci_host_can_dequeue(isci_host, 1); } /* the device is going down... */ - else if (!device || (isci_ready_for_io != isci_remote_device_get_state(device))) { + else if (!device || device->status != isci_ready_for_io) { dev_dbg(task->dev->port->ha->dev, "%s: task %p: isci_host->status = %d, " @@ -207,8 +191,7 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags) if (device) dev_dbg(task->dev->port->ha->dev, "%s: device->status = 0x%x\n", - __func__, - isci_remote_device_get_state(device)); + __func__, device->status); /* Indicate SAS_TASK_UNDELIVERED, so that the scsi * midlayer removes the target. @@ -247,11 +230,6 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags) isci_host_can_dequeue(isci_host, 1); } } - if (device) { - spin_unlock_irqrestore(&device->host_quiesce_lock, - quiesce_flags - ); - } task = list_entry(task->list.next, struct sas_task, list); } while (--num > 0); return 0; @@ -442,14 +420,11 @@ int isci_task_execute_tmf( /* sanity check, return TMF_RESP_FUNC_FAILED * if the device is not there and ready. */ - if (!isci_device || - ((isci_ready_for_io != isci_remote_device_get_state(isci_device)) && - (isci_host_quiesce != isci_remote_device_get_state(isci_device)))) { + if (!isci_device || isci_device->status != isci_ready_for_io) { dev_dbg(&isci_host->pdev->dev, "%s: isci_device = %p not ready (%d)\n", __func__, - isci_device, - isci_remote_device_get_state(isci_device)); + isci_device, isci_device->status); return TMF_RESP_FUNC_FAILED; } else dev_dbg(&isci_host->pdev->dev, @@ -986,9 +961,6 @@ int isci_task_lu_reset( return TMF_RESP_FUNC_FAILED; } - /* Stop I/O to the remote device. */ - isci_device_set_host_quiesce_lock_state(isci_device, true); - /* Send the task management part of the reset. */ if (sas_protocol_ata(domain_device->tproto)) { ret = isci_task_send_lu_reset_sata( @@ -1004,9 +976,6 @@ int isci_task_lu_reset( isci_device, terminating); - /* Resume I/O to the remote device. */ - isci_device_set_host_quiesce_lock_state(isci_device, false); - return ret; } @@ -1627,9 +1596,6 @@ int isci_bus_reset_handler(struct scsi_cmnd *cmd) if (isci_host != NULL) spin_unlock_irqrestore(&isci_host->scic_lock, flags); - /* Stop I/O to the remote device. */ - isci_device_set_host_quiesce_lock_state(isci_dev, true); - /* Make sure all pending requests are able to be fully terminated. */ isci_device_clear_reset_pending(isci_dev); @@ -1671,8 +1637,5 @@ int isci_bus_reset_handler(struct scsi_cmnd *cmd) "%s: cmd %p, isci_dev %p complete.\n", __func__, cmd, isci_dev); - /* Resume I/O to the remote device. */ - isci_device_set_host_quiesce_lock_state(isci_dev, false); - return TMF_RESP_FUNC_COMPLETE; } -- cgit v1.2.1 From 18d3d72a42a846d46b71131982c51d63eba2b7b3 Mon Sep 17 00:00:00 2001 From: Jeff Skirvin Date: Fri, 4 Mar 2011 14:06:38 -0800 Subject: isci: isci_request_cleanup_completed_loiterer checks task before task_done In the condition where outstanding I/Os are being cleaned from the device requests in process list, the cleanup function needs to check that the request is actually a sas-task and not a task management function. Signed-off-by: Jeff Skirvin Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 98204b031649..779f6cfba6be 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -631,13 +631,16 @@ static void isci_request_cleanup_completed_loiterer( struct isci_remote_device *isci_device, struct isci_request *isci_request) { - struct sas_task *task = isci_request_access_task(isci_request); - unsigned long flags; + struct sas_task *task; + unsigned long flags; + + task = (isci_request->ttype == io_task) + ? isci_request_access_task(isci_request) + : NULL; dev_dbg(&isci_host->pdev->dev, "%s: isci_device=%p, request=%p, task=%p\n", - __func__, isci_device, isci_request, - isci_request->ttype_ptr.io_task_ptr); + __func__, isci_device, isci_request, task); spin_lock_irqsave(&isci_host->scic_lock, flags); list_del_init(&isci_request->dev_node); -- cgit v1.2.1 From a5fde225364df30507ba1a5aafeec85e595000d3 Mon Sep 17 00:00:00 2001 From: Jeff Skirvin Date: Fri, 4 Mar 2011 14:06:42 -0800 Subject: isci: fix completion / abort path. Corrected use of the request state_lock in the completion callback. In the case where an abort (or reset) thread is trying to terminate an I/O request, it sets the request state to "aborting" (or "terminating") if the state is still "starting". One of the bugs was to never set the state to "completed". Another was to not correctly recognize the situation where the I/O had completed but the sas_task was still pending callback to task_done - this was typically a problem in the LUN and device reset cases. It is now possible that we leave isci_task_abort_task() with request->io_request_completion pointing to localy allocated aborted_io_completion struct. It may result in a system crash. Signed-off-by: Jeff Skirvin Signed-off-by: Maciej Trela Signed-off-by: Jacek Danecki Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 230 +++++++++++++++++++++-------------------------- 1 file changed, 100 insertions(+), 130 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 779f6cfba6be..02c40c00cb8b 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -618,9 +618,6 @@ static enum isci_request_status isci_task_validate_request_to_abort( old_state = isci_request_change_started_to_aborted( isci_request, aborted_io_completion); - /* Only abort requests in the started state. */ - if (old_state != started) - old_state = unallocated; } return old_state; @@ -644,10 +641,23 @@ static void isci_request_cleanup_completed_loiterer( spin_lock_irqsave(&isci_host->scic_lock, flags); list_del_init(&isci_request->dev_node); - if (task != NULL) - task->lldd_task = NULL; spin_unlock_irqrestore(&isci_host->scic_lock, flags); + if (task != NULL) { + + spin_lock_irqsave(&task->task_state_lock, flags); + task->lldd_task = NULL; + + isci_set_task_doneflags(task); + + /* If this task is not in the abort path, call task_done. */ + if (!(task->task_state_flags & SAS_TASK_STATE_ABORTED)) { + + spin_unlock_irqrestore(&task->task_state_lock, flags); + task->task_done(task); + } else + spin_unlock_irqrestore(&task->task_state_lock, flags); + } isci_request_free(isci_host, isci_request); } /** @@ -684,17 +694,20 @@ static void isci_terminate_request_core( spin_lock_irqsave(&isci_request->state_lock, flags); request_status = isci_request_get_state(isci_request); - /* TMFs are in their own thread */ - if ((isci_request->ttype == io_task) && - ((request_status == aborted) || - (request_status == aborting) || - (request_status == terminating))) + if ((isci_request->ttype == io_task) /* TMFs are in their own thread */ + && ((request_status == aborted) + || (request_status == aborting) + || (request_status == terminating) + || (request_status == completed) + ) + ) { + /* 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); spin_lock_irqsave(&isci_host->scic_lock, flags); @@ -765,10 +778,10 @@ static void isci_terminate_request( new_request_state ); - spin_unlock_irqrestore(&isci_host->scic_lock, flags); + if ((old_state == started) || (old_state == completed)) { - if (old_state == started) - /* This request was not already being aborted. If it had been, + /* If the old_state is started: + * This request was not already being aborted. If it had been, * then the aborting I/O (ie. the TMF request) would not be in * the aborting state, and thus would be terminated here. Note * that since the TMF completion's call to the kernel function @@ -777,9 +790,15 @@ static void isci_terminate_request( * special wait here for already aborting requests - the * termination of the TMF request will force the request * to finish it's already started terminate. + * + * If old_state == completed: + * This request completed from the SCU hardware perspective + * and now just needs cleaning up in terms of freeing the + * request and potentially calling up to libsas. */ isci_terminate_request_core(isci_host, isci_device, isci_request, &request_completion); + } } /** @@ -863,10 +882,6 @@ void isci_terminate_pending_requests( isci_terminate_request(isci_host, isci_device, isci_request, new_request_state ); - - /* Set the 'done' state on the task. */ - if (task) - isci_task_all_done(task); } } while (!done); } @@ -1067,13 +1082,15 @@ static void isci_abort_task_process_cb( int isci_task_abort_task(struct sas_task *task) { DECLARE_COMPLETION_ONSTACK(aborted_io_completion); - struct isci_request *old_request = NULL; + struct isci_request *old_request = NULL; + enum isci_request_status old_state; struct isci_remote_device *isci_device = NULL; - struct isci_host *isci_host = NULL; - struct isci_tmf tmf; - int ret = TMF_RESP_FUNC_FAILED; - unsigned long flags; - bool any_dev_reset, device_stopping; + struct isci_host *isci_host = NULL; + struct isci_tmf tmf; + int ret = TMF_RESP_FUNC_FAILED; + unsigned long flags; + bool any_dev_reset = false; + bool device_stopping; /* Get the isci_request reference from the task. Note that * this check does not depend on the pending request list @@ -1093,21 +1110,6 @@ int isci_task_abort_task(struct sas_task *task) device_stopping = (isci_device->status == isci_stopping) || (isci_device->status == isci_stopped); -#ifdef NOMORE - /* This abort task function is the first stop of the libsas error - * handler thread. Since libsas is executing in a thread with a - * referernce to the "task" parameter, that task cannot be completed - * directly back to the upper layers. In order to make sure that - * the task is managed correctly if this abort task fails, set the - * "SAS_TASK_STATE_ABORTED" bit now such that completions up the - * stack will be intercepted and only allowed to happen in the - * libsas SCSI error handler thread. - */ - spin_lock_irqsave(&task->task_state_lock, flags); - task->task_state_flags |= SAS_TASK_STATE_ABORTED; - spin_unlock_irqrestore(&task->task_state_lock, flags); -#endif /* NOMORE */ - /* This version of the driver will fail abort requests for * SATA/STP. Failing the abort request this way will cause the * SCSI error handler thread to escalate to LUN reset @@ -1123,35 +1125,27 @@ int isci_task_abort_task(struct sas_task *task) dev_dbg(&isci_host->pdev->dev, "%s: old_request == %p\n", __func__, old_request); + if (!device_stopping) + any_dev_reset = isci_device_is_reset_pending(isci_host,isci_device); + spin_lock_irqsave(&task->task_state_lock, flags); /* Don't do resets to stopping devices. */ - if (device_stopping) - task->task_state_flags &= ~SAS_TASK_NEED_DEV_RESET; + if (device_stopping) { - /* See if there is a pending device reset for this device. */ - any_dev_reset = task->task_state_flags & SAS_TASK_NEED_DEV_RESET; - - spin_unlock_irqrestore(&task->task_state_lock, flags); + task->task_state_flags &= ~SAS_TASK_NEED_DEV_RESET; + any_dev_reset = false; - if ((isci_device != NULL) && !device_stopping) + } else /* See if there is a pending device reset for this device. */ any_dev_reset = any_dev_reset - || isci_device_is_reset_pending(isci_host, - isci_device - ); + || (task->task_state_flags & SAS_TASK_NEED_DEV_RESET); /* If the extraction of the request reference from the task * failed, then the request has been completed (or if there is a * pending reset then this abort request function must be failed * in order to escalate to the target reset). */ - if ((old_request == NULL) || - ((old_request != NULL) && - (old_request->sci_request_handle == NULL) && - (old_request->complete_in_target)) || - any_dev_reset) { - - spin_lock_irqsave(&task->task_state_lock, flags); + if ((old_request == NULL) || any_dev_reset) { /* If the device reset task flag is set, fail the task * management request. Otherwise, the original request @@ -1164,6 +1158,11 @@ int isci_task_abort_task(struct sas_task *task) */ task->task_state_flags &= ~SAS_TASK_STATE_DONE; + /* Make the reset happen as soon as possible. */ + task->task_state_flags |= SAS_TASK_NEED_DEV_RESET; + + spin_unlock_irqrestore(&task->task_state_lock, flags); + /* Fail the task management request in order to * escalate to the target reset. */ @@ -1176,13 +1175,8 @@ int isci_task_abort_task(struct sas_task *task) "task %p on dev %p\n", __func__, task, isci_device); - } else { - ret = TMF_RESP_FUNC_COMPLETE; - - dev_dbg(&isci_host->pdev->dev, - "%s: abort task not needed for %p\n", - __func__, task); + } else { /* The request has already completed and there * is nothing to do here other than to set the task * done bit, and indicate that the task abort function @@ -1190,89 +1184,65 @@ int isci_task_abort_task(struct sas_task *task) */ isci_set_task_doneflags(task); - /* Set the abort bit to make sure that libsas sticks the - * task in the completed task queue. - */ -/* task->task_state_flags |= SAS_TASK_STATE_ABORTED; */ + spin_unlock_irqrestore(&task->task_state_lock, flags); - /* Check for the situation where the request was - * left around on the device list but the - * request already completed. - */ - if (old_request && !old_request->sci_request_handle) { + ret = TMF_RESP_FUNC_COMPLETE; - isci_request_cleanup_completed_loiterer( - isci_host, isci_device, old_request - ); - } + dev_dbg(&isci_host->pdev->dev, + "%s: abort task not needed for %p\n", + __func__, task); } - spin_unlock_irqrestore(&task->task_state_lock, flags); return ret; } + else + spin_unlock_irqrestore(&task->task_state_lock, flags); spin_lock_irqsave(&isci_host->scic_lock, flags); - /* Sanity check the request status, and set the I/O kernel completion + /* Check the request status and change to "aborting" if currently + * "starting"; if true then set the I/O kernel completion * struct that will be triggered when the request completes. */ - if (isci_task_validate_request_to_abort( - old_request, - isci_host, - isci_device, - &aborted_io_completion) - == unallocated) { - dev_dbg(&isci_host->pdev->dev, - "%s: old_request not valid for device = %p\n", - __func__, - isci_device); - old_request = NULL; - } - - if (!old_request) { - - /* There is no isci_request attached to the sas_task. - * It must have been completed and detached. - */ - dev_dbg(&isci_host->pdev->dev, - "%s: old_request == NULL\n", - __func__); + old_state = isci_task_validate_request_to_abort( + old_request, isci_host, isci_device, + &aborted_io_completion); + if ((old_state != started) && (old_state != completed)) { spin_unlock_irqrestore(&isci_host->scic_lock, flags); - /* Set the state on the task. */ - isci_task_all_done(task); + /* The request was already being handled by someone else (because + * they got to set the state away from started). + */ + dev_dbg(&isci_host->pdev->dev, + "%s: device = %p; old_request %p already being aborted\n", + __func__, + isci_device, old_request); return TMF_RESP_FUNC_COMPLETE; } - if (task->task_proto == SAS_PROTOCOL_SMP || device_stopping) { - - if (device_stopping) - dev_dbg(&isci_host->pdev->dev, - "%s: device is stopping, thus no TMF\n", - __func__); - else - dev_dbg(&isci_host->pdev->dev, - "%s: request is SMP, thus no TMF\n", - __func__); - - old_request->complete_in_target = true; + if ((task->task_proto == SAS_PROTOCOL_SMP) + || device_stopping + || old_request->complete_in_target + ) { spin_unlock_irqrestore(&isci_host->scic_lock, flags); + dev_dbg(&isci_host->pdev->dev, + "%s: SMP request (%d)" + " or device is stopping (%d)" + " or complete_in_target (%d), thus no TMF\n", + __func__, (task->task_proto == SAS_PROTOCOL_SMP), + device_stopping, old_request->complete_in_target); + /* Set the state on the task. */ isci_task_all_done(task); ret = TMF_RESP_FUNC_COMPLETE; /* Stopping and SMP devices are not sent a TMF, and are not - * reset, but the outstanding I/O request is terminated here. - * - * Clean up the request on our side, and wait for the aborted - * I/O to complete. + * reset, but the outstanding I/O request is terminated below. */ - isci_terminate_request_core(isci_host, isci_device, old_request, - &aborted_io_completion); } else { /* Fill in the tmf stucture */ isci_task_build_tmf(&tmf, isci_device, isci_tmf_ssp_task_abort, @@ -1288,23 +1258,23 @@ int isci_task_abort_task(struct sas_task *task) ret = isci_task_execute_tmf(isci_host, &tmf, ISCI_ABORT_TASK_TIMEOUT_MS); - if (ret == TMF_RESP_FUNC_COMPLETE) { - old_request->complete_in_target = true; - - /* Clean up the request on our side, and wait for the aborted I/O to - * complete. - */ - isci_terminate_request_core(isci_host, isci_device, old_request, - &aborted_io_completion); - - /* Set the state on the task. */ - isci_task_all_done(task); - } else + if (ret != TMF_RESP_FUNC_COMPLETE) dev_err(&isci_host->pdev->dev, "%s: isci_task_send_tmf failed\n", __func__); } + if (ret == TMF_RESP_FUNC_COMPLETE) { + old_request->complete_in_target = true; + + /* Clean up the request on our side, and wait for the aborted I/O to + * complete. + */ + isci_terminate_request_core(isci_host, isci_device, old_request, + &aborted_io_completion); + } + /* Make sure we do not leave a reference to aborted_io_completion */ + old_request->io_request_completion = NULL; return ret; } -- cgit v1.2.1 From 1fad9e934a43407c1ba397b1b6b8882aa8a2cafd Mon Sep 17 00:00:00 2001 From: Jeff Skirvin Date: Fri, 4 Mar 2011 14:06:46 -0800 Subject: isci: save the i/o tag outside the scic request structure. The pointer to the core representation of a request is marked NULL at completion, but we need to save the i/o tag for task management. Signed-off-by: Jeff Skirvin Signed-off-by: Jacek Danecki [revise changelog] Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 02c40c00cb8b..e9bfc22d91d0 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -544,7 +544,7 @@ void isci_task_build_tmf( void (*tmf_sent_cb)(enum isci_tmf_cb_state, struct isci_tmf *, void *), - void *cb_data) + struct isci_request *old_request) { dev_dbg(&isci_device->isci_port->isci_host->pdev->dev, "%s: isci_device = %p\n", __func__, isci_device); @@ -555,7 +555,9 @@ void isci_task_build_tmf( tmf->tmf_code = code; tmf->timeout_timer = NULL; tmf->cb_state_func = tmf_sent_cb; - tmf->cb_data = cb_data; + tmf->cb_data = old_request; + tmf->io_tag = old_request->io_tag; + } static struct isci_request *isci_task_get_request_from_task( @@ -1248,10 +1250,6 @@ int isci_task_abort_task(struct sas_task *task) isci_task_build_tmf(&tmf, isci_device, isci_tmf_ssp_task_abort, isci_abort_task_process_cb, old_request); - tmf.io_tag = scic_io_request_get_io_tag( - old_request->sci_request_handle - ); - spin_unlock_irqrestore(&isci_host->scic_lock, flags); #define ISCI_ABORT_TASK_TIMEOUT_MS 500 /* half second timeout. */ -- cgit v1.2.1 From f0846c68912545d70da16b2fbedded37ea4394d8 Mon Sep 17 00:00:00 2001 From: Jeff Skirvin Date: Tue, 8 Mar 2011 19:22:07 -0700 Subject: isci: Cleaning up task execute path. Made sure the device ready check accounts for all states. Moved the aborted task check into the loop of pulling task requests off of the submitted list. Signed-off-by: Jeff Skirvin Signed-off-by: Jacek Danecki [remove host and device starting state checks] Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 141 ++++++++++++++++++++++++----------------------- 1 file changed, 71 insertions(+), 70 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index e9bfc22d91d0..3dc9ef3f305b 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -83,21 +83,10 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags) unsigned long flags; int ret; enum sci_status status; - + enum isci_status device_status; dev_dbg(task->dev->port->ha->dev, "%s: num=%d\n", __func__, num); - if (task->task_state_flags & SAS_TASK_STATE_ABORTED) { - - isci_task_complete_for_upper_layer( - task, - SAS_TASK_UNDELIVERED, - SAM_STAT_TASK_ABORTED, - isci_perform_normal_io_completion - ); - - return 0; /* The I/O was accepted (and failed). */ - } if ((task->dev == NULL) || (task->dev->port == NULL)) { /* Indicate SAS_TASK_UNDELIVERED, so that the scsi midlayer @@ -143,93 +132,105 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags) /* We don't have a valid host reference, so we * can't control the host queueing condition. */ - continue; + 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 == isci_ready) { + if (device) + device_status = device->status; + else + device_status = isci_freed; + + /* From this point onward, any process that needs to guarantee + * that there is no kernel I/O being started will have to wait + * for the quiesce spinlock. + */ + + if (device_status != isci_ready_for_io) { /* Forces a retry from scsi mid layer. */ dev_warn(task->dev->port->ha->dev, "%s: task %p: isci_host->status = %d, " - "device = %p\n", + "device = %p; device_status = 0x%x\n\n", __func__, task, isci_host_get_state(isci_host), - device); - - if (device) - dev_dbg(task->dev->port->ha->dev, - "%s: device->status = 0x%x\n", - __func__, device->status); + device, device_status); - /* 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 - ); + 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 + ); + } 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_host_can_dequeue(isci_host, 1); - } - /* the device is going down... */ - else if (!device || device->status != isci_ready_for_io) { + } else { + /* There is a device and it's ready for I/O. */ + spin_lock_irqsave(&task->task_state_lock, flags); - dev_dbg(task->dev->port->ha->dev, - "%s: task %p: isci_host->status = %d, " - "device = %p\n", - __func__, - task, - isci_host_get_state(isci_host), - device); + if (task->task_state_flags & SAS_TASK_STATE_ABORTED) { - if (device) - dev_dbg(task->dev->port->ha->dev, - "%s: device->status = 0x%x\n", - __func__, device->status); + spin_unlock_irqrestore(&task->task_state_lock, + flags); - /* 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 - ); - isci_host_can_dequeue(isci_host, 1); + isci_task_complete_for_upper_layer( + task, + SAS_TASK_UNDELIVERED, + SAM_STAT_TASK_ABORTED, + isci_perform_normal_io_completion + ); - } else { - /* build and send the request. */ - status = isci_request_execute(isci_host, task, &request, - gfp_flags); + /* The I/O was aborted. */ - if (status == SCI_SUCCESS) { - spin_lock_irqsave(&task->task_state_lock, flags); + } else { task->task_state_flags |= SAS_TASK_AT_INITIATOR; spin_unlock_irqrestore(&task->task_state_lock, flags); - } else { - /* Indicate QUEUE_FULL so that the scsi - * midlayer retries. if the request - * failed for remote device reasons, - * it gets returned as - * SAS_TASK_UNDELIVERED next time - * through. - */ - isci_task_complete_for_upper_layer( + + /* build and send the request. */ + status = isci_request_execute(isci_host, task, &request, + gfp_flags); + + if (status != SCI_SUCCESS) { + + spin_lock_irqsave(&task->task_state_lock, flags); + /* Did not really start this command. */ + task->task_state_flags &= ~SAS_TASK_AT_INITIATOR; + spin_unlock_irqrestore(&task->task_state_lock, flags); + + /* Indicate QUEUE_FULL so that the scsi + * midlayer retries. if the request + * failed for remote device reasons, + * it gets returned as + * 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_host_can_dequeue(isci_host, 1); + } } } +next_task: task = list_entry(task->list.next, struct sas_task, list); } while (--num > 0); return 0; -- cgit v1.2.1 From cbb65c665b341e560b7a3b37cc616376031b3ee5 Mon Sep 17 00:00:00 2001 From: Jeff Skirvin Date: Fri, 4 Mar 2011 14:06:50 -0800 Subject: isci: Code review change for completion pointer cleanup. Since the request structure contains a pointer to the completion to be used if the request is being aborted or terminated, there is no reason to pass the completion as a pointer to isci_terminate_request_core(). Signed-off-by: Jeff Skirvin Signed-off-by: Jacek Danecki Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 3dc9ef3f305b..5e80e8449223 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -677,10 +677,9 @@ static void isci_request_cleanup_completed_loiterer( static void isci_terminate_request_core( struct isci_host *isci_host, struct isci_remote_device *isci_device, - struct isci_request *isci_request, - struct completion *request_completion) + struct isci_request *isci_request) { - enum sci_status status = SCI_SUCCESS; + enum sci_status status = SCI_SUCCESS; bool was_terminated = false; bool needs_cleanup_handling = false; enum isci_request_status request_status; @@ -720,6 +719,7 @@ static void isci_terminate_request_core( */ if (isci_request->sci_request_handle != NULL) { was_terminated = true; + needs_cleanup_handling = true; status = scic_controller_terminate_request( isci_host->core_controller, to_sci_dev(isci_device), @@ -744,15 +744,15 @@ static void isci_terminate_request_core( dev_dbg(&isci_host->pdev->dev, "%s: before completion wait (%p)\n", __func__, - request_completion); + isci_request->io_request_completion); /* Wait here for the request to complete. */ - wait_for_completion(request_completion); + wait_for_completion(isci_request->io_request_completion); dev_dbg(&isci_host->pdev->dev, "%s: after completion wait (%p)\n", __func__, - request_completion); + isci_request->io_request_completion); } if (needs_cleanup_handling) @@ -760,7 +760,10 @@ static void isci_terminate_request_core( isci_host, isci_device, isci_request ); } + /* Clear the completion pointer from the request. */ + isci_request->io_request_completion = NULL; } + static void isci_terminate_request( struct isci_host *isci_host, struct isci_remote_device *isci_device, @@ -800,7 +803,7 @@ static void isci_terminate_request( * request and potentially calling up to libsas. */ isci_terminate_request_core(isci_host, isci_device, - isci_request, &request_completion); + isci_request); } } @@ -1268,8 +1271,7 @@ int isci_task_abort_task(struct sas_task *task) /* Clean up the request on our side, and wait for the aborted I/O to * complete. */ - isci_terminate_request_core(isci_host, isci_device, old_request, - &aborted_io_completion); + isci_terminate_request_core(isci_host, isci_device, old_request); } /* Make sure we do not leave a reference to aborted_io_completion */ -- cgit v1.2.1 From 4dc043c41037fc6e369270daaa626465a8766565 Mon Sep 17 00:00:00 2001 From: Jeff Skirvin Date: Fri, 4 Mar 2011 14:06:52 -0800 Subject: isci: Termination handling cleanup, added termination timeouts. Added a request "dead" state for use when a termination wait times-out. isci_terminate_pending_requests now detaches the device's pending list and terminates each entry on the detached list. Signed-off-by: Jeff Skirvin Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 233 ++++++++++++++++++++++++++++------------------- 1 file changed, 141 insertions(+), 92 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 5e80e8449223..c781a4ab4a50 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -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 @@ -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). @@ -733,13 +771,16 @@ 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", @@ -747,21 +788,62 @@ static void isci_terminate_request_core( 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( @@ -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( @@ -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 + ); + } } /** -- cgit v1.2.1 From c3f42feb0c3d20dc7007336e7de949408b93afef Mon Sep 17 00:00:00 2001 From: Jeff Skirvin Date: Fri, 4 Mar 2011 14:06:56 -0800 Subject: isci: Fix TMF build for SAS/SATA LUN reset cases. In the case where a SAS or SATA LUN reset TMF is built a NULL pointer dereference occurred because of the (unused) callback data pointer. Signed-off-by: Jeff Skirvin Signed-off-by: Dan Williams Signed-off-by: Jacek Danecki --- drivers/scsi/isci/task.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index c781a4ab4a50..c2d74c3929fb 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -545,7 +545,7 @@ void isci_task_build_tmf( void (*tmf_sent_cb)(enum isci_tmf_cb_state, struct isci_tmf *, void *), - struct isci_request *old_request) + void *cb_data) { dev_dbg(&isci_device->isci_port->isci_host->pdev->dev, "%s: isci_device = %p\n", __func__, isci_device); @@ -556,9 +556,21 @@ void isci_task_build_tmf( tmf->tmf_code = code; tmf->timeout_timer = NULL; tmf->cb_state_func = tmf_sent_cb; - tmf->cb_data = old_request; - tmf->io_tag = old_request->io_tag; + tmf->cb_data = cb_data; +} +void isci_task_build_abort_task_tmf( + struct isci_tmf *tmf, + struct isci_remote_device *isci_device, + enum isci_tmf_function_codes code, + void (*tmf_sent_cb)(enum isci_tmf_cb_state, + struct isci_tmf *, + void *), + struct isci_request *old_request) +{ + isci_task_build_tmf(tmf, isci_device, code, tmf_sent_cb, + (void *)old_request); + tmf->io_tag = old_request->io_tag; } static struct isci_request *isci_task_get_request_from_task( @@ -1300,8 +1312,10 @@ int isci_task_abort_task(struct sas_task *task) */ } else { /* Fill in the tmf stucture */ - isci_task_build_tmf(&tmf, isci_device, isci_tmf_ssp_task_abort, - isci_abort_task_process_cb, old_request); + isci_task_build_abort_task_tmf(&tmf, isci_device, + isci_tmf_ssp_task_abort, + isci_abort_task_process_cb, + old_request); spin_unlock_irqrestore(&isci_host->scic_lock, flags); -- cgit v1.2.1 From 70957a94d70cb82459bd3aea171c54d0a5cd6dbb Mon Sep 17 00:00:00 2001 From: Jeff Skirvin Date: Fri, 4 Mar 2011 14:06:58 -0800 Subject: isci: Fixed BUG_ON in isci_abort_task_process_cb callback. The request may be in the "aborted" or the "completed" state when performing a task management operation on it. Signed-off-by: Jeff Skirvin Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index c2d74c3929fb..a1234e42937e 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -1116,7 +1116,8 @@ static void isci_abort_task_process_cb( * request state was already set to "aborted" by the abort * task function. */ - BUG_ON(old_request->status != aborted); + BUG_ON((old_request->status != aborted) + && (old_request->status != completed)); break; case isci_tmf_timed_out: -- cgit v1.2.1 From 50e7f9b5a9ae4a763b2c27500807cf237faca9b0 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 9 Mar 2011 21:27:46 -0800 Subject: isci: Errors in the submit path for SATA devices manage the ap lock. Since libsas takes the domain device sata_dev.ap->lock before submitting a task, error completions in the submit path for SATA devices must unlock/relock when completing the sas_task back to libsas. Signed-off-by: Jeff Skirvin Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index a1234e42937e..d00b4c97b85b 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -54,6 +54,8 @@ */ #include +#include +#include #include "scic_task_request.h" #include "scic_remote_device.h" #include "scic_io_request.h" @@ -64,6 +66,91 @@ #include "sata.h" #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. +* +* 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) +{ + unsigned long flags = 0; + struct Scsi_Host *host = NULL; + + 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) */ + dev_dbg(task->dev->port->ha->dev, + "%s: Normal - task = %p, response=%d, status=%d\n", + __func__, task, response, status); + + 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 + * devices before I/O starts, we need to unlock + * before we can call back and report the I/O + * submission error. + */ + if (task->dev + && task->dev->port + && task->dev->port->ha) { + + host = task->dev->port->ha->core.shost; + raw_local_irq_save(flags); + spin_unlock(host->host_lock); + } + task->task_done(task); + if (host) { + spin_lock(host->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, + "%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, + "%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, + "%s: isci task notification default case!", + __func__); + sas_task_abort(task); + break; + } +} /** * isci_task_execute_task() - This function is one of the SAS Domain Template -- cgit v1.2.1 From 1077a574103177bff22b7cdd155d960f46ac1e8f Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 11 Mar 2011 10:13:51 -0800 Subject: 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 --- drivers/scsi/isci/task.c | 168 ++++++++++++++++------------------------------- 1 file changed, 55 insertions(+), 113 deletions(-) (limited to 'drivers/scsi/isci/task.c') 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; } -- cgit v1.2.1 From 35173d579a08c0d145b3020039d3ba33fbf2c184 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sat, 26 Mar 2011 16:43:01 -0700 Subject: isci: namespacecheck cleanups * mark needlessly global routines static * delete unused functions * move kernel-doc blocks from header files to source * reorder some functions to delete declarations * more default handler cleanups phy Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index d48368002504..7e9668402559 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -588,7 +588,7 @@ void isci_task_build_tmf( tmf->cb_data = cb_data; } -void isci_task_build_abort_task_tmf( +static void isci_task_build_abort_task_tmf( struct isci_tmf *tmf, struct isci_remote_device *isci_device, enum isci_tmf_function_codes code, @@ -1528,15 +1528,6 @@ void isci_task_request_complete( * * lun for specified task request. */ -u32 isci_task_ssp_request_get_lun(struct isci_request *request) -{ - struct isci_tmf *isci_tmf = isci_request_access_tmf(request); - - dev_dbg(&request->isci_host->pdev->dev, - "%s: lun = %d\n", __func__, isci_tmf->lun[0]); -/* @todo: build lun from array of bytes to 32 bit */ - return isci_tmf->lun[0]; -} /** * isci_task_ssp_request_get_function() - This function is called by the sci -- cgit v1.2.1 From f219f010a355487638bf2fff4724a420e7158fd2 Mon Sep 17 00:00:00 2001 From: Jeff Skirvin Date: Thu, 31 Mar 2011 13:10:34 -0700 Subject: isci: Properly handle requests in the "aborting" state. When a TMF times-out, the request is set back to "aborting". Requests in the "aborting" state must be terminated when LUN and device resets occur. Signed-off-by: Jeff Skirvin Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 7e9668402559..338f08ec4d8e 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -903,7 +903,9 @@ static void isci_terminate_request( new_request_state ); - if ((old_state == started) || (old_state == completed)) { + if ((old_state == started) || + (old_state == completed) || + (old_state == aborting)) { /* If the old_state is started: * This request was not already being aborted. If it had been, @@ -920,6 +922,10 @@ static void isci_terminate_request( * This request completed from the SCU hardware perspective * and now just needs cleaning up in terms of freeing the * request and potentially calling up to libsas. + * + * If old_state == aborting: + * This request has already gone through a TMF timeout, but may + * not have been terminated; needs cleaning up at least. */ isci_terminate_request_core(isci_host, isci_device, isci_request); @@ -1297,14 +1303,16 @@ int isci_task_abort_task(struct sas_task *task) spin_lock_irqsave(&isci_host->scic_lock, flags); - /* Check the request status and change to "aborting" if currently + /* Check the request status and change to "aborted" if currently * "starting"; if true then set the I/O kernel completion * struct that will be triggered when the request completes. */ old_state = isci_task_validate_request_to_abort( old_request, isci_host, isci_device, &aborted_io_completion); - if ((old_state != started) && (old_state != completed)) { + if ((old_state != started) && + (old_state != completed) && + (old_state != aborting)) { spin_unlock_irqrestore(&isci_host->scic_lock, flags); -- cgit v1.2.1 From ed8a72d108bd951909b28fa4a89aad6489f414e1 Mon Sep 17 00:00:00 2001 From: Jeff Skirvin Date: Thu, 31 Mar 2011 13:10:40 -0700 Subject: isci: Qualify when the host lock is managed for STP/SATA callbacks. In the case of internal discovery related STP/SATA I/O started through sas_execute_task the host lock is not taken by libsas before calling lldd_execute_task, so the lock should not be managed before calling back to libsas through task->task_done or sas_task_abort. Signed-off-by: Jeff Skirvin Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 338f08ec4d8e..5bcea60fd8c4 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -55,7 +55,6 @@ #include #include -#include #include "scic_task_request.h" #include "scic_remote_device.h" #include "scic_io_request.h" @@ -93,26 +92,13 @@ static void isci_task_refuse(struct isci_host *ihost, struct sas_task *task, case isci_perform_normal_io_completion: /* Normal notification (task_done) */ dev_dbg(&ihost->pdev->dev, - "%s: Normal - task = %p, response=%d, status=%d\n", + "%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 - * devices before I/O starts, we need to unlock - * before we can call back and report the I/O - * submission error. - */ - unsigned long flags; - raw_local_irq_save(flags); - spin_unlock(ihost->shost->host_lock); - task->task_done(task); - spin_lock(ihost->shost->host_lock); - raw_local_irq_restore(flags); - } else - task->task_done(task); + isci_execpath_callback(ihost, task, task->task_done); break; case isci_perform_aborted_io_completion: @@ -120,16 +106,19 @@ static void isci_task_refuse(struct isci_host *ihost, struct sas_task *task, * abort path. */ dev_warn(&ihost->pdev->dev, - "%s: Aborted - task = %p, response=%d, status=%d\n", + "%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(&ihost->pdev->dev, - "%s: Error - task = %p, response=%d, status=%d\n", + "%s: Error - task = %p, response=%d, " + "status=%d\n", __func__, task, response, status); - sas_task_abort(task); + + isci_execpath_callback(ihost, task, sas_task_abort); break; default: -- cgit v1.2.1 From 4393aa4e6b9517a666f0ef6b774fd421a9dc4c68 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 31 Mar 2011 13:10:44 -0700 Subject: isci: fix fragile/conditional isci_host lookups A domain_device can always reference back to ->lldd_ha unlike local lldd structures. Fix up cases where the driver uses local objects to look up the isci_host. This also changes the calling conventions of some routines to expect a valid isci_host parameter rather than re-lookup the pointer on entry. Incidentally cleans up some macros that are longer to type than the open-coded equivalent: isci_host_from_sas_ha isci_dev_from_domain_dev Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 87 +++++++++++++++--------------------------------- 1 file changed, 27 insertions(+), 60 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 5bcea60fd8c4..c6c97ad58c9f 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -146,7 +146,7 @@ static void isci_task_refuse(struct isci_host *ihost, struct sas_task *task, */ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags) { - struct isci_host *ihost = task->dev->port->ha->lldd_ha; + struct isci_host *ihost = dev_to_ihost(task->dev); struct isci_request *request = NULL; struct isci_remote_device *device; unsigned long flags; @@ -169,7 +169,7 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags) "task = %p, num = %d; dev = %p; cmd = %p\n", task, num, task->dev, task->uldd_task); - device = isci_dev_from_domain_dev(task->dev); + device = task->dev->lldd_dev; if (device) device_status = device->status; @@ -593,7 +593,6 @@ static void isci_task_build_abort_task_tmf( static struct isci_request *isci_task_get_request_from_task( struct sas_task *task, - struct isci_host **isci_host, struct isci_remote_device **isci_device) { @@ -609,9 +608,6 @@ static struct isci_request *isci_task_get_request_from_task( (task->task_state_flags & SAS_TASK_AT_INITIATOR) && (request != NULL)) { - if (isci_host != NULL) - *isci_host = request->isci_host; - if (isci_device != NULL) *isci_device = request->isci_device; } @@ -1027,26 +1023,17 @@ static int isci_task_send_lu_reset_sas( * * status, zero indicates success. */ -int isci_task_lu_reset( - struct domain_device *domain_device, - u8 *lun) +int isci_task_lu_reset(struct domain_device *domain_device, u8 *lun) { - struct isci_host *isci_host = NULL; + struct isci_host *isci_host = dev_to_ihost(domain_device); struct isci_remote_device *isci_device = NULL; int ret; bool device_stopping = false; - if (domain_device == NULL) { - pr_warn("%s: domain_device == NULL\n", __func__); - return TMF_RESP_FUNC_FAILED; - } - - isci_device = isci_dev_from_domain_dev(domain_device); - - if (domain_device->port != NULL) - isci_host = isci_host_from_sas_ha(domain_device->port->ha); + isci_device = domain_device->lldd_dev; - pr_debug("%s: domain_device=%p, isci_host=%p; isci_device=%p\n", + dev_dbg(&isci_host->pdev->dev, + "%s: domain_device=%p, isci_host=%p; isci_device=%p\n", __func__, domain_device, isci_host, isci_device); if (isci_device != NULL) @@ -1057,24 +1044,18 @@ int isci_task_lu_reset( * device's list, fail this LUN reset request in order to * escalate to the device reset. */ - if ((isci_device == NULL) || - (isci_host == NULL) || - ((isci_host != NULL) && - (isci_device != NULL) && - (device_stopping || - (isci_device_is_reset_pending(isci_host, isci_device))))) { + if (!isci_device || device_stopping || + isci_device_is_reset_pending(isci_host, isci_device)) { dev_warn(&isci_host->pdev->dev, - "%s: No dev (%p), no host (%p), or " + "%s: No dev (%p), or " "RESET PENDING: domain_device=%p\n", - __func__, isci_device, isci_host, domain_device); + __func__, isci_device, domain_device); return TMF_RESP_FUNC_FAILED; } /* Send the task management part of the reset. */ if (sas_protocol_ata(domain_device->tproto)) { - ret = isci_task_send_lu_reset_sata( - isci_host, isci_device, lun - ); + ret = isci_task_send_lu_reset_sata(isci_host, isci_device, lun); } else ret = isci_task_send_lu_reset_sas(isci_host, isci_device, lun); @@ -1173,11 +1154,11 @@ static void isci_abort_task_process_cb( */ int isci_task_abort_task(struct sas_task *task) { + struct isci_host *isci_host = dev_to_ihost(task->dev); DECLARE_COMPLETION_ONSTACK(aborted_io_completion); struct isci_request *old_request = NULL; enum isci_request_status old_state; struct isci_remote_device *isci_device = NULL; - struct isci_host *isci_host = NULL; struct isci_tmf tmf; int ret = TMF_RESP_FUNC_FAILED; unsigned long flags; @@ -1189,8 +1170,7 @@ int isci_task_abort_task(struct sas_task *task) * in the device, because tasks driving resets may land here * after completion in the core. */ - old_request = isci_task_get_request_from_task(task, &isci_host, - &isci_device); + old_request = isci_task_get_request_from_task(task, &isci_device); dev_dbg(&isci_host->pdev->dev, "%s: task = %p\n", __func__, task); @@ -1610,37 +1590,29 @@ u32 isci_task_ssp_request_get_response_data_length( */ int isci_bus_reset_handler(struct scsi_cmnd *cmd) { + struct domain_device *dev = cmd_to_domain_dev(cmd); + struct isci_host *isci_host = dev_to_ihost(dev); unsigned long flags = 0; - struct isci_host *isci_host = NULL; enum sci_status status; int base_status; - struct isci_remote_device *isci_dev - = isci_dev_from_domain_dev( - sdev_to_domain_dev(cmd->device)); + struct isci_remote_device *isci_dev = dev->lldd_dev; - dev_dbg(&cmd->device->sdev_gendev, + dev_dbg(&isci_host->pdev->dev, "%s: cmd %p, isci_dev %p\n", __func__, cmd, isci_dev); if (!isci_dev) { - dev_warn(&cmd->device->sdev_gendev, + dev_warn(&isci_host->pdev->dev, "%s: isci_dev is GONE!\n", __func__); return TMF_RESP_FUNC_COMPLETE; /* Nothing to reset. */ } - if (isci_dev->isci_port != NULL) - isci_host = isci_dev->isci_port->isci_host; - - if (isci_host != NULL) - spin_lock_irqsave(&isci_host->scic_lock, flags); - + spin_lock_irqsave(&isci_host->scic_lock, flags); status = scic_remote_device_reset(to_sci_dev(isci_dev)); if (status != SCI_SUCCESS) { - - if (isci_host != NULL) - spin_unlock_irqrestore(&isci_host->scic_lock, flags); + spin_unlock_irqrestore(&isci_host->scic_lock, flags); scmd_printk(KERN_WARNING, cmd, "%s: scic_remote_device_reset(%p) returned %d!\n", @@ -1648,14 +1620,13 @@ int isci_bus_reset_handler(struct scsi_cmnd *cmd) return TMF_RESP_FUNC_FAILED; } - if (isci_host != NULL) - spin_unlock_irqrestore(&isci_host->scic_lock, flags); + spin_unlock_irqrestore(&isci_host->scic_lock, flags); /* Make sure all pending requests are able to be fully terminated. */ - isci_device_clear_reset_pending(isci_dev); + isci_device_clear_reset_pending(isci_host, isci_dev); /* Terminate in-progress I/O now. */ - isci_remote_device_nuke_requests(isci_dev); + isci_remote_device_nuke_requests(isci_host, isci_dev); /* Call into the libsas default handler (which calls sas_phy_reset). */ base_status = sas_eh_bus_reset_handler(cmd); @@ -1672,13 +1643,9 @@ int isci_bus_reset_handler(struct scsi_cmnd *cmd) } /* WHAT TO DO HERE IF sas_phy_reset FAILS? */ - - if (isci_host != NULL) - spin_lock_irqsave(&isci_host->scic_lock, flags); + spin_lock_irqsave(&isci_host->scic_lock, flags); status = scic_remote_device_reset_complete(to_sci_dev(isci_dev)); - - if (isci_host != NULL) - spin_unlock_irqrestore(&isci_host->scic_lock, flags); + spin_unlock_irqrestore(&isci_host->scic_lock, flags); if (status != SCI_SUCCESS) { scmd_printk(KERN_WARNING, cmd, @@ -1688,7 +1655,7 @@ int isci_bus_reset_handler(struct scsi_cmnd *cmd) } /* WHAT TO DO HERE IF scic_remote_device_reset_complete FAILS? */ - dev_dbg(&cmd->device->sdev_gendev, + dev_dbg(&isci_host->pdev->dev, "%s: cmd %p, isci_dev %p complete.\n", __func__, cmd, isci_dev); -- cgit v1.2.1 From c629582d0dea42d8b3617f8c46ea2770b95e23aa Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 2 Apr 2011 08:15:20 -0400 Subject: isci: remove scic_controller state handlers Remove the state handler indirections for the scic_controller, and replace them with procedural calls that check for the correct state first. Signed-off-by: Christoph Hellwig Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index c6c97ad58c9f..aa6b43067e25 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -1480,7 +1480,7 @@ void isci_task_request_complete( /* PRINT_TMF( ((struct isci_tmf *)request->task)); */ tmf_complete = tmf->complete; - scic_controller_complete_task( + scic_controller_complete_io( isci_host->core_controller, to_sci_dev(isci_device), request->sci_request_handle -- cgit v1.2.1 From 467e855a0331f619f41fbf7391bc29ec0ca923a0 Mon Sep 17 00:00:00 2001 From: Bartosz Barcinski Date: Tue, 12 Apr 2011 17:28:41 -0700 Subject: isci: sparse warnings cleanup Clean warnings and errors reported by sparse tool. request.c:430:50: warning: mixing different enum types remote_device.c:534:39: warning: symbol 'flags' shadows an earlier one task.c:495:44: warning: mixing different enum types scic_sds_controller.c:2155:24: warning: mixing different enum types scic_sds_controller.c:2272:36: warning: mixing different enum types scic_sds_controller.c:2911:38: warning: incorrect type in initializer (different address spaces) scic_sds_controller.c:2913:25: warning: incorrect type in argument 2 (different address spaces) scic_sds_request.c:875:34: warning: cast removes address space of expression scic_sds_request.c:876:123: warning: incorrect type in argument 2 (different address spaces) scic_sds_port.c:585:51: warning: incorrect type in assignment (different address spaces) scic_sds_port.c:712:9: warning: incorrect type in argument 2 (different address spaces) scic_sds_port.c:1770:25: warning: incorrect type in argument 2 (different address spaces) Signed-off-by: Bartosz Barcinski Signed-off-by: Maciej Patelczyk [fixed up some false positives and misconversions] Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index aa6b43067e25..b88101e195d1 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -429,7 +429,7 @@ int isci_task_execute_tmf( unsigned long timeout_ms) { DECLARE_COMPLETION_ONSTACK(completion); - enum sci_status status = SCI_FAILURE; + enum sci_task_status status = SCI_TASK_FAILURE; struct scic_sds_remote_device *sci_device; struct isci_remote_device *isci_device = tmf->device; struct isci_request *request; @@ -488,7 +488,7 @@ int isci_task_execute_tmf( SCI_CONTROLLER_INVALID_IO_TAG ); - if (status != SCI_SUCCESS) { + if (status != SCI_TASK_SUCCESS) { dev_warn(&isci_host->pdev->dev, "%s: start_io failed - status = 0x%x, request = %p\n", __func__, -- cgit v1.2.1 From 6cb4d6b382be6345c2d0c4b1b90dfdf9af32da7e Mon Sep 17 00:00:00 2001 From: Bartosz Barcinski Date: Tue, 12 Apr 2011 17:28:43 -0700 Subject: isci: audit usage of BUG_ON macro in isci driver Removes unnecessary usage of BUG_ON macro, excluding core directory. In some cases macro is unnecesary, check is done in caller function. In other cases macro is replaced by if construction with appropriate warning. Signed-off-by: Maciej Patelczyk [changed some survivable bug conditions to WARN_ONCE] Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index b88101e195d1..c79968db871c 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -272,7 +272,7 @@ static enum sci_status isci_task_request_build( { struct scic_sds_remote_device *sci_device; enum sci_status status = SCI_FAILURE; - struct isci_request *request; + struct isci_request *request = NULL; struct isci_remote_device *isci_device; /* struct sci_sas_identify_address_frame_protocols dev_protocols; */ struct smp_discover_response_protocols dev_protocols; @@ -372,8 +372,6 @@ static void isci_tmf_timeout_cb(void *tmf_request_arg) struct isci_tmf *tmf = isci_request_access_tmf(request); enum sci_status status; - BUG_ON(request->ttype != tmf_task); - /* This task management request has timed-out. Terminate the request * so that the request eventually completes to the requestor in the * request completion callback path. @@ -1121,8 +1119,11 @@ static void isci_abort_task_process_cb( * request state was already set to "aborted" by the abort * task function. */ - BUG_ON((old_request->status != aborted) - && (old_request->status != completed)); + if ((old_request->status != aborted) + && (old_request->status != completed)) + dev_err(&old_request->isci_host->pdev->dev, + "%s: Bad request status (%d): tmf=%p, old_request=%p\n", + __func__, old_request->status, tmf, old_request); break; case isci_tmf_timed_out: -- cgit v1.2.1 From 57f20f4ed6fb702339be2ef4dea9d15e6a7d0d07 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 21 Apr 2011 18:14:45 -0700 Subject: isci: unify remote_device data structures Make it explicit that isci_remote_device and scic_sds_remote_device are one in the same object. Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index c79968db871c..f54f523b8d40 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -282,7 +282,7 @@ static enum sci_status isci_task_request_build( "%s: isci_tmf = %p\n", __func__, isci_tmf); isci_device = isci_tmf->device; - sci_device = to_sci_dev(isci_device); + sci_device = &isci_device->sci; /* do common allocation and init of request object. */ status = isci_request_alloc_tmf( @@ -390,7 +390,7 @@ static void isci_tmf_timeout_cb(void *tmf_request_arg) /* Terminate the TMF transmit request. */ status = scic_controller_terminate_request( request->isci_host->core_controller, - to_sci_dev(request->isci_device), + &request->isci_device->sci, request->sci_request_handle ); @@ -448,7 +448,7 @@ int isci_task_execute_tmf( "%s: isci_device = %p\n", __func__, isci_device); - sci_device = to_sci_dev(isci_device); + sci_device = &isci_device->sci; /* Assign the pointer to the TMF's completion kernel wait structure. */ tmf->complete = &completion; @@ -784,9 +784,8 @@ static void isci_terminate_request_core( needs_cleanup_handling = true; status = scic_controller_terminate_request( isci_host->core_controller, - to_sci_dev(isci_device), - isci_request->sci_request_handle - ); + &isci_device->sci, + isci_request->sci_request_handle); } spin_unlock_irqrestore(&isci_host->scic_lock, flags); @@ -1483,9 +1482,8 @@ void isci_task_request_complete( scic_controller_complete_io( isci_host->core_controller, - to_sci_dev(isci_device), - request->sci_request_handle - ); + &isci_device->sci, + request->sci_request_handle); /* NULL the request handle to make sure it cannot be terminated * or completed again. */ @@ -1611,7 +1609,7 @@ int isci_bus_reset_handler(struct scsi_cmnd *cmd) } spin_lock_irqsave(&isci_host->scic_lock, flags); - status = scic_remote_device_reset(to_sci_dev(isci_dev)); + status = scic_remote_device_reset(&isci_dev->sci); if (status != SCI_SUCCESS) { spin_unlock_irqrestore(&isci_host->scic_lock, flags); @@ -1645,7 +1643,7 @@ int isci_bus_reset_handler(struct scsi_cmnd *cmd) /* WHAT TO DO HERE IF sas_phy_reset FAILS? */ spin_lock_irqsave(&isci_host->scic_lock, flags); - status = scic_remote_device_reset_complete(to_sci_dev(isci_dev)); + status = scic_remote_device_reset_complete(&isci_dev->sci); spin_unlock_irqrestore(&isci_host->scic_lock, flags); if (status != SCI_SUCCESS) { -- cgit v1.2.1 From 88f3b62ac131e2549b6c262cacbd47e8cca42d6e Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 22 Apr 2011 19:18:03 -0700 Subject: isci: move remote_device handling out of the core Now that the core/lldd remote_device data structures are nominally unified merge the corresponding sources into the top-level directory. Also move the remote_node_context infrastructure which has no analog at the lldd level. Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index f54f523b8d40..e011d668949d 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -56,10 +56,9 @@ #include #include #include "scic_task_request.h" -#include "scic_remote_device.h" #include "scic_io_request.h" -#include "scic_sds_remote_device.h" -#include "scic_sds_remote_node_context.h" +#include "remote_device.h" +#include "remote_node_context.h" #include "isci.h" #include "request.h" #include "sata.h" -- cgit v1.2.1 From a1a113b0a1ea437daf099b44f8a39e93a02a3f47 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 21 Apr 2011 18:44:45 -0700 Subject: isci: kill smp_discover_response_protocols in favor of domain_device.dev_type This is step 1 of removing the contortions to: 1/ unparse expander phy data into a smp discover frame 2/ open-code-parse the smp discover fram into a domain_device.dev_type equivalent libsas has already spent cycles determining the dev_type, so now that scic_sds_remote_device is unified with isci_remote_device we can directly reference dev_type. This might also change multi-level expander detection as we previously only looked at dev_type == EDGE_DEV and we did not consider the FANOUT_DEV case. Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index e011d668949d..c6f1ffd713a8 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -273,15 +273,14 @@ static enum sci_status isci_task_request_build( enum sci_status status = SCI_FAILURE; struct isci_request *request = NULL; struct isci_remote_device *isci_device; -/* struct sci_sas_identify_address_frame_protocols dev_protocols; */ - struct smp_discover_response_protocols dev_protocols; - + struct domain_device *dev; dev_dbg(&isci_host->pdev->dev, "%s: isci_tmf = %p\n", __func__, isci_tmf); isci_device = isci_tmf->device; sci_device = &isci_device->sci; + dev = isci_device->domain_dev; /* do common allocation and init of request object. */ status = isci_request_alloc_tmf( @@ -319,16 +318,8 @@ static enum sci_status isci_task_request_build( request ); - scic_remote_device_get_protocols( - sci_device, - &dev_protocols - ); - - /* let the core do it's protocol - * specific construction. - */ - if (dev_protocols.u.bits.attached_ssp_target) { - + /* XXX convert to get this from task->tproto like other drivers */ + if (dev->dev_type == SAS_END_DEV) { isci_tmf->proto = SAS_PROTOCOL_SSP; status = scic_task_request_construct_ssp( request->sci_request_handle @@ -337,8 +328,7 @@ static enum sci_status isci_task_request_build( goto errout; } - if (dev_protocols.u.bits.attached_stp_target) { - + if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) { isci_tmf->proto = SAS_PROTOCOL_SATA; status = isci_sata_management_task_request_build(request); -- cgit v1.2.1 From d2d61433a85f814c7bc0b20993bb39e97f2dde76 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Thu, 21 Apr 2011 05:36:23 +0000 Subject: isci: Remove excessive log noise with expander hot-unplug We are logging excessive output when hot unplug from expander. Moving that to debug. Signed-off-by: Dave Jiang Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index c6f1ffd713a8..c0ed1b28f3e5 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -183,13 +183,14 @@ 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(&ihost->pdev->dev, - "%s: task %p: isci_host->status = %d, " - "device = %p; device_status = 0x%x\n\n", - __func__, - task, - isci_host_get_state(ihost), - device, device_status); + dev_dbg(&ihost->pdev->dev, + "%s: task %p: isci_host->status = %d, " + "device = %p; device_status = 0x%x\n\n", + __func__, + task, + isci_host_get_state(ihost), + device, + device_status); if (device_status == isci_ready) { /* Indicate QUEUE_FULL so that the scsi midlayer -- cgit v1.2.1 From 890cae9b8a7defd87feb1ec77a2affd25bd59cce Mon Sep 17 00:00:00 2001 From: Maciej Patelczyk Date: Thu, 28 Apr 2011 22:06:31 +0000 Subject: isci: Removed sci_base_object from scic_sds_request. The 'struct sci_base_object' was removed from the struct scic_sds_request and was replaced by a pointer to struct isci_request. Signed-off-by: Maciej Patelczyk Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index c0ed1b28f3e5..95f386723212 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -63,7 +63,7 @@ #include "request.h" #include "sata.h" #include "task.h" - +#include "core/scic_sds_request.h" /** * 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. @@ -314,10 +314,7 @@ static enum sci_status isci_task_request_build( goto errout; } - sci_object_set_association( - request->sci_request_handle, - request - ); + request->sci_request_handle->ireq = request; /* XXX convert to get this from task->tproto like other drivers */ if (dev->dev_type == SAS_END_DEV) { -- cgit v1.2.1 From f2f300806fe186a6c45020a444667755edcce672 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Wed, 4 May 2011 15:02:02 -0700 Subject: isci: Convert SATA fis data structures to Linux native Converting of sata_fis_reg_d2h to dev_to_host_fis Converting of sata_fis_reg_h2d to host_to_dev_fis Signed-off-by: Dave Jiang Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 95f386723212..f9a1c41a5ce8 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -1452,10 +1452,8 @@ void isci_task_request_complete( memcpy(&tmf->resp.d2h_fis, scic_stp_io_request_get_d2h_reg_address( - request->sci_request_handle - ), - sizeof(struct sata_fis_reg_d2h) - ); + request->sci_request_handle), + sizeof(struct dev_to_host_fis)); } /* Manage the timer if it is still running. */ -- cgit v1.2.1 From 0cfa890e5a8a9e3b01b75c17a7856cf96e026e27 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Wed, 4 May 2011 17:44:54 -0700 Subject: isci: Fixup SSP command IU and task IU Fixup of SSP command IU and SSP task IU to something that looks like Linux Signed-off-by: Dave Jiang Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 49 ------------------------------------------------ 1 file changed, 49 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index f9a1c41a5ce8..c4db95933d41 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -1481,55 +1481,6 @@ void isci_task_request_complete( complete(tmf_complete); } - -/** - * isci_task_ssp_request_get_lun() - This function is called by the sci core to - * retrieve the lun for a given task request. - * @request: This parameter is the isci_request object. - * - * lun for specified task request. - */ - -/** - * isci_task_ssp_request_get_function() - This function is called by the sci - * core to retrieve the function for a given task request. - * @request: This parameter is the isci_request object. - * - * function code for specified task request. - */ -u8 isci_task_ssp_request_get_function(struct isci_request *request) -{ - struct isci_tmf *isci_tmf = isci_request_access_tmf(request); - - dev_dbg(&request->isci_host->pdev->dev, - "%s: func = %d\n", __func__, isci_tmf->tmf_code); - - return isci_tmf->tmf_code; -} - -/** - * isci_task_ssp_request_get_io_tag_to_manage() - This function is called by - * the sci core to retrieve the io tag for a given task request. - * @request: This parameter is the isci_request object. - * - * io tag for specified task request. - */ -u16 isci_task_ssp_request_get_io_tag_to_manage(struct isci_request *request) -{ - u16 io_tag = SCI_CONTROLLER_INVALID_IO_TAG; - - if (tmf_task == request->ttype) { - struct isci_tmf *tmf = isci_request_access_tmf(request); - io_tag = tmf->io_tag; - } - - dev_dbg(&request->isci_host->pdev->dev, - "%s: request = %p, io_tag = %d\n", - __func__, request, io_tag); - - return io_tag; -} - /** * isci_task_ssp_request_get_response_data_address() - This function is called * by the sci core to retrieve the response data address for a given task -- cgit v1.2.1 From af5ae89350840b9d724fc4fb81d928673bffdd4d Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Wed, 4 May 2011 17:53:24 -0700 Subject: isci: Convert of sci_ssp_response_iu to ssp_response_iu Converting to Linux native format. However the isci driver does a lot of the calculation based on the max size of this data structure and the Linux data structure only has a pointer to the response data. Thus the sizeof(struct ssp_response_iu) will be incorrect and we need to define the max size. Signed-off-by: Dave Jiang Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 100 ++++++++++++++++------------------------------- 1 file changed, 34 insertions(+), 66 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index c4db95933d41..8449d8abd66a 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -55,6 +55,7 @@ #include #include +#include "sas.h" #include "scic_task_request.h" #include "scic_io_request.h" #include "remote_device.h" @@ -63,7 +64,8 @@ #include "request.h" #include "sata.h" #include "task.h" -#include "core/scic_sds_request.h" +#include "scic_sds_stp_request.h" + /** * 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. @@ -1411,108 +1413,74 @@ int isci_task_query_task( return TMF_RESP_FUNC_SUCC; } -/** +/* * isci_task_request_complete() - This function is called by the sci core when * an task request completes. - * @isci_host: This parameter specifies the ISCI host object - * @request: This parameter is the completed isci_request object. + * @ihost: This parameter specifies the ISCI host object + * @ireq: This parameter is the completed isci_request object. * @completion_status: This parameter specifies the completion status from the * sci core. * * none. */ -void isci_task_request_complete( - struct isci_host *isci_host, - struct isci_request *request, - enum sci_task_status completion_status) +void +isci_task_request_complete(struct isci_host *ihost, + struct isci_request *ireq, + enum sci_task_status completion_status) { - struct isci_remote_device *isci_device = request->isci_device; + struct isci_remote_device *idev = ireq->isci_device; enum isci_request_status old_state; - struct isci_tmf *tmf = isci_request_access_tmf(request); + struct isci_tmf *tmf = isci_request_access_tmf(ireq); struct completion *tmf_complete; + struct scic_sds_request *sci_req = ireq->sci_request_handle; + struct scic_sds_stp_request *stp_req = + container_of(sci_req, typeof(*stp_req), parent); - dev_dbg(&isci_host->pdev->dev, + dev_dbg(&ihost->pdev->dev, "%s: request = %p, status=%d\n", - __func__, request, completion_status); + __func__, ireq, completion_status); - old_state = isci_request_change_state(request, completed); + old_state = isci_request_change_state(ireq, completed); tmf->status = completion_status; - request->complete_in_target = true; - - if (SAS_PROTOCOL_SSP == tmf->proto) { + ireq->complete_in_target = true; + if (tmf->proto == SAS_PROTOCOL_SSP) { memcpy(&tmf->resp.resp_iu, - scic_io_request_get_response_iu_address( - request->sci_request_handle - ), - sizeof(struct sci_ssp_response_iu)); - - } else if (SAS_PROTOCOL_SATA == tmf->proto) { - + sci_req->response_buffer, + SSP_RESP_IU_MAX_SIZE); + } else if (tmf->proto == SAS_PROTOCOL_SATA) { memcpy(&tmf->resp.d2h_fis, - scic_stp_io_request_get_d2h_reg_address( - request->sci_request_handle), + &stp_req->d2h_reg_fis, sizeof(struct dev_to_host_fis)); } /* Manage the timer if it is still running. */ if (tmf->timeout_timer) { - isci_del_timer(isci_host, tmf->timeout_timer); + isci_del_timer(ihost, tmf->timeout_timer); tmf->timeout_timer = NULL; } /* PRINT_TMF( ((struct isci_tmf *)request->task)); */ tmf_complete = tmf->complete; - scic_controller_complete_io( - isci_host->core_controller, - &isci_device->sci, - request->sci_request_handle); - /* NULL the request handle to make sure it cannot be terminated + scic_controller_complete_io(ihost->core_controller, + &idev->sci, + ireq->sci_request_handle); + + /* + * NULL the request handle to make sure it cannot be terminated * or completed again. */ - request->sci_request_handle = NULL; + ireq->sci_request_handle = NULL; - isci_request_change_state(request, unallocated); - list_del_init(&request->dev_node); + isci_request_change_state(ireq, unallocated); + list_del_init(&ireq->dev_node); /* The task management part completes last. */ complete(tmf_complete); } -/** - * isci_task_ssp_request_get_response_data_address() - This function is called - * by the sci core to retrieve the response data address for a given task - * request. - * @request: This parameter is the isci_request object. - * - * response data address for specified task request. - */ -void *isci_task_ssp_request_get_response_data_address( - struct isci_request *request) -{ - struct isci_tmf *isci_tmf = isci_request_access_tmf(request); - - return &isci_tmf->resp.resp_iu; -} - -/** - * isci_task_ssp_request_get_response_data_length() - This function is called - * by the sci core to retrieve the response data length for a given task - * request. - * @request: This parameter is the isci_request object. - * - * response data length for specified task request. - */ -u32 isci_task_ssp_request_get_response_data_length( - struct isci_request *request) -{ - struct isci_tmf *isci_tmf = isci_request_access_tmf(request); - - return sizeof(isci_tmf->resp.resp_iu); -} - /** * isci_bus_reset_handler() - This function performs a target reset of the * device referenced by "cmd'. This function is exported through the -- cgit v1.2.1 From d06b487b78f28a02efdcdcc9ec295bf230b9d0e8 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 2 May 2011 13:59:25 -0700 Subject: isci: implement I_T_nexus_reset This is a requirement for 2.6.39's new libata eh. Still some questions about lldd_dev_gone racing against dev->lldd_dev lookups, but we are at least no more broken than mvsas in this regard. We also short-circuit I_T_nexus_reset invocations from the device discovery path (IDEV_EH similar to MVS_DEV_EH) to filter out the resulting domain rediscoveries triggered by the reset. Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 138 +++++++++++++++++++++++++---------------------- 1 file changed, 74 insertions(+), 64 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 8449d8abd66a..3a3f54677e5b 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -1022,9 +1022,11 @@ int isci_task_lu_reset(struct domain_device *domain_device, u8 *lun) "%s: domain_device=%p, isci_host=%p; isci_device=%p\n", __func__, domain_device, isci_host, isci_device); - if (isci_device != NULL) + if (isci_device != NULL) { device_stopping = (isci_device->status == isci_stopping) || (isci_device->status == isci_stopped); + set_bit(IDEV_EH, &isci_device->flags); + } /* If there is a device reset pending on any request in the * device's list, fail this LUN reset request in order to @@ -1069,12 +1071,6 @@ int isci_task_clear_nexus_ha(struct sas_ha_struct *ha) return TMF_RESP_FUNC_FAILED; } -int isci_task_I_T_nexus_reset(struct domain_device *dev) -{ - return TMF_RESP_FUNC_FAILED; -} - - /* Task Management Functions. Must be called from process context. */ /** @@ -1171,6 +1167,12 @@ int isci_task_abort_task(struct sas_task *task) device_stopping = (isci_device->status == isci_stopping) || (isci_device->status == isci_stopped); + /* XXX need to fix device lookup lifetime (needs to be done + * under scic_lock, among other things...), but for now assume + * the device is available like the above code + */ + set_bit(IDEV_EH, &isci_device->flags); + /* This version of the driver will fail abort requests for * SATA/STP. Failing the abort request this way will cause the * SCSI error handler thread to escalate to LUN reset @@ -1481,86 +1483,94 @@ isci_task_request_complete(struct isci_host *ihost, complete(tmf_complete); } -/** - * isci_bus_reset_handler() - This function performs a target reset of the - * device referenced by "cmd'. This function is exported through the - * "struct scsi_host_template" structure such that it is called when an I/O - * recovery process has escalated to a target reset. Note that this function - * is called from the scsi error handler event thread, so may block on calls. - * @scsi_cmd: This parameter specifies the target to be reset. - * - * SUCCESS if the reset process was successful, else FAILED. - */ -int isci_bus_reset_handler(struct scsi_cmnd *cmd) +static int isci_reset_device(struct domain_device *dev, int hard_reset) { - struct domain_device *dev = cmd_to_domain_dev(cmd); - struct isci_host *isci_host = dev_to_ihost(dev); - unsigned long flags = 0; + struct isci_remote_device *idev = dev->lldd_dev; + struct sas_phy *phy = sas_find_local_phy(dev); + struct isci_host *ihost = dev_to_ihost(dev); enum sci_status status; - int base_status; - struct isci_remote_device *isci_dev = dev->lldd_dev; + unsigned long flags; + int rc; - dev_dbg(&isci_host->pdev->dev, - "%s: cmd %p, isci_dev %p\n", - __func__, cmd, isci_dev); + dev_dbg(&ihost->pdev->dev, "%s: idev %p\n", __func__, idev); - if (!isci_dev) { - dev_warn(&isci_host->pdev->dev, - "%s: isci_dev is GONE!\n", + if (!idev) { + dev_warn(&ihost->pdev->dev, + "%s: idev is GONE!\n", __func__); return TMF_RESP_FUNC_COMPLETE; /* Nothing to reset. */ } - spin_lock_irqsave(&isci_host->scic_lock, flags); - status = scic_remote_device_reset(&isci_dev->sci); + spin_lock_irqsave(&ihost->scic_lock, flags); + status = scic_remote_device_reset(&idev->sci); if (status != SCI_SUCCESS) { - spin_unlock_irqrestore(&isci_host->scic_lock, flags); + spin_unlock_irqrestore(&ihost->scic_lock, flags); - scmd_printk(KERN_WARNING, cmd, - "%s: scic_remote_device_reset(%p) returned %d!\n", - __func__, isci_dev, status); + dev_warn(&ihost->pdev->dev, + "%s: scic_remote_device_reset(%p) returned %d!\n", + __func__, idev, status); return TMF_RESP_FUNC_FAILED; } - spin_unlock_irqrestore(&isci_host->scic_lock, flags); + spin_unlock_irqrestore(&ihost->scic_lock, flags); /* Make sure all pending requests are able to be fully terminated. */ - isci_device_clear_reset_pending(isci_host, isci_dev); + isci_device_clear_reset_pending(ihost, idev); - /* Terminate in-progress I/O now. */ - isci_remote_device_nuke_requests(isci_host, isci_dev); + rc = sas_phy_reset(phy, hard_reset); + msleep(2000); /* just like mvsas */ - /* Call into the libsas default handler (which calls sas_phy_reset). */ - base_status = sas_eh_bus_reset_handler(cmd); + /* Terminate in-progress I/O now. */ + isci_remote_device_nuke_requests(ihost, idev); - if (base_status != SUCCESS) { + spin_lock_irqsave(&ihost->scic_lock, flags); + status = scic_remote_device_reset_complete(&idev->sci); + spin_unlock_irqrestore(&ihost->scic_lock, flags); - /* There can be cases where the resets to individual devices - * behind an expander will fail because of an unplug of the - * expander itself. - */ - scmd_printk(KERN_WARNING, cmd, - "%s: sas_eh_bus_reset_handler(%p) returned %d!\n", - __func__, cmd, base_status); + if (status != SCI_SUCCESS) { + dev_warn(&ihost->pdev->dev, + "%s: scic_remote_device_reset_complete(%p) " + "returned %d!\n", __func__, idev, status); } - /* WHAT TO DO HERE IF sas_phy_reset FAILS? */ - spin_lock_irqsave(&isci_host->scic_lock, flags); - status = scic_remote_device_reset_complete(&isci_dev->sci); - spin_unlock_irqrestore(&isci_host->scic_lock, flags); + dev_dbg(&ihost->pdev->dev, "%s: idev %p complete.\n", __func__, idev); - if (status != SCI_SUCCESS) { - scmd_printk(KERN_WARNING, cmd, - "%s: scic_remote_device_reset_complete(%p) " - "returned %d!\n", - __func__, isci_dev, status); - } - /* WHAT TO DO HERE IF scic_remote_device_reset_complete FAILS? */ + return rc; +} - dev_dbg(&isci_host->pdev->dev, - "%s: cmd %p, isci_dev %p complete.\n", - __func__, cmd, isci_dev); +int isci_task_I_T_nexus_reset(struct domain_device *dev) +{ + struct isci_host *ihost = dev_to_ihost(dev); + int ret = TMF_RESP_FUNC_FAILED, hard_reset = 1; + struct isci_remote_device *idev; + unsigned long flags; + + /* XXX mvsas is not protecting against ->lldd_dev_gone(), are we + * being too paranoid, or is mvsas busted?! + */ + spin_lock_irqsave(&ihost->scic_lock, flags); + idev = dev->lldd_dev; + if (!idev || !test_bit(IDEV_EH, &idev->flags)) + ret = TMF_RESP_FUNC_COMPLETE; + spin_unlock_irqrestore(&ihost->scic_lock, flags); + + if (ret == TMF_RESP_FUNC_COMPLETE) + return ret; + + if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) + hard_reset = 0; + + return isci_reset_device(dev, hard_reset); +} + +int isci_bus_reset_handler(struct scsi_cmnd *cmd) +{ + struct domain_device *dev = sdev_to_domain_dev(cmd->device); + int hard_reset = 1; + + if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) + hard_reset = 0; - return TMF_RESP_FUNC_COMPLETE; + return isci_reset_device(dev, hard_reset); } -- cgit v1.2.1 From cc3dbd0a9178865d4444f8e28b51715808e9ac85 Mon Sep 17 00:00:00 2001 From: Artur Wojcik Date: Wed, 4 May 2011 07:58:16 +0000 Subject: isci: unify isci_host data structures Make it explicit that isci_host and scic_sds_controller are one in the same object. Signed-off-by: Artur Wojcik [removed ->ihost back pointer] Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 3a3f54677e5b..cabad0b03ee5 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -299,7 +299,7 @@ static enum sci_status isci_task_request_build( /* let the core do it's construct. */ status = scic_task_request_construct( - isci_host->core_controller, + &isci_host->sci, sci_device, SCI_CONTROLLER_INVALID_IO_TAG, request, @@ -378,7 +378,7 @@ static void isci_tmf_timeout_cb(void *tmf_request_arg) /* Terminate the TMF transmit request. */ status = scic_controller_terminate_request( - request->isci_host->core_controller, + &request->isci_host->sci, &request->isci_device->sci, request->sci_request_handle ); @@ -469,7 +469,7 @@ int isci_task_execute_tmf( /* start the TMF io. */ status = scic_controller_start_task( - isci_host->core_controller, + &isci_host->sci, sci_device, request->sci_request_handle, SCI_CONTROLLER_INVALID_IO_TAG @@ -772,7 +772,7 @@ static void isci_terminate_request_core( was_terminated = true; needs_cleanup_handling = true; status = scic_controller_terminate_request( - isci_host->core_controller, + &isci_host->sci, &isci_device->sci, isci_request->sci_request_handle); } @@ -1466,12 +1466,9 @@ isci_task_request_complete(struct isci_host *ihost, /* PRINT_TMF( ((struct isci_tmf *)request->task)); */ tmf_complete = tmf->complete; - scic_controller_complete_io(ihost->core_controller, - &idev->sci, + scic_controller_complete_io(&ihost->sci, &idev->sci, ireq->sci_request_handle); - - /* - * NULL the request handle to make sure it cannot be terminated + /* NULL the request handle to make sure it cannot be terminated * or completed again. */ ireq->sci_request_handle = NULL; -- cgit v1.2.1 From 827a84d4e036b342b31abc2bcc3893505c2c7daa Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sat, 7 May 2011 15:59:09 -0700 Subject: isci: move stp request info to scic_sds_request In preparation for unifying allocation of all request information make stp data available in all requests. Incidentally collapse indentation. Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index cabad0b03ee5..12f2df947362 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -64,7 +64,7 @@ #include "request.h" #include "sata.h" #include "task.h" -#include "scic_sds_stp_request.h" +#include "scic_sds_request.h" /** * isci_task_refuse() - complete the request to the upper layer driver in @@ -1435,8 +1435,7 @@ isci_task_request_complete(struct isci_host *ihost, struct isci_tmf *tmf = isci_request_access_tmf(ireq); struct completion *tmf_complete; struct scic_sds_request *sci_req = ireq->sci_request_handle; - struct scic_sds_stp_request *stp_req = - container_of(sci_req, typeof(*stp_req), parent); + struct scic_sds_stp_request *stp_req = &sci_req->stp.req; dev_dbg(&ihost->pdev->dev, "%s: request = %p, status=%d\n", -- cgit v1.2.1 From 0d84366fbef557f92ef82ac9a224c57ffb3318bc Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sun, 8 May 2011 01:56:57 -0700 Subject: isci: make sgl explicit/aligned request object member Towards unifying request objects we need all members to be defined in the object and not carved out of anonymous buffer space. Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 12f2df947362..7d5f79378452 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -298,14 +298,10 @@ static enum sci_status isci_task_request_build( goto out; /* let the core do it's construct. */ - status = scic_task_request_construct( - &isci_host->sci, - sci_device, - SCI_CONTROLLER_INVALID_IO_TAG, - request, - request->sci_request_mem_ptr, - &request->sci_request_handle - ); + status = scic_task_request_construct(&isci_host->sci, sci_device, + SCI_CONTROLLER_INVALID_IO_TAG, + request, &request->sci_req, + &request->sci_request_handle); if (status != SCI_SUCCESS) { dev_warn(&isci_host->pdev->dev, -- cgit v1.2.1 From b7645818cff1536038c0b21407eefb6b9d5755e6 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sun, 8 May 2011 02:35:32 -0700 Subject: isci: make command/response iu explicit request object members Final elimination of the anonymous data at the end of the request structure. Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 7d5f79378452..492faeea8b3a 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -1431,7 +1431,6 @@ isci_task_request_complete(struct isci_host *ihost, struct isci_tmf *tmf = isci_request_access_tmf(ireq); struct completion *tmf_complete; struct scic_sds_request *sci_req = ireq->sci_request_handle; - struct scic_sds_stp_request *stp_req = &sci_req->stp.req; dev_dbg(&ihost->pdev->dev, "%s: request = %p, status=%d\n", @@ -1444,11 +1443,11 @@ isci_task_request_complete(struct isci_host *ihost, if (tmf->proto == SAS_PROTOCOL_SSP) { memcpy(&tmf->resp.resp_iu, - sci_req->response_buffer, + &sci_req->ssp.rsp, SSP_RESP_IU_MAX_SIZE); } else if (tmf->proto == SAS_PROTOCOL_SATA) { memcpy(&tmf->resp.d2h_fis, - &stp_req->d2h_reg_fis, + &sci_req->stp.rsp, sizeof(struct dev_to_host_fis)); } -- cgit v1.2.1 From 67ea838d17acdad3331aeae848683c768df96aaa Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sun, 8 May 2011 11:47:15 -0700 Subject: isci: unify request data structures Make scic_sds_request a proper member of isci_request. Also let's us get rid of the dma pool object size tracking since we now know that all requests are sizeof(isci_request). While cleaning up the construct routine incidentally replaced SCI_FIELD_OFFSET with offsetof. Reported-by: Christoph Hellwig Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 492faeea8b3a..7adaf71c19d1 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -300,8 +300,7 @@ static enum sci_status isci_task_request_build( /* let the core do it's construct. */ status = scic_task_request_construct(&isci_host->sci, sci_device, SCI_CONTROLLER_INVALID_IO_TAG, - request, &request->sci_req, - &request->sci_request_handle); + &request->sci); if (status != SCI_SUCCESS) { dev_warn(&isci_host->pdev->dev, @@ -312,14 +311,10 @@ static enum sci_status isci_task_request_build( goto errout; } - request->sci_request_handle->ireq = request; - /* XXX convert to get this from task->tproto like other drivers */ if (dev->dev_type == SAS_END_DEV) { isci_tmf->proto = SAS_PROTOCOL_SSP; - status = scic_task_request_construct_ssp( - request->sci_request_handle - ); + status = scic_task_request_construct_ssp(&request->sci); if (status != SCI_SUCCESS) goto errout; } @@ -376,8 +371,7 @@ static void isci_tmf_timeout_cb(void *tmf_request_arg) status = scic_controller_terminate_request( &request->isci_host->sci, &request->isci_device->sci, - request->sci_request_handle - ); + &request->sci); dev_dbg(&request->isci_host->pdev->dev, "%s: tmf_request = %p; tmf = %p; status = %d\n", @@ -467,9 +461,8 @@ int isci_task_execute_tmf( status = scic_controller_start_task( &isci_host->sci, sci_device, - request->sci_request_handle, - SCI_CONTROLLER_INVALID_IO_TAG - ); + &request->sci, + SCI_CONTROLLER_INVALID_IO_TAG); if (status != SCI_TASK_SUCCESS) { dev_warn(&isci_host->pdev->dev, @@ -764,13 +757,13 @@ static void isci_terminate_request_core( * device condition (if the request handle is NULL, then the * request completed but needed additional handling here). */ - if (isci_request->sci_request_handle != NULL) { + if (!isci_request->terminated) { was_terminated = true; needs_cleanup_handling = true; status = scic_controller_terminate_request( &isci_host->sci, &isci_device->sci, - isci_request->sci_request_handle); + &isci_request->sci); } spin_unlock_irqrestore(&isci_host->scic_lock, flags); @@ -1430,7 +1423,7 @@ isci_task_request_complete(struct isci_host *ihost, enum isci_request_status old_state; struct isci_tmf *tmf = isci_request_access_tmf(ireq); struct completion *tmf_complete; - struct scic_sds_request *sci_req = ireq->sci_request_handle; + struct scic_sds_request *sci_req = &ireq->sci; dev_dbg(&ihost->pdev->dev, "%s: request = %p, status=%d\n", @@ -1460,12 +1453,11 @@ isci_task_request_complete(struct isci_host *ihost, /* PRINT_TMF( ((struct isci_tmf *)request->task)); */ tmf_complete = tmf->complete; - scic_controller_complete_io(&ihost->sci, &idev->sci, - ireq->sci_request_handle); - /* NULL the request handle to make sure it cannot be terminated + scic_controller_complete_io(&ihost->sci, &idev->sci, &ireq->sci); + /* set the 'terminated' flag handle to make sure it cannot be terminated * or completed again. */ - ireq->sci_request_handle = NULL; + ireq->terminated = true;; isci_request_change_state(ireq, unallocated); list_del_init(&ireq->dev_node); -- cgit v1.2.1 From ce2b3261b6765c3b80fda95426c73e8d3bb1b035 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sun, 8 May 2011 15:49:15 -0700 Subject: isci: unify constants cross driver constants are spread out over multiple header files, consolidate them into isci.h, and push some includes out to the source files that need them. TODO: remove SCI_MODE_SIZE infrastructure. TODO: task.h is full of inlines that are too large Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 7adaf71c19d1..597c49020ac8 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -65,6 +65,8 @@ #include "sata.h" #include "task.h" #include "scic_sds_request.h" +#include "scic_controller.h" +#include "timers.h" /** * isci_task_refuse() - complete the request to the upper layer driver in -- cgit v1.2.1 From cc9203bf381a465cd115762b9cf7c9a313c874bc Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sun, 8 May 2011 17:34:44 -0700 Subject: isci: move core/controller to host Now that the data structures are unified unify the implementation in host.[ch] and cleanup namespace pollution. Reported-by: Christoph Hellwig Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 597c49020ac8..2a8603881929 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -65,7 +65,6 @@ #include "sata.h" #include "task.h" #include "scic_sds_request.h" -#include "scic_controller.h" #include "timers.h" /** -- cgit v1.2.1 From f1f52e75939b56c40b3d153ae99faf2720250242 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 10 May 2011 02:28:45 -0700 Subject: isci: uplevel request infrastructure * Consolidate tiny header files * Move files out of core/ (drop core/scic_sds_ prefix) * Merge core/scic_sds_request.[ch] into request.[ch] * Cleanup request.c namespace (clean forward declarations and global namespace pollution) Reported-by: Christoph Hellwig Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 2a8603881929..078e2ee4f4be 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -56,15 +56,12 @@ #include #include #include "sas.h" -#include "scic_task_request.h" -#include "scic_io_request.h" #include "remote_device.h" #include "remote_node_context.h" #include "isci.h" #include "request.h" #include "sata.h" #include "task.h" -#include "scic_sds_request.h" #include "timers.h" /** -- cgit v1.2.1 From fd18388bc5820b3e7807302ac18e8e7de83c9f4c Mon Sep 17 00:00:00 2001 From: Edmund Nadolski Date: Thu, 19 May 2011 12:00:15 +0000 Subject: isci: Remove tmf timeout_timer Replace the timeout_timer in the isci_tmf with a call to wait_for_completion_timeout Signed-off-by: Edmund Nadolski Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 105 +++++++++-------------------------------------- 1 file changed, 20 insertions(+), 85 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 078e2ee4f4be..60b687b77d56 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -338,54 +338,6 @@ static enum sci_status isci_task_request_build( return status; } -/** - * isci_tmf_timeout_cb() - This function is called as a kernel callback when - * the timeout period for the TMF has expired. - * - * - */ -static void isci_tmf_timeout_cb(void *tmf_request_arg) -{ - struct isci_request *request = (struct isci_request *)tmf_request_arg; - struct isci_tmf *tmf = isci_request_access_tmf(request); - enum sci_status status; - - /* This task management request has timed-out. Terminate the request - * so that the request eventually completes to the requestor in the - * request completion callback path. - */ - /* Note - the timer callback function itself has provided spinlock - * exclusion from the start and completion paths. No need to take - * the request->isci_host->scic_lock here. - */ - - if (tmf->timeout_timer != NULL) { - /* Call the users callback, if any. */ - if (tmf->cb_state_func != NULL) - tmf->cb_state_func(isci_tmf_timed_out, tmf, - tmf->cb_data); - - /* Terminate the TMF transmit request. */ - status = scic_controller_terminate_request( - &request->isci_host->sci, - &request->isci_device->sci, - &request->sci); - - dev_dbg(&request->isci_host->pdev->dev, - "%s: tmf_request = %p; tmf = %p; status = %d\n", - __func__, request, tmf, status); - } else - dev_dbg(&request->isci_host->pdev->dev, - "%s: timer already canceled! " - "tmf_request = %p; tmf = %p\n", - __func__, request, tmf); - - /* No need to unlock since the caller to this callback is doing it for - * us. - * request->isci_host->scic_lock - */ -} - /** * isci_task_execute_tmf() - This function builds and sends a task request, * then waits for the completion. @@ -410,6 +362,7 @@ int isci_task_execute_tmf( struct isci_request *request; int ret = TMF_RESP_FUNC_FAILED; unsigned long flags; + unsigned long timeleft; /* sanity check, return TMF_RESP_FUNC_FAILED * if the device is not there and ready. @@ -443,17 +396,7 @@ int isci_task_execute_tmf( return TMF_RESP_FUNC_FAILED; } - /* Allocate the TMF timeout timer. */ spin_lock_irqsave(&isci_host->scic_lock, flags); - tmf->timeout_timer = isci_timer_create(isci_host, request, isci_tmf_timeout_cb); - - /* Start the timer. */ - if (tmf->timeout_timer) - isci_timer_start(tmf->timeout_timer, timeout_ms); - else - dev_warn(&isci_host->pdev->dev, - "%s: isci_timer_create failed!!!!\n", - __func__); /* start the TMF io. */ status = scic_controller_start_task( @@ -468,14 +411,13 @@ int isci_task_execute_tmf( __func__, status, request); + spin_unlock_irqrestore(&isci_host->scic_lock, flags); goto cleanup_request; } - /* Call the users callback, if any. */ if (tmf->cb_state_func != NULL) tmf->cb_state_func(isci_tmf_started, tmf, tmf->cb_data); - /* Change the state of the TMF-bearing request to "started". */ isci_request_change_state(request, started); /* add the request to the remote device request list. */ @@ -484,7 +426,22 @@ int isci_task_execute_tmf( spin_unlock_irqrestore(&isci_host->scic_lock, flags); /* Wait for the TMF to complete, or a timeout. */ - wait_for_completion(&completion); + timeleft = wait_for_completion_timeout(&completion, + jiffies + msecs_to_jiffies(timeout_ms)); + + if (timeleft == 0) { + spin_lock_irqsave(&isci_host->scic_lock, flags); + + if (tmf->cb_state_func != NULL) + tmf->cb_state_func(isci_tmf_timed_out, tmf, tmf->cb_data); + + status = scic_controller_terminate_request( + &request->isci_host->sci, + &request->isci_device->sci, + &request->sci); + + spin_unlock_irqrestore(&isci_host->scic_lock, flags); + } isci_print_tmf(tmf); @@ -505,28 +462,12 @@ int isci_task_execute_tmf( request); if (request->io_request_completion != NULL) { - - /* The fact that this is non-NULL for a TMF request - * means there is a thread waiting for this TMF to - * finish. - */ + /* A thread is waiting for this TMF to finish. */ complete(request->io_request_completion); } - spin_lock_irqsave(&isci_host->scic_lock, flags); - cleanup_request: - - /* Clean up the timer if needed. */ - if (tmf->timeout_timer) { - isci_del_timer(isci_host, tmf->timeout_timer); - tmf->timeout_timer = NULL; - } - - spin_unlock_irqrestore(&isci_host->scic_lock, flags); - isci_request_free(isci_host, request); - return ret; } @@ -546,7 +487,7 @@ void isci_task_build_tmf( tmf->device = isci_device; tmf->tmf_code = code; - tmf->timeout_timer = NULL; + tmf->cb_state_func = tmf_sent_cb; tmf->cb_data = cb_data; } @@ -1442,12 +1383,6 @@ isci_task_request_complete(struct isci_host *ihost, sizeof(struct dev_to_host_fis)); } - /* Manage the timer if it is still running. */ - if (tmf->timeout_timer) { - isci_del_timer(ihost, tmf->timeout_timer); - tmf->timeout_timer = NULL; - } - /* PRINT_TMF( ((struct isci_tmf *)request->task)); */ tmf_complete = tmf->complete; -- cgit v1.2.1 From 8db02da52895285e99d7eb2fa825fd393e61d9c5 Mon Sep 17 00:00:00 2001 From: Edmund Nadolski Date: Thu, 19 May 2011 12:00:22 +0000 Subject: isci: remove isci_timer interface Delete code which is no longer used. Signed-off-by: Edmund Nadolski Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 60b687b77d56..93c75560a5c7 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -62,7 +62,6 @@ #include "request.h" #include "sata.h" #include "task.h" -#include "timers.h" /** * isci_task_refuse() - complete the request to the upper layer driver in -- cgit v1.2.1 From 8d2c65c09c9e0adc16070562e7944c1c3277f332 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Wed, 1 Jun 2011 09:03:08 +0000 Subject: isci: Removing unused variables compiler warnings Newer gcc's are better at identifying "set, but not used" variables. Signed-off-by: Dave Jiang Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 93c75560a5c7..b54ef2b0fca1 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -1358,7 +1358,6 @@ isci_task_request_complete(struct isci_host *ihost, enum sci_task_status completion_status) { struct isci_remote_device *idev = ireq->isci_device; - enum isci_request_status old_state; struct isci_tmf *tmf = isci_request_access_tmf(ireq); struct completion *tmf_complete; struct scic_sds_request *sci_req = &ireq->sci; @@ -1367,7 +1366,7 @@ isci_task_request_complete(struct isci_host *ihost, "%s: request = %p, status=%d\n", __func__, ireq, completion_status); - old_state = isci_request_change_state(ireq, completed); + isci_request_change_state(ireq, completed); tmf->status = completion_status; ireq->complete_in_target = true; -- cgit v1.2.1 From ff717ab05f0c33f93514eccea6dfe1a15983e1d1 Mon Sep 17 00:00:00 2001 From: Jeff Skirvin Date: Mon, 20 Jun 2011 14:08:51 -0700 Subject: isci: Move the reset delay after the remote node resumption. Delay after bringing up the RNC to allow for resumption latency. Signed-off-by: Jeff Skirvin Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index b54ef2b0fca1..69f17b98e4fa 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -1433,15 +1433,17 @@ static int isci_reset_device(struct domain_device *dev, int hard_reset) isci_device_clear_reset_pending(ihost, idev); rc = sas_phy_reset(phy, hard_reset); - msleep(2000); /* just like mvsas */ /* Terminate in-progress I/O now. */ isci_remote_device_nuke_requests(ihost, idev); + /* Since all pending TCs have been cleaned, resume the RNC. */ spin_lock_irqsave(&ihost->scic_lock, flags); status = scic_remote_device_reset_complete(&idev->sci); spin_unlock_irqrestore(&ihost->scic_lock, flags); + msleep(2000); /* just like mvsas */ + if (status != SCI_SUCCESS) { dev_warn(&ihost->pdev->dev, "%s: scic_remote_device_reset_complete(%p) " -- cgit v1.2.1 From 61aaff49e20fdb700f1300a49962bc76effc77fc Mon Sep 17 00:00:00 2001 From: Jeff Skirvin Date: Tue, 21 Jun 2011 12:16:33 -0700 Subject: isci: filter broadcast change notifications during SMP phy resets When resetting a sata device in the domain we have seen occasions where libsas prematurely marks a device gone in the time it takes for the device to re-establish the link. This plays badly with software raid arrays. Other libsas drivers have non-uniform delays in their reset handlers to try to cover this condition, but not sufficient to close the hole. Given that a sata device can take many seconds to recover we filter bcns and poll for the device reattach state before notifying libsas that the port needs the domain to be rediscovered. Once this has been proven out at the lldd level we can think about uplevelling this feature to a common implementation in libsas. Signed-off-by: Jeff Skirvin [ use kzalloc instead of kmem_cache ] Signed-off-by: Dave Jiang [ use eventq and time macros ] Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 259 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 258 insertions(+), 1 deletion(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 69f17b98e4fa..709c08171743 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -56,6 +56,7 @@ #include #include #include "sas.h" +#include #include "remote_device.h" #include "remote_node_context.h" #include "isci.h" @@ -1397,11 +1398,250 @@ isci_task_request_complete(struct isci_host *ihost, complete(tmf_complete); } +static void isci_smp_task_timedout(unsigned long _task) +{ + struct sas_task *task = (void *) _task; + unsigned long flags; + + spin_lock_irqsave(&task->task_state_lock, flags); + if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) + task->task_state_flags |= SAS_TASK_STATE_ABORTED; + spin_unlock_irqrestore(&task->task_state_lock, flags); + + complete(&task->completion); +} + +static void isci_smp_task_done(struct sas_task *task) +{ + if (!del_timer(&task->timer)) + return; + complete(&task->completion); +} + +static struct sas_task *isci_alloc_task(void) +{ + struct sas_task *task = kzalloc(sizeof(*task), GFP_KERNEL); + + if (task) { + INIT_LIST_HEAD(&task->list); + spin_lock_init(&task->task_state_lock); + task->task_state_flags = SAS_TASK_STATE_PENDING; + init_timer(&task->timer); + init_completion(&task->completion); + } + + return task; +} + +static void isci_free_task(struct isci_host *ihost, struct sas_task *task) +{ + if (task) { + BUG_ON(!list_empty(&task->list)); + kfree(task); + } +} + +static int isci_smp_execute_task(struct isci_host *ihost, + struct domain_device *dev, void *req, + int req_size, void *resp, int resp_size) +{ + int res, retry; + struct sas_task *task = NULL; + + for (retry = 0; retry < 3; retry++) { + task = isci_alloc_task(); + if (!task) + return -ENOMEM; + + task->dev = dev; + task->task_proto = dev->tproto; + sg_init_one(&task->smp_task.smp_req, req, req_size); + sg_init_one(&task->smp_task.smp_resp, resp, resp_size); + + task->task_done = isci_smp_task_done; + + task->timer.data = (unsigned long) task; + task->timer.function = isci_smp_task_timedout; + task->timer.expires = jiffies + 10*HZ; + add_timer(&task->timer); + + res = isci_task_execute_task(task, 1, GFP_KERNEL); + + if (res) { + del_timer(&task->timer); + dev_err(&ihost->pdev->dev, + "%s: executing SMP task failed:%d\n", + __func__, res); + goto ex_err; + } + + wait_for_completion(&task->completion); + res = -ECOMM; + if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) { + dev_err(&ihost->pdev->dev, + "%s: smp task timed out or aborted\n", + __func__); + isci_task_abort_task(task); + if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { + dev_err(&ihost->pdev->dev, + "%s: SMP task aborted and not done\n", + __func__); + goto ex_err; + } + } + if (task->task_status.resp == SAS_TASK_COMPLETE && + task->task_status.stat == SAM_STAT_GOOD) { + res = 0; + break; + } + if (task->task_status.resp == SAS_TASK_COMPLETE && + task->task_status.stat == SAS_DATA_UNDERRUN) { + /* no error, but return the number of bytes of + * underrun */ + res = task->task_status.residual; + break; + } + if (task->task_status.resp == SAS_TASK_COMPLETE && + task->task_status.stat == SAS_DATA_OVERRUN) { + res = -EMSGSIZE; + break; + } else { + dev_err(&ihost->pdev->dev, + "%s: task to dev %016llx response: 0x%x " + "status 0x%x\n", __func__, + SAS_ADDR(dev->sas_addr), + task->task_status.resp, + task->task_status.stat); + isci_free_task(ihost, task); + task = NULL; + } + } +ex_err: + BUG_ON(retry == 3 && task != NULL); + isci_free_task(ihost, task); + return res; +} + +#define DISCOVER_REQ_SIZE 16 +#define DISCOVER_RESP_SIZE 56 + +int isci_smp_get_phy_attached_dev_type(struct isci_host *ihost, + struct domain_device *dev, + int phy_id, int *adt) +{ + struct smp_resp *disc_resp; + u8 *disc_req; + int res; + + disc_resp = kzalloc(DISCOVER_RESP_SIZE, GFP_KERNEL); + if (!disc_resp) + return -ENOMEM; + + disc_req = kzalloc(DISCOVER_REQ_SIZE, GFP_KERNEL); + if (disc_req) { + disc_req[0] = SMP_REQUEST; + disc_req[1] = SMP_DISCOVER; + disc_req[9] = phy_id; + } else { + kfree(disc_resp); + return -ENOMEM; + } + res = isci_smp_execute_task(ihost, dev, disc_req, DISCOVER_REQ_SIZE, + disc_resp, DISCOVER_RESP_SIZE); + if (!res) { + if (disc_resp->result != SMP_RESP_FUNC_ACC) + res = disc_resp->result; + else + *adt = disc_resp->disc.attached_dev_type; + } + kfree(disc_req); + kfree(disc_resp); + + return res; +} + +static void isci_wait_for_smp_phy_reset(struct isci_remote_device *idev, int phy_num) +{ + struct domain_device *dev = idev->domain_dev; + struct isci_port *iport = idev->isci_port; + struct isci_host *ihost = iport->isci_host; + int res, iteration = 0, attached_device_type; + #define STP_WAIT_MSECS 25000 + unsigned long tmo = msecs_to_jiffies(STP_WAIT_MSECS); + unsigned long deadline = jiffies + tmo; + enum { + SMP_PHYWAIT_PHYDOWN, + SMP_PHYWAIT_PHYUP, + SMP_PHYWAIT_DONE + } phy_state = SMP_PHYWAIT_PHYDOWN; + + /* While there is time, wait for the phy to go away and come back */ + while (time_is_after_jiffies(deadline) && phy_state != SMP_PHYWAIT_DONE) { + int event = atomic_read(&iport->event); + + ++iteration; + + tmo = wait_event_timeout(ihost->eventq, + event != atomic_read(&iport->event) || + !test_bit(IPORT_BCN_BLOCKED, &iport->flags), + tmo); + /* link down, stop polling */ + if (!test_bit(IPORT_BCN_BLOCKED, &iport->flags)) + break; + + dev_dbg(&ihost->pdev->dev, + "%s: iport %p, iteration %d," + " phase %d: time_remaining %lu, bcns = %d\n", + __func__, iport, iteration, phy_state, + tmo, test_bit(IPORT_BCN_PENDING, &iport->flags)); + + res = isci_smp_get_phy_attached_dev_type(ihost, dev, phy_num, + &attached_device_type); + tmo = deadline - jiffies; + + if (res) { + dev_warn(&ihost->pdev->dev, + "%s: iteration %d, phase %d:" + " SMP error=%d, time_remaining=%lu\n", + __func__, iteration, phy_state, res, tmo); + break; + } + dev_dbg(&ihost->pdev->dev, + "%s: iport %p, iteration %d," + " phase %d: time_remaining %lu, bcns = %d, " + "attdevtype = %x\n", + __func__, iport, iteration, phy_state, + tmo, test_bit(IPORT_BCN_PENDING, &iport->flags), + attached_device_type); + + switch (phy_state) { + case SMP_PHYWAIT_PHYDOWN: + /* Has the device gone away? */ + if (!attached_device_type) + phy_state = SMP_PHYWAIT_PHYUP; + + break; + + case SMP_PHYWAIT_PHYUP: + /* Has the device come back? */ + if (attached_device_type) + phy_state = SMP_PHYWAIT_DONE; + break; + + case SMP_PHYWAIT_DONE: + break; + } + + } + dev_dbg(&ihost->pdev->dev, "%s: done\n", __func__); +} + static int isci_reset_device(struct domain_device *dev, int hard_reset) { struct isci_remote_device *idev = dev->lldd_dev; struct sas_phy *phy = sas_find_local_phy(dev); struct isci_host *ihost = dev_to_ihost(dev); + struct isci_port *iport = idev->isci_port; enum sci_status status; unsigned long flags; int rc; @@ -1432,6 +1672,10 @@ static int isci_reset_device(struct domain_device *dev, int hard_reset) /* Make sure all pending requests are able to be fully terminated. */ isci_device_clear_reset_pending(ihost, idev); + /* If this is a device on an expander, disable BCN processing. */ + if (!scsi_is_sas_phy_local(phy)) + set_bit(IPORT_BCN_BLOCKED, &iport->flags); + rc = sas_phy_reset(phy, hard_reset); /* Terminate in-progress I/O now. */ @@ -1442,7 +1686,20 @@ static int isci_reset_device(struct domain_device *dev, int hard_reset) status = scic_remote_device_reset_complete(&idev->sci); spin_unlock_irqrestore(&ihost->scic_lock, flags); - msleep(2000); /* just like mvsas */ + /* If this is a device on an expander, bring the phy back up. */ + if (!scsi_is_sas_phy_local(phy)) { + /* A phy reset will cause the device to go away then reappear. + * Since libsas will take action on incoming BCNs (eg. remove + * a device going through an SMP phy-control driven reset), + * we need to wait until the phy comes back up before letting + * discovery proceed in libsas. + */ + isci_wait_for_smp_phy_reset(idev, phy->number); + + spin_lock_irqsave(&ihost->scic_lock, flags); + isci_port_bcn_enable(ihost, idev->isci_port); + spin_unlock_irqrestore(&ihost->scic_lock, flags); + } if (status != SCI_SUCCESS) { dev_warn(&ihost->pdev->dev, -- cgit v1.2.1 From 77c852f312243192b1f2ce7fc56d678784786692 Mon Sep 17 00:00:00 2001 From: Jeff Skirvin Date: Mon, 20 Jun 2011 14:09:16 -0700 Subject: isci: Handle timed-out request terminations correctly In the situation where a termination of an I/O times-out, make sure that the linkage from the request to the task is severed completely. Also make sure that the selection of tasks to terminate occurs under scic_lock. Signed-off-by: Jeff Skirvin Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 358 +++++++++++++++++++++++------------------------ 1 file changed, 172 insertions(+), 186 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 709c08171743..573cf1c9e81d 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -567,31 +567,33 @@ static enum isci_request_status isci_task_validate_request_to_abort( return old_state; } +/** +* isci_request_cleanup_completed_loiterer() - This function will take care of +* the final cleanup on any request which has been explicitly terminated. +* @isci_host: This parameter specifies the ISCI host object +* @isci_device: This is the device to which the request is pending. +* @isci_request: This parameter specifies the terminated request object. +* @task: This parameter is the libsas I/O request. +*/ static void isci_request_cleanup_completed_loiterer( - struct isci_host *isci_host, + struct isci_host *isci_host, struct isci_remote_device *isci_device, - struct isci_request *isci_request) + struct isci_request *isci_request, + struct sas_task *task) { - struct sas_task *task; - unsigned long flags; - - task = (isci_request->ttype == io_task) - ? isci_request_access_task(isci_request) - : NULL; + unsigned long flags; dev_dbg(&isci_host->pdev->dev, "%s: isci_device=%p, request=%p, task=%p\n", __func__, isci_device, isci_request, task); - spin_lock_irqsave(&isci_host->scic_lock, flags); - list_del_init(&isci_request->dev_node); - spin_unlock_irqrestore(&isci_host->scic_lock, flags); - if (task != NULL) { spin_lock_irqsave(&task->task_state_lock, flags); task->lldd_task = NULL; + task->task_state_flags &= ~SAS_TASK_NEED_DEV_RESET; + isci_set_task_doneflags(task); /* If this task is not in the abort path, call task_done. */ @@ -602,61 +604,16 @@ static void isci_request_cleanup_completed_loiterer( } else spin_unlock_irqrestore(&task->task_state_lock, flags); } - 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) { + if (isci_request != NULL) { + spin_lock_irqsave(&isci_host->scic_lock, flags); + list_del_init(&isci_request->dev_node); + spin_unlock_irqrestore(&isci_host->scic_lock, flags); - request->ttype_ptr.io_task_ptr->lldd_task = NULL; - request->ttype_ptr.io_task_ptr = NULL; - } - } + isci_request_free(isci_host, isci_request); } - 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 @@ -666,7 +623,6 @@ isci_termination_timed_out( * @isci_device: The target. * @isci_request: The I/O request to be terminated. * - * */ static void isci_terminate_request_core( struct isci_host *isci_host, @@ -677,9 +633,10 @@ static void isci_terminate_request_core( bool was_terminated = false; bool needs_cleanup_handling = false; enum isci_request_status request_status; - unsigned long flags; - unsigned long timeout_remaining; - + unsigned long flags; + unsigned long termination_completed = 1; + struct completion *io_request_completion; + struct sas_task *task; dev_dbg(&isci_host->pdev->dev, "%s: device = %p; request = %p\n", @@ -687,6 +644,12 @@ static void isci_terminate_request_core( spin_lock_irqsave(&isci_host->scic_lock, flags); + io_request_completion = isci_request->io_request_completion; + + task = (isci_request->ttype == io_task) + ? isci_request_access_task(isci_request) + : NULL; + /* Note that we are not going to control * the target to abort the request. */ @@ -715,119 +678,112 @@ static void isci_terminate_request_core( dev_err(&isci_host->pdev->dev, "%s: scic_controller_terminate_request" " returned = 0x%x\n", - __func__, - status); - /* Clear the completion pointer from the request. */ + __func__, status); + 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); + "%s: before completion wait (%p/%p)\n", + __func__, isci_request, io_request_completion); /* Wait here for the request to complete. */ - #define TERMINATION_TIMEOUT_MSEC 50 - timeout_remaining + #define TERMINATION_TIMEOUT_MSEC 500 + termination_completed = wait_for_completion_timeout( - isci_request->io_request_completion, + io_request_completion, msecs_to_jiffies(TERMINATION_TIMEOUT_MSEC)); - if (!timeout_remaining) { + if (!termination_completed) { + + /* The request to terminate has timed out. */ + spin_lock_irqsave(&isci_host->scic_lock, + flags); + + /* Check for state changes. */ + if (!isci_request->terminated) { + + /* The best we can do is to have the + * request die a silent death if it + * ever really completes. + * + * Set the request state to "dead", + * and clear the task pointer so that + * an actual completion event callback + * doesn't do anything. + */ + isci_request->status = dead; + isci_request->io_request_completion + = NULL; + + if (isci_request->ttype == io_task) { + + /* Break links with the + * sas_task. + */ + isci_request->ttype_ptr.io_task_ptr + = NULL; + } + } else + termination_completed = 1; + + spin_unlock_irqrestore(&isci_host->scic_lock, + flags); - isci_termination_timed_out(isci_host, - isci_request); + if (!termination_completed) { - dev_err(&isci_host->pdev->dev, - "%s: *** Timeout waiting for " - "termination(%p/%p)\n", - __func__, - isci_request->io_request_completion, - isci_request); + dev_err(&isci_host->pdev->dev, + "%s: *** Timeout waiting for " + "termination(%p/%p)\n", + __func__, io_request_completion, + isci_request); - } else + /* The request can no longer be referenced + * safely since it may go away if the + * termination every really does complete. + */ + isci_request = NULL; + } + } + if (termination_completed) dev_dbg(&isci_host->pdev->dev, - "%s: after completion wait (%p)\n", - __func__, - isci_request->io_request_completion); + "%s: after completion wait (%p/%p)\n", + __func__, isci_request, io_request_completion); } - /* Clear the completion pointer from the request. */ - isci_request->io_request_completion = NULL; - /* 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 - ); - } -} + if (termination_completed) { -static void isci_terminate_request( - struct isci_host *isci_host, - struct isci_remote_device *isci_device, - struct isci_request *isci_request, - enum isci_request_status new_request_state) -{ - enum isci_request_status old_state; - DECLARE_COMPLETION_ONSTACK(request_completion); + isci_request->io_request_completion = NULL; - /* Change state to "new_request_state" if it is currently "started" */ - old_state = isci_request_change_started_to_newstate( - isci_request, - &request_completion, - new_request_state - ); + /* 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 ((old_state == started) || - (old_state == completed) || - (old_state == aborting)) { - - /* If the old_state is started: - * This request was not already being aborted. If it had been, - * then the aborting I/O (ie. the TMF request) would not be in - * the aborting state, and thus would be terminated here. Note - * that since the TMF completion's call to the kernel function - * "complete()" does not happen until the pending I/O request - * terminate fully completes, we do not have to implement a - * special wait here for already aborting requests - the - * termination of the TMF request will force the request - * to finish it's already started terminate. - * - * If old_state == completed: - * This request completed from the SCU hardware perspective - * and now just needs cleaning up in terms of freeing the - * request and potentially calling up to libsas. - * - * If old_state == aborting: - * This request has already gone through a TMF timeout, but may - * not have been terminated; needs cleaning up at least. - */ - isci_terminate_request_core(isci_host, isci_device, - isci_request); + } + if (needs_cleanup_handling) + isci_request_cleanup_completed_loiterer( + isci_host, isci_device, isci_request, task); } } @@ -850,9 +806,8 @@ void isci_terminate_pending_requests( struct isci_request *request; struct isci_request *next_request; unsigned long flags; - struct list_head aborted_request_list; - - INIT_LIST_HEAD(&aborted_request_list); + enum isci_request_status old_state; + DECLARE_COMPLETION_ONSTACK(request_completion); dev_dbg(&isci_host->pdev->dev, "%s: isci_device = %p (new request state = %d)\n", @@ -860,31 +815,62 @@ void isci_terminate_pending_requests( spin_lock_irqsave(&isci_host->scic_lock, flags); - /* 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); - - /* Iterate through the now-local list. */ + /* Iterate through the list. */ list_for_each_entry_safe(request, next_request, - &aborted_request_list, dev_node) { + &isci_device->reqs_in_process, dev_node) { - 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)); + init_completion(&request_completion); - /* Mark all still pending I/O with the selected next - * state, terminate and free it. + /* Change state to "new_request_state" if it is currently + * "started". */ - isci_terminate_request(isci_host, isci_device, - request, new_request_state - ); + old_state = isci_request_change_started_to_newstate( + request, + &request_completion, + new_request_state); + + spin_unlock_irqrestore(&isci_host->scic_lock, flags); + + if ((old_state == started) || + (old_state == completed) || + (old_state == aborting)) { + + dev_warn(&isci_host->pdev->dev, + "%s: isci_device=%p request=%p; task=%p " + "old_state=%d\n", + __func__, + isci_device, request, + ((request->ttype == io_task) + ? isci_request_access_task(request) + : NULL), + old_state); + + /* If the old_state is started: + * This request was not already being aborted. If it had been, + * then the aborting I/O (ie. the TMF request) would not be in + * the aborting state, and thus would be terminated here. Note + * that since the TMF completion's call to the kernel function + * "complete()" does not happen until the pending I/O request + * terminate fully completes, we do not have to implement a + * special wait here for already aborting requests - the + * termination of the TMF request will force the request + * to finish it's already started terminate. + * + * If old_state == completed: + * This request completed from the SCU hardware perspective + * and now just needs cleaning up in terms of freeing the + * request and potentially calling up to libsas. + * + * If old_state == aborting: + * This request has already gone through a TMF timeout, but may + * not have been terminated; needs cleaning up at least. + */ + isci_terminate_request_core(isci_host, isci_device, + request); + } + spin_lock_irqsave(&isci_host->scic_lock, flags); } + spin_unlock_irqrestore(&isci_host->scic_lock, flags); } /** @@ -1257,9 +1243,9 @@ int isci_task_abort_task(struct sas_task *task) if (ret == TMF_RESP_FUNC_COMPLETE) { old_request->complete_in_target = true; - /* Clean up the request on our side, and wait for the aborted I/O to - * complete. - */ + /* Clean up the request on our side, and wait for the aborted + * I/O to complete. + */ isci_terminate_request_core(isci_host, isci_device, old_request); } -- cgit v1.2.1 From 980d3aeb3828b0fdf2a0b2e893d238130b014575 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 20 Jun 2011 15:11:22 -0700 Subject: isci: fix isci_terminate_pending() list management Walk through the list of pending requests being careful to consider that multiple requests can be terminated when the lock is dropped (i.e. invalidating the 'next' reference established by list_for_each_entry_safe). Also noticed that all callers to isci_terminate_pending_requests() specifying terminating, so just drop the parameter. Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 131 +++++++++++++++++++++++------------------------ 1 file changed, 64 insertions(+), 67 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 573cf1c9e81d..01032dc2c116 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -796,81 +796,79 @@ static void isci_terminate_request_core( * @isci_host: This parameter specifies SCU. * @isci_device: This parameter specifies the target. * - * */ -void isci_terminate_pending_requests( - struct isci_host *isci_host, - struct isci_remote_device *isci_device, - enum isci_request_status new_request_state) +void isci_terminate_pending_requests(struct isci_host *ihost, + struct isci_remote_device *idev) { - struct isci_request *request; - struct isci_request *next_request; - unsigned long flags; + struct completion request_completion; enum isci_request_status old_state; - DECLARE_COMPLETION_ONSTACK(request_completion); - - dev_dbg(&isci_host->pdev->dev, - "%s: isci_device = %p (new request state = %d)\n", - __func__, isci_device, new_request_state); + unsigned long flags; + LIST_HEAD(list); - spin_lock_irqsave(&isci_host->scic_lock, flags); + spin_lock_irqsave(&ihost->scic_lock, flags); + list_splice_init(&idev->reqs_in_process, &list); - /* Iterate through the list. */ - list_for_each_entry_safe(request, next_request, - &isci_device->reqs_in_process, dev_node) { + /* assumes that isci_terminate_request_core deletes from the list */ + while (!list_empty(&list)) { + struct isci_request *ireq = list_entry(list.next, typeof(*ireq), dev_node); - init_completion(&request_completion); + /* Change state to "terminating" if it is currently + * "started". + */ + old_state = isci_request_change_started_to_newstate(ireq, + &request_completion, + terminating); + switch (old_state) { + case started: + case completed: + case aborting: + break; + default: + /* termination in progress, or otherwise dispositioned. + * We know the request was on 'list' so should be safe + * to move it back to reqs_in_process + */ + list_move(&ireq->dev_node, &idev->reqs_in_process); + ireq = NULL; + break; + } - /* Change state to "new_request_state" if it is currently - * "started". - */ - old_state = isci_request_change_started_to_newstate( - request, - &request_completion, - new_request_state); + if (!ireq) + continue; + spin_unlock_irqrestore(&ihost->scic_lock, flags); - spin_unlock_irqrestore(&isci_host->scic_lock, flags); + init_completion(&request_completion); - if ((old_state == started) || - (old_state == completed) || - (old_state == aborting)) { - - dev_warn(&isci_host->pdev->dev, - "%s: isci_device=%p request=%p; task=%p " - "old_state=%d\n", - __func__, - isci_device, request, - ((request->ttype == io_task) - ? isci_request_access_task(request) - : NULL), - old_state); - - /* If the old_state is started: - * This request was not already being aborted. If it had been, - * then the aborting I/O (ie. the TMF request) would not be in - * the aborting state, and thus would be terminated here. Note - * that since the TMF completion's call to the kernel function - * "complete()" does not happen until the pending I/O request - * terminate fully completes, we do not have to implement a - * special wait here for already aborting requests - the - * termination of the TMF request will force the request - * to finish it's already started terminate. - * - * If old_state == completed: - * This request completed from the SCU hardware perspective - * and now just needs cleaning up in terms of freeing the - * request and potentially calling up to libsas. - * - * If old_state == aborting: - * This request has already gone through a TMF timeout, but may - * not have been terminated; needs cleaning up at least. - */ - isci_terminate_request_core(isci_host, isci_device, - request); - } - spin_lock_irqsave(&isci_host->scic_lock, flags); + dev_dbg(&ihost->pdev->dev, + "%s: idev=%p request=%p; task=%p old_state=%d\n", + __func__, idev, ireq, + ireq->ttype == io_task ? isci_request_access_task(ireq) : NULL, + old_state); + + /* If the old_state is started: + * This request was not already being aborted. If it had been, + * then the aborting I/O (ie. the TMF request) would not be in + * the aborting state, and thus would be terminated here. Note + * that since the TMF completion's call to the kernel function + * "complete()" does not happen until the pending I/O request + * terminate fully completes, we do not have to implement a + * special wait here for already aborting requests - the + * termination of the TMF request will force the request + * to finish it's already started terminate. + * + * If old_state == completed: + * This request completed from the SCU hardware perspective + * and now just needs cleaning up in terms of freeing the + * request and potentially calling up to libsas. + * + * If old_state == aborting: + * This request has already gone through a TMF timeout, but may + * not have been terminated; needs cleaning up at least. + */ + isci_terminate_request_core(ihost, idev, ireq); + spin_lock_irqsave(&ihost->scic_lock, flags); } - spin_unlock_irqrestore(&isci_host->scic_lock, flags); + spin_unlock_irqrestore(&ihost->scic_lock, flags); } /** @@ -965,8 +963,7 @@ int isci_task_lu_reset(struct domain_device *domain_device, u8 *lun) if (ret == TMF_RESP_FUNC_COMPLETE) /* Terminate all I/O now. */ isci_terminate_pending_requests(isci_host, - isci_device, - terminating); + isci_device); return ret; } -- cgit v1.2.1 From 0d0cf14c9bd2943ed5afd15df459f564d85eacde Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 13 Jun 2011 00:51:30 -0700 Subject: isci: cleanup request allocation Rather than return an error code and update a pointer that was passed by reference just return the request object directly (or null if allocation failed). Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 136 +++++++++++++++++------------------------------ 1 file changed, 50 insertions(+), 86 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 01032dc2c116..ded81cd1a781 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -146,7 +146,6 @@ static void isci_task_refuse(struct isci_host *ihost, struct sas_task *task, int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags) { struct isci_host *ihost = dev_to_ihost(task->dev); - struct isci_request *request = NULL; struct isci_remote_device *device; unsigned long flags; int ret; @@ -226,8 +225,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(ihost, task, &request, - gfp_flags); + status = isci_request_execute(ihost, task, gfp_flags); if (status != SCI_SUCCESS) { @@ -254,54 +252,34 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags) return 0; } - - -/** - * isci_task_request_build() - This function builds the task request object. - * @isci_host: This parameter specifies the ISCI host object - * @request: This parameter points to the isci_request object allocated in the - * request construct function. - * @tmf: This parameter is the task management struct to be built - * - * SCI_SUCCESS on successfull completion, or specific failure code. - */ -static enum sci_status isci_task_request_build( - struct isci_host *isci_host, - struct isci_request **isci_request, - struct isci_tmf *isci_tmf) +static struct isci_request *isci_task_request_build(struct isci_host *ihost, + struct isci_tmf *isci_tmf) { - struct scic_sds_remote_device *sci_device; + struct scic_sds_remote_device *sci_dev; enum sci_status status = SCI_FAILURE; - struct isci_request *request = NULL; - struct isci_remote_device *isci_device; + struct isci_request *ireq = NULL; + struct isci_remote_device *idev; struct domain_device *dev; - dev_dbg(&isci_host->pdev->dev, + dev_dbg(&ihost->pdev->dev, "%s: isci_tmf = %p\n", __func__, isci_tmf); - isci_device = isci_tmf->device; - sci_device = &isci_device->sci; - dev = isci_device->domain_dev; + idev = isci_tmf->device; + sci_dev = &idev->sci; + dev = idev->domain_dev; /* do common allocation and init of request object. */ - status = isci_request_alloc_tmf( - isci_host, - isci_tmf, - &request, - isci_device, - GFP_ATOMIC - ); - - if (status != SCI_SUCCESS) - goto out; + ireq = isci_request_alloc_tmf(ihost, isci_tmf, idev, GFP_ATOMIC); + if (!ireq) + return NULL; /* let the core do it's construct. */ - status = scic_task_request_construct(&isci_host->sci, sci_device, + status = scic_task_request_construct(&ihost->sci, sci_dev, SCI_CONTROLLER_INVALID_IO_TAG, - &request->sci); + &ireq->sci); if (status != SCI_SUCCESS) { - dev_warn(&isci_host->pdev->dev, + dev_warn(&ihost->pdev->dev, "%s: scic_task_request_construct failed - " "status = 0x%x\n", __func__, @@ -312,30 +290,23 @@ static enum sci_status isci_task_request_build( /* XXX convert to get this from task->tproto like other drivers */ if (dev->dev_type == SAS_END_DEV) { isci_tmf->proto = SAS_PROTOCOL_SSP; - status = scic_task_request_construct_ssp(&request->sci); + status = scic_task_request_construct_ssp(&ireq->sci); if (status != SCI_SUCCESS) goto errout; } if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) { isci_tmf->proto = SAS_PROTOCOL_SATA; - status = isci_sata_management_task_request_build(request); + status = isci_sata_management_task_request_build(ireq); if (status != SCI_SUCCESS) goto errout; } - - goto out; - + return ireq; errout: - - /* release the dma memory if we fail. */ - isci_request_free(isci_host, request); - request = NULL; - - out: - *isci_request = request; - return status; + isci_request_free(ihost, ireq); + ireq = NULL; + return ireq; } /** @@ -350,16 +321,14 @@ static enum sci_status isci_task_request_build( * TMF_RESP_FUNC_COMPLETE on successful completion of the TMF (this includes * error conditions reported in the IU status), or TMF_RESP_FUNC_FAILED. */ -int isci_task_execute_tmf( - struct isci_host *isci_host, - struct isci_tmf *tmf, - unsigned long timeout_ms) +int isci_task_execute_tmf(struct isci_host *ihost, struct isci_tmf *tmf, + unsigned long timeout_ms) { DECLARE_COMPLETION_ONSTACK(completion); enum sci_task_status status = SCI_TASK_FAILURE; struct scic_sds_remote_device *sci_device; struct isci_remote_device *isci_device = tmf->device; - struct isci_request *request; + struct isci_request *ireq; int ret = TMF_RESP_FUNC_FAILED; unsigned long flags; unsigned long timeleft; @@ -368,13 +337,13 @@ int isci_task_execute_tmf( * if the device is not there and ready. */ if (!isci_device || isci_device->status != isci_ready_for_io) { - dev_dbg(&isci_host->pdev->dev, + dev_dbg(&ihost->pdev->dev, "%s: isci_device = %p not ready (%d)\n", __func__, isci_device, isci_device->status); return TMF_RESP_FUNC_FAILED; } else - dev_dbg(&isci_host->pdev->dev, + dev_dbg(&ihost->pdev->dev, "%s: isci_device = %p\n", __func__, isci_device); @@ -383,64 +352,59 @@ int isci_task_execute_tmf( /* Assign the pointer to the TMF's completion kernel wait structure. */ tmf->complete = &completion; - isci_task_request_build( - isci_host, - &request, - tmf - ); - - if (!request) { - dev_warn(&isci_host->pdev->dev, + ireq = isci_task_request_build(ihost, tmf); + if (!ireq) { + dev_warn(&ihost->pdev->dev, "%s: isci_task_request_build failed\n", __func__); return TMF_RESP_FUNC_FAILED; } - spin_lock_irqsave(&isci_host->scic_lock, flags); + spin_lock_irqsave(&ihost->scic_lock, flags); /* start the TMF io. */ status = scic_controller_start_task( - &isci_host->sci, + &ihost->sci, sci_device, - &request->sci, + &ireq->sci, SCI_CONTROLLER_INVALID_IO_TAG); if (status != SCI_TASK_SUCCESS) { - dev_warn(&isci_host->pdev->dev, + dev_warn(&ihost->pdev->dev, "%s: start_io failed - status = 0x%x, request = %p\n", __func__, status, - request); - spin_unlock_irqrestore(&isci_host->scic_lock, flags); + ireq); + spin_unlock_irqrestore(&ihost->scic_lock, flags); goto cleanup_request; } if (tmf->cb_state_func != NULL) tmf->cb_state_func(isci_tmf_started, tmf, tmf->cb_data); - isci_request_change_state(request, started); + isci_request_change_state(ireq, started); /* add the request to the remote device request list. */ - list_add(&request->dev_node, &isci_device->reqs_in_process); + list_add(&ireq->dev_node, &isci_device->reqs_in_process); - spin_unlock_irqrestore(&isci_host->scic_lock, flags); + spin_unlock_irqrestore(&ihost->scic_lock, flags); /* Wait for the TMF to complete, or a timeout. */ timeleft = wait_for_completion_timeout(&completion, jiffies + msecs_to_jiffies(timeout_ms)); if (timeleft == 0) { - spin_lock_irqsave(&isci_host->scic_lock, flags); + spin_lock_irqsave(&ihost->scic_lock, flags); if (tmf->cb_state_func != NULL) tmf->cb_state_func(isci_tmf_timed_out, tmf, tmf->cb_data); status = scic_controller_terminate_request( - &request->isci_host->sci, - &request->isci_device->sci, - &request->sci); + &ireq->isci_host->sci, + &ireq->isci_device->sci, + &ireq->sci); - spin_unlock_irqrestore(&isci_host->scic_lock, flags); + spin_unlock_irqrestore(&ihost->scic_lock, flags); } isci_print_tmf(tmf); @@ -448,7 +412,7 @@ int isci_task_execute_tmf( if (tmf->status == SCI_SUCCESS) ret = TMF_RESP_FUNC_COMPLETE; else if (tmf->status == SCI_FAILURE_IO_RESPONSE_VALID) { - dev_dbg(&isci_host->pdev->dev, + dev_dbg(&ihost->pdev->dev, "%s: tmf.status == " "SCI_FAILURE_IO_RESPONSE_VALID\n", __func__); @@ -456,18 +420,18 @@ int isci_task_execute_tmf( } /* Else - leave the default "failed" status alone. */ - dev_dbg(&isci_host->pdev->dev, + dev_dbg(&ihost->pdev->dev, "%s: completed request = %p\n", __func__, - request); + ireq); - if (request->io_request_completion != NULL) { + if (ireq->io_request_completion != NULL) { /* A thread is waiting for this TMF to finish. */ - complete(request->io_request_completion); + complete(ireq->io_request_completion); } cleanup_request: - isci_request_free(isci_host, request); + isci_request_free(ihost, ireq); return ret; } -- cgit v1.2.1 From 209fae14fabfd48525e5630bebbbd4ca15090c60 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 13 Jun 2011 17:39:44 -0700 Subject: isci: atomic device lookup and reference counting We have unsafe references to remote devices that are notified to disappear at lldd_dev_gone. In order to clean this up we need a single canonical source for device lookups and stable references once a lookup succeeds. Towards that end guarantee that domain_device.lldd_dev is NULL as soon as we start the process of stopping a device. Any code path that wants to safely lookup a remote device must do so through task->dev->lldd_dev (isci_lookup_device()). For in-flight references outside of scic_lock we need reference counting to ensure that the device is not recycled before we are done with it. Simplify device back references to just scic_sds_request.target_device which is now the only permissible internal reference that is maintained relative to the reference count. There were two occasions where we wanted new i/o's to be treated as SAS_TASK_UNDELIVERED but where the domain_dev->lldd_dev link is still intact. Introduce a 'gone' flag to prevent i/o while waiting for libsas to take action on the port down event. One 'core' leftover is that we currently call scic_remote_device_destruct() from isci_remote_device_deconstruct() which is called when the 'core' says the device is stopped. It would be more natural for the final put to trigger isci_remote_device_deconstruct() but this implementation is deferred as it requires other changes. Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 231 +++++++++++++++++++---------------------------- 1 file changed, 91 insertions(+), 140 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index ded81cd1a781..dd5e9de1ffb5 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -146,7 +146,7 @@ static void isci_task_refuse(struct isci_host *ihost, struct sas_task *task, int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags) { struct isci_host *ihost = dev_to_ihost(task->dev); - struct isci_remote_device *device; + struct isci_remote_device *idev; unsigned long flags; int ret; enum sci_status status; @@ -166,11 +166,12 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags) dev_dbg(&ihost->pdev->dev, "task = %p, num = %d; dev = %p; cmd = %p\n", task, num, task->dev, task->uldd_task); + spin_lock_irqsave(&ihost->scic_lock, flags); + idev = isci_lookup_device(task->dev); + spin_unlock_irqrestore(&ihost->scic_lock, flags); - device = task->dev->lldd_dev; - - if (device) - device_status = device->status; + if (idev) + device_status = idev->status; else device_status = isci_freed; @@ -188,7 +189,7 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags) __func__, task, isci_host_get_state(ihost), - device, + idev, device_status); if (device_status == isci_ready) { @@ -225,7 +226,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(ihost, task, gfp_flags); + status = isci_request_execute(ihost, idev, task, gfp_flags); if (status != SCI_SUCCESS) { @@ -248,33 +249,31 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags) } } } + isci_put_device(idev); } return 0; } static struct isci_request *isci_task_request_build(struct isci_host *ihost, + struct isci_remote_device *idev, struct isci_tmf *isci_tmf) { - struct scic_sds_remote_device *sci_dev; enum sci_status status = SCI_FAILURE; struct isci_request *ireq = NULL; - struct isci_remote_device *idev; struct domain_device *dev; dev_dbg(&ihost->pdev->dev, "%s: isci_tmf = %p\n", __func__, isci_tmf); - idev = isci_tmf->device; - sci_dev = &idev->sci; dev = idev->domain_dev; /* do common allocation and init of request object. */ - ireq = isci_request_alloc_tmf(ihost, isci_tmf, idev, GFP_ATOMIC); + ireq = isci_request_alloc_tmf(ihost, isci_tmf, GFP_ATOMIC); if (!ireq) return NULL; /* let the core do it's construct. */ - status = scic_task_request_construct(&ihost->sci, sci_dev, + status = scic_task_request_construct(&ihost->sci, &idev->sci, SCI_CONTROLLER_INVALID_IO_TAG, &ireq->sci); @@ -309,25 +308,13 @@ static struct isci_request *isci_task_request_build(struct isci_host *ihost, return ireq; } -/** - * isci_task_execute_tmf() - This function builds and sends a task request, - * then waits for the completion. - * @isci_host: This parameter specifies the ISCI host object - * @tmf: This parameter is the pointer to the task management structure for - * this request. - * @timeout_ms: This parameter specifies the timeout period for the task - * management request. - * - * TMF_RESP_FUNC_COMPLETE on successful completion of the TMF (this includes - * error conditions reported in the IU status), or TMF_RESP_FUNC_FAILED. - */ -int isci_task_execute_tmf(struct isci_host *ihost, struct isci_tmf *tmf, - unsigned long timeout_ms) +int isci_task_execute_tmf(struct isci_host *ihost, + struct isci_remote_device *isci_device, + struct isci_tmf *tmf, unsigned long timeout_ms) { DECLARE_COMPLETION_ONSTACK(completion); enum sci_task_status status = SCI_TASK_FAILURE; struct scic_sds_remote_device *sci_device; - struct isci_remote_device *isci_device = tmf->device; struct isci_request *ireq; int ret = TMF_RESP_FUNC_FAILED; unsigned long flags; @@ -352,7 +339,7 @@ int isci_task_execute_tmf(struct isci_host *ihost, struct isci_tmf *tmf, /* Assign the pointer to the TMF's completion kernel wait structure. */ tmf->complete = &completion; - ireq = isci_task_request_build(ihost, tmf); + ireq = isci_task_request_build(ihost, isci_device, tmf); if (!ireq) { dev_warn(&ihost->pdev->dev, "%s: isci_task_request_build failed\n", @@ -399,10 +386,9 @@ int isci_task_execute_tmf(struct isci_host *ihost, struct isci_tmf *tmf, if (tmf->cb_state_func != NULL) tmf->cb_state_func(isci_tmf_timed_out, tmf, tmf->cb_data); - status = scic_controller_terminate_request( - &ireq->isci_host->sci, - &ireq->isci_device->sci, - &ireq->sci); + status = scic_controller_terminate_request(&ihost->sci, + &isci_device->sci, + &ireq->sci); spin_unlock_irqrestore(&ihost->scic_lock, flags); } @@ -437,65 +423,32 @@ int isci_task_execute_tmf(struct isci_host *ihost, struct isci_tmf *tmf, void isci_task_build_tmf( struct isci_tmf *tmf, - struct isci_remote_device *isci_device, enum isci_tmf_function_codes code, void (*tmf_sent_cb)(enum isci_tmf_cb_state, struct isci_tmf *, void *), void *cb_data) { - dev_dbg(&isci_device->isci_port->isci_host->pdev->dev, - "%s: isci_device = %p\n", __func__, isci_device); - memset(tmf, 0, sizeof(*tmf)); - tmf->device = isci_device; tmf->tmf_code = code; - tmf->cb_state_func = tmf_sent_cb; tmf->cb_data = cb_data; } static void isci_task_build_abort_task_tmf( struct isci_tmf *tmf, - struct isci_remote_device *isci_device, enum isci_tmf_function_codes code, void (*tmf_sent_cb)(enum isci_tmf_cb_state, struct isci_tmf *, void *), struct isci_request *old_request) { - isci_task_build_tmf(tmf, isci_device, code, tmf_sent_cb, + isci_task_build_tmf(tmf, code, tmf_sent_cb, (void *)old_request); tmf->io_tag = old_request->io_tag; } -static struct isci_request *isci_task_get_request_from_task( - struct sas_task *task, - struct isci_remote_device **isci_device) -{ - - struct isci_request *request = NULL; - unsigned long flags; - - spin_lock_irqsave(&task->task_state_lock, flags); - - request = task->lldd_task; - - /* If task is already done, the request isn't valid */ - if (!(task->task_state_flags & SAS_TASK_STATE_DONE) && - (task->task_state_flags & SAS_TASK_AT_INITIATOR) && - (request != NULL)) { - - if (isci_device != NULL) - *isci_device = request->isci_device; - } - - spin_unlock_irqrestore(&task->task_state_lock, flags); - - return request; -} - /** * isci_task_validate_request_to_abort() - This function checks the given I/O * against the "started" state. If the request is still "started", it's @@ -858,11 +811,10 @@ static int isci_task_send_lu_reset_sas( * value is "TMF_RESP_FUNC_COMPLETE", or the request timed-out (or * was otherwise unable to be executed ("TMF_RESP_FUNC_FAILED"). */ - isci_task_build_tmf(&tmf, isci_device, isci_tmf_ssp_lun_reset, NULL, - NULL); + isci_task_build_tmf(&tmf, isci_tmf_ssp_lun_reset, NULL, NULL); #define ISCI_LU_RESET_TIMEOUT_MS 2000 /* 2 second timeout. */ - ret = isci_task_execute_tmf(isci_host, &tmf, ISCI_LU_RESET_TIMEOUT_MS); + ret = isci_task_execute_tmf(isci_host, isci_device, &tmf, ISCI_LU_RESET_TIMEOUT_MS); if (ret == TMF_RESP_FUNC_COMPLETE) dev_dbg(&isci_host->pdev->dev, @@ -888,33 +840,33 @@ static int isci_task_send_lu_reset_sas( int isci_task_lu_reset(struct domain_device *domain_device, u8 *lun) { struct isci_host *isci_host = dev_to_ihost(domain_device); - struct isci_remote_device *isci_device = NULL; + struct isci_remote_device *isci_device; + unsigned long flags; int ret; - bool device_stopping = false; - isci_device = domain_device->lldd_dev; + spin_lock_irqsave(&isci_host->scic_lock, flags); + isci_device = isci_lookup_device(domain_device); + spin_unlock_irqrestore(&isci_host->scic_lock, flags); dev_dbg(&isci_host->pdev->dev, "%s: domain_device=%p, isci_host=%p; isci_device=%p\n", __func__, domain_device, isci_host, isci_device); - if (isci_device != NULL) { - device_stopping = (isci_device->status == isci_stopping) - || (isci_device->status == isci_stopped); + if (isci_device) set_bit(IDEV_EH, &isci_device->flags); - } /* If there is a device reset pending on any request in the * device's list, fail this LUN reset request in order to * escalate to the device reset. */ - if (!isci_device || device_stopping || + if (!isci_device || isci_device_is_reset_pending(isci_host, isci_device)) { dev_warn(&isci_host->pdev->dev, "%s: No dev (%p), or " "RESET PENDING: domain_device=%p\n", __func__, isci_device, domain_device); - return TMF_RESP_FUNC_FAILED; + ret = TMF_RESP_FUNC_FAILED; + goto out; } /* Send the task management part of the reset. */ @@ -929,6 +881,8 @@ int isci_task_lu_reset(struct domain_device *domain_device, u8 *lun) isci_terminate_pending_requests(isci_host, isci_device); + out: + isci_put_device(isci_device); return ret; } @@ -1023,60 +977,54 @@ int isci_task_abort_task(struct sas_task *task) int ret = TMF_RESP_FUNC_FAILED; unsigned long flags; bool any_dev_reset = false; - bool device_stopping; /* Get the isci_request reference from the task. Note that * this check does not depend on the pending request list * in the device, because tasks driving resets may land here * after completion in the core. */ - old_request = isci_task_get_request_from_task(task, &isci_device); + spin_lock_irqsave(&isci_host->scic_lock, flags); + spin_lock(&task->task_state_lock); + + old_request = task->lldd_task; + + /* If task is already done, the request isn't valid */ + if (!(task->task_state_flags & SAS_TASK_STATE_DONE) && + (task->task_state_flags & SAS_TASK_AT_INITIATOR) && + old_request) + isci_device = isci_lookup_device(task->dev); + + spin_unlock(&task->task_state_lock); + spin_unlock_irqrestore(&isci_host->scic_lock, flags); dev_dbg(&isci_host->pdev->dev, "%s: task = %p\n", __func__, task); - /* Check if the device has been / is currently being removed. - * If so, no task management will be done, and the I/O will - * be terminated. - */ - device_stopping = (isci_device->status == isci_stopping) - || (isci_device->status == isci_stopped); + if (!isci_device || !old_request) + goto out; - /* XXX need to fix device lookup lifetime (needs to be done - * under scic_lock, among other things...), but for now assume - * the device is available like the above code - */ set_bit(IDEV_EH, &isci_device->flags); /* This version of the driver will fail abort requests for * SATA/STP. Failing the abort request this way will cause the * SCSI error handler thread to escalate to LUN reset */ - if (sas_protocol_ata(task->task_proto) && !device_stopping) { + if (sas_protocol_ata(task->task_proto)) { dev_warn(&isci_host->pdev->dev, " task %p is for a STP/SATA device;" " returning TMF_RESP_FUNC_FAILED\n" " to cause a LUN reset...\n", task); - return TMF_RESP_FUNC_FAILED; + goto out; } dev_dbg(&isci_host->pdev->dev, "%s: old_request == %p\n", __func__, old_request); - if (!device_stopping) - any_dev_reset = isci_device_is_reset_pending(isci_host,isci_device); + any_dev_reset = isci_device_is_reset_pending(isci_host,isci_device); spin_lock_irqsave(&task->task_state_lock, flags); - /* Don't do resets to stopping devices. */ - if (device_stopping) { - - task->task_state_flags &= ~SAS_TASK_NEED_DEV_RESET; - any_dev_reset = false; - - } else /* See if there is a pending device reset for this device. */ - any_dev_reset = any_dev_reset - || (task->task_state_flags & SAS_TASK_NEED_DEV_RESET); + any_dev_reset = any_dev_reset || (task->task_state_flags & SAS_TASK_NEED_DEV_RESET); /* If the extraction of the request reference from the task * failed, then the request has been completed (or if there is a @@ -1130,8 +1078,7 @@ int isci_task_abort_task(struct sas_task *task) "%s: abort task not needed for %p\n", __func__, task); } - - return ret; + goto out; } else spin_unlock_irqrestore(&task->task_state_lock, flags); @@ -1158,11 +1105,10 @@ int isci_task_abort_task(struct sas_task *task) "%s: device = %p; old_request %p already being aborted\n", __func__, isci_device, old_request); - - return TMF_RESP_FUNC_COMPLETE; + ret = TMF_RESP_FUNC_COMPLETE; + goto out; } if ((task->task_proto == SAS_PROTOCOL_SMP) - || device_stopping || old_request->complete_in_target ) { @@ -1170,10 +1116,9 @@ int isci_task_abort_task(struct sas_task *task) dev_dbg(&isci_host->pdev->dev, "%s: SMP request (%d)" - " or device is stopping (%d)" " or complete_in_target (%d), thus no TMF\n", __func__, (task->task_proto == SAS_PROTOCOL_SMP), - device_stopping, old_request->complete_in_target); + old_request->complete_in_target); /* Set the state on the task. */ isci_task_all_done(task); @@ -1185,15 +1130,14 @@ int isci_task_abort_task(struct sas_task *task) */ } else { /* Fill in the tmf stucture */ - isci_task_build_abort_task_tmf(&tmf, isci_device, - isci_tmf_ssp_task_abort, + isci_task_build_abort_task_tmf(&tmf, isci_tmf_ssp_task_abort, isci_abort_task_process_cb, old_request); spin_unlock_irqrestore(&isci_host->scic_lock, flags); #define ISCI_ABORT_TASK_TIMEOUT_MS 500 /* half second timeout. */ - ret = isci_task_execute_tmf(isci_host, &tmf, + ret = isci_task_execute_tmf(isci_host, isci_device, &tmf, ISCI_ABORT_TASK_TIMEOUT_MS); if (ret != TMF_RESP_FUNC_COMPLETE) @@ -1212,6 +1156,8 @@ int isci_task_abort_task(struct sas_task *task) /* Make sure we do not leave a reference to aborted_io_completion */ old_request->io_request_completion = NULL; + out: + isci_put_device(isci_device); return ret; } @@ -1305,7 +1251,6 @@ isci_task_request_complete(struct isci_host *ihost, struct isci_request *ireq, enum sci_task_status completion_status) { - struct isci_remote_device *idev = ireq->isci_device; struct isci_tmf *tmf = isci_request_access_tmf(ireq); struct completion *tmf_complete; struct scic_sds_request *sci_req = &ireq->sci; @@ -1332,7 +1277,7 @@ isci_task_request_complete(struct isci_host *ihost, /* PRINT_TMF( ((struct isci_tmf *)request->task)); */ tmf_complete = tmf->complete; - scic_controller_complete_io(&ihost->sci, &idev->sci, &ireq->sci); + scic_controller_complete_io(&ihost->sci, ireq->sci.target_device, &ireq->sci); /* set the 'terminated' flag handle to make sure it cannot be terminated * or completed again. */ @@ -1583,11 +1528,10 @@ static void isci_wait_for_smp_phy_reset(struct isci_remote_device *idev, int phy dev_dbg(&ihost->pdev->dev, "%s: done\n", __func__); } -static int isci_reset_device(struct domain_device *dev, int hard_reset) +static int isci_reset_device(struct isci_host *ihost, + struct isci_remote_device *idev, int hard_reset) { - struct isci_remote_device *idev = dev->lldd_dev; - struct sas_phy *phy = sas_find_local_phy(dev); - struct isci_host *ihost = dev_to_ihost(dev); + struct sas_phy *phy = sas_find_local_phy(idev->domain_dev); struct isci_port *iport = idev->isci_port; enum sci_status status; unsigned long flags; @@ -1595,14 +1539,6 @@ static int isci_reset_device(struct domain_device *dev, int hard_reset) dev_dbg(&ihost->pdev->dev, "%s: idev %p\n", __func__, idev); - if (!idev) { - dev_warn(&ihost->pdev->dev, - "%s: idev is GONE!\n", - __func__); - - return TMF_RESP_FUNC_COMPLETE; /* Nothing to reset. */ - } - spin_lock_irqsave(&ihost->scic_lock, flags); status = scic_remote_device_reset(&idev->sci); if (status != SCI_SUCCESS) { @@ -1662,35 +1598,50 @@ static int isci_reset_device(struct domain_device *dev, int hard_reset) int isci_task_I_T_nexus_reset(struct domain_device *dev) { struct isci_host *ihost = dev_to_ihost(dev); - int ret = TMF_RESP_FUNC_FAILED, hard_reset = 1; struct isci_remote_device *idev; + int ret, hard_reset = 1; unsigned long flags; - /* XXX mvsas is not protecting against ->lldd_dev_gone(), are we - * being too paranoid, or is mvsas busted?! - */ spin_lock_irqsave(&ihost->scic_lock, flags); - idev = dev->lldd_dev; - if (!idev || !test_bit(IDEV_EH, &idev->flags)) - ret = TMF_RESP_FUNC_COMPLETE; + idev = isci_lookup_device(dev); spin_unlock_irqrestore(&ihost->scic_lock, flags); - if (ret == TMF_RESP_FUNC_COMPLETE) - return ret; + if (!idev || !test_bit(IDEV_EH, &idev->flags)) { + ret = TMF_RESP_FUNC_COMPLETE; + goto out; + } if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) hard_reset = 0; - return isci_reset_device(dev, hard_reset); + ret = isci_reset_device(ihost, idev, hard_reset); + out: + isci_put_device(idev); + return ret; } int isci_bus_reset_handler(struct scsi_cmnd *cmd) { struct domain_device *dev = sdev_to_domain_dev(cmd->device); - int hard_reset = 1; + struct isci_host *ihost = dev_to_ihost(dev); + struct isci_remote_device *idev; + int ret, hard_reset = 1; + unsigned long flags; if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) hard_reset = 0; - return isci_reset_device(dev, hard_reset); + spin_lock_irqsave(&ihost->scic_lock, flags); + idev = isci_lookup_device(dev); + spin_unlock_irqrestore(&ihost->scic_lock, flags); + + if (!idev) { + ret = TMF_RESP_FUNC_COMPLETE; + goto out; + } + + ret = isci_reset_device(ihost, idev, hard_reset); + out: + isci_put_device(idev); + return ret; } -- cgit v1.2.1 From f2088267514b39af1a94409168101527769a911c Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 16 Jun 2011 11:26:12 -0700 Subject: isci: kill isci_remote_device_change_state() Now that "stopping/stopped" are one in the same and signalled by a NULL device pointer the rest of the device status infrastructure can be removed (->status and ->state_lock). The "not ready for i/o state" is replaced with a state flag, and is evaluated under scic_lock so that we don't see transients from taking the device reference to submitting the i/o. This also fixes a potential leakage of can_queue slots in the rare case that SAS_TASK_ABORTED is set at submission. Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 68 ++++++++++++++++-------------------------------- 1 file changed, 22 insertions(+), 46 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index dd5e9de1ffb5..c313bc16c218 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -147,10 +147,10 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags) { struct isci_host *ihost = dev_to_ihost(task->dev); struct isci_remote_device *idev; + enum sci_status status; unsigned long flags; + bool io_ready; int ret; - enum sci_status status; - enum isci_status device_status; dev_dbg(&ihost->pdev->dev, "%s: num=%d\n", __func__, num); @@ -163,64 +163,40 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags) } 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); spin_lock_irqsave(&ihost->scic_lock, flags); idev = isci_lookup_device(task->dev); + io_ready = idev ? test_bit(IDEV_IO_READY, &idev->flags) : 0; spin_unlock_irqrestore(&ihost->scic_lock, flags); - if (idev) - device_status = idev->status; - else - device_status = isci_freed; - - /* From this point onward, any process that needs to guarantee - * that there is no kernel I/O being started will have to wait - * for the quiesce spinlock. - */ - - if (device_status != isci_ready_for_io) { + dev_dbg(&ihost->pdev->dev, + "task: %p, num: %d dev: %p idev: %p:%#lx cmd = %p\n", + task, num, task->dev, idev, idev ? idev->flags : 0, + task->uldd_task); - /* Forces a retry from scsi mid layer. */ - dev_dbg(&ihost->pdev->dev, - "%s: task %p: isci_host->status = %d, " - "device = %p; device_status = 0x%x\n\n", - __func__, - task, - isci_host_get_state(ihost), - idev, - device_status); - - if (device_status == isci_ready) { - /* Indicate QUEUE_FULL so that the scsi midlayer - * retries. - */ - isci_task_refuse(ihost, task, - SAS_TASK_COMPLETE, - SAS_QUEUE_FULL); - } else { - /* Else, the device is going down. */ - isci_task_refuse(ihost, task, - SAS_TASK_UNDELIVERED, - SAS_DEVICE_UNKNOWN); - } + if (!idev) { + isci_task_refuse(ihost, task, SAS_TASK_UNDELIVERED, + SAS_DEVICE_UNKNOWN); + isci_host_can_dequeue(ihost, 1); + } else if (!io_ready) { + /* Indicate QUEUE_FULL so that the scsi midlayer + * retries. + */ + isci_task_refuse(ihost, task, SAS_TASK_COMPLETE, + SAS_QUEUE_FULL); 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); if (task->task_state_flags & SAS_TASK_STATE_ABORTED) { - + /* The I/O was aborted. */ spin_unlock_irqrestore(&task->task_state_lock, flags); isci_task_refuse(ihost, task, SAS_TASK_UNDELIVERED, SAM_STAT_TASK_ABORTED); - - /* The I/O was aborted. */ - + isci_host_can_dequeue(ihost, 1); } else { task->task_state_flags |= SAS_TASK_AT_INITIATOR; spin_unlock_irqrestore(&task->task_state_lock, flags); @@ -323,11 +299,11 @@ int isci_task_execute_tmf(struct isci_host *ihost, /* sanity check, return TMF_RESP_FUNC_FAILED * if the device is not there and ready. */ - if (!isci_device || isci_device->status != isci_ready_for_io) { + if (!isci_device || !test_bit(IDEV_IO_READY, &isci_device->flags)) { dev_dbg(&ihost->pdev->dev, - "%s: isci_device = %p not ready (%d)\n", + "%s: isci_device = %p not ready (%#lx)\n", __func__, - isci_device, isci_device->status); + isci_device, isci_device ? isci_device->flags : 0); return TMF_RESP_FUNC_FAILED; } else dev_dbg(&ihost->pdev->dev, -- cgit v1.2.1 From 086a0dabc5bf154e13604a6d71e2d051207f9718 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 21 Jun 2011 16:23:03 -0700 Subject: isci: fix isci_task_execute_tmf completion 1/ fix the timeout for wait_for_completion_timeout 2/ In the tmf timeout case we need to wait for our termination callback 3/ Once the request is successfully started it will be freed according to the normal lifetime for requests. Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index c313bc16c218..0835a2c2dc71 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -339,7 +339,8 @@ int isci_task_execute_tmf(struct isci_host *ihost, status, ireq); spin_unlock_irqrestore(&ihost->scic_lock, flags); - goto cleanup_request; + isci_request_free(ihost, ireq); + return ret; } if (tmf->cb_state_func != NULL) @@ -354,7 +355,7 @@ int isci_task_execute_tmf(struct isci_host *ihost, /* Wait for the TMF to complete, or a timeout. */ timeleft = wait_for_completion_timeout(&completion, - jiffies + msecs_to_jiffies(timeout_ms)); + msecs_to_jiffies(timeout_ms)); if (timeleft == 0) { spin_lock_irqsave(&ihost->scic_lock, flags); @@ -362,11 +363,13 @@ int isci_task_execute_tmf(struct isci_host *ihost, if (tmf->cb_state_func != NULL) tmf->cb_state_func(isci_tmf_timed_out, tmf, tmf->cb_data); - status = scic_controller_terminate_request(&ihost->sci, - &isci_device->sci, - &ireq->sci); + scic_controller_terminate_request(&ihost->sci, + &isci_device->sci, + &ireq->sci); spin_unlock_irqrestore(&ihost->scic_lock, flags); + + wait_for_completion(tmf->complete); } isci_print_tmf(tmf); @@ -387,13 +390,6 @@ int isci_task_execute_tmf(struct isci_host *ihost, __func__, ireq); - if (ireq->io_request_completion != NULL) { - /* A thread is waiting for this TMF to finish. */ - complete(ireq->io_request_completion); - } - - cleanup_request: - isci_request_free(ihost, ireq); return ret; } -- cgit v1.2.1 From 9274f45ea551421cd3bf329de9dd8d1e6208285a Mon Sep 17 00:00:00 2001 From: Jeff Skirvin Date: Thu, 23 Jun 2011 17:09:02 -0700 Subject: isci: Terminate dev requests on FIS err bit rx in NCQ When the remote device transitions to a not-ready state because of an NCQ error condition, all outstanding requests to that device are terminated and completed to libsas on the normal path. The device then waits for a READ LOG EXT command to issue on the task management path. Signed-off-by: Jeff Skirvin Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 0835a2c2dc71..157e9978183a 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -133,6 +133,15 @@ static void isci_task_refuse(struct isci_host *ihost, struct sas_task *task, for (; num > 0; num--,\ task = list_entry(task->list.next, struct sas_task, list)) + +static inline int isci_device_io_ready(struct isci_remote_device *idev, + struct sas_task *task) +{ + return idev ? test_bit(IDEV_IO_READY, &idev->flags) || + (test_bit(IDEV_IO_NCQERROR, &idev->flags) && + isci_task_is_ncq_recovery(task)) + : 0; +} /** * 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 @@ -165,7 +174,7 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags) for_each_sas_task(num, task) { spin_lock_irqsave(&ihost->scic_lock, flags); idev = isci_lookup_device(task->dev); - io_ready = idev ? test_bit(IDEV_IO_READY, &idev->flags) : 0; + io_ready = isci_device_io_ready(idev, task); spin_unlock_irqrestore(&ihost->scic_lock, flags); dev_dbg(&ihost->pdev->dev, @@ -178,6 +187,7 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags) SAS_DEVICE_UNKNOWN); isci_host_can_dequeue(ihost, 1); } else if (!io_ready) { + /* Indicate QUEUE_FULL so that the scsi midlayer * retries. */ @@ -299,7 +309,9 @@ int isci_task_execute_tmf(struct isci_host *ihost, /* sanity check, return TMF_RESP_FUNC_FAILED * if the device is not there and ready. */ - if (!isci_device || !test_bit(IDEV_IO_READY, &isci_device->flags)) { + if (!isci_device || + (!test_bit(IDEV_IO_READY, &isci_device->flags) && + !test_bit(IDEV_IO_NCQERROR, &isci_device->flags))) { dev_dbg(&ihost->pdev->dev, "%s: isci_device = %p not ready (%#lx)\n", __func__, -- cgit v1.2.1 From 312e0c2455c18716cf640d4336dcb1e9e5053818 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 28 Jun 2011 13:47:09 -0700 Subject: isci: unify can_queue tracking on the tci_pool, uplevel tag assignment The tci_pool tracks our outstanding command slots which are also the 'index' portion of our tags. Grabbing the tag early in ->lldd_execute_task let's us drop the isci_host_can_queue() and ->was_tag_assigned_by_user infrastructure. ->was_tag_assigned_by_user required the task context to be duplicated in request-local buffer. With the tci established early we can build the task_context directly into its final location and skip a memcpy. With the task context buffer at a known address at request construction we have the opportunity/obligation to also fix sgl handling. This rework feels like it belongs in another patch but the sgl handling and task_context are too intertwined. 1/ fix the 'ab' pair embedded in the task context to point to the 'cd' pair in the task context (previously we were prematurely linking to the staging buffer). 2/ fix the broken iteration of pio sgls that assumes all sgls are relative to the request, and does a dangerous looking reverse lookup of physical address to virtual address. Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 80 ++++++++++++++++++++++++++---------------------- 1 file changed, 43 insertions(+), 37 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 157e9978183a..22f6fe171111 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -63,6 +63,7 @@ #include "request.h" #include "sata.h" #include "task.h" +#include "host.h" /** * isci_task_refuse() - complete the request to the upper layer driver in @@ -156,25 +157,19 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags) { struct isci_host *ihost = dev_to_ihost(task->dev); struct isci_remote_device *idev; - enum sci_status status; unsigned long flags; bool io_ready; - int ret; + u16 tag; dev_dbg(&ihost->pdev->dev, "%s: num=%d\n", __func__, num); - /* Check if we have room for more tasks */ - ret = isci_host_can_queue(ihost, num); - - if (ret) { - dev_warn(&ihost->pdev->dev, "%s: queue full\n", __func__); - return ret; - } - for_each_sas_task(num, task) { + enum sci_status status = SCI_FAILURE; + spin_lock_irqsave(&ihost->scic_lock, flags); idev = isci_lookup_device(task->dev); io_ready = isci_device_io_ready(idev, task); + tag = isci_alloc_tag(ihost); spin_unlock_irqrestore(&ihost->scic_lock, flags); dev_dbg(&ihost->pdev->dev, @@ -185,15 +180,12 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags) if (!idev) { isci_task_refuse(ihost, task, SAS_TASK_UNDELIVERED, SAS_DEVICE_UNKNOWN); - isci_host_can_dequeue(ihost, 1); - } else if (!io_ready) { - + } else if (!io_ready || tag == SCI_CONTROLLER_INVALID_IO_TAG) { /* Indicate QUEUE_FULL so that the scsi midlayer * retries. */ isci_task_refuse(ihost, task, SAS_TASK_COMPLETE, SAS_QUEUE_FULL); - 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); @@ -206,13 +198,12 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags) isci_task_refuse(ihost, task, SAS_TASK_UNDELIVERED, SAM_STAT_TASK_ABORTED); - isci_host_can_dequeue(ihost, 1); } else { task->task_state_flags |= SAS_TASK_AT_INITIATOR; spin_unlock_irqrestore(&task->task_state_lock, flags); /* build and send the request. */ - status = isci_request_execute(ihost, idev, task, gfp_flags); + status = isci_request_execute(ihost, idev, task, tag, gfp_flags); if (status != SCI_SUCCESS) { @@ -231,10 +222,17 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags) isci_task_refuse(ihost, task, SAS_TASK_COMPLETE, SAS_QUEUE_FULL); - isci_host_can_dequeue(ihost, 1); } } } + if (status != SCI_SUCCESS && tag != SCI_CONTROLLER_INVALID_IO_TAG) { + spin_lock_irqsave(&ihost->scic_lock, flags); + /* command never hit the device, so just free + * the tci and skip the sequence increment + */ + isci_tci_free(ihost, ISCI_TAG_TCI(tag)); + spin_unlock_irqrestore(&ihost->scic_lock, flags); + } isci_put_device(idev); } return 0; @@ -242,7 +240,7 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags) static struct isci_request *isci_task_request_build(struct isci_host *ihost, struct isci_remote_device *idev, - struct isci_tmf *isci_tmf) + u16 tag, struct isci_tmf *isci_tmf) { enum sci_status status = SCI_FAILURE; struct isci_request *ireq = NULL; @@ -259,8 +257,7 @@ static struct isci_request *isci_task_request_build(struct isci_host *ihost, return NULL; /* let the core do it's construct. */ - status = scic_task_request_construct(&ihost->sci, &idev->sci, - SCI_CONTROLLER_INVALID_IO_TAG, + status = scic_task_request_construct(&ihost->sci, &idev->sci, tag, &ireq->sci); if (status != SCI_SUCCESS) { @@ -290,8 +287,7 @@ static struct isci_request *isci_task_request_build(struct isci_host *ihost, return ireq; errout: isci_request_free(ihost, ireq); - ireq = NULL; - return ireq; + return NULL; } int isci_task_execute_tmf(struct isci_host *ihost, @@ -305,6 +301,14 @@ int isci_task_execute_tmf(struct isci_host *ihost, int ret = TMF_RESP_FUNC_FAILED; unsigned long flags; unsigned long timeleft; + u16 tag; + + spin_lock_irqsave(&ihost->scic_lock, flags); + tag = isci_alloc_tag(ihost); + spin_unlock_irqrestore(&ihost->scic_lock, flags); + + if (tag == SCI_CONTROLLER_INVALID_IO_TAG) + return ret; /* sanity check, return TMF_RESP_FUNC_FAILED * if the device is not there and ready. @@ -316,7 +320,7 @@ int isci_task_execute_tmf(struct isci_host *ihost, "%s: isci_device = %p not ready (%#lx)\n", __func__, isci_device, isci_device ? isci_device->flags : 0); - return TMF_RESP_FUNC_FAILED; + goto err_tci; } else dev_dbg(&ihost->pdev->dev, "%s: isci_device = %p\n", @@ -327,22 +331,16 @@ int isci_task_execute_tmf(struct isci_host *ihost, /* Assign the pointer to the TMF's completion kernel wait structure. */ tmf->complete = &completion; - ireq = isci_task_request_build(ihost, isci_device, tmf); - if (!ireq) { - dev_warn(&ihost->pdev->dev, - "%s: isci_task_request_build failed\n", - __func__); - return TMF_RESP_FUNC_FAILED; - } + ireq = isci_task_request_build(ihost, isci_device, tag, tmf); + if (!ireq) + goto err_tci; spin_lock_irqsave(&ihost->scic_lock, flags); /* start the TMF io. */ - status = scic_controller_start_task( - &ihost->sci, - sci_device, - &ireq->sci, - SCI_CONTROLLER_INVALID_IO_TAG); + status = scic_controller_start_task(&ihost->sci, + sci_device, + &ireq->sci); if (status != SCI_TASK_SUCCESS) { dev_warn(&ihost->pdev->dev, @@ -351,8 +349,7 @@ int isci_task_execute_tmf(struct isci_host *ihost, status, ireq); spin_unlock_irqrestore(&ihost->scic_lock, flags); - isci_request_free(ihost, ireq); - return ret; + goto err_ireq; } if (tmf->cb_state_func != NULL) @@ -403,6 +400,15 @@ int isci_task_execute_tmf(struct isci_host *ihost, ireq); return ret; + + err_ireq: + isci_request_free(ihost, ireq); + err_tci: + spin_lock_irqsave(&ihost->scic_lock, flags); + isci_tci_free(ihost, ISCI_TAG_TCI(tag)); + spin_unlock_irqrestore(&ihost->scic_lock, flags); + + return ret; } void isci_task_build_tmf( -- cgit v1.2.1 From 38d8879baeb61b6946052739e7c03fa79b3a57f0 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 23 Jun 2011 14:33:48 -0700 Subject: isci: combine request flags Combine three bools into one unsigned long 'flags'. Doesn't increase the request size due to packing. (to do: optimize the structure layout). Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 22f6fe171111..d1a46710f4a7 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -558,15 +558,15 @@ static void isci_terminate_request_core( : NULL; /* Note that we are not going to control - * the target to abort the request. - */ - isci_request->complete_in_target = true; + * the target to abort the request. + */ + set_bit(IREQ_COMPLETE_IN_TARGET, &isci_request->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). */ - if (!isci_request->terminated) { + if (!test_bit(IREQ_TERMINATED, &isci_request->flags)) { was_terminated = true; needs_cleanup_handling = true; status = scic_controller_terminate_request( @@ -609,7 +609,7 @@ static void isci_terminate_request_core( flags); /* Check for state changes. */ - if (!isci_request->terminated) { + if (!test_bit(IREQ_TERMINATED, &isci_request->flags)) { /* The best we can do is to have the * request die a silent death if it @@ -1098,9 +1098,8 @@ int isci_task_abort_task(struct sas_task *task) ret = TMF_RESP_FUNC_COMPLETE; goto out; } - if ((task->task_proto == SAS_PROTOCOL_SMP) - || old_request->complete_in_target - ) { + if (task->task_proto == SAS_PROTOCOL_SMP || + test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags)) { spin_unlock_irqrestore(&isci_host->scic_lock, flags); @@ -1108,7 +1107,7 @@ int isci_task_abort_task(struct sas_task *task) "%s: SMP request (%d)" " or complete_in_target (%d), thus no TMF\n", __func__, (task->task_proto == SAS_PROTOCOL_SMP), - old_request->complete_in_target); + test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags)); /* Set the state on the task. */ isci_task_all_done(task); @@ -1136,7 +1135,7 @@ int isci_task_abort_task(struct sas_task *task) __func__); } if (ret == TMF_RESP_FUNC_COMPLETE) { - old_request->complete_in_target = true; + set_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags); /* Clean up the request on our side, and wait for the aborted * I/O to complete. @@ -1252,7 +1251,7 @@ isci_task_request_complete(struct isci_host *ihost, isci_request_change_state(ireq, completed); tmf->status = completion_status; - ireq->complete_in_target = true; + set_bit(IREQ_COMPLETE_IN_TARGET, &ireq->flags); if (tmf->proto == SAS_PROTOCOL_SSP) { memcpy(&tmf->resp.resp_iu, @@ -1271,7 +1270,7 @@ isci_task_request_complete(struct isci_host *ihost, /* set the 'terminated' flag handle to make sure it cannot be terminated * or completed again. */ - ireq->terminated = true;; + set_bit(IREQ_TERMINATED, &ireq->flags); isci_request_change_state(ireq, unallocated); list_del_init(&ireq->dev_node); -- cgit v1.2.1 From db0562509800a2d4cb5cb14a66413c30484f165c Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 17 Jun 2011 14:18:39 -0700 Subject: isci: preallocate requests the dma_pool interface is optimized for object_size << page_size which is not the case with isci_request objects and the dma_pool routines show up in the top of the profile. The old io_request_table which tracked whether tci slots were in-flight or not is replaced with an IREQ_ACTIVE flag per request. Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index d1a46710f4a7..d2dba8354899 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -203,7 +203,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(ihost, idev, task, tag, gfp_flags); + status = isci_request_execute(ihost, idev, task, tag); if (status != SCI_SUCCESS) { @@ -252,7 +252,7 @@ static struct isci_request *isci_task_request_build(struct isci_host *ihost, dev = idev->domain_dev; /* do common allocation and init of request object. */ - ireq = isci_request_alloc_tmf(ihost, isci_tmf, GFP_ATOMIC); + ireq = isci_tmf_request_from_tag(ihost, isci_tmf, tag); if (!ireq) return NULL; @@ -266,7 +266,7 @@ static struct isci_request *isci_task_request_build(struct isci_host *ihost, "status = 0x%x\n", __func__, status); - goto errout; + return NULL; } /* XXX convert to get this from task->tproto like other drivers */ @@ -274,7 +274,7 @@ static struct isci_request *isci_task_request_build(struct isci_host *ihost, isci_tmf->proto = SAS_PROTOCOL_SSP; status = scic_task_request_construct_ssp(&ireq->sci); if (status != SCI_SUCCESS) - goto errout; + return NULL; } if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) { @@ -282,12 +282,9 @@ static struct isci_request *isci_task_request_build(struct isci_host *ihost, status = isci_sata_management_task_request_build(ireq); if (status != SCI_SUCCESS) - goto errout; + return NULL; } return ireq; - errout: - isci_request_free(ihost, ireq); - return NULL; } int isci_task_execute_tmf(struct isci_host *ihost, @@ -349,7 +346,7 @@ int isci_task_execute_tmf(struct isci_host *ihost, status, ireq); spin_unlock_irqrestore(&ihost->scic_lock, flags); - goto err_ireq; + goto err_tci; } if (tmf->cb_state_func != NULL) @@ -401,8 +398,6 @@ int isci_task_execute_tmf(struct isci_host *ihost, return ret; - err_ireq: - isci_request_free(ihost, ireq); err_tci: spin_lock_irqsave(&ihost->scic_lock, flags); isci_tci_free(ihost, ISCI_TAG_TCI(tag)); @@ -516,8 +511,6 @@ static void isci_request_cleanup_completed_loiterer( spin_lock_irqsave(&isci_host->scic_lock, flags); list_del_init(&isci_request->dev_node); spin_unlock_irqrestore(&isci_host->scic_lock, flags); - - isci_request_free(isci_host, isci_request); } } -- cgit v1.2.1 From 5076a1a97e2fa61c847a5fdd4b1991faf7716da6 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 27 Jun 2011 14:57:03 -0700 Subject: isci: unify isci_request and scic_sds_request They are one in the same object so remove the distinction. The near duplicate fields (owning_controller, and isci_host) will be cleaned up after the scic_sds_contoller isci_host unification. Reported-by: Christoph Hellwig Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index d2dba8354899..700708c82678 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -258,7 +258,7 @@ static struct isci_request *isci_task_request_build(struct isci_host *ihost, /* let the core do it's construct. */ status = scic_task_request_construct(&ihost->sci, &idev->sci, tag, - &ireq->sci); + ireq); if (status != SCI_SUCCESS) { dev_warn(&ihost->pdev->dev, @@ -272,7 +272,7 @@ static struct isci_request *isci_task_request_build(struct isci_host *ihost, /* XXX convert to get this from task->tproto like other drivers */ if (dev->dev_type == SAS_END_DEV) { isci_tmf->proto = SAS_PROTOCOL_SSP; - status = scic_task_request_construct_ssp(&ireq->sci); + status = scic_task_request_construct_ssp(ireq); if (status != SCI_SUCCESS) return NULL; } @@ -337,7 +337,7 @@ int isci_task_execute_tmf(struct isci_host *ihost, /* start the TMF io. */ status = scic_controller_start_task(&ihost->sci, sci_device, - &ireq->sci); + ireq); if (status != SCI_TASK_SUCCESS) { dev_warn(&ihost->pdev->dev, @@ -371,7 +371,7 @@ int isci_task_execute_tmf(struct isci_host *ihost, scic_controller_terminate_request(&ihost->sci, &isci_device->sci, - &ireq->sci); + ireq); spin_unlock_irqrestore(&ihost->scic_lock, flags); @@ -565,7 +565,7 @@ static void isci_terminate_request_core( status = scic_controller_terminate_request( &isci_host->sci, &isci_device->sci, - &isci_request->sci); + isci_request); } spin_unlock_irqrestore(&isci_host->scic_lock, flags); @@ -1235,7 +1235,6 @@ isci_task_request_complete(struct isci_host *ihost, { struct isci_tmf *tmf = isci_request_access_tmf(ireq); struct completion *tmf_complete; - struct scic_sds_request *sci_req = &ireq->sci; dev_dbg(&ihost->pdev->dev, "%s: request = %p, status=%d\n", @@ -1248,18 +1247,18 @@ isci_task_request_complete(struct isci_host *ihost, if (tmf->proto == SAS_PROTOCOL_SSP) { memcpy(&tmf->resp.resp_iu, - &sci_req->ssp.rsp, + &ireq->ssp.rsp, SSP_RESP_IU_MAX_SIZE); } else if (tmf->proto == SAS_PROTOCOL_SATA) { memcpy(&tmf->resp.d2h_fis, - &sci_req->stp.rsp, + &ireq->stp.rsp, sizeof(struct dev_to_host_fis)); } /* PRINT_TMF( ((struct isci_tmf *)request->task)); */ tmf_complete = tmf->complete; - scic_controller_complete_io(&ihost->sci, ireq->sci.target_device, &ireq->sci); + scic_controller_complete_io(&ihost->sci, ireq->target_device, ireq); /* set the 'terminated' flag handle to make sure it cannot be terminated * or completed again. */ -- cgit v1.2.1 From 78a6f06e0e82125787d7aa308fe28c2c8381540c Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 30 Jun 2011 16:31:37 -0700 Subject: isci: unify isci_remote_device and scic_sds_remote_device Remove the distinction between these two implementations and unify on isci_remote_device (local instances named idev). Reported-by: Christoph Hellwig Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 47 +++++++++++++++++++++-------------------------- 1 file changed, 21 insertions(+), 26 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 700708c82678..89b01eef44b1 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -257,7 +257,7 @@ static struct isci_request *isci_task_request_build(struct isci_host *ihost, return NULL; /* let the core do it's construct. */ - status = scic_task_request_construct(&ihost->sci, &idev->sci, tag, + status = scic_task_request_construct(&ihost->sci, idev, tag, ireq); if (status != SCI_SUCCESS) { @@ -288,12 +288,11 @@ static struct isci_request *isci_task_request_build(struct isci_host *ihost, } int isci_task_execute_tmf(struct isci_host *ihost, - struct isci_remote_device *isci_device, + struct isci_remote_device *idev, struct isci_tmf *tmf, unsigned long timeout_ms) { DECLARE_COMPLETION_ONSTACK(completion); enum sci_task_status status = SCI_TASK_FAILURE; - struct scic_sds_remote_device *sci_device; struct isci_request *ireq; int ret = TMF_RESP_FUNC_FAILED; unsigned long flags; @@ -310,34 +309,30 @@ int isci_task_execute_tmf(struct isci_host *ihost, /* sanity check, return TMF_RESP_FUNC_FAILED * if the device is not there and ready. */ - if (!isci_device || - (!test_bit(IDEV_IO_READY, &isci_device->flags) && - !test_bit(IDEV_IO_NCQERROR, &isci_device->flags))) { + if (!idev || + (!test_bit(IDEV_IO_READY, &idev->flags) && + !test_bit(IDEV_IO_NCQERROR, &idev->flags))) { dev_dbg(&ihost->pdev->dev, - "%s: isci_device = %p not ready (%#lx)\n", + "%s: idev = %p not ready (%#lx)\n", __func__, - isci_device, isci_device ? isci_device->flags : 0); + idev, idev ? idev->flags : 0); goto err_tci; } else dev_dbg(&ihost->pdev->dev, - "%s: isci_device = %p\n", - __func__, isci_device); - - sci_device = &isci_device->sci; + "%s: idev = %p\n", + __func__, idev); /* Assign the pointer to the TMF's completion kernel wait structure. */ tmf->complete = &completion; - ireq = isci_task_request_build(ihost, isci_device, tag, tmf); + ireq = isci_task_request_build(ihost, idev, tag, tmf); if (!ireq) goto err_tci; spin_lock_irqsave(&ihost->scic_lock, flags); /* start the TMF io. */ - status = scic_controller_start_task(&ihost->sci, - sci_device, - ireq); + status = scic_controller_start_task(&ihost->sci, idev, ireq); if (status != SCI_TASK_SUCCESS) { dev_warn(&ihost->pdev->dev, @@ -355,7 +350,7 @@ int isci_task_execute_tmf(struct isci_host *ihost, isci_request_change_state(ireq, started); /* add the request to the remote device request list. */ - list_add(&ireq->dev_node, &isci_device->reqs_in_process); + list_add(&ireq->dev_node, &idev->reqs_in_process); spin_unlock_irqrestore(&ihost->scic_lock, flags); @@ -370,7 +365,7 @@ int isci_task_execute_tmf(struct isci_host *ihost, tmf->cb_state_func(isci_tmf_timed_out, tmf, tmf->cb_data); scic_controller_terminate_request(&ihost->sci, - &isci_device->sci, + idev, ireq); spin_unlock_irqrestore(&ihost->scic_lock, flags); @@ -520,13 +515,13 @@ static void isci_request_cleanup_completed_loiterer( * from a thread that can wait. Note that the request is terminated and * completed (back to the host, if started there). * @isci_host: This SCU. - * @isci_device: The target. + * @idev: The target. * @isci_request: The I/O request to be terminated. * */ static void isci_terminate_request_core( struct isci_host *isci_host, - struct isci_remote_device *isci_device, + struct isci_remote_device *idev, struct isci_request *isci_request) { enum sci_status status = SCI_SUCCESS; @@ -540,7 +535,7 @@ static void isci_terminate_request_core( dev_dbg(&isci_host->pdev->dev, "%s: device = %p; request = %p\n", - __func__, isci_device, isci_request); + __func__, idev, isci_request); spin_lock_irqsave(&isci_host->scic_lock, flags); @@ -564,7 +559,7 @@ static void isci_terminate_request_core( needs_cleanup_handling = true; status = scic_controller_terminate_request( &isci_host->sci, - &isci_device->sci, + idev, isci_request); } spin_unlock_irqrestore(&isci_host->scic_lock, flags); @@ -683,7 +678,7 @@ static void isci_terminate_request_core( } if (needs_cleanup_handling) isci_request_cleanup_completed_loiterer( - isci_host, isci_device, isci_request, task); + isci_host, idev, isci_request, task); } } @@ -694,7 +689,7 @@ static void isci_terminate_request_core( * called from a thread that can wait. Note that the requests are all * terminated and completed (back to the host, if started there). * @isci_host: This parameter specifies SCU. - * @isci_device: This parameter specifies the target. + * @idev: This parameter specifies the target. * */ void isci_terminate_pending_requests(struct isci_host *ihost, @@ -1521,7 +1516,7 @@ static int isci_reset_device(struct isci_host *ihost, dev_dbg(&ihost->pdev->dev, "%s: idev %p\n", __func__, idev); spin_lock_irqsave(&ihost->scic_lock, flags); - status = scic_remote_device_reset(&idev->sci); + status = scic_remote_device_reset(idev); if (status != SCI_SUCCESS) { spin_unlock_irqrestore(&ihost->scic_lock, flags); @@ -1547,7 +1542,7 @@ static int isci_reset_device(struct isci_host *ihost, /* Since all pending TCs have been cleaned, resume the RNC. */ spin_lock_irqsave(&ihost->scic_lock, flags); - status = scic_remote_device_reset_complete(&idev->sci); + status = scic_remote_device_reset_complete(idev); spin_unlock_irqrestore(&ihost->scic_lock, flags); /* If this is a device on an expander, bring the phy back up. */ -- cgit v1.2.1 From d9dcb4ba791de2a06b19ac47cd61601cf3d4e208 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 30 Jun 2011 17:38:32 -0700 Subject: isci: unify isci_host and scic_sds_controller Remove the distinction between these two implementations and unify on isci_host (local instances named ihost). Hmmm, we had two 'oem_parameters' instances, one was unused... nice. Reported-by: Christoph Hellwig Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 44 +++++++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 23 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 89b01eef44b1..3a1fc55a7557 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -257,7 +257,7 @@ static struct isci_request *isci_task_request_build(struct isci_host *ihost, return NULL; /* let the core do it's construct. */ - status = scic_task_request_construct(&ihost->sci, idev, tag, + status = scic_task_request_construct(ihost, idev, tag, ireq); if (status != SCI_SUCCESS) { @@ -332,7 +332,7 @@ int isci_task_execute_tmf(struct isci_host *ihost, spin_lock_irqsave(&ihost->scic_lock, flags); /* start the TMF io. */ - status = scic_controller_start_task(&ihost->sci, idev, ireq); + status = scic_controller_start_task(ihost, idev, ireq); if (status != SCI_TASK_SUCCESS) { dev_warn(&ihost->pdev->dev, @@ -364,7 +364,7 @@ int isci_task_execute_tmf(struct isci_host *ihost, if (tmf->cb_state_func != NULL) tmf->cb_state_func(isci_tmf_timed_out, tmf, tmf->cb_data); - scic_controller_terminate_request(&ihost->sci, + scic_controller_terminate_request(ihost, idev, ireq); @@ -514,15 +514,14 @@ static void isci_request_cleanup_completed_loiterer( * request, and wait for it to complete. This function must only be called * from a thread that can wait. Note that the request is terminated and * completed (back to the host, if started there). - * @isci_host: This SCU. + * @ihost: This SCU. * @idev: The target. * @isci_request: The I/O request to be terminated. * */ -static void isci_terminate_request_core( - struct isci_host *isci_host, - struct isci_remote_device *idev, - struct isci_request *isci_request) +static void isci_terminate_request_core(struct isci_host *ihost, + struct isci_remote_device *idev, + struct isci_request *isci_request) { enum sci_status status = SCI_SUCCESS; bool was_terminated = false; @@ -533,11 +532,11 @@ static void isci_terminate_request_core( struct completion *io_request_completion; struct sas_task *task; - dev_dbg(&isci_host->pdev->dev, + dev_dbg(&ihost->pdev->dev, "%s: device = %p; request = %p\n", __func__, idev, isci_request); - spin_lock_irqsave(&isci_host->scic_lock, flags); + spin_lock_irqsave(&ihost->scic_lock, flags); io_request_completion = isci_request->io_request_completion; @@ -557,12 +556,11 @@ static void isci_terminate_request_core( if (!test_bit(IREQ_TERMINATED, &isci_request->flags)) { was_terminated = true; needs_cleanup_handling = true; - status = scic_controller_terminate_request( - &isci_host->sci, - idev, - isci_request); + status = scic_controller_terminate_request(ihost, + idev, + isci_request); } - spin_unlock_irqrestore(&isci_host->scic_lock, flags); + spin_unlock_irqrestore(&ihost->scic_lock, flags); /* * The only time the request to terminate will @@ -570,7 +568,7 @@ static void isci_terminate_request_core( * being aborted. */ if (status != SCI_SUCCESS) { - dev_err(&isci_host->pdev->dev, + dev_err(&ihost->pdev->dev, "%s: scic_controller_terminate_request" " returned = 0x%x\n", __func__, status); @@ -579,7 +577,7 @@ static void isci_terminate_request_core( } else { if (was_terminated) { - dev_dbg(&isci_host->pdev->dev, + dev_dbg(&ihost->pdev->dev, "%s: before completion wait (%p/%p)\n", __func__, isci_request, io_request_completion); @@ -593,7 +591,7 @@ static void isci_terminate_request_core( if (!termination_completed) { /* The request to terminate has timed out. */ - spin_lock_irqsave(&isci_host->scic_lock, + spin_lock_irqsave(&ihost->scic_lock, flags); /* Check for state changes. */ @@ -623,12 +621,12 @@ static void isci_terminate_request_core( } else termination_completed = 1; - spin_unlock_irqrestore(&isci_host->scic_lock, + spin_unlock_irqrestore(&ihost->scic_lock, flags); if (!termination_completed) { - dev_err(&isci_host->pdev->dev, + dev_err(&ihost->pdev->dev, "%s: *** Timeout waiting for " "termination(%p/%p)\n", __func__, io_request_completion, @@ -642,7 +640,7 @@ static void isci_terminate_request_core( } } if (termination_completed) - dev_dbg(&isci_host->pdev->dev, + dev_dbg(&ihost->pdev->dev, "%s: after completion wait (%p/%p)\n", __func__, isci_request, io_request_completion); } @@ -678,7 +676,7 @@ static void isci_terminate_request_core( } if (needs_cleanup_handling) isci_request_cleanup_completed_loiterer( - isci_host, idev, isci_request, task); + ihost, idev, isci_request, task); } } @@ -1253,7 +1251,7 @@ isci_task_request_complete(struct isci_host *ihost, /* PRINT_TMF( ((struct isci_tmf *)request->task)); */ tmf_complete = tmf->complete; - scic_controller_complete_io(&ihost->sci, ireq->target_device, ireq); + scic_controller_complete_io(ihost, ireq->target_device, ireq); /* set the 'terminated' flag handle to make sure it cannot be terminated * or completed again. */ -- cgit v1.2.1 From 89a7301f21fb00e753089671eb9e4132aab8ea08 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 30 Jun 2011 19:14:33 -0700 Subject: isci: retire scic_sds_ and scic_ prefixes The distinction between scic_sds_ scic_ and sci_ are no longer relevant so just unify the prefixes on sci_. The distinction between isci_ and sci_ is historically significant, and useful for comparing the old 'core' to the current Linux driver. 'sci_' represents the former core as well as the routines that are closer to the hardware and protocol than their 'isci_' brethren. sci == sas controller interface. Also unwind the 'sds1' out of the parameter structs. Reported-by: Christoph Hellwig Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 3a1fc55a7557..d040aa2f3722 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -257,12 +257,12 @@ static struct isci_request *isci_task_request_build(struct isci_host *ihost, return NULL; /* let the core do it's construct. */ - status = scic_task_request_construct(ihost, idev, tag, + status = sci_task_request_construct(ihost, idev, tag, ireq); if (status != SCI_SUCCESS) { dev_warn(&ihost->pdev->dev, - "%s: scic_task_request_construct failed - " + "%s: sci_task_request_construct failed - " "status = 0x%x\n", __func__, status); @@ -272,7 +272,7 @@ static struct isci_request *isci_task_request_build(struct isci_host *ihost, /* XXX convert to get this from task->tproto like other drivers */ if (dev->dev_type == SAS_END_DEV) { isci_tmf->proto = SAS_PROTOCOL_SSP; - status = scic_task_request_construct_ssp(ireq); + status = sci_task_request_construct_ssp(ireq); if (status != SCI_SUCCESS) return NULL; } @@ -332,7 +332,7 @@ int isci_task_execute_tmf(struct isci_host *ihost, spin_lock_irqsave(&ihost->scic_lock, flags); /* start the TMF io. */ - status = scic_controller_start_task(ihost, idev, ireq); + status = sci_controller_start_task(ihost, idev, ireq); if (status != SCI_TASK_SUCCESS) { dev_warn(&ihost->pdev->dev, @@ -364,7 +364,7 @@ int isci_task_execute_tmf(struct isci_host *ihost, if (tmf->cb_state_func != NULL) tmf->cb_state_func(isci_tmf_timed_out, tmf, tmf->cb_data); - scic_controller_terminate_request(ihost, + sci_controller_terminate_request(ihost, idev, ireq); @@ -556,7 +556,7 @@ static void isci_terminate_request_core(struct isci_host *ihost, if (!test_bit(IREQ_TERMINATED, &isci_request->flags)) { was_terminated = true; needs_cleanup_handling = true; - status = scic_controller_terminate_request(ihost, + status = sci_controller_terminate_request(ihost, idev, isci_request); } @@ -569,7 +569,7 @@ static void isci_terminate_request_core(struct isci_host *ihost, */ if (status != SCI_SUCCESS) { dev_err(&ihost->pdev->dev, - "%s: scic_controller_terminate_request" + "%s: sci_controller_terminate_request" " returned = 0x%x\n", __func__, status); @@ -1251,7 +1251,7 @@ isci_task_request_complete(struct isci_host *ihost, /* PRINT_TMF( ((struct isci_tmf *)request->task)); */ tmf_complete = tmf->complete; - scic_controller_complete_io(ihost, ireq->target_device, ireq); + sci_controller_complete_io(ihost, ireq->target_device, ireq); /* set the 'terminated' flag handle to make sure it cannot be terminated * or completed again. */ @@ -1514,12 +1514,12 @@ static int isci_reset_device(struct isci_host *ihost, dev_dbg(&ihost->pdev->dev, "%s: idev %p\n", __func__, idev); spin_lock_irqsave(&ihost->scic_lock, flags); - status = scic_remote_device_reset(idev); + status = sci_remote_device_reset(idev); if (status != SCI_SUCCESS) { spin_unlock_irqrestore(&ihost->scic_lock, flags); dev_warn(&ihost->pdev->dev, - "%s: scic_remote_device_reset(%p) returned %d!\n", + "%s: sci_remote_device_reset(%p) returned %d!\n", __func__, idev, status); return TMF_RESP_FUNC_FAILED; @@ -1540,7 +1540,7 @@ static int isci_reset_device(struct isci_host *ihost, /* Since all pending TCs have been cleaned, resume the RNC. */ spin_lock_irqsave(&ihost->scic_lock, flags); - status = scic_remote_device_reset_complete(idev); + status = sci_remote_device_reset_complete(idev); spin_unlock_irqrestore(&ihost->scic_lock, flags); /* If this is a device on an expander, bring the phy back up. */ @@ -1560,7 +1560,7 @@ static int isci_reset_device(struct isci_host *ihost, if (status != SCI_SUCCESS) { dev_warn(&ihost->pdev->dev, - "%s: scic_remote_device_reset_complete(%p) " + "%s: sci_remote_device_reset_complete(%p) " "returned %d!\n", __func__, idev, status); } -- cgit v1.2.1 From 34a991587a5cc9f78960c2c9beea217866458c41 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 1 Jul 2011 02:25:15 -0700 Subject: isci: kill 'get/set' macros Most of these simple dereference macros are longer than their open coded equivalent. Deleting enum sci_controller_mode is thrown in for good measure. Reported-by: Christoph Hellwig Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index d040aa2f3722..20112cd5b646 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -654,7 +654,7 @@ static void isci_terminate_request_core(struct isci_host *ihost, * needs to be detached and freed here. */ spin_lock_irqsave(&isci_request->state_lock, flags); - request_status = isci_request_get_state(isci_request); + request_status = isci_request->status; if ((isci_request->ttype == io_task) /* TMFs are in their own thread */ && ((request_status == aborted) -- cgit v1.2.1 From 16ba77091b44af28b3ff3318b4a2aa4fbf7d4c24 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 1 Jul 2011 10:52:55 -0700 Subject: isci: merge sata.[ch] into request.c Undo some needless separation. Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 100 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 80 insertions(+), 20 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 20112cd5b646..5d962b6b03eb 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -61,7 +61,6 @@ #include "remote_node_context.h" #include "isci.h" #include "request.h" -#include "sata.h" #include "task.h" #include "host.h" @@ -238,6 +237,46 @@ int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags) return 0; } +static enum sci_status isci_sata_management_task_request_build(struct isci_request *ireq) +{ + struct isci_tmf *isci_tmf; + enum sci_status status; + + if (tmf_task != ireq->ttype) + return SCI_FAILURE; + + isci_tmf = isci_request_access_tmf(ireq); + + switch (isci_tmf->tmf_code) { + + case isci_tmf_sata_srst_high: + case isci_tmf_sata_srst_low: { + struct host_to_dev_fis *fis = &ireq->stp.cmd; + + memset(fis, 0, sizeof(*fis)); + + fis->fis_type = 0x27; + fis->flags &= ~0x80; + fis->flags &= 0xF0; + if (isci_tmf->tmf_code == isci_tmf_sata_srst_high) + fis->control |= ATA_SRST; + else + fis->control &= ~ATA_SRST; + break; + } + /* other management commnd go here... */ + default: + return SCI_FAILURE; + } + + /* core builds the protocol specific request + * based on the h2d fis. + */ + status = sci_task_request_construct_sata(ireq); + + return status; +} + static struct isci_request *isci_task_request_build(struct isci_host *ihost, struct isci_remote_device *idev, u16 tag, struct isci_tmf *isci_tmf) @@ -287,9 +326,9 @@ static struct isci_request *isci_task_request_build(struct isci_host *ihost, return ireq; } -int isci_task_execute_tmf(struct isci_host *ihost, - struct isci_remote_device *idev, - struct isci_tmf *tmf, unsigned long timeout_ms) +static int isci_task_execute_tmf(struct isci_host *ihost, + struct isci_remote_device *idev, + struct isci_tmf *tmf, unsigned long timeout_ms) { DECLARE_COMPLETION_ONSTACK(completion); enum sci_task_status status = SCI_TASK_FAILURE; @@ -401,13 +440,12 @@ int isci_task_execute_tmf(struct isci_host *ihost, return ret; } -void isci_task_build_tmf( - struct isci_tmf *tmf, - enum isci_tmf_function_codes code, - void (*tmf_sent_cb)(enum isci_tmf_cb_state, - struct isci_tmf *, - void *), - void *cb_data) +static void isci_task_build_tmf(struct isci_tmf *tmf, + enum isci_tmf_function_codes code, + void (*tmf_sent_cb)(enum isci_tmf_cb_state, + struct isci_tmf *, + void *), + void *cb_data) { memset(tmf, 0, sizeof(*tmf)); @@ -416,16 +454,14 @@ void isci_task_build_tmf( tmf->cb_data = cb_data; } -static void isci_task_build_abort_task_tmf( - struct isci_tmf *tmf, - enum isci_tmf_function_codes code, - void (*tmf_sent_cb)(enum isci_tmf_cb_state, - struct isci_tmf *, - void *), - struct isci_request *old_request) +static void isci_task_build_abort_task_tmf(struct isci_tmf *tmf, + enum isci_tmf_function_codes code, + void (*tmf_sent_cb)(enum isci_tmf_cb_state, + struct isci_tmf *, + void *), + struct isci_request *old_request) { - isci_task_build_tmf(tmf, code, tmf_sent_cb, - (void *)old_request); + isci_task_build_tmf(tmf, code, tmf_sent_cb, old_request); tmf->io_tag = old_request->io_tag; } @@ -804,6 +840,30 @@ static int isci_task_send_lu_reset_sas( return ret; } +static int isci_task_send_lu_reset_sata(struct isci_host *ihost, + struct isci_remote_device *idev, u8 *lun) +{ + int ret = TMF_RESP_FUNC_FAILED; + struct isci_tmf tmf; + + /* Send the soft reset to the target */ + #define ISCI_SRST_TIMEOUT_MS 25000 /* 25 second timeout. */ + isci_task_build_tmf(&tmf, isci_tmf_sata_srst_high, NULL, NULL); + + ret = isci_task_execute_tmf(ihost, idev, &tmf, ISCI_SRST_TIMEOUT_MS); + + if (ret != TMF_RESP_FUNC_COMPLETE) { + dev_warn(&ihost->pdev->dev, + "%s: Assert SRST failed (%p) = %x", + __func__, idev, ret); + + /* Return the failure so that the LUN reset is escalated + * to a target reset. + */ + } + return ret; +} + /** * isci_task_lu_reset() - This function is one of the SAS Domain Template * functions. This is one of the Task Management functoins called by libsas, -- cgit v1.2.1 From a8a0a133b03c6863d0f77229d19befca4de905fa Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 1 Jul 2011 12:07:25 -0700 Subject: isci: pare back error messsages The messages emitted from task.c and some from request.c likely duplicate (in a less undertandable way) what is reported by the midlayer. Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 5d962b6b03eb..22504c7ef2dc 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -104,7 +104,7 @@ static void isci_task_refuse(struct isci_host *ihost, struct sas_task *task, /* No notification because this request is already in the * abort path. */ - dev_warn(&ihost->pdev->dev, + dev_dbg(&ihost->pdev->dev, "%s: Aborted - task = %p, response=%d, " "status=%d\n", __func__, task, response, status); @@ -112,7 +112,7 @@ static void isci_task_refuse(struct isci_host *ihost, struct sas_task *task, case isci_perform_error_io_completion: /* Use sas_task_abort */ - dev_warn(&ihost->pdev->dev, + dev_dbg(&ihost->pdev->dev, "%s: Error - task = %p, response=%d, " "status=%d\n", __func__, task, response, status); @@ -121,7 +121,7 @@ static void isci_task_refuse(struct isci_host *ihost, struct sas_task *task, break; default: - dev_warn(&ihost->pdev->dev, + dev_dbg(&ihost->pdev->dev, "%s: isci task notification default case!", __func__); sas_task_abort(task); @@ -374,7 +374,7 @@ static int isci_task_execute_tmf(struct isci_host *ihost, status = sci_controller_start_task(ihost, idev, ireq); if (status != SCI_TASK_SUCCESS) { - dev_warn(&ihost->pdev->dev, + dev_dbg(&ihost->pdev->dev, "%s: start_io failed - status = 0x%x, request = %p\n", __func__, status, @@ -604,7 +604,7 @@ static void isci_terminate_request_core(struct isci_host *ihost, * being aborted. */ if (status != SCI_SUCCESS) { - dev_err(&ihost->pdev->dev, + dev_dbg(&ihost->pdev->dev, "%s: sci_controller_terminate_request" " returned = 0x%x\n", __func__, status); @@ -662,7 +662,7 @@ static void isci_terminate_request_core(struct isci_host *ihost, if (!termination_completed) { - dev_err(&ihost->pdev->dev, + dev_dbg(&ihost->pdev->dev, "%s: *** Timeout waiting for " "termination(%p/%p)\n", __func__, io_request_completion, @@ -853,7 +853,7 @@ static int isci_task_send_lu_reset_sata(struct isci_host *ihost, ret = isci_task_execute_tmf(ihost, idev, &tmf, ISCI_SRST_TIMEOUT_MS); if (ret != TMF_RESP_FUNC_COMPLETE) { - dev_warn(&ihost->pdev->dev, + dev_dbg(&ihost->pdev->dev, "%s: Assert SRST failed (%p) = %x", __func__, idev, ret); @@ -897,7 +897,7 @@ int isci_task_lu_reset(struct domain_device *domain_device, u8 *lun) */ if (!isci_device || isci_device_is_reset_pending(isci_host, isci_device)) { - dev_warn(&isci_host->pdev->dev, + dev_dbg(&isci_host->pdev->dev, "%s: No dev (%p), or " "RESET PENDING: domain_device=%p\n", __func__, isci_device, domain_device); @@ -970,7 +970,7 @@ static void isci_abort_task_process_cb( */ if ((old_request->status != aborted) && (old_request->status != completed)) - dev_err(&old_request->isci_host->pdev->dev, + dev_dbg(&old_request->isci_host->pdev->dev, "%s: Bad request status (%d): tmf=%p, old_request=%p\n", __func__, old_request->status, tmf, old_request); break; @@ -988,7 +988,7 @@ static void isci_abort_task_process_cb( break; default: - dev_err(&old_request->isci_host->pdev->dev, + dev_dbg(&old_request->isci_host->pdev->dev, "%s: Bad cb_state (%d): tmf=%p, old_request=%p\n", __func__, cb_state, tmf, old_request); break; @@ -1046,7 +1046,7 @@ int isci_task_abort_task(struct sas_task *task) * SCSI error handler thread to escalate to LUN reset */ if (sas_protocol_ata(task->task_proto)) { - dev_warn(&isci_host->pdev->dev, + dev_dbg(&isci_host->pdev->dev, " task %p is for a STP/SATA device;" " returning TMF_RESP_FUNC_FAILED\n" " to cause a LUN reset...\n", task); @@ -1176,7 +1176,7 @@ int isci_task_abort_task(struct sas_task *task) ISCI_ABORT_TASK_TIMEOUT_MS); if (ret != TMF_RESP_FUNC_COMPLETE) - dev_err(&isci_host->pdev->dev, + dev_dbg(&isci_host->pdev->dev, "%s: isci_task_send_tmf failed\n", __func__); } @@ -1395,7 +1395,7 @@ static int isci_smp_execute_task(struct isci_host *ihost, if (res) { del_timer(&task->timer); - dev_err(&ihost->pdev->dev, + dev_dbg(&ihost->pdev->dev, "%s: executing SMP task failed:%d\n", __func__, res); goto ex_err; @@ -1404,12 +1404,12 @@ static int isci_smp_execute_task(struct isci_host *ihost, wait_for_completion(&task->completion); res = -ECOMM; if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) { - dev_err(&ihost->pdev->dev, + dev_dbg(&ihost->pdev->dev, "%s: smp task timed out or aborted\n", __func__); isci_task_abort_task(task); if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { - dev_err(&ihost->pdev->dev, + dev_dbg(&ihost->pdev->dev, "%s: SMP task aborted and not done\n", __func__); goto ex_err; @@ -1432,7 +1432,7 @@ static int isci_smp_execute_task(struct isci_host *ihost, res = -EMSGSIZE; break; } else { - dev_err(&ihost->pdev->dev, + dev_dbg(&ihost->pdev->dev, "%s: task to dev %016llx response: 0x%x " "status 0x%x\n", __func__, SAS_ADDR(dev->sas_addr), @@ -1526,7 +1526,7 @@ static void isci_wait_for_smp_phy_reset(struct isci_remote_device *idev, int phy tmo = deadline - jiffies; if (res) { - dev_warn(&ihost->pdev->dev, + dev_dbg(&ihost->pdev->dev, "%s: iteration %d, phase %d:" " SMP error=%d, time_remaining=%lu\n", __func__, iteration, phy_state, res, tmo); @@ -1578,7 +1578,7 @@ static int isci_reset_device(struct isci_host *ihost, if (status != SCI_SUCCESS) { spin_unlock_irqrestore(&ihost->scic_lock, flags); - dev_warn(&ihost->pdev->dev, + dev_dbg(&ihost->pdev->dev, "%s: sci_remote_device_reset(%p) returned %d!\n", __func__, idev, status); @@ -1619,7 +1619,7 @@ static int isci_reset_device(struct isci_host *ihost, } if (status != SCI_SUCCESS) { - dev_warn(&ihost->pdev->dev, + dev_dbg(&ihost->pdev->dev, "%s: sci_remote_device_reset_complete(%p) " "returned %d!\n", __func__, idev, status); } -- cgit v1.2.1 From bc6f387d3156702a0430585b93c04934254c0de1 Mon Sep 17 00:00:00 2001 From: Jeff Skirvin Date: Fri, 1 Jul 2011 13:03:44 -0700 Subject: isci: Device reset should request sas_phy_reset(phy, true) The hard_reset parameter passed to the LLDD in the direct-attached phy control case allows the LLDD to filter link failure events while the direct-attached device reset is executing. Signed-off-by: Jeff Skirvin Signed-off-by: Dan Williams --- drivers/scsi/isci/task.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 22504c7ef2dc..2df45c57fc60 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -1563,7 +1563,7 @@ static void isci_wait_for_smp_phy_reset(struct isci_remote_device *idev, int phy } static int isci_reset_device(struct isci_host *ihost, - struct isci_remote_device *idev, int hard_reset) + struct isci_remote_device *idev) { struct sas_phy *phy = sas_find_local_phy(idev->domain_dev); struct isci_port *iport = idev->isci_port; @@ -1593,7 +1593,7 @@ static int isci_reset_device(struct isci_host *ihost, if (!scsi_is_sas_phy_local(phy)) set_bit(IPORT_BCN_BLOCKED, &iport->flags); - rc = sas_phy_reset(phy, hard_reset); + rc = sas_phy_reset(phy, true); /* Terminate in-progress I/O now. */ isci_remote_device_nuke_requests(ihost, idev); @@ -1633,8 +1633,8 @@ int isci_task_I_T_nexus_reset(struct domain_device *dev) { struct isci_host *ihost = dev_to_ihost(dev); struct isci_remote_device *idev; - int ret, hard_reset = 1; unsigned long flags; + int ret; spin_lock_irqsave(&ihost->scic_lock, flags); idev = isci_lookup_device(dev); @@ -1645,10 +1645,7 @@ int isci_task_I_T_nexus_reset(struct domain_device *dev) goto out; } - if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) - hard_reset = 0; - - ret = isci_reset_device(ihost, idev, hard_reset); + ret = isci_reset_device(ihost, idev); out: isci_put_device(idev); return ret; @@ -1659,11 +1656,8 @@ int isci_bus_reset_handler(struct scsi_cmnd *cmd) struct domain_device *dev = sdev_to_domain_dev(cmd->device); struct isci_host *ihost = dev_to_ihost(dev); struct isci_remote_device *idev; - int ret, hard_reset = 1; unsigned long flags; - - if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) - hard_reset = 0; + int ret; spin_lock_irqsave(&ihost->scic_lock, flags); idev = isci_lookup_device(dev); @@ -1674,7 +1668,7 @@ int isci_bus_reset_handler(struct scsi_cmnd *cmd) goto out; } - ret = isci_reset_device(ihost, idev, hard_reset); + ret = isci_reset_device(ihost, idev); out: isci_put_device(idev); return ret; -- cgit v1.2.1 From a5ec7f86dc5432c44d8407a144e7617ec65da770 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sun, 3 Jul 2011 14:14:45 -0500 Subject: [SCSI] isci: fix checkpatch errors Signed-off-by: James Bottomley --- drivers/scsi/isci/task.c | 71 ++++++++++++++++++++++++------------------------ 1 file changed, 36 insertions(+), 35 deletions(-) (limited to 'drivers/scsi/isci/task.c') diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index 2df45c57fc60..d6bcdd013dc9 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -88,44 +88,45 @@ static void isci_task_refuse(struct isci_host *ihost, struct sas_task *task, * 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(&ihost->pdev->dev, - "%s: Normal - task = %p, response=%d, " - "status=%d\n", - __func__, task, response, status); + case isci_perform_normal_io_completion: + /* Normal notification (task_done) */ + dev_dbg(&ihost->pdev->dev, + "%s: Normal - task = %p, response=%d, " + "status=%d\n", + __func__, task, response, status); - task->lldd_task = NULL; + task->lldd_task = NULL; - isci_execpath_callback(ihost, task, task->task_done); - break; + isci_execpath_callback(ihost, task, task->task_done); + break; - case isci_perform_aborted_io_completion: - /* No notification because this request is already in the - * abort path. - */ - dev_dbg(&ihost->pdev->dev, - "%s: Aborted - task = %p, response=%d, " - "status=%d\n", - __func__, task, response, status); - break; + case isci_perform_aborted_io_completion: + /* + * No notification because this request is already in the + * abort path. + */ + dev_dbg(&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_dbg(&ihost->pdev->dev, - "%s: Error - task = %p, response=%d, " - "status=%d\n", - __func__, task, response, status); + case isci_perform_error_io_completion: + /* Use sas_task_abort */ + dev_dbg(&ihost->pdev->dev, + "%s: Error - task = %p, response=%d, " + "status=%d\n", + __func__, task, response, status); - isci_execpath_callback(ihost, task, sas_task_abort); - break; + isci_execpath_callback(ihost, task, sas_task_abort); + break; - default: - dev_dbg(&ihost->pdev->dev, - "%s: isci task notification default case!", - __func__); - sas_task_abort(task); - break; + default: + dev_dbg(&ihost->pdev->dev, + "%s: isci task notification default case!", + __func__); + sas_task_abort(task); + break; } } @@ -1056,7 +1057,7 @@ int isci_task_abort_task(struct sas_task *task) dev_dbg(&isci_host->pdev->dev, "%s: old_request == %p\n", __func__, old_request); - any_dev_reset = isci_device_is_reset_pending(isci_host,isci_device); + any_dev_reset = isci_device_is_reset_pending(isci_host, isci_device); spin_lock_irqsave(&task->task_state_lock, flags); @@ -1115,9 +1116,9 @@ int isci_task_abort_task(struct sas_task *task) __func__, task); } goto out; - } - else + } else { spin_unlock_irqrestore(&task->task_state_lock, flags); + } spin_lock_irqsave(&isci_host->scic_lock, flags); -- cgit v1.2.1