2008-12-10 02:10:17 +03:00
/*
* Copyright ( c ) 2008 Intel Corporation . All rights reserved .
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms and conditions of the GNU General Public License ,
* version 2 , as published by the Free Software Foundation .
*
* This program is distributed in the hope 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 . ,
* 51 Franklin St - Fifth Floor , Boston , MA 02110 - 1301 USA .
*
* Maintained at www . Open - FCoE . org
*/
/*
* Provide interface to send ELS / CT FC frames
*/
2011-05-27 17:37:25 +04:00
# include <linux/export.h>
2008-12-10 02:10:17 +03:00
# include <asm/unaligned.h>
# include <scsi/fc/fc_gs.h>
# include <scsi/fc/fc_ns.h>
# include <scsi/fc/fc_els.h>
# include <scsi/libfc.h>
# include <scsi/fc_encode.h>
2012-01-14 05:26:20 +04:00
# include "fc_libfc.h"
2008-12-10 02:10:17 +03:00
2009-11-03 22:47:39 +03:00
/**
* fc_elsct_send ( ) - Send an ELS or CT frame
* @ lport : The local port to send the frame on
* @ did : The destination ID for the frame
* @ fp : The frame to be sent
* @ op : The operational code
* @ resp : The callback routine when the response is received
* @ arg : The argument to pass to the response callback routine
* @ timer_msec : The timeout period for the frame ( in msecs )
2008-12-10 02:10:17 +03:00
*/
2009-11-03 22:47:39 +03:00
struct fc_seq * fc_elsct_send ( struct fc_lport * lport , u32 did ,
struct fc_frame * fp , unsigned int op ,
void ( * resp ) ( struct fc_seq * ,
struct fc_frame * ,
void * ) ,
void * arg , u32 timer_msec )
2008-12-10 02:10:17 +03:00
{
enum fc_rctl r_ctl ;
enum fc_fh_type fh_type ;
int rc ;
/* ELS requests */
if ( ( op > = ELS_LS_RJT ) & & ( op < = ELS_AUTH_ELS ) )
2009-08-26 01:00:55 +04:00
rc = fc_els_fill ( lport , did , fp , op , & r_ctl , & fh_type ) ;
else {
2008-12-10 02:10:17 +03:00
/* CT requests */
2012-01-23 05:30:00 +04:00
rc = fc_ct_fill ( lport , did , fp , op , & r_ctl , & fh_type , & did ) ;
2009-08-26 01:00:55 +04:00
}
2008-12-10 02:10:17 +03:00
2009-10-22 03:28:09 +04:00
if ( rc ) {
fc_frame_free ( fp ) ;
2008-12-10 02:10:17 +03:00
return NULL ;
2009-10-22 03:28:09 +04:00
}
2008-12-10 02:10:17 +03:00
2010-05-08 02:18:41 +04:00
fc_fill_fc_hdr ( fp , r_ctl , did , lport - > port_id , fh_type ,
2010-07-21 02:21:01 +04:00
FC_FCTL_REQ , 0 ) ;
2008-12-10 02:10:17 +03:00
return lport - > tt . exch_seq_send ( lport , fp , resp , NULL , arg , timer_msec ) ;
}
2009-11-03 22:46:29 +03:00
EXPORT_SYMBOL ( fc_elsct_send ) ;
2008-12-10 02:10:17 +03:00
2009-11-03 22:47:39 +03:00
/**
* fc_elsct_init ( ) - Initialize the ELS / CT layer
* @ lport : The local port to initialize the ELS / CT layer for
*/
2008-12-10 02:10:17 +03:00
int fc_elsct_init ( struct fc_lport * lport )
{
if ( ! lport - > tt . elsct_send )
lport - > tt . elsct_send = fc_elsct_send ;
return 0 ;
}
EXPORT_SYMBOL ( fc_elsct_init ) ;
2009-08-26 01:03:21 +04:00
/**
2009-11-03 22:47:39 +03:00
* fc_els_resp_type ( ) - Return a string describing the ELS response
* @ fp : The frame pointer or possible error code
2009-08-26 01:03:21 +04:00
*/
const char * fc_els_resp_type ( struct fc_frame * fp )
{
const char * msg ;
2009-11-03 22:49:00 +03:00
struct fc_frame_header * fh ;
struct fc_ct_hdr * ct ;
2009-08-26 01:03:21 +04:00
if ( IS_ERR ( fp ) ) {
switch ( - PTR_ERR ( fp ) ) {
case FC_NO_ERR :
msg = " response no error " ;
break ;
case FC_EX_TIMEOUT :
msg = " response timeout " ;
break ;
case FC_EX_CLOSED :
msg = " response closed " ;
break ;
default :
msg = " response unknown error " ;
break ;
}
} else {
2009-11-03 22:49:00 +03:00
fh = fc_frame_header_get ( fp ) ;
switch ( fh - > fh_type ) {
case FC_TYPE_ELS :
switch ( fc_frame_payload_op ( fp ) ) {
case ELS_LS_ACC :
msg = " accept " ;
break ;
case ELS_LS_RJT :
msg = " reject " ;
break ;
default :
msg = " response unknown ELS " ;
break ;
}
2009-08-26 01:03:21 +04:00
break ;
2009-11-03 22:49:00 +03:00
case FC_TYPE_CT :
ct = fc_frame_payload_get ( fp , sizeof ( * ct ) ) ;
if ( ct ) {
switch ( ntohs ( ct - > ct_cmd ) ) {
case FC_FS_ACC :
msg = " CT accept " ;
break ;
case FC_FS_RJT :
msg = " CT reject " ;
break ;
default :
msg = " response unknown CT " ;
break ;
}
} else {
msg = " short CT response " ;
}
2009-08-26 01:03:21 +04:00
break ;
default :
2009-11-03 22:49:00 +03:00
msg = " response not ELS or CT " ;
2009-08-26 01:03:21 +04:00
break ;
}
}
return msg ;
}