2014-01-14 15:54:11 +01:00
/*
* Copyright IBM Corp . 2013
* Author ( s ) : Eugene Crosser < eugene . crosser @ ru . ibm . com >
*/
# include <linux/slab.h>
# include <asm/ebcdic.h>
2014-09-02 08:20:17 +02:00
# include "qeth_core.h"
2014-01-14 15:54:11 +01:00
# include "qeth_l2.h"
static ssize_t qeth_bridge_port_role_state_show ( struct device * dev ,
struct device_attribute * attr , char * buf ,
int show_state )
{
struct qeth_card * card = dev_get_drvdata ( dev ) ;
enum qeth_sbp_states state = QETH_SBP_STATE_INACTIVE ;
int rc = 0 ;
char * word ;
if ( ! card )
return - EINVAL ;
2017-09-18 21:18:15 +02:00
if ( qeth_l2_vnicc_is_in_use ( card ) )
return sprintf ( buf , " n/a (VNIC characteristics) \ n " ) ;
2014-01-14 15:54:11 +01:00
if ( qeth_card_hw_is_reachable ( card ) & &
card - > options . sbp . supported_funcs )
rc = qeth_bridgeport_query_ports ( card ,
& card - > options . sbp . role , & state ) ;
if ( ! rc ) {
if ( show_state )
switch ( state ) {
case QETH_SBP_STATE_INACTIVE :
word = " inactive " ; break ;
case QETH_SBP_STATE_STANDBY :
word = " standby " ; break ;
case QETH_SBP_STATE_ACTIVE :
word = " active " ; break ;
default :
rc = - EIO ;
}
else
switch ( card - > options . sbp . role ) {
case QETH_SBP_ROLE_NONE :
word = " none " ; break ;
case QETH_SBP_ROLE_PRIMARY :
word = " primary " ; break ;
case QETH_SBP_ROLE_SECONDARY :
word = " secondary " ; break ;
default :
rc = - EIO ;
}
if ( rc )
QETH_CARD_TEXT_ ( card , 2 , " SBP%02x:%02x " ,
card - > options . sbp . role , state ) ;
else
rc = sprintf ( buf , " %s \n " , word ) ;
}
return rc ;
}
static ssize_t qeth_bridge_port_role_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
2017-09-18 21:18:15 +02:00
struct qeth_card * card = dev_get_drvdata ( dev ) ;
if ( qeth_l2_vnicc_is_in_use ( card ) )
return sprintf ( buf , " n/a (VNIC characteristics) \ n " ) ;
2014-01-14 15:54:11 +01:00
return qeth_bridge_port_role_state_show ( dev , attr , buf , 0 ) ;
}
static ssize_t qeth_bridge_port_role_store ( struct device * dev ,
struct device_attribute * attr , const char * buf , size_t count )
{
struct qeth_card * card = dev_get_drvdata ( dev ) ;
int rc = 0 ;
enum qeth_sbp_roles role ;
if ( ! card )
return - EINVAL ;
if ( sysfs_streq ( buf , " primary " ) )
role = QETH_SBP_ROLE_PRIMARY ;
else if ( sysfs_streq ( buf , " secondary " ) )
role = QETH_SBP_ROLE_SECONDARY ;
else if ( sysfs_streq ( buf , " none " ) )
role = QETH_SBP_ROLE_NONE ;
else
return - EINVAL ;
mutex_lock ( & card - > conf_mutex ) ;
2017-09-18 21:18:15 +02:00
if ( qeth_l2_vnicc_is_in_use ( card ) )
rc = - EBUSY ;
else if ( card - > options . sbp . reflect_promisc )
/* Forbid direct manipulation */
2015-05-18 14:27:57 +02:00
rc = - EPERM ;
else if ( qeth_card_hw_is_reachable ( card ) ) {
2014-01-14 15:54:11 +01:00
rc = qeth_bridgeport_setrole ( card , role ) ;
if ( ! rc )
card - > options . sbp . role = role ;
} else
card - > options . sbp . role = role ;
mutex_unlock ( & card - > conf_mutex ) ;
return rc ? rc : count ;
}
static DEVICE_ATTR ( bridge_role , 0644 , qeth_bridge_port_role_show ,
qeth_bridge_port_role_store ) ;
static ssize_t qeth_bridge_port_state_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
2017-09-18 21:18:15 +02:00
struct qeth_card * card = dev_get_drvdata ( dev ) ;
if ( qeth_l2_vnicc_is_in_use ( card ) )
return sprintf ( buf , " n/a (VNIC characteristics) \ n " ) ;
2014-01-14 15:54:11 +01:00
return qeth_bridge_port_role_state_show ( dev , attr , buf , 1 ) ;
}
2015-09-18 16:06:49 +02:00
static DEVICE_ATTR ( bridge_state , 0444 , qeth_bridge_port_state_show ,
2014-01-14 15:54:11 +01:00
NULL ) ;
2014-01-14 15:54:13 +01:00
static ssize_t qeth_bridgeport_hostnotification_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct qeth_card * card = dev_get_drvdata ( dev ) ;
int enabled ;
if ( ! card )
return - EINVAL ;
2017-09-18 21:18:15 +02:00
if ( qeth_l2_vnicc_is_in_use ( card ) )
return sprintf ( buf , " n/a (VNIC characteristics) \ n " ) ;
2014-01-14 15:54:13 +01:00
enabled = card - > options . sbp . hostnotification ;
return sprintf ( buf , " %d \n " , enabled ) ;
}
static ssize_t qeth_bridgeport_hostnotification_store ( struct device * dev ,
struct device_attribute * attr , const char * buf , size_t count )
{
struct qeth_card * card = dev_get_drvdata ( dev ) ;
int rc = 0 ;
int enable ;
if ( ! card )
return - EINVAL ;
if ( sysfs_streq ( buf , " 0 " ) )
enable = 0 ;
else if ( sysfs_streq ( buf , " 1 " ) )
enable = 1 ;
else
return - EINVAL ;
mutex_lock ( & card - > conf_mutex ) ;
2017-09-18 21:18:15 +02:00
if ( qeth_l2_vnicc_is_in_use ( card ) )
rc = - EBUSY ;
else if ( qeth_card_hw_is_reachable ( card ) ) {
2014-01-14 15:54:13 +01:00
rc = qeth_bridgeport_an_set ( card , enable ) ;
if ( ! rc )
card - > options . sbp . hostnotification = enable ;
} else
card - > options . sbp . hostnotification = enable ;
mutex_unlock ( & card - > conf_mutex ) ;
return rc ? rc : count ;
}
static DEVICE_ATTR ( bridge_hostnotify , 0644 ,
qeth_bridgeport_hostnotification_show ,
qeth_bridgeport_hostnotification_store ) ;
2015-05-18 14:27:55 +02:00
static ssize_t qeth_bridgeport_reflect_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct qeth_card * card = dev_get_drvdata ( dev ) ;
char * state ;
if ( ! card )
return - EINVAL ;
2017-09-18 21:18:15 +02:00
if ( qeth_l2_vnicc_is_in_use ( card ) )
return sprintf ( buf , " n/a (VNIC characteristics) \ n " ) ;
2015-05-18 14:27:55 +02:00
if ( card - > options . sbp . reflect_promisc ) {
if ( card - > options . sbp . reflect_promisc_primary )
state = " primary " ;
else
state = " secondary " ;
} else
state = " none " ;
return sprintf ( buf , " %s \n " , state ) ;
}
static ssize_t qeth_bridgeport_reflect_store ( struct device * dev ,
struct device_attribute * attr , const char * buf , size_t count )
{
struct qeth_card * card = dev_get_drvdata ( dev ) ;
int enable , primary ;
2015-05-18 14:27:57 +02:00
int rc = 0 ;
2015-05-18 14:27:55 +02:00
if ( ! card )
return - EINVAL ;
if ( sysfs_streq ( buf , " none " ) ) {
enable = 0 ;
primary = 0 ;
} else if ( sysfs_streq ( buf , " primary " ) ) {
enable = 1 ;
primary = 1 ;
} else if ( sysfs_streq ( buf , " secondary " ) ) {
enable = 1 ;
primary = 0 ;
} else
return - EINVAL ;
mutex_lock ( & card - > conf_mutex ) ;
2017-09-18 21:18:15 +02:00
if ( qeth_l2_vnicc_is_in_use ( card ) )
rc = - EBUSY ;
else if ( card - > options . sbp . role ! = QETH_SBP_ROLE_NONE )
2015-05-18 14:27:57 +02:00
rc = - EPERM ;
else {
card - > options . sbp . reflect_promisc = enable ;
card - > options . sbp . reflect_promisc_primary = primary ;
rc = 0 ;
}
2015-05-18 14:27:55 +02:00
mutex_unlock ( & card - > conf_mutex ) ;
2015-05-18 14:27:57 +02:00
return rc ? rc : count ;
2015-05-18 14:27:55 +02:00
}
static DEVICE_ATTR ( bridge_reflect_promisc , 0644 ,
qeth_bridgeport_reflect_show ,
qeth_bridgeport_reflect_store ) ;
2014-01-14 15:54:11 +01:00
static struct attribute * qeth_l2_bridgeport_attrs [ ] = {
& dev_attr_bridge_role . attr ,
& dev_attr_bridge_state . attr ,
2014-01-14 15:54:13 +01:00
& dev_attr_bridge_hostnotify . attr ,
2015-05-18 14:27:55 +02:00
& dev_attr_bridge_reflect_promisc . attr ,
2014-01-14 15:54:11 +01:00
NULL ,
} ;
static struct attribute_group qeth_l2_bridgeport_attr_group = {
. attrs = qeth_l2_bridgeport_attrs ,
} ;
/**
* qeth_l2_setup_bridgeport_attrs ( ) - set / restore attrs when turning online .
* @ card : qeth_card structure pointer
*
* Note : this function is called with conf_mutex held by the caller
*/
void qeth_l2_setup_bridgeport_attrs ( struct qeth_card * card )
{
2014-01-14 15:54:13 +01:00
int rc ;
2014-01-14 15:54:11 +01:00
if ( ! card )
return ;
if ( ! card - > options . sbp . supported_funcs )
return ;
if ( card - > options . sbp . role ! = QETH_SBP_ROLE_NONE ) {
/* Conditional to avoid spurious error messages */
qeth_bridgeport_setrole ( card , card - > options . sbp . role ) ;
/* Let the callback function refresh the stored role value. */
qeth_bridgeport_query_ports ( card ,
& card - > options . sbp . role , NULL ) ;
}
2014-01-14 15:54:13 +01:00
if ( card - > options . sbp . hostnotification ) {
rc = qeth_bridgeport_an_set ( card , 1 ) ;
if ( rc )
card - > options . sbp . hostnotification = 0 ;
} else
qeth_bridgeport_an_set ( card , 0 ) ;
2014-01-14 15:54:11 +01:00
}
2017-05-10 19:07:52 +02:00
2017-09-18 21:18:15 +02:00
/* VNIC CHARS support */
/* convert sysfs attr name to VNIC characteristic */
static u32 qeth_l2_vnicc_sysfs_attr_to_char ( const char * attr_name )
{
if ( sysfs_streq ( attr_name , " flooding " ) )
return QETH_VNICC_FLOODING ;
else if ( sysfs_streq ( attr_name , " mcast_flooding " ) )
return QETH_VNICC_MCAST_FLOODING ;
else if ( sysfs_streq ( attr_name , " learning " ) )
return QETH_VNICC_LEARNING ;
else if ( sysfs_streq ( attr_name , " takeover_setvmac " ) )
return QETH_VNICC_TAKEOVER_SETVMAC ;
else if ( sysfs_streq ( attr_name , " takeover_learning " ) )
return QETH_VNICC_TAKEOVER_LEARNING ;
else if ( sysfs_streq ( attr_name , " bridge_invisible " ) )
return QETH_VNICC_BRIDGE_INVISIBLE ;
else if ( sysfs_streq ( attr_name , " rx_bcast " ) )
return QETH_VNICC_RX_BCAST ;
return 0 ;
}
2017-09-18 21:18:16 +02:00
/* get current timeout setting */
static ssize_t qeth_vnicc_timeout_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct qeth_card * card = dev_get_drvdata ( dev ) ;
u32 timeout ;
int rc ;
if ( ! card )
return - EINVAL ;
rc = qeth_l2_vnicc_get_timeout ( card , & timeout ) ;
if ( rc = = - EBUSY )
return sprintf ( buf , " n/a (BridgePort) \ n " ) ;
if ( rc = = - EOPNOTSUPP )
return sprintf ( buf , " n/a \n " ) ;
return rc ? rc : sprintf ( buf , " %d \n " , timeout ) ;
}
/* change timeout setting */
static ssize_t qeth_vnicc_timeout_store ( struct device * dev ,
struct device_attribute * attr ,
const char * buf , size_t count )
{
struct qeth_card * card = dev_get_drvdata ( dev ) ;
u32 timeout ;
int rc ;
if ( ! card )
return - EINVAL ;
rc = kstrtou32 ( buf , 10 , & timeout ) ;
if ( rc )
return rc ;
mutex_lock ( & card - > conf_mutex ) ;
rc = qeth_l2_vnicc_set_timeout ( card , timeout ) ;
mutex_unlock ( & card - > conf_mutex ) ;
return rc ? rc : count ;
}
2017-09-18 21:18:15 +02:00
/* get current setting of characteristic */
static ssize_t qeth_vnicc_char_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct qeth_card * card = dev_get_drvdata ( dev ) ;
bool state ;
u32 vnicc ;
int rc ;
if ( ! card )
return - EINVAL ;
vnicc = qeth_l2_vnicc_sysfs_attr_to_char ( attr - > attr . name ) ;
rc = qeth_l2_vnicc_get_state ( card , vnicc , & state ) ;
if ( rc = = - EBUSY )
return sprintf ( buf , " n/a (BridgePort) \ n " ) ;
if ( rc = = - EOPNOTSUPP )
return sprintf ( buf , " n/a \n " ) ;
return rc ? rc : sprintf ( buf , " %d \n " , state ) ;
}
/* change setting of characteristic */
static ssize_t qeth_vnicc_char_store ( struct device * dev ,
struct device_attribute * attr ,
const char * buf , size_t count )
{
struct qeth_card * card = dev_get_drvdata ( dev ) ;
bool state ;
u32 vnicc ;
int rc ;
if ( ! card )
return - EINVAL ;
if ( kstrtobool ( buf , & state ) )
return - EINVAL ;
vnicc = qeth_l2_vnicc_sysfs_attr_to_char ( attr - > attr . name ) ;
mutex_lock ( & card - > conf_mutex ) ;
rc = qeth_l2_vnicc_set_state ( card , vnicc , state ) ;
mutex_unlock ( & card - > conf_mutex ) ;
return rc ? rc : count ;
}
static DEVICE_ATTR ( flooding , 0644 , qeth_vnicc_char_show , qeth_vnicc_char_store ) ;
static DEVICE_ATTR ( mcast_flooding , 0644 , qeth_vnicc_char_show ,
qeth_vnicc_char_store ) ;
static DEVICE_ATTR ( learning , 0644 , qeth_vnicc_char_show , qeth_vnicc_char_store ) ;
2017-09-18 21:18:16 +02:00
static DEVICE_ATTR ( learning_timeout , 0644 , qeth_vnicc_timeout_show ,
qeth_vnicc_timeout_store ) ;
2017-09-18 21:18:15 +02:00
static DEVICE_ATTR ( takeover_setvmac , 0644 , qeth_vnicc_char_show ,
qeth_vnicc_char_store ) ;
static DEVICE_ATTR ( takeover_learning , 0644 , qeth_vnicc_char_show ,
qeth_vnicc_char_store ) ;
static DEVICE_ATTR ( bridge_invisible , 0644 , qeth_vnicc_char_show ,
qeth_vnicc_char_store ) ;
static DEVICE_ATTR ( rx_bcast , 0644 , qeth_vnicc_char_show , qeth_vnicc_char_store ) ;
static struct attribute * qeth_l2_vnicc_attrs [ ] = {
& dev_attr_flooding . attr ,
& dev_attr_mcast_flooding . attr ,
& dev_attr_learning . attr ,
2017-09-18 21:18:16 +02:00
& dev_attr_learning_timeout . attr ,
2017-09-18 21:18:15 +02:00
& dev_attr_takeover_setvmac . attr ,
& dev_attr_takeover_learning . attr ,
& dev_attr_bridge_invisible . attr ,
& dev_attr_rx_bcast . attr ,
NULL ,
} ;
static struct attribute_group qeth_l2_vnicc_attr_group = {
. attrs = qeth_l2_vnicc_attrs ,
. name = " vnicc " ,
} ;
static const struct attribute_group * qeth_l2_only_attr_groups [ ] = {
& qeth_l2_bridgeport_attr_group ,
& qeth_l2_vnicc_attr_group ,
NULL ,
} ;
int qeth_l2_create_device_attributes ( struct device * dev )
{
return sysfs_create_groups ( & dev - > kobj , qeth_l2_only_attr_groups ) ;
}
void qeth_l2_remove_device_attributes ( struct device * dev )
{
sysfs_remove_groups ( & dev - > kobj , qeth_l2_only_attr_groups ) ;
}
2017-05-10 19:07:52 +02:00
const struct attribute_group * qeth_l2_attr_groups [ ] = {
& qeth_device_attr_group ,
& qeth_device_blkt_group ,
2017-09-18 21:18:15 +02:00
/* l2 specific, see qeth_l2_only_attr_groups: */
2017-05-10 19:07:52 +02:00
& qeth_l2_bridgeport_attr_group ,
2017-09-18 21:18:15 +02:00
& qeth_l2_vnicc_attr_group ,
2017-05-10 19:07:52 +02:00
NULL ,
} ;