xref: /dpdk/drivers/common/sfc_efx/base/efx_mae.c (revision 97b914f4e715565d53d38ac6e04815b9be5e58a9)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  *
3  * Copyright(c) 2019-2021 Xilinx, Inc.
4  */
5 
6 #include "efx.h"
7 #include "efx_impl.h"
8 
9 
10 #if EFSYS_OPT_MAE
11 
12 static	__checkReturn			efx_rc_t
13 efx_mae_get_capabilities(
14 	__in				efx_nic_t *enp)
15 {
16 	efx_mcdi_req_t req;
17 	EFX_MCDI_DECLARE_BUF(payload,
18 	    MC_CMD_MAE_GET_CAPS_IN_LEN,
19 	    MC_CMD_MAE_GET_CAPS_OUT_LEN);
20 	struct efx_mae_s *maep = enp->en_maep;
21 	efx_rc_t rc;
22 
23 	req.emr_cmd = MC_CMD_MAE_GET_CAPS;
24 	req.emr_in_buf = payload;
25 	req.emr_in_length = MC_CMD_MAE_GET_CAPS_IN_LEN;
26 	req.emr_out_buf = payload;
27 	req.emr_out_length = MC_CMD_MAE_GET_CAPS_OUT_LEN;
28 
29 	efx_mcdi_execute(enp, &req);
30 
31 	if (req.emr_rc != 0) {
32 		rc = req.emr_rc;
33 		goto fail1;
34 	}
35 
36 	if (req.emr_out_length_used < MC_CMD_MAE_GET_CAPS_OUT_LEN) {
37 		rc = EMSGSIZE;
38 		goto fail2;
39 	}
40 
41 	maep->em_max_n_outer_prios =
42 	    MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_OUTER_PRIOS);
43 
44 	maep->em_max_n_action_prios =
45 	    MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_ACTION_PRIOS);
46 
47 	maep->em_encap_types_supported = 0;
48 
49 	if (MCDI_OUT_DWORD_FIELD(req, MAE_GET_CAPS_OUT_ENCAP_TYPES_SUPPORTED,
50 	    MAE_GET_CAPS_OUT_ENCAP_TYPE_VXLAN) != 0) {
51 		maep->em_encap_types_supported |=
52 		    (1U << EFX_TUNNEL_PROTOCOL_VXLAN);
53 	}
54 
55 	if (MCDI_OUT_DWORD_FIELD(req, MAE_GET_CAPS_OUT_ENCAP_TYPES_SUPPORTED,
56 	    MAE_GET_CAPS_OUT_ENCAP_TYPE_GENEVE) != 0) {
57 		maep->em_encap_types_supported |=
58 		    (1U << EFX_TUNNEL_PROTOCOL_GENEVE);
59 	}
60 
61 	if (MCDI_OUT_DWORD_FIELD(req, MAE_GET_CAPS_OUT_ENCAP_TYPES_SUPPORTED,
62 	    MAE_GET_CAPS_OUT_ENCAP_TYPE_NVGRE) != 0) {
63 		maep->em_encap_types_supported |=
64 		    (1U << EFX_TUNNEL_PROTOCOL_NVGRE);
65 	}
66 
67 	maep->em_max_nfields =
68 	    MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_MATCH_FIELD_COUNT);
69 
70 	maep->em_max_ncounters =
71 	    MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_COUNTERS);
72 
73 	return (0);
74 
75 fail2:
76 	EFSYS_PROBE(fail2);
77 fail1:
78 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
79 	return (rc);
80 }
81 
82 static	__checkReturn			efx_rc_t
83 efx_mae_get_outer_rule_caps(
84 	__in				efx_nic_t *enp,
85 	__in				unsigned int field_ncaps,
86 	__out_ecount(field_ncaps)	efx_mae_field_cap_t *field_caps)
87 {
88 	efx_mcdi_req_t req;
89 	EFX_MCDI_DECLARE_BUF(payload,
90 	    MC_CMD_MAE_GET_OR_CAPS_IN_LEN,
91 	    MC_CMD_MAE_GET_OR_CAPS_OUT_LENMAX_MCDI2);
92 	unsigned int mcdi_field_ncaps;
93 	unsigned int i;
94 	efx_rc_t rc;
95 
96 	if (MC_CMD_MAE_GET_OR_CAPS_OUT_LEN(field_ncaps) >
97 	    MC_CMD_MAE_GET_OR_CAPS_OUT_LENMAX_MCDI2) {
98 		rc = EINVAL;
99 		goto fail1;
100 	}
101 
102 	req.emr_cmd = MC_CMD_MAE_GET_OR_CAPS;
103 	req.emr_in_buf = payload;
104 	req.emr_in_length = MC_CMD_MAE_GET_OR_CAPS_IN_LEN;
105 	req.emr_out_buf = payload;
106 	req.emr_out_length = MC_CMD_MAE_GET_OR_CAPS_OUT_LEN(field_ncaps);
107 
108 	efx_mcdi_execute(enp, &req);
109 
110 	if (req.emr_rc != 0) {
111 		rc = req.emr_rc;
112 		goto fail2;
113 	}
114 
115 	if (req.emr_out_length_used < MC_CMD_MAE_GET_OR_CAPS_OUT_LENMIN) {
116 		rc = EMSGSIZE;
117 		goto fail3;
118 	}
119 
120 	mcdi_field_ncaps = MCDI_OUT_DWORD(req, MAE_GET_OR_CAPS_OUT_COUNT);
121 
122 	if (req.emr_out_length_used <
123 	    MC_CMD_MAE_GET_OR_CAPS_OUT_LEN(mcdi_field_ncaps)) {
124 		rc = EMSGSIZE;
125 		goto fail4;
126 	}
127 
128 	if (mcdi_field_ncaps > field_ncaps) {
129 		rc = EMSGSIZE;
130 		goto fail5;
131 	}
132 
133 	for (i = 0; i < mcdi_field_ncaps; ++i) {
134 		uint32_t match_flag;
135 		uint32_t mask_flag;
136 
137 		field_caps[i].emfc_support = MCDI_OUT_INDEXED_DWORD_FIELD(req,
138 		    MAE_GET_OR_CAPS_OUT_FIELD_FLAGS, i,
139 		    MAE_FIELD_FLAGS_SUPPORT_STATUS);
140 
141 		match_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req,
142 		    MAE_GET_OR_CAPS_OUT_FIELD_FLAGS, i,
143 		    MAE_FIELD_FLAGS_MATCH_AFFECTS_CLASS);
144 
145 		field_caps[i].emfc_match_affects_class =
146 		    (match_flag != 0) ? B_TRUE : B_FALSE;
147 
148 		mask_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req,
149 		    MAE_GET_OR_CAPS_OUT_FIELD_FLAGS, i,
150 		    MAE_FIELD_FLAGS_MASK_AFFECTS_CLASS);
151 
152 		field_caps[i].emfc_mask_affects_class =
153 		    (mask_flag != 0) ? B_TRUE : B_FALSE;
154 	}
155 
156 	return (0);
157 
158 fail5:
159 	EFSYS_PROBE(fail5);
160 fail4:
161 	EFSYS_PROBE(fail4);
162 fail3:
163 	EFSYS_PROBE(fail3);
164 fail2:
165 	EFSYS_PROBE(fail2);
166 fail1:
167 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
168 	return (rc);
169 }
170 
171 static	__checkReturn			efx_rc_t
172 efx_mae_get_action_rule_caps(
173 	__in				efx_nic_t *enp,
174 	__in				unsigned int field_ncaps,
175 	__out_ecount(field_ncaps)	efx_mae_field_cap_t *field_caps)
176 {
177 	efx_mcdi_req_t req;
178 	EFX_MCDI_DECLARE_BUF(payload,
179 	    MC_CMD_MAE_GET_AR_CAPS_IN_LEN,
180 	    MC_CMD_MAE_GET_AR_CAPS_OUT_LENMAX_MCDI2);
181 	unsigned int mcdi_field_ncaps;
182 	unsigned int i;
183 	efx_rc_t rc;
184 
185 	if (MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(field_ncaps) >
186 	    MC_CMD_MAE_GET_AR_CAPS_OUT_LENMAX_MCDI2) {
187 		rc = EINVAL;
188 		goto fail1;
189 	}
190 
191 	req.emr_cmd = MC_CMD_MAE_GET_AR_CAPS;
192 	req.emr_in_buf = payload;
193 	req.emr_in_length = MC_CMD_MAE_GET_AR_CAPS_IN_LEN;
194 	req.emr_out_buf = payload;
195 	req.emr_out_length = MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(field_ncaps);
196 
197 	efx_mcdi_execute(enp, &req);
198 
199 	if (req.emr_rc != 0) {
200 		rc = req.emr_rc;
201 		goto fail2;
202 	}
203 
204 	if (req.emr_out_length_used < MC_CMD_MAE_GET_AR_CAPS_OUT_LENMIN) {
205 		rc = EMSGSIZE;
206 		goto fail3;
207 	}
208 
209 	mcdi_field_ncaps = MCDI_OUT_DWORD(req, MAE_GET_AR_CAPS_OUT_COUNT);
210 
211 	if (req.emr_out_length_used <
212 	    MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(mcdi_field_ncaps)) {
213 		rc = EMSGSIZE;
214 		goto fail4;
215 	}
216 
217 	if (mcdi_field_ncaps > field_ncaps) {
218 		rc = EMSGSIZE;
219 		goto fail5;
220 	}
221 
222 	for (i = 0; i < mcdi_field_ncaps; ++i) {
223 		uint32_t match_flag;
224 		uint32_t mask_flag;
225 
226 		field_caps[i].emfc_support = MCDI_OUT_INDEXED_DWORD_FIELD(req,
227 		    MAE_GET_AR_CAPS_OUT_FIELD_FLAGS, i,
228 		    MAE_FIELD_FLAGS_SUPPORT_STATUS);
229 
230 		match_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req,
231 		    MAE_GET_AR_CAPS_OUT_FIELD_FLAGS, i,
232 		    MAE_FIELD_FLAGS_MATCH_AFFECTS_CLASS);
233 
234 		field_caps[i].emfc_match_affects_class =
235 		    (match_flag != 0) ? B_TRUE : B_FALSE;
236 
237 		mask_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req,
238 		    MAE_GET_AR_CAPS_OUT_FIELD_FLAGS, i,
239 		    MAE_FIELD_FLAGS_MASK_AFFECTS_CLASS);
240 
241 		field_caps[i].emfc_mask_affects_class =
242 		    (mask_flag != 0) ? B_TRUE : B_FALSE;
243 	}
244 
245 	return (0);
246 
247 fail5:
248 	EFSYS_PROBE(fail5);
249 fail4:
250 	EFSYS_PROBE(fail4);
251 fail3:
252 	EFSYS_PROBE(fail3);
253 fail2:
254 	EFSYS_PROBE(fail2);
255 fail1:
256 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
257 	return (rc);
258 }
259 
260 	__checkReturn			efx_rc_t
261 efx_mae_init(
262 	__in				efx_nic_t *enp)
263 {
264 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
265 	efx_mae_field_cap_t *or_fcaps;
266 	size_t or_fcaps_size;
267 	efx_mae_field_cap_t *ar_fcaps;
268 	size_t ar_fcaps_size;
269 	efx_mae_t *maep;
270 	efx_rc_t rc;
271 
272 	if (encp->enc_mae_supported == B_FALSE) {
273 		rc = ENOTSUP;
274 		goto fail1;
275 	}
276 
277 	EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*maep), maep);
278 	if (maep == NULL) {
279 		rc = ENOMEM;
280 		goto fail2;
281 	}
282 
283 	enp->en_maep = maep;
284 
285 	rc = efx_mae_get_capabilities(enp);
286 	if (rc != 0)
287 		goto fail3;
288 
289 	or_fcaps_size = maep->em_max_nfields * sizeof (*or_fcaps);
290 	EFSYS_KMEM_ALLOC(enp->en_esip, or_fcaps_size, or_fcaps);
291 	if (or_fcaps == NULL) {
292 		rc = ENOMEM;
293 		goto fail4;
294 	}
295 
296 	maep->em_outer_rule_field_caps_size = or_fcaps_size;
297 	maep->em_outer_rule_field_caps = or_fcaps;
298 
299 	rc = efx_mae_get_outer_rule_caps(enp, maep->em_max_nfields, or_fcaps);
300 	if (rc != 0)
301 		goto fail5;
302 
303 	ar_fcaps_size = maep->em_max_nfields * sizeof (*ar_fcaps);
304 	EFSYS_KMEM_ALLOC(enp->en_esip, ar_fcaps_size, ar_fcaps);
305 	if (ar_fcaps == NULL) {
306 		rc = ENOMEM;
307 		goto fail6;
308 	}
309 
310 	maep->em_action_rule_field_caps_size = ar_fcaps_size;
311 	maep->em_action_rule_field_caps = ar_fcaps;
312 
313 	rc = efx_mae_get_action_rule_caps(enp, maep->em_max_nfields, ar_fcaps);
314 	if (rc != 0)
315 		goto fail7;
316 
317 	return (0);
318 
319 fail7:
320 	EFSYS_PROBE(fail5);
321 	EFSYS_KMEM_FREE(enp->en_esip, ar_fcaps_size, ar_fcaps);
322 fail6:
323 	EFSYS_PROBE(fail4);
324 fail5:
325 	EFSYS_PROBE(fail5);
326 	EFSYS_KMEM_FREE(enp->en_esip, or_fcaps_size, or_fcaps);
327 fail4:
328 	EFSYS_PROBE(fail4);
329 fail3:
330 	EFSYS_PROBE(fail3);
331 	EFSYS_KMEM_FREE(enp->en_esip, sizeof (struct efx_mae_s), enp->en_maep);
332 	enp->en_maep = NULL;
333 fail2:
334 	EFSYS_PROBE(fail2);
335 fail1:
336 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
337 	return (rc);
338 }
339 
340 					void
341 efx_mae_fini(
342 	__in				efx_nic_t *enp)
343 {
344 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
345 	efx_mae_t *maep = enp->en_maep;
346 
347 	if (encp->enc_mae_supported == B_FALSE)
348 		return;
349 
350 	EFSYS_KMEM_FREE(enp->en_esip, maep->em_action_rule_field_caps_size,
351 	    maep->em_action_rule_field_caps);
352 	EFSYS_KMEM_FREE(enp->en_esip, maep->em_outer_rule_field_caps_size,
353 	    maep->em_outer_rule_field_caps);
354 	EFSYS_KMEM_FREE(enp->en_esip, sizeof (*maep), maep);
355 	enp->en_maep = NULL;
356 }
357 
358 	__checkReturn			efx_rc_t
359 efx_mae_get_limits(
360 	__in				efx_nic_t *enp,
361 	__out				efx_mae_limits_t *emlp)
362 {
363 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
364 	struct efx_mae_s *maep = enp->en_maep;
365 	efx_rc_t rc;
366 
367 	if (encp->enc_mae_supported == B_FALSE) {
368 		rc = ENOTSUP;
369 		goto fail1;
370 	}
371 
372 	emlp->eml_max_n_outer_prios = maep->em_max_n_outer_prios;
373 	emlp->eml_max_n_action_prios = maep->em_max_n_action_prios;
374 	emlp->eml_encap_types_supported = maep->em_encap_types_supported;
375 	emlp->eml_encap_header_size_limit =
376 	    MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_MAXNUM_MCDI2;
377 	emlp->eml_max_n_counters = maep->em_max_ncounters;
378 
379 	return (0);
380 
381 fail1:
382 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
383 	return (rc);
384 }
385 
386 	__checkReturn			efx_rc_t
387 efx_mae_match_spec_init(
388 	__in				efx_nic_t *enp,
389 	__in				efx_mae_rule_type_t type,
390 	__in				uint32_t prio,
391 	__out				efx_mae_match_spec_t **specp)
392 {
393 	efx_mae_match_spec_t *spec;
394 	efx_rc_t rc;
395 
396 	switch (type) {
397 	case EFX_MAE_RULE_OUTER:
398 		break;
399 	case EFX_MAE_RULE_ACTION:
400 		break;
401 	default:
402 		rc = ENOTSUP;
403 		goto fail1;
404 	}
405 
406 	EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), spec);
407 	if (spec == NULL) {
408 		rc = ENOMEM;
409 		goto fail2;
410 	}
411 
412 	spec->emms_type = type;
413 	spec->emms_prio = prio;
414 
415 	*specp = spec;
416 
417 	return (0);
418 
419 fail2:
420 	EFSYS_PROBE(fail2);
421 fail1:
422 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
423 	return (rc);
424 }
425 
426 					void
427 efx_mae_match_spec_fini(
428 	__in				efx_nic_t *enp,
429 	__in				efx_mae_match_spec_t *spec)
430 {
431 	EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec);
432 }
433 
434 /* Named identifiers which are valid indices to efx_mae_field_cap_t */
435 typedef enum efx_mae_field_cap_id_e {
436 	EFX_MAE_FIELD_ID_INGRESS_MPORT_SELECTOR = MAE_FIELD_INGRESS_PORT,
437 	EFX_MAE_FIELD_ID_ETHER_TYPE_BE = MAE_FIELD_ETHER_TYPE,
438 	EFX_MAE_FIELD_ID_ETH_SADDR_BE = MAE_FIELD_ETH_SADDR,
439 	EFX_MAE_FIELD_ID_ETH_DADDR_BE = MAE_FIELD_ETH_DADDR,
440 	EFX_MAE_FIELD_ID_VLAN0_TCI_BE = MAE_FIELD_VLAN0_TCI,
441 	EFX_MAE_FIELD_ID_VLAN0_PROTO_BE = MAE_FIELD_VLAN0_PROTO,
442 	EFX_MAE_FIELD_ID_VLAN1_TCI_BE = MAE_FIELD_VLAN1_TCI,
443 	EFX_MAE_FIELD_ID_VLAN1_PROTO_BE = MAE_FIELD_VLAN1_PROTO,
444 	EFX_MAE_FIELD_ID_SRC_IP4_BE = MAE_FIELD_SRC_IP4,
445 	EFX_MAE_FIELD_ID_DST_IP4_BE = MAE_FIELD_DST_IP4,
446 	EFX_MAE_FIELD_ID_IP_PROTO = MAE_FIELD_IP_PROTO,
447 	EFX_MAE_FIELD_ID_IP_TOS = MAE_FIELD_IP_TOS,
448 	EFX_MAE_FIELD_ID_IP_TTL = MAE_FIELD_IP_TTL,
449 	EFX_MAE_FIELD_ID_SRC_IP6_BE = MAE_FIELD_SRC_IP6,
450 	EFX_MAE_FIELD_ID_DST_IP6_BE = MAE_FIELD_DST_IP6,
451 	EFX_MAE_FIELD_ID_L4_SPORT_BE = MAE_FIELD_L4_SPORT,
452 	EFX_MAE_FIELD_ID_L4_DPORT_BE = MAE_FIELD_L4_DPORT,
453 	EFX_MAE_FIELD_ID_TCP_FLAGS_BE = MAE_FIELD_TCP_FLAGS,
454 	EFX_MAE_FIELD_ID_ENC_ETHER_TYPE_BE = MAE_FIELD_ENC_ETHER_TYPE,
455 	EFX_MAE_FIELD_ID_ENC_ETH_SADDR_BE = MAE_FIELD_ENC_ETH_SADDR,
456 	EFX_MAE_FIELD_ID_ENC_ETH_DADDR_BE = MAE_FIELD_ENC_ETH_DADDR,
457 	EFX_MAE_FIELD_ID_ENC_VLAN0_TCI_BE = MAE_FIELD_ENC_VLAN0_TCI,
458 	EFX_MAE_FIELD_ID_ENC_VLAN0_PROTO_BE = MAE_FIELD_ENC_VLAN0_PROTO,
459 	EFX_MAE_FIELD_ID_ENC_VLAN1_TCI_BE = MAE_FIELD_ENC_VLAN1_TCI,
460 	EFX_MAE_FIELD_ID_ENC_VLAN1_PROTO_BE = MAE_FIELD_ENC_VLAN1_PROTO,
461 	EFX_MAE_FIELD_ID_ENC_SRC_IP4_BE = MAE_FIELD_ENC_SRC_IP4,
462 	EFX_MAE_FIELD_ID_ENC_DST_IP4_BE = MAE_FIELD_ENC_DST_IP4,
463 	EFX_MAE_FIELD_ID_ENC_IP_PROTO = MAE_FIELD_ENC_IP_PROTO,
464 	EFX_MAE_FIELD_ID_ENC_IP_TOS = MAE_FIELD_ENC_IP_TOS,
465 	EFX_MAE_FIELD_ID_ENC_IP_TTL = MAE_FIELD_ENC_IP_TTL,
466 	EFX_MAE_FIELD_ID_ENC_SRC_IP6_BE = MAE_FIELD_ENC_SRC_IP6,
467 	EFX_MAE_FIELD_ID_ENC_DST_IP6_BE = MAE_FIELD_ENC_DST_IP6,
468 	EFX_MAE_FIELD_ID_ENC_L4_SPORT_BE = MAE_FIELD_ENC_L4_SPORT,
469 	EFX_MAE_FIELD_ID_ENC_L4_DPORT_BE = MAE_FIELD_ENC_L4_DPORT,
470 	EFX_MAE_FIELD_ID_ENC_VNET_ID_BE = MAE_FIELD_ENC_VNET_ID,
471 	EFX_MAE_FIELD_ID_OUTER_RULE_ID = MAE_FIELD_OUTER_RULE_ID,
472 	EFX_MAE_FIELD_ID_HAS_OVLAN = MAE_FIELD_HAS_OVLAN,
473 	EFX_MAE_FIELD_ID_HAS_IVLAN = MAE_FIELD_HAS_IVLAN,
474 	EFX_MAE_FIELD_ID_ENC_HAS_OVLAN = MAE_FIELD_ENC_HAS_OVLAN,
475 	EFX_MAE_FIELD_ID_ENC_HAS_IVLAN = MAE_FIELD_ENC_HAS_IVLAN,
476 	EFX_MAE_FIELD_ID_RECIRC_ID = MAE_FIELD_RECIRC_ID,
477 
478 	EFX_MAE_FIELD_CAP_NIDS
479 } efx_mae_field_cap_id_t;
480 
481 typedef enum efx_mae_field_endianness_e {
482 	EFX_MAE_FIELD_LE = 0,
483 	EFX_MAE_FIELD_BE,
484 
485 	EFX_MAE_FIELD_ENDIANNESS_NTYPES
486 } efx_mae_field_endianness_t;
487 
488 /*
489  * The following structure is a means to describe an MAE field.
490  * The information in it is meant to be used internally by
491  * APIs for addressing a given field in a mask-value pairs
492  * structure and for validation purposes.
493  *
494  * A field may have an alternative one. This structure
495  * has additional members to reference the alternative
496  * field's mask. See efx_mae_match_spec_is_valid().
497  */
498 typedef struct efx_mae_mv_desc_s {
499 	efx_mae_field_cap_id_t		emmd_field_cap_id;
500 
501 	size_t				emmd_value_size;
502 	size_t				emmd_value_offset;
503 	size_t				emmd_mask_size;
504 	size_t				emmd_mask_offset;
505 
506 	/*
507 	 * Having the alternative field's mask size set to 0
508 	 * means that there's no alternative field specified.
509 	 */
510 	size_t				emmd_alt_mask_size;
511 	size_t				emmd_alt_mask_offset;
512 
513 	/* Primary field and the alternative one are of the same endianness. */
514 	efx_mae_field_endianness_t	emmd_endianness;
515 } efx_mae_mv_desc_t;
516 
517 /* Indices to this array are provided by efx_mae_field_id_t */
518 static const efx_mae_mv_desc_t __efx_mae_action_rule_mv_desc_set[] = {
519 #define	EFX_MAE_MV_DESC(_name, _endianness)				\
520 	[EFX_MAE_FIELD_##_name] =					\
521 	{								\
522 		EFX_MAE_FIELD_ID_##_name,				\
523 		MAE_FIELD_MASK_VALUE_PAIRS_V2_##_name##_LEN,		\
524 		MAE_FIELD_MASK_VALUE_PAIRS_V2_##_name##_OFST,		\
525 		MAE_FIELD_MASK_VALUE_PAIRS_V2_##_name##_MASK_LEN,	\
526 		MAE_FIELD_MASK_VALUE_PAIRS_V2_##_name##_MASK_OFST,	\
527 		0, 0 /* no alternative field */,			\
528 		_endianness						\
529 	}
530 
531 	EFX_MAE_MV_DESC(INGRESS_MPORT_SELECTOR, EFX_MAE_FIELD_LE),
532 	EFX_MAE_MV_DESC(ETHER_TYPE_BE, EFX_MAE_FIELD_BE),
533 	EFX_MAE_MV_DESC(ETH_SADDR_BE, EFX_MAE_FIELD_BE),
534 	EFX_MAE_MV_DESC(ETH_DADDR_BE, EFX_MAE_FIELD_BE),
535 	EFX_MAE_MV_DESC(VLAN0_TCI_BE, EFX_MAE_FIELD_BE),
536 	EFX_MAE_MV_DESC(VLAN0_PROTO_BE, EFX_MAE_FIELD_BE),
537 	EFX_MAE_MV_DESC(VLAN1_TCI_BE, EFX_MAE_FIELD_BE),
538 	EFX_MAE_MV_DESC(VLAN1_PROTO_BE, EFX_MAE_FIELD_BE),
539 	EFX_MAE_MV_DESC(SRC_IP4_BE, EFX_MAE_FIELD_BE),
540 	EFX_MAE_MV_DESC(DST_IP4_BE, EFX_MAE_FIELD_BE),
541 	EFX_MAE_MV_DESC(IP_PROTO, EFX_MAE_FIELD_BE),
542 	EFX_MAE_MV_DESC(IP_TOS, EFX_MAE_FIELD_BE),
543 	EFX_MAE_MV_DESC(IP_TTL, EFX_MAE_FIELD_BE),
544 	EFX_MAE_MV_DESC(SRC_IP6_BE, EFX_MAE_FIELD_BE),
545 	EFX_MAE_MV_DESC(DST_IP6_BE, EFX_MAE_FIELD_BE),
546 	EFX_MAE_MV_DESC(L4_SPORT_BE, EFX_MAE_FIELD_BE),
547 	EFX_MAE_MV_DESC(L4_DPORT_BE, EFX_MAE_FIELD_BE),
548 	EFX_MAE_MV_DESC(TCP_FLAGS_BE, EFX_MAE_FIELD_BE),
549 	EFX_MAE_MV_DESC(ENC_VNET_ID_BE, EFX_MAE_FIELD_BE),
550 	EFX_MAE_MV_DESC(OUTER_RULE_ID, EFX_MAE_FIELD_LE),
551 	EFX_MAE_MV_DESC(RECIRC_ID, EFX_MAE_FIELD_LE),
552 
553 #undef EFX_MAE_MV_DESC
554 };
555 
556 /* Indices to this array are provided by efx_mae_field_id_t */
557 static const efx_mae_mv_desc_t __efx_mae_outer_rule_mv_desc_set[] = {
558 #define	EFX_MAE_MV_DESC(_name, _endianness)				\
559 	[EFX_MAE_FIELD_##_name] =					\
560 	{								\
561 		EFX_MAE_FIELD_ID_##_name,				\
562 		MAE_ENC_FIELD_PAIRS_##_name##_LEN,			\
563 		MAE_ENC_FIELD_PAIRS_##_name##_OFST,			\
564 		MAE_ENC_FIELD_PAIRS_##_name##_MASK_LEN,			\
565 		MAE_ENC_FIELD_PAIRS_##_name##_MASK_OFST,		\
566 		0, 0 /* no alternative field */,			\
567 		_endianness						\
568 	}
569 
570 /* Same as EFX_MAE_MV_DESC(), but also indicates an alternative field. */
571 #define	EFX_MAE_MV_DESC_ALT(_name, _alt_name, _endianness)		\
572 	[EFX_MAE_FIELD_##_name] =					\
573 	{								\
574 		EFX_MAE_FIELD_ID_##_name,				\
575 		MAE_ENC_FIELD_PAIRS_##_name##_LEN,			\
576 		MAE_ENC_FIELD_PAIRS_##_name##_OFST,			\
577 		MAE_ENC_FIELD_PAIRS_##_name##_MASK_LEN,			\
578 		MAE_ENC_FIELD_PAIRS_##_name##_MASK_OFST,		\
579 		MAE_ENC_FIELD_PAIRS_##_alt_name##_MASK_LEN,		\
580 		MAE_ENC_FIELD_PAIRS_##_alt_name##_MASK_OFST,		\
581 		_endianness						\
582 	}
583 
584 	EFX_MAE_MV_DESC(INGRESS_MPORT_SELECTOR, EFX_MAE_FIELD_LE),
585 	EFX_MAE_MV_DESC(ENC_ETHER_TYPE_BE, EFX_MAE_FIELD_BE),
586 	EFX_MAE_MV_DESC(ENC_ETH_SADDR_BE, EFX_MAE_FIELD_BE),
587 	EFX_MAE_MV_DESC(ENC_ETH_DADDR_BE, EFX_MAE_FIELD_BE),
588 	EFX_MAE_MV_DESC(ENC_VLAN0_TCI_BE, EFX_MAE_FIELD_BE),
589 	EFX_MAE_MV_DESC(ENC_VLAN0_PROTO_BE, EFX_MAE_FIELD_BE),
590 	EFX_MAE_MV_DESC(ENC_VLAN1_TCI_BE, EFX_MAE_FIELD_BE),
591 	EFX_MAE_MV_DESC(ENC_VLAN1_PROTO_BE, EFX_MAE_FIELD_BE),
592 	EFX_MAE_MV_DESC_ALT(ENC_SRC_IP4_BE, ENC_SRC_IP6_BE, EFX_MAE_FIELD_BE),
593 	EFX_MAE_MV_DESC_ALT(ENC_DST_IP4_BE, ENC_DST_IP6_BE, EFX_MAE_FIELD_BE),
594 	EFX_MAE_MV_DESC(ENC_IP_PROTO, EFX_MAE_FIELD_BE),
595 	EFX_MAE_MV_DESC(ENC_IP_TOS, EFX_MAE_FIELD_BE),
596 	EFX_MAE_MV_DESC(ENC_IP_TTL, EFX_MAE_FIELD_BE),
597 	EFX_MAE_MV_DESC_ALT(ENC_SRC_IP6_BE, ENC_SRC_IP4_BE, EFX_MAE_FIELD_BE),
598 	EFX_MAE_MV_DESC_ALT(ENC_DST_IP6_BE, ENC_DST_IP4_BE, EFX_MAE_FIELD_BE),
599 	EFX_MAE_MV_DESC(ENC_L4_SPORT_BE, EFX_MAE_FIELD_BE),
600 	EFX_MAE_MV_DESC(ENC_L4_DPORT_BE, EFX_MAE_FIELD_BE),
601 
602 #undef EFX_MAE_MV_DESC_ALT
603 #undef EFX_MAE_MV_DESC
604 };
605 
606 /*
607  * The following structure is a means to describe an MAE bit.
608  * The information in it is meant to be used internally by
609  * APIs for addressing a given flag in a mask-value pairs
610  * structure and for validation purposes.
611  */
612 typedef struct efx_mae_mv_bit_desc_s {
613 	/*
614 	 * Arrays using this struct are indexed by field IDs.
615 	 * Fields which aren't meant to be referenced by these
616 	 * arrays comprise gaps (invalid entries). Below field
617 	 * helps to identify such entries.
618 	 */
619 	boolean_t			emmbd_entry_is_valid;
620 	efx_mae_field_cap_id_t		emmbd_bit_cap_id;
621 	size_t				emmbd_value_ofst;
622 	unsigned int			emmbd_value_lbn;
623 	size_t				emmbd_mask_ofst;
624 	unsigned int			emmbd_mask_lbn;
625 } efx_mae_mv_bit_desc_t;
626 
627 static const efx_mae_mv_bit_desc_t __efx_mae_outer_rule_mv_bit_desc_set[] = {
628 #define	EFX_MAE_MV_BIT_DESC(_name)					\
629 	[EFX_MAE_FIELD_##_name] =					\
630 	{								\
631 		B_TRUE,							\
632 		EFX_MAE_FIELD_ID_##_name,				\
633 		MAE_ENC_FIELD_PAIRS_##_name##_OFST,			\
634 		MAE_ENC_FIELD_PAIRS_##_name##_LBN,			\
635 		MAE_ENC_FIELD_PAIRS_##_name##_MASK_OFST,		\
636 		MAE_ENC_FIELD_PAIRS_##_name##_MASK_LBN,			\
637 	}
638 
639 	EFX_MAE_MV_BIT_DESC(ENC_HAS_OVLAN),
640 	EFX_MAE_MV_BIT_DESC(ENC_HAS_IVLAN),
641 
642 #undef EFX_MAE_MV_BIT_DESC
643 };
644 
645 static const efx_mae_mv_bit_desc_t __efx_mae_action_rule_mv_bit_desc_set[] = {
646 #define	EFX_MAE_MV_BIT_DESC(_name)					\
647 	[EFX_MAE_FIELD_##_name] =					\
648 	{								\
649 		B_TRUE,							\
650 		EFX_MAE_FIELD_ID_##_name,				\
651 		MAE_FIELD_MASK_VALUE_PAIRS_V2_FLAGS_OFST,		\
652 		MAE_FIELD_MASK_VALUE_PAIRS_V2_##_name##_LBN,		\
653 		MAE_FIELD_MASK_VALUE_PAIRS_V2_FLAGS_MASK_OFST,		\
654 		MAE_FIELD_MASK_VALUE_PAIRS_V2_##_name##_LBN,		\
655 	}
656 
657 	EFX_MAE_MV_BIT_DESC(HAS_OVLAN),
658 	EFX_MAE_MV_BIT_DESC(HAS_IVLAN),
659 	EFX_MAE_MV_BIT_DESC(ENC_HAS_OVLAN),
660 	EFX_MAE_MV_BIT_DESC(ENC_HAS_IVLAN),
661 
662 #undef EFX_MAE_MV_BIT_DESC
663 };
664 
665 	__checkReturn			efx_rc_t
666 efx_mae_mport_invalid(
667 	__out				efx_mport_sel_t *mportp)
668 {
669 	efx_dword_t dword;
670 	efx_rc_t rc;
671 
672 	if (mportp == NULL) {
673 		rc = EINVAL;
674 		goto fail1;
675 	}
676 
677 	EFX_POPULATE_DWORD_1(dword,
678 	    MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_INVALID);
679 
680 	memset(mportp, 0, sizeof (*mportp));
681 	mportp->sel = dword.ed_u32[0];
682 
683 	return (0);
684 
685 fail1:
686 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
687 	return (rc);
688 }
689 
690 	__checkReturn			efx_rc_t
691 efx_mae_mport_by_phy_port(
692 	__in				uint32_t phy_port,
693 	__out				efx_mport_sel_t *mportp)
694 {
695 	efx_dword_t dword;
696 	efx_rc_t rc;
697 
698 	if (phy_port > EFX_MASK32(MAE_MPORT_SELECTOR_PPORT_ID)) {
699 		rc = EINVAL;
700 		goto fail1;
701 	}
702 
703 	EFX_POPULATE_DWORD_2(dword,
704 	    MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_PPORT,
705 	    MAE_MPORT_SELECTOR_PPORT_ID, phy_port);
706 
707 	memset(mportp, 0, sizeof (*mportp));
708 	/*
709 	 * The constructed DWORD is little-endian,
710 	 * but the resulting value is meant to be
711 	 * passed to MCDIs, where it will undergo
712 	 * host-order to little endian conversion.
713 	 */
714 	mportp->sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
715 
716 	return (0);
717 
718 fail1:
719 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
720 	return (rc);
721 }
722 
723 	__checkReturn			efx_rc_t
724 efx_mae_mport_by_pcie_function(
725 	__in				uint32_t pf,
726 	__in				uint32_t vf,
727 	__out				efx_mport_sel_t *mportp)
728 {
729 	efx_dword_t dword;
730 	efx_rc_t rc;
731 
732 	rc = efx_mae_mport_by_pcie_mh_function(EFX_PCIE_INTERFACE_CALLER,
733 					       pf, vf, mportp);
734 	if (rc != 0)
735 		goto fail1;
736 
737 	return (0);
738 
739 fail1:
740 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
741 	return (rc);
742 }
743 
744 static	__checkReturn			efx_rc_t
745 efx_mae_intf_to_selector(
746 	__in				efx_pcie_interface_t intf,
747 	__out				uint32_t *selector_intfp)
748 {
749 	efx_rc_t rc;
750 
751 	switch (intf) {
752 	case EFX_PCIE_INTERFACE_HOST_PRIMARY:
753 		EFX_STATIC_ASSERT(MAE_MPORT_SELECTOR_HOST_PRIMARY <=
754 		    EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_INTF_ID));
755 		*selector_intfp = MAE_MPORT_SELECTOR_HOST_PRIMARY;
756 		break;
757 	case EFX_PCIE_INTERFACE_NIC_EMBEDDED:
758 		EFX_STATIC_ASSERT(MAE_MPORT_SELECTOR_NIC_EMBEDDED <=
759 		    EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_INTF_ID));
760 		*selector_intfp = MAE_MPORT_SELECTOR_NIC_EMBEDDED;
761 		break;
762 	case EFX_PCIE_INTERFACE_CALLER:
763 		EFX_STATIC_ASSERT(MAE_MPORT_SELECTOR_CALLER_INTF <=
764 		    EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_INTF_ID));
765 		*selector_intfp = MAE_MPORT_SELECTOR_CALLER_INTF;
766 		break;
767 	default:
768 		rc = EINVAL;
769 		goto fail1;
770 	}
771 
772 	return (0);
773 
774 fail1:
775 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
776 	return (rc);
777 }
778 
779 	__checkReturn			efx_rc_t
780 efx_mae_mport_by_pcie_mh_function(
781 	__in				efx_pcie_interface_t intf,
782 	__in				uint32_t pf,
783 	__in				uint32_t vf,
784 	__out				efx_mport_sel_t *mportp)
785 {
786 	uint32_t selector_intf;
787 	efx_dword_t dword;
788 	efx_rc_t rc;
789 
790 	EFX_STATIC_ASSERT(EFX_PCI_VF_INVALID ==
791 	    MAE_MPORT_SELECTOR_FUNC_VF_ID_NULL);
792 
793 	rc = efx_mae_intf_to_selector(intf, &selector_intf);
794 	if (rc != 0)
795 		goto fail1;
796 
797 	if (pf > EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_MH_PF_ID)) {
798 		rc = EINVAL;
799 		goto fail2;
800 	}
801 
802 	if (vf > EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_VF_ID)) {
803 		rc = EINVAL;
804 		goto fail3;
805 	}
806 
807 
808 	EFX_POPULATE_DWORD_4(dword,
809 	    MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_MH_FUNC,
810 	    MAE_MPORT_SELECTOR_FUNC_INTF_ID, selector_intf,
811 	    MAE_MPORT_SELECTOR_FUNC_MH_PF_ID, pf,
812 	    MAE_MPORT_SELECTOR_FUNC_VF_ID, vf);
813 
814 	memset(mportp, 0, sizeof (*mportp));
815 	mportp->sel = dword.ed_u32[0];
816 
817 	return (0);
818 
819 fail3:
820 	EFSYS_PROBE(fail3);
821 fail2:
822 	EFSYS_PROBE(fail2);
823 fail1:
824 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
825 	return (rc);
826 }
827 
828 static	__checkReturn			efx_rc_t
829 efx_mcdi_mae_mport_lookup(
830 	__in				efx_nic_t *enp,
831 	__in				const efx_mport_sel_t *mport_selectorp,
832 	__out				efx_mport_id_t *mport_idp)
833 {
834 	efx_mcdi_req_t req;
835 	EFX_MCDI_DECLARE_BUF(payload,
836 	    MC_CMD_MAE_MPORT_LOOKUP_IN_LEN,
837 	    MC_CMD_MAE_MPORT_LOOKUP_OUT_LEN);
838 	efx_rc_t rc;
839 
840 	req.emr_cmd = MC_CMD_MAE_MPORT_LOOKUP;
841 	req.emr_in_buf = payload;
842 	req.emr_in_length = MC_CMD_MAE_MPORT_LOOKUP_IN_LEN;
843 	req.emr_out_buf = payload;
844 	req.emr_out_length = MC_CMD_MAE_MPORT_LOOKUP_OUT_LEN;
845 
846 	MCDI_IN_SET_DWORD(req, MAE_MPORT_LOOKUP_IN_MPORT_SELECTOR,
847 	    mport_selectorp->sel);
848 
849 	efx_mcdi_execute(enp, &req);
850 
851 	if (req.emr_rc != 0) {
852 		rc = req.emr_rc;
853 		goto fail1;
854 	}
855 
856 	mport_idp->id = MCDI_OUT_DWORD(req, MAE_MPORT_LOOKUP_OUT_MPORT_ID);
857 
858 	return (0);
859 
860 fail1:
861 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
862 	return (rc);
863 }
864 
865 	__checkReturn			efx_rc_t
866 efx_mae_mport_id_by_selector(
867 	__in				efx_nic_t *enp,
868 	__in				const efx_mport_sel_t *mport_selectorp,
869 	__out				efx_mport_id_t *mport_idp)
870 {
871 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
872 	efx_rc_t rc;
873 
874 	if (encp->enc_mae_supported == B_FALSE) {
875 		rc = ENOTSUP;
876 		goto fail1;
877 	}
878 
879 	rc = efx_mcdi_mae_mport_lookup(enp, mport_selectorp, mport_idp);
880 	if (rc != 0)
881 		goto fail2;
882 
883 	return (0);
884 
885 fail2:
886 	EFSYS_PROBE(fail2);
887 fail1:
888 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
889 	return (rc);
890 }
891 
892 	__checkReturn			efx_rc_t
893 efx_mae_match_spec_recirc_id_set(
894 	__in				efx_mae_match_spec_t *spec,
895 	__in				uint8_t recirc_id)
896 {
897 	uint8_t full_mask = UINT8_MAX;
898 	const uint8_t *vp;
899 	const uint8_t *mp;
900 	efx_rc_t rc;
901 
902 	vp = (const uint8_t *)&recirc_id;
903 	mp = (const uint8_t *)&full_mask;
904 
905 	rc = efx_mae_match_spec_field_set(spec, EFX_MAE_FIELD_RECIRC_ID,
906 					  sizeof (recirc_id), vp,
907 					  sizeof (full_mask), mp);
908 	if (rc != 0)
909 		goto fail1;
910 
911 	return (0);
912 
913 fail1:
914 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
915 	return (rc);
916 }
917 
918 	__checkReturn			efx_rc_t
919 efx_mae_mport_by_id(
920 	__in				const efx_mport_id_t *mport_idp,
921 	__out				efx_mport_sel_t *mportp)
922 {
923 	efx_dword_t dword;
924 
925 	EFX_POPULATE_DWORD_2(dword,
926 	    MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_MPORT_ID,
927 	    MAE_MPORT_SELECTOR_MPORT_ID, mport_idp->id);
928 
929 	memset(mportp, 0, sizeof (*mportp));
930 	mportp->sel = __LE_TO_CPU_32(dword.ed_u32[0]);
931 
932 	return (0);
933 }
934 
935 	__checkReturn			efx_rc_t
936 efx_mae_match_spec_field_set(
937 	__in				efx_mae_match_spec_t *spec,
938 	__in				efx_mae_field_id_t field_id,
939 	__in				size_t value_size,
940 	__in_bcount(value_size)		const uint8_t *value,
941 	__in				size_t mask_size,
942 	__in_bcount(mask_size)		const uint8_t *mask)
943 {
944 	const efx_mae_mv_desc_t *descp;
945 	unsigned int desc_set_nentries;
946 	uint8_t *mvp;
947 	efx_rc_t rc;
948 
949 	switch (spec->emms_type) {
950 	case EFX_MAE_RULE_OUTER:
951 		desc_set_nentries =
952 		    EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
953 		descp = &__efx_mae_outer_rule_mv_desc_set[field_id];
954 		mvp = spec->emms_mask_value_pairs.outer;
955 		break;
956 	case EFX_MAE_RULE_ACTION:
957 		desc_set_nentries =
958 		    EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
959 		descp = &__efx_mae_action_rule_mv_desc_set[field_id];
960 		mvp = spec->emms_mask_value_pairs.action;
961 		break;
962 	default:
963 		rc = ENOTSUP;
964 		goto fail1;
965 	}
966 
967 	if ((unsigned int)field_id >= desc_set_nentries) {
968 		rc = EINVAL;
969 		goto fail2;
970 	}
971 
972 	if (descp->emmd_mask_size == 0) {
973 		/* The ID points to a gap in the array of field descriptors. */
974 		rc = EINVAL;
975 		goto fail3;
976 	}
977 
978 	if (value_size != descp->emmd_value_size) {
979 		rc = EINVAL;
980 		goto fail4;
981 	}
982 
983 	if (mask_size != descp->emmd_mask_size) {
984 		rc = EINVAL;
985 		goto fail5;
986 	}
987 
988 	if (descp->emmd_endianness == EFX_MAE_FIELD_BE) {
989 		unsigned int i;
990 
991 		/*
992 		 * The mask/value are in network (big endian) order.
993 		 * The MCDI request field is also big endian.
994 		 */
995 
996 		EFSYS_ASSERT3U(value_size, ==, mask_size);
997 
998 		for (i = 0; i < value_size; ++i) {
999 			uint8_t *v_bytep = mvp + descp->emmd_value_offset + i;
1000 			uint8_t *m_bytep = mvp + descp->emmd_mask_offset + i;
1001 
1002 			/*
1003 			 * Apply the mask (which may be all-zeros) to the value.
1004 			 *
1005 			 * If this API is provided with some value to set for a
1006 			 * given field in one specification and with some other
1007 			 * value to set for this field in another specification,
1008 			 * then, if the two masks are all-zeros, the field will
1009 			 * avoid being counted as a mismatch when comparing the
1010 			 * specifications using efx_mae_match_specs_equal() API.
1011 			 */
1012 			*v_bytep = value[i] & mask[i];
1013 			*m_bytep = mask[i];
1014 		}
1015 	} else {
1016 		efx_dword_t dword;
1017 
1018 		/*
1019 		 * The mask/value are in host byte order.
1020 		 * The MCDI request field is little endian.
1021 		 */
1022 		switch (value_size) {
1023 		case 4:
1024 			EFX_POPULATE_DWORD_1(dword,
1025 			    EFX_DWORD_0, *(const uint32_t *)value);
1026 
1027 			memcpy(mvp + descp->emmd_value_offset,
1028 			    &dword, sizeof (dword));
1029 			break;
1030 		case 1:
1031 			memcpy(mvp + descp->emmd_value_offset,
1032 			    value, 1);
1033 			break;
1034 		default:
1035 			EFSYS_ASSERT(B_FALSE);
1036 		}
1037 
1038 		switch (mask_size) {
1039 		case 4:
1040 			EFX_POPULATE_DWORD_1(dword,
1041 			    EFX_DWORD_0, *(const uint32_t *)mask);
1042 
1043 			memcpy(mvp + descp->emmd_mask_offset,
1044 			    &dword, sizeof (dword));
1045 			break;
1046 		case 1:
1047 			memcpy(mvp + descp->emmd_mask_offset,
1048 			    mask, 1);
1049 			break;
1050 		default:
1051 			EFSYS_ASSERT(B_FALSE);
1052 		}
1053 	}
1054 
1055 	return (0);
1056 
1057 fail5:
1058 	EFSYS_PROBE(fail5);
1059 fail4:
1060 	EFSYS_PROBE(fail4);
1061 fail3:
1062 	EFSYS_PROBE(fail3);
1063 fail2:
1064 	EFSYS_PROBE(fail2);
1065 fail1:
1066 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1067 	return (rc);
1068 }
1069 
1070 	__checkReturn			efx_rc_t
1071 efx_mae_match_spec_bit_set(
1072 	__in				efx_mae_match_spec_t *spec,
1073 	__in				efx_mae_field_id_t field_id,
1074 	__in				boolean_t value)
1075 {
1076 	const efx_mae_mv_bit_desc_t *bit_descp;
1077 	unsigned int bit_desc_set_nentries;
1078 	unsigned int byte_idx;
1079 	unsigned int bit_idx;
1080 	uint8_t *mvp;
1081 	efx_rc_t rc;
1082 
1083 	switch (spec->emms_type) {
1084 	case EFX_MAE_RULE_OUTER:
1085 		bit_desc_set_nentries =
1086 		    EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_bit_desc_set);
1087 		bit_descp = &__efx_mae_outer_rule_mv_bit_desc_set[field_id];
1088 		mvp = spec->emms_mask_value_pairs.outer;
1089 		break;
1090 	case EFX_MAE_RULE_ACTION:
1091 		bit_desc_set_nentries =
1092 		    EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_bit_desc_set);
1093 		bit_descp = &__efx_mae_action_rule_mv_bit_desc_set[field_id];
1094 		mvp = spec->emms_mask_value_pairs.action;
1095 		break;
1096 	default:
1097 		rc = ENOTSUP;
1098 		goto fail1;
1099 	}
1100 
1101 	if ((unsigned int)field_id >= bit_desc_set_nentries) {
1102 		rc = EINVAL;
1103 		goto fail2;
1104 	}
1105 
1106 	if (bit_descp->emmbd_entry_is_valid == B_FALSE) {
1107 		rc = EINVAL;
1108 		goto fail3;
1109 	}
1110 
1111 	byte_idx = bit_descp->emmbd_value_ofst + bit_descp->emmbd_value_lbn / 8;
1112 	bit_idx = bit_descp->emmbd_value_lbn % 8;
1113 
1114 	if (value != B_FALSE)
1115 		mvp[byte_idx] |= (1U << bit_idx);
1116 	else
1117 		mvp[byte_idx] &= ~(1U << bit_idx);
1118 
1119 	byte_idx = bit_descp->emmbd_mask_ofst + bit_descp->emmbd_mask_lbn / 8;
1120 	bit_idx = bit_descp->emmbd_mask_lbn % 8;
1121 	mvp[byte_idx] |= (1U << bit_idx);
1122 
1123 	return (0);
1124 
1125 fail3:
1126 	EFSYS_PROBE(fail3);
1127 fail2:
1128 	EFSYS_PROBE(fail2);
1129 fail1:
1130 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1131 	return (rc);
1132 }
1133 
1134 	__checkReturn			efx_rc_t
1135 efx_mae_match_spec_mport_set(
1136 	__in				efx_mae_match_spec_t *spec,
1137 	__in				const efx_mport_sel_t *valuep,
1138 	__in_opt			const efx_mport_sel_t *maskp)
1139 {
1140 	uint32_t full_mask = UINT32_MAX;
1141 	const uint8_t *vp;
1142 	const uint8_t *mp;
1143 	efx_rc_t rc;
1144 
1145 	if (valuep == NULL) {
1146 		rc = EINVAL;
1147 		goto fail1;
1148 	}
1149 
1150 	vp = (const uint8_t *)&valuep->sel;
1151 	if (maskp != NULL)
1152 		mp = (const uint8_t *)&maskp->sel;
1153 	else
1154 		mp = (const uint8_t *)&full_mask;
1155 
1156 	rc = efx_mae_match_spec_field_set(spec,
1157 	    EFX_MAE_FIELD_INGRESS_MPORT_SELECTOR,
1158 	    sizeof (valuep->sel), vp, sizeof (maskp->sel), mp);
1159 	if (rc != 0)
1160 		goto fail2;
1161 
1162 	return (0);
1163 
1164 fail2:
1165 	EFSYS_PROBE(fail2);
1166 fail1:
1167 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1168 	return (rc);
1169 }
1170 
1171 	__checkReturn			boolean_t
1172 efx_mae_match_specs_equal(
1173 	__in				const efx_mae_match_spec_t *left,
1174 	__in				const efx_mae_match_spec_t *right)
1175 {
1176 	return ((memcmp(left, right, sizeof (*left)) == 0) ? B_TRUE : B_FALSE);
1177 }
1178 
1179 #define	EFX_MASK_BIT_IS_SET(_mask, _mask_page_nbits, _bit)		\
1180 	    ((_mask)[(_bit) / (_mask_page_nbits)] &			\
1181 		    (1ULL << ((_bit) & ((_mask_page_nbits) - 1))))
1182 
1183 static					boolean_t
1184 efx_mask_is_prefix(
1185 	__in				size_t mask_nbytes,
1186 	__in_bcount(mask_nbytes)	const uint8_t *maskp)
1187 {
1188 	boolean_t prev_bit_is_set = B_TRUE;
1189 	unsigned int i;
1190 
1191 	for (i = 0; i < 8 * mask_nbytes; ++i) {
1192 		boolean_t bit_is_set = EFX_MASK_BIT_IS_SET(maskp, 8, i);
1193 
1194 		if (!prev_bit_is_set && bit_is_set)
1195 			return B_FALSE;
1196 
1197 		prev_bit_is_set = bit_is_set;
1198 	}
1199 
1200 	return B_TRUE;
1201 }
1202 
1203 static					boolean_t
1204 efx_mask_is_all_ones(
1205 	__in				size_t mask_nbytes,
1206 	__in_bcount(mask_nbytes)	const uint8_t *maskp)
1207 {
1208 	unsigned int i;
1209 	uint8_t t = ~0;
1210 
1211 	for (i = 0; i < mask_nbytes; ++i)
1212 		t &= maskp[i];
1213 
1214 	return (t == (uint8_t)(~0));
1215 }
1216 
1217 static					boolean_t
1218 efx_mask_is_all_zeros(
1219 	__in				size_t mask_nbytes,
1220 	__in_bcount(mask_nbytes)	const uint8_t *maskp)
1221 {
1222 	unsigned int i;
1223 	uint8_t t = 0;
1224 
1225 	for (i = 0; i < mask_nbytes; ++i)
1226 		t |= maskp[i];
1227 
1228 	return (t == 0);
1229 }
1230 
1231 	__checkReturn			boolean_t
1232 efx_mae_match_spec_is_valid(
1233 	__in				efx_nic_t *enp,
1234 	__in				const efx_mae_match_spec_t *spec)
1235 {
1236 	efx_mae_t *maep = enp->en_maep;
1237 	unsigned int field_ncaps = maep->em_max_nfields;
1238 	const efx_mae_field_cap_t *field_caps;
1239 	const efx_mae_mv_desc_t *desc_setp;
1240 	unsigned int desc_set_nentries;
1241 	const efx_mae_mv_bit_desc_t *bit_desc_setp;
1242 	unsigned int bit_desc_set_nentries;
1243 	boolean_t is_valid = B_TRUE;
1244 	efx_mae_field_id_t field_id;
1245 	const uint8_t *mvp;
1246 
1247 	switch (spec->emms_type) {
1248 	case EFX_MAE_RULE_OUTER:
1249 		field_caps = maep->em_outer_rule_field_caps;
1250 		desc_setp = __efx_mae_outer_rule_mv_desc_set;
1251 		desc_set_nentries =
1252 		    EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
1253 		bit_desc_setp = __efx_mae_outer_rule_mv_bit_desc_set;
1254 		bit_desc_set_nentries =
1255 		    EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_bit_desc_set);
1256 		mvp = spec->emms_mask_value_pairs.outer;
1257 		break;
1258 	case EFX_MAE_RULE_ACTION:
1259 		field_caps = maep->em_action_rule_field_caps;
1260 		desc_setp = __efx_mae_action_rule_mv_desc_set;
1261 		desc_set_nentries =
1262 		    EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
1263 		bit_desc_setp = __efx_mae_action_rule_mv_bit_desc_set;
1264 		bit_desc_set_nentries =
1265 		    EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_bit_desc_set);
1266 		mvp = spec->emms_mask_value_pairs.action;
1267 		break;
1268 	default:
1269 		return (B_FALSE);
1270 	}
1271 
1272 	if (field_caps == NULL)
1273 		return (B_FALSE);
1274 
1275 	for (field_id = 0; (unsigned int)field_id < desc_set_nentries;
1276 	     ++field_id) {
1277 		const efx_mae_mv_desc_t *descp = &desc_setp[field_id];
1278 		efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id;
1279 		const uint8_t *alt_m_buf = mvp + descp->emmd_alt_mask_offset;
1280 		const uint8_t *m_buf = mvp + descp->emmd_mask_offset;
1281 		size_t alt_m_size = descp->emmd_alt_mask_size;
1282 		size_t m_size = descp->emmd_mask_size;
1283 
1284 		if (m_size == 0)
1285 			continue; /* Skip array gap */
1286 
1287 		if ((unsigned int)field_cap_id >= field_ncaps) {
1288 			/*
1289 			 * The FW has not reported capability status for
1290 			 * this field. Make sure that its mask is zeroed.
1291 			 */
1292 			is_valid = efx_mask_is_all_zeros(m_size, m_buf);
1293 			if (is_valid != B_FALSE)
1294 				continue;
1295 			else
1296 				break;
1297 		}
1298 
1299 		switch (field_caps[field_cap_id].emfc_support) {
1300 		case MAE_FIELD_SUPPORTED_MATCH_MASK:
1301 			is_valid = B_TRUE;
1302 			break;
1303 		case MAE_FIELD_SUPPORTED_MATCH_PREFIX:
1304 			is_valid = efx_mask_is_prefix(m_size, m_buf);
1305 			break;
1306 		case MAE_FIELD_SUPPORTED_MATCH_OPTIONAL:
1307 			is_valid = (efx_mask_is_all_ones(m_size, m_buf) ||
1308 			    efx_mask_is_all_zeros(m_size, m_buf));
1309 			break;
1310 		case MAE_FIELD_SUPPORTED_MATCH_ALWAYS:
1311 			is_valid = efx_mask_is_all_ones(m_size, m_buf);
1312 
1313 			if ((is_valid == B_FALSE) && (alt_m_size != 0)) {
1314 				/*
1315 				 * This field has an alternative one. The FW
1316 				 * reports ALWAYS for both implying that one
1317 				 * of them is required to have all-ones mask.
1318 				 *
1319 				 * The primary field's mask is incorrect; go
1320 				 * on to check that of the alternative field.
1321 				 */
1322 				is_valid = efx_mask_is_all_ones(alt_m_size,
1323 								alt_m_buf);
1324 			}
1325 			break;
1326 		case MAE_FIELD_SUPPORTED_MATCH_NEVER:
1327 		case MAE_FIELD_UNSUPPORTED:
1328 		default:
1329 			is_valid = efx_mask_is_all_zeros(m_size, m_buf);
1330 			break;
1331 		}
1332 
1333 		if (is_valid == B_FALSE)
1334 			return (B_FALSE);
1335 	}
1336 
1337 	for (field_id = 0; (unsigned int)field_id < bit_desc_set_nentries;
1338 	     ++field_id) {
1339 		const efx_mae_mv_bit_desc_t *bit_descp =
1340 		    &bit_desc_setp[field_id];
1341 		unsigned int byte_idx =
1342 		    bit_descp->emmbd_mask_ofst +
1343 		    bit_descp->emmbd_mask_lbn / 8;
1344 		unsigned int bit_idx =
1345 		    bit_descp->emmbd_mask_lbn % 8;
1346 		efx_mae_field_cap_id_t bit_cap_id =
1347 		    bit_descp->emmbd_bit_cap_id;
1348 
1349 		if (bit_descp->emmbd_entry_is_valid == B_FALSE)
1350 			continue; /* Skip array gap */
1351 
1352 		if ((unsigned int)bit_cap_id >= field_ncaps) {
1353 			/* No capability for this bit = unsupported. */
1354 			is_valid = ((mvp[byte_idx] & (1U << bit_idx)) == 0);
1355 			if (is_valid == B_FALSE)
1356 				break;
1357 			else
1358 				continue;
1359 		}
1360 
1361 		switch (field_caps[bit_cap_id].emfc_support) {
1362 		case MAE_FIELD_SUPPORTED_MATCH_OPTIONAL:
1363 			is_valid = B_TRUE;
1364 			break;
1365 		case MAE_FIELD_SUPPORTED_MATCH_ALWAYS:
1366 			is_valid = ((mvp[byte_idx] & (1U << bit_idx)) != 0);
1367 			break;
1368 		case MAE_FIELD_SUPPORTED_MATCH_NEVER:
1369 		case MAE_FIELD_UNSUPPORTED:
1370 		default:
1371 			is_valid = ((mvp[byte_idx] & (1U << bit_idx)) == 0);
1372 			break;
1373 		}
1374 
1375 		if (is_valid == B_FALSE)
1376 			break;
1377 	}
1378 
1379 	return (is_valid);
1380 }
1381 
1382 	__checkReturn			efx_rc_t
1383 efx_mae_action_set_spec_init(
1384 	__in				efx_nic_t *enp,
1385 	__out				efx_mae_actions_t **specp)
1386 {
1387 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1388 	efx_mae_actions_t *spec;
1389 	efx_rc_t rc;
1390 
1391 	EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), spec);
1392 	if (spec == NULL) {
1393 		rc = ENOMEM;
1394 		goto fail1;
1395 	}
1396 
1397 	spec->ema_rsrc.emar_dst_mac_id.id = EFX_MAE_RSRC_ID_INVALID;
1398 	spec->ema_rsrc.emar_src_mac_id.id = EFX_MAE_RSRC_ID_INVALID;
1399 	spec->ema_rsrc.emar_eh_id.id = EFX_MAE_RSRC_ID_INVALID;
1400 	spec->ema_rsrc.emar_counter_id.id = EFX_MAE_RSRC_ID_INVALID;
1401 
1402 	/*
1403 	 * Helpers which populate v2 actions must reject them when v2 is not
1404 	 * supported. As they have no EFX NIC argument, save v2 status here.
1405 	 */
1406 	spec->ema_v2_is_supported = encp->enc_mae_aset_v2_supported;
1407 
1408 	*specp = spec;
1409 
1410 	return (0);
1411 
1412 fail1:
1413 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1414 	return (rc);
1415 }
1416 
1417 					void
1418 efx_mae_action_set_spec_fini(
1419 	__in				efx_nic_t *enp,
1420 	__in				efx_mae_actions_t *spec)
1421 {
1422 	EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec);
1423 }
1424 
1425 static	__checkReturn			efx_rc_t
1426 efx_mae_action_set_no_op(
1427 	__in				efx_mae_actions_t *spec,
1428 	__in				size_t arg_size,
1429 	__in_bcount(arg_size)		const uint8_t *arg)
1430 {
1431 	efx_rc_t rc;
1432 
1433 	_NOTE(ARGUNUSED(spec))
1434 
1435 	if (arg_size != 0) {
1436 		rc = EINVAL;
1437 		goto fail1;
1438 	}
1439 
1440 	if (arg != NULL) {
1441 		rc = EINVAL;
1442 		goto fail2;
1443 	}
1444 
1445 	/* This action does not have any arguments, so do nothing here. */
1446 
1447 	return (0);
1448 
1449 fail2:
1450 	EFSYS_PROBE(fail2);
1451 fail1:
1452 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1453 	return (rc);
1454 }
1455 
1456 static	__checkReturn			efx_rc_t
1457 efx_mae_action_set_add_vlan_pop(
1458 	__in				efx_mae_actions_t *spec,
1459 	__in				size_t arg_size,
1460 	__in_bcount(arg_size)		const uint8_t *arg)
1461 {
1462 	efx_rc_t rc;
1463 
1464 	if (arg_size != 0) {
1465 		rc = EINVAL;
1466 		goto fail1;
1467 	}
1468 
1469 	if (arg != NULL) {
1470 		rc = EINVAL;
1471 		goto fail2;
1472 	}
1473 
1474 	if (spec->ema_n_vlan_tags_to_pop == EFX_MAE_VLAN_POP_MAX_NTAGS) {
1475 		rc = ENOTSUP;
1476 		goto fail3;
1477 	}
1478 
1479 	++spec->ema_n_vlan_tags_to_pop;
1480 
1481 	return (0);
1482 
1483 fail3:
1484 	EFSYS_PROBE(fail3);
1485 fail2:
1486 	EFSYS_PROBE(fail2);
1487 fail1:
1488 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1489 	return (rc);
1490 }
1491 
1492 static	__checkReturn			efx_rc_t
1493 efx_mae_action_set_add_vlan_push(
1494 	__in				efx_mae_actions_t *spec,
1495 	__in				size_t arg_size,
1496 	__in_bcount(arg_size)		const uint8_t *arg)
1497 {
1498 	unsigned int n_tags = spec->ema_n_vlan_tags_to_push;
1499 	efx_rc_t rc;
1500 
1501 	if (arg_size != sizeof (*spec->ema_vlan_push_descs)) {
1502 		rc = EINVAL;
1503 		goto fail1;
1504 	}
1505 
1506 	if (arg == NULL) {
1507 		rc = EINVAL;
1508 		goto fail2;
1509 	}
1510 
1511 	if (n_tags == EFX_MAE_VLAN_PUSH_MAX_NTAGS) {
1512 		rc = ENOTSUP;
1513 		goto fail3;
1514 	}
1515 
1516 	memcpy(&spec->ema_vlan_push_descs[n_tags], arg, arg_size);
1517 	++(spec->ema_n_vlan_tags_to_push);
1518 
1519 	return (0);
1520 
1521 fail3:
1522 	EFSYS_PROBE(fail3);
1523 fail2:
1524 	EFSYS_PROBE(fail2);
1525 fail1:
1526 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1527 	return (rc);
1528 }
1529 
1530 static	__checkReturn			efx_rc_t
1531 efx_mae_action_set_add_count(
1532 	__in				efx_mae_actions_t *spec,
1533 	__in				size_t arg_size,
1534 	__in_bcount(arg_size)		const uint8_t *arg)
1535 {
1536 	efx_rc_t rc;
1537 
1538 	EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
1539 			  MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_NULL);
1540 
1541 	/*
1542 	 * Preparing an action set spec to update a counter requires
1543 	 * two steps: first add this action to the action spec, and then
1544 	 * add the counter ID to the spec. This allows validity checking
1545 	 * and resource allocation to be done separately.
1546 	 *
1547 	 * In order to fill in the counter ID, the caller is supposed to invoke
1548 	 * efx_mae_action_set_fill_in_counter_id(). If they do not do that,
1549 	 * efx_mae_action_set_alloc() invocation will throw an error.
1550 	 *
1551 	 * For now, no arguments are supposed to be handled.
1552 	 */
1553 
1554 	if (arg_size != 0) {
1555 		rc = EINVAL;
1556 		goto fail1;
1557 	}
1558 
1559 	if (arg != NULL) {
1560 		rc = EINVAL;
1561 		goto fail2;
1562 	}
1563 
1564 	++(spec->ema_n_count_actions);
1565 
1566 	return (0);
1567 
1568 fail2:
1569 	EFSYS_PROBE(fail2);
1570 fail1:
1571 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1572 	return (rc);
1573 }
1574 
1575 static	__checkReturn			efx_rc_t
1576 efx_mae_action_set_add_mark(
1577 	__in				efx_mae_actions_t *spec,
1578 	__in				size_t arg_size,
1579 	__in_bcount(arg_size)		const uint8_t *arg)
1580 {
1581 	efx_rc_t rc;
1582 
1583 	if (arg_size != sizeof (spec->ema_mark_value)) {
1584 		rc = EINVAL;
1585 		goto fail1;
1586 	}
1587 
1588 	if (arg == NULL) {
1589 		rc = EINVAL;
1590 		goto fail2;
1591 	}
1592 
1593 	memcpy(&spec->ema_mark_value, arg, arg_size);
1594 
1595 	return (0);
1596 
1597 fail2:
1598 	EFSYS_PROBE(fail2);
1599 fail1:
1600 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1601 	return (rc);
1602 }
1603 
1604 static	__checkReturn			efx_rc_t
1605 efx_mae_action_set_add_deliver(
1606 	__in				efx_mae_actions_t *spec,
1607 	__in				size_t arg_size,
1608 	__in_bcount(arg_size)		const uint8_t *arg)
1609 {
1610 	efx_rc_t rc;
1611 
1612 	if (arg_size != sizeof (spec->ema_deliver_mport)) {
1613 		rc = EINVAL;
1614 		goto fail1;
1615 	}
1616 
1617 	if (arg == NULL) {
1618 		rc = EINVAL;
1619 		goto fail2;
1620 	}
1621 
1622 	memcpy(&spec->ema_deliver_mport, arg, arg_size);
1623 
1624 	return (0);
1625 
1626 fail2:
1627 	EFSYS_PROBE(fail2);
1628 fail1:
1629 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1630 	return (rc);
1631 }
1632 
1633 typedef struct efx_mae_action_desc_s {
1634 	/* Action specific handler */
1635 	efx_rc_t	(*emad_add)(efx_mae_actions_t *,
1636 				    size_t, const uint8_t *);
1637 } efx_mae_action_desc_t;
1638 
1639 static const efx_mae_action_desc_t efx_mae_actions[EFX_MAE_NACTIONS] = {
1640 	[EFX_MAE_ACTION_DECAP] = {
1641 		.emad_add = efx_mae_action_set_no_op
1642 	},
1643 	[EFX_MAE_ACTION_VLAN_POP] = {
1644 		.emad_add = efx_mae_action_set_add_vlan_pop
1645 	},
1646 	[EFX_MAE_ACTION_SET_DST_MAC] = {
1647 		.emad_add = efx_mae_action_set_no_op
1648 	},
1649 	[EFX_MAE_ACTION_SET_SRC_MAC] = {
1650 		.emad_add = efx_mae_action_set_no_op
1651 	},
1652 	[EFX_MAE_ACTION_DECR_IP_TTL] = {
1653 		.emad_add = efx_mae_action_set_no_op
1654 	},
1655 	[EFX_MAE_ACTION_VLAN_PUSH] = {
1656 		.emad_add = efx_mae_action_set_add_vlan_push
1657 	},
1658 	[EFX_MAE_ACTION_ENCAP] = {
1659 		.emad_add = efx_mae_action_set_no_op
1660 	},
1661 	[EFX_MAE_ACTION_COUNT] = {
1662 		.emad_add = efx_mae_action_set_add_count
1663 	},
1664 	[EFX_MAE_ACTION_FLAG] = {
1665 		.emad_add = efx_mae_action_set_no_op
1666 	},
1667 	[EFX_MAE_ACTION_MARK] = {
1668 		.emad_add = efx_mae_action_set_add_mark
1669 	},
1670 	[EFX_MAE_ACTION_DELIVER] = {
1671 		.emad_add = efx_mae_action_set_add_deliver
1672 	}
1673 };
1674 
1675 static const uint32_t efx_mae_action_ordered_map =
1676 	(1U << EFX_MAE_ACTION_DECAP) |
1677 	(1U << EFX_MAE_ACTION_VLAN_POP) |
1678 	(1U << EFX_MAE_ACTION_SET_DST_MAC) |
1679 	(1U << EFX_MAE_ACTION_SET_SRC_MAC) |
1680 	(1U << EFX_MAE_ACTION_DECR_IP_TTL) |
1681 	(1U << EFX_MAE_ACTION_VLAN_PUSH) |
1682 	/*
1683 	 * HW will conduct action COUNT after
1684 	 * the matching packet has been modified by
1685 	 * length-affecting actions except for ENCAP.
1686 	 */
1687 	(1U << EFX_MAE_ACTION_COUNT) |
1688 	(1U << EFX_MAE_ACTION_ENCAP) |
1689 	(1U << EFX_MAE_ACTION_FLAG) |
1690 	(1U << EFX_MAE_ACTION_MARK) |
1691 	(1U << EFX_MAE_ACTION_DELIVER);
1692 
1693 /*
1694  * These actions must not be added after DELIVER, but
1695  * they can have any place among the rest of
1696  * strictly ordered actions.
1697  */
1698 static const uint32_t efx_mae_action_nonstrict_map =
1699 	(1U << EFX_MAE_ACTION_COUNT) |
1700 	(1U << EFX_MAE_ACTION_FLAG) |
1701 	(1U << EFX_MAE_ACTION_MARK);
1702 
1703 static const uint32_t efx_mae_action_repeat_map =
1704 	(1U << EFX_MAE_ACTION_VLAN_POP) |
1705 	(1U << EFX_MAE_ACTION_VLAN_PUSH) |
1706 	(1U << EFX_MAE_ACTION_COUNT);
1707 
1708 /*
1709  * Add an action to an action set.
1710  *
1711  * This has to be invoked in the desired action order.
1712  * An out-of-order action request will be turned down.
1713  */
1714 static	__checkReturn			efx_rc_t
1715 efx_mae_action_set_spec_populate(
1716 	__in				efx_mae_actions_t *spec,
1717 	__in				efx_mae_action_t type,
1718 	__in				size_t arg_size,
1719 	__in_bcount(arg_size)		const uint8_t *arg)
1720 {
1721 	uint32_t action_mask;
1722 	efx_rc_t rc;
1723 
1724 	EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <=
1725 	    (sizeof (efx_mae_action_ordered_map) * 8));
1726 	EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <=
1727 	    (sizeof (efx_mae_action_repeat_map) * 8));
1728 
1729 	EFX_STATIC_ASSERT(EFX_MAE_ACTION_DELIVER + 1 == EFX_MAE_NACTIONS);
1730 	EFX_STATIC_ASSERT(EFX_MAE_ACTION_FLAG + 1 == EFX_MAE_ACTION_MARK);
1731 	EFX_STATIC_ASSERT(EFX_MAE_ACTION_MARK + 1 == EFX_MAE_ACTION_DELIVER);
1732 
1733 	if (type >= EFX_ARRAY_SIZE(efx_mae_actions)) {
1734 		rc = EINVAL;
1735 		goto fail1;
1736 	}
1737 
1738 	action_mask = (1U << type);
1739 
1740 	if ((spec->ema_actions & action_mask) != 0) {
1741 		/* The action set already contains this action. */
1742 		if ((efx_mae_action_repeat_map & action_mask) == 0) {
1743 			/* Cannot add another non-repeatable action. */
1744 			rc = ENOTSUP;
1745 			goto fail2;
1746 		}
1747 	}
1748 
1749 	if ((efx_mae_action_ordered_map & action_mask) != 0) {
1750 		uint32_t strict_ordered_map =
1751 		    efx_mae_action_ordered_map & ~efx_mae_action_nonstrict_map;
1752 		uint32_t later_actions_mask =
1753 		    strict_ordered_map & ~(action_mask | (action_mask - 1));
1754 
1755 		if ((spec->ema_actions & later_actions_mask) != 0) {
1756 			/* Cannot add an action after later ordered actions. */
1757 			rc = ENOTSUP;
1758 			goto fail3;
1759 		}
1760 	}
1761 
1762 	if (efx_mae_actions[type].emad_add != NULL) {
1763 		rc = efx_mae_actions[type].emad_add(spec, arg_size, arg);
1764 		if (rc != 0)
1765 			goto fail4;
1766 	}
1767 
1768 	spec->ema_actions |= action_mask;
1769 
1770 	return (0);
1771 
1772 fail4:
1773 	EFSYS_PROBE(fail4);
1774 fail3:
1775 	EFSYS_PROBE(fail3);
1776 fail2:
1777 	EFSYS_PROBE(fail2);
1778 fail1:
1779 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1780 	return (rc);
1781 }
1782 
1783 	__checkReturn			efx_rc_t
1784 efx_mae_action_set_populate_decap(
1785 	__in				efx_mae_actions_t *spec)
1786 {
1787 	return (efx_mae_action_set_spec_populate(spec,
1788 	    EFX_MAE_ACTION_DECAP, 0, NULL));
1789 }
1790 
1791 	__checkReturn			efx_rc_t
1792 efx_mae_action_set_populate_vlan_pop(
1793 	__in				efx_mae_actions_t *spec)
1794 {
1795 	return (efx_mae_action_set_spec_populate(spec,
1796 	    EFX_MAE_ACTION_VLAN_POP, 0, NULL));
1797 }
1798 
1799 	__checkReturn			efx_rc_t
1800 efx_mae_action_set_populate_set_dst_mac(
1801 	__in				efx_mae_actions_t *spec)
1802 {
1803 	efx_rc_t rc;
1804 
1805 	if (spec->ema_v2_is_supported == B_FALSE) {
1806 		rc = ENOTSUP;
1807 		goto fail1;
1808 	}
1809 
1810 	return (efx_mae_action_set_spec_populate(spec,
1811 	    EFX_MAE_ACTION_SET_DST_MAC, 0, NULL));
1812 
1813 fail1:
1814 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1815 	return (rc);
1816 }
1817 
1818 	__checkReturn			efx_rc_t
1819 efx_mae_action_set_populate_set_src_mac(
1820 	__in				efx_mae_actions_t *spec)
1821 {
1822 	efx_rc_t rc;
1823 
1824 	if (spec->ema_v2_is_supported == B_FALSE) {
1825 		rc = ENOTSUP;
1826 		goto fail1;
1827 	}
1828 
1829 	return (efx_mae_action_set_spec_populate(spec,
1830 	    EFX_MAE_ACTION_SET_SRC_MAC, 0, NULL));
1831 
1832 fail1:
1833 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1834 	return (rc);
1835 }
1836 
1837 	__checkReturn			efx_rc_t
1838 efx_mae_action_set_populate_decr_ip_ttl(
1839 	__in				efx_mae_actions_t *spec)
1840 {
1841 	efx_rc_t rc;
1842 
1843 	if (spec->ema_v2_is_supported == B_FALSE) {
1844 		rc = ENOTSUP;
1845 		goto fail1;
1846 	}
1847 
1848 	return (efx_mae_action_set_spec_populate(spec,
1849 	    EFX_MAE_ACTION_DECR_IP_TTL, 0, NULL));
1850 
1851 fail1:
1852 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1853 	return (rc);
1854 }
1855 
1856 	__checkReturn			efx_rc_t
1857 efx_mae_action_set_populate_vlan_push(
1858 	__in				efx_mae_actions_t *spec,
1859 	__in				uint16_t tpid_be,
1860 	__in				uint16_t tci_be)
1861 {
1862 	efx_mae_action_vlan_push_t action;
1863 	const uint8_t *arg = (const uint8_t *)&action;
1864 
1865 	action.emavp_tpid_be = tpid_be;
1866 	action.emavp_tci_be = tci_be;
1867 
1868 	return (efx_mae_action_set_spec_populate(spec,
1869 	    EFX_MAE_ACTION_VLAN_PUSH, sizeof (action), arg));
1870 }
1871 
1872 	__checkReturn			efx_rc_t
1873 efx_mae_action_set_populate_encap(
1874 	__in				efx_mae_actions_t *spec)
1875 {
1876 	/*
1877 	 * There is no argument to pass encap. header ID, thus, one does not
1878 	 * need to allocate an encap. header while parsing application input.
1879 	 * This is useful since building an action set may be done simply to
1880 	 * validate a rule, whilst resource allocation usually consumes time.
1881 	 */
1882 	return (efx_mae_action_set_spec_populate(spec,
1883 	    EFX_MAE_ACTION_ENCAP, 0, NULL));
1884 }
1885 
1886 	__checkReturn			efx_rc_t
1887 efx_mae_action_set_populate_count(
1888 	__in				efx_mae_actions_t *spec)
1889 {
1890 	/*
1891 	 * There is no argument to pass counter ID, thus, one does not
1892 	 * need to allocate a counter while parsing application input.
1893 	 * This is useful since building an action set may be done simply to
1894 	 * validate a rule, whilst resource allocation usually consumes time.
1895 	 */
1896 	return (efx_mae_action_set_spec_populate(spec,
1897 	    EFX_MAE_ACTION_COUNT, 0, NULL));
1898 }
1899 
1900 	__checkReturn			efx_rc_t
1901 efx_mae_action_set_populate_flag(
1902 	__in				efx_mae_actions_t *spec)
1903 {
1904 	return (efx_mae_action_set_spec_populate(spec,
1905 	    EFX_MAE_ACTION_FLAG, 0, NULL));
1906 }
1907 
1908 	__checkReturn			efx_rc_t
1909 efx_mae_action_set_populate_mark(
1910 	__in				efx_mae_actions_t *spec,
1911 	__in				uint32_t mark_value)
1912 {
1913 	const uint8_t *arg = (const uint8_t *)&mark_value;
1914 
1915 	return (efx_mae_action_set_spec_populate(spec,
1916 	    EFX_MAE_ACTION_MARK, sizeof (mark_value), arg));
1917 }
1918 
1919 	__checkReturn			efx_rc_t
1920 efx_mae_action_set_populate_deliver(
1921 	__in				efx_mae_actions_t *spec,
1922 	__in				const efx_mport_sel_t *mportp)
1923 {
1924 	const uint8_t *arg;
1925 	efx_rc_t rc;
1926 
1927 	if (mportp == NULL) {
1928 		rc = EINVAL;
1929 		goto fail1;
1930 	}
1931 
1932 	arg = (const uint8_t *)&mportp->sel;
1933 
1934 	return (efx_mae_action_set_spec_populate(spec,
1935 	    EFX_MAE_ACTION_DELIVER, sizeof (mportp->sel), arg));
1936 
1937 fail1:
1938 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1939 	return (rc);
1940 }
1941 
1942 	__checkReturn			efx_rc_t
1943 efx_mae_action_set_populate_drop(
1944 	__in				efx_mae_actions_t *spec)
1945 {
1946 	efx_mport_sel_t mport;
1947 	const uint8_t *arg;
1948 	efx_dword_t dword;
1949 
1950 	EFX_POPULATE_DWORD_1(dword,
1951 	    MAE_MPORT_SELECTOR_FLAT, MAE_MPORT_SELECTOR_NULL);
1952 
1953 	/*
1954 	 * The constructed DWORD is little-endian,
1955 	 * but the resulting value is meant to be
1956 	 * passed to MCDIs, where it will undergo
1957 	 * host-order to little endian conversion.
1958 	 */
1959 	mport.sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
1960 
1961 	arg = (const uint8_t *)&mport.sel;
1962 
1963 	return (efx_mae_action_set_spec_populate(spec,
1964 	    EFX_MAE_ACTION_DELIVER, sizeof (mport.sel), arg));
1965 }
1966 
1967 	__checkReturn			boolean_t
1968 efx_mae_action_set_specs_equal(
1969 	__in				const efx_mae_actions_t *left,
1970 	__in				const efx_mae_actions_t *right)
1971 {
1972 	size_t cmp_size = EFX_FIELD_OFFSET(efx_mae_actions_t, ema_rsrc);
1973 
1974 	/*
1975 	 * An action set specification consists of two parts. The first part
1976 	 * indicates what actions are included in the action set, as well as
1977 	 * extra quantitative values (in example, the number of VLAN tags to
1978 	 * push). The second part comprises resource IDs used by the actions.
1979 	 *
1980 	 * A resource, in example, a counter, is allocated from the hardware
1981 	 * by the client, and it's the client who is responsible for keeping
1982 	 * track of allocated resources and comparing resource IDs if needed.
1983 	 *
1984 	 * In this API, don't compare resource IDs in the two specifications.
1985 	 */
1986 
1987 	return ((memcmp(left, right, cmp_size) == 0) ? B_TRUE : B_FALSE);
1988 }
1989 
1990 	__checkReturn			efx_rc_t
1991 efx_mae_match_specs_class_cmp(
1992 	__in				efx_nic_t *enp,
1993 	__in				const efx_mae_match_spec_t *left,
1994 	__in				const efx_mae_match_spec_t *right,
1995 	__out				boolean_t *have_same_classp)
1996 {
1997 	efx_mae_t *maep = enp->en_maep;
1998 	unsigned int field_ncaps = maep->em_max_nfields;
1999 	const efx_mae_field_cap_t *field_caps;
2000 	const efx_mae_mv_desc_t *desc_setp;
2001 	unsigned int desc_set_nentries;
2002 	const efx_mae_mv_bit_desc_t *bit_desc_setp;
2003 	unsigned int bit_desc_set_nentries;
2004 	boolean_t have_same_class = B_TRUE;
2005 	efx_mae_field_id_t field_id;
2006 	const uint8_t *mvpl;
2007 	const uint8_t *mvpr;
2008 	efx_rc_t rc;
2009 
2010 	switch (left->emms_type) {
2011 	case EFX_MAE_RULE_OUTER:
2012 		field_caps = maep->em_outer_rule_field_caps;
2013 		desc_setp = __efx_mae_outer_rule_mv_desc_set;
2014 		desc_set_nentries =
2015 		    EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
2016 		bit_desc_setp = __efx_mae_outer_rule_mv_bit_desc_set;
2017 		bit_desc_set_nentries =
2018 		    EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_bit_desc_set);
2019 		mvpl = left->emms_mask_value_pairs.outer;
2020 		mvpr = right->emms_mask_value_pairs.outer;
2021 		break;
2022 	case EFX_MAE_RULE_ACTION:
2023 		field_caps = maep->em_action_rule_field_caps;
2024 		desc_setp = __efx_mae_action_rule_mv_desc_set;
2025 		desc_set_nentries =
2026 		    EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
2027 		bit_desc_setp = __efx_mae_action_rule_mv_bit_desc_set;
2028 		bit_desc_set_nentries =
2029 		    EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_bit_desc_set);
2030 		mvpl = left->emms_mask_value_pairs.action;
2031 		mvpr = right->emms_mask_value_pairs.action;
2032 		break;
2033 	default:
2034 		rc = ENOTSUP;
2035 		goto fail1;
2036 	}
2037 
2038 	if (field_caps == NULL) {
2039 		rc = EAGAIN;
2040 		goto fail2;
2041 	}
2042 
2043 	if (left->emms_type != right->emms_type ||
2044 	    left->emms_prio != right->emms_prio) {
2045 		/*
2046 		 * Rules of different types can never map to the same class.
2047 		 *
2048 		 * The FW can support some set of match criteria for one
2049 		 * priority and not support the very same set for
2050 		 * another priority. Thus, two rules which have
2051 		 * different priorities can never map to
2052 		 * the same class.
2053 		 */
2054 		*have_same_classp = B_FALSE;
2055 		return (0);
2056 	}
2057 
2058 	for (field_id = 0; (unsigned int)field_id < desc_set_nentries;
2059 	     ++field_id) {
2060 		const efx_mae_mv_desc_t *descp = &desc_setp[field_id];
2061 		efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id;
2062 		const uint8_t *lmaskp = mvpl + descp->emmd_mask_offset;
2063 		const uint8_t *rmaskp = mvpr + descp->emmd_mask_offset;
2064 		size_t mask_size = descp->emmd_mask_size;
2065 		const uint8_t *lvalp = mvpl + descp->emmd_value_offset;
2066 		const uint8_t *rvalp = mvpr + descp->emmd_value_offset;
2067 		size_t value_size = descp->emmd_value_size;
2068 
2069 		if (mask_size == 0)
2070 			continue; /* Skip array gap */
2071 
2072 		if ((unsigned int)field_cap_id >= field_ncaps) {
2073 			/*
2074 			 * The FW has not reported capability status for this
2075 			 * field. It's unknown whether any difference between
2076 			 * the two masks / values affects the class. The only
2077 			 * case when the class must be the same is when these
2078 			 * mask-value pairs match. Otherwise, report mismatch.
2079 			 */
2080 			if ((memcmp(lmaskp, rmaskp, mask_size) == 0) &&
2081 			    (memcmp(lvalp, rvalp, value_size) == 0))
2082 				continue;
2083 			else
2084 				break;
2085 		}
2086 
2087 		if (field_caps[field_cap_id].emfc_mask_affects_class) {
2088 			if (memcmp(lmaskp, rmaskp, mask_size) != 0) {
2089 				have_same_class = B_FALSE;
2090 				break;
2091 			}
2092 		}
2093 
2094 		if (field_caps[field_cap_id].emfc_match_affects_class) {
2095 			if (memcmp(lvalp, rvalp, value_size) != 0) {
2096 				have_same_class = B_FALSE;
2097 				break;
2098 			}
2099 		}
2100 	}
2101 
2102 	if (have_same_class == B_FALSE)
2103 		goto done;
2104 
2105 	for (field_id = 0; (unsigned int)field_id < bit_desc_set_nentries;
2106 	     ++field_id) {
2107 		const efx_mae_mv_bit_desc_t *bit_descp =
2108 		    &bit_desc_setp[field_id];
2109 		efx_mae_field_cap_id_t bit_cap_id =
2110 		    bit_descp->emmbd_bit_cap_id;
2111 		unsigned int byte_idx;
2112 		unsigned int bit_idx;
2113 
2114 		if (bit_descp->emmbd_entry_is_valid == B_FALSE)
2115 			continue; /* Skip array gap */
2116 
2117 		if ((unsigned int)bit_cap_id >= field_ncaps)
2118 			break;
2119 
2120 		byte_idx =
2121 		    bit_descp->emmbd_mask_ofst +
2122 		    bit_descp->emmbd_mask_lbn / 8;
2123 		bit_idx =
2124 		    bit_descp->emmbd_mask_lbn % 8;
2125 
2126 		if (field_caps[bit_cap_id].emfc_mask_affects_class &&
2127 		    (mvpl[byte_idx] & (1U << bit_idx)) !=
2128 		    (mvpr[byte_idx] & (1U << bit_idx))) {
2129 			have_same_class = B_FALSE;
2130 			break;
2131 		}
2132 
2133 		byte_idx =
2134 		    bit_descp->emmbd_value_ofst +
2135 		    bit_descp->emmbd_value_lbn / 8;
2136 		bit_idx =
2137 		    bit_descp->emmbd_value_lbn % 8;
2138 
2139 		if (field_caps[bit_cap_id].emfc_match_affects_class &&
2140 		    (mvpl[byte_idx] & (1U << bit_idx)) !=
2141 		    (mvpr[byte_idx] & (1U << bit_idx))) {
2142 			have_same_class = B_FALSE;
2143 			break;
2144 		}
2145 	}
2146 
2147 done:
2148 	*have_same_classp = have_same_class;
2149 
2150 	return (0);
2151 
2152 fail2:
2153 	EFSYS_PROBE(fail2);
2154 fail1:
2155 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2156 	return (rc);
2157 }
2158 
2159 	__checkReturn			efx_rc_t
2160 efx_mae_outer_rule_recirc_id_set(
2161 	__in				efx_mae_match_spec_t *spec,
2162 	__in				uint8_t recirc_id)
2163 {
2164 	efx_rc_t rc;
2165 
2166 	if (spec->emms_type != EFX_MAE_RULE_OUTER) {
2167 		rc = EINVAL;
2168 		goto fail1;
2169 	}
2170 
2171 	spec->emms_outer_rule_recirc_id = recirc_id;
2172 
2173 	return (0);
2174 
2175 fail1:
2176 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2177 	return (rc);
2178 }
2179 
2180 	__checkReturn		efx_rc_t
2181 efx_mae_outer_rule_insert(
2182 	__in			efx_nic_t *enp,
2183 	__in			const efx_mae_match_spec_t *spec,
2184 	__in			efx_tunnel_protocol_t encap_type,
2185 	__out			efx_mae_rule_id_t *or_idp)
2186 {
2187 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2188 	efx_mcdi_req_t req;
2189 	EFX_MCDI_DECLARE_BUF(payload,
2190 	    MC_CMD_MAE_OUTER_RULE_INSERT_IN_LENMAX_MCDI2,
2191 	    MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN);
2192 	uint32_t encap_type_mcdi;
2193 	efx_mae_rule_id_t or_id;
2194 	size_t offset;
2195 	efx_rc_t rc;
2196 
2197 	EFX_STATIC_ASSERT(sizeof (or_idp->id) ==
2198 	    MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OR_ID_LEN);
2199 
2200 	EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
2201 	    MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OUTER_RULE_ID_NULL);
2202 
2203 	if (encp->enc_mae_supported == B_FALSE) {
2204 		rc = ENOTSUP;
2205 		goto fail1;
2206 	}
2207 
2208 	if (spec->emms_type != EFX_MAE_RULE_OUTER) {
2209 		rc = EINVAL;
2210 		goto fail2;
2211 	}
2212 
2213 	switch (encap_type) {
2214 	case EFX_TUNNEL_PROTOCOL_NONE:
2215 		encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NONE;
2216 		break;
2217 	case EFX_TUNNEL_PROTOCOL_VXLAN:
2218 		encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_VXLAN;
2219 		break;
2220 	case EFX_TUNNEL_PROTOCOL_GENEVE:
2221 		encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_GENEVE;
2222 		break;
2223 	case EFX_TUNNEL_PROTOCOL_NVGRE:
2224 		encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NVGRE;
2225 		break;
2226 	default:
2227 		rc = ENOTSUP;
2228 		goto fail3;
2229 	}
2230 
2231 	req.emr_cmd = MC_CMD_MAE_OUTER_RULE_INSERT;
2232 	req.emr_in_buf = payload;
2233 	req.emr_in_length = MC_CMD_MAE_OUTER_RULE_INSERT_IN_LENMAX_MCDI2;
2234 	req.emr_out_buf = payload;
2235 	req.emr_out_length = MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN;
2236 
2237 	MCDI_IN_SET_DWORD(req,
2238 	    MAE_OUTER_RULE_INSERT_IN_ENCAP_TYPE, encap_type_mcdi);
2239 
2240 	MCDI_IN_SET_DWORD(req, MAE_OUTER_RULE_INSERT_IN_PRIO, spec->emms_prio);
2241 
2242 	/*
2243 	 * Mask-value pairs have been stored in the byte order needed for the
2244 	 * MCDI request and are thus safe to be copied directly to the buffer.
2245 	 * The library cares about byte order in efx_mae_match_spec_field_set().
2246 	 */
2247 	EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.outer) >=
2248 	    MAE_ENC_FIELD_PAIRS_LEN);
2249 	offset = MC_CMD_MAE_OUTER_RULE_INSERT_IN_FIELD_MATCH_CRITERIA_OFST;
2250 	memcpy(payload + offset, spec->emms_mask_value_pairs.outer,
2251 	    MAE_ENC_FIELD_PAIRS_LEN);
2252 
2253 	MCDI_IN_SET_DWORD_FIELD(req, MAE_OUTER_RULE_INSERT_IN_LOOKUP_CONTROL,
2254 	    MAE_OUTER_RULE_INSERT_IN_RECIRC_ID,
2255 	    spec->emms_outer_rule_recirc_id);
2256 
2257 	efx_mcdi_execute(enp, &req);
2258 
2259 	if (req.emr_rc != 0) {
2260 		rc = req.emr_rc;
2261 		goto fail4;
2262 	}
2263 
2264 	if (req.emr_out_length_used < MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN) {
2265 		rc = EMSGSIZE;
2266 		goto fail5;
2267 	}
2268 
2269 	or_id.id = MCDI_OUT_DWORD(req, MAE_OUTER_RULE_INSERT_OUT_OR_ID);
2270 	if (or_id.id == EFX_MAE_RSRC_ID_INVALID) {
2271 		rc = ENOENT;
2272 		goto fail6;
2273 	}
2274 
2275 	or_idp->id = or_id.id;
2276 
2277 	return (0);
2278 
2279 fail6:
2280 	EFSYS_PROBE(fail6);
2281 fail5:
2282 	EFSYS_PROBE(fail5);
2283 fail4:
2284 	EFSYS_PROBE(fail4);
2285 fail3:
2286 	EFSYS_PROBE(fail3);
2287 fail2:
2288 	EFSYS_PROBE(fail2);
2289 fail1:
2290 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2291 	return (rc);
2292 }
2293 
2294 	__checkReturn		efx_rc_t
2295 efx_mae_outer_rule_remove(
2296 	__in			efx_nic_t *enp,
2297 	__in			const efx_mae_rule_id_t *or_idp)
2298 {
2299 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2300 	efx_mcdi_req_t req;
2301 	EFX_MCDI_DECLARE_BUF(payload,
2302 	    MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1),
2303 	    MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1));
2304 	efx_rc_t rc;
2305 
2306 	if (encp->enc_mae_supported == B_FALSE) {
2307 		rc = ENOTSUP;
2308 		goto fail1;
2309 	}
2310 
2311 	req.emr_cmd = MC_CMD_MAE_OUTER_RULE_REMOVE;
2312 	req.emr_in_buf = payload;
2313 	req.emr_in_length = MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1);
2314 	req.emr_out_buf = payload;
2315 	req.emr_out_length = MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1);
2316 
2317 	MCDI_IN_SET_DWORD(req, MAE_OUTER_RULE_REMOVE_IN_OR_ID, or_idp->id);
2318 
2319 	efx_mcdi_execute(enp, &req);
2320 
2321 	if (req.emr_rc != 0) {
2322 		rc = req.emr_rc;
2323 		goto fail2;
2324 	}
2325 
2326 	if (req.emr_out_length_used < MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LENMIN) {
2327 		rc = EMSGSIZE;
2328 		goto fail3;
2329 	}
2330 
2331 	if (MCDI_OUT_DWORD(req, MAE_OUTER_RULE_REMOVE_OUT_REMOVED_OR_ID) !=
2332 	    or_idp->id) {
2333 		/* Firmware failed to remove the outer rule. */
2334 		rc = EAGAIN;
2335 		goto fail4;
2336 	}
2337 
2338 	return (0);
2339 
2340 fail4:
2341 	EFSYS_PROBE(fail4);
2342 fail3:
2343 	EFSYS_PROBE(fail3);
2344 fail2:
2345 	EFSYS_PROBE(fail2);
2346 fail1:
2347 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2348 	return (rc);
2349 }
2350 
2351 	__checkReturn			efx_rc_t
2352 efx_mae_match_spec_outer_rule_id_set(
2353 	__in				efx_mae_match_spec_t *spec,
2354 	__in				const efx_mae_rule_id_t *or_idp)
2355 {
2356 	uint32_t full_mask = UINT32_MAX;
2357 	efx_rc_t rc;
2358 
2359 	if (spec->emms_type != EFX_MAE_RULE_ACTION) {
2360 		rc = EINVAL;
2361 		goto fail1;
2362 	}
2363 
2364 	if (or_idp == NULL) {
2365 		rc = EINVAL;
2366 		goto fail2;
2367 	}
2368 
2369 	rc = efx_mae_match_spec_field_set(spec, EFX_MAE_FIELD_OUTER_RULE_ID,
2370 	    sizeof (or_idp->id), (const uint8_t *)&or_idp->id,
2371 	    sizeof (full_mask), (const uint8_t *)&full_mask);
2372 	if (rc != 0)
2373 		goto fail3;
2374 
2375 	return (0);
2376 
2377 fail3:
2378 	EFSYS_PROBE(fail3);
2379 fail2:
2380 	EFSYS_PROBE(fail2);
2381 fail1:
2382 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2383 	return (rc);
2384 }
2385 
2386 	 __checkReturn	efx_rc_t
2387 efx_mae_mac_addr_alloc(
2388 	__in		efx_nic_t *enp,
2389 	__in		uint8_t addr_bytes[EFX_MAC_ADDR_LEN],
2390 	__out		efx_mae_mac_id_t *mac_idp)
2391 {
2392 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2393 	efx_mcdi_req_t req;
2394 	EFX_MCDI_DECLARE_BUF(payload,
2395 	    MC_CMD_MAE_MAC_ADDR_ALLOC_IN_LEN,
2396 	    MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_LEN);
2397 	efx_mae_mac_id_t mac_id;
2398 	efx_rc_t rc;
2399 
2400 	EFX_STATIC_ASSERT(sizeof (mac_idp->id) ==
2401 	    MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_LEN);
2402 
2403 	EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
2404 	    MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
2405 
2406 	if (encp->enc_mae_supported == B_FALSE) {
2407 		rc = ENOTSUP;
2408 		goto fail1;
2409 	}
2410 
2411 	if (encp->enc_mae_aset_v2_supported == B_FALSE) {
2412 		rc = ENOTSUP;
2413 		goto fail2;
2414 	}
2415 
2416 	req.emr_cmd = MC_CMD_MAE_MAC_ADDR_ALLOC;
2417 	req.emr_in_buf = payload;
2418 	req.emr_in_length = MC_CMD_MAE_MAC_ADDR_ALLOC_IN_LEN;
2419 	req.emr_out_buf = payload;
2420 	req.emr_out_length = MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_LEN;
2421 
2422 	memcpy(payload + MC_CMD_MAE_MAC_ADDR_ALLOC_IN_MAC_ADDR_OFST,
2423 	    addr_bytes, EFX_MAC_ADDR_LEN);
2424 
2425 	efx_mcdi_execute(enp, &req);
2426 
2427 	if (req.emr_rc != 0) {
2428 		rc = req.emr_rc;
2429 		goto fail3;
2430 	}
2431 
2432 	if (req.emr_out_length_used < MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_LEN) {
2433 		rc = EMSGSIZE;
2434 		goto fail4;
2435 	}
2436 
2437 	mac_id.id = MCDI_OUT_DWORD(req, MAE_MAC_ADDR_ALLOC_OUT_MAC_ID);
2438 	if (mac_id.id == EFX_MAE_RSRC_ID_INVALID) {
2439 		rc = ENOENT;
2440 		goto fail5;
2441 	}
2442 
2443 	mac_idp->id = mac_id.id;
2444 
2445 	return (0);
2446 
2447 fail5:
2448 	EFSYS_PROBE(fail5);
2449 fail4:
2450 	EFSYS_PROBE(fail4);
2451 fail3:
2452 	EFSYS_PROBE(fail3);
2453 fail2:
2454 	EFSYS_PROBE(fail2);
2455 fail1:
2456 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2457 	return (rc);
2458 }
2459 
2460 	__checkReturn	efx_rc_t
2461 efx_mae_mac_addr_free(
2462 	__in		efx_nic_t *enp,
2463 	__in		const efx_mae_mac_id_t *mac_idp)
2464 {
2465 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2466 	efx_mcdi_req_t req;
2467 	EFX_MCDI_DECLARE_BUF(payload,
2468 	    MC_CMD_MAE_MAC_ADDR_FREE_IN_LEN(1),
2469 	    MC_CMD_MAE_MAC_ADDR_FREE_OUT_LEN(1));
2470 	efx_rc_t rc;
2471 
2472 	if (encp->enc_mae_supported == B_FALSE) {
2473 		rc = ENOTSUP;
2474 		goto fail1;
2475 	}
2476 
2477 	if (encp->enc_mae_aset_v2_supported == B_FALSE) {
2478 		rc = ENOTSUP;
2479 		goto fail2;
2480 	}
2481 
2482 	req.emr_cmd = MC_CMD_MAE_MAC_ADDR_FREE;
2483 	req.emr_in_buf = payload;
2484 	req.emr_in_length = MC_CMD_MAE_MAC_ADDR_FREE_IN_LEN(1);
2485 	req.emr_out_buf = payload;
2486 	req.emr_out_length = MC_CMD_MAE_MAC_ADDR_FREE_OUT_LEN(1);
2487 
2488 	MCDI_IN_SET_DWORD(req, MAE_MAC_ADDR_FREE_IN_MAC_ID, mac_idp->id);
2489 
2490 	efx_mcdi_execute(enp, &req);
2491 
2492 	if (req.emr_rc != 0) {
2493 		rc = req.emr_rc;
2494 		goto fail3;
2495 	}
2496 
2497 	if (req.emr_out_length_used < MC_CMD_MAE_MAC_ADDR_FREE_OUT_LEN(1)) {
2498 		rc = EMSGSIZE;
2499 		goto fail4;
2500 	}
2501 
2502 	if (MCDI_OUT_DWORD(req, MAE_MAC_ADDR_FREE_OUT_FREED_MAC_ID) !=
2503 	    mac_idp->id) {
2504 		/* Firmware failed to remove the MAC address entry. */
2505 		rc = EAGAIN;
2506 		goto fail5;
2507 	}
2508 
2509 	return (0);
2510 
2511 fail5:
2512 	EFSYS_PROBE(fail5);
2513 fail4:
2514 	EFSYS_PROBE(fail4);
2515 fail3:
2516 	EFSYS_PROBE(fail3);
2517 fail2:
2518 	EFSYS_PROBE(fail2);
2519 fail1:
2520 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2521 	return (rc);
2522 }
2523 
2524 	__checkReturn			efx_rc_t
2525 efx_mae_action_set_fill_in_dst_mac_id(
2526 	__in				efx_mae_actions_t *spec,
2527 	__in				const efx_mae_mac_id_t *mac_idp)
2528 {
2529 	efx_rc_t rc;
2530 
2531 	if ((spec->ema_actions & (1U << EFX_MAE_ACTION_SET_DST_MAC)) == 0) {
2532 		/*
2533 		 * The caller has not intended to have this action originally,
2534 		 * hence, they cannot indicate the MAC address entry ID.
2535 		 */
2536 		rc = EINVAL;
2537 		goto fail1;
2538 	}
2539 
2540 	if (spec->ema_rsrc.emar_dst_mac_id.id != EFX_MAE_RSRC_ID_INVALID) {
2541 		/* An attempt to indicate the MAC address entry ID twice. */
2542 		rc = EINVAL;
2543 		goto fail2;
2544 	}
2545 
2546 	if (mac_idp->id == EFX_MAE_RSRC_ID_INVALID) {
2547 		rc = EINVAL;
2548 		goto fail3;
2549 	}
2550 
2551 	spec->ema_rsrc.emar_dst_mac_id.id = mac_idp->id;
2552 
2553 	return (0);
2554 
2555 fail3:
2556 	EFSYS_PROBE(fail3);
2557 fail2:
2558 	EFSYS_PROBE(fail2);
2559 fail1:
2560 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2561 	return (rc);
2562 }
2563 
2564 	__checkReturn			efx_rc_t
2565 efx_mae_action_set_fill_in_src_mac_id(
2566 	__in				efx_mae_actions_t *spec,
2567 	__in				const efx_mae_mac_id_t *mac_idp)
2568 {
2569 	efx_rc_t rc;
2570 
2571 	if ((spec->ema_actions & (1U << EFX_MAE_ACTION_SET_SRC_MAC)) == 0) {
2572 		/*
2573 		 * The caller has not intended to have this action originally,
2574 		 * hence, they cannot indicate the MAC address entry ID.
2575 		 */
2576 		rc = EINVAL;
2577 		goto fail1;
2578 	}
2579 
2580 	if (spec->ema_rsrc.emar_src_mac_id.id != EFX_MAE_RSRC_ID_INVALID) {
2581 		/* An attempt to indicate the MAC address entry ID twice. */
2582 		rc = EINVAL;
2583 		goto fail2;
2584 	}
2585 
2586 	if (mac_idp->id == EFX_MAE_RSRC_ID_INVALID) {
2587 		rc = EINVAL;
2588 		goto fail3;
2589 	}
2590 
2591 	spec->ema_rsrc.emar_src_mac_id.id = mac_idp->id;
2592 
2593 	return (0);
2594 
2595 fail3:
2596 	EFSYS_PROBE(fail3);
2597 fail2:
2598 	EFSYS_PROBE(fail2);
2599 fail1:
2600 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2601 	return (rc);
2602 }
2603 
2604 	 __checkReturn			efx_rc_t
2605 efx_mae_encap_header_alloc(
2606 	__in				efx_nic_t *enp,
2607 	__in				efx_tunnel_protocol_t encap_type,
2608 	__in_bcount(header_size)	uint8_t *header_data,
2609 	__in				size_t header_size,
2610 	__out				efx_mae_eh_id_t *eh_idp)
2611 {
2612 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2613 	efx_mcdi_req_t req;
2614 	EFX_MCDI_DECLARE_BUF(payload,
2615 	    MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LENMAX_MCDI2,
2616 	    MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN);
2617 	uint32_t encap_type_mcdi;
2618 	efx_mae_eh_id_t eh_id;
2619 	efx_rc_t rc;
2620 
2621 	EFX_STATIC_ASSERT(sizeof (eh_idp->id) ==
2622 	    MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_LEN);
2623 
2624 	EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
2625 	    MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_NULL);
2626 
2627 	if (encp->enc_mae_supported == B_FALSE) {
2628 		rc = ENOTSUP;
2629 		goto fail1;
2630 	}
2631 
2632 	switch (encap_type) {
2633 	case EFX_TUNNEL_PROTOCOL_NONE:
2634 		encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NONE;
2635 		break;
2636 	case EFX_TUNNEL_PROTOCOL_VXLAN:
2637 		encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_VXLAN;
2638 		break;
2639 	case EFX_TUNNEL_PROTOCOL_GENEVE:
2640 		encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_GENEVE;
2641 		break;
2642 	case EFX_TUNNEL_PROTOCOL_NVGRE:
2643 		encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NVGRE;
2644 		break;
2645 	default:
2646 		rc = ENOTSUP;
2647 		goto fail2;
2648 	}
2649 
2650 	if (header_size >
2651 	    MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_MAXNUM_MCDI2) {
2652 		rc = EINVAL;
2653 		goto fail3;
2654 	}
2655 
2656 	req.emr_cmd = MC_CMD_MAE_ENCAP_HEADER_ALLOC;
2657 	req.emr_in_buf = payload;
2658 	req.emr_in_length = MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LEN(header_size);
2659 	req.emr_out_buf = payload;
2660 	req.emr_out_length = MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN;
2661 
2662 	MCDI_IN_SET_DWORD(req,
2663 	    MAE_ENCAP_HEADER_ALLOC_IN_ENCAP_TYPE, encap_type_mcdi);
2664 
2665 	memcpy(payload + MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_OFST,
2666 	    header_data, header_size);
2667 
2668 	efx_mcdi_execute(enp, &req);
2669 
2670 	if (req.emr_rc != 0) {
2671 		rc = req.emr_rc;
2672 		goto fail4;
2673 	}
2674 
2675 	if (req.emr_out_length_used < MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN) {
2676 		rc = EMSGSIZE;
2677 		goto fail5;
2678 	}
2679 
2680 	eh_id.id = MCDI_OUT_DWORD(req,
2681 	    MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID);
2682 
2683 	if (eh_id.id == EFX_MAE_RSRC_ID_INVALID) {
2684 		rc = ENOENT;
2685 		goto fail6;
2686 	}
2687 
2688 	eh_idp->id = eh_id.id;
2689 
2690 	return (0);
2691 
2692 fail6:
2693 	EFSYS_PROBE(fail6);
2694 fail5:
2695 	EFSYS_PROBE(fail5);
2696 fail4:
2697 	EFSYS_PROBE(fail4);
2698 fail3:
2699 	EFSYS_PROBE(fail3);
2700 fail2:
2701 	EFSYS_PROBE(fail2);
2702 fail1:
2703 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2704 	return (rc);
2705 }
2706 
2707 	__checkReturn			efx_rc_t
2708 efx_mae_encap_header_free(
2709 	__in				efx_nic_t *enp,
2710 	__in				const efx_mae_eh_id_t *eh_idp)
2711 {
2712 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2713 	efx_mcdi_req_t req;
2714 	EFX_MCDI_DECLARE_BUF(payload,
2715 	    MC_CMD_MAE_ENCAP_HEADER_FREE_IN_LEN(1),
2716 	    MC_CMD_MAE_ENCAP_HEADER_FREE_OUT_LEN(1));
2717 	efx_rc_t rc;
2718 
2719 	if (encp->enc_mae_supported == B_FALSE) {
2720 		rc = ENOTSUP;
2721 		goto fail1;
2722 	}
2723 
2724 	req.emr_cmd = MC_CMD_MAE_ENCAP_HEADER_FREE;
2725 	req.emr_in_buf = payload;
2726 	req.emr_in_length = MC_CMD_MAE_ENCAP_HEADER_FREE_IN_LEN(1);
2727 	req.emr_out_buf = payload;
2728 	req.emr_out_length = MC_CMD_MAE_ENCAP_HEADER_FREE_OUT_LEN(1);
2729 
2730 	MCDI_IN_SET_DWORD(req, MAE_ENCAP_HEADER_FREE_IN_EH_ID, eh_idp->id);
2731 
2732 	efx_mcdi_execute(enp, &req);
2733 
2734 	if (req.emr_rc != 0) {
2735 		rc = req.emr_rc;
2736 		goto fail2;
2737 	}
2738 
2739 	if (MCDI_OUT_DWORD(req, MAE_ENCAP_HEADER_FREE_OUT_FREED_EH_ID) !=
2740 	    eh_idp->id) {
2741 		/* Firmware failed to remove the encap. header. */
2742 		rc = EAGAIN;
2743 		goto fail3;
2744 	}
2745 
2746 	return (0);
2747 
2748 fail3:
2749 	EFSYS_PROBE(fail3);
2750 fail2:
2751 	EFSYS_PROBE(fail2);
2752 fail1:
2753 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2754 	return (rc);
2755 }
2756 
2757 	__checkReturn			efx_rc_t
2758 efx_mae_action_set_fill_in_eh_id(
2759 	__in				efx_mae_actions_t *spec,
2760 	__in				const efx_mae_eh_id_t *eh_idp)
2761 {
2762 	efx_rc_t rc;
2763 
2764 	if ((spec->ema_actions & (1U << EFX_MAE_ACTION_ENCAP)) == 0) {
2765 		/*
2766 		 * The caller has not intended to have action ENCAP originally,
2767 		 * hence, this attempt to indicate encap. header ID is invalid.
2768 		 */
2769 		rc = EINVAL;
2770 		goto fail1;
2771 	}
2772 
2773 	if (spec->ema_rsrc.emar_eh_id.id != EFX_MAE_RSRC_ID_INVALID) {
2774 		/* The caller attempts to indicate encap. header ID twice. */
2775 		rc = EINVAL;
2776 		goto fail2;
2777 	}
2778 
2779 	if (eh_idp->id == EFX_MAE_RSRC_ID_INVALID) {
2780 		rc = EINVAL;
2781 		goto fail3;
2782 	}
2783 
2784 	spec->ema_rsrc.emar_eh_id.id = eh_idp->id;
2785 
2786 	return (0);
2787 
2788 fail3:
2789 	EFSYS_PROBE(fail3);
2790 fail2:
2791 	EFSYS_PROBE(fail2);
2792 fail1:
2793 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2794 	return (rc);
2795 }
2796 
2797 	__checkReturn			efx_rc_t
2798 efx_mae_action_set_alloc(
2799 	__in				efx_nic_t *enp,
2800 	__in				const efx_mae_actions_t *spec,
2801 	__out				efx_mae_aset_id_t *aset_idp)
2802 {
2803 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2804 	efx_mcdi_req_t req;
2805 	EFX_MCDI_DECLARE_BUF(payload,
2806 	    MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN,
2807 	    MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN);
2808 	efx_mae_aset_id_t aset_id;
2809 	efx_rc_t rc;
2810 
2811 	if (encp->enc_mae_supported == B_FALSE) {
2812 		rc = ENOTSUP;
2813 		goto fail1;
2814 	}
2815 
2816 	if ((spec->ema_actions & (1U << EFX_MAE_ACTION_SET_DST_MAC)) != 0 &&
2817 	    spec->ema_rsrc.emar_dst_mac_id.id == EFX_MAE_RSRC_ID_INVALID) {
2818 		rc = EINVAL;
2819 		goto fail2;
2820 	}
2821 
2822 	if ((spec->ema_actions & (1U << EFX_MAE_ACTION_SET_SRC_MAC)) != 0 &&
2823 	    spec->ema_rsrc.emar_src_mac_id.id == EFX_MAE_RSRC_ID_INVALID) {
2824 		rc = EINVAL;
2825 		goto fail3;
2826 	}
2827 
2828 	if ((spec->ema_actions & (1U << EFX_MAE_ACTION_ENCAP)) != 0 &&
2829 	    spec->ema_rsrc.emar_eh_id.id == EFX_MAE_RSRC_ID_INVALID) {
2830 		rc = EINVAL;
2831 		goto fail4;
2832 	}
2833 
2834 	if (spec->ema_n_count_actions == 1 &&
2835 	    spec->ema_rsrc.emar_counter_id.id == EFX_MAE_RSRC_ID_INVALID) {
2836 		rc = EINVAL;
2837 		goto fail5;
2838 	}
2839 
2840 	req.emr_cmd = MC_CMD_MAE_ACTION_SET_ALLOC;
2841 	req.emr_in_buf = payload;
2842 	req.emr_in_length = MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN;
2843 	req.emr_out_buf = payload;
2844 	req.emr_out_length = MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN;
2845 
2846 	/*
2847 	 * TODO: Remove these EFX_MAE_RSRC_ID_INVALID assignments once the
2848 	 * corresponding resource types are supported by the implementation.
2849 	 * Use proper resource ID assignments instead.
2850 	 */
2851 	MCDI_IN_SET_DWORD(req,
2852 	    MAE_ACTION_SET_ALLOC_IN_COUNTER_LIST_ID, EFX_MAE_RSRC_ID_INVALID);
2853 
2854 	if ((spec->ema_actions & (1U << EFX_MAE_ACTION_DECAP)) != 0) {
2855 		MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2856 		    MAE_ACTION_SET_ALLOC_IN_DECAP, 1);
2857 	}
2858 
2859 	MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2860 	    MAE_ACTION_SET_ALLOC_IN_VLAN_POP, spec->ema_n_vlan_tags_to_pop);
2861 
2862 	MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID,
2863 	    spec->ema_rsrc.emar_dst_mac_id.id);
2864 
2865 	MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID,
2866 	    spec->ema_rsrc.emar_src_mac_id.id);
2867 
2868 	if ((spec->ema_actions & (1U << EFX_MAE_ACTION_DECR_IP_TTL)) != 0) {
2869 		MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2870 		    MAE_ACTION_SET_ALLOC_IN_DO_DECR_IP_TTL, 1);
2871 	}
2872 
2873 	if (spec->ema_n_vlan_tags_to_push > 0) {
2874 		unsigned int outer_tag_idx;
2875 
2876 		MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2877 		    MAE_ACTION_SET_ALLOC_IN_VLAN_PUSH,
2878 		    spec->ema_n_vlan_tags_to_push);
2879 
2880 		if (spec->ema_n_vlan_tags_to_push ==
2881 		    EFX_MAE_VLAN_PUSH_MAX_NTAGS) {
2882 			MCDI_IN_SET_WORD(req,
2883 			    MAE_ACTION_SET_ALLOC_IN_VLAN1_PROTO_BE,
2884 			    spec->ema_vlan_push_descs[0].emavp_tpid_be);
2885 			MCDI_IN_SET_WORD(req,
2886 			    MAE_ACTION_SET_ALLOC_IN_VLAN1_TCI_BE,
2887 			    spec->ema_vlan_push_descs[0].emavp_tci_be);
2888 		}
2889 
2890 		outer_tag_idx = spec->ema_n_vlan_tags_to_push - 1;
2891 
2892 		MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_PROTO_BE,
2893 		    spec->ema_vlan_push_descs[outer_tag_idx].emavp_tpid_be);
2894 		MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_TCI_BE,
2895 		    spec->ema_vlan_push_descs[outer_tag_idx].emavp_tci_be);
2896 	}
2897 
2898 	MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID,
2899 	    spec->ema_rsrc.emar_eh_id.id);
2900 	MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_COUNTER_ID,
2901 	    spec->ema_rsrc.emar_counter_id.id);
2902 
2903 	if ((spec->ema_actions & (1U << EFX_MAE_ACTION_FLAG)) != 0) {
2904 		MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2905 		    MAE_ACTION_SET_ALLOC_IN_FLAG, 1);
2906 	}
2907 
2908 	if ((spec->ema_actions & (1U << EFX_MAE_ACTION_MARK)) != 0) {
2909 		MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2910 		    MAE_ACTION_SET_ALLOC_IN_MARK, 1);
2911 
2912 		MCDI_IN_SET_DWORD(req,
2913 		    MAE_ACTION_SET_ALLOC_IN_MARK_VALUE, spec->ema_mark_value);
2914 	}
2915 
2916 	MCDI_IN_SET_DWORD(req,
2917 	    MAE_ACTION_SET_ALLOC_IN_DELIVER, spec->ema_deliver_mport.sel);
2918 
2919 	efx_mcdi_execute(enp, &req);
2920 
2921 	if (req.emr_rc != 0) {
2922 		rc = req.emr_rc;
2923 		goto fail6;
2924 	}
2925 
2926 	if (req.emr_out_length_used < MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN) {
2927 		rc = EMSGSIZE;
2928 		goto fail7;
2929 	}
2930 
2931 	aset_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_SET_ALLOC_OUT_AS_ID);
2932 	if (aset_id.id == EFX_MAE_RSRC_ID_INVALID) {
2933 		rc = ENOENT;
2934 		goto fail8;
2935 	}
2936 
2937 	aset_idp->id = aset_id.id;
2938 
2939 	return (0);
2940 
2941 fail8:
2942 	EFSYS_PROBE(fail8);
2943 fail7:
2944 	EFSYS_PROBE(fail7);
2945 fail6:
2946 	EFSYS_PROBE(fail6);
2947 fail5:
2948 	EFSYS_PROBE(fail5);
2949 fail4:
2950 	EFSYS_PROBE(fail4);
2951 fail3:
2952 	EFSYS_PROBE(fail3);
2953 fail2:
2954 	EFSYS_PROBE(fail2);
2955 fail1:
2956 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2957 	return (rc);
2958 }
2959 
2960 	__checkReturn			unsigned int
2961 efx_mae_action_set_get_nb_count(
2962 	__in				const efx_mae_actions_t *spec)
2963 {
2964 	return (spec->ema_n_count_actions);
2965 }
2966 
2967 	__checkReturn			efx_rc_t
2968 efx_mae_action_set_fill_in_counter_id(
2969 	__in				efx_mae_actions_t *spec,
2970 	__in				const efx_counter_t *counter_idp)
2971 {
2972 	efx_rc_t rc;
2973 
2974 	if ((spec->ema_actions & (1U << EFX_MAE_ACTION_COUNT)) == 0) {
2975 		/*
2976 		 * Invalid to add counter ID if spec does not have COUNT action.
2977 		 */
2978 		rc = EINVAL;
2979 		goto fail1;
2980 	}
2981 
2982 	if (spec->ema_n_count_actions != 1) {
2983 		/*
2984 		 * Having multiple COUNT actions in the spec requires a counter
2985 		 * list to be used. This API must only be used for a single
2986 		 * counter per spec. Turn down the request as inappropriate.
2987 		 */
2988 		rc = EINVAL;
2989 		goto fail2;
2990 	}
2991 
2992 	if (spec->ema_rsrc.emar_counter_id.id != EFX_MAE_RSRC_ID_INVALID) {
2993 		/* The caller attempts to indicate counter ID twice. */
2994 		rc = EALREADY;
2995 		goto fail3;
2996 	}
2997 
2998 	if (counter_idp->id == EFX_MAE_RSRC_ID_INVALID) {
2999 		rc = EINVAL;
3000 		goto fail4;
3001 	}
3002 
3003 	spec->ema_rsrc.emar_counter_id.id = counter_idp->id;
3004 
3005 	return (0);
3006 
3007 fail4:
3008 	EFSYS_PROBE(fail4);
3009 fail3:
3010 	EFSYS_PROBE(fail3);
3011 fail2:
3012 	EFSYS_PROBE(fail2);
3013 fail1:
3014 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
3015 	return (rc);
3016 }
3017 
3018 	__checkReturn			efx_rc_t
3019 efx_mae_counters_alloc(
3020 	__in				efx_nic_t *enp,
3021 	__in				uint32_t n_counters,
3022 	__out				uint32_t *n_allocatedp,
3023 	__out_ecount(n_counters)	efx_counter_t *countersp,
3024 	__out_opt			uint32_t *gen_countp)
3025 {
3026 	EFX_MCDI_DECLARE_BUF(payload,
3027 	    MC_CMD_MAE_COUNTER_ALLOC_IN_LEN,
3028 	    MC_CMD_MAE_COUNTER_ALLOC_OUT_LENMAX_MCDI2);
3029 	efx_mae_t *maep = enp->en_maep;
3030 	uint32_t n_allocated;
3031 	efx_mcdi_req_t req;
3032 	unsigned int i;
3033 	efx_rc_t rc;
3034 
3035 	if (n_counters > maep->em_max_ncounters ||
3036 	    n_counters < MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_MINNUM ||
3037 	    n_counters > MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_MAXNUM_MCDI2) {
3038 		rc = EINVAL;
3039 		goto fail1;
3040 	}
3041 
3042 	req.emr_cmd = MC_CMD_MAE_COUNTER_ALLOC;
3043 	req.emr_in_buf = payload;
3044 	req.emr_in_length = MC_CMD_MAE_COUNTER_ALLOC_IN_LEN;
3045 	req.emr_out_buf = payload;
3046 	req.emr_out_length = MC_CMD_MAE_COUNTER_ALLOC_OUT_LEN(n_counters);
3047 
3048 	MCDI_IN_SET_DWORD(req, MAE_COUNTER_ALLOC_IN_REQUESTED_COUNT,
3049 	    n_counters);
3050 
3051 	efx_mcdi_execute(enp, &req);
3052 
3053 	if (req.emr_rc != 0) {
3054 		rc = req.emr_rc;
3055 		goto fail2;
3056 	}
3057 
3058 	if (req.emr_out_length_used < MC_CMD_MAE_COUNTER_ALLOC_OUT_LENMIN) {
3059 		rc = EMSGSIZE;
3060 		goto fail3;
3061 	}
3062 
3063 	n_allocated = MCDI_OUT_DWORD(req,
3064 	    MAE_COUNTER_ALLOC_OUT_COUNTER_ID_COUNT);
3065 	if (n_allocated < MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_MINNUM) {
3066 		rc = EFAULT;
3067 		goto fail4;
3068 	}
3069 
3070 	for (i = 0; i < n_allocated; i++) {
3071 		countersp[i].id = MCDI_OUT_INDEXED_DWORD(req,
3072 		    MAE_COUNTER_ALLOC_OUT_COUNTER_ID, i);
3073 	}
3074 
3075 	if (gen_countp != NULL) {
3076 		*gen_countp = MCDI_OUT_DWORD(req,
3077 				    MAE_COUNTER_ALLOC_OUT_GENERATION_COUNT);
3078 	}
3079 
3080 	*n_allocatedp = n_allocated;
3081 
3082 	return (0);
3083 
3084 fail4:
3085 	EFSYS_PROBE(fail4);
3086 fail3:
3087 	EFSYS_PROBE(fail3);
3088 fail2:
3089 	EFSYS_PROBE(fail2);
3090 fail1:
3091 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
3092 
3093 	return (rc);
3094 }
3095 
3096 	__checkReturn			efx_rc_t
3097 efx_mae_counters_free(
3098 	__in				efx_nic_t *enp,
3099 	__in				uint32_t n_counters,
3100 	__out				uint32_t *n_freedp,
3101 	__in_ecount(n_counters)		const efx_counter_t *countersp,
3102 	__out_opt			uint32_t *gen_countp)
3103 {
3104 	EFX_MCDI_DECLARE_BUF(payload,
3105 	    MC_CMD_MAE_COUNTER_FREE_IN_LENMAX_MCDI2,
3106 	    MC_CMD_MAE_COUNTER_FREE_OUT_LENMAX_MCDI2);
3107 	efx_mae_t *maep = enp->en_maep;
3108 	efx_mcdi_req_t req;
3109 	uint32_t n_freed;
3110 	unsigned int i;
3111 	efx_rc_t rc;
3112 
3113 	if (n_counters > maep->em_max_ncounters ||
3114 	    n_counters < MC_CMD_MAE_COUNTER_FREE_IN_FREE_COUNTER_ID_MINNUM ||
3115 	    n_counters >
3116 	    MC_CMD_MAE_COUNTER_FREE_IN_FREE_COUNTER_ID_MAXNUM_MCDI2) {
3117 		rc = EINVAL;
3118 		goto fail1;
3119 	}
3120 
3121 	req.emr_cmd = MC_CMD_MAE_COUNTER_FREE;
3122 	req.emr_in_buf = payload;
3123 	req.emr_in_length = MC_CMD_MAE_COUNTER_FREE_IN_LEN(n_counters);
3124 	req.emr_out_buf = payload;
3125 	req.emr_out_length = MC_CMD_MAE_COUNTER_FREE_OUT_LEN(n_counters);
3126 
3127 	for (i = 0; i < n_counters; i++) {
3128 		MCDI_IN_SET_INDEXED_DWORD(req,
3129 		    MAE_COUNTER_FREE_IN_FREE_COUNTER_ID, i, countersp[i].id);
3130 	}
3131 	MCDI_IN_SET_DWORD(req, MAE_COUNTER_FREE_IN_COUNTER_ID_COUNT,
3132 			  n_counters);
3133 
3134 	efx_mcdi_execute(enp, &req);
3135 
3136 	if (req.emr_rc != 0) {
3137 		rc = req.emr_rc;
3138 		goto fail2;
3139 	}
3140 
3141 	if (req.emr_out_length_used < MC_CMD_MAE_COUNTER_FREE_OUT_LENMIN) {
3142 		rc = EMSGSIZE;
3143 		goto fail3;
3144 	}
3145 
3146 	n_freed = MCDI_OUT_DWORD(req, MAE_COUNTER_FREE_OUT_COUNTER_ID_COUNT);
3147 
3148 	if (n_freed < MC_CMD_MAE_COUNTER_FREE_OUT_FREED_COUNTER_ID_MINNUM) {
3149 		rc = EFAULT;
3150 		goto fail4;
3151 	}
3152 
3153 	if (gen_countp != NULL) {
3154 		*gen_countp = MCDI_OUT_DWORD(req,
3155 				    MAE_COUNTER_FREE_OUT_GENERATION_COUNT);
3156 	}
3157 
3158 	*n_freedp = n_freed;
3159 
3160 	return (0);
3161 
3162 fail4:
3163 	EFSYS_PROBE(fail4);
3164 fail3:
3165 	EFSYS_PROBE(fail3);
3166 fail2:
3167 	EFSYS_PROBE(fail2);
3168 fail1:
3169 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
3170 
3171 	return (rc);
3172 }
3173 
3174 	__checkReturn			efx_rc_t
3175 efx_mae_counters_stream_start(
3176 	__in				efx_nic_t *enp,
3177 	__in				uint16_t rxq_id,
3178 	__in				uint16_t packet_size,
3179 	__in				uint32_t flags_in,
3180 	__out				uint32_t *flags_out)
3181 {
3182 	efx_mcdi_req_t req;
3183 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_MAE_COUNTERS_STREAM_START_IN_LEN,
3184 			     MC_CMD_MAE_COUNTERS_STREAM_START_OUT_LEN);
3185 	efx_rc_t rc;
3186 
3187 	EFX_STATIC_ASSERT(EFX_MAE_COUNTERS_STREAM_IN_ZERO_SQUASH_DISABLE ==
3188 	    1U << MC_CMD_MAE_COUNTERS_STREAM_START_IN_ZERO_SQUASH_DISABLE_LBN);
3189 
3190 	EFX_STATIC_ASSERT(EFX_MAE_COUNTERS_STREAM_OUT_USES_CREDITS ==
3191 	    1U << MC_CMD_MAE_COUNTERS_STREAM_START_OUT_USES_CREDITS_LBN);
3192 
3193 	req.emr_cmd = MC_CMD_MAE_COUNTERS_STREAM_START;
3194 	req.emr_in_buf = payload;
3195 	req.emr_in_length = MC_CMD_MAE_COUNTERS_STREAM_START_IN_LEN;
3196 	req.emr_out_buf = payload;
3197 	req.emr_out_length = MC_CMD_MAE_COUNTERS_STREAM_START_OUT_LEN;
3198 
3199 	MCDI_IN_SET_WORD(req, MAE_COUNTERS_STREAM_START_IN_QID, rxq_id);
3200 	MCDI_IN_SET_WORD(req, MAE_COUNTERS_STREAM_START_IN_PACKET_SIZE,
3201 			 packet_size);
3202 	MCDI_IN_SET_DWORD(req, MAE_COUNTERS_STREAM_START_IN_FLAGS, flags_in);
3203 
3204 	efx_mcdi_execute(enp, &req);
3205 
3206 	if (req.emr_rc != 0) {
3207 		rc = req.emr_rc;
3208 		goto fail1;
3209 	}
3210 
3211 	if (req.emr_out_length_used <
3212 	    MC_CMD_MAE_COUNTERS_STREAM_START_OUT_LEN) {
3213 		rc = EMSGSIZE;
3214 		goto fail2;
3215 	}
3216 
3217 	*flags_out = MCDI_OUT_DWORD(req, MAE_COUNTERS_STREAM_START_OUT_FLAGS);
3218 
3219 	return (0);
3220 
3221 fail2:
3222 	EFSYS_PROBE(fail2);
3223 fail1:
3224 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
3225 
3226 	return (rc);
3227 }
3228 
3229 	__checkReturn			efx_rc_t
3230 efx_mae_counters_stream_stop(
3231 	__in				efx_nic_t *enp,
3232 	__in				uint16_t rxq_id,
3233 	__out_opt			uint32_t *gen_countp)
3234 {
3235 	efx_mcdi_req_t req;
3236 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_MAE_COUNTERS_STREAM_STOP_IN_LEN,
3237 			     MC_CMD_MAE_COUNTERS_STREAM_STOP_OUT_LEN);
3238 	efx_rc_t rc;
3239 
3240 	req.emr_cmd = MC_CMD_MAE_COUNTERS_STREAM_STOP;
3241 	req.emr_in_buf = payload;
3242 	req.emr_in_length = MC_CMD_MAE_COUNTERS_STREAM_STOP_IN_LEN;
3243 	req.emr_out_buf = payload;
3244 	req.emr_out_length = MC_CMD_MAE_COUNTERS_STREAM_STOP_OUT_LEN;
3245 
3246 	MCDI_IN_SET_WORD(req, MAE_COUNTERS_STREAM_STOP_IN_QID, rxq_id);
3247 
3248 	efx_mcdi_execute(enp, &req);
3249 
3250 	if (req.emr_rc != 0) {
3251 		rc = req.emr_rc;
3252 		goto fail1;
3253 	}
3254 
3255 	if (req.emr_out_length_used <
3256 	    MC_CMD_MAE_COUNTERS_STREAM_STOP_OUT_LEN) {
3257 		rc = EMSGSIZE;
3258 		goto fail2;
3259 	}
3260 
3261 	if (gen_countp != NULL) {
3262 		*gen_countp = MCDI_OUT_DWORD(req,
3263 			    MAE_COUNTERS_STREAM_STOP_OUT_GENERATION_COUNT);
3264 	}
3265 
3266 	return (0);
3267 
3268 fail2:
3269 	EFSYS_PROBE(fail2);
3270 fail1:
3271 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
3272 
3273 	return (rc);
3274 }
3275 
3276 	__checkReturn			efx_rc_t
3277 efx_mae_counters_stream_give_credits(
3278 	__in				efx_nic_t *enp,
3279 	__in				uint32_t n_credits)
3280 {
3281 	efx_mcdi_req_t req;
3282 	EFX_MCDI_DECLARE_BUF(payload,
3283 			     MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_LEN,
3284 			     MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_OUT_LEN);
3285 	efx_rc_t rc;
3286 
3287 	req.emr_cmd = MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS;
3288 	req.emr_in_buf = payload;
3289 	req.emr_in_length = MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_LEN;
3290 	req.emr_out_buf = payload;
3291 	req.emr_out_length = MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_OUT_LEN;
3292 
3293 	MCDI_IN_SET_DWORD(req, MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_NUM_CREDITS,
3294 			 n_credits);
3295 
3296 	efx_mcdi_execute(enp, &req);
3297 
3298 	if (req.emr_rc != 0) {
3299 		rc = req.emr_rc;
3300 		goto fail1;
3301 	}
3302 
3303 	return (0);
3304 
3305 fail1:
3306 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
3307 
3308 	return (rc);
3309 }
3310 
3311 	__checkReturn			efx_rc_t
3312 efx_mae_action_set_free(
3313 	__in				efx_nic_t *enp,
3314 	__in				const efx_mae_aset_id_t *aset_idp)
3315 {
3316 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
3317 	efx_mcdi_req_t req;
3318 	EFX_MCDI_DECLARE_BUF(payload,
3319 	    MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1),
3320 	    MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1));
3321 	efx_rc_t rc;
3322 
3323 	if (encp->enc_mae_supported == B_FALSE) {
3324 		rc = ENOTSUP;
3325 		goto fail1;
3326 	}
3327 
3328 	req.emr_cmd = MC_CMD_MAE_ACTION_SET_FREE;
3329 	req.emr_in_buf = payload;
3330 	req.emr_in_length = MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1);
3331 	req.emr_out_buf = payload;
3332 	req.emr_out_length = MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1);
3333 
3334 	MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_FREE_IN_AS_ID, aset_idp->id);
3335 
3336 	efx_mcdi_execute(enp, &req);
3337 
3338 	if (req.emr_rc != 0) {
3339 		rc = req.emr_rc;
3340 		goto fail2;
3341 	}
3342 
3343 	if (req.emr_out_length_used < MC_CMD_MAE_ACTION_SET_FREE_OUT_LENMIN) {
3344 		rc = EMSGSIZE;
3345 		goto fail3;
3346 	}
3347 
3348 	if (MCDI_OUT_DWORD(req, MAE_ACTION_SET_FREE_OUT_FREED_AS_ID) !=
3349 	    aset_idp->id) {
3350 		/* Firmware failed to free the action set. */
3351 		rc = EAGAIN;
3352 		goto fail4;
3353 	}
3354 
3355 	return (0);
3356 
3357 fail4:
3358 	EFSYS_PROBE(fail4);
3359 fail3:
3360 	EFSYS_PROBE(fail3);
3361 fail2:
3362 	EFSYS_PROBE(fail2);
3363 fail1:
3364 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
3365 	return (rc);
3366 }
3367 
3368 	__checkReturn			efx_rc_t
3369 efx_mae_action_rule_insert(
3370 	__in				efx_nic_t *enp,
3371 	__in				const efx_mae_match_spec_t *spec,
3372 	__in				const efx_mae_aset_list_id_t *asl_idp,
3373 	__in				const efx_mae_aset_id_t *as_idp,
3374 	__out				efx_mae_rule_id_t *ar_idp)
3375 {
3376 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
3377 	efx_mcdi_req_t req;
3378 	EFX_MCDI_DECLARE_BUF(payload,
3379 	    MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2,
3380 	    MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN);
3381 	efx_oword_t *rule_response;
3382 	efx_mae_rule_id_t ar_id;
3383 	size_t offset;
3384 	efx_rc_t rc;
3385 
3386 	EFX_STATIC_ASSERT(sizeof (ar_idp->id) ==
3387 	    MC_CMD_MAE_ACTION_RULE_INSERT_OUT_AR_ID_LEN);
3388 
3389 	EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
3390 	    MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL);
3391 
3392 	if (encp->enc_mae_supported == B_FALSE) {
3393 		rc = ENOTSUP;
3394 		goto fail1;
3395 	}
3396 
3397 	if (spec->emms_type != EFX_MAE_RULE_ACTION ||
3398 	    (asl_idp != NULL && as_idp != NULL) ||
3399 	    (asl_idp == NULL && as_idp == NULL)) {
3400 		rc = EINVAL;
3401 		goto fail2;
3402 	}
3403 
3404 	req.emr_cmd = MC_CMD_MAE_ACTION_RULE_INSERT;
3405 	req.emr_in_buf = payload;
3406 	req.emr_in_length = MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2;
3407 	req.emr_out_buf = payload;
3408 	req.emr_out_length = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN;
3409 
3410 	EFX_STATIC_ASSERT(sizeof (*rule_response) <=
3411 	    MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_LEN);
3412 	offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_OFST;
3413 	rule_response = (efx_oword_t *)(payload + offset);
3414 	EFX_POPULATE_OWORD_3(*rule_response,
3415 	    MAE_ACTION_RULE_RESPONSE_ASL_ID,
3416 	    (asl_idp != NULL) ? asl_idp->id : EFX_MAE_RSRC_ID_INVALID,
3417 	    MAE_ACTION_RULE_RESPONSE_AS_ID,
3418 	    (as_idp != NULL) ? as_idp->id : EFX_MAE_RSRC_ID_INVALID,
3419 	    MAE_ACTION_RULE_RESPONSE_COUNTER_ID, EFX_MAE_RSRC_ID_INVALID);
3420 
3421 	MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_INSERT_IN_PRIO, spec->emms_prio);
3422 
3423 	/*
3424 	 * Mask-value pairs have been stored in the byte order needed for the
3425 	 * MCDI request and are thus safe to be copied directly to the buffer.
3426 	 */
3427 	EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.action) >=
3428 	    MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN);
3429 	offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_MATCH_CRITERIA_OFST;
3430 	memcpy(payload + offset, spec->emms_mask_value_pairs.action,
3431 	    MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN);
3432 
3433 	efx_mcdi_execute(enp, &req);
3434 
3435 	if (req.emr_rc != 0) {
3436 		rc = req.emr_rc;
3437 		goto fail3;
3438 	}
3439 
3440 	if (req.emr_out_length_used < MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN) {
3441 		rc = EMSGSIZE;
3442 		goto fail4;
3443 	}
3444 
3445 	ar_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_RULE_INSERT_OUT_AR_ID);
3446 	if (ar_id.id == EFX_MAE_RSRC_ID_INVALID) {
3447 		rc = ENOENT;
3448 		goto fail5;
3449 	}
3450 
3451 	ar_idp->id = ar_id.id;
3452 
3453 	return (0);
3454 
3455 fail5:
3456 	EFSYS_PROBE(fail5);
3457 fail4:
3458 	EFSYS_PROBE(fail4);
3459 fail3:
3460 	EFSYS_PROBE(fail3);
3461 fail2:
3462 	EFSYS_PROBE(fail2);
3463 fail1:
3464 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
3465 	return (rc);
3466 }
3467 
3468 	__checkReturn			efx_rc_t
3469 efx_mae_action_rule_remove(
3470 	__in				efx_nic_t *enp,
3471 	__in				const efx_mae_rule_id_t *ar_idp)
3472 {
3473 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
3474 	efx_mcdi_req_t req;
3475 	EFX_MCDI_DECLARE_BUF(payload,
3476 	    MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1),
3477 	    MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1));
3478 	efx_rc_t rc;
3479 
3480 	if (encp->enc_mae_supported == B_FALSE) {
3481 		rc = ENOTSUP;
3482 		goto fail1;
3483 	}
3484 
3485 	req.emr_cmd = MC_CMD_MAE_ACTION_RULE_DELETE;
3486 	req.emr_in_buf = payload;
3487 	req.emr_in_length = MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1);
3488 	req.emr_out_buf = payload;
3489 	req.emr_out_length = MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1);
3490 
3491 	MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_DELETE_IN_AR_ID, ar_idp->id);
3492 
3493 	efx_mcdi_execute(enp, &req);
3494 
3495 	if (req.emr_rc != 0) {
3496 		rc = req.emr_rc;
3497 		goto fail2;
3498 	}
3499 
3500 	if (req.emr_out_length_used <
3501 	    MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LENMIN) {
3502 		rc = EMSGSIZE;
3503 		goto fail3;
3504 	}
3505 
3506 	if (MCDI_OUT_DWORD(req, MAE_ACTION_RULE_DELETE_OUT_DELETED_AR_ID) !=
3507 	    ar_idp->id) {
3508 		/* Firmware failed to delete the action rule. */
3509 		rc = EAGAIN;
3510 		goto fail4;
3511 	}
3512 
3513 	return (0);
3514 
3515 fail4:
3516 	EFSYS_PROBE(fail4);
3517 fail3:
3518 	EFSYS_PROBE(fail3);
3519 fail2:
3520 	EFSYS_PROBE(fail2);
3521 fail1:
3522 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
3523 	return (rc);
3524 }
3525 
3526 	__checkReturn			efx_rc_t
3527 efx_mcdi_mport_alloc_alias(
3528 	__in				efx_nic_t *enp,
3529 	__out				efx_mport_id_t *mportp,
3530 	__out_opt			uint32_t *labelp)
3531 {
3532 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
3533 	efx_mcdi_req_t req;
3534 	EFX_MCDI_DECLARE_BUF(payload,
3535 	    MC_CMD_MAE_MPORT_ALLOC_ALIAS_IN_LEN,
3536 	    MC_CMD_MAE_MPORT_ALLOC_ALIAS_OUT_LEN);
3537 	efx_rc_t rc;
3538 
3539 	if (encp->enc_mae_supported == B_FALSE) {
3540 		rc = ENOTSUP;
3541 		goto fail1;
3542 	}
3543 
3544 	req.emr_cmd = MC_CMD_MAE_MPORT_ALLOC;
3545 	req.emr_in_buf = payload;
3546 	req.emr_in_length = MC_CMD_MAE_MPORT_ALLOC_ALIAS_IN_LEN;
3547 	req.emr_out_buf = payload;
3548 	req.emr_out_length = MC_CMD_MAE_MPORT_ALLOC_ALIAS_OUT_LEN;
3549 
3550 	MCDI_IN_SET_DWORD(req, MAE_MPORT_ALLOC_IN_TYPE,
3551 			  MC_CMD_MAE_MPORT_ALLOC_IN_MPORT_TYPE_ALIAS);
3552 	MCDI_IN_SET_DWORD(req, MAE_MPORT_ALLOC_ALIAS_IN_DELIVER_MPORT,
3553 			  MAE_MPORT_SELECTOR_ASSIGNED);
3554 
3555 	efx_mcdi_execute(enp, &req);
3556 
3557 	if (req.emr_rc != 0) {
3558 		rc = req.emr_rc;
3559 		goto fail2;
3560 	}
3561 
3562 	mportp->id = MCDI_OUT_DWORD(req, MAE_MPORT_ALLOC_OUT_MPORT_ID);
3563 	if (labelp != NULL)
3564 		*labelp = MCDI_OUT_DWORD(req, MAE_MPORT_ALLOC_ALIAS_OUT_LABEL);
3565 
3566 	return (0);
3567 
3568 fail2:
3569 	EFSYS_PROBE(fail2);
3570 fail1:
3571 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
3572 	return (rc);
3573 }
3574 
3575 	__checkReturn			efx_rc_t
3576 efx_mae_mport_free(
3577 	__in				efx_nic_t *enp,
3578 	__in				const efx_mport_id_t *mportp)
3579 {
3580 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
3581 	efx_mcdi_req_t req;
3582 	EFX_MCDI_DECLARE_BUF(payload,
3583 	    MC_CMD_MAE_MPORT_FREE_IN_LEN,
3584 	    MC_CMD_MAE_MPORT_FREE_OUT_LEN);
3585 	efx_rc_t rc;
3586 
3587 	if (encp->enc_mae_supported == B_FALSE) {
3588 		rc = ENOTSUP;
3589 		goto fail1;
3590 	}
3591 
3592 	req.emr_cmd = MC_CMD_MAE_MPORT_FREE;
3593 	req.emr_in_buf = payload;
3594 	req.emr_in_length = MC_CMD_MAE_MPORT_FREE_IN_LEN;
3595 	req.emr_out_buf = payload;
3596 	req.emr_out_length = MC_CMD_MAE_MPORT_FREE_OUT_LEN;
3597 
3598 	MCDI_IN_SET_DWORD(req, MAE_MPORT_FREE_IN_MPORT_ID, mportp->id);
3599 
3600 	efx_mcdi_execute(enp, &req);
3601 
3602 	if (req.emr_rc != 0) {
3603 		rc = req.emr_rc;
3604 		goto fail2;
3605 	}
3606 
3607 	return (0);
3608 
3609 fail2:
3610 	EFSYS_PROBE(fail2);
3611 fail1:
3612 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
3613 	return (rc);
3614 }
3615 
3616 static	__checkReturn			efx_rc_t
3617 efx_mae_read_mport_journal_single(
3618 	__in				uint8_t *entry_buf,
3619 	__out				efx_mport_desc_t *desc)
3620 {
3621 	uint32_t pcie_intf;
3622 	efx_rc_t rc;
3623 
3624 	memset(desc, 0, sizeof (*desc));
3625 
3626 	desc->emd_id.id = MCDI_STRUCT_DWORD(entry_buf,
3627 	    MAE_MPORT_DESC_V2_MPORT_ID);
3628 
3629 	desc->emd_can_receive_on = MCDI_STRUCT_DWORD_FIELD(entry_buf,
3630 	    MAE_MPORT_DESC_V2_FLAGS,
3631 	    MAE_MPORT_DESC_V2_CAN_RECEIVE_ON);
3632 
3633 	desc->emd_can_deliver_to = MCDI_STRUCT_DWORD_FIELD(entry_buf,
3634 	    MAE_MPORT_DESC_V2_FLAGS,
3635 	    MAE_MPORT_DESC_V2_CAN_DELIVER_TO);
3636 
3637 	desc->emd_can_delete = MCDI_STRUCT_DWORD_FIELD(entry_buf,
3638 	    MAE_MPORT_DESC_V2_FLAGS,
3639 	    MAE_MPORT_DESC_V2_CAN_DELETE);
3640 
3641 	desc->emd_zombie = MCDI_STRUCT_DWORD_FIELD(entry_buf,
3642 	    MAE_MPORT_DESC_V2_FLAGS,
3643 	    MAE_MPORT_DESC_V2_IS_ZOMBIE);
3644 
3645 	desc->emd_type = MCDI_STRUCT_DWORD(entry_buf,
3646 	    MAE_MPORT_DESC_V2_MPORT_TYPE);
3647 
3648 	/*
3649 	 * We can't check everything here. If some additional checks are
3650 	 * required, they should be performed by the callback function.
3651 	 */
3652 	switch (desc->emd_type) {
3653 	case EFX_MPORT_TYPE_NET_PORT:
3654 		desc->emd_net_port.ep_index =
3655 		    MCDI_STRUCT_DWORD(entry_buf,
3656 			MAE_MPORT_DESC_V2_NET_PORT_IDX);
3657 		break;
3658 	case EFX_MPORT_TYPE_ALIAS:
3659 		desc->emd_alias.ea_target_mport_id.id =
3660 		    MCDI_STRUCT_DWORD(entry_buf,
3661 			MAE_MPORT_DESC_V2_ALIAS_DELIVER_MPORT_ID);
3662 		break;
3663 	case EFX_MPORT_TYPE_VNIC:
3664 		desc->emd_vnic.ev_client_type =
3665 		    MCDI_STRUCT_DWORD(entry_buf,
3666 			MAE_MPORT_DESC_V2_VNIC_CLIENT_TYPE);
3667 		if (desc->emd_vnic.ev_client_type !=
3668 		    EFX_MPORT_VNIC_CLIENT_FUNCTION)
3669 			break;
3670 
3671 		pcie_intf = MCDI_STRUCT_DWORD(entry_buf,
3672 		    MAE_MPORT_DESC_V2_VNIC_FUNCTION_INTERFACE);
3673 		rc = efx_mcdi_intf_from_pcie(pcie_intf,
3674 		    &desc->emd_vnic.ev_intf);
3675 		if (rc != 0)
3676 			goto fail1;
3677 
3678 		desc->emd_vnic.ev_pf = MCDI_STRUCT_WORD(entry_buf,
3679 		    MAE_MPORT_DESC_V2_VNIC_FUNCTION_PF_IDX);
3680 		desc->emd_vnic.ev_vf = MCDI_STRUCT_WORD(entry_buf,
3681 		    MAE_MPORT_DESC_V2_VNIC_FUNCTION_VF_IDX);
3682 		desc->emd_vnic.ev_handle = MCDI_STRUCT_DWORD(entry_buf,
3683 		    MAE_MPORT_DESC_V2_VNIC_CLIENT_HANDLE);
3684 		break;
3685 	default:
3686 		rc = EINVAL;
3687 		goto fail2;
3688 	}
3689 
3690 	return (0);
3691 
3692 fail2:
3693 	EFSYS_PROBE(fail2);
3694 fail1:
3695 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
3696 	return (rc);
3697 }
3698 
3699 static	__checkReturn			efx_rc_t
3700 efx_mae_read_mport_journal_batch(
3701 	__in				efx_nic_t *enp,
3702 	__in				efx_mae_read_mport_journal_cb *cbp,
3703 	__in				void *cb_datap,
3704 	__out				uint32_t *morep)
3705 {
3706 	efx_mcdi_req_t req;
3707 	EFX_MCDI_DECLARE_BUF(payload,
3708 	    MC_CMD_MAE_MPORT_READ_JOURNAL_IN_LEN,
3709 	    MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LENMAX_MCDI2);
3710 	uint32_t n_entries;
3711 	uint32_t entry_sz;
3712 	uint8_t *entry_buf;
3713 	unsigned int i;
3714 	efx_rc_t rc;
3715 
3716 	EFX_STATIC_ASSERT(EFX_MPORT_TYPE_NET_PORT ==
3717 	    MAE_MPORT_DESC_V2_MPORT_TYPE_NET_PORT);
3718 	EFX_STATIC_ASSERT(EFX_MPORT_TYPE_ALIAS ==
3719 	    MAE_MPORT_DESC_V2_MPORT_TYPE_ALIAS);
3720 	EFX_STATIC_ASSERT(EFX_MPORT_TYPE_VNIC ==
3721 	    MAE_MPORT_DESC_V2_MPORT_TYPE_VNIC);
3722 
3723 	EFX_STATIC_ASSERT(EFX_MPORT_VNIC_CLIENT_FUNCTION ==
3724 	    MAE_MPORT_DESC_V2_VNIC_CLIENT_TYPE_FUNCTION);
3725 	EFX_STATIC_ASSERT(EFX_MPORT_VNIC_CLIENT_PLUGIN ==
3726 	    MAE_MPORT_DESC_V2_VNIC_CLIENT_TYPE_PLUGIN);
3727 
3728 	if (cbp == NULL) {
3729 		rc = EINVAL;
3730 		goto fail1;
3731 	}
3732 
3733 	req.emr_cmd = MC_CMD_MAE_MPORT_READ_JOURNAL;
3734 	req.emr_in_buf = payload;
3735 	req.emr_in_length = MC_CMD_MAE_MPORT_READ_JOURNAL_IN_LEN;
3736 	req.emr_out_buf = payload;
3737 	req.emr_out_length = MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LENMAX_MCDI2;
3738 
3739 	MCDI_IN_SET_DWORD(req, MAE_MPORT_READ_JOURNAL_IN_FLAGS, 0);
3740 
3741 	efx_mcdi_execute(enp, &req);
3742 
3743 	if (req.emr_rc != 0) {
3744 		rc = req.emr_rc;
3745 		goto fail2;
3746 	}
3747 
3748 	if (req.emr_out_length_used <
3749 	    MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LENMIN) {
3750 		rc = EMSGSIZE;
3751 		goto fail3;
3752 	}
3753 
3754 	if (morep != NULL) {
3755 		*morep = MCDI_OUT_DWORD_FIELD(req,
3756 		    MAE_MPORT_READ_JOURNAL_OUT_FLAGS,
3757 		    MAE_MPORT_READ_JOURNAL_OUT_MORE);
3758 	}
3759 	n_entries = MCDI_OUT_DWORD(req,
3760 	    MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_COUNT);
3761 	entry_sz = MCDI_OUT_DWORD(req,
3762 	    MAE_MPORT_READ_JOURNAL_OUT_SIZEOF_MPORT_DESC);
3763 	entry_buf = MCDI_OUT2(req, uint8_t,
3764 	    MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_DATA);
3765 
3766 	if (entry_sz < MAE_MPORT_DESC_V2_VNIC_CLIENT_HANDLE_OFST +
3767 	    MAE_MPORT_DESC_V2_VNIC_CLIENT_HANDLE_LEN) {
3768 		rc = EINVAL;
3769 		goto fail4;
3770 	}
3771 	if (n_entries * entry_sz / entry_sz != n_entries) {
3772 		rc = EINVAL;
3773 		goto fail5;
3774 	}
3775 	if (req.emr_out_length_used !=
3776 	    MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LENMIN + n_entries * entry_sz) {
3777 		rc = EINVAL;
3778 		goto fail6;
3779 	}
3780 
3781 	for (i = 0; i < n_entries; i++) {
3782 		efx_mport_desc_t desc;
3783 
3784 		rc = efx_mae_read_mport_journal_single(entry_buf, &desc);
3785 		if (rc != 0)
3786 			continue;
3787 
3788 		(*cbp)(cb_datap, &desc, sizeof (desc));
3789 		entry_buf += entry_sz;
3790 	}
3791 
3792 	return (0);
3793 
3794 fail6:
3795 	EFSYS_PROBE(fail6);
3796 fail5:
3797 	EFSYS_PROBE(fail5);
3798 fail4:
3799 	EFSYS_PROBE(fail4);
3800 fail3:
3801 	EFSYS_PROBE(fail3);
3802 fail2:
3803 	EFSYS_PROBE(fail2);
3804 fail1:
3805 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
3806 	return (rc);
3807 }
3808 
3809 	__checkReturn			efx_rc_t
3810 efx_mae_read_mport_journal(
3811 	__in				efx_nic_t *enp,
3812 	__in				efx_mae_read_mport_journal_cb *cbp,
3813 	__in				void *cb_datap)
3814 {
3815 	const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
3816 	uint32_t more = 0;
3817 	efx_rc_t rc;
3818 
3819 	if (encp->enc_mae_supported == B_FALSE) {
3820 		rc = ENOTSUP;
3821 		goto fail1;
3822 	}
3823 
3824 	do {
3825 		rc = efx_mae_read_mport_journal_batch(enp, cbp, cb_datap,
3826 		    &more);
3827 		if (rc != 0)
3828 			goto fail2;
3829 	} while (more != 0);
3830 
3831 	return (0);
3832 
3833 fail2:
3834 	EFSYS_PROBE(fail2);
3835 fail1:
3836 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
3837 	return (rc);
3838 }
3839 
3840 #endif /* EFSYS_OPT_MAE */
3841