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/ddi.h>
33*49ef7e06SGarrett D'Amore #include <sys/sunddi.h>
34*49ef7e06SGarrett D'Amore #include <sys/stream.h>
35*49ef7e06SGarrett D'Amore #include <sys/dlpi.h>
36*49ef7e06SGarrett D'Amore 
37*49ef7e06SGarrett D'Amore #include "sfxge.h"
38*49ef7e06SGarrett D'Amore 
39*49ef7e06SGarrett D'Amore static int
sfxge_nvram_rw(sfxge_t * sp,sfxge_nvram_ioc_t * snip,efx_nvram_type_t type,boolean_t write)40*49ef7e06SGarrett D'Amore sfxge_nvram_rw(sfxge_t *sp, sfxge_nvram_ioc_t *snip, efx_nvram_type_t type,
41*49ef7e06SGarrett D'Amore     boolean_t write)
42*49ef7e06SGarrett D'Amore {
43*49ef7e06SGarrett D'Amore 	int (*op)(efx_nic_t *, efx_nvram_type_t, unsigned int, caddr_t, size_t);
44*49ef7e06SGarrett D'Amore 	efx_nic_t *enp = sp->s_enp;
45*49ef7e06SGarrett D'Amore 	size_t chunk_size;
46*49ef7e06SGarrett D'Amore 	off_t off;
47*49ef7e06SGarrett D'Amore 	int rc;
48*49ef7e06SGarrett D'Amore 
49*49ef7e06SGarrett D'Amore 	op = (write) ? efx_nvram_write_chunk : efx_nvram_read_chunk;
50*49ef7e06SGarrett D'Amore 
51*49ef7e06SGarrett D'Amore 	if ((rc = efx_nvram_rw_start(enp, type, &chunk_size)) != 0)
52*49ef7e06SGarrett D'Amore 		goto fail1;
53*49ef7e06SGarrett D'Amore 
54*49ef7e06SGarrett D'Amore 	off = 0;
55*49ef7e06SGarrett D'Amore 	while (snip->sni_size) {
56*49ef7e06SGarrett D'Amore 		size_t len = MIN(chunk_size, snip->sni_size);
57*49ef7e06SGarrett D'Amore 		caddr_t buf = (caddr_t)(&snip->sni_data[off]);
58*49ef7e06SGarrett D'Amore 
59*49ef7e06SGarrett D'Amore 		if ((rc = op(enp, type, snip->sni_offset + off, buf, len)) != 0)
60*49ef7e06SGarrett D'Amore 			goto fail2;
61*49ef7e06SGarrett D'Amore 
62*49ef7e06SGarrett D'Amore 		snip->sni_size -= len;
63*49ef7e06SGarrett D'Amore 		off += len;
64*49ef7e06SGarrett D'Amore 	}
65*49ef7e06SGarrett D'Amore 
66*49ef7e06SGarrett D'Amore 	efx_nvram_rw_finish(enp, type);
67*49ef7e06SGarrett D'Amore 	return (0);
68*49ef7e06SGarrett D'Amore 
69*49ef7e06SGarrett D'Amore fail2:
70*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail2);
71*49ef7e06SGarrett D'Amore 	efx_nvram_rw_finish(enp, type);
72*49ef7e06SGarrett D'Amore fail1:
73*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
74*49ef7e06SGarrett D'Amore 	return (rc);
75*49ef7e06SGarrett D'Amore }
76*49ef7e06SGarrett D'Amore 
77*49ef7e06SGarrett D'Amore 
78*49ef7e06SGarrett D'Amore static int
sfxge_nvram_erase(sfxge_t * sp,sfxge_nvram_ioc_t * snip,efx_nvram_type_t type)79*49ef7e06SGarrett D'Amore sfxge_nvram_erase(sfxge_t *sp, sfxge_nvram_ioc_t *snip, efx_nvram_type_t type)
80*49ef7e06SGarrett D'Amore {
81*49ef7e06SGarrett D'Amore 	efx_nic_t *enp = sp->s_enp;
82*49ef7e06SGarrett D'Amore 	size_t chunk_size;
83*49ef7e06SGarrett D'Amore 	int rc;
84*49ef7e06SGarrett D'Amore 	_NOTE(ARGUNUSED(snip));
85*49ef7e06SGarrett D'Amore 
86*49ef7e06SGarrett D'Amore 	if ((rc = efx_nvram_rw_start(enp, type, &chunk_size)) != 0)
87*49ef7e06SGarrett D'Amore 		goto fail1;
88*49ef7e06SGarrett D'Amore 
89*49ef7e06SGarrett D'Amore 	if ((rc = efx_nvram_erase(enp, type)) != 0)
90*49ef7e06SGarrett D'Amore 		goto fail2;
91*49ef7e06SGarrett D'Amore 
92*49ef7e06SGarrett D'Amore 	efx_nvram_rw_finish(enp, type);
93*49ef7e06SGarrett D'Amore 	return (0);
94*49ef7e06SGarrett D'Amore 
95*49ef7e06SGarrett D'Amore fail2:
96*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail2);
97*49ef7e06SGarrett D'Amore 	efx_nvram_rw_finish(enp, type);
98*49ef7e06SGarrett D'Amore fail1:
99*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
100*49ef7e06SGarrett D'Amore 	return (rc);
101*49ef7e06SGarrett D'Amore }
102*49ef7e06SGarrett D'Amore 
103*49ef7e06SGarrett D'Amore int
sfxge_nvram_ioctl(sfxge_t * sp,sfxge_nvram_ioc_t * snip)104*49ef7e06SGarrett D'Amore sfxge_nvram_ioctl(sfxge_t *sp, sfxge_nvram_ioc_t *snip)
105*49ef7e06SGarrett D'Amore {
106*49ef7e06SGarrett D'Amore 	efx_nic_t *enp = sp->s_enp;
107*49ef7e06SGarrett D'Amore 	efx_nvram_type_t type;
108*49ef7e06SGarrett D'Amore 	int rc;
109*49ef7e06SGarrett D'Amore 
110*49ef7e06SGarrett D'Amore 	switch (snip->sni_type) {
111*49ef7e06SGarrett D'Amore 	case SFXGE_NVRAM_TYPE_BOOTROM:
112*49ef7e06SGarrett D'Amore 		type = EFX_NVRAM_BOOTROM;
113*49ef7e06SGarrett D'Amore 		break;
114*49ef7e06SGarrett D'Amore 	case SFXGE_NVRAM_TYPE_BOOTROM_CFG:
115*49ef7e06SGarrett D'Amore 		type = EFX_NVRAM_BOOTROM_CFG;
116*49ef7e06SGarrett D'Amore 		break;
117*49ef7e06SGarrett D'Amore 	case SFXGE_NVRAM_TYPE_MC:
118*49ef7e06SGarrett D'Amore 		type = EFX_NVRAM_MC_FIRMWARE;
119*49ef7e06SGarrett D'Amore 		break;
120*49ef7e06SGarrett D'Amore 	case SFXGE_NVRAM_TYPE_MC_GOLDEN:
121*49ef7e06SGarrett D'Amore 		type = EFX_NVRAM_MC_GOLDEN;
122*49ef7e06SGarrett D'Amore 		if (snip->sni_op == SFXGE_NVRAM_OP_WRITE ||
123*49ef7e06SGarrett D'Amore 		    snip->sni_op == SFXGE_NVRAM_OP_ERASE ||
124*49ef7e06SGarrett D'Amore 		    snip->sni_op == SFXGE_NVRAM_OP_SET_VER) {
125*49ef7e06SGarrett D'Amore 			rc = ENOTSUP;
126*49ef7e06SGarrett D'Amore 			goto fail1;
127*49ef7e06SGarrett D'Amore 		}
128*49ef7e06SGarrett D'Amore 		break;
129*49ef7e06SGarrett D'Amore 	case SFXGE_NVRAM_TYPE_PHY:
130*49ef7e06SGarrett D'Amore 		type = EFX_NVRAM_PHY;
131*49ef7e06SGarrett D'Amore 		break;
132*49ef7e06SGarrett D'Amore 	case SFXGE_NVRAM_TYPE_NULL_PHY:
133*49ef7e06SGarrett D'Amore 		type = EFX_NVRAM_NULLPHY;
134*49ef7e06SGarrett D'Amore 		break;
135*49ef7e06SGarrett D'Amore 	case SFXGE_NVRAM_TYPE_FPGA: /* PTP timestamping FPGA */
136*49ef7e06SGarrett D'Amore 		type = EFX_NVRAM_FPGA;
137*49ef7e06SGarrett D'Amore 		break;
138*49ef7e06SGarrett D'Amore 	case SFXGE_NVRAM_TYPE_FCFW:
139*49ef7e06SGarrett D'Amore 		type = EFX_NVRAM_FCFW;
140*49ef7e06SGarrett D'Amore 		break;
141*49ef7e06SGarrett D'Amore 	case SFXGE_NVRAM_TYPE_CPLD:
142*49ef7e06SGarrett D'Amore 		type = EFX_NVRAM_CPLD;
143*49ef7e06SGarrett D'Amore 		break;
144*49ef7e06SGarrett D'Amore 	case SFXGE_NVRAM_TYPE_FPGA_BACKUP:
145*49ef7e06SGarrett D'Amore 		type = EFX_NVRAM_FPGA_BACKUP;
146*49ef7e06SGarrett D'Amore 		break;
147*49ef7e06SGarrett D'Amore 	case SFXGE_NVRAM_TYPE_DYNAMIC_CFG:
148*49ef7e06SGarrett D'Amore 		type = EFX_NVRAM_DYNAMIC_CFG;
149*49ef7e06SGarrett D'Amore 		break;
150*49ef7e06SGarrett D'Amore 	default:
151*49ef7e06SGarrett D'Amore 		rc = EINVAL;
152*49ef7e06SGarrett D'Amore 		goto fail2;
153*49ef7e06SGarrett D'Amore 	}
154*49ef7e06SGarrett D'Amore 
155*49ef7e06SGarrett D'Amore 	if (snip->sni_size > sizeof (snip->sni_data)) {
156*49ef7e06SGarrett D'Amore 		rc = ENOSPC;
157*49ef7e06SGarrett D'Amore 		goto fail3;
158*49ef7e06SGarrett D'Amore 	}
159*49ef7e06SGarrett D'Amore 
160*49ef7e06SGarrett D'Amore 	switch (snip->sni_op) {
161*49ef7e06SGarrett D'Amore 	case SFXGE_NVRAM_OP_SIZE:
162*49ef7e06SGarrett D'Amore 	{
163*49ef7e06SGarrett D'Amore 		size_t size;
164*49ef7e06SGarrett D'Amore 		if ((rc = efx_nvram_size(enp, type, &size)) != 0)
165*49ef7e06SGarrett D'Amore 			goto fail4;
166*49ef7e06SGarrett D'Amore 		snip->sni_size = (uint32_t)size;
167*49ef7e06SGarrett D'Amore 		break;
168*49ef7e06SGarrett D'Amore 	}
169*49ef7e06SGarrett D'Amore 	case SFXGE_NVRAM_OP_READ:
170*49ef7e06SGarrett D'Amore 		if ((rc = sfxge_nvram_rw(sp, snip, type, B_FALSE)) != 0)
171*49ef7e06SGarrett D'Amore 			goto fail4;
172*49ef7e06SGarrett D'Amore 		break;
173*49ef7e06SGarrett D'Amore 	case SFXGE_NVRAM_OP_WRITE:
174*49ef7e06SGarrett D'Amore 		if ((rc = sfxge_nvram_rw(sp, snip, type, B_TRUE)) != 0)
175*49ef7e06SGarrett D'Amore 			goto fail4;
176*49ef7e06SGarrett D'Amore 		break;
177*49ef7e06SGarrett D'Amore 	case SFXGE_NVRAM_OP_ERASE:
178*49ef7e06SGarrett D'Amore 		if ((rc = sfxge_nvram_erase(sp, snip, type)) != 0)
179*49ef7e06SGarrett D'Amore 			goto fail4;
180*49ef7e06SGarrett D'Amore 		break;
181*49ef7e06SGarrett D'Amore 	case SFXGE_NVRAM_OP_GET_VER:
182*49ef7e06SGarrett D'Amore 		if ((rc = efx_nvram_get_version(enp, type, &snip->sni_subtype,
183*49ef7e06SGarrett D'Amore 		    &snip->sni_version[0])) != 0)
184*49ef7e06SGarrett D'Amore 			goto fail4;
185*49ef7e06SGarrett D'Amore 		break;
186*49ef7e06SGarrett D'Amore 	case SFXGE_NVRAM_OP_SET_VER:
187*49ef7e06SGarrett D'Amore 		if ((rc = efx_nvram_set_version(enp, type,
188*49ef7e06SGarrett D'Amore 		    &snip->sni_version[0])) != 0)
189*49ef7e06SGarrett D'Amore 			goto fail4;
190*49ef7e06SGarrett D'Amore 		break;
191*49ef7e06SGarrett D'Amore 	default:
192*49ef7e06SGarrett D'Amore 		rc = ENOTSUP;
193*49ef7e06SGarrett D'Amore 		goto fail5;
194*49ef7e06SGarrett D'Amore 	}
195*49ef7e06SGarrett D'Amore 
196*49ef7e06SGarrett D'Amore 	return (0);
197*49ef7e06SGarrett D'Amore 
198*49ef7e06SGarrett D'Amore fail5:
199*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail5);
200*49ef7e06SGarrett D'Amore fail4:
201*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail4);
202*49ef7e06SGarrett D'Amore fail3:
203*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail3);
204*49ef7e06SGarrett D'Amore fail2:
205*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail2);
206*49ef7e06SGarrett D'Amore fail1:
207*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
208*49ef7e06SGarrett D'Amore 
209*49ef7e06SGarrett D'Amore 	return (rc);
210*49ef7e06SGarrett D'Amore }
211