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_core.h" 9 #include "qeth_l2.h" 10 11 static ssize_t qeth_bridge_port_role_state_show(struct device *dev, 12 struct device_attribute *attr, char *buf, 13 int show_state) 14 { 15 struct qeth_card *card = dev_get_drvdata(dev); 16 enum qeth_sbp_states state = QETH_SBP_STATE_INACTIVE; 17 int rc = 0; 18 char *word; 19 20 if (!card) 21 return -EINVAL; 22 23 if (qeth_l2_vnicc_is_in_use(card)) 24 return sprintf(buf, "n/a (VNIC characteristics)\n"); 25 26 if (qeth_card_hw_is_reachable(card) && 27 card->options.sbp.supported_funcs) 28 rc = qeth_bridgeport_query_ports(card, 29 &card->options.sbp.role, &state); 30 if (!rc) { 31 if (show_state) 32 switch (state) { 33 case QETH_SBP_STATE_INACTIVE: 34 word = "inactive"; break; 35 case QETH_SBP_STATE_STANDBY: 36 word = "standby"; break; 37 case QETH_SBP_STATE_ACTIVE: 38 word = "active"; break; 39 default: 40 rc = -EIO; 41 } 42 else 43 switch (card->options.sbp.role) { 44 case QETH_SBP_ROLE_NONE: 45 word = "none"; break; 46 case QETH_SBP_ROLE_PRIMARY: 47 word = "primary"; break; 48 case QETH_SBP_ROLE_SECONDARY: 49 word = "secondary"; break; 50 default: 51 rc = -EIO; 52 } 53 if (rc) 54 QETH_CARD_TEXT_(card, 2, "SBP%02x:%02x", 55 card->options.sbp.role, state); 56 else 57 rc = sprintf(buf, "%s\n", word); 58 } 59 60 return rc; 61 } 62 63 static 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_l2_vnicc_is_in_use(card)) 69 return sprintf(buf, "n/a (VNIC characteristics)\n"); 70 71 return qeth_bridge_port_role_state_show(dev, attr, buf, 0); 72 } 73 74 static 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 (!card) 82 return -EINVAL; 83 if (sysfs_streq(buf, "primary")) 84 role = QETH_SBP_ROLE_PRIMARY; 85 else if (sysfs_streq(buf, "secondary")) 86 role = QETH_SBP_ROLE_SECONDARY; 87 else if (sysfs_streq(buf, "none")) 88 role = QETH_SBP_ROLE_NONE; 89 else 90 return -EINVAL; 91 92 mutex_lock(&card->conf_mutex); 93 94 if (qeth_l2_vnicc_is_in_use(card)) 95 rc = -EBUSY; 96 else if (card->options.sbp.reflect_promisc) 97 /* Forbid direct manipulation */ 98 rc = -EPERM; 99 else if (qeth_card_hw_is_reachable(card)) { 100 rc = qeth_bridgeport_setrole(card, role); 101 if (!rc) 102 card->options.sbp.role = role; 103 } else 104 card->options.sbp.role = role; 105 106 mutex_unlock(&card->conf_mutex); 107 108 return rc ? rc : count; 109 } 110 111 static DEVICE_ATTR(bridge_role, 0644, qeth_bridge_port_role_show, 112 qeth_bridge_port_role_store); 113 114 static 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_l2_vnicc_is_in_use(card)) 120 return sprintf(buf, "n/a (VNIC characteristics)\n"); 121 122 return qeth_bridge_port_role_state_show(dev, attr, buf, 1); 123 } 124 125 static DEVICE_ATTR(bridge_state, 0444, qeth_bridge_port_state_show, 126 NULL); 127 128 static 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 (!card) 135 return -EINVAL; 136 137 if (qeth_l2_vnicc_is_in_use(card)) 138 return sprintf(buf, "n/a (VNIC characteristics)\n"); 139 140 enabled = card->options.sbp.hostnotification; 141 142 return sprintf(buf, "%d\n", enabled); 143 } 144 145 static ssize_t qeth_bridgeport_hostnotification_store(struct device *dev, 146 struct device_attribute *attr, const char *buf, size_t count) 147 { 148 struct qeth_card *card = dev_get_drvdata(dev); 149 bool enable; 150 int rc; 151 152 if (!card) 153 return -EINVAL; 154 155 rc = kstrtobool(buf, &enable); 156 if (rc) 157 return rc; 158 159 mutex_lock(&card->conf_mutex); 160 161 if (qeth_l2_vnicc_is_in_use(card)) 162 rc = -EBUSY; 163 else if (qeth_card_hw_is_reachable(card)) { 164 rc = qeth_bridgeport_an_set(card, enable); 165 if (!rc) 166 card->options.sbp.hostnotification = enable; 167 } else 168 card->options.sbp.hostnotification = enable; 169 170 mutex_unlock(&card->conf_mutex); 171 172 return rc ? rc : count; 173 } 174 175 static DEVICE_ATTR(bridge_hostnotify, 0644, 176 qeth_bridgeport_hostnotification_show, 177 qeth_bridgeport_hostnotification_store); 178 179 static ssize_t qeth_bridgeport_reflect_show(struct device *dev, 180 struct device_attribute *attr, char *buf) 181 { 182 struct qeth_card *card = dev_get_drvdata(dev); 183 char *state; 184 185 if (!card) 186 return -EINVAL; 187 188 if (qeth_l2_vnicc_is_in_use(card)) 189 return sprintf(buf, "n/a (VNIC characteristics)\n"); 190 191 if (card->options.sbp.reflect_promisc) { 192 if (card->options.sbp.reflect_promisc_primary) 193 state = "primary"; 194 else 195 state = "secondary"; 196 } else 197 state = "none"; 198 199 return sprintf(buf, "%s\n", state); 200 } 201 202 static ssize_t qeth_bridgeport_reflect_store(struct device *dev, 203 struct device_attribute *attr, const char *buf, size_t count) 204 { 205 struct qeth_card *card = dev_get_drvdata(dev); 206 int enable, primary; 207 int rc = 0; 208 209 if (!card) 210 return -EINVAL; 211 212 if (sysfs_streq(buf, "none")) { 213 enable = 0; 214 primary = 0; 215 } else if (sysfs_streq(buf, "primary")) { 216 enable = 1; 217 primary = 1; 218 } else if (sysfs_streq(buf, "secondary")) { 219 enable = 1; 220 primary = 0; 221 } else 222 return -EINVAL; 223 224 mutex_lock(&card->conf_mutex); 225 226 if (qeth_l2_vnicc_is_in_use(card)) 227 rc = -EBUSY; 228 else if (card->options.sbp.role != QETH_SBP_ROLE_NONE) 229 rc = -EPERM; 230 else { 231 card->options.sbp.reflect_promisc = enable; 232 card->options.sbp.reflect_promisc_primary = primary; 233 rc = 0; 234 } 235 236 mutex_unlock(&card->conf_mutex); 237 238 return rc ? rc : count; 239 } 240 241 static DEVICE_ATTR(bridge_reflect_promisc, 0644, 242 qeth_bridgeport_reflect_show, 243 qeth_bridgeport_reflect_store); 244 245 static struct attribute *qeth_l2_bridgeport_attrs[] = { 246 &dev_attr_bridge_role.attr, 247 &dev_attr_bridge_state.attr, 248 &dev_attr_bridge_hostnotify.attr, 249 &dev_attr_bridge_reflect_promisc.attr, 250 NULL, 251 }; 252 253 static struct attribute_group qeth_l2_bridgeport_attr_group = { 254 .attrs = qeth_l2_bridgeport_attrs, 255 }; 256 257 /** 258 * qeth_l2_setup_bridgeport_attrs() - set/restore attrs when turning online. 259 * @card: qeth_card structure pointer 260 * 261 * Note: this function is called with conf_mutex held by the caller 262 */ 263 void qeth_l2_setup_bridgeport_attrs(struct qeth_card *card) 264 { 265 int rc; 266 267 if (!card) 268 return; 269 if (!card->options.sbp.supported_funcs) 270 return; 271 if (card->options.sbp.role != QETH_SBP_ROLE_NONE) { 272 /* Conditional to avoid spurious error messages */ 273 qeth_bridgeport_setrole(card, card->options.sbp.role); 274 /* Let the callback function refresh the stored role value. */ 275 qeth_bridgeport_query_ports(card, 276 &card->options.sbp.role, NULL); 277 } 278 if (card->options.sbp.hostnotification) { 279 rc = qeth_bridgeport_an_set(card, 1); 280 if (rc) 281 card->options.sbp.hostnotification = 0; 282 } else 283 qeth_bridgeport_an_set(card, 0); 284 } 285 286 /* VNIC CHARS support */ 287 288 /* convert sysfs attr name to VNIC characteristic */ 289 static u32 qeth_l2_vnicc_sysfs_attr_to_char(const char *attr_name) 290 { 291 if (sysfs_streq(attr_name, "flooding")) 292 return QETH_VNICC_FLOODING; 293 else if (sysfs_streq(attr_name, "mcast_flooding")) 294 return QETH_VNICC_MCAST_FLOODING; 295 else if (sysfs_streq(attr_name, "learning")) 296 return QETH_VNICC_LEARNING; 297 else if (sysfs_streq(attr_name, "takeover_setvmac")) 298 return QETH_VNICC_TAKEOVER_SETVMAC; 299 else if (sysfs_streq(attr_name, "takeover_learning")) 300 return QETH_VNICC_TAKEOVER_LEARNING; 301 else if (sysfs_streq(attr_name, "bridge_invisible")) 302 return QETH_VNICC_BRIDGE_INVISIBLE; 303 else if (sysfs_streq(attr_name, "rx_bcast")) 304 return QETH_VNICC_RX_BCAST; 305 306 return 0; 307 } 308 309 /* get current timeout setting */ 310 static ssize_t qeth_vnicc_timeout_show(struct device *dev, 311 struct device_attribute *attr, char *buf) 312 { 313 struct qeth_card *card = dev_get_drvdata(dev); 314 u32 timeout; 315 int rc; 316 317 if (!card) 318 return -EINVAL; 319 320 rc = qeth_l2_vnicc_get_timeout(card, &timeout); 321 if (rc == -EBUSY) 322 return sprintf(buf, "n/a (BridgePort)\n"); 323 if (rc == -EOPNOTSUPP) 324 return sprintf(buf, "n/a\n"); 325 return rc ? rc : sprintf(buf, "%d\n", timeout); 326 } 327 328 /* change timeout setting */ 329 static ssize_t qeth_vnicc_timeout_store(struct device *dev, 330 struct device_attribute *attr, 331 const char *buf, size_t count) 332 { 333 struct qeth_card *card = dev_get_drvdata(dev); 334 u32 timeout; 335 int rc; 336 337 if (!card) 338 return -EINVAL; 339 340 rc = kstrtou32(buf, 10, &timeout); 341 if (rc) 342 return rc; 343 344 mutex_lock(&card->conf_mutex); 345 rc = qeth_l2_vnicc_set_timeout(card, timeout); 346 mutex_unlock(&card->conf_mutex); 347 return rc ? rc : count; 348 } 349 350 /* get current setting of characteristic */ 351 static ssize_t qeth_vnicc_char_show(struct device *dev, 352 struct device_attribute *attr, char *buf) 353 { 354 struct qeth_card *card = dev_get_drvdata(dev); 355 bool state; 356 u32 vnicc; 357 int rc; 358 359 if (!card) 360 return -EINVAL; 361 362 vnicc = qeth_l2_vnicc_sysfs_attr_to_char(attr->attr.name); 363 rc = qeth_l2_vnicc_get_state(card, vnicc, &state); 364 365 if (rc == -EBUSY) 366 return sprintf(buf, "n/a (BridgePort)\n"); 367 if (rc == -EOPNOTSUPP) 368 return sprintf(buf, "n/a\n"); 369 return rc ? rc : sprintf(buf, "%d\n", state); 370 } 371 372 /* change setting of characteristic */ 373 static ssize_t qeth_vnicc_char_store(struct device *dev, 374 struct device_attribute *attr, 375 const char *buf, size_t count) 376 { 377 struct qeth_card *card = dev_get_drvdata(dev); 378 bool state; 379 u32 vnicc; 380 int rc; 381 382 if (!card) 383 return -EINVAL; 384 385 if (kstrtobool(buf, &state)) 386 return -EINVAL; 387 388 vnicc = qeth_l2_vnicc_sysfs_attr_to_char(attr->attr.name); 389 mutex_lock(&card->conf_mutex); 390 rc = qeth_l2_vnicc_set_state(card, vnicc, state); 391 mutex_unlock(&card->conf_mutex); 392 393 return rc ? rc : count; 394 } 395 396 static DEVICE_ATTR(flooding, 0644, qeth_vnicc_char_show, qeth_vnicc_char_store); 397 static DEVICE_ATTR(mcast_flooding, 0644, qeth_vnicc_char_show, 398 qeth_vnicc_char_store); 399 static DEVICE_ATTR(learning, 0644, qeth_vnicc_char_show, qeth_vnicc_char_store); 400 static DEVICE_ATTR(learning_timeout, 0644, qeth_vnicc_timeout_show, 401 qeth_vnicc_timeout_store); 402 static DEVICE_ATTR(takeover_setvmac, 0644, qeth_vnicc_char_show, 403 qeth_vnicc_char_store); 404 static DEVICE_ATTR(takeover_learning, 0644, qeth_vnicc_char_show, 405 qeth_vnicc_char_store); 406 static DEVICE_ATTR(bridge_invisible, 0644, qeth_vnicc_char_show, 407 qeth_vnicc_char_store); 408 static DEVICE_ATTR(rx_bcast, 0644, qeth_vnicc_char_show, qeth_vnicc_char_store); 409 410 static struct attribute *qeth_l2_vnicc_attrs[] = { 411 &dev_attr_flooding.attr, 412 &dev_attr_mcast_flooding.attr, 413 &dev_attr_learning.attr, 414 &dev_attr_learning_timeout.attr, 415 &dev_attr_takeover_setvmac.attr, 416 &dev_attr_takeover_learning.attr, 417 &dev_attr_bridge_invisible.attr, 418 &dev_attr_rx_bcast.attr, 419 NULL, 420 }; 421 422 static struct attribute_group qeth_l2_vnicc_attr_group = { 423 .attrs = qeth_l2_vnicc_attrs, 424 .name = "vnicc", 425 }; 426 427 static const struct attribute_group *qeth_l2_only_attr_groups[] = { 428 &qeth_l2_bridgeport_attr_group, 429 &qeth_l2_vnicc_attr_group, 430 NULL, 431 }; 432 433 int qeth_l2_create_device_attributes(struct device *dev) 434 { 435 return sysfs_create_groups(&dev->kobj, qeth_l2_only_attr_groups); 436 } 437 438 void qeth_l2_remove_device_attributes(struct device *dev) 439 { 440 sysfs_remove_groups(&dev->kobj, qeth_l2_only_attr_groups); 441 } 442 443 const struct attribute_group *qeth_l2_attr_groups[] = { 444 &qeth_device_attr_group, 445 &qeth_device_blkt_group, 446 /* l2 specific, see qeth_l2_only_attr_groups: */ 447 &qeth_l2_bridgeport_attr_group, 448 &qeth_l2_vnicc_attr_group, 449 NULL, 450 }; 451