linux/drivers/s390/net/qeth_l2_sys.c
<<
>>
Prefs
   1/*
   2 *    Copyright IBM Corp. 2013
   3 *    Author(s): Eugene Crosser <eugene.crosser@ru.ibm.com>
   4 */
   5
   6#include <linux/slab.h>
   7#include <asm/ebcdic.h>
   8#include "qeth_l2.h"
   9
  10#define QETH_DEVICE_ATTR(_id, _name, _mode, _show, _store) \
  11struct device_attribute dev_attr_##_id = __ATTR(_name, _mode, _show, _store)
  12
  13static int qeth_card_hw_is_reachable(struct qeth_card *card)
  14{
  15        return (card->state == CARD_STATE_SOFTSETUP) ||
  16                (card->state == CARD_STATE_UP);
  17}
  18
  19static ssize_t qeth_bridge_port_role_state_show(struct device *dev,
  20                                struct device_attribute *attr, char *buf,
  21                                int show_state)
  22{
  23        struct qeth_card *card = dev_get_drvdata(dev);
  24        enum qeth_sbp_states state = QETH_SBP_STATE_INACTIVE;
  25        int rc = 0;
  26        char *word;
  27
  28        if (!card)
  29                return -EINVAL;
  30
  31        mutex_lock(&card->conf_mutex);
  32
  33        if (qeth_card_hw_is_reachable(card) &&
  34                                        card->options.sbp.supported_funcs)
  35                rc = qeth_bridgeport_query_ports(card,
  36                        &card->options.sbp.role, &state);
  37        if (!rc) {
  38                if (show_state)
  39                        switch (state) {
  40                        case QETH_SBP_STATE_INACTIVE:
  41                                word = "inactive"; break;
  42                        case QETH_SBP_STATE_STANDBY:
  43                                word = "standby"; break;
  44                        case QETH_SBP_STATE_ACTIVE:
  45                                word = "active"; break;
  46                        default:
  47                                rc = -EIO;
  48                        }
  49                else
  50                        switch (card->options.sbp.role) {
  51                        case QETH_SBP_ROLE_NONE:
  52                                word = "none"; break;
  53                        case QETH_SBP_ROLE_PRIMARY:
  54                                word = "primary"; break;
  55                        case QETH_SBP_ROLE_SECONDARY:
  56                                word = "secondary"; break;
  57                        default:
  58                                rc = -EIO;
  59                        }
  60                if (rc)
  61                        QETH_CARD_TEXT_(card, 2, "SBP%02x:%02x",
  62                                card->options.sbp.role, state);
  63                else
  64                        rc = sprintf(buf, "%s\n", word);
  65        }
  66
  67        mutex_unlock(&card->conf_mutex);
  68
  69        return rc;
  70}
  71
  72static ssize_t qeth_bridge_port_role_show(struct device *dev,
  73                                struct device_attribute *attr, char *buf)
  74{
  75        return qeth_bridge_port_role_state_show(dev, attr, buf, 0);
  76}
  77
  78static ssize_t qeth_bridge_port_role_store(struct device *dev,
  79                struct device_attribute *attr, const char *buf, size_t count)
  80{
  81        struct qeth_card *card = dev_get_drvdata(dev);
  82        int rc = 0;
  83        enum qeth_sbp_roles role;
  84
  85        if (!card)
  86                return -EINVAL;
  87        if (sysfs_streq(buf, "primary"))
  88                role = QETH_SBP_ROLE_PRIMARY;
  89        else if (sysfs_streq(buf, "secondary"))
  90                role = QETH_SBP_ROLE_SECONDARY;
  91        else if (sysfs_streq(buf, "none"))
  92                role = QETH_SBP_ROLE_NONE;
  93        else
  94                return -EINVAL;
  95
  96        mutex_lock(&card->conf_mutex);
  97
  98        if (card->options.sbp.reflect_promisc) /* Forbid direct manipulation */
  99                rc = -EPERM;
 100        else if (qeth_card_hw_is_reachable(card)) {
 101                rc = qeth_bridgeport_setrole(card, role);
 102                if (!rc)
 103                        card->options.sbp.role = role;
 104        } else
 105                card->options.sbp.role = role;
 106
 107        mutex_unlock(&card->conf_mutex);
 108
 109        return rc ? rc : count;
 110}
 111
 112static DEVICE_ATTR(bridge_role, 0644, qeth_bridge_port_role_show,
 113                   qeth_bridge_port_role_store);
 114
 115static ssize_t qeth_bridge_port_state_show(struct device *dev,
 116                                struct device_attribute *attr, char *buf)
 117{
 118        return qeth_bridge_port_role_state_show(dev, attr, buf, 1);
 119}
 120
 121static DEVICE_ATTR(bridge_state, 0644, qeth_bridge_port_state_show,
 122                   NULL);
 123
 124static ssize_t qeth_bridgeport_hostnotification_show(struct device *dev,
 125                                struct device_attribute *attr, char *buf)
 126{
 127        struct qeth_card *card = dev_get_drvdata(dev);
 128        int enabled;
 129
 130        if (!card)
 131                return -EINVAL;
 132
 133        mutex_lock(&card->conf_mutex);
 134
 135        enabled = card->options.sbp.hostnotification;
 136
 137        mutex_unlock(&card->conf_mutex);
 138
 139        return sprintf(buf, "%d\n", enabled);
 140}
 141
 142static ssize_t qeth_bridgeport_hostnotification_store(struct device *dev,
 143                struct device_attribute *attr, const char *buf, size_t count)
 144{
 145        struct qeth_card *card = dev_get_drvdata(dev);
 146        int rc = 0;
 147        int enable;
 148
 149        if (!card)
 150                return -EINVAL;
 151
 152        if (sysfs_streq(buf, "0"))
 153                enable = 0;
 154        else if (sysfs_streq(buf, "1"))
 155                enable = 1;
 156        else
 157                return -EINVAL;
 158
 159        mutex_lock(&card->conf_mutex);
 160
 161        if (qeth_card_hw_is_reachable(card)) {
 162                rc = qeth_bridgeport_an_set(card, enable);
 163                if (!rc)
 164                        card->options.sbp.hostnotification = enable;
 165        } else
 166                card->options.sbp.hostnotification = enable;
 167
 168        mutex_unlock(&card->conf_mutex);
 169
 170        return rc ? rc : count;
 171}
 172
 173static DEVICE_ATTR(bridge_hostnotify, 0644,
 174                        qeth_bridgeport_hostnotification_show,
 175                        qeth_bridgeport_hostnotification_store);
 176
 177static ssize_t qeth_bridgeport_reflect_show(struct device *dev,
 178                                struct device_attribute *attr, char *buf)
 179{
 180        struct qeth_card *card = dev_get_drvdata(dev);
 181        char *state;
 182
 183        if (!card)
 184                return -EINVAL;
 185
 186        if (card->options.sbp.reflect_promisc) {
 187                if (card->options.sbp.reflect_promisc_primary)
 188                        state = "primary";
 189                else
 190                        state = "secondary";
 191        } else
 192                state = "none";
 193
 194        return sprintf(buf, "%s\n", state);
 195}
 196
 197static ssize_t qeth_bridgeport_reflect_store(struct device *dev,
 198                struct device_attribute *attr, const char *buf, size_t count)
 199{
 200        struct qeth_card *card = dev_get_drvdata(dev);
 201        int enable, primary;
 202        int rc = 0;
 203
 204        if (!card)
 205                return -EINVAL;
 206
 207        if (sysfs_streq(buf, "none")) {
 208                enable = 0;
 209                primary = 0;
 210        } else if (sysfs_streq(buf, "primary")) {
 211                enable = 1;
 212                primary = 1;
 213        } else if (sysfs_streq(buf, "secondary")) {
 214                enable = 1;
 215                primary = 0;
 216        } else
 217                return -EINVAL;
 218
 219        mutex_lock(&card->conf_mutex);
 220
 221        if (card->options.sbp.role != QETH_SBP_ROLE_NONE)
 222                rc = -EPERM;
 223        else {
 224                card->options.sbp.reflect_promisc = enable;
 225                card->options.sbp.reflect_promisc_primary = primary;
 226                rc = 0;
 227        }
 228
 229        mutex_unlock(&card->conf_mutex);
 230
 231        return rc ? rc : count;
 232}
 233
 234static DEVICE_ATTR(bridge_reflect_promisc, 0644,
 235                        qeth_bridgeport_reflect_show,
 236                        qeth_bridgeport_reflect_store);
 237
 238static struct attribute *qeth_l2_bridgeport_attrs[] = {
 239        &dev_attr_bridge_role.attr,
 240        &dev_attr_bridge_state.attr,
 241        &dev_attr_bridge_hostnotify.attr,
 242        &dev_attr_bridge_reflect_promisc.attr,
 243        NULL,
 244};
 245
 246static struct attribute_group qeth_l2_bridgeport_attr_group = {
 247        .attrs = qeth_l2_bridgeport_attrs,
 248};
 249
 250int qeth_l2_create_device_attributes(struct device *dev)
 251{
 252        return sysfs_create_group(&dev->kobj, &qeth_l2_bridgeport_attr_group);
 253}
 254
 255void qeth_l2_remove_device_attributes(struct device *dev)
 256{
 257        sysfs_remove_group(&dev->kobj, &qeth_l2_bridgeport_attr_group);
 258}
 259
 260/**
 261 * qeth_l2_setup_bridgeport_attrs() - set/restore attrs when turning online.
 262 * @card:                             qeth_card structure pointer
 263 *
 264 * Note: this function is called with conf_mutex held by the caller
 265 */
 266void qeth_l2_setup_bridgeport_attrs(struct qeth_card *card)
 267{
 268        int rc;
 269
 270        if (!card)
 271                return;
 272        if (!card->options.sbp.supported_funcs)
 273                return;
 274        if (card->options.sbp.role != QETH_SBP_ROLE_NONE) {
 275                /* Conditional to avoid spurious error messages */
 276                qeth_bridgeport_setrole(card, card->options.sbp.role);
 277                /* Let the callback function refresh the stored role value. */
 278                qeth_bridgeport_query_ports(card,
 279                        &card->options.sbp.role, NULL);
 280        }
 281        if (card->options.sbp.hostnotification) {
 282                rc = qeth_bridgeport_an_set(card, 1);
 283                if (rc)
 284                        card->options.sbp.hostnotification = 0;
 285        } else
 286                qeth_bridgeport_an_set(card, 0);
 287}
 288
 289const struct attribute_group *qeth_l2_attr_groups[] = {
 290        &qeth_device_attr_group,
 291        &qeth_device_blkt_group,
 292        /* l2 specific, see l2_{create,remove}_device_attributes(): */
 293        &qeth_l2_bridgeport_attr_group,
 294        NULL,
 295};
 296