2007-09-07 09:15:31 +02:00
/*
2006-05-22 18:14:08 +02:00
* This file is part of the zfcp device driver for
* FCP adapters for IBM System z9 and zSeries .
2005-04-16 15:20:36 -07:00
*
2006-05-22 18:14:08 +02:00
* ( C ) Copyright IBM Corp . 2002 , 2006
2007-09-07 09:15:31 +02:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 , or ( at your option )
* any later version .
*
* 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 . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
2005-04-16 15:20:36 -07:00
*/
# define ZFCP_LOG_AREA ZFCP_LOG_AREA_ERP
# include "zfcp_ext.h"
2005-06-13 13:18:56 +02:00
static int zfcp_erp_adisc ( struct zfcp_port * ) ;
2005-04-16 15:20:36 -07:00
static void zfcp_erp_adisc_handler ( unsigned long ) ;
2008-03-27 14:22:03 +01:00
static int zfcp_erp_adapter_reopen_internal ( struct zfcp_adapter * , int , u8 ,
u64 ) ;
static int zfcp_erp_port_forced_reopen_internal ( struct zfcp_port * , int , u8 ,
u64 ) ;
static int zfcp_erp_port_reopen_internal ( struct zfcp_port * , int , u8 , u64 ) ;
static int zfcp_erp_unit_reopen_internal ( struct zfcp_unit * , int , u8 , u64 ) ;
2005-04-16 15:20:36 -07:00
2008-03-27 14:22:03 +01:00
static int zfcp_erp_port_reopen_all_internal ( struct zfcp_adapter * , int , u8 ,
u64 ) ;
static int zfcp_erp_unit_reopen_all_internal ( struct zfcp_port * , int , u8 , u64 ) ;
2005-04-16 15:20:36 -07:00
static void zfcp_erp_adapter_block ( struct zfcp_adapter * , int ) ;
static void zfcp_erp_adapter_unblock ( struct zfcp_adapter * ) ;
static void zfcp_erp_port_block ( struct zfcp_port * , int ) ;
static void zfcp_erp_port_unblock ( struct zfcp_port * ) ;
static void zfcp_erp_unit_block ( struct zfcp_unit * , int ) ;
static void zfcp_erp_unit_unblock ( struct zfcp_unit * ) ;
static int zfcp_erp_thread ( void * ) ;
static int zfcp_erp_strategy ( struct zfcp_erp_action * ) ;
static int zfcp_erp_strategy_do_action ( struct zfcp_erp_action * ) ;
static int zfcp_erp_strategy_memwait ( struct zfcp_erp_action * ) ;
static int zfcp_erp_strategy_check_target ( struct zfcp_erp_action * , int ) ;
static int zfcp_erp_strategy_check_unit ( struct zfcp_unit * , int ) ;
static int zfcp_erp_strategy_check_port ( struct zfcp_port * , int ) ;
static int zfcp_erp_strategy_check_adapter ( struct zfcp_adapter * , int ) ;
static int zfcp_erp_strategy_statechange ( int , u32 , struct zfcp_adapter * ,
struct zfcp_port * ,
struct zfcp_unit * , int ) ;
2007-10-12 16:11:35 +02:00
static int zfcp_erp_strategy_statechange_detected ( atomic_t * , u32 ) ;
2005-04-16 15:20:36 -07:00
static int zfcp_erp_strategy_followup_actions ( int , struct zfcp_adapter * ,
struct zfcp_port * ,
struct zfcp_unit * , int ) ;
static int zfcp_erp_strategy_check_queues ( struct zfcp_adapter * ) ;
static int zfcp_erp_strategy_check_action ( struct zfcp_erp_action * , int ) ;
static int zfcp_erp_adapter_strategy ( struct zfcp_erp_action * ) ;
static int zfcp_erp_adapter_strategy_generic ( struct zfcp_erp_action * , int ) ;
static int zfcp_erp_adapter_strategy_close ( struct zfcp_erp_action * ) ;
static int zfcp_erp_adapter_strategy_open ( struct zfcp_erp_action * ) ;
static int zfcp_erp_adapter_strategy_open_qdio ( struct zfcp_erp_action * ) ;
static int zfcp_erp_adapter_strategy_open_fsf ( struct zfcp_erp_action * ) ;
static int zfcp_erp_adapter_strategy_open_fsf_xconfig ( struct zfcp_erp_action * ) ;
2005-09-13 21:51:16 +02:00
static int zfcp_erp_adapter_strategy_open_fsf_xport ( struct zfcp_erp_action * ) ;
2005-04-16 15:20:36 -07:00
static int zfcp_erp_adapter_strategy_open_fsf_statusread (
struct zfcp_erp_action * ) ;
static int zfcp_erp_port_forced_strategy ( struct zfcp_erp_action * ) ;
static int zfcp_erp_port_forced_strategy_close ( struct zfcp_erp_action * ) ;
static int zfcp_erp_port_strategy ( struct zfcp_erp_action * ) ;
static int zfcp_erp_port_strategy_clearstati ( struct zfcp_port * ) ;
static int zfcp_erp_port_strategy_close ( struct zfcp_erp_action * ) ;
static int zfcp_erp_port_strategy_open ( struct zfcp_erp_action * ) ;
static int zfcp_erp_port_strategy_open_nameserver ( struct zfcp_erp_action * ) ;
static int zfcp_erp_port_strategy_open_nameserver_wakeup (
struct zfcp_erp_action * ) ;
static int zfcp_erp_port_strategy_open_common ( struct zfcp_erp_action * ) ;
static int zfcp_erp_port_strategy_open_common_lookup ( struct zfcp_erp_action * ) ;
static int zfcp_erp_port_strategy_open_port ( struct zfcp_erp_action * ) ;
static int zfcp_erp_unit_strategy ( struct zfcp_erp_action * ) ;
static int zfcp_erp_unit_strategy_clearstati ( struct zfcp_unit * ) ;
static int zfcp_erp_unit_strategy_close ( struct zfcp_erp_action * ) ;
static int zfcp_erp_unit_strategy_open ( struct zfcp_erp_action * ) ;
2006-09-18 22:30:36 +02:00
static void zfcp_erp_action_dismiss_adapter ( struct zfcp_adapter * ) ;
2006-08-02 11:05:52 +02:00
static void zfcp_erp_action_dismiss_port ( struct zfcp_port * ) ;
static void zfcp_erp_action_dismiss_unit ( struct zfcp_unit * ) ;
static void zfcp_erp_action_dismiss ( struct zfcp_erp_action * ) ;
2005-04-16 15:20:36 -07:00
static int zfcp_erp_action_enqueue ( int , struct zfcp_adapter * ,
2008-03-27 14:22:03 +01:00
struct zfcp_port * , struct zfcp_unit * ,
u8 id , u64 ref ) ;
2005-04-16 15:20:36 -07:00
static int zfcp_erp_action_dequeue ( struct zfcp_erp_action * ) ;
static void zfcp_erp_action_cleanup ( int , struct zfcp_adapter * ,
struct zfcp_port * , struct zfcp_unit * ,
int ) ;
static void zfcp_erp_action_ready ( struct zfcp_erp_action * ) ;
static int zfcp_erp_action_exists ( struct zfcp_erp_action * ) ;
2007-10-12 16:11:35 +02:00
static void zfcp_erp_action_to_ready ( struct zfcp_erp_action * ) ;
static void zfcp_erp_action_to_running ( struct zfcp_erp_action * ) ;
2005-04-16 15:20:36 -07:00
static void zfcp_erp_memwait_handler ( unsigned long ) ;
/**
2006-09-18 22:29:56 +02:00
* zfcp_close_qdio - close qdio queues for an adapter
2005-04-16 15:20:36 -07:00
*/
2006-09-18 22:29:56 +02:00
static void zfcp_close_qdio ( struct zfcp_adapter * adapter )
2005-04-16 15:20:36 -07:00
{
2006-09-18 22:29:56 +02:00
struct zfcp_qdio_queue * req_queue ;
int first , count ;
2005-04-16 15:20:36 -07:00
2006-09-18 22:29:56 +02:00
if ( ! atomic_test_mask ( ZFCP_STATUS_ADAPTER_QDIOUP , & adapter - > status ) )
return ;
2005-04-16 15:20:36 -07:00
2006-09-18 22:29:56 +02:00
/* clear QDIOUP flag, thus do_QDIO is not called during qdio_shutdown */
req_queue = & adapter - > request_queue ;
write_lock_irq ( & req_queue - > queue_lock ) ;
atomic_clear_mask ( ZFCP_STATUS_ADAPTER_QDIOUP , & adapter - > status ) ;
write_unlock_irq ( & req_queue - > queue_lock ) ;
while ( qdio_shutdown ( adapter - > ccw_device ,
QDIO_FLAG_CLEANUP_USING_CLEAR ) = = - EINPROGRESS )
2007-11-05 12:37:45 +01:00
ssleep ( 1 ) ;
2006-09-18 22:29:56 +02:00
/* cleanup used outbound sbals */
count = atomic_read ( & req_queue - > free_count ) ;
if ( count < QDIO_MAX_BUFFERS_PER_Q ) {
first = ( req_queue - > free_index + count ) % QDIO_MAX_BUFFERS_PER_Q ;
count = QDIO_MAX_BUFFERS_PER_Q - count ;
zfcp_qdio_zero_sbals ( req_queue - > buffer , first , count ) ;
}
req_queue - > free_index = 0 ;
atomic_set ( & req_queue - > free_count , 0 ) ;
req_queue - > distance_from_int = 0 ;
adapter - > response_queue . free_index = 0 ;
atomic_set ( & adapter - > response_queue . free_count , 0 ) ;
2005-04-16 15:20:36 -07:00
}
2006-08-02 11:05:52 +02:00
/**
2006-09-18 22:29:56 +02:00
* zfcp_close_fsf - stop FSF operations for an adapter
2006-08-02 11:05:52 +02:00
*
2006-09-18 22:29:56 +02:00
* Dismiss and cleanup all pending fsf_reqs ( this wakes up all initiators of
* requests waiting for completion ; especially this returns SCSI commands
* with error state ) .
2005-04-16 15:20:36 -07:00
*/
2006-09-18 22:29:56 +02:00
static void zfcp_close_fsf ( struct zfcp_adapter * adapter )
2005-04-16 15:20:36 -07:00
{
2006-09-18 22:29:56 +02:00
/* close queues to ensure that buffers are not accessed by adapter */
zfcp_close_qdio ( adapter ) ;
zfcp_fsf_req_dismiss_all ( adapter ) ;
/* reset FSF request sequence number */
adapter - > fsf_req_seq_no = 0 ;
/* all ports and units are closed */
2008-03-27 14:22:02 +01:00
zfcp_erp_modify_adapter_status ( adapter , 24 , 0 ,
2006-09-18 22:29:56 +02:00
ZFCP_STATUS_COMMON_OPEN , ZFCP_CLEAR ) ;
}
2005-04-16 15:20:36 -07:00
2006-09-18 22:29:56 +02:00
/**
* zfcp_fsf_request_timeout_handler - called if a request timed out
* @ data : pointer to adapter for handler function
*
* This function needs to be called if requests ( ELS , Generic Service ,
* or SCSI commands ) exceed a certain time limit . The assumption is
* that after the time limit the adapter get stuck . So we trigger a reopen of
* the adapter .
*/
static void zfcp_fsf_request_timeout_handler ( unsigned long data )
{
struct zfcp_adapter * adapter = ( struct zfcp_adapter * ) data ;
2008-03-27 14:22:03 +01:00
zfcp_erp_adapter_reopen ( adapter , ZFCP_STATUS_COMMON_ERP_FAILED , 62 , 0 ) ;
2005-04-16 15:20:36 -07:00
}
2006-09-18 22:29:56 +02:00
void zfcp_fsf_start_timer ( struct zfcp_fsf_req * fsf_req , unsigned long timeout )
{
fsf_req - > timer . function = zfcp_fsf_request_timeout_handler ;
fsf_req - > timer . data = ( unsigned long ) fsf_req - > adapter ;
2007-03-28 14:20:40 +02:00
fsf_req - > timer . expires = jiffies + timeout ;
2006-09-18 22:29:56 +02:00
add_timer ( & fsf_req - > timer ) ;
}
2005-04-16 15:20:36 -07:00
/*
2007-09-07 09:15:31 +02:00
* function :
2005-04-16 15:20:36 -07:00
*
* purpose : called if an adapter failed ,
* initiates adapter recovery which is done
* asynchronously
*
2006-06-26 18:35:02 +02:00
* returns : 0 - initiated action successfully
2005-04-16 15:20:36 -07:00
* < 0 - failed to initiate action
*/
2008-03-27 14:22:03 +01:00
static int zfcp_erp_adapter_reopen_internal ( struct zfcp_adapter * adapter ,
int clear_mask , u8 id , u64 ref )
2005-04-16 15:20:36 -07:00
{
int retval ;
ZFCP_LOG_DEBUG ( " reopen adapter %s \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
zfcp_erp_adapter_block ( adapter , clear_mask ) ;
if ( atomic_test_mask ( ZFCP_STATUS_COMMON_ERP_FAILED , & adapter - > status ) ) {
ZFCP_LOG_DEBUG ( " skipped reopen of failed adapter %s \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
/* ensure propagation of failed status to new devices */
2008-03-27 14:22:02 +01:00
zfcp_erp_adapter_failed ( adapter , 13 , 0 ) ;
2005-04-16 15:20:36 -07:00
retval = - EIO ;
goto out ;
}
retval = zfcp_erp_action_enqueue ( ZFCP_ERP_ACTION_REOPEN_ADAPTER ,
2008-03-27 14:22:03 +01:00
adapter , NULL , NULL , id , ref ) ;
2005-04-16 15:20:36 -07:00
out :
return retval ;
}
/*
2007-09-07 09:15:31 +02:00
* function :
2005-04-16 15:20:36 -07:00
*
* purpose : Wrappper for zfcp_erp_adapter_reopen_internal
* used to ensure the correct locking
*
2006-06-26 18:35:02 +02:00
* returns : 0 - initiated action successfully
2005-04-16 15:20:36 -07:00
* < 0 - failed to initiate action
*/
2008-03-27 14:22:03 +01:00
int zfcp_erp_adapter_reopen ( struct zfcp_adapter * adapter , int clear_mask ,
u8 id , u64 ref )
2005-04-16 15:20:36 -07:00
{
int retval ;
unsigned long flags ;
read_lock_irqsave ( & zfcp_data . config_lock , flags ) ;
write_lock ( & adapter - > erp_lock ) ;
2008-03-27 14:22:03 +01:00
retval = zfcp_erp_adapter_reopen_internal ( adapter , clear_mask , 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-03-27 14:22:03 +01:00
int zfcp_erp_adapter_shutdown ( struct zfcp_adapter * adapter , int clear_mask ,
u8 id , u64 ref )
2005-04-16 15:20:36 -07:00
{
int retval ;
retval = zfcp_erp_adapter_reopen ( adapter ,
ZFCP_STATUS_COMMON_RUNNING |
ZFCP_STATUS_COMMON_ERP_FAILED |
2008-03-27 14:22:03 +01:00
clear_mask , id , ref ) ;
2005-04-16 15:20:36 -07:00
return retval ;
}
2008-03-27 14:22:03 +01:00
int zfcp_erp_port_shutdown ( struct zfcp_port * port , int clear_mask , u8 id ,
u64 ref )
2005-04-16 15:20:36 -07:00
{
int retval ;
retval = zfcp_erp_port_reopen ( port ,
ZFCP_STATUS_COMMON_RUNNING |
ZFCP_STATUS_COMMON_ERP_FAILED |
2008-03-27 14:22:03 +01:00
clear_mask , id , ref ) ;
2005-04-16 15:20:36 -07:00
return retval ;
}
2008-03-27 14:22:03 +01:00
int zfcp_erp_unit_shutdown ( struct zfcp_unit * unit , int clear_mask , u8 id ,
u64 ref )
2005-04-16 15:20:36 -07:00
{
int retval ;
retval = zfcp_erp_unit_reopen ( unit ,
ZFCP_STATUS_COMMON_RUNNING |
ZFCP_STATUS_COMMON_ERP_FAILED |
2008-03-27 14:22:03 +01:00
clear_mask , id , ref ) ;
2005-04-16 15:20:36 -07:00
return retval ;
}
/**
* zfcp_erp_adisc - send ADISC ELS command
2005-06-13 13:18:56 +02:00
* @ port : port structure
2005-04-16 15:20:36 -07:00
*/
2007-02-05 21:16:47 +01:00
static int
2005-06-13 13:18:56 +02:00
zfcp_erp_adisc ( struct zfcp_port * port )
2005-04-16 15:20:36 -07:00
{
2005-06-13 13:18:56 +02:00
struct zfcp_adapter * adapter = port - > adapter ;
2005-04-16 15:20:36 -07:00
struct zfcp_send_els * send_els ;
struct zfcp_ls_adisc * adisc ;
void * address = NULL ;
int retval = 0 ;
2006-05-22 18:17:30 +02:00
send_els = kzalloc ( sizeof ( struct zfcp_send_els ) , GFP_ATOMIC ) ;
2005-04-16 15:20:36 -07:00
if ( send_els = = NULL )
goto nomem ;
2007-10-23 09:17:53 +02:00
send_els - > req = kmalloc ( sizeof ( struct scatterlist ) , GFP_ATOMIC ) ;
2005-04-16 15:20:36 -07:00
if ( send_els - > req = = NULL )
goto nomem ;
2007-10-23 09:17:53 +02:00
sg_init_table ( send_els - > req , 1 ) ;
2005-04-16 15:20:36 -07:00
2007-10-23 09:17:53 +02:00
send_els - > resp = kmalloc ( sizeof ( struct scatterlist ) , GFP_ATOMIC ) ;
2005-04-16 15:20:36 -07:00
if ( send_els - > resp = = NULL )
goto nomem ;
2007-10-23 09:17:53 +02:00
sg_init_table ( send_els - > resp , 1 ) ;
2005-04-16 15:20:36 -07:00
address = ( void * ) get_zeroed_page ( GFP_ATOMIC ) ;
if ( address = = NULL )
goto nomem ;
2007-10-24 11:20:47 +02:00
zfcp_address_to_sg ( address , send_els - > req , sizeof ( struct zfcp_ls_adisc ) ) ;
2005-04-16 15:20:36 -07:00
address + = PAGE_SIZE > > 1 ;
2007-10-24 11:20:47 +02:00
zfcp_address_to_sg ( address , send_els - > resp , sizeof ( struct zfcp_ls_adisc_acc ) ) ;
2005-04-16 15:20:36 -07:00
send_els - > req_count = send_els - > resp_count = 1 ;
send_els - > adapter = adapter ;
2005-06-13 13:18:56 +02:00
send_els - > port = port ;
send_els - > d_id = port - > d_id ;
2005-04-16 15:20:36 -07:00
send_els - > handler = zfcp_erp_adisc_handler ;
send_els - > handler_data = ( unsigned long ) send_els ;
adisc = zfcp_sg_to_address ( send_els - > req ) ;
send_els - > ls_code = adisc - > code = ZFCP_LS_ADISC ;
/* acc. to FC-FS, hard_nport_id in ADISC should not be set for ports
without FC - AL - 2 capability , so we don ' t set it */
2005-09-19 16:56:17 +02:00
adisc - > wwpn = fc_host_port_name ( adapter - > scsi_host ) ;
adisc - > wwnn = fc_host_node_name ( adapter - > scsi_host ) ;
adisc - > nport_id = fc_host_port_id ( adapter - > scsi_host ) ;
2007-05-08 11:14:41 +02:00
ZFCP_LOG_INFO ( " ADISC request from s_id 0x%06x to d_id 0x%06x "
2005-04-16 15:20:36 -07:00
" (wwpn=0x%016Lx, wwnn=0x%016Lx, "
2007-05-08 11:14:41 +02:00
" hard_nport_id=0x%06x, nport_id=0x%06x) \n " ,
2005-09-19 16:56:17 +02:00
adisc - > nport_id , send_els - > d_id , ( wwn_t ) adisc - > wwpn ,
2005-04-16 15:20:36 -07:00
( wwn_t ) adisc - > wwnn , adisc - > hard_nport_id ,
adisc - > nport_id ) ;
retval = zfcp_fsf_send_els ( send_els ) ;
if ( retval ! = 0 ) {
ZFCP_LOG_NORMAL ( " error: initiation of Send ELS failed for port "
2007-05-08 11:14:41 +02:00
" 0x%06x on adapter %s \n " , send_els - > d_id ,
2005-04-16 15:20:36 -07:00
zfcp_get_busid_by_adapter ( adapter ) ) ;
goto freemem ;
}
goto out ;
nomem :
retval = - ENOMEM ;
freemem :
if ( address ! = NULL )
2007-10-23 09:17:53 +02:00
__free_pages ( sg_page ( send_els - > req ) , 0 ) ;
2005-04-16 15:20:36 -07:00
if ( send_els ! = NULL ) {
kfree ( send_els - > req ) ;
kfree ( send_els - > resp ) ;
kfree ( send_els ) ;
}
out :
return retval ;
}
/**
* zfcp_erp_adisc_handler - handler for ADISC ELS command
* @ data : pointer to struct zfcp_send_els
*
* If ADISC failed ( LS_RJT or timed out ) forced reopen of the port is triggered .
*/
2007-02-05 21:16:47 +01:00
static void
2005-04-16 15:20:36 -07:00
zfcp_erp_adisc_handler ( unsigned long data )
{
struct zfcp_send_els * send_els ;
struct zfcp_port * port ;
struct zfcp_adapter * adapter ;
2005-09-19 16:56:17 +02:00
u32 d_id ;
2005-04-16 15:20:36 -07:00
struct zfcp_ls_adisc_acc * adisc ;
send_els = ( struct zfcp_send_els * ) data ;
adapter = send_els - > adapter ;
2005-06-13 13:18:56 +02:00
port = send_els - > port ;
2005-04-16 15:20:36 -07:00
d_id = send_els - > d_id ;
/* request rejected or timed out */
if ( send_els - > status ! = 0 ) {
ZFCP_LOG_NORMAL ( " ELS request rejected/timed out, "
" force physical port reopen "
2007-05-08 11:14:41 +02:00
" (adapter %s, port d_id=0x%06x) \n " ,
2005-04-16 15:20:36 -07:00
zfcp_get_busid_by_adapter ( adapter ) , d_id ) ;
2008-03-27 14:22:03 +01:00
if ( zfcp_erp_port_forced_reopen ( port , 0 , 63 , 0 ) )
2005-04-16 15:20:36 -07:00
ZFCP_LOG_NORMAL ( " failed reopen of port "
" (adapter %s, wwpn=0x%016Lx) \n " ,
zfcp_get_busid_by_port ( port ) ,
port - > wwpn ) ;
goto out ;
}
adisc = zfcp_sg_to_address ( send_els - > resp ) ;
2007-05-08 11:14:41 +02:00
ZFCP_LOG_INFO ( " ADISC response from d_id 0x%06x to s_id "
" 0x%06x (wwpn=0x%016Lx, wwnn=0x%016Lx, "
" hard_nport_id=0x%06x, nport_id=0x%06x) \n " ,
2005-09-19 16:56:17 +02:00
d_id , fc_host_port_id ( adapter - > scsi_host ) ,
( wwn_t ) adisc - > wwpn , ( wwn_t ) adisc - > wwnn ,
adisc - > hard_nport_id , adisc - > nport_id ) ;
2005-04-16 15:20:36 -07:00
/* set wwnn for port */
if ( port - > wwnn = = 0 )
port - > wwnn = adisc - > wwnn ;
if ( port - > wwpn ! = adisc - > wwpn ) {
ZFCP_LOG_NORMAL ( " d_id assignment changed, reopening "
" port (adapter %s, wwpn=0x%016Lx, "
" adisc_resp_wwpn=0x%016Lx) \n " ,
zfcp_get_busid_by_port ( port ) ,
port - > wwpn , ( wwn_t ) adisc - > wwpn ) ;
2008-03-27 14:22:03 +01:00
if ( zfcp_erp_port_reopen ( port , 0 , 64 , 0 ) )
2005-04-16 15:20:36 -07:00
ZFCP_LOG_NORMAL ( " failed reopen of port "
" (adapter %s, wwpn=0x%016Lx) \n " ,
zfcp_get_busid_by_port ( port ) ,
port - > wwpn ) ;
}
out :
zfcp_port_put ( port ) ;
2007-10-23 09:17:53 +02:00
__free_pages ( sg_page ( send_els - > req ) , 0 ) ;
2005-04-16 15:20:36 -07:00
kfree ( send_els - > req ) ;
kfree ( send_els - > resp ) ;
kfree ( send_els ) ;
}
/**
* zfcp_test_link - lightweight link test procedure
* @ port : port to be tested
*
* Test status of a link to a remote port using the ELS command ADISC .
*/
int
zfcp_test_link ( struct zfcp_port * port )
{
int retval ;
zfcp_port_get ( port ) ;
2005-06-13 13:18:56 +02:00
retval = zfcp_erp_adisc ( port ) ;
2007-12-20 12:30:25 +01:00
if ( retval ! = 0 & & retval ! = - EBUSY ) {
2005-04-16 15:20:36 -07:00
zfcp_port_put ( port ) ;
ZFCP_LOG_NORMAL ( " reopen needed for port 0x%016Lx "
" on adapter %s \n " , port - > wwpn ,
zfcp_get_busid_by_port ( port ) ) ;
2008-03-27 14:22:03 +01:00
retval = zfcp_erp_port_forced_reopen ( port , 0 , 65 , 0 ) ;
2005-04-16 15:20:36 -07:00
if ( retval ! = 0 ) {
ZFCP_LOG_NORMAL ( " reopen of remote port 0x%016Lx "
" on adapter %s failed \n " , port - > wwpn ,
zfcp_get_busid_by_port ( port ) ) ;
retval = - EPERM ;
}
}
return retval ;
}
/*
2007-09-07 09:15:31 +02:00
* function :
2005-04-16 15:20:36 -07:00
*
* purpose : called if a port failed to be opened normally
* initiates Forced Reopen recovery which is done
* asynchronously
*
2006-06-26 18:35:02 +02:00
* returns : 0 - initiated action successfully
2005-04-16 15:20:36 -07:00
* < 0 - failed to initiate action
*/
2008-03-27 14:22:03 +01:00
static int zfcp_erp_port_forced_reopen_internal ( struct zfcp_port * port ,
int clear_mask , u8 id , u64 ref )
2005-04-16 15:20:36 -07:00
{
int retval ;
ZFCP_LOG_DEBUG ( " forced reopen of port 0x%016Lx on adapter %s \n " ,
port - > wwpn , zfcp_get_busid_by_port ( port ) ) ;
zfcp_erp_port_block ( port , clear_mask ) ;
if ( atomic_test_mask ( ZFCP_STATUS_COMMON_ERP_FAILED , & port - > status ) ) {
ZFCP_LOG_DEBUG ( " skipped forced reopen of failed port 0x%016Lx "
" on adapter %s \n " , port - > wwpn ,
zfcp_get_busid_by_port ( port ) ) ;
retval = - EIO ;
goto out ;
}
retval = zfcp_erp_action_enqueue ( ZFCP_ERP_ACTION_REOPEN_PORT_FORCED ,
2008-03-27 14:22:03 +01:00
port - > adapter , port , NULL , id , ref ) ;
2005-04-16 15:20:36 -07:00
out :
return retval ;
}
/*
2007-09-07 09:15:31 +02:00
* function :
2005-04-16 15:20:36 -07:00
*
* purpose : Wrappper for zfcp_erp_port_forced_reopen_internal
* used to ensure the correct locking
*
2006-06-26 18:35:02 +02:00
* returns : 0 - initiated action successfully
2005-04-16 15:20:36 -07:00
* < 0 - failed to initiate action
*/
2008-03-27 14:22:03 +01:00
int zfcp_erp_port_forced_reopen ( struct zfcp_port * port , int clear_mask , u8 id ,
u64 ref )
2005-04-16 15:20:36 -07:00
{
int retval ;
unsigned long flags ;
struct zfcp_adapter * adapter ;
adapter = port - > adapter ;
read_lock_irqsave ( & zfcp_data . config_lock , flags ) ;
write_lock ( & adapter - > erp_lock ) ;
2008-03-27 14:22:03 +01:00
retval = zfcp_erp_port_forced_reopen_internal ( port , clear_mask , 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 ;
}
/*
2007-09-07 09:15:31 +02:00
* function :
2005-04-16 15:20:36 -07:00
*
* purpose : called if a port is to be opened
* initiates Reopen recovery which is done
* asynchronously
*
2006-06-26 18:35:02 +02:00
* returns : 0 - initiated action successfully
2005-04-16 15:20:36 -07:00
* < 0 - failed to initiate action
*/
2008-03-27 14:22:03 +01:00
static int zfcp_erp_port_reopen_internal ( struct zfcp_port * port , int clear_mask ,
u8 id , u64 ref )
2005-04-16 15:20:36 -07:00
{
int retval ;
ZFCP_LOG_DEBUG ( " reopen of port 0x%016Lx on adapter %s \n " ,
port - > wwpn , zfcp_get_busid_by_port ( port ) ) ;
zfcp_erp_port_block ( port , clear_mask ) ;
if ( atomic_test_mask ( ZFCP_STATUS_COMMON_ERP_FAILED , & port - > status ) ) {
ZFCP_LOG_DEBUG ( " skipped reopen of failed port 0x%016Lx "
" on adapter %s \n " , port - > wwpn ,
zfcp_get_busid_by_port ( port ) ) ;
/* ensure propagation of failed status to new devices */
2008-03-27 14:22:02 +01:00
zfcp_erp_port_failed ( port , 14 , 0 ) ;
2005-04-16 15:20:36 -07:00
retval = - EIO ;
goto out ;
}
retval = zfcp_erp_action_enqueue ( ZFCP_ERP_ACTION_REOPEN_PORT ,
2008-03-27 14:22:03 +01:00
port - > adapter , port , NULL , id , ref ) ;
2005-04-16 15:20:36 -07:00
out :
return retval ;
}
/**
* zfcp_erp_port_reopen - initiate reopen of a remote port
* @ port : port to be reopened
* @ clear_mask : specifies flags in port status to be cleared
* Return : 0 on success , < 0 on error
*
* This is a wrappper function for zfcp_erp_port_reopen_internal . It ensures
* correct locking . An error recovery task is initiated to do the reopen .
* To wait for the completion of the reopen zfcp_erp_wait should be used .
*/
2008-03-27 14:22:03 +01:00
int zfcp_erp_port_reopen ( struct zfcp_port * port , int clear_mask , u8 id , u64 ref )
2005-04-16 15:20:36 -07:00
{
int retval ;
unsigned long flags ;
struct zfcp_adapter * adapter = port - > adapter ;
read_lock_irqsave ( & zfcp_data . config_lock , flags ) ;
write_lock ( & adapter - > erp_lock ) ;
2008-03-27 14:22:03 +01:00
retval = zfcp_erp_port_reopen_internal ( port , clear_mask , 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 ;
}
/*
2007-09-07 09:15:31 +02:00
* function :
2005-04-16 15:20:36 -07:00
*
* purpose : called if a unit is to be opened
* initiates Reopen recovery which is done
* asynchronously
*
2006-06-26 18:35:02 +02:00
* returns : 0 - initiated action successfully
2005-04-16 15:20:36 -07:00
* < 0 - failed to initiate action
*/
2008-03-27 14:22:03 +01:00
static int zfcp_erp_unit_reopen_internal ( struct zfcp_unit * unit , int clear_mask ,
u8 id , u64 ref )
2005-04-16 15:20:36 -07:00
{
int retval ;
struct zfcp_adapter * adapter = unit - > port - > adapter ;
ZFCP_LOG_DEBUG ( " reopen of unit 0x%016Lx on port 0x%016Lx "
" on adapter %s \n " , unit - > fcp_lun ,
unit - > port - > wwpn , zfcp_get_busid_by_unit ( unit ) ) ;
zfcp_erp_unit_block ( unit , clear_mask ) ;
if ( atomic_test_mask ( ZFCP_STATUS_COMMON_ERP_FAILED , & unit - > status ) ) {
ZFCP_LOG_DEBUG ( " skipped reopen of failed unit 0x%016Lx "
" on port 0x%016Lx on adapter %s \n " ,
unit - > fcp_lun , unit - > port - > wwpn ,
zfcp_get_busid_by_unit ( unit ) ) ;
retval = - EIO ;
goto out ;
}
retval = zfcp_erp_action_enqueue ( ZFCP_ERP_ACTION_REOPEN_UNIT ,
2008-03-27 14:22:03 +01:00
adapter , unit - > port , unit , id , ref ) ;
2005-04-16 15:20:36 -07:00
out :
return retval ;
}
/**
* 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
*
* This is a wrappper for zfcp_erp_unit_reopen_internal . It ensures correct
* locking . An error recovery task is initiated to do the reopen .
* To wait for the completion of the reopen zfcp_erp_wait should be used .
*/
2008-03-27 14:22:03 +01:00
int zfcp_erp_unit_reopen ( struct zfcp_unit * unit , int clear_mask , u8 id , u64 ref )
2005-04-16 15:20:36 -07:00
{
int retval ;
unsigned long flags ;
struct zfcp_adapter * adapter ;
struct zfcp_port * port ;
port = unit - > port ;
adapter = port - > adapter ;
read_lock_irqsave ( & zfcp_data . config_lock , flags ) ;
write_lock ( & adapter - > erp_lock ) ;
2008-03-27 14:22:03 +01:00
retval = zfcp_erp_unit_reopen_internal ( unit , clear_mask , 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 ;
}
2006-08-02 11:05:52 +02:00
/**
* zfcp_erp_adapter_block - mark adapter as blocked , block scsi requests
2005-04-16 15:20:36 -07:00
*/
2006-08-02 11:05:52 +02:00
static void zfcp_erp_adapter_block ( struct zfcp_adapter * adapter , int clear_mask )
2005-04-16 15:20:36 -07:00
{
2008-03-27 14:22:02 +01:00
zfcp_erp_modify_adapter_status ( adapter , 15 , 0 ,
2005-04-16 15:20:36 -07:00
ZFCP_STATUS_COMMON_UNBLOCKED |
clear_mask , ZFCP_CLEAR ) ;
}
2008-03-27 14:22:02 +01:00
/* FIXME: isn't really atomic */
/*
* returns the mask which has not been set so far , i . e .
* 0 if no bit has been changed , ! 0 if some bit has been changed
*/
static int atomic_test_and_set_mask ( unsigned long mask , atomic_t * v )
{
int changed_bits = ( atomic_read ( v ) /*XOR*/ ^ mask ) & mask ;
atomic_set_mask ( mask , v ) ;
return changed_bits ;
}
/* FIXME: isn't really atomic */
/*
* returns the mask which has not been cleared so far , i . e .
* 0 if no bit has been changed , ! 0 if some bit has been changed
*/
static int atomic_test_and_clear_mask ( unsigned long mask , atomic_t * v )
{
int changed_bits = atomic_read ( v ) & mask ;
atomic_clear_mask ( mask , v ) ;
return changed_bits ;
}
2006-08-02 11:05:52 +02:00
/**
* zfcp_erp_adapter_unblock - mark adapter as unblocked , allow scsi requests
2005-04-16 15:20:36 -07:00
*/
2006-08-02 11:05:52 +02:00
static void zfcp_erp_adapter_unblock ( struct zfcp_adapter * adapter )
2005-04-16 15:20:36 -07:00
{
2008-03-27 14:22:02 +01:00
if ( atomic_test_and_set_mask ( ZFCP_STATUS_COMMON_UNBLOCKED ,
& adapter - > status ) )
zfcp_rec_dbf_event_adapter ( 16 , 0 , adapter ) ;
2005-04-16 15:20:36 -07:00
}
/*
2007-09-07 09:15:31 +02:00
* function :
2005-04-16 15:20:36 -07:00
*
* purpose : disable I / O ,
* return any open requests and clean them up ,
* aim : no pending and incoming I / O
*
* returns :
*/
static void
zfcp_erp_port_block ( struct zfcp_port * port , int clear_mask )
{
2008-03-27 14:22:02 +01:00
zfcp_erp_modify_port_status ( port , 17 , 0 ,
2005-04-16 15:20:36 -07:00
ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask ,
ZFCP_CLEAR ) ;
}
/*
2007-09-07 09:15:31 +02:00
* function :
2005-04-16 15:20:36 -07:00
*
* purpose : enable I / O
*
* returns :
*/
static void
zfcp_erp_port_unblock ( struct zfcp_port * port )
{
2008-03-27 14:22:02 +01:00
if ( atomic_test_and_set_mask ( ZFCP_STATUS_COMMON_UNBLOCKED ,
& port - > status ) )
zfcp_rec_dbf_event_port ( 18 , 0 , port ) ;
2005-04-16 15:20:36 -07:00
}
/*
2007-09-07 09:15:31 +02:00
* function :
2005-04-16 15:20:36 -07:00
*
* purpose : disable I / O ,
* return any open requests and clean them up ,
* aim : no pending and incoming I / O
*
* returns :
*/
static void
zfcp_erp_unit_block ( struct zfcp_unit * unit , int clear_mask )
{
2008-03-27 14:22:02 +01:00
zfcp_erp_modify_unit_status ( unit , 19 , 0 ,
2005-04-16 15:20:36 -07:00
ZFCP_STATUS_COMMON_UNBLOCKED | clear_mask ,
ZFCP_CLEAR ) ;
}
/*
2007-09-07 09:15:31 +02:00
* function :
2005-04-16 15:20:36 -07:00
*
* purpose : enable I / O
*
* returns :
*/
static void
zfcp_erp_unit_unblock ( struct zfcp_unit * unit )
{
2008-03-27 14:22:02 +01:00
if ( atomic_test_and_set_mask ( ZFCP_STATUS_COMMON_UNBLOCKED ,
& unit - > status ) )
zfcp_rec_dbf_event_unit ( 20 , 0 , unit ) ;
2005-04-16 15:20:36 -07:00
}
static void
zfcp_erp_action_ready ( struct zfcp_erp_action * erp_action )
{
struct zfcp_adapter * adapter = erp_action - > adapter ;
zfcp_erp_action_to_ready ( erp_action ) ;
up ( & adapter - > erp_ready_sem ) ;
2008-03-27 14:22:01 +01:00
zfcp_rec_dbf_event_thread ( 2 , adapter , 0 ) ;
2005-04-16 15:20:36 -07:00
}
/*
2007-09-07 09:15:31 +02:00
* function :
2005-04-16 15:20:36 -07:00
*
* purpose :
*
* returns : < 0 erp_action not found in any list
* ZFCP_ERP_ACTION_READY erp_action is in ready list
* ZFCP_ERP_ACTION_RUNNING erp_action is in running list
*
* locks : erp_lock must be held
*/
static int
zfcp_erp_action_exists ( struct zfcp_erp_action * erp_action )
{
int retval = - EINVAL ;
struct list_head * entry ;
struct zfcp_erp_action * entry_erp_action ;
struct zfcp_adapter * adapter = erp_action - > adapter ;
/* search in running list */
list_for_each ( entry , & adapter - > erp_running_head ) {
entry_erp_action =
list_entry ( entry , struct zfcp_erp_action , list ) ;
if ( entry_erp_action = = erp_action ) {
retval = ZFCP_ERP_ACTION_RUNNING ;
goto out ;
}
}
/* search in ready list */
list_for_each ( entry , & adapter - > erp_ready_head ) {
entry_erp_action =
list_entry ( entry , struct zfcp_erp_action , list ) ;
if ( entry_erp_action = = erp_action ) {
retval = ZFCP_ERP_ACTION_READY ;
goto out ;
}
}
out :
return retval ;
}
/*
* purpose : checks current status of action ( timed out , dismissed , . . . )
* and does appropriate preparations ( dismiss fsf request , . . . )
*
* locks : called under erp_lock ( disabled interrupts )
*/
2007-02-09 10:00:14 +01:00
static void
2005-04-16 15:20:36 -07:00
zfcp_erp_strategy_check_fsfreq ( struct zfcp_erp_action * erp_action )
{
struct zfcp_adapter * adapter = erp_action - > adapter ;
if ( erp_action - > fsf_req ) {
2006-08-02 11:05:16 +02:00
/* take lock to ensure that request is not deleted meanwhile */
spin_lock ( & adapter - > req_list_lock ) ;
2007-12-20 12:30:22 +01:00
if ( zfcp_reqlist_find_safe ( adapter , erp_action - > fsf_req ) & &
erp_action - > fsf_req - > erp_action = = erp_action ) {
2005-04-16 15:20:36 -07:00
/* fsf_req still exists */
2006-08-02 11:05:16 +02:00
/* dismiss fsf_req of timed out/dismissed erp_action */
2005-04-16 15:20:36 -07:00
if ( erp_action - > status & ( ZFCP_STATUS_ERP_DISMISSED |
ZFCP_STATUS_ERP_TIMEDOUT ) ) {
2007-02-09 10:00:14 +01:00
erp_action - > fsf_req - > status | =
ZFCP_STATUS_FSFREQ_DISMISSED ;
2008-03-27 14:22:04 +01:00
zfcp_rec_dbf_event_action ( 142 , erp_action ) ;
2005-04-16 15:20:36 -07:00
}
if ( erp_action - > status & ZFCP_STATUS_ERP_TIMEDOUT ) {
2008-03-27 14:22:04 +01:00
zfcp_rec_dbf_event_action ( 143 , erp_action ) ;
2005-04-16 15:20:36 -07:00
ZFCP_LOG_NORMAL ( " error: erp step timed out "
" (action=%d, fsf_req=%p) \n " ,
erp_action - > action ,
erp_action - > fsf_req ) ;
}
/*
* If fsf_req is neither dismissed nor completed
* then keep it running asynchronously and don ' t mess
* with the association of erp_action and fsf_req .
*/
2007-02-09 10:00:14 +01:00
if ( erp_action - > fsf_req - > status &
( ZFCP_STATUS_FSFREQ_COMPLETED |
2005-04-16 15:20:36 -07:00
ZFCP_STATUS_FSFREQ_DISMISSED ) ) {
/* forget about association between fsf_req
and erp_action */
erp_action - > fsf_req = NULL ;
}
} else {
/*
* even if this fsf_req has gone , forget about
* association between erp_action and fsf_req
*/
erp_action - > fsf_req = NULL ;
}
2006-08-02 11:05:16 +02:00
spin_unlock ( & adapter - > req_list_lock ) ;
2008-03-27 14:22:05 +01:00
}
2005-04-16 15:20:36 -07:00
}
2006-08-02 11:05:52 +02:00
/**
* zfcp_erp_async_handler_nolock - complete erp_action
2005-04-16 15:20:36 -07:00
*
2006-08-02 11:05:52 +02:00
* Used for normal completion , time - out , dismissal and failure after
* low memory condition .
2005-04-16 15:20:36 -07:00
*/
2006-08-02 11:05:52 +02:00
static void zfcp_erp_async_handler_nolock ( struct zfcp_erp_action * erp_action ,
unsigned long set_mask )
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 ) ;
} else {
/* action is ready or gone - nothing to do */
}
}
2006-08-02 11:05:52 +02:00
/**
* zfcp_erp_async_handler - wrapper for erp_async_handler_nolock w / locking
2005-04-16 15:20:36 -07:00
*/
2006-08-02 11:05:52 +02:00
void zfcp_erp_async_handler ( 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 ;
unsigned long flags ;
write_lock_irqsave ( & adapter - > erp_lock , flags ) ;
2006-08-02 11:05:52 +02:00
zfcp_erp_async_handler_nolock ( erp_action , set_mask ) ;
2005-04-16 15:20:36 -07:00
write_unlock_irqrestore ( & adapter - > erp_lock , flags ) ;
}
/*
* purpose : is called for erp_action which was slept waiting for
* memory becoming avaliable ,
* will trigger that this action will be continued
*/
static void
zfcp_erp_memwait_handler ( unsigned long data )
{
struct zfcp_erp_action * erp_action = ( struct zfcp_erp_action * ) data ;
zfcp_erp_async_handler ( erp_action , 0 ) ;
}
/*
* purpose : is called if an asynchronous erp step timed out ,
* action gets an appropriate flag and will be processed
* accordingly
*/
2007-10-12 16:11:35 +02:00
static void zfcp_erp_timeout_handler ( unsigned long data )
2005-04-16 15:20:36 -07:00
{
struct zfcp_erp_action * erp_action = ( struct zfcp_erp_action * ) data ;
zfcp_erp_async_handler ( erp_action , ZFCP_STATUS_ERP_TIMEDOUT ) ;
}
2006-08-02 11:05:52 +02:00
/**
* zfcp_erp_action_dismiss - dismiss an erp_action
2005-04-16 15:20:36 -07:00
*
2006-08-02 11:05:52 +02:00
* adapter - > erp_lock must be held
2007-09-07 09:15:31 +02:00
*
2006-08-02 11:05:52 +02:00
* Dismissal of an erp_action is usually required if an erp_action of
* higher priority is generated .
2005-04-16 15:20:36 -07:00
*/
2006-08-02 11:05:52 +02:00
static void zfcp_erp_action_dismiss ( struct zfcp_erp_action * erp_action )
2005-04-16 15:20:36 -07:00
{
2007-11-15 13:57:08 +01:00
erp_action - > status | = ZFCP_STATUS_ERP_DISMISSED ;
if ( zfcp_erp_action_exists ( erp_action ) = = ZFCP_ERP_ACTION_RUNNING )
zfcp_erp_action_ready ( erp_action ) ;
2005-04-16 15:20:36 -07:00
}
int
zfcp_erp_thread_setup ( struct zfcp_adapter * adapter )
{
int retval = 0 ;
atomic_clear_mask ( ZFCP_STATUS_ADAPTER_ERP_THREAD_UP , & adapter - > status ) ;
retval = kernel_thread ( zfcp_erp_thread , adapter , SIGCHLD ) ;
if ( retval < 0 ) {
ZFCP_LOG_NORMAL ( " error: creation of erp thread failed for "
" adapter %s \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
} else {
wait_event ( adapter - > erp_thread_wqh ,
atomic_test_mask ( ZFCP_STATUS_ADAPTER_ERP_THREAD_UP ,
& adapter - > status ) ) ;
}
return ( retval < 0 ) ;
}
/*
2007-09-07 09:15:31 +02:00
* function :
2005-04-16 15:20:36 -07:00
*
2007-09-07 09:15:31 +02:00
* purpose :
2005-04-16 15:20:36 -07:00
*
* returns :
*
* context : process ( i . e . proc - fs or rmmod / insmod )
*
* note : 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 .
*/
int
zfcp_erp_thread_kill ( struct zfcp_adapter * adapter )
{
int retval = 0 ;
atomic_set_mask ( ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL , & adapter - > status ) ;
up ( & adapter - > erp_ready_sem ) ;
2008-03-27 14:22:01 +01:00
zfcp_rec_dbf_event_thread ( 2 , adapter , 1 ) ;
2005-04-16 15:20:36 -07:00
wait_event ( adapter - > erp_thread_wqh ,
! atomic_test_mask ( ZFCP_STATUS_ADAPTER_ERP_THREAD_UP ,
& adapter - > status ) ) ;
atomic_clear_mask ( ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL ,
& adapter - > status ) ;
return retval ;
}
/*
* purpose : is run as a kernel thread ,
* goes through list of error recovery actions of associated adapter
* and delegates single action to execution
*
* returns : 0
*/
static int
zfcp_erp_thread ( void * data )
{
struct zfcp_adapter * adapter = ( struct zfcp_adapter * ) data ;
struct list_head * next ;
struct zfcp_erp_action * erp_action ;
unsigned long flags ;
daemonize ( " zfcperp%s " , zfcp_get_busid_by_adapter ( adapter ) ) ;
/* Block all signals */
siginitsetinv ( & current - > blocked , 0 ) ;
atomic_set_mask ( ZFCP_STATUS_ADAPTER_ERP_THREAD_UP , & adapter - > status ) ;
wake_up ( & adapter - > erp_thread_wqh ) ;
while ( ! atomic_test_mask ( ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL ,
& adapter - > status ) ) {
write_lock_irqsave ( & adapter - > erp_lock , flags ) ;
[SCSI] zfcp: fix cleanup of dismissed error recovery actions
Calling zfcp_erp_strategy_check_action() after zfcp_erp_action_to_running()
in zfcp_erp_strategy() might cause an unbalanced up() for erp_ready_sem,
which makes the zfcp recovery fail somewhere along the way:
erp thread processing erp_action:
|
| someone waking up erp thread for erp_action
| |
| | someone else dismissing erp_action:
| | |
V V V
write_lock_irqsave(&adapter->erp_lock, flags);
...
if (zfcp_erp_action_exists(erp_action) == ZFCP_ERP_ACTION_RUNNING) {
zfcp_erp_action_to_ready(erp_action);
up(&adapter->erp_ready_sem); /* first up() for erp_action */
}
write_unlock_irqrestore(&adapter->erp_lock, flags);
write_lock_irqsave(&adapter->erp_lock, flags);
...
zfcp_erp_action_to_running(erp_action);
write_unlock_restore(&adapter->erp_lock, flags);
/* processing erp_action */
write_lock_irqsave(&adapter->erp_lock, flags);
...
erp_action->status |= ZFCP_STATUS_ERP_DISMISSED;
if (zfcp_erp_action_exists(erp_action) ==
ZFCP_ERP_ACTION_RUNNING) {
zfcp_erp_action_to_ready(erp_action);
up(&adapter->erp_ready_sem);
/* second, unbalanced up() for erp_action */
}
...
write_unlock_restore(&adapter->erp_lock, flags);
write_lock_irqsave(&adapter->erp_lock, flags);
if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) {
zfcp_erp_action_dequeue(erp_action);
retval = ZFCP_ERP_DISMISSED;
}
...
write_unlock_restore(&adapter->erp_lock, flags);
down(&adapter->erp_ready_sem);
/* this down() is meant to balance the first up() */
The erp thread must not dismiss an erp_action after moving that action to
erp_running_head. Instead it should just go through the down() operation,
which balances the first up(), and run through zfcp_erp_strategy one more
time for the second up(), which eventually cleans up erp_action. Which
is similar to the normal processing of an event for erp_action doing
something asynchronously (e.g. waiting for the completion of an fsf_req).
This only works if we make sure that a dismissed erp_action is passed to
zfcp_erp_strategy() prior to the other action, which caused actions to be
dismissed. Therefore the patch implements this rule: running actions go to
the head of the ready list; new actions go to the tail of the ready list;
the erp thread picks actions to be processed from the ready list's head.
Signed-off-by: Martin Peschke <mp3@de.ibm.com>
Acked-by: Swen Schillig <swen@vnet.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
2007-11-15 13:57:17 +01:00
next = adapter - > erp_ready_head . next ;
2005-04-16 15:20:36 -07:00
write_unlock_irqrestore ( & adapter - > erp_lock , flags ) ;
if ( next ! = & adapter - > erp_ready_head ) {
erp_action =
list_entry ( next , struct zfcp_erp_action , list ) ;
/*
* process action ( incl . [ re ] moving it
* from ' ready ' queue )
*/
zfcp_erp_strategy ( erp_action ) ;
}
/*
* sleep as long as there is nothing to do , i . e .
* no action in ' ready ' queue to be processed and
* thread is not to be killed
*/
2008-03-27 14:22:01 +01:00
zfcp_rec_dbf_event_thread ( 4 , adapter , 1 ) ;
2005-04-16 15:20:36 -07:00
down_interruptible ( & adapter - > erp_ready_sem ) ;
2008-03-27 14:22:01 +01:00
zfcp_rec_dbf_event_thread ( 5 , adapter , 1 ) ;
2005-04-16 15:20:36 -07:00
}
atomic_clear_mask ( ZFCP_STATUS_ADAPTER_ERP_THREAD_UP , & adapter - > status ) ;
wake_up ( & adapter - > erp_thread_wqh ) ;
return 0 ;
}
/*
2007-09-07 09:15:31 +02:00
* function :
2005-04-16 15:20:36 -07:00
*
* purpose : drives single error recovery action and schedules higher and
* subordinate actions , if necessary
*
* returns : ZFCP_ERP_CONTINUES - action continues ( asynchronously )
* ZFCP_ERP_SUCCEEDED - action finished successfully ( deqd )
* ZFCP_ERP_FAILED - action finished unsuccessfully ( deqd )
* ZFCP_ERP_EXIT - action finished ( dequeued ) , offline
* ZFCP_ERP_DISMISSED - action canceled ( dequeued )
*/
static int
zfcp_erp_strategy ( struct zfcp_erp_action * erp_action )
{
int retval = 0 ;
struct zfcp_adapter * adapter = erp_action - > adapter ;
struct zfcp_port * port = erp_action - > port ;
struct zfcp_unit * unit = erp_action - > unit ;
int action = erp_action - > action ;
u32 status = erp_action - > status ;
unsigned long flags ;
/* serialise dismissing, timing out, moving, enqueueing */
read_lock_irqsave ( & zfcp_data . config_lock , flags ) ;
write_lock ( & adapter - > erp_lock ) ;
/* dequeue dismissed action and leave, if required */
retval = zfcp_erp_strategy_check_action ( erp_action , retval ) ;
if ( retval = = ZFCP_ERP_DISMISSED ) {
goto unlock ;
}
/*
* move action to ' running ' queue before processing it
* ( to avoid a race condition regarding moving the
* action to the ' running ' queue and back )
*/
zfcp_erp_action_to_running ( erp_action ) ;
/*
* try to process action as far as possible ,
* no lock to allow for blocking operations ( kmalloc , qdio , . . . ) ,
* afterwards the lock is required again for the following reasons :
* - dequeueing of finished action and enqueueing of
* follow - up actions must be atomic so that any other
* reopen - routine does not believe there is nothing to do
* and that it is safe to enqueue something else ,
* - we want to force any control thread which is dismissing
* actions to finish this before we decide about
* necessary steps to be taken here further
*/
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 ) ;
/*
* check for dismissed status again to avoid follow - up actions ,
[SCSI] zfcp: fix cleanup of dismissed error recovery actions
Calling zfcp_erp_strategy_check_action() after zfcp_erp_action_to_running()
in zfcp_erp_strategy() might cause an unbalanced up() for erp_ready_sem,
which makes the zfcp recovery fail somewhere along the way:
erp thread processing erp_action:
|
| someone waking up erp thread for erp_action
| |
| | someone else dismissing erp_action:
| | |
V V V
write_lock_irqsave(&adapter->erp_lock, flags);
...
if (zfcp_erp_action_exists(erp_action) == ZFCP_ERP_ACTION_RUNNING) {
zfcp_erp_action_to_ready(erp_action);
up(&adapter->erp_ready_sem); /* first up() for erp_action */
}
write_unlock_irqrestore(&adapter->erp_lock, flags);
write_lock_irqsave(&adapter->erp_lock, flags);
...
zfcp_erp_action_to_running(erp_action);
write_unlock_restore(&adapter->erp_lock, flags);
/* processing erp_action */
write_lock_irqsave(&adapter->erp_lock, flags);
...
erp_action->status |= ZFCP_STATUS_ERP_DISMISSED;
if (zfcp_erp_action_exists(erp_action) ==
ZFCP_ERP_ACTION_RUNNING) {
zfcp_erp_action_to_ready(erp_action);
up(&adapter->erp_ready_sem);
/* second, unbalanced up() for erp_action */
}
...
write_unlock_restore(&adapter->erp_lock, flags);
write_lock_irqsave(&adapter->erp_lock, flags);
if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) {
zfcp_erp_action_dequeue(erp_action);
retval = ZFCP_ERP_DISMISSED;
}
...
write_unlock_restore(&adapter->erp_lock, flags);
down(&adapter->erp_ready_sem);
/* this down() is meant to balance the first up() */
The erp thread must not dismiss an erp_action after moving that action to
erp_running_head. Instead it should just go through the down() operation,
which balances the first up(), and run through zfcp_erp_strategy one more
time for the second up(), which eventually cleans up erp_action. Which
is similar to the normal processing of an event for erp_action doing
something asynchronously (e.g. waiting for the completion of an fsf_req).
This only works if we make sure that a dismissed erp_action is passed to
zfcp_erp_strategy() prior to the other action, which caused actions to be
dismissed. Therefore the patch implements this rule: running actions go to
the head of the ready list; new actions go to the tail of the ready list;
the erp thread picks actions to be processed from the ready list's head.
Signed-off-by: Martin Peschke <mp3@de.ibm.com>
Acked-by: Swen Schillig <swen@vnet.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
2007-11-15 13:57:17 +01:00
* failing of targets and so on for dismissed actions ,
* we go through down ( ) here because there has been an up ( )
2005-04-16 15:20:36 -07:00
*/
[SCSI] zfcp: fix cleanup of dismissed error recovery actions
Calling zfcp_erp_strategy_check_action() after zfcp_erp_action_to_running()
in zfcp_erp_strategy() might cause an unbalanced up() for erp_ready_sem,
which makes the zfcp recovery fail somewhere along the way:
erp thread processing erp_action:
|
| someone waking up erp thread for erp_action
| |
| | someone else dismissing erp_action:
| | |
V V V
write_lock_irqsave(&adapter->erp_lock, flags);
...
if (zfcp_erp_action_exists(erp_action) == ZFCP_ERP_ACTION_RUNNING) {
zfcp_erp_action_to_ready(erp_action);
up(&adapter->erp_ready_sem); /* first up() for erp_action */
}
write_unlock_irqrestore(&adapter->erp_lock, flags);
write_lock_irqsave(&adapter->erp_lock, flags);
...
zfcp_erp_action_to_running(erp_action);
write_unlock_restore(&adapter->erp_lock, flags);
/* processing erp_action */
write_lock_irqsave(&adapter->erp_lock, flags);
...
erp_action->status |= ZFCP_STATUS_ERP_DISMISSED;
if (zfcp_erp_action_exists(erp_action) ==
ZFCP_ERP_ACTION_RUNNING) {
zfcp_erp_action_to_ready(erp_action);
up(&adapter->erp_ready_sem);
/* second, unbalanced up() for erp_action */
}
...
write_unlock_restore(&adapter->erp_lock, flags);
write_lock_irqsave(&adapter->erp_lock, flags);
if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) {
zfcp_erp_action_dequeue(erp_action);
retval = ZFCP_ERP_DISMISSED;
}
...
write_unlock_restore(&adapter->erp_lock, flags);
down(&adapter->erp_ready_sem);
/* this down() is meant to balance the first up() */
The erp thread must not dismiss an erp_action after moving that action to
erp_running_head. Instead it should just go through the down() operation,
which balances the first up(), and run through zfcp_erp_strategy one more
time for the second up(), which eventually cleans up erp_action. Which
is similar to the normal processing of an event for erp_action doing
something asynchronously (e.g. waiting for the completion of an fsf_req).
This only works if we make sure that a dismissed erp_action is passed to
zfcp_erp_strategy() prior to the other action, which caused actions to be
dismissed. Therefore the patch implements this rule: running actions go to
the head of the ready list; new actions go to the tail of the ready list;
the erp thread picks actions to be processed from the ready list's head.
Signed-off-by: Martin Peschke <mp3@de.ibm.com>
Acked-by: Swen Schillig <swen@vnet.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
2007-11-15 13:57:17 +01:00
if ( erp_action - > status & ZFCP_STATUS_ERP_DISMISSED )
retval = ZFCP_ERP_CONTINUES ;
2005-04-16 15:20:36 -07:00
switch ( retval ) {
case ZFCP_ERP_NOMEM :
/* no memory to continue immediately, let it sleep */
if ( ! ( erp_action - > status & ZFCP_STATUS_ERP_LOWMEM ) ) {
+ + adapter - > erp_low_mem_count ;
erp_action - > status | = ZFCP_STATUS_ERP_LOWMEM ;
}
/* This condition is true if there is no memory available
for any erp_action on this adapter . This implies that there
are no elements in the memory pool ( s ) left for erp_actions .
This might happen if an erp_action that used a memory pool
element was timed out .
*/
if ( adapter - > erp_total_count = = adapter - > erp_low_mem_count ) {
ZFCP_LOG_NORMAL ( " error: no mempool elements available, "
" restarting I/O on adapter %s "
" to free mempool \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
2008-03-27 14:22:03 +01:00
zfcp_erp_adapter_reopen_internal ( adapter , 0 , 66 , 0 ) ;
2005-04-16 15:20:36 -07:00
} else {
retval = zfcp_erp_strategy_memwait ( erp_action ) ;
}
goto unlock ;
case ZFCP_ERP_CONTINUES :
/* leave since this action runs asynchronously */
if ( erp_action - > status & ZFCP_STATUS_ERP_LOWMEM ) {
- - adapter - > erp_low_mem_count ;
erp_action - > status & = ~ ZFCP_STATUS_ERP_LOWMEM ;
}
goto unlock ;
}
/* ok, finished action (whatever its result is) */
/* check for unrecoverable targets */
retval = zfcp_erp_strategy_check_target ( erp_action , retval ) ;
/* action must be dequeued (here to allow for further ones) */
zfcp_erp_action_dequeue ( erp_action ) ;
/*
* put this target through the erp mill again if someone has
2007-09-07 09:15:31 +02:00
* requested to change the status of a target being online
2005-04-16 15:20:36 -07:00
* to offline or the other way around
* ( old retval is preserved if nothing has to be done here )
*/
retval = zfcp_erp_strategy_statechange ( action , status , adapter ,
port , unit , retval ) ;
/*
* leave if target is in permanent error state or if
* action is repeated in order to process state change
*/
if ( retval = = ZFCP_ERP_EXIT ) {
goto unlock ;
}
/* trigger follow up actions */
zfcp_erp_strategy_followup_actions ( action , adapter , port , unit , retval ) ;
unlock :
write_unlock ( & adapter - > erp_lock ) ;
read_unlock_irqrestore ( & zfcp_data . config_lock , flags ) ;
2007-09-07 09:15:31 +02:00
2005-04-16 15:20:36 -07:00
if ( retval ! = ZFCP_ERP_CONTINUES )
zfcp_erp_action_cleanup ( action , adapter , port , unit , retval ) ;
/*
* a few tasks remain when the erp queues are empty
* ( don ' t do that if the last action evaluated was dismissed
* since this clearly indicates that there is more to come ) :
* - close the name server port if it is open yet
* ( enqueues another [ probably ] final action )
* - otherwise , wake up whoever wants to be woken when we are
* done with erp
*/
if ( retval ! = ZFCP_ERP_DISMISSED )
zfcp_erp_strategy_check_queues ( adapter ) ;
return retval ;
}
/*
2007-09-07 09:15:31 +02:00
* function :
2005-04-16 15:20:36 -07:00
*
2007-09-07 09:15:31 +02:00
* purpose :
2005-04-16 15:20:36 -07:00
*
* returns : ZFCP_ERP_DISMISSED - if action has been dismissed
* retval - otherwise
*/
static int
zfcp_erp_strategy_check_action ( struct zfcp_erp_action * erp_action , int retval )
{
zfcp_erp_strategy_check_fsfreq ( erp_action ) ;
if ( erp_action - > status & ZFCP_STATUS_ERP_DISMISSED ) {
zfcp_erp_action_dequeue ( erp_action ) ;
retval = ZFCP_ERP_DISMISSED ;
2008-03-27 14:22:05 +01:00
}
2005-04-16 15:20:36 -07:00
return retval ;
}
static int
zfcp_erp_strategy_do_action ( struct zfcp_erp_action * erp_action )
{
int retval = ZFCP_ERP_FAILED ;
/*
* try to execute / continue action as far as possible ,
* note : no lock in subsequent strategy routines
* ( this allows these routine to call schedule , e . g .
* kmalloc with such flags or qdio_initialize & friends )
2008-01-26 14:11:20 +01:00
* Note : in case of timeout , the separate strategies will fail
2005-04-16 15:20:36 -07:00
* anyhow . No need for a special action . Even worse , a nameserver
* failure would not wake up waiting ports without the call .
*/
switch ( erp_action - > action ) {
case ZFCP_ERP_ACTION_REOPEN_ADAPTER :
retval = zfcp_erp_adapter_strategy ( erp_action ) ;
break ;
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED :
retval = zfcp_erp_port_forced_strategy ( erp_action ) ;
break ;
case ZFCP_ERP_ACTION_REOPEN_PORT :
retval = zfcp_erp_port_strategy ( erp_action ) ;
break ;
case ZFCP_ERP_ACTION_REOPEN_UNIT :
retval = zfcp_erp_unit_strategy ( erp_action ) ;
break ;
default :
ZFCP_LOG_NORMAL ( " bug: unknown erp action requested on "
" adapter %s (action=%d) \n " ,
zfcp_get_busid_by_adapter ( erp_action - > adapter ) ,
erp_action - > action ) ;
}
return retval ;
}
/*
2007-09-07 09:15:31 +02:00
* function :
2005-04-16 15:20:36 -07:00
*
* purpose : triggers retry of this action after a certain amount of time
* by means of timer provided by erp_action
*
* returns : ZFCP_ERP_CONTINUES - erp_action sleeps in erp running queue
*/
static int
zfcp_erp_strategy_memwait ( struct zfcp_erp_action * erp_action )
{
int retval = ZFCP_ERP_CONTINUES ;
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 + ZFCP_ERP_MEMWAIT_TIMEOUT ;
add_timer ( & erp_action - > timer ) ;
return retval ;
}
2007-09-07 09:15:31 +02:00
/*
2005-04-16 15:20:36 -07:00
* function : zfcp_erp_adapter_failed
*
* purpose : sets the adapter and all underlying devices to ERP_FAILED
*
*/
void
2008-03-27 14:22:02 +01:00
zfcp_erp_adapter_failed ( struct zfcp_adapter * adapter , u8 id , u64 ref )
2005-04-16 15:20:36 -07:00
{
2008-03-27 14:22:02 +01:00
zfcp_erp_modify_adapter_status ( adapter , id , ref ,
2005-04-16 15:20:36 -07:00
ZFCP_STATUS_COMMON_ERP_FAILED , ZFCP_SET ) ;
ZFCP_LOG_NORMAL ( " adapter erp failed on adapter %s \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
}
2007-09-07 09:15:31 +02:00
/*
2005-04-16 15:20:36 -07:00
* function : zfcp_erp_port_failed
*
* purpose : sets the port and all underlying devices to ERP_FAILED
*
*/
void
2008-03-27 14:22:02 +01:00
zfcp_erp_port_failed ( struct zfcp_port * port , u8 id , u64 ref )
2005-04-16 15:20:36 -07:00
{
2008-03-27 14:22:02 +01:00
zfcp_erp_modify_port_status ( port , id , ref ,
2005-04-16 15:20:36 -07:00
ZFCP_STATUS_COMMON_ERP_FAILED , ZFCP_SET ) ;
if ( atomic_test_mask ( ZFCP_STATUS_PORT_WKA , & port - > status ) )
ZFCP_LOG_NORMAL ( " port erp failed (adapter %s, "
2007-05-08 11:14:41 +02:00
" port d_id=0x%06x) \n " ,
2005-04-16 15:20:36 -07:00
zfcp_get_busid_by_port ( port ) , port - > d_id ) ;
else
ZFCP_LOG_NORMAL ( " port erp failed (adapter %s, wwpn=0x%016Lx) \n " ,
zfcp_get_busid_by_port ( port ) , port - > wwpn ) ;
}
2007-09-07 09:15:31 +02:00
/*
2005-04-16 15:20:36 -07:00
* function : zfcp_erp_unit_failed
*
* purpose : sets the unit to ERP_FAILED
*
*/
void
2008-03-27 14:22:02 +01:00
zfcp_erp_unit_failed ( struct zfcp_unit * unit , u8 id , u64 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 ,
2005-04-16 15:20:36 -07:00
ZFCP_STATUS_COMMON_ERP_FAILED , ZFCP_SET ) ;
ZFCP_LOG_NORMAL ( " unit erp failed on unit 0x%016Lx on port 0x%016Lx "
" on adapter %s \n " , unit - > fcp_lun ,
unit - > port - > wwpn , zfcp_get_busid_by_unit ( unit ) ) ;
}
/*
* function : zfcp_erp_strategy_check_target
*
* purpose : increments the erp action count on the device currently in
* recovery if the action failed or resets the count in case of
* success . If a maximum count is exceeded the device is marked
* as ERP_FAILED .
* The ' blocked ' state of a target which has been recovered
* successfully is reset .
*
* returns : ZFCP_ERP_CONTINUES - action continues ( not considered )
2007-09-07 09:15:31 +02:00
* ZFCP_ERP_SUCCEEDED - action finished successfully
2005-04-16 15:20:36 -07:00
* ZFCP_ERP_EXIT - action failed and will not continue
*/
static int
zfcp_erp_strategy_check_target ( struct zfcp_erp_action * erp_action , int result )
{
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 ;
}
static int
zfcp_erp_strategy_statechange ( int action ,
u32 status ,
struct zfcp_adapter * adapter ,
struct zfcp_port * port ,
struct zfcp_unit * unit , int retval )
{
switch ( action ) {
case ZFCP_ERP_ACTION_REOPEN_ADAPTER :
if ( zfcp_erp_strategy_statechange_detected ( & adapter - > status ,
status ) ) {
2008-03-27 14:22:03 +01:00
zfcp_erp_adapter_reopen_internal ( adapter ,
ZFCP_STATUS_COMMON_ERP_FAILED ,
67 , 0 ) ;
2005-04-16 15:20:36 -07:00
retval = ZFCP_ERP_EXIT ;
}
break ;
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED :
case ZFCP_ERP_ACTION_REOPEN_PORT :
if ( zfcp_erp_strategy_statechange_detected ( & port - > status ,
status ) ) {
2008-03-27 14:22:03 +01:00
zfcp_erp_port_reopen_internal ( port ,
ZFCP_STATUS_COMMON_ERP_FAILED ,
68 , 0 ) ;
2005-04-16 15:20:36 -07:00
retval = ZFCP_ERP_EXIT ;
}
break ;
case ZFCP_ERP_ACTION_REOPEN_UNIT :
if ( zfcp_erp_strategy_statechange_detected ( & unit - > status ,
status ) ) {
2008-03-27 14:22:03 +01:00
zfcp_erp_unit_reopen_internal ( unit ,
ZFCP_STATUS_COMMON_ERP_FAILED ,
69 , 0 ) ;
2005-04-16 15:20:36 -07:00
retval = ZFCP_ERP_EXIT ;
}
break ;
}
return retval ;
}
2007-10-12 16:11:35 +02:00
static int
2005-04-16 15:20:36 -07:00
zfcp_erp_strategy_statechange_detected ( atomic_t * target_status , u32 erp_status )
{
return
/* take it online */
( atomic_test_mask ( ZFCP_STATUS_COMMON_RUNNING , target_status ) & &
( ZFCP_STATUS_ERP_CLOSE_ONLY & erp_status ) ) | |
/* take it offline */
( ! atomic_test_mask ( ZFCP_STATUS_COMMON_RUNNING , target_status ) & &
! ( ZFCP_STATUS_ERP_CLOSE_ONLY & erp_status ) ) ;
}
static int
zfcp_erp_strategy_check_unit ( struct zfcp_unit * unit , int result )
{
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 ) ;
if ( atomic_read ( & unit - > erp_counter ) > ZFCP_MAX_ERPS )
2008-03-27 14:22:02 +01:00
zfcp_erp_unit_failed ( unit , 21 , 0 ) ;
2005-04-16 15:20:36 -07:00
break ;
case ZFCP_ERP_EXIT :
/* nothing */
break ;
}
if ( atomic_test_mask ( ZFCP_STATUS_COMMON_ERP_FAILED , & unit - > status ) ) {
zfcp_erp_unit_block ( unit , 0 ) ; /* for ZFCP_ERP_SUCCEEDED */
result = ZFCP_ERP_EXIT ;
}
return result ;
}
static int
zfcp_erp_strategy_check_port ( struct zfcp_port * port , int result )
{
switch ( result ) {
case ZFCP_ERP_SUCCEEDED :
atomic_set ( & port - > erp_counter , 0 ) ;
zfcp_erp_port_unblock ( port ) ;
break ;
case ZFCP_ERP_FAILED :
atomic_inc ( & port - > erp_counter ) ;
if ( atomic_read ( & port - > erp_counter ) > ZFCP_MAX_ERPS )
2008-03-27 14:22:02 +01:00
zfcp_erp_port_failed ( port , 22 , 0 ) ;
2005-04-16 15:20:36 -07:00
break ;
case ZFCP_ERP_EXIT :
/* nothing */
break ;
}
if ( atomic_test_mask ( ZFCP_STATUS_COMMON_ERP_FAILED , & port - > status ) ) {
zfcp_erp_port_block ( port , 0 ) ; /* for ZFCP_ERP_SUCCEEDED */
result = ZFCP_ERP_EXIT ;
}
return result ;
}
static int
zfcp_erp_strategy_check_adapter ( struct zfcp_adapter * adapter , int result )
{
switch ( result ) {
case ZFCP_ERP_SUCCEEDED :
atomic_set ( & adapter - > erp_counter , 0 ) ;
zfcp_erp_adapter_unblock ( adapter ) ;
break ;
case ZFCP_ERP_FAILED :
atomic_inc ( & adapter - > erp_counter ) ;
if ( atomic_read ( & adapter - > erp_counter ) > ZFCP_MAX_ERPS )
2008-03-27 14:22:02 +01:00
zfcp_erp_adapter_failed ( adapter , 23 , 0 ) ;
2005-04-16 15:20:36 -07:00
break ;
case ZFCP_ERP_EXIT :
/* nothing */
break ;
}
if ( atomic_test_mask ( ZFCP_STATUS_COMMON_ERP_FAILED , & adapter - > status ) ) {
zfcp_erp_adapter_block ( adapter , 0 ) ; /* for ZFCP_ERP_SUCCEEDED */
result = ZFCP_ERP_EXIT ;
}
return result ;
}
2007-05-08 11:16:52 +02:00
struct zfcp_erp_add_work {
struct zfcp_unit * unit ;
struct work_struct work ;
} ;
/**
* zfcp_erp_scsi_scan
* @ data : pointer to a struct zfcp_erp_add_work
*
* Registers a logical unit with the SCSI stack .
*/
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 ,
unit - > scsi_lun , 0 ) ;
atomic_clear_mask ( ZFCP_STATUS_UNIT_SCSI_WORK_PENDING , & unit - > status ) ;
zfcp_unit_put ( unit ) ;
kfree ( p ) ;
}
/**
* zfcp_erp_schedule_work
* @ unit : pointer to unit which should be registered with SCSI stack
*
* Schedules work which registers a unit with the SCSI stack
*/
static void
zfcp_erp_schedule_work ( struct zfcp_unit * unit )
{
struct zfcp_erp_add_work * p ;
2007-07-18 10:55:08 +02:00
p = kzalloc ( sizeof ( * p ) , GFP_KERNEL ) ;
2007-05-08 11:16:52 +02:00
if ( ! p ) {
ZFCP_LOG_NORMAL ( " error: Out of resources. Could not register "
" the FCP-LUN 0x%Lx connected to "
" the port with WWPN 0x%Lx connected to "
" the adapter %s with the SCSI stack. \n " ,
unit - > fcp_lun ,
unit - > port - > wwpn ,
zfcp_get_busid_by_unit ( unit ) ) ;
return ;
}
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 ;
schedule_work ( & p - > work ) ;
}
2005-04-16 15:20:36 -07:00
/*
2007-09-07 09:15:31 +02:00
* function :
2005-04-16 15:20:36 -07:00
*
* purpose : remaining things in good cases ,
* escalation in bad cases
*
* returns :
*/
static int
zfcp_erp_strategy_followup_actions ( int action ,
struct zfcp_adapter * adapter ,
struct zfcp_port * port ,
struct zfcp_unit * unit , int status )
{
/* initiate follow-up actions depending on success of finished action */
switch ( action ) {
case ZFCP_ERP_ACTION_REOPEN_ADAPTER :
if ( status = = ZFCP_ERP_SUCCEEDED )
2008-03-27 14:22:03 +01:00
zfcp_erp_port_reopen_all_internal ( adapter , 0 , 70 , 0 ) ;
2005-04-16 15:20:36 -07:00
else
2008-03-27 14:22:03 +01:00
zfcp_erp_adapter_reopen_internal ( adapter , 0 , 71 , 0 ) ;
2005-04-16 15:20:36 -07:00
break ;
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED :
if ( status = = ZFCP_ERP_SUCCEEDED )
2008-03-27 14:22:03 +01:00
zfcp_erp_port_reopen_internal ( port , 0 , 72 , 0 ) ;
2005-04-16 15:20:36 -07:00
else
2008-03-27 14:22:03 +01:00
zfcp_erp_adapter_reopen_internal ( adapter , 0 , 73 , 0 ) ;
2005-04-16 15:20:36 -07:00
break ;
case ZFCP_ERP_ACTION_REOPEN_PORT :
if ( status = = ZFCP_ERP_SUCCEEDED )
2008-03-27 14:22:03 +01:00
zfcp_erp_unit_reopen_all_internal ( port , 0 , 74 , 0 ) ;
2005-04-16 15:20:36 -07:00
else
2008-03-27 14:22:03 +01:00
zfcp_erp_port_forced_reopen_internal ( port , 0 , 75 , 0 ) ;
2005-04-16 15:20:36 -07:00
break ;
case ZFCP_ERP_ACTION_REOPEN_UNIT :
2007-08-28 09:30:42 +02:00
/* Nothing to do if status == ZFCP_ERP_SUCCEEDED */
if ( status ! = ZFCP_ERP_SUCCEEDED )
2008-03-27 14:22:03 +01:00
zfcp_erp_port_reopen_internal ( unit - > port , 0 , 76 , 0 ) ;
2005-04-16 15:20:36 -07:00
break ;
}
return 0 ;
}
static int
zfcp_erp_strategy_check_queues ( struct zfcp_adapter * adapter )
{
unsigned long flags ;
read_lock_irqsave ( & zfcp_data . config_lock , flags ) ;
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 ) ;
2008-03-27 14:22:05 +01:00
}
2005-04-16 15:20:36 -07:00
read_unlock ( & adapter - > erp_lock ) ;
read_unlock_irqrestore ( & zfcp_data . config_lock , flags ) ;
return 0 ;
}
/**
* zfcp_erp_wait - wait for completion of error recovery on an adapter
* @ adapter : adapter for which to wait for completion of its error recovery
* Return : 0
*/
int
zfcp_erp_wait ( struct zfcp_adapter * adapter )
{
int retval = 0 ;
wait_event ( adapter - > erp_done_wqh ,
! atomic_test_mask ( ZFCP_STATUS_ADAPTER_ERP_PENDING ,
& adapter - > status ) ) ;
return retval ;
}
2008-03-27 14:22:02 +01:00
void zfcp_erp_modify_adapter_status ( struct zfcp_adapter * adapter , u8 id ,
u64 ref , u32 mask , int set_or_clear )
2005-04-16 15:20:36 -07:00
{
struct zfcp_port * port ;
2008-03-27 14:22:02 +01:00
u32 changed , common_mask = mask & ZFCP_COMMON_FLAGS ;
2005-04-16 15:20:36 -07:00
if ( set_or_clear = = ZFCP_SET ) {
2008-03-27 14:22:02 +01:00
changed = atomic_test_and_set_mask ( mask , & adapter - > status ) ;
2005-04-16 15:20:36 -07:00
} else {
2008-03-27 14:22:02 +01:00
changed = atomic_test_and_clear_mask ( mask , & adapter - > status ) ;
2005-04-16 15:20:36 -07:00
if ( mask & ZFCP_STATUS_COMMON_ERP_FAILED )
atomic_set ( & adapter - > erp_counter , 0 ) ;
}
2008-03-27 14:22:02 +01:00
if ( changed )
zfcp_rec_dbf_event_adapter ( id , ref , adapter ) ;
2005-04-16 15:20:36 -07:00
/* Deal with all underlying devices, only pass common_mask */
if ( common_mask )
list_for_each_entry ( port , & adapter - > port_list_head , list )
2008-03-27 14:22:02 +01:00
zfcp_erp_modify_port_status ( port , id , ref , common_mask ,
set_or_clear ) ;
2005-04-16 15:20:36 -07:00
}
/*
* function : zfcp_erp_modify_port_status
*
* purpose : sets the port and all underlying devices to ERP_FAILED
*
*/
2008-03-27 14:22:02 +01:00
void zfcp_erp_modify_port_status ( struct zfcp_port * port , u8 id , u64 ref ,
u32 mask , int set_or_clear )
2005-04-16 15:20:36 -07:00
{
struct zfcp_unit * unit ;
2008-03-27 14:22:02 +01:00
u32 changed , common_mask = mask & ZFCP_COMMON_FLAGS ;
2005-04-16 15:20:36 -07:00
if ( set_or_clear = = ZFCP_SET ) {
2008-03-27 14:22:02 +01:00
changed = atomic_test_and_set_mask ( mask , & port - > status ) ;
2005-04-16 15:20:36 -07:00
} else {
2008-03-27 14:22:02 +01:00
changed = atomic_test_and_clear_mask ( mask , & port - > status ) ;
2005-04-16 15:20:36 -07:00
if ( mask & ZFCP_STATUS_COMMON_ERP_FAILED )
atomic_set ( & port - > erp_counter , 0 ) ;
}
2008-03-27 14:22:02 +01:00
if ( changed )
zfcp_rec_dbf_event_port ( id , ref , port ) ;
2005-04-16 15:20:36 -07:00
/* Modify status of all underlying devices, only pass common mask */
if ( common_mask )
list_for_each_entry ( unit , & port - > unit_list_head , list )
2008-03-27 14:22:02 +01:00
zfcp_erp_modify_unit_status ( unit , id , ref , common_mask ,
set_or_clear ) ;
2005-04-16 15:20:36 -07:00
}
/*
* function : zfcp_erp_modify_unit_status
*
* purpose : sets the unit to ERP_FAILED
*
*/
2008-03-27 14:22:02 +01:00
void zfcp_erp_modify_unit_status ( struct zfcp_unit * unit , u8 id , u64 ref ,
u32 mask , int set_or_clear )
2005-04-16 15:20:36 -07:00
{
2008-03-27 14:22:02 +01:00
u32 changed ;
2005-04-16 15:20:36 -07:00
if ( set_or_clear = = ZFCP_SET ) {
2008-03-27 14:22:02 +01:00
changed = atomic_test_and_set_mask ( mask , & unit - > status ) ;
2005-04-16 15:20:36 -07:00
} else {
2008-03-27 14:22:02 +01:00
changed = atomic_test_and_clear_mask ( mask , & unit - > status ) ;
2005-04-16 15:20:36 -07:00
if ( mask & ZFCP_STATUS_COMMON_ERP_FAILED ) {
atomic_set ( & unit - > erp_counter , 0 ) ;
}
}
2008-03-27 14:22:02 +01:00
if ( changed )
zfcp_rec_dbf_event_unit ( id , ref , unit ) ;
2005-04-16 15:20:36 -07:00
}
/*
2007-09-07 09:15:31 +02:00
* function :
2005-04-16 15:20:36 -07:00
*
* purpose : Wrappper for zfcp_erp_port_reopen_all_internal
* used to ensure the correct locking
*
2006-06-26 18:35:02 +02:00
* returns : 0 - initiated action successfully
2005-04-16 15:20:36 -07:00
* < 0 - failed to initiate action
*/
2008-03-27 14:22:03 +01:00
int zfcp_erp_port_reopen_all ( struct zfcp_adapter * adapter , int clear_mask ,
u8 id , u64 ref )
2005-04-16 15:20:36 -07:00
{
int retval ;
unsigned long flags ;
read_lock_irqsave ( & zfcp_data . config_lock , flags ) ;
write_lock ( & adapter - > erp_lock ) ;
2008-03-27 14:22:03 +01:00
retval = zfcp_erp_port_reopen_all_internal ( adapter , clear_mask , 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-03-27 14:22:03 +01:00
static int zfcp_erp_port_reopen_all_internal ( struct zfcp_adapter * adapter ,
int clear_mask , u8 id , u64 ref )
2005-04-16 15:20:36 -07:00
{
int retval = 0 ;
struct zfcp_port * port ;
list_for_each_entry ( port , & adapter - > port_list_head , list )
if ( ! atomic_test_mask ( ZFCP_STATUS_PORT_WKA , & port - > status ) )
2008-03-27 14:22:03 +01:00
zfcp_erp_port_reopen_internal ( port , clear_mask , id ,
ref ) ;
2005-04-16 15:20:36 -07:00
return retval ;
}
/*
2007-09-07 09:15:31 +02:00
* function :
2005-04-16 15:20:36 -07:00
*
2007-09-07 09:15:31 +02:00
* purpose :
2005-04-16 15:20:36 -07:00
*
* returns : FIXME
*/
2008-03-27 14:22:03 +01:00
static int zfcp_erp_unit_reopen_all_internal ( struct zfcp_port * port ,
int clear_mask , u8 id , u64 ref )
2005-04-16 15:20:36 -07:00
{
int retval = 0 ;
struct zfcp_unit * unit ;
list_for_each_entry ( unit , & port - > unit_list_head , list )
2008-03-27 14:22:03 +01:00
zfcp_erp_unit_reopen_internal ( unit , clear_mask , id , ref ) ;
2005-04-16 15:20:36 -07:00
return retval ;
}
/*
2007-09-07 09:15:31 +02:00
* function :
2005-04-16 15:20:36 -07:00
*
* purpose : this routine executes the ' Reopen Adapter ' action
* ( the entire action is processed synchronously , since
* there are no actions which might be run concurrently
* per definition )
*
* returns : ZFCP_ERP_SUCCEEDED - action finished successfully
* ZFCP_ERP_FAILED - action finished unsuccessfully
*/
static int
zfcp_erp_adapter_strategy ( struct zfcp_erp_action * erp_action )
{
int retval ;
struct zfcp_adapter * adapter = erp_action - > adapter ;
retval = zfcp_erp_adapter_strategy_close ( erp_action ) ;
if ( erp_action - > status & ZFCP_STATUS_ERP_CLOSE_ONLY )
retval = ZFCP_ERP_EXIT ;
else
retval = zfcp_erp_adapter_strategy_open ( erp_action ) ;
if ( retval = = ZFCP_ERP_FAILED ) {
ZFCP_LOG_INFO ( " Waiting to allow the adapter %s "
" to recover itself \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
2007-11-05 12:37:45 +01:00
ssleep ( ZFCP_TYPE2_RECOVERY_TIME ) ;
2005-04-16 15:20:36 -07:00
}
return retval ;
}
/*
2007-09-07 09:15:31 +02:00
* function :
2005-04-16 15:20:36 -07:00
*
2007-09-07 09:15:31 +02:00
* purpose :
2005-04-16 15:20:36 -07:00
*
* returns : ZFCP_ERP_SUCCEEDED - action finished successfully
* ZFCP_ERP_FAILED - action finished unsuccessfully
*/
static int
zfcp_erp_adapter_strategy_close ( struct zfcp_erp_action * erp_action )
{
int retval ;
atomic_set_mask ( ZFCP_STATUS_COMMON_CLOSING ,
& erp_action - > adapter - > status ) ;
retval = zfcp_erp_adapter_strategy_generic ( erp_action , 1 ) ;
atomic_clear_mask ( ZFCP_STATUS_COMMON_CLOSING ,
& erp_action - > adapter - > status ) ;
return retval ;
}
/*
2007-09-07 09:15:31 +02:00
* function :
2005-04-16 15:20:36 -07:00
*
2007-09-07 09:15:31 +02:00
* purpose :
2005-04-16 15:20:36 -07:00
*
* returns : ZFCP_ERP_SUCCEEDED - action finished successfully
* ZFCP_ERP_FAILED - action finished unsuccessfully
*/
static int
zfcp_erp_adapter_strategy_open ( struct zfcp_erp_action * erp_action )
{
int retval ;
atomic_set_mask ( ZFCP_STATUS_COMMON_OPENING ,
& erp_action - > adapter - > status ) ;
retval = zfcp_erp_adapter_strategy_generic ( erp_action , 0 ) ;
atomic_clear_mask ( ZFCP_STATUS_COMMON_OPENING ,
& erp_action - > adapter - > status ) ;
return retval ;
}
/*
* function : zfcp_register_adapter
*
* purpose : allocate the irq associated with this devno and register
* the FSF adapter with the SCSI stack
*
2007-09-07 09:15:31 +02:00
* returns :
2005-04-16 15:20:36 -07:00
*/
static int
zfcp_erp_adapter_strategy_generic ( struct zfcp_erp_action * erp_action , int close )
{
int retval = ZFCP_ERP_SUCCEEDED ;
if ( close )
goto close_only ;
retval = zfcp_erp_adapter_strategy_open_qdio ( erp_action ) ;
if ( retval ! = ZFCP_ERP_SUCCEEDED )
goto failed_qdio ;
retval = zfcp_erp_adapter_strategy_open_fsf ( erp_action ) ;
if ( retval ! = ZFCP_ERP_SUCCEEDED )
goto failed_openfcp ;
atomic_set_mask ( ZFCP_STATUS_COMMON_OPEN , & erp_action - > adapter - > status ) ;
goto out ;
close_only :
atomic_clear_mask ( ZFCP_STATUS_COMMON_OPEN ,
& erp_action - > adapter - > status ) ;
failed_openfcp :
2006-09-18 22:29:56 +02:00
zfcp_close_fsf ( erp_action - > adapter ) ;
2005-04-16 15:20:36 -07:00
failed_qdio :
2007-05-29 15:29:49 +02:00
atomic_clear_mask ( ZFCP_STATUS_ADAPTER_XCONFIG_OK |
ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
ZFCP_STATUS_ADAPTER_XPORT_OK ,
& erp_action - > adapter - > status ) ;
2005-04-16 15:20:36 -07:00
out :
return retval ;
}
/*
* function : zfcp_qdio_init
*
* purpose : setup QDIO operation for specified adapter
*
* returns : 0 - successful setup
* ! 0 - failed setup
*/
2007-10-12 16:11:35 +02:00
static int
2005-04-16 15:20:36 -07:00
zfcp_erp_adapter_strategy_open_qdio ( struct zfcp_erp_action * erp_action )
{
int retval ;
int i ;
volatile struct qdio_buffer_element * sbale ;
struct zfcp_adapter * adapter = erp_action - > adapter ;
if ( atomic_test_mask ( ZFCP_STATUS_ADAPTER_QDIOUP , & adapter - > status ) ) {
ZFCP_LOG_NORMAL ( " bug: second attempt to set up QDIO on "
" adapter %s \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
goto failed_sanity ;
}
if ( qdio_establish ( & adapter - > qdio_init_data ) ! = 0 ) {
ZFCP_LOG_INFO ( " error: establishment of QDIO queues failed "
" on adapter %s \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
goto failed_qdio_establish ;
}
if ( qdio_activate ( adapter - > ccw_device , 0 ) ! = 0 ) {
ZFCP_LOG_INFO ( " error: activation of QDIO queues failed "
" on adapter %s \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
goto failed_qdio_activate ;
}
/*
* put buffers into response queue ,
*/
for ( i = 0 ; i < QDIO_MAX_BUFFERS_PER_Q ; i + + ) {
sbale = & ( adapter - > response_queue . buffer [ i ] - > element [ 0 ] ) ;
sbale - > length = 0 ;
sbale - > flags = SBAL_FLAGS_LAST_ENTRY ;
2006-10-10 22:44:27 +01:00
sbale - > addr = NULL ;
2005-04-16 15:20:36 -07:00
}
ZFCP_LOG_TRACE ( " calling do_QDIO on adapter %s (flags=0x%x, "
" queue_no=%i, index_in_queue=%i, count=%i) \n " ,
zfcp_get_busid_by_adapter ( adapter ) ,
QDIO_FLAG_SYNC_INPUT , 0 , 0 , QDIO_MAX_BUFFERS_PER_Q ) ;
retval = do_QDIO ( adapter - > ccw_device ,
QDIO_FLAG_SYNC_INPUT ,
0 , 0 , QDIO_MAX_BUFFERS_PER_Q , NULL ) ;
if ( retval ) {
ZFCP_LOG_NORMAL ( " bug: setup of QDIO failed (retval=%d) \n " ,
retval ) ;
goto failed_do_qdio ;
} else {
adapter - > response_queue . free_index = 0 ;
atomic_set ( & adapter - > response_queue . free_count , 0 ) ;
ZFCP_LOG_DEBUG ( " %i buffers successfully enqueued to "
" response queue \n " , QDIO_MAX_BUFFERS_PER_Q ) ;
}
/* set index of first avalable SBALS / number of available SBALS */
adapter - > request_queue . free_index = 0 ;
atomic_set ( & adapter - > request_queue . free_count , QDIO_MAX_BUFFERS_PER_Q ) ;
adapter - > request_queue . distance_from_int = 0 ;
/* initialize waitqueue used to wait for free SBALs in requests queue */
init_waitqueue_head ( & adapter - > request_wq ) ;
/* ok, we did it - skip all cleanups for different failures */
atomic_set_mask ( ZFCP_STATUS_ADAPTER_QDIOUP , & adapter - > status ) ;
retval = ZFCP_ERP_SUCCEEDED ;
goto out ;
failed_do_qdio :
/* NOP */
failed_qdio_activate :
while ( qdio_shutdown ( adapter - > ccw_device ,
QDIO_FLAG_CLEANUP_USING_CLEAR ) = = - EINPROGRESS )
2007-11-05 12:37:45 +01:00
ssleep ( 1 ) ;
2005-04-16 15:20:36 -07:00
failed_qdio_establish :
failed_sanity :
retval = ZFCP_ERP_FAILED ;
out :
return retval ;
}
static int
zfcp_erp_adapter_strategy_open_fsf ( struct zfcp_erp_action * erp_action )
{
2005-12-01 02:50:36 +01:00
int retval ;
2005-09-13 21:51:16 +02:00
2005-12-01 02:50:36 +01:00
retval = zfcp_erp_adapter_strategy_open_fsf_xconfig ( erp_action ) ;
if ( retval = = ZFCP_ERP_FAILED )
return ZFCP_ERP_FAILED ;
retval = zfcp_erp_adapter_strategy_open_fsf_xport ( erp_action ) ;
if ( retval = = ZFCP_ERP_FAILED )
2005-09-13 21:51:16 +02:00
return ZFCP_ERP_FAILED ;
2005-04-16 15:20:36 -07:00
2005-09-13 21:51:16 +02:00
return zfcp_erp_adapter_strategy_open_fsf_statusread ( erp_action ) ;
2005-04-16 15:20:36 -07:00
}
static int
zfcp_erp_adapter_strategy_open_fsf_xconfig ( struct zfcp_erp_action * erp_action )
{
int retval = ZFCP_ERP_SUCCEEDED ;
int retries ;
2005-06-13 13:15:15 +02:00
int sleep = ZFCP_EXCHANGE_CONFIG_DATA_FIRST_SLEEP ;
2005-04-16 15:20:36 -07:00
struct zfcp_adapter * adapter = erp_action - > adapter ;
atomic_clear_mask ( ZFCP_STATUS_ADAPTER_XCONFIG_OK , & adapter - > status ) ;
2005-06-13 13:15:15 +02:00
for ( retries = ZFCP_EXCHANGE_CONFIG_DATA_RETRIES ; retries ; retries - - ) {
2005-04-16 15:20:36 -07:00
atomic_clear_mask ( ZFCP_STATUS_ADAPTER_HOST_CON_INIT ,
& adapter - > status ) ;
ZFCP_LOG_DEBUG ( " Doing exchange config data \n " ) ;
2006-07-03 17:32:20 -07:00
write_lock_irq ( & adapter - > erp_lock ) ;
2005-04-16 15:20:36 -07:00
zfcp_erp_action_to_running ( erp_action ) ;
2006-07-03 17:32:20 -07:00
write_unlock_irq ( & adapter - > erp_lock ) ;
2005-04-16 15:20:36 -07:00
if ( zfcp_fsf_exchange_config_data ( erp_action ) ) {
retval = ZFCP_ERP_FAILED ;
ZFCP_LOG_INFO ( " error: initiation of exchange of "
" configuration data failed for "
" adapter %s \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
break ;
}
ZFCP_LOG_DEBUG ( " Xchange underway \n " ) ;
/*
* Why this works :
* Both the normal completion handler as well as the timeout
* handler will do an ' up ' when the ' exchange config data '
* request completes or times out . Thus , the signal to go on
* won ' t be lost utilizing this semaphore .
* Furthermore , this ' adapter_reopen ' action is
* guaranteed to be the only action being there ( highest action
* which prevents other actions from being created ) .
* Resulting from that , the wake signal recognized here
* _must_ be the one belonging to the ' exchange config
* data ' request .
*/
2008-03-27 14:22:01 +01:00
zfcp_rec_dbf_event_thread ( 6 , adapter , 1 ) ;
2005-04-16 15:20:36 -07:00
down ( & adapter - > erp_ready_sem ) ;
2008-03-27 14:22:01 +01:00
zfcp_rec_dbf_event_thread ( 7 , adapter , 1 ) ;
2005-04-16 15:20:36 -07:00
if ( erp_action - > status & ZFCP_STATUS_ERP_TIMEDOUT ) {
ZFCP_LOG_INFO ( " error: exchange of configuration data "
" for adapter %s timed out \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
break ;
}
2005-06-13 13:15:15 +02:00
if ( ! atomic_test_mask ( ZFCP_STATUS_ADAPTER_HOST_CON_INIT ,
& adapter - > status ) )
break ;
ZFCP_LOG_DEBUG ( " host connection still initialising... "
" waiting and retrying... \n " ) ;
/* sleep a little bit before retry */
2007-11-05 12:37:45 +01:00
ssleep ( sleep ) ;
2005-06-13 13:15:15 +02:00
sleep * = 2 ;
}
2005-04-16 15:20:36 -07:00
2007-05-29 15:29:49 +02:00
atomic_clear_mask ( ZFCP_STATUS_ADAPTER_HOST_CON_INIT ,
& adapter - > status ) ;
2005-04-16 15:20:36 -07:00
if ( ! atomic_test_mask ( ZFCP_STATUS_ADAPTER_XCONFIG_OK ,
& adapter - > status ) ) {
ZFCP_LOG_INFO ( " error: exchange of configuration data for "
" adapter %s failed \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
retval = ZFCP_ERP_FAILED ;
}
return retval ;
}
2005-09-13 21:51:16 +02:00
static int
zfcp_erp_adapter_strategy_open_fsf_xport ( struct zfcp_erp_action * erp_action )
{
2005-12-01 02:50:36 +01:00
int ret ;
2006-02-11 01:41:50 +01:00
struct zfcp_adapter * adapter ;
2005-09-13 21:51:16 +02:00
2006-02-11 01:41:50 +01:00
adapter = erp_action - > adapter ;
2005-09-13 21:51:16 +02:00
atomic_clear_mask ( ZFCP_STATUS_ADAPTER_XPORT_OK , & adapter - > status ) ;
2006-07-03 17:32:20 -07:00
write_lock_irq ( & adapter - > erp_lock ) ;
2006-02-11 01:41:50 +01:00
zfcp_erp_action_to_running ( erp_action ) ;
2006-07-03 17:32:20 -07:00
write_unlock_irq ( & adapter - > erp_lock ) ;
2005-09-13 21:51:16 +02:00
2007-08-28 09:31:09 +02:00
ret = zfcp_fsf_exchange_port_data ( erp_action ) ;
2006-02-11 01:41:50 +01:00
if ( ret = = - EOPNOTSUPP ) {
return ZFCP_ERP_SUCCEEDED ;
} else if ( ret ) {
return ZFCP_ERP_FAILED ;
}
ret = ZFCP_ERP_SUCCEEDED ;
2008-03-27 14:22:01 +01:00
zfcp_rec_dbf_event_thread ( 8 , adapter , 1 ) ;
2006-02-11 01:41:50 +01:00
down ( & adapter - > erp_ready_sem ) ;
2008-03-27 14:22:01 +01:00
zfcp_rec_dbf_event_thread ( 9 , adapter , 1 ) ;
2006-02-11 01:41:50 +01:00
if ( erp_action - > status & ZFCP_STATUS_ERP_TIMEDOUT ) {
ZFCP_LOG_INFO ( " error: exchange port data timed out (adapter "
" %s) \n " , zfcp_get_busid_by_adapter ( adapter ) ) ;
ret = ZFCP_ERP_FAILED ;
}
2006-08-02 11:05:52 +02:00
/* don't treat as error for the sake of compatibility */
if ( ! atomic_test_mask ( ZFCP_STATUS_ADAPTER_XPORT_OK , & adapter - > status ) )
ZFCP_LOG_INFO ( " warning: exchange port data failed (adapter "
2006-02-11 01:41:50 +01:00
" %s \n " , zfcp_get_busid_by_adapter ( adapter ) ) ;
2005-09-13 21:51:16 +02:00
2006-02-11 01:41:50 +01:00
return ret ;
2005-09-13 21:51:16 +02:00
}
2005-04-16 15:20:36 -07:00
static int
zfcp_erp_adapter_strategy_open_fsf_statusread ( struct zfcp_erp_action
* erp_action )
{
int retval = ZFCP_ERP_SUCCEEDED ;
int temp_ret ;
struct zfcp_adapter * adapter = erp_action - > adapter ;
int i ;
adapter - > status_read_failed = 0 ;
for ( i = 0 ; i < ZFCP_STATUS_READS_RECOM ; i + + ) {
temp_ret = zfcp_fsf_status_read ( adapter , ZFCP_WAIT_FOR_SBAL ) ;
if ( temp_ret < 0 ) {
ZFCP_LOG_INFO ( " error: set-up of unsolicited status "
" notification failed on adapter %s \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
retval = ZFCP_ERP_FAILED ;
i - - ;
break ;
}
}
return retval ;
}
/*
2007-09-07 09:15:31 +02:00
* function :
2005-04-16 15:20:36 -07:00
*
* purpose : this routine executes the ' Reopen Physical Port ' action
*
* returns : ZFCP_ERP_CONTINUES - action continues ( asynchronously )
* ZFCP_ERP_SUCCEEDED - action finished successfully
* ZFCP_ERP_FAILED - action finished unsuccessfully
*/
static int
zfcp_erp_port_forced_strategy ( struct zfcp_erp_action * erp_action )
{
int retval = ZFCP_ERP_FAILED ;
struct zfcp_port * port = erp_action - > port ;
switch ( erp_action - > step ) {
/*
* FIXME :
* the ULP spec . begs for waiting for oustanding commands
*/
case ZFCP_ERP_STEP_UNINITIALIZED :
zfcp_erp_port_strategy_clearstati ( port ) ;
/*
* it would be sufficient to test only the normal open flag
* since the phys . open flag cannot be set if the normal
* open flag is unset - however , this is for readabilty . . .
*/
if ( atomic_test_mask ( ( ZFCP_STATUS_PORT_PHYS_OPEN |
ZFCP_STATUS_COMMON_OPEN ) ,
& port - > status ) ) {
ZFCP_LOG_DEBUG ( " port 0x%016Lx is open -> trying "
" close physical \n " , port - > wwpn ) ;
retval =
zfcp_erp_port_forced_strategy_close ( erp_action ) ;
} else
retval = ZFCP_ERP_FAILED ;
break ;
case ZFCP_ERP_STEP_PHYS_PORT_CLOSING :
if ( atomic_test_mask ( ZFCP_STATUS_PORT_PHYS_OPEN ,
& port - > status ) ) {
ZFCP_LOG_DEBUG ( " close physical failed for port "
" 0x%016Lx \n " , port - > wwpn ) ;
retval = ZFCP_ERP_FAILED ;
} else
retval = ZFCP_ERP_SUCCEEDED ;
break ;
}
return retval ;
}
/*
2007-09-07 09:15:31 +02:00
* function :
2005-04-16 15:20:36 -07:00
*
* purpose : this routine executes the ' Reopen Port ' action
*
* returns : ZFCP_ERP_CONTINUES - action continues ( asynchronously )
* ZFCP_ERP_SUCCEEDED - action finished successfully
* ZFCP_ERP_FAILED - action finished unsuccessfully
*/
static int
zfcp_erp_port_strategy ( struct zfcp_erp_action * erp_action )
{
int retval = ZFCP_ERP_FAILED ;
struct zfcp_port * port = erp_action - > port ;
switch ( erp_action - > step ) {
/*
* FIXME :
* the ULP spec . begs for waiting for oustanding commands
*/
case ZFCP_ERP_STEP_UNINITIALIZED :
zfcp_erp_port_strategy_clearstati ( port ) ;
if ( atomic_test_mask ( ZFCP_STATUS_COMMON_OPEN , & port - > status ) ) {
ZFCP_LOG_DEBUG ( " port 0x%016Lx is open -> trying "
" close \n " , port - > wwpn ) ;
retval = zfcp_erp_port_strategy_close ( erp_action ) ;
goto out ;
} /* else it's already closed, open it */
break ;
case ZFCP_ERP_STEP_PORT_CLOSING :
if ( atomic_test_mask ( ZFCP_STATUS_COMMON_OPEN , & port - > status ) ) {
ZFCP_LOG_DEBUG ( " close failed for port 0x%016Lx \n " ,
port - > wwpn ) ;
retval = ZFCP_ERP_FAILED ;
goto out ;
} /* else it's closed now, open it */
break ;
}
if ( erp_action - > status & ZFCP_STATUS_ERP_CLOSE_ONLY )
retval = ZFCP_ERP_EXIT ;
else
retval = zfcp_erp_port_strategy_open ( erp_action ) ;
out :
return retval ;
}
static int
zfcp_erp_port_strategy_open ( struct zfcp_erp_action * erp_action )
{
int retval ;
if ( atomic_test_mask ( ZFCP_STATUS_PORT_WKA ,
& erp_action - > port - > status ) )
retval = zfcp_erp_port_strategy_open_nameserver ( erp_action ) ;
else
retval = zfcp_erp_port_strategy_open_common ( erp_action ) ;
return retval ;
}
static int
zfcp_erp_port_strategy_open_common ( struct zfcp_erp_action * erp_action )
{
int retval = 0 ;
struct zfcp_adapter * adapter = erp_action - > adapter ;
struct zfcp_port * port = erp_action - > port ;
switch ( erp_action - > step ) {
case ZFCP_ERP_STEP_UNINITIALIZED :
case ZFCP_ERP_STEP_PHYS_PORT_CLOSING :
case ZFCP_ERP_STEP_PORT_CLOSING :
2006-01-13 02:26:11 +01:00
if ( fc_host_port_type ( adapter - > scsi_host ) = = FC_PORTTYPE_PTP ) {
2005-04-10 23:04:28 -05:00
if ( port - > wwpn ! = adapter - > peer_wwpn ) {
ZFCP_LOG_NORMAL ( " Failed to open port 0x%016Lx "
" on adapter %s. \n Peer WWPN "
" 0x%016Lx does not match \n " ,
port - > wwpn ,
zfcp_get_busid_by_adapter ( adapter ) ,
adapter - > peer_wwpn ) ;
2008-03-27 14:22:02 +01:00
zfcp_erp_port_failed ( port , 25 , 0 ) ;
2005-04-10 23:04:28 -05:00
retval = ZFCP_ERP_FAILED ;
break ;
}
port - > d_id = adapter - > peer_d_id ;
atomic_set_mask ( ZFCP_STATUS_PORT_DID_DID , & port - > status ) ;
retval = zfcp_erp_port_strategy_open_port ( erp_action ) ;
break ;
}
2005-04-16 15:20:36 -07:00
if ( ! ( adapter - > nameserver_port ) ) {
retval = zfcp_nameserver_enqueue ( adapter ) ;
if ( retval ! = 0 ) {
ZFCP_LOG_NORMAL ( " error: nameserver port "
" unavailable for adapter %s \n " ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
retval = ZFCP_ERP_FAILED ;
break ;
}
}
if ( ! atomic_test_mask ( ZFCP_STATUS_COMMON_UNBLOCKED ,
& adapter - > nameserver_port - > status ) ) {
ZFCP_LOG_DEBUG ( " nameserver port is not open -> open "
" nameserver port \n " ) ;
/* nameserver port may live again */
atomic_set_mask ( ZFCP_STATUS_COMMON_RUNNING ,
& adapter - > nameserver_port - > status ) ;
2008-03-27 14:22:03 +01:00
if ( zfcp_erp_port_reopen ( adapter - > nameserver_port , 0 ,
77 , ( u64 ) erp_action ) > = 0 ) {
2005-04-16 15:20:36 -07:00
erp_action - > step =
ZFCP_ERP_STEP_NAMESERVER_OPEN ;
retval = ZFCP_ERP_CONTINUES ;
} else
retval = ZFCP_ERP_FAILED ;
break ;
}
/* else nameserver port is already open, fall through */
case ZFCP_ERP_STEP_NAMESERVER_OPEN :
if ( ! atomic_test_mask ( ZFCP_STATUS_COMMON_OPEN ,
& adapter - > nameserver_port - > status ) ) {
ZFCP_LOG_DEBUG ( " open failed for nameserver port \n " ) ;
retval = ZFCP_ERP_FAILED ;
} else {
ZFCP_LOG_DEBUG ( " nameserver port is open -> "
" nameserver look-up for port 0x%016Lx \n " ,
port - > wwpn ) ;
retval = zfcp_erp_port_strategy_open_common_lookup
( erp_action ) ;
}
break ;
case ZFCP_ERP_STEP_NAMESERVER_LOOKUP :
if ( ! atomic_test_mask ( ZFCP_STATUS_PORT_DID_DID , & port - > status ) ) {
if ( atomic_test_mask
( ZFCP_STATUS_PORT_INVALID_WWPN , & port - > status ) ) {
ZFCP_LOG_DEBUG ( " nameserver look-up failed "
" for port 0x%016Lx "
" (misconfigured WWPN?) \n " ,
port - > wwpn ) ;
2008-03-27 14:22:02 +01:00
zfcp_erp_port_failed ( port , 26 , 0 ) ;
2005-04-16 15:20:36 -07:00
retval = ZFCP_ERP_EXIT ;
} else {
ZFCP_LOG_DEBUG ( " nameserver look-up failed for "
" port 0x%016Lx \n " , port - > wwpn ) ;
retval = ZFCP_ERP_FAILED ;
}
} else {
2007-05-08 11:14:41 +02:00
ZFCP_LOG_DEBUG ( " port 0x%016Lx has d_id=0x%06x -> "
2005-04-16 15:20:36 -07:00
" trying open \n " , port - > wwpn , port - > d_id ) ;
retval = zfcp_erp_port_strategy_open_port ( erp_action ) ;
}
break ;
case ZFCP_ERP_STEP_PORT_OPENING :
/* D_ID might have changed during open */
if ( atomic_test_mask ( ( ZFCP_STATUS_COMMON_OPEN |
ZFCP_STATUS_PORT_DID_DID ) ,
& port - > status ) ) {
ZFCP_LOG_DEBUG ( " port 0x%016Lx is open \n " , port - > wwpn ) ;
retval = ZFCP_ERP_SUCCEEDED ;
} else {
ZFCP_LOG_DEBUG ( " open failed for port 0x%016Lx \n " ,
port - > wwpn ) ;
retval = ZFCP_ERP_FAILED ;
}
break ;
default :
ZFCP_LOG_NORMAL ( " bug: unknown erp step 0x%08x \n " ,
erp_action - > step ) ;
retval = ZFCP_ERP_FAILED ;
}
return retval ;
}
static int
zfcp_erp_port_strategy_open_nameserver ( struct zfcp_erp_action * erp_action )
{
int retval ;
struct zfcp_port * port = erp_action - > port ;
switch ( erp_action - > step ) {
case ZFCP_ERP_STEP_UNINITIALIZED :
case ZFCP_ERP_STEP_PHYS_PORT_CLOSING :
case ZFCP_ERP_STEP_PORT_CLOSING :
2007-05-08 11:14:41 +02:00
ZFCP_LOG_DEBUG ( " port 0x%016Lx has d_id=0x%06x -> trying open \n " ,
2005-04-16 15:20:36 -07:00
port - > wwpn , port - > d_id ) ;
retval = zfcp_erp_port_strategy_open_port ( erp_action ) ;
break ;
case ZFCP_ERP_STEP_PORT_OPENING :
if ( atomic_test_mask ( ZFCP_STATUS_COMMON_OPEN , & port - > status ) ) {
ZFCP_LOG_DEBUG ( " WKA port is open \n " ) ;
retval = ZFCP_ERP_SUCCEEDED ;
} else {
ZFCP_LOG_DEBUG ( " open failed for WKA port \n " ) ;
retval = ZFCP_ERP_FAILED ;
}
/* this is needed anyway (dont care for retval of wakeup) */
ZFCP_LOG_DEBUG ( " continue other open port operations \n " ) ;
zfcp_erp_port_strategy_open_nameserver_wakeup ( erp_action ) ;
break ;
default :
ZFCP_LOG_NORMAL ( " bug: unknown erp step 0x%08x \n " ,
erp_action - > step ) ;
retval = ZFCP_ERP_FAILED ;
}
return retval ;
}
/*
2007-09-07 09:15:31 +02:00
* function :
2005-04-16 15:20:36 -07:00
*
* purpose : makes the erp thread continue with reopen ( physical ) port
* actions which have been paused until the name server port
* is opened ( or failed )
*
* returns : 0 ( a kind of void retval , its not used )
*/
static int
zfcp_erp_port_strategy_open_nameserver_wakeup ( struct zfcp_erp_action
* ns_erp_action )
{
int retval = 0 ;
unsigned long flags ;
struct zfcp_adapter * adapter = ns_erp_action - > adapter ;
struct zfcp_erp_action * erp_action , * tmp ;
read_lock_irqsave ( & adapter - > erp_lock , flags ) ;
list_for_each_entry_safe ( erp_action , tmp , & adapter - > erp_running_head ,
list ) {
if ( erp_action - > step = = ZFCP_ERP_STEP_NAMESERVER_OPEN ) {
if ( atomic_test_mask (
ZFCP_STATUS_COMMON_ERP_FAILED ,
& adapter - > nameserver_port - > status ) )
2008-03-27 14:22:02 +01:00
zfcp_erp_port_failed ( erp_action - > port , 27 , 0 ) ;
2005-04-16 15:20:36 -07:00
zfcp_erp_action_ready ( erp_action ) ;
}
}
read_unlock_irqrestore ( & adapter - > erp_lock , flags ) ;
return retval ;
}
/*
2007-09-07 09:15:31 +02:00
* function :
2005-04-16 15:20:36 -07:00
*
2007-09-07 09:15:31 +02:00
* purpose :
2005-04-16 15:20:36 -07:00
*
* returns : ZFCP_ERP_CONTINUES - action continues ( asynchronously )
* ZFCP_ERP_FAILED - action finished unsuccessfully
*/
static int
zfcp_erp_port_forced_strategy_close ( struct zfcp_erp_action * erp_action )
{
int retval ;
retval = zfcp_fsf_close_physical_port ( erp_action ) ;
if ( retval = = - ENOMEM ) {
retval = ZFCP_ERP_NOMEM ;
goto out ;
}
erp_action - > step = ZFCP_ERP_STEP_PHYS_PORT_CLOSING ;
if ( retval ! = 0 ) {
/* could not send 'open', fail */
retval = ZFCP_ERP_FAILED ;
goto out ;
}
retval = ZFCP_ERP_CONTINUES ;
out :
return retval ;
}
static int
zfcp_erp_port_strategy_clearstati ( struct zfcp_port * port )
{
int retval = 0 ;
atomic_clear_mask ( ZFCP_STATUS_COMMON_OPENING |
ZFCP_STATUS_COMMON_CLOSING |
ZFCP_STATUS_COMMON_ACCESS_DENIED |
ZFCP_STATUS_PORT_DID_DID |
ZFCP_STATUS_PORT_PHYS_CLOSING |
ZFCP_STATUS_PORT_INVALID_WWPN ,
& port - > status ) ;
return retval ;
}
/*
2007-09-07 09:15:31 +02:00
* function :
2005-04-16 15:20:36 -07:00
*
2007-09-07 09:15:31 +02:00
* purpose :
2005-04-16 15:20:36 -07:00
*
* returns : ZFCP_ERP_CONTINUES - action continues ( asynchronously )
* ZFCP_ERP_FAILED - action finished unsuccessfully
*/
static int
zfcp_erp_port_strategy_close ( struct zfcp_erp_action * erp_action )
{
int retval ;
retval = zfcp_fsf_close_port ( erp_action ) ;
if ( retval = = - ENOMEM ) {
retval = ZFCP_ERP_NOMEM ;
goto out ;
}
erp_action - > step = ZFCP_ERP_STEP_PORT_CLOSING ;
if ( retval ! = 0 ) {
/* could not send 'close', fail */
retval = ZFCP_ERP_FAILED ;
goto out ;
}
retval = ZFCP_ERP_CONTINUES ;
out :
return retval ;
}
/*
2007-09-07 09:15:31 +02:00
* function :
2005-04-16 15:20:36 -07:00
*
2007-09-07 09:15:31 +02:00
* purpose :
2005-04-16 15:20:36 -07:00
*
* returns : ZFCP_ERP_CONTINUES - action continues ( asynchronously )
* ZFCP_ERP_FAILED - action finished unsuccessfully
*/
static int
zfcp_erp_port_strategy_open_port ( struct zfcp_erp_action * erp_action )
{
int retval ;
retval = zfcp_fsf_open_port ( erp_action ) ;
if ( retval = = - ENOMEM ) {
retval = ZFCP_ERP_NOMEM ;
goto out ;
}
erp_action - > step = ZFCP_ERP_STEP_PORT_OPENING ;
if ( retval ! = 0 ) {
/* could not send 'open', fail */
retval = ZFCP_ERP_FAILED ;
goto out ;
}
retval = ZFCP_ERP_CONTINUES ;
out :
return retval ;
}
/*
2007-09-07 09:15:31 +02:00
* function :
2005-04-16 15:20:36 -07:00
*
2007-09-07 09:15:31 +02:00
* purpose :
2005-04-16 15:20:36 -07:00
*
* returns : ZFCP_ERP_CONTINUES - action continues ( asynchronously )
* ZFCP_ERP_FAILED - action finished unsuccessfully
*/
static int
zfcp_erp_port_strategy_open_common_lookup ( struct zfcp_erp_action * erp_action )
{
int retval ;
retval = zfcp_ns_gid_pn_request ( erp_action ) ;
if ( retval = = - ENOMEM ) {
retval = ZFCP_ERP_NOMEM ;
goto out ;
}
erp_action - > step = ZFCP_ERP_STEP_NAMESERVER_LOOKUP ;
if ( retval ! = 0 ) {
/* could not send nameserver request, fail */
retval = ZFCP_ERP_FAILED ;
goto out ;
}
retval = ZFCP_ERP_CONTINUES ;
out :
return retval ;
}
/*
2007-09-07 09:15:31 +02:00
* function :
2005-04-16 15:20:36 -07:00
*
* purpose : this routine executes the ' Reopen Unit ' action
* currently no retries
*
* returns : ZFCP_ERP_CONTINUES - action continues ( asynchronously )
* ZFCP_ERP_SUCCEEDED - action finished successfully
* ZFCP_ERP_FAILED - action finished unsuccessfully
*/
static int
zfcp_erp_unit_strategy ( struct zfcp_erp_action * erp_action )
{
int retval = ZFCP_ERP_FAILED ;
struct zfcp_unit * unit = erp_action - > unit ;
switch ( erp_action - > step ) {
/*
* FIXME :
* the ULP spec . begs for waiting for oustanding commands
*/
case ZFCP_ERP_STEP_UNINITIALIZED :
zfcp_erp_unit_strategy_clearstati ( unit ) ;
if ( atomic_test_mask ( ZFCP_STATUS_COMMON_OPEN , & unit - > status ) ) {
ZFCP_LOG_DEBUG ( " unit 0x%016Lx is open -> "
" trying close \n " , unit - > fcp_lun ) ;
retval = zfcp_erp_unit_strategy_close ( erp_action ) ;
break ;
}
/* else it's already closed, fall through */
case ZFCP_ERP_STEP_UNIT_CLOSING :
if ( atomic_test_mask ( ZFCP_STATUS_COMMON_OPEN , & unit - > status ) ) {
ZFCP_LOG_DEBUG ( " close failed for unit 0x%016Lx \n " ,
unit - > fcp_lun ) ;
retval = ZFCP_ERP_FAILED ;
} else {
if ( erp_action - > status & ZFCP_STATUS_ERP_CLOSE_ONLY )
retval = ZFCP_ERP_EXIT ;
else {
ZFCP_LOG_DEBUG ( " unit 0x%016Lx is not open -> "
" trying open \n " , unit - > fcp_lun ) ;
retval =
zfcp_erp_unit_strategy_open ( erp_action ) ;
}
}
break ;
case ZFCP_ERP_STEP_UNIT_OPENING :
if ( atomic_test_mask ( ZFCP_STATUS_COMMON_OPEN , & unit - > status ) ) {
ZFCP_LOG_DEBUG ( " unit 0x%016Lx is open \n " ,
unit - > fcp_lun ) ;
retval = ZFCP_ERP_SUCCEEDED ;
} else {
ZFCP_LOG_DEBUG ( " open failed for unit 0x%016Lx \n " ,
unit - > fcp_lun ) ;
retval = ZFCP_ERP_FAILED ;
}
break ;
}
return retval ;
}
static int
zfcp_erp_unit_strategy_clearstati ( struct zfcp_unit * unit )
{
int retval = 0 ;
atomic_clear_mask ( ZFCP_STATUS_COMMON_OPENING |
ZFCP_STATUS_COMMON_CLOSING |
ZFCP_STATUS_COMMON_ACCESS_DENIED |
ZFCP_STATUS_UNIT_SHARED |
ZFCP_STATUS_UNIT_READONLY ,
& unit - > status ) ;
return retval ;
}
/*
2007-09-07 09:15:31 +02:00
* function :
2005-04-16 15:20:36 -07:00
*
2007-09-07 09:15:31 +02:00
* purpose :
2005-04-16 15:20:36 -07:00
*
* returns : ZFCP_ERP_CONTINUES - action continues ( asynchronously )
* ZFCP_ERP_FAILED - action finished unsuccessfully
*/
static int
zfcp_erp_unit_strategy_close ( struct zfcp_erp_action * erp_action )
{
int retval ;
retval = zfcp_fsf_close_unit ( erp_action ) ;
if ( retval = = - ENOMEM ) {
retval = ZFCP_ERP_NOMEM ;
goto out ;
}
erp_action - > step = ZFCP_ERP_STEP_UNIT_CLOSING ;
if ( retval ! = 0 ) {
/* could not send 'close', fail */
retval = ZFCP_ERP_FAILED ;
goto out ;
}
retval = ZFCP_ERP_CONTINUES ;
out :
return retval ;
}
/*
2007-09-07 09:15:31 +02:00
* function :
2005-04-16 15:20:36 -07:00
*
2007-09-07 09:15:31 +02:00
* purpose :
2005-04-16 15:20:36 -07:00
*
* returns : ZFCP_ERP_CONTINUES - action continues ( asynchronously )
* ZFCP_ERP_FAILED - action finished unsuccessfully
*/
static int
zfcp_erp_unit_strategy_open ( struct zfcp_erp_action * erp_action )
{
int retval ;
retval = zfcp_fsf_open_unit ( erp_action ) ;
if ( retval = = - ENOMEM ) {
retval = ZFCP_ERP_NOMEM ;
goto out ;
}
erp_action - > step = ZFCP_ERP_STEP_UNIT_OPENING ;
if ( retval ! = 0 ) {
/* could not send 'open', fail */
retval = ZFCP_ERP_FAILED ;
goto out ;
}
retval = ZFCP_ERP_CONTINUES ;
out :
return retval ;
}
2006-09-18 22:29:56 +02:00
void zfcp_erp_start_timer ( struct zfcp_fsf_req * fsf_req )
2005-04-16 15:20:36 -07:00
{
2006-09-18 22:29:56 +02:00
BUG_ON ( ! fsf_req - > erp_action ) ;
fsf_req - > timer . function = zfcp_erp_timeout_handler ;
fsf_req - > timer . data = ( unsigned long ) fsf_req - > erp_action ;
fsf_req - > timer . expires = jiffies + ZFCP_ERP_FSFREQ_TIMEOUT ;
add_timer ( & fsf_req - > timer ) ;
2005-04-16 15:20:36 -07:00
}
/*
2007-09-07 09:15:31 +02:00
* function :
2005-04-16 15:20:36 -07:00
*
* purpose : enqueue the specified error recovery action , if needed
*
* returns :
*/
2008-03-27 14:22:03 +01:00
static int zfcp_erp_action_enqueue ( int want , struct zfcp_adapter * adapter ,
struct zfcp_port * port ,
struct zfcp_unit * unit , u8 id , u64 ref )
2005-04-16 15:20:36 -07:00
{
2008-03-27 14:22:03 +01:00
int retval = 1 , need = want ;
2005-04-16 15:20:36 -07:00
struct zfcp_erp_action * erp_action = NULL ;
u32 status = 0 ;
/*
* We need some rules here which check whether we really need
* this action or whether we should just drop it .
* E . g . if there is a unfinished ' Reopen Port ' request then we drop a
* ' Reopen Unit ' request for an associated unit since we can ' t
* satisfy this request now . A ' Reopen Port ' action will trigger
* ' Reopen Unit ' actions when it completes .
* Thus , there are only actions in the queue which can immediately be
* executed . This makes the processing of the action queue more
* efficient .
*/
if ( ! atomic_test_mask ( ZFCP_STATUS_ADAPTER_ERP_THREAD_UP ,
& adapter - > status ) )
return - EIO ;
/* check whether we really need this */
2008-03-27 14:22:03 +01:00
switch ( want ) {
2005-04-16 15:20:36 -07:00
case ZFCP_ERP_ACTION_REOPEN_UNIT :
if ( atomic_test_mask
( ZFCP_STATUS_COMMON_ERP_INUSE , & unit - > status ) ) {
goto out ;
}
if ( ! atomic_test_mask
( ZFCP_STATUS_COMMON_RUNNING , & port - > status ) | |
atomic_test_mask
( ZFCP_STATUS_COMMON_ERP_FAILED , & port - > status ) ) {
goto out ;
}
if ( ! atomic_test_mask
2008-03-27 14:22:03 +01:00
( ZFCP_STATUS_COMMON_UNBLOCKED , & port - > status ) )
need = ZFCP_ERP_ACTION_REOPEN_PORT ;
2005-04-16 15:20:36 -07:00
/* fall through !!! */
case ZFCP_ERP_ACTION_REOPEN_PORT :
if ( atomic_test_mask
( ZFCP_STATUS_COMMON_ERP_INUSE , & port - > status ) ) {
goto out ;
}
/* fall through !!! */
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED :
2005-09-13 21:47:11 +02:00
if ( atomic_test_mask ( ZFCP_STATUS_COMMON_ERP_INUSE ,
& port - > status ) ) {
if ( port - > erp_action . action ! =
ZFCP_ERP_ACTION_REOPEN_PORT_FORCED ) {
ZFCP_LOG_INFO ( " dropped erp action %i (port "
" 0x%016Lx, action in use: %i) \n " ,
2008-03-27 14:22:03 +01:00
want , port - > wwpn ,
2005-09-13 21:47:11 +02:00
port - > erp_action . action ) ;
2008-03-27 14:22:05 +01:00
}
2005-04-16 15:20:36 -07:00
goto out ;
}
if ( ! atomic_test_mask
( ZFCP_STATUS_COMMON_RUNNING , & adapter - > status ) | |
atomic_test_mask
( ZFCP_STATUS_COMMON_ERP_FAILED , & adapter - > status ) ) {
goto out ;
}
if ( ! atomic_test_mask
2008-03-27 14:22:03 +01:00
( ZFCP_STATUS_COMMON_UNBLOCKED , & adapter - > status ) )
need = ZFCP_ERP_ACTION_REOPEN_ADAPTER ;
2005-04-16 15:20:36 -07:00
/* fall through !!! */
case ZFCP_ERP_ACTION_REOPEN_ADAPTER :
if ( atomic_test_mask
( ZFCP_STATUS_COMMON_ERP_INUSE , & adapter - > status ) ) {
goto out ;
}
break ;
default :
ZFCP_LOG_NORMAL ( " bug: unknown erp action requested "
" on adapter %s (action=%d) \n " ,
2008-03-27 14:22:03 +01:00
zfcp_get_busid_by_adapter ( adapter ) , want ) ;
2005-04-16 15:20:36 -07:00
goto out ;
}
/* check whether we need something stronger first */
2008-03-27 14:22:03 +01:00
if ( need ) {
2005-04-16 15:20:36 -07:00
ZFCP_LOG_DEBUG ( " stronger erp action %d needed before "
" erp action %d on adapter %s \n " ,
2008-03-27 14:22:03 +01:00
need , want , zfcp_get_busid_by_adapter ( adapter ) ) ;
2005-04-16 15:20:36 -07:00
}
/* mark adapter to have some error recovery pending */
atomic_set_mask ( ZFCP_STATUS_ADAPTER_ERP_PENDING , & adapter - > status ) ;
/* setup error recovery action */
2008-03-27 14:22:03 +01:00
switch ( need ) {
2005-04-16 15:20:36 -07:00
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_test_mask
( ZFCP_STATUS_COMMON_RUNNING , & unit - > status ) )
status = ZFCP_STATUS_ERP_CLOSE_ONLY ;
break ;
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_test_mask
( ZFCP_STATUS_COMMON_RUNNING , & port - > status ) )
status = ZFCP_STATUS_ERP_CLOSE_ONLY ;
break ;
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_test_mask
( ZFCP_STATUS_COMMON_RUNNING , & adapter - > status ) )
status = ZFCP_STATUS_ERP_CLOSE_ONLY ;
break ;
}
memset ( erp_action , 0 , sizeof ( struct zfcp_erp_action ) ) ;
erp_action - > adapter = adapter ;
erp_action - > port = port ;
erp_action - > unit = unit ;
2008-03-27 14:22:03 +01:00
erp_action - > action = need ;
2005-04-16 15:20:36 -07:00
erp_action - > status = status ;
+ + adapter - > erp_total_count ;
/* finally put it into 'ready' queue and kick erp thread */
[SCSI] zfcp: fix cleanup of dismissed error recovery actions
Calling zfcp_erp_strategy_check_action() after zfcp_erp_action_to_running()
in zfcp_erp_strategy() might cause an unbalanced up() for erp_ready_sem,
which makes the zfcp recovery fail somewhere along the way:
erp thread processing erp_action:
|
| someone waking up erp thread for erp_action
| |
| | someone else dismissing erp_action:
| | |
V V V
write_lock_irqsave(&adapter->erp_lock, flags);
...
if (zfcp_erp_action_exists(erp_action) == ZFCP_ERP_ACTION_RUNNING) {
zfcp_erp_action_to_ready(erp_action);
up(&adapter->erp_ready_sem); /* first up() for erp_action */
}
write_unlock_irqrestore(&adapter->erp_lock, flags);
write_lock_irqsave(&adapter->erp_lock, flags);
...
zfcp_erp_action_to_running(erp_action);
write_unlock_restore(&adapter->erp_lock, flags);
/* processing erp_action */
write_lock_irqsave(&adapter->erp_lock, flags);
...
erp_action->status |= ZFCP_STATUS_ERP_DISMISSED;
if (zfcp_erp_action_exists(erp_action) ==
ZFCP_ERP_ACTION_RUNNING) {
zfcp_erp_action_to_ready(erp_action);
up(&adapter->erp_ready_sem);
/* second, unbalanced up() for erp_action */
}
...
write_unlock_restore(&adapter->erp_lock, flags);
write_lock_irqsave(&adapter->erp_lock, flags);
if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) {
zfcp_erp_action_dequeue(erp_action);
retval = ZFCP_ERP_DISMISSED;
}
...
write_unlock_restore(&adapter->erp_lock, flags);
down(&adapter->erp_ready_sem);
/* this down() is meant to balance the first up() */
The erp thread must not dismiss an erp_action after moving that action to
erp_running_head. Instead it should just go through the down() operation,
which balances the first up(), and run through zfcp_erp_strategy one more
time for the second up(), which eventually cleans up erp_action. Which
is similar to the normal processing of an event for erp_action doing
something asynchronously (e.g. waiting for the completion of an fsf_req).
This only works if we make sure that a dismissed erp_action is passed to
zfcp_erp_strategy() prior to the other action, which caused actions to be
dismissed. Therefore the patch implements this rule: running actions go to
the head of the ready list; new actions go to the tail of the ready list;
the erp thread picks actions to be processed from the ready list's head.
Signed-off-by: Martin Peschke <mp3@de.ibm.com>
Acked-by: Swen Schillig <swen@vnet.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
2007-11-15 13:57:17 +01:00
list_add_tail ( & erp_action - > list , & adapter - > erp_ready_head ) ;
2005-04-16 15:20:36 -07:00
up ( & adapter - > erp_ready_sem ) ;
2008-03-27 14:22:01 +01:00
zfcp_rec_dbf_event_thread ( 1 , adapter , 0 ) ;
2005-04-16 15:20:36 -07:00
retval = 0 ;
out :
2008-03-27 14:22:03 +01:00
zfcp_rec_dbf_event_trigger ( id , ref , want , need , ( u64 ) erp_action ,
adapter , port , unit ) ;
2005-04-16 15:20:36 -07:00
return retval ;
}
static int
zfcp_erp_action_dequeue ( struct zfcp_erp_action * erp_action )
{
int retval = 0 ;
struct zfcp_adapter * adapter = erp_action - > adapter ;
- - adapter - > erp_total_count ;
if ( erp_action - > status & ZFCP_STATUS_ERP_LOWMEM ) {
- - adapter - > erp_low_mem_count ;
erp_action - > status & = ~ ZFCP_STATUS_ERP_LOWMEM ;
}
list_del ( & erp_action - > list ) ;
2008-03-27 14:22:04 +01:00
zfcp_rec_dbf_event_action ( 144 , erp_action ) ;
2005-04-16 15:20:36 -07:00
switch ( erp_action - > action ) {
case ZFCP_ERP_ACTION_REOPEN_UNIT :
atomic_clear_mask ( ZFCP_STATUS_COMMON_ERP_INUSE ,
& erp_action - > unit - > status ) ;
break ;
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 ;
case ZFCP_ERP_ACTION_REOPEN_ADAPTER :
atomic_clear_mask ( ZFCP_STATUS_COMMON_ERP_INUSE ,
& erp_action - > adapter - > status ) ;
break ;
default :
/* bug */
break ;
}
return retval ;
}
/**
* zfcp_erp_action_cleanup
*
2006-01-15 02:00:17 +01:00
* Register unit with scsi stack if appropriate and fix reference counts .
2005-04-16 15:20:36 -07:00
* Note : Temporary units are not registered with scsi stack .
*/
static void
zfcp_erp_action_cleanup ( int action , struct zfcp_adapter * adapter ,
struct zfcp_port * port , struct zfcp_unit * unit ,
int result )
{
switch ( action ) {
case ZFCP_ERP_ACTION_REOPEN_UNIT :
if ( ( result = = ZFCP_ERP_SUCCEEDED )
& & ( ! atomic_test_mask ( ZFCP_STATUS_UNIT_TEMPORARY ,
& unit - > status ) )
2005-08-27 11:07:54 -07:00
& & ! unit - > device
2006-03-10 00:56:16 +01:00
& & port - > rport ) {
atomic_set_mask ( ZFCP_STATUS_UNIT_REGISTERED ,
& unit - > status ) ;
2007-05-08 11:16:52 +02:00
if ( atomic_test_mask ( ZFCP_STATUS_UNIT_SCSI_WORK_PENDING ,
& unit - > status ) = = 0 )
zfcp_erp_schedule_work ( unit ) ;
2006-03-10 00:56:16 +01:00
}
2005-04-16 15:20:36 -07:00
zfcp_unit_put ( unit ) ;
break ;
case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED :
case ZFCP_ERP_ACTION_REOPEN_PORT :
2006-05-22 18:25:56 +02:00
if ( atomic_test_mask ( ZFCP_STATUS_PORT_NO_WWPN ,
& port - > status ) ) {
zfcp_port_put ( port ) ;
break ;
}
2005-08-27 11:07:54 -07:00
if ( ( result = = ZFCP_ERP_SUCCEEDED )
& & ! port - > rport ) {
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 ( adapter - > scsi_host , 0 , & ids ) ;
if ( ! port - > rport )
ZFCP_LOG_NORMAL ( " failed registration of rport "
" (adapter %s, wwpn=0x%016Lx) \n " ,
zfcp_get_busid_by_port ( port ) ,
port - > wwpn ) ;
2006-05-22 18:24:33 +02:00
else {
2007-05-08 11:16:52 +02:00
scsi_target_unblock ( & port - > rport - > dev ) ;
2006-05-22 18:24:33 +02:00
port - > rport - > maxframe_size = port - > maxframe_size ;
port - > rport - > supported_classes =
port - > supported_classes ;
}
2005-08-27 11:07:54 -07:00
}
2006-05-22 18:25:56 +02:00
if ( ( result ! = ZFCP_ERP_SUCCEEDED ) & & port - > rport ) {
fc_remote_port_delete ( port - > rport ) ;
port - > rport = NULL ;
}
2005-04-16 15:20:36 -07:00
zfcp_port_put ( port ) ;
break ;
case ZFCP_ERP_ACTION_REOPEN_ADAPTER :
2006-05-22 18:25:56 +02:00
if ( result ! = ZFCP_ERP_SUCCEEDED ) {
list_for_each_entry ( port , & adapter - > port_list_head , list )
if ( port - > rport & &
! atomic_test_mask ( ZFCP_STATUS_PORT_WKA ,
& port - > status ) ) {
fc_remote_port_delete ( port - > rport ) ;
port - > rport = NULL ;
}
}
2005-04-16 15:20:36 -07:00
zfcp_adapter_put ( adapter ) ;
break ;
default :
break ;
}
}
2006-09-18 22:30:36 +02:00
static void zfcp_erp_action_dismiss_adapter ( struct zfcp_adapter * adapter )
2005-04-16 15:20:36 -07:00
{
struct zfcp_port * port ;
if ( atomic_test_mask ( ZFCP_STATUS_COMMON_ERP_INUSE , & adapter - > status ) )
zfcp_erp_action_dismiss ( & adapter - > erp_action ) ;
else
list_for_each_entry ( port , & adapter - > port_list_head , list )
zfcp_erp_action_dismiss_port ( port ) ;
}
2006-08-02 11:05:52 +02:00
static void zfcp_erp_action_dismiss_port ( struct zfcp_port * port )
2005-04-16 15:20:36 -07:00
{
struct zfcp_unit * unit ;
if ( atomic_test_mask ( ZFCP_STATUS_COMMON_ERP_INUSE , & port - > status ) )
zfcp_erp_action_dismiss ( & port - > erp_action ) ;
else
list_for_each_entry ( unit , & port - > unit_list_head , list )
zfcp_erp_action_dismiss_unit ( unit ) ;
}
2006-08-02 11:05:52 +02:00
static void zfcp_erp_action_dismiss_unit ( struct zfcp_unit * unit )
2005-04-16 15:20:36 -07:00
{
if ( atomic_test_mask ( ZFCP_STATUS_COMMON_ERP_INUSE , & unit - > status ) )
zfcp_erp_action_dismiss ( & unit - > erp_action ) ;
}
2007-10-12 16:11:35 +02:00
static void zfcp_erp_action_to_running ( struct zfcp_erp_action * erp_action )
2005-04-16 15:20:36 -07:00
{
list_move ( & erp_action - > list , & erp_action - > adapter - > erp_running_head ) ;
2008-03-27 14:22:04 +01:00
zfcp_rec_dbf_event_action ( 145 , erp_action ) ;
2005-04-16 15:20:36 -07:00
}
2007-10-12 16:11:35 +02:00
static void zfcp_erp_action_to_ready ( struct zfcp_erp_action * erp_action )
2005-04-16 15:20:36 -07:00
{
list_move ( & erp_action - > list , & erp_action - > adapter - > erp_ready_head ) ;
2008-03-27 14:22:04 +01:00
zfcp_rec_dbf_event_action ( 146 , erp_action ) ;
2005-04-16 15:20:36 -07:00
}
2008-03-27 14:22:02 +01:00
void zfcp_erp_port_boxed ( struct zfcp_port * port , u8 id , u64 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-03-27 14:22:02 +01:00
void zfcp_erp_unit_boxed ( struct zfcp_unit * unit , u8 id , u64 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-03-27 14:22:02 +01:00
void zfcp_erp_port_access_denied ( struct zfcp_port * port , u8 id , u64 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-03-27 14:22:02 +01:00
void zfcp_erp_unit_access_denied ( struct zfcp_unit * unit , u8 id , u64 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-03-27 14:22:03 +01:00
void zfcp_erp_adapter_access_changed ( struct zfcp_adapter * adapter , u8 id ,
u64 ref )
2005-04-16 15:20:36 -07:00
{
struct zfcp_port * port ;
unsigned long flags ;
2005-09-13 21:51:16 +02:00
if ( adapter - > connection_features & FSF_FEATURE_NPIV_MODE )
return ;
2005-04-16 15:20:36 -07:00
read_lock_irqsave ( & zfcp_data . config_lock , flags ) ;
2005-04-10 23:04:28 -05:00
if ( adapter - > nameserver_port )
2008-03-27 14:22:03 +01:00
zfcp_erp_port_access_changed ( adapter - > nameserver_port , id , ref ) ;
2005-04-16 15:20:36 -07:00
list_for_each_entry ( port , & adapter - > port_list_head , list )
if ( port ! = adapter - > nameserver_port )
2008-03-27 14:22:03 +01:00
zfcp_erp_port_access_changed ( port , id , ref ) ;
2005-04-16 15:20:36 -07:00
read_unlock_irqrestore ( & zfcp_data . config_lock , flags ) ;
}
2008-03-27 14:22:03 +01:00
void zfcp_erp_port_access_changed ( struct zfcp_port * port , u8 id , u64 ref )
2005-04-16 15:20:36 -07:00
{
struct zfcp_adapter * adapter = port - > adapter ;
struct zfcp_unit * unit ;
if ( ! atomic_test_mask ( ZFCP_STATUS_COMMON_ACCESS_DENIED ,
2005-06-13 13:23:57 +02:00
& port - > status ) & &
! atomic_test_mask ( ZFCP_STATUS_COMMON_ACCESS_BOXED ,
2005-04-16 15:20:36 -07:00
& port - > status ) ) {
if ( ! atomic_test_mask ( ZFCP_STATUS_PORT_WKA , & port - > status ) )
list_for_each_entry ( unit , & port - > unit_list_head , list )
2008-03-27 14:22:03 +01:00
zfcp_erp_unit_access_changed ( unit , id , ref ) ;
2005-04-16 15:20:36 -07:00
return ;
}
ZFCP_LOG_NORMAL ( " reopen of port 0x%016Lx on adapter %s "
" (due to ACT update) \n " ,
port - > wwpn , zfcp_get_busid_by_adapter ( adapter ) ) ;
2008-03-27 14:22:03 +01:00
if ( zfcp_erp_port_reopen ( port , ZFCP_STATUS_COMMON_ERP_FAILED , id , ref ) )
2005-04-16 15:20:36 -07:00
ZFCP_LOG_NORMAL ( " failed reopen of port "
" (adapter %s, wwpn=0x%016Lx) \n " ,
zfcp_get_busid_by_adapter ( adapter ) , port - > wwpn ) ;
}
2008-03-27 14:22:03 +01:00
void zfcp_erp_unit_access_changed ( struct zfcp_unit * unit , u8 id , u64 ref )
2005-04-16 15:20:36 -07:00
{
struct zfcp_adapter * adapter = unit - > port - > adapter ;
2005-06-13 13:23:57 +02:00
if ( ! atomic_test_mask ( ZFCP_STATUS_COMMON_ACCESS_DENIED ,
& unit - > status ) & &
! atomic_test_mask ( ZFCP_STATUS_COMMON_ACCESS_BOXED ,
& unit - > status ) )
2005-04-16 15:20:36 -07:00
return ;
ZFCP_LOG_NORMAL ( " reopen of unit 0x%016Lx on port 0x%016Lx "
" on adapter %s (due to ACT update) \n " ,
unit - > fcp_lun , unit - > port - > wwpn ,
zfcp_get_busid_by_adapter ( adapter ) ) ;
2008-03-27 14:22:03 +01:00
if ( zfcp_erp_unit_reopen ( unit , ZFCP_STATUS_COMMON_ERP_FAILED , id , ref ) )
2005-04-16 15:20:36 -07:00
ZFCP_LOG_NORMAL ( " failed reopen of unit (adapter %s, "
" wwpn=0x%016Lx, fcp_lun=0x%016Lx) \n " ,
zfcp_get_busid_by_adapter ( adapter ) ,
unit - > port - > wwpn , unit - > fcp_lun ) ;
}
# undef ZFCP_LOG_AREA