xref: /openbmc/linux/drivers/s390/net/qeth_l2_sys.c (revision b24413180f5600bcb3bb70fbed5cf186b60864bd)
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 
12 static 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_card_hw_is_reachable(card) &&
25 					card->options.sbp.supported_funcs)
26 		rc = qeth_bridgeport_query_ports(card,
27 			&card->options.sbp.role, &state);
28 	if (!rc) {
29 		if (show_state)
30 			switch (state) {
31 			case QETH_SBP_STATE_INACTIVE:
32 				word = "inactive"; break;
33 			case QETH_SBP_STATE_STANDBY:
34 				word = "standby"; break;
35 			case QETH_SBP_STATE_ACTIVE:
36 				word = "active"; break;
37 			default:
38 				rc = -EIO;
39 			}
40 		else
41 			switch (card->options.sbp.role) {
42 			case QETH_SBP_ROLE_NONE:
43 				word = "none"; break;
44 			case QETH_SBP_ROLE_PRIMARY:
45 				word = "primary"; break;
46 			case QETH_SBP_ROLE_SECONDARY:
47 				word = "secondary"; break;
48 			default:
49 				rc = -EIO;
50 			}
51 		if (rc)
52 			QETH_CARD_TEXT_(card, 2, "SBP%02x:%02x",
53 				card->options.sbp.role, state);
54 		else
55 			rc = sprintf(buf, "%s\n", word);
56 	}
57 
58 	return rc;
59 }
60 
61 static ssize_t qeth_bridge_port_role_show(struct device *dev,
62 				struct device_attribute *attr, char *buf)
63 {
64 	return qeth_bridge_port_role_state_show(dev, attr, buf, 0);
65 }
66 
67 static ssize_t qeth_bridge_port_role_store(struct device *dev,
68 		struct device_attribute *attr, const char *buf, size_t count)
69 {
70 	struct qeth_card *card = dev_get_drvdata(dev);
71 	int rc = 0;
72 	enum qeth_sbp_roles role;
73 
74 	if (!card)
75 		return -EINVAL;
76 	if (sysfs_streq(buf, "primary"))
77 		role = QETH_SBP_ROLE_PRIMARY;
78 	else if (sysfs_streq(buf, "secondary"))
79 		role = QETH_SBP_ROLE_SECONDARY;
80 	else if (sysfs_streq(buf, "none"))
81 		role = QETH_SBP_ROLE_NONE;
82 	else
83 		return -EINVAL;
84 
85 	mutex_lock(&card->conf_mutex);
86 
87 	if (card->options.sbp.reflect_promisc) /* Forbid direct manipulation */
88 		rc = -EPERM;
89 	else if (qeth_card_hw_is_reachable(card)) {
90 		rc = qeth_bridgeport_setrole(card, role);
91 		if (!rc)
92 			card->options.sbp.role = role;
93 	} else
94 		card->options.sbp.role = role;
95 
96 	mutex_unlock(&card->conf_mutex);
97 
98 	return rc ? rc : count;
99 }
100 
101 static DEVICE_ATTR(bridge_role, 0644, qeth_bridge_port_role_show,
102 		   qeth_bridge_port_role_store);
103 
104 static ssize_t qeth_bridge_port_state_show(struct device *dev,
105 				struct device_attribute *attr, char *buf)
106 {
107 	return qeth_bridge_port_role_state_show(dev, attr, buf, 1);
108 }
109 
110 static DEVICE_ATTR(bridge_state, 0444, qeth_bridge_port_state_show,
111 		   NULL);
112 
113 static ssize_t qeth_bridgeport_hostnotification_show(struct device *dev,
114 				struct device_attribute *attr, char *buf)
115 {
116 	struct qeth_card *card = dev_get_drvdata(dev);
117 	int enabled;
118 
119 	if (!card)
120 		return -EINVAL;
121 
122 	enabled = card->options.sbp.hostnotification;
123 
124 	return sprintf(buf, "%d\n", enabled);
125 }
126 
127 static ssize_t qeth_bridgeport_hostnotification_store(struct device *dev,
128 		struct device_attribute *attr, const char *buf, size_t count)
129 {
130 	struct qeth_card *card = dev_get_drvdata(dev);
131 	int rc = 0;
132 	int enable;
133 
134 	if (!card)
135 		return -EINVAL;
136 
137 	if (sysfs_streq(buf, "0"))
138 		enable = 0;
139 	else if (sysfs_streq(buf, "1"))
140 		enable = 1;
141 	else
142 		return -EINVAL;
143 
144 	mutex_lock(&card->conf_mutex);
145 
146 	if (qeth_card_hw_is_reachable(card)) {
147 		rc = qeth_bridgeport_an_set(card, enable);
148 		if (!rc)
149 			card->options.sbp.hostnotification = enable;
150 	} else
151 		card->options.sbp.hostnotification = enable;
152 
153 	mutex_unlock(&card->conf_mutex);
154 
155 	return rc ? rc : count;
156 }
157 
158 static DEVICE_ATTR(bridge_hostnotify, 0644,
159 			qeth_bridgeport_hostnotification_show,
160 			qeth_bridgeport_hostnotification_store);
161 
162 static ssize_t qeth_bridgeport_reflect_show(struct device *dev,
163 				struct device_attribute *attr, char *buf)
164 {
165 	struct qeth_card *card = dev_get_drvdata(dev);
166 	char *state;
167 
168 	if (!card)
169 		return -EINVAL;
170 
171 	if (card->options.sbp.reflect_promisc) {
172 		if (card->options.sbp.reflect_promisc_primary)
173 			state = "primary";
174 		else
175 			state = "secondary";
176 	} else
177 		state = "none";
178 
179 	return sprintf(buf, "%s\n", state);
180 }
181 
182 static ssize_t qeth_bridgeport_reflect_store(struct device *dev,
183 		struct device_attribute *attr, const char *buf, size_t count)
184 {
185 	struct qeth_card *card = dev_get_drvdata(dev);
186 	int enable, primary;
187 	int rc = 0;
188 
189 	if (!card)
190 		return -EINVAL;
191 
192 	if (sysfs_streq(buf, "none")) {
193 		enable = 0;
194 		primary = 0;
195 	} else if (sysfs_streq(buf, "primary")) {
196 		enable = 1;
197 		primary = 1;
198 	} else if (sysfs_streq(buf, "secondary")) {
199 		enable = 1;
200 		primary = 0;
201 	} else
202 		return -EINVAL;
203 
204 	mutex_lock(&card->conf_mutex);
205 
206 	if (card->options.sbp.role != QETH_SBP_ROLE_NONE)
207 		rc = -EPERM;
208 	else {
209 		card->options.sbp.reflect_promisc = enable;
210 		card->options.sbp.reflect_promisc_primary = primary;
211 		rc = 0;
212 	}
213 
214 	mutex_unlock(&card->conf_mutex);
215 
216 	return rc ? rc : count;
217 }
218 
219 static DEVICE_ATTR(bridge_reflect_promisc, 0644,
220 			qeth_bridgeport_reflect_show,
221 			qeth_bridgeport_reflect_store);
222 
223 static struct attribute *qeth_l2_bridgeport_attrs[] = {
224 	&dev_attr_bridge_role.attr,
225 	&dev_attr_bridge_state.attr,
226 	&dev_attr_bridge_hostnotify.attr,
227 	&dev_attr_bridge_reflect_promisc.attr,
228 	NULL,
229 };
230 
231 static struct attribute_group qeth_l2_bridgeport_attr_group = {
232 	.attrs = qeth_l2_bridgeport_attrs,
233 };
234 
235 int qeth_l2_create_device_attributes(struct device *dev)
236 {
237 	return sysfs_create_group(&dev->kobj, &qeth_l2_bridgeport_attr_group);
238 }
239 
240 void qeth_l2_remove_device_attributes(struct device *dev)
241 {
242 	sysfs_remove_group(&dev->kobj, &qeth_l2_bridgeport_attr_group);
243 }
244 
245 /**
246  * qeth_l2_setup_bridgeport_attrs() - set/restore attrs when turning online.
247  * @card:			      qeth_card structure pointer
248  *
249  * Note: this function is called with conf_mutex held by the caller
250  */
251 void qeth_l2_setup_bridgeport_attrs(struct qeth_card *card)
252 {
253 	int rc;
254 
255 	if (!card)
256 		return;
257 	if (!card->options.sbp.supported_funcs)
258 		return;
259 	if (card->options.sbp.role != QETH_SBP_ROLE_NONE) {
260 		/* Conditional to avoid spurious error messages */
261 		qeth_bridgeport_setrole(card, card->options.sbp.role);
262 		/* Let the callback function refresh the stored role value. */
263 		qeth_bridgeport_query_ports(card,
264 			&card->options.sbp.role, NULL);
265 	}
266 	if (card->options.sbp.hostnotification) {
267 		rc = qeth_bridgeport_an_set(card, 1);
268 		if (rc)
269 			card->options.sbp.hostnotification = 0;
270 	} else
271 		qeth_bridgeport_an_set(card, 0);
272 }
273 
274 const struct attribute_group *qeth_l2_attr_groups[] = {
275 	&qeth_device_attr_group,
276 	&qeth_device_blkt_group,
277 	/* l2 specific, see l2_{create,remove}_device_attributes(): */
278 	&qeth_l2_bridgeport_attr_group,
279 	NULL,
280 };
281