xref: /linux/drivers/net/ethernet/cisco/enic/enic_pp.c (revision daa2be74b1b2302004945b2a5e32424e177cc7da)
1 // SPDX-License-Identifier: GPL-2.0-only
2 // Copyright 2011 Cisco Systems, Inc.  All rights reserved.
3 
4 #include <linux/kernel.h>
5 #include <linux/string.h>
6 #include <linux/errno.h>
7 #include <linux/types.h>
8 #include <linux/netdevice.h>
9 #include <linux/etherdevice.h>
10 #include <linux/rtnetlink.h>
11 #include <net/ip.h>
12 
13 #include "vnic_vic.h"
14 #include "enic_res.h"
15 #include "enic.h"
16 #include "enic_dev.h"
17 #include "enic_pp.h"
18 
19 /*
20  * Checks validity of vf index that came in
21  * port profile request
22  */
23 int enic_is_valid_pp_vf(struct enic *enic, int vf, int *err)
24 {
25 	if (vf != PORT_SELF_VF) {
26 #ifdef CONFIG_PCI_IOV
27 		if (enic_sriov_enabled(enic)) {
28 			if (vf < 0 || vf >= enic->num_vfs) {
29 				*err = -EINVAL;
30 				goto err_out;
31 			}
32 		} else {
33 			*err = -EOPNOTSUPP;
34 			goto err_out;
35 		}
36 #else
37 		*err = -EOPNOTSUPP;
38 		goto err_out;
39 #endif
40 	}
41 
42 	if (vf == PORT_SELF_VF && !enic_is_dynamic(enic)) {
43 		*err = -EOPNOTSUPP;
44 		goto err_out;
45 	}
46 
47 	*err = 0;
48 	return 1;
49 
50 err_out:
51 	return 0;
52 }
53 
54 static int enic_set_port_profile(struct enic *enic, int vf)
55 {
56 	struct net_device *netdev = enic->netdev;
57 	struct enic_port_profile *pp;
58 	struct vic_provinfo *vp;
59 	const u8 oui[3] = VIC_PROVINFO_CISCO_OUI;
60 	const __be16 os_type = htons(VIC_GENERIC_PROV_OS_TYPE_LINUX);
61 	const u8 *client_mac;
62 	char uuid_str[38];
63 	char client_mac_str[18];
64 	int err;
65 
66 	ENIC_PP_BY_INDEX(enic, vf, pp, &err);
67 	if (err)
68 		return err;
69 
70 	if (!(pp->set & ENIC_SET_NAME) || !strlen(pp->name))
71 		return -EINVAL;
72 
73 	vp = vic_provinfo_alloc(GFP_KERNEL, oui,
74 		VIC_PROVINFO_GENERIC_TYPE);
75 	if (!vp)
76 		return -ENOMEM;
77 
78 	VIC_PROVINFO_ADD_TLV(vp,
79 		VIC_GENERIC_PROV_TLV_PORT_PROFILE_NAME_STR,
80 		strlen(pp->name) + 1, pp->name);
81 
82 	if (!is_zero_ether_addr(pp->mac_addr)) {
83 		client_mac = pp->mac_addr;
84 	} else if (vf == PORT_SELF_VF) {
85 		client_mac = netdev->dev_addr;
86 	} else {
87 		netdev_err(netdev, "Cannot find pp mac address "
88 			"for VF %d\n", vf);
89 		err = -EINVAL;
90 		goto add_tlv_failure;
91 	}
92 
93 	VIC_PROVINFO_ADD_TLV(vp,
94 		VIC_GENERIC_PROV_TLV_CLIENT_MAC_ADDR,
95 		ETH_ALEN, client_mac);
96 
97 	snprintf(client_mac_str, sizeof(client_mac_str), "%pM", client_mac);
98 	VIC_PROVINFO_ADD_TLV(vp,
99 		VIC_GENERIC_PROV_TLV_CLUSTER_PORT_UUID_STR,
100 		sizeof(client_mac_str), client_mac_str);
101 
102 	if (pp->set & ENIC_SET_INSTANCE) {
103 		sprintf(uuid_str, "%pUB", pp->instance_uuid);
104 		VIC_PROVINFO_ADD_TLV(vp,
105 			VIC_GENERIC_PROV_TLV_CLIENT_UUID_STR,
106 			sizeof(uuid_str), uuid_str);
107 	}
108 
109 	if (pp->set & ENIC_SET_HOST) {
110 		sprintf(uuid_str, "%pUB", pp->host_uuid);
111 		VIC_PROVINFO_ADD_TLV(vp,
112 			VIC_GENERIC_PROV_TLV_HOST_UUID_STR,
113 			sizeof(uuid_str), uuid_str);
114 	}
115 
116 	VIC_PROVINFO_ADD_TLV(vp,
117 		VIC_GENERIC_PROV_TLV_OS_TYPE,
118 		sizeof(os_type), &os_type);
119 
120 	ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_init_prov2, (u8 *)vp,
121 		vic_provinfo_size(vp));
122 	err = enic_dev_status_to_errno(err);
123 
124 add_tlv_failure:
125 	vic_provinfo_free(vp);
126 
127 	return err;
128 }
129 
130 static int enic_unset_port_profile(struct enic *enic, int vf)
131 {
132 	int err;
133 
134 	ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_deinit);
135 	if (err)
136 		return enic_dev_status_to_errno(err);
137 
138 	if (vf == PORT_SELF_VF)
139 		enic_reset_addr_lists(enic);
140 
141 	return 0;
142 }
143 
144 static int enic_are_pp_different(struct enic_port_profile *pp1,
145 		struct enic_port_profile *pp2)
146 {
147 	return strcmp(pp1->name, pp2->name) | !!memcmp(pp1->instance_uuid,
148 		pp2->instance_uuid, PORT_UUID_MAX) |
149 		!!memcmp(pp1->host_uuid, pp2->host_uuid, PORT_UUID_MAX) |
150 		!ether_addr_equal(pp1->mac_addr, pp2->mac_addr);
151 }
152 
153 static int enic_pp_preassociate(struct enic *enic, int vf,
154 	struct enic_port_profile *prev_pp, int *restore_pp);
155 static int enic_pp_disassociate(struct enic *enic, int vf,
156 	struct enic_port_profile *prev_pp, int *restore_pp);
157 static int enic_pp_preassociate_rr(struct enic *enic, int vf,
158 	struct enic_port_profile *prev_pp, int *restore_pp);
159 static int enic_pp_associate(struct enic *enic, int vf,
160 	struct enic_port_profile *prev_pp, int *restore_pp);
161 
162 static int (*enic_pp_handlers[])(struct enic *enic, int vf,
163 		struct enic_port_profile *prev_state,
164 		int *restore_pp) = {
165 	[PORT_REQUEST_PREASSOCIATE]	= enic_pp_preassociate,
166 	[PORT_REQUEST_PREASSOCIATE_RR]	= enic_pp_preassociate_rr,
167 	[PORT_REQUEST_ASSOCIATE]	= enic_pp_associate,
168 	[PORT_REQUEST_DISASSOCIATE]	= enic_pp_disassociate,
169 };
170 
171 static const int enic_pp_handlers_count =
172 			ARRAY_SIZE(enic_pp_handlers);
173 
174 static int enic_pp_preassociate(struct enic *enic, int vf,
175 	struct enic_port_profile *prev_pp, int *restore_pp)
176 {
177 	return -EOPNOTSUPP;
178 }
179 
180 static int enic_pp_disassociate(struct enic *enic, int vf,
181 	struct enic_port_profile *prev_pp, int *restore_pp)
182 {
183 	struct net_device *netdev = enic->netdev;
184 	struct enic_port_profile *pp;
185 	int err;
186 
187 	ENIC_PP_BY_INDEX(enic, vf, pp, &err);
188 	if (err)
189 		return err;
190 
191 	/* Deregister mac addresses */
192 	if (!is_zero_ether_addr(pp->mac_addr))
193 		ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_del_addr,
194 			pp->mac_addr);
195 	else if (vf == PORT_SELF_VF && !is_zero_ether_addr(netdev->dev_addr))
196 		ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_del_addr,
197 			netdev->dev_addr);
198 
199 	return enic_unset_port_profile(enic, vf);
200 }
201 
202 static int enic_pp_preassociate_rr(struct enic *enic, int vf,
203 	struct enic_port_profile *prev_pp, int *restore_pp)
204 {
205 	struct enic_port_profile *pp;
206 	int err;
207 	int active = 0;
208 
209 	ENIC_PP_BY_INDEX(enic, vf, pp, &err);
210 	if (err)
211 		return err;
212 
213 	if (pp->request != PORT_REQUEST_ASSOCIATE) {
214 		/* If pre-associate is not part of an associate.
215 		We always disassociate first */
216 		err = enic_pp_handlers[PORT_REQUEST_DISASSOCIATE](enic, vf,
217 			prev_pp, restore_pp);
218 		if (err)
219 			return err;
220 
221 		*restore_pp = 0;
222 	}
223 
224 	*restore_pp = 0;
225 
226 	err = enic_set_port_profile(enic, vf);
227 	if (err)
228 		return err;
229 
230 	/* If pre-associate is not part of an associate. */
231 	if (pp->request != PORT_REQUEST_ASSOCIATE) {
232 		/* Enable device as standby */
233 		ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_enable2,
234 			active);
235 		err = enic_dev_status_to_errno(err);
236 	}
237 
238 	return err;
239 }
240 
241 static int enic_pp_associate(struct enic *enic, int vf,
242 	struct enic_port_profile *prev_pp, int *restore_pp)
243 {
244 	struct net_device *netdev = enic->netdev;
245 	struct enic_port_profile *pp;
246 	int err;
247 	int active = 1;
248 
249 	ENIC_PP_BY_INDEX(enic, vf, pp, &err);
250 	if (err)
251 		return err;
252 
253 	/* Check if a pre-associate was called before */
254 	if (prev_pp->request != PORT_REQUEST_PREASSOCIATE_RR ||
255 		(prev_pp->request == PORT_REQUEST_PREASSOCIATE_RR &&
256 			enic_are_pp_different(prev_pp, pp))) {
257 		err = enic_pp_handlers[PORT_REQUEST_DISASSOCIATE](
258 			enic, vf, prev_pp, restore_pp);
259 		if (err)
260 			return err;
261 
262 		*restore_pp = 0;
263 	}
264 
265 	err = enic_pp_handlers[PORT_REQUEST_PREASSOCIATE_RR](
266 			enic, vf, prev_pp, restore_pp);
267 	if (err)
268 		return err;
269 
270 	*restore_pp = 0;
271 
272 	/* Enable device as active */
273 	ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_enable2, active);
274 	err = enic_dev_status_to_errno(err);
275 	if (err)
276 		return err;
277 
278 	/* Register mac address */
279 	if (!is_zero_ether_addr(pp->mac_addr))
280 		ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_add_addr,
281 			pp->mac_addr);
282 	else if (vf == PORT_SELF_VF && !is_zero_ether_addr(netdev->dev_addr))
283 		ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic, vnic_dev_add_addr,
284 			netdev->dev_addr);
285 
286 	return 0;
287 }
288 
289 int enic_process_set_pp_request(struct enic *enic, int vf,
290 	struct enic_port_profile *prev_pp, int *restore_pp)
291 {
292 	struct enic_port_profile *pp;
293 	int err;
294 
295 	ENIC_PP_BY_INDEX(enic, vf, pp, &err);
296 	if (err)
297 		return err;
298 
299 	if (pp->request >= enic_pp_handlers_count
300 		|| !enic_pp_handlers[pp->request])
301 		return -EOPNOTSUPP;
302 
303 	return enic_pp_handlers[pp->request](enic, vf, prev_pp, restore_pp);
304 }
305 
306 int enic_process_get_pp_request(struct enic *enic, int vf,
307 	int request, u16 *response)
308 {
309 	int err, status = ERR_SUCCESS;
310 
311 	switch (request) {
312 
313 	case PORT_REQUEST_PREASSOCIATE_RR:
314 	case PORT_REQUEST_ASSOCIATE:
315 		ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic,
316 			vnic_dev_enable2_done, &status);
317 		break;
318 
319 	case PORT_REQUEST_DISASSOCIATE:
320 		ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic,
321 			vnic_dev_deinit_done, &status);
322 		break;
323 
324 	default:
325 		return -EINVAL;
326 	}
327 
328 	if (err)
329 		status = err;
330 
331 	switch (status) {
332 	case ERR_SUCCESS:
333 		*response = PORT_PROFILE_RESPONSE_SUCCESS;
334 		break;
335 	case ERR_EINVAL:
336 		*response = PORT_PROFILE_RESPONSE_INVALID;
337 		break;
338 	case ERR_EBADSTATE:
339 		*response = PORT_PROFILE_RESPONSE_BADSTATE;
340 		break;
341 	case ERR_ENOMEM:
342 		*response = PORT_PROFILE_RESPONSE_INSUFFICIENT_RESOURCES;
343 		break;
344 	case ERR_EINPROGRESS:
345 		*response = PORT_PROFILE_RESPONSE_INPROGRESS;
346 		break;
347 	default:
348 		*response = PORT_PROFILE_RESPONSE_ERROR;
349 		break;
350 	}
351 
352 	return 0;
353 }
354