2023-04-25 00:12:42 +03:00
// SPDX-License-Identifier: GPL-2.0
/*
* Sysfs interface for the NVMe core driver .
*
* Copyright ( c ) 2011 - 2014 , Intel Corporation .
*/
# include <linux/nvme-auth.h>
# include "nvme.h"
# include "fabrics.h"
static ssize_t nvme_sysfs_reset ( struct device * dev ,
struct device_attribute * attr , const char * buf ,
size_t count )
{
struct nvme_ctrl * ctrl = dev_get_drvdata ( dev ) ;
int ret ;
ret = nvme_reset_ctrl_sync ( ctrl ) ;
if ( ret < 0 )
return ret ;
return count ;
}
static DEVICE_ATTR ( reset_controller , S_IWUSR , NULL , nvme_sysfs_reset ) ;
static ssize_t nvme_sysfs_rescan ( struct device * dev ,
struct device_attribute * attr , const char * buf ,
size_t count )
{
struct nvme_ctrl * ctrl = dev_get_drvdata ( dev ) ;
nvme_queue_scan ( ctrl ) ;
return count ;
}
static DEVICE_ATTR ( rescan_controller , S_IWUSR , NULL , nvme_sysfs_rescan ) ;
static inline struct nvme_ns_head * dev_to_ns_head ( struct device * dev )
{
struct gendisk * disk = dev_to_disk ( dev ) ;
if ( disk - > fops = = & nvme_bdev_ops )
return nvme_get_ns_from_dev ( dev ) - > head ;
else
return disk - > private_data ;
}
static ssize_t wwid_show ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
struct nvme_ns_head * head = dev_to_ns_head ( dev ) ;
struct nvme_ns_ids * ids = & head - > ids ;
struct nvme_subsystem * subsys = head - > subsys ;
int serial_len = sizeof ( subsys - > serial ) ;
int model_len = sizeof ( subsys - > model ) ;
if ( ! uuid_is_null ( & ids - > uuid ) )
return sysfs_emit ( buf , " uuid.%pU \n " , & ids - > uuid ) ;
if ( memchr_inv ( ids - > nguid , 0 , sizeof ( ids - > nguid ) ) )
return sysfs_emit ( buf , " eui.%16phN \n " , ids - > nguid ) ;
if ( memchr_inv ( ids - > eui64 , 0 , sizeof ( ids - > eui64 ) ) )
return sysfs_emit ( buf , " eui.%8phN \n " , ids - > eui64 ) ;
while ( serial_len > 0 & & ( subsys - > serial [ serial_len - 1 ] = = ' ' | |
subsys - > serial [ serial_len - 1 ] = = ' \0 ' ) )
serial_len - - ;
while ( model_len > 0 & & ( subsys - > model [ model_len - 1 ] = = ' ' | |
subsys - > model [ model_len - 1 ] = = ' \0 ' ) )
model_len - - ;
return sysfs_emit ( buf , " nvme.%04x-%*phN-%*phN-%08x \n " , subsys - > vendor_id ,
serial_len , subsys - > serial , model_len , subsys - > model ,
head - > ns_id ) ;
}
static DEVICE_ATTR_RO ( wwid ) ;
static ssize_t nguid_show ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
return sysfs_emit ( buf , " %pU \n " , dev_to_ns_head ( dev ) - > ids . nguid ) ;
}
static DEVICE_ATTR_RO ( nguid ) ;
static ssize_t uuid_show ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
struct nvme_ns_ids * ids = & dev_to_ns_head ( dev ) - > ids ;
/* For backward compatibility expose the NGUID to userspace if
* we have no UUID set
*/
if ( uuid_is_null ( & ids - > uuid ) ) {
2023-07-12 07:54:59 -07:00
dev_warn_once ( dev ,
2023-04-25 00:12:42 +03:00
" No UUID available providing old NGUID \n " ) ;
return sysfs_emit ( buf , " %pU \n " , ids - > nguid ) ;
}
return sysfs_emit ( buf , " %pU \n " , & ids - > uuid ) ;
}
static DEVICE_ATTR_RO ( uuid ) ;
static ssize_t eui_show ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
return sysfs_emit ( buf , " %8ph \n " , dev_to_ns_head ( dev ) - > ids . eui64 ) ;
}
static DEVICE_ATTR_RO ( eui ) ;
static ssize_t nsid_show ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
return sysfs_emit ( buf , " %d \n " , dev_to_ns_head ( dev ) - > ns_id ) ;
}
static DEVICE_ATTR_RO ( nsid ) ;
static struct attribute * nvme_ns_id_attrs [ ] = {
& dev_attr_wwid . attr ,
& dev_attr_uuid . attr ,
& dev_attr_nguid . attr ,
& dev_attr_eui . attr ,
& dev_attr_nsid . attr ,
# ifdef CONFIG_NVME_MULTIPATH
& dev_attr_ana_grpid . attr ,
& dev_attr_ana_state . attr ,
# endif
NULL ,
} ;
static umode_t nvme_ns_id_attrs_are_visible ( struct kobject * kobj ,
struct attribute * a , int n )
{
struct device * dev = container_of ( kobj , struct device , kobj ) ;
struct nvme_ns_ids * ids = & dev_to_ns_head ( dev ) - > ids ;
if ( a = = & dev_attr_uuid . attr ) {
if ( uuid_is_null ( & ids - > uuid ) & &
! memchr_inv ( ids - > nguid , 0 , sizeof ( ids - > nguid ) ) )
return 0 ;
}
if ( a = = & dev_attr_nguid . attr ) {
if ( ! memchr_inv ( ids - > nguid , 0 , sizeof ( ids - > nguid ) ) )
return 0 ;
}
if ( a = = & dev_attr_eui . attr ) {
if ( ! memchr_inv ( ids - > eui64 , 0 , sizeof ( ids - > eui64 ) ) )
return 0 ;
}
# ifdef CONFIG_NVME_MULTIPATH
if ( a = = & dev_attr_ana_grpid . attr | | a = = & dev_attr_ana_state . attr ) {
if ( dev_to_disk ( dev ) - > fops ! = & nvme_bdev_ops ) /* per-path attr */
return 0 ;
if ( ! nvme_ctrl_use_ana ( nvme_get_ns_from_dev ( dev ) - > ctrl ) )
return 0 ;
}
# endif
return a - > mode ;
}
static const struct attribute_group nvme_ns_id_attr_group = {
. attrs = nvme_ns_id_attrs ,
. is_visible = nvme_ns_id_attrs_are_visible ,
} ;
const struct attribute_group * nvme_ns_id_attr_groups [ ] = {
& nvme_ns_id_attr_group ,
NULL ,
} ;
# define nvme_show_str_function(field) \
static ssize_t field # # _show ( struct device * dev , \
struct device_attribute * attr , char * buf ) \
{ \
struct nvme_ctrl * ctrl = dev_get_drvdata ( dev ) ; \
return sysfs_emit ( buf , " %.*s \n " , \
( int ) sizeof ( ctrl - > subsys - > field ) , ctrl - > subsys - > field ) ; \
} \
static DEVICE_ATTR ( field , S_IRUGO , field # # _show , NULL ) ;
nvme_show_str_function ( model ) ;
nvme_show_str_function ( serial ) ;
nvme_show_str_function ( firmware_rev ) ;
# define nvme_show_int_function(field) \
static ssize_t field # # _show ( struct device * dev , \
struct device_attribute * attr , char * buf ) \
{ \
struct nvme_ctrl * ctrl = dev_get_drvdata ( dev ) ; \
return sysfs_emit ( buf , " %d \n " , ctrl - > field ) ; \
} \
static DEVICE_ATTR ( field , S_IRUGO , field # # _show , NULL ) ;
nvme_show_int_function ( cntlid ) ;
nvme_show_int_function ( numa_node ) ;
nvme_show_int_function ( queue_count ) ;
nvme_show_int_function ( sqsize ) ;
nvme_show_int_function ( kato ) ;
static ssize_t nvme_sysfs_delete ( struct device * dev ,
struct device_attribute * attr , const char * buf ,
size_t count )
{
struct nvme_ctrl * ctrl = dev_get_drvdata ( dev ) ;
2023-06-15 08:17:57 -07:00
if ( ! test_bit ( NVME_CTRL_STARTED_ONCE , & ctrl - > flags ) )
return - EBUSY ;
2023-04-25 00:12:42 +03:00
if ( device_remove_file_self ( dev , attr ) )
nvme_delete_ctrl_sync ( ctrl ) ;
return count ;
}
static DEVICE_ATTR ( delete_controller , S_IWUSR , NULL , nvme_sysfs_delete ) ;
static ssize_t nvme_sysfs_show_transport ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
struct nvme_ctrl * ctrl = dev_get_drvdata ( dev ) ;
return sysfs_emit ( buf , " %s \n " , ctrl - > ops - > name ) ;
}
static DEVICE_ATTR ( transport , S_IRUGO , nvme_sysfs_show_transport , NULL ) ;
static ssize_t nvme_sysfs_show_state ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
struct nvme_ctrl * ctrl = dev_get_drvdata ( dev ) ;
static const char * const state_name [ ] = {
[ NVME_CTRL_NEW ] = " new " ,
[ NVME_CTRL_LIVE ] = " live " ,
[ NVME_CTRL_RESETTING ] = " resetting " ,
[ NVME_CTRL_CONNECTING ] = " connecting " ,
[ NVME_CTRL_DELETING ] = " deleting " ,
[ NVME_CTRL_DELETING_NOIO ] = " deleting (no IO) " ,
[ NVME_CTRL_DEAD ] = " dead " ,
} ;
if ( ( unsigned ) ctrl - > state < ARRAY_SIZE ( state_name ) & &
state_name [ ctrl - > state ] )
return sysfs_emit ( buf , " %s \n " , state_name [ ctrl - > state ] ) ;
return sysfs_emit ( buf , " unknown state \n " ) ;
}
static DEVICE_ATTR ( state , S_IRUGO , nvme_sysfs_show_state , NULL ) ;
static ssize_t nvme_sysfs_show_subsysnqn ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
struct nvme_ctrl * ctrl = dev_get_drvdata ( dev ) ;
return sysfs_emit ( buf , " %s \n " , ctrl - > subsys - > subnqn ) ;
}
static DEVICE_ATTR ( subsysnqn , S_IRUGO , nvme_sysfs_show_subsysnqn , NULL ) ;
static ssize_t nvme_sysfs_show_hostnqn ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
struct nvme_ctrl * ctrl = dev_get_drvdata ( dev ) ;
return sysfs_emit ( buf , " %s \n " , ctrl - > opts - > host - > nqn ) ;
}
static DEVICE_ATTR ( hostnqn , S_IRUGO , nvme_sysfs_show_hostnqn , NULL ) ;
static ssize_t nvme_sysfs_show_hostid ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
struct nvme_ctrl * ctrl = dev_get_drvdata ( dev ) ;
return sysfs_emit ( buf , " %pU \n " , & ctrl - > opts - > host - > id ) ;
}
static DEVICE_ATTR ( hostid , S_IRUGO , nvme_sysfs_show_hostid , NULL ) ;
static ssize_t nvme_sysfs_show_address ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
struct nvme_ctrl * ctrl = dev_get_drvdata ( dev ) ;
return ctrl - > ops - > get_address ( ctrl , buf , PAGE_SIZE ) ;
}
static DEVICE_ATTR ( address , S_IRUGO , nvme_sysfs_show_address , NULL ) ;
static ssize_t nvme_ctrl_loss_tmo_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct nvme_ctrl * ctrl = dev_get_drvdata ( dev ) ;
struct nvmf_ctrl_options * opts = ctrl - > opts ;
if ( ctrl - > opts - > max_reconnects = = - 1 )
return sysfs_emit ( buf , " off \n " ) ;
return sysfs_emit ( buf , " %d \n " ,
opts - > max_reconnects * opts - > reconnect_delay ) ;
}
static ssize_t nvme_ctrl_loss_tmo_store ( struct device * dev ,
struct device_attribute * attr , const char * buf , size_t count )
{
struct nvme_ctrl * ctrl = dev_get_drvdata ( dev ) ;
struct nvmf_ctrl_options * opts = ctrl - > opts ;
int ctrl_loss_tmo , err ;
err = kstrtoint ( buf , 10 , & ctrl_loss_tmo ) ;
if ( err )
return - EINVAL ;
if ( ctrl_loss_tmo < 0 )
opts - > max_reconnects = - 1 ;
else
opts - > max_reconnects = DIV_ROUND_UP ( ctrl_loss_tmo ,
opts - > reconnect_delay ) ;
return count ;
}
static DEVICE_ATTR ( ctrl_loss_tmo , S_IRUGO | S_IWUSR ,
nvme_ctrl_loss_tmo_show , nvme_ctrl_loss_tmo_store ) ;
static ssize_t nvme_ctrl_reconnect_delay_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct nvme_ctrl * ctrl = dev_get_drvdata ( dev ) ;
if ( ctrl - > opts - > reconnect_delay = = - 1 )
return sysfs_emit ( buf , " off \n " ) ;
return sysfs_emit ( buf , " %d \n " , ctrl - > opts - > reconnect_delay ) ;
}
static ssize_t nvme_ctrl_reconnect_delay_store ( struct device * dev ,
struct device_attribute * attr , const char * buf , size_t count )
{
struct nvme_ctrl * ctrl = dev_get_drvdata ( dev ) ;
unsigned int v ;
int err ;
err = kstrtou32 ( buf , 10 , & v ) ;
if ( err )
return err ;
ctrl - > opts - > reconnect_delay = v ;
return count ;
}
static DEVICE_ATTR ( reconnect_delay , S_IRUGO | S_IWUSR ,
nvme_ctrl_reconnect_delay_show , nvme_ctrl_reconnect_delay_store ) ;
static ssize_t nvme_ctrl_fast_io_fail_tmo_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct nvme_ctrl * ctrl = dev_get_drvdata ( dev ) ;
if ( ctrl - > opts - > fast_io_fail_tmo = = - 1 )
return sysfs_emit ( buf , " off \n " ) ;
return sysfs_emit ( buf , " %d \n " , ctrl - > opts - > fast_io_fail_tmo ) ;
}
static ssize_t nvme_ctrl_fast_io_fail_tmo_store ( struct device * dev ,
struct device_attribute * attr , const char * buf , size_t count )
{
struct nvme_ctrl * ctrl = dev_get_drvdata ( dev ) ;
struct nvmf_ctrl_options * opts = ctrl - > opts ;
int fast_io_fail_tmo , err ;
err = kstrtoint ( buf , 10 , & fast_io_fail_tmo ) ;
if ( err )
return - EINVAL ;
if ( fast_io_fail_tmo < 0 )
opts - > fast_io_fail_tmo = - 1 ;
else
opts - > fast_io_fail_tmo = fast_io_fail_tmo ;
return count ;
}
static DEVICE_ATTR ( fast_io_fail_tmo , S_IRUGO | S_IWUSR ,
nvme_ctrl_fast_io_fail_tmo_show , nvme_ctrl_fast_io_fail_tmo_store ) ;
static ssize_t cntrltype_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
static const char * const type [ ] = {
[ NVME_CTRL_IO ] = " io \n " ,
[ NVME_CTRL_DISC ] = " discovery \n " ,
[ NVME_CTRL_ADMIN ] = " admin \n " ,
} ;
struct nvme_ctrl * ctrl = dev_get_drvdata ( dev ) ;
if ( ctrl - > cntrltype > NVME_CTRL_ADMIN | | ! type [ ctrl - > cntrltype ] )
return sysfs_emit ( buf , " reserved \n " ) ;
return sysfs_emit ( buf , type [ ctrl - > cntrltype ] ) ;
}
static DEVICE_ATTR_RO ( cntrltype ) ;
static ssize_t dctype_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
static const char * const type [ ] = {
[ NVME_DCTYPE_NOT_REPORTED ] = " none \n " ,
[ NVME_DCTYPE_DDC ] = " ddc \n " ,
[ NVME_DCTYPE_CDC ] = " cdc \n " ,
} ;
struct nvme_ctrl * ctrl = dev_get_drvdata ( dev ) ;
if ( ctrl - > dctype > NVME_DCTYPE_CDC | | ! type [ ctrl - > dctype ] )
return sysfs_emit ( buf , " reserved \n " ) ;
return sysfs_emit ( buf , type [ ctrl - > dctype ] ) ;
}
static DEVICE_ATTR_RO ( dctype ) ;
# ifdef CONFIG_NVME_AUTH
static ssize_t nvme_ctrl_dhchap_secret_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct nvme_ctrl * ctrl = dev_get_drvdata ( dev ) ;
struct nvmf_ctrl_options * opts = ctrl - > opts ;
if ( ! opts - > dhchap_secret )
return sysfs_emit ( buf , " none \n " ) ;
return sysfs_emit ( buf , " %s \n " , opts - > dhchap_secret ) ;
}
static ssize_t nvme_ctrl_dhchap_secret_store ( struct device * dev ,
struct device_attribute * attr , const char * buf , size_t count )
{
struct nvme_ctrl * ctrl = dev_get_drvdata ( dev ) ;
struct nvmf_ctrl_options * opts = ctrl - > opts ;
char * dhchap_secret ;
if ( ! ctrl - > opts - > dhchap_secret )
return - EINVAL ;
if ( count < 7 )
return - EINVAL ;
if ( memcmp ( buf , " DHHC-1: " , 7 ) )
return - EINVAL ;
dhchap_secret = kzalloc ( count + 1 , GFP_KERNEL ) ;
if ( ! dhchap_secret )
return - ENOMEM ;
memcpy ( dhchap_secret , buf , count ) ;
nvme_auth_stop ( ctrl ) ;
if ( strcmp ( dhchap_secret , opts - > dhchap_secret ) ) {
struct nvme_dhchap_key * key , * host_key ;
int ret ;
ret = nvme_auth_generate_key ( dhchap_secret , & key ) ;
if ( ret ) {
kfree ( dhchap_secret ) ;
return ret ;
}
kfree ( opts - > dhchap_secret ) ;
opts - > dhchap_secret = dhchap_secret ;
host_key = ctrl - > host_key ;
mutex_lock ( & ctrl - > dhchap_auth_mutex ) ;
ctrl - > host_key = key ;
mutex_unlock ( & ctrl - > dhchap_auth_mutex ) ;
nvme_auth_free_key ( host_key ) ;
} else
kfree ( dhchap_secret ) ;
/* Start re-authentication */
dev_info ( ctrl - > device , " re-authenticating controller \n " ) ;
queue_work ( nvme_wq , & ctrl - > dhchap_auth_work ) ;
return count ;
}
static DEVICE_ATTR ( dhchap_secret , S_IRUGO | S_IWUSR ,
nvme_ctrl_dhchap_secret_show , nvme_ctrl_dhchap_secret_store ) ;
static ssize_t nvme_ctrl_dhchap_ctrl_secret_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct nvme_ctrl * ctrl = dev_get_drvdata ( dev ) ;
struct nvmf_ctrl_options * opts = ctrl - > opts ;
if ( ! opts - > dhchap_ctrl_secret )
return sysfs_emit ( buf , " none \n " ) ;
return sysfs_emit ( buf , " %s \n " , opts - > dhchap_ctrl_secret ) ;
}
static ssize_t nvme_ctrl_dhchap_ctrl_secret_store ( struct device * dev ,
struct device_attribute * attr , const char * buf , size_t count )
{
struct nvme_ctrl * ctrl = dev_get_drvdata ( dev ) ;
struct nvmf_ctrl_options * opts = ctrl - > opts ;
char * dhchap_secret ;
if ( ! ctrl - > opts - > dhchap_ctrl_secret )
return - EINVAL ;
if ( count < 7 )
return - EINVAL ;
if ( memcmp ( buf , " DHHC-1: " , 7 ) )
return - EINVAL ;
dhchap_secret = kzalloc ( count + 1 , GFP_KERNEL ) ;
if ( ! dhchap_secret )
return - ENOMEM ;
memcpy ( dhchap_secret , buf , count ) ;
nvme_auth_stop ( ctrl ) ;
if ( strcmp ( dhchap_secret , opts - > dhchap_ctrl_secret ) ) {
struct nvme_dhchap_key * key , * ctrl_key ;
int ret ;
ret = nvme_auth_generate_key ( dhchap_secret , & key ) ;
if ( ret ) {
kfree ( dhchap_secret ) ;
return ret ;
}
kfree ( opts - > dhchap_ctrl_secret ) ;
opts - > dhchap_ctrl_secret = dhchap_secret ;
ctrl_key = ctrl - > ctrl_key ;
mutex_lock ( & ctrl - > dhchap_auth_mutex ) ;
ctrl - > ctrl_key = key ;
mutex_unlock ( & ctrl - > dhchap_auth_mutex ) ;
nvme_auth_free_key ( ctrl_key ) ;
} else
kfree ( dhchap_secret ) ;
/* Start re-authentication */
dev_info ( ctrl - > device , " re-authenticating controller \n " ) ;
queue_work ( nvme_wq , & ctrl - > dhchap_auth_work ) ;
return count ;
}
static DEVICE_ATTR ( dhchap_ctrl_secret , S_IRUGO | S_IWUSR ,
nvme_ctrl_dhchap_ctrl_secret_show , nvme_ctrl_dhchap_ctrl_secret_store ) ;
# endif
static struct attribute * nvme_dev_attrs [ ] = {
& dev_attr_reset_controller . attr ,
& dev_attr_rescan_controller . attr ,
& dev_attr_model . attr ,
& dev_attr_serial . attr ,
& dev_attr_firmware_rev . attr ,
& dev_attr_cntlid . attr ,
& dev_attr_delete_controller . attr ,
& dev_attr_transport . attr ,
& dev_attr_subsysnqn . attr ,
& dev_attr_address . attr ,
& dev_attr_state . attr ,
& dev_attr_numa_node . attr ,
& dev_attr_queue_count . attr ,
& dev_attr_sqsize . attr ,
& dev_attr_hostnqn . attr ,
& dev_attr_hostid . attr ,
& dev_attr_ctrl_loss_tmo . attr ,
& dev_attr_reconnect_delay . attr ,
& dev_attr_fast_io_fail_tmo . attr ,
& dev_attr_kato . attr ,
& dev_attr_cntrltype . attr ,
& dev_attr_dctype . attr ,
# ifdef CONFIG_NVME_AUTH
& dev_attr_dhchap_secret . attr ,
& dev_attr_dhchap_ctrl_secret . attr ,
# endif
NULL
} ;
static umode_t nvme_dev_attrs_are_visible ( struct kobject * kobj ,
struct attribute * a , int n )
{
struct device * dev = container_of ( kobj , struct device , kobj ) ;
struct nvme_ctrl * ctrl = dev_get_drvdata ( dev ) ;
if ( a = = & dev_attr_delete_controller . attr & & ! ctrl - > ops - > delete_ctrl )
return 0 ;
if ( a = = & dev_attr_address . attr & & ! ctrl - > ops - > get_address )
return 0 ;
if ( a = = & dev_attr_hostnqn . attr & & ! ctrl - > opts )
return 0 ;
if ( a = = & dev_attr_hostid . attr & & ! ctrl - > opts )
return 0 ;
if ( a = = & dev_attr_ctrl_loss_tmo . attr & & ! ctrl - > opts )
return 0 ;
if ( a = = & dev_attr_reconnect_delay . attr & & ! ctrl - > opts )
return 0 ;
if ( a = = & dev_attr_fast_io_fail_tmo . attr & & ! ctrl - > opts )
return 0 ;
# ifdef CONFIG_NVME_AUTH
if ( a = = & dev_attr_dhchap_secret . attr & & ! ctrl - > opts )
return 0 ;
if ( a = = & dev_attr_dhchap_ctrl_secret . attr & & ! ctrl - > opts )
return 0 ;
# endif
return a - > mode ;
}
const struct attribute_group nvme_dev_attrs_group = {
. attrs = nvme_dev_attrs ,
. is_visible = nvme_dev_attrs_are_visible ,
} ;
EXPORT_SYMBOL_GPL ( nvme_dev_attrs_group ) ;
const struct attribute_group * nvme_dev_attr_groups [ ] = {
& nvme_dev_attrs_group ,
NULL ,
} ;
# define SUBSYS_ATTR_RO(_name, _mode, _show) \
struct device_attribute subsys_attr_ # # _name = \
__ATTR ( _name , _mode , _show , NULL )
static ssize_t nvme_subsys_show_nqn ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
struct nvme_subsystem * subsys =
container_of ( dev , struct nvme_subsystem , dev ) ;
return sysfs_emit ( buf , " %s \n " , subsys - > subnqn ) ;
}
static SUBSYS_ATTR_RO ( subsysnqn , S_IRUGO , nvme_subsys_show_nqn ) ;
static ssize_t nvme_subsys_show_type ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
struct nvme_subsystem * subsys =
container_of ( dev , struct nvme_subsystem , dev ) ;
switch ( subsys - > subtype ) {
case NVME_NQN_DISC :
return sysfs_emit ( buf , " discovery \n " ) ;
case NVME_NQN_NVME :
return sysfs_emit ( buf , " nvm \n " ) ;
default :
return sysfs_emit ( buf , " reserved \n " ) ;
}
}
static SUBSYS_ATTR_RO ( subsystype , S_IRUGO , nvme_subsys_show_type ) ;
# define nvme_subsys_show_str_function(field) \
static ssize_t subsys_ # # field # # _show ( struct device * dev , \
struct device_attribute * attr , char * buf ) \
{ \
struct nvme_subsystem * subsys = \
container_of ( dev , struct nvme_subsystem , dev ) ; \
return sysfs_emit ( buf , " %.*s \n " , \
( int ) sizeof ( subsys - > field ) , subsys - > field ) ; \
} \
static SUBSYS_ATTR_RO ( field , S_IRUGO , subsys_ # # field # # _show ) ;
nvme_subsys_show_str_function ( model ) ;
nvme_subsys_show_str_function ( serial ) ;
nvme_subsys_show_str_function ( firmware_rev ) ;
static struct attribute * nvme_subsys_attrs [ ] = {
& subsys_attr_model . attr ,
& subsys_attr_serial . attr ,
& subsys_attr_firmware_rev . attr ,
& subsys_attr_subsysnqn . attr ,
& subsys_attr_subsystype . attr ,
# ifdef CONFIG_NVME_MULTIPATH
& subsys_attr_iopolicy . attr ,
# endif
NULL ,
} ;
static const struct attribute_group nvme_subsys_attrs_group = {
. attrs = nvme_subsys_attrs ,
} ;
const struct attribute_group * nvme_subsys_attrs_groups [ ] = {
& nvme_subsys_attrs_group ,
NULL ,
} ;