19e39c5baSBill Taylor /*
29e39c5baSBill Taylor * CDDL HEADER START
39e39c5baSBill Taylor *
49e39c5baSBill Taylor * The contents of this file are subject to the terms of the
59e39c5baSBill Taylor * Common Development and Distribution License (the "License").
69e39c5baSBill Taylor * You may not use this file except in compliance with the License.
79e39c5baSBill Taylor *
89e39c5baSBill Taylor * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99e39c5baSBill Taylor * or http://www.opensolaris.org/os/licensing.
109e39c5baSBill Taylor * See the License for the specific language governing permissions
119e39c5baSBill Taylor * and limitations under the License.
129e39c5baSBill Taylor *
139e39c5baSBill Taylor * When distributing Covered Code, include this CDDL HEADER in each
149e39c5baSBill Taylor * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159e39c5baSBill Taylor * If applicable, add the following below this CDDL HEADER, with the
169e39c5baSBill Taylor * fields enclosed by brackets "[]" replaced with your own identifying
179e39c5baSBill Taylor * information: Portions Copyright [yyyy] [name of copyright owner]
189e39c5baSBill Taylor *
199e39c5baSBill Taylor * CDDL HEADER END
209e39c5baSBill Taylor */
219e39c5baSBill Taylor
229e39c5baSBill Taylor /*
239e39c5baSBill Taylor * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
249e39c5baSBill Taylor * Use is subject to license terms.
259e39c5baSBill Taylor */
269e39c5baSBill Taylor
279e39c5baSBill Taylor /*
289e39c5baSBill Taylor * tavor_ioctl.c
299e39c5baSBill Taylor * Tavor IOCTL Routines
309e39c5baSBill Taylor *
319e39c5baSBill Taylor * Implements all ioctl access into the driver. This includes all routines
329e39c5baSBill Taylor * necessary for updating firmware, accessing the tavor flash device, and
339e39c5baSBill Taylor * providing interfaces for VTS.
349e39c5baSBill Taylor */
359e39c5baSBill Taylor
369e39c5baSBill Taylor #include <sys/types.h>
379e39c5baSBill Taylor #include <sys/conf.h>
389e39c5baSBill Taylor #include <sys/ddi.h>
399e39c5baSBill Taylor #include <sys/sunddi.h>
409e39c5baSBill Taylor #include <sys/modctl.h>
419e39c5baSBill Taylor #include <sys/file.h>
429e39c5baSBill Taylor
439e39c5baSBill Taylor #include <sys/ib/adapters/tavor/tavor.h>
449e39c5baSBill Taylor
459e39c5baSBill Taylor /* Tavor HCA state pointer (extern) */
469e39c5baSBill Taylor extern void *tavor_statep;
479e39c5baSBill Taylor
489e39c5baSBill Taylor /*
499e39c5baSBill Taylor * The ioctl declarations (for firmware flash burning, register read/write
509e39c5baSBill Taylor * (DEBUG-only), and VTS interfaces)
519e39c5baSBill Taylor */
529e39c5baSBill Taylor static int tavor_ioctl_flash_read(tavor_state_t *state, dev_t dev,
539e39c5baSBill Taylor intptr_t arg, int mode);
549e39c5baSBill Taylor static int tavor_ioctl_flash_write(tavor_state_t *state, dev_t dev,
559e39c5baSBill Taylor intptr_t arg, int mode);
569e39c5baSBill Taylor static int tavor_ioctl_flash_erase(tavor_state_t *state, dev_t dev,
579e39c5baSBill Taylor intptr_t arg, int mode);
589e39c5baSBill Taylor static int tavor_ioctl_flash_init(tavor_state_t *state, dev_t dev,
599e39c5baSBill Taylor intptr_t arg, int mode);
609e39c5baSBill Taylor static int tavor_ioctl_flash_fini(tavor_state_t *state, dev_t dev);
619e39c5baSBill Taylor static void tavor_ioctl_flash_cleanup(tavor_state_t *state);
629e39c5baSBill Taylor static void tavor_ioctl_flash_cleanup_nolock(tavor_state_t *state);
639e39c5baSBill Taylor #ifdef DEBUG
649e39c5baSBill Taylor static int tavor_ioctl_reg_write(tavor_state_t *state, intptr_t arg,
659e39c5baSBill Taylor int mode);
669e39c5baSBill Taylor static int tavor_ioctl_reg_read(tavor_state_t *state, intptr_t arg,
679e39c5baSBill Taylor int mode);
689e39c5baSBill Taylor #endif /* DEBUG */
699e39c5baSBill Taylor static int tavor_ioctl_info(tavor_state_t *state, dev_t dev,
709e39c5baSBill Taylor intptr_t arg, int mode);
719e39c5baSBill Taylor static int tavor_ioctl_ports(tavor_state_t *state, intptr_t arg,
729e39c5baSBill Taylor int mode);
739e39c5baSBill Taylor static int tavor_ioctl_loopback(tavor_state_t *state, intptr_t arg,
749e39c5baSBill Taylor int mode);
759e39c5baSBill Taylor static int tavor_ioctl_ddr_read(tavor_state_t *state, intptr_t arg,
769e39c5baSBill Taylor int mode);
779e39c5baSBill Taylor
789e39c5baSBill Taylor /* Tavor Flash Functions */
799e39c5baSBill Taylor static void tavor_flash_read_sector(tavor_state_t *state, uint32_t sector_num);
809e39c5baSBill Taylor static void tavor_flash_read_quadlet(tavor_state_t *state, uint32_t *data,
819e39c5baSBill Taylor uint32_t addr);
829e39c5baSBill Taylor static int tavor_flash_write_sector(tavor_state_t *state, uint32_t sector_num);
839e39c5baSBill Taylor static int tavor_flash_write_byte(tavor_state_t *state, uint32_t addr,
849e39c5baSBill Taylor uchar_t data);
859e39c5baSBill Taylor static int tavor_flash_erase_sector(tavor_state_t *state, uint32_t sector_num);
869e39c5baSBill Taylor static int tavor_flash_erase_chip(tavor_state_t *state);
879e39c5baSBill Taylor static void tavor_flash_bank(tavor_state_t *state, uint32_t addr);
889e39c5baSBill Taylor static uint32_t tavor_flash_read(tavor_state_t *state, uint32_t addr);
899e39c5baSBill Taylor static void tavor_flash_write(tavor_state_t *state, uint32_t addr,
909e39c5baSBill Taylor uchar_t data);
919e39c5baSBill Taylor static void tavor_flash_init(tavor_state_t *state);
929e39c5baSBill Taylor static void tavor_flash_cfi_init(tavor_state_t *state, uint32_t *cfi_info,
939e39c5baSBill Taylor int *intel_xcmd);
949e39c5baSBill Taylor static void tavor_flash_fini(tavor_state_t *state);
959e39c5baSBill Taylor static void tavor_flash_reset(tavor_state_t *state);
969e39c5baSBill Taylor static uint32_t tavor_flash_read_cfg(ddi_acc_handle_t pci_config_hdl,
979e39c5baSBill Taylor uint32_t addr);
989e39c5baSBill Taylor static void tavor_flash_write_cfg(ddi_acc_handle_t pci_config_hdl,
999e39c5baSBill Taylor uint32_t addr, uint32_t data);
1009e39c5baSBill Taylor static void tavor_flash_cfi_byte(uint8_t *ch, uint32_t dword, int i);
1019e39c5baSBill Taylor static void tavor_flash_cfi_dword(uint32_t *dword, uint8_t *ch, int i);
1029e39c5baSBill Taylor
1039e39c5baSBill Taylor /* Tavor loopback test functions */
1049e39c5baSBill Taylor static void tavor_loopback_free_qps(tavor_loopback_state_t *lstate);
1059e39c5baSBill Taylor static void tavor_loopback_free_state(tavor_loopback_state_t *lstate);
1069e39c5baSBill Taylor static int tavor_loopback_init(tavor_state_t *state,
1079e39c5baSBill Taylor tavor_loopback_state_t *lstate);
1089e39c5baSBill Taylor static void tavor_loopback_init_qp_info(tavor_loopback_state_t *lstate,
1099e39c5baSBill Taylor tavor_loopback_comm_t *comm);
1109e39c5baSBill Taylor static int tavor_loopback_alloc_mem(tavor_loopback_state_t *lstate,
1119e39c5baSBill Taylor tavor_loopback_comm_t *comm, int sz);
1129e39c5baSBill Taylor static int tavor_loopback_alloc_qps(tavor_loopback_state_t *lstate,
1139e39c5baSBill Taylor tavor_loopback_comm_t *comm);
1149e39c5baSBill Taylor static int tavor_loopback_modify_qp(tavor_loopback_state_t *lstate,
1159e39c5baSBill Taylor tavor_loopback_comm_t *comm, uint_t qp_num);
1169e39c5baSBill Taylor static int tavor_loopback_copyout(tavor_loopback_ioctl_t *lb,
1179e39c5baSBill Taylor intptr_t arg, int mode);
1189e39c5baSBill Taylor static int tavor_loopback_post_send(tavor_loopback_state_t *lstate,
1199e39c5baSBill Taylor tavor_loopback_comm_t *tx, tavor_loopback_comm_t *rx);
1209e39c5baSBill Taylor static int tavor_loopback_poll_cq(tavor_loopback_state_t *lstate,
1219e39c5baSBill Taylor tavor_loopback_comm_t *comm);
1229e39c5baSBill Taylor
1239e39c5baSBill Taylor /* Patchable timeout values for flash operations */
1249e39c5baSBill Taylor int tavor_hw_flash_timeout_gpio_sema = TAVOR_HW_FLASH_TIMEOUT_GPIO_SEMA;
1259e39c5baSBill Taylor int tavor_hw_flash_timeout_config = TAVOR_HW_FLASH_TIMEOUT_CONFIG;
1269e39c5baSBill Taylor int tavor_hw_flash_timeout_write = TAVOR_HW_FLASH_TIMEOUT_WRITE;
1279e39c5baSBill Taylor int tavor_hw_flash_timeout_erase = TAVOR_HW_FLASH_TIMEOUT_ERASE;
1289e39c5baSBill Taylor
1299e39c5baSBill Taylor /*
1309e39c5baSBill Taylor * tavor_ioctl()
1319e39c5baSBill Taylor */
1329e39c5baSBill Taylor /* ARGSUSED */
1339e39c5baSBill Taylor int
tavor_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)1349e39c5baSBill Taylor tavor_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
1359e39c5baSBill Taylor int *rvalp)
1369e39c5baSBill Taylor {
1379e39c5baSBill Taylor tavor_state_t *state;
1389e39c5baSBill Taylor minor_t instance;
1399e39c5baSBill Taylor int status;
1409e39c5baSBill Taylor
1419e39c5baSBill Taylor if (drv_priv(credp) != 0) {
1429e39c5baSBill Taylor return (EPERM);
1439e39c5baSBill Taylor }
1449e39c5baSBill Taylor
1459e39c5baSBill Taylor instance = TAVOR_DEV_INSTANCE(dev);
1469e39c5baSBill Taylor if (instance == -1) {
1479e39c5baSBill Taylor return (EBADF);
1489e39c5baSBill Taylor }
1499e39c5baSBill Taylor
1509e39c5baSBill Taylor state = ddi_get_soft_state(tavor_statep, instance);
1519e39c5baSBill Taylor if (state == NULL) {
1529e39c5baSBill Taylor return (EBADF);
1539e39c5baSBill Taylor }
1549e39c5baSBill Taylor
1559e39c5baSBill Taylor status = 0;
1569e39c5baSBill Taylor
1579e39c5baSBill Taylor switch (cmd) {
1589e39c5baSBill Taylor case TAVOR_IOCTL_FLASH_READ:
1599e39c5baSBill Taylor status = tavor_ioctl_flash_read(state, dev, arg, mode);
1609e39c5baSBill Taylor break;
1619e39c5baSBill Taylor
1629e39c5baSBill Taylor case TAVOR_IOCTL_FLASH_WRITE:
1639e39c5baSBill Taylor status = tavor_ioctl_flash_write(state, dev, arg, mode);
1649e39c5baSBill Taylor break;
1659e39c5baSBill Taylor
1669e39c5baSBill Taylor case TAVOR_IOCTL_FLASH_ERASE:
1679e39c5baSBill Taylor status = tavor_ioctl_flash_erase(state, dev, arg, mode);
1689e39c5baSBill Taylor break;
1699e39c5baSBill Taylor
1709e39c5baSBill Taylor case TAVOR_IOCTL_FLASH_INIT:
1719e39c5baSBill Taylor status = tavor_ioctl_flash_init(state, dev, arg, mode);
1729e39c5baSBill Taylor break;
1739e39c5baSBill Taylor
1749e39c5baSBill Taylor case TAVOR_IOCTL_FLASH_FINI:
1759e39c5baSBill Taylor status = tavor_ioctl_flash_fini(state, dev);
1769e39c5baSBill Taylor break;
1779e39c5baSBill Taylor
1789e39c5baSBill Taylor case TAVOR_IOCTL_INFO:
1799e39c5baSBill Taylor status = tavor_ioctl_info(state, dev, arg, mode);
1809e39c5baSBill Taylor break;
1819e39c5baSBill Taylor
1829e39c5baSBill Taylor case TAVOR_IOCTL_PORTS:
1839e39c5baSBill Taylor status = tavor_ioctl_ports(state, arg, mode);
1849e39c5baSBill Taylor break;
1859e39c5baSBill Taylor
1869e39c5baSBill Taylor case TAVOR_IOCTL_DDR_READ:
1879e39c5baSBill Taylor status = tavor_ioctl_ddr_read(state, arg, mode);
1889e39c5baSBill Taylor break;
1899e39c5baSBill Taylor
1909e39c5baSBill Taylor case TAVOR_IOCTL_LOOPBACK:
1919e39c5baSBill Taylor status = tavor_ioctl_loopback(state, arg, mode);
1929e39c5baSBill Taylor break;
1939e39c5baSBill Taylor
1949e39c5baSBill Taylor #ifdef DEBUG
1959e39c5baSBill Taylor case TAVOR_IOCTL_REG_WRITE:
1969e39c5baSBill Taylor status = tavor_ioctl_reg_write(state, arg, mode);
1979e39c5baSBill Taylor break;
1989e39c5baSBill Taylor
1999e39c5baSBill Taylor case TAVOR_IOCTL_REG_READ:
2009e39c5baSBill Taylor status = tavor_ioctl_reg_read(state, arg, mode);
2019e39c5baSBill Taylor break;
2029e39c5baSBill Taylor #endif /* DEBUG */
2039e39c5baSBill Taylor
2049e39c5baSBill Taylor default:
2059e39c5baSBill Taylor status = ENOTTY;
2069e39c5baSBill Taylor break;
2079e39c5baSBill Taylor }
2089e39c5baSBill Taylor *rvalp = status;
2099e39c5baSBill Taylor
2109e39c5baSBill Taylor return (status);
2119e39c5baSBill Taylor }
2129e39c5baSBill Taylor
2139e39c5baSBill Taylor /*
2149e39c5baSBill Taylor * tavor_ioctl_flash_read()
2159e39c5baSBill Taylor */
2169e39c5baSBill Taylor static int
tavor_ioctl_flash_read(tavor_state_t * state,dev_t dev,intptr_t arg,int mode)2179e39c5baSBill Taylor tavor_ioctl_flash_read(tavor_state_t *state, dev_t dev, intptr_t arg, int mode)
2189e39c5baSBill Taylor {
2199e39c5baSBill Taylor tavor_flash_ioctl_t ioctl_info;
2209e39c5baSBill Taylor int status = 0;
2219e39c5baSBill Taylor
2229e39c5baSBill Taylor /*
2239e39c5baSBill Taylor * Check that flash init ioctl has been called first. And check
2249e39c5baSBill Taylor * that the same dev_t that called init is the one calling read now.
2259e39c5baSBill Taylor */
2269e39c5baSBill Taylor mutex_enter(&state->ts_fw_flashlock);
2279e39c5baSBill Taylor if ((state->ts_fw_flashdev != dev) ||
2289e39c5baSBill Taylor (state->ts_fw_flashstarted == 0)) {
2299e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock);
2309e39c5baSBill Taylor return (EIO);
2319e39c5baSBill Taylor }
2329e39c5baSBill Taylor
2339e39c5baSBill Taylor /* copy user struct to kernel */
2349e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
2359e39c5baSBill Taylor if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
2369e39c5baSBill Taylor tavor_flash_ioctl32_t info32;
2379e39c5baSBill Taylor
2389e39c5baSBill Taylor if (ddi_copyin((void *)arg, &info32,
2399e39c5baSBill Taylor sizeof (tavor_flash_ioctl32_t), mode) != 0) {
2409e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock);
2419e39c5baSBill Taylor return (EFAULT);
2429e39c5baSBill Taylor }
2439e39c5baSBill Taylor ioctl_info.tf_type = info32.tf_type;
2449e39c5baSBill Taylor ioctl_info.tf_sector = (caddr_t)(uintptr_t)info32.tf_sector;
2459e39c5baSBill Taylor ioctl_info.tf_sector_num = info32.tf_sector_num;
2469e39c5baSBill Taylor ioctl_info.tf_addr = info32.tf_addr;
2479e39c5baSBill Taylor } else
2489e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
2499e39c5baSBill Taylor if (ddi_copyin((void *)arg, &ioctl_info, sizeof (tavor_flash_ioctl_t),
2509e39c5baSBill Taylor mode) != 0) {
2519e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock);
2529e39c5baSBill Taylor return (EFAULT);
2539e39c5baSBill Taylor }
2549e39c5baSBill Taylor
2559e39c5baSBill Taylor /*
2569e39c5baSBill Taylor * Determine type of READ ioctl
2579e39c5baSBill Taylor */
2589e39c5baSBill Taylor switch (ioctl_info.tf_type) {
2599e39c5baSBill Taylor case TAVOR_FLASH_READ_SECTOR:
2609e39c5baSBill Taylor /* Check if sector num is too large for flash device */
2619e39c5baSBill Taylor if (ioctl_info.tf_sector_num >=
2629e39c5baSBill Taylor (state->ts_fw_device_sz >> state->ts_fw_log_sector_sz)) {
2639e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock);
2649e39c5baSBill Taylor return (EFAULT);
2659e39c5baSBill Taylor }
2669e39c5baSBill Taylor
2679e39c5baSBill Taylor /* Perform the Sector Read */
2689e39c5baSBill Taylor tavor_flash_reset(state);
2699e39c5baSBill Taylor tavor_flash_read_sector(state, ioctl_info.tf_sector_num);
2709e39c5baSBill Taylor
2719e39c5baSBill Taylor /* copyout the firmware sector image data */
2729e39c5baSBill Taylor if (ddi_copyout(&state->ts_fw_sector[0],
2739e39c5baSBill Taylor &ioctl_info.tf_sector[0], 1 << state->ts_fw_log_sector_sz,
2749e39c5baSBill Taylor mode) != 0) {
2759e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock);
2769e39c5baSBill Taylor return (EFAULT);
2779e39c5baSBill Taylor }
2789e39c5baSBill Taylor break;
2799e39c5baSBill Taylor
2809e39c5baSBill Taylor case TAVOR_FLASH_READ_QUADLET:
2819e39c5baSBill Taylor /* Check if addr is too large for flash device */
2829e39c5baSBill Taylor if (ioctl_info.tf_addr >= state->ts_fw_device_sz) {
2839e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock);
2849e39c5baSBill Taylor return (EFAULT);
2859e39c5baSBill Taylor }
2869e39c5baSBill Taylor
2879e39c5baSBill Taylor /* Perform the Quadlet Read */
2889e39c5baSBill Taylor tavor_flash_reset(state);
2899e39c5baSBill Taylor tavor_flash_read_quadlet(state, &ioctl_info.tf_quadlet,
2909e39c5baSBill Taylor ioctl_info.tf_addr);
2919e39c5baSBill Taylor break;
2929e39c5baSBill Taylor
2939e39c5baSBill Taylor default:
2949e39c5baSBill Taylor status = EIO;
2959e39c5baSBill Taylor break;
2969e39c5baSBill Taylor }
2979e39c5baSBill Taylor
2989e39c5baSBill Taylor /* copy results back to userland */
2999e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
3009e39c5baSBill Taylor if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
3019e39c5baSBill Taylor tavor_flash_ioctl32_t info32;
3029e39c5baSBill Taylor
3039e39c5baSBill Taylor info32.tf_quadlet = ioctl_info.tf_quadlet;
3049e39c5baSBill Taylor info32.tf_type = ioctl_info.tf_type;
3059e39c5baSBill Taylor info32.tf_sector_num = ioctl_info.tf_sector_num;
3069e39c5baSBill Taylor info32.tf_sector = (caddr32_t)(uintptr_t)ioctl_info.tf_sector;
3079e39c5baSBill Taylor info32.tf_addr = ioctl_info.tf_addr;
3089e39c5baSBill Taylor
3099e39c5baSBill Taylor if (ddi_copyout(&info32, (void *)arg,
3109e39c5baSBill Taylor sizeof (tavor_flash_ioctl32_t), mode) != 0) {
3119e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock);
3129e39c5baSBill Taylor return (EFAULT);
3139e39c5baSBill Taylor }
3149e39c5baSBill Taylor } else
3159e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
3169e39c5baSBill Taylor if (ddi_copyout(&ioctl_info, (void *)arg,
3179e39c5baSBill Taylor sizeof (tavor_flash_ioctl_t), mode) != 0) {
3189e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock);
3199e39c5baSBill Taylor return (EFAULT);
3209e39c5baSBill Taylor }
3219e39c5baSBill Taylor
3229e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock);
3239e39c5baSBill Taylor return (status);
3249e39c5baSBill Taylor }
3259e39c5baSBill Taylor
3269e39c5baSBill Taylor /*
3279e39c5baSBill Taylor * tavor_ioctl_flash_write()
3289e39c5baSBill Taylor */
3299e39c5baSBill Taylor static int
tavor_ioctl_flash_write(tavor_state_t * state,dev_t dev,intptr_t arg,int mode)3309e39c5baSBill Taylor tavor_ioctl_flash_write(tavor_state_t *state, dev_t dev, intptr_t arg, int mode)
3319e39c5baSBill Taylor {
3329e39c5baSBill Taylor tavor_flash_ioctl_t ioctl_info;
3339e39c5baSBill Taylor int status = 0;
3349e39c5baSBill Taylor
3359e39c5baSBill Taylor /*
3369e39c5baSBill Taylor * Check that flash init ioctl has been called first. And check
3379e39c5baSBill Taylor * that the same dev_t that called init is the one calling write now.
3389e39c5baSBill Taylor */
3399e39c5baSBill Taylor mutex_enter(&state->ts_fw_flashlock);
3409e39c5baSBill Taylor if ((state->ts_fw_flashdev != dev) ||
3419e39c5baSBill Taylor (state->ts_fw_flashstarted == 0)) {
3429e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock);
3439e39c5baSBill Taylor return (EIO);
3449e39c5baSBill Taylor }
3459e39c5baSBill Taylor
3469e39c5baSBill Taylor /* copy user struct to kernel */
3479e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
3489e39c5baSBill Taylor if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
3499e39c5baSBill Taylor tavor_flash_ioctl32_t info32;
3509e39c5baSBill Taylor
3519e39c5baSBill Taylor if (ddi_copyin((void *)arg, &info32,
3529e39c5baSBill Taylor sizeof (tavor_flash_ioctl32_t), mode) != 0) {
3539e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock);
3549e39c5baSBill Taylor return (EFAULT);
3559e39c5baSBill Taylor }
3569e39c5baSBill Taylor ioctl_info.tf_type = info32.tf_type;
3579e39c5baSBill Taylor ioctl_info.tf_sector = (caddr_t)(uintptr_t)info32.tf_sector;
3589e39c5baSBill Taylor ioctl_info.tf_sector_num = info32.tf_sector_num;
3599e39c5baSBill Taylor ioctl_info.tf_addr = info32.tf_addr;
3609e39c5baSBill Taylor ioctl_info.tf_byte = info32.tf_byte;
3619e39c5baSBill Taylor } else
3629e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
3639e39c5baSBill Taylor if (ddi_copyin((void *)arg, &ioctl_info,
3649e39c5baSBill Taylor sizeof (tavor_flash_ioctl_t), mode) != 0) {
3659e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock);
3669e39c5baSBill Taylor return (EFAULT);
3679e39c5baSBill Taylor }
3689e39c5baSBill Taylor
3699e39c5baSBill Taylor /*
3709e39c5baSBill Taylor * Determine type of WRITE ioctl
3719e39c5baSBill Taylor */
3729e39c5baSBill Taylor switch (ioctl_info.tf_type) {
3739e39c5baSBill Taylor case TAVOR_FLASH_WRITE_SECTOR:
3749e39c5baSBill Taylor /* Check if sector num is too large for flash device */
3759e39c5baSBill Taylor if (ioctl_info.tf_sector_num >=
3769e39c5baSBill Taylor (state->ts_fw_device_sz >> state->ts_fw_log_sector_sz)) {
3779e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock);
3789e39c5baSBill Taylor return (EFAULT);
3799e39c5baSBill Taylor }
3809e39c5baSBill Taylor
3819e39c5baSBill Taylor /* copy in fw sector image data */
3829e39c5baSBill Taylor if (ddi_copyin(&ioctl_info.tf_sector[0],
3839e39c5baSBill Taylor &state->ts_fw_sector[0], 1 << state->ts_fw_log_sector_sz,
3849e39c5baSBill Taylor mode) != 0) {
3859e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock);
3869e39c5baSBill Taylor return (EFAULT);
3879e39c5baSBill Taylor }
3889e39c5baSBill Taylor
3899e39c5baSBill Taylor /* Perform Write Sector */
3909e39c5baSBill Taylor status = tavor_flash_write_sector(state,
3919e39c5baSBill Taylor ioctl_info.tf_sector_num);
3929e39c5baSBill Taylor break;
3939e39c5baSBill Taylor
3949e39c5baSBill Taylor case TAVOR_FLASH_WRITE_BYTE:
3959e39c5baSBill Taylor /* Check if addr is too large for flash device */
3969e39c5baSBill Taylor if (ioctl_info.tf_addr >= state->ts_fw_device_sz) {
3979e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock);
3989e39c5baSBill Taylor return (EFAULT);
3999e39c5baSBill Taylor }
4009e39c5baSBill Taylor
4019e39c5baSBill Taylor /* Perform Write Byte */
4029e39c5baSBill Taylor tavor_flash_bank(state, ioctl_info.tf_addr);
4039e39c5baSBill Taylor tavor_flash_reset(state);
4049e39c5baSBill Taylor status = tavor_flash_write_byte(state, ioctl_info.tf_addr,
4059e39c5baSBill Taylor ioctl_info.tf_byte);
4069e39c5baSBill Taylor tavor_flash_reset(state);
4079e39c5baSBill Taylor break;
4089e39c5baSBill Taylor
4099e39c5baSBill Taylor default:
4109e39c5baSBill Taylor status = EIO;
4119e39c5baSBill Taylor break;
4129e39c5baSBill Taylor }
4139e39c5baSBill Taylor
4149e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock);
4159e39c5baSBill Taylor return (status);
4169e39c5baSBill Taylor }
4179e39c5baSBill Taylor
4189e39c5baSBill Taylor /*
4199e39c5baSBill Taylor * tavor_ioctl_flash_erase()
4209e39c5baSBill Taylor */
4219e39c5baSBill Taylor static int
tavor_ioctl_flash_erase(tavor_state_t * state,dev_t dev,intptr_t arg,int mode)4229e39c5baSBill Taylor tavor_ioctl_flash_erase(tavor_state_t *state, dev_t dev, intptr_t arg, int mode)
4239e39c5baSBill Taylor {
4249e39c5baSBill Taylor tavor_flash_ioctl_t ioctl_info;
4259e39c5baSBill Taylor int status = 0;
4269e39c5baSBill Taylor
4279e39c5baSBill Taylor /*
4289e39c5baSBill Taylor * Check that flash init ioctl has been called first. And check
4299e39c5baSBill Taylor * that the same dev_t that called init is the one calling erase now.
4309e39c5baSBill Taylor */
4319e39c5baSBill Taylor mutex_enter(&state->ts_fw_flashlock);
4329e39c5baSBill Taylor if ((state->ts_fw_flashdev != dev) ||
4339e39c5baSBill Taylor (state->ts_fw_flashstarted == 0)) {
4349e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock);
4359e39c5baSBill Taylor return (EIO);
4369e39c5baSBill Taylor }
4379e39c5baSBill Taylor
4389e39c5baSBill Taylor /* copy user struct to kernel */
4399e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
4409e39c5baSBill Taylor if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
4419e39c5baSBill Taylor tavor_flash_ioctl32_t info32;
4429e39c5baSBill Taylor
4439e39c5baSBill Taylor if (ddi_copyin((void *)arg, &info32,
4449e39c5baSBill Taylor sizeof (tavor_flash_ioctl32_t), mode) != 0) {
4459e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock);
4469e39c5baSBill Taylor return (EFAULT);
4479e39c5baSBill Taylor }
4489e39c5baSBill Taylor ioctl_info.tf_type = info32.tf_type;
4499e39c5baSBill Taylor ioctl_info.tf_sector_num = info32.tf_sector_num;
4509e39c5baSBill Taylor } else
4519e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
4529e39c5baSBill Taylor if (ddi_copyin((void *)arg, &ioctl_info, sizeof (tavor_flash_ioctl_t),
4539e39c5baSBill Taylor mode) != 0) {
4549e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock);
4559e39c5baSBill Taylor return (EFAULT);
4569e39c5baSBill Taylor }
4579e39c5baSBill Taylor
4589e39c5baSBill Taylor /*
4599e39c5baSBill Taylor * Determine type of ERASE ioctl
4609e39c5baSBill Taylor */
4619e39c5baSBill Taylor switch (ioctl_info.tf_type) {
4629e39c5baSBill Taylor case TAVOR_FLASH_ERASE_SECTOR:
4639e39c5baSBill Taylor /* Check if sector num is too large for flash device */
4649e39c5baSBill Taylor if (ioctl_info.tf_sector_num >=
4659e39c5baSBill Taylor (state->ts_fw_device_sz >> state->ts_fw_log_sector_sz)) {
4669e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock);
4679e39c5baSBill Taylor return (EFAULT);
4689e39c5baSBill Taylor }
4699e39c5baSBill Taylor
4709e39c5baSBill Taylor /* Perform Sector Erase */
4719e39c5baSBill Taylor status = tavor_flash_erase_sector(state,
4729e39c5baSBill Taylor ioctl_info.tf_sector_num);
4739e39c5baSBill Taylor break;
4749e39c5baSBill Taylor
4759e39c5baSBill Taylor case TAVOR_FLASH_ERASE_CHIP:
4769e39c5baSBill Taylor /* Perform Chip Erase */
4779e39c5baSBill Taylor status = tavor_flash_erase_chip(state);
4789e39c5baSBill Taylor break;
4799e39c5baSBill Taylor
4809e39c5baSBill Taylor default:
4819e39c5baSBill Taylor status = EIO;
4829e39c5baSBill Taylor break;
4839e39c5baSBill Taylor }
4849e39c5baSBill Taylor
4859e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock);
4869e39c5baSBill Taylor return (status);
4879e39c5baSBill Taylor }
4889e39c5baSBill Taylor
4899e39c5baSBill Taylor /*
4909e39c5baSBill Taylor * tavor_ioctl_flash_init()
4919e39c5baSBill Taylor */
4929e39c5baSBill Taylor static int
tavor_ioctl_flash_init(tavor_state_t * state,dev_t dev,intptr_t arg,int mode)4939e39c5baSBill Taylor tavor_ioctl_flash_init(tavor_state_t *state, dev_t dev, intptr_t arg, int mode)
4949e39c5baSBill Taylor {
4959e39c5baSBill Taylor tavor_flash_init_ioctl_t init_info;
4969e39c5baSBill Taylor int ret;
4979e39c5baSBill Taylor int intel_xcmd = 0;
4989e39c5baSBill Taylor
4999e39c5baSBill Taylor /*
5009e39c5baSBill Taylor * init cannot be called more than once. If we have already init'd the
5019e39c5baSBill Taylor * flash, return directly.
5029e39c5baSBill Taylor */
5039e39c5baSBill Taylor mutex_enter(&state->ts_fw_flashlock);
5049e39c5baSBill Taylor if (state->ts_fw_flashstarted == 1) {
5059e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock);
5069e39c5baSBill Taylor return (EIO);
5079e39c5baSBill Taylor }
5089e39c5baSBill Taylor
5099e39c5baSBill Taylor /* copyin the user struct to kernel */
5109e39c5baSBill Taylor if (ddi_copyin((void *)arg, &init_info,
5119e39c5baSBill Taylor sizeof (tavor_flash_init_ioctl_t), mode) != 0) {
5129e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock);
5139e39c5baSBill Taylor return (EFAULT);
5149e39c5baSBill Taylor }
5159e39c5baSBill Taylor
5169e39c5baSBill Taylor /* Init Flash */
5179e39c5baSBill Taylor tavor_flash_init(state);
5189e39c5baSBill Taylor
5199e39c5baSBill Taylor /* Read CFI info */
5209e39c5baSBill Taylor tavor_flash_cfi_init(state, &init_info.tf_cfi_info[0], &intel_xcmd);
5219e39c5baSBill Taylor
5229e39c5baSBill Taylor /*
5239e39c5baSBill Taylor * Return error if the command set is unknown.
5249e39c5baSBill Taylor */
5259e39c5baSBill Taylor if (state->ts_fw_cmdset == TAVOR_FLASH_UNKNOWN_CMDSET) {
5269e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock);
5279e39c5baSBill Taylor return (EFAULT);
5289e39c5baSBill Taylor }
5299e39c5baSBill Taylor
5309e39c5baSBill Taylor /* Read HWREV - least significant 8 bits is revision ID */
5319e39c5baSBill Taylor init_info.tf_hwrev = pci_config_get32(state->ts_pci_cfghdl,
5329e39c5baSBill Taylor TAVOR_HW_FLASH_CFG_HWREV) & 0xFF;
5339e39c5baSBill Taylor
5349e39c5baSBill Taylor /* Fill in the firmwate revision numbers */
5359e39c5baSBill Taylor init_info.tf_fwrev.tfi_maj = state->ts_fw.fw_rev_major;
5369e39c5baSBill Taylor init_info.tf_fwrev.tfi_min = state->ts_fw.fw_rev_minor;
5379e39c5baSBill Taylor init_info.tf_fwrev.tfi_sub = state->ts_fw.fw_rev_subminor;
5389e39c5baSBill Taylor
5399e39c5baSBill Taylor /* Alloc flash mem for one sector size */
5409e39c5baSBill Taylor state->ts_fw_sector = (uint32_t *)kmem_zalloc(1 <<
5419e39c5baSBill Taylor state->ts_fw_log_sector_sz, KM_SLEEP);
5429e39c5baSBill Taylor
5439e39c5baSBill Taylor /* Set HW part number and length */
5449e39c5baSBill Taylor init_info.tf_pn_len = state->ts_hca_pn_len;
5459e39c5baSBill Taylor if (state->ts_hca_pn_len != 0) {
5469e39c5baSBill Taylor (void) memcpy(init_info.tf_hwpn, state->ts_hca_pn,
5479e39c5baSBill Taylor state->ts_hca_pn_len);
5489e39c5baSBill Taylor }
5499e39c5baSBill Taylor
5509e39c5baSBill Taylor /* Copy ioctl results back to userland */
5519e39c5baSBill Taylor if (ddi_copyout(&init_info, (void *)arg,
5529e39c5baSBill Taylor sizeof (tavor_flash_init_ioctl_t), mode) != 0) {
5539e39c5baSBill Taylor
5549e39c5baSBill Taylor tavor_ioctl_flash_cleanup_nolock(state);
5559e39c5baSBill Taylor
5569e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock);
5579e39c5baSBill Taylor return (EFAULT);
5589e39c5baSBill Taylor }
5599e39c5baSBill Taylor
5609e39c5baSBill Taylor /* Set flash state to started */
5619e39c5baSBill Taylor state->ts_fw_flashstarted = 1;
5629e39c5baSBill Taylor state->ts_fw_flashdev = dev;
5639e39c5baSBill Taylor
5649e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock);
5659e39c5baSBill Taylor
5669e39c5baSBill Taylor /*
5679e39c5baSBill Taylor * If "flash init" is successful, add an "on close" callback to the
5689e39c5baSBill Taylor * current dev node to ensure that "flash fini" gets called later
5699e39c5baSBill Taylor * even if the userland process prematurely exits.
5709e39c5baSBill Taylor */
5719e39c5baSBill Taylor ret = tavor_umap_db_set_onclose_cb(dev,
5729e39c5baSBill Taylor TAVOR_ONCLOSE_FLASH_INPROGRESS,
5739e39c5baSBill Taylor (void (*)(void *))tavor_ioctl_flash_cleanup, state);
5749e39c5baSBill Taylor if (ret != DDI_SUCCESS) {
5759e39c5baSBill Taylor (void) tavor_ioctl_flash_fini(state, dev);
5769e39c5baSBill Taylor
5779e39c5baSBill Taylor return (EFAULT);
5789e39c5baSBill Taylor }
5799e39c5baSBill Taylor
5809e39c5baSBill Taylor return (0);
5819e39c5baSBill Taylor }
5829e39c5baSBill Taylor
5839e39c5baSBill Taylor /*
5849e39c5baSBill Taylor * tavor_ioctl_flash_fini()
5859e39c5baSBill Taylor */
5869e39c5baSBill Taylor static int
tavor_ioctl_flash_fini(tavor_state_t * state,dev_t dev)5879e39c5baSBill Taylor tavor_ioctl_flash_fini(tavor_state_t *state, dev_t dev)
5889e39c5baSBill Taylor {
5899e39c5baSBill Taylor int ret;
5909e39c5baSBill Taylor
5919e39c5baSBill Taylor /*
5929e39c5baSBill Taylor * Check that flash init ioctl has been called first. And check
5939e39c5baSBill Taylor * that the same dev_t that called init is the one calling fini now.
5949e39c5baSBill Taylor */
5959e39c5baSBill Taylor mutex_enter(&state->ts_fw_flashlock);
5969e39c5baSBill Taylor if ((state->ts_fw_flashdev != dev) ||
5979e39c5baSBill Taylor (state->ts_fw_flashstarted == 0)) {
5989e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock);
5999e39c5baSBill Taylor return (EIO);
6009e39c5baSBill Taylor }
6019e39c5baSBill Taylor
6029e39c5baSBill Taylor tavor_ioctl_flash_cleanup_nolock(state);
6039e39c5baSBill Taylor
6049e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock);
6059e39c5baSBill Taylor
6069e39c5baSBill Taylor /*
6079e39c5baSBill Taylor * If "flash fini" is successful, remove the "on close" callback
6089e39c5baSBill Taylor * that was setup during "flash init".
6099e39c5baSBill Taylor */
6109e39c5baSBill Taylor ret = tavor_umap_db_clear_onclose_cb(dev,
6119e39c5baSBill Taylor TAVOR_ONCLOSE_FLASH_INPROGRESS);
6129e39c5baSBill Taylor if (ret != DDI_SUCCESS) {
6139e39c5baSBill Taylor return (EFAULT);
6149e39c5baSBill Taylor }
6159e39c5baSBill Taylor
6169e39c5baSBill Taylor return (0);
6179e39c5baSBill Taylor }
6189e39c5baSBill Taylor
6199e39c5baSBill Taylor
6209e39c5baSBill Taylor /*
6219e39c5baSBill Taylor * tavor_ioctl_flash_cleanup()
6229e39c5baSBill Taylor */
6239e39c5baSBill Taylor static void
tavor_ioctl_flash_cleanup(tavor_state_t * state)6249e39c5baSBill Taylor tavor_ioctl_flash_cleanup(tavor_state_t *state)
6259e39c5baSBill Taylor {
6269e39c5baSBill Taylor mutex_enter(&state->ts_fw_flashlock);
6279e39c5baSBill Taylor tavor_ioctl_flash_cleanup_nolock(state);
6289e39c5baSBill Taylor mutex_exit(&state->ts_fw_flashlock);
6299e39c5baSBill Taylor }
6309e39c5baSBill Taylor
6319e39c5baSBill Taylor
6329e39c5baSBill Taylor /*
6339e39c5baSBill Taylor * tavor_ioctl_flash_cleanup_nolock()
6349e39c5baSBill Taylor */
6359e39c5baSBill Taylor static void
tavor_ioctl_flash_cleanup_nolock(tavor_state_t * state)6369e39c5baSBill Taylor tavor_ioctl_flash_cleanup_nolock(tavor_state_t *state)
6379e39c5baSBill Taylor {
6389e39c5baSBill Taylor ASSERT(MUTEX_HELD(&state->ts_fw_flashlock));
6399e39c5baSBill Taylor
6409e39c5baSBill Taylor /* free flash mem */
6419e39c5baSBill Taylor kmem_free(state->ts_fw_sector, 1 << state->ts_fw_log_sector_sz);
6429e39c5baSBill Taylor
6439e39c5baSBill Taylor /* Fini the Flash */
6449e39c5baSBill Taylor tavor_flash_fini(state);
6459e39c5baSBill Taylor
6469e39c5baSBill Taylor /* Set flash state to fini */
6479e39c5baSBill Taylor state->ts_fw_flashstarted = 0;
6489e39c5baSBill Taylor state->ts_fw_flashdev = 0;
6499e39c5baSBill Taylor }
6509e39c5baSBill Taylor
6519e39c5baSBill Taylor
6529e39c5baSBill Taylor /*
6539e39c5baSBill Taylor * tavor_ioctl_info()
6549e39c5baSBill Taylor */
6559e39c5baSBill Taylor static int
tavor_ioctl_info(tavor_state_t * state,dev_t dev,intptr_t arg,int mode)6569e39c5baSBill Taylor tavor_ioctl_info(tavor_state_t *state, dev_t dev, intptr_t arg, int mode)
6579e39c5baSBill Taylor {
6589e39c5baSBill Taylor tavor_info_ioctl_t info;
6599e39c5baSBill Taylor tavor_flash_init_ioctl_t init_info;
6609e39c5baSBill Taylor
6619e39c5baSBill Taylor /*
6629e39c5baSBill Taylor * Access to Tavor VTS ioctls is not allowed in "maintenance mode".
6639e39c5baSBill Taylor */
6649e39c5baSBill Taylor if (state->ts_operational_mode == TAVOR_MAINTENANCE_MODE) {
6659e39c5baSBill Taylor return (EFAULT);
6669e39c5baSBill Taylor }
6679e39c5baSBill Taylor
6689e39c5baSBill Taylor /* copyin the user struct to kernel */
6699e39c5baSBill Taylor if (ddi_copyin((void *)arg, &info, sizeof (tavor_info_ioctl_t),
6709e39c5baSBill Taylor mode) != 0) {
6719e39c5baSBill Taylor return (EFAULT);
6729e39c5baSBill Taylor }
6739e39c5baSBill Taylor
6749e39c5baSBill Taylor /*
6759e39c5baSBill Taylor * Check ioctl revision
6769e39c5baSBill Taylor */
6779e39c5baSBill Taylor if (info.ti_revision != TAVOR_VTS_IOCTL_REVISION) {
6789e39c5baSBill Taylor return (EINVAL);
6799e39c5baSBill Taylor }
6809e39c5baSBill Taylor
6819e39c5baSBill Taylor /*
6829e39c5baSBill Taylor * If the 'fw_device_sz' has not been initialized yet, we initialize it
6839e39c5baSBill Taylor * here. This is done by leveraging the
6849e39c5baSBill Taylor * tavor_ioctl_flash_init()/fini() calls. We also hold our own mutex
6859e39c5baSBill Taylor * around this operation in case we have multiple VTS threads in
6869e39c5baSBill Taylor * process at the same time.
6879e39c5baSBill Taylor */
6889e39c5baSBill Taylor mutex_enter(&state->ts_info_lock);
6899e39c5baSBill Taylor if (state->ts_fw_device_sz == 0) {
6909e39c5baSBill Taylor if (tavor_ioctl_flash_init(state, dev, (intptr_t)&init_info,
6919e39c5baSBill Taylor (FKIOCTL | mode)) != 0) {
6929e39c5baSBill Taylor mutex_exit(&state->ts_info_lock);
6939e39c5baSBill Taylor return (EFAULT);
6949e39c5baSBill Taylor }
6959e39c5baSBill Taylor (void) tavor_ioctl_flash_fini(state, dev);
6969e39c5baSBill Taylor }
6979e39c5baSBill Taylor mutex_exit(&state->ts_info_lock);
6989e39c5baSBill Taylor
6999e39c5baSBill Taylor info.ti_hw_rev = state->ts_adapter.rev_id;
7009e39c5baSBill Taylor info.ti_flash_sz = state->ts_fw_device_sz;
7019e39c5baSBill Taylor info.ti_fw_rev.tfi_maj = state->ts_fw.fw_rev_major;
7029e39c5baSBill Taylor info.ti_fw_rev.tfi_min = state->ts_fw.fw_rev_minor;
7039e39c5baSBill Taylor info.ti_fw_rev.tfi_sub = state->ts_fw.fw_rev_subminor;
7049e39c5baSBill Taylor info.ti_mem_start_offset = 0;
7059e39c5baSBill Taylor info.ti_mem_end_offset = state->ts_ddr.ddr_endaddr -
7069e39c5baSBill Taylor state->ts_ddr.ddr_baseaddr;
7079e39c5baSBill Taylor
7089e39c5baSBill Taylor /* Copy ioctl results back to user struct */
7099e39c5baSBill Taylor if (ddi_copyout(&info, (void *)arg, sizeof (tavor_info_ioctl_t),
7109e39c5baSBill Taylor mode) != 0) {
7119e39c5baSBill Taylor return (EFAULT);
7129e39c5baSBill Taylor }
7139e39c5baSBill Taylor
7149e39c5baSBill Taylor return (0);
7159e39c5baSBill Taylor }
7169e39c5baSBill Taylor
7179e39c5baSBill Taylor /*
7189e39c5baSBill Taylor * tavor_ioctl_ports()
7199e39c5baSBill Taylor */
7209e39c5baSBill Taylor static int
tavor_ioctl_ports(tavor_state_t * state,intptr_t arg,int mode)7219e39c5baSBill Taylor tavor_ioctl_ports(tavor_state_t *state, intptr_t arg, int mode)
7229e39c5baSBill Taylor {
7239e39c5baSBill Taylor tavor_ports_ioctl_t info;
7249e39c5baSBill Taylor tavor_stat_port_ioctl_t portstat;
7259e39c5baSBill Taylor ibt_hca_portinfo_t pi;
7269e39c5baSBill Taylor uint_t tbl_size;
7279e39c5baSBill Taylor ib_gid_t *sgid_tbl;
7289e39c5baSBill Taylor ib_pkey_t *pkey_tbl;
7299e39c5baSBill Taylor int i;
7309e39c5baSBill Taylor
7319e39c5baSBill Taylor /*
7329e39c5baSBill Taylor * Access to Tavor VTS ioctls is not allowed in "maintenance mode".
7339e39c5baSBill Taylor */
7349e39c5baSBill Taylor if (state->ts_operational_mode == TAVOR_MAINTENANCE_MODE) {
7359e39c5baSBill Taylor return (EFAULT);
7369e39c5baSBill Taylor }
7379e39c5baSBill Taylor
7389e39c5baSBill Taylor /* copyin the user struct to kernel */
7399e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
7409e39c5baSBill Taylor if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
7419e39c5baSBill Taylor tavor_ports_ioctl32_t info32;
7429e39c5baSBill Taylor
7439e39c5baSBill Taylor if (ddi_copyin((void *)arg, &info32,
7449e39c5baSBill Taylor sizeof (tavor_ports_ioctl32_t), mode) != 0) {
7459e39c5baSBill Taylor return (EFAULT);
7469e39c5baSBill Taylor }
7479e39c5baSBill Taylor info.tp_revision = info32.tp_revision;
7489e39c5baSBill Taylor info.tp_ports =
7499e39c5baSBill Taylor (tavor_stat_port_ioctl_t *)(uintptr_t)info32.tp_ports;
7509e39c5baSBill Taylor info.tp_num_ports = info32.tp_num_ports;
7519e39c5baSBill Taylor
7529e39c5baSBill Taylor } else
7539e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
7549e39c5baSBill Taylor if (ddi_copyin((void *)arg, &info, sizeof (tavor_ports_ioctl_t),
7559e39c5baSBill Taylor mode) != 0) {
7569e39c5baSBill Taylor return (EFAULT);
7579e39c5baSBill Taylor }
7589e39c5baSBill Taylor
7599e39c5baSBill Taylor /*
7609e39c5baSBill Taylor * Check ioctl revision
7619e39c5baSBill Taylor */
7629e39c5baSBill Taylor if (info.tp_revision != TAVOR_VTS_IOCTL_REVISION) {
7639e39c5baSBill Taylor return (EINVAL);
7649e39c5baSBill Taylor }
7659e39c5baSBill Taylor
7669e39c5baSBill Taylor /* Allocate space for temporary GID table/PKey table */
7679e39c5baSBill Taylor tbl_size = (1 << state->ts_cfg_profile->cp_log_max_gidtbl);
7689e39c5baSBill Taylor sgid_tbl = (ib_gid_t *)kmem_zalloc(tbl_size * sizeof (ib_gid_t),
7699e39c5baSBill Taylor KM_SLEEP);
7709e39c5baSBill Taylor tbl_size = (1 << state->ts_cfg_profile->cp_log_max_pkeytbl);
7719e39c5baSBill Taylor pkey_tbl = (ib_pkey_t *)kmem_zalloc(tbl_size * sizeof (ib_pkey_t),
7729e39c5baSBill Taylor KM_SLEEP);
7739e39c5baSBill Taylor
7749e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*sgid_tbl, *pkey_tbl))
7759e39c5baSBill Taylor
7769e39c5baSBill Taylor /*
7779e39c5baSBill Taylor * Setup the number of ports, then loop through all ports and
7789e39c5baSBill Taylor * query properties of each.
7799e39c5baSBill Taylor */
7809e39c5baSBill Taylor info.tp_num_ports = (uint8_t)state->ts_cfg_profile->cp_num_ports;
7819e39c5baSBill Taylor for (i = 0; i < info.tp_num_ports; i++) {
7829e39c5baSBill Taylor /*
7839e39c5baSBill Taylor * Get portstate information from the device. If
7849e39c5baSBill Taylor * tavor_port_query() fails, leave zeroes in user
7859e39c5baSBill Taylor * struct port entry and continue.
7869e39c5baSBill Taylor */
7879e39c5baSBill Taylor bzero(&pi, sizeof (ibt_hca_portinfo_t));
7889e39c5baSBill Taylor pi.p_sgid_tbl = sgid_tbl;
7899e39c5baSBill Taylor pi.p_pkey_tbl = pkey_tbl;
790*2570281cSToomas Soome (void) tavor_port_query(state, i + 1, &pi);
7919e39c5baSBill Taylor
7929e39c5baSBill Taylor portstat.tsp_port_num = pi.p_port_num;
7939e39c5baSBill Taylor portstat.tsp_state = pi.p_linkstate;
7949e39c5baSBill Taylor portstat.tsp_guid = pi.p_sgid_tbl[0].gid_guid;
7959e39c5baSBill Taylor
7969e39c5baSBill Taylor /*
7979e39c5baSBill Taylor * Copy queried port results back to user struct. If
7989e39c5baSBill Taylor * this fails, then break out of loop, attempt to copy
7999e39c5baSBill Taylor * out remaining info to user struct, and return (without
8009e39c5baSBill Taylor * error).
8019e39c5baSBill Taylor */
8029e39c5baSBill Taylor if (ddi_copyout(&portstat,
8039e39c5baSBill Taylor &(((tavor_stat_port_ioctl_t *)info.tp_ports)[i]),
8049e39c5baSBill Taylor sizeof (tavor_stat_port_ioctl_t), mode) != 0) {
8059e39c5baSBill Taylor break;
8069e39c5baSBill Taylor }
8079e39c5baSBill Taylor }
8089e39c5baSBill Taylor
8099e39c5baSBill Taylor /* Free the temporary space used for GID table/PKey table */
8109e39c5baSBill Taylor tbl_size = (1 << state->ts_cfg_profile->cp_log_max_gidtbl);
8119e39c5baSBill Taylor kmem_free(sgid_tbl, tbl_size * sizeof (ib_gid_t));
8129e39c5baSBill Taylor tbl_size = (1 << state->ts_cfg_profile->cp_log_max_pkeytbl);
8139e39c5baSBill Taylor kmem_free(pkey_tbl, tbl_size * sizeof (ib_pkey_t));
8149e39c5baSBill Taylor
8159e39c5baSBill Taylor /* Copy ioctl results back to user struct */
8169e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
8179e39c5baSBill Taylor if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
8189e39c5baSBill Taylor tavor_ports_ioctl32_t info32;
8199e39c5baSBill Taylor
8209e39c5baSBill Taylor info32.tp_revision = info.tp_revision;
8219e39c5baSBill Taylor info32.tp_ports = (caddr32_t)(uintptr_t)info.tp_ports;
8229e39c5baSBill Taylor info32.tp_num_ports = info.tp_num_ports;
8239e39c5baSBill Taylor
8249e39c5baSBill Taylor if (ddi_copyout(&info32, (void *)arg,
8259e39c5baSBill Taylor sizeof (tavor_ports_ioctl32_t), mode) != 0) {
8269e39c5baSBill Taylor return (EFAULT);
8279e39c5baSBill Taylor }
8289e39c5baSBill Taylor } else
8299e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
8309e39c5baSBill Taylor if (ddi_copyout(&info, (void *)arg, sizeof (tavor_ports_ioctl_t),
8319e39c5baSBill Taylor mode) != 0) {
8329e39c5baSBill Taylor return (EFAULT);
8339e39c5baSBill Taylor }
8349e39c5baSBill Taylor
8359e39c5baSBill Taylor return (0);
8369e39c5baSBill Taylor }
8379e39c5baSBill Taylor
8389e39c5baSBill Taylor /*
8399e39c5baSBill Taylor * tavor_ioctl_loopback()
8409e39c5baSBill Taylor */
8419e39c5baSBill Taylor static int
tavor_ioctl_loopback(tavor_state_t * state,intptr_t arg,int mode)8429e39c5baSBill Taylor tavor_ioctl_loopback(tavor_state_t *state, intptr_t arg, int mode)
8439e39c5baSBill Taylor {
8449e39c5baSBill Taylor tavor_loopback_ioctl_t lb;
8459e39c5baSBill Taylor tavor_loopback_state_t lstate;
8469e39c5baSBill Taylor ibt_hca_portinfo_t pi;
8479e39c5baSBill Taylor uint_t tbl_size, loopmax, max_usec;
8489e39c5baSBill Taylor ib_gid_t *sgid_tbl;
8499e39c5baSBill Taylor ib_pkey_t *pkey_tbl;
8509e39c5baSBill Taylor int j, iter, ret;
8519e39c5baSBill Taylor
8529e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(lstate))
8539e39c5baSBill Taylor
8549e39c5baSBill Taylor /*
8559e39c5baSBill Taylor * Access to Tavor VTS ioctls is not allowed in "maintenance mode".
8569e39c5baSBill Taylor */
8579e39c5baSBill Taylor if (state->ts_operational_mode == TAVOR_MAINTENANCE_MODE) {
8589e39c5baSBill Taylor return (EFAULT);
8599e39c5baSBill Taylor }
8609e39c5baSBill Taylor
8619e39c5baSBill Taylor /* copyin the user struct to kernel */
8629e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
8639e39c5baSBill Taylor if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
8649e39c5baSBill Taylor tavor_loopback_ioctl32_t lb32;
8659e39c5baSBill Taylor
8669e39c5baSBill Taylor if (ddi_copyin((void *)arg, &lb32,
8679e39c5baSBill Taylor sizeof (tavor_loopback_ioctl32_t), mode) != 0) {
8689e39c5baSBill Taylor return (EFAULT);
8699e39c5baSBill Taylor }
8709e39c5baSBill Taylor lb.tlb_revision = lb32.tlb_revision;
8719e39c5baSBill Taylor lb.tlb_send_buf = (caddr_t)(uintptr_t)lb32.tlb_send_buf;
8729e39c5baSBill Taylor lb.tlb_fail_buf = (caddr_t)(uintptr_t)lb32.tlb_fail_buf;
8739e39c5baSBill Taylor lb.tlb_buf_sz = lb32.tlb_buf_sz;
8749e39c5baSBill Taylor lb.tlb_num_iter = lb32.tlb_num_iter;
8759e39c5baSBill Taylor lb.tlb_pass_done = lb32.tlb_pass_done;
8769e39c5baSBill Taylor lb.tlb_timeout = lb32.tlb_timeout;
8779e39c5baSBill Taylor lb.tlb_error_type = lb32.tlb_error_type;
8789e39c5baSBill Taylor lb.tlb_port_num = lb32.tlb_port_num;
8799e39c5baSBill Taylor lb.tlb_num_retry = lb32.tlb_num_retry;
8809e39c5baSBill Taylor } else
8819e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
8829e39c5baSBill Taylor if (ddi_copyin((void *)arg, &lb, sizeof (tavor_loopback_ioctl_t),
8839e39c5baSBill Taylor mode) != 0) {
8849e39c5baSBill Taylor return (EFAULT);
8859e39c5baSBill Taylor }
8869e39c5baSBill Taylor
8879e39c5baSBill Taylor /* Initialize the internal loopback test state structure */
8889e39c5baSBill Taylor bzero(&lstate, sizeof (tavor_loopback_state_t));
8899e39c5baSBill Taylor
8909e39c5baSBill Taylor /*
8919e39c5baSBill Taylor * Check ioctl revision
8929e39c5baSBill Taylor */
8939e39c5baSBill Taylor if (lb.tlb_revision != TAVOR_VTS_IOCTL_REVISION) {
8949e39c5baSBill Taylor lb.tlb_error_type = TAVOR_LOOPBACK_INVALID_REVISION;
8959e39c5baSBill Taylor (void) tavor_loopback_copyout(&lb, arg, mode);
8969e39c5baSBill Taylor return (EINVAL);
8979e39c5baSBill Taylor }
8989e39c5baSBill Taylor
8999e39c5baSBill Taylor /* Validate that specified port number is legal */
9009e39c5baSBill Taylor if (!tavor_portnum_is_valid(state, lb.tlb_port_num)) {
9019e39c5baSBill Taylor lb.tlb_error_type = TAVOR_LOOPBACK_INVALID_PORT;
9029e39c5baSBill Taylor (void) tavor_loopback_copyout(&lb, arg, mode);
9039e39c5baSBill Taylor return (EINVAL);
9049e39c5baSBill Taylor }
9059e39c5baSBill Taylor
9069e39c5baSBill Taylor /* Allocate space for temporary GID table/PKey table */
9079e39c5baSBill Taylor tbl_size = (1 << state->ts_cfg_profile->cp_log_max_gidtbl);
9089e39c5baSBill Taylor sgid_tbl = (ib_gid_t *)kmem_zalloc(tbl_size * sizeof (ib_gid_t),
9099e39c5baSBill Taylor KM_SLEEP);
9109e39c5baSBill Taylor tbl_size = (1 << state->ts_cfg_profile->cp_log_max_pkeytbl);
9119e39c5baSBill Taylor pkey_tbl = (ib_pkey_t *)kmem_zalloc(tbl_size * sizeof (ib_pkey_t),
9129e39c5baSBill Taylor KM_SLEEP);
9139e39c5baSBill Taylor
9149e39c5baSBill Taylor /*
9159e39c5baSBill Taylor * Get portstate information from specific port on device
9169e39c5baSBill Taylor */
9179e39c5baSBill Taylor bzero(&pi, sizeof (ibt_hca_portinfo_t));
9189e39c5baSBill Taylor pi.p_sgid_tbl = sgid_tbl;
9199e39c5baSBill Taylor pi.p_pkey_tbl = pkey_tbl;
9209e39c5baSBill Taylor if (tavor_port_query(state, lb.tlb_port_num, &pi) != 0) {
9219e39c5baSBill Taylor /* Free the temporary space used for GID table/PKey table */
9229e39c5baSBill Taylor tbl_size = (1 << state->ts_cfg_profile->cp_log_max_gidtbl);
9239e39c5baSBill Taylor kmem_free(sgid_tbl, tbl_size * sizeof (ib_gid_t));
9249e39c5baSBill Taylor tbl_size = (1 << state->ts_cfg_profile->cp_log_max_pkeytbl);
9259e39c5baSBill Taylor kmem_free(pkey_tbl, tbl_size * sizeof (ib_pkey_t));
9269e39c5baSBill Taylor
9279e39c5baSBill Taylor lb.tlb_error_type = TAVOR_LOOPBACK_INVALID_PORT;
9289e39c5baSBill Taylor (void) tavor_loopback_copyout(&lb, arg, mode);
9299e39c5baSBill Taylor tavor_loopback_free_state(&lstate);
9309e39c5baSBill Taylor return (EINVAL);
9319e39c5baSBill Taylor }
9329e39c5baSBill Taylor
9339e39c5baSBill Taylor lstate.tls_port = pi.p_port_num;
9349e39c5baSBill Taylor lstate.tls_lid = pi.p_base_lid;
9359e39c5baSBill Taylor lstate.tls_pkey_ix = (pi.p_linkstate == TAVOR_PORT_LINK_ACTIVE) ? 1 : 0;
9369e39c5baSBill Taylor lstate.tls_state = state;
9379e39c5baSBill Taylor lstate.tls_retry = lb.tlb_num_retry;
9389e39c5baSBill Taylor
9399e39c5baSBill Taylor /* Free the temporary space used for GID table/PKey table */
9409e39c5baSBill Taylor tbl_size = (1 << state->ts_cfg_profile->cp_log_max_gidtbl);
9419e39c5baSBill Taylor kmem_free(sgid_tbl, tbl_size * sizeof (ib_gid_t));
9429e39c5baSBill Taylor tbl_size = (1 << state->ts_cfg_profile->cp_log_max_pkeytbl);
9439e39c5baSBill Taylor kmem_free(pkey_tbl, tbl_size * sizeof (ib_pkey_t));
9449e39c5baSBill Taylor
9459e39c5baSBill Taylor /*
9469e39c5baSBill Taylor * Compute the timeout duration in usec per the formula:
9479e39c5baSBill Taylor * to_usec_per_retry = 4.096us * (2 ^ supplied_timeout)
9489e39c5baSBill Taylor * (plus we add a little fudge-factor here too)
9499e39c5baSBill Taylor */
9509e39c5baSBill Taylor lstate.tls_timeout = lb.tlb_timeout;
9519e39c5baSBill Taylor max_usec = (4096 * (1 << lstate.tls_timeout)) / 1000;
9529e39c5baSBill Taylor max_usec = max_usec * (lstate.tls_retry + 1);
9539e39c5baSBill Taylor max_usec = max_usec + 10000;
9549e39c5baSBill Taylor
9559e39c5baSBill Taylor /*
9569e39c5baSBill Taylor * Determine how many times we should loop before declaring a
9579e39c5baSBill Taylor * timeout failure.
9589e39c5baSBill Taylor */
9599e39c5baSBill Taylor loopmax = max_usec/TAVOR_VTS_LOOPBACK_MIN_WAIT_DUR;
9609e39c5baSBill Taylor if ((max_usec % TAVOR_VTS_LOOPBACK_MIN_WAIT_DUR) != 0) {
9619e39c5baSBill Taylor loopmax++;
9629e39c5baSBill Taylor }
9639e39c5baSBill Taylor
9649e39c5baSBill Taylor if (lb.tlb_send_buf == NULL || lb.tlb_buf_sz == 0) {
9659e39c5baSBill Taylor lb.tlb_error_type = TAVOR_LOOPBACK_SEND_BUF_INVALID;
9669e39c5baSBill Taylor (void) tavor_loopback_copyout(&lb, arg, mode);
9679e39c5baSBill Taylor tavor_loopback_free_state(&lstate);
9689e39c5baSBill Taylor return (EINVAL);
9699e39c5baSBill Taylor }
9709e39c5baSBill Taylor
9719e39c5baSBill Taylor /* Allocate protection domain (PD) */
9729e39c5baSBill Taylor if (tavor_loopback_init(state, &lstate) != 0) {
9739e39c5baSBill Taylor lb.tlb_error_type = lstate.tls_err;
9749e39c5baSBill Taylor (void) tavor_loopback_copyout(&lb, arg, mode);
9759e39c5baSBill Taylor tavor_loopback_free_state(&lstate);
9769e39c5baSBill Taylor return (EFAULT);
9779e39c5baSBill Taylor }
9789e39c5baSBill Taylor
9799e39c5baSBill Taylor /* Allocate and register a TX buffer */
9809e39c5baSBill Taylor if (tavor_loopback_alloc_mem(&lstate, &lstate.tls_tx,
9819e39c5baSBill Taylor lb.tlb_buf_sz) != 0) {
9829e39c5baSBill Taylor lb.tlb_error_type =
9839e39c5baSBill Taylor TAVOR_LOOPBACK_SEND_BUF_MEM_REGION_ALLOC_FAIL;
9849e39c5baSBill Taylor (void) tavor_loopback_copyout(&lb, arg, mode);
9859e39c5baSBill Taylor tavor_loopback_free_state(&lstate);
9869e39c5baSBill Taylor return (EFAULT);
9879e39c5baSBill Taylor }
9889e39c5baSBill Taylor
9899e39c5baSBill Taylor /* Allocate and register an RX buffer */
9909e39c5baSBill Taylor if (tavor_loopback_alloc_mem(&lstate, &lstate.tls_rx,
9919e39c5baSBill Taylor lb.tlb_buf_sz) != 0) {
9929e39c5baSBill Taylor lb.tlb_error_type =
9939e39c5baSBill Taylor TAVOR_LOOPBACK_RECV_BUF_MEM_REGION_ALLOC_FAIL;
9949e39c5baSBill Taylor (void) tavor_loopback_copyout(&lb, arg, mode);
9959e39c5baSBill Taylor tavor_loopback_free_state(&lstate);
9969e39c5baSBill Taylor return (EFAULT);
9979e39c5baSBill Taylor }
9989e39c5baSBill Taylor
9999e39c5baSBill Taylor /* Copy in the transmit buffer data */
10009e39c5baSBill Taylor if (ddi_copyin((void *)lb.tlb_send_buf, lstate.tls_tx.tlc_buf,
10019e39c5baSBill Taylor lb.tlb_buf_sz, mode) != 0) {
10029e39c5baSBill Taylor lb.tlb_error_type = TAVOR_LOOPBACK_SEND_BUF_COPY_FAIL;
10039e39c5baSBill Taylor (void) tavor_loopback_copyout(&lb, arg, mode);
10049e39c5baSBill Taylor tavor_loopback_free_state(&lstate);
10059e39c5baSBill Taylor return (EFAULT);
10069e39c5baSBill Taylor }
10079e39c5baSBill Taylor
10089e39c5baSBill Taylor /* Allocate the transmit QP and CQs */
10099e39c5baSBill Taylor lstate.tls_err = TAVOR_LOOPBACK_XMIT_SEND_CQ_ALLOC_FAIL;
10109e39c5baSBill Taylor if (tavor_loopback_alloc_qps(&lstate, &lstate.tls_tx) != 0) {
10119e39c5baSBill Taylor lb.tlb_error_type = lstate.tls_err;
10129e39c5baSBill Taylor (void) tavor_loopback_copyout(&lb, arg, mode);
10139e39c5baSBill Taylor tavor_loopback_free_state(&lstate);
10149e39c5baSBill Taylor return (EFAULT);
10159e39c5baSBill Taylor }
10169e39c5baSBill Taylor
10179e39c5baSBill Taylor /* Allocate the receive QP and CQs */
10189e39c5baSBill Taylor lstate.tls_err = TAVOR_LOOPBACK_RECV_SEND_CQ_ALLOC_FAIL;
10199e39c5baSBill Taylor if (tavor_loopback_alloc_qps(&lstate, &lstate.tls_rx) != 0) {
10209e39c5baSBill Taylor lb.tlb_error_type = lstate.tls_err;
10219e39c5baSBill Taylor (void) tavor_loopback_copyout(&lb, arg, mode);
10229e39c5baSBill Taylor tavor_loopback_free_state(&lstate);
10239e39c5baSBill Taylor return (EFAULT);
10249e39c5baSBill Taylor }
10259e39c5baSBill Taylor
10269e39c5baSBill Taylor /* Activate the TX QP (connect to RX QP) */
10279e39c5baSBill Taylor lstate.tls_err = TAVOR_LOOPBACK_XMIT_QP_INIT_FAIL;
10289e39c5baSBill Taylor if (tavor_loopback_modify_qp(&lstate, &lstate.tls_tx,
10299e39c5baSBill Taylor lstate.tls_rx.tlc_qp_num) != 0) {
10309e39c5baSBill Taylor lb.tlb_error_type = lstate.tls_err;
10319e39c5baSBill Taylor (void) tavor_loopback_copyout(&lb, arg, mode);
10329e39c5baSBill Taylor tavor_loopback_free_state(&lstate);
10339e39c5baSBill Taylor return (EFAULT);
10349e39c5baSBill Taylor }
10359e39c5baSBill Taylor
10369e39c5baSBill Taylor /* Activate the RX QP (connect to TX QP) */
10379e39c5baSBill Taylor lstate.tls_err = TAVOR_LOOPBACK_RECV_QP_INIT_FAIL;
10389e39c5baSBill Taylor if (tavor_loopback_modify_qp(&lstate, &lstate.tls_rx,
10399e39c5baSBill Taylor lstate.tls_tx.tlc_qp_num) != 0) {
10409e39c5baSBill Taylor lb.tlb_error_type = lstate.tls_err;
10419e39c5baSBill Taylor (void) tavor_loopback_copyout(&lb, arg, mode);
10429e39c5baSBill Taylor tavor_loopback_free_state(&lstate);
10439e39c5baSBill Taylor return (EFAULT);
10449e39c5baSBill Taylor }
10459e39c5baSBill Taylor
10469e39c5baSBill Taylor /* Run the loopback test (for specified number of iterations) */
10479e39c5baSBill Taylor lb.tlb_pass_done = 0;
10489e39c5baSBill Taylor for (iter = 0; iter < lb.tlb_num_iter; iter++) {
10499e39c5baSBill Taylor lstate.tls_err = 0;
10509e39c5baSBill Taylor bzero(lstate.tls_rx.tlc_buf, lb.tlb_buf_sz);
10519e39c5baSBill Taylor
10529e39c5baSBill Taylor /* Post RDMA Write work request */
10539e39c5baSBill Taylor if (tavor_loopback_post_send(&lstate, &lstate.tls_tx,
10549e39c5baSBill Taylor &lstate.tls_rx) != IBT_SUCCESS) {
10559e39c5baSBill Taylor lb.tlb_error_type = TAVOR_LOOPBACK_WQE_POST_FAIL;
10569e39c5baSBill Taylor (void) tavor_loopback_copyout(&lb, arg, mode);
10579e39c5baSBill Taylor tavor_loopback_free_state(&lstate);
10589e39c5baSBill Taylor return (EFAULT);
10599e39c5baSBill Taylor }
10609e39c5baSBill Taylor
10619e39c5baSBill Taylor /* Poll the TX CQ for a completion every few ticks */
10629e39c5baSBill Taylor for (j = 0; j < loopmax; j++) {
10639e39c5baSBill Taylor delay(drv_usectohz(TAVOR_VTS_LOOPBACK_MIN_WAIT_DUR));
10649e39c5baSBill Taylor
10659e39c5baSBill Taylor ret = tavor_loopback_poll_cq(&lstate, &lstate.tls_tx);
10669e39c5baSBill Taylor if (((ret != IBT_SUCCESS) && (ret != IBT_CQ_EMPTY)) ||
10679e39c5baSBill Taylor ((ret == IBT_CQ_EMPTY) && (j == loopmax - 1))) {
10689e39c5baSBill Taylor lb.tlb_error_type = TAVOR_LOOPBACK_CQ_POLL_FAIL;
10699e39c5baSBill Taylor if (ddi_copyout(lstate.tls_rx.tlc_buf,
10709e39c5baSBill Taylor lb.tlb_fail_buf, lstate.tls_tx.tlc_buf_sz,
10719e39c5baSBill Taylor mode) != 0) {
10729e39c5baSBill Taylor return (EFAULT);
10739e39c5baSBill Taylor }
10749e39c5baSBill Taylor (void) tavor_loopback_copyout(&lb, arg, mode);
10759e39c5baSBill Taylor tavor_loopback_free_state(&lstate);
10769e39c5baSBill Taylor return (EFAULT);
10779e39c5baSBill Taylor } else if (ret == IBT_CQ_EMPTY) {
10789e39c5baSBill Taylor continue;
10799e39c5baSBill Taylor }
10809e39c5baSBill Taylor
10819e39c5baSBill Taylor /* Compare the data buffers */
10829e39c5baSBill Taylor if (bcmp(lstate.tls_tx.tlc_buf, lstate.tls_rx.tlc_buf,
10839e39c5baSBill Taylor lb.tlb_buf_sz) == 0) {
10849e39c5baSBill Taylor break;
10859e39c5baSBill Taylor } else {
10869e39c5baSBill Taylor lb.tlb_error_type =
10879e39c5baSBill Taylor TAVOR_LOOPBACK_SEND_RECV_COMPARE_FAIL;
10889e39c5baSBill Taylor if (ddi_copyout(lstate.tls_rx.tlc_buf,
10899e39c5baSBill Taylor lb.tlb_fail_buf, lstate.tls_tx.tlc_buf_sz,
10909e39c5baSBill Taylor mode) != 0) {
10919e39c5baSBill Taylor return (EFAULT);
10929e39c5baSBill Taylor }
10939e39c5baSBill Taylor (void) tavor_loopback_copyout(&lb, arg, mode);
10949e39c5baSBill Taylor tavor_loopback_free_state(&lstate);
10959e39c5baSBill Taylor return (EFAULT);
10969e39c5baSBill Taylor }
10979e39c5baSBill Taylor }
10989e39c5baSBill Taylor
10999e39c5baSBill Taylor lstate.tls_err = TAVOR_LOOPBACK_SUCCESS;
11009e39c5baSBill Taylor lb.tlb_pass_done = iter + 1;
11019e39c5baSBill Taylor }
11029e39c5baSBill Taylor
11039e39c5baSBill Taylor lb.tlb_error_type = TAVOR_LOOPBACK_SUCCESS;
11049e39c5baSBill Taylor
11059e39c5baSBill Taylor /* Copy ioctl results back to user struct */
11069e39c5baSBill Taylor ret = tavor_loopback_copyout(&lb, arg, mode);
11079e39c5baSBill Taylor
11089e39c5baSBill Taylor /* Free up everything and release all consumed resources */
11099e39c5baSBill Taylor tavor_loopback_free_state(&lstate);
11109e39c5baSBill Taylor
11119e39c5baSBill Taylor return (ret);
11129e39c5baSBill Taylor }
11139e39c5baSBill Taylor
11149e39c5baSBill Taylor /*
11159e39c5baSBill Taylor * tavor_ioctl_ddr_read()
11169e39c5baSBill Taylor */
11179e39c5baSBill Taylor static int
tavor_ioctl_ddr_read(tavor_state_t * state,intptr_t arg,int mode)11189e39c5baSBill Taylor tavor_ioctl_ddr_read(tavor_state_t *state, intptr_t arg, int mode)
11199e39c5baSBill Taylor {
11209e39c5baSBill Taylor tavor_ddr_read_ioctl_t rdreg;
11219e39c5baSBill Taylor uint32_t *addr;
11229e39c5baSBill Taylor uintptr_t baseaddr;
11239e39c5baSBill Taylor uint64_t ddr_size;
11249e39c5baSBill Taylor
11259e39c5baSBill Taylor /*
11269e39c5baSBill Taylor * Access to Tavor VTS ioctls is not allowed in "maintenance mode".
11279e39c5baSBill Taylor */
11289e39c5baSBill Taylor if (state->ts_operational_mode == TAVOR_MAINTENANCE_MODE) {
11299e39c5baSBill Taylor return (EFAULT);
11309e39c5baSBill Taylor }
11319e39c5baSBill Taylor
11329e39c5baSBill Taylor /* copyin the user struct to kernel */
11339e39c5baSBill Taylor if (ddi_copyin((void *)arg, &rdreg, sizeof (tavor_ddr_read_ioctl_t),
11349e39c5baSBill Taylor mode) != 0) {
11359e39c5baSBill Taylor return (EFAULT);
11369e39c5baSBill Taylor }
11379e39c5baSBill Taylor
11389e39c5baSBill Taylor /*
11399e39c5baSBill Taylor * Check ioctl revision
11409e39c5baSBill Taylor */
11419e39c5baSBill Taylor if (rdreg.tdr_revision != TAVOR_VTS_IOCTL_REVISION) {
11429e39c5baSBill Taylor return (EINVAL);
11439e39c5baSBill Taylor }
11449e39c5baSBill Taylor
11459e39c5baSBill Taylor /*
11469e39c5baSBill Taylor * Check for valid offset
11479e39c5baSBill Taylor */
11489e39c5baSBill Taylor ddr_size = (state->ts_ddr.ddr_endaddr - state->ts_ddr.ddr_baseaddr + 1);
11499e39c5baSBill Taylor if ((uint64_t)rdreg.tdr_offset >= ddr_size) {
11509e39c5baSBill Taylor return (EINVAL);
11519e39c5baSBill Taylor }
11529e39c5baSBill Taylor
11539e39c5baSBill Taylor /* Determine base address for requested register read */
11549e39c5baSBill Taylor baseaddr = (uintptr_t)state->ts_reg_ddr_baseaddr;
11559e39c5baSBill Taylor
11569e39c5baSBill Taylor /* Ensure that address is properly-aligned */
11579e39c5baSBill Taylor addr = (uint32_t *)((baseaddr + rdreg.tdr_offset) & ~0x3);
11589e39c5baSBill Taylor
11599e39c5baSBill Taylor /* Read the register pointed to by addr */
11609e39c5baSBill Taylor rdreg.tdr_data = ddi_get32(state->ts_reg_cmdhdl, addr);
11619e39c5baSBill Taylor
11629e39c5baSBill Taylor /* Copy ioctl results back to user struct */
11639e39c5baSBill Taylor if (ddi_copyout(&rdreg, (void *)arg, sizeof (tavor_ddr_read_ioctl_t),
11649e39c5baSBill Taylor mode) != 0) {
11659e39c5baSBill Taylor return (EFAULT);
11669e39c5baSBill Taylor }
11679e39c5baSBill Taylor
11689e39c5baSBill Taylor return (0);
11699e39c5baSBill Taylor }
11709e39c5baSBill Taylor
11719e39c5baSBill Taylor
11729e39c5baSBill Taylor #ifdef DEBUG
11739e39c5baSBill Taylor /*
11749e39c5baSBill Taylor * tavor_ioctl_reg_read()
11759e39c5baSBill Taylor */
11769e39c5baSBill Taylor static int
tavor_ioctl_reg_read(tavor_state_t * state,intptr_t arg,int mode)11779e39c5baSBill Taylor tavor_ioctl_reg_read(tavor_state_t *state, intptr_t arg, int mode)
11789e39c5baSBill Taylor {
11799e39c5baSBill Taylor tavor_reg_ioctl_t rdreg;
11809e39c5baSBill Taylor uint32_t *addr;
11819e39c5baSBill Taylor uintptr_t baseaddr;
11829e39c5baSBill Taylor int status;
11839e39c5baSBill Taylor
11849e39c5baSBill Taylor /*
11859e39c5baSBill Taylor * Access to Tavor registers is not allowed in "maintenance mode".
11869e39c5baSBill Taylor * This is primarily because the device may not have BARs to access
11879e39c5baSBill Taylor */
11889e39c5baSBill Taylor if (state->ts_operational_mode == TAVOR_MAINTENANCE_MODE) {
11899e39c5baSBill Taylor return (EFAULT);
11909e39c5baSBill Taylor }
11919e39c5baSBill Taylor
11929e39c5baSBill Taylor /* Copy in the tavor_reg_ioctl_t structure */
11939e39c5baSBill Taylor status = ddi_copyin((void *)arg, &rdreg, sizeof (tavor_reg_ioctl_t),
11949e39c5baSBill Taylor mode);
11959e39c5baSBill Taylor if (status != 0) {
11969e39c5baSBill Taylor return (EFAULT);
11979e39c5baSBill Taylor }
11989e39c5baSBill Taylor
11999e39c5baSBill Taylor /* Determine base address for requested register set */
12009e39c5baSBill Taylor switch (rdreg.trg_reg_set) {
12019e39c5baSBill Taylor case TAVOR_CMD_BAR:
12029e39c5baSBill Taylor baseaddr = (uintptr_t)state->ts_reg_cmd_baseaddr;
12039e39c5baSBill Taylor break;
12049e39c5baSBill Taylor
12059e39c5baSBill Taylor case TAVOR_UAR_BAR:
12069e39c5baSBill Taylor baseaddr = (uintptr_t)state->ts_reg_uar_baseaddr;
12079e39c5baSBill Taylor break;
12089e39c5baSBill Taylor
12099e39c5baSBill Taylor case TAVOR_DDR_BAR:
12109e39c5baSBill Taylor baseaddr = (uintptr_t)state->ts_reg_ddr_baseaddr;
12119e39c5baSBill Taylor break;
12129e39c5baSBill Taylor
12139e39c5baSBill Taylor default:
12149e39c5baSBill Taylor return (EFAULT);
12159e39c5baSBill Taylor }
12169e39c5baSBill Taylor
12179e39c5baSBill Taylor /* Ensure that address is properly-aligned */
12189e39c5baSBill Taylor addr = (uint32_t *)((baseaddr + rdreg.trg_offset) & ~0x3);
12199e39c5baSBill Taylor
12209e39c5baSBill Taylor /* Read the register pointed to by addr */
12219e39c5baSBill Taylor rdreg.trg_data = ddi_get32(state->ts_reg_cmdhdl, addr);
12229e39c5baSBill Taylor
12239e39c5baSBill Taylor /* Copy in the result into the tavor_reg_ioctl_t structure */
12249e39c5baSBill Taylor status = ddi_copyout(&rdreg, (void *)arg, sizeof (tavor_reg_ioctl_t),
12259e39c5baSBill Taylor mode);
12269e39c5baSBill Taylor if (status != 0) {
12279e39c5baSBill Taylor return (EFAULT);
12289e39c5baSBill Taylor }
12299e39c5baSBill Taylor
12309e39c5baSBill Taylor return (0);
12319e39c5baSBill Taylor }
12329e39c5baSBill Taylor
12339e39c5baSBill Taylor
12349e39c5baSBill Taylor /*
12359e39c5baSBill Taylor * tavor_ioctl_reg_write()
12369e39c5baSBill Taylor */
12379e39c5baSBill Taylor static int
tavor_ioctl_reg_write(tavor_state_t * state,intptr_t arg,int mode)12389e39c5baSBill Taylor tavor_ioctl_reg_write(tavor_state_t *state, intptr_t arg, int mode)
12399e39c5baSBill Taylor {
12409e39c5baSBill Taylor tavor_reg_ioctl_t wrreg;
12419e39c5baSBill Taylor uint32_t *addr;
12429e39c5baSBill Taylor uintptr_t baseaddr;
12439e39c5baSBill Taylor int status;
12449e39c5baSBill Taylor
12459e39c5baSBill Taylor /*
12469e39c5baSBill Taylor * Access to Tavor registers is not allowed in "maintenance mode".
12479e39c5baSBill Taylor * This is primarily because the device may not have BARs to access
12489e39c5baSBill Taylor */
12499e39c5baSBill Taylor if (state->ts_operational_mode == TAVOR_MAINTENANCE_MODE) {
12509e39c5baSBill Taylor return (EFAULT);
12519e39c5baSBill Taylor }
12529e39c5baSBill Taylor
12539e39c5baSBill Taylor /* Copy in the tavor_reg_ioctl_t structure */
12549e39c5baSBill Taylor status = ddi_copyin((void *)arg, &wrreg, sizeof (tavor_reg_ioctl_t),
12559e39c5baSBill Taylor mode);
12569e39c5baSBill Taylor if (status != 0) {
12579e39c5baSBill Taylor return (EFAULT);
12589e39c5baSBill Taylor }
12599e39c5baSBill Taylor
12609e39c5baSBill Taylor /* Determine base address for requested register set */
12619e39c5baSBill Taylor switch (wrreg.trg_reg_set) {
12629e39c5baSBill Taylor case TAVOR_CMD_BAR:
12639e39c5baSBill Taylor baseaddr = (uintptr_t)state->ts_reg_cmd_baseaddr;
12649e39c5baSBill Taylor break;
12659e39c5baSBill Taylor
12669e39c5baSBill Taylor case TAVOR_UAR_BAR:
12679e39c5baSBill Taylor baseaddr = (uintptr_t)state->ts_reg_uar_baseaddr;
12689e39c5baSBill Taylor break;
12699e39c5baSBill Taylor
12709e39c5baSBill Taylor case TAVOR_DDR_BAR:
12719e39c5baSBill Taylor baseaddr = (uintptr_t)state->ts_reg_ddr_baseaddr;
12729e39c5baSBill Taylor break;
12739e39c5baSBill Taylor
12749e39c5baSBill Taylor default:
12759e39c5baSBill Taylor return (EFAULT);
12769e39c5baSBill Taylor }
12779e39c5baSBill Taylor
12789e39c5baSBill Taylor /* Ensure that address is properly-aligned */
12799e39c5baSBill Taylor addr = (uint32_t *)((baseaddr + wrreg.trg_offset) & ~0x3);
12809e39c5baSBill Taylor
12819e39c5baSBill Taylor /* Write the data to the register pointed to by addr */
12829e39c5baSBill Taylor ddi_put32(state->ts_reg_cmdhdl, addr, wrreg.trg_data);
12839e39c5baSBill Taylor
12849e39c5baSBill Taylor return (0);
12859e39c5baSBill Taylor }
12869e39c5baSBill Taylor #endif /* DEBUG */
12879e39c5baSBill Taylor
12889e39c5baSBill Taylor /*
12899e39c5baSBill Taylor * tavor_flash_reset()
12909e39c5baSBill Taylor */
12919e39c5baSBill Taylor static void
tavor_flash_reset(tavor_state_t * state)12929e39c5baSBill Taylor tavor_flash_reset(tavor_state_t *state)
12939e39c5baSBill Taylor {
12949e39c5baSBill Taylor /*
12959e39c5baSBill Taylor * Performs a reset to the flash device. After a reset the flash will
12969e39c5baSBill Taylor * be operating in normal mode (capable of read/write, etc.).
12979e39c5baSBill Taylor */
12989e39c5baSBill Taylor switch (state->ts_fw_cmdset) {
12999e39c5baSBill Taylor case TAVOR_FLASH_AMD_CMDSET:
13009e39c5baSBill Taylor tavor_flash_write(state, 0x555, TAVOR_HW_FLASH_RESET_AMD);
13019e39c5baSBill Taylor break;
13029e39c5baSBill Taylor
13039e39c5baSBill Taylor case TAVOR_FLASH_INTEL_CMDSET:
13049e39c5baSBill Taylor tavor_flash_write(state, 0x555, TAVOR_HW_FLASH_RESET_INTEL);
13059e39c5baSBill Taylor break;
13069e39c5baSBill Taylor
13079e39c5baSBill Taylor default:
13089e39c5baSBill Taylor break;
13099e39c5baSBill Taylor }
13109e39c5baSBill Taylor }
13119e39c5baSBill Taylor
13129e39c5baSBill Taylor /*
13139e39c5baSBill Taylor * tavor_flash_read_sector()
13149e39c5baSBill Taylor */
13159e39c5baSBill Taylor static void
tavor_flash_read_sector(tavor_state_t * state,uint32_t sector_num)13169e39c5baSBill Taylor tavor_flash_read_sector(tavor_state_t *state, uint32_t sector_num)
13179e39c5baSBill Taylor {
13189e39c5baSBill Taylor uint32_t addr;
13199e39c5baSBill Taylor uint32_t end_addr;
13209e39c5baSBill Taylor uint32_t *image;
13219e39c5baSBill Taylor int i;
13229e39c5baSBill Taylor
13239e39c5baSBill Taylor image = (uint32_t *)&state->ts_fw_sector[0];
13249e39c5baSBill Taylor
13259e39c5baSBill Taylor /*
13269e39c5baSBill Taylor * Calculate the start and end address of the sector, based on the
13279e39c5baSBill Taylor * sector number passed in.
13289e39c5baSBill Taylor */
13299e39c5baSBill Taylor addr = sector_num << state->ts_fw_log_sector_sz;
13309e39c5baSBill Taylor end_addr = addr + (1 << state->ts_fw_log_sector_sz);
13319e39c5baSBill Taylor
13329e39c5baSBill Taylor /* Set the flash bank correctly for the given address */
13339e39c5baSBill Taylor tavor_flash_bank(state, addr);
13349e39c5baSBill Taylor
13359e39c5baSBill Taylor /* Read the entire sector, one quadlet at a time */
13369e39c5baSBill Taylor for (i = 0; addr < end_addr; i++, addr += 4) {
13379e39c5baSBill Taylor image[i] = tavor_flash_read(state, addr);
13389e39c5baSBill Taylor }
13399e39c5baSBill Taylor }
13409e39c5baSBill Taylor
13419e39c5baSBill Taylor /*
13429e39c5baSBill Taylor * tavor_flash_read_quadlet()
13439e39c5baSBill Taylor */
13449e39c5baSBill Taylor static void
tavor_flash_read_quadlet(tavor_state_t * state,uint32_t * data,uint32_t addr)13459e39c5baSBill Taylor tavor_flash_read_quadlet(tavor_state_t *state, uint32_t *data,
13469e39c5baSBill Taylor uint32_t addr)
13479e39c5baSBill Taylor {
13489e39c5baSBill Taylor /* Set the flash bank correctly for the given address */
13499e39c5baSBill Taylor tavor_flash_bank(state, addr);
13509e39c5baSBill Taylor
13519e39c5baSBill Taylor /* Read one quadlet of data */
13529e39c5baSBill Taylor *data = tavor_flash_read(state, addr);
13539e39c5baSBill Taylor }
13549e39c5baSBill Taylor
13559e39c5baSBill Taylor /*
13569e39c5baSBill Taylor * tavor_flash_write_sector()
13579e39c5baSBill Taylor */
13589e39c5baSBill Taylor static int
tavor_flash_write_sector(tavor_state_t * state,uint32_t sector_num)13599e39c5baSBill Taylor tavor_flash_write_sector(tavor_state_t *state, uint32_t sector_num)
13609e39c5baSBill Taylor {
13619e39c5baSBill Taylor uint32_t addr;
13629e39c5baSBill Taylor uint32_t end_addr;
13639e39c5baSBill Taylor uchar_t *sector;
13649e39c5baSBill Taylor int status = 0;
13659e39c5baSBill Taylor int i;
13669e39c5baSBill Taylor
13679e39c5baSBill Taylor sector = (uchar_t *)&state->ts_fw_sector[0];
13689e39c5baSBill Taylor
13699e39c5baSBill Taylor /*
13709e39c5baSBill Taylor * Calculate the start and end address of the sector, based on the
13719e39c5baSBill Taylor * sector number passed in.
13729e39c5baSBill Taylor */
13739e39c5baSBill Taylor addr = sector_num << state->ts_fw_log_sector_sz;
13749e39c5baSBill Taylor end_addr = addr + (1 << state->ts_fw_log_sector_sz);
13759e39c5baSBill Taylor
13769e39c5baSBill Taylor /* Set the flash bank correctly for the given address */
13779e39c5baSBill Taylor tavor_flash_bank(state, addr);
13789e39c5baSBill Taylor
13799e39c5baSBill Taylor /* Erase the sector before writing */
13809e39c5baSBill Taylor tavor_flash_reset(state);
13819e39c5baSBill Taylor status = tavor_flash_erase_sector(state, sector_num);
13829e39c5baSBill Taylor if (status != 0) {
13839e39c5baSBill Taylor return (status);
13849e39c5baSBill Taylor }
13859e39c5baSBill Taylor
13869e39c5baSBill Taylor /* Write the entire sector, one byte at a time */
13879e39c5baSBill Taylor for (i = 0; addr < end_addr; i++, addr++) {
13889e39c5baSBill Taylor status = tavor_flash_write_byte(state, addr, sector[i]);
13899e39c5baSBill Taylor if (status != 0) {
13909e39c5baSBill Taylor break;
13919e39c5baSBill Taylor }
13929e39c5baSBill Taylor }
13939e39c5baSBill Taylor
13949e39c5baSBill Taylor tavor_flash_reset(state);
13959e39c5baSBill Taylor return (status);
13969e39c5baSBill Taylor }
13979e39c5baSBill Taylor
13989e39c5baSBill Taylor /*
13999e39c5baSBill Taylor * tavor_flash_write_byte()
14009e39c5baSBill Taylor */
14019e39c5baSBill Taylor static int
tavor_flash_write_byte(tavor_state_t * state,uint32_t addr,uchar_t data)14029e39c5baSBill Taylor tavor_flash_write_byte(tavor_state_t *state, uint32_t addr, uchar_t data)
14039e39c5baSBill Taylor {
14049e39c5baSBill Taylor uint32_t stat;
14059e39c5baSBill Taylor int status = 0;
14069e39c5baSBill Taylor int i;
14079e39c5baSBill Taylor
14089e39c5baSBill Taylor switch (state->ts_fw_cmdset) {
14099e39c5baSBill Taylor case TAVOR_FLASH_AMD_CMDSET:
14109e39c5baSBill Taylor /* Issue Flash Byte program command */
14119e39c5baSBill Taylor tavor_flash_write(state, addr, 0xAA);
14129e39c5baSBill Taylor tavor_flash_write(state, addr, 0x55);
14139e39c5baSBill Taylor tavor_flash_write(state, addr, 0xA0);
14149e39c5baSBill Taylor tavor_flash_write(state, addr, data);
14159e39c5baSBill Taylor
14169e39c5baSBill Taylor /*
14179e39c5baSBill Taylor * Wait for Write Byte to Complete:
14189e39c5baSBill Taylor * 1) Wait 1usec
14199e39c5baSBill Taylor * 2) Read status of the write operation
14209e39c5baSBill Taylor * 3) Determine if we have timed out the write operation
14219e39c5baSBill Taylor * 4) Compare correct data value to the status value that
14229e39c5baSBill Taylor * was read from the same address.
14239e39c5baSBill Taylor */
14249e39c5baSBill Taylor i = 0;
14259e39c5baSBill Taylor do {
14269e39c5baSBill Taylor drv_usecwait(1);
14279e39c5baSBill Taylor stat = tavor_flash_read(state, addr & ~3);
14289e39c5baSBill Taylor
14299e39c5baSBill Taylor if (i == tavor_hw_flash_timeout_write) {
14309e39c5baSBill Taylor cmn_err(CE_WARN,
14319e39c5baSBill Taylor "tavor_flash_write_byte: ACS write "
14329e39c5baSBill Taylor "timeout: addr: 0x%x, data: 0x%x\n",
14339e39c5baSBill Taylor addr, data);
14349e39c5baSBill Taylor status = EIO;
14359e39c5baSBill Taylor break;
14369e39c5baSBill Taylor }
14379e39c5baSBill Taylor
14389e39c5baSBill Taylor i++;
14399e39c5baSBill Taylor } while (data != ((stat >> ((3 - (addr & 3)) << 3)) & 0xFF));
14409e39c5baSBill Taylor break;
14419e39c5baSBill Taylor
14429e39c5baSBill Taylor case TAVOR_FLASH_INTEL_CMDSET:
14439e39c5baSBill Taylor /* Issue Flash Byte program command */
14449e39c5baSBill Taylor tavor_flash_write(state, addr, TAVOR_HW_FLASH_ICS_WRITE);
14459e39c5baSBill Taylor tavor_flash_write(state, addr, data);
14469e39c5baSBill Taylor
14479e39c5baSBill Taylor /* wait for completion */
14489e39c5baSBill Taylor i = 0;
14499e39c5baSBill Taylor do {
14509e39c5baSBill Taylor drv_usecwait(1);
14519e39c5baSBill Taylor stat = tavor_flash_read(state, addr & ~3);
14529e39c5baSBill Taylor
14539e39c5baSBill Taylor if (i == tavor_hw_flash_timeout_write) {
14549e39c5baSBill Taylor cmn_err(CE_WARN,
14559e39c5baSBill Taylor "tavor_flash_write_byte: ICS write "
14569e39c5baSBill Taylor "timeout: addr: %x, data: %x\n",
14579e39c5baSBill Taylor addr, data);
14589e39c5baSBill Taylor status = EIO;
14599e39c5baSBill Taylor break;
14609e39c5baSBill Taylor }
14619e39c5baSBill Taylor
14629e39c5baSBill Taylor i++;
14639e39c5baSBill Taylor } while ((stat & TAVOR_HW_FLASH_ICS_READY) == 0);
14649e39c5baSBill Taylor
14659e39c5baSBill Taylor if (stat & TAVOR_HW_FLASH_ICS_ERROR) {
14669e39c5baSBill Taylor cmn_err(CE_WARN,
14679e39c5baSBill Taylor "tavor_flash_write_byte: ICS write cmd error: "
14689e39c5baSBill Taylor "addr: %x, data: %x\n",
14699e39c5baSBill Taylor addr, data);
14709e39c5baSBill Taylor status = EIO;
14719e39c5baSBill Taylor }
14729e39c5baSBill Taylor break;
14739e39c5baSBill Taylor
14749e39c5baSBill Taylor default:
14759e39c5baSBill Taylor cmn_err(CE_WARN,
14769e39c5baSBill Taylor "tavor_flash_write_byte: unknown cmd set: 0x%x\n",
14779e39c5baSBill Taylor state->ts_fw_cmdset);
14789e39c5baSBill Taylor status = EIO;
14799e39c5baSBill Taylor break;
14809e39c5baSBill Taylor }
14819e39c5baSBill Taylor
14829e39c5baSBill Taylor return (status);
14839e39c5baSBill Taylor }
14849e39c5baSBill Taylor
14859e39c5baSBill Taylor /*
14869e39c5baSBill Taylor * tavor_flash_erase_sector()
14879e39c5baSBill Taylor */
14889e39c5baSBill Taylor static int
tavor_flash_erase_sector(tavor_state_t * state,uint32_t sector_num)14899e39c5baSBill Taylor tavor_flash_erase_sector(tavor_state_t *state, uint32_t sector_num)
14909e39c5baSBill Taylor {
14919e39c5baSBill Taylor uint32_t addr;
14929e39c5baSBill Taylor uint32_t stat;
14939e39c5baSBill Taylor int status = 0;
14949e39c5baSBill Taylor int i;
14959e39c5baSBill Taylor
14969e39c5baSBill Taylor /* Get address from sector num */
14979e39c5baSBill Taylor addr = sector_num << state->ts_fw_log_sector_sz;
14989e39c5baSBill Taylor
14999e39c5baSBill Taylor switch (state->ts_fw_cmdset) {
15009e39c5baSBill Taylor case TAVOR_FLASH_AMD_CMDSET:
15019e39c5baSBill Taylor /* Issue Flash Sector Erase Command */
15029e39c5baSBill Taylor tavor_flash_write(state, addr, 0xAA);
15039e39c5baSBill Taylor tavor_flash_write(state, addr, 0x55);
15049e39c5baSBill Taylor tavor_flash_write(state, addr, 0x80);
15059e39c5baSBill Taylor tavor_flash_write(state, addr, 0xAA);
15069e39c5baSBill Taylor tavor_flash_write(state, addr, 0x55);
15079e39c5baSBill Taylor tavor_flash_write(state, addr, 0x30);
15089e39c5baSBill Taylor
15099e39c5baSBill Taylor /*
15109e39c5baSBill Taylor * Wait for Sector Erase to Complete
15119e39c5baSBill Taylor * 1) Wait 1usec
15129e39c5baSBill Taylor * 2) read the status at the base addr of the sector
15139e39c5baSBill Taylor * 3) Determine if we have timed out
15149e39c5baSBill Taylor * 4) Compare status of address with the value of a fully
15159e39c5baSBill Taylor * erased quadlet. If these are equal, the sector
15169e39c5baSBill Taylor * has been erased.
15179e39c5baSBill Taylor */
15189e39c5baSBill Taylor i = 0;
15199e39c5baSBill Taylor do {
15209e39c5baSBill Taylor /* wait 1usec */
15219e39c5baSBill Taylor drv_usecwait(1);
15229e39c5baSBill Taylor stat = tavor_flash_read(state, addr);
15239e39c5baSBill Taylor
15249e39c5baSBill Taylor if (i == tavor_hw_flash_timeout_erase) {
15259e39c5baSBill Taylor cmn_err(CE_WARN,
15269e39c5baSBill Taylor "tavor_flash_erase_sector: "
15279e39c5baSBill Taylor "ACS erase timeout\n");
15289e39c5baSBill Taylor status = EIO;
15299e39c5baSBill Taylor break;
15309e39c5baSBill Taylor }
15319e39c5baSBill Taylor
15329e39c5baSBill Taylor i++;
15339e39c5baSBill Taylor } while (stat != 0xFFFFFFFF);
15349e39c5baSBill Taylor break;
15359e39c5baSBill Taylor
15369e39c5baSBill Taylor case TAVOR_FLASH_INTEL_CMDSET:
15379e39c5baSBill Taylor /* Issue Erase Command */
15389e39c5baSBill Taylor tavor_flash_write(state, addr, TAVOR_HW_FLASH_ICS_ERASE);
15399e39c5baSBill Taylor tavor_flash_write(state, addr, TAVOR_HW_FLASH_ICS_CONFIRM);
15409e39c5baSBill Taylor
15419e39c5baSBill Taylor /* wait for completion */
15429e39c5baSBill Taylor i = 0;
15439e39c5baSBill Taylor do {
15449e39c5baSBill Taylor drv_usecwait(1);
15459e39c5baSBill Taylor stat = tavor_flash_read(state, addr & ~3);
15469e39c5baSBill Taylor
15479e39c5baSBill Taylor if (i == tavor_hw_flash_timeout_erase) {
15489e39c5baSBill Taylor cmn_err(CE_WARN,
15499e39c5baSBill Taylor "tavor_flash_erase_sector: "
15509e39c5baSBill Taylor "ICS erase timeout\n");
15519e39c5baSBill Taylor status = EIO;
15529e39c5baSBill Taylor break;
15539e39c5baSBill Taylor }
15549e39c5baSBill Taylor
15559e39c5baSBill Taylor i++;
15569e39c5baSBill Taylor } while ((stat & TAVOR_HW_FLASH_ICS_READY) == 0);
15579e39c5baSBill Taylor
15589e39c5baSBill Taylor if (stat & TAVOR_HW_FLASH_ICS_ERROR) {
15599e39c5baSBill Taylor cmn_err(CE_WARN,
15609e39c5baSBill Taylor "tavor_flash_erase_sector: "
15619e39c5baSBill Taylor "ICS erase cmd error\n");
15629e39c5baSBill Taylor status = EIO;
15639e39c5baSBill Taylor }
15649e39c5baSBill Taylor break;
15659e39c5baSBill Taylor
15669e39c5baSBill Taylor default:
15679e39c5baSBill Taylor cmn_err(CE_WARN,
15689e39c5baSBill Taylor "tavor_flash_erase_sector: unknown cmd set: 0x%x\n",
15699e39c5baSBill Taylor state->ts_fw_cmdset);
15709e39c5baSBill Taylor status = EIO;
15719e39c5baSBill Taylor break;
15729e39c5baSBill Taylor }
15739e39c5baSBill Taylor
15749e39c5baSBill Taylor tavor_flash_reset(state);
15759e39c5baSBill Taylor
15769e39c5baSBill Taylor return (status);
15779e39c5baSBill Taylor }
15789e39c5baSBill Taylor
15799e39c5baSBill Taylor /*
15809e39c5baSBill Taylor * tavor_flash_erase_chip()
15819e39c5baSBill Taylor */
15829e39c5baSBill Taylor static int
tavor_flash_erase_chip(tavor_state_t * state)15839e39c5baSBill Taylor tavor_flash_erase_chip(tavor_state_t *state)
15849e39c5baSBill Taylor {
15859e39c5baSBill Taylor uint_t size;
15869e39c5baSBill Taylor uint32_t stat;
15879e39c5baSBill Taylor int status = 0;
15889e39c5baSBill Taylor int num_sect;
15899e39c5baSBill Taylor int i;
15909e39c5baSBill Taylor
15919e39c5baSBill Taylor switch (state->ts_fw_cmdset) {
15929e39c5baSBill Taylor case TAVOR_FLASH_AMD_CMDSET:
15939e39c5baSBill Taylor /* Issue Flash Chip Erase Command */
15949e39c5baSBill Taylor tavor_flash_write(state, 0, 0xAA);
15959e39c5baSBill Taylor tavor_flash_write(state, 0, 0x55);
15969e39c5baSBill Taylor tavor_flash_write(state, 0, 0x80);
15979e39c5baSBill Taylor tavor_flash_write(state, 0, 0xAA);
15989e39c5baSBill Taylor tavor_flash_write(state, 0, 0x55);
15999e39c5baSBill Taylor tavor_flash_write(state, 0, 0x10);
16009e39c5baSBill Taylor
16019e39c5baSBill Taylor /*
16029e39c5baSBill Taylor * Wait for Chip Erase to Complete
16039e39c5baSBill Taylor * 1) Wait 1usec
16049e39c5baSBill Taylor * 2) read the status at the base addr of the sector
16059e39c5baSBill Taylor * 3) Determine if we have timed out
16069e39c5baSBill Taylor * 4) Compare status of address with the value of a
16079e39c5baSBill Taylor * fully erased quadlet. If these are equal, the
16089e39c5baSBill Taylor * chip has been erased.
16099e39c5baSBill Taylor */
16109e39c5baSBill Taylor i = 0;
16119e39c5baSBill Taylor do {
16129e39c5baSBill Taylor /* wait 1usec */
16139e39c5baSBill Taylor drv_usecwait(1);
16149e39c5baSBill Taylor stat = tavor_flash_read(state, 0);
16159e39c5baSBill Taylor
16169e39c5baSBill Taylor if (i == tavor_hw_flash_timeout_erase) {
16179e39c5baSBill Taylor cmn_err(CE_WARN,
16189e39c5baSBill Taylor "tavor_flash_erase_chip: erase timeout\n");
16199e39c5baSBill Taylor status = EIO;
16209e39c5baSBill Taylor break;
16219e39c5baSBill Taylor }
16229e39c5baSBill Taylor
16239e39c5baSBill Taylor i++;
16249e39c5baSBill Taylor } while (stat != 0xFFFFFFFF);
16259e39c5baSBill Taylor break;
16269e39c5baSBill Taylor
16279e39c5baSBill Taylor case TAVOR_FLASH_INTEL_CMDSET:
16289e39c5baSBill Taylor /*
16299e39c5baSBill Taylor * The Intel chip doesn't have a chip erase command, so erase
16309e39c5baSBill Taylor * all blocks one at a time.
16319e39c5baSBill Taylor */
16329e39c5baSBill Taylor size = (0x1 << state->ts_fw_log_sector_sz);
16339e39c5baSBill Taylor num_sect = state->ts_fw_device_sz / size;
16349e39c5baSBill Taylor
16359e39c5baSBill Taylor for (i = 0; i < num_sect; i++) {
16369e39c5baSBill Taylor status = tavor_flash_erase_sector(state, i);
16379e39c5baSBill Taylor if (status != 0) {
16389e39c5baSBill Taylor cmn_err(CE_WARN,
16399e39c5baSBill Taylor "tavor_flash_erase_chip: "
16409e39c5baSBill Taylor "ICS sector %d erase error\n", i);
16419e39c5baSBill Taylor status = EIO;
16429e39c5baSBill Taylor break;
16439e39c5baSBill Taylor }
16449e39c5baSBill Taylor }
16459e39c5baSBill Taylor break;
16469e39c5baSBill Taylor
16479e39c5baSBill Taylor default:
16489e39c5baSBill Taylor cmn_err(CE_WARN, "tavor_flash_erase_chip: "
16499e39c5baSBill Taylor "unknown cmd set: 0x%x\n", state->ts_fw_cmdset);
16509e39c5baSBill Taylor status = EIO;
16519e39c5baSBill Taylor break;
16529e39c5baSBill Taylor }
16539e39c5baSBill Taylor
16549e39c5baSBill Taylor return (status);
16559e39c5baSBill Taylor }
16569e39c5baSBill Taylor
16579e39c5baSBill Taylor /*
16589e39c5baSBill Taylor * tavor_flash_bank()
16599e39c5baSBill Taylor */
16609e39c5baSBill Taylor static void
tavor_flash_bank(tavor_state_t * state,uint32_t addr)16619e39c5baSBill Taylor tavor_flash_bank(tavor_state_t *state, uint32_t addr)
16629e39c5baSBill Taylor {
16639e39c5baSBill Taylor ddi_acc_handle_t hdl;
16649e39c5baSBill Taylor uint32_t bank;
16659e39c5baSBill Taylor
16669e39c5baSBill Taylor /* Set handle */
16679e39c5baSBill Taylor hdl = state->ts_pci_cfghdl;
16689e39c5baSBill Taylor
16699e39c5baSBill Taylor /* Determine the bank setting from the address */
16709e39c5baSBill Taylor bank = addr & TAVOR_HW_FLASH_BANK_MASK;
16719e39c5baSBill Taylor
16729e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(state->ts_fw_flashbank))
16739e39c5baSBill Taylor
16749e39c5baSBill Taylor /*
16759e39c5baSBill Taylor * If the bank is different from the currently set bank, we need to
16769e39c5baSBill Taylor * change it. Also, if an 'addr' of 0 is given, this allows the
16779e39c5baSBill Taylor * capability to force the flash bank to 0. This is useful at init
16789e39c5baSBill Taylor * time to initially set the bank value
16799e39c5baSBill Taylor */
16809e39c5baSBill Taylor if (state->ts_fw_flashbank != bank || addr == 0) {
16819e39c5baSBill Taylor /* Set bank using the GPIO settings */
16829e39c5baSBill Taylor tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_GPIO_DATACLEAR, 0x70);
16839e39c5baSBill Taylor tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_GPIO_DATASET,
16849e39c5baSBill Taylor (bank >> 15) & 0x70);
16859e39c5baSBill Taylor
16869e39c5baSBill Taylor /* Save the bank state */
16879e39c5baSBill Taylor state->ts_fw_flashbank = bank;
16889e39c5baSBill Taylor }
16899e39c5baSBill Taylor }
16909e39c5baSBill Taylor
16919e39c5baSBill Taylor /*
16929e39c5baSBill Taylor * tavor_flash_read()
16939e39c5baSBill Taylor */
16949e39c5baSBill Taylor static uint32_t
tavor_flash_read(tavor_state_t * state,uint32_t addr)16959e39c5baSBill Taylor tavor_flash_read(tavor_state_t *state, uint32_t addr)
16969e39c5baSBill Taylor {
16979e39c5baSBill Taylor ddi_acc_handle_t hdl;
16989e39c5baSBill Taylor uint32_t data;
16999e39c5baSBill Taylor int timeout;
17009e39c5baSBill Taylor
17019e39c5baSBill Taylor /* Set handle */
17029e39c5baSBill Taylor hdl = state->ts_pci_cfghdl;
17039e39c5baSBill Taylor
17049e39c5baSBill Taylor /*
17059e39c5baSBill Taylor * The Read operation does the following:
17069e39c5baSBill Taylor * 1) Write the masked address to the TAVOR_FLASH_ADDR register.
17079e39c5baSBill Taylor * Only the least significant 19 bits are valid.
17089e39c5baSBill Taylor * 2) Read back the register until the command has completed.
17099e39c5baSBill Taylor * 3) Read the data retrieved from the address at the TAVOR_FLASH_DATA
17109e39c5baSBill Taylor * register.
17119e39c5baSBill Taylor */
17129e39c5baSBill Taylor tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_ADDR,
17139e39c5baSBill Taylor (addr & TAVOR_HW_FLASH_ADDR_MASK) | (1 << 29));
17149e39c5baSBill Taylor
17159e39c5baSBill Taylor timeout = 0;
17169e39c5baSBill Taylor do {
17179e39c5baSBill Taylor data = tavor_flash_read_cfg(hdl, TAVOR_HW_FLASH_ADDR);
17189e39c5baSBill Taylor timeout++;
17199e39c5baSBill Taylor } while ((data & TAVOR_HW_FLASH_CMD_MASK) &&
17209e39c5baSBill Taylor (timeout < tavor_hw_flash_timeout_config));
17219e39c5baSBill Taylor
17229e39c5baSBill Taylor if (timeout == tavor_hw_flash_timeout_config) {
17239e39c5baSBill Taylor cmn_err(CE_WARN, "tavor_flash_read: config command timeout.\n");
17249e39c5baSBill Taylor }
17259e39c5baSBill Taylor
17269e39c5baSBill Taylor data = tavor_flash_read_cfg(hdl, TAVOR_HW_FLASH_DATA);
17279e39c5baSBill Taylor
17289e39c5baSBill Taylor return (data);
17299e39c5baSBill Taylor }
17309e39c5baSBill Taylor
17319e39c5baSBill Taylor /*
17329e39c5baSBill Taylor * tavor_flash_write()
17339e39c5baSBill Taylor */
17349e39c5baSBill Taylor static void
tavor_flash_write(tavor_state_t * state,uint32_t addr,uchar_t data)17359e39c5baSBill Taylor tavor_flash_write(tavor_state_t *state, uint32_t addr, uchar_t data)
17369e39c5baSBill Taylor {
17379e39c5baSBill Taylor ddi_acc_handle_t hdl;
17389e39c5baSBill Taylor int cmd;
17399e39c5baSBill Taylor int timeout;
17409e39c5baSBill Taylor
17419e39c5baSBill Taylor /* Set handle */
17429e39c5baSBill Taylor hdl = state->ts_pci_cfghdl;
17439e39c5baSBill Taylor
17449e39c5baSBill Taylor /*
17459e39c5baSBill Taylor * The Write operation does the following:
17469e39c5baSBill Taylor * 1) Write the data to be written to the TAVOR_FLASH_DATA offset.
17479e39c5baSBill Taylor * 2) Write the address to write the data to to the TAVOR_FLASH_ADDR
17489e39c5baSBill Taylor * offset.
17499e39c5baSBill Taylor * 3) Wait until the write completes.
17509e39c5baSBill Taylor */
17519e39c5baSBill Taylor tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_DATA, data << 24);
17529e39c5baSBill Taylor tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_ADDR,
17539e39c5baSBill Taylor (addr & 0x7FFFF) | (2 << 29));
17549e39c5baSBill Taylor
17559e39c5baSBill Taylor timeout = 0;
17569e39c5baSBill Taylor do {
17579e39c5baSBill Taylor cmd = tavor_flash_read_cfg(hdl, TAVOR_HW_FLASH_ADDR);
17589e39c5baSBill Taylor timeout++;
17599e39c5baSBill Taylor } while ((cmd & TAVOR_HW_FLASH_CMD_MASK) &&
17609e39c5baSBill Taylor (timeout < tavor_hw_flash_timeout_config));
17619e39c5baSBill Taylor
17629e39c5baSBill Taylor if (timeout == tavor_hw_flash_timeout_config) {
17639e39c5baSBill Taylor cmn_err(CE_WARN, "tavor_flash_write: config cmd timeout.\n");
17649e39c5baSBill Taylor }
17659e39c5baSBill Taylor }
17669e39c5baSBill Taylor
17679e39c5baSBill Taylor /*
17689e39c5baSBill Taylor * tavor_flash_init()
17699e39c5baSBill Taylor */
17709e39c5baSBill Taylor static void
tavor_flash_init(tavor_state_t * state)17719e39c5baSBill Taylor tavor_flash_init(tavor_state_t *state)
17729e39c5baSBill Taylor {
17739e39c5baSBill Taylor uint32_t word;
17749e39c5baSBill Taylor ddi_acc_handle_t hdl;
17759e39c5baSBill Taylor int sema_cnt;
17769e39c5baSBill Taylor int gpio;
17779e39c5baSBill Taylor
17789e39c5baSBill Taylor /* Set handle */
17799e39c5baSBill Taylor hdl = state->ts_pci_cfghdl;
17809e39c5baSBill Taylor
17819e39c5baSBill Taylor /* Init the flash */
17829e39c5baSBill Taylor
17839e39c5baSBill Taylor /*
17849e39c5baSBill Taylor * Grab the GPIO semaphore. This allows us exclusive access to the
17859e39c5baSBill Taylor * GPIO settings on the Tavor for the duration of the flash burning
17869e39c5baSBill Taylor * procedure.
17879e39c5baSBill Taylor */
17889e39c5baSBill Taylor sema_cnt = 0;
17899e39c5baSBill Taylor do {
17909e39c5baSBill Taylor word = tavor_flash_read_cfg(hdl, TAVOR_HW_FLASH_GPIO_SEMA);
17919e39c5baSBill Taylor if (word == 0) {
17929e39c5baSBill Taylor break;
17939e39c5baSBill Taylor }
17949e39c5baSBill Taylor
17959e39c5baSBill Taylor sema_cnt++;
17969e39c5baSBill Taylor drv_usecwait(1);
17979e39c5baSBill Taylor } while (sema_cnt < tavor_hw_flash_timeout_gpio_sema);
17989e39c5baSBill Taylor
17999e39c5baSBill Taylor /*
18009e39c5baSBill Taylor * Determine if we timed out trying to grab the GPIO semaphore
18019e39c5baSBill Taylor */
18029e39c5baSBill Taylor if (sema_cnt == tavor_hw_flash_timeout_gpio_sema) {
18039e39c5baSBill Taylor cmn_err(CE_WARN, "tavor_flash_init: GPIO SEMA timeout\n");
18049e39c5baSBill Taylor }
18059e39c5baSBill Taylor
18069e39c5baSBill Taylor /* Save away original GPIO Values */
18079e39c5baSBill Taylor state->ts_fw_gpio[0] = tavor_flash_read_cfg(hdl,
18089e39c5baSBill Taylor TAVOR_HW_FLASH_GPIO_DIR);
18099e39c5baSBill Taylor state->ts_fw_gpio[1] = tavor_flash_read_cfg(hdl,
18109e39c5baSBill Taylor TAVOR_HW_FLASH_GPIO_POL);
18119e39c5baSBill Taylor state->ts_fw_gpio[2] = tavor_flash_read_cfg(hdl,
18129e39c5baSBill Taylor TAVOR_HW_FLASH_GPIO_MOD);
18139e39c5baSBill Taylor state->ts_fw_gpio[3] = tavor_flash_read_cfg(hdl,
18149e39c5baSBill Taylor TAVOR_HW_FLASH_GPIO_DAT);
18159e39c5baSBill Taylor
18169e39c5baSBill Taylor /* Set New GPIO Values */
18179e39c5baSBill Taylor gpio = state->ts_fw_gpio[0] | 0x70;
18189e39c5baSBill Taylor tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_GPIO_DIR, gpio);
18199e39c5baSBill Taylor
18209e39c5baSBill Taylor gpio = state->ts_fw_gpio[1] & ~0x70;
18219e39c5baSBill Taylor tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_GPIO_POL, gpio);
18229e39c5baSBill Taylor
18239e39c5baSBill Taylor gpio = state->ts_fw_gpio[2] & ~0x70;
18249e39c5baSBill Taylor tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_GPIO_MOD, gpio);
18259e39c5baSBill Taylor
18269e39c5baSBill Taylor /* Set CPUMODE to enable tavor to access the flash device */
18279e39c5baSBill Taylor tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_CPUMODE,
18289e39c5baSBill Taylor 1 << TAVOR_HW_FLASH_CPU_SHIFT);
18299e39c5baSBill Taylor
18309e39c5baSBill Taylor /* Initialize to bank 0 */
18319e39c5baSBill Taylor tavor_flash_bank(state, 0);
18329e39c5baSBill Taylor }
18339e39c5baSBill Taylor
18349e39c5baSBill Taylor /*
18359e39c5baSBill Taylor * tavor_flash_cfi_init
18369e39c5baSBill Taylor * Implements access to the CFI (Common Flash Interface) data
18379e39c5baSBill Taylor */
18389e39c5baSBill Taylor static void
tavor_flash_cfi_init(tavor_state_t * state,uint32_t * cfi_info,int * intel_xcmd)18399e39c5baSBill Taylor tavor_flash_cfi_init(tavor_state_t *state, uint32_t *cfi_info, int *intel_xcmd)
18409e39c5baSBill Taylor {
18419e39c5baSBill Taylor uint32_t data;
18429e39c5baSBill Taylor uint32_t sector_sz_bytes;
18439e39c5baSBill Taylor uint32_t bit_count;
18449e39c5baSBill Taylor uint8_t cfi_ch_info[TAVOR_CFI_INFO_SIZE];
18459e39c5baSBill Taylor int i;
18469e39c5baSBill Taylor
18479e39c5baSBill Taylor /*
18489e39c5baSBill Taylor * Determine if the user command supports the Intel Extended
18499e39c5baSBill Taylor * Command Set. The query string is contained in the fourth
18509e39c5baSBill Taylor * quad word.
18519e39c5baSBill Taylor */
18529e39c5baSBill Taylor tavor_flash_cfi_byte(cfi_ch_info, cfi_info[0x04], 0x10);
18539e39c5baSBill Taylor if (cfi_ch_info[0x10] == 'M' &&
18549e39c5baSBill Taylor cfi_ch_info[0x11] == 'X' &&
18559e39c5baSBill Taylor cfi_ch_info[0x12] == '2') {
18569e39c5baSBill Taylor *intel_xcmd = 1; /* support is there */
18579e39c5baSBill Taylor }
18589e39c5baSBill Taylor
18599e39c5baSBill Taylor /* CFI QUERY */
18609e39c5baSBill Taylor tavor_flash_write(state, 0x55, TAVOR_FLASH_CFI_INIT);
18619e39c5baSBill Taylor
18629e39c5baSBill Taylor /* Read in CFI data */
18639e39c5baSBill Taylor for (i = 0; i < TAVOR_CFI_INFO_SIZE; i += 4) {
18649e39c5baSBill Taylor data = tavor_flash_read(state, i);
18659e39c5baSBill Taylor tavor_flash_cfi_byte(cfi_ch_info, data, i);
18669e39c5baSBill Taylor }
18679e39c5baSBill Taylor
18689e39c5baSBill Taylor /* Determine chip set */
18699e39c5baSBill Taylor state->ts_fw_cmdset = TAVOR_FLASH_UNKNOWN_CMDSET;
18709e39c5baSBill Taylor if (cfi_ch_info[0x20] == 'Q' &&
18719e39c5baSBill Taylor cfi_ch_info[0x22] == 'R' &&
18729e39c5baSBill Taylor cfi_ch_info[0x24] == 'Y') {
18739e39c5baSBill Taylor /*
18749e39c5baSBill Taylor * Mode: x16 working in x8 mode (Intel).
18759e39c5baSBill Taylor * Pack data - skip spacing bytes.
18769e39c5baSBill Taylor */
18779e39c5baSBill Taylor for (i = 0; i < TAVOR_CFI_INFO_SIZE; i += 2) {
18789e39c5baSBill Taylor cfi_ch_info[i/2] = cfi_ch_info[i];
18799e39c5baSBill Taylor }
18809e39c5baSBill Taylor }
18819e39c5baSBill Taylor state->ts_fw_cmdset = cfi_ch_info[0x13];
18829e39c5baSBill Taylor if (state->ts_fw_cmdset != TAVOR_FLASH_INTEL_CMDSET &&
18839e39c5baSBill Taylor state->ts_fw_cmdset != TAVOR_FLASH_AMD_CMDSET) {
18849e39c5baSBill Taylor cmn_err(CE_WARN,
18859e39c5baSBill Taylor "tavor_flash_cfi_init: UNKNOWN chip cmd set\n");
18869e39c5baSBill Taylor state->ts_fw_cmdset = TAVOR_FLASH_UNKNOWN_CMDSET;
1887*2570281cSToomas Soome return;
18889e39c5baSBill Taylor }
18899e39c5baSBill Taylor
18909e39c5baSBill Taylor /* Determine total bytes in one sector size */
18919e39c5baSBill Taylor sector_sz_bytes = ((cfi_ch_info[0x30] << 8) | cfi_ch_info[0x2F]) << 8;
18929e39c5baSBill Taylor
18939e39c5baSBill Taylor /* Calculate equivalent of log2 (n) */
18949e39c5baSBill Taylor for (bit_count = 0; sector_sz_bytes > 1; bit_count++) {
18959e39c5baSBill Taylor sector_sz_bytes >>= 1;
18969e39c5baSBill Taylor }
18979e39c5baSBill Taylor
18989e39c5baSBill Taylor /* Set sector size */
18999e39c5baSBill Taylor state->ts_fw_log_sector_sz = bit_count;
19009e39c5baSBill Taylor
19019e39c5baSBill Taylor /* Set flash size */
19029e39c5baSBill Taylor state->ts_fw_device_sz = 0x1 << cfi_ch_info[0x27];
19039e39c5baSBill Taylor
19049e39c5baSBill Taylor /* Reset to turn off CFI mode */
19059e39c5baSBill Taylor tavor_flash_reset(state);
19069e39c5baSBill Taylor
19079e39c5baSBill Taylor /*
19089e39c5baSBill Taylor * Pass CFI data back to user command.
19099e39c5baSBill Taylor */
19109e39c5baSBill Taylor for (i = 0; i < TAVOR_FLASH_CFI_SIZE_QUADLET; i++) {
19119e39c5baSBill Taylor tavor_flash_cfi_dword(&cfi_info[i], cfi_ch_info, i << 2);
19129e39c5baSBill Taylor }
19139e39c5baSBill Taylor
19149e39c5baSBill Taylor if (*intel_xcmd == 1) {
19159e39c5baSBill Taylor /*
19169e39c5baSBill Taylor * Inform the user cmd that this driver does support the
19179e39c5baSBill Taylor * Intel Extended Command Set.
19189e39c5baSBill Taylor */
19199e39c5baSBill Taylor cfi_ch_info[0x10] = 'M';
19209e39c5baSBill Taylor cfi_ch_info[0x11] = 'X';
19219e39c5baSBill Taylor cfi_ch_info[0x12] = '2';
19229e39c5baSBill Taylor } else {
19239e39c5baSBill Taylor cfi_ch_info[0x10] = 'Q';
19249e39c5baSBill Taylor cfi_ch_info[0x11] = 'R';
19259e39c5baSBill Taylor cfi_ch_info[0x12] = 'Y';
19269e39c5baSBill Taylor }
19279e39c5baSBill Taylor cfi_ch_info[0x13] = state->ts_fw_cmdset;
19289e39c5baSBill Taylor tavor_flash_cfi_dword(&cfi_info[0x4], cfi_ch_info, 0x10);
19299e39c5baSBill Taylor }
19309e39c5baSBill Taylor
19319e39c5baSBill Taylor /*
19329e39c5baSBill Taylor * tavor_flash_fini()
19339e39c5baSBill Taylor */
19349e39c5baSBill Taylor static void
tavor_flash_fini(tavor_state_t * state)19359e39c5baSBill Taylor tavor_flash_fini(tavor_state_t *state)
19369e39c5baSBill Taylor {
19379e39c5baSBill Taylor ddi_acc_handle_t hdl;
19389e39c5baSBill Taylor
19399e39c5baSBill Taylor /* Set handle */
19409e39c5baSBill Taylor hdl = state->ts_pci_cfghdl;
19419e39c5baSBill Taylor
19429e39c5baSBill Taylor /* Restore original GPIO Values */
19439e39c5baSBill Taylor tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_GPIO_DIR,
19449e39c5baSBill Taylor state->ts_fw_gpio[0]);
19459e39c5baSBill Taylor tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_GPIO_POL,
19469e39c5baSBill Taylor state->ts_fw_gpio[1]);
19479e39c5baSBill Taylor tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_GPIO_MOD,
19489e39c5baSBill Taylor state->ts_fw_gpio[2]);
19499e39c5baSBill Taylor tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_GPIO_DAT,
19509e39c5baSBill Taylor state->ts_fw_gpio[3]);
19519e39c5baSBill Taylor
19529e39c5baSBill Taylor /* Give up semaphore */
19539e39c5baSBill Taylor tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_GPIO_SEMA, 0);
19549e39c5baSBill Taylor }
19559e39c5baSBill Taylor
19569e39c5baSBill Taylor /*
19579e39c5baSBill Taylor * tavor_flash_read_cfg
19589e39c5baSBill Taylor */
19599e39c5baSBill Taylor static uint32_t
tavor_flash_read_cfg(ddi_acc_handle_t pci_config_hdl,uint32_t addr)19609e39c5baSBill Taylor tavor_flash_read_cfg(ddi_acc_handle_t pci_config_hdl, uint32_t addr)
19619e39c5baSBill Taylor {
19629e39c5baSBill Taylor uint32_t read;
19639e39c5baSBill Taylor
19649e39c5baSBill Taylor /*
19659e39c5baSBill Taylor * Perform flash read operation:
19669e39c5baSBill Taylor * 1) Place addr to read from on the TAVOR_HW_FLASH_CFG_ADDR register
19679e39c5baSBill Taylor * 2) Read data at that addr from the TAVOR_HW_FLASH_CFG_DATA register
19689e39c5baSBill Taylor */
19699e39c5baSBill Taylor pci_config_put32(pci_config_hdl, TAVOR_HW_FLASH_CFG_ADDR, addr);
19709e39c5baSBill Taylor read = pci_config_get32(pci_config_hdl, TAVOR_HW_FLASH_CFG_DATA);
19719e39c5baSBill Taylor
19729e39c5baSBill Taylor return (read);
19739e39c5baSBill Taylor }
19749e39c5baSBill Taylor
19759e39c5baSBill Taylor /*
19769e39c5baSBill Taylor * tavor_flash_write_cfg
19779e39c5baSBill Taylor */
19789e39c5baSBill Taylor static void
tavor_flash_write_cfg(ddi_acc_handle_t pci_config_hdl,uint32_t addr,uint32_t data)19799e39c5baSBill Taylor tavor_flash_write_cfg(ddi_acc_handle_t pci_config_hdl, uint32_t addr,
19809e39c5baSBill Taylor uint32_t data)
19819e39c5baSBill Taylor {
19829e39c5baSBill Taylor /*
19839e39c5baSBill Taylor * Perform flash write operation:
19849e39c5baSBill Taylor * 1) Place addr to write to on the TAVOR_HW_FLASH_CFG_ADDR register
19859e39c5baSBill Taylor * 2) Place data to write on to the TAVOR_HW_FLASH_CFG_DATA register
19869e39c5baSBill Taylor */
19879e39c5baSBill Taylor pci_config_put32(pci_config_hdl, TAVOR_HW_FLASH_CFG_ADDR, addr);
19889e39c5baSBill Taylor pci_config_put32(pci_config_hdl, TAVOR_HW_FLASH_CFG_DATA, data);
19899e39c5baSBill Taylor }
19909e39c5baSBill Taylor
19919e39c5baSBill Taylor /*
19929e39c5baSBill Taylor * Support routines to convert Common Flash Interface (CFI) data
19939e39c5baSBill Taylor * from a 32 bit word to a char array, and from a char array to
19949e39c5baSBill Taylor * a 32 bit word.
19959e39c5baSBill Taylor */
19969e39c5baSBill Taylor static void
tavor_flash_cfi_byte(uint8_t * ch,uint32_t dword,int i)19979e39c5baSBill Taylor tavor_flash_cfi_byte(uint8_t *ch, uint32_t dword, int i)
19989e39c5baSBill Taylor {
19999e39c5baSBill Taylor ch[i] = (uint8_t)((dword & 0xFF000000) >> 24);
20009e39c5baSBill Taylor ch[i+1] = (uint8_t)((dword & 0x00FF0000) >> 16);
20019e39c5baSBill Taylor ch[i+2] = (uint8_t)((dword & 0x0000FF00) >> 8);
20029e39c5baSBill Taylor ch[i+3] = (uint8_t)((dword & 0x000000FF));
20039e39c5baSBill Taylor }
20049e39c5baSBill Taylor
20059e39c5baSBill Taylor static void
tavor_flash_cfi_dword(uint32_t * dword,uint8_t * ch,int i)20069e39c5baSBill Taylor tavor_flash_cfi_dword(uint32_t *dword, uint8_t *ch, int i)
20079e39c5baSBill Taylor {
20089e39c5baSBill Taylor *dword = (uint32_t)
20099e39c5baSBill Taylor ((uint32_t)ch[i] << 24 |
20109e39c5baSBill Taylor (uint32_t)ch[i+1] << 16 |
20119e39c5baSBill Taylor (uint32_t)ch[i+2] << 8 |
20129e39c5baSBill Taylor (uint32_t)ch[i+3]);
20139e39c5baSBill Taylor }
20149e39c5baSBill Taylor
20159e39c5baSBill Taylor /*
20169e39c5baSBill Taylor * tavor_loopback_free_qps
20179e39c5baSBill Taylor */
20189e39c5baSBill Taylor static void
tavor_loopback_free_qps(tavor_loopback_state_t * lstate)20199e39c5baSBill Taylor tavor_loopback_free_qps(tavor_loopback_state_t *lstate)
20209e39c5baSBill Taylor {
20219e39c5baSBill Taylor int i;
20229e39c5baSBill Taylor
20239e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lstate))
20249e39c5baSBill Taylor
20259e39c5baSBill Taylor if (lstate->tls_tx.tlc_qp_hdl != NULL) {
20269e39c5baSBill Taylor (void) tavor_qp_free(lstate->tls_state,
20279e39c5baSBill Taylor &lstate->tls_tx.tlc_qp_hdl, IBC_FREE_QP_AND_QPN, NULL,
20289e39c5baSBill Taylor TAVOR_NOSLEEP);
20299e39c5baSBill Taylor }
20309e39c5baSBill Taylor if (lstate->tls_rx.tlc_qp_hdl != NULL) {
20319e39c5baSBill Taylor (void) tavor_qp_free(lstate->tls_state,
20329e39c5baSBill Taylor &lstate->tls_rx.tlc_qp_hdl, IBC_FREE_QP_AND_QPN, NULL,
20339e39c5baSBill Taylor TAVOR_NOSLEEP);
20349e39c5baSBill Taylor }
20359e39c5baSBill Taylor lstate->tls_tx.tlc_qp_hdl = NULL;
20369e39c5baSBill Taylor lstate->tls_rx.tlc_qp_hdl = NULL;
20379e39c5baSBill Taylor for (i = 0; i < 2; i++) {
20389e39c5baSBill Taylor if (lstate->tls_tx.tlc_cqhdl[i] != NULL) {
20399e39c5baSBill Taylor (void) tavor_cq_free(lstate->tls_state,
20409e39c5baSBill Taylor &lstate->tls_tx.tlc_cqhdl[i], TAVOR_NOSLEEP);
20419e39c5baSBill Taylor }
20429e39c5baSBill Taylor if (lstate->tls_rx.tlc_cqhdl[i] != NULL) {
20439e39c5baSBill Taylor (void) tavor_cq_free(lstate->tls_state,
20449e39c5baSBill Taylor &lstate->tls_rx.tlc_cqhdl[i], TAVOR_NOSLEEP);
20459e39c5baSBill Taylor }
20469e39c5baSBill Taylor lstate->tls_tx.tlc_cqhdl[i] = NULL;
20479e39c5baSBill Taylor lstate->tls_rx.tlc_cqhdl[i] = NULL;
20489e39c5baSBill Taylor }
20499e39c5baSBill Taylor }
20509e39c5baSBill Taylor
20519e39c5baSBill Taylor /*
20529e39c5baSBill Taylor * tavor_loopback_free_state
20539e39c5baSBill Taylor */
20549e39c5baSBill Taylor static void
tavor_loopback_free_state(tavor_loopback_state_t * lstate)20559e39c5baSBill Taylor tavor_loopback_free_state(tavor_loopback_state_t *lstate)
20569e39c5baSBill Taylor {
20579e39c5baSBill Taylor tavor_loopback_free_qps(lstate);
20589e39c5baSBill Taylor if (lstate->tls_tx.tlc_mrhdl != NULL) {
20599e39c5baSBill Taylor (void) tavor_mr_deregister(lstate->tls_state,
20609e39c5baSBill Taylor &lstate->tls_tx.tlc_mrhdl, TAVOR_MR_DEREG_ALL,
20619e39c5baSBill Taylor TAVOR_NOSLEEP);
20629e39c5baSBill Taylor }
20639e39c5baSBill Taylor if (lstate->tls_rx.tlc_mrhdl != NULL) {
20649e39c5baSBill Taylor (void) tavor_mr_deregister(lstate->tls_state,
20659e39c5baSBill Taylor &lstate->tls_rx.tlc_mrhdl, TAVOR_MR_DEREG_ALL,
20669e39c5baSBill Taylor TAVOR_NOSLEEP);
20679e39c5baSBill Taylor }
20689e39c5baSBill Taylor if (lstate->tls_pd_hdl != NULL) {
20699e39c5baSBill Taylor (void) tavor_pd_free(lstate->tls_state, &lstate->tls_pd_hdl);
20709e39c5baSBill Taylor }
20719e39c5baSBill Taylor if (lstate->tls_tx.tlc_buf != NULL) {
20729e39c5baSBill Taylor kmem_free(lstate->tls_tx.tlc_buf, lstate->tls_tx.tlc_buf_sz);
20739e39c5baSBill Taylor }
20749e39c5baSBill Taylor if (lstate->tls_rx.tlc_buf != NULL) {
20759e39c5baSBill Taylor kmem_free(lstate->tls_rx.tlc_buf, lstate->tls_rx.tlc_buf_sz);
20769e39c5baSBill Taylor }
20779e39c5baSBill Taylor bzero(lstate, sizeof (tavor_loopback_state_t));
20789e39c5baSBill Taylor }
20799e39c5baSBill Taylor
20809e39c5baSBill Taylor /*
20819e39c5baSBill Taylor * tavor_loopback_init
20829e39c5baSBill Taylor */
20839e39c5baSBill Taylor static int
tavor_loopback_init(tavor_state_t * state,tavor_loopback_state_t * lstate)20849e39c5baSBill Taylor tavor_loopback_init(tavor_state_t *state, tavor_loopback_state_t *lstate)
20859e39c5baSBill Taylor {
20869e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lstate))
20879e39c5baSBill Taylor
20889e39c5baSBill Taylor lstate->tls_hca_hdl = (ibc_hca_hdl_t)state;
20899e39c5baSBill Taylor lstate->tls_status = tavor_pd_alloc(lstate->tls_state,
20909e39c5baSBill Taylor &lstate->tls_pd_hdl, TAVOR_NOSLEEP);
20919e39c5baSBill Taylor if (lstate->tls_status != IBT_SUCCESS) {
20929e39c5baSBill Taylor lstate->tls_err = TAVOR_LOOPBACK_PROT_DOMAIN_ALLOC_FAIL;
20939e39c5baSBill Taylor return (EFAULT);
20949e39c5baSBill Taylor }
20959e39c5baSBill Taylor
20969e39c5baSBill Taylor return (0);
20979e39c5baSBill Taylor }
20989e39c5baSBill Taylor
20999e39c5baSBill Taylor /*
21009e39c5baSBill Taylor * tavor_loopback_init_qp_info
21019e39c5baSBill Taylor */
21029e39c5baSBill Taylor static void
tavor_loopback_init_qp_info(tavor_loopback_state_t * lstate,tavor_loopback_comm_t * comm)21039e39c5baSBill Taylor tavor_loopback_init_qp_info(tavor_loopback_state_t *lstate,
21049e39c5baSBill Taylor tavor_loopback_comm_t *comm)
21059e39c5baSBill Taylor {
21069e39c5baSBill Taylor bzero(&comm->tlc_cq_attr, sizeof (ibt_cq_attr_t));
21079e39c5baSBill Taylor bzero(&comm->tlc_qp_attr, sizeof (ibt_qp_alloc_attr_t));
21089e39c5baSBill Taylor bzero(&comm->tlc_qp_info, sizeof (ibt_qp_info_t));
21099e39c5baSBill Taylor
21109e39c5baSBill Taylor comm->tlc_wrid = 1;
21119e39c5baSBill Taylor comm->tlc_cq_attr.cq_size = 128;
21129e39c5baSBill Taylor comm->tlc_qp_attr.qp_sizes.cs_sq_sgl = 3;
21139e39c5baSBill Taylor comm->tlc_qp_attr.qp_sizes.cs_rq_sgl = 3;
21149e39c5baSBill Taylor comm->tlc_qp_attr.qp_sizes.cs_sq = 16;
21159e39c5baSBill Taylor comm->tlc_qp_attr.qp_sizes.cs_rq = 16;
21169e39c5baSBill Taylor comm->tlc_qp_attr.qp_flags = IBT_WR_SIGNALED;
21179e39c5baSBill Taylor
21189e39c5baSBill Taylor comm->tlc_qp_info.qp_state = IBT_STATE_RESET;
21199e39c5baSBill Taylor comm->tlc_qp_info.qp_trans = IBT_RC_SRV;
21209e39c5baSBill Taylor comm->tlc_qp_info.qp_flags = IBT_CEP_RDMA_RD | IBT_CEP_RDMA_WR;
21219e39c5baSBill Taylor comm->tlc_qp_info.qp_transport.rc.rc_path.cep_hca_port_num =
21229e39c5baSBill Taylor lstate->tls_port;
21239e39c5baSBill Taylor comm->tlc_qp_info.qp_transport.rc.rc_path.cep_pkey_ix =
21249e39c5baSBill Taylor lstate->tls_pkey_ix;
21259e39c5baSBill Taylor comm->tlc_qp_info.qp_transport.rc.rc_path.cep_timeout =
21269e39c5baSBill Taylor lstate->tls_timeout;
21279e39c5baSBill Taylor comm->tlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_srvl = 0;
21289e39c5baSBill Taylor comm->tlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_srate =
21299e39c5baSBill Taylor IBT_SRATE_4X;
21309e39c5baSBill Taylor comm->tlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_send_grh = 0;
21319e39c5baSBill Taylor comm->tlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_dlid =
21329e39c5baSBill Taylor lstate->tls_lid;
21339e39c5baSBill Taylor comm->tlc_qp_info.qp_transport.rc.rc_retry_cnt = lstate->tls_retry;
21349e39c5baSBill Taylor comm->tlc_qp_info.qp_transport.rc.rc_sq_psn = 0;
21359e39c5baSBill Taylor comm->tlc_qp_info.qp_transport.rc.rc_rq_psn = 0;
21369e39c5baSBill Taylor comm->tlc_qp_info.qp_transport.rc.rc_rdma_ra_in = 4;
21379e39c5baSBill Taylor comm->tlc_qp_info.qp_transport.rc.rc_rdma_ra_out = 4;
21389e39c5baSBill Taylor comm->tlc_qp_info.qp_transport.rc.rc_dst_qpn = 0;
21399e39c5baSBill Taylor comm->tlc_qp_info.qp_transport.rc.rc_min_rnr_nak = IBT_RNR_NAK_655ms;
21409e39c5baSBill Taylor comm->tlc_qp_info.qp_transport.rc.rc_path_mtu = IB_MTU_1K;
21419e39c5baSBill Taylor }
21429e39c5baSBill Taylor
21439e39c5baSBill Taylor /*
21449e39c5baSBill Taylor * tavor_loopback_alloc_mem
21459e39c5baSBill Taylor */
21469e39c5baSBill Taylor static int
tavor_loopback_alloc_mem(tavor_loopback_state_t * lstate,tavor_loopback_comm_t * comm,int sz)21479e39c5baSBill Taylor tavor_loopback_alloc_mem(tavor_loopback_state_t *lstate,
21489e39c5baSBill Taylor tavor_loopback_comm_t *comm, int sz)
21499e39c5baSBill Taylor {
21509e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm))
21519e39c5baSBill Taylor
21529e39c5baSBill Taylor /* Allocate buffer of specified size */
21539e39c5baSBill Taylor comm->tlc_buf_sz = sz;
21549e39c5baSBill Taylor comm->tlc_buf = kmem_zalloc(sz, KM_NOSLEEP);
21559e39c5baSBill Taylor if (comm->tlc_buf == NULL) {
21569e39c5baSBill Taylor return (EFAULT);
21579e39c5baSBill Taylor }
21589e39c5baSBill Taylor
21599e39c5baSBill Taylor /* Register the buffer as a memory region */
21609e39c5baSBill Taylor comm->tlc_memattr.mr_vaddr = (uint64_t)(uintptr_t)comm->tlc_buf;
21619e39c5baSBill Taylor comm->tlc_memattr.mr_len = (ib_msglen_t)sz;
21629e39c5baSBill Taylor comm->tlc_memattr.mr_as = NULL;
21639e39c5baSBill Taylor comm->tlc_memattr.mr_flags = IBT_MR_NOSLEEP |
21649e39c5baSBill Taylor IBT_MR_ENABLE_REMOTE_WRITE | IBT_MR_ENABLE_LOCAL_WRITE;
21659e39c5baSBill Taylor
21669e39c5baSBill Taylor comm->tlc_status = tavor_mr_register(lstate->tls_state,
21679e39c5baSBill Taylor lstate->tls_pd_hdl, &comm->tlc_memattr, &comm->tlc_mrhdl, NULL);
21689e39c5baSBill Taylor
21699e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm->tlc_mrhdl))
21709e39c5baSBill Taylor
21719e39c5baSBill Taylor comm->tlc_mrdesc.md_vaddr = comm->tlc_mrhdl->mr_bindinfo.bi_addr;
21729e39c5baSBill Taylor comm->tlc_mrdesc.md_lkey = comm->tlc_mrhdl->mr_lkey;
21739e39c5baSBill Taylor comm->tlc_mrdesc.md_rkey = comm->tlc_mrhdl->mr_rkey;
21749e39c5baSBill Taylor if (comm->tlc_status != IBT_SUCCESS) {
21759e39c5baSBill Taylor return (EFAULT);
21769e39c5baSBill Taylor }
21779e39c5baSBill Taylor return (0);
21789e39c5baSBill Taylor }
21799e39c5baSBill Taylor
21809e39c5baSBill Taylor /*
21819e39c5baSBill Taylor * tavor_loopback_alloc_qps
21829e39c5baSBill Taylor */
21839e39c5baSBill Taylor static int
tavor_loopback_alloc_qps(tavor_loopback_state_t * lstate,tavor_loopback_comm_t * comm)21849e39c5baSBill Taylor tavor_loopback_alloc_qps(tavor_loopback_state_t *lstate,
21859e39c5baSBill Taylor tavor_loopback_comm_t *comm)
21869e39c5baSBill Taylor {
21879e39c5baSBill Taylor uint32_t i, real_size;
21889e39c5baSBill Taylor tavor_qp_info_t qpinfo;
21899e39c5baSBill Taylor
21909e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm))
21919e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lstate))
21929e39c5baSBill Taylor
21939e39c5baSBill Taylor /* Allocate send and recv CQs */
21949e39c5baSBill Taylor for (i = 0; i < 2; i++) {
21959e39c5baSBill Taylor bzero(&comm->tlc_cq_attr, sizeof (ibt_cq_attr_t));
21969e39c5baSBill Taylor comm->tlc_cq_attr.cq_size = 128;
21979e39c5baSBill Taylor comm->tlc_status = tavor_cq_alloc(lstate->tls_state,
21989e39c5baSBill Taylor (ibt_cq_hdl_t)NULL, &comm->tlc_cq_attr, &real_size,
21999e39c5baSBill Taylor &comm->tlc_cqhdl[i], TAVOR_NOSLEEP);
22009e39c5baSBill Taylor if (comm->tlc_status != IBT_SUCCESS) {
22019e39c5baSBill Taylor lstate->tls_err += i;
22029e39c5baSBill Taylor return (EFAULT);
22039e39c5baSBill Taylor }
22049e39c5baSBill Taylor }
22059e39c5baSBill Taylor
22069e39c5baSBill Taylor /* Allocate the QP */
22079e39c5baSBill Taylor tavor_loopback_init_qp_info(lstate, comm);
22089e39c5baSBill Taylor comm->tlc_qp_attr.qp_pd_hdl = (ibt_pd_hdl_t)lstate->tls_pd_hdl;
22099e39c5baSBill Taylor comm->tlc_qp_attr.qp_scq_hdl = (ibt_cq_hdl_t)comm->tlc_cqhdl[0];
22109e39c5baSBill Taylor comm->tlc_qp_attr.qp_rcq_hdl = (ibt_cq_hdl_t)comm->tlc_cqhdl[1];
22119e39c5baSBill Taylor comm->tlc_qp_attr.qp_ibc_scq_hdl = (ibt_opaque1_t)comm->tlc_cqhdl[0];
22129e39c5baSBill Taylor comm->tlc_qp_attr.qp_ibc_rcq_hdl = (ibt_opaque1_t)comm->tlc_cqhdl[1];
22139e39c5baSBill Taylor qpinfo.qpi_attrp = &comm->tlc_qp_attr;
22149e39c5baSBill Taylor qpinfo.qpi_type = IBT_RC_RQP;
22159e39c5baSBill Taylor qpinfo.qpi_ibt_qphdl = NULL;
22169e39c5baSBill Taylor qpinfo.qpi_queueszp = &comm->tlc_chan_sizes;
22179e39c5baSBill Taylor qpinfo.qpi_qpn = &comm->tlc_qp_num;
22189e39c5baSBill Taylor comm->tlc_status = tavor_qp_alloc(lstate->tls_state, &qpinfo,
22199e39c5baSBill Taylor TAVOR_NOSLEEP, NULL);
22209e39c5baSBill Taylor if (comm->tlc_status == DDI_SUCCESS) {
22219e39c5baSBill Taylor comm->tlc_qp_hdl = qpinfo.qpi_qphdl;
22229e39c5baSBill Taylor }
22239e39c5baSBill Taylor
22249e39c5baSBill Taylor if (comm->tlc_status != IBT_SUCCESS) {
22259e39c5baSBill Taylor lstate->tls_err += 2;
22269e39c5baSBill Taylor return (EFAULT);
22279e39c5baSBill Taylor }
22289e39c5baSBill Taylor return (0);
22299e39c5baSBill Taylor }
22309e39c5baSBill Taylor
22319e39c5baSBill Taylor /*
22329e39c5baSBill Taylor * tavor_loopback_modify_qp
22339e39c5baSBill Taylor */
22349e39c5baSBill Taylor static int
tavor_loopback_modify_qp(tavor_loopback_state_t * lstate,tavor_loopback_comm_t * comm,uint_t qp_num)22359e39c5baSBill Taylor tavor_loopback_modify_qp(tavor_loopback_state_t *lstate,
22369e39c5baSBill Taylor tavor_loopback_comm_t *comm, uint_t qp_num)
22379e39c5baSBill Taylor {
22389e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm))
22399e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lstate))
22409e39c5baSBill Taylor
22419e39c5baSBill Taylor /* Modify QP to INIT */
22429e39c5baSBill Taylor tavor_loopback_init_qp_info(lstate, comm);
22439e39c5baSBill Taylor comm->tlc_qp_info.qp_state = IBT_STATE_INIT;
22449e39c5baSBill Taylor comm->tlc_status = tavor_qp_modify(lstate->tls_state, comm->tlc_qp_hdl,
22459e39c5baSBill Taylor IBT_CEP_SET_STATE, &comm->tlc_qp_info, &comm->tlc_queue_sizes);
22469e39c5baSBill Taylor if (comm->tlc_status != IBT_SUCCESS) {
22479e39c5baSBill Taylor return (EFAULT);
22489e39c5baSBill Taylor }
22499e39c5baSBill Taylor
22509e39c5baSBill Taylor /*
22519e39c5baSBill Taylor * Modify QP to RTR (set destination LID and QP number to local
22529e39c5baSBill Taylor * LID and QP number)
22539e39c5baSBill Taylor */
22549e39c5baSBill Taylor comm->tlc_qp_info.qp_state = IBT_STATE_RTR;
22559e39c5baSBill Taylor comm->tlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_dlid
22569e39c5baSBill Taylor = lstate->tls_lid;
22579e39c5baSBill Taylor comm->tlc_qp_info.qp_transport.rc.rc_dst_qpn = qp_num;
22589e39c5baSBill Taylor comm->tlc_status = tavor_qp_modify(lstate->tls_state, comm->tlc_qp_hdl,
22599e39c5baSBill Taylor IBT_CEP_SET_STATE, &comm->tlc_qp_info, &comm->tlc_queue_sizes);
22609e39c5baSBill Taylor if (comm->tlc_status != IBT_SUCCESS) {
22619e39c5baSBill Taylor lstate->tls_err += 1;
22629e39c5baSBill Taylor return (EFAULT);
22639e39c5baSBill Taylor }
22649e39c5baSBill Taylor
22659e39c5baSBill Taylor /* Modify QP to RTS */
22669e39c5baSBill Taylor comm->tlc_qp_info.qp_current_state = IBT_STATE_RTR;
22679e39c5baSBill Taylor comm->tlc_qp_info.qp_state = IBT_STATE_RTS;
22689e39c5baSBill Taylor comm->tlc_status = tavor_qp_modify(lstate->tls_state, comm->tlc_qp_hdl,
22699e39c5baSBill Taylor IBT_CEP_SET_STATE, &comm->tlc_qp_info, &comm->tlc_queue_sizes);
22709e39c5baSBill Taylor if (comm->tlc_status != IBT_SUCCESS) {
22719e39c5baSBill Taylor lstate->tls_err += 2;
22729e39c5baSBill Taylor return (EFAULT);
22739e39c5baSBill Taylor }
22749e39c5baSBill Taylor return (0);
22759e39c5baSBill Taylor }
22769e39c5baSBill Taylor
22779e39c5baSBill Taylor /*
22789e39c5baSBill Taylor * tavor_loopback_copyout
22799e39c5baSBill Taylor */
22809e39c5baSBill Taylor static int
tavor_loopback_copyout(tavor_loopback_ioctl_t * lb,intptr_t arg,int mode)22819e39c5baSBill Taylor tavor_loopback_copyout(tavor_loopback_ioctl_t *lb, intptr_t arg, int mode)
22829e39c5baSBill Taylor {
22839e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
22849e39c5baSBill Taylor if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
22859e39c5baSBill Taylor tavor_loopback_ioctl32_t lb32;
22869e39c5baSBill Taylor
22879e39c5baSBill Taylor lb32.tlb_revision = lb->tlb_revision;
22889e39c5baSBill Taylor lb32.tlb_send_buf =
22899e39c5baSBill Taylor (caddr32_t)(uintptr_t)lb->tlb_send_buf;
22909e39c5baSBill Taylor lb32.tlb_fail_buf =
22919e39c5baSBill Taylor (caddr32_t)(uintptr_t)lb->tlb_fail_buf;
22929e39c5baSBill Taylor lb32.tlb_buf_sz = lb->tlb_buf_sz;
22939e39c5baSBill Taylor lb32.tlb_num_iter = lb->tlb_num_iter;
22949e39c5baSBill Taylor lb32.tlb_pass_done = lb->tlb_pass_done;
22959e39c5baSBill Taylor lb32.tlb_timeout = lb->tlb_timeout;
22969e39c5baSBill Taylor lb32.tlb_error_type = lb->tlb_error_type;
22979e39c5baSBill Taylor lb32.tlb_port_num = lb->tlb_port_num;
22989e39c5baSBill Taylor lb32.tlb_num_retry = lb->tlb_num_retry;
22999e39c5baSBill Taylor
23009e39c5baSBill Taylor if (ddi_copyout(&lb32, (void *)arg,
23019e39c5baSBill Taylor sizeof (tavor_loopback_ioctl32_t), mode) != 0) {
23029e39c5baSBill Taylor return (EFAULT);
23039e39c5baSBill Taylor }
23049e39c5baSBill Taylor } else
23059e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
23069e39c5baSBill Taylor if (ddi_copyout(lb, (void *)arg, sizeof (tavor_loopback_ioctl_t),
23079e39c5baSBill Taylor mode) != 0) {
23089e39c5baSBill Taylor return (EFAULT);
23099e39c5baSBill Taylor }
23109e39c5baSBill Taylor return (0);
23119e39c5baSBill Taylor }
23129e39c5baSBill Taylor
23139e39c5baSBill Taylor /*
23149e39c5baSBill Taylor * tavor_loopback_post_send
23159e39c5baSBill Taylor */
23169e39c5baSBill Taylor static int
tavor_loopback_post_send(tavor_loopback_state_t * lstate,tavor_loopback_comm_t * tx,tavor_loopback_comm_t * rx)23179e39c5baSBill Taylor tavor_loopback_post_send(tavor_loopback_state_t *lstate,
23189e39c5baSBill Taylor tavor_loopback_comm_t *tx, tavor_loopback_comm_t *rx)
23199e39c5baSBill Taylor {
23209e39c5baSBill Taylor int ret;
23219e39c5baSBill Taylor
23229e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*tx))
23239e39c5baSBill Taylor
23249e39c5baSBill Taylor bzero(&tx->tlc_sgl, sizeof (ibt_wr_ds_t));
23259e39c5baSBill Taylor bzero(&tx->tlc_wr, sizeof (ibt_send_wr_t));
23269e39c5baSBill Taylor
23279e39c5baSBill Taylor /* Initialize local address for TX buffer */
23289e39c5baSBill Taylor tx->tlc_sgl.ds_va = tx->tlc_mrdesc.md_vaddr;
23299e39c5baSBill Taylor tx->tlc_sgl.ds_key = tx->tlc_mrdesc.md_lkey;
23309e39c5baSBill Taylor tx->tlc_sgl.ds_len = tx->tlc_buf_sz;
23319e39c5baSBill Taylor
23329e39c5baSBill Taylor /* Initialize the remaining details of the work request */
23339e39c5baSBill Taylor tx->tlc_wr.wr_id = tx->tlc_wrid++;
23349e39c5baSBill Taylor tx->tlc_wr.wr_flags = IBT_WR_SEND_SIGNAL;
23359e39c5baSBill Taylor tx->tlc_wr.wr_nds = 1;
23369e39c5baSBill Taylor tx->tlc_wr.wr_sgl = &tx->tlc_sgl;
23379e39c5baSBill Taylor tx->tlc_wr.wr_opcode = IBT_WRC_RDMAW;
23389e39c5baSBill Taylor tx->tlc_wr.wr_trans = IBT_RC_SRV;
23399e39c5baSBill Taylor
23409e39c5baSBill Taylor /* Initialize the remote address for RX buffer */
23419e39c5baSBill Taylor tx->tlc_wr.wr.rc.rcwr.rdma.rdma_raddr = rx->tlc_mrdesc.md_vaddr;
23429e39c5baSBill Taylor tx->tlc_wr.wr.rc.rcwr.rdma.rdma_rkey = rx->tlc_mrdesc.md_rkey;
23439e39c5baSBill Taylor tx->tlc_complete = 0;
23449e39c5baSBill Taylor ret = tavor_post_send(lstate->tls_state, tx->tlc_qp_hdl, &tx->tlc_wr,
23459e39c5baSBill Taylor 1, NULL);
23469e39c5baSBill Taylor if (ret != IBT_SUCCESS) {
23479e39c5baSBill Taylor return (EFAULT);
23489e39c5baSBill Taylor }
23499e39c5baSBill Taylor return (0);
23509e39c5baSBill Taylor }
23519e39c5baSBill Taylor
23529e39c5baSBill Taylor /*
23539e39c5baSBill Taylor * tavor_loopback_poll_cq
23549e39c5baSBill Taylor */
23559e39c5baSBill Taylor static int
tavor_loopback_poll_cq(tavor_loopback_state_t * lstate,tavor_loopback_comm_t * comm)23569e39c5baSBill Taylor tavor_loopback_poll_cq(tavor_loopback_state_t *lstate,
23579e39c5baSBill Taylor tavor_loopback_comm_t *comm)
23589e39c5baSBill Taylor {
23599e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm))
23609e39c5baSBill Taylor
23619e39c5baSBill Taylor comm->tlc_wc.wc_status = 0;
23629e39c5baSBill Taylor comm->tlc_num_polled = 0;
23639e39c5baSBill Taylor comm->tlc_status = tavor_cq_poll(lstate->tls_state,
23649e39c5baSBill Taylor comm->tlc_cqhdl[0], &comm->tlc_wc, 1, &comm->tlc_num_polled);
23659e39c5baSBill Taylor if ((comm->tlc_status == IBT_SUCCESS) &&
23669e39c5baSBill Taylor (comm->tlc_wc.wc_status != IBT_WC_SUCCESS)) {
23679e39c5baSBill Taylor comm->tlc_status = ibc_get_ci_failure(0);
23689e39c5baSBill Taylor }
23699e39c5baSBill Taylor return (comm->tlc_status);
23709e39c5baSBill Taylor }
2371