xref: /freebsd/sys/dev/sfxge/common/efx_lic.c (revision 1f4bcc459a76b7aa664f3fd557684cd0ba6da352)
1 /*-
2  * Copyright (c) 2009-2015 Solarflare Communications Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  *    this list of conditions and the following disclaimer in the documentation
12  *    and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * The views and conclusions contained in the software and documentation are
27  * those of the authors and should not be interpreted as representing official
28  * policies, either expressed or implied, of the FreeBSD Project.
29  */
30 
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33 
34 #include "efx.h"
35 #include "efx_impl.h"
36 
37 #if EFSYS_OPT_LICENSING
38 
39 #if EFSYS_OPT_SIENA
40 
41 static	__checkReturn	efx_rc_t
42 efx_mcdi_fc_license_update_license(
43 	__in		efx_nic_t *enp);
44 
45 static	__checkReturn	efx_rc_t
46 efx_mcdi_fc_license_get_key_stats(
47 	__in		efx_nic_t *enp,
48 	__out		efx_key_stats_t *eksp);
49 
50 static efx_lic_ops_t	__efx_lic_v1_ops = {
51 	efx_mcdi_fc_license_update_license,	/* elo_update_licenses */
52 	efx_mcdi_fc_license_get_key_stats,	/* elo_get_key_stats */
53 	NULL,					/* elo_app_state */
54 	NULL,					/* elo_get_id */
55 };
56 
57 #endif	/* EFSYS_OPT_SIENA */
58 
59 #if EFSYS_OPT_HUNTINGTON
60 
61 static	__checkReturn	efx_rc_t
62 efx_mcdi_licensing_update_licenses(
63 	__in		efx_nic_t *enp);
64 
65 static	__checkReturn	efx_rc_t
66 efx_mcdi_licensing_get_key_stats(
67 	__in		efx_nic_t *enp,
68 	__out		efx_key_stats_t *eksp);
69 
70 static	__checkReturn	efx_rc_t
71 efx_mcdi_licensed_app_state(
72 	__in		efx_nic_t *enp,
73 	__in		uint64_t app_id,
74 	__out		boolean_t *licensedp);
75 
76 static efx_lic_ops_t	__efx_lic_v2_ops = {
77 	efx_mcdi_licensing_update_licenses,	/* elo_update_licenses */
78 	efx_mcdi_licensing_get_key_stats,	/* elo_get_key_stats */
79 	efx_mcdi_licensed_app_state,		/* elo_app_state */
80 	NULL,					/* elo_get_id */
81 };
82 
83 #endif	/* EFSYS_OPT_HUNTINGTON */
84 
85 #if EFSYS_OPT_MEDFORD
86 
87 static	__checkReturn	efx_rc_t
88 efx_mcdi_licensing_v3_update_licenses(
89 	__in		efx_nic_t *enp);
90 
91 static	__checkReturn	efx_rc_t
92 efx_mcdi_licensing_v3_report_license(
93 	__in		efx_nic_t *enp,
94 	__out		efx_key_stats_t *eksp);
95 
96 static	__checkReturn	efx_rc_t
97 efx_mcdi_licensing_v3_app_state(
98 	__in		efx_nic_t *enp,
99 	__in		uint64_t app_id,
100 	__out		boolean_t *licensedp);
101 
102 static	__checkReturn	efx_rc_t
103 efx_mcdi_licensing_v3_get_id(
104 	__in		efx_nic_t *enp,
105 	__in		size_t buffer_size,
106 	__out		uint32_t *typep,
107 	__out		size_t *lengthp,
108 	__out_bcount_part_opt(buffer_size, *lengthp)
109 			uint8_t *bufferp);
110 
111 static efx_lic_ops_t	__efx_lic_v3_ops = {
112 	efx_mcdi_licensing_v3_update_licenses,	/* elo_update_licenses */
113 	efx_mcdi_licensing_v3_report_license,	/* elo_get_key_stats */
114 	efx_mcdi_licensing_v3_app_state,	/* elo_app_state */
115 	efx_mcdi_licensing_v3_get_id,		/* elo_get_id */
116 };
117 
118 #endif	/* EFSYS_OPT_MEDFORD */
119 
120 
121 /* V1 Licensing - used in Siena Modena only */
122 
123 #if EFSYS_OPT_SIENA
124 
125 static	__checkReturn	efx_rc_t
126 efx_mcdi_fc_license_update_license(
127 	__in		efx_nic_t *enp)
128 {
129 	efx_mcdi_req_t req;
130 	uint8_t payload[MC_CMD_FC_IN_LICENSE_LEN];
131 	efx_rc_t rc;
132 
133 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
134 
135 	(void) memset(payload, 0, sizeof (payload));
136 	req.emr_cmd = MC_CMD_FC_OP_LICENSE;
137 	req.emr_in_buf = payload;
138 	req.emr_in_length = MC_CMD_FC_IN_LICENSE_LEN;
139 	req.emr_out_buf = payload;
140 	req.emr_out_length = 0;
141 
142 	MCDI_IN_SET_DWORD(req, FC_IN_LICENSE_OP,
143 	    MC_CMD_FC_IN_LICENSE_UPDATE_LICENSE);
144 
145 	efx_mcdi_execute(enp, &req);
146 
147 	if (req.emr_rc != 0) {
148 		rc = req.emr_rc;
149 		goto fail1;
150 	}
151 
152 	if (req.emr_out_length_used != 0) {
153 		rc = EIO;
154 		goto fail2;
155 	}
156 
157 	return (0);
158 
159 fail2:
160 	EFSYS_PROBE(fail2);
161 fail1:
162 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
163 
164 	return (rc);
165 }
166 
167 static	__checkReturn	efx_rc_t
168 efx_mcdi_fc_license_get_key_stats(
169 	__in		efx_nic_t *enp,
170 	__out		efx_key_stats_t *eksp)
171 {
172 	efx_mcdi_req_t req;
173 	uint8_t payload[MAX(MC_CMD_FC_IN_LICENSE_LEN,
174 			    MC_CMD_FC_OUT_LICENSE_LEN)];
175 	efx_rc_t rc;
176 
177 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
178 
179 	(void) memset(payload, 0, sizeof (payload));
180 	req.emr_cmd = MC_CMD_FC_OP_LICENSE;
181 	req.emr_in_buf = payload;
182 	req.emr_in_length = MC_CMD_FC_IN_LICENSE_LEN;
183 	req.emr_out_buf = payload;
184 	req.emr_out_length = MC_CMD_FC_OUT_LICENSE_LEN;
185 
186 	MCDI_IN_SET_DWORD(req, FC_IN_LICENSE_OP,
187 	    MC_CMD_FC_IN_LICENSE_GET_KEY_STATS);
188 
189 	efx_mcdi_execute(enp, &req);
190 
191 	if (req.emr_rc != 0) {
192 		rc = req.emr_rc;
193 		goto fail1;
194 	}
195 
196 	if (req.emr_out_length_used < MC_CMD_FC_OUT_LICENSE_LEN) {
197 		rc = EMSGSIZE;
198 		goto fail2;
199 	}
200 
201 	eksp->eks_valid =
202 		MCDI_OUT_DWORD(req, FC_OUT_LICENSE_VALID_KEYS);
203 	eksp->eks_invalid =
204 		MCDI_OUT_DWORD(req, FC_OUT_LICENSE_INVALID_KEYS);
205 	eksp->eks_blacklisted =
206 		MCDI_OUT_DWORD(req, FC_OUT_LICENSE_BLACKLISTED_KEYS);
207 	eksp->eks_unverifiable = 0;
208 	eksp->eks_wrong_node = 0;
209 	eksp->eks_licensed_apps_lo = 0;
210 	eksp->eks_licensed_apps_hi = 0;
211 	eksp->eks_licensed_features_lo = 0;
212 	eksp->eks_licensed_features_hi = 0;
213 
214 	return (0);
215 
216 fail2:
217 	EFSYS_PROBE(fail2);
218 fail1:
219 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
220 
221 	return (rc);
222 }
223 
224 #endif	/* EFSYS_OPT_SIENA */
225 
226 /* V2 Licensing - used by Huntington family only. See SF-113611-TC */
227 
228 #if EFSYS_OPT_HUNTINGTON
229 
230 static	__checkReturn	efx_rc_t
231 efx_mcdi_licensed_app_state(
232 	__in		efx_nic_t *enp,
233 	__in		uint64_t app_id,
234 	__out		boolean_t *licensedp)
235 {
236 	efx_mcdi_req_t req;
237 	uint8_t payload[MAX(MC_CMD_GET_LICENSED_APP_STATE_IN_LEN,
238 			    MC_CMD_GET_LICENSED_APP_STATE_OUT_LEN)];
239 	uint32_t app_state;
240 	efx_rc_t rc;
241 
242 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
243 
244 	/* V2 licensing supports 32bit app id only */
245 	if ((app_id >> 32) != 0) {
246 		rc = EINVAL;
247 		goto fail1;
248 	}
249 
250 	(void) memset(payload, 0, sizeof (payload));
251 	req.emr_cmd = MC_CMD_GET_LICENSED_APP_STATE;
252 	req.emr_in_buf = payload;
253 	req.emr_in_length = MC_CMD_GET_LICENSED_APP_STATE_IN_LEN;
254 	req.emr_out_buf = payload;
255 	req.emr_out_length = MC_CMD_GET_LICENSED_APP_STATE_OUT_LEN;
256 
257 	MCDI_IN_SET_DWORD(req, GET_LICENSED_APP_STATE_IN_APP_ID,
258 		    app_id & 0xffffffff);
259 
260 	efx_mcdi_execute(enp, &req);
261 
262 	if (req.emr_rc != 0) {
263 		rc = req.emr_rc;
264 		goto fail2;
265 	}
266 
267 	if (req.emr_out_length_used < MC_CMD_GET_LICENSED_APP_STATE_OUT_LEN) {
268 		rc = EMSGSIZE;
269 		goto fail3;
270 	}
271 
272 	app_state = (MCDI_OUT_DWORD(req, GET_LICENSED_APP_STATE_OUT_STATE));
273 	if (app_state != MC_CMD_GET_LICENSED_APP_STATE_OUT_NOT_LICENSED) {
274 		*licensedp = B_TRUE;
275 	} else {
276 		*licensedp = B_FALSE;
277 	}
278 
279 	return (0);
280 
281 fail3:
282 	EFSYS_PROBE(fail3);
283 fail2:
284 	EFSYS_PROBE(fail2);
285 fail1:
286 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
287 
288 	return (rc);
289 }
290 
291 static	__checkReturn	efx_rc_t
292 efx_mcdi_licensing_update_licenses(
293 	__in		efx_nic_t *enp)
294 {
295 	efx_mcdi_req_t req;
296 	uint8_t payload[MC_CMD_LICENSING_IN_LEN];
297 	efx_rc_t rc;
298 
299 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
300 
301 	(void) memset(payload, 0, sizeof (payload));
302 	req.emr_cmd = MC_CMD_LICENSING;
303 	req.emr_in_buf = payload;
304 	req.emr_in_length = MC_CMD_LICENSING_IN_LEN;
305 	req.emr_out_buf = payload;
306 	req.emr_out_length = 0;
307 
308 	MCDI_IN_SET_DWORD(req, LICENSING_IN_OP,
309 	    MC_CMD_LICENSING_IN_OP_UPDATE_LICENSE);
310 
311 	efx_mcdi_execute(enp, &req);
312 
313 	if (req.emr_rc != 0) {
314 		rc = req.emr_rc;
315 		goto fail1;
316 	}
317 
318 	if (req.emr_out_length_used != 0) {
319 		rc = EIO;
320 		goto fail2;
321 	}
322 
323 	return (0);
324 
325 fail2:
326 	EFSYS_PROBE(fail2);
327 fail1:
328 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
329 
330 	return (rc);
331 }
332 
333 static	__checkReturn	efx_rc_t
334 efx_mcdi_licensing_get_key_stats(
335 	__in		efx_nic_t *enp,
336 	__out		efx_key_stats_t *eksp)
337 {
338 	efx_mcdi_req_t req;
339 	uint8_t payload[MAX(MC_CMD_LICENSING_IN_LEN,
340 			    MC_CMD_LICENSING_OUT_LEN)];
341 	efx_rc_t rc;
342 
343 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
344 
345 	(void) memset(payload, 0, sizeof (payload));
346 	req.emr_cmd = MC_CMD_LICENSING;
347 	req.emr_in_buf = payload;
348 	req.emr_in_length = MC_CMD_LICENSING_IN_LEN;
349 	req.emr_out_buf = payload;
350 	req.emr_out_length = MC_CMD_LICENSING_OUT_LEN;
351 
352 	MCDI_IN_SET_DWORD(req, LICENSING_IN_OP,
353 	    MC_CMD_LICENSING_IN_OP_GET_KEY_STATS);
354 
355 	efx_mcdi_execute(enp, &req);
356 
357 	if (req.emr_rc != 0) {
358 		rc = req.emr_rc;
359 		goto fail1;
360 	}
361 
362 	if (req.emr_out_length_used < MC_CMD_LICENSING_OUT_LEN) {
363 		rc = EMSGSIZE;
364 		goto fail2;
365 	}
366 
367 	eksp->eks_valid =
368 		MCDI_OUT_DWORD(req, LICENSING_OUT_VALID_APP_KEYS);
369 	eksp->eks_invalid =
370 		MCDI_OUT_DWORD(req, LICENSING_OUT_INVALID_APP_KEYS);
371 	eksp->eks_blacklisted =
372 		MCDI_OUT_DWORD(req, LICENSING_OUT_BLACKLISTED_APP_KEYS);
373 	eksp->eks_unverifiable =
374 		MCDI_OUT_DWORD(req, LICENSING_OUT_UNVERIFIABLE_APP_KEYS);
375 	eksp->eks_wrong_node =
376 		MCDI_OUT_DWORD(req, LICENSING_OUT_WRONG_NODE_APP_KEYS);
377 	eksp->eks_licensed_apps_lo = 0;
378 	eksp->eks_licensed_apps_hi = 0;
379 	eksp->eks_licensed_features_lo = 0;
380 	eksp->eks_licensed_features_hi = 0;
381 
382 	return (0);
383 
384 fail2:
385 	EFSYS_PROBE(fail2);
386 fail1:
387 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
388 
389 	return (rc);
390 }
391 
392 #endif	/* EFSYS_OPT_HUNTINGTON */
393 
394 /* V3 Licensing - used starting from Medford family. See SF-114884-SW */
395 
396 #if EFSYS_OPT_MEDFORD
397 
398 static	__checkReturn	efx_rc_t
399 efx_mcdi_licensing_v3_update_licenses(
400 	__in		efx_nic_t *enp)
401 {
402 	efx_mcdi_req_t req;
403 	uint8_t payload[MC_CMD_LICENSING_V3_IN_LEN];
404 	efx_rc_t rc;
405 
406 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_MEDFORD);
407 
408 	(void) memset(payload, 0, sizeof (payload));
409 	req.emr_cmd = MC_CMD_LICENSING_V3;
410 	req.emr_in_buf = payload;
411 	req.emr_in_length = MC_CMD_LICENSING_V3_IN_LEN;
412 	req.emr_out_buf = NULL;
413 	req.emr_out_length = 0;
414 
415 	MCDI_IN_SET_DWORD(req, LICENSING_V3_IN_OP,
416 	    MC_CMD_LICENSING_V3_IN_OP_UPDATE_LICENSE);
417 
418 	efx_mcdi_execute(enp, &req);
419 
420 	if (req.emr_rc != 0) {
421 		rc = req.emr_rc;
422 		goto fail1;
423 	}
424 
425 	return (0);
426 
427 fail1:
428 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
429 
430 	return (rc);
431 }
432 
433 static	__checkReturn	efx_rc_t
434 efx_mcdi_licensing_v3_report_license(
435 	__in		efx_nic_t *enp,
436 	__out		efx_key_stats_t *eksp)
437 {
438 	efx_mcdi_req_t req;
439 	uint8_t payload[MAX(MC_CMD_LICENSING_V3_IN_LEN,
440 			    MC_CMD_LICENSING_V3_OUT_LEN)];
441 	efx_rc_t rc;
442 
443 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_MEDFORD);
444 
445 	(void) memset(payload, 0, sizeof (payload));
446 	req.emr_cmd = MC_CMD_LICENSING_V3;
447 	req.emr_in_buf = payload;
448 	req.emr_in_length = MC_CMD_LICENSING_V3_IN_LEN;
449 	req.emr_out_buf = payload;
450 	req.emr_out_length = MC_CMD_LICENSING_V3_OUT_LEN;
451 
452 	MCDI_IN_SET_DWORD(req, LICENSING_V3_IN_OP,
453 	    MC_CMD_LICENSING_V3_IN_OP_REPORT_LICENSE);
454 
455 	efx_mcdi_execute(enp, &req);
456 
457 	if (req.emr_rc != 0) {
458 		rc = req.emr_rc;
459 		goto fail1;
460 	}
461 
462 	if (req.emr_out_length_used < MC_CMD_LICENSING_V3_OUT_LEN) {
463 		rc = EMSGSIZE;
464 		goto fail2;
465 	}
466 
467 	eksp->eks_valid =
468 		MCDI_OUT_DWORD(req, LICENSING_V3_OUT_VALID_KEYS);
469 	eksp->eks_invalid =
470 		MCDI_OUT_DWORD(req, LICENSING_V3_OUT_INVALID_KEYS);
471 	eksp->eks_blacklisted = 0;
472 	eksp->eks_unverifiable =
473 		MCDI_OUT_DWORD(req, LICENSING_V3_OUT_UNVERIFIABLE_KEYS);
474 	eksp->eks_wrong_node =
475 		MCDI_OUT_DWORD(req, LICENSING_V3_OUT_WRONG_NODE_KEYS);
476 	eksp->eks_licensed_apps_lo =
477 		MCDI_OUT_DWORD(req, LICENSING_V3_OUT_LICENSED_APPS_LO);
478 	eksp->eks_licensed_apps_hi =
479 		MCDI_OUT_DWORD(req, LICENSING_V3_OUT_LICENSED_APPS_HI);
480 	eksp->eks_licensed_features_lo =
481 		MCDI_OUT_DWORD(req, LICENSING_V3_OUT_LICENSED_FEATURES_LO);
482 	eksp->eks_licensed_features_hi =
483 		MCDI_OUT_DWORD(req, LICENSING_V3_OUT_LICENSED_FEATURES_HI);
484 
485 	return (0);
486 
487 fail2:
488 	EFSYS_PROBE(fail2);
489 fail1:
490 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
491 
492 	return (rc);
493 }
494 
495 static	__checkReturn	efx_rc_t
496 efx_mcdi_licensing_v3_app_state(
497 	__in		efx_nic_t *enp,
498 	__in		uint64_t app_id,
499 	__out		boolean_t *licensedp)
500 {
501 	efx_mcdi_req_t req;
502 	uint8_t payload[MAX(MC_CMD_GET_LICENSED_V3_APP_STATE_IN_LEN,
503 			    MC_CMD_GET_LICENSED_V3_APP_STATE_OUT_LEN)];
504 	uint32_t app_state;
505 	efx_rc_t rc;
506 
507 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_MEDFORD);
508 
509 	(void) memset(payload, 0, sizeof (payload));
510 	req.emr_cmd = MC_CMD_GET_LICENSED_V3_APP_STATE;
511 	req.emr_in_buf = payload;
512 	req.emr_in_length = MC_CMD_GET_LICENSED_V3_APP_STATE_IN_LEN;
513 	req.emr_out_buf = payload;
514 	req.emr_out_length = MC_CMD_GET_LICENSED_V3_APP_STATE_OUT_LEN;
515 
516 	MCDI_IN_SET_DWORD(req, GET_LICENSED_V3_APP_STATE_IN_APP_ID_LO,
517 		    app_id & 0xffffffff);
518 	MCDI_IN_SET_DWORD(req, GET_LICENSED_V3_APP_STATE_IN_APP_ID_HI,
519 		    app_id >> 32);
520 
521 	efx_mcdi_execute(enp, &req);
522 
523 	if (req.emr_rc != 0) {
524 		rc = req.emr_rc;
525 		goto fail1;
526 	}
527 
528 	if (req.emr_out_length_used < MC_CMD_GET_LICENSED_V3_APP_STATE_OUT_LEN) {
529 		rc = EMSGSIZE;
530 		goto fail2;
531 	}
532 
533 	app_state = (MCDI_OUT_DWORD(req, GET_LICENSED_V3_APP_STATE_OUT_STATE));
534 	if (app_state != MC_CMD_GET_LICENSED_V3_APP_STATE_OUT_NOT_LICENSED) {
535 		*licensedp = B_TRUE;
536 	} else {
537 		*licensedp = B_FALSE;
538 	}
539 
540 	return (0);
541 
542 fail2:
543 	EFSYS_PROBE(fail2);
544 fail1:
545 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
546 
547 	return (rc);
548 }
549 
550 static	__checkReturn	efx_rc_t
551 efx_mcdi_licensing_v3_get_id(
552 	__in		efx_nic_t *enp,
553 	__in		size_t buffer_size,
554 	__out		uint32_t *typep,
555 	__out		size_t *lengthp,
556 	__out_bcount_part_opt(buffer_size, *lengthp)
557 			uint8_t *bufferp)
558 {
559 	efx_mcdi_req_t req;
560 	uint8_t payload[MAX(MC_CMD_LICENSING_GET_ID_V3_IN_LEN,
561 			    MC_CMD_LICENSING_GET_ID_V3_OUT_LENMIN)];
562 	efx_rc_t rc;
563 
564 	req.emr_cmd = MC_CMD_LICENSING_GET_ID_V3;
565 
566 	if (bufferp == NULL) {
567 		/* Request id type and length only */
568 		req.emr_in_buf = bufferp;
569 		req.emr_in_length = MC_CMD_LICENSING_GET_ID_V3_IN_LEN;
570 		req.emr_out_buf = bufferp;
571 		req.emr_out_length = MC_CMD_LICENSING_GET_ID_V3_OUT_LENMIN;
572 		(void) memset(payload, 0, sizeof (payload));
573 	} else {
574 		/* Request full buffer */
575 		req.emr_in_buf = bufferp;
576 		req.emr_in_length = MC_CMD_LICENSING_GET_ID_V3_IN_LEN;
577 		req.emr_out_buf = bufferp;
578 		req.emr_out_length = MIN(buffer_size, MC_CMD_LICENSING_GET_ID_V3_OUT_LENMIN);
579 		(void) memset(bufferp, 0, req.emr_out_length);
580 	}
581 
582 	efx_mcdi_execute(enp, &req);
583 
584 	if (req.emr_rc != 0) {
585 		rc = req.emr_rc;
586 		goto fail1;
587 	}
588 
589 	if (req.emr_out_length_used < MC_CMD_LICENSING_GET_ID_V3_OUT_LENMIN) {
590 		rc = EMSGSIZE;
591 		goto fail2;
592 	}
593 
594 	*typep = MCDI_OUT_DWORD(req, LICENSING_GET_ID_V3_OUT_LICENSE_TYPE);
595 	*lengthp = MCDI_OUT_DWORD(req, LICENSING_GET_ID_V3_OUT_LICENSE_ID_LENGTH);
596 
597 	if (bufferp == NULL) {
598 		/* modify length requirements to indicate to caller the extra buffering
599 		** needed to read the complete output.
600 		*/
601 		*lengthp += MC_CMD_LICENSING_GET_ID_V3_OUT_LENMIN;
602 	} else {
603 		/* Shift ID down to start of buffer */
604 		memmove(bufferp,
605 		  bufferp+MC_CMD_LICENSING_GET_ID_V3_OUT_LICENSE_ID_OFST,
606 		  *lengthp);
607 		memset(bufferp+(*lengthp), 0, MC_CMD_LICENSING_GET_ID_V3_OUT_LICENSE_ID_OFST);
608 	}
609 
610 	return (0);
611 
612 fail2:
613 	EFSYS_PROBE(fail2);
614 fail1:
615 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
616 
617 	return (rc);
618 }
619 
620 
621 #endif	/* EFSYS_OPT_MEDFORD */
622 
623 	__checkReturn		efx_rc_t
624 efx_lic_init(
625 	__in			efx_nic_t *enp)
626 {
627 	efx_lic_ops_t *elop;
628 	efx_rc_t rc;
629 
630 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
631 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
632 	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_LIC));
633 
634 	switch (enp->en_family) {
635 
636 #if EFSYS_OPT_SIENA
637 	case EFX_FAMILY_SIENA:
638 		elop = (efx_lic_ops_t *)&__efx_lic_v1_ops;
639 		break;
640 #endif	/* EFSYS_OPT_SIENA */
641 
642 #if EFSYS_OPT_HUNTINGTON
643 	case EFX_FAMILY_HUNTINGTON:
644 		elop = (efx_lic_ops_t *)&__efx_lic_v2_ops;
645 		break;
646 #endif	/* EFSYS_OPT_HUNTINGTON */
647 
648 #if EFSYS_OPT_MEDFORD
649 	case EFX_FAMILY_MEDFORD:
650 		elop = (efx_lic_ops_t *)&__efx_lic_v3_ops;
651 		break;
652 #endif	/* EFSYS_OPT_MEDFORD */
653 
654 	default:
655 		EFSYS_ASSERT(0);
656 		rc = ENOTSUP;
657 		goto fail1;
658 	}
659 
660 	enp->en_elop = elop;
661 	enp->en_mod_flags |= EFX_MOD_LIC;
662 
663 	return (0);
664 
665 fail1:
666 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
667 
668 	return (rc);
669 }
670 
671 				void
672 efx_lic_fini(
673 	__in			efx_nic_t *enp)
674 {
675 	efx_lic_ops_t *elop = enp->en_elop;
676 
677 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
678 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
679 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_LIC);
680 
681 	enp->en_elop = NULL;
682 	enp->en_mod_flags &= ~EFX_MOD_LIC;
683 }
684 
685 
686 	__checkReturn	efx_rc_t
687 efx_lic_update_licenses(
688 	__in		efx_nic_t *enp)
689 {
690 	efx_lic_ops_t *elop = enp->en_elop;
691 	efx_rc_t rc;
692 
693 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
694 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_LIC);
695 
696 	if ((rc = elop->elo_update_licenses(enp)) != 0)
697 		goto fail1;
698 
699 	return (0);
700 
701 fail1:
702 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
703 
704 	return (rc);
705 }
706 
707 	__checkReturn	efx_rc_t
708 efx_lic_get_key_stats(
709 	__in		efx_nic_t *enp,
710 	__out		efx_key_stats_t *eksp)
711 {
712 	efx_lic_ops_t *elop = enp->en_elop;
713 	efx_rc_t rc;
714 
715 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
716 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_LIC);
717 
718 	if ((rc = elop->elo_get_key_stats(enp, eksp)) != 0)
719 		goto fail1;
720 
721 	return (0);
722 
723 fail1:
724 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
725 
726 	return (rc);
727 }
728 
729 	__checkReturn	efx_rc_t
730 efx_lic_app_state(
731 	__in		efx_nic_t *enp,
732 	__in		uint64_t app_id,
733 	__out		boolean_t *licensedp)
734 {
735 	efx_lic_ops_t *elop = enp->en_elop;
736 	efx_rc_t rc;
737 
738 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
739 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_LIC);
740 
741 	if (elop->elo_app_state == NULL) {
742 		rc = ENOTSUP;
743 		goto fail1;
744 	}
745 	if ((rc = elop->elo_app_state(enp, app_id, licensedp)) != 0)
746 		goto fail2;
747 
748 	return (0);
749 
750 fail2:
751 	EFSYS_PROBE(fail2);
752 fail1:
753 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
754 
755 	return (rc);
756 }
757 
758 	__checkReturn	efx_rc_t
759 efx_lic_get_id(
760 	__in		efx_nic_t *enp,
761 	__in		size_t buffer_size,
762 	__out		uint32_t *typep,
763 	__out		size_t *lengthp,
764 	__out_opt	uint8_t *bufferp
765 	)
766 {
767 	efx_lic_ops_t *elop = enp->en_elop;
768 	efx_rc_t rc;
769 
770 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
771 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_LIC);
772 
773 	if (elop->elo_get_id == NULL) {
774 		rc = ENOTSUP;
775 		goto fail1;
776 	}
777 
778 	if ((rc = elop->elo_get_id(enp, buffer_size, typep,
779 				    lengthp, bufferp)) != 0)
780 		goto fail2;
781 
782 	return (0);
783 
784 fail2:
785 	EFSYS_PROBE(fail2);
786 fail1:
787 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
788 
789 	return (rc);
790 }
791 
792 #endif	/* EFSYS_OPT_LICENSING */
793