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 <sys/types.h>
32 #include <sys/kmem.h>
33 #include "sfxge.h"
34
35
36 static int
37 sfxge_vpd_get_keyword(sfxge_t *sp, sfxge_vpd_ioc_t *svip)
38 {
39 efx_nic_t *enp = sp->s_enp;
40 efx_vpd_value_t vpd;
41 size_t size;
42 void *buf;
43 int rc;
44
45 if ((rc = efx_vpd_size(enp, &size)) != 0)
46 goto fail1;
47
48 buf = kmem_zalloc(size, KM_SLEEP);
49 ASSERT(buf);
50
51 if ((rc = efx_vpd_read(enp, buf, size)) != 0)
52 goto fail2;
53
54 if ((rc = efx_vpd_verify(enp, buf, size)) != 0)
55 goto fail3;
56
57 vpd.evv_tag = svip->svi_tag;
58 vpd.evv_keyword = svip->svi_keyword;
59
60 if ((rc = efx_vpd_get(enp, buf, size, &vpd)) != 0)
61 goto fail4;
62
63 svip->svi_len = vpd.evv_length;
64 EFX_STATIC_ASSERT(sizeof (svip->svi_payload) == sizeof (vpd.evv_value));
65 bcopy(&vpd.evv_value[0], svip->svi_payload, sizeof (svip->svi_payload));
66
67 kmem_free(buf, size);
68
69 return (0);
70
71 fail4:
72 DTRACE_PROBE(fail4);
73 fail3:
74 DTRACE_PROBE(fail3);
75 fail2:
76 DTRACE_PROBE(fail2);
77 kmem_free(buf, size);
78 fail1:
79 DTRACE_PROBE1(fail1, int, rc);
80
81 return (rc);
82 }
83
84
85 static int
86 sfxge_vpd_set_keyword(sfxge_t *sp, sfxge_vpd_ioc_t *svip)
87 {
88 efx_nic_t *enp = sp->s_enp;
89 efx_vpd_value_t vpd;
90 size_t size;
91 void *buf;
92 int rc;
93
94 /* restriction on writable tags is in efx_vpd_hunk_set() */
95
96 if ((rc = efx_vpd_size(enp, &size)) != 0)
97 goto fail1;
98
99 buf = kmem_zalloc(size, KM_SLEEP);
100 ASSERT(buf);
101
102 if ((rc = efx_vpd_read(enp, buf, size)) != 0)
103 goto fail2;
104
105 if ((rc = efx_vpd_verify(enp, buf, size)) != 0) {
106 if ((rc = efx_vpd_reinit(enp, buf, size)) != 0)
107 goto fail3;
108 if ((rc = efx_vpd_verify(enp, buf, size)) != 0)
109 goto fail4;
110 }
111
112 vpd.evv_tag = svip->svi_tag;
113 vpd.evv_keyword = svip->svi_keyword;
114 vpd.evv_length = svip->svi_len;
115
116 EFX_STATIC_ASSERT(sizeof (svip->svi_payload) == sizeof (vpd.evv_value));
117 bcopy(svip->svi_payload, &vpd.evv_value[0], sizeof (svip->svi_payload));
118
119 if ((rc = efx_vpd_set(enp, buf, size, &vpd)) != 0)
120 goto fail5;
121
122 if ((rc = efx_vpd_verify(enp, buf, size)) != 0)
123 goto fail6;
124
125 /* And write the VPD back to the hardware */
126 if ((rc = efx_vpd_write(enp, buf, size)) != 0)
127 goto fail7;
128
129 kmem_free(buf, size);
130
131 return (0);
132
133 fail7:
134 DTRACE_PROBE(fail7);
135 fail6:
136 DTRACE_PROBE(fail6);
137 fail5:
138 DTRACE_PROBE(fail5);
139 fail4:
140 DTRACE_PROBE(fail4);
141 fail3:
142 DTRACE_PROBE(fail3);
143 fail2:
144 DTRACE_PROBE(fail2);
145 kmem_free(buf, size);
146 fail1:
147 DTRACE_PROBE1(fail1, int, rc);
148
149 return (rc);
150 }
151
152
153 int
154 sfxge_vpd_ioctl(sfxge_t *sp, sfxge_vpd_ioc_t *svip)
155 {
156 int rc;
157
158 switch (svip->svi_op) {
159 case SFXGE_VPD_OP_GET_KEYWORD:
160 if ((rc = sfxge_vpd_get_keyword(sp, svip)) != 0)
161 goto fail1;
162 break;
163 case SFXGE_VPD_OP_SET_KEYWORD:
164 if ((rc = sfxge_vpd_set_keyword(sp, svip)) != 0)
165 goto fail1;
166 break;
167 default:
168 rc = EINVAL;
169 goto fail2;
170 }
171
172 return (0);
173
174 fail2:
175 DTRACE_PROBE(fail2);
176 fail1:
177 DTRACE_PROBE1(fail1, int, rc);
178
179 return (rc);
180 }