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