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