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