2005-04-17 02:20:36 +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
* Module interface and handling of zfcp data structures .
2005-04-17 02:20:36 +04:00
*
2009-03-02 15:09:08 +03:00
* Copyright IBM Corporation 2002 , 2009
2005-04-17 02:20:36 +04:00
*/
2006-05-22 20:14:08 +04:00
/*
* Driver authors :
* Martin Peschke ( originator of the driver )
* Raimund Schroeder
* Aron Zeh
* Wolfgang Taphorn
* Stefan Bader
* Heiko Carstens ( kernel 2.6 port of the driver )
* Andreas Herrmann
* Maxim Shchetynin
* Volker Sameske
* Ralph Wuerthner
2008-06-10 20:20:58 +04:00
* Michael Loehr
* Swen Schillig
* Christof Schmitt
* Martin Petermann
* Sven Schuetz
2006-05-22 20:14:08 +04:00
*/
2008-12-25 15:39:53 +03:00
# define KMSG_COMPONENT "zfcp"
# define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
2008-06-10 20:20:55 +04:00
# include <linux/miscdevice.h>
2008-12-25 15:38:50 +03:00
# include <linux/seq_file.h>
2005-04-17 02:20:36 +04:00
# include "zfcp_ext.h"
2008-12-25 15:38:55 +03:00
# define ZFCP_BUS_ID_SIZE 20
2006-05-22 20:14:08 +04:00
MODULE_AUTHOR ( " IBM Deutschland Entwicklung GmbH - linux390@de.ibm.com " ) ;
2008-07-02 12:56:37 +04:00
MODULE_DESCRIPTION ( " FCP HBA driver " ) ;
2005-04-17 02:20:36 +04:00
MODULE_LICENSE ( " GPL " ) ;
2008-12-19 18:56:57 +03:00
static char * init_device ;
module_param_named ( device , init_device , charp , 0400 ) ;
2005-04-17 02:20:36 +04:00
MODULE_PARM_DESC ( device , " specify initial device " ) ;
2009-08-18 17:43:15 +04:00
static struct kmem_cache * zfcp_cache_hw_align ( const char * name ,
unsigned long size )
{
return kmem_cache_create ( name , size , roundup_pow_of_two ( size ) , 0 , NULL ) ;
}
2007-05-08 13:17:54 +04:00
static int zfcp_reqlist_alloc ( struct zfcp_adapter * adapter )
2006-08-02 13:05:16 +04:00
{
2007-05-08 13:17:54 +04:00
int idx ;
2006-08-02 13:05:16 +04:00
adapter - > req_list = kcalloc ( REQUEST_LIST_SIZE , sizeof ( struct list_head ) ,
GFP_KERNEL ) ;
if ( ! adapter - > req_list )
return - ENOMEM ;
2007-05-08 13:17:54 +04:00
for ( idx = 0 ; idx < REQUEST_LIST_SIZE ; idx + + )
INIT_LIST_HEAD ( & adapter - > req_list [ idx ] ) ;
2006-08-02 13:05:16 +04:00
return 0 ;
}
2008-07-02 12:56:37 +04:00
/**
* zfcp_reqlist_isempty - is the request list empty
* @ adapter : pointer to struct zfcp_adapter
*
* Returns : true if list is empty , false otherwise
*/
2006-08-02 13:05:16 +04:00
int zfcp_reqlist_isempty ( struct zfcp_adapter * adapter )
{
2007-05-08 13:17:54 +04:00
unsigned int idx ;
2006-08-02 13:05:16 +04:00
2007-05-08 13:17:54 +04:00
for ( idx = 0 ; idx < REQUEST_LIST_SIZE ; idx + + )
if ( ! list_empty ( & adapter - > req_list [ idx ] ) )
2006-08-02 13:05:16 +04:00
return 0 ;
return 1 ;
}
2008-12-19 18:56:57 +03:00
static void __init zfcp_init_device_configure ( char * busid , u64 wwpn , u64 lun )
2005-04-17 02:20:36 +04:00
{
2009-11-24 18:54:00 +03:00
struct ccw_device * cdev ;
2005-04-17 02:20:36 +04:00
struct zfcp_adapter * adapter ;
struct zfcp_port * port ;
struct zfcp_unit * unit ;
2009-11-24 18:54:00 +03:00
cdev = get_ccwdev_by_busid ( & zfcp_ccw_driver , busid ) ;
if ( ! cdev )
2009-09-24 12:23:22 +04:00
return ;
2009-11-24 18:54:00 +03:00
if ( ccw_device_set_online ( cdev ) )
goto out_ccw_device ;
2005-04-17 02:20:36 +04:00
2009-11-24 18:54:00 +03:00
adapter = zfcp_ccw_adapter_by_cdev ( cdev ) ;
2008-07-02 12:56:37 +04:00
if ( ! adapter )
2009-11-24 18:54:00 +03:00
goto out_ccw_device ;
2009-09-24 12:23:22 +04:00
port = zfcp_get_port_by_wwpn ( adapter , wwpn ) ;
if ( ! port )
2005-04-17 02:20:36 +04:00
goto out_port ;
2009-09-24 12:23:22 +04:00
2008-12-19 18:56:57 +03:00
unit = zfcp_unit_enqueue ( port , lun ) ;
2008-07-02 12:56:37 +04:00
if ( IS_ERR ( unit ) )
2005-04-17 02:20:36 +04:00
goto out_unit ;
2008-10-01 14:42:25 +04:00
2009-09-24 12:23:22 +04:00
zfcp_erp_unit_reopen ( unit , 0 , " auidc_1 " , NULL ) ;
2005-04-17 02:20:36 +04:00
zfcp_erp_wait ( adapter ) ;
2009-04-17 17:08:04 +04:00
flush_work ( & unit - > scsi_work ) ;
2008-10-01 14:42:25 +04:00
2008-07-02 12:56:37 +04:00
out_unit :
2009-11-24 18:53:59 +03:00
put_device ( & port - > sysfs_device ) ;
2008-07-02 12:56:37 +04:00
out_port :
2009-11-24 18:54:00 +03:00
zfcp_ccw_adapter_put ( adapter ) ;
out_ccw_device :
put_device ( & cdev - > dev ) ;
2005-04-17 02:20:36 +04:00
return ;
}
2008-12-19 18:56:57 +03:00
static void __init zfcp_init_device_setup ( char * devstr )
{
char * token ;
2009-10-13 12:44:07 +04:00
char * str , * str_saved ;
2008-12-19 18:56:57 +03:00
char busid [ ZFCP_BUS_ID_SIZE ] ;
u64 wwpn , lun ;
/* duplicate devstr and keep the original for sysfs presentation*/
2009-10-13 12:44:07 +04:00
str_saved = kmalloc ( strlen ( devstr ) + 1 , GFP_KERNEL ) ;
str = str_saved ;
2008-12-19 18:56:57 +03:00
if ( ! str )
return ;
strcpy ( str , devstr ) ;
token = strsep ( & str , " , " ) ;
if ( ! token | | strlen ( token ) > = ZFCP_BUS_ID_SIZE )
goto err_out ;
strncpy ( busid , token , ZFCP_BUS_ID_SIZE ) ;
token = strsep ( & str , " , " ) ;
if ( ! token | | strict_strtoull ( token , 0 , ( unsigned long long * ) & wwpn ) )
goto err_out ;
token = strsep ( & str , " , " ) ;
if ( ! token | | strict_strtoull ( token , 0 , ( unsigned long long * ) & lun ) )
goto err_out ;
2009-10-13 12:44:07 +04:00
kfree ( str_saved ) ;
2008-12-19 18:56:57 +03:00
zfcp_init_device_configure ( busid , wwpn , lun ) ;
return ;
2009-10-13 12:44:07 +04:00
err_out :
kfree ( str_saved ) ;
2008-12-19 18:56:57 +03:00
pr_err ( " %s is not a valid SCSI device \n " , devstr ) ;
}
2008-07-02 12:56:37 +04:00
static int __init zfcp_module_init ( void )
2005-04-17 02:20:36 +04:00
{
2006-09-19 00:28:49 +04:00
int retval = - ENOMEM ;
2009-08-18 17:43:15 +04:00
zfcp_data . gpn_ft_cache = zfcp_cache_hw_align ( " zfcp_gpn " ,
sizeof ( struct ct_iu_gpn_ft_req ) ) ;
if ( ! zfcp_data . gpn_ft_cache )
2006-09-19 00:28:49 +04:00
goto out ;
2005-04-17 02:20:36 +04:00
2009-08-18 17:43:15 +04:00
zfcp_data . qtcb_cache = zfcp_cache_hw_align ( " zfcp_qtcb " ,
sizeof ( struct fsf_qtcb ) ) ;
if ( ! zfcp_data . qtcb_cache )
goto out_qtcb_cache ;
zfcp_data . sr_buffer_cache = zfcp_cache_hw_align ( " zfcp_sr " ,
sizeof ( struct fsf_status_read_buffer ) ) ;
2006-09-19 00:28:49 +04:00
if ( ! zfcp_data . sr_buffer_cache )
goto out_sr_cache ;
2009-08-18 17:43:15 +04:00
zfcp_data . gid_pn_cache = zfcp_cache_hw_align ( " zfcp_gid " ,
sizeof ( struct zfcp_gid_pn_data ) ) ;
2006-09-19 00:28:49 +04:00
if ( ! zfcp_data . gid_pn_cache )
goto out_gid_cache ;
2005-04-17 02:20:36 +04:00
2006-09-19 00:28:49 +04:00
zfcp_data . scsi_transport_template =
fc_attach_transport ( & zfcp_transport_functions ) ;
if ( ! zfcp_data . scsi_transport_template )
goto out_transport ;
2005-04-17 02:20:36 +04:00
retval = misc_register ( & zfcp_cfdc_misc ) ;
2008-07-02 12:56:37 +04:00
if ( retval ) {
2008-12-25 15:39:53 +03:00
pr_err ( " Registering the misc device zfcp_cfdc failed \n " ) ;
2006-09-19 00:28:49 +04:00
goto out_misc ;
2005-04-17 02:20:36 +04:00
}
2009-11-24 18:54:04 +03:00
retval = ccw_driver_register ( & zfcp_ccw_driver ) ;
2005-04-17 02:20:36 +04:00
if ( retval ) {
2008-12-25 15:39:53 +03:00
pr_err ( " The zfcp device driver could not register with "
2008-10-01 14:42:15 +04:00
" the common I/O layer \n " ) ;
2005-04-17 02:20:36 +04:00
goto out_ccw_register ;
}
2008-12-19 18:56:57 +03:00
if ( init_device )
zfcp_init_device_setup ( init_device ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
2008-07-02 12:56:37 +04:00
out_ccw_register :
2005-04-17 02:20:36 +04:00
misc_deregister ( & zfcp_cfdc_misc ) ;
2008-07-02 12:56:37 +04:00
out_misc :
2006-09-19 00:28:49 +04:00
fc_release_transport ( zfcp_data . scsi_transport_template ) ;
2008-07-02 12:56:37 +04:00
out_transport :
2006-09-19 00:28:49 +04:00
kmem_cache_destroy ( zfcp_data . gid_pn_cache ) ;
2008-07-02 12:56:37 +04:00
out_gid_cache :
2006-09-19 00:28:49 +04:00
kmem_cache_destroy ( zfcp_data . sr_buffer_cache ) ;
2008-07-02 12:56:37 +04:00
out_sr_cache :
2009-08-18 17:43:15 +04:00
kmem_cache_destroy ( zfcp_data . qtcb_cache ) ;
out_qtcb_cache :
kmem_cache_destroy ( zfcp_data . gpn_ft_cache ) ;
2008-07-02 12:56:37 +04:00
out :
2005-04-17 02:20:36 +04:00
return retval ;
}
2008-07-02 12:56:37 +04:00
module_init ( zfcp_module_init ) ;
2005-04-17 02:20:36 +04:00
2009-11-24 18:54:04 +03:00
static void __exit zfcp_module_exit ( void )
{
ccw_driver_unregister ( & zfcp_ccw_driver ) ;
misc_deregister ( & zfcp_cfdc_misc ) ;
fc_release_transport ( zfcp_data . scsi_transport_template ) ;
kmem_cache_destroy ( zfcp_data . gid_pn_cache ) ;
kmem_cache_destroy ( zfcp_data . sr_buffer_cache ) ;
kmem_cache_destroy ( zfcp_data . qtcb_cache ) ;
kmem_cache_destroy ( zfcp_data . gpn_ft_cache ) ;
}
module_exit ( zfcp_module_exit ) ;
2005-04-17 02:20:36 +04:00
/**
* zfcp_get_unit_by_lun - find unit in unit list of port by FCP LUN
* @ port : pointer to port to search for unit
* @ fcp_lun : FCP LUN to search for
2008-07-02 12:56:37 +04:00
*
* Returns : pointer to zfcp_unit or NULL
2005-04-17 02:20:36 +04:00
*/
2008-10-01 14:42:18 +04:00
struct zfcp_unit * zfcp_get_unit_by_lun ( struct zfcp_port * port , u64 fcp_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_unit * unit ;
2009-11-24 18:53:58 +03:00
read_lock_irqsave ( & port - > unit_list_lock , flags ) ;
list_for_each_entry ( unit , & port - > unit_list , list )
2009-11-24 18:54:05 +03:00
if ( unit - > fcp_lun = = fcp_lun ) {
if ( ! get_device ( & unit - > sysfs_device ) )
unit = NULL ;
2009-11-24 18:53:58 +03:00
read_unlock_irqrestore ( & port - > unit_list_lock , flags ) ;
return unit ;
}
read_unlock_irqrestore ( & port - > unit_list_lock , flags ) ;
2008-07-02 12:56:37 +04:00
return NULL ;
2005-04-17 02:20:36 +04:00
}
/**
* zfcp_get_port_by_wwpn - find port in port list of adapter by wwpn
* @ adapter : pointer to adapter to search for port
* @ wwpn : wwpn to search for
2008-07-02 12:56:37 +04:00
*
* Returns : pointer to zfcp_port or NULL
2005-04-17 02:20:36 +04:00
*/
2008-07-02 12:56:37 +04:00
struct zfcp_port * zfcp_get_port_by_wwpn ( struct zfcp_adapter * adapter ,
2008-10-01 14:42:18 +04:00
u64 wwpn )
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
read_lock_irqsave ( & adapter - > port_list_lock , flags ) ;
list_for_each_entry ( port , & adapter - > port_list , list )
2009-11-24 18:54:05 +03:00
if ( port - > wwpn = = wwpn ) {
if ( ! get_device ( & port - > sysfs_device ) )
port = NULL ;
2009-11-24 18:53:58 +03:00
read_unlock_irqrestore ( & adapter - > port_list_lock , flags ) ;
2008-07-02 12:56:37 +04:00
return port ;
2009-11-24 18:53:58 +03:00
}
read_unlock_irqrestore ( & adapter - > port_list_lock , flags ) ;
2008-07-02 12:56:37 +04:00
return NULL ;
2005-04-17 02:20:36 +04:00
}
2009-11-24 18:53:59 +03:00
/**
* zfcp_unit_release - dequeue unit
* @ dev : pointer to device
*
* waits until all work is done on unit and removes it then from the unit - > list
* of the associated port .
*/
static void zfcp_unit_release ( struct device * dev )
2008-07-02 12:56:38 +04:00
{
2009-11-24 18:53:59 +03:00
struct zfcp_unit * unit = container_of ( dev , struct zfcp_unit ,
sysfs_device ) ;
put_device ( & unit - > port - > sysfs_device ) ;
kfree ( unit ) ;
2008-07-02 12:56:38 +04:00
}
2005-04-17 02:20:36 +04:00
/**
* zfcp_unit_enqueue - enqueue unit to unit list of a port .
* @ port : pointer to port where unit is added
* @ fcp_lun : FCP LUN of unit to be enqueued
2008-07-02 12:56:37 +04:00
* Returns : pointer to enqueued unit on success , ERR_PTR on error
2005-04-17 02:20:36 +04:00
*
* Sets up some unit internal structures and creates sysfs entry .
*/
2008-10-01 14:42:18 +04:00
struct zfcp_unit * zfcp_unit_enqueue ( struct zfcp_port * port , u64 fcp_lun )
2005-04-17 02:20:36 +04:00
{
2007-06-19 12:25:30 +04:00
struct zfcp_unit * unit ;
2009-11-24 18:53:59 +03:00
int retval = - ENOMEM ;
get_device ( & port - > sysfs_device ) ;
2005-04-17 02:20:36 +04:00
2009-11-24 18:53:58 +03:00
unit = zfcp_get_unit_by_lun ( port , fcp_lun ) ;
if ( unit ) {
2009-11-24 18:53:59 +03:00
put_device ( & unit - > sysfs_device ) ;
retval = - EEXIST ;
goto err_out ;
2009-08-18 17:43:30 +04:00
}
2008-07-02 12:56:37 +04:00
unit = kzalloc ( sizeof ( struct zfcp_unit ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! unit )
2009-11-24 18:53:59 +03:00
goto err_out ;
2005-04-17 02:20:36 +04:00
unit - > port = port ;
unit - > fcp_lun = fcp_lun ;
2009-11-24 18:53:59 +03:00
unit - > sysfs_device . parent = & port - > sysfs_device ;
unit - > sysfs_device . release = zfcp_unit_release ;
2005-04-17 02:20:36 +04:00
2009-08-18 17:43:30 +04:00
if ( dev_set_name ( & unit - > sysfs_device , " 0x%016llx " ,
( unsigned long long ) fcp_lun ) ) {
kfree ( unit ) ;
2009-11-24 18:53:59 +03:00
goto err_out ;
2009-08-18 17:43:30 +04:00
}
2009-11-24 18:53:59 +03:00
retval = - EINVAL ;
2005-04-17 02:20:36 +04:00
2009-11-24 18:53:59 +03:00
INIT_WORK ( & unit - > scsi_work , zfcp_scsi_scan ) ;
2008-05-06 13:00:05 +04:00
spin_lock_init ( & unit - > latencies . lock ) ;
unit - > latencies . write . channel . min = 0xFFFFFFFF ;
unit - > latencies . write . fabric . min = 0xFFFFFFFF ;
unit - > latencies . read . channel . min = 0xFFFFFFFF ;
unit - > latencies . read . fabric . min = 0xFFFFFFFF ;
unit - > latencies . cmd . channel . min = 0xFFFFFFFF ;
unit - > latencies . cmd . fabric . min = 0xFFFFFFFF ;
2009-08-18 17:43:29 +04:00
if ( device_register ( & unit - > sysfs_device ) ) {
put_device ( & unit - > sysfs_device ) ;
2009-11-24 18:53:59 +03:00
goto err_out ;
2009-08-18 17:43:29 +04:00
}
2005-04-17 02:20:36 +04:00
2008-07-02 12:56:38 +04:00
if ( sysfs_create_group ( & unit - > sysfs_device . kobj ,
2009-11-24 18:53:59 +03:00
& zfcp_sysfs_unit_attrs ) )
goto err_out_put ;
2005-04-17 02:20:36 +04:00
2009-11-24 18:53:58 +03:00
write_lock_irq ( & port - > unit_list_lock ) ;
list_add_tail ( & unit - > list , & port - > unit_list ) ;
write_unlock_irq ( & port - > unit_list_lock ) ;
2005-04-17 02:20:36 +04:00
atomic_set_mask ( ZFCP_STATUS_COMMON_RUNNING , & unit - > status ) ;
2008-07-02 12:56:37 +04:00
2005-04-17 02:20:36 +04:00
return unit ;
2009-11-24 18:53:58 +03:00
2009-11-24 18:53:59 +03:00
err_out_put :
2005-04-17 02:20:36 +04:00
device_unregister ( & unit - > sysfs_device ) ;
2009-11-24 18:53:59 +03:00
err_out :
put_device ( & port - > sysfs_device ) ;
return ERR_PTR ( retval ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-02 12:56:37 +04:00
static int zfcp_allocate_low_mem_buffers ( struct zfcp_adapter * adapter )
2005-04-17 02:20:36 +04:00
{
2009-08-18 17:43:15 +04:00
adapter - > pool . erp_req =
mempool_create_kmalloc_pool ( 1 , sizeof ( struct zfcp_fsf_req ) ) ;
if ( ! adapter - > pool . erp_req )
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
2009-08-18 17:43:20 +04:00
adapter - > pool . gid_pn_req =
mempool_create_kmalloc_pool ( 1 , sizeof ( struct zfcp_fsf_req ) ) ;
if ( ! adapter - > pool . gid_pn_req )
return - ENOMEM ;
2009-08-18 17:43:15 +04:00
adapter - > pool . scsi_req =
mempool_create_kmalloc_pool ( 1 , sizeof ( struct zfcp_fsf_req ) ) ;
if ( ! adapter - > pool . scsi_req )
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
2009-08-18 17:43:15 +04:00
adapter - > pool . scsi_abort =
mempool_create_kmalloc_pool ( 1 , sizeof ( struct zfcp_fsf_req ) ) ;
if ( ! adapter - > pool . scsi_abort )
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
2009-08-18 17:43:15 +04:00
adapter - > pool . status_read_req =
2008-07-02 12:56:37 +04:00
mempool_create_kmalloc_pool ( FSF_STATUS_READS_RECOM ,
2006-03-26 13:37:47 +04:00
sizeof ( struct zfcp_fsf_req ) ) ;
2009-08-18 17:43:15 +04:00
if ( ! adapter - > pool . status_read_req )
return - ENOMEM ;
adapter - > pool . qtcb_pool =
2009-08-18 17:43:20 +04:00
mempool_create_slab_pool ( 4 , zfcp_data . qtcb_cache ) ;
2009-08-18 17:43:15 +04:00
if ( ! adapter - > pool . qtcb_pool )
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
2009-08-18 17:43:15 +04:00
adapter - > pool . status_read_data =
2008-07-02 12:56:37 +04:00
mempool_create_slab_pool ( FSF_STATUS_READS_RECOM ,
2006-09-19 00:28:49 +04:00
zfcp_data . sr_buffer_cache ) ;
2009-08-18 17:43:15 +04:00
if ( ! adapter - > pool . status_read_data )
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
2009-08-18 17:43:15 +04:00
adapter - > pool . gid_pn_data =
2008-07-02 12:56:37 +04:00
mempool_create_slab_pool ( 1 , zfcp_data . gid_pn_cache ) ;
2009-08-18 17:43:15 +04:00
if ( ! adapter - > pool . gid_pn_data )
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
return 0 ;
}
2008-07-02 12:56:37 +04:00
static void zfcp_free_low_mem_buffers ( struct zfcp_adapter * adapter )
2005-04-17 02:20:36 +04:00
{
2009-08-18 17:43:15 +04:00
if ( adapter - > pool . erp_req )
mempool_destroy ( adapter - > pool . erp_req ) ;
if ( adapter - > pool . scsi_req )
mempool_destroy ( adapter - > pool . scsi_req ) ;
if ( adapter - > pool . scsi_abort )
mempool_destroy ( adapter - > pool . scsi_abort ) ;
if ( adapter - > pool . qtcb_pool )
mempool_destroy ( adapter - > pool . qtcb_pool ) ;
if ( adapter - > pool . status_read_req )
mempool_destroy ( adapter - > pool . status_read_req ) ;
if ( adapter - > pool . status_read_data )
mempool_destroy ( adapter - > pool . status_read_data ) ;
if ( adapter - > pool . gid_pn_data )
mempool_destroy ( adapter - > pool . gid_pn_data ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-02 12:56:37 +04:00
/**
* zfcp_status_read_refill - refill the long running status_read_requests
* @ adapter : ptr to struct zfcp_adapter for which the buffers should be refilled
*
* Returns : 0 on success , 1 otherwise
*
* if there are 16 or more status_read requests missing an adapter_reopen
* is triggered
*/
2008-05-19 14:17:37 +04:00
int zfcp_status_read_refill ( struct zfcp_adapter * adapter )
{
while ( atomic_read ( & adapter - > stat_miss ) > 0 )
2009-08-18 17:43:19 +04:00
if ( zfcp_fsf_status_read ( adapter - > qdio ) ) {
2008-07-02 12:56:33 +04:00
if ( atomic_read ( & adapter - > stat_miss ) > = 16 ) {
2009-03-02 15:09:04 +03:00
zfcp_erp_adapter_reopen ( adapter , 0 , " axsref1 " ,
NULL ) ;
2008-07-02 12:56:33 +04:00
return 1 ;
}
2008-05-19 14:17:37 +04:00
break ;
2008-07-02 12:56:33 +04:00
} else
atomic_dec ( & adapter - > stat_miss ) ;
2008-05-19 14:17:37 +04:00
return 0 ;
}
static void _zfcp_status_read_scheduler ( struct work_struct * work )
{
zfcp_status_read_refill ( container_of ( work , struct zfcp_adapter ,
stat_work ) ) ;
}
2008-12-25 15:38:50 +03:00
static void zfcp_print_sl ( struct seq_file * m , struct service_level * sl )
{
struct zfcp_adapter * adapter =
container_of ( sl , struct zfcp_adapter , service_level ) ;
seq_printf ( m , " zfcp: %s microcode level %x \n " ,
dev_name ( & adapter - > ccw_device - > dev ) ,
adapter - > fsf_lic_version ) ;
}
2009-08-18 17:43:17 +04:00
static int zfcp_setup_adapter_work_queue ( struct zfcp_adapter * adapter )
{
char name [ TASK_COMM_LEN ] ;
snprintf ( name , sizeof ( name ) , " zfcp_q_%s " ,
dev_name ( & adapter - > ccw_device - > dev ) ) ;
adapter - > work_queue = create_singlethread_workqueue ( name ) ;
if ( adapter - > work_queue )
return 0 ;
return - ENOMEM ;
}
static void zfcp_destroy_adapter_work_queue ( struct zfcp_adapter * adapter )
{
if ( adapter - > work_queue )
destroy_workqueue ( adapter - > work_queue ) ;
adapter - > work_queue = NULL ;
}
2008-07-02 12:56:37 +04:00
/**
* zfcp_adapter_enqueue - enqueue a new adapter to the list
* @ ccw_device : pointer to the struct cc_device
*
2009-11-24 18:54:00 +03:00
* Returns : struct zfcp_adapter *
2005-04-17 02:20:36 +04:00
* Enqueues an adapter at the end of the adapter list in the driver data .
* All adapter internal structures are set up .
* Proc - fs entries are also created .
*/
2009-11-24 18:54:00 +03:00
struct zfcp_adapter * zfcp_adapter_enqueue ( struct ccw_device * ccw_device )
2005-04-17 02:20:36 +04:00
{
struct zfcp_adapter * adapter ;
2009-11-24 18:53:59 +03:00
if ( ! get_device ( & ccw_device - > dev ) )
2009-11-24 18:54:00 +03:00
return ERR_PTR ( - ENODEV ) ;
2005-04-17 02:20:36 +04:00
2008-07-02 12:56:37 +04:00
adapter = kzalloc ( sizeof ( struct zfcp_adapter ) , GFP_KERNEL ) ;
2009-11-24 18:53:59 +03:00
if ( ! adapter ) {
put_device ( & ccw_device - > dev ) ;
2009-11-24 18:54:00 +03:00
return ERR_PTR ( - ENOMEM ) ;
2009-11-24 18:53:59 +03:00
}
kref_init ( & adapter - > ref ) ;
2005-04-17 02:20:36 +04:00
ccw_device - > handler = NULL ;
adapter - > ccw_device = ccw_device ;
2009-11-24 18:53:59 +03:00
INIT_WORK ( & adapter - > stat_work , _zfcp_status_read_scheduler ) ;
2009-11-24 18:54:06 +03:00
INIT_WORK ( & adapter - > scan_work , zfcp_fc_scan_ports ) ;
2005-04-17 02:20:36 +04:00
2009-08-18 17:43:22 +04:00
if ( zfcp_qdio_setup ( adapter ) )
2009-11-24 18:53:59 +03:00
goto failed ;
2005-04-17 02:20:36 +04:00
2008-06-10 20:20:57 +04:00
if ( zfcp_allocate_low_mem_buffers ( adapter ) )
2009-11-24 18:53:59 +03:00
goto failed ;
2005-04-17 02:20:36 +04:00
2008-07-02 12:56:37 +04:00
if ( zfcp_reqlist_alloc ( adapter ) )
2009-11-24 18:53:59 +03:00
goto failed ;
2008-07-02 12:56:37 +04:00
2009-08-18 17:43:21 +04:00
if ( zfcp_dbf_adapter_register ( adapter ) )
2009-11-24 18:53:59 +03:00
goto failed ;
2008-07-02 12:56:37 +04:00
2009-08-18 17:43:17 +04:00
if ( zfcp_setup_adapter_work_queue ( adapter ) )
2009-11-24 18:53:59 +03:00
goto failed ;
2009-08-18 17:43:17 +04:00
2009-08-18 17:43:22 +04:00
if ( zfcp_fc_gs_setup ( adapter ) )
2009-11-24 18:53:59 +03:00
goto failed ;
2009-08-18 17:43:22 +04:00
2009-11-24 18:53:58 +03:00
rwlock_init ( & adapter - > port_list_lock ) ;
INIT_LIST_HEAD ( & adapter - > port_list ) ;
2009-08-18 17:43:25 +04:00
init_waitqueue_head ( & adapter - > erp_ready_wq ) ;
2008-07-02 12:56:37 +04:00
init_waitqueue_head ( & adapter - > erp_done_wqh ) ;
2005-04-17 02:20:36 +04:00
2008-07-02 12:56:37 +04:00
INIT_LIST_HEAD ( & adapter - > erp_ready_head ) ;
INIT_LIST_HEAD ( & adapter - > erp_running_head ) ;
2005-04-17 02:20:36 +04:00
2006-08-02 13:05:16 +04:00
spin_lock_init ( & adapter - > req_list_lock ) ;
2005-12-01 04:46:32 +03:00
rwlock_init ( & adapter - > erp_lock ) ;
2005-04-17 02:20:36 +04:00
rwlock_init ( & adapter - > abort_lock ) ;
2009-08-18 17:43:27 +04:00
if ( zfcp_erp_thread_setup ( adapter ) )
2009-11-24 18:53:59 +03:00
goto failed ;
2005-04-17 02:20:36 +04:00
2008-12-25 15:38:50 +03:00
adapter - > service_level . seq_print = zfcp_print_sl ;
2005-04-17 02:20:36 +04:00
dev_set_drvdata ( & ccw_device - > dev , adapter ) ;
2008-07-02 12:56:38 +04:00
if ( sysfs_create_group ( & ccw_device - > dev . kobj ,
& zfcp_sysfs_adapter_attrs ) )
2009-11-24 18:53:59 +03:00
goto failed ;
2005-04-17 02:20:36 +04:00
2008-12-19 18:56:53 +03:00
if ( ! zfcp_adapter_scsi_register ( adapter ) )
2009-11-24 18:54:00 +03:00
return adapter ;
2005-04-17 02:20:36 +04:00
2009-11-24 18:53:59 +03:00
failed :
2009-11-24 18:54:00 +03:00
zfcp_adapter_unregister ( adapter ) ;
return ERR_PTR ( - ENOMEM ) ;
}
void zfcp_adapter_unregister ( struct zfcp_adapter * adapter )
{
struct ccw_device * cdev = adapter - > ccw_device ;
cancel_work_sync ( & adapter - > scan_work ) ;
cancel_work_sync ( & adapter - > stat_work ) ;
zfcp_destroy_adapter_work_queue ( adapter ) ;
zfcp_fc_wka_ports_force_offline ( adapter - > gs ) ;
zfcp_adapter_scsi_unregister ( adapter ) ;
sysfs_remove_group ( & cdev - > dev . kobj , & zfcp_sysfs_adapter_attrs ) ;
zfcp_erp_thread_kill ( adapter ) ;
zfcp_dbf_adapter_unregister ( adapter - > dbf ) ;
zfcp_qdio_destroy ( adapter - > qdio ) ;
zfcp_ccw_adapter_put ( adapter ) ; /* final put to release */
2005-04-17 02:20:36 +04:00
}
2008-07-02 12:56:37 +04:00
/**
2009-11-24 18:53:59 +03:00
* zfcp_adapter_release - remove the adapter from the resource list
* @ ref : pointer to struct kref
2005-04-17 02:20:36 +04:00
* locks : adapter list write lock is assumed to be held by caller
*/
2009-11-24 18:53:59 +03:00
void zfcp_adapter_release ( struct kref * ref )
2005-04-17 02:20:36 +04:00
{
2009-11-24 18:53:59 +03:00
struct zfcp_adapter * adapter = container_of ( ref , struct zfcp_adapter ,
ref ) ;
2009-11-24 18:54:00 +03:00
struct ccw_device * cdev = adapter - > ccw_device ;
2005-04-17 02:20:36 +04:00
2009-11-24 18:53:59 +03:00
dev_set_drvdata ( & adapter - > ccw_device - > dev , NULL ) ;
2009-08-18 17:43:22 +04:00
zfcp_fc_gs_destroy ( adapter ) ;
2005-04-17 02:20:36 +04:00
zfcp_free_low_mem_buffers ( adapter ) ;
2008-07-02 12:56:37 +04:00
kfree ( adapter - > req_list ) ;
2006-01-05 11:59:34 +03:00
kfree ( adapter - > fc_stats ) ;
kfree ( adapter - > stats_reset_data ) ;
2005-04-17 02:20:36 +04:00
kfree ( adapter ) ;
2009-11-24 18:54:00 +03:00
put_device ( & cdev - > dev ) ;
2009-11-24 18:53:59 +03:00
}
/**
* zfcp_device_unregister - remove port , unit from system
* @ dev : reference to device which is to be removed
* @ grp : related reference to attribute group
*
* Helper function to unregister port , unit from system
*/
void zfcp_device_unregister ( struct device * dev ,
const struct attribute_group * grp )
{
sysfs_remove_group ( & dev - > kobj , grp ) ;
device_unregister ( dev ) ;
2005-04-17 02:20:36 +04:00
}
2009-11-24 18:53:59 +03:00
static void zfcp_port_release ( struct device * dev )
2008-07-02 12:56:38 +04:00
{
2009-11-24 18:53:59 +03:00
struct zfcp_port * port = container_of ( dev , struct zfcp_port ,
sysfs_device ) ;
2009-11-24 18:54:00 +03:00
zfcp_ccw_adapter_put ( port - > adapter ) ;
2009-11-24 18:53:59 +03:00
kfree ( port ) ;
2008-07-02 12:56:38 +04:00
}
2005-04-17 02:20:36 +04:00
/**
* zfcp_port_enqueue - enqueue port to port list of adapter
* @ adapter : adapter where remote port is added
* @ wwpn : WWPN of the remote port to be enqueued
* @ status : initial status for the port
* @ d_id : destination id of the remote port to be enqueued
2008-07-02 12:56:37 +04:00
* Returns : pointer to enqueued port on success , ERR_PTR on error
2005-04-17 02:20:36 +04:00
*
* All port internal structures are set up and the sysfs entry is generated .
* d_id is used to enqueue ports with a well known address like the Directory
* Service for nameserver lookup .
*/
2008-10-01 14:42:18 +04:00
struct zfcp_port * zfcp_port_enqueue ( struct zfcp_adapter * adapter , u64 wwpn ,
2008-07-02 12:56:37 +04:00
u32 status , u32 d_id )
2005-04-17 02:20:36 +04:00
{
2005-08-27 22:07:54 +04:00
struct zfcp_port * port ;
2009-11-24 18:53:59 +03:00
int retval = - ENOMEM ;
kref_get ( & adapter - > ref ) ;
2009-08-18 17:43:30 +04:00
2009-11-24 18:53:58 +03:00
port = zfcp_get_port_by_wwpn ( adapter , wwpn ) ;
if ( port ) {
2009-11-24 18:53:59 +03:00
put_device ( & port - > sysfs_device ) ;
retval = - EEXIST ;
goto err_out ;
2009-08-18 17:43:30 +04:00
}
2005-04-17 02:20:36 +04:00
2008-07-02 12:56:37 +04:00
port = kzalloc ( sizeof ( struct zfcp_port ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! port )
2009-11-24 18:53:59 +03:00
goto err_out ;
2005-04-17 02:20:36 +04:00
2009-11-24 18:53:58 +03:00
rwlock_init ( & port - > unit_list_lock ) ;
INIT_LIST_HEAD ( & port - > unit_list ) ;
2009-08-18 17:43:20 +04:00
INIT_WORK ( & port - > gid_pn_work , zfcp_fc_port_did_lookup ) ;
2009-03-02 15:09:01 +03:00
INIT_WORK ( & port - > test_link_work , zfcp_fc_link_test_work ) ;
2009-03-02 15:09:08 +03:00
INIT_WORK ( & port - > rport_work , zfcp_scsi_rport_work ) ;
2005-04-17 02:20:36 +04:00
port - > adapter = adapter ;
2008-07-02 12:56:37 +04:00
port - > d_id = d_id ;
port - > wwpn = wwpn ;
2009-03-02 15:09:08 +03:00
port - > rport_task = RPORT_NONE ;
2009-11-24 18:53:59 +03:00
port - > sysfs_device . parent = & adapter - > ccw_device - > dev ;
port - > sysfs_device . release = zfcp_port_release ;
2005-04-17 02:20:36 +04:00
2009-08-18 17:43:30 +04:00
if ( dev_set_name ( & port - > sysfs_device , " 0x%016llx " ,
( unsigned long long ) wwpn ) ) {
kfree ( port ) ;
2009-11-24 18:53:59 +03:00
goto err_out ;
2009-08-18 17:43:30 +04:00
}
2009-11-24 18:53:59 +03:00
retval = - EINVAL ;
2005-04-17 02:20:36 +04:00
2009-08-18 17:43:29 +04:00
if ( device_register ( & port - > sysfs_device ) ) {
put_device ( & port - > sysfs_device ) ;
2009-11-24 18:53:59 +03:00
goto err_out ;
2009-08-18 17:43:29 +04:00
}
2005-04-17 02:20:36 +04:00
2009-08-18 17:43:30 +04:00
if ( sysfs_create_group ( & port - > sysfs_device . kobj ,
2009-11-24 18:53:59 +03:00
& zfcp_sysfs_port_attrs ) )
goto err_out_put ;
2005-04-17 02:20:36 +04:00
2009-11-24 18:53:58 +03:00
write_lock_irq ( & adapter - > port_list_lock ) ;
list_add_tail ( & port - > list , & adapter - > port_list ) ;
write_unlock_irq ( & adapter - > port_list_lock ) ;
2009-11-24 18:54:05 +03:00
atomic_set_mask ( status | ZFCP_STATUS_COMMON_RUNNING , & port - > status ) ;
2008-07-02 12:56:37 +04:00
2005-04-17 02:20:36 +04:00
return port ;
2009-11-24 18:53:59 +03:00
err_out_put :
2005-04-17 02:20:36 +04:00
device_unregister ( & port - > sysfs_device ) ;
2009-11-24 18:53:59 +03:00
err_out :
2009-11-24 18:54:00 +03:00
zfcp_ccw_adapter_put ( adapter ) ;
2009-11-24 18:53:59 +03:00
return ERR_PTR ( retval ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-02 12:56:37 +04:00
/**
* zfcp_sg_free_table - free memory used by scatterlists
* @ sg : pointer to scatterlist
* @ count : number of scatterlist which are to be free ' ed
* the scatterlist are expected to reference pages always
*/
2008-06-10 20:20:55 +04:00
void zfcp_sg_free_table ( struct scatterlist * sg , int count )
{
int i ;
for ( i = 0 ; i < count ; i + + , sg + + )
if ( sg )
free_page ( ( unsigned long ) sg_virt ( sg ) ) ;
else
break ;
}
2008-07-02 12:56:37 +04:00
/**
* zfcp_sg_setup_table - init scatterlist and allocate , assign buffers
* @ sg : pointer to struct scatterlist
* @ count : number of scatterlists which should be assigned with buffers
* of size page
*
* Returns : 0 on success , - ENOMEM otherwise
*/
2008-06-10 20:20:55 +04:00
int zfcp_sg_setup_table ( struct scatterlist * sg , int count )
{
void * addr ;
int i ;
sg_init_table ( sg , count ) ;
for ( i = 0 ; i < count ; i + + , sg + + ) {
addr = ( void * ) get_zeroed_page ( GFP_KERNEL ) ;
if ( ! addr ) {
zfcp_sg_free_table ( sg , i ) ;
return - ENOMEM ;
}
sg_set_buf ( sg , addr , PAGE_SIZE ) ;
}
return 0 ;
}