]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/sfxge/common/siena_vpd.c
Upgrade to OpenSSH 7.7p1.
[FreeBSD/FreeBSD.git] / sys / dev / sfxge / common / siena_vpd.c
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_VPD
40
41 #if EFSYS_OPT_SIENA
42
43 static  __checkReturn                   efx_rc_t
44 siena_vpd_get_static(
45         __in                            efx_nic_t *enp,
46         __in                            uint32_t partn,
47         __deref_out_bcount_opt(*sizep)  caddr_t *svpdp,
48         __out                           size_t *sizep)
49 {
50         siena_mc_static_config_hdr_t *scfg;
51         caddr_t svpd;
52         size_t size;
53         uint8_t cksum;
54         unsigned int vpd_offset;
55         unsigned int vpd_length;
56         unsigned int hdr_length;
57         unsigned int pos;
58         unsigned int region;
59         efx_rc_t rc;
60
61         EFSYS_ASSERT(partn == MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT0 ||
62                     partn == MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT1);
63
64         /* Allocate sufficient memory for the entire static cfg area */
65         if ((rc = siena_nvram_partn_size(enp, partn, &size)) != 0)
66                 goto fail1;
67
68         EFSYS_KMEM_ALLOC(enp->en_esip, size, scfg);
69         if (scfg == NULL) {
70                 rc = ENOMEM;
71                 goto fail2;
72         }
73
74         if ((rc = siena_nvram_partn_read(enp, partn, 0,
75             (caddr_t)scfg, SIENA_NVRAM_CHUNK)) != 0)
76                 goto fail3;
77
78         /* Verify the magic number */
79         if (EFX_DWORD_FIELD(scfg->magic, EFX_DWORD_0) !=
80             SIENA_MC_STATIC_CONFIG_MAGIC) {
81                 rc = EINVAL;
82                 goto fail4;
83         }
84
85         /* All future versions of the structure must be backwards compatible */
86         EFX_STATIC_ASSERT(SIENA_MC_STATIC_CONFIG_VERSION == 0);
87
88         hdr_length = EFX_WORD_FIELD(scfg->length, EFX_WORD_0);
89         vpd_offset = EFX_DWORD_FIELD(scfg->static_vpd_offset, EFX_DWORD_0);
90         vpd_length = EFX_DWORD_FIELD(scfg->static_vpd_length, EFX_DWORD_0);
91
92         /* Verify the hdr doesn't overflow the sector size */
93         if (hdr_length > size || vpd_offset > size || vpd_length > size ||
94             vpd_length + vpd_offset > size) {
95                 rc = EINVAL;
96                 goto fail5;
97         }
98
99         /* Read the remainder of scfg + static vpd */
100         region = vpd_offset + vpd_length;
101         if (region > SIENA_NVRAM_CHUNK) {
102                 if ((rc = siena_nvram_partn_read(enp, partn, SIENA_NVRAM_CHUNK,
103                     (caddr_t)scfg + SIENA_NVRAM_CHUNK,
104                     region - SIENA_NVRAM_CHUNK)) != 0)
105                         goto fail6;
106         }
107
108         /* Verify checksum */
109         cksum = 0;
110         for (pos = 0; pos < hdr_length; pos++)
111                 cksum += ((uint8_t *)scfg)[pos];
112         if (cksum != 0) {
113                 rc = EINVAL;
114                 goto fail7;
115         }
116
117         if (vpd_length == 0)
118                 svpd = NULL;
119         else {
120                 /* Copy the vpd data out */
121                 EFSYS_KMEM_ALLOC(enp->en_esip, vpd_length, svpd);
122                 if (svpd == NULL) {
123                         rc = ENOMEM;
124                         goto fail8;
125                 }
126                 memcpy(svpd, (caddr_t)scfg + vpd_offset, vpd_length);
127         }
128
129         EFSYS_KMEM_FREE(enp->en_esip, size, scfg);
130
131         *svpdp = svpd;
132         *sizep = vpd_length;
133
134         return (0);
135
136 fail8:
137         EFSYS_PROBE(fail8);
138 fail7:
139         EFSYS_PROBE(fail7);
140 fail6:
141         EFSYS_PROBE(fail6);
142 fail5:
143         EFSYS_PROBE(fail5);
144 fail4:
145         EFSYS_PROBE(fail4);
146 fail3:
147         EFSYS_PROBE(fail3);
148
149         EFSYS_KMEM_FREE(enp->en_esip, size, scfg);
150
151 fail2:
152         EFSYS_PROBE(fail2);
153 fail1:
154         EFSYS_PROBE1(fail1, efx_rc_t, rc);
155
156         return (rc);
157 }
158
159         __checkReturn           efx_rc_t
160 siena_vpd_init(
161         __in                    efx_nic_t *enp)
162 {
163         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
164         caddr_t svpd = NULL;
165         unsigned int partn;
166         size_t size = 0;
167         efx_rc_t rc;
168
169         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
170
171         partn = (emip->emi_port == 1)
172                 ? MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT0
173                 : MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT1;
174
175         /*
176          * We need the static VPD sector to present a unified static+dynamic
177          * VPD, that is, basically on every read, write, verify cycle. Since
178          * it should *never* change we can just cache it here.
179          */
180         if ((rc = siena_vpd_get_static(enp, partn, &svpd, &size)) != 0)
181                 goto fail1;
182
183         if (svpd != NULL && size > 0) {
184                 if ((rc = efx_vpd_hunk_verify(svpd, size, NULL)) != 0)
185                         goto fail2;
186         }
187
188         enp->en_u.siena.enu_svpd = svpd;
189         enp->en_u.siena.enu_svpd_length = size;
190
191         return (0);
192
193 fail2:
194         EFSYS_PROBE(fail2);
195
196         EFSYS_KMEM_FREE(enp->en_esip, size, svpd);
197 fail1:
198         EFSYS_PROBE1(fail1, efx_rc_t, rc);
199
200         return (rc);
201 }
202
203         __checkReturn           efx_rc_t
204 siena_vpd_size(
205         __in                    efx_nic_t *enp,
206         __out                   size_t *sizep)
207 {
208         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
209         uint32_t partn;
210         efx_rc_t rc;
211
212         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
213
214         /*
215          * This function returns the total size the user should allocate
216          * for all VPD operations. We've already cached the static vpd,
217          * so we just need to return an upper bound on the dynamic vpd.
218          * Since the dynamic_config structure can change under our feet,
219          * (as version numbers are inserted), just be safe and return the
220          * total size of the dynamic_config *sector*
221          */
222         partn = (emip->emi_port == 1)
223                 ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0
224                 : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1;
225
226         if ((rc = siena_nvram_partn_size(enp, partn, sizep)) != 0)
227                 goto fail1;
228
229         return (0);
230
231 fail1:
232         EFSYS_PROBE1(fail1, efx_rc_t, rc);
233
234         return (rc);
235 }
236
237         __checkReturn           efx_rc_t
238 siena_vpd_read(
239         __in                    efx_nic_t *enp,
240         __out_bcount(size)      caddr_t data,
241         __in                    size_t size)
242 {
243         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
244         siena_mc_dynamic_config_hdr_t *dcfg = NULL;
245         unsigned int vpd_length;
246         unsigned int vpd_offset;
247         unsigned int dcfg_partn;
248         size_t dcfg_size;
249         efx_rc_t rc;
250
251         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
252
253         dcfg_partn = (emip->emi_port == 1)
254                 ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0
255                 : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1;
256
257         if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn,
258             B_TRUE, &dcfg, &dcfg_size)) != 0)
259                 goto fail1;
260
261         vpd_length = EFX_DWORD_FIELD(dcfg->dynamic_vpd_length, EFX_DWORD_0);
262         vpd_offset = EFX_DWORD_FIELD(dcfg->dynamic_vpd_offset, EFX_DWORD_0);
263
264         if (vpd_length > size) {
265                 rc = EFAULT;    /* Invalid dcfg: header bigger than sector */
266                 goto fail2;
267         }
268
269         EFSYS_ASSERT3U(vpd_length, <=, size);
270         memcpy(data, (caddr_t)dcfg + vpd_offset, vpd_length);
271
272         /* Pad data with all-1s, consistent with update operations */
273         memset(data + vpd_length, 0xff, size - vpd_length);
274
275         EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg);
276
277         return (0);
278
279 fail2:
280         EFSYS_PROBE(fail2);
281
282         EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg);
283 fail1:
284         EFSYS_PROBE1(fail1, efx_rc_t, rc);
285
286         return (rc);
287 }
288
289         __checkReturn           efx_rc_t
290 siena_vpd_verify(
291         __in                    efx_nic_t *enp,
292         __in_bcount(size)       caddr_t data,
293         __in                    size_t size)
294 {
295         efx_vpd_tag_t stag;
296         efx_vpd_tag_t dtag;
297         efx_vpd_keyword_t skey;
298         efx_vpd_keyword_t dkey;
299         unsigned int scont;
300         unsigned int dcont;
301
302         efx_rc_t rc;
303
304         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
305
306         /*
307          * Strictly you could take the view that dynamic vpd is optional.
308          * Instead, to conform more closely to the read/verify/reinit()
309          * paradigm, we require dynamic vpd. siena_vpd_reinit() will
310          * reinitialize it as required.
311          */
312         if ((rc = efx_vpd_hunk_verify(data, size, NULL)) != 0)
313                 goto fail1;
314
315         /*
316          * Verify that there is no duplication between the static and
317          * dynamic cfg sectors.
318          */
319         if (enp->en_u.siena.enu_svpd_length == 0)
320                 goto done;
321
322         dcont = 0;
323         _NOTE(CONSTANTCONDITION)
324         while (1) {
325                 if ((rc = efx_vpd_hunk_next(data, size, &dtag,
326                     &dkey, NULL, NULL, &dcont)) != 0)
327                         goto fail2;
328                 if (dcont == 0)
329                         break;
330
331                 /*
332                  * Skip the RV keyword. It should be present in both the static
333                  * and dynamic cfg sectors.
334                  */
335                 if (dtag == EFX_VPD_RO && dkey == EFX_VPD_KEYWORD('R', 'V'))
336                         continue;
337
338                 scont = 0;
339                 _NOTE(CONSTANTCONDITION)
340                 while (1) {
341                         if ((rc = efx_vpd_hunk_next(
342                             enp->en_u.siena.enu_svpd,
343                             enp->en_u.siena.enu_svpd_length, &stag, &skey,
344                             NULL, NULL, &scont)) != 0)
345                                 goto fail3;
346                         if (scont == 0)
347                                 break;
348
349                         if (stag == dtag && skey == dkey) {
350                                 rc = EEXIST;
351                                 goto fail4;
352                         }
353                 }
354         }
355
356 done:
357         return (0);
358
359 fail4:
360         EFSYS_PROBE(fail4);
361 fail3:
362         EFSYS_PROBE(fail3);
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 siena_vpd_reinit(
373         __in                    efx_nic_t *enp,
374         __in_bcount(size)       caddr_t data,
375         __in                    size_t size)
376 {
377         boolean_t wantpid;
378         efx_rc_t rc;
379
380         /*
381          * Only create a PID if the dynamic cfg doesn't have one
382          */
383         if (enp->en_u.siena.enu_svpd_length == 0)
384                 wantpid = B_TRUE;
385         else {
386                 unsigned int offset;
387                 uint8_t length;
388
389                 rc = efx_vpd_hunk_get(enp->en_u.siena.enu_svpd,
390                                     enp->en_u.siena.enu_svpd_length,
391                                     EFX_VPD_ID, 0, &offset, &length);
392                 if (rc == 0)
393                         wantpid = B_FALSE;
394                 else if (rc == ENOENT)
395                         wantpid = B_TRUE;
396                 else
397                         goto fail1;
398         }
399
400         if ((rc = efx_vpd_hunk_reinit(data, size, wantpid)) != 0)
401                 goto fail2;
402
403         return (0);
404
405 fail2:
406         EFSYS_PROBE(fail2);
407 fail1:
408         EFSYS_PROBE1(fail1, efx_rc_t, rc);
409
410         return (rc);
411 }
412
413         __checkReturn           efx_rc_t
414 siena_vpd_get(
415         __in                    efx_nic_t *enp,
416         __in_bcount(size)       caddr_t data,
417         __in                    size_t size,
418         __inout                 efx_vpd_value_t *evvp)
419 {
420         unsigned int offset;
421         uint8_t length;
422         efx_rc_t rc;
423
424         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
425
426         /* Attempt to satisfy the request from svpd first */
427         if (enp->en_u.siena.enu_svpd_length > 0) {
428                 if ((rc = efx_vpd_hunk_get(enp->en_u.siena.enu_svpd,
429                     enp->en_u.siena.enu_svpd_length, evvp->evv_tag,
430                     evvp->evv_keyword, &offset, &length)) == 0) {
431                         evvp->evv_length = length;
432                         memcpy(evvp->evv_value,
433                             enp->en_u.siena.enu_svpd + offset, length);
434                         return (0);
435                 } else if (rc != ENOENT)
436                         goto fail1;
437         }
438
439         /* And then from the provided data buffer */
440         if ((rc = efx_vpd_hunk_get(data, size, evvp->evv_tag,
441             evvp->evv_keyword, &offset, &length)) != 0) {
442                 if (rc == ENOENT)
443                         return (rc);
444
445                 goto fail2;
446         }
447
448         evvp->evv_length = length;
449         memcpy(evvp->evv_value, data + offset, length);
450
451         return (0);
452
453 fail2:
454         EFSYS_PROBE(fail2);
455 fail1:
456         EFSYS_PROBE1(fail1, efx_rc_t, rc);
457
458         return (rc);
459 }
460
461         __checkReturn           efx_rc_t
462 siena_vpd_set(
463         __in                    efx_nic_t *enp,
464         __in_bcount(size)       caddr_t data,
465         __in                    size_t size,
466         __in                    efx_vpd_value_t *evvp)
467 {
468         efx_rc_t rc;
469
470         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
471
472         /* If the provided (tag,keyword) exists in svpd, then it is readonly */
473         if (enp->en_u.siena.enu_svpd_length > 0) {
474                 unsigned int offset;
475                 uint8_t length;
476
477                 if ((rc = efx_vpd_hunk_get(enp->en_u.siena.enu_svpd,
478                     enp->en_u.siena.enu_svpd_length, evvp->evv_tag,
479                     evvp->evv_keyword, &offset, &length)) == 0) {
480                         rc = EACCES;
481                         goto fail1;
482                 }
483         }
484
485         if ((rc = efx_vpd_hunk_set(data, size, evvp)) != 0)
486                 goto fail2;
487
488         return (0);
489
490 fail2:
491         EFSYS_PROBE(fail2);
492 fail1:
493         EFSYS_PROBE1(fail1, efx_rc_t, rc);
494
495         return (rc);
496 }
497
498         __checkReturn           efx_rc_t
499 siena_vpd_next(
500         __in                    efx_nic_t *enp,
501         __in_bcount(size)       caddr_t data,
502         __in                    size_t size,
503         __out                   efx_vpd_value_t *evvp,
504         __inout                 unsigned int *contp)
505 {
506         _NOTE(ARGUNUSED(enp, data, size, evvp, contp))
507
508         return (ENOTSUP);
509 }
510
511         __checkReturn           efx_rc_t
512 siena_vpd_write(
513         __in                    efx_nic_t *enp,
514         __in_bcount(size)       caddr_t data,
515         __in                    size_t size)
516 {
517         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
518         siena_mc_dynamic_config_hdr_t *dcfg = NULL;
519         unsigned int vpd_offset;
520         unsigned int dcfg_partn;
521         unsigned int hdr_length;
522         unsigned int pos;
523         uint8_t cksum;
524         size_t partn_size, dcfg_size;
525         size_t vpd_length;
526         efx_rc_t rc;
527
528         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
529
530         /* Determine total length of all tags */
531         if ((rc = efx_vpd_hunk_length(data, size, &vpd_length)) != 0)
532                 goto fail1;
533
534         /* Lock dynamic config sector for write, and read structure only */
535         dcfg_partn = (emip->emi_port == 1)
536                 ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0
537                 : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1;
538
539         if ((rc = siena_nvram_partn_size(enp, dcfg_partn, &partn_size)) != 0)
540                 goto fail2;
541
542         if ((rc = siena_nvram_partn_lock(enp, dcfg_partn)) != 0)
543                 goto fail3;
544
545         if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn,
546             B_FALSE, &dcfg, &dcfg_size)) != 0)
547                 goto fail4;
548
549         hdr_length = EFX_WORD_FIELD(dcfg->length, EFX_WORD_0);
550
551         /* Allocated memory should have room for the new VPD */
552         if (hdr_length + vpd_length > dcfg_size) {
553                 rc = ENOSPC;
554                 goto fail5;
555         }
556
557         /* Copy in new vpd and update header */
558         vpd_offset = dcfg_size - vpd_length;
559         EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_offset, EFX_DWORD_0, vpd_offset);
560         memcpy((caddr_t)dcfg + vpd_offset, data, vpd_length);
561         EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_length, EFX_DWORD_0, vpd_length);
562
563         /* Update the checksum */
564         cksum = 0;
565         for (pos = 0; pos < hdr_length; pos++)
566                 cksum += ((uint8_t *)dcfg)[pos];
567         dcfg->csum.eb_u8[0] -= cksum;
568
569         /* Erase and write the new sector */
570         if ((rc = siena_nvram_partn_erase(enp, dcfg_partn, 0, partn_size)) != 0)
571                 goto fail6;
572
573         /* Write out the new structure to nvram */
574         if ((rc = siena_nvram_partn_write(enp, dcfg_partn, 0, (caddr_t)dcfg,
575             vpd_offset + vpd_length)) != 0)
576                 goto fail7;
577
578         EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg);
579
580         siena_nvram_partn_unlock(enp, dcfg_partn);
581
582         return (0);
583
584 fail7:
585         EFSYS_PROBE(fail7);
586 fail6:
587         EFSYS_PROBE(fail6);
588 fail5:
589         EFSYS_PROBE(fail5);
590
591         EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg);
592 fail4:
593         EFSYS_PROBE(fail4);
594
595         siena_nvram_partn_unlock(enp, dcfg_partn);
596 fail3:
597         EFSYS_PROBE(fail3);
598 fail2:
599         EFSYS_PROBE(fail2);
600 fail1:
601         EFSYS_PROBE1(fail1, efx_rc_t, rc);
602
603         return (rc);
604 }
605
606                                 void
607 siena_vpd_fini(
608         __in                    efx_nic_t *enp)
609 {
610         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
611
612         if (enp->en_u.siena.enu_svpd_length > 0) {
613                 EFSYS_KMEM_FREE(enp->en_esip, enp->en_u.siena.enu_svpd_length,
614                                 enp->en_u.siena.enu_svpd);
615
616                 enp->en_u.siena.enu_svpd = NULL;
617                 enp->en_u.siena.enu_svpd_length = 0;
618         }
619 }
620
621 #endif  /* EFSYS_OPT_SIENA */
622
623 #endif  /* EFSYS_OPT_VPD */