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