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 * tavor_ioctl.c 29*9e39c5baSBill Taylor * Tavor 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 tavor 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/tavor/tavor.h> 44*9e39c5baSBill Taylor 45*9e39c5baSBill Taylor /* Tavor HCA state pointer (extern) */ 46*9e39c5baSBill Taylor extern void *tavor_statep; 47*9e39c5baSBill Taylor 48*9e39c5baSBill Taylor /* 49*9e39c5baSBill Taylor * The ioctl declarations (for firmware flash burning, register read/write 50*9e39c5baSBill Taylor * (DEBUG-only), and VTS interfaces) 51*9e39c5baSBill Taylor */ 52*9e39c5baSBill Taylor static int tavor_ioctl_flash_read(tavor_state_t *state, dev_t dev, 53*9e39c5baSBill Taylor intptr_t arg, int mode); 54*9e39c5baSBill Taylor static int tavor_ioctl_flash_write(tavor_state_t *state, dev_t dev, 55*9e39c5baSBill Taylor intptr_t arg, int mode); 56*9e39c5baSBill Taylor static int tavor_ioctl_flash_erase(tavor_state_t *state, dev_t dev, 57*9e39c5baSBill Taylor intptr_t arg, int mode); 58*9e39c5baSBill Taylor static int tavor_ioctl_flash_init(tavor_state_t *state, dev_t dev, 59*9e39c5baSBill Taylor intptr_t arg, int mode); 60*9e39c5baSBill Taylor static int tavor_ioctl_flash_fini(tavor_state_t *state, dev_t dev); 61*9e39c5baSBill Taylor static void tavor_ioctl_flash_cleanup(tavor_state_t *state); 62*9e39c5baSBill Taylor static void tavor_ioctl_flash_cleanup_nolock(tavor_state_t *state); 63*9e39c5baSBill Taylor #ifdef DEBUG 64*9e39c5baSBill Taylor static int tavor_ioctl_reg_write(tavor_state_t *state, intptr_t arg, 65*9e39c5baSBill Taylor int mode); 66*9e39c5baSBill Taylor static int tavor_ioctl_reg_read(tavor_state_t *state, intptr_t arg, 67*9e39c5baSBill Taylor int mode); 68*9e39c5baSBill Taylor #endif /* DEBUG */ 69*9e39c5baSBill Taylor static int tavor_ioctl_info(tavor_state_t *state, dev_t dev, 70*9e39c5baSBill Taylor intptr_t arg, int mode); 71*9e39c5baSBill Taylor static int tavor_ioctl_ports(tavor_state_t *state, intptr_t arg, 72*9e39c5baSBill Taylor int mode); 73*9e39c5baSBill Taylor static int tavor_ioctl_loopback(tavor_state_t *state, intptr_t arg, 74*9e39c5baSBill Taylor int mode); 75*9e39c5baSBill Taylor static int tavor_ioctl_ddr_read(tavor_state_t *state, intptr_t arg, 76*9e39c5baSBill Taylor int mode); 77*9e39c5baSBill Taylor 78*9e39c5baSBill Taylor /* Tavor Flash Functions */ 79*9e39c5baSBill Taylor static void tavor_flash_read_sector(tavor_state_t *state, uint32_t sector_num); 80*9e39c5baSBill Taylor static void tavor_flash_read_quadlet(tavor_state_t *state, uint32_t *data, 81*9e39c5baSBill Taylor uint32_t addr); 82*9e39c5baSBill Taylor static int tavor_flash_write_sector(tavor_state_t *state, uint32_t sector_num); 83*9e39c5baSBill Taylor static int tavor_flash_write_byte(tavor_state_t *state, uint32_t addr, 84*9e39c5baSBill Taylor uchar_t data); 85*9e39c5baSBill Taylor static int tavor_flash_erase_sector(tavor_state_t *state, uint32_t sector_num); 86*9e39c5baSBill Taylor static int tavor_flash_erase_chip(tavor_state_t *state); 87*9e39c5baSBill Taylor static void tavor_flash_bank(tavor_state_t *state, uint32_t addr); 88*9e39c5baSBill Taylor static uint32_t tavor_flash_read(tavor_state_t *state, uint32_t addr); 89*9e39c5baSBill Taylor static void tavor_flash_write(tavor_state_t *state, uint32_t addr, 90*9e39c5baSBill Taylor uchar_t data); 91*9e39c5baSBill Taylor static void tavor_flash_init(tavor_state_t *state); 92*9e39c5baSBill Taylor static void tavor_flash_cfi_init(tavor_state_t *state, uint32_t *cfi_info, 93*9e39c5baSBill Taylor int *intel_xcmd); 94*9e39c5baSBill Taylor static void tavor_flash_fini(tavor_state_t *state); 95*9e39c5baSBill Taylor static void tavor_flash_reset(tavor_state_t *state); 96*9e39c5baSBill Taylor static uint32_t tavor_flash_read_cfg(ddi_acc_handle_t pci_config_hdl, 97*9e39c5baSBill Taylor uint32_t addr); 98*9e39c5baSBill Taylor static void tavor_flash_write_cfg(ddi_acc_handle_t pci_config_hdl, 99*9e39c5baSBill Taylor uint32_t addr, uint32_t data); 100*9e39c5baSBill Taylor static void tavor_flash_cfi_byte(uint8_t *ch, uint32_t dword, int i); 101*9e39c5baSBill Taylor static void tavor_flash_cfi_dword(uint32_t *dword, uint8_t *ch, int i); 102*9e39c5baSBill Taylor 103*9e39c5baSBill Taylor /* Tavor loopback test functions */ 104*9e39c5baSBill Taylor static void tavor_loopback_free_qps(tavor_loopback_state_t *lstate); 105*9e39c5baSBill Taylor static void tavor_loopback_free_state(tavor_loopback_state_t *lstate); 106*9e39c5baSBill Taylor static int tavor_loopback_init(tavor_state_t *state, 107*9e39c5baSBill Taylor tavor_loopback_state_t *lstate); 108*9e39c5baSBill Taylor static void tavor_loopback_init_qp_info(tavor_loopback_state_t *lstate, 109*9e39c5baSBill Taylor tavor_loopback_comm_t *comm); 110*9e39c5baSBill Taylor static int tavor_loopback_alloc_mem(tavor_loopback_state_t *lstate, 111*9e39c5baSBill Taylor tavor_loopback_comm_t *comm, int sz); 112*9e39c5baSBill Taylor static int tavor_loopback_alloc_qps(tavor_loopback_state_t *lstate, 113*9e39c5baSBill Taylor tavor_loopback_comm_t *comm); 114*9e39c5baSBill Taylor static int tavor_loopback_modify_qp(tavor_loopback_state_t *lstate, 115*9e39c5baSBill Taylor tavor_loopback_comm_t *comm, uint_t qp_num); 116*9e39c5baSBill Taylor static int tavor_loopback_copyout(tavor_loopback_ioctl_t *lb, 117*9e39c5baSBill Taylor intptr_t arg, int mode); 118*9e39c5baSBill Taylor static int tavor_loopback_post_send(tavor_loopback_state_t *lstate, 119*9e39c5baSBill Taylor tavor_loopback_comm_t *tx, tavor_loopback_comm_t *rx); 120*9e39c5baSBill Taylor static int tavor_loopback_poll_cq(tavor_loopback_state_t *lstate, 121*9e39c5baSBill Taylor tavor_loopback_comm_t *comm); 122*9e39c5baSBill Taylor 123*9e39c5baSBill Taylor /* Patchable timeout values for flash operations */ 124*9e39c5baSBill Taylor int tavor_hw_flash_timeout_gpio_sema = TAVOR_HW_FLASH_TIMEOUT_GPIO_SEMA; 125*9e39c5baSBill Taylor int tavor_hw_flash_timeout_config = TAVOR_HW_FLASH_TIMEOUT_CONFIG; 126*9e39c5baSBill Taylor int tavor_hw_flash_timeout_write = TAVOR_HW_FLASH_TIMEOUT_WRITE; 127*9e39c5baSBill Taylor int tavor_hw_flash_timeout_erase = TAVOR_HW_FLASH_TIMEOUT_ERASE; 128*9e39c5baSBill Taylor 129*9e39c5baSBill Taylor /* 130*9e39c5baSBill Taylor * tavor_ioctl() 131*9e39c5baSBill Taylor */ 132*9e39c5baSBill Taylor /* ARGSUSED */ 133*9e39c5baSBill Taylor int 134*9e39c5baSBill Taylor tavor_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 135*9e39c5baSBill Taylor int *rvalp) 136*9e39c5baSBill Taylor { 137*9e39c5baSBill Taylor tavor_state_t *state; 138*9e39c5baSBill Taylor minor_t instance; 139*9e39c5baSBill Taylor int status; 140*9e39c5baSBill Taylor 141*9e39c5baSBill Taylor TAVOR_TNF_ENTER(tavor_ioctl); 142*9e39c5baSBill Taylor 143*9e39c5baSBill Taylor if (drv_priv(credp) != 0) { 144*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_priv_fail, TAVOR_TNF_ERROR, ""); 145*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl); 146*9e39c5baSBill Taylor return (EPERM); 147*9e39c5baSBill Taylor } 148*9e39c5baSBill Taylor 149*9e39c5baSBill Taylor instance = TAVOR_DEV_INSTANCE(dev); 150*9e39c5baSBill Taylor if (instance == -1) { 151*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_inst_fail, TAVOR_TNF_ERROR, ""); 152*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl); 153*9e39c5baSBill Taylor return (EBADF); 154*9e39c5baSBill Taylor } 155*9e39c5baSBill Taylor 156*9e39c5baSBill Taylor state = ddi_get_soft_state(tavor_statep, instance); 157*9e39c5baSBill Taylor if (state == NULL) { 158*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_gss_fail, TAVOR_TNF_ERROR, ""); 159*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl); 160*9e39c5baSBill Taylor return (EBADF); 161*9e39c5baSBill Taylor } 162*9e39c5baSBill Taylor 163*9e39c5baSBill Taylor status = 0; 164*9e39c5baSBill Taylor 165*9e39c5baSBill Taylor switch (cmd) { 166*9e39c5baSBill Taylor case TAVOR_IOCTL_FLASH_READ: 167*9e39c5baSBill Taylor status = tavor_ioctl_flash_read(state, dev, arg, mode); 168*9e39c5baSBill Taylor break; 169*9e39c5baSBill Taylor 170*9e39c5baSBill Taylor case TAVOR_IOCTL_FLASH_WRITE: 171*9e39c5baSBill Taylor status = tavor_ioctl_flash_write(state, dev, arg, mode); 172*9e39c5baSBill Taylor break; 173*9e39c5baSBill Taylor 174*9e39c5baSBill Taylor case TAVOR_IOCTL_FLASH_ERASE: 175*9e39c5baSBill Taylor status = tavor_ioctl_flash_erase(state, dev, arg, mode); 176*9e39c5baSBill Taylor break; 177*9e39c5baSBill Taylor 178*9e39c5baSBill Taylor case TAVOR_IOCTL_FLASH_INIT: 179*9e39c5baSBill Taylor status = tavor_ioctl_flash_init(state, dev, arg, mode); 180*9e39c5baSBill Taylor break; 181*9e39c5baSBill Taylor 182*9e39c5baSBill Taylor case TAVOR_IOCTL_FLASH_FINI: 183*9e39c5baSBill Taylor status = tavor_ioctl_flash_fini(state, dev); 184*9e39c5baSBill Taylor break; 185*9e39c5baSBill Taylor 186*9e39c5baSBill Taylor case TAVOR_IOCTL_INFO: 187*9e39c5baSBill Taylor status = tavor_ioctl_info(state, dev, arg, mode); 188*9e39c5baSBill Taylor break; 189*9e39c5baSBill Taylor 190*9e39c5baSBill Taylor case TAVOR_IOCTL_PORTS: 191*9e39c5baSBill Taylor status = tavor_ioctl_ports(state, arg, mode); 192*9e39c5baSBill Taylor break; 193*9e39c5baSBill Taylor 194*9e39c5baSBill Taylor case TAVOR_IOCTL_DDR_READ: 195*9e39c5baSBill Taylor status = tavor_ioctl_ddr_read(state, arg, mode); 196*9e39c5baSBill Taylor break; 197*9e39c5baSBill Taylor 198*9e39c5baSBill Taylor case TAVOR_IOCTL_LOOPBACK: 199*9e39c5baSBill Taylor status = tavor_ioctl_loopback(state, arg, mode); 200*9e39c5baSBill Taylor break; 201*9e39c5baSBill Taylor 202*9e39c5baSBill Taylor #ifdef DEBUG 203*9e39c5baSBill Taylor case TAVOR_IOCTL_REG_WRITE: 204*9e39c5baSBill Taylor status = tavor_ioctl_reg_write(state, arg, mode); 205*9e39c5baSBill Taylor break; 206*9e39c5baSBill Taylor 207*9e39c5baSBill Taylor case TAVOR_IOCTL_REG_READ: 208*9e39c5baSBill Taylor status = tavor_ioctl_reg_read(state, arg, mode); 209*9e39c5baSBill Taylor break; 210*9e39c5baSBill Taylor #endif /* DEBUG */ 211*9e39c5baSBill Taylor 212*9e39c5baSBill Taylor default: 213*9e39c5baSBill Taylor status = ENOTTY; 214*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_default_fail, TAVOR_TNF_ERROR, ""); 215*9e39c5baSBill Taylor break; 216*9e39c5baSBill Taylor } 217*9e39c5baSBill Taylor *rvalp = status; 218*9e39c5baSBill Taylor 219*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl); 220*9e39c5baSBill Taylor return (status); 221*9e39c5baSBill Taylor } 222*9e39c5baSBill Taylor 223*9e39c5baSBill Taylor /* 224*9e39c5baSBill Taylor * tavor_ioctl_flash_read() 225*9e39c5baSBill Taylor */ 226*9e39c5baSBill Taylor static int 227*9e39c5baSBill Taylor tavor_ioctl_flash_read(tavor_state_t *state, dev_t dev, intptr_t arg, int mode) 228*9e39c5baSBill Taylor { 229*9e39c5baSBill Taylor tavor_flash_ioctl_t ioctl_info; 230*9e39c5baSBill Taylor int status = 0; 231*9e39c5baSBill Taylor 232*9e39c5baSBill Taylor TAVOR_TNF_ENTER(tavor_ioctl_flash_read); 233*9e39c5baSBill Taylor 234*9e39c5baSBill Taylor /* 235*9e39c5baSBill Taylor * Check that flash init ioctl has been called first. And check 236*9e39c5baSBill Taylor * that the same dev_t that called init is the one calling read now. 237*9e39c5baSBill Taylor */ 238*9e39c5baSBill Taylor mutex_enter(&state->ts_fw_flashlock); 239*9e39c5baSBill Taylor if ((state->ts_fw_flashdev != dev) || 240*9e39c5baSBill Taylor (state->ts_fw_flashstarted == 0)) { 241*9e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock); 242*9e39c5baSBill Taylor TNF_PROBE_0(tavor_flash_bad_state, TAVOR_TNF_ERROR, ""); 243*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_flash_read); 244*9e39c5baSBill Taylor return (EIO); 245*9e39c5baSBill Taylor } 246*9e39c5baSBill Taylor 247*9e39c5baSBill Taylor /* copy user struct to kernel */ 248*9e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL 249*9e39c5baSBill Taylor if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 250*9e39c5baSBill Taylor tavor_flash_ioctl32_t info32; 251*9e39c5baSBill Taylor 252*9e39c5baSBill Taylor if (ddi_copyin((void *)arg, &info32, 253*9e39c5baSBill Taylor sizeof (tavor_flash_ioctl32_t), mode) != 0) { 254*9e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock); 255*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_flash_read_copyin_fail, 256*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 257*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_flash_read); 258*9e39c5baSBill Taylor return (EFAULT); 259*9e39c5baSBill Taylor } 260*9e39c5baSBill Taylor ioctl_info.tf_type = info32.tf_type; 261*9e39c5baSBill Taylor ioctl_info.tf_sector = (caddr_t)(uintptr_t)info32.tf_sector; 262*9e39c5baSBill Taylor ioctl_info.tf_sector_num = info32.tf_sector_num; 263*9e39c5baSBill Taylor ioctl_info.tf_addr = info32.tf_addr; 264*9e39c5baSBill Taylor } else 265*9e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */ 266*9e39c5baSBill Taylor if (ddi_copyin((void *)arg, &ioctl_info, sizeof (tavor_flash_ioctl_t), 267*9e39c5baSBill Taylor mode) != 0) { 268*9e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock); 269*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_flash_read_copyin_fail, 270*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 271*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_flash_read); 272*9e39c5baSBill Taylor return (EFAULT); 273*9e39c5baSBill Taylor } 274*9e39c5baSBill Taylor 275*9e39c5baSBill Taylor /* 276*9e39c5baSBill Taylor * Determine type of READ ioctl 277*9e39c5baSBill Taylor */ 278*9e39c5baSBill Taylor switch (ioctl_info.tf_type) { 279*9e39c5baSBill Taylor case TAVOR_FLASH_READ_SECTOR: 280*9e39c5baSBill Taylor /* Check if sector num is too large for flash device */ 281*9e39c5baSBill Taylor if (ioctl_info.tf_sector_num >= 282*9e39c5baSBill Taylor (state->ts_fw_device_sz >> state->ts_fw_log_sector_sz)) { 283*9e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock); 284*9e39c5baSBill Taylor TNF_PROBE_0(tavor_flash_read_sector_num_too_large, 285*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 286*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_flash_read); 287*9e39c5baSBill Taylor return (EFAULT); 288*9e39c5baSBill Taylor } 289*9e39c5baSBill Taylor 290*9e39c5baSBill Taylor /* Perform the Sector Read */ 291*9e39c5baSBill Taylor tavor_flash_reset(state); 292*9e39c5baSBill Taylor tavor_flash_read_sector(state, ioctl_info.tf_sector_num); 293*9e39c5baSBill Taylor 294*9e39c5baSBill Taylor /* copyout the firmware sector image data */ 295*9e39c5baSBill Taylor if (ddi_copyout(&state->ts_fw_sector[0], 296*9e39c5baSBill Taylor &ioctl_info.tf_sector[0], 1 << state->ts_fw_log_sector_sz, 297*9e39c5baSBill Taylor mode) != 0) { 298*9e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock); 299*9e39c5baSBill Taylor TNF_PROBE_0(tavor_flash_read_copyout_fail, 300*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 301*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_flash_read); 302*9e39c5baSBill Taylor return (EFAULT); 303*9e39c5baSBill Taylor } 304*9e39c5baSBill Taylor break; 305*9e39c5baSBill Taylor 306*9e39c5baSBill Taylor case TAVOR_FLASH_READ_QUADLET: 307*9e39c5baSBill Taylor /* Check if addr is too large for flash device */ 308*9e39c5baSBill Taylor if (ioctl_info.tf_addr >= state->ts_fw_device_sz) { 309*9e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock); 310*9e39c5baSBill Taylor TNF_PROBE_0(tavor_flash_read_quad_addr_too_large, 311*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 312*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_flash_read); 313*9e39c5baSBill Taylor return (EFAULT); 314*9e39c5baSBill Taylor } 315*9e39c5baSBill Taylor 316*9e39c5baSBill Taylor /* Perform the Quadlet Read */ 317*9e39c5baSBill Taylor tavor_flash_reset(state); 318*9e39c5baSBill Taylor tavor_flash_read_quadlet(state, &ioctl_info.tf_quadlet, 319*9e39c5baSBill Taylor ioctl_info.tf_addr); 320*9e39c5baSBill Taylor break; 321*9e39c5baSBill Taylor 322*9e39c5baSBill Taylor default: 323*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_flash_read_invalid_type, 324*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 325*9e39c5baSBill Taylor status = EIO; 326*9e39c5baSBill Taylor break; 327*9e39c5baSBill Taylor } 328*9e39c5baSBill Taylor 329*9e39c5baSBill Taylor /* copy results back to userland */ 330*9e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL 331*9e39c5baSBill Taylor if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 332*9e39c5baSBill Taylor tavor_flash_ioctl32_t info32; 333*9e39c5baSBill Taylor 334*9e39c5baSBill Taylor info32.tf_quadlet = ioctl_info.tf_quadlet; 335*9e39c5baSBill Taylor info32.tf_type = ioctl_info.tf_type; 336*9e39c5baSBill Taylor info32.tf_sector_num = ioctl_info.tf_sector_num; 337*9e39c5baSBill Taylor info32.tf_sector = (caddr32_t)(uintptr_t)ioctl_info.tf_sector; 338*9e39c5baSBill Taylor info32.tf_addr = ioctl_info.tf_addr; 339*9e39c5baSBill Taylor 340*9e39c5baSBill Taylor if (ddi_copyout(&info32, (void *)arg, 341*9e39c5baSBill Taylor sizeof (tavor_flash_ioctl32_t), mode) != 0) { 342*9e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock); 343*9e39c5baSBill Taylor TNF_PROBE_0(tavor_flash_read_copyout_fail, 344*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 345*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_flash_read); 346*9e39c5baSBill Taylor return (EFAULT); 347*9e39c5baSBill Taylor } 348*9e39c5baSBill Taylor } else 349*9e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */ 350*9e39c5baSBill Taylor if (ddi_copyout(&ioctl_info, (void *)arg, 351*9e39c5baSBill Taylor sizeof (tavor_flash_ioctl_t), mode) != 0) { 352*9e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock); 353*9e39c5baSBill Taylor TNF_PROBE_0(tavor_flash_read_copyout_fail, 354*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 355*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_flash_read); 356*9e39c5baSBill Taylor return (EFAULT); 357*9e39c5baSBill Taylor } 358*9e39c5baSBill Taylor 359*9e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock); 360*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_flash_read); 361*9e39c5baSBill Taylor return (status); 362*9e39c5baSBill Taylor } 363*9e39c5baSBill Taylor 364*9e39c5baSBill Taylor /* 365*9e39c5baSBill Taylor * tavor_ioctl_flash_write() 366*9e39c5baSBill Taylor */ 367*9e39c5baSBill Taylor static int 368*9e39c5baSBill Taylor tavor_ioctl_flash_write(tavor_state_t *state, dev_t dev, intptr_t arg, int mode) 369*9e39c5baSBill Taylor { 370*9e39c5baSBill Taylor tavor_flash_ioctl_t ioctl_info; 371*9e39c5baSBill Taylor int status = 0; 372*9e39c5baSBill Taylor 373*9e39c5baSBill Taylor TAVOR_TNF_ENTER(tavor_ioctl_flash_write); 374*9e39c5baSBill Taylor 375*9e39c5baSBill Taylor /* 376*9e39c5baSBill Taylor * Check that flash init ioctl has been called first. And check 377*9e39c5baSBill Taylor * that the same dev_t that called init is the one calling write now. 378*9e39c5baSBill Taylor */ 379*9e39c5baSBill Taylor mutex_enter(&state->ts_fw_flashlock); 380*9e39c5baSBill Taylor if ((state->ts_fw_flashdev != dev) || 381*9e39c5baSBill Taylor (state->ts_fw_flashstarted == 0)) { 382*9e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock); 383*9e39c5baSBill Taylor TNF_PROBE_0(tavor_flash_bad_state, TAVOR_TNF_ERROR, ""); 384*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_flash_write); 385*9e39c5baSBill Taylor return (EIO); 386*9e39c5baSBill Taylor } 387*9e39c5baSBill Taylor 388*9e39c5baSBill Taylor /* copy user struct to kernel */ 389*9e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL 390*9e39c5baSBill Taylor if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 391*9e39c5baSBill Taylor tavor_flash_ioctl32_t info32; 392*9e39c5baSBill Taylor 393*9e39c5baSBill Taylor if (ddi_copyin((void *)arg, &info32, 394*9e39c5baSBill Taylor sizeof (tavor_flash_ioctl32_t), mode) != 0) { 395*9e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock); 396*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_flash_write_copyin_fail, 397*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 398*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_flash_write); 399*9e39c5baSBill Taylor return (EFAULT); 400*9e39c5baSBill Taylor } 401*9e39c5baSBill Taylor ioctl_info.tf_type = info32.tf_type; 402*9e39c5baSBill Taylor ioctl_info.tf_sector = (caddr_t)(uintptr_t)info32.tf_sector; 403*9e39c5baSBill Taylor ioctl_info.tf_sector_num = info32.tf_sector_num; 404*9e39c5baSBill Taylor ioctl_info.tf_addr = info32.tf_addr; 405*9e39c5baSBill Taylor ioctl_info.tf_byte = info32.tf_byte; 406*9e39c5baSBill Taylor } else 407*9e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */ 408*9e39c5baSBill Taylor if (ddi_copyin((void *)arg, &ioctl_info, 409*9e39c5baSBill Taylor sizeof (tavor_flash_ioctl_t), mode) != 0) { 410*9e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock); 411*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_flash_write_ci_fail, 412*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 413*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_flash_write); 414*9e39c5baSBill Taylor return (EFAULT); 415*9e39c5baSBill Taylor } 416*9e39c5baSBill Taylor 417*9e39c5baSBill Taylor /* 418*9e39c5baSBill Taylor * Determine type of WRITE ioctl 419*9e39c5baSBill Taylor */ 420*9e39c5baSBill Taylor switch (ioctl_info.tf_type) { 421*9e39c5baSBill Taylor case TAVOR_FLASH_WRITE_SECTOR: 422*9e39c5baSBill Taylor /* Check if sector num is too large for flash device */ 423*9e39c5baSBill Taylor if (ioctl_info.tf_sector_num >= 424*9e39c5baSBill Taylor (state->ts_fw_device_sz >> state->ts_fw_log_sector_sz)) { 425*9e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock); 426*9e39c5baSBill Taylor TNF_PROBE_0(tavor_flash_write_sector_num_too_large, 427*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 428*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_flash_write); 429*9e39c5baSBill Taylor return (EFAULT); 430*9e39c5baSBill Taylor } 431*9e39c5baSBill Taylor 432*9e39c5baSBill Taylor /* copy in fw sector image data */ 433*9e39c5baSBill Taylor if (ddi_copyin(&ioctl_info.tf_sector[0], 434*9e39c5baSBill Taylor &state->ts_fw_sector[0], 1 << state->ts_fw_log_sector_sz, 435*9e39c5baSBill Taylor mode) != 0) { 436*9e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock); 437*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_flash_write_fw_sector_ci_fail, 438*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 439*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_flash_write); 440*9e39c5baSBill Taylor return (EFAULT); 441*9e39c5baSBill Taylor } 442*9e39c5baSBill Taylor 443*9e39c5baSBill Taylor /* Perform Write Sector */ 444*9e39c5baSBill Taylor status = tavor_flash_write_sector(state, 445*9e39c5baSBill Taylor ioctl_info.tf_sector_num); 446*9e39c5baSBill Taylor break; 447*9e39c5baSBill Taylor 448*9e39c5baSBill Taylor case TAVOR_FLASH_WRITE_BYTE: 449*9e39c5baSBill Taylor /* Check if addr is too large for flash device */ 450*9e39c5baSBill Taylor if (ioctl_info.tf_addr >= state->ts_fw_device_sz) { 451*9e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock); 452*9e39c5baSBill Taylor TNF_PROBE_0(tavor_flash_write_byte_addr_too_large, 453*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 454*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_flash_write); 455*9e39c5baSBill Taylor return (EFAULT); 456*9e39c5baSBill Taylor } 457*9e39c5baSBill Taylor 458*9e39c5baSBill Taylor /* Perform Write Byte */ 459*9e39c5baSBill Taylor tavor_flash_bank(state, ioctl_info.tf_addr); 460*9e39c5baSBill Taylor tavor_flash_reset(state); 461*9e39c5baSBill Taylor status = tavor_flash_write_byte(state, ioctl_info.tf_addr, 462*9e39c5baSBill Taylor ioctl_info.tf_byte); 463*9e39c5baSBill Taylor tavor_flash_reset(state); 464*9e39c5baSBill Taylor break; 465*9e39c5baSBill Taylor 466*9e39c5baSBill Taylor default: 467*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_flash_write_invalid_type, 468*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 469*9e39c5baSBill Taylor status = EIO; 470*9e39c5baSBill Taylor break; 471*9e39c5baSBill Taylor } 472*9e39c5baSBill Taylor 473*9e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock); 474*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_flash_write); 475*9e39c5baSBill Taylor return (status); 476*9e39c5baSBill Taylor } 477*9e39c5baSBill Taylor 478*9e39c5baSBill Taylor /* 479*9e39c5baSBill Taylor * tavor_ioctl_flash_erase() 480*9e39c5baSBill Taylor */ 481*9e39c5baSBill Taylor static int 482*9e39c5baSBill Taylor tavor_ioctl_flash_erase(tavor_state_t *state, dev_t dev, intptr_t arg, int mode) 483*9e39c5baSBill Taylor { 484*9e39c5baSBill Taylor tavor_flash_ioctl_t ioctl_info; 485*9e39c5baSBill Taylor int status = 0; 486*9e39c5baSBill Taylor 487*9e39c5baSBill Taylor TAVOR_TNF_ENTER(tavor_ioctl_flash_erase); 488*9e39c5baSBill Taylor 489*9e39c5baSBill Taylor /* 490*9e39c5baSBill Taylor * Check that flash init ioctl has been called first. And check 491*9e39c5baSBill Taylor * that the same dev_t that called init is the one calling erase now. 492*9e39c5baSBill Taylor */ 493*9e39c5baSBill Taylor mutex_enter(&state->ts_fw_flashlock); 494*9e39c5baSBill Taylor if ((state->ts_fw_flashdev != dev) || 495*9e39c5baSBill Taylor (state->ts_fw_flashstarted == 0)) { 496*9e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock); 497*9e39c5baSBill Taylor TNF_PROBE_0(tavor_flash_bad_state, TAVOR_TNF_ERROR, ""); 498*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_flash_erase); 499*9e39c5baSBill Taylor return (EIO); 500*9e39c5baSBill Taylor } 501*9e39c5baSBill Taylor 502*9e39c5baSBill Taylor /* copy user struct to kernel */ 503*9e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL 504*9e39c5baSBill Taylor if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 505*9e39c5baSBill Taylor tavor_flash_ioctl32_t info32; 506*9e39c5baSBill Taylor 507*9e39c5baSBill Taylor if (ddi_copyin((void *)arg, &info32, 508*9e39c5baSBill Taylor sizeof (tavor_flash_ioctl32_t), mode) != 0) { 509*9e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock); 510*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_flash_read_copyin_fail, 511*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 512*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_flash_erase); 513*9e39c5baSBill Taylor return (EFAULT); 514*9e39c5baSBill Taylor } 515*9e39c5baSBill Taylor ioctl_info.tf_type = info32.tf_type; 516*9e39c5baSBill Taylor ioctl_info.tf_sector_num = info32.tf_sector_num; 517*9e39c5baSBill Taylor } else 518*9e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */ 519*9e39c5baSBill Taylor if (ddi_copyin((void *)arg, &ioctl_info, sizeof (tavor_flash_ioctl_t), 520*9e39c5baSBill Taylor mode) != 0) { 521*9e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock); 522*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_flash_erase_ci_fail, 523*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 524*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_flash_erase); 525*9e39c5baSBill Taylor return (EFAULT); 526*9e39c5baSBill Taylor } 527*9e39c5baSBill Taylor 528*9e39c5baSBill Taylor /* 529*9e39c5baSBill Taylor * Determine type of ERASE ioctl 530*9e39c5baSBill Taylor */ 531*9e39c5baSBill Taylor switch (ioctl_info.tf_type) { 532*9e39c5baSBill Taylor case TAVOR_FLASH_ERASE_SECTOR: 533*9e39c5baSBill Taylor /* Check if sector num is too large for flash device */ 534*9e39c5baSBill Taylor if (ioctl_info.tf_sector_num >= 535*9e39c5baSBill Taylor (state->ts_fw_device_sz >> state->ts_fw_log_sector_sz)) { 536*9e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock); 537*9e39c5baSBill Taylor TNF_PROBE_0(tavor_flash_erase_sector_num_too_large, 538*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 539*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_flash_write); 540*9e39c5baSBill Taylor return (EFAULT); 541*9e39c5baSBill Taylor } 542*9e39c5baSBill Taylor 543*9e39c5baSBill Taylor /* Perform Sector Erase */ 544*9e39c5baSBill Taylor status = tavor_flash_erase_sector(state, 545*9e39c5baSBill Taylor ioctl_info.tf_sector_num); 546*9e39c5baSBill Taylor break; 547*9e39c5baSBill Taylor 548*9e39c5baSBill Taylor case TAVOR_FLASH_ERASE_CHIP: 549*9e39c5baSBill Taylor /* Perform Chip Erase */ 550*9e39c5baSBill Taylor status = tavor_flash_erase_chip(state); 551*9e39c5baSBill Taylor break; 552*9e39c5baSBill Taylor 553*9e39c5baSBill Taylor default: 554*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_flash_erase_invalid_type, 555*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 556*9e39c5baSBill Taylor status = EIO; 557*9e39c5baSBill Taylor break; 558*9e39c5baSBill Taylor } 559*9e39c5baSBill Taylor 560*9e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock); 561*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_flash_erase); 562*9e39c5baSBill Taylor return (status); 563*9e39c5baSBill Taylor } 564*9e39c5baSBill Taylor 565*9e39c5baSBill Taylor /* 566*9e39c5baSBill Taylor * tavor_ioctl_flash_init() 567*9e39c5baSBill Taylor */ 568*9e39c5baSBill Taylor static int 569*9e39c5baSBill Taylor tavor_ioctl_flash_init(tavor_state_t *state, dev_t dev, intptr_t arg, int mode) 570*9e39c5baSBill Taylor { 571*9e39c5baSBill Taylor tavor_flash_init_ioctl_t init_info; 572*9e39c5baSBill Taylor int ret; 573*9e39c5baSBill Taylor int intel_xcmd = 0; 574*9e39c5baSBill Taylor 575*9e39c5baSBill Taylor TAVOR_TNF_ENTER(tavor_ioctl_flash_init); 576*9e39c5baSBill Taylor 577*9e39c5baSBill Taylor /* 578*9e39c5baSBill Taylor * init cannot be called more than once. If we have already init'd the 579*9e39c5baSBill Taylor * flash, return directly. 580*9e39c5baSBill Taylor */ 581*9e39c5baSBill Taylor mutex_enter(&state->ts_fw_flashlock); 582*9e39c5baSBill Taylor if (state->ts_fw_flashstarted == 1) { 583*9e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock); 584*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_flash_init_already_started, 585*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 586*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_flash_init); 587*9e39c5baSBill Taylor return (EIO); 588*9e39c5baSBill Taylor } 589*9e39c5baSBill Taylor 590*9e39c5baSBill Taylor /* copyin the user struct to kernel */ 591*9e39c5baSBill Taylor if (ddi_copyin((void *)arg, &init_info, 592*9e39c5baSBill Taylor sizeof (tavor_flash_init_ioctl_t), mode) != 0) { 593*9e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock); 594*9e39c5baSBill Taylor TNF_PROBE_0(tavor_flash_init_ioctl_copyin_fail, 595*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 596*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_flash_init); 597*9e39c5baSBill Taylor return (EFAULT); 598*9e39c5baSBill Taylor } 599*9e39c5baSBill Taylor 600*9e39c5baSBill Taylor /* Init Flash */ 601*9e39c5baSBill Taylor tavor_flash_init(state); 602*9e39c5baSBill Taylor 603*9e39c5baSBill Taylor /* Read CFI info */ 604*9e39c5baSBill Taylor tavor_flash_cfi_init(state, &init_info.tf_cfi_info[0], &intel_xcmd); 605*9e39c5baSBill Taylor 606*9e39c5baSBill Taylor /* 607*9e39c5baSBill Taylor * Return error if the command set is unknown. 608*9e39c5baSBill Taylor */ 609*9e39c5baSBill Taylor if (state->ts_fw_cmdset == TAVOR_FLASH_UNKNOWN_CMDSET) { 610*9e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock); 611*9e39c5baSBill Taylor TNF_PROBE_1(tavor_ioctl_flash_init_cmdset_fail, 612*9e39c5baSBill Taylor TAVOR_TNF_ERROR, "", tnf_string, errmsg, 613*9e39c5baSBill Taylor "UNKNOWN flash command set"); 614*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_flash_init); 615*9e39c5baSBill Taylor return (EFAULT); 616*9e39c5baSBill Taylor } 617*9e39c5baSBill Taylor 618*9e39c5baSBill Taylor /* Read HWREV - least significant 8 bits is revision ID */ 619*9e39c5baSBill Taylor init_info.tf_hwrev = pci_config_get32(state->ts_pci_cfghdl, 620*9e39c5baSBill Taylor TAVOR_HW_FLASH_CFG_HWREV) & 0xFF; 621*9e39c5baSBill Taylor 622*9e39c5baSBill Taylor /* Fill in the firmwate revision numbers */ 623*9e39c5baSBill Taylor init_info.tf_fwrev.tfi_maj = state->ts_fw.fw_rev_major; 624*9e39c5baSBill Taylor init_info.tf_fwrev.tfi_min = state->ts_fw.fw_rev_minor; 625*9e39c5baSBill Taylor init_info.tf_fwrev.tfi_sub = state->ts_fw.fw_rev_subminor; 626*9e39c5baSBill Taylor 627*9e39c5baSBill Taylor /* Alloc flash mem for one sector size */ 628*9e39c5baSBill Taylor state->ts_fw_sector = (uint32_t *)kmem_zalloc(1 << 629*9e39c5baSBill Taylor state->ts_fw_log_sector_sz, KM_SLEEP); 630*9e39c5baSBill Taylor 631*9e39c5baSBill Taylor /* Set HW part number and length */ 632*9e39c5baSBill Taylor init_info.tf_pn_len = state->ts_hca_pn_len; 633*9e39c5baSBill Taylor if (state->ts_hca_pn_len != 0) { 634*9e39c5baSBill Taylor (void) memcpy(init_info.tf_hwpn, state->ts_hca_pn, 635*9e39c5baSBill Taylor state->ts_hca_pn_len); 636*9e39c5baSBill Taylor } 637*9e39c5baSBill Taylor 638*9e39c5baSBill Taylor /* Copy ioctl results back to userland */ 639*9e39c5baSBill Taylor if (ddi_copyout(&init_info, (void *)arg, 640*9e39c5baSBill Taylor sizeof (tavor_flash_init_ioctl_t), mode) != 0) { 641*9e39c5baSBill Taylor 642*9e39c5baSBill Taylor tavor_ioctl_flash_cleanup_nolock(state); 643*9e39c5baSBill Taylor 644*9e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock); 645*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_flash_init_copyout_fail, 646*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 647*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_flash_init); 648*9e39c5baSBill Taylor return (EFAULT); 649*9e39c5baSBill Taylor } 650*9e39c5baSBill Taylor 651*9e39c5baSBill Taylor /* Set flash state to started */ 652*9e39c5baSBill Taylor state->ts_fw_flashstarted = 1; 653*9e39c5baSBill Taylor state->ts_fw_flashdev = dev; 654*9e39c5baSBill Taylor 655*9e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock); 656*9e39c5baSBill Taylor 657*9e39c5baSBill Taylor /* 658*9e39c5baSBill Taylor * If "flash init" is successful, add an "on close" callback to the 659*9e39c5baSBill Taylor * current dev node to ensure that "flash fini" gets called later 660*9e39c5baSBill Taylor * even if the userland process prematurely exits. 661*9e39c5baSBill Taylor */ 662*9e39c5baSBill Taylor ret = tavor_umap_db_set_onclose_cb(dev, 663*9e39c5baSBill Taylor TAVOR_ONCLOSE_FLASH_INPROGRESS, 664*9e39c5baSBill Taylor (void (*)(void *))tavor_ioctl_flash_cleanup, state); 665*9e39c5baSBill Taylor if (ret != DDI_SUCCESS) { 666*9e39c5baSBill Taylor (void) tavor_ioctl_flash_fini(state, dev); 667*9e39c5baSBill Taylor 668*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_flash_init_set_cb_fail, 669*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 670*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_flash_init); 671*9e39c5baSBill Taylor return (EFAULT); 672*9e39c5baSBill Taylor } 673*9e39c5baSBill Taylor 674*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_flash_init); 675*9e39c5baSBill Taylor return (0); 676*9e39c5baSBill Taylor } 677*9e39c5baSBill Taylor 678*9e39c5baSBill Taylor /* 679*9e39c5baSBill Taylor * tavor_ioctl_flash_fini() 680*9e39c5baSBill Taylor */ 681*9e39c5baSBill Taylor static int 682*9e39c5baSBill Taylor tavor_ioctl_flash_fini(tavor_state_t *state, dev_t dev) 683*9e39c5baSBill Taylor { 684*9e39c5baSBill Taylor int ret; 685*9e39c5baSBill Taylor 686*9e39c5baSBill Taylor TAVOR_TNF_ENTER(tavor_ioctl_flash_fini); 687*9e39c5baSBill Taylor 688*9e39c5baSBill Taylor /* 689*9e39c5baSBill Taylor * Check that flash init ioctl has been called first. And check 690*9e39c5baSBill Taylor * that the same dev_t that called init is the one calling fini now. 691*9e39c5baSBill Taylor */ 692*9e39c5baSBill Taylor mutex_enter(&state->ts_fw_flashlock); 693*9e39c5baSBill Taylor if ((state->ts_fw_flashdev != dev) || 694*9e39c5baSBill Taylor (state->ts_fw_flashstarted == 0)) { 695*9e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock); 696*9e39c5baSBill Taylor TNF_PROBE_0(tavor_flash_bad_state, TAVOR_TNF_ERROR, ""); 697*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_flash_fini); 698*9e39c5baSBill Taylor return (EIO); 699*9e39c5baSBill Taylor } 700*9e39c5baSBill Taylor 701*9e39c5baSBill Taylor tavor_ioctl_flash_cleanup_nolock(state); 702*9e39c5baSBill Taylor 703*9e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock); 704*9e39c5baSBill Taylor 705*9e39c5baSBill Taylor /* 706*9e39c5baSBill Taylor * If "flash fini" is successful, remove the "on close" callback 707*9e39c5baSBill Taylor * that was setup during "flash init". 708*9e39c5baSBill Taylor */ 709*9e39c5baSBill Taylor ret = tavor_umap_db_clear_onclose_cb(dev, 710*9e39c5baSBill Taylor TAVOR_ONCLOSE_FLASH_INPROGRESS); 711*9e39c5baSBill Taylor if (ret != DDI_SUCCESS) { 712*9e39c5baSBill Taylor TNF_PROBE_0(tavor_flash_fini_clear_cb_fail, TAVOR_TNF_ERROR, 713*9e39c5baSBill Taylor ""); 714*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_flash_fini); 715*9e39c5baSBill Taylor return (EFAULT); 716*9e39c5baSBill Taylor } 717*9e39c5baSBill Taylor 718*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_flash_fini); 719*9e39c5baSBill Taylor return (0); 720*9e39c5baSBill Taylor } 721*9e39c5baSBill Taylor 722*9e39c5baSBill Taylor 723*9e39c5baSBill Taylor /* 724*9e39c5baSBill Taylor * tavor_ioctl_flash_cleanup() 725*9e39c5baSBill Taylor */ 726*9e39c5baSBill Taylor static void 727*9e39c5baSBill Taylor tavor_ioctl_flash_cleanup(tavor_state_t *state) 728*9e39c5baSBill Taylor { 729*9e39c5baSBill Taylor TAVOR_TNF_ENTER(tavor_ioctl_flash_cleanup); 730*9e39c5baSBill Taylor 731*9e39c5baSBill Taylor mutex_enter(&state->ts_fw_flashlock); 732*9e39c5baSBill Taylor tavor_ioctl_flash_cleanup_nolock(state); 733*9e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock); 734*9e39c5baSBill Taylor 735*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_flash_cleanup); 736*9e39c5baSBill Taylor } 737*9e39c5baSBill Taylor 738*9e39c5baSBill Taylor 739*9e39c5baSBill Taylor /* 740*9e39c5baSBill Taylor * tavor_ioctl_flash_cleanup_nolock() 741*9e39c5baSBill Taylor */ 742*9e39c5baSBill Taylor static void 743*9e39c5baSBill Taylor tavor_ioctl_flash_cleanup_nolock(tavor_state_t *state) 744*9e39c5baSBill Taylor { 745*9e39c5baSBill Taylor TAVOR_TNF_ENTER(tavor_ioctl_flash_cleanup_nolock); 746*9e39c5baSBill Taylor 747*9e39c5baSBill Taylor ASSERT(MUTEX_HELD(&state->ts_fw_flashlock)); 748*9e39c5baSBill Taylor 749*9e39c5baSBill Taylor /* free flash mem */ 750*9e39c5baSBill Taylor kmem_free(state->ts_fw_sector, 1 << state->ts_fw_log_sector_sz); 751*9e39c5baSBill Taylor 752*9e39c5baSBill Taylor /* Fini the Flash */ 753*9e39c5baSBill Taylor tavor_flash_fini(state); 754*9e39c5baSBill Taylor 755*9e39c5baSBill Taylor /* Set flash state to fini */ 756*9e39c5baSBill Taylor state->ts_fw_flashstarted = 0; 757*9e39c5baSBill Taylor state->ts_fw_flashdev = 0; 758*9e39c5baSBill Taylor 759*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_flash_cleanup_nolock); 760*9e39c5baSBill Taylor } 761*9e39c5baSBill Taylor 762*9e39c5baSBill Taylor 763*9e39c5baSBill Taylor /* 764*9e39c5baSBill Taylor * tavor_ioctl_info() 765*9e39c5baSBill Taylor */ 766*9e39c5baSBill Taylor static int 767*9e39c5baSBill Taylor tavor_ioctl_info(tavor_state_t *state, dev_t dev, intptr_t arg, int mode) 768*9e39c5baSBill Taylor { 769*9e39c5baSBill Taylor tavor_info_ioctl_t info; 770*9e39c5baSBill Taylor tavor_flash_init_ioctl_t init_info; 771*9e39c5baSBill Taylor 772*9e39c5baSBill Taylor TAVOR_TNF_ENTER(tavor_ioctl_info); 773*9e39c5baSBill Taylor 774*9e39c5baSBill Taylor /* 775*9e39c5baSBill Taylor * Access to Tavor VTS ioctls is not allowed in "maintenance mode". 776*9e39c5baSBill Taylor */ 777*9e39c5baSBill Taylor if (state->ts_operational_mode == TAVOR_MAINTENANCE_MODE) { 778*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_info_maintenance_mode_fail, 779*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 780*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_info); 781*9e39c5baSBill Taylor return (EFAULT); 782*9e39c5baSBill Taylor } 783*9e39c5baSBill Taylor 784*9e39c5baSBill Taylor /* copyin the user struct to kernel */ 785*9e39c5baSBill Taylor if (ddi_copyin((void *)arg, &info, sizeof (tavor_info_ioctl_t), 786*9e39c5baSBill Taylor mode) != 0) { 787*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_info_copyin_fail, TAVOR_TNF_ERROR, ""); 788*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_info); 789*9e39c5baSBill Taylor return (EFAULT); 790*9e39c5baSBill Taylor } 791*9e39c5baSBill Taylor 792*9e39c5baSBill Taylor /* 793*9e39c5baSBill Taylor * Check ioctl revision 794*9e39c5baSBill Taylor */ 795*9e39c5baSBill Taylor if (info.ti_revision != TAVOR_VTS_IOCTL_REVISION) { 796*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_info_bad_rev, TAVOR_TNF_ERROR, ""); 797*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_info); 798*9e39c5baSBill Taylor return (EINVAL); 799*9e39c5baSBill Taylor } 800*9e39c5baSBill Taylor 801*9e39c5baSBill Taylor /* 802*9e39c5baSBill Taylor * If the 'fw_device_sz' has not been initialized yet, we initialize it 803*9e39c5baSBill Taylor * here. This is done by leveraging the 804*9e39c5baSBill Taylor * tavor_ioctl_flash_init()/fini() calls. We also hold our own mutex 805*9e39c5baSBill Taylor * around this operation in case we have multiple VTS threads in 806*9e39c5baSBill Taylor * process at the same time. 807*9e39c5baSBill Taylor */ 808*9e39c5baSBill Taylor mutex_enter(&state->ts_info_lock); 809*9e39c5baSBill Taylor if (state->ts_fw_device_sz == 0) { 810*9e39c5baSBill Taylor if (tavor_ioctl_flash_init(state, dev, (intptr_t)&init_info, 811*9e39c5baSBill Taylor (FKIOCTL | mode)) != 0) { 812*9e39c5baSBill Taylor mutex_exit(&state->ts_info_lock); 813*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_info_flash_init_fail, 814*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 815*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_info); 816*9e39c5baSBill Taylor return (EFAULT); 817*9e39c5baSBill Taylor } 818*9e39c5baSBill Taylor (void) tavor_ioctl_flash_fini(state, dev); 819*9e39c5baSBill Taylor } 820*9e39c5baSBill Taylor mutex_exit(&state->ts_info_lock); 821*9e39c5baSBill Taylor 822*9e39c5baSBill Taylor info.ti_hw_rev = state->ts_adapter.rev_id; 823*9e39c5baSBill Taylor info.ti_flash_sz = state->ts_fw_device_sz; 824*9e39c5baSBill Taylor info.ti_fw_rev.tfi_maj = state->ts_fw.fw_rev_major; 825*9e39c5baSBill Taylor info.ti_fw_rev.tfi_min = state->ts_fw.fw_rev_minor; 826*9e39c5baSBill Taylor info.ti_fw_rev.tfi_sub = state->ts_fw.fw_rev_subminor; 827*9e39c5baSBill Taylor info.ti_mem_start_offset = 0; 828*9e39c5baSBill Taylor info.ti_mem_end_offset = state->ts_ddr.ddr_endaddr - 829*9e39c5baSBill Taylor state->ts_ddr.ddr_baseaddr; 830*9e39c5baSBill Taylor 831*9e39c5baSBill Taylor /* Copy ioctl results back to user struct */ 832*9e39c5baSBill Taylor if (ddi_copyout(&info, (void *)arg, sizeof (tavor_info_ioctl_t), 833*9e39c5baSBill Taylor mode) != 0) { 834*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_info_copyout_fail, TAVOR_TNF_ERROR, ""); 835*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_info); 836*9e39c5baSBill Taylor return (EFAULT); 837*9e39c5baSBill Taylor } 838*9e39c5baSBill Taylor 839*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_info); 840*9e39c5baSBill Taylor return (0); 841*9e39c5baSBill Taylor } 842*9e39c5baSBill Taylor 843*9e39c5baSBill Taylor /* 844*9e39c5baSBill Taylor * tavor_ioctl_ports() 845*9e39c5baSBill Taylor */ 846*9e39c5baSBill Taylor static int 847*9e39c5baSBill Taylor tavor_ioctl_ports(tavor_state_t *state, intptr_t arg, int mode) 848*9e39c5baSBill Taylor { 849*9e39c5baSBill Taylor tavor_ports_ioctl_t info; 850*9e39c5baSBill Taylor tavor_stat_port_ioctl_t portstat; 851*9e39c5baSBill Taylor ibt_hca_portinfo_t pi; 852*9e39c5baSBill Taylor uint_t tbl_size; 853*9e39c5baSBill Taylor ib_gid_t *sgid_tbl; 854*9e39c5baSBill Taylor ib_pkey_t *pkey_tbl; 855*9e39c5baSBill Taylor int i; 856*9e39c5baSBill Taylor 857*9e39c5baSBill Taylor TAVOR_TNF_ENTER(tavor_ioctl_ports); 858*9e39c5baSBill Taylor 859*9e39c5baSBill Taylor /* 860*9e39c5baSBill Taylor * Access to Tavor VTS ioctls is not allowed in "maintenance mode". 861*9e39c5baSBill Taylor */ 862*9e39c5baSBill Taylor if (state->ts_operational_mode == TAVOR_MAINTENANCE_MODE) { 863*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_ports_maintenance_mode_fail, 864*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 865*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_ports); 866*9e39c5baSBill Taylor return (EFAULT); 867*9e39c5baSBill Taylor } 868*9e39c5baSBill Taylor 869*9e39c5baSBill Taylor /* copyin the user struct to kernel */ 870*9e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL 871*9e39c5baSBill Taylor if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 872*9e39c5baSBill Taylor tavor_ports_ioctl32_t info32; 873*9e39c5baSBill Taylor 874*9e39c5baSBill Taylor if (ddi_copyin((void *)arg, &info32, 875*9e39c5baSBill Taylor sizeof (tavor_ports_ioctl32_t), mode) != 0) { 876*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_ports_copyin_fail, 877*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 878*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_ports); 879*9e39c5baSBill Taylor return (EFAULT); 880*9e39c5baSBill Taylor } 881*9e39c5baSBill Taylor info.tp_revision = info32.tp_revision; 882*9e39c5baSBill Taylor info.tp_ports = 883*9e39c5baSBill Taylor (tavor_stat_port_ioctl_t *)(uintptr_t)info32.tp_ports; 884*9e39c5baSBill Taylor info.tp_num_ports = info32.tp_num_ports; 885*9e39c5baSBill Taylor 886*9e39c5baSBill Taylor } else 887*9e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */ 888*9e39c5baSBill Taylor if (ddi_copyin((void *)arg, &info, sizeof (tavor_ports_ioctl_t), 889*9e39c5baSBill Taylor mode) != 0) { 890*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_ports_copyin_fail, TAVOR_TNF_ERROR, ""); 891*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_ports); 892*9e39c5baSBill Taylor return (EFAULT); 893*9e39c5baSBill Taylor } 894*9e39c5baSBill Taylor 895*9e39c5baSBill Taylor /* 896*9e39c5baSBill Taylor * Check ioctl revision 897*9e39c5baSBill Taylor */ 898*9e39c5baSBill Taylor if (info.tp_revision != TAVOR_VTS_IOCTL_REVISION) { 899*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_ports_bad_rev, TAVOR_TNF_ERROR, ""); 900*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_ports); 901*9e39c5baSBill Taylor return (EINVAL); 902*9e39c5baSBill Taylor } 903*9e39c5baSBill Taylor 904*9e39c5baSBill Taylor /* Allocate space for temporary GID table/PKey table */ 905*9e39c5baSBill Taylor tbl_size = (1 << state->ts_cfg_profile->cp_log_max_gidtbl); 906*9e39c5baSBill Taylor sgid_tbl = (ib_gid_t *)kmem_zalloc(tbl_size * sizeof (ib_gid_t), 907*9e39c5baSBill Taylor KM_SLEEP); 908*9e39c5baSBill Taylor tbl_size = (1 << state->ts_cfg_profile->cp_log_max_pkeytbl); 909*9e39c5baSBill Taylor pkey_tbl = (ib_pkey_t *)kmem_zalloc(tbl_size * sizeof (ib_pkey_t), 910*9e39c5baSBill Taylor KM_SLEEP); 911*9e39c5baSBill Taylor 912*9e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*sgid_tbl, *pkey_tbl)) 913*9e39c5baSBill Taylor 914*9e39c5baSBill Taylor /* 915*9e39c5baSBill Taylor * Setup the number of ports, then loop through all ports and 916*9e39c5baSBill Taylor * query properties of each. 917*9e39c5baSBill Taylor */ 918*9e39c5baSBill Taylor info.tp_num_ports = (uint8_t)state->ts_cfg_profile->cp_num_ports; 919*9e39c5baSBill Taylor for (i = 0; i < info.tp_num_ports; i++) { 920*9e39c5baSBill Taylor /* 921*9e39c5baSBill Taylor * Get portstate information from the device. If 922*9e39c5baSBill Taylor * tavor_port_query() fails, leave zeroes in user 923*9e39c5baSBill Taylor * struct port entry and continue. 924*9e39c5baSBill Taylor */ 925*9e39c5baSBill Taylor bzero(&pi, sizeof (ibt_hca_portinfo_t)); 926*9e39c5baSBill Taylor pi.p_sgid_tbl = sgid_tbl; 927*9e39c5baSBill Taylor pi.p_pkey_tbl = pkey_tbl; 928*9e39c5baSBill Taylor if (tavor_port_query(state, i + 1, &pi) != 0) { 929*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_ports_query_failed, 930*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 931*9e39c5baSBill Taylor } 932*9e39c5baSBill Taylor 933*9e39c5baSBill Taylor portstat.tsp_port_num = pi.p_port_num; 934*9e39c5baSBill Taylor portstat.tsp_state = pi.p_linkstate; 935*9e39c5baSBill Taylor portstat.tsp_guid = pi.p_sgid_tbl[0].gid_guid; 936*9e39c5baSBill Taylor 937*9e39c5baSBill Taylor /* 938*9e39c5baSBill Taylor * Copy queried port results back to user struct. If 939*9e39c5baSBill Taylor * this fails, then break out of loop, attempt to copy 940*9e39c5baSBill Taylor * out remaining info to user struct, and return (without 941*9e39c5baSBill Taylor * error). 942*9e39c5baSBill Taylor */ 943*9e39c5baSBill Taylor if (ddi_copyout(&portstat, 944*9e39c5baSBill Taylor &(((tavor_stat_port_ioctl_t *)info.tp_ports)[i]), 945*9e39c5baSBill Taylor sizeof (tavor_stat_port_ioctl_t), mode) != 0) { 946*9e39c5baSBill Taylor break; 947*9e39c5baSBill Taylor } 948*9e39c5baSBill Taylor } 949*9e39c5baSBill Taylor 950*9e39c5baSBill Taylor /* Free the temporary space used for GID table/PKey table */ 951*9e39c5baSBill Taylor tbl_size = (1 << state->ts_cfg_profile->cp_log_max_gidtbl); 952*9e39c5baSBill Taylor kmem_free(sgid_tbl, tbl_size * sizeof (ib_gid_t)); 953*9e39c5baSBill Taylor tbl_size = (1 << state->ts_cfg_profile->cp_log_max_pkeytbl); 954*9e39c5baSBill Taylor kmem_free(pkey_tbl, tbl_size * sizeof (ib_pkey_t)); 955*9e39c5baSBill Taylor 956*9e39c5baSBill Taylor /* Copy ioctl results back to user struct */ 957*9e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL 958*9e39c5baSBill Taylor if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 959*9e39c5baSBill Taylor tavor_ports_ioctl32_t info32; 960*9e39c5baSBill Taylor 961*9e39c5baSBill Taylor info32.tp_revision = info.tp_revision; 962*9e39c5baSBill Taylor info32.tp_ports = (caddr32_t)(uintptr_t)info.tp_ports; 963*9e39c5baSBill Taylor info32.tp_num_ports = info.tp_num_ports; 964*9e39c5baSBill Taylor 965*9e39c5baSBill Taylor if (ddi_copyout(&info32, (void *)arg, 966*9e39c5baSBill Taylor sizeof (tavor_ports_ioctl32_t), mode) != 0) { 967*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_ports_copyout_fail, 968*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 969*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_ports); 970*9e39c5baSBill Taylor return (EFAULT); 971*9e39c5baSBill Taylor } 972*9e39c5baSBill Taylor } else 973*9e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */ 974*9e39c5baSBill Taylor if (ddi_copyout(&info, (void *)arg, sizeof (tavor_ports_ioctl_t), 975*9e39c5baSBill Taylor mode) != 0) { 976*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_ports_copyout_fail, 977*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 978*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_ports); 979*9e39c5baSBill Taylor return (EFAULT); 980*9e39c5baSBill Taylor } 981*9e39c5baSBill Taylor 982*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_ports); 983*9e39c5baSBill Taylor return (0); 984*9e39c5baSBill Taylor } 985*9e39c5baSBill Taylor 986*9e39c5baSBill Taylor /* 987*9e39c5baSBill Taylor * tavor_ioctl_loopback() 988*9e39c5baSBill Taylor */ 989*9e39c5baSBill Taylor static int 990*9e39c5baSBill Taylor tavor_ioctl_loopback(tavor_state_t *state, intptr_t arg, int mode) 991*9e39c5baSBill Taylor { 992*9e39c5baSBill Taylor tavor_loopback_ioctl_t lb; 993*9e39c5baSBill Taylor tavor_loopback_state_t lstate; 994*9e39c5baSBill Taylor ibt_hca_portinfo_t pi; 995*9e39c5baSBill Taylor uint_t tbl_size, loopmax, max_usec; 996*9e39c5baSBill Taylor ib_gid_t *sgid_tbl; 997*9e39c5baSBill Taylor ib_pkey_t *pkey_tbl; 998*9e39c5baSBill Taylor int j, iter, ret; 999*9e39c5baSBill Taylor 1000*9e39c5baSBill Taylor TAVOR_TNF_ENTER(tavor_ioctl_loopback); 1001*9e39c5baSBill Taylor 1002*9e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(lstate)) 1003*9e39c5baSBill Taylor 1004*9e39c5baSBill Taylor /* 1005*9e39c5baSBill Taylor * Access to Tavor VTS ioctls is not allowed in "maintenance mode". 1006*9e39c5baSBill Taylor */ 1007*9e39c5baSBill Taylor if (state->ts_operational_mode == TAVOR_MAINTENANCE_MODE) { 1008*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_loopback_maintenance_mode_fail, 1009*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 1010*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_loopback); 1011*9e39c5baSBill Taylor return (EFAULT); 1012*9e39c5baSBill Taylor } 1013*9e39c5baSBill Taylor 1014*9e39c5baSBill Taylor /* copyin the user struct to kernel */ 1015*9e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL 1016*9e39c5baSBill Taylor if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 1017*9e39c5baSBill Taylor tavor_loopback_ioctl32_t lb32; 1018*9e39c5baSBill Taylor 1019*9e39c5baSBill Taylor if (ddi_copyin((void *)arg, &lb32, 1020*9e39c5baSBill Taylor sizeof (tavor_loopback_ioctl32_t), mode) != 0) { 1021*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_loopback_copyin_fail, 1022*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 1023*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_loopback); 1024*9e39c5baSBill Taylor return (EFAULT); 1025*9e39c5baSBill Taylor } 1026*9e39c5baSBill Taylor lb.tlb_revision = lb32.tlb_revision; 1027*9e39c5baSBill Taylor lb.tlb_send_buf = (caddr_t)(uintptr_t)lb32.tlb_send_buf; 1028*9e39c5baSBill Taylor lb.tlb_fail_buf = (caddr_t)(uintptr_t)lb32.tlb_fail_buf; 1029*9e39c5baSBill Taylor lb.tlb_buf_sz = lb32.tlb_buf_sz; 1030*9e39c5baSBill Taylor lb.tlb_num_iter = lb32.tlb_num_iter; 1031*9e39c5baSBill Taylor lb.tlb_pass_done = lb32.tlb_pass_done; 1032*9e39c5baSBill Taylor lb.tlb_timeout = lb32.tlb_timeout; 1033*9e39c5baSBill Taylor lb.tlb_error_type = lb32.tlb_error_type; 1034*9e39c5baSBill Taylor lb.tlb_port_num = lb32.tlb_port_num; 1035*9e39c5baSBill Taylor lb.tlb_num_retry = lb32.tlb_num_retry; 1036*9e39c5baSBill Taylor } else 1037*9e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */ 1038*9e39c5baSBill Taylor if (ddi_copyin((void *)arg, &lb, sizeof (tavor_loopback_ioctl_t), 1039*9e39c5baSBill Taylor mode) != 0) { 1040*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_loopback_copyin_fail, 1041*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 1042*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_loopback); 1043*9e39c5baSBill Taylor return (EFAULT); 1044*9e39c5baSBill Taylor } 1045*9e39c5baSBill Taylor 1046*9e39c5baSBill Taylor /* Initialize the internal loopback test state structure */ 1047*9e39c5baSBill Taylor bzero(&lstate, sizeof (tavor_loopback_state_t)); 1048*9e39c5baSBill Taylor 1049*9e39c5baSBill Taylor /* 1050*9e39c5baSBill Taylor * Check ioctl revision 1051*9e39c5baSBill Taylor */ 1052*9e39c5baSBill Taylor if (lb.tlb_revision != TAVOR_VTS_IOCTL_REVISION) { 1053*9e39c5baSBill Taylor lb.tlb_error_type = TAVOR_LOOPBACK_INVALID_REVISION; 1054*9e39c5baSBill Taylor (void) tavor_loopback_copyout(&lb, arg, mode); 1055*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_loopback_bad_rev, 1056*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 1057*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_loopback); 1058*9e39c5baSBill Taylor return (EINVAL); 1059*9e39c5baSBill Taylor } 1060*9e39c5baSBill Taylor 1061*9e39c5baSBill Taylor /* Validate that specified port number is legal */ 1062*9e39c5baSBill Taylor if (!tavor_portnum_is_valid(state, lb.tlb_port_num)) { 1063*9e39c5baSBill Taylor lb.tlb_error_type = TAVOR_LOOPBACK_INVALID_PORT; 1064*9e39c5baSBill Taylor (void) tavor_loopback_copyout(&lb, arg, mode); 1065*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_loopback_inv_port, 1066*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 1067*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_loopback); 1068*9e39c5baSBill Taylor return (EINVAL); 1069*9e39c5baSBill Taylor } 1070*9e39c5baSBill Taylor 1071*9e39c5baSBill Taylor /* Allocate space for temporary GID table/PKey table */ 1072*9e39c5baSBill Taylor tbl_size = (1 << state->ts_cfg_profile->cp_log_max_gidtbl); 1073*9e39c5baSBill Taylor sgid_tbl = (ib_gid_t *)kmem_zalloc(tbl_size * sizeof (ib_gid_t), 1074*9e39c5baSBill Taylor KM_SLEEP); 1075*9e39c5baSBill Taylor tbl_size = (1 << state->ts_cfg_profile->cp_log_max_pkeytbl); 1076*9e39c5baSBill Taylor pkey_tbl = (ib_pkey_t *)kmem_zalloc(tbl_size * sizeof (ib_pkey_t), 1077*9e39c5baSBill Taylor KM_SLEEP); 1078*9e39c5baSBill Taylor 1079*9e39c5baSBill Taylor /* 1080*9e39c5baSBill Taylor * Get portstate information from specific port on device 1081*9e39c5baSBill Taylor */ 1082*9e39c5baSBill Taylor bzero(&pi, sizeof (ibt_hca_portinfo_t)); 1083*9e39c5baSBill Taylor pi.p_sgid_tbl = sgid_tbl; 1084*9e39c5baSBill Taylor pi.p_pkey_tbl = pkey_tbl; 1085*9e39c5baSBill Taylor if (tavor_port_query(state, lb.tlb_port_num, &pi) != 0) { 1086*9e39c5baSBill Taylor /* Free the temporary space used for GID table/PKey table */ 1087*9e39c5baSBill Taylor tbl_size = (1 << state->ts_cfg_profile->cp_log_max_gidtbl); 1088*9e39c5baSBill Taylor kmem_free(sgid_tbl, tbl_size * sizeof (ib_gid_t)); 1089*9e39c5baSBill Taylor tbl_size = (1 << state->ts_cfg_profile->cp_log_max_pkeytbl); 1090*9e39c5baSBill Taylor kmem_free(pkey_tbl, tbl_size * sizeof (ib_pkey_t)); 1091*9e39c5baSBill Taylor 1092*9e39c5baSBill Taylor lb.tlb_error_type = TAVOR_LOOPBACK_INVALID_PORT; 1093*9e39c5baSBill Taylor (void) tavor_loopback_copyout(&lb, arg, mode); 1094*9e39c5baSBill Taylor tavor_loopback_free_state(&lstate); 1095*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_loopback_bad_port, 1096*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 1097*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_loopback); 1098*9e39c5baSBill Taylor return (EINVAL); 1099*9e39c5baSBill Taylor } 1100*9e39c5baSBill Taylor 1101*9e39c5baSBill Taylor lstate.tls_port = pi.p_port_num; 1102*9e39c5baSBill Taylor lstate.tls_lid = pi.p_base_lid; 1103*9e39c5baSBill Taylor lstate.tls_pkey_ix = (pi.p_linkstate == TAVOR_PORT_LINK_ACTIVE) ? 1 : 0; 1104*9e39c5baSBill Taylor lstate.tls_state = state; 1105*9e39c5baSBill Taylor lstate.tls_retry = lb.tlb_num_retry; 1106*9e39c5baSBill Taylor 1107*9e39c5baSBill Taylor /* Free the temporary space used for GID table/PKey table */ 1108*9e39c5baSBill Taylor tbl_size = (1 << state->ts_cfg_profile->cp_log_max_gidtbl); 1109*9e39c5baSBill Taylor kmem_free(sgid_tbl, tbl_size * sizeof (ib_gid_t)); 1110*9e39c5baSBill Taylor tbl_size = (1 << state->ts_cfg_profile->cp_log_max_pkeytbl); 1111*9e39c5baSBill Taylor kmem_free(pkey_tbl, tbl_size * sizeof (ib_pkey_t)); 1112*9e39c5baSBill Taylor 1113*9e39c5baSBill Taylor /* 1114*9e39c5baSBill Taylor * Compute the timeout duration in usec per the formula: 1115*9e39c5baSBill Taylor * to_usec_per_retry = 4.096us * (2 ^ supplied_timeout) 1116*9e39c5baSBill Taylor * (plus we add a little fudge-factor here too) 1117*9e39c5baSBill Taylor */ 1118*9e39c5baSBill Taylor lstate.tls_timeout = lb.tlb_timeout; 1119*9e39c5baSBill Taylor max_usec = (4096 * (1 << lstate.tls_timeout)) / 1000; 1120*9e39c5baSBill Taylor max_usec = max_usec * (lstate.tls_retry + 1); 1121*9e39c5baSBill Taylor max_usec = max_usec + 10000; 1122*9e39c5baSBill Taylor 1123*9e39c5baSBill Taylor /* 1124*9e39c5baSBill Taylor * Determine how many times we should loop before declaring a 1125*9e39c5baSBill Taylor * timeout failure. 1126*9e39c5baSBill Taylor */ 1127*9e39c5baSBill Taylor loopmax = max_usec/TAVOR_VTS_LOOPBACK_MIN_WAIT_DUR; 1128*9e39c5baSBill Taylor if ((max_usec % TAVOR_VTS_LOOPBACK_MIN_WAIT_DUR) != 0) { 1129*9e39c5baSBill Taylor loopmax++; 1130*9e39c5baSBill Taylor } 1131*9e39c5baSBill Taylor 1132*9e39c5baSBill Taylor if (lb.tlb_send_buf == NULL || lb.tlb_buf_sz == 0) { 1133*9e39c5baSBill Taylor lb.tlb_error_type = TAVOR_LOOPBACK_SEND_BUF_INVALID; 1134*9e39c5baSBill Taylor (void) tavor_loopback_copyout(&lb, arg, mode); 1135*9e39c5baSBill Taylor tavor_loopback_free_state(&lstate); 1136*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_loopback_buf_null, 1137*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 1138*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_loopback); 1139*9e39c5baSBill Taylor return (EINVAL); 1140*9e39c5baSBill Taylor } 1141*9e39c5baSBill Taylor 1142*9e39c5baSBill Taylor /* Allocate protection domain (PD) */ 1143*9e39c5baSBill Taylor if (tavor_loopback_init(state, &lstate) != 0) { 1144*9e39c5baSBill Taylor lb.tlb_error_type = lstate.tls_err; 1145*9e39c5baSBill Taylor (void) tavor_loopback_copyout(&lb, arg, mode); 1146*9e39c5baSBill Taylor tavor_loopback_free_state(&lstate); 1147*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_loopback); 1148*9e39c5baSBill Taylor return (EFAULT); 1149*9e39c5baSBill Taylor } 1150*9e39c5baSBill Taylor 1151*9e39c5baSBill Taylor /* Allocate and register a TX buffer */ 1152*9e39c5baSBill Taylor if (tavor_loopback_alloc_mem(&lstate, &lstate.tls_tx, 1153*9e39c5baSBill Taylor lb.tlb_buf_sz) != 0) { 1154*9e39c5baSBill Taylor lb.tlb_error_type = 1155*9e39c5baSBill Taylor TAVOR_LOOPBACK_SEND_BUF_MEM_REGION_ALLOC_FAIL; 1156*9e39c5baSBill Taylor (void) tavor_loopback_copyout(&lb, arg, mode); 1157*9e39c5baSBill Taylor tavor_loopback_free_state(&lstate); 1158*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_loopback_txbuf_alloc_fail, 1159*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 1160*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_loopback); 1161*9e39c5baSBill Taylor return (EFAULT); 1162*9e39c5baSBill Taylor } 1163*9e39c5baSBill Taylor 1164*9e39c5baSBill Taylor /* Allocate and register an RX buffer */ 1165*9e39c5baSBill Taylor if (tavor_loopback_alloc_mem(&lstate, &lstate.tls_rx, 1166*9e39c5baSBill Taylor lb.tlb_buf_sz) != 0) { 1167*9e39c5baSBill Taylor lb.tlb_error_type = 1168*9e39c5baSBill Taylor TAVOR_LOOPBACK_RECV_BUF_MEM_REGION_ALLOC_FAIL; 1169*9e39c5baSBill Taylor (void) tavor_loopback_copyout(&lb, arg, mode); 1170*9e39c5baSBill Taylor tavor_loopback_free_state(&lstate); 1171*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_loopback_rxbuf_alloc_fail, 1172*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 1173*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_loopback); 1174*9e39c5baSBill Taylor return (EFAULT); 1175*9e39c5baSBill Taylor } 1176*9e39c5baSBill Taylor 1177*9e39c5baSBill Taylor /* Copy in the transmit buffer data */ 1178*9e39c5baSBill Taylor if (ddi_copyin((void *)lb.tlb_send_buf, lstate.tls_tx.tlc_buf, 1179*9e39c5baSBill Taylor lb.tlb_buf_sz, mode) != 0) { 1180*9e39c5baSBill Taylor lb.tlb_error_type = TAVOR_LOOPBACK_SEND_BUF_COPY_FAIL; 1181*9e39c5baSBill Taylor (void) tavor_loopback_copyout(&lb, arg, mode); 1182*9e39c5baSBill Taylor tavor_loopback_free_state(&lstate); 1183*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_loopback_tx_copyin_fail, 1184*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 1185*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_loopback); 1186*9e39c5baSBill Taylor return (EFAULT); 1187*9e39c5baSBill Taylor } 1188*9e39c5baSBill Taylor 1189*9e39c5baSBill Taylor /* Allocate the transmit QP and CQs */ 1190*9e39c5baSBill Taylor lstate.tls_err = TAVOR_LOOPBACK_XMIT_SEND_CQ_ALLOC_FAIL; 1191*9e39c5baSBill Taylor if (tavor_loopback_alloc_qps(&lstate, &lstate.tls_tx) != 0) { 1192*9e39c5baSBill Taylor lb.tlb_error_type = lstate.tls_err; 1193*9e39c5baSBill Taylor (void) tavor_loopback_copyout(&lb, arg, mode); 1194*9e39c5baSBill Taylor tavor_loopback_free_state(&lstate); 1195*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_loopback_txqp_alloc_fail, 1196*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 1197*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_loopback); 1198*9e39c5baSBill Taylor return (EFAULT); 1199*9e39c5baSBill Taylor } 1200*9e39c5baSBill Taylor 1201*9e39c5baSBill Taylor /* Allocate the receive QP and CQs */ 1202*9e39c5baSBill Taylor lstate.tls_err = TAVOR_LOOPBACK_RECV_SEND_CQ_ALLOC_FAIL; 1203*9e39c5baSBill Taylor if (tavor_loopback_alloc_qps(&lstate, &lstate.tls_rx) != 0) { 1204*9e39c5baSBill Taylor lb.tlb_error_type = lstate.tls_err; 1205*9e39c5baSBill Taylor (void) tavor_loopback_copyout(&lb, arg, mode); 1206*9e39c5baSBill Taylor tavor_loopback_free_state(&lstate); 1207*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_loopback_rxqp_alloc_fail, 1208*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 1209*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_loopback); 1210*9e39c5baSBill Taylor return (EFAULT); 1211*9e39c5baSBill Taylor } 1212*9e39c5baSBill Taylor 1213*9e39c5baSBill Taylor /* Activate the TX QP (connect to RX QP) */ 1214*9e39c5baSBill Taylor lstate.tls_err = TAVOR_LOOPBACK_XMIT_QP_INIT_FAIL; 1215*9e39c5baSBill Taylor if (tavor_loopback_modify_qp(&lstate, &lstate.tls_tx, 1216*9e39c5baSBill Taylor lstate.tls_rx.tlc_qp_num) != 0) { 1217*9e39c5baSBill Taylor lb.tlb_error_type = lstate.tls_err; 1218*9e39c5baSBill Taylor (void) tavor_loopback_copyout(&lb, arg, mode); 1219*9e39c5baSBill Taylor tavor_loopback_free_state(&lstate); 1220*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_loopback_txqp_init_fail, 1221*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 1222*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_loopback); 1223*9e39c5baSBill Taylor return (EFAULT); 1224*9e39c5baSBill Taylor } 1225*9e39c5baSBill Taylor 1226*9e39c5baSBill Taylor /* Activate the RX QP (connect to TX QP) */ 1227*9e39c5baSBill Taylor lstate.tls_err = TAVOR_LOOPBACK_RECV_QP_INIT_FAIL; 1228*9e39c5baSBill Taylor if (tavor_loopback_modify_qp(&lstate, &lstate.tls_rx, 1229*9e39c5baSBill Taylor lstate.tls_tx.tlc_qp_num) != 0) { 1230*9e39c5baSBill Taylor lb.tlb_error_type = lstate.tls_err; 1231*9e39c5baSBill Taylor (void) tavor_loopback_copyout(&lb, arg, mode); 1232*9e39c5baSBill Taylor tavor_loopback_free_state(&lstate); 1233*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_loopback_rxqp_init_fail, 1234*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 1235*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_loopback); 1236*9e39c5baSBill Taylor return (EFAULT); 1237*9e39c5baSBill Taylor } 1238*9e39c5baSBill Taylor 1239*9e39c5baSBill Taylor /* Run the loopback test (for specified number of iterations) */ 1240*9e39c5baSBill Taylor lb.tlb_pass_done = 0; 1241*9e39c5baSBill Taylor for (iter = 0; iter < lb.tlb_num_iter; iter++) { 1242*9e39c5baSBill Taylor lstate.tls_err = 0; 1243*9e39c5baSBill Taylor bzero(lstate.tls_rx.tlc_buf, lb.tlb_buf_sz); 1244*9e39c5baSBill Taylor 1245*9e39c5baSBill Taylor /* Post RDMA Write work request */ 1246*9e39c5baSBill Taylor if (tavor_loopback_post_send(&lstate, &lstate.tls_tx, 1247*9e39c5baSBill Taylor &lstate.tls_rx) != IBT_SUCCESS) { 1248*9e39c5baSBill Taylor lb.tlb_error_type = TAVOR_LOOPBACK_WQE_POST_FAIL; 1249*9e39c5baSBill Taylor (void) tavor_loopback_copyout(&lb, arg, mode); 1250*9e39c5baSBill Taylor tavor_loopback_free_state(&lstate); 1251*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_loopback_wqe_post_fail, 1252*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 1253*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_loopback); 1254*9e39c5baSBill Taylor return (EFAULT); 1255*9e39c5baSBill Taylor } 1256*9e39c5baSBill Taylor 1257*9e39c5baSBill Taylor /* Poll the TX CQ for a completion every few ticks */ 1258*9e39c5baSBill Taylor for (j = 0; j < loopmax; j++) { 1259*9e39c5baSBill Taylor delay(drv_usectohz(TAVOR_VTS_LOOPBACK_MIN_WAIT_DUR)); 1260*9e39c5baSBill Taylor 1261*9e39c5baSBill Taylor ret = tavor_loopback_poll_cq(&lstate, &lstate.tls_tx); 1262*9e39c5baSBill Taylor if (((ret != IBT_SUCCESS) && (ret != IBT_CQ_EMPTY)) || 1263*9e39c5baSBill Taylor ((ret == IBT_CQ_EMPTY) && (j == loopmax - 1))) { 1264*9e39c5baSBill Taylor lb.tlb_error_type = TAVOR_LOOPBACK_CQ_POLL_FAIL; 1265*9e39c5baSBill Taylor if (ddi_copyout(lstate.tls_rx.tlc_buf, 1266*9e39c5baSBill Taylor lb.tlb_fail_buf, lstate.tls_tx.tlc_buf_sz, 1267*9e39c5baSBill Taylor mode) != 0) { 1268*9e39c5baSBill Taylor TNF_PROBE_0( 1269*9e39c5baSBill Taylor tavor_ioctl_loopback_xfer_co_fail, 1270*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 1271*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_loopback); 1272*9e39c5baSBill Taylor return (EFAULT); 1273*9e39c5baSBill Taylor } 1274*9e39c5baSBill Taylor (void) tavor_loopback_copyout(&lb, arg, mode); 1275*9e39c5baSBill Taylor tavor_loopback_free_state(&lstate); 1276*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_loopback_xfer_fail, 1277*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 1278*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_loopback); 1279*9e39c5baSBill Taylor return (EFAULT); 1280*9e39c5baSBill Taylor } else if (ret == IBT_CQ_EMPTY) { 1281*9e39c5baSBill Taylor continue; 1282*9e39c5baSBill Taylor } 1283*9e39c5baSBill Taylor 1284*9e39c5baSBill Taylor /* Compare the data buffers */ 1285*9e39c5baSBill Taylor if (bcmp(lstate.tls_tx.tlc_buf, lstate.tls_rx.tlc_buf, 1286*9e39c5baSBill Taylor lb.tlb_buf_sz) == 0) { 1287*9e39c5baSBill Taylor break; 1288*9e39c5baSBill Taylor } else { 1289*9e39c5baSBill Taylor lb.tlb_error_type = 1290*9e39c5baSBill Taylor TAVOR_LOOPBACK_SEND_RECV_COMPARE_FAIL; 1291*9e39c5baSBill Taylor if (ddi_copyout(lstate.tls_rx.tlc_buf, 1292*9e39c5baSBill Taylor lb.tlb_fail_buf, lstate.tls_tx.tlc_buf_sz, 1293*9e39c5baSBill Taylor mode) != 0) { 1294*9e39c5baSBill Taylor TNF_PROBE_0( 1295*9e39c5baSBill Taylor tavor_ioctl_loopback_bcmp_co_fail, 1296*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 1297*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_loopback); 1298*9e39c5baSBill Taylor return (EFAULT); 1299*9e39c5baSBill Taylor } 1300*9e39c5baSBill Taylor (void) tavor_loopback_copyout(&lb, arg, mode); 1301*9e39c5baSBill Taylor tavor_loopback_free_state(&lstate); 1302*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_loopback_bcmp_fail, 1303*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 1304*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_loopback); 1305*9e39c5baSBill Taylor return (EFAULT); 1306*9e39c5baSBill Taylor } 1307*9e39c5baSBill Taylor } 1308*9e39c5baSBill Taylor 1309*9e39c5baSBill Taylor lstate.tls_err = TAVOR_LOOPBACK_SUCCESS; 1310*9e39c5baSBill Taylor lb.tlb_pass_done = iter + 1; 1311*9e39c5baSBill Taylor } 1312*9e39c5baSBill Taylor 1313*9e39c5baSBill Taylor lb.tlb_error_type = TAVOR_LOOPBACK_SUCCESS; 1314*9e39c5baSBill Taylor 1315*9e39c5baSBill Taylor /* Copy ioctl results back to user struct */ 1316*9e39c5baSBill Taylor ret = tavor_loopback_copyout(&lb, arg, mode); 1317*9e39c5baSBill Taylor 1318*9e39c5baSBill Taylor /* Free up everything and release all consumed resources */ 1319*9e39c5baSBill Taylor tavor_loopback_free_state(&lstate); 1320*9e39c5baSBill Taylor 1321*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_loopback); 1322*9e39c5baSBill Taylor return (ret); 1323*9e39c5baSBill Taylor } 1324*9e39c5baSBill Taylor 1325*9e39c5baSBill Taylor /* 1326*9e39c5baSBill Taylor * tavor_ioctl_ddr_read() 1327*9e39c5baSBill Taylor */ 1328*9e39c5baSBill Taylor static int 1329*9e39c5baSBill Taylor tavor_ioctl_ddr_read(tavor_state_t *state, intptr_t arg, int mode) 1330*9e39c5baSBill Taylor { 1331*9e39c5baSBill Taylor tavor_ddr_read_ioctl_t rdreg; 1332*9e39c5baSBill Taylor uint32_t *addr; 1333*9e39c5baSBill Taylor uintptr_t baseaddr; 1334*9e39c5baSBill Taylor uint64_t ddr_size; 1335*9e39c5baSBill Taylor 1336*9e39c5baSBill Taylor TAVOR_TNF_ENTER(tavor_ioctl_ddr_read); 1337*9e39c5baSBill Taylor 1338*9e39c5baSBill Taylor /* 1339*9e39c5baSBill Taylor * Access to Tavor VTS ioctls is not allowed in "maintenance mode". 1340*9e39c5baSBill Taylor */ 1341*9e39c5baSBill Taylor if (state->ts_operational_mode == TAVOR_MAINTENANCE_MODE) { 1342*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_ddr_read_maintenance_mode_fail, 1343*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 1344*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_ddr_read); 1345*9e39c5baSBill Taylor return (EFAULT); 1346*9e39c5baSBill Taylor } 1347*9e39c5baSBill Taylor 1348*9e39c5baSBill Taylor /* copyin the user struct to kernel */ 1349*9e39c5baSBill Taylor if (ddi_copyin((void *)arg, &rdreg, sizeof (tavor_ddr_read_ioctl_t), 1350*9e39c5baSBill Taylor mode) != 0) { 1351*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_ddr_read_copyin_fail, 1352*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 1353*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_ddr_read); 1354*9e39c5baSBill Taylor return (EFAULT); 1355*9e39c5baSBill Taylor } 1356*9e39c5baSBill Taylor 1357*9e39c5baSBill Taylor /* 1358*9e39c5baSBill Taylor * Check ioctl revision 1359*9e39c5baSBill Taylor */ 1360*9e39c5baSBill Taylor if (rdreg.tdr_revision != TAVOR_VTS_IOCTL_REVISION) { 1361*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_ddr_read_bad_rev, TAVOR_TNF_ERROR, ""); 1362*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_ddr_read); 1363*9e39c5baSBill Taylor return (EINVAL); 1364*9e39c5baSBill Taylor } 1365*9e39c5baSBill Taylor 1366*9e39c5baSBill Taylor /* 1367*9e39c5baSBill Taylor * Check for valid offset 1368*9e39c5baSBill Taylor */ 1369*9e39c5baSBill Taylor ddr_size = (state->ts_ddr.ddr_endaddr - state->ts_ddr.ddr_baseaddr + 1); 1370*9e39c5baSBill Taylor if ((uint64_t)rdreg.tdr_offset >= ddr_size) { 1371*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_ddr_read_bad_offset, 1372*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 1373*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_ddr_read); 1374*9e39c5baSBill Taylor return (EINVAL); 1375*9e39c5baSBill Taylor } 1376*9e39c5baSBill Taylor 1377*9e39c5baSBill Taylor /* Determine base address for requested register read */ 1378*9e39c5baSBill Taylor baseaddr = (uintptr_t)state->ts_reg_ddr_baseaddr; 1379*9e39c5baSBill Taylor 1380*9e39c5baSBill Taylor /* Ensure that address is properly-aligned */ 1381*9e39c5baSBill Taylor addr = (uint32_t *)((baseaddr + rdreg.tdr_offset) & ~0x3); 1382*9e39c5baSBill Taylor 1383*9e39c5baSBill Taylor /* Read the register pointed to by addr */ 1384*9e39c5baSBill Taylor rdreg.tdr_data = ddi_get32(state->ts_reg_cmdhdl, addr); 1385*9e39c5baSBill Taylor 1386*9e39c5baSBill Taylor /* Copy ioctl results back to user struct */ 1387*9e39c5baSBill Taylor if (ddi_copyout(&rdreg, (void *)arg, sizeof (tavor_ddr_read_ioctl_t), 1388*9e39c5baSBill Taylor mode) != 0) { 1389*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_ddr_read_copyout_fail, 1390*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 1391*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_ddr_read); 1392*9e39c5baSBill Taylor return (EFAULT); 1393*9e39c5baSBill Taylor } 1394*9e39c5baSBill Taylor 1395*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_ddr_read); 1396*9e39c5baSBill Taylor return (0); 1397*9e39c5baSBill Taylor } 1398*9e39c5baSBill Taylor 1399*9e39c5baSBill Taylor 1400*9e39c5baSBill Taylor #ifdef DEBUG 1401*9e39c5baSBill Taylor /* 1402*9e39c5baSBill Taylor * tavor_ioctl_reg_read() 1403*9e39c5baSBill Taylor */ 1404*9e39c5baSBill Taylor static int 1405*9e39c5baSBill Taylor tavor_ioctl_reg_read(tavor_state_t *state, intptr_t arg, int mode) 1406*9e39c5baSBill Taylor { 1407*9e39c5baSBill Taylor tavor_reg_ioctl_t rdreg; 1408*9e39c5baSBill Taylor uint32_t *addr; 1409*9e39c5baSBill Taylor uintptr_t baseaddr; 1410*9e39c5baSBill Taylor int status; 1411*9e39c5baSBill Taylor 1412*9e39c5baSBill Taylor TAVOR_TNF_ENTER(tavor_ioctl_reg_read); 1413*9e39c5baSBill Taylor 1414*9e39c5baSBill Taylor /* 1415*9e39c5baSBill Taylor * Access to Tavor registers is not allowed in "maintenance mode". 1416*9e39c5baSBill Taylor * This is primarily because the device may not have BARs to access 1417*9e39c5baSBill Taylor */ 1418*9e39c5baSBill Taylor if (state->ts_operational_mode == TAVOR_MAINTENANCE_MODE) { 1419*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_reg_read_maintence_mode_fail, 1420*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 1421*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_reg_read); 1422*9e39c5baSBill Taylor return (EFAULT); 1423*9e39c5baSBill Taylor } 1424*9e39c5baSBill Taylor 1425*9e39c5baSBill Taylor /* Copy in the tavor_reg_ioctl_t structure */ 1426*9e39c5baSBill Taylor status = ddi_copyin((void *)arg, &rdreg, sizeof (tavor_reg_ioctl_t), 1427*9e39c5baSBill Taylor mode); 1428*9e39c5baSBill Taylor if (status != 0) { 1429*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_reg_read_copyin_fail, 1430*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 1431*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_reg_read); 1432*9e39c5baSBill Taylor return (EFAULT); 1433*9e39c5baSBill Taylor } 1434*9e39c5baSBill Taylor 1435*9e39c5baSBill Taylor /* Determine base address for requested register set */ 1436*9e39c5baSBill Taylor switch (rdreg.trg_reg_set) { 1437*9e39c5baSBill Taylor case TAVOR_CMD_BAR: 1438*9e39c5baSBill Taylor baseaddr = (uintptr_t)state->ts_reg_cmd_baseaddr; 1439*9e39c5baSBill Taylor break; 1440*9e39c5baSBill Taylor 1441*9e39c5baSBill Taylor case TAVOR_UAR_BAR: 1442*9e39c5baSBill Taylor baseaddr = (uintptr_t)state->ts_reg_uar_baseaddr; 1443*9e39c5baSBill Taylor break; 1444*9e39c5baSBill Taylor 1445*9e39c5baSBill Taylor case TAVOR_DDR_BAR: 1446*9e39c5baSBill Taylor baseaddr = (uintptr_t)state->ts_reg_ddr_baseaddr; 1447*9e39c5baSBill Taylor break; 1448*9e39c5baSBill Taylor 1449*9e39c5baSBill Taylor default: 1450*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_reg_read_invregset_fail, 1451*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 1452*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_reg_read); 1453*9e39c5baSBill Taylor return (EFAULT); 1454*9e39c5baSBill Taylor } 1455*9e39c5baSBill Taylor 1456*9e39c5baSBill Taylor /* Ensure that address is properly-aligned */ 1457*9e39c5baSBill Taylor addr = (uint32_t *)((baseaddr + rdreg.trg_offset) & ~0x3); 1458*9e39c5baSBill Taylor 1459*9e39c5baSBill Taylor /* Read the register pointed to by addr */ 1460*9e39c5baSBill Taylor rdreg.trg_data = ddi_get32(state->ts_reg_cmdhdl, addr); 1461*9e39c5baSBill Taylor 1462*9e39c5baSBill Taylor /* Copy in the result into the tavor_reg_ioctl_t structure */ 1463*9e39c5baSBill Taylor status = ddi_copyout(&rdreg, (void *)arg, sizeof (tavor_reg_ioctl_t), 1464*9e39c5baSBill Taylor mode); 1465*9e39c5baSBill Taylor if (status != 0) { 1466*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_reg_read_copyout_fail, 1467*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 1468*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_reg_read); 1469*9e39c5baSBill Taylor return (EFAULT); 1470*9e39c5baSBill Taylor } 1471*9e39c5baSBill Taylor 1472*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_reg_read); 1473*9e39c5baSBill Taylor return (0); 1474*9e39c5baSBill Taylor } 1475*9e39c5baSBill Taylor 1476*9e39c5baSBill Taylor 1477*9e39c5baSBill Taylor /* 1478*9e39c5baSBill Taylor * tavor_ioctl_reg_write() 1479*9e39c5baSBill Taylor */ 1480*9e39c5baSBill Taylor static int 1481*9e39c5baSBill Taylor tavor_ioctl_reg_write(tavor_state_t *state, intptr_t arg, int mode) 1482*9e39c5baSBill Taylor { 1483*9e39c5baSBill Taylor tavor_reg_ioctl_t wrreg; 1484*9e39c5baSBill Taylor uint32_t *addr; 1485*9e39c5baSBill Taylor uintptr_t baseaddr; 1486*9e39c5baSBill Taylor int status; 1487*9e39c5baSBill Taylor 1488*9e39c5baSBill Taylor TAVOR_TNF_ENTER(tavor_ioctl_reg_write); 1489*9e39c5baSBill Taylor 1490*9e39c5baSBill Taylor /* 1491*9e39c5baSBill Taylor * Access to Tavor registers is not allowed in "maintenance mode". 1492*9e39c5baSBill Taylor * This is primarily because the device may not have BARs to access 1493*9e39c5baSBill Taylor */ 1494*9e39c5baSBill Taylor if (state->ts_operational_mode == TAVOR_MAINTENANCE_MODE) { 1495*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_reg_write_maintence_mode_fail, 1496*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 1497*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_reg_write); 1498*9e39c5baSBill Taylor return (EFAULT); 1499*9e39c5baSBill Taylor } 1500*9e39c5baSBill Taylor 1501*9e39c5baSBill Taylor /* Copy in the tavor_reg_ioctl_t structure */ 1502*9e39c5baSBill Taylor status = ddi_copyin((void *)arg, &wrreg, sizeof (tavor_reg_ioctl_t), 1503*9e39c5baSBill Taylor mode); 1504*9e39c5baSBill Taylor if (status != 0) { 1505*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_reg_write_copyin_fail, 1506*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 1507*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_reg_write); 1508*9e39c5baSBill Taylor return (EFAULT); 1509*9e39c5baSBill Taylor } 1510*9e39c5baSBill Taylor 1511*9e39c5baSBill Taylor /* Determine base address for requested register set */ 1512*9e39c5baSBill Taylor switch (wrreg.trg_reg_set) { 1513*9e39c5baSBill Taylor case TAVOR_CMD_BAR: 1514*9e39c5baSBill Taylor baseaddr = (uintptr_t)state->ts_reg_cmd_baseaddr; 1515*9e39c5baSBill Taylor break; 1516*9e39c5baSBill Taylor 1517*9e39c5baSBill Taylor case TAVOR_UAR_BAR: 1518*9e39c5baSBill Taylor baseaddr = (uintptr_t)state->ts_reg_uar_baseaddr; 1519*9e39c5baSBill Taylor break; 1520*9e39c5baSBill Taylor 1521*9e39c5baSBill Taylor case TAVOR_DDR_BAR: 1522*9e39c5baSBill Taylor baseaddr = (uintptr_t)state->ts_reg_ddr_baseaddr; 1523*9e39c5baSBill Taylor break; 1524*9e39c5baSBill Taylor 1525*9e39c5baSBill Taylor default: 1526*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_reg_write_invregset_fail, 1527*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 1528*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_reg_write); 1529*9e39c5baSBill Taylor return (EFAULT); 1530*9e39c5baSBill Taylor } 1531*9e39c5baSBill Taylor 1532*9e39c5baSBill Taylor /* Ensure that address is properly-aligned */ 1533*9e39c5baSBill Taylor addr = (uint32_t *)((baseaddr + wrreg.trg_offset) & ~0x3); 1534*9e39c5baSBill Taylor 1535*9e39c5baSBill Taylor /* Write the data to the register pointed to by addr */ 1536*9e39c5baSBill Taylor ddi_put32(state->ts_reg_cmdhdl, addr, wrreg.trg_data); 1537*9e39c5baSBill Taylor 1538*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_ioctl_reg_write); 1539*9e39c5baSBill Taylor return (0); 1540*9e39c5baSBill Taylor } 1541*9e39c5baSBill Taylor #endif /* DEBUG */ 1542*9e39c5baSBill Taylor 1543*9e39c5baSBill Taylor /* 1544*9e39c5baSBill Taylor * tavor_flash_reset() 1545*9e39c5baSBill Taylor */ 1546*9e39c5baSBill Taylor static void 1547*9e39c5baSBill Taylor tavor_flash_reset(tavor_state_t *state) 1548*9e39c5baSBill Taylor { 1549*9e39c5baSBill Taylor TAVOR_TNF_ENTER(tavor_flash_reset); 1550*9e39c5baSBill Taylor 1551*9e39c5baSBill Taylor /* 1552*9e39c5baSBill Taylor * Performs a reset to the flash device. After a reset the flash will 1553*9e39c5baSBill Taylor * be operating in normal mode (capable of read/write, etc.). 1554*9e39c5baSBill Taylor */ 1555*9e39c5baSBill Taylor switch (state->ts_fw_cmdset) { 1556*9e39c5baSBill Taylor case TAVOR_FLASH_AMD_CMDSET: 1557*9e39c5baSBill Taylor tavor_flash_write(state, 0x555, TAVOR_HW_FLASH_RESET_AMD); 1558*9e39c5baSBill Taylor break; 1559*9e39c5baSBill Taylor 1560*9e39c5baSBill Taylor case TAVOR_FLASH_INTEL_CMDSET: 1561*9e39c5baSBill Taylor tavor_flash_write(state, 0x555, TAVOR_HW_FLASH_RESET_INTEL); 1562*9e39c5baSBill Taylor break; 1563*9e39c5baSBill Taylor 1564*9e39c5baSBill Taylor default: 1565*9e39c5baSBill Taylor break; 1566*9e39c5baSBill Taylor } 1567*9e39c5baSBill Taylor 1568*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_flash_reset); 1569*9e39c5baSBill Taylor } 1570*9e39c5baSBill Taylor 1571*9e39c5baSBill Taylor /* 1572*9e39c5baSBill Taylor * tavor_flash_read_sector() 1573*9e39c5baSBill Taylor */ 1574*9e39c5baSBill Taylor static void 1575*9e39c5baSBill Taylor tavor_flash_read_sector(tavor_state_t *state, uint32_t sector_num) 1576*9e39c5baSBill Taylor { 1577*9e39c5baSBill Taylor uint32_t addr; 1578*9e39c5baSBill Taylor uint32_t end_addr; 1579*9e39c5baSBill Taylor uint32_t *image; 1580*9e39c5baSBill Taylor int i; 1581*9e39c5baSBill Taylor 1582*9e39c5baSBill Taylor TAVOR_TNF_ENTER(tavor_flash_read_sector); 1583*9e39c5baSBill Taylor 1584*9e39c5baSBill Taylor image = (uint32_t *)&state->ts_fw_sector[0]; 1585*9e39c5baSBill Taylor 1586*9e39c5baSBill Taylor /* 1587*9e39c5baSBill Taylor * Calculate the start and end address of the sector, based on the 1588*9e39c5baSBill Taylor * sector number passed in. 1589*9e39c5baSBill Taylor */ 1590*9e39c5baSBill Taylor addr = sector_num << state->ts_fw_log_sector_sz; 1591*9e39c5baSBill Taylor end_addr = addr + (1 << state->ts_fw_log_sector_sz); 1592*9e39c5baSBill Taylor 1593*9e39c5baSBill Taylor /* Set the flash bank correctly for the given address */ 1594*9e39c5baSBill Taylor tavor_flash_bank(state, addr); 1595*9e39c5baSBill Taylor 1596*9e39c5baSBill Taylor /* Read the entire sector, one quadlet at a time */ 1597*9e39c5baSBill Taylor for (i = 0; addr < end_addr; i++, addr += 4) { 1598*9e39c5baSBill Taylor image[i] = tavor_flash_read(state, addr); 1599*9e39c5baSBill Taylor } 1600*9e39c5baSBill Taylor 1601*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_flash_read_sector); 1602*9e39c5baSBill Taylor } 1603*9e39c5baSBill Taylor 1604*9e39c5baSBill Taylor /* 1605*9e39c5baSBill Taylor * tavor_flash_read_quadlet() 1606*9e39c5baSBill Taylor */ 1607*9e39c5baSBill Taylor static void 1608*9e39c5baSBill Taylor tavor_flash_read_quadlet(tavor_state_t *state, uint32_t *data, 1609*9e39c5baSBill Taylor uint32_t addr) 1610*9e39c5baSBill Taylor { 1611*9e39c5baSBill Taylor TAVOR_TNF_ENTER(tavor_flash_read_quadlet); 1612*9e39c5baSBill Taylor 1613*9e39c5baSBill Taylor /* Set the flash bank correctly for the given address */ 1614*9e39c5baSBill Taylor tavor_flash_bank(state, addr); 1615*9e39c5baSBill Taylor 1616*9e39c5baSBill Taylor /* Read one quadlet of data */ 1617*9e39c5baSBill Taylor *data = tavor_flash_read(state, addr); 1618*9e39c5baSBill Taylor 1619*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_flash_read_quadlet); 1620*9e39c5baSBill Taylor } 1621*9e39c5baSBill Taylor 1622*9e39c5baSBill Taylor /* 1623*9e39c5baSBill Taylor * tavor_flash_write_sector() 1624*9e39c5baSBill Taylor */ 1625*9e39c5baSBill Taylor static int 1626*9e39c5baSBill Taylor tavor_flash_write_sector(tavor_state_t *state, uint32_t sector_num) 1627*9e39c5baSBill Taylor { 1628*9e39c5baSBill Taylor uint32_t addr; 1629*9e39c5baSBill Taylor uint32_t end_addr; 1630*9e39c5baSBill Taylor uchar_t *sector; 1631*9e39c5baSBill Taylor int status = 0; 1632*9e39c5baSBill Taylor int i; 1633*9e39c5baSBill Taylor 1634*9e39c5baSBill Taylor TAVOR_TNF_ENTER(tavor_flash_write_sector); 1635*9e39c5baSBill Taylor 1636*9e39c5baSBill Taylor sector = (uchar_t *)&state->ts_fw_sector[0]; 1637*9e39c5baSBill Taylor 1638*9e39c5baSBill Taylor /* 1639*9e39c5baSBill Taylor * Calculate the start and end address of the sector, based on the 1640*9e39c5baSBill Taylor * sector number passed in. 1641*9e39c5baSBill Taylor */ 1642*9e39c5baSBill Taylor addr = sector_num << state->ts_fw_log_sector_sz; 1643*9e39c5baSBill Taylor end_addr = addr + (1 << state->ts_fw_log_sector_sz); 1644*9e39c5baSBill Taylor 1645*9e39c5baSBill Taylor /* Set the flash bank correctly for the given address */ 1646*9e39c5baSBill Taylor tavor_flash_bank(state, addr); 1647*9e39c5baSBill Taylor 1648*9e39c5baSBill Taylor /* Erase the sector before writing */ 1649*9e39c5baSBill Taylor tavor_flash_reset(state); 1650*9e39c5baSBill Taylor status = tavor_flash_erase_sector(state, sector_num); 1651*9e39c5baSBill Taylor if (status != 0) { 1652*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_flash_write_sector); 1653*9e39c5baSBill Taylor return (status); 1654*9e39c5baSBill Taylor } 1655*9e39c5baSBill Taylor 1656*9e39c5baSBill Taylor /* Write the entire sector, one byte at a time */ 1657*9e39c5baSBill Taylor for (i = 0; addr < end_addr; i++, addr++) { 1658*9e39c5baSBill Taylor status = tavor_flash_write_byte(state, addr, sector[i]); 1659*9e39c5baSBill Taylor if (status != 0) { 1660*9e39c5baSBill Taylor break; 1661*9e39c5baSBill Taylor } 1662*9e39c5baSBill Taylor } 1663*9e39c5baSBill Taylor 1664*9e39c5baSBill Taylor tavor_flash_reset(state); 1665*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_flash_write_sector); 1666*9e39c5baSBill Taylor return (status); 1667*9e39c5baSBill Taylor } 1668*9e39c5baSBill Taylor 1669*9e39c5baSBill Taylor /* 1670*9e39c5baSBill Taylor * tavor_flash_write_byte() 1671*9e39c5baSBill Taylor */ 1672*9e39c5baSBill Taylor static int 1673*9e39c5baSBill Taylor tavor_flash_write_byte(tavor_state_t *state, uint32_t addr, uchar_t data) 1674*9e39c5baSBill Taylor { 1675*9e39c5baSBill Taylor uint32_t stat; 1676*9e39c5baSBill Taylor int status = 0; 1677*9e39c5baSBill Taylor int i; 1678*9e39c5baSBill Taylor 1679*9e39c5baSBill Taylor TAVOR_TNF_ENTER(tavor_flash_write_byte); 1680*9e39c5baSBill Taylor 1681*9e39c5baSBill Taylor switch (state->ts_fw_cmdset) { 1682*9e39c5baSBill Taylor case TAVOR_FLASH_AMD_CMDSET: 1683*9e39c5baSBill Taylor /* Issue Flash Byte program command */ 1684*9e39c5baSBill Taylor tavor_flash_write(state, addr, 0xAA); 1685*9e39c5baSBill Taylor tavor_flash_write(state, addr, 0x55); 1686*9e39c5baSBill Taylor tavor_flash_write(state, addr, 0xA0); 1687*9e39c5baSBill Taylor tavor_flash_write(state, addr, data); 1688*9e39c5baSBill Taylor 1689*9e39c5baSBill Taylor /* 1690*9e39c5baSBill Taylor * Wait for Write Byte to Complete: 1691*9e39c5baSBill Taylor * 1) Wait 1usec 1692*9e39c5baSBill Taylor * 2) Read status of the write operation 1693*9e39c5baSBill Taylor * 3) Determine if we have timed out the write operation 1694*9e39c5baSBill Taylor * 4) Compare correct data value to the status value that 1695*9e39c5baSBill Taylor * was read from the same address. 1696*9e39c5baSBill Taylor */ 1697*9e39c5baSBill Taylor i = 0; 1698*9e39c5baSBill Taylor do { 1699*9e39c5baSBill Taylor drv_usecwait(1); 1700*9e39c5baSBill Taylor stat = tavor_flash_read(state, addr & ~3); 1701*9e39c5baSBill Taylor 1702*9e39c5baSBill Taylor if (i == tavor_hw_flash_timeout_write) { 1703*9e39c5baSBill Taylor cmn_err(CE_WARN, 1704*9e39c5baSBill Taylor "tavor_flash_write_byte: ACS write " 1705*9e39c5baSBill Taylor "timeout: addr: 0x%x, data: 0x%x\n", 1706*9e39c5baSBill Taylor addr, data); 1707*9e39c5baSBill Taylor status = EIO; 1708*9e39c5baSBill Taylor break; 1709*9e39c5baSBill Taylor } 1710*9e39c5baSBill Taylor 1711*9e39c5baSBill Taylor i++; 1712*9e39c5baSBill Taylor } while (data != ((stat >> ((3 - (addr & 3)) << 3)) & 0xFF)); 1713*9e39c5baSBill Taylor break; 1714*9e39c5baSBill Taylor 1715*9e39c5baSBill Taylor case TAVOR_FLASH_INTEL_CMDSET: 1716*9e39c5baSBill Taylor /* Issue Flash Byte program command */ 1717*9e39c5baSBill Taylor tavor_flash_write(state, addr, TAVOR_HW_FLASH_ICS_WRITE); 1718*9e39c5baSBill Taylor tavor_flash_write(state, addr, data); 1719*9e39c5baSBill Taylor 1720*9e39c5baSBill Taylor /* wait for completion */ 1721*9e39c5baSBill Taylor i = 0; 1722*9e39c5baSBill Taylor do { 1723*9e39c5baSBill Taylor drv_usecwait(1); 1724*9e39c5baSBill Taylor stat = tavor_flash_read(state, addr & ~3); 1725*9e39c5baSBill Taylor 1726*9e39c5baSBill Taylor if (i == tavor_hw_flash_timeout_write) { 1727*9e39c5baSBill Taylor cmn_err(CE_WARN, 1728*9e39c5baSBill Taylor "tavor_flash_write_byte: ICS write " 1729*9e39c5baSBill Taylor "timeout: addr: %x, data: %x\n", 1730*9e39c5baSBill Taylor addr, data); 1731*9e39c5baSBill Taylor status = EIO; 1732*9e39c5baSBill Taylor break; 1733*9e39c5baSBill Taylor } 1734*9e39c5baSBill Taylor 1735*9e39c5baSBill Taylor i++; 1736*9e39c5baSBill Taylor } while ((stat & TAVOR_HW_FLASH_ICS_READY) == 0); 1737*9e39c5baSBill Taylor 1738*9e39c5baSBill Taylor if (stat & TAVOR_HW_FLASH_ICS_ERROR) { 1739*9e39c5baSBill Taylor cmn_err(CE_WARN, 1740*9e39c5baSBill Taylor "tavor_flash_write_byte: ICS write cmd error: " 1741*9e39c5baSBill Taylor "addr: %x, data: %x\n", 1742*9e39c5baSBill Taylor addr, data); 1743*9e39c5baSBill Taylor status = EIO; 1744*9e39c5baSBill Taylor } 1745*9e39c5baSBill Taylor break; 1746*9e39c5baSBill Taylor 1747*9e39c5baSBill Taylor default: 1748*9e39c5baSBill Taylor cmn_err(CE_WARN, 1749*9e39c5baSBill Taylor "tavor_flash_write_byte: unknown cmd set: 0x%x\n", 1750*9e39c5baSBill Taylor state->ts_fw_cmdset); 1751*9e39c5baSBill Taylor status = EIO; 1752*9e39c5baSBill Taylor break; 1753*9e39c5baSBill Taylor } 1754*9e39c5baSBill Taylor 1755*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_flash_write_byte); 1756*9e39c5baSBill Taylor return (status); 1757*9e39c5baSBill Taylor } 1758*9e39c5baSBill Taylor 1759*9e39c5baSBill Taylor /* 1760*9e39c5baSBill Taylor * tavor_flash_erase_sector() 1761*9e39c5baSBill Taylor */ 1762*9e39c5baSBill Taylor static int 1763*9e39c5baSBill Taylor tavor_flash_erase_sector(tavor_state_t *state, uint32_t sector_num) 1764*9e39c5baSBill Taylor { 1765*9e39c5baSBill Taylor uint32_t addr; 1766*9e39c5baSBill Taylor uint32_t stat; 1767*9e39c5baSBill Taylor int status = 0; 1768*9e39c5baSBill Taylor int i; 1769*9e39c5baSBill Taylor 1770*9e39c5baSBill Taylor TAVOR_TNF_ENTER(tavor_flash_erase_sector); 1771*9e39c5baSBill Taylor 1772*9e39c5baSBill Taylor /* Get address from sector num */ 1773*9e39c5baSBill Taylor addr = sector_num << state->ts_fw_log_sector_sz; 1774*9e39c5baSBill Taylor 1775*9e39c5baSBill Taylor switch (state->ts_fw_cmdset) { 1776*9e39c5baSBill Taylor case TAVOR_FLASH_AMD_CMDSET: 1777*9e39c5baSBill Taylor /* Issue Flash Sector Erase Command */ 1778*9e39c5baSBill Taylor tavor_flash_write(state, addr, 0xAA); 1779*9e39c5baSBill Taylor tavor_flash_write(state, addr, 0x55); 1780*9e39c5baSBill Taylor tavor_flash_write(state, addr, 0x80); 1781*9e39c5baSBill Taylor tavor_flash_write(state, addr, 0xAA); 1782*9e39c5baSBill Taylor tavor_flash_write(state, addr, 0x55); 1783*9e39c5baSBill Taylor tavor_flash_write(state, addr, 0x30); 1784*9e39c5baSBill Taylor 1785*9e39c5baSBill Taylor /* 1786*9e39c5baSBill Taylor * Wait for Sector Erase to Complete 1787*9e39c5baSBill Taylor * 1) Wait 1usec 1788*9e39c5baSBill Taylor * 2) read the status at the base addr of the sector 1789*9e39c5baSBill Taylor * 3) Determine if we have timed out 1790*9e39c5baSBill Taylor * 4) Compare status of address with the value of a fully 1791*9e39c5baSBill Taylor * erased quadlet. If these are equal, the sector 1792*9e39c5baSBill Taylor * has been erased. 1793*9e39c5baSBill Taylor */ 1794*9e39c5baSBill Taylor i = 0; 1795*9e39c5baSBill Taylor do { 1796*9e39c5baSBill Taylor /* wait 1usec */ 1797*9e39c5baSBill Taylor drv_usecwait(1); 1798*9e39c5baSBill Taylor stat = tavor_flash_read(state, addr); 1799*9e39c5baSBill Taylor 1800*9e39c5baSBill Taylor if (i == tavor_hw_flash_timeout_erase) { 1801*9e39c5baSBill Taylor cmn_err(CE_WARN, 1802*9e39c5baSBill Taylor "tavor_flash_erase_sector: " 1803*9e39c5baSBill Taylor "ACS erase timeout\n"); 1804*9e39c5baSBill Taylor status = EIO; 1805*9e39c5baSBill Taylor break; 1806*9e39c5baSBill Taylor } 1807*9e39c5baSBill Taylor 1808*9e39c5baSBill Taylor i++; 1809*9e39c5baSBill Taylor } while (stat != 0xFFFFFFFF); 1810*9e39c5baSBill Taylor break; 1811*9e39c5baSBill Taylor 1812*9e39c5baSBill Taylor case TAVOR_FLASH_INTEL_CMDSET: 1813*9e39c5baSBill Taylor /* Issue Erase Command */ 1814*9e39c5baSBill Taylor tavor_flash_write(state, addr, TAVOR_HW_FLASH_ICS_ERASE); 1815*9e39c5baSBill Taylor tavor_flash_write(state, addr, TAVOR_HW_FLASH_ICS_CONFIRM); 1816*9e39c5baSBill Taylor 1817*9e39c5baSBill Taylor /* wait for completion */ 1818*9e39c5baSBill Taylor i = 0; 1819*9e39c5baSBill Taylor do { 1820*9e39c5baSBill Taylor drv_usecwait(1); 1821*9e39c5baSBill Taylor stat = tavor_flash_read(state, addr & ~3); 1822*9e39c5baSBill Taylor 1823*9e39c5baSBill Taylor if (i == tavor_hw_flash_timeout_erase) { 1824*9e39c5baSBill Taylor cmn_err(CE_WARN, 1825*9e39c5baSBill Taylor "tavor_flash_erase_sector: " 1826*9e39c5baSBill Taylor "ICS erase timeout\n"); 1827*9e39c5baSBill Taylor status = EIO; 1828*9e39c5baSBill Taylor break; 1829*9e39c5baSBill Taylor } 1830*9e39c5baSBill Taylor 1831*9e39c5baSBill Taylor i++; 1832*9e39c5baSBill Taylor } while ((stat & TAVOR_HW_FLASH_ICS_READY) == 0); 1833*9e39c5baSBill Taylor 1834*9e39c5baSBill Taylor if (stat & TAVOR_HW_FLASH_ICS_ERROR) { 1835*9e39c5baSBill Taylor cmn_err(CE_WARN, 1836*9e39c5baSBill Taylor "tavor_flash_erase_sector: " 1837*9e39c5baSBill Taylor "ICS erase cmd error\n"); 1838*9e39c5baSBill Taylor status = EIO; 1839*9e39c5baSBill Taylor } 1840*9e39c5baSBill Taylor break; 1841*9e39c5baSBill Taylor 1842*9e39c5baSBill Taylor default: 1843*9e39c5baSBill Taylor cmn_err(CE_WARN, 1844*9e39c5baSBill Taylor "tavor_flash_erase_sector: unknown cmd set: 0x%x\n", 1845*9e39c5baSBill Taylor state->ts_fw_cmdset); 1846*9e39c5baSBill Taylor status = EIO; 1847*9e39c5baSBill Taylor break; 1848*9e39c5baSBill Taylor } 1849*9e39c5baSBill Taylor 1850*9e39c5baSBill Taylor tavor_flash_reset(state); 1851*9e39c5baSBill Taylor 1852*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_flash_erase_sector); 1853*9e39c5baSBill Taylor return (status); 1854*9e39c5baSBill Taylor } 1855*9e39c5baSBill Taylor 1856*9e39c5baSBill Taylor /* 1857*9e39c5baSBill Taylor * tavor_flash_erase_chip() 1858*9e39c5baSBill Taylor */ 1859*9e39c5baSBill Taylor static int 1860*9e39c5baSBill Taylor tavor_flash_erase_chip(tavor_state_t *state) 1861*9e39c5baSBill Taylor { 1862*9e39c5baSBill Taylor uint_t size; 1863*9e39c5baSBill Taylor uint32_t stat; 1864*9e39c5baSBill Taylor int status = 0; 1865*9e39c5baSBill Taylor int num_sect; 1866*9e39c5baSBill Taylor int i; 1867*9e39c5baSBill Taylor 1868*9e39c5baSBill Taylor TAVOR_TNF_ENTER(tavor_flash_erase_chip); 1869*9e39c5baSBill Taylor 1870*9e39c5baSBill Taylor switch (state->ts_fw_cmdset) { 1871*9e39c5baSBill Taylor case TAVOR_FLASH_AMD_CMDSET: 1872*9e39c5baSBill Taylor /* Issue Flash Chip Erase Command */ 1873*9e39c5baSBill Taylor tavor_flash_write(state, 0, 0xAA); 1874*9e39c5baSBill Taylor tavor_flash_write(state, 0, 0x55); 1875*9e39c5baSBill Taylor tavor_flash_write(state, 0, 0x80); 1876*9e39c5baSBill Taylor tavor_flash_write(state, 0, 0xAA); 1877*9e39c5baSBill Taylor tavor_flash_write(state, 0, 0x55); 1878*9e39c5baSBill Taylor tavor_flash_write(state, 0, 0x10); 1879*9e39c5baSBill Taylor 1880*9e39c5baSBill Taylor /* 1881*9e39c5baSBill Taylor * Wait for Chip Erase to Complete 1882*9e39c5baSBill Taylor * 1) Wait 1usec 1883*9e39c5baSBill Taylor * 2) read the status at the base addr of the sector 1884*9e39c5baSBill Taylor * 3) Determine if we have timed out 1885*9e39c5baSBill Taylor * 4) Compare status of address with the value of a 1886*9e39c5baSBill Taylor * fully erased quadlet. If these are equal, the 1887*9e39c5baSBill Taylor * chip has been erased. 1888*9e39c5baSBill Taylor */ 1889*9e39c5baSBill Taylor i = 0; 1890*9e39c5baSBill Taylor do { 1891*9e39c5baSBill Taylor /* wait 1usec */ 1892*9e39c5baSBill Taylor drv_usecwait(1); 1893*9e39c5baSBill Taylor stat = tavor_flash_read(state, 0); 1894*9e39c5baSBill Taylor 1895*9e39c5baSBill Taylor if (i == tavor_hw_flash_timeout_erase) { 1896*9e39c5baSBill Taylor cmn_err(CE_WARN, 1897*9e39c5baSBill Taylor "tavor_flash_erase_chip: erase timeout\n"); 1898*9e39c5baSBill Taylor status = EIO; 1899*9e39c5baSBill Taylor break; 1900*9e39c5baSBill Taylor } 1901*9e39c5baSBill Taylor 1902*9e39c5baSBill Taylor i++; 1903*9e39c5baSBill Taylor } while (stat != 0xFFFFFFFF); 1904*9e39c5baSBill Taylor break; 1905*9e39c5baSBill Taylor 1906*9e39c5baSBill Taylor case TAVOR_FLASH_INTEL_CMDSET: 1907*9e39c5baSBill Taylor /* 1908*9e39c5baSBill Taylor * The Intel chip doesn't have a chip erase command, so erase 1909*9e39c5baSBill Taylor * all blocks one at a time. 1910*9e39c5baSBill Taylor */ 1911*9e39c5baSBill Taylor size = (0x1 << state->ts_fw_log_sector_sz); 1912*9e39c5baSBill Taylor num_sect = state->ts_fw_device_sz / size; 1913*9e39c5baSBill Taylor 1914*9e39c5baSBill Taylor for (i = 0; i < num_sect; i++) { 1915*9e39c5baSBill Taylor status = tavor_flash_erase_sector(state, i); 1916*9e39c5baSBill Taylor if (status != 0) { 1917*9e39c5baSBill Taylor cmn_err(CE_WARN, 1918*9e39c5baSBill Taylor "tavor_flash_erase_chip: " 1919*9e39c5baSBill Taylor "ICS sector %d erase error\n", i); 1920*9e39c5baSBill Taylor status = EIO; 1921*9e39c5baSBill Taylor break; 1922*9e39c5baSBill Taylor } 1923*9e39c5baSBill Taylor } 1924*9e39c5baSBill Taylor break; 1925*9e39c5baSBill Taylor 1926*9e39c5baSBill Taylor default: 1927*9e39c5baSBill Taylor cmn_err(CE_WARN, "tavor_flash_erase_chip: " 1928*9e39c5baSBill Taylor "unknown cmd set: 0x%x\n", state->ts_fw_cmdset); 1929*9e39c5baSBill Taylor status = EIO; 1930*9e39c5baSBill Taylor break; 1931*9e39c5baSBill Taylor } 1932*9e39c5baSBill Taylor 1933*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_flash_erase_chip); 1934*9e39c5baSBill Taylor return (status); 1935*9e39c5baSBill Taylor } 1936*9e39c5baSBill Taylor 1937*9e39c5baSBill Taylor /* 1938*9e39c5baSBill Taylor * tavor_flash_bank() 1939*9e39c5baSBill Taylor */ 1940*9e39c5baSBill Taylor static void 1941*9e39c5baSBill Taylor tavor_flash_bank(tavor_state_t *state, uint32_t addr) 1942*9e39c5baSBill Taylor { 1943*9e39c5baSBill Taylor ddi_acc_handle_t hdl; 1944*9e39c5baSBill Taylor uint32_t bank; 1945*9e39c5baSBill Taylor 1946*9e39c5baSBill Taylor TAVOR_TNF_ENTER(tavor_flash_bank); 1947*9e39c5baSBill Taylor 1948*9e39c5baSBill Taylor /* Set handle */ 1949*9e39c5baSBill Taylor hdl = state->ts_pci_cfghdl; 1950*9e39c5baSBill Taylor 1951*9e39c5baSBill Taylor /* Determine the bank setting from the address */ 1952*9e39c5baSBill Taylor bank = addr & TAVOR_HW_FLASH_BANK_MASK; 1953*9e39c5baSBill Taylor 1954*9e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(state->ts_fw_flashbank)) 1955*9e39c5baSBill Taylor 1956*9e39c5baSBill Taylor /* 1957*9e39c5baSBill Taylor * If the bank is different from the currently set bank, we need to 1958*9e39c5baSBill Taylor * change it. Also, if an 'addr' of 0 is given, this allows the 1959*9e39c5baSBill Taylor * capability to force the flash bank to 0. This is useful at init 1960*9e39c5baSBill Taylor * time to initially set the bank value 1961*9e39c5baSBill Taylor */ 1962*9e39c5baSBill Taylor if (state->ts_fw_flashbank != bank || addr == 0) { 1963*9e39c5baSBill Taylor /* Set bank using the GPIO settings */ 1964*9e39c5baSBill Taylor tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_GPIO_DATACLEAR, 0x70); 1965*9e39c5baSBill Taylor tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_GPIO_DATASET, 1966*9e39c5baSBill Taylor (bank >> 15) & 0x70); 1967*9e39c5baSBill Taylor 1968*9e39c5baSBill Taylor /* Save the bank state */ 1969*9e39c5baSBill Taylor state->ts_fw_flashbank = bank; 1970*9e39c5baSBill Taylor } 1971*9e39c5baSBill Taylor 1972*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_flash_bank); 1973*9e39c5baSBill Taylor } 1974*9e39c5baSBill Taylor 1975*9e39c5baSBill Taylor /* 1976*9e39c5baSBill Taylor * tavor_flash_read() 1977*9e39c5baSBill Taylor */ 1978*9e39c5baSBill Taylor static uint32_t 1979*9e39c5baSBill Taylor tavor_flash_read(tavor_state_t *state, uint32_t addr) 1980*9e39c5baSBill Taylor { 1981*9e39c5baSBill Taylor ddi_acc_handle_t hdl; 1982*9e39c5baSBill Taylor uint32_t data; 1983*9e39c5baSBill Taylor int timeout; 1984*9e39c5baSBill Taylor 1985*9e39c5baSBill Taylor TAVOR_TNF_ENTER(tavor_flash_read); 1986*9e39c5baSBill Taylor 1987*9e39c5baSBill Taylor /* Set handle */ 1988*9e39c5baSBill Taylor hdl = state->ts_pci_cfghdl; 1989*9e39c5baSBill Taylor 1990*9e39c5baSBill Taylor /* 1991*9e39c5baSBill Taylor * The Read operation does the following: 1992*9e39c5baSBill Taylor * 1) Write the masked address to the TAVOR_FLASH_ADDR register. 1993*9e39c5baSBill Taylor * Only the least significant 19 bits are valid. 1994*9e39c5baSBill Taylor * 2) Read back the register until the command has completed. 1995*9e39c5baSBill Taylor * 3) Read the data retrieved from the address at the TAVOR_FLASH_DATA 1996*9e39c5baSBill Taylor * register. 1997*9e39c5baSBill Taylor */ 1998*9e39c5baSBill Taylor tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_ADDR, 1999*9e39c5baSBill Taylor (addr & TAVOR_HW_FLASH_ADDR_MASK) | (1 << 29)); 2000*9e39c5baSBill Taylor 2001*9e39c5baSBill Taylor timeout = 0; 2002*9e39c5baSBill Taylor do { 2003*9e39c5baSBill Taylor data = tavor_flash_read_cfg(hdl, TAVOR_HW_FLASH_ADDR); 2004*9e39c5baSBill Taylor timeout++; 2005*9e39c5baSBill Taylor } while ((data & TAVOR_HW_FLASH_CMD_MASK) && 2006*9e39c5baSBill Taylor (timeout < tavor_hw_flash_timeout_config)); 2007*9e39c5baSBill Taylor 2008*9e39c5baSBill Taylor if (timeout == tavor_hw_flash_timeout_config) { 2009*9e39c5baSBill Taylor cmn_err(CE_WARN, "tavor_flash_read: config command timeout.\n"); 2010*9e39c5baSBill Taylor } 2011*9e39c5baSBill Taylor 2012*9e39c5baSBill Taylor data = tavor_flash_read_cfg(hdl, TAVOR_HW_FLASH_DATA); 2013*9e39c5baSBill Taylor 2014*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_flash_read); 2015*9e39c5baSBill Taylor return (data); 2016*9e39c5baSBill Taylor } 2017*9e39c5baSBill Taylor 2018*9e39c5baSBill Taylor /* 2019*9e39c5baSBill Taylor * tavor_flash_write() 2020*9e39c5baSBill Taylor */ 2021*9e39c5baSBill Taylor static void 2022*9e39c5baSBill Taylor tavor_flash_write(tavor_state_t *state, uint32_t addr, uchar_t data) 2023*9e39c5baSBill Taylor { 2024*9e39c5baSBill Taylor ddi_acc_handle_t hdl; 2025*9e39c5baSBill Taylor int cmd; 2026*9e39c5baSBill Taylor int timeout; 2027*9e39c5baSBill Taylor 2028*9e39c5baSBill Taylor TAVOR_TNF_ENTER(tavor_flash_write); 2029*9e39c5baSBill Taylor 2030*9e39c5baSBill Taylor /* Set handle */ 2031*9e39c5baSBill Taylor hdl = state->ts_pci_cfghdl; 2032*9e39c5baSBill Taylor 2033*9e39c5baSBill Taylor /* 2034*9e39c5baSBill Taylor * The Write operation does the following: 2035*9e39c5baSBill Taylor * 1) Write the data to be written to the TAVOR_FLASH_DATA offset. 2036*9e39c5baSBill Taylor * 2) Write the address to write the data to to the TAVOR_FLASH_ADDR 2037*9e39c5baSBill Taylor * offset. 2038*9e39c5baSBill Taylor * 3) Wait until the write completes. 2039*9e39c5baSBill Taylor */ 2040*9e39c5baSBill Taylor tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_DATA, data << 24); 2041*9e39c5baSBill Taylor tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_ADDR, 2042*9e39c5baSBill Taylor (addr & 0x7FFFF) | (2 << 29)); 2043*9e39c5baSBill Taylor 2044*9e39c5baSBill Taylor timeout = 0; 2045*9e39c5baSBill Taylor do { 2046*9e39c5baSBill Taylor cmd = tavor_flash_read_cfg(hdl, TAVOR_HW_FLASH_ADDR); 2047*9e39c5baSBill Taylor timeout++; 2048*9e39c5baSBill Taylor } while ((cmd & TAVOR_HW_FLASH_CMD_MASK) && 2049*9e39c5baSBill Taylor (timeout < tavor_hw_flash_timeout_config)); 2050*9e39c5baSBill Taylor 2051*9e39c5baSBill Taylor if (timeout == tavor_hw_flash_timeout_config) { 2052*9e39c5baSBill Taylor cmn_err(CE_WARN, "tavor_flash_write: config cmd timeout.\n"); 2053*9e39c5baSBill Taylor } 2054*9e39c5baSBill Taylor 2055*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_flash_write); 2056*9e39c5baSBill Taylor } 2057*9e39c5baSBill Taylor 2058*9e39c5baSBill Taylor /* 2059*9e39c5baSBill Taylor * tavor_flash_init() 2060*9e39c5baSBill Taylor */ 2061*9e39c5baSBill Taylor static void 2062*9e39c5baSBill Taylor tavor_flash_init(tavor_state_t *state) 2063*9e39c5baSBill Taylor { 2064*9e39c5baSBill Taylor uint32_t word; 2065*9e39c5baSBill Taylor ddi_acc_handle_t hdl; 2066*9e39c5baSBill Taylor int sema_cnt; 2067*9e39c5baSBill Taylor int gpio; 2068*9e39c5baSBill Taylor 2069*9e39c5baSBill Taylor TAVOR_TNF_ENTER(tavor_flash_init); 2070*9e39c5baSBill Taylor 2071*9e39c5baSBill Taylor /* Set handle */ 2072*9e39c5baSBill Taylor hdl = state->ts_pci_cfghdl; 2073*9e39c5baSBill Taylor 2074*9e39c5baSBill Taylor /* Init the flash */ 2075*9e39c5baSBill Taylor 2076*9e39c5baSBill Taylor /* 2077*9e39c5baSBill Taylor * Grab the GPIO semaphore. This allows us exclusive access to the 2078*9e39c5baSBill Taylor * GPIO settings on the Tavor for the duration of the flash burning 2079*9e39c5baSBill Taylor * procedure. 2080*9e39c5baSBill Taylor */ 2081*9e39c5baSBill Taylor sema_cnt = 0; 2082*9e39c5baSBill Taylor do { 2083*9e39c5baSBill Taylor word = tavor_flash_read_cfg(hdl, TAVOR_HW_FLASH_GPIO_SEMA); 2084*9e39c5baSBill Taylor if (word == 0) { 2085*9e39c5baSBill Taylor break; 2086*9e39c5baSBill Taylor } 2087*9e39c5baSBill Taylor 2088*9e39c5baSBill Taylor sema_cnt++; 2089*9e39c5baSBill Taylor drv_usecwait(1); 2090*9e39c5baSBill Taylor } while (sema_cnt < tavor_hw_flash_timeout_gpio_sema); 2091*9e39c5baSBill Taylor 2092*9e39c5baSBill Taylor /* 2093*9e39c5baSBill Taylor * Determine if we timed out trying to grab the GPIO semaphore 2094*9e39c5baSBill Taylor */ 2095*9e39c5baSBill Taylor if (sema_cnt == tavor_hw_flash_timeout_gpio_sema) { 2096*9e39c5baSBill Taylor cmn_err(CE_WARN, "tavor_flash_init: GPIO SEMA timeout\n"); 2097*9e39c5baSBill Taylor } 2098*9e39c5baSBill Taylor 2099*9e39c5baSBill Taylor /* Save away original GPIO Values */ 2100*9e39c5baSBill Taylor state->ts_fw_gpio[0] = tavor_flash_read_cfg(hdl, 2101*9e39c5baSBill Taylor TAVOR_HW_FLASH_GPIO_DIR); 2102*9e39c5baSBill Taylor state->ts_fw_gpio[1] = tavor_flash_read_cfg(hdl, 2103*9e39c5baSBill Taylor TAVOR_HW_FLASH_GPIO_POL); 2104*9e39c5baSBill Taylor state->ts_fw_gpio[2] = tavor_flash_read_cfg(hdl, 2105*9e39c5baSBill Taylor TAVOR_HW_FLASH_GPIO_MOD); 2106*9e39c5baSBill Taylor state->ts_fw_gpio[3] = tavor_flash_read_cfg(hdl, 2107*9e39c5baSBill Taylor TAVOR_HW_FLASH_GPIO_DAT); 2108*9e39c5baSBill Taylor 2109*9e39c5baSBill Taylor /* Set New GPIO Values */ 2110*9e39c5baSBill Taylor gpio = state->ts_fw_gpio[0] | 0x70; 2111*9e39c5baSBill Taylor tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_GPIO_DIR, gpio); 2112*9e39c5baSBill Taylor 2113*9e39c5baSBill Taylor gpio = state->ts_fw_gpio[1] & ~0x70; 2114*9e39c5baSBill Taylor tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_GPIO_POL, gpio); 2115*9e39c5baSBill Taylor 2116*9e39c5baSBill Taylor gpio = state->ts_fw_gpio[2] & ~0x70; 2117*9e39c5baSBill Taylor tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_GPIO_MOD, gpio); 2118*9e39c5baSBill Taylor 2119*9e39c5baSBill Taylor /* Set CPUMODE to enable tavor to access the flash device */ 2120*9e39c5baSBill Taylor tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_CPUMODE, 2121*9e39c5baSBill Taylor 1 << TAVOR_HW_FLASH_CPU_SHIFT); 2122*9e39c5baSBill Taylor 2123*9e39c5baSBill Taylor /* Initialize to bank 0 */ 2124*9e39c5baSBill Taylor tavor_flash_bank(state, 0); 2125*9e39c5baSBill Taylor 2126*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_flash_init); 2127*9e39c5baSBill Taylor } 2128*9e39c5baSBill Taylor 2129*9e39c5baSBill Taylor /* 2130*9e39c5baSBill Taylor * tavor_flash_cfi_init 2131*9e39c5baSBill Taylor * Implements access to the CFI (Common Flash Interface) data 2132*9e39c5baSBill Taylor */ 2133*9e39c5baSBill Taylor static void 2134*9e39c5baSBill Taylor tavor_flash_cfi_init(tavor_state_t *state, uint32_t *cfi_info, int *intel_xcmd) 2135*9e39c5baSBill Taylor { 2136*9e39c5baSBill Taylor uint32_t data; 2137*9e39c5baSBill Taylor uint32_t sector_sz_bytes; 2138*9e39c5baSBill Taylor uint32_t bit_count; 2139*9e39c5baSBill Taylor uint8_t cfi_ch_info[TAVOR_CFI_INFO_SIZE]; 2140*9e39c5baSBill Taylor uint32_t cfi_dw_info[TAVOR_CFI_INFO_QSIZE]; 2141*9e39c5baSBill Taylor int i; 2142*9e39c5baSBill Taylor 2143*9e39c5baSBill Taylor TAVOR_TNF_ENTER(tavor_flash_cfi_init); 2144*9e39c5baSBill Taylor 2145*9e39c5baSBill Taylor /* 2146*9e39c5baSBill Taylor * Determine if the user command supports the Intel Extended 2147*9e39c5baSBill Taylor * Command Set. The query string is contained in the fourth 2148*9e39c5baSBill Taylor * quad word. 2149*9e39c5baSBill Taylor */ 2150*9e39c5baSBill Taylor tavor_flash_cfi_byte(cfi_ch_info, cfi_info[0x04], 0x10); 2151*9e39c5baSBill Taylor if (cfi_ch_info[0x10] == 'M' && 2152*9e39c5baSBill Taylor cfi_ch_info[0x11] == 'X' && 2153*9e39c5baSBill Taylor cfi_ch_info[0x12] == '2') { 2154*9e39c5baSBill Taylor *intel_xcmd = 1; /* support is there */ 2155*9e39c5baSBill Taylor } 2156*9e39c5baSBill Taylor 2157*9e39c5baSBill Taylor /* CFI QUERY */ 2158*9e39c5baSBill Taylor tavor_flash_write(state, 0x55, TAVOR_FLASH_CFI_INIT); 2159*9e39c5baSBill Taylor 2160*9e39c5baSBill Taylor /* Read in CFI data */ 2161*9e39c5baSBill Taylor for (i = 0; i < TAVOR_CFI_INFO_SIZE; i += 4) { 2162*9e39c5baSBill Taylor data = tavor_flash_read(state, i); 2163*9e39c5baSBill Taylor cfi_dw_info[i >> 2] = data; 2164*9e39c5baSBill Taylor tavor_flash_cfi_byte(cfi_ch_info, data, i); 2165*9e39c5baSBill Taylor } 2166*9e39c5baSBill Taylor 2167*9e39c5baSBill Taylor /* Determine chip set */ 2168*9e39c5baSBill Taylor state->ts_fw_cmdset = TAVOR_FLASH_UNKNOWN_CMDSET; 2169*9e39c5baSBill Taylor if (cfi_ch_info[0x20] == 'Q' && 2170*9e39c5baSBill Taylor cfi_ch_info[0x22] == 'R' && 2171*9e39c5baSBill Taylor cfi_ch_info[0x24] == 'Y') { 2172*9e39c5baSBill Taylor /* 2173*9e39c5baSBill Taylor * Mode: x16 working in x8 mode (Intel). 2174*9e39c5baSBill Taylor * Pack data - skip spacing bytes. 2175*9e39c5baSBill Taylor */ 2176*9e39c5baSBill Taylor for (i = 0; i < TAVOR_CFI_INFO_SIZE; i += 2) { 2177*9e39c5baSBill Taylor cfi_ch_info[i/2] = cfi_ch_info[i]; 2178*9e39c5baSBill Taylor } 2179*9e39c5baSBill Taylor } 2180*9e39c5baSBill Taylor state->ts_fw_cmdset = cfi_ch_info[0x13]; 2181*9e39c5baSBill Taylor if (state->ts_fw_cmdset != TAVOR_FLASH_INTEL_CMDSET && 2182*9e39c5baSBill Taylor state->ts_fw_cmdset != TAVOR_FLASH_AMD_CMDSET) { 2183*9e39c5baSBill Taylor cmn_err(CE_WARN, 2184*9e39c5baSBill Taylor "tavor_flash_cfi_init: UNKNOWN chip cmd set\n"); 2185*9e39c5baSBill Taylor state->ts_fw_cmdset = TAVOR_FLASH_UNKNOWN_CMDSET; 2186*9e39c5baSBill Taylor goto out; 2187*9e39c5baSBill Taylor } 2188*9e39c5baSBill Taylor 2189*9e39c5baSBill Taylor /* Determine total bytes in one sector size */ 2190*9e39c5baSBill Taylor sector_sz_bytes = ((cfi_ch_info[0x30] << 8) | cfi_ch_info[0x2F]) << 8; 2191*9e39c5baSBill Taylor 2192*9e39c5baSBill Taylor /* Calculate equivalent of log2 (n) */ 2193*9e39c5baSBill Taylor for (bit_count = 0; sector_sz_bytes > 1; bit_count++) { 2194*9e39c5baSBill Taylor sector_sz_bytes >>= 1; 2195*9e39c5baSBill Taylor } 2196*9e39c5baSBill Taylor 2197*9e39c5baSBill Taylor /* Set sector size */ 2198*9e39c5baSBill Taylor state->ts_fw_log_sector_sz = bit_count; 2199*9e39c5baSBill Taylor 2200*9e39c5baSBill Taylor /* Set flash size */ 2201*9e39c5baSBill Taylor state->ts_fw_device_sz = 0x1 << cfi_ch_info[0x27]; 2202*9e39c5baSBill Taylor 2203*9e39c5baSBill Taylor /* Reset to turn off CFI mode */ 2204*9e39c5baSBill Taylor tavor_flash_reset(state); 2205*9e39c5baSBill Taylor 2206*9e39c5baSBill Taylor /* 2207*9e39c5baSBill Taylor * Pass CFI data back to user command. 2208*9e39c5baSBill Taylor */ 2209*9e39c5baSBill Taylor for (i = 0; i < TAVOR_FLASH_CFI_SIZE_QUADLET; i++) { 2210*9e39c5baSBill Taylor tavor_flash_cfi_dword(&cfi_info[i], cfi_ch_info, i << 2); 2211*9e39c5baSBill Taylor } 2212*9e39c5baSBill Taylor 2213*9e39c5baSBill Taylor if (*intel_xcmd == 1) { 2214*9e39c5baSBill Taylor /* 2215*9e39c5baSBill Taylor * Inform the user cmd that this driver does support the 2216*9e39c5baSBill Taylor * Intel Extended Command Set. 2217*9e39c5baSBill Taylor */ 2218*9e39c5baSBill Taylor cfi_ch_info[0x10] = 'M'; 2219*9e39c5baSBill Taylor cfi_ch_info[0x11] = 'X'; 2220*9e39c5baSBill Taylor cfi_ch_info[0x12] = '2'; 2221*9e39c5baSBill Taylor } else { 2222*9e39c5baSBill Taylor cfi_ch_info[0x10] = 'Q'; 2223*9e39c5baSBill Taylor cfi_ch_info[0x11] = 'R'; 2224*9e39c5baSBill Taylor cfi_ch_info[0x12] = 'Y'; 2225*9e39c5baSBill Taylor } 2226*9e39c5baSBill Taylor cfi_ch_info[0x13] = state->ts_fw_cmdset; 2227*9e39c5baSBill Taylor tavor_flash_cfi_dword(&cfi_info[0x4], cfi_ch_info, 0x10); 2228*9e39c5baSBill Taylor out: 2229*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_flash_cfi_init); 2230*9e39c5baSBill Taylor } 2231*9e39c5baSBill Taylor 2232*9e39c5baSBill Taylor /* 2233*9e39c5baSBill Taylor * tavor_flash_fini() 2234*9e39c5baSBill Taylor */ 2235*9e39c5baSBill Taylor static void 2236*9e39c5baSBill Taylor tavor_flash_fini(tavor_state_t *state) 2237*9e39c5baSBill Taylor { 2238*9e39c5baSBill Taylor ddi_acc_handle_t hdl; 2239*9e39c5baSBill Taylor 2240*9e39c5baSBill Taylor TAVOR_TNF_ENTER(tavor_flash_fini); 2241*9e39c5baSBill Taylor 2242*9e39c5baSBill Taylor /* Set handle */ 2243*9e39c5baSBill Taylor hdl = state->ts_pci_cfghdl; 2244*9e39c5baSBill Taylor 2245*9e39c5baSBill Taylor /* Restore original GPIO Values */ 2246*9e39c5baSBill Taylor tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_GPIO_DIR, 2247*9e39c5baSBill Taylor state->ts_fw_gpio[0]); 2248*9e39c5baSBill Taylor tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_GPIO_POL, 2249*9e39c5baSBill Taylor state->ts_fw_gpio[1]); 2250*9e39c5baSBill Taylor tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_GPIO_MOD, 2251*9e39c5baSBill Taylor state->ts_fw_gpio[2]); 2252*9e39c5baSBill Taylor tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_GPIO_DAT, 2253*9e39c5baSBill Taylor state->ts_fw_gpio[3]); 2254*9e39c5baSBill Taylor 2255*9e39c5baSBill Taylor /* Give up semaphore */ 2256*9e39c5baSBill Taylor tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_GPIO_SEMA, 0); 2257*9e39c5baSBill Taylor 2258*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_flash_fini); 2259*9e39c5baSBill Taylor } 2260*9e39c5baSBill Taylor 2261*9e39c5baSBill Taylor /* 2262*9e39c5baSBill Taylor * tavor_flash_read_cfg 2263*9e39c5baSBill Taylor */ 2264*9e39c5baSBill Taylor static uint32_t 2265*9e39c5baSBill Taylor tavor_flash_read_cfg(ddi_acc_handle_t pci_config_hdl, uint32_t addr) 2266*9e39c5baSBill Taylor { 2267*9e39c5baSBill Taylor uint32_t read; 2268*9e39c5baSBill Taylor 2269*9e39c5baSBill Taylor TAVOR_TNF_ENTER(tavor_flash_read_cfg); 2270*9e39c5baSBill Taylor 2271*9e39c5baSBill Taylor /* 2272*9e39c5baSBill Taylor * Perform flash read operation: 2273*9e39c5baSBill Taylor * 1) Place addr to read from on the TAVOR_HW_FLASH_CFG_ADDR register 2274*9e39c5baSBill Taylor * 2) Read data at that addr from the TAVOR_HW_FLASH_CFG_DATA register 2275*9e39c5baSBill Taylor */ 2276*9e39c5baSBill Taylor pci_config_put32(pci_config_hdl, TAVOR_HW_FLASH_CFG_ADDR, addr); 2277*9e39c5baSBill Taylor read = pci_config_get32(pci_config_hdl, TAVOR_HW_FLASH_CFG_DATA); 2278*9e39c5baSBill Taylor 2279*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_flash_read_cfg); 2280*9e39c5baSBill Taylor 2281*9e39c5baSBill Taylor return (read); 2282*9e39c5baSBill Taylor } 2283*9e39c5baSBill Taylor 2284*9e39c5baSBill Taylor /* 2285*9e39c5baSBill Taylor * tavor_flash_write_cfg 2286*9e39c5baSBill Taylor */ 2287*9e39c5baSBill Taylor static void 2288*9e39c5baSBill Taylor tavor_flash_write_cfg(ddi_acc_handle_t pci_config_hdl, uint32_t addr, 2289*9e39c5baSBill Taylor uint32_t data) 2290*9e39c5baSBill Taylor { 2291*9e39c5baSBill Taylor TAVOR_TNF_ENTER(tavor_flash_write_cfg); 2292*9e39c5baSBill Taylor 2293*9e39c5baSBill Taylor /* 2294*9e39c5baSBill Taylor * Perform flash write operation: 2295*9e39c5baSBill Taylor * 1) Place addr to write to on the TAVOR_HW_FLASH_CFG_ADDR register 2296*9e39c5baSBill Taylor * 2) Place data to write on to the TAVOR_HW_FLASH_CFG_DATA register 2297*9e39c5baSBill Taylor */ 2298*9e39c5baSBill Taylor pci_config_put32(pci_config_hdl, TAVOR_HW_FLASH_CFG_ADDR, addr); 2299*9e39c5baSBill Taylor pci_config_put32(pci_config_hdl, TAVOR_HW_FLASH_CFG_DATA, data); 2300*9e39c5baSBill Taylor 2301*9e39c5baSBill Taylor TAVOR_TNF_EXIT(tavor_flash_write_cfg); 2302*9e39c5baSBill Taylor } 2303*9e39c5baSBill Taylor 2304*9e39c5baSBill Taylor /* 2305*9e39c5baSBill Taylor * Support routines to convert Common Flash Interface (CFI) data 2306*9e39c5baSBill Taylor * from a 32 bit word to a char array, and from a char array to 2307*9e39c5baSBill Taylor * a 32 bit word. 2308*9e39c5baSBill Taylor */ 2309*9e39c5baSBill Taylor static void 2310*9e39c5baSBill Taylor tavor_flash_cfi_byte(uint8_t *ch, uint32_t dword, int i) 2311*9e39c5baSBill Taylor { 2312*9e39c5baSBill Taylor ch[i] = (uint8_t)((dword & 0xFF000000) >> 24); 2313*9e39c5baSBill Taylor ch[i+1] = (uint8_t)((dword & 0x00FF0000) >> 16); 2314*9e39c5baSBill Taylor ch[i+2] = (uint8_t)((dword & 0x0000FF00) >> 8); 2315*9e39c5baSBill Taylor ch[i+3] = (uint8_t)((dword & 0x000000FF)); 2316*9e39c5baSBill Taylor } 2317*9e39c5baSBill Taylor 2318*9e39c5baSBill Taylor static void 2319*9e39c5baSBill Taylor tavor_flash_cfi_dword(uint32_t *dword, uint8_t *ch, int i) 2320*9e39c5baSBill Taylor { 2321*9e39c5baSBill Taylor *dword = (uint32_t) 2322*9e39c5baSBill Taylor ((uint32_t)ch[i] << 24 | 2323*9e39c5baSBill Taylor (uint32_t)ch[i+1] << 16 | 2324*9e39c5baSBill Taylor (uint32_t)ch[i+2] << 8 | 2325*9e39c5baSBill Taylor (uint32_t)ch[i+3]); 2326*9e39c5baSBill Taylor } 2327*9e39c5baSBill Taylor 2328*9e39c5baSBill Taylor /* 2329*9e39c5baSBill Taylor * tavor_loopback_free_qps 2330*9e39c5baSBill Taylor */ 2331*9e39c5baSBill Taylor static void 2332*9e39c5baSBill Taylor tavor_loopback_free_qps(tavor_loopback_state_t *lstate) 2333*9e39c5baSBill Taylor { 2334*9e39c5baSBill Taylor int i; 2335*9e39c5baSBill Taylor 2336*9e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lstate)) 2337*9e39c5baSBill Taylor 2338*9e39c5baSBill Taylor if (lstate->tls_tx.tlc_qp_hdl != NULL) { 2339*9e39c5baSBill Taylor (void) tavor_qp_free(lstate->tls_state, 2340*9e39c5baSBill Taylor &lstate->tls_tx.tlc_qp_hdl, IBC_FREE_QP_AND_QPN, NULL, 2341*9e39c5baSBill Taylor TAVOR_NOSLEEP); 2342*9e39c5baSBill Taylor } 2343*9e39c5baSBill Taylor if (lstate->tls_rx.tlc_qp_hdl != NULL) { 2344*9e39c5baSBill Taylor (void) tavor_qp_free(lstate->tls_state, 2345*9e39c5baSBill Taylor &lstate->tls_rx.tlc_qp_hdl, IBC_FREE_QP_AND_QPN, NULL, 2346*9e39c5baSBill Taylor TAVOR_NOSLEEP); 2347*9e39c5baSBill Taylor } 2348*9e39c5baSBill Taylor lstate->tls_tx.tlc_qp_hdl = NULL; 2349*9e39c5baSBill Taylor lstate->tls_rx.tlc_qp_hdl = NULL; 2350*9e39c5baSBill Taylor for (i = 0; i < 2; i++) { 2351*9e39c5baSBill Taylor if (lstate->tls_tx.tlc_cqhdl[i] != NULL) { 2352*9e39c5baSBill Taylor (void) tavor_cq_free(lstate->tls_state, 2353*9e39c5baSBill Taylor &lstate->tls_tx.tlc_cqhdl[i], TAVOR_NOSLEEP); 2354*9e39c5baSBill Taylor } 2355*9e39c5baSBill Taylor if (lstate->tls_rx.tlc_cqhdl[i] != NULL) { 2356*9e39c5baSBill Taylor (void) tavor_cq_free(lstate->tls_state, 2357*9e39c5baSBill Taylor &lstate->tls_rx.tlc_cqhdl[i], TAVOR_NOSLEEP); 2358*9e39c5baSBill Taylor } 2359*9e39c5baSBill Taylor lstate->tls_tx.tlc_cqhdl[i] = NULL; 2360*9e39c5baSBill Taylor lstate->tls_rx.tlc_cqhdl[i] = NULL; 2361*9e39c5baSBill Taylor } 2362*9e39c5baSBill Taylor } 2363*9e39c5baSBill Taylor 2364*9e39c5baSBill Taylor /* 2365*9e39c5baSBill Taylor * tavor_loopback_free_state 2366*9e39c5baSBill Taylor */ 2367*9e39c5baSBill Taylor static void 2368*9e39c5baSBill Taylor tavor_loopback_free_state(tavor_loopback_state_t *lstate) 2369*9e39c5baSBill Taylor { 2370*9e39c5baSBill Taylor tavor_loopback_free_qps(lstate); 2371*9e39c5baSBill Taylor if (lstate->tls_tx.tlc_mrhdl != NULL) { 2372*9e39c5baSBill Taylor (void) tavor_mr_deregister(lstate->tls_state, 2373*9e39c5baSBill Taylor &lstate->tls_tx.tlc_mrhdl, TAVOR_MR_DEREG_ALL, 2374*9e39c5baSBill Taylor TAVOR_NOSLEEP); 2375*9e39c5baSBill Taylor } 2376*9e39c5baSBill Taylor if (lstate->tls_rx.tlc_mrhdl != NULL) { 2377*9e39c5baSBill Taylor (void) tavor_mr_deregister(lstate->tls_state, 2378*9e39c5baSBill Taylor &lstate->tls_rx.tlc_mrhdl, TAVOR_MR_DEREG_ALL, 2379*9e39c5baSBill Taylor TAVOR_NOSLEEP); 2380*9e39c5baSBill Taylor } 2381*9e39c5baSBill Taylor if (lstate->tls_pd_hdl != NULL) { 2382*9e39c5baSBill Taylor (void) tavor_pd_free(lstate->tls_state, &lstate->tls_pd_hdl); 2383*9e39c5baSBill Taylor } 2384*9e39c5baSBill Taylor if (lstate->tls_tx.tlc_buf != NULL) { 2385*9e39c5baSBill Taylor kmem_free(lstate->tls_tx.tlc_buf, lstate->tls_tx.tlc_buf_sz); 2386*9e39c5baSBill Taylor } 2387*9e39c5baSBill Taylor if (lstate->tls_rx.tlc_buf != NULL) { 2388*9e39c5baSBill Taylor kmem_free(lstate->tls_rx.tlc_buf, lstate->tls_rx.tlc_buf_sz); 2389*9e39c5baSBill Taylor } 2390*9e39c5baSBill Taylor bzero(lstate, sizeof (tavor_loopback_state_t)); 2391*9e39c5baSBill Taylor } 2392*9e39c5baSBill Taylor 2393*9e39c5baSBill Taylor /* 2394*9e39c5baSBill Taylor * tavor_loopback_init 2395*9e39c5baSBill Taylor */ 2396*9e39c5baSBill Taylor static int 2397*9e39c5baSBill Taylor tavor_loopback_init(tavor_state_t *state, tavor_loopback_state_t *lstate) 2398*9e39c5baSBill Taylor { 2399*9e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lstate)) 2400*9e39c5baSBill Taylor 2401*9e39c5baSBill Taylor lstate->tls_hca_hdl = (ibc_hca_hdl_t)state; 2402*9e39c5baSBill Taylor lstate->tls_status = tavor_pd_alloc(lstate->tls_state, 2403*9e39c5baSBill Taylor &lstate->tls_pd_hdl, TAVOR_NOSLEEP); 2404*9e39c5baSBill Taylor if (lstate->tls_status != IBT_SUCCESS) { 2405*9e39c5baSBill Taylor lstate->tls_err = TAVOR_LOOPBACK_PROT_DOMAIN_ALLOC_FAIL; 2406*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_loopback_alloc_pd_fail, 2407*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 2408*9e39c5baSBill Taylor return (EFAULT); 2409*9e39c5baSBill Taylor } 2410*9e39c5baSBill Taylor 2411*9e39c5baSBill Taylor return (0); 2412*9e39c5baSBill Taylor } 2413*9e39c5baSBill Taylor 2414*9e39c5baSBill Taylor /* 2415*9e39c5baSBill Taylor * tavor_loopback_init_qp_info 2416*9e39c5baSBill Taylor */ 2417*9e39c5baSBill Taylor static void 2418*9e39c5baSBill Taylor tavor_loopback_init_qp_info(tavor_loopback_state_t *lstate, 2419*9e39c5baSBill Taylor tavor_loopback_comm_t *comm) 2420*9e39c5baSBill Taylor { 2421*9e39c5baSBill Taylor bzero(&comm->tlc_cq_attr, sizeof (ibt_cq_attr_t)); 2422*9e39c5baSBill Taylor bzero(&comm->tlc_qp_attr, sizeof (ibt_qp_alloc_attr_t)); 2423*9e39c5baSBill Taylor bzero(&comm->tlc_qp_info, sizeof (ibt_qp_info_t)); 2424*9e39c5baSBill Taylor 2425*9e39c5baSBill Taylor comm->tlc_wrid = 1; 2426*9e39c5baSBill Taylor comm->tlc_cq_attr.cq_size = 128; 2427*9e39c5baSBill Taylor comm->tlc_qp_attr.qp_sizes.cs_sq_sgl = 3; 2428*9e39c5baSBill Taylor comm->tlc_qp_attr.qp_sizes.cs_rq_sgl = 3; 2429*9e39c5baSBill Taylor comm->tlc_qp_attr.qp_sizes.cs_sq = 16; 2430*9e39c5baSBill Taylor comm->tlc_qp_attr.qp_sizes.cs_rq = 16; 2431*9e39c5baSBill Taylor comm->tlc_qp_attr.qp_flags = IBT_WR_SIGNALED; 2432*9e39c5baSBill Taylor 2433*9e39c5baSBill Taylor comm->tlc_qp_info.qp_state = IBT_STATE_RESET; 2434*9e39c5baSBill Taylor comm->tlc_qp_info.qp_trans = IBT_RC_SRV; 2435*9e39c5baSBill Taylor comm->tlc_qp_info.qp_flags = IBT_CEP_RDMA_RD | IBT_CEP_RDMA_WR; 2436*9e39c5baSBill Taylor comm->tlc_qp_info.qp_transport.rc.rc_path.cep_hca_port_num = 2437*9e39c5baSBill Taylor lstate->tls_port; 2438*9e39c5baSBill Taylor comm->tlc_qp_info.qp_transport.rc.rc_path.cep_pkey_ix = 2439*9e39c5baSBill Taylor lstate->tls_pkey_ix; 2440*9e39c5baSBill Taylor comm->tlc_qp_info.qp_transport.rc.rc_path.cep_timeout = 2441*9e39c5baSBill Taylor lstate->tls_timeout; 2442*9e39c5baSBill Taylor comm->tlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_srvl = 0; 2443*9e39c5baSBill Taylor comm->tlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_srate = 2444*9e39c5baSBill Taylor IBT_SRATE_4X; 2445*9e39c5baSBill Taylor comm->tlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_send_grh = 0; 2446*9e39c5baSBill Taylor comm->tlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_dlid = 2447*9e39c5baSBill Taylor lstate->tls_lid; 2448*9e39c5baSBill Taylor comm->tlc_qp_info.qp_transport.rc.rc_retry_cnt = lstate->tls_retry; 2449*9e39c5baSBill Taylor comm->tlc_qp_info.qp_transport.rc.rc_sq_psn = 0; 2450*9e39c5baSBill Taylor comm->tlc_qp_info.qp_transport.rc.rc_rq_psn = 0; 2451*9e39c5baSBill Taylor comm->tlc_qp_info.qp_transport.rc.rc_rdma_ra_in = 4; 2452*9e39c5baSBill Taylor comm->tlc_qp_info.qp_transport.rc.rc_rdma_ra_out = 4; 2453*9e39c5baSBill Taylor comm->tlc_qp_info.qp_transport.rc.rc_dst_qpn = 0; 2454*9e39c5baSBill Taylor comm->tlc_qp_info.qp_transport.rc.rc_min_rnr_nak = IBT_RNR_NAK_655ms; 2455*9e39c5baSBill Taylor comm->tlc_qp_info.qp_transport.rc.rc_path_mtu = IB_MTU_1K; 2456*9e39c5baSBill Taylor } 2457*9e39c5baSBill Taylor 2458*9e39c5baSBill Taylor /* 2459*9e39c5baSBill Taylor * tavor_loopback_alloc_mem 2460*9e39c5baSBill Taylor */ 2461*9e39c5baSBill Taylor static int 2462*9e39c5baSBill Taylor tavor_loopback_alloc_mem(tavor_loopback_state_t *lstate, 2463*9e39c5baSBill Taylor tavor_loopback_comm_t *comm, int sz) 2464*9e39c5baSBill Taylor { 2465*9e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm)) 2466*9e39c5baSBill Taylor 2467*9e39c5baSBill Taylor /* Allocate buffer of specified size */ 2468*9e39c5baSBill Taylor comm->tlc_buf_sz = sz; 2469*9e39c5baSBill Taylor comm->tlc_buf = kmem_zalloc(sz, KM_NOSLEEP); 2470*9e39c5baSBill Taylor if (comm->tlc_buf == NULL) { 2471*9e39c5baSBill Taylor return (EFAULT); 2472*9e39c5baSBill Taylor } 2473*9e39c5baSBill Taylor 2474*9e39c5baSBill Taylor /* Register the buffer as a memory region */ 2475*9e39c5baSBill Taylor comm->tlc_memattr.mr_vaddr = (uint64_t)(uintptr_t)comm->tlc_buf; 2476*9e39c5baSBill Taylor comm->tlc_memattr.mr_len = (ib_msglen_t)sz; 2477*9e39c5baSBill Taylor comm->tlc_memattr.mr_as = NULL; 2478*9e39c5baSBill Taylor comm->tlc_memattr.mr_flags = IBT_MR_NOSLEEP | 2479*9e39c5baSBill Taylor IBT_MR_ENABLE_REMOTE_WRITE | IBT_MR_ENABLE_LOCAL_WRITE; 2480*9e39c5baSBill Taylor 2481*9e39c5baSBill Taylor comm->tlc_status = tavor_mr_register(lstate->tls_state, 2482*9e39c5baSBill Taylor lstate->tls_pd_hdl, &comm->tlc_memattr, &comm->tlc_mrhdl, NULL); 2483*9e39c5baSBill Taylor 2484*9e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm->tlc_mrhdl)) 2485*9e39c5baSBill Taylor 2486*9e39c5baSBill Taylor comm->tlc_mrdesc.md_vaddr = comm->tlc_mrhdl->mr_bindinfo.bi_addr; 2487*9e39c5baSBill Taylor comm->tlc_mrdesc.md_lkey = comm->tlc_mrhdl->mr_lkey; 2488*9e39c5baSBill Taylor comm->tlc_mrdesc.md_rkey = comm->tlc_mrhdl->mr_rkey; 2489*9e39c5baSBill Taylor if (comm->tlc_status != IBT_SUCCESS) { 2490*9e39c5baSBill Taylor return (EFAULT); 2491*9e39c5baSBill Taylor } 2492*9e39c5baSBill Taylor return (0); 2493*9e39c5baSBill Taylor } 2494*9e39c5baSBill Taylor 2495*9e39c5baSBill Taylor /* 2496*9e39c5baSBill Taylor * tavor_loopback_alloc_qps 2497*9e39c5baSBill Taylor */ 2498*9e39c5baSBill Taylor static int 2499*9e39c5baSBill Taylor tavor_loopback_alloc_qps(tavor_loopback_state_t *lstate, 2500*9e39c5baSBill Taylor tavor_loopback_comm_t *comm) 2501*9e39c5baSBill Taylor { 2502*9e39c5baSBill Taylor uint32_t i, real_size; 2503*9e39c5baSBill Taylor tavor_qp_info_t qpinfo; 2504*9e39c5baSBill Taylor 2505*9e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm)) 2506*9e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lstate)) 2507*9e39c5baSBill Taylor 2508*9e39c5baSBill Taylor /* Allocate send and recv CQs */ 2509*9e39c5baSBill Taylor for (i = 0; i < 2; i++) { 2510*9e39c5baSBill Taylor bzero(&comm->tlc_cq_attr, sizeof (ibt_cq_attr_t)); 2511*9e39c5baSBill Taylor comm->tlc_cq_attr.cq_size = 128; 2512*9e39c5baSBill Taylor comm->tlc_status = tavor_cq_alloc(lstate->tls_state, 2513*9e39c5baSBill Taylor (ibt_cq_hdl_t)NULL, &comm->tlc_cq_attr, &real_size, 2514*9e39c5baSBill Taylor &comm->tlc_cqhdl[i], TAVOR_NOSLEEP); 2515*9e39c5baSBill Taylor if (comm->tlc_status != IBT_SUCCESS) { 2516*9e39c5baSBill Taylor lstate->tls_err += i; 2517*9e39c5baSBill Taylor return (EFAULT); 2518*9e39c5baSBill Taylor } 2519*9e39c5baSBill Taylor } 2520*9e39c5baSBill Taylor 2521*9e39c5baSBill Taylor /* Allocate the QP */ 2522*9e39c5baSBill Taylor tavor_loopback_init_qp_info(lstate, comm); 2523*9e39c5baSBill Taylor comm->tlc_qp_attr.qp_pd_hdl = (ibt_pd_hdl_t)lstate->tls_pd_hdl; 2524*9e39c5baSBill Taylor comm->tlc_qp_attr.qp_scq_hdl = (ibt_cq_hdl_t)comm->tlc_cqhdl[0]; 2525*9e39c5baSBill Taylor comm->tlc_qp_attr.qp_rcq_hdl = (ibt_cq_hdl_t)comm->tlc_cqhdl[1]; 2526*9e39c5baSBill Taylor comm->tlc_qp_attr.qp_ibc_scq_hdl = (ibt_opaque1_t)comm->tlc_cqhdl[0]; 2527*9e39c5baSBill Taylor comm->tlc_qp_attr.qp_ibc_rcq_hdl = (ibt_opaque1_t)comm->tlc_cqhdl[1]; 2528*9e39c5baSBill Taylor qpinfo.qpi_attrp = &comm->tlc_qp_attr; 2529*9e39c5baSBill Taylor qpinfo.qpi_type = IBT_RC_RQP; 2530*9e39c5baSBill Taylor qpinfo.qpi_ibt_qphdl = NULL; 2531*9e39c5baSBill Taylor qpinfo.qpi_queueszp = &comm->tlc_chan_sizes; 2532*9e39c5baSBill Taylor qpinfo.qpi_qpn = &comm->tlc_qp_num; 2533*9e39c5baSBill Taylor comm->tlc_status = tavor_qp_alloc(lstate->tls_state, &qpinfo, 2534*9e39c5baSBill Taylor TAVOR_NOSLEEP, NULL); 2535*9e39c5baSBill Taylor if (comm->tlc_status == DDI_SUCCESS) { 2536*9e39c5baSBill Taylor comm->tlc_qp_hdl = qpinfo.qpi_qphdl; 2537*9e39c5baSBill Taylor } 2538*9e39c5baSBill Taylor 2539*9e39c5baSBill Taylor if (comm->tlc_status != IBT_SUCCESS) { 2540*9e39c5baSBill Taylor lstate->tls_err += 2; 2541*9e39c5baSBill Taylor return (EFAULT); 2542*9e39c5baSBill Taylor } 2543*9e39c5baSBill Taylor return (0); 2544*9e39c5baSBill Taylor } 2545*9e39c5baSBill Taylor 2546*9e39c5baSBill Taylor /* 2547*9e39c5baSBill Taylor * tavor_loopback_modify_qp 2548*9e39c5baSBill Taylor */ 2549*9e39c5baSBill Taylor static int 2550*9e39c5baSBill Taylor tavor_loopback_modify_qp(tavor_loopback_state_t *lstate, 2551*9e39c5baSBill Taylor tavor_loopback_comm_t *comm, uint_t qp_num) 2552*9e39c5baSBill Taylor { 2553*9e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm)) 2554*9e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lstate)) 2555*9e39c5baSBill Taylor 2556*9e39c5baSBill Taylor /* Modify QP to INIT */ 2557*9e39c5baSBill Taylor tavor_loopback_init_qp_info(lstate, comm); 2558*9e39c5baSBill Taylor comm->tlc_qp_info.qp_state = IBT_STATE_INIT; 2559*9e39c5baSBill Taylor comm->tlc_status = tavor_qp_modify(lstate->tls_state, comm->tlc_qp_hdl, 2560*9e39c5baSBill Taylor IBT_CEP_SET_STATE, &comm->tlc_qp_info, &comm->tlc_queue_sizes); 2561*9e39c5baSBill Taylor if (comm->tlc_status != IBT_SUCCESS) { 2562*9e39c5baSBill Taylor return (EFAULT); 2563*9e39c5baSBill Taylor } 2564*9e39c5baSBill Taylor 2565*9e39c5baSBill Taylor /* 2566*9e39c5baSBill Taylor * Modify QP to RTR (set destination LID and QP number to local 2567*9e39c5baSBill Taylor * LID and QP number) 2568*9e39c5baSBill Taylor */ 2569*9e39c5baSBill Taylor comm->tlc_qp_info.qp_state = IBT_STATE_RTR; 2570*9e39c5baSBill Taylor comm->tlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_dlid 2571*9e39c5baSBill Taylor = lstate->tls_lid; 2572*9e39c5baSBill Taylor comm->tlc_qp_info.qp_transport.rc.rc_dst_qpn = qp_num; 2573*9e39c5baSBill Taylor comm->tlc_status = tavor_qp_modify(lstate->tls_state, comm->tlc_qp_hdl, 2574*9e39c5baSBill Taylor IBT_CEP_SET_STATE, &comm->tlc_qp_info, &comm->tlc_queue_sizes); 2575*9e39c5baSBill Taylor if (comm->tlc_status != IBT_SUCCESS) { 2576*9e39c5baSBill Taylor lstate->tls_err += 1; 2577*9e39c5baSBill Taylor return (EFAULT); 2578*9e39c5baSBill Taylor } 2579*9e39c5baSBill Taylor 2580*9e39c5baSBill Taylor /* Modify QP to RTS */ 2581*9e39c5baSBill Taylor comm->tlc_qp_info.qp_current_state = IBT_STATE_RTR; 2582*9e39c5baSBill Taylor comm->tlc_qp_info.qp_state = IBT_STATE_RTS; 2583*9e39c5baSBill Taylor comm->tlc_status = tavor_qp_modify(lstate->tls_state, comm->tlc_qp_hdl, 2584*9e39c5baSBill Taylor IBT_CEP_SET_STATE, &comm->tlc_qp_info, &comm->tlc_queue_sizes); 2585*9e39c5baSBill Taylor if (comm->tlc_status != IBT_SUCCESS) { 2586*9e39c5baSBill Taylor lstate->tls_err += 2; 2587*9e39c5baSBill Taylor return (EFAULT); 2588*9e39c5baSBill Taylor } 2589*9e39c5baSBill Taylor return (0); 2590*9e39c5baSBill Taylor } 2591*9e39c5baSBill Taylor 2592*9e39c5baSBill Taylor /* 2593*9e39c5baSBill Taylor * tavor_loopback_copyout 2594*9e39c5baSBill Taylor */ 2595*9e39c5baSBill Taylor static int 2596*9e39c5baSBill Taylor tavor_loopback_copyout(tavor_loopback_ioctl_t *lb, intptr_t arg, int mode) 2597*9e39c5baSBill Taylor { 2598*9e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL 2599*9e39c5baSBill Taylor if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 2600*9e39c5baSBill Taylor tavor_loopback_ioctl32_t lb32; 2601*9e39c5baSBill Taylor 2602*9e39c5baSBill Taylor lb32.tlb_revision = lb->tlb_revision; 2603*9e39c5baSBill Taylor lb32.tlb_send_buf = 2604*9e39c5baSBill Taylor (caddr32_t)(uintptr_t)lb->tlb_send_buf; 2605*9e39c5baSBill Taylor lb32.tlb_fail_buf = 2606*9e39c5baSBill Taylor (caddr32_t)(uintptr_t)lb->tlb_fail_buf; 2607*9e39c5baSBill Taylor lb32.tlb_buf_sz = lb->tlb_buf_sz; 2608*9e39c5baSBill Taylor lb32.tlb_num_iter = lb->tlb_num_iter; 2609*9e39c5baSBill Taylor lb32.tlb_pass_done = lb->tlb_pass_done; 2610*9e39c5baSBill Taylor lb32.tlb_timeout = lb->tlb_timeout; 2611*9e39c5baSBill Taylor lb32.tlb_error_type = lb->tlb_error_type; 2612*9e39c5baSBill Taylor lb32.tlb_port_num = lb->tlb_port_num; 2613*9e39c5baSBill Taylor lb32.tlb_num_retry = lb->tlb_num_retry; 2614*9e39c5baSBill Taylor 2615*9e39c5baSBill Taylor if (ddi_copyout(&lb32, (void *)arg, 2616*9e39c5baSBill Taylor sizeof (tavor_loopback_ioctl32_t), mode) != 0) { 2617*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_loopback_copyout_fail, 2618*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 2619*9e39c5baSBill Taylor return (EFAULT); 2620*9e39c5baSBill Taylor } 2621*9e39c5baSBill Taylor } else 2622*9e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */ 2623*9e39c5baSBill Taylor if (ddi_copyout(lb, (void *)arg, sizeof (tavor_loopback_ioctl_t), 2624*9e39c5baSBill Taylor mode) != 0) { 2625*9e39c5baSBill Taylor TNF_PROBE_0(tavor_ioctl_loopback_copyout_fail, 2626*9e39c5baSBill Taylor TAVOR_TNF_ERROR, ""); 2627*9e39c5baSBill Taylor return (EFAULT); 2628*9e39c5baSBill Taylor } 2629*9e39c5baSBill Taylor return (0); 2630*9e39c5baSBill Taylor } 2631*9e39c5baSBill Taylor 2632*9e39c5baSBill Taylor /* 2633*9e39c5baSBill Taylor * tavor_loopback_post_send 2634*9e39c5baSBill Taylor */ 2635*9e39c5baSBill Taylor static int 2636*9e39c5baSBill Taylor tavor_loopback_post_send(tavor_loopback_state_t *lstate, 2637*9e39c5baSBill Taylor tavor_loopback_comm_t *tx, tavor_loopback_comm_t *rx) 2638*9e39c5baSBill Taylor { 2639*9e39c5baSBill Taylor int ret; 2640*9e39c5baSBill Taylor 2641*9e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*tx)) 2642*9e39c5baSBill Taylor 2643*9e39c5baSBill Taylor bzero(&tx->tlc_sgl, sizeof (ibt_wr_ds_t)); 2644*9e39c5baSBill Taylor bzero(&tx->tlc_wr, sizeof (ibt_send_wr_t)); 2645*9e39c5baSBill Taylor 2646*9e39c5baSBill Taylor /* Initialize local address for TX buffer */ 2647*9e39c5baSBill Taylor tx->tlc_sgl.ds_va = tx->tlc_mrdesc.md_vaddr; 2648*9e39c5baSBill Taylor tx->tlc_sgl.ds_key = tx->tlc_mrdesc.md_lkey; 2649*9e39c5baSBill Taylor tx->tlc_sgl.ds_len = tx->tlc_buf_sz; 2650*9e39c5baSBill Taylor 2651*9e39c5baSBill Taylor /* Initialize the remaining details of the work request */ 2652*9e39c5baSBill Taylor tx->tlc_wr.wr_id = tx->tlc_wrid++; 2653*9e39c5baSBill Taylor tx->tlc_wr.wr_flags = IBT_WR_SEND_SIGNAL; 2654*9e39c5baSBill Taylor tx->tlc_wr.wr_nds = 1; 2655*9e39c5baSBill Taylor tx->tlc_wr.wr_sgl = &tx->tlc_sgl; 2656*9e39c5baSBill Taylor tx->tlc_wr.wr_opcode = IBT_WRC_RDMAW; 2657*9e39c5baSBill Taylor tx->tlc_wr.wr_trans = IBT_RC_SRV; 2658*9e39c5baSBill Taylor 2659*9e39c5baSBill Taylor /* Initialize the remote address for RX buffer */ 2660*9e39c5baSBill Taylor tx->tlc_wr.wr.rc.rcwr.rdma.rdma_raddr = rx->tlc_mrdesc.md_vaddr; 2661*9e39c5baSBill Taylor tx->tlc_wr.wr.rc.rcwr.rdma.rdma_rkey = rx->tlc_mrdesc.md_rkey; 2662*9e39c5baSBill Taylor tx->tlc_complete = 0; 2663*9e39c5baSBill Taylor ret = tavor_post_send(lstate->tls_state, tx->tlc_qp_hdl, &tx->tlc_wr, 2664*9e39c5baSBill Taylor 1, NULL); 2665*9e39c5baSBill Taylor if (ret != IBT_SUCCESS) { 2666*9e39c5baSBill Taylor return (EFAULT); 2667*9e39c5baSBill Taylor } 2668*9e39c5baSBill Taylor return (0); 2669*9e39c5baSBill Taylor } 2670*9e39c5baSBill Taylor 2671*9e39c5baSBill Taylor /* 2672*9e39c5baSBill Taylor * tavor_loopback_poll_cq 2673*9e39c5baSBill Taylor */ 2674*9e39c5baSBill Taylor static int 2675*9e39c5baSBill Taylor tavor_loopback_poll_cq(tavor_loopback_state_t *lstate, 2676*9e39c5baSBill Taylor tavor_loopback_comm_t *comm) 2677*9e39c5baSBill Taylor { 2678*9e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm)) 2679*9e39c5baSBill Taylor 2680*9e39c5baSBill Taylor comm->tlc_wc.wc_status = 0; 2681*9e39c5baSBill Taylor comm->tlc_num_polled = 0; 2682*9e39c5baSBill Taylor comm->tlc_status = tavor_cq_poll(lstate->tls_state, 2683*9e39c5baSBill Taylor comm->tlc_cqhdl[0], &comm->tlc_wc, 1, &comm->tlc_num_polled); 2684*9e39c5baSBill Taylor if ((comm->tlc_status == IBT_SUCCESS) && 2685*9e39c5baSBill Taylor (comm->tlc_wc.wc_status != IBT_WC_SUCCESS)) { 2686*9e39c5baSBill Taylor comm->tlc_status = ibc_get_ci_failure(0); 2687*9e39c5baSBill Taylor } 2688*9e39c5baSBill Taylor return (comm->tlc_status); 2689*9e39c5baSBill Taylor } 2690