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 ) Event processing
*
* Copyright ( C ) 2005 Adaptec , Inc . All rights reserved .
* Copyright ( C ) 2005 Luben Tuikov < luben_tuikov @ adaptec . com >
*/
2011-12-20 04:42:34 +04:00
# include <linux/export.h>
2006-08-29 18:22:51 +04:00
# include <scsi/scsi_host.h>
# include "sas_internal.h"
2017-06-14 14:52:43 +03:00
int sas_queue_work ( struct sas_ha_struct * ha , struct sas_work * sw )
2011-12-20 04:42:34 +04:00
{
2017-12-08 12:42:04 +03:00
/* it's added to the defer_q when draining so return succeed */
int rc = 1 ;
2017-06-14 14:52:43 +03:00
2011-12-20 04:42:34 +04:00
if ( ! test_bit ( SAS_HA_REGISTERED , & ha - > state ) )
2017-06-14 14:52:43 +03:00
return 0 ;
2011-12-20 04:42:34 +04:00
2012-03-09 23:00:06 +04:00
if ( test_bit ( SAS_HA_DRAINING , & ha - > state ) ) {
/* add it to the defer list, if not already pending */
if ( list_empty ( & sw - > drain_node ) )
2017-09-06 12:15:14 +03:00
list_add_tail ( & sw - > drain_node , & ha - > defer_q ) ;
2012-03-09 23:00:06 +04:00
} else
2017-12-08 12:42:07 +03:00
rc = queue_work ( ha - > event_q , & sw - > work ) ;
2017-06-14 14:52:43 +03:00
return rc ;
2011-12-20 04:42:34 +04:00
}
2017-12-08 12:42:04 +03:00
static int sas_queue_event ( int event , struct sas_work * work ,
2011-12-20 04:42:34 +04:00
struct sas_ha_struct * ha )
{
2017-12-08 12:42:04 +03:00
unsigned long flags ;
int rc ;
2017-06-14 14:52:43 +03:00
2017-12-08 12:42:04 +03:00
spin_lock_irqsave ( & ha - > lock , flags ) ;
rc = sas_queue_work ( ha , work ) ;
spin_unlock_irqrestore ( & ha - > lock , flags ) ;
2017-06-14 14:52:43 +03:00
return rc ;
2011-12-20 04:42:34 +04:00
}
2012-01-12 23:47:24 +04:00
void __sas_drain_work ( struct sas_ha_struct * ha )
2011-12-20 04:42:34 +04:00
{
2012-03-09 23:00:06 +04:00
struct sas_work * sw , * _sw ;
2017-12-08 12:42:04 +03:00
int ret ;
2011-12-20 04:42:34 +04:00
set_bit ( SAS_HA_DRAINING , & ha - > state ) ;
/* flush submitters */
2012-06-22 10:25:27 +04:00
spin_lock_irq ( & ha - > lock ) ;
spin_unlock_irq ( & ha - > lock ) ;
2011-12-20 04:42:34 +04:00
2017-12-08 12:42:07 +03:00
drain_workqueue ( ha - > event_q ) ;
drain_workqueue ( ha - > disco_q ) ;
2011-12-20 04:42:34 +04:00
2012-06-22 10:25:27 +04:00
spin_lock_irq ( & ha - > lock ) ;
2011-12-20 04:42:34 +04:00
clear_bit ( SAS_HA_DRAINING , & ha - > state ) ;
2012-03-09 23:00:06 +04:00
list_for_each_entry_safe ( sw , _sw , & ha - > defer_q , drain_node ) {
list_del_init ( & sw - > drain_node ) ;
2017-12-08 12:42:04 +03:00
ret = sas_queue_work ( ha , sw ) ;
if ( ret ! = 1 )
sas_free_event ( to_asd_sas_event ( & sw - > work ) ) ;
2011-12-20 04:42:34 +04:00
}
2012-06-22 10:25:27 +04:00
spin_unlock_irq ( & ha - > lock ) ;
2012-01-12 23:47:24 +04:00
}
int sas_drain_work ( struct sas_ha_struct * ha )
{
int err ;
err = mutex_lock_interruptible ( & ha - > drain_mutex ) ;
if ( err )
return err ;
if ( test_bit ( SAS_HA_REGISTERED , & ha - > state ) )
__sas_drain_work ( ha ) ;
2011-12-20 04:42:34 +04:00
mutex_unlock ( & ha - > drain_mutex ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( sas_drain_work ) ;
2011-11-18 05:59:51 +04:00
void sas_disable_revalidation ( struct sas_ha_struct * ha )
{
mutex_lock ( & ha - > disco_mutex ) ;
set_bit ( SAS_HA_ATA_EH_ACTIVE , & ha - > state ) ;
mutex_unlock ( & ha - > disco_mutex ) ;
}
void sas_enable_revalidation ( struct sas_ha_struct * ha )
{
int i ;
mutex_lock ( & ha - > disco_mutex ) ;
clear_bit ( SAS_HA_ATA_EH_ACTIVE , & ha - > state ) ;
for ( i = 0 ; i < ha - > num_phys ; i + + ) {
struct asd_sas_port * port = ha - > sas_port [ i ] ;
const int ev = DISCE_REVALIDATE_DOMAIN ;
struct sas_discovery * d = & port - > disc ;
2017-12-08 12:42:10 +03:00
struct asd_sas_phy * sas_phy ;
2011-11-18 05:59:51 +04:00
if ( ! test_and_clear_bit ( ev , & d - > pending ) )
continue ;
2017-12-08 12:42:10 +03:00
if ( list_empty ( & port - > phy_list ) )
continue ;
sas_phy = container_of ( port - > phy_list . next , struct asd_sas_phy ,
port_phy_el ) ;
ha - > notify_port_event ( sas_phy , PORTE_BROADCAST_RCVD ) ;
2011-11-18 05:59:51 +04:00
}
mutex_unlock ( & ha - > disco_mutex ) ;
}
2017-12-08 12:42:04 +03:00
static void sas_port_event_worker ( struct work_struct * work )
{
struct asd_sas_event * ev = to_asd_sas_event ( work ) ;
sas_port_event_fns [ ev - > event ] ( work ) ;
sas_free_event ( ev ) ;
}
static void sas_phy_event_worker ( struct work_struct * work )
{
struct asd_sas_event * ev = to_asd_sas_event ( work ) ;
sas_phy_event_fns [ ev - > event ] ( work ) ;
sas_free_event ( ev ) ;
}
2017-09-06 12:15:07 +03:00
static int sas_notify_port_event ( struct asd_sas_phy * phy , enum port_event event )
2006-08-29 18:22:51 +04:00
{
2017-12-08 12:42:04 +03:00
struct asd_sas_event * ev ;
2006-08-29 18:22:51 +04:00
struct sas_ha_struct * ha = phy - > ha ;
2017-12-08 12:42:04 +03:00
int ret ;
2006-08-29 18:22:51 +04:00
BUG_ON ( event > = PORT_NUM_EVENTS ) ;
2017-12-08 12:42:04 +03:00
ev = sas_alloc_event ( phy ) ;
if ( ! ev )
return - ENOMEM ;
INIT_SAS_EVENT ( ev , sas_port_event_worker , phy , event ) ;
ret = sas_queue_event ( event , & ev - > work , ha ) ;
if ( ret ! = 1 )
sas_free_event ( ev ) ;
return ret ;
2006-08-29 18:22:51 +04:00
}
2017-06-14 14:52:43 +03:00
int sas_notify_phy_event ( struct asd_sas_phy * phy , enum phy_event event )
2006-08-29 18:22:51 +04:00
{
2017-12-08 12:42:04 +03:00
struct asd_sas_event * ev ;
2006-08-29 18:22:51 +04:00
struct sas_ha_struct * ha = phy - > ha ;
2017-12-08 12:42:04 +03:00
int ret ;
2006-08-29 18:22:51 +04:00
BUG_ON ( event > = PHY_NUM_EVENTS ) ;
2017-12-08 12:42:04 +03:00
ev = sas_alloc_event ( phy ) ;
if ( ! ev )
return - ENOMEM ;
INIT_SAS_EVENT ( ev , sas_phy_event_worker , phy , event ) ;
ret = sas_queue_event ( event , & ev - > work , ha ) ;
if ( ret ! = 1 )
sas_free_event ( ev ) ;
return ret ;
2006-08-29 18:22:51 +04:00
}
int sas_init_events ( struct sas_ha_struct * sas_ha )
{
2017-09-06 12:15:07 +03:00
sas_ha - > notify_port_event = sas_notify_port_event ;
2012-06-22 10:41:51 +04:00
sas_ha - > notify_phy_event = sas_notify_phy_event ;
2006-08-29 18:22:51 +04:00
return 0 ;
}