blob: a553fbab17fc42966ce35866e06f5f737c69fcd8 [file] [log] [blame]
Eugene Crosserb4d72c02014-01-14 15:54:11 +01001/*
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>
Eugene Crosser511c2442014-09-02 08:20:17 +02008#include "qeth_core.h"
Eugene Crosserb4d72c02014-01-14 15:54:11 +01009#include "qeth_l2.h"
10
11#define QETH_DEVICE_ATTR(_id, _name, _mode, _show, _store) \
12struct device_attribute dev_attr_##_id = __ATTR(_name, _mode, _show, _store)
13
Eugene Crosserb4d72c02014-01-14 15:54:11 +010014static 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
Eugene Crosserb4d72c02014-01-14 15:54:11 +010026 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
Eugene Crosserb4d72c02014-01-14 15:54:11 +010060 return rc;
61}
62
63static 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
69static 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 (qeth_card_hw_is_reachable(card)) {
90 rc = qeth_bridgeport_setrole(card, role);
91 if (!rc)
92 card->options.sbp.role = role;
93 } else
94 card->options.sbp.role = role;
95
96 mutex_unlock(&card->conf_mutex);
97
98 return rc ? rc : count;
99}
100
101static DEVICE_ATTR(bridge_role, 0644, qeth_bridge_port_role_show,
102 qeth_bridge_port_role_store);
103
104static ssize_t qeth_bridge_port_state_show(struct device *dev,
105 struct device_attribute *attr, char *buf)
106{
107 return qeth_bridge_port_role_state_show(dev, attr, buf, 1);
108}
109
110static DEVICE_ATTR(bridge_state, 0644, qeth_bridge_port_state_show,
111 NULL);
112
Eugene Crosser9f48b9d2014-01-14 15:54:13 +0100113static ssize_t qeth_bridgeport_hostnotification_show(struct device *dev,
114 struct device_attribute *attr, char *buf)
115{
116 struct qeth_card *card = dev_get_drvdata(dev);
117 int enabled;
118
119 if (!card)
120 return -EINVAL;
121
Eugene Crosser9f48b9d2014-01-14 15:54:13 +0100122 enabled = card->options.sbp.hostnotification;
123
Eugene Crosser9f48b9d2014-01-14 15:54:13 +0100124 return sprintf(buf, "%d\n", enabled);
125}
126
127static ssize_t qeth_bridgeport_hostnotification_store(struct device *dev,
128 struct device_attribute *attr, const char *buf, size_t count)
129{
130 struct qeth_card *card = dev_get_drvdata(dev);
131 int rc = 0;
132 int enable;
133
134 if (!card)
135 return -EINVAL;
136
137 if (sysfs_streq(buf, "0"))
138 enable = 0;
139 else if (sysfs_streq(buf, "1"))
140 enable = 1;
141 else
142 return -EINVAL;
143
144 mutex_lock(&card->conf_mutex);
145
146 if (qeth_card_hw_is_reachable(card)) {
147 rc = qeth_bridgeport_an_set(card, enable);
148 if (!rc)
149 card->options.sbp.hostnotification = enable;
150 } else
151 card->options.sbp.hostnotification = enable;
152
153 mutex_unlock(&card->conf_mutex);
154
155 return rc ? rc : count;
156}
157
158static DEVICE_ATTR(bridge_hostnotify, 0644,
159 qeth_bridgeport_hostnotification_show,
160 qeth_bridgeport_hostnotification_store);
161
Eugene Crosser0db587b2015-05-18 14:27:55 +0200162static ssize_t qeth_bridgeport_reflect_show(struct device *dev,
163 struct device_attribute *attr, char *buf)
164{
165 struct qeth_card *card = dev_get_drvdata(dev);
166 char *state;
167
168 if (!card)
169 return -EINVAL;
170
171 if (card->options.sbp.reflect_promisc) {
172 if (card->options.sbp.reflect_promisc_primary)
173 state = "primary";
174 else
175 state = "secondary";
176 } else
177 state = "none";
178
179 return sprintf(buf, "%s\n", state);
180}
181
182static ssize_t qeth_bridgeport_reflect_store(struct device *dev,
183 struct device_attribute *attr, const char *buf, size_t count)
184{
185 struct qeth_card *card = dev_get_drvdata(dev);
186 int enable, primary;
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 card->options.sbp.reflect_promisc = enable;
206 card->options.sbp.reflect_promisc_primary = primary;
207
208 mutex_unlock(&card->conf_mutex);
209
210 return count;
211}
212
213static DEVICE_ATTR(bridge_reflect_promisc, 0644,
214 qeth_bridgeport_reflect_show,
215 qeth_bridgeport_reflect_store);
216
Eugene Crosserb4d72c02014-01-14 15:54:11 +0100217static struct attribute *qeth_l2_bridgeport_attrs[] = {
218 &dev_attr_bridge_role.attr,
219 &dev_attr_bridge_state.attr,
Eugene Crosser9f48b9d2014-01-14 15:54:13 +0100220 &dev_attr_bridge_hostnotify.attr,
Eugene Crosser0db587b2015-05-18 14:27:55 +0200221 &dev_attr_bridge_reflect_promisc.attr,
Eugene Crosserb4d72c02014-01-14 15:54:11 +0100222 NULL,
223};
224
225static struct attribute_group qeth_l2_bridgeport_attr_group = {
226 .attrs = qeth_l2_bridgeport_attrs,
227};
228
229int qeth_l2_create_device_attributes(struct device *dev)
230{
231 return sysfs_create_group(&dev->kobj, &qeth_l2_bridgeport_attr_group);
232}
233
234void qeth_l2_remove_device_attributes(struct device *dev)
235{
236 sysfs_remove_group(&dev->kobj, &qeth_l2_bridgeport_attr_group);
237}
238
239/**
240 * qeth_l2_setup_bridgeport_attrs() - set/restore attrs when turning online.
241 * @card: qeth_card structure pointer
242 *
243 * Note: this function is called with conf_mutex held by the caller
244 */
245void qeth_l2_setup_bridgeport_attrs(struct qeth_card *card)
246{
Eugene Crosser9f48b9d2014-01-14 15:54:13 +0100247 int rc;
248
Eugene Crosserb4d72c02014-01-14 15:54:11 +0100249 if (!card)
250 return;
251 if (!card->options.sbp.supported_funcs)
252 return;
253 if (card->options.sbp.role != QETH_SBP_ROLE_NONE) {
254 /* Conditional to avoid spurious error messages */
255 qeth_bridgeport_setrole(card, card->options.sbp.role);
256 /* Let the callback function refresh the stored role value. */
257 qeth_bridgeport_query_ports(card,
258 &card->options.sbp.role, NULL);
259 }
Eugene Crosser9f48b9d2014-01-14 15:54:13 +0100260 if (card->options.sbp.hostnotification) {
261 rc = qeth_bridgeport_an_set(card, 1);
262 if (rc)
263 card->options.sbp.hostnotification = 0;
264 } else
265 qeth_bridgeport_an_set(card, 0);
Eugene Crosserb4d72c02014-01-14 15:54:11 +0100266}