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
*
2009-03-02 15:09:08 +03:00
* Copyright IBM Corporation 2002 , 2009
2005-04-17 02:20:36 +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:08 +03:00
# include <linux/types.h>
# include <scsi/fc/fc_fcp.h>
2007-05-08 13:16:52 +04:00
# include <asm/atomic.h>
2009-08-18 17:43:08 +04:00
# include "zfcp_ext.h"
# include "zfcp_dbf.h"
2009-11-24 18:54:13 +03:00
# include "zfcp_fc.h"
2010-02-17 13:18:50 +03:00
# include "zfcp_reqlist.h"
2005-04-17 02:20:36 +04:00
2009-05-15 15:18:16 +04:00
static unsigned int default_depth = 32 ;
module_param_named ( queue_depth , default_depth , uint , 0600 ) ;
MODULE_PARM_DESC ( queue_depth , " Default queue depth for new SCSI devices " ) ;
2009-10-16 04:46:39 +04:00
static int zfcp_scsi_change_queue_depth ( struct scsi_device * sdev , int depth ,
int reason )
2009-05-15 15:18:16 +04:00
{
2009-10-16 04:47:11 +04:00
switch ( reason ) {
case SCSI_QDEPTH_DEFAULT :
scsi_adjust_queue_depth ( sdev , scsi_get_tag_type ( sdev ) , depth ) ;
break ;
case SCSI_QDEPTH_QFULL :
scsi_track_queue_full ( sdev , depth ) ;
break ;
case SCSI_QDEPTH_RAMP_UP :
scsi_adjust_queue_depth ( sdev , scsi_get_tag_type ( sdev ) , depth ) ;
break ;
default :
2009-10-16 04:46:39 +04:00
return - EOPNOTSUPP ;
2009-10-16 04:47:11 +04:00
}
2009-05-15 15:18:16 +04:00
return sdev - > queue_depth ;
}
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-11-04 18:35:05 +03:00
unit - > device = NULL ;
2009-11-24 18:53:59 +03:00
put_device ( & unit - > sysfs_device ) ;
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 )
2009-05-15 15:18:16 +04:00
scsi_adjust_queue_depth ( sdp , MSG_SIMPLE_TAG , default_depth ) ;
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
{
2009-08-18 17:43:21 +04:00
struct zfcp_adapter * adapter =
( struct zfcp_adapter * ) scpnt - > device - > host - > hostdata [ 0 ] ;
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 ) )
2009-08-18 17:43:21 +04:00
zfcp_dbf_scsi_result ( " fail " , 4 , adapter - > dbf , 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 ;
2009-03-02 15:09:08 +03:00
int status , scsi_result , ret ;
struct fc_rport * rport = starget_to_rport ( scsi_target ( scpnt - > device ) ) ;
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 ;
}
2009-03-02 15:09:08 +03:00
scsi_result = fc_remote_port_chkready ( rport ) ;
if ( unlikely ( scsi_result ) ) {
scpnt - > result = scsi_result ;
2009-08-18 17:43:21 +04:00
zfcp_dbf_scsi_result ( " fail " , 4 , adapter - > dbf , scpnt , NULL ) ;
2009-03-02 15:09:08 +03:00
scpnt - > scsi_done ( scpnt ) ;
return 0 ;
}
2008-07-02 12:56:36 +04:00
status = atomic_read ( & unit - > status ) ;
2009-11-24 18:54:07 +03:00
if ( unlikely ( status & ZFCP_STATUS_COMMON_ERP_FAILED ) & &
! ( atomic_read ( & unit - > port - > status ) &
ZFCP_STATUS_COMMON_ERP_FAILED ) ) {
/* only unit access denied, but port is good
* not covered by FC transport , have to fail here */
2008-07-02 12:56:36 +04:00
zfcp_scsi_command_fail ( scpnt , DID_ERROR ) ;
2009-08-18 22:18:35 +04:00
return 0 ;
2008-07-02 12:56:36 +04:00
}
2009-11-24 18:54:07 +03:00
if ( unlikely ( ! ( status & ZFCP_STATUS_COMMON_UNBLOCKED ) ) ) {
/* This could be either
* open unit pending : this is temporary , will result in
* open unit or ERP_FAILED , so retry command
* call to rport_delete pending : mimic retry from
* fc_remote_port_chkready until rport is BLOCKED
*/
zfcp_scsi_command_fail ( scpnt , DID_IMM_RETRY ) ;
return 0 ;
}
2009-03-02 15:09:00 +03:00
ret = zfcp_fsf_send_fcp_command_task ( unit , scpnt ) ;
2008-07-02 12:56:36 +04:00
if ( unlikely ( ret = = - EBUSY ) )
2008-11-27 13:44:07 +03:00
return SCSI_MLQUEUE_DEVICE_BUSY ;
2008-07-02 12:56:36 +04:00
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 ,
2009-11-24 18:53:58 +03:00
unsigned int id , u64 lun )
2005-04-17 02:20:36 +04:00
{
2009-11-24 18:53:58 +03:00
unsigned long flags ;
2005-04-17 02:20:36 +04:00
struct zfcp_port * port ;
2009-11-24 18:53:58 +03:00
struct zfcp_unit * unit = NULL ;
2005-04-17 02:20:36 +04:00
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 ) {
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 ;
2009-11-24 18:53:58 +03:00
unit = zfcp_get_unit_by_lun ( port , lun ) ;
if ( unit )
break ;
2005-04-17 02:20:36 +04:00
}
2009-11-24 18:53:58 +03:00
read_unlock_irqrestore ( & adapter - > port_list_lock , flags ) ;
2008-07-02 12:56:36 +04:00
2009-11-24 18:53:58 +03:00
return unit ;
2008-07-02 12:56:36 +04:00
}
static int zfcp_scsi_slave_alloc ( struct scsi_device * sdp )
{
struct zfcp_adapter * adapter ;
struct zfcp_unit * unit ;
2009-11-24 18:53:58 +03:00
u64 lun ;
2008-07-02 12:56:36 +04:00
adapter = ( struct zfcp_adapter * ) sdp - > host - > hostdata [ 0 ] ;
if ( ! adapter )
goto out ;
2009-11-24 18:53:58 +03:00
int_to_scsilun ( sdp - > lun , ( struct scsi_lun * ) & lun ) ;
unit = zfcp_unit_lookup ( adapter , sdp - > id , lun ) ;
2009-03-02 15:08:55 +03:00
if ( unit ) {
2008-07-02 12:56:36 +04:00
sdp - > hostdata = unit ;
unit - > device = sdp ;
2009-11-24 18:53:58 +03:00
return 0 ;
2008-07-02 12:56:36 +04:00
}
out :
2009-11-24 18:53:58 +03:00
return - ENXIO ;
2005-04-17 02:20:36 +04:00
}
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
{
2009-03-02 15:09:00 +03:00
struct Scsi_Host * scsi_host = scpnt - > device - > host ;
struct zfcp_adapter * adapter =
( struct zfcp_adapter * ) scsi_host - > hostdata [ 0 ] ;
struct zfcp_unit * unit = scpnt - > device - > hostdata ;
struct zfcp_fsf_req * old_req , * abrt_req ;
2005-04-17 02:20:36 +04:00
unsigned long flags ;
2009-07-13 17:06:14 +04:00
unsigned long old_reqid = ( unsigned long ) scpnt - > host_scribble ;
2006-09-19 00:29:20 +04:00
int retval = SUCCESS ;
2009-03-02 15:09:00 +03:00
int retry = 3 ;
2009-07-13 17:06:14 +04:00
char * dbf_tag ;
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 ) ;
2010-02-17 13:18:50 +03:00
old_req = zfcp_reqlist_find ( adapter - > req_list , old_reqid ) ;
2009-03-02 15:09:00 +03:00
if ( ! old_req ) {
2005-04-17 02:20:36 +04:00
write_unlock_irqrestore ( & adapter - > abort_lock , flags ) ;
2009-08-18 17:43:21 +04:00
zfcp_dbf_scsi_abort ( " lte1 " , adapter - > dbf , scpnt , NULL ,
old_reqid ) ;
2009-04-17 17:08:11 +04:00
return FAILED ; /* completion could be in progress */
2005-04-17 02:20:36 +04:00
}
2009-03-02 15:09:00 +03:00
old_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
2009-03-02 15:09:00 +03:00
while ( retry - - ) {
2009-07-13 17:06:14 +04:00
abrt_req = zfcp_fsf_abort_fcp_command ( old_reqid , unit ) ;
2009-03-02 15:09:00 +03:00
if ( abrt_req )
break ;
zfcp_erp_wait ( adapter ) ;
2009-11-24 18:54:16 +03:00
fc_block_scsi_eh ( scpnt ) ;
2009-03-02 15:09:00 +03:00
if ( ! ( atomic_read ( & adapter - > status ) &
ZFCP_STATUS_COMMON_RUNNING ) ) {
2009-08-18 17:43:21 +04:00
zfcp_dbf_scsi_abort ( " nres " , adapter - > dbf , scpnt , NULL ,
old_reqid ) ;
2009-03-02 15:09:00 +03:00
return SUCCESS ;
}
2005-04-17 02:20:36 +04:00
}
2009-03-02 15:09:00 +03:00
if ( ! abrt_req )
return FAILED ;
2005-04-17 02:20:36 +04:00
2009-08-18 17:43:14 +04:00
wait_for_completion ( & abrt_req - > completion ) ;
2005-09-13 23:47:52 +04:00
2009-03-02 15:09:00 +03:00
if ( abrt_req - > status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED )
2009-07-13 17:06:14 +04:00
dbf_tag = " okay " ;
2009-03-02 15:09:00 +03:00
else if ( abrt_req - > status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED )
2009-07-13 17:06:14 +04:00
dbf_tag = " lte2 " ;
2009-03-02 15:09:00 +03:00
else {
2009-07-13 17:06:14 +04:00
dbf_tag = " fail " ;
2005-04-17 02:20:36 +04:00
retval = FAILED ;
}
2009-08-18 17:43:21 +04:00
zfcp_dbf_scsi_abort ( dbf_tag , adapter - > dbf , scpnt , abrt_req , old_reqid ) ;
2009-03-02 15:09:00 +03:00
zfcp_fsf_req_free ( abrt_req ) ;
2008-07-02 12:56:36 +04:00
return retval ;
2005-04-17 02:20:36 +04:00
}
2009-03-02 15:09:00 +03:00
static int zfcp_task_mgmt_function ( struct scsi_cmnd * scpnt , u8 tm_flags )
2005-04-17 02:20:36 +04:00
{
2009-03-02 15:09:00 +03:00
struct zfcp_unit * unit = scpnt - > device - > hostdata ;
2005-04-17 02:20:36 +04:00
struct zfcp_adapter * adapter = unit - > port - > adapter ;
2009-08-18 17:43:19 +04:00
struct zfcp_fsf_req * fsf_req = NULL ;
2008-07-02 12:56:36 +04:00
int retval = SUCCESS ;
2009-03-02 15:09:00 +03:00
int retry = 3 ;
while ( retry - - ) {
fsf_req = zfcp_fsf_send_fcp_ctm ( unit , tm_flags ) ;
if ( fsf_req )
break ;
zfcp_erp_wait ( adapter ) ;
2009-11-24 18:54:16 +03:00
fc_block_scsi_eh ( scpnt ) ;
2009-03-02 15:09:00 +03:00
if ( ! ( atomic_read ( & adapter - > status ) &
ZFCP_STATUS_COMMON_RUNNING ) ) {
2009-08-18 17:43:21 +04:00
zfcp_dbf_scsi_devreset ( " nres " , tm_flags , unit , scpnt ) ;
2009-03-02 15:09:00 +03:00
return SUCCESS ;
}
2005-04-17 02:20:36 +04:00
}
2009-03-02 15:09:00 +03:00
if ( ! fsf_req )
return FAILED ;
2005-04-17 02:20:36 +04:00
2009-08-18 17:43:14 +04:00
wait_for_completion ( & fsf_req - > completion ) ;
2005-09-13 23:48:33 +04:00
2005-09-13 23:50:38 +04:00
if ( fsf_req - > status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED ) {
2009-08-18 17:43:21 +04:00
zfcp_dbf_scsi_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
2009-08-18 17:43:21 +04:00
zfcp_dbf_scsi_devreset ( " okay " , tm_flags , unit , scpnt ) ;
2005-09-13 23:48:33 +04:00
zfcp_fsf_req_free ( fsf_req ) ;
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 )
{
2009-11-24 18:54:08 +03:00
return zfcp_task_mgmt_function ( scpnt , FCP_TMF_LUN_RESET ) ;
2008-07-02 12:56:36 +04:00
}
static int zfcp_scsi_eh_target_reset_handler ( struct scsi_cmnd * scpnt )
{
2009-11-24 18:54:08 +03:00
return zfcp_task_mgmt_function ( scpnt , FCP_TMF_TGT_RESET ) ;
2008-07-02 12:56:36 +04:00
}
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
{
2009-03-02 15:09:00 +03:00
struct zfcp_unit * unit = scpnt - > device - > hostdata ;
struct zfcp_adapter * adapter = unit - > port - > adapter ;
2005-04-17 02:20:36 +04:00
2009-03-02 15:09:04 +03:00
zfcp_erp_adapter_reopen ( adapter , 0 , " schrh_1 " , scpnt ) ;
2006-09-19 00:30:36 +04:00
zfcp_erp_wait ( adapter ) ;
2009-11-24 18:54:16 +03:00
fc_block_scsi_eh ( scpnt ) ;
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 ;
2009-11-24 18:54:08 +03:00
adapter - > scsi_host - > max_cmd_len = 16 ; /* in struct fcp_cmnd */
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
2009-11-24 18:53:58 +03:00
read_lock_irq ( & adapter - > port_list_lock ) ;
list_for_each_entry ( port , & adapter - > port_list , list )
2009-11-24 18:53:59 +03:00
port - > rport = NULL ;
2009-11-24 18:53:58 +03:00
read_unlock_irq ( & adapter - > port_list_lock ) ;
2008-07-02 12:56:36 +04:00
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 ;
2009-11-24 18:53:59 +03:00
adapter - > fc_stats = fc_stats ; /* freed in adapter_release */
2006-01-05 11:59:34 +03:00
}
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 ;
2009-08-18 17:43:19 +04:00
ret = zfcp_fsf_exchange_port_data_sync ( adapter - > qdio , 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 ;
2009-08-18 17:43:19 +04:00
ret = zfcp_fsf_exchange_port_data_sync ( adapter - > qdio , 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
2009-11-24 18:53:59 +03:00
adapter_release */
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 ;
}
2009-03-02 15:09:08 +03:00
/**
* zfcp_scsi_terminate_rport_io - Terminate all I / O on a rport
* @ rport : The FC rport where to teminate I / O
*
* Abort all pending SCSI commands for a port by closing the
2009-11-24 18:53:58 +03:00
* port . Using a reopen avoiding a conflict with a shutdown
2009-03-02 15:09:08 +03:00
* overwriting a reopen .
*/
static void zfcp_scsi_terminate_rport_io ( struct fc_rport * rport )
{
2009-04-17 17:08:15 +04:00
struct zfcp_port * port ;
2009-08-18 17:43:24 +04:00
struct Scsi_Host * shost = rport_to_shost ( rport ) ;
struct zfcp_adapter * adapter =
( struct zfcp_adapter * ) shost - > hostdata [ 0 ] ;
2009-04-17 17:08:15 +04:00
2009-08-18 17:43:24 +04:00
port = zfcp_get_port_by_wwpn ( adapter , rport - > port_name ) ;
2009-03-02 15:09:08 +03:00
2009-04-17 17:08:15 +04:00
if ( port ) {
zfcp_erp_port_reopen ( port , 0 , " sctrpi1 " , NULL ) ;
2009-11-24 18:53:59 +03:00
put_device ( & port - > sysfs_device ) ;
2009-04-17 17:08:15 +04:00
}
2009-03-02 15:09:08 +03:00
}
static void zfcp_scsi_rport_register ( struct zfcp_port * port )
{
struct fc_rport_identifiers ids ;
struct fc_rport * rport ;
2009-07-13 17:06:11 +04:00
if ( port - > rport )
return ;
2009-03-02 15:09:08 +03:00
ids . node_name = port - > wwnn ;
ids . port_name = port - > wwpn ;
ids . port_id = port - > d_id ;
ids . roles = FC_RPORT_ROLE_FCP_TARGET ;
rport = fc_remote_port_add ( port - > adapter - > scsi_host , 0 , & ids ) ;
if ( ! rport ) {
dev_err ( & port - > adapter - > ccw_device - > dev ,
" Registering port 0x%016Lx failed \n " ,
( unsigned long long ) port - > wwpn ) ;
return ;
}
rport - > maxframe_size = port - > maxframe_size ;
rport - > supported_classes = port - > supported_classes ;
port - > rport = rport ;
}
static void zfcp_scsi_rport_block ( struct zfcp_port * port )
{
2009-04-17 17:08:15 +04:00
struct fc_rport * rport = port - > rport ;
2009-07-13 17:06:11 +04:00
if ( rport ) {
2009-04-17 17:08:15 +04:00
fc_remote_port_delete ( rport ) ;
2009-07-13 17:06:11 +04:00
port - > rport = NULL ;
}
2009-03-02 15:09:08 +03:00
}
void zfcp_scsi_schedule_rport_register ( struct zfcp_port * port )
{
2009-11-24 18:53:59 +03:00
get_device ( & port - > sysfs_device ) ;
2009-03-02 15:09:08 +03:00
port - > rport_task = RPORT_ADD ;
2009-08-18 17:43:17 +04:00
if ( ! queue_work ( port - > adapter - > work_queue , & port - > rport_work ) )
2009-11-24 18:53:59 +03:00
put_device ( & port - > sysfs_device ) ;
2009-03-02 15:09:08 +03:00
}
void zfcp_scsi_schedule_rport_block ( struct zfcp_port * port )
{
2009-11-24 18:53:59 +03:00
get_device ( & port - > sysfs_device ) ;
2009-03-02 15:09:08 +03:00
port - > rport_task = RPORT_DEL ;
2009-08-18 17:43:17 +04:00
if ( port - > rport & & queue_work ( port - > adapter - > work_queue ,
& port - > rport_work ) )
2009-08-18 17:43:06 +04:00
return ;
2009-11-24 18:53:59 +03:00
put_device ( & port - > sysfs_device ) ;
2009-03-02 15:09:08 +03:00
}
void zfcp_scsi_schedule_rports_block ( struct zfcp_adapter * adapter )
{
2009-11-24 18:53:58 +03:00
unsigned long flags ;
2009-03-02 15:09:08 +03: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-03-02 15:09:08 +03:00
zfcp_scsi_schedule_rport_block ( port ) ;
2009-11-24 18:53:58 +03:00
read_unlock_irqrestore ( & adapter - > port_list_lock , flags ) ;
2009-03-02 15:09:08 +03:00
}
void zfcp_scsi_rport_work ( struct work_struct * work )
{
struct zfcp_port * port = container_of ( work , struct zfcp_port ,
rport_work ) ;
while ( port - > rport_task ) {
if ( port - > rport_task = = RPORT_ADD ) {
port - > rport_task = RPORT_NONE ;
zfcp_scsi_rport_register ( port ) ;
} else {
port - > rport_task = RPORT_NONE ;
zfcp_scsi_rport_block ( port ) ;
}
}
2009-11-24 18:53:59 +03:00
put_device ( & port - > sysfs_device ) ;
2009-03-02 15:09:08 +03:00
}
2009-04-17 17:08:04 +04:00
void zfcp_scsi_scan ( struct work_struct * work )
{
struct zfcp_unit * unit = container_of ( work , struct zfcp_unit ,
scsi_work ) ;
struct fc_rport * rport ;
flush_work ( & unit - > port - > rport_work ) ;
rport = unit - > port - > rport ;
if ( rport & & rport - > port_state = = FC_PORTSTATE_ONLINE )
scsi_scan_target ( & rport - > dev , 0 , rport - > scsi_target_id ,
scsilun_to_int ( ( struct scsi_lun * )
& unit - > fcp_lun ) , 0 ) ;
2009-11-24 18:53:59 +03:00
put_device ( & unit - > sysfs_device ) ;
2009-04-17 17:08:04 +04:00
}
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 ,
2009-11-24 18:54:17 +03:00
. show_host_supported_fc4s = 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 ,
2009-03-02 15:09:08 +03:00
. terminate_rport_io = zfcp_scsi_terminate_rport_io ,
2008-06-10 20:20:59 +04:00
. show_host_port_state = 1 ,
2009-11-24 18:54:17 +03:00
. show_host_active_fc4s = 1 ,
2009-11-24 18:54:13 +03:00
. bsg_request = zfcp_fc_exec_bsg_job ,
2010-01-14 19:19:01 +03:00
. bsg_timeout = zfcp_fc_timeout_bsg_job ,
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 ,
2009-11-24 18:54:13 +03:00
. dd_bsg_size = sizeof ( struct zfcp_fsf_ct_els ) ,
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 " ,
2009-05-15 15:18:16 +04:00
. change_queue_depth = zfcp_scsi_change_queue_depth ,
2008-07-02 12:56:36 +04:00
. 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
} ,
} ;