384 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright IBM Corp. 20134 * Author(s): Eugene Crosser <eugene.crosser@ru.ibm.com>5 */6 7#include <linux/slab.h>8#include <asm/ebcdic.h>9#include "qeth_core.h"10#include "qeth_l2.h"11 12static ssize_t qeth_bridge_port_role_state_show(struct device *dev,13 struct device_attribute *attr, char *buf,14 int show_state)15{16 struct qeth_card *card = dev_get_drvdata(dev);17 enum qeth_sbp_states state = QETH_SBP_STATE_INACTIVE;18 int rc = 0;19 char *word;20 21 if (!qeth_bridgeport_allowed(card))22 return sysfs_emit(buf, "n/a (VNIC characteristics)\n");23 24 mutex_lock(&card->sbp_lock);25 if (qeth_card_hw_is_reachable(card) &&26 card->options.sbp.supported_funcs)27 rc = qeth_bridgeport_query_ports(card,28 &card->options.sbp.role, &state);29 if (!rc) {30 if (show_state)31 switch (state) {32 case QETH_SBP_STATE_INACTIVE:33 word = "inactive"; break;34 case QETH_SBP_STATE_STANDBY:35 word = "standby"; break;36 case QETH_SBP_STATE_ACTIVE:37 word = "active"; break;38 default:39 rc = -EIO;40 }41 else42 switch (card->options.sbp.role) {43 case QETH_SBP_ROLE_NONE:44 word = "none"; break;45 case QETH_SBP_ROLE_PRIMARY:46 word = "primary"; break;47 case QETH_SBP_ROLE_SECONDARY:48 word = "secondary"; break;49 default:50 rc = -EIO;51 }52 if (rc)53 QETH_CARD_TEXT_(card, 2, "SBP%02x:%02x",54 card->options.sbp.role, state);55 else56 rc = sysfs_emit(buf, "%s\n", word);57 }58 mutex_unlock(&card->sbp_lock);59 60 return rc;61}62 63static ssize_t qeth_bridge_port_role_show(struct device *dev,64 struct device_attribute *attr, char *buf)65{66 struct qeth_card *card = dev_get_drvdata(dev);67 68 if (!qeth_bridgeport_allowed(card))69 return sysfs_emit(buf, "n/a (VNIC characteristics)\n");70 71 return qeth_bridge_port_role_state_show(dev, attr, buf, 0);72}73 74static ssize_t qeth_bridge_port_role_store(struct device *dev,75 struct device_attribute *attr, const char *buf, size_t count)76{77 struct qeth_card *card = dev_get_drvdata(dev);78 int rc = 0;79 enum qeth_sbp_roles role;80 81 if (sysfs_streq(buf, "primary"))82 role = QETH_SBP_ROLE_PRIMARY;83 else if (sysfs_streq(buf, "secondary"))84 role = QETH_SBP_ROLE_SECONDARY;85 else if (sysfs_streq(buf, "none"))86 role = QETH_SBP_ROLE_NONE;87 else88 return -EINVAL;89 90 mutex_lock(&card->conf_mutex);91 mutex_lock(&card->sbp_lock);92 93 if (!qeth_bridgeport_allowed(card))94 rc = -EBUSY;95 else if (card->options.sbp.reflect_promisc)96 /* Forbid direct manipulation */97 rc = -EPERM;98 else if (qeth_card_hw_is_reachable(card)) {99 rc = qeth_bridgeport_setrole(card, role);100 if (!rc)101 card->options.sbp.role = role;102 } else103 card->options.sbp.role = role;104 105 mutex_unlock(&card->sbp_lock);106 mutex_unlock(&card->conf_mutex);107 108 return rc ? rc : count;109}110 111static DEVICE_ATTR(bridge_role, 0644, qeth_bridge_port_role_show,112 qeth_bridge_port_role_store);113 114static ssize_t qeth_bridge_port_state_show(struct device *dev,115 struct device_attribute *attr, char *buf)116{117 struct qeth_card *card = dev_get_drvdata(dev);118 119 if (!qeth_bridgeport_allowed(card))120 return sysfs_emit(buf, "n/a (VNIC characteristics)\n");121 122 return qeth_bridge_port_role_state_show(dev, attr, buf, 1);123}124 125static DEVICE_ATTR(bridge_state, 0444, qeth_bridge_port_state_show,126 NULL);127 128static ssize_t qeth_bridgeport_hostnotification_show(struct device *dev,129 struct device_attribute *attr, char *buf)130{131 struct qeth_card *card = dev_get_drvdata(dev);132 int enabled;133 134 if (!qeth_bridgeport_allowed(card))135 return sysfs_emit(buf, "n/a (VNIC characteristics)\n");136 137 enabled = card->options.sbp.hostnotification;138 139 return sysfs_emit(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 bool enable;147 int rc;148 149 rc = kstrtobool(buf, &enable);150 if (rc)151 return rc;152 153 mutex_lock(&card->conf_mutex);154 mutex_lock(&card->sbp_lock);155 156 if (!qeth_bridgeport_allowed(card))157 rc = -EBUSY;158 else if (qeth_card_hw_is_reachable(card)) {159 rc = qeth_bridgeport_an_set(card, enable);160 /* sbp_lock ensures ordering vs notifications-stopped events */161 if (!rc)162 card->options.sbp.hostnotification = enable;163 } else164 card->options.sbp.hostnotification = enable;165 166 mutex_unlock(&card->sbp_lock);167 mutex_unlock(&card->conf_mutex);168 169 return rc ? rc : count;170}171 172static DEVICE_ATTR(bridge_hostnotify, 0644,173 qeth_bridgeport_hostnotification_show,174 qeth_bridgeport_hostnotification_store);175 176static ssize_t qeth_bridgeport_reflect_show(struct device *dev,177 struct device_attribute *attr, char *buf)178{179 struct qeth_card *card = dev_get_drvdata(dev);180 char *state;181 182 if (!qeth_bridgeport_allowed(card))183 return sysfs_emit(buf, "n/a (VNIC characteristics)\n");184 185 if (card->options.sbp.reflect_promisc) {186 if (card->options.sbp.reflect_promisc_primary)187 state = "primary";188 else189 state = "secondary";190 } else191 state = "none";192 193 return sysfs_emit(buf, "%s\n", state);194}195 196static ssize_t qeth_bridgeport_reflect_store(struct device *dev,197 struct device_attribute *attr, const char *buf, size_t count)198{199 struct qeth_card *card = dev_get_drvdata(dev);200 int enable, primary;201 int rc = 0;202 203 if (sysfs_streq(buf, "none")) {204 enable = 0;205 primary = 0;206 } else if (sysfs_streq(buf, "primary")) {207 enable = 1;208 primary = 1;209 } else if (sysfs_streq(buf, "secondary")) {210 enable = 1;211 primary = 0;212 } else213 return -EINVAL;214 215 mutex_lock(&card->conf_mutex);216 mutex_lock(&card->sbp_lock);217 218 if (!qeth_bridgeport_allowed(card))219 rc = -EBUSY;220 else if (card->options.sbp.role != QETH_SBP_ROLE_NONE)221 rc = -EPERM;222 else {223 card->options.sbp.reflect_promisc = enable;224 card->options.sbp.reflect_promisc_primary = primary;225 rc = 0;226 }227 228 mutex_unlock(&card->sbp_lock);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 250/* VNIC CHARS support */251 252/* convert sysfs attr name to VNIC characteristic */253static u32 qeth_l2_vnicc_sysfs_attr_to_char(const char *attr_name)254{255 if (sysfs_streq(attr_name, "flooding"))256 return QETH_VNICC_FLOODING;257 else if (sysfs_streq(attr_name, "mcast_flooding"))258 return QETH_VNICC_MCAST_FLOODING;259 else if (sysfs_streq(attr_name, "learning"))260 return QETH_VNICC_LEARNING;261 else if (sysfs_streq(attr_name, "takeover_setvmac"))262 return QETH_VNICC_TAKEOVER_SETVMAC;263 else if (sysfs_streq(attr_name, "takeover_learning"))264 return QETH_VNICC_TAKEOVER_LEARNING;265 else if (sysfs_streq(attr_name, "bridge_invisible"))266 return QETH_VNICC_BRIDGE_INVISIBLE;267 else if (sysfs_streq(attr_name, "rx_bcast"))268 return QETH_VNICC_RX_BCAST;269 270 return 0;271}272 273/* get current timeout setting */274static ssize_t qeth_vnicc_timeout_show(struct device *dev,275 struct device_attribute *attr, char *buf)276{277 struct qeth_card *card = dev_get_drvdata(dev);278 u32 timeout;279 int rc;280 281 rc = qeth_l2_vnicc_get_timeout(card, &timeout);282 if (rc == -EBUSY)283 return sysfs_emit(buf, "n/a (BridgePort)\n");284 if (rc == -EOPNOTSUPP)285 return sysfs_emit(buf, "n/a\n");286 return rc ? rc : sysfs_emit(buf, "%d\n", timeout);287}288 289/* change timeout setting */290static ssize_t qeth_vnicc_timeout_store(struct device *dev,291 struct device_attribute *attr,292 const char *buf, size_t count)293{294 struct qeth_card *card = dev_get_drvdata(dev);295 u32 timeout;296 int rc;297 298 rc = kstrtou32(buf, 10, &timeout);299 if (rc)300 return rc;301 302 mutex_lock(&card->conf_mutex);303 rc = qeth_l2_vnicc_set_timeout(card, timeout);304 mutex_unlock(&card->conf_mutex);305 return rc ? rc : count;306}307 308/* get current setting of characteristic */309static ssize_t qeth_vnicc_char_show(struct device *dev,310 struct device_attribute *attr, char *buf)311{312 struct qeth_card *card = dev_get_drvdata(dev);313 bool state;314 u32 vnicc;315 int rc;316 317 vnicc = qeth_l2_vnicc_sysfs_attr_to_char(attr->attr.name);318 rc = qeth_l2_vnicc_get_state(card, vnicc, &state);319 320 if (rc == -EBUSY)321 return sysfs_emit(buf, "n/a (BridgePort)\n");322 if (rc == -EOPNOTSUPP)323 return sysfs_emit(buf, "n/a\n");324 return rc ? rc : sysfs_emit(buf, "%d\n", state);325}326 327/* change setting of characteristic */328static ssize_t qeth_vnicc_char_store(struct device *dev,329 struct device_attribute *attr,330 const char *buf, size_t count)331{332 struct qeth_card *card = dev_get_drvdata(dev);333 bool state;334 u32 vnicc;335 int rc;336 337 if (kstrtobool(buf, &state))338 return -EINVAL;339 340 vnicc = qeth_l2_vnicc_sysfs_attr_to_char(attr->attr.name);341 mutex_lock(&card->conf_mutex);342 rc = qeth_l2_vnicc_set_state(card, vnicc, state);343 mutex_unlock(&card->conf_mutex);344 345 return rc ? rc : count;346}347 348static DEVICE_ATTR(flooding, 0644, qeth_vnicc_char_show, qeth_vnicc_char_store);349static DEVICE_ATTR(mcast_flooding, 0644, qeth_vnicc_char_show,350 qeth_vnicc_char_store);351static DEVICE_ATTR(learning, 0644, qeth_vnicc_char_show, qeth_vnicc_char_store);352static DEVICE_ATTR(learning_timeout, 0644, qeth_vnicc_timeout_show,353 qeth_vnicc_timeout_store);354static DEVICE_ATTR(takeover_setvmac, 0644, qeth_vnicc_char_show,355 qeth_vnicc_char_store);356static DEVICE_ATTR(takeover_learning, 0644, qeth_vnicc_char_show,357 qeth_vnicc_char_store);358static DEVICE_ATTR(bridge_invisible, 0644, qeth_vnicc_char_show,359 qeth_vnicc_char_store);360static DEVICE_ATTR(rx_bcast, 0644, qeth_vnicc_char_show, qeth_vnicc_char_store);361 362static struct attribute *qeth_l2_vnicc_attrs[] = {363 &dev_attr_flooding.attr,364 &dev_attr_mcast_flooding.attr,365 &dev_attr_learning.attr,366 &dev_attr_learning_timeout.attr,367 &dev_attr_takeover_setvmac.attr,368 &dev_attr_takeover_learning.attr,369 &dev_attr_bridge_invisible.attr,370 &dev_attr_rx_bcast.attr,371 NULL,372};373 374static struct attribute_group qeth_l2_vnicc_attr_group = {375 .attrs = qeth_l2_vnicc_attrs,376 .name = "vnicc",377};378 379const struct attribute_group *qeth_l2_attr_groups[] = {380 &qeth_l2_bridgeport_attr_group,381 &qeth_l2_vnicc_attr_group,382 NULL,383};384