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