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
36static int
37sfxge_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
74fail4:
75	DTRACE_PROBE(fail4);
76fail3:
77	DTRACE_PROBE(fail3);
78fail2:
79	DTRACE_PROBE(fail2);
80	kmem_free(buf, size);
81fail1:
82	DTRACE_PROBE1(fail1, int, rc);
83
84	return (rc);
85}
86
87
88static int
89sfxge_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
139fail7:
140	DTRACE_PROBE(fail7);
141fail6:
142	DTRACE_PROBE(fail6);
143fail5:
144	DTRACE_PROBE(fail5);
145fail4:
146	DTRACE_PROBE(fail4);
147fail3:
148	DTRACE_PROBE(fail3);
149fail2:
150	DTRACE_PROBE(fail2);
151	kmem_free(buf, size);
152fail1:
153	DTRACE_PROBE1(fail1, int, rc);
154
155	return (rc);
156}
157
158
159int
160sfxge_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
180fail2:
181	DTRACE_PROBE(fail2);
182fail1:
183	DTRACE_PROBE1(fail1, int, rc);
184
185	return (rc);
186}
187