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