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