efx_lic.c revision 299923
1293901Sarybchik/*-
2293901Sarybchik * Copyright (c) 2009-2015 Solarflare Communications Inc.
3293901Sarybchik * All rights reserved.
4293901Sarybchik *
5293901Sarybchik * Redistribution and use in source and binary forms, with or without
6293901Sarybchik * modification, are permitted provided that the following conditions are met:
7293901Sarybchik *
8293901Sarybchik * 1. Redistributions of source code must retain the above copyright notice,
9293901Sarybchik *    this list of conditions and the following disclaimer.
10293901Sarybchik * 2. Redistributions in binary form must reproduce the above copyright notice,
11293901Sarybchik *    this list of conditions and the following disclaimer in the documentation
12293901Sarybchik *    and/or other materials provided with the distribution.
13293901Sarybchik *
14293901Sarybchik * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15293901Sarybchik * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16293901Sarybchik * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17293901Sarybchik * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18293901Sarybchik * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19293901Sarybchik * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20293901Sarybchik * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21293901Sarybchik * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22293901Sarybchik * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23293901Sarybchik * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24293901Sarybchik * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25293901Sarybchik *
26293901Sarybchik * The views and conclusions contained in the software and documentation are
27293901Sarybchik * those of the authors and should not be interpreted as representing official
28293901Sarybchik * policies, either expressed or implied, of the FreeBSD Project.
29293901Sarybchik */
30293901Sarybchik
31293901Sarybchik#include <sys/cdefs.h>
32293901Sarybchik__FBSDID("$FreeBSD: head/sys/dev/sfxge/common/efx_lic.c 299923 2016-05-16 08:27:20Z arybchik $");
33293901Sarybchik
34293901Sarybchik#include "efx.h"
35293901Sarybchik#include "efx_impl.h"
36293901Sarybchik
37293901Sarybchik#if EFSYS_OPT_LICENSING
38293901Sarybchik
39299898Sarybchik#include "ef10_tlv_layout.h"
40299898Sarybchik
41299898Sarybchik#if EFSYS_OPT_SIENA | EFSYS_OPT_HUNTINGTON
42299898Sarybchik
43299898Sarybchik	__checkReturn		efx_rc_t
44299898Sarybchikefx_lic_v1v2_find_start(
45299898Sarybchik	__in			efx_nic_t *enp,
46299898Sarybchik	__in_bcount(buffer_size)
47299898Sarybchik				caddr_t bufferp,
48299898Sarybchik	__in			size_t buffer_size,
49299898Sarybchik	__out			uint32_t *startp
50299898Sarybchik	);
51299898Sarybchik
52299898Sarybchik	__checkReturn		efx_rc_t
53299898Sarybchikefx_lic_v1v2_find_end(
54299898Sarybchik	__in			efx_nic_t *enp,
55299898Sarybchik	__in_bcount(buffer_size)
56299898Sarybchik				caddr_t bufferp,
57299898Sarybchik	__in			size_t buffer_size,
58299898Sarybchik	__in			uint32_t offset,
59299898Sarybchik	__out			uint32_t *endp
60299898Sarybchik	);
61299898Sarybchik
62299898Sarybchik	__checkReturn	__success(return != B_FALSE)	boolean_t
63299898Sarybchikefx_lic_v1v2_find_key(
64299898Sarybchik	__in			efx_nic_t *enp,
65299898Sarybchik	__in_bcount(buffer_size)
66299898Sarybchik				caddr_t bufferp,
67299898Sarybchik	__in			size_t buffer_size,
68299898Sarybchik	__in			uint32_t offset,
69299898Sarybchik	__out			uint32_t *startp,
70299898Sarybchik	__out			uint32_t *lengthp
71299898Sarybchik	);
72299898Sarybchik
73299898Sarybchik	__checkReturn	__success(return != B_FALSE)	boolean_t
74299898Sarybchikefx_lic_v1v2_validate_key(
75299898Sarybchik	__in			efx_nic_t *enp,
76299898Sarybchik	__in_bcount(length)	caddr_t keyp,
77299898Sarybchik	__in			uint32_t length
78299898Sarybchik	);
79299898Sarybchik
80299898Sarybchik	__checkReturn		efx_rc_t
81299898Sarybchikefx_lic_v1v2_read_key(
82299898Sarybchik	__in			efx_nic_t *enp,
83299898Sarybchik	__in_bcount(buffer_size)
84299898Sarybchik				caddr_t bufferp,
85299898Sarybchik	__in			size_t buffer_size,
86299898Sarybchik	__in			uint32_t offset,
87299898Sarybchik	__in			uint32_t length,
88299898Sarybchik	__out_bcount_part(key_max_size, *lengthp)
89299898Sarybchik				caddr_t keyp,
90299898Sarybchik	__in			size_t key_max_size,
91299898Sarybchik	__out			uint32_t *lengthp
92299898Sarybchik	);
93299898Sarybchik
94299898Sarybchik	__checkReturn		efx_rc_t
95299898Sarybchikefx_lic_v1v2_write_key(
96299898Sarybchik	__in			efx_nic_t *enp,
97299898Sarybchik	__in_bcount(buffer_size)
98299898Sarybchik				caddr_t bufferp,
99299898Sarybchik	__in			size_t buffer_size,
100299898Sarybchik	__in			uint32_t offset,
101299898Sarybchik	__in_bcount(length)	caddr_t keyp,
102299898Sarybchik	__in			uint32_t length,
103299898Sarybchik	__out			uint32_t *lengthp
104299898Sarybchik	);
105299898Sarybchik
106299898Sarybchik	__checkReturn		efx_rc_t
107299898Sarybchikefx_lic_v1v2_delete_key(
108299898Sarybchik	__in			efx_nic_t *enp,
109299898Sarybchik	__in_bcount(buffer_size)
110299898Sarybchik				caddr_t bufferp,
111299898Sarybchik	__in			size_t buffer_size,
112299898Sarybchik	__in			uint32_t offset,
113299898Sarybchik	__in			uint32_t length,
114299898Sarybchik	__in			uint32_t end,
115299898Sarybchik	__out			uint32_t *deltap
116299898Sarybchik	);
117299898Sarybchik
118299898Sarybchik	__checkReturn		efx_rc_t
119299898Sarybchikefx_lic_v1v2_create_partition(
120299898Sarybchik	__in			efx_nic_t *enp,
121299898Sarybchik	__in_bcount(buffer_size)
122299898Sarybchik				caddr_t bufferp,
123299898Sarybchik	__in			size_t buffer_size
124299898Sarybchik	);
125299898Sarybchik
126299898Sarybchik	__checkReturn		efx_rc_t
127299898Sarybchikefx_lic_v1v2_finish_partition(
128299898Sarybchik	__in			efx_nic_t *enp,
129299898Sarybchik	__in_bcount(buffer_size)
130299898Sarybchik				caddr_t bufferp,
131299898Sarybchik	__in			size_t buffer_size
132299898Sarybchik	);
133299898Sarybchik
134299898Sarybchik#endif	/* EFSYS_OPT_HUNTINGTON | EFSYS_OPT_SIENA */
135299898Sarybchik
136299898Sarybchik
137293901Sarybchik#if EFSYS_OPT_SIENA
138293901Sarybchik
139293901Sarybchikstatic	__checkReturn	efx_rc_t
140293901Sarybchikefx_mcdi_fc_license_update_license(
141293901Sarybchik	__in		efx_nic_t *enp);
142293901Sarybchik
143293901Sarybchikstatic	__checkReturn	efx_rc_t
144293901Sarybchikefx_mcdi_fc_license_get_key_stats(
145293901Sarybchik	__in		efx_nic_t *enp,
146293901Sarybchik	__out		efx_key_stats_t *eksp);
147293901Sarybchik
148299517Sarybchikstatic const efx_lic_ops_t	__efx_lic_v1_ops = {
149293901Sarybchik	efx_mcdi_fc_license_update_license,	/* elo_update_licenses */
150293901Sarybchik	efx_mcdi_fc_license_get_key_stats,	/* elo_get_key_stats */
151293901Sarybchik	NULL,					/* elo_app_state */
152293901Sarybchik	NULL,					/* elo_get_id */
153299898Sarybchik	efx_lic_v1v2_find_start,		/* elo_find_start */
154299898Sarybchik	efx_lic_v1v2_find_end,			/* elo_find_end */
155299898Sarybchik	efx_lic_v1v2_find_key,			/* elo_find_key */
156299898Sarybchik	efx_lic_v1v2_validate_key,		/* elo_validate_key */
157299898Sarybchik	efx_lic_v1v2_read_key,			/* elo_read_key */
158299898Sarybchik	efx_lic_v1v2_write_key,			/* elo_write_key */
159299898Sarybchik	efx_lic_v1v2_delete_key,		/* elo_delete_key */
160299898Sarybchik	efx_lic_v1v2_create_partition,		/* elo_create_partition */
161299898Sarybchik	efx_lic_v1v2_finish_partition,		/* elo_finish_partition */
162293901Sarybchik};
163293901Sarybchik
164293901Sarybchik#endif	/* EFSYS_OPT_SIENA */
165293901Sarybchik
166293901Sarybchik#if EFSYS_OPT_HUNTINGTON
167293901Sarybchik
168293901Sarybchikstatic	__checkReturn	efx_rc_t
169293901Sarybchikefx_mcdi_licensing_update_licenses(
170293901Sarybchik	__in		efx_nic_t *enp);
171293901Sarybchik
172293901Sarybchikstatic	__checkReturn	efx_rc_t
173293901Sarybchikefx_mcdi_licensing_get_key_stats(
174293901Sarybchik	__in		efx_nic_t *enp,
175293901Sarybchik	__out		efx_key_stats_t *eksp);
176293901Sarybchik
177293901Sarybchikstatic	__checkReturn	efx_rc_t
178293901Sarybchikefx_mcdi_licensed_app_state(
179293901Sarybchik	__in		efx_nic_t *enp,
180293901Sarybchik	__in		uint64_t app_id,
181293901Sarybchik	__out		boolean_t *licensedp);
182293901Sarybchik
183299517Sarybchikstatic const efx_lic_ops_t	__efx_lic_v2_ops = {
184293901Sarybchik	efx_mcdi_licensing_update_licenses,	/* elo_update_licenses */
185293901Sarybchik	efx_mcdi_licensing_get_key_stats,	/* elo_get_key_stats */
186293901Sarybchik	efx_mcdi_licensed_app_state,		/* elo_app_state */
187293901Sarybchik	NULL,					/* elo_get_id */
188299898Sarybchik	efx_lic_v1v2_find_start,		/* elo_find_start */
189299898Sarybchik	efx_lic_v1v2_find_end,			/* elo_find_end */
190299898Sarybchik	efx_lic_v1v2_find_key,			/* elo_find_key */
191299898Sarybchik	efx_lic_v1v2_validate_key,		/* elo_validate_key */
192299898Sarybchik	efx_lic_v1v2_read_key,			/* elo_read_key */
193299898Sarybchik	efx_lic_v1v2_write_key,			/* elo_write_key */
194299898Sarybchik	efx_lic_v1v2_delete_key,		/* elo_delete_key */
195299898Sarybchik	efx_lic_v1v2_create_partition,		/* elo_create_partition */
196299898Sarybchik	efx_lic_v1v2_finish_partition,		/* elo_finish_partition */
197293901Sarybchik};
198293901Sarybchik
199293901Sarybchik#endif	/* EFSYS_OPT_HUNTINGTON */
200293901Sarybchik
201293901Sarybchik#if EFSYS_OPT_MEDFORD
202293901Sarybchik
203293901Sarybchikstatic	__checkReturn	efx_rc_t
204293901Sarybchikefx_mcdi_licensing_v3_update_licenses(
205293901Sarybchik	__in		efx_nic_t *enp);
206293901Sarybchik
207293901Sarybchikstatic	__checkReturn	efx_rc_t
208293901Sarybchikefx_mcdi_licensing_v3_report_license(
209293901Sarybchik	__in		efx_nic_t *enp,
210293901Sarybchik	__out		efx_key_stats_t *eksp);
211293901Sarybchik
212293901Sarybchikstatic	__checkReturn	efx_rc_t
213293901Sarybchikefx_mcdi_licensing_v3_app_state(
214293901Sarybchik	__in		efx_nic_t *enp,
215293901Sarybchik	__in		uint64_t app_id,
216293901Sarybchik	__out		boolean_t *licensedp);
217293901Sarybchik
218293901Sarybchikstatic	__checkReturn	efx_rc_t
219293901Sarybchikefx_mcdi_licensing_v3_get_id(
220293901Sarybchik	__in		efx_nic_t *enp,
221293901Sarybchik	__in		size_t buffer_size,
222293901Sarybchik	__out		uint32_t *typep,
223293901Sarybchik	__out		size_t *lengthp,
224293901Sarybchik	__out_bcount_part_opt(buffer_size, *lengthp)
225293901Sarybchik			uint8_t *bufferp);
226293901Sarybchik
227299898Sarybchik	__checkReturn		efx_rc_t
228299898Sarybchikefx_lic_v3_find_start(
229299898Sarybchik	__in			efx_nic_t *enp,
230299898Sarybchik	__in_bcount(buffer_size)
231299898Sarybchik				caddr_t bufferp,
232299898Sarybchik	__in			size_t buffer_size,
233299898Sarybchik	__out			uint32_t *startp
234299898Sarybchik	);
235299898Sarybchik
236299898Sarybchik	__checkReturn		efx_rc_t
237299898Sarybchikefx_lic_v3_find_end(
238299898Sarybchik	__in			efx_nic_t *enp,
239299898Sarybchik	__in_bcount(buffer_size)
240299898Sarybchik				caddr_t bufferp,
241299898Sarybchik	__in			size_t buffer_size,
242299898Sarybchik	__in			uint32_t offset,
243299898Sarybchik	__out			uint32_t *endp
244299898Sarybchik	);
245299898Sarybchik
246299898Sarybchik	__checkReturn	__success(return != B_FALSE)	boolean_t
247299898Sarybchikefx_lic_v3_find_key(
248299898Sarybchik	__in			efx_nic_t *enp,
249299898Sarybchik	__in_bcount(buffer_size)
250299898Sarybchik				caddr_t bufferp,
251299898Sarybchik	__in			size_t buffer_size,
252299898Sarybchik	__in			uint32_t offset,
253299898Sarybchik	__out			uint32_t *startp,
254299898Sarybchik	__out			uint32_t *lengthp
255299898Sarybchik	);
256299898Sarybchik
257299898Sarybchik	__checkReturn	__success(return != B_FALSE)	boolean_t
258299898Sarybchikefx_lic_v3_validate_key(
259299898Sarybchik	__in			efx_nic_t *enp,
260299898Sarybchik	__in_bcount(length)	caddr_t keyp,
261299898Sarybchik	__in			uint32_t length
262299898Sarybchik	);
263299898Sarybchik
264299898Sarybchik	__checkReturn		efx_rc_t
265299898Sarybchikefx_lic_v3_read_key(
266299898Sarybchik	__in			efx_nic_t *enp,
267299898Sarybchik	__in_bcount(buffer_size)
268299898Sarybchik				caddr_t bufferp,
269299898Sarybchik	__in			size_t buffer_size,
270299898Sarybchik	__in			uint32_t offset,
271299898Sarybchik	__in			uint32_t length,
272299898Sarybchik	__out_bcount_part(key_max_size, *lengthp)
273299898Sarybchik				caddr_t keyp,
274299898Sarybchik	__in			size_t key_max_size,
275299898Sarybchik	__out			uint32_t *lengthp
276299898Sarybchik	);
277299898Sarybchik
278299898Sarybchik	__checkReturn		efx_rc_t
279299898Sarybchikefx_lic_v3_write_key(
280299898Sarybchik	__in			efx_nic_t *enp,
281299898Sarybchik	__in_bcount(buffer_size)
282299898Sarybchik				caddr_t bufferp,
283299898Sarybchik	__in			size_t buffer_size,
284299898Sarybchik	__in			uint32_t offset,
285299898Sarybchik	__in_bcount(length)	caddr_t keyp,
286299898Sarybchik	__in			uint32_t length,
287299898Sarybchik	__out			uint32_t *lengthp
288299898Sarybchik	);
289299898Sarybchik
290299898Sarybchik	__checkReturn		efx_rc_t
291299898Sarybchikefx_lic_v3_delete_key(
292299898Sarybchik	__in			efx_nic_t *enp,
293299898Sarybchik	__in_bcount(buffer_size)
294299898Sarybchik				caddr_t bufferp,
295299898Sarybchik	__in			size_t buffer_size,
296299898Sarybchik	__in			uint32_t offset,
297299898Sarybchik	__in			uint32_t length,
298299898Sarybchik	__in			uint32_t end,
299299898Sarybchik	__out			uint32_t *deltap
300299898Sarybchik	);
301299898Sarybchik
302299898Sarybchik	__checkReturn		efx_rc_t
303299898Sarybchikefx_lic_v3_create_partition(
304299898Sarybchik	__in			efx_nic_t *enp,
305299898Sarybchik	__in_bcount(buffer_size)
306299898Sarybchik				caddr_t bufferp,
307299898Sarybchik	__in			size_t buffer_size
308299898Sarybchik	);
309299898Sarybchik
310299898Sarybchik	__checkReturn		efx_rc_t
311299898Sarybchikefx_lic_v3_finish_partition(
312299898Sarybchik	__in			efx_nic_t *enp,
313299898Sarybchik	__in_bcount(buffer_size)
314299898Sarybchik				caddr_t bufferp,
315299898Sarybchik	__in			size_t buffer_size
316299898Sarybchik	);
317299898Sarybchik
318299517Sarybchikstatic const efx_lic_ops_t	__efx_lic_v3_ops = {
319293901Sarybchik	efx_mcdi_licensing_v3_update_licenses,	/* elo_update_licenses */
320293901Sarybchik	efx_mcdi_licensing_v3_report_license,	/* elo_get_key_stats */
321293901Sarybchik	efx_mcdi_licensing_v3_app_state,	/* elo_app_state */
322293901Sarybchik	efx_mcdi_licensing_v3_get_id,		/* elo_get_id */
323299898Sarybchik	efx_lic_v3_find_start,			/* elo_find_start*/
324299898Sarybchik	efx_lic_v3_find_end,			/* elo_find_end */
325299898Sarybchik	efx_lic_v3_find_key,			/* elo_find_key */
326299898Sarybchik	efx_lic_v3_validate_key,		/* elo_validate_key */
327299898Sarybchik	efx_lic_v3_read_key,			/* elo_read_key */
328299898Sarybchik	efx_lic_v3_write_key,			/* elo_write_key */
329299898Sarybchik	efx_lic_v3_delete_key,			/* elo_delete_key */
330299898Sarybchik	efx_lic_v3_create_partition,		/* elo_create_partition */
331299898Sarybchik	efx_lic_v3_finish_partition,		/* elo_finish_partition */
332293901Sarybchik};
333293901Sarybchik
334293901Sarybchik#endif	/* EFSYS_OPT_MEDFORD */
335293901Sarybchik
336293901Sarybchik
337293901Sarybchik/* V1 Licensing - used in Siena Modena only */
338293901Sarybchik
339293901Sarybchik#if EFSYS_OPT_SIENA
340293901Sarybchik
341293901Sarybchikstatic	__checkReturn	efx_rc_t
342293901Sarybchikefx_mcdi_fc_license_update_license(
343293901Sarybchik	__in		efx_nic_t *enp)
344293901Sarybchik{
345293901Sarybchik	efx_mcdi_req_t req;
346293901Sarybchik	uint8_t payload[MC_CMD_FC_IN_LICENSE_LEN];
347293901Sarybchik	efx_rc_t rc;
348293901Sarybchik
349293901Sarybchik	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
350293901Sarybchik
351293901Sarybchik	(void) memset(payload, 0, sizeof (payload));
352299905Sarybchik	req.emr_cmd = MC_CMD_FC;
353293901Sarybchik	req.emr_in_buf = payload;
354293901Sarybchik	req.emr_in_length = MC_CMD_FC_IN_LICENSE_LEN;
355293901Sarybchik	req.emr_out_buf = payload;
356293901Sarybchik	req.emr_out_length = 0;
357293901Sarybchik
358299905Sarybchik	MCDI_IN_SET_DWORD(req, FC_IN_CMD,
359299905Sarybchik	    MC_CMD_FC_OP_LICENSE);
360299905Sarybchik
361293901Sarybchik	MCDI_IN_SET_DWORD(req, FC_IN_LICENSE_OP,
362293901Sarybchik	    MC_CMD_FC_IN_LICENSE_UPDATE_LICENSE);
363293901Sarybchik
364293901Sarybchik	efx_mcdi_execute(enp, &req);
365293901Sarybchik
366293901Sarybchik	if (req.emr_rc != 0) {
367293901Sarybchik		rc = req.emr_rc;
368293901Sarybchik		goto fail1;
369293901Sarybchik	}
370293901Sarybchik
371293901Sarybchik	if (req.emr_out_length_used != 0) {
372293901Sarybchik		rc = EIO;
373293901Sarybchik		goto fail2;
374293901Sarybchik	}
375293901Sarybchik
376293901Sarybchik	return (0);
377293901Sarybchik
378293901Sarybchikfail2:
379293901Sarybchik	EFSYS_PROBE(fail2);
380293901Sarybchikfail1:
381293901Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
382293901Sarybchik
383293901Sarybchik	return (rc);
384293901Sarybchik}
385293901Sarybchik
386293901Sarybchikstatic	__checkReturn	efx_rc_t
387293901Sarybchikefx_mcdi_fc_license_get_key_stats(
388293901Sarybchik	__in		efx_nic_t *enp,
389293901Sarybchik	__out		efx_key_stats_t *eksp)
390293901Sarybchik{
391293901Sarybchik	efx_mcdi_req_t req;
392293901Sarybchik	uint8_t payload[MAX(MC_CMD_FC_IN_LICENSE_LEN,
393293901Sarybchik			    MC_CMD_FC_OUT_LICENSE_LEN)];
394293901Sarybchik	efx_rc_t rc;
395293901Sarybchik
396293901Sarybchik	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
397293901Sarybchik
398293901Sarybchik	(void) memset(payload, 0, sizeof (payload));
399299905Sarybchik	req.emr_cmd = MC_CMD_FC;
400293901Sarybchik	req.emr_in_buf = payload;
401293901Sarybchik	req.emr_in_length = MC_CMD_FC_IN_LICENSE_LEN;
402293901Sarybchik	req.emr_out_buf = payload;
403293901Sarybchik	req.emr_out_length = MC_CMD_FC_OUT_LICENSE_LEN;
404293901Sarybchik
405299905Sarybchik	MCDI_IN_SET_DWORD(req, FC_IN_CMD,
406299905Sarybchik	    MC_CMD_FC_OP_LICENSE);
407299905Sarybchik
408293901Sarybchik	MCDI_IN_SET_DWORD(req, FC_IN_LICENSE_OP,
409293901Sarybchik	    MC_CMD_FC_IN_LICENSE_GET_KEY_STATS);
410293901Sarybchik
411299923Sarybchik	efx_mcdi_execute_quiet(enp, &req);
412293901Sarybchik
413293901Sarybchik	if (req.emr_rc != 0) {
414293901Sarybchik		rc = req.emr_rc;
415293901Sarybchik		goto fail1;
416293901Sarybchik	}
417293901Sarybchik
418293901Sarybchik	if (req.emr_out_length_used < MC_CMD_FC_OUT_LICENSE_LEN) {
419293901Sarybchik		rc = EMSGSIZE;
420293901Sarybchik		goto fail2;
421293901Sarybchik	}
422293901Sarybchik
423293901Sarybchik	eksp->eks_valid =
424293901Sarybchik		MCDI_OUT_DWORD(req, FC_OUT_LICENSE_VALID_KEYS);
425293901Sarybchik	eksp->eks_invalid =
426293901Sarybchik		MCDI_OUT_DWORD(req, FC_OUT_LICENSE_INVALID_KEYS);
427293901Sarybchik	eksp->eks_blacklisted =
428293901Sarybchik		MCDI_OUT_DWORD(req, FC_OUT_LICENSE_BLACKLISTED_KEYS);
429293901Sarybchik	eksp->eks_unverifiable = 0;
430293901Sarybchik	eksp->eks_wrong_node = 0;
431293901Sarybchik	eksp->eks_licensed_apps_lo = 0;
432293901Sarybchik	eksp->eks_licensed_apps_hi = 0;
433293901Sarybchik	eksp->eks_licensed_features_lo = 0;
434293901Sarybchik	eksp->eks_licensed_features_hi = 0;
435293901Sarybchik
436293901Sarybchik	return (0);
437293901Sarybchik
438293901Sarybchikfail2:
439293901Sarybchik	EFSYS_PROBE(fail2);
440293901Sarybchikfail1:
441293901Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
442293901Sarybchik
443293901Sarybchik	return (rc);
444293901Sarybchik}
445293901Sarybchik
446293901Sarybchik#endif	/* EFSYS_OPT_SIENA */
447293901Sarybchik
448299898Sarybchik/* V1 and V2 Partition format - based on a 16-bit TLV format */
449299898Sarybchik
450299898Sarybchik#if EFSYS_OPT_SIENA | EFSYS_OPT_HUNTINGTON
451299898Sarybchik
452299898Sarybchik/*
453299898Sarybchik * V1/V2 format - defined in SF-108542-TC section 4.2:
454299898Sarybchik *  Type (T):   16bit - revision/HMAC algorithm
455299898Sarybchik *  Length (L): 16bit - value length in bytes
456299898Sarybchik *  Value (V):  L bytes - payload
457299898Sarybchik */
458299898Sarybchik#define EFX_LICENSE_V1V2_PAYLOAD_LENGTH_MAX    (256)
459299898Sarybchik#define EFX_LICENSE_V1V2_HEADER_LENGTH         (2*sizeof(uint16_t))
460299898Sarybchik
461299898Sarybchik	__checkReturn		efx_rc_t
462299898Sarybchikefx_lic_v1v2_find_start(
463299898Sarybchik	__in			efx_nic_t *enp,
464299898Sarybchik	__in_bcount(buffer_size)
465299898Sarybchik				caddr_t bufferp,
466299898Sarybchik	__in			size_t buffer_size,
467299898Sarybchik	__out			uint32_t *startp
468299898Sarybchik	)
469299898Sarybchik{
470299898Sarybchik	_NOTE(ARGUNUSED(enp, bufferp, buffer_size))
471299898Sarybchik
472299898Sarybchik	*startp = 0;
473299898Sarybchik	return (0);
474299898Sarybchik}
475299898Sarybchik
476299898Sarybchik	__checkReturn		efx_rc_t
477299898Sarybchikefx_lic_v1v2_find_end(
478299898Sarybchik	__in			efx_nic_t *enp,
479299898Sarybchik	__in_bcount(buffer_size)
480299898Sarybchik				caddr_t bufferp,
481299898Sarybchik	__in			size_t buffer_size,
482299898Sarybchik	__in			uint32_t offset,
483299898Sarybchik	__out			uint32_t *endp
484299898Sarybchik	)
485299898Sarybchik{
486299898Sarybchik	_NOTE(ARGUNUSED(enp, bufferp, buffer_size))
487299898Sarybchik
488299898Sarybchik	*endp = offset + EFX_LICENSE_V1V2_HEADER_LENGTH;
489299898Sarybchik	return (0);
490299898Sarybchik}
491299898Sarybchik
492299898Sarybchik	__checkReturn	__success(return != B_FALSE)	boolean_t
493299898Sarybchikefx_lic_v1v2_find_key(
494299898Sarybchik	__in			efx_nic_t *enp,
495299898Sarybchik	__in_bcount(buffer_size)
496299898Sarybchik				caddr_t bufferp,
497299898Sarybchik	__in			size_t buffer_size,
498299898Sarybchik	__in			uint32_t offset,
499299898Sarybchik	__out			uint32_t *startp,
500299898Sarybchik	__out			uint32_t *lengthp
501299898Sarybchik	)
502299898Sarybchik{
503299898Sarybchik	boolean_t found;
504299898Sarybchik	uint16_t tlv_type;
505299898Sarybchik	uint16_t tlv_length;
506299898Sarybchik
507299898Sarybchik	_NOTE(ARGUNUSED(enp))
508299898Sarybchik
509299898Sarybchik	if((size_t)buffer_size - offset < EFX_LICENSE_V1V2_HEADER_LENGTH)
510299898Sarybchik		goto fail1;
511299898Sarybchik
512299898Sarybchik	tlv_type = __LE_TO_CPU_16(((uint16_t*)&bufferp[offset])[0]);
513299898Sarybchik	tlv_length = __LE_TO_CPU_16(((uint16_t*)&bufferp[offset])[1]);
514299898Sarybchik	if ((tlv_length > EFX_LICENSE_V1V2_PAYLOAD_LENGTH_MAX) ||
515299898Sarybchik	    (tlv_type == 0 && tlv_length == 0)) {
516299898Sarybchik		found = B_FALSE;
517299898Sarybchik	} else {
518299898Sarybchik		*startp = offset;
519299898Sarybchik		*lengthp = tlv_length + EFX_LICENSE_V1V2_HEADER_LENGTH;
520299898Sarybchik		found = B_TRUE;
521299898Sarybchik	}
522299898Sarybchik	return (found);
523299898Sarybchik
524299898Sarybchikfail1:
525299898Sarybchik	EFSYS_PROBE(fail1);
526299898Sarybchik
527299898Sarybchik	return (B_FALSE);
528299898Sarybchik}
529299898Sarybchik
530299898Sarybchik	__checkReturn	__success(return != B_FALSE)	boolean_t
531299898Sarybchikefx_lic_v1v2_validate_key(
532299898Sarybchik	__in			efx_nic_t *enp,
533299898Sarybchik	__in_bcount(length)	caddr_t keyp,
534299898Sarybchik	__in			uint32_t length
535299898Sarybchik	)
536299898Sarybchik{
537299898Sarybchik	const efx_lic_ops_t *elop = enp->en_elop;
538299898Sarybchik	efx_rc_t rc;
539299898Sarybchik	uint16_t tlv_type;
540299898Sarybchik	uint16_t tlv_length;
541299898Sarybchik
542299898Sarybchik	_NOTE(ARGUNUSED(enp))
543299898Sarybchik
544299898Sarybchik	if (length < EFX_LICENSE_V1V2_HEADER_LENGTH) {
545299898Sarybchik		goto fail1;
546299898Sarybchik	}
547299898Sarybchik
548299898Sarybchik	tlv_type = __LE_TO_CPU_16(((uint16_t*)keyp)[0]);
549299898Sarybchik	tlv_length = __LE_TO_CPU_16(((uint16_t*)keyp)[1]);
550299898Sarybchik
551299898Sarybchik	if(tlv_length > EFX_LICENSE_V1V2_PAYLOAD_LENGTH_MAX) {
552299898Sarybchik		goto fail2;
553299898Sarybchik	}
554299898Sarybchik	if (tlv_type == 0) {
555299898Sarybchik		goto fail3;
556299898Sarybchik	}
557299898Sarybchik	if ((tlv_length + EFX_LICENSE_V1V2_HEADER_LENGTH) != length) {
558299898Sarybchik		goto fail4;
559299898Sarybchik	}
560299898Sarybchik
561299898Sarybchik	return (B_TRUE);
562299898Sarybchik
563299898Sarybchikfail4:
564299898Sarybchik	EFSYS_PROBE(fail4);
565299898Sarybchikfail3:
566299898Sarybchik	EFSYS_PROBE(fail3);
567299898Sarybchikfail2:
568299898Sarybchik	EFSYS_PROBE(fail2);
569299898Sarybchikfail1:
570299898Sarybchik	EFSYS_PROBE(fail1);
571299898Sarybchik
572299898Sarybchik	return (B_FALSE);
573299898Sarybchik}
574299898Sarybchik
575299898Sarybchik
576299898Sarybchik	__checkReturn		efx_rc_t
577299898Sarybchikefx_lic_v1v2_read_key(
578299898Sarybchik	__in			efx_nic_t *enp,
579299898Sarybchik	__in_bcount(buffer_size)
580299898Sarybchik				caddr_t bufferp,
581299898Sarybchik	__in			size_t buffer_size,
582299898Sarybchik	__in			uint32_t offset,
583299898Sarybchik	__in			uint32_t length,
584299898Sarybchik	__out_bcount_part(key_max_size, *lengthp)
585299898Sarybchik				caddr_t keyp,
586299898Sarybchik	__in			size_t key_max_size,
587299898Sarybchik	__out			uint32_t *lengthp
588299898Sarybchik	)
589299898Sarybchik{
590299898Sarybchik	efx_rc_t rc;
591299898Sarybchik
592299898Sarybchik	_NOTE(ARGUNUSED(enp))
593299898Sarybchik	EFSYS_ASSERT(length <= (EFX_LICENSE_V1V2_PAYLOAD_LENGTH_MAX +
594299898Sarybchik	    EFX_LICENSE_V1V2_HEADER_LENGTH));
595299898Sarybchik
596299898Sarybchik	if (key_max_size < length) {
597299898Sarybchik		rc = ENOSPC;
598299898Sarybchik		goto fail1;
599299898Sarybchik	}
600299898Sarybchik	memcpy(keyp, &bufferp[offset], length);
601299898Sarybchik
602299898Sarybchik	*lengthp = length;
603299898Sarybchik
604299898Sarybchik	return (0);
605299898Sarybchik
606299898Sarybchikfail1:
607299898Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
608299898Sarybchik
609299898Sarybchik	return (rc);
610299898Sarybchik}
611299898Sarybchik
612299898Sarybchik	__checkReturn		efx_rc_t
613299898Sarybchikefx_lic_v1v2_write_key(
614299898Sarybchik	__in			efx_nic_t *enp,
615299898Sarybchik	__in_bcount(buffer_size)
616299898Sarybchik				caddr_t bufferp,
617299898Sarybchik	__in			size_t buffer_size,
618299898Sarybchik	__in			uint32_t offset,
619299898Sarybchik	__in_bcount(length)	caddr_t keyp,
620299898Sarybchik	__in			uint32_t length,
621299898Sarybchik	__out			uint32_t *lengthp
622299898Sarybchik	)
623299898Sarybchik{
624299898Sarybchik	efx_rc_t rc;
625299898Sarybchik
626299898Sarybchik	_NOTE(ARGUNUSED(enp))
627299898Sarybchik	EFSYS_ASSERT(length <= (EFX_LICENSE_V1V2_PAYLOAD_LENGTH_MAX +
628299898Sarybchik	    EFX_LICENSE_V1V2_HEADER_LENGTH));
629299898Sarybchik
630299898Sarybchik	// Ensure space for terminator remains
631299898Sarybchik	if ((offset + length) >
632299898Sarybchik	    (buffer_size - EFX_LICENSE_V1V2_HEADER_LENGTH) ) {
633299898Sarybchik		rc = ENOSPC;
634299898Sarybchik		goto fail1;
635299898Sarybchik	}
636299898Sarybchik
637299898Sarybchik	memcpy(bufferp + offset, keyp, length);
638299898Sarybchik
639299898Sarybchik	*lengthp = length;
640299898Sarybchik
641299898Sarybchik	return (0);
642299898Sarybchik
643299898Sarybchikfail1:
644299898Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
645299898Sarybchik
646299898Sarybchik	return (rc);
647299898Sarybchik}
648299898Sarybchik
649299898Sarybchik	__checkReturn		efx_rc_t
650299898Sarybchikefx_lic_v1v2_delete_key(
651299898Sarybchik	__in			efx_nic_t *enp,
652299898Sarybchik	__in_bcount(buffer_size)
653299898Sarybchik				caddr_t bufferp,
654299898Sarybchik	__in			size_t buffer_size,
655299898Sarybchik	__in			uint32_t offset,
656299898Sarybchik	__in			uint32_t length,
657299898Sarybchik	__in			uint32_t end,
658299898Sarybchik	__out			uint32_t *deltap
659299898Sarybchik	)
660299898Sarybchik{
661299898Sarybchik	efx_rc_t rc;
662299898Sarybchik	uint32_t move_start = offset + length;
663299898Sarybchik	uint32_t move_length = end - move_start;
664299898Sarybchik
665299898Sarybchik	_NOTE(ARGUNUSED(enp))
666299898Sarybchik	EFSYS_ASSERT(end <= buffer_size);
667299898Sarybchik
668299898Sarybchik	// Shift everything after the key down
669299898Sarybchik	memmove(bufferp + offset, bufferp + move_start, move_length);
670299898Sarybchik
671299898Sarybchik	*deltap = length;
672299898Sarybchik
673299898Sarybchik	return (0);
674299898Sarybchik}
675299898Sarybchik
676299898Sarybchik	__checkReturn		efx_rc_t
677299898Sarybchikefx_lic_v1v2_create_partition(
678299898Sarybchik	__in			efx_nic_t *enp,
679299898Sarybchik	__in_bcount(buffer_size)
680299898Sarybchik				caddr_t bufferp,
681299898Sarybchik	__in			size_t buffer_size
682299898Sarybchik	)
683299898Sarybchik{
684299898Sarybchik	_NOTE(ARGUNUSED(enp))
685299898Sarybchik	EFSYS_ASSERT(EFX_LICENSE_V1V2_HEADER_LENGTH <= buffer_size);
686299898Sarybchik
687299898Sarybchik	// Write terminator
688299898Sarybchik	memset(bufferp, '\0', EFX_LICENSE_V1V2_HEADER_LENGTH);
689299898Sarybchik	return (0);
690299898Sarybchik}
691299898Sarybchik
692299898Sarybchik
693299898Sarybchik	__checkReturn		efx_rc_t
694299898Sarybchikefx_lic_v1v2_finish_partition(
695299898Sarybchik	__in			efx_nic_t *enp,
696299898Sarybchik	__in_bcount(buffer_size)
697299898Sarybchik				caddr_t bufferp,
698299898Sarybchik	__in			size_t buffer_size
699299898Sarybchik	)
700299898Sarybchik{
701299898Sarybchik	_NOTE(ARGUNUSED(enp, bufferp, buffer_size))
702299898Sarybchik
703299898Sarybchik	return (0);
704299898Sarybchik}
705299898Sarybchik
706299898Sarybchik#endif	/* EFSYS_OPT_HUNTINGTON | EFSYS_OPT_SIENA */
707299898Sarybchik
708299898Sarybchik
709293901Sarybchik/* V2 Licensing - used by Huntington family only. See SF-113611-TC */
710293901Sarybchik
711293901Sarybchik#if EFSYS_OPT_HUNTINGTON
712293901Sarybchik
713293901Sarybchikstatic	__checkReturn	efx_rc_t
714293901Sarybchikefx_mcdi_licensed_app_state(
715293901Sarybchik	__in		efx_nic_t *enp,
716293901Sarybchik	__in		uint64_t app_id,
717293901Sarybchik	__out		boolean_t *licensedp)
718293901Sarybchik{
719293901Sarybchik	efx_mcdi_req_t req;
720293901Sarybchik	uint8_t payload[MAX(MC_CMD_GET_LICENSED_APP_STATE_IN_LEN,
721293901Sarybchik			    MC_CMD_GET_LICENSED_APP_STATE_OUT_LEN)];
722293901Sarybchik	uint32_t app_state;
723293901Sarybchik	efx_rc_t rc;
724293901Sarybchik
725293901Sarybchik	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
726293901Sarybchik
727293901Sarybchik	/* V2 licensing supports 32bit app id only */
728293901Sarybchik	if ((app_id >> 32) != 0) {
729293901Sarybchik		rc = EINVAL;
730293901Sarybchik		goto fail1;
731293901Sarybchik	}
732293901Sarybchik
733293901Sarybchik	(void) memset(payload, 0, sizeof (payload));
734293901Sarybchik	req.emr_cmd = MC_CMD_GET_LICENSED_APP_STATE;
735293901Sarybchik	req.emr_in_buf = payload;
736293901Sarybchik	req.emr_in_length = MC_CMD_GET_LICENSED_APP_STATE_IN_LEN;
737293901Sarybchik	req.emr_out_buf = payload;
738293901Sarybchik	req.emr_out_length = MC_CMD_GET_LICENSED_APP_STATE_OUT_LEN;
739293901Sarybchik
740293901Sarybchik	MCDI_IN_SET_DWORD(req, GET_LICENSED_APP_STATE_IN_APP_ID,
741293901Sarybchik		    app_id & 0xffffffff);
742293901Sarybchik
743293901Sarybchik	efx_mcdi_execute(enp, &req);
744293901Sarybchik
745293901Sarybchik	if (req.emr_rc != 0) {
746293901Sarybchik		rc = req.emr_rc;
747293901Sarybchik		goto fail2;
748293901Sarybchik	}
749293901Sarybchik
750293901Sarybchik	if (req.emr_out_length_used < MC_CMD_GET_LICENSED_APP_STATE_OUT_LEN) {
751293901Sarybchik		rc = EMSGSIZE;
752293901Sarybchik		goto fail3;
753293901Sarybchik	}
754293901Sarybchik
755293901Sarybchik	app_state = (MCDI_OUT_DWORD(req, GET_LICENSED_APP_STATE_OUT_STATE));
756293901Sarybchik	if (app_state != MC_CMD_GET_LICENSED_APP_STATE_OUT_NOT_LICENSED) {
757293901Sarybchik		*licensedp = B_TRUE;
758293901Sarybchik	} else {
759293901Sarybchik		*licensedp = B_FALSE;
760293901Sarybchik	}
761293901Sarybchik
762293901Sarybchik	return (0);
763293901Sarybchik
764293901Sarybchikfail3:
765293901Sarybchik	EFSYS_PROBE(fail3);
766293901Sarybchikfail2:
767293901Sarybchik	EFSYS_PROBE(fail2);
768293901Sarybchikfail1:
769293901Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
770293901Sarybchik
771293901Sarybchik	return (rc);
772293901Sarybchik}
773293901Sarybchik
774293901Sarybchikstatic	__checkReturn	efx_rc_t
775293901Sarybchikefx_mcdi_licensing_update_licenses(
776293901Sarybchik	__in		efx_nic_t *enp)
777293901Sarybchik{
778293901Sarybchik	efx_mcdi_req_t req;
779293901Sarybchik	uint8_t payload[MC_CMD_LICENSING_IN_LEN];
780293901Sarybchik	efx_rc_t rc;
781293901Sarybchik
782293901Sarybchik	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
783293901Sarybchik
784293901Sarybchik	(void) memset(payload, 0, sizeof (payload));
785293901Sarybchik	req.emr_cmd = MC_CMD_LICENSING;
786293901Sarybchik	req.emr_in_buf = payload;
787293901Sarybchik	req.emr_in_length = MC_CMD_LICENSING_IN_LEN;
788293901Sarybchik	req.emr_out_buf = payload;
789293901Sarybchik	req.emr_out_length = 0;
790293901Sarybchik
791293901Sarybchik	MCDI_IN_SET_DWORD(req, LICENSING_IN_OP,
792293901Sarybchik	    MC_CMD_LICENSING_IN_OP_UPDATE_LICENSE);
793293901Sarybchik
794293901Sarybchik	efx_mcdi_execute(enp, &req);
795293901Sarybchik
796293901Sarybchik	if (req.emr_rc != 0) {
797293901Sarybchik		rc = req.emr_rc;
798293901Sarybchik		goto fail1;
799293901Sarybchik	}
800293901Sarybchik
801293901Sarybchik	if (req.emr_out_length_used != 0) {
802293901Sarybchik		rc = EIO;
803293901Sarybchik		goto fail2;
804293901Sarybchik	}
805293901Sarybchik
806293901Sarybchik	return (0);
807293901Sarybchik
808293901Sarybchikfail2:
809293901Sarybchik	EFSYS_PROBE(fail2);
810293901Sarybchikfail1:
811293901Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
812293901Sarybchik
813293901Sarybchik	return (rc);
814293901Sarybchik}
815293901Sarybchik
816293901Sarybchikstatic	__checkReturn	efx_rc_t
817293901Sarybchikefx_mcdi_licensing_get_key_stats(
818293901Sarybchik	__in		efx_nic_t *enp,
819293901Sarybchik	__out		efx_key_stats_t *eksp)
820293901Sarybchik{
821293901Sarybchik	efx_mcdi_req_t req;
822293901Sarybchik	uint8_t payload[MAX(MC_CMD_LICENSING_IN_LEN,
823293901Sarybchik			    MC_CMD_LICENSING_OUT_LEN)];
824293901Sarybchik	efx_rc_t rc;
825293901Sarybchik
826293901Sarybchik	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
827293901Sarybchik
828293901Sarybchik	(void) memset(payload, 0, sizeof (payload));
829293901Sarybchik	req.emr_cmd = MC_CMD_LICENSING;
830293901Sarybchik	req.emr_in_buf = payload;
831293901Sarybchik	req.emr_in_length = MC_CMD_LICENSING_IN_LEN;
832293901Sarybchik	req.emr_out_buf = payload;
833293901Sarybchik	req.emr_out_length = MC_CMD_LICENSING_OUT_LEN;
834293901Sarybchik
835293901Sarybchik	MCDI_IN_SET_DWORD(req, LICENSING_IN_OP,
836293901Sarybchik	    MC_CMD_LICENSING_IN_OP_GET_KEY_STATS);
837293901Sarybchik
838293901Sarybchik	efx_mcdi_execute(enp, &req);
839293901Sarybchik
840293901Sarybchik	if (req.emr_rc != 0) {
841293901Sarybchik		rc = req.emr_rc;
842293901Sarybchik		goto fail1;
843293901Sarybchik	}
844293901Sarybchik
845293901Sarybchik	if (req.emr_out_length_used < MC_CMD_LICENSING_OUT_LEN) {
846293901Sarybchik		rc = EMSGSIZE;
847293901Sarybchik		goto fail2;
848293901Sarybchik	}
849293901Sarybchik
850293901Sarybchik	eksp->eks_valid =
851293901Sarybchik		MCDI_OUT_DWORD(req, LICENSING_OUT_VALID_APP_KEYS);
852293901Sarybchik	eksp->eks_invalid =
853293901Sarybchik		MCDI_OUT_DWORD(req, LICENSING_OUT_INVALID_APP_KEYS);
854293901Sarybchik	eksp->eks_blacklisted =
855293901Sarybchik		MCDI_OUT_DWORD(req, LICENSING_OUT_BLACKLISTED_APP_KEYS);
856293901Sarybchik	eksp->eks_unverifiable =
857293901Sarybchik		MCDI_OUT_DWORD(req, LICENSING_OUT_UNVERIFIABLE_APP_KEYS);
858293901Sarybchik	eksp->eks_wrong_node =
859293901Sarybchik		MCDI_OUT_DWORD(req, LICENSING_OUT_WRONG_NODE_APP_KEYS);
860293901Sarybchik	eksp->eks_licensed_apps_lo = 0;
861293901Sarybchik	eksp->eks_licensed_apps_hi = 0;
862293901Sarybchik	eksp->eks_licensed_features_lo = 0;
863293901Sarybchik	eksp->eks_licensed_features_hi = 0;
864293901Sarybchik
865293901Sarybchik	return (0);
866293901Sarybchik
867293901Sarybchikfail2:
868293901Sarybchik	EFSYS_PROBE(fail2);
869293901Sarybchikfail1:
870293901Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
871293901Sarybchik
872293901Sarybchik	return (rc);
873293901Sarybchik}
874293901Sarybchik
875293901Sarybchik#endif	/* EFSYS_OPT_HUNTINGTON */
876293901Sarybchik
877293901Sarybchik/* V3 Licensing - used starting from Medford family. See SF-114884-SW */
878293901Sarybchik
879293901Sarybchik#if EFSYS_OPT_MEDFORD
880293901Sarybchik
881293901Sarybchikstatic	__checkReturn	efx_rc_t
882293901Sarybchikefx_mcdi_licensing_v3_update_licenses(
883293901Sarybchik	__in		efx_nic_t *enp)
884293901Sarybchik{
885293901Sarybchik	efx_mcdi_req_t req;
886293901Sarybchik	uint8_t payload[MC_CMD_LICENSING_V3_IN_LEN];
887293901Sarybchik	efx_rc_t rc;
888293901Sarybchik
889293901Sarybchik	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_MEDFORD);
890293901Sarybchik
891293901Sarybchik	(void) memset(payload, 0, sizeof (payload));
892293901Sarybchik	req.emr_cmd = MC_CMD_LICENSING_V3;
893293901Sarybchik	req.emr_in_buf = payload;
894293901Sarybchik	req.emr_in_length = MC_CMD_LICENSING_V3_IN_LEN;
895293901Sarybchik	req.emr_out_buf = NULL;
896293901Sarybchik	req.emr_out_length = 0;
897293901Sarybchik
898293901Sarybchik	MCDI_IN_SET_DWORD(req, LICENSING_V3_IN_OP,
899293901Sarybchik	    MC_CMD_LICENSING_V3_IN_OP_UPDATE_LICENSE);
900293901Sarybchik
901293901Sarybchik	efx_mcdi_execute(enp, &req);
902293901Sarybchik
903293901Sarybchik	if (req.emr_rc != 0) {
904293901Sarybchik		rc = req.emr_rc;
905293901Sarybchik		goto fail1;
906293901Sarybchik	}
907293901Sarybchik
908293901Sarybchik	return (0);
909293901Sarybchik
910293901Sarybchikfail1:
911293901Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
912293901Sarybchik
913293901Sarybchik	return (rc);
914293901Sarybchik}
915293901Sarybchik
916293901Sarybchikstatic	__checkReturn	efx_rc_t
917293901Sarybchikefx_mcdi_licensing_v3_report_license(
918293901Sarybchik	__in		efx_nic_t *enp,
919293901Sarybchik	__out		efx_key_stats_t *eksp)
920293901Sarybchik{
921293901Sarybchik	efx_mcdi_req_t req;
922293901Sarybchik	uint8_t payload[MAX(MC_CMD_LICENSING_V3_IN_LEN,
923293901Sarybchik			    MC_CMD_LICENSING_V3_OUT_LEN)];
924293901Sarybchik	efx_rc_t rc;
925293901Sarybchik
926293901Sarybchik	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_MEDFORD);
927293901Sarybchik
928293901Sarybchik	(void) memset(payload, 0, sizeof (payload));
929293901Sarybchik	req.emr_cmd = MC_CMD_LICENSING_V3;
930293901Sarybchik	req.emr_in_buf = payload;
931293901Sarybchik	req.emr_in_length = MC_CMD_LICENSING_V3_IN_LEN;
932293901Sarybchik	req.emr_out_buf = payload;
933293901Sarybchik	req.emr_out_length = MC_CMD_LICENSING_V3_OUT_LEN;
934293901Sarybchik
935293901Sarybchik	MCDI_IN_SET_DWORD(req, LICENSING_V3_IN_OP,
936293901Sarybchik	    MC_CMD_LICENSING_V3_IN_OP_REPORT_LICENSE);
937293901Sarybchik
938299923Sarybchik	efx_mcdi_execute_quiet(enp, &req);
939293901Sarybchik
940293901Sarybchik	if (req.emr_rc != 0) {
941293901Sarybchik		rc = req.emr_rc;
942293901Sarybchik		goto fail1;
943293901Sarybchik	}
944293901Sarybchik
945293901Sarybchik	if (req.emr_out_length_used < MC_CMD_LICENSING_V3_OUT_LEN) {
946293901Sarybchik		rc = EMSGSIZE;
947293901Sarybchik		goto fail2;
948293901Sarybchik	}
949293901Sarybchik
950293901Sarybchik	eksp->eks_valid =
951293901Sarybchik		MCDI_OUT_DWORD(req, LICENSING_V3_OUT_VALID_KEYS);
952293901Sarybchik	eksp->eks_invalid =
953293901Sarybchik		MCDI_OUT_DWORD(req, LICENSING_V3_OUT_INVALID_KEYS);
954293901Sarybchik	eksp->eks_blacklisted = 0;
955293901Sarybchik	eksp->eks_unverifiable =
956293901Sarybchik		MCDI_OUT_DWORD(req, LICENSING_V3_OUT_UNVERIFIABLE_KEYS);
957293901Sarybchik	eksp->eks_wrong_node =
958293901Sarybchik		MCDI_OUT_DWORD(req, LICENSING_V3_OUT_WRONG_NODE_KEYS);
959293901Sarybchik	eksp->eks_licensed_apps_lo =
960293901Sarybchik		MCDI_OUT_DWORD(req, LICENSING_V3_OUT_LICENSED_APPS_LO);
961293901Sarybchik	eksp->eks_licensed_apps_hi =
962293901Sarybchik		MCDI_OUT_DWORD(req, LICENSING_V3_OUT_LICENSED_APPS_HI);
963293901Sarybchik	eksp->eks_licensed_features_lo =
964293901Sarybchik		MCDI_OUT_DWORD(req, LICENSING_V3_OUT_LICENSED_FEATURES_LO);
965293901Sarybchik	eksp->eks_licensed_features_hi =
966293901Sarybchik		MCDI_OUT_DWORD(req, LICENSING_V3_OUT_LICENSED_FEATURES_HI);
967293901Sarybchik
968293901Sarybchik	return (0);
969293901Sarybchik
970293901Sarybchikfail2:
971293901Sarybchik	EFSYS_PROBE(fail2);
972293901Sarybchikfail1:
973293901Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
974293901Sarybchik
975293901Sarybchik	return (rc);
976293901Sarybchik}
977293901Sarybchik
978293901Sarybchikstatic	__checkReturn	efx_rc_t
979293901Sarybchikefx_mcdi_licensing_v3_app_state(
980293901Sarybchik	__in		efx_nic_t *enp,
981293901Sarybchik	__in		uint64_t app_id,
982293901Sarybchik	__out		boolean_t *licensedp)
983293901Sarybchik{
984293901Sarybchik	efx_mcdi_req_t req;
985293901Sarybchik	uint8_t payload[MAX(MC_CMD_GET_LICENSED_V3_APP_STATE_IN_LEN,
986293901Sarybchik			    MC_CMD_GET_LICENSED_V3_APP_STATE_OUT_LEN)];
987293901Sarybchik	uint32_t app_state;
988293901Sarybchik	efx_rc_t rc;
989293901Sarybchik
990293901Sarybchik	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_MEDFORD);
991293901Sarybchik
992293901Sarybchik	(void) memset(payload, 0, sizeof (payload));
993293901Sarybchik	req.emr_cmd = MC_CMD_GET_LICENSED_V3_APP_STATE;
994293901Sarybchik	req.emr_in_buf = payload;
995293901Sarybchik	req.emr_in_length = MC_CMD_GET_LICENSED_V3_APP_STATE_IN_LEN;
996293901Sarybchik	req.emr_out_buf = payload;
997293901Sarybchik	req.emr_out_length = MC_CMD_GET_LICENSED_V3_APP_STATE_OUT_LEN;
998293901Sarybchik
999293901Sarybchik	MCDI_IN_SET_DWORD(req, GET_LICENSED_V3_APP_STATE_IN_APP_ID_LO,
1000293901Sarybchik		    app_id & 0xffffffff);
1001293901Sarybchik	MCDI_IN_SET_DWORD(req, GET_LICENSED_V3_APP_STATE_IN_APP_ID_HI,
1002293901Sarybchik		    app_id >> 32);
1003293901Sarybchik
1004293901Sarybchik	efx_mcdi_execute(enp, &req);
1005293901Sarybchik
1006293901Sarybchik	if (req.emr_rc != 0) {
1007293901Sarybchik		rc = req.emr_rc;
1008293901Sarybchik		goto fail1;
1009293901Sarybchik	}
1010293901Sarybchik
1011293901Sarybchik	if (req.emr_out_length_used < MC_CMD_GET_LICENSED_V3_APP_STATE_OUT_LEN) {
1012293901Sarybchik		rc = EMSGSIZE;
1013293901Sarybchik		goto fail2;
1014293901Sarybchik	}
1015293901Sarybchik
1016293901Sarybchik	app_state = (MCDI_OUT_DWORD(req, GET_LICENSED_V3_APP_STATE_OUT_STATE));
1017293901Sarybchik	if (app_state != MC_CMD_GET_LICENSED_V3_APP_STATE_OUT_NOT_LICENSED) {
1018293901Sarybchik		*licensedp = B_TRUE;
1019293901Sarybchik	} else {
1020293901Sarybchik		*licensedp = B_FALSE;
1021293901Sarybchik	}
1022293901Sarybchik
1023293901Sarybchik	return (0);
1024293901Sarybchik
1025293901Sarybchikfail2:
1026293901Sarybchik	EFSYS_PROBE(fail2);
1027293901Sarybchikfail1:
1028293901Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1029293901Sarybchik
1030293901Sarybchik	return (rc);
1031293901Sarybchik}
1032293901Sarybchik
1033293901Sarybchikstatic	__checkReturn	efx_rc_t
1034293901Sarybchikefx_mcdi_licensing_v3_get_id(
1035293901Sarybchik	__in		efx_nic_t *enp,
1036293901Sarybchik	__in		size_t buffer_size,
1037293901Sarybchik	__out		uint32_t *typep,
1038293901Sarybchik	__out		size_t *lengthp,
1039293901Sarybchik	__out_bcount_part_opt(buffer_size, *lengthp)
1040293901Sarybchik			uint8_t *bufferp)
1041293901Sarybchik{
1042293901Sarybchik	efx_mcdi_req_t req;
1043293901Sarybchik	uint8_t payload[MAX(MC_CMD_LICENSING_GET_ID_V3_IN_LEN,
1044293901Sarybchik			    MC_CMD_LICENSING_GET_ID_V3_OUT_LENMIN)];
1045293901Sarybchik	efx_rc_t rc;
1046293901Sarybchik
1047293901Sarybchik	req.emr_cmd = MC_CMD_LICENSING_GET_ID_V3;
1048293901Sarybchik
1049293901Sarybchik	if (bufferp == NULL) {
1050293901Sarybchik		/* Request id type and length only */
1051293901Sarybchik		req.emr_in_buf = bufferp;
1052293901Sarybchik		req.emr_in_length = MC_CMD_LICENSING_GET_ID_V3_IN_LEN;
1053293901Sarybchik		req.emr_out_buf = bufferp;
1054293901Sarybchik		req.emr_out_length = MC_CMD_LICENSING_GET_ID_V3_OUT_LENMIN;
1055293901Sarybchik		(void) memset(payload, 0, sizeof (payload));
1056293901Sarybchik	} else {
1057293901Sarybchik		/* Request full buffer */
1058293901Sarybchik		req.emr_in_buf = bufferp;
1059293901Sarybchik		req.emr_in_length = MC_CMD_LICENSING_GET_ID_V3_IN_LEN;
1060293901Sarybchik		req.emr_out_buf = bufferp;
1061299898Sarybchik		req.emr_out_length = MIN(buffer_size, MC_CMD_LICENSING_GET_ID_V3_OUT_LENMAX);
1062293901Sarybchik		(void) memset(bufferp, 0, req.emr_out_length);
1063293901Sarybchik	}
1064293901Sarybchik
1065299923Sarybchik	efx_mcdi_execute_quiet(enp, &req);
1066293901Sarybchik
1067293901Sarybchik	if (req.emr_rc != 0) {
1068293901Sarybchik		rc = req.emr_rc;
1069293901Sarybchik		goto fail1;
1070293901Sarybchik	}
1071293901Sarybchik
1072293901Sarybchik	if (req.emr_out_length_used < MC_CMD_LICENSING_GET_ID_V3_OUT_LENMIN) {
1073293901Sarybchik		rc = EMSGSIZE;
1074293901Sarybchik		goto fail2;
1075293901Sarybchik	}
1076293901Sarybchik
1077293901Sarybchik	*typep = MCDI_OUT_DWORD(req, LICENSING_GET_ID_V3_OUT_LICENSE_TYPE);
1078293901Sarybchik	*lengthp = MCDI_OUT_DWORD(req, LICENSING_GET_ID_V3_OUT_LICENSE_ID_LENGTH);
1079293901Sarybchik
1080293901Sarybchik	if (bufferp == NULL) {
1081293901Sarybchik		/* modify length requirements to indicate to caller the extra buffering
1082293901Sarybchik		** needed to read the complete output.
1083293901Sarybchik		*/
1084293901Sarybchik		*lengthp += MC_CMD_LICENSING_GET_ID_V3_OUT_LENMIN;
1085293901Sarybchik	} else {
1086293901Sarybchik		/* Shift ID down to start of buffer */
1087293901Sarybchik		memmove(bufferp,
1088293901Sarybchik		  bufferp+MC_CMD_LICENSING_GET_ID_V3_OUT_LICENSE_ID_OFST,
1089293901Sarybchik		  *lengthp);
1090293901Sarybchik		memset(bufferp+(*lengthp), 0, MC_CMD_LICENSING_GET_ID_V3_OUT_LICENSE_ID_OFST);
1091293901Sarybchik	}
1092293901Sarybchik
1093293901Sarybchik	return (0);
1094293901Sarybchik
1095293901Sarybchikfail2:
1096293901Sarybchik	EFSYS_PROBE(fail2);
1097293901Sarybchikfail1:
1098293901Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1099293901Sarybchik
1100293901Sarybchik	return (rc);
1101293901Sarybchik}
1102293901Sarybchik
1103299898Sarybchik/* V3 format uses Huntington TLV format partition. See SF-108797-SW */
1104299898Sarybchik#define EFX_LICENSE_V3_KEY_LENGTH_MIN    (64)
1105299907Sarybchik#define EFX_LICENSE_V3_KEY_LENGTH_MAX    (160)
1106293901Sarybchik
1107299898Sarybchik	__checkReturn		efx_rc_t
1108299898Sarybchikefx_lic_v3_find_start(
1109299898Sarybchik	__in			efx_nic_t *enp,
1110299898Sarybchik	__in_bcount(buffer_size)
1111299898Sarybchik				caddr_t bufferp,
1112299898Sarybchik	__in			size_t buffer_size,
1113299898Sarybchik	__out			uint32_t *startp
1114299898Sarybchik	)
1115299898Sarybchik{
1116299898Sarybchik	_NOTE(ARGUNUSED(enp))
1117299898Sarybchik
1118299898Sarybchik	return ef10_nvram_buffer_find_item_start(bufferp, buffer_size, startp);
1119299898Sarybchik}
1120299898Sarybchik
1121299898Sarybchik	__checkReturn		efx_rc_t
1122299898Sarybchikefx_lic_v3_find_end(
1123299898Sarybchik	__in			efx_nic_t *enp,
1124299898Sarybchik	__in_bcount(buffer_size)
1125299898Sarybchik				caddr_t bufferp,
1126299898Sarybchik	__in			size_t buffer_size,
1127299898Sarybchik	__in			uint32_t offset,
1128299898Sarybchik	__out			uint32_t *endp
1129299898Sarybchik	)
1130299898Sarybchik{
1131299898Sarybchik	_NOTE(ARGUNUSED(enp))
1132299898Sarybchik
1133299898Sarybchik	return ef10_nvram_buffer_find_end(bufferp, buffer_size, offset, endp);
1134299898Sarybchik}
1135299898Sarybchik
1136299898Sarybchik	__checkReturn	__success(return != B_FALSE)	boolean_t
1137299898Sarybchikefx_lic_v3_find_key(
1138299898Sarybchik	__in			efx_nic_t *enp,
1139299898Sarybchik	__in_bcount(buffer_size)
1140299898Sarybchik				caddr_t bufferp,
1141299898Sarybchik	__in			size_t buffer_size,
1142299898Sarybchik	__in			uint32_t offset,
1143299898Sarybchik	__out			uint32_t *startp,
1144299898Sarybchik	__out			uint32_t *lengthp
1145299898Sarybchik	)
1146299898Sarybchik{
1147299898Sarybchik	_NOTE(ARGUNUSED(enp))
1148299898Sarybchik
1149299898Sarybchik	return ef10_nvram_buffer_find_item(bufferp, buffer_size,
1150299898Sarybchik	    offset, startp, lengthp);
1151299898Sarybchik}
1152299898Sarybchik
1153299898Sarybchik	__checkReturn	__success(return != B_FALSE)	boolean_t
1154299898Sarybchikefx_lic_v3_validate_key(
1155299898Sarybchik	__in			efx_nic_t *enp,
1156299898Sarybchik	__in_bcount(length)	caddr_t keyp,
1157299898Sarybchik	__in			uint32_t length
1158299898Sarybchik	)
1159299898Sarybchik{
1160299898Sarybchik	// Check key is a valid V3 key
1161299898Sarybchik	efx_rc_t rc;
1162299898Sarybchik	uint8_t key_type;
1163299898Sarybchik	uint8_t key_length;
1164299898Sarybchik
1165299898Sarybchik	_NOTE(ARGUNUSED(enp))
1166299898Sarybchik
1167299898Sarybchik	if (length < EFX_LICENSE_V3_KEY_LENGTH_MIN) {
1168299898Sarybchik		goto fail1;
1169299898Sarybchik	}
1170299898Sarybchik
1171299911Sarybchik	if (length > EFX_LICENSE_V3_KEY_LENGTH_MAX) {
1172299911Sarybchik		goto fail2;
1173299911Sarybchik	}
1174299911Sarybchik
1175299898Sarybchik	key_type = ((uint8_t*)keyp)[0];
1176299911Sarybchik	key_length = ((uint8_t*)keyp)[1];
1177299898Sarybchik
1178299898Sarybchik	if (key_type < 3) {
1179299898Sarybchik		goto fail3;
1180299898Sarybchik	}
1181299911Sarybchik	if (key_length > length) {
1182299898Sarybchik		goto fail4;
1183299898Sarybchik	}
1184299898Sarybchik	return (B_TRUE);
1185299898Sarybchik
1186299898Sarybchikfail4:
1187299898Sarybchik	EFSYS_PROBE(fail4);
1188299898Sarybchikfail3:
1189299898Sarybchik	EFSYS_PROBE(fail3);
1190299898Sarybchikfail2:
1191299898Sarybchik	EFSYS_PROBE(fail2);
1192299898Sarybchikfail1:
1193299898Sarybchik	EFSYS_PROBE(fail1);
1194299898Sarybchik
1195299898Sarybchik	return (B_FALSE);
1196299898Sarybchik}
1197299898Sarybchik
1198299898Sarybchik	__checkReturn		efx_rc_t
1199299898Sarybchikefx_lic_v3_read_key(
1200299898Sarybchik	__in			efx_nic_t *enp,
1201299898Sarybchik	__in_bcount(buffer_size)
1202299898Sarybchik				caddr_t bufferp,
1203299898Sarybchik	__in			size_t buffer_size,
1204299898Sarybchik	__in			uint32_t offset,
1205299898Sarybchik	__in			uint32_t length,
1206299898Sarybchik	__out_bcount_part(key_max_size, *lengthp)
1207299898Sarybchik				caddr_t keyp,
1208299898Sarybchik	__in			size_t key_max_size,
1209299898Sarybchik	__out			uint32_t *lengthp
1210299898Sarybchik	)
1211299898Sarybchik{
1212299898Sarybchik	_NOTE(ARGUNUSED(enp))
1213299898Sarybchik
1214299898Sarybchik	return ef10_nvram_buffer_get_item(bufferp, buffer_size,
1215299898Sarybchik		    offset, length, keyp, key_max_size, lengthp);
1216299898Sarybchik}
1217299898Sarybchik
1218299898Sarybchik	__checkReturn		efx_rc_t
1219299898Sarybchikefx_lic_v3_write_key(
1220299898Sarybchik	__in			efx_nic_t *enp,
1221299898Sarybchik	__in_bcount(buffer_size)
1222299898Sarybchik				caddr_t bufferp,
1223299898Sarybchik	__in			size_t buffer_size,
1224299898Sarybchik	__in			uint32_t offset,
1225299898Sarybchik	__in_bcount(length)	caddr_t keyp,
1226299898Sarybchik	__in			uint32_t length,
1227299898Sarybchik	__out			uint32_t *lengthp
1228299898Sarybchik	)
1229299898Sarybchik{
1230299898Sarybchik	_NOTE(ARGUNUSED(enp))
1231299898Sarybchik	EFSYS_ASSERT(length <= EFX_LICENSE_V3_KEY_LENGTH_MAX);
1232299898Sarybchik
1233299898Sarybchik	return ef10_nvram_buffer_insert_item(bufferp, buffer_size,
1234299898Sarybchik		    offset, keyp, length, lengthp);
1235299898Sarybchik}
1236299898Sarybchik
1237299898Sarybchik	__checkReturn		efx_rc_t
1238299898Sarybchikefx_lic_v3_delete_key(
1239299898Sarybchik	__in			efx_nic_t *enp,
1240299898Sarybchik	__in_bcount(buffer_size)
1241299898Sarybchik				caddr_t bufferp,
1242299898Sarybchik	__in			size_t buffer_size,
1243299898Sarybchik	__in			uint32_t offset,
1244299898Sarybchik	__in			uint32_t length,
1245299898Sarybchik	__in			uint32_t end,
1246299898Sarybchik	__out			uint32_t *deltap
1247299898Sarybchik	)
1248299898Sarybchik{
1249299898Sarybchik	efx_rc_t rc;
1250299898Sarybchik
1251299898Sarybchik	_NOTE(ARGUNUSED(enp))
1252299898Sarybchik
1253299898Sarybchik	if ((rc = ef10_nvram_buffer_delete_item(bufferp,
1254299898Sarybchik			buffer_size, offset, length, end)) != 0) {
1255299898Sarybchik		goto fail1;
1256299898Sarybchik	}
1257299898Sarybchik
1258299898Sarybchik	*deltap = length;
1259299898Sarybchik
1260299898Sarybchik	return (0);
1261299898Sarybchik
1262299898Sarybchikfail1:
1263299898Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1264299898Sarybchik
1265299898Sarybchik	return (rc);
1266299898Sarybchik}
1267299898Sarybchik
1268299898Sarybchik	__checkReturn		efx_rc_t
1269299898Sarybchikefx_lic_v3_create_partition(
1270299898Sarybchik	__in			efx_nic_t *enp,
1271299898Sarybchik	__in_bcount(buffer_size)
1272299898Sarybchik				caddr_t bufferp,
1273299898Sarybchik	__in			size_t buffer_size
1274299898Sarybchik	)
1275299898Sarybchik{
1276299898Sarybchik	efx_rc_t rc;
1277299898Sarybchik
1278299898Sarybchik	// Construct empty partition
1279299898Sarybchik	if ((rc = ef10_nvram_buffer_create(enp,
1280299898Sarybchik	    NVRAM_PARTITION_TYPE_LICENSE,
1281299898Sarybchik	    bufferp, buffer_size)) != 0) {
1282299898Sarybchik		rc = EFAULT;
1283299898Sarybchik		goto fail1;
1284299898Sarybchik	}
1285299898Sarybchik
1286299898Sarybchik	return (0);
1287299898Sarybchik
1288299898Sarybchikfail1:
1289299898Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1290299898Sarybchik
1291299898Sarybchik	return (rc);
1292299898Sarybchik}
1293299898Sarybchik
1294299898Sarybchik	__checkReturn		efx_rc_t
1295299898Sarybchikefx_lic_v3_finish_partition(
1296299898Sarybchik	__in			efx_nic_t *enp,
1297299898Sarybchik	__in_bcount(buffer_size)
1298299898Sarybchik				caddr_t bufferp,
1299299898Sarybchik	__in			size_t buffer_size
1300299898Sarybchik	)
1301299898Sarybchik{
1302299898Sarybchik	efx_rc_t rc;
1303299898Sarybchik
1304299898Sarybchik	if ((rc = ef10_nvram_buffer_finish(bufferp,
1305299898Sarybchik			buffer_size)) != 0) {
1306299898Sarybchik		goto fail1;
1307299898Sarybchik	}
1308299898Sarybchik
1309299898Sarybchik	// Validate completed partition
1310299898Sarybchik	if ((rc = ef10_nvram_buffer_validate(enp, NVRAM_PARTITION_TYPE_LICENSE,
1311299898Sarybchik					bufferp, buffer_size)) != 0) {
1312299898Sarybchik		goto fail2;
1313299898Sarybchik	}
1314299898Sarybchik
1315299898Sarybchik	return (0);
1316299898Sarybchik
1317299898Sarybchikfail2:
1318299898Sarybchik	EFSYS_PROBE(fail2);
1319299898Sarybchikfail1:
1320299898Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1321299898Sarybchik
1322299898Sarybchik	return (rc);
1323299898Sarybchik}
1324299898Sarybchik
1325299898Sarybchik
1326293901Sarybchik#endif	/* EFSYS_OPT_MEDFORD */
1327293901Sarybchik
1328293901Sarybchik	__checkReturn		efx_rc_t
1329293901Sarybchikefx_lic_init(
1330293901Sarybchik	__in			efx_nic_t *enp)
1331293901Sarybchik{
1332299517Sarybchik	const efx_lic_ops_t *elop;
1333293901Sarybchik	efx_rc_t rc;
1334293901Sarybchik
1335293901Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1336293901Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
1337293901Sarybchik	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_LIC));
1338293901Sarybchik
1339293901Sarybchik	switch (enp->en_family) {
1340293901Sarybchik
1341293901Sarybchik#if EFSYS_OPT_SIENA
1342293901Sarybchik	case EFX_FAMILY_SIENA:
1343299517Sarybchik		elop = &__efx_lic_v1_ops;
1344293901Sarybchik		break;
1345293901Sarybchik#endif	/* EFSYS_OPT_SIENA */
1346293901Sarybchik
1347293901Sarybchik#if EFSYS_OPT_HUNTINGTON
1348293901Sarybchik	case EFX_FAMILY_HUNTINGTON:
1349299517Sarybchik		elop = &__efx_lic_v2_ops;
1350293901Sarybchik		break;
1351293901Sarybchik#endif	/* EFSYS_OPT_HUNTINGTON */
1352293901Sarybchik
1353293901Sarybchik#if EFSYS_OPT_MEDFORD
1354293901Sarybchik	case EFX_FAMILY_MEDFORD:
1355299517Sarybchik		elop = &__efx_lic_v3_ops;
1356293901Sarybchik		break;
1357293901Sarybchik#endif	/* EFSYS_OPT_MEDFORD */
1358293901Sarybchik
1359293901Sarybchik	default:
1360293901Sarybchik		EFSYS_ASSERT(0);
1361293901Sarybchik		rc = ENOTSUP;
1362293901Sarybchik		goto fail1;
1363293901Sarybchik	}
1364293901Sarybchik
1365293901Sarybchik	enp->en_elop = elop;
1366293901Sarybchik	enp->en_mod_flags |= EFX_MOD_LIC;
1367293901Sarybchik
1368293901Sarybchik	return (0);
1369293901Sarybchik
1370293901Sarybchikfail1:
1371293901Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1372293901Sarybchik
1373293901Sarybchik	return (rc);
1374293901Sarybchik}
1375293901Sarybchik
1376293901Sarybchik				void
1377293901Sarybchikefx_lic_fini(
1378293901Sarybchik	__in			efx_nic_t *enp)
1379293901Sarybchik{
1380299517Sarybchik	const efx_lic_ops_t *elop = enp->en_elop;
1381293901Sarybchik
1382293901Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1383293901Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
1384293901Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_LIC);
1385293901Sarybchik
1386293901Sarybchik	enp->en_elop = NULL;
1387293901Sarybchik	enp->en_mod_flags &= ~EFX_MOD_LIC;
1388293901Sarybchik}
1389293901Sarybchik
1390293901Sarybchik
1391293901Sarybchik	__checkReturn	efx_rc_t
1392293901Sarybchikefx_lic_update_licenses(
1393293901Sarybchik	__in		efx_nic_t *enp)
1394293901Sarybchik{
1395299517Sarybchik	const efx_lic_ops_t *elop = enp->en_elop;
1396293901Sarybchik	efx_rc_t rc;
1397293901Sarybchik
1398293901Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1399293901Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_LIC);
1400293901Sarybchik
1401293901Sarybchik	if ((rc = elop->elo_update_licenses(enp)) != 0)
1402293901Sarybchik		goto fail1;
1403293901Sarybchik
1404293901Sarybchik	return (0);
1405293901Sarybchik
1406293901Sarybchikfail1:
1407293901Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1408293901Sarybchik
1409293901Sarybchik	return (rc);
1410293901Sarybchik}
1411293901Sarybchik
1412293901Sarybchik	__checkReturn	efx_rc_t
1413293901Sarybchikefx_lic_get_key_stats(
1414293901Sarybchik	__in		efx_nic_t *enp,
1415293901Sarybchik	__out		efx_key_stats_t *eksp)
1416293901Sarybchik{
1417299517Sarybchik	const efx_lic_ops_t *elop = enp->en_elop;
1418293901Sarybchik	efx_rc_t rc;
1419293901Sarybchik
1420293901Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1421293901Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_LIC);
1422293901Sarybchik
1423293901Sarybchik	if ((rc = elop->elo_get_key_stats(enp, eksp)) != 0)
1424293901Sarybchik		goto fail1;
1425293901Sarybchik
1426293901Sarybchik	return (0);
1427293901Sarybchik
1428293901Sarybchikfail1:
1429293901Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1430293901Sarybchik
1431293901Sarybchik	return (rc);
1432293901Sarybchik}
1433293901Sarybchik
1434293901Sarybchik	__checkReturn	efx_rc_t
1435293901Sarybchikefx_lic_app_state(
1436293901Sarybchik	__in		efx_nic_t *enp,
1437293901Sarybchik	__in		uint64_t app_id,
1438293901Sarybchik	__out		boolean_t *licensedp)
1439293901Sarybchik{
1440299517Sarybchik	const efx_lic_ops_t *elop = enp->en_elop;
1441293901Sarybchik	efx_rc_t rc;
1442293901Sarybchik
1443293901Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1444293901Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_LIC);
1445293901Sarybchik
1446299899Sarybchik	if (elop->elo_app_state == NULL)
1447299899Sarybchik		return (ENOTSUP);
1448299899Sarybchik
1449299899Sarybchik	if ((rc = elop->elo_app_state(enp, app_id, licensedp)) != 0)
1450293901Sarybchik		goto fail1;
1451293901Sarybchik
1452293901Sarybchik	return (0);
1453293901Sarybchik
1454293901Sarybchikfail1:
1455293901Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1456293901Sarybchik
1457293901Sarybchik	return (rc);
1458293901Sarybchik}
1459293901Sarybchik
1460293901Sarybchik	__checkReturn	efx_rc_t
1461293901Sarybchikefx_lic_get_id(
1462293901Sarybchik	__in		efx_nic_t *enp,
1463293901Sarybchik	__in		size_t buffer_size,
1464293901Sarybchik	__out		uint32_t *typep,
1465293901Sarybchik	__out		size_t *lengthp,
1466293901Sarybchik	__out_opt	uint8_t *bufferp
1467293901Sarybchik	)
1468293901Sarybchik{
1469299517Sarybchik	const efx_lic_ops_t *elop = enp->en_elop;
1470293901Sarybchik	efx_rc_t rc;
1471293901Sarybchik
1472293901Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1473293901Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_LIC);
1474293901Sarybchik
1475299899Sarybchik	if (elop->elo_get_id == NULL)
1476299899Sarybchik		return (ENOTSUP);
1477293901Sarybchik
1478293901Sarybchik	if ((rc = elop->elo_get_id(enp, buffer_size, typep,
1479293901Sarybchik				    lengthp, bufferp)) != 0)
1480299899Sarybchik		goto fail1;
1481293901Sarybchik
1482293901Sarybchik	return (0);
1483293901Sarybchik
1484293901Sarybchikfail1:
1485293901Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1486293901Sarybchik
1487293901Sarybchik	return (rc);
1488293901Sarybchik}
1489293901Sarybchik
1490299898Sarybchik/* Buffer management API - abstracts varying TLV format used for License partition */
1491299898Sarybchik
1492299898Sarybchik	__checkReturn		efx_rc_t
1493299898Sarybchikefx_lic_find_start(
1494299898Sarybchik	__in			efx_nic_t *enp,
1495299898Sarybchik	__in_bcount(buffer_size)
1496299898Sarybchik				caddr_t bufferp,
1497299898Sarybchik	__in			size_t buffer_size,
1498299898Sarybchik	__out			uint32_t *startp
1499299898Sarybchik	)
1500299898Sarybchik{
1501299898Sarybchik	const efx_lic_ops_t *elop = enp->en_elop;
1502299898Sarybchik	efx_rc_t rc;
1503299898Sarybchik
1504299898Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1505299898Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_LIC);
1506299898Sarybchik
1507299898Sarybchik	if ((rc = elop->elo_find_start(enp, bufferp, buffer_size, startp)) != 0)
1508299898Sarybchik		goto fail1;
1509299898Sarybchik
1510299898Sarybchik	return (0);
1511299898Sarybchik
1512299898Sarybchikfail1:
1513299898Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1514299898Sarybchik
1515299898Sarybchik	return (rc);
1516299898Sarybchik}
1517299898Sarybchik
1518299898Sarybchik	__checkReturn		efx_rc_t
1519299898Sarybchikefx_lic_find_end(
1520299898Sarybchik	__in			efx_nic_t *enp,
1521299898Sarybchik	__in_bcount(buffer_size)
1522299898Sarybchik				caddr_t bufferp,
1523299898Sarybchik	__in			size_t buffer_size,
1524299898Sarybchik	__in			uint32_t offset,
1525299898Sarybchik	__out			uint32_t *endp
1526299898Sarybchik	)
1527299898Sarybchik{
1528299898Sarybchik	const efx_lic_ops_t *elop = enp->en_elop;
1529299898Sarybchik	efx_rc_t rc;
1530299898Sarybchik
1531299898Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1532299898Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_LIC);
1533299898Sarybchik
1534299898Sarybchik	if ((rc = elop->elo_find_end(enp, bufferp, buffer_size, offset, endp)) != 0)
1535299898Sarybchik		goto fail1;
1536299898Sarybchik
1537299898Sarybchik	return (0);
1538299898Sarybchik
1539299898Sarybchikfail1:
1540299898Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1541299898Sarybchik
1542299898Sarybchik	return (rc);
1543299898Sarybchik}
1544299898Sarybchik
1545299898Sarybchik	__checkReturn	__success(return != B_FALSE)	boolean_t
1546299898Sarybchikefx_lic_find_key(
1547299898Sarybchik	__in			efx_nic_t *enp,
1548299898Sarybchik	__in_bcount(buffer_size)
1549299898Sarybchik				caddr_t bufferp,
1550299898Sarybchik	__in			size_t buffer_size,
1551299898Sarybchik	__in			uint32_t offset,
1552299898Sarybchik	__out			uint32_t *startp,
1553299898Sarybchik	__out			uint32_t *lengthp
1554299898Sarybchik	)
1555299898Sarybchik{
1556299898Sarybchik	const efx_lic_ops_t *elop = enp->en_elop;
1557299898Sarybchik	boolean_t rc;
1558299898Sarybchik
1559299898Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1560299898Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_LIC);
1561299898Sarybchik
1562299898Sarybchik	EFSYS_ASSERT(bufferp);
1563299898Sarybchik	EFSYS_ASSERT(startp);
1564299898Sarybchik	EFSYS_ASSERT(lengthp);
1565299898Sarybchik
1566299898Sarybchik	return (elop->elo_find_key(enp, bufferp, buffer_size, offset,
1567299898Sarybchik				    startp, lengthp));
1568299898Sarybchik}
1569299898Sarybchik
1570299898Sarybchik
1571299898Sarybchik/* Validate that the buffer contains a single key in a recognised format.
1572299898Sarybchik** An empty or terminator buffer is not accepted as a valid key.
1573299898Sarybchik*/
1574299898Sarybchik	__checkReturn	__success(return != B_FALSE)	boolean_t
1575299898Sarybchikefx_lic_validate_key(
1576299898Sarybchik	__in			efx_nic_t *enp,
1577299898Sarybchik	__in_bcount(length)	caddr_t keyp,
1578299898Sarybchik	__in			uint32_t length
1579299898Sarybchik	)
1580299898Sarybchik{
1581299898Sarybchik	const efx_lic_ops_t *elop = enp->en_elop;
1582299898Sarybchik	boolean_t rc;
1583299898Sarybchik	uint16_t tlv_type;
1584299898Sarybchik	uint16_t tlv_length;
1585299898Sarybchik
1586299898Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1587299898Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_LIC);
1588299898Sarybchik
1589299898Sarybchik	if ((rc = elop->elo_validate_key(enp, keyp, length)) == B_FALSE)
1590299898Sarybchik		goto fail1;
1591299898Sarybchik
1592299898Sarybchik	return (B_TRUE);
1593299898Sarybchik
1594299898Sarybchikfail1:
1595299898Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1596299898Sarybchik
1597299898Sarybchik	return (rc);
1598299898Sarybchik}
1599299898Sarybchik
1600299898Sarybchik	__checkReturn		efx_rc_t
1601299898Sarybchikefx_lic_read_key(
1602299898Sarybchik	__in			efx_nic_t *enp,
1603299898Sarybchik	__in_bcount(buffer_size)
1604299898Sarybchik				caddr_t bufferp,
1605299898Sarybchik	__in			size_t buffer_size,
1606299898Sarybchik	__in			uint32_t offset,
1607299898Sarybchik	__in			uint32_t length,
1608299898Sarybchik	__out_bcount_part(key_max_size, *lengthp)
1609299898Sarybchik				caddr_t keyp,
1610299898Sarybchik	__in			size_t key_max_size,
1611299898Sarybchik	__out			uint32_t *lengthp
1612299898Sarybchik	)
1613299898Sarybchik{
1614299898Sarybchik	const efx_lic_ops_t *elop = enp->en_elop;
1615299898Sarybchik	efx_rc_t rc;
1616299898Sarybchik
1617299898Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1618299898Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_LIC);
1619299898Sarybchik
1620299898Sarybchik	if ((rc = elop->elo_read_key(enp, bufferp, buffer_size, offset,
1621299898Sarybchik				    length, keyp, key_max_size, lengthp)) != 0)
1622299898Sarybchik		goto fail1;
1623299898Sarybchik
1624299898Sarybchik	return (0);
1625299898Sarybchik
1626299898Sarybchikfail1:
1627299898Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1628299898Sarybchik
1629299898Sarybchik	return (rc);
1630299898Sarybchik}
1631299898Sarybchik
1632299898Sarybchik	__checkReturn		efx_rc_t
1633299898Sarybchikefx_lic_write_key(
1634299898Sarybchik	__in			efx_nic_t *enp,
1635299898Sarybchik	__in_bcount(buffer_size)
1636299898Sarybchik				caddr_t bufferp,
1637299898Sarybchik	__in			size_t buffer_size,
1638299898Sarybchik	__in			uint32_t offset,
1639299898Sarybchik	__in_bcount(length)	caddr_t keyp,
1640299898Sarybchik	__in			uint32_t length,
1641299898Sarybchik	__out			uint32_t *lengthp
1642299898Sarybchik	)
1643299898Sarybchik{
1644299898Sarybchik	const efx_lic_ops_t *elop = enp->en_elop;
1645299898Sarybchik	efx_rc_t rc;
1646299898Sarybchik
1647299898Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1648299898Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_LIC);
1649299898Sarybchik
1650299898Sarybchik	if ((rc = elop->elo_write_key(enp, bufferp, buffer_size, offset,
1651299898Sarybchik				    keyp, length, lengthp)) != 0)
1652299898Sarybchik		goto fail1;
1653299898Sarybchik
1654299898Sarybchik	return (0);
1655299898Sarybchik
1656299898Sarybchikfail1:
1657299898Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1658299898Sarybchik
1659299898Sarybchik	return (rc);
1660299898Sarybchik}
1661299898Sarybchik
1662299898Sarybchik	__checkReturn		efx_rc_t
1663299898Sarybchikefx_lic_delete_key(
1664299898Sarybchik	__in			efx_nic_t *enp,
1665299898Sarybchik	__in_bcount(buffer_size)
1666299898Sarybchik				caddr_t bufferp,
1667299898Sarybchik	__in			size_t buffer_size,
1668299898Sarybchik	__in			uint32_t offset,
1669299898Sarybchik	__in			uint32_t length,
1670299898Sarybchik	__in			uint32_t end,
1671299898Sarybchik	__out			uint32_t *deltap
1672299898Sarybchik	)
1673299898Sarybchik{
1674299898Sarybchik	const efx_lic_ops_t *elop = enp->en_elop;
1675299898Sarybchik	efx_rc_t rc;
1676299898Sarybchik
1677299898Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1678299898Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_LIC);
1679299898Sarybchik
1680299898Sarybchik	if ((rc = elop->elo_delete_key(enp, bufferp, buffer_size, offset,
1681299898Sarybchik				    length, end, deltap)) != 0)
1682299898Sarybchik		goto fail1;
1683299898Sarybchik
1684299898Sarybchik	return (0);
1685299898Sarybchik
1686299898Sarybchikfail1:
1687299898Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1688299898Sarybchik
1689299898Sarybchik	return (rc);
1690299898Sarybchik}
1691299898Sarybchik
1692299898Sarybchik	__checkReturn		efx_rc_t
1693299898Sarybchikefx_lic_create_partition(
1694299898Sarybchik	__in			efx_nic_t *enp,
1695299898Sarybchik	__in_bcount(buffer_size)
1696299898Sarybchik				caddr_t bufferp,
1697299898Sarybchik	__in			size_t buffer_size
1698299898Sarybchik	)
1699299898Sarybchik{
1700299898Sarybchik	const efx_lic_ops_t *elop = enp->en_elop;
1701299898Sarybchik	efx_rc_t rc;
1702299898Sarybchik
1703299898Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1704299898Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_LIC);
1705299898Sarybchik
1706299898Sarybchik	if ((rc = elop->elo_create_partition(enp, bufferp, buffer_size)) != 0)
1707299898Sarybchik		goto fail1;
1708299898Sarybchik
1709299898Sarybchik	return (0);
1710299898Sarybchik
1711299898Sarybchikfail1:
1712299898Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1713299898Sarybchik
1714299898Sarybchik	return (rc);
1715299898Sarybchik}
1716299898Sarybchik
1717299898Sarybchik
1718299898Sarybchik	__checkReturn		efx_rc_t
1719299898Sarybchikefx_lic_finish_partition(
1720299898Sarybchik	__in			efx_nic_t *enp,
1721299898Sarybchik	__in_bcount(buffer_size)
1722299898Sarybchik				caddr_t bufferp,
1723299898Sarybchik	__in			size_t buffer_size
1724299898Sarybchik	)
1725299898Sarybchik{
1726299898Sarybchik	const efx_lic_ops_t *elop = enp->en_elop;
1727299898Sarybchik	efx_rc_t rc;
1728299898Sarybchik
1729299898Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1730299898Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_LIC);
1731299898Sarybchik
1732299898Sarybchik	if ((rc = elop->elo_finish_partition(enp, bufferp, buffer_size)) != 0)
1733299898Sarybchik		goto fail1;
1734299898Sarybchik
1735299898Sarybchik	return (0);
1736299898Sarybchik
1737299898Sarybchikfail1:
1738299898Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1739299898Sarybchik
1740299898Sarybchik	return (rc);
1741299898Sarybchik}
1742299898Sarybchik
1743293901Sarybchik#endif	/* EFSYS_OPT_LICENSING */
1744