]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/dev/sfxge/common/siena_vpd.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / dev / sfxge / common / siena_vpd.c
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$");
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
39 static  __checkReturn                   int
40 siena_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
132 fail8:
133         EFSYS_PROBE(fail8);
134 fail7:
135         EFSYS_PROBE(fail7);
136 fail6:
137         EFSYS_PROBE(fail6);
138 fail5:
139         EFSYS_PROBE(fail5);
140 fail4:
141         EFSYS_PROBE(fail4);
142 fail3:
143         EFSYS_PROBE(fail3);
144 fail2:
145         EFSYS_PROBE(fail2);
146
147         EFSYS_KMEM_FREE(enp->en_esip, size, scfg);
148
149 fail1:
150         EFSYS_PROBE1(fail1, int, rc);
151
152         return (rc);
153 }
154
155         __checkReturn           int
156 siena_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
189 fail2:
190         EFSYS_PROBE(fail2);
191
192         EFSYS_KMEM_FREE(enp->en_esip, size, svpd);
193 fail1:
194         EFSYS_PROBE1(fail1, int, rc);
195
196         return (rc);
197 }
198
199         __checkReturn           int
200 siena_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
227 fail1:
228         EFSYS_PROBE1(fail1, int, rc);
229
230         return (rc);
231 }
232
233         __checkReturn           int
234 siena_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
275 fail2:
276         EFSYS_PROBE(fail2);
277
278         EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg);
279 fail1:
280         EFSYS_PROBE1(fail1, int, rc);
281
282         return (rc);
283 }
284
285         __checkReturn           int
286 siena_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
345 done:
346         return (0);
347
348 fail4:
349         EFSYS_PROBE(fail4);
350 fail3:
351         EFSYS_PROBE(fail3);
352 fail2:
353         EFSYS_PROBE(fail2);
354 fail1:
355         EFSYS_PROBE1(fail1, int, rc);
356
357         return (rc);
358 }
359
360         __checkReturn           int
361 siena_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
394 fail2:
395         EFSYS_PROBE(fail2);
396 fail1:
397         EFSYS_PROBE1(fail1, int, rc);
398
399         return (rc);
400 }
401
402         __checkReturn           int
403 siena_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
438 fail2:
439         EFSYS_PROBE(fail2);
440 fail1:
441         EFSYS_PROBE1(fail1, int, rc);
442
443         return (rc);
444 }
445
446         __checkReturn           int
447 siena_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
475 fail2:
476         EFSYS_PROBE(fail2);
477 fail1:
478         EFSYS_PROBE1(fail1, int, rc);
479
480         return (rc);
481 }
482
483         __checkReturn           int
484 siena_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
497 siena_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,
545                              EFX_DWORD_0, vpd_offset);
546         memcpy((caddr_t)dcfg + vpd_offset, data, vpd_length);
547         EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_length,
548                             EFX_DWORD_0, vpd_length);
549
550         /* Update the checksum */
551         cksum = 0;
552         for (pos = 0; pos < hdr_length; pos++)
553                 cksum += ((uint8_t *)dcfg)[pos];
554         dcfg->csum.eb_u8[0] -= cksum;
555
556         /* Erase and write the new sector */
557         if ((rc = siena_nvram_partn_erase(enp, dcfg_partn, 0, partn_size)) != 0)
558                 goto fail4;
559
560         /* Write out the new structure to nvram */
561         if ((rc = siena_nvram_partn_write(enp, dcfg_partn, 0, (caddr_t)dcfg,
562             vpd_offset + vpd_length)) != 0)
563                 goto fail5;
564
565         EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg);
566
567         siena_nvram_partn_unlock(enp, dcfg_partn);
568
569         return (0);
570
571 fail5:
572         EFSYS_PROBE(fail5);
573 fail4:
574         EFSYS_PROBE(fail4);
575 fail3:
576         EFSYS_PROBE(fail3);
577
578         EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg);
579 fail2:
580         EFSYS_PROBE(fail2);
581
582         siena_nvram_partn_unlock(enp, dcfg_partn);
583 fail1:
584         EFSYS_PROBE1(fail1, int, rc);
585
586         return (rc);
587 }
588
589                                 void
590 siena_vpd_fini(
591         __in                    efx_nic_t *enp)
592 {
593         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
594
595         if (enp->en_u.siena.enu_svpd_length > 0) {
596                 EFSYS_KMEM_FREE(enp->en_esip, enp->en_u.siena.enu_svpd_length,
597                                 enp->en_u.siena.enu_svpd);
598
599                 enp->en_u.siena.enu_svpd = NULL;
600                 enp->en_u.siena.enu_svpd_length = 0;
601         }
602 }
603
604 #endif  /* EFSYS_OPT_SIENA */
605
606 #endif  /* EFSYS_OPT_VPD */