1// 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 (!qeth_bridgeport_allowed(card))
22		return sysfs_emit(buf, "n/a (VNIC characteristics)\n");
23
24	mutex_lock(&card->sbp_lock);
25	if (qeth_card_hw_is_reachable(card) &&
26					card->options.sbp.supported_funcs)
27		rc = qeth_bridgeport_query_ports(card,
28			&card->options.sbp.role, &state);
29	if (!rc) {
30		if (show_state)
31			switch (state) {
32			case QETH_SBP_STATE_INACTIVE:
33				word = "inactive"; break;
34			case QETH_SBP_STATE_STANDBY:
35				word = "standby"; break;
36			case QETH_SBP_STATE_ACTIVE:
37				word = "active"; break;
38			default:
39				rc = -EIO;
40			}
41		else
42			switch (card->options.sbp.role) {
43			case QETH_SBP_ROLE_NONE:
44				word = "none"; break;
45			case QETH_SBP_ROLE_PRIMARY:
46				word = "primary"; break;
47			case QETH_SBP_ROLE_SECONDARY:
48				word = "secondary"; break;
49			default:
50				rc = -EIO;
51			}
52		if (rc)
53			QETH_CARD_TEXT_(card, 2, "SBP%02x:%02x",
54				card->options.sbp.role, state);
55		else
56			rc = sysfs_emit(buf, "%s\n", word);
57	}
58	mutex_unlock(&card->sbp_lock);
59
60	return rc;
61}
62
63static ssize_t qeth_bridge_port_role_show(struct device *dev,
64				struct device_attribute *attr, char *buf)
65{
66	struct qeth_card *card = dev_get_drvdata(dev);
67
68	if (!qeth_bridgeport_allowed(card))
69		return sysfs_emit(buf, "n/a (VNIC characteristics)\n");
70
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 (sysfs_streq(buf, "primary"))
82		role = QETH_SBP_ROLE_PRIMARY;
83	else if (sysfs_streq(buf, "secondary"))
84		role = QETH_SBP_ROLE_SECONDARY;
85	else if (sysfs_streq(buf, "none"))
86		role = QETH_SBP_ROLE_NONE;
87	else
88		return -EINVAL;
89
90	mutex_lock(&card->conf_mutex);
91	mutex_lock(&card->sbp_lock);
92
93	if (!qeth_bridgeport_allowed(card))
94		rc = -EBUSY;
95	else if (card->options.sbp.reflect_promisc)
96		/* Forbid direct manipulation */
97		rc = -EPERM;
98	else 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->sbp_lock);
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{
117	struct qeth_card *card = dev_get_drvdata(dev);
118
119	if (!qeth_bridgeport_allowed(card))
120		return sysfs_emit(buf, "n/a (VNIC characteristics)\n");
121
122	return qeth_bridge_port_role_state_show(dev, attr, buf, 1);
123}
124
125static DEVICE_ATTR(bridge_state, 0444, qeth_bridge_port_state_show,
126		   NULL);
127
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 (!qeth_bridgeport_allowed(card))
135		return sysfs_emit(buf, "n/a (VNIC characteristics)\n");
136
137	enabled = card->options.sbp.hostnotification;
138
139	return sysfs_emit(buf, "%d\n", enabled);
140}
141
142static ssize_t qeth_bridgeport_hostnotification_store(struct device *dev,
143		struct device_attribute *attr, const char *buf, size_t count)
144{
145	struct qeth_card *card = dev_get_drvdata(dev);
146	bool enable;
147	int rc;
148
149	rc = kstrtobool(buf, &enable);
150	if (rc)
151		return rc;
152
153	mutex_lock(&card->conf_mutex);
154	mutex_lock(&card->sbp_lock);
155
156	if (!qeth_bridgeport_allowed(card))
157		rc = -EBUSY;
158	else if (qeth_card_hw_is_reachable(card)) {
159		rc = qeth_bridgeport_an_set(card, enable);
160		/* sbp_lock ensures ordering vs notifications-stopped events */
161		if (!rc)
162			card->options.sbp.hostnotification = enable;
163	} else
164		card->options.sbp.hostnotification = enable;
165
166	mutex_unlock(&card->sbp_lock);
167	mutex_unlock(&card->conf_mutex);
168
169	return rc ? rc : count;
170}
171
172static DEVICE_ATTR(bridge_hostnotify, 0644,
173			qeth_bridgeport_hostnotification_show,
174			qeth_bridgeport_hostnotification_store);
175
176static ssize_t qeth_bridgeport_reflect_show(struct device *dev,
177				struct device_attribute *attr, char *buf)
178{
179	struct qeth_card *card = dev_get_drvdata(dev);
180	char *state;
181
182	if (!qeth_bridgeport_allowed(card))
183		return sysfs_emit(buf, "n/a (VNIC characteristics)\n");
184
185	if (card->options.sbp.reflect_promisc) {
186		if (card->options.sbp.reflect_promisc_primary)
187			state = "primary";
188		else
189			state = "secondary";
190	} else
191		state = "none";
192
193	return sysfs_emit(buf, "%s\n", state);
194}
195
196static ssize_t qeth_bridgeport_reflect_store(struct device *dev,
197		struct device_attribute *attr, const char *buf, size_t count)
198{
199	struct qeth_card *card = dev_get_drvdata(dev);
200	int enable, primary;
201	int rc = 0;
202
203	if (sysfs_streq(buf, "none")) {
204		enable = 0;
205		primary = 0;
206	} else if (sysfs_streq(buf, "primary")) {
207		enable = 1;
208		primary = 1;
209	} else if (sysfs_streq(buf, "secondary")) {
210		enable = 1;
211		primary = 0;
212	} else
213		return -EINVAL;
214
215	mutex_lock(&card->conf_mutex);
216	mutex_lock(&card->sbp_lock);
217
218	if (!qeth_bridgeport_allowed(card))
219		rc = -EBUSY;
220	else if (card->options.sbp.role != QETH_SBP_ROLE_NONE)
221		rc = -EPERM;
222	else {
223		card->options.sbp.reflect_promisc = enable;
224		card->options.sbp.reflect_promisc_primary = primary;
225		rc = 0;
226	}
227
228	mutex_unlock(&card->sbp_lock);
229	mutex_unlock(&card->conf_mutex);
230
231	return rc ? rc : count;
232}
233
234static DEVICE_ATTR(bridge_reflect_promisc, 0644,
235			qeth_bridgeport_reflect_show,
236			qeth_bridgeport_reflect_store);
237
238static struct attribute *qeth_l2_bridgeport_attrs[] = {
239	&dev_attr_bridge_role.attr,
240	&dev_attr_bridge_state.attr,
241	&dev_attr_bridge_hostnotify.attr,
242	&dev_attr_bridge_reflect_promisc.attr,
243	NULL,
244};
245
246static struct attribute_group qeth_l2_bridgeport_attr_group = {
247	.attrs = qeth_l2_bridgeport_attrs,
248};
249
250/* VNIC CHARS support */
251
252/* convert sysfs attr name to VNIC characteristic */
253static u32 qeth_l2_vnicc_sysfs_attr_to_char(const char *attr_name)
254{
255	if (sysfs_streq(attr_name, "flooding"))
256		return QETH_VNICC_FLOODING;
257	else if (sysfs_streq(attr_name, "mcast_flooding"))
258		return QETH_VNICC_MCAST_FLOODING;
259	else if (sysfs_streq(attr_name, "learning"))
260		return QETH_VNICC_LEARNING;
261	else if (sysfs_streq(attr_name, "takeover_setvmac"))
262		return QETH_VNICC_TAKEOVER_SETVMAC;
263	else if (sysfs_streq(attr_name, "takeover_learning"))
264		return QETH_VNICC_TAKEOVER_LEARNING;
265	else if (sysfs_streq(attr_name, "bridge_invisible"))
266		return QETH_VNICC_BRIDGE_INVISIBLE;
267	else if (sysfs_streq(attr_name, "rx_bcast"))
268		return QETH_VNICC_RX_BCAST;
269
270	return 0;
271}
272
273/* get current timeout setting */
274static ssize_t qeth_vnicc_timeout_show(struct device *dev,
275				       struct device_attribute *attr, char *buf)
276{
277	struct qeth_card *card = dev_get_drvdata(dev);
278	u32 timeout;
279	int rc;
280
281	rc = qeth_l2_vnicc_get_timeout(card, &timeout);
282	if (rc == -EBUSY)
283		return sysfs_emit(buf, "n/a (BridgePort)\n");
284	if (rc == -EOPNOTSUPP)
285		return sysfs_emit(buf, "n/a\n");
286	return rc ? rc : sysfs_emit(buf, "%d\n", timeout);
287}
288
289/* change timeout setting */
290static ssize_t qeth_vnicc_timeout_store(struct device *dev,
291					struct device_attribute *attr,
292					const char *buf, size_t count)
293{
294	struct qeth_card *card = dev_get_drvdata(dev);
295	u32 timeout;
296	int rc;
297
298	rc = kstrtou32(buf, 10, &timeout);
299	if (rc)
300		return rc;
301
302	mutex_lock(&card->conf_mutex);
303	rc = qeth_l2_vnicc_set_timeout(card, timeout);
304	mutex_unlock(&card->conf_mutex);
305	return rc ? rc : count;
306}
307
308/* get current setting of characteristic */
309static ssize_t qeth_vnicc_char_show(struct device *dev,
310				    struct device_attribute *attr, char *buf)
311{
312	struct qeth_card *card = dev_get_drvdata(dev);
313	bool state;
314	u32 vnicc;
315	int rc;
316
317	vnicc = qeth_l2_vnicc_sysfs_attr_to_char(attr->attr.name);
318	rc = qeth_l2_vnicc_get_state(card, vnicc, &state);
319
320	if (rc == -EBUSY)
321		return sysfs_emit(buf, "n/a (BridgePort)\n");
322	if (rc == -EOPNOTSUPP)
323		return sysfs_emit(buf, "n/a\n");
324	return rc ? rc : sysfs_emit(buf, "%d\n", state);
325}
326
327/* change setting of characteristic */
328static ssize_t qeth_vnicc_char_store(struct device *dev,
329				     struct device_attribute *attr,
330				     const char *buf, size_t count)
331{
332	struct qeth_card *card = dev_get_drvdata(dev);
333	bool state;
334	u32 vnicc;
335	int rc;
336
337	if (kstrtobool(buf, &state))
338		return -EINVAL;
339
340	vnicc = qeth_l2_vnicc_sysfs_attr_to_char(attr->attr.name);
341	mutex_lock(&card->conf_mutex);
342	rc = qeth_l2_vnicc_set_state(card, vnicc, state);
343	mutex_unlock(&card->conf_mutex);
344
345	return rc ? rc : count;
346}
347
348static DEVICE_ATTR(flooding, 0644, qeth_vnicc_char_show, qeth_vnicc_char_store);
349static DEVICE_ATTR(mcast_flooding, 0644, qeth_vnicc_char_show,
350		   qeth_vnicc_char_store);
351static DEVICE_ATTR(learning, 0644, qeth_vnicc_char_show, qeth_vnicc_char_store);
352static DEVICE_ATTR(learning_timeout, 0644, qeth_vnicc_timeout_show,
353		   qeth_vnicc_timeout_store);
354static DEVICE_ATTR(takeover_setvmac, 0644, qeth_vnicc_char_show,
355		   qeth_vnicc_char_store);
356static DEVICE_ATTR(takeover_learning, 0644, qeth_vnicc_char_show,
357		   qeth_vnicc_char_store);
358static DEVICE_ATTR(bridge_invisible, 0644, qeth_vnicc_char_show,
359		   qeth_vnicc_char_store);
360static DEVICE_ATTR(rx_bcast, 0644, qeth_vnicc_char_show, qeth_vnicc_char_store);
361
362static struct attribute *qeth_l2_vnicc_attrs[] = {
363	&dev_attr_flooding.attr,
364	&dev_attr_mcast_flooding.attr,
365	&dev_attr_learning.attr,
366	&dev_attr_learning_timeout.attr,
367	&dev_attr_takeover_setvmac.attr,
368	&dev_attr_takeover_learning.attr,
369	&dev_attr_bridge_invisible.attr,
370	&dev_attr_rx_bcast.attr,
371	NULL,
372};
373
374static struct attribute_group qeth_l2_vnicc_attr_group = {
375	.attrs = qeth_l2_vnicc_attrs,
376	.name = "vnicc",
377};
378
379const struct attribute_group *qeth_l2_attr_groups[] = {
380	&qeth_l2_bridgeport_attr_group,
381	&qeth_l2_vnicc_attr_group,
382	NULL,
383};
384