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) \ 12 struct device_attribute dev_attr_##_id = __ATTR(_name, _mode, _show, _store) 13 14 static 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 mutex_lock(&card->conf_mutex); 27 28 if (qeth_card_hw_is_reachable(card) && 29 card->options.sbp.supported_funcs) 30 rc = qeth_bridgeport_query_ports(card, 31 &card->options.sbp.role, &state); 32 if (!rc) { 33 if (show_state) 34 switch (state) { 35 case QETH_SBP_STATE_INACTIVE: 36 word = "inactive"; break; 37 case QETH_SBP_STATE_STANDBY: 38 word = "standby"; break; 39 case QETH_SBP_STATE_ACTIVE: 40 word = "active"; break; 41 default: 42 rc = -EIO; 43 } 44 else 45 switch (card->options.sbp.role) { 46 case QETH_SBP_ROLE_NONE: 47 word = "none"; break; 48 case QETH_SBP_ROLE_PRIMARY: 49 word = "primary"; break; 50 case QETH_SBP_ROLE_SECONDARY: 51 word = "secondary"; break; 52 default: 53 rc = -EIO; 54 } 55 if (rc) 56 QETH_CARD_TEXT_(card, 2, "SBP%02x:%02x", 57 card->options.sbp.role, state); 58 else 59 rc = sprintf(buf, "%s\n", word); 60 } 61 62 mutex_unlock(&card->conf_mutex); 63 64 return rc; 65 } 66 67 static ssize_t qeth_bridge_port_role_show(struct device *dev, 68 struct device_attribute *attr, char *buf) 69 { 70 return qeth_bridge_port_role_state_show(dev, attr, buf, 0); 71 } 72 73 static ssize_t qeth_bridge_port_role_store(struct device *dev, 74 struct device_attribute *attr, const char *buf, size_t count) 75 { 76 struct qeth_card *card = dev_get_drvdata(dev); 77 int rc = 0; 78 enum qeth_sbp_roles role; 79 80 if (!card) 81 return -EINVAL; 82 if (sysfs_streq(buf, "primary")) 83 role = QETH_SBP_ROLE_PRIMARY; 84 else if (sysfs_streq(buf, "secondary")) 85 role = QETH_SBP_ROLE_SECONDARY; 86 else if (sysfs_streq(buf, "none")) 87 role = QETH_SBP_ROLE_NONE; 88 else 89 return -EINVAL; 90 91 mutex_lock(&card->conf_mutex); 92 93 if (qeth_card_hw_is_reachable(card)) { 94 rc = qeth_bridgeport_setrole(card, role); 95 if (!rc) 96 card->options.sbp.role = role; 97 } else 98 card->options.sbp.role = role; 99 100 mutex_unlock(&card->conf_mutex); 101 102 return rc ? rc : count; 103 } 104 105 static DEVICE_ATTR(bridge_role, 0644, qeth_bridge_port_role_show, 106 qeth_bridge_port_role_store); 107 108 static ssize_t qeth_bridge_port_state_show(struct device *dev, 109 struct device_attribute *attr, char *buf) 110 { 111 return qeth_bridge_port_role_state_show(dev, attr, buf, 1); 112 } 113 114 static DEVICE_ATTR(bridge_state, 0644, qeth_bridge_port_state_show, 115 NULL); 116 117 static ssize_t qeth_bridgeport_hostnotification_show(struct device *dev, 118 struct device_attribute *attr, char *buf) 119 { 120 struct qeth_card *card = dev_get_drvdata(dev); 121 int enabled; 122 123 if (!card) 124 return -EINVAL; 125 126 mutex_lock(&card->conf_mutex); 127 128 enabled = card->options.sbp.hostnotification; 129 130 mutex_unlock(&card->conf_mutex); 131 132 return sprintf(buf, "%d\n", enabled); 133 } 134 135 static ssize_t qeth_bridgeport_hostnotification_store(struct device *dev, 136 struct device_attribute *attr, const char *buf, size_t count) 137 { 138 struct qeth_card *card = dev_get_drvdata(dev); 139 int rc = 0; 140 int enable; 141 142 if (!card) 143 return -EINVAL; 144 145 if (sysfs_streq(buf, "0")) 146 enable = 0; 147 else if (sysfs_streq(buf, "1")) 148 enable = 1; 149 else 150 return -EINVAL; 151 152 mutex_lock(&card->conf_mutex); 153 154 if (qeth_card_hw_is_reachable(card)) { 155 rc = qeth_bridgeport_an_set(card, enable); 156 if (!rc) 157 card->options.sbp.hostnotification = enable; 158 } else 159 card->options.sbp.hostnotification = enable; 160 161 mutex_unlock(&card->conf_mutex); 162 163 return rc ? rc : count; 164 } 165 166 static DEVICE_ATTR(bridge_hostnotify, 0644, 167 qeth_bridgeport_hostnotification_show, 168 qeth_bridgeport_hostnotification_store); 169 170 static struct attribute *qeth_l2_bridgeport_attrs[] = { 171 &dev_attr_bridge_role.attr, 172 &dev_attr_bridge_state.attr, 173 &dev_attr_bridge_hostnotify.attr, 174 NULL, 175 }; 176 177 static struct attribute_group qeth_l2_bridgeport_attr_group = { 178 .attrs = qeth_l2_bridgeport_attrs, 179 }; 180 181 int qeth_l2_create_device_attributes(struct device *dev) 182 { 183 return sysfs_create_group(&dev->kobj, &qeth_l2_bridgeport_attr_group); 184 } 185 186 void qeth_l2_remove_device_attributes(struct device *dev) 187 { 188 sysfs_remove_group(&dev->kobj, &qeth_l2_bridgeport_attr_group); 189 } 190 191 /** 192 * qeth_l2_setup_bridgeport_attrs() - set/restore attrs when turning online. 193 * @card: qeth_card structure pointer 194 * 195 * Note: this function is called with conf_mutex held by the caller 196 */ 197 void qeth_l2_setup_bridgeport_attrs(struct qeth_card *card) 198 { 199 int rc; 200 201 if (!card) 202 return; 203 if (!card->options.sbp.supported_funcs) 204 return; 205 if (card->options.sbp.role != QETH_SBP_ROLE_NONE) { 206 /* Conditional to avoid spurious error messages */ 207 qeth_bridgeport_setrole(card, card->options.sbp.role); 208 /* Let the callback function refresh the stored role value. */ 209 qeth_bridgeport_query_ports(card, 210 &card->options.sbp.role, NULL); 211 } 212 if (card->options.sbp.hostnotification) { 213 rc = qeth_bridgeport_an_set(card, 1); 214 if (rc) 215 card->options.sbp.hostnotification = 0; 216 } else 217 qeth_bridgeport_an_set(card, 0); 218 } 219