2011-07-03 09:56:22 +04: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-10 08:27:46 +03:00
# include <linux/irqflags.h>
2011-05-05 04:53:24 +04:00
# include "sas.h"
2011-06-21 23:16:33 +04:00
# include <scsi/libsas.h>
2011-04-23 06:18:03 +04:00
# include "remote_device.h"
# include "remote_node_context.h"
2011-07-03 09:56:22 +04:00
# include "isci.h"
# include "request.h"
# include "task.h"
2011-06-29 00:47:09 +04:00
# include "host.h"
2011-05-05 04:53:24 +04:00
2011-03-10 08:27:46 +03:00
/**
2011-03-11 21:13:51 +03: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-10 08:27:46 +03:00
*
*/
2011-03-11 21:13:51 +03:00
static void isci_task_refuse ( struct isci_host * ihost , struct sas_task * task ,
enum service_response response ,
enum exec_status status )
2011-03-10 08:27:46 +03:00
{
2012-03-09 10:41:54 +04:00
unsigned long flags ;
2011-03-10 08:27:46 +03:00
2012-03-09 10:41:54 +04:00
/* Normal notification (task_done) */
dev_dbg ( & ihost - > pdev - > dev , " %s: task = %p, response=%d, status=%d \n " ,
__func__ , task , response , status ) ;
2011-03-10 08:27:46 +03:00
2012-03-09 10:41:54 +04:00
spin_lock_irqsave ( & task - > task_state_lock , flags ) ;
2011-03-10 08:27:46 +03:00
2012-03-09 10:41:54 +04:00
task - > task_status . resp = response ;
task - > task_status . stat = status ;
2011-03-10 08:27:46 +03:00
2012-03-09 10:41:54 +04:00
/* Normal notification (task_done) */
task - > task_state_flags | = SAS_TASK_STATE_DONE ;
task - > task_state_flags & = ~ ( SAS_TASK_AT_INITIATOR |
SAS_TASK_STATE_PENDING ) ;
task - > lldd_task = NULL ;
spin_unlock_irqrestore ( & task - > task_state_lock , flags ) ;
task - > task_done ( task ) ;
2011-03-10 08:27:46 +03:00
}
2011-07-03 09:56:22 +04:00
2011-03-11 21:13:51 +03:00
# define for_each_sas_task(num, task) \
for ( ; num > 0 ; num - - , \
task = list_entry ( task - > list . next , struct sas_task , list ) )
2011-06-24 04:09:02 +04: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-03 09:56:22 +04: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-04-01 00:10:44 +04:00
struct isci_host * ihost = dev_to_ihost ( task - > dev ) ;
2011-06-14 04:39:44 +04:00
struct isci_remote_device * idev ;
2011-07-03 09:56:22 +04:00
unsigned long flags ;
2011-06-16 22:26:12 +04:00
bool io_ready ;
2011-06-29 00:47:09 +04:00
u16 tag ;
2011-07-03 09:56:22 +04:00
2011-03-11 21:13:51 +03:00
dev_dbg ( & ihost - > pdev - > dev , " %s: num=%d \n " , __func__ , num ) ;
2011-07-03 09:56:22 +04:00
2011-03-11 21:13:51 +03:00
for_each_sas_task ( num , task ) {
2011-06-29 00:47:09 +04:00
enum sci_status status = SCI_FAILURE ;
2011-06-14 04:39:44 +04:00
spin_lock_irqsave ( & ihost - > scic_lock , flags ) ;
idev = isci_lookup_device ( task - > dev ) ;
2011-06-24 04:09:02 +04:00
io_ready = isci_device_io_ready ( idev , task ) ;
2011-06-29 00:47:09 +04:00
tag = isci_alloc_tag ( ihost ) ;
2011-06-14 04:39:44 +04:00
spin_unlock_irqrestore ( & ihost - > scic_lock , flags ) ;
2011-07-03 09:56:22 +04:00
2011-06-16 22:26:12 +04: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-03 09:56:22 +04:00
2011-06-16 22:26:12 +04:00
if ( ! idev ) {
isci_task_refuse ( ihost , task , SAS_TASK_UNDELIVERED ,
SAS_DEVICE_UNKNOWN ) ;
2011-06-29 00:47:09 +04:00
} else if ( ! io_ready | | tag = = SCI_CONTROLLER_INVALID_IO_TAG ) {
2011-06-16 22:26:12 +04:00
/* Indicate QUEUE_FULL so that the scsi midlayer
* retries .
*/
isci_task_refuse ( ihost , task , SAS_TASK_COMPLETE ,
SAS_QUEUE_FULL ) ;
2011-03-09 05:22:07 +03:00
} else {
/* There is a device and it's ready for I/O. */
spin_lock_irqsave ( & task - > task_state_lock , flags ) ;
2011-07-03 09:56:22 +04:00
2011-03-09 05:22:07 +03:00
if ( task - > task_state_flags & SAS_TASK_STATE_ABORTED ) {
2011-06-16 22:26:12 +04:00
/* The I/O was aborted. */
2011-03-09 05:22:07 +03:00
spin_unlock_irqrestore ( & task - > task_state_lock ,
flags ) ;
2011-07-03 09:56:22 +04:00
2011-03-11 21:13:51 +03:00
isci_task_refuse ( ihost , task ,
SAS_TASK_UNDELIVERED ,
SAM_STAT_TASK_ABORTED ) ;
2011-03-09 05:22:07 +03:00
} else {
2011-07-03 09:56:22 +04:00
task - > task_state_flags | = SAS_TASK_AT_INITIATOR ;
spin_unlock_irqrestore ( & task - > task_state_lock , flags ) ;
2011-03-09 05:22:07 +03:00
/* build and send the request. */
2011-06-18 01:18:39 +04:00
status = isci_request_execute ( ihost , idev , task , tag ) ;
2011-03-09 05:22:07 +03: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-28 02:04:56 +04: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-09 05:22:07 +03:00
}
2011-07-03 09:56:22 +04:00
}
}
2011-06-29 00:47:09 +04: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-14 04:39:44 +04:00
isci_put_device ( idev ) ;
2011-03-11 21:13:51 +03:00
}
2011-07-03 09:56:22 +04:00
return 0 ;
}
2011-06-13 11:51:30 +04:00
static struct isci_request * isci_task_request_build ( struct isci_host * ihost ,
2011-06-14 04:39:44 +04:00
struct isci_remote_device * idev ,
2011-06-29 00:47:09 +04:00
u16 tag , struct isci_tmf * isci_tmf )
2011-07-03 09:56:22 +04:00
{
enum sci_status status = SCI_FAILURE ;
2011-06-13 11:51:30 +04:00
struct isci_request * ireq = NULL ;
2011-04-22 05:44:45 +04:00
struct domain_device * dev ;
2011-07-03 09:56:22 +04:00
2011-06-13 11:51:30 +04:00
dev_dbg ( & ihost - > pdev - > dev ,
2011-07-03 09:56:22 +04:00
" %s: isci_tmf = %p \n " , __func__ , isci_tmf ) ;
2011-06-13 11:51:30 +04:00
dev = idev - > domain_dev ;
2011-07-03 09:56:22 +04:00
/* do common allocation and init of request object. */
2011-06-18 01:18:39 +04:00
ireq = isci_tmf_request_from_tag ( ihost , isci_tmf , tag ) ;
2011-06-13 11:51:30 +04:00
if ( ! ireq )
return NULL ;
2011-07-03 09:56:22 +04:00
/* let the core do it's construct. */
2011-07-01 06:14:33 +04:00
status = sci_task_request_construct ( ihost , idev , tag ,
2011-06-28 01:57:03 +04:00
ireq ) ;
2011-07-03 09:56:22 +04:00
if ( status ! = SCI_SUCCESS ) {
2011-06-13 11:51:30 +04:00
dev_warn ( & ihost - > pdev - > dev ,
2011-07-01 06:14:33 +04:00
" %s: sci_task_request_construct failed - "
2011-07-03 09:56:22 +04:00
" status = 0x%x \n " ,
__func__ ,
status ) ;
2011-06-18 01:18:39 +04:00
return NULL ;
2011-07-03 09:56:22 +04:00
}
2011-04-22 05:44:45 +04:00
/* XXX convert to get this from task->tproto like other drivers */
if ( dev - > dev_type = = SAS_END_DEV ) {
2011-07-03 09:56:22 +04:00
isci_tmf - > proto = SAS_PROTOCOL_SSP ;
2011-07-01 06:14:33 +04:00
status = sci_task_request_construct_ssp ( ireq ) ;
2011-07-03 09:56:22 +04:00
if ( status ! = SCI_SUCCESS )
2011-06-18 01:18:39 +04:00
return NULL ;
2011-07-03 09:56:22 +04:00
}
2011-06-13 11:51:30 +04:00
return ireq ;
2011-07-03 09:56:22 +04:00
}
2011-07-01 21:52:55 +04: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-03 09:56:22 +04:00
{
DECLARE_COMPLETION_ONSTACK ( completion ) ;
2011-04-13 04:28:41 +04:00
enum sci_task_status status = SCI_TASK_FAILURE ;
2011-06-13 11:51:30 +04:00
struct isci_request * ireq ;
2011-07-03 09:56:22 +04:00
int ret = TMF_RESP_FUNC_FAILED ;
unsigned long flags ;
2011-05-19 16:00:15 +04:00
unsigned long timeleft ;
2011-06-29 00:47:09 +04: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-03 09:56:22 +04:00
/* sanity check, return TMF_RESP_FUNC_FAILED
* if the device is not there and ready .
*/
2011-07-01 03:31:37 +04:00
if ( ! idev | |
( ! test_bit ( IDEV_IO_READY , & idev - > flags ) & &
! test_bit ( IDEV_IO_NCQERROR , & idev - > flags ) ) ) {
2011-06-13 11:51:30 +04:00
dev_dbg ( & ihost - > pdev - > dev ,
2011-07-01 03:31:37 +04:00
" %s: idev = %p not ready (%#lx) \n " ,
2011-07-03 09:56:22 +04:00
__func__ ,
2011-07-01 03:31:37 +04:00
idev , idev ? idev - > flags : 0 ) ;
2011-06-29 00:47:09 +04:00
goto err_tci ;
2011-07-03 09:56:22 +04:00
} else
2011-06-13 11:51:30 +04:00
dev_dbg ( & ihost - > pdev - > dev ,
2011-07-01 03:31:37 +04:00
" %s: idev = %p \n " ,
__func__ , idev ) ;
2011-07-03 09:56:22 +04:00
/* Assign the pointer to the TMF's completion kernel wait structure. */
tmf - > complete = & completion ;
2011-10-28 02:05:06 +04:00
tmf - > status = SCI_FAILURE_TIMEOUT ;
2011-07-03 09:56:22 +04:00
2011-07-01 03:31:37 +04:00
ireq = isci_task_request_build ( ihost , idev , tag , tmf ) ;
2011-06-29 00:47:09 +04:00
if ( ! ireq )
goto err_tci ;
2011-07-03 09:56:22 +04:00
2011-06-13 11:51:30 +04:00
spin_lock_irqsave ( & ihost - > scic_lock , flags ) ;
2011-07-03 09:56:22 +04:00
/* start the TMF io. */
2011-07-01 06:14:33 +04:00
status = sci_controller_start_task ( ihost , idev , ireq ) ;
2011-07-03 09:56:22 +04:00
2011-04-13 04:28:41 +04:00
if ( status ! = SCI_TASK_SUCCESS ) {
2011-07-01 23:07:25 +04:00
dev_dbg ( & ihost - > pdev - > dev ,
2011-07-03 09:56:22 +04:00
" %s: start_io failed - status = 0x%x, request = %p \n " ,
__func__ ,
status ,
2011-06-13 11:51:30 +04:00
ireq ) ;
spin_unlock_irqrestore ( & ihost - > scic_lock , flags ) ;
2011-06-18 01:18:39 +04:00
goto err_tci ;
2011-07-03 09:56:22 +04:00
}
2012-03-09 10:41:54 +04:00
/* The RNC must be unsuspended before the TMF can get a response. */
sci_remote_device_resume ( idev , NULL , NULL ) ;
2011-06-13 11:51:30 +04:00
spin_unlock_irqrestore ( & ihost - > scic_lock , flags ) ;
2011-07-03 09:56:22 +04:00
/* Wait for the TMF to complete, or a timeout. */
2011-05-19 16:00:15 +04:00
timeleft = wait_for_completion_timeout ( & completion ,
2011-06-22 03:23:03 +04:00
msecs_to_jiffies ( timeout_ms ) ) ;
2011-05-19 16:00:15 +04:00
if ( timeleft = = 0 ) {
2011-10-28 02:05:06 +04:00
/* The TMF did not complete - this could be because
* of an unplug . Terminate the TMF request now .
*/
2012-03-09 10:41:54 +04:00
isci_remote_device_suspend_terminate ( ihost , idev , ireq ) ;
2011-05-19 16:00:15 +04:00
}
2011-07-03 09:56:22 +04:00
2012-01-04 13:33:05 +04:00
isci_print_tmf ( ihost , tmf ) ;
2011-07-03 09:56:22 +04:00
if ( tmf - > status = = SCI_SUCCESS )
ret = TMF_RESP_FUNC_COMPLETE ;
else if ( tmf - > status = = SCI_FAILURE_IO_RESPONSE_VALID ) {
2011-06-13 11:51:30 +04:00
dev_dbg ( & ihost - > pdev - > dev ,
2011-07-03 09:56:22 +04: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 11:51:30 +04:00
dev_dbg ( & ihost - > pdev - > dev ,
2011-07-03 09:56:22 +04:00
" %s: completed request = %p \n " ,
__func__ ,
2011-06-13 11:51:30 +04:00
ireq ) ;
2011-07-03 09:56:22 +04:00
return ret ;
2011-06-29 00:47:09 +04: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-03 09:56:22 +04:00
}
2011-07-01 21:52:55 +04:00
static void isci_task_build_tmf ( struct isci_tmf * tmf ,
2012-03-09 10:41:54 +04:00
enum isci_tmf_function_codes code )
2011-07-03 09:56:22 +04:00
{
memset ( tmf , 0 , sizeof ( * tmf ) ) ;
2012-03-09 10:41:54 +04:00
tmf - > tmf_code = code ;
2011-03-05 01:06:56 +03:00
}
2011-03-05 01:06:46 +03:00
2011-07-01 21:52:55 +04:00
static void isci_task_build_abort_task_tmf ( struct isci_tmf * tmf ,
enum isci_tmf_function_codes code ,
struct isci_request * old_request )
2011-03-05 01:06:56 +03:00
{
2012-03-09 10:41:54 +04:00
isci_task_build_tmf ( tmf , code ) ;
2011-03-05 01:06:56 +03:00
tmf - > io_tag = old_request - > io_tag ;
2011-07-03 09:56:22 +04: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 " ) .
*/
2012-03-09 10:41:54 +04:00
isci_task_build_tmf ( & tmf , isci_tmf_ssp_lun_reset ) ;
2011-07-03 09:56:22 +04:00
# define ISCI_LU_RESET_TIMEOUT_MS 2000 /* 2 second timeout. */
2011-06-14 04:39:44 +04:00
ret = isci_task_execute_tmf ( isci_host , isci_device , & tmf , ISCI_LU_RESET_TIMEOUT_MS ) ;
2011-07-03 09:56:22 +04: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-12-09 11:20:44 +04:00
int isci_task_lu_reset ( struct domain_device * dev , u8 * lun )
2011-07-01 21:52:55 +04:00
{
2012-03-09 10:41:51 +04:00
struct isci_host * ihost = dev_to_ihost ( dev ) ;
2012-03-09 10:41:54 +04:00
struct isci_remote_device * idev ;
2011-06-14 04:39:44 +04:00
unsigned long flags ;
2011-07-03 09:56:22 +04:00
int ret ;
2012-03-09 10:41:51 +04:00
spin_lock_irqsave ( & ihost - > scic_lock , flags ) ;
2012-03-09 10:41:55 +04:00
idev = isci_get_device ( dev - > lldd_dev ) ;
2012-03-09 10:41:51 +04:00
spin_unlock_irqrestore ( & ihost - > scic_lock , flags ) ;
2011-07-03 09:56:22 +04:00
2012-03-09 10:41:51 +04:00
dev_dbg ( & ihost - > pdev - > dev ,
2011-04-01 00:10:44 +04:00
" %s: domain_device=%p, isci_host=%p; isci_device=%p \n " ,
2012-03-09 10:41:54 +04:00
__func__ , dev , ihost , idev ) ;
2011-07-03 09:56:22 +04:00
2012-03-09 10:41:54 +04:00
if ( ! idev ) {
2012-03-09 10:41:53 +04:00
/* If the device is gone, escalate to I_T_Nexus_Reset. */
2012-03-09 10:41:51 +04:00
dev_dbg ( & ihost - > pdev - > dev , " %s: No dev \n " , __func__ ) ;
2011-07-03 09:56:22 +04:00
2012-03-09 10:41:53 +04:00
ret = TMF_RESP_FUNC_FAILED ;
2011-06-14 04:39:44 +04:00
goto out ;
2011-07-03 09:56:22 +04:00
}
2011-12-09 11:20:44 +04:00
if ( dev_is_sata ( dev ) ) {
sas_ata_schedule_reset ( dev ) ;
ret = TMF_RESP_FUNC_COMPLETE ;
2012-03-09 10:41:54 +04:00
} else {
/* Suspend the RNC, kill all TCs */
if ( isci_remote_device_suspend_terminate ( ihost , idev , NULL )
! = SCI_SUCCESS ) {
ret = TMF_RESP_FUNC_FAILED ;
goto out ;
}
/* Send the task management part of the reset. */
ret = isci_task_send_lu_reset_sas ( ihost , idev , lun ) ;
2012-03-09 10:41:51 +04:00
}
2011-06-14 04:39:44 +04:00
out :
2012-03-09 10:41:54 +04:00
isci_put_device ( idev ) ;
2011-07-03 09:56:22 +04: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_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 )
{
2012-03-09 10:41:54 +04:00
struct isci_host * ihost = dev_to_ihost ( task - > dev ) ;
2011-07-03 09:56:22 +04:00
DECLARE_COMPLETION_ONSTACK ( aborted_io_completion ) ;
2011-03-05 01:06:42 +03:00
struct isci_request * old_request = NULL ;
2012-03-09 10:41:54 +04:00
struct isci_remote_device * idev = NULL ;
2011-03-05 01:06:42 +03:00
struct isci_tmf tmf ;
int ret = TMF_RESP_FUNC_FAILED ;
unsigned long flags ;
2011-07-03 09:56:22 +04: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 .
*/
2012-03-09 10:41:54 +04:00
spin_lock_irqsave ( & ihost - > scic_lock , flags ) ;
2011-06-14 04:39:44 +04:00
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 )
2012-03-09 10:41:55 +04:00
idev = isci_get_device ( task - > dev - > lldd_dev ) ;
2011-06-14 04:39:44 +04:00
spin_unlock ( & task - > task_state_lock ) ;
2012-03-09 10:41:54 +04:00
spin_unlock_irqrestore ( & ihost - > scic_lock , flags ) ;
2011-07-03 09:56:22 +04:00
2012-03-09 10:41:54 +04:00
dev_warn ( & ihost - > pdev - > dev ,
" %s: dev = %p, task = %p, old_request == %p \n " ,
__func__ , idev , task , old_request ) ;
2011-07-03 09:56:22 +04:00
2011-10-28 02:05:16 +04: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-03 09:56:22 +04:00
*/
2012-03-09 10:41:54 +04:00
if ( ! idev | | ! old_request ) {
2011-10-28 02:05:16 +04:00
/* 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-03 09:56:22 +04:00
2011-10-28 02:05:16 +04:00
ret = TMF_RESP_FUNC_COMPLETE ;
2011-07-03 09:56:22 +04:00
2012-03-09 10:41:54 +04:00
dev_warn ( & ihost - > pdev - > dev ,
" %s: abort task not needed for %p \n " ,
__func__ , task ) ;
2011-06-14 04:39:44 +04:00
goto out ;
2011-07-03 23:14:45 +04:00
}
2012-03-09 10:41:54 +04:00
/* Suspend the RNC, kill the TC */
if ( isci_remote_device_suspend_terminate ( ihost , idev , old_request )
! = SCI_SUCCESS ) {
dev_warn ( & ihost - > pdev - > dev ,
" %s: isci_remote_device_reset_terminate(dev=%p, "
" req=%p, task=%p) failed \n " ,
__func__ , idev , old_request , task ) ;
ret = TMF_RESP_FUNC_FAILED ;
2011-06-14 04:39:44 +04:00
goto out ;
2011-07-03 09:56:22 +04:00
}
2012-03-09 10:41:54 +04:00
spin_lock_irqsave ( & ihost - > scic_lock , flags ) ;
2011-06-24 01:33:48 +04:00
if ( task - > task_proto = = SAS_PROTOCOL_SMP | |
2011-10-28 02:05:16 +04:00
sas_protocol_ata ( task - > task_proto ) | |
2011-06-24 01:33:48 +04:00
test_bit ( IREQ_COMPLETE_IN_TARGET , & old_request - > flags ) ) {
2011-07-03 09:56:22 +04:00
2012-03-09 10:41:54 +04:00
/* No task to send, so explicitly resume the device here */
sci_remote_device_resume ( idev , NULL , NULL ) ;
2011-07-03 09:56:22 +04:00
2012-03-09 10:41:54 +04:00
spin_unlock_irqrestore ( & ihost - > scic_lock , flags ) ;
2011-07-03 09:56:22 +04:00
2012-03-09 10:41:54 +04:00
dev_warn ( & ihost - > pdev - > dev ,
" %s: %s request "
" or complete_in_target (%d), thus no TMF \n " ,
__func__ ,
( ( task - > task_proto = = SAS_PROTOCOL_SMP )
? " SMP "
: ( sas_protocol_ata ( task - > task_proto )
? " SATA/STP "
: " <other> " )
) ,
test_bit ( IREQ_COMPLETE_IN_TARGET ,
& old_request - > flags ) ) ;
2012-03-09 10:41:51 +04:00
2012-03-09 10:41:54 +04:00
spin_lock_irqsave ( & task - > task_state_lock , flags ) ;
task - > task_state_flags & = ~ ( SAS_TASK_AT_INITIATOR |
SAS_TASK_STATE_PENDING ) ;
task - > task_state_flags | = SAS_TASK_STATE_DONE ;
spin_unlock_irqrestore ( & task - > task_state_lock , flags ) ;
ret = TMF_RESP_FUNC_COMPLETE ;
2011-07-03 09:56:22 +04:00
} else {
/* Fill in the tmf stucture */
2011-06-14 04:39:44 +04:00
isci_task_build_abort_task_tmf ( & tmf , isci_tmf_ssp_task_abort ,
2011-03-05 01:06:56 +03:00
old_request ) ;
2011-07-03 09:56:22 +04:00
2012-03-09 10:41:54 +04:00
spin_unlock_irqrestore ( & ihost - > scic_lock , flags ) ;
2012-03-09 10:41:51 +04:00
2012-03-09 10:41:54 +04:00
/* Send the task management request. */
2011-10-28 02:05:16 +04:00
# define ISCI_ABORT_TASK_TIMEOUT_MS 500 /* 1/2 second timeout */
2012-03-09 10:41:54 +04:00
ret = isci_task_execute_tmf ( ihost , idev , & tmf ,
2011-07-03 09:56:22 +04:00
ISCI_ABORT_TASK_TIMEOUT_MS ) ;
2011-03-05 01:06:42 +03:00
}
2012-03-09 10:41:54 +04:00
out :
2012-03-09 10:41:55 +04:00
dev_warn ( & ihost - > pdev - > dev ,
" %s: Done; dev = %p, task = %p , old_request == %p \n " ,
__func__ , idev , task , old_request ) ;
2012-03-09 10:41:54 +04:00
isci_put_device ( idev ) ;
2011-07-03 09:56:22 +04: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-05 04:53:24 +04:00
/*
2011-07-03 09:56:22 +04:00
* isci_task_request_complete ( ) - This function is called by the sci core when
* an task request completes .
2011-05-05 04:53:24 +04:00
* @ ihost : This parameter specifies the ISCI host object
* @ ireq : This parameter is the completed isci_request object .
2011-07-03 09:56:22 +04:00
* @ completion_status : This parameter specifies the completion status from the
* sci core .
*
* none .
*/
2011-05-05 04:53:24 +04:00
void
isci_task_request_complete ( struct isci_host * ihost ,
struct isci_request * ireq ,
enum sci_task_status completion_status )
2011-07-03 09:56:22 +04:00
{
2011-05-05 04:53:24 +04:00
struct isci_tmf * tmf = isci_request_access_tmf ( ireq ) ;
2011-10-28 02:05:06 +04:00
struct completion * tmf_complete = NULL ;
2011-07-03 09:56:22 +04:00
2011-05-05 04:53:24 +04:00
dev_dbg ( & ihost - > pdev - > dev ,
2011-07-03 09:56:22 +04:00
" %s: request = %p, status=%d \n " ,
2011-05-05 04:53:24 +04:00
__func__ , ireq , completion_status ) ;
2011-07-03 09:56:22 +04:00
2011-06-24 01:33:48 +04:00
set_bit ( IREQ_COMPLETE_IN_TARGET , & ireq - > flags ) ;
2011-07-03 09:56:22 +04:00
2011-10-28 02:05:06 +04: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-03 09:56:22 +04:00
}
2011-07-01 06:14:33 +04:00
sci_controller_complete_io ( ihost , ireq - > target_device , ireq ) ;
2011-05-08 22:47:15 +04:00
/* set the 'terminated' flag handle to make sure it cannot be terminated
2011-07-03 09:56:22 +04:00
* or completed again .
*/
2011-06-24 01:33:48 +04:00
set_bit ( IREQ_TERMINATED , & ireq - > flags ) ;
2011-07-03 09:56:22 +04:00
2012-03-09 10:41:54 +04:00
isci_free_tag ( ihost , ireq - > io_tag ) ;
2011-10-28 02:05:06 +04:00
2011-07-03 09:56:22 +04:00
/* The task management part completes last. */
2011-10-28 02:05:06 +04:00
if ( tmf_complete )
complete ( tmf_complete ) ;
2011-07-03 09:56:22 +04:00
}
2011-06-14 04:39:44 +04:00
static int isci_reset_device ( struct isci_host * ihost ,
2011-11-30 23:57:34 +04:00
struct domain_device * dev ,
2011-07-02 00:03:44 +04:00
struct isci_remote_device * idev )
2011-07-03 09:56:22 +04:00
{
2012-03-09 10:41:54 +04:00
int rc = TMF_RESP_FUNC_COMPLETE , reset_stat ;
2011-11-30 23:57:34 +04:00
struct sas_phy * phy = sas_get_local_phy ( dev ) ;
struct isci_port * iport = dev - > port - > lldd_port ;
2011-07-03 09:56:22 +04:00
2011-05-03 00:59:25 +04:00
dev_dbg ( & ihost - > pdev - > dev , " %s: idev %p \n " , __func__ , idev ) ;
2011-07-03 09:56:22 +04:00
2012-03-09 10:41:54 +04:00
/* Suspend the RNC, terminate all outstanding TCs. */
if ( isci_remote_device_suspend_terminate ( ihost , idev , NULL )
! = SCI_SUCCESS ) {
2011-12-22 09:33:17 +04:00
rc = TMF_RESP_FUNC_FAILED ;
goto out ;
2011-07-03 09:56:22 +04:00
}
2012-03-09 10:41:54 +04:00
/* Note that since the termination for outstanding requests succeeded,
* this function will return success . This is because the resets will
* only fail if the device has been removed ( ie . hotplug ) , and the
* primary duty of this function is to cleanup tasks , so that is the
* relevant status .
*/
2011-07-03 09:56:22 +04:00
2011-11-30 23:57:34 +04:00
if ( scsi_is_sas_phy_local ( phy ) ) {
struct isci_phy * iphy = & ihost - > phys [ phy - > number ] ;
2012-03-09 10:41:54 +04:00
reset_stat = isci_port_perform_hard_reset ( ihost , iport , iphy ) ;
2011-11-30 23:57:34 +04:00
} else
2012-03-09 10:41:54 +04:00
reset_stat = sas_phy_reset ( phy , ! dev_is_sata ( dev ) ) ;
2011-07-03 09:56:22 +04:00
2012-03-09 10:41:54 +04:00
/* Explicitly resume the RNC here, since there was no task sent. */
isci_remote_device_resume ( ihost , idev , NULL , NULL ) ;
2011-07-03 09:56:22 +04:00
2012-03-09 10:41:54 +04:00
dev_dbg ( & ihost - > pdev - > dev , " %s: idev %p complete, reset_stat=%d. \n " ,
__func__ , idev , reset_stat ) ;
2011-12-22 09:33:17 +04:00
out :
sas_put_local_phy ( phy ) ;
2011-05-03 00:59:25 +04:00
return rc ;
}
2011-07-03 09:56:22 +04:00
2011-05-03 00:59:25 +04: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-02 00:03:44 +04:00
int ret ;
2011-05-03 00:59:25 +04:00
spin_lock_irqsave ( & ihost - > scic_lock , flags ) ;
2012-03-09 10:41:54 +04:00
idev = isci_get_device ( dev - > lldd_dev ) ;
2011-05-03 00:59:25 +04:00
spin_unlock_irqrestore ( & ihost - > scic_lock , flags ) ;
2011-12-13 08:32:09 +04:00
if ( ! idev ) {
/* XXX: need to cleanup any ireqs targeting this
* domain_device
*/
2011-06-14 04:39:44 +04:00
ret = TMF_RESP_FUNC_COMPLETE ;
goto out ;
}
2011-05-03 00:59:25 +04:00
2011-11-30 23:57:34 +04:00
ret = isci_reset_device ( ihost , dev , idev ) ;
2011-06-14 04:39:44 +04:00
out :
isci_put_device ( idev ) ;
return ret ;
2011-05-03 00:59:25 +04:00
}