Merge branch 'next-smack' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris...
[sfrench/cifs-2.6.git] / drivers / s390 / net / qeth_l2_sys.c
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_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
64 static 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
75 static 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
112 static DEVICE_ATTR(bridge_role, 0644, qeth_bridge_port_role_show,
113                    qeth_bridge_port_role_store);
114
115 static 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
126 static DEVICE_ATTR(bridge_state, 0444, qeth_bridge_port_state_show,
127                    NULL);
128
129 static 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
146 static 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
176 static DEVICE_ATTR(bridge_hostnotify, 0644,
177                         qeth_bridgeport_hostnotification_show,
178                         qeth_bridgeport_hostnotification_store);
179
180 static 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
203 static 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
242 static DEVICE_ATTR(bridge_reflect_promisc, 0644,
243                         qeth_bridgeport_reflect_show,
244                         qeth_bridgeport_reflect_store);
245
246 static 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
254 static 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  */
264 void 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 */
290 static 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 */
311 static 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 */
330 static 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 */
352 static 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 */
374 static 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
397 static DEVICE_ATTR(flooding, 0644, qeth_vnicc_char_show, qeth_vnicc_char_store);
398 static DEVICE_ATTR(mcast_flooding, 0644, qeth_vnicc_char_show,
399                    qeth_vnicc_char_store);
400 static DEVICE_ATTR(learning, 0644, qeth_vnicc_char_show, qeth_vnicc_char_store);
401 static DEVICE_ATTR(learning_timeout, 0644, qeth_vnicc_timeout_show,
402                    qeth_vnicc_timeout_store);
403 static DEVICE_ATTR(takeover_setvmac, 0644, qeth_vnicc_char_show,
404                    qeth_vnicc_char_store);
405 static DEVICE_ATTR(takeover_learning, 0644, qeth_vnicc_char_show,
406                    qeth_vnicc_char_store);
407 static DEVICE_ATTR(bridge_invisible, 0644, qeth_vnicc_char_show,
408                    qeth_vnicc_char_store);
409 static DEVICE_ATTR(rx_bcast, 0644, qeth_vnicc_char_show, qeth_vnicc_char_store);
410
411 static 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
423 static struct attribute_group qeth_l2_vnicc_attr_group = {
424         .attrs = qeth_l2_vnicc_attrs,
425         .name = "vnicc",
426 };
427
428 static 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
434 int qeth_l2_create_device_attributes(struct device *dev)
435 {
436         return sysfs_create_groups(&dev->kobj, qeth_l2_only_attr_groups);
437 }
438
439 void qeth_l2_remove_device_attributes(struct device *dev)
440 {
441         sysfs_remove_groups(&dev->kobj, qeth_l2_only_attr_groups);
442 }
443
444 const 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 };