1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2009-2016 Solarflare Communications Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright notice,
11  *    this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright notice,
13  *    this list of conditions and the following disclaimer in the documentation
14  *    and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
20  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * The views and conclusions contained in the software and documentation are
29  * those of the authors and should not be interpreted as representing official
30  * policies, either expressed or implied, of the FreeBSD Project.
31  */
32 
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD: stable/12/sys/dev/sfxge/common/efx_nvram.c 342344 2018-12-21 16:57:59Z arybchik $");
35 
36 #include "efx.h"
37 #include "efx_impl.h"
38 
39 #if EFSYS_OPT_NVRAM
40 
41 #if EFSYS_OPT_SIENA
42 
43 static const efx_nvram_ops_t	__efx_nvram_siena_ops = {
44 #if EFSYS_OPT_DIAG
45 	siena_nvram_test,		/* envo_test */
46 #endif	/* EFSYS_OPT_DIAG */
47 	siena_nvram_type_to_partn,	/* envo_type_to_partn */
48 	siena_nvram_partn_size,		/* envo_partn_size */
49 	siena_nvram_partn_rw_start,	/* envo_partn_rw_start */
50 	siena_nvram_partn_read,		/* envo_partn_read */
51 	siena_nvram_partn_erase,	/* envo_partn_erase */
52 	siena_nvram_partn_write,	/* envo_partn_write */
53 	siena_nvram_partn_rw_finish,	/* envo_partn_rw_finish */
54 	siena_nvram_partn_get_version,	/* envo_partn_get_version */
55 	siena_nvram_partn_set_version,	/* envo_partn_set_version */
56 	NULL,				/* envo_partn_validate */
57 };
58 
59 #endif	/* EFSYS_OPT_SIENA */
60 
61 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
62 
63 static const efx_nvram_ops_t	__efx_nvram_ef10_ops = {
64 #if EFSYS_OPT_DIAG
65 	ef10_nvram_test,		/* envo_test */
66 #endif	/* EFSYS_OPT_DIAG */
67 	ef10_nvram_type_to_partn,	/* envo_type_to_partn */
68 	ef10_nvram_partn_size,		/* envo_partn_size */
69 	ef10_nvram_partn_rw_start,	/* envo_partn_rw_start */
70 	ef10_nvram_partn_read,		/* envo_partn_read */
71 	ef10_nvram_partn_erase,		/* envo_partn_erase */
72 	ef10_nvram_partn_write,		/* envo_partn_write */
73 	ef10_nvram_partn_rw_finish,	/* envo_partn_rw_finish */
74 	ef10_nvram_partn_get_version,	/* envo_partn_get_version */
75 	ef10_nvram_partn_set_version,	/* envo_partn_set_version */
76 	ef10_nvram_buffer_validate,	/* envo_buffer_validate */
77 };
78 
79 #endif	/* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
80 
81 	__checkReturn	efx_rc_t
efx_nvram_init(__in efx_nic_t * enp)82 efx_nvram_init(
83 	__in		efx_nic_t *enp)
84 {
85 	const efx_nvram_ops_t *envop;
86 	efx_rc_t rc;
87 
88 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
89 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
90 	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NVRAM));
91 
92 	switch (enp->en_family) {
93 #if EFSYS_OPT_SIENA
94 	case EFX_FAMILY_SIENA:
95 		envop = &__efx_nvram_siena_ops;
96 		break;
97 #endif	/* EFSYS_OPT_SIENA */
98 
99 #if EFSYS_OPT_HUNTINGTON
100 	case EFX_FAMILY_HUNTINGTON:
101 		envop = &__efx_nvram_ef10_ops;
102 		break;
103 #endif	/* EFSYS_OPT_HUNTINGTON */
104 
105 #if EFSYS_OPT_MEDFORD
106 	case EFX_FAMILY_MEDFORD:
107 		envop = &__efx_nvram_ef10_ops;
108 		break;
109 #endif	/* EFSYS_OPT_MEDFORD */
110 
111 	default:
112 		EFSYS_ASSERT(0);
113 		rc = ENOTSUP;
114 		goto fail1;
115 	}
116 
117 	enp->en_envop = envop;
118 	enp->en_mod_flags |= EFX_MOD_NVRAM;
119 
120 	return (0);
121 
122 fail1:
123 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
124 
125 	return (rc);
126 }
127 
128 #if EFSYS_OPT_DIAG
129 
130 	__checkReturn		efx_rc_t
efx_nvram_test(__in efx_nic_t * enp)131 efx_nvram_test(
132 	__in			efx_nic_t *enp)
133 {
134 	const efx_nvram_ops_t *envop = enp->en_envop;
135 	efx_rc_t rc;
136 
137 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
138 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
139 
140 	if ((rc = envop->envo_test(enp)) != 0)
141 		goto fail1;
142 
143 	return (0);
144 
145 fail1:
146 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
147 
148 	return (rc);
149 }
150 
151 #endif	/* EFSYS_OPT_DIAG */
152 
153 	__checkReturn		efx_rc_t
efx_nvram_size(__in efx_nic_t * enp,__in efx_nvram_type_t type,__out size_t * sizep)154 efx_nvram_size(
155 	__in			efx_nic_t *enp,
156 	__in			efx_nvram_type_t type,
157 	__out			size_t *sizep)
158 {
159 	const efx_nvram_ops_t *envop = enp->en_envop;
160 	uint32_t partn;
161 	efx_rc_t rc;
162 
163 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
164 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
165 
166 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
167 
168 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
169 		goto fail1;
170 
171 	if ((rc = envop->envo_partn_size(enp, partn, sizep)) != 0)
172 		goto fail2;
173 
174 	return (0);
175 
176 fail2:
177 	EFSYS_PROBE(fail2);
178 fail1:
179 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
180 	*sizep = 0;
181 
182 	return (rc);
183 }
184 
185 	__checkReturn		efx_rc_t
186 efx_nvram_get_version(
187 	__in			efx_nic_t *enp,
188 	__in			efx_nvram_type_t type,
189 	__out			uint32_t *subtypep,
190 	__out_ecount(4)		uint16_t version[4])
191 {
192 	const efx_nvram_ops_t *envop = enp->en_envop;
193 	uint32_t partn;
194 	efx_rc_t rc;
195 
196 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
197 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
198 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
199 
200 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
201 
202 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
203 		goto fail1;
204 
205 	if ((rc = envop->envo_partn_get_version(enp, partn,
206 		    subtypep, version)) != 0)
207 		goto fail2;
208 
209 	return (0);
210 
211 fail2:
212 	EFSYS_PROBE(fail2);
213 fail1:
214 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
215 
216 	return (rc);
217 }
218 
219 	__checkReturn		efx_rc_t
efx_nvram_rw_start(__in efx_nic_t * enp,__in efx_nvram_type_t type,__out_opt size_t * chunk_sizep)220 efx_nvram_rw_start(
221 	__in			efx_nic_t *enp,
222 	__in			efx_nvram_type_t type,
223 	__out_opt		size_t *chunk_sizep)
224 {
225 	const efx_nvram_ops_t *envop = enp->en_envop;
226 	uint32_t partn;
227 	efx_rc_t rc;
228 
229 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
230 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
231 
232 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
233 	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
234 
235 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID);
236 
237 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
238 		goto fail1;
239 
240 	if ((rc = envop->envo_partn_rw_start(enp, partn, chunk_sizep)) != 0)
241 		goto fail2;
242 
243 	enp->en_nvram_locked = type;
244 
245 	return (0);
246 
247 fail2:
248 	EFSYS_PROBE(fail2);
249 fail1:
250 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
251 
252 	return (rc);
253 }
254 
255 	__checkReturn		efx_rc_t
efx_nvram_read_chunk(__in efx_nic_t * enp,__in efx_nvram_type_t type,__in unsigned int offset,__out_bcount (size)caddr_t data,__in size_t size)256 efx_nvram_read_chunk(
257 	__in			efx_nic_t *enp,
258 	__in			efx_nvram_type_t type,
259 	__in			unsigned int offset,
260 	__out_bcount(size)	caddr_t data,
261 	__in			size_t size)
262 {
263 	const efx_nvram_ops_t *envop = enp->en_envop;
264 	uint32_t partn;
265 	efx_rc_t rc;
266 
267 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
268 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
269 
270 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
271 	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
272 
273 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);
274 
275 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
276 		goto fail1;
277 
278 	if ((rc = envop->envo_partn_read(enp, partn, offset, data, size)) != 0)
279 		goto fail2;
280 
281 	return (0);
282 
283 fail2:
284 	EFSYS_PROBE(fail2);
285 fail1:
286 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
287 
288 	return (rc);
289 }
290 
291 	__checkReturn		efx_rc_t
efx_nvram_erase(__in efx_nic_t * enp,__in efx_nvram_type_t type)292 efx_nvram_erase(
293 	__in			efx_nic_t *enp,
294 	__in			efx_nvram_type_t type)
295 {
296 	const efx_nvram_ops_t *envop = enp->en_envop;
297 	unsigned int offset = 0;
298 	size_t size = 0;
299 	uint32_t partn;
300 	efx_rc_t rc;
301 
302 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
303 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
304 
305 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
306 	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
307 
308 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);
309 
310 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
311 		goto fail1;
312 
313 	if ((rc = envop->envo_partn_size(enp, partn, &size)) != 0)
314 		goto fail2;
315 
316 	if ((rc = envop->envo_partn_erase(enp, partn, offset, size)) != 0)
317 		goto fail3;
318 
319 	return (0);
320 
321 fail3:
322 	EFSYS_PROBE(fail3);
323 fail2:
324 	EFSYS_PROBE(fail2);
325 fail1:
326 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
327 
328 	return (rc);
329 }
330 
331 	__checkReturn		efx_rc_t
efx_nvram_write_chunk(__in efx_nic_t * enp,__in efx_nvram_type_t type,__in unsigned int offset,__in_bcount (size)caddr_t data,__in size_t size)332 efx_nvram_write_chunk(
333 	__in			efx_nic_t *enp,
334 	__in			efx_nvram_type_t type,
335 	__in			unsigned int offset,
336 	__in_bcount(size)	caddr_t data,
337 	__in			size_t size)
338 {
339 	const efx_nvram_ops_t *envop = enp->en_envop;
340 	uint32_t partn;
341 	efx_rc_t rc;
342 
343 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
344 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
345 
346 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
347 	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
348 
349 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);
350 
351 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
352 		goto fail1;
353 
354 	if ((rc = envop->envo_partn_write(enp, partn, offset, data, size)) != 0)
355 		goto fail2;
356 
357 	return (0);
358 
359 fail2:
360 	EFSYS_PROBE(fail2);
361 fail1:
362 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
363 
364 	return (rc);
365 }
366 
367 	__checkReturn		efx_rc_t
efx_nvram_rw_finish(__in efx_nic_t * enp,__in efx_nvram_type_t type)368 efx_nvram_rw_finish(
369 	__in			efx_nic_t *enp,
370 	__in			efx_nvram_type_t type)
371 {
372 	const efx_nvram_ops_t *envop = enp->en_envop;
373 	uint32_t partn;
374 	efx_rc_t rc;
375 
376 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
377 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
378 
379 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
380 	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
381 
382 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type);
383 
384 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
385 		goto fail1;
386 
387 	if ((rc = envop->envo_partn_rw_finish(enp, partn)) != 0)
388 		goto fail2;
389 
390 	enp->en_nvram_locked = EFX_NVRAM_INVALID;
391 
392 	return (0);
393 
394 fail2:
395 	EFSYS_PROBE(fail2);
396 	enp->en_nvram_locked = EFX_NVRAM_INVALID;
397 
398 fail1:
399 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
400 
401 	return (rc);
402 }
403 
404 	__checkReturn		efx_rc_t
405 efx_nvram_set_version(
406 	__in			efx_nic_t *enp,
407 	__in			efx_nvram_type_t type,
408 	__in_ecount(4)		uint16_t version[4])
409 {
410 	const efx_nvram_ops_t *envop = enp->en_envop;
411 	uint32_t partn;
412 	efx_rc_t rc;
413 
414 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
415 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
416 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
417 
418 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
419 
420 	/*
421 	 * The Siena implementation of envo_set_version() will attempt to
422 	 * acquire the NVRAM_UPDATE lock for the DYNAMIC_CONFIG sector.
423 	 * Therefore, you can't have already acquired the NVRAM_UPDATE lock.
424 	 */
425 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID);
426 
427 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
428 		goto fail1;
429 
430 	if ((rc = envop->envo_partn_set_version(enp, partn, version)) != 0)
431 		goto fail2;
432 
433 	return (0);
434 
435 fail2:
436 	EFSYS_PROBE(fail2);
437 fail1:
438 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
439 
440 	return (rc);
441 }
442 
443 /* Validate buffer contents (before writing to flash) */
444 	__checkReturn		efx_rc_t
efx_nvram_validate(__in efx_nic_t * enp,__in efx_nvram_type_t type,__in_bcount (partn_size)caddr_t partn_data,__in size_t partn_size)445 efx_nvram_validate(
446 	__in			efx_nic_t *enp,
447 	__in			efx_nvram_type_t type,
448 	__in_bcount(partn_size)	caddr_t partn_data,
449 	__in			size_t partn_size)
450 {
451 	const efx_nvram_ops_t *envop = enp->en_envop;
452 	uint32_t partn;
453 	efx_rc_t rc;
454 
455 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
456 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
457 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
458 
459 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
460 
461 
462 	if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0)
463 		goto fail1;
464 
465 	if (envop->envo_buffer_validate != NULL) {
466 		if ((rc = envop->envo_buffer_validate(enp, partn,
467 			    partn_data, partn_size)) != 0)
468 			goto fail2;
469 	}
470 
471 	return (0);
472 
473 fail2:
474 	EFSYS_PROBE(fail2);
475 fail1:
476 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
477 
478 	return (rc);
479 }
480 
481 
482 void
efx_nvram_fini(__in efx_nic_t * enp)483 efx_nvram_fini(
484 	__in		efx_nic_t *enp)
485 {
486 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
487 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
488 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM);
489 
490 	EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID);
491 
492 	enp->en_envop = NULL;
493 	enp->en_mod_flags &= ~EFX_MOD_NVRAM;
494 }
495 
496 #endif	/* EFSYS_OPT_NVRAM */
497 
498 #if EFSYS_OPT_NVRAM || EFSYS_OPT_VPD
499 
500 /*
501  * Internal MCDI request handling
502  */
503 
504 	__checkReturn		efx_rc_t
efx_mcdi_nvram_partitions(__in efx_nic_t * enp,__out_bcount (size)caddr_t data,__in size_t size,__out unsigned int * npartnp)505 efx_mcdi_nvram_partitions(
506 	__in			efx_nic_t *enp,
507 	__out_bcount(size)	caddr_t data,
508 	__in			size_t size,
509 	__out			unsigned int *npartnp)
510 {
511 	efx_mcdi_req_t req;
512 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_PARTITIONS_IN_LEN,
513 		MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX);
514 	unsigned int npartn;
515 	efx_rc_t rc;
516 
517 	req.emr_cmd = MC_CMD_NVRAM_PARTITIONS;
518 	req.emr_in_buf = payload;
519 	req.emr_in_length = MC_CMD_NVRAM_PARTITIONS_IN_LEN;
520 	req.emr_out_buf = payload;
521 	req.emr_out_length = MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX;
522 
523 	efx_mcdi_execute(enp, &req);
524 
525 	if (req.emr_rc != 0) {
526 		rc = req.emr_rc;
527 		goto fail1;
528 	}
529 
530 	if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LENMIN) {
531 		rc = EMSGSIZE;
532 		goto fail2;
533 	}
534 	npartn = MCDI_OUT_DWORD(req, NVRAM_PARTITIONS_OUT_NUM_PARTITIONS);
535 
536 	if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LEN(npartn)) {
537 		rc = ENOENT;
538 		goto fail3;
539 	}
540 
541 	if (size < npartn * sizeof (uint32_t)) {
542 		rc = ENOSPC;
543 		goto fail3;
544 	}
545 
546 	*npartnp = npartn;
547 
548 	memcpy(data,
549 	    MCDI_OUT2(req, uint32_t, NVRAM_PARTITIONS_OUT_TYPE_ID),
550 	    (npartn * sizeof (uint32_t)));
551 
552 	return (0);
553 
554 fail3:
555 	EFSYS_PROBE(fail3);
556 fail2:
557 	EFSYS_PROBE(fail2);
558 fail1:
559 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
560 
561 	return (rc);
562 }
563 
564 	__checkReturn		efx_rc_t
565 efx_mcdi_nvram_metadata(
566 	__in			efx_nic_t *enp,
567 	__in			uint32_t partn,
568 	__out			uint32_t *subtypep,
569 	__out_ecount(4)		uint16_t version[4],
570 	__out_bcount_opt(size)	char *descp,
571 	__in			size_t size)
572 {
573 	efx_mcdi_req_t req;
574 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_METADATA_IN_LEN,
575 		MC_CMD_NVRAM_METADATA_OUT_LENMAX);
576 	efx_rc_t rc;
577 
578 	req.emr_cmd = MC_CMD_NVRAM_METADATA;
579 	req.emr_in_buf = payload;
580 	req.emr_in_length = MC_CMD_NVRAM_METADATA_IN_LEN;
581 	req.emr_out_buf = payload;
582 	req.emr_out_length = MC_CMD_NVRAM_METADATA_OUT_LENMAX;
583 
584 	MCDI_IN_SET_DWORD(req, NVRAM_METADATA_IN_TYPE, partn);
585 
586 	efx_mcdi_execute(enp, &req);
587 
588 	if (req.emr_rc != 0) {
589 		rc = req.emr_rc;
590 		goto fail1;
591 	}
592 
593 	if (req.emr_out_length_used < MC_CMD_NVRAM_METADATA_OUT_LENMIN) {
594 		rc = EMSGSIZE;
595 		goto fail2;
596 	}
597 
598 	if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
599 		NVRAM_METADATA_OUT_SUBTYPE_VALID)) {
600 		*subtypep = MCDI_OUT_DWORD(req, NVRAM_METADATA_OUT_SUBTYPE);
601 	} else {
602 		*subtypep = 0;
603 	}
604 
605 	if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
606 		NVRAM_METADATA_OUT_VERSION_VALID)) {
607 		version[0] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_W);
608 		version[1] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_X);
609 		version[2] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Y);
610 		version[3] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Z);
611 	} else {
612 		version[0] = version[1] = version[2] = version[3] = 0;
613 	}
614 
615 	if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS,
616 		NVRAM_METADATA_OUT_DESCRIPTION_VALID)) {
617 		/* Return optional descrition string */
618 		if ((descp != NULL) && (size > 0)) {
619 			size_t desclen;
620 
621 			descp[0] = '\0';
622 			desclen = (req.emr_out_length_used
623 			    - MC_CMD_NVRAM_METADATA_OUT_LEN(0));
624 
625 			EFSYS_ASSERT3U(desclen, <=,
626 			    MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_MAXNUM);
627 
628 			if (size < desclen) {
629 				rc = ENOSPC;
630 				goto fail3;
631 			}
632 
633 			memcpy(descp, MCDI_OUT2(req, char,
634 				NVRAM_METADATA_OUT_DESCRIPTION),
635 			    desclen);
636 
637 			/* Ensure string is NUL terminated */
638 			descp[desclen] = '\0';
639 		}
640 	}
641 
642 	return (0);
643 
644 fail3:
645 	EFSYS_PROBE(fail3);
646 fail2:
647 	EFSYS_PROBE(fail2);
648 fail1:
649 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
650 
651 	return (rc);
652 }
653 
654 	__checkReturn		efx_rc_t
efx_mcdi_nvram_info(__in efx_nic_t * enp,__in uint32_t partn,__out_opt size_t * sizep,__out_opt uint32_t * addressp,__out_opt uint32_t * erase_sizep,__out_opt uint32_t * write_sizep)655 efx_mcdi_nvram_info(
656 	__in			efx_nic_t *enp,
657 	__in			uint32_t partn,
658 	__out_opt		size_t *sizep,
659 	__out_opt		uint32_t *addressp,
660 	__out_opt		uint32_t *erase_sizep,
661 	__out_opt		uint32_t *write_sizep)
662 {
663 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_INFO_IN_LEN,
664 		MC_CMD_NVRAM_INFO_V2_OUT_LEN);
665 	efx_mcdi_req_t req;
666 	efx_rc_t rc;
667 
668 	req.emr_cmd = MC_CMD_NVRAM_INFO;
669 	req.emr_in_buf = payload;
670 	req.emr_in_length = MC_CMD_NVRAM_INFO_IN_LEN;
671 	req.emr_out_buf = payload;
672 	req.emr_out_length = MC_CMD_NVRAM_INFO_V2_OUT_LEN;
673 
674 	MCDI_IN_SET_DWORD(req, NVRAM_INFO_IN_TYPE, partn);
675 
676 	efx_mcdi_execute_quiet(enp, &req);
677 
678 	if (req.emr_rc != 0) {
679 		rc = req.emr_rc;
680 		goto fail1;
681 	}
682 
683 	if (req.emr_out_length_used < MC_CMD_NVRAM_INFO_OUT_LEN) {
684 		rc = EMSGSIZE;
685 		goto fail2;
686 	}
687 
688 	if (sizep)
689 		*sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_SIZE);
690 
691 	if (addressp)
692 		*addressp = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_PHYSADDR);
693 
694 	if (erase_sizep)
695 		*erase_sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_ERASESIZE);
696 
697 	if (write_sizep) {
698 		*write_sizep =
699 			(req.emr_out_length_used <
700 			    MC_CMD_NVRAM_INFO_V2_OUT_LEN) ?
701 			0 : MCDI_OUT_DWORD(req, NVRAM_INFO_V2_OUT_WRITESIZE);
702 	}
703 
704 	return (0);
705 
706 fail2:
707 	EFSYS_PROBE(fail2);
708 fail1:
709 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
710 
711 	return (rc);
712 }
713 
714 /*
715  * MC_CMD_NVRAM_UPDATE_START_V2 must be used to support firmware-verified
716  * NVRAM updates. Older firmware will ignore the flags field in the request.
717  */
718 	__checkReturn		efx_rc_t
efx_mcdi_nvram_update_start(__in efx_nic_t * enp,__in uint32_t partn)719 efx_mcdi_nvram_update_start(
720 	__in			efx_nic_t *enp,
721 	__in			uint32_t partn)
722 {
723 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_UPDATE_START_V2_IN_LEN,
724 		MC_CMD_NVRAM_UPDATE_START_OUT_LEN);
725 	efx_mcdi_req_t req;
726 	efx_rc_t rc;
727 
728 	req.emr_cmd = MC_CMD_NVRAM_UPDATE_START;
729 	req.emr_in_buf = payload;
730 	req.emr_in_length = MC_CMD_NVRAM_UPDATE_START_V2_IN_LEN;
731 	req.emr_out_buf = payload;
732 	req.emr_out_length = MC_CMD_NVRAM_UPDATE_START_OUT_LEN;
733 
734 	MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_START_V2_IN_TYPE, partn);
735 
736 	MCDI_IN_POPULATE_DWORD_1(req, NVRAM_UPDATE_START_V2_IN_FLAGS,
737 	    NVRAM_UPDATE_START_V2_IN_FLAG_REPORT_VERIFY_RESULT, 1);
738 
739 	efx_mcdi_execute(enp, &req);
740 
741 	if (req.emr_rc != 0) {
742 		rc = req.emr_rc;
743 		goto fail1;
744 	}
745 
746 	return (0);
747 
748 fail1:
749 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
750 
751 	return (rc);
752 }
753 
754 	__checkReturn		efx_rc_t
efx_mcdi_nvram_read(__in efx_nic_t * enp,__in uint32_t partn,__in uint32_t offset,__out_bcount (size)caddr_t data,__in size_t size,__in uint32_t mode)755 efx_mcdi_nvram_read(
756 	__in			efx_nic_t *enp,
757 	__in			uint32_t partn,
758 	__in			uint32_t offset,
759 	__out_bcount(size)	caddr_t data,
760 	__in			size_t size,
761 	__in			uint32_t mode)
762 {
763 	efx_mcdi_req_t req;
764 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_READ_IN_V2_LEN,
765 		MC_CMD_NVRAM_READ_OUT_LENMAX);
766 	efx_rc_t rc;
767 
768 	if (size > MC_CMD_NVRAM_READ_OUT_LENMAX) {
769 		rc = EINVAL;
770 		goto fail1;
771 	}
772 
773 	req.emr_cmd = MC_CMD_NVRAM_READ;
774 	req.emr_in_buf = payload;
775 	req.emr_in_length = MC_CMD_NVRAM_READ_IN_V2_LEN;
776 	req.emr_out_buf = payload;
777 	req.emr_out_length = MC_CMD_NVRAM_READ_OUT_LENMAX;
778 
779 	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_TYPE, partn);
780 	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_OFFSET, offset);
781 	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_LENGTH, size);
782 	MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_MODE, mode);
783 
784 	efx_mcdi_execute(enp, &req);
785 
786 	if (req.emr_rc != 0) {
787 		rc = req.emr_rc;
788 		goto fail1;
789 	}
790 
791 	if (req.emr_out_length_used < MC_CMD_NVRAM_READ_OUT_LEN(size)) {
792 		rc = EMSGSIZE;
793 		goto fail2;
794 	}
795 
796 	memcpy(data,
797 	    MCDI_OUT2(req, uint8_t, NVRAM_READ_OUT_READ_BUFFER),
798 	    size);
799 
800 	return (0);
801 
802 fail2:
803 	EFSYS_PROBE(fail2);
804 fail1:
805 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
806 
807 	return (rc);
808 }
809 
810 	__checkReturn		efx_rc_t
efx_mcdi_nvram_erase(__in efx_nic_t * enp,__in uint32_t partn,__in uint32_t offset,__in size_t size)811 efx_mcdi_nvram_erase(
812 	__in			efx_nic_t *enp,
813 	__in			uint32_t partn,
814 	__in			uint32_t offset,
815 	__in			size_t size)
816 {
817 	efx_mcdi_req_t req;
818 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_ERASE_IN_LEN,
819 		MC_CMD_NVRAM_ERASE_OUT_LEN);
820 	efx_rc_t rc;
821 
822 	req.emr_cmd = MC_CMD_NVRAM_ERASE;
823 	req.emr_in_buf = payload;
824 	req.emr_in_length = MC_CMD_NVRAM_ERASE_IN_LEN;
825 	req.emr_out_buf = payload;
826 	req.emr_out_length = MC_CMD_NVRAM_ERASE_OUT_LEN;
827 
828 	MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_TYPE, partn);
829 	MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_OFFSET, offset);
830 	MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_LENGTH, size);
831 
832 	efx_mcdi_execute(enp, &req);
833 
834 	if (req.emr_rc != 0) {
835 		rc = req.emr_rc;
836 		goto fail1;
837 	}
838 
839 	return (0);
840 
841 fail1:
842 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
843 
844 	return (rc);
845 }
846 
847 /*
848  * The NVRAM_WRITE MCDI command is a V1 command and so is supported by both
849  * Sienna and EF10 based boards.  However EF10 based boards support the use
850  * of this command with payloads up to the maximum MCDI V2 payload length.
851  */
852 	__checkReturn		efx_rc_t
efx_mcdi_nvram_write(__in efx_nic_t * enp,__in uint32_t partn,__in uint32_t offset,__in_bcount (size)caddr_t data,__in size_t size)853 efx_mcdi_nvram_write(
854 	__in			efx_nic_t *enp,
855 	__in			uint32_t partn,
856 	__in			uint32_t offset,
857 	__in_bcount(size)	caddr_t data,
858 	__in			size_t size)
859 {
860 	efx_mcdi_req_t req;
861 	uint8_t *payload;
862 	efx_rc_t rc;
863 	size_t max_data_size;
864 	size_t payload_len = enp->en_nic_cfg.enc_mcdi_max_payload_length;
865 
866 	max_data_size = payload_len - MC_CMD_NVRAM_WRITE_IN_LEN(0);
867 	EFSYS_ASSERT3U(payload_len, >, 0);
868 	EFSYS_ASSERT3U(max_data_size, <, payload_len);
869 
870 	if (size > max_data_size) {
871 		rc = EINVAL;
872 		goto fail1;
873 	}
874 
875 	EFSYS_KMEM_ALLOC(enp->en_esip, payload_len, payload);
876 	if (payload == NULL) {
877 		rc = ENOMEM;
878 		goto fail2;
879 	}
880 
881 	(void) memset(payload, 0, payload_len);
882 	req.emr_cmd = MC_CMD_NVRAM_WRITE;
883 	req.emr_in_buf = payload;
884 	req.emr_in_length = MC_CMD_NVRAM_WRITE_IN_LEN(size);
885 	req.emr_out_buf = payload;
886 	req.emr_out_length = MC_CMD_NVRAM_WRITE_OUT_LEN;
887 
888 	MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_TYPE, partn);
889 	MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_OFFSET, offset);
890 	MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_LENGTH, size);
891 
892 	memcpy(MCDI_IN2(req, uint8_t, NVRAM_WRITE_IN_WRITE_BUFFER),
893 	    data, size);
894 
895 	efx_mcdi_execute(enp, &req);
896 
897 	if (req.emr_rc != 0) {
898 		rc = req.emr_rc;
899 		goto fail3;
900 	}
901 
902 	EFSYS_KMEM_FREE(enp->en_esip, payload_len, payload);
903 
904 	return (0);
905 
906 fail3:
907 	EFSYS_PROBE(fail3);
908 	EFSYS_KMEM_FREE(enp->en_esip, payload_len, payload);
909 fail2:
910 	EFSYS_PROBE(fail2);
911 fail1:
912 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
913 
914 	return (rc);
915 }
916 
917 
918 /*
919  * MC_CMD_NVRAM_UPDATE_FINISH_V2 must be used to support firmware-verified
920  * NVRAM updates. Older firmware will ignore the flags field in the request.
921  */
922 	__checkReturn		efx_rc_t
efx_mcdi_nvram_update_finish(__in efx_nic_t * enp,__in uint32_t partn,__in boolean_t reboot,__out_opt uint32_t * resultp)923 efx_mcdi_nvram_update_finish(
924 	__in			efx_nic_t *enp,
925 	__in			uint32_t partn,
926 	__in			boolean_t reboot,
927 	__out_opt		uint32_t *resultp)
928 {
929 	const efx_nic_cfg_t *encp = &enp->en_nic_cfg;
930 	efx_mcdi_req_t req;
931 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_UPDATE_FINISH_V2_IN_LEN,
932 		MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN);
933 	uint32_t result = MC_CMD_NVRAM_VERIFY_RC_UNKNOWN;
934 	efx_rc_t rc;
935 
936 	req.emr_cmd = MC_CMD_NVRAM_UPDATE_FINISH;
937 	req.emr_in_buf = payload;
938 	req.emr_in_length = MC_CMD_NVRAM_UPDATE_FINISH_V2_IN_LEN;
939 	req.emr_out_buf = payload;
940 	req.emr_out_length = MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN;
941 
942 	MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_V2_IN_TYPE, partn);
943 	MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_V2_IN_REBOOT, reboot);
944 
945 	MCDI_IN_POPULATE_DWORD_1(req, NVRAM_UPDATE_FINISH_V2_IN_FLAGS,
946 	    NVRAM_UPDATE_FINISH_V2_IN_FLAG_REPORT_VERIFY_RESULT, 1);
947 
948 	efx_mcdi_execute(enp, &req);
949 
950 	if (req.emr_rc != 0) {
951 		rc = req.emr_rc;
952 		goto fail1;
953 	}
954 
955 	if (encp->enc_fw_verified_nvram_update_required == B_FALSE) {
956 		/* Report success if verified updates are not supported. */
957 		result = MC_CMD_NVRAM_VERIFY_RC_SUCCESS;
958 	} else {
959 		/* Firmware-verified NVRAM updates are required */
960 		if (req.emr_out_length_used <
961 		    MC_CMD_NVRAM_UPDATE_FINISH_V2_OUT_LEN) {
962 			rc = EMSGSIZE;
963 			goto fail2;
964 		}
965 		result =
966 		    MCDI_OUT_DWORD(req, NVRAM_UPDATE_FINISH_V2_OUT_RESULT_CODE);
967 
968 		if (result != MC_CMD_NVRAM_VERIFY_RC_SUCCESS) {
969 			/* Mandatory verification failed */
970 			rc = EINVAL;
971 			goto fail3;
972 		}
973 	}
974 
975 	if (resultp != NULL)
976 		*resultp = result;
977 
978 	return (0);
979 
980 fail3:
981 	EFSYS_PROBE(fail3);
982 fail2:
983 	EFSYS_PROBE(fail2);
984 fail1:
985 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
986 
987 	/* Always report verification result */
988 	if (resultp != NULL)
989 		*resultp = result;
990 
991 	return (rc);
992 }
993 
994 #if EFSYS_OPT_DIAG
995 
996 	__checkReturn		efx_rc_t
efx_mcdi_nvram_test(__in efx_nic_t * enp,__in uint32_t partn)997 efx_mcdi_nvram_test(
998 	__in			efx_nic_t *enp,
999 	__in			uint32_t partn)
1000 {
1001 	efx_mcdi_req_t req;
1002 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_TEST_IN_LEN,
1003 		MC_CMD_NVRAM_TEST_OUT_LEN);
1004 	int result;
1005 	efx_rc_t rc;
1006 
1007 	req.emr_cmd = MC_CMD_NVRAM_TEST;
1008 	req.emr_in_buf = payload;
1009 	req.emr_in_length = MC_CMD_NVRAM_TEST_IN_LEN;
1010 	req.emr_out_buf = payload;
1011 	req.emr_out_length = MC_CMD_NVRAM_TEST_OUT_LEN;
1012 
1013 	MCDI_IN_SET_DWORD(req, NVRAM_TEST_IN_TYPE, partn);
1014 
1015 	efx_mcdi_execute(enp, &req);
1016 
1017 	if (req.emr_rc != 0) {
1018 		rc = req.emr_rc;
1019 		goto fail1;
1020 	}
1021 
1022 	if (req.emr_out_length_used < MC_CMD_NVRAM_TEST_OUT_LEN) {
1023 		rc = EMSGSIZE;
1024 		goto fail2;
1025 	}
1026 
1027 	result = MCDI_OUT_DWORD(req, NVRAM_TEST_OUT_RESULT);
1028 	if (result == MC_CMD_NVRAM_TEST_FAIL) {
1029 
1030 		EFSYS_PROBE1(nvram_test_failure, int, partn);
1031 
1032 		rc = (EINVAL);
1033 		goto fail3;
1034 	}
1035 
1036 	return (0);
1037 
1038 fail3:
1039 	EFSYS_PROBE(fail3);
1040 fail2:
1041 	EFSYS_PROBE(fail2);
1042 fail1:
1043 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1044 
1045 	return (rc);
1046 }
1047 
1048 #endif	/* EFSYS_OPT_DIAG */
1049 
1050 
1051 #endif /* EFSYS_OPT_NVRAM || EFSYS_OPT_VPD */
1052