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