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
qeth_bridge_port_role_state_show(struct device * dev,struct device_attribute * attr,char * buf,int show_state)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 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
qeth_bridge_port_role_show(struct device * dev,struct device_attribute * attr,char * buf)63 static 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
qeth_bridge_port_role_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)69 static 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
103 static DEVICE_ATTR(bridge_role, 0644, qeth_bridge_port_role_show,
104 qeth_bridge_port_role_store);
105
qeth_bridge_port_state_show(struct device * dev,struct device_attribute * attr,char * buf)106 static 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
112 static DEVICE_ATTR(bridge_state, 0444, qeth_bridge_port_state_show,
113 NULL);
114
qeth_bridgeport_hostnotification_show(struct device * dev,struct device_attribute * attr,char * buf)115 static 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
qeth_bridgeport_hostnotification_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)129 static 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
160 static DEVICE_ATTR(bridge_hostnotify, 0644,
161 qeth_bridgeport_hostnotification_show,
162 qeth_bridgeport_hostnotification_store);
163
qeth_bridgeport_reflect_show(struct device * dev,struct device_attribute * attr,char * buf)164 static 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
qeth_bridgeport_reflect_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)184 static 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
221 static DEVICE_ATTR(bridge_reflect_promisc, 0644,
222 qeth_bridgeport_reflect_show,
223 qeth_bridgeport_reflect_store);
224
225 static 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
233 static struct attribute_group qeth_l2_bridgeport_attr_group = {
234 .attrs = qeth_l2_bridgeport_attrs,
235 };
236
qeth_l2_create_device_attributes(struct device * dev)237 int qeth_l2_create_device_attributes(struct device *dev)
238 {
239 return sysfs_create_group(&dev->kobj, &qeth_l2_bridgeport_attr_group);
240 }
241
qeth_l2_remove_device_attributes(struct device * dev)242 void 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 */
qeth_l2_setup_bridgeport_attrs(struct qeth_card * card)253 void 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
276 const struct attribute_group *qeth_l2_attr_groups[] = {
277 &qeth_device_attr_group,
278 &qeth_device_blkt_group,
279 /* l2 specific, see l2_{create,remove}_device_attributes(): */
280 &qeth_l2_bridgeport_attr_group,
281 NULL,
282 };
283