2007-09-07 11:15:31 +04:00
/*
2008-06-10 20:20:58 +04:00
* zfcp device driver
2005-04-17 02:20:36 +04:00
*
2008-06-10 20:20:58 +04:00
* Interface to Linux SCSI midlayer .
2007-09-07 11:15:31 +04:00
*
2008-06-10 20:20:58 +04:00
* Copyright IBM Corporation 2002 , 2008
2005-04-17 02:20:36 +04:00
*/
# include "zfcp_ext.h"
2007-05-08 13:16:52 +04:00
# include <asm/atomic.h>
2005-04-17 02:20:36 +04:00
/* Find start of Sense Information in FCP response unit*/
2008-07-02 12:56:36 +04:00
char * zfcp_get_fcp_sns_info_ptr ( struct fcp_rsp_iu * fcp_rsp_iu )
2005-04-17 02:20:36 +04:00
{
char * fcp_sns_info_ptr ;
2008-07-02 12:56:36 +04:00
fcp_sns_info_ptr = ( unsigned char * ) & fcp_rsp_iu [ 1 ] ;
2005-04-17 02:20:36 +04:00
if ( fcp_rsp_iu - > validity . bits . fcp_rsp_len_valid )
2008-07-02 12:56:36 +04:00
fcp_sns_info_ptr + = fcp_rsp_iu - > fcp_rsp_len ;
2005-04-17 02:20:36 +04:00
return fcp_sns_info_ptr ;
}
2006-08-02 13:05:52 +04:00
static void zfcp_scsi_slave_destroy ( struct scsi_device * sdpnt )
2005-04-17 02:20:36 +04:00
{
struct zfcp_unit * unit = ( struct zfcp_unit * ) sdpnt - > hostdata ;
2008-06-10 20:20:58 +04:00
WARN_ON ( ! unit ) ;
2005-04-17 02:20:36 +04:00
if ( unit ) {
2006-03-10 02:56:16 +03:00
atomic_clear_mask ( ZFCP_STATUS_UNIT_REGISTERED , & unit - > status ) ;
2005-04-17 02:20:36 +04:00
sdpnt - > hostdata = NULL ;
unit - > device = NULL ;
2008-04-18 14:51:55 +04:00
zfcp_erp_unit_failed ( unit , 12 , NULL ) ;
2005-04-17 02:20:36 +04:00
zfcp_unit_put ( unit ) ;
2008-06-10 20:20:58 +04:00
}
2005-04-17 02:20:36 +04:00
}
2008-07-02 12:56:36 +04:00
static int zfcp_scsi_slave_configure ( struct scsi_device * sdp )
2005-04-17 02:20:36 +04:00
{
if ( sdp - > tagged_supported )
2008-07-02 12:56:36 +04:00
scsi_adjust_queue_depth ( sdp , MSG_SIMPLE_TAG , 32 ) ;
2005-04-17 02:20:36 +04:00
else
scsi_adjust_queue_depth ( sdp , 0 , 1 ) ;
return 0 ;
}
2008-07-02 12:56:36 +04:00
static void zfcp_scsi_command_fail ( struct scsi_cmnd * scpnt , int result )
2005-04-17 02:20:36 +04:00
{
2008-07-02 12:56:35 +04:00
set_host_byte ( scpnt , result ) ;
2005-09-13 23:50:38 +04:00
if ( ( scpnt - > device ! = NULL ) & & ( scpnt - > device - > host ! = NULL ) )
zfcp_scsi_dbf_event_result ( " fail " , 4 ,
( struct zfcp_adapter * ) scpnt - > device - > host - > hostdata [ 0 ] ,
2006-02-11 03:42:58 +03:00
scpnt , NULL ) ;
2005-04-17 02:20:36 +04:00
/* return directly */
scpnt - > scsi_done ( scpnt ) ;
}
2008-07-02 12:56:36 +04:00
static int zfcp_scsi_queuecommand ( struct scsi_cmnd * scpnt ,
void ( * done ) ( struct scsi_cmnd * ) )
2005-04-17 02:20:36 +04:00
{
struct zfcp_unit * unit ;
struct zfcp_adapter * adapter ;
2008-07-02 12:56:36 +04:00
int status ;
int ret ;
2005-04-17 02:20:36 +04:00
/* reset the status for this request */
scpnt - > result = 0 ;
scpnt - > host_scribble = NULL ;
scpnt - > scsi_done = done ;
/*
* figure out adapter and target device
* ( stored there by zfcp_scsi_slave_alloc )
*/
adapter = ( struct zfcp_adapter * ) scpnt - > device - > host - > hostdata [ 0 ] ;
2008-07-02 12:56:36 +04:00
unit = scpnt - > device - > hostdata ;
BUG_ON ( ! adapter | | ( adapter ! = unit - > port - > adapter ) ) ;
BUG_ON ( ! scpnt - > scsi_done ) ;
if ( unlikely ( ! unit ) ) {
zfcp_scsi_command_fail ( scpnt , DID_NO_CONNECT ) ;
return 0 ;
}
status = atomic_read ( & unit - > status ) ;
if ( unlikely ( ( status & ZFCP_STATUS_COMMON_ERP_FAILED ) | |
! ( status & ZFCP_STATUS_COMMON_RUNNING ) ) ) {
zfcp_scsi_command_fail ( scpnt , DID_ERROR ) ;
return 0 ; ;
}
ret = zfcp_fsf_send_fcp_command_task ( adapter , unit , scpnt , 0 ,
ZFCP_REQ_AUTO_CLEANUP ) ;
if ( unlikely ( ret = = - EBUSY ) )
zfcp_scsi_command_fail ( scpnt , DID_NO_CONNECT ) ;
else if ( unlikely ( ret < 0 ) )
return SCSI_MLQUEUE_HOST_BUSY ;
2005-04-17 02:20:36 +04:00
2008-07-02 12:56:36 +04:00
return ret ;
2005-04-17 02:20:36 +04:00
}
2008-07-02 12:56:36 +04:00
static struct zfcp_unit * zfcp_unit_lookup ( struct zfcp_adapter * adapter ,
int channel , unsigned int id ,
unsigned int lun )
2005-04-17 02:20:36 +04:00
{
struct zfcp_port * port ;
2008-07-02 12:56:36 +04:00
struct zfcp_unit * unit ;
2005-04-17 02:20:36 +04:00
list_for_each_entry ( port , & adapter - > port_list_head , list ) {
2005-08-27 22:07:54 +04:00
if ( ! port - > rport | | ( id ! = port - > rport - > scsi_target_id ) )
2005-04-17 02:20:36 +04:00
continue ;
2007-08-28 11:30:59 +04:00
list_for_each_entry ( unit , & port - > unit_list_head , list )
2008-07-02 12:56:36 +04:00
if ( lun = = unit - > scsi_lun )
return unit ;
2005-04-17 02:20:36 +04:00
}
2008-07-02 12:56:36 +04:00
return NULL ;
}
static int zfcp_scsi_slave_alloc ( struct scsi_device * sdp )
{
struct zfcp_adapter * adapter ;
struct zfcp_unit * unit ;
unsigned long flags ;
int retval = - ENXIO ;
adapter = ( struct zfcp_adapter * ) sdp - > host - > hostdata [ 0 ] ;
if ( ! adapter )
goto out ;
read_lock_irqsave ( & zfcp_data . config_lock , flags ) ;
unit = zfcp_unit_lookup ( adapter , sdp - > channel , sdp - > id , sdp - > lun ) ;
if ( unit & &
( atomic_read ( & unit - > status ) & ZFCP_STATUS_UNIT_REGISTERED ) ) {
sdp - > hostdata = unit ;
unit - > device = sdp ;
zfcp_unit_get ( unit ) ;
retval = 0 ;
}
read_unlock_irqrestore ( & zfcp_data . config_lock , flags ) ;
out :
2005-04-17 02:20:36 +04:00
return retval ;
}
2007-02-05 23:16:47 +03:00
static int zfcp_scsi_eh_abort_handler ( struct scsi_cmnd * scpnt )
2005-04-17 02:20:36 +04:00
{
2005-09-13 23:47:52 +04:00
struct Scsi_Host * scsi_host ;
struct zfcp_adapter * adapter ;
struct zfcp_unit * unit ;
2006-09-19 00:29:20 +04:00
struct zfcp_fsf_req * fsf_req ;
2005-04-17 02:20:36 +04:00
unsigned long flags ;
2008-07-02 12:56:36 +04:00
unsigned long old_req_id = ( unsigned long ) scpnt - > host_scribble ;
2006-09-19 00:29:20 +04:00
int retval = SUCCESS ;
2005-09-13 23:47:52 +04:00
scsi_host = scpnt - > device - > host ;
adapter = ( struct zfcp_adapter * ) scsi_host - > hostdata [ 0 ] ;
2008-07-02 12:56:36 +04:00
unit = scpnt - > device - > hostdata ;
2005-04-17 02:20:36 +04:00
2005-09-13 23:47:52 +04:00
/* avoid race condition between late normal completion and abort */
2005-04-17 02:20:36 +04:00
write_lock_irqsave ( & adapter - > abort_lock , flags ) ;
2006-09-19 00:29:20 +04:00
/* Check whether corresponding fsf_req is still pending */
spin_lock ( & adapter - > req_list_lock ) ;
2008-07-02 12:56:36 +04:00
fsf_req = zfcp_reqlist_find ( adapter , old_req_id ) ;
2006-09-19 00:29:20 +04:00
spin_unlock ( & adapter - > req_list_lock ) ;
if ( ! fsf_req ) {
2005-04-17 02:20:36 +04:00
write_unlock_irqrestore ( & adapter - > abort_lock , flags ) ;
2006-09-19 00:29:20 +04:00
zfcp_scsi_dbf_event_abort ( " lte1 " , adapter , scpnt , NULL , 0 ) ;
2008-07-02 12:56:36 +04:00
return retval ;
2005-04-17 02:20:36 +04:00
}
2008-07-02 12:56:39 +04:00
fsf_req - > data = NULL ;
2005-04-17 02:20:36 +04:00
2006-09-19 00:29:20 +04:00
/* don't access old fsf_req after releasing the abort_lock */
2005-04-17 02:20:36 +04:00
write_unlock_irqrestore ( & adapter - > abort_lock , flags ) ;
2006-09-19 00:29:20 +04:00
fsf_req = zfcp_fsf_abort_fcp_command ( old_req_id , adapter , unit , 0 ) ;
if ( ! fsf_req ) {
2006-02-11 03:42:58 +03:00
zfcp_scsi_dbf_event_abort ( " nres " , adapter , scpnt , NULL ,
2006-09-19 00:29:20 +04:00
old_req_id ) ;
2005-04-17 02:20:36 +04:00
retval = FAILED ;
2008-07-02 12:56:36 +04:00
return retval ;
2005-04-17 02:20:36 +04:00
}
2006-09-19 00:29:20 +04:00
__wait_event ( fsf_req - > completion_wq ,
fsf_req - > status & ZFCP_STATUS_FSFREQ_COMPLETED ) ;
2005-09-13 23:47:52 +04:00
2006-09-19 00:29:20 +04:00
if ( fsf_req - > status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED ) {
zfcp_scsi_dbf_event_abort ( " okay " , adapter , scpnt , fsf_req , 0 ) ;
} else if ( fsf_req - > status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED ) {
zfcp_scsi_dbf_event_abort ( " lte2 " , adapter , scpnt , fsf_req , 0 ) ;
2005-04-17 02:20:36 +04:00
} else {
2006-09-19 00:29:20 +04:00
zfcp_scsi_dbf_event_abort ( " fail " , adapter , scpnt , fsf_req , 0 ) ;
2005-04-17 02:20:36 +04:00
retval = FAILED ;
}
2006-09-19 00:29:20 +04:00
zfcp_fsf_req_free ( fsf_req ) ;
2005-04-17 02:20:36 +04:00
2008-07-02 12:56:36 +04:00
return retval ;
2005-04-17 02:20:36 +04:00
}
2008-07-02 12:56:36 +04:00
static int zfcp_task_mgmt_function ( struct zfcp_unit * unit , u8 tm_flags ,
struct scsi_cmnd * scpnt )
2005-04-17 02:20:36 +04:00
{
struct zfcp_adapter * adapter = unit - > port - > adapter ;
struct zfcp_fsf_req * fsf_req ;
2008-07-02 12:56:36 +04:00
int retval = SUCCESS ;
2005-04-17 02:20:36 +04:00
/* issue task management function */
2008-07-02 12:56:39 +04:00
fsf_req = zfcp_fsf_send_fcp_ctm ( adapter , unit , tm_flags , 0 ) ;
2005-04-17 02:20:36 +04:00
if ( ! fsf_req ) {
2005-09-13 23:50:38 +04:00
zfcp_scsi_dbf_event_devreset ( " nres " , tm_flags , unit , scpnt ) ;
2008-07-02 12:56:36 +04:00
return FAILED ;
2005-04-17 02:20:36 +04:00
}
2005-09-13 23:48:33 +04:00
__wait_event ( fsf_req - > completion_wq ,
fsf_req - > status & ZFCP_STATUS_FSFREQ_COMPLETED ) ;
2005-09-13 23:50:38 +04:00
/*
* check completion status of task management function
*/
if ( fsf_req - > status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED ) {
zfcp_scsi_dbf_event_devreset ( " fail " , tm_flags , unit , scpnt ) ;
2008-07-02 12:56:36 +04:00
retval = FAILED ;
2005-09-13 23:50:38 +04:00
} else if ( fsf_req - > status & ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP ) {
zfcp_scsi_dbf_event_devreset ( " nsup " , tm_flags , unit , scpnt ) ;
2008-07-02 12:56:36 +04:00
retval = FAILED ;
2005-09-13 23:50:38 +04:00
} else
zfcp_scsi_dbf_event_devreset ( " okay " , tm_flags , unit , scpnt ) ;
2005-09-13 23:48:33 +04:00
zfcp_fsf_req_free ( fsf_req ) ;
2008-07-02 12:56:36 +04:00
2005-04-17 02:20:36 +04:00
return retval ;
}
2008-07-02 12:56:36 +04:00
static int zfcp_scsi_eh_device_reset_handler ( struct scsi_cmnd * scpnt )
{
struct zfcp_unit * unit = scpnt - > device - > hostdata ;
if ( ! unit ) {
WARN_ON ( 1 ) ;
return SUCCESS ;
}
return zfcp_task_mgmt_function ( unit , FCP_LOGICAL_UNIT_RESET , scpnt ) ;
}
static int zfcp_scsi_eh_target_reset_handler ( struct scsi_cmnd * scpnt )
{
struct zfcp_unit * unit = scpnt - > device - > hostdata ;
if ( ! unit ) {
WARN_ON ( 1 ) ;
return SUCCESS ;
}
return zfcp_task_mgmt_function ( unit , FCP_TARGET_RESET , scpnt ) ;
}
2007-02-05 23:16:47 +03:00
static int zfcp_scsi_eh_host_reset_handler ( struct scsi_cmnd * scpnt )
2005-04-17 02:20:36 +04:00
{
2006-08-02 13:05:52 +04:00
struct zfcp_unit * unit ;
struct zfcp_adapter * adapter ;
2005-04-17 02:20:36 +04:00
2008-07-02 12:56:36 +04:00
unit = scpnt - > device - > hostdata ;
2006-08-02 13:05:52 +04:00
adapter = unit - > port - > adapter ;
2008-04-18 14:51:55 +04:00
zfcp_erp_adapter_reopen ( adapter , 0 , 141 , scpnt ) ;
2006-09-19 00:30:36 +04:00
zfcp_erp_wait ( adapter ) ;
2005-04-17 02:20:36 +04:00
2005-09-13 23:49:52 +04:00
return SUCCESS ;
2005-04-17 02:20:36 +04:00
}
2008-07-02 12:56:36 +04:00
int zfcp_adapter_scsi_register ( struct zfcp_adapter * adapter )
2005-04-17 02:20:36 +04:00
{
2008-07-02 12:56:36 +04:00
struct ccw_dev_id dev_id ;
2005-04-17 02:20:36 +04:00
2007-05-09 13:01:24 +04:00
if ( adapter - > scsi_host )
2008-07-02 12:56:36 +04:00
return 0 ;
2007-05-09 13:01:24 +04:00
2008-07-02 12:56:36 +04:00
ccw_device_get_id ( adapter - > ccw_device , & dev_id ) ;
2005-04-17 02:20:36 +04:00
/* register adapter as SCSI host with mid layer of SCSI stack */
adapter - > scsi_host = scsi_host_alloc ( & zfcp_data . scsi_host_template ,
sizeof ( struct zfcp_adapter * ) ) ;
if ( ! adapter - > scsi_host ) {
2008-06-10 20:20:58 +04:00
dev_err ( & adapter - > ccw_device - > dev ,
2008-10-01 14:42:15 +04:00
" Registering the FCP device with the "
" SCSI stack failed \n " ) ;
2008-07-02 12:56:36 +04:00
return - EIO ;
2005-04-17 02:20:36 +04:00
}
/* tell the SCSI stack some characteristics of this adapter */
adapter - > scsi_host - > max_id = 1 ;
adapter - > scsi_host - > max_lun = 1 ;
adapter - > scsi_host - > max_channel = 0 ;
2008-07-02 12:56:36 +04:00
adapter - > scsi_host - > unique_id = dev_id . devno ;
adapter - > scsi_host - > max_cmd_len = 255 ;
2006-09-19 00:28:49 +04:00
adapter - > scsi_host - > transportt = zfcp_data . scsi_transport_template ;
2005-04-17 02:20:36 +04:00
adapter - > scsi_host - > hostdata [ 0 ] = ( unsigned long ) adapter ;
if ( scsi_add_host ( adapter - > scsi_host , & adapter - > ccw_device - > dev ) ) {
scsi_host_put ( adapter - > scsi_host ) ;
2008-07-02 12:56:36 +04:00
return - EIO ;
2005-04-17 02:20:36 +04:00
}
2008-07-02 12:56:36 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2008-07-02 12:56:36 +04:00
void zfcp_adapter_scsi_unregister ( struct zfcp_adapter * adapter )
2005-04-17 02:20:36 +04:00
{
struct Scsi_Host * shost ;
2005-09-19 18:56:17 +04:00
struct zfcp_port * port ;
2005-04-17 02:20:36 +04:00
shost = adapter - > scsi_host ;
if ( ! shost )
return ;
2008-07-02 12:56:36 +04:00
2005-09-19 18:56:17 +04:00
read_lock_irq ( & zfcp_data . config_lock ) ;
list_for_each_entry ( port , & adapter - > port_list_head , list )
if ( port - > rport )
port - > rport = NULL ;
2008-07-02 12:56:36 +04:00
2005-09-19 18:56:17 +04:00
read_unlock_irq ( & zfcp_data . config_lock ) ;
2005-08-27 22:07:54 +04:00
fc_remove_host ( shost ) ;
2005-04-17 02:20:36 +04:00
scsi_remove_host ( shost ) ;
scsi_host_put ( shost ) ;
adapter - > scsi_host = NULL ;
return ;
}
2006-01-05 11:59:34 +03:00
static struct fc_host_statistics *
zfcp_init_fc_host_stats ( struct zfcp_adapter * adapter )
2005-04-17 02:20:36 +04:00
{
2006-01-05 11:59:34 +03:00
struct fc_host_statistics * fc_stats ;
2005-04-17 02:20:36 +04:00
2006-01-05 11:59:34 +03:00
if ( ! adapter - > fc_stats ) {
fc_stats = kmalloc ( sizeof ( * fc_stats ) , GFP_KERNEL ) ;
if ( ! fc_stats )
return NULL ;
adapter - > fc_stats = fc_stats ; /* freed in adater_dequeue */
}
memset ( adapter - > fc_stats , 0 , sizeof ( * adapter - > fc_stats ) ) ;
return adapter - > fc_stats ;
2005-04-17 02:20:36 +04:00
}
2008-07-02 12:56:36 +04:00
static void zfcp_adjust_fc_host_stats ( struct fc_host_statistics * fc_stats ,
struct fsf_qtcb_bottom_port * data ,
struct fsf_qtcb_bottom_port * old )
2005-04-17 02:20:36 +04:00
{
2008-07-02 12:56:36 +04:00
fc_stats - > seconds_since_last_reset =
data - > seconds_since_last_reset - old - > seconds_since_last_reset ;
2006-01-05 11:59:34 +03:00
fc_stats - > tx_frames = data - > tx_frames - old - > tx_frames ;
fc_stats - > tx_words = data - > tx_words - old - > tx_words ;
fc_stats - > rx_frames = data - > rx_frames - old - > rx_frames ;
fc_stats - > rx_words = data - > rx_words - old - > rx_words ;
fc_stats - > lip_count = data - > lip - old - > lip ;
fc_stats - > nos_count = data - > nos - old - > nos ;
fc_stats - > error_frames = data - > error_frames - old - > error_frames ;
fc_stats - > dumped_frames = data - > dumped_frames - old - > dumped_frames ;
fc_stats - > link_failure_count = data - > link_failure - old - > link_failure ;
fc_stats - > loss_of_sync_count = data - > loss_of_sync - old - > loss_of_sync ;
2008-07-02 12:56:36 +04:00
fc_stats - > loss_of_signal_count =
data - > loss_of_signal - old - > loss_of_signal ;
fc_stats - > prim_seq_protocol_err_count =
data - > psp_error_counts - old - > psp_error_counts ;
fc_stats - > invalid_tx_word_count =
data - > invalid_tx_words - old - > invalid_tx_words ;
2006-01-05 11:59:34 +03:00
fc_stats - > invalid_crc_count = data - > invalid_crcs - old - > invalid_crcs ;
2008-07-02 12:56:36 +04:00
fc_stats - > fcp_input_requests =
data - > input_requests - old - > input_requests ;
fc_stats - > fcp_output_requests =
data - > output_requests - old - > output_requests ;
fc_stats - > fcp_control_requests =
data - > control_requests - old - > control_requests ;
2006-01-05 11:59:34 +03:00
fc_stats - > fcp_input_megabytes = data - > input_mb - old - > input_mb ;
fc_stats - > fcp_output_megabytes = data - > output_mb - old - > output_mb ;
}
2005-04-17 02:20:36 +04:00
2008-07-02 12:56:36 +04:00
static void zfcp_set_fc_host_stats ( struct fc_host_statistics * fc_stats ,
struct fsf_qtcb_bottom_port * data )
2006-01-05 11:59:34 +03:00
{
fc_stats - > seconds_since_last_reset = data - > seconds_since_last_reset ;
fc_stats - > tx_frames = data - > tx_frames ;
fc_stats - > tx_words = data - > tx_words ;
fc_stats - > rx_frames = data - > rx_frames ;
fc_stats - > rx_words = data - > rx_words ;
fc_stats - > lip_count = data - > lip ;
fc_stats - > nos_count = data - > nos ;
fc_stats - > error_frames = data - > error_frames ;
fc_stats - > dumped_frames = data - > dumped_frames ;
fc_stats - > link_failure_count = data - > link_failure ;
fc_stats - > loss_of_sync_count = data - > loss_of_sync ;
fc_stats - > loss_of_signal_count = data - > loss_of_signal ;
fc_stats - > prim_seq_protocol_err_count = data - > psp_error_counts ;
fc_stats - > invalid_tx_word_count = data - > invalid_tx_words ;
fc_stats - > invalid_crc_count = data - > invalid_crcs ;
fc_stats - > fcp_input_requests = data - > input_requests ;
fc_stats - > fcp_output_requests = data - > output_requests ;
fc_stats - > fcp_control_requests = data - > control_requests ;
fc_stats - > fcp_input_megabytes = data - > input_mb ;
fc_stats - > fcp_output_megabytes = data - > output_mb ;
}
2008-07-02 12:56:36 +04:00
static struct fc_host_statistics * zfcp_get_fc_host_stats ( struct Scsi_Host * host )
2006-01-05 11:59:34 +03:00
{
struct zfcp_adapter * adapter ;
struct fc_host_statistics * fc_stats ;
struct fsf_qtcb_bottom_port * data ;
int ret ;
2008-07-02 12:56:36 +04:00
adapter = ( struct zfcp_adapter * ) host - > hostdata [ 0 ] ;
2006-01-05 11:59:34 +03:00
fc_stats = zfcp_init_fc_host_stats ( adapter ) ;
if ( ! fc_stats )
return NULL ;
2006-05-22 20:17:30 +04:00
data = kzalloc ( sizeof ( * data ) , GFP_KERNEL ) ;
2006-01-05 11:59:34 +03:00
if ( ! data )
return NULL ;
2007-08-28 11:31:09 +04:00
ret = zfcp_fsf_exchange_port_data_sync ( adapter , data ) ;
2006-01-05 11:59:34 +03:00
if ( ret ) {
kfree ( data ) ;
2008-07-02 12:56:36 +04:00
return NULL ;
2006-01-05 11:59:34 +03:00
}
if ( adapter - > stats_reset & &
( ( jiffies / HZ - adapter - > stats_reset ) <
2008-07-02 12:56:36 +04:00
data - > seconds_since_last_reset ) )
2006-01-05 11:59:34 +03:00
zfcp_adjust_fc_host_stats ( fc_stats , data ,
adapter - > stats_reset_data ) ;
2008-07-02 12:56:36 +04:00
else
2006-01-05 11:59:34 +03:00
zfcp_set_fc_host_stats ( fc_stats , data ) ;
kfree ( data ) ;
return fc_stats ;
2005-04-17 02:20:36 +04:00
}
2008-07-02 12:56:36 +04:00
static void zfcp_reset_fc_host_stats ( struct Scsi_Host * shost )
2005-04-17 02:20:36 +04:00
{
2006-01-05 11:59:34 +03:00
struct zfcp_adapter * adapter ;
2008-07-02 12:56:36 +04:00
struct fsf_qtcb_bottom_port * data ;
2006-01-05 11:59:34 +03:00
int ret ;
2005-04-17 02:20:36 +04:00
2006-01-05 11:59:34 +03:00
adapter = ( struct zfcp_adapter * ) shost - > hostdata [ 0 ] ;
2006-05-22 20:17:30 +04:00
data = kzalloc ( sizeof ( * data ) , GFP_KERNEL ) ;
2006-01-05 11:59:34 +03:00
if ( ! data )
return ;
2007-08-28 11:31:09 +04:00
ret = zfcp_fsf_exchange_port_data_sync ( adapter , data ) ;
2008-07-02 12:56:36 +04:00
if ( ret )
2007-08-08 12:47:02 +04:00
kfree ( data ) ;
2008-07-02 12:56:36 +04:00
else {
2006-01-05 11:59:34 +03:00
adapter - > stats_reset = jiffies / HZ ;
2008-07-02 12:56:36 +04:00
kfree ( adapter - > stats_reset_data ) ;
2006-01-05 11:59:34 +03:00
adapter - > stats_reset_data = data ; /* finally freed in
2008-07-02 12:56:36 +04:00
adapter_dequeue */
2006-01-05 11:59:34 +03:00
}
2005-04-17 02:20:36 +04:00
}
2008-06-10 20:20:59 +04:00
static void zfcp_get_host_port_state ( struct Scsi_Host * shost )
{
struct zfcp_adapter * adapter =
( struct zfcp_adapter * ) shost - > hostdata [ 0 ] ;
int status = atomic_read ( & adapter - > status ) ;
if ( ( status & ZFCP_STATUS_COMMON_RUNNING ) & &
! ( status & ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED ) )
fc_host_port_state ( shost ) = FC_PORTSTATE_ONLINE ;
else if ( status & ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED )
fc_host_port_state ( shost ) = FC_PORTSTATE_LINKDOWN ;
else if ( status & ZFCP_STATUS_COMMON_ERP_FAILED )
fc_host_port_state ( shost ) = FC_PORTSTATE_ERROR ;
else
fc_host_port_state ( shost ) = FC_PORTSTATE_UNKNOWN ;
}
2006-05-22 20:25:56 +04:00
static void zfcp_set_rport_dev_loss_tmo ( struct fc_rport * rport , u32 timeout )
{
rport - > dev_loss_tmo = timeout ;
}
2005-04-17 02:20:36 +04:00
struct fc_function_template zfcp_transport_functions = {
. show_starget_port_id = 1 ,
. show_starget_port_name = 1 ,
. show_starget_node_name = 1 ,
2005-08-27 22:07:54 +04:00
. show_rport_supported_classes = 1 ,
2006-05-22 20:24:33 +04:00
. show_rport_maxframe_size = 1 ,
2006-05-22 20:25:56 +04:00
. show_rport_dev_loss_tmo = 1 ,
2005-08-27 22:07:54 +04:00
. show_host_node_name = 1 ,
. show_host_port_name = 1 ,
2006-01-13 04:26:11 +03:00
. show_host_permanent_port_name = 1 ,
2005-08-27 22:07:54 +04:00
. show_host_supported_classes = 1 ,
2006-01-13 04:26:11 +03:00
. show_host_supported_speeds = 1 ,
2005-09-19 18:56:17 +04:00
. show_host_maxframe_size = 1 ,
2005-08-27 22:07:54 +04:00
. show_host_serial_number = 1 ,
2006-01-05 11:59:34 +03:00
. get_fc_host_stats = zfcp_get_fc_host_stats ,
. reset_fc_host_stats = zfcp_reset_fc_host_stats ,
2006-05-22 20:25:56 +04:00
. set_rport_dev_loss_tmo = zfcp_set_rport_dev_loss_tmo ,
2008-06-10 20:20:59 +04:00
. get_host_port_state = zfcp_get_host_port_state ,
. show_host_port_state = 1 ,
2006-01-05 11:59:34 +03:00
/* no functions registered for following dynamic attributes but
directly set by LLDD */
2006-01-13 04:26:11 +03:00
. show_host_port_type = 1 ,
2005-09-19 18:56:17 +04:00
. show_host_speed = 1 ,
. show_host_port_id = 1 ,
2007-08-28 11:31:09 +04:00
. disable_target_scan = 1 ,
2005-04-17 02:20:36 +04:00
} ;
2008-07-02 12:56:36 +04:00
struct zfcp_data zfcp_data = {
. scsi_host_template = {
. name = " zfcp " ,
. module = THIS_MODULE ,
. proc_name = " zfcp " ,
. slave_alloc = zfcp_scsi_slave_alloc ,
. slave_configure = zfcp_scsi_slave_configure ,
. slave_destroy = zfcp_scsi_slave_destroy ,
. queuecommand = zfcp_scsi_queuecommand ,
. eh_abort_handler = zfcp_scsi_eh_abort_handler ,
. eh_device_reset_handler = zfcp_scsi_eh_device_reset_handler ,
. eh_target_reset_handler = zfcp_scsi_eh_target_reset_handler ,
. eh_host_reset_handler = zfcp_scsi_eh_host_reset_handler ,
. can_queue = 4096 ,
. this_id = - 1 ,
. sg_tablesize = ZFCP_MAX_SBALES_PER_REQ ,
. cmd_per_lun = 1 ,
. use_clustering = 1 ,
. sdev_attrs = zfcp_sysfs_sdev_attrs ,
. max_sectors = ( ZFCP_MAX_SBALES_PER_REQ * 8 ) ,
2008-07-02 12:56:38 +04:00
. shost_attrs = zfcp_sysfs_shost_attrs ,
2008-07-02 12:56:36 +04:00
} ,
} ;