1/*-
2 * Copyright (c) 2009-2016 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: stable/10/sys/dev/sfxge/common/efx_lic.c 342516 2018-12-26 10:25:01Z arybchik $");
33
34#include "efx.h"
35#include "efx_impl.h"
36
37#if EFSYS_OPT_LICENSING
38
39#include "ef10_tlv_layout.h"
40
41#if EFSYS_OPT_SIENA | EFSYS_OPT_HUNTINGTON
42
43	__checkReturn		efx_rc_t
44efx_lic_v1v2_find_start(
45	__in			efx_nic_t *enp,
46	__in_bcount(buffer_size)
47				caddr_t bufferp,
48	__in			size_t buffer_size,
49	__out			uint32_t *startp
50	);
51
52	__checkReturn		efx_rc_t
53efx_lic_v1v2_find_end(
54	__in			efx_nic_t *enp,
55	__in_bcount(buffer_size)
56				caddr_t bufferp,
57	__in			size_t buffer_size,
58	__in			uint32_t offset,
59	__out			uint32_t *endp
60	);
61
62	__checkReturn	__success(return != B_FALSE)	boolean_t
63efx_lic_v1v2_find_key(
64	__in			efx_nic_t *enp,
65	__in_bcount(buffer_size)
66				caddr_t bufferp,
67	__in			size_t buffer_size,
68	__in			uint32_t offset,
69	__out			uint32_t *startp,
70	__out			uint32_t *lengthp
71	);
72
73	__checkReturn	__success(return != B_FALSE)	boolean_t
74efx_lic_v1v2_validate_key(
75	__in			efx_nic_t *enp,
76	__in_bcount(length)	caddr_t keyp,
77	__in			uint32_t length
78	);
79
80	__checkReturn		efx_rc_t
81efx_lic_v1v2_read_key(
82	__in			efx_nic_t *enp,
83	__in_bcount(buffer_size)
84				caddr_t bufferp,
85	__in			size_t buffer_size,
86	__in			uint32_t offset,
87	__in			uint32_t length,
88	__out_bcount_part(key_max_size, *lengthp)
89				caddr_t keyp,
90	__in			size_t key_max_size,
91	__out			uint32_t *lengthp
92	);
93
94	__checkReturn		efx_rc_t
95efx_lic_v1v2_write_key(
96	__in			efx_nic_t *enp,
97	__in_bcount(buffer_size)
98				caddr_t bufferp,
99	__in			size_t buffer_size,
100	__in			uint32_t offset,
101	__in_bcount(length)	caddr_t keyp,
102	__in			uint32_t length,
103	__out			uint32_t *lengthp
104	);
105
106	__checkReturn		efx_rc_t
107efx_lic_v1v2_delete_key(
108	__in			efx_nic_t *enp,
109	__in_bcount(buffer_size)
110				caddr_t bufferp,
111	__in			size_t buffer_size,
112	__in			uint32_t offset,
113	__in			uint32_t length,
114	__in			uint32_t end,
115	__out			uint32_t *deltap
116	);
117
118	__checkReturn		efx_rc_t
119efx_lic_v1v2_create_partition(
120	__in			efx_nic_t *enp,
121	__in_bcount(buffer_size)
122				caddr_t bufferp,
123	__in			size_t buffer_size
124	);
125
126	__checkReturn		efx_rc_t
127efx_lic_v1v2_finish_partition(
128	__in			efx_nic_t *enp,
129	__in_bcount(buffer_size)
130				caddr_t bufferp,
131	__in			size_t buffer_size
132	);
133
134#endif	/* EFSYS_OPT_HUNTINGTON | EFSYS_OPT_SIENA */
135
136
137#if EFSYS_OPT_SIENA
138
139static	__checkReturn	efx_rc_t
140efx_mcdi_fc_license_update_license(
141	__in		efx_nic_t *enp);
142
143static	__checkReturn	efx_rc_t
144efx_mcdi_fc_license_get_key_stats(
145	__in		efx_nic_t *enp,
146	__out		efx_key_stats_t *eksp);
147
148static const efx_lic_ops_t	__efx_lic_v1_ops = {
149	efx_mcdi_fc_license_update_license,	/* elo_update_licenses */
150	efx_mcdi_fc_license_get_key_stats,	/* elo_get_key_stats */
151	NULL,					/* elo_app_state */
152	NULL,					/* elo_get_id */
153	efx_lic_v1v2_find_start,		/* elo_find_start */
154	efx_lic_v1v2_find_end,			/* elo_find_end */
155	efx_lic_v1v2_find_key,			/* elo_find_key */
156	efx_lic_v1v2_validate_key,		/* elo_validate_key */
157	efx_lic_v1v2_read_key,			/* elo_read_key */
158	efx_lic_v1v2_write_key,			/* elo_write_key */
159	efx_lic_v1v2_delete_key,		/* elo_delete_key */
160	efx_lic_v1v2_create_partition,		/* elo_create_partition */
161	efx_lic_v1v2_finish_partition,		/* elo_finish_partition */
162};
163
164#endif	/* EFSYS_OPT_SIENA */
165
166#if EFSYS_OPT_HUNTINGTON
167
168static	__checkReturn	efx_rc_t
169efx_mcdi_licensing_update_licenses(
170	__in		efx_nic_t *enp);
171
172static	__checkReturn	efx_rc_t
173efx_mcdi_licensing_get_key_stats(
174	__in		efx_nic_t *enp,
175	__out		efx_key_stats_t *eksp);
176
177static	__checkReturn	efx_rc_t
178efx_mcdi_licensed_app_state(
179	__in		efx_nic_t *enp,
180	__in		uint64_t app_id,
181	__out		boolean_t *licensedp);
182
183static const efx_lic_ops_t	__efx_lic_v2_ops = {
184	efx_mcdi_licensing_update_licenses,	/* elo_update_licenses */
185	efx_mcdi_licensing_get_key_stats,	/* elo_get_key_stats */
186	efx_mcdi_licensed_app_state,		/* elo_app_state */
187	NULL,					/* elo_get_id */
188	efx_lic_v1v2_find_start,		/* elo_find_start */
189	efx_lic_v1v2_find_end,			/* elo_find_end */
190	efx_lic_v1v2_find_key,			/* elo_find_key */
191	efx_lic_v1v2_validate_key,		/* elo_validate_key */
192	efx_lic_v1v2_read_key,			/* elo_read_key */
193	efx_lic_v1v2_write_key,			/* elo_write_key */
194	efx_lic_v1v2_delete_key,		/* elo_delete_key */
195	efx_lic_v1v2_create_partition,		/* elo_create_partition */
196	efx_lic_v1v2_finish_partition,		/* elo_finish_partition */
197};
198
199#endif	/* EFSYS_OPT_HUNTINGTON */
200
201#if EFSYS_OPT_MEDFORD
202
203static	__checkReturn	efx_rc_t
204efx_mcdi_licensing_v3_update_licenses(
205	__in		efx_nic_t *enp);
206
207static	__checkReturn	efx_rc_t
208efx_mcdi_licensing_v3_report_license(
209	__in		efx_nic_t *enp,
210	__out		efx_key_stats_t *eksp);
211
212static	__checkReturn	efx_rc_t
213efx_mcdi_licensing_v3_app_state(
214	__in		efx_nic_t *enp,
215	__in		uint64_t app_id,
216	__out		boolean_t *licensedp);
217
218static	__checkReturn	efx_rc_t
219efx_mcdi_licensing_v3_get_id(
220	__in		efx_nic_t *enp,
221	__in		size_t buffer_size,
222	__out		uint32_t *typep,
223	__out		size_t *lengthp,
224	__out_bcount_part_opt(buffer_size, *lengthp)
225			uint8_t *bufferp);
226
227	__checkReturn		efx_rc_t
228efx_lic_v3_find_start(
229	__in			efx_nic_t *enp,
230	__in_bcount(buffer_size)
231				caddr_t bufferp,
232	__in			size_t buffer_size,
233	__out			uint32_t *startp
234	);
235
236	__checkReturn		efx_rc_t
237efx_lic_v3_find_end(
238	__in			efx_nic_t *enp,
239	__in_bcount(buffer_size)
240				caddr_t bufferp,
241	__in			size_t buffer_size,
242	__in			uint32_t offset,
243	__out			uint32_t *endp
244	);
245
246	__checkReturn	__success(return != B_FALSE)	boolean_t
247efx_lic_v3_find_key(
248	__in			efx_nic_t *enp,
249	__in_bcount(buffer_size)
250				caddr_t bufferp,
251	__in			size_t buffer_size,
252	__in			uint32_t offset,
253	__out			uint32_t *startp,
254	__out			uint32_t *lengthp
255	);
256
257	__checkReturn	__success(return != B_FALSE)	boolean_t
258efx_lic_v3_validate_key(
259	__in			efx_nic_t *enp,
260	__in_bcount(length)	caddr_t keyp,
261	__in			uint32_t length
262	);
263
264	__checkReturn		efx_rc_t
265efx_lic_v3_read_key(
266	__in			efx_nic_t *enp,
267	__in_bcount(buffer_size)
268				caddr_t bufferp,
269	__in			size_t buffer_size,
270	__in			uint32_t offset,
271	__in			uint32_t length,
272	__out_bcount_part(key_max_size, *lengthp)
273				caddr_t keyp,
274	__in			size_t key_max_size,
275	__out			uint32_t *lengthp
276	);
277
278	__checkReturn		efx_rc_t
279efx_lic_v3_write_key(
280	__in			efx_nic_t *enp,
281	__in_bcount(buffer_size)
282				caddr_t bufferp,
283	__in			size_t buffer_size,
284	__in			uint32_t offset,
285	__in_bcount(length)	caddr_t keyp,
286	__in			uint32_t length,
287	__out			uint32_t *lengthp
288	);
289
290	__checkReturn		efx_rc_t
291efx_lic_v3_delete_key(
292	__in			efx_nic_t *enp,
293	__in_bcount(buffer_size)
294				caddr_t bufferp,
295	__in			size_t buffer_size,
296	__in			uint32_t offset,
297	__in			uint32_t length,
298	__in			uint32_t end,
299	__out			uint32_t *deltap
300	);
301
302	__checkReturn		efx_rc_t
303efx_lic_v3_create_partition(
304	__in			efx_nic_t *enp,
305	__in_bcount(buffer_size)
306				caddr_t bufferp,
307	__in			size_t buffer_size
308	);
309
310	__checkReturn		efx_rc_t
311efx_lic_v3_finish_partition(
312	__in			efx_nic_t *enp,
313	__in_bcount(buffer_size)
314				caddr_t bufferp,
315	__in			size_t buffer_size
316	);
317
318static const efx_lic_ops_t	__efx_lic_v3_ops = {
319	efx_mcdi_licensing_v3_update_licenses,	/* elo_update_licenses */
320	efx_mcdi_licensing_v3_report_license,	/* elo_get_key_stats */
321	efx_mcdi_licensing_v3_app_state,	/* elo_app_state */
322	efx_mcdi_licensing_v3_get_id,		/* elo_get_id */
323	efx_lic_v3_find_start,			/* elo_find_start*/
324	efx_lic_v3_find_end,			/* elo_find_end */
325	efx_lic_v3_find_key,			/* elo_find_key */
326	efx_lic_v3_validate_key,		/* elo_validate_key */
327	efx_lic_v3_read_key,			/* elo_read_key */
328	efx_lic_v3_write_key,			/* elo_write_key */
329	efx_lic_v3_delete_key,			/* elo_delete_key */
330	efx_lic_v3_create_partition,		/* elo_create_partition */
331	efx_lic_v3_finish_partition,		/* elo_finish_partition */
332};
333
334#endif	/* EFSYS_OPT_MEDFORD */
335
336
337/* V1 Licensing - used in Siena Modena only */
338
339#if EFSYS_OPT_SIENA
340
341static	__checkReturn	efx_rc_t
342efx_mcdi_fc_license_update_license(
343	__in		efx_nic_t *enp)
344{
345	efx_mcdi_req_t req;
346	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_FC_IN_LICENSE_LEN, 0);
347	efx_rc_t rc;
348
349	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
350
351	req.emr_cmd = MC_CMD_FC;
352	req.emr_in_buf = payload;
353	req.emr_in_length = MC_CMD_FC_IN_LICENSE_LEN;
354	req.emr_out_buf = payload;
355	req.emr_out_length = 0;
356
357	MCDI_IN_SET_DWORD(req, FC_IN_CMD,
358	    MC_CMD_FC_OP_LICENSE);
359
360	MCDI_IN_SET_DWORD(req, FC_IN_LICENSE_OP,
361	    MC_CMD_FC_IN_LICENSE_UPDATE_LICENSE);
362
363	efx_mcdi_execute(enp, &req);
364
365	if (req.emr_rc != 0) {
366		rc = req.emr_rc;
367		goto fail1;
368	}
369
370	if (req.emr_out_length_used != 0) {
371		rc = EIO;
372		goto fail2;
373	}
374
375	return (0);
376
377fail2:
378	EFSYS_PROBE(fail2);
379fail1:
380	EFSYS_PROBE1(fail1, efx_rc_t, rc);
381
382	return (rc);
383}
384
385static	__checkReturn	efx_rc_t
386efx_mcdi_fc_license_get_key_stats(
387	__in		efx_nic_t *enp,
388	__out		efx_key_stats_t *eksp)
389{
390	efx_mcdi_req_t req;
391	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_FC_IN_LICENSE_LEN,
392		MC_CMD_FC_OUT_LICENSE_LEN);
393	efx_rc_t rc;
394
395	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
396
397	req.emr_cmd = MC_CMD_FC;
398	req.emr_in_buf = payload;
399	req.emr_in_length = MC_CMD_FC_IN_LICENSE_LEN;
400	req.emr_out_buf = payload;
401	req.emr_out_length = MC_CMD_FC_OUT_LICENSE_LEN;
402
403	MCDI_IN_SET_DWORD(req, FC_IN_CMD,
404	    MC_CMD_FC_OP_LICENSE);
405
406	MCDI_IN_SET_DWORD(req, FC_IN_LICENSE_OP,
407	    MC_CMD_FC_IN_LICENSE_GET_KEY_STATS);
408
409	efx_mcdi_execute_quiet(enp, &req);
410
411	if (req.emr_rc != 0) {
412		rc = req.emr_rc;
413		goto fail1;
414	}
415
416	if (req.emr_out_length_used < MC_CMD_FC_OUT_LICENSE_LEN) {
417		rc = EMSGSIZE;
418		goto fail2;
419	}
420
421	eksp->eks_valid =
422		MCDI_OUT_DWORD(req, FC_OUT_LICENSE_VALID_KEYS);
423	eksp->eks_invalid =
424		MCDI_OUT_DWORD(req, FC_OUT_LICENSE_INVALID_KEYS);
425	eksp->eks_blacklisted =
426		MCDI_OUT_DWORD(req, FC_OUT_LICENSE_BLACKLISTED_KEYS);
427	eksp->eks_unverifiable = 0;
428	eksp->eks_wrong_node = 0;
429	eksp->eks_licensed_apps_lo = 0;
430	eksp->eks_licensed_apps_hi = 0;
431	eksp->eks_licensed_features_lo = 0;
432	eksp->eks_licensed_features_hi = 0;
433
434	return (0);
435
436fail2:
437	EFSYS_PROBE(fail2);
438fail1:
439	EFSYS_PROBE1(fail1, efx_rc_t, rc);
440
441	return (rc);
442}
443
444#endif	/* EFSYS_OPT_SIENA */
445
446/* V1 and V2 Partition format - based on a 16-bit TLV format */
447
448#if EFSYS_OPT_SIENA | EFSYS_OPT_HUNTINGTON
449
450/*
451 * V1/V2 format - defined in SF-108542-TC section 4.2:
452 *  Type (T):   16bit - revision/HMAC algorithm
453 *  Length (L): 16bit - value length in bytes
454 *  Value (V):  L bytes - payload
455 */
456#define EFX_LICENSE_V1V2_PAYLOAD_LENGTH_MAX    (256)
457#define EFX_LICENSE_V1V2_HEADER_LENGTH         (2 * sizeof(uint16_t))
458
459	__checkReturn		efx_rc_t
460efx_lic_v1v2_find_start(
461	__in			efx_nic_t *enp,
462	__in_bcount(buffer_size)
463				caddr_t bufferp,
464	__in			size_t buffer_size,
465	__out			uint32_t *startp
466	)
467{
468	_NOTE(ARGUNUSED(enp, bufferp, buffer_size))
469
470	*startp = 0;
471	return (0);
472}
473
474	__checkReturn		efx_rc_t
475efx_lic_v1v2_find_end(
476	__in			efx_nic_t *enp,
477	__in_bcount(buffer_size)
478				caddr_t bufferp,
479	__in			size_t buffer_size,
480	__in			uint32_t offset,
481	__out			uint32_t *endp
482	)
483{
484	_NOTE(ARGUNUSED(enp, bufferp, buffer_size))
485
486	*endp = offset + EFX_LICENSE_V1V2_HEADER_LENGTH;
487	return (0);
488}
489
490	__checkReturn	__success(return != B_FALSE)	boolean_t
491efx_lic_v1v2_find_key(
492	__in			efx_nic_t *enp,
493	__in_bcount(buffer_size)
494				caddr_t bufferp,
495	__in			size_t buffer_size,
496	__in			uint32_t offset,
497	__out			uint32_t *startp,
498	__out			uint32_t *lengthp
499	)
500{
501	boolean_t found;
502	uint16_t tlv_type;
503	uint16_t tlv_length;
504
505	_NOTE(ARGUNUSED(enp))
506
507	if ((size_t)buffer_size - offset < EFX_LICENSE_V1V2_HEADER_LENGTH)
508		goto fail1;
509
510	tlv_type = __LE_TO_CPU_16(((uint16_t *)&bufferp[offset])[0]);
511	tlv_length = __LE_TO_CPU_16(((uint16_t *)&bufferp[offset])[1]);
512	if ((tlv_length > EFX_LICENSE_V1V2_PAYLOAD_LENGTH_MAX) ||
513	    (tlv_type == 0 && tlv_length == 0)) {
514		found = B_FALSE;
515	} else {
516		*startp = offset;
517		*lengthp = tlv_length + EFX_LICENSE_V1V2_HEADER_LENGTH;
518		found = B_TRUE;
519	}
520	return (found);
521
522fail1:
523	EFSYS_PROBE1(fail1, boolean_t, B_FALSE);
524
525	return (B_FALSE);
526}
527
528	__checkReturn	__success(return != B_FALSE)	boolean_t
529efx_lic_v1v2_validate_key(
530	__in			efx_nic_t *enp,
531	__in_bcount(length)	caddr_t keyp,
532	__in			uint32_t length
533	)
534{
535	uint16_t tlv_type;
536	uint16_t tlv_length;
537
538	_NOTE(ARGUNUSED(enp))
539
540	if (length < EFX_LICENSE_V1V2_HEADER_LENGTH) {
541		goto fail1;
542	}
543
544	tlv_type = __LE_TO_CPU_16(((uint16_t *)keyp)[0]);
545	tlv_length = __LE_TO_CPU_16(((uint16_t *)keyp)[1]);
546
547	if (tlv_length > EFX_LICENSE_V1V2_PAYLOAD_LENGTH_MAX) {
548		goto fail2;
549	}
550	if (tlv_type == 0) {
551		goto fail3;
552	}
553	if ((tlv_length + EFX_LICENSE_V1V2_HEADER_LENGTH) != length) {
554		goto fail4;
555	}
556
557	return (B_TRUE);
558
559fail4:
560	EFSYS_PROBE(fail4);
561fail3:
562	EFSYS_PROBE(fail3);
563fail2:
564	EFSYS_PROBE(fail2);
565fail1:
566	EFSYS_PROBE1(fail1, boolean_t, B_FALSE);
567
568	return (B_FALSE);
569}
570
571
572	__checkReturn		efx_rc_t
573efx_lic_v1v2_read_key(
574	__in			efx_nic_t *enp,
575	__in_bcount(buffer_size)
576				caddr_t bufferp,
577	__in			size_t buffer_size,
578	__in			uint32_t offset,
579	__in			uint32_t length,
580	__out_bcount_part(key_max_size, *lengthp)
581				caddr_t keyp,
582	__in			size_t key_max_size,
583	__out			uint32_t *lengthp
584	)
585{
586	efx_rc_t rc;
587
588	_NOTE(ARGUNUSED(enp, buffer_size))
589	EFSYS_ASSERT(length <= (EFX_LICENSE_V1V2_PAYLOAD_LENGTH_MAX +
590	    EFX_LICENSE_V1V2_HEADER_LENGTH));
591
592	if (key_max_size < length) {
593		rc = ENOSPC;
594		goto fail1;
595	}
596	memcpy(keyp, &bufferp[offset], length);
597
598	*lengthp = length;
599
600	return (0);
601
602fail1:
603	EFSYS_PROBE1(fail1, efx_rc_t, rc);
604
605	return (rc);
606}
607
608	__checkReturn		efx_rc_t
609efx_lic_v1v2_write_key(
610	__in			efx_nic_t *enp,
611	__in_bcount(buffer_size)
612				caddr_t bufferp,
613	__in			size_t buffer_size,
614	__in			uint32_t offset,
615	__in_bcount(length)	caddr_t keyp,
616	__in			uint32_t length,
617	__out			uint32_t *lengthp
618	)
619{
620	efx_rc_t rc;
621
622	_NOTE(ARGUNUSED(enp))
623	EFSYS_ASSERT(length <= (EFX_LICENSE_V1V2_PAYLOAD_LENGTH_MAX +
624	    EFX_LICENSE_V1V2_HEADER_LENGTH));
625
626	/* Ensure space for terminator remains */
627	if ((offset + length) >
628	    (buffer_size - EFX_LICENSE_V1V2_HEADER_LENGTH)) {
629		rc = ENOSPC;
630		goto fail1;
631	}
632
633	memcpy(bufferp + offset, keyp, length);
634
635	*lengthp = length;
636
637	return (0);
638
639fail1:
640	EFSYS_PROBE1(fail1, efx_rc_t, rc);
641
642	return (rc);
643}
644
645	__checkReturn		efx_rc_t
646efx_lic_v1v2_delete_key(
647	__in			efx_nic_t *enp,
648	__in_bcount(buffer_size)
649				caddr_t bufferp,
650	__in			size_t buffer_size,
651	__in			uint32_t offset,
652	__in			uint32_t length,
653	__in			uint32_t end,
654	__out			uint32_t *deltap
655	)
656{
657	uint32_t move_start = offset + length;
658	uint32_t move_length = end - move_start;
659
660	_NOTE(ARGUNUSED(enp, buffer_size))
661	EFSYS_ASSERT(end <= buffer_size);
662
663	/* Shift everything after the key down */
664	memmove(bufferp + offset, bufferp + move_start, move_length);
665
666	*deltap = length;
667
668	return (0);
669}
670
671	__checkReturn		efx_rc_t
672efx_lic_v1v2_create_partition(
673	__in			efx_nic_t *enp,
674	__in_bcount(buffer_size)
675				caddr_t bufferp,
676	__in			size_t buffer_size
677	)
678{
679	_NOTE(ARGUNUSED(enp, buffer_size))
680	EFSYS_ASSERT(EFX_LICENSE_V1V2_HEADER_LENGTH <= buffer_size);
681
682	/* Write terminator */
683	memset(bufferp, '\0', EFX_LICENSE_V1V2_HEADER_LENGTH);
684	return (0);
685}
686
687
688	__checkReturn		efx_rc_t
689efx_lic_v1v2_finish_partition(
690	__in			efx_nic_t *enp,
691	__in_bcount(buffer_size)
692				caddr_t bufferp,
693	__in			size_t buffer_size
694	)
695{
696	_NOTE(ARGUNUSED(enp, bufferp, buffer_size))
697
698	return (0);
699}
700
701#endif	/* EFSYS_OPT_HUNTINGTON | EFSYS_OPT_SIENA */
702
703
704/* V2 Licensing - used by Huntington family only. See SF-113611-TC */
705
706#if EFSYS_OPT_HUNTINGTON
707
708static	__checkReturn	efx_rc_t
709efx_mcdi_licensed_app_state(
710	__in		efx_nic_t *enp,
711	__in		uint64_t app_id,
712	__out		boolean_t *licensedp)
713{
714	efx_mcdi_req_t req;
715	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_LICENSED_APP_STATE_IN_LEN,
716		MC_CMD_GET_LICENSED_APP_STATE_OUT_LEN);
717	uint32_t app_state;
718	efx_rc_t rc;
719
720	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
721
722	/* V2 licensing supports 32bit app id only */
723	if ((app_id >> 32) != 0) {
724		rc = EINVAL;
725		goto fail1;
726	}
727
728	req.emr_cmd = MC_CMD_GET_LICENSED_APP_STATE;
729	req.emr_in_buf = payload;
730	req.emr_in_length = MC_CMD_GET_LICENSED_APP_STATE_IN_LEN;
731	req.emr_out_buf = payload;
732	req.emr_out_length = MC_CMD_GET_LICENSED_APP_STATE_OUT_LEN;
733
734	MCDI_IN_SET_DWORD(req, GET_LICENSED_APP_STATE_IN_APP_ID,
735		    app_id & 0xffffffff);
736
737	efx_mcdi_execute(enp, &req);
738
739	if (req.emr_rc != 0) {
740		rc = req.emr_rc;
741		goto fail2;
742	}
743
744	if (req.emr_out_length_used < MC_CMD_GET_LICENSED_APP_STATE_OUT_LEN) {
745		rc = EMSGSIZE;
746		goto fail3;
747	}
748
749	app_state = (MCDI_OUT_DWORD(req, GET_LICENSED_APP_STATE_OUT_STATE));
750	if (app_state != MC_CMD_GET_LICENSED_APP_STATE_OUT_NOT_LICENSED) {
751		*licensedp = B_TRUE;
752	} else {
753		*licensedp = B_FALSE;
754	}
755
756	return (0);
757
758fail3:
759	EFSYS_PROBE(fail3);
760fail2:
761	EFSYS_PROBE(fail2);
762fail1:
763	EFSYS_PROBE1(fail1, efx_rc_t, rc);
764
765	return (rc);
766}
767
768static	__checkReturn	efx_rc_t
769efx_mcdi_licensing_update_licenses(
770	__in		efx_nic_t *enp)
771{
772	efx_mcdi_req_t req;
773	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_LICENSING_IN_LEN, 0);
774	efx_rc_t rc;
775
776	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
777
778	req.emr_cmd = MC_CMD_LICENSING;
779	req.emr_in_buf = payload;
780	req.emr_in_length = MC_CMD_LICENSING_IN_LEN;
781	req.emr_out_buf = payload;
782	req.emr_out_length = 0;
783
784	MCDI_IN_SET_DWORD(req, LICENSING_IN_OP,
785	    MC_CMD_LICENSING_IN_OP_UPDATE_LICENSE);
786
787	efx_mcdi_execute(enp, &req);
788
789	if (req.emr_rc != 0) {
790		rc = req.emr_rc;
791		goto fail1;
792	}
793
794	if (req.emr_out_length_used != 0) {
795		rc = EIO;
796		goto fail2;
797	}
798
799	return (0);
800
801fail2:
802	EFSYS_PROBE(fail2);
803fail1:
804	EFSYS_PROBE1(fail1, efx_rc_t, rc);
805
806	return (rc);
807}
808
809static	__checkReturn	efx_rc_t
810efx_mcdi_licensing_get_key_stats(
811	__in		efx_nic_t *enp,
812	__out		efx_key_stats_t *eksp)
813{
814	efx_mcdi_req_t req;
815	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_LICENSING_IN_LEN,
816		MC_CMD_LICENSING_OUT_LEN);
817	efx_rc_t rc;
818
819	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
820
821	req.emr_cmd = MC_CMD_LICENSING;
822	req.emr_in_buf = payload;
823	req.emr_in_length = MC_CMD_LICENSING_IN_LEN;
824	req.emr_out_buf = payload;
825	req.emr_out_length = MC_CMD_LICENSING_OUT_LEN;
826
827	MCDI_IN_SET_DWORD(req, LICENSING_IN_OP,
828	    MC_CMD_LICENSING_IN_OP_GET_KEY_STATS);
829
830	efx_mcdi_execute(enp, &req);
831
832	if (req.emr_rc != 0) {
833		rc = req.emr_rc;
834		goto fail1;
835	}
836
837	if (req.emr_out_length_used < MC_CMD_LICENSING_OUT_LEN) {
838		rc = EMSGSIZE;
839		goto fail2;
840	}
841
842	eksp->eks_valid =
843		MCDI_OUT_DWORD(req, LICENSING_OUT_VALID_APP_KEYS);
844	eksp->eks_invalid =
845		MCDI_OUT_DWORD(req, LICENSING_OUT_INVALID_APP_KEYS);
846	eksp->eks_blacklisted =
847		MCDI_OUT_DWORD(req, LICENSING_OUT_BLACKLISTED_APP_KEYS);
848	eksp->eks_unverifiable =
849		MCDI_OUT_DWORD(req, LICENSING_OUT_UNVERIFIABLE_APP_KEYS);
850	eksp->eks_wrong_node =
851		MCDI_OUT_DWORD(req, LICENSING_OUT_WRONG_NODE_APP_KEYS);
852	eksp->eks_licensed_apps_lo = 0;
853	eksp->eks_licensed_apps_hi = 0;
854	eksp->eks_licensed_features_lo = 0;
855	eksp->eks_licensed_features_hi = 0;
856
857	return (0);
858
859fail2:
860	EFSYS_PROBE(fail2);
861fail1:
862	EFSYS_PROBE1(fail1, efx_rc_t, rc);
863
864	return (rc);
865}
866
867#endif	/* EFSYS_OPT_HUNTINGTON */
868
869/* V3 Licensing - used starting from Medford family. See SF-114884-SW */
870
871#if EFSYS_OPT_MEDFORD
872
873static	__checkReturn	efx_rc_t
874efx_mcdi_licensing_v3_update_licenses(
875	__in		efx_nic_t *enp)
876{
877	efx_mcdi_req_t req;
878	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_LICENSING_V3_IN_LEN, 0);
879	efx_rc_t rc;
880
881	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_MEDFORD);
882
883	req.emr_cmd = MC_CMD_LICENSING_V3;
884	req.emr_in_buf = payload;
885	req.emr_in_length = MC_CMD_LICENSING_V3_IN_LEN;
886	req.emr_out_buf = NULL;
887	req.emr_out_length = 0;
888
889	MCDI_IN_SET_DWORD(req, LICENSING_V3_IN_OP,
890	    MC_CMD_LICENSING_V3_IN_OP_UPDATE_LICENSE);
891
892	efx_mcdi_execute(enp, &req);
893
894	if (req.emr_rc != 0) {
895		rc = req.emr_rc;
896		goto fail1;
897	}
898
899	return (0);
900
901fail1:
902	EFSYS_PROBE1(fail1, efx_rc_t, rc);
903
904	return (rc);
905}
906
907static	__checkReturn	efx_rc_t
908efx_mcdi_licensing_v3_report_license(
909	__in		efx_nic_t *enp,
910	__out		efx_key_stats_t *eksp)
911{
912	efx_mcdi_req_t req;
913	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_LICENSING_V3_IN_LEN,
914		MC_CMD_LICENSING_V3_OUT_LEN);
915	efx_rc_t rc;
916
917	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_MEDFORD);
918
919	req.emr_cmd = MC_CMD_LICENSING_V3;
920	req.emr_in_buf = payload;
921	req.emr_in_length = MC_CMD_LICENSING_V3_IN_LEN;
922	req.emr_out_buf = payload;
923	req.emr_out_length = MC_CMD_LICENSING_V3_OUT_LEN;
924
925	MCDI_IN_SET_DWORD(req, LICENSING_V3_IN_OP,
926	    MC_CMD_LICENSING_V3_IN_OP_REPORT_LICENSE);
927
928	efx_mcdi_execute_quiet(enp, &req);
929
930	if (req.emr_rc != 0) {
931		rc = req.emr_rc;
932		goto fail1;
933	}
934
935	if (req.emr_out_length_used < MC_CMD_LICENSING_V3_OUT_LEN) {
936		rc = EMSGSIZE;
937		goto fail2;
938	}
939
940	eksp->eks_valid =
941		MCDI_OUT_DWORD(req, LICENSING_V3_OUT_VALID_KEYS);
942	eksp->eks_invalid =
943		MCDI_OUT_DWORD(req, LICENSING_V3_OUT_INVALID_KEYS);
944	eksp->eks_blacklisted = 0;
945	eksp->eks_unverifiable =
946		MCDI_OUT_DWORD(req, LICENSING_V3_OUT_UNVERIFIABLE_KEYS);
947	eksp->eks_wrong_node =
948		MCDI_OUT_DWORD(req, LICENSING_V3_OUT_WRONG_NODE_KEYS);
949	eksp->eks_licensed_apps_lo =
950		MCDI_OUT_DWORD(req, LICENSING_V3_OUT_LICENSED_APPS_LO);
951	eksp->eks_licensed_apps_hi =
952		MCDI_OUT_DWORD(req, LICENSING_V3_OUT_LICENSED_APPS_HI);
953	eksp->eks_licensed_features_lo =
954		MCDI_OUT_DWORD(req, LICENSING_V3_OUT_LICENSED_FEATURES_LO);
955	eksp->eks_licensed_features_hi =
956		MCDI_OUT_DWORD(req, LICENSING_V3_OUT_LICENSED_FEATURES_HI);
957
958	return (0);
959
960fail2:
961	EFSYS_PROBE(fail2);
962fail1:
963	EFSYS_PROBE1(fail1, efx_rc_t, rc);
964
965	return (rc);
966}
967
968static	__checkReturn	efx_rc_t
969efx_mcdi_licensing_v3_app_state(
970	__in		efx_nic_t *enp,
971	__in		uint64_t app_id,
972	__out		boolean_t *licensedp)
973{
974	efx_mcdi_req_t req;
975	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_LICENSED_V3_APP_STATE_IN_LEN,
976		MC_CMD_GET_LICENSED_V3_APP_STATE_OUT_LEN);
977	uint32_t app_state;
978	efx_rc_t rc;
979
980	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_MEDFORD);
981
982	req.emr_cmd = MC_CMD_GET_LICENSED_V3_APP_STATE;
983	req.emr_in_buf = payload;
984	req.emr_in_length = MC_CMD_GET_LICENSED_V3_APP_STATE_IN_LEN;
985	req.emr_out_buf = payload;
986	req.emr_out_length = MC_CMD_GET_LICENSED_V3_APP_STATE_OUT_LEN;
987
988	MCDI_IN_SET_DWORD(req, GET_LICENSED_V3_APP_STATE_IN_APP_ID_LO,
989		    app_id & 0xffffffff);
990	MCDI_IN_SET_DWORD(req, GET_LICENSED_V3_APP_STATE_IN_APP_ID_HI,
991		    app_id >> 32);
992
993	efx_mcdi_execute(enp, &req);
994
995	if (req.emr_rc != 0) {
996		rc = req.emr_rc;
997		goto fail1;
998	}
999
1000	if (req.emr_out_length_used < MC_CMD_GET_LICENSED_V3_APP_STATE_OUT_LEN) {
1001		rc = EMSGSIZE;
1002		goto fail2;
1003	}
1004
1005	app_state = (MCDI_OUT_DWORD(req, GET_LICENSED_V3_APP_STATE_OUT_STATE));
1006	if (app_state != MC_CMD_GET_LICENSED_V3_APP_STATE_OUT_NOT_LICENSED) {
1007		*licensedp = B_TRUE;
1008	} else {
1009		*licensedp = B_FALSE;
1010	}
1011
1012	return (0);
1013
1014fail2:
1015	EFSYS_PROBE(fail2);
1016fail1:
1017	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1018
1019	return (rc);
1020}
1021
1022static	__checkReturn	efx_rc_t
1023efx_mcdi_licensing_v3_get_id(
1024	__in		efx_nic_t *enp,
1025	__in		size_t buffer_size,
1026	__out		uint32_t *typep,
1027	__out		size_t *lengthp,
1028	__out_bcount_part_opt(buffer_size, *lengthp)
1029			uint8_t *bufferp)
1030{
1031	efx_mcdi_req_t req;
1032	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_LICENSING_GET_ID_V3_IN_LEN,
1033		MC_CMD_LICENSING_GET_ID_V3_OUT_LENMIN);
1034	efx_rc_t rc;
1035
1036	req.emr_cmd = MC_CMD_LICENSING_GET_ID_V3;
1037
1038	if (bufferp == NULL) {
1039		/* Request id type and length only */
1040		req.emr_in_buf = bufferp;
1041		req.emr_in_length = MC_CMD_LICENSING_GET_ID_V3_IN_LEN;
1042		req.emr_out_buf = bufferp;
1043		req.emr_out_length = MC_CMD_LICENSING_GET_ID_V3_OUT_LENMIN;
1044	} else {
1045		/* Request full buffer */
1046		req.emr_in_buf = bufferp;
1047		req.emr_in_length = MC_CMD_LICENSING_GET_ID_V3_IN_LEN;
1048		req.emr_out_buf = bufferp;
1049		req.emr_out_length = MIN(buffer_size, MC_CMD_LICENSING_GET_ID_V3_OUT_LENMAX);
1050		(void) memset(bufferp, 0, req.emr_out_length);
1051	}
1052
1053	efx_mcdi_execute_quiet(enp, &req);
1054
1055	if (req.emr_rc != 0) {
1056		rc = req.emr_rc;
1057		goto fail1;
1058	}
1059
1060	if (req.emr_out_length_used < MC_CMD_LICENSING_GET_ID_V3_OUT_LENMIN) {
1061		rc = EMSGSIZE;
1062		goto fail2;
1063	}
1064
1065	*typep = MCDI_OUT_DWORD(req, LICENSING_GET_ID_V3_OUT_LICENSE_TYPE);
1066	*lengthp = MCDI_OUT_DWORD(req, LICENSING_GET_ID_V3_OUT_LICENSE_ID_LENGTH);
1067
1068	if (bufferp == NULL) {
1069		/* modify length requirements to indicate to caller the extra buffering
1070		** needed to read the complete output.
1071		*/
1072		*lengthp += MC_CMD_LICENSING_GET_ID_V3_OUT_LENMIN;
1073	} else {
1074		/* Shift ID down to start of buffer */
1075		memmove(bufferp,
1076		    bufferp + MC_CMD_LICENSING_GET_ID_V3_OUT_LICENSE_ID_OFST,
1077		    *lengthp);
1078		memset(bufferp + (*lengthp), 0,
1079		    MC_CMD_LICENSING_GET_ID_V3_OUT_LICENSE_ID_OFST);
1080	}
1081
1082	return (0);
1083
1084fail2:
1085	EFSYS_PROBE(fail2);
1086fail1:
1087	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1088
1089	return (rc);
1090}
1091
1092/* V3 format uses Huntington TLV format partition. See SF-108797-SW */
1093#define EFX_LICENSE_V3_KEY_LENGTH_MIN    (64)
1094#define EFX_LICENSE_V3_KEY_LENGTH_MAX    (160)
1095
1096	__checkReturn		efx_rc_t
1097efx_lic_v3_find_start(
1098	__in			efx_nic_t *enp,
1099	__in_bcount(buffer_size)
1100				caddr_t bufferp,
1101	__in			size_t buffer_size,
1102	__out			uint32_t *startp
1103	)
1104{
1105	_NOTE(ARGUNUSED(enp))
1106
1107	return ef10_nvram_buffer_find_item_start(bufferp, buffer_size, startp);
1108}
1109
1110	__checkReturn		efx_rc_t
1111efx_lic_v3_find_end(
1112	__in			efx_nic_t *enp,
1113	__in_bcount(buffer_size)
1114				caddr_t bufferp,
1115	__in			size_t buffer_size,
1116	__in			uint32_t offset,
1117	__out			uint32_t *endp
1118	)
1119{
1120	_NOTE(ARGUNUSED(enp))
1121
1122	return ef10_nvram_buffer_find_end(bufferp, buffer_size, offset, endp);
1123}
1124
1125	__checkReturn	__success(return != B_FALSE)	boolean_t
1126efx_lic_v3_find_key(
1127	__in			efx_nic_t *enp,
1128	__in_bcount(buffer_size)
1129				caddr_t bufferp,
1130	__in			size_t buffer_size,
1131	__in			uint32_t offset,
1132	__out			uint32_t *startp,
1133	__out			uint32_t *lengthp
1134	)
1135{
1136	_NOTE(ARGUNUSED(enp))
1137
1138	return ef10_nvram_buffer_find_item(bufferp, buffer_size,
1139	    offset, startp, lengthp);
1140}
1141
1142	__checkReturn	__success(return != B_FALSE)	boolean_t
1143efx_lic_v3_validate_key(
1144	__in			efx_nic_t *enp,
1145	__in_bcount(length)	caddr_t keyp,
1146	__in			uint32_t length
1147	)
1148{
1149	/* Check key is a valid V3 key */
1150	uint8_t key_type;
1151	uint8_t key_length;
1152
1153	_NOTE(ARGUNUSED(enp))
1154
1155	if (length < EFX_LICENSE_V3_KEY_LENGTH_MIN) {
1156		goto fail1;
1157	}
1158
1159	if (length > EFX_LICENSE_V3_KEY_LENGTH_MAX) {
1160		goto fail2;
1161	}
1162
1163	key_type = ((uint8_t *)keyp)[0];
1164	key_length = ((uint8_t *)keyp)[1];
1165
1166	if (key_type < 3) {
1167		goto fail3;
1168	}
1169	if (key_length > length) {
1170		goto fail4;
1171	}
1172	return (B_TRUE);
1173
1174fail4:
1175	EFSYS_PROBE(fail4);
1176fail3:
1177	EFSYS_PROBE(fail3);
1178fail2:
1179	EFSYS_PROBE(fail2);
1180fail1:
1181	EFSYS_PROBE1(fail1, boolean_t, B_FALSE);
1182
1183	return (B_FALSE);
1184}
1185
1186	__checkReturn		efx_rc_t
1187efx_lic_v3_read_key(
1188	__in			efx_nic_t *enp,
1189	__in_bcount(buffer_size)
1190				caddr_t bufferp,
1191	__in			size_t buffer_size,
1192	__in			uint32_t offset,
1193	__in			uint32_t length,
1194	__out_bcount_part(key_max_size, *lengthp)
1195				caddr_t keyp,
1196	__in			size_t key_max_size,
1197	__out			uint32_t *lengthp
1198	)
1199{
1200	_NOTE(ARGUNUSED(enp))
1201
1202	return ef10_nvram_buffer_get_item(bufferp, buffer_size,
1203		    offset, length, keyp, key_max_size, lengthp);
1204}
1205
1206	__checkReturn		efx_rc_t
1207efx_lic_v3_write_key(
1208	__in			efx_nic_t *enp,
1209	__in_bcount(buffer_size)
1210				caddr_t bufferp,
1211	__in			size_t buffer_size,
1212	__in			uint32_t offset,
1213	__in_bcount(length)	caddr_t keyp,
1214	__in			uint32_t length,
1215	__out			uint32_t *lengthp
1216	)
1217{
1218	_NOTE(ARGUNUSED(enp))
1219	EFSYS_ASSERT(length <= EFX_LICENSE_V3_KEY_LENGTH_MAX);
1220
1221	return ef10_nvram_buffer_insert_item(bufferp, buffer_size,
1222		    offset, keyp, length, lengthp);
1223}
1224
1225	__checkReturn		efx_rc_t
1226efx_lic_v3_delete_key(
1227	__in			efx_nic_t *enp,
1228	__in_bcount(buffer_size)
1229				caddr_t bufferp,
1230	__in			size_t buffer_size,
1231	__in			uint32_t offset,
1232	__in			uint32_t length,
1233	__in			uint32_t end,
1234	__out			uint32_t *deltap
1235	)
1236{
1237	efx_rc_t rc;
1238
1239	_NOTE(ARGUNUSED(enp))
1240
1241	if ((rc = ef10_nvram_buffer_delete_item(bufferp,
1242			buffer_size, offset, length, end)) != 0) {
1243		goto fail1;
1244	}
1245
1246	*deltap = length;
1247
1248	return (0);
1249
1250fail1:
1251	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1252
1253	return (rc);
1254}
1255
1256	__checkReturn		efx_rc_t
1257efx_lic_v3_create_partition(
1258	__in			efx_nic_t *enp,
1259	__in_bcount(buffer_size)
1260				caddr_t bufferp,
1261	__in			size_t buffer_size
1262	)
1263{
1264	efx_rc_t rc;
1265
1266	/* Construct empty partition */
1267	if ((rc = ef10_nvram_buffer_create(enp,
1268	    NVRAM_PARTITION_TYPE_LICENSE,
1269	    bufferp, buffer_size)) != 0) {
1270		rc = EFAULT;
1271		goto fail1;
1272	}
1273
1274	return (0);
1275
1276fail1:
1277	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1278
1279	return (rc);
1280}
1281
1282	__checkReturn		efx_rc_t
1283efx_lic_v3_finish_partition(
1284	__in			efx_nic_t *enp,
1285	__in_bcount(buffer_size)
1286				caddr_t bufferp,
1287	__in			size_t buffer_size
1288	)
1289{
1290	efx_rc_t rc;
1291
1292	if ((rc = ef10_nvram_buffer_finish(bufferp,
1293			buffer_size)) != 0) {
1294		goto fail1;
1295	}
1296
1297	/* Validate completed partition */
1298	if ((rc = ef10_nvram_buffer_validate(enp, NVRAM_PARTITION_TYPE_LICENSE,
1299					bufferp, buffer_size)) != 0) {
1300		goto fail2;
1301	}
1302
1303	return (0);
1304
1305fail2:
1306	EFSYS_PROBE(fail2);
1307fail1:
1308	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1309
1310	return (rc);
1311}
1312
1313
1314#endif	/* EFSYS_OPT_MEDFORD */
1315
1316	__checkReturn		efx_rc_t
1317efx_lic_init(
1318	__in			efx_nic_t *enp)
1319{
1320	const efx_lic_ops_t *elop;
1321	efx_key_stats_t eks;
1322	efx_rc_t rc;
1323
1324	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1325	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
1326	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_LIC));
1327
1328	switch (enp->en_family) {
1329
1330#if EFSYS_OPT_SIENA
1331	case EFX_FAMILY_SIENA:
1332		elop = &__efx_lic_v1_ops;
1333		break;
1334#endif	/* EFSYS_OPT_SIENA */
1335
1336#if EFSYS_OPT_HUNTINGTON
1337	case EFX_FAMILY_HUNTINGTON:
1338		elop = &__efx_lic_v2_ops;
1339		break;
1340#endif	/* EFSYS_OPT_HUNTINGTON */
1341
1342#if EFSYS_OPT_MEDFORD
1343	case EFX_FAMILY_MEDFORD:
1344		elop = &__efx_lic_v3_ops;
1345		break;
1346#endif	/* EFSYS_OPT_MEDFORD */
1347
1348	default:
1349		EFSYS_ASSERT(0);
1350		rc = ENOTSUP;
1351		goto fail1;
1352	}
1353
1354	enp->en_elop = elop;
1355	enp->en_mod_flags |= EFX_MOD_LIC;
1356
1357	/* Probe for support */
1358	if (efx_lic_get_key_stats(enp, &eks) == 0) {
1359		enp->en_licensing_supported = B_TRUE;
1360	} else {
1361		enp->en_licensing_supported = B_FALSE;
1362	}
1363
1364	return (0);
1365
1366fail1:
1367	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1368
1369	return (rc);
1370}
1371
1372extern	__checkReturn	boolean_t
1373efx_lic_check_support(
1374	__in			efx_nic_t *enp)
1375{
1376	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1377	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
1378	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_LIC);
1379
1380	return enp->en_licensing_supported;
1381}
1382
1383				void
1384efx_lic_fini(
1385	__in			efx_nic_t *enp)
1386{
1387	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1388	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
1389	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_LIC);
1390
1391	enp->en_elop = NULL;
1392	enp->en_mod_flags &= ~EFX_MOD_LIC;
1393}
1394
1395
1396	__checkReturn	efx_rc_t
1397efx_lic_update_licenses(
1398	__in		efx_nic_t *enp)
1399{
1400	const efx_lic_ops_t *elop = enp->en_elop;
1401	efx_rc_t rc;
1402
1403	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1404	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_LIC);
1405
1406	if ((rc = elop->elo_update_licenses(enp)) != 0)
1407		goto fail1;
1408
1409	return (0);
1410
1411fail1:
1412	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1413
1414	return (rc);
1415}
1416
1417	__checkReturn	efx_rc_t
1418efx_lic_get_key_stats(
1419	__in		efx_nic_t *enp,
1420	__out		efx_key_stats_t *eksp)
1421{
1422	const efx_lic_ops_t *elop = enp->en_elop;
1423	efx_rc_t rc;
1424
1425	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1426	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_LIC);
1427
1428	if ((rc = elop->elo_get_key_stats(enp, eksp)) != 0)
1429		goto fail1;
1430
1431	return (0);
1432
1433fail1:
1434	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1435
1436	return (rc);
1437}
1438
1439	__checkReturn	efx_rc_t
1440efx_lic_app_state(
1441	__in		efx_nic_t *enp,
1442	__in		uint64_t app_id,
1443	__out		boolean_t *licensedp)
1444{
1445	const efx_lic_ops_t *elop = enp->en_elop;
1446	efx_rc_t rc;
1447
1448	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1449	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_LIC);
1450
1451	if (elop->elo_app_state == NULL)
1452		return (ENOTSUP);
1453
1454	if ((rc = elop->elo_app_state(enp, app_id, licensedp)) != 0)
1455		goto fail1;
1456
1457	return (0);
1458
1459fail1:
1460	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1461
1462	return (rc);
1463}
1464
1465	__checkReturn	efx_rc_t
1466efx_lic_get_id(
1467	__in		efx_nic_t *enp,
1468	__in		size_t buffer_size,
1469	__out		uint32_t *typep,
1470	__out		size_t *lengthp,
1471	__out_opt	uint8_t *bufferp
1472	)
1473{
1474	const efx_lic_ops_t *elop = enp->en_elop;
1475	efx_rc_t rc;
1476
1477	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1478	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_LIC);
1479
1480	if (elop->elo_get_id == NULL)
1481		return (ENOTSUP);
1482
1483	if ((rc = elop->elo_get_id(enp, buffer_size, typep,
1484				    lengthp, bufferp)) != 0)
1485		goto fail1;
1486
1487	return (0);
1488
1489fail1:
1490	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1491
1492	return (rc);
1493}
1494
1495/* Buffer management API - abstracts varying TLV format used for License partition */
1496
1497	__checkReturn		efx_rc_t
1498efx_lic_find_start(
1499	__in			efx_nic_t *enp,
1500	__in_bcount(buffer_size)
1501				caddr_t bufferp,
1502	__in			size_t buffer_size,
1503	__out			uint32_t *startp
1504	)
1505{
1506	const efx_lic_ops_t *elop = enp->en_elop;
1507	efx_rc_t rc;
1508
1509	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1510	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_LIC);
1511
1512	if ((rc = elop->elo_find_start(enp, bufferp, buffer_size, startp)) != 0)
1513		goto fail1;
1514
1515	return (0);
1516
1517fail1:
1518	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1519
1520	return (rc);
1521}
1522
1523	__checkReturn		efx_rc_t
1524efx_lic_find_end(
1525	__in			efx_nic_t *enp,
1526	__in_bcount(buffer_size)
1527				caddr_t bufferp,
1528	__in			size_t buffer_size,
1529	__in			uint32_t offset,
1530	__out			uint32_t *endp
1531	)
1532{
1533	const efx_lic_ops_t *elop = enp->en_elop;
1534	efx_rc_t rc;
1535
1536	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1537	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_LIC);
1538
1539	if ((rc = elop->elo_find_end(enp, bufferp, buffer_size, offset, endp)) != 0)
1540		goto fail1;
1541
1542	return (0);
1543
1544fail1:
1545	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1546
1547	return (rc);
1548}
1549
1550	__checkReturn	__success(return != B_FALSE)	boolean_t
1551efx_lic_find_key(
1552	__in			efx_nic_t *enp,
1553	__in_bcount(buffer_size)
1554				caddr_t bufferp,
1555	__in			size_t buffer_size,
1556	__in			uint32_t offset,
1557	__out			uint32_t *startp,
1558	__out			uint32_t *lengthp
1559	)
1560{
1561	const efx_lic_ops_t *elop = enp->en_elop;
1562
1563	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1564	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_LIC);
1565
1566	EFSYS_ASSERT(bufferp);
1567	EFSYS_ASSERT(startp);
1568	EFSYS_ASSERT(lengthp);
1569
1570	return (elop->elo_find_key(enp, bufferp, buffer_size, offset,
1571				    startp, lengthp));
1572}
1573
1574
1575/* Validate that the buffer contains a single key in a recognised format.
1576** An empty or terminator buffer is not accepted as a valid key.
1577*/
1578	__checkReturn	__success(return != B_FALSE)	boolean_t
1579efx_lic_validate_key(
1580	__in			efx_nic_t *enp,
1581	__in_bcount(length)	caddr_t keyp,
1582	__in			uint32_t length
1583	)
1584{
1585	const efx_lic_ops_t *elop = enp->en_elop;
1586	boolean_t rc;
1587
1588	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1589	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_LIC);
1590
1591	if ((rc = elop->elo_validate_key(enp, keyp, length)) == B_FALSE)
1592		goto fail1;
1593
1594	return (B_TRUE);
1595
1596fail1:
1597	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1598
1599	return (rc);
1600}
1601
1602	__checkReturn		efx_rc_t
1603efx_lic_read_key(
1604	__in			efx_nic_t *enp,
1605	__in_bcount(buffer_size)
1606				caddr_t bufferp,
1607	__in			size_t buffer_size,
1608	__in			uint32_t offset,
1609	__in			uint32_t length,
1610	__out_bcount_part(key_max_size, *lengthp)
1611				caddr_t keyp,
1612	__in			size_t key_max_size,
1613	__out			uint32_t *lengthp
1614	)
1615{
1616	const efx_lic_ops_t *elop = enp->en_elop;
1617	efx_rc_t rc;
1618
1619	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1620	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_LIC);
1621
1622	if ((rc = elop->elo_read_key(enp, bufferp, buffer_size, offset,
1623				    length, keyp, key_max_size, lengthp)) != 0)
1624		goto fail1;
1625
1626	return (0);
1627
1628fail1:
1629	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1630
1631	return (rc);
1632}
1633
1634	__checkReturn		efx_rc_t
1635efx_lic_write_key(
1636	__in			efx_nic_t *enp,
1637	__in_bcount(buffer_size)
1638				caddr_t bufferp,
1639	__in			size_t buffer_size,
1640	__in			uint32_t offset,
1641	__in_bcount(length)	caddr_t keyp,
1642	__in			uint32_t length,
1643	__out			uint32_t *lengthp
1644	)
1645{
1646	const efx_lic_ops_t *elop = enp->en_elop;
1647	efx_rc_t rc;
1648
1649	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1650	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_LIC);
1651
1652	if ((rc = elop->elo_write_key(enp, bufferp, buffer_size, offset,
1653				    keyp, length, lengthp)) != 0)
1654		goto fail1;
1655
1656	return (0);
1657
1658fail1:
1659	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1660
1661	return (rc);
1662}
1663
1664	__checkReturn		efx_rc_t
1665efx_lic_delete_key(
1666	__in			efx_nic_t *enp,
1667	__in_bcount(buffer_size)
1668				caddr_t bufferp,
1669	__in			size_t buffer_size,
1670	__in			uint32_t offset,
1671	__in			uint32_t length,
1672	__in			uint32_t end,
1673	__out			uint32_t *deltap
1674	)
1675{
1676	const efx_lic_ops_t *elop = enp->en_elop;
1677	efx_rc_t rc;
1678
1679	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1680	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_LIC);
1681
1682	if ((rc = elop->elo_delete_key(enp, bufferp, buffer_size, offset,
1683				    length, end, deltap)) != 0)
1684		goto fail1;
1685
1686	return (0);
1687
1688fail1:
1689	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1690
1691	return (rc);
1692}
1693
1694	__checkReturn		efx_rc_t
1695efx_lic_create_partition(
1696	__in			efx_nic_t *enp,
1697	__in_bcount(buffer_size)
1698				caddr_t bufferp,
1699	__in			size_t buffer_size
1700	)
1701{
1702	const efx_lic_ops_t *elop = enp->en_elop;
1703	efx_rc_t rc;
1704
1705	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1706	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_LIC);
1707
1708	if ((rc = elop->elo_create_partition(enp, bufferp, buffer_size)) != 0)
1709		goto fail1;
1710
1711	return (0);
1712
1713fail1:
1714	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1715
1716	return (rc);
1717}
1718
1719
1720	__checkReturn		efx_rc_t
1721efx_lic_finish_partition(
1722	__in			efx_nic_t *enp,
1723	__in_bcount(buffer_size)
1724				caddr_t bufferp,
1725	__in			size_t buffer_size
1726	)
1727{
1728	const efx_lic_ops_t *elop = enp->en_elop;
1729	efx_rc_t rc;
1730
1731	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1732	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_LIC);
1733
1734	if ((rc = elop->elo_finish_partition(enp, bufferp, buffer_size)) != 0)
1735		goto fail1;
1736
1737	return (0);
1738
1739fail1:
1740	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1741
1742	return (rc);
1743}
1744
1745#endif	/* EFSYS_OPT_LICENSING */
1746