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
*
2008-06-10 20:20:58 +04:00
* Copyright IBM Corporation 2002 , 2008
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-06-10 20:20:55 +04:00
# include <linux/miscdevice.h>
2005-04-17 02:20:36 +04:00
# include "zfcp_ext.h"
static char * device ;
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 " ) ;
2005-04-11 08:04:28 +04:00
module_param ( device , charp , 0400 ) ;
2005-04-17 02:20:36 +04:00
MODULE_PARM_DESC ( device , " specify initial device " ) ;
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-07-02 12:56:37 +04:00
static int __init zfcp_device_setup ( char * devstr )
2005-04-17 02:20:36 +04:00
{
2008-07-02 12:56:37 +04:00
char * token ;
char * str ;
2005-04-17 02:20:36 +04:00
2005-06-13 15:22:25 +04:00
if ( ! devstr )
2005-04-17 02:20:36 +04:00
return 0 ;
2008-07-02 12:56:37 +04:00
/* duplicate devstr and keep the original for sysfs presentation*/
str = kmalloc ( strlen ( devstr ) + 1 , GFP_KERNEL ) ;
if ( ! str )
2008-06-10 20:20:58 +04:00
return 0 ;
2005-06-13 15:22:25 +04:00
2008-07-02 12:56:37 +04:00
strcpy ( str , devstr ) ;
2005-04-17 02:20:36 +04:00
2008-07-02 12:56:37 +04:00
token = strsep ( & str , " , " ) ;
if ( ! token | | strlen ( token ) > = BUS_ID_SIZE )
2005-04-17 02:20:36 +04:00
goto err_out ;
2008-07-02 12:56:37 +04:00
strncpy ( zfcp_data . init_busid , token , BUS_ID_SIZE ) ;
token = strsep ( & str , " , " ) ;
2008-10-01 14:42:18 +04:00
if ( ! token | | strict_strtoull ( token , 0 ,
( unsigned long long * ) & zfcp_data . init_wwpn ) )
2005-04-17 02:20:36 +04:00
goto err_out ;
2008-07-02 12:56:37 +04:00
token = strsep ( & str , " , " ) ;
2008-10-01 14:42:18 +04:00
if ( ! token | | strict_strtoull ( token , 0 ,
( unsigned long long * ) & zfcp_data . init_fcp_lun ) )
2005-04-17 02:20:36 +04:00
goto err_out ;
2008-07-02 12:56:37 +04:00
2005-06-13 15:22:25 +04:00
kfree ( str ) ;
2005-04-17 02:20:36 +04:00
return 1 ;
err_out :
2005-06-13 15:22:25 +04:00
kfree ( str ) ;
2008-10-01 14:42:15 +04:00
pr_err ( " zfcp: %s is not a valid SCSI device \n " , devstr ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2008-07-02 12:56:37 +04:00
static void __init zfcp_init_device_configure ( void )
2005-04-17 02:20:36 +04:00
{
struct zfcp_adapter * adapter ;
struct zfcp_port * port ;
struct zfcp_unit * unit ;
down ( & zfcp_data . config_sema ) ;
read_lock_irq ( & zfcp_data . config_lock ) ;
adapter = zfcp_get_adapter_by_busid ( zfcp_data . init_busid ) ;
if ( adapter )
zfcp_adapter_get ( adapter ) ;
read_unlock_irq ( & zfcp_data . config_lock ) ;
2008-07-02 12:56:37 +04:00
if ( ! adapter )
2005-04-17 02:20:36 +04:00
goto out_adapter ;
port = zfcp_port_enqueue ( adapter , zfcp_data . init_wwpn , 0 , 0 ) ;
2008-07-02 12:56:37 +04:00
if ( IS_ERR ( port ) )
2005-04-17 02:20:36 +04:00
goto out_port ;
unit = zfcp_unit_enqueue ( port , zfcp_data . init_fcp_lun ) ;
2008-07-02 12:56:37 +04:00
if ( IS_ERR ( unit ) )
2005-04-17 02:20:36 +04:00
goto out_unit ;
up ( & zfcp_data . config_sema ) ;
ccw_device_set_online ( adapter - > ccw_device ) ;
2008-10-01 14:42:25 +04:00
2005-04-17 02:20:36 +04:00
zfcp_erp_wait ( adapter ) ;
2008-10-01 14:42:25 +04:00
wait_event ( adapter - > erp_done_wqh ,
! ( atomic_read ( & unit - > status ) &
ZFCP_STATUS_UNIT_SCSI_WORK_PENDING ) ) ;
2005-04-17 02:20:36 +04:00
down ( & zfcp_data . config_sema ) ;
zfcp_unit_put ( unit ) ;
2008-07-02 12:56:37 +04:00
out_unit :
2005-04-17 02:20:36 +04:00
zfcp_port_put ( port ) ;
2008-07-02 12:56:37 +04:00
out_port :
2005-04-17 02:20:36 +04:00
zfcp_adapter_put ( adapter ) ;
2008-07-02 12:56:37 +04:00
out_adapter :
2005-04-17 02:20:36 +04:00
up ( & zfcp_data . config_sema ) ;
return ;
}
2008-07-02 12:56:37 +04:00
static struct kmem_cache * zfcp_cache_create ( int size , char * name )
2006-09-19 00:28:49 +04:00
{
int align = 1 ;
while ( ( size - align ) > 0 )
align < < = 1 ;
2008-07-02 12:56:37 +04:00
return kmem_cache_create ( name , size , align , 0 , NULL ) ;
2006-09-19 00:28:49 +04:00
}
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 ;
2008-07-02 12:56:37 +04:00
zfcp_data . fsf_req_qtcb_cache = zfcp_cache_create (
sizeof ( struct zfcp_fsf_req_qtcb ) , " zfcp_fsf " ) ;
2006-09-19 00:28:49 +04:00
if ( ! zfcp_data . fsf_req_qtcb_cache )
goto out ;
2005-04-17 02:20:36 +04:00
2008-07-02 12:56:37 +04:00
zfcp_data . sr_buffer_cache = zfcp_cache_create (
sizeof ( struct fsf_status_read_buffer ) , " zfcp_sr " ) ;
2006-09-19 00:28:49 +04:00
if ( ! zfcp_data . sr_buffer_cache )
goto out_sr_cache ;
2008-07-02 12:56:37 +04:00
zfcp_data . gid_pn_cache = zfcp_cache_create (
sizeof ( struct zfcp_gid_pn_data ) , " zfcp_gid " ) ;
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
2008-10-01 14:42:22 +04:00
zfcp_data . work_queue = create_singlethread_workqueue ( " zfcp_wq " ) ;
2005-04-17 02:20:36 +04:00
INIT_LIST_HEAD ( & zfcp_data . adapter_list_head ) ;
2008-07-02 12:56:37 +04:00
sema_init ( & zfcp_data . config_sema , 1 ) ;
rwlock_init ( & zfcp_data . config_lock ) ;
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-10-01 14:42:15 +04:00
pr_err ( " zfcp: 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
}
retval = zfcp_ccw_register ( ) ;
if ( retval ) {
2008-10-01 14:42:15 +04:00
pr_err ( " zfcp: The zfcp device driver could not register with "
" the common I/O layer \n " ) ;
2005-04-17 02:20:36 +04:00
goto out_ccw_register ;
}
if ( zfcp_device_setup ( device ) )
zfcp_init_device_configure ( ) ;
goto out ;
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 :
2006-09-19 00:28:49 +04:00
kmem_cache_destroy ( zfcp_data . fsf_req_qtcb_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
/**
* 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
{
struct zfcp_unit * unit ;
2008-07-02 12:56:37 +04:00
list_for_each_entry ( unit , & port - > unit_list_head , list )
2005-04-17 02:20:36 +04:00
if ( ( unit - > fcp_lun = = fcp_lun ) & &
2008-07-02 12:56:37 +04:00
! ( atomic_read ( & unit - > status ) & ZFCP_STATUS_COMMON_REMOVE ) )
return unit ;
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
{
struct zfcp_port * port ;
2008-07-02 12:56:37 +04:00
list_for_each_entry ( port , & adapter - > port_list_head , list )
if ( ( port - > wwpn = = wwpn ) & & ! ( atomic_read ( & port - > status ) &
( ZFCP_STATUS_PORT_NO_WWPN | ZFCP_STATUS_COMMON_REMOVE ) ) )
return port ;
return NULL ;
2005-04-17 02:20:36 +04:00
}
2008-07-02 12:56:38 +04:00
static void zfcp_sysfs_unit_release ( struct device * dev )
{
kfree ( container_of ( dev , struct zfcp_unit , sysfs_device ) ) ;
}
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
* Locks : config_sema must be held to serialize changes to the unit list
*
* 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 ;
2005-04-17 02:20:36 +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 )
2008-07-02 12:56:37 +04:00
return ERR_PTR ( - ENOMEM ) ;
2005-04-17 02:20:36 +04:00
atomic_set ( & unit - > refcount , 0 ) ;
init_waitqueue_head ( & unit - > remove_wq ) ;
unit - > port = port ;
unit - > fcp_lun = fcp_lun ;
2008-10-10 23:33:10 +04:00
dev_set_name ( & unit - > sysfs_device , " 0x%016llx " ,
( unsigned long long ) fcp_lun ) ;
2005-04-17 02:20:36 +04:00
unit - > sysfs_device . parent = & port - > sysfs_device ;
unit - > sysfs_device . release = zfcp_sysfs_unit_release ;
dev_set_drvdata ( & unit - > sysfs_device , unit ) ;
/* mark unit unusable as long as sysfs registration is not complete */
atomic_set_mask ( ZFCP_STATUS_COMMON_REMOVE , & unit - > status ) ;
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 ;
2008-07-02 12:56:37 +04:00
read_lock_irq ( & zfcp_data . config_lock ) ;
if ( zfcp_get_unit_by_lun ( port , fcp_lun ) ) {
read_unlock_irq ( & zfcp_data . config_lock ) ;
goto err_out_free ;
2005-04-17 02:20:36 +04:00
}
2008-07-02 12:56:37 +04:00
read_unlock_irq ( & zfcp_data . config_lock ) ;
if ( device_register ( & unit - > sysfs_device ) )
goto err_out_free ;
2005-04-17 02:20:36 +04:00
2008-07-02 12:56:38 +04:00
if ( sysfs_create_group ( & unit - > sysfs_device . kobj ,
& zfcp_sysfs_unit_attrs ) ) {
2005-04-17 02:20:36 +04:00
device_unregister ( & unit - > sysfs_device ) ;
2008-07-02 12:56:37 +04:00
return ERR_PTR ( - EIO ) ;
2005-04-17 02:20:36 +04:00
}
zfcp_unit_get ( unit ) ;
write_lock_irq ( & zfcp_data . config_lock ) ;
2007-06-19 12:25:30 +04:00
list_add_tail ( & unit - > list , & port - > unit_list_head ) ;
2005-04-17 02:20:36 +04:00
atomic_clear_mask ( ZFCP_STATUS_COMMON_REMOVE , & unit - > status ) ;
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
write_unlock_irq ( & zfcp_data . config_lock ) ;
zfcp_port_get ( port ) ;
return unit ;
2008-07-02 12:56:37 +04:00
err_out_free :
kfree ( unit ) ;
return ERR_PTR ( - EINVAL ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-02 12:56:37 +04:00
/**
* zfcp_unit_dequeue - dequeue unit
* @ unit : pointer to zfcp_unit
*
* waits until all work is done on unit and removes it then from the unit - > list
* of the associated port .
*/
void zfcp_unit_dequeue ( struct zfcp_unit * unit )
2005-04-17 02:20:36 +04:00
{
2008-10-01 14:42:16 +04:00
wait_event ( unit - > remove_wq , atomic_read ( & unit - > refcount ) = = 0 ) ;
2005-04-17 02:20:36 +04:00
write_lock_irq ( & zfcp_data . config_lock ) ;
list_del ( & unit - > list ) ;
write_unlock_irq ( & zfcp_data . config_lock ) ;
zfcp_port_put ( unit - > port ) ;
2008-07-02 12:56:38 +04:00
sysfs_remove_group ( & unit - > sysfs_device . kobj , & zfcp_sysfs_unit_attrs ) ;
2005-04-17 02:20:36 +04:00
device_unregister ( & unit - > sysfs_device ) ;
}
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
{
2008-07-02 12:56:37 +04:00
/* must only be called with zfcp_data.config_sema taken */
2005-04-17 02:20:36 +04:00
adapter - > pool . fsf_req_erp =
2008-07-02 12:56:37 +04:00
mempool_create_slab_pool ( 1 , zfcp_data . fsf_req_qtcb_cache ) ;
2006-03-26 13:37:47 +04:00
if ( ! adapter - > pool . fsf_req_erp )
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
adapter - > pool . fsf_req_scsi =
2008-07-02 12:56:37 +04:00
mempool_create_slab_pool ( 1 , zfcp_data . fsf_req_qtcb_cache ) ;
2006-03-26 13:37:47 +04:00
if ( ! adapter - > pool . fsf_req_scsi )
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
adapter - > pool . fsf_req_abort =
2008-07-02 12:56:37 +04:00
mempool_create_slab_pool ( 1 , zfcp_data . fsf_req_qtcb_cache ) ;
2006-03-26 13:37:47 +04:00
if ( ! adapter - > pool . fsf_req_abort )
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
adapter - > pool . fsf_req_status_read =
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 ) ) ;
if ( ! adapter - > pool . fsf_req_status_read )
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
adapter - > pool . data_status_read =
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 ) ;
2006-03-26 13:37:47 +04:00
if ( ! adapter - > pool . data_status_read )
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
adapter - > pool . data_gid_pn =
2008-07-02 12:56:37 +04:00
mempool_create_slab_pool ( 1 , zfcp_data . gid_pn_cache ) ;
2006-03-26 13:37:47 +04:00
if ( ! adapter - > pool . data_gid_pn )
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
{
2008-07-02 12:56:37 +04:00
/* zfcp_data.config_sema must be held */
2005-04-17 02:20:36 +04:00
if ( adapter - > pool . fsf_req_erp )
mempool_destroy ( adapter - > pool . fsf_req_erp ) ;
if ( adapter - > pool . fsf_req_scsi )
mempool_destroy ( adapter - > pool . fsf_req_scsi ) ;
if ( adapter - > pool . fsf_req_abort )
mempool_destroy ( adapter - > pool . fsf_req_abort ) ;
if ( adapter - > pool . fsf_req_status_read )
mempool_destroy ( adapter - > pool . fsf_req_status_read ) ;
if ( adapter - > pool . data_status_read )
mempool_destroy ( adapter - > pool . data_status_read ) ;
if ( adapter - > pool . data_gid_pn )
mempool_destroy ( adapter - > pool . data_gid_pn ) ;
}
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 )
2008-07-02 12:56:39 +04:00
if ( zfcp_fsf_status_read ( adapter ) ) {
2008-07-02 12:56:33 +04:00
if ( atomic_read ( & adapter - > stat_miss ) > = 16 ) {
zfcp_erp_adapter_reopen ( adapter , 0 , 103 , NULL ) ;
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-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
*
* Returns : 0 if a new adapter was successfully enqueued
* - ENOMEM if alloc failed
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 .
* locks : config_sema must be held to serialise changes to the adapter list
*/
2008-07-02 12:56:37 +04:00
int zfcp_adapter_enqueue ( struct ccw_device * ccw_device )
2005-04-17 02:20:36 +04:00
{
struct zfcp_adapter * adapter ;
/*
2007-09-07 11:15:31 +04:00
* Note : It is safe to release the list_lock , as any list changes
2005-04-17 02:20:36 +04:00
* are protected by the config_sema , which must be held to get here
*/
2008-07-02 12:56:37 +04:00
adapter = kzalloc ( sizeof ( struct zfcp_adapter ) , GFP_KERNEL ) ;
2008-06-10 20:20:58 +04:00
if ( ! adapter )
2008-07-02 12:56:37 +04:00
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
ccw_device - > handler = NULL ;
adapter - > ccw_device = ccw_device ;
2008-07-02 12:56:37 +04:00
atomic_set ( & adapter - > refcount , 0 ) ;
2005-04-17 02:20:36 +04:00
2008-06-10 20:20:57 +04:00
if ( zfcp_qdio_allocate ( adapter ) )
2005-04-17 02:20:36 +04:00
goto qdio_allocate_failed ;
2008-06-10 20:20:57 +04:00
if ( zfcp_allocate_low_mem_buffers ( adapter ) )
2005-04-17 02:20:36 +04:00
goto failed_low_mem_buffers ;
2008-07-02 12:56:37 +04:00
if ( zfcp_reqlist_alloc ( adapter ) )
goto failed_low_mem_buffers ;
if ( zfcp_adapter_debug_register ( adapter ) )
goto debug_register_failed ;
2005-04-17 02:20:36 +04:00
init_waitqueue_head ( & adapter - > remove_wq ) ;
2008-07-02 12:56:37 +04:00
init_waitqueue_head ( & adapter - > erp_thread_wqh ) ;
init_waitqueue_head ( & adapter - > erp_done_wqh ) ;
2005-04-17 02:20:36 +04:00
INIT_LIST_HEAD ( & adapter - > port_list_head ) ;
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
spin_lock_init ( & adapter - > hba_dbf_lock ) ;
spin_lock_init ( & adapter - > san_dbf_lock ) ;
spin_lock_init ( & adapter - > scsi_dbf_lock ) ;
2008-03-27 16:22:00 +03:00
spin_lock_init ( & adapter - > rec_dbf_lock ) ;
2008-10-01 14:42:20 +04:00
spin_lock_init ( & adapter - > req_q_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 ) ;
2008-07-02 12:56:37 +04:00
sema_init ( & adapter - > erp_ready_sem , 0 ) ;
2005-04-17 02:20:36 +04:00
2008-05-19 14:17:37 +04:00
INIT_WORK ( & adapter - > stat_work , _zfcp_status_read_scheduler ) ;
2008-06-10 20:21:00 +04:00
INIT_WORK ( & adapter - > scan_work , _zfcp_scan_ports_later ) ;
2005-04-17 02:20:36 +04:00
/* mark adapter unusable as long as sysfs registration is not complete */
atomic_set_mask ( ZFCP_STATUS_COMMON_REMOVE , & adapter - > status ) ;
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 ) )
2005-04-17 02:20:36 +04:00
goto sysfs_failed ;
write_lock_irq ( & zfcp_data . config_lock ) ;
atomic_clear_mask ( ZFCP_STATUS_COMMON_REMOVE , & adapter - > status ) ;
list_add_tail ( & adapter - > list , & zfcp_data . adapter_list_head ) ;
write_unlock_irq ( & zfcp_data . config_lock ) ;
2008-10-01 14:42:17 +04:00
zfcp_fc_nameserver_init ( adapter ) ;
2008-06-10 20:21:00 +04:00
2008-07-02 12:56:37 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
2008-07-02 12:56:37 +04:00
sysfs_failed :
2007-08-28 11:31:41 +04:00
zfcp_adapter_debug_unregister ( adapter ) ;
2008-07-02 12:56:37 +04:00
debug_register_failed :
2005-04-17 02:20:36 +04:00
dev_set_drvdata ( & ccw_device - > dev , NULL ) ;
2008-07-02 12:56:37 +04:00
kfree ( adapter - > req_list ) ;
failed_low_mem_buffers :
2005-04-17 02:20:36 +04:00
zfcp_free_low_mem_buffers ( adapter ) ;
2008-07-02 12:56:37 +04:00
qdio_allocate_failed :
2008-06-10 20:20:57 +04:00
zfcp_qdio_free ( adapter ) ;
2005-04-17 02:20:36 +04:00
kfree ( adapter ) ;
2008-07-02 12:56:37 +04:00
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
}
2008-07-02 12:56:37 +04:00
/**
* zfcp_adapter_dequeue - remove the adapter from the resource list
* @ adapter : pointer to struct zfcp_adapter which should be removed
2005-04-17 02:20:36 +04:00
* locks : adapter list write lock is assumed to be held by caller
*/
2008-07-02 12:56:37 +04:00
void zfcp_adapter_dequeue ( struct zfcp_adapter * adapter )
2005-04-17 02:20:36 +04:00
{
int retval = 0 ;
unsigned long flags ;
2008-06-10 20:21:00 +04:00
cancel_work_sync ( & adapter - > scan_work ) ;
2008-05-19 14:17:37 +04:00
cancel_work_sync ( & adapter - > stat_work ) ;
2007-05-09 13:01:24 +04:00
zfcp_adapter_scsi_unregister ( adapter ) ;
2008-07-02 12:56:38 +04:00
sysfs_remove_group ( & adapter - > ccw_device - > dev . kobj ,
& zfcp_sysfs_adapter_attrs ) ;
2005-04-17 02:20:36 +04:00
dev_set_drvdata ( & adapter - > ccw_device - > dev , NULL ) ;
/* sanity check: no pending FSF requests */
2006-08-02 13:05:16 +04:00
spin_lock_irqsave ( & adapter - > req_list_lock , flags ) ;
retval = zfcp_reqlist_isempty ( adapter ) ;
spin_unlock_irqrestore ( & adapter - > req_list_lock , flags ) ;
2008-07-02 12:56:37 +04:00
if ( ! retval )
return ;
2005-04-17 02:20:36 +04:00
2007-08-28 11:31:41 +04:00
zfcp_adapter_debug_unregister ( adapter ) ;
2005-04-17 02:20:36 +04:00
/* remove specified adapter data structure from list */
write_lock_irq ( & zfcp_data . config_lock ) ;
list_del ( & adapter - > list ) ;
write_unlock_irq ( & zfcp_data . config_lock ) ;
2008-06-10 20:20:57 +04:00
zfcp_qdio_free ( 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 ) ;
}
2008-07-02 12:56:38 +04:00
static void zfcp_sysfs_port_release ( struct device * dev )
{
kfree ( container_of ( dev , struct zfcp_port , sysfs_device ) ) ;
}
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
* Locks : config_sema must be held to serialize changes to the port list
*
* 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 ;
2008-07-02 12:56:38 +04:00
int retval ;
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 )
2008-07-02 12:56:37 +04:00
return ERR_PTR ( - ENOMEM ) ;
2005-04-17 02:20:36 +04:00
init_waitqueue_head ( & port - > remove_wq ) ;
INIT_LIST_HEAD ( & port - > unit_list_head ) ;
2008-10-01 14:42:17 +04:00
INIT_WORK ( & port - > gid_pn_work , zfcp_erp_port_strategy_open_lookup ) ;
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 ;
2005-04-17 02:20:36 +04:00
2008-07-02 12:56:37 +04:00
/* mark port unusable as long as sysfs registration is not complete */
atomic_set_mask ( status | ZFCP_STATUS_COMMON_REMOVE , & port - > status ) ;
atomic_set ( & port - > refcount , 0 ) ;
2005-04-17 02:20:36 +04:00
2008-11-04 18:35:09 +03:00
dev_set_name ( & port - > sysfs_device , " 0x%016llx " ,
( unsigned long long ) wwpn ) ;
2008-10-01 14:42:17 +04:00
port - > sysfs_device . parent = & adapter - > ccw_device - > dev ;
2008-06-10 20:21:00 +04:00
2005-04-17 02:20:36 +04:00
port - > sysfs_device . release = zfcp_sysfs_port_release ;
dev_set_drvdata ( & port - > sysfs_device , port ) ;
2008-07-02 12:56:37 +04:00
read_lock_irq ( & zfcp_data . config_lock ) ;
if ( ! ( status & ZFCP_STATUS_PORT_NO_WWPN ) )
if ( zfcp_get_port_by_wwpn ( adapter , wwpn ) ) {
read_unlock_irq ( & zfcp_data . config_lock ) ;
goto err_out_free ;
}
read_unlock_irq ( & zfcp_data . config_lock ) ;
2005-04-17 02:20:36 +04:00
2008-07-02 12:56:37 +04:00
if ( device_register ( & port - > sysfs_device ) )
goto err_out_free ;
2005-04-17 02:20:36 +04:00
2008-10-01 14:42:17 +04:00
retval = sysfs_create_group ( & port - > sysfs_device . kobj ,
& zfcp_sysfs_port_attrs ) ;
2008-07-02 12:56:38 +04:00
if ( retval ) {
2005-04-17 02:20:36 +04:00
device_unregister ( & port - > sysfs_device ) ;
2008-07-02 12:56:37 +04:00
goto err_out ;
2005-04-17 02:20:36 +04:00
}
zfcp_port_get ( port ) ;
write_lock_irq ( & zfcp_data . config_lock ) ;
2005-08-27 22:07:54 +04:00
list_add_tail ( & port - > list , & adapter - > port_list_head ) ;
2005-04-17 02:20:36 +04:00
atomic_clear_mask ( ZFCP_STATUS_COMMON_REMOVE , & port - > status ) ;
atomic_set_mask ( ZFCP_STATUS_COMMON_RUNNING , & port - > status ) ;
2008-07-02 12:56:37 +04:00
2005-04-17 02:20:36 +04:00
write_unlock_irq ( & zfcp_data . config_lock ) ;
zfcp_adapter_get ( adapter ) ;
return port ;
2008-07-02 12:56:37 +04:00
err_out_free :
kfree ( port ) ;
err_out :
return ERR_PTR ( - EINVAL ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-02 12:56:37 +04:00
/**
* zfcp_port_dequeue - dequeues a port from the port list of the adapter
* @ port : pointer to struct zfcp_port which should be removed
*/
void zfcp_port_dequeue ( struct zfcp_port * port )
2005-04-17 02:20:36 +04:00
{
2008-10-01 14:42:16 +04:00
wait_event ( port - > remove_wq , atomic_read ( & port - > refcount ) = = 0 ) ;
2005-04-17 02:20:36 +04:00
write_lock_irq ( & zfcp_data . config_lock ) ;
list_del ( & port - > list ) ;
write_unlock_irq ( & zfcp_data . config_lock ) ;
2005-08-27 22:07:54 +04:00
if ( port - > rport )
2005-08-29 00:22:37 +04:00
fc_remote_port_delete ( port - > rport ) ;
port - > rport = NULL ;
2005-04-17 02:20:36 +04:00
zfcp_adapter_put ( port - > adapter ) ;
2008-10-01 14:42:17 +04:00
sysfs_remove_group ( & port - > sysfs_device . kobj , & zfcp_sysfs_port_attrs ) ;
2005-04-17 02:20:36 +04:00
device_unregister ( & port - > sysfs_device ) ;
}
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 ;
}