1255570Strasz/*-
2255570Strasz * Copyright (c) 2010-2016 Solarflare Communications, Inc.
3255570Strasz * All rights reserved.
4255570Strasz *
5255570Strasz * This software was developed in part by OKTET Labs Ltd. under contract for
6255570Strasz * Solarflare Communications, Inc.
7255570Strasz *
8255570Strasz * Redistribution and use in source and binary forms, with or without
9255570Strasz * modification, are permitted provided that the following conditions
10255570Strasz * are met:
11255570Strasz * 1. Redistributions of source code must retain the above copyright
12255570Strasz *    notice, this list of conditions and the following disclaimer.
13255570Strasz * 2. Redistributions in binary form must reproduce the above copyright
14255570Strasz *    notice, this list of conditions and the following disclaimer in the
15255570Strasz *    documentation and/or other materials provided with the distribution.
16255570Strasz *
17255570Strasz * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18255570Strasz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19255570Strasz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20255570Strasz * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21255570Strasz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22255570Strasz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23255570Strasz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24255570Strasz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25255570Strasz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26255570Strasz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27255570Strasz * SUCH DAMAGE.
28255570Strasz */
29255570Strasz
30255570Strasz#include <sys/cdefs.h>
31270279Strasz__FBSDID("$FreeBSD$");
32270279Strasz
33270279Strasz
34255570Strasz#include <sys/types.h>
35255570Strasz#include <sys/malloc.h>
36255570Strasz
37255570Strasz#include "common/efx.h"
38255570Strasz#include "sfxge.h"
39255570Strasz
40267606Smav/* These data make no real sense, they are here just to make sfupdate happy.
41267606Smav * Any code that would rely on it is broken.
42255570Strasz */
43255570Straszstatic const uint8_t fake_dynamic_cfg_nvram[] = {
44255570Strasz	0x7a, 0xda, 0x10, 0xef, 0x0c, 0x00, 0x00, 0x00,
45255570Strasz	0x00, 0x05, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
46255570Strasz	0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x10,
47255570Strasz	0x08, 0x00, 0x00, 0x00, 0x90, 0x04, 0x00, 0x52,
48255570Strasz	0x56, 0x01, 0xc3, 0x78, 0x01, 0x00, 0x03, 0x10,
49255570Strasz	0x08, 0x00, 0x00, 0x00, 0x90, 0x04, 0x00, 0x52,
50255570Strasz	0x56, 0x01, 0xc3, 0x78, 0x57, 0x1a, 0x10, 0xef,
51255570Strasz	0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
52255570Strasz	0x02, 0x0b, 0x64, 0x7d, 0xee, 0xee, 0xee, 0xee
53255570Strasz};
54255570Strasz
55255570Straszstatic int
56255570Straszsfxge_nvram_rw(struct sfxge_softc *sc, sfxge_ioc_t *ip, efx_nvram_type_t type,
57255570Strasz	       boolean_t write)
58255570Strasz{
59255570Strasz	efx_nic_t *enp = sc->enp;
60255570Strasz	size_t total_size = ip->u.nvram.size;
61255570Strasz	size_t chunk_size;
62255570Strasz	off_t off;
63255570Strasz	int rc = 0;
64255570Strasz	uint8_t *buf;
65255570Strasz
66255570Strasz	if (type == EFX_NVRAM_DYNAMIC_CFG && sc->family == EFX_FAMILY_SIENA) {
67255570Strasz		if (write)
68255570Strasz			return (0);
69255570Strasz		rc = copyout(fake_dynamic_cfg_nvram, ip->u.nvram.data,
70255570Strasz			     MIN(total_size, sizeof(fake_dynamic_cfg_nvram)));
71255570Strasz		return (rc);
72255570Strasz	}
73255570Strasz
74255570Strasz	if ((rc = efx_nvram_rw_start(enp, type, &chunk_size)) != 0)
75255570Strasz		goto fail1;
76255570Strasz
77255570Strasz	buf = malloc(chunk_size, M_TEMP, M_WAITOK);
78255570Strasz
79255570Strasz	off = 0;
80255570Strasz	while (total_size) {
81255570Strasz		size_t len = MIN(chunk_size, total_size);
82255570Strasz
83255570Strasz		if (write) {
84255570Strasz			rc = copyin(ip->u.nvram.data + off, buf, len);
85255570Strasz			if (rc != 0)
86255570Strasz				goto fail3;
87255570Strasz			rc = efx_nvram_write_chunk(enp, type,
88255570Strasz						   ip->u.nvram.offset + off, buf, len);
89255570Strasz			if (rc != 0)
90255570Strasz				goto fail3;
91255570Strasz		} else {
92255570Strasz			rc = efx_nvram_read_chunk(enp, type,
93255570Strasz						  ip->u.nvram.offset + off, buf, len);
94255570Strasz			if (rc != 0)
95255570Strasz				goto fail3;
96255570Strasz			rc = copyout(buf, ip->u.nvram.data + off, len);
97255570Strasz			if (rc != 0)
98255570Strasz				goto fail3;
99255570Strasz		}
100255570Strasz
101255570Strasz		total_size -= len;
102255570Strasz		off += len;
103255570Strasz	}
104255570Strasz
105255570Straszfail3:
106255570Strasz	free(buf, M_TEMP);
107255570Strasz	efx_nvram_rw_finish(enp, type);
108255570Straszfail1:
109255570Strasz	return (rc);
110255570Strasz}
111255570Strasz
112255570Strasz
113255570Straszstatic int
114255570Straszsfxge_nvram_erase(struct sfxge_softc *sc, efx_nvram_type_t type)
115255570Strasz{
116255570Strasz	efx_nic_t *enp = sc->enp;
117255570Strasz	size_t chunk_size;
118255570Strasz	int rc = 0;
119255570Strasz
120255570Strasz	if (type == EFX_NVRAM_DYNAMIC_CFG && sc->family == EFX_FAMILY_SIENA)
121255570Strasz		return (0);
122255570Strasz
123255570Strasz	if ((rc = efx_nvram_rw_start(enp, type, &chunk_size)) != 0)
124255570Strasz		return (rc);
125255570Strasz
126255570Strasz	rc = efx_nvram_erase(enp, type);
127255570Strasz
128255570Strasz	efx_nvram_rw_finish(enp, type);
129255570Strasz	return (rc);
130255570Strasz}
131255570Strasz
132255570Straszint
133255570Straszsfxge_nvram_ioctl(struct sfxge_softc *sc, sfxge_ioc_t *ip)
134255570Strasz{
135255570Strasz	static const efx_nvram_type_t nvram_types[] = {
136255570Strasz		[SFXGE_NVRAM_TYPE_BOOTROM]  = EFX_NVRAM_BOOTROM,
137255570Strasz		[SFXGE_NVRAM_TYPE_BOOTROM_CFG]  = EFX_NVRAM_BOOTROM_CFG,
138255570Strasz		[SFXGE_NVRAM_TYPE_MC]  = EFX_NVRAM_MC_FIRMWARE,
139255570Strasz		[SFXGE_NVRAM_TYPE_MC_GOLDEN]  = EFX_NVRAM_MC_GOLDEN,
140255570Strasz		[SFXGE_NVRAM_TYPE_PHY]  = EFX_NVRAM_PHY,
141255570Strasz		[SFXGE_NVRAM_TYPE_NULL_PHY]  = EFX_NVRAM_NULLPHY,
142255570Strasz		[SFXGE_NVRAM_TYPE_FPGA]  = EFX_NVRAM_FPGA,
143255570Strasz		[SFXGE_NVRAM_TYPE_FCFW]  = EFX_NVRAM_FCFW,
144255570Strasz		[SFXGE_NVRAM_TYPE_CPLD]  = EFX_NVRAM_CPLD,
145255570Strasz		[SFXGE_NVRAM_TYPE_FPGA_BACKUP]  = EFX_NVRAM_FPGA_BACKUP,
146255570Strasz		[SFXGE_NVRAM_TYPE_DYNAMIC_CFG]  = EFX_NVRAM_DYNAMIC_CFG,
147255570Strasz	};
148255570Strasz
149255570Strasz	efx_nic_t *enp = sc->enp;
150255570Strasz	efx_nvram_type_t type;
151255570Strasz	int rc = 0;
152255570Strasz
153255570Strasz	if (ip->u.nvram.type > SFXGE_NVRAM_TYPE_DYNAMIC_CFG)
154255570Strasz		return (EINVAL);
155255570Strasz	type = nvram_types[ip->u.nvram.type];
156255570Strasz	if (type == EFX_NVRAM_MC_GOLDEN &&
157255570Strasz	    (ip->u.nvram.op == SFXGE_NVRAM_OP_WRITE ||
158255570Strasz	     ip->u.nvram.op == SFXGE_NVRAM_OP_ERASE ||
159255570Strasz	     ip->u.nvram.op == SFXGE_NVRAM_OP_SET_VER))
160255570Strasz		return (EOPNOTSUPP);
161255570Strasz
162267606Smav	switch (ip->u.nvram.op) {
163273543Strasz	case SFXGE_NVRAM_OP_SIZE:
164267606Smav	{
165267606Smav		size_t size;
166267606Smav
167267606Smav		if (type == EFX_NVRAM_DYNAMIC_CFG && sc->family == EFX_FAMILY_SIENA) {
168267606Smav			ip->u.nvram.size = sizeof(fake_dynamic_cfg_nvram);
169267606Smav		} else {
170267606Smav			if ((rc = efx_nvram_size(enp, type, &size)) != 0)
171267606Smav				return (rc);
172267606Smav			ip->u.nvram.size = size;
173267606Smav		}
174267606Smav		break;
175267606Smav	}
176267606Smav	case SFXGE_NVRAM_OP_READ:
177267606Smav		rc = sfxge_nvram_rw(sc, ip, type, B_FALSE);
178267606Smav		break;
179267606Smav	case SFXGE_NVRAM_OP_WRITE:
180267606Smav		rc = sfxge_nvram_rw(sc, ip, type, B_TRUE);
181267606Smav		break;
182267606Smav	case SFXGE_NVRAM_OP_ERASE:
183267606Smav		rc = sfxge_nvram_erase(sc, type);
184267606Smav		break;
185267606Smav	case SFXGE_NVRAM_OP_GET_VER:
186267606Smav		rc = efx_nvram_get_version(enp, type, &ip->u.nvram.subtype,
187267606Smav					   &ip->u.nvram.version[0]);
188267606Smav		break;
189267606Smav	case SFXGE_NVRAM_OP_SET_VER:
190267606Smav		rc = efx_nvram_set_version(enp, type, &ip->u.nvram.version[0]);
191267606Smav		break;
192267606Smav	default:
193267606Smav		rc = EOPNOTSUPP;
194267606Smav		break;
195267606Smav	}
196267606Smav
197267606Smav	return (rc);
198267606Smav}
199267606Smav