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