]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - drivers/s390/net/qeth_l2_sys.c
Merge remote-tracking branch 'regulator/fix/max77802' into regulator-linus
[mirror_ubuntu-artful-kernel.git] / drivers / s390 / net / qeth_l2_sys.c
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 };