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