2007-09-07 09:15:31 +02:00
/*
2008-06-10 18:20:58 +02:00
* zfcp device driver
2005-04-16 15:20:36 -07:00
*
2008-06-10 18:20:58 +02:00
* Error Recovery Procedures ( ERP ) .
2007-09-07 09:15:31 +02:00
*
2008-06-10 18:20:58 +02:00
* Copyright IBM Corporation 2002 , 2008
2005-04-16 15:20:36 -07:00
*/
# include "zfcp_ext.h"
2008-07-02 10:56:40 +02:00
# define ZFCP_MAX_ERPS 3
enum zfcp_erp_act_flags {
ZFCP_STATUS_ERP_TIMEDOUT = 0x10000000 ,
ZFCP_STATUS_ERP_CLOSE_ONLY = 0x01000000 ,
ZFCP_STATUS_ERP_DISMISSING = 0x00100000 ,
ZFCP_STATUS_ERP_DISMISSED = 0x00200000 ,
ZFCP_STATUS_ERP_LOWMEM = 0x00400000 ,
} ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
enum zfcp_erp_steps {
ZFCP_ERP_STEP_UNINITIALIZED = 0x0000 ,
ZFCP_ERP_STEP_FSF_XCONFIG = 0x0001 ,
ZFCP_ERP_STEP_PHYS_PORT_CLOSING = 0x0010 ,
ZFCP_ERP_STEP_PORT_CLOSING = 0x0100 ,
ZFCP_ERP_STEP_NAMESERVER_LOOKUP = 0x0400 ,
ZFCP_ERP_STEP_PORT_OPENING = 0x0800 ,
ZFCP_ERP_STEP_UNIT_CLOSING = 0x1000 ,
ZFCP_ERP_STEP_UNIT_OPENING = 0x2000 ,
} ;
enum zfcp_erp_act_type {
ZFCP_ERP_ACTION_REOPEN_UNIT = 1 ,
ZFCP_ERP_ACTION_REOPEN_PORT = 2 ,
ZFCP_ERP_ACTION_REOPEN_PORT_FORCED = 3 ,
ZFCP_ERP_ACTION_REOPEN_ADAPTER = 4 ,
} ;
enum zfcp_erp_act_state {
ZFCP_ERP_ACTION_RUNNING = 1 ,
ZFCP_ERP_ACTION_READY = 2 ,
} ;
enum zfcp_erp_act_result {
ZFCP_ERP_SUCCEEDED = 0 ,
ZFCP_ERP_FAILED = 1 ,
ZFCP_ERP_CONTINUES = 2 ,
ZFCP_ERP_EXIT = 3 ,
ZFCP_ERP_DISMISSED = 4 ,
ZFCP_ERP_NOMEM = 5 ,
} ;
static void zfcp_erp_adapter_block ( struct zfcp_adapter * adapter , int mask )
2005-04-16 15:20:36 -07:00
{
2008-07-02 10:56:40 +02:00
zfcp_erp_modify_adapter_status ( adapter , 15 , NULL ,
ZFCP_STATUS_COMMON_UNBLOCKED | mask ,
ZFCP_CLEAR ) ;
2006-09-18 22:29:56 +02:00
}
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
static int zfcp_erp_action_exists ( struct zfcp_erp_action * act )
2006-09-18 22:29:56 +02:00
{
2008-07-02 10:56:40 +02:00
struct zfcp_erp_action * curr_act ;
list_for_each_entry ( curr_act , & act - > adapter - > erp_running_head , list )
if ( act = = curr_act )
return ZFCP_ERP_ACTION_RUNNING ;
return 0 ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
static void zfcp_erp_action_ready ( struct zfcp_erp_action * act )
2006-09-18 22:29:56 +02:00
{
2008-07-02 10:56:40 +02:00
struct zfcp_adapter * adapter = act - > adapter ;
list_move ( & act - > list , & act - > adapter - > erp_ready_head ) ;
zfcp_rec_dbf_event_action ( 146 , act ) ;
up ( & adapter - > erp_ready_sem ) ;
zfcp_rec_dbf_event_thread ( 2 , adapter ) ;
2006-09-18 22:29:56 +02:00
}
2008-07-02 10:56:40 +02:00
static void zfcp_erp_action_dismiss ( struct zfcp_erp_action * act )
2005-04-16 15:20:36 -07:00
{
2008-07-02 10:56:40 +02:00
act - > status | = ZFCP_STATUS_ERP_DISMISSED ;
if ( zfcp_erp_action_exists ( act ) = = ZFCP_ERP_ACTION_RUNNING )
zfcp_erp_action_ready ( act ) ;
}
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
static void zfcp_erp_action_dismiss_unit ( struct zfcp_unit * unit )
{
if ( atomic_read ( & unit - > status ) & ZFCP_STATUS_COMMON_ERP_INUSE )
zfcp_erp_action_dismiss ( & unit - > erp_action ) ;
}
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
static void zfcp_erp_action_dismiss_port ( struct zfcp_port * port )
{
struct zfcp_unit * unit ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
if ( atomic_read ( & port - > status ) & ZFCP_STATUS_COMMON_ERP_INUSE )
zfcp_erp_action_dismiss ( & port - > erp_action ) ;
else
list_for_each_entry ( unit , & port - > unit_list_head , list )
zfcp_erp_action_dismiss_unit ( unit ) ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
static void zfcp_erp_action_dismiss_adapter ( struct zfcp_adapter * adapter )
2005-04-16 15:20:36 -07:00
{
2008-07-02 10:56:40 +02:00
struct zfcp_port * port ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
if ( atomic_read ( & adapter - > status ) & ZFCP_STATUS_COMMON_ERP_INUSE )
zfcp_erp_action_dismiss ( & adapter - > erp_action ) ;
else
list_for_each_entry ( port , & adapter - > port_list_head , list )
zfcp_erp_action_dismiss_port ( port ) ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
static int zfcp_erp_required_act ( int want , struct zfcp_adapter * adapter ,
struct zfcp_port * port ,
struct zfcp_unit * unit )
2005-04-16 15:20:36 -07:00
{
2008-07-02 10:56:40 +02:00
int need = want ;
int u_status , p_status , a_status ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
switch ( want ) {
case ZFCP_ERP_ACTION_REOPEN_UNIT :
u_status = atomic_read ( & unit - > status ) ;
if ( u_status & ZFCP_STATUS_COMMON_ERP_INUSE )
return 0 ;
p_status = atomic_read ( & port - > status ) ;
if ( ! ( p_status & ZFCP_STATUS_COMMON_RUNNING ) | |
p_status & ZFCP_STATUS_COMMON_ERP_FAILED )
return 0 ;
if ( ! ( p_status & ZFCP_STATUS_COMMON_UNBLOCKED ) )
need = ZFCP_ERP_ACTION_REOPEN_PORT ;
/* fall through */
case ZFCP_ERP_ACTION_REOPEN_PORT :
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED :
p_status = atomic_read ( & port - > status ) ;
if ( p_status & ZFCP_STATUS_COMMON_ERP_INUSE )
return 0 ;
a_status = atomic_read ( & adapter - > status ) ;
if ( ! ( a_status & ZFCP_STATUS_COMMON_RUNNING ) | |
a_status & ZFCP_STATUS_COMMON_ERP_FAILED )
return 0 ;
if ( ! ( a_status & ZFCP_STATUS_COMMON_UNBLOCKED ) )
need = ZFCP_ERP_ACTION_REOPEN_ADAPTER ;
/* fall through */
case ZFCP_ERP_ACTION_REOPEN_ADAPTER :
a_status = atomic_read ( & adapter - > status ) ;
if ( a_status & ZFCP_STATUS_COMMON_ERP_INUSE )
return 0 ;
}
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
return need ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
static struct zfcp_erp_action * zfcp_erp_setup_act ( int need ,
struct zfcp_adapter * adapter ,
struct zfcp_port * port ,
struct zfcp_unit * unit )
2005-04-16 15:20:36 -07:00
{
2008-07-02 10:56:40 +02:00
struct zfcp_erp_action * erp_action ;
u32 status = 0 ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
switch ( need ) {
case ZFCP_ERP_ACTION_REOPEN_UNIT :
zfcp_unit_get ( unit ) ;
atomic_set_mask ( ZFCP_STATUS_COMMON_ERP_INUSE , & unit - > status ) ;
erp_action = & unit - > erp_action ;
if ( ! ( atomic_read ( & unit - > status ) & ZFCP_STATUS_COMMON_RUNNING ) )
status = ZFCP_STATUS_ERP_CLOSE_ONLY ;
break ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
case ZFCP_ERP_ACTION_REOPEN_PORT :
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED :
zfcp_port_get ( port ) ;
zfcp_erp_action_dismiss_port ( port ) ;
atomic_set_mask ( ZFCP_STATUS_COMMON_ERP_INUSE , & port - > status ) ;
erp_action = & port - > erp_action ;
if ( ! ( atomic_read ( & port - > status ) & ZFCP_STATUS_COMMON_RUNNING ) )
status = ZFCP_STATUS_ERP_CLOSE_ONLY ;
break ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
case ZFCP_ERP_ACTION_REOPEN_ADAPTER :
zfcp_adapter_get ( adapter ) ;
zfcp_erp_action_dismiss_adapter ( adapter ) ;
atomic_set_mask ( ZFCP_STATUS_COMMON_ERP_INUSE , & adapter - > status ) ;
erp_action = & adapter - > erp_action ;
if ( ! ( atomic_read ( & adapter - > status ) &
ZFCP_STATUS_COMMON_RUNNING ) )
status = ZFCP_STATUS_ERP_CLOSE_ONLY ;
break ;
default :
return NULL ;
}
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
memset ( erp_action , 0 , sizeof ( struct zfcp_erp_action ) ) ;
erp_action - > adapter = adapter ;
erp_action - > port = port ;
erp_action - > unit = unit ;
erp_action - > action = need ;
erp_action - > status = status ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
return erp_action ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
static int zfcp_erp_action_enqueue ( int want , struct zfcp_adapter * adapter ,
struct zfcp_port * port ,
struct zfcp_unit * unit , u8 id , void * ref )
2005-04-16 15:20:36 -07:00
{
2008-07-02 10:56:40 +02:00
int retval = 1 , need ;
struct zfcp_erp_action * act = NULL ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
if ( ! ( atomic_read ( & adapter - > status ) &
ZFCP_STATUS_ADAPTER_ERP_THREAD_UP ) )
return - EIO ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
need = zfcp_erp_required_act ( want , adapter , port , unit ) ;
if ( ! need )
2005-04-16 15:20:36 -07:00
goto out ;
2008-07-02 10:56:40 +02:00
atomic_set_mask ( ZFCP_STATUS_ADAPTER_ERP_PENDING , & adapter - > status ) ;
act = zfcp_erp_setup_act ( need , adapter , port , unit ) ;
if ( ! act )
goto out ;
+ + adapter - > erp_total_count ;
list_add_tail ( & act - > list , & adapter - > erp_ready_head ) ;
up ( & adapter - > erp_ready_sem ) ;
zfcp_rec_dbf_event_thread ( 1 , adapter ) ;
retval = 0 ;
2005-04-16 15:20:36 -07:00
out :
2008-07-02 10:56:40 +02:00
zfcp_rec_dbf_event_trigger ( id , ref , want , need , act ,
adapter , port , unit ) ;
2005-04-16 15:20:36 -07:00
return retval ;
}
2008-07-02 10:56:40 +02:00
static int _zfcp_erp_adapter_reopen ( struct zfcp_adapter * adapter ,
int clear_mask , u8 id , void * ref )
{
zfcp_erp_adapter_block ( adapter , clear_mask ) ;
/* ensure propagation of failed status to new devices */
if ( atomic_read ( & adapter - > status ) & ZFCP_STATUS_COMMON_ERP_FAILED ) {
zfcp_erp_adapter_failed ( adapter , 13 , NULL ) ;
return - EIO ;
}
return zfcp_erp_action_enqueue ( ZFCP_ERP_ACTION_REOPEN_ADAPTER ,
adapter , NULL , NULL , id , ref ) ;
}
/**
* zfcp_erp_adapter_reopen - Reopen adapter .
* @ adapter : Adapter to reopen .
* @ clear : Status flags to clear .
* @ id : Id for debug trace event .
* @ ref : Reference for debug trace event .
2005-04-16 15:20:36 -07:00
*/
2008-07-02 10:56:40 +02:00
void zfcp_erp_adapter_reopen ( struct zfcp_adapter * adapter , int clear ,
u8 id , void * ref )
2005-04-16 15:20:36 -07:00
{
unsigned long flags ;
read_lock_irqsave ( & zfcp_data . config_lock , flags ) ;
write_lock ( & adapter - > erp_lock ) ;
2008-07-02 10:56:40 +02:00
_zfcp_erp_adapter_reopen ( adapter , clear , id , ref ) ;
2005-04-16 15:20:36 -07:00
write_unlock ( & adapter - > erp_lock ) ;
read_unlock_irqrestore ( & zfcp_data . config_lock , flags ) ;
2008-07-02 10:56:40 +02:00
}
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
/**
* zfcp_erp_adapter_shutdown - Shutdown adapter .
* @ adapter : Adapter to shut down .
* @ clear : Status flags to clear .
* @ id : Id for debug trace event .
* @ ref : Reference for debug trace event .
*/
void zfcp_erp_adapter_shutdown ( struct zfcp_adapter * adapter , int clear ,
u8 id , void * ref )
{
int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED ;
zfcp_erp_adapter_reopen ( adapter , clear | flags , id , ref ) ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
/**
* zfcp_erp_port_shutdown - Shutdown port
* @ port : Port to shut down .
* @ clear : Status flags to clear .
* @ id : Id for debug trace event .
* @ ref : Reference for debug trace event .
2005-04-16 15:20:36 -07:00
*/
2008-07-02 10:56:40 +02:00
void zfcp_erp_port_shutdown ( struct zfcp_port * port , int clear , u8 id , void * ref )
2005-04-16 15:20:36 -07:00
{
2008-07-02 10:56:40 +02:00
int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED ;
zfcp_erp_port_reopen ( port , clear | flags , id , ref ) ;
}
/**
* zfcp_erp_unit_shutdown - Shutdown unit
* @ unit : Unit to shut down .
* @ clear : Status flags to clear .
* @ id : Id for debug trace event .
* @ ref : Reference for debug trace event .
*/
void zfcp_erp_unit_shutdown ( struct zfcp_unit * unit , int clear , u8 id , void * ref )
{
int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED ;
zfcp_erp_unit_reopen ( unit , clear | flags , id , ref ) ;
}
static void zfcp_erp_port_block ( struct zfcp_port * port , int clear )
{
zfcp_erp_modify_port_status ( port , 17 , NULL ,
ZFCP_STATUS_COMMON_UNBLOCKED | clear ,
ZFCP_CLEAR ) ;
}
static void _zfcp_erp_port_forced_reopen ( struct zfcp_port * port ,
int clear , u8 id , void * ref )
{
zfcp_erp_port_block ( port , clear ) ;
if ( atomic_read ( & port - > status ) & ZFCP_STATUS_COMMON_ERP_FAILED )
return ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
zfcp_erp_action_enqueue ( ZFCP_ERP_ACTION_REOPEN_PORT_FORCED ,
port - > adapter , port , NULL , id , ref ) ;
}
/**
* zfcp_erp_port_forced_reopen - Forced close of port and open again
* @ port : Port to force close and to reopen .
* @ id : Id for debug trace event .
* @ ref : Reference for debug trace event .
*/
void zfcp_erp_port_forced_reopen ( struct zfcp_port * port , int clear , u8 id ,
void * ref )
{
unsigned long flags ;
struct zfcp_adapter * adapter = port - > adapter ;
read_lock_irqsave ( & zfcp_data . config_lock , flags ) ;
write_lock ( & adapter - > erp_lock ) ;
_zfcp_erp_port_forced_reopen ( port , clear , id , ref ) ;
write_unlock ( & adapter - > erp_lock ) ;
read_unlock_irqrestore ( & zfcp_data . config_lock , flags ) ;
}
static int _zfcp_erp_port_reopen ( struct zfcp_port * port , int clear , u8 id ,
void * ref )
{
zfcp_erp_port_block ( port , clear ) ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
if ( atomic_read ( & port - > status ) & ZFCP_STATUS_COMMON_ERP_FAILED ) {
2005-04-16 15:20:36 -07:00
/* ensure propagation of failed status to new devices */
2008-04-18 12:51:55 +02:00
zfcp_erp_port_failed ( port , 14 , NULL ) ;
2008-07-02 10:56:40 +02:00
return - EIO ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
return zfcp_erp_action_enqueue ( ZFCP_ERP_ACTION_REOPEN_PORT ,
port - > adapter , port , NULL , id , ref ) ;
2005-04-16 15:20:36 -07:00
}
/**
2008-07-02 10:56:40 +02:00
* zfcp_erp_port_reopen - trigger remote port recovery
* @ port : port to recover
* @ clear_mask : flags in port status to be cleared
2005-04-16 15:20:36 -07:00
*
2008-07-02 10:56:40 +02:00
* Returns 0 if recovery has been triggered , < 0 if not .
2005-04-16 15:20:36 -07:00
*/
2008-07-02 10:56:40 +02:00
int zfcp_erp_port_reopen ( struct zfcp_port * port , int clear , u8 id , void * ref )
2005-04-16 15:20:36 -07:00
{
unsigned long flags ;
2008-07-02 10:56:40 +02:00
int retval ;
2005-04-16 15:20:36 -07:00
struct zfcp_adapter * adapter = port - > adapter ;
read_lock_irqsave ( & zfcp_data . config_lock , flags ) ;
write_lock ( & adapter - > erp_lock ) ;
2008-07-02 10:56:40 +02:00
retval = _zfcp_erp_port_reopen ( port , clear , id , ref ) ;
2005-04-16 15:20:36 -07:00
write_unlock ( & adapter - > erp_lock ) ;
read_unlock_irqrestore ( & zfcp_data . config_lock , flags ) ;
return retval ;
}
2008-07-02 10:56:40 +02:00
static void zfcp_erp_unit_block ( struct zfcp_unit * unit , int clear_mask )
{
zfcp_erp_modify_unit_status ( unit , 19 , NULL ,
ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask ,
ZFCP_CLEAR ) ;
}
static void _zfcp_erp_unit_reopen ( struct zfcp_unit * unit , int clear , u8 id ,
void * ref )
2005-04-16 15:20:36 -07:00
{
struct zfcp_adapter * adapter = unit - > port - > adapter ;
2008-07-02 10:56:40 +02:00
zfcp_erp_unit_block ( unit , clear ) ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
if ( atomic_read ( & unit - > status ) & ZFCP_STATUS_COMMON_ERP_FAILED )
return ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
zfcp_erp_action_enqueue ( ZFCP_ERP_ACTION_REOPEN_UNIT ,
adapter , unit - > port , unit , id , ref ) ;
2005-04-16 15:20:36 -07:00
}
/**
* zfcp_erp_unit_reopen - initiate reopen of a unit
* @ unit : unit to be reopened
* @ clear_mask : specifies flags in unit status to be cleared
* Return : 0 on success , < 0 on error
*/
2008-07-02 10:56:40 +02:00
void zfcp_erp_unit_reopen ( struct zfcp_unit * unit , int clear , u8 id , void * ref )
2005-04-16 15:20:36 -07:00
{
unsigned long flags ;
2008-07-02 10:56:40 +02:00
struct zfcp_port * port = unit - > port ;
struct zfcp_adapter * adapter = port - > adapter ;
2005-04-16 15:20:36 -07:00
read_lock_irqsave ( & zfcp_data . config_lock , flags ) ;
write_lock ( & adapter - > erp_lock ) ;
2008-07-02 10:56:40 +02:00
_zfcp_erp_unit_reopen ( unit , clear , id , ref ) ;
2005-04-16 15:20:36 -07:00
write_unlock ( & adapter - > erp_lock ) ;
read_unlock_irqrestore ( & zfcp_data . config_lock , flags ) ;
}
2008-07-02 10:56:40 +02:00
static int status_change_set ( unsigned long mask , atomic_t * status )
2005-04-16 15:20:36 -07:00
{
2008-07-02 10:56:40 +02:00
return ( atomic_read ( status ) ^ mask ) & mask ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
static int status_change_clear ( unsigned long mask , atomic_t * status )
2008-03-27 14:22:02 +01:00
{
2008-07-02 10:56:40 +02:00
return atomic_read ( status ) & mask ;
2008-03-27 14:22:02 +01:00
}
2008-07-02 10:56:40 +02:00
static void zfcp_erp_adapter_unblock ( struct zfcp_adapter * adapter )
2008-03-27 14:22:02 +01:00
{
2008-07-02 10:56:40 +02:00
if ( status_change_set ( ZFCP_STATUS_COMMON_UNBLOCKED , & adapter - > status ) )
zfcp_rec_dbf_event_adapter ( 16 , NULL , adapter ) ;
atomic_set_mask ( ZFCP_STATUS_COMMON_UNBLOCKED , & adapter - > status ) ;
2008-03-27 14:22:02 +01:00
}
2008-07-02 10:56:40 +02:00
static void zfcp_erp_port_unblock ( struct zfcp_port * port )
2005-04-16 15:20:36 -07:00
{
2008-07-02 10:56:40 +02:00
if ( status_change_set ( ZFCP_STATUS_COMMON_UNBLOCKED , & port - > status ) )
zfcp_rec_dbf_event_port ( 18 , NULL , port ) ;
atomic_set_mask ( ZFCP_STATUS_COMMON_UNBLOCKED , & port - > status ) ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
static void zfcp_erp_unit_unblock ( struct zfcp_unit * unit )
2005-04-16 15:20:36 -07:00
{
2008-07-02 10:56:40 +02:00
if ( status_change_set ( ZFCP_STATUS_COMMON_UNBLOCKED , & unit - > status ) )
zfcp_rec_dbf_event_unit ( 20 , NULL , unit ) ;
atomic_set_mask ( ZFCP_STATUS_COMMON_UNBLOCKED , & unit - > status ) ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
static void zfcp_erp_action_to_running ( struct zfcp_erp_action * erp_action )
2005-04-16 15:20:36 -07:00
{
2008-07-02 10:56:40 +02:00
list_move ( & erp_action - > list , & erp_action - > adapter - > erp_running_head ) ;
zfcp_rec_dbf_event_action ( 145 , erp_action ) ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
static void zfcp_erp_strategy_check_fsfreq ( struct zfcp_erp_action * act )
2005-04-16 15:20:36 -07:00
{
2008-07-02 10:56:40 +02:00
struct zfcp_adapter * adapter = act - > adapter ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
if ( ! act - > fsf_req )
return ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
spin_lock ( & adapter - > req_list_lock ) ;
if ( zfcp_reqlist_find_safe ( adapter , act - > fsf_req ) & &
act - > fsf_req - > erp_action = = act ) {
if ( act - > status & ( ZFCP_STATUS_ERP_DISMISSED |
ZFCP_STATUS_ERP_TIMEDOUT ) ) {
act - > fsf_req - > status | = ZFCP_STATUS_FSFREQ_DISMISSED ;
zfcp_rec_dbf_event_action ( 142 , act ) ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
if ( act - > status & ZFCP_STATUS_ERP_TIMEDOUT )
zfcp_rec_dbf_event_action ( 143 , act ) ;
if ( act - > fsf_req - > status & ( ZFCP_STATUS_FSFREQ_COMPLETED |
ZFCP_STATUS_FSFREQ_DISMISSED ) )
act - > fsf_req = NULL ;
} else
act - > fsf_req = NULL ;
spin_unlock ( & adapter - > req_list_lock ) ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
/**
* zfcp_erp_notify - Trigger ERP action .
* @ erp_action : ERP action to continue .
* @ set_mask : ERP action status flags to set .
2005-04-16 15:20:36 -07:00
*/
2008-07-02 10:56:40 +02:00
void zfcp_erp_notify ( struct zfcp_erp_action * erp_action , unsigned long set_mask )
2005-04-16 15:20:36 -07:00
{
struct zfcp_adapter * adapter = erp_action - > adapter ;
2008-07-02 10:56:40 +02:00
unsigned long flags ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
write_lock_irqsave ( & adapter - > erp_lock , flags ) ;
2005-04-16 15:20:36 -07:00
if ( zfcp_erp_action_exists ( erp_action ) = = ZFCP_ERP_ACTION_RUNNING ) {
erp_action - > status | = set_mask ;
zfcp_erp_action_ready ( erp_action ) ;
}
write_unlock_irqrestore ( & adapter - > erp_lock , flags ) ;
}
2008-07-02 10:56:40 +02:00
/**
* zfcp_erp_timeout_handler - Trigger ERP action from timed out ERP request
* @ data : ERP action ( from timer data )
2005-04-16 15:20:36 -07:00
*/
2008-07-02 10:56:40 +02:00
void zfcp_erp_timeout_handler ( unsigned long data )
2005-04-16 15:20:36 -07:00
{
2008-07-02 10:56:40 +02:00
struct zfcp_erp_action * act = ( struct zfcp_erp_action * ) data ;
zfcp_erp_notify ( act , ZFCP_STATUS_ERP_TIMEDOUT ) ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
static void zfcp_erp_memwait_handler ( unsigned long data )
2005-04-16 15:20:36 -07:00
{
2008-07-02 10:56:40 +02:00
zfcp_erp_notify ( ( struct zfcp_erp_action * ) data , 0 ) ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
static void zfcp_erp_strategy_memwait ( struct zfcp_erp_action * erp_action )
2005-04-16 15:20:36 -07:00
{
2008-07-02 10:56:40 +02:00
init_timer ( & erp_action - > timer ) ;
erp_action - > timer . function = zfcp_erp_memwait_handler ;
erp_action - > timer . data = ( unsigned long ) erp_action ;
erp_action - > timer . expires = jiffies + HZ ;
add_timer ( & erp_action - > timer ) ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
static void _zfcp_erp_port_reopen_all ( struct zfcp_adapter * adapter ,
int clear , u8 id , void * ref )
2005-04-16 15:20:36 -07:00
{
2008-07-02 10:56:40 +02:00
struct zfcp_port * port ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
list_for_each_entry ( port , & adapter - > port_list_head , list )
2008-10-01 12:42:17 +02:00
_zfcp_erp_port_reopen ( port , clear , id , ref ) ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
static void _zfcp_erp_unit_reopen_all ( struct zfcp_port * port , int clear , u8 id ,
void * ref )
2005-04-16 15:20:36 -07:00
{
2008-07-02 10:56:40 +02:00
struct zfcp_unit * unit ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
list_for_each_entry ( unit , & port - > unit_list_head , list )
_zfcp_erp_unit_reopen ( unit , clear , id , ref ) ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
static void zfcp_erp_strategy_followup_actions ( struct zfcp_erp_action * act )
2005-04-16 15:20:36 -07:00
{
2008-07-02 10:56:40 +02:00
struct zfcp_adapter * adapter = act - > adapter ;
struct zfcp_port * port = act - > port ;
struct zfcp_unit * unit = act - > unit ;
u32 status = act - > status ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
/* initiate follow-up actions depending on success of finished action */
switch ( act - > action ) {
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
case ZFCP_ERP_ACTION_REOPEN_ADAPTER :
if ( status = = ZFCP_ERP_SUCCEEDED )
_zfcp_erp_port_reopen_all ( adapter , 0 , 70 , NULL ) ;
else
_zfcp_erp_adapter_reopen ( adapter , 0 , 71 , NULL ) ;
break ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED :
if ( status = = ZFCP_ERP_SUCCEEDED )
_zfcp_erp_port_reopen ( port , 0 , 72 , NULL ) ;
else
_zfcp_erp_adapter_reopen ( adapter , 0 , 73 , NULL ) ;
break ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
case ZFCP_ERP_ACTION_REOPEN_PORT :
if ( status = = ZFCP_ERP_SUCCEEDED )
_zfcp_erp_unit_reopen_all ( port , 0 , 74 , NULL ) ;
else
_zfcp_erp_port_forced_reopen ( port , 0 , 75 , NULL ) ;
break ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
case ZFCP_ERP_ACTION_REOPEN_UNIT :
if ( status ! = ZFCP_ERP_SUCCEEDED )
_zfcp_erp_port_reopen ( unit - > port , 0 , 76 , NULL ) ;
break ;
2005-04-16 15:20:36 -07:00
}
}
2008-07-02 10:56:40 +02:00
static void zfcp_erp_wakeup ( struct zfcp_adapter * adapter )
2005-04-16 15:20:36 -07:00
{
unsigned long flags ;
read_lock_irqsave ( & zfcp_data . config_lock , flags ) ;
2008-07-02 10:56:40 +02:00
read_lock ( & adapter - > erp_lock ) ;
if ( list_empty ( & adapter - > erp_ready_head ) & &
list_empty ( & adapter - > erp_running_head ) ) {
atomic_clear_mask ( ZFCP_STATUS_ADAPTER_ERP_PENDING ,
& adapter - > status ) ;
wake_up ( & adapter - > erp_done_wqh ) ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
read_unlock ( & adapter - > erp_lock ) ;
read_unlock_irqrestore ( & zfcp_data . config_lock , flags ) ;
}
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
static int zfcp_erp_adapter_strategy_open_qdio ( struct zfcp_erp_action * act )
{
if ( zfcp_qdio_open ( act - > adapter ) )
return ZFCP_ERP_FAILED ;
init_waitqueue_head ( & act - > adapter - > request_wq ) ;
atomic_set_mask ( ZFCP_STATUS_ADAPTER_QDIOUP , & act - > adapter - > status ) ;
return ZFCP_ERP_SUCCEEDED ;
}
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
static void zfcp_erp_enqueue_ptp_port ( struct zfcp_adapter * adapter )
{
struct zfcp_port * port ;
port = zfcp_port_enqueue ( adapter , adapter - > peer_wwpn , 0 ,
adapter - > peer_d_id ) ;
if ( IS_ERR ( port ) ) /* error or port already attached */
return ;
_zfcp_erp_port_reopen ( port , 0 , 150 , NULL ) ;
}
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
static int zfcp_erp_adapter_strat_fsf_xconf ( struct zfcp_erp_action * erp_action )
{
int retries ;
int sleep = 1 ;
struct zfcp_adapter * adapter = erp_action - > adapter ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
atomic_clear_mask ( ZFCP_STATUS_ADAPTER_XCONFIG_OK , & adapter - > status ) ;
for ( retries = 7 ; retries ; retries - - ) {
atomic_clear_mask ( ZFCP_STATUS_ADAPTER_HOST_CON_INIT ,
& adapter - > status ) ;
write_lock_irq ( & adapter - > erp_lock ) ;
zfcp_erp_action_to_running ( erp_action ) ;
write_unlock_irq ( & adapter - > erp_lock ) ;
if ( zfcp_fsf_exchange_config_data ( erp_action ) ) {
atomic_clear_mask ( ZFCP_STATUS_ADAPTER_HOST_CON_INIT ,
& adapter - > status ) ;
return ZFCP_ERP_FAILED ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
zfcp_rec_dbf_event_thread_lock ( 6 , adapter ) ;
down ( & adapter - > erp_ready_sem ) ;
zfcp_rec_dbf_event_thread_lock ( 7 , adapter ) ;
if ( erp_action - > status & ZFCP_STATUS_ERP_TIMEDOUT )
break ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
if ( ! ( atomic_read ( & adapter - > status ) &
ZFCP_STATUS_ADAPTER_HOST_CON_INIT ) )
break ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
ssleep ( sleep ) ;
sleep * = 2 ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
atomic_clear_mask ( ZFCP_STATUS_ADAPTER_HOST_CON_INIT ,
& adapter - > status ) ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
if ( ! ( atomic_read ( & adapter - > status ) & ZFCP_STATUS_ADAPTER_XCONFIG_OK ) )
return ZFCP_ERP_FAILED ;
2007-09-07 09:15:31 +02:00
2008-07-02 10:56:40 +02:00
if ( fc_host_port_type ( adapter - > scsi_host ) = = FC_PORTTYPE_PTP )
zfcp_erp_enqueue_ptp_port ( adapter ) ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
return ZFCP_ERP_SUCCEEDED ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
static int zfcp_erp_adapter_strategy_open_fsf_xport ( struct zfcp_erp_action * act )
2005-04-16 15:20:36 -07:00
{
2008-07-02 10:56:40 +02:00
int ret ;
struct zfcp_adapter * adapter = act - > adapter ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
write_lock_irq ( & adapter - > erp_lock ) ;
zfcp_erp_action_to_running ( act ) ;
write_unlock_irq ( & adapter - > erp_lock ) ;
ret = zfcp_fsf_exchange_port_data ( act ) ;
if ( ret = = - EOPNOTSUPP )
return ZFCP_ERP_SUCCEEDED ;
if ( ret )
return ZFCP_ERP_FAILED ;
zfcp_rec_dbf_event_thread_lock ( 8 , adapter ) ;
down ( & adapter - > erp_ready_sem ) ;
zfcp_rec_dbf_event_thread_lock ( 9 , adapter ) ;
if ( act - > status & ZFCP_STATUS_ERP_TIMEDOUT )
return ZFCP_ERP_FAILED ;
return ZFCP_ERP_SUCCEEDED ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
static int zfcp_erp_adapter_strategy_open_fsf ( struct zfcp_erp_action * act )
2005-04-16 15:20:36 -07:00
{
2008-07-02 10:56:40 +02:00
if ( zfcp_erp_adapter_strat_fsf_xconf ( act ) = = ZFCP_ERP_FAILED )
return ZFCP_ERP_FAILED ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
if ( zfcp_erp_adapter_strategy_open_fsf_xport ( act ) = = ZFCP_ERP_FAILED )
return ZFCP_ERP_FAILED ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
atomic_set ( & act - > adapter - > stat_miss , 16 ) ;
if ( zfcp_status_read_refill ( act - > adapter ) )
return ZFCP_ERP_FAILED ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
return ZFCP_ERP_SUCCEEDED ;
}
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
static int zfcp_erp_adapter_strategy_generic ( struct zfcp_erp_action * act ,
int close )
{
int retval = ZFCP_ERP_SUCCEEDED ;
struct zfcp_adapter * adapter = act - > adapter ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
if ( close )
goto close_only ;
retval = zfcp_erp_adapter_strategy_open_qdio ( act ) ;
if ( retval ! = ZFCP_ERP_SUCCEEDED )
goto failed_qdio ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
retval = zfcp_erp_adapter_strategy_open_fsf ( act ) ;
if ( retval ! = ZFCP_ERP_SUCCEEDED )
goto failed_openfcp ;
atomic_set_mask ( ZFCP_STATUS_COMMON_OPEN , & act - > adapter - > status ) ;
schedule_work ( & act - > adapter - > scan_work ) ;
return ZFCP_ERP_SUCCEEDED ;
close_only :
atomic_clear_mask ( ZFCP_STATUS_COMMON_OPEN ,
& act - > adapter - > status ) ;
failed_openfcp :
/* close queues to ensure that buffers are not accessed by adapter */
zfcp_qdio_close ( adapter ) ;
zfcp_fsf_req_dismiss_all ( adapter ) ;
adapter - > fsf_req_seq_no = 0 ;
/* all ports and units are closed */
zfcp_erp_modify_adapter_status ( adapter , 24 , NULL ,
ZFCP_STATUS_COMMON_OPEN , ZFCP_CLEAR ) ;
failed_qdio :
atomic_clear_mask ( ZFCP_STATUS_ADAPTER_XCONFIG_OK |
2008-10-01 12:42:16 +02:00
ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED ,
2008-07-02 10:56:40 +02:00
& act - > adapter - > status ) ;
2005-04-16 15:20:36 -07:00
return retval ;
}
2008-07-02 10:56:40 +02:00
static int zfcp_erp_adapter_strategy ( struct zfcp_erp_action * act )
2005-04-16 15:20:36 -07:00
{
2008-07-02 10:56:40 +02:00
int retval ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
zfcp_erp_adapter_strategy_generic ( act , 1 ) ; /* close */
if ( act - > status & ZFCP_STATUS_ERP_CLOSE_ONLY )
return ZFCP_ERP_EXIT ;
retval = zfcp_erp_adapter_strategy_generic ( act , 0 ) ; /* open */
if ( retval = = ZFCP_ERP_FAILED )
ssleep ( 8 ) ;
2005-04-16 15:20:36 -07:00
return retval ;
}
2008-07-02 10:56:40 +02:00
static int zfcp_erp_port_forced_strategy_close ( struct zfcp_erp_action * act )
2005-04-16 15:20:36 -07:00
{
2008-07-02 10:56:40 +02:00
int retval ;
retval = zfcp_fsf_close_physical_port ( act ) ;
if ( retval = = - ENOMEM )
return ZFCP_ERP_NOMEM ;
act - > step = ZFCP_ERP_STEP_PHYS_PORT_CLOSING ;
if ( retval )
return ZFCP_ERP_FAILED ;
return ZFCP_ERP_CONTINUES ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
static void zfcp_erp_port_strategy_clearstati ( struct zfcp_port * port )
2005-04-16 15:20:36 -07:00
{
2008-10-01 12:42:16 +02:00
atomic_clear_mask ( ZFCP_STATUS_COMMON_ACCESS_DENIED |
2008-07-02 10:56:40 +02:00
ZFCP_STATUS_PORT_PHYS_CLOSING |
ZFCP_STATUS_PORT_INVALID_WWPN ,
& port - > status ) ;
}
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
static int zfcp_erp_port_forced_strategy ( struct zfcp_erp_action * erp_action )
{
struct zfcp_port * port = erp_action - > port ;
int status = atomic_read ( & port - > status ) ;
switch ( erp_action - > step ) {
case ZFCP_ERP_STEP_UNINITIALIZED :
zfcp_erp_port_strategy_clearstati ( port ) ;
if ( ( status & ZFCP_STATUS_PORT_PHYS_OPEN ) & &
( status & ZFCP_STATUS_COMMON_OPEN ) )
return zfcp_erp_port_forced_strategy_close ( erp_action ) ;
else
return ZFCP_ERP_FAILED ;
case ZFCP_ERP_STEP_PHYS_PORT_CLOSING :
if ( status & ZFCP_STATUS_PORT_PHYS_OPEN )
return ZFCP_ERP_SUCCEEDED ;
}
return ZFCP_ERP_FAILED ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
static int zfcp_erp_port_strategy_close ( struct zfcp_erp_action * erp_action )
2005-04-16 15:20:36 -07:00
{
2008-07-02 10:56:40 +02:00
int retval ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
retval = zfcp_fsf_close_port ( erp_action ) ;
if ( retval = = - ENOMEM )
return ZFCP_ERP_NOMEM ;
erp_action - > step = ZFCP_ERP_STEP_PORT_CLOSING ;
if ( retval )
return ZFCP_ERP_FAILED ;
return ZFCP_ERP_CONTINUES ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
static int zfcp_erp_port_strategy_open_port ( struct zfcp_erp_action * erp_action )
2005-04-16 15:20:36 -07:00
{
2008-07-02 10:56:40 +02:00
int retval ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
retval = zfcp_fsf_open_port ( erp_action ) ;
if ( retval = = - ENOMEM )
return ZFCP_ERP_NOMEM ;
erp_action - > step = ZFCP_ERP_STEP_PORT_OPENING ;
if ( retval )
return ZFCP_ERP_FAILED ;
return ZFCP_ERP_CONTINUES ;
}
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
static int zfcp_erp_open_ptp_port ( struct zfcp_erp_action * act )
2005-04-16 15:20:36 -07:00
{
2008-07-02 10:56:40 +02:00
struct zfcp_adapter * adapter = act - > adapter ;
struct zfcp_port * port = act - > port ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
if ( port - > wwpn ! = adapter - > peer_wwpn ) {
zfcp_erp_port_failed ( port , 25 , NULL ) ;
return ZFCP_ERP_FAILED ;
}
port - > d_id = adapter - > peer_d_id ;
atomic_set_mask ( ZFCP_STATUS_PORT_DID_DID , & port - > status ) ;
return zfcp_erp_port_strategy_open_port ( act ) ;
}
2008-10-01 12:42:17 +02:00
void zfcp_erp_port_strategy_open_lookup ( struct work_struct * work )
{
int retval ;
struct zfcp_port * port = container_of ( work , struct zfcp_port ,
gid_pn_work ) ;
retval = zfcp_fc_ns_gid_pn ( & port - > erp_action ) ;
if ( retval = = - ENOMEM )
zfcp_erp_notify ( & port - > erp_action , ZFCP_ERP_NOMEM ) ;
port - > erp_action . step = ZFCP_ERP_STEP_NAMESERVER_LOOKUP ;
if ( retval )
zfcp_erp_notify ( & port - > erp_action , ZFCP_ERP_FAILED ) ;
}
2008-07-02 10:56:40 +02:00
static int zfcp_erp_port_strategy_open_common ( struct zfcp_erp_action * act )
{
struct zfcp_adapter * adapter = act - > adapter ;
struct zfcp_port * port = act - > port ;
int p_status = atomic_read ( & port - > status ) ;
switch ( act - > step ) {
case ZFCP_ERP_STEP_UNINITIALIZED :
case ZFCP_ERP_STEP_PHYS_PORT_CLOSING :
case ZFCP_ERP_STEP_PORT_CLOSING :
if ( fc_host_port_type ( adapter - > scsi_host ) = = FC_PORTTYPE_PTP )
return zfcp_erp_open_ptp_port ( act ) ;
2008-10-01 12:42:17 +02:00
if ( ! ( p_status & ZFCP_STATUS_PORT_DID_DID ) ) {
2008-10-01 12:42:22 +02:00
queue_work ( zfcp_data . work_queue , & port - > gid_pn_work ) ;
2008-10-01 12:42:17 +02:00
return ZFCP_ERP_CONTINUES ;
2008-07-02 10:56:40 +02:00
}
case ZFCP_ERP_STEP_NAMESERVER_LOOKUP :
if ( ! ( p_status & ZFCP_STATUS_PORT_DID_DID ) ) {
if ( p_status & ( ZFCP_STATUS_PORT_INVALID_WWPN ) ) {
zfcp_erp_port_failed ( port , 26 , NULL ) ;
return ZFCP_ERP_EXIT ;
}
return ZFCP_ERP_FAILED ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
return zfcp_erp_port_strategy_open_port ( act ) ;
case ZFCP_ERP_STEP_PORT_OPENING :
/* D_ID might have changed during open */
2008-10-01 12:42:17 +02:00
if ( p_status & ZFCP_STATUS_COMMON_OPEN ) {
if ( p_status & ZFCP_STATUS_PORT_DID_DID )
return ZFCP_ERP_SUCCEEDED ;
else {
act - > step = ZFCP_ERP_STEP_PORT_CLOSING ;
return ZFCP_ERP_CONTINUES ;
}
2008-07-02 10:56:40 +02:00
/* fall through otherwise */
2008-10-01 12:42:17 +02:00
}
2008-07-02 10:56:40 +02:00
}
return ZFCP_ERP_FAILED ;
}
static int zfcp_erp_port_strategy ( struct zfcp_erp_action * erp_action )
{
struct zfcp_port * port = erp_action - > port ;
2008-10-01 12:42:17 +02:00
if ( atomic_read ( & port - > status ) & ZFCP_STATUS_COMMON_NOESC )
goto close_init_done ;
2008-07-02 10:56:40 +02:00
switch ( erp_action - > step ) {
case ZFCP_ERP_STEP_UNINITIALIZED :
zfcp_erp_port_strategy_clearstati ( port ) ;
if ( atomic_read ( & port - > status ) & ZFCP_STATUS_COMMON_OPEN )
return zfcp_erp_port_strategy_close ( erp_action ) ;
2005-04-16 15:20:36 -07:00
break ;
2008-07-02 10:56:40 +02:00
case ZFCP_ERP_STEP_PORT_CLOSING :
if ( atomic_read ( & port - > status ) & ZFCP_STATUS_COMMON_OPEN )
return ZFCP_ERP_FAILED ;
2005-04-16 15:20:36 -07:00
break ;
}
2008-10-01 12:42:17 +02:00
close_init_done :
2008-07-02 10:56:40 +02:00
if ( erp_action - > status & ZFCP_STATUS_ERP_CLOSE_ONLY )
return ZFCP_ERP_EXIT ;
2005-04-16 15:20:36 -07:00
2008-10-01 12:42:17 +02:00
return zfcp_erp_port_strategy_open_common ( erp_action ) ;
2008-07-02 10:56:40 +02:00
}
static void zfcp_erp_unit_strategy_clearstati ( struct zfcp_unit * unit )
{
2008-10-01 12:42:16 +02:00
atomic_clear_mask ( ZFCP_STATUS_COMMON_ACCESS_DENIED |
2008-07-02 10:56:40 +02:00
ZFCP_STATUS_UNIT_SHARED |
ZFCP_STATUS_UNIT_READONLY ,
& unit - > status ) ;
}
static int zfcp_erp_unit_strategy_close ( struct zfcp_erp_action * erp_action )
{
int retval = zfcp_fsf_close_unit ( erp_action ) ;
if ( retval = = - ENOMEM )
return ZFCP_ERP_NOMEM ;
erp_action - > step = ZFCP_ERP_STEP_UNIT_CLOSING ;
if ( retval )
return ZFCP_ERP_FAILED ;
return ZFCP_ERP_CONTINUES ;
}
static int zfcp_erp_unit_strategy_open ( struct zfcp_erp_action * erp_action )
{
int retval = zfcp_fsf_open_unit ( erp_action ) ;
if ( retval = = - ENOMEM )
return ZFCP_ERP_NOMEM ;
erp_action - > step = ZFCP_ERP_STEP_UNIT_OPENING ;
if ( retval )
return ZFCP_ERP_FAILED ;
return ZFCP_ERP_CONTINUES ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
static int zfcp_erp_unit_strategy ( struct zfcp_erp_action * erp_action )
2005-04-16 15:20:36 -07:00
{
2008-07-02 10:56:40 +02:00
struct zfcp_unit * unit = erp_action - > unit ;
switch ( erp_action - > step ) {
case ZFCP_ERP_STEP_UNINITIALIZED :
zfcp_erp_unit_strategy_clearstati ( unit ) ;
if ( atomic_read ( & unit - > status ) & ZFCP_STATUS_COMMON_OPEN )
return zfcp_erp_unit_strategy_close ( erp_action ) ;
/* already closed, fall through */
case ZFCP_ERP_STEP_UNIT_CLOSING :
if ( atomic_read ( & unit - > status ) & ZFCP_STATUS_COMMON_OPEN )
return ZFCP_ERP_FAILED ;
if ( erp_action - > status & ZFCP_STATUS_ERP_CLOSE_ONLY )
return ZFCP_ERP_EXIT ;
return zfcp_erp_unit_strategy_open ( erp_action ) ;
case ZFCP_ERP_STEP_UNIT_OPENING :
if ( atomic_read ( & unit - > status ) & ZFCP_STATUS_COMMON_OPEN )
return ZFCP_ERP_SUCCEEDED ;
}
return ZFCP_ERP_FAILED ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
static int zfcp_erp_strategy_check_unit ( struct zfcp_unit * unit , int result )
2005-04-16 15:20:36 -07:00
{
switch ( result ) {
case ZFCP_ERP_SUCCEEDED :
atomic_set ( & unit - > erp_counter , 0 ) ;
zfcp_erp_unit_unblock ( unit ) ;
break ;
case ZFCP_ERP_FAILED :
atomic_inc ( & unit - > erp_counter ) ;
2008-10-01 12:42:15 +02:00
if ( atomic_read ( & unit - > erp_counter ) > ZFCP_MAX_ERPS ) {
dev_err ( & unit - > port - > adapter - > ccw_device - > dev ,
" ERP failed for unit 0x%016Lx on "
" port 0x%016Lx \n " ,
2008-10-01 12:42:18 +02:00
( unsigned long long ) unit - > fcp_lun ,
( unsigned long long ) unit - > port - > wwpn ) ;
2008-04-18 12:51:55 +02:00
zfcp_erp_unit_failed ( unit , 21 , NULL ) ;
2008-10-01 12:42:15 +02:00
}
2005-04-16 15:20:36 -07:00
break ;
}
2008-07-02 10:56:40 +02:00
if ( atomic_read ( & unit - > status ) & ZFCP_STATUS_COMMON_ERP_FAILED ) {
zfcp_erp_unit_block ( unit , 0 ) ;
2005-04-16 15:20:36 -07:00
result = ZFCP_ERP_EXIT ;
}
return result ;
}
2008-07-02 10:56:40 +02:00
static int zfcp_erp_strategy_check_port ( struct zfcp_port * port , int result )
2005-04-16 15:20:36 -07:00
{
switch ( result ) {
case ZFCP_ERP_SUCCEEDED :
atomic_set ( & port - > erp_counter , 0 ) ;
zfcp_erp_port_unblock ( port ) ;
break ;
2008-07-02 10:56:40 +02:00
2005-04-16 15:20:36 -07:00
case ZFCP_ERP_FAILED :
2008-07-02 10:56:40 +02:00
if ( atomic_read ( & port - > status ) & ZFCP_STATUS_COMMON_NOESC ) {
2008-06-10 18:21:00 +02:00
zfcp_erp_port_block ( port , 0 ) ;
result = ZFCP_ERP_EXIT ;
}
2005-04-16 15:20:36 -07:00
atomic_inc ( & port - > erp_counter ) ;
2008-10-01 12:42:15 +02:00
if ( atomic_read ( & port - > erp_counter ) > ZFCP_MAX_ERPS ) {
dev_err ( & port - > adapter - > ccw_device - > dev ,
" ERP failed for remote port 0x%016Lx \n " ,
2008-10-01 12:42:18 +02:00
( unsigned long long ) port - > wwpn ) ;
2008-04-18 12:51:55 +02:00
zfcp_erp_port_failed ( port , 22 , NULL ) ;
2008-10-01 12:42:15 +02:00
}
2005-04-16 15:20:36 -07:00
break ;
}
2008-07-02 10:56:40 +02:00
if ( atomic_read ( & port - > status ) & ZFCP_STATUS_COMMON_ERP_FAILED ) {
zfcp_erp_port_block ( port , 0 ) ;
2005-04-16 15:20:36 -07:00
result = ZFCP_ERP_EXIT ;
}
return result ;
}
2008-07-02 10:56:40 +02:00
static int zfcp_erp_strategy_check_adapter ( struct zfcp_adapter * adapter ,
int result )
2005-04-16 15:20:36 -07:00
{
switch ( result ) {
case ZFCP_ERP_SUCCEEDED :
atomic_set ( & adapter - > erp_counter , 0 ) ;
zfcp_erp_adapter_unblock ( adapter ) ;
break ;
2008-07-02 10:56:40 +02:00
2005-04-16 15:20:36 -07:00
case ZFCP_ERP_FAILED :
atomic_inc ( & adapter - > erp_counter ) ;
2008-10-01 12:42:15 +02:00
if ( atomic_read ( & adapter - > erp_counter ) > ZFCP_MAX_ERPS ) {
dev_err ( & adapter - > ccw_device - > dev ,
" ERP cannot recover an error "
" on the FCP device \n " ) ;
2008-04-18 12:51:55 +02:00
zfcp_erp_adapter_failed ( adapter , 23 , NULL ) ;
2008-10-01 12:42:15 +02:00
}
2005-04-16 15:20:36 -07:00
break ;
}
2008-07-02 10:56:40 +02:00
if ( atomic_read ( & adapter - > status ) & ZFCP_STATUS_COMMON_ERP_FAILED ) {
zfcp_erp_adapter_block ( adapter , 0 ) ;
2005-04-16 15:20:36 -07:00
result = ZFCP_ERP_EXIT ;
}
return result ;
}
2008-07-02 10:56:40 +02:00
static int zfcp_erp_strategy_check_target ( struct zfcp_erp_action * erp_action ,
int result )
2007-05-08 11:16:52 +02:00
{
2008-07-02 10:56:40 +02:00
struct zfcp_adapter * adapter = erp_action - > adapter ;
struct zfcp_port * port = erp_action - > port ;
struct zfcp_unit * unit = erp_action - > unit ;
switch ( erp_action - > action ) {
case ZFCP_ERP_ACTION_REOPEN_UNIT :
result = zfcp_erp_strategy_check_unit ( unit , result ) ;
break ;
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED :
case ZFCP_ERP_ACTION_REOPEN_PORT :
result = zfcp_erp_strategy_check_port ( port , result ) ;
break ;
case ZFCP_ERP_ACTION_REOPEN_ADAPTER :
result = zfcp_erp_strategy_check_adapter ( adapter , result ) ;
break ;
}
return result ;
2007-05-08 11:16:52 +02:00
}
2008-07-02 10:56:40 +02:00
static int zfcp_erp_strat_change_det ( atomic_t * target_status , u32 erp_status )
2007-05-08 11:16:52 +02:00
{
2008-07-02 10:56:40 +02:00
int status = atomic_read ( target_status ) ;
2007-05-08 11:16:52 +02:00
2008-07-02 10:56:40 +02:00
if ( ( status & ZFCP_STATUS_COMMON_RUNNING ) & &
( erp_status & ZFCP_STATUS_ERP_CLOSE_ONLY ) )
return 1 ; /* take it online */
2007-05-08 11:16:52 +02:00
2008-07-02 10:56:40 +02:00
if ( ! ( status & ZFCP_STATUS_COMMON_RUNNING ) & &
! ( erp_status & ZFCP_STATUS_ERP_CLOSE_ONLY ) )
return 1 ; /* take it offline */
return 0 ;
2007-05-08 11:16:52 +02:00
}
2008-07-02 10:56:40 +02:00
static int zfcp_erp_strategy_statechange ( struct zfcp_erp_action * act , int ret )
2005-04-16 15:20:36 -07:00
{
2008-07-02 10:56:40 +02:00
int action = act - > action ;
struct zfcp_adapter * adapter = act - > adapter ;
struct zfcp_port * port = act - > port ;
struct zfcp_unit * unit = act - > unit ;
u32 erp_status = act - > status ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
switch ( action ) {
2005-04-16 15:20:36 -07:00
case ZFCP_ERP_ACTION_REOPEN_ADAPTER :
2008-07-02 10:56:40 +02:00
if ( zfcp_erp_strat_change_det ( & adapter - > status , erp_status ) ) {
_zfcp_erp_adapter_reopen ( adapter ,
ZFCP_STATUS_COMMON_ERP_FAILED ,
67 , NULL ) ;
return ZFCP_ERP_EXIT ;
}
2005-04-16 15:20:36 -07:00
break ;
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED :
case ZFCP_ERP_ACTION_REOPEN_PORT :
2008-07-02 10:56:40 +02:00
if ( zfcp_erp_strat_change_det ( & port - > status , erp_status ) ) {
_zfcp_erp_port_reopen ( port ,
ZFCP_STATUS_COMMON_ERP_FAILED ,
68 , NULL ) ;
return ZFCP_ERP_EXIT ;
}
2005-04-16 15:20:36 -07:00
break ;
case ZFCP_ERP_ACTION_REOPEN_UNIT :
2008-07-02 10:56:40 +02:00
if ( zfcp_erp_strat_change_det ( & unit - > status , erp_status ) ) {
_zfcp_erp_unit_reopen ( unit ,
ZFCP_STATUS_COMMON_ERP_FAILED ,
69 , NULL ) ;
return ZFCP_ERP_EXIT ;
}
2005-04-16 15:20:36 -07:00
break ;
}
2008-07-02 10:56:40 +02:00
return ret ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
static void zfcp_erp_action_dequeue ( struct zfcp_erp_action * erp_action )
2005-04-16 15:20:36 -07:00
{
2008-07-02 10:56:40 +02:00
struct zfcp_adapter * adapter = erp_action - > adapter ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
adapter - > erp_total_count - - ;
if ( erp_action - > status & ZFCP_STATUS_ERP_LOWMEM ) {
adapter - > erp_low_mem_count - - ;
erp_action - > status & = ~ ZFCP_STATUS_ERP_LOWMEM ;
2008-03-27 14:22:05 +01:00
}
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
list_del ( & erp_action - > list ) ;
zfcp_rec_dbf_event_action ( 144 , erp_action ) ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
switch ( erp_action - > action ) {
case ZFCP_ERP_ACTION_REOPEN_UNIT :
atomic_clear_mask ( ZFCP_STATUS_COMMON_ERP_INUSE ,
& erp_action - > unit - > status ) ;
break ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED :
case ZFCP_ERP_ACTION_REOPEN_PORT :
atomic_clear_mask ( ZFCP_STATUS_COMMON_ERP_INUSE ,
& erp_action - > port - > status ) ;
break ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
case ZFCP_ERP_ACTION_REOPEN_ADAPTER :
atomic_clear_mask ( ZFCP_STATUS_COMMON_ERP_INUSE ,
& erp_action - > adapter - > status ) ;
break ;
}
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
struct zfcp_erp_add_work {
struct zfcp_unit * unit ;
struct work_struct work ;
} ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
static void zfcp_erp_scsi_scan ( struct work_struct * work )
{
struct zfcp_erp_add_work * p =
container_of ( work , struct zfcp_erp_add_work , work ) ;
struct zfcp_unit * unit = p - > unit ;
struct fc_rport * rport = unit - > port - > rport ;
scsi_scan_target ( & rport - > dev , 0 , rport - > scsi_target_id ,
2008-10-01 12:42:20 +02:00
scsilun_to_int ( ( struct scsi_lun * ) & unit - > fcp_lun ) , 0 ) ;
2008-07-02 10:56:40 +02:00
atomic_clear_mask ( ZFCP_STATUS_UNIT_SCSI_WORK_PENDING , & unit - > status ) ;
zfcp_unit_put ( unit ) ;
kfree ( p ) ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
static void zfcp_erp_schedule_work ( struct zfcp_unit * unit )
2005-04-16 15:20:36 -07:00
{
2008-07-02 10:56:40 +02:00
struct zfcp_erp_add_work * p ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
p = kzalloc ( sizeof ( * p ) , GFP_KERNEL ) ;
if ( ! p ) {
dev_err ( & unit - > port - > adapter - > ccw_device - > dev ,
2008-10-01 12:42:15 +02:00
" Registering unit 0x%016Lx on port 0x%016Lx failed \n " ,
2008-10-01 12:42:18 +02:00
( unsigned long long ) unit - > fcp_lun ,
( unsigned long long ) unit - > port - > wwpn ) ;
2008-07-02 10:56:40 +02:00
return ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
zfcp_unit_get ( unit ) ;
atomic_set_mask ( ZFCP_STATUS_UNIT_SCSI_WORK_PENDING , & unit - > status ) ;
INIT_WORK ( & p - > work , zfcp_erp_scsi_scan ) ;
p - > unit = unit ;
2008-10-01 12:42:22 +02:00
queue_work ( zfcp_data . work_queue , & p - > work ) ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
static void zfcp_erp_rport_register ( struct zfcp_port * port )
2005-04-16 15:20:36 -07:00
{
2008-07-02 10:56:40 +02:00
struct fc_rport_identifiers ids ;
ids . node_name = port - > wwnn ;
ids . port_name = port - > wwpn ;
ids . port_id = port - > d_id ;
ids . roles = FC_RPORT_ROLE_FCP_TARGET ;
port - > rport = fc_remote_port_add ( port - > adapter - > scsi_host , 0 , & ids ) ;
if ( ! port - > rport ) {
dev_err ( & port - > adapter - > ccw_device - > dev ,
2008-10-01 12:42:15 +02:00
" Registering port 0x%016Lx failed \n " ,
2008-10-01 12:42:18 +02:00
( unsigned long long ) port - > wwpn ) ;
2008-07-02 10:56:40 +02:00
return ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
scsi_target_unblock ( & port - > rport - > dev ) ;
port - > rport - > maxframe_size = port - > maxframe_size ;
port - > rport - > supported_classes = port - > supported_classes ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
static void zfcp_erp_rports_del ( struct zfcp_adapter * adapter )
2005-04-16 15:20:36 -07:00
{
struct zfcp_port * port ;
2008-10-01 12:42:17 +02:00
list_for_each_entry ( port , & adapter - > port_list_head , list ) {
2008-10-01 12:42:23 +02:00
if ( ! port - > rport )
continue ;
2008-10-01 12:42:17 +02:00
fc_remote_port_delete ( port - > rport ) ;
port - > rport = NULL ;
}
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
static void zfcp_erp_action_cleanup ( struct zfcp_erp_action * act , int result )
2005-04-16 15:20:36 -07:00
{
2008-07-02 10:56:40 +02:00
struct zfcp_adapter * adapter = act - > adapter ;
struct zfcp_port * port = act - > port ;
struct zfcp_unit * unit = act - > unit ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
switch ( act - > action ) {
case ZFCP_ERP_ACTION_REOPEN_UNIT :
if ( ( result = = ZFCP_ERP_SUCCEEDED ) & &
! unit - > device & & port - > rport ) {
atomic_set_mask ( ZFCP_STATUS_UNIT_REGISTERED ,
& unit - > status ) ;
if ( ! ( atomic_read ( & unit - > status ) &
ZFCP_STATUS_UNIT_SCSI_WORK_PENDING ) )
zfcp_erp_schedule_work ( unit ) ;
}
zfcp_unit_put ( unit ) ;
break ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED :
case ZFCP_ERP_ACTION_REOPEN_PORT :
if ( atomic_read ( & port - > status ) & ZFCP_STATUS_PORT_NO_WWPN ) {
zfcp_port_put ( port ) ;
return ;
}
if ( ( result = = ZFCP_ERP_SUCCEEDED ) & & ! port - > rport )
zfcp_erp_rport_register ( port ) ;
if ( ( result ! = ZFCP_ERP_SUCCEEDED ) & & port - > rport ) {
fc_remote_port_delete ( port - > rport ) ;
port - > rport = NULL ;
}
zfcp_port_put ( port ) ;
break ;
case ZFCP_ERP_ACTION_REOPEN_ADAPTER :
if ( result ! = ZFCP_ERP_SUCCEEDED )
zfcp_erp_rports_del ( adapter ) ;
zfcp_adapter_put ( adapter ) ;
break ;
}
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
static int zfcp_erp_strategy_do_action ( struct zfcp_erp_action * erp_action )
2005-04-16 15:20:36 -07:00
{
2008-07-02 10:56:40 +02:00
switch ( erp_action - > action ) {
case ZFCP_ERP_ACTION_REOPEN_ADAPTER :
return zfcp_erp_adapter_strategy ( erp_action ) ;
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED :
return zfcp_erp_port_forced_strategy ( erp_action ) ;
case ZFCP_ERP_ACTION_REOPEN_PORT :
return zfcp_erp_port_strategy ( erp_action ) ;
case ZFCP_ERP_ACTION_REOPEN_UNIT :
return zfcp_erp_unit_strategy ( erp_action ) ;
}
return ZFCP_ERP_FAILED ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
static int zfcp_erp_strategy ( struct zfcp_erp_action * erp_action )
2005-04-16 15:20:36 -07:00
{
int retval ;
2008-07-02 10:56:40 +02:00
struct zfcp_adapter * adapter = erp_action - > adapter ;
unsigned long flags ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
read_lock_irqsave ( & zfcp_data . config_lock , flags ) ;
write_lock ( & adapter - > erp_lock ) ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
zfcp_erp_strategy_check_fsfreq ( erp_action ) ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
if ( erp_action - > status & ZFCP_STATUS_ERP_DISMISSED ) {
zfcp_erp_action_dequeue ( erp_action ) ;
retval = ZFCP_ERP_DISMISSED ;
goto unlock ;
2005-06-13 13:15:15 +02:00
}
2005-04-16 15:20:36 -07:00
2006-02-11 01:41:50 +01:00
zfcp_erp_action_to_running ( erp_action ) ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
/* no lock to allow for blocking operations */
write_unlock ( & adapter - > erp_lock ) ;
read_unlock_irqrestore ( & zfcp_data . config_lock , flags ) ;
retval = zfcp_erp_strategy_do_action ( erp_action ) ;
read_lock_irqsave ( & zfcp_data . config_lock , flags ) ;
write_lock ( & adapter - > erp_lock ) ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
if ( erp_action - > status & ZFCP_STATUS_ERP_DISMISSED )
retval = ZFCP_ERP_CONTINUES ;
2008-06-10 18:21:00 +02:00
2008-07-02 10:56:40 +02:00
switch ( retval ) {
case ZFCP_ERP_NOMEM :
if ( ! ( erp_action - > status & ZFCP_STATUS_ERP_LOWMEM ) ) {
+ + adapter - > erp_low_mem_count ;
erp_action - > status | = ZFCP_STATUS_ERP_LOWMEM ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
if ( adapter - > erp_total_count = = adapter - > erp_low_mem_count )
_zfcp_erp_adapter_reopen ( adapter , 0 , 66 , NULL ) ;
else {
zfcp_erp_strategy_memwait ( erp_action ) ;
retval = ZFCP_ERP_CONTINUES ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
goto unlock ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
case ZFCP_ERP_CONTINUES :
if ( erp_action - > status & ZFCP_STATUS_ERP_LOWMEM ) {
- - adapter - > erp_low_mem_count ;
erp_action - > status & = ~ ZFCP_STATUS_ERP_LOWMEM ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
goto unlock ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
retval = zfcp_erp_strategy_check_target ( erp_action , retval ) ;
zfcp_erp_action_dequeue ( erp_action ) ;
retval = zfcp_erp_strategy_statechange ( erp_action , retval ) ;
if ( retval = = ZFCP_ERP_EXIT )
goto unlock ;
zfcp_erp_strategy_followup_actions ( erp_action ) ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
unlock :
write_unlock ( & adapter - > erp_lock ) ;
read_unlock_irqrestore ( & zfcp_data . config_lock , flags ) ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
if ( retval ! = ZFCP_ERP_CONTINUES )
zfcp_erp_action_cleanup ( erp_action , retval ) ;
2005-04-16 15:20:36 -07:00
return retval ;
}
2008-07-02 10:56:40 +02:00
static int zfcp_erp_thread ( void * data )
2005-04-16 15:20:36 -07:00
{
2008-07-02 10:56:40 +02:00
struct zfcp_adapter * adapter = ( struct zfcp_adapter * ) data ;
struct list_head * next ;
struct zfcp_erp_action * act ;
unsigned long flags ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
daemonize ( " zfcperp%s " , adapter - > ccw_device - > dev . bus_id ) ;
/* Block all signals */
siginitsetinv ( & current - > blocked , 0 ) ;
atomic_set_mask ( ZFCP_STATUS_ADAPTER_ERP_THREAD_UP , & adapter - > status ) ;
wake_up ( & adapter - > erp_thread_wqh ) ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
while ( ! ( atomic_read ( & adapter - > status ) &
ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL ) ) {
write_lock_irqsave ( & adapter - > erp_lock , flags ) ;
next = adapter - > erp_ready_head . next ;
write_unlock_irqrestore ( & adapter - > erp_lock , flags ) ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
if ( next ! = & adapter - > erp_ready_head ) {
act = list_entry ( next , struct zfcp_erp_action , list ) ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
/* there is more to come after dismission, no notify */
if ( zfcp_erp_strategy ( act ) ! = ZFCP_ERP_DISMISSED )
zfcp_erp_wakeup ( adapter ) ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
zfcp_rec_dbf_event_thread ( 4 , adapter ) ;
down_interruptible ( & adapter - > erp_ready_sem ) ;
zfcp_rec_dbf_event_thread ( 5 , adapter ) ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
atomic_clear_mask ( ZFCP_STATUS_ADAPTER_ERP_THREAD_UP , & adapter - > status ) ;
wake_up ( & adapter - > erp_thread_wqh ) ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
return 0 ;
}
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
/**
* zfcp_erp_thread_setup - Start ERP thread for adapter
* @ adapter : Adapter to start the ERP thread for
*
* Returns 0 on success or error code from kernel_thread ( )
*/
int zfcp_erp_thread_setup ( struct zfcp_adapter * adapter )
{
int retval ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
atomic_clear_mask ( ZFCP_STATUS_ADAPTER_ERP_THREAD_UP , & adapter - > status ) ;
retval = kernel_thread ( zfcp_erp_thread , adapter , SIGCHLD ) ;
if ( retval < 0 ) {
dev_err ( & adapter - > ccw_device - > dev ,
2008-10-01 12:42:15 +02:00
" Creating an ERP thread for the FCP device failed. \n " ) ;
2008-07-02 10:56:40 +02:00
return retval ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
wait_event ( adapter - > erp_thread_wqh ,
atomic_read ( & adapter - > status ) &
ZFCP_STATUS_ADAPTER_ERP_THREAD_UP ) ;
return 0 ;
}
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
/**
* zfcp_erp_thread_kill - Stop ERP thread .
* @ adapter : Adapter where the ERP thread should be stopped .
*
* The caller of this routine ensures that the specified adapter has
* been shut down and that this operation has been completed . Thus ,
* there are no pending erp_actions which would need to be handled
* here .
*/
void zfcp_erp_thread_kill ( struct zfcp_adapter * adapter )
{
atomic_set_mask ( ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL , & adapter - > status ) ;
up ( & adapter - > erp_ready_sem ) ;
zfcp_rec_dbf_event_thread_lock ( 2 , adapter ) ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
wait_event ( adapter - > erp_thread_wqh ,
! ( atomic_read ( & adapter - > status ) &
ZFCP_STATUS_ADAPTER_ERP_THREAD_UP ) ) ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
atomic_clear_mask ( ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL ,
& adapter - > status ) ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
/**
* zfcp_erp_adapter_failed - Set adapter status to failed .
* @ adapter : Failed adapter .
* @ id : Event id for debug trace .
* @ ref : Reference for debug trace .
*/
void zfcp_erp_adapter_failed ( struct zfcp_adapter * adapter , u8 id , void * ref )
2005-04-16 15:20:36 -07:00
{
2008-07-02 10:56:40 +02:00
zfcp_erp_modify_adapter_status ( adapter , id , ref ,
ZFCP_STATUS_COMMON_ERP_FAILED , ZFCP_SET ) ;
}
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
/**
* zfcp_erp_port_failed - Set port status to failed .
* @ port : Failed port .
* @ id : Event id for debug trace .
* @ ref : Reference for debug trace .
*/
void zfcp_erp_port_failed ( struct zfcp_port * port , u8 id , void * ref )
{
zfcp_erp_modify_port_status ( port , id , ref ,
ZFCP_STATUS_COMMON_ERP_FAILED , ZFCP_SET ) ;
2005-04-16 15:20:36 -07:00
}
/**
2008-07-02 10:56:40 +02:00
* zfcp_erp_unit_failed - Set unit status to failed .
* @ unit : Failed unit .
* @ id : Event id for debug trace .
* @ ref : Reference for debug trace .
2005-04-16 15:20:36 -07:00
*/
2008-07-02 10:56:40 +02:00
void zfcp_erp_unit_failed ( struct zfcp_unit * unit , u8 id , void * ref )
2005-04-16 15:20:36 -07:00
{
2008-07-02 10:56:40 +02:00
zfcp_erp_modify_unit_status ( unit , id , ref ,
ZFCP_STATUS_COMMON_ERP_FAILED , ZFCP_SET ) ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
/**
* zfcp_erp_wait - wait for completion of error recovery on an adapter
* @ adapter : adapter for which to wait for completion of its error recovery
*/
void zfcp_erp_wait ( struct zfcp_adapter * adapter )
{
wait_event ( adapter - > erp_done_wqh ,
! ( atomic_read ( & adapter - > status ) &
ZFCP_STATUS_ADAPTER_ERP_PENDING ) ) ;
}
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
/**
* zfcp_erp_modify_adapter_status - change adapter status bits
* @ adapter : adapter to change the status
* @ id : id for the debug trace
* @ ref : reference for the debug trace
* @ mask : status bits to change
* @ set_or_clear : ZFCP_SET or ZFCP_CLEAR
*
* Changes in common status bits are propagated to attached ports and units .
*/
void zfcp_erp_modify_adapter_status ( struct zfcp_adapter * adapter , u8 id ,
void * ref , u32 mask , int set_or_clear )
2005-04-16 15:20:36 -07:00
{
struct zfcp_port * port ;
2008-07-02 10:56:40 +02:00
u32 common_mask = mask & ZFCP_COMMON_FLAGS ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
if ( set_or_clear = = ZFCP_SET ) {
if ( status_change_set ( mask , & adapter - > status ) )
zfcp_rec_dbf_event_adapter ( id , ref , adapter ) ;
atomic_set_mask ( mask , & adapter - > status ) ;
} else {
if ( status_change_clear ( mask , & adapter - > status ) )
zfcp_rec_dbf_event_adapter ( id , ref , adapter ) ;
atomic_clear_mask ( mask , & adapter - > status ) ;
if ( mask & ZFCP_STATUS_COMMON_ERP_FAILED )
atomic_set ( & adapter - > erp_counter , 0 ) ;
}
if ( common_mask )
2005-04-16 15:20:36 -07:00
list_for_each_entry ( port , & adapter - > port_list_head , list )
2008-07-02 10:56:40 +02:00
zfcp_erp_modify_port_status ( port , id , ref , common_mask ,
set_or_clear ) ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
/**
* zfcp_erp_modify_port_status - change port status bits
* @ port : port to change the status bits
* @ id : id for the debug trace
* @ ref : reference for the debug trace
* @ mask : status bits to change
* @ set_or_clear : ZFCP_SET or ZFCP_CLEAR
*
* Changes in common status bits are propagated to attached units .
*/
void zfcp_erp_modify_port_status ( struct zfcp_port * port , u8 id , void * ref ,
u32 mask , int set_or_clear )
2005-04-16 15:20:36 -07:00
{
struct zfcp_unit * unit ;
2008-07-02 10:56:40 +02:00
u32 common_mask = mask & ZFCP_COMMON_FLAGS ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
if ( set_or_clear = = ZFCP_SET ) {
if ( status_change_set ( mask , & port - > status ) )
zfcp_rec_dbf_event_port ( id , ref , port ) ;
atomic_set_mask ( mask , & port - > status ) ;
} else {
if ( status_change_clear ( mask , & port - > status ) )
zfcp_rec_dbf_event_port ( id , ref , port ) ;
atomic_clear_mask ( mask , & port - > status ) ;
if ( mask & ZFCP_STATUS_COMMON_ERP_FAILED )
atomic_set ( & port - > erp_counter , 0 ) ;
}
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
if ( common_mask )
list_for_each_entry ( unit , & port - > unit_list_head , list )
zfcp_erp_modify_unit_status ( unit , id , ref , common_mask ,
set_or_clear ) ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
/**
* zfcp_erp_modify_unit_status - change unit status bits
* @ unit : unit to change the status bits
* @ id : id for the debug trace
* @ ref : reference for the debug trace
* @ mask : status bits to change
* @ set_or_clear : ZFCP_SET or ZFCP_CLEAR
*/
void zfcp_erp_modify_unit_status ( struct zfcp_unit * unit , u8 id , void * ref ,
u32 mask , int set_or_clear )
2005-04-16 15:20:36 -07:00
{
2008-07-02 10:56:40 +02:00
if ( set_or_clear = = ZFCP_SET ) {
if ( status_change_set ( mask , & unit - > status ) )
zfcp_rec_dbf_event_unit ( id , ref , unit ) ;
atomic_set_mask ( mask , & unit - > status ) ;
} else {
if ( status_change_clear ( mask , & unit - > status ) )
zfcp_rec_dbf_event_unit ( id , ref , unit ) ;
atomic_clear_mask ( mask , & unit - > status ) ;
if ( mask & ZFCP_STATUS_COMMON_ERP_FAILED ) {
atomic_set ( & unit - > erp_counter , 0 ) ;
}
}
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
/**
* zfcp_erp_port_boxed - Mark port as " boxed " and start ERP
* @ port : The " boxed " port .
* @ id : The debug trace id .
* @ id : Reference for the debug trace .
*/
2008-04-18 12:51:55 +02:00
void zfcp_erp_port_boxed ( struct zfcp_port * port , u8 id , void * ref )
2005-06-13 13:23:57 +02:00
{
unsigned long flags ;
read_lock_irqsave ( & zfcp_data . config_lock , flags ) ;
2008-03-27 14:22:02 +01:00
zfcp_erp_modify_port_status ( port , id , ref ,
ZFCP_STATUS_COMMON_ACCESS_BOXED , ZFCP_SET ) ;
2005-06-13 13:23:57 +02:00
read_unlock_irqrestore ( & zfcp_data . config_lock , flags ) ;
2008-03-27 14:22:03 +01:00
zfcp_erp_port_reopen ( port , ZFCP_STATUS_COMMON_ERP_FAILED , id , ref ) ;
2005-06-13 13:23:57 +02:00
}
2008-07-02 10:56:40 +02:00
/**
* zfcp_erp_unit_boxed - Mark unit as " boxed " and start ERP
* @ port : The " boxed " unit .
* @ id : The debug trace id .
* @ id : Reference for the debug trace .
*/
2008-04-18 12:51:55 +02:00
void zfcp_erp_unit_boxed ( struct zfcp_unit * unit , u8 id , void * ref )
2005-06-13 13:23:57 +02:00
{
2008-03-27 14:22:02 +01:00
zfcp_erp_modify_unit_status ( unit , id , ref ,
ZFCP_STATUS_COMMON_ACCESS_BOXED , ZFCP_SET ) ;
2008-03-27 14:22:03 +01:00
zfcp_erp_unit_reopen ( unit , ZFCP_STATUS_COMMON_ERP_FAILED , id , ref ) ;
2005-06-13 13:23:57 +02:00
}
2008-07-02 10:56:40 +02:00
/**
* zfcp_erp_port_access_denied - Adapter denied access to port .
* @ port : port where access has been denied
* @ id : id for debug trace
* @ ref : reference for debug trace
*
* Since the adapter has denied access , stop using the port and the
* attached units .
*/
2008-04-18 12:51:55 +02:00
void zfcp_erp_port_access_denied ( struct zfcp_port * port , u8 id , void * ref )
2005-04-16 15:20:36 -07:00
{
unsigned long flags ;
read_lock_irqsave ( & zfcp_data . config_lock , flags ) ;
2008-03-27 14:22:02 +01:00
zfcp_erp_modify_port_status ( port , id , ref ,
ZFCP_STATUS_COMMON_ERP_FAILED |
ZFCP_STATUS_COMMON_ACCESS_DENIED , ZFCP_SET ) ;
2005-04-16 15:20:36 -07:00
read_unlock_irqrestore ( & zfcp_data . config_lock , flags ) ;
}
2008-07-02 10:56:40 +02:00
/**
* zfcp_erp_unit_access_denied - Adapter denied access to unit .
* @ unit : unit where access has been denied
* @ id : id for debug trace
* @ ref : reference for debug trace
*
* Since the adapter has denied access , stop using the unit .
*/
2008-04-18 12:51:55 +02:00
void zfcp_erp_unit_access_denied ( struct zfcp_unit * unit , u8 id , void * ref )
2005-04-16 15:20:36 -07:00
{
2008-03-27 14:22:02 +01:00
zfcp_erp_modify_unit_status ( unit , id , ref ,
ZFCP_STATUS_COMMON_ERP_FAILED |
ZFCP_STATUS_COMMON_ACCESS_DENIED , ZFCP_SET ) ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
static void zfcp_erp_unit_access_changed ( struct zfcp_unit * unit , u8 id ,
void * ref )
2005-04-16 15:20:36 -07:00
{
2008-07-02 10:56:40 +02:00
int status = atomic_read ( & unit - > status ) ;
if ( ! ( status & ( ZFCP_STATUS_COMMON_ACCESS_DENIED |
ZFCP_STATUS_COMMON_ACCESS_BOXED ) ) )
2005-09-13 21:51:16 +02:00
return ;
2008-07-02 10:56:40 +02:00
zfcp_erp_unit_reopen ( unit , ZFCP_STATUS_COMMON_ERP_FAILED , id , ref ) ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
static void zfcp_erp_port_access_changed ( struct zfcp_port * port , u8 id ,
void * ref )
2005-04-16 15:20:36 -07:00
{
struct zfcp_unit * unit ;
2008-07-02 10:56:40 +02:00
int status = atomic_read ( & port - > status ) ;
2005-04-16 15:20:36 -07:00
2008-07-02 10:56:40 +02:00
if ( ! ( status & ( ZFCP_STATUS_COMMON_ACCESS_DENIED |
ZFCP_STATUS_COMMON_ACCESS_BOXED ) ) ) {
2008-10-01 12:42:17 +02:00
list_for_each_entry ( unit , & port - > unit_list_head , list )
zfcp_erp_unit_access_changed ( unit , id , ref ) ;
2005-04-16 15:20:36 -07:00
return ;
}
2008-06-10 18:20:58 +02:00
zfcp_erp_port_reopen ( port , ZFCP_STATUS_COMMON_ERP_FAILED , id , ref ) ;
2005-04-16 15:20:36 -07:00
}
2008-07-02 10:56:40 +02:00
/**
* zfcp_erp_adapter_access_changed - Process change in adapter ACT
* @ adapter : Adapter where the Access Control Table ( ACT ) changed
* @ id : Id for debug trace
* @ ref : Reference for debug trace
*/
void zfcp_erp_adapter_access_changed ( struct zfcp_adapter * adapter , u8 id ,
void * ref )
2005-04-16 15:20:36 -07:00
{
2008-07-02 10:56:40 +02:00
struct zfcp_port * port ;
unsigned long flags ;
if ( adapter - > connection_features & FSF_FEATURE_NPIV_MODE )
2005-04-16 15:20:36 -07:00
return ;
2008-07-02 10:56:40 +02:00
read_lock_irqsave ( & zfcp_data . config_lock , flags ) ;
list_for_each_entry ( port , & adapter - > port_list_head , list )
2008-10-01 12:42:17 +02:00
zfcp_erp_port_access_changed ( port , id , ref ) ;
2008-07-02 10:56:40 +02:00
read_unlock_irqrestore ( & zfcp_data . config_lock , flags ) ;
2005-04-16 15:20:36 -07:00
}