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 /*
23*13cc0a0bSBill Taylor  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
249e39c5baSBill Taylor  */
259e39c5baSBill Taylor 
269e39c5baSBill Taylor /*
279e39c5baSBill Taylor  * hermon_ioctl.c
289e39c5baSBill Taylor  *    Hemron IOCTL Routines
299e39c5baSBill Taylor  *
309e39c5baSBill Taylor  *    Implements all ioctl access into the driver.  This includes all routines
319e39c5baSBill Taylor  *    necessary for updating firmware, accessing the hermon flash device, and
329e39c5baSBill Taylor  *    providing interfaces for VTS.
339e39c5baSBill Taylor  */
349e39c5baSBill Taylor 
359e39c5baSBill Taylor #include <sys/types.h>
369e39c5baSBill Taylor #include <sys/conf.h>
379e39c5baSBill Taylor #include <sys/ddi.h>
389e39c5baSBill Taylor #include <sys/sunddi.h>
399e39c5baSBill Taylor #include <sys/modctl.h>
409e39c5baSBill Taylor #include <sys/file.h>
419e39c5baSBill Taylor 
429e39c5baSBill Taylor #include <sys/ib/adapters/hermon/hermon.h>
439e39c5baSBill Taylor 
449e39c5baSBill Taylor /* Hemron HCA state pointer (extern) */
459e39c5baSBill Taylor extern void	*hermon_statep;
469e39c5baSBill Taylor extern int	hermon_verbose;
479e39c5baSBill Taylor 
489e39c5baSBill Taylor #define	DO_WRCONF	1
499e39c5baSBill Taylor static int do_bar0 = 1;
509e39c5baSBill Taylor 
519e39c5baSBill Taylor /*
529e39c5baSBill Taylor  * The ioctl declarations (for firmware flash burning, register read/write
539e39c5baSBill Taylor  * (DEBUG-only), and VTS interfaces)
549e39c5baSBill Taylor  */
559e39c5baSBill Taylor static int hermon_ioctl_flash_read(hermon_state_t *state, dev_t dev,
569e39c5baSBill Taylor     intptr_t arg, int mode);
579e39c5baSBill Taylor static int hermon_ioctl_flash_write(hermon_state_t *state, dev_t dev,
589e39c5baSBill Taylor     intptr_t arg, int mode);
599e39c5baSBill Taylor static int hermon_ioctl_flash_erase(hermon_state_t *state, dev_t dev,
609e39c5baSBill Taylor     intptr_t arg, int mode);
619e39c5baSBill Taylor static int hermon_ioctl_flash_init(hermon_state_t *state, dev_t dev,
629e39c5baSBill Taylor     intptr_t arg, int mode);
639e39c5baSBill Taylor static int hermon_ioctl_flash_fini(hermon_state_t *state, dev_t dev);
649e39c5baSBill Taylor static int hermon_ioctl_flash_cleanup(hermon_state_t *state);
659e39c5baSBill Taylor static int hermon_ioctl_flash_cleanup_nolock(hermon_state_t *state);
669e39c5baSBill Taylor #ifdef	DEBUG
679e39c5baSBill Taylor static int hermon_ioctl_reg_write(hermon_state_t *state, intptr_t arg,
689e39c5baSBill Taylor     int mode);
699e39c5baSBill Taylor static int hermon_ioctl_reg_read(hermon_state_t *state, intptr_t arg,
709e39c5baSBill Taylor     int mode);
719e39c5baSBill Taylor #endif	/* DEBUG */
729e39c5baSBill Taylor static int hermon_ioctl_write_boot_addr(hermon_state_t *state, dev_t dev,
739e39c5baSBill Taylor     intptr_t arg, int mode);
749e39c5baSBill Taylor static int hermon_ioctl_info(hermon_state_t *state, dev_t dev,
759e39c5baSBill Taylor     intptr_t arg, int mode);
769e39c5baSBill Taylor static int hermon_ioctl_ports(hermon_state_t *state, intptr_t arg,
779e39c5baSBill Taylor     int mode);
789e39c5baSBill Taylor static int hermon_ioctl_loopback(hermon_state_t *state, intptr_t arg,
799e39c5baSBill Taylor     int mode);
809e39c5baSBill Taylor 
819e39c5baSBill Taylor /* Hemron Flash Functions */
829e39c5baSBill Taylor static void hermon_flash_spi_exec_command(hermon_state_t *state,
839e39c5baSBill Taylor     ddi_acc_handle_t hdl, uint32_t cmd);
849e39c5baSBill Taylor static int hermon_flash_read_sector(hermon_state_t *state,
859e39c5baSBill Taylor     uint32_t sector_num);
869e39c5baSBill Taylor static int hermon_flash_read_quadlet(hermon_state_t *state, uint32_t *data,
879e39c5baSBill Taylor     uint32_t addr);
889e39c5baSBill Taylor static int hermon_flash_write_sector(hermon_state_t *state,
899e39c5baSBill Taylor     uint32_t sector_num);
909e39c5baSBill Taylor static int hermon_flash_spi_write_dword(hermon_state_t *state,
919e39c5baSBill Taylor     uint32_t addr, uint32_t data);
929e39c5baSBill Taylor static int hermon_flash_write_byte(hermon_state_t *state, uint32_t addr,
939e39c5baSBill Taylor     uchar_t data);
949e39c5baSBill Taylor static int hermon_flash_erase_sector(hermon_state_t *state,
959e39c5baSBill Taylor     uint32_t sector_num);
969e39c5baSBill Taylor static int hermon_flash_erase_chip(hermon_state_t *state);
979e39c5baSBill Taylor static int hermon_flash_bank(hermon_state_t *state, uint32_t addr);
989e39c5baSBill Taylor static uint32_t hermon_flash_read(hermon_state_t *state, uint32_t addr,
999e39c5baSBill Taylor     int *err);
1009e39c5baSBill Taylor static void hermon_flash_write(hermon_state_t *state, uint32_t addr,
1019e39c5baSBill Taylor     uchar_t data, int *err);
1029e39c5baSBill Taylor static int hermon_flash_spi_wait_wip(hermon_state_t *state);
1039e39c5baSBill Taylor static void hermon_flash_spi_write_enable(hermon_state_t *state);
1049e39c5baSBill Taylor static int hermon_flash_init(hermon_state_t *state);
1059e39c5baSBill Taylor static int hermon_flash_cfi_init(hermon_state_t *state, uint32_t *cfi_info,
1069e39c5baSBill Taylor     int *intel_xcmd);
1079e39c5baSBill Taylor static int hermon_flash_fini(hermon_state_t *state);
1089e39c5baSBill Taylor static int hermon_flash_reset(hermon_state_t *state);
1099e39c5baSBill Taylor static uint32_t hermon_flash_read_cfg(hermon_state_t *state,
1109e39c5baSBill Taylor     ddi_acc_handle_t pci_config_hdl, uint32_t addr);
1119e39c5baSBill Taylor #ifdef DO_WRCONF
1129e39c5baSBill Taylor static void hermon_flash_write_cfg(hermon_state_t *state,
1139e39c5baSBill Taylor     ddi_acc_handle_t pci_config_hdl, uint32_t addr, uint32_t data);
1149e39c5baSBill Taylor static void hermon_flash_write_cfg_helper(hermon_state_t *state,
1159e39c5baSBill Taylor     ddi_acc_handle_t pci_config_hdl, uint32_t addr, uint32_t data);
1169e39c5baSBill Taylor static void hermon_flash_write_confirm(hermon_state_t *state,
1179e39c5baSBill Taylor     ddi_acc_handle_t pci_config_hdl);
1189e39c5baSBill Taylor #endif
1199e39c5baSBill Taylor static void hermon_flash_cfi_byte(uint8_t *ch, uint32_t dword, int i);
1209e39c5baSBill Taylor static void hermon_flash_cfi_dword(uint32_t *dword, uint8_t *ch, int i);
1219e39c5baSBill Taylor 
1229e39c5baSBill Taylor /* Hemron loopback test functions */
1239e39c5baSBill Taylor static void hermon_loopback_free_qps(hermon_loopback_state_t *lstate);
1249e39c5baSBill Taylor static void hermon_loopback_free_state(hermon_loopback_state_t *lstate);
1259e39c5baSBill Taylor static int hermon_loopback_init(hermon_state_t *state,
1269e39c5baSBill Taylor     hermon_loopback_state_t *lstate);
1279e39c5baSBill Taylor static void hermon_loopback_init_qp_info(hermon_loopback_state_t *lstate,
1289e39c5baSBill Taylor     hermon_loopback_comm_t *comm);
1299e39c5baSBill Taylor static int hermon_loopback_alloc_mem(hermon_loopback_state_t *lstate,
1309e39c5baSBill Taylor     hermon_loopback_comm_t *comm, int sz);
1319e39c5baSBill Taylor static int hermon_loopback_alloc_qps(hermon_loopback_state_t *lstate,
1329e39c5baSBill Taylor     hermon_loopback_comm_t *comm);
1339e39c5baSBill Taylor static int hermon_loopback_modify_qp(hermon_loopback_state_t *lstate,
1349e39c5baSBill Taylor     hermon_loopback_comm_t *comm, uint_t qp_num);
1359e39c5baSBill Taylor static int hermon_loopback_copyout(hermon_loopback_ioctl_t *lb,
1369e39c5baSBill Taylor     intptr_t arg, int mode);
1379e39c5baSBill Taylor static int hermon_loopback_post_send(hermon_loopback_state_t *lstate,
1389e39c5baSBill Taylor     hermon_loopback_comm_t *tx, hermon_loopback_comm_t *rx);
1399e39c5baSBill Taylor static int hermon_loopback_poll_cq(hermon_loopback_state_t *lstate,
1409e39c5baSBill Taylor     hermon_loopback_comm_t *comm);
1419e39c5baSBill Taylor 
1429e39c5baSBill Taylor /* Patchable timeout values for flash operations */
1439e39c5baSBill Taylor int hermon_hw_flash_timeout_gpio_sema = HERMON_HW_FLASH_TIMEOUT_GPIO_SEMA;
1449e39c5baSBill Taylor int hermon_hw_flash_timeout_config = HERMON_HW_FLASH_TIMEOUT_CONFIG;
1459e39c5baSBill Taylor int hermon_hw_flash_timeout_write = HERMON_HW_FLASH_TIMEOUT_WRITE;
1469e39c5baSBill Taylor int hermon_hw_flash_timeout_erase = HERMON_HW_FLASH_TIMEOUT_ERASE;
1479e39c5baSBill Taylor 
1489e39c5baSBill Taylor /*
1499e39c5baSBill Taylor  * hermon_ioctl()
1509e39c5baSBill Taylor  */
1519e39c5baSBill Taylor /* ARGSUSED */
1529e39c5baSBill Taylor int
hermon_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)1539e39c5baSBill Taylor hermon_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
1549e39c5baSBill Taylor     int *rvalp)
1559e39c5baSBill Taylor {
1569e39c5baSBill Taylor 	hermon_state_t	*state;
1579e39c5baSBill Taylor 	minor_t		instance;
1589e39c5baSBill Taylor 	int		status;
1599e39c5baSBill Taylor 
1609e39c5baSBill Taylor 	if (drv_priv(credp) != 0) {
1619e39c5baSBill Taylor 		return (EPERM);
1629e39c5baSBill Taylor 	}
1639e39c5baSBill Taylor 
1649e39c5baSBill Taylor 	instance = HERMON_DEV_INSTANCE(dev);
1659e39c5baSBill Taylor 	if (instance == (minor_t)-1) {
1669e39c5baSBill Taylor 		return (EBADF);
1679e39c5baSBill Taylor 	}
1689e39c5baSBill Taylor 
1699e39c5baSBill Taylor 	state = ddi_get_soft_state(hermon_statep, instance);
1709e39c5baSBill Taylor 	if (state == NULL) {
1719e39c5baSBill Taylor 		return (EBADF);
1729e39c5baSBill Taylor 	}
1739e39c5baSBill Taylor 
1749e39c5baSBill Taylor 	status = 0;
1759e39c5baSBill Taylor 
1769e39c5baSBill Taylor 	switch (cmd) {
1779e39c5baSBill Taylor 	case HERMON_IOCTL_FLASH_READ:
1789e39c5baSBill Taylor 		status = hermon_ioctl_flash_read(state, dev, arg, mode);
1799e39c5baSBill Taylor 		break;
1809e39c5baSBill Taylor 
1819e39c5baSBill Taylor 	case HERMON_IOCTL_FLASH_WRITE:
1829e39c5baSBill Taylor 		status = hermon_ioctl_flash_write(state, dev, arg, mode);
1839e39c5baSBill Taylor 		break;
1849e39c5baSBill Taylor 
1859e39c5baSBill Taylor 	case HERMON_IOCTL_FLASH_ERASE:
1869e39c5baSBill Taylor 		status = hermon_ioctl_flash_erase(state, dev, arg, mode);
1879e39c5baSBill Taylor 		break;
1889e39c5baSBill Taylor 
1899e39c5baSBill Taylor 	case HERMON_IOCTL_FLASH_INIT:
1909e39c5baSBill Taylor 		status = hermon_ioctl_flash_init(state, dev, arg, mode);
1919e39c5baSBill Taylor 		break;
1929e39c5baSBill Taylor 
1939e39c5baSBill Taylor 	case HERMON_IOCTL_FLASH_FINI:
1949e39c5baSBill Taylor 		status = hermon_ioctl_flash_fini(state, dev);
1959e39c5baSBill Taylor 		break;
1969e39c5baSBill Taylor 
1979e39c5baSBill Taylor 	case HERMON_IOCTL_INFO:
1989e39c5baSBill Taylor 		status = hermon_ioctl_info(state, dev, arg, mode);
1999e39c5baSBill Taylor 		break;
2009e39c5baSBill Taylor 
2019e39c5baSBill Taylor 	case HERMON_IOCTL_PORTS:
2029e39c5baSBill Taylor 		status = hermon_ioctl_ports(state, arg, mode);
2039e39c5baSBill Taylor 		break;
2049e39c5baSBill Taylor 
2059e39c5baSBill Taylor 	case HERMON_IOCTL_LOOPBACK:
2069e39c5baSBill Taylor 		status = hermon_ioctl_loopback(state, arg, mode);
2079e39c5baSBill Taylor 		break;
2089e39c5baSBill Taylor 
2099e39c5baSBill Taylor #ifdef	DEBUG
2109e39c5baSBill Taylor 	case HERMON_IOCTL_REG_WRITE:
2119e39c5baSBill Taylor 		status = hermon_ioctl_reg_write(state, arg, mode);
2129e39c5baSBill Taylor 		break;
2139e39c5baSBill Taylor 
2149e39c5baSBill Taylor 	case HERMON_IOCTL_REG_READ:
2159e39c5baSBill Taylor 		status = hermon_ioctl_reg_read(state, arg, mode);
2169e39c5baSBill Taylor 		break;
2179e39c5baSBill Taylor #endif	/* DEBUG */
2189e39c5baSBill Taylor 
2199e39c5baSBill Taylor 	case HERMON_IOCTL_DDR_READ:
2209e39c5baSBill Taylor 		/* XXX guard until the ioctl header is cleaned up */
2219e39c5baSBill Taylor 		status = ENODEV;
2229e39c5baSBill Taylor 		break;
2239e39c5baSBill Taylor 
2249e39c5baSBill Taylor 	case HERMON_IOCTL_WRITE_BOOT_ADDR:
2259e39c5baSBill Taylor 		status = hermon_ioctl_write_boot_addr(state, dev, arg, mode);
2269e39c5baSBill Taylor 		break;
2279e39c5baSBill Taylor 
2289e39c5baSBill Taylor 	default:
2299e39c5baSBill Taylor 		status = ENOTTY;
2309e39c5baSBill Taylor 		break;
2319e39c5baSBill Taylor 	}
2329e39c5baSBill Taylor 	*rvalp = status;
2339e39c5baSBill Taylor 
2349e39c5baSBill Taylor 	return (status);
2359e39c5baSBill Taylor }
2369e39c5baSBill Taylor 
2379e39c5baSBill Taylor /*
2389e39c5baSBill Taylor  * hermon_ioctl_flash_read()
2399e39c5baSBill Taylor  */
2409e39c5baSBill Taylor static int
hermon_ioctl_flash_read(hermon_state_t * state,dev_t dev,intptr_t arg,int mode)2419e39c5baSBill Taylor hermon_ioctl_flash_read(hermon_state_t *state, dev_t dev, intptr_t arg,
2429e39c5baSBill Taylor     int mode)
2439e39c5baSBill Taylor {
2449e39c5baSBill Taylor 	hermon_flash_ioctl_t ioctl_info;
2459e39c5baSBill Taylor 	int status = 0;
2469e39c5baSBill Taylor 
2479e39c5baSBill Taylor 	/*
2489e39c5baSBill Taylor 	 * Check that flash init ioctl has been called first.  And check
2499e39c5baSBill Taylor 	 * that the same dev_t that called init is the one calling read now.
2509e39c5baSBill Taylor 	 */
2519e39c5baSBill Taylor 	mutex_enter(&state->hs_fw_flashlock);
2529e39c5baSBill Taylor 	if ((state->hs_fw_flashdev != dev) ||
2539e39c5baSBill Taylor 	    (state->hs_fw_flashstarted == 0)) {
2549e39c5baSBill Taylor 		mutex_exit(&state->hs_fw_flashlock);
2559e39c5baSBill Taylor 		return (EIO);
2569e39c5baSBill Taylor 	}
2579e39c5baSBill Taylor 
2589e39c5baSBill Taylor 	/* copy user struct to kernel */
2599e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
2609e39c5baSBill Taylor 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
2619e39c5baSBill Taylor 		hermon_flash_ioctl32_t info32;
2629e39c5baSBill Taylor 
2639e39c5baSBill Taylor 		if (ddi_copyin((void *)arg, &info32,
2649e39c5baSBill Taylor 		    sizeof (hermon_flash_ioctl32_t), mode) != 0) {
2659e39c5baSBill Taylor 			mutex_exit(&state->hs_fw_flashlock);
2669e39c5baSBill Taylor 			return (EFAULT);
2679e39c5baSBill Taylor 		}
2689e39c5baSBill Taylor 		ioctl_info.af_type = info32.af_type;
2699e39c5baSBill Taylor 		ioctl_info.af_sector = (caddr_t)(uintptr_t)info32.af_sector;
2709e39c5baSBill Taylor 		ioctl_info.af_sector_num = info32.af_sector_num;
2719e39c5baSBill Taylor 		ioctl_info.af_addr = info32.af_addr;
2729e39c5baSBill Taylor 	} else
2739e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
2749e39c5baSBill Taylor 	if (ddi_copyin((void *)arg, &ioctl_info, sizeof (hermon_flash_ioctl_t),
2759e39c5baSBill Taylor 	    mode) != 0) {
2769e39c5baSBill Taylor 		mutex_exit(&state->hs_fw_flashlock);
2779e39c5baSBill Taylor 		return (EFAULT);
2789e39c5baSBill Taylor 	}
2799e39c5baSBill Taylor 
2809e39c5baSBill Taylor 	/*
2819e39c5baSBill Taylor 	 * Determine type of READ ioctl
2829e39c5baSBill Taylor 	 */
2839e39c5baSBill Taylor 	switch (ioctl_info.af_type) {
2849e39c5baSBill Taylor 	case HERMON_FLASH_READ_SECTOR:
2859e39c5baSBill Taylor 		/* Check if sector num is too large for flash device */
2869e39c5baSBill Taylor 		if (ioctl_info.af_sector_num >=
2879e39c5baSBill Taylor 		    (state->hs_fw_device_sz >> state->hs_fw_log_sector_sz)) {
2889e39c5baSBill Taylor 			mutex_exit(&state->hs_fw_flashlock);
2899e39c5baSBill Taylor 			return (EFAULT);
2909e39c5baSBill Taylor 		}
2919e39c5baSBill Taylor 
2929e39c5baSBill Taylor 		/* Perform the Sector Read */
2939e39c5baSBill Taylor 		if ((status = hermon_flash_reset(state)) != 0 ||
2949e39c5baSBill Taylor 		    (status = hermon_flash_read_sector(state,
2959e39c5baSBill Taylor 		    ioctl_info.af_sector_num)) != 0) {
2969e39c5baSBill Taylor 			mutex_exit(&state->hs_fw_flashlock);
2979e39c5baSBill Taylor 			return (status);
2989e39c5baSBill Taylor 		}
2999e39c5baSBill Taylor 
3009e39c5baSBill Taylor 		/* copyout the firmware sector image data */
3019e39c5baSBill Taylor 		if (ddi_copyout(&state->hs_fw_sector[0],
3029e39c5baSBill Taylor 		    &ioctl_info.af_sector[0], 1 << state->hs_fw_log_sector_sz,
3039e39c5baSBill Taylor 		    mode) != 0) {
3049e39c5baSBill Taylor 			mutex_exit(&state->hs_fw_flashlock);
3059e39c5baSBill Taylor 			return (EFAULT);
3069e39c5baSBill Taylor 		}
3079e39c5baSBill Taylor 		break;
3089e39c5baSBill Taylor 
3099e39c5baSBill Taylor 	case HERMON_FLASH_READ_QUADLET:
3109e39c5baSBill Taylor 		/* Check if addr is too large for flash device */
3119e39c5baSBill Taylor 		if (ioctl_info.af_addr >= state->hs_fw_device_sz) {
3129e39c5baSBill Taylor 			mutex_exit(&state->hs_fw_flashlock);
3139e39c5baSBill Taylor 			return (EFAULT);
3149e39c5baSBill Taylor 		}
3159e39c5baSBill Taylor 
3169e39c5baSBill Taylor 		/* Perform the Quadlet Read */
3179e39c5baSBill Taylor 		if ((status = hermon_flash_reset(state)) != 0 ||
3189e39c5baSBill Taylor 		    (status = hermon_flash_read_quadlet(state,
3199e39c5baSBill Taylor 		    &ioctl_info.af_quadlet, ioctl_info.af_addr)) != 0) {
3209e39c5baSBill Taylor 			mutex_exit(&state->hs_fw_flashlock);
3219e39c5baSBill Taylor 			return (status);
3229e39c5baSBill Taylor 		}
3239e39c5baSBill Taylor 		break;
3249e39c5baSBill Taylor 
3259e39c5baSBill Taylor 	default:
3269e39c5baSBill Taylor 		mutex_exit(&state->hs_fw_flashlock);
3279e39c5baSBill Taylor 		return (EINVAL);
3289e39c5baSBill Taylor 	}
3299e39c5baSBill Taylor 
3309e39c5baSBill Taylor 	/* copy results back to userland */
3319e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
3329e39c5baSBill Taylor 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
3339e39c5baSBill Taylor 		hermon_flash_ioctl32_t info32;
3349e39c5baSBill Taylor 
3359e39c5baSBill Taylor 		info32.af_quadlet = ioctl_info.af_quadlet;
3369e39c5baSBill Taylor 		info32.af_type = ioctl_info.af_type;
3379e39c5baSBill Taylor 		info32.af_sector_num = ioctl_info.af_sector_num;
3389e39c5baSBill Taylor 		info32.af_sector = (caddr32_t)(uintptr_t)ioctl_info.af_sector;
3399e39c5baSBill Taylor 		info32.af_addr = ioctl_info.af_addr;
3409e39c5baSBill Taylor 
3419e39c5baSBill Taylor 		if (ddi_copyout(&info32, (void *)arg,
3429e39c5baSBill Taylor 		    sizeof (hermon_flash_ioctl32_t), mode) != 0) {
3439e39c5baSBill Taylor 			mutex_exit(&state->hs_fw_flashlock);
3449e39c5baSBill Taylor 			return (EFAULT);
3459e39c5baSBill Taylor 		}
3469e39c5baSBill Taylor 	} else
3479e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
3489e39c5baSBill Taylor 	if (ddi_copyout(&ioctl_info, (void *)arg,
3499e39c5baSBill Taylor 	    sizeof (hermon_flash_ioctl_t), mode) != 0) {
3509e39c5baSBill Taylor 		mutex_exit(&state->hs_fw_flashlock);
3519e39c5baSBill Taylor 		return (EFAULT);
3529e39c5baSBill Taylor 	}
3539e39c5baSBill Taylor 
3549e39c5baSBill Taylor 	mutex_exit(&state->hs_fw_flashlock);
3559e39c5baSBill Taylor 	return (status);
3569e39c5baSBill Taylor }
3579e39c5baSBill Taylor 
3589e39c5baSBill Taylor /*
3599e39c5baSBill Taylor  * hermon_ioctl_flash_write()
3609e39c5baSBill Taylor  */
3619e39c5baSBill Taylor static int
hermon_ioctl_flash_write(hermon_state_t * state,dev_t dev,intptr_t arg,int mode)3629e39c5baSBill Taylor hermon_ioctl_flash_write(hermon_state_t *state, dev_t dev, intptr_t arg,
3639e39c5baSBill Taylor     int mode)
3649e39c5baSBill Taylor {
3659e39c5baSBill Taylor 	hermon_flash_ioctl_t	ioctl_info;
3669e39c5baSBill Taylor 	int status = 0;
3679e39c5baSBill Taylor 
3689e39c5baSBill Taylor 	/*
3699e39c5baSBill Taylor 	 * Check that flash init ioctl has been called first.  And check
3709e39c5baSBill Taylor 	 * that the same dev_t that called init is the one calling write now.
3719e39c5baSBill Taylor 	 */
3729e39c5baSBill Taylor 	mutex_enter(&state->hs_fw_flashlock);
3739e39c5baSBill Taylor 	if ((state->hs_fw_flashdev != dev) ||
3749e39c5baSBill Taylor 	    (state->hs_fw_flashstarted == 0)) {
3759e39c5baSBill Taylor 		mutex_exit(&state->hs_fw_flashlock);
3769e39c5baSBill Taylor 		return (EIO);
3779e39c5baSBill Taylor 	}
3789e39c5baSBill Taylor 
3799e39c5baSBill Taylor 	/* copy user struct to kernel */
3809e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
3819e39c5baSBill Taylor 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
3829e39c5baSBill Taylor 		hermon_flash_ioctl32_t info32;
3839e39c5baSBill Taylor 
3849e39c5baSBill Taylor 		if (ddi_copyin((void *)arg, &info32,
3859e39c5baSBill Taylor 		    sizeof (hermon_flash_ioctl32_t), mode) != 0) {
3869e39c5baSBill Taylor 			mutex_exit(&state->hs_fw_flashlock);
3879e39c5baSBill Taylor 			return (EFAULT);
3889e39c5baSBill Taylor 		}
3899e39c5baSBill Taylor 		ioctl_info.af_type = info32.af_type;
3909e39c5baSBill Taylor 		ioctl_info.af_sector = (caddr_t)(uintptr_t)info32.af_sector;
3919e39c5baSBill Taylor 		ioctl_info.af_sector_num = info32.af_sector_num;
3929e39c5baSBill Taylor 		ioctl_info.af_addr = info32.af_addr;
3939e39c5baSBill Taylor 		ioctl_info.af_byte = info32.af_byte;
3949e39c5baSBill Taylor 	} else
3959e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
3969e39c5baSBill Taylor 	if (ddi_copyin((void *)arg, &ioctl_info,
3979e39c5baSBill Taylor 	    sizeof (hermon_flash_ioctl_t), mode) != 0) {
3989e39c5baSBill Taylor 		mutex_exit(&state->hs_fw_flashlock);
3999e39c5baSBill Taylor 		return (EFAULT);
4009e39c5baSBill Taylor 	}
4019e39c5baSBill Taylor 
4029e39c5baSBill Taylor 	/*
4039e39c5baSBill Taylor 	 * Determine type of WRITE ioctl
4049e39c5baSBill Taylor 	 */
4059e39c5baSBill Taylor 	switch (ioctl_info.af_type) {
4069e39c5baSBill Taylor 	case HERMON_FLASH_WRITE_SECTOR:
4079e39c5baSBill Taylor 		/* Check if sector num is too large for flash device */
4089e39c5baSBill Taylor 		if (ioctl_info.af_sector_num >=
4099e39c5baSBill Taylor 		    (state->hs_fw_device_sz >> state->hs_fw_log_sector_sz)) {
4109e39c5baSBill Taylor 			mutex_exit(&state->hs_fw_flashlock);
4119e39c5baSBill Taylor 			return (EFAULT);
4129e39c5baSBill Taylor 		}
4139e39c5baSBill Taylor 
4149e39c5baSBill Taylor 		/* copy in fw sector image data */
4159e39c5baSBill Taylor 		if (ddi_copyin(&ioctl_info.af_sector[0],
4169e39c5baSBill Taylor 		    &state->hs_fw_sector[0], 1 << state->hs_fw_log_sector_sz,
4179e39c5baSBill Taylor 		    mode) != 0) {
4189e39c5baSBill Taylor 			mutex_exit(&state->hs_fw_flashlock);
4199e39c5baSBill Taylor 			return (EFAULT);
4209e39c5baSBill Taylor 		}
4219e39c5baSBill Taylor 
4229e39c5baSBill Taylor 		/* Perform Write Sector */
4239e39c5baSBill Taylor 		status = hermon_flash_write_sector(state,
4249e39c5baSBill Taylor 		    ioctl_info.af_sector_num);
4259e39c5baSBill Taylor 		break;
4269e39c5baSBill Taylor 
4279e39c5baSBill Taylor 	case HERMON_FLASH_WRITE_BYTE:
4289e39c5baSBill Taylor 		/* Check if addr is too large for flash device */
4299e39c5baSBill Taylor 		if (ioctl_info.af_addr >= state->hs_fw_device_sz) {
4309e39c5baSBill Taylor 			mutex_exit(&state->hs_fw_flashlock);
4319e39c5baSBill Taylor 			return (EFAULT);
4329e39c5baSBill Taylor 		}
4339e39c5baSBill Taylor 
4349e39c5baSBill Taylor 		/* Perform Write Byte */
4359e39c5baSBill Taylor 		/*
4369e39c5baSBill Taylor 		 * CMJ -- is a reset really needed before and after writing
4379e39c5baSBill Taylor 		 * each byte?  This code came from arbel, but we should look
4389e39c5baSBill Taylor 		 * into this.  Also, for SPI, no reset is actually performed.
4399e39c5baSBill Taylor 		 */
4409e39c5baSBill Taylor 		if ((status = hermon_flash_bank(state,
4419e39c5baSBill Taylor 		    ioctl_info.af_addr)) != 0 ||
4429e39c5baSBill Taylor 		    (status = hermon_flash_reset(state)) != 0 ||
4439e39c5baSBill Taylor 		    (status = hermon_flash_write_byte(state,
4449e39c5baSBill Taylor 		    ioctl_info.af_addr, ioctl_info.af_byte)) != 0 ||
4459e39c5baSBill Taylor 		    (status = hermon_flash_reset(state)) != 0) {
4469e39c5baSBill Taylor 			mutex_exit(&state->hs_fw_flashlock);
4479e39c5baSBill Taylor 			return (status);
4489e39c5baSBill Taylor 		}
4499e39c5baSBill Taylor 		break;
4509e39c5baSBill Taylor 
4519e39c5baSBill Taylor 	default:
4529e39c5baSBill Taylor 		status = EINVAL;
4539e39c5baSBill Taylor 		break;
4549e39c5baSBill Taylor 	}
4559e39c5baSBill Taylor 
4569e39c5baSBill Taylor 	mutex_exit(&state->hs_fw_flashlock);
4579e39c5baSBill Taylor 	return (status);
4589e39c5baSBill Taylor }
4599e39c5baSBill Taylor 
4609e39c5baSBill Taylor /*
4619e39c5baSBill Taylor  * hermon_ioctl_flash_erase()
4629e39c5baSBill Taylor  */
4639e39c5baSBill Taylor static int
hermon_ioctl_flash_erase(hermon_state_t * state,dev_t dev,intptr_t arg,int mode)4649e39c5baSBill Taylor hermon_ioctl_flash_erase(hermon_state_t *state, dev_t dev, intptr_t arg,
4659e39c5baSBill Taylor     int mode)
4669e39c5baSBill Taylor {
4679e39c5baSBill Taylor 	hermon_flash_ioctl_t	ioctl_info;
4689e39c5baSBill Taylor 	int status = 0;
4699e39c5baSBill Taylor 
4709e39c5baSBill Taylor 	/*
4719e39c5baSBill Taylor 	 * Check that flash init ioctl has been called first.  And check
4729e39c5baSBill Taylor 	 * that the same dev_t that called init is the one calling erase now.
4739e39c5baSBill Taylor 	 */
4749e39c5baSBill Taylor 	mutex_enter(&state->hs_fw_flashlock);
4759e39c5baSBill Taylor 	if ((state->hs_fw_flashdev != dev) ||
4769e39c5baSBill Taylor 	    (state->hs_fw_flashstarted == 0)) {
4779e39c5baSBill Taylor 		mutex_exit(&state->hs_fw_flashlock);
4789e39c5baSBill Taylor 		return (EIO);
4799e39c5baSBill Taylor 	}
4809e39c5baSBill Taylor 
4819e39c5baSBill Taylor 	/* copy user struct to kernel */
4829e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
4839e39c5baSBill Taylor 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
4849e39c5baSBill Taylor 		hermon_flash_ioctl32_t info32;
4859e39c5baSBill Taylor 
4869e39c5baSBill Taylor 		if (ddi_copyin((void *)arg, &info32,
4879e39c5baSBill Taylor 		    sizeof (hermon_flash_ioctl32_t), mode) != 0) {
4889e39c5baSBill Taylor 			mutex_exit(&state->hs_fw_flashlock);
4899e39c5baSBill Taylor 			return (EFAULT);
4909e39c5baSBill Taylor 		}
4919e39c5baSBill Taylor 		ioctl_info.af_type = info32.af_type;
4929e39c5baSBill Taylor 		ioctl_info.af_sector_num = info32.af_sector_num;
4939e39c5baSBill Taylor 	} else
4949e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
4959e39c5baSBill Taylor 	if (ddi_copyin((void *)arg, &ioctl_info, sizeof (hermon_flash_ioctl_t),
4969e39c5baSBill Taylor 	    mode) != 0) {
4979e39c5baSBill Taylor 		mutex_exit(&state->hs_fw_flashlock);
4989e39c5baSBill Taylor 		return (EFAULT);
4999e39c5baSBill Taylor 	}
5009e39c5baSBill Taylor 
5019e39c5baSBill Taylor 	/*
5029e39c5baSBill Taylor 	 * Determine type of ERASE ioctl
5039e39c5baSBill Taylor 	 */
5049e39c5baSBill Taylor 	switch (ioctl_info.af_type) {
5059e39c5baSBill Taylor 	case HERMON_FLASH_ERASE_SECTOR:
5069e39c5baSBill Taylor 		/* Check if sector num is too large for flash device */
5079e39c5baSBill Taylor 		if (ioctl_info.af_sector_num >=
5089e39c5baSBill Taylor 		    (state->hs_fw_device_sz >> state->hs_fw_log_sector_sz)) {
5099e39c5baSBill Taylor 			mutex_exit(&state->hs_fw_flashlock);
5109e39c5baSBill Taylor 			return (EFAULT);
5119e39c5baSBill Taylor 		}
5129e39c5baSBill Taylor 
5139e39c5baSBill Taylor 		/* Perform Sector Erase */
5149e39c5baSBill Taylor 		status = hermon_flash_erase_sector(state,
5159e39c5baSBill Taylor 		    ioctl_info.af_sector_num);
5169e39c5baSBill Taylor 		break;
5179e39c5baSBill Taylor 
5189e39c5baSBill Taylor 	case HERMON_FLASH_ERASE_CHIP:
5199e39c5baSBill Taylor 		/* Perform Chip Erase */
5209e39c5baSBill Taylor 		status = hermon_flash_erase_chip(state);
5219e39c5baSBill Taylor 		break;
5229e39c5baSBill Taylor 
5239e39c5baSBill Taylor 	default:
5249e39c5baSBill Taylor 		status = EINVAL;
5259e39c5baSBill Taylor 		break;
5269e39c5baSBill Taylor 	}
5279e39c5baSBill Taylor 
5289e39c5baSBill Taylor 	mutex_exit(&state->hs_fw_flashlock);
5299e39c5baSBill Taylor 	return (status);
5309e39c5baSBill Taylor }
5319e39c5baSBill Taylor 
5329e39c5baSBill Taylor /*
5339e39c5baSBill Taylor  * hermon_ioctl_flash_init()
5349e39c5baSBill Taylor  */
5359e39c5baSBill Taylor static int
hermon_ioctl_flash_init(hermon_state_t * state,dev_t dev,intptr_t arg,int mode)5369e39c5baSBill Taylor hermon_ioctl_flash_init(hermon_state_t *state, dev_t dev, intptr_t arg,
5379e39c5baSBill Taylor     int mode)
5389e39c5baSBill Taylor {
5399e39c5baSBill Taylor 	hermon_flash_init_ioctl_t init_info;
5409e39c5baSBill Taylor 	int ret;
5419e39c5baSBill Taylor 	int intel_xcmd = 0;
5429e39c5baSBill Taylor 	ddi_acc_handle_t pci_hdl = hermon_get_pcihdl(state);
5439e39c5baSBill Taylor 
5449e39c5baSBill Taylor 	/* initialize the FMA retry loop */
5459e39c5baSBill Taylor 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
5469e39c5baSBill Taylor 
5479e39c5baSBill Taylor 	state->hs_fw_sector = NULL;
5489e39c5baSBill Taylor 
5499e39c5baSBill Taylor 	/*
5509e39c5baSBill Taylor 	 * init cannot be called more than once.  If we have already init'd the
5519e39c5baSBill Taylor 	 * flash, return directly.
5529e39c5baSBill Taylor 	 */
5539e39c5baSBill Taylor 	mutex_enter(&state->hs_fw_flashlock);
5549e39c5baSBill Taylor 	if (state->hs_fw_flashstarted == 1) {
5559e39c5baSBill Taylor 		mutex_exit(&state->hs_fw_flashlock);
5569e39c5baSBill Taylor 		return (EINVAL);
5579e39c5baSBill Taylor 	}
5589e39c5baSBill Taylor 
5599e39c5baSBill Taylor 	/* copyin the user struct to kernel */
5609e39c5baSBill Taylor 	if (ddi_copyin((void *)arg, &init_info,
5619e39c5baSBill Taylor 	    sizeof (hermon_flash_init_ioctl_t), mode) != 0) {
5629e39c5baSBill Taylor 		mutex_exit(&state->hs_fw_flashlock);
5639e39c5baSBill Taylor 		return (EFAULT);
5649e39c5baSBill Taylor 	}
5659e39c5baSBill Taylor 
5669e39c5baSBill Taylor 	/* Init Flash */
5679e39c5baSBill Taylor 	if ((ret = hermon_flash_init(state)) != 0) {
5689e39c5baSBill Taylor 		if (ret == EIO) {
5699e39c5baSBill Taylor 			goto pio_error;
5709e39c5baSBill Taylor 		}
5719e39c5baSBill Taylor 		mutex_exit(&state->hs_fw_flashlock);
5729e39c5baSBill Taylor 		return (ret);
5739e39c5baSBill Taylor 	}
5749e39c5baSBill Taylor 
5759e39c5baSBill Taylor 	/* Read CFI info */
5769e39c5baSBill Taylor 	if ((ret = hermon_flash_cfi_init(state, &init_info.af_cfi_info[0],
5779e39c5baSBill Taylor 	    &intel_xcmd)) != 0) {
5789e39c5baSBill Taylor 		if (ret == EIO) {
5799e39c5baSBill Taylor 			goto pio_error;
5809e39c5baSBill Taylor 		}
5819e39c5baSBill Taylor 		mutex_exit(&state->hs_fw_flashlock);
5829e39c5baSBill Taylor 		return (ret);
5839e39c5baSBill Taylor 	}
5849e39c5baSBill Taylor 
5859e39c5baSBill Taylor 	/*
5869e39c5baSBill Taylor 	 * Return error if the command set is unknown.
5879e39c5baSBill Taylor 	 */
5889e39c5baSBill Taylor 	if (state->hs_fw_cmdset == HERMON_FLASH_UNKNOWN_CMDSET) {
5899e39c5baSBill Taylor 		if ((ret = hermon_ioctl_flash_cleanup_nolock(state)) != 0) {
5909e39c5baSBill Taylor 			if (ret == EIO) {
5919e39c5baSBill Taylor 				goto pio_error;
5929e39c5baSBill Taylor 			}
5939e39c5baSBill Taylor 			mutex_exit(&state->hs_fw_flashlock);
5949e39c5baSBill Taylor 			return (ret);
5959e39c5baSBill Taylor 		}
5969e39c5baSBill Taylor 		mutex_exit(&state->hs_fw_flashlock);
5979e39c5baSBill Taylor 		return (EFAULT);
5989e39c5baSBill Taylor 	}
5999e39c5baSBill Taylor 
6009e39c5baSBill Taylor 	/* the FMA retry loop starts. */
6019e39c5baSBill Taylor 	hermon_pio_start(state, pci_hdl, pio_error,
6029e39c5baSBill Taylor 	    fm_loop_cnt, fm_status, fm_test);
6039e39c5baSBill Taylor 
6049e39c5baSBill Taylor 	/* Read HWREV - least significant 8 bits is revision ID */
6059e39c5baSBill Taylor 	init_info.af_hwrev = pci_config_get32(pci_hdl,
6069e39c5baSBill Taylor 	    HERMON_HW_FLASH_CFG_HWREV) & 0xFF;
6079e39c5baSBill Taylor 
6089e39c5baSBill Taylor 	/* the FMA retry loop ends. */
6099e39c5baSBill Taylor 	hermon_pio_end(state, pci_hdl, pio_error, fm_loop_cnt,
6109e39c5baSBill Taylor 	    fm_status, fm_test);
6119e39c5baSBill Taylor 
6129e39c5baSBill Taylor 	/* Fill in the firmwate revision numbers */
6139e39c5baSBill Taylor 	init_info.af_fwrev.afi_maj	= state->hs_fw.fw_rev_major;
6149e39c5baSBill Taylor 	init_info.af_fwrev.afi_min	= state->hs_fw.fw_rev_minor;
6159e39c5baSBill Taylor 	init_info.af_fwrev.afi_sub	= state->hs_fw.fw_rev_subminor;
6169e39c5baSBill Taylor 
6179e39c5baSBill Taylor 	/* Alloc flash mem for one sector size */
6189e39c5baSBill Taylor 	state->hs_fw_sector = (uint32_t *)kmem_zalloc(1 <<
6199e39c5baSBill Taylor 	    state->hs_fw_log_sector_sz, KM_SLEEP);
6209e39c5baSBill Taylor 
6219e39c5baSBill Taylor 	/* Set HW part number and length */
6229e39c5baSBill Taylor 	init_info.af_pn_len = state->hs_hca_pn_len;
6239e39c5baSBill Taylor 	if (state->hs_hca_pn_len != 0) {
6249e39c5baSBill Taylor 		(void) memcpy(init_info.af_hwpn, state->hs_hca_pn,
6259e39c5baSBill Taylor 		    state->hs_hca_pn_len);
6269e39c5baSBill Taylor 	}
6279e39c5baSBill Taylor 
6289e39c5baSBill Taylor 	/* Copy ioctl results back to userland */
6299e39c5baSBill Taylor 	if (ddi_copyout(&init_info, (void *)arg,
6309e39c5baSBill Taylor 	    sizeof (hermon_flash_init_ioctl_t), mode) != 0) {
6319e39c5baSBill Taylor 		if ((ret = hermon_ioctl_flash_cleanup_nolock(state)) != 0) {
6329e39c5baSBill Taylor 			if (ret == EIO) {
6339e39c5baSBill Taylor 				goto pio_error;
6349e39c5baSBill Taylor 			}
6359e39c5baSBill Taylor 			mutex_exit(&state->hs_fw_flashlock);
6369e39c5baSBill Taylor 			return (ret);
6379e39c5baSBill Taylor 		}
6389e39c5baSBill Taylor 		mutex_exit(&state->hs_fw_flashlock);
6399e39c5baSBill Taylor 		return (EFAULT);
6409e39c5baSBill Taylor 	}
6419e39c5baSBill Taylor 
6429e39c5baSBill Taylor 	/* Set flash state to started */
6439e39c5baSBill Taylor 	state->hs_fw_flashstarted = 1;
6449e39c5baSBill Taylor 	state->hs_fw_flashdev	  = dev;
6459e39c5baSBill Taylor 
6469e39c5baSBill Taylor 	mutex_exit(&state->hs_fw_flashlock);
6479e39c5baSBill Taylor 
6489e39c5baSBill Taylor 	/*
6499e39c5baSBill Taylor 	 * If "flash init" is successful, add an "on close" callback to the
6509e39c5baSBill Taylor 	 * current dev node to ensure that "flash fini" gets called later
6519e39c5baSBill Taylor 	 * even if the userland process prematurely exits.
6529e39c5baSBill Taylor 	 */
6539e39c5baSBill Taylor 	ret = hermon_umap_db_set_onclose_cb(dev,
6549e39c5baSBill Taylor 	    HERMON_ONCLOSE_FLASH_INPROGRESS,
6559e39c5baSBill Taylor 	    (int (*)(void *))hermon_ioctl_flash_cleanup, state);
6569e39c5baSBill Taylor 	if (ret != DDI_SUCCESS) {
6579e39c5baSBill Taylor 		int status = hermon_ioctl_flash_fini(state, dev);
6589e39c5baSBill Taylor 		if (status != 0) {
6599e39c5baSBill Taylor 			if (status == EIO) {
6609e39c5baSBill Taylor 				hermon_fm_ereport(state, HCA_SYS_ERR,
6619e39c5baSBill Taylor 				    HCA_ERR_IOCTL);
6629e39c5baSBill Taylor 				return (EIO);
6639e39c5baSBill Taylor 			}
6649e39c5baSBill Taylor 			return (status);
6659e39c5baSBill Taylor 		}
6669e39c5baSBill Taylor 	}
6679e39c5baSBill Taylor 	return (0);
6689e39c5baSBill Taylor 
6699e39c5baSBill Taylor pio_error:
6709e39c5baSBill Taylor 	mutex_exit(&state->hs_fw_flashlock);
6719e39c5baSBill Taylor 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
6729e39c5baSBill Taylor 	return (EIO);
6739e39c5baSBill Taylor }
6749e39c5baSBill Taylor 
6759e39c5baSBill Taylor /*
6769e39c5baSBill Taylor  * hermon_ioctl_flash_fini()
6779e39c5baSBill Taylor  */
6789e39c5baSBill Taylor static int
hermon_ioctl_flash_fini(hermon_state_t * state,dev_t dev)6799e39c5baSBill Taylor hermon_ioctl_flash_fini(hermon_state_t *state, dev_t dev)
6809e39c5baSBill Taylor {
6819e39c5baSBill Taylor 	int ret;
6829e39c5baSBill Taylor 
6839e39c5baSBill Taylor 	/*
6849e39c5baSBill Taylor 	 * Check that flash init ioctl has been called first.  And check
6859e39c5baSBill Taylor 	 * that the same dev_t that called init is the one calling fini now.
6869e39c5baSBill Taylor 	 */
6879e39c5baSBill Taylor 	mutex_enter(&state->hs_fw_flashlock);
6889e39c5baSBill Taylor 	if ((state->hs_fw_flashdev != dev) ||
6899e39c5baSBill Taylor 	    (state->hs_fw_flashstarted == 0)) {
6909e39c5baSBill Taylor 		mutex_exit(&state->hs_fw_flashlock);
6919e39c5baSBill Taylor 		return (EINVAL);
6929e39c5baSBill Taylor 	}
6939e39c5baSBill Taylor 
6949e39c5baSBill Taylor 	if ((ret = hermon_ioctl_flash_cleanup_nolock(state)) != 0) {
6959e39c5baSBill Taylor 		mutex_exit(&state->hs_fw_flashlock);
6969e39c5baSBill Taylor 		if (ret == EIO) {
6979e39c5baSBill Taylor 			hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
6989e39c5baSBill Taylor 		}
6999e39c5baSBill Taylor 		return (ret);
7009e39c5baSBill Taylor 	}
7019e39c5baSBill Taylor 	mutex_exit(&state->hs_fw_flashlock);
7029e39c5baSBill Taylor 
7039e39c5baSBill Taylor 	/*
7049e39c5baSBill Taylor 	 * If "flash fini" is successful, remove the "on close" callback
7059e39c5baSBill Taylor 	 * that was setup during "flash init".
7069e39c5baSBill Taylor 	 */
7079e39c5baSBill Taylor 	ret = hermon_umap_db_clear_onclose_cb(dev,
7089e39c5baSBill Taylor 	    HERMON_ONCLOSE_FLASH_INPROGRESS);
7099e39c5baSBill Taylor 	if (ret != DDI_SUCCESS) {
7109e39c5baSBill Taylor 		return (EFAULT);
7119e39c5baSBill Taylor 	}
7129e39c5baSBill Taylor 	return (0);
7139e39c5baSBill Taylor }
7149e39c5baSBill Taylor 
7159e39c5baSBill Taylor 
7169e39c5baSBill Taylor /*
7179e39c5baSBill Taylor  * hermon_ioctl_flash_cleanup()
7189e39c5baSBill Taylor  */
7199e39c5baSBill Taylor static int
hermon_ioctl_flash_cleanup(hermon_state_t * state)7209e39c5baSBill Taylor hermon_ioctl_flash_cleanup(hermon_state_t *state)
7219e39c5baSBill Taylor {
7229e39c5baSBill Taylor 	int status;
7239e39c5baSBill Taylor 
7249e39c5baSBill Taylor 	mutex_enter(&state->hs_fw_flashlock);
7259e39c5baSBill Taylor 	status = hermon_ioctl_flash_cleanup_nolock(state);
7269e39c5baSBill Taylor 	mutex_exit(&state->hs_fw_flashlock);
7279e39c5baSBill Taylor 
7289e39c5baSBill Taylor 	return (status);
7299e39c5baSBill Taylor }
7309e39c5baSBill Taylor 
7319e39c5baSBill Taylor 
7329e39c5baSBill Taylor /*
7339e39c5baSBill Taylor  * hermon_ioctl_flash_cleanup_nolock()
7349e39c5baSBill Taylor  */
7359e39c5baSBill Taylor static int
hermon_ioctl_flash_cleanup_nolock(hermon_state_t * state)7369e39c5baSBill Taylor hermon_ioctl_flash_cleanup_nolock(hermon_state_t *state)
7379e39c5baSBill Taylor {
7389e39c5baSBill Taylor 	int status;
7399e39c5baSBill Taylor 	ASSERT(MUTEX_HELD(&state->hs_fw_flashlock));
7409e39c5baSBill Taylor 
7419e39c5baSBill Taylor 	/* free flash mem */
7429e39c5baSBill Taylor 	if (state->hs_fw_sector) {
7439e39c5baSBill Taylor 		kmem_free(state->hs_fw_sector, 1 << state->hs_fw_log_sector_sz);
7449e39c5baSBill Taylor 	}
7459e39c5baSBill Taylor 
7469e39c5baSBill Taylor 	/* Fini the Flash */
7479e39c5baSBill Taylor 	if ((status = hermon_flash_fini(state)) != 0)
7489e39c5baSBill Taylor 		return (status);
7499e39c5baSBill Taylor 
7509e39c5baSBill Taylor 	/* Set flash state to fini */
7519e39c5baSBill Taylor 	state->hs_fw_flashstarted = 0;
7529e39c5baSBill Taylor 	state->hs_fw_flashdev	  = 0;
7539e39c5baSBill Taylor 	return (0);
7549e39c5baSBill Taylor }
7559e39c5baSBill Taylor 
7569e39c5baSBill Taylor 
7579e39c5baSBill Taylor /*
7589e39c5baSBill Taylor  * hermon_ioctl_info()
7599e39c5baSBill Taylor  */
7609e39c5baSBill Taylor static int
hermon_ioctl_info(hermon_state_t * state,dev_t dev,intptr_t arg,int mode)7619e39c5baSBill Taylor hermon_ioctl_info(hermon_state_t *state, dev_t dev, intptr_t arg, int mode)
7629e39c5baSBill Taylor {
7639e39c5baSBill Taylor 	hermon_info_ioctl_t	 info;
7649e39c5baSBill Taylor 	hermon_flash_init_ioctl_t init_info;
7659e39c5baSBill Taylor 
7669e39c5baSBill Taylor 	/*
7679e39c5baSBill Taylor 	 * Access to Hemron VTS ioctls is not allowed in "maintenance mode".
7689e39c5baSBill Taylor 	 */
7699e39c5baSBill Taylor 	if (state->hs_operational_mode == HERMON_MAINTENANCE_MODE) {
7709e39c5baSBill Taylor 		return (EFAULT);
7719e39c5baSBill Taylor 	}
7729e39c5baSBill Taylor 
7739e39c5baSBill Taylor 	/* copyin the user struct to kernel */
7749e39c5baSBill Taylor 	if (ddi_copyin((void *)arg, &info, sizeof (hermon_info_ioctl_t),
7759e39c5baSBill Taylor 	    mode) != 0) {
7769e39c5baSBill Taylor 		return (EFAULT);
7779e39c5baSBill Taylor 	}
7789e39c5baSBill Taylor 
7799e39c5baSBill Taylor 	/*
7809e39c5baSBill Taylor 	 * Check ioctl revision
7819e39c5baSBill Taylor 	 */
7829e39c5baSBill Taylor 	if (info.ai_revision != HERMON_VTS_IOCTL_REVISION) {
7839e39c5baSBill Taylor 		return (EINVAL);
7849e39c5baSBill Taylor 	}
7859e39c5baSBill Taylor 
7869e39c5baSBill Taylor 	/*
7879e39c5baSBill Taylor 	 * If the 'fw_device_sz' has not been initialized yet, we initialize it
7889e39c5baSBill Taylor 	 * here.  This is done by leveraging the
7899e39c5baSBill Taylor 	 * hermon_ioctl_flash_init()/fini() calls.  We also hold our own mutex
7909e39c5baSBill Taylor 	 * around this operation in case we have multiple VTS threads in
7919e39c5baSBill Taylor 	 * process at the same time.
7929e39c5baSBill Taylor 	 */
7939e39c5baSBill Taylor 	mutex_enter(&state->hs_info_lock);
7949e39c5baSBill Taylor 	if (state->hs_fw_device_sz == 0) {
7959e39c5baSBill Taylor 		if (hermon_ioctl_flash_init(state, dev, (intptr_t)&init_info,
7969e39c5baSBill Taylor 		    (FKIOCTL | mode)) != 0) {
7979e39c5baSBill Taylor 			mutex_exit(&state->hs_info_lock);
7989e39c5baSBill Taylor 			return (EFAULT);
7999e39c5baSBill Taylor 		}
8009e39c5baSBill Taylor 		(void) hermon_ioctl_flash_fini(state, dev);
8019e39c5baSBill Taylor 	}
8029e39c5baSBill Taylor 	mutex_exit(&state->hs_info_lock);
8039e39c5baSBill Taylor 
8049e39c5baSBill Taylor 	info.ai_hw_rev		 = state->hs_revision_id;
8059e39c5baSBill Taylor 	info.ai_flash_sz	 = state->hs_fw_device_sz;
8069e39c5baSBill Taylor 	info.ai_fw_rev.afi_maj	 = state->hs_fw.fw_rev_major;
8079e39c5baSBill Taylor 	info.ai_fw_rev.afi_min	 = state->hs_fw.fw_rev_minor;
8089e39c5baSBill Taylor 	info.ai_fw_rev.afi_sub	 = state->hs_fw.fw_rev_subminor;
8099e39c5baSBill Taylor 
8109e39c5baSBill Taylor 	/* Copy ioctl results back to user struct */
8119e39c5baSBill Taylor 	if (ddi_copyout(&info, (void *)arg, sizeof (hermon_info_ioctl_t),
8129e39c5baSBill Taylor 	    mode) != 0) {
8139e39c5baSBill Taylor 		return (EFAULT);
8149e39c5baSBill Taylor 	}
8159e39c5baSBill Taylor 
8169e39c5baSBill Taylor 	return (0);
8179e39c5baSBill Taylor }
8189e39c5baSBill Taylor 
8199e39c5baSBill Taylor /*
8209e39c5baSBill Taylor  * hermon_ioctl_ports()
8219e39c5baSBill Taylor  */
8229e39c5baSBill Taylor static int
hermon_ioctl_ports(hermon_state_t * state,intptr_t arg,int mode)8239e39c5baSBill Taylor hermon_ioctl_ports(hermon_state_t *state, intptr_t arg, int mode)
8249e39c5baSBill Taylor {
8259e39c5baSBill Taylor 	hermon_ports_ioctl_t	info;
8269e39c5baSBill Taylor 	hermon_stat_port_ioctl_t	portstat;
8279e39c5baSBill Taylor 	ibt_hca_portinfo_t	pi;
8289e39c5baSBill Taylor 	uint_t			tbl_size;
8299e39c5baSBill Taylor 	ib_gid_t		*sgid_tbl;
8309e39c5baSBill Taylor 	ib_pkey_t		*pkey_tbl;
8319e39c5baSBill Taylor 	int			i;
8329e39c5baSBill Taylor 
8339e39c5baSBill Taylor 	/*
8349e39c5baSBill Taylor 	 * Access to Hemron VTS ioctls is not allowed in "maintenance mode".
8359e39c5baSBill Taylor 	 */
8369e39c5baSBill Taylor 	if (state->hs_operational_mode == HERMON_MAINTENANCE_MODE) {
8379e39c5baSBill Taylor 		return (EFAULT);
8389e39c5baSBill Taylor 	}
8399e39c5baSBill Taylor 
8409e39c5baSBill Taylor 	/* copyin the user struct to kernel */
8419e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
8429e39c5baSBill Taylor 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
8439e39c5baSBill Taylor 		hermon_ports_ioctl32_t info32;
8449e39c5baSBill Taylor 
8459e39c5baSBill Taylor 		if (ddi_copyin((void *)arg, &info32,
8469e39c5baSBill Taylor 		    sizeof (hermon_ports_ioctl32_t), mode) != 0) {
8479e39c5baSBill Taylor 			return (EFAULT);
8489e39c5baSBill Taylor 		}
8499e39c5baSBill Taylor 		info.ap_revision  = info32.ap_revision;
8509e39c5baSBill Taylor 		info.ap_ports	  =
8519e39c5baSBill Taylor 		    (hermon_stat_port_ioctl_t *)(uintptr_t)info32.ap_ports;
8529e39c5baSBill Taylor 		info.ap_num_ports = info32.ap_num_ports;
8539e39c5baSBill Taylor 
8549e39c5baSBill Taylor 	} else
8559e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
8569e39c5baSBill Taylor 	if (ddi_copyin((void *)arg, &info, sizeof (hermon_ports_ioctl_t),
8579e39c5baSBill Taylor 	    mode) != 0) {
8589e39c5baSBill Taylor 		return (EFAULT);
8599e39c5baSBill Taylor 	}
8609e39c5baSBill Taylor 
8619e39c5baSBill Taylor 	/*
8629e39c5baSBill Taylor 	 * Check ioctl revision
8639e39c5baSBill Taylor 	 */
8649e39c5baSBill Taylor 	if (info.ap_revision != HERMON_VTS_IOCTL_REVISION) {
8659e39c5baSBill Taylor 		return (EINVAL);
8669e39c5baSBill Taylor 	}
8679e39c5baSBill Taylor 
8689e39c5baSBill Taylor 	/* Allocate space for temporary GID table/PKey table */
8699e39c5baSBill Taylor 	tbl_size = (1 << state->hs_cfg_profile->cp_log_max_gidtbl);
8709e39c5baSBill Taylor 	sgid_tbl = (ib_gid_t *)kmem_zalloc(tbl_size * sizeof (ib_gid_t),
8719e39c5baSBill Taylor 	    KM_SLEEP);
8729e39c5baSBill Taylor 	tbl_size = (1 << state->hs_cfg_profile->cp_log_max_pkeytbl);
8739e39c5baSBill Taylor 	pkey_tbl = (ib_pkey_t *)kmem_zalloc(tbl_size * sizeof (ib_pkey_t),
8749e39c5baSBill Taylor 	    KM_SLEEP);
8759e39c5baSBill Taylor 
8769e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*sgid_tbl, *pkey_tbl))
8779e39c5baSBill Taylor 
8789e39c5baSBill Taylor 	/*
8799e39c5baSBill Taylor 	 * Setup the number of ports, then loop through all ports and
8809e39c5baSBill Taylor 	 * query properties of each.
8819e39c5baSBill Taylor 	 */
8829e39c5baSBill Taylor 	info.ap_num_ports = (uint8_t)state->hs_cfg_profile->cp_num_ports;
8839e39c5baSBill Taylor 	for (i = 0; i < info.ap_num_ports; i++) {
8849e39c5baSBill Taylor 		/*
8859e39c5baSBill Taylor 		 * Get portstate information from the device.  If
8869e39c5baSBill Taylor 		 * hermon_port_query() fails, leave zeroes in user
8879e39c5baSBill Taylor 		 * struct port entry and continue.
8889e39c5baSBill Taylor 		 */
8899e39c5baSBill Taylor 		bzero(&pi, sizeof (ibt_hca_portinfo_t));
8909e39c5baSBill Taylor 		pi.p_sgid_tbl = sgid_tbl;
8919e39c5baSBill Taylor 		pi.p_pkey_tbl = pkey_tbl;
8929e39c5baSBill Taylor 		(void) hermon_port_query(state, i + 1, &pi);
8939e39c5baSBill Taylor 
8949e39c5baSBill Taylor 		portstat.asp_port_num	= pi.p_port_num;
8959e39c5baSBill Taylor 		portstat.asp_state	= pi.p_linkstate;
8969e39c5baSBill Taylor 		portstat.asp_guid	= pi.p_sgid_tbl[0].gid_guid;
8979e39c5baSBill Taylor 
8989e39c5baSBill Taylor 		/*
8999e39c5baSBill Taylor 		 * Copy queried port results back to user struct.  If
9009e39c5baSBill Taylor 		 * this fails, then break out of loop, attempt to copy
9019e39c5baSBill Taylor 		 * out remaining info to user struct, and return (without
9029e39c5baSBill Taylor 		 * error).
9039e39c5baSBill Taylor 		 */
9049e39c5baSBill Taylor 		if (ddi_copyout(&portstat,
9059e39c5baSBill Taylor 		    &(((hermon_stat_port_ioctl_t *)info.ap_ports)[i]),
9069e39c5baSBill Taylor 		    sizeof (hermon_stat_port_ioctl_t), mode) != 0) {
9079e39c5baSBill Taylor 			break;
9089e39c5baSBill Taylor 		}
9099e39c5baSBill Taylor 	}
9109e39c5baSBill Taylor 
9119e39c5baSBill Taylor 	/* Free the temporary space used for GID table/PKey table */
9129e39c5baSBill Taylor 	tbl_size = (1 << state->hs_cfg_profile->cp_log_max_gidtbl);
9139e39c5baSBill Taylor 	kmem_free(sgid_tbl, tbl_size * sizeof (ib_gid_t));
9149e39c5baSBill Taylor 	tbl_size = (1 << state->hs_cfg_profile->cp_log_max_pkeytbl);
9159e39c5baSBill Taylor 	kmem_free(pkey_tbl, tbl_size * sizeof (ib_pkey_t));
9169e39c5baSBill Taylor 
9179e39c5baSBill Taylor 	/* Copy ioctl results back to user struct */
9189e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
9199e39c5baSBill Taylor 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
9209e39c5baSBill Taylor 		hermon_ports_ioctl32_t info32;
9219e39c5baSBill Taylor 
9229e39c5baSBill Taylor 		info32.ap_revision  = info.ap_revision;
9239e39c5baSBill Taylor 		info32.ap_ports	    = (caddr32_t)(uintptr_t)info.ap_ports;
9249e39c5baSBill Taylor 		info32.ap_num_ports = info.ap_num_ports;
9259e39c5baSBill Taylor 
9269e39c5baSBill Taylor 		if (ddi_copyout(&info32, (void *)arg,
9279e39c5baSBill Taylor 		    sizeof (hermon_ports_ioctl32_t), mode) != 0) {
9289e39c5baSBill Taylor 			return (EFAULT);
9299e39c5baSBill Taylor 		}
9309e39c5baSBill Taylor 	} else
9319e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
9329e39c5baSBill Taylor 	if (ddi_copyout(&info, (void *)arg, sizeof (hermon_ports_ioctl_t),
9339e39c5baSBill Taylor 	    mode) != 0) {
9349e39c5baSBill Taylor 		return (EFAULT);
9359e39c5baSBill Taylor 	}
9369e39c5baSBill Taylor 
9379e39c5baSBill Taylor 	return (0);
9389e39c5baSBill Taylor }
9399e39c5baSBill Taylor 
9409e39c5baSBill Taylor /*
9419e39c5baSBill Taylor  * hermon_ioctl_loopback()
9429e39c5baSBill Taylor  */
9439e39c5baSBill Taylor static int
hermon_ioctl_loopback(hermon_state_t * state,intptr_t arg,int mode)9449e39c5baSBill Taylor hermon_ioctl_loopback(hermon_state_t *state, intptr_t arg, int mode)
9459e39c5baSBill Taylor {
9469e39c5baSBill Taylor 	hermon_loopback_ioctl_t	lb;
9479e39c5baSBill Taylor 	hermon_loopback_state_t	lstate;
9489e39c5baSBill Taylor 	ibt_hca_portinfo_t 	pi;
9499e39c5baSBill Taylor 	uint_t			tbl_size, loopmax, max_usec;
9509e39c5baSBill Taylor 	ib_gid_t		*sgid_tbl;
9519e39c5baSBill Taylor 	ib_pkey_t		*pkey_tbl;
9529e39c5baSBill Taylor 	int			j, iter, ret;
9539e39c5baSBill Taylor 
9549e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(lstate))
9559e39c5baSBill Taylor 
9569e39c5baSBill Taylor 	/*
9579e39c5baSBill Taylor 	 * Access to Hemron VTS ioctls is not allowed in "maintenance mode".
9589e39c5baSBill Taylor 	 */
9599e39c5baSBill Taylor 	if (state->hs_operational_mode == HERMON_MAINTENANCE_MODE) {
9609e39c5baSBill Taylor 		return (EFAULT);
9619e39c5baSBill Taylor 	}
9629e39c5baSBill Taylor 
9639e39c5baSBill Taylor 	/* copyin the user struct to kernel */
9649e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
9659e39c5baSBill Taylor 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
9669e39c5baSBill Taylor 		hermon_loopback_ioctl32_t lb32;
9679e39c5baSBill Taylor 
9689e39c5baSBill Taylor 		if (ddi_copyin((void *)arg, &lb32,
9699e39c5baSBill Taylor 		    sizeof (hermon_loopback_ioctl32_t), mode) != 0) {
9709e39c5baSBill Taylor 			return (EFAULT);
9719e39c5baSBill Taylor 		}
9729e39c5baSBill Taylor 		lb.alb_revision	    = lb32.alb_revision;
9739e39c5baSBill Taylor 		lb.alb_send_buf	    = (caddr_t)(uintptr_t)lb32.alb_send_buf;
9749e39c5baSBill Taylor 		lb.alb_fail_buf	    = (caddr_t)(uintptr_t)lb32.alb_fail_buf;
9759e39c5baSBill Taylor 		lb.alb_buf_sz	    = lb32.alb_buf_sz;
9769e39c5baSBill Taylor 		lb.alb_num_iter	    = lb32.alb_num_iter;
9779e39c5baSBill Taylor 		lb.alb_pass_done    = lb32.alb_pass_done;
9789e39c5baSBill Taylor 		lb.alb_timeout	    = lb32.alb_timeout;
9799e39c5baSBill Taylor 		lb.alb_error_type   = lb32.alb_error_type;
9809e39c5baSBill Taylor 		lb.alb_port_num	    = lb32.alb_port_num;
9819e39c5baSBill Taylor 		lb.alb_num_retry    = lb32.alb_num_retry;
9829e39c5baSBill Taylor 	} else
9839e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
9849e39c5baSBill Taylor 	if (ddi_copyin((void *)arg, &lb, sizeof (hermon_loopback_ioctl_t),
9859e39c5baSBill Taylor 	    mode) != 0) {
9869e39c5baSBill Taylor 		return (EFAULT);
9879e39c5baSBill Taylor 	}
9889e39c5baSBill Taylor 
9899e39c5baSBill Taylor 	/* Initialize the internal loopback test state structure */
9909e39c5baSBill Taylor 	bzero(&lstate, sizeof (hermon_loopback_state_t));
9919e39c5baSBill Taylor 
9929e39c5baSBill Taylor 	/*
9939e39c5baSBill Taylor 	 * Check ioctl revision
9949e39c5baSBill Taylor 	 */
9959e39c5baSBill Taylor 	if (lb.alb_revision != HERMON_VTS_IOCTL_REVISION) {
9969e39c5baSBill Taylor 		lb.alb_error_type = HERMON_LOOPBACK_INVALID_REVISION;
9979e39c5baSBill Taylor 		(void) hermon_loopback_copyout(&lb, arg, mode);
9989e39c5baSBill Taylor 		return (EINVAL);
9999e39c5baSBill Taylor 	}
10009e39c5baSBill Taylor 
10019e39c5baSBill Taylor 	/* Validate that specified port number is legal */
10029e39c5baSBill Taylor 	if (!hermon_portnum_is_valid(state, lb.alb_port_num)) {
10039e39c5baSBill Taylor 		lb.alb_error_type = HERMON_LOOPBACK_INVALID_PORT;
10049e39c5baSBill Taylor 		(void) hermon_loopback_copyout(&lb, arg, mode);
10059e39c5baSBill Taylor 		return (EINVAL);
10069e39c5baSBill Taylor 	}
10079e39c5baSBill Taylor 
10089e39c5baSBill Taylor 	/* Allocate space for temporary GID table/PKey table */
10099e39c5baSBill Taylor 	tbl_size = (1 << state->hs_cfg_profile->cp_log_max_gidtbl);
10109e39c5baSBill Taylor 	sgid_tbl = (ib_gid_t *)kmem_zalloc(tbl_size * sizeof (ib_gid_t),
10119e39c5baSBill Taylor 	    KM_SLEEP);
10129e39c5baSBill Taylor 	tbl_size = (1 << state->hs_cfg_profile->cp_log_max_pkeytbl);
10139e39c5baSBill Taylor 	pkey_tbl = (ib_pkey_t *)kmem_zalloc(tbl_size * sizeof (ib_pkey_t),
10149e39c5baSBill Taylor 	    KM_SLEEP);
10159e39c5baSBill Taylor 
10169e39c5baSBill Taylor 	/*
10179e39c5baSBill Taylor 	 * Get portstate information from specific port on device
10189e39c5baSBill Taylor 	 */
10199e39c5baSBill Taylor 	bzero(&pi, sizeof (ibt_hca_portinfo_t));
10209e39c5baSBill Taylor 	pi.p_sgid_tbl = sgid_tbl;
10219e39c5baSBill Taylor 	pi.p_pkey_tbl = pkey_tbl;
10229e39c5baSBill Taylor 	if (hermon_port_query(state, lb.alb_port_num, &pi) != 0) {
10239e39c5baSBill Taylor 		/* Free the temporary space used for GID table/PKey table */
10249e39c5baSBill Taylor 		tbl_size = (1 << state->hs_cfg_profile->cp_log_max_gidtbl);
10259e39c5baSBill Taylor 		kmem_free(sgid_tbl, tbl_size * sizeof (ib_gid_t));
10269e39c5baSBill Taylor 		tbl_size = (1 << state->hs_cfg_profile->cp_log_max_pkeytbl);
10279e39c5baSBill Taylor 		kmem_free(pkey_tbl, tbl_size * sizeof (ib_pkey_t));
10289e39c5baSBill Taylor 
10299e39c5baSBill Taylor 		lb.alb_error_type = HERMON_LOOPBACK_INVALID_PORT;
10309e39c5baSBill Taylor 		(void) hermon_loopback_copyout(&lb, arg, mode);
10319e39c5baSBill Taylor 		hermon_loopback_free_state(&lstate);
10329e39c5baSBill Taylor 		return (EINVAL);
10339e39c5baSBill Taylor 	}
10349e39c5baSBill Taylor 
10359e39c5baSBill Taylor 	lstate.hls_port	   = pi.p_port_num;
10369e39c5baSBill Taylor 	lstate.hls_lid	   = pi.p_base_lid;
10379e39c5baSBill Taylor 	lstate.hls_pkey_ix = (pi.p_linkstate == HERMON_PORT_LINK_ACTIVE) ?
10389e39c5baSBill Taylor 	    1 : 0;	/* XXX bogus assumption of a SUN subnet manager */
10399e39c5baSBill Taylor 	lstate.hls_state   = state;
10409e39c5baSBill Taylor 	lstate.hls_retry   = lb.alb_num_retry;
10419e39c5baSBill Taylor 
10429e39c5baSBill Taylor 	/* Free the temporary space used for GID table/PKey table */
10439e39c5baSBill Taylor 	tbl_size = (1 << state->hs_cfg_profile->cp_log_max_gidtbl);
10449e39c5baSBill Taylor 	kmem_free(sgid_tbl, tbl_size * sizeof (ib_gid_t));
10459e39c5baSBill Taylor 	tbl_size = (1 << state->hs_cfg_profile->cp_log_max_pkeytbl);
10469e39c5baSBill Taylor 	kmem_free(pkey_tbl, tbl_size * sizeof (ib_pkey_t));
10479e39c5baSBill Taylor 
10489e39c5baSBill Taylor 	/*
10499e39c5baSBill Taylor 	 * Compute the timeout duration in usec per the formula:
10509e39c5baSBill Taylor 	 *    to_usec_per_retry = 4.096us * (2 ^ supplied_timeout)
10519e39c5baSBill Taylor 	 * (plus we add a little fudge-factor here too)
10529e39c5baSBill Taylor 	 */
10539e39c5baSBill Taylor 	lstate.hls_timeout = lb.alb_timeout;
10549e39c5baSBill Taylor 	max_usec = (4096 * (1 << lstate.hls_timeout)) / 1000;
10559e39c5baSBill Taylor 	max_usec = max_usec * (lstate.hls_retry + 1);
10569e39c5baSBill Taylor 	max_usec = max_usec + 10000;
10579e39c5baSBill Taylor 
10589e39c5baSBill Taylor 	/*
10599e39c5baSBill Taylor 	 * Determine how many times we should loop before declaring a
10609e39c5baSBill Taylor 	 * timeout failure.
10619e39c5baSBill Taylor 	 */
10629e39c5baSBill Taylor 	loopmax	 = max_usec/HERMON_VTS_LOOPBACK_MIN_WAIT_DUR;
10639e39c5baSBill Taylor 	if ((max_usec % HERMON_VTS_LOOPBACK_MIN_WAIT_DUR) != 0) {
10649e39c5baSBill Taylor 		loopmax++;
10659e39c5baSBill Taylor 	}
10669e39c5baSBill Taylor 
10679e39c5baSBill Taylor 	if (lb.alb_send_buf == NULL || lb.alb_buf_sz == 0) {
10689e39c5baSBill Taylor 		lb.alb_error_type = HERMON_LOOPBACK_SEND_BUF_INVALID;
10699e39c5baSBill Taylor 		(void) hermon_loopback_copyout(&lb, arg, mode);
10709e39c5baSBill Taylor 		hermon_loopback_free_state(&lstate);
10719e39c5baSBill Taylor 		return (EINVAL);
10729e39c5baSBill Taylor 	}
10739e39c5baSBill Taylor 
10749e39c5baSBill Taylor 	/* Allocate protection domain (PD) */
10759e39c5baSBill Taylor 	if (hermon_loopback_init(state, &lstate) != 0) {
10769e39c5baSBill Taylor 		lb.alb_error_type = lstate.hls_err;
10779e39c5baSBill Taylor 		(void) hermon_loopback_copyout(&lb, arg, mode);
10789e39c5baSBill Taylor 		hermon_loopback_free_state(&lstate);
10799e39c5baSBill Taylor 		return (EFAULT);
10809e39c5baSBill Taylor 	}
10819e39c5baSBill Taylor 
10829e39c5baSBill Taylor 	/* Allocate and register a TX buffer */
10839e39c5baSBill Taylor 	if (hermon_loopback_alloc_mem(&lstate, &lstate.hls_tx,
10849e39c5baSBill Taylor 	    lb.alb_buf_sz) != 0) {
10859e39c5baSBill Taylor 		lb.alb_error_type =
10869e39c5baSBill Taylor 		    HERMON_LOOPBACK_SEND_BUF_MEM_REGION_ALLOC_FAIL;
10879e39c5baSBill Taylor 		(void) hermon_loopback_copyout(&lb, arg, mode);
10889e39c5baSBill Taylor 		hermon_loopback_free_state(&lstate);
10899e39c5baSBill Taylor 		return (EFAULT);
10909e39c5baSBill Taylor 	}
10919e39c5baSBill Taylor 
10929e39c5baSBill Taylor 	/* Allocate and register an RX buffer */
10939e39c5baSBill Taylor 	if (hermon_loopback_alloc_mem(&lstate, &lstate.hls_rx,
10949e39c5baSBill Taylor 	    lb.alb_buf_sz) != 0) {
10959e39c5baSBill Taylor 		lb.alb_error_type =
10969e39c5baSBill Taylor 		    HERMON_LOOPBACK_RECV_BUF_MEM_REGION_ALLOC_FAIL;
10979e39c5baSBill Taylor 		(void) hermon_loopback_copyout(&lb, arg, mode);
10989e39c5baSBill Taylor 		hermon_loopback_free_state(&lstate);
10999e39c5baSBill Taylor 		return (EFAULT);
11009e39c5baSBill Taylor 	}
11019e39c5baSBill Taylor 
11029e39c5baSBill Taylor 	/* Copy in the transmit buffer data */
11039e39c5baSBill Taylor 	if (ddi_copyin((void *)lb.alb_send_buf, lstate.hls_tx.hlc_buf,
11049e39c5baSBill Taylor 	    lb.alb_buf_sz, mode) != 0) {
11059e39c5baSBill Taylor 		lb.alb_error_type = HERMON_LOOPBACK_SEND_BUF_COPY_FAIL;
11069e39c5baSBill Taylor 		(void) hermon_loopback_copyout(&lb, arg, mode);
11079e39c5baSBill Taylor 		hermon_loopback_free_state(&lstate);
11089e39c5baSBill Taylor 		return (EFAULT);
11099e39c5baSBill Taylor 	}
11109e39c5baSBill Taylor 
11119e39c5baSBill Taylor 	/* Allocate the transmit QP and CQs */
11129e39c5baSBill Taylor 	lstate.hls_err = HERMON_LOOPBACK_XMIT_SEND_CQ_ALLOC_FAIL;
11139e39c5baSBill Taylor 	if (hermon_loopback_alloc_qps(&lstate, &lstate.hls_tx) != 0) {
11149e39c5baSBill Taylor 		lb.alb_error_type = lstate.hls_err;
11159e39c5baSBill Taylor 		(void) hermon_loopback_copyout(&lb, arg, mode);
11169e39c5baSBill Taylor 		hermon_loopback_free_state(&lstate);
11179e39c5baSBill Taylor 		return (EFAULT);
11189e39c5baSBill Taylor 	}
11199e39c5baSBill Taylor 
11209e39c5baSBill Taylor 	/* Allocate the receive QP and CQs */
11219e39c5baSBill Taylor 	lstate.hls_err = HERMON_LOOPBACK_RECV_SEND_CQ_ALLOC_FAIL;
11229e39c5baSBill Taylor 	if (hermon_loopback_alloc_qps(&lstate, &lstate.hls_rx) != 0) {
11239e39c5baSBill Taylor 		lb.alb_error_type = lstate.hls_err;
11249e39c5baSBill Taylor 		(void) hermon_loopback_copyout(&lb, arg, mode);
11259e39c5baSBill Taylor 		hermon_loopback_free_state(&lstate);
11269e39c5baSBill Taylor 		return (EFAULT);
11279e39c5baSBill Taylor 	}
11289e39c5baSBill Taylor 
11299e39c5baSBill Taylor 	/* Activate the TX QP (connect to RX QP) */
11309e39c5baSBill Taylor 	lstate.hls_err = HERMON_LOOPBACK_XMIT_QP_INIT_FAIL;
11319e39c5baSBill Taylor 	if (hermon_loopback_modify_qp(&lstate, &lstate.hls_tx,
11329e39c5baSBill Taylor 	    lstate.hls_rx.hlc_qp_num) != 0) {
11339e39c5baSBill Taylor 		lb.alb_error_type = lstate.hls_err;
11349e39c5baSBill Taylor 		(void) hermon_loopback_copyout(&lb, arg, mode);
11359e39c5baSBill Taylor 		hermon_loopback_free_state(&lstate);
11369e39c5baSBill Taylor 		return (EFAULT);
11379e39c5baSBill Taylor 	}
11389e39c5baSBill Taylor 
11399e39c5baSBill Taylor 	/* Activate the RX QP (connect to TX QP) */
11409e39c5baSBill Taylor 	lstate.hls_err = HERMON_LOOPBACK_RECV_QP_INIT_FAIL;
11419e39c5baSBill Taylor 	if (hermon_loopback_modify_qp(&lstate, &lstate.hls_rx,
11429e39c5baSBill Taylor 	    lstate.hls_tx.hlc_qp_num) != 0) {
11439e39c5baSBill Taylor 		lb.alb_error_type = lstate.hls_err;
11449e39c5baSBill Taylor 		(void) hermon_loopback_copyout(&lb, arg, mode);
11459e39c5baSBill Taylor 		hermon_loopback_free_state(&lstate);
11469e39c5baSBill Taylor 		return (EFAULT);
11479e39c5baSBill Taylor 	}
11489e39c5baSBill Taylor 
11499e39c5baSBill Taylor 	/* Run the loopback test (for specified number of iterations) */
11509e39c5baSBill Taylor 	lb.alb_pass_done = 0;
11519e39c5baSBill Taylor 	for (iter = 0; iter < lb.alb_num_iter; iter++) {
11529e39c5baSBill Taylor 		lstate.hls_err = 0;
11539e39c5baSBill Taylor 		bzero(lstate.hls_rx.hlc_buf, lb.alb_buf_sz);
11549e39c5baSBill Taylor 
11559e39c5baSBill Taylor 		/* Post RDMA Write work request */
11569e39c5baSBill Taylor 		if (hermon_loopback_post_send(&lstate, &lstate.hls_tx,
11579e39c5baSBill Taylor 		    &lstate.hls_rx) != IBT_SUCCESS) {
11589e39c5baSBill Taylor 			lb.alb_error_type = HERMON_LOOPBACK_WQE_POST_FAIL;
11599e39c5baSBill Taylor 			(void) hermon_loopback_copyout(&lb, arg, mode);
11609e39c5baSBill Taylor 			hermon_loopback_free_state(&lstate);
11619e39c5baSBill Taylor 			return (EFAULT);
11629e39c5baSBill Taylor 		}
11639e39c5baSBill Taylor 
11649e39c5baSBill Taylor 		/* Poll the TX CQ for a completion every few ticks */
11659e39c5baSBill Taylor 		for (j = 0; j < loopmax; j++) {
11669e39c5baSBill Taylor 			delay(drv_usectohz(HERMON_VTS_LOOPBACK_MIN_WAIT_DUR));
11679e39c5baSBill Taylor 
11689e39c5baSBill Taylor 			ret = hermon_loopback_poll_cq(&lstate, &lstate.hls_tx);
11699e39c5baSBill Taylor 			if (((ret != IBT_SUCCESS) && (ret != IBT_CQ_EMPTY)) ||
11709e39c5baSBill Taylor 			    ((ret == IBT_CQ_EMPTY) && (j == loopmax - 1))) {
11719e39c5baSBill Taylor 				lb.alb_error_type =
11729e39c5baSBill Taylor 				    HERMON_LOOPBACK_CQ_POLL_FAIL;
11739e39c5baSBill Taylor 				if (ddi_copyout(lstate.hls_rx.hlc_buf,
11749e39c5baSBill Taylor 				    lb.alb_fail_buf, lstate.hls_tx.hlc_buf_sz,
11759e39c5baSBill Taylor 				    mode) != 0) {
11769e39c5baSBill Taylor 					return (EFAULT);
11779e39c5baSBill Taylor 				}
11789e39c5baSBill Taylor 				(void) hermon_loopback_copyout(&lb, arg, mode);
11799e39c5baSBill Taylor 				hermon_loopback_free_state(&lstate);
11809e39c5baSBill Taylor 				return (EFAULT);
11819e39c5baSBill Taylor 			} else if (ret == IBT_CQ_EMPTY) {
11829e39c5baSBill Taylor 				continue;
11839e39c5baSBill Taylor 			}
11849e39c5baSBill Taylor 
11859e39c5baSBill Taylor 			/* Compare the data buffers */
11869e39c5baSBill Taylor 			if (bcmp(lstate.hls_tx.hlc_buf, lstate.hls_rx.hlc_buf,
11879e39c5baSBill Taylor 			    lb.alb_buf_sz) == 0) {
11889e39c5baSBill Taylor 				break;
11899e39c5baSBill Taylor 			} else {
11909e39c5baSBill Taylor 				lb.alb_error_type =
11919e39c5baSBill Taylor 				    HERMON_LOOPBACK_SEND_RECV_COMPARE_FAIL;
11929e39c5baSBill Taylor 				if (ddi_copyout(lstate.hls_rx.hlc_buf,
11939e39c5baSBill Taylor 				    lb.alb_fail_buf, lstate.hls_tx.hlc_buf_sz,
11949e39c5baSBill Taylor 				    mode) != 0) {
11959e39c5baSBill Taylor 					return (EFAULT);
11969e39c5baSBill Taylor 				}
11979e39c5baSBill Taylor 				(void) hermon_loopback_copyout(&lb, arg, mode);
11989e39c5baSBill Taylor 				hermon_loopback_free_state(&lstate);
11999e39c5baSBill Taylor 				return (EFAULT);
12009e39c5baSBill Taylor 			}
12019e39c5baSBill Taylor 		}
12029e39c5baSBill Taylor 
12039e39c5baSBill Taylor 		lstate.hls_err	 = HERMON_LOOPBACK_SUCCESS;
12049e39c5baSBill Taylor 		lb.alb_pass_done = iter + 1;
12059e39c5baSBill Taylor 	}
12069e39c5baSBill Taylor 
12079e39c5baSBill Taylor 	lb.alb_error_type = HERMON_LOOPBACK_SUCCESS;
12089e39c5baSBill Taylor 
12099e39c5baSBill Taylor 	/* Copy ioctl results back to user struct */
12109e39c5baSBill Taylor 	ret = hermon_loopback_copyout(&lb, arg, mode);
12119e39c5baSBill Taylor 
12129e39c5baSBill Taylor 	/* Free up everything and release all consumed resources */
12139e39c5baSBill Taylor 	hermon_loopback_free_state(&lstate);
12149e39c5baSBill Taylor 
12159e39c5baSBill Taylor 	return (ret);
12169e39c5baSBill Taylor }
12179e39c5baSBill Taylor 
12189e39c5baSBill Taylor #ifdef	DEBUG
12199e39c5baSBill Taylor /*
12209e39c5baSBill Taylor  * hermon_ioctl_reg_read()
12219e39c5baSBill Taylor  */
12229e39c5baSBill Taylor static int
hermon_ioctl_reg_read(hermon_state_t * state,intptr_t arg,int mode)12239e39c5baSBill Taylor hermon_ioctl_reg_read(hermon_state_t *state, intptr_t arg, int mode)
12249e39c5baSBill Taylor {
12259e39c5baSBill Taylor 	hermon_reg_ioctl_t	rdreg;
12269e39c5baSBill Taylor 	uint32_t		*addr;
12279e39c5baSBill Taylor 	uintptr_t		baseaddr;
12289e39c5baSBill Taylor 	int			status;
12299e39c5baSBill Taylor 	ddi_acc_handle_t	handle;
12309e39c5baSBill Taylor 
12319e39c5baSBill Taylor 	/* initialize the FMA retry loop */
12329e39c5baSBill Taylor 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
12339e39c5baSBill Taylor 
12349e39c5baSBill Taylor 	/*
12359e39c5baSBill Taylor 	 * Access to Hemron registers is not allowed in "maintenance mode".
12369e39c5baSBill Taylor 	 * This is primarily because the device may not have BARs to access
12379e39c5baSBill Taylor 	 */
12389e39c5baSBill Taylor 	if (state->hs_operational_mode == HERMON_MAINTENANCE_MODE) {
12399e39c5baSBill Taylor 		return (EFAULT);
12409e39c5baSBill Taylor 	}
12419e39c5baSBill Taylor 
12429e39c5baSBill Taylor 	/* Copy in the hermon_reg_ioctl_t structure */
12439e39c5baSBill Taylor 	status = ddi_copyin((void *)arg, &rdreg, sizeof (hermon_reg_ioctl_t),
12449e39c5baSBill Taylor 	    mode);
12459e39c5baSBill Taylor 	if (status != 0) {
12469e39c5baSBill Taylor 		return (EFAULT);
12479e39c5baSBill Taylor 	}
12489e39c5baSBill Taylor 
12499e39c5baSBill Taylor 	/* Determine base address for requested register set */
12509e39c5baSBill Taylor 	switch (rdreg.arg_reg_set) {
12519e39c5baSBill Taylor 	case HERMON_CMD_BAR:
12529e39c5baSBill Taylor 		baseaddr = (uintptr_t)state->hs_reg_cmd_baseaddr;
12539e39c5baSBill Taylor 		handle = hermon_get_cmdhdl(state);
12549e39c5baSBill Taylor 		break;
12559e39c5baSBill Taylor 
12569e39c5baSBill Taylor 	case HERMON_UAR_BAR:
12579e39c5baSBill Taylor 		baseaddr = (uintptr_t)state->hs_reg_uar_baseaddr;
12589e39c5baSBill Taylor 		handle = hermon_get_uarhdl(state);
12599e39c5baSBill Taylor 		break;
12609e39c5baSBill Taylor 
12619e39c5baSBill Taylor 
12629e39c5baSBill Taylor 	default:
12639e39c5baSBill Taylor 		return (EINVAL);
12649e39c5baSBill Taylor 	}
12659e39c5baSBill Taylor 
12669e39c5baSBill Taylor 	/* Ensure that address is properly-aligned */
12679e39c5baSBill Taylor 	addr = (uint32_t *)((baseaddr + rdreg.arg_offset) & ~0x3);
12689e39c5baSBill Taylor 
12699e39c5baSBill Taylor 	/* the FMA retry loop starts. */
12709e39c5baSBill Taylor 	hermon_pio_start(state, handle, pio_error, fm_loop_cnt,
12719e39c5baSBill Taylor 	    fm_status, fm_test);
12729e39c5baSBill Taylor 
12739e39c5baSBill Taylor 	/* Read the register pointed to by addr */
12749e39c5baSBill Taylor 	rdreg.arg_data = ddi_get32(handle, addr);
12759e39c5baSBill Taylor 
12769e39c5baSBill Taylor 	/* the FMA retry loop ends. */
12779e39c5baSBill Taylor 	hermon_pio_end(state, handle, pio_error, fm_loop_cnt, fm_status,
12789e39c5baSBill Taylor 	    fm_test);
12799e39c5baSBill Taylor 
12809e39c5baSBill Taylor 	/* Copy in the result into the hermon_reg_ioctl_t structure */
12819e39c5baSBill Taylor 	status = ddi_copyout(&rdreg, (void *)arg, sizeof (hermon_reg_ioctl_t),
12829e39c5baSBill Taylor 	    mode);
12839e39c5baSBill Taylor 	if (status != 0) {
12849e39c5baSBill Taylor 		return (EFAULT);
12859e39c5baSBill Taylor 	}
12869e39c5baSBill Taylor 	return (0);
12879e39c5baSBill Taylor 
12889e39c5baSBill Taylor pio_error:
12899e39c5baSBill Taylor 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
12909e39c5baSBill Taylor 	return (EIO);
12919e39c5baSBill Taylor }
12929e39c5baSBill Taylor 
12939e39c5baSBill Taylor 
12949e39c5baSBill Taylor /*
12959e39c5baSBill Taylor  * hermon_ioctl_reg_write()
12969e39c5baSBill Taylor  */
12979e39c5baSBill Taylor static int
hermon_ioctl_reg_write(hermon_state_t * state,intptr_t arg,int mode)12989e39c5baSBill Taylor hermon_ioctl_reg_write(hermon_state_t *state, intptr_t arg, int mode)
12999e39c5baSBill Taylor {
13009e39c5baSBill Taylor 	hermon_reg_ioctl_t	wrreg;
13019e39c5baSBill Taylor 	uint32_t		*addr;
13029e39c5baSBill Taylor 	uintptr_t		baseaddr;
13039e39c5baSBill Taylor 	int			status;
13049e39c5baSBill Taylor 	ddi_acc_handle_t	handle;
13059e39c5baSBill Taylor 
13069e39c5baSBill Taylor 	/* initialize the FMA retry loop */
13079e39c5baSBill Taylor 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
13089e39c5baSBill Taylor 
13099e39c5baSBill Taylor 	/*
13109e39c5baSBill Taylor 	 * Access to Hermon registers is not allowed in "maintenance mode".
13119e39c5baSBill Taylor 	 * This is primarily because the device may not have BARs to access
13129e39c5baSBill Taylor 	 */
13139e39c5baSBill Taylor 	if (state->hs_operational_mode == HERMON_MAINTENANCE_MODE) {
13149e39c5baSBill Taylor 		return (EFAULT);
13159e39c5baSBill Taylor 	}
13169e39c5baSBill Taylor 
13179e39c5baSBill Taylor 	/* Copy in the hermon_reg_ioctl_t structure */
13189e39c5baSBill Taylor 	status = ddi_copyin((void *)arg, &wrreg, sizeof (hermon_reg_ioctl_t),
13199e39c5baSBill Taylor 	    mode);
13209e39c5baSBill Taylor 	if (status != 0) {
13219e39c5baSBill Taylor 		return (EFAULT);
13229e39c5baSBill Taylor 	}
13239e39c5baSBill Taylor 
13249e39c5baSBill Taylor 	/* Determine base address for requested register set */
13259e39c5baSBill Taylor 	switch (wrreg.arg_reg_set) {
13269e39c5baSBill Taylor 	case HERMON_CMD_BAR:
13279e39c5baSBill Taylor 		baseaddr = (uintptr_t)state->hs_reg_cmd_baseaddr;
13289e39c5baSBill Taylor 		handle = hermon_get_cmdhdl(state);
13299e39c5baSBill Taylor 		break;
13309e39c5baSBill Taylor 
13319e39c5baSBill Taylor 	case HERMON_UAR_BAR:
13329e39c5baSBill Taylor 		baseaddr = (uintptr_t)state->hs_reg_uar_baseaddr;
13339e39c5baSBill Taylor 		handle = hermon_get_uarhdl(state);
13349e39c5baSBill Taylor 		break;
13359e39c5baSBill Taylor 
13369e39c5baSBill Taylor 	default:
13379e39c5baSBill Taylor 		return (EINVAL);
13389e39c5baSBill Taylor 	}
13399e39c5baSBill Taylor 
13409e39c5baSBill Taylor 	/* Ensure that address is properly-aligned */
13419e39c5baSBill Taylor 	addr = (uint32_t *)((baseaddr + wrreg.arg_offset) & ~0x3);
13429e39c5baSBill Taylor 
13439e39c5baSBill Taylor 	/* the FMA retry loop starts. */
13449e39c5baSBill Taylor 	hermon_pio_start(state, handle, pio_error, fm_loop_cnt,
13459e39c5baSBill Taylor 	    fm_status, fm_test);
13469e39c5baSBill Taylor 
13479e39c5baSBill Taylor 	/* Write the data to the register pointed to by addr */
13489e39c5baSBill Taylor 	ddi_put32(handle, addr, wrreg.arg_data);
13499e39c5baSBill Taylor 
13509e39c5baSBill Taylor 	/* the FMA retry loop ends. */
13519e39c5baSBill Taylor 	hermon_pio_end(state, handle, pio_error, fm_loop_cnt, fm_status,
13529e39c5baSBill Taylor 	    fm_test);
13539e39c5baSBill Taylor 	return (0);
13549e39c5baSBill Taylor 
13559e39c5baSBill Taylor pio_error:
13569e39c5baSBill Taylor 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
13579e39c5baSBill Taylor 	return (EIO);
13589e39c5baSBill Taylor }
13599e39c5baSBill Taylor #endif	/* DEBUG */
13609e39c5baSBill Taylor 
13619e39c5baSBill Taylor static int
hermon_ioctl_write_boot_addr(hermon_state_t * state,dev_t dev,intptr_t arg,int mode)13629e39c5baSBill Taylor hermon_ioctl_write_boot_addr(hermon_state_t *state, dev_t dev, intptr_t arg,
13639e39c5baSBill Taylor     int mode)
13649e39c5baSBill Taylor {
13659e39c5baSBill Taylor 	hermon_flash_ioctl_t	ioctl_info;
13669e39c5baSBill Taylor 
13679e39c5baSBill Taylor 	/* initialize the FMA retry loop */
13689e39c5baSBill Taylor 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
13699e39c5baSBill Taylor 
13709e39c5baSBill Taylor 	/*
13719e39c5baSBill Taylor 	 * Check that flash init ioctl has been called first.  And check
13729e39c5baSBill Taylor 	 * that the same dev_t that called init is the one calling write now.
13739e39c5baSBill Taylor 	 */
13749e39c5baSBill Taylor 	mutex_enter(&state->hs_fw_flashlock);
13759e39c5baSBill Taylor 	if ((state->hs_fw_flashdev != dev) ||
13769e39c5baSBill Taylor 	    (state->hs_fw_flashstarted == 0)) {
13779e39c5baSBill Taylor 		mutex_exit(&state->hs_fw_flashlock);
13789e39c5baSBill Taylor 		return (EIO);
13799e39c5baSBill Taylor 	}
13809e39c5baSBill Taylor 
13819e39c5baSBill Taylor 	/* copy user struct to kernel */
13829e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
13839e39c5baSBill Taylor 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
13849e39c5baSBill Taylor 		hermon_flash_ioctl32_t info32;
13859e39c5baSBill Taylor 
13869e39c5baSBill Taylor 		if (ddi_copyin((void *)arg, &info32,
13879e39c5baSBill Taylor 		    sizeof (hermon_flash_ioctl32_t), mode) != 0) {
13889e39c5baSBill Taylor 			mutex_exit(&state->hs_fw_flashlock);
13899e39c5baSBill Taylor 			return (EFAULT);
13909e39c5baSBill Taylor 		}
13919e39c5baSBill Taylor 		ioctl_info.af_type = info32.af_type;
13929e39c5baSBill Taylor 		ioctl_info.af_sector = (caddr_t)(uintptr_t)info32.af_sector;
13939e39c5baSBill Taylor 		ioctl_info.af_sector_num = info32.af_sector_num;
13949e39c5baSBill Taylor 		ioctl_info.af_addr = info32.af_addr;
13959e39c5baSBill Taylor 		ioctl_info.af_byte = info32.af_byte;
13969e39c5baSBill Taylor 	} else
13979e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
13989e39c5baSBill Taylor 	if (ddi_copyin((void *)arg, &ioctl_info,
13999e39c5baSBill Taylor 	    sizeof (hermon_flash_ioctl_t), mode) != 0) {
14009e39c5baSBill Taylor 		mutex_exit(&state->hs_fw_flashlock);
14019e39c5baSBill Taylor 		return (EFAULT);
14029e39c5baSBill Taylor 	}
14039e39c5baSBill Taylor 
14049e39c5baSBill Taylor 	switch (state->hs_fw_cmdset) {
14059e39c5baSBill Taylor 	case HERMON_FLASH_AMD_CMDSET:
14069e39c5baSBill Taylor 	case HERMON_FLASH_INTEL_CMDSET:
14079e39c5baSBill Taylor 		break;
14089e39c5baSBill Taylor 
14099e39c5baSBill Taylor 	case HERMON_FLASH_SPI_CMDSET:
14109e39c5baSBill Taylor 	{
14119e39c5baSBill Taylor 		ddi_acc_handle_t pci_hdl = hermon_get_pcihdl(state);
14129e39c5baSBill Taylor 
14139e39c5baSBill Taylor 		/* the FMA retry loop starts. */
14149e39c5baSBill Taylor 		hermon_pio_start(state, pci_hdl, pio_error,
14159e39c5baSBill Taylor 		    fm_loop_cnt, fm_status, fm_test);
14169e39c5baSBill Taylor 
14179e39c5baSBill Taylor 		hermon_flash_write_cfg(state, pci_hdl,
14189e39c5baSBill Taylor 		    HERMON_HW_FLASH_SPI_BOOT_ADDR_REG,
14199e39c5baSBill Taylor 		    (ioctl_info.af_addr << 8) | 0x06);
14209e39c5baSBill Taylor 
14219e39c5baSBill Taylor 		/* the FMA retry loop ends. */
14229e39c5baSBill Taylor 		hermon_pio_end(state, pci_hdl, pio_error,
14239e39c5baSBill Taylor 		    fm_loop_cnt, fm_status, fm_test);
14249e39c5baSBill Taylor 		break;
14259e39c5baSBill Taylor 	}
14269e39c5baSBill Taylor 
14279e39c5baSBill Taylor 	case HERMON_FLASH_UNKNOWN_CMDSET:
14289e39c5baSBill Taylor 	default:
14299e39c5baSBill Taylor 		mutex_exit(&state->hs_fw_flashlock);
14309e39c5baSBill Taylor 		return (EINVAL);
14319e39c5baSBill Taylor 	}
14329e39c5baSBill Taylor 	mutex_exit(&state->hs_fw_flashlock);
14339e39c5baSBill Taylor 	return (0);
14349e39c5baSBill Taylor 
14359e39c5baSBill Taylor pio_error:
14369e39c5baSBill Taylor 	mutex_exit(&state->hs_fw_flashlock);
14379e39c5baSBill Taylor 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
14389e39c5baSBill Taylor 	return (EIO);
14399e39c5baSBill Taylor }
14409e39c5baSBill Taylor 
14419e39c5baSBill Taylor /*
14429e39c5baSBill Taylor  * hermon_flash_reset()
14439e39c5baSBill Taylor  */
14449e39c5baSBill Taylor static int
hermon_flash_reset(hermon_state_t * state)14459e39c5baSBill Taylor hermon_flash_reset(hermon_state_t *state)
14469e39c5baSBill Taylor {
14479e39c5baSBill Taylor 	int status;
14489e39c5baSBill Taylor 
14499e39c5baSBill Taylor 	/*
14509e39c5baSBill Taylor 	 * Performs a reset to the flash device.  After a reset the flash will
14519e39c5baSBill Taylor 	 * be operating in normal mode (capable of read/write, etc.).
14529e39c5baSBill Taylor 	 */
14539e39c5baSBill Taylor 	switch (state->hs_fw_cmdset) {
14549e39c5baSBill Taylor 	case HERMON_FLASH_AMD_CMDSET:
14559e39c5baSBill Taylor 		hermon_flash_write(state, 0x555, HERMON_HW_FLASH_RESET_AMD,
14569e39c5baSBill Taylor 		    &status);
14579e39c5baSBill Taylor 		if (status != 0) {
14589e39c5baSBill Taylor 			return (status);
14599e39c5baSBill Taylor 		}
14609e39c5baSBill Taylor 		break;
14619e39c5baSBill Taylor 
14629e39c5baSBill Taylor 	case HERMON_FLASH_INTEL_CMDSET:
14639e39c5baSBill Taylor 		hermon_flash_write(state, 0x555, HERMON_HW_FLASH_RESET_INTEL,
14649e39c5baSBill Taylor 		    &status);
14659e39c5baSBill Taylor 		if (status != 0) {
14669e39c5baSBill Taylor 			return (status);
14679e39c5baSBill Taylor 		}
14689e39c5baSBill Taylor 		break;
14699e39c5baSBill Taylor 
14709e39c5baSBill Taylor 	/* It appears no reset is needed for SPI */
14719e39c5baSBill Taylor 	case HERMON_FLASH_SPI_CMDSET:
14729e39c5baSBill Taylor 		status = 0;
14739e39c5baSBill Taylor 		break;
14749e39c5baSBill Taylor 
14759e39c5baSBill Taylor 	case HERMON_FLASH_UNKNOWN_CMDSET:
14769e39c5baSBill Taylor 	default:
14779e39c5baSBill Taylor 		status = EINVAL;
14789e39c5baSBill Taylor 		break;
14799e39c5baSBill Taylor 	}
14809e39c5baSBill Taylor 	return (status);
14819e39c5baSBill Taylor }
14829e39c5baSBill Taylor 
14839e39c5baSBill Taylor /*
14849e39c5baSBill Taylor  * hermon_flash_read_sector()
14859e39c5baSBill Taylor  */
14869e39c5baSBill Taylor static int
hermon_flash_read_sector(hermon_state_t * state,uint32_t sector_num)14879e39c5baSBill Taylor hermon_flash_read_sector(hermon_state_t *state, uint32_t sector_num)
14889e39c5baSBill Taylor {
14899e39c5baSBill Taylor 	uint32_t addr;
14909e39c5baSBill Taylor 	uint32_t end_addr;
14919e39c5baSBill Taylor 	uint32_t *image;
14929e39c5baSBill Taylor 	int i, status;
14939e39c5baSBill Taylor 
14949e39c5baSBill Taylor 	image = (uint32_t *)&state->hs_fw_sector[0];
14959e39c5baSBill Taylor 
14969e39c5baSBill Taylor 	/*
14979e39c5baSBill Taylor 	 * Calculate the start and end address of the sector, based on the
14989e39c5baSBill Taylor 	 * sector number passed in.
14999e39c5baSBill Taylor 	 */
15009e39c5baSBill Taylor 	addr = sector_num << state->hs_fw_log_sector_sz;
15019e39c5baSBill Taylor 	end_addr = addr + (1 << state->hs_fw_log_sector_sz);
15029e39c5baSBill Taylor 
15039e39c5baSBill Taylor 	/* Set the flash bank correctly for the given address */
15049e39c5baSBill Taylor 	if ((status = hermon_flash_bank(state, addr)) != 0)
15059e39c5baSBill Taylor 		return (status);
15069e39c5baSBill Taylor 
15079e39c5baSBill Taylor 	/* Read the entire sector, one quadlet at a time */
15089e39c5baSBill Taylor 	for (i = 0; addr < end_addr; i++, addr += 4) {
15099e39c5baSBill Taylor 		image[i] = hermon_flash_read(state, addr, &status);
15109e39c5baSBill Taylor 		if (status != 0) {
15119e39c5baSBill Taylor 			return (status);
15129e39c5baSBill Taylor 		}
15139e39c5baSBill Taylor 	}
15149e39c5baSBill Taylor 	return (0);
15159e39c5baSBill Taylor }
15169e39c5baSBill Taylor 
15179e39c5baSBill Taylor /*
15189e39c5baSBill Taylor  * hermon_flash_read_quadlet()
15199e39c5baSBill Taylor  */
15209e39c5baSBill Taylor static int
hermon_flash_read_quadlet(hermon_state_t * state,uint32_t * data,uint32_t addr)15219e39c5baSBill Taylor hermon_flash_read_quadlet(hermon_state_t *state, uint32_t *data,
15229e39c5baSBill Taylor     uint32_t addr)
15239e39c5baSBill Taylor {
15249e39c5baSBill Taylor 	int status;
15259e39c5baSBill Taylor 
15269e39c5baSBill Taylor 	/* Set the flash bank correctly for the given address */
15279e39c5baSBill Taylor 	if ((status = hermon_flash_bank(state, addr)) != 0) {
15289e39c5baSBill Taylor 		return (status);
15299e39c5baSBill Taylor 	}
15309e39c5baSBill Taylor 
15319e39c5baSBill Taylor 	/* Read one quadlet of data */
15329e39c5baSBill Taylor 	*data = hermon_flash_read(state, addr, &status);
15339e39c5baSBill Taylor 	if (status != 0) {
15349e39c5baSBill Taylor 		return (EIO);
15359e39c5baSBill Taylor 	}
15369e39c5baSBill Taylor 
15379e39c5baSBill Taylor 	return (0);
15389e39c5baSBill Taylor }
15399e39c5baSBill Taylor 
15409e39c5baSBill Taylor /*
15419e39c5baSBill Taylor  * hermon_flash_write_sector()
15429e39c5baSBill Taylor  */
15439e39c5baSBill Taylor static int
hermon_flash_write_sector(hermon_state_t * state,uint32_t sector_num)15449e39c5baSBill Taylor hermon_flash_write_sector(hermon_state_t *state, uint32_t sector_num)
15459e39c5baSBill Taylor {
15469e39c5baSBill Taylor 	uint32_t	addr;
15479e39c5baSBill Taylor 	uint32_t	end_addr;
15489e39c5baSBill Taylor 	uint32_t	*databuf;
15499e39c5baSBill Taylor 	uchar_t		*sector;
15509e39c5baSBill Taylor 	int		status = 0;
15519e39c5baSBill Taylor 	int		i;
15529e39c5baSBill Taylor 
15539e39c5baSBill Taylor 	sector = (uchar_t *)&state->hs_fw_sector[0];
15549e39c5baSBill Taylor 
15559e39c5baSBill Taylor 	/*
15569e39c5baSBill Taylor 	 * Calculate the start and end address of the sector, based on the
15579e39c5baSBill Taylor 	 * sector number passed in.
15589e39c5baSBill Taylor 	 */
15599e39c5baSBill Taylor 	addr = sector_num << state->hs_fw_log_sector_sz;
15609e39c5baSBill Taylor 	end_addr = addr + (1 << state->hs_fw_log_sector_sz);
15619e39c5baSBill Taylor 
15629e39c5baSBill Taylor 	/* Set the flash bank correctly for the given address */
15639e39c5baSBill Taylor 	if ((status = hermon_flash_bank(state, addr)) != 0 ||
15649e39c5baSBill Taylor 	    (status = hermon_flash_reset(state)) != 0) {
15659e39c5baSBill Taylor 		return (status);
15669e39c5baSBill Taylor 	}
15679e39c5baSBill Taylor 
15689e39c5baSBill Taylor 	/* Erase the sector before writing */
15699e39c5baSBill Taylor 	status = hermon_flash_erase_sector(state, sector_num);
15709e39c5baSBill Taylor 	if (status != 0) {
15719e39c5baSBill Taylor 		return (status);
15729e39c5baSBill Taylor 	}
15739e39c5baSBill Taylor 
15749e39c5baSBill Taylor 	switch (state->hs_fw_cmdset) {
15759e39c5baSBill Taylor 	case HERMON_FLASH_SPI_CMDSET:
15769e39c5baSBill Taylor 		databuf = (uint32_t *)(void *)sector;
15779e39c5baSBill Taylor 		/* Write the sector, one dword at a time */
15789e39c5baSBill Taylor 		for (i = 0; addr < end_addr; i++, addr += 4) {
15799e39c5baSBill Taylor 			if ((status = hermon_flash_spi_write_dword(state, addr,
15809e39c5baSBill Taylor 			    htonl(databuf[i]))) != 0) {
15819e39c5baSBill Taylor 				return (status);
15829e39c5baSBill Taylor 			}
15839e39c5baSBill Taylor 		}
15849e39c5baSBill Taylor 		status = hermon_flash_reset(state);
15859e39c5baSBill Taylor 		break;
15869e39c5baSBill Taylor 
15879e39c5baSBill Taylor 	case HERMON_FLASH_INTEL_CMDSET:
15889e39c5baSBill Taylor 	case HERMON_FLASH_AMD_CMDSET:
15899e39c5baSBill Taylor 		/* Write the sector, one byte at a time */
15909e39c5baSBill Taylor 		for (i = 0; addr < end_addr; i++, addr++) {
15919e39c5baSBill Taylor 			status = hermon_flash_write_byte(state, addr,
15929e39c5baSBill Taylor 			    sector[i]);
15939e39c5baSBill Taylor 			if (status != 0) {
15949e39c5baSBill Taylor 				break;
15959e39c5baSBill Taylor 			}
15969e39c5baSBill Taylor 		}
15979e39c5baSBill Taylor 		status = hermon_flash_reset(state);
15989e39c5baSBill Taylor 		break;
15999e39c5baSBill Taylor 
16009e39c5baSBill Taylor 	case HERMON_FLASH_UNKNOWN_CMDSET:
16019e39c5baSBill Taylor 	default:
16029e39c5baSBill Taylor 		status = EINVAL;
16039e39c5baSBill Taylor 		break;
16049e39c5baSBill Taylor 	}
16059e39c5baSBill Taylor 
16069e39c5baSBill Taylor 	return (status);
16079e39c5baSBill Taylor }
16089e39c5baSBill Taylor 
16099e39c5baSBill Taylor /*
16109e39c5baSBill Taylor  * hermon_flash_spi_write_dword()
16119e39c5baSBill Taylor  *
16129e39c5baSBill Taylor  * NOTE: This function assumes that "data" is in network byte order.
16139e39c5baSBill Taylor  *
16149e39c5baSBill Taylor  */
16159e39c5baSBill Taylor static int
hermon_flash_spi_write_dword(hermon_state_t * state,uint32_t addr,uint32_t data)16169e39c5baSBill Taylor hermon_flash_spi_write_dword(hermon_state_t *state, uint32_t addr,
16179e39c5baSBill Taylor     uint32_t data)
16189e39c5baSBill Taylor {
16199e39c5baSBill Taylor 	int status;
16209e39c5baSBill Taylor 	ddi_acc_handle_t	hdl;
16219e39c5baSBill Taylor 
16229e39c5baSBill Taylor 	/* initialize the FMA retry loop */
16239e39c5baSBill Taylor 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
16249e39c5baSBill Taylor 
16259e39c5baSBill Taylor 	hdl = hermon_get_pcihdl(state);
16269e39c5baSBill Taylor 
16279e39c5baSBill Taylor 	/* the FMA retry loop starts. */
16289e39c5baSBill Taylor 	hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status,
16299e39c5baSBill Taylor 	    fm_test);
16309e39c5baSBill Taylor 
16319e39c5baSBill Taylor 	/* Issue Write Enable */
16329e39c5baSBill Taylor 	hermon_flash_spi_write_enable(state);
16339e39c5baSBill Taylor 
16349e39c5baSBill Taylor 	/* Set the Address */
16359e39c5baSBill Taylor 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_SPI_ADDR,
16369e39c5baSBill Taylor 	    addr & HERMON_HW_FLASH_SPI_ADDR_MASK);
16379e39c5baSBill Taylor 
16389e39c5baSBill Taylor 	/* Set the Data */
16399e39c5baSBill Taylor 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_SPI_DATA, data);
16409e39c5baSBill Taylor 
16419e39c5baSBill Taylor 	/* Set the Page Program and execute */
16429e39c5baSBill Taylor 	hermon_flash_spi_exec_command(state, hdl,
16439e39c5baSBill Taylor 	    HERMON_HW_FLASH_SPI_INSTR_PHASE_OFF |
16449e39c5baSBill Taylor 	    HERMON_HW_FLASH_SPI_ADDR_PHASE_OFF |
16459e39c5baSBill Taylor 	    HERMON_HW_FLASH_SPI_DATA_PHASE_OFF |
16469e39c5baSBill Taylor 	    HERMON_HW_FLASH_SPI_TRANS_SZ_4B |
16479e39c5baSBill Taylor 	    (HERMON_HW_FLASH_SPI_PAGE_PROGRAM <<
16489e39c5baSBill Taylor 	    HERMON_HW_FLASH_SPI_INSTR_SHIFT));
16499e39c5baSBill Taylor 
16509e39c5baSBill Taylor 	/* Wait for write to complete */
16519e39c5baSBill Taylor 	if ((status = hermon_flash_spi_wait_wip(state)) != 0) {
16529e39c5baSBill Taylor 		return (status);
16539e39c5baSBill Taylor 	}
16549e39c5baSBill Taylor 
16559e39c5baSBill Taylor 	/* the FMA retry loop ends. */
16569e39c5baSBill Taylor 	hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status, fm_test);
16579e39c5baSBill Taylor 	return (0);
16589e39c5baSBill Taylor 
16599e39c5baSBill Taylor pio_error:
16609e39c5baSBill Taylor 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
16619e39c5baSBill Taylor 	return (EIO);
16629e39c5baSBill Taylor }
16639e39c5baSBill Taylor 
16649e39c5baSBill Taylor /*
16659e39c5baSBill Taylor  * hermon_flash_write_byte()
16669e39c5baSBill Taylor  */
16679e39c5baSBill Taylor static int
hermon_flash_write_byte(hermon_state_t * state,uint32_t addr,uchar_t data)16689e39c5baSBill Taylor hermon_flash_write_byte(hermon_state_t *state, uint32_t addr, uchar_t data)
16699e39c5baSBill Taylor {
16709e39c5baSBill Taylor 	uint32_t stat;
16719e39c5baSBill Taylor 	int status = 0;
16729e39c5baSBill Taylor 	int dword_addr;
16739e39c5baSBill Taylor 	int byte_offset;
16749e39c5baSBill Taylor 	int i;
16759e39c5baSBill Taylor 	union {
16769e39c5baSBill Taylor 		uint8_t		bytes[4];
16779e39c5baSBill Taylor 		uint32_t	dword;
16789e39c5baSBill Taylor 	} dword;
16799e39c5baSBill Taylor 
16809e39c5baSBill Taylor 	switch (state->hs_fw_cmdset) {
16819e39c5baSBill Taylor 	case HERMON_FLASH_AMD_CMDSET:
16829e39c5baSBill Taylor 		/* Issue Flash Byte program command */
16839e39c5baSBill Taylor 		hermon_flash_write(state, addr, 0xAA, &status);
16849e39c5baSBill Taylor 		if (status != 0) {
16859e39c5baSBill Taylor 			return (status);
16869e39c5baSBill Taylor 		}
16879e39c5baSBill Taylor 
16889e39c5baSBill Taylor 		hermon_flash_write(state, addr, 0x55, &status);
16899e39c5baSBill Taylor 		if (status != 0) {
16909e39c5baSBill Taylor 			return (status);
16919e39c5baSBill Taylor 		}
16929e39c5baSBill Taylor 
16939e39c5baSBill Taylor 		hermon_flash_write(state, addr, 0xA0, &status);
16949e39c5baSBill Taylor 		if (status != 0) {
16959e39c5baSBill Taylor 			return (status);
16969e39c5baSBill Taylor 		}
16979e39c5baSBill Taylor 
16989e39c5baSBill Taylor 		hermon_flash_write(state, addr, data, &status);
16999e39c5baSBill Taylor 		if (status != 0) {
17009e39c5baSBill Taylor 			return (status);
17019e39c5baSBill Taylor 		}
17029e39c5baSBill Taylor 
17039e39c5baSBill Taylor 		/* Wait for Write Byte to Complete */
17049e39c5baSBill Taylor 		i = 0;
17059e39c5baSBill Taylor 		do {
17069e39c5baSBill Taylor 			drv_usecwait(1);
17079e39c5baSBill Taylor 			stat = hermon_flash_read(state, addr & ~3, &status);
17089e39c5baSBill Taylor 			if (status != 0) {
17099e39c5baSBill Taylor 				return (status);
17109e39c5baSBill Taylor 			}
17119e39c5baSBill Taylor 
17129e39c5baSBill Taylor 			if (i == hermon_hw_flash_timeout_write) {
17139e39c5baSBill Taylor 				cmn_err(CE_WARN,
17149e39c5baSBill Taylor 				    "hermon_flash_write_byte: ACS write "
17159e39c5baSBill Taylor 				    "timeout: addr: 0x%x, data: 0x%x\n",
17169e39c5baSBill Taylor 				    addr, data);
17179e39c5baSBill Taylor 				hermon_fm_ereport(state, HCA_SYS_ERR,
17189e39c5baSBill Taylor 				    HCA_ERR_IOCTL);
17199e39c5baSBill Taylor 				return (EIO);
17209e39c5baSBill Taylor 			}
17219e39c5baSBill Taylor 			i++;
17229e39c5baSBill Taylor 		} while (data != ((stat >> ((3 - (addr & 3)) << 3)) & 0xFF));
17239e39c5baSBill Taylor 
17249e39c5baSBill Taylor 		break;
17259e39c5baSBill Taylor 
17269e39c5baSBill Taylor 	case HERMON_FLASH_INTEL_CMDSET:
17279e39c5baSBill Taylor 		/* Issue Flash Byte program command */
17289e39c5baSBill Taylor 		hermon_flash_write(state, addr, HERMON_HW_FLASH_ICS_WRITE,
17299e39c5baSBill Taylor 		    &status);
17309e39c5baSBill Taylor 		if (status != 0) {
17319e39c5baSBill Taylor 			return (status);
17329e39c5baSBill Taylor 		}
17339e39c5baSBill Taylor 		hermon_flash_write(state, addr, data, &status);
17349e39c5baSBill Taylor 		if (status != 0) {
17359e39c5baSBill Taylor 			return (status);
17369e39c5baSBill Taylor 		}
17379e39c5baSBill Taylor 
17389e39c5baSBill Taylor 		/* Wait for Write Byte to Complete */
17399e39c5baSBill Taylor 		i = 0;
17409e39c5baSBill Taylor 		do {
17419e39c5baSBill Taylor 			drv_usecwait(1);
17429e39c5baSBill Taylor 			stat = hermon_flash_read(state, addr & ~3, &status);
17439e39c5baSBill Taylor 			if (status != 0) {
17449e39c5baSBill Taylor 				return (status);
17459e39c5baSBill Taylor 			}
17469e39c5baSBill Taylor 
17479e39c5baSBill Taylor 			if (i == hermon_hw_flash_timeout_write) {
17489e39c5baSBill Taylor 				cmn_err(CE_WARN,
17499e39c5baSBill Taylor 				    "hermon_flash_write_byte: ICS write "
17509e39c5baSBill Taylor 				    "timeout: addr: %x, data: %x\n",
17519e39c5baSBill Taylor 				    addr, data);
17529e39c5baSBill Taylor 				hermon_fm_ereport(state, HCA_SYS_ERR,
17539e39c5baSBill Taylor 				    HCA_ERR_IOCTL);
17549e39c5baSBill Taylor 				return (EIO);
17559e39c5baSBill Taylor 			}
17569e39c5baSBill Taylor 			i++;
17579e39c5baSBill Taylor 		} while ((stat & HERMON_HW_FLASH_ICS_READY) == 0);
17589e39c5baSBill Taylor 
17599e39c5baSBill Taylor 		if (stat & HERMON_HW_FLASH_ICS_ERROR) {
17609e39c5baSBill Taylor 			cmn_err(CE_WARN,
17619e39c5baSBill Taylor 			    "hermon_flash_write_byte: ICS write cmd error: "
17629e39c5baSBill Taylor 			    "addr: %x, data: %x\n",
17639e39c5baSBill Taylor 			    addr, data);
17649e39c5baSBill Taylor 			hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
17659e39c5baSBill Taylor 			return (EIO);
17669e39c5baSBill Taylor 		}
17679e39c5baSBill Taylor 		break;
17689e39c5baSBill Taylor 
17699e39c5baSBill Taylor 	case HERMON_FLASH_SPI_CMDSET:
17709e39c5baSBill Taylor 		/*
17719e39c5baSBill Taylor 		 * Our lowest write granularity on SPI is a dword.
17729e39c5baSBill Taylor 		 * To support this ioctl option, we can read in the
17739e39c5baSBill Taylor 		 * dword that contains this byte, modify this byte,
17749e39c5baSBill Taylor 		 * and write the dword back out.
17759e39c5baSBill Taylor 		 */
17769e39c5baSBill Taylor 
17779e39c5baSBill Taylor 		/* Determine dword offset and byte offset within the dword */
17789e39c5baSBill Taylor 		byte_offset = addr & 3;
17799e39c5baSBill Taylor 		dword_addr = addr - byte_offset;
17809e39c5baSBill Taylor #ifdef _LITTLE_ENDIAN
17819e39c5baSBill Taylor 		byte_offset = 3 - byte_offset;
17829e39c5baSBill Taylor #endif
17839e39c5baSBill Taylor 
17849e39c5baSBill Taylor 		/* Read in dword */
17859e39c5baSBill Taylor 		if ((status = hermon_flash_read_quadlet(state, &dword.dword,
17869e39c5baSBill Taylor 		    dword_addr)) != 0)
17879e39c5baSBill Taylor 			break;
17889e39c5baSBill Taylor 
17899e39c5baSBill Taylor 		/* Set "data" to the appopriate byte */
17909e39c5baSBill Taylor 		dword.bytes[byte_offset] = data;
17919e39c5baSBill Taylor 
17929e39c5baSBill Taylor 		/* Write modified dword back out */
17939e39c5baSBill Taylor 		status = hermon_flash_spi_write_dword(state, dword_addr,
17949e39c5baSBill Taylor 		    dword.dword);
17959e39c5baSBill Taylor 
17969e39c5baSBill Taylor 		break;
17979e39c5baSBill Taylor 
17989e39c5baSBill Taylor 	case HERMON_FLASH_UNKNOWN_CMDSET:
17999e39c5baSBill Taylor 	default:
18009e39c5baSBill Taylor 		cmn_err(CE_WARN,
18019e39c5baSBill Taylor 		    "hermon_flash_write_byte: unknown cmd set: 0x%x\n",
18029e39c5baSBill Taylor 		    state->hs_fw_cmdset);
18039e39c5baSBill Taylor 		status = EINVAL;
18049e39c5baSBill Taylor 		break;
18059e39c5baSBill Taylor 	}
18069e39c5baSBill Taylor 
18079e39c5baSBill Taylor 	return (status);
18089e39c5baSBill Taylor }
18099e39c5baSBill Taylor 
18109e39c5baSBill Taylor /*
18119e39c5baSBill Taylor  * hermon_flash_erase_sector()
18129e39c5baSBill Taylor  */
18139e39c5baSBill Taylor static int
hermon_flash_erase_sector(hermon_state_t * state,uint32_t sector_num)18149e39c5baSBill Taylor hermon_flash_erase_sector(hermon_state_t *state, uint32_t sector_num)
18159e39c5baSBill Taylor {
18169e39c5baSBill Taylor 	ddi_acc_handle_t	hdl;
18179e39c5baSBill Taylor 	uint32_t addr;
18189e39c5baSBill Taylor 	uint32_t stat;
18199e39c5baSBill Taylor 	int status = 0;
18209e39c5baSBill Taylor 	int i;
18219e39c5baSBill Taylor 
18229e39c5baSBill Taylor 	/* initialize the FMA retry loop */
18239e39c5baSBill Taylor 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
18249e39c5baSBill Taylor 
18259e39c5baSBill Taylor 	/* Get address from sector num */
18269e39c5baSBill Taylor 	addr = sector_num << state->hs_fw_log_sector_sz;
18279e39c5baSBill Taylor 
18289e39c5baSBill Taylor 	switch (state->hs_fw_cmdset) {
18299e39c5baSBill Taylor 	case HERMON_FLASH_AMD_CMDSET:
18309e39c5baSBill Taylor 		/* Issue Flash Sector Erase Command */
18319e39c5baSBill Taylor 		hermon_flash_write(state, addr, 0xAA, &status);
18329e39c5baSBill Taylor 		if (status != 0) {
18339e39c5baSBill Taylor 			return (status);
18349e39c5baSBill Taylor 		}
18359e39c5baSBill Taylor 
18369e39c5baSBill Taylor 		hermon_flash_write(state, addr, 0x55, &status);
18379e39c5baSBill Taylor 		if (status != 0) {
18389e39c5baSBill Taylor 			return (status);
18399e39c5baSBill Taylor 		}
18409e39c5baSBill Taylor 
18419e39c5baSBill Taylor 		hermon_flash_write(state, addr, 0x80, &status);
18429e39c5baSBill Taylor 		if (status != 0) {
18439e39c5baSBill Taylor 			return (status);
18449e39c5baSBill Taylor 		}
18459e39c5baSBill Taylor 
18469e39c5baSBill Taylor 		hermon_flash_write(state, addr, 0xAA, &status);
18479e39c5baSBill Taylor 		if (status != 0) {
18489e39c5baSBill Taylor 			return (status);
18499e39c5baSBill Taylor 		}
18509e39c5baSBill Taylor 
18519e39c5baSBill Taylor 		hermon_flash_write(state, addr, 0x55, &status);
18529e39c5baSBill Taylor 		if (status != 0) {
18539e39c5baSBill Taylor 			return (status);
18549e39c5baSBill Taylor 		}
18559e39c5baSBill Taylor 
18569e39c5baSBill Taylor 		hermon_flash_write(state, addr, 0x30, &status);
18579e39c5baSBill Taylor 		if (status != 0) {
18589e39c5baSBill Taylor 			return (status);
18599e39c5baSBill Taylor 		}
18609e39c5baSBill Taylor 
18619e39c5baSBill Taylor 		/* Wait for Sector Erase to complete */
18629e39c5baSBill Taylor 		i = 0;
18639e39c5baSBill Taylor 		do {
18649e39c5baSBill Taylor 			drv_usecwait(1);
18659e39c5baSBill Taylor 			stat = hermon_flash_read(state, addr, &status);
18669e39c5baSBill Taylor 			if (status != 0) {
18679e39c5baSBill Taylor 				return (status);
18689e39c5baSBill Taylor 			}
18699e39c5baSBill Taylor 
18709e39c5baSBill Taylor 			if (i == hermon_hw_flash_timeout_erase) {
18719e39c5baSBill Taylor 				cmn_err(CE_WARN,
18729e39c5baSBill Taylor 				    "hermon_flash_erase_sector: "
18739e39c5baSBill Taylor 				    "ACS erase timeout\n");
18749e39c5baSBill Taylor 				hermon_fm_ereport(state, HCA_SYS_ERR,
18759e39c5baSBill Taylor 				    HCA_ERR_IOCTL);
18769e39c5baSBill Taylor 				return (EIO);
18779e39c5baSBill Taylor 			}
18789e39c5baSBill Taylor 			i++;
18799e39c5baSBill Taylor 		} while (stat != 0xFFFFFFFF);
18809e39c5baSBill Taylor 		break;
18819e39c5baSBill Taylor 
18829e39c5baSBill Taylor 	case HERMON_FLASH_INTEL_CMDSET:
18839e39c5baSBill Taylor 		/* Issue Flash Sector Erase Command */
18849e39c5baSBill Taylor 		hermon_flash_write(state, addr, HERMON_HW_FLASH_ICS_ERASE,
18859e39c5baSBill Taylor 		    &status);
18869e39c5baSBill Taylor 		if (status != 0) {
18879e39c5baSBill Taylor 			return (status);
18889e39c5baSBill Taylor 		}
18899e39c5baSBill Taylor 
18909e39c5baSBill Taylor 		hermon_flash_write(state, addr, HERMON_HW_FLASH_ICS_CONFIRM,
18919e39c5baSBill Taylor 		    &status);
18929e39c5baSBill Taylor 		if (status != 0) {
18939e39c5baSBill Taylor 			return (status);
18949e39c5baSBill Taylor 		}
18959e39c5baSBill Taylor 
18969e39c5baSBill Taylor 		/* Wait for Sector Erase to complete */
18979e39c5baSBill Taylor 		i = 0;
18989e39c5baSBill Taylor 		do {
18999e39c5baSBill Taylor 			drv_usecwait(1);
19009e39c5baSBill Taylor 			stat = hermon_flash_read(state, addr & ~3, &status);
19019e39c5baSBill Taylor 			if (status != 0) {
19029e39c5baSBill Taylor 				return (status);
19039e39c5baSBill Taylor 			}
19049e39c5baSBill Taylor 
19059e39c5baSBill Taylor 			if (i == hermon_hw_flash_timeout_erase) {
19069e39c5baSBill Taylor 				cmn_err(CE_WARN,
19079e39c5baSBill Taylor 				    "hermon_flash_erase_sector: "
19089e39c5baSBill Taylor 				    "ICS erase timeout\n");
19099e39c5baSBill Taylor 				hermon_fm_ereport(state, HCA_SYS_ERR,
19109e39c5baSBill Taylor 				    HCA_ERR_IOCTL);
19119e39c5baSBill Taylor 				return (EIO);
19129e39c5baSBill Taylor 			}
19139e39c5baSBill Taylor 			i++;
19149e39c5baSBill Taylor 		} while ((stat & HERMON_HW_FLASH_ICS_READY) == 0);
19159e39c5baSBill Taylor 
19169e39c5baSBill Taylor 		if (stat & HERMON_HW_FLASH_ICS_ERROR) {
19179e39c5baSBill Taylor 			cmn_err(CE_WARN,
19189e39c5baSBill Taylor 			    "hermon_flash_erase_sector: "
19199e39c5baSBill Taylor 			    "ICS erase cmd error\n");
19209e39c5baSBill Taylor 			hermon_fm_ereport(state, HCA_SYS_ERR,
19219e39c5baSBill Taylor 			    HCA_ERR_IOCTL);
19229e39c5baSBill Taylor 			return (EIO);
19239e39c5baSBill Taylor 		}
19249e39c5baSBill Taylor 		break;
19259e39c5baSBill Taylor 
19269e39c5baSBill Taylor 	case HERMON_FLASH_SPI_CMDSET:
19279e39c5baSBill Taylor 		hdl = hermon_get_pcihdl(state);
19289e39c5baSBill Taylor 
19299e39c5baSBill Taylor 		/* the FMA retry loop starts. */
19309e39c5baSBill Taylor 		hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status,
19319e39c5baSBill Taylor 		    fm_test);
19329e39c5baSBill Taylor 
19339e39c5baSBill Taylor 		/* Issue Write Enable */
19349e39c5baSBill Taylor 		hermon_flash_spi_write_enable(state);
19359e39c5baSBill Taylor 
19369e39c5baSBill Taylor 		/* Set the Address */
19379e39c5baSBill Taylor 		hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_SPI_ADDR,
19389e39c5baSBill Taylor 		    addr & HERMON_HW_FLASH_SPI_ADDR_MASK);
19399e39c5baSBill Taylor 
19409e39c5baSBill Taylor 		/* Issue Flash Sector Erase */
19419e39c5baSBill Taylor 		hermon_flash_spi_exec_command(state, hdl,
19429e39c5baSBill Taylor 		    HERMON_HW_FLASH_SPI_INSTR_PHASE_OFF |
19439e39c5baSBill Taylor 		    HERMON_HW_FLASH_SPI_ADDR_PHASE_OFF |
19449e39c5baSBill Taylor 		    ((uint32_t)(HERMON_HW_FLASH_SPI_SECTOR_ERASE) <<
19459e39c5baSBill Taylor 		    HERMON_HW_FLASH_SPI_INSTR_SHIFT));
19469e39c5baSBill Taylor 
19479e39c5baSBill Taylor 		/* the FMA retry loop ends. */
19489e39c5baSBill Taylor 		hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status,
19499e39c5baSBill Taylor 		    fm_test);
19509e39c5baSBill Taylor 
19519e39c5baSBill Taylor 		/* Wait for Sector Erase to complete */
19529e39c5baSBill Taylor 		status = hermon_flash_spi_wait_wip(state);
19539e39c5baSBill Taylor 		break;
19549e39c5baSBill Taylor 
19559e39c5baSBill Taylor 	case HERMON_FLASH_UNKNOWN_CMDSET:
19569e39c5baSBill Taylor 	default:
19579e39c5baSBill Taylor 		cmn_err(CE_WARN,
19589e39c5baSBill Taylor 		    "hermon_flash_erase_sector: unknown cmd set: 0x%x\n",
19599e39c5baSBill Taylor 		    state->hs_fw_cmdset);
19609e39c5baSBill Taylor 		status = EINVAL;
19619e39c5baSBill Taylor 		break;
19629e39c5baSBill Taylor 	}
19639e39c5baSBill Taylor 
19649e39c5baSBill Taylor 	/* Reset the flash device */
19659e39c5baSBill Taylor 	if (status == 0) {
19669e39c5baSBill Taylor 		status = hermon_flash_reset(state);
19679e39c5baSBill Taylor 	}
19689e39c5baSBill Taylor 	return (status);
19699e39c5baSBill Taylor 
19709e39c5baSBill Taylor pio_error:
19719e39c5baSBill Taylor 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
19729e39c5baSBill Taylor 	return (EIO);
19739e39c5baSBill Taylor }
19749e39c5baSBill Taylor 
19759e39c5baSBill Taylor /*
19769e39c5baSBill Taylor  * hermon_flash_erase_chip()
19779e39c5baSBill Taylor  */
19789e39c5baSBill Taylor static int
hermon_flash_erase_chip(hermon_state_t * state)19799e39c5baSBill Taylor hermon_flash_erase_chip(hermon_state_t *state)
19809e39c5baSBill Taylor {
19819e39c5baSBill Taylor 	uint32_t stat;
19829e39c5baSBill Taylor 	uint_t size;
19839e39c5baSBill Taylor 	int status = 0;
19849e39c5baSBill Taylor 	int i;
19859e39c5baSBill Taylor 	int num_sect;
19869e39c5baSBill Taylor 
19879e39c5baSBill Taylor 	switch (state->hs_fw_cmdset) {
19889e39c5baSBill Taylor 	case HERMON_FLASH_AMD_CMDSET:
19899e39c5baSBill Taylor 		/* Issue Flash Chip Erase Command */
19909e39c5baSBill Taylor 		hermon_flash_write(state, 0, 0xAA, &status);
19919e39c5baSBill Taylor 		if (status != 0) {
19929e39c5baSBill Taylor 			return (status);
19939e39c5baSBill Taylor 		}
19949e39c5baSBill Taylor 
19959e39c5baSBill Taylor 		hermon_flash_write(state, 0, 0x55, &status);
19969e39c5baSBill Taylor 		if (status != 0) {
19979e39c5baSBill Taylor 			return (status);
19989e39c5baSBill Taylor 		}
19999e39c5baSBill Taylor 
20009e39c5baSBill Taylor 		hermon_flash_write(state, 0, 0x80, &status);
20019e39c5baSBill Taylor 		if (status != 0) {
20029e39c5baSBill Taylor 			return (status);
20039e39c5baSBill Taylor 		}
20049e39c5baSBill Taylor 
20059e39c5baSBill Taylor 		hermon_flash_write(state, 0, 0xAA, &status);
20069e39c5baSBill Taylor 		if (status != 0) {
20079e39c5baSBill Taylor 			return (status);
20089e39c5baSBill Taylor 		}
20099e39c5baSBill Taylor 
20109e39c5baSBill Taylor 		hermon_flash_write(state, 0, 0x55, &status);
20119e39c5baSBill Taylor 		if (status != 0) {
20129e39c5baSBill Taylor 			return (status);
20139e39c5baSBill Taylor 		}
20149e39c5baSBill Taylor 
20159e39c5baSBill Taylor 		hermon_flash_write(state, 0, 0x10, &status);
20169e39c5baSBill Taylor 		if (status != 0) {
20179e39c5baSBill Taylor 			return (status);
20189e39c5baSBill Taylor 		}
20199e39c5baSBill Taylor 
20209e39c5baSBill Taylor 		/* Wait for Chip Erase to Complete */
20219e39c5baSBill Taylor 		i = 0;
20229e39c5baSBill Taylor 		do {
20239e39c5baSBill Taylor 			drv_usecwait(1);
20249e39c5baSBill Taylor 			stat = hermon_flash_read(state, 0, &status);
20259e39c5baSBill Taylor 			if (status != 0) {
20269e39c5baSBill Taylor 				return (status);
20279e39c5baSBill Taylor 			}
20289e39c5baSBill Taylor 
20299e39c5baSBill Taylor 			if (i == hermon_hw_flash_timeout_erase) {
20309e39c5baSBill Taylor 				cmn_err(CE_WARN,
20319e39c5baSBill Taylor 				    "hermon_flash_erase_chip: erase timeout\n");
20329e39c5baSBill Taylor 				hermon_fm_ereport(state, HCA_SYS_ERR,
20339e39c5baSBill Taylor 				    HCA_ERR_IOCTL);
20349e39c5baSBill Taylor 				return (EIO);
20359e39c5baSBill Taylor 			}
20369e39c5baSBill Taylor 			i++;
20379e39c5baSBill Taylor 		} while (stat != 0xFFFFFFFF);
20389e39c5baSBill Taylor 		break;
20399e39c5baSBill Taylor 
20409e39c5baSBill Taylor 	case HERMON_FLASH_INTEL_CMDSET:
20419e39c5baSBill Taylor 	case HERMON_FLASH_SPI_CMDSET:
20429e39c5baSBill Taylor 		/*
20439e39c5baSBill Taylor 		 * These chips don't have a chip erase command, so erase
20449e39c5baSBill Taylor 		 * all blocks one at a time.
20459e39c5baSBill Taylor 		 */
20469e39c5baSBill Taylor 		size = (0x1 << state->hs_fw_log_sector_sz);
20479e39c5baSBill Taylor 		num_sect = state->hs_fw_device_sz / size;
20489e39c5baSBill Taylor 
20499e39c5baSBill Taylor 		for (i = 0; i < num_sect; i++) {
20509e39c5baSBill Taylor 			status = hermon_flash_erase_sector(state, i);
20519e39c5baSBill Taylor 			if (status != 0) {
20529e39c5baSBill Taylor 				cmn_err(CE_WARN,
20539e39c5baSBill Taylor 				    "hermon_flash_erase_chip: "
20549e39c5baSBill Taylor 				    "sector %d erase error\n", i);
20559e39c5baSBill Taylor 				return (status);
20569e39c5baSBill Taylor 			}
20579e39c5baSBill Taylor 		}
20589e39c5baSBill Taylor 		break;
20599e39c5baSBill Taylor 
20609e39c5baSBill Taylor 	case HERMON_FLASH_UNKNOWN_CMDSET:
20619e39c5baSBill Taylor 	default:
20629e39c5baSBill Taylor 		cmn_err(CE_WARN, "hermon_flash_erase_chip: "
20639e39c5baSBill Taylor 		    "unknown cmd set: 0x%x\n", state->hs_fw_cmdset);
20649e39c5baSBill Taylor 		status = EINVAL;
20659e39c5baSBill Taylor 		break;
20669e39c5baSBill Taylor 	}
20679e39c5baSBill Taylor 
20689e39c5baSBill Taylor 	return (status);
20699e39c5baSBill Taylor }
20709e39c5baSBill Taylor 
20719e39c5baSBill Taylor /*
20729e39c5baSBill Taylor  * hermon_flash_spi_write_enable()
20739e39c5baSBill Taylor  */
20749e39c5baSBill Taylor static void
hermon_flash_spi_write_enable(hermon_state_t * state)20759e39c5baSBill Taylor hermon_flash_spi_write_enable(hermon_state_t *state)
20769e39c5baSBill Taylor {
20779e39c5baSBill Taylor 	ddi_acc_handle_t	hdl;
20789e39c5baSBill Taylor 
20799e39c5baSBill Taylor 	hdl = hermon_get_pcihdl(state);
20809e39c5baSBill Taylor 
20819e39c5baSBill Taylor 	hermon_flash_spi_exec_command(state, hdl,
20829e39c5baSBill Taylor 	    HERMON_HW_FLASH_SPI_INSTR_PHASE_OFF |
20839e39c5baSBill Taylor 	    (HERMON_HW_FLASH_SPI_WRITE_ENABLE <<
20849e39c5baSBill Taylor 	    HERMON_HW_FLASH_SPI_INSTR_SHIFT));
20859e39c5baSBill Taylor }
20869e39c5baSBill Taylor 
20879e39c5baSBill Taylor /*
20889e39c5baSBill Taylor  * hermon_flash_spi_wait_wip()
20899e39c5baSBill Taylor  */
20909e39c5baSBill Taylor static int
hermon_flash_spi_wait_wip(hermon_state_t * state)20919e39c5baSBill Taylor hermon_flash_spi_wait_wip(hermon_state_t *state)
20929e39c5baSBill Taylor {
20939e39c5baSBill Taylor 	ddi_acc_handle_t	hdl;
20949e39c5baSBill Taylor 	uint32_t		status;
20959e39c5baSBill Taylor 
20969e39c5baSBill Taylor 	/* initialize the FMA retry loop */
20979e39c5baSBill Taylor 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
20989e39c5baSBill Taylor 
20999e39c5baSBill Taylor 	hdl = hermon_get_pcihdl(state);
21009e39c5baSBill Taylor 
21019e39c5baSBill Taylor 	/* the FMA retry loop starts. */
21029e39c5baSBill Taylor 	hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status,
21039e39c5baSBill Taylor 	    fm_test);
21049e39c5baSBill Taylor 
21059e39c5baSBill Taylor 	/* wait on the gateway to clear busy */
21069e39c5baSBill Taylor 	do {
21079e39c5baSBill Taylor 		status = hermon_flash_read_cfg(state, hdl,
21089e39c5baSBill Taylor 		    HERMON_HW_FLASH_SPI_GW);
21099e39c5baSBill Taylor 	} while (status & HERMON_HW_FLASH_SPI_BUSY);
21109e39c5baSBill Taylor 
21119e39c5baSBill Taylor 	/* now, get the status and check for WIP to clear */
21129e39c5baSBill Taylor 	do {
21139e39c5baSBill Taylor 		hermon_flash_spi_exec_command(state, hdl,
21149e39c5baSBill Taylor 		    HERMON_HW_FLASH_SPI_READ_OP |
21159e39c5baSBill Taylor 		    HERMON_HW_FLASH_SPI_INSTR_PHASE_OFF |
21169e39c5baSBill Taylor 		    HERMON_HW_FLASH_SPI_DATA_PHASE_OFF |
21179e39c5baSBill Taylor 		    HERMON_HW_FLASH_SPI_TRANS_SZ_4B |
21189e39c5baSBill Taylor 		    (HERMON_HW_FLASH_SPI_READ_STATUS_REG <<
21199e39c5baSBill Taylor 		    HERMON_HW_FLASH_SPI_INSTR_SHIFT));
21209e39c5baSBill Taylor 
21219e39c5baSBill Taylor 		status = hermon_flash_read_cfg(state, hdl,
21229e39c5baSBill Taylor 		    HERMON_HW_FLASH_SPI_DATA);
21239e39c5baSBill Taylor 	} while (status & HERMON_HW_FLASH_SPI_WIP);
21249e39c5baSBill Taylor 
21259e39c5baSBill Taylor 	/* the FMA retry loop ends. */
21269e39c5baSBill Taylor 	hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status, fm_test);
21279e39c5baSBill Taylor 	return (0);
21289e39c5baSBill Taylor 
21299e39c5baSBill Taylor pio_error:
21309e39c5baSBill Taylor 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
21319e39c5baSBill Taylor 	return (EIO);
21329e39c5baSBill Taylor }
21339e39c5baSBill Taylor 
21349e39c5baSBill Taylor /*
21359e39c5baSBill Taylor  * hermon_flash_bank()
21369e39c5baSBill Taylor  */
21379e39c5baSBill Taylor static int
hermon_flash_bank(hermon_state_t * state,uint32_t addr)21389e39c5baSBill Taylor hermon_flash_bank(hermon_state_t *state, uint32_t addr)
21399e39c5baSBill Taylor {
21409e39c5baSBill Taylor 	ddi_acc_handle_t	hdl;
21419e39c5baSBill Taylor 	uint32_t		bank;
21429e39c5baSBill Taylor 
21439e39c5baSBill Taylor 	/* initialize the FMA retry loop */
21449e39c5baSBill Taylor 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
21459e39c5baSBill Taylor 
21469e39c5baSBill Taylor 	/* Set handle */
21479e39c5baSBill Taylor 	hdl = hermon_get_pcihdl(state);
21489e39c5baSBill Taylor 
21499e39c5baSBill Taylor 	/* Determine the bank setting from the address */
21509e39c5baSBill Taylor 	bank = addr & HERMON_HW_FLASH_BANK_MASK;
21519e39c5baSBill Taylor 
21529e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(state->hs_fw_flashbank))
21539e39c5baSBill Taylor 
21549e39c5baSBill Taylor 	/*
21559e39c5baSBill Taylor 	 * If the bank is different from the currently set bank, we need to
21569e39c5baSBill Taylor 	 * change it.  Also, if an 'addr' of 0 is given, this allows the
21579e39c5baSBill Taylor 	 * capability to force the flash bank to 0.  This is useful at init
21589e39c5baSBill Taylor 	 * time to initially set the bank value
21599e39c5baSBill Taylor 	 */
21609e39c5baSBill Taylor 	if (state->hs_fw_flashbank != bank || addr == 0) {
21619e39c5baSBill Taylor 		switch (state->hs_fw_cmdset) {
21629e39c5baSBill Taylor 		case HERMON_FLASH_SPI_CMDSET:
21639e39c5baSBill Taylor 			/* CMJ: not needed for hermon */
21649e39c5baSBill Taylor 			break;
21659e39c5baSBill Taylor 
21669e39c5baSBill Taylor 		case HERMON_FLASH_INTEL_CMDSET:
21679e39c5baSBill Taylor 		case HERMON_FLASH_AMD_CMDSET:
21689e39c5baSBill Taylor 			/* the FMA retry loop starts. */
21699e39c5baSBill Taylor 			hermon_pio_start(state, hdl, pio_error, fm_loop_cnt,
21709e39c5baSBill Taylor 			    fm_status, fm_test);
21719e39c5baSBill Taylor 
21729e39c5baSBill Taylor 			hermon_flash_write_cfg(state, hdl,
21739e39c5baSBill Taylor 			    HERMON_HW_FLASH_GPIO_DATACLEAR, 0x70);
21749e39c5baSBill Taylor 			hermon_flash_write_cfg(state, hdl,
21759e39c5baSBill Taylor 			    HERMON_HW_FLASH_GPIO_DATASET, (bank >> 15) & 0x70);
21769e39c5baSBill Taylor 
21779e39c5baSBill Taylor 			/* the FMA retry loop ends. */
21789e39c5baSBill Taylor 			hermon_pio_end(state, hdl, pio_error, fm_loop_cnt,
21799e39c5baSBill Taylor 			    fm_status, fm_test);
21809e39c5baSBill Taylor 			break;
21819e39c5baSBill Taylor 
21829e39c5baSBill Taylor 		case HERMON_FLASH_UNKNOWN_CMDSET:
21839e39c5baSBill Taylor 		default:
21849e39c5baSBill Taylor 			return (EINVAL);
21859e39c5baSBill Taylor 		}
21869e39c5baSBill Taylor 
21879e39c5baSBill Taylor 		state->hs_fw_flashbank = bank;
21889e39c5baSBill Taylor 	}
21899e39c5baSBill Taylor 	return (0);
21909e39c5baSBill Taylor 
21919e39c5baSBill Taylor pio_error:
21929e39c5baSBill Taylor 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
21939e39c5baSBill Taylor 	return (EIO);
21949e39c5baSBill Taylor }
21959e39c5baSBill Taylor 
21969e39c5baSBill Taylor /*
21979e39c5baSBill Taylor  * hermon_flash_spi_exec_command()
21989e39c5baSBill Taylor  */
21999e39c5baSBill Taylor static void
hermon_flash_spi_exec_command(hermon_state_t * state,ddi_acc_handle_t hdl,uint32_t cmd)22009e39c5baSBill Taylor hermon_flash_spi_exec_command(hermon_state_t *state, ddi_acc_handle_t hdl,
22019e39c5baSBill Taylor     uint32_t cmd)
22029e39c5baSBill Taylor {
22039e39c5baSBill Taylor 	uint32_t data;
22049e39c5baSBill Taylor 	int timeout = 0;
22059e39c5baSBill Taylor 
22069e39c5baSBill Taylor 	cmd |= HERMON_HW_FLASH_SPI_BUSY | HERMON_HW_FLASH_SPI_ENABLE_OFF;
22079e39c5baSBill Taylor 
22089e39c5baSBill Taylor 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_SPI_GW, cmd);
22099e39c5baSBill Taylor 
22109e39c5baSBill Taylor 	do {
22119e39c5baSBill Taylor 		data = hermon_flash_read_cfg(state, hdl,
22129e39c5baSBill Taylor 		    HERMON_HW_FLASH_SPI_GW);
22139e39c5baSBill Taylor 		timeout++;
22149e39c5baSBill Taylor 	} while ((data & HERMON_HW_FLASH_SPI_BUSY) &&
22159e39c5baSBill Taylor 	    (timeout < hermon_hw_flash_timeout_config));
22169e39c5baSBill Taylor }
22179e39c5baSBill Taylor 
22189e39c5baSBill Taylor /*
22199e39c5baSBill Taylor  * hermon_flash_read()
22209e39c5baSBill Taylor  */
22219e39c5baSBill Taylor static uint32_t
hermon_flash_read(hermon_state_t * state,uint32_t addr,int * err)22229e39c5baSBill Taylor hermon_flash_read(hermon_state_t *state, uint32_t addr, int *err)
22239e39c5baSBill Taylor {
22249e39c5baSBill Taylor 	ddi_acc_handle_t	hdl;
22259e39c5baSBill Taylor 	uint32_t		data = 0;
22269e39c5baSBill Taylor 	int			timeout, status = 0;
22279e39c5baSBill Taylor 
22289e39c5baSBill Taylor 	/* initialize the FMA retry loop */
22299e39c5baSBill Taylor 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
22309e39c5baSBill Taylor 
22319e39c5baSBill Taylor 	hdl = hermon_get_pcihdl(state);
22329e39c5baSBill Taylor 
22339e39c5baSBill Taylor 	/* the FMA retry loop starts. */
22349e39c5baSBill Taylor 	hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status,
22359e39c5baSBill Taylor 	    fm_test);
22369e39c5baSBill Taylor 
22379e39c5baSBill Taylor 	switch (state->hs_fw_cmdset) {
22389e39c5baSBill Taylor 	case HERMON_FLASH_SPI_CMDSET:
22399e39c5baSBill Taylor 		/* Set the transaction address */
22409e39c5baSBill Taylor 		hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_SPI_ADDR,
22419e39c5baSBill Taylor 		    (addr & HERMON_HW_FLASH_SPI_ADDR_MASK));
22429e39c5baSBill Taylor 
22439e39c5baSBill Taylor 		hermon_flash_spi_exec_command(state, hdl,
22449e39c5baSBill Taylor 		    HERMON_HW_FLASH_SPI_READ_OP |
22459e39c5baSBill Taylor 		    HERMON_HW_FLASH_SPI_INSTR_PHASE_OFF |
22469e39c5baSBill Taylor 		    HERMON_HW_FLASH_SPI_ADDR_PHASE_OFF |
22479e39c5baSBill Taylor 		    HERMON_HW_FLASH_SPI_DATA_PHASE_OFF |
22489e39c5baSBill Taylor 		    HERMON_HW_FLASH_SPI_TRANS_SZ_4B |
22499e39c5baSBill Taylor 		    (HERMON_HW_FLASH_SPI_READ <<
22509e39c5baSBill Taylor 		    HERMON_HW_FLASH_SPI_INSTR_SHIFT));
22519e39c5baSBill Taylor 
22529e39c5baSBill Taylor 		data = hermon_flash_read_cfg(state, hdl,
22539e39c5baSBill Taylor 		    HERMON_HW_FLASH_SPI_DATA);
22549e39c5baSBill Taylor 		break;
22559e39c5baSBill Taylor 
22569e39c5baSBill Taylor 	case HERMON_FLASH_INTEL_CMDSET:
22579e39c5baSBill Taylor 	case HERMON_FLASH_AMD_CMDSET:
22589e39c5baSBill Taylor 		/*
22599e39c5baSBill Taylor 		 * The Read operation does the following:
22609e39c5baSBill Taylor 		 *   1) Write the masked address to the HERMON_FLASH_ADDR
22619e39c5baSBill Taylor 		 *	register. Only the least significant 19 bits are valid.
22629e39c5baSBill Taylor 		 *   2) Read back the register until the command has completed.
22639e39c5baSBill Taylor 		 *   3) Read the data retrieved from the address at the
22649e39c5baSBill Taylor 		 *	HERMON_FLASH_DATA register.
22659e39c5baSBill Taylor 		 */
22669e39c5baSBill Taylor 		hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_ADDR,
22679e39c5baSBill Taylor 		    (addr & HERMON_HW_FLASH_ADDR_MASK) | (1 << 29));
22689e39c5baSBill Taylor 
22699e39c5baSBill Taylor 		timeout = 0;
22709e39c5baSBill Taylor 		do {
22719e39c5baSBill Taylor 			data = hermon_flash_read_cfg(state, hdl,
22729e39c5baSBill Taylor 			    HERMON_HW_FLASH_ADDR);
22739e39c5baSBill Taylor 			timeout++;
22749e39c5baSBill Taylor 		} while ((data & HERMON_HW_FLASH_CMD_MASK) &&
22759e39c5baSBill Taylor 		    (timeout < hermon_hw_flash_timeout_config));
22769e39c5baSBill Taylor 
227726190627SShantkumar Hiremath 		if (timeout == hermon_hw_flash_timeout_config) {
227826190627SShantkumar Hiremath 			cmn_err(CE_WARN, "hermon_flash_read: command timed "
227926190627SShantkumar Hiremath 			    "out.\n");
228026190627SShantkumar Hiremath 			*err = EIO;
228126190627SShantkumar Hiremath 			hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
228226190627SShantkumar Hiremath 			return (data);
228326190627SShantkumar Hiremath 		}
228426190627SShantkumar Hiremath 
22859e39c5baSBill Taylor 		data = hermon_flash_read_cfg(state, hdl, HERMON_HW_FLASH_DATA);
22869e39c5baSBill Taylor 		break;
22879e39c5baSBill Taylor 
22889e39c5baSBill Taylor 	case HERMON_FLASH_UNKNOWN_CMDSET:
22899e39c5baSBill Taylor 	default:
22909e39c5baSBill Taylor 		cmn_err(CE_CONT, "hermon_flash_read: unknown cmdset: 0x%x\n",
22919e39c5baSBill Taylor 		    state->hs_fw_cmdset);
22929e39c5baSBill Taylor 		status = EINVAL;
22939e39c5baSBill Taylor 		break;
22949e39c5baSBill Taylor 	}
22959e39c5baSBill Taylor 
22969e39c5baSBill Taylor 
22979e39c5baSBill Taylor 	/* the FMA retry loop ends. */
22989e39c5baSBill Taylor 	hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status, fm_test);
22999e39c5baSBill Taylor 	*err = status;
23009e39c5baSBill Taylor 	return (data);
23019e39c5baSBill Taylor 
23029e39c5baSBill Taylor pio_error:
23039e39c5baSBill Taylor 	*err = EIO;
23049e39c5baSBill Taylor 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
23059e39c5baSBill Taylor 	return (data);
23069e39c5baSBill Taylor }
23079e39c5baSBill Taylor 
23089e39c5baSBill Taylor /*
23099e39c5baSBill Taylor  * hermon_flash_write()
23109e39c5baSBill Taylor  */
23119e39c5baSBill Taylor static void
hermon_flash_write(hermon_state_t * state,uint32_t addr,uchar_t data,int * err)23129e39c5baSBill Taylor hermon_flash_write(hermon_state_t *state, uint32_t addr, uchar_t data, int *err)
23139e39c5baSBill Taylor {
23149e39c5baSBill Taylor 	ddi_acc_handle_t	hdl;
23159e39c5baSBill Taylor 	int			cmd;
23169e39c5baSBill Taylor 	int			timeout;
23179e39c5baSBill Taylor 
23189e39c5baSBill Taylor 	/* initialize the FMA retry loop */
23199e39c5baSBill Taylor 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
23209e39c5baSBill Taylor 
23219e39c5baSBill Taylor 	hdl = hermon_get_pcihdl(state);
23229e39c5baSBill Taylor 
23239e39c5baSBill Taylor 	/* the FMA retry loop starts. */
23249e39c5baSBill Taylor 	hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status,
23259e39c5baSBill Taylor 	    fm_test);
23269e39c5baSBill Taylor 
23279e39c5baSBill Taylor 	/*
23289e39c5baSBill Taylor 	 * The Write operation does the following:
23299e39c5baSBill Taylor 	 *   1) Write the data to be written to the HERMON_FLASH_DATA offset.
23309e39c5baSBill Taylor 	 *   2) Write the address to write the data to to the HERMON_FLASH_ADDR
23319e39c5baSBill Taylor 	 *	offset.
23329e39c5baSBill Taylor 	 *   3) Wait until the write completes.
23339e39c5baSBill Taylor 	 */
23349e39c5baSBill Taylor 
23359e39c5baSBill Taylor 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_DATA, data << 24);
23369e39c5baSBill Taylor 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_ADDR,
23379e39c5baSBill Taylor 	    (addr & 0x7FFFF) | (2 << 29));
23389e39c5baSBill Taylor 
23399e39c5baSBill Taylor 	timeout = 0;
23409e39c5baSBill Taylor 	do {
23419e39c5baSBill Taylor 		cmd = hermon_flash_read_cfg(state, hdl, HERMON_HW_FLASH_ADDR);
23429e39c5baSBill Taylor 		timeout++;
23439e39c5baSBill Taylor 	} while ((cmd & HERMON_HW_FLASH_CMD_MASK) &&
23449e39c5baSBill Taylor 	    (timeout < hermon_hw_flash_timeout_config));
23459e39c5baSBill Taylor 
23469e39c5baSBill Taylor 	if (timeout == hermon_hw_flash_timeout_config) {
23479e39c5baSBill Taylor 		cmn_err(CE_WARN, "hermon_flash_write: config cmd timeout.\n");
23489e39c5baSBill Taylor 		*err = EIO;
23499e39c5baSBill Taylor 		hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
23509e39c5baSBill Taylor 		return;
23519e39c5baSBill Taylor 	}
23529e39c5baSBill Taylor 
23539e39c5baSBill Taylor 	/* the FMA retry loop ends. */
23549e39c5baSBill Taylor 	hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status, fm_test);
23559e39c5baSBill Taylor 	*err = 0;
23569e39c5baSBill Taylor 	return;
23579e39c5baSBill Taylor 
23589e39c5baSBill Taylor pio_error:
23599e39c5baSBill Taylor 	*err = EIO;
23609e39c5baSBill Taylor 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
23619e39c5baSBill Taylor }
23629e39c5baSBill Taylor 
23639e39c5baSBill Taylor /*
23649e39c5baSBill Taylor  * hermon_flash_init()
23659e39c5baSBill Taylor  */
23669e39c5baSBill Taylor static int
hermon_flash_init(hermon_state_t * state)23679e39c5baSBill Taylor hermon_flash_init(hermon_state_t *state)
23689e39c5baSBill Taylor {
23699e39c5baSBill Taylor 	uint32_t		word;
23709e39c5baSBill Taylor 	ddi_acc_handle_t	hdl;
23719e39c5baSBill Taylor 	int			sema_cnt;
23729e39c5baSBill Taylor 	int			gpio;
23739e39c5baSBill Taylor 
23749e39c5baSBill Taylor 	/* initialize the FMA retry loop */
23759e39c5baSBill Taylor 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
23769e39c5baSBill Taylor 
23779e39c5baSBill Taylor 	/* Set handle */
23789e39c5baSBill Taylor 	hdl = hermon_get_pcihdl(state);
23799e39c5baSBill Taylor 
23809e39c5baSBill Taylor 	/* the FMA retry loop starts. */
23819e39c5baSBill Taylor 	hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status,
23829e39c5baSBill Taylor 	    fm_test);
23839e39c5baSBill Taylor 
23849e39c5baSBill Taylor 	/* Init the flash */
23859e39c5baSBill Taylor 
23869e39c5baSBill Taylor #ifdef DO_WRCONF
23879e39c5baSBill Taylor 	/*
23889e39c5baSBill Taylor 	 * Grab the WRCONF semaphore.
23899e39c5baSBill Taylor 	 */
23909e39c5baSBill Taylor 	word = hermon_flash_read_cfg(state, hdl, HERMON_HW_FLASH_WRCONF_SEMA);
23919e39c5baSBill Taylor #endif
23929e39c5baSBill Taylor 
23939e39c5baSBill Taylor 	/*
23949e39c5baSBill Taylor 	 * Grab the GPIO semaphore.  This allows us exclusive access to the
23959e39c5baSBill Taylor 	 * GPIO settings on the Hermon for the duration of the flash burning
23969e39c5baSBill Taylor 	 * procedure.
23979e39c5baSBill Taylor 	 */
23989e39c5baSBill Taylor 	sema_cnt = 0;
23999e39c5baSBill Taylor 	do {
24009e39c5baSBill Taylor 		word = hermon_flash_read_cfg(state, hdl,
24019e39c5baSBill Taylor 		    HERMON_HW_FLASH_GPIO_SEMA);
24029e39c5baSBill Taylor 		if (word == 0) {
24039e39c5baSBill Taylor 			break;
24049e39c5baSBill Taylor 		}
24059e39c5baSBill Taylor 
24069e39c5baSBill Taylor 		sema_cnt++;
24079e39c5baSBill Taylor 		drv_usecwait(1);
24089e39c5baSBill Taylor 
24099e39c5baSBill Taylor 	} while (sema_cnt < hermon_hw_flash_timeout_gpio_sema);
24109e39c5baSBill Taylor 
24119e39c5baSBill Taylor 	/*
24129e39c5baSBill Taylor 	 * Determine if we timed out trying to grab the GPIO semaphore
24139e39c5baSBill Taylor 	 */
24149e39c5baSBill Taylor 	if (sema_cnt == hermon_hw_flash_timeout_gpio_sema) {
24159e39c5baSBill Taylor 		cmn_err(CE_WARN, "hermon_flash_init: GPIO SEMA timeout\n");
24169e39c5baSBill Taylor 		cmn_err(CE_WARN, "GPIO_SEMA value: 0x%x\n", word);
24179e39c5baSBill Taylor 		hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
24189e39c5baSBill Taylor 		return (EIO);
24199e39c5baSBill Taylor 	}
24209e39c5baSBill Taylor 
24219e39c5baSBill Taylor 	/* Save away original GPIO Values */
24229e39c5baSBill Taylor 	state->hs_fw_gpio[0] = hermon_flash_read_cfg(state, hdl,
24239e39c5baSBill Taylor 	    HERMON_HW_FLASH_GPIO_DATA);
24249e39c5baSBill Taylor 
24259e39c5baSBill Taylor 	/* Set new GPIO value */
24269e39c5baSBill Taylor 	gpio = state->hs_fw_gpio[0] | HERMON_HW_FLASH_GPIO_PIN_ENABLE;
24279e39c5baSBill Taylor 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_DATA, gpio);
24289e39c5baSBill Taylor 
24299e39c5baSBill Taylor 	/* Save away original GPIO Values */
24309e39c5baSBill Taylor 	state->hs_fw_gpio[1] = hermon_flash_read_cfg(state, hdl,
24319e39c5baSBill Taylor 	    HERMON_HW_FLASH_GPIO_MOD0);
24329e39c5baSBill Taylor 	state->hs_fw_gpio[2] = hermon_flash_read_cfg(state, hdl,
24339e39c5baSBill Taylor 	    HERMON_HW_FLASH_GPIO_MOD1);
24349e39c5baSBill Taylor 
24359e39c5baSBill Taylor 	/* unlock GPIO */
24369e39c5baSBill Taylor 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_LOCK,
24379e39c5baSBill Taylor 	    HERMON_HW_FLASH_GPIO_UNLOCK_VAL);
24389e39c5baSBill Taylor 
24399e39c5baSBill Taylor 	/*
24409e39c5baSBill Taylor 	 * Set new GPIO values
24419e39c5baSBill Taylor 	 */
24429e39c5baSBill Taylor 	gpio = state->hs_fw_gpio[1] | HERMON_HW_FLASH_GPIO_PIN_ENABLE;
24439e39c5baSBill Taylor 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_MOD0, gpio);
24449e39c5baSBill Taylor 
24459e39c5baSBill Taylor 	gpio = state->hs_fw_gpio[2] & ~HERMON_HW_FLASH_GPIO_PIN_ENABLE;
24469e39c5baSBill Taylor 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_MOD1, gpio);
24479e39c5baSBill Taylor 
24489e39c5baSBill Taylor 	/* re-lock GPIO */
24499e39c5baSBill Taylor 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_LOCK, 0);
24509e39c5baSBill Taylor 
24519e39c5baSBill Taylor 	/* Set CPUMODE to enable hermon to access the flash device */
24529e39c5baSBill Taylor 	/* CMJ This code came from arbel.  Hermon doesn't seem to need it. */
24539e39c5baSBill Taylor 	/*
24549e39c5baSBill Taylor 	 *	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_CPUMODE,
24559e39c5baSBill Taylor 	 *	    1 << HERMON_HW_FLASH_CPU_SHIFT);
24569e39c5baSBill Taylor 	 */
24579e39c5baSBill Taylor 
24589e39c5baSBill Taylor 	/* the FMA retry loop ends. */
24599e39c5baSBill Taylor 	hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status, fm_test);
24609e39c5baSBill Taylor 	return (0);
24619e39c5baSBill Taylor 
24629e39c5baSBill Taylor pio_error:
24639e39c5baSBill Taylor 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
24649e39c5baSBill Taylor 	return (EIO);
24659e39c5baSBill Taylor }
24669e39c5baSBill Taylor 
24679e39c5baSBill Taylor /*
24689e39c5baSBill Taylor  * hermon_flash_cfi_init
24699e39c5baSBill Taylor  *   Implements access to the CFI (Common Flash Interface) data
24709e39c5baSBill Taylor  */
24719e39c5baSBill Taylor static int
hermon_flash_cfi_init(hermon_state_t * state,uint32_t * cfi_info,int * intel_xcmd)24729e39c5baSBill Taylor hermon_flash_cfi_init(hermon_state_t *state, uint32_t *cfi_info,
24739e39c5baSBill Taylor     int *intel_xcmd)
24749e39c5baSBill Taylor {
24759e39c5baSBill Taylor 	uint32_t	data;
24769e39c5baSBill Taylor 	uint32_t	sector_sz_bytes;
24779e39c5baSBill Taylor 	uint32_t	bit_count;
24789e39c5baSBill Taylor 	uint8_t		cfi_ch_info[HERMON_CFI_INFO_SIZE];
24799e39c5baSBill Taylor 	int		i;
24809e39c5baSBill Taylor 	int		status;
24819e39c5baSBill Taylor 
24829e39c5baSBill Taylor 	/* Right now, all hermon cards use SPI. */
2483*13cc0a0bSBill Taylor 	if (hermon_device_mode(state)) {
24849e39c5baSBill Taylor 		/*
24859e39c5baSBill Taylor 		 * Don't use CFI for SPI part. Just fill in what we need
24869e39c5baSBill Taylor 		 * and return.
24879e39c5baSBill Taylor 		 */
24889e39c5baSBill Taylor 		state->hs_fw_cmdset = HERMON_FLASH_SPI_CMDSET;
24899e39c5baSBill Taylor 		state->hs_fw_log_sector_sz = HERMON_FLASH_SPI_LOG_SECTOR_SIZE;
24909e39c5baSBill Taylor 		state->hs_fw_device_sz = HERMON_FLASH_SPI_DEVICE_SIZE;
24919e39c5baSBill Taylor 
24929e39c5baSBill Taylor 		/*
24939e39c5baSBill Taylor 		 * set this to inform caller of cmdset type.
24949e39c5baSBill Taylor 		 */
24959e39c5baSBill Taylor 		cfi_ch_info[0x13] = HERMON_FLASH_SPI_CMDSET;
24969e39c5baSBill Taylor 		hermon_flash_cfi_dword(&cfi_info[4], cfi_ch_info, 0x10);
24979e39c5baSBill Taylor 		return (0);
24989e39c5baSBill Taylor 	}
24999e39c5baSBill Taylor 
25009e39c5baSBill Taylor 	/*
25019e39c5baSBill Taylor 	 * Determine if the user command supports the Intel Extended
25029e39c5baSBill Taylor 	 * Command Set. The query string is contained in the fourth
25039e39c5baSBill Taylor 	 * quad word.
25049e39c5baSBill Taylor 	 */
25059e39c5baSBill Taylor 	hermon_flash_cfi_byte(cfi_ch_info, cfi_info[0x04], 0x10);
25069e39c5baSBill Taylor 	if (cfi_ch_info[0x10] == 'M' &&
25079e39c5baSBill Taylor 	    cfi_ch_info[0x11] == 'X' &&
25089e39c5baSBill Taylor 	    cfi_ch_info[0x12] == '2') {
25099e39c5baSBill Taylor 		*intel_xcmd = 1; /* support is there */
25109e39c5baSBill Taylor 		if (hermon_verbose) {
25119e39c5baSBill Taylor 			IBTF_DPRINTF_L2("hermon",
25129e39c5baSBill Taylor 			    "Support for Intel X is present\n");
25139e39c5baSBill Taylor 		}
25149e39c5baSBill Taylor 	}
25159e39c5baSBill Taylor 
25169e39c5baSBill Taylor 	/* CFI QUERY */
25179e39c5baSBill Taylor 	hermon_flash_write(state, 0x55, HERMON_FLASH_CFI_INIT, &status);
25189e39c5baSBill Taylor 	if (status != 0) {
25199e39c5baSBill Taylor 		return (status);
25209e39c5baSBill Taylor 	}
25219e39c5baSBill Taylor 
25229e39c5baSBill Taylor 	/* temporarily set the cmdset in order to do the initial read */
25239e39c5baSBill Taylor 	state->hs_fw_cmdset = HERMON_FLASH_INTEL_CMDSET;
25249e39c5baSBill Taylor 
25259e39c5baSBill Taylor 	/* Read in CFI data */
25269e39c5baSBill Taylor 	for (i = 0; i < HERMON_CFI_INFO_SIZE; i += 4) {
25279e39c5baSBill Taylor 		data = hermon_flash_read(state, i, &status);
25289e39c5baSBill Taylor 		if (status != 0) {
25299e39c5baSBill Taylor 			return (status);
25309e39c5baSBill Taylor 		}
25319e39c5baSBill Taylor 		hermon_flash_cfi_byte(cfi_ch_info, data, i);
25329e39c5baSBill Taylor 	}
25339e39c5baSBill Taylor 
25349e39c5baSBill Taylor 	/* Determine chip set */
25359e39c5baSBill Taylor 	state->hs_fw_cmdset = HERMON_FLASH_UNKNOWN_CMDSET;
25369e39c5baSBill Taylor 	if (cfi_ch_info[0x20] == 'Q' &&
25379e39c5baSBill Taylor 	    cfi_ch_info[0x22] == 'R' &&
25389e39c5baSBill Taylor 	    cfi_ch_info[0x24] == 'Y') {
25399e39c5baSBill Taylor 		/*
25409e39c5baSBill Taylor 		 * Mode: x16 working in x8 mode (Intel).
25419e39c5baSBill Taylor 		 * Pack data - skip spacing bytes.
25429e39c5baSBill Taylor 		 */
25439e39c5baSBill Taylor 		if (hermon_verbose) {
25449e39c5baSBill Taylor 			IBTF_DPRINTF_L2("hermon",
25459e39c5baSBill Taylor 			    "x16 working in x8 mode (Intel)\n");
25469e39c5baSBill Taylor 		}
25479e39c5baSBill Taylor 		for (i = 0; i < HERMON_CFI_INFO_SIZE; i += 2) {
25489e39c5baSBill Taylor 			cfi_ch_info[i/2] = cfi_ch_info[i];
25499e39c5baSBill Taylor 		}
25509e39c5baSBill Taylor 	}
25519e39c5baSBill Taylor 	state->hs_fw_cmdset = cfi_ch_info[0x13];
25529e39c5baSBill Taylor 
25539e39c5baSBill Taylor 	if (state->hs_fw_cmdset != HERMON_FLASH_INTEL_CMDSET &&
25549e39c5baSBill Taylor 	    state->hs_fw_cmdset != HERMON_FLASH_AMD_CMDSET) {
25559e39c5baSBill Taylor 		cmn_err(CE_WARN,
25569e39c5baSBill Taylor 		    "hermon_flash_cfi_init: UNKNOWN chip cmd set 0x%04x\n",
25579e39c5baSBill Taylor 		    state->hs_fw_cmdset);
25589e39c5baSBill Taylor 		state->hs_fw_cmdset = HERMON_FLASH_UNKNOWN_CMDSET;
25599e39c5baSBill Taylor 		return (0);
25609e39c5baSBill Taylor 	}
25619e39c5baSBill Taylor 
25629e39c5baSBill Taylor 	/* Determine total bytes in one sector size */
25639e39c5baSBill Taylor 	sector_sz_bytes = ((cfi_ch_info[0x30] << 8) | cfi_ch_info[0x2F]) << 8;
25649e39c5baSBill Taylor 
25659e39c5baSBill Taylor 	/* Calculate equivalent of log2 (n) */
25669e39c5baSBill Taylor 	for (bit_count = 0; sector_sz_bytes > 1; bit_count++) {
25679e39c5baSBill Taylor 		sector_sz_bytes >>= 1;
25689e39c5baSBill Taylor 	}
25699e39c5baSBill Taylor 
25709e39c5baSBill Taylor 	/* Set sector size */
25719e39c5baSBill Taylor 	state->hs_fw_log_sector_sz = bit_count;
25729e39c5baSBill Taylor 
25739e39c5baSBill Taylor 	/* Set flash size */
25749e39c5baSBill Taylor 	state->hs_fw_device_sz = 0x1 << cfi_ch_info[0x27];
25759e39c5baSBill Taylor 
25769e39c5baSBill Taylor 	/* Reset to turn off CFI mode */
25779e39c5baSBill Taylor 	if ((status = hermon_flash_reset(state)) != 0)
25789e39c5baSBill Taylor 		goto out;
25799e39c5baSBill Taylor 
25809e39c5baSBill Taylor 	/* Pass CFI data back to user command. */
25819e39c5baSBill Taylor 	for (i = 0; i < HERMON_FLASH_CFI_SIZE_QUADLET; i++) {
25829e39c5baSBill Taylor 		hermon_flash_cfi_dword(&cfi_info[i], cfi_ch_info, i << 2);
25839e39c5baSBill Taylor 	}
25849e39c5baSBill Taylor 
25859e39c5baSBill Taylor 	if (*intel_xcmd == 1) {
25869e39c5baSBill Taylor 		/*
25879e39c5baSBill Taylor 		 * Inform the user cmd that this driver does support the
25889e39c5baSBill Taylor 		 * Intel Extended Command Set.
25899e39c5baSBill Taylor 		 */
25909e39c5baSBill Taylor 		cfi_ch_info[0x10] = 'M';
25919e39c5baSBill Taylor 		cfi_ch_info[0x11] = 'X';
25929e39c5baSBill Taylor 		cfi_ch_info[0x12] = '2';
25939e39c5baSBill Taylor 	} else {
25949e39c5baSBill Taylor 		cfi_ch_info[0x10] = 'Q';
25959e39c5baSBill Taylor 		cfi_ch_info[0x11] = 'R';
25969e39c5baSBill Taylor 		cfi_ch_info[0x12] = 'Y';
25979e39c5baSBill Taylor 	}
25989e39c5baSBill Taylor 	cfi_ch_info[0x13] = state->hs_fw_cmdset;
25999e39c5baSBill Taylor 	hermon_flash_cfi_dword(&cfi_info[0x4], cfi_ch_info, 0x10);
26009e39c5baSBill Taylor out:
26019e39c5baSBill Taylor 	return (status);
26029e39c5baSBill Taylor }
26039e39c5baSBill Taylor 
26049e39c5baSBill Taylor /*
26059e39c5baSBill Taylor  * hermon_flash_fini()
26069e39c5baSBill Taylor  */
26079e39c5baSBill Taylor static int
hermon_flash_fini(hermon_state_t * state)26089e39c5baSBill Taylor hermon_flash_fini(hermon_state_t *state)
26099e39c5baSBill Taylor {
26109e39c5baSBill Taylor 	int status;
26119e39c5baSBill Taylor 	ddi_acc_handle_t hdl;
26129e39c5baSBill Taylor 
26139e39c5baSBill Taylor 	/* initialize the FMA retry loop */
26149e39c5baSBill Taylor 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
26159e39c5baSBill Taylor 
26169e39c5baSBill Taylor 	/* Set handle */
26179e39c5baSBill Taylor 	hdl = hermon_get_pcihdl(state);
26189e39c5baSBill Taylor 
26199e39c5baSBill Taylor 	if ((status = hermon_flash_bank(state, 0)) != 0)
26209e39c5baSBill Taylor 		return (status);
26219e39c5baSBill Taylor 
26229e39c5baSBill Taylor 	/* the FMA retry loop starts. */
26239e39c5baSBill Taylor 	hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status,
26249e39c5baSBill Taylor 	    fm_test);
26259e39c5baSBill Taylor 
26269e39c5baSBill Taylor 	/*
26279e39c5baSBill Taylor 	 * Restore original GPIO Values
26289e39c5baSBill Taylor 	 */
26299e39c5baSBill Taylor 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_DATA,
26309e39c5baSBill Taylor 	    state->hs_fw_gpio[0]);
26319e39c5baSBill Taylor 
26329e39c5baSBill Taylor 	/* unlock GPIOs */
26339e39c5baSBill Taylor 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_LOCK,
26349e39c5baSBill Taylor 	    HERMON_HW_FLASH_GPIO_UNLOCK_VAL);
26359e39c5baSBill Taylor 
26369e39c5baSBill Taylor 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_MOD0,
26379e39c5baSBill Taylor 	    state->hs_fw_gpio[1]);
26389e39c5baSBill Taylor 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_MOD1,
26399e39c5baSBill Taylor 	    state->hs_fw_gpio[2]);
26409e39c5baSBill Taylor 
26419e39c5baSBill Taylor 	/* re-lock GPIOs */
26429e39c5baSBill Taylor 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_LOCK, 0);
26439e39c5baSBill Taylor 
26449e39c5baSBill Taylor 	/* Give up gpio semaphore */
26459e39c5baSBill Taylor 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_SEMA, 0);
26469e39c5baSBill Taylor 
26479e39c5baSBill Taylor 	/* the FMA retry loop ends. */
26489e39c5baSBill Taylor 	hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status, fm_test);
26499e39c5baSBill Taylor 	return (0);
26509e39c5baSBill Taylor 
26519e39c5baSBill Taylor pio_error:
26529e39c5baSBill Taylor 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
26539e39c5baSBill Taylor 	return (EIO);
26549e39c5baSBill Taylor }
26559e39c5baSBill Taylor 
26569e39c5baSBill Taylor /*
26579e39c5baSBill Taylor  * hermon_flash_read_cfg
26589e39c5baSBill Taylor  */
26599e39c5baSBill Taylor static uint32_t
hermon_flash_read_cfg(hermon_state_t * state,ddi_acc_handle_t pci_config_hdl,uint32_t addr)26609e39c5baSBill Taylor hermon_flash_read_cfg(hermon_state_t *state, ddi_acc_handle_t pci_config_hdl,
26619e39c5baSBill Taylor     uint32_t addr)
26629e39c5baSBill Taylor {
26639e39c5baSBill Taylor 	uint32_t	read;
26649e39c5baSBill Taylor 
26659e39c5baSBill Taylor 	if (do_bar0) {
26669e39c5baSBill Taylor 		read = ddi_get32(hermon_get_cmdhdl(state), (uint32_t *)(void *)
26679e39c5baSBill Taylor 		    (state->hs_reg_cmd_baseaddr + addr));
26689e39c5baSBill Taylor 	} else {
26699e39c5baSBill Taylor 		/*
26709e39c5baSBill Taylor 		 * Perform flash read operation:
26719e39c5baSBill Taylor 		 *   1) Place addr to read from on the HERMON_HW_FLASH_CFG_ADDR
26729e39c5baSBill Taylor 		 *	register
26739e39c5baSBill Taylor 		 *   2) Read data at that addr from the HERMON_HW_FLASH_CFG_DATA
26749e39c5baSBill Taylor 		 *	 register
26759e39c5baSBill Taylor 		 */
26769e39c5baSBill Taylor 		pci_config_put32(pci_config_hdl, HERMON_HW_FLASH_CFG_ADDR,
26779e39c5baSBill Taylor 		    addr);
26789e39c5baSBill Taylor 		read = pci_config_get32(pci_config_hdl,
26799e39c5baSBill Taylor 		    HERMON_HW_FLASH_CFG_DATA);
26809e39c5baSBill Taylor 	}
26819e39c5baSBill Taylor 
26829e39c5baSBill Taylor 	return (read);
26839e39c5baSBill Taylor }
26849e39c5baSBill Taylor 
26859e39c5baSBill Taylor #ifdef DO_WRCONF
26869e39c5baSBill Taylor static void
hermon_flash_write_cfg(hermon_state_t * state,ddi_acc_handle_t pci_config_hdl,uint32_t addr,uint32_t data)26879e39c5baSBill Taylor hermon_flash_write_cfg(hermon_state_t *state,
26889e39c5baSBill Taylor     ddi_acc_handle_t pci_config_hdl, uint32_t addr, uint32_t data)
26899e39c5baSBill Taylor {
26909e39c5baSBill Taylor 	hermon_flash_write_cfg_helper(state, pci_config_hdl, addr, data);
26919e39c5baSBill Taylor 	hermon_flash_write_confirm(state, pci_config_hdl);
26929e39c5baSBill Taylor }
26939e39c5baSBill Taylor 
26949e39c5baSBill Taylor static void
hermon_flash_write_confirm(hermon_state_t * state,ddi_acc_handle_t pci_config_hdl)26959e39c5baSBill Taylor hermon_flash_write_confirm(hermon_state_t *state,
26969e39c5baSBill Taylor     ddi_acc_handle_t pci_config_hdl)
26979e39c5baSBill Taylor {
26989e39c5baSBill Taylor 	uint32_t	sem_value = 1;
26999e39c5baSBill Taylor 
27009e39c5baSBill Taylor 	hermon_flash_write_cfg_helper(state, pci_config_hdl,
27019e39c5baSBill Taylor 	    HERMON_HW_FLASH_WRCONF_SEMA, 0);
27029e39c5baSBill Taylor 	while (sem_value) {
27039e39c5baSBill Taylor 		sem_value = hermon_flash_read_cfg(state, pci_config_hdl,
27049e39c5baSBill Taylor 		    HERMON_HW_FLASH_WRCONF_SEMA);
27059e39c5baSBill Taylor 	}
27069e39c5baSBill Taylor }
27079e39c5baSBill Taylor #endif
27089e39c5baSBill Taylor 
27099e39c5baSBill Taylor /*
27109e39c5baSBill Taylor  * hermon_flash_write_cfg
27119e39c5baSBill Taylor  */
27129e39c5baSBill Taylor static void
27139e39c5baSBill Taylor #ifdef DO_WRCONF
hermon_flash_write_cfg_helper(hermon_state_t * state,ddi_acc_handle_t pci_config_hdl,uint32_t addr,uint32_t data)27149e39c5baSBill Taylor hermon_flash_write_cfg_helper(hermon_state_t *state,
27159e39c5baSBill Taylor     ddi_acc_handle_t pci_config_hdl, uint32_t addr, uint32_t data)
27169e39c5baSBill Taylor #else
27179e39c5baSBill Taylor hermon_flash_write_cfg(hermon_state_t *state,
27189e39c5baSBill Taylor     ddi_acc_handle_t pci_config_hdl, uint32_t addr, uint32_t data)
27199e39c5baSBill Taylor #endif
27209e39c5baSBill Taylor {
27219e39c5baSBill Taylor 	if (do_bar0) {
27229e39c5baSBill Taylor 		ddi_put32(hermon_get_cmdhdl(state), (uint32_t *)(void *)
27239e39c5baSBill Taylor 		    (state->hs_reg_cmd_baseaddr + addr), data);
27249e39c5baSBill Taylor 
27259e39c5baSBill Taylor 	} else {
27269e39c5baSBill Taylor 
27279e39c5baSBill Taylor 		/*
27289e39c5baSBill Taylor 		 * Perform flash write operation:
27299e39c5baSBill Taylor 		 *   1) Place addr to write to on the HERMON_HW_FLASH_CFG_ADDR
27309e39c5baSBill Taylor 		 *	register
27319e39c5baSBill Taylor 		 *   2) Place data to write on to the HERMON_HW_FLASH_CFG_DATA
27329e39c5baSBill Taylor 		 *	register
27339e39c5baSBill Taylor 		 */
27349e39c5baSBill Taylor 		pci_config_put32(pci_config_hdl, HERMON_HW_FLASH_CFG_ADDR,
27359e39c5baSBill Taylor 		    addr);
27369e39c5baSBill Taylor 		pci_config_put32(pci_config_hdl, HERMON_HW_FLASH_CFG_DATA,
27379e39c5baSBill Taylor 		    data);
27389e39c5baSBill Taylor 	}
27399e39c5baSBill Taylor }
27409e39c5baSBill Taylor 
27419e39c5baSBill Taylor /*
27429e39c5baSBill Taylor  * Support routines to convert Common Flash Interface (CFI) data
27439e39c5baSBill Taylor  * from a 32  bit word to a char array, and from a char array to
27449e39c5baSBill Taylor  * a 32 bit word.
27459e39c5baSBill Taylor  */
27469e39c5baSBill Taylor static void
hermon_flash_cfi_byte(uint8_t * ch,uint32_t dword,int i)27479e39c5baSBill Taylor hermon_flash_cfi_byte(uint8_t *ch, uint32_t dword, int i)
27489e39c5baSBill Taylor {
27499e39c5baSBill Taylor 	ch[i] = (uint8_t)((dword & 0xFF000000) >> 24);
27509e39c5baSBill Taylor 	ch[i+1] = (uint8_t)((dword & 0x00FF0000) >> 16);
27519e39c5baSBill Taylor 	ch[i+2] = (uint8_t)((dword & 0x0000FF00) >> 8);
27529e39c5baSBill Taylor 	ch[i+3] = (uint8_t)((dword & 0x000000FF));
27539e39c5baSBill Taylor }
27549e39c5baSBill Taylor 
27559e39c5baSBill Taylor static void
hermon_flash_cfi_dword(uint32_t * dword,uint8_t * ch,int i)27569e39c5baSBill Taylor hermon_flash_cfi_dword(uint32_t *dword, uint8_t *ch, int i)
27579e39c5baSBill Taylor {
27589e39c5baSBill Taylor 	*dword = (uint32_t)
27599e39c5baSBill Taylor 	    ((uint32_t)ch[i] << 24 |
27609e39c5baSBill Taylor 	    (uint32_t)ch[i+1] << 16 |
27619e39c5baSBill Taylor 	    (uint32_t)ch[i+2] << 8 |
27629e39c5baSBill Taylor 	    (uint32_t)ch[i+3]);
27639e39c5baSBill Taylor }
27649e39c5baSBill Taylor 
27659e39c5baSBill Taylor /*
27669e39c5baSBill Taylor  * hermon_loopback_free_qps
27679e39c5baSBill Taylor  */
27689e39c5baSBill Taylor static void
hermon_loopback_free_qps(hermon_loopback_state_t * lstate)27699e39c5baSBill Taylor hermon_loopback_free_qps(hermon_loopback_state_t *lstate)
27709e39c5baSBill Taylor {
27719e39c5baSBill Taylor 	int i;
27729e39c5baSBill Taylor 
27739e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lstate))
27749e39c5baSBill Taylor 
27759e39c5baSBill Taylor 	if (lstate->hls_tx.hlc_qp_hdl != NULL) {
27769e39c5baSBill Taylor 		(void) hermon_qp_free(lstate->hls_state,
27779e39c5baSBill Taylor 		    &lstate->hls_tx.hlc_qp_hdl, IBC_FREE_QP_AND_QPN, NULL,
27789e39c5baSBill Taylor 		    HERMON_NOSLEEP);
27799e39c5baSBill Taylor 	}
27809e39c5baSBill Taylor 	if (lstate->hls_rx.hlc_qp_hdl != NULL) {
27819e39c5baSBill Taylor 		(void) hermon_qp_free(lstate->hls_state,
27829e39c5baSBill Taylor 		    &lstate->hls_rx.hlc_qp_hdl, IBC_FREE_QP_AND_QPN, NULL,
27839e39c5baSBill Taylor 		    HERMON_NOSLEEP);
27849e39c5baSBill Taylor 	}
27859e39c5baSBill Taylor 	lstate->hls_tx.hlc_qp_hdl = NULL;
27869e39c5baSBill Taylor 	lstate->hls_rx.hlc_qp_hdl = NULL;
27879e39c5baSBill Taylor 	for (i = 0; i < 2; i++) {
27889e39c5baSBill Taylor 		if (lstate->hls_tx.hlc_cqhdl[i] != NULL) {
27899e39c5baSBill Taylor 			(void) hermon_cq_free(lstate->hls_state,
27909e39c5baSBill Taylor 			    &lstate->hls_tx.hlc_cqhdl[i], HERMON_NOSLEEP);
27919e39c5baSBill Taylor 		}
27929e39c5baSBill Taylor 		if (lstate->hls_rx.hlc_cqhdl[i] != NULL) {
27939e39c5baSBill Taylor 			(void) hermon_cq_free(lstate->hls_state,
27949e39c5baSBill Taylor 			    &lstate->hls_rx.hlc_cqhdl[i], HERMON_NOSLEEP);
27959e39c5baSBill Taylor 		}
27969e39c5baSBill Taylor 		lstate->hls_tx.hlc_cqhdl[i] = NULL;
27979e39c5baSBill Taylor 		lstate->hls_rx.hlc_cqhdl[i] = NULL;
27989e39c5baSBill Taylor 	}
27999e39c5baSBill Taylor }
28009e39c5baSBill Taylor 
28019e39c5baSBill Taylor /*
28029e39c5baSBill Taylor  * hermon_loopback_free_state
28039e39c5baSBill Taylor  */
28049e39c5baSBill Taylor static void
hermon_loopback_free_state(hermon_loopback_state_t * lstate)28059e39c5baSBill Taylor hermon_loopback_free_state(hermon_loopback_state_t *lstate)
28069e39c5baSBill Taylor {
28079e39c5baSBill Taylor 	hermon_loopback_free_qps(lstate);
28089e39c5baSBill Taylor 	if (lstate->hls_tx.hlc_mrhdl != NULL) {
28099e39c5baSBill Taylor 		(void) hermon_mr_deregister(lstate->hls_state,
28109e39c5baSBill Taylor 		    &lstate->hls_tx.hlc_mrhdl, HERMON_MR_DEREG_ALL,
28119e39c5baSBill Taylor 		    HERMON_NOSLEEP);
28129e39c5baSBill Taylor 	}
28139e39c5baSBill Taylor 	if (lstate->hls_rx.hlc_mrhdl !=  NULL) {
28149e39c5baSBill Taylor 		(void) hermon_mr_deregister(lstate->hls_state,
28159e39c5baSBill Taylor 		    &lstate->hls_rx.hlc_mrhdl, HERMON_MR_DEREG_ALL,
28169e39c5baSBill Taylor 		    HERMON_NOSLEEP);
28179e39c5baSBill Taylor 	}
28189e39c5baSBill Taylor 	if (lstate->hls_pd_hdl != NULL) {
28199e39c5baSBill Taylor 		(void) hermon_pd_free(lstate->hls_state, &lstate->hls_pd_hdl);
28209e39c5baSBill Taylor 	}
28219e39c5baSBill Taylor 	if (lstate->hls_tx.hlc_buf != NULL) {
28229e39c5baSBill Taylor 		kmem_free(lstate->hls_tx.hlc_buf, lstate->hls_tx.hlc_buf_sz);
28239e39c5baSBill Taylor 	}
28249e39c5baSBill Taylor 	if (lstate->hls_rx.hlc_buf != NULL) {
28259e39c5baSBill Taylor 		kmem_free(lstate->hls_rx.hlc_buf, lstate->hls_rx.hlc_buf_sz);
28269e39c5baSBill Taylor 	}
28279e39c5baSBill Taylor 	bzero(lstate, sizeof (hermon_loopback_state_t));
28289e39c5baSBill Taylor }
28299e39c5baSBill Taylor 
28309e39c5baSBill Taylor /*
28319e39c5baSBill Taylor  * hermon_loopback_init
28329e39c5baSBill Taylor  */
28339e39c5baSBill Taylor static int
hermon_loopback_init(hermon_state_t * state,hermon_loopback_state_t * lstate)28349e39c5baSBill Taylor hermon_loopback_init(hermon_state_t *state, hermon_loopback_state_t *lstate)
28359e39c5baSBill Taylor {
28369e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lstate))
28379e39c5baSBill Taylor 
28389e39c5baSBill Taylor 	lstate->hls_hca_hdl = (ibc_hca_hdl_t)state;
28399e39c5baSBill Taylor 	lstate->hls_status  = hermon_pd_alloc(lstate->hls_state,
28409e39c5baSBill Taylor 	    &lstate->hls_pd_hdl, HERMON_NOSLEEP);
28419e39c5baSBill Taylor 	if (lstate->hls_status != IBT_SUCCESS) {
28429e39c5baSBill Taylor 		lstate->hls_err = HERMON_LOOPBACK_PROT_DOMAIN_ALLOC_FAIL;
28439e39c5baSBill Taylor 		return (EFAULT);
28449e39c5baSBill Taylor 	}
28459e39c5baSBill Taylor 
28469e39c5baSBill Taylor 	return (0);
28479e39c5baSBill Taylor }
28489e39c5baSBill Taylor 
28499e39c5baSBill Taylor /*
28509e39c5baSBill Taylor  * hermon_loopback_init_qp_info
28519e39c5baSBill Taylor  */
28529e39c5baSBill Taylor static void
hermon_loopback_init_qp_info(hermon_loopback_state_t * lstate,hermon_loopback_comm_t * comm)28539e39c5baSBill Taylor hermon_loopback_init_qp_info(hermon_loopback_state_t *lstate,
28549e39c5baSBill Taylor     hermon_loopback_comm_t *comm)
28559e39c5baSBill Taylor {
28569e39c5baSBill Taylor 	bzero(&comm->hlc_cq_attr, sizeof (ibt_cq_attr_t));
28579e39c5baSBill Taylor 	bzero(&comm->hlc_qp_attr, sizeof (ibt_qp_alloc_attr_t));
28589e39c5baSBill Taylor 	bzero(&comm->hlc_qp_info, sizeof (ibt_qp_info_t));
28599e39c5baSBill Taylor 
28609e39c5baSBill Taylor 	comm->hlc_wrid = 1;
28619e39c5baSBill Taylor 	comm->hlc_cq_attr.cq_size = 128;
28629e39c5baSBill Taylor 	comm->hlc_qp_attr.qp_sizes.cs_sq_sgl = 3;
28639e39c5baSBill Taylor 	comm->hlc_qp_attr.qp_sizes.cs_rq_sgl = 3;
28649e39c5baSBill Taylor 	comm->hlc_qp_attr.qp_sizes.cs_sq = 16;
28659e39c5baSBill Taylor 	comm->hlc_qp_attr.qp_sizes.cs_rq = 16;
28669e39c5baSBill Taylor 	comm->hlc_qp_attr.qp_flags = IBT_WR_SIGNALED;
28679e39c5baSBill Taylor 
28689e39c5baSBill Taylor 	comm->hlc_qp_info.qp_state = IBT_STATE_RESET;
28699e39c5baSBill Taylor 	comm->hlc_qp_info.qp_trans = IBT_RC_SRV;
28709e39c5baSBill Taylor 	comm->hlc_qp_info.qp_flags = IBT_CEP_RDMA_RD | IBT_CEP_RDMA_WR;
28719e39c5baSBill Taylor 	comm->hlc_qp_info.qp_transport.rc.rc_path.cep_hca_port_num =
28729e39c5baSBill Taylor 	    lstate->hls_port;
28739e39c5baSBill Taylor 	comm->hlc_qp_info.qp_transport.rc.rc_path.cep_pkey_ix =
28749e39c5baSBill Taylor 	    lstate->hls_pkey_ix;
28759e39c5baSBill Taylor 	comm->hlc_qp_info.qp_transport.rc.rc_path.cep_timeout =
28769e39c5baSBill Taylor 	    lstate->hls_timeout;
28779e39c5baSBill Taylor 	comm->hlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_srvl = 0;
28789e39c5baSBill Taylor 	comm->hlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_srate =
28799e39c5baSBill Taylor 	    IBT_SRATE_4X;
28809e39c5baSBill Taylor 	comm->hlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_send_grh = 0;
28819e39c5baSBill Taylor 	comm->hlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_dlid =
28829e39c5baSBill Taylor 	    lstate->hls_lid;
28839e39c5baSBill Taylor 	comm->hlc_qp_info.qp_transport.rc.rc_retry_cnt = lstate->hls_retry;
28849e39c5baSBill Taylor 	comm->hlc_qp_info.qp_transport.rc.rc_sq_psn = 0;
28859e39c5baSBill Taylor 	comm->hlc_qp_info.qp_transport.rc.rc_rq_psn = 0;
28869e39c5baSBill Taylor 	comm->hlc_qp_info.qp_transport.rc.rc_rdma_ra_in	 = 4;
28879e39c5baSBill Taylor 	comm->hlc_qp_info.qp_transport.rc.rc_rdma_ra_out = 4;
28889e39c5baSBill Taylor 	comm->hlc_qp_info.qp_transport.rc.rc_dst_qpn = 0;
28899e39c5baSBill Taylor 	comm->hlc_qp_info.qp_transport.rc.rc_min_rnr_nak = IBT_RNR_NAK_655ms;
28909e39c5baSBill Taylor 	comm->hlc_qp_info.qp_transport.rc.rc_path_mtu = IB_MTU_1K;
28919e39c5baSBill Taylor }
28929e39c5baSBill Taylor 
28939e39c5baSBill Taylor /*
28949e39c5baSBill Taylor  * hermon_loopback_alloc_mem
28959e39c5baSBill Taylor  */
28969e39c5baSBill Taylor static int
hermon_loopback_alloc_mem(hermon_loopback_state_t * lstate,hermon_loopback_comm_t * comm,int sz)28979e39c5baSBill Taylor hermon_loopback_alloc_mem(hermon_loopback_state_t *lstate,
28989e39c5baSBill Taylor     hermon_loopback_comm_t *comm, int sz)
28999e39c5baSBill Taylor {
29009e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm))
29019e39c5baSBill Taylor 
29029e39c5baSBill Taylor 	/* Allocate buffer of specified size */
29039e39c5baSBill Taylor 	comm->hlc_buf_sz = sz;
29049e39c5baSBill Taylor 	comm->hlc_buf	 = kmem_zalloc(sz, KM_NOSLEEP);
29059e39c5baSBill Taylor 	if (comm->hlc_buf == NULL) {
29069e39c5baSBill Taylor 		return (EFAULT);
29079e39c5baSBill Taylor 	}
29089e39c5baSBill Taylor 
29099e39c5baSBill Taylor 	/* Register the buffer as a memory region */
29109e39c5baSBill Taylor 	comm->hlc_memattr.mr_vaddr = (uint64_t)(uintptr_t)comm->hlc_buf;
29119e39c5baSBill Taylor 	comm->hlc_memattr.mr_len   = (ib_msglen_t)sz;
29129e39c5baSBill Taylor 	comm->hlc_memattr.mr_as	   = NULL;
29139e39c5baSBill Taylor 	comm->hlc_memattr.mr_flags = IBT_MR_NOSLEEP |
29149e39c5baSBill Taylor 	    IBT_MR_ENABLE_REMOTE_WRITE | IBT_MR_ENABLE_LOCAL_WRITE;
29159e39c5baSBill Taylor 
29169e39c5baSBill Taylor 	comm->hlc_status = hermon_mr_register(lstate->hls_state,
29179e39c5baSBill Taylor 	    lstate->hls_pd_hdl, &comm->hlc_memattr, &comm->hlc_mrhdl,
29189e39c5baSBill Taylor 	    NULL, HERMON_MPT_DMPT);
29199e39c5baSBill Taylor 
29209e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm->hlc_mrhdl))
29219e39c5baSBill Taylor 
29229e39c5baSBill Taylor 	comm->hlc_mrdesc.md_vaddr  = comm->hlc_mrhdl->mr_bindinfo.bi_addr;
29239e39c5baSBill Taylor 	comm->hlc_mrdesc.md_lkey   = comm->hlc_mrhdl->mr_lkey;
29249e39c5baSBill Taylor 	comm->hlc_mrdesc.md_rkey   = comm->hlc_mrhdl->mr_rkey;
29259e39c5baSBill Taylor 	if (comm->hlc_status != IBT_SUCCESS) {
29269e39c5baSBill Taylor 		return (EFAULT);
29279e39c5baSBill Taylor 	}
29289e39c5baSBill Taylor 	return (0);
29299e39c5baSBill Taylor }
29309e39c5baSBill Taylor 
29319e39c5baSBill Taylor /*
29329e39c5baSBill Taylor  * hermon_loopback_alloc_qps
29339e39c5baSBill Taylor  */
29349e39c5baSBill Taylor static int
hermon_loopback_alloc_qps(hermon_loopback_state_t * lstate,hermon_loopback_comm_t * comm)29359e39c5baSBill Taylor hermon_loopback_alloc_qps(hermon_loopback_state_t *lstate,
29369e39c5baSBill Taylor     hermon_loopback_comm_t *comm)
29379e39c5baSBill Taylor {
29389e39c5baSBill Taylor 	uint32_t		i, real_size;
29399e39c5baSBill Taylor 	hermon_qp_info_t		qpinfo;
29409e39c5baSBill Taylor 
29419e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm))
29429e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lstate))
29439e39c5baSBill Taylor 
29449e39c5baSBill Taylor 	/* Allocate send and recv CQs */
29459e39c5baSBill Taylor 	for (i = 0; i < 2; i++) {
29469e39c5baSBill Taylor 		bzero(&comm->hlc_cq_attr, sizeof (ibt_cq_attr_t));
29479e39c5baSBill Taylor 		comm->hlc_cq_attr.cq_size = 128;
29489e39c5baSBill Taylor 		comm->hlc_status = hermon_cq_alloc(lstate->hls_state,
29499e39c5baSBill Taylor 		    (ibt_cq_hdl_t)NULL, &comm->hlc_cq_attr, &real_size,
29509e39c5baSBill Taylor 		    &comm->hlc_cqhdl[i], HERMON_NOSLEEP);
29519e39c5baSBill Taylor 		if (comm->hlc_status != IBT_SUCCESS) {
29529e39c5baSBill Taylor 			lstate->hls_err += i;
29539e39c5baSBill Taylor 			return (EFAULT);
29549e39c5baSBill Taylor 		}
29559e39c5baSBill Taylor 	}
29569e39c5baSBill Taylor 
29579e39c5baSBill Taylor 	/* Allocate the QP */
29589e39c5baSBill Taylor 	hermon_loopback_init_qp_info(lstate, comm);
29599e39c5baSBill Taylor 	comm->hlc_qp_attr.qp_pd_hdl	 = (ibt_pd_hdl_t)lstate->hls_pd_hdl;
29609e39c5baSBill Taylor 	comm->hlc_qp_attr.qp_scq_hdl	 = (ibt_cq_hdl_t)comm->hlc_cqhdl[0];
29619e39c5baSBill Taylor 	comm->hlc_qp_attr.qp_rcq_hdl	 = (ibt_cq_hdl_t)comm->hlc_cqhdl[1];
29629e39c5baSBill Taylor 	comm->hlc_qp_attr.qp_ibc_scq_hdl = (ibt_opaque1_t)comm->hlc_cqhdl[0];
29639e39c5baSBill Taylor 	comm->hlc_qp_attr.qp_ibc_rcq_hdl = (ibt_opaque1_t)comm->hlc_cqhdl[1];
29649e39c5baSBill Taylor 	qpinfo.qpi_attrp	= &comm->hlc_qp_attr;
29659e39c5baSBill Taylor 	qpinfo.qpi_type		= IBT_RC_RQP;
29669e39c5baSBill Taylor 	qpinfo.qpi_ibt_qphdl	= NULL;
29679e39c5baSBill Taylor 	qpinfo.qpi_queueszp	= &comm->hlc_chan_sizes;
29689e39c5baSBill Taylor 	qpinfo.qpi_qpn		= &comm->hlc_qp_num;
29699e39c5baSBill Taylor 	comm->hlc_status = hermon_qp_alloc(lstate->hls_state, &qpinfo,
29709e39c5baSBill Taylor 	    HERMON_NOSLEEP);
29719e39c5baSBill Taylor 	if (comm->hlc_status == DDI_SUCCESS) {
29729e39c5baSBill Taylor 		comm->hlc_qp_hdl = qpinfo.qpi_qphdl;
29739e39c5baSBill Taylor 	}
29749e39c5baSBill Taylor 
29759e39c5baSBill Taylor 	if (comm->hlc_status != IBT_SUCCESS) {
29769e39c5baSBill Taylor 		lstate->hls_err += 2;
29779e39c5baSBill Taylor 		return (EFAULT);
29789e39c5baSBill Taylor 	}
29799e39c5baSBill Taylor 	return (0);
29809e39c5baSBill Taylor }
29819e39c5baSBill Taylor 
29829e39c5baSBill Taylor /*
29839e39c5baSBill Taylor  * hermon_loopback_modify_qp
29849e39c5baSBill Taylor  */
29859e39c5baSBill Taylor static int
hermon_loopback_modify_qp(hermon_loopback_state_t * lstate,hermon_loopback_comm_t * comm,uint_t qp_num)29869e39c5baSBill Taylor hermon_loopback_modify_qp(hermon_loopback_state_t *lstate,
29879e39c5baSBill Taylor     hermon_loopback_comm_t *comm, uint_t qp_num)
29889e39c5baSBill Taylor {
29899e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm))
29909e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lstate))
29919e39c5baSBill Taylor 
29929e39c5baSBill Taylor 	/* Modify QP to INIT */
29939e39c5baSBill Taylor 	hermon_loopback_init_qp_info(lstate, comm);
29949e39c5baSBill Taylor 	comm->hlc_qp_info.qp_state = IBT_STATE_INIT;
29959e39c5baSBill Taylor 	comm->hlc_status = hermon_qp_modify(lstate->hls_state, comm->hlc_qp_hdl,
29969e39c5baSBill Taylor 	    IBT_CEP_SET_STATE, &comm->hlc_qp_info, &comm->hlc_queue_sizes);
29979e39c5baSBill Taylor 	if (comm->hlc_status != IBT_SUCCESS) {
29989e39c5baSBill Taylor 		return (EFAULT);
29999e39c5baSBill Taylor 	}
30009e39c5baSBill Taylor 
30019e39c5baSBill Taylor 	/*
30029e39c5baSBill Taylor 	 * Modify QP to RTR (set destination LID and QP number to local
30039e39c5baSBill Taylor 	 * LID and QP number)
30049e39c5baSBill Taylor 	 */
30059e39c5baSBill Taylor 	comm->hlc_qp_info.qp_state = IBT_STATE_RTR;
30069e39c5baSBill Taylor 	comm->hlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_dlid
30079e39c5baSBill Taylor 	    = lstate->hls_lid;
30089e39c5baSBill Taylor 	comm->hlc_qp_info.qp_transport.rc.rc_dst_qpn = qp_num;
30099e39c5baSBill Taylor 	comm->hlc_status = hermon_qp_modify(lstate->hls_state, comm->hlc_qp_hdl,
30109e39c5baSBill Taylor 	    IBT_CEP_SET_STATE, &comm->hlc_qp_info, &comm->hlc_queue_sizes);
30119e39c5baSBill Taylor 	if (comm->hlc_status != IBT_SUCCESS) {
30129e39c5baSBill Taylor 		lstate->hls_err += 1;
30139e39c5baSBill Taylor 		return (EFAULT);
30149e39c5baSBill Taylor 	}
30159e39c5baSBill Taylor 
30169e39c5baSBill Taylor 	/* Modify QP to RTS */
30179e39c5baSBill Taylor 	comm->hlc_qp_info.qp_current_state = IBT_STATE_RTR;
30189e39c5baSBill Taylor 	comm->hlc_qp_info.qp_state = IBT_STATE_RTS;
30199e39c5baSBill Taylor 	comm->hlc_status = hermon_qp_modify(lstate->hls_state, comm->hlc_qp_hdl,
30209e39c5baSBill Taylor 	    IBT_CEP_SET_STATE, &comm->hlc_qp_info, &comm->hlc_queue_sizes);
30219e39c5baSBill Taylor 	if (comm->hlc_status != IBT_SUCCESS) {
30229e39c5baSBill Taylor 		lstate->hls_err += 2;
30239e39c5baSBill Taylor 		return (EFAULT);
30249e39c5baSBill Taylor 	}
30259e39c5baSBill Taylor 	return (0);
30269e39c5baSBill Taylor }
30279e39c5baSBill Taylor 
30289e39c5baSBill Taylor /*
30299e39c5baSBill Taylor  * hermon_loopback_copyout
30309e39c5baSBill Taylor  */
30319e39c5baSBill Taylor static int
hermon_loopback_copyout(hermon_loopback_ioctl_t * lb,intptr_t arg,int mode)30329e39c5baSBill Taylor hermon_loopback_copyout(hermon_loopback_ioctl_t *lb, intptr_t arg, int mode)
30339e39c5baSBill Taylor {
30349e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
30359e39c5baSBill Taylor 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
30369e39c5baSBill Taylor 		hermon_loopback_ioctl32_t lb32;
30379e39c5baSBill Taylor 
30389e39c5baSBill Taylor 		lb32.alb_revision	= lb->alb_revision;
30399e39c5baSBill Taylor 		lb32.alb_send_buf	=
30409e39c5baSBill Taylor 		    (caddr32_t)(uintptr_t)lb->alb_send_buf;
30419e39c5baSBill Taylor 		lb32.alb_fail_buf	=
30429e39c5baSBill Taylor 		    (caddr32_t)(uintptr_t)lb->alb_fail_buf;
30439e39c5baSBill Taylor 		lb32.alb_buf_sz		= lb->alb_buf_sz;
30449e39c5baSBill Taylor 		lb32.alb_num_iter	= lb->alb_num_iter;
30459e39c5baSBill Taylor 		lb32.alb_pass_done	= lb->alb_pass_done;
30469e39c5baSBill Taylor 		lb32.alb_timeout	= lb->alb_timeout;
30479e39c5baSBill Taylor 		lb32.alb_error_type	= lb->alb_error_type;
30489e39c5baSBill Taylor 		lb32.alb_port_num	= lb->alb_port_num;
30499e39c5baSBill Taylor 		lb32.alb_num_retry	= lb->alb_num_retry;
30509e39c5baSBill Taylor 
30519e39c5baSBill Taylor 		if (ddi_copyout(&lb32, (void *)arg,
30529e39c5baSBill Taylor 		    sizeof (hermon_loopback_ioctl32_t), mode) != 0) {
30539e39c5baSBill Taylor 			return (EFAULT);
30549e39c5baSBill Taylor 		}
30559e39c5baSBill Taylor 	} else
30569e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
30579e39c5baSBill Taylor 	if (ddi_copyout(lb, (void *)arg, sizeof (hermon_loopback_ioctl_t),
30589e39c5baSBill Taylor 	    mode) != 0) {
30599e39c5baSBill Taylor 		return (EFAULT);
30609e39c5baSBill Taylor 	}
30619e39c5baSBill Taylor 	return (0);
30629e39c5baSBill Taylor }
30639e39c5baSBill Taylor 
30649e39c5baSBill Taylor /*
30659e39c5baSBill Taylor  * hermon_loopback_post_send
30669e39c5baSBill Taylor  */
30679e39c5baSBill Taylor static int
hermon_loopback_post_send(hermon_loopback_state_t * lstate,hermon_loopback_comm_t * tx,hermon_loopback_comm_t * rx)30689e39c5baSBill Taylor hermon_loopback_post_send(hermon_loopback_state_t *lstate,
30699e39c5baSBill Taylor     hermon_loopback_comm_t *tx, hermon_loopback_comm_t *rx)
30709e39c5baSBill Taylor {
30719e39c5baSBill Taylor 	int	 ret;
30729e39c5baSBill Taylor 
30739e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*tx))
30749e39c5baSBill Taylor 
30759e39c5baSBill Taylor 	bzero(&tx->hlc_sgl, sizeof (ibt_wr_ds_t));
30769e39c5baSBill Taylor 	bzero(&tx->hlc_wr, sizeof (ibt_send_wr_t));
30779e39c5baSBill Taylor 
30789e39c5baSBill Taylor 	/* Initialize local address for TX buffer */
30799e39c5baSBill Taylor 	tx->hlc_sgl.ds_va   = tx->hlc_mrdesc.md_vaddr;
30809e39c5baSBill Taylor 	tx->hlc_sgl.ds_key  = tx->hlc_mrdesc.md_lkey;
30819e39c5baSBill Taylor 	tx->hlc_sgl.ds_len  = tx->hlc_buf_sz;
30829e39c5baSBill Taylor 
30839e39c5baSBill Taylor 	/* Initialize the remaining details of the work request */
30849e39c5baSBill Taylor 	tx->hlc_wr.wr_id = tx->hlc_wrid++;
30859e39c5baSBill Taylor 	tx->hlc_wr.wr_flags  = IBT_WR_SEND_SIGNAL;
30869e39c5baSBill Taylor 	tx->hlc_wr.wr_nds    = 1;
30879e39c5baSBill Taylor 	tx->hlc_wr.wr_sgl    = &tx->hlc_sgl;
30889e39c5baSBill Taylor 	tx->hlc_wr.wr_opcode = IBT_WRC_RDMAW;
30899e39c5baSBill Taylor 	tx->hlc_wr.wr_trans  = IBT_RC_SRV;
30909e39c5baSBill Taylor 
30919e39c5baSBill Taylor 	/* Initialize the remote address for RX buffer */
30929e39c5baSBill Taylor 	tx->hlc_wr.wr.rc.rcwr.rdma.rdma_raddr = rx->hlc_mrdesc.md_vaddr;
30939e39c5baSBill Taylor 	tx->hlc_wr.wr.rc.rcwr.rdma.rdma_rkey  = rx->hlc_mrdesc.md_rkey;
30949e39c5baSBill Taylor 	tx->hlc_complete = 0;
30959e39c5baSBill Taylor 	ret = hermon_post_send(lstate->hls_state, tx->hlc_qp_hdl, &tx->hlc_wr,
30969e39c5baSBill Taylor 	    1, NULL);
30979e39c5baSBill Taylor 	if (ret != IBT_SUCCESS) {
30989e39c5baSBill Taylor 		return (EFAULT);
30999e39c5baSBill Taylor 	}
31009e39c5baSBill Taylor 	return (0);
31019e39c5baSBill Taylor }
31029e39c5baSBill Taylor 
31039e39c5baSBill Taylor /*
31049e39c5baSBill Taylor  * hermon_loopback_poll_cq
31059e39c5baSBill Taylor  */
31069e39c5baSBill Taylor static int
hermon_loopback_poll_cq(hermon_loopback_state_t * lstate,hermon_loopback_comm_t * comm)31079e39c5baSBill Taylor hermon_loopback_poll_cq(hermon_loopback_state_t *lstate,
31089e39c5baSBill Taylor     hermon_loopback_comm_t *comm)
31099e39c5baSBill Taylor {
31109e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm))
31119e39c5baSBill Taylor 
31129e39c5baSBill Taylor 	comm->hlc_wc.wc_status	= 0;
31139e39c5baSBill Taylor 	comm->hlc_num_polled	= 0;
31149e39c5baSBill Taylor 	comm->hlc_status = hermon_cq_poll(lstate->hls_state,
31159e39c5baSBill Taylor 	    comm->hlc_cqhdl[0], &comm->hlc_wc, 1, &comm->hlc_num_polled);
31169e39c5baSBill Taylor 	if ((comm->hlc_status == IBT_SUCCESS) &&
31179e39c5baSBill Taylor 	    (comm->hlc_wc.wc_status != IBT_WC_SUCCESS)) {
31189e39c5baSBill Taylor 		comm->hlc_status = ibc_get_ci_failure(0);
31199e39c5baSBill Taylor 	}
31209e39c5baSBill Taylor 	return (comm->hlc_status);
31219e39c5baSBill Taylor }
3122