2005-04-17 02:20:36 +04:00
/*
2008-06-10 20:20:56 +04:00
* zfcp device driver
2005-04-17 02:20:36 +04:00
*
2008-06-10 20:20:56 +04:00
* Registration and callback for the s390 common I / O layer .
2005-04-17 02:20:36 +04:00
*
2009-03-02 15:09:11 +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
2005-04-17 02:20:36 +04:00
# include "zfcp_ext.h"
/**
* zfcp_ccw_probe - probe function of zfcp driver
* @ ccw_device : pointer to belonging ccw device
*
* This function gets called by the common i / o layer and sets up the initial
* data structures for each fcp adapter , which was detected by the system .
* Also the sysfs files for this adapter will be created by this function .
* In addition the nameserver port will be added to the ports of the adapter
* and its sysfs representation will be created too .
*/
2008-06-10 20:20:56 +04:00
static int zfcp_ccw_probe ( struct ccw_device * ccw_device )
2005-04-17 02:20:36 +04:00
{
int retval = 0 ;
down ( & zfcp_data . config_sema ) ;
2008-07-02 12:56:37 +04:00
if ( zfcp_adapter_enqueue ( ccw_device ) ) {
2008-06-10 20:20:56 +04:00
dev_err ( & ccw_device - > dev ,
2008-10-01 14:42:15 +04:00
" Setting up data structures for the "
" FCP adapter failed \n " ) ;
2005-04-17 02:20:36 +04:00
retval = - EINVAL ;
2008-06-10 20:20:56 +04:00
}
2005-04-17 02:20:36 +04:00
up ( & zfcp_data . config_sema ) ;
return retval ;
}
/**
* zfcp_ccw_remove - remove function of zfcp driver
* @ ccw_device : pointer to belonging ccw device
*
* This function gets called by the common i / o layer and removes an adapter
* from the system . Task of this function is to get rid of all units and
* ports that belong to this adapter . And in addition all resources of this
* adapter will be freed too .
*/
2008-06-10 20:20:56 +04:00
static void zfcp_ccw_remove ( struct ccw_device * ccw_device )
2005-04-17 02:20:36 +04:00
{
struct zfcp_adapter * adapter ;
struct zfcp_port * port , * p ;
struct zfcp_unit * unit , * u ;
2008-10-01 14:42:20 +04:00
LIST_HEAD ( unit_remove_lh ) ;
LIST_HEAD ( port_remove_lh ) ;
2005-04-17 02:20:36 +04:00
ccw_device_set_offline ( ccw_device ) ;
down ( & zfcp_data . config_sema ) ;
adapter = dev_get_drvdata ( & ccw_device - > dev ) ;
write_lock_irq ( & zfcp_data . config_lock ) ;
list_for_each_entry_safe ( port , p , & adapter - > port_list_head , list ) {
list_for_each_entry_safe ( unit , u , & port - > unit_list_head , list ) {
2008-10-01 14:42:20 +04:00
list_move ( & unit - > list , & unit_remove_lh ) ;
2005-04-17 02:20:36 +04:00
atomic_set_mask ( ZFCP_STATUS_COMMON_REMOVE ,
& unit - > status ) ;
}
2008-10-01 14:42:20 +04:00
list_move ( & port - > list , & port_remove_lh ) ;
2005-04-17 02:20:36 +04:00
atomic_set_mask ( ZFCP_STATUS_COMMON_REMOVE , & port - > status ) ;
}
atomic_set_mask ( ZFCP_STATUS_COMMON_REMOVE , & adapter - > status ) ;
write_unlock_irq ( & zfcp_data . config_lock ) ;
2008-10-01 14:42:20 +04:00
list_for_each_entry_safe ( port , p , & port_remove_lh , list ) {
list_for_each_entry_safe ( unit , u , & unit_remove_lh , list ) {
2009-03-02 15:08:55 +03:00
if ( unit - > device )
2007-11-05 14:37:46 +03:00
scsi_remove_device ( unit - > device ) ;
2005-04-17 02:20:36 +04:00
zfcp_unit_dequeue ( unit ) ;
}
zfcp_port_dequeue ( port ) ;
}
2008-10-01 14:42:16 +04:00
wait_event ( adapter - > remove_wq , atomic_read ( & adapter - > refcount ) = = 0 ) ;
2005-04-17 02:20:36 +04:00
zfcp_adapter_dequeue ( adapter ) ;
up ( & zfcp_data . config_sema ) ;
}
/**
* zfcp_ccw_set_online - set_online function of zfcp driver
* @ ccw_device : pointer to belonging ccw device
*
* This function gets called by the common i / o layer and sets an adapter
* into state online . Setting an fcp device online means that it will be
* registered with the SCSI stack , that the QDIO queues will be set up
* and that the adapter will be opened ( asynchronously ) .
*/
2008-06-10 20:20:56 +04:00
static int zfcp_ccw_set_online ( struct ccw_device * ccw_device )
2005-04-17 02:20:36 +04:00
{
struct zfcp_adapter * adapter ;
int retval ;
down ( & zfcp_data . config_sema ) ;
adapter = dev_get_drvdata ( & ccw_device - > dev ) ;
retval = zfcp_erp_thread_setup ( adapter ) ;
2008-06-10 20:20:56 +04:00
if ( retval )
2007-08-28 11:31:41 +04:00
goto out ;
2005-04-17 02:20:36 +04:00
2006-08-02 13:05:16 +04:00
/* initialize request counter */
BUG_ON ( ! zfcp_reqlist_isempty ( adapter ) ) ;
adapter - > req_no = 0 ;
2009-03-02 15:09:04 +03:00
zfcp_erp_modify_adapter_status ( adapter , " ccsonl1 " , NULL ,
2008-03-27 16:22:02 +03:00
ZFCP_STATUS_COMMON_RUNNING , ZFCP_SET ) ;
2009-03-02 15:09:04 +03:00
zfcp_erp_adapter_reopen ( adapter , ZFCP_STATUS_COMMON_ERP_FAILED ,
" ccsonl2 " , NULL ) ;
2005-04-17 02:20:36 +04:00
zfcp_erp_wait ( adapter ) ;
2008-11-04 18:35:10 +03:00
up ( & zfcp_data . config_sema ) ;
flush_work ( & adapter - > scan_work ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
out :
up ( & zfcp_data . config_sema ) ;
return retval ;
}
/**
* zfcp_ccw_set_offline - set_offline function of zfcp driver
* @ ccw_device : pointer to belonging ccw device
*
* This function gets called by the common i / o layer and sets an adapter
2007-05-09 13:01:24 +04:00
* into state offline .
2005-04-17 02:20:36 +04:00
*/
2008-06-10 20:20:56 +04:00
static int zfcp_ccw_set_offline ( struct ccw_device * ccw_device )
2005-04-17 02:20:36 +04:00
{
struct zfcp_adapter * adapter ;
down ( & zfcp_data . config_sema ) ;
adapter = dev_get_drvdata ( & ccw_device - > dev ) ;
2009-03-02 15:09:04 +03:00
zfcp_erp_adapter_shutdown ( adapter , 0 , " ccsoff1 " , NULL ) ;
2005-04-17 02:20:36 +04:00
zfcp_erp_wait ( adapter ) ;
zfcp_erp_thread_kill ( adapter ) ;
up ( & zfcp_data . config_sema ) ;
return 0 ;
}
/**
2008-06-10 20:20:56 +04:00
* zfcp_ccw_notify - ccw notify function
2005-04-17 02:20:36 +04:00
* @ ccw_device : pointer to belonging ccw device
* @ event : indicates if adapter was detached or attached
*
* This function gets called by the common i / o layer if an adapter has gone
* or reappeared .
*/
2008-06-10 20:20:56 +04:00
static int zfcp_ccw_notify ( struct ccw_device * ccw_device , int event )
2005-04-17 02:20:36 +04:00
{
2008-08-21 15:43:34 +04:00
struct zfcp_adapter * adapter = dev_get_drvdata ( & ccw_device - > dev ) ;
2005-04-17 02:20:36 +04:00
switch ( event ) {
case CIO_GONE :
2008-10-01 14:42:15 +04:00
dev_warn ( & adapter - > ccw_device - > dev ,
" The FCP device has been detached \n " ) ;
2009-03-02 15:09:04 +03:00
zfcp_erp_adapter_shutdown ( adapter , 0 , " ccnoti1 " , NULL ) ;
2005-04-17 02:20:36 +04:00
break ;
case CIO_NO_PATH :
2008-10-01 14:42:15 +04:00
dev_warn ( & adapter - > ccw_device - > dev ,
" The CHPID for the FCP device is offline \n " ) ;
2009-03-02 15:09:04 +03:00
zfcp_erp_adapter_shutdown ( adapter , 0 , " ccnoti2 " , NULL ) ;
2005-04-17 02:20:36 +04:00
break ;
case CIO_OPER :
2008-10-01 14:42:15 +04:00
dev_info ( & adapter - > ccw_device - > dev ,
" The FCP device is operational again \n " ) ;
2009-03-02 15:09:04 +03:00
zfcp_erp_modify_adapter_status ( adapter , " ccnoti3 " , NULL ,
2005-04-17 02:20:36 +04:00
ZFCP_STATUS_COMMON_RUNNING ,
ZFCP_SET ) ;
2008-04-18 14:51:55 +04:00
zfcp_erp_adapter_reopen ( adapter , ZFCP_STATUS_COMMON_ERP_FAILED ,
2009-03-02 15:09:04 +03:00
" ccnoti4 " , NULL ) ;
2005-04-17 02:20:36 +04:00
break ;
2009-03-31 21:16:05 +04:00
case CIO_BOXED :
2009-05-15 15:18:15 +04:00
dev_warn ( & adapter - > ccw_device - > dev , " The FCP device "
" did not respond within the specified time \n " ) ;
2009-03-31 21:16:05 +04:00
zfcp_erp_adapter_shutdown ( adapter , 0 , " ccnoti5 " , NULL ) ;
break ;
2005-04-17 02:20:36 +04:00
}
return 1 ;
}
/**
2008-06-10 20:20:56 +04:00
* zfcp_ccw_shutdown - handle shutdown from cio
* @ cdev : device for adapter to shutdown .
2005-04-17 02:20:36 +04:00
*/
2008-06-10 20:20:56 +04:00
static void zfcp_ccw_shutdown ( struct ccw_device * cdev )
2005-04-17 02:20:36 +04:00
{
struct zfcp_adapter * adapter ;
down ( & zfcp_data . config_sema ) ;
2007-10-12 18:11:21 +04:00
adapter = dev_get_drvdata ( & cdev - > dev ) ;
2009-03-02 15:09:04 +03:00
zfcp_erp_adapter_shutdown ( adapter , 0 , " ccshut1 " , NULL ) ;
2005-04-17 02:20:36 +04:00
zfcp_erp_wait ( adapter ) ;
up ( & zfcp_data . config_sema ) ;
}
2008-06-10 20:20:56 +04:00
static struct ccw_device_id zfcp_ccw_device_id [ ] = {
{ CCW_DEVICE_DEVTYPE ( 0x1731 , 0x3 , 0x1732 , 0x3 ) } ,
{ CCW_DEVICE_DEVTYPE ( 0x1731 , 0x3 , 0x1732 , 0x4 ) } , /* priv. */
{ } ,
} ;
MODULE_DEVICE_TABLE ( ccw , zfcp_ccw_device_id ) ;
static struct ccw_driver zfcp_ccw_driver = {
. owner = THIS_MODULE ,
. name = " zfcp " ,
. ids = zfcp_ccw_device_id ,
. probe = zfcp_ccw_probe ,
. remove = zfcp_ccw_remove ,
. set_online = zfcp_ccw_set_online ,
. set_offline = zfcp_ccw_set_offline ,
. notify = zfcp_ccw_notify ,
. shutdown = zfcp_ccw_shutdown ,
} ;
/**
* zfcp_ccw_register - ccw register function
*
* Registers the driver at the common i / o layer . This function will be called
* at module load time / system start .
*/
int __init zfcp_ccw_register ( void )
{
return ccw_driver_register ( & zfcp_ccw_driver ) ;
}
2008-10-01 14:42:19 +04:00
/**
* zfcp_get_adapter_by_busid - find zfcp_adapter struct
* @ busid : bus id string of zfcp adapter to find
*/
struct zfcp_adapter * zfcp_get_adapter_by_busid ( char * busid )
{
struct ccw_device * ccw_device ;
struct zfcp_adapter * adapter = NULL ;
ccw_device = get_ccwdev_by_busid ( & zfcp_ccw_driver , busid ) ;
if ( ccw_device ) {
adapter = dev_get_drvdata ( & ccw_device - > dev ) ;
put_device ( & ccw_device - > dev ) ;
}
return adapter ;
}