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
*
2010-02-17 13:18:56 +03:00
* Copyright IBM Corporation 2002 , 2010
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"
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:21 +04:00
# define ZFCP_MODEL_PRIV 0x4
2009-11-24 18:54:00 +03:00
static DEFINE_SPINLOCK ( zfcp_ccw_adapter_ref_lock ) ;
struct zfcp_adapter * zfcp_ccw_adapter_by_cdev ( struct ccw_device * cdev )
{
struct zfcp_adapter * adapter ;
unsigned long flags ;
spin_lock_irqsave ( & zfcp_ccw_adapter_ref_lock , flags ) ;
adapter = dev_get_drvdata ( & cdev - > dev ) ;
if ( adapter )
kref_get ( & adapter - > ref ) ;
spin_unlock_irqrestore ( & zfcp_ccw_adapter_ref_lock , flags ) ;
return adapter ;
}
void zfcp_ccw_adapter_put ( struct zfcp_adapter * adapter )
{
unsigned long flags ;
spin_lock_irqsave ( & zfcp_ccw_adapter_ref_lock , flags ) ;
kref_put ( & adapter - > ref , zfcp_adapter_release ) ;
spin_unlock_irqrestore ( & zfcp_ccw_adapter_ref_lock , flags ) ;
}
2009-06-16 12:30:34 +04:00
static int zfcp_ccw_activate ( struct ccw_device * cdev )
{
2009-11-24 18:54:00 +03:00
struct zfcp_adapter * adapter = zfcp_ccw_adapter_by_cdev ( cdev ) ;
2009-06-16 12:30:34 +04:00
2009-08-18 17:43:27 +04:00
if ( ! adapter )
return 0 ;
2010-09-08 16:40:01 +04:00
zfcp_erp_set_adapter_status ( adapter , ZFCP_STATUS_COMMON_RUNNING ) ;
2009-06-16 12:30:34 +04:00
zfcp_erp_adapter_reopen ( adapter , ZFCP_STATUS_COMMON_ERP_FAILED ,
2010-12-02 17:16:16 +03:00
" ccresu2 " ) ;
2009-06-16 12:30:34 +04:00
zfcp_erp_wait ( adapter ) ;
flush_work ( & adapter - > scan_work ) ;
2009-11-24 18:54:00 +03:00
zfcp_ccw_adapter_put ( adapter ) ;
2009-06-16 12:30:34 +04:00
return 0 ;
}
2009-05-15 15:18:21 +04:00
static struct ccw_device_id zfcp_ccw_device_id [ ] = {
{ CCW_DEVICE_DEVTYPE ( 0x1731 , 0x3 , 0x1732 , 0x3 ) } ,
{ CCW_DEVICE_DEVTYPE ( 0x1731 , 0x3 , 0x1732 , ZFCP_MODEL_PRIV ) } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( ccw , zfcp_ccw_device_id ) ;
/**
* zfcp_ccw_priv_sch - check if subchannel is privileged
* @ adapter : Adapter / Subchannel to check
*/
int zfcp_ccw_priv_sch ( struct zfcp_adapter * adapter )
{
return adapter - > ccw_device - > id . dev_model = = ZFCP_MODEL_PRIV ;
}
2005-04-17 02:20:36 +04:00
/**
* zfcp_ccw_probe - probe function of zfcp driver
2009-11-24 18:54:00 +03:00
* @ cdev : pointer to belonging ccw device
2005-04-17 02:20:36 +04:00
*
2009-08-18 17:43:27 +04:00
* This function gets called by the common i / o layer for each FCP
* device found on the current system . This is only a stub to make cio
* work : To only allocate adapter resources for devices actually used ,
* the allocation is deferred to the first call to ccw_set_online .
2005-04-17 02:20:36 +04:00
*/
2009-11-24 18:54:00 +03:00
static int zfcp_ccw_probe ( struct ccw_device * cdev )
2005-04-17 02:20:36 +04:00
{
2009-08-18 17:43:27 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
/**
* zfcp_ccw_remove - remove function of zfcp driver
2009-11-24 18:54:00 +03:00
* @ cdev : pointer to belonging ccw device
2005-04-17 02:20:36 +04:00
*
* 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 .
*/
2009-11-24 18:54:00 +03:00
static void zfcp_ccw_remove ( struct ccw_device * cdev )
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
2009-11-24 18:54:00 +03:00
ccw_device_set_offline ( cdev ) ;
2009-09-24 12:23:24 +04:00
2009-11-24 18:54:00 +03:00
adapter = zfcp_ccw_adapter_by_cdev ( cdev ) ;
2009-11-24 18:53:58 +03:00
if ( ! adapter )
return ;
write_lock_irq ( & adapter - > port_list_lock ) ;
list_for_each_entry_safe ( port , p , & adapter - > port_list , list ) {
write_lock ( & port - > unit_list_lock ) ;
2009-11-24 18:54:05 +03:00
list_for_each_entry_safe ( unit , u , & port - > unit_list , list )
2009-11-24 18:53:58 +03:00
list_move ( & unit - > list , & unit_remove_lh ) ;
write_unlock ( & port - > unit_list_lock ) ;
list_move ( & port - > list , & port_remove_lh ) ;
2005-04-17 02:20:36 +04:00
}
2009-11-24 18:53:58 +03:00
write_unlock_irq ( & adapter - > port_list_lock ) ;
2009-11-24 18:54:00 +03:00
zfcp_ccw_adapter_put ( adapter ) ; /* put from zfcp_ccw_adapter_by_cdev */
2005-04-17 02:20:36 +04:00
2009-11-24 18:53:59 +03:00
list_for_each_entry_safe ( unit , u , & unit_remove_lh , list )
2010-02-17 13:18:56 +03:00
zfcp_device_unregister ( & unit - > dev , & zfcp_sysfs_unit_attrs ) ;
2009-11-24 18:53:59 +03:00
list_for_each_entry_safe ( port , p , & port_remove_lh , list )
2010-02-17 13:18:56 +03:00
zfcp_device_unregister ( & port - > dev , & zfcp_sysfs_port_attrs ) ;
2009-11-24 18:53:59 +03:00
2009-11-24 18:54:00 +03:00
zfcp_adapter_unregister ( adapter ) ;
2005-04-17 02:20:36 +04:00
}
/**
* zfcp_ccw_set_online - set_online function of zfcp driver
2009-11-24 18:54:00 +03:00
* @ cdev : pointer to belonging ccw device
2005-04-17 02:20:36 +04:00
*
2009-08-18 17:43:27 +04:00
* This function gets called by the common i / o layer and sets an
* adapter into state online . The first call will allocate all
* adapter resources that will be retained until the device is removed
* via zfcp_ccw_remove .
*
* 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 .
2005-04-17 02:20:36 +04:00
*/
2009-11-24 18:54:00 +03:00
static int zfcp_ccw_set_online ( struct ccw_device * cdev )
2005-04-17 02:20:36 +04:00
{
2009-11-24 18:54:00 +03:00
struct zfcp_adapter * adapter = zfcp_ccw_adapter_by_cdev ( cdev ) ;
2005-04-17 02:20:36 +04:00
2009-08-18 17:43:27 +04:00
if ( ! adapter ) {
2009-11-24 18:54:00 +03:00
adapter = zfcp_adapter_enqueue ( cdev ) ;
if ( IS_ERR ( adapter ) ) {
dev_err ( & cdev - > dev ,
2009-08-18 17:43:27 +04:00
" Setting up data structures for the "
" FCP adapter failed \n " ) ;
2009-11-24 18:54:00 +03:00
return PTR_ERR ( adapter ) ;
2009-08-18 17:43:27 +04:00
}
2009-11-24 18:54:00 +03:00
kref_get ( & adapter - > ref ) ;
2009-08-18 17:43:27 +04:00
}
2005-04-17 02:20:36 +04:00
2006-08-02 13:05:16 +04:00
/* initialize request counter */
2010-02-17 13:18:50 +03:00
BUG_ON ( ! zfcp_reqlist_isempty ( adapter - > req_list ) ) ;
2006-08-02 13:05:16 +04:00
adapter - > req_no = 0 ;
2010-09-08 16:40:00 +04:00
zfcp_ccw_activate ( cdev ) ;
2009-11-24 18:54:00 +03:00
zfcp_ccw_adapter_put ( adapter ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
/**
* zfcp_ccw_set_offline - set_offline function of zfcp driver
2009-11-24 18:54:00 +03:00
* @ cdev : pointer to belonging ccw device
2005-04-17 02:20:36 +04:00
*
* 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
*/
2009-11-24 18:54:00 +03:00
static int zfcp_ccw_set_offline ( struct ccw_device * cdev )
2005-04-17 02:20:36 +04:00
{
2009-11-24 18:54:00 +03:00
struct zfcp_adapter * adapter = zfcp_ccw_adapter_by_cdev ( cdev ) ;
if ( ! adapter )
return 0 ;
2005-04-17 02:20:36 +04:00
2010-12-02 17:16:16 +03:00
zfcp_erp_adapter_shutdown ( adapter , 0 , " ccsoff1 " ) ;
2005-04-17 02:20:36 +04:00
zfcp_erp_wait ( adapter ) ;
2009-11-24 18:54:00 +03:00
zfcp_ccw_adapter_put ( adapter ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
/**
2008-06-10 20:20:56 +04:00
* zfcp_ccw_notify - ccw notify function
2009-11-24 18:54:00 +03:00
* @ cdev : pointer to belonging ccw device
2005-04-17 02:20:36 +04:00
* @ 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 .
*/
2009-11-24 18:54:00 +03:00
static int zfcp_ccw_notify ( struct ccw_device * cdev , int event )
2005-04-17 02:20:36 +04:00
{
2009-11-24 18:54:00 +03:00
struct zfcp_adapter * adapter = zfcp_ccw_adapter_by_cdev ( cdev ) ;
if ( ! adapter )
return 1 ;
2005-04-17 02:20:36 +04:00
switch ( event ) {
case CIO_GONE :
2009-11-24 18:54:00 +03:00
dev_warn ( & cdev - > dev , " The FCP device has been detached \n " ) ;
2010-12-02 17:16:16 +03:00
zfcp_erp_adapter_shutdown ( adapter , 0 , " ccnoti1 " ) ;
2005-04-17 02:20:36 +04:00
break ;
case CIO_NO_PATH :
2009-11-24 18:54:00 +03:00
dev_warn ( & cdev - > dev ,
2008-10-01 14:42:15 +04:00
" The CHPID for the FCP device is offline \n " ) ;
2010-12-02 17:16:16 +03:00
zfcp_erp_adapter_shutdown ( adapter , 0 , " ccnoti2 " ) ;
2005-04-17 02:20:36 +04:00
break ;
case CIO_OPER :
2009-11-24 18:54:00 +03:00
dev_info ( & cdev - > dev , " The FCP device is operational again \n " ) ;
2010-09-08 16:40:01 +04:00
zfcp_erp_set_adapter_status ( adapter ,
ZFCP_STATUS_COMMON_RUNNING ) ;
2008-04-18 14:51:55 +04:00
zfcp_erp_adapter_reopen ( adapter , ZFCP_STATUS_COMMON_ERP_FAILED ,
2010-12-02 17:16:16 +03:00
" ccnoti4 " ) ;
2005-04-17 02:20:36 +04:00
break ;
2009-03-31 21:16:05 +04:00
case CIO_BOXED :
2009-11-24 18:54:00 +03:00
dev_warn ( & cdev - > dev , " The FCP device did not respond within "
" the specified time \n " ) ;
2010-12-02 17:16:16 +03:00
zfcp_erp_adapter_shutdown ( adapter , 0 , " ccnoti5 " ) ;
2009-03-31 21:16:05 +04:00
break ;
2005-04-17 02:20:36 +04:00
}
2009-11-24 18:54:00 +03:00
zfcp_ccw_adapter_put ( adapter ) ;
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
{
2009-11-24 18:54:00 +03:00
struct zfcp_adapter * adapter = zfcp_ccw_adapter_by_cdev ( cdev ) ;
2005-04-17 02:20:36 +04:00
2009-09-24 12:23:23 +04:00
if ( ! adapter )
2009-11-24 18:54:00 +03:00
return ;
2009-09-24 12:23:23 +04:00
2010-12-02 17:16:16 +03:00
zfcp_erp_adapter_shutdown ( adapter , 0 , " ccshut1 " ) ;
2005-04-17 02:20:36 +04:00
zfcp_erp_wait ( adapter ) ;
2009-08-18 17:43:27 +04:00
zfcp_erp_thread_kill ( adapter ) ;
2009-11-24 18:54:00 +03:00
zfcp_ccw_adapter_put ( adapter ) ;
2005-04-17 02:20:36 +04:00
}
2009-09-24 12:23:22 +04:00
struct ccw_driver zfcp_ccw_driver = {
2011-03-23 12:16:02 +03:00
. driver = {
. owner = THIS_MODULE ,
. name = " zfcp " ,
} ,
2008-06-10 20:20:56 +04:00
. 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 ,
2009-11-24 18:54:01 +03:00
. freeze = zfcp_ccw_set_offline ,
2009-06-16 12:30:34 +04:00
. thaw = zfcp_ccw_activate ,
. restore = zfcp_ccw_activate ,
2008-06-10 20:20:56 +04:00
} ;