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 "isci.h"
2011-05-09 02:49:15 +04:00
# include "host.h"
2011-07-03 09:56:22 +04:00
# include "phy.h"
2011-05-10 13:28:45 +04:00
# include "scu_event_codes.h"
2011-05-10 13:28:46 +04:00
# include "probe_roms.h"
2011-07-03 09:56:22 +04:00
2012-02-10 13:18:44 +04:00
# undef C
# define C(a) (#a)
static const char * phy_state_name ( enum sci_phy_states state )
{
static const char * const strings [ ] = PHY_STATES ;
return strings [ state ] ;
}
# undef C
2011-05-10 13:28:45 +04:00
/* Maximum arbitration wait time in micro-seconds */
# define SCIC_SDS_PHY_MAX_ARBITRATION_WAIT_TIME (700)
2011-06-29 02:05:53 +04:00
enum sas_linkrate sci_phy_linkrate ( struct isci_phy * iphy )
2011-05-10 13:28:45 +04:00
{
2011-06-29 02:05:53 +04:00
return iphy - > max_negotiated_speed ;
2011-05-10 13:28:45 +04:00
}
2012-02-10 13:18:49 +04:00
static struct isci_host * phy_to_host ( struct isci_phy * iphy )
2012-01-04 11:26:08 +04:00
{
struct isci_phy * table = iphy - iphy - > phy_index ;
struct isci_host * ihost = container_of ( table , typeof ( * ihost ) , phys [ 0 ] ) ;
2012-02-10 13:18:49 +04:00
return ihost ;
}
static struct device * sciphy_to_dev ( struct isci_phy * iphy )
{
return & phy_to_host ( iphy ) - > pdev - > dev ;
2012-01-04 11:26:08 +04:00
}
2011-07-01 06:14:33 +04:00
static enum sci_status
sci_phy_transport_layer_initialization ( struct isci_phy * iphy ,
struct scu_transport_layer_registers __iomem * reg )
2011-05-10 13:28:45 +04:00
{
u32 tl_control ;
2011-07-01 06:14:33 +04:00
iphy - > transport_layer_registers = reg ;
2011-05-10 13:28:45 +04:00
writel ( SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX ,
2011-06-29 02:05:53 +04:00
& iphy - > transport_layer_registers - > stp_rni ) ;
2011-05-10 13:28:45 +04:00
/*
* Hardware team recommends that we enable the STP prefetch for all
* transports
*/
2011-06-29 02:05:53 +04:00
tl_control = readl ( & iphy - > transport_layer_registers - > control ) ;
2011-05-10 13:28:45 +04:00
tl_control | = SCU_TLCR_GEN_BIT ( STP_WRITE_DATA_PREFETCH ) ;
2011-06-29 02:05:53 +04:00
writel ( tl_control , & iphy - > transport_layer_registers - > control ) ;
2011-05-10 13:28:45 +04:00
return SCI_SUCCESS ;
}
static enum sci_status
2011-07-01 06:14:33 +04:00
sci_phy_link_layer_initialization ( struct isci_phy * iphy ,
2012-01-04 13:32:34 +04:00
struct scu_link_layer_registers __iomem * llr )
2011-05-10 13:28:45 +04:00
{
2011-07-01 06:14:33 +04:00
struct isci_host * ihost = iphy - > owning_port - > owning_controller ;
2012-01-04 13:32:34 +04:00
struct sci_phy_user_params * phy_user ;
struct sci_phy_oem_params * phy_oem ;
2011-06-29 02:05:53 +04:00
int phy_idx = iphy - > phy_index ;
2011-07-01 06:14:33 +04:00
struct sci_phy_cap phy_cap ;
2012-01-04 13:32:34 +04:00
u32 phy_configuration ;
2011-05-10 13:28:45 +04:00
u32 parity_check = 0 ;
u32 parity_count = 0 ;
u32 llctl , link_rate ;
u32 clksm_value = 0 ;
2011-07-30 04:16:50 +04:00
u32 sp_timeouts = 0 ;
2011-05-10 13:28:45 +04:00
2012-01-04 13:32:34 +04:00
phy_user = & ihost - > user_parameters . phys [ phy_idx ] ;
phy_oem = & ihost - > oem_parameters . phys [ phy_idx ] ;
iphy - > link_layer_registers = llr ;
2011-05-10 13:28:45 +04:00
/* Set our IDENTIFY frame data */
# define SCI_END_DEVICE 0x01
writel ( SCU_SAS_TIID_GEN_BIT ( SMP_INITIATOR ) |
SCU_SAS_TIID_GEN_BIT ( SSP_INITIATOR ) |
SCU_SAS_TIID_GEN_BIT ( STP_INITIATOR ) |
SCU_SAS_TIID_GEN_BIT ( DA_SATA_HOST ) |
SCU_SAS_TIID_GEN_VAL ( DEVICE_TYPE , SCI_END_DEVICE ) ,
2012-01-04 13:32:34 +04:00
& llr - > transmit_identification ) ;
2011-05-10 13:28:45 +04:00
/* Write the device SAS Address */
2012-01-04 13:32:34 +04:00
writel ( 0xFEDCBA98 , & llr - > sas_device_name_high ) ;
writel ( phy_idx , & llr - > sas_device_name_low ) ;
2011-05-10 13:28:45 +04:00
/* Write the source SAS Address */
2012-01-04 13:32:34 +04:00
writel ( phy_oem - > sas_address . high , & llr - > source_sas_address_high ) ;
writel ( phy_oem - > sas_address . low , & llr - > source_sas_address_low ) ;
2011-05-10 13:28:45 +04:00
/* Clear and Set the PHY Identifier */
2012-01-04 13:32:34 +04:00
writel ( 0 , & llr - > identify_frame_phy_id ) ;
writel ( SCU_SAS_TIPID_GEN_VALUE ( ID , phy_idx ) , & llr - > identify_frame_phy_id ) ;
2011-05-10 13:28:45 +04:00
/* Change the initial state of the phy configuration register */
2012-01-04 13:32:34 +04:00
phy_configuration = readl ( & llr - > phy_configuration ) ;
2011-05-10 13:28:45 +04:00
/* Hold OOB state machine in reset */
phy_configuration | = SCU_SAS_PCFG_GEN_BIT ( OOB_RESET ) ;
2012-01-04 13:32:34 +04:00
writel ( phy_configuration , & llr - > phy_configuration ) ;
2011-05-10 13:28:45 +04:00
/* Configure the SNW capabilities */
phy_cap . all = 0 ;
phy_cap . start = 1 ;
phy_cap . gen3_no_ssc = 1 ;
phy_cap . gen2_no_ssc = 1 ;
phy_cap . gen1_no_ssc = 1 ;
2012-01-04 13:32:44 +04:00
if ( ihost - > oem_parameters . controller . do_enable_ssc ) {
struct scu_afe_registers __iomem * afe = & ihost - > scu_registers - > afe ;
2012-06-27 13:05:21 +04:00
struct scu_afe_transceiver __iomem * xcvr = & afe - > scu_afe_xcvr [ phy_idx ] ;
2012-01-04 13:32:44 +04:00
struct isci_pci_info * pci_info = to_pci_info ( ihost - > pdev ) ;
bool en_sas = false ;
bool en_sata = false ;
u32 sas_type = 0 ;
u32 sata_spread = 0x2 ;
u32 sas_spread = 0x2 ;
2011-05-10 13:28:45 +04:00
phy_cap . gen3_ssc = 1 ;
phy_cap . gen2_ssc = 1 ;
phy_cap . gen1_ssc = 1 ;
2012-01-04 13:32:44 +04:00
if ( pci_info - > orom - > hdr . version < ISCI_ROM_VER_1_1 )
en_sas = en_sata = true ;
else {
sata_spread = ihost - > oem_parameters . controller . ssc_sata_tx_spread_level ;
sas_spread = ihost - > oem_parameters . controller . ssc_sas_tx_spread_level ;
if ( sata_spread )
en_sata = true ;
if ( sas_spread ) {
en_sas = true ;
sas_type = ihost - > oem_parameters . controller . ssc_sas_tx_type ;
}
}
if ( en_sas ) {
u32 reg ;
reg = readl ( & xcvr - > afe_xcvr_control0 ) ;
reg | = ( 0x00100000 | ( sas_type < < 19 ) ) ;
writel ( reg , & xcvr - > afe_xcvr_control0 ) ;
reg = readl ( & xcvr - > afe_tx_ssc_control ) ;
reg | = sas_spread < < 8 ;
writel ( reg , & xcvr - > afe_tx_ssc_control ) ;
}
if ( en_sata ) {
u32 reg ;
reg = readl ( & xcvr - > afe_tx_ssc_control ) ;
reg | = sata_spread ;
writel ( reg , & xcvr - > afe_tx_ssc_control ) ;
reg = readl ( & llr - > stp_control ) ;
reg | = 1 < < 12 ;
writel ( reg , & llr - > stp_control ) ;
}
2011-05-10 13:28:45 +04:00
}
2012-01-04 13:32:34 +04:00
/* The SAS specification indicates that the phy_capabilities that
* are transmitted shall have an even parity . Calculate the parity .
*/
2011-05-10 13:28:45 +04:00
parity_check = phy_cap . all ;
while ( parity_check ! = 0 ) {
if ( parity_check & 0x1 )
parity_count + + ;
parity_check > > = 1 ;
}
2012-01-04 13:32:34 +04:00
/* If parity indicates there are an odd number of bits set, then
* set the parity bit to 1 in the phy capabilities .
*/
2011-05-10 13:28:45 +04:00
if ( ( parity_count % 2 ) ! = 0 )
phy_cap . parity = 1 ;
2012-01-04 13:32:34 +04:00
writel ( phy_cap . all , & llr - > phy_capabilities ) ;
2011-05-10 13:28:45 +04:00
/* Set the enable spinup period but disable the ability to send
* notify enable spinup
*/
writel ( SCU_ENSPINUP_GEN_VAL ( COUNT ,
phy_user - > notify_enable_spin_up_insertion_frequency ) ,
2012-01-04 13:32:34 +04:00
& llr - > notify_enable_spinup_control ) ;
2011-05-10 13:28:45 +04:00
/* Write the ALIGN Insertion Ferequency for connected phy and
* inpendent of connected state
*/
clksm_value = SCU_ALIGN_INSERTION_FREQUENCY_GEN_VAL ( CONNECTED ,
phy_user - > in_connection_align_insertion_frequency ) ;
clksm_value | = SCU_ALIGN_INSERTION_FREQUENCY_GEN_VAL ( GENERAL ,
phy_user - > align_insertion_frequency ) ;
2012-01-04 13:32:34 +04:00
writel ( clksm_value , & llr - > clock_skew_management ) ;
2011-05-10 13:28:45 +04:00
2012-01-04 13:32:39 +04:00
if ( is_c0 ( ihost - > pdev ) | | is_c1 ( ihost - > pdev ) ) {
writel ( 0x04210400 , & llr - > afe_lookup_table_control ) ;
writel ( 0x020A7C05 , & llr - > sas_primitive_timeout ) ;
} else
writel ( 0x02108421 , & llr - > afe_lookup_table_control ) ;
2011-05-10 13:28:45 +04:00
llctl = SCU_SAS_LLCTL_GEN_VAL ( NO_OUTBOUND_TASK_TIMEOUT ,
2011-07-01 06:14:33 +04:00
( u8 ) ihost - > user_parameters . no_outbound_task_timeout ) ;
2011-05-10 13:28:45 +04:00
2011-07-03 23:14:45 +04:00
switch ( phy_user - > max_speed_generation ) {
2011-05-10 13:28:45 +04:00
case SCIC_SDS_PARM_GEN3_SPEED :
link_rate = SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_GEN3 ;
break ;
case SCIC_SDS_PARM_GEN2_SPEED :
link_rate = SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_GEN2 ;
break ;
default :
link_rate = SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_GEN1 ;
break ;
}
llctl | = SCU_SAS_LLCTL_GEN_VAL ( MAX_LINK_RATE , link_rate ) ;
2012-01-04 13:32:34 +04:00
writel ( llctl , & llr - > link_layer_control ) ;
2011-05-10 13:28:45 +04:00
2012-01-04 13:32:34 +04:00
sp_timeouts = readl ( & llr - > sas_phy_timeouts ) ;
2011-07-30 04:16:50 +04:00
/* Clear the default 0x36 (54us) RATE_CHANGE timeout value. */
sp_timeouts & = ~ SCU_SAS_PHYTOV_GEN_VAL ( RATE_CHANGE , 0xFF ) ;
/* Set RATE_CHANGE timeout value to 0x3B (59us). This ensures SCU can
* lock with 3 Gb drive when SCU max rate is set to 1.5 Gb .
*/
sp_timeouts | = SCU_SAS_PHYTOV_GEN_VAL ( RATE_CHANGE , 0x3B ) ;
2012-01-04 13:32:34 +04:00
writel ( sp_timeouts , & llr - > sas_phy_timeouts ) ;
2011-07-30 04:16:50 +04:00
2011-07-01 22:41:21 +04:00
if ( is_a2 ( ihost - > pdev ) ) {
2012-01-04 13:32:34 +04:00
/* Program the max ARB time for the PHY to 700us so we
* inter - operate with the PMC expander which shuts down
* PHYs if the expander PHY generates too many breaks .
* This time value will guarantee that the initiator PHY
* will generate the break .
2011-05-10 13:28:45 +04:00
*/
writel ( SCIC_SDS_PHY_MAX_ARBITRATION_WAIT_TIME ,
2012-01-04 13:32:34 +04:00
& llr - > maximum_arbitration_wait_timer_timeout ) ;
2011-05-10 13:28:45 +04:00
}
2012-01-04 13:32:34 +04:00
/* Disable link layer hang detection, rely on the OS timeout for
* I / O timeouts .
*/
writel ( 0 , & llr - > link_layer_hang_detection_timeout ) ;
2011-05-10 13:28:45 +04:00
/* We can exit the initial state to the stopped state */
2011-06-29 02:05:53 +04:00
sci_change_state ( & iphy - > sm , SCI_PHY_STOPPED ) ;
2011-05-10 13:28:45 +04:00
return SCI_SUCCESS ;
}
2011-05-19 15:59:36 +04:00
static void phy_sata_timeout ( unsigned long data )
2011-05-10 13:28:45 +04:00
{
2011-05-19 15:59:36 +04:00
struct sci_timer * tmr = ( struct sci_timer * ) data ;
2011-06-29 02:05:53 +04:00
struct isci_phy * iphy = container_of ( tmr , typeof ( * iphy ) , sata_timer ) ;
2011-07-01 04:38:32 +04:00
struct isci_host * ihost = iphy - > owning_port - > owning_controller ;
2011-05-19 15:59:36 +04:00
unsigned long flags ;
spin_lock_irqsave ( & ihost - > scic_lock , flags ) ;
if ( tmr - > cancel )
goto done ;
2011-05-10 13:28:45 +04:00
2011-06-29 02:05:53 +04:00
dev_dbg ( sciphy_to_dev ( iphy ) ,
2011-05-10 13:28:45 +04:00
" %s: SCIC SDS Phy 0x%p did not receive signature fis before "
" timeout. \n " ,
__func__ ,
2011-06-29 02:05:53 +04:00
iphy ) ;
2011-05-10 13:28:45 +04:00
2011-06-29 02:05:53 +04:00
sci_change_state ( & iphy - > sm , SCI_PHY_STARTING ) ;
2011-05-19 15:59:36 +04:00
done :
spin_unlock_irqrestore ( & ihost - > scic_lock , flags ) ;
2011-05-10 13:28:45 +04:00
}
/**
* This method returns the port currently containing this phy . If the phy is
* currently contained by the dummy port , then the phy is considered to not
* be part of a port .
* @ sci_phy : This parameter specifies the phy for which to retrieve the
* containing port .
*
* This method returns a handle to a port that contains the supplied phy .
* NULL This value is returned if the phy is not part of a real
* port ( i . e . it ' s contained in the dummy port ) . ! NULL All other
* values indicate a handle / pointer to the port containing the phy .
*/
2011-07-01 13:25:15 +04:00
struct isci_port * phy_get_non_dummy_port ( struct isci_phy * iphy )
2011-05-10 13:28:45 +04:00
{
2011-07-01 13:25:15 +04:00
struct isci_port * iport = iphy - > owning_port ;
if ( iport - > physical_port_index = = SCIC_SDS_DUMMY_PORT )
2011-05-10 13:28:45 +04:00
return NULL ;
2011-06-29 02:05:53 +04:00
return iphy - > owning_port ;
2011-05-10 13:28:45 +04:00
}
/**
* This method will assign a port to the phy object .
2011-06-29 02:05:53 +04:00
* @ out ] : iphy This parameter specifies the phy for which to assign a port
2011-05-10 13:28:45 +04:00
* object .
*
*
*/
2011-07-01 06:14:33 +04:00
void sci_phy_set_port (
2011-06-29 02:05:53 +04:00
struct isci_phy * iphy ,
2011-06-30 00:09:25 +04:00
struct isci_port * iport )
2011-05-10 13:28:45 +04:00
{
2011-06-30 00:09:25 +04:00
iphy - > owning_port = iport ;
2011-05-10 13:28:45 +04:00
2011-06-29 02:05:53 +04:00
if ( iphy - > bcn_received_while_port_unassigned ) {
iphy - > bcn_received_while_port_unassigned = false ;
2011-07-01 06:14:33 +04:00
sci_port_broadcast_change_received ( iphy - > owning_port , iphy ) ;
2011-05-10 13:28:45 +04:00
}
}
2011-07-01 06:14:33 +04:00
enum sci_status sci_phy_initialize ( struct isci_phy * iphy ,
struct scu_transport_layer_registers __iomem * tl ,
struct scu_link_layer_registers __iomem * ll )
2011-05-10 13:28:45 +04:00
{
/* Perfrom the initialization of the TL hardware */
2011-07-01 06:14:33 +04:00
sci_phy_transport_layer_initialization ( iphy , tl ) ;
2011-05-10 13:28:45 +04:00
/* Perofrm the initialization of the PE hardware */
2011-07-01 06:14:33 +04:00
sci_phy_link_layer_initialization ( iphy , ll ) ;
2011-05-10 13:28:45 +04:00
2011-07-01 06:14:33 +04:00
/* There is nothing that needs to be done in this state just
* transition to the stopped state
*/
2011-06-29 02:05:53 +04:00
sci_change_state ( & iphy - > sm , SCI_PHY_STOPPED ) ;
2011-05-10 13:28:45 +04:00
return SCI_SUCCESS ;
}
/**
* This method assigns the direct attached device ID for this phy .
*
2011-06-29 02:05:53 +04:00
* @ iphy The phy for which the direct attached device id is to
2011-05-10 13:28:45 +04:00
* be assigned .
* @ device_id The direct attached device ID to assign to the phy .
* This will either be the RNi for the device or an invalid RNi if there
* is no current device assigned to the phy .
*/
2011-07-01 06:14:33 +04:00
void sci_phy_setup_transport ( struct isci_phy * iphy , u32 device_id )
2011-05-10 13:28:45 +04:00
{
u32 tl_control ;
2011-06-29 02:05:53 +04:00
writel ( device_id , & iphy - > transport_layer_registers - > stp_rni ) ;
2011-05-10 13:28:45 +04:00
/*
* The read should guarantee that the first write gets posted
* before the next write
*/
2011-06-29 02:05:53 +04:00
tl_control = readl ( & iphy - > transport_layer_registers - > control ) ;
2011-05-10 13:28:45 +04:00
tl_control | = SCU_TLCR_GEN_BIT ( CLEAR_TCI_NCQ_MAPPING_TABLE ) ;
2011-06-29 02:05:53 +04:00
writel ( tl_control , & iphy - > transport_layer_registers - > control ) ;
2011-05-10 13:28:45 +04:00
}
2011-07-01 06:14:33 +04:00
static void sci_phy_suspend ( struct isci_phy * iphy )
2011-05-10 13:28:45 +04:00
{
u32 scu_sas_pcfg_value ;
scu_sas_pcfg_value =
2011-06-29 02:05:53 +04:00
readl ( & iphy - > link_layer_registers - > phy_configuration ) ;
2011-05-10 13:28:45 +04:00
scu_sas_pcfg_value | = SCU_SAS_PCFG_GEN_BIT ( SUSPEND_PROTOCOL_ENGINE ) ;
writel ( scu_sas_pcfg_value ,
2011-06-29 02:05:53 +04:00
& iphy - > link_layer_registers - > phy_configuration ) ;
2011-05-10 13:28:45 +04:00
2011-07-01 06:14:33 +04:00
sci_phy_setup_transport ( iphy , SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX ) ;
2011-05-10 13:28:45 +04:00
}
2011-07-01 06:14:33 +04:00
void sci_phy_resume ( struct isci_phy * iphy )
2011-05-10 13:28:45 +04:00
{
u32 scu_sas_pcfg_value ;
scu_sas_pcfg_value =
2011-06-29 02:05:53 +04:00
readl ( & iphy - > link_layer_registers - > phy_configuration ) ;
2011-05-10 13:28:45 +04:00
scu_sas_pcfg_value & = ~ SCU_SAS_PCFG_GEN_BIT ( SUSPEND_PROTOCOL_ENGINE ) ;
writel ( scu_sas_pcfg_value ,
2011-06-29 02:05:53 +04:00
& iphy - > link_layer_registers - > phy_configuration ) ;
2011-05-10 13:28:45 +04:00
}
2011-07-01 06:14:33 +04:00
void sci_phy_get_sas_address ( struct isci_phy * iphy , struct sci_sas_address * sas )
2011-05-10 13:28:45 +04:00
{
2011-07-01 06:14:33 +04:00
sas - > high = readl ( & iphy - > link_layer_registers - > source_sas_address_high ) ;
sas - > low = readl ( & iphy - > link_layer_registers - > source_sas_address_low ) ;
2011-05-10 13:28:45 +04:00
}
2011-07-01 06:14:33 +04:00
void sci_phy_get_attached_sas_address ( struct isci_phy * iphy , struct sci_sas_address * sas )
2011-05-10 13:28:45 +04:00
{
struct sas_identify_frame * iaf ;
iaf = & iphy - > frame_rcvd . iaf ;
2011-07-01 06:14:33 +04:00
memcpy ( sas , iaf - > sas_addr , SAS_ADDR_SIZE ) ;
2011-05-10 13:28:45 +04:00
}
2011-07-01 06:14:33 +04:00
void sci_phy_get_protocols ( struct isci_phy * iphy , struct sci_phy_proto * proto )
2011-05-10 13:28:45 +04:00
{
2011-07-01 06:14:33 +04:00
proto - > all = readl ( & iphy - > link_layer_registers - > transmit_identification ) ;
2011-05-10 13:28:45 +04:00
}
2011-07-01 06:14:33 +04:00
enum sci_status sci_phy_start ( struct isci_phy * iphy )
2011-05-10 13:28:45 +04:00
{
2011-07-01 06:14:33 +04:00
enum sci_phy_states state = iphy - > sm . current_state_id ;
2011-05-12 14:44:24 +04:00
2011-06-02 04:10:43 +04:00
if ( state ! = SCI_PHY_STOPPED ) {
2012-02-10 13:18:44 +04:00
dev_dbg ( sciphy_to_dev ( iphy ) , " %s: in wrong state: %s \n " ,
__func__ , phy_state_name ( state ) ) ;
2011-05-12 14:44:24 +04:00
return SCI_FAILURE_INVALID_STATE ;
}
2011-06-29 02:05:53 +04:00
sci_change_state ( & iphy - > sm , SCI_PHY_STARTING ) ;
2011-05-12 14:44:24 +04:00
return SCI_SUCCESS ;
2011-05-10 13:28:45 +04:00
}
2011-07-01 06:14:33 +04:00
enum sci_status sci_phy_stop ( struct isci_phy * iphy )
2011-05-10 13:28:45 +04:00
{
2011-07-01 06:14:33 +04:00
enum sci_phy_states state = iphy - > sm . current_state_id ;
2011-05-12 15:01:03 +04:00
switch ( state ) {
2011-06-02 04:10:43 +04:00
case SCI_PHY_SUB_INITIAL :
case SCI_PHY_SUB_AWAIT_OSSP_EN :
case SCI_PHY_SUB_AWAIT_SAS_SPEED_EN :
case SCI_PHY_SUB_AWAIT_SAS_POWER :
case SCI_PHY_SUB_AWAIT_SATA_POWER :
case SCI_PHY_SUB_AWAIT_SATA_PHY_EN :
case SCI_PHY_SUB_AWAIT_SATA_SPEED_EN :
case SCI_PHY_SUB_AWAIT_SIG_FIS_UF :
case SCI_PHY_SUB_FINAL :
case SCI_PHY_READY :
2011-05-12 15:01:03 +04:00
break ;
default :
2012-02-10 13:18:44 +04:00
dev_dbg ( sciphy_to_dev ( iphy ) , " %s: in wrong state: %s \n " ,
__func__ , phy_state_name ( state ) ) ;
2011-05-12 15:01:03 +04:00
return SCI_FAILURE_INVALID_STATE ;
}
2011-06-29 02:05:53 +04:00
sci_change_state ( & iphy - > sm , SCI_PHY_STOPPED ) ;
2011-05-12 15:01:03 +04:00
return SCI_SUCCESS ;
2011-05-10 13:28:45 +04:00
}
2011-07-01 06:14:33 +04:00
enum sci_status sci_phy_reset ( struct isci_phy * iphy )
2011-05-10 13:28:45 +04:00
{
2011-07-01 06:14:33 +04:00
enum sci_phy_states state = iphy - > sm . current_state_id ;
2011-05-12 15:02:07 +04:00
2011-06-02 04:10:43 +04:00
if ( state ! = SCI_PHY_READY ) {
2012-02-10 13:18:44 +04:00
dev_dbg ( sciphy_to_dev ( iphy ) , " %s: in wrong state: %s \n " ,
__func__ , phy_state_name ( state ) ) ;
2011-05-12 15:02:07 +04:00
return SCI_FAILURE_INVALID_STATE ;
}
2011-06-29 02:05:53 +04:00
sci_change_state ( & iphy - > sm , SCI_PHY_RESETTING ) ;
2011-05-12 15:02:07 +04:00
return SCI_SUCCESS ;
2011-05-10 13:28:45 +04:00
}
2011-07-01 06:14:33 +04:00
enum sci_status sci_phy_consume_power_handler ( struct isci_phy * iphy )
2011-05-10 13:28:45 +04:00
{
2011-07-01 06:14:33 +04:00
enum sci_phy_states state = iphy - > sm . current_state_id ;
2011-05-12 15:51:41 +04:00
switch ( state ) {
2011-06-02 04:10:43 +04:00
case SCI_PHY_SUB_AWAIT_SAS_POWER : {
2011-05-12 15:51:41 +04:00
u32 enable_spinup ;
2011-06-29 02:05:53 +04:00
enable_spinup = readl ( & iphy - > link_layer_registers - > notify_enable_spinup_control ) ;
2011-05-12 15:51:41 +04:00
enable_spinup | = SCU_ENSPINUP_GEN_BIT ( ENABLE ) ;
2011-06-29 02:05:53 +04:00
writel ( enable_spinup , & iphy - > link_layer_registers - > notify_enable_spinup_control ) ;
2011-05-12 15:51:41 +04:00
/* Change state to the final state this substate machine has run to completion */
2011-06-29 02:05:53 +04:00
sci_change_state ( & iphy - > sm , SCI_PHY_SUB_FINAL ) ;
2011-05-12 15:51:41 +04:00
return SCI_SUCCESS ;
}
2011-06-02 04:10:43 +04:00
case SCI_PHY_SUB_AWAIT_SATA_POWER : {
2011-05-12 15:51:41 +04:00
u32 scu_sas_pcfg_value ;
/* Release the spinup hold state and reset the OOB state machine */
scu_sas_pcfg_value =
2011-06-29 02:05:53 +04:00
readl ( & iphy - > link_layer_registers - > phy_configuration ) ;
2011-05-12 15:51:41 +04:00
scu_sas_pcfg_value & =
~ ( SCU_SAS_PCFG_GEN_BIT ( SATA_SPINUP_HOLD ) | SCU_SAS_PCFG_GEN_BIT ( OOB_ENABLE ) ) ;
scu_sas_pcfg_value | = SCU_SAS_PCFG_GEN_BIT ( OOB_RESET ) ;
writel ( scu_sas_pcfg_value ,
2011-06-29 02:05:53 +04:00
& iphy - > link_layer_registers - > phy_configuration ) ;
2011-05-12 15:51:41 +04:00
/* Now restart the OOB operation */
scu_sas_pcfg_value & = ~ SCU_SAS_PCFG_GEN_BIT ( OOB_RESET ) ;
scu_sas_pcfg_value | = SCU_SAS_PCFG_GEN_BIT ( OOB_ENABLE ) ;
writel ( scu_sas_pcfg_value ,
2011-06-29 02:05:53 +04:00
& iphy - > link_layer_registers - > phy_configuration ) ;
2011-05-12 15:51:41 +04:00
/* Change state to the final state this substate machine has run to completion */
2011-06-29 02:05:53 +04:00
sci_change_state ( & iphy - > sm , SCI_PHY_SUB_AWAIT_SATA_PHY_EN ) ;
2011-05-12 15:51:41 +04:00
return SCI_SUCCESS ;
}
default :
2012-02-10 13:18:44 +04:00
dev_dbg ( sciphy_to_dev ( iphy ) , " %s: in wrong state: %s \n " ,
__func__ , phy_state_name ( state ) ) ;
2011-05-12 15:51:41 +04:00
return SCI_FAILURE_INVALID_STATE ;
}
2011-05-10 13:28:45 +04:00
}
2011-07-01 06:14:33 +04:00
static void sci_phy_start_sas_link_training ( struct isci_phy * iphy )
2011-05-10 13:28:45 +04:00
{
2011-07-01 06:14:33 +04:00
/* continue the link training for the phy as if it were a SAS PHY
* instead of a SATA PHY . This is done because the completion queue had a SAS
* PHY DETECTED event when the state machine was expecting a SATA PHY event .
*/
2011-05-10 13:28:45 +04:00
u32 phy_control ;
2011-07-01 06:14:33 +04:00
phy_control = readl ( & iphy - > link_layer_registers - > phy_configuration ) ;
2011-05-10 13:28:45 +04:00
phy_control | = SCU_SAS_PCFG_GEN_BIT ( SATA_SPINUP_HOLD ) ;
writel ( phy_control ,
2011-07-01 06:14:33 +04:00
& iphy - > link_layer_registers - > phy_configuration ) ;
2011-05-10 13:28:45 +04:00
2011-06-29 02:05:53 +04:00
sci_change_state ( & iphy - > sm , SCI_PHY_SUB_AWAIT_SAS_SPEED_EN ) ;
2011-05-10 13:28:45 +04:00
2012-02-01 12:44:14 +04:00
iphy - > protocol = SAS_PROTOCOL_SSP ;
2011-05-10 13:28:45 +04:00
}
2011-07-01 06:14:33 +04:00
static void sci_phy_start_sata_link_training ( struct isci_phy * iphy )
2011-05-10 13:28:45 +04:00
{
2011-07-01 06:14:33 +04:00
/* This method continues the link training for the phy as if it were a SATA PHY
* instead of a SAS PHY . This is done because the completion queue had a SATA
* SPINUP HOLD event when the state machine was expecting a SAS PHY event . none
*/
2011-06-29 02:05:53 +04:00
sci_change_state ( & iphy - > sm , SCI_PHY_SUB_AWAIT_SATA_POWER ) ;
2011-05-10 13:28:45 +04:00
2012-02-01 12:44:14 +04:00
iphy - > protocol = SAS_PROTOCOL_SATA ;
2011-05-10 13:28:45 +04:00
}
/**
2011-07-01 06:14:33 +04:00
* sci_phy_complete_link_training - perform processing common to
2011-05-10 13:28:45 +04:00
* all protocols upon completion of link training .
* @ sci_phy : This parameter specifies the phy object for which link training
* has completed .
* @ max_link_rate : This parameter specifies the maximum link rate to be
* associated with this phy .
* @ next_state : This parameter specifies the next state for the phy ' s starting
* sub - state machine .
*
*/
2011-07-01 06:14:33 +04:00
static void sci_phy_complete_link_training ( struct isci_phy * iphy ,
enum sas_linkrate max_link_rate ,
u32 next_state )
2011-05-10 13:28:45 +04:00
{
2011-06-29 02:05:53 +04:00
iphy - > max_negotiated_speed = max_link_rate ;
2011-05-10 13:28:45 +04:00
2011-06-29 02:05:53 +04:00
sci_change_state ( & iphy - > sm , next_state ) ;
2011-05-10 13:28:45 +04:00
}
2012-02-10 13:18:49 +04:00
static const char * phy_event_name ( u32 event_code )
{
switch ( scu_get_event_code ( event_code ) ) {
case SCU_EVENT_PORT_SELECTOR_DETECTED :
return " port selector " ;
case SCU_EVENT_SENT_PORT_SELECTION :
return " port selection " ;
case SCU_EVENT_HARD_RESET_TRANSMITTED :
return " tx hard reset " ;
case SCU_EVENT_HARD_RESET_RECEIVED :
return " rx hard reset " ;
case SCU_EVENT_RECEIVED_IDENTIFY_TIMEOUT :
return " identify timeout " ;
case SCU_EVENT_LINK_FAILURE :
return " link fail " ;
case SCU_EVENT_SATA_SPINUP_HOLD :
return " sata spinup hold " ;
case SCU_EVENT_SAS_15_SSC :
case SCU_EVENT_SAS_15 :
return " sas 1.5 " ;
case SCU_EVENT_SAS_30_SSC :
case SCU_EVENT_SAS_30 :
return " sas 3.0 " ;
case SCU_EVENT_SAS_60_SSC :
case SCU_EVENT_SAS_60 :
return " sas 6.0 " ;
case SCU_EVENT_SATA_15_SSC :
case SCU_EVENT_SATA_15 :
return " sata 1.5 " ;
case SCU_EVENT_SATA_30_SSC :
case SCU_EVENT_SATA_30 :
return " sata 3.0 " ;
case SCU_EVENT_SATA_60_SSC :
case SCU_EVENT_SATA_60 :
return " sata 6.0 " ;
case SCU_EVENT_SAS_PHY_DETECTED :
return " sas detect " ;
case SCU_EVENT_SATA_PHY_DETECTED :
return " sata detect " ;
default :
return " unknown " ;
}
}
# define phy_event_dbg(iphy, state, code) \
dev_dbg ( sciphy_to_dev ( iphy ) , " phy-%d:%d: %s event: %s (%x) \n " , \
phy_to_host ( iphy ) - > id , iphy - > phy_index , \
phy_state_name ( state ) , phy_event_name ( code ) , code )
# define phy_event_warn(iphy, state, code) \
dev_warn ( sciphy_to_dev ( iphy ) , " phy-%d:%d: %s event: %s (%x) \n " , \
phy_to_host ( iphy ) - > id , iphy - > phy_index , \
phy_state_name ( state ) , phy_event_name ( code ) , code )
2012-03-08 23:38:50 +04:00
void scu_link_layer_set_txcomsas_timeout ( struct isci_phy * iphy , u32 timeout )
{
u32 val ;
/* Extend timeout */
val = readl ( & iphy - > link_layer_registers - > transmit_comsas_signal ) ;
val & = ~ SCU_SAS_LLTXCOMSAS_GEN_VAL ( NEGTIME , SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_MASK ) ;
val | = SCU_SAS_LLTXCOMSAS_GEN_VAL ( NEGTIME , timeout ) ;
writel ( val , & iphy - > link_layer_registers - > transmit_comsas_signal ) ;
}
2011-07-01 06:14:33 +04:00
enum sci_status sci_phy_event_handler ( struct isci_phy * iphy , u32 event_code )
2011-05-11 03:54:23 +04:00
{
2011-07-01 06:14:33 +04:00
enum sci_phy_states state = iphy - > sm . current_state_id ;
2011-05-11 03:54:23 +04:00
2011-05-12 15:27:29 +04:00
switch ( state ) {
2011-06-02 04:10:43 +04:00
case SCI_PHY_SUB_AWAIT_OSSP_EN :
2011-05-12 15:27:29 +04:00
switch ( scu_get_event_code ( event_code ) ) {
case SCU_EVENT_SAS_PHY_DETECTED :
2011-07-01 06:14:33 +04:00
sci_phy_start_sas_link_training ( iphy ) ;
2011-06-29 02:05:53 +04:00
iphy - > is_in_link_training = true ;
2011-05-12 15:27:29 +04:00
break ;
case SCU_EVENT_SATA_SPINUP_HOLD :
2011-07-01 06:14:33 +04:00
sci_phy_start_sata_link_training ( iphy ) ;
2011-06-29 02:05:53 +04:00
iphy - > is_in_link_training = true ;
2011-05-12 15:27:29 +04:00
break ;
2012-03-08 23:38:50 +04:00
case SCU_EVENT_RECEIVED_IDENTIFY_TIMEOUT :
/* Extend timeout value */
scu_link_layer_set_txcomsas_timeout ( iphy , SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_EXTENDED ) ;
/* Start the oob/sn state machine over again */
sci_change_state ( & iphy - > sm , SCI_PHY_STARTING ) ;
break ;
2011-05-12 15:27:29 +04:00
default :
2012-02-10 13:18:49 +04:00
phy_event_dbg ( iphy , state , event_code ) ;
2011-05-12 15:27:29 +04:00
return SCI_FAILURE ;
}
return SCI_SUCCESS ;
2011-06-02 04:10:43 +04:00
case SCI_PHY_SUB_AWAIT_SAS_SPEED_EN :
2011-05-12 15:27:29 +04:00
switch ( scu_get_event_code ( event_code ) ) {
case SCU_EVENT_SAS_PHY_DETECTED :
/*
* Why is this being reported again by the controller ?
* We would re - enter this state so just stay here */
break ;
case SCU_EVENT_SAS_15 :
case SCU_EVENT_SAS_15_SSC :
2011-07-01 06:14:33 +04:00
sci_phy_complete_link_training ( iphy , SAS_LINK_RATE_1_5_GBPS ,
SCI_PHY_SUB_AWAIT_IAF_UF ) ;
2011-05-12 15:27:29 +04:00
break ;
case SCU_EVENT_SAS_30 :
case SCU_EVENT_SAS_30_SSC :
2011-07-01 06:14:33 +04:00
sci_phy_complete_link_training ( iphy , SAS_LINK_RATE_3_0_GBPS ,
SCI_PHY_SUB_AWAIT_IAF_UF ) ;
2011-05-12 15:27:29 +04:00
break ;
case SCU_EVENT_SAS_60 :
case SCU_EVENT_SAS_60_SSC :
2011-07-01 06:14:33 +04:00
sci_phy_complete_link_training ( iphy , SAS_LINK_RATE_6_0_GBPS ,
SCI_PHY_SUB_AWAIT_IAF_UF ) ;
2011-05-12 15:27:29 +04:00
break ;
case SCU_EVENT_SATA_SPINUP_HOLD :
/*
* We were doing SAS PHY link training and received a SATA PHY event
* continue OOB / SN as if this were a SATA PHY */
2011-07-01 06:14:33 +04:00
sci_phy_start_sata_link_training ( iphy ) ;
2011-05-12 15:27:29 +04:00
break ;
case SCU_EVENT_LINK_FAILURE :
2012-03-08 23:38:50 +04:00
/* Change the timeout value to default */
scu_link_layer_set_txcomsas_timeout ( iphy , SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT ) ;
2011-05-12 15:27:29 +04:00
/* Link failure change state back to the starting state */
2011-06-29 02:05:53 +04:00
sci_change_state ( & iphy - > sm , SCI_PHY_STARTING ) ;
2011-05-12 15:27:29 +04:00
break ;
2012-03-08 23:38:50 +04:00
case SCU_EVENT_RECEIVED_IDENTIFY_TIMEOUT :
/* Extend the timeout value */
scu_link_layer_set_txcomsas_timeout ( iphy , SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_EXTENDED ) ;
/* Start the oob/sn state machine over again */
sci_change_state ( & iphy - > sm , SCI_PHY_STARTING ) ;
break ;
2011-05-12 15:27:29 +04:00
default :
2012-02-10 13:18:49 +04:00
phy_event_warn ( iphy , state , event_code ) ;
2011-05-12 15:27:29 +04:00
return SCI_FAILURE ;
break ;
}
return SCI_SUCCESS ;
2011-06-02 04:10:43 +04:00
case SCI_PHY_SUB_AWAIT_IAF_UF :
2011-05-12 15:27:29 +04:00
switch ( scu_get_event_code ( event_code ) ) {
case SCU_EVENT_SAS_PHY_DETECTED :
/* Backup the state machine */
2011-07-01 06:14:33 +04:00
sci_phy_start_sas_link_training ( iphy ) ;
2011-05-12 15:27:29 +04:00
break ;
case SCU_EVENT_SATA_SPINUP_HOLD :
/* We were doing SAS PHY link training and received a
* SATA PHY event continue OOB / SN as if this were a
* SATA PHY
*/
2011-07-01 06:14:33 +04:00
sci_phy_start_sata_link_training ( iphy ) ;
2011-05-12 15:27:29 +04:00
break ;
case SCU_EVENT_RECEIVED_IDENTIFY_TIMEOUT :
2012-03-08 23:38:50 +04:00
/* Extend the timeout value */
scu_link_layer_set_txcomsas_timeout ( iphy , SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_EXTENDED ) ;
/* Start the oob/sn state machine over again */
sci_change_state ( & iphy - > sm , SCI_PHY_STARTING ) ;
break ;
2011-05-12 15:27:29 +04:00
case SCU_EVENT_LINK_FAILURE :
2012-03-08 23:38:50 +04:00
scu_link_layer_set_txcomsas_timeout ( iphy , SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT ) ;
2011-05-12 15:27:29 +04:00
case SCU_EVENT_HARD_RESET_RECEIVED :
/* Start the oob/sn state machine over again */
2011-06-29 02:05:53 +04:00
sci_change_state ( & iphy - > sm , SCI_PHY_STARTING ) ;
2011-05-12 15:27:29 +04:00
break ;
default :
2012-02-10 13:18:49 +04:00
phy_event_warn ( iphy , state , event_code ) ;
2011-05-12 15:27:29 +04:00
return SCI_FAILURE ;
}
return SCI_SUCCESS ;
2011-06-02 04:10:43 +04:00
case SCI_PHY_SUB_AWAIT_SAS_POWER :
2011-05-12 15:27:29 +04:00
switch ( scu_get_event_code ( event_code ) ) {
case SCU_EVENT_LINK_FAILURE :
2012-03-08 23:38:50 +04:00
/* Change the timeout value to default */
scu_link_layer_set_txcomsas_timeout ( iphy , SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT ) ;
2011-05-12 15:27:29 +04:00
/* Link failure change state back to the starting state */
2011-06-29 02:05:53 +04:00
sci_change_state ( & iphy - > sm , SCI_PHY_STARTING ) ;
2011-05-12 15:27:29 +04:00
break ;
default :
2012-02-10 13:18:49 +04:00
phy_event_warn ( iphy , state , event_code ) ;
2011-05-12 15:27:29 +04:00
return SCI_FAILURE ;
}
return SCI_SUCCESS ;
2011-06-02 04:10:43 +04:00
case SCI_PHY_SUB_AWAIT_SATA_POWER :
2011-05-12 15:27:29 +04:00
switch ( scu_get_event_code ( event_code ) ) {
case SCU_EVENT_LINK_FAILURE :
2012-03-08 23:38:50 +04:00
/* Change the timeout value to default */
scu_link_layer_set_txcomsas_timeout ( iphy , SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT ) ;
2011-05-12 15:27:29 +04:00
/* Link failure change state back to the starting state */
2011-06-29 02:05:53 +04:00
sci_change_state ( & iphy - > sm , SCI_PHY_STARTING ) ;
2011-05-12 15:27:29 +04:00
break ;
case SCU_EVENT_SATA_SPINUP_HOLD :
/* These events are received every 10ms and are
* expected while in this state
*/
break ;
case SCU_EVENT_SAS_PHY_DETECTED :
/* There has been a change in the phy type before OOB/SN for the
* SATA finished start down the SAS link traning path .
*/
2011-07-01 06:14:33 +04:00
sci_phy_start_sas_link_training ( iphy ) ;
2011-05-12 15:27:29 +04:00
break ;
default :
2012-02-10 13:18:49 +04:00
phy_event_warn ( iphy , state , event_code ) ;
2011-05-12 15:27:29 +04:00
return SCI_FAILURE ;
}
return SCI_SUCCESS ;
2011-06-02 04:10:43 +04:00
case SCI_PHY_SUB_AWAIT_SATA_PHY_EN :
2011-05-12 15:27:29 +04:00
switch ( scu_get_event_code ( event_code ) ) {
case SCU_EVENT_LINK_FAILURE :
2012-03-08 23:38:50 +04:00
/* Change the timeout value to default */
scu_link_layer_set_txcomsas_timeout ( iphy , SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT ) ;
2011-05-12 15:27:29 +04:00
/* Link failure change state back to the starting state */
2011-06-29 02:05:53 +04:00
sci_change_state ( & iphy - > sm , SCI_PHY_STARTING ) ;
2011-05-12 15:27:29 +04:00
break ;
case SCU_EVENT_SATA_SPINUP_HOLD :
/* These events might be received since we dont know how many may be in
* the completion queue while waiting for power
*/
break ;
case SCU_EVENT_SATA_PHY_DETECTED :
2012-02-01 12:44:14 +04:00
iphy - > protocol = SAS_PROTOCOL_SATA ;
2011-05-12 15:27:29 +04:00
/* We have received the SATA PHY notification change state */
2011-06-29 02:05:53 +04:00
sci_change_state ( & iphy - > sm , SCI_PHY_SUB_AWAIT_SATA_SPEED_EN ) ;
2011-05-12 15:27:29 +04:00
break ;
case SCU_EVENT_SAS_PHY_DETECTED :
/* There has been a change in the phy type before OOB/SN for the
* SATA finished start down the SAS link traning path .
*/
2011-07-01 06:14:33 +04:00
sci_phy_start_sas_link_training ( iphy ) ;
2011-05-12 15:27:29 +04:00
break ;
default :
2012-02-10 13:18:49 +04:00
phy_event_warn ( iphy , state , event_code ) ;
2011-07-27 10:06:29 +04:00
return SCI_FAILURE ;
2011-05-12 15:27:29 +04:00
}
return SCI_SUCCESS ;
2011-06-02 04:10:43 +04:00
case SCI_PHY_SUB_AWAIT_SATA_SPEED_EN :
2011-05-12 15:27:29 +04:00
switch ( scu_get_event_code ( event_code ) ) {
case SCU_EVENT_SATA_PHY_DETECTED :
/*
* The hardware reports multiple SATA PHY detected events
* ignore the extras */
break ;
case SCU_EVENT_SATA_15 :
case SCU_EVENT_SATA_15_SSC :
2011-07-01 06:14:33 +04:00
sci_phy_complete_link_training ( iphy , SAS_LINK_RATE_1_5_GBPS ,
SCI_PHY_SUB_AWAIT_SIG_FIS_UF ) ;
2011-05-12 15:27:29 +04:00
break ;
case SCU_EVENT_SATA_30 :
case SCU_EVENT_SATA_30_SSC :
2011-07-01 06:14:33 +04:00
sci_phy_complete_link_training ( iphy , SAS_LINK_RATE_3_0_GBPS ,
SCI_PHY_SUB_AWAIT_SIG_FIS_UF ) ;
2011-05-12 15:27:29 +04:00
break ;
case SCU_EVENT_SATA_60 :
case SCU_EVENT_SATA_60_SSC :
2011-07-01 06:14:33 +04:00
sci_phy_complete_link_training ( iphy , SAS_LINK_RATE_6_0_GBPS ,
SCI_PHY_SUB_AWAIT_SIG_FIS_UF ) ;
2011-05-12 15:27:29 +04:00
break ;
case SCU_EVENT_LINK_FAILURE :
2012-03-08 23:38:50 +04:00
/* Change the timeout value to default */
scu_link_layer_set_txcomsas_timeout ( iphy , SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT ) ;
2011-05-12 15:27:29 +04:00
/* Link failure change state back to the starting state */
2011-06-29 02:05:53 +04:00
sci_change_state ( & iphy - > sm , SCI_PHY_STARTING ) ;
2011-05-12 15:27:29 +04:00
break ;
case SCU_EVENT_SAS_PHY_DETECTED :
/*
* There has been a change in the phy type before OOB / SN for the
* SATA finished start down the SAS link traning path . */
2011-07-01 06:14:33 +04:00
sci_phy_start_sas_link_training ( iphy ) ;
2011-05-12 15:27:29 +04:00
break ;
default :
2012-02-10 13:18:49 +04:00
phy_event_warn ( iphy , state , event_code ) ;
2011-05-12 15:27:29 +04:00
return SCI_FAILURE ;
}
return SCI_SUCCESS ;
2011-06-02 04:10:43 +04:00
case SCI_PHY_SUB_AWAIT_SIG_FIS_UF :
2011-05-12 15:27:29 +04:00
switch ( scu_get_event_code ( event_code ) ) {
case SCU_EVENT_SATA_PHY_DETECTED :
/* Backup the state machine */
2011-06-29 02:05:53 +04:00
sci_change_state ( & iphy - > sm , SCI_PHY_SUB_AWAIT_SATA_SPEED_EN ) ;
2011-05-12 15:27:29 +04:00
break ;
2011-05-11 03:54:23 +04:00
2011-05-12 15:27:29 +04:00
case SCU_EVENT_LINK_FAILURE :
2012-03-08 23:38:50 +04:00
/* Change the timeout value to default */
scu_link_layer_set_txcomsas_timeout ( iphy , SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT ) ;
2011-05-12 15:27:29 +04:00
/* Link failure change state back to the starting state */
2011-06-29 02:05:53 +04:00
sci_change_state ( & iphy - > sm , SCI_PHY_STARTING ) ;
2011-05-12 15:27:29 +04:00
break ;
default :
2012-02-10 13:18:49 +04:00
phy_event_warn ( iphy , state , event_code ) ;
2011-05-12 15:27:29 +04:00
return SCI_FAILURE ;
}
return SCI_SUCCESS ;
2011-06-02 04:10:43 +04:00
case SCI_PHY_READY :
2011-05-12 15:27:29 +04:00
switch ( scu_get_event_code ( event_code ) ) {
case SCU_EVENT_LINK_FAILURE :
2012-03-08 23:38:50 +04:00
/* Set default timeout */
scu_link_layer_set_txcomsas_timeout ( iphy , SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT ) ;
2011-05-12 15:27:29 +04:00
/* Link failure change state back to the starting state */
2011-06-29 02:05:53 +04:00
sci_change_state ( & iphy - > sm , SCI_PHY_STARTING ) ;
2011-05-12 15:27:29 +04:00
break ;
case SCU_EVENT_BROADCAST_CHANGE :
2012-02-24 13:38:49 +04:00
case SCU_EVENT_BROADCAST_SES :
case SCU_EVENT_BROADCAST_RESERVED0 :
case SCU_EVENT_BROADCAST_RESERVED1 :
case SCU_EVENT_BROADCAST_EXPANDER :
case SCU_EVENT_BROADCAST_AEN :
2011-05-12 15:27:29 +04:00
/* Broadcast change received. Notify the port. */
2011-06-29 02:05:53 +04:00
if ( phy_get_non_dummy_port ( iphy ) ! = NULL )
2011-07-01 06:14:33 +04:00
sci_port_broadcast_change_received ( iphy - > owning_port , iphy ) ;
2011-05-12 15:27:29 +04:00
else
2011-06-29 02:05:53 +04:00
iphy - > bcn_received_while_port_unassigned = true ;
2011-05-12 15:27:29 +04:00
break ;
2012-02-24 13:38:49 +04:00
case SCU_EVENT_BROADCAST_RESERVED3 :
case SCU_EVENT_BROADCAST_RESERVED4 :
2011-05-12 15:27:29 +04:00
default :
2012-02-10 13:18:49 +04:00
phy_event_warn ( iphy , state , event_code ) ;
2011-05-12 15:27:29 +04:00
return SCI_FAILURE_INVALID_STATE ;
}
return SCI_SUCCESS ;
2011-06-02 04:10:43 +04:00
case SCI_PHY_RESETTING :
2011-05-12 15:27:29 +04:00
switch ( scu_get_event_code ( event_code ) ) {
case SCU_EVENT_HARD_RESET_TRANSMITTED :
/* Link failure change state back to the starting state */
2011-06-29 02:05:53 +04:00
sci_change_state ( & iphy - > sm , SCI_PHY_STARTING ) ;
2011-05-12 15:27:29 +04:00
break ;
default :
2012-02-10 13:18:49 +04:00
phy_event_warn ( iphy , state , event_code ) ;
2011-05-12 15:27:29 +04:00
return SCI_FAILURE_INVALID_STATE ;
break ;
}
return SCI_SUCCESS ;
default :
2012-02-10 13:18:44 +04:00
dev_dbg ( sciphy_to_dev ( iphy ) , " %s: in wrong state: %s \n " ,
__func__ , phy_state_name ( state ) ) ;
2011-05-12 15:27:29 +04:00
return SCI_FAILURE_INVALID_STATE ;
}
2011-05-11 03:54:23 +04:00
}
2011-07-01 06:14:33 +04:00
enum sci_status sci_phy_frame_handler ( struct isci_phy * iphy , u32 frame_index )
2011-05-11 03:54:23 +04:00
{
2011-07-01 06:14:33 +04:00
enum sci_phy_states state = iphy - > sm . current_state_id ;
2011-07-01 04:38:32 +04:00
struct isci_host * ihost = iphy - > owning_port - > owning_controller ;
2011-05-12 15:27:29 +04:00
enum sci_status result ;
2011-06-24 10:44:52 +04:00
unsigned long flags ;
2011-05-11 03:54:23 +04:00
2011-05-12 15:27:29 +04:00
switch ( state ) {
2011-06-02 04:10:43 +04:00
case SCI_PHY_SUB_AWAIT_IAF_UF : {
2011-05-12 15:27:29 +04:00
u32 * frame_words ;
struct sas_identify_frame iaf ;
2011-05-11 03:54:23 +04:00
2011-07-01 06:14:33 +04:00
result = sci_unsolicited_frame_control_get_header ( & ihost - > uf_control ,
frame_index ,
( void * * ) & frame_words ) ;
2011-05-11 03:54:23 +04:00
2011-05-12 15:27:29 +04:00
if ( result ! = SCI_SUCCESS )
return result ;
sci_swab32_cpy ( & iaf , frame_words , sizeof ( iaf ) / sizeof ( u32 ) ) ;
if ( iaf . frame_type = = 0 ) {
u32 state ;
2011-06-24 10:44:52 +04:00
spin_lock_irqsave ( & iphy - > sas_phy . frame_rcvd_lock , flags ) ;
2011-05-12 15:27:29 +04:00
memcpy ( & iphy - > frame_rcvd . iaf , & iaf , sizeof ( iaf ) ) ;
2011-06-24 10:44:52 +04:00
spin_unlock_irqrestore ( & iphy - > sas_phy . frame_rcvd_lock , flags ) ;
2011-05-12 15:27:29 +04:00
if ( iaf . smp_tport ) {
/* We got the IAF for an expander PHY go to the final
* state since there are no power requirements for
* expander phys .
*/
2011-06-02 04:10:43 +04:00
state = SCI_PHY_SUB_FINAL ;
2011-05-12 15:27:29 +04:00
} else {
/* We got the IAF we can now go to the await spinup
* semaphore state
*/
2011-06-02 04:10:43 +04:00
state = SCI_PHY_SUB_AWAIT_SAS_POWER ;
2011-05-12 15:27:29 +04:00
}
2011-06-29 02:05:53 +04:00
sci_change_state ( & iphy - > sm , state ) ;
2011-05-12 15:27:29 +04:00
result = SCI_SUCCESS ;
} else
2011-06-29 02:05:53 +04:00
dev_warn ( sciphy_to_dev ( iphy ) ,
2011-05-12 15:27:29 +04:00
" %s: PHY starting substate machine received "
" unexpected frame id %x \n " ,
__func__ , frame_index ) ;
2011-07-01 06:14:33 +04:00
sci_controller_release_frame ( ihost , frame_index ) ;
2011-05-12 15:27:29 +04:00
return result ;
2011-05-11 03:54:23 +04:00
}
2011-06-02 04:10:43 +04:00
case SCI_PHY_SUB_AWAIT_SIG_FIS_UF : {
2011-05-12 15:27:29 +04:00
struct dev_to_host_fis * frame_header ;
u32 * fis_frame_data ;
2011-07-01 13:25:15 +04:00
result = sci_unsolicited_frame_control_get_header ( & ihost - > uf_control ,
frame_index ,
( void * * ) & frame_header ) ;
2011-05-12 15:27:29 +04:00
if ( result ! = SCI_SUCCESS )
return result ;
2011-05-11 03:54:23 +04:00
2011-05-12 15:27:29 +04:00
if ( ( frame_header - > fis_type = = FIS_REGD2H ) & &
! ( frame_header - > status & ATA_BUSY ) ) {
2011-07-01 06:14:33 +04:00
sci_unsolicited_frame_control_get_buffer ( & ihost - > uf_control ,
frame_index ,
( void * * ) & fis_frame_data ) ;
2011-05-12 15:27:29 +04:00
2011-06-24 10:44:52 +04:00
spin_lock_irqsave ( & iphy - > sas_phy . frame_rcvd_lock , flags ) ;
2011-07-01 06:14:33 +04:00
sci_controller_copy_sata_response ( & iphy - > frame_rcvd . fis ,
frame_header ,
fis_frame_data ) ;
2011-06-24 10:44:52 +04:00
spin_unlock_irqrestore ( & iphy - > sas_phy . frame_rcvd_lock , flags ) ;
2011-05-12 15:27:29 +04:00
/* got IAF we can now go to the await spinup semaphore state */
2011-06-29 02:05:53 +04:00
sci_change_state ( & iphy - > sm , SCI_PHY_SUB_FINAL ) ;
2011-05-12 15:27:29 +04:00
result = SCI_SUCCESS ;
} else
2011-06-29 02:05:53 +04:00
dev_warn ( sciphy_to_dev ( iphy ) ,
2011-05-12 15:27:29 +04:00
" %s: PHY starting substate machine received "
" unexpected frame id %x \n " ,
__func__ , frame_index ) ;
/* Regardless of the result we are done with this frame with it */
2011-07-01 06:14:33 +04:00
sci_controller_release_frame ( ihost , frame_index ) ;
2011-05-12 15:27:29 +04:00
return result ;
}
default :
2012-02-10 13:18:44 +04:00
dev_dbg ( sciphy_to_dev ( iphy ) , " %s: in wrong state: %s \n " ,
__func__ , phy_state_name ( state ) ) ;
2011-05-12 15:27:29 +04:00
return SCI_FAILURE_INVALID_STATE ;
}
2011-06-28 01:57:03 +04:00
2011-05-11 03:54:23 +04:00
}
2011-07-01 06:14:33 +04:00
static void sci_phy_starting_initial_substate_enter ( struct sci_base_state_machine * sm )
2011-05-10 13:28:45 +04:00
{
2011-06-29 02:05:53 +04:00
struct isci_phy * iphy = container_of ( sm , typeof ( * iphy ) , sm ) ;
2011-05-10 13:28:45 +04:00
/* This is just an temporary state go off to the starting state */
2011-06-29 02:05:53 +04:00
sci_change_state ( & iphy - > sm , SCI_PHY_SUB_AWAIT_OSSP_EN ) ;
2011-05-10 13:28:45 +04:00
}
2011-07-01 06:14:33 +04:00
static void sci_phy_starting_await_sas_power_substate_enter ( struct sci_base_state_machine * sm )
2011-05-10 13:28:45 +04:00
{
2011-06-29 02:05:53 +04:00
struct isci_phy * iphy = container_of ( sm , typeof ( * iphy ) , sm ) ;
2011-07-01 04:38:32 +04:00
struct isci_host * ihost = iphy - > owning_port - > owning_controller ;
2011-05-10 13:28:45 +04:00
2011-07-01 06:14:33 +04:00
sci_controller_power_control_queue_insert ( ihost , iphy ) ;
2011-05-10 13:28:45 +04:00
}
2011-07-01 06:14:33 +04:00
static void sci_phy_starting_await_sas_power_substate_exit ( struct sci_base_state_machine * sm )
2011-05-10 13:28:45 +04:00
{
2011-06-29 02:05:53 +04:00
struct isci_phy * iphy = container_of ( sm , typeof ( * iphy ) , sm ) ;
2011-07-01 04:38:32 +04:00
struct isci_host * ihost = iphy - > owning_port - > owning_controller ;
2011-05-10 13:28:45 +04:00
2011-07-01 06:14:33 +04:00
sci_controller_power_control_queue_remove ( ihost , iphy ) ;
2011-05-10 13:28:45 +04:00
}
2011-07-01 06:14:33 +04:00
static void sci_phy_starting_await_sata_power_substate_enter ( struct sci_base_state_machine * sm )
2011-05-10 13:28:45 +04:00
{
2011-06-29 02:05:53 +04:00
struct isci_phy * iphy = container_of ( sm , typeof ( * iphy ) , sm ) ;
2011-07-01 04:38:32 +04:00
struct isci_host * ihost = iphy - > owning_port - > owning_controller ;
2011-05-10 13:28:45 +04:00
2011-07-01 06:14:33 +04:00
sci_controller_power_control_queue_insert ( ihost , iphy ) ;
2011-05-10 13:28:45 +04:00
}
2011-07-01 06:14:33 +04:00
static void sci_phy_starting_await_sata_power_substate_exit ( struct sci_base_state_machine * sm )
2011-05-10 13:28:45 +04:00
{
2011-06-29 02:05:53 +04:00
struct isci_phy * iphy = container_of ( sm , typeof ( * iphy ) , sm ) ;
2011-07-01 04:38:32 +04:00
struct isci_host * ihost = iphy - > owning_port - > owning_controller ;
2011-05-10 13:28:45 +04:00
2011-07-01 06:14:33 +04:00
sci_controller_power_control_queue_remove ( ihost , iphy ) ;
2011-05-10 13:28:45 +04:00
}
2011-07-01 06:14:33 +04:00
static void sci_phy_starting_await_sata_phy_substate_enter ( struct sci_base_state_machine * sm )
2011-05-10 13:28:45 +04:00
{
2011-06-29 02:05:53 +04:00
struct isci_phy * iphy = container_of ( sm , typeof ( * iphy ) , sm ) ;
2011-05-10 13:28:45 +04:00
2011-06-29 02:05:53 +04:00
sci_mod_timer ( & iphy - > sata_timer , SCIC_SDS_SATA_LINK_TRAINING_TIMEOUT ) ;
2011-05-10 13:28:45 +04:00
}
2011-07-01 06:14:33 +04:00
static void sci_phy_starting_await_sata_phy_substate_exit ( struct sci_base_state_machine * sm )
2011-05-10 13:28:45 +04:00
{
2011-06-29 02:05:53 +04:00
struct isci_phy * iphy = container_of ( sm , typeof ( * iphy ) , sm ) ;
2011-05-10 13:28:45 +04:00
2011-06-29 02:05:53 +04:00
sci_del_timer ( & iphy - > sata_timer ) ;
2011-05-10 13:28:45 +04:00
}
2011-07-01 06:14:33 +04:00
static void sci_phy_starting_await_sata_speed_substate_enter ( struct sci_base_state_machine * sm )
2011-05-10 13:28:45 +04:00
{
2011-06-29 02:05:53 +04:00
struct isci_phy * iphy = container_of ( sm , typeof ( * iphy ) , sm ) ;
2011-05-10 13:28:45 +04:00
2011-06-29 02:05:53 +04:00
sci_mod_timer ( & iphy - > sata_timer , SCIC_SDS_SATA_LINK_TRAINING_TIMEOUT ) ;
2011-05-10 13:28:45 +04:00
}
2011-07-01 06:14:33 +04:00
static void sci_phy_starting_await_sata_speed_substate_exit ( struct sci_base_state_machine * sm )
2011-05-10 13:28:45 +04:00
{
2011-06-29 02:05:53 +04:00
struct isci_phy * iphy = container_of ( sm , typeof ( * iphy ) , sm ) ;
2011-05-10 13:28:45 +04:00
2011-06-29 02:05:53 +04:00
sci_del_timer ( & iphy - > sata_timer ) ;
2011-05-10 13:28:45 +04:00
}
2011-07-01 06:14:33 +04:00
static void sci_phy_starting_await_sig_fis_uf_substate_enter ( struct sci_base_state_machine * sm )
2011-05-10 13:28:45 +04:00
{
2011-06-29 02:05:53 +04:00
struct isci_phy * iphy = container_of ( sm , typeof ( * iphy ) , sm ) ;
2011-05-10 13:28:45 +04:00
2011-07-01 06:14:33 +04:00
if ( sci_port_link_detected ( iphy - > owning_port , iphy ) ) {
2011-05-10 13:28:45 +04:00
/*
* Clear the PE suspend condition so we can actually
* receive SIG FIS
* The hardware will not respond to the XRDY until the PE
* suspend condition is cleared .
*/
2011-07-01 06:14:33 +04:00
sci_phy_resume ( iphy ) ;
2011-05-10 13:28:45 +04:00
2011-06-29 02:05:53 +04:00
sci_mod_timer ( & iphy - > sata_timer ,
2011-05-19 15:59:36 +04:00
SCIC_SDS_SIGNATURE_FIS_TIMEOUT ) ;
2011-05-10 13:28:45 +04:00
} else
2011-06-29 02:05:53 +04:00
iphy - > is_in_link_training = false ;
2011-05-10 13:28:45 +04:00
}
2011-07-01 06:14:33 +04:00
static void sci_phy_starting_await_sig_fis_uf_substate_exit ( struct sci_base_state_machine * sm )
2011-05-10 13:28:45 +04:00
{
2011-06-29 02:05:53 +04:00
struct isci_phy * iphy = container_of ( sm , typeof ( * iphy ) , sm ) ;
2011-05-10 13:28:45 +04:00
2011-06-29 02:05:53 +04:00
sci_del_timer ( & iphy - > sata_timer ) ;
2011-05-10 13:28:45 +04:00
}
2011-07-01 06:14:33 +04:00
static void sci_phy_starting_final_substate_enter ( struct sci_base_state_machine * sm )
2011-05-10 13:28:45 +04:00
{
2011-06-29 02:05:53 +04:00
struct isci_phy * iphy = container_of ( sm , typeof ( * iphy ) , sm ) ;
2011-05-10 13:28:45 +04:00
/* State machine has run to completion so exit out and change
* the base state machine to the ready state
*/
2011-06-29 02:05:53 +04:00
sci_change_state ( & iphy - > sm , SCI_PHY_READY ) ;
2011-05-10 13:28:45 +04:00
}
/**
*
2011-06-29 02:05:53 +04:00
* @ sci_phy : This is the struct isci_phy object to stop .
2011-05-10 13:28:45 +04:00
*
2011-06-29 02:05:53 +04:00
* This method will stop the struct isci_phy object . This does not reset the
2011-05-10 13:28:45 +04:00
* protocol engine it just suspends it and places it in a state where it will
* not cause the end device to power up . none
*/
static void scu_link_layer_stop_protocol_engine (
2011-06-29 02:05:53 +04:00
struct isci_phy * iphy )
2011-05-10 13:28:45 +04:00
{
u32 scu_sas_pcfg_value ;
u32 enable_spinup_value ;
/* Suspend the protocol engine and place it in a sata spinup hold state */
scu_sas_pcfg_value =
2011-06-29 02:05:53 +04:00
readl ( & iphy - > link_layer_registers - > phy_configuration ) ;
2011-05-10 13:28:45 +04:00
scu_sas_pcfg_value | =
( SCU_SAS_PCFG_GEN_BIT ( OOB_RESET ) |
SCU_SAS_PCFG_GEN_BIT ( SUSPEND_PROTOCOL_ENGINE ) |
SCU_SAS_PCFG_GEN_BIT ( SATA_SPINUP_HOLD ) ) ;
writel ( scu_sas_pcfg_value ,
2011-06-29 02:05:53 +04:00
& iphy - > link_layer_registers - > phy_configuration ) ;
2011-05-10 13:28:45 +04:00
/* Disable the notify enable spinup primitives */
2011-06-29 02:05:53 +04:00
enable_spinup_value = readl ( & iphy - > link_layer_registers - > notify_enable_spinup_control ) ;
2011-05-10 13:28:45 +04:00
enable_spinup_value & = ~ SCU_ENSPINUP_GEN_BIT ( ENABLE ) ;
2011-06-29 02:05:53 +04:00
writel ( enable_spinup_value , & iphy - > link_layer_registers - > notify_enable_spinup_control ) ;
2011-05-10 13:28:45 +04:00
}
2012-01-04 13:33:36 +04:00
static void scu_link_layer_start_oob ( struct isci_phy * iphy )
2011-05-10 13:28:45 +04:00
{
2012-01-04 13:33:36 +04:00
struct scu_link_layer_registers __iomem * ll = iphy - > link_layer_registers ;
u32 val ;
/** Reset OOB sequence - start */
val = readl ( & ll - > phy_configuration ) ;
val & = ~ ( SCU_SAS_PCFG_GEN_BIT ( OOB_RESET ) |
2012-06-22 10:45:33 +04:00
SCU_SAS_PCFG_GEN_BIT ( OOB_ENABLE ) |
2012-01-04 13:33:36 +04:00
SCU_SAS_PCFG_GEN_BIT ( HARD_RESET ) ) ;
writel ( val , & ll - > phy_configuration ) ;
readl ( & ll - > phy_configuration ) ; /* flush */
/** Reset OOB sequence - end */
/** Start OOB sequence - start */
val = readl ( & ll - > phy_configuration ) ;
val | = SCU_SAS_PCFG_GEN_BIT ( OOB_ENABLE ) ;
writel ( val , & ll - > phy_configuration ) ;
readl ( & ll - > phy_configuration ) ; /* flush */
/** Start OOB sequence - end */
2011-05-10 13:28:45 +04:00
}
/**
*
*
* This method will transmit a hard reset request on the specified phy . The SCU
* hardware requires that we reset the OOB state machine and set the hard reset
* bit in the phy configuration register . We then must start OOB over with the
* hard reset bit set .
*/
static void scu_link_layer_tx_hard_reset (
2011-06-29 02:05:53 +04:00
struct isci_phy * iphy )
2011-05-10 13:28:45 +04:00
{
u32 phy_configuration_value ;
/*
* SAS Phys must wait for the HARD_RESET_TX event notification to transition
* to the starting state . */
phy_configuration_value =
2011-06-29 02:05:53 +04:00
readl ( & iphy - > link_layer_registers - > phy_configuration ) ;
2012-06-22 10:45:33 +04:00
phy_configuration_value & = ~ ( SCU_SAS_PCFG_GEN_BIT ( OOB_ENABLE ) ) ;
2011-05-10 13:28:45 +04:00
phy_configuration_value | =
( SCU_SAS_PCFG_GEN_BIT ( HARD_RESET ) |
SCU_SAS_PCFG_GEN_BIT ( OOB_RESET ) ) ;
writel ( phy_configuration_value ,
2011-06-29 02:05:53 +04:00
& iphy - > link_layer_registers - > phy_configuration ) ;
2011-05-10 13:28:45 +04:00
/* Now take the OOB state machine out of reset */
phy_configuration_value | = SCU_SAS_PCFG_GEN_BIT ( OOB_ENABLE ) ;
phy_configuration_value & = ~ SCU_SAS_PCFG_GEN_BIT ( OOB_RESET ) ;
writel ( phy_configuration_value ,
2011-06-29 02:05:53 +04:00
& iphy - > link_layer_registers - > phy_configuration ) ;
2011-05-10 13:28:45 +04:00
}
2011-07-01 06:14:33 +04:00
static void sci_phy_stopped_state_enter ( struct sci_base_state_machine * sm )
2011-05-10 13:28:45 +04:00
{
2011-06-29 02:05:53 +04:00
struct isci_phy * iphy = container_of ( sm , typeof ( * iphy ) , sm ) ;
2011-07-01 13:25:15 +04:00
struct isci_port * iport = iphy - > owning_port ;
struct isci_host * ihost = iport - > owning_controller ;
2011-05-10 13:28:45 +04:00
/*
* @ todo We need to get to the controller to place this PE in a
* reset state
*/
2011-06-29 02:05:53 +04:00
sci_del_timer ( & iphy - > sata_timer ) ;
2011-05-10 13:28:45 +04:00
2011-06-29 02:05:53 +04:00
scu_link_layer_stop_protocol_engine ( iphy ) ;
2011-05-10 13:28:45 +04:00
2011-06-29 02:05:53 +04:00
if ( iphy - > sm . previous_state_id ! = SCI_PHY_INITIAL )
2011-07-01 13:25:15 +04:00
sci_controller_link_down ( ihost , phy_get_non_dummy_port ( iphy ) , iphy ) ;
2011-05-10 13:28:45 +04:00
}
2011-07-01 06:14:33 +04:00
static void sci_phy_starting_state_enter ( struct sci_base_state_machine * sm )
2011-05-10 13:28:45 +04:00
{
2011-06-29 02:05:53 +04:00
struct isci_phy * iphy = container_of ( sm , typeof ( * iphy ) , sm ) ;
2011-07-01 13:25:15 +04:00
struct isci_port * iport = iphy - > owning_port ;
struct isci_host * ihost = iport - > owning_controller ;
2011-05-10 13:28:45 +04:00
2011-06-29 02:05:53 +04:00
scu_link_layer_stop_protocol_engine ( iphy ) ;
scu_link_layer_start_oob ( iphy ) ;
2011-05-10 13:28:45 +04:00
/* We don't know what kind of phy we are going to be just yet */
2012-02-01 12:44:14 +04:00
iphy - > protocol = SAS_PROTOCOL_NONE ;
2011-06-29 02:05:53 +04:00
iphy - > bcn_received_while_port_unassigned = false ;
2011-05-10 13:28:45 +04:00
2011-06-29 02:05:53 +04:00
if ( iphy - > sm . previous_state_id = = SCI_PHY_READY )
2011-07-01 13:25:15 +04:00
sci_controller_link_down ( ihost , phy_get_non_dummy_port ( iphy ) , iphy ) ;
2011-05-11 03:54:23 +04:00
2011-06-29 02:05:53 +04:00
sci_change_state ( & iphy - > sm , SCI_PHY_SUB_INITIAL ) ;
2011-05-10 13:28:45 +04:00
}
2011-07-01 06:14:33 +04:00
static void sci_phy_ready_state_enter ( struct sci_base_state_machine * sm )
2011-05-10 13:28:45 +04:00
{
2011-06-29 02:05:53 +04:00
struct isci_phy * iphy = container_of ( sm , typeof ( * iphy ) , sm ) ;
2011-07-01 13:25:15 +04:00
struct isci_port * iport = iphy - > owning_port ;
struct isci_host * ihost = iport - > owning_controller ;
2011-05-10 13:28:45 +04:00
2011-07-01 13:25:15 +04:00
sci_controller_link_up ( ihost , phy_get_non_dummy_port ( iphy ) , iphy ) ;
2011-05-10 13:28:45 +04:00
}
2011-07-01 06:14:33 +04:00
static void sci_phy_ready_state_exit ( struct sci_base_state_machine * sm )
2011-05-10 13:28:45 +04:00
{
2011-06-29 02:05:53 +04:00
struct isci_phy * iphy = container_of ( sm , typeof ( * iphy ) , sm ) ;
2011-05-10 13:28:45 +04:00
2011-07-01 06:14:33 +04:00
sci_phy_suspend ( iphy ) ;
2011-05-10 13:28:45 +04:00
}
2011-07-01 06:14:33 +04:00
static void sci_phy_resetting_state_enter ( struct sci_base_state_machine * sm )
2011-05-10 13:28:45 +04:00
{
2011-06-29 02:05:53 +04:00
struct isci_phy * iphy = container_of ( sm , typeof ( * iphy ) , sm ) ;
2011-05-10 13:28:45 +04:00
2011-05-12 15:51:41 +04:00
/* The phy is being reset, therefore deactivate it from the port. In
* the resetting state we don ' t notify the user regarding link up and
* link down notifications
*/
2011-07-01 06:14:33 +04:00
sci_port_deactivate_phy ( iphy - > owning_port , iphy , false ) ;
2011-05-10 13:28:45 +04:00
2012-02-01 12:44:14 +04:00
if ( iphy - > protocol = = SAS_PROTOCOL_SSP ) {
2011-06-29 02:05:53 +04:00
scu_link_layer_tx_hard_reset ( iphy ) ;
2011-05-10 13:28:45 +04:00
} else {
2011-05-12 15:51:41 +04:00
/* The SCU does not need to have a discrete reset state so
2011-05-10 13:28:45 +04:00
* just go back to the starting state .
*/
2011-06-29 02:05:53 +04:00
sci_change_state ( & iphy - > sm , SCI_PHY_STARTING ) ;
2011-05-10 13:28:45 +04:00
}
}
2011-07-01 06:14:33 +04:00
static const struct sci_base_state sci_phy_state_table [ ] = {
2011-06-02 04:10:43 +04:00
[ SCI_PHY_INITIAL ] = { } ,
[ SCI_PHY_STOPPED ] = {
2011-07-01 06:14:33 +04:00
. enter_state = sci_phy_stopped_state_enter ,
2011-05-10 13:28:45 +04:00
} ,
2011-06-02 04:10:43 +04:00
[ SCI_PHY_STARTING ] = {
2011-07-01 06:14:33 +04:00
. enter_state = sci_phy_starting_state_enter ,
2011-05-10 13:28:45 +04:00
} ,
2011-06-02 04:10:43 +04:00
[ SCI_PHY_SUB_INITIAL ] = {
2011-07-01 06:14:33 +04:00
. enter_state = sci_phy_starting_initial_substate_enter ,
2011-05-11 03:54:23 +04:00
} ,
2011-06-02 04:10:43 +04:00
[ SCI_PHY_SUB_AWAIT_OSSP_EN ] = { } ,
[ SCI_PHY_SUB_AWAIT_SAS_SPEED_EN ] = { } ,
[ SCI_PHY_SUB_AWAIT_IAF_UF ] = { } ,
[ SCI_PHY_SUB_AWAIT_SAS_POWER ] = {
2011-07-01 06:14:33 +04:00
. enter_state = sci_phy_starting_await_sas_power_substate_enter ,
. exit_state = sci_phy_starting_await_sas_power_substate_exit ,
2011-05-11 03:54:23 +04:00
} ,
2011-06-02 04:10:43 +04:00
[ SCI_PHY_SUB_AWAIT_SATA_POWER ] = {
2011-07-01 06:14:33 +04:00
. enter_state = sci_phy_starting_await_sata_power_substate_enter ,
. exit_state = sci_phy_starting_await_sata_power_substate_exit
2011-05-11 03:54:23 +04:00
} ,
2011-06-02 04:10:43 +04:00
[ SCI_PHY_SUB_AWAIT_SATA_PHY_EN ] = {
2011-07-01 06:14:33 +04:00
. enter_state = sci_phy_starting_await_sata_phy_substate_enter ,
. exit_state = sci_phy_starting_await_sata_phy_substate_exit
2011-05-11 03:54:23 +04:00
} ,
2011-06-02 04:10:43 +04:00
[ SCI_PHY_SUB_AWAIT_SATA_SPEED_EN ] = {
2011-07-01 06:14:33 +04:00
. enter_state = sci_phy_starting_await_sata_speed_substate_enter ,
. exit_state = sci_phy_starting_await_sata_speed_substate_exit
2011-05-11 03:54:23 +04:00
} ,
2011-06-02 04:10:43 +04:00
[ SCI_PHY_SUB_AWAIT_SIG_FIS_UF ] = {
2011-07-01 06:14:33 +04:00
. enter_state = sci_phy_starting_await_sig_fis_uf_substate_enter ,
. exit_state = sci_phy_starting_await_sig_fis_uf_substate_exit
2011-05-11 03:54:23 +04:00
} ,
2011-06-02 04:10:43 +04:00
[ SCI_PHY_SUB_FINAL ] = {
2011-07-01 06:14:33 +04:00
. enter_state = sci_phy_starting_final_substate_enter ,
2011-05-11 03:54:23 +04:00
} ,
2011-06-02 04:10:43 +04:00
[ SCI_PHY_READY ] = {
2011-07-01 06:14:33 +04:00
. enter_state = sci_phy_ready_state_enter ,
. exit_state = sci_phy_ready_state_exit ,
2011-05-10 13:28:45 +04:00
} ,
2011-06-02 04:10:43 +04:00
[ SCI_PHY_RESETTING ] = {
2011-07-01 06:14:33 +04:00
. enter_state = sci_phy_resetting_state_enter ,
2011-05-10 13:28:45 +04:00
} ,
2011-06-02 04:10:43 +04:00
[ SCI_PHY_FINAL ] = { } ,
2011-05-10 13:28:45 +04:00
} ;
2011-07-01 06:14:33 +04:00
void sci_phy_construct ( struct isci_phy * iphy ,
2011-06-30 00:09:25 +04:00
struct isci_port * iport , u8 phy_index )
2011-05-10 13:28:45 +04:00
{
2011-07-01 06:14:33 +04:00
sci_init_sm ( & iphy - > sm , sci_phy_state_table , SCI_PHY_INITIAL ) ;
2011-05-10 13:28:45 +04:00
/* Copy the rest of the input data to our locals */
2011-06-30 00:09:25 +04:00
iphy - > owning_port = iport ;
2011-06-29 02:05:53 +04:00
iphy - > phy_index = phy_index ;
iphy - > bcn_received_while_port_unassigned = false ;
2012-02-01 12:44:14 +04:00
iphy - > protocol = SAS_PROTOCOL_NONE ;
2011-06-29 02:05:53 +04:00
iphy - > link_layer_registers = NULL ;
iphy - > max_negotiated_speed = SAS_LINK_RATE_UNKNOWN ;
2011-05-19 15:59:36 +04:00
/* Create the SIGNATURE FIS Timeout timer for this phy */
2011-06-29 02:05:53 +04:00
sci_init_timer ( & iphy - > sata_timer , phy_sata_timeout ) ;
2011-05-10 13:28:45 +04:00
}
2011-07-03 09:56:22 +04:00
2011-05-07 04:36:38 +04:00
void isci_phy_init ( struct isci_phy * iphy , struct isci_host * ihost , int index )
2011-07-03 09:56:22 +04:00
{
2011-07-01 06:14:33 +04:00
struct sci_oem_params * oem = & ihost - > oem_parameters ;
2011-05-07 04:36:38 +04:00
u64 sci_sas_addr ;
__be64 sas_addr ;
2011-07-01 06:14:33 +04:00
sci_sas_addr = oem - > phys [ index ] . sas_address . high ;
2011-05-07 04:36:38 +04:00
sci_sas_addr < < = 32 ;
2011-07-01 06:14:33 +04:00
sci_sas_addr | = oem - > phys [ index ] . sas_address . low ;
2011-05-07 04:36:38 +04:00
sas_addr = cpu_to_be64 ( sci_sas_addr ) ;
memcpy ( iphy - > sas_addr , & sas_addr , sizeof ( sas_addr ) ) ;
iphy - > sas_phy . enabled = 0 ;
iphy - > sas_phy . id = index ;
iphy - > sas_phy . sas_addr = & iphy - > sas_addr [ 0 ] ;
iphy - > sas_phy . frame_rcvd = ( u8 * ) & iphy - > frame_rcvd ;
iphy - > sas_phy . ha = & ihost - > sas_ha ;
iphy - > sas_phy . lldd_phy = iphy ;
iphy - > sas_phy . enabled = 1 ;
iphy - > sas_phy . class = SAS ;
iphy - > sas_phy . iproto = SAS_PROTOCOL_ALL ;
iphy - > sas_phy . tproto = 0 ;
iphy - > sas_phy . type = PHY_TYPE_PHYSICAL ;
iphy - > sas_phy . role = PHY_ROLE_INITIATOR ;
iphy - > sas_phy . oob_mode = OOB_NOT_CONNECTED ;
iphy - > sas_phy . linkrate = SAS_LINK_RATE_UNKNOWN ;
memset ( & iphy - > frame_rcvd , 0 , sizeof ( iphy - > frame_rcvd ) ) ;
2011-07-03 09:56:22 +04:00
}
/**
* isci_phy_control ( ) - This function is one of the SAS Domain Template
* functions . This is a phy management function .
* @ phy : This parameter specifies the sphy being controlled .
* @ func : This parameter specifies the phy control function being invoked .
* @ buf : This parameter is specific to the phy function being invoked .
*
* status , zero indicates success .
*/
2011-03-02 23:31:24 +03:00
int isci_phy_control ( struct asd_sas_phy * sas_phy ,
enum phy_func func ,
void * buf )
2011-07-03 09:56:22 +04:00
{
2011-03-02 23:31:24 +03:00
int ret = 0 ;
struct isci_phy * iphy = sas_phy - > lldd_phy ;
2012-01-04 11:26:08 +04:00
struct asd_sas_port * port = sas_phy - > port ;
2011-03-02 23:31:24 +03:00
struct isci_host * ihost = sas_phy - > ha - > lldd_ha ;
unsigned long flags ;
2011-07-03 09:56:22 +04:00
2011-03-02 23:31:24 +03:00
dev_dbg ( & ihost - > pdev - > dev ,
" %s: phy %p; func %d; buf %p; isci phy %p, port %p \n " ,
2012-01-04 11:26:08 +04:00
__func__ , sas_phy , func , buf , iphy , port ) ;
2011-07-03 09:56:22 +04:00
switch ( func ) {
2011-03-02 23:31:24 +03:00
case PHY_FUNC_DISABLE :
spin_lock_irqsave ( & ihost - > scic_lock , flags ) ;
2012-03-09 10:42:07 +04:00
scu_link_layer_start_oob ( iphy ) ;
2011-07-01 06:14:33 +04:00
sci_phy_stop ( iphy ) ;
2011-03-02 23:31:24 +03:00
spin_unlock_irqrestore ( & ihost - > scic_lock , flags ) ;
break ;
2011-07-03 09:56:22 +04:00
case PHY_FUNC_LINK_RESET :
2011-03-02 23:31:24 +03:00
spin_lock_irqsave ( & ihost - > scic_lock , flags ) ;
2012-03-09 10:42:07 +04:00
scu_link_layer_start_oob ( iphy ) ;
2011-07-01 06:14:33 +04:00
sci_phy_stop ( iphy ) ;
sci_phy_start ( iphy ) ;
2011-03-02 23:31:24 +03:00
spin_unlock_irqrestore ( & ihost - > scic_lock , flags ) ;
break ;
case PHY_FUNC_HARD_RESET :
2012-01-04 11:26:08 +04:00
if ( ! port )
2011-03-02 23:31:24 +03:00
return - ENODEV ;
2011-07-03 09:56:22 +04:00
2012-01-04 11:26:08 +04:00
ret = isci_port_perform_hard_reset ( ihost , port - > lldd_port , iphy ) ;
2011-07-03 09:56:22 +04:00
break ;
2011-09-29 05:48:02 +04:00
case PHY_FUNC_GET_EVENTS : {
struct scu_link_layer_registers __iomem * r ;
struct sas_phy * phy = sas_phy - > phy ;
r = iphy - > link_layer_registers ;
phy - > running_disparity_error_count = readl ( & r - > running_disparity_error_count ) ;
phy - > loss_of_dword_sync_count = readl ( & r - > loss_of_sync_error_count ) ;
phy - > phy_reset_problem_count = readl ( & r - > phy_reset_problem_count ) ;
phy - > invalid_dword_count = readl ( & r - > invalid_dword_counter ) ;
break ;
}
2011-07-03 09:56:22 +04:00
default :
2011-03-02 23:31:24 +03:00
dev_dbg ( & ihost - > pdev - > dev ,
" %s: phy %p; func %d NOT IMPLEMENTED! \n " ,
__func__ , sas_phy , func ) ;
ret = - ENOSYS ;
2011-07-03 09:56:22 +04:00
break ;
}
return ret ;
}