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