1*9e39c5baSBill Taylor /* 2*9e39c5baSBill Taylor * CDDL HEADER START 3*9e39c5baSBill Taylor * 4*9e39c5baSBill Taylor * The contents of this file are subject to the terms of the 5*9e39c5baSBill Taylor * Common Development and Distribution License (the "License"). 6*9e39c5baSBill Taylor * You may not use this file except in compliance with the License. 7*9e39c5baSBill Taylor * 8*9e39c5baSBill Taylor * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*9e39c5baSBill Taylor * or http://www.opensolaris.org/os/licensing. 10*9e39c5baSBill Taylor * See the License for the specific language governing permissions 11*9e39c5baSBill Taylor * and limitations under the License. 12*9e39c5baSBill Taylor * 13*9e39c5baSBill Taylor * When distributing Covered Code, include this CDDL HEADER in each 14*9e39c5baSBill Taylor * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*9e39c5baSBill Taylor * If applicable, add the following below this CDDL HEADER, with the 16*9e39c5baSBill Taylor * fields enclosed by brackets "[]" replaced with your own identifying 17*9e39c5baSBill Taylor * information: Portions Copyright [yyyy] [name of copyright owner] 18*9e39c5baSBill Taylor * 19*9e39c5baSBill Taylor * CDDL HEADER END 20*9e39c5baSBill Taylor */ 21*9e39c5baSBill Taylor 22*9e39c5baSBill Taylor /* 23*9e39c5baSBill Taylor * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24*9e39c5baSBill Taylor * Use is subject to license terms. 25*9e39c5baSBill Taylor */ 26*9e39c5baSBill Taylor 27*9e39c5baSBill Taylor /* 28*9e39c5baSBill Taylor * hermon_ioctl.c 29*9e39c5baSBill Taylor * Hemron IOCTL Routines 30*9e39c5baSBill Taylor * 31*9e39c5baSBill Taylor * Implements all ioctl access into the driver. This includes all routines 32*9e39c5baSBill Taylor * necessary for updating firmware, accessing the hermon flash device, and 33*9e39c5baSBill Taylor * providing interfaces for VTS. 34*9e39c5baSBill Taylor */ 35*9e39c5baSBill Taylor 36*9e39c5baSBill Taylor #include <sys/types.h> 37*9e39c5baSBill Taylor #include <sys/conf.h> 38*9e39c5baSBill Taylor #include <sys/ddi.h> 39*9e39c5baSBill Taylor #include <sys/sunddi.h> 40*9e39c5baSBill Taylor #include <sys/modctl.h> 41*9e39c5baSBill Taylor #include <sys/file.h> 42*9e39c5baSBill Taylor 43*9e39c5baSBill Taylor #include <sys/ib/adapters/hermon/hermon.h> 44*9e39c5baSBill Taylor 45*9e39c5baSBill Taylor /* Hemron HCA state pointer (extern) */ 46*9e39c5baSBill Taylor extern void *hermon_statep; 47*9e39c5baSBill Taylor extern int hermon_verbose; 48*9e39c5baSBill Taylor 49*9e39c5baSBill Taylor #define DO_WRCONF 1 50*9e39c5baSBill Taylor static int do_bar0 = 1; 51*9e39c5baSBill Taylor 52*9e39c5baSBill Taylor /* 53*9e39c5baSBill Taylor * The ioctl declarations (for firmware flash burning, register read/write 54*9e39c5baSBill Taylor * (DEBUG-only), and VTS interfaces) 55*9e39c5baSBill Taylor */ 56*9e39c5baSBill Taylor static int hermon_ioctl_flash_read(hermon_state_t *state, dev_t dev, 57*9e39c5baSBill Taylor intptr_t arg, int mode); 58*9e39c5baSBill Taylor static int hermon_ioctl_flash_write(hermon_state_t *state, dev_t dev, 59*9e39c5baSBill Taylor intptr_t arg, int mode); 60*9e39c5baSBill Taylor static int hermon_ioctl_flash_erase(hermon_state_t *state, dev_t dev, 61*9e39c5baSBill Taylor intptr_t arg, int mode); 62*9e39c5baSBill Taylor static int hermon_ioctl_flash_init(hermon_state_t *state, dev_t dev, 63*9e39c5baSBill Taylor intptr_t arg, int mode); 64*9e39c5baSBill Taylor static int hermon_ioctl_flash_fini(hermon_state_t *state, dev_t dev); 65*9e39c5baSBill Taylor static int hermon_ioctl_flash_cleanup(hermon_state_t *state); 66*9e39c5baSBill Taylor static int hermon_ioctl_flash_cleanup_nolock(hermon_state_t *state); 67*9e39c5baSBill Taylor #ifdef DEBUG 68*9e39c5baSBill Taylor static int hermon_ioctl_reg_write(hermon_state_t *state, intptr_t arg, 69*9e39c5baSBill Taylor int mode); 70*9e39c5baSBill Taylor static int hermon_ioctl_reg_read(hermon_state_t *state, intptr_t arg, 71*9e39c5baSBill Taylor int mode); 72*9e39c5baSBill Taylor #endif /* DEBUG */ 73*9e39c5baSBill Taylor static int hermon_ioctl_write_boot_addr(hermon_state_t *state, dev_t dev, 74*9e39c5baSBill Taylor intptr_t arg, int mode); 75*9e39c5baSBill Taylor static int hermon_ioctl_info(hermon_state_t *state, dev_t dev, 76*9e39c5baSBill Taylor intptr_t arg, int mode); 77*9e39c5baSBill Taylor static int hermon_ioctl_ports(hermon_state_t *state, intptr_t arg, 78*9e39c5baSBill Taylor int mode); 79*9e39c5baSBill Taylor static int hermon_ioctl_loopback(hermon_state_t *state, intptr_t arg, 80*9e39c5baSBill Taylor int mode); 81*9e39c5baSBill Taylor 82*9e39c5baSBill Taylor /* Hemron Flash Functions */ 83*9e39c5baSBill Taylor static void hermon_flash_spi_exec_command(hermon_state_t *state, 84*9e39c5baSBill Taylor ddi_acc_handle_t hdl, uint32_t cmd); 85*9e39c5baSBill Taylor static int hermon_flash_read_sector(hermon_state_t *state, 86*9e39c5baSBill Taylor uint32_t sector_num); 87*9e39c5baSBill Taylor static int hermon_flash_read_quadlet(hermon_state_t *state, uint32_t *data, 88*9e39c5baSBill Taylor uint32_t addr); 89*9e39c5baSBill Taylor static int hermon_flash_write_sector(hermon_state_t *state, 90*9e39c5baSBill Taylor uint32_t sector_num); 91*9e39c5baSBill Taylor static int hermon_flash_spi_write_dword(hermon_state_t *state, 92*9e39c5baSBill Taylor uint32_t addr, uint32_t data); 93*9e39c5baSBill Taylor static int hermon_flash_write_byte(hermon_state_t *state, uint32_t addr, 94*9e39c5baSBill Taylor uchar_t data); 95*9e39c5baSBill Taylor static int hermon_flash_erase_sector(hermon_state_t *state, 96*9e39c5baSBill Taylor uint32_t sector_num); 97*9e39c5baSBill Taylor static int hermon_flash_erase_chip(hermon_state_t *state); 98*9e39c5baSBill Taylor static int hermon_flash_bank(hermon_state_t *state, uint32_t addr); 99*9e39c5baSBill Taylor static uint32_t hermon_flash_read(hermon_state_t *state, uint32_t addr, 100*9e39c5baSBill Taylor int *err); 101*9e39c5baSBill Taylor static void hermon_flash_write(hermon_state_t *state, uint32_t addr, 102*9e39c5baSBill Taylor uchar_t data, int *err); 103*9e39c5baSBill Taylor static int hermon_flash_spi_wait_wip(hermon_state_t *state); 104*9e39c5baSBill Taylor static void hermon_flash_spi_write_enable(hermon_state_t *state); 105*9e39c5baSBill Taylor static int hermon_flash_init(hermon_state_t *state); 106*9e39c5baSBill Taylor static int hermon_flash_cfi_init(hermon_state_t *state, uint32_t *cfi_info, 107*9e39c5baSBill Taylor int *intel_xcmd); 108*9e39c5baSBill Taylor static int hermon_flash_fini(hermon_state_t *state); 109*9e39c5baSBill Taylor static int hermon_flash_reset(hermon_state_t *state); 110*9e39c5baSBill Taylor static uint32_t hermon_flash_read_cfg(hermon_state_t *state, 111*9e39c5baSBill Taylor ddi_acc_handle_t pci_config_hdl, uint32_t addr); 112*9e39c5baSBill Taylor #ifdef DO_WRCONF 113*9e39c5baSBill Taylor static void hermon_flash_write_cfg(hermon_state_t *state, 114*9e39c5baSBill Taylor ddi_acc_handle_t pci_config_hdl, uint32_t addr, uint32_t data); 115*9e39c5baSBill Taylor static void hermon_flash_write_cfg_helper(hermon_state_t *state, 116*9e39c5baSBill Taylor ddi_acc_handle_t pci_config_hdl, uint32_t addr, uint32_t data); 117*9e39c5baSBill Taylor static void hermon_flash_write_confirm(hermon_state_t *state, 118*9e39c5baSBill Taylor ddi_acc_handle_t pci_config_hdl); 119*9e39c5baSBill Taylor #endif 120*9e39c5baSBill Taylor static void hermon_flash_cfi_byte(uint8_t *ch, uint32_t dword, int i); 121*9e39c5baSBill Taylor static void hermon_flash_cfi_dword(uint32_t *dword, uint8_t *ch, int i); 122*9e39c5baSBill Taylor 123*9e39c5baSBill Taylor /* Hemron loopback test functions */ 124*9e39c5baSBill Taylor static void hermon_loopback_free_qps(hermon_loopback_state_t *lstate); 125*9e39c5baSBill Taylor static void hermon_loopback_free_state(hermon_loopback_state_t *lstate); 126*9e39c5baSBill Taylor static int hermon_loopback_init(hermon_state_t *state, 127*9e39c5baSBill Taylor hermon_loopback_state_t *lstate); 128*9e39c5baSBill Taylor static void hermon_loopback_init_qp_info(hermon_loopback_state_t *lstate, 129*9e39c5baSBill Taylor hermon_loopback_comm_t *comm); 130*9e39c5baSBill Taylor static int hermon_loopback_alloc_mem(hermon_loopback_state_t *lstate, 131*9e39c5baSBill Taylor hermon_loopback_comm_t *comm, int sz); 132*9e39c5baSBill Taylor static int hermon_loopback_alloc_qps(hermon_loopback_state_t *lstate, 133*9e39c5baSBill Taylor hermon_loopback_comm_t *comm); 134*9e39c5baSBill Taylor static int hermon_loopback_modify_qp(hermon_loopback_state_t *lstate, 135*9e39c5baSBill Taylor hermon_loopback_comm_t *comm, uint_t qp_num); 136*9e39c5baSBill Taylor static int hermon_loopback_copyout(hermon_loopback_ioctl_t *lb, 137*9e39c5baSBill Taylor intptr_t arg, int mode); 138*9e39c5baSBill Taylor static int hermon_loopback_post_send(hermon_loopback_state_t *lstate, 139*9e39c5baSBill Taylor hermon_loopback_comm_t *tx, hermon_loopback_comm_t *rx); 140*9e39c5baSBill Taylor static int hermon_loopback_poll_cq(hermon_loopback_state_t *lstate, 141*9e39c5baSBill Taylor hermon_loopback_comm_t *comm); 142*9e39c5baSBill Taylor 143*9e39c5baSBill Taylor /* Patchable timeout values for flash operations */ 144*9e39c5baSBill Taylor int hermon_hw_flash_timeout_gpio_sema = HERMON_HW_FLASH_TIMEOUT_GPIO_SEMA; 145*9e39c5baSBill Taylor int hermon_hw_flash_timeout_config = HERMON_HW_FLASH_TIMEOUT_CONFIG; 146*9e39c5baSBill Taylor int hermon_hw_flash_timeout_write = HERMON_HW_FLASH_TIMEOUT_WRITE; 147*9e39c5baSBill Taylor int hermon_hw_flash_timeout_erase = HERMON_HW_FLASH_TIMEOUT_ERASE; 148*9e39c5baSBill Taylor 149*9e39c5baSBill Taylor /* 150*9e39c5baSBill Taylor * hermon_ioctl() 151*9e39c5baSBill Taylor */ 152*9e39c5baSBill Taylor /* ARGSUSED */ 153*9e39c5baSBill Taylor int 154*9e39c5baSBill Taylor hermon_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 155*9e39c5baSBill Taylor int *rvalp) 156*9e39c5baSBill Taylor { 157*9e39c5baSBill Taylor hermon_state_t *state; 158*9e39c5baSBill Taylor minor_t instance; 159*9e39c5baSBill Taylor int status; 160*9e39c5baSBill Taylor 161*9e39c5baSBill Taylor if (drv_priv(credp) != 0) { 162*9e39c5baSBill Taylor return (EPERM); 163*9e39c5baSBill Taylor } 164*9e39c5baSBill Taylor 165*9e39c5baSBill Taylor instance = HERMON_DEV_INSTANCE(dev); 166*9e39c5baSBill Taylor if (instance == (minor_t)-1) { 167*9e39c5baSBill Taylor return (EBADF); 168*9e39c5baSBill Taylor } 169*9e39c5baSBill Taylor 170*9e39c5baSBill Taylor state = ddi_get_soft_state(hermon_statep, instance); 171*9e39c5baSBill Taylor if (state == NULL) { 172*9e39c5baSBill Taylor return (EBADF); 173*9e39c5baSBill Taylor } 174*9e39c5baSBill Taylor 175*9e39c5baSBill Taylor status = 0; 176*9e39c5baSBill Taylor 177*9e39c5baSBill Taylor switch (cmd) { 178*9e39c5baSBill Taylor case HERMON_IOCTL_FLASH_READ: 179*9e39c5baSBill Taylor status = hermon_ioctl_flash_read(state, dev, arg, mode); 180*9e39c5baSBill Taylor break; 181*9e39c5baSBill Taylor 182*9e39c5baSBill Taylor case HERMON_IOCTL_FLASH_WRITE: 183*9e39c5baSBill Taylor status = hermon_ioctl_flash_write(state, dev, arg, mode); 184*9e39c5baSBill Taylor break; 185*9e39c5baSBill Taylor 186*9e39c5baSBill Taylor case HERMON_IOCTL_FLASH_ERASE: 187*9e39c5baSBill Taylor status = hermon_ioctl_flash_erase(state, dev, arg, mode); 188*9e39c5baSBill Taylor break; 189*9e39c5baSBill Taylor 190*9e39c5baSBill Taylor case HERMON_IOCTL_FLASH_INIT: 191*9e39c5baSBill Taylor status = hermon_ioctl_flash_init(state, dev, arg, mode); 192*9e39c5baSBill Taylor break; 193*9e39c5baSBill Taylor 194*9e39c5baSBill Taylor case HERMON_IOCTL_FLASH_FINI: 195*9e39c5baSBill Taylor status = hermon_ioctl_flash_fini(state, dev); 196*9e39c5baSBill Taylor break; 197*9e39c5baSBill Taylor 198*9e39c5baSBill Taylor case HERMON_IOCTL_INFO: 199*9e39c5baSBill Taylor status = hermon_ioctl_info(state, dev, arg, mode); 200*9e39c5baSBill Taylor break; 201*9e39c5baSBill Taylor 202*9e39c5baSBill Taylor case HERMON_IOCTL_PORTS: 203*9e39c5baSBill Taylor status = hermon_ioctl_ports(state, arg, mode); 204*9e39c5baSBill Taylor break; 205*9e39c5baSBill Taylor 206*9e39c5baSBill Taylor case HERMON_IOCTL_LOOPBACK: 207*9e39c5baSBill Taylor status = hermon_ioctl_loopback(state, arg, mode); 208*9e39c5baSBill Taylor break; 209*9e39c5baSBill Taylor 210*9e39c5baSBill Taylor #ifdef DEBUG 211*9e39c5baSBill Taylor case HERMON_IOCTL_REG_WRITE: 212*9e39c5baSBill Taylor status = hermon_ioctl_reg_write(state, arg, mode); 213*9e39c5baSBill Taylor break; 214*9e39c5baSBill Taylor 215*9e39c5baSBill Taylor case HERMON_IOCTL_REG_READ: 216*9e39c5baSBill Taylor status = hermon_ioctl_reg_read(state, arg, mode); 217*9e39c5baSBill Taylor break; 218*9e39c5baSBill Taylor #endif /* DEBUG */ 219*9e39c5baSBill Taylor 220*9e39c5baSBill Taylor case HERMON_IOCTL_DDR_READ: 221*9e39c5baSBill Taylor /* XXX guard until the ioctl header is cleaned up */ 222*9e39c5baSBill Taylor status = ENODEV; 223*9e39c5baSBill Taylor break; 224*9e39c5baSBill Taylor 225*9e39c5baSBill Taylor case HERMON_IOCTL_WRITE_BOOT_ADDR: 226*9e39c5baSBill Taylor status = hermon_ioctl_write_boot_addr(state, dev, arg, mode); 227*9e39c5baSBill Taylor break; 228*9e39c5baSBill Taylor 229*9e39c5baSBill Taylor default: 230*9e39c5baSBill Taylor status = ENOTTY; 231*9e39c5baSBill Taylor break; 232*9e39c5baSBill Taylor } 233*9e39c5baSBill Taylor *rvalp = status; 234*9e39c5baSBill Taylor 235*9e39c5baSBill Taylor return (status); 236*9e39c5baSBill Taylor } 237*9e39c5baSBill Taylor 238*9e39c5baSBill Taylor /* 239*9e39c5baSBill Taylor * hermon_ioctl_flash_read() 240*9e39c5baSBill Taylor */ 241*9e39c5baSBill Taylor static int 242*9e39c5baSBill Taylor hermon_ioctl_flash_read(hermon_state_t *state, dev_t dev, intptr_t arg, 243*9e39c5baSBill Taylor int mode) 244*9e39c5baSBill Taylor { 245*9e39c5baSBill Taylor hermon_flash_ioctl_t ioctl_info; 246*9e39c5baSBill Taylor int status = 0; 247*9e39c5baSBill Taylor 248*9e39c5baSBill Taylor /* 249*9e39c5baSBill Taylor * Check that flash init ioctl has been called first. And check 250*9e39c5baSBill Taylor * that the same dev_t that called init is the one calling read now. 251*9e39c5baSBill Taylor */ 252*9e39c5baSBill Taylor mutex_enter(&state->hs_fw_flashlock); 253*9e39c5baSBill Taylor if ((state->hs_fw_flashdev != dev) || 254*9e39c5baSBill Taylor (state->hs_fw_flashstarted == 0)) { 255*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 256*9e39c5baSBill Taylor return (EIO); 257*9e39c5baSBill Taylor } 258*9e39c5baSBill Taylor 259*9e39c5baSBill Taylor /* copy user struct to kernel */ 260*9e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL 261*9e39c5baSBill Taylor if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 262*9e39c5baSBill Taylor hermon_flash_ioctl32_t info32; 263*9e39c5baSBill Taylor 264*9e39c5baSBill Taylor if (ddi_copyin((void *)arg, &info32, 265*9e39c5baSBill Taylor sizeof (hermon_flash_ioctl32_t), mode) != 0) { 266*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 267*9e39c5baSBill Taylor return (EFAULT); 268*9e39c5baSBill Taylor } 269*9e39c5baSBill Taylor ioctl_info.af_type = info32.af_type; 270*9e39c5baSBill Taylor ioctl_info.af_sector = (caddr_t)(uintptr_t)info32.af_sector; 271*9e39c5baSBill Taylor ioctl_info.af_sector_num = info32.af_sector_num; 272*9e39c5baSBill Taylor ioctl_info.af_addr = info32.af_addr; 273*9e39c5baSBill Taylor } else 274*9e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */ 275*9e39c5baSBill Taylor if (ddi_copyin((void *)arg, &ioctl_info, sizeof (hermon_flash_ioctl_t), 276*9e39c5baSBill Taylor mode) != 0) { 277*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 278*9e39c5baSBill Taylor return (EFAULT); 279*9e39c5baSBill Taylor } 280*9e39c5baSBill Taylor 281*9e39c5baSBill Taylor /* 282*9e39c5baSBill Taylor * Determine type of READ ioctl 283*9e39c5baSBill Taylor */ 284*9e39c5baSBill Taylor switch (ioctl_info.af_type) { 285*9e39c5baSBill Taylor case HERMON_FLASH_READ_SECTOR: 286*9e39c5baSBill Taylor /* Check if sector num is too large for flash device */ 287*9e39c5baSBill Taylor if (ioctl_info.af_sector_num >= 288*9e39c5baSBill Taylor (state->hs_fw_device_sz >> state->hs_fw_log_sector_sz)) { 289*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 290*9e39c5baSBill Taylor return (EFAULT); 291*9e39c5baSBill Taylor } 292*9e39c5baSBill Taylor 293*9e39c5baSBill Taylor /* Perform the Sector Read */ 294*9e39c5baSBill Taylor if ((status = hermon_flash_reset(state)) != 0 || 295*9e39c5baSBill Taylor (status = hermon_flash_read_sector(state, 296*9e39c5baSBill Taylor ioctl_info.af_sector_num)) != 0) { 297*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 298*9e39c5baSBill Taylor return (status); 299*9e39c5baSBill Taylor } 300*9e39c5baSBill Taylor 301*9e39c5baSBill Taylor /* copyout the firmware sector image data */ 302*9e39c5baSBill Taylor if (ddi_copyout(&state->hs_fw_sector[0], 303*9e39c5baSBill Taylor &ioctl_info.af_sector[0], 1 << state->hs_fw_log_sector_sz, 304*9e39c5baSBill Taylor mode) != 0) { 305*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 306*9e39c5baSBill Taylor return (EFAULT); 307*9e39c5baSBill Taylor } 308*9e39c5baSBill Taylor break; 309*9e39c5baSBill Taylor 310*9e39c5baSBill Taylor case HERMON_FLASH_READ_QUADLET: 311*9e39c5baSBill Taylor /* Check if addr is too large for flash device */ 312*9e39c5baSBill Taylor if (ioctl_info.af_addr >= state->hs_fw_device_sz) { 313*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 314*9e39c5baSBill Taylor return (EFAULT); 315*9e39c5baSBill Taylor } 316*9e39c5baSBill Taylor 317*9e39c5baSBill Taylor /* Perform the Quadlet Read */ 318*9e39c5baSBill Taylor if ((status = hermon_flash_reset(state)) != 0 || 319*9e39c5baSBill Taylor (status = hermon_flash_read_quadlet(state, 320*9e39c5baSBill Taylor &ioctl_info.af_quadlet, ioctl_info.af_addr)) != 0) { 321*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 322*9e39c5baSBill Taylor return (status); 323*9e39c5baSBill Taylor } 324*9e39c5baSBill Taylor break; 325*9e39c5baSBill Taylor 326*9e39c5baSBill Taylor default: 327*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 328*9e39c5baSBill Taylor return (EINVAL); 329*9e39c5baSBill Taylor } 330*9e39c5baSBill Taylor 331*9e39c5baSBill Taylor /* copy results back to userland */ 332*9e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL 333*9e39c5baSBill Taylor if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 334*9e39c5baSBill Taylor hermon_flash_ioctl32_t info32; 335*9e39c5baSBill Taylor 336*9e39c5baSBill Taylor info32.af_quadlet = ioctl_info.af_quadlet; 337*9e39c5baSBill Taylor info32.af_type = ioctl_info.af_type; 338*9e39c5baSBill Taylor info32.af_sector_num = ioctl_info.af_sector_num; 339*9e39c5baSBill Taylor info32.af_sector = (caddr32_t)(uintptr_t)ioctl_info.af_sector; 340*9e39c5baSBill Taylor info32.af_addr = ioctl_info.af_addr; 341*9e39c5baSBill Taylor 342*9e39c5baSBill Taylor if (ddi_copyout(&info32, (void *)arg, 343*9e39c5baSBill Taylor sizeof (hermon_flash_ioctl32_t), mode) != 0) { 344*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 345*9e39c5baSBill Taylor return (EFAULT); 346*9e39c5baSBill Taylor } 347*9e39c5baSBill Taylor } else 348*9e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */ 349*9e39c5baSBill Taylor if (ddi_copyout(&ioctl_info, (void *)arg, 350*9e39c5baSBill Taylor sizeof (hermon_flash_ioctl_t), mode) != 0) { 351*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 352*9e39c5baSBill Taylor return (EFAULT); 353*9e39c5baSBill Taylor } 354*9e39c5baSBill Taylor 355*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 356*9e39c5baSBill Taylor return (status); 357*9e39c5baSBill Taylor } 358*9e39c5baSBill Taylor 359*9e39c5baSBill Taylor /* 360*9e39c5baSBill Taylor * hermon_ioctl_flash_write() 361*9e39c5baSBill Taylor */ 362*9e39c5baSBill Taylor static int 363*9e39c5baSBill Taylor hermon_ioctl_flash_write(hermon_state_t *state, dev_t dev, intptr_t arg, 364*9e39c5baSBill Taylor int mode) 365*9e39c5baSBill Taylor { 366*9e39c5baSBill Taylor hermon_flash_ioctl_t ioctl_info; 367*9e39c5baSBill Taylor int status = 0; 368*9e39c5baSBill Taylor 369*9e39c5baSBill Taylor /* 370*9e39c5baSBill Taylor * Check that flash init ioctl has been called first. And check 371*9e39c5baSBill Taylor * that the same dev_t that called init is the one calling write now. 372*9e39c5baSBill Taylor */ 373*9e39c5baSBill Taylor mutex_enter(&state->hs_fw_flashlock); 374*9e39c5baSBill Taylor if ((state->hs_fw_flashdev != dev) || 375*9e39c5baSBill Taylor (state->hs_fw_flashstarted == 0)) { 376*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 377*9e39c5baSBill Taylor return (EIO); 378*9e39c5baSBill Taylor } 379*9e39c5baSBill Taylor 380*9e39c5baSBill Taylor /* copy user struct to kernel */ 381*9e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL 382*9e39c5baSBill Taylor if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 383*9e39c5baSBill Taylor hermon_flash_ioctl32_t info32; 384*9e39c5baSBill Taylor 385*9e39c5baSBill Taylor if (ddi_copyin((void *)arg, &info32, 386*9e39c5baSBill Taylor sizeof (hermon_flash_ioctl32_t), mode) != 0) { 387*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 388*9e39c5baSBill Taylor return (EFAULT); 389*9e39c5baSBill Taylor } 390*9e39c5baSBill Taylor ioctl_info.af_type = info32.af_type; 391*9e39c5baSBill Taylor ioctl_info.af_sector = (caddr_t)(uintptr_t)info32.af_sector; 392*9e39c5baSBill Taylor ioctl_info.af_sector_num = info32.af_sector_num; 393*9e39c5baSBill Taylor ioctl_info.af_addr = info32.af_addr; 394*9e39c5baSBill Taylor ioctl_info.af_byte = info32.af_byte; 395*9e39c5baSBill Taylor } else 396*9e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */ 397*9e39c5baSBill Taylor if (ddi_copyin((void *)arg, &ioctl_info, 398*9e39c5baSBill Taylor sizeof (hermon_flash_ioctl_t), mode) != 0) { 399*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 400*9e39c5baSBill Taylor return (EFAULT); 401*9e39c5baSBill Taylor } 402*9e39c5baSBill Taylor 403*9e39c5baSBill Taylor /* 404*9e39c5baSBill Taylor * Determine type of WRITE ioctl 405*9e39c5baSBill Taylor */ 406*9e39c5baSBill Taylor switch (ioctl_info.af_type) { 407*9e39c5baSBill Taylor case HERMON_FLASH_WRITE_SECTOR: 408*9e39c5baSBill Taylor /* Check if sector num is too large for flash device */ 409*9e39c5baSBill Taylor if (ioctl_info.af_sector_num >= 410*9e39c5baSBill Taylor (state->hs_fw_device_sz >> state->hs_fw_log_sector_sz)) { 411*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 412*9e39c5baSBill Taylor return (EFAULT); 413*9e39c5baSBill Taylor } 414*9e39c5baSBill Taylor 415*9e39c5baSBill Taylor /* copy in fw sector image data */ 416*9e39c5baSBill Taylor if (ddi_copyin(&ioctl_info.af_sector[0], 417*9e39c5baSBill Taylor &state->hs_fw_sector[0], 1 << state->hs_fw_log_sector_sz, 418*9e39c5baSBill Taylor mode) != 0) { 419*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 420*9e39c5baSBill Taylor return (EFAULT); 421*9e39c5baSBill Taylor } 422*9e39c5baSBill Taylor 423*9e39c5baSBill Taylor /* Perform Write Sector */ 424*9e39c5baSBill Taylor status = hermon_flash_write_sector(state, 425*9e39c5baSBill Taylor ioctl_info.af_sector_num); 426*9e39c5baSBill Taylor break; 427*9e39c5baSBill Taylor 428*9e39c5baSBill Taylor case HERMON_FLASH_WRITE_BYTE: 429*9e39c5baSBill Taylor /* Check if addr is too large for flash device */ 430*9e39c5baSBill Taylor if (ioctl_info.af_addr >= state->hs_fw_device_sz) { 431*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 432*9e39c5baSBill Taylor return (EFAULT); 433*9e39c5baSBill Taylor } 434*9e39c5baSBill Taylor 435*9e39c5baSBill Taylor /* Perform Write Byte */ 436*9e39c5baSBill Taylor /* 437*9e39c5baSBill Taylor * CMJ -- is a reset really needed before and after writing 438*9e39c5baSBill Taylor * each byte? This code came from arbel, but we should look 439*9e39c5baSBill Taylor * into this. Also, for SPI, no reset is actually performed. 440*9e39c5baSBill Taylor */ 441*9e39c5baSBill Taylor if ((status = hermon_flash_bank(state, 442*9e39c5baSBill Taylor ioctl_info.af_addr)) != 0 || 443*9e39c5baSBill Taylor (status = hermon_flash_reset(state)) != 0 || 444*9e39c5baSBill Taylor (status = hermon_flash_write_byte(state, 445*9e39c5baSBill Taylor ioctl_info.af_addr, ioctl_info.af_byte)) != 0 || 446*9e39c5baSBill Taylor (status = hermon_flash_reset(state)) != 0) { 447*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 448*9e39c5baSBill Taylor return (status); 449*9e39c5baSBill Taylor } 450*9e39c5baSBill Taylor break; 451*9e39c5baSBill Taylor 452*9e39c5baSBill Taylor default: 453*9e39c5baSBill Taylor status = EINVAL; 454*9e39c5baSBill Taylor break; 455*9e39c5baSBill Taylor } 456*9e39c5baSBill Taylor 457*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 458*9e39c5baSBill Taylor return (status); 459*9e39c5baSBill Taylor } 460*9e39c5baSBill Taylor 461*9e39c5baSBill Taylor /* 462*9e39c5baSBill Taylor * hermon_ioctl_flash_erase() 463*9e39c5baSBill Taylor */ 464*9e39c5baSBill Taylor static int 465*9e39c5baSBill Taylor hermon_ioctl_flash_erase(hermon_state_t *state, dev_t dev, intptr_t arg, 466*9e39c5baSBill Taylor int mode) 467*9e39c5baSBill Taylor { 468*9e39c5baSBill Taylor hermon_flash_ioctl_t ioctl_info; 469*9e39c5baSBill Taylor int status = 0; 470*9e39c5baSBill Taylor 471*9e39c5baSBill Taylor /* 472*9e39c5baSBill Taylor * Check that flash init ioctl has been called first. And check 473*9e39c5baSBill Taylor * that the same dev_t that called init is the one calling erase now. 474*9e39c5baSBill Taylor */ 475*9e39c5baSBill Taylor mutex_enter(&state->hs_fw_flashlock); 476*9e39c5baSBill Taylor if ((state->hs_fw_flashdev != dev) || 477*9e39c5baSBill Taylor (state->hs_fw_flashstarted == 0)) { 478*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 479*9e39c5baSBill Taylor return (EIO); 480*9e39c5baSBill Taylor } 481*9e39c5baSBill Taylor 482*9e39c5baSBill Taylor /* copy user struct to kernel */ 483*9e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL 484*9e39c5baSBill Taylor if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 485*9e39c5baSBill Taylor hermon_flash_ioctl32_t info32; 486*9e39c5baSBill Taylor 487*9e39c5baSBill Taylor if (ddi_copyin((void *)arg, &info32, 488*9e39c5baSBill Taylor sizeof (hermon_flash_ioctl32_t), mode) != 0) { 489*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 490*9e39c5baSBill Taylor return (EFAULT); 491*9e39c5baSBill Taylor } 492*9e39c5baSBill Taylor ioctl_info.af_type = info32.af_type; 493*9e39c5baSBill Taylor ioctl_info.af_sector_num = info32.af_sector_num; 494*9e39c5baSBill Taylor } else 495*9e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */ 496*9e39c5baSBill Taylor if (ddi_copyin((void *)arg, &ioctl_info, sizeof (hermon_flash_ioctl_t), 497*9e39c5baSBill Taylor mode) != 0) { 498*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 499*9e39c5baSBill Taylor return (EFAULT); 500*9e39c5baSBill Taylor } 501*9e39c5baSBill Taylor 502*9e39c5baSBill Taylor /* 503*9e39c5baSBill Taylor * Determine type of ERASE ioctl 504*9e39c5baSBill Taylor */ 505*9e39c5baSBill Taylor switch (ioctl_info.af_type) { 506*9e39c5baSBill Taylor case HERMON_FLASH_ERASE_SECTOR: 507*9e39c5baSBill Taylor /* Check if sector num is too large for flash device */ 508*9e39c5baSBill Taylor if (ioctl_info.af_sector_num >= 509*9e39c5baSBill Taylor (state->hs_fw_device_sz >> state->hs_fw_log_sector_sz)) { 510*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 511*9e39c5baSBill Taylor return (EFAULT); 512*9e39c5baSBill Taylor } 513*9e39c5baSBill Taylor 514*9e39c5baSBill Taylor /* Perform Sector Erase */ 515*9e39c5baSBill Taylor status = hermon_flash_erase_sector(state, 516*9e39c5baSBill Taylor ioctl_info.af_sector_num); 517*9e39c5baSBill Taylor break; 518*9e39c5baSBill Taylor 519*9e39c5baSBill Taylor case HERMON_FLASH_ERASE_CHIP: 520*9e39c5baSBill Taylor /* Perform Chip Erase */ 521*9e39c5baSBill Taylor status = hermon_flash_erase_chip(state); 522*9e39c5baSBill Taylor break; 523*9e39c5baSBill Taylor 524*9e39c5baSBill Taylor default: 525*9e39c5baSBill Taylor status = EINVAL; 526*9e39c5baSBill Taylor break; 527*9e39c5baSBill Taylor } 528*9e39c5baSBill Taylor 529*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 530*9e39c5baSBill Taylor return (status); 531*9e39c5baSBill Taylor } 532*9e39c5baSBill Taylor 533*9e39c5baSBill Taylor /* 534*9e39c5baSBill Taylor * hermon_ioctl_flash_init() 535*9e39c5baSBill Taylor */ 536*9e39c5baSBill Taylor static int 537*9e39c5baSBill Taylor hermon_ioctl_flash_init(hermon_state_t *state, dev_t dev, intptr_t arg, 538*9e39c5baSBill Taylor int mode) 539*9e39c5baSBill Taylor { 540*9e39c5baSBill Taylor hermon_flash_init_ioctl_t init_info; 541*9e39c5baSBill Taylor int ret; 542*9e39c5baSBill Taylor int intel_xcmd = 0; 543*9e39c5baSBill Taylor ddi_acc_handle_t pci_hdl = hermon_get_pcihdl(state); 544*9e39c5baSBill Taylor 545*9e39c5baSBill Taylor /* initialize the FMA retry loop */ 546*9e39c5baSBill Taylor hermon_pio_init(fm_loop_cnt, fm_status, fm_test); 547*9e39c5baSBill Taylor 548*9e39c5baSBill Taylor state->hs_fw_sector = NULL; 549*9e39c5baSBill Taylor 550*9e39c5baSBill Taylor /* 551*9e39c5baSBill Taylor * init cannot be called more than once. If we have already init'd the 552*9e39c5baSBill Taylor * flash, return directly. 553*9e39c5baSBill Taylor */ 554*9e39c5baSBill Taylor mutex_enter(&state->hs_fw_flashlock); 555*9e39c5baSBill Taylor if (state->hs_fw_flashstarted == 1) { 556*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 557*9e39c5baSBill Taylor return (EINVAL); 558*9e39c5baSBill Taylor } 559*9e39c5baSBill Taylor 560*9e39c5baSBill Taylor /* copyin the user struct to kernel */ 561*9e39c5baSBill Taylor if (ddi_copyin((void *)arg, &init_info, 562*9e39c5baSBill Taylor sizeof (hermon_flash_init_ioctl_t), mode) != 0) { 563*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 564*9e39c5baSBill Taylor return (EFAULT); 565*9e39c5baSBill Taylor } 566*9e39c5baSBill Taylor 567*9e39c5baSBill Taylor /* Init Flash */ 568*9e39c5baSBill Taylor if ((ret = hermon_flash_init(state)) != 0) { 569*9e39c5baSBill Taylor if (ret == EIO) { 570*9e39c5baSBill Taylor goto pio_error; 571*9e39c5baSBill Taylor } 572*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 573*9e39c5baSBill Taylor return (ret); 574*9e39c5baSBill Taylor } 575*9e39c5baSBill Taylor 576*9e39c5baSBill Taylor /* Read CFI info */ 577*9e39c5baSBill Taylor if ((ret = hermon_flash_cfi_init(state, &init_info.af_cfi_info[0], 578*9e39c5baSBill Taylor &intel_xcmd)) != 0) { 579*9e39c5baSBill Taylor if (ret == EIO) { 580*9e39c5baSBill Taylor goto pio_error; 581*9e39c5baSBill Taylor } 582*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 583*9e39c5baSBill Taylor return (ret); 584*9e39c5baSBill Taylor } 585*9e39c5baSBill Taylor 586*9e39c5baSBill Taylor /* 587*9e39c5baSBill Taylor * Return error if the command set is unknown. 588*9e39c5baSBill Taylor */ 589*9e39c5baSBill Taylor if (state->hs_fw_cmdset == HERMON_FLASH_UNKNOWN_CMDSET) { 590*9e39c5baSBill Taylor if ((ret = hermon_ioctl_flash_cleanup_nolock(state)) != 0) { 591*9e39c5baSBill Taylor if (ret == EIO) { 592*9e39c5baSBill Taylor goto pio_error; 593*9e39c5baSBill Taylor } 594*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 595*9e39c5baSBill Taylor return (ret); 596*9e39c5baSBill Taylor } 597*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 598*9e39c5baSBill Taylor return (EFAULT); 599*9e39c5baSBill Taylor } 600*9e39c5baSBill Taylor 601*9e39c5baSBill Taylor /* the FMA retry loop starts. */ 602*9e39c5baSBill Taylor hermon_pio_start(state, pci_hdl, pio_error, 603*9e39c5baSBill Taylor fm_loop_cnt, fm_status, fm_test); 604*9e39c5baSBill Taylor 605*9e39c5baSBill Taylor /* Read HWREV - least significant 8 bits is revision ID */ 606*9e39c5baSBill Taylor init_info.af_hwrev = pci_config_get32(pci_hdl, 607*9e39c5baSBill Taylor HERMON_HW_FLASH_CFG_HWREV) & 0xFF; 608*9e39c5baSBill Taylor 609*9e39c5baSBill Taylor /* the FMA retry loop ends. */ 610*9e39c5baSBill Taylor hermon_pio_end(state, pci_hdl, pio_error, fm_loop_cnt, 611*9e39c5baSBill Taylor fm_status, fm_test); 612*9e39c5baSBill Taylor 613*9e39c5baSBill Taylor /* Fill in the firmwate revision numbers */ 614*9e39c5baSBill Taylor init_info.af_fwrev.afi_maj = state->hs_fw.fw_rev_major; 615*9e39c5baSBill Taylor init_info.af_fwrev.afi_min = state->hs_fw.fw_rev_minor; 616*9e39c5baSBill Taylor init_info.af_fwrev.afi_sub = state->hs_fw.fw_rev_subminor; 617*9e39c5baSBill Taylor 618*9e39c5baSBill Taylor /* Alloc flash mem for one sector size */ 619*9e39c5baSBill Taylor state->hs_fw_sector = (uint32_t *)kmem_zalloc(1 << 620*9e39c5baSBill Taylor state->hs_fw_log_sector_sz, KM_SLEEP); 621*9e39c5baSBill Taylor 622*9e39c5baSBill Taylor /* Set HW part number and length */ 623*9e39c5baSBill Taylor init_info.af_pn_len = state->hs_hca_pn_len; 624*9e39c5baSBill Taylor if (state->hs_hca_pn_len != 0) { 625*9e39c5baSBill Taylor (void) memcpy(init_info.af_hwpn, state->hs_hca_pn, 626*9e39c5baSBill Taylor state->hs_hca_pn_len); 627*9e39c5baSBill Taylor } 628*9e39c5baSBill Taylor 629*9e39c5baSBill Taylor /* Copy ioctl results back to userland */ 630*9e39c5baSBill Taylor if (ddi_copyout(&init_info, (void *)arg, 631*9e39c5baSBill Taylor sizeof (hermon_flash_init_ioctl_t), mode) != 0) { 632*9e39c5baSBill Taylor if ((ret = hermon_ioctl_flash_cleanup_nolock(state)) != 0) { 633*9e39c5baSBill Taylor if (ret == EIO) { 634*9e39c5baSBill Taylor goto pio_error; 635*9e39c5baSBill Taylor } 636*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 637*9e39c5baSBill Taylor return (ret); 638*9e39c5baSBill Taylor } 639*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 640*9e39c5baSBill Taylor return (EFAULT); 641*9e39c5baSBill Taylor } 642*9e39c5baSBill Taylor 643*9e39c5baSBill Taylor /* Set flash state to started */ 644*9e39c5baSBill Taylor state->hs_fw_flashstarted = 1; 645*9e39c5baSBill Taylor state->hs_fw_flashdev = dev; 646*9e39c5baSBill Taylor 647*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 648*9e39c5baSBill Taylor 649*9e39c5baSBill Taylor /* 650*9e39c5baSBill Taylor * If "flash init" is successful, add an "on close" callback to the 651*9e39c5baSBill Taylor * current dev node to ensure that "flash fini" gets called later 652*9e39c5baSBill Taylor * even if the userland process prematurely exits. 653*9e39c5baSBill Taylor */ 654*9e39c5baSBill Taylor ret = hermon_umap_db_set_onclose_cb(dev, 655*9e39c5baSBill Taylor HERMON_ONCLOSE_FLASH_INPROGRESS, 656*9e39c5baSBill Taylor (int (*)(void *))hermon_ioctl_flash_cleanup, state); 657*9e39c5baSBill Taylor if (ret != DDI_SUCCESS) { 658*9e39c5baSBill Taylor int status = hermon_ioctl_flash_fini(state, dev); 659*9e39c5baSBill Taylor if (status != 0) { 660*9e39c5baSBill Taylor if (status == EIO) { 661*9e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR, 662*9e39c5baSBill Taylor HCA_ERR_IOCTL); 663*9e39c5baSBill Taylor return (EIO); 664*9e39c5baSBill Taylor } 665*9e39c5baSBill Taylor return (status); 666*9e39c5baSBill Taylor } 667*9e39c5baSBill Taylor } 668*9e39c5baSBill Taylor return (0); 669*9e39c5baSBill Taylor 670*9e39c5baSBill Taylor pio_error: 671*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 672*9e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL); 673*9e39c5baSBill Taylor return (EIO); 674*9e39c5baSBill Taylor } 675*9e39c5baSBill Taylor 676*9e39c5baSBill Taylor /* 677*9e39c5baSBill Taylor * hermon_ioctl_flash_fini() 678*9e39c5baSBill Taylor */ 679*9e39c5baSBill Taylor static int 680*9e39c5baSBill Taylor hermon_ioctl_flash_fini(hermon_state_t *state, dev_t dev) 681*9e39c5baSBill Taylor { 682*9e39c5baSBill Taylor int ret; 683*9e39c5baSBill Taylor 684*9e39c5baSBill Taylor /* 685*9e39c5baSBill Taylor * Check that flash init ioctl has been called first. And check 686*9e39c5baSBill Taylor * that the same dev_t that called init is the one calling fini now. 687*9e39c5baSBill Taylor */ 688*9e39c5baSBill Taylor mutex_enter(&state->hs_fw_flashlock); 689*9e39c5baSBill Taylor if ((state->hs_fw_flashdev != dev) || 690*9e39c5baSBill Taylor (state->hs_fw_flashstarted == 0)) { 691*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 692*9e39c5baSBill Taylor return (EINVAL); 693*9e39c5baSBill Taylor } 694*9e39c5baSBill Taylor 695*9e39c5baSBill Taylor if ((ret = hermon_ioctl_flash_cleanup_nolock(state)) != 0) { 696*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 697*9e39c5baSBill Taylor if (ret == EIO) { 698*9e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL); 699*9e39c5baSBill Taylor } 700*9e39c5baSBill Taylor return (ret); 701*9e39c5baSBill Taylor } 702*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 703*9e39c5baSBill Taylor 704*9e39c5baSBill Taylor /* 705*9e39c5baSBill Taylor * If "flash fini" is successful, remove the "on close" callback 706*9e39c5baSBill Taylor * that was setup during "flash init". 707*9e39c5baSBill Taylor */ 708*9e39c5baSBill Taylor ret = hermon_umap_db_clear_onclose_cb(dev, 709*9e39c5baSBill Taylor HERMON_ONCLOSE_FLASH_INPROGRESS); 710*9e39c5baSBill Taylor if (ret != DDI_SUCCESS) { 711*9e39c5baSBill Taylor return (EFAULT); 712*9e39c5baSBill Taylor } 713*9e39c5baSBill Taylor return (0); 714*9e39c5baSBill Taylor } 715*9e39c5baSBill Taylor 716*9e39c5baSBill Taylor 717*9e39c5baSBill Taylor /* 718*9e39c5baSBill Taylor * hermon_ioctl_flash_cleanup() 719*9e39c5baSBill Taylor */ 720*9e39c5baSBill Taylor static int 721*9e39c5baSBill Taylor hermon_ioctl_flash_cleanup(hermon_state_t *state) 722*9e39c5baSBill Taylor { 723*9e39c5baSBill Taylor int status; 724*9e39c5baSBill Taylor 725*9e39c5baSBill Taylor mutex_enter(&state->hs_fw_flashlock); 726*9e39c5baSBill Taylor status = hermon_ioctl_flash_cleanup_nolock(state); 727*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 728*9e39c5baSBill Taylor 729*9e39c5baSBill Taylor return (status); 730*9e39c5baSBill Taylor } 731*9e39c5baSBill Taylor 732*9e39c5baSBill Taylor 733*9e39c5baSBill Taylor /* 734*9e39c5baSBill Taylor * hermon_ioctl_flash_cleanup_nolock() 735*9e39c5baSBill Taylor */ 736*9e39c5baSBill Taylor static int 737*9e39c5baSBill Taylor hermon_ioctl_flash_cleanup_nolock(hermon_state_t *state) 738*9e39c5baSBill Taylor { 739*9e39c5baSBill Taylor int status; 740*9e39c5baSBill Taylor ASSERT(MUTEX_HELD(&state->hs_fw_flashlock)); 741*9e39c5baSBill Taylor 742*9e39c5baSBill Taylor /* free flash mem */ 743*9e39c5baSBill Taylor if (state->hs_fw_sector) { 744*9e39c5baSBill Taylor kmem_free(state->hs_fw_sector, 1 << state->hs_fw_log_sector_sz); 745*9e39c5baSBill Taylor } 746*9e39c5baSBill Taylor 747*9e39c5baSBill Taylor /* Fini the Flash */ 748*9e39c5baSBill Taylor if ((status = hermon_flash_fini(state)) != 0) 749*9e39c5baSBill Taylor return (status); 750*9e39c5baSBill Taylor 751*9e39c5baSBill Taylor /* Set flash state to fini */ 752*9e39c5baSBill Taylor state->hs_fw_flashstarted = 0; 753*9e39c5baSBill Taylor state->hs_fw_flashdev = 0; 754*9e39c5baSBill Taylor return (0); 755*9e39c5baSBill Taylor } 756*9e39c5baSBill Taylor 757*9e39c5baSBill Taylor 758*9e39c5baSBill Taylor /* 759*9e39c5baSBill Taylor * hermon_ioctl_info() 760*9e39c5baSBill Taylor */ 761*9e39c5baSBill Taylor static int 762*9e39c5baSBill Taylor hermon_ioctl_info(hermon_state_t *state, dev_t dev, intptr_t arg, int mode) 763*9e39c5baSBill Taylor { 764*9e39c5baSBill Taylor hermon_info_ioctl_t info; 765*9e39c5baSBill Taylor hermon_flash_init_ioctl_t init_info; 766*9e39c5baSBill Taylor 767*9e39c5baSBill Taylor /* 768*9e39c5baSBill Taylor * Access to Hemron VTS ioctls is not allowed in "maintenance mode". 769*9e39c5baSBill Taylor */ 770*9e39c5baSBill Taylor if (state->hs_operational_mode == HERMON_MAINTENANCE_MODE) { 771*9e39c5baSBill Taylor return (EFAULT); 772*9e39c5baSBill Taylor } 773*9e39c5baSBill Taylor 774*9e39c5baSBill Taylor /* copyin the user struct to kernel */ 775*9e39c5baSBill Taylor if (ddi_copyin((void *)arg, &info, sizeof (hermon_info_ioctl_t), 776*9e39c5baSBill Taylor mode) != 0) { 777*9e39c5baSBill Taylor return (EFAULT); 778*9e39c5baSBill Taylor } 779*9e39c5baSBill Taylor 780*9e39c5baSBill Taylor /* 781*9e39c5baSBill Taylor * Check ioctl revision 782*9e39c5baSBill Taylor */ 783*9e39c5baSBill Taylor if (info.ai_revision != HERMON_VTS_IOCTL_REVISION) { 784*9e39c5baSBill Taylor return (EINVAL); 785*9e39c5baSBill Taylor } 786*9e39c5baSBill Taylor 787*9e39c5baSBill Taylor /* 788*9e39c5baSBill Taylor * If the 'fw_device_sz' has not been initialized yet, we initialize it 789*9e39c5baSBill Taylor * here. This is done by leveraging the 790*9e39c5baSBill Taylor * hermon_ioctl_flash_init()/fini() calls. We also hold our own mutex 791*9e39c5baSBill Taylor * around this operation in case we have multiple VTS threads in 792*9e39c5baSBill Taylor * process at the same time. 793*9e39c5baSBill Taylor */ 794*9e39c5baSBill Taylor mutex_enter(&state->hs_info_lock); 795*9e39c5baSBill Taylor if (state->hs_fw_device_sz == 0) { 796*9e39c5baSBill Taylor if (hermon_ioctl_flash_init(state, dev, (intptr_t)&init_info, 797*9e39c5baSBill Taylor (FKIOCTL | mode)) != 0) { 798*9e39c5baSBill Taylor mutex_exit(&state->hs_info_lock); 799*9e39c5baSBill Taylor return (EFAULT); 800*9e39c5baSBill Taylor } 801*9e39c5baSBill Taylor (void) hermon_ioctl_flash_fini(state, dev); 802*9e39c5baSBill Taylor } 803*9e39c5baSBill Taylor mutex_exit(&state->hs_info_lock); 804*9e39c5baSBill Taylor 805*9e39c5baSBill Taylor info.ai_hw_rev = state->hs_revision_id; 806*9e39c5baSBill Taylor info.ai_flash_sz = state->hs_fw_device_sz; 807*9e39c5baSBill Taylor info.ai_fw_rev.afi_maj = state->hs_fw.fw_rev_major; 808*9e39c5baSBill Taylor info.ai_fw_rev.afi_min = state->hs_fw.fw_rev_minor; 809*9e39c5baSBill Taylor info.ai_fw_rev.afi_sub = state->hs_fw.fw_rev_subminor; 810*9e39c5baSBill Taylor 811*9e39c5baSBill Taylor /* Copy ioctl results back to user struct */ 812*9e39c5baSBill Taylor if (ddi_copyout(&info, (void *)arg, sizeof (hermon_info_ioctl_t), 813*9e39c5baSBill Taylor mode) != 0) { 814*9e39c5baSBill Taylor return (EFAULT); 815*9e39c5baSBill Taylor } 816*9e39c5baSBill Taylor 817*9e39c5baSBill Taylor return (0); 818*9e39c5baSBill Taylor } 819*9e39c5baSBill Taylor 820*9e39c5baSBill Taylor /* 821*9e39c5baSBill Taylor * hermon_ioctl_ports() 822*9e39c5baSBill Taylor */ 823*9e39c5baSBill Taylor static int 824*9e39c5baSBill Taylor hermon_ioctl_ports(hermon_state_t *state, intptr_t arg, int mode) 825*9e39c5baSBill Taylor { 826*9e39c5baSBill Taylor hermon_ports_ioctl_t info; 827*9e39c5baSBill Taylor hermon_stat_port_ioctl_t portstat; 828*9e39c5baSBill Taylor ibt_hca_portinfo_t pi; 829*9e39c5baSBill Taylor uint_t tbl_size; 830*9e39c5baSBill Taylor ib_gid_t *sgid_tbl; 831*9e39c5baSBill Taylor ib_pkey_t *pkey_tbl; 832*9e39c5baSBill Taylor int i; 833*9e39c5baSBill Taylor 834*9e39c5baSBill Taylor /* 835*9e39c5baSBill Taylor * Access to Hemron VTS ioctls is not allowed in "maintenance mode". 836*9e39c5baSBill Taylor */ 837*9e39c5baSBill Taylor if (state->hs_operational_mode == HERMON_MAINTENANCE_MODE) { 838*9e39c5baSBill Taylor return (EFAULT); 839*9e39c5baSBill Taylor } 840*9e39c5baSBill Taylor 841*9e39c5baSBill Taylor /* copyin the user struct to kernel */ 842*9e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL 843*9e39c5baSBill Taylor if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 844*9e39c5baSBill Taylor hermon_ports_ioctl32_t info32; 845*9e39c5baSBill Taylor 846*9e39c5baSBill Taylor if (ddi_copyin((void *)arg, &info32, 847*9e39c5baSBill Taylor sizeof (hermon_ports_ioctl32_t), mode) != 0) { 848*9e39c5baSBill Taylor return (EFAULT); 849*9e39c5baSBill Taylor } 850*9e39c5baSBill Taylor info.ap_revision = info32.ap_revision; 851*9e39c5baSBill Taylor info.ap_ports = 852*9e39c5baSBill Taylor (hermon_stat_port_ioctl_t *)(uintptr_t)info32.ap_ports; 853*9e39c5baSBill Taylor info.ap_num_ports = info32.ap_num_ports; 854*9e39c5baSBill Taylor 855*9e39c5baSBill Taylor } else 856*9e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */ 857*9e39c5baSBill Taylor if (ddi_copyin((void *)arg, &info, sizeof (hermon_ports_ioctl_t), 858*9e39c5baSBill Taylor mode) != 0) { 859*9e39c5baSBill Taylor return (EFAULT); 860*9e39c5baSBill Taylor } 861*9e39c5baSBill Taylor 862*9e39c5baSBill Taylor /* 863*9e39c5baSBill Taylor * Check ioctl revision 864*9e39c5baSBill Taylor */ 865*9e39c5baSBill Taylor if (info.ap_revision != HERMON_VTS_IOCTL_REVISION) { 866*9e39c5baSBill Taylor return (EINVAL); 867*9e39c5baSBill Taylor } 868*9e39c5baSBill Taylor 869*9e39c5baSBill Taylor /* Allocate space for temporary GID table/PKey table */ 870*9e39c5baSBill Taylor tbl_size = (1 << state->hs_cfg_profile->cp_log_max_gidtbl); 871*9e39c5baSBill Taylor sgid_tbl = (ib_gid_t *)kmem_zalloc(tbl_size * sizeof (ib_gid_t), 872*9e39c5baSBill Taylor KM_SLEEP); 873*9e39c5baSBill Taylor tbl_size = (1 << state->hs_cfg_profile->cp_log_max_pkeytbl); 874*9e39c5baSBill Taylor pkey_tbl = (ib_pkey_t *)kmem_zalloc(tbl_size * sizeof (ib_pkey_t), 875*9e39c5baSBill Taylor KM_SLEEP); 876*9e39c5baSBill Taylor 877*9e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*sgid_tbl, *pkey_tbl)) 878*9e39c5baSBill Taylor 879*9e39c5baSBill Taylor /* 880*9e39c5baSBill Taylor * Setup the number of ports, then loop through all ports and 881*9e39c5baSBill Taylor * query properties of each. 882*9e39c5baSBill Taylor */ 883*9e39c5baSBill Taylor info.ap_num_ports = (uint8_t)state->hs_cfg_profile->cp_num_ports; 884*9e39c5baSBill Taylor for (i = 0; i < info.ap_num_ports; i++) { 885*9e39c5baSBill Taylor /* 886*9e39c5baSBill Taylor * Get portstate information from the device. If 887*9e39c5baSBill Taylor * hermon_port_query() fails, leave zeroes in user 888*9e39c5baSBill Taylor * struct port entry and continue. 889*9e39c5baSBill Taylor */ 890*9e39c5baSBill Taylor bzero(&pi, sizeof (ibt_hca_portinfo_t)); 891*9e39c5baSBill Taylor pi.p_sgid_tbl = sgid_tbl; 892*9e39c5baSBill Taylor pi.p_pkey_tbl = pkey_tbl; 893*9e39c5baSBill Taylor (void) hermon_port_query(state, i + 1, &pi); 894*9e39c5baSBill Taylor 895*9e39c5baSBill Taylor portstat.asp_port_num = pi.p_port_num; 896*9e39c5baSBill Taylor portstat.asp_state = pi.p_linkstate; 897*9e39c5baSBill Taylor portstat.asp_guid = pi.p_sgid_tbl[0].gid_guid; 898*9e39c5baSBill Taylor 899*9e39c5baSBill Taylor /* 900*9e39c5baSBill Taylor * Copy queried port results back to user struct. If 901*9e39c5baSBill Taylor * this fails, then break out of loop, attempt to copy 902*9e39c5baSBill Taylor * out remaining info to user struct, and return (without 903*9e39c5baSBill Taylor * error). 904*9e39c5baSBill Taylor */ 905*9e39c5baSBill Taylor if (ddi_copyout(&portstat, 906*9e39c5baSBill Taylor &(((hermon_stat_port_ioctl_t *)info.ap_ports)[i]), 907*9e39c5baSBill Taylor sizeof (hermon_stat_port_ioctl_t), mode) != 0) { 908*9e39c5baSBill Taylor break; 909*9e39c5baSBill Taylor } 910*9e39c5baSBill Taylor } 911*9e39c5baSBill Taylor 912*9e39c5baSBill Taylor /* Free the temporary space used for GID table/PKey table */ 913*9e39c5baSBill Taylor tbl_size = (1 << state->hs_cfg_profile->cp_log_max_gidtbl); 914*9e39c5baSBill Taylor kmem_free(sgid_tbl, tbl_size * sizeof (ib_gid_t)); 915*9e39c5baSBill Taylor tbl_size = (1 << state->hs_cfg_profile->cp_log_max_pkeytbl); 916*9e39c5baSBill Taylor kmem_free(pkey_tbl, tbl_size * sizeof (ib_pkey_t)); 917*9e39c5baSBill Taylor 918*9e39c5baSBill Taylor /* Copy ioctl results back to user struct */ 919*9e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL 920*9e39c5baSBill Taylor if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 921*9e39c5baSBill Taylor hermon_ports_ioctl32_t info32; 922*9e39c5baSBill Taylor 923*9e39c5baSBill Taylor info32.ap_revision = info.ap_revision; 924*9e39c5baSBill Taylor info32.ap_ports = (caddr32_t)(uintptr_t)info.ap_ports; 925*9e39c5baSBill Taylor info32.ap_num_ports = info.ap_num_ports; 926*9e39c5baSBill Taylor 927*9e39c5baSBill Taylor if (ddi_copyout(&info32, (void *)arg, 928*9e39c5baSBill Taylor sizeof (hermon_ports_ioctl32_t), mode) != 0) { 929*9e39c5baSBill Taylor return (EFAULT); 930*9e39c5baSBill Taylor } 931*9e39c5baSBill Taylor } else 932*9e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */ 933*9e39c5baSBill Taylor if (ddi_copyout(&info, (void *)arg, sizeof (hermon_ports_ioctl_t), 934*9e39c5baSBill Taylor mode) != 0) { 935*9e39c5baSBill Taylor return (EFAULT); 936*9e39c5baSBill Taylor } 937*9e39c5baSBill Taylor 938*9e39c5baSBill Taylor return (0); 939*9e39c5baSBill Taylor } 940*9e39c5baSBill Taylor 941*9e39c5baSBill Taylor /* 942*9e39c5baSBill Taylor * hermon_ioctl_loopback() 943*9e39c5baSBill Taylor */ 944*9e39c5baSBill Taylor static int 945*9e39c5baSBill Taylor hermon_ioctl_loopback(hermon_state_t *state, intptr_t arg, int mode) 946*9e39c5baSBill Taylor { 947*9e39c5baSBill Taylor hermon_loopback_ioctl_t lb; 948*9e39c5baSBill Taylor hermon_loopback_state_t lstate; 949*9e39c5baSBill Taylor ibt_hca_portinfo_t pi; 950*9e39c5baSBill Taylor uint_t tbl_size, loopmax, max_usec; 951*9e39c5baSBill Taylor ib_gid_t *sgid_tbl; 952*9e39c5baSBill Taylor ib_pkey_t *pkey_tbl; 953*9e39c5baSBill Taylor int j, iter, ret; 954*9e39c5baSBill Taylor 955*9e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(lstate)) 956*9e39c5baSBill Taylor 957*9e39c5baSBill Taylor /* 958*9e39c5baSBill Taylor * Access to Hemron VTS ioctls is not allowed in "maintenance mode". 959*9e39c5baSBill Taylor */ 960*9e39c5baSBill Taylor if (state->hs_operational_mode == HERMON_MAINTENANCE_MODE) { 961*9e39c5baSBill Taylor return (EFAULT); 962*9e39c5baSBill Taylor } 963*9e39c5baSBill Taylor 964*9e39c5baSBill Taylor /* copyin the user struct to kernel */ 965*9e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL 966*9e39c5baSBill Taylor if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 967*9e39c5baSBill Taylor hermon_loopback_ioctl32_t lb32; 968*9e39c5baSBill Taylor 969*9e39c5baSBill Taylor if (ddi_copyin((void *)arg, &lb32, 970*9e39c5baSBill Taylor sizeof (hermon_loopback_ioctl32_t), mode) != 0) { 971*9e39c5baSBill Taylor return (EFAULT); 972*9e39c5baSBill Taylor } 973*9e39c5baSBill Taylor lb.alb_revision = lb32.alb_revision; 974*9e39c5baSBill Taylor lb.alb_send_buf = (caddr_t)(uintptr_t)lb32.alb_send_buf; 975*9e39c5baSBill Taylor lb.alb_fail_buf = (caddr_t)(uintptr_t)lb32.alb_fail_buf; 976*9e39c5baSBill Taylor lb.alb_buf_sz = lb32.alb_buf_sz; 977*9e39c5baSBill Taylor lb.alb_num_iter = lb32.alb_num_iter; 978*9e39c5baSBill Taylor lb.alb_pass_done = lb32.alb_pass_done; 979*9e39c5baSBill Taylor lb.alb_timeout = lb32.alb_timeout; 980*9e39c5baSBill Taylor lb.alb_error_type = lb32.alb_error_type; 981*9e39c5baSBill Taylor lb.alb_port_num = lb32.alb_port_num; 982*9e39c5baSBill Taylor lb.alb_num_retry = lb32.alb_num_retry; 983*9e39c5baSBill Taylor } else 984*9e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */ 985*9e39c5baSBill Taylor if (ddi_copyin((void *)arg, &lb, sizeof (hermon_loopback_ioctl_t), 986*9e39c5baSBill Taylor mode) != 0) { 987*9e39c5baSBill Taylor return (EFAULT); 988*9e39c5baSBill Taylor } 989*9e39c5baSBill Taylor 990*9e39c5baSBill Taylor /* Initialize the internal loopback test state structure */ 991*9e39c5baSBill Taylor bzero(&lstate, sizeof (hermon_loopback_state_t)); 992*9e39c5baSBill Taylor 993*9e39c5baSBill Taylor /* 994*9e39c5baSBill Taylor * Check ioctl revision 995*9e39c5baSBill Taylor */ 996*9e39c5baSBill Taylor if (lb.alb_revision != HERMON_VTS_IOCTL_REVISION) { 997*9e39c5baSBill Taylor lb.alb_error_type = HERMON_LOOPBACK_INVALID_REVISION; 998*9e39c5baSBill Taylor (void) hermon_loopback_copyout(&lb, arg, mode); 999*9e39c5baSBill Taylor return (EINVAL); 1000*9e39c5baSBill Taylor } 1001*9e39c5baSBill Taylor 1002*9e39c5baSBill Taylor /* Validate that specified port number is legal */ 1003*9e39c5baSBill Taylor if (!hermon_portnum_is_valid(state, lb.alb_port_num)) { 1004*9e39c5baSBill Taylor lb.alb_error_type = HERMON_LOOPBACK_INVALID_PORT; 1005*9e39c5baSBill Taylor (void) hermon_loopback_copyout(&lb, arg, mode); 1006*9e39c5baSBill Taylor return (EINVAL); 1007*9e39c5baSBill Taylor } 1008*9e39c5baSBill Taylor 1009*9e39c5baSBill Taylor /* Allocate space for temporary GID table/PKey table */ 1010*9e39c5baSBill Taylor tbl_size = (1 << state->hs_cfg_profile->cp_log_max_gidtbl); 1011*9e39c5baSBill Taylor sgid_tbl = (ib_gid_t *)kmem_zalloc(tbl_size * sizeof (ib_gid_t), 1012*9e39c5baSBill Taylor KM_SLEEP); 1013*9e39c5baSBill Taylor tbl_size = (1 << state->hs_cfg_profile->cp_log_max_pkeytbl); 1014*9e39c5baSBill Taylor pkey_tbl = (ib_pkey_t *)kmem_zalloc(tbl_size * sizeof (ib_pkey_t), 1015*9e39c5baSBill Taylor KM_SLEEP); 1016*9e39c5baSBill Taylor 1017*9e39c5baSBill Taylor /* 1018*9e39c5baSBill Taylor * Get portstate information from specific port on device 1019*9e39c5baSBill Taylor */ 1020*9e39c5baSBill Taylor bzero(&pi, sizeof (ibt_hca_portinfo_t)); 1021*9e39c5baSBill Taylor pi.p_sgid_tbl = sgid_tbl; 1022*9e39c5baSBill Taylor pi.p_pkey_tbl = pkey_tbl; 1023*9e39c5baSBill Taylor if (hermon_port_query(state, lb.alb_port_num, &pi) != 0) { 1024*9e39c5baSBill Taylor /* Free the temporary space used for GID table/PKey table */ 1025*9e39c5baSBill Taylor tbl_size = (1 << state->hs_cfg_profile->cp_log_max_gidtbl); 1026*9e39c5baSBill Taylor kmem_free(sgid_tbl, tbl_size * sizeof (ib_gid_t)); 1027*9e39c5baSBill Taylor tbl_size = (1 << state->hs_cfg_profile->cp_log_max_pkeytbl); 1028*9e39c5baSBill Taylor kmem_free(pkey_tbl, tbl_size * sizeof (ib_pkey_t)); 1029*9e39c5baSBill Taylor 1030*9e39c5baSBill Taylor lb.alb_error_type = HERMON_LOOPBACK_INVALID_PORT; 1031*9e39c5baSBill Taylor (void) hermon_loopback_copyout(&lb, arg, mode); 1032*9e39c5baSBill Taylor hermon_loopback_free_state(&lstate); 1033*9e39c5baSBill Taylor return (EINVAL); 1034*9e39c5baSBill Taylor } 1035*9e39c5baSBill Taylor 1036*9e39c5baSBill Taylor lstate.hls_port = pi.p_port_num; 1037*9e39c5baSBill Taylor lstate.hls_lid = pi.p_base_lid; 1038*9e39c5baSBill Taylor lstate.hls_pkey_ix = (pi.p_linkstate == HERMON_PORT_LINK_ACTIVE) ? 1039*9e39c5baSBill Taylor 1 : 0; /* XXX bogus assumption of a SUN subnet manager */ 1040*9e39c5baSBill Taylor lstate.hls_state = state; 1041*9e39c5baSBill Taylor lstate.hls_retry = lb.alb_num_retry; 1042*9e39c5baSBill Taylor 1043*9e39c5baSBill Taylor /* Free the temporary space used for GID table/PKey table */ 1044*9e39c5baSBill Taylor tbl_size = (1 << state->hs_cfg_profile->cp_log_max_gidtbl); 1045*9e39c5baSBill Taylor kmem_free(sgid_tbl, tbl_size * sizeof (ib_gid_t)); 1046*9e39c5baSBill Taylor tbl_size = (1 << state->hs_cfg_profile->cp_log_max_pkeytbl); 1047*9e39c5baSBill Taylor kmem_free(pkey_tbl, tbl_size * sizeof (ib_pkey_t)); 1048*9e39c5baSBill Taylor 1049*9e39c5baSBill Taylor /* 1050*9e39c5baSBill Taylor * Compute the timeout duration in usec per the formula: 1051*9e39c5baSBill Taylor * to_usec_per_retry = 4.096us * (2 ^ supplied_timeout) 1052*9e39c5baSBill Taylor * (plus we add a little fudge-factor here too) 1053*9e39c5baSBill Taylor */ 1054*9e39c5baSBill Taylor lstate.hls_timeout = lb.alb_timeout; 1055*9e39c5baSBill Taylor max_usec = (4096 * (1 << lstate.hls_timeout)) / 1000; 1056*9e39c5baSBill Taylor max_usec = max_usec * (lstate.hls_retry + 1); 1057*9e39c5baSBill Taylor max_usec = max_usec + 10000; 1058*9e39c5baSBill Taylor 1059*9e39c5baSBill Taylor /* 1060*9e39c5baSBill Taylor * Determine how many times we should loop before declaring a 1061*9e39c5baSBill Taylor * timeout failure. 1062*9e39c5baSBill Taylor */ 1063*9e39c5baSBill Taylor loopmax = max_usec/HERMON_VTS_LOOPBACK_MIN_WAIT_DUR; 1064*9e39c5baSBill Taylor if ((max_usec % HERMON_VTS_LOOPBACK_MIN_WAIT_DUR) != 0) { 1065*9e39c5baSBill Taylor loopmax++; 1066*9e39c5baSBill Taylor } 1067*9e39c5baSBill Taylor 1068*9e39c5baSBill Taylor if (lb.alb_send_buf == NULL || lb.alb_buf_sz == 0) { 1069*9e39c5baSBill Taylor lb.alb_error_type = HERMON_LOOPBACK_SEND_BUF_INVALID; 1070*9e39c5baSBill Taylor (void) hermon_loopback_copyout(&lb, arg, mode); 1071*9e39c5baSBill Taylor hermon_loopback_free_state(&lstate); 1072*9e39c5baSBill Taylor return (EINVAL); 1073*9e39c5baSBill Taylor } 1074*9e39c5baSBill Taylor 1075*9e39c5baSBill Taylor /* Allocate protection domain (PD) */ 1076*9e39c5baSBill Taylor if (hermon_loopback_init(state, &lstate) != 0) { 1077*9e39c5baSBill Taylor lb.alb_error_type = lstate.hls_err; 1078*9e39c5baSBill Taylor (void) hermon_loopback_copyout(&lb, arg, mode); 1079*9e39c5baSBill Taylor hermon_loopback_free_state(&lstate); 1080*9e39c5baSBill Taylor return (EFAULT); 1081*9e39c5baSBill Taylor } 1082*9e39c5baSBill Taylor 1083*9e39c5baSBill Taylor /* Allocate and register a TX buffer */ 1084*9e39c5baSBill Taylor if (hermon_loopback_alloc_mem(&lstate, &lstate.hls_tx, 1085*9e39c5baSBill Taylor lb.alb_buf_sz) != 0) { 1086*9e39c5baSBill Taylor lb.alb_error_type = 1087*9e39c5baSBill Taylor HERMON_LOOPBACK_SEND_BUF_MEM_REGION_ALLOC_FAIL; 1088*9e39c5baSBill Taylor (void) hermon_loopback_copyout(&lb, arg, mode); 1089*9e39c5baSBill Taylor hermon_loopback_free_state(&lstate); 1090*9e39c5baSBill Taylor return (EFAULT); 1091*9e39c5baSBill Taylor } 1092*9e39c5baSBill Taylor 1093*9e39c5baSBill Taylor /* Allocate and register an RX buffer */ 1094*9e39c5baSBill Taylor if (hermon_loopback_alloc_mem(&lstate, &lstate.hls_rx, 1095*9e39c5baSBill Taylor lb.alb_buf_sz) != 0) { 1096*9e39c5baSBill Taylor lb.alb_error_type = 1097*9e39c5baSBill Taylor HERMON_LOOPBACK_RECV_BUF_MEM_REGION_ALLOC_FAIL; 1098*9e39c5baSBill Taylor (void) hermon_loopback_copyout(&lb, arg, mode); 1099*9e39c5baSBill Taylor hermon_loopback_free_state(&lstate); 1100*9e39c5baSBill Taylor return (EFAULT); 1101*9e39c5baSBill Taylor } 1102*9e39c5baSBill Taylor 1103*9e39c5baSBill Taylor /* Copy in the transmit buffer data */ 1104*9e39c5baSBill Taylor if (ddi_copyin((void *)lb.alb_send_buf, lstate.hls_tx.hlc_buf, 1105*9e39c5baSBill Taylor lb.alb_buf_sz, mode) != 0) { 1106*9e39c5baSBill Taylor lb.alb_error_type = HERMON_LOOPBACK_SEND_BUF_COPY_FAIL; 1107*9e39c5baSBill Taylor (void) hermon_loopback_copyout(&lb, arg, mode); 1108*9e39c5baSBill Taylor hermon_loopback_free_state(&lstate); 1109*9e39c5baSBill Taylor return (EFAULT); 1110*9e39c5baSBill Taylor } 1111*9e39c5baSBill Taylor 1112*9e39c5baSBill Taylor /* Allocate the transmit QP and CQs */ 1113*9e39c5baSBill Taylor lstate.hls_err = HERMON_LOOPBACK_XMIT_SEND_CQ_ALLOC_FAIL; 1114*9e39c5baSBill Taylor if (hermon_loopback_alloc_qps(&lstate, &lstate.hls_tx) != 0) { 1115*9e39c5baSBill Taylor lb.alb_error_type = lstate.hls_err; 1116*9e39c5baSBill Taylor (void) hermon_loopback_copyout(&lb, arg, mode); 1117*9e39c5baSBill Taylor hermon_loopback_free_state(&lstate); 1118*9e39c5baSBill Taylor return (EFAULT); 1119*9e39c5baSBill Taylor } 1120*9e39c5baSBill Taylor 1121*9e39c5baSBill Taylor /* Allocate the receive QP and CQs */ 1122*9e39c5baSBill Taylor lstate.hls_err = HERMON_LOOPBACK_RECV_SEND_CQ_ALLOC_FAIL; 1123*9e39c5baSBill Taylor if (hermon_loopback_alloc_qps(&lstate, &lstate.hls_rx) != 0) { 1124*9e39c5baSBill Taylor lb.alb_error_type = lstate.hls_err; 1125*9e39c5baSBill Taylor (void) hermon_loopback_copyout(&lb, arg, mode); 1126*9e39c5baSBill Taylor hermon_loopback_free_state(&lstate); 1127*9e39c5baSBill Taylor return (EFAULT); 1128*9e39c5baSBill Taylor } 1129*9e39c5baSBill Taylor 1130*9e39c5baSBill Taylor /* Activate the TX QP (connect to RX QP) */ 1131*9e39c5baSBill Taylor lstate.hls_err = HERMON_LOOPBACK_XMIT_QP_INIT_FAIL; 1132*9e39c5baSBill Taylor if (hermon_loopback_modify_qp(&lstate, &lstate.hls_tx, 1133*9e39c5baSBill Taylor lstate.hls_rx.hlc_qp_num) != 0) { 1134*9e39c5baSBill Taylor lb.alb_error_type = lstate.hls_err; 1135*9e39c5baSBill Taylor (void) hermon_loopback_copyout(&lb, arg, mode); 1136*9e39c5baSBill Taylor hermon_loopback_free_state(&lstate); 1137*9e39c5baSBill Taylor return (EFAULT); 1138*9e39c5baSBill Taylor } 1139*9e39c5baSBill Taylor 1140*9e39c5baSBill Taylor /* Activate the RX QP (connect to TX QP) */ 1141*9e39c5baSBill Taylor lstate.hls_err = HERMON_LOOPBACK_RECV_QP_INIT_FAIL; 1142*9e39c5baSBill Taylor if (hermon_loopback_modify_qp(&lstate, &lstate.hls_rx, 1143*9e39c5baSBill Taylor lstate.hls_tx.hlc_qp_num) != 0) { 1144*9e39c5baSBill Taylor lb.alb_error_type = lstate.hls_err; 1145*9e39c5baSBill Taylor (void) hermon_loopback_copyout(&lb, arg, mode); 1146*9e39c5baSBill Taylor hermon_loopback_free_state(&lstate); 1147*9e39c5baSBill Taylor return (EFAULT); 1148*9e39c5baSBill Taylor } 1149*9e39c5baSBill Taylor 1150*9e39c5baSBill Taylor /* Run the loopback test (for specified number of iterations) */ 1151*9e39c5baSBill Taylor lb.alb_pass_done = 0; 1152*9e39c5baSBill Taylor for (iter = 0; iter < lb.alb_num_iter; iter++) { 1153*9e39c5baSBill Taylor lstate.hls_err = 0; 1154*9e39c5baSBill Taylor bzero(lstate.hls_rx.hlc_buf, lb.alb_buf_sz); 1155*9e39c5baSBill Taylor 1156*9e39c5baSBill Taylor /* Post RDMA Write work request */ 1157*9e39c5baSBill Taylor if (hermon_loopback_post_send(&lstate, &lstate.hls_tx, 1158*9e39c5baSBill Taylor &lstate.hls_rx) != IBT_SUCCESS) { 1159*9e39c5baSBill Taylor lb.alb_error_type = HERMON_LOOPBACK_WQE_POST_FAIL; 1160*9e39c5baSBill Taylor (void) hermon_loopback_copyout(&lb, arg, mode); 1161*9e39c5baSBill Taylor hermon_loopback_free_state(&lstate); 1162*9e39c5baSBill Taylor return (EFAULT); 1163*9e39c5baSBill Taylor } 1164*9e39c5baSBill Taylor 1165*9e39c5baSBill Taylor /* Poll the TX CQ for a completion every few ticks */ 1166*9e39c5baSBill Taylor for (j = 0; j < loopmax; j++) { 1167*9e39c5baSBill Taylor delay(drv_usectohz(HERMON_VTS_LOOPBACK_MIN_WAIT_DUR)); 1168*9e39c5baSBill Taylor 1169*9e39c5baSBill Taylor ret = hermon_loopback_poll_cq(&lstate, &lstate.hls_tx); 1170*9e39c5baSBill Taylor if (((ret != IBT_SUCCESS) && (ret != IBT_CQ_EMPTY)) || 1171*9e39c5baSBill Taylor ((ret == IBT_CQ_EMPTY) && (j == loopmax - 1))) { 1172*9e39c5baSBill Taylor lb.alb_error_type = 1173*9e39c5baSBill Taylor HERMON_LOOPBACK_CQ_POLL_FAIL; 1174*9e39c5baSBill Taylor if (ddi_copyout(lstate.hls_rx.hlc_buf, 1175*9e39c5baSBill Taylor lb.alb_fail_buf, lstate.hls_tx.hlc_buf_sz, 1176*9e39c5baSBill Taylor mode) != 0) { 1177*9e39c5baSBill Taylor return (EFAULT); 1178*9e39c5baSBill Taylor } 1179*9e39c5baSBill Taylor (void) hermon_loopback_copyout(&lb, arg, mode); 1180*9e39c5baSBill Taylor hermon_loopback_free_state(&lstate); 1181*9e39c5baSBill Taylor return (EFAULT); 1182*9e39c5baSBill Taylor } else if (ret == IBT_CQ_EMPTY) { 1183*9e39c5baSBill Taylor continue; 1184*9e39c5baSBill Taylor } 1185*9e39c5baSBill Taylor 1186*9e39c5baSBill Taylor /* Compare the data buffers */ 1187*9e39c5baSBill Taylor if (bcmp(lstate.hls_tx.hlc_buf, lstate.hls_rx.hlc_buf, 1188*9e39c5baSBill Taylor lb.alb_buf_sz) == 0) { 1189*9e39c5baSBill Taylor break; 1190*9e39c5baSBill Taylor } else { 1191*9e39c5baSBill Taylor lb.alb_error_type = 1192*9e39c5baSBill Taylor HERMON_LOOPBACK_SEND_RECV_COMPARE_FAIL; 1193*9e39c5baSBill Taylor if (ddi_copyout(lstate.hls_rx.hlc_buf, 1194*9e39c5baSBill Taylor lb.alb_fail_buf, lstate.hls_tx.hlc_buf_sz, 1195*9e39c5baSBill Taylor mode) != 0) { 1196*9e39c5baSBill Taylor return (EFAULT); 1197*9e39c5baSBill Taylor } 1198*9e39c5baSBill Taylor (void) hermon_loopback_copyout(&lb, arg, mode); 1199*9e39c5baSBill Taylor hermon_loopback_free_state(&lstate); 1200*9e39c5baSBill Taylor return (EFAULT); 1201*9e39c5baSBill Taylor } 1202*9e39c5baSBill Taylor } 1203*9e39c5baSBill Taylor 1204*9e39c5baSBill Taylor lstate.hls_err = HERMON_LOOPBACK_SUCCESS; 1205*9e39c5baSBill Taylor lb.alb_pass_done = iter + 1; 1206*9e39c5baSBill Taylor } 1207*9e39c5baSBill Taylor 1208*9e39c5baSBill Taylor lb.alb_error_type = HERMON_LOOPBACK_SUCCESS; 1209*9e39c5baSBill Taylor 1210*9e39c5baSBill Taylor /* Copy ioctl results back to user struct */ 1211*9e39c5baSBill Taylor ret = hermon_loopback_copyout(&lb, arg, mode); 1212*9e39c5baSBill Taylor 1213*9e39c5baSBill Taylor /* Free up everything and release all consumed resources */ 1214*9e39c5baSBill Taylor hermon_loopback_free_state(&lstate); 1215*9e39c5baSBill Taylor 1216*9e39c5baSBill Taylor return (ret); 1217*9e39c5baSBill Taylor } 1218*9e39c5baSBill Taylor 1219*9e39c5baSBill Taylor #ifdef DEBUG 1220*9e39c5baSBill Taylor /* 1221*9e39c5baSBill Taylor * hermon_ioctl_reg_read() 1222*9e39c5baSBill Taylor */ 1223*9e39c5baSBill Taylor static int 1224*9e39c5baSBill Taylor hermon_ioctl_reg_read(hermon_state_t *state, intptr_t arg, int mode) 1225*9e39c5baSBill Taylor { 1226*9e39c5baSBill Taylor hermon_reg_ioctl_t rdreg; 1227*9e39c5baSBill Taylor uint32_t *addr; 1228*9e39c5baSBill Taylor uintptr_t baseaddr; 1229*9e39c5baSBill Taylor int status; 1230*9e39c5baSBill Taylor ddi_acc_handle_t handle; 1231*9e39c5baSBill Taylor 1232*9e39c5baSBill Taylor /* initialize the FMA retry loop */ 1233*9e39c5baSBill Taylor hermon_pio_init(fm_loop_cnt, fm_status, fm_test); 1234*9e39c5baSBill Taylor 1235*9e39c5baSBill Taylor /* 1236*9e39c5baSBill Taylor * Access to Hemron registers is not allowed in "maintenance mode". 1237*9e39c5baSBill Taylor * This is primarily because the device may not have BARs to access 1238*9e39c5baSBill Taylor */ 1239*9e39c5baSBill Taylor if (state->hs_operational_mode == HERMON_MAINTENANCE_MODE) { 1240*9e39c5baSBill Taylor return (EFAULT); 1241*9e39c5baSBill Taylor } 1242*9e39c5baSBill Taylor 1243*9e39c5baSBill Taylor /* Copy in the hermon_reg_ioctl_t structure */ 1244*9e39c5baSBill Taylor status = ddi_copyin((void *)arg, &rdreg, sizeof (hermon_reg_ioctl_t), 1245*9e39c5baSBill Taylor mode); 1246*9e39c5baSBill Taylor if (status != 0) { 1247*9e39c5baSBill Taylor return (EFAULT); 1248*9e39c5baSBill Taylor } 1249*9e39c5baSBill Taylor 1250*9e39c5baSBill Taylor /* Determine base address for requested register set */ 1251*9e39c5baSBill Taylor switch (rdreg.arg_reg_set) { 1252*9e39c5baSBill Taylor case HERMON_CMD_BAR: 1253*9e39c5baSBill Taylor baseaddr = (uintptr_t)state->hs_reg_cmd_baseaddr; 1254*9e39c5baSBill Taylor handle = hermon_get_cmdhdl(state); 1255*9e39c5baSBill Taylor break; 1256*9e39c5baSBill Taylor 1257*9e39c5baSBill Taylor case HERMON_UAR_BAR: 1258*9e39c5baSBill Taylor baseaddr = (uintptr_t)state->hs_reg_uar_baseaddr; 1259*9e39c5baSBill Taylor handle = hermon_get_uarhdl(state); 1260*9e39c5baSBill Taylor break; 1261*9e39c5baSBill Taylor 1262*9e39c5baSBill Taylor 1263*9e39c5baSBill Taylor default: 1264*9e39c5baSBill Taylor return (EINVAL); 1265*9e39c5baSBill Taylor } 1266*9e39c5baSBill Taylor 1267*9e39c5baSBill Taylor /* Ensure that address is properly-aligned */ 1268*9e39c5baSBill Taylor addr = (uint32_t *)((baseaddr + rdreg.arg_offset) & ~0x3); 1269*9e39c5baSBill Taylor 1270*9e39c5baSBill Taylor /* the FMA retry loop starts. */ 1271*9e39c5baSBill Taylor hermon_pio_start(state, handle, pio_error, fm_loop_cnt, 1272*9e39c5baSBill Taylor fm_status, fm_test); 1273*9e39c5baSBill Taylor 1274*9e39c5baSBill Taylor /* Read the register pointed to by addr */ 1275*9e39c5baSBill Taylor rdreg.arg_data = ddi_get32(handle, addr); 1276*9e39c5baSBill Taylor 1277*9e39c5baSBill Taylor /* the FMA retry loop ends. */ 1278*9e39c5baSBill Taylor hermon_pio_end(state, handle, pio_error, fm_loop_cnt, fm_status, 1279*9e39c5baSBill Taylor fm_test); 1280*9e39c5baSBill Taylor 1281*9e39c5baSBill Taylor /* Copy in the result into the hermon_reg_ioctl_t structure */ 1282*9e39c5baSBill Taylor status = ddi_copyout(&rdreg, (void *)arg, sizeof (hermon_reg_ioctl_t), 1283*9e39c5baSBill Taylor mode); 1284*9e39c5baSBill Taylor if (status != 0) { 1285*9e39c5baSBill Taylor return (EFAULT); 1286*9e39c5baSBill Taylor } 1287*9e39c5baSBill Taylor return (0); 1288*9e39c5baSBill Taylor 1289*9e39c5baSBill Taylor pio_error: 1290*9e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL); 1291*9e39c5baSBill Taylor return (EIO); 1292*9e39c5baSBill Taylor } 1293*9e39c5baSBill Taylor 1294*9e39c5baSBill Taylor 1295*9e39c5baSBill Taylor /* 1296*9e39c5baSBill Taylor * hermon_ioctl_reg_write() 1297*9e39c5baSBill Taylor */ 1298*9e39c5baSBill Taylor static int 1299*9e39c5baSBill Taylor hermon_ioctl_reg_write(hermon_state_t *state, intptr_t arg, int mode) 1300*9e39c5baSBill Taylor { 1301*9e39c5baSBill Taylor hermon_reg_ioctl_t wrreg; 1302*9e39c5baSBill Taylor uint32_t *addr; 1303*9e39c5baSBill Taylor uintptr_t baseaddr; 1304*9e39c5baSBill Taylor int status; 1305*9e39c5baSBill Taylor ddi_acc_handle_t handle; 1306*9e39c5baSBill Taylor 1307*9e39c5baSBill Taylor /* initialize the FMA retry loop */ 1308*9e39c5baSBill Taylor hermon_pio_init(fm_loop_cnt, fm_status, fm_test); 1309*9e39c5baSBill Taylor 1310*9e39c5baSBill Taylor /* 1311*9e39c5baSBill Taylor * Access to Hermon registers is not allowed in "maintenance mode". 1312*9e39c5baSBill Taylor * This is primarily because the device may not have BARs to access 1313*9e39c5baSBill Taylor */ 1314*9e39c5baSBill Taylor if (state->hs_operational_mode == HERMON_MAINTENANCE_MODE) { 1315*9e39c5baSBill Taylor return (EFAULT); 1316*9e39c5baSBill Taylor } 1317*9e39c5baSBill Taylor 1318*9e39c5baSBill Taylor /* Copy in the hermon_reg_ioctl_t structure */ 1319*9e39c5baSBill Taylor status = ddi_copyin((void *)arg, &wrreg, sizeof (hermon_reg_ioctl_t), 1320*9e39c5baSBill Taylor mode); 1321*9e39c5baSBill Taylor if (status != 0) { 1322*9e39c5baSBill Taylor return (EFAULT); 1323*9e39c5baSBill Taylor } 1324*9e39c5baSBill Taylor 1325*9e39c5baSBill Taylor /* Determine base address for requested register set */ 1326*9e39c5baSBill Taylor switch (wrreg.arg_reg_set) { 1327*9e39c5baSBill Taylor case HERMON_CMD_BAR: 1328*9e39c5baSBill Taylor baseaddr = (uintptr_t)state->hs_reg_cmd_baseaddr; 1329*9e39c5baSBill Taylor handle = hermon_get_cmdhdl(state); 1330*9e39c5baSBill Taylor break; 1331*9e39c5baSBill Taylor 1332*9e39c5baSBill Taylor case HERMON_UAR_BAR: 1333*9e39c5baSBill Taylor baseaddr = (uintptr_t)state->hs_reg_uar_baseaddr; 1334*9e39c5baSBill Taylor handle = hermon_get_uarhdl(state); 1335*9e39c5baSBill Taylor break; 1336*9e39c5baSBill Taylor 1337*9e39c5baSBill Taylor default: 1338*9e39c5baSBill Taylor return (EINVAL); 1339*9e39c5baSBill Taylor } 1340*9e39c5baSBill Taylor 1341*9e39c5baSBill Taylor /* Ensure that address is properly-aligned */ 1342*9e39c5baSBill Taylor addr = (uint32_t *)((baseaddr + wrreg.arg_offset) & ~0x3); 1343*9e39c5baSBill Taylor 1344*9e39c5baSBill Taylor /* the FMA retry loop starts. */ 1345*9e39c5baSBill Taylor hermon_pio_start(state, handle, pio_error, fm_loop_cnt, 1346*9e39c5baSBill Taylor fm_status, fm_test); 1347*9e39c5baSBill Taylor 1348*9e39c5baSBill Taylor /* Write the data to the register pointed to by addr */ 1349*9e39c5baSBill Taylor ddi_put32(handle, addr, wrreg.arg_data); 1350*9e39c5baSBill Taylor 1351*9e39c5baSBill Taylor /* the FMA retry loop ends. */ 1352*9e39c5baSBill Taylor hermon_pio_end(state, handle, pio_error, fm_loop_cnt, fm_status, 1353*9e39c5baSBill Taylor fm_test); 1354*9e39c5baSBill Taylor return (0); 1355*9e39c5baSBill Taylor 1356*9e39c5baSBill Taylor pio_error: 1357*9e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL); 1358*9e39c5baSBill Taylor return (EIO); 1359*9e39c5baSBill Taylor } 1360*9e39c5baSBill Taylor #endif /* DEBUG */ 1361*9e39c5baSBill Taylor 1362*9e39c5baSBill Taylor static int 1363*9e39c5baSBill Taylor hermon_ioctl_write_boot_addr(hermon_state_t *state, dev_t dev, intptr_t arg, 1364*9e39c5baSBill Taylor int mode) 1365*9e39c5baSBill Taylor { 1366*9e39c5baSBill Taylor hermon_flash_ioctl_t ioctl_info; 1367*9e39c5baSBill Taylor 1368*9e39c5baSBill Taylor /* initialize the FMA retry loop */ 1369*9e39c5baSBill Taylor hermon_pio_init(fm_loop_cnt, fm_status, fm_test); 1370*9e39c5baSBill Taylor 1371*9e39c5baSBill Taylor /* 1372*9e39c5baSBill Taylor * Check that flash init ioctl has been called first. And check 1373*9e39c5baSBill Taylor * that the same dev_t that called init is the one calling write now. 1374*9e39c5baSBill Taylor */ 1375*9e39c5baSBill Taylor mutex_enter(&state->hs_fw_flashlock); 1376*9e39c5baSBill Taylor if ((state->hs_fw_flashdev != dev) || 1377*9e39c5baSBill Taylor (state->hs_fw_flashstarted == 0)) { 1378*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 1379*9e39c5baSBill Taylor return (EIO); 1380*9e39c5baSBill Taylor } 1381*9e39c5baSBill Taylor 1382*9e39c5baSBill Taylor /* copy user struct to kernel */ 1383*9e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL 1384*9e39c5baSBill Taylor if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 1385*9e39c5baSBill Taylor hermon_flash_ioctl32_t info32; 1386*9e39c5baSBill Taylor 1387*9e39c5baSBill Taylor if (ddi_copyin((void *)arg, &info32, 1388*9e39c5baSBill Taylor sizeof (hermon_flash_ioctl32_t), mode) != 0) { 1389*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 1390*9e39c5baSBill Taylor return (EFAULT); 1391*9e39c5baSBill Taylor } 1392*9e39c5baSBill Taylor ioctl_info.af_type = info32.af_type; 1393*9e39c5baSBill Taylor ioctl_info.af_sector = (caddr_t)(uintptr_t)info32.af_sector; 1394*9e39c5baSBill Taylor ioctl_info.af_sector_num = info32.af_sector_num; 1395*9e39c5baSBill Taylor ioctl_info.af_addr = info32.af_addr; 1396*9e39c5baSBill Taylor ioctl_info.af_byte = info32.af_byte; 1397*9e39c5baSBill Taylor } else 1398*9e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */ 1399*9e39c5baSBill Taylor if (ddi_copyin((void *)arg, &ioctl_info, 1400*9e39c5baSBill Taylor sizeof (hermon_flash_ioctl_t), mode) != 0) { 1401*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 1402*9e39c5baSBill Taylor return (EFAULT); 1403*9e39c5baSBill Taylor } 1404*9e39c5baSBill Taylor 1405*9e39c5baSBill Taylor switch (state->hs_fw_cmdset) { 1406*9e39c5baSBill Taylor case HERMON_FLASH_AMD_CMDSET: 1407*9e39c5baSBill Taylor case HERMON_FLASH_INTEL_CMDSET: 1408*9e39c5baSBill Taylor break; 1409*9e39c5baSBill Taylor 1410*9e39c5baSBill Taylor case HERMON_FLASH_SPI_CMDSET: 1411*9e39c5baSBill Taylor { 1412*9e39c5baSBill Taylor ddi_acc_handle_t pci_hdl = hermon_get_pcihdl(state); 1413*9e39c5baSBill Taylor 1414*9e39c5baSBill Taylor /* the FMA retry loop starts. */ 1415*9e39c5baSBill Taylor hermon_pio_start(state, pci_hdl, pio_error, 1416*9e39c5baSBill Taylor fm_loop_cnt, fm_status, fm_test); 1417*9e39c5baSBill Taylor 1418*9e39c5baSBill Taylor hermon_flash_write_cfg(state, pci_hdl, 1419*9e39c5baSBill Taylor HERMON_HW_FLASH_SPI_BOOT_ADDR_REG, 1420*9e39c5baSBill Taylor (ioctl_info.af_addr << 8) | 0x06); 1421*9e39c5baSBill Taylor 1422*9e39c5baSBill Taylor /* the FMA retry loop ends. */ 1423*9e39c5baSBill Taylor hermon_pio_end(state, pci_hdl, pio_error, 1424*9e39c5baSBill Taylor fm_loop_cnt, fm_status, fm_test); 1425*9e39c5baSBill Taylor break; 1426*9e39c5baSBill Taylor } 1427*9e39c5baSBill Taylor 1428*9e39c5baSBill Taylor case HERMON_FLASH_UNKNOWN_CMDSET: 1429*9e39c5baSBill Taylor default: 1430*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 1431*9e39c5baSBill Taylor return (EINVAL); 1432*9e39c5baSBill Taylor } 1433*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 1434*9e39c5baSBill Taylor return (0); 1435*9e39c5baSBill Taylor 1436*9e39c5baSBill Taylor pio_error: 1437*9e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock); 1438*9e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL); 1439*9e39c5baSBill Taylor return (EIO); 1440*9e39c5baSBill Taylor } 1441*9e39c5baSBill Taylor 1442*9e39c5baSBill Taylor /* 1443*9e39c5baSBill Taylor * hermon_flash_reset() 1444*9e39c5baSBill Taylor */ 1445*9e39c5baSBill Taylor static int 1446*9e39c5baSBill Taylor hermon_flash_reset(hermon_state_t *state) 1447*9e39c5baSBill Taylor { 1448*9e39c5baSBill Taylor int status; 1449*9e39c5baSBill Taylor 1450*9e39c5baSBill Taylor /* 1451*9e39c5baSBill Taylor * Performs a reset to the flash device. After a reset the flash will 1452*9e39c5baSBill Taylor * be operating in normal mode (capable of read/write, etc.). 1453*9e39c5baSBill Taylor */ 1454*9e39c5baSBill Taylor switch (state->hs_fw_cmdset) { 1455*9e39c5baSBill Taylor case HERMON_FLASH_AMD_CMDSET: 1456*9e39c5baSBill Taylor hermon_flash_write(state, 0x555, HERMON_HW_FLASH_RESET_AMD, 1457*9e39c5baSBill Taylor &status); 1458*9e39c5baSBill Taylor if (status != 0) { 1459*9e39c5baSBill Taylor return (status); 1460*9e39c5baSBill Taylor } 1461*9e39c5baSBill Taylor break; 1462*9e39c5baSBill Taylor 1463*9e39c5baSBill Taylor case HERMON_FLASH_INTEL_CMDSET: 1464*9e39c5baSBill Taylor hermon_flash_write(state, 0x555, HERMON_HW_FLASH_RESET_INTEL, 1465*9e39c5baSBill Taylor &status); 1466*9e39c5baSBill Taylor if (status != 0) { 1467*9e39c5baSBill Taylor return (status); 1468*9e39c5baSBill Taylor } 1469*9e39c5baSBill Taylor break; 1470*9e39c5baSBill Taylor 1471*9e39c5baSBill Taylor /* It appears no reset is needed for SPI */ 1472*9e39c5baSBill Taylor case HERMON_FLASH_SPI_CMDSET: 1473*9e39c5baSBill Taylor status = 0; 1474*9e39c5baSBill Taylor break; 1475*9e39c5baSBill Taylor 1476*9e39c5baSBill Taylor case HERMON_FLASH_UNKNOWN_CMDSET: 1477*9e39c5baSBill Taylor default: 1478*9e39c5baSBill Taylor status = EINVAL; 1479*9e39c5baSBill Taylor break; 1480*9e39c5baSBill Taylor } 1481*9e39c5baSBill Taylor return (status); 1482*9e39c5baSBill Taylor } 1483*9e39c5baSBill Taylor 1484*9e39c5baSBill Taylor /* 1485*9e39c5baSBill Taylor * hermon_flash_read_sector() 1486*9e39c5baSBill Taylor */ 1487*9e39c5baSBill Taylor static int 1488*9e39c5baSBill Taylor hermon_flash_read_sector(hermon_state_t *state, uint32_t sector_num) 1489*9e39c5baSBill Taylor { 1490*9e39c5baSBill Taylor uint32_t addr; 1491*9e39c5baSBill Taylor uint32_t end_addr; 1492*9e39c5baSBill Taylor uint32_t *image; 1493*9e39c5baSBill Taylor int i, status; 1494*9e39c5baSBill Taylor 1495*9e39c5baSBill Taylor image = (uint32_t *)&state->hs_fw_sector[0]; 1496*9e39c5baSBill Taylor 1497*9e39c5baSBill Taylor /* 1498*9e39c5baSBill Taylor * Calculate the start and end address of the sector, based on the 1499*9e39c5baSBill Taylor * sector number passed in. 1500*9e39c5baSBill Taylor */ 1501*9e39c5baSBill Taylor addr = sector_num << state->hs_fw_log_sector_sz; 1502*9e39c5baSBill Taylor end_addr = addr + (1 << state->hs_fw_log_sector_sz); 1503*9e39c5baSBill Taylor 1504*9e39c5baSBill Taylor /* Set the flash bank correctly for the given address */ 1505*9e39c5baSBill Taylor if ((status = hermon_flash_bank(state, addr)) != 0) 1506*9e39c5baSBill Taylor return (status); 1507*9e39c5baSBill Taylor 1508*9e39c5baSBill Taylor /* Read the entire sector, one quadlet at a time */ 1509*9e39c5baSBill Taylor for (i = 0; addr < end_addr; i++, addr += 4) { 1510*9e39c5baSBill Taylor image[i] = hermon_flash_read(state, addr, &status); 1511*9e39c5baSBill Taylor if (status != 0) { 1512*9e39c5baSBill Taylor return (status); 1513*9e39c5baSBill Taylor } 1514*9e39c5baSBill Taylor } 1515*9e39c5baSBill Taylor return (0); 1516*9e39c5baSBill Taylor } 1517*9e39c5baSBill Taylor 1518*9e39c5baSBill Taylor /* 1519*9e39c5baSBill Taylor * hermon_flash_read_quadlet() 1520*9e39c5baSBill Taylor */ 1521*9e39c5baSBill Taylor static int 1522*9e39c5baSBill Taylor hermon_flash_read_quadlet(hermon_state_t *state, uint32_t *data, 1523*9e39c5baSBill Taylor uint32_t addr) 1524*9e39c5baSBill Taylor { 1525*9e39c5baSBill Taylor int status; 1526*9e39c5baSBill Taylor 1527*9e39c5baSBill Taylor /* Set the flash bank correctly for the given address */ 1528*9e39c5baSBill Taylor if ((status = hermon_flash_bank(state, addr)) != 0) { 1529*9e39c5baSBill Taylor return (status); 1530*9e39c5baSBill Taylor } 1531*9e39c5baSBill Taylor 1532*9e39c5baSBill Taylor /* Read one quadlet of data */ 1533*9e39c5baSBill Taylor *data = hermon_flash_read(state, addr, &status); 1534*9e39c5baSBill Taylor if (status != 0) { 1535*9e39c5baSBill Taylor return (EIO); 1536*9e39c5baSBill Taylor } 1537*9e39c5baSBill Taylor 1538*9e39c5baSBill Taylor return (0); 1539*9e39c5baSBill Taylor } 1540*9e39c5baSBill Taylor 1541*9e39c5baSBill Taylor /* 1542*9e39c5baSBill Taylor * hermon_flash_write_sector() 1543*9e39c5baSBill Taylor */ 1544*9e39c5baSBill Taylor static int 1545*9e39c5baSBill Taylor hermon_flash_write_sector(hermon_state_t *state, uint32_t sector_num) 1546*9e39c5baSBill Taylor { 1547*9e39c5baSBill Taylor uint32_t addr; 1548*9e39c5baSBill Taylor uint32_t end_addr; 1549*9e39c5baSBill Taylor uint32_t *databuf; 1550*9e39c5baSBill Taylor uchar_t *sector; 1551*9e39c5baSBill Taylor int status = 0; 1552*9e39c5baSBill Taylor int i; 1553*9e39c5baSBill Taylor 1554*9e39c5baSBill Taylor sector = (uchar_t *)&state->hs_fw_sector[0]; 1555*9e39c5baSBill Taylor 1556*9e39c5baSBill Taylor /* 1557*9e39c5baSBill Taylor * Calculate the start and end address of the sector, based on the 1558*9e39c5baSBill Taylor * sector number passed in. 1559*9e39c5baSBill Taylor */ 1560*9e39c5baSBill Taylor addr = sector_num << state->hs_fw_log_sector_sz; 1561*9e39c5baSBill Taylor end_addr = addr + (1 << state->hs_fw_log_sector_sz); 1562*9e39c5baSBill Taylor 1563*9e39c5baSBill Taylor /* Set the flash bank correctly for the given address */ 1564*9e39c5baSBill Taylor if ((status = hermon_flash_bank(state, addr)) != 0 || 1565*9e39c5baSBill Taylor (status = hermon_flash_reset(state)) != 0) { 1566*9e39c5baSBill Taylor return (status); 1567*9e39c5baSBill Taylor } 1568*9e39c5baSBill Taylor 1569*9e39c5baSBill Taylor /* Erase the sector before writing */ 1570*9e39c5baSBill Taylor status = hermon_flash_erase_sector(state, sector_num); 1571*9e39c5baSBill Taylor if (status != 0) { 1572*9e39c5baSBill Taylor return (status); 1573*9e39c5baSBill Taylor } 1574*9e39c5baSBill Taylor 1575*9e39c5baSBill Taylor switch (state->hs_fw_cmdset) { 1576*9e39c5baSBill Taylor case HERMON_FLASH_SPI_CMDSET: 1577*9e39c5baSBill Taylor databuf = (uint32_t *)(void *)sector; 1578*9e39c5baSBill Taylor /* Write the sector, one dword at a time */ 1579*9e39c5baSBill Taylor for (i = 0; addr < end_addr; i++, addr += 4) { 1580*9e39c5baSBill Taylor if ((status = hermon_flash_spi_write_dword(state, addr, 1581*9e39c5baSBill Taylor htonl(databuf[i]))) != 0) { 1582*9e39c5baSBill Taylor return (status); 1583*9e39c5baSBill Taylor } 1584*9e39c5baSBill Taylor } 1585*9e39c5baSBill Taylor status = hermon_flash_reset(state); 1586*9e39c5baSBill Taylor break; 1587*9e39c5baSBill Taylor 1588*9e39c5baSBill Taylor case HERMON_FLASH_INTEL_CMDSET: 1589*9e39c5baSBill Taylor case HERMON_FLASH_AMD_CMDSET: 1590*9e39c5baSBill Taylor /* Write the sector, one byte at a time */ 1591*9e39c5baSBill Taylor for (i = 0; addr < end_addr; i++, addr++) { 1592*9e39c5baSBill Taylor status = hermon_flash_write_byte(state, addr, 1593*9e39c5baSBill Taylor sector[i]); 1594*9e39c5baSBill Taylor if (status != 0) { 1595*9e39c5baSBill Taylor break; 1596*9e39c5baSBill Taylor } 1597*9e39c5baSBill Taylor } 1598*9e39c5baSBill Taylor status = hermon_flash_reset(state); 1599*9e39c5baSBill Taylor break; 1600*9e39c5baSBill Taylor 1601*9e39c5baSBill Taylor case HERMON_FLASH_UNKNOWN_CMDSET: 1602*9e39c5baSBill Taylor default: 1603*9e39c5baSBill Taylor status = EINVAL; 1604*9e39c5baSBill Taylor break; 1605*9e39c5baSBill Taylor } 1606*9e39c5baSBill Taylor 1607*9e39c5baSBill Taylor return (status); 1608*9e39c5baSBill Taylor } 1609*9e39c5baSBill Taylor 1610*9e39c5baSBill Taylor /* 1611*9e39c5baSBill Taylor * hermon_flash_spi_write_dword() 1612*9e39c5baSBill Taylor * 1613*9e39c5baSBill Taylor * NOTE: This function assumes that "data" is in network byte order. 1614*9e39c5baSBill Taylor * 1615*9e39c5baSBill Taylor */ 1616*9e39c5baSBill Taylor static int 1617*9e39c5baSBill Taylor hermon_flash_spi_write_dword(hermon_state_t *state, uint32_t addr, 1618*9e39c5baSBill Taylor uint32_t data) 1619*9e39c5baSBill Taylor { 1620*9e39c5baSBill Taylor int status; 1621*9e39c5baSBill Taylor ddi_acc_handle_t hdl; 1622*9e39c5baSBill Taylor 1623*9e39c5baSBill Taylor /* initialize the FMA retry loop */ 1624*9e39c5baSBill Taylor hermon_pio_init(fm_loop_cnt, fm_status, fm_test); 1625*9e39c5baSBill Taylor 1626*9e39c5baSBill Taylor hdl = hermon_get_pcihdl(state); 1627*9e39c5baSBill Taylor 1628*9e39c5baSBill Taylor /* the FMA retry loop starts. */ 1629*9e39c5baSBill Taylor hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status, 1630*9e39c5baSBill Taylor fm_test); 1631*9e39c5baSBill Taylor 1632*9e39c5baSBill Taylor /* Issue Write Enable */ 1633*9e39c5baSBill Taylor hermon_flash_spi_write_enable(state); 1634*9e39c5baSBill Taylor 1635*9e39c5baSBill Taylor /* Set the Address */ 1636*9e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_SPI_ADDR, 1637*9e39c5baSBill Taylor addr & HERMON_HW_FLASH_SPI_ADDR_MASK); 1638*9e39c5baSBill Taylor 1639*9e39c5baSBill Taylor /* Set the Data */ 1640*9e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_SPI_DATA, data); 1641*9e39c5baSBill Taylor 1642*9e39c5baSBill Taylor /* Set the Page Program and execute */ 1643*9e39c5baSBill Taylor hermon_flash_spi_exec_command(state, hdl, 1644*9e39c5baSBill Taylor HERMON_HW_FLASH_SPI_INSTR_PHASE_OFF | 1645*9e39c5baSBill Taylor HERMON_HW_FLASH_SPI_ADDR_PHASE_OFF | 1646*9e39c5baSBill Taylor HERMON_HW_FLASH_SPI_DATA_PHASE_OFF | 1647*9e39c5baSBill Taylor HERMON_HW_FLASH_SPI_TRANS_SZ_4B | 1648*9e39c5baSBill Taylor (HERMON_HW_FLASH_SPI_PAGE_PROGRAM << 1649*9e39c5baSBill Taylor HERMON_HW_FLASH_SPI_INSTR_SHIFT)); 1650*9e39c5baSBill Taylor 1651*9e39c5baSBill Taylor /* Wait for write to complete */ 1652*9e39c5baSBill Taylor if ((status = hermon_flash_spi_wait_wip(state)) != 0) { 1653*9e39c5baSBill Taylor return (status); 1654*9e39c5baSBill Taylor } 1655*9e39c5baSBill Taylor 1656*9e39c5baSBill Taylor /* the FMA retry loop ends. */ 1657*9e39c5baSBill Taylor hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status, fm_test); 1658*9e39c5baSBill Taylor return (0); 1659*9e39c5baSBill Taylor 1660*9e39c5baSBill Taylor pio_error: 1661*9e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL); 1662*9e39c5baSBill Taylor return (EIO); 1663*9e39c5baSBill Taylor } 1664*9e39c5baSBill Taylor 1665*9e39c5baSBill Taylor /* 1666*9e39c5baSBill Taylor * hermon_flash_write_byte() 1667*9e39c5baSBill Taylor */ 1668*9e39c5baSBill Taylor static int 1669*9e39c5baSBill Taylor hermon_flash_write_byte(hermon_state_t *state, uint32_t addr, uchar_t data) 1670*9e39c5baSBill Taylor { 1671*9e39c5baSBill Taylor uint32_t stat; 1672*9e39c5baSBill Taylor int status = 0; 1673*9e39c5baSBill Taylor int dword_addr; 1674*9e39c5baSBill Taylor int byte_offset; 1675*9e39c5baSBill Taylor int i; 1676*9e39c5baSBill Taylor union { 1677*9e39c5baSBill Taylor uint8_t bytes[4]; 1678*9e39c5baSBill Taylor uint32_t dword; 1679*9e39c5baSBill Taylor } dword; 1680*9e39c5baSBill Taylor 1681*9e39c5baSBill Taylor switch (state->hs_fw_cmdset) { 1682*9e39c5baSBill Taylor case HERMON_FLASH_AMD_CMDSET: 1683*9e39c5baSBill Taylor /* Issue Flash Byte program command */ 1684*9e39c5baSBill Taylor hermon_flash_write(state, addr, 0xAA, &status); 1685*9e39c5baSBill Taylor if (status != 0) { 1686*9e39c5baSBill Taylor return (status); 1687*9e39c5baSBill Taylor } 1688*9e39c5baSBill Taylor 1689*9e39c5baSBill Taylor hermon_flash_write(state, addr, 0x55, &status); 1690*9e39c5baSBill Taylor if (status != 0) { 1691*9e39c5baSBill Taylor return (status); 1692*9e39c5baSBill Taylor } 1693*9e39c5baSBill Taylor 1694*9e39c5baSBill Taylor hermon_flash_write(state, addr, 0xA0, &status); 1695*9e39c5baSBill Taylor if (status != 0) { 1696*9e39c5baSBill Taylor return (status); 1697*9e39c5baSBill Taylor } 1698*9e39c5baSBill Taylor 1699*9e39c5baSBill Taylor hermon_flash_write(state, addr, data, &status); 1700*9e39c5baSBill Taylor if (status != 0) { 1701*9e39c5baSBill Taylor return (status); 1702*9e39c5baSBill Taylor } 1703*9e39c5baSBill Taylor 1704*9e39c5baSBill Taylor /* Wait for Write Byte to Complete */ 1705*9e39c5baSBill Taylor i = 0; 1706*9e39c5baSBill Taylor do { 1707*9e39c5baSBill Taylor drv_usecwait(1); 1708*9e39c5baSBill Taylor stat = hermon_flash_read(state, addr & ~3, &status); 1709*9e39c5baSBill Taylor if (status != 0) { 1710*9e39c5baSBill Taylor return (status); 1711*9e39c5baSBill Taylor } 1712*9e39c5baSBill Taylor 1713*9e39c5baSBill Taylor if (i == hermon_hw_flash_timeout_write) { 1714*9e39c5baSBill Taylor cmn_err(CE_WARN, 1715*9e39c5baSBill Taylor "hermon_flash_write_byte: ACS write " 1716*9e39c5baSBill Taylor "timeout: addr: 0x%x, data: 0x%x\n", 1717*9e39c5baSBill Taylor addr, data); 1718*9e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR, 1719*9e39c5baSBill Taylor HCA_ERR_IOCTL); 1720*9e39c5baSBill Taylor return (EIO); 1721*9e39c5baSBill Taylor } 1722*9e39c5baSBill Taylor i++; 1723*9e39c5baSBill Taylor } while (data != ((stat >> ((3 - (addr & 3)) << 3)) & 0xFF)); 1724*9e39c5baSBill Taylor 1725*9e39c5baSBill Taylor break; 1726*9e39c5baSBill Taylor 1727*9e39c5baSBill Taylor case HERMON_FLASH_INTEL_CMDSET: 1728*9e39c5baSBill Taylor /* Issue Flash Byte program command */ 1729*9e39c5baSBill Taylor hermon_flash_write(state, addr, HERMON_HW_FLASH_ICS_WRITE, 1730*9e39c5baSBill Taylor &status); 1731*9e39c5baSBill Taylor if (status != 0) { 1732*9e39c5baSBill Taylor return (status); 1733*9e39c5baSBill Taylor } 1734*9e39c5baSBill Taylor hermon_flash_write(state, addr, data, &status); 1735*9e39c5baSBill Taylor if (status != 0) { 1736*9e39c5baSBill Taylor return (status); 1737*9e39c5baSBill Taylor } 1738*9e39c5baSBill Taylor 1739*9e39c5baSBill Taylor /* Wait for Write Byte to Complete */ 1740*9e39c5baSBill Taylor i = 0; 1741*9e39c5baSBill Taylor do { 1742*9e39c5baSBill Taylor drv_usecwait(1); 1743*9e39c5baSBill Taylor stat = hermon_flash_read(state, addr & ~3, &status); 1744*9e39c5baSBill Taylor if (status != 0) { 1745*9e39c5baSBill Taylor return (status); 1746*9e39c5baSBill Taylor } 1747*9e39c5baSBill Taylor 1748*9e39c5baSBill Taylor if (i == hermon_hw_flash_timeout_write) { 1749*9e39c5baSBill Taylor cmn_err(CE_WARN, 1750*9e39c5baSBill Taylor "hermon_flash_write_byte: ICS write " 1751*9e39c5baSBill Taylor "timeout: addr: %x, data: %x\n", 1752*9e39c5baSBill Taylor addr, data); 1753*9e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR, 1754*9e39c5baSBill Taylor HCA_ERR_IOCTL); 1755*9e39c5baSBill Taylor return (EIO); 1756*9e39c5baSBill Taylor } 1757*9e39c5baSBill Taylor i++; 1758*9e39c5baSBill Taylor } while ((stat & HERMON_HW_FLASH_ICS_READY) == 0); 1759*9e39c5baSBill Taylor 1760*9e39c5baSBill Taylor if (stat & HERMON_HW_FLASH_ICS_ERROR) { 1761*9e39c5baSBill Taylor cmn_err(CE_WARN, 1762*9e39c5baSBill Taylor "hermon_flash_write_byte: ICS write cmd error: " 1763*9e39c5baSBill Taylor "addr: %x, data: %x\n", 1764*9e39c5baSBill Taylor addr, data); 1765*9e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL); 1766*9e39c5baSBill Taylor return (EIO); 1767*9e39c5baSBill Taylor } 1768*9e39c5baSBill Taylor break; 1769*9e39c5baSBill Taylor 1770*9e39c5baSBill Taylor case HERMON_FLASH_SPI_CMDSET: 1771*9e39c5baSBill Taylor /* 1772*9e39c5baSBill Taylor * Our lowest write granularity on SPI is a dword. 1773*9e39c5baSBill Taylor * To support this ioctl option, we can read in the 1774*9e39c5baSBill Taylor * dword that contains this byte, modify this byte, 1775*9e39c5baSBill Taylor * and write the dword back out. 1776*9e39c5baSBill Taylor */ 1777*9e39c5baSBill Taylor 1778*9e39c5baSBill Taylor /* Determine dword offset and byte offset within the dword */ 1779*9e39c5baSBill Taylor byte_offset = addr & 3; 1780*9e39c5baSBill Taylor dword_addr = addr - byte_offset; 1781*9e39c5baSBill Taylor #ifdef _LITTLE_ENDIAN 1782*9e39c5baSBill Taylor byte_offset = 3 - byte_offset; 1783*9e39c5baSBill Taylor #endif 1784*9e39c5baSBill Taylor 1785*9e39c5baSBill Taylor /* Read in dword */ 1786*9e39c5baSBill Taylor if ((status = hermon_flash_read_quadlet(state, &dword.dword, 1787*9e39c5baSBill Taylor dword_addr)) != 0) 1788*9e39c5baSBill Taylor break; 1789*9e39c5baSBill Taylor 1790*9e39c5baSBill Taylor /* Set "data" to the appopriate byte */ 1791*9e39c5baSBill Taylor dword.bytes[byte_offset] = data; 1792*9e39c5baSBill Taylor 1793*9e39c5baSBill Taylor /* Write modified dword back out */ 1794*9e39c5baSBill Taylor status = hermon_flash_spi_write_dword(state, dword_addr, 1795*9e39c5baSBill Taylor dword.dword); 1796*9e39c5baSBill Taylor 1797*9e39c5baSBill Taylor break; 1798*9e39c5baSBill Taylor 1799*9e39c5baSBill Taylor case HERMON_FLASH_UNKNOWN_CMDSET: 1800*9e39c5baSBill Taylor default: 1801*9e39c5baSBill Taylor cmn_err(CE_WARN, 1802*9e39c5baSBill Taylor "hermon_flash_write_byte: unknown cmd set: 0x%x\n", 1803*9e39c5baSBill Taylor state->hs_fw_cmdset); 1804*9e39c5baSBill Taylor status = EINVAL; 1805*9e39c5baSBill Taylor break; 1806*9e39c5baSBill Taylor } 1807*9e39c5baSBill Taylor 1808*9e39c5baSBill Taylor return (status); 1809*9e39c5baSBill Taylor } 1810*9e39c5baSBill Taylor 1811*9e39c5baSBill Taylor /* 1812*9e39c5baSBill Taylor * hermon_flash_erase_sector() 1813*9e39c5baSBill Taylor */ 1814*9e39c5baSBill Taylor static int 1815*9e39c5baSBill Taylor hermon_flash_erase_sector(hermon_state_t *state, uint32_t sector_num) 1816*9e39c5baSBill Taylor { 1817*9e39c5baSBill Taylor ddi_acc_handle_t hdl; 1818*9e39c5baSBill Taylor uint32_t addr; 1819*9e39c5baSBill Taylor uint32_t stat; 1820*9e39c5baSBill Taylor int status = 0; 1821*9e39c5baSBill Taylor int i; 1822*9e39c5baSBill Taylor 1823*9e39c5baSBill Taylor /* initialize the FMA retry loop */ 1824*9e39c5baSBill Taylor hermon_pio_init(fm_loop_cnt, fm_status, fm_test); 1825*9e39c5baSBill Taylor 1826*9e39c5baSBill Taylor /* Get address from sector num */ 1827*9e39c5baSBill Taylor addr = sector_num << state->hs_fw_log_sector_sz; 1828*9e39c5baSBill Taylor 1829*9e39c5baSBill Taylor switch (state->hs_fw_cmdset) { 1830*9e39c5baSBill Taylor case HERMON_FLASH_AMD_CMDSET: 1831*9e39c5baSBill Taylor /* Issue Flash Sector Erase Command */ 1832*9e39c5baSBill Taylor hermon_flash_write(state, addr, 0xAA, &status); 1833*9e39c5baSBill Taylor if (status != 0) { 1834*9e39c5baSBill Taylor return (status); 1835*9e39c5baSBill Taylor } 1836*9e39c5baSBill Taylor 1837*9e39c5baSBill Taylor hermon_flash_write(state, addr, 0x55, &status); 1838*9e39c5baSBill Taylor if (status != 0) { 1839*9e39c5baSBill Taylor return (status); 1840*9e39c5baSBill Taylor } 1841*9e39c5baSBill Taylor 1842*9e39c5baSBill Taylor hermon_flash_write(state, addr, 0x80, &status); 1843*9e39c5baSBill Taylor if (status != 0) { 1844*9e39c5baSBill Taylor return (status); 1845*9e39c5baSBill Taylor } 1846*9e39c5baSBill Taylor 1847*9e39c5baSBill Taylor hermon_flash_write(state, addr, 0xAA, &status); 1848*9e39c5baSBill Taylor if (status != 0) { 1849*9e39c5baSBill Taylor return (status); 1850*9e39c5baSBill Taylor } 1851*9e39c5baSBill Taylor 1852*9e39c5baSBill Taylor hermon_flash_write(state, addr, 0x55, &status); 1853*9e39c5baSBill Taylor if (status != 0) { 1854*9e39c5baSBill Taylor return (status); 1855*9e39c5baSBill Taylor } 1856*9e39c5baSBill Taylor 1857*9e39c5baSBill Taylor hermon_flash_write(state, addr, 0x30, &status); 1858*9e39c5baSBill Taylor if (status != 0) { 1859*9e39c5baSBill Taylor return (status); 1860*9e39c5baSBill Taylor } 1861*9e39c5baSBill Taylor 1862*9e39c5baSBill Taylor /* Wait for Sector Erase to complete */ 1863*9e39c5baSBill Taylor i = 0; 1864*9e39c5baSBill Taylor do { 1865*9e39c5baSBill Taylor drv_usecwait(1); 1866*9e39c5baSBill Taylor stat = hermon_flash_read(state, addr, &status); 1867*9e39c5baSBill Taylor if (status != 0) { 1868*9e39c5baSBill Taylor return (status); 1869*9e39c5baSBill Taylor } 1870*9e39c5baSBill Taylor 1871*9e39c5baSBill Taylor if (i == hermon_hw_flash_timeout_erase) { 1872*9e39c5baSBill Taylor cmn_err(CE_WARN, 1873*9e39c5baSBill Taylor "hermon_flash_erase_sector: " 1874*9e39c5baSBill Taylor "ACS erase timeout\n"); 1875*9e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR, 1876*9e39c5baSBill Taylor HCA_ERR_IOCTL); 1877*9e39c5baSBill Taylor return (EIO); 1878*9e39c5baSBill Taylor } 1879*9e39c5baSBill Taylor i++; 1880*9e39c5baSBill Taylor } while (stat != 0xFFFFFFFF); 1881*9e39c5baSBill Taylor break; 1882*9e39c5baSBill Taylor 1883*9e39c5baSBill Taylor case HERMON_FLASH_INTEL_CMDSET: 1884*9e39c5baSBill Taylor /* Issue Flash Sector Erase Command */ 1885*9e39c5baSBill Taylor hermon_flash_write(state, addr, HERMON_HW_FLASH_ICS_ERASE, 1886*9e39c5baSBill Taylor &status); 1887*9e39c5baSBill Taylor if (status != 0) { 1888*9e39c5baSBill Taylor return (status); 1889*9e39c5baSBill Taylor } 1890*9e39c5baSBill Taylor 1891*9e39c5baSBill Taylor hermon_flash_write(state, addr, HERMON_HW_FLASH_ICS_CONFIRM, 1892*9e39c5baSBill Taylor &status); 1893*9e39c5baSBill Taylor if (status != 0) { 1894*9e39c5baSBill Taylor return (status); 1895*9e39c5baSBill Taylor } 1896*9e39c5baSBill Taylor 1897*9e39c5baSBill Taylor /* Wait for Sector Erase to complete */ 1898*9e39c5baSBill Taylor i = 0; 1899*9e39c5baSBill Taylor do { 1900*9e39c5baSBill Taylor drv_usecwait(1); 1901*9e39c5baSBill Taylor stat = hermon_flash_read(state, addr & ~3, &status); 1902*9e39c5baSBill Taylor if (status != 0) { 1903*9e39c5baSBill Taylor return (status); 1904*9e39c5baSBill Taylor } 1905*9e39c5baSBill Taylor 1906*9e39c5baSBill Taylor if (i == hermon_hw_flash_timeout_erase) { 1907*9e39c5baSBill Taylor cmn_err(CE_WARN, 1908*9e39c5baSBill Taylor "hermon_flash_erase_sector: " 1909*9e39c5baSBill Taylor "ICS erase timeout\n"); 1910*9e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR, 1911*9e39c5baSBill Taylor HCA_ERR_IOCTL); 1912*9e39c5baSBill Taylor return (EIO); 1913*9e39c5baSBill Taylor } 1914*9e39c5baSBill Taylor i++; 1915*9e39c5baSBill Taylor } while ((stat & HERMON_HW_FLASH_ICS_READY) == 0); 1916*9e39c5baSBill Taylor 1917*9e39c5baSBill Taylor if (stat & HERMON_HW_FLASH_ICS_ERROR) { 1918*9e39c5baSBill Taylor cmn_err(CE_WARN, 1919*9e39c5baSBill Taylor "hermon_flash_erase_sector: " 1920*9e39c5baSBill Taylor "ICS erase cmd error\n"); 1921*9e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR, 1922*9e39c5baSBill Taylor HCA_ERR_IOCTL); 1923*9e39c5baSBill Taylor return (EIO); 1924*9e39c5baSBill Taylor } 1925*9e39c5baSBill Taylor break; 1926*9e39c5baSBill Taylor 1927*9e39c5baSBill Taylor case HERMON_FLASH_SPI_CMDSET: 1928*9e39c5baSBill Taylor hdl = hermon_get_pcihdl(state); 1929*9e39c5baSBill Taylor 1930*9e39c5baSBill Taylor /* the FMA retry loop starts. */ 1931*9e39c5baSBill Taylor hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status, 1932*9e39c5baSBill Taylor fm_test); 1933*9e39c5baSBill Taylor 1934*9e39c5baSBill Taylor /* Issue Write Enable */ 1935*9e39c5baSBill Taylor hermon_flash_spi_write_enable(state); 1936*9e39c5baSBill Taylor 1937*9e39c5baSBill Taylor /* Set the Address */ 1938*9e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_SPI_ADDR, 1939*9e39c5baSBill Taylor addr & HERMON_HW_FLASH_SPI_ADDR_MASK); 1940*9e39c5baSBill Taylor 1941*9e39c5baSBill Taylor /* Issue Flash Sector Erase */ 1942*9e39c5baSBill Taylor hermon_flash_spi_exec_command(state, hdl, 1943*9e39c5baSBill Taylor HERMON_HW_FLASH_SPI_INSTR_PHASE_OFF | 1944*9e39c5baSBill Taylor HERMON_HW_FLASH_SPI_ADDR_PHASE_OFF | 1945*9e39c5baSBill Taylor ((uint32_t)(HERMON_HW_FLASH_SPI_SECTOR_ERASE) << 1946*9e39c5baSBill Taylor HERMON_HW_FLASH_SPI_INSTR_SHIFT)); 1947*9e39c5baSBill Taylor 1948*9e39c5baSBill Taylor /* the FMA retry loop ends. */ 1949*9e39c5baSBill Taylor hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status, 1950*9e39c5baSBill Taylor fm_test); 1951*9e39c5baSBill Taylor 1952*9e39c5baSBill Taylor /* Wait for Sector Erase to complete */ 1953*9e39c5baSBill Taylor status = hermon_flash_spi_wait_wip(state); 1954*9e39c5baSBill Taylor break; 1955*9e39c5baSBill Taylor 1956*9e39c5baSBill Taylor case HERMON_FLASH_UNKNOWN_CMDSET: 1957*9e39c5baSBill Taylor default: 1958*9e39c5baSBill Taylor cmn_err(CE_WARN, 1959*9e39c5baSBill Taylor "hermon_flash_erase_sector: unknown cmd set: 0x%x\n", 1960*9e39c5baSBill Taylor state->hs_fw_cmdset); 1961*9e39c5baSBill Taylor status = EINVAL; 1962*9e39c5baSBill Taylor break; 1963*9e39c5baSBill Taylor } 1964*9e39c5baSBill Taylor 1965*9e39c5baSBill Taylor /* Reset the flash device */ 1966*9e39c5baSBill Taylor if (status == 0) { 1967*9e39c5baSBill Taylor status = hermon_flash_reset(state); 1968*9e39c5baSBill Taylor } 1969*9e39c5baSBill Taylor return (status); 1970*9e39c5baSBill Taylor 1971*9e39c5baSBill Taylor pio_error: 1972*9e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL); 1973*9e39c5baSBill Taylor return (EIO); 1974*9e39c5baSBill Taylor } 1975*9e39c5baSBill Taylor 1976*9e39c5baSBill Taylor /* 1977*9e39c5baSBill Taylor * hermon_flash_erase_chip() 1978*9e39c5baSBill Taylor */ 1979*9e39c5baSBill Taylor static int 1980*9e39c5baSBill Taylor hermon_flash_erase_chip(hermon_state_t *state) 1981*9e39c5baSBill Taylor { 1982*9e39c5baSBill Taylor uint32_t stat; 1983*9e39c5baSBill Taylor uint_t size; 1984*9e39c5baSBill Taylor int status = 0; 1985*9e39c5baSBill Taylor int i; 1986*9e39c5baSBill Taylor int num_sect; 1987*9e39c5baSBill Taylor 1988*9e39c5baSBill Taylor switch (state->hs_fw_cmdset) { 1989*9e39c5baSBill Taylor case HERMON_FLASH_AMD_CMDSET: 1990*9e39c5baSBill Taylor /* Issue Flash Chip Erase Command */ 1991*9e39c5baSBill Taylor hermon_flash_write(state, 0, 0xAA, &status); 1992*9e39c5baSBill Taylor if (status != 0) { 1993*9e39c5baSBill Taylor return (status); 1994*9e39c5baSBill Taylor } 1995*9e39c5baSBill Taylor 1996*9e39c5baSBill Taylor hermon_flash_write(state, 0, 0x55, &status); 1997*9e39c5baSBill Taylor if (status != 0) { 1998*9e39c5baSBill Taylor return (status); 1999*9e39c5baSBill Taylor } 2000*9e39c5baSBill Taylor 2001*9e39c5baSBill Taylor hermon_flash_write(state, 0, 0x80, &status); 2002*9e39c5baSBill Taylor if (status != 0) { 2003*9e39c5baSBill Taylor return (status); 2004*9e39c5baSBill Taylor } 2005*9e39c5baSBill Taylor 2006*9e39c5baSBill Taylor hermon_flash_write(state, 0, 0xAA, &status); 2007*9e39c5baSBill Taylor if (status != 0) { 2008*9e39c5baSBill Taylor return (status); 2009*9e39c5baSBill Taylor } 2010*9e39c5baSBill Taylor 2011*9e39c5baSBill Taylor hermon_flash_write(state, 0, 0x55, &status); 2012*9e39c5baSBill Taylor if (status != 0) { 2013*9e39c5baSBill Taylor return (status); 2014*9e39c5baSBill Taylor } 2015*9e39c5baSBill Taylor 2016*9e39c5baSBill Taylor hermon_flash_write(state, 0, 0x10, &status); 2017*9e39c5baSBill Taylor if (status != 0) { 2018*9e39c5baSBill Taylor return (status); 2019*9e39c5baSBill Taylor } 2020*9e39c5baSBill Taylor 2021*9e39c5baSBill Taylor /* Wait for Chip Erase to Complete */ 2022*9e39c5baSBill Taylor i = 0; 2023*9e39c5baSBill Taylor do { 2024*9e39c5baSBill Taylor drv_usecwait(1); 2025*9e39c5baSBill Taylor stat = hermon_flash_read(state, 0, &status); 2026*9e39c5baSBill Taylor if (status != 0) { 2027*9e39c5baSBill Taylor return (status); 2028*9e39c5baSBill Taylor } 2029*9e39c5baSBill Taylor 2030*9e39c5baSBill Taylor if (i == hermon_hw_flash_timeout_erase) { 2031*9e39c5baSBill Taylor cmn_err(CE_WARN, 2032*9e39c5baSBill Taylor "hermon_flash_erase_chip: erase timeout\n"); 2033*9e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR, 2034*9e39c5baSBill Taylor HCA_ERR_IOCTL); 2035*9e39c5baSBill Taylor return (EIO); 2036*9e39c5baSBill Taylor } 2037*9e39c5baSBill Taylor i++; 2038*9e39c5baSBill Taylor } while (stat != 0xFFFFFFFF); 2039*9e39c5baSBill Taylor break; 2040*9e39c5baSBill Taylor 2041*9e39c5baSBill Taylor case HERMON_FLASH_INTEL_CMDSET: 2042*9e39c5baSBill Taylor case HERMON_FLASH_SPI_CMDSET: 2043*9e39c5baSBill Taylor /* 2044*9e39c5baSBill Taylor * These chips don't have a chip erase command, so erase 2045*9e39c5baSBill Taylor * all blocks one at a time. 2046*9e39c5baSBill Taylor */ 2047*9e39c5baSBill Taylor size = (0x1 << state->hs_fw_log_sector_sz); 2048*9e39c5baSBill Taylor num_sect = state->hs_fw_device_sz / size; 2049*9e39c5baSBill Taylor 2050*9e39c5baSBill Taylor for (i = 0; i < num_sect; i++) { 2051*9e39c5baSBill Taylor status = hermon_flash_erase_sector(state, i); 2052*9e39c5baSBill Taylor if (status != 0) { 2053*9e39c5baSBill Taylor cmn_err(CE_WARN, 2054*9e39c5baSBill Taylor "hermon_flash_erase_chip: " 2055*9e39c5baSBill Taylor "sector %d erase error\n", i); 2056*9e39c5baSBill Taylor return (status); 2057*9e39c5baSBill Taylor } 2058*9e39c5baSBill Taylor } 2059*9e39c5baSBill Taylor break; 2060*9e39c5baSBill Taylor 2061*9e39c5baSBill Taylor case HERMON_FLASH_UNKNOWN_CMDSET: 2062*9e39c5baSBill Taylor default: 2063*9e39c5baSBill Taylor cmn_err(CE_WARN, "hermon_flash_erase_chip: " 2064*9e39c5baSBill Taylor "unknown cmd set: 0x%x\n", state->hs_fw_cmdset); 2065*9e39c5baSBill Taylor status = EINVAL; 2066*9e39c5baSBill Taylor break; 2067*9e39c5baSBill Taylor } 2068*9e39c5baSBill Taylor 2069*9e39c5baSBill Taylor return (status); 2070*9e39c5baSBill Taylor } 2071*9e39c5baSBill Taylor 2072*9e39c5baSBill Taylor /* 2073*9e39c5baSBill Taylor * hermon_flash_spi_write_enable() 2074*9e39c5baSBill Taylor */ 2075*9e39c5baSBill Taylor static void 2076*9e39c5baSBill Taylor hermon_flash_spi_write_enable(hermon_state_t *state) 2077*9e39c5baSBill Taylor { 2078*9e39c5baSBill Taylor ddi_acc_handle_t hdl; 2079*9e39c5baSBill Taylor 2080*9e39c5baSBill Taylor hdl = hermon_get_pcihdl(state); 2081*9e39c5baSBill Taylor 2082*9e39c5baSBill Taylor hermon_flash_spi_exec_command(state, hdl, 2083*9e39c5baSBill Taylor HERMON_HW_FLASH_SPI_INSTR_PHASE_OFF | 2084*9e39c5baSBill Taylor (HERMON_HW_FLASH_SPI_WRITE_ENABLE << 2085*9e39c5baSBill Taylor HERMON_HW_FLASH_SPI_INSTR_SHIFT)); 2086*9e39c5baSBill Taylor } 2087*9e39c5baSBill Taylor 2088*9e39c5baSBill Taylor /* 2089*9e39c5baSBill Taylor * hermon_flash_spi_wait_wip() 2090*9e39c5baSBill Taylor */ 2091*9e39c5baSBill Taylor static int 2092*9e39c5baSBill Taylor hermon_flash_spi_wait_wip(hermon_state_t *state) 2093*9e39c5baSBill Taylor { 2094*9e39c5baSBill Taylor ddi_acc_handle_t hdl; 2095*9e39c5baSBill Taylor uint32_t status; 2096*9e39c5baSBill Taylor 2097*9e39c5baSBill Taylor /* initialize the FMA retry loop */ 2098*9e39c5baSBill Taylor hermon_pio_init(fm_loop_cnt, fm_status, fm_test); 2099*9e39c5baSBill Taylor 2100*9e39c5baSBill Taylor hdl = hermon_get_pcihdl(state); 2101*9e39c5baSBill Taylor 2102*9e39c5baSBill Taylor /* the FMA retry loop starts. */ 2103*9e39c5baSBill Taylor hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status, 2104*9e39c5baSBill Taylor fm_test); 2105*9e39c5baSBill Taylor 2106*9e39c5baSBill Taylor /* wait on the gateway to clear busy */ 2107*9e39c5baSBill Taylor do { 2108*9e39c5baSBill Taylor status = hermon_flash_read_cfg(state, hdl, 2109*9e39c5baSBill Taylor HERMON_HW_FLASH_SPI_GW); 2110*9e39c5baSBill Taylor } while (status & HERMON_HW_FLASH_SPI_BUSY); 2111*9e39c5baSBill Taylor 2112*9e39c5baSBill Taylor /* now, get the status and check for WIP to clear */ 2113*9e39c5baSBill Taylor do { 2114*9e39c5baSBill Taylor hermon_flash_spi_exec_command(state, hdl, 2115*9e39c5baSBill Taylor HERMON_HW_FLASH_SPI_READ_OP | 2116*9e39c5baSBill Taylor HERMON_HW_FLASH_SPI_INSTR_PHASE_OFF | 2117*9e39c5baSBill Taylor HERMON_HW_FLASH_SPI_DATA_PHASE_OFF | 2118*9e39c5baSBill Taylor HERMON_HW_FLASH_SPI_TRANS_SZ_4B | 2119*9e39c5baSBill Taylor (HERMON_HW_FLASH_SPI_READ_STATUS_REG << 2120*9e39c5baSBill Taylor HERMON_HW_FLASH_SPI_INSTR_SHIFT)); 2121*9e39c5baSBill Taylor 2122*9e39c5baSBill Taylor status = hermon_flash_read_cfg(state, hdl, 2123*9e39c5baSBill Taylor HERMON_HW_FLASH_SPI_DATA); 2124*9e39c5baSBill Taylor } while (status & HERMON_HW_FLASH_SPI_WIP); 2125*9e39c5baSBill Taylor 2126*9e39c5baSBill Taylor /* the FMA retry loop ends. */ 2127*9e39c5baSBill Taylor hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status, fm_test); 2128*9e39c5baSBill Taylor return (0); 2129*9e39c5baSBill Taylor 2130*9e39c5baSBill Taylor pio_error: 2131*9e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL); 2132*9e39c5baSBill Taylor return (EIO); 2133*9e39c5baSBill Taylor } 2134*9e39c5baSBill Taylor 2135*9e39c5baSBill Taylor /* 2136*9e39c5baSBill Taylor * hermon_flash_bank() 2137*9e39c5baSBill Taylor */ 2138*9e39c5baSBill Taylor static int 2139*9e39c5baSBill Taylor hermon_flash_bank(hermon_state_t *state, uint32_t addr) 2140*9e39c5baSBill Taylor { 2141*9e39c5baSBill Taylor ddi_acc_handle_t hdl; 2142*9e39c5baSBill Taylor uint32_t bank; 2143*9e39c5baSBill Taylor 2144*9e39c5baSBill Taylor /* initialize the FMA retry loop */ 2145*9e39c5baSBill Taylor hermon_pio_init(fm_loop_cnt, fm_status, fm_test); 2146*9e39c5baSBill Taylor 2147*9e39c5baSBill Taylor /* Set handle */ 2148*9e39c5baSBill Taylor hdl = hermon_get_pcihdl(state); 2149*9e39c5baSBill Taylor 2150*9e39c5baSBill Taylor /* Determine the bank setting from the address */ 2151*9e39c5baSBill Taylor bank = addr & HERMON_HW_FLASH_BANK_MASK; 2152*9e39c5baSBill Taylor 2153*9e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(state->hs_fw_flashbank)) 2154*9e39c5baSBill Taylor 2155*9e39c5baSBill Taylor /* 2156*9e39c5baSBill Taylor * If the bank is different from the currently set bank, we need to 2157*9e39c5baSBill Taylor * change it. Also, if an 'addr' of 0 is given, this allows the 2158*9e39c5baSBill Taylor * capability to force the flash bank to 0. This is useful at init 2159*9e39c5baSBill Taylor * time to initially set the bank value 2160*9e39c5baSBill Taylor */ 2161*9e39c5baSBill Taylor if (state->hs_fw_flashbank != bank || addr == 0) { 2162*9e39c5baSBill Taylor switch (state->hs_fw_cmdset) { 2163*9e39c5baSBill Taylor case HERMON_FLASH_SPI_CMDSET: 2164*9e39c5baSBill Taylor /* CMJ: not needed for hermon */ 2165*9e39c5baSBill Taylor break; 2166*9e39c5baSBill Taylor 2167*9e39c5baSBill Taylor case HERMON_FLASH_INTEL_CMDSET: 2168*9e39c5baSBill Taylor case HERMON_FLASH_AMD_CMDSET: 2169*9e39c5baSBill Taylor /* the FMA retry loop starts. */ 2170*9e39c5baSBill Taylor hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, 2171*9e39c5baSBill Taylor fm_status, fm_test); 2172*9e39c5baSBill Taylor 2173*9e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl, 2174*9e39c5baSBill Taylor HERMON_HW_FLASH_GPIO_DATACLEAR, 0x70); 2175*9e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl, 2176*9e39c5baSBill Taylor HERMON_HW_FLASH_GPIO_DATASET, (bank >> 15) & 0x70); 2177*9e39c5baSBill Taylor 2178*9e39c5baSBill Taylor /* the FMA retry loop ends. */ 2179*9e39c5baSBill Taylor hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, 2180*9e39c5baSBill Taylor fm_status, fm_test); 2181*9e39c5baSBill Taylor break; 2182*9e39c5baSBill Taylor 2183*9e39c5baSBill Taylor case HERMON_FLASH_UNKNOWN_CMDSET: 2184*9e39c5baSBill Taylor default: 2185*9e39c5baSBill Taylor return (EINVAL); 2186*9e39c5baSBill Taylor } 2187*9e39c5baSBill Taylor 2188*9e39c5baSBill Taylor state->hs_fw_flashbank = bank; 2189*9e39c5baSBill Taylor } 2190*9e39c5baSBill Taylor return (0); 2191*9e39c5baSBill Taylor 2192*9e39c5baSBill Taylor pio_error: 2193*9e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL); 2194*9e39c5baSBill Taylor return (EIO); 2195*9e39c5baSBill Taylor } 2196*9e39c5baSBill Taylor 2197*9e39c5baSBill Taylor /* 2198*9e39c5baSBill Taylor * hermon_flash_spi_exec_command() 2199*9e39c5baSBill Taylor */ 2200*9e39c5baSBill Taylor static void 2201*9e39c5baSBill Taylor hermon_flash_spi_exec_command(hermon_state_t *state, ddi_acc_handle_t hdl, 2202*9e39c5baSBill Taylor uint32_t cmd) 2203*9e39c5baSBill Taylor { 2204*9e39c5baSBill Taylor uint32_t data; 2205*9e39c5baSBill Taylor int timeout = 0; 2206*9e39c5baSBill Taylor 2207*9e39c5baSBill Taylor cmd |= HERMON_HW_FLASH_SPI_BUSY | HERMON_HW_FLASH_SPI_ENABLE_OFF; 2208*9e39c5baSBill Taylor 2209*9e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_SPI_GW, cmd); 2210*9e39c5baSBill Taylor 2211*9e39c5baSBill Taylor do { 2212*9e39c5baSBill Taylor data = hermon_flash_read_cfg(state, hdl, 2213*9e39c5baSBill Taylor HERMON_HW_FLASH_SPI_GW); 2214*9e39c5baSBill Taylor timeout++; 2215*9e39c5baSBill Taylor } while ((data & HERMON_HW_FLASH_SPI_BUSY) && 2216*9e39c5baSBill Taylor (timeout < hermon_hw_flash_timeout_config)); 2217*9e39c5baSBill Taylor } 2218*9e39c5baSBill Taylor 2219*9e39c5baSBill Taylor /* 2220*9e39c5baSBill Taylor * hermon_flash_read() 2221*9e39c5baSBill Taylor */ 2222*9e39c5baSBill Taylor static uint32_t 2223*9e39c5baSBill Taylor hermon_flash_read(hermon_state_t *state, uint32_t addr, int *err) 2224*9e39c5baSBill Taylor { 2225*9e39c5baSBill Taylor ddi_acc_handle_t hdl; 2226*9e39c5baSBill Taylor uint32_t data = 0; 2227*9e39c5baSBill Taylor int timeout, status = 0; 2228*9e39c5baSBill Taylor 2229*9e39c5baSBill Taylor /* initialize the FMA retry loop */ 2230*9e39c5baSBill Taylor hermon_pio_init(fm_loop_cnt, fm_status, fm_test); 2231*9e39c5baSBill Taylor 2232*9e39c5baSBill Taylor hdl = hermon_get_pcihdl(state); 2233*9e39c5baSBill Taylor 2234*9e39c5baSBill Taylor /* the FMA retry loop starts. */ 2235*9e39c5baSBill Taylor hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status, 2236*9e39c5baSBill Taylor fm_test); 2237*9e39c5baSBill Taylor 2238*9e39c5baSBill Taylor switch (state->hs_fw_cmdset) { 2239*9e39c5baSBill Taylor case HERMON_FLASH_SPI_CMDSET: 2240*9e39c5baSBill Taylor /* Set the transaction address */ 2241*9e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_SPI_ADDR, 2242*9e39c5baSBill Taylor (addr & HERMON_HW_FLASH_SPI_ADDR_MASK)); 2243*9e39c5baSBill Taylor 2244*9e39c5baSBill Taylor hermon_flash_spi_exec_command(state, hdl, 2245*9e39c5baSBill Taylor HERMON_HW_FLASH_SPI_READ_OP | 2246*9e39c5baSBill Taylor HERMON_HW_FLASH_SPI_INSTR_PHASE_OFF | 2247*9e39c5baSBill Taylor HERMON_HW_FLASH_SPI_ADDR_PHASE_OFF | 2248*9e39c5baSBill Taylor HERMON_HW_FLASH_SPI_DATA_PHASE_OFF | 2249*9e39c5baSBill Taylor HERMON_HW_FLASH_SPI_TRANS_SZ_4B | 2250*9e39c5baSBill Taylor (HERMON_HW_FLASH_SPI_READ << 2251*9e39c5baSBill Taylor HERMON_HW_FLASH_SPI_INSTR_SHIFT)); 2252*9e39c5baSBill Taylor 2253*9e39c5baSBill Taylor data = hermon_flash_read_cfg(state, hdl, 2254*9e39c5baSBill Taylor HERMON_HW_FLASH_SPI_DATA); 2255*9e39c5baSBill Taylor break; 2256*9e39c5baSBill Taylor 2257*9e39c5baSBill Taylor case HERMON_FLASH_INTEL_CMDSET: 2258*9e39c5baSBill Taylor case HERMON_FLASH_AMD_CMDSET: 2259*9e39c5baSBill Taylor /* 2260*9e39c5baSBill Taylor * The Read operation does the following: 2261*9e39c5baSBill Taylor * 1) Write the masked address to the HERMON_FLASH_ADDR 2262*9e39c5baSBill Taylor * register. Only the least significant 19 bits are valid. 2263*9e39c5baSBill Taylor * 2) Read back the register until the command has completed. 2264*9e39c5baSBill Taylor * 3) Read the data retrieved from the address at the 2265*9e39c5baSBill Taylor * HERMON_FLASH_DATA register. 2266*9e39c5baSBill Taylor */ 2267*9e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_ADDR, 2268*9e39c5baSBill Taylor (addr & HERMON_HW_FLASH_ADDR_MASK) | (1 << 29)); 2269*9e39c5baSBill Taylor 2270*9e39c5baSBill Taylor timeout = 0; 2271*9e39c5baSBill Taylor do { 2272*9e39c5baSBill Taylor data = hermon_flash_read_cfg(state, hdl, 2273*9e39c5baSBill Taylor HERMON_HW_FLASH_ADDR); 2274*9e39c5baSBill Taylor timeout++; 2275*9e39c5baSBill Taylor } while ((data & HERMON_HW_FLASH_CMD_MASK) && 2276*9e39c5baSBill Taylor (timeout < hermon_hw_flash_timeout_config)); 2277*9e39c5baSBill Taylor 2278*9e39c5baSBill Taylor data = hermon_flash_read_cfg(state, hdl, HERMON_HW_FLASH_DATA); 2279*9e39c5baSBill Taylor break; 2280*9e39c5baSBill Taylor 2281*9e39c5baSBill Taylor case HERMON_FLASH_UNKNOWN_CMDSET: 2282*9e39c5baSBill Taylor default: 2283*9e39c5baSBill Taylor cmn_err(CE_CONT, "hermon_flash_read: unknown cmdset: 0x%x\n", 2284*9e39c5baSBill Taylor state->hs_fw_cmdset); 2285*9e39c5baSBill Taylor status = EINVAL; 2286*9e39c5baSBill Taylor break; 2287*9e39c5baSBill Taylor } 2288*9e39c5baSBill Taylor 2289*9e39c5baSBill Taylor if (timeout == hermon_hw_flash_timeout_config) { 2290*9e39c5baSBill Taylor cmn_err(CE_WARN, "hermon_flash_read: command timed out.\n"); 2291*9e39c5baSBill Taylor *err = EIO; 2292*9e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL); 2293*9e39c5baSBill Taylor return (data); 2294*9e39c5baSBill Taylor } 2295*9e39c5baSBill Taylor 2296*9e39c5baSBill Taylor /* the FMA retry loop ends. */ 2297*9e39c5baSBill Taylor hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status, fm_test); 2298*9e39c5baSBill Taylor *err = status; 2299*9e39c5baSBill Taylor return (data); 2300*9e39c5baSBill Taylor 2301*9e39c5baSBill Taylor pio_error: 2302*9e39c5baSBill Taylor *err = EIO; 2303*9e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL); 2304*9e39c5baSBill Taylor return (data); 2305*9e39c5baSBill Taylor } 2306*9e39c5baSBill Taylor 2307*9e39c5baSBill Taylor /* 2308*9e39c5baSBill Taylor * hermon_flash_write() 2309*9e39c5baSBill Taylor */ 2310*9e39c5baSBill Taylor static void 2311*9e39c5baSBill Taylor hermon_flash_write(hermon_state_t *state, uint32_t addr, uchar_t data, int *err) 2312*9e39c5baSBill Taylor { 2313*9e39c5baSBill Taylor ddi_acc_handle_t hdl; 2314*9e39c5baSBill Taylor int cmd; 2315*9e39c5baSBill Taylor int timeout; 2316*9e39c5baSBill Taylor 2317*9e39c5baSBill Taylor /* initialize the FMA retry loop */ 2318*9e39c5baSBill Taylor hermon_pio_init(fm_loop_cnt, fm_status, fm_test); 2319*9e39c5baSBill Taylor 2320*9e39c5baSBill Taylor hdl = hermon_get_pcihdl(state); 2321*9e39c5baSBill Taylor 2322*9e39c5baSBill Taylor /* the FMA retry loop starts. */ 2323*9e39c5baSBill Taylor hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status, 2324*9e39c5baSBill Taylor fm_test); 2325*9e39c5baSBill Taylor 2326*9e39c5baSBill Taylor /* 2327*9e39c5baSBill Taylor * The Write operation does the following: 2328*9e39c5baSBill Taylor * 1) Write the data to be written to the HERMON_FLASH_DATA offset. 2329*9e39c5baSBill Taylor * 2) Write the address to write the data to to the HERMON_FLASH_ADDR 2330*9e39c5baSBill Taylor * offset. 2331*9e39c5baSBill Taylor * 3) Wait until the write completes. 2332*9e39c5baSBill Taylor */ 2333*9e39c5baSBill Taylor 2334*9e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_DATA, data << 24); 2335*9e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_ADDR, 2336*9e39c5baSBill Taylor (addr & 0x7FFFF) | (2 << 29)); 2337*9e39c5baSBill Taylor 2338*9e39c5baSBill Taylor timeout = 0; 2339*9e39c5baSBill Taylor do { 2340*9e39c5baSBill Taylor cmd = hermon_flash_read_cfg(state, hdl, HERMON_HW_FLASH_ADDR); 2341*9e39c5baSBill Taylor timeout++; 2342*9e39c5baSBill Taylor } while ((cmd & HERMON_HW_FLASH_CMD_MASK) && 2343*9e39c5baSBill Taylor (timeout < hermon_hw_flash_timeout_config)); 2344*9e39c5baSBill Taylor 2345*9e39c5baSBill Taylor if (timeout == hermon_hw_flash_timeout_config) { 2346*9e39c5baSBill Taylor cmn_err(CE_WARN, "hermon_flash_write: config cmd timeout.\n"); 2347*9e39c5baSBill Taylor *err = EIO; 2348*9e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL); 2349*9e39c5baSBill Taylor return; 2350*9e39c5baSBill Taylor } 2351*9e39c5baSBill Taylor 2352*9e39c5baSBill Taylor /* the FMA retry loop ends. */ 2353*9e39c5baSBill Taylor hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status, fm_test); 2354*9e39c5baSBill Taylor *err = 0; 2355*9e39c5baSBill Taylor return; 2356*9e39c5baSBill Taylor 2357*9e39c5baSBill Taylor pio_error: 2358*9e39c5baSBill Taylor *err = EIO; 2359*9e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL); 2360*9e39c5baSBill Taylor } 2361*9e39c5baSBill Taylor 2362*9e39c5baSBill Taylor /* 2363*9e39c5baSBill Taylor * hermon_flash_init() 2364*9e39c5baSBill Taylor */ 2365*9e39c5baSBill Taylor static int 2366*9e39c5baSBill Taylor hermon_flash_init(hermon_state_t *state) 2367*9e39c5baSBill Taylor { 2368*9e39c5baSBill Taylor uint32_t word; 2369*9e39c5baSBill Taylor ddi_acc_handle_t hdl; 2370*9e39c5baSBill Taylor int sema_cnt; 2371*9e39c5baSBill Taylor int gpio; 2372*9e39c5baSBill Taylor 2373*9e39c5baSBill Taylor /* initialize the FMA retry loop */ 2374*9e39c5baSBill Taylor hermon_pio_init(fm_loop_cnt, fm_status, fm_test); 2375*9e39c5baSBill Taylor 2376*9e39c5baSBill Taylor /* Set handle */ 2377*9e39c5baSBill Taylor hdl = hermon_get_pcihdl(state); 2378*9e39c5baSBill Taylor 2379*9e39c5baSBill Taylor /* the FMA retry loop starts. */ 2380*9e39c5baSBill Taylor hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status, 2381*9e39c5baSBill Taylor fm_test); 2382*9e39c5baSBill Taylor 2383*9e39c5baSBill Taylor /* Init the flash */ 2384*9e39c5baSBill Taylor 2385*9e39c5baSBill Taylor #ifdef DO_WRCONF 2386*9e39c5baSBill Taylor /* 2387*9e39c5baSBill Taylor * Grab the WRCONF semaphore. 2388*9e39c5baSBill Taylor */ 2389*9e39c5baSBill Taylor word = hermon_flash_read_cfg(state, hdl, HERMON_HW_FLASH_WRCONF_SEMA); 2390*9e39c5baSBill Taylor #endif 2391*9e39c5baSBill Taylor 2392*9e39c5baSBill Taylor /* 2393*9e39c5baSBill Taylor * Grab the GPIO semaphore. This allows us exclusive access to the 2394*9e39c5baSBill Taylor * GPIO settings on the Hermon for the duration of the flash burning 2395*9e39c5baSBill Taylor * procedure. 2396*9e39c5baSBill Taylor */ 2397*9e39c5baSBill Taylor sema_cnt = 0; 2398*9e39c5baSBill Taylor do { 2399*9e39c5baSBill Taylor word = hermon_flash_read_cfg(state, hdl, 2400*9e39c5baSBill Taylor HERMON_HW_FLASH_GPIO_SEMA); 2401*9e39c5baSBill Taylor if (word == 0) { 2402*9e39c5baSBill Taylor break; 2403*9e39c5baSBill Taylor } 2404*9e39c5baSBill Taylor 2405*9e39c5baSBill Taylor sema_cnt++; 2406*9e39c5baSBill Taylor drv_usecwait(1); 2407*9e39c5baSBill Taylor 2408*9e39c5baSBill Taylor } while (sema_cnt < hermon_hw_flash_timeout_gpio_sema); 2409*9e39c5baSBill Taylor 2410*9e39c5baSBill Taylor /* 2411*9e39c5baSBill Taylor * Determine if we timed out trying to grab the GPIO semaphore 2412*9e39c5baSBill Taylor */ 2413*9e39c5baSBill Taylor if (sema_cnt == hermon_hw_flash_timeout_gpio_sema) { 2414*9e39c5baSBill Taylor cmn_err(CE_WARN, "hermon_flash_init: GPIO SEMA timeout\n"); 2415*9e39c5baSBill Taylor cmn_err(CE_WARN, "GPIO_SEMA value: 0x%x\n", word); 2416*9e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL); 2417*9e39c5baSBill Taylor return (EIO); 2418*9e39c5baSBill Taylor } 2419*9e39c5baSBill Taylor 2420*9e39c5baSBill Taylor /* Save away original GPIO Values */ 2421*9e39c5baSBill Taylor state->hs_fw_gpio[0] = hermon_flash_read_cfg(state, hdl, 2422*9e39c5baSBill Taylor HERMON_HW_FLASH_GPIO_DATA); 2423*9e39c5baSBill Taylor 2424*9e39c5baSBill Taylor /* Set new GPIO value */ 2425*9e39c5baSBill Taylor gpio = state->hs_fw_gpio[0] | HERMON_HW_FLASH_GPIO_PIN_ENABLE; 2426*9e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_DATA, gpio); 2427*9e39c5baSBill Taylor 2428*9e39c5baSBill Taylor /* Save away original GPIO Values */ 2429*9e39c5baSBill Taylor state->hs_fw_gpio[1] = hermon_flash_read_cfg(state, hdl, 2430*9e39c5baSBill Taylor HERMON_HW_FLASH_GPIO_MOD0); 2431*9e39c5baSBill Taylor state->hs_fw_gpio[2] = hermon_flash_read_cfg(state, hdl, 2432*9e39c5baSBill Taylor HERMON_HW_FLASH_GPIO_MOD1); 2433*9e39c5baSBill Taylor 2434*9e39c5baSBill Taylor /* unlock GPIO */ 2435*9e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_LOCK, 2436*9e39c5baSBill Taylor HERMON_HW_FLASH_GPIO_UNLOCK_VAL); 2437*9e39c5baSBill Taylor 2438*9e39c5baSBill Taylor /* 2439*9e39c5baSBill Taylor * Set new GPIO values 2440*9e39c5baSBill Taylor */ 2441*9e39c5baSBill Taylor gpio = state->hs_fw_gpio[1] | HERMON_HW_FLASH_GPIO_PIN_ENABLE; 2442*9e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_MOD0, gpio); 2443*9e39c5baSBill Taylor 2444*9e39c5baSBill Taylor gpio = state->hs_fw_gpio[2] & ~HERMON_HW_FLASH_GPIO_PIN_ENABLE; 2445*9e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_MOD1, gpio); 2446*9e39c5baSBill Taylor 2447*9e39c5baSBill Taylor /* re-lock GPIO */ 2448*9e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_LOCK, 0); 2449*9e39c5baSBill Taylor 2450*9e39c5baSBill Taylor /* Set CPUMODE to enable hermon to access the flash device */ 2451*9e39c5baSBill Taylor /* CMJ This code came from arbel. Hermon doesn't seem to need it. */ 2452*9e39c5baSBill Taylor /* 2453*9e39c5baSBill Taylor * hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_CPUMODE, 2454*9e39c5baSBill Taylor * 1 << HERMON_HW_FLASH_CPU_SHIFT); 2455*9e39c5baSBill Taylor */ 2456*9e39c5baSBill Taylor 2457*9e39c5baSBill Taylor /* the FMA retry loop ends. */ 2458*9e39c5baSBill Taylor hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status, fm_test); 2459*9e39c5baSBill Taylor return (0); 2460*9e39c5baSBill Taylor 2461*9e39c5baSBill Taylor pio_error: 2462*9e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL); 2463*9e39c5baSBill Taylor return (EIO); 2464*9e39c5baSBill Taylor } 2465*9e39c5baSBill Taylor 2466*9e39c5baSBill Taylor /* 2467*9e39c5baSBill Taylor * hermon_flash_cfi_init 2468*9e39c5baSBill Taylor * Implements access to the CFI (Common Flash Interface) data 2469*9e39c5baSBill Taylor */ 2470*9e39c5baSBill Taylor static int 2471*9e39c5baSBill Taylor hermon_flash_cfi_init(hermon_state_t *state, uint32_t *cfi_info, 2472*9e39c5baSBill Taylor int *intel_xcmd) 2473*9e39c5baSBill Taylor { 2474*9e39c5baSBill Taylor uint32_t data; 2475*9e39c5baSBill Taylor uint32_t sector_sz_bytes; 2476*9e39c5baSBill Taylor uint32_t bit_count; 2477*9e39c5baSBill Taylor uint8_t cfi_ch_info[HERMON_CFI_INFO_SIZE]; 2478*9e39c5baSBill Taylor uint32_t cfi_dw_info[HERMON_CFI_INFO_QSIZE]; 2479*9e39c5baSBill Taylor int i; 2480*9e39c5baSBill Taylor int status; 2481*9e39c5baSBill Taylor 2482*9e39c5baSBill Taylor /* Right now, all hermon cards use SPI. */ 2483*9e39c5baSBill Taylor if (HERMON_IS_MAINTENANCE_MODE(state->hs_dip) || 2484*9e39c5baSBill Taylor HERMON_IS_HCA_MODE(state->hs_dip)) { 2485*9e39c5baSBill Taylor /* 2486*9e39c5baSBill Taylor * Don't use CFI for SPI part. Just fill in what we need 2487*9e39c5baSBill Taylor * and return. 2488*9e39c5baSBill Taylor */ 2489*9e39c5baSBill Taylor state->hs_fw_cmdset = HERMON_FLASH_SPI_CMDSET; 2490*9e39c5baSBill Taylor state->hs_fw_log_sector_sz = HERMON_FLASH_SPI_LOG_SECTOR_SIZE; 2491*9e39c5baSBill Taylor state->hs_fw_device_sz = HERMON_FLASH_SPI_DEVICE_SIZE; 2492*9e39c5baSBill Taylor 2493*9e39c5baSBill Taylor /* 2494*9e39c5baSBill Taylor * set this to inform caller of cmdset type. 2495*9e39c5baSBill Taylor */ 2496*9e39c5baSBill Taylor cfi_ch_info[0x13] = HERMON_FLASH_SPI_CMDSET; 2497*9e39c5baSBill Taylor hermon_flash_cfi_dword(&cfi_info[4], cfi_ch_info, 0x10); 2498*9e39c5baSBill Taylor return (0); 2499*9e39c5baSBill Taylor } 2500*9e39c5baSBill Taylor 2501*9e39c5baSBill Taylor /* 2502*9e39c5baSBill Taylor * Determine if the user command supports the Intel Extended 2503*9e39c5baSBill Taylor * Command Set. The query string is contained in the fourth 2504*9e39c5baSBill Taylor * quad word. 2505*9e39c5baSBill Taylor */ 2506*9e39c5baSBill Taylor hermon_flash_cfi_byte(cfi_ch_info, cfi_info[0x04], 0x10); 2507*9e39c5baSBill Taylor if (cfi_ch_info[0x10] == 'M' && 2508*9e39c5baSBill Taylor cfi_ch_info[0x11] == 'X' && 2509*9e39c5baSBill Taylor cfi_ch_info[0x12] == '2') { 2510*9e39c5baSBill Taylor *intel_xcmd = 1; /* support is there */ 2511*9e39c5baSBill Taylor if (hermon_verbose) { 2512*9e39c5baSBill Taylor IBTF_DPRINTF_L2("hermon", 2513*9e39c5baSBill Taylor "Support for Intel X is present\n"); 2514*9e39c5baSBill Taylor } 2515*9e39c5baSBill Taylor } 2516*9e39c5baSBill Taylor 2517*9e39c5baSBill Taylor /* CFI QUERY */ 2518*9e39c5baSBill Taylor hermon_flash_write(state, 0x55, HERMON_FLASH_CFI_INIT, &status); 2519*9e39c5baSBill Taylor if (status != 0) { 2520*9e39c5baSBill Taylor return (status); 2521*9e39c5baSBill Taylor } 2522*9e39c5baSBill Taylor 2523*9e39c5baSBill Taylor /* temporarily set the cmdset in order to do the initial read */ 2524*9e39c5baSBill Taylor state->hs_fw_cmdset = HERMON_FLASH_INTEL_CMDSET; 2525*9e39c5baSBill Taylor 2526*9e39c5baSBill Taylor /* Read in CFI data */ 2527*9e39c5baSBill Taylor for (i = 0; i < HERMON_CFI_INFO_SIZE; i += 4) { 2528*9e39c5baSBill Taylor data = hermon_flash_read(state, i, &status); 2529*9e39c5baSBill Taylor if (status != 0) { 2530*9e39c5baSBill Taylor return (status); 2531*9e39c5baSBill Taylor } 2532*9e39c5baSBill Taylor cfi_dw_info[i >> 2] = data; 2533*9e39c5baSBill Taylor hermon_flash_cfi_byte(cfi_ch_info, data, i); 2534*9e39c5baSBill Taylor } 2535*9e39c5baSBill Taylor 2536*9e39c5baSBill Taylor /* Determine chip set */ 2537*9e39c5baSBill Taylor state->hs_fw_cmdset = HERMON_FLASH_UNKNOWN_CMDSET; 2538*9e39c5baSBill Taylor if (cfi_ch_info[0x20] == 'Q' && 2539*9e39c5baSBill Taylor cfi_ch_info[0x22] == 'R' && 2540*9e39c5baSBill Taylor cfi_ch_info[0x24] == 'Y') { 2541*9e39c5baSBill Taylor /* 2542*9e39c5baSBill Taylor * Mode: x16 working in x8 mode (Intel). 2543*9e39c5baSBill Taylor * Pack data - skip spacing bytes. 2544*9e39c5baSBill Taylor */ 2545*9e39c5baSBill Taylor if (hermon_verbose) { 2546*9e39c5baSBill Taylor IBTF_DPRINTF_L2("hermon", 2547*9e39c5baSBill Taylor "x16 working in x8 mode (Intel)\n"); 2548*9e39c5baSBill Taylor } 2549*9e39c5baSBill Taylor for (i = 0; i < HERMON_CFI_INFO_SIZE; i += 2) { 2550*9e39c5baSBill Taylor cfi_ch_info[i/2] = cfi_ch_info[i]; 2551*9e39c5baSBill Taylor } 2552*9e39c5baSBill Taylor } 2553*9e39c5baSBill Taylor state->hs_fw_cmdset = cfi_ch_info[0x13]; 2554*9e39c5baSBill Taylor 2555*9e39c5baSBill Taylor if (state->hs_fw_cmdset != HERMON_FLASH_INTEL_CMDSET && 2556*9e39c5baSBill Taylor state->hs_fw_cmdset != HERMON_FLASH_AMD_CMDSET) { 2557*9e39c5baSBill Taylor cmn_err(CE_WARN, 2558*9e39c5baSBill Taylor "hermon_flash_cfi_init: UNKNOWN chip cmd set 0x%04x\n", 2559*9e39c5baSBill Taylor state->hs_fw_cmdset); 2560*9e39c5baSBill Taylor state->hs_fw_cmdset = HERMON_FLASH_UNKNOWN_CMDSET; 2561*9e39c5baSBill Taylor return (0); 2562*9e39c5baSBill Taylor } 2563*9e39c5baSBill Taylor 2564*9e39c5baSBill Taylor /* Determine total bytes in one sector size */ 2565*9e39c5baSBill Taylor sector_sz_bytes = ((cfi_ch_info[0x30] << 8) | cfi_ch_info[0x2F]) << 8; 2566*9e39c5baSBill Taylor 2567*9e39c5baSBill Taylor /* Calculate equivalent of log2 (n) */ 2568*9e39c5baSBill Taylor for (bit_count = 0; sector_sz_bytes > 1; bit_count++) { 2569*9e39c5baSBill Taylor sector_sz_bytes >>= 1; 2570*9e39c5baSBill Taylor } 2571*9e39c5baSBill Taylor 2572*9e39c5baSBill Taylor /* Set sector size */ 2573*9e39c5baSBill Taylor state->hs_fw_log_sector_sz = bit_count; 2574*9e39c5baSBill Taylor 2575*9e39c5baSBill Taylor /* Set flash size */ 2576*9e39c5baSBill Taylor state->hs_fw_device_sz = 0x1 << cfi_ch_info[0x27]; 2577*9e39c5baSBill Taylor 2578*9e39c5baSBill Taylor /* Reset to turn off CFI mode */ 2579*9e39c5baSBill Taylor if ((status = hermon_flash_reset(state)) != 0) 2580*9e39c5baSBill Taylor goto out; 2581*9e39c5baSBill Taylor 2582*9e39c5baSBill Taylor /* Pass CFI data back to user command. */ 2583*9e39c5baSBill Taylor for (i = 0; i < HERMON_FLASH_CFI_SIZE_QUADLET; i++) { 2584*9e39c5baSBill Taylor hermon_flash_cfi_dword(&cfi_info[i], cfi_ch_info, i << 2); 2585*9e39c5baSBill Taylor } 2586*9e39c5baSBill Taylor 2587*9e39c5baSBill Taylor if (*intel_xcmd == 1) { 2588*9e39c5baSBill Taylor /* 2589*9e39c5baSBill Taylor * Inform the user cmd that this driver does support the 2590*9e39c5baSBill Taylor * Intel Extended Command Set. 2591*9e39c5baSBill Taylor */ 2592*9e39c5baSBill Taylor cfi_ch_info[0x10] = 'M'; 2593*9e39c5baSBill Taylor cfi_ch_info[0x11] = 'X'; 2594*9e39c5baSBill Taylor cfi_ch_info[0x12] = '2'; 2595*9e39c5baSBill Taylor } else { 2596*9e39c5baSBill Taylor cfi_ch_info[0x10] = 'Q'; 2597*9e39c5baSBill Taylor cfi_ch_info[0x11] = 'R'; 2598*9e39c5baSBill Taylor cfi_ch_info[0x12] = 'Y'; 2599*9e39c5baSBill Taylor } 2600*9e39c5baSBill Taylor cfi_ch_info[0x13] = state->hs_fw_cmdset; 2601*9e39c5baSBill Taylor hermon_flash_cfi_dword(&cfi_info[0x4], cfi_ch_info, 0x10); 2602*9e39c5baSBill Taylor out: 2603*9e39c5baSBill Taylor return (status); 2604*9e39c5baSBill Taylor } 2605*9e39c5baSBill Taylor 2606*9e39c5baSBill Taylor /* 2607*9e39c5baSBill Taylor * hermon_flash_fini() 2608*9e39c5baSBill Taylor */ 2609*9e39c5baSBill Taylor static int 2610*9e39c5baSBill Taylor hermon_flash_fini(hermon_state_t *state) 2611*9e39c5baSBill Taylor { 2612*9e39c5baSBill Taylor int status; 2613*9e39c5baSBill Taylor ddi_acc_handle_t hdl; 2614*9e39c5baSBill Taylor 2615*9e39c5baSBill Taylor /* initialize the FMA retry loop */ 2616*9e39c5baSBill Taylor hermon_pio_init(fm_loop_cnt, fm_status, fm_test); 2617*9e39c5baSBill Taylor 2618*9e39c5baSBill Taylor /* Set handle */ 2619*9e39c5baSBill Taylor hdl = hermon_get_pcihdl(state); 2620*9e39c5baSBill Taylor 2621*9e39c5baSBill Taylor if ((status = hermon_flash_bank(state, 0)) != 0) 2622*9e39c5baSBill Taylor return (status); 2623*9e39c5baSBill Taylor 2624*9e39c5baSBill Taylor /* the FMA retry loop starts. */ 2625*9e39c5baSBill Taylor hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status, 2626*9e39c5baSBill Taylor fm_test); 2627*9e39c5baSBill Taylor 2628*9e39c5baSBill Taylor /* 2629*9e39c5baSBill Taylor * Restore original GPIO Values 2630*9e39c5baSBill Taylor */ 2631*9e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_DATA, 2632*9e39c5baSBill Taylor state->hs_fw_gpio[0]); 2633*9e39c5baSBill Taylor 2634*9e39c5baSBill Taylor /* unlock GPIOs */ 2635*9e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_LOCK, 2636*9e39c5baSBill Taylor HERMON_HW_FLASH_GPIO_UNLOCK_VAL); 2637*9e39c5baSBill Taylor 2638*9e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_MOD0, 2639*9e39c5baSBill Taylor state->hs_fw_gpio[1]); 2640*9e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_MOD1, 2641*9e39c5baSBill Taylor state->hs_fw_gpio[2]); 2642*9e39c5baSBill Taylor 2643*9e39c5baSBill Taylor /* re-lock GPIOs */ 2644*9e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_LOCK, 0); 2645*9e39c5baSBill Taylor 2646*9e39c5baSBill Taylor /* Give up gpio semaphore */ 2647*9e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_SEMA, 0); 2648*9e39c5baSBill Taylor 2649*9e39c5baSBill Taylor /* the FMA retry loop ends. */ 2650*9e39c5baSBill Taylor hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status, fm_test); 2651*9e39c5baSBill Taylor return (0); 2652*9e39c5baSBill Taylor 2653*9e39c5baSBill Taylor pio_error: 2654*9e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL); 2655*9e39c5baSBill Taylor return (EIO); 2656*9e39c5baSBill Taylor } 2657*9e39c5baSBill Taylor 2658*9e39c5baSBill Taylor /* 2659*9e39c5baSBill Taylor * hermon_flash_read_cfg 2660*9e39c5baSBill Taylor */ 2661*9e39c5baSBill Taylor static uint32_t 2662*9e39c5baSBill Taylor hermon_flash_read_cfg(hermon_state_t *state, ddi_acc_handle_t pci_config_hdl, 2663*9e39c5baSBill Taylor uint32_t addr) 2664*9e39c5baSBill Taylor { 2665*9e39c5baSBill Taylor uint32_t read; 2666*9e39c5baSBill Taylor 2667*9e39c5baSBill Taylor if (do_bar0) { 2668*9e39c5baSBill Taylor read = ddi_get32(hermon_get_cmdhdl(state), (uint32_t *)(void *) 2669*9e39c5baSBill Taylor (state->hs_reg_cmd_baseaddr + addr)); 2670*9e39c5baSBill Taylor } else { 2671*9e39c5baSBill Taylor /* 2672*9e39c5baSBill Taylor * Perform flash read operation: 2673*9e39c5baSBill Taylor * 1) Place addr to read from on the HERMON_HW_FLASH_CFG_ADDR 2674*9e39c5baSBill Taylor * register 2675*9e39c5baSBill Taylor * 2) Read data at that addr from the HERMON_HW_FLASH_CFG_DATA 2676*9e39c5baSBill Taylor * register 2677*9e39c5baSBill Taylor */ 2678*9e39c5baSBill Taylor pci_config_put32(pci_config_hdl, HERMON_HW_FLASH_CFG_ADDR, 2679*9e39c5baSBill Taylor addr); 2680*9e39c5baSBill Taylor read = pci_config_get32(pci_config_hdl, 2681*9e39c5baSBill Taylor HERMON_HW_FLASH_CFG_DATA); 2682*9e39c5baSBill Taylor } 2683*9e39c5baSBill Taylor 2684*9e39c5baSBill Taylor return (read); 2685*9e39c5baSBill Taylor } 2686*9e39c5baSBill Taylor 2687*9e39c5baSBill Taylor #ifdef DO_WRCONF 2688*9e39c5baSBill Taylor static void 2689*9e39c5baSBill Taylor hermon_flash_write_cfg(hermon_state_t *state, 2690*9e39c5baSBill Taylor ddi_acc_handle_t pci_config_hdl, uint32_t addr, uint32_t data) 2691*9e39c5baSBill Taylor { 2692*9e39c5baSBill Taylor hermon_flash_write_cfg_helper(state, pci_config_hdl, addr, data); 2693*9e39c5baSBill Taylor hermon_flash_write_confirm(state, pci_config_hdl); 2694*9e39c5baSBill Taylor } 2695*9e39c5baSBill Taylor 2696*9e39c5baSBill Taylor static void 2697*9e39c5baSBill Taylor hermon_flash_write_confirm(hermon_state_t *state, 2698*9e39c5baSBill Taylor ddi_acc_handle_t pci_config_hdl) 2699*9e39c5baSBill Taylor { 2700*9e39c5baSBill Taylor uint32_t sem_value = 1; 2701*9e39c5baSBill Taylor 2702*9e39c5baSBill Taylor hermon_flash_write_cfg_helper(state, pci_config_hdl, 2703*9e39c5baSBill Taylor HERMON_HW_FLASH_WRCONF_SEMA, 0); 2704*9e39c5baSBill Taylor while (sem_value) { 2705*9e39c5baSBill Taylor sem_value = hermon_flash_read_cfg(state, pci_config_hdl, 2706*9e39c5baSBill Taylor HERMON_HW_FLASH_WRCONF_SEMA); 2707*9e39c5baSBill Taylor } 2708*9e39c5baSBill Taylor } 2709*9e39c5baSBill Taylor #endif 2710*9e39c5baSBill Taylor 2711*9e39c5baSBill Taylor /* 2712*9e39c5baSBill Taylor * hermon_flash_write_cfg 2713*9e39c5baSBill Taylor */ 2714*9e39c5baSBill Taylor static void 2715*9e39c5baSBill Taylor #ifdef DO_WRCONF 2716*9e39c5baSBill Taylor hermon_flash_write_cfg_helper(hermon_state_t *state, 2717*9e39c5baSBill Taylor ddi_acc_handle_t pci_config_hdl, uint32_t addr, uint32_t data) 2718*9e39c5baSBill Taylor #else 2719*9e39c5baSBill Taylor hermon_flash_write_cfg(hermon_state_t *state, 2720*9e39c5baSBill Taylor ddi_acc_handle_t pci_config_hdl, uint32_t addr, uint32_t data) 2721*9e39c5baSBill Taylor #endif 2722*9e39c5baSBill Taylor { 2723*9e39c5baSBill Taylor if (do_bar0) { 2724*9e39c5baSBill Taylor ddi_put32(hermon_get_cmdhdl(state), (uint32_t *)(void *) 2725*9e39c5baSBill Taylor (state->hs_reg_cmd_baseaddr + addr), data); 2726*9e39c5baSBill Taylor 2727*9e39c5baSBill Taylor } else { 2728*9e39c5baSBill Taylor 2729*9e39c5baSBill Taylor /* 2730*9e39c5baSBill Taylor * Perform flash write operation: 2731*9e39c5baSBill Taylor * 1) Place addr to write to on the HERMON_HW_FLASH_CFG_ADDR 2732*9e39c5baSBill Taylor * register 2733*9e39c5baSBill Taylor * 2) Place data to write on to the HERMON_HW_FLASH_CFG_DATA 2734*9e39c5baSBill Taylor * register 2735*9e39c5baSBill Taylor */ 2736*9e39c5baSBill Taylor pci_config_put32(pci_config_hdl, HERMON_HW_FLASH_CFG_ADDR, 2737*9e39c5baSBill Taylor addr); 2738*9e39c5baSBill Taylor pci_config_put32(pci_config_hdl, HERMON_HW_FLASH_CFG_DATA, 2739*9e39c5baSBill Taylor data); 2740*9e39c5baSBill Taylor } 2741*9e39c5baSBill Taylor } 2742*9e39c5baSBill Taylor 2743*9e39c5baSBill Taylor /* 2744*9e39c5baSBill Taylor * Support routines to convert Common Flash Interface (CFI) data 2745*9e39c5baSBill Taylor * from a 32 bit word to a char array, and from a char array to 2746*9e39c5baSBill Taylor * a 32 bit word. 2747*9e39c5baSBill Taylor */ 2748*9e39c5baSBill Taylor static void 2749*9e39c5baSBill Taylor hermon_flash_cfi_byte(uint8_t *ch, uint32_t dword, int i) 2750*9e39c5baSBill Taylor { 2751*9e39c5baSBill Taylor ch[i] = (uint8_t)((dword & 0xFF000000) >> 24); 2752*9e39c5baSBill Taylor ch[i+1] = (uint8_t)((dword & 0x00FF0000) >> 16); 2753*9e39c5baSBill Taylor ch[i+2] = (uint8_t)((dword & 0x0000FF00) >> 8); 2754*9e39c5baSBill Taylor ch[i+3] = (uint8_t)((dword & 0x000000FF)); 2755*9e39c5baSBill Taylor } 2756*9e39c5baSBill Taylor 2757*9e39c5baSBill Taylor static void 2758*9e39c5baSBill Taylor hermon_flash_cfi_dword(uint32_t *dword, uint8_t *ch, int i) 2759*9e39c5baSBill Taylor { 2760*9e39c5baSBill Taylor *dword = (uint32_t) 2761*9e39c5baSBill Taylor ((uint32_t)ch[i] << 24 | 2762*9e39c5baSBill Taylor (uint32_t)ch[i+1] << 16 | 2763*9e39c5baSBill Taylor (uint32_t)ch[i+2] << 8 | 2764*9e39c5baSBill Taylor (uint32_t)ch[i+3]); 2765*9e39c5baSBill Taylor } 2766*9e39c5baSBill Taylor 2767*9e39c5baSBill Taylor /* 2768*9e39c5baSBill Taylor * hermon_loopback_free_qps 2769*9e39c5baSBill Taylor */ 2770*9e39c5baSBill Taylor static void 2771*9e39c5baSBill Taylor hermon_loopback_free_qps(hermon_loopback_state_t *lstate) 2772*9e39c5baSBill Taylor { 2773*9e39c5baSBill Taylor int i; 2774*9e39c5baSBill Taylor 2775*9e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lstate)) 2776*9e39c5baSBill Taylor 2777*9e39c5baSBill Taylor if (lstate->hls_tx.hlc_qp_hdl != NULL) { 2778*9e39c5baSBill Taylor (void) hermon_qp_free(lstate->hls_state, 2779*9e39c5baSBill Taylor &lstate->hls_tx.hlc_qp_hdl, IBC_FREE_QP_AND_QPN, NULL, 2780*9e39c5baSBill Taylor HERMON_NOSLEEP); 2781*9e39c5baSBill Taylor } 2782*9e39c5baSBill Taylor if (lstate->hls_rx.hlc_qp_hdl != NULL) { 2783*9e39c5baSBill Taylor (void) hermon_qp_free(lstate->hls_state, 2784*9e39c5baSBill Taylor &lstate->hls_rx.hlc_qp_hdl, IBC_FREE_QP_AND_QPN, NULL, 2785*9e39c5baSBill Taylor HERMON_NOSLEEP); 2786*9e39c5baSBill Taylor } 2787*9e39c5baSBill Taylor lstate->hls_tx.hlc_qp_hdl = NULL; 2788*9e39c5baSBill Taylor lstate->hls_rx.hlc_qp_hdl = NULL; 2789*9e39c5baSBill Taylor for (i = 0; i < 2; i++) { 2790*9e39c5baSBill Taylor if (lstate->hls_tx.hlc_cqhdl[i] != NULL) { 2791*9e39c5baSBill Taylor (void) hermon_cq_free(lstate->hls_state, 2792*9e39c5baSBill Taylor &lstate->hls_tx.hlc_cqhdl[i], HERMON_NOSLEEP); 2793*9e39c5baSBill Taylor } 2794*9e39c5baSBill Taylor if (lstate->hls_rx.hlc_cqhdl[i] != NULL) { 2795*9e39c5baSBill Taylor (void) hermon_cq_free(lstate->hls_state, 2796*9e39c5baSBill Taylor &lstate->hls_rx.hlc_cqhdl[i], HERMON_NOSLEEP); 2797*9e39c5baSBill Taylor } 2798*9e39c5baSBill Taylor lstate->hls_tx.hlc_cqhdl[i] = NULL; 2799*9e39c5baSBill Taylor lstate->hls_rx.hlc_cqhdl[i] = NULL; 2800*9e39c5baSBill Taylor } 2801*9e39c5baSBill Taylor } 2802*9e39c5baSBill Taylor 2803*9e39c5baSBill Taylor /* 2804*9e39c5baSBill Taylor * hermon_loopback_free_state 2805*9e39c5baSBill Taylor */ 2806*9e39c5baSBill Taylor static void 2807*9e39c5baSBill Taylor hermon_loopback_free_state(hermon_loopback_state_t *lstate) 2808*9e39c5baSBill Taylor { 2809*9e39c5baSBill Taylor hermon_loopback_free_qps(lstate); 2810*9e39c5baSBill Taylor if (lstate->hls_tx.hlc_mrhdl != NULL) { 2811*9e39c5baSBill Taylor (void) hermon_mr_deregister(lstate->hls_state, 2812*9e39c5baSBill Taylor &lstate->hls_tx.hlc_mrhdl, HERMON_MR_DEREG_ALL, 2813*9e39c5baSBill Taylor HERMON_NOSLEEP); 2814*9e39c5baSBill Taylor } 2815*9e39c5baSBill Taylor if (lstate->hls_rx.hlc_mrhdl != NULL) { 2816*9e39c5baSBill Taylor (void) hermon_mr_deregister(lstate->hls_state, 2817*9e39c5baSBill Taylor &lstate->hls_rx.hlc_mrhdl, HERMON_MR_DEREG_ALL, 2818*9e39c5baSBill Taylor HERMON_NOSLEEP); 2819*9e39c5baSBill Taylor } 2820*9e39c5baSBill Taylor if (lstate->hls_pd_hdl != NULL) { 2821*9e39c5baSBill Taylor (void) hermon_pd_free(lstate->hls_state, &lstate->hls_pd_hdl); 2822*9e39c5baSBill Taylor } 2823*9e39c5baSBill Taylor if (lstate->hls_tx.hlc_buf != NULL) { 2824*9e39c5baSBill Taylor kmem_free(lstate->hls_tx.hlc_buf, lstate->hls_tx.hlc_buf_sz); 2825*9e39c5baSBill Taylor } 2826*9e39c5baSBill Taylor if (lstate->hls_rx.hlc_buf != NULL) { 2827*9e39c5baSBill Taylor kmem_free(lstate->hls_rx.hlc_buf, lstate->hls_rx.hlc_buf_sz); 2828*9e39c5baSBill Taylor } 2829*9e39c5baSBill Taylor bzero(lstate, sizeof (hermon_loopback_state_t)); 2830*9e39c5baSBill Taylor } 2831*9e39c5baSBill Taylor 2832*9e39c5baSBill Taylor /* 2833*9e39c5baSBill Taylor * hermon_loopback_init 2834*9e39c5baSBill Taylor */ 2835*9e39c5baSBill Taylor static int 2836*9e39c5baSBill Taylor hermon_loopback_init(hermon_state_t *state, hermon_loopback_state_t *lstate) 2837*9e39c5baSBill Taylor { 2838*9e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lstate)) 2839*9e39c5baSBill Taylor 2840*9e39c5baSBill Taylor lstate->hls_hca_hdl = (ibc_hca_hdl_t)state; 2841*9e39c5baSBill Taylor lstate->hls_status = hermon_pd_alloc(lstate->hls_state, 2842*9e39c5baSBill Taylor &lstate->hls_pd_hdl, HERMON_NOSLEEP); 2843*9e39c5baSBill Taylor if (lstate->hls_status != IBT_SUCCESS) { 2844*9e39c5baSBill Taylor lstate->hls_err = HERMON_LOOPBACK_PROT_DOMAIN_ALLOC_FAIL; 2845*9e39c5baSBill Taylor return (EFAULT); 2846*9e39c5baSBill Taylor } 2847*9e39c5baSBill Taylor 2848*9e39c5baSBill Taylor return (0); 2849*9e39c5baSBill Taylor } 2850*9e39c5baSBill Taylor 2851*9e39c5baSBill Taylor /* 2852*9e39c5baSBill Taylor * hermon_loopback_init_qp_info 2853*9e39c5baSBill Taylor */ 2854*9e39c5baSBill Taylor static void 2855*9e39c5baSBill Taylor hermon_loopback_init_qp_info(hermon_loopback_state_t *lstate, 2856*9e39c5baSBill Taylor hermon_loopback_comm_t *comm) 2857*9e39c5baSBill Taylor { 2858*9e39c5baSBill Taylor bzero(&comm->hlc_cq_attr, sizeof (ibt_cq_attr_t)); 2859*9e39c5baSBill Taylor bzero(&comm->hlc_qp_attr, sizeof (ibt_qp_alloc_attr_t)); 2860*9e39c5baSBill Taylor bzero(&comm->hlc_qp_info, sizeof (ibt_qp_info_t)); 2861*9e39c5baSBill Taylor 2862*9e39c5baSBill Taylor comm->hlc_wrid = 1; 2863*9e39c5baSBill Taylor comm->hlc_cq_attr.cq_size = 128; 2864*9e39c5baSBill Taylor comm->hlc_qp_attr.qp_sizes.cs_sq_sgl = 3; 2865*9e39c5baSBill Taylor comm->hlc_qp_attr.qp_sizes.cs_rq_sgl = 3; 2866*9e39c5baSBill Taylor comm->hlc_qp_attr.qp_sizes.cs_sq = 16; 2867*9e39c5baSBill Taylor comm->hlc_qp_attr.qp_sizes.cs_rq = 16; 2868*9e39c5baSBill Taylor comm->hlc_qp_attr.qp_flags = IBT_WR_SIGNALED; 2869*9e39c5baSBill Taylor 2870*9e39c5baSBill Taylor comm->hlc_qp_info.qp_state = IBT_STATE_RESET; 2871*9e39c5baSBill Taylor comm->hlc_qp_info.qp_trans = IBT_RC_SRV; 2872*9e39c5baSBill Taylor comm->hlc_qp_info.qp_flags = IBT_CEP_RDMA_RD | IBT_CEP_RDMA_WR; 2873*9e39c5baSBill Taylor comm->hlc_qp_info.qp_transport.rc.rc_path.cep_hca_port_num = 2874*9e39c5baSBill Taylor lstate->hls_port; 2875*9e39c5baSBill Taylor comm->hlc_qp_info.qp_transport.rc.rc_path.cep_pkey_ix = 2876*9e39c5baSBill Taylor lstate->hls_pkey_ix; 2877*9e39c5baSBill Taylor comm->hlc_qp_info.qp_transport.rc.rc_path.cep_timeout = 2878*9e39c5baSBill Taylor lstate->hls_timeout; 2879*9e39c5baSBill Taylor comm->hlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_srvl = 0; 2880*9e39c5baSBill Taylor comm->hlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_srate = 2881*9e39c5baSBill Taylor IBT_SRATE_4X; 2882*9e39c5baSBill Taylor comm->hlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_send_grh = 0; 2883*9e39c5baSBill Taylor comm->hlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_dlid = 2884*9e39c5baSBill Taylor lstate->hls_lid; 2885*9e39c5baSBill Taylor comm->hlc_qp_info.qp_transport.rc.rc_retry_cnt = lstate->hls_retry; 2886*9e39c5baSBill Taylor comm->hlc_qp_info.qp_transport.rc.rc_sq_psn = 0; 2887*9e39c5baSBill Taylor comm->hlc_qp_info.qp_transport.rc.rc_rq_psn = 0; 2888*9e39c5baSBill Taylor comm->hlc_qp_info.qp_transport.rc.rc_rdma_ra_in = 4; 2889*9e39c5baSBill Taylor comm->hlc_qp_info.qp_transport.rc.rc_rdma_ra_out = 4; 2890*9e39c5baSBill Taylor comm->hlc_qp_info.qp_transport.rc.rc_dst_qpn = 0; 2891*9e39c5baSBill Taylor comm->hlc_qp_info.qp_transport.rc.rc_min_rnr_nak = IBT_RNR_NAK_655ms; 2892*9e39c5baSBill Taylor comm->hlc_qp_info.qp_transport.rc.rc_path_mtu = IB_MTU_1K; 2893*9e39c5baSBill Taylor } 2894*9e39c5baSBill Taylor 2895*9e39c5baSBill Taylor /* 2896*9e39c5baSBill Taylor * hermon_loopback_alloc_mem 2897*9e39c5baSBill Taylor */ 2898*9e39c5baSBill Taylor static int 2899*9e39c5baSBill Taylor hermon_loopback_alloc_mem(hermon_loopback_state_t *lstate, 2900*9e39c5baSBill Taylor hermon_loopback_comm_t *comm, int sz) 2901*9e39c5baSBill Taylor { 2902*9e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm)) 2903*9e39c5baSBill Taylor 2904*9e39c5baSBill Taylor /* Allocate buffer of specified size */ 2905*9e39c5baSBill Taylor comm->hlc_buf_sz = sz; 2906*9e39c5baSBill Taylor comm->hlc_buf = kmem_zalloc(sz, KM_NOSLEEP); 2907*9e39c5baSBill Taylor if (comm->hlc_buf == NULL) { 2908*9e39c5baSBill Taylor return (EFAULT); 2909*9e39c5baSBill Taylor } 2910*9e39c5baSBill Taylor 2911*9e39c5baSBill Taylor /* Register the buffer as a memory region */ 2912*9e39c5baSBill Taylor comm->hlc_memattr.mr_vaddr = (uint64_t)(uintptr_t)comm->hlc_buf; 2913*9e39c5baSBill Taylor comm->hlc_memattr.mr_len = (ib_msglen_t)sz; 2914*9e39c5baSBill Taylor comm->hlc_memattr.mr_as = NULL; 2915*9e39c5baSBill Taylor comm->hlc_memattr.mr_flags = IBT_MR_NOSLEEP | 2916*9e39c5baSBill Taylor IBT_MR_ENABLE_REMOTE_WRITE | IBT_MR_ENABLE_LOCAL_WRITE; 2917*9e39c5baSBill Taylor 2918*9e39c5baSBill Taylor comm->hlc_status = hermon_mr_register(lstate->hls_state, 2919*9e39c5baSBill Taylor lstate->hls_pd_hdl, &comm->hlc_memattr, &comm->hlc_mrhdl, 2920*9e39c5baSBill Taylor NULL, HERMON_MPT_DMPT); 2921*9e39c5baSBill Taylor 2922*9e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm->hlc_mrhdl)) 2923*9e39c5baSBill Taylor 2924*9e39c5baSBill Taylor comm->hlc_mrdesc.md_vaddr = comm->hlc_mrhdl->mr_bindinfo.bi_addr; 2925*9e39c5baSBill Taylor comm->hlc_mrdesc.md_lkey = comm->hlc_mrhdl->mr_lkey; 2926*9e39c5baSBill Taylor comm->hlc_mrdesc.md_rkey = comm->hlc_mrhdl->mr_rkey; 2927*9e39c5baSBill Taylor if (comm->hlc_status != IBT_SUCCESS) { 2928*9e39c5baSBill Taylor return (EFAULT); 2929*9e39c5baSBill Taylor } 2930*9e39c5baSBill Taylor return (0); 2931*9e39c5baSBill Taylor } 2932*9e39c5baSBill Taylor 2933*9e39c5baSBill Taylor /* 2934*9e39c5baSBill Taylor * hermon_loopback_alloc_qps 2935*9e39c5baSBill Taylor */ 2936*9e39c5baSBill Taylor static int 2937*9e39c5baSBill Taylor hermon_loopback_alloc_qps(hermon_loopback_state_t *lstate, 2938*9e39c5baSBill Taylor hermon_loopback_comm_t *comm) 2939*9e39c5baSBill Taylor { 2940*9e39c5baSBill Taylor uint32_t i, real_size; 2941*9e39c5baSBill Taylor hermon_qp_info_t qpinfo; 2942*9e39c5baSBill Taylor 2943*9e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm)) 2944*9e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lstate)) 2945*9e39c5baSBill Taylor 2946*9e39c5baSBill Taylor /* Allocate send and recv CQs */ 2947*9e39c5baSBill Taylor for (i = 0; i < 2; i++) { 2948*9e39c5baSBill Taylor bzero(&comm->hlc_cq_attr, sizeof (ibt_cq_attr_t)); 2949*9e39c5baSBill Taylor comm->hlc_cq_attr.cq_size = 128; 2950*9e39c5baSBill Taylor comm->hlc_status = hermon_cq_alloc(lstate->hls_state, 2951*9e39c5baSBill Taylor (ibt_cq_hdl_t)NULL, &comm->hlc_cq_attr, &real_size, 2952*9e39c5baSBill Taylor &comm->hlc_cqhdl[i], HERMON_NOSLEEP); 2953*9e39c5baSBill Taylor if (comm->hlc_status != IBT_SUCCESS) { 2954*9e39c5baSBill Taylor lstate->hls_err += i; 2955*9e39c5baSBill Taylor return (EFAULT); 2956*9e39c5baSBill Taylor } 2957*9e39c5baSBill Taylor } 2958*9e39c5baSBill Taylor 2959*9e39c5baSBill Taylor /* Allocate the QP */ 2960*9e39c5baSBill Taylor hermon_loopback_init_qp_info(lstate, comm); 2961*9e39c5baSBill Taylor comm->hlc_qp_attr.qp_pd_hdl = (ibt_pd_hdl_t)lstate->hls_pd_hdl; 2962*9e39c5baSBill Taylor comm->hlc_qp_attr.qp_scq_hdl = (ibt_cq_hdl_t)comm->hlc_cqhdl[0]; 2963*9e39c5baSBill Taylor comm->hlc_qp_attr.qp_rcq_hdl = (ibt_cq_hdl_t)comm->hlc_cqhdl[1]; 2964*9e39c5baSBill Taylor comm->hlc_qp_attr.qp_ibc_scq_hdl = (ibt_opaque1_t)comm->hlc_cqhdl[0]; 2965*9e39c5baSBill Taylor comm->hlc_qp_attr.qp_ibc_rcq_hdl = (ibt_opaque1_t)comm->hlc_cqhdl[1]; 2966*9e39c5baSBill Taylor qpinfo.qpi_attrp = &comm->hlc_qp_attr; 2967*9e39c5baSBill Taylor qpinfo.qpi_type = IBT_RC_RQP; 2968*9e39c5baSBill Taylor qpinfo.qpi_ibt_qphdl = NULL; 2969*9e39c5baSBill Taylor qpinfo.qpi_queueszp = &comm->hlc_chan_sizes; 2970*9e39c5baSBill Taylor qpinfo.qpi_qpn = &comm->hlc_qp_num; 2971*9e39c5baSBill Taylor comm->hlc_status = hermon_qp_alloc(lstate->hls_state, &qpinfo, 2972*9e39c5baSBill Taylor HERMON_NOSLEEP); 2973*9e39c5baSBill Taylor if (comm->hlc_status == DDI_SUCCESS) { 2974*9e39c5baSBill Taylor comm->hlc_qp_hdl = qpinfo.qpi_qphdl; 2975*9e39c5baSBill Taylor } 2976*9e39c5baSBill Taylor 2977*9e39c5baSBill Taylor if (comm->hlc_status != IBT_SUCCESS) { 2978*9e39c5baSBill Taylor lstate->hls_err += 2; 2979*9e39c5baSBill Taylor return (EFAULT); 2980*9e39c5baSBill Taylor } 2981*9e39c5baSBill Taylor return (0); 2982*9e39c5baSBill Taylor } 2983*9e39c5baSBill Taylor 2984*9e39c5baSBill Taylor /* 2985*9e39c5baSBill Taylor * hermon_loopback_modify_qp 2986*9e39c5baSBill Taylor */ 2987*9e39c5baSBill Taylor static int 2988*9e39c5baSBill Taylor hermon_loopback_modify_qp(hermon_loopback_state_t *lstate, 2989*9e39c5baSBill Taylor hermon_loopback_comm_t *comm, uint_t qp_num) 2990*9e39c5baSBill Taylor { 2991*9e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm)) 2992*9e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lstate)) 2993*9e39c5baSBill Taylor 2994*9e39c5baSBill Taylor /* Modify QP to INIT */ 2995*9e39c5baSBill Taylor hermon_loopback_init_qp_info(lstate, comm); 2996*9e39c5baSBill Taylor comm->hlc_qp_info.qp_state = IBT_STATE_INIT; 2997*9e39c5baSBill Taylor comm->hlc_status = hermon_qp_modify(lstate->hls_state, comm->hlc_qp_hdl, 2998*9e39c5baSBill Taylor IBT_CEP_SET_STATE, &comm->hlc_qp_info, &comm->hlc_queue_sizes); 2999*9e39c5baSBill Taylor if (comm->hlc_status != IBT_SUCCESS) { 3000*9e39c5baSBill Taylor return (EFAULT); 3001*9e39c5baSBill Taylor } 3002*9e39c5baSBill Taylor 3003*9e39c5baSBill Taylor /* 3004*9e39c5baSBill Taylor * Modify QP to RTR (set destination LID and QP number to local 3005*9e39c5baSBill Taylor * LID and QP number) 3006*9e39c5baSBill Taylor */ 3007*9e39c5baSBill Taylor comm->hlc_qp_info.qp_state = IBT_STATE_RTR; 3008*9e39c5baSBill Taylor comm->hlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_dlid 3009*9e39c5baSBill Taylor = lstate->hls_lid; 3010*9e39c5baSBill Taylor comm->hlc_qp_info.qp_transport.rc.rc_dst_qpn = qp_num; 3011*9e39c5baSBill Taylor comm->hlc_status = hermon_qp_modify(lstate->hls_state, comm->hlc_qp_hdl, 3012*9e39c5baSBill Taylor IBT_CEP_SET_STATE, &comm->hlc_qp_info, &comm->hlc_queue_sizes); 3013*9e39c5baSBill Taylor if (comm->hlc_status != IBT_SUCCESS) { 3014*9e39c5baSBill Taylor lstate->hls_err += 1; 3015*9e39c5baSBill Taylor return (EFAULT); 3016*9e39c5baSBill Taylor } 3017*9e39c5baSBill Taylor 3018*9e39c5baSBill Taylor /* Modify QP to RTS */ 3019*9e39c5baSBill Taylor comm->hlc_qp_info.qp_current_state = IBT_STATE_RTR; 3020*9e39c5baSBill Taylor comm->hlc_qp_info.qp_state = IBT_STATE_RTS; 3021*9e39c5baSBill Taylor comm->hlc_status = hermon_qp_modify(lstate->hls_state, comm->hlc_qp_hdl, 3022*9e39c5baSBill Taylor IBT_CEP_SET_STATE, &comm->hlc_qp_info, &comm->hlc_queue_sizes); 3023*9e39c5baSBill Taylor if (comm->hlc_status != IBT_SUCCESS) { 3024*9e39c5baSBill Taylor lstate->hls_err += 2; 3025*9e39c5baSBill Taylor return (EFAULT); 3026*9e39c5baSBill Taylor } 3027*9e39c5baSBill Taylor return (0); 3028*9e39c5baSBill Taylor } 3029*9e39c5baSBill Taylor 3030*9e39c5baSBill Taylor /* 3031*9e39c5baSBill Taylor * hermon_loopback_copyout 3032*9e39c5baSBill Taylor */ 3033*9e39c5baSBill Taylor static int 3034*9e39c5baSBill Taylor hermon_loopback_copyout(hermon_loopback_ioctl_t *lb, intptr_t arg, int mode) 3035*9e39c5baSBill Taylor { 3036*9e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL 3037*9e39c5baSBill Taylor if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 3038*9e39c5baSBill Taylor hermon_loopback_ioctl32_t lb32; 3039*9e39c5baSBill Taylor 3040*9e39c5baSBill Taylor lb32.alb_revision = lb->alb_revision; 3041*9e39c5baSBill Taylor lb32.alb_send_buf = 3042*9e39c5baSBill Taylor (caddr32_t)(uintptr_t)lb->alb_send_buf; 3043*9e39c5baSBill Taylor lb32.alb_fail_buf = 3044*9e39c5baSBill Taylor (caddr32_t)(uintptr_t)lb->alb_fail_buf; 3045*9e39c5baSBill Taylor lb32.alb_buf_sz = lb->alb_buf_sz; 3046*9e39c5baSBill Taylor lb32.alb_num_iter = lb->alb_num_iter; 3047*9e39c5baSBill Taylor lb32.alb_pass_done = lb->alb_pass_done; 3048*9e39c5baSBill Taylor lb32.alb_timeout = lb->alb_timeout; 3049*9e39c5baSBill Taylor lb32.alb_error_type = lb->alb_error_type; 3050*9e39c5baSBill Taylor lb32.alb_port_num = lb->alb_port_num; 3051*9e39c5baSBill Taylor lb32.alb_num_retry = lb->alb_num_retry; 3052*9e39c5baSBill Taylor 3053*9e39c5baSBill Taylor if (ddi_copyout(&lb32, (void *)arg, 3054*9e39c5baSBill Taylor sizeof (hermon_loopback_ioctl32_t), mode) != 0) { 3055*9e39c5baSBill Taylor return (EFAULT); 3056*9e39c5baSBill Taylor } 3057*9e39c5baSBill Taylor } else 3058*9e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */ 3059*9e39c5baSBill Taylor if (ddi_copyout(lb, (void *)arg, sizeof (hermon_loopback_ioctl_t), 3060*9e39c5baSBill Taylor mode) != 0) { 3061*9e39c5baSBill Taylor return (EFAULT); 3062*9e39c5baSBill Taylor } 3063*9e39c5baSBill Taylor return (0); 3064*9e39c5baSBill Taylor } 3065*9e39c5baSBill Taylor 3066*9e39c5baSBill Taylor /* 3067*9e39c5baSBill Taylor * hermon_loopback_post_send 3068*9e39c5baSBill Taylor */ 3069*9e39c5baSBill Taylor static int 3070*9e39c5baSBill Taylor hermon_loopback_post_send(hermon_loopback_state_t *lstate, 3071*9e39c5baSBill Taylor hermon_loopback_comm_t *tx, hermon_loopback_comm_t *rx) 3072*9e39c5baSBill Taylor { 3073*9e39c5baSBill Taylor int ret; 3074*9e39c5baSBill Taylor 3075*9e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*tx)) 3076*9e39c5baSBill Taylor 3077*9e39c5baSBill Taylor bzero(&tx->hlc_sgl, sizeof (ibt_wr_ds_t)); 3078*9e39c5baSBill Taylor bzero(&tx->hlc_wr, sizeof (ibt_send_wr_t)); 3079*9e39c5baSBill Taylor 3080*9e39c5baSBill Taylor /* Initialize local address for TX buffer */ 3081*9e39c5baSBill Taylor tx->hlc_sgl.ds_va = tx->hlc_mrdesc.md_vaddr; 3082*9e39c5baSBill Taylor tx->hlc_sgl.ds_key = tx->hlc_mrdesc.md_lkey; 3083*9e39c5baSBill Taylor tx->hlc_sgl.ds_len = tx->hlc_buf_sz; 3084*9e39c5baSBill Taylor 3085*9e39c5baSBill Taylor /* Initialize the remaining details of the work request */ 3086*9e39c5baSBill Taylor tx->hlc_wr.wr_id = tx->hlc_wrid++; 3087*9e39c5baSBill Taylor tx->hlc_wr.wr_flags = IBT_WR_SEND_SIGNAL; 3088*9e39c5baSBill Taylor tx->hlc_wr.wr_nds = 1; 3089*9e39c5baSBill Taylor tx->hlc_wr.wr_sgl = &tx->hlc_sgl; 3090*9e39c5baSBill Taylor tx->hlc_wr.wr_opcode = IBT_WRC_RDMAW; 3091*9e39c5baSBill Taylor tx->hlc_wr.wr_trans = IBT_RC_SRV; 3092*9e39c5baSBill Taylor 3093*9e39c5baSBill Taylor /* Initialize the remote address for RX buffer */ 3094*9e39c5baSBill Taylor tx->hlc_wr.wr.rc.rcwr.rdma.rdma_raddr = rx->hlc_mrdesc.md_vaddr; 3095*9e39c5baSBill Taylor tx->hlc_wr.wr.rc.rcwr.rdma.rdma_rkey = rx->hlc_mrdesc.md_rkey; 3096*9e39c5baSBill Taylor tx->hlc_complete = 0; 3097*9e39c5baSBill Taylor ret = hermon_post_send(lstate->hls_state, tx->hlc_qp_hdl, &tx->hlc_wr, 3098*9e39c5baSBill Taylor 1, NULL); 3099*9e39c5baSBill Taylor if (ret != IBT_SUCCESS) { 3100*9e39c5baSBill Taylor return (EFAULT); 3101*9e39c5baSBill Taylor } 3102*9e39c5baSBill Taylor return (0); 3103*9e39c5baSBill Taylor } 3104*9e39c5baSBill Taylor 3105*9e39c5baSBill Taylor /* 3106*9e39c5baSBill Taylor * hermon_loopback_poll_cq 3107*9e39c5baSBill Taylor */ 3108*9e39c5baSBill Taylor static int 3109*9e39c5baSBill Taylor hermon_loopback_poll_cq(hermon_loopback_state_t *lstate, 3110*9e39c5baSBill Taylor hermon_loopback_comm_t *comm) 3111*9e39c5baSBill Taylor { 3112*9e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm)) 3113*9e39c5baSBill Taylor 3114*9e39c5baSBill Taylor comm->hlc_wc.wc_status = 0; 3115*9e39c5baSBill Taylor comm->hlc_num_polled = 0; 3116*9e39c5baSBill Taylor comm->hlc_status = hermon_cq_poll(lstate->hls_state, 3117*9e39c5baSBill Taylor comm->hlc_cqhdl[0], &comm->hlc_wc, 1, &comm->hlc_num_polled); 3118*9e39c5baSBill Taylor if ((comm->hlc_status == IBT_SUCCESS) && 3119*9e39c5baSBill Taylor (comm->hlc_wc.wc_status != IBT_WC_SUCCESS)) { 3120*9e39c5baSBill Taylor comm->hlc_status = ibc_get_ci_failure(0); 3121*9e39c5baSBill Taylor } 3122*9e39c5baSBill Taylor return (comm->hlc_status); 3123*9e39c5baSBill Taylor } 3124