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