Deleted Added
sdiff udiff text old ( 228078 ) new ( 278839 )
full compact
1/*-
2 * Copyright 2009 Solarflare Communications Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26#include <sys/cdefs.h>
27__FBSDID("$FreeBSD: head/sys/dev/sfxge/common/siena_vpd.c 278839 2015-02-16 06:12:04Z arybchik $");
28
29#include "efsys.h"
30#include "efx.h"
31#include "efx_types.h"
32#include "efx_regs.h"
33#include "efx_impl.h"
34
35#if EFSYS_OPT_VPD
36
37#if EFSYS_OPT_SIENA
38
39static __checkReturn int
40siena_vpd_get_static(
41 __in efx_nic_t *enp,
42 __in unsigned int partn,
43 __deref_out_bcount_opt(*sizep) caddr_t *svpdp,
44 __out size_t *sizep)
45{
46 siena_mc_static_config_hdr_t *scfg;
47 caddr_t svpd;
48 size_t size;
49 uint8_t cksum;
50 unsigned int vpd_offset;
51 unsigned int vpd_length;
52 unsigned int hdr_length;
53 unsigned int pos;
54 unsigned int region;
55 int rc;
56
57 EFSYS_ASSERT(partn == MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT0 ||
58 partn == MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT1);
59
60 /* Allocate sufficient memory for the entire static cfg area */
61 if ((rc = siena_nvram_partn_size(enp, partn, &size)) != 0)
62 goto fail1;
63
64 EFSYS_KMEM_ALLOC(enp->en_esip, size, scfg);
65 if (scfg == NULL) {
66 rc = ENOMEM;
67 goto fail2;
68 }
69
70 if ((rc = siena_nvram_partn_read(enp, partn, 0,
71 (caddr_t)scfg, SIENA_NVRAM_CHUNK)) != 0)
72 goto fail3;
73
74 /* Verify the magic number */
75 if (EFX_DWORD_FIELD(scfg->magic, EFX_DWORD_0) !=
76 SIENA_MC_STATIC_CONFIG_MAGIC) {
77 rc = EINVAL;
78 goto fail4;
79 }
80
81 /* All future versions of the structure must be backwards compatable */
82 EFX_STATIC_ASSERT(SIENA_MC_STATIC_CONFIG_VERSION == 0);
83
84 hdr_length = EFX_WORD_FIELD(scfg->length, EFX_WORD_0);
85 vpd_offset = EFX_DWORD_FIELD(scfg->static_vpd_offset, EFX_DWORD_0);
86 vpd_length = EFX_DWORD_FIELD(scfg->static_vpd_length, EFX_DWORD_0);
87
88 /* Verify the hdr doesn't overflow the sector size */
89 if (hdr_length > size || vpd_offset > size || vpd_length > size ||
90 vpd_length + vpd_offset > size) {
91 rc = EINVAL;
92 goto fail5;
93 }
94
95 /* Read the remainder of scfg + static vpd */
96 region = vpd_offset + vpd_length;
97 if (region > SIENA_NVRAM_CHUNK) {
98 if ((rc = siena_nvram_partn_read(enp, partn, SIENA_NVRAM_CHUNK,
99 (caddr_t)scfg + SIENA_NVRAM_CHUNK,
100 region - SIENA_NVRAM_CHUNK)) != 0)
101 goto fail6;
102 }
103
104 /* Verify checksum */
105 cksum = 0;
106 for (pos = 0; pos < hdr_length; pos++)
107 cksum += ((uint8_t *)scfg)[pos];
108 if (cksum != 0) {
109 rc = EINVAL;
110 goto fail7;
111 }
112
113 if (vpd_length == 0)
114 svpd = NULL;
115 else {
116 /* Copy the vpd data out */
117 EFSYS_KMEM_ALLOC(enp->en_esip, vpd_length, svpd);
118 if (svpd == NULL) {
119 rc = ENOMEM;
120 goto fail8;
121 }
122 memcpy(svpd, (caddr_t)scfg + vpd_offset, vpd_length);
123 }
124
125 EFSYS_KMEM_FREE(enp->en_esip, size, scfg);
126
127 *svpdp = svpd;
128 *sizep = vpd_length;
129
130 return (0);
131
132fail8:
133 EFSYS_PROBE(fail8);
134fail7:
135 EFSYS_PROBE(fail7);
136fail6:
137 EFSYS_PROBE(fail6);
138fail5:
139 EFSYS_PROBE(fail5);
140fail4:
141 EFSYS_PROBE(fail4);
142fail3:
143 EFSYS_PROBE(fail3);
144fail2:
145 EFSYS_PROBE(fail2);
146
147 EFSYS_KMEM_FREE(enp->en_esip, size, scfg);
148
149fail1:
150 EFSYS_PROBE1(fail1, int, rc);
151
152 return (rc);
153}
154
155 __checkReturn int
156siena_vpd_init(
157 __in efx_nic_t *enp)
158{
159 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
160 caddr_t svpd = NULL;
161 unsigned partn;
162 size_t size = 0;
163 int rc;
164
165 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
166
167 partn = (emip->emi_port == 1)
168 ? MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT0
169 : MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT1;
170
171 /*
172 * We need the static VPD sector to present a unified static+dynamic
173 * VPD, that is, basically on every read, write, verify cycle. Since
174 * it should *never* change we can just cache it here.
175 */
176 if ((rc = siena_vpd_get_static(enp, partn, &svpd, &size)) != 0)
177 goto fail1;
178
179 if (svpd != NULL && size > 0) {
180 if ((rc = efx_vpd_hunk_verify(svpd, size, NULL)) != 0)
181 goto fail2;
182 }
183
184 enp->en_u.siena.enu_svpd = svpd;
185 enp->en_u.siena.enu_svpd_length = size;
186
187 return (0);
188
189fail2:
190 EFSYS_PROBE(fail2);
191
192 EFSYS_KMEM_FREE(enp->en_esip, size, svpd);
193fail1:
194 EFSYS_PROBE1(fail1, int, rc);
195
196 return (rc);
197}
198
199 __checkReturn int
200siena_vpd_size(
201 __in efx_nic_t *enp,
202 __out size_t *sizep)
203{
204 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
205 unsigned int partn;
206 int rc;
207
208 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
209
210 /*
211 * This function returns the total size the user should allocate
212 * for all VPD operations. We've already cached the static vpd,
213 * so we just need to return an upper bound on the dynamic vpd.
214 * Since the dynamic_config structure can change under our feet,
215 * (as version numbers are inserted), just be safe and return the
216 * total size of the dynamic_config *sector*
217 */
218 partn = (emip->emi_port == 1)
219 ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0
220 : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1;
221
222 if ((rc = siena_nvram_partn_size(enp, partn, sizep)) != 0)
223 goto fail1;
224
225 return (0);
226
227fail1:
228 EFSYS_PROBE1(fail1, int, rc);
229
230 return (rc);
231}
232
233 __checkReturn int
234siena_vpd_read(
235 __in efx_nic_t *enp,
236 __out_bcount(size) caddr_t data,
237 __in size_t size)
238{
239 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
240 siena_mc_dynamic_config_hdr_t *dcfg;
241 unsigned int vpd_length;
242 unsigned int vpd_offset;
243 unsigned int dcfg_partn;
244 size_t dcfg_size;
245 int rc;
246
247 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
248
249 dcfg_partn = (emip->emi_port == 1)
250 ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0
251 : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1;
252
253 if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn,
254 B_TRUE, &dcfg, &dcfg_size)) != 0)
255 goto fail1;
256
257 vpd_length = EFX_DWORD_FIELD(dcfg->dynamic_vpd_length, EFX_DWORD_0);
258 vpd_offset = EFX_DWORD_FIELD(dcfg->dynamic_vpd_offset, EFX_DWORD_0);
259
260 if (vpd_length > size) {
261 rc = EFAULT; /* Invalid dcfg: header bigger than sector */
262 goto fail2;
263 }
264
265 EFSYS_ASSERT3U(vpd_length, <=, size);
266 memcpy(data, (caddr_t)dcfg + vpd_offset, vpd_length);
267
268 /* Pad data with all-1s, consistent with update operations */
269 memset(data + vpd_length, 0xff, size - vpd_length);
270
271 EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg);
272
273 return (0);
274
275fail2:
276 EFSYS_PROBE(fail2);
277
278 EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg);
279fail1:
280 EFSYS_PROBE1(fail1, int, rc);
281
282 return (rc);
283}
284
285 __checkReturn int
286siena_vpd_verify(
287 __in efx_nic_t *enp,
288 __in_bcount(size) caddr_t data,
289 __in size_t size)
290{
291 efx_vpd_tag_t stag;
292 efx_vpd_tag_t dtag;
293 efx_vpd_keyword_t skey;
294 efx_vpd_keyword_t dkey;
295 unsigned int scont;
296 unsigned int dcont;
297
298 int rc;
299
300 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
301
302 /*
303 * Strictly you could take the view that dynamic vpd is optional.
304 * Instead, to conform more closely to the read/verify/reinit()
305 * paradigm, we require dynamic vpd. siena_vpd_reinit() will
306 * reinitialize it as required.
307 */
308 if ((rc = efx_vpd_hunk_verify(data, size, NULL)) != 0)
309 goto fail1;
310
311 /*
312 * Verify that there is no duplication between the static and
313 * dynamic cfg sectors.
314 */
315 if (enp->en_u.siena.enu_svpd_length == 0)
316 goto done;
317
318 dcont = 0;
319 _NOTE(CONSTANTCONDITION)
320 while (1) {
321 if ((rc = efx_vpd_hunk_next(data, size, &dtag,
322 &dkey, NULL, NULL, &dcont)) != 0)
323 goto fail2;
324 if (dcont == 0)
325 break;
326
327 scont = 0;
328 _NOTE(CONSTANTCONDITION)
329 while (1) {
330 if ((rc = efx_vpd_hunk_next(
331 enp->en_u.siena.enu_svpd,
332 enp->en_u.siena.enu_svpd_length, &stag, &skey,
333 NULL, NULL, &scont)) != 0)
334 goto fail3;
335 if (scont == 0)
336 break;
337
338 if (stag == dtag && skey == dkey) {
339 rc = EEXIST;
340 goto fail4;
341 }
342 }
343 }
344
345done:
346 return (0);
347
348fail4:
349 EFSYS_PROBE(fail4);
350fail3:
351 EFSYS_PROBE(fail3);
352fail2:
353 EFSYS_PROBE(fail2);
354fail1:
355 EFSYS_PROBE1(fail1, int, rc);
356
357 return (rc);
358}
359
360 __checkReturn int
361siena_vpd_reinit(
362 __in efx_nic_t *enp,
363 __in_bcount(size) caddr_t data,
364 __in size_t size)
365{
366 boolean_t wantpid;
367 int rc;
368
369 /*
370 * Only create a PID if the dynamic cfg doesn't have one
371 */
372 if (enp->en_u.siena.enu_svpd_length == 0)
373 wantpid = B_TRUE;
374 else {
375 unsigned int offset;
376 uint8_t length;
377
378 rc = efx_vpd_hunk_get(enp->en_u.siena.enu_svpd,
379 enp->en_u.siena.enu_svpd_length,
380 EFX_VPD_ID, 0, &offset, &length);
381 if (rc == 0)
382 wantpid = B_FALSE;
383 else if (rc == ENOENT)
384 wantpid = B_TRUE;
385 else
386 goto fail1;
387 }
388
389 if ((rc = efx_vpd_hunk_reinit(data, size, wantpid)) != 0)
390 goto fail2;
391
392 return (0);
393
394fail2:
395 EFSYS_PROBE(fail2);
396fail1:
397 EFSYS_PROBE1(fail1, int, rc);
398
399 return (rc);
400}
401
402 __checkReturn int
403siena_vpd_get(
404 __in efx_nic_t *enp,
405 __in_bcount(size) caddr_t data,
406 __in size_t size,
407 __inout efx_vpd_value_t *evvp)
408{
409 unsigned int offset;
410 uint8_t length;
411 int rc;
412
413 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
414
415 /* Attempt to satisfy the request from svpd first */
416 if (enp->en_u.siena.enu_svpd_length > 0) {
417 if ((rc = efx_vpd_hunk_get(enp->en_u.siena.enu_svpd,
418 enp->en_u.siena.enu_svpd_length, evvp->evv_tag,
419 evvp->evv_keyword, &offset, &length)) == 0) {
420 evvp->evv_length = length;
421 memcpy(evvp->evv_value,
422 enp->en_u.siena.enu_svpd + offset, length);
423 return (0);
424 } else if (rc != ENOENT)
425 goto fail1;
426 }
427
428 /* And then from the provided data buffer */
429 if ((rc = efx_vpd_hunk_get(data, size, evvp->evv_tag,
430 evvp->evv_keyword, &offset, &length)) != 0)
431 goto fail2;
432
433 evvp->evv_length = length;
434 memcpy(evvp->evv_value, data + offset, length);
435
436 return (0);
437
438fail2:
439 EFSYS_PROBE(fail2);
440fail1:
441 EFSYS_PROBE1(fail1, int, rc);
442
443 return (rc);
444}
445
446 __checkReturn int
447siena_vpd_set(
448 __in efx_nic_t *enp,
449 __in_bcount(size) caddr_t data,
450 __in size_t size,
451 __in efx_vpd_value_t *evvp)
452{
453 int rc;
454
455 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
456
457 /* If the provided (tag,keyword) exists in svpd, then it is readonly */
458 if (enp->en_u.siena.enu_svpd_length > 0) {
459 unsigned int offset;
460 uint8_t length;
461
462 if ((rc = efx_vpd_hunk_get(enp->en_u.siena.enu_svpd,
463 enp->en_u.siena.enu_svpd_length, evvp->evv_tag,
464 evvp->evv_keyword, &offset, &length)) == 0) {
465 rc = EACCES;
466 goto fail1;
467 }
468 }
469
470 if ((rc = efx_vpd_hunk_set(data, size, evvp)) != 0)
471 goto fail2;
472
473 return (0);
474
475fail2:
476 EFSYS_PROBE(fail2);
477fail1:
478 EFSYS_PROBE1(fail1, int, rc);
479
480 return (rc);
481}
482
483 __checkReturn int
484siena_vpd_next(
485 __in efx_nic_t *enp,
486 __in_bcount(size) caddr_t data,
487 __in size_t size,
488 __out efx_vpd_value_t *evvp,
489 __inout unsigned int *contp)
490{
491 _NOTE(ARGUNUSED(enp, data, size, evvp, contp))
492
493 return (ENOTSUP);
494}
495
496 __checkReturn int
497siena_vpd_write(
498 __in efx_nic_t *enp,
499 __in_bcount(size) caddr_t data,
500 __in size_t size)
501{
502 efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip);
503 siena_mc_dynamic_config_hdr_t *dcfg;
504 unsigned int vpd_offset;
505 unsigned int dcfg_partn;
506 unsigned int hdr_length;
507 unsigned int pos;
508 uint8_t cksum;
509 size_t partn_size, dcfg_size;
510 size_t vpd_length;
511 int rc;
512
513 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
514
515 /* Determine total length of all tags */
516 if ((rc = efx_vpd_hunk_length(data, size, &vpd_length)) != 0)
517 goto fail1;
518
519 /* Lock dynamic config sector for write, and read structure only */
520 dcfg_partn = (emip->emi_port == 1)
521 ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0
522 : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1;
523
524 if ((rc = siena_nvram_partn_size(enp, dcfg_partn, &partn_size)) != 0)
525 goto fail2;
526
527 if ((rc = siena_nvram_partn_lock(enp, dcfg_partn)) != 0)
528 goto fail2;
529
530 if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn,
531 B_FALSE, &dcfg, &dcfg_size)) != 0)
532 goto fail3;
533
534 hdr_length = EFX_WORD_FIELD(dcfg->length, EFX_WORD_0);
535
536 /* Allocated memory should have room for the new VPD */
537 if (hdr_length + vpd_length > dcfg_size) {
538 rc = ENOSPC;
539 goto fail3;
540 }
541
542 /* Copy in new vpd and update header */
543 vpd_offset = dcfg_size - vpd_length;
544 EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_offset, EFX_DWORD_0, vpd_offset);
545 memcpy((caddr_t)dcfg + vpd_offset, data, vpd_length);
546 EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_length, EFX_DWORD_0, vpd_length);
547
548 /* Update the checksum */
549 cksum = 0;
550 for (pos = 0; pos < hdr_length; pos++)
551 cksum += ((uint8_t *)dcfg)[pos];
552 dcfg->csum.eb_u8[0] -= cksum;
553
554 /* Erase and write the new sector */
555 if ((rc = siena_nvram_partn_erase(enp, dcfg_partn, 0, partn_size)) != 0)
556 goto fail4;
557
558 /* Write out the new structure to nvram */
559 if ((rc = siena_nvram_partn_write(enp, dcfg_partn, 0, (caddr_t)dcfg,
560 vpd_offset + vpd_length)) != 0)
561 goto fail5;
562
563 EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg);
564
565 siena_nvram_partn_unlock(enp, dcfg_partn);
566
567 return (0);
568
569fail5:
570 EFSYS_PROBE(fail5);
571fail4:
572 EFSYS_PROBE(fail4);
573fail3:
574 EFSYS_PROBE(fail3);
575
576 EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg);
577fail2:
578 EFSYS_PROBE(fail2);
579
580 siena_nvram_partn_unlock(enp, dcfg_partn);
581fail1:
582 EFSYS_PROBE1(fail1, int, rc);
583
584 return (rc);
585}
586
587 void
588siena_vpd_fini(
589 __in efx_nic_t *enp)
590{
591 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
592
593 if (enp->en_u.siena.enu_svpd_length > 0) {
594 EFSYS_KMEM_FREE(enp->en_esip, enp->en_u.siena.enu_svpd_length,
595 enp->en_u.siena.enu_svpd);
596
597 enp->en_u.siena.enu_svpd = NULL;
598 enp->en_u.siena.enu_svpd_length = 0;
599 }
600}
601
602#endif /* EFSYS_OPT_SIENA */
603
604#endif /* EFSYS_OPT_VPD */