]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/s390/net/qeth_l2_sys.c
s390/qeth: use kstrtobool() in qeth_bridgeport_hostnotification_store()
[mirror_ubuntu-bionic-kernel.git] / drivers / s390 / net / qeth_l2_sys.c
CommitLineData
b4d72c08
EC
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>
511c2445 8#include "qeth_core.h"
b4d72c08
EC
9#include "qeth_l2.h"
10
b4d72c08
EC
11static 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
caa1f0b1
HW
23 if (qeth_l2_vnicc_is_in_use(card))
24 return sprintf(buf, "n/a (VNIC characteristics)\n");
25
b4d72c08
EC
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
b4d72c08
EC
60 return rc;
61}
62
63static ssize_t qeth_bridge_port_role_show(struct device *dev,
64 struct device_attribute *attr, char *buf)
65{
caa1f0b1
HW
66 struct qeth_card *card = dev_get_drvdata(dev);
67
68 if (qeth_l2_vnicc_is_in_use(card))
69 return sprintf(buf, "n/a (VNIC characteristics)\n");
70
b4d72c08
EC
71 return qeth_bridge_port_role_state_show(dev, attr, buf, 0);
72}
73
74static ssize_t qeth_bridge_port_role_store(struct device *dev,
75 struct device_attribute *attr, const char *buf, size_t count)
76{
77 struct qeth_card *card = dev_get_drvdata(dev);
78 int rc = 0;
79 enum qeth_sbp_roles role;
80
81 if (!card)
82 return -EINVAL;
83 if (sysfs_streq(buf, "primary"))
84 role = QETH_SBP_ROLE_PRIMARY;
85 else if (sysfs_streq(buf, "secondary"))
86 role = QETH_SBP_ROLE_SECONDARY;
87 else if (sysfs_streq(buf, "none"))
88 role = QETH_SBP_ROLE_NONE;
89 else
90 return -EINVAL;
91
92 mutex_lock(&card->conf_mutex);
93
caa1f0b1
HW
94 if (qeth_l2_vnicc_is_in_use(card))
95 rc = -EBUSY;
96 else if (card->options.sbp.reflect_promisc)
97 /* Forbid direct manipulation */
ff1d9291
EC
98 rc = -EPERM;
99 else if (qeth_card_hw_is_reachable(card)) {
b4d72c08
EC
100 rc = qeth_bridgeport_setrole(card, role);
101 if (!rc)
102 card->options.sbp.role = role;
103 } else
104 card->options.sbp.role = role;
105
106 mutex_unlock(&card->conf_mutex);
107
108 return rc ? rc : count;
109}
110
111static DEVICE_ATTR(bridge_role, 0644, qeth_bridge_port_role_show,
112 qeth_bridge_port_role_store);
113
114static ssize_t qeth_bridge_port_state_show(struct device *dev,
115 struct device_attribute *attr, char *buf)
116{
caa1f0b1
HW
117 struct qeth_card *card = dev_get_drvdata(dev);
118
119 if (qeth_l2_vnicc_is_in_use(card))
120 return sprintf(buf, "n/a (VNIC characteristics)\n");
121
b4d72c08
EC
122 return qeth_bridge_port_role_state_show(dev, attr, buf, 1);
123}
124
248046ba 125static DEVICE_ATTR(bridge_state, 0444, qeth_bridge_port_state_show,
b4d72c08
EC
126 NULL);
127
9f48b9db
EC
128static ssize_t qeth_bridgeport_hostnotification_show(struct device *dev,
129 struct device_attribute *attr, char *buf)
130{
131 struct qeth_card *card = dev_get_drvdata(dev);
132 int enabled;
133
134 if (!card)
135 return -EINVAL;
136
caa1f0b1
HW
137 if (qeth_l2_vnicc_is_in_use(card))
138 return sprintf(buf, "n/a (VNIC characteristics)\n");
139
9f48b9db
EC
140 enabled = card->options.sbp.hostnotification;
141
9f48b9db
EC
142 return sprintf(buf, "%d\n", enabled);
143}
144
145static ssize_t qeth_bridgeport_hostnotification_store(struct device *dev,
146 struct device_attribute *attr, const char *buf, size_t count)
147{
148 struct qeth_card *card = dev_get_drvdata(dev);
025d0dfc
AS
149 bool enable;
150 int rc;
9f48b9db
EC
151
152 if (!card)
153 return -EINVAL;
154
025d0dfc
AS
155 rc = kstrtobool(buf, &enable);
156 if (rc)
157 return rc;
9f48b9db
EC
158
159 mutex_lock(&card->conf_mutex);
160
caa1f0b1
HW
161 if (qeth_l2_vnicc_is_in_use(card))
162 rc = -EBUSY;
163 else if (qeth_card_hw_is_reachable(card)) {
9f48b9db
EC
164 rc = qeth_bridgeport_an_set(card, enable);
165 if (!rc)
166 card->options.sbp.hostnotification = enable;
167 } else
168 card->options.sbp.hostnotification = enable;
169
170 mutex_unlock(&card->conf_mutex);
171
172 return rc ? rc : count;
173}
174
175static DEVICE_ATTR(bridge_hostnotify, 0644,
176 qeth_bridgeport_hostnotification_show,
177 qeth_bridgeport_hostnotification_store);
178
0db587b0
EC
179static ssize_t qeth_bridgeport_reflect_show(struct device *dev,
180 struct device_attribute *attr, char *buf)
181{
182 struct qeth_card *card = dev_get_drvdata(dev);
183 char *state;
184
185 if (!card)
186 return -EINVAL;
187
caa1f0b1
HW
188 if (qeth_l2_vnicc_is_in_use(card))
189 return sprintf(buf, "n/a (VNIC characteristics)\n");
190
0db587b0
EC
191 if (card->options.sbp.reflect_promisc) {
192 if (card->options.sbp.reflect_promisc_primary)
193 state = "primary";
194 else
195 state = "secondary";
196 } else
197 state = "none";
198
199 return sprintf(buf, "%s\n", state);
200}
201
202static ssize_t qeth_bridgeport_reflect_store(struct device *dev,
203 struct device_attribute *attr, const char *buf, size_t count)
204{
205 struct qeth_card *card = dev_get_drvdata(dev);
206 int enable, primary;
ff1d9291 207 int rc = 0;
0db587b0
EC
208
209 if (!card)
210 return -EINVAL;
211
212 if (sysfs_streq(buf, "none")) {
213 enable = 0;
214 primary = 0;
215 } else if (sysfs_streq(buf, "primary")) {
216 enable = 1;
217 primary = 1;
218 } else if (sysfs_streq(buf, "secondary")) {
219 enable = 1;
220 primary = 0;
221 } else
222 return -EINVAL;
223
224 mutex_lock(&card->conf_mutex);
225
caa1f0b1
HW
226 if (qeth_l2_vnicc_is_in_use(card))
227 rc = -EBUSY;
228 else if (card->options.sbp.role != QETH_SBP_ROLE_NONE)
ff1d9291
EC
229 rc = -EPERM;
230 else {
231 card->options.sbp.reflect_promisc = enable;
232 card->options.sbp.reflect_promisc_primary = primary;
233 rc = 0;
234 }
0db587b0
EC
235
236 mutex_unlock(&card->conf_mutex);
237
ff1d9291 238 return rc ? rc : count;
0db587b0
EC
239}
240
241static DEVICE_ATTR(bridge_reflect_promisc, 0644,
242 qeth_bridgeport_reflect_show,
243 qeth_bridgeport_reflect_store);
244
b4d72c08
EC
245static struct attribute *qeth_l2_bridgeport_attrs[] = {
246 &dev_attr_bridge_role.attr,
247 &dev_attr_bridge_state.attr,
9f48b9db 248 &dev_attr_bridge_hostnotify.attr,
0db587b0 249 &dev_attr_bridge_reflect_promisc.attr,
b4d72c08
EC
250 NULL,
251};
252
253static struct attribute_group qeth_l2_bridgeport_attr_group = {
254 .attrs = qeth_l2_bridgeport_attrs,
255};
256
b4d72c08
EC
257/**
258 * qeth_l2_setup_bridgeport_attrs() - set/restore attrs when turning online.
259 * @card: qeth_card structure pointer
260 *
261 * Note: this function is called with conf_mutex held by the caller
262 */
263void qeth_l2_setup_bridgeport_attrs(struct qeth_card *card)
264{
9f48b9db
EC
265 int rc;
266
b4d72c08
EC
267 if (!card)
268 return;
269 if (!card->options.sbp.supported_funcs)
270 return;
271 if (card->options.sbp.role != QETH_SBP_ROLE_NONE) {
272 /* Conditional to avoid spurious error messages */
273 qeth_bridgeport_setrole(card, card->options.sbp.role);
274 /* Let the callback function refresh the stored role value. */
275 qeth_bridgeport_query_ports(card,
276 &card->options.sbp.role, NULL);
277 }
9f48b9db
EC
278 if (card->options.sbp.hostnotification) {
279 rc = qeth_bridgeport_an_set(card, 1);
280 if (rc)
281 card->options.sbp.hostnotification = 0;
282 } else
283 qeth_bridgeport_an_set(card, 0);
b4d72c08 284}
2d2ebb3e 285
caa1f0b1
HW
286/* VNIC CHARS support */
287
288/* convert sysfs attr name to VNIC characteristic */
289static u32 qeth_l2_vnicc_sysfs_attr_to_char(const char *attr_name)
290{
291 if (sysfs_streq(attr_name, "flooding"))
292 return QETH_VNICC_FLOODING;
293 else if (sysfs_streq(attr_name, "mcast_flooding"))
294 return QETH_VNICC_MCAST_FLOODING;
295 else if (sysfs_streq(attr_name, "learning"))
296 return QETH_VNICC_LEARNING;
297 else if (sysfs_streq(attr_name, "takeover_setvmac"))
298 return QETH_VNICC_TAKEOVER_SETVMAC;
299 else if (sysfs_streq(attr_name, "takeover_learning"))
300 return QETH_VNICC_TAKEOVER_LEARNING;
301 else if (sysfs_streq(attr_name, "bridge_invisible"))
302 return QETH_VNICC_BRIDGE_INVISIBLE;
303 else if (sysfs_streq(attr_name, "rx_bcast"))
304 return QETH_VNICC_RX_BCAST;
305
306 return 0;
307}
308
349d13d5
HW
309/* get current timeout setting */
310static ssize_t qeth_vnicc_timeout_show(struct device *dev,
311 struct device_attribute *attr, char *buf)
312{
313 struct qeth_card *card = dev_get_drvdata(dev);
314 u32 timeout;
315 int rc;
316
317 if (!card)
318 return -EINVAL;
319
320 rc = qeth_l2_vnicc_get_timeout(card, &timeout);
321 if (rc == -EBUSY)
322 return sprintf(buf, "n/a (BridgePort)\n");
323 if (rc == -EOPNOTSUPP)
324 return sprintf(buf, "n/a\n");
325 return rc ? rc : sprintf(buf, "%d\n", timeout);
326}
327
328/* change timeout setting */
329static ssize_t qeth_vnicc_timeout_store(struct device *dev,
330 struct device_attribute *attr,
331 const char *buf, size_t count)
332{
333 struct qeth_card *card = dev_get_drvdata(dev);
334 u32 timeout;
335 int rc;
336
337 if (!card)
338 return -EINVAL;
339
340 rc = kstrtou32(buf, 10, &timeout);
341 if (rc)
342 return rc;
343
344 mutex_lock(&card->conf_mutex);
345 rc = qeth_l2_vnicc_set_timeout(card, timeout);
346 mutex_unlock(&card->conf_mutex);
347 return rc ? rc : count;
348}
349
caa1f0b1
HW
350/* get current setting of characteristic */
351static ssize_t qeth_vnicc_char_show(struct device *dev,
352 struct device_attribute *attr, char *buf)
353{
354 struct qeth_card *card = dev_get_drvdata(dev);
355 bool state;
356 u32 vnicc;
357 int rc;
358
359 if (!card)
360 return -EINVAL;
361
362 vnicc = qeth_l2_vnicc_sysfs_attr_to_char(attr->attr.name);
363 rc = qeth_l2_vnicc_get_state(card, vnicc, &state);
364
365 if (rc == -EBUSY)
366 return sprintf(buf, "n/a (BridgePort)\n");
367 if (rc == -EOPNOTSUPP)
368 return sprintf(buf, "n/a\n");
369 return rc ? rc : sprintf(buf, "%d\n", state);
370}
371
372/* change setting of characteristic */
373static ssize_t qeth_vnicc_char_store(struct device *dev,
374 struct device_attribute *attr,
375 const char *buf, size_t count)
376{
377 struct qeth_card *card = dev_get_drvdata(dev);
378 bool state;
379 u32 vnicc;
380 int rc;
381
382 if (!card)
383 return -EINVAL;
384
385 if (kstrtobool(buf, &state))
386 return -EINVAL;
387
388 vnicc = qeth_l2_vnicc_sysfs_attr_to_char(attr->attr.name);
389 mutex_lock(&card->conf_mutex);
390 rc = qeth_l2_vnicc_set_state(card, vnicc, state);
391 mutex_unlock(&card->conf_mutex);
392
393 return rc ? rc : count;
394}
395
396static DEVICE_ATTR(flooding, 0644, qeth_vnicc_char_show, qeth_vnicc_char_store);
397static DEVICE_ATTR(mcast_flooding, 0644, qeth_vnicc_char_show,
398 qeth_vnicc_char_store);
399static DEVICE_ATTR(learning, 0644, qeth_vnicc_char_show, qeth_vnicc_char_store);
349d13d5
HW
400static DEVICE_ATTR(learning_timeout, 0644, qeth_vnicc_timeout_show,
401 qeth_vnicc_timeout_store);
caa1f0b1
HW
402static DEVICE_ATTR(takeover_setvmac, 0644, qeth_vnicc_char_show,
403 qeth_vnicc_char_store);
404static DEVICE_ATTR(takeover_learning, 0644, qeth_vnicc_char_show,
405 qeth_vnicc_char_store);
406static DEVICE_ATTR(bridge_invisible, 0644, qeth_vnicc_char_show,
407 qeth_vnicc_char_store);
408static DEVICE_ATTR(rx_bcast, 0644, qeth_vnicc_char_show, qeth_vnicc_char_store);
409
410static struct attribute *qeth_l2_vnicc_attrs[] = {
411 &dev_attr_flooding.attr,
412 &dev_attr_mcast_flooding.attr,
413 &dev_attr_learning.attr,
349d13d5 414 &dev_attr_learning_timeout.attr,
caa1f0b1
HW
415 &dev_attr_takeover_setvmac.attr,
416 &dev_attr_takeover_learning.attr,
417 &dev_attr_bridge_invisible.attr,
418 &dev_attr_rx_bcast.attr,
419 NULL,
420};
421
422static struct attribute_group qeth_l2_vnicc_attr_group = {
423 .attrs = qeth_l2_vnicc_attrs,
424 .name = "vnicc",
425};
426
427static const struct attribute_group *qeth_l2_only_attr_groups[] = {
428 &qeth_l2_bridgeport_attr_group,
429 &qeth_l2_vnicc_attr_group,
430 NULL,
431};
432
433int qeth_l2_create_device_attributes(struct device *dev)
434{
435 return sysfs_create_groups(&dev->kobj, qeth_l2_only_attr_groups);
436}
437
438void qeth_l2_remove_device_attributes(struct device *dev)
439{
440 sysfs_remove_groups(&dev->kobj, qeth_l2_only_attr_groups);
441}
442
2d2ebb3e
JW
443const struct attribute_group *qeth_l2_attr_groups[] = {
444 &qeth_device_attr_group,
445 &qeth_device_blkt_group,
caa1f0b1 446 /* l2 specific, see qeth_l2_only_attr_groups: */
2d2ebb3e 447 &qeth_l2_bridgeport_attr_group,
caa1f0b1 448 &qeth_l2_vnicc_attr_group,
2d2ebb3e
JW
449 NULL,
450};