2008-06-10 20:20:54 +04:00
/*
* zfcp device driver
*
* Fibre Channel related functions for the zfcp device driver .
*
2010-02-17 13:18:56 +03:00
* Copyright IBM Corporation 2008 , 2010
2008-06-10 20:20:54 +04:00
*/
2008-12-25 15:39:53 +03:00
# define KMSG_COMPONENT "zfcp"
# define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
2009-11-24 18:54:09 +03:00
# include <linux/types.h>
# include <scsi/fc/fc_els.h>
# include <scsi/libfc.h>
2008-06-10 20:20:54 +04:00
# include "zfcp_ext.h"
2009-11-24 18:54:09 +03:00
# include "zfcp_fc.h"
2008-06-10 20:20:54 +04:00
2009-11-24 18:54:09 +03:00
static u32 zfcp_fc_rscn_range_mask [ ] = {
[ ELS_ADDR_FMT_PORT ] = 0xFFFFFF ,
[ ELS_ADDR_FMT_AREA ] = 0xFFFF00 ,
[ ELS_ADDR_FMT_DOM ] = 0xFF0000 ,
[ ELS_ADDR_FMT_FAB ] = 0x000000 ,
2008-12-19 18:56:58 +03:00
} ;
2009-11-24 18:54:11 +03:00
static int zfcp_fc_wka_port_get ( struct zfcp_fc_wka_port * wka_port )
2008-10-01 14:42:17 +04:00
{
if ( mutex_lock_interruptible ( & wka_port - > mutex ) )
return - ERESTARTSYS ;
2009-11-24 18:54:11 +03:00
if ( wka_port - > status = = ZFCP_FC_WKA_PORT_OFFLINE | |
wka_port - > status = = ZFCP_FC_WKA_PORT_CLOSING ) {
wka_port - > status = ZFCP_FC_WKA_PORT_OPENING ;
2008-10-01 14:42:17 +04:00
if ( zfcp_fsf_open_wka_port ( wka_port ) )
2009-11-24 18:54:11 +03:00
wka_port - > status = ZFCP_FC_WKA_PORT_OFFLINE ;
2008-10-01 14:42:17 +04:00
}
mutex_unlock ( & wka_port - > mutex ) ;
2009-07-13 17:06:13 +04:00
wait_event ( wka_port - > completion_wq ,
2009-11-24 18:54:11 +03:00
wka_port - > status = = ZFCP_FC_WKA_PORT_ONLINE | |
wka_port - > status = = ZFCP_FC_WKA_PORT_OFFLINE ) ;
2008-10-01 14:42:17 +04:00
2009-11-24 18:54:11 +03:00
if ( wka_port - > status = = ZFCP_FC_WKA_PORT_ONLINE ) {
2008-10-01 14:42:17 +04:00
atomic_inc ( & wka_port - > refcount ) ;
return 0 ;
}
return - EIO ;
}
2009-08-18 17:43:23 +04:00
static void zfcp_fc_wka_port_offline ( struct work_struct * work )
2008-10-01 14:42:17 +04:00
{
2009-04-03 03:56:54 +04:00
struct delayed_work * dw = to_delayed_work ( work ) ;
2009-11-24 18:54:11 +03:00
struct zfcp_fc_wka_port * wka_port =
container_of ( dw , struct zfcp_fc_wka_port , work ) ;
2008-10-01 14:42:17 +04:00
mutex_lock ( & wka_port - > mutex ) ;
if ( ( atomic_read ( & wka_port - > refcount ) ! = 0 ) | |
2009-11-24 18:54:11 +03:00
( wka_port - > status ! = ZFCP_FC_WKA_PORT_ONLINE ) )
2008-10-01 14:42:17 +04:00
goto out ;
2009-11-24 18:54:11 +03:00
wka_port - > status = ZFCP_FC_WKA_PORT_CLOSING ;
2008-10-01 14:42:17 +04:00
if ( zfcp_fsf_close_wka_port ( wka_port ) ) {
2009-11-24 18:54:11 +03:00
wka_port - > status = ZFCP_FC_WKA_PORT_OFFLINE ;
2008-10-01 14:42:17 +04:00
wake_up ( & wka_port - > completion_wq ) ;
}
out :
mutex_unlock ( & wka_port - > mutex ) ;
}
2009-11-24 18:54:11 +03:00
static void zfcp_fc_wka_port_put ( struct zfcp_fc_wka_port * wka_port )
2008-10-01 14:42:17 +04:00
{
if ( atomic_dec_return ( & wka_port - > refcount ) ! = 0 )
return ;
2009-04-23 13:37:37 +04:00
/* wait 10 milliseconds, other reqs might pop in */
2008-10-01 14:42:17 +04:00
schedule_delayed_work ( & wka_port - > work , HZ / 100 ) ;
}
2009-11-24 18:54:11 +03:00
static void zfcp_fc_wka_port_init ( struct zfcp_fc_wka_port * wka_port , u32 d_id ,
2009-04-06 20:31:47 +04:00
struct zfcp_adapter * adapter )
2008-10-01 14:42:17 +04:00
{
init_waitqueue_head ( & wka_port - > completion_wq ) ;
wka_port - > adapter = adapter ;
2009-04-06 20:31:47 +04:00
wka_port - > d_id = d_id ;
2008-10-01 14:42:17 +04:00
2009-11-24 18:54:11 +03:00
wka_port - > status = ZFCP_FC_WKA_PORT_OFFLINE ;
2008-10-01 14:42:17 +04:00
atomic_set ( & wka_port - > refcount , 0 ) ;
mutex_init ( & wka_port - > mutex ) ;
2009-08-18 17:43:23 +04:00
INIT_DELAYED_WORK ( & wka_port - > work , zfcp_fc_wka_port_offline ) ;
2008-10-01 14:42:17 +04:00
}
2009-11-24 18:54:11 +03:00
static void zfcp_fc_wka_port_force_offline ( struct zfcp_fc_wka_port * wka )
2009-04-17 17:08:05 +04:00
{
cancel_delayed_work_sync ( & wka - > work ) ;
mutex_lock ( & wka - > mutex ) ;
2009-11-24 18:54:11 +03:00
wka - > status = ZFCP_FC_WKA_PORT_OFFLINE ;
2009-04-17 17:08:05 +04:00
mutex_unlock ( & wka - > mutex ) ;
}
2009-11-24 18:54:11 +03:00
void zfcp_fc_wka_ports_force_offline ( struct zfcp_fc_wka_ports * gs )
2009-08-18 17:43:12 +04:00
{
2009-11-24 18:53:59 +03:00
if ( ! gs )
return ;
2009-08-18 17:43:12 +04:00
zfcp_fc_wka_port_force_offline ( & gs - > ms ) ;
zfcp_fc_wka_port_force_offline ( & gs - > ts ) ;
zfcp_fc_wka_port_force_offline ( & gs - > ds ) ;
zfcp_fc_wka_port_force_offline ( & gs - > as ) ;
}
2008-06-10 20:20:54 +04:00
static void _zfcp_fc_incoming_rscn ( struct zfcp_fsf_req * fsf_req , u32 range ,
2009-11-24 18:54:09 +03:00
struct fc_els_rscn_page * page )
2008-06-10 20:20:54 +04:00
{
unsigned long flags ;
2009-11-24 18:53:58 +03:00
struct zfcp_adapter * adapter = fsf_req - > adapter ;
2008-06-10 20:20:54 +04:00
struct zfcp_port * port ;
2009-11-24 18:53:58 +03:00
read_lock_irqsave ( & adapter - > port_list_lock , flags ) ;
list_for_each_entry ( port , & adapter - > port_list , list ) {
2009-11-24 18:54:09 +03:00
if ( ( port - > d_id & range ) = = ( ntoh24 ( page - > rscn_fid ) & range ) )
2009-08-18 17:43:23 +04:00
zfcp_fc_test_link ( port ) ;
2009-05-15 15:18:20 +04:00
if ( ! port - > d_id )
zfcp_erp_port_reopen ( port ,
ZFCP_STATUS_COMMON_ERP_FAILED ,
" fcrscn1 " , NULL ) ;
}
2009-11-24 18:53:58 +03:00
read_unlock_irqrestore ( & adapter - > port_list_lock , flags ) ;
2008-06-10 20:20:54 +04:00
}
static void zfcp_fc_incoming_rscn ( struct zfcp_fsf_req * fsf_req )
{
struct fsf_status_read_buffer * status_buffer = ( void * ) fsf_req - > data ;
2009-11-24 18:54:09 +03:00
struct fc_els_rscn * head ;
struct fc_els_rscn_page * page ;
2008-06-10 20:20:54 +04:00
u16 i ;
u16 no_entries ;
2009-11-24 18:54:09 +03:00
unsigned int afmt ;
2008-06-10 20:20:54 +04:00
2009-11-24 18:54:09 +03:00
head = ( struct fc_els_rscn * ) status_buffer - > payload . data ;
page = ( struct fc_els_rscn_page * ) head ;
2008-06-10 20:20:54 +04:00
/* see FC-FS */
2009-11-24 18:54:09 +03:00
no_entries = head - > rscn_plen / sizeof ( struct fc_els_rscn_page ) ;
2008-06-10 20:20:54 +04:00
for ( i = 1 ; i < no_entries ; i + + ) {
/* skip head and start with 1st element */
2009-11-24 18:54:09 +03:00
page + + ;
afmt = page - > rscn_page_flags & ELS_RSCN_ADDR_FMT_MASK ;
_zfcp_fc_incoming_rscn ( fsf_req , zfcp_fc_rscn_range_mask [ afmt ] ,
page ) ;
2008-06-10 20:20:54 +04:00
}
2009-11-24 18:54:06 +03:00
queue_work ( fsf_req - > adapter - > work_queue , & fsf_req - > adapter - > scan_work ) ;
2008-06-10 20:20:54 +04:00
}
2008-10-01 14:42:18 +04:00
static void zfcp_fc_incoming_wwpn ( struct zfcp_fsf_req * req , u64 wwpn )
2008-06-10 20:20:54 +04:00
{
2009-11-24 18:53:58 +03:00
unsigned long flags ;
2008-06-10 20:20:54 +04:00
struct zfcp_adapter * adapter = req - > adapter ;
struct zfcp_port * port ;
2009-11-24 18:53:58 +03:00
read_lock_irqsave ( & adapter - > port_list_lock , flags ) ;
list_for_each_entry ( port , & adapter - > port_list , list )
if ( port - > wwpn = = wwpn ) {
zfcp_erp_port_forced_reopen ( port , 0 , " fciwwp1 " , req ) ;
2008-06-10 20:20:54 +04:00
break ;
2009-11-24 18:53:58 +03:00
}
read_unlock_irqrestore ( & adapter - > port_list_lock , flags ) ;
2008-06-10 20:20:54 +04:00
}
static void zfcp_fc_incoming_plogi ( struct zfcp_fsf_req * req )
{
2009-11-24 18:54:09 +03:00
struct fsf_status_read_buffer * status_buffer ;
struct fc_els_flogi * plogi ;
2008-06-10 20:20:54 +04:00
2009-11-24 18:54:09 +03:00
status_buffer = ( struct fsf_status_read_buffer * ) req - > data ;
plogi = ( struct fc_els_flogi * ) status_buffer - > payload . data ;
zfcp_fc_incoming_wwpn ( req , plogi - > fl_wwpn ) ;
2008-06-10 20:20:54 +04:00
}
static void zfcp_fc_incoming_logo ( struct zfcp_fsf_req * req )
{
struct fsf_status_read_buffer * status_buffer =
( struct fsf_status_read_buffer * ) req - > data ;
2009-11-24 18:54:09 +03:00
struct fc_els_logo * logo =
( struct fc_els_logo * ) status_buffer - > payload . data ;
2008-06-10 20:20:54 +04:00
2009-11-24 18:54:09 +03:00
zfcp_fc_incoming_wwpn ( req , logo - > fl_n_port_wwn ) ;
2008-06-10 20:20:54 +04:00
}
/**
* zfcp_fc_incoming_els - handle incoming ELS
* @ fsf_req - request which contains incoming ELS
*/
void zfcp_fc_incoming_els ( struct zfcp_fsf_req * fsf_req )
{
struct fsf_status_read_buffer * status_buffer =
( struct fsf_status_read_buffer * ) fsf_req - > data ;
2008-07-02 12:56:39 +04:00
unsigned int els_type = status_buffer - > payload . data [ 0 ] ;
2008-06-10 20:20:54 +04:00
2009-08-18 17:43:21 +04:00
zfcp_dbf_san_incoming_els ( fsf_req ) ;
2009-11-24 18:54:09 +03:00
if ( els_type = = ELS_PLOGI )
2008-06-10 20:20:54 +04:00
zfcp_fc_incoming_plogi ( fsf_req ) ;
2009-11-24 18:54:09 +03:00
else if ( els_type = = ELS_LOGO )
2008-06-10 20:20:54 +04:00
zfcp_fc_incoming_logo ( fsf_req ) ;
2009-11-24 18:54:09 +03:00
else if ( els_type = = ELS_RSCN )
2008-06-10 20:20:54 +04:00
zfcp_fc_incoming_rscn ( fsf_req ) ;
}
2009-11-24 18:54:13 +03:00
static void zfcp_fc_ns_gid_pn_eval ( void * data )
2008-06-10 20:20:54 +04:00
{
2009-11-24 18:54:13 +03:00
struct zfcp_fc_gid_pn * gid_pn = data ;
struct zfcp_fsf_ct_els * ct = & gid_pn - > ct ;
2009-11-24 18:54:10 +03:00
struct zfcp_fc_gid_pn_req * gid_pn_req = sg_virt ( ct - > req ) ;
struct zfcp_fc_gid_pn_resp * gid_pn_resp = sg_virt ( ct - > resp ) ;
2008-06-10 20:20:54 +04:00
struct zfcp_port * port = gid_pn - > port ;
if ( ct - > status )
2008-10-01 14:42:17 +04:00
return ;
2009-11-24 18:54:10 +03:00
if ( gid_pn_resp - > ct_hdr . ct_cmd ! = FC_FS_ACC )
2008-10-01 14:42:17 +04:00
return ;
2009-03-02 15:08:54 +03:00
2008-06-10 20:20:54 +04:00
/* paranoia */
2009-11-24 18:54:10 +03:00
if ( gid_pn_req - > gid_pn . fn_wwpn ! = port - > wwpn )
2008-10-01 14:42:17 +04:00
return ;
2008-06-10 20:20:54 +04:00
/* looks like a valid d_id */
2009-11-24 18:54:10 +03:00
port - > d_id = ntoh24 ( gid_pn_resp - > gid_pn . fp_fid ) ;
2008-06-10 20:20:54 +04:00
}
2009-11-24 18:54:13 +03:00
static void zfcp_fc_complete ( void * data )
{
complete ( data ) ;
}
2009-08-18 17:43:20 +04:00
static int zfcp_fc_ns_gid_pn_request ( struct zfcp_port * port ,
2009-11-24 18:54:10 +03:00
struct zfcp_fc_gid_pn * gid_pn )
2008-06-10 20:20:54 +04:00
{
2009-08-18 17:43:20 +04:00
struct zfcp_adapter * adapter = port - > adapter ;
2009-11-24 18:54:13 +03:00
DECLARE_COMPLETION_ONSTACK ( completion ) ;
2008-10-01 14:42:17 +04:00
int ret ;
2008-06-10 20:20:54 +04:00
/* setup parameters for send generic command */
2009-08-18 17:43:20 +04:00
gid_pn - > port = port ;
2009-11-24 18:54:13 +03:00
gid_pn - > ct . handler = zfcp_fc_complete ;
gid_pn - > ct . handler_data = & completion ;
2009-11-24 18:54:10 +03:00
gid_pn - > ct . req = & gid_pn - > sg_req ;
gid_pn - > ct . resp = & gid_pn - > sg_resp ;
sg_init_one ( & gid_pn - > sg_req , & gid_pn - > gid_pn_req ,
sizeof ( struct zfcp_fc_gid_pn_req ) ) ;
sg_init_one ( & gid_pn - > sg_resp , & gid_pn - > gid_pn_resp ,
sizeof ( struct zfcp_fc_gid_pn_resp ) ) ;
2008-06-10 20:20:54 +04:00
/* setup nameserver request */
2009-11-24 18:54:10 +03:00
gid_pn - > gid_pn_req . ct_hdr . ct_rev = FC_CT_REV ;
gid_pn - > gid_pn_req . ct_hdr . ct_fs_type = FC_FST_DIR ;
gid_pn - > gid_pn_req . ct_hdr . ct_fs_subtype = FC_NS_SUBTYPE ;
gid_pn - > gid_pn_req . ct_hdr . ct_options = 0 ;
gid_pn - > gid_pn_req . ct_hdr . ct_cmd = FC_NS_GID_PN ;
gid_pn - > gid_pn_req . ct_hdr . ct_mr_size = ZFCP_FC_CT_SIZE_PAGE / 4 ;
gid_pn - > gid_pn_req . gid_pn . fn_wwpn = port - > wwpn ;
2008-06-10 20:20:54 +04:00
2009-11-24 18:54:13 +03:00
ret = zfcp_fsf_send_ct ( & adapter - > gs - > ds , & gid_pn - > ct ,
2010-01-14 19:19:02 +03:00
adapter - > pool . gid_pn_req ,
ZFCP_FC_CTELS_TMO ) ;
2009-11-24 18:54:13 +03:00
if ( ! ret ) {
wait_for_completion ( & completion ) ;
zfcp_fc_ns_gid_pn_eval ( gid_pn ) ;
}
2008-10-01 14:42:17 +04:00
return ret ;
}
/**
* zfcp_fc_ns_gid_pn_request - initiate GID_PN nameserver request
2009-08-18 17:43:20 +04:00
* @ port : port where GID_PN request is needed
2008-10-01 14:42:17 +04:00
* return : - ENOMEM on error , 0 otherwise
*/
2009-08-18 17:43:20 +04:00
static int zfcp_fc_ns_gid_pn ( struct zfcp_port * port )
2008-10-01 14:42:17 +04:00
{
int ret ;
2009-11-24 18:54:10 +03:00
struct zfcp_fc_gid_pn * gid_pn ;
2009-08-18 17:43:20 +04:00
struct zfcp_adapter * adapter = port - > adapter ;
2008-10-01 14:42:17 +04:00
2009-11-24 18:54:10 +03:00
gid_pn = mempool_alloc ( adapter - > pool . gid_pn , GFP_ATOMIC ) ;
2008-10-01 14:42:17 +04:00
if ( ! gid_pn )
return - ENOMEM ;
memset ( gid_pn , 0 , sizeof ( * gid_pn ) ) ;
2009-08-18 17:43:23 +04:00
ret = zfcp_fc_wka_port_get ( & adapter - > gs - > ds ) ;
2008-06-10 20:20:54 +04:00
if ( ret )
2008-10-01 14:42:17 +04:00
goto out ;
2009-08-18 17:43:20 +04:00
ret = zfcp_fc_ns_gid_pn_request ( port , gid_pn ) ;
2008-10-01 14:42:17 +04:00
2009-08-18 17:43:23 +04:00
zfcp_fc_wka_port_put ( & adapter - > gs - > ds ) ;
2008-10-01 14:42:17 +04:00
out :
2009-11-24 18:54:10 +03:00
mempool_free ( gid_pn , adapter - > pool . gid_pn ) ;
2008-06-10 20:20:54 +04:00
return ret ;
}
2009-08-18 17:43:20 +04:00
void zfcp_fc_port_did_lookup ( struct work_struct * work )
{
int ret ;
struct zfcp_port * port = container_of ( work , struct zfcp_port ,
gid_pn_work ) ;
ret = zfcp_fc_ns_gid_pn ( port ) ;
if ( ret ) {
/* could not issue gid_pn for some reason */
zfcp_erp_adapter_reopen ( port - > adapter , 0 , " fcgpn_1 " , NULL ) ;
goto out ;
}
if ( ! port - > d_id ) {
zfcp_erp_port_failed ( port , " fcgpn_2 " , NULL ) ;
goto out ;
}
zfcp_erp_port_reopen ( port , 0 , " fcgpn_3 " , NULL ) ;
out :
2010-02-17 13:18:56 +03:00
put_device ( & port - > dev ) ;
2009-08-18 17:43:20 +04:00
}
2009-10-14 13:00:43 +04:00
/**
* zfcp_fc_trigger_did_lookup - trigger the d_id lookup using a GID_PN request
* @ port : The zfcp_port to lookup the d_id for .
*/
void zfcp_fc_trigger_did_lookup ( struct zfcp_port * port )
{
2010-02-17 13:18:56 +03:00
get_device ( & port - > dev ) ;
2009-10-14 13:00:43 +04:00
if ( ! queue_work ( port - > adapter - > work_queue , & port - > gid_pn_work ) )
2010-02-17 13:18:56 +03:00
put_device ( & port - > dev ) ;
2009-10-14 13:00:43 +04:00
}
2008-06-10 20:20:54 +04:00
/**
* zfcp_fc_plogi_evaluate - evaluate PLOGI playload
* @ port : zfcp_port structure
* @ plogi : plogi payload
*
* Evaluate PLOGI playload and copy important fields into zfcp_port structure
*/
2009-11-24 18:54:09 +03:00
void zfcp_fc_plogi_evaluate ( struct zfcp_port * port , struct fc_els_flogi * plogi )
2008-06-10 20:20:54 +04:00
{
2009-11-24 18:54:09 +03:00
if ( plogi - > fl_wwpn ! = port - > wwpn ) {
port - > d_id = 0 ;
dev_warn ( & port - > adapter - > ccw_device - > dev ,
" A port opened with WWPN 0x%016Lx returned data that "
" identifies it as WWPN 0x%016Lx \n " ,
( unsigned long long ) port - > wwpn ,
( unsigned long long ) plogi - > fl_wwpn ) ;
return ;
}
port - > wwnn = plogi - > fl_wwnn ;
port - > maxframe_size = plogi - > fl_csp . sp_bb_data ;
if ( plogi - > fl_cssp [ 0 ] . cp_class & FC_CPC_VALID )
2008-06-10 20:20:54 +04:00
port - > supported_classes | = FC_COS_CLASS1 ;
2009-11-24 18:54:09 +03:00
if ( plogi - > fl_cssp [ 1 ] . cp_class & FC_CPC_VALID )
2008-06-10 20:20:54 +04:00
port - > supported_classes | = FC_COS_CLASS2 ;
2009-11-24 18:54:09 +03:00
if ( plogi - > fl_cssp [ 2 ] . cp_class & FC_CPC_VALID )
2008-06-10 20:20:54 +04:00
port - > supported_classes | = FC_COS_CLASS3 ;
2009-11-24 18:54:09 +03:00
if ( plogi - > fl_cssp [ 3 ] . cp_class & FC_CPC_VALID )
2008-06-10 20:20:54 +04:00
port - > supported_classes | = FC_COS_CLASS4 ;
}
2009-11-24 18:54:13 +03:00
static void zfcp_fc_adisc_handler ( void * data )
2008-06-10 20:20:54 +04:00
{
2009-11-24 18:54:13 +03:00
struct zfcp_fc_els_adisc * adisc = data ;
2008-06-10 20:20:54 +04:00
struct zfcp_port * port = adisc - > els . port ;
2009-11-24 18:54:09 +03:00
struct fc_els_adisc * adisc_resp = & adisc - > adisc_resp ;
2008-06-10 20:20:54 +04:00
2008-07-02 12:56:32 +04:00
if ( adisc - > els . status ) {
2008-06-10 20:20:54 +04:00
/* request rejected or timed out */
2009-04-17 17:08:10 +04:00
zfcp_erp_port_forced_reopen ( port , ZFCP_STATUS_COMMON_ERP_FAILED ,
" fcadh_1 " , NULL ) ;
2008-06-10 20:20:54 +04:00
goto out ;
}
if ( ! port - > wwnn )
2009-11-24 18:54:09 +03:00
port - > wwnn = adisc_resp - > adisc_wwnn ;
2008-06-10 20:20:54 +04:00
2009-11-24 18:54:09 +03:00
if ( ( port - > wwpn ! = adisc_resp - > adisc_wwpn ) | |
2009-03-02 15:09:08 +03:00
! ( atomic_read ( & port - > status ) & ZFCP_STATUS_COMMON_OPEN ) ) {
2009-03-02 15:09:07 +03:00
zfcp_erp_port_reopen ( port , ZFCP_STATUS_COMMON_ERP_FAILED ,
" fcadh_2 " , NULL ) ;
2009-03-02 15:09:08 +03:00
goto out ;
}
2008-06-10 20:20:54 +04:00
2009-03-02 15:09:08 +03:00
/* port is good, unblock rport without going through erp */
zfcp_scsi_schedule_rport_register ( port ) ;
2008-06-10 20:20:54 +04:00
out :
2009-08-18 17:43:11 +04:00
atomic_clear_mask ( ZFCP_STATUS_PORT_LINK_TEST , & port - > status ) ;
2010-02-17 13:18:56 +03:00
put_device ( & port - > dev ) ;
2009-11-24 18:54:14 +03:00
kmem_cache_free ( zfcp_data . adisc_cache , adisc ) ;
2008-06-10 20:20:54 +04:00
}
static int zfcp_fc_adisc ( struct zfcp_port * port )
{
2009-11-24 18:54:09 +03:00
struct zfcp_fc_els_adisc * adisc ;
2008-06-10 20:20:54 +04:00
struct zfcp_adapter * adapter = port - > adapter ;
2009-11-24 18:54:14 +03:00
int ret ;
2008-06-10 20:20:54 +04:00
2009-11-24 18:54:14 +03:00
adisc = kmem_cache_alloc ( zfcp_data . adisc_cache , GFP_ATOMIC ) ;
2008-06-10 20:20:54 +04:00
if ( ! adisc )
return - ENOMEM ;
2009-11-24 18:54:13 +03:00
adisc - > els . port = port ;
2008-06-10 20:20:54 +04:00
adisc - > els . req = & adisc - > req ;
adisc - > els . resp = & adisc - > resp ;
2009-11-24 18:54:09 +03:00
sg_init_one ( adisc - > els . req , & adisc - > adisc_req ,
sizeof ( struct fc_els_adisc ) ) ;
sg_init_one ( adisc - > els . resp , & adisc - > adisc_resp ,
sizeof ( struct fc_els_adisc ) ) ;
2008-06-10 20:20:54 +04:00
adisc - > els . handler = zfcp_fc_adisc_handler ;
2009-11-24 18:54:13 +03:00
adisc - > els . handler_data = adisc ;
2008-06-10 20:20:54 +04:00
/* 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 */
2009-11-24 18:54:09 +03:00
adisc - > adisc_req . adisc_wwpn = fc_host_port_name ( adapter - > scsi_host ) ;
adisc - > adisc_req . adisc_wwnn = fc_host_node_name ( adapter - > scsi_host ) ;
2009-11-24 18:54:13 +03:00
adisc - > adisc_req . adisc_cmd = ELS_ADISC ;
2009-11-24 18:54:09 +03:00
hton24 ( adisc - > adisc_req . adisc_port_id ,
fc_host_port_id ( adapter - > scsi_host ) ) ;
2008-06-10 20:20:54 +04:00
2010-01-14 19:19:02 +03:00
ret = zfcp_fsf_send_els ( adapter , port - > d_id , & adisc - > els ,
ZFCP_FC_CTELS_TMO ) ;
2009-11-24 18:54:14 +03:00
if ( ret )
kmem_cache_free ( zfcp_data . adisc_cache , adisc ) ;
return ret ;
2008-06-10 20:20:54 +04:00
}
2009-03-02 15:09:01 +03:00
void zfcp_fc_link_test_work ( struct work_struct * work )
2008-06-10 20:20:54 +04:00
{
2009-03-02 15:09:01 +03:00
struct zfcp_port * port =
container_of ( work , struct zfcp_port , test_link_work ) ;
2008-06-10 20:20:54 +04:00
int retval ;
2010-02-17 13:18:56 +03:00
get_device ( & port - > dev ) ;
2009-03-02 15:09:08 +03:00
port - > rport_task = RPORT_DEL ;
zfcp_scsi_rport_work ( & port - > rport_work ) ;
2009-08-18 17:43:11 +04:00
/* only issue one test command at one time per port */
if ( atomic_read ( & port - > status ) & ZFCP_STATUS_PORT_LINK_TEST )
goto out ;
atomic_set_mask ( ZFCP_STATUS_PORT_LINK_TEST , & port - > status ) ;
2008-06-10 20:20:54 +04:00
retval = zfcp_fc_adisc ( port ) ;
2008-08-21 15:43:35 +04:00
if ( retval = = 0 )
2008-06-10 20:20:54 +04:00
return ;
/* send of ADISC was not possible */
2009-08-18 17:43:11 +04:00
atomic_clear_mask ( ZFCP_STATUS_PORT_LINK_TEST , & port - > status ) ;
2009-03-02 15:09:08 +03:00
zfcp_erp_port_forced_reopen ( port , 0 , " fcltwk1 " , NULL ) ;
2009-08-18 17:43:11 +04:00
out :
2010-02-17 13:18:56 +03:00
put_device ( & port - > dev ) ;
2008-06-10 20:20:54 +04:00
}
2008-06-10 20:21:00 +04:00
2009-03-02 15:09:01 +03:00
/**
2009-08-18 17:43:23 +04:00
* zfcp_fc_test_link - lightweight link test procedure
2009-03-02 15:09:01 +03:00
* @ port : port to be tested
*
* Test status of a link to a remote port using the ELS command ADISC .
* If there is a problem with the remote port , error recovery steps
* will be triggered .
*/
2009-08-18 17:43:23 +04:00
void zfcp_fc_test_link ( struct zfcp_port * port )
2009-03-02 15:09:01 +03:00
{
2010-02-17 13:18:56 +03:00
get_device ( & port - > dev ) ;
2009-08-18 17:43:17 +04:00
if ( ! queue_work ( port - > adapter - > work_queue , & port - > test_link_work ) )
2010-02-17 13:18:56 +03:00
put_device ( & port - > dev ) ;
2009-03-02 15:09:01 +03:00
}
2009-11-24 18:54:10 +03:00
static void zfcp_free_sg_env ( struct zfcp_fc_gpn_ft * gpn_ft , int buf_num )
2008-06-10 20:21:00 +04:00
{
struct scatterlist * sg = & gpn_ft - > sg_req ;
2009-08-18 17:43:15 +04:00
kmem_cache_free ( zfcp_data . gpn_ft_cache , sg_virt ( sg ) ) ;
2008-12-19 18:57:01 +03:00
zfcp_sg_free_table ( gpn_ft - > sg_resp , buf_num ) ;
2008-06-10 20:21:00 +04:00
kfree ( gpn_ft ) ;
}
2009-11-24 18:54:10 +03:00
static struct zfcp_fc_gpn_ft * zfcp_alloc_sg_env ( int buf_num )
2008-06-10 20:21:00 +04:00
{
2009-11-24 18:54:10 +03:00
struct zfcp_fc_gpn_ft * gpn_ft ;
struct zfcp_fc_gpn_ft_req * req ;
2008-06-10 20:21:00 +04:00
gpn_ft = kzalloc ( sizeof ( * gpn_ft ) , GFP_KERNEL ) ;
if ( ! gpn_ft )
return NULL ;
2009-08-18 17:43:15 +04:00
req = kmem_cache_alloc ( zfcp_data . gpn_ft_cache , GFP_KERNEL ) ;
2008-06-10 20:21:00 +04:00
if ( ! req ) {
kfree ( gpn_ft ) ;
gpn_ft = NULL ;
goto out ;
}
sg_init_one ( & gpn_ft - > sg_req , req , sizeof ( * req ) ) ;
2008-12-19 18:57:01 +03:00
if ( zfcp_sg_setup_table ( gpn_ft - > sg_resp , buf_num ) ) {
zfcp_free_sg_env ( gpn_ft , buf_num ) ;
2008-06-10 20:21:00 +04:00
gpn_ft = NULL ;
}
out :
return gpn_ft ;
}
2009-11-24 18:54:10 +03:00
static int zfcp_fc_send_gpn_ft ( struct zfcp_fc_gpn_ft * gpn_ft ,
2009-08-18 17:43:23 +04:00
struct zfcp_adapter * adapter , int max_bytes )
2008-06-10 20:21:00 +04:00
{
2009-11-24 18:54:13 +03:00
struct zfcp_fsf_ct_els * ct = & gpn_ft - > ct ;
2009-11-24 18:54:10 +03:00
struct zfcp_fc_gpn_ft_req * req = sg_virt ( & gpn_ft - > sg_req ) ;
2009-11-24 18:54:13 +03:00
DECLARE_COMPLETION_ONSTACK ( completion ) ;
2008-06-10 20:21:00 +04:00
int ret ;
/* prepare CT IU for GPN_FT */
2009-11-24 18:54:10 +03:00
req - > ct_hdr . ct_rev = FC_CT_REV ;
req - > ct_hdr . ct_fs_type = FC_FST_DIR ;
req - > ct_hdr . ct_fs_subtype = FC_NS_SUBTYPE ;
req - > ct_hdr . ct_options = 0 ;
req - > ct_hdr . ct_cmd = FC_NS_GPN_FT ;
req - > ct_hdr . ct_mr_size = max_bytes / 4 ;
req - > gpn_ft . fn_domain_id_scope = 0 ;
req - > gpn_ft . fn_area_id_scope = 0 ;
req - > gpn_ft . fn_fc4_type = FC_TYPE_FCP ;
2008-06-10 20:21:00 +04:00
/* prepare zfcp_send_ct */
2009-11-24 18:54:13 +03:00
ct - > handler = zfcp_fc_complete ;
ct - > handler_data = & completion ;
2008-06-10 20:21:00 +04:00
ct - > req = & gpn_ft - > sg_req ;
ct - > resp = gpn_ft - > sg_resp ;
2010-01-14 19:19:02 +03:00
ret = zfcp_fsf_send_ct ( & adapter - > gs - > ds , ct , NULL ,
ZFCP_FC_CTELS_TMO ) ;
2008-06-10 20:21:00 +04:00
if ( ! ret )
2009-11-24 18:54:13 +03:00
wait_for_completion ( & completion ) ;
2008-06-10 20:21:00 +04:00
return ret ;
}
2009-11-24 18:53:59 +03:00
static void zfcp_fc_validate_port ( struct zfcp_port * port , struct list_head * lh )
2008-06-10 20:21:00 +04:00
{
2009-04-17 17:08:13 +04:00
if ( ! ( atomic_read ( & port - > status ) & ZFCP_STATUS_COMMON_NOESC ) )
return ;
2008-06-10 20:21:00 +04:00
atomic_clear_mask ( ZFCP_STATUS_COMMON_NOESC , & port - > status ) ;
2008-10-01 14:42:20 +04:00
if ( ( port - > supported_classes ! = 0 ) | |
2009-11-24 18:53:59 +03:00
! list_empty ( & port - > unit_list ) )
2008-06-10 20:21:00 +04:00
return ;
2009-11-24 18:53:59 +03:00
list_move_tail ( & port - > list , lh ) ;
2008-06-10 20:21:00 +04:00
}
2009-11-24 18:54:13 +03:00
static int zfcp_fc_eval_gpn_ft ( struct zfcp_fc_gpn_ft * gpn_ft ,
struct zfcp_adapter * adapter , int max_entries )
2008-06-10 20:21:00 +04:00
{
2009-11-24 18:54:13 +03:00
struct zfcp_fsf_ct_els * ct = & gpn_ft - > ct ;
2008-06-10 20:21:00 +04:00
struct scatterlist * sg = gpn_ft - > sg_resp ;
2009-11-24 18:54:10 +03:00
struct fc_ct_hdr * hdr = sg_virt ( sg ) ;
struct fc_gpn_ft_resp * acc = sg_virt ( sg ) ;
2008-06-10 20:21:00 +04:00
struct zfcp_port * port , * tmp ;
2009-11-24 18:53:58 +03:00
unsigned long flags ;
2009-11-24 18:53:59 +03:00
LIST_HEAD ( remove_lh ) ;
2008-06-10 20:21:00 +04:00
u32 d_id ;
2008-08-21 15:43:33 +04:00
int ret = 0 , x , last = 0 ;
2008-06-10 20:21:00 +04:00
if ( ct - > status )
return - EIO ;
2009-11-24 18:54:10 +03:00
if ( hdr - > ct_cmd ! = FC_FS_ACC ) {
if ( hdr - > ct_reason = = FC_BA_RJT_UNABLE )
2008-06-10 20:21:00 +04:00
return - EAGAIN ; /* might be a temporary condition */
return - EIO ;
}
2009-11-24 18:54:10 +03:00
if ( hdr - > ct_mr_size ) {
2008-12-19 18:57:01 +03:00
dev_warn ( & adapter - > ccw_device - > dev ,
" The name server reported %d words residual data \n " ,
2009-11-24 18:54:10 +03:00
hdr - > ct_mr_size ) ;
2008-06-10 20:21:00 +04:00
return - E2BIG ;
2008-12-19 18:57:01 +03:00
}
2008-06-10 20:21:00 +04:00
/* first entry is the header */
2008-12-19 18:57:01 +03:00
for ( x = 1 ; x < max_entries & & ! last ; x + + ) {
2009-11-24 18:54:10 +03:00
if ( x % ( ZFCP_FC_GPN_FT_ENT_PAGE + 1 ) )
2008-06-10 20:21:00 +04:00
acc + + ;
else
acc = sg_virt ( + + sg ) ;
2009-11-24 18:54:10 +03:00
last = acc - > fp_flags & FC_NS_FID_LAST ;
d_id = ntoh24 ( acc - > fp_fid ) ;
2008-06-10 20:21:00 +04:00
2008-10-01 14:42:17 +04:00
/* don't attach ports with a well known address */
2009-11-24 18:54:10 +03:00
if ( d_id > = FC_FID_WELL_KNOWN_BASE )
2008-10-01 14:42:17 +04:00
continue ;
2008-06-10 20:21:00 +04:00
/* skip the adapter's port and known remote ports */
2009-11-24 18:54:10 +03:00
if ( acc - > fp_wwpn = = fc_host_port_name ( adapter - > scsi_host ) )
2008-06-10 20:21:00 +04:00
continue ;
2009-11-24 18:54:10 +03:00
port = zfcp_port_enqueue ( adapter , acc - > fp_wwpn ,
2008-06-10 20:21:00 +04:00
ZFCP_STATUS_COMMON_NOESC , d_id ) ;
2009-11-24 18:53:58 +03:00
if ( ! IS_ERR ( port ) )
2009-03-02 15:09:04 +03:00
zfcp_erp_port_reopen ( port , 0 , " fcegpf1 " , NULL ) ;
2009-11-24 18:53:58 +03:00
else if ( PTR_ERR ( port ) ! = - EEXIST )
ret = PTR_ERR ( port ) ;
2008-06-10 20:21:00 +04:00
}
zfcp_erp_wait ( adapter ) ;
2009-11-24 18:53:58 +03:00
write_lock_irqsave ( & adapter - > port_list_lock , flags ) ;
list_for_each_entry_safe ( port , tmp , & adapter - > port_list , list )
2009-11-24 18:53:59 +03:00
zfcp_fc_validate_port ( port , & remove_lh ) ;
2009-11-24 18:53:58 +03:00
write_unlock_irqrestore ( & adapter - > port_list_lock , flags ) ;
2009-11-24 18:53:59 +03:00
list_for_each_entry_safe ( port , tmp , & remove_lh , list ) {
zfcp_erp_port_shutdown ( port , 0 , " fcegpf2 " , NULL ) ;
2010-02-17 13:18:56 +03:00
zfcp_device_unregister ( & port - > dev , & zfcp_sysfs_port_attrs ) ;
2009-11-24 18:53:59 +03:00
}
2008-06-10 20:21:00 +04:00
return ret ;
}
/**
2009-08-18 17:43:23 +04:00
* zfcp_fc_scan_ports - scan remote ports and attach new ports
2009-11-24 18:54:06 +03:00
* @ work : reference to scheduled work
2008-06-10 20:21:00 +04:00
*/
2009-11-24 18:54:06 +03:00
void zfcp_fc_scan_ports ( struct work_struct * work )
2008-06-10 20:21:00 +04:00
{
2009-11-24 18:54:06 +03:00
struct zfcp_adapter * adapter = container_of ( work , struct zfcp_adapter ,
scan_work ) ;
2008-06-10 20:21:00 +04:00
int ret , i ;
2009-11-24 18:54:10 +03:00
struct zfcp_fc_gpn_ft * gpn_ft ;
2008-12-19 18:57:01 +03:00
int chain , max_entries , buf_num , max_bytes ;
chain = adapter - > adapter_features & FSF_FEATURE_ELS_CT_CHAINED_SBALS ;
2009-11-24 18:54:10 +03:00
buf_num = chain ? ZFCP_FC_GPN_FT_NUM_BUFS : 1 ;
max_entries = chain ? ZFCP_FC_GPN_FT_MAX_ENT : ZFCP_FC_GPN_FT_ENT_PAGE ;
max_bytes = chain ? ZFCP_FC_GPN_FT_MAX_SIZE : ZFCP_FC_CT_SIZE_PAGE ;
2008-06-10 20:21:00 +04:00
2009-04-17 17:08:02 +04:00
if ( fc_host_port_type ( adapter - > scsi_host ) ! = FC_PORTTYPE_NPORT & &
fc_host_port_type ( adapter - > scsi_host ) ! = FC_PORTTYPE_NPIV )
2009-11-24 18:54:06 +03:00
return ;
2008-06-10 20:21:00 +04:00
2009-11-24 18:54:06 +03:00
if ( zfcp_fc_wka_port_get ( & adapter - > gs - > ds ) )
return ;
2008-06-10 20:21:00 +04:00
2008-12-19 18:57:01 +03:00
gpn_ft = zfcp_alloc_sg_env ( buf_num ) ;
2009-11-24 18:54:06 +03:00
if ( ! gpn_ft )
2008-10-01 14:42:17 +04:00
goto out ;
2008-06-10 20:21:00 +04:00
for ( i = 0 ; i < 3 ; i + + ) {
2009-08-18 17:43:23 +04:00
ret = zfcp_fc_send_gpn_ft ( gpn_ft , adapter , max_bytes ) ;
2008-06-10 20:21:00 +04:00
if ( ! ret ) {
2009-11-24 18:54:13 +03:00
ret = zfcp_fc_eval_gpn_ft ( gpn_ft , adapter , max_entries ) ;
2008-06-10 20:21:00 +04:00
if ( ret = = - EAGAIN )
ssleep ( 1 ) ;
else
break ;
}
}
2008-12-19 18:57:01 +03:00
zfcp_free_sg_env ( gpn_ft , buf_num ) ;
2008-10-01 14:42:17 +04:00
out :
2009-08-18 17:43:23 +04:00
zfcp_fc_wka_port_put ( & adapter - > gs - > ds ) ;
2008-06-10 20:21:00 +04:00
}
2009-11-24 18:54:13 +03:00
static void zfcp_fc_ct_els_job_handler ( void * data )
2009-04-06 20:31:47 +04:00
{
2009-11-24 18:54:13 +03:00
struct fc_bsg_job * job = data ;
struct zfcp_fsf_ct_els * zfcp_ct_els = job - > dd_data ;
2010-01-26 19:49:19 +03:00
struct fc_bsg_reply * jr = job - > reply ;
2009-04-06 20:31:47 +04:00
2010-01-26 19:49:19 +03:00
jr - > reply_payload_rcv_len = job - > reply_payload . payload_len ;
jr - > reply_data . ctels_reply . status = FC_CTELS_STATUS_OK ;
jr - > result = zfcp_ct_els - > status ? - EIO : 0 ;
2009-04-06 20:31:47 +04:00
job - > job_done ( job ) ;
}
2010-01-13 19:52:36 +03:00
static struct zfcp_fc_wka_port * zfcp_fc_job_wka_port ( struct fc_bsg_job * job )
{
u32 preamble_word1 ;
u8 gs_type ;
struct zfcp_adapter * adapter ;
preamble_word1 = job - > request - > rqst_data . r_ct . preamble_word1 ;
gs_type = ( preamble_word1 & 0xff000000 ) > > 24 ;
adapter = ( struct zfcp_adapter * ) job - > shost - > hostdata [ 0 ] ;
switch ( gs_type ) {
case FC_FST_ALIAS :
return & adapter - > gs - > as ;
case FC_FST_MGMT :
return & adapter - > gs - > ms ;
case FC_FST_TIME :
return & adapter - > gs - > ts ;
break ;
case FC_FST_DIR :
return & adapter - > gs - > ds ;
break ;
default :
return NULL ;
}
}
static void zfcp_fc_ct_job_handler ( void * data )
{
struct fc_bsg_job * job = data ;
struct zfcp_fc_wka_port * wka_port ;
wka_port = zfcp_fc_job_wka_port ( job ) ;
zfcp_fc_wka_port_put ( wka_port ) ;
zfcp_fc_ct_els_job_handler ( data ) ;
}
2009-11-24 18:54:13 +03:00
static int zfcp_fc_exec_els_job ( struct fc_bsg_job * job ,
struct zfcp_adapter * adapter )
2009-04-06 20:31:47 +04:00
{
2009-11-24 18:54:13 +03:00
struct zfcp_fsf_ct_els * els = job - > dd_data ;
2009-04-06 20:31:47 +04:00
struct fc_rport * rport = job - > rport ;
struct zfcp_port * port ;
2009-11-24 18:54:13 +03:00
u32 d_id ;
2009-04-06 20:31:47 +04:00
if ( rport ) {
2009-08-18 17:43:24 +04:00
port = zfcp_get_port_by_wwpn ( adapter , rport - > port_name ) ;
2009-11-24 18:54:13 +03:00
if ( ! port )
2009-04-06 20:31:47 +04:00
return - EINVAL ;
2009-11-24 18:53:58 +03:00
2009-11-24 18:54:13 +03:00
d_id = port - > d_id ;
2010-02-17 13:18:56 +03:00
put_device ( & port - > dev ) ;
2009-11-24 18:54:13 +03:00
} else
d_id = ntoh24 ( job - > request - > rqst_data . h_els . port_id ) ;
2009-04-06 20:31:47 +04:00
2010-01-13 19:52:36 +03:00
els - > handler = zfcp_fc_ct_els_job_handler ;
2010-01-14 19:19:02 +03:00
return zfcp_fsf_send_els ( adapter , d_id , els , job - > req - > timeout / HZ ) ;
2009-04-06 20:31:47 +04:00
}
2009-11-24 18:54:13 +03:00
static int zfcp_fc_exec_ct_job ( struct fc_bsg_job * job ,
struct zfcp_adapter * adapter )
2009-04-06 20:31:47 +04:00
{
int ret ;
2009-11-24 18:54:13 +03:00
struct zfcp_fsf_ct_els * ct = job - > dd_data ;
struct zfcp_fc_wka_port * wka_port ;
2009-04-06 20:31:47 +04:00
2010-01-13 19:52:36 +03:00
wka_port = zfcp_fc_job_wka_port ( job ) ;
if ( ! wka_port )
return - EINVAL ;
2009-04-06 20:31:47 +04:00
2009-11-24 18:54:13 +03:00
ret = zfcp_fc_wka_port_get ( wka_port ) ;
if ( ret )
2009-04-06 20:31:47 +04:00
return ret ;
2010-01-13 19:52:36 +03:00
ct - > handler = zfcp_fc_ct_job_handler ;
2010-01-14 19:19:02 +03:00
ret = zfcp_fsf_send_ct ( wka_port , ct , NULL , job - > req - > timeout / HZ ) ;
2009-11-24 18:54:13 +03:00
if ( ret )
zfcp_fc_wka_port_put ( wka_port ) ;
2009-04-06 20:31:47 +04:00
return ret ;
}
2009-08-18 17:43:22 +04:00
2009-11-24 18:54:13 +03:00
int zfcp_fc_exec_bsg_job ( struct fc_bsg_job * job )
{
struct Scsi_Host * shost ;
struct zfcp_adapter * adapter ;
struct zfcp_fsf_ct_els * ct_els = job - > dd_data ;
shost = job - > rport ? rport_to_shost ( job - > rport ) : job - > shost ;
adapter = ( struct zfcp_adapter * ) shost - > hostdata [ 0 ] ;
if ( ! ( atomic_read ( & adapter - > status ) & ZFCP_STATUS_COMMON_OPEN ) )
return - EINVAL ;
ct_els - > req = job - > request_payload . sg_list ;
ct_els - > resp = job - > reply_payload . sg_list ;
ct_els - > handler_data = job ;
switch ( job - > request - > msgcode ) {
case FC_BSG_RPT_ELS :
case FC_BSG_HST_ELS_NOLOGIN :
return zfcp_fc_exec_els_job ( job , adapter ) ;
case FC_BSG_RPT_CT :
case FC_BSG_HST_CT :
return zfcp_fc_exec_ct_job ( job , adapter ) ;
default :
return - EINVAL ;
}
}
2010-01-14 19:19:01 +03:00
int zfcp_fc_timeout_bsg_job ( struct fc_bsg_job * job )
{
/* hardware tracks timeout, reset bsg timeout to not interfere */
return - EAGAIN ;
}
2009-08-18 17:43:22 +04:00
int zfcp_fc_gs_setup ( struct zfcp_adapter * adapter )
{
2009-11-24 18:54:11 +03:00
struct zfcp_fc_wka_ports * wka_ports ;
2009-08-18 17:43:22 +04:00
2009-11-24 18:54:11 +03:00
wka_ports = kzalloc ( sizeof ( struct zfcp_fc_wka_ports ) , GFP_KERNEL ) ;
2009-08-18 17:43:22 +04:00
if ( ! wka_ports )
return - ENOMEM ;
adapter - > gs = wka_ports ;
zfcp_fc_wka_port_init ( & wka_ports - > ms , FC_FID_MGMT_SERV , adapter ) ;
zfcp_fc_wka_port_init ( & wka_ports - > ts , FC_FID_TIME_SERV , adapter ) ;
zfcp_fc_wka_port_init ( & wka_ports - > ds , FC_FID_DIR_SERV , adapter ) ;
zfcp_fc_wka_port_init ( & wka_ports - > as , FC_FID_ALIASES , adapter ) ;
return 0 ;
}
void zfcp_fc_gs_destroy ( struct zfcp_adapter * adapter )
{
kfree ( adapter - > gs ) ;
adapter - > gs = NULL ;
}