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 "isci.h"
# include "port.h"
# include "request.h"
2011-05-10 02:28:46 -07:00
# define SCIC_SDS_PORT_HARD_RESET_TIMEOUT (1000)
# define SCU_DUMMY_INDEX (0xFFFF)
2011-07-02 22:56:22 -07:00
2012-02-10 01:18:44 -08:00
# undef C
# define C(a) (#a)
2021-03-17 09:11:24 +00:00
static const char * port_state_name ( enum sci_port_states state )
2012-02-10 01:18:44 -08:00
{
static const char * const strings [ ] = PORT_STATES ;
return strings [ state ] ;
}
# undef C
2012-01-03 23:26:08 -08:00
static struct device * sciport_to_dev ( struct isci_port * iport )
{
int i = iport - > physical_port_index ;
struct isci_port * table ;
struct isci_host * ihost ;
if ( i = = SCIC_SDS_DUMMY_PORT )
i = SCI_MAX_PORTS + 1 ;
table = iport - i ;
ihost = container_of ( table , typeof ( * ihost ) , ports [ 0 ] ) ;
return & ihost - > pdev - > dev ;
}
2011-06-30 19:14:33 -07:00
static void sci_port_get_protocols ( struct isci_port * iport , struct sci_phy_proto * proto )
2011-07-02 22:56:22 -07:00
{
2011-05-10 02:28:46 -07:00
u8 index ;
2011-06-30 19:14:33 -07:00
proto - > all = 0 ;
2011-05-10 02:28:46 -07:00
for ( index = 0 ; index < SCI_MAX_PHYS ; index + + ) {
2011-06-30 19:14:33 -07:00
struct isci_phy * iphy = iport - > phy_table [ index ] ;
if ( ! iphy )
continue ;
sci_phy_get_protocols ( iphy , proto ) ;
2011-05-10 02:28:46 -07:00
}
2011-07-02 22:56:22 -07:00
}
2011-06-30 19:14:33 -07:00
static u32 sci_port_get_phys ( struct isci_port * iport )
2011-07-02 22:56:22 -07:00
{
2011-05-10 02:28:46 -07:00
u32 index ;
u32 mask ;
mask = 0 ;
2011-06-30 19:14:33 -07:00
for ( index = 0 ; index < SCI_MAX_PHYS ; index + + )
if ( iport - > phy_table [ index ] )
2011-05-10 02:28:46 -07:00
mask | = ( 1 < < index ) ;
return mask ;
2011-07-02 22:56:22 -07:00
}
2011-05-10 02:28:46 -07:00
/**
2011-06-30 19:14:33 -07:00
* sci_port_get_properties ( ) - This method simply returns the properties
2011-05-10 02:28:46 -07:00
* regarding the port , such as : physical index , protocols , sas address , etc .
2021-03-17 09:12:22 +00:00
* @ iport : this parameter specifies the port for which to retrieve the physical
2011-05-10 02:28:46 -07:00
* index .
2021-03-17 09:12:22 +00:00
* @ prop : This parameter specifies the properties structure into which to
2011-05-10 02:28:46 -07:00
* copy the requested information .
*
* Indicate if the user specified a valid port . SCI_SUCCESS This value is
* returned if the specified port was valid . SCI_FAILURE_INVALID_PORT This
* value is returned if the specified port is not valid . When this value is
* returned , no data is copied to the properties output parameter .
*/
2012-01-04 01:33:20 -08:00
enum sci_status sci_port_get_properties ( struct isci_port * iport ,
2011-06-30 19:14:33 -07:00
struct sci_port_properties * prop )
2011-07-02 22:56:22 -07:00
{
2011-06-29 13:09:25 -07:00
if ( ! iport | | iport - > logical_port_index = = SCIC_SDS_DUMMY_PORT )
2011-05-10 02:28:46 -07:00
return SCI_FAILURE_INVALID_PORT ;
2011-07-02 22:56:22 -07:00
2011-06-30 19:14:33 -07:00
prop - > index = iport - > logical_port_index ;
prop - > phy_mask = sci_port_get_phys ( iport ) ;
sci_port_get_sas_address ( iport , & prop - > local . sas_address ) ;
sci_port_get_protocols ( iport , & prop - > local . protocols ) ;
sci_port_get_attached_sas_address ( iport , & prop - > remote . sas_address ) ;
2011-07-02 22:56:22 -07:00
2011-05-10 02:28:46 -07:00
return SCI_SUCCESS ;
2011-07-02 22:56:22 -07:00
}
2011-06-30 19:14:33 -07:00
static void sci_port_bcn_enable ( struct isci_port * iport )
2011-06-21 12:16:33 -07:00
{
2011-06-28 15:05:53 -07:00
struct isci_phy * iphy ;
2011-06-21 12:16:33 -07:00
u32 val ;
int i ;
2011-06-29 13:09:25 -07:00
for ( i = 0 ; i < ARRAY_SIZE ( iport - > phy_table ) ; i + + ) {
iphy = iport - > phy_table [ i ] ;
2011-06-28 15:05:53 -07:00
if ( ! iphy )
2011-06-21 12:16:33 -07:00
continue ;
2011-06-28 15:05:53 -07:00
val = readl ( & iphy - > link_layer_registers - > link_layer_control ) ;
2011-06-21 12:16:33 -07:00
/* clear the bit by writing 1. */
2011-06-28 15:05:53 -07:00
writel ( val , & iphy - > link_layer_registers - > link_layer_control ) ;
2011-06-21 12:16:33 -07:00
}
}
2011-06-29 13:09:25 -07:00
static void isci_port_bc_change_received ( struct isci_host * ihost ,
struct isci_port * iport ,
struct isci_phy * iphy )
2011-06-21 12:16:33 -07:00
{
2011-10-27 15:05:37 -07:00
dev_dbg ( & ihost - > pdev - > dev ,
" %s: isci_phy = %p, sas_phy = %p \n " ,
__func__ , iphy , & iphy - > sas_phy ) ;
2011-06-21 12:16:33 -07:00
2021-01-18 11:09:53 +01:00
sas_notify_port_event ( & iphy - > sas_phy ,
PORTE_BROADCAST_RCVD , GFP_ATOMIC ) ;
2011-06-30 19:14:33 -07:00
sci_port_bcn_enable ( iport ) ;
2011-06-21 12:16:33 -07:00
}
2011-05-10 02:28:46 -07:00
static void isci_port_link_up ( struct isci_host * isci_host ,
2011-06-29 13:09:25 -07:00
struct isci_port * iport ,
2011-06-28 15:05:53 -07:00
struct isci_phy * iphy )
2011-07-02 22:56:22 -07:00
{
unsigned long flags ;
2011-06-30 19:14:33 -07:00
struct sci_port_properties properties ;
2011-07-02 22:56:22 -07:00
unsigned long success = true ;
dev_dbg ( & isci_host - > pdev - > dev ,
" %s: isci_port = %p \n " ,
2011-06-29 13:09:25 -07:00
__func__ , iport ) ;
2011-07-02 22:56:22 -07:00
2011-06-28 15:05:53 -07:00
spin_lock_irqsave ( & iphy - > sas_phy . frame_rcvd_lock , flags ) ;
2011-07-02 22:56:22 -07:00
2011-06-30 19:14:33 -07:00
sci_port_get_properties ( iport , & properties ) ;
2011-07-02 22:56:22 -07:00
2012-02-01 00:44:14 -08:00
if ( iphy - > protocol = = SAS_PROTOCOL_SATA ) {
2011-02-25 10:25:21 -08:00
u64 attached_sas_address ;
2011-07-02 22:56:22 -07:00
2011-06-28 15:05:53 -07:00
iphy - > sas_phy . oob_mode = SATA_OOB_MODE ;
iphy - > sas_phy . frame_rcvd_size = sizeof ( struct dev_to_host_fis ) ;
2011-07-02 22:56:22 -07:00
/*
* For direct - attached SATA devices , the SCI core will
* automagically assign a SAS address to the end device
* for the purpose of creating a port . This SAS address
* will not be the same as assigned to the PHY and needs
2011-06-30 19:14:33 -07:00
* to be obtained from struct sci_port_properties properties .
2011-07-02 22:56:22 -07:00
*/
2011-02-25 10:25:21 -08:00
attached_sas_address = properties . remote . sas_address . high ;
attached_sas_address < < = 32 ;
attached_sas_address | = properties . remote . sas_address . low ;
swab64s ( & attached_sas_address ) ;
2011-07-02 22:56:22 -07:00
2011-06-28 15:05:53 -07:00
memcpy ( & iphy - > sas_phy . attached_sas_addr ,
2011-02-25 10:25:21 -08:00
& attached_sas_address , sizeof ( attached_sas_address ) ) ;
2012-02-01 00:44:14 -08:00
} else if ( iphy - > protocol = = SAS_PROTOCOL_SSP ) {
2011-06-28 15:05:53 -07:00
iphy - > sas_phy . oob_mode = SAS_OOB_MODE ;
iphy - > sas_phy . frame_rcvd_size = sizeof ( struct sas_identify_frame ) ;
2011-07-02 22:56:22 -07:00
/* Copy the attached SAS address from the IAF */
2011-06-28 15:05:53 -07:00
memcpy ( iphy - > sas_phy . attached_sas_addr ,
iphy - > frame_rcvd . iaf . sas_addr , SAS_ADDR_SIZE ) ;
2011-07-02 22:56:22 -07:00
} else {
2012-04-25 00:24:16 +09:00
dev_err ( & isci_host - > pdev - > dev , " %s: unknown target \n " , __func__ ) ;
2011-07-02 22:56:22 -07:00
success = false ;
}
2011-06-28 15:05:53 -07:00
iphy - > sas_phy . phy - > negotiated_linkrate = sci_phy_linkrate ( iphy ) ;
2011-02-18 09:25:13 -08:00
2011-06-28 15:05:53 -07:00
spin_unlock_irqrestore ( & iphy - > sas_phy . frame_rcvd_lock , flags ) ;
2011-07-02 22:56:22 -07:00
/* Notify libsas that we have an address frame, if indeed
* we ' ve found an SSP , SMP , or STP target */
if ( success )
2021-01-18 11:09:53 +01:00
sas_notify_port_event ( & iphy - > sas_phy ,
PORTE_BYTES_DMAED , GFP_ATOMIC ) ;
2011-07-02 22:56:22 -07:00
}
/**
* isci_port_link_down ( ) - This function is called by the sci core when a link
* becomes inactive .
* @ isci_host : This parameter specifies the isci host object .
2021-03-17 09:12:22 +00:00
* @ isci_phy : This parameter specifies the isci phy with the active link .
* @ isci_port : This parameter specifies the isci port with the active link .
2011-07-02 22:56:22 -07:00
*
*/
2011-05-10 02:28:46 -07:00
static void isci_port_link_down ( struct isci_host * isci_host ,
struct isci_phy * isci_phy ,
struct isci_port * isci_port )
2011-07-02 22:56:22 -07:00
{
2012-03-10 05:46:46 +00:00
struct isci_remote_device * isci_device ;
2011-07-02 22:56:22 -07:00
dev_dbg ( & isci_host - > pdev - > dev ,
" %s: isci_port = %p \n " , __func__ , isci_port ) ;
2012-03-10 05:46:46 +00:00
if ( isci_port ) {
/* check to see if this is the last phy on this port. */
if ( isci_phy - > sas_phy . port & &
isci_phy - > sas_phy . port - > num_phys = = 1 ) {
/* change the state for all devices on this port. The
* next task sent to this device will be returned as
* SAS_TASK_UNDELIVERED , and the scsi mid layer will
* remove the target
*/
list_for_each_entry ( isci_device ,
& isci_port - > remote_dev_list ,
node ) {
dev_dbg ( & isci_host - > pdev - > dev ,
" %s: isci_device = %p \n " ,
__func__ , isci_device ) ;
set_bit ( IDEV_GONE , & isci_device - > flags ) ;
}
}
}
2011-07-02 22:56:22 -07:00
/* Notify libsas of the borken link, this will trigger calls to our
* isci_port_deformed and isci_dev_gone functions .
*/
sas_phy_disconnected ( & isci_phy - > sas_phy ) ;
2021-01-18 11:09:53 +01:00
sas_notify_phy_event ( & isci_phy - > sas_phy ,
PHYE_LOSS_OF_SIGNAL , GFP_ATOMIC ) ;
2011-07-02 22:56:22 -07:00
dev_dbg ( & isci_host - > pdev - > dev ,
" %s: isci_port = %p - Done \n " , __func__ , isci_port ) ;
}
2011-10-27 15:05:32 -07:00
static bool is_port_ready_state ( enum sci_port_states state )
{
switch ( state ) {
case SCI_PORT_READY :
case SCI_PORT_SUB_WAITING :
case SCI_PORT_SUB_OPERATIONAL :
case SCI_PORT_SUB_CONFIGURING :
return true ;
default :
return false ;
}
}
/* flag dummy rnc hanling when exiting a ready state */
static void port_state_machine_change ( struct isci_port * iport ,
enum sci_port_states state )
{
struct sci_base_state_machine * sm = & iport - > sm ;
enum sci_port_states old_state = sm - > current_state_id ;
if ( is_port_ready_state ( old_state ) & & ! is_port_ready_state ( state ) )
iport - > ready_exit = true ;
sci_change_state ( sm , state ) ;
iport - > ready_exit = false ;
}
2011-07-02 22:56:22 -07:00
/**
* isci_port_hard_reset_complete ( ) - This function is called by the sci core
* when the hard reset complete notification has been received .
2021-03-17 09:12:22 +00:00
* @ isci_port : This parameter specifies the sci port with the active link .
2011-07-02 22:56:22 -07:00
* @ completion_status : This parameter specifies the core status for the reset
* process .
*
*/
2011-05-10 02:28:46 -07:00
static void isci_port_hard_reset_complete ( struct isci_port * isci_port ,
enum sci_status completion_status )
2011-07-02 22:56:22 -07:00
{
2011-11-30 11:57:34 -08:00
struct isci_host * ihost = isci_port - > owning_controller ;
dev_dbg ( & ihost - > pdev - > dev ,
2011-07-02 22:56:22 -07:00
" %s: isci_port = %p, completion_status=%x \n " ,
__func__ , isci_port , completion_status ) ;
/* Save the status of the hard reset from the port. */
isci_port - > hard_reset_status = completion_status ;
2011-10-27 15:05:32 -07:00
if ( completion_status ! = SCI_SUCCESS ) {
/* The reset failed. The port state is now SCI_PORT_FAILED. */
if ( isci_port - > active_phy_mask = = 0 ) {
2011-11-30 11:57:34 -08:00
int phy_idx = isci_port - > last_active_phy ;
struct isci_phy * iphy = & ihost - > phys [ phy_idx ] ;
2011-10-27 15:05:32 -07:00
/* Generate the link down now to the host, since it
* was intercepted by the hard reset state machine when
* it really happened .
*/
2011-11-30 11:57:34 -08:00
isci_port_link_down ( ihost , iphy , isci_port ) ;
2011-10-27 15:05:32 -07:00
}
/* Advance the port state so that link state changes will be
2011-11-30 11:57:34 -08:00
* noticed .
*/
2011-10-27 15:05:32 -07:00
port_state_machine_change ( isci_port , SCI_PORT_SUB_WAITING ) ;
}
2011-11-30 11:57:34 -08:00
clear_bit ( IPORT_RESET_PENDING , & isci_port - > state ) ;
wake_up ( & ihost - > eventq ) ;
2011-07-02 22:56:22 -07:00
}
2011-03-31 13:10:44 -07:00
2011-05-10 02:28:46 -07:00
/* This method will return a true value if the specified phy can be assigned to
* this port The following is a list of phys for each port that are allowed : -
* Port 0 - 3 2 1 0 - Port 1 - 1 - Port 2 - 3 2 - Port 3 - 3 This method
* doesn ' t preclude all configurations . It merely ensures that a phy is part
* of the allowable set of phy identifiers for that port . For example , one
* could assign phy 3 to port 0 and no other phys . Please refer to
2011-06-30 19:14:33 -07:00
* sci_port_is_phy_mask_valid ( ) for information regarding whether the
2011-05-10 02:28:46 -07:00
* phy_mask for a port can be supported . bool true if this is a valid phy
* assignment for the port false if this is not a valid phy assignment for the
* port
*/
2011-06-30 19:14:33 -07:00
bool sci_port_is_valid_phy_assignment ( struct isci_port * iport , u32 phy_index )
2011-07-02 22:56:22 -07:00
{
2011-06-30 19:14:33 -07:00
struct isci_host * ihost = iport - > owning_controller ;
struct sci_user_parameters * user = & ihost - > user_parameters ;
2011-05-10 02:28:46 -07:00
/* Initialize to invalid value. */
u32 existing_phy_index = SCI_MAX_PHYS ;
u32 index ;
2011-07-02 22:56:22 -07:00
2011-06-30 19:14:33 -07:00
if ( ( iport - > physical_port_index = = 1 ) & & ( phy_index ! = 1 ) )
2011-05-10 02:28:46 -07:00
return false ;
2011-07-02 22:56:22 -07:00
2011-06-30 19:14:33 -07:00
if ( iport - > physical_port_index = = 3 & & phy_index ! = 3 )
2011-05-10 02:28:46 -07:00
return false ;
2011-07-02 22:56:22 -07:00
2011-06-30 19:14:33 -07:00
if ( iport - > physical_port_index = = 2 & &
( phy_index = = 0 | | phy_index = = 1 ) )
2011-05-10 02:28:46 -07:00
return false ;
2011-07-02 22:56:22 -07:00
2011-06-30 19:14:33 -07:00
for ( index = 0 ; index < SCI_MAX_PHYS ; index + + )
if ( iport - > phy_table [ index ] & & index ! = phy_index )
2011-05-10 02:28:46 -07:00
existing_phy_index = index ;
2011-07-02 22:56:22 -07:00
2011-06-30 19:14:33 -07:00
/* Ensure that all of the phys in the port are capable of
* operating at the same maximum link rate .
*/
if ( existing_phy_index < SCI_MAX_PHYS & &
user - > phys [ phy_index ] . max_speed_generation ! =
user - > phys [ existing_phy_index ] . max_speed_generation )
2011-05-10 02:28:46 -07:00
return false ;
2011-07-02 22:56:22 -07:00
2011-05-10 02:28:46 -07:00
return true ;
}
2011-07-02 22:56:22 -07:00
2011-05-10 02:28:46 -07:00
/**
2021-03-17 09:12:22 +00:00
* sci_port_is_phy_mask_valid ( )
* @ iport : This is the port object for which to determine if the phy mask
2011-05-10 02:28:46 -07:00
* can be supported .
2021-03-17 09:12:22 +00:00
* @ phy_mask : Phy mask belonging to this port
2011-05-10 02:28:46 -07:00
*
* This method will return a true value if the port ' s phy mask can be supported
* by the SCU . The following is a list of valid PHY mask configurations for
* each port : - Port 0 - [ [ 3 2 ] 1 ] 0 - Port 1 - [ 1 ] - Port 2 - [ [ 3 ] 2 ]
* - Port 3 - [ 3 ] This method returns a boolean indication specifying if the
* phy mask can be supported . true if this is a valid phy assignment for the
* port false if this is not a valid phy assignment for the port
*/
2011-06-30 19:14:33 -07:00
static bool sci_port_is_phy_mask_valid (
2011-06-29 13:09:25 -07:00
struct isci_port * iport ,
2011-05-10 02:28:46 -07:00
u32 phy_mask )
{
2011-06-29 13:09:25 -07:00
if ( iport - > physical_port_index = = 0 ) {
2011-05-10 02:28:46 -07:00
if ( ( ( phy_mask & 0x0F ) = = 0x0F )
| | ( ( phy_mask & 0x03 ) = = 0x03 )
| | ( ( phy_mask & 0x01 ) = = 0x01 )
| | ( phy_mask = = 0 ) )
return true ;
2011-06-29 13:09:25 -07:00
} else if ( iport - > physical_port_index = = 1 ) {
2011-05-10 02:28:46 -07:00
if ( ( ( phy_mask & 0x02 ) = = 0x02 )
| | ( phy_mask = = 0 ) )
return true ;
2011-06-29 13:09:25 -07:00
} else if ( iport - > physical_port_index = = 2 ) {
2011-05-10 02:28:46 -07:00
if ( ( ( phy_mask & 0x0C ) = = 0x0C )
| | ( ( phy_mask & 0x04 ) = = 0x04 )
| | ( phy_mask = = 0 ) )
return true ;
2011-06-29 13:09:25 -07:00
} else if ( iport - > physical_port_index = = 3 ) {
2011-05-10 02:28:46 -07:00
if ( ( ( phy_mask & 0x08 ) = = 0x08 )
| | ( phy_mask = = 0 ) )
return true ;
}
2011-07-02 22:56:22 -07:00
2011-05-10 02:28:46 -07:00
return false ;
}
2011-07-02 22:56:22 -07:00
2011-06-28 15:05:53 -07:00
/*
2011-05-10 02:28:46 -07:00
* This method retrieves a currently active ( i . e . connected ) phy contained in
* the port . Currently , the lowest order phy that is connected is returned .
* This method returns a pointer to a SCIS_SDS_PHY object . NULL This value is
* returned if there are no currently active ( i . e . connected to a remote end
2011-06-30 19:14:33 -07:00
* point ) phys contained in the port . All other values specify a struct sci_phy
2011-05-10 02:28:46 -07:00
* object that is active in the port .
*/
2011-06-30 19:14:33 -07:00
static struct isci_phy * sci_port_get_a_connected_phy ( struct isci_port * iport )
2011-06-28 15:05:53 -07:00
{
2011-05-10 02:28:46 -07:00
u32 index ;
2011-06-28 15:05:53 -07:00
struct isci_phy * iphy ;
2011-07-02 22:56:22 -07:00
2011-05-10 02:28:46 -07:00
for ( index = 0 ; index < SCI_MAX_PHYS ; index + + ) {
2011-06-28 15:05:53 -07:00
/* Ensure that the phy is both part of the port and currently
* connected to the remote end - point .
*/
2011-06-29 13:09:25 -07:00
iphy = iport - > phy_table [ index ] ;
2011-06-30 19:14:33 -07:00
if ( iphy & & sci_port_active_phy ( iport , iphy ) )
2011-06-28 15:05:53 -07:00
return iphy ;
2011-07-02 22:56:22 -07:00
}
2011-05-10 02:28:46 -07:00
return NULL ;
}
2011-06-30 19:14:33 -07:00
static enum sci_status sci_port_set_phy ( struct isci_port * iport , struct isci_phy * iphy )
2011-05-10 02:28:46 -07:00
{
2011-06-28 15:05:53 -07:00
/* Check to see if we can add this phy to a port
2011-05-10 02:28:46 -07:00
* that means that the phy is not part of a port and that the port does
2011-06-28 15:05:53 -07:00
* not already have a phy assinged to the phy index .
*/
2011-06-29 13:09:25 -07:00
if ( ! iport - > phy_table [ iphy - > phy_index ] & &
2011-06-28 15:05:53 -07:00
! phy_get_non_dummy_port ( iphy ) & &
2011-06-30 19:14:33 -07:00
sci_port_is_valid_phy_assignment ( iport , iphy - > phy_index ) ) {
2011-06-28 15:05:53 -07:00
/* Phy is being added in the stopped state so we are in MPC mode
* make logical port index = physical port index
*/
2011-06-29 13:09:25 -07:00
iport - > logical_port_index = iport - > physical_port_index ;
iport - > phy_table [ iphy - > phy_index ] = iphy ;
2011-06-30 19:14:33 -07:00
sci_phy_set_port ( iphy , iport ) ;
2011-05-10 02:28:46 -07:00
return SCI_SUCCESS ;
}
return SCI_FAILURE ;
}
2011-06-30 19:14:33 -07:00
static enum sci_status sci_port_clear_phy ( struct isci_port * iport , struct isci_phy * iphy )
2011-05-10 02:28:46 -07:00
{
/* Make sure that this phy is part of this port */
2011-06-29 13:09:25 -07:00
if ( iport - > phy_table [ iphy - > phy_index ] = = iphy & &
phy_get_non_dummy_port ( iphy ) = = iport ) {
2011-06-30 17:38:32 -07:00
struct isci_host * ihost = iport - > owning_controller ;
2011-05-10 02:28:46 -07:00
/* Yep it is assigned to this port so remove it */
2011-06-30 19:14:33 -07:00
sci_phy_set_port ( iphy , & ihost - > ports [ SCI_MAX_PORTS ] ) ;
2011-06-29 13:09:25 -07:00
iport - > phy_table [ iphy - > phy_index ] = NULL ;
2011-05-10 02:28:46 -07:00
return SCI_SUCCESS ;
}
return SCI_FAILURE ;
}
2011-06-30 19:14:33 -07:00
void sci_port_get_sas_address ( struct isci_port * iport , struct sci_sas_address * sas )
2011-05-10 02:28:46 -07:00
{
u32 index ;
2011-06-30 19:14:33 -07:00
sas - > high = 0 ;
sas - > low = 0 ;
for ( index = 0 ; index < SCI_MAX_PHYS ; index + + )
if ( iport - > phy_table [ index ] )
sci_phy_get_sas_address ( iport - > phy_table [ index ] , sas ) ;
2011-05-10 02:28:46 -07:00
}
2011-06-30 19:14:33 -07:00
void sci_port_get_attached_sas_address ( struct isci_port * iport , struct sci_sas_address * sas )
2011-05-10 02:28:46 -07:00
{
2011-06-28 15:05:53 -07:00
struct isci_phy * iphy ;
2011-05-10 02:28:46 -07:00
/*
* Ensure that the phy is both part of the port and currently
* connected to the remote end - point .
2011-07-02 22:56:22 -07:00
*/
2011-06-30 19:14:33 -07:00
iphy = sci_port_get_a_connected_phy ( iport ) ;
2011-06-28 15:05:53 -07:00
if ( iphy ) {
2012-02-01 00:44:14 -08:00
if ( iphy - > protocol ! = SAS_PROTOCOL_SATA ) {
2011-06-30 19:14:33 -07:00
sci_phy_get_attached_sas_address ( iphy , sas ) ;
2011-05-10 02:28:46 -07:00
} else {
2011-06-30 19:14:33 -07:00
sci_phy_get_sas_address ( iphy , sas ) ;
sas - > low + = iphy - > phy_index ;
2011-05-10 02:28:46 -07:00
}
} else {
2011-06-30 19:14:33 -07:00
sas - > high = 0 ;
sas - > low = 0 ;
2011-05-10 02:28:46 -07:00
}
}
2011-03-31 13:10:44 -07:00
2011-05-10 02:28:46 -07:00
/**
2011-06-30 19:14:33 -07:00
* sci_port_construct_dummy_rnc ( ) - create dummy rnc for si workaround
2011-05-10 02:28:46 -07:00
*
2021-03-17 09:12:22 +00:00
* @ iport : logical port on which we need to create the remote node context
2011-05-10 02:28:46 -07:00
* @ rni : remote node index for this remote node context .
*
* This routine will construct a dummy remote node context data structure
* This structure will be posted to the hardware to work around a scheduler
* error in the hardware .
*/
2011-06-30 19:14:33 -07:00
static void sci_port_construct_dummy_rnc ( struct isci_port * iport , u16 rni )
2011-05-10 02:28:46 -07:00
{
union scu_remote_node_context * rnc ;
2011-06-29 13:09:25 -07:00
rnc = & iport - > owning_controller - > remote_node_context_table [ rni ] ;
2011-05-10 02:28:46 -07:00
memset ( rnc , 0 , sizeof ( union scu_remote_node_context ) ) ;
rnc - > ssp . remote_sas_address_hi = 0 ;
rnc - > ssp . remote_sas_address_lo = 0 ;
rnc - > ssp . remote_node_index = rni ;
rnc - > ssp . remote_node_port_width = 1 ;
2011-06-29 13:09:25 -07:00
rnc - > ssp . logical_port_index = iport - > physical_port_index ;
2011-05-10 02:28:46 -07:00
rnc - > ssp . nexus_loss_timer_enable = false ;
rnc - > ssp . check_bit = false ;
rnc - > ssp . is_valid = true ;
rnc - > ssp . is_remote_node_context = true ;
rnc - > ssp . function_number = 0 ;
rnc - > ssp . arbitration_wait_time = 0 ;
}
2011-06-09 11:06:58 -07:00
/*
* construct a dummy task context data structure . This
2011-05-10 02:28:46 -07:00
* structure will be posted to the hardwre to work around a scheduler error
* in the hardware .
*/
2011-06-30 19:14:33 -07:00
static void sci_port_construct_dummy_task ( struct isci_port * iport , u16 tag )
2011-05-10 02:28:46 -07:00
{
2011-06-30 17:38:32 -07:00
struct isci_host * ihost = iport - > owning_controller ;
2011-05-10 02:28:46 -07:00
struct scu_task_context * task_context ;
2011-06-30 17:38:32 -07:00
task_context = & ihost - > task_context_table [ ISCI_TAG_TCI ( tag ) ] ;
2011-05-10 02:28:46 -07:00
memset ( task_context , 0 , sizeof ( struct scu_task_context ) ) ;
task_context - > initiator_request = 1 ;
task_context - > connection_rate = 1 ;
2011-06-29 13:09:25 -07:00
task_context - > logical_port_index = iport - > physical_port_index ;
2011-05-10 02:28:46 -07:00
task_context - > protocol_type = SCU_TASK_CONTEXT_PROTOCOL_SSP ;
2011-06-09 11:06:58 -07:00
task_context - > task_index = ISCI_TAG_TCI ( tag ) ;
2011-05-10 02:28:46 -07:00
task_context - > valid = SCU_TASK_CONTEXT_VALID ;
task_context - > context_type = SCU_TASK_CONTEXT_TYPE ;
2011-06-29 13:09:25 -07:00
task_context - > remote_node_index = iport - > reserved_rni ;
2011-05-10 02:28:46 -07:00
task_context - > do_not_dma_ssp_good_response = 1 ;
task_context - > task_phase = 0x01 ;
}
2011-06-30 19:14:33 -07:00
static void sci_port_destroy_dummy_resources ( struct isci_port * iport )
2011-05-10 02:28:46 -07:00
{
2011-06-30 17:38:32 -07:00
struct isci_host * ihost = iport - > owning_controller ;
2011-05-10 02:28:46 -07:00
2011-06-29 13:09:25 -07:00
if ( iport - > reserved_tag ! = SCI_CONTROLLER_INVALID_IO_TAG )
2011-06-30 17:38:32 -07:00
isci_free_tag ( ihost , iport - > reserved_tag ) ;
2011-05-10 02:28:46 -07:00
2011-06-29 13:09:25 -07:00
if ( iport - > reserved_rni ! = SCU_DUMMY_INDEX )
2011-06-30 19:14:33 -07:00
sci_remote_node_table_release_remote_node_index ( & ihost - > available_remote_nodes ,
2011-06-29 13:09:25 -07:00
1 , iport - > reserved_rni ) ;
2011-05-10 02:28:46 -07:00
2011-06-29 13:09:25 -07:00
iport - > reserved_rni = SCU_DUMMY_INDEX ;
iport - > reserved_tag = SCI_CONTROLLER_INVALID_IO_TAG ;
2011-05-10 02:28:46 -07:00
}
2011-06-30 19:14:33 -07:00
void sci_port_setup_transports ( struct isci_port * iport , u32 device_id )
2011-05-10 02:28:46 -07:00
{
u8 index ;
for ( index = 0 ; index < SCI_MAX_PHYS ; index + + ) {
2011-06-29 13:09:25 -07:00
if ( iport - > active_phy_mask & ( 1 < < index ) )
2011-06-30 19:14:33 -07:00
sci_phy_setup_transport ( iport - > phy_table [ index ] , device_id ) ;
2011-07-02 22:56:22 -07:00
}
2011-05-10 02:28:46 -07:00
}
2011-07-02 22:56:22 -07:00
2012-01-04 01:33:41 -08:00
static void sci_port_resume_phy ( struct isci_port * iport , struct isci_phy * iphy )
{
sci_phy_resume ( iphy ) ;
iport - > enabled_phy_mask | = 1 < < iphy - > phy_index ;
}
static void sci_port_activate_phy ( struct isci_port * iport ,
struct isci_phy * iphy ,
u8 flags )
2011-05-10 02:28:46 -07:00
{
2011-06-30 17:38:32 -07:00
struct isci_host * ihost = iport - > owning_controller ;
2011-05-10 02:28:46 -07:00
2012-02-01 00:44:14 -08:00
if ( iphy - > protocol ! = SAS_PROTOCOL_SATA & & ( flags & PF_RESUME ) )
2011-06-30 19:14:33 -07:00
sci_phy_resume ( iphy ) ;
2011-05-10 02:28:46 -07:00
2011-06-29 13:09:25 -07:00
iport - > active_phy_mask | = 1 < < iphy - > phy_index ;
2011-05-10 02:28:46 -07:00
2011-06-30 19:14:33 -07:00
sci_controller_clear_invalid_phy ( ihost , iphy ) ;
2011-05-10 02:28:46 -07:00
2012-01-04 01:33:41 -08:00
if ( flags & PF_NOTIFY )
2011-06-29 13:09:25 -07:00
isci_port_link_up ( ihost , iport , iphy ) ;
2011-07-02 22:56:22 -07:00
}
2011-03-26 16:11:51 -07:00
2011-06-30 19:14:33 -07:00
void sci_port_deactivate_phy ( struct isci_port * iport , struct isci_phy * iphy ,
bool do_notify_user )
2011-03-26 16:11:51 -07:00
{
2011-07-01 02:25:15 -07:00
struct isci_host * ihost = iport - > owning_controller ;
2011-05-10 02:28:46 -07:00
2011-06-29 13:09:25 -07:00
iport - > active_phy_mask & = ~ ( 1 < < iphy - > phy_index ) ;
2012-01-04 01:33:41 -08:00
iport - > enabled_phy_mask & = ~ ( 1 < < iphy - > phy_index ) ;
2011-10-27 15:05:32 -07:00
if ( ! iport - > active_phy_mask )
iport - > last_active_phy = iphy - > phy_index ;
2011-05-10 02:28:46 -07:00
2011-06-28 15:05:53 -07:00
iphy - > max_negotiated_speed = SAS_LINK_RATE_UNKNOWN ;
2011-05-10 02:28:46 -07:00
2012-01-04 01:33:15 -08:00
/* Re-assign the phy back to the LP as if it were a narrow port for APC
* mode . For MPC mode , the phy will remain in the port .
*/
if ( iport - > owning_controller - > oem_parameters . controller . mode_type = =
SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE )
writel ( iphy - > phy_index ,
& iport - > port_pe_configuration_register [ iphy - > phy_index ] ) ;
2011-05-10 02:28:46 -07:00
if ( do_notify_user = = true )
isci_port_link_down ( ihost , iphy , iport ) ;
}
2011-06-30 19:14:33 -07:00
static void sci_port_invalid_link_up ( struct isci_port * iport , struct isci_phy * iphy )
2011-05-10 02:28:46 -07:00
{
2011-06-30 17:38:32 -07:00
struct isci_host * ihost = iport - > owning_controller ;
2011-05-10 02:28:46 -07:00
/*
* Check to see if we have alreay reported this link as bad and if
* not go ahead and tell the SCI_USER that we have discovered an
* invalid link .
*/
2011-06-30 17:38:32 -07:00
if ( ( ihost - > invalid_phy_mask & ( 1 < < iphy - > phy_index ) ) = = 0 ) {
2011-07-01 02:25:15 -07:00
ihost - > invalid_phy_mask | = 1 < < iphy - > phy_index ;
2011-06-30 17:38:32 -07:00
dev_warn ( & ihost - > pdev - > dev , " Invalid link up! \n " ) ;
2011-05-10 02:28:46 -07:00
}
}
/**
2011-06-30 19:14:33 -07:00
* sci_port_general_link_up_handler - phy can be assigned to port ?
2021-03-17 09:12:22 +00:00
* @ iport : sci_port object for which has a phy that has gone link up .
* @ iphy : This is the struct isci_phy object that has gone link up .
2012-01-04 01:33:41 -08:00
* @ flags : PF_RESUME , PF_NOTIFY to sci_port_activate_phy
2011-05-10 02:28:46 -07:00
*
2012-01-04 01:33:41 -08:00
* Determine if this phy can be assigned to this port . If the phy is
* not a valid PHY for this port then the function will notify the user .
* A PHY can only be part of a port if it ' s attached SAS ADDRESS is the
* same as all other PHYs in the same port .
2011-05-10 02:28:46 -07:00
*/
2011-06-30 19:14:33 -07:00
static void sci_port_general_link_up_handler ( struct isci_port * iport ,
2012-01-04 01:33:41 -08:00
struct isci_phy * iphy ,
u8 flags )
2011-05-10 02:28:46 -07:00
{
struct sci_sas_address port_sas_address ;
struct sci_sas_address phy_sas_address ;
2011-06-30 19:14:33 -07:00
sci_port_get_attached_sas_address ( iport , & port_sas_address ) ;
sci_phy_get_attached_sas_address ( iphy , & phy_sas_address ) ;
2011-05-10 02:28:46 -07:00
/* If the SAS address of the new phy matches the SAS address of
* other phys in the port OR this is the first phy in the port ,
* then activate the phy and allow it to be used for operations
* in this port .
*/
if ( ( phy_sas_address . high = = port_sas_address . high & &
phy_sas_address . low = = port_sas_address . low ) | |
2011-06-29 13:09:25 -07:00
iport - > active_phy_mask = = 0 ) {
struct sci_base_state_machine * sm = & iport - > sm ;
2011-05-10 02:28:46 -07:00
2012-01-04 01:33:41 -08:00
sci_port_activate_phy ( iport , iphy , flags ) ;
2011-06-02 00:10:43 +00:00
if ( sm - > current_state_id = = SCI_PORT_RESETTING )
2011-06-29 13:09:25 -07:00
port_state_machine_change ( iport , SCI_PORT_READY ) ;
2011-05-10 02:28:46 -07:00
} else
2011-06-30 19:14:33 -07:00
sci_port_invalid_link_up ( iport , iphy ) ;
2011-05-10 02:28:46 -07:00
}
/**
2021-03-17 09:12:22 +00:00
* sci_port_is_wide ( )
2011-05-10 02:28:46 -07:00
* This method returns false if the port only has a single phy object assigned .
* If there are no phys or more than one phy then the method will return
* true .
2021-03-17 09:12:22 +00:00
* @ iport : The port for which the wide port condition is to be checked .
2011-05-10 02:28:46 -07:00
*
* bool true Is returned if this is a wide ported port . false Is returned if
* this is a narrow port .
*/
2011-06-30 19:14:33 -07:00
static bool sci_port_is_wide ( struct isci_port * iport )
2011-05-10 02:28:46 -07:00
{
u32 index ;
u32 phy_count = 0 ;
for ( index = 0 ; index < SCI_MAX_PHYS ; index + + ) {
2011-06-29 13:09:25 -07:00
if ( iport - > phy_table [ index ] ! = NULL ) {
2011-05-10 02:28:46 -07:00
phy_count + + ;
}
}
return phy_count ! = 1 ;
}
/**
2021-03-17 09:12:22 +00:00
* sci_port_link_detected ( )
2011-05-10 02:28:46 -07:00
* This method is called by the PHY object when the link is detected . if the
* port wants the PHY to continue on to the link up state then the port
* layer must return true . If the port object returns false the phy object
* must halt its attempt to go link up .
2021-03-17 09:12:22 +00:00
* @ iport : The port associated with the phy object .
* @ iphy : The phy object that is trying to go link up .
2011-05-10 02:28:46 -07:00
*
* true if the phy object can continue to the link up condition . true Is
* returned if this phy can continue to the ready state . false Is returned if
* can not continue on to the ready state . This notification is in place for
* wide ports and direct attached phys . Since there are no wide ported SATA
* devices this could become an invalid port configuration .
*/
2012-02-01 00:44:14 -08:00
bool sci_port_link_detected ( struct isci_port * iport , struct isci_phy * iphy )
2011-05-10 02:28:46 -07:00
{
2011-06-29 13:09:25 -07:00
if ( ( iport - > logical_port_index ! = SCIC_SDS_DUMMY_PORT ) & &
2012-02-01 00:44:14 -08:00
( iphy - > protocol = = SAS_PROTOCOL_SATA ) ) {
2012-01-04 01:33:41 -08:00
if ( sci_port_is_wide ( iport ) ) {
sci_port_invalid_link_up ( iport , iphy ) ;
return false ;
} else {
struct isci_host * ihost = iport - > owning_controller ;
struct isci_port * dst_port = & ( ihost - > ports [ iphy - > phy_index ] ) ;
writel ( iphy - > phy_index ,
& dst_port - > port_pe_configuration_register [ iphy - > phy_index ] ) ;
}
2011-05-10 02:28:46 -07:00
}
return true ;
}
2017-09-01 23:21:24 -07:00
static void port_timeout ( struct timer_list * t )
2011-05-10 02:28:46 -07:00
{
2017-09-01 23:21:24 -07:00
struct sci_timer * tmr = from_timer ( tmr , t , timer ) ;
2011-06-29 13:09:25 -07:00
struct isci_port * iport = container_of ( tmr , typeof ( * iport ) , timer ) ;
2011-06-30 17:38:32 -07:00
struct isci_host * ihost = iport - > owning_controller ;
2011-05-19 11:59:10 +00:00
unsigned long flags ;
2011-05-10 02:28:46 -07:00
u32 current_state ;
2011-05-19 11:59:10 +00:00
spin_lock_irqsave ( & ihost - > scic_lock , flags ) ;
if ( tmr - > cancel )
goto done ;
2011-06-29 13:09:25 -07:00
current_state = iport - > sm . current_state_id ;
2011-05-10 02:28:46 -07:00
2011-06-02 00:10:43 +00:00
if ( current_state = = SCI_PORT_RESETTING ) {
2011-05-11 23:52:21 +00:00
/* if the port is still in the resetting state then the timeout
* fired before the reset completed .
2011-05-10 02:28:46 -07:00
*/
2011-06-29 13:09:25 -07:00
port_state_machine_change ( iport , SCI_PORT_FAILED ) ;
2011-06-02 00:10:43 +00:00
} else if ( current_state = = SCI_PORT_STOPPED ) {
2011-05-11 23:52:21 +00:00
/* if the port is stopped then the start request failed In this
* case stay in the stopped state .
2011-05-10 02:28:46 -07:00
*/
2011-06-29 13:09:25 -07:00
dev_err ( sciport_to_dev ( iport ) ,
2016-02-08 20:53:12 +09:00
" %s: SCIC Port 0x%p failed to stop before timeout. \n " ,
2011-05-10 02:28:46 -07:00
__func__ ,
2011-06-29 13:09:25 -07:00
iport ) ;
2011-06-02 00:10:43 +00:00
} else if ( current_state = = SCI_PORT_STOPPING ) {
2012-01-03 23:26:15 -08:00
dev_dbg ( sciport_to_dev ( iport ) ,
" %s: port%d: stop complete timeout \n " ,
__func__ , iport - > physical_port_index ) ;
2011-05-10 02:28:46 -07:00
} else {
2011-05-11 23:52:21 +00:00
/* The port is in the ready state and we have a timer
2011-05-10 02:28:46 -07:00
* reporting a timeout this should not happen .
*/
2011-06-29 13:09:25 -07:00
dev_err ( sciport_to_dev ( iport ) ,
2011-05-10 02:28:46 -07:00
" %s: SCIC Port 0x%p is processing a timeout operation "
2011-06-29 13:09:25 -07:00
" in state %d. \n " , __func__ , iport , current_state ) ;
2011-05-10 02:28:46 -07:00
}
2011-05-19 11:59:10 +00:00
done :
spin_unlock_irqrestore ( & ihost - > scic_lock , flags ) ;
2011-05-10 02:28:46 -07:00
}
/* --------------------------------------------------------------------------- */
2021-03-17 09:12:22 +00:00
/*
2011-05-10 02:28:46 -07:00
* This function updates the hardwares VIIT entry for this port .
*/
2011-06-30 19:14:33 -07:00
static void sci_port_update_viit_entry ( struct isci_port * iport )
2011-05-10 02:28:46 -07:00
{
struct sci_sas_address sas_address ;
2011-06-30 19:14:33 -07:00
sci_port_get_sas_address ( iport , & sas_address ) ;
2011-05-10 02:28:46 -07:00
writel ( sas_address . high ,
2011-06-29 13:09:25 -07:00
& iport - > viit_registers - > initiator_sas_address_hi ) ;
2011-05-10 02:28:46 -07:00
writel ( sas_address . low ,
2011-06-29 13:09:25 -07:00
& iport - > viit_registers - > initiator_sas_address_lo ) ;
2011-05-10 02:28:46 -07:00
/* This value get cleared just in case its not already cleared */
2011-06-29 13:09:25 -07:00
writel ( 0 , & iport - > viit_registers - > reserved ) ;
2011-05-10 02:28:46 -07:00
/* We are required to update the status register last */
writel ( SCU_VIIT_ENTRY_ID_VIIT |
SCU_VIIT_IPPT_INITIATOR |
2011-06-29 13:09:25 -07:00
( ( 1 < < iport - > physical_port_index ) < < SCU_VIIT_ENTRY_LPVIE_SHIFT ) |
2011-05-10 02:28:46 -07:00
SCU_VIIT_STATUS_ALL_VALID ,
2011-06-29 13:09:25 -07:00
& iport - > viit_registers - > status ) ;
2011-05-10 02:28:46 -07:00
}
2011-06-30 19:14:33 -07:00
enum sas_linkrate sci_port_get_max_allowed_speed ( struct isci_port * iport )
2011-05-10 02:28:46 -07:00
{
u16 index ;
2011-06-28 15:05:53 -07:00
struct isci_phy * iphy ;
2011-05-10 02:28:46 -07:00
enum sas_linkrate max_allowed_speed = SAS_LINK_RATE_6_0_GBPS ;
/*
* Loop through all of the phys in this port and find the phy with the
* lowest maximum link rate . */
for ( index = 0 ; index < SCI_MAX_PHYS ; index + + ) {
2011-06-29 13:09:25 -07:00
iphy = iport - > phy_table [ index ] ;
2011-06-30 19:14:33 -07:00
if ( iphy & & sci_port_active_phy ( iport , iphy ) & &
2011-06-28 15:05:53 -07:00
iphy - > max_negotiated_speed < max_allowed_speed )
max_allowed_speed = iphy - > max_negotiated_speed ;
2011-05-10 02:28:46 -07:00
}
return max_allowed_speed ;
}
2011-06-30 19:14:33 -07:00
static void sci_port_suspend_port_task_scheduler ( struct isci_port * iport )
2011-05-10 02:28:46 -07:00
{
u32 pts_control_value ;
2011-06-29 13:09:25 -07:00
pts_control_value = readl ( & iport - > port_task_scheduler_registers - > control ) ;
2011-05-10 02:28:46 -07:00
pts_control_value | = SCU_PTSxCR_GEN_BIT ( SUSPEND ) ;
2011-06-29 13:09:25 -07:00
writel ( pts_control_value , & iport - > port_task_scheduler_registers - > control ) ;
2011-05-10 02:28:46 -07:00
}
/**
2011-06-30 19:14:33 -07:00
* sci_port_post_dummy_request ( ) - post dummy / workaround request
2021-03-17 09:12:22 +00:00
* @ iport : port to post task
2011-05-10 02:28:46 -07:00
*
* Prevent the hardware scheduler from posting new requests to the front
* of the scheduler queue causing a starvation problem for currently
* ongoing requests .
*
*/
2011-06-30 19:14:33 -07:00
static void sci_port_post_dummy_request ( struct isci_port * iport )
2011-05-10 02:28:46 -07:00
{
2011-06-30 17:38:32 -07:00
struct isci_host * ihost = iport - > owning_controller ;
2011-06-29 13:09:25 -07:00
u16 tag = iport - > reserved_tag ;
2011-06-28 13:47:09 -07:00
struct scu_task_context * tc ;
u32 command ;
2011-05-10 02:28:46 -07:00
2011-06-30 17:38:32 -07:00
tc = & ihost - > task_context_table [ ISCI_TAG_TCI ( tag ) ] ;
2011-06-28 13:47:09 -07:00
tc - > abort = 0 ;
2011-05-10 02:28:46 -07:00
command = SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC |
2011-06-29 13:09:25 -07:00
iport - > physical_port_index < < SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT |
2011-06-28 13:47:09 -07:00
ISCI_TAG_TCI ( tag ) ;
2011-05-10 02:28:46 -07:00
2011-06-30 19:14:33 -07:00
sci_controller_post_request ( ihost , command ) ;
2011-05-10 02:28:46 -07:00
}
/**
2021-03-17 09:12:22 +00:00
* sci_port_abort_dummy_request ( )
* This routine will abort the dummy request . This will allow the hardware to
2011-05-10 02:28:46 -07:00
* power down parts of the silicon to save power .
*
2021-03-17 09:12:22 +00:00
* @ iport : The port on which the task must be aborted .
2011-05-10 02:28:46 -07:00
*
*/
2011-06-30 19:14:33 -07:00
static void sci_port_abort_dummy_request ( struct isci_port * iport )
2011-05-10 02:28:46 -07:00
{
2011-06-30 17:38:32 -07:00
struct isci_host * ihost = iport - > owning_controller ;
2011-06-29 13:09:25 -07:00
u16 tag = iport - > reserved_tag ;
2011-05-10 02:28:46 -07:00
struct scu_task_context * tc ;
u32 command ;
2011-06-30 17:38:32 -07:00
tc = & ihost - > task_context_table [ ISCI_TAG_TCI ( tag ) ] ;
2011-05-10 02:28:46 -07:00
tc - > abort = 1 ;
command = SCU_CONTEXT_COMMAND_REQUEST_POST_TC_ABORT |
2011-06-29 13:09:25 -07:00
iport - > physical_port_index < < SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT |
2011-06-28 13:47:09 -07:00
ISCI_TAG_TCI ( tag ) ;
2011-05-10 02:28:46 -07:00
2011-06-30 19:14:33 -07:00
sci_controller_post_request ( ihost , command ) ;
2011-05-10 02:28:46 -07:00
}
/**
2021-03-17 09:12:22 +00:00
* sci_port_resume_port_task_scheduler ( )
* @ iport : This is the struct isci_port object to resume .
2011-05-10 02:28:46 -07:00
*
* This method will resume the port task scheduler for this port object . none
*/
static void
2011-06-30 19:14:33 -07:00
sci_port_resume_port_task_scheduler ( struct isci_port * iport )
2011-05-10 02:28:46 -07:00
{
u32 pts_control_value ;
2011-06-29 13:09:25 -07:00
pts_control_value = readl ( & iport - > port_task_scheduler_registers - > control ) ;
2011-05-10 02:28:46 -07:00
pts_control_value & = ~ SCU_PTSxCR_GEN_BIT ( SUSPEND ) ;
2011-06-29 13:09:25 -07:00
writel ( pts_control_value , & iport - > port_task_scheduler_registers - > control ) ;
2011-05-10 02:28:46 -07:00
}
2011-06-30 19:14:33 -07:00
static void sci_port_ready_substate_waiting_enter ( struct sci_base_state_machine * sm )
2011-05-10 02:28:46 -07:00
{
2011-06-29 13:09:25 -07:00
struct isci_port * iport = container_of ( sm , typeof ( * iport ) , sm ) ;
2011-05-10 02:28:46 -07:00
2011-06-30 19:14:33 -07:00
sci_port_suspend_port_task_scheduler ( iport ) ;
2011-05-10 02:28:46 -07:00
2011-06-29 13:09:25 -07:00
iport - > not_ready_reason = SCIC_PORT_NOT_READY_NO_ACTIVE_PHYS ;
2011-05-10 02:28:46 -07:00
2011-06-29 13:09:25 -07:00
if ( iport - > active_phy_mask ! = 0 ) {
2011-05-10 02:28:46 -07:00
/* At least one of the phys on the port is ready */
2011-06-29 13:09:25 -07:00
port_state_machine_change ( iport ,
2011-06-02 00:10:43 +00:00
SCI_PORT_SUB_OPERATIONAL ) ;
2011-05-10 02:28:46 -07:00
}
}
2012-01-04 01:33:41 -08:00
static void scic_sds_port_ready_substate_waiting_exit (
struct sci_base_state_machine * sm )
{
struct isci_port * iport = container_of ( sm , typeof ( * iport ) , sm ) ;
sci_port_resume_port_task_scheduler ( iport ) ;
}
2011-06-30 19:14:33 -07:00
static void sci_port_ready_substate_operational_enter ( struct sci_base_state_machine * sm )
2011-05-10 02:28:46 -07:00
{
u32 index ;
2011-06-29 13:09:25 -07:00
struct isci_port * iport = container_of ( sm , typeof ( * iport ) , sm ) ;
2011-06-30 17:38:32 -07:00
struct isci_host * ihost = iport - > owning_controller ;
2011-05-10 02:28:46 -07:00
2012-01-03 23:26:15 -08:00
dev_dbg ( & ihost - > pdev - > dev , " %s: port%d ready \n " ,
__func__ , iport - > physical_port_index ) ;
2011-05-10 02:28:46 -07:00
for ( index = 0 ; index < SCI_MAX_PHYS ; index + + ) {
2011-06-29 13:09:25 -07:00
if ( iport - > phy_table [ index ] ) {
writel ( iport - > physical_port_index ,
& iport - > port_pe_configuration_register [
iport - > phy_table [ index ] - > phy_index ] ) ;
2012-01-04 01:33:41 -08:00
if ( ( ( iport - > active_phy_mask ^ iport - > enabled_phy_mask ) & ( 1 < < index ) ) ! = 0 )
sci_port_resume_phy ( iport , iport - > phy_table [ index ] ) ;
2011-05-10 02:28:46 -07:00
}
}
2011-06-30 19:14:33 -07:00
sci_port_update_viit_entry ( iport ) ;
2011-05-10 02:28:46 -07:00
/*
* Post the dummy task for the port so the hardware can schedule
* io correctly
*/
2011-06-30 19:14:33 -07:00
sci_port_post_dummy_request ( iport ) ;
2011-05-10 02:28:46 -07:00
}
2011-06-30 19:14:33 -07:00
static void sci_port_invalidate_dummy_remote_node ( struct isci_port * iport )
2011-05-11 23:52:21 +00:00
{
2011-06-30 17:38:32 -07:00
struct isci_host * ihost = iport - > owning_controller ;
2011-06-29 13:09:25 -07:00
u8 phys_index = iport - > physical_port_index ;
2011-05-11 23:52:21 +00:00
union scu_remote_node_context * rnc ;
2011-06-29 13:09:25 -07:00
u16 rni = iport - > reserved_rni ;
2011-05-11 23:52:21 +00:00
u32 command ;
2011-06-30 17:38:32 -07:00
rnc = & ihost - > remote_node_context_table [ rni ] ;
2011-05-11 23:52:21 +00:00
rnc - > ssp . is_valid = false ;
/* ensure the preceding tc abort request has reached the
* controller and give it ample time to act before posting the rnc
* invalidate
*/
2011-06-30 17:38:32 -07:00
readl ( & ihost - > smu_registers - > interrupt_status ) ; /* flush */
2011-05-11 23:52:21 +00:00
udelay ( 10 ) ;
command = SCU_CONTEXT_COMMAND_POST_RNC_INVALIDATE |
phys_index < < SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT | rni ;
2011-06-30 19:14:33 -07:00
sci_controller_post_request ( ihost , command ) ;
2011-05-11 23:52:21 +00:00
}
2011-05-10 02:28:46 -07:00
/**
2021-03-17 09:12:22 +00:00
* sci_port_ready_substate_operational_exit ( )
* @ sm : This is the object which is cast to a struct isci_port object .
2011-05-10 02:28:46 -07:00
*
2011-06-29 13:09:25 -07:00
* This method will perform the actions required by the struct isci_port on
2011-06-02 00:10:43 +00:00
* exiting the SCI_PORT_SUB_OPERATIONAL . This function reports
2011-05-10 02:28:46 -07:00
* the port not ready and suspends the port task scheduler . none
*/
2011-06-30 19:14:33 -07:00
static void sci_port_ready_substate_operational_exit ( struct sci_base_state_machine * sm )
2011-05-10 02:28:46 -07:00
{
2011-06-29 13:09:25 -07:00
struct isci_port * iport = container_of ( sm , typeof ( * iport ) , sm ) ;
2011-06-30 17:38:32 -07:00
struct isci_host * ihost = iport - > owning_controller ;
2011-05-10 02:28:46 -07:00
/*
* Kill the dummy task for this port if it has not yet posted
* the hardware will treat this as a NOP and just return abort
* complete .
*/
2011-06-30 19:14:33 -07:00
sci_port_abort_dummy_request ( iport ) ;
2011-05-10 02:28:46 -07:00
2012-01-03 23:26:15 -08:00
dev_dbg ( & ihost - > pdev - > dev , " %s: port%d !ready \n " ,
__func__ , iport - > physical_port_index ) ;
2011-05-11 23:52:21 +00:00
2011-06-29 13:09:25 -07:00
if ( iport - > ready_exit )
2011-06-30 19:14:33 -07:00
sci_port_invalidate_dummy_remote_node ( iport ) ;
2011-05-10 02:28:46 -07:00
}
2011-06-30 19:14:33 -07:00
static void sci_port_ready_substate_configuring_enter ( struct sci_base_state_machine * sm )
2011-05-10 02:28:46 -07:00
{
2011-06-29 13:09:25 -07:00
struct isci_port * iport = container_of ( sm , typeof ( * iport ) , sm ) ;
2011-06-30 17:38:32 -07:00
struct isci_host * ihost = iport - > owning_controller ;
2011-05-10 02:28:46 -07:00
2011-06-29 13:09:25 -07:00
if ( iport - > active_phy_mask = = 0 ) {
2012-01-03 23:26:15 -08:00
dev_dbg ( & ihost - > pdev - > dev , " %s: port%d !ready \n " ,
__func__ , iport - > physical_port_index ) ;
2011-05-10 02:28:46 -07:00
2012-01-04 01:33:41 -08:00
port_state_machine_change ( iport , SCI_PORT_SUB_WAITING ) ;
} else
port_state_machine_change ( iport , SCI_PORT_SUB_OPERATIONAL ) ;
2011-05-10 02:28:46 -07:00
}
2011-06-30 19:14:33 -07:00
enum sci_status sci_port_start ( struct isci_port * iport )
2011-05-11 23:52:26 +00:00
{
2011-06-30 17:38:32 -07:00
struct isci_host * ihost = iport - > owning_controller ;
2011-05-11 23:52:26 +00:00
enum sci_status status = SCI_SUCCESS ;
2011-06-30 19:14:33 -07:00
enum sci_port_states state ;
2011-05-11 23:52:26 +00:00
u32 phy_mask ;
2011-06-29 13:09:25 -07:00
state = iport - > sm . current_state_id ;
2011-06-02 00:10:43 +00:00
if ( state ! = SCI_PORT_STOPPED ) {
2012-02-10 01:18:44 -08:00
dev_warn ( sciport_to_dev ( iport ) , " %s: in wrong state: %s \n " ,
__func__ , port_state_name ( state ) ) ;
2011-05-11 23:52:26 +00:00
return SCI_FAILURE_INVALID_STATE ;
}
2011-06-29 13:09:25 -07:00
if ( iport - > assigned_device_count > 0 ) {
2011-05-11 23:52:26 +00:00
/* TODO This is a start failure operation because
* there are still devices assigned to this port .
* There must be no devices assigned to a port on a
* start operation .
*/
return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION ;
}
2011-06-29 13:09:25 -07:00
if ( iport - > reserved_rni = = SCU_DUMMY_INDEX ) {
2011-06-30 19:14:33 -07:00
u16 rni = sci_remote_node_table_allocate_remote_node (
2011-06-30 17:38:32 -07:00
& ihost - > available_remote_nodes , 1 ) ;
2011-05-11 23:52:26 +00:00
if ( rni ! = SCU_DUMMY_INDEX )
2011-06-30 19:14:33 -07:00
sci_port_construct_dummy_rnc ( iport , rni ) ;
2011-05-11 23:52:26 +00:00
else
status = SCI_FAILURE_INSUFFICIENT_RESOURCES ;
2011-06-29 13:09:25 -07:00
iport - > reserved_rni = rni ;
2011-05-11 23:52:26 +00:00
}
2011-06-29 13:09:25 -07:00
if ( iport - > reserved_tag = = SCI_CONTROLLER_INVALID_IO_TAG ) {
2011-06-28 13:47:09 -07:00
u16 tag ;
2011-05-11 23:52:26 +00:00
2011-06-28 13:47:09 -07:00
tag = isci_alloc_tag ( ihost ) ;
if ( tag = = SCI_CONTROLLER_INVALID_IO_TAG )
2011-05-11 23:52:26 +00:00
status = SCI_FAILURE_INSUFFICIENT_RESOURCES ;
2011-06-28 13:47:09 -07:00
else
2011-06-30 19:14:33 -07:00
sci_port_construct_dummy_task ( iport , tag ) ;
2011-06-29 13:09:25 -07:00
iport - > reserved_tag = tag ;
2011-05-11 23:52:26 +00:00
}
if ( status = = SCI_SUCCESS ) {
2011-06-30 19:14:33 -07:00
phy_mask = sci_port_get_phys ( iport ) ;
2011-05-11 23:52:26 +00:00
/*
* There are one or more phys assigned to this port . Make sure
* the port ' s phy mask is in fact legal and supported by the
* silicon .
*/
2011-06-30 19:14:33 -07:00
if ( sci_port_is_phy_mask_valid ( iport , phy_mask ) = = true ) {
2011-06-29 13:09:25 -07:00
port_state_machine_change ( iport ,
2011-06-02 00:10:43 +00:00
SCI_PORT_READY ) ;
2011-05-11 23:52:26 +00:00
return SCI_SUCCESS ;
}
status = SCI_FAILURE ;
}
if ( status ! = SCI_SUCCESS )
2011-06-30 19:14:33 -07:00
sci_port_destroy_dummy_resources ( iport ) ;
2011-05-11 23:52:26 +00:00
return status ;
}
2011-06-30 19:14:33 -07:00
enum sci_status sci_port_stop ( struct isci_port * iport )
2011-05-11 23:52:31 +00:00
{
2011-06-30 19:14:33 -07:00
enum sci_port_states state ;
2011-05-11 23:52:31 +00:00
2011-06-29 13:09:25 -07:00
state = iport - > sm . current_state_id ;
2011-05-11 23:52:31 +00:00
switch ( state ) {
2011-06-02 00:10:43 +00:00
case SCI_PORT_STOPPED :
2011-05-11 23:52:31 +00:00
return SCI_SUCCESS ;
2011-06-02 00:10:43 +00:00
case SCI_PORT_SUB_WAITING :
case SCI_PORT_SUB_OPERATIONAL :
case SCI_PORT_SUB_CONFIGURING :
case SCI_PORT_RESETTING :
2011-06-29 13:09:25 -07:00
port_state_machine_change ( iport ,
2011-06-02 00:10:43 +00:00
SCI_PORT_STOPPING ) ;
2011-05-11 23:52:31 +00:00
return SCI_SUCCESS ;
default :
2012-02-10 01:18:44 -08:00
dev_warn ( sciport_to_dev ( iport ) , " %s: in wrong state: %s \n " ,
__func__ , port_state_name ( state ) ) ;
2011-05-11 23:52:31 +00:00
return SCI_FAILURE_INVALID_STATE ;
}
}
2011-06-30 19:14:33 -07:00
static enum sci_status sci_port_hard_reset ( struct isci_port * iport , u32 timeout )
2011-05-12 19:10:03 +00:00
{
enum sci_status status = SCI_FAILURE_INVALID_PHY ;
2011-06-28 15:05:53 -07:00
struct isci_phy * iphy = NULL ;
2011-06-30 19:14:33 -07:00
enum sci_port_states state ;
2011-05-12 19:10:03 +00:00
u32 phy_index ;
2011-06-29 13:09:25 -07:00
state = iport - > sm . current_state_id ;
2011-06-02 00:10:43 +00:00
if ( state ! = SCI_PORT_SUB_OPERATIONAL ) {
2012-02-10 01:18:44 -08:00
dev_warn ( sciport_to_dev ( iport ) , " %s: in wrong state: %s \n " ,
__func__ , port_state_name ( state ) ) ;
2011-05-12 19:10:03 +00:00
return SCI_FAILURE_INVALID_STATE ;
}
/* Select a phy on which we can send the hard reset request. */
2011-06-28 15:05:53 -07:00
for ( phy_index = 0 ; phy_index < SCI_MAX_PHYS & & ! iphy ; phy_index + + ) {
2011-06-29 13:09:25 -07:00
iphy = iport - > phy_table [ phy_index ] ;
2011-06-30 19:14:33 -07:00
if ( iphy & & ! sci_port_active_phy ( iport , iphy ) ) {
2011-05-12 19:10:03 +00:00
/*
* We found a phy but it is not ready select
* different phy
*/
2011-06-28 15:05:53 -07:00
iphy = NULL ;
2011-05-12 19:10:03 +00:00
}
}
/* If we have a phy then go ahead and start the reset procedure */
2011-06-28 15:05:53 -07:00
if ( ! iphy )
2011-05-12 19:10:03 +00:00
return status ;
2011-06-30 19:14:33 -07:00
status = sci_phy_reset ( iphy ) ;
2011-05-12 19:10:03 +00:00
if ( status ! = SCI_SUCCESS )
return status ;
2011-06-29 13:09:25 -07:00
sci_mod_timer ( & iport - > timer , timeout ) ;
iport - > not_ready_reason = SCIC_PORT_NOT_READY_HARD_RESET_REQUESTED ;
2011-05-12 19:10:03 +00:00
2011-06-29 13:09:25 -07:00
port_state_machine_change ( iport , SCI_PORT_RESETTING ) ;
2011-05-12 19:10:03 +00:00
return SCI_SUCCESS ;
}
/**
2021-03-17 09:12:22 +00:00
* sci_port_add_phy ( )
* @ iport : This parameter specifies the port in which the phy will be added .
* @ iphy : This parameter is the phy which is to be added to the port .
2011-05-12 19:10:03 +00:00
*
* This method will add a PHY to the selected port . This method returns an
* enum sci_status . SCI_SUCCESS the phy has been added to the port . Any other
* status is a failure to add the phy to the port .
*/
2011-06-30 19:14:33 -07:00
enum sci_status sci_port_add_phy ( struct isci_port * iport ,
2011-06-28 15:05:53 -07:00
struct isci_phy * iphy )
2011-05-12 19:10:03 +00:00
{
enum sci_status status ;
2011-06-30 19:14:33 -07:00
enum sci_port_states state ;
2011-05-12 19:10:03 +00:00
2012-03-12 23:29:30 +00:00
sci_port_bcn_enable ( iport ) ;
2011-06-29 13:09:25 -07:00
state = iport - > sm . current_state_id ;
2011-05-12 19:10:03 +00:00
switch ( state ) {
2011-06-02 00:10:43 +00:00
case SCI_PORT_STOPPED : {
2011-05-12 19:10:03 +00:00
struct sci_sas_address port_sas_address ;
/* Read the port assigned SAS Address if there is one */
2011-06-30 19:14:33 -07:00
sci_port_get_sas_address ( iport , & port_sas_address ) ;
2011-05-12 19:10:03 +00:00
if ( port_sas_address . high ! = 0 & & port_sas_address . low ! = 0 ) {
struct sci_sas_address phy_sas_address ;
/* Make sure that the PHY SAS Address matches the SAS Address
* for this port
*/
2011-06-30 19:14:33 -07:00
sci_phy_get_sas_address ( iphy , & phy_sas_address ) ;
2011-05-12 19:10:03 +00:00
if ( port_sas_address . high ! = phy_sas_address . high | |
port_sas_address . low ! = phy_sas_address . low )
return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION ;
}
2011-06-30 19:14:33 -07:00
return sci_port_set_phy ( iport , iphy ) ;
2011-05-12 19:10:03 +00:00
}
2011-06-02 00:10:43 +00:00
case SCI_PORT_SUB_WAITING :
case SCI_PORT_SUB_OPERATIONAL :
2011-06-30 19:14:33 -07:00
status = sci_port_set_phy ( iport , iphy ) ;
2011-05-12 19:10:03 +00:00
if ( status ! = SCI_SUCCESS )
return status ;
2012-01-04 01:33:41 -08:00
sci_port_general_link_up_handler ( iport , iphy , PF_NOTIFY | PF_RESUME ) ;
2011-06-29 13:09:25 -07:00
iport - > not_ready_reason = SCIC_PORT_NOT_READY_RECONFIGURING ;
port_state_machine_change ( iport , SCI_PORT_SUB_CONFIGURING ) ;
2011-05-12 19:10:03 +00:00
return status ;
2011-06-02 00:10:43 +00:00
case SCI_PORT_SUB_CONFIGURING :
2011-06-30 19:14:33 -07:00
status = sci_port_set_phy ( iport , iphy ) ;
2011-05-12 19:10:03 +00:00
if ( status ! = SCI_SUCCESS )
return status ;
2012-01-04 01:33:41 -08:00
sci_port_general_link_up_handler ( iport , iphy , PF_NOTIFY ) ;
2011-05-12 19:10:03 +00:00
/* Re-enter the configuring state since this may be the last phy in
* the port .
*/
2011-06-29 13:09:25 -07:00
port_state_machine_change ( iport ,
2011-06-02 00:10:43 +00:00
SCI_PORT_SUB_CONFIGURING ) ;
2011-05-12 19:10:03 +00:00
return SCI_SUCCESS ;
default :
2012-02-10 01:18:44 -08:00
dev_warn ( sciport_to_dev ( iport ) , " %s: in wrong state: %s \n " ,
__func__ , port_state_name ( state ) ) ;
2011-05-12 19:10:03 +00:00
return SCI_FAILURE_INVALID_STATE ;
}
}
/**
2021-03-17 09:12:22 +00:00
* sci_port_remove_phy ( )
* @ iport : This parameter specifies the port in which the phy will be added .
* @ iphy : This parameter is the phy which is to be added to the port .
2011-05-12 19:10:03 +00:00
*
* This method will remove the PHY from the selected PORT . This method returns
* an enum sci_status . SCI_SUCCESS the phy has been removed from the port . Any
* other status is a failure to add the phy to the port .
*/
2011-06-30 19:14:33 -07:00
enum sci_status sci_port_remove_phy ( struct isci_port * iport ,
2011-06-28 15:05:53 -07:00
struct isci_phy * iphy )
2011-05-12 19:10:03 +00:00
{
enum sci_status status ;
2011-06-30 19:14:33 -07:00
enum sci_port_states state ;
2011-05-12 19:10:03 +00:00
2011-06-29 13:09:25 -07:00
state = iport - > sm . current_state_id ;
2011-05-12 19:10:03 +00:00
switch ( state ) {
2011-06-02 00:10:43 +00:00
case SCI_PORT_STOPPED :
2011-06-30 19:14:33 -07:00
return sci_port_clear_phy ( iport , iphy ) ;
2011-06-02 00:10:43 +00:00
case SCI_PORT_SUB_OPERATIONAL :
2011-06-30 19:14:33 -07:00
status = sci_port_clear_phy ( iport , iphy ) ;
2011-05-12 19:10:03 +00:00
if ( status ! = SCI_SUCCESS )
return status ;
2011-06-30 19:14:33 -07:00
sci_port_deactivate_phy ( iport , iphy , true ) ;
2011-06-29 13:09:25 -07:00
iport - > not_ready_reason = SCIC_PORT_NOT_READY_RECONFIGURING ;
port_state_machine_change ( iport ,
2011-06-02 00:10:43 +00:00
SCI_PORT_SUB_CONFIGURING ) ;
2011-05-12 19:10:03 +00:00
return SCI_SUCCESS ;
2011-06-02 00:10:43 +00:00
case SCI_PORT_SUB_CONFIGURING :
2011-06-30 19:14:33 -07:00
status = sci_port_clear_phy ( iport , iphy ) ;
2011-05-12 19:10:03 +00:00
if ( status ! = SCI_SUCCESS )
return status ;
2011-06-30 19:14:33 -07:00
sci_port_deactivate_phy ( iport , iphy , true ) ;
2011-05-12 19:10:03 +00:00
/* Re-enter the configuring state since this may be the last phy in
* the port
*/
2011-06-29 13:09:25 -07:00
port_state_machine_change ( iport ,
2011-06-02 00:10:43 +00:00
SCI_PORT_SUB_CONFIGURING ) ;
2011-05-12 19:10:14 +00:00
return SCI_SUCCESS ;
default :
2012-02-10 01:18:44 -08:00
dev_warn ( sciport_to_dev ( iport ) , " %s: in wrong state: %s \n " ,
__func__ , port_state_name ( state ) ) ;
2011-05-12 19:10:14 +00:00
return SCI_FAILURE_INVALID_STATE ;
}
}
2011-05-12 19:10:03 +00:00
2011-06-30 19:14:33 -07:00
enum sci_status sci_port_link_up ( struct isci_port * iport ,
2011-06-28 15:05:53 -07:00
struct isci_phy * iphy )
2011-05-12 19:10:14 +00:00
{
2011-06-30 19:14:33 -07:00
enum sci_port_states state ;
2011-05-12 19:10:14 +00:00
2011-06-29 13:09:25 -07:00
state = iport - > sm . current_state_id ;
2011-05-12 19:10:14 +00:00
switch ( state ) {
2011-06-02 00:10:43 +00:00
case SCI_PORT_SUB_WAITING :
2011-05-12 19:10:14 +00:00
/* Since this is the first phy going link up for the port we
* can just enable it and continue
*/
2012-01-04 01:33:41 -08:00
sci_port_activate_phy ( iport , iphy , PF_NOTIFY | PF_RESUME ) ;
2011-05-12 19:10:14 +00:00
2011-06-29 13:09:25 -07:00
port_state_machine_change ( iport ,
2011-06-02 00:10:43 +00:00
SCI_PORT_SUB_OPERATIONAL ) ;
2011-05-12 19:10:14 +00:00
return SCI_SUCCESS ;
2011-06-02 00:10:43 +00:00
case SCI_PORT_SUB_OPERATIONAL :
2012-01-04 01:33:41 -08:00
sci_port_general_link_up_handler ( iport , iphy , PF_NOTIFY | PF_RESUME ) ;
2011-05-12 19:10:14 +00:00
return SCI_SUCCESS ;
2011-06-02 00:10:43 +00:00
case SCI_PORT_RESETTING :
2011-05-12 19:10:14 +00:00
/* TODO We should make sure that the phy that has gone
* link up is the same one on which we sent the reset . It is
* possible that the phy on which we sent the reset is not the
* one that has gone link up and we want to make sure that
* phy being reset comes back . Consider the case where a
* reset is sent but before the hardware processes the reset it
* get a link up on the port because of a hot plug event .
* because of the reset request this phy will go link down
* almost immediately .
*/
/* In the resetting state we don't notify the user regarding
* link up and link down notifications .
*/
2012-01-04 01:33:41 -08:00
sci_port_general_link_up_handler ( iport , iphy , PF_RESUME ) ;
2011-05-12 19:10:14 +00:00
return SCI_SUCCESS ;
default :
2012-02-10 01:18:44 -08:00
dev_warn ( sciport_to_dev ( iport ) , " %s: in wrong state: %s \n " ,
__func__ , port_state_name ( state ) ) ;
2011-05-12 19:10:14 +00:00
return SCI_FAILURE_INVALID_STATE ;
}
}
2011-06-30 19:14:33 -07:00
enum sci_status sci_port_link_down ( struct isci_port * iport ,
2011-06-28 15:05:53 -07:00
struct isci_phy * iphy )
2011-05-12 19:10:14 +00:00
{
2011-06-30 19:14:33 -07:00
enum sci_port_states state ;
2011-05-12 19:10:14 +00:00
2011-06-29 13:09:25 -07:00
state = iport - > sm . current_state_id ;
2011-05-12 19:10:14 +00:00
switch ( state ) {
2011-06-02 00:10:43 +00:00
case SCI_PORT_SUB_OPERATIONAL :
2011-06-30 19:14:33 -07:00
sci_port_deactivate_phy ( iport , iphy , true ) ;
2011-05-12 19:10:14 +00:00
/* If there are no active phys left in the port, then
* transition the port to the WAITING state until such time
* as a phy goes link up
*/
2011-06-29 13:09:25 -07:00
if ( iport - > active_phy_mask = = 0 )
port_state_machine_change ( iport ,
2011-06-02 00:10:43 +00:00
SCI_PORT_SUB_WAITING ) ;
2011-05-12 19:10:14 +00:00
return SCI_SUCCESS ;
2011-06-02 00:10:43 +00:00
case SCI_PORT_RESETTING :
2011-05-12 19:10:14 +00:00
/* In the resetting state we don't notify the user regarding
* link up and link down notifications . */
2011-06-30 19:14:33 -07:00
sci_port_deactivate_phy ( iport , iphy , false ) ;
2011-05-12 19:10:03 +00:00
return SCI_SUCCESS ;
default :
2012-02-10 01:18:44 -08:00
dev_warn ( sciport_to_dev ( iport ) , " %s: in wrong state: %s \n " ,
__func__ , port_state_name ( state ) ) ;
2011-05-12 19:10:03 +00:00
return SCI_FAILURE_INVALID_STATE ;
}
}
2011-06-30 19:14:33 -07:00
enum sci_status sci_port_start_io ( struct isci_port * iport ,
struct isci_remote_device * idev ,
struct isci_request * ireq )
2011-05-12 07:16:06 -07:00
{
2011-06-30 19:14:33 -07:00
enum sci_port_states state ;
2011-05-12 07:16:06 -07:00
2011-06-29 13:09:25 -07:00
state = iport - > sm . current_state_id ;
2011-05-12 07:16:06 -07:00
switch ( state ) {
2011-06-02 00:10:43 +00:00
case SCI_PORT_SUB_WAITING :
2011-05-12 07:16:06 -07:00
return SCI_FAILURE_INVALID_STATE ;
2011-06-02 00:10:43 +00:00
case SCI_PORT_SUB_OPERATIONAL :
2011-06-29 13:09:25 -07:00
iport - > started_request_count + + ;
2011-05-12 07:16:06 -07:00
return SCI_SUCCESS ;
default :
2012-02-10 01:18:44 -08:00
dev_warn ( sciport_to_dev ( iport ) , " %s: in wrong state: %s \n " ,
__func__ , port_state_name ( state ) ) ;
2011-05-12 07:16:06 -07:00
return SCI_FAILURE_INVALID_STATE ;
2011-05-10 02:28:46 -07:00
}
2011-05-12 07:16:06 -07:00
}
2011-05-10 02:28:46 -07:00
2011-06-30 19:14:33 -07:00
enum sci_status sci_port_complete_io ( struct isci_port * iport ,
struct isci_remote_device * idev ,
struct isci_request * ireq )
2011-05-12 07:16:06 -07:00
{
2011-06-30 19:14:33 -07:00
enum sci_port_states state ;
2011-05-12 07:16:06 -07:00
2011-06-29 13:09:25 -07:00
state = iport - > sm . current_state_id ;
2011-05-12 07:16:06 -07:00
switch ( state ) {
2011-06-02 00:10:43 +00:00
case SCI_PORT_STOPPED :
2012-02-10 01:18:44 -08:00
dev_warn ( sciport_to_dev ( iport ) , " %s: in wrong state: %s \n " ,
__func__ , port_state_name ( state ) ) ;
2011-05-12 07:16:06 -07:00
return SCI_FAILURE_INVALID_STATE ;
2011-06-02 00:10:43 +00:00
case SCI_PORT_STOPPING :
2011-06-30 19:14:33 -07:00
sci_port_decrement_request_count ( iport ) ;
2011-05-12 07:16:06 -07:00
2011-06-29 13:09:25 -07:00
if ( iport - > started_request_count = = 0 )
port_state_machine_change ( iport ,
2011-06-02 00:10:43 +00:00
SCI_PORT_STOPPED ) ;
2011-05-12 07:16:06 -07:00
break ;
2011-06-02 00:10:43 +00:00
case SCI_PORT_READY :
case SCI_PORT_RESETTING :
case SCI_PORT_FAILED :
case SCI_PORT_SUB_WAITING :
case SCI_PORT_SUB_OPERATIONAL :
2011-06-30 19:14:33 -07:00
sci_port_decrement_request_count ( iport ) ;
2011-05-12 07:16:06 -07:00
break ;
2011-06-02 00:10:43 +00:00
case SCI_PORT_SUB_CONFIGURING :
2011-06-30 19:14:33 -07:00
sci_port_decrement_request_count ( iport ) ;
2011-06-29 13:09:25 -07:00
if ( iport - > started_request_count = = 0 ) {
port_state_machine_change ( iport ,
2011-06-02 00:10:43 +00:00
SCI_PORT_SUB_OPERATIONAL ) ;
2011-05-12 07:16:06 -07:00
}
break ;
}
return SCI_SUCCESS ;
}
2011-05-10 02:28:46 -07:00
2011-06-30 19:14:33 -07:00
static void sci_port_enable_port_task_scheduler ( struct isci_port * iport )
2011-05-10 02:28:46 -07:00
{
u32 pts_control_value ;
2011-06-30 19:14:33 -07:00
/* enable the port task scheduler in a suspended state */
2011-06-29 13:09:25 -07:00
pts_control_value = readl ( & iport - > port_task_scheduler_registers - > control ) ;
2011-05-10 02:28:46 -07:00
pts_control_value | = SCU_PTSxCR_GEN_BIT ( ENABLE ) | SCU_PTSxCR_GEN_BIT ( SUSPEND ) ;
2011-06-29 13:09:25 -07:00
writel ( pts_control_value , & iport - > port_task_scheduler_registers - > control ) ;
2011-05-10 02:28:46 -07:00
}
2011-06-30 19:14:33 -07:00
static void sci_port_disable_port_task_scheduler ( struct isci_port * iport )
2011-05-10 02:28:46 -07:00
{
u32 pts_control_value ;
2011-06-29 13:09:25 -07:00
pts_control_value = readl ( & iport - > port_task_scheduler_registers - > control ) ;
2011-05-10 02:28:46 -07:00
pts_control_value & =
~ ( SCU_PTSxCR_GEN_BIT ( ENABLE ) | SCU_PTSxCR_GEN_BIT ( SUSPEND ) ) ;
2011-06-29 13:09:25 -07:00
writel ( pts_control_value , & iport - > port_task_scheduler_registers - > control ) ;
2011-05-10 02:28:46 -07:00
}
2011-06-30 19:14:33 -07:00
static void sci_port_post_dummy_remote_node ( struct isci_port * iport )
2011-05-10 02:28:46 -07:00
{
2011-06-30 17:38:32 -07:00
struct isci_host * ihost = iport - > owning_controller ;
2011-06-29 13:09:25 -07:00
u8 phys_index = iport - > physical_port_index ;
2011-05-10 02:28:46 -07:00
union scu_remote_node_context * rnc ;
2011-06-29 13:09:25 -07:00
u16 rni = iport - > reserved_rni ;
2011-05-10 02:28:46 -07:00
u32 command ;
2011-06-30 17:38:32 -07:00
rnc = & ihost - > remote_node_context_table [ rni ] ;
2011-05-10 02:28:46 -07:00
rnc - > ssp . is_valid = true ;
command = SCU_CONTEXT_COMMAND_POST_RNC_32 |
phys_index < < SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT | rni ;
2011-06-30 19:14:33 -07:00
sci_controller_post_request ( ihost , command ) ;
2011-05-10 02:28:46 -07:00
/* ensure hardware has seen the post rnc command and give it
* ample time to act before sending the suspend
*/
2011-06-30 17:38:32 -07:00
readl ( & ihost - > smu_registers - > interrupt_status ) ; /* flush */
2011-05-10 02:28:46 -07:00
udelay ( 10 ) ;
command = SCU_CONTEXT_COMMAND_POST_RNC_SUSPEND_TX_RX |
phys_index < < SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT | rni ;
2011-06-30 19:14:33 -07:00
sci_controller_post_request ( ihost , command ) ;
2011-05-10 02:28:46 -07:00
}
2011-06-30 19:14:33 -07:00
static void sci_port_stopped_state_enter ( struct sci_base_state_machine * sm )
2011-05-10 02:28:46 -07:00
{
2011-06-29 13:09:25 -07:00
struct isci_port * iport = container_of ( sm , typeof ( * iport ) , sm ) ;
2011-05-10 02:28:46 -07:00
2011-06-29 13:09:25 -07:00
if ( iport - > sm . previous_state_id = = SCI_PORT_STOPPING ) {
2011-05-10 02:28:46 -07:00
/*
* If we enter this state becasuse of a request to stop
* the port then we want to disable the hardwares port
* task scheduler . */
2011-06-30 19:14:33 -07:00
sci_port_disable_port_task_scheduler ( iport ) ;
2011-05-10 02:28:46 -07:00
}
}
2011-06-30 19:14:33 -07:00
static void sci_port_stopped_state_exit ( struct sci_base_state_machine * sm )
2011-05-10 02:28:46 -07:00
{
2011-06-29 13:09:25 -07:00
struct isci_port * iport = container_of ( sm , typeof ( * iport ) , sm ) ;
2011-05-10 02:28:46 -07:00
/* Enable and suspend the port task scheduler */
2011-06-30 19:14:33 -07:00
sci_port_enable_port_task_scheduler ( iport ) ;
2011-05-10 02:28:46 -07:00
}
2011-06-30 19:14:33 -07:00
static void sci_port_ready_state_enter ( struct sci_base_state_machine * sm )
2011-05-10 02:28:46 -07:00
{
2011-06-29 13:09:25 -07:00
struct isci_port * iport = container_of ( sm , typeof ( * iport ) , sm ) ;
2011-06-30 17:38:32 -07:00
struct isci_host * ihost = iport - > owning_controller ;
2011-05-10 02:28:46 -07:00
u32 prev_state ;
2011-06-29 13:09:25 -07:00
prev_state = iport - > sm . previous_state_id ;
2011-06-02 00:10:43 +00:00
if ( prev_state = = SCI_PORT_RESETTING )
2011-05-10 02:28:46 -07:00
isci_port_hard_reset_complete ( iport , SCI_SUCCESS ) ;
else
2012-01-03 23:26:15 -08:00
dev_dbg ( & ihost - > pdev - > dev , " %s: port%d !ready \n " ,
__func__ , iport - > physical_port_index ) ;
2011-05-10 02:28:46 -07:00
/* Post and suspend the dummy remote node context for this port. */
2011-06-30 19:14:33 -07:00
sci_port_post_dummy_remote_node ( iport ) ;
2011-05-10 02:28:46 -07:00
/* Start the ready substate machine */
2011-06-29 13:09:25 -07:00
port_state_machine_change ( iport ,
2011-06-02 00:10:43 +00:00
SCI_PORT_SUB_WAITING ) ;
2011-05-10 02:28:46 -07:00
}
2011-06-30 19:14:33 -07:00
static void sci_port_resetting_state_exit ( struct sci_base_state_machine * sm )
2011-05-10 02:28:46 -07:00
{
2011-06-29 13:09:25 -07:00
struct isci_port * iport = container_of ( sm , typeof ( * iport ) , sm ) ;
2011-05-10 02:28:46 -07:00
2011-06-29 13:09:25 -07:00
sci_del_timer ( & iport - > timer ) ;
2011-05-10 02:28:46 -07:00
}
2011-06-30 19:14:33 -07:00
static void sci_port_stopping_state_exit ( struct sci_base_state_machine * sm )
2011-05-10 02:28:46 -07:00
{
2011-06-29 13:09:25 -07:00
struct isci_port * iport = container_of ( sm , typeof ( * iport ) , sm ) ;
2011-05-10 02:28:46 -07:00
2011-06-29 13:09:25 -07:00
sci_del_timer ( & iport - > timer ) ;
2011-05-10 02:28:46 -07:00
2011-06-30 19:14:33 -07:00
sci_port_destroy_dummy_resources ( iport ) ;
2011-05-10 02:28:46 -07:00
}
2011-06-30 19:14:33 -07:00
static void sci_port_failed_state_enter ( struct sci_base_state_machine * sm )
2011-05-10 02:28:46 -07:00
{
2011-06-29 13:09:25 -07:00
struct isci_port * iport = container_of ( sm , typeof ( * iport ) , sm ) ;
2011-05-10 02:28:46 -07:00
isci_port_hard_reset_complete ( iport , SCI_FAILURE_TIMEOUT ) ;
}
2012-03-08 22:41:48 -08:00
void sci_port_set_hang_detection_timeout ( struct isci_port * iport , u32 timeout )
{
int phy_index ;
u32 phy_mask = iport - > active_phy_mask ;
if ( timeout )
+ + iport - > hang_detect_users ;
else if ( iport - > hang_detect_users > 1 )
- - iport - > hang_detect_users ;
else
iport - > hang_detect_users = 0 ;
if ( timeout | | ( iport - > hang_detect_users = = 0 ) ) {
for ( phy_index = 0 ; phy_index < SCI_MAX_PHYS ; phy_index + + ) {
if ( ( phy_mask > > phy_index ) & 1 ) {
writel ( timeout ,
& iport - > phy_table [ phy_index ]
- > link_layer_registers
- > link_layer_hang_detection_timeout ) ;
}
}
}
}
2011-05-10 02:28:46 -07:00
/* --------------------------------------------------------------------------- */
2011-06-30 19:14:33 -07:00
static const struct sci_base_state sci_port_state_table [ ] = {
2011-06-02 00:10:43 +00:00
[ SCI_PORT_STOPPED ] = {
2011-06-30 19:14:33 -07:00
. enter_state = sci_port_stopped_state_enter ,
. exit_state = sci_port_stopped_state_exit
2011-05-10 02:28:46 -07:00
} ,
2011-06-02 00:10:43 +00:00
[ SCI_PORT_STOPPING ] = {
2011-06-30 19:14:33 -07:00
. exit_state = sci_port_stopping_state_exit
2011-05-10 02:28:46 -07:00
} ,
2011-06-02 00:10:43 +00:00
[ SCI_PORT_READY ] = {
2011-06-30 19:14:33 -07:00
. enter_state = sci_port_ready_state_enter ,
2011-05-11 23:52:21 +00:00
} ,
2011-06-02 00:10:43 +00:00
[ SCI_PORT_SUB_WAITING ] = {
2011-06-30 19:14:33 -07:00
. enter_state = sci_port_ready_substate_waiting_enter ,
2012-01-04 01:33:41 -08:00
. exit_state = scic_sds_port_ready_substate_waiting_exit ,
2011-05-11 23:52:21 +00:00
} ,
2011-06-02 00:10:43 +00:00
[ SCI_PORT_SUB_OPERATIONAL ] = {
2011-06-30 19:14:33 -07:00
. enter_state = sci_port_ready_substate_operational_enter ,
. exit_state = sci_port_ready_substate_operational_exit
2011-05-11 23:52:21 +00:00
} ,
2011-06-02 00:10:43 +00:00
[ SCI_PORT_SUB_CONFIGURING ] = {
2012-01-04 01:33:41 -08:00
. enter_state = sci_port_ready_substate_configuring_enter
2011-05-10 02:28:46 -07:00
} ,
2011-06-02 00:10:43 +00:00
[ SCI_PORT_RESETTING ] = {
2011-06-30 19:14:33 -07:00
. exit_state = sci_port_resetting_state_exit
2011-05-10 02:28:46 -07:00
} ,
2011-06-02 00:10:43 +00:00
[ SCI_PORT_FAILED ] = {
2011-06-30 19:14:33 -07:00
. enter_state = sci_port_failed_state_enter ,
2011-05-10 02:28:46 -07:00
}
} ;
2011-06-30 19:14:33 -07:00
void sci_port_construct ( struct isci_port * iport , u8 index ,
2011-06-30 17:38:32 -07:00
struct isci_host * ihost )
2011-05-10 02:28:46 -07:00
{
2011-06-30 19:14:33 -07:00
sci_init_sm ( & iport - > sm , sci_port_state_table , SCI_PORT_STOPPED ) ;
2011-05-10 02:28:46 -07:00
2011-06-29 13:09:25 -07:00
iport - > logical_port_index = SCIC_SDS_DUMMY_PORT ;
iport - > physical_port_index = index ;
iport - > active_phy_mask = 0 ;
2012-01-04 01:33:41 -08:00
iport - > enabled_phy_mask = 0 ;
2011-10-27 15:05:32 -07:00
iport - > last_active_phy = 0 ;
iport - > ready_exit = false ;
2011-05-10 02:28:46 -07:00
2011-06-30 17:38:32 -07:00
iport - > owning_controller = ihost ;
2011-05-10 02:28:46 -07:00
2011-06-29 13:09:25 -07:00
iport - > started_request_count = 0 ;
iport - > assigned_device_count = 0 ;
2012-03-08 22:41:48 -08:00
iport - > hang_detect_users = 0 ;
2011-05-10 02:28:46 -07:00
2011-06-29 13:09:25 -07:00
iport - > reserved_rni = SCU_DUMMY_INDEX ;
iport - > reserved_tag = SCI_CONTROLLER_INVALID_IO_TAG ;
2011-05-10 02:28:46 -07:00
2011-06-29 13:09:25 -07:00
sci_init_timer ( & iport - > timer , port_timeout ) ;
2011-05-19 11:59:10 +00:00
2011-06-29 13:09:25 -07:00
iport - > port_task_scheduler_registers = NULL ;
2011-05-10 02:28:46 -07:00
for ( index = 0 ; index < SCI_MAX_PHYS ; index + + )
2011-06-29 13:09:25 -07:00
iport - > phy_table [ index ] = NULL ;
2011-05-10 02:28:46 -07:00
}
2011-06-30 19:14:33 -07:00
void sci_port_broadcast_change_received ( struct isci_port * iport , struct isci_phy * iphy )
2011-05-10 02:28:46 -07:00
{
2011-06-30 17:38:32 -07:00
struct isci_host * ihost = iport - > owning_controller ;
2011-05-10 02:28:46 -07:00
/* notify the user. */
2011-06-29 13:09:25 -07:00
isci_port_bc_change_received ( ihost , iport , iphy ) ;
2011-05-10 02:28:46 -07:00
}
2011-11-30 11:57:34 -08:00
static void wait_port_reset ( struct isci_host * ihost , struct isci_port * iport )
{
wait_event ( ihost - > eventq , ! test_bit ( IPORT_RESET_PENDING , & iport - > state ) ) ;
}
2011-05-10 02:28:46 -07:00
int isci_port_perform_hard_reset ( struct isci_host * ihost , struct isci_port * iport ,
struct isci_phy * iphy )
{
unsigned long flags ;
enum sci_status status ;
2011-10-27 15:05:32 -07:00
int ret = TMF_RESP_FUNC_COMPLETE ;
2011-05-10 02:28:46 -07:00
dev_dbg ( & ihost - > pdev - > dev , " %s: iport = %p \n " ,
__func__ , iport ) ;
spin_lock_irqsave ( & ihost - > scic_lock , flags ) ;
2011-11-30 11:57:34 -08:00
set_bit ( IPORT_RESET_PENDING , & iport - > state ) ;
2011-05-10 02:28:46 -07:00
# define ISCI_PORT_RESET_TIMEOUT SCIC_SDS_SIGNATURE_FIS_TIMEOUT
2011-06-30 19:14:33 -07:00
status = sci_port_hard_reset ( iport , ISCI_PORT_RESET_TIMEOUT ) ;
2011-05-10 02:28:46 -07:00
spin_unlock_irqrestore ( & ihost - > scic_lock , flags ) ;
if ( status = = SCI_SUCCESS ) {
2011-11-30 11:57:34 -08:00
wait_port_reset ( ihost , iport ) ;
2011-05-10 02:28:46 -07:00
dev_dbg ( & ihost - > pdev - > dev ,
" %s: iport = %p; hard reset completion \n " ,
__func__ , iport ) ;
2011-10-27 15:05:32 -07:00
if ( iport - > hard_reset_status ! = SCI_SUCCESS ) {
2011-05-10 02:28:46 -07:00
ret = TMF_RESP_FUNC_FAILED ;
2011-10-27 15:05:32 -07:00
dev_err ( & ihost - > pdev - > dev ,
" %s: iport = %p; hard reset failed (0x%x) \n " ,
__func__ , iport , iport - > hard_reset_status ) ;
}
2011-05-10 02:28:46 -07:00
} else {
2011-11-30 11:57:34 -08:00
clear_bit ( IPORT_RESET_PENDING , & iport - > state ) ;
wake_up ( & ihost - > eventq ) ;
2011-05-10 02:28:46 -07:00
ret = TMF_RESP_FUNC_FAILED ;
dev_err ( & ihost - > pdev - > dev ,
2011-06-30 19:14:33 -07:00
" %s: iport = %p; sci_port_hard_reset call "
2011-05-10 02:28:46 -07:00
" failed 0x%x \n " ,
__func__ , iport , status ) ;
}
return ret ;
}
2011-11-17 18:01:38 -08:00
int isci_ata_check_ready ( struct domain_device * dev )
{
struct isci_port * iport = dev - > port - > lldd_port ;
struct isci_host * ihost = dev_to_ihost ( dev ) ;
struct isci_remote_device * idev ;
unsigned long flags ;
int rc = 0 ;
spin_lock_irqsave ( & ihost - > scic_lock , flags ) ;
idev = isci_lookup_device ( dev ) ;
spin_unlock_irqrestore ( & ihost - > scic_lock , flags ) ;
if ( ! idev )
goto out ;
if ( test_bit ( IPORT_RESET_PENDING , & iport - > state ) )
goto out ;
rc = ! ! iport - > active_phy_mask ;
out :
isci_put_device ( idev ) ;
return rc ;
}
2011-05-10 02:28:46 -07:00
void isci_port_deformed ( struct asd_sas_phy * phy )
{
2012-01-03 23:26:08 -08:00
struct isci_host * ihost = phy - > ha - > lldd_ha ;
struct isci_port * iport = phy - > port - > lldd_port ;
unsigned long flags ;
int i ;
/* we got a port notification on a port that was subsequently
* torn down and libsas is just now catching up
*/
if ( ! iport )
return ;
spin_lock_irqsave ( & ihost - > scic_lock , flags ) ;
for ( i = 0 ; i < SCI_MAX_PHYS ; i + + ) {
if ( iport - > active_phy_mask & 1 < < i )
break ;
}
spin_unlock_irqrestore ( & ihost - > scic_lock , flags ) ;
if ( i > = SCI_MAX_PHYS )
dev_dbg ( & ihost - > pdev - > dev , " %s: port: %ld \n " ,
__func__ , ( long ) ( iport - & ihost - > ports [ 0 ] ) ) ;
2011-05-10 02:28:46 -07:00
}
void isci_port_formed ( struct asd_sas_phy * phy )
{
2012-01-03 23:26:08 -08:00
struct isci_host * ihost = phy - > ha - > lldd_ha ;
struct isci_phy * iphy = to_iphy ( phy ) ;
struct asd_sas_port * port = phy - > port ;
2012-03-08 22:41:48 -08:00
struct isci_port * iport = NULL ;
2012-01-03 23:26:08 -08:00
unsigned long flags ;
int i ;
/* initial ports are formed as the driver is still initializing,
* wait for that process to complete
*/
wait_for_start ( ihost ) ;
spin_lock_irqsave ( & ihost - > scic_lock , flags ) ;
for ( i = 0 ; i < SCI_MAX_PORTS ; i + + ) {
iport = & ihost - > ports [ i ] ;
if ( iport - > active_phy_mask & 1 < < iphy - > phy_index )
break ;
}
spin_unlock_irqrestore ( & ihost - > scic_lock , flags ) ;
if ( i > = SCI_MAX_PORTS )
iport = NULL ;
port - > lldd_port = iport ;
2011-03-26 16:11:51 -07:00
}