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#define QETH_DEVICE_ATTR(_id, _name, _mode, _show, _store) \ 12struct device_attribute dev_attr_##_id = __ATTR(_name, _mode, _show, _store) 13 14static ssize_t qeth_bridge_port_role_state_show(struct device *dev, 15 struct device_attribute *attr, char *buf, 16 int show_state) 17{ 18 struct qeth_card *card = dev_get_drvdata(dev); 19 enum qeth_sbp_states state = QETH_SBP_STATE_INACTIVE; 20 int rc = 0; 21 char *word; 22 23 if (!card) 24 return -EINVAL; 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 63static ssize_t qeth_bridge_port_role_show(struct device *dev, 64 struct device_attribute *attr, char *buf) 65{ 66 return qeth_bridge_port_role_state_show(dev, attr, buf, 0); 67} 68 69static ssize_t qeth_bridge_port_role_store(struct device *dev, 70 struct device_attribute *attr, const char *buf, size_t count) 71{ 72 struct qeth_card *card = dev_get_drvdata(dev); 73 int rc = 0; 74 enum qeth_sbp_roles role; 75 76 if (!card) 77 return -EINVAL; 78 if (sysfs_streq(buf, "primary")) 79 role = QETH_SBP_ROLE_PRIMARY; 80 else if (sysfs_streq(buf, "secondary")) 81 role = QETH_SBP_ROLE_SECONDARY; 82 else if (sysfs_streq(buf, "none")) 83 role = QETH_SBP_ROLE_NONE; 84 else 85 return -EINVAL; 86 87 mutex_lock(&card->conf_mutex); 88 89 if (card->options.sbp.reflect_promisc) /* Forbid direct manipulation */ 90 rc = -EPERM; 91 else if (qeth_card_hw_is_reachable(card)) { 92 rc = qeth_bridgeport_setrole(card, role); 93 if (!rc) 94 card->options.sbp.role = role; 95 } else 96 card->options.sbp.role = role; 97 98 mutex_unlock(&card->conf_mutex); 99 100 return rc ? rc : count; 101} 102 103static DEVICE_ATTR(bridge_role, 0644, qeth_bridge_port_role_show, 104 qeth_bridge_port_role_store); 105 106static ssize_t qeth_bridge_port_state_show(struct device *dev, 107 struct device_attribute *attr, char *buf) 108{ 109 return qeth_bridge_port_role_state_show(dev, attr, buf, 1); 110} 111 112static DEVICE_ATTR(bridge_state, 0444, qeth_bridge_port_state_show, 113 NULL); 114 115static ssize_t qeth_bridgeport_hostnotification_show(struct device *dev, 116 struct device_attribute *attr, char *buf) 117{ 118 struct qeth_card *card = dev_get_drvdata(dev); 119 int enabled; 120 121 if (!card) 122 return -EINVAL; 123 124 enabled = card->options.sbp.hostnotification; 125 126 return sprintf(buf, "%d\n", enabled); 127} 128 129static ssize_t qeth_bridgeport_hostnotification_store(struct device *dev, 130 struct device_attribute *attr, const char *buf, size_t count) 131{ 132 struct qeth_card *card = dev_get_drvdata(dev); 133 int rc = 0; 134 int enable; 135 136 if (!card) 137 return -EINVAL; 138 139 if (sysfs_streq(buf, "0")) 140 enable = 0; 141 else if (sysfs_streq(buf, "1")) 142 enable = 1; 143 else 144 return -EINVAL; 145 146 mutex_lock(&card->conf_mutex); 147 148 if (qeth_card_hw_is_reachable(card)) { 149 rc = qeth_bridgeport_an_set(card, enable); 150 if (!rc) 151 card->options.sbp.hostnotification = enable; 152 } else 153 card->options.sbp.hostnotification = enable; 154 155 mutex_unlock(&card->conf_mutex); 156 157 return rc ? rc : count; 158} 159 160static DEVICE_ATTR(bridge_hostnotify, 0644, 161 qeth_bridgeport_hostnotification_show, 162 qeth_bridgeport_hostnotification_store); 163 164static ssize_t qeth_bridgeport_reflect_show(struct device *dev, 165 struct device_attribute *attr, char *buf) 166{ 167 struct qeth_card *card = dev_get_drvdata(dev); 168 char *state; 169 170 if (!card) 171 return -EINVAL; 172 173 if (card->options.sbp.reflect_promisc) { 174 if (card->options.sbp.reflect_promisc_primary) 175 state = "primary"; 176 else 177 state = "secondary"; 178 } else 179 state = "none"; 180 181 return sprintf(buf, "%s\n", state); 182} 183 184static ssize_t qeth_bridgeport_reflect_store(struct device *dev, 185 struct device_attribute *attr, const char *buf, size_t count) 186{ 187 struct qeth_card *card = dev_get_drvdata(dev); 188 int enable, primary; 189 int rc = 0; 190 191 if (!card) 192 return -EINVAL; 193 194 if (sysfs_streq(buf, "none")) { 195 enable = 0; 196 primary = 0; 197 } else if (sysfs_streq(buf, "primary")) { 198 enable = 1; 199 primary = 1; 200 } else if (sysfs_streq(buf, "secondary")) { 201 enable = 1; 202 primary = 0; 203 } else 204 return -EINVAL; 205 206 mutex_lock(&card->conf_mutex); 207 208 if (card->options.sbp.role != QETH_SBP_ROLE_NONE) 209 rc = -EPERM; 210 else { 211 card->options.sbp.reflect_promisc = enable; 212 card->options.sbp.reflect_promisc_primary = primary; 213 rc = 0; 214 } 215 216 mutex_unlock(&card->conf_mutex); 217 218 return rc ? rc : count; 219} 220 221static DEVICE_ATTR(bridge_reflect_promisc, 0644, 222 qeth_bridgeport_reflect_show, 223 qeth_bridgeport_reflect_store); 224 225static struct attribute *qeth_l2_bridgeport_attrs[] = { 226 &dev_attr_bridge_role.attr, 227 &dev_attr_bridge_state.attr, 228 &dev_attr_bridge_hostnotify.attr, 229 &dev_attr_bridge_reflect_promisc.attr, 230 NULL, 231}; 232 233static struct attribute_group qeth_l2_bridgeport_attr_group = { 234 .attrs = qeth_l2_bridgeport_attrs, 235}; 236 237int qeth_l2_create_device_attributes(struct device *dev) 238{ 239 return sysfs_create_group(&dev->kobj, &qeth_l2_bridgeport_attr_group); 240} 241 242void qeth_l2_remove_device_attributes(struct device *dev) 243{ 244 sysfs_remove_group(&dev->kobj, &qeth_l2_bridgeport_attr_group); 245} 246 247/** 248 * qeth_l2_setup_bridgeport_attrs() - set/restore attrs when turning online. 249 * @card: qeth_card structure pointer 250 * 251 * Note: this function is called with conf_mutex held by the caller 252 */ 253void qeth_l2_setup_bridgeport_attrs(struct qeth_card *card) 254{ 255 int rc; 256 257 if (!card) 258 return; 259 if (!card->options.sbp.supported_funcs) 260 return; 261 if (card->options.sbp.role != QETH_SBP_ROLE_NONE) { 262 /* Conditional to avoid spurious error messages */ 263 qeth_bridgeport_setrole(card, card->options.sbp.role); 264 /* Let the callback function refresh the stored role value. */ 265 qeth_bridgeport_query_ports(card, 266 &card->options.sbp.role, NULL); 267 } 268 if (card->options.sbp.hostnotification) { 269 rc = qeth_bridgeport_an_set(card, 1); 270 if (rc) 271 card->options.sbp.hostnotification = 0; 272 } else 273 qeth_bridgeport_an_set(card, 0); 274} 275