Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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 (!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	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
 61	return rc;
 62}
 63
 64static ssize_t qeth_bridge_port_role_show(struct device *dev,
 65				struct device_attribute *attr, char *buf)
 66{
 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
 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
 95	if (qeth_l2_vnicc_is_in_use(card))
 96		rc = -EBUSY;
 97	else if (card->options.sbp.reflect_promisc)
 98		/* Forbid direct manipulation */
 99		rc = -EPERM;
100	else if (qeth_card_hw_is_reachable(card)) {
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{
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
123	return qeth_bridge_port_role_state_show(dev, attr, buf, 1);
124}
125
126static DEVICE_ATTR(bridge_state, 0444, qeth_bridge_port_state_show,
127		   NULL);
128
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
138	if (qeth_l2_vnicc_is_in_use(card))
139		return sprintf(buf, "n/a (VNIC characteristics)\n");
140
141	enabled = card->options.sbp.hostnotification;
142
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);
150	bool enable;
151	int rc;
152
153	if (!card)
154		return -EINVAL;
155
156	rc = kstrtobool(buf, &enable);
157	if (rc)
158		return rc;
159
160	mutex_lock(&card->conf_mutex);
161
162	if (qeth_l2_vnicc_is_in_use(card))
163		rc = -EBUSY;
164	else if (qeth_card_hw_is_reachable(card)) {
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
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
189	if (qeth_l2_vnicc_is_in_use(card))
190		return sprintf(buf, "n/a (VNIC characteristics)\n");
191
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;
208	int rc = 0;
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
227	if (qeth_l2_vnicc_is_in_use(card))
228		rc = -EBUSY;
229	else if (card->options.sbp.role != QETH_SBP_ROLE_NONE)
230		rc = -EPERM;
231	else {
232		card->options.sbp.reflect_promisc = enable;
233		card->options.sbp.reflect_promisc_primary = primary;
234		rc = 0;
235	}
236
237	mutex_unlock(&card->conf_mutex);
238
239	return rc ? rc : count;
240}
241
242static DEVICE_ATTR(bridge_reflect_promisc, 0644,
243			qeth_bridgeport_reflect_show,
244			qeth_bridgeport_reflect_store);
245
246static struct attribute *qeth_l2_bridgeport_attrs[] = {
247	&dev_attr_bridge_role.attr,
248	&dev_attr_bridge_state.attr,
249	&dev_attr_bridge_hostnotify.attr,
250	&dev_attr_bridge_reflect_promisc.attr,
251	NULL,
252};
253
254static struct attribute_group qeth_l2_bridgeport_attr_group = {
255	.attrs = qeth_l2_bridgeport_attrs,
256};
257
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{
266	int rc;
267
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	}
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);
285}
286
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
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
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);
401static DEVICE_ATTR(learning_timeout, 0644, qeth_vnicc_timeout_show,
402		   qeth_vnicc_timeout_store);
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,
415	&dev_attr_learning_timeout.attr,
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
444const struct attribute_group *qeth_l2_attr_groups[] = {
445	&qeth_device_attr_group,
446	&qeth_device_blkt_group,
447	/* l2 specific, see qeth_l2_only_attr_groups: */
448	&qeth_l2_bridgeport_attr_group,
449	&qeth_l2_vnicc_attr_group,
450	NULL,
451};