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