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