2019-05-01 19:14:10 +03:00
// SPDX-License-Identifier: GPL-2.0
2006-08-29 18:22:51 +04:00
/*
* Serial Attached SCSI ( SAS ) Phy class
*
* Copyright ( C ) 2005 Adaptec , Inc . All rights reserved .
* Copyright ( C ) 2005 Luben Tuikov < luben_tuikov @ adaptec . com >
*/
# include "sas_internal.h"
# include <scsi/scsi_host.h>
# include <scsi/scsi_transport.h>
# include <scsi/scsi_transport_sas.h>
2021-07-16 10:45:51 +03:00
# include "scsi_sas_internal.h"
2006-08-29 18:22:51 +04:00
/* ---------- Phy events ---------- */
2006-11-22 17:57:56 +03:00
static void sas_phye_loss_of_signal ( struct work_struct * work )
2006-08-29 18:22:51 +04:00
{
2012-03-09 23:00:06 +04:00
struct asd_sas_event * ev = to_asd_sas_event ( work ) ;
2006-11-22 17:57:56 +03:00
struct asd_sas_phy * phy = ev - > phy ;
2006-08-29 18:22:51 +04:00
phy - > error = 0 ;
2011-05-25 00:17:53 +04:00
sas_deform_port ( phy , 1 ) ;
2006-08-29 18:22:51 +04:00
}
2006-11-22 17:57:56 +03:00
static void sas_phye_oob_done ( struct work_struct * work )
2006-08-29 18:22:51 +04:00
{
2012-03-09 23:00:06 +04:00
struct asd_sas_event * ev = to_asd_sas_event ( work ) ;
2006-11-22 17:57:56 +03:00
struct asd_sas_phy * phy = ev - > phy ;
2006-08-29 18:22:51 +04:00
phy - > error = 0 ;
}
2006-11-22 17:57:56 +03:00
static void sas_phye_oob_error ( struct work_struct * work )
2006-08-29 18:22:51 +04:00
{
2012-03-09 23:00:06 +04:00
struct asd_sas_event * ev = to_asd_sas_event ( work ) ;
2006-11-22 17:57:56 +03:00
struct asd_sas_phy * phy = ev - > phy ;
2006-08-29 18:22:51 +04:00
struct sas_ha_struct * sas_ha = phy - > ha ;
struct asd_sas_port * port = phy - > port ;
struct sas_internal * i =
to_sas_internal ( sas_ha - > core . shost - > transportt ) ;
2011-05-25 00:17:53 +04:00
sas_deform_port ( phy , 1 ) ;
2006-08-29 18:22:51 +04:00
if ( ! port & & phy - > enabled & & i - > dft - > lldd_control_phy ) {
phy - > error + + ;
switch ( phy - > error ) {
case 1 :
case 2 :
2006-09-07 04:28:07 +04:00
i - > dft - > lldd_control_phy ( phy , PHY_FUNC_HARD_RESET ,
NULL ) ;
2006-08-29 18:22:51 +04:00
break ;
case 3 :
default :
phy - > error = 0 ;
phy - > enabled = 0 ;
2006-09-07 04:28:07 +04:00
i - > dft - > lldd_control_phy ( phy , PHY_FUNC_DISABLE , NULL ) ;
2006-08-29 18:22:51 +04:00
break ;
}
}
}
2006-11-22 17:57:56 +03:00
static void sas_phye_spinup_hold ( struct work_struct * work )
2006-08-29 18:22:51 +04:00
{
2012-03-09 23:00:06 +04:00
struct asd_sas_event * ev = to_asd_sas_event ( work ) ;
2006-11-22 17:57:56 +03:00
struct asd_sas_phy * phy = ev - > phy ;
2006-08-29 18:22:51 +04:00
struct sas_ha_struct * sas_ha = phy - > ha ;
struct sas_internal * i =
to_sas_internal ( sas_ha - > core . shost - > transportt ) ;
phy - > error = 0 ;
2006-09-07 04:28:07 +04:00
i - > dft - > lldd_control_phy ( phy , PHY_FUNC_RELEASE_SPINUP_HOLD , NULL ) ;
2006-08-29 18:22:51 +04:00
}
2012-06-22 10:41:51 +04:00
static void sas_phye_resume_timeout ( struct work_struct * work )
{
struct asd_sas_event * ev = to_asd_sas_event ( work ) ;
struct asd_sas_phy * phy = ev - > phy ;
/* phew, lldd got the phy back in the nick of time */
if ( ! phy - > suspended ) {
dev_info ( & phy - > phy - > dev , " resume timeout cancelled \n " ) ;
return ;
}
phy - > error = 0 ;
phy - > suspended = 0 ;
sas_deform_port ( phy , 1 ) ;
}
2017-12-08 12:42:05 +03:00
static void sas_phye_shutdown ( struct work_struct * work )
{
struct asd_sas_event * ev = to_asd_sas_event ( work ) ;
struct asd_sas_phy * phy = ev - > phy ;
struct sas_ha_struct * sas_ha = phy - > ha ;
struct sas_internal * i =
to_sas_internal ( sas_ha - > core . shost - > transportt ) ;
if ( phy - > enabled ) {
int ret ;
phy - > error = 0 ;
phy - > enabled = 0 ;
ret = i - > dft - > lldd_control_phy ( phy , PHY_FUNC_DISABLE , NULL ) ;
if ( ret )
2019-04-12 11:57:57 +03:00
pr_notice ( " lldd disable phy%d returned %d \n " , phy - > id ,
ret ) ;
2017-12-08 12:42:05 +03:00
} else
2019-04-12 11:57:57 +03:00
pr_notice ( " phy%d is not enabled, cannot shutdown \n " , phy - > id ) ;
2019-05-14 05:42:38 +03:00
phy - > in_shutdown = 0 ;
2017-12-08 12:42:05 +03:00
}
2006-08-29 18:22:51 +04:00
/* ---------- Phy class registration ---------- */
int sas_register_phys ( struct sas_ha_struct * sas_ha )
{
int i ;
/* Now register the phys. */
for ( i = 0 ; i < sas_ha - > num_phys ; i + + ) {
struct asd_sas_phy * phy = sas_ha - > sas_phy [ i ] ;
phy - > error = 0 ;
2017-12-08 12:42:05 +03:00
atomic_set ( & phy - > event_nr , 0 ) ;
2006-08-29 18:22:51 +04:00
INIT_LIST_HEAD ( & phy - > port_phy_el ) ;
phy - > port = NULL ;
phy - > ha = sas_ha ;
spin_lock_init ( & phy - > frame_rcvd_lock ) ;
spin_lock_init ( & phy - > sas_prim_lock ) ;
phy - > frame_rcvd_size = 0 ;
2012-03-09 23:00:06 +04:00
phy - > phy = sas_phy_alloc ( & sas_ha - > core . shost - > shost_gendev , i ) ;
2006-08-29 18:22:51 +04:00
if ( ! phy - > phy )
return - ENOMEM ;
phy - > phy - > identify . initiator_port_protocols =
phy - > iproto ;
phy - > phy - > identify . target_port_protocols = phy - > tproto ;
phy - > phy - > identify . sas_address = SAS_ADDR ( sas_ha - > sas_addr ) ;
phy - > phy - > identify . phy_identifier = i ;
2006-09-07 04:28:07 +04:00
phy - > phy - > minimum_linkrate_hw = SAS_LINK_RATE_UNKNOWN ;
phy - > phy - > maximum_linkrate_hw = SAS_LINK_RATE_UNKNOWN ;
phy - > phy - > minimum_linkrate = SAS_LINK_RATE_UNKNOWN ;
phy - > phy - > maximum_linkrate = SAS_LINK_RATE_UNKNOWN ;
2006-08-29 18:22:51 +04:00
phy - > phy - > negotiated_linkrate = SAS_LINK_RATE_UNKNOWN ;
sas_phy_add ( phy - > phy ) ;
}
return 0 ;
}
2017-12-08 12:42:04 +03:00
const work_func_t sas_phy_event_fns [ PHY_NUM_EVENTS ] = {
[ PHYE_LOSS_OF_SIGNAL ] = sas_phye_loss_of_signal ,
[ PHYE_OOB_DONE ] = sas_phye_oob_done ,
[ PHYE_OOB_ERROR ] = sas_phye_oob_error ,
[ PHYE_SPINUP_HOLD ] = sas_phye_spinup_hold ,
[ PHYE_RESUME_TIMEOUT ] = sas_phye_resume_timeout ,
2017-12-08 12:42:05 +03:00
[ PHYE_SHUTDOWN ] = sas_phye_shutdown ,
2017-12-08 12:42:04 +03:00
} ;