2005-04-17 02:20:36 +04:00
/*
* File . . . . . . . . . . . : linux / drivers / s390 / block / dasd_devmap . c
* Author ( s ) . . . . . . : Holger Smolinski < Holger . Smolinski @ de . ibm . com >
* Horst Hummel < Horst . Hummel @ de . ibm . com >
* Carsten Otte < Cotte @ de . ibm . com >
* Martin Schwidefsky < schwidefsky @ de . ibm . com >
* Bugreports . to . . : < Linux390 @ de . ibm . com >
* ( C ) IBM Corporation , IBM Deutschland Entwicklung GmbH , 1999 - 2001
*
* Device mapping and dasd = parameter parsing functions . All devmap
* functions may not be called from interrupt context . In particular
* dasd_get_device is a no - no from interrupt context .
*
*/
2009-03-26 17:23:49 +03:00
# define KMSG_COMPONENT "dasd"
2005-04-17 02:20:36 +04:00
# include <linux/ctype.h>
# include <linux/init.h>
2006-03-25 14:07:05 +03:00
# include <linux/module.h>
2005-04-17 02:20:36 +04:00
# include <asm/debug.h>
# include <asm/uaccess.h>
2007-04-27 18:01:48 +04:00
# include <asm/ipl.h>
2005-04-17 02:20:36 +04:00
/* This is ugly... */
# define PRINTK_HEADER "dasd_devmap:"
2008-12-25 15:38:55 +03:00
# define DASD_BUS_ID_SIZE 20
2005-04-17 02:20:36 +04:00
# include "dasd_int.h"
2006-12-07 07:33:20 +03:00
struct kmem_cache * dasd_page_cache ;
2006-06-29 17:08:18 +04:00
EXPORT_SYMBOL_GPL ( dasd_page_cache ) ;
2005-04-17 02:20:36 +04:00
/*
* dasd_devmap_t is used to store the features and the relation
* between device number and device index . To find a dasd_devmap_t
* that corresponds to a device number of a device index each
* dasd_devmap_t is added to two linked lists , one to search by
* the device number and one to search by the device index . As
* soon as big minor numbers are available the device index list
* can be removed since the device number will then be identical
* to the device index .
*/
struct dasd_devmap {
struct list_head list ;
2008-12-25 15:38:55 +03:00
char bus_id [ DASD_BUS_ID_SIZE ] ;
2005-04-17 02:20:36 +04:00
unsigned int devindex ;
unsigned short features ;
struct dasd_device * device ;
2006-04-28 05:40:28 +04:00
struct dasd_uid uid ;
2005-04-17 02:20:36 +04:00
} ;
/*
* Parameter parsing functions for dasd = parameter . The syntax is :
* < devno > : ( 0 x ) ? [ 0 - 9 a - fA - F ] +
* < busid > : [ 0 - 0 a - f ] \ . [ 0 - 9 a - f ] \ . ( 0 x ) ? [ 0 - 9 a - fA - F ] +
* < feature > : ro
* < feature_list > : \ ( < feature > ( : < feature > ) * \ )
* < devno - range > : < devno > ( - < devno > ) ? < feature_list > ?
* < busid - range > : < busid > ( - < busid > ) ? < feature_list > ?
* < devices > : < devno - range > | < busid - range >
* < dasd_module > : dasd_diag_mod | dasd_eckd_mod | dasd_fba_mod
*
* < dasd > : autodetect | probeonly | < devices > ( , < devices > ) *
*/
int dasd_probeonly = 0 ; /* is true, when probeonly mode is active */
int dasd_autodetect = 0 ; /* is true, when autodetection is active */
2006-06-29 17:08:18 +04:00
int dasd_nopav = 0 ; /* is true, when PAV is disabled */
EXPORT_SYMBOL_GPL ( dasd_nopav ) ;
2009-03-26 17:23:48 +03:00
int dasd_nofcx ; /* disable High Performance Ficon */
EXPORT_SYMBOL_GPL ( dasd_nofcx ) ;
2005-04-17 02:20:36 +04:00
/*
* char * dasd [ ] is intended to hold the ranges supplied by the dasd = statement
* it is named ' dasd ' to directly be filled by insmod with the comma separated
* strings when running as a module .
*/
static char * dasd [ 256 ] ;
2006-03-25 14:07:05 +03:00
module_param_array ( dasd , charp , NULL , 0 ) ;
2005-04-17 02:20:36 +04:00
/*
2006-08-10 17:45:16 +04:00
* Single spinlock to protect devmap and servermap structures and lists .
2005-04-17 02:20:36 +04:00
*/
static DEFINE_SPINLOCK ( dasd_devmap_lock ) ;
/*
* Hash lists for devmap structures .
*/
static struct list_head dasd_hashlists [ 256 ] ;
int dasd_max_devindex ;
2008-05-15 18:52:34 +04:00
static struct dasd_devmap * dasd_add_busid ( const char * , int ) ;
2005-04-17 02:20:36 +04:00
static inline int
2008-05-15 18:52:34 +04:00
dasd_hash_busid ( const char * bus_id )
2005-04-17 02:20:36 +04:00
{
int hash , i ;
hash = 0 ;
2008-12-25 15:38:55 +03:00
for ( i = 0 ; ( i < DASD_BUS_ID_SIZE ) & & * bus_id ; i + + , bus_id + + )
2005-04-17 02:20:36 +04:00
hash + = * bus_id ;
return hash & 0xff ;
}
# ifndef MODULE
/*
* The parameter parsing functions for builtin - drivers are called
* before kmalloc works . Store the pointers to the parameters strings
* into dasd [ ] for later processing .
*/
static int __init
dasd_call_setup ( char * str )
{
static int count = 0 ;
if ( count < 256 )
dasd [ count + + ] = str ;
return 1 ;
}
__setup ( " dasd= " , dasd_call_setup ) ;
# endif /* #ifndef MODULE */
2007-04-27 18:01:48 +04:00
# define DASD_IPLDEV "ipldev"
2005-04-17 02:20:36 +04:00
/*
* Read a device busid / devno from a string .
*/
2007-02-05 23:18:53 +03:00
static int
2009-03-26 17:23:49 +03:00
2005-04-17 02:20:36 +04:00
dasd_busid ( char * * str , int * id0 , int * id1 , int * devno )
{
int val , old_style ;
2006-06-29 16:58:12 +04:00
2007-04-27 18:01:48 +04:00
/* Interpret ipldev busid */
if ( strncmp ( DASD_IPLDEV , * str , strlen ( DASD_IPLDEV ) ) = = 0 ) {
if ( ipl_info . type ! = IPL_TYPE_CCW ) {
2009-03-26 17:23:49 +03:00
pr_err ( " The IPL device is not a CCW device \n " ) ;
2007-04-27 18:01:48 +04:00
return - EINVAL ;
}
* id0 = 0 ;
* id1 = ipl_info . data . ccw . dev_id . ssid ;
* devno = ipl_info . data . ccw . dev_id . devno ;
* str + = strlen ( DASD_IPLDEV ) ;
return 0 ;
}
2005-04-17 02:20:36 +04:00
/* check for leading '0x' */
old_style = 0 ;
if ( ( * str ) [ 0 ] = = ' 0 ' & & ( * str ) [ 1 ] = = ' x ' ) {
* str + = 2 ;
old_style = 1 ;
}
if ( ! isxdigit ( ( * str ) [ 0 ] ) ) /* We require at least one hex digit */
return - EINVAL ;
val = simple_strtoul ( * str , str , 16 ) ;
if ( old_style | | ( * str ) [ 0 ] ! = ' . ' ) {
* id0 = * id1 = 0 ;
if ( val < 0 | | val > 0xffff )
return - EINVAL ;
* devno = val ;
return 0 ;
}
/* New style x.y.z busid */
if ( val < 0 | | val > 0xff )
return - EINVAL ;
* id0 = val ;
( * str ) + + ;
if ( ! isxdigit ( ( * str ) [ 0 ] ) ) /* We require at least one hex digit */
return - EINVAL ;
val = simple_strtoul ( * str , str , 16 ) ;
if ( val < 0 | | val > 0xff | | ( * str ) + + [ 0 ] ! = ' . ' )
return - EINVAL ;
* id1 = val ;
if ( ! isxdigit ( ( * str ) [ 0 ] ) ) /* We require at least one hex digit */
return - EINVAL ;
val = simple_strtoul ( * str , str , 16 ) ;
if ( val < 0 | | val > 0xffff )
return - EINVAL ;
* devno = val ;
return 0 ;
}
/*
* Read colon separated list of dasd features . Currently there is
* only one : " ro " for read - only devices . The default feature set
* is empty ( value 0 ) .
*/
2007-02-05 23:18:53 +03:00
static int
2005-04-17 02:20:36 +04:00
dasd_feature_list ( char * str , char * * endp )
{
int features , len , rc ;
rc = 0 ;
if ( * str ! = ' ( ' ) {
* endp = str ;
return DASD_FEATURE_DEFAULT ;
}
str + + ;
features = 0 ;
while ( 1 ) {
2006-06-29 16:58:12 +04:00
for ( len = 0 ;
2005-04-17 02:20:36 +04:00
str [ len ] & & str [ len ] ! = ' : ' & & str [ len ] ! = ' ) ' ; len + + ) ;
if ( len = = 2 & & ! strncmp ( str , " ro " , 2 ) )
features | = DASD_FEATURE_READONLY ;
else if ( len = = 4 & & ! strncmp ( str , " diag " , 4 ) )
features | = DASD_FEATURE_USEDIAG ;
2006-12-08 17:54:15 +03:00
else if ( len = = 6 & & ! strncmp ( str , " erplog " , 6 ) )
features | = DASD_FEATURE_ERPLOG ;
2009-01-09 14:14:51 +03:00
else if ( len = = 8 & & ! strncmp ( str , " failfast " , 8 ) )
features | = DASD_FEATURE_FAILFAST ;
2005-04-17 02:20:36 +04:00
else {
2009-03-26 17:23:49 +03:00
pr_warning ( " %*s is not a supported device option \n " ,
len , str ) ;
2005-04-17 02:20:36 +04:00
rc = - EINVAL ;
}
str + = len ;
if ( * str ! = ' : ' )
break ;
str + + ;
}
if ( * str ! = ' ) ' ) {
2009-03-26 17:23:49 +03:00
pr_warning ( " A closing parenthesis ')' is missing in the "
" dasd= parameter \n " ) ;
2005-04-17 02:20:36 +04:00
rc = - EINVAL ;
} else
str + + ;
* endp = str ;
if ( rc ! = 0 )
return rc ;
return features ;
}
/*
* Try to match the first element on the comma separated parse string
* with one of the known keywords . If a keyword is found , take the approprate
* action and return a pointer to the residual string . If the first element
* could not be matched to any keyword then return an error code .
*/
static char *
dasd_parse_keyword ( char * parsestring ) {
char * nextcomma , * residual_str ;
int length ;
nextcomma = strchr ( parsestring , ' , ' ) ;
if ( nextcomma ) {
length = nextcomma - parsestring ;
residual_str = nextcomma + 1 ;
} else {
length = strlen ( parsestring ) ;
residual_str = parsestring + length ;
}
2006-06-29 17:08:18 +04:00
if ( strncmp ( " autodetect " , parsestring , length ) = = 0 ) {
2005-04-17 02:20:36 +04:00
dasd_autodetect = 1 ;
2009-03-26 17:23:49 +03:00
pr_info ( " The autodetection mode has been activated \n " ) ;
2005-04-17 02:20:36 +04:00
return residual_str ;
}
2006-06-29 17:08:18 +04:00
if ( strncmp ( " probeonly " , parsestring , length ) = = 0 ) {
2005-04-17 02:20:36 +04:00
dasd_probeonly = 1 ;
2009-03-26 17:23:49 +03:00
pr_info ( " The probeonly mode has been activated \n " ) ;
2005-04-17 02:20:36 +04:00
return residual_str ;
}
2006-06-29 17:08:18 +04:00
if ( strncmp ( " nopav " , parsestring , length ) = = 0 ) {
2006-09-20 17:59:52 +04:00
if ( MACHINE_IS_VM )
2009-03-26 17:23:49 +03:00
pr_info ( " 'nopav' is not supported on z/VM \n " ) ;
2006-09-20 17:59:52 +04:00
else {
dasd_nopav = 1 ;
2009-03-26 17:23:49 +03:00
pr_info ( " PAV support has be deactivated \n " ) ;
2006-09-20 17:59:52 +04:00
}
2006-06-29 17:08:18 +04:00
return residual_str ;
}
2009-03-26 17:23:48 +03:00
if ( strncmp ( " nofcx " , parsestring , length ) = = 0 ) {
dasd_nofcx = 1 ;
2009-03-26 17:23:49 +03:00
pr_info ( " High Performance FICON support has been "
" deactivated \n " ) ;
2009-03-26 17:23:48 +03:00
return residual_str ;
}
2006-06-29 17:08:18 +04:00
if ( strncmp ( " fixedbuffers " , parsestring , length ) = = 0 ) {
2005-04-17 02:20:36 +04:00
if ( dasd_page_cache )
return residual_str ;
dasd_page_cache =
2006-08-16 15:49:27 +04:00
kmem_cache_create ( " dasd_page_cache " , PAGE_SIZE ,
PAGE_SIZE , SLAB_CACHE_DMA ,
2007-07-20 05:11:58 +04:00
NULL ) ;
2005-04-17 02:20:36 +04:00
if ( ! dasd_page_cache )
2009-03-26 17:23:49 +03:00
DBF_EVENT ( DBF_WARNING , " %s " , " Failed to create slab, "
2005-04-17 02:20:36 +04:00
" fixed buffer mode disabled. " ) ;
else
2009-03-26 17:23:49 +03:00
DBF_EVENT ( DBF_INFO , " %s " ,
2005-04-17 02:20:36 +04:00
" turning on fixed buffer mode " ) ;
return residual_str ;
}
return ERR_PTR ( - EINVAL ) ;
}
/*
* Try to interprete the first element on the comma separated parse string
* as a device number or a range of devices . If the interpretation is
* successfull , create the matching dasd_devmap entries and return a pointer
* to the residual string .
* If interpretation fails or in case of an error , return an error code .
*/
static char *
dasd_parse_range ( char * parsestring ) {
struct dasd_devmap * devmap ;
int from , from_id0 , from_id1 ;
int to , to_id0 , to_id1 ;
int features , rc ;
2008-12-25 15:38:55 +03:00
char bus_id [ DASD_BUS_ID_SIZE + 1 ] , * str ;
2005-04-17 02:20:36 +04:00
str = parsestring ;
rc = dasd_busid ( & str , & from_id0 , & from_id1 , & from ) ;
if ( rc = = 0 ) {
to = from ;
to_id0 = from_id0 ;
to_id1 = from_id1 ;
if ( * str = = ' - ' ) {
str + + ;
rc = dasd_busid ( & str , & to_id0 , & to_id1 , & to ) ;
}
}
if ( rc = = 0 & &
( from_id0 ! = to_id0 | | from_id1 ! = to_id1 | | from > to ) )
rc = - EINVAL ;
if ( rc ) {
2009-03-26 17:23:49 +03:00
pr_err ( " %s is not a valid device range \n " , parsestring ) ;
2005-04-17 02:20:36 +04:00
return ERR_PTR ( rc ) ;
}
features = dasd_feature_list ( str , & str ) ;
if ( features < 0 )
return ERR_PTR ( - EINVAL ) ;
2006-06-29 17:08:18 +04:00
/* each device in dasd= parameter should be set initially online */
features | = DASD_FEATURE_INITIAL_ONLINE ;
2005-04-17 02:20:36 +04:00
while ( from < = to ) {
sprintf ( bus_id , " %01x.%01x.%04x " ,
from_id0 , from_id1 , from + + ) ;
devmap = dasd_add_busid ( bus_id , features ) ;
if ( IS_ERR ( devmap ) )
return ( char * ) devmap ;
}
if ( * str = = ' , ' )
return str + 1 ;
if ( * str = = ' \0 ' )
return str ;
2009-03-26 17:23:49 +03:00
pr_warning ( " The dasd= parameter value %s has an invalid ending \n " ,
str ) ;
2005-04-17 02:20:36 +04:00
return ERR_PTR ( - EINVAL ) ;
}
2007-02-05 23:18:53 +03:00
static char *
2005-04-17 02:20:36 +04:00
dasd_parse_next_element ( char * parsestring ) {
char * residual_str ;
residual_str = dasd_parse_keyword ( parsestring ) ;
if ( ! IS_ERR ( residual_str ) )
return residual_str ;
residual_str = dasd_parse_range ( parsestring ) ;
return residual_str ;
}
/*
* Parse parameters stored in dasd [ ]
* The ' dasd = . . . ' parameter allows to specify a comma separated list of
* keywords and device ranges . When the dasd driver is build into the kernel ,
* the complete list will be stored as one element of the dasd [ ] array .
* When the dasd driver is build as a module , then the list is broken into
* it ' s elements and each dasd [ ] entry contains one element .
*/
int
dasd_parse ( void )
{
int rc , i ;
char * parsestring ;
rc = 0 ;
for ( i = 0 ; i < 256 ; i + + ) {
if ( dasd [ i ] = = NULL )
break ;
parsestring = dasd [ i ] ;
/* loop over the comma separated list in the parsestring */
while ( * parsestring ) {
parsestring = dasd_parse_next_element ( parsestring ) ;
if ( IS_ERR ( parsestring ) ) {
rc = PTR_ERR ( parsestring ) ;
break ;
}
}
if ( rc ) {
DBF_EVENT ( DBF_ALERT , " %s " , " invalid range found " ) ;
break ;
}
}
return rc ;
}
/*
* Add a devmap for the device specified by busid . It is possible that
* the devmap already exists ( dasd = parameter ) . The order of the devices
* added through this function will define the kdevs for the individual
2006-06-29 16:58:12 +04:00
* devices .
2005-04-17 02:20:36 +04:00
*/
static struct dasd_devmap *
2008-05-15 18:52:34 +04:00
dasd_add_busid ( const char * bus_id , int features )
2005-04-17 02:20:36 +04:00
{
struct dasd_devmap * devmap , * new , * tmp ;
int hash ;
new = ( struct dasd_devmap * )
2006-06-29 16:58:12 +04:00
kzalloc ( sizeof ( struct dasd_devmap ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! new )
return ERR_PTR ( - ENOMEM ) ;
spin_lock ( & dasd_devmap_lock ) ;
2006-07-12 18:41:55 +04:00
devmap = NULL ;
2005-04-17 02:20:36 +04:00
hash = dasd_hash_busid ( bus_id ) ;
list_for_each_entry ( tmp , & dasd_hashlists [ hash ] , list )
2008-12-25 15:38:55 +03:00
if ( strncmp ( tmp - > bus_id , bus_id , DASD_BUS_ID_SIZE ) = = 0 ) {
2005-04-17 02:20:36 +04:00
devmap = tmp ;
break ;
}
if ( ! devmap ) {
/* This bus_id is new. */
new - > devindex = dasd_max_devindex + + ;
2008-12-25 15:38:55 +03:00
strncpy ( new - > bus_id , bus_id , DASD_BUS_ID_SIZE ) ;
2005-04-17 02:20:36 +04:00
new - > features = features ;
2006-07-12 18:41:55 +04:00
new - > device = NULL ;
2005-04-17 02:20:36 +04:00
list_add ( & new - > list , & dasd_hashlists [ hash ] ) ;
devmap = new ;
2006-07-12 18:41:55 +04:00
new = NULL ;
2005-04-17 02:20:36 +04:00
}
spin_unlock ( & dasd_devmap_lock ) ;
2005-11-07 12:01:30 +03:00
kfree ( new ) ;
2005-04-17 02:20:36 +04:00
return devmap ;
}
/*
* Find devmap for device with given bus_id .
*/
static struct dasd_devmap *
2008-05-15 18:52:34 +04:00
dasd_find_busid ( const char * bus_id )
2005-04-17 02:20:36 +04:00
{
struct dasd_devmap * devmap , * tmp ;
int hash ;
spin_lock ( & dasd_devmap_lock ) ;
devmap = ERR_PTR ( - ENODEV ) ;
hash = dasd_hash_busid ( bus_id ) ;
list_for_each_entry ( tmp , & dasd_hashlists [ hash ] , list ) {
2008-12-25 15:38:55 +03:00
if ( strncmp ( tmp - > bus_id , bus_id , DASD_BUS_ID_SIZE ) = = 0 ) {
2005-04-17 02:20:36 +04:00
devmap = tmp ;
break ;
}
}
spin_unlock ( & dasd_devmap_lock ) ;
return devmap ;
}
/*
* Check if busid has been added to the list of dasd ranges .
*/
int
2008-05-15 18:52:34 +04:00
dasd_busid_known ( const char * bus_id )
2005-04-17 02:20:36 +04:00
{
return IS_ERR ( dasd_find_busid ( bus_id ) ) ? - ENOENT : 0 ;
}
/*
* Forget all about the device numbers added so far .
* This may only be called at module unload or system shutdown .
*/
static void
dasd_forget_ranges ( void )
{
struct dasd_devmap * devmap , * n ;
int i ;
spin_lock ( & dasd_devmap_lock ) ;
for ( i = 0 ; i < 256 ; i + + ) {
list_for_each_entry_safe ( devmap , n , & dasd_hashlists [ i ] , list ) {
2006-03-26 20:33:07 +04:00
BUG_ON ( devmap - > device ! = NULL ) ;
2005-04-17 02:20:36 +04:00
list_del ( & devmap - > list ) ;
kfree ( devmap ) ;
}
}
spin_unlock ( & dasd_devmap_lock ) ;
}
/*
* Find the device struct by its device index .
*/
struct dasd_device *
dasd_device_from_devindex ( int devindex )
{
struct dasd_devmap * devmap , * tmp ;
struct dasd_device * device ;
int i ;
spin_lock ( & dasd_devmap_lock ) ;
2006-07-12 18:41:55 +04:00
devmap = NULL ;
2005-04-17 02:20:36 +04:00
for ( i = 0 ; ( i < 256 ) & & ! devmap ; i + + )
list_for_each_entry ( tmp , & dasd_hashlists [ i ] , list )
if ( tmp - > devindex = = devindex ) {
/* Found the devmap for the device. */
devmap = tmp ;
break ;
}
if ( devmap & & devmap - > device ) {
device = devmap - > device ;
dasd_get_device ( device ) ;
} else
device = ERR_PTR ( - ENODEV ) ;
spin_unlock ( & dasd_devmap_lock ) ;
return device ;
}
/*
* Return devmap for cdev . If no devmap exists yet , create one and
* connect it to the cdev .
*/
static struct dasd_devmap *
dasd_devmap_from_cdev ( struct ccw_device * cdev )
{
struct dasd_devmap * devmap ;
2008-10-10 23:33:09 +04:00
devmap = dasd_find_busid ( dev_name ( & cdev - > dev ) ) ;
2005-04-17 02:20:36 +04:00
if ( IS_ERR ( devmap ) )
2008-10-10 23:33:09 +04:00
devmap = dasd_add_busid ( dev_name ( & cdev - > dev ) ,
2005-04-17 02:20:36 +04:00
DASD_FEATURE_DEFAULT ) ;
return devmap ;
}
/*
* Create a dasd device structure for cdev .
*/
struct dasd_device *
dasd_create_device ( struct ccw_device * cdev )
{
struct dasd_devmap * devmap ;
struct dasd_device * device ;
2006-09-20 17:59:05 +04:00
unsigned long flags ;
2005-04-17 02:20:36 +04:00
int rc ;
devmap = dasd_devmap_from_cdev ( cdev ) ;
if ( IS_ERR ( devmap ) )
return ( void * ) devmap ;
device = dasd_alloc_device ( ) ;
if ( IS_ERR ( device ) )
return device ;
2006-09-20 17:59:05 +04:00
atomic_set ( & device - > ref_count , 3 ) ;
2005-04-17 02:20:36 +04:00
spin_lock ( & dasd_devmap_lock ) ;
if ( ! devmap - > device ) {
devmap - > device = device ;
device - > devindex = devmap - > devindex ;
2005-09-04 02:57:58 +04:00
device - > features = devmap - > features ;
2005-04-17 02:20:36 +04:00
get_device ( & cdev - > dev ) ;
device - > cdev = cdev ;
rc = 0 ;
} else
/* Someone else was faster. */
rc = - EBUSY ;
spin_unlock ( & dasd_devmap_lock ) ;
if ( rc ) {
dasd_free_device ( device ) ;
return ERR_PTR ( rc ) ;
}
2006-09-20 17:59:05 +04:00
spin_lock_irqsave ( get_ccwdev_lock ( cdev ) , flags ) ;
2008-12-25 15:38:52 +03:00
dev_set_drvdata ( & cdev - > dev , device ) ;
2006-09-20 17:59:05 +04:00
spin_unlock_irqrestore ( get_ccwdev_lock ( cdev ) , flags ) ;
2005-04-17 02:20:36 +04:00
return device ;
}
/*
* Wait queue for dasd_delete_device waits .
*/
static DECLARE_WAIT_QUEUE_HEAD ( dasd_delete_wq ) ;
/*
* Remove a dasd device structure . The passed referenced
* is destroyed .
*/
void
dasd_delete_device ( struct dasd_device * device )
{
struct ccw_device * cdev ;
struct dasd_devmap * devmap ;
2006-09-20 17:59:05 +04:00
unsigned long flags ;
2005-04-17 02:20:36 +04:00
/* First remove device pointer from devmap. */
2008-10-10 23:33:09 +04:00
devmap = dasd_find_busid ( dev_name ( & device - > cdev - > dev ) ) ;
2006-03-26 20:33:07 +04:00
BUG_ON ( IS_ERR ( devmap ) ) ;
2005-04-17 02:20:36 +04:00
spin_lock ( & dasd_devmap_lock ) ;
if ( devmap - > device ! = device ) {
spin_unlock ( & dasd_devmap_lock ) ;
dasd_put_device ( device ) ;
return ;
}
devmap - > device = NULL ;
spin_unlock ( & dasd_devmap_lock ) ;
2006-09-20 17:59:05 +04:00
/* Disconnect dasd_device structure from ccw_device structure. */
spin_lock_irqsave ( get_ccwdev_lock ( device - > cdev ) , flags ) ;
2008-12-25 15:38:52 +03:00
dev_set_drvdata ( & device - > cdev - > dev , NULL ) ;
2006-09-20 17:59:05 +04:00
spin_unlock_irqrestore ( get_ccwdev_lock ( device - > cdev ) , flags ) ;
/*
* Drop ref_count by 3 , one for the devmap reference , one for
* the cdev reference and one for the passed reference .
*/
atomic_sub ( 3 , & device - > ref_count ) ;
2005-04-17 02:20:36 +04:00
/* Wait for reference counter to drop to zero. */
wait_event ( dasd_delete_wq , atomic_read ( & device - > ref_count ) = = 0 ) ;
/* Disconnect dasd_device structure from ccw_device structure. */
cdev = device - > cdev ;
device - > cdev = NULL ;
/* Put ccw_device structure. */
put_device ( & cdev - > dev ) ;
/* Now the device structure can be freed. */
dasd_free_device ( device ) ;
}
/*
* Reference counter dropped to zero . Wake up waiter
* in dasd_delete_device .
*/
void
dasd_put_device_wake ( struct dasd_device * device )
{
wake_up ( & dasd_delete_wq ) ;
}
2006-09-20 17:59:05 +04:00
/*
* Return dasd_device structure associated with cdev .
* This function needs to be called with the ccw device
* lock held . It can be used from interrupt context .
*/
struct dasd_device *
dasd_device_from_cdev_locked ( struct ccw_device * cdev )
{
2008-12-25 15:38:52 +03:00
struct dasd_device * device = dev_get_drvdata ( & cdev - > dev ) ;
2006-09-20 17:59:05 +04:00
if ( ! device )
return ERR_PTR ( - ENODEV ) ;
dasd_get_device ( device ) ;
return device ;
}
2005-04-17 02:20:36 +04:00
/*
* Return dasd_device structure associated with cdev .
*/
struct dasd_device *
dasd_device_from_cdev ( struct ccw_device * cdev )
{
struct dasd_device * device ;
2006-09-20 17:59:05 +04:00
unsigned long flags ;
2005-04-17 02:20:36 +04:00
2006-09-20 17:59:05 +04:00
spin_lock_irqsave ( get_ccwdev_lock ( cdev ) , flags ) ;
device = dasd_device_from_cdev_locked ( cdev ) ;
spin_unlock_irqrestore ( get_ccwdev_lock ( cdev ) , flags ) ;
2005-04-17 02:20:36 +04:00
return device ;
}
/*
* SECTION : files in sysfs
*/
2009-01-09 14:14:51 +03:00
/*
* failfast controls the behaviour , if no path is available
*/
static ssize_t dasd_ff_show ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
struct dasd_devmap * devmap ;
int ff_flag ;
2009-02-11 12:37:30 +03:00
devmap = dasd_find_busid ( dev_name ( dev ) ) ;
2009-01-09 14:14:51 +03:00
if ( ! IS_ERR ( devmap ) )
ff_flag = ( devmap - > features & DASD_FEATURE_FAILFAST ) ! = 0 ;
else
ff_flag = ( DASD_FEATURE_DEFAULT & DASD_FEATURE_FAILFAST ) ! = 0 ;
return snprintf ( buf , PAGE_SIZE , ff_flag ? " 1 \n " : " 0 \n " ) ;
}
static ssize_t dasd_ff_store ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
{
struct dasd_devmap * devmap ;
int val ;
char * endp ;
devmap = dasd_devmap_from_cdev ( to_ccwdev ( dev ) ) ;
if ( IS_ERR ( devmap ) )
return PTR_ERR ( devmap ) ;
val = simple_strtoul ( buf , & endp , 0 ) ;
if ( ( ( endp + 1 ) < ( buf + count ) ) | | ( val > 1 ) )
return - EINVAL ;
spin_lock ( & dasd_devmap_lock ) ;
if ( val )
devmap - > features | = DASD_FEATURE_FAILFAST ;
else
devmap - > features & = ~ DASD_FEATURE_FAILFAST ;
if ( devmap - > device )
devmap - > device - > features = devmap - > features ;
spin_unlock ( & dasd_devmap_lock ) ;
return count ;
}
static DEVICE_ATTR ( failfast , 0644 , dasd_ff_show , dasd_ff_store ) ;
2005-04-17 02:20:36 +04:00
/*
* readonly controls the readonly status of a dasd
*/
static ssize_t
2005-05-17 14:42:58 +04:00
dasd_ro_show ( struct device * dev , struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
struct dasd_devmap * devmap ;
int ro_flag ;
2008-10-10 23:33:09 +04:00
devmap = dasd_find_busid ( dev_name ( dev ) ) ;
2005-04-17 02:20:36 +04:00
if ( ! IS_ERR ( devmap ) )
ro_flag = ( devmap - > features & DASD_FEATURE_READONLY ) ! = 0 ;
else
ro_flag = ( DASD_FEATURE_DEFAULT & DASD_FEATURE_READONLY ) ! = 0 ;
return snprintf ( buf , PAGE_SIZE , ro_flag ? " 1 \n " : " 0 \n " ) ;
}
static ssize_t
2006-06-29 16:58:12 +04:00
dasd_ro_store ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
2005-04-17 02:20:36 +04:00
{
struct dasd_devmap * devmap ;
2006-12-04 17:39:50 +03:00
int val ;
char * endp ;
2005-04-17 02:20:36 +04:00
devmap = dasd_devmap_from_cdev ( to_ccwdev ( dev ) ) ;
if ( IS_ERR ( devmap ) )
return PTR_ERR ( devmap ) ;
2006-12-04 17:39:50 +03:00
val = simple_strtoul ( buf , & endp , 0 ) ;
if ( ( ( endp + 1 ) < ( buf + count ) ) | | ( val > 1 ) )
return - EINVAL ;
2005-04-17 02:20:36 +04:00
spin_lock ( & dasd_devmap_lock ) ;
2006-12-04 17:39:50 +03:00
if ( val )
2005-04-17 02:20:36 +04:00
devmap - > features | = DASD_FEATURE_READONLY ;
else
devmap - > features & = ~ DASD_FEATURE_READONLY ;
2005-09-04 02:57:58 +04:00
if ( devmap - > device )
devmap - > device - > features = devmap - > features ;
2008-01-26 16:11:23 +03:00
if ( devmap - > device & & devmap - > device - > block
& & devmap - > device - > block - > gdp )
set_disk_ro ( devmap - > device - > block - > gdp , val ) ;
2005-04-17 02:20:36 +04:00
spin_unlock ( & dasd_devmap_lock ) ;
return count ;
}
static DEVICE_ATTR ( readonly , 0644 , dasd_ro_show , dasd_ro_store ) ;
2006-12-08 17:54:15 +03:00
/*
* erplog controls the logging of ERP related data
* ( e . g . failing channel programs ) .
*/
static ssize_t
dasd_erplog_show ( struct device * dev , struct device_attribute * attr , char * buf )
{
struct dasd_devmap * devmap ;
int erplog ;
2008-10-10 23:33:09 +04:00
devmap = dasd_find_busid ( dev_name ( dev ) ) ;
2006-12-08 17:54:15 +03:00
if ( ! IS_ERR ( devmap ) )
erplog = ( devmap - > features & DASD_FEATURE_ERPLOG ) ! = 0 ;
else
erplog = ( DASD_FEATURE_DEFAULT & DASD_FEATURE_ERPLOG ) ! = 0 ;
return snprintf ( buf , PAGE_SIZE , erplog ? " 1 \n " : " 0 \n " ) ;
}
static ssize_t
dasd_erplog_store ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
{
struct dasd_devmap * devmap ;
int val ;
char * endp ;
devmap = dasd_devmap_from_cdev ( to_ccwdev ( dev ) ) ;
if ( IS_ERR ( devmap ) )
return PTR_ERR ( devmap ) ;
val = simple_strtoul ( buf , & endp , 0 ) ;
if ( ( ( endp + 1 ) < ( buf + count ) ) | | ( val > 1 ) )
return - EINVAL ;
spin_lock ( & dasd_devmap_lock ) ;
if ( val )
devmap - > features | = DASD_FEATURE_ERPLOG ;
else
devmap - > features & = ~ DASD_FEATURE_ERPLOG ;
if ( devmap - > device )
devmap - > device - > features = devmap - > features ;
spin_unlock ( & dasd_devmap_lock ) ;
return count ;
}
static DEVICE_ATTR ( erplog , 0644 , dasd_erplog_show , dasd_erplog_store ) ;
2005-04-17 02:20:36 +04:00
/*
* use_diag controls whether the driver should use diag rather than ssch
* to talk to the device
*/
2006-06-29 16:58:12 +04:00
static ssize_t
2005-05-17 14:42:58 +04:00
dasd_use_diag_show ( struct device * dev , struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
struct dasd_devmap * devmap ;
int use_diag ;
2008-10-10 23:33:09 +04:00
devmap = dasd_find_busid ( dev_name ( dev ) ) ;
2005-04-17 02:20:36 +04:00
if ( ! IS_ERR ( devmap ) )
use_diag = ( devmap - > features & DASD_FEATURE_USEDIAG ) ! = 0 ;
else
use_diag = ( DASD_FEATURE_DEFAULT & DASD_FEATURE_USEDIAG ) ! = 0 ;
return sprintf ( buf , use_diag ? " 1 \n " : " 0 \n " ) ;
}
static ssize_t
2006-06-29 16:58:12 +04:00
dasd_use_diag_store ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
2005-04-17 02:20:36 +04:00
{
struct dasd_devmap * devmap ;
ssize_t rc ;
2006-12-04 17:39:50 +03:00
int val ;
char * endp ;
2005-04-17 02:20:36 +04:00
devmap = dasd_devmap_from_cdev ( to_ccwdev ( dev ) ) ;
if ( IS_ERR ( devmap ) )
return PTR_ERR ( devmap ) ;
2006-12-04 17:39:50 +03:00
val = simple_strtoul ( buf , & endp , 0 ) ;
if ( ( ( endp + 1 ) < ( buf + count ) ) | | ( val > 1 ) )
return - EINVAL ;
2005-04-17 02:20:36 +04:00
spin_lock ( & dasd_devmap_lock ) ;
/* Changing diag discipline flag is only allowed in offline state. */
rc = count ;
if ( ! devmap - > device ) {
2006-12-04 17:39:50 +03:00
if ( val )
2005-04-17 02:20:36 +04:00
devmap - > features | = DASD_FEATURE_USEDIAG ;
else
devmap - > features & = ~ DASD_FEATURE_USEDIAG ;
} else
rc = - EPERM ;
spin_unlock ( & dasd_devmap_lock ) ;
return rc ;
}
2006-06-29 16:58:12 +04:00
static DEVICE_ATTR ( use_diag , 0644 , dasd_use_diag_show , dasd_use_diag_store ) ;
2005-04-17 02:20:36 +04:00
static ssize_t
2006-06-29 16:58:12 +04:00
dasd_discipline_show ( struct device * dev , struct device_attribute * attr ,
char * buf )
2005-04-17 02:20:36 +04:00
{
2006-09-20 17:59:05 +04:00
struct dasd_device * device ;
ssize_t len ;
2005-04-17 02:20:36 +04:00
2006-09-20 17:59:05 +04:00
device = dasd_device_from_cdev ( to_ccwdev ( dev ) ) ;
if ( ! IS_ERR ( device ) & & device - > discipline ) {
len = snprintf ( buf , PAGE_SIZE , " %s \n " ,
device - > discipline - > name ) ;
dasd_put_device ( device ) ;
} else
len = snprintf ( buf , PAGE_SIZE , " none \n " ) ;
return len ;
2005-04-17 02:20:36 +04:00
}
static DEVICE_ATTR ( discipline , 0444 , dasd_discipline_show , NULL ) ;
2007-04-27 18:01:47 +04:00
static ssize_t
dasd_device_status_show ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
struct dasd_device * device ;
ssize_t len ;
device = dasd_device_from_cdev ( to_ccwdev ( dev ) ) ;
if ( ! IS_ERR ( device ) ) {
switch ( device - > state ) {
case DASD_STATE_NEW :
len = snprintf ( buf , PAGE_SIZE , " new \n " ) ;
break ;
case DASD_STATE_KNOWN :
len = snprintf ( buf , PAGE_SIZE , " detected \n " ) ;
break ;
case DASD_STATE_BASIC :
len = snprintf ( buf , PAGE_SIZE , " basic \n " ) ;
break ;
case DASD_STATE_UNFMT :
len = snprintf ( buf , PAGE_SIZE , " unformatted \n " ) ;
break ;
case DASD_STATE_READY :
len = snprintf ( buf , PAGE_SIZE , " ready \n " ) ;
break ;
case DASD_STATE_ONLINE :
len = snprintf ( buf , PAGE_SIZE , " online \n " ) ;
break ;
default :
len = snprintf ( buf , PAGE_SIZE , " no stat \n " ) ;
break ;
}
dasd_put_device ( device ) ;
} else
len = snprintf ( buf , PAGE_SIZE , " unknown \n " ) ;
return len ;
}
static DEVICE_ATTR ( status , 0444 , dasd_device_status_show , NULL ) ;
2006-04-28 05:40:28 +04:00
static ssize_t
dasd_alias_show ( struct device * dev , struct device_attribute * attr , char * buf )
{
struct dasd_devmap * devmap ;
int alias ;
2008-10-10 23:33:09 +04:00
devmap = dasd_find_busid ( dev_name ( dev ) ) ;
2006-04-28 05:40:28 +04:00
spin_lock ( & dasd_devmap_lock ) ;
2008-01-26 16:11:23 +03:00
if ( IS_ERR ( devmap ) | | strlen ( devmap - > uid . vendor ) = = 0 ) {
spin_unlock ( & dasd_devmap_lock ) ;
return sprintf ( buf , " 0 \n " ) ;
}
if ( devmap - > uid . type = = UA_BASE_PAV_ALIAS | |
devmap - > uid . type = = UA_HYPER_PAV_ALIAS )
alias = 1 ;
2006-04-28 05:40:28 +04:00
else
alias = 0 ;
spin_unlock ( & dasd_devmap_lock ) ;
return sprintf ( buf , alias ? " 1 \n " : " 0 \n " ) ;
}
static DEVICE_ATTR ( alias , 0444 , dasd_alias_show , NULL ) ;
static ssize_t
dasd_vendor_show ( struct device * dev , struct device_attribute * attr , char * buf )
{
struct dasd_devmap * devmap ;
char * vendor ;
2008-10-10 23:33:09 +04:00
devmap = dasd_find_busid ( dev_name ( dev ) ) ;
2006-04-28 05:40:28 +04:00
spin_lock ( & dasd_devmap_lock ) ;
if ( ! IS_ERR ( devmap ) & & strlen ( devmap - > uid . vendor ) > 0 )
vendor = devmap - > uid . vendor ;
else
vendor = " " ;
spin_unlock ( & dasd_devmap_lock ) ;
return snprintf ( buf , PAGE_SIZE , " %s \n " , vendor ) ;
}
static DEVICE_ATTR ( vendor , 0444 , dasd_vendor_show , NULL ) ;
# define UID_STRLEN ( /* vendor */ 3 + 1 + /* serial */ 14 + 1 +\
2008-08-01 18:39:09 +04:00
/* SSID */ 4 + 1 + /* unit addr */ 2 + 1 + \
/* vduit */ 32 + 1 )
2006-04-28 05:40:28 +04:00
static ssize_t
dasd_uid_show ( struct device * dev , struct device_attribute * attr , char * buf )
{
struct dasd_devmap * devmap ;
2008-01-26 16:11:23 +03:00
char uid_string [ UID_STRLEN ] ;
char ua_string [ 3 ] ;
struct dasd_uid * uid ;
2006-04-28 05:40:28 +04:00
2008-10-10 23:33:09 +04:00
devmap = dasd_find_busid ( dev_name ( dev ) ) ;
2006-04-28 05:40:28 +04:00
spin_lock ( & dasd_devmap_lock ) ;
2008-01-26 16:11:23 +03:00
if ( IS_ERR ( devmap ) | | strlen ( devmap - > uid . vendor ) = = 0 ) {
spin_unlock ( & dasd_devmap_lock ) ;
return sprintf ( buf , " \n " ) ;
}
uid = & devmap - > uid ;
switch ( uid - > type ) {
case UA_BASE_DEVICE :
sprintf ( ua_string , " %02x " , uid - > real_unit_addr ) ;
break ;
case UA_BASE_PAV_ALIAS :
sprintf ( ua_string , " %02x " , uid - > base_unit_addr ) ;
break ;
case UA_HYPER_PAV_ALIAS :
sprintf ( ua_string , " xx " ) ;
break ;
default :
/* should not happen, treat like base device */
sprintf ( ua_string , " %02x " , uid - > real_unit_addr ) ;
break ;
}
2008-08-01 18:39:09 +04:00
if ( strlen ( uid - > vduit ) > 0 )
snprintf ( uid_string , sizeof ( uid_string ) ,
" %s.%s.%04x.%s.%s " ,
uid - > vendor , uid - > serial ,
uid - > ssid , ua_string ,
uid - > vduit ) ;
else
snprintf ( uid_string , sizeof ( uid_string ) ,
" %s.%s.%04x.%s " ,
uid - > vendor , uid - > serial ,
uid - > ssid , ua_string ) ;
2006-04-28 05:40:28 +04:00
spin_unlock ( & dasd_devmap_lock ) ;
2008-01-26 16:11:23 +03:00
return snprintf ( buf , PAGE_SIZE , " %s \n " , uid_string ) ;
2006-04-28 05:40:28 +04:00
}
static DEVICE_ATTR ( uid , 0444 , dasd_uid_show , NULL ) ;
2006-03-24 14:15:25 +03:00
/*
* extended error - reporting
*/
static ssize_t
dasd_eer_show ( struct device * dev , struct device_attribute * attr , char * buf )
{
struct dasd_devmap * devmap ;
int eer_flag ;
2008-10-10 23:33:09 +04:00
devmap = dasd_find_busid ( dev_name ( dev ) ) ;
2006-03-24 14:15:25 +03:00
if ( ! IS_ERR ( devmap ) & & devmap - > device )
eer_flag = dasd_eer_enabled ( devmap - > device ) ;
else
eer_flag = 0 ;
return snprintf ( buf , PAGE_SIZE , eer_flag ? " 1 \n " : " 0 \n " ) ;
}
static ssize_t
dasd_eer_store ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
{
struct dasd_devmap * devmap ;
2006-12-04 17:39:50 +03:00
int val , rc ;
char * endp ;
2006-03-24 14:15:25 +03:00
devmap = dasd_devmap_from_cdev ( to_ccwdev ( dev ) ) ;
if ( IS_ERR ( devmap ) )
return PTR_ERR ( devmap ) ;
if ( ! devmap - > device )
2006-12-04 17:39:50 +03:00
return - ENODEV ;
val = simple_strtoul ( buf , & endp , 0 ) ;
if ( ( ( endp + 1 ) < ( buf + count ) ) | | ( val > 1 ) )
return - EINVAL ;
2006-12-04 17:40:18 +03:00
if ( val ) {
2006-03-24 14:15:25 +03:00
rc = dasd_eer_enable ( devmap - > device ) ;
2006-12-04 17:40:18 +03:00
if ( rc )
return rc ;
} else
2006-03-24 14:15:25 +03:00
dasd_eer_disable ( devmap - > device ) ;
2006-12-04 17:40:18 +03:00
return count ;
2006-03-24 14:15:25 +03:00
}
static DEVICE_ATTR ( eer_enabled , 0644 , dasd_eer_show , dasd_eer_store ) ;
2005-04-17 02:20:36 +04:00
static struct attribute * dasd_attrs [ ] = {
& dev_attr_readonly . attr ,
& dev_attr_discipline . attr ,
2007-04-27 18:01:47 +04:00
& dev_attr_status . attr ,
2006-04-28 05:40:28 +04:00
& dev_attr_alias . attr ,
& dev_attr_vendor . attr ,
& dev_attr_uid . attr ,
2005-04-17 02:20:36 +04:00
& dev_attr_use_diag . attr ,
2006-03-24 14:15:25 +03:00
& dev_attr_eer_enabled . attr ,
2006-12-08 17:54:15 +03:00
& dev_attr_erplog . attr ,
2009-01-09 14:14:51 +03:00
& dev_attr_failfast . attr ,
2005-04-17 02:20:36 +04:00
NULL ,
} ;
static struct attribute_group dasd_attr_group = {
. attrs = dasd_attrs ,
} ;
2006-04-28 05:40:28 +04:00
/*
* Return copy of the device unique identifier .
*/
int
dasd_get_uid ( struct ccw_device * cdev , struct dasd_uid * uid )
{
struct dasd_devmap * devmap ;
2008-10-10 23:33:09 +04:00
devmap = dasd_find_busid ( dev_name ( & cdev - > dev ) ) ;
2006-04-28 05:40:28 +04:00
if ( IS_ERR ( devmap ) )
return PTR_ERR ( devmap ) ;
spin_lock ( & dasd_devmap_lock ) ;
* uid = devmap - > uid ;
spin_unlock ( & dasd_devmap_lock ) ;
return 0 ;
}
2009-06-16 12:30:25 +04:00
EXPORT_SYMBOL_GPL ( dasd_get_uid ) ;
2006-04-28 05:40:28 +04:00
/*
* Register the given device unique identifier into devmap struct .
2006-08-16 15:49:33 +04:00
* In addition check if the related storage server subsystem ID is already
* contained in the dasd_server_ssid_list . If subsystem ID is not contained ,
* create new entry .
2006-06-29 17:08:18 +04:00
* Return 0 if server was already in serverlist ,
* 1 if the server was added successful
* < 0 in case of error .
2006-04-28 05:40:28 +04:00
*/
int
dasd_set_uid ( struct ccw_device * cdev , struct dasd_uid * uid )
{
struct dasd_devmap * devmap ;
2008-10-10 23:33:09 +04:00
devmap = dasd_find_busid ( dev_name ( & cdev - > dev ) ) ;
2006-04-28 05:40:28 +04:00
if ( IS_ERR ( devmap ) )
return PTR_ERR ( devmap ) ;
2006-08-10 17:45:16 +04:00
2006-04-28 05:40:28 +04:00
spin_lock ( & dasd_devmap_lock ) ;
devmap - > uid = * uid ;
spin_unlock ( & dasd_devmap_lock ) ;
2006-08-10 17:45:16 +04:00
2008-01-26 16:11:23 +03:00
return 0 ;
2006-04-28 05:40:28 +04:00
}
2006-06-29 17:08:18 +04:00
EXPORT_SYMBOL_GPL ( dasd_set_uid ) ;
2006-04-28 05:40:28 +04:00
2005-05-01 19:58:59 +04:00
/*
* Return value of the specified feature .
*/
int
dasd_get_feature ( struct ccw_device * cdev , int feature )
{
struct dasd_devmap * devmap ;
2008-10-10 23:33:09 +04:00
devmap = dasd_find_busid ( dev_name ( & cdev - > dev ) ) ;
2005-05-01 19:58:59 +04:00
if ( IS_ERR ( devmap ) )
2006-06-29 17:08:18 +04:00
return PTR_ERR ( devmap ) ;
2005-05-01 19:58:59 +04:00
return ( ( devmap - > features & feature ) ! = 0 ) ;
}
/*
* Set / reset given feature .
* Flag indicates wether to set ( ! = 0 ) or the reset ( = 0 ) the feature .
*/
int
dasd_set_feature ( struct ccw_device * cdev , int feature , int flag )
{
struct dasd_devmap * devmap ;
2008-10-10 23:33:09 +04:00
devmap = dasd_find_busid ( dev_name ( & cdev - > dev ) ) ;
2005-05-01 19:58:59 +04:00
if ( IS_ERR ( devmap ) )
2006-06-29 17:08:18 +04:00
return PTR_ERR ( devmap ) ;
2005-05-01 19:58:59 +04:00
spin_lock ( & dasd_devmap_lock ) ;
if ( flag )
devmap - > features | = feature ;
else
devmap - > features & = ~ feature ;
2005-09-04 02:57:58 +04:00
if ( devmap - > device )
devmap - > device - > features = devmap - > features ;
2005-05-01 19:58:59 +04:00
spin_unlock ( & dasd_devmap_lock ) ;
return 0 ;
}
2005-04-17 02:20:36 +04:00
int
dasd_add_sysfs_files ( struct ccw_device * cdev )
{
return sysfs_create_group ( & cdev - > dev . kobj , & dasd_attr_group ) ;
}
void
dasd_remove_sysfs_files ( struct ccw_device * cdev )
{
sysfs_remove_group ( & cdev - > dev . kobj , & dasd_attr_group ) ;
}
int
dasd_devmap_init ( void )
{
int i ;
/* Initialize devmap structures. */
dasd_max_devindex = 0 ;
for ( i = 0 ; i < 256 ; i + + )
INIT_LIST_HEAD ( & dasd_hashlists [ i ] ) ;
2006-06-29 17:08:18 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
void
dasd_devmap_exit ( void )
{
dasd_forget_ranges ( ) ;
}