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