1*49ef7e06SGarrett D'Amore /*
2*49ef7e06SGarrett D'Amore  * Copyright (c) 2009-2016 Solarflare Communications Inc.
3*49ef7e06SGarrett D'Amore  * All rights reserved.
4*49ef7e06SGarrett D'Amore  *
5*49ef7e06SGarrett D'Amore  * Redistribution and use in source and binary forms, with or without
6*49ef7e06SGarrett D'Amore  * modification, are permitted provided that the following conditions are met:
7*49ef7e06SGarrett D'Amore  *
8*49ef7e06SGarrett D'Amore  * 1. Redistributions of source code must retain the above copyright notice,
9*49ef7e06SGarrett D'Amore  *    this list of conditions and the following disclaimer.
10*49ef7e06SGarrett D'Amore  * 2. Redistributions in binary form must reproduce the above copyright notice,
11*49ef7e06SGarrett D'Amore  *    this list of conditions and the following disclaimer in the documentation
12*49ef7e06SGarrett D'Amore  *    and/or other materials provided with the distribution.
13*49ef7e06SGarrett D'Amore  *
14*49ef7e06SGarrett D'Amore  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15*49ef7e06SGarrett D'Amore  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16*49ef7e06SGarrett D'Amore  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17*49ef7e06SGarrett D'Amore  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18*49ef7e06SGarrett D'Amore  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19*49ef7e06SGarrett D'Amore  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20*49ef7e06SGarrett D'Amore  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21*49ef7e06SGarrett D'Amore  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22*49ef7e06SGarrett D'Amore  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23*49ef7e06SGarrett D'Amore  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24*49ef7e06SGarrett D'Amore  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25*49ef7e06SGarrett D'Amore  *
26*49ef7e06SGarrett D'Amore  * The views and conclusions contained in the software and documentation are
27*49ef7e06SGarrett D'Amore  * those of the authors and should not be interpreted as representing official
28*49ef7e06SGarrett D'Amore  * policies, either expressed or implied, of the FreeBSD Project.
29*49ef7e06SGarrett D'Amore  */
30*49ef7e06SGarrett D'Amore 
31*49ef7e06SGarrett D'Amore #include <sys/types.h>
32*49ef7e06SGarrett D'Amore #include <sys/kmem.h>
33*49ef7e06SGarrett D'Amore #include "sfxge.h"
34*49ef7e06SGarrett D'Amore 
35*49ef7e06SGarrett D'Amore 
36*49ef7e06SGarrett D'Amore static int
sfxge_vpd_get_keyword(sfxge_t * sp,sfxge_vpd_ioc_t * svip)37*49ef7e06SGarrett D'Amore sfxge_vpd_get_keyword(sfxge_t *sp, sfxge_vpd_ioc_t *svip)
38*49ef7e06SGarrett D'Amore {
39*49ef7e06SGarrett D'Amore 	efx_nic_t *enp = sp->s_enp;
40*49ef7e06SGarrett D'Amore 	efx_vpd_value_t vpd;
41*49ef7e06SGarrett D'Amore 	size_t size;
42*49ef7e06SGarrett D'Amore 	void *buf;
43*49ef7e06SGarrett D'Amore 	int rc;
44*49ef7e06SGarrett D'Amore 
45*49ef7e06SGarrett D'Amore 	if ((rc = efx_vpd_size(enp, &size)) != 0)
46*49ef7e06SGarrett D'Amore 		goto fail1;
47*49ef7e06SGarrett D'Amore 
48*49ef7e06SGarrett D'Amore 	buf = kmem_zalloc(size, KM_NOSLEEP);
49*49ef7e06SGarrett D'Amore 	if (buf == NULL) {
50*49ef7e06SGarrett D'Amore 		rc = ENOMEM;
51*49ef7e06SGarrett D'Amore 		goto fail1;
52*49ef7e06SGarrett D'Amore 	}
53*49ef7e06SGarrett D'Amore 
54*49ef7e06SGarrett D'Amore 	if ((rc = efx_vpd_read(enp, buf, size)) != 0)
55*49ef7e06SGarrett D'Amore 		goto fail2;
56*49ef7e06SGarrett D'Amore 
57*49ef7e06SGarrett D'Amore 	if ((rc = efx_vpd_verify(enp, buf, size)) != 0)
58*49ef7e06SGarrett D'Amore 		goto fail3;
59*49ef7e06SGarrett D'Amore 
60*49ef7e06SGarrett D'Amore 	vpd.evv_tag = svip->svi_tag;
61*49ef7e06SGarrett D'Amore 	vpd.evv_keyword = svip->svi_keyword;
62*49ef7e06SGarrett D'Amore 
63*49ef7e06SGarrett D'Amore 	if ((rc = efx_vpd_get(enp, buf, size, &vpd)) != 0)
64*49ef7e06SGarrett D'Amore 		goto fail4;
65*49ef7e06SGarrett D'Amore 
66*49ef7e06SGarrett D'Amore 	svip->svi_len = vpd.evv_length;
67*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(sizeof (svip->svi_payload) == sizeof (vpd.evv_value));
68*49ef7e06SGarrett D'Amore 	bcopy(&vpd.evv_value[0], svip->svi_payload, sizeof (svip->svi_payload));
69*49ef7e06SGarrett D'Amore 
70*49ef7e06SGarrett D'Amore 	kmem_free(buf, size);
71*49ef7e06SGarrett D'Amore 
72*49ef7e06SGarrett D'Amore 	return (0);
73*49ef7e06SGarrett D'Amore 
74*49ef7e06SGarrett D'Amore fail4:
75*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail4);
76*49ef7e06SGarrett D'Amore fail3:
77*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail3);
78*49ef7e06SGarrett D'Amore fail2:
79*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail2);
80*49ef7e06SGarrett D'Amore 	kmem_free(buf, size);
81*49ef7e06SGarrett D'Amore fail1:
82*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
83*49ef7e06SGarrett D'Amore 
84*49ef7e06SGarrett D'Amore 	return (rc);
85*49ef7e06SGarrett D'Amore }
86*49ef7e06SGarrett D'Amore 
87*49ef7e06SGarrett D'Amore 
88*49ef7e06SGarrett D'Amore static int
sfxge_vpd_set_keyword(sfxge_t * sp,sfxge_vpd_ioc_t * svip)89*49ef7e06SGarrett D'Amore sfxge_vpd_set_keyword(sfxge_t *sp, sfxge_vpd_ioc_t *svip)
90*49ef7e06SGarrett D'Amore {
91*49ef7e06SGarrett D'Amore 	efx_nic_t *enp = sp->s_enp;
92*49ef7e06SGarrett D'Amore 	efx_vpd_value_t vpd;
93*49ef7e06SGarrett D'Amore 	size_t size;
94*49ef7e06SGarrett D'Amore 	void *buf;
95*49ef7e06SGarrett D'Amore 	int rc;
96*49ef7e06SGarrett D'Amore 
97*49ef7e06SGarrett D'Amore 	/* restriction on writable tags is in efx_vpd_hunk_set() */
98*49ef7e06SGarrett D'Amore 
99*49ef7e06SGarrett D'Amore 	if ((rc = efx_vpd_size(enp, &size)) != 0)
100*49ef7e06SGarrett D'Amore 		goto fail1;
101*49ef7e06SGarrett D'Amore 
102*49ef7e06SGarrett D'Amore 	buf = kmem_zalloc(size, KM_NOSLEEP);
103*49ef7e06SGarrett D'Amore 	if (buf == NULL) {
104*49ef7e06SGarrett D'Amore 		rc = ENOMEM;
105*49ef7e06SGarrett D'Amore 		goto fail1;
106*49ef7e06SGarrett D'Amore 	}
107*49ef7e06SGarrett D'Amore 
108*49ef7e06SGarrett D'Amore 	if ((rc = efx_vpd_read(enp, buf, size)) != 0)
109*49ef7e06SGarrett D'Amore 		goto fail2;
110*49ef7e06SGarrett D'Amore 
111*49ef7e06SGarrett D'Amore 	if ((rc = efx_vpd_verify(enp, buf, size)) != 0) {
112*49ef7e06SGarrett D'Amore 		if ((rc = efx_vpd_reinit(enp, buf, size)) != 0)
113*49ef7e06SGarrett D'Amore 			goto fail3;
114*49ef7e06SGarrett D'Amore 		if ((rc = efx_vpd_verify(enp, buf, size)) != 0)
115*49ef7e06SGarrett D'Amore 			goto fail4;
116*49ef7e06SGarrett D'Amore 	}
117*49ef7e06SGarrett D'Amore 
118*49ef7e06SGarrett D'Amore 	vpd.evv_tag = svip->svi_tag;
119*49ef7e06SGarrett D'Amore 	vpd.evv_keyword = svip->svi_keyword;
120*49ef7e06SGarrett D'Amore 	vpd.evv_length = svip->svi_len;
121*49ef7e06SGarrett D'Amore 
122*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(sizeof (svip->svi_payload) == sizeof (vpd.evv_value));
123*49ef7e06SGarrett D'Amore 	bcopy(svip->svi_payload, &vpd.evv_value[0], sizeof (svip->svi_payload));
124*49ef7e06SGarrett D'Amore 
125*49ef7e06SGarrett D'Amore 	if ((rc = efx_vpd_set(enp, buf, size, &vpd)) != 0)
126*49ef7e06SGarrett D'Amore 		goto fail5;
127*49ef7e06SGarrett D'Amore 
128*49ef7e06SGarrett D'Amore 	if ((rc = efx_vpd_verify(enp, buf, size)) != 0)
129*49ef7e06SGarrett D'Amore 			goto fail6;
130*49ef7e06SGarrett D'Amore 
131*49ef7e06SGarrett D'Amore 	/* And write the VPD back to the hardware */
132*49ef7e06SGarrett D'Amore 	if ((rc = efx_vpd_write(enp, buf, size)) != 0)
133*49ef7e06SGarrett D'Amore 		goto fail7;
134*49ef7e06SGarrett D'Amore 
135*49ef7e06SGarrett D'Amore 	kmem_free(buf, size);
136*49ef7e06SGarrett D'Amore 
137*49ef7e06SGarrett D'Amore 	return (0);
138*49ef7e06SGarrett D'Amore 
139*49ef7e06SGarrett D'Amore fail7:
140*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail7);
141*49ef7e06SGarrett D'Amore fail6:
142*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail6);
143*49ef7e06SGarrett D'Amore fail5:
144*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail5);
145*49ef7e06SGarrett D'Amore fail4:
146*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail4);
147*49ef7e06SGarrett D'Amore fail3:
148*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail3);
149*49ef7e06SGarrett D'Amore fail2:
150*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail2);
151*49ef7e06SGarrett D'Amore 	kmem_free(buf, size);
152*49ef7e06SGarrett D'Amore fail1:
153*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
154*49ef7e06SGarrett D'Amore 
155*49ef7e06SGarrett D'Amore 	return (rc);
156*49ef7e06SGarrett D'Amore }
157*49ef7e06SGarrett D'Amore 
158*49ef7e06SGarrett D'Amore 
159*49ef7e06SGarrett D'Amore int
sfxge_vpd_ioctl(sfxge_t * sp,sfxge_vpd_ioc_t * svip)160*49ef7e06SGarrett D'Amore sfxge_vpd_ioctl(sfxge_t *sp, sfxge_vpd_ioc_t *svip)
161*49ef7e06SGarrett D'Amore {
162*49ef7e06SGarrett D'Amore 	int rc;
163*49ef7e06SGarrett D'Amore 
164*49ef7e06SGarrett D'Amore 	switch (svip->svi_op) {
165*49ef7e06SGarrett D'Amore 	case SFXGE_VPD_OP_GET_KEYWORD:
166*49ef7e06SGarrett D'Amore 		if ((rc = sfxge_vpd_get_keyword(sp, svip)) != 0)
167*49ef7e06SGarrett D'Amore 			goto fail1;
168*49ef7e06SGarrett D'Amore 		break;
169*49ef7e06SGarrett D'Amore 	case SFXGE_VPD_OP_SET_KEYWORD:
170*49ef7e06SGarrett D'Amore 		if ((rc = sfxge_vpd_set_keyword(sp, svip)) != 0)
171*49ef7e06SGarrett D'Amore 			goto fail1;
172*49ef7e06SGarrett D'Amore 		break;
173*49ef7e06SGarrett D'Amore 	default:
174*49ef7e06SGarrett D'Amore 		rc = EINVAL;
175*49ef7e06SGarrett D'Amore 		goto fail2;
176*49ef7e06SGarrett D'Amore 	}
177*49ef7e06SGarrett D'Amore 
178*49ef7e06SGarrett D'Amore 	return (0);
179*49ef7e06SGarrett D'Amore 
180*49ef7e06SGarrett D'Amore fail2:
181*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail2);
182*49ef7e06SGarrett D'Amore fail1:
183*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
184*49ef7e06SGarrett D'Amore 
185*49ef7e06SGarrett D'Amore 	return (rc);
186*49ef7e06SGarrett D'Amore }
187