2011-07-02 22:56:22 -07:00
/*
* 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 <linux/completion.h>
2011-03-09 21:27:46 -08:00
# include <linux/irqflags.h>
2011-05-04 17:53:24 -07:00
# include "sas.h"
2011-06-21 12:16:33 -07:00
# include <scsi/libsas.h>
2011-04-22 19:18:03 -07:00
# include "remote_device.h"
# include "remote_node_context.h"
2011-07-02 22:56:22 -07:00
# include "isci.h"
# include "request.h"
# include "task.h"
2011-06-28 13:47:09 -07:00
# include "host.h"
2011-05-04 17:53:24 -07:00
2011-03-09 21:27:46 -08:00
/**
2011-03-11 10:13:51 -08:00
* 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 .
2011-03-09 21:27:46 -08:00
*
*/
2011-03-11 10:13:51 -08:00
static void isci_task_refuse ( struct isci_host * ihost , struct sas_task * task ,
enum service_response response ,
enum exec_status status )
2011-03-09 21:27:46 -08:00
{
2011-03-11 10:13:51 -08:00
enum isci_completion_selection disposition ;
2011-03-09 21:27:46 -08:00
2011-03-11 10:13:51 -08:00
disposition = isci_perform_normal_io_completion ;
disposition = isci_task_set_completion_status ( task , response , status ,
disposition ) ;
2011-03-09 21:27:46 -08:00
/* Tasks aborted specifically by a call to the lldd_abort_task
2011-03-11 10:13:51 -08:00
* function should not be completed to the host in the regular path .
*/
switch ( disposition ) {
2011-07-03 14:14:45 -05:00
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 ) ;
2011-03-09 21:27:46 -08:00
2011-07-03 14:14:45 -05:00
task - > lldd_task = NULL ;
2011-03-09 21:27:46 -08:00
2011-07-03 14:14:45 -05:00
isci_execpath_callback ( ihost , task , task - > task_done ) ;
break ;
2011-03-09 21:27:46 -08:00
2011-07-03 14:14:45 -05:00
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 ;
2011-03-09 21:27:46 -08:00
2011-07-03 14:14:45 -05:00
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 ) ;
2011-03-31 13:10:40 -07:00
2011-07-03 14:14:45 -05:00
isci_execpath_callback ( ihost , task , sas_task_abort ) ;
break ;
2011-03-09 21:27:46 -08:00
2011-07-03 14:14:45 -05:00
default :
dev_dbg ( & ihost - > pdev - > dev ,
" %s: isci task notification default case! " ,
__func__ ) ;
sas_task_abort ( task ) ;
break ;
2011-03-09 21:27:46 -08:00
}
}
2011-07-02 22:56:22 -07:00
2011-03-11 10:13:51 -08:00
# define for_each_sas_task(num, task) \
for ( ; num > 0 ; num - - , \
task = list_entry ( task - > list . next , struct sas_task , list ) )
2011-06-23 17:09:02 -07:00
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 ;
}
2011-07-02 22:56:22 -07:00
/**
* 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 )
{
2011-03-31 13:10:44 -07:00
struct isci_host * ihost = dev_to_ihost ( task - > dev ) ;
2011-06-13 17:39:44 -07:00
struct isci_remote_device * idev ;
2011-07-02 22:56:22 -07:00
unsigned long flags ;
2011-06-16 11:26:12 -07:00
bool io_ready ;
2011-06-28 13:47:09 -07:00
u16 tag ;
2011-07-02 22:56:22 -07:00
2011-03-11 10:13:51 -08:00
dev_dbg ( & ihost - > pdev - > dev , " %s: num=%d \n " , __func__ , num ) ;
2011-07-02 22:56:22 -07:00
2011-03-11 10:13:51 -08:00
for_each_sas_task ( num , task ) {
2011-06-28 13:47:09 -07:00
enum sci_status status = SCI_FAILURE ;
2011-06-13 17:39:44 -07:00
spin_lock_irqsave ( & ihost - > scic_lock , flags ) ;
idev = isci_lookup_device ( task - > dev ) ;
2011-06-23 17:09:02 -07:00
io_ready = isci_device_io_ready ( idev , task ) ;
2011-06-28 13:47:09 -07:00
tag = isci_alloc_tag ( ihost ) ;
2011-06-13 17:39:44 -07:00
spin_unlock_irqrestore ( & ihost - > scic_lock , flags ) ;
2011-07-02 22:56:22 -07:00
2011-06-16 11:26:12 -07:00
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 ) ;
2011-07-02 22:56:22 -07:00
2011-06-16 11:26:12 -07:00
if ( ! idev ) {
isci_task_refuse ( ihost , task , SAS_TASK_UNDELIVERED ,
SAS_DEVICE_UNKNOWN ) ;
2011-06-28 13:47:09 -07:00
} else if ( ! io_ready | | tag = = SCI_CONTROLLER_INVALID_IO_TAG ) {
2011-06-16 11:26:12 -07:00
/* Indicate QUEUE_FULL so that the scsi midlayer
* retries .
*/
isci_task_refuse ( ihost , task , SAS_TASK_COMPLETE ,
SAS_QUEUE_FULL ) ;
2011-03-08 19:22:07 -07:00
} else {
/* There is a device and it's ready for I/O. */
spin_lock_irqsave ( & task - > task_state_lock , flags ) ;
2011-07-02 22:56:22 -07:00
2011-03-08 19:22:07 -07:00
if ( task - > task_state_flags & SAS_TASK_STATE_ABORTED ) {
2011-06-16 11:26:12 -07:00
/* The I/O was aborted. */
2011-03-08 19:22:07 -07:00
spin_unlock_irqrestore ( & task - > task_state_lock ,
flags ) ;
2011-07-02 22:56:22 -07:00
2011-03-11 10:13:51 -08:00
isci_task_refuse ( ihost , task ,
SAS_TASK_UNDELIVERED ,
SAM_STAT_TASK_ABORTED ) ;
2011-03-08 19:22:07 -07:00
} else {
2011-07-02 22:56:22 -07:00
task - > task_state_flags | = SAS_TASK_AT_INITIATOR ;
spin_unlock_irqrestore ( & task - > task_state_lock , flags ) ;
2011-03-08 19:22:07 -07:00
/* build and send the request. */
2011-06-17 14:18:39 -07:00
status = isci_request_execute ( ihost , idev , task , tag ) ;
2011-03-08 19:22:07 -07:00
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 ) ;
2011-10-27 15:04:56 -07:00
if ( test_bit ( IDEV_GONE , & idev - > flags ) ) {
/* Indicate that the device
* is gone .
*/
isci_task_refuse ( ihost , task ,
SAS_TASK_UNDELIVERED ,
SAS_DEVICE_UNKNOWN ) ;
} 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_refuse ( ihost , task ,
SAS_TASK_COMPLETE ,
SAS_QUEUE_FULL ) ;
}
2011-03-08 19:22:07 -07:00
}
2011-07-02 22:56:22 -07:00
}
}
2011-06-28 13:47:09 -07:00
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 ) ;
}
2011-06-13 17:39:44 -07:00
isci_put_device ( idev ) ;
2011-03-11 10:13:51 -08:00
}
2011-07-02 22:56:22 -07:00
return 0 ;
}
2011-07-01 10:52:55 -07:00
static enum sci_status isci_sata_management_task_request_build ( struct isci_request * ireq )
{
struct isci_tmf * isci_tmf ;
enum sci_status status ;
2011-10-27 15:05:22 -07:00
if ( ! test_bit ( IREQ_TMF , & ireq - > flags ) )
2011-07-01 10:52:55 -07:00
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 ;
}
2011-06-13 00:51:30 -07:00
static struct isci_request * isci_task_request_build ( struct isci_host * ihost ,
2011-06-13 17:39:44 -07:00
struct isci_remote_device * idev ,
2011-06-28 13:47:09 -07:00
u16 tag , struct isci_tmf * isci_tmf )
2011-07-02 22:56:22 -07:00
{
enum sci_status status = SCI_FAILURE ;
2011-06-13 00:51:30 -07:00
struct isci_request * ireq = NULL ;
2011-04-21 18:44:45 -07:00
struct domain_device * dev ;
2011-07-02 22:56:22 -07:00
2011-06-13 00:51:30 -07:00
dev_dbg ( & ihost - > pdev - > dev ,
2011-07-02 22:56:22 -07:00
" %s: isci_tmf = %p \n " , __func__ , isci_tmf ) ;
2011-06-13 00:51:30 -07:00
dev = idev - > domain_dev ;
2011-07-02 22:56:22 -07:00
/* do common allocation and init of request object. */
2011-06-17 14:18:39 -07:00
ireq = isci_tmf_request_from_tag ( ihost , isci_tmf , tag ) ;
2011-06-13 00:51:30 -07:00
if ( ! ireq )
return NULL ;
2011-07-02 22:56:22 -07:00
/* let the core do it's construct. */
2011-06-30 19:14:33 -07:00
status = sci_task_request_construct ( ihost , idev , tag ,
2011-06-27 14:57:03 -07:00
ireq ) ;
2011-07-02 22:56:22 -07:00
if ( status ! = SCI_SUCCESS ) {
2011-06-13 00:51:30 -07:00
dev_warn ( & ihost - > pdev - > dev ,
2011-06-30 19:14:33 -07:00
" %s: sci_task_request_construct failed - "
2011-07-02 22:56:22 -07:00
" status = 0x%x \n " ,
__func__ ,
status ) ;
2011-06-17 14:18:39 -07:00
return NULL ;
2011-07-02 22:56:22 -07:00
}
2011-04-21 18:44:45 -07:00
/* XXX convert to get this from task->tproto like other drivers */
if ( dev - > dev_type = = SAS_END_DEV ) {
2011-07-02 22:56:22 -07:00
isci_tmf - > proto = SAS_PROTOCOL_SSP ;
2011-06-30 19:14:33 -07:00
status = sci_task_request_construct_ssp ( ireq ) ;
2011-07-02 22:56:22 -07:00
if ( status ! = SCI_SUCCESS )
2011-06-17 14:18:39 -07:00
return NULL ;
2011-07-02 22:56:22 -07:00
}
2011-04-21 18:44:45 -07:00
if ( dev - > dev_type = = SATA_DEV | | ( dev - > tproto & SAS_PROTOCOL_STP ) ) {
2011-07-02 22:56:22 -07:00
isci_tmf - > proto = SAS_PROTOCOL_SATA ;
2011-06-13 00:51:30 -07:00
status = isci_sata_management_task_request_build ( ireq ) ;
2011-07-02 22:56:22 -07:00
if ( status ! = SCI_SUCCESS )
2011-06-17 14:18:39 -07:00
return NULL ;
2011-07-02 22:56:22 -07:00
}
2011-06-13 00:51:30 -07:00
return ireq ;
2011-07-02 22:56:22 -07:00
}
2011-10-27 15:05:06 -07:00
/**
* isci_request_mark_zombie ( ) - This function must be called with scic_lock held .
*/
static void isci_request_mark_zombie ( struct isci_host * ihost , struct isci_request * ireq )
{
struct completion * tmf_completion = NULL ;
struct completion * req_completion ;
/* Set the request state to "dead". */
ireq - > status = dead ;
req_completion = ireq - > io_request_completion ;
ireq - > io_request_completion = NULL ;
2011-10-27 15:05:22 -07:00
if ( test_bit ( IREQ_TMF , & ireq - > flags ) ) {
2011-10-27 15:05:06 -07:00
/* Break links with the TMF request. */
struct isci_tmf * tmf = isci_request_access_tmf ( ireq ) ;
/* In the case where a task request is dying,
* the thread waiting on the complete will sit and
* timeout unless we wake it now . Since the TMF
* has a default error status , complete it here
* to wake the waiting thread .
*/
if ( tmf ) {
tmf_completion = tmf - > complete ;
tmf - > complete = NULL ;
}
ireq - > ttype_ptr . tmf_task_ptr = NULL ;
dev_dbg ( & ihost - > pdev - > dev , " %s: tmf_code %d, managed tag %#x \n " ,
__func__ , tmf - > tmf_code , tmf - > io_tag ) ;
2011-10-27 15:05:22 -07:00
} else {
/* Break links with the sas_task - the callback is done
* elsewhere .
*/
struct sas_task * task = isci_request_access_task ( ireq ) ;
if ( task )
task - > lldd_task = NULL ;
ireq - > ttype_ptr . io_task_ptr = NULL ;
2011-10-27 15:05:06 -07:00
}
dev_warn ( & ihost - > pdev - > dev , " task context unrecoverable (tag: %#x) \n " ,
ireq - > io_tag ) ;
/* Don't force waiting threads to timeout. */
if ( req_completion )
complete ( req_completion ) ;
if ( tmf_completion ! = NULL )
complete ( tmf_completion ) ;
}
2011-07-01 10:52:55 -07:00
static int isci_task_execute_tmf ( struct isci_host * ihost ,
struct isci_remote_device * idev ,
struct isci_tmf * tmf , unsigned long timeout_ms )
2011-07-02 22:56:22 -07:00
{
DECLARE_COMPLETION_ONSTACK ( completion ) ;
2011-04-12 17:28:41 -07:00
enum sci_task_status status = SCI_TASK_FAILURE ;
2011-06-13 00:51:30 -07:00
struct isci_request * ireq ;
2011-07-02 22:56:22 -07:00
int ret = TMF_RESP_FUNC_FAILED ;
unsigned long flags ;
2011-05-19 12:00:15 +00:00
unsigned long timeleft ;
2011-06-28 13:47:09 -07:00
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 ;
2011-07-02 22:56:22 -07:00
/* sanity check, return TMF_RESP_FUNC_FAILED
* if the device is not there and ready .
*/
2011-06-30 16:31:37 -07:00
if ( ! idev | |
( ! test_bit ( IDEV_IO_READY , & idev - > flags ) & &
! test_bit ( IDEV_IO_NCQERROR , & idev - > flags ) ) ) {
2011-06-13 00:51:30 -07:00
dev_dbg ( & ihost - > pdev - > dev ,
2011-06-30 16:31:37 -07:00
" %s: idev = %p not ready (%#lx) \n " ,
2011-07-02 22:56:22 -07:00
__func__ ,
2011-06-30 16:31:37 -07:00
idev , idev ? idev - > flags : 0 ) ;
2011-06-28 13:47:09 -07:00
goto err_tci ;
2011-07-02 22:56:22 -07:00
} else
2011-06-13 00:51:30 -07:00
dev_dbg ( & ihost - > pdev - > dev ,
2011-06-30 16:31:37 -07:00
" %s: idev = %p \n " ,
__func__ , idev ) ;
2011-07-02 22:56:22 -07:00
/* Assign the pointer to the TMF's completion kernel wait structure. */
tmf - > complete = & completion ;
2011-10-27 15:05:06 -07:00
tmf - > status = SCI_FAILURE_TIMEOUT ;
2011-07-02 22:56:22 -07:00
2011-06-30 16:31:37 -07:00
ireq = isci_task_request_build ( ihost , idev , tag , tmf ) ;
2011-06-28 13:47:09 -07:00
if ( ! ireq )
goto err_tci ;
2011-07-02 22:56:22 -07:00
2011-06-13 00:51:30 -07:00
spin_lock_irqsave ( & ihost - > scic_lock , flags ) ;
2011-07-02 22:56:22 -07:00
/* start the TMF io. */
2011-06-30 19:14:33 -07:00
status = sci_controller_start_task ( ihost , idev , ireq ) ;
2011-07-02 22:56:22 -07:00
2011-04-12 17:28:41 -07:00
if ( status ! = SCI_TASK_SUCCESS ) {
2011-07-01 12:07:25 -07:00
dev_dbg ( & ihost - > pdev - > dev ,
2011-07-02 22:56:22 -07:00
" %s: start_io failed - status = 0x%x, request = %p \n " ,
__func__ ,
status ,
2011-06-13 00:51:30 -07:00
ireq ) ;
spin_unlock_irqrestore ( & ihost - > scic_lock , flags ) ;
2011-06-17 14:18:39 -07:00
goto err_tci ;
2011-07-02 22:56:22 -07:00
}
if ( tmf - > cb_state_func ! = NULL )
tmf - > cb_state_func ( isci_tmf_started , tmf , tmf - > cb_data ) ;
2011-06-13 00:51:30 -07:00
isci_request_change_state ( ireq , started ) ;
2011-07-02 22:56:22 -07:00
/* add the request to the remote device request list. */
2011-06-30 16:31:37 -07:00
list_add ( & ireq - > dev_node , & idev - > reqs_in_process ) ;
2011-07-02 22:56:22 -07:00
2011-06-13 00:51:30 -07:00
spin_unlock_irqrestore ( & ihost - > scic_lock , flags ) ;
2011-07-02 22:56:22 -07:00
/* Wait for the TMF to complete, or a timeout. */
2011-05-19 12:00:15 +00:00
timeleft = wait_for_completion_timeout ( & completion ,
2011-06-21 16:23:03 -07:00
msecs_to_jiffies ( timeout_ms ) ) ;
2011-05-19 12:00:15 +00:00
if ( timeleft = = 0 ) {
2011-10-27 15:05:06 -07:00
/* The TMF did not complete - this could be because
* of an unplug . Terminate the TMF request now .
*/
2011-06-13 00:51:30 -07:00
spin_lock_irqsave ( & ihost - > scic_lock , flags ) ;
2011-05-19 12:00:15 +00:00
if ( tmf - > cb_state_func ! = NULL )
2011-10-27 15:05:06 -07:00
tmf - > cb_state_func ( isci_tmf_timed_out , tmf ,
tmf - > cb_data ) ;
2011-05-19 12:00:15 +00:00
2011-10-27 15:05:06 -07:00
sci_controller_terminate_request ( ihost , idev , ireq ) ;
2011-05-19 12:00:15 +00:00
2011-06-13 00:51:30 -07:00
spin_unlock_irqrestore ( & ihost - > scic_lock , flags ) ;
2011-06-21 16:23:03 -07:00
2011-10-27 15:05:06 -07:00
timeleft = wait_for_completion_timeout (
& completion ,
msecs_to_jiffies ( ISCI_TERMINATION_TIMEOUT_MSEC ) ) ;
if ( ! timeleft ) {
/* Strange condition - the termination of the TMF
* request timed - out .
*/
spin_lock_irqsave ( & ihost - > scic_lock , flags ) ;
/* If the TMF status has not changed, kill it. */
if ( tmf - > status = = SCI_FAILURE_TIMEOUT )
isci_request_mark_zombie ( ihost , ireq ) ;
spin_unlock_irqrestore ( & ihost - > scic_lock , flags ) ;
}
2011-05-19 12:00:15 +00:00
}
2011-07-02 22:56:22 -07:00
2012-01-04 01:33:05 -08:00
isci_print_tmf ( ihost , tmf ) ;
2011-07-02 22:56:22 -07:00
if ( tmf - > status = = SCI_SUCCESS )
ret = TMF_RESP_FUNC_COMPLETE ;
else if ( tmf - > status = = SCI_FAILURE_IO_RESPONSE_VALID ) {
2011-06-13 00:51:30 -07:00
dev_dbg ( & ihost - > pdev - > dev ,
2011-07-02 22:56:22 -07:00
" %s: tmf.status == "
" SCI_FAILURE_IO_RESPONSE_VALID \n " ,
__func__ ) ;
ret = TMF_RESP_FUNC_COMPLETE ;
}
/* Else - leave the default "failed" status alone. */
2011-06-13 00:51:30 -07:00
dev_dbg ( & ihost - > pdev - > dev ,
2011-07-02 22:56:22 -07:00
" %s: completed request = %p \n " ,
__func__ ,
2011-06-13 00:51:30 -07:00
ireq ) ;
2011-07-02 22:56:22 -07:00
return ret ;
2011-06-28 13:47:09 -07:00
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 ;
2011-07-02 22:56:22 -07:00
}
2011-07-01 10:52:55 -07:00
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 )
2011-07-02 22:56:22 -07:00
{
memset ( tmf , 0 , sizeof ( * tmf ) ) ;
tmf - > tmf_code = code ;
tmf - > cb_state_func = tmf_sent_cb ;
2011-03-04 14:06:56 -08:00
tmf - > cb_data = cb_data ;
}
2011-03-04 14:06:46 -08:00
2011-07-01 10:52:55 -07:00
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 )
2011-03-04 14:06:56 -08:00
{
2011-07-01 10:52:55 -07:00
isci_task_build_tmf ( tmf , code , tmf_sent_cb , old_request ) ;
2011-03-04 14:06:56 -08:00
tmf - > io_tag = old_request - > io_tag ;
2011-07-02 22:56:22 -07:00
}
/**
* 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 ) ;
}
return old_state ;
}
2011-10-27 15:05:01 -07:00
static int isci_request_is_dealloc_managed ( enum isci_request_status stat )
{
switch ( stat ) {
case aborted :
case aborting :
case terminating :
case completed :
case dead :
return true ;
default :
return false ;
}
}
2011-07-02 22:56:22 -07:00
/**
* 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 ) .
2011-06-30 17:38:32 -07:00
* @ ihost : This SCU .
2011-06-30 16:31:37 -07:00
* @ idev : The target .
2011-07-02 22:56:22 -07:00
* @ isci_request : The I / O request to be terminated .
*
*/
2011-06-30 17:38:32 -07:00
static void isci_terminate_request_core ( struct isci_host * ihost ,
struct isci_remote_device * idev ,
struct isci_request * isci_request )
2011-07-02 22:56:22 -07:00
{
2011-03-04 14:06:50 -08:00
enum sci_status status = SCI_SUCCESS ;
2011-07-02 22:56:22 -07:00
bool was_terminated = false ;
bool needs_cleanup_handling = false ;
2011-06-20 14:09:16 -07:00
unsigned long flags ;
unsigned long termination_completed = 1 ;
struct completion * io_request_completion ;
2011-07-02 22:56:22 -07:00
2011-06-30 17:38:32 -07:00
dev_dbg ( & ihost - > pdev - > dev ,
2011-07-02 22:56:22 -07:00
" %s: device = %p; request = %p \n " ,
2011-06-30 16:31:37 -07:00
__func__ , idev , isci_request ) ;
2011-07-02 22:56:22 -07:00
2011-06-30 17:38:32 -07:00
spin_lock_irqsave ( & ihost - > scic_lock , flags ) ;
2011-03-04 14:06:52 -08:00
2011-06-20 14:09:16 -07:00
io_request_completion = isci_request - > io_request_completion ;
2011-03-04 14:06:52 -08:00
/* Note that we are not going to control
2011-06-23 14:33:48 -07:00
* the target to abort the request .
*/
set_bit ( IREQ_COMPLETE_IN_TARGET , & isci_request - > flags ) ;
2011-03-04 14:06:52 -08:00
2011-07-02 22:56:22 -07:00
/* 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 ) .
*/
2011-06-23 14:33:48 -07:00
if ( ! test_bit ( IREQ_TERMINATED , & isci_request - > flags ) ) {
2011-07-02 22:56:22 -07:00
was_terminated = true ;
2011-03-04 14:06:50 -08:00
needs_cleanup_handling = true ;
2011-06-30 19:14:33 -07:00
status = sci_controller_terminate_request ( ihost ,
2011-06-30 17:38:32 -07:00
idev ,
isci_request ) ;
2011-07-02 22:56:22 -07:00
}
2011-06-30 17:38:32 -07:00
spin_unlock_irqrestore ( & ihost - > scic_lock , flags ) ;
2011-07-02 22:56:22 -07:00
/*
* The only time the request to terminate will
* fail is when the io request is completed and
* being aborted .
*/
2011-03-04 14:06:52 -08:00
if ( status ! = SCI_SUCCESS ) {
2011-07-01 12:07:25 -07:00
dev_dbg ( & ihost - > pdev - > dev ,
2011-06-30 19:14:33 -07:00
" %s: sci_controller_terminate_request "
2011-07-02 22:56:22 -07:00
" returned = 0x%x \n " ,
2011-06-20 14:09:16 -07:00
__func__ , status ) ;
2011-03-04 14:06:52 -08:00
isci_request - > io_request_completion = NULL ;
} else {
2011-07-02 22:56:22 -07:00
if ( was_terminated ) {
2011-06-30 17:38:32 -07:00
dev_dbg ( & ihost - > pdev - > dev ,
2011-06-20 14:09:16 -07:00
" %s: before completion wait (%p/%p) \n " ,
__func__ , isci_request , io_request_completion ) ;
2011-07-02 22:56:22 -07:00
/* Wait here for the request to complete. */
2011-06-20 14:09:16 -07:00
termination_completed
2011-03-04 14:06:52 -08:00
= wait_for_completion_timeout (
2011-06-20 14:09:16 -07:00
io_request_completion ,
2011-10-27 15:05:06 -07:00
msecs_to_jiffies ( ISCI_TERMINATION_TIMEOUT_MSEC ) ) ;
2011-03-04 14:06:52 -08:00
2011-06-20 14:09:16 -07:00
if ( ! termination_completed ) {
/* The request to terminate has timed out. */
2011-10-27 15:05:06 -07:00
spin_lock_irqsave ( & ihost - > scic_lock , flags ) ;
2011-06-20 14:09:16 -07:00
/* Check for state changes. */
2011-10-27 15:05:06 -07:00
if ( ! test_bit ( IREQ_TERMINATED ,
& isci_request - > flags ) ) {
2011-06-20 14:09:16 -07:00
/* The best we can do is to have the
* request die a silent death if it
* ever really completes .
*/
2011-10-27 15:05:06 -07:00
isci_request_mark_zombie ( ihost ,
isci_request ) ;
needs_cleanup_handling = true ;
2011-06-20 14:09:16 -07:00
} else
termination_completed = 1 ;
2011-06-30 17:38:32 -07:00
spin_unlock_irqrestore ( & ihost - > scic_lock ,
2011-06-20 14:09:16 -07:00
flags ) ;
2011-03-04 14:06:52 -08:00
2011-06-20 14:09:16 -07:00
if ( ! termination_completed ) {
2011-03-04 14:06:52 -08:00
2011-07-01 12:07:25 -07:00
dev_dbg ( & ihost - > pdev - > dev ,
2011-06-20 14:09:16 -07:00
" %s: *** Timeout waiting for "
" termination(%p/%p) \n " ,
__func__ , io_request_completion ,
isci_request ) ;
2011-03-04 14:06:52 -08:00
2011-06-20 14:09:16 -07:00
/* 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 )
2011-06-30 17:38:32 -07:00
dev_dbg ( & ihost - > pdev - > dev ,
2011-06-20 14:09:16 -07:00
" %s: after completion wait (%p/%p) \n " ,
__func__ , isci_request , io_request_completion ) ;
2011-03-04 14:06:52 -08:00
}
2011-06-20 14:09:16 -07:00
if ( termination_completed ) {
2011-03-04 14:06:50 -08:00
2011-06-20 14:09:16 -07:00
isci_request - > io_request_completion = NULL ;
2011-07-02 22:56:22 -07:00
2011-06-20 14:09:16 -07:00
/* 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 ) ;
2011-10-27 15:05:01 -07:00
needs_cleanup_handling
= isci_request_is_dealloc_managed (
isci_request - > status ) ;
2011-06-20 14:09:16 -07:00
spin_unlock_irqrestore ( & isci_request - > state_lock , flags ) ;
2011-07-02 22:56:22 -07:00
2011-06-20 14:09:16 -07:00
}
2011-10-27 15:05:11 -07:00
if ( needs_cleanup_handling ) {
dev_dbg ( & ihost - > pdev - > dev ,
" %s: cleanup isci_device=%p, request=%p \n " ,
__func__ , idev , isci_request ) ;
if ( isci_request ! = NULL ) {
spin_lock_irqsave ( & ihost - > scic_lock , flags ) ;
isci_free_tag ( ihost , isci_request - > io_tag ) ;
isci_request_change_state ( isci_request , unallocated ) ;
list_del_init ( & isci_request - > dev_node ) ;
spin_unlock_irqrestore ( & ihost - > scic_lock , flags ) ;
}
}
2011-03-04 14:06:42 -08:00
}
2011-07-02 22:56:22 -07:00
}
/**
* 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 .
2011-06-30 16:31:37 -07:00
* @ idev : This parameter specifies the target .
2011-07-02 22:56:22 -07:00
*
*/
2011-06-20 15:11:22 -07:00
void isci_terminate_pending_requests ( struct isci_host * ihost ,
struct isci_remote_device * idev )
2011-07-02 22:56:22 -07:00
{
2011-06-20 15:11:22 -07:00
struct completion request_completion ;
2011-06-20 14:09:16 -07:00
enum isci_request_status old_state ;
2011-06-20 15:11:22 -07:00
unsigned long flags ;
LIST_HEAD ( list ) ;
2011-07-02 22:56:22 -07:00
2011-06-20 15:11:22 -07:00
spin_lock_irqsave ( & ihost - > scic_lock , flags ) ;
list_splice_init ( & idev - > reqs_in_process , & list ) ;
2011-07-02 22:56:22 -07:00
2011-06-20 15:11:22 -07:00
/* 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 ) ;
2011-07-02 22:56:22 -07:00
2011-06-20 15:11:22 -07:00
/* 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 ;
}
2011-03-04 14:06:52 -08:00
2011-06-20 15:11:22 -07:00
if ( ! ireq )
continue ;
spin_unlock_irqrestore ( & ihost - > scic_lock , flags ) ;
2011-06-20 14:09:16 -07:00
2011-06-20 15:11:22 -07:00
init_completion ( & request_completion ) ;
2011-06-20 14:09:16 -07:00
2011-06-20 15:11:22 -07:00
dev_dbg ( & ihost - > pdev - > dev ,
" %s: idev=%p request=%p; task=%p old_state=%d \n " ,
__func__ , idev , ireq ,
2011-10-27 15:05:22 -07:00
( ! test_bit ( IREQ_TMF , & ireq - > flags )
? isci_request_access_task ( ireq )
: NULL ) ,
2011-06-20 15:11:22 -07:00
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 ) ;
2011-03-04 14:06:52 -08:00
}
2011-06-20 15:11:22 -07:00
spin_unlock_irqrestore ( & ihost - > scic_lock , flags ) ;
2011-07-02 22:56:22 -07:00
}
/**
* 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 " ) .
*/
2011-06-13 17:39:44 -07:00
isci_task_build_tmf ( & tmf , isci_tmf_ssp_lun_reset , NULL , NULL ) ;
2011-07-02 22:56:22 -07:00
# define ISCI_LU_RESET_TIMEOUT_MS 2000 /* 2 second timeout. */
2011-06-13 17:39:44 -07:00
ret = isci_task_execute_tmf ( isci_host , isci_device , & tmf , ISCI_LU_RESET_TIMEOUT_MS ) ;
2011-07-02 22:56:22 -07:00
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 ;
}
2011-07-01 10:52:55 -07:00
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 ) {
2011-07-01 12:07:25 -07:00
dev_dbg ( & ihost - > pdev - > dev ,
2011-07-01 10:52:55 -07:00
" %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 ;
}
2011-07-02 22:56:22 -07:00
/**
* 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 .
*/
2011-03-31 13:10:44 -07:00
int isci_task_lu_reset ( struct domain_device * domain_device , u8 * lun )
2011-07-02 22:56:22 -07:00
{
2011-03-31 13:10:44 -07:00
struct isci_host * isci_host = dev_to_ihost ( domain_device ) ;
2011-06-13 17:39:44 -07:00
struct isci_remote_device * isci_device ;
unsigned long flags ;
2011-07-02 22:56:22 -07:00
int ret ;
2011-06-13 17:39:44 -07:00
spin_lock_irqsave ( & isci_host - > scic_lock , flags ) ;
isci_device = isci_lookup_device ( domain_device ) ;
spin_unlock_irqrestore ( & isci_host - > scic_lock , flags ) ;
2011-07-02 22:56:22 -07:00
2011-03-31 13:10:44 -07:00
dev_dbg ( & isci_host - > pdev - > dev ,
" %s: domain_device=%p, isci_host=%p; isci_device=%p \n " ,
2011-07-02 22:56:22 -07:00
__func__ , domain_device , isci_host , isci_device ) ;
2011-10-27 15:05:16 -07:00
if ( ! isci_device ) {
/* If the device is gone, stop the escalations. */
dev_dbg ( & isci_host - > pdev - > dev , " %s: No dev \n " , __func__ ) ;
2011-07-02 22:56:22 -07:00
2011-10-27 15:05:16 -07:00
ret = TMF_RESP_FUNC_COMPLETE ;
2011-06-13 17:39:44 -07:00
goto out ;
2011-07-02 22:56:22 -07:00
}
2011-10-27 15:05:16 -07:00
set_bit ( IDEV_EH , & isci_device - > flags ) ;
2011-07-02 22:56:22 -07:00
/* Send the task management part of the reset. */
if ( sas_protocol_ata ( domain_device - > tproto ) ) {
2011-03-31 13:10:44 -07:00
ret = isci_task_send_lu_reset_sata ( isci_host , isci_device , lun ) ;
2011-07-02 22:56:22 -07:00
} 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 ,
2011-06-20 15:11:22 -07:00
isci_device ) ;
2011-07-02 22:56:22 -07:00
2011-06-13 17:39:44 -07:00
out :
isci_put_device ( isci_device ) ;
2011-07-02 22:56:22 -07:00
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 ;
}
/* 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 .
*/
2011-04-12 17:28:43 -07:00
if ( ( old_request - > status ! = aborted )
& & ( old_request - > status ! = completed ) )
2011-07-01 12:07:25 -07:00
dev_dbg ( & old_request - > isci_host - > pdev - > dev ,
2011-04-12 17:28:43 -07:00
" %s: Bad request status (%d): tmf=%p, old_request=%p \n " ,
__func__ , old_request - > status , tmf , old_request ) ;
2011-07-02 22:56:22 -07:00
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 :
2011-07-01 12:07:25 -07:00
dev_dbg ( & old_request - > isci_host - > pdev - > dev ,
2011-07-02 22:56:22 -07:00
" %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 )
{
2011-03-31 13:10:44 -07:00
struct isci_host * isci_host = dev_to_ihost ( task - > dev ) ;
2011-07-02 22:56:22 -07:00
DECLARE_COMPLETION_ONSTACK ( aborted_io_completion ) ;
2011-03-04 14:06:42 -08:00
struct isci_request * old_request = NULL ;
enum isci_request_status old_state ;
2011-07-02 22:56:22 -07:00
struct isci_remote_device * isci_device = NULL ;
2011-03-04 14:06:42 -08:00
struct isci_tmf tmf ;
int ret = TMF_RESP_FUNC_FAILED ;
unsigned long flags ;
2011-10-27 15:05:16 -07:00
int perform_termination = 0 ;
2011-07-02 22:56:22 -07:00
/* 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 .
*/
2011-06-13 17:39:44 -07:00
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 ) ;
2011-07-02 22:56:22 -07:00
dev_dbg ( & isci_host - > pdev - > dev ,
2011-10-27 15:05:16 -07:00
" %s: dev = %p, task = %p, old_request == %p \n " ,
__func__ , isci_device , task , old_request ) ;
2011-07-02 22:56:22 -07:00
2011-10-27 15:05:16 -07:00
if ( isci_device )
set_bit ( IDEV_EH , & isci_device - > flags ) ;
2011-07-02 22:56:22 -07:00
2011-10-27 15:05:16 -07:00
/* Device reset conditions signalled in task_state_flags are the
* responsbility of libsas to observe at the start of the error
* handler thread .
2011-07-02 22:56:22 -07:00
*/
2011-10-27 15:05:16 -07:00
if ( ! isci_device | | ! old_request ) {
/* 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 .
*/
spin_lock_irqsave ( & task - > task_state_lock , flags ) ;
task - > task_state_flags | = SAS_TASK_STATE_DONE ;
task - > task_state_flags & = ~ ( SAS_TASK_AT_INITIATOR |
SAS_TASK_STATE_PENDING ) ;
spin_unlock_irqrestore ( & task - > task_state_lock , flags ) ;
2011-07-02 22:56:22 -07:00
2011-10-27 15:05:16 -07:00
ret = TMF_RESP_FUNC_COMPLETE ;
2011-07-02 22:56:22 -07:00
2011-10-27 15:05:16 -07:00
dev_dbg ( & isci_host - > pdev - > dev ,
" %s: abort task not needed for %p \n " ,
__func__ , task ) ;
2011-06-13 17:39:44 -07:00
goto out ;
2011-07-03 14:14:45 -05:00
}
2011-07-02 22:56:22 -07:00
spin_lock_irqsave ( & isci_host - > scic_lock , flags ) ;
2011-03-31 13:10:34 -07:00
/* Check the request status and change to "aborted" if currently
2011-03-04 14:06:42 -08:00
* " starting " ; if true then set the I / O kernel completion
2011-07-02 22:56:22 -07:00
* struct that will be triggered when the request completes .
*/
2011-03-04 14:06:42 -08:00
old_state = isci_task_validate_request_to_abort (
old_request , isci_host , isci_device ,
& aborted_io_completion ) ;
2011-03-31 13:10:34 -07:00
if ( ( old_state ! = started ) & &
( old_state ! = completed ) & &
( old_state ! = aborting ) ) {
2011-07-02 22:56:22 -07:00
spin_unlock_irqrestore ( & isci_host - > scic_lock , flags ) ;
2011-03-04 14:06:42 -08:00
/* 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 ) ;
2011-06-13 17:39:44 -07:00
ret = TMF_RESP_FUNC_COMPLETE ;
goto out ;
2011-07-02 22:56:22 -07:00
}
2011-06-23 14:33:48 -07:00
if ( task - > task_proto = = SAS_PROTOCOL_SMP | |
2011-10-27 15:05:16 -07:00
sas_protocol_ata ( task - > task_proto ) | |
2011-06-23 14:33:48 -07:00
test_bit ( IREQ_COMPLETE_IN_TARGET , & old_request - > flags ) ) {
2011-07-02 22:56:22 -07:00
spin_unlock_irqrestore ( & isci_host - > scic_lock , flags ) ;
2011-03-04 14:06:42 -08:00
dev_dbg ( & isci_host - > pdev - > dev ,
2011-10-27 15:05:16 -07:00
" %s: %s request "
2011-03-04 14:06:42 -08:00
" or complete_in_target (%d), thus no TMF \n " ,
2011-10-27 15:05:16 -07:00
__func__ ,
( ( task - > task_proto = = SAS_PROTOCOL_SMP )
? " SMP "
: ( sas_protocol_ata ( task - > task_proto )
? " SATA/STP "
: " <other> " )
) ,
2011-06-23 14:33:48 -07:00
test_bit ( IREQ_COMPLETE_IN_TARGET , & old_request - > flags ) ) ;
2011-03-04 14:06:42 -08:00
2011-10-27 15:05:16 -07:00
if ( test_bit ( IREQ_COMPLETE_IN_TARGET , & old_request - > flags ) ) {
spin_lock_irqsave ( & task - > task_state_lock , flags ) ;
task - > task_state_flags | = SAS_TASK_STATE_DONE ;
task - > task_state_flags & = ~ ( SAS_TASK_AT_INITIATOR |
SAS_TASK_STATE_PENDING ) ;
spin_unlock_irqrestore ( & task - > task_state_lock , flags ) ;
ret = TMF_RESP_FUNC_COMPLETE ;
} else {
spin_lock_irqsave ( & task - > task_state_lock , flags ) ;
task - > task_state_flags & = ~ ( SAS_TASK_AT_INITIATOR |
SAS_TASK_STATE_PENDING ) ;
spin_unlock_irqrestore ( & task - > task_state_lock , flags ) ;
}
2011-07-02 22:56:22 -07:00
2011-10-27 15:05:16 -07:00
/* STP and SMP devices are not sent a TMF, but the
* outstanding I / O request is terminated below . This is
* because SATA / STP and SMP discovery path timeouts directly
* call the abort task interface for cleanup .
2011-07-02 22:56:22 -07:00
*/
2011-10-27 15:05:16 -07:00
perform_termination = 1 ;
2011-07-02 22:56:22 -07:00
} else {
/* Fill in the tmf stucture */
2011-06-13 17:39:44 -07:00
isci_task_build_abort_task_tmf ( & tmf , isci_tmf_ssp_task_abort ,
2011-03-04 14:06:56 -08:00
isci_abort_task_process_cb ,
old_request ) ;
2011-07-02 22:56:22 -07:00
spin_unlock_irqrestore ( & isci_host - > scic_lock , flags ) ;
2011-10-27 15:05:16 -07:00
# define ISCI_ABORT_TASK_TIMEOUT_MS 500 /* 1/2 second timeout */
2011-06-13 17:39:44 -07:00
ret = isci_task_execute_tmf ( isci_host , isci_device , & tmf ,
2011-07-02 22:56:22 -07:00
ISCI_ABORT_TASK_TIMEOUT_MS ) ;
2011-10-27 15:05:16 -07:00
if ( ret = = TMF_RESP_FUNC_COMPLETE )
perform_termination = 1 ;
else
2011-07-01 12:07:25 -07:00
dev_dbg ( & isci_host - > pdev - > dev ,
2011-10-27 15:05:16 -07:00
" %s: isci_task_send_tmf failed \n " , __func__ ) ;
2011-07-02 22:56:22 -07:00
}
2011-10-27 15:05:16 -07:00
if ( perform_termination ) {
2011-06-23 14:33:48 -07:00
set_bit ( IREQ_COMPLETE_IN_TARGET , & old_request - > flags ) ;
2011-03-04 14:06:42 -08:00
2011-06-20 14:09:16 -07:00
/* Clean up the request on our side, and wait for the aborted
* I / O to complete .
*/
2011-10-27 15:05:16 -07:00
isci_terminate_request_core ( isci_host , isci_device ,
old_request ) ;
2011-03-04 14:06:42 -08:00
}
2011-07-02 22:56:22 -07:00
2011-03-04 14:06:42 -08:00
/* Make sure we do not leave a reference to aborted_io_completion */
old_request - > io_request_completion = NULL ;
2011-06-13 17:39:44 -07:00
out :
isci_put_device ( isci_device ) ;
2011-07-02 22:56:22 -07:00
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 ;
}
2011-05-04 17:53:24 -07:00
/*
2011-07-02 22:56:22 -07:00
* isci_task_request_complete ( ) - This function is called by the sci core when
* an task request completes .
2011-05-04 17:53:24 -07:00
* @ ihost : This parameter specifies the ISCI host object
* @ ireq : This parameter is the completed isci_request object .
2011-07-02 22:56:22 -07:00
* @ completion_status : This parameter specifies the completion status from the
* sci core .
*
* none .
*/
2011-05-04 17:53:24 -07:00
void
isci_task_request_complete ( struct isci_host * ihost ,
struct isci_request * ireq ,
enum sci_task_status completion_status )
2011-07-02 22:56:22 -07:00
{
2011-05-04 17:53:24 -07:00
struct isci_tmf * tmf = isci_request_access_tmf ( ireq ) ;
2011-10-27 15:05:06 -07:00
struct completion * tmf_complete = NULL ;
struct completion * request_complete = ireq - > io_request_completion ;
2011-07-02 22:56:22 -07:00
2011-05-04 17:53:24 -07:00
dev_dbg ( & ihost - > pdev - > dev ,
2011-07-02 22:56:22 -07:00
" %s: request = %p, status=%d \n " ,
2011-05-04 17:53:24 -07:00
__func__ , ireq , completion_status ) ;
2011-07-02 22:56:22 -07:00
2011-06-01 09:03:08 +00:00
isci_request_change_state ( ireq , completed ) ;
2011-07-02 22:56:22 -07:00
2011-06-23 14:33:48 -07:00
set_bit ( IREQ_COMPLETE_IN_TARGET , & ireq - > flags ) ;
2011-07-02 22:56:22 -07:00
2011-10-27 15:05:06 -07:00
if ( tmf ) {
tmf - > status = completion_status ;
if ( tmf - > proto = = SAS_PROTOCOL_SSP ) {
memcpy ( & tmf - > resp . resp_iu ,
& ireq - > ssp . rsp ,
SSP_RESP_IU_MAX_SIZE ) ;
} else if ( tmf - > proto = = SAS_PROTOCOL_SATA ) {
memcpy ( & tmf - > resp . d2h_fis ,
& ireq - > stp . rsp ,
sizeof ( struct dev_to_host_fis ) ) ;
}
/* PRINT_TMF( ((struct isci_tmf *)request->task)); */
tmf_complete = tmf - > complete ;
2011-07-02 22:56:22 -07:00
}
2011-06-30 19:14:33 -07:00
sci_controller_complete_io ( ihost , ireq - > target_device , ireq ) ;
2011-05-08 11:47:15 -07:00
/* set the 'terminated' flag handle to make sure it cannot be terminated
2011-07-02 22:56:22 -07:00
* or completed again .
*/
2011-06-23 14:33:48 -07:00
set_bit ( IREQ_TERMINATED , & ireq - > flags ) ;
2011-07-02 22:56:22 -07:00
2011-10-27 15:05:01 -07:00
/* As soon as something is in the terminate path, deallocation is
* managed there . Note that the final non - managed state of a task
* request is " completed " .
*/
if ( ( ireq - > status = = completed ) | |
! isci_request_is_dealloc_managed ( ireq - > status ) ) {
isci_request_change_state ( ireq , unallocated ) ;
isci_free_tag ( ihost , ireq - > io_tag ) ;
list_del_init ( & ireq - > dev_node ) ;
}
2011-07-02 22:56:22 -07:00
2011-10-27 15:05:06 -07:00
/* "request_complete" is set if the task was being terminated. */
if ( request_complete )
complete ( request_complete ) ;
2011-07-02 22:56:22 -07:00
/* The task management part completes last. */
2011-10-27 15:05:06 -07:00
if ( tmf_complete )
complete ( tmf_complete ) ;
2011-07-02 22:56:22 -07:00
}
2011-06-13 17:39:44 -07:00
static int isci_reset_device ( struct isci_host * ihost ,
2011-07-01 13:03:44 -07:00
struct isci_remote_device * idev )
2011-07-02 22:56:22 -07:00
{
2011-06-13 17:39:44 -07:00
struct sas_phy * phy = sas_find_local_phy ( idev - > domain_dev ) ;
2011-07-02 22:56:22 -07:00
enum sci_status status ;
2011-05-02 13:59:25 -07:00
unsigned long flags ;
int rc ;
2011-07-02 22:56:22 -07:00
2011-05-02 13:59:25 -07:00
dev_dbg ( & ihost - > pdev - > dev , " %s: idev %p \n " , __func__ , idev ) ;
2011-07-02 22:56:22 -07:00
2011-05-02 13:59:25 -07:00
spin_lock_irqsave ( & ihost - > scic_lock , flags ) ;
2011-06-30 19:14:33 -07:00
status = sci_remote_device_reset ( idev ) ;
2011-07-02 22:56:22 -07:00
if ( status ! = SCI_SUCCESS ) {
2011-05-02 13:59:25 -07:00
spin_unlock_irqrestore ( & ihost - > scic_lock , flags ) ;
2011-07-02 22:56:22 -07:00
2011-07-01 12:07:25 -07:00
dev_dbg ( & ihost - > pdev - > dev ,
2011-06-30 19:14:33 -07:00
" %s: sci_remote_device_reset(%p) returned %d! \n " ,
2011-05-02 13:59:25 -07:00
__func__ , idev , status ) ;
2011-07-02 22:56:22 -07:00
return TMF_RESP_FUNC_FAILED ;
}
2011-05-02 13:59:25 -07:00
spin_unlock_irqrestore ( & ihost - > scic_lock , flags ) ;
2011-07-02 22:56:22 -07:00
2011-07-01 13:03:44 -07:00
rc = sas_phy_reset ( phy , true ) ;
2011-07-02 22:56:22 -07:00
2011-05-02 13:59:25 -07:00
/* Terminate in-progress I/O now. */
isci_remote_device_nuke_requests ( ihost , idev ) ;
2011-07-02 22:56:22 -07:00
2011-06-20 14:08:51 -07:00
/* Since all pending TCs have been cleaned, resume the RNC. */
2011-05-02 13:59:25 -07:00
spin_lock_irqsave ( & ihost - > scic_lock , flags ) ;
2011-06-30 19:14:33 -07:00
status = sci_remote_device_reset_complete ( idev ) ;
2011-05-02 13:59:25 -07:00
spin_unlock_irqrestore ( & ihost - > scic_lock , flags ) ;
2011-07-02 22:56:22 -07:00
2011-05-02 13:59:25 -07:00
if ( status ! = SCI_SUCCESS ) {
2011-07-01 12:07:25 -07:00
dev_dbg ( & ihost - > pdev - > dev ,
2011-06-30 19:14:33 -07:00
" %s: sci_remote_device_reset_complete(%p) "
2011-05-02 13:59:25 -07:00
" returned %d! \n " , __func__ , idev , status ) ;
2011-07-02 22:56:22 -07:00
}
2011-05-02 13:59:25 -07:00
dev_dbg ( & ihost - > pdev - > dev , " %s: idev %p complete. \n " , __func__ , idev ) ;
2011-07-02 22:56:22 -07:00
2011-05-02 13:59:25 -07:00
return rc ;
}
2011-07-02 22:56:22 -07:00
2011-05-02 13:59:25 -07:00
int isci_task_I_T_nexus_reset ( struct domain_device * dev )
{
struct isci_host * ihost = dev_to_ihost ( dev ) ;
struct isci_remote_device * idev ;
unsigned long flags ;
2011-07-01 13:03:44 -07:00
int ret ;
2011-05-02 13:59:25 -07:00
spin_lock_irqsave ( & ihost - > scic_lock , flags ) ;
2011-06-13 17:39:44 -07:00
idev = isci_lookup_device ( dev ) ;
2011-05-02 13:59:25 -07:00
spin_unlock_irqrestore ( & ihost - > scic_lock , flags ) ;
2011-06-13 17:39:44 -07:00
if ( ! idev | | ! test_bit ( IDEV_EH , & idev - > flags ) ) {
ret = TMF_RESP_FUNC_COMPLETE ;
goto out ;
}
2011-05-02 13:59:25 -07:00
2011-07-01 13:03:44 -07:00
ret = isci_reset_device ( ihost , idev ) ;
2011-06-13 17:39:44 -07:00
out :
isci_put_device ( idev ) ;
return ret ;
2011-05-02 13:59:25 -07:00
}
int isci_bus_reset_handler ( struct scsi_cmnd * cmd )
{
struct domain_device * dev = sdev_to_domain_dev ( cmd - > device ) ;
2011-06-13 17:39:44 -07:00
struct isci_host * ihost = dev_to_ihost ( dev ) ;
struct isci_remote_device * idev ;
unsigned long flags ;
2011-07-01 13:03:44 -07:00
int ret ;
2011-07-02 22:56:22 -07:00
2011-06-13 17:39:44 -07:00
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 ;
}
2011-07-01 13:03:44 -07:00
ret = isci_reset_device ( ihost , idev ) ;
2011-06-13 17:39:44 -07:00
out :
isci_put_device ( idev ) ;
return ret ;
2011-07-02 22:56:22 -07:00
}