xref: /onnv-gate/usr/src/uts/common/io/ib/adapters/hermon/hermon_ioctl.c (revision 12688:f2264e49907f)
19517SBill.Taylor@Sun.COM /*
29517SBill.Taylor@Sun.COM  * CDDL HEADER START
39517SBill.Taylor@Sun.COM  *
49517SBill.Taylor@Sun.COM  * The contents of this file are subject to the terms of the
59517SBill.Taylor@Sun.COM  * Common Development and Distribution License (the "License").
69517SBill.Taylor@Sun.COM  * You may not use this file except in compliance with the License.
79517SBill.Taylor@Sun.COM  *
89517SBill.Taylor@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99517SBill.Taylor@Sun.COM  * or http://www.opensolaris.org/os/licensing.
109517SBill.Taylor@Sun.COM  * See the License for the specific language governing permissions
119517SBill.Taylor@Sun.COM  * and limitations under the License.
129517SBill.Taylor@Sun.COM  *
139517SBill.Taylor@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
149517SBill.Taylor@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159517SBill.Taylor@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
169517SBill.Taylor@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
179517SBill.Taylor@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
189517SBill.Taylor@Sun.COM  *
199517SBill.Taylor@Sun.COM  * CDDL HEADER END
209517SBill.Taylor@Sun.COM  */
219517SBill.Taylor@Sun.COM 
229517SBill.Taylor@Sun.COM /*
23*12688SWilliam.Taylor@Oracle.COM  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
249517SBill.Taylor@Sun.COM  */
259517SBill.Taylor@Sun.COM 
269517SBill.Taylor@Sun.COM /*
279517SBill.Taylor@Sun.COM  * hermon_ioctl.c
289517SBill.Taylor@Sun.COM  *    Hemron IOCTL Routines
299517SBill.Taylor@Sun.COM  *
309517SBill.Taylor@Sun.COM  *    Implements all ioctl access into the driver.  This includes all routines
319517SBill.Taylor@Sun.COM  *    necessary for updating firmware, accessing the hermon flash device, and
329517SBill.Taylor@Sun.COM  *    providing interfaces for VTS.
339517SBill.Taylor@Sun.COM  */
349517SBill.Taylor@Sun.COM 
359517SBill.Taylor@Sun.COM #include <sys/types.h>
369517SBill.Taylor@Sun.COM #include <sys/conf.h>
379517SBill.Taylor@Sun.COM #include <sys/ddi.h>
389517SBill.Taylor@Sun.COM #include <sys/sunddi.h>
399517SBill.Taylor@Sun.COM #include <sys/modctl.h>
409517SBill.Taylor@Sun.COM #include <sys/file.h>
419517SBill.Taylor@Sun.COM 
429517SBill.Taylor@Sun.COM #include <sys/ib/adapters/hermon/hermon.h>
439517SBill.Taylor@Sun.COM 
449517SBill.Taylor@Sun.COM /* Hemron HCA state pointer (extern) */
459517SBill.Taylor@Sun.COM extern void	*hermon_statep;
469517SBill.Taylor@Sun.COM extern int	hermon_verbose;
479517SBill.Taylor@Sun.COM 
489517SBill.Taylor@Sun.COM #define	DO_WRCONF	1
499517SBill.Taylor@Sun.COM static int do_bar0 = 1;
509517SBill.Taylor@Sun.COM 
519517SBill.Taylor@Sun.COM /*
529517SBill.Taylor@Sun.COM  * The ioctl declarations (for firmware flash burning, register read/write
539517SBill.Taylor@Sun.COM  * (DEBUG-only), and VTS interfaces)
549517SBill.Taylor@Sun.COM  */
559517SBill.Taylor@Sun.COM static int hermon_ioctl_flash_read(hermon_state_t *state, dev_t dev,
569517SBill.Taylor@Sun.COM     intptr_t arg, int mode);
579517SBill.Taylor@Sun.COM static int hermon_ioctl_flash_write(hermon_state_t *state, dev_t dev,
589517SBill.Taylor@Sun.COM     intptr_t arg, int mode);
599517SBill.Taylor@Sun.COM static int hermon_ioctl_flash_erase(hermon_state_t *state, dev_t dev,
609517SBill.Taylor@Sun.COM     intptr_t arg, int mode);
619517SBill.Taylor@Sun.COM static int hermon_ioctl_flash_init(hermon_state_t *state, dev_t dev,
629517SBill.Taylor@Sun.COM     intptr_t arg, int mode);
639517SBill.Taylor@Sun.COM static int hermon_ioctl_flash_fini(hermon_state_t *state, dev_t dev);
649517SBill.Taylor@Sun.COM static int hermon_ioctl_flash_cleanup(hermon_state_t *state);
659517SBill.Taylor@Sun.COM static int hermon_ioctl_flash_cleanup_nolock(hermon_state_t *state);
669517SBill.Taylor@Sun.COM #ifdef	DEBUG
679517SBill.Taylor@Sun.COM static int hermon_ioctl_reg_write(hermon_state_t *state, intptr_t arg,
689517SBill.Taylor@Sun.COM     int mode);
699517SBill.Taylor@Sun.COM static int hermon_ioctl_reg_read(hermon_state_t *state, intptr_t arg,
709517SBill.Taylor@Sun.COM     int mode);
719517SBill.Taylor@Sun.COM #endif	/* DEBUG */
729517SBill.Taylor@Sun.COM static int hermon_ioctl_write_boot_addr(hermon_state_t *state, dev_t dev,
739517SBill.Taylor@Sun.COM     intptr_t arg, int mode);
749517SBill.Taylor@Sun.COM static int hermon_ioctl_info(hermon_state_t *state, dev_t dev,
759517SBill.Taylor@Sun.COM     intptr_t arg, int mode);
769517SBill.Taylor@Sun.COM static int hermon_ioctl_ports(hermon_state_t *state, intptr_t arg,
779517SBill.Taylor@Sun.COM     int mode);
789517SBill.Taylor@Sun.COM static int hermon_ioctl_loopback(hermon_state_t *state, intptr_t arg,
799517SBill.Taylor@Sun.COM     int mode);
809517SBill.Taylor@Sun.COM 
819517SBill.Taylor@Sun.COM /* Hemron Flash Functions */
829517SBill.Taylor@Sun.COM static void hermon_flash_spi_exec_command(hermon_state_t *state,
839517SBill.Taylor@Sun.COM     ddi_acc_handle_t hdl, uint32_t cmd);
849517SBill.Taylor@Sun.COM static int hermon_flash_read_sector(hermon_state_t *state,
859517SBill.Taylor@Sun.COM     uint32_t sector_num);
869517SBill.Taylor@Sun.COM static int hermon_flash_read_quadlet(hermon_state_t *state, uint32_t *data,
879517SBill.Taylor@Sun.COM     uint32_t addr);
889517SBill.Taylor@Sun.COM static int hermon_flash_write_sector(hermon_state_t *state,
899517SBill.Taylor@Sun.COM     uint32_t sector_num);
909517SBill.Taylor@Sun.COM static int hermon_flash_spi_write_dword(hermon_state_t *state,
919517SBill.Taylor@Sun.COM     uint32_t addr, uint32_t data);
929517SBill.Taylor@Sun.COM static int hermon_flash_write_byte(hermon_state_t *state, uint32_t addr,
939517SBill.Taylor@Sun.COM     uchar_t data);
949517SBill.Taylor@Sun.COM static int hermon_flash_erase_sector(hermon_state_t *state,
959517SBill.Taylor@Sun.COM     uint32_t sector_num);
969517SBill.Taylor@Sun.COM static int hermon_flash_erase_chip(hermon_state_t *state);
979517SBill.Taylor@Sun.COM static int hermon_flash_bank(hermon_state_t *state, uint32_t addr);
989517SBill.Taylor@Sun.COM static uint32_t hermon_flash_read(hermon_state_t *state, uint32_t addr,
999517SBill.Taylor@Sun.COM     int *err);
1009517SBill.Taylor@Sun.COM static void hermon_flash_write(hermon_state_t *state, uint32_t addr,
1019517SBill.Taylor@Sun.COM     uchar_t data, int *err);
1029517SBill.Taylor@Sun.COM static int hermon_flash_spi_wait_wip(hermon_state_t *state);
1039517SBill.Taylor@Sun.COM static void hermon_flash_spi_write_enable(hermon_state_t *state);
1049517SBill.Taylor@Sun.COM static int hermon_flash_init(hermon_state_t *state);
1059517SBill.Taylor@Sun.COM static int hermon_flash_cfi_init(hermon_state_t *state, uint32_t *cfi_info,
1069517SBill.Taylor@Sun.COM     int *intel_xcmd);
1079517SBill.Taylor@Sun.COM static int hermon_flash_fini(hermon_state_t *state);
1089517SBill.Taylor@Sun.COM static int hermon_flash_reset(hermon_state_t *state);
1099517SBill.Taylor@Sun.COM static uint32_t hermon_flash_read_cfg(hermon_state_t *state,
1109517SBill.Taylor@Sun.COM     ddi_acc_handle_t pci_config_hdl, uint32_t addr);
1119517SBill.Taylor@Sun.COM #ifdef DO_WRCONF
1129517SBill.Taylor@Sun.COM static void hermon_flash_write_cfg(hermon_state_t *state,
1139517SBill.Taylor@Sun.COM     ddi_acc_handle_t pci_config_hdl, uint32_t addr, uint32_t data);
1149517SBill.Taylor@Sun.COM static void hermon_flash_write_cfg_helper(hermon_state_t *state,
1159517SBill.Taylor@Sun.COM     ddi_acc_handle_t pci_config_hdl, uint32_t addr, uint32_t data);
1169517SBill.Taylor@Sun.COM static void hermon_flash_write_confirm(hermon_state_t *state,
1179517SBill.Taylor@Sun.COM     ddi_acc_handle_t pci_config_hdl);
1189517SBill.Taylor@Sun.COM #endif
1199517SBill.Taylor@Sun.COM static void hermon_flash_cfi_byte(uint8_t *ch, uint32_t dword, int i);
1209517SBill.Taylor@Sun.COM static void hermon_flash_cfi_dword(uint32_t *dword, uint8_t *ch, int i);
1219517SBill.Taylor@Sun.COM 
1229517SBill.Taylor@Sun.COM /* Hemron loopback test functions */
1239517SBill.Taylor@Sun.COM static void hermon_loopback_free_qps(hermon_loopback_state_t *lstate);
1249517SBill.Taylor@Sun.COM static void hermon_loopback_free_state(hermon_loopback_state_t *lstate);
1259517SBill.Taylor@Sun.COM static int hermon_loopback_init(hermon_state_t *state,
1269517SBill.Taylor@Sun.COM     hermon_loopback_state_t *lstate);
1279517SBill.Taylor@Sun.COM static void hermon_loopback_init_qp_info(hermon_loopback_state_t *lstate,
1289517SBill.Taylor@Sun.COM     hermon_loopback_comm_t *comm);
1299517SBill.Taylor@Sun.COM static int hermon_loopback_alloc_mem(hermon_loopback_state_t *lstate,
1309517SBill.Taylor@Sun.COM     hermon_loopback_comm_t *comm, int sz);
1319517SBill.Taylor@Sun.COM static int hermon_loopback_alloc_qps(hermon_loopback_state_t *lstate,
1329517SBill.Taylor@Sun.COM     hermon_loopback_comm_t *comm);
1339517SBill.Taylor@Sun.COM static int hermon_loopback_modify_qp(hermon_loopback_state_t *lstate,
1349517SBill.Taylor@Sun.COM     hermon_loopback_comm_t *comm, uint_t qp_num);
1359517SBill.Taylor@Sun.COM static int hermon_loopback_copyout(hermon_loopback_ioctl_t *lb,
1369517SBill.Taylor@Sun.COM     intptr_t arg, int mode);
1379517SBill.Taylor@Sun.COM static int hermon_loopback_post_send(hermon_loopback_state_t *lstate,
1389517SBill.Taylor@Sun.COM     hermon_loopback_comm_t *tx, hermon_loopback_comm_t *rx);
1399517SBill.Taylor@Sun.COM static int hermon_loopback_poll_cq(hermon_loopback_state_t *lstate,
1409517SBill.Taylor@Sun.COM     hermon_loopback_comm_t *comm);
1419517SBill.Taylor@Sun.COM 
1429517SBill.Taylor@Sun.COM /* Patchable timeout values for flash operations */
1439517SBill.Taylor@Sun.COM int hermon_hw_flash_timeout_gpio_sema = HERMON_HW_FLASH_TIMEOUT_GPIO_SEMA;
1449517SBill.Taylor@Sun.COM int hermon_hw_flash_timeout_config = HERMON_HW_FLASH_TIMEOUT_CONFIG;
1459517SBill.Taylor@Sun.COM int hermon_hw_flash_timeout_write = HERMON_HW_FLASH_TIMEOUT_WRITE;
1469517SBill.Taylor@Sun.COM int hermon_hw_flash_timeout_erase = HERMON_HW_FLASH_TIMEOUT_ERASE;
1479517SBill.Taylor@Sun.COM 
1489517SBill.Taylor@Sun.COM /*
1499517SBill.Taylor@Sun.COM  * hermon_ioctl()
1509517SBill.Taylor@Sun.COM  */
1519517SBill.Taylor@Sun.COM /* ARGSUSED */
1529517SBill.Taylor@Sun.COM int
hermon_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)1539517SBill.Taylor@Sun.COM hermon_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
1549517SBill.Taylor@Sun.COM     int *rvalp)
1559517SBill.Taylor@Sun.COM {
1569517SBill.Taylor@Sun.COM 	hermon_state_t	*state;
1579517SBill.Taylor@Sun.COM 	minor_t		instance;
1589517SBill.Taylor@Sun.COM 	int		status;
1599517SBill.Taylor@Sun.COM 
1609517SBill.Taylor@Sun.COM 	if (drv_priv(credp) != 0) {
1619517SBill.Taylor@Sun.COM 		return (EPERM);
1629517SBill.Taylor@Sun.COM 	}
1639517SBill.Taylor@Sun.COM 
1649517SBill.Taylor@Sun.COM 	instance = HERMON_DEV_INSTANCE(dev);
1659517SBill.Taylor@Sun.COM 	if (instance == (minor_t)-1) {
1669517SBill.Taylor@Sun.COM 		return (EBADF);
1679517SBill.Taylor@Sun.COM 	}
1689517SBill.Taylor@Sun.COM 
1699517SBill.Taylor@Sun.COM 	state = ddi_get_soft_state(hermon_statep, instance);
1709517SBill.Taylor@Sun.COM 	if (state == NULL) {
1719517SBill.Taylor@Sun.COM 		return (EBADF);
1729517SBill.Taylor@Sun.COM 	}
1739517SBill.Taylor@Sun.COM 
1749517SBill.Taylor@Sun.COM 	status = 0;
1759517SBill.Taylor@Sun.COM 
1769517SBill.Taylor@Sun.COM 	switch (cmd) {
1779517SBill.Taylor@Sun.COM 	case HERMON_IOCTL_FLASH_READ:
1789517SBill.Taylor@Sun.COM 		status = hermon_ioctl_flash_read(state, dev, arg, mode);
1799517SBill.Taylor@Sun.COM 		break;
1809517SBill.Taylor@Sun.COM 
1819517SBill.Taylor@Sun.COM 	case HERMON_IOCTL_FLASH_WRITE:
1829517SBill.Taylor@Sun.COM 		status = hermon_ioctl_flash_write(state, dev, arg, mode);
1839517SBill.Taylor@Sun.COM 		break;
1849517SBill.Taylor@Sun.COM 
1859517SBill.Taylor@Sun.COM 	case HERMON_IOCTL_FLASH_ERASE:
1869517SBill.Taylor@Sun.COM 		status = hermon_ioctl_flash_erase(state, dev, arg, mode);
1879517SBill.Taylor@Sun.COM 		break;
1889517SBill.Taylor@Sun.COM 
1899517SBill.Taylor@Sun.COM 	case HERMON_IOCTL_FLASH_INIT:
1909517SBill.Taylor@Sun.COM 		status = hermon_ioctl_flash_init(state, dev, arg, mode);
1919517SBill.Taylor@Sun.COM 		break;
1929517SBill.Taylor@Sun.COM 
1939517SBill.Taylor@Sun.COM 	case HERMON_IOCTL_FLASH_FINI:
1949517SBill.Taylor@Sun.COM 		status = hermon_ioctl_flash_fini(state, dev);
1959517SBill.Taylor@Sun.COM 		break;
1969517SBill.Taylor@Sun.COM 
1979517SBill.Taylor@Sun.COM 	case HERMON_IOCTL_INFO:
1989517SBill.Taylor@Sun.COM 		status = hermon_ioctl_info(state, dev, arg, mode);
1999517SBill.Taylor@Sun.COM 		break;
2009517SBill.Taylor@Sun.COM 
2019517SBill.Taylor@Sun.COM 	case HERMON_IOCTL_PORTS:
2029517SBill.Taylor@Sun.COM 		status = hermon_ioctl_ports(state, arg, mode);
2039517SBill.Taylor@Sun.COM 		break;
2049517SBill.Taylor@Sun.COM 
2059517SBill.Taylor@Sun.COM 	case HERMON_IOCTL_LOOPBACK:
2069517SBill.Taylor@Sun.COM 		status = hermon_ioctl_loopback(state, arg, mode);
2079517SBill.Taylor@Sun.COM 		break;
2089517SBill.Taylor@Sun.COM 
2099517SBill.Taylor@Sun.COM #ifdef	DEBUG
2109517SBill.Taylor@Sun.COM 	case HERMON_IOCTL_REG_WRITE:
2119517SBill.Taylor@Sun.COM 		status = hermon_ioctl_reg_write(state, arg, mode);
2129517SBill.Taylor@Sun.COM 		break;
2139517SBill.Taylor@Sun.COM 
2149517SBill.Taylor@Sun.COM 	case HERMON_IOCTL_REG_READ:
2159517SBill.Taylor@Sun.COM 		status = hermon_ioctl_reg_read(state, arg, mode);
2169517SBill.Taylor@Sun.COM 		break;
2179517SBill.Taylor@Sun.COM #endif	/* DEBUG */
2189517SBill.Taylor@Sun.COM 
2199517SBill.Taylor@Sun.COM 	case HERMON_IOCTL_DDR_READ:
2209517SBill.Taylor@Sun.COM 		/* XXX guard until the ioctl header is cleaned up */
2219517SBill.Taylor@Sun.COM 		status = ENODEV;
2229517SBill.Taylor@Sun.COM 		break;
2239517SBill.Taylor@Sun.COM 
2249517SBill.Taylor@Sun.COM 	case HERMON_IOCTL_WRITE_BOOT_ADDR:
2259517SBill.Taylor@Sun.COM 		status = hermon_ioctl_write_boot_addr(state, dev, arg, mode);
2269517SBill.Taylor@Sun.COM 		break;
2279517SBill.Taylor@Sun.COM 
2289517SBill.Taylor@Sun.COM 	default:
2299517SBill.Taylor@Sun.COM 		status = ENOTTY;
2309517SBill.Taylor@Sun.COM 		break;
2319517SBill.Taylor@Sun.COM 	}
2329517SBill.Taylor@Sun.COM 	*rvalp = status;
2339517SBill.Taylor@Sun.COM 
2349517SBill.Taylor@Sun.COM 	return (status);
2359517SBill.Taylor@Sun.COM }
2369517SBill.Taylor@Sun.COM 
2379517SBill.Taylor@Sun.COM /*
2389517SBill.Taylor@Sun.COM  * hermon_ioctl_flash_read()
2399517SBill.Taylor@Sun.COM  */
2409517SBill.Taylor@Sun.COM static int
hermon_ioctl_flash_read(hermon_state_t * state,dev_t dev,intptr_t arg,int mode)2419517SBill.Taylor@Sun.COM hermon_ioctl_flash_read(hermon_state_t *state, dev_t dev, intptr_t arg,
2429517SBill.Taylor@Sun.COM     int mode)
2439517SBill.Taylor@Sun.COM {
2449517SBill.Taylor@Sun.COM 	hermon_flash_ioctl_t ioctl_info;
2459517SBill.Taylor@Sun.COM 	int status = 0;
2469517SBill.Taylor@Sun.COM 
2479517SBill.Taylor@Sun.COM 	/*
2489517SBill.Taylor@Sun.COM 	 * Check that flash init ioctl has been called first.  And check
2499517SBill.Taylor@Sun.COM 	 * that the same dev_t that called init is the one calling read now.
2509517SBill.Taylor@Sun.COM 	 */
2519517SBill.Taylor@Sun.COM 	mutex_enter(&state->hs_fw_flashlock);
2529517SBill.Taylor@Sun.COM 	if ((state->hs_fw_flashdev != dev) ||
2539517SBill.Taylor@Sun.COM 	    (state->hs_fw_flashstarted == 0)) {
2549517SBill.Taylor@Sun.COM 		mutex_exit(&state->hs_fw_flashlock);
2559517SBill.Taylor@Sun.COM 		return (EIO);
2569517SBill.Taylor@Sun.COM 	}
2579517SBill.Taylor@Sun.COM 
2589517SBill.Taylor@Sun.COM 	/* copy user struct to kernel */
2599517SBill.Taylor@Sun.COM #ifdef _MULTI_DATAMODEL
2609517SBill.Taylor@Sun.COM 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
2619517SBill.Taylor@Sun.COM 		hermon_flash_ioctl32_t info32;
2629517SBill.Taylor@Sun.COM 
2639517SBill.Taylor@Sun.COM 		if (ddi_copyin((void *)arg, &info32,
2649517SBill.Taylor@Sun.COM 		    sizeof (hermon_flash_ioctl32_t), mode) != 0) {
2659517SBill.Taylor@Sun.COM 			mutex_exit(&state->hs_fw_flashlock);
2669517SBill.Taylor@Sun.COM 			return (EFAULT);
2679517SBill.Taylor@Sun.COM 		}
2689517SBill.Taylor@Sun.COM 		ioctl_info.af_type = info32.af_type;
2699517SBill.Taylor@Sun.COM 		ioctl_info.af_sector = (caddr_t)(uintptr_t)info32.af_sector;
2709517SBill.Taylor@Sun.COM 		ioctl_info.af_sector_num = info32.af_sector_num;
2719517SBill.Taylor@Sun.COM 		ioctl_info.af_addr = info32.af_addr;
2729517SBill.Taylor@Sun.COM 	} else
2739517SBill.Taylor@Sun.COM #endif /* _MULTI_DATAMODEL */
2749517SBill.Taylor@Sun.COM 	if (ddi_copyin((void *)arg, &ioctl_info, sizeof (hermon_flash_ioctl_t),
2759517SBill.Taylor@Sun.COM 	    mode) != 0) {
2769517SBill.Taylor@Sun.COM 		mutex_exit(&state->hs_fw_flashlock);
2779517SBill.Taylor@Sun.COM 		return (EFAULT);
2789517SBill.Taylor@Sun.COM 	}
2799517SBill.Taylor@Sun.COM 
2809517SBill.Taylor@Sun.COM 	/*
2819517SBill.Taylor@Sun.COM 	 * Determine type of READ ioctl
2829517SBill.Taylor@Sun.COM 	 */
2839517SBill.Taylor@Sun.COM 	switch (ioctl_info.af_type) {
2849517SBill.Taylor@Sun.COM 	case HERMON_FLASH_READ_SECTOR:
2859517SBill.Taylor@Sun.COM 		/* Check if sector num is too large for flash device */
2869517SBill.Taylor@Sun.COM 		if (ioctl_info.af_sector_num >=
2879517SBill.Taylor@Sun.COM 		    (state->hs_fw_device_sz >> state->hs_fw_log_sector_sz)) {
2889517SBill.Taylor@Sun.COM 			mutex_exit(&state->hs_fw_flashlock);
2899517SBill.Taylor@Sun.COM 			return (EFAULT);
2909517SBill.Taylor@Sun.COM 		}
2919517SBill.Taylor@Sun.COM 
2929517SBill.Taylor@Sun.COM 		/* Perform the Sector Read */
2939517SBill.Taylor@Sun.COM 		if ((status = hermon_flash_reset(state)) != 0 ||
2949517SBill.Taylor@Sun.COM 		    (status = hermon_flash_read_sector(state,
2959517SBill.Taylor@Sun.COM 		    ioctl_info.af_sector_num)) != 0) {
2969517SBill.Taylor@Sun.COM 			mutex_exit(&state->hs_fw_flashlock);
2979517SBill.Taylor@Sun.COM 			return (status);
2989517SBill.Taylor@Sun.COM 		}
2999517SBill.Taylor@Sun.COM 
3009517SBill.Taylor@Sun.COM 		/* copyout the firmware sector image data */
3019517SBill.Taylor@Sun.COM 		if (ddi_copyout(&state->hs_fw_sector[0],
3029517SBill.Taylor@Sun.COM 		    &ioctl_info.af_sector[0], 1 << state->hs_fw_log_sector_sz,
3039517SBill.Taylor@Sun.COM 		    mode) != 0) {
3049517SBill.Taylor@Sun.COM 			mutex_exit(&state->hs_fw_flashlock);
3059517SBill.Taylor@Sun.COM 			return (EFAULT);
3069517SBill.Taylor@Sun.COM 		}
3079517SBill.Taylor@Sun.COM 		break;
3089517SBill.Taylor@Sun.COM 
3099517SBill.Taylor@Sun.COM 	case HERMON_FLASH_READ_QUADLET:
3109517SBill.Taylor@Sun.COM 		/* Check if addr is too large for flash device */
3119517SBill.Taylor@Sun.COM 		if (ioctl_info.af_addr >= state->hs_fw_device_sz) {
3129517SBill.Taylor@Sun.COM 			mutex_exit(&state->hs_fw_flashlock);
3139517SBill.Taylor@Sun.COM 			return (EFAULT);
3149517SBill.Taylor@Sun.COM 		}
3159517SBill.Taylor@Sun.COM 
3169517SBill.Taylor@Sun.COM 		/* Perform the Quadlet Read */
3179517SBill.Taylor@Sun.COM 		if ((status = hermon_flash_reset(state)) != 0 ||
3189517SBill.Taylor@Sun.COM 		    (status = hermon_flash_read_quadlet(state,
3199517SBill.Taylor@Sun.COM 		    &ioctl_info.af_quadlet, ioctl_info.af_addr)) != 0) {
3209517SBill.Taylor@Sun.COM 			mutex_exit(&state->hs_fw_flashlock);
3219517SBill.Taylor@Sun.COM 			return (status);
3229517SBill.Taylor@Sun.COM 		}
3239517SBill.Taylor@Sun.COM 		break;
3249517SBill.Taylor@Sun.COM 
3259517SBill.Taylor@Sun.COM 	default:
3269517SBill.Taylor@Sun.COM 		mutex_exit(&state->hs_fw_flashlock);
3279517SBill.Taylor@Sun.COM 		return (EINVAL);
3289517SBill.Taylor@Sun.COM 	}
3299517SBill.Taylor@Sun.COM 
3309517SBill.Taylor@Sun.COM 	/* copy results back to userland */
3319517SBill.Taylor@Sun.COM #ifdef _MULTI_DATAMODEL
3329517SBill.Taylor@Sun.COM 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
3339517SBill.Taylor@Sun.COM 		hermon_flash_ioctl32_t info32;
3349517SBill.Taylor@Sun.COM 
3359517SBill.Taylor@Sun.COM 		info32.af_quadlet = ioctl_info.af_quadlet;
3369517SBill.Taylor@Sun.COM 		info32.af_type = ioctl_info.af_type;
3379517SBill.Taylor@Sun.COM 		info32.af_sector_num = ioctl_info.af_sector_num;
3389517SBill.Taylor@Sun.COM 		info32.af_sector = (caddr32_t)(uintptr_t)ioctl_info.af_sector;
3399517SBill.Taylor@Sun.COM 		info32.af_addr = ioctl_info.af_addr;
3409517SBill.Taylor@Sun.COM 
3419517SBill.Taylor@Sun.COM 		if (ddi_copyout(&info32, (void *)arg,
3429517SBill.Taylor@Sun.COM 		    sizeof (hermon_flash_ioctl32_t), mode) != 0) {
3439517SBill.Taylor@Sun.COM 			mutex_exit(&state->hs_fw_flashlock);
3449517SBill.Taylor@Sun.COM 			return (EFAULT);
3459517SBill.Taylor@Sun.COM 		}
3469517SBill.Taylor@Sun.COM 	} else
3479517SBill.Taylor@Sun.COM #endif /* _MULTI_DATAMODEL */
3489517SBill.Taylor@Sun.COM 	if (ddi_copyout(&ioctl_info, (void *)arg,
3499517SBill.Taylor@Sun.COM 	    sizeof (hermon_flash_ioctl_t), mode) != 0) {
3509517SBill.Taylor@Sun.COM 		mutex_exit(&state->hs_fw_flashlock);
3519517SBill.Taylor@Sun.COM 		return (EFAULT);
3529517SBill.Taylor@Sun.COM 	}
3539517SBill.Taylor@Sun.COM 
3549517SBill.Taylor@Sun.COM 	mutex_exit(&state->hs_fw_flashlock);
3559517SBill.Taylor@Sun.COM 	return (status);
3569517SBill.Taylor@Sun.COM }
3579517SBill.Taylor@Sun.COM 
3589517SBill.Taylor@Sun.COM /*
3599517SBill.Taylor@Sun.COM  * hermon_ioctl_flash_write()
3609517SBill.Taylor@Sun.COM  */
3619517SBill.Taylor@Sun.COM static int
hermon_ioctl_flash_write(hermon_state_t * state,dev_t dev,intptr_t arg,int mode)3629517SBill.Taylor@Sun.COM hermon_ioctl_flash_write(hermon_state_t *state, dev_t dev, intptr_t arg,
3639517SBill.Taylor@Sun.COM     int mode)
3649517SBill.Taylor@Sun.COM {
3659517SBill.Taylor@Sun.COM 	hermon_flash_ioctl_t	ioctl_info;
3669517SBill.Taylor@Sun.COM 	int status = 0;
3679517SBill.Taylor@Sun.COM 
3689517SBill.Taylor@Sun.COM 	/*
3699517SBill.Taylor@Sun.COM 	 * Check that flash init ioctl has been called first.  And check
3709517SBill.Taylor@Sun.COM 	 * that the same dev_t that called init is the one calling write now.
3719517SBill.Taylor@Sun.COM 	 */
3729517SBill.Taylor@Sun.COM 	mutex_enter(&state->hs_fw_flashlock);
3739517SBill.Taylor@Sun.COM 	if ((state->hs_fw_flashdev != dev) ||
3749517SBill.Taylor@Sun.COM 	    (state->hs_fw_flashstarted == 0)) {
3759517SBill.Taylor@Sun.COM 		mutex_exit(&state->hs_fw_flashlock);
3769517SBill.Taylor@Sun.COM 		return (EIO);
3779517SBill.Taylor@Sun.COM 	}
3789517SBill.Taylor@Sun.COM 
3799517SBill.Taylor@Sun.COM 	/* copy user struct to kernel */
3809517SBill.Taylor@Sun.COM #ifdef _MULTI_DATAMODEL
3819517SBill.Taylor@Sun.COM 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
3829517SBill.Taylor@Sun.COM 		hermon_flash_ioctl32_t info32;
3839517SBill.Taylor@Sun.COM 
3849517SBill.Taylor@Sun.COM 		if (ddi_copyin((void *)arg, &info32,
3859517SBill.Taylor@Sun.COM 		    sizeof (hermon_flash_ioctl32_t), mode) != 0) {
3869517SBill.Taylor@Sun.COM 			mutex_exit(&state->hs_fw_flashlock);
3879517SBill.Taylor@Sun.COM 			return (EFAULT);
3889517SBill.Taylor@Sun.COM 		}
3899517SBill.Taylor@Sun.COM 		ioctl_info.af_type = info32.af_type;
3909517SBill.Taylor@Sun.COM 		ioctl_info.af_sector = (caddr_t)(uintptr_t)info32.af_sector;
3919517SBill.Taylor@Sun.COM 		ioctl_info.af_sector_num = info32.af_sector_num;
3929517SBill.Taylor@Sun.COM 		ioctl_info.af_addr = info32.af_addr;
3939517SBill.Taylor@Sun.COM 		ioctl_info.af_byte = info32.af_byte;
3949517SBill.Taylor@Sun.COM 	} else
3959517SBill.Taylor@Sun.COM #endif /* _MULTI_DATAMODEL */
3969517SBill.Taylor@Sun.COM 	if (ddi_copyin((void *)arg, &ioctl_info,
3979517SBill.Taylor@Sun.COM 	    sizeof (hermon_flash_ioctl_t), mode) != 0) {
3989517SBill.Taylor@Sun.COM 		mutex_exit(&state->hs_fw_flashlock);
3999517SBill.Taylor@Sun.COM 		return (EFAULT);
4009517SBill.Taylor@Sun.COM 	}
4019517SBill.Taylor@Sun.COM 
4029517SBill.Taylor@Sun.COM 	/*
4039517SBill.Taylor@Sun.COM 	 * Determine type of WRITE ioctl
4049517SBill.Taylor@Sun.COM 	 */
4059517SBill.Taylor@Sun.COM 	switch (ioctl_info.af_type) {
4069517SBill.Taylor@Sun.COM 	case HERMON_FLASH_WRITE_SECTOR:
4079517SBill.Taylor@Sun.COM 		/* Check if sector num is too large for flash device */
4089517SBill.Taylor@Sun.COM 		if (ioctl_info.af_sector_num >=
4099517SBill.Taylor@Sun.COM 		    (state->hs_fw_device_sz >> state->hs_fw_log_sector_sz)) {
4109517SBill.Taylor@Sun.COM 			mutex_exit(&state->hs_fw_flashlock);
4119517SBill.Taylor@Sun.COM 			return (EFAULT);
4129517SBill.Taylor@Sun.COM 		}
4139517SBill.Taylor@Sun.COM 
4149517SBill.Taylor@Sun.COM 		/* copy in fw sector image data */
4159517SBill.Taylor@Sun.COM 		if (ddi_copyin(&ioctl_info.af_sector[0],
4169517SBill.Taylor@Sun.COM 		    &state->hs_fw_sector[0], 1 << state->hs_fw_log_sector_sz,
4179517SBill.Taylor@Sun.COM 		    mode) != 0) {
4189517SBill.Taylor@Sun.COM 			mutex_exit(&state->hs_fw_flashlock);
4199517SBill.Taylor@Sun.COM 			return (EFAULT);
4209517SBill.Taylor@Sun.COM 		}
4219517SBill.Taylor@Sun.COM 
4229517SBill.Taylor@Sun.COM 		/* Perform Write Sector */
4239517SBill.Taylor@Sun.COM 		status = hermon_flash_write_sector(state,
4249517SBill.Taylor@Sun.COM 		    ioctl_info.af_sector_num);
4259517SBill.Taylor@Sun.COM 		break;
4269517SBill.Taylor@Sun.COM 
4279517SBill.Taylor@Sun.COM 	case HERMON_FLASH_WRITE_BYTE:
4289517SBill.Taylor@Sun.COM 		/* Check if addr is too large for flash device */
4299517SBill.Taylor@Sun.COM 		if (ioctl_info.af_addr >= state->hs_fw_device_sz) {
4309517SBill.Taylor@Sun.COM 			mutex_exit(&state->hs_fw_flashlock);
4319517SBill.Taylor@Sun.COM 			return (EFAULT);
4329517SBill.Taylor@Sun.COM 		}
4339517SBill.Taylor@Sun.COM 
4349517SBill.Taylor@Sun.COM 		/* Perform Write Byte */
4359517SBill.Taylor@Sun.COM 		/*
4369517SBill.Taylor@Sun.COM 		 * CMJ -- is a reset really needed before and after writing
4379517SBill.Taylor@Sun.COM 		 * each byte?  This code came from arbel, but we should look
4389517SBill.Taylor@Sun.COM 		 * into this.  Also, for SPI, no reset is actually performed.
4399517SBill.Taylor@Sun.COM 		 */
4409517SBill.Taylor@Sun.COM 		if ((status = hermon_flash_bank(state,
4419517SBill.Taylor@Sun.COM 		    ioctl_info.af_addr)) != 0 ||
4429517SBill.Taylor@Sun.COM 		    (status = hermon_flash_reset(state)) != 0 ||
4439517SBill.Taylor@Sun.COM 		    (status = hermon_flash_write_byte(state,
4449517SBill.Taylor@Sun.COM 		    ioctl_info.af_addr, ioctl_info.af_byte)) != 0 ||
4459517SBill.Taylor@Sun.COM 		    (status = hermon_flash_reset(state)) != 0) {
4469517SBill.Taylor@Sun.COM 			mutex_exit(&state->hs_fw_flashlock);
4479517SBill.Taylor@Sun.COM 			return (status);
4489517SBill.Taylor@Sun.COM 		}
4499517SBill.Taylor@Sun.COM 		break;
4509517SBill.Taylor@Sun.COM 
4519517SBill.Taylor@Sun.COM 	default:
4529517SBill.Taylor@Sun.COM 		status = EINVAL;
4539517SBill.Taylor@Sun.COM 		break;
4549517SBill.Taylor@Sun.COM 	}
4559517SBill.Taylor@Sun.COM 
4569517SBill.Taylor@Sun.COM 	mutex_exit(&state->hs_fw_flashlock);
4579517SBill.Taylor@Sun.COM 	return (status);
4589517SBill.Taylor@Sun.COM }
4599517SBill.Taylor@Sun.COM 
4609517SBill.Taylor@Sun.COM /*
4619517SBill.Taylor@Sun.COM  * hermon_ioctl_flash_erase()
4629517SBill.Taylor@Sun.COM  */
4639517SBill.Taylor@Sun.COM static int
hermon_ioctl_flash_erase(hermon_state_t * state,dev_t dev,intptr_t arg,int mode)4649517SBill.Taylor@Sun.COM hermon_ioctl_flash_erase(hermon_state_t *state, dev_t dev, intptr_t arg,
4659517SBill.Taylor@Sun.COM     int mode)
4669517SBill.Taylor@Sun.COM {
4679517SBill.Taylor@Sun.COM 	hermon_flash_ioctl_t	ioctl_info;
4689517SBill.Taylor@Sun.COM 	int status = 0;
4699517SBill.Taylor@Sun.COM 
4709517SBill.Taylor@Sun.COM 	/*
4719517SBill.Taylor@Sun.COM 	 * Check that flash init ioctl has been called first.  And check
4729517SBill.Taylor@Sun.COM 	 * that the same dev_t that called init is the one calling erase now.
4739517SBill.Taylor@Sun.COM 	 */
4749517SBill.Taylor@Sun.COM 	mutex_enter(&state->hs_fw_flashlock);
4759517SBill.Taylor@Sun.COM 	if ((state->hs_fw_flashdev != dev) ||
4769517SBill.Taylor@Sun.COM 	    (state->hs_fw_flashstarted == 0)) {
4779517SBill.Taylor@Sun.COM 		mutex_exit(&state->hs_fw_flashlock);
4789517SBill.Taylor@Sun.COM 		return (EIO);
4799517SBill.Taylor@Sun.COM 	}
4809517SBill.Taylor@Sun.COM 
4819517SBill.Taylor@Sun.COM 	/* copy user struct to kernel */
4829517SBill.Taylor@Sun.COM #ifdef _MULTI_DATAMODEL
4839517SBill.Taylor@Sun.COM 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
4849517SBill.Taylor@Sun.COM 		hermon_flash_ioctl32_t info32;
4859517SBill.Taylor@Sun.COM 
4869517SBill.Taylor@Sun.COM 		if (ddi_copyin((void *)arg, &info32,
4879517SBill.Taylor@Sun.COM 		    sizeof (hermon_flash_ioctl32_t), mode) != 0) {
4889517SBill.Taylor@Sun.COM 			mutex_exit(&state->hs_fw_flashlock);
4899517SBill.Taylor@Sun.COM 			return (EFAULT);
4909517SBill.Taylor@Sun.COM 		}
4919517SBill.Taylor@Sun.COM 		ioctl_info.af_type = info32.af_type;
4929517SBill.Taylor@Sun.COM 		ioctl_info.af_sector_num = info32.af_sector_num;
4939517SBill.Taylor@Sun.COM 	} else
4949517SBill.Taylor@Sun.COM #endif /* _MULTI_DATAMODEL */
4959517SBill.Taylor@Sun.COM 	if (ddi_copyin((void *)arg, &ioctl_info, sizeof (hermon_flash_ioctl_t),
4969517SBill.Taylor@Sun.COM 	    mode) != 0) {
4979517SBill.Taylor@Sun.COM 		mutex_exit(&state->hs_fw_flashlock);
4989517SBill.Taylor@Sun.COM 		return (EFAULT);
4999517SBill.Taylor@Sun.COM 	}
5009517SBill.Taylor@Sun.COM 
5019517SBill.Taylor@Sun.COM 	/*
5029517SBill.Taylor@Sun.COM 	 * Determine type of ERASE ioctl
5039517SBill.Taylor@Sun.COM 	 */
5049517SBill.Taylor@Sun.COM 	switch (ioctl_info.af_type) {
5059517SBill.Taylor@Sun.COM 	case HERMON_FLASH_ERASE_SECTOR:
5069517SBill.Taylor@Sun.COM 		/* Check if sector num is too large for flash device */
5079517SBill.Taylor@Sun.COM 		if (ioctl_info.af_sector_num >=
5089517SBill.Taylor@Sun.COM 		    (state->hs_fw_device_sz >> state->hs_fw_log_sector_sz)) {
5099517SBill.Taylor@Sun.COM 			mutex_exit(&state->hs_fw_flashlock);
5109517SBill.Taylor@Sun.COM 			return (EFAULT);
5119517SBill.Taylor@Sun.COM 		}
5129517SBill.Taylor@Sun.COM 
5139517SBill.Taylor@Sun.COM 		/* Perform Sector Erase */
5149517SBill.Taylor@Sun.COM 		status = hermon_flash_erase_sector(state,
5159517SBill.Taylor@Sun.COM 		    ioctl_info.af_sector_num);
5169517SBill.Taylor@Sun.COM 		break;
5179517SBill.Taylor@Sun.COM 
5189517SBill.Taylor@Sun.COM 	case HERMON_FLASH_ERASE_CHIP:
5199517SBill.Taylor@Sun.COM 		/* Perform Chip Erase */
5209517SBill.Taylor@Sun.COM 		status = hermon_flash_erase_chip(state);
5219517SBill.Taylor@Sun.COM 		break;
5229517SBill.Taylor@Sun.COM 
5239517SBill.Taylor@Sun.COM 	default:
5249517SBill.Taylor@Sun.COM 		status = EINVAL;
5259517SBill.Taylor@Sun.COM 		break;
5269517SBill.Taylor@Sun.COM 	}
5279517SBill.Taylor@Sun.COM 
5289517SBill.Taylor@Sun.COM 	mutex_exit(&state->hs_fw_flashlock);
5299517SBill.Taylor@Sun.COM 	return (status);
5309517SBill.Taylor@Sun.COM }
5319517SBill.Taylor@Sun.COM 
5329517SBill.Taylor@Sun.COM /*
5339517SBill.Taylor@Sun.COM  * hermon_ioctl_flash_init()
5349517SBill.Taylor@Sun.COM  */
5359517SBill.Taylor@Sun.COM static int
hermon_ioctl_flash_init(hermon_state_t * state,dev_t dev,intptr_t arg,int mode)5369517SBill.Taylor@Sun.COM hermon_ioctl_flash_init(hermon_state_t *state, dev_t dev, intptr_t arg,
5379517SBill.Taylor@Sun.COM     int mode)
5389517SBill.Taylor@Sun.COM {
5399517SBill.Taylor@Sun.COM 	hermon_flash_init_ioctl_t init_info;
5409517SBill.Taylor@Sun.COM 	int ret;
5419517SBill.Taylor@Sun.COM 	int intel_xcmd = 0;
5429517SBill.Taylor@Sun.COM 	ddi_acc_handle_t pci_hdl = hermon_get_pcihdl(state);
5439517SBill.Taylor@Sun.COM 
5449517SBill.Taylor@Sun.COM 	/* initialize the FMA retry loop */
5459517SBill.Taylor@Sun.COM 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
5469517SBill.Taylor@Sun.COM 
5479517SBill.Taylor@Sun.COM 	state->hs_fw_sector = NULL;
5489517SBill.Taylor@Sun.COM 
5499517SBill.Taylor@Sun.COM 	/*
5509517SBill.Taylor@Sun.COM 	 * init cannot be called more than once.  If we have already init'd the
5519517SBill.Taylor@Sun.COM 	 * flash, return directly.
5529517SBill.Taylor@Sun.COM 	 */
5539517SBill.Taylor@Sun.COM 	mutex_enter(&state->hs_fw_flashlock);
5549517SBill.Taylor@Sun.COM 	if (state->hs_fw_flashstarted == 1) {
5559517SBill.Taylor@Sun.COM 		mutex_exit(&state->hs_fw_flashlock);
5569517SBill.Taylor@Sun.COM 		return (EINVAL);
5579517SBill.Taylor@Sun.COM 	}
5589517SBill.Taylor@Sun.COM 
5599517SBill.Taylor@Sun.COM 	/* copyin the user struct to kernel */
5609517SBill.Taylor@Sun.COM 	if (ddi_copyin((void *)arg, &init_info,
5619517SBill.Taylor@Sun.COM 	    sizeof (hermon_flash_init_ioctl_t), mode) != 0) {
5629517SBill.Taylor@Sun.COM 		mutex_exit(&state->hs_fw_flashlock);
5639517SBill.Taylor@Sun.COM 		return (EFAULT);
5649517SBill.Taylor@Sun.COM 	}
5659517SBill.Taylor@Sun.COM 
5669517SBill.Taylor@Sun.COM 	/* Init Flash */
5679517SBill.Taylor@Sun.COM 	if ((ret = hermon_flash_init(state)) != 0) {
5689517SBill.Taylor@Sun.COM 		if (ret == EIO) {
5699517SBill.Taylor@Sun.COM 			goto pio_error;
5709517SBill.Taylor@Sun.COM 		}
5719517SBill.Taylor@Sun.COM 		mutex_exit(&state->hs_fw_flashlock);
5729517SBill.Taylor@Sun.COM 		return (ret);
5739517SBill.Taylor@Sun.COM 	}
5749517SBill.Taylor@Sun.COM 
5759517SBill.Taylor@Sun.COM 	/* Read CFI info */
5769517SBill.Taylor@Sun.COM 	if ((ret = hermon_flash_cfi_init(state, &init_info.af_cfi_info[0],
5779517SBill.Taylor@Sun.COM 	    &intel_xcmd)) != 0) {
5789517SBill.Taylor@Sun.COM 		if (ret == EIO) {
5799517SBill.Taylor@Sun.COM 			goto pio_error;
5809517SBill.Taylor@Sun.COM 		}
5819517SBill.Taylor@Sun.COM 		mutex_exit(&state->hs_fw_flashlock);
5829517SBill.Taylor@Sun.COM 		return (ret);
5839517SBill.Taylor@Sun.COM 	}
5849517SBill.Taylor@Sun.COM 
5859517SBill.Taylor@Sun.COM 	/*
5869517SBill.Taylor@Sun.COM 	 * Return error if the command set is unknown.
5879517SBill.Taylor@Sun.COM 	 */
5889517SBill.Taylor@Sun.COM 	if (state->hs_fw_cmdset == HERMON_FLASH_UNKNOWN_CMDSET) {
5899517SBill.Taylor@Sun.COM 		if ((ret = hermon_ioctl_flash_cleanup_nolock(state)) != 0) {
5909517SBill.Taylor@Sun.COM 			if (ret == EIO) {
5919517SBill.Taylor@Sun.COM 				goto pio_error;
5929517SBill.Taylor@Sun.COM 			}
5939517SBill.Taylor@Sun.COM 			mutex_exit(&state->hs_fw_flashlock);
5949517SBill.Taylor@Sun.COM 			return (ret);
5959517SBill.Taylor@Sun.COM 		}
5969517SBill.Taylor@Sun.COM 		mutex_exit(&state->hs_fw_flashlock);
5979517SBill.Taylor@Sun.COM 		return (EFAULT);
5989517SBill.Taylor@Sun.COM 	}
5999517SBill.Taylor@Sun.COM 
6009517SBill.Taylor@Sun.COM 	/* the FMA retry loop starts. */
6019517SBill.Taylor@Sun.COM 	hermon_pio_start(state, pci_hdl, pio_error,
6029517SBill.Taylor@Sun.COM 	    fm_loop_cnt, fm_status, fm_test);
6039517SBill.Taylor@Sun.COM 
6049517SBill.Taylor@Sun.COM 	/* Read HWREV - least significant 8 bits is revision ID */
6059517SBill.Taylor@Sun.COM 	init_info.af_hwrev = pci_config_get32(pci_hdl,
6069517SBill.Taylor@Sun.COM 	    HERMON_HW_FLASH_CFG_HWREV) & 0xFF;
6079517SBill.Taylor@Sun.COM 
6089517SBill.Taylor@Sun.COM 	/* the FMA retry loop ends. */
6099517SBill.Taylor@Sun.COM 	hermon_pio_end(state, pci_hdl, pio_error, fm_loop_cnt,
6109517SBill.Taylor@Sun.COM 	    fm_status, fm_test);
6119517SBill.Taylor@Sun.COM 
6129517SBill.Taylor@Sun.COM 	/* Fill in the firmwate revision numbers */
6139517SBill.Taylor@Sun.COM 	init_info.af_fwrev.afi_maj	= state->hs_fw.fw_rev_major;
6149517SBill.Taylor@Sun.COM 	init_info.af_fwrev.afi_min	= state->hs_fw.fw_rev_minor;
6159517SBill.Taylor@Sun.COM 	init_info.af_fwrev.afi_sub	= state->hs_fw.fw_rev_subminor;
6169517SBill.Taylor@Sun.COM 
6179517SBill.Taylor@Sun.COM 	/* Alloc flash mem for one sector size */
6189517SBill.Taylor@Sun.COM 	state->hs_fw_sector = (uint32_t *)kmem_zalloc(1 <<
6199517SBill.Taylor@Sun.COM 	    state->hs_fw_log_sector_sz, KM_SLEEP);
6209517SBill.Taylor@Sun.COM 
6219517SBill.Taylor@Sun.COM 	/* Set HW part number and length */
6229517SBill.Taylor@Sun.COM 	init_info.af_pn_len = state->hs_hca_pn_len;
6239517SBill.Taylor@Sun.COM 	if (state->hs_hca_pn_len != 0) {
6249517SBill.Taylor@Sun.COM 		(void) memcpy(init_info.af_hwpn, state->hs_hca_pn,
6259517SBill.Taylor@Sun.COM 		    state->hs_hca_pn_len);
6269517SBill.Taylor@Sun.COM 	}
6279517SBill.Taylor@Sun.COM 
6289517SBill.Taylor@Sun.COM 	/* Copy ioctl results back to userland */
6299517SBill.Taylor@Sun.COM 	if (ddi_copyout(&init_info, (void *)arg,
6309517SBill.Taylor@Sun.COM 	    sizeof (hermon_flash_init_ioctl_t), mode) != 0) {
6319517SBill.Taylor@Sun.COM 		if ((ret = hermon_ioctl_flash_cleanup_nolock(state)) != 0) {
6329517SBill.Taylor@Sun.COM 			if (ret == EIO) {
6339517SBill.Taylor@Sun.COM 				goto pio_error;
6349517SBill.Taylor@Sun.COM 			}
6359517SBill.Taylor@Sun.COM 			mutex_exit(&state->hs_fw_flashlock);
6369517SBill.Taylor@Sun.COM 			return (ret);
6379517SBill.Taylor@Sun.COM 		}
6389517SBill.Taylor@Sun.COM 		mutex_exit(&state->hs_fw_flashlock);
6399517SBill.Taylor@Sun.COM 		return (EFAULT);
6409517SBill.Taylor@Sun.COM 	}
6419517SBill.Taylor@Sun.COM 
6429517SBill.Taylor@Sun.COM 	/* Set flash state to started */
6439517SBill.Taylor@Sun.COM 	state->hs_fw_flashstarted = 1;
6449517SBill.Taylor@Sun.COM 	state->hs_fw_flashdev	  = dev;
6459517SBill.Taylor@Sun.COM 
6469517SBill.Taylor@Sun.COM 	mutex_exit(&state->hs_fw_flashlock);
6479517SBill.Taylor@Sun.COM 
6489517SBill.Taylor@Sun.COM 	/*
6499517SBill.Taylor@Sun.COM 	 * If "flash init" is successful, add an "on close" callback to the
6509517SBill.Taylor@Sun.COM 	 * current dev node to ensure that "flash fini" gets called later
6519517SBill.Taylor@Sun.COM 	 * even if the userland process prematurely exits.
6529517SBill.Taylor@Sun.COM 	 */
6539517SBill.Taylor@Sun.COM 	ret = hermon_umap_db_set_onclose_cb(dev,
6549517SBill.Taylor@Sun.COM 	    HERMON_ONCLOSE_FLASH_INPROGRESS,
6559517SBill.Taylor@Sun.COM 	    (int (*)(void *))hermon_ioctl_flash_cleanup, state);
6569517SBill.Taylor@Sun.COM 	if (ret != DDI_SUCCESS) {
6579517SBill.Taylor@Sun.COM 		int status = hermon_ioctl_flash_fini(state, dev);
6589517SBill.Taylor@Sun.COM 		if (status != 0) {
6599517SBill.Taylor@Sun.COM 			if (status == EIO) {
6609517SBill.Taylor@Sun.COM 				hermon_fm_ereport(state, HCA_SYS_ERR,
6619517SBill.Taylor@Sun.COM 				    HCA_ERR_IOCTL);
6629517SBill.Taylor@Sun.COM 				return (EIO);
6639517SBill.Taylor@Sun.COM 			}
6649517SBill.Taylor@Sun.COM 			return (status);
6659517SBill.Taylor@Sun.COM 		}
6669517SBill.Taylor@Sun.COM 	}
6679517SBill.Taylor@Sun.COM 	return (0);
6689517SBill.Taylor@Sun.COM 
6699517SBill.Taylor@Sun.COM pio_error:
6709517SBill.Taylor@Sun.COM 	mutex_exit(&state->hs_fw_flashlock);
6719517SBill.Taylor@Sun.COM 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
6729517SBill.Taylor@Sun.COM 	return (EIO);
6739517SBill.Taylor@Sun.COM }
6749517SBill.Taylor@Sun.COM 
6759517SBill.Taylor@Sun.COM /*
6769517SBill.Taylor@Sun.COM  * hermon_ioctl_flash_fini()
6779517SBill.Taylor@Sun.COM  */
6789517SBill.Taylor@Sun.COM static int
hermon_ioctl_flash_fini(hermon_state_t * state,dev_t dev)6799517SBill.Taylor@Sun.COM hermon_ioctl_flash_fini(hermon_state_t *state, dev_t dev)
6809517SBill.Taylor@Sun.COM {
6819517SBill.Taylor@Sun.COM 	int ret;
6829517SBill.Taylor@Sun.COM 
6839517SBill.Taylor@Sun.COM 	/*
6849517SBill.Taylor@Sun.COM 	 * Check that flash init ioctl has been called first.  And check
6859517SBill.Taylor@Sun.COM 	 * that the same dev_t that called init is the one calling fini now.
6869517SBill.Taylor@Sun.COM 	 */
6879517SBill.Taylor@Sun.COM 	mutex_enter(&state->hs_fw_flashlock);
6889517SBill.Taylor@Sun.COM 	if ((state->hs_fw_flashdev != dev) ||
6899517SBill.Taylor@Sun.COM 	    (state->hs_fw_flashstarted == 0)) {
6909517SBill.Taylor@Sun.COM 		mutex_exit(&state->hs_fw_flashlock);
6919517SBill.Taylor@Sun.COM 		return (EINVAL);
6929517SBill.Taylor@Sun.COM 	}
6939517SBill.Taylor@Sun.COM 
6949517SBill.Taylor@Sun.COM 	if ((ret = hermon_ioctl_flash_cleanup_nolock(state)) != 0) {
6959517SBill.Taylor@Sun.COM 		mutex_exit(&state->hs_fw_flashlock);
6969517SBill.Taylor@Sun.COM 		if (ret == EIO) {
6979517SBill.Taylor@Sun.COM 			hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
6989517SBill.Taylor@Sun.COM 		}
6999517SBill.Taylor@Sun.COM 		return (ret);
7009517SBill.Taylor@Sun.COM 	}
7019517SBill.Taylor@Sun.COM 	mutex_exit(&state->hs_fw_flashlock);
7029517SBill.Taylor@Sun.COM 
7039517SBill.Taylor@Sun.COM 	/*
7049517SBill.Taylor@Sun.COM 	 * If "flash fini" is successful, remove the "on close" callback
7059517SBill.Taylor@Sun.COM 	 * that was setup during "flash init".
7069517SBill.Taylor@Sun.COM 	 */
7079517SBill.Taylor@Sun.COM 	ret = hermon_umap_db_clear_onclose_cb(dev,
7089517SBill.Taylor@Sun.COM 	    HERMON_ONCLOSE_FLASH_INPROGRESS);
7099517SBill.Taylor@Sun.COM 	if (ret != DDI_SUCCESS) {
7109517SBill.Taylor@Sun.COM 		return (EFAULT);
7119517SBill.Taylor@Sun.COM 	}
7129517SBill.Taylor@Sun.COM 	return (0);
7139517SBill.Taylor@Sun.COM }
7149517SBill.Taylor@Sun.COM 
7159517SBill.Taylor@Sun.COM 
7169517SBill.Taylor@Sun.COM /*
7179517SBill.Taylor@Sun.COM  * hermon_ioctl_flash_cleanup()
7189517SBill.Taylor@Sun.COM  */
7199517SBill.Taylor@Sun.COM static int
hermon_ioctl_flash_cleanup(hermon_state_t * state)7209517SBill.Taylor@Sun.COM hermon_ioctl_flash_cleanup(hermon_state_t *state)
7219517SBill.Taylor@Sun.COM {
7229517SBill.Taylor@Sun.COM 	int status;
7239517SBill.Taylor@Sun.COM 
7249517SBill.Taylor@Sun.COM 	mutex_enter(&state->hs_fw_flashlock);
7259517SBill.Taylor@Sun.COM 	status = hermon_ioctl_flash_cleanup_nolock(state);
7269517SBill.Taylor@Sun.COM 	mutex_exit(&state->hs_fw_flashlock);
7279517SBill.Taylor@Sun.COM 
7289517SBill.Taylor@Sun.COM 	return (status);
7299517SBill.Taylor@Sun.COM }
7309517SBill.Taylor@Sun.COM 
7319517SBill.Taylor@Sun.COM 
7329517SBill.Taylor@Sun.COM /*
7339517SBill.Taylor@Sun.COM  * hermon_ioctl_flash_cleanup_nolock()
7349517SBill.Taylor@Sun.COM  */
7359517SBill.Taylor@Sun.COM static int
hermon_ioctl_flash_cleanup_nolock(hermon_state_t * state)7369517SBill.Taylor@Sun.COM hermon_ioctl_flash_cleanup_nolock(hermon_state_t *state)
7379517SBill.Taylor@Sun.COM {
7389517SBill.Taylor@Sun.COM 	int status;
7399517SBill.Taylor@Sun.COM 	ASSERT(MUTEX_HELD(&state->hs_fw_flashlock));
7409517SBill.Taylor@Sun.COM 
7419517SBill.Taylor@Sun.COM 	/* free flash mem */
7429517SBill.Taylor@Sun.COM 	if (state->hs_fw_sector) {
7439517SBill.Taylor@Sun.COM 		kmem_free(state->hs_fw_sector, 1 << state->hs_fw_log_sector_sz);
7449517SBill.Taylor@Sun.COM 	}
7459517SBill.Taylor@Sun.COM 
7469517SBill.Taylor@Sun.COM 	/* Fini the Flash */
7479517SBill.Taylor@Sun.COM 	if ((status = hermon_flash_fini(state)) != 0)
7489517SBill.Taylor@Sun.COM 		return (status);
7499517SBill.Taylor@Sun.COM 
7509517SBill.Taylor@Sun.COM 	/* Set flash state to fini */
7519517SBill.Taylor@Sun.COM 	state->hs_fw_flashstarted = 0;
7529517SBill.Taylor@Sun.COM 	state->hs_fw_flashdev	  = 0;
7539517SBill.Taylor@Sun.COM 	return (0);
7549517SBill.Taylor@Sun.COM }
7559517SBill.Taylor@Sun.COM 
7569517SBill.Taylor@Sun.COM 
7579517SBill.Taylor@Sun.COM /*
7589517SBill.Taylor@Sun.COM  * hermon_ioctl_info()
7599517SBill.Taylor@Sun.COM  */
7609517SBill.Taylor@Sun.COM static int
hermon_ioctl_info(hermon_state_t * state,dev_t dev,intptr_t arg,int mode)7619517SBill.Taylor@Sun.COM hermon_ioctl_info(hermon_state_t *state, dev_t dev, intptr_t arg, int mode)
7629517SBill.Taylor@Sun.COM {
7639517SBill.Taylor@Sun.COM 	hermon_info_ioctl_t	 info;
7649517SBill.Taylor@Sun.COM 	hermon_flash_init_ioctl_t init_info;
7659517SBill.Taylor@Sun.COM 
7669517SBill.Taylor@Sun.COM 	/*
7679517SBill.Taylor@Sun.COM 	 * Access to Hemron VTS ioctls is not allowed in "maintenance mode".
7689517SBill.Taylor@Sun.COM 	 */
7699517SBill.Taylor@Sun.COM 	if (state->hs_operational_mode == HERMON_MAINTENANCE_MODE) {
7709517SBill.Taylor@Sun.COM 		return (EFAULT);
7719517SBill.Taylor@Sun.COM 	}
7729517SBill.Taylor@Sun.COM 
7739517SBill.Taylor@Sun.COM 	/* copyin the user struct to kernel */
7749517SBill.Taylor@Sun.COM 	if (ddi_copyin((void *)arg, &info, sizeof (hermon_info_ioctl_t),
7759517SBill.Taylor@Sun.COM 	    mode) != 0) {
7769517SBill.Taylor@Sun.COM 		return (EFAULT);
7779517SBill.Taylor@Sun.COM 	}
7789517SBill.Taylor@Sun.COM 
7799517SBill.Taylor@Sun.COM 	/*
7809517SBill.Taylor@Sun.COM 	 * Check ioctl revision
7819517SBill.Taylor@Sun.COM 	 */
7829517SBill.Taylor@Sun.COM 	if (info.ai_revision != HERMON_VTS_IOCTL_REVISION) {
7839517SBill.Taylor@Sun.COM 		return (EINVAL);
7849517SBill.Taylor@Sun.COM 	}
7859517SBill.Taylor@Sun.COM 
7869517SBill.Taylor@Sun.COM 	/*
7879517SBill.Taylor@Sun.COM 	 * If the 'fw_device_sz' has not been initialized yet, we initialize it
7889517SBill.Taylor@Sun.COM 	 * here.  This is done by leveraging the
7899517SBill.Taylor@Sun.COM 	 * hermon_ioctl_flash_init()/fini() calls.  We also hold our own mutex
7909517SBill.Taylor@Sun.COM 	 * around this operation in case we have multiple VTS threads in
7919517SBill.Taylor@Sun.COM 	 * process at the same time.
7929517SBill.Taylor@Sun.COM 	 */
7939517SBill.Taylor@Sun.COM 	mutex_enter(&state->hs_info_lock);
7949517SBill.Taylor@Sun.COM 	if (state->hs_fw_device_sz == 0) {
7959517SBill.Taylor@Sun.COM 		if (hermon_ioctl_flash_init(state, dev, (intptr_t)&init_info,
7969517SBill.Taylor@Sun.COM 		    (FKIOCTL | mode)) != 0) {
7979517SBill.Taylor@Sun.COM 			mutex_exit(&state->hs_info_lock);
7989517SBill.Taylor@Sun.COM 			return (EFAULT);
7999517SBill.Taylor@Sun.COM 		}
8009517SBill.Taylor@Sun.COM 		(void) hermon_ioctl_flash_fini(state, dev);
8019517SBill.Taylor@Sun.COM 	}
8029517SBill.Taylor@Sun.COM 	mutex_exit(&state->hs_info_lock);
8039517SBill.Taylor@Sun.COM 
8049517SBill.Taylor@Sun.COM 	info.ai_hw_rev		 = state->hs_revision_id;
8059517SBill.Taylor@Sun.COM 	info.ai_flash_sz	 = state->hs_fw_device_sz;
8069517SBill.Taylor@Sun.COM 	info.ai_fw_rev.afi_maj	 = state->hs_fw.fw_rev_major;
8079517SBill.Taylor@Sun.COM 	info.ai_fw_rev.afi_min	 = state->hs_fw.fw_rev_minor;
8089517SBill.Taylor@Sun.COM 	info.ai_fw_rev.afi_sub	 = state->hs_fw.fw_rev_subminor;
8099517SBill.Taylor@Sun.COM 
8109517SBill.Taylor@Sun.COM 	/* Copy ioctl results back to user struct */
8119517SBill.Taylor@Sun.COM 	if (ddi_copyout(&info, (void *)arg, sizeof (hermon_info_ioctl_t),
8129517SBill.Taylor@Sun.COM 	    mode) != 0) {
8139517SBill.Taylor@Sun.COM 		return (EFAULT);
8149517SBill.Taylor@Sun.COM 	}
8159517SBill.Taylor@Sun.COM 
8169517SBill.Taylor@Sun.COM 	return (0);
8179517SBill.Taylor@Sun.COM }
8189517SBill.Taylor@Sun.COM 
8199517SBill.Taylor@Sun.COM /*
8209517SBill.Taylor@Sun.COM  * hermon_ioctl_ports()
8219517SBill.Taylor@Sun.COM  */
8229517SBill.Taylor@Sun.COM static int
hermon_ioctl_ports(hermon_state_t * state,intptr_t arg,int mode)8239517SBill.Taylor@Sun.COM hermon_ioctl_ports(hermon_state_t *state, intptr_t arg, int mode)
8249517SBill.Taylor@Sun.COM {
8259517SBill.Taylor@Sun.COM 	hermon_ports_ioctl_t	info;
8269517SBill.Taylor@Sun.COM 	hermon_stat_port_ioctl_t	portstat;
8279517SBill.Taylor@Sun.COM 	ibt_hca_portinfo_t	pi;
8289517SBill.Taylor@Sun.COM 	uint_t			tbl_size;
8299517SBill.Taylor@Sun.COM 	ib_gid_t		*sgid_tbl;
8309517SBill.Taylor@Sun.COM 	ib_pkey_t		*pkey_tbl;
8319517SBill.Taylor@Sun.COM 	int			i;
8329517SBill.Taylor@Sun.COM 
8339517SBill.Taylor@Sun.COM 	/*
8349517SBill.Taylor@Sun.COM 	 * Access to Hemron VTS ioctls is not allowed in "maintenance mode".
8359517SBill.Taylor@Sun.COM 	 */
8369517SBill.Taylor@Sun.COM 	if (state->hs_operational_mode == HERMON_MAINTENANCE_MODE) {
8379517SBill.Taylor@Sun.COM 		return (EFAULT);
8389517SBill.Taylor@Sun.COM 	}
8399517SBill.Taylor@Sun.COM 
8409517SBill.Taylor@Sun.COM 	/* copyin the user struct to kernel */
8419517SBill.Taylor@Sun.COM #ifdef _MULTI_DATAMODEL
8429517SBill.Taylor@Sun.COM 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
8439517SBill.Taylor@Sun.COM 		hermon_ports_ioctl32_t info32;
8449517SBill.Taylor@Sun.COM 
8459517SBill.Taylor@Sun.COM 		if (ddi_copyin((void *)arg, &info32,
8469517SBill.Taylor@Sun.COM 		    sizeof (hermon_ports_ioctl32_t), mode) != 0) {
8479517SBill.Taylor@Sun.COM 			return (EFAULT);
8489517SBill.Taylor@Sun.COM 		}
8499517SBill.Taylor@Sun.COM 		info.ap_revision  = info32.ap_revision;
8509517SBill.Taylor@Sun.COM 		info.ap_ports	  =
8519517SBill.Taylor@Sun.COM 		    (hermon_stat_port_ioctl_t *)(uintptr_t)info32.ap_ports;
8529517SBill.Taylor@Sun.COM 		info.ap_num_ports = info32.ap_num_ports;
8539517SBill.Taylor@Sun.COM 
8549517SBill.Taylor@Sun.COM 	} else
8559517SBill.Taylor@Sun.COM #endif /* _MULTI_DATAMODEL */
8569517SBill.Taylor@Sun.COM 	if (ddi_copyin((void *)arg, &info, sizeof (hermon_ports_ioctl_t),
8579517SBill.Taylor@Sun.COM 	    mode) != 0) {
8589517SBill.Taylor@Sun.COM 		return (EFAULT);
8599517SBill.Taylor@Sun.COM 	}
8609517SBill.Taylor@Sun.COM 
8619517SBill.Taylor@Sun.COM 	/*
8629517SBill.Taylor@Sun.COM 	 * Check ioctl revision
8639517SBill.Taylor@Sun.COM 	 */
8649517SBill.Taylor@Sun.COM 	if (info.ap_revision != HERMON_VTS_IOCTL_REVISION) {
8659517SBill.Taylor@Sun.COM 		return (EINVAL);
8669517SBill.Taylor@Sun.COM 	}
8679517SBill.Taylor@Sun.COM 
8689517SBill.Taylor@Sun.COM 	/* Allocate space for temporary GID table/PKey table */
8699517SBill.Taylor@Sun.COM 	tbl_size = (1 << state->hs_cfg_profile->cp_log_max_gidtbl);
8709517SBill.Taylor@Sun.COM 	sgid_tbl = (ib_gid_t *)kmem_zalloc(tbl_size * sizeof (ib_gid_t),
8719517SBill.Taylor@Sun.COM 	    KM_SLEEP);
8729517SBill.Taylor@Sun.COM 	tbl_size = (1 << state->hs_cfg_profile->cp_log_max_pkeytbl);
8739517SBill.Taylor@Sun.COM 	pkey_tbl = (ib_pkey_t *)kmem_zalloc(tbl_size * sizeof (ib_pkey_t),
8749517SBill.Taylor@Sun.COM 	    KM_SLEEP);
8759517SBill.Taylor@Sun.COM 
8769517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*sgid_tbl, *pkey_tbl))
8779517SBill.Taylor@Sun.COM 
8789517SBill.Taylor@Sun.COM 	/*
8799517SBill.Taylor@Sun.COM 	 * Setup the number of ports, then loop through all ports and
8809517SBill.Taylor@Sun.COM 	 * query properties of each.
8819517SBill.Taylor@Sun.COM 	 */
8829517SBill.Taylor@Sun.COM 	info.ap_num_ports = (uint8_t)state->hs_cfg_profile->cp_num_ports;
8839517SBill.Taylor@Sun.COM 	for (i = 0; i < info.ap_num_ports; i++) {
8849517SBill.Taylor@Sun.COM 		/*
8859517SBill.Taylor@Sun.COM 		 * Get portstate information from the device.  If
8869517SBill.Taylor@Sun.COM 		 * hermon_port_query() fails, leave zeroes in user
8879517SBill.Taylor@Sun.COM 		 * struct port entry and continue.
8889517SBill.Taylor@Sun.COM 		 */
8899517SBill.Taylor@Sun.COM 		bzero(&pi, sizeof (ibt_hca_portinfo_t));
8909517SBill.Taylor@Sun.COM 		pi.p_sgid_tbl = sgid_tbl;
8919517SBill.Taylor@Sun.COM 		pi.p_pkey_tbl = pkey_tbl;
8929517SBill.Taylor@Sun.COM 		(void) hermon_port_query(state, i + 1, &pi);
8939517SBill.Taylor@Sun.COM 
8949517SBill.Taylor@Sun.COM 		portstat.asp_port_num	= pi.p_port_num;
8959517SBill.Taylor@Sun.COM 		portstat.asp_state	= pi.p_linkstate;
8969517SBill.Taylor@Sun.COM 		portstat.asp_guid	= pi.p_sgid_tbl[0].gid_guid;
8979517SBill.Taylor@Sun.COM 
8989517SBill.Taylor@Sun.COM 		/*
8999517SBill.Taylor@Sun.COM 		 * Copy queried port results back to user struct.  If
9009517SBill.Taylor@Sun.COM 		 * this fails, then break out of loop, attempt to copy
9019517SBill.Taylor@Sun.COM 		 * out remaining info to user struct, and return (without
9029517SBill.Taylor@Sun.COM 		 * error).
9039517SBill.Taylor@Sun.COM 		 */
9049517SBill.Taylor@Sun.COM 		if (ddi_copyout(&portstat,
9059517SBill.Taylor@Sun.COM 		    &(((hermon_stat_port_ioctl_t *)info.ap_ports)[i]),
9069517SBill.Taylor@Sun.COM 		    sizeof (hermon_stat_port_ioctl_t), mode) != 0) {
9079517SBill.Taylor@Sun.COM 			break;
9089517SBill.Taylor@Sun.COM 		}
9099517SBill.Taylor@Sun.COM 	}
9109517SBill.Taylor@Sun.COM 
9119517SBill.Taylor@Sun.COM 	/* Free the temporary space used for GID table/PKey table */
9129517SBill.Taylor@Sun.COM 	tbl_size = (1 << state->hs_cfg_profile->cp_log_max_gidtbl);
9139517SBill.Taylor@Sun.COM 	kmem_free(sgid_tbl, tbl_size * sizeof (ib_gid_t));
9149517SBill.Taylor@Sun.COM 	tbl_size = (1 << state->hs_cfg_profile->cp_log_max_pkeytbl);
9159517SBill.Taylor@Sun.COM 	kmem_free(pkey_tbl, tbl_size * sizeof (ib_pkey_t));
9169517SBill.Taylor@Sun.COM 
9179517SBill.Taylor@Sun.COM 	/* Copy ioctl results back to user struct */
9189517SBill.Taylor@Sun.COM #ifdef _MULTI_DATAMODEL
9199517SBill.Taylor@Sun.COM 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
9209517SBill.Taylor@Sun.COM 		hermon_ports_ioctl32_t info32;
9219517SBill.Taylor@Sun.COM 
9229517SBill.Taylor@Sun.COM 		info32.ap_revision  = info.ap_revision;
9239517SBill.Taylor@Sun.COM 		info32.ap_ports	    = (caddr32_t)(uintptr_t)info.ap_ports;
9249517SBill.Taylor@Sun.COM 		info32.ap_num_ports = info.ap_num_ports;
9259517SBill.Taylor@Sun.COM 
9269517SBill.Taylor@Sun.COM 		if (ddi_copyout(&info32, (void *)arg,
9279517SBill.Taylor@Sun.COM 		    sizeof (hermon_ports_ioctl32_t), mode) != 0) {
9289517SBill.Taylor@Sun.COM 			return (EFAULT);
9299517SBill.Taylor@Sun.COM 		}
9309517SBill.Taylor@Sun.COM 	} else
9319517SBill.Taylor@Sun.COM #endif /* _MULTI_DATAMODEL */
9329517SBill.Taylor@Sun.COM 	if (ddi_copyout(&info, (void *)arg, sizeof (hermon_ports_ioctl_t),
9339517SBill.Taylor@Sun.COM 	    mode) != 0) {
9349517SBill.Taylor@Sun.COM 		return (EFAULT);
9359517SBill.Taylor@Sun.COM 	}
9369517SBill.Taylor@Sun.COM 
9379517SBill.Taylor@Sun.COM 	return (0);
9389517SBill.Taylor@Sun.COM }
9399517SBill.Taylor@Sun.COM 
9409517SBill.Taylor@Sun.COM /*
9419517SBill.Taylor@Sun.COM  * hermon_ioctl_loopback()
9429517SBill.Taylor@Sun.COM  */
9439517SBill.Taylor@Sun.COM static int
hermon_ioctl_loopback(hermon_state_t * state,intptr_t arg,int mode)9449517SBill.Taylor@Sun.COM hermon_ioctl_loopback(hermon_state_t *state, intptr_t arg, int mode)
9459517SBill.Taylor@Sun.COM {
9469517SBill.Taylor@Sun.COM 	hermon_loopback_ioctl_t	lb;
9479517SBill.Taylor@Sun.COM 	hermon_loopback_state_t	lstate;
9489517SBill.Taylor@Sun.COM 	ibt_hca_portinfo_t 	pi;
9499517SBill.Taylor@Sun.COM 	uint_t			tbl_size, loopmax, max_usec;
9509517SBill.Taylor@Sun.COM 	ib_gid_t		*sgid_tbl;
9519517SBill.Taylor@Sun.COM 	ib_pkey_t		*pkey_tbl;
9529517SBill.Taylor@Sun.COM 	int			j, iter, ret;
9539517SBill.Taylor@Sun.COM 
9549517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(lstate))
9559517SBill.Taylor@Sun.COM 
9569517SBill.Taylor@Sun.COM 	/*
9579517SBill.Taylor@Sun.COM 	 * Access to Hemron VTS ioctls is not allowed in "maintenance mode".
9589517SBill.Taylor@Sun.COM 	 */
9599517SBill.Taylor@Sun.COM 	if (state->hs_operational_mode == HERMON_MAINTENANCE_MODE) {
9609517SBill.Taylor@Sun.COM 		return (EFAULT);
9619517SBill.Taylor@Sun.COM 	}
9629517SBill.Taylor@Sun.COM 
9639517SBill.Taylor@Sun.COM 	/* copyin the user struct to kernel */
9649517SBill.Taylor@Sun.COM #ifdef _MULTI_DATAMODEL
9659517SBill.Taylor@Sun.COM 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
9669517SBill.Taylor@Sun.COM 		hermon_loopback_ioctl32_t lb32;
9679517SBill.Taylor@Sun.COM 
9689517SBill.Taylor@Sun.COM 		if (ddi_copyin((void *)arg, &lb32,
9699517SBill.Taylor@Sun.COM 		    sizeof (hermon_loopback_ioctl32_t), mode) != 0) {
9709517SBill.Taylor@Sun.COM 			return (EFAULT);
9719517SBill.Taylor@Sun.COM 		}
9729517SBill.Taylor@Sun.COM 		lb.alb_revision	    = lb32.alb_revision;
9739517SBill.Taylor@Sun.COM 		lb.alb_send_buf	    = (caddr_t)(uintptr_t)lb32.alb_send_buf;
9749517SBill.Taylor@Sun.COM 		lb.alb_fail_buf	    = (caddr_t)(uintptr_t)lb32.alb_fail_buf;
9759517SBill.Taylor@Sun.COM 		lb.alb_buf_sz	    = lb32.alb_buf_sz;
9769517SBill.Taylor@Sun.COM 		lb.alb_num_iter	    = lb32.alb_num_iter;
9779517SBill.Taylor@Sun.COM 		lb.alb_pass_done    = lb32.alb_pass_done;
9789517SBill.Taylor@Sun.COM 		lb.alb_timeout	    = lb32.alb_timeout;
9799517SBill.Taylor@Sun.COM 		lb.alb_error_type   = lb32.alb_error_type;
9809517SBill.Taylor@Sun.COM 		lb.alb_port_num	    = lb32.alb_port_num;
9819517SBill.Taylor@Sun.COM 		lb.alb_num_retry    = lb32.alb_num_retry;
9829517SBill.Taylor@Sun.COM 	} else
9839517SBill.Taylor@Sun.COM #endif /* _MULTI_DATAMODEL */
9849517SBill.Taylor@Sun.COM 	if (ddi_copyin((void *)arg, &lb, sizeof (hermon_loopback_ioctl_t),
9859517SBill.Taylor@Sun.COM 	    mode) != 0) {
9869517SBill.Taylor@Sun.COM 		return (EFAULT);
9879517SBill.Taylor@Sun.COM 	}
9889517SBill.Taylor@Sun.COM 
9899517SBill.Taylor@Sun.COM 	/* Initialize the internal loopback test state structure */
9909517SBill.Taylor@Sun.COM 	bzero(&lstate, sizeof (hermon_loopback_state_t));
9919517SBill.Taylor@Sun.COM 
9929517SBill.Taylor@Sun.COM 	/*
9939517SBill.Taylor@Sun.COM 	 * Check ioctl revision
9949517SBill.Taylor@Sun.COM 	 */
9959517SBill.Taylor@Sun.COM 	if (lb.alb_revision != HERMON_VTS_IOCTL_REVISION) {
9969517SBill.Taylor@Sun.COM 		lb.alb_error_type = HERMON_LOOPBACK_INVALID_REVISION;
9979517SBill.Taylor@Sun.COM 		(void) hermon_loopback_copyout(&lb, arg, mode);
9989517SBill.Taylor@Sun.COM 		return (EINVAL);
9999517SBill.Taylor@Sun.COM 	}
10009517SBill.Taylor@Sun.COM 
10019517SBill.Taylor@Sun.COM 	/* Validate that specified port number is legal */
10029517SBill.Taylor@Sun.COM 	if (!hermon_portnum_is_valid(state, lb.alb_port_num)) {
10039517SBill.Taylor@Sun.COM 		lb.alb_error_type = HERMON_LOOPBACK_INVALID_PORT;
10049517SBill.Taylor@Sun.COM 		(void) hermon_loopback_copyout(&lb, arg, mode);
10059517SBill.Taylor@Sun.COM 		return (EINVAL);
10069517SBill.Taylor@Sun.COM 	}
10079517SBill.Taylor@Sun.COM 
10089517SBill.Taylor@Sun.COM 	/* Allocate space for temporary GID table/PKey table */
10099517SBill.Taylor@Sun.COM 	tbl_size = (1 << state->hs_cfg_profile->cp_log_max_gidtbl);
10109517SBill.Taylor@Sun.COM 	sgid_tbl = (ib_gid_t *)kmem_zalloc(tbl_size * sizeof (ib_gid_t),
10119517SBill.Taylor@Sun.COM 	    KM_SLEEP);
10129517SBill.Taylor@Sun.COM 	tbl_size = (1 << state->hs_cfg_profile->cp_log_max_pkeytbl);
10139517SBill.Taylor@Sun.COM 	pkey_tbl = (ib_pkey_t *)kmem_zalloc(tbl_size * sizeof (ib_pkey_t),
10149517SBill.Taylor@Sun.COM 	    KM_SLEEP);
10159517SBill.Taylor@Sun.COM 
10169517SBill.Taylor@Sun.COM 	/*
10179517SBill.Taylor@Sun.COM 	 * Get portstate information from specific port on device
10189517SBill.Taylor@Sun.COM 	 */
10199517SBill.Taylor@Sun.COM 	bzero(&pi, sizeof (ibt_hca_portinfo_t));
10209517SBill.Taylor@Sun.COM 	pi.p_sgid_tbl = sgid_tbl;
10219517SBill.Taylor@Sun.COM 	pi.p_pkey_tbl = pkey_tbl;
10229517SBill.Taylor@Sun.COM 	if (hermon_port_query(state, lb.alb_port_num, &pi) != 0) {
10239517SBill.Taylor@Sun.COM 		/* Free the temporary space used for GID table/PKey table */
10249517SBill.Taylor@Sun.COM 		tbl_size = (1 << state->hs_cfg_profile->cp_log_max_gidtbl);
10259517SBill.Taylor@Sun.COM 		kmem_free(sgid_tbl, tbl_size * sizeof (ib_gid_t));
10269517SBill.Taylor@Sun.COM 		tbl_size = (1 << state->hs_cfg_profile->cp_log_max_pkeytbl);
10279517SBill.Taylor@Sun.COM 		kmem_free(pkey_tbl, tbl_size * sizeof (ib_pkey_t));
10289517SBill.Taylor@Sun.COM 
10299517SBill.Taylor@Sun.COM 		lb.alb_error_type = HERMON_LOOPBACK_INVALID_PORT;
10309517SBill.Taylor@Sun.COM 		(void) hermon_loopback_copyout(&lb, arg, mode);
10319517SBill.Taylor@Sun.COM 		hermon_loopback_free_state(&lstate);
10329517SBill.Taylor@Sun.COM 		return (EINVAL);
10339517SBill.Taylor@Sun.COM 	}
10349517SBill.Taylor@Sun.COM 
10359517SBill.Taylor@Sun.COM 	lstate.hls_port	   = pi.p_port_num;
10369517SBill.Taylor@Sun.COM 	lstate.hls_lid	   = pi.p_base_lid;
10379517SBill.Taylor@Sun.COM 	lstate.hls_pkey_ix = (pi.p_linkstate == HERMON_PORT_LINK_ACTIVE) ?
10389517SBill.Taylor@Sun.COM 	    1 : 0;	/* XXX bogus assumption of a SUN subnet manager */
10399517SBill.Taylor@Sun.COM 	lstate.hls_state   = state;
10409517SBill.Taylor@Sun.COM 	lstate.hls_retry   = lb.alb_num_retry;
10419517SBill.Taylor@Sun.COM 
10429517SBill.Taylor@Sun.COM 	/* Free the temporary space used for GID table/PKey table */
10439517SBill.Taylor@Sun.COM 	tbl_size = (1 << state->hs_cfg_profile->cp_log_max_gidtbl);
10449517SBill.Taylor@Sun.COM 	kmem_free(sgid_tbl, tbl_size * sizeof (ib_gid_t));
10459517SBill.Taylor@Sun.COM 	tbl_size = (1 << state->hs_cfg_profile->cp_log_max_pkeytbl);
10469517SBill.Taylor@Sun.COM 	kmem_free(pkey_tbl, tbl_size * sizeof (ib_pkey_t));
10479517SBill.Taylor@Sun.COM 
10489517SBill.Taylor@Sun.COM 	/*
10499517SBill.Taylor@Sun.COM 	 * Compute the timeout duration in usec per the formula:
10509517SBill.Taylor@Sun.COM 	 *    to_usec_per_retry = 4.096us * (2 ^ supplied_timeout)
10519517SBill.Taylor@Sun.COM 	 * (plus we add a little fudge-factor here too)
10529517SBill.Taylor@Sun.COM 	 */
10539517SBill.Taylor@Sun.COM 	lstate.hls_timeout = lb.alb_timeout;
10549517SBill.Taylor@Sun.COM 	max_usec = (4096 * (1 << lstate.hls_timeout)) / 1000;
10559517SBill.Taylor@Sun.COM 	max_usec = max_usec * (lstate.hls_retry + 1);
10569517SBill.Taylor@Sun.COM 	max_usec = max_usec + 10000;
10579517SBill.Taylor@Sun.COM 
10589517SBill.Taylor@Sun.COM 	/*
10599517SBill.Taylor@Sun.COM 	 * Determine how many times we should loop before declaring a
10609517SBill.Taylor@Sun.COM 	 * timeout failure.
10619517SBill.Taylor@Sun.COM 	 */
10629517SBill.Taylor@Sun.COM 	loopmax	 = max_usec/HERMON_VTS_LOOPBACK_MIN_WAIT_DUR;
10639517SBill.Taylor@Sun.COM 	if ((max_usec % HERMON_VTS_LOOPBACK_MIN_WAIT_DUR) != 0) {
10649517SBill.Taylor@Sun.COM 		loopmax++;
10659517SBill.Taylor@Sun.COM 	}
10669517SBill.Taylor@Sun.COM 
10679517SBill.Taylor@Sun.COM 	if (lb.alb_send_buf == NULL || lb.alb_buf_sz == 0) {
10689517SBill.Taylor@Sun.COM 		lb.alb_error_type = HERMON_LOOPBACK_SEND_BUF_INVALID;
10699517SBill.Taylor@Sun.COM 		(void) hermon_loopback_copyout(&lb, arg, mode);
10709517SBill.Taylor@Sun.COM 		hermon_loopback_free_state(&lstate);
10719517SBill.Taylor@Sun.COM 		return (EINVAL);
10729517SBill.Taylor@Sun.COM 	}
10739517SBill.Taylor@Sun.COM 
10749517SBill.Taylor@Sun.COM 	/* Allocate protection domain (PD) */
10759517SBill.Taylor@Sun.COM 	if (hermon_loopback_init(state, &lstate) != 0) {
10769517SBill.Taylor@Sun.COM 		lb.alb_error_type = lstate.hls_err;
10779517SBill.Taylor@Sun.COM 		(void) hermon_loopback_copyout(&lb, arg, mode);
10789517SBill.Taylor@Sun.COM 		hermon_loopback_free_state(&lstate);
10799517SBill.Taylor@Sun.COM 		return (EFAULT);
10809517SBill.Taylor@Sun.COM 	}
10819517SBill.Taylor@Sun.COM 
10829517SBill.Taylor@Sun.COM 	/* Allocate and register a TX buffer */
10839517SBill.Taylor@Sun.COM 	if (hermon_loopback_alloc_mem(&lstate, &lstate.hls_tx,
10849517SBill.Taylor@Sun.COM 	    lb.alb_buf_sz) != 0) {
10859517SBill.Taylor@Sun.COM 		lb.alb_error_type =
10869517SBill.Taylor@Sun.COM 		    HERMON_LOOPBACK_SEND_BUF_MEM_REGION_ALLOC_FAIL;
10879517SBill.Taylor@Sun.COM 		(void) hermon_loopback_copyout(&lb, arg, mode);
10889517SBill.Taylor@Sun.COM 		hermon_loopback_free_state(&lstate);
10899517SBill.Taylor@Sun.COM 		return (EFAULT);
10909517SBill.Taylor@Sun.COM 	}
10919517SBill.Taylor@Sun.COM 
10929517SBill.Taylor@Sun.COM 	/* Allocate and register an RX buffer */
10939517SBill.Taylor@Sun.COM 	if (hermon_loopback_alloc_mem(&lstate, &lstate.hls_rx,
10949517SBill.Taylor@Sun.COM 	    lb.alb_buf_sz) != 0) {
10959517SBill.Taylor@Sun.COM 		lb.alb_error_type =
10969517SBill.Taylor@Sun.COM 		    HERMON_LOOPBACK_RECV_BUF_MEM_REGION_ALLOC_FAIL;
10979517SBill.Taylor@Sun.COM 		(void) hermon_loopback_copyout(&lb, arg, mode);
10989517SBill.Taylor@Sun.COM 		hermon_loopback_free_state(&lstate);
10999517SBill.Taylor@Sun.COM 		return (EFAULT);
11009517SBill.Taylor@Sun.COM 	}
11019517SBill.Taylor@Sun.COM 
11029517SBill.Taylor@Sun.COM 	/* Copy in the transmit buffer data */
11039517SBill.Taylor@Sun.COM 	if (ddi_copyin((void *)lb.alb_send_buf, lstate.hls_tx.hlc_buf,
11049517SBill.Taylor@Sun.COM 	    lb.alb_buf_sz, mode) != 0) {
11059517SBill.Taylor@Sun.COM 		lb.alb_error_type = HERMON_LOOPBACK_SEND_BUF_COPY_FAIL;
11069517SBill.Taylor@Sun.COM 		(void) hermon_loopback_copyout(&lb, arg, mode);
11079517SBill.Taylor@Sun.COM 		hermon_loopback_free_state(&lstate);
11089517SBill.Taylor@Sun.COM 		return (EFAULT);
11099517SBill.Taylor@Sun.COM 	}
11109517SBill.Taylor@Sun.COM 
11119517SBill.Taylor@Sun.COM 	/* Allocate the transmit QP and CQs */
11129517SBill.Taylor@Sun.COM 	lstate.hls_err = HERMON_LOOPBACK_XMIT_SEND_CQ_ALLOC_FAIL;
11139517SBill.Taylor@Sun.COM 	if (hermon_loopback_alloc_qps(&lstate, &lstate.hls_tx) != 0) {
11149517SBill.Taylor@Sun.COM 		lb.alb_error_type = lstate.hls_err;
11159517SBill.Taylor@Sun.COM 		(void) hermon_loopback_copyout(&lb, arg, mode);
11169517SBill.Taylor@Sun.COM 		hermon_loopback_free_state(&lstate);
11179517SBill.Taylor@Sun.COM 		return (EFAULT);
11189517SBill.Taylor@Sun.COM 	}
11199517SBill.Taylor@Sun.COM 
11209517SBill.Taylor@Sun.COM 	/* Allocate the receive QP and CQs */
11219517SBill.Taylor@Sun.COM 	lstate.hls_err = HERMON_LOOPBACK_RECV_SEND_CQ_ALLOC_FAIL;
11229517SBill.Taylor@Sun.COM 	if (hermon_loopback_alloc_qps(&lstate, &lstate.hls_rx) != 0) {
11239517SBill.Taylor@Sun.COM 		lb.alb_error_type = lstate.hls_err;
11249517SBill.Taylor@Sun.COM 		(void) hermon_loopback_copyout(&lb, arg, mode);
11259517SBill.Taylor@Sun.COM 		hermon_loopback_free_state(&lstate);
11269517SBill.Taylor@Sun.COM 		return (EFAULT);
11279517SBill.Taylor@Sun.COM 	}
11289517SBill.Taylor@Sun.COM 
11299517SBill.Taylor@Sun.COM 	/* Activate the TX QP (connect to RX QP) */
11309517SBill.Taylor@Sun.COM 	lstate.hls_err = HERMON_LOOPBACK_XMIT_QP_INIT_FAIL;
11319517SBill.Taylor@Sun.COM 	if (hermon_loopback_modify_qp(&lstate, &lstate.hls_tx,
11329517SBill.Taylor@Sun.COM 	    lstate.hls_rx.hlc_qp_num) != 0) {
11339517SBill.Taylor@Sun.COM 		lb.alb_error_type = lstate.hls_err;
11349517SBill.Taylor@Sun.COM 		(void) hermon_loopback_copyout(&lb, arg, mode);
11359517SBill.Taylor@Sun.COM 		hermon_loopback_free_state(&lstate);
11369517SBill.Taylor@Sun.COM 		return (EFAULT);
11379517SBill.Taylor@Sun.COM 	}
11389517SBill.Taylor@Sun.COM 
11399517SBill.Taylor@Sun.COM 	/* Activate the RX QP (connect to TX QP) */
11409517SBill.Taylor@Sun.COM 	lstate.hls_err = HERMON_LOOPBACK_RECV_QP_INIT_FAIL;
11419517SBill.Taylor@Sun.COM 	if (hermon_loopback_modify_qp(&lstate, &lstate.hls_rx,
11429517SBill.Taylor@Sun.COM 	    lstate.hls_tx.hlc_qp_num) != 0) {
11439517SBill.Taylor@Sun.COM 		lb.alb_error_type = lstate.hls_err;
11449517SBill.Taylor@Sun.COM 		(void) hermon_loopback_copyout(&lb, arg, mode);
11459517SBill.Taylor@Sun.COM 		hermon_loopback_free_state(&lstate);
11469517SBill.Taylor@Sun.COM 		return (EFAULT);
11479517SBill.Taylor@Sun.COM 	}
11489517SBill.Taylor@Sun.COM 
11499517SBill.Taylor@Sun.COM 	/* Run the loopback test (for specified number of iterations) */
11509517SBill.Taylor@Sun.COM 	lb.alb_pass_done = 0;
11519517SBill.Taylor@Sun.COM 	for (iter = 0; iter < lb.alb_num_iter; iter++) {
11529517SBill.Taylor@Sun.COM 		lstate.hls_err = 0;
11539517SBill.Taylor@Sun.COM 		bzero(lstate.hls_rx.hlc_buf, lb.alb_buf_sz);
11549517SBill.Taylor@Sun.COM 
11559517SBill.Taylor@Sun.COM 		/* Post RDMA Write work request */
11569517SBill.Taylor@Sun.COM 		if (hermon_loopback_post_send(&lstate, &lstate.hls_tx,
11579517SBill.Taylor@Sun.COM 		    &lstate.hls_rx) != IBT_SUCCESS) {
11589517SBill.Taylor@Sun.COM 			lb.alb_error_type = HERMON_LOOPBACK_WQE_POST_FAIL;
11599517SBill.Taylor@Sun.COM 			(void) hermon_loopback_copyout(&lb, arg, mode);
11609517SBill.Taylor@Sun.COM 			hermon_loopback_free_state(&lstate);
11619517SBill.Taylor@Sun.COM 			return (EFAULT);
11629517SBill.Taylor@Sun.COM 		}
11639517SBill.Taylor@Sun.COM 
11649517SBill.Taylor@Sun.COM 		/* Poll the TX CQ for a completion every few ticks */
11659517SBill.Taylor@Sun.COM 		for (j = 0; j < loopmax; j++) {
11669517SBill.Taylor@Sun.COM 			delay(drv_usectohz(HERMON_VTS_LOOPBACK_MIN_WAIT_DUR));
11679517SBill.Taylor@Sun.COM 
11689517SBill.Taylor@Sun.COM 			ret = hermon_loopback_poll_cq(&lstate, &lstate.hls_tx);
11699517SBill.Taylor@Sun.COM 			if (((ret != IBT_SUCCESS) && (ret != IBT_CQ_EMPTY)) ||
11709517SBill.Taylor@Sun.COM 			    ((ret == IBT_CQ_EMPTY) && (j == loopmax - 1))) {
11719517SBill.Taylor@Sun.COM 				lb.alb_error_type =
11729517SBill.Taylor@Sun.COM 				    HERMON_LOOPBACK_CQ_POLL_FAIL;
11739517SBill.Taylor@Sun.COM 				if (ddi_copyout(lstate.hls_rx.hlc_buf,
11749517SBill.Taylor@Sun.COM 				    lb.alb_fail_buf, lstate.hls_tx.hlc_buf_sz,
11759517SBill.Taylor@Sun.COM 				    mode) != 0) {
11769517SBill.Taylor@Sun.COM 					return (EFAULT);
11779517SBill.Taylor@Sun.COM 				}
11789517SBill.Taylor@Sun.COM 				(void) hermon_loopback_copyout(&lb, arg, mode);
11799517SBill.Taylor@Sun.COM 				hermon_loopback_free_state(&lstate);
11809517SBill.Taylor@Sun.COM 				return (EFAULT);
11819517SBill.Taylor@Sun.COM 			} else if (ret == IBT_CQ_EMPTY) {
11829517SBill.Taylor@Sun.COM 				continue;
11839517SBill.Taylor@Sun.COM 			}
11849517SBill.Taylor@Sun.COM 
11859517SBill.Taylor@Sun.COM 			/* Compare the data buffers */
11869517SBill.Taylor@Sun.COM 			if (bcmp(lstate.hls_tx.hlc_buf, lstate.hls_rx.hlc_buf,
11879517SBill.Taylor@Sun.COM 			    lb.alb_buf_sz) == 0) {
11889517SBill.Taylor@Sun.COM 				break;
11899517SBill.Taylor@Sun.COM 			} else {
11909517SBill.Taylor@Sun.COM 				lb.alb_error_type =
11919517SBill.Taylor@Sun.COM 				    HERMON_LOOPBACK_SEND_RECV_COMPARE_FAIL;
11929517SBill.Taylor@Sun.COM 				if (ddi_copyout(lstate.hls_rx.hlc_buf,
11939517SBill.Taylor@Sun.COM 				    lb.alb_fail_buf, lstate.hls_tx.hlc_buf_sz,
11949517SBill.Taylor@Sun.COM 				    mode) != 0) {
11959517SBill.Taylor@Sun.COM 					return (EFAULT);
11969517SBill.Taylor@Sun.COM 				}
11979517SBill.Taylor@Sun.COM 				(void) hermon_loopback_copyout(&lb, arg, mode);
11989517SBill.Taylor@Sun.COM 				hermon_loopback_free_state(&lstate);
11999517SBill.Taylor@Sun.COM 				return (EFAULT);
12009517SBill.Taylor@Sun.COM 			}
12019517SBill.Taylor@Sun.COM 		}
12029517SBill.Taylor@Sun.COM 
12039517SBill.Taylor@Sun.COM 		lstate.hls_err	 = HERMON_LOOPBACK_SUCCESS;
12049517SBill.Taylor@Sun.COM 		lb.alb_pass_done = iter + 1;
12059517SBill.Taylor@Sun.COM 	}
12069517SBill.Taylor@Sun.COM 
12079517SBill.Taylor@Sun.COM 	lb.alb_error_type = HERMON_LOOPBACK_SUCCESS;
12089517SBill.Taylor@Sun.COM 
12099517SBill.Taylor@Sun.COM 	/* Copy ioctl results back to user struct */
12109517SBill.Taylor@Sun.COM 	ret = hermon_loopback_copyout(&lb, arg, mode);
12119517SBill.Taylor@Sun.COM 
12129517SBill.Taylor@Sun.COM 	/* Free up everything and release all consumed resources */
12139517SBill.Taylor@Sun.COM 	hermon_loopback_free_state(&lstate);
12149517SBill.Taylor@Sun.COM 
12159517SBill.Taylor@Sun.COM 	return (ret);
12169517SBill.Taylor@Sun.COM }
12179517SBill.Taylor@Sun.COM 
12189517SBill.Taylor@Sun.COM #ifdef	DEBUG
12199517SBill.Taylor@Sun.COM /*
12209517SBill.Taylor@Sun.COM  * hermon_ioctl_reg_read()
12219517SBill.Taylor@Sun.COM  */
12229517SBill.Taylor@Sun.COM static int
hermon_ioctl_reg_read(hermon_state_t * state,intptr_t arg,int mode)12239517SBill.Taylor@Sun.COM hermon_ioctl_reg_read(hermon_state_t *state, intptr_t arg, int mode)
12249517SBill.Taylor@Sun.COM {
12259517SBill.Taylor@Sun.COM 	hermon_reg_ioctl_t	rdreg;
12269517SBill.Taylor@Sun.COM 	uint32_t		*addr;
12279517SBill.Taylor@Sun.COM 	uintptr_t		baseaddr;
12289517SBill.Taylor@Sun.COM 	int			status;
12299517SBill.Taylor@Sun.COM 	ddi_acc_handle_t	handle;
12309517SBill.Taylor@Sun.COM 
12319517SBill.Taylor@Sun.COM 	/* initialize the FMA retry loop */
12329517SBill.Taylor@Sun.COM 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
12339517SBill.Taylor@Sun.COM 
12349517SBill.Taylor@Sun.COM 	/*
12359517SBill.Taylor@Sun.COM 	 * Access to Hemron registers is not allowed in "maintenance mode".
12369517SBill.Taylor@Sun.COM 	 * This is primarily because the device may not have BARs to access
12379517SBill.Taylor@Sun.COM 	 */
12389517SBill.Taylor@Sun.COM 	if (state->hs_operational_mode == HERMON_MAINTENANCE_MODE) {
12399517SBill.Taylor@Sun.COM 		return (EFAULT);
12409517SBill.Taylor@Sun.COM 	}
12419517SBill.Taylor@Sun.COM 
12429517SBill.Taylor@Sun.COM 	/* Copy in the hermon_reg_ioctl_t structure */
12439517SBill.Taylor@Sun.COM 	status = ddi_copyin((void *)arg, &rdreg, sizeof (hermon_reg_ioctl_t),
12449517SBill.Taylor@Sun.COM 	    mode);
12459517SBill.Taylor@Sun.COM 	if (status != 0) {
12469517SBill.Taylor@Sun.COM 		return (EFAULT);
12479517SBill.Taylor@Sun.COM 	}
12489517SBill.Taylor@Sun.COM 
12499517SBill.Taylor@Sun.COM 	/* Determine base address for requested register set */
12509517SBill.Taylor@Sun.COM 	switch (rdreg.arg_reg_set) {
12519517SBill.Taylor@Sun.COM 	case HERMON_CMD_BAR:
12529517SBill.Taylor@Sun.COM 		baseaddr = (uintptr_t)state->hs_reg_cmd_baseaddr;
12539517SBill.Taylor@Sun.COM 		handle = hermon_get_cmdhdl(state);
12549517SBill.Taylor@Sun.COM 		break;
12559517SBill.Taylor@Sun.COM 
12569517SBill.Taylor@Sun.COM 	case HERMON_UAR_BAR:
12579517SBill.Taylor@Sun.COM 		baseaddr = (uintptr_t)state->hs_reg_uar_baseaddr;
12589517SBill.Taylor@Sun.COM 		handle = hermon_get_uarhdl(state);
12599517SBill.Taylor@Sun.COM 		break;
12609517SBill.Taylor@Sun.COM 
12619517SBill.Taylor@Sun.COM 
12629517SBill.Taylor@Sun.COM 	default:
12639517SBill.Taylor@Sun.COM 		return (EINVAL);
12649517SBill.Taylor@Sun.COM 	}
12659517SBill.Taylor@Sun.COM 
12669517SBill.Taylor@Sun.COM 	/* Ensure that address is properly-aligned */
12679517SBill.Taylor@Sun.COM 	addr = (uint32_t *)((baseaddr + rdreg.arg_offset) & ~0x3);
12689517SBill.Taylor@Sun.COM 
12699517SBill.Taylor@Sun.COM 	/* the FMA retry loop starts. */
12709517SBill.Taylor@Sun.COM 	hermon_pio_start(state, handle, pio_error, fm_loop_cnt,
12719517SBill.Taylor@Sun.COM 	    fm_status, fm_test);
12729517SBill.Taylor@Sun.COM 
12739517SBill.Taylor@Sun.COM 	/* Read the register pointed to by addr */
12749517SBill.Taylor@Sun.COM 	rdreg.arg_data = ddi_get32(handle, addr);
12759517SBill.Taylor@Sun.COM 
12769517SBill.Taylor@Sun.COM 	/* the FMA retry loop ends. */
12779517SBill.Taylor@Sun.COM 	hermon_pio_end(state, handle, pio_error, fm_loop_cnt, fm_status,
12789517SBill.Taylor@Sun.COM 	    fm_test);
12799517SBill.Taylor@Sun.COM 
12809517SBill.Taylor@Sun.COM 	/* Copy in the result into the hermon_reg_ioctl_t structure */
12819517SBill.Taylor@Sun.COM 	status = ddi_copyout(&rdreg, (void *)arg, sizeof (hermon_reg_ioctl_t),
12829517SBill.Taylor@Sun.COM 	    mode);
12839517SBill.Taylor@Sun.COM 	if (status != 0) {
12849517SBill.Taylor@Sun.COM 		return (EFAULT);
12859517SBill.Taylor@Sun.COM 	}
12869517SBill.Taylor@Sun.COM 	return (0);
12879517SBill.Taylor@Sun.COM 
12889517SBill.Taylor@Sun.COM pio_error:
12899517SBill.Taylor@Sun.COM 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
12909517SBill.Taylor@Sun.COM 	return (EIO);
12919517SBill.Taylor@Sun.COM }
12929517SBill.Taylor@Sun.COM 
12939517SBill.Taylor@Sun.COM 
12949517SBill.Taylor@Sun.COM /*
12959517SBill.Taylor@Sun.COM  * hermon_ioctl_reg_write()
12969517SBill.Taylor@Sun.COM  */
12979517SBill.Taylor@Sun.COM static int
hermon_ioctl_reg_write(hermon_state_t * state,intptr_t arg,int mode)12989517SBill.Taylor@Sun.COM hermon_ioctl_reg_write(hermon_state_t *state, intptr_t arg, int mode)
12999517SBill.Taylor@Sun.COM {
13009517SBill.Taylor@Sun.COM 	hermon_reg_ioctl_t	wrreg;
13019517SBill.Taylor@Sun.COM 	uint32_t		*addr;
13029517SBill.Taylor@Sun.COM 	uintptr_t		baseaddr;
13039517SBill.Taylor@Sun.COM 	int			status;
13049517SBill.Taylor@Sun.COM 	ddi_acc_handle_t	handle;
13059517SBill.Taylor@Sun.COM 
13069517SBill.Taylor@Sun.COM 	/* initialize the FMA retry loop */
13079517SBill.Taylor@Sun.COM 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
13089517SBill.Taylor@Sun.COM 
13099517SBill.Taylor@Sun.COM 	/*
13109517SBill.Taylor@Sun.COM 	 * Access to Hermon registers is not allowed in "maintenance mode".
13119517SBill.Taylor@Sun.COM 	 * This is primarily because the device may not have BARs to access
13129517SBill.Taylor@Sun.COM 	 */
13139517SBill.Taylor@Sun.COM 	if (state->hs_operational_mode == HERMON_MAINTENANCE_MODE) {
13149517SBill.Taylor@Sun.COM 		return (EFAULT);
13159517SBill.Taylor@Sun.COM 	}
13169517SBill.Taylor@Sun.COM 
13179517SBill.Taylor@Sun.COM 	/* Copy in the hermon_reg_ioctl_t structure */
13189517SBill.Taylor@Sun.COM 	status = ddi_copyin((void *)arg, &wrreg, sizeof (hermon_reg_ioctl_t),
13199517SBill.Taylor@Sun.COM 	    mode);
13209517SBill.Taylor@Sun.COM 	if (status != 0) {
13219517SBill.Taylor@Sun.COM 		return (EFAULT);
13229517SBill.Taylor@Sun.COM 	}
13239517SBill.Taylor@Sun.COM 
13249517SBill.Taylor@Sun.COM 	/* Determine base address for requested register set */
13259517SBill.Taylor@Sun.COM 	switch (wrreg.arg_reg_set) {
13269517SBill.Taylor@Sun.COM 	case HERMON_CMD_BAR:
13279517SBill.Taylor@Sun.COM 		baseaddr = (uintptr_t)state->hs_reg_cmd_baseaddr;
13289517SBill.Taylor@Sun.COM 		handle = hermon_get_cmdhdl(state);
13299517SBill.Taylor@Sun.COM 		break;
13309517SBill.Taylor@Sun.COM 
13319517SBill.Taylor@Sun.COM 	case HERMON_UAR_BAR:
13329517SBill.Taylor@Sun.COM 		baseaddr = (uintptr_t)state->hs_reg_uar_baseaddr;
13339517SBill.Taylor@Sun.COM 		handle = hermon_get_uarhdl(state);
13349517SBill.Taylor@Sun.COM 		break;
13359517SBill.Taylor@Sun.COM 
13369517SBill.Taylor@Sun.COM 	default:
13379517SBill.Taylor@Sun.COM 		return (EINVAL);
13389517SBill.Taylor@Sun.COM 	}
13399517SBill.Taylor@Sun.COM 
13409517SBill.Taylor@Sun.COM 	/* Ensure that address is properly-aligned */
13419517SBill.Taylor@Sun.COM 	addr = (uint32_t *)((baseaddr + wrreg.arg_offset) & ~0x3);
13429517SBill.Taylor@Sun.COM 
13439517SBill.Taylor@Sun.COM 	/* the FMA retry loop starts. */
13449517SBill.Taylor@Sun.COM 	hermon_pio_start(state, handle, pio_error, fm_loop_cnt,
13459517SBill.Taylor@Sun.COM 	    fm_status, fm_test);
13469517SBill.Taylor@Sun.COM 
13479517SBill.Taylor@Sun.COM 	/* Write the data to the register pointed to by addr */
13489517SBill.Taylor@Sun.COM 	ddi_put32(handle, addr, wrreg.arg_data);
13499517SBill.Taylor@Sun.COM 
13509517SBill.Taylor@Sun.COM 	/* the FMA retry loop ends. */
13519517SBill.Taylor@Sun.COM 	hermon_pio_end(state, handle, pio_error, fm_loop_cnt, fm_status,
13529517SBill.Taylor@Sun.COM 	    fm_test);
13539517SBill.Taylor@Sun.COM 	return (0);
13549517SBill.Taylor@Sun.COM 
13559517SBill.Taylor@Sun.COM pio_error:
13569517SBill.Taylor@Sun.COM 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
13579517SBill.Taylor@Sun.COM 	return (EIO);
13589517SBill.Taylor@Sun.COM }
13599517SBill.Taylor@Sun.COM #endif	/* DEBUG */
13609517SBill.Taylor@Sun.COM 
13619517SBill.Taylor@Sun.COM static int
hermon_ioctl_write_boot_addr(hermon_state_t * state,dev_t dev,intptr_t arg,int mode)13629517SBill.Taylor@Sun.COM hermon_ioctl_write_boot_addr(hermon_state_t *state, dev_t dev, intptr_t arg,
13639517SBill.Taylor@Sun.COM     int mode)
13649517SBill.Taylor@Sun.COM {
13659517SBill.Taylor@Sun.COM 	hermon_flash_ioctl_t	ioctl_info;
13669517SBill.Taylor@Sun.COM 
13679517SBill.Taylor@Sun.COM 	/* initialize the FMA retry loop */
13689517SBill.Taylor@Sun.COM 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
13699517SBill.Taylor@Sun.COM 
13709517SBill.Taylor@Sun.COM 	/*
13719517SBill.Taylor@Sun.COM 	 * Check that flash init ioctl has been called first.  And check
13729517SBill.Taylor@Sun.COM 	 * that the same dev_t that called init is the one calling write now.
13739517SBill.Taylor@Sun.COM 	 */
13749517SBill.Taylor@Sun.COM 	mutex_enter(&state->hs_fw_flashlock);
13759517SBill.Taylor@Sun.COM 	if ((state->hs_fw_flashdev != dev) ||
13769517SBill.Taylor@Sun.COM 	    (state->hs_fw_flashstarted == 0)) {
13779517SBill.Taylor@Sun.COM 		mutex_exit(&state->hs_fw_flashlock);
13789517SBill.Taylor@Sun.COM 		return (EIO);
13799517SBill.Taylor@Sun.COM 	}
13809517SBill.Taylor@Sun.COM 
13819517SBill.Taylor@Sun.COM 	/* copy user struct to kernel */
13829517SBill.Taylor@Sun.COM #ifdef _MULTI_DATAMODEL
13839517SBill.Taylor@Sun.COM 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
13849517SBill.Taylor@Sun.COM 		hermon_flash_ioctl32_t info32;
13859517SBill.Taylor@Sun.COM 
13869517SBill.Taylor@Sun.COM 		if (ddi_copyin((void *)arg, &info32,
13879517SBill.Taylor@Sun.COM 		    sizeof (hermon_flash_ioctl32_t), mode) != 0) {
13889517SBill.Taylor@Sun.COM 			mutex_exit(&state->hs_fw_flashlock);
13899517SBill.Taylor@Sun.COM 			return (EFAULT);
13909517SBill.Taylor@Sun.COM 		}
13919517SBill.Taylor@Sun.COM 		ioctl_info.af_type = info32.af_type;
13929517SBill.Taylor@Sun.COM 		ioctl_info.af_sector = (caddr_t)(uintptr_t)info32.af_sector;
13939517SBill.Taylor@Sun.COM 		ioctl_info.af_sector_num = info32.af_sector_num;
13949517SBill.Taylor@Sun.COM 		ioctl_info.af_addr = info32.af_addr;
13959517SBill.Taylor@Sun.COM 		ioctl_info.af_byte = info32.af_byte;
13969517SBill.Taylor@Sun.COM 	} else
13979517SBill.Taylor@Sun.COM #endif /* _MULTI_DATAMODEL */
13989517SBill.Taylor@Sun.COM 	if (ddi_copyin((void *)arg, &ioctl_info,
13999517SBill.Taylor@Sun.COM 	    sizeof (hermon_flash_ioctl_t), mode) != 0) {
14009517SBill.Taylor@Sun.COM 		mutex_exit(&state->hs_fw_flashlock);
14019517SBill.Taylor@Sun.COM 		return (EFAULT);
14029517SBill.Taylor@Sun.COM 	}
14039517SBill.Taylor@Sun.COM 
14049517SBill.Taylor@Sun.COM 	switch (state->hs_fw_cmdset) {
14059517SBill.Taylor@Sun.COM 	case HERMON_FLASH_AMD_CMDSET:
14069517SBill.Taylor@Sun.COM 	case HERMON_FLASH_INTEL_CMDSET:
14079517SBill.Taylor@Sun.COM 		break;
14089517SBill.Taylor@Sun.COM 
14099517SBill.Taylor@Sun.COM 	case HERMON_FLASH_SPI_CMDSET:
14109517SBill.Taylor@Sun.COM 	{
14119517SBill.Taylor@Sun.COM 		ddi_acc_handle_t pci_hdl = hermon_get_pcihdl(state);
14129517SBill.Taylor@Sun.COM 
14139517SBill.Taylor@Sun.COM 		/* the FMA retry loop starts. */
14149517SBill.Taylor@Sun.COM 		hermon_pio_start(state, pci_hdl, pio_error,
14159517SBill.Taylor@Sun.COM 		    fm_loop_cnt, fm_status, fm_test);
14169517SBill.Taylor@Sun.COM 
14179517SBill.Taylor@Sun.COM 		hermon_flash_write_cfg(state, pci_hdl,
14189517SBill.Taylor@Sun.COM 		    HERMON_HW_FLASH_SPI_BOOT_ADDR_REG,
14199517SBill.Taylor@Sun.COM 		    (ioctl_info.af_addr << 8) | 0x06);
14209517SBill.Taylor@Sun.COM 
14219517SBill.Taylor@Sun.COM 		/* the FMA retry loop ends. */
14229517SBill.Taylor@Sun.COM 		hermon_pio_end(state, pci_hdl, pio_error,
14239517SBill.Taylor@Sun.COM 		    fm_loop_cnt, fm_status, fm_test);
14249517SBill.Taylor@Sun.COM 		break;
14259517SBill.Taylor@Sun.COM 	}
14269517SBill.Taylor@Sun.COM 
14279517SBill.Taylor@Sun.COM 	case HERMON_FLASH_UNKNOWN_CMDSET:
14289517SBill.Taylor@Sun.COM 	default:
14299517SBill.Taylor@Sun.COM 		mutex_exit(&state->hs_fw_flashlock);
14309517SBill.Taylor@Sun.COM 		return (EINVAL);
14319517SBill.Taylor@Sun.COM 	}
14329517SBill.Taylor@Sun.COM 	mutex_exit(&state->hs_fw_flashlock);
14339517SBill.Taylor@Sun.COM 	return (0);
14349517SBill.Taylor@Sun.COM 
14359517SBill.Taylor@Sun.COM pio_error:
14369517SBill.Taylor@Sun.COM 	mutex_exit(&state->hs_fw_flashlock);
14379517SBill.Taylor@Sun.COM 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
14389517SBill.Taylor@Sun.COM 	return (EIO);
14399517SBill.Taylor@Sun.COM }
14409517SBill.Taylor@Sun.COM 
14419517SBill.Taylor@Sun.COM /*
14429517SBill.Taylor@Sun.COM  * hermon_flash_reset()
14439517SBill.Taylor@Sun.COM  */
14449517SBill.Taylor@Sun.COM static int
hermon_flash_reset(hermon_state_t * state)14459517SBill.Taylor@Sun.COM hermon_flash_reset(hermon_state_t *state)
14469517SBill.Taylor@Sun.COM {
14479517SBill.Taylor@Sun.COM 	int status;
14489517SBill.Taylor@Sun.COM 
14499517SBill.Taylor@Sun.COM 	/*
14509517SBill.Taylor@Sun.COM 	 * Performs a reset to the flash device.  After a reset the flash will
14519517SBill.Taylor@Sun.COM 	 * be operating in normal mode (capable of read/write, etc.).
14529517SBill.Taylor@Sun.COM 	 */
14539517SBill.Taylor@Sun.COM 	switch (state->hs_fw_cmdset) {
14549517SBill.Taylor@Sun.COM 	case HERMON_FLASH_AMD_CMDSET:
14559517SBill.Taylor@Sun.COM 		hermon_flash_write(state, 0x555, HERMON_HW_FLASH_RESET_AMD,
14569517SBill.Taylor@Sun.COM 		    &status);
14579517SBill.Taylor@Sun.COM 		if (status != 0) {
14589517SBill.Taylor@Sun.COM 			return (status);
14599517SBill.Taylor@Sun.COM 		}
14609517SBill.Taylor@Sun.COM 		break;
14619517SBill.Taylor@Sun.COM 
14629517SBill.Taylor@Sun.COM 	case HERMON_FLASH_INTEL_CMDSET:
14639517SBill.Taylor@Sun.COM 		hermon_flash_write(state, 0x555, HERMON_HW_FLASH_RESET_INTEL,
14649517SBill.Taylor@Sun.COM 		    &status);
14659517SBill.Taylor@Sun.COM 		if (status != 0) {
14669517SBill.Taylor@Sun.COM 			return (status);
14679517SBill.Taylor@Sun.COM 		}
14689517SBill.Taylor@Sun.COM 		break;
14699517SBill.Taylor@Sun.COM 
14709517SBill.Taylor@Sun.COM 	/* It appears no reset is needed for SPI */
14719517SBill.Taylor@Sun.COM 	case HERMON_FLASH_SPI_CMDSET:
14729517SBill.Taylor@Sun.COM 		status = 0;
14739517SBill.Taylor@Sun.COM 		break;
14749517SBill.Taylor@Sun.COM 
14759517SBill.Taylor@Sun.COM 	case HERMON_FLASH_UNKNOWN_CMDSET:
14769517SBill.Taylor@Sun.COM 	default:
14779517SBill.Taylor@Sun.COM 		status = EINVAL;
14789517SBill.Taylor@Sun.COM 		break;
14799517SBill.Taylor@Sun.COM 	}
14809517SBill.Taylor@Sun.COM 	return (status);
14819517SBill.Taylor@Sun.COM }
14829517SBill.Taylor@Sun.COM 
14839517SBill.Taylor@Sun.COM /*
14849517SBill.Taylor@Sun.COM  * hermon_flash_read_sector()
14859517SBill.Taylor@Sun.COM  */
14869517SBill.Taylor@Sun.COM static int
hermon_flash_read_sector(hermon_state_t * state,uint32_t sector_num)14879517SBill.Taylor@Sun.COM hermon_flash_read_sector(hermon_state_t *state, uint32_t sector_num)
14889517SBill.Taylor@Sun.COM {
14899517SBill.Taylor@Sun.COM 	uint32_t addr;
14909517SBill.Taylor@Sun.COM 	uint32_t end_addr;
14919517SBill.Taylor@Sun.COM 	uint32_t *image;
14929517SBill.Taylor@Sun.COM 	int i, status;
14939517SBill.Taylor@Sun.COM 
14949517SBill.Taylor@Sun.COM 	image = (uint32_t *)&state->hs_fw_sector[0];
14959517SBill.Taylor@Sun.COM 
14969517SBill.Taylor@Sun.COM 	/*
14979517SBill.Taylor@Sun.COM 	 * Calculate the start and end address of the sector, based on the
14989517SBill.Taylor@Sun.COM 	 * sector number passed in.
14999517SBill.Taylor@Sun.COM 	 */
15009517SBill.Taylor@Sun.COM 	addr = sector_num << state->hs_fw_log_sector_sz;
15019517SBill.Taylor@Sun.COM 	end_addr = addr + (1 << state->hs_fw_log_sector_sz);
15029517SBill.Taylor@Sun.COM 
15039517SBill.Taylor@Sun.COM 	/* Set the flash bank correctly for the given address */
15049517SBill.Taylor@Sun.COM 	if ((status = hermon_flash_bank(state, addr)) != 0)
15059517SBill.Taylor@Sun.COM 		return (status);
15069517SBill.Taylor@Sun.COM 
15079517SBill.Taylor@Sun.COM 	/* Read the entire sector, one quadlet at a time */
15089517SBill.Taylor@Sun.COM 	for (i = 0; addr < end_addr; i++, addr += 4) {
15099517SBill.Taylor@Sun.COM 		image[i] = hermon_flash_read(state, addr, &status);
15109517SBill.Taylor@Sun.COM 		if (status != 0) {
15119517SBill.Taylor@Sun.COM 			return (status);
15129517SBill.Taylor@Sun.COM 		}
15139517SBill.Taylor@Sun.COM 	}
15149517SBill.Taylor@Sun.COM 	return (0);
15159517SBill.Taylor@Sun.COM }
15169517SBill.Taylor@Sun.COM 
15179517SBill.Taylor@Sun.COM /*
15189517SBill.Taylor@Sun.COM  * hermon_flash_read_quadlet()
15199517SBill.Taylor@Sun.COM  */
15209517SBill.Taylor@Sun.COM static int
hermon_flash_read_quadlet(hermon_state_t * state,uint32_t * data,uint32_t addr)15219517SBill.Taylor@Sun.COM hermon_flash_read_quadlet(hermon_state_t *state, uint32_t *data,
15229517SBill.Taylor@Sun.COM     uint32_t addr)
15239517SBill.Taylor@Sun.COM {
15249517SBill.Taylor@Sun.COM 	int status;
15259517SBill.Taylor@Sun.COM 
15269517SBill.Taylor@Sun.COM 	/* Set the flash bank correctly for the given address */
15279517SBill.Taylor@Sun.COM 	if ((status = hermon_flash_bank(state, addr)) != 0) {
15289517SBill.Taylor@Sun.COM 		return (status);
15299517SBill.Taylor@Sun.COM 	}
15309517SBill.Taylor@Sun.COM 
15319517SBill.Taylor@Sun.COM 	/* Read one quadlet of data */
15329517SBill.Taylor@Sun.COM 	*data = hermon_flash_read(state, addr, &status);
15339517SBill.Taylor@Sun.COM 	if (status != 0) {
15349517SBill.Taylor@Sun.COM 		return (EIO);
15359517SBill.Taylor@Sun.COM 	}
15369517SBill.Taylor@Sun.COM 
15379517SBill.Taylor@Sun.COM 	return (0);
15389517SBill.Taylor@Sun.COM }
15399517SBill.Taylor@Sun.COM 
15409517SBill.Taylor@Sun.COM /*
15419517SBill.Taylor@Sun.COM  * hermon_flash_write_sector()
15429517SBill.Taylor@Sun.COM  */
15439517SBill.Taylor@Sun.COM static int
hermon_flash_write_sector(hermon_state_t * state,uint32_t sector_num)15449517SBill.Taylor@Sun.COM hermon_flash_write_sector(hermon_state_t *state, uint32_t sector_num)
15459517SBill.Taylor@Sun.COM {
15469517SBill.Taylor@Sun.COM 	uint32_t	addr;
15479517SBill.Taylor@Sun.COM 	uint32_t	end_addr;
15489517SBill.Taylor@Sun.COM 	uint32_t	*databuf;
15499517SBill.Taylor@Sun.COM 	uchar_t		*sector;
15509517SBill.Taylor@Sun.COM 	int		status = 0;
15519517SBill.Taylor@Sun.COM 	int		i;
15529517SBill.Taylor@Sun.COM 
15539517SBill.Taylor@Sun.COM 	sector = (uchar_t *)&state->hs_fw_sector[0];
15549517SBill.Taylor@Sun.COM 
15559517SBill.Taylor@Sun.COM 	/*
15569517SBill.Taylor@Sun.COM 	 * Calculate the start and end address of the sector, based on the
15579517SBill.Taylor@Sun.COM 	 * sector number passed in.
15589517SBill.Taylor@Sun.COM 	 */
15599517SBill.Taylor@Sun.COM 	addr = sector_num << state->hs_fw_log_sector_sz;
15609517SBill.Taylor@Sun.COM 	end_addr = addr + (1 << state->hs_fw_log_sector_sz);
15619517SBill.Taylor@Sun.COM 
15629517SBill.Taylor@Sun.COM 	/* Set the flash bank correctly for the given address */
15639517SBill.Taylor@Sun.COM 	if ((status = hermon_flash_bank(state, addr)) != 0 ||
15649517SBill.Taylor@Sun.COM 	    (status = hermon_flash_reset(state)) != 0) {
15659517SBill.Taylor@Sun.COM 		return (status);
15669517SBill.Taylor@Sun.COM 	}
15679517SBill.Taylor@Sun.COM 
15689517SBill.Taylor@Sun.COM 	/* Erase the sector before writing */
15699517SBill.Taylor@Sun.COM 	status = hermon_flash_erase_sector(state, sector_num);
15709517SBill.Taylor@Sun.COM 	if (status != 0) {
15719517SBill.Taylor@Sun.COM 		return (status);
15729517SBill.Taylor@Sun.COM 	}
15739517SBill.Taylor@Sun.COM 
15749517SBill.Taylor@Sun.COM 	switch (state->hs_fw_cmdset) {
15759517SBill.Taylor@Sun.COM 	case HERMON_FLASH_SPI_CMDSET:
15769517SBill.Taylor@Sun.COM 		databuf = (uint32_t *)(void *)sector;
15779517SBill.Taylor@Sun.COM 		/* Write the sector, one dword at a time */
15789517SBill.Taylor@Sun.COM 		for (i = 0; addr < end_addr; i++, addr += 4) {
15799517SBill.Taylor@Sun.COM 			if ((status = hermon_flash_spi_write_dword(state, addr,
15809517SBill.Taylor@Sun.COM 			    htonl(databuf[i]))) != 0) {
15819517SBill.Taylor@Sun.COM 				return (status);
15829517SBill.Taylor@Sun.COM 			}
15839517SBill.Taylor@Sun.COM 		}
15849517SBill.Taylor@Sun.COM 		status = hermon_flash_reset(state);
15859517SBill.Taylor@Sun.COM 		break;
15869517SBill.Taylor@Sun.COM 
15879517SBill.Taylor@Sun.COM 	case HERMON_FLASH_INTEL_CMDSET:
15889517SBill.Taylor@Sun.COM 	case HERMON_FLASH_AMD_CMDSET:
15899517SBill.Taylor@Sun.COM 		/* Write the sector, one byte at a time */
15909517SBill.Taylor@Sun.COM 		for (i = 0; addr < end_addr; i++, addr++) {
15919517SBill.Taylor@Sun.COM 			status = hermon_flash_write_byte(state, addr,
15929517SBill.Taylor@Sun.COM 			    sector[i]);
15939517SBill.Taylor@Sun.COM 			if (status != 0) {
15949517SBill.Taylor@Sun.COM 				break;
15959517SBill.Taylor@Sun.COM 			}
15969517SBill.Taylor@Sun.COM 		}
15979517SBill.Taylor@Sun.COM 		status = hermon_flash_reset(state);
15989517SBill.Taylor@Sun.COM 		break;
15999517SBill.Taylor@Sun.COM 
16009517SBill.Taylor@Sun.COM 	case HERMON_FLASH_UNKNOWN_CMDSET:
16019517SBill.Taylor@Sun.COM 	default:
16029517SBill.Taylor@Sun.COM 		status = EINVAL;
16039517SBill.Taylor@Sun.COM 		break;
16049517SBill.Taylor@Sun.COM 	}
16059517SBill.Taylor@Sun.COM 
16069517SBill.Taylor@Sun.COM 	return (status);
16079517SBill.Taylor@Sun.COM }
16089517SBill.Taylor@Sun.COM 
16099517SBill.Taylor@Sun.COM /*
16109517SBill.Taylor@Sun.COM  * hermon_flash_spi_write_dword()
16119517SBill.Taylor@Sun.COM  *
16129517SBill.Taylor@Sun.COM  * NOTE: This function assumes that "data" is in network byte order.
16139517SBill.Taylor@Sun.COM  *
16149517SBill.Taylor@Sun.COM  */
16159517SBill.Taylor@Sun.COM static int
hermon_flash_spi_write_dword(hermon_state_t * state,uint32_t addr,uint32_t data)16169517SBill.Taylor@Sun.COM hermon_flash_spi_write_dword(hermon_state_t *state, uint32_t addr,
16179517SBill.Taylor@Sun.COM     uint32_t data)
16189517SBill.Taylor@Sun.COM {
16199517SBill.Taylor@Sun.COM 	int status;
16209517SBill.Taylor@Sun.COM 	ddi_acc_handle_t	hdl;
16219517SBill.Taylor@Sun.COM 
16229517SBill.Taylor@Sun.COM 	/* initialize the FMA retry loop */
16239517SBill.Taylor@Sun.COM 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
16249517SBill.Taylor@Sun.COM 
16259517SBill.Taylor@Sun.COM 	hdl = hermon_get_pcihdl(state);
16269517SBill.Taylor@Sun.COM 
16279517SBill.Taylor@Sun.COM 	/* the FMA retry loop starts. */
16289517SBill.Taylor@Sun.COM 	hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status,
16299517SBill.Taylor@Sun.COM 	    fm_test);
16309517SBill.Taylor@Sun.COM 
16319517SBill.Taylor@Sun.COM 	/* Issue Write Enable */
16329517SBill.Taylor@Sun.COM 	hermon_flash_spi_write_enable(state);
16339517SBill.Taylor@Sun.COM 
16349517SBill.Taylor@Sun.COM 	/* Set the Address */
16359517SBill.Taylor@Sun.COM 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_SPI_ADDR,
16369517SBill.Taylor@Sun.COM 	    addr & HERMON_HW_FLASH_SPI_ADDR_MASK);
16379517SBill.Taylor@Sun.COM 
16389517SBill.Taylor@Sun.COM 	/* Set the Data */
16399517SBill.Taylor@Sun.COM 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_SPI_DATA, data);
16409517SBill.Taylor@Sun.COM 
16419517SBill.Taylor@Sun.COM 	/* Set the Page Program and execute */
16429517SBill.Taylor@Sun.COM 	hermon_flash_spi_exec_command(state, hdl,
16439517SBill.Taylor@Sun.COM 	    HERMON_HW_FLASH_SPI_INSTR_PHASE_OFF |
16449517SBill.Taylor@Sun.COM 	    HERMON_HW_FLASH_SPI_ADDR_PHASE_OFF |
16459517SBill.Taylor@Sun.COM 	    HERMON_HW_FLASH_SPI_DATA_PHASE_OFF |
16469517SBill.Taylor@Sun.COM 	    HERMON_HW_FLASH_SPI_TRANS_SZ_4B |
16479517SBill.Taylor@Sun.COM 	    (HERMON_HW_FLASH_SPI_PAGE_PROGRAM <<
16489517SBill.Taylor@Sun.COM 	    HERMON_HW_FLASH_SPI_INSTR_SHIFT));
16499517SBill.Taylor@Sun.COM 
16509517SBill.Taylor@Sun.COM 	/* Wait for write to complete */
16519517SBill.Taylor@Sun.COM 	if ((status = hermon_flash_spi_wait_wip(state)) != 0) {
16529517SBill.Taylor@Sun.COM 		return (status);
16539517SBill.Taylor@Sun.COM 	}
16549517SBill.Taylor@Sun.COM 
16559517SBill.Taylor@Sun.COM 	/* the FMA retry loop ends. */
16569517SBill.Taylor@Sun.COM 	hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status, fm_test);
16579517SBill.Taylor@Sun.COM 	return (0);
16589517SBill.Taylor@Sun.COM 
16599517SBill.Taylor@Sun.COM pio_error:
16609517SBill.Taylor@Sun.COM 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
16619517SBill.Taylor@Sun.COM 	return (EIO);
16629517SBill.Taylor@Sun.COM }
16639517SBill.Taylor@Sun.COM 
16649517SBill.Taylor@Sun.COM /*
16659517SBill.Taylor@Sun.COM  * hermon_flash_write_byte()
16669517SBill.Taylor@Sun.COM  */
16679517SBill.Taylor@Sun.COM static int
hermon_flash_write_byte(hermon_state_t * state,uint32_t addr,uchar_t data)16689517SBill.Taylor@Sun.COM hermon_flash_write_byte(hermon_state_t *state, uint32_t addr, uchar_t data)
16699517SBill.Taylor@Sun.COM {
16709517SBill.Taylor@Sun.COM 	uint32_t stat;
16719517SBill.Taylor@Sun.COM 	int status = 0;
16729517SBill.Taylor@Sun.COM 	int dword_addr;
16739517SBill.Taylor@Sun.COM 	int byte_offset;
16749517SBill.Taylor@Sun.COM 	int i;
16759517SBill.Taylor@Sun.COM 	union {
16769517SBill.Taylor@Sun.COM 		uint8_t		bytes[4];
16779517SBill.Taylor@Sun.COM 		uint32_t	dword;
16789517SBill.Taylor@Sun.COM 	} dword;
16799517SBill.Taylor@Sun.COM 
16809517SBill.Taylor@Sun.COM 	switch (state->hs_fw_cmdset) {
16819517SBill.Taylor@Sun.COM 	case HERMON_FLASH_AMD_CMDSET:
16829517SBill.Taylor@Sun.COM 		/* Issue Flash Byte program command */
16839517SBill.Taylor@Sun.COM 		hermon_flash_write(state, addr, 0xAA, &status);
16849517SBill.Taylor@Sun.COM 		if (status != 0) {
16859517SBill.Taylor@Sun.COM 			return (status);
16869517SBill.Taylor@Sun.COM 		}
16879517SBill.Taylor@Sun.COM 
16889517SBill.Taylor@Sun.COM 		hermon_flash_write(state, addr, 0x55, &status);
16899517SBill.Taylor@Sun.COM 		if (status != 0) {
16909517SBill.Taylor@Sun.COM 			return (status);
16919517SBill.Taylor@Sun.COM 		}
16929517SBill.Taylor@Sun.COM 
16939517SBill.Taylor@Sun.COM 		hermon_flash_write(state, addr, 0xA0, &status);
16949517SBill.Taylor@Sun.COM 		if (status != 0) {
16959517SBill.Taylor@Sun.COM 			return (status);
16969517SBill.Taylor@Sun.COM 		}
16979517SBill.Taylor@Sun.COM 
16989517SBill.Taylor@Sun.COM 		hermon_flash_write(state, addr, data, &status);
16999517SBill.Taylor@Sun.COM 		if (status != 0) {
17009517SBill.Taylor@Sun.COM 			return (status);
17019517SBill.Taylor@Sun.COM 		}
17029517SBill.Taylor@Sun.COM 
17039517SBill.Taylor@Sun.COM 		/* Wait for Write Byte to Complete */
17049517SBill.Taylor@Sun.COM 		i = 0;
17059517SBill.Taylor@Sun.COM 		do {
17069517SBill.Taylor@Sun.COM 			drv_usecwait(1);
17079517SBill.Taylor@Sun.COM 			stat = hermon_flash_read(state, addr & ~3, &status);
17089517SBill.Taylor@Sun.COM 			if (status != 0) {
17099517SBill.Taylor@Sun.COM 				return (status);
17109517SBill.Taylor@Sun.COM 			}
17119517SBill.Taylor@Sun.COM 
17129517SBill.Taylor@Sun.COM 			if (i == hermon_hw_flash_timeout_write) {
17139517SBill.Taylor@Sun.COM 				cmn_err(CE_WARN,
17149517SBill.Taylor@Sun.COM 				    "hermon_flash_write_byte: ACS write "
17159517SBill.Taylor@Sun.COM 				    "timeout: addr: 0x%x, data: 0x%x\n",
17169517SBill.Taylor@Sun.COM 				    addr, data);
17179517SBill.Taylor@Sun.COM 				hermon_fm_ereport(state, HCA_SYS_ERR,
17189517SBill.Taylor@Sun.COM 				    HCA_ERR_IOCTL);
17199517SBill.Taylor@Sun.COM 				return (EIO);
17209517SBill.Taylor@Sun.COM 			}
17219517SBill.Taylor@Sun.COM 			i++;
17229517SBill.Taylor@Sun.COM 		} while (data != ((stat >> ((3 - (addr & 3)) << 3)) & 0xFF));
17239517SBill.Taylor@Sun.COM 
17249517SBill.Taylor@Sun.COM 		break;
17259517SBill.Taylor@Sun.COM 
17269517SBill.Taylor@Sun.COM 	case HERMON_FLASH_INTEL_CMDSET:
17279517SBill.Taylor@Sun.COM 		/* Issue Flash Byte program command */
17289517SBill.Taylor@Sun.COM 		hermon_flash_write(state, addr, HERMON_HW_FLASH_ICS_WRITE,
17299517SBill.Taylor@Sun.COM 		    &status);
17309517SBill.Taylor@Sun.COM 		if (status != 0) {
17319517SBill.Taylor@Sun.COM 			return (status);
17329517SBill.Taylor@Sun.COM 		}
17339517SBill.Taylor@Sun.COM 		hermon_flash_write(state, addr, data, &status);
17349517SBill.Taylor@Sun.COM 		if (status != 0) {
17359517SBill.Taylor@Sun.COM 			return (status);
17369517SBill.Taylor@Sun.COM 		}
17379517SBill.Taylor@Sun.COM 
17389517SBill.Taylor@Sun.COM 		/* Wait for Write Byte to Complete */
17399517SBill.Taylor@Sun.COM 		i = 0;
17409517SBill.Taylor@Sun.COM 		do {
17419517SBill.Taylor@Sun.COM 			drv_usecwait(1);
17429517SBill.Taylor@Sun.COM 			stat = hermon_flash_read(state, addr & ~3, &status);
17439517SBill.Taylor@Sun.COM 			if (status != 0) {
17449517SBill.Taylor@Sun.COM 				return (status);
17459517SBill.Taylor@Sun.COM 			}
17469517SBill.Taylor@Sun.COM 
17479517SBill.Taylor@Sun.COM 			if (i == hermon_hw_flash_timeout_write) {
17489517SBill.Taylor@Sun.COM 				cmn_err(CE_WARN,
17499517SBill.Taylor@Sun.COM 				    "hermon_flash_write_byte: ICS write "
17509517SBill.Taylor@Sun.COM 				    "timeout: addr: %x, data: %x\n",
17519517SBill.Taylor@Sun.COM 				    addr, data);
17529517SBill.Taylor@Sun.COM 				hermon_fm_ereport(state, HCA_SYS_ERR,
17539517SBill.Taylor@Sun.COM 				    HCA_ERR_IOCTL);
17549517SBill.Taylor@Sun.COM 				return (EIO);
17559517SBill.Taylor@Sun.COM 			}
17569517SBill.Taylor@Sun.COM 			i++;
17579517SBill.Taylor@Sun.COM 		} while ((stat & HERMON_HW_FLASH_ICS_READY) == 0);
17589517SBill.Taylor@Sun.COM 
17599517SBill.Taylor@Sun.COM 		if (stat & HERMON_HW_FLASH_ICS_ERROR) {
17609517SBill.Taylor@Sun.COM 			cmn_err(CE_WARN,
17619517SBill.Taylor@Sun.COM 			    "hermon_flash_write_byte: ICS write cmd error: "
17629517SBill.Taylor@Sun.COM 			    "addr: %x, data: %x\n",
17639517SBill.Taylor@Sun.COM 			    addr, data);
17649517SBill.Taylor@Sun.COM 			hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
17659517SBill.Taylor@Sun.COM 			return (EIO);
17669517SBill.Taylor@Sun.COM 		}
17679517SBill.Taylor@Sun.COM 		break;
17689517SBill.Taylor@Sun.COM 
17699517SBill.Taylor@Sun.COM 	case HERMON_FLASH_SPI_CMDSET:
17709517SBill.Taylor@Sun.COM 		/*
17719517SBill.Taylor@Sun.COM 		 * Our lowest write granularity on SPI is a dword.
17729517SBill.Taylor@Sun.COM 		 * To support this ioctl option, we can read in the
17739517SBill.Taylor@Sun.COM 		 * dword that contains this byte, modify this byte,
17749517SBill.Taylor@Sun.COM 		 * and write the dword back out.
17759517SBill.Taylor@Sun.COM 		 */
17769517SBill.Taylor@Sun.COM 
17779517SBill.Taylor@Sun.COM 		/* Determine dword offset and byte offset within the dword */
17789517SBill.Taylor@Sun.COM 		byte_offset = addr & 3;
17799517SBill.Taylor@Sun.COM 		dword_addr = addr - byte_offset;
17809517SBill.Taylor@Sun.COM #ifdef _LITTLE_ENDIAN
17819517SBill.Taylor@Sun.COM 		byte_offset = 3 - byte_offset;
17829517SBill.Taylor@Sun.COM #endif
17839517SBill.Taylor@Sun.COM 
17849517SBill.Taylor@Sun.COM 		/* Read in dword */
17859517SBill.Taylor@Sun.COM 		if ((status = hermon_flash_read_quadlet(state, &dword.dword,
17869517SBill.Taylor@Sun.COM 		    dword_addr)) != 0)
17879517SBill.Taylor@Sun.COM 			break;
17889517SBill.Taylor@Sun.COM 
17899517SBill.Taylor@Sun.COM 		/* Set "data" to the appopriate byte */
17909517SBill.Taylor@Sun.COM 		dword.bytes[byte_offset] = data;
17919517SBill.Taylor@Sun.COM 
17929517SBill.Taylor@Sun.COM 		/* Write modified dword back out */
17939517SBill.Taylor@Sun.COM 		status = hermon_flash_spi_write_dword(state, dword_addr,
17949517SBill.Taylor@Sun.COM 		    dword.dword);
17959517SBill.Taylor@Sun.COM 
17969517SBill.Taylor@Sun.COM 		break;
17979517SBill.Taylor@Sun.COM 
17989517SBill.Taylor@Sun.COM 	case HERMON_FLASH_UNKNOWN_CMDSET:
17999517SBill.Taylor@Sun.COM 	default:
18009517SBill.Taylor@Sun.COM 		cmn_err(CE_WARN,
18019517SBill.Taylor@Sun.COM 		    "hermon_flash_write_byte: unknown cmd set: 0x%x\n",
18029517SBill.Taylor@Sun.COM 		    state->hs_fw_cmdset);
18039517SBill.Taylor@Sun.COM 		status = EINVAL;
18049517SBill.Taylor@Sun.COM 		break;
18059517SBill.Taylor@Sun.COM 	}
18069517SBill.Taylor@Sun.COM 
18079517SBill.Taylor@Sun.COM 	return (status);
18089517SBill.Taylor@Sun.COM }
18099517SBill.Taylor@Sun.COM 
18109517SBill.Taylor@Sun.COM /*
18119517SBill.Taylor@Sun.COM  * hermon_flash_erase_sector()
18129517SBill.Taylor@Sun.COM  */
18139517SBill.Taylor@Sun.COM static int
hermon_flash_erase_sector(hermon_state_t * state,uint32_t sector_num)18149517SBill.Taylor@Sun.COM hermon_flash_erase_sector(hermon_state_t *state, uint32_t sector_num)
18159517SBill.Taylor@Sun.COM {
18169517SBill.Taylor@Sun.COM 	ddi_acc_handle_t	hdl;
18179517SBill.Taylor@Sun.COM 	uint32_t addr;
18189517SBill.Taylor@Sun.COM 	uint32_t stat;
18199517SBill.Taylor@Sun.COM 	int status = 0;
18209517SBill.Taylor@Sun.COM 	int i;
18219517SBill.Taylor@Sun.COM 
18229517SBill.Taylor@Sun.COM 	/* initialize the FMA retry loop */
18239517SBill.Taylor@Sun.COM 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
18249517SBill.Taylor@Sun.COM 
18259517SBill.Taylor@Sun.COM 	/* Get address from sector num */
18269517SBill.Taylor@Sun.COM 	addr = sector_num << state->hs_fw_log_sector_sz;
18279517SBill.Taylor@Sun.COM 
18289517SBill.Taylor@Sun.COM 	switch (state->hs_fw_cmdset) {
18299517SBill.Taylor@Sun.COM 	case HERMON_FLASH_AMD_CMDSET:
18309517SBill.Taylor@Sun.COM 		/* Issue Flash Sector Erase Command */
18319517SBill.Taylor@Sun.COM 		hermon_flash_write(state, addr, 0xAA, &status);
18329517SBill.Taylor@Sun.COM 		if (status != 0) {
18339517SBill.Taylor@Sun.COM 			return (status);
18349517SBill.Taylor@Sun.COM 		}
18359517SBill.Taylor@Sun.COM 
18369517SBill.Taylor@Sun.COM 		hermon_flash_write(state, addr, 0x55, &status);
18379517SBill.Taylor@Sun.COM 		if (status != 0) {
18389517SBill.Taylor@Sun.COM 			return (status);
18399517SBill.Taylor@Sun.COM 		}
18409517SBill.Taylor@Sun.COM 
18419517SBill.Taylor@Sun.COM 		hermon_flash_write(state, addr, 0x80, &status);
18429517SBill.Taylor@Sun.COM 		if (status != 0) {
18439517SBill.Taylor@Sun.COM 			return (status);
18449517SBill.Taylor@Sun.COM 		}
18459517SBill.Taylor@Sun.COM 
18469517SBill.Taylor@Sun.COM 		hermon_flash_write(state, addr, 0xAA, &status);
18479517SBill.Taylor@Sun.COM 		if (status != 0) {
18489517SBill.Taylor@Sun.COM 			return (status);
18499517SBill.Taylor@Sun.COM 		}
18509517SBill.Taylor@Sun.COM 
18519517SBill.Taylor@Sun.COM 		hermon_flash_write(state, addr, 0x55, &status);
18529517SBill.Taylor@Sun.COM 		if (status != 0) {
18539517SBill.Taylor@Sun.COM 			return (status);
18549517SBill.Taylor@Sun.COM 		}
18559517SBill.Taylor@Sun.COM 
18569517SBill.Taylor@Sun.COM 		hermon_flash_write(state, addr, 0x30, &status);
18579517SBill.Taylor@Sun.COM 		if (status != 0) {
18589517SBill.Taylor@Sun.COM 			return (status);
18599517SBill.Taylor@Sun.COM 		}
18609517SBill.Taylor@Sun.COM 
18619517SBill.Taylor@Sun.COM 		/* Wait for Sector Erase to complete */
18629517SBill.Taylor@Sun.COM 		i = 0;
18639517SBill.Taylor@Sun.COM 		do {
18649517SBill.Taylor@Sun.COM 			drv_usecwait(1);
18659517SBill.Taylor@Sun.COM 			stat = hermon_flash_read(state, addr, &status);
18669517SBill.Taylor@Sun.COM 			if (status != 0) {
18679517SBill.Taylor@Sun.COM 				return (status);
18689517SBill.Taylor@Sun.COM 			}
18699517SBill.Taylor@Sun.COM 
18709517SBill.Taylor@Sun.COM 			if (i == hermon_hw_flash_timeout_erase) {
18719517SBill.Taylor@Sun.COM 				cmn_err(CE_WARN,
18729517SBill.Taylor@Sun.COM 				    "hermon_flash_erase_sector: "
18739517SBill.Taylor@Sun.COM 				    "ACS erase timeout\n");
18749517SBill.Taylor@Sun.COM 				hermon_fm_ereport(state, HCA_SYS_ERR,
18759517SBill.Taylor@Sun.COM 				    HCA_ERR_IOCTL);
18769517SBill.Taylor@Sun.COM 				return (EIO);
18779517SBill.Taylor@Sun.COM 			}
18789517SBill.Taylor@Sun.COM 			i++;
18799517SBill.Taylor@Sun.COM 		} while (stat != 0xFFFFFFFF);
18809517SBill.Taylor@Sun.COM 		break;
18819517SBill.Taylor@Sun.COM 
18829517SBill.Taylor@Sun.COM 	case HERMON_FLASH_INTEL_CMDSET:
18839517SBill.Taylor@Sun.COM 		/* Issue Flash Sector Erase Command */
18849517SBill.Taylor@Sun.COM 		hermon_flash_write(state, addr, HERMON_HW_FLASH_ICS_ERASE,
18859517SBill.Taylor@Sun.COM 		    &status);
18869517SBill.Taylor@Sun.COM 		if (status != 0) {
18879517SBill.Taylor@Sun.COM 			return (status);
18889517SBill.Taylor@Sun.COM 		}
18899517SBill.Taylor@Sun.COM 
18909517SBill.Taylor@Sun.COM 		hermon_flash_write(state, addr, HERMON_HW_FLASH_ICS_CONFIRM,
18919517SBill.Taylor@Sun.COM 		    &status);
18929517SBill.Taylor@Sun.COM 		if (status != 0) {
18939517SBill.Taylor@Sun.COM 			return (status);
18949517SBill.Taylor@Sun.COM 		}
18959517SBill.Taylor@Sun.COM 
18969517SBill.Taylor@Sun.COM 		/* Wait for Sector Erase to complete */
18979517SBill.Taylor@Sun.COM 		i = 0;
18989517SBill.Taylor@Sun.COM 		do {
18999517SBill.Taylor@Sun.COM 			drv_usecwait(1);
19009517SBill.Taylor@Sun.COM 			stat = hermon_flash_read(state, addr & ~3, &status);
19019517SBill.Taylor@Sun.COM 			if (status != 0) {
19029517SBill.Taylor@Sun.COM 				return (status);
19039517SBill.Taylor@Sun.COM 			}
19049517SBill.Taylor@Sun.COM 
19059517SBill.Taylor@Sun.COM 			if (i == hermon_hw_flash_timeout_erase) {
19069517SBill.Taylor@Sun.COM 				cmn_err(CE_WARN,
19079517SBill.Taylor@Sun.COM 				    "hermon_flash_erase_sector: "
19089517SBill.Taylor@Sun.COM 				    "ICS erase timeout\n");
19099517SBill.Taylor@Sun.COM 				hermon_fm_ereport(state, HCA_SYS_ERR,
19109517SBill.Taylor@Sun.COM 				    HCA_ERR_IOCTL);
19119517SBill.Taylor@Sun.COM 				return (EIO);
19129517SBill.Taylor@Sun.COM 			}
19139517SBill.Taylor@Sun.COM 			i++;
19149517SBill.Taylor@Sun.COM 		} while ((stat & HERMON_HW_FLASH_ICS_READY) == 0);
19159517SBill.Taylor@Sun.COM 
19169517SBill.Taylor@Sun.COM 		if (stat & HERMON_HW_FLASH_ICS_ERROR) {
19179517SBill.Taylor@Sun.COM 			cmn_err(CE_WARN,
19189517SBill.Taylor@Sun.COM 			    "hermon_flash_erase_sector: "
19199517SBill.Taylor@Sun.COM 			    "ICS erase cmd error\n");
19209517SBill.Taylor@Sun.COM 			hermon_fm_ereport(state, HCA_SYS_ERR,
19219517SBill.Taylor@Sun.COM 			    HCA_ERR_IOCTL);
19229517SBill.Taylor@Sun.COM 			return (EIO);
19239517SBill.Taylor@Sun.COM 		}
19249517SBill.Taylor@Sun.COM 		break;
19259517SBill.Taylor@Sun.COM 
19269517SBill.Taylor@Sun.COM 	case HERMON_FLASH_SPI_CMDSET:
19279517SBill.Taylor@Sun.COM 		hdl = hermon_get_pcihdl(state);
19289517SBill.Taylor@Sun.COM 
19299517SBill.Taylor@Sun.COM 		/* the FMA retry loop starts. */
19309517SBill.Taylor@Sun.COM 		hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status,
19319517SBill.Taylor@Sun.COM 		    fm_test);
19329517SBill.Taylor@Sun.COM 
19339517SBill.Taylor@Sun.COM 		/* Issue Write Enable */
19349517SBill.Taylor@Sun.COM 		hermon_flash_spi_write_enable(state);
19359517SBill.Taylor@Sun.COM 
19369517SBill.Taylor@Sun.COM 		/* Set the Address */
19379517SBill.Taylor@Sun.COM 		hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_SPI_ADDR,
19389517SBill.Taylor@Sun.COM 		    addr & HERMON_HW_FLASH_SPI_ADDR_MASK);
19399517SBill.Taylor@Sun.COM 
19409517SBill.Taylor@Sun.COM 		/* Issue Flash Sector Erase */
19419517SBill.Taylor@Sun.COM 		hermon_flash_spi_exec_command(state, hdl,
19429517SBill.Taylor@Sun.COM 		    HERMON_HW_FLASH_SPI_INSTR_PHASE_OFF |
19439517SBill.Taylor@Sun.COM 		    HERMON_HW_FLASH_SPI_ADDR_PHASE_OFF |
19449517SBill.Taylor@Sun.COM 		    ((uint32_t)(HERMON_HW_FLASH_SPI_SECTOR_ERASE) <<
19459517SBill.Taylor@Sun.COM 		    HERMON_HW_FLASH_SPI_INSTR_SHIFT));
19469517SBill.Taylor@Sun.COM 
19479517SBill.Taylor@Sun.COM 		/* the FMA retry loop ends. */
19489517SBill.Taylor@Sun.COM 		hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status,
19499517SBill.Taylor@Sun.COM 		    fm_test);
19509517SBill.Taylor@Sun.COM 
19519517SBill.Taylor@Sun.COM 		/* Wait for Sector Erase to complete */
19529517SBill.Taylor@Sun.COM 		status = hermon_flash_spi_wait_wip(state);
19539517SBill.Taylor@Sun.COM 		break;
19549517SBill.Taylor@Sun.COM 
19559517SBill.Taylor@Sun.COM 	case HERMON_FLASH_UNKNOWN_CMDSET:
19569517SBill.Taylor@Sun.COM 	default:
19579517SBill.Taylor@Sun.COM 		cmn_err(CE_WARN,
19589517SBill.Taylor@Sun.COM 		    "hermon_flash_erase_sector: unknown cmd set: 0x%x\n",
19599517SBill.Taylor@Sun.COM 		    state->hs_fw_cmdset);
19609517SBill.Taylor@Sun.COM 		status = EINVAL;
19619517SBill.Taylor@Sun.COM 		break;
19629517SBill.Taylor@Sun.COM 	}
19639517SBill.Taylor@Sun.COM 
19649517SBill.Taylor@Sun.COM 	/* Reset the flash device */
19659517SBill.Taylor@Sun.COM 	if (status == 0) {
19669517SBill.Taylor@Sun.COM 		status = hermon_flash_reset(state);
19679517SBill.Taylor@Sun.COM 	}
19689517SBill.Taylor@Sun.COM 	return (status);
19699517SBill.Taylor@Sun.COM 
19709517SBill.Taylor@Sun.COM pio_error:
19719517SBill.Taylor@Sun.COM 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
19729517SBill.Taylor@Sun.COM 	return (EIO);
19739517SBill.Taylor@Sun.COM }
19749517SBill.Taylor@Sun.COM 
19759517SBill.Taylor@Sun.COM /*
19769517SBill.Taylor@Sun.COM  * hermon_flash_erase_chip()
19779517SBill.Taylor@Sun.COM  */
19789517SBill.Taylor@Sun.COM static int
hermon_flash_erase_chip(hermon_state_t * state)19799517SBill.Taylor@Sun.COM hermon_flash_erase_chip(hermon_state_t *state)
19809517SBill.Taylor@Sun.COM {
19819517SBill.Taylor@Sun.COM 	uint32_t stat;
19829517SBill.Taylor@Sun.COM 	uint_t size;
19839517SBill.Taylor@Sun.COM 	int status = 0;
19849517SBill.Taylor@Sun.COM 	int i;
19859517SBill.Taylor@Sun.COM 	int num_sect;
19869517SBill.Taylor@Sun.COM 
19879517SBill.Taylor@Sun.COM 	switch (state->hs_fw_cmdset) {
19889517SBill.Taylor@Sun.COM 	case HERMON_FLASH_AMD_CMDSET:
19899517SBill.Taylor@Sun.COM 		/* Issue Flash Chip Erase Command */
19909517SBill.Taylor@Sun.COM 		hermon_flash_write(state, 0, 0xAA, &status);
19919517SBill.Taylor@Sun.COM 		if (status != 0) {
19929517SBill.Taylor@Sun.COM 			return (status);
19939517SBill.Taylor@Sun.COM 		}
19949517SBill.Taylor@Sun.COM 
19959517SBill.Taylor@Sun.COM 		hermon_flash_write(state, 0, 0x55, &status);
19969517SBill.Taylor@Sun.COM 		if (status != 0) {
19979517SBill.Taylor@Sun.COM 			return (status);
19989517SBill.Taylor@Sun.COM 		}
19999517SBill.Taylor@Sun.COM 
20009517SBill.Taylor@Sun.COM 		hermon_flash_write(state, 0, 0x80, &status);
20019517SBill.Taylor@Sun.COM 		if (status != 0) {
20029517SBill.Taylor@Sun.COM 			return (status);
20039517SBill.Taylor@Sun.COM 		}
20049517SBill.Taylor@Sun.COM 
20059517SBill.Taylor@Sun.COM 		hermon_flash_write(state, 0, 0xAA, &status);
20069517SBill.Taylor@Sun.COM 		if (status != 0) {
20079517SBill.Taylor@Sun.COM 			return (status);
20089517SBill.Taylor@Sun.COM 		}
20099517SBill.Taylor@Sun.COM 
20109517SBill.Taylor@Sun.COM 		hermon_flash_write(state, 0, 0x55, &status);
20119517SBill.Taylor@Sun.COM 		if (status != 0) {
20129517SBill.Taylor@Sun.COM 			return (status);
20139517SBill.Taylor@Sun.COM 		}
20149517SBill.Taylor@Sun.COM 
20159517SBill.Taylor@Sun.COM 		hermon_flash_write(state, 0, 0x10, &status);
20169517SBill.Taylor@Sun.COM 		if (status != 0) {
20179517SBill.Taylor@Sun.COM 			return (status);
20189517SBill.Taylor@Sun.COM 		}
20199517SBill.Taylor@Sun.COM 
20209517SBill.Taylor@Sun.COM 		/* Wait for Chip Erase to Complete */
20219517SBill.Taylor@Sun.COM 		i = 0;
20229517SBill.Taylor@Sun.COM 		do {
20239517SBill.Taylor@Sun.COM 			drv_usecwait(1);
20249517SBill.Taylor@Sun.COM 			stat = hermon_flash_read(state, 0, &status);
20259517SBill.Taylor@Sun.COM 			if (status != 0) {
20269517SBill.Taylor@Sun.COM 				return (status);
20279517SBill.Taylor@Sun.COM 			}
20289517SBill.Taylor@Sun.COM 
20299517SBill.Taylor@Sun.COM 			if (i == hermon_hw_flash_timeout_erase) {
20309517SBill.Taylor@Sun.COM 				cmn_err(CE_WARN,
20319517SBill.Taylor@Sun.COM 				    "hermon_flash_erase_chip: erase timeout\n");
20329517SBill.Taylor@Sun.COM 				hermon_fm_ereport(state, HCA_SYS_ERR,
20339517SBill.Taylor@Sun.COM 				    HCA_ERR_IOCTL);
20349517SBill.Taylor@Sun.COM 				return (EIO);
20359517SBill.Taylor@Sun.COM 			}
20369517SBill.Taylor@Sun.COM 			i++;
20379517SBill.Taylor@Sun.COM 		} while (stat != 0xFFFFFFFF);
20389517SBill.Taylor@Sun.COM 		break;
20399517SBill.Taylor@Sun.COM 
20409517SBill.Taylor@Sun.COM 	case HERMON_FLASH_INTEL_CMDSET:
20419517SBill.Taylor@Sun.COM 	case HERMON_FLASH_SPI_CMDSET:
20429517SBill.Taylor@Sun.COM 		/*
20439517SBill.Taylor@Sun.COM 		 * These chips don't have a chip erase command, so erase
20449517SBill.Taylor@Sun.COM 		 * all blocks one at a time.
20459517SBill.Taylor@Sun.COM 		 */
20469517SBill.Taylor@Sun.COM 		size = (0x1 << state->hs_fw_log_sector_sz);
20479517SBill.Taylor@Sun.COM 		num_sect = state->hs_fw_device_sz / size;
20489517SBill.Taylor@Sun.COM 
20499517SBill.Taylor@Sun.COM 		for (i = 0; i < num_sect; i++) {
20509517SBill.Taylor@Sun.COM 			status = hermon_flash_erase_sector(state, i);
20519517SBill.Taylor@Sun.COM 			if (status != 0) {
20529517SBill.Taylor@Sun.COM 				cmn_err(CE_WARN,
20539517SBill.Taylor@Sun.COM 				    "hermon_flash_erase_chip: "
20549517SBill.Taylor@Sun.COM 				    "sector %d erase error\n", i);
20559517SBill.Taylor@Sun.COM 				return (status);
20569517SBill.Taylor@Sun.COM 			}
20579517SBill.Taylor@Sun.COM 		}
20589517SBill.Taylor@Sun.COM 		break;
20599517SBill.Taylor@Sun.COM 
20609517SBill.Taylor@Sun.COM 	case HERMON_FLASH_UNKNOWN_CMDSET:
20619517SBill.Taylor@Sun.COM 	default:
20629517SBill.Taylor@Sun.COM 		cmn_err(CE_WARN, "hermon_flash_erase_chip: "
20639517SBill.Taylor@Sun.COM 		    "unknown cmd set: 0x%x\n", state->hs_fw_cmdset);
20649517SBill.Taylor@Sun.COM 		status = EINVAL;
20659517SBill.Taylor@Sun.COM 		break;
20669517SBill.Taylor@Sun.COM 	}
20679517SBill.Taylor@Sun.COM 
20689517SBill.Taylor@Sun.COM 	return (status);
20699517SBill.Taylor@Sun.COM }
20709517SBill.Taylor@Sun.COM 
20719517SBill.Taylor@Sun.COM /*
20729517SBill.Taylor@Sun.COM  * hermon_flash_spi_write_enable()
20739517SBill.Taylor@Sun.COM  */
20749517SBill.Taylor@Sun.COM static void
hermon_flash_spi_write_enable(hermon_state_t * state)20759517SBill.Taylor@Sun.COM hermon_flash_spi_write_enable(hermon_state_t *state)
20769517SBill.Taylor@Sun.COM {
20779517SBill.Taylor@Sun.COM 	ddi_acc_handle_t	hdl;
20789517SBill.Taylor@Sun.COM 
20799517SBill.Taylor@Sun.COM 	hdl = hermon_get_pcihdl(state);
20809517SBill.Taylor@Sun.COM 
20819517SBill.Taylor@Sun.COM 	hermon_flash_spi_exec_command(state, hdl,
20829517SBill.Taylor@Sun.COM 	    HERMON_HW_FLASH_SPI_INSTR_PHASE_OFF |
20839517SBill.Taylor@Sun.COM 	    (HERMON_HW_FLASH_SPI_WRITE_ENABLE <<
20849517SBill.Taylor@Sun.COM 	    HERMON_HW_FLASH_SPI_INSTR_SHIFT));
20859517SBill.Taylor@Sun.COM }
20869517SBill.Taylor@Sun.COM 
20879517SBill.Taylor@Sun.COM /*
20889517SBill.Taylor@Sun.COM  * hermon_flash_spi_wait_wip()
20899517SBill.Taylor@Sun.COM  */
20909517SBill.Taylor@Sun.COM static int
hermon_flash_spi_wait_wip(hermon_state_t * state)20919517SBill.Taylor@Sun.COM hermon_flash_spi_wait_wip(hermon_state_t *state)
20929517SBill.Taylor@Sun.COM {
20939517SBill.Taylor@Sun.COM 	ddi_acc_handle_t	hdl;
20949517SBill.Taylor@Sun.COM 	uint32_t		status;
20959517SBill.Taylor@Sun.COM 
20969517SBill.Taylor@Sun.COM 	/* initialize the FMA retry loop */
20979517SBill.Taylor@Sun.COM 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
20989517SBill.Taylor@Sun.COM 
20999517SBill.Taylor@Sun.COM 	hdl = hermon_get_pcihdl(state);
21009517SBill.Taylor@Sun.COM 
21019517SBill.Taylor@Sun.COM 	/* the FMA retry loop starts. */
21029517SBill.Taylor@Sun.COM 	hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status,
21039517SBill.Taylor@Sun.COM 	    fm_test);
21049517SBill.Taylor@Sun.COM 
21059517SBill.Taylor@Sun.COM 	/* wait on the gateway to clear busy */
21069517SBill.Taylor@Sun.COM 	do {
21079517SBill.Taylor@Sun.COM 		status = hermon_flash_read_cfg(state, hdl,
21089517SBill.Taylor@Sun.COM 		    HERMON_HW_FLASH_SPI_GW);
21099517SBill.Taylor@Sun.COM 	} while (status & HERMON_HW_FLASH_SPI_BUSY);
21109517SBill.Taylor@Sun.COM 
21119517SBill.Taylor@Sun.COM 	/* now, get the status and check for WIP to clear */
21129517SBill.Taylor@Sun.COM 	do {
21139517SBill.Taylor@Sun.COM 		hermon_flash_spi_exec_command(state, hdl,
21149517SBill.Taylor@Sun.COM 		    HERMON_HW_FLASH_SPI_READ_OP |
21159517SBill.Taylor@Sun.COM 		    HERMON_HW_FLASH_SPI_INSTR_PHASE_OFF |
21169517SBill.Taylor@Sun.COM 		    HERMON_HW_FLASH_SPI_DATA_PHASE_OFF |
21179517SBill.Taylor@Sun.COM 		    HERMON_HW_FLASH_SPI_TRANS_SZ_4B |
21189517SBill.Taylor@Sun.COM 		    (HERMON_HW_FLASH_SPI_READ_STATUS_REG <<
21199517SBill.Taylor@Sun.COM 		    HERMON_HW_FLASH_SPI_INSTR_SHIFT));
21209517SBill.Taylor@Sun.COM 
21219517SBill.Taylor@Sun.COM 		status = hermon_flash_read_cfg(state, hdl,
21229517SBill.Taylor@Sun.COM 		    HERMON_HW_FLASH_SPI_DATA);
21239517SBill.Taylor@Sun.COM 	} while (status & HERMON_HW_FLASH_SPI_WIP);
21249517SBill.Taylor@Sun.COM 
21259517SBill.Taylor@Sun.COM 	/* the FMA retry loop ends. */
21269517SBill.Taylor@Sun.COM 	hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status, fm_test);
21279517SBill.Taylor@Sun.COM 	return (0);
21289517SBill.Taylor@Sun.COM 
21299517SBill.Taylor@Sun.COM pio_error:
21309517SBill.Taylor@Sun.COM 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
21319517SBill.Taylor@Sun.COM 	return (EIO);
21329517SBill.Taylor@Sun.COM }
21339517SBill.Taylor@Sun.COM 
21349517SBill.Taylor@Sun.COM /*
21359517SBill.Taylor@Sun.COM  * hermon_flash_bank()
21369517SBill.Taylor@Sun.COM  */
21379517SBill.Taylor@Sun.COM static int
hermon_flash_bank(hermon_state_t * state,uint32_t addr)21389517SBill.Taylor@Sun.COM hermon_flash_bank(hermon_state_t *state, uint32_t addr)
21399517SBill.Taylor@Sun.COM {
21409517SBill.Taylor@Sun.COM 	ddi_acc_handle_t	hdl;
21419517SBill.Taylor@Sun.COM 	uint32_t		bank;
21429517SBill.Taylor@Sun.COM 
21439517SBill.Taylor@Sun.COM 	/* initialize the FMA retry loop */
21449517SBill.Taylor@Sun.COM 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
21459517SBill.Taylor@Sun.COM 
21469517SBill.Taylor@Sun.COM 	/* Set handle */
21479517SBill.Taylor@Sun.COM 	hdl = hermon_get_pcihdl(state);
21489517SBill.Taylor@Sun.COM 
21499517SBill.Taylor@Sun.COM 	/* Determine the bank setting from the address */
21509517SBill.Taylor@Sun.COM 	bank = addr & HERMON_HW_FLASH_BANK_MASK;
21519517SBill.Taylor@Sun.COM 
21529517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(state->hs_fw_flashbank))
21539517SBill.Taylor@Sun.COM 
21549517SBill.Taylor@Sun.COM 	/*
21559517SBill.Taylor@Sun.COM 	 * If the bank is different from the currently set bank, we need to
21569517SBill.Taylor@Sun.COM 	 * change it.  Also, if an 'addr' of 0 is given, this allows the
21579517SBill.Taylor@Sun.COM 	 * capability to force the flash bank to 0.  This is useful at init
21589517SBill.Taylor@Sun.COM 	 * time to initially set the bank value
21599517SBill.Taylor@Sun.COM 	 */
21609517SBill.Taylor@Sun.COM 	if (state->hs_fw_flashbank != bank || addr == 0) {
21619517SBill.Taylor@Sun.COM 		switch (state->hs_fw_cmdset) {
21629517SBill.Taylor@Sun.COM 		case HERMON_FLASH_SPI_CMDSET:
21639517SBill.Taylor@Sun.COM 			/* CMJ: not needed for hermon */
21649517SBill.Taylor@Sun.COM 			break;
21659517SBill.Taylor@Sun.COM 
21669517SBill.Taylor@Sun.COM 		case HERMON_FLASH_INTEL_CMDSET:
21679517SBill.Taylor@Sun.COM 		case HERMON_FLASH_AMD_CMDSET:
21689517SBill.Taylor@Sun.COM 			/* the FMA retry loop starts. */
21699517SBill.Taylor@Sun.COM 			hermon_pio_start(state, hdl, pio_error, fm_loop_cnt,
21709517SBill.Taylor@Sun.COM 			    fm_status, fm_test);
21719517SBill.Taylor@Sun.COM 
21729517SBill.Taylor@Sun.COM 			hermon_flash_write_cfg(state, hdl,
21739517SBill.Taylor@Sun.COM 			    HERMON_HW_FLASH_GPIO_DATACLEAR, 0x70);
21749517SBill.Taylor@Sun.COM 			hermon_flash_write_cfg(state, hdl,
21759517SBill.Taylor@Sun.COM 			    HERMON_HW_FLASH_GPIO_DATASET, (bank >> 15) & 0x70);
21769517SBill.Taylor@Sun.COM 
21779517SBill.Taylor@Sun.COM 			/* the FMA retry loop ends. */
21789517SBill.Taylor@Sun.COM 			hermon_pio_end(state, hdl, pio_error, fm_loop_cnt,
21799517SBill.Taylor@Sun.COM 			    fm_status, fm_test);
21809517SBill.Taylor@Sun.COM 			break;
21819517SBill.Taylor@Sun.COM 
21829517SBill.Taylor@Sun.COM 		case HERMON_FLASH_UNKNOWN_CMDSET:
21839517SBill.Taylor@Sun.COM 		default:
21849517SBill.Taylor@Sun.COM 			return (EINVAL);
21859517SBill.Taylor@Sun.COM 		}
21869517SBill.Taylor@Sun.COM 
21879517SBill.Taylor@Sun.COM 		state->hs_fw_flashbank = bank;
21889517SBill.Taylor@Sun.COM 	}
21899517SBill.Taylor@Sun.COM 	return (0);
21909517SBill.Taylor@Sun.COM 
21919517SBill.Taylor@Sun.COM pio_error:
21929517SBill.Taylor@Sun.COM 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
21939517SBill.Taylor@Sun.COM 	return (EIO);
21949517SBill.Taylor@Sun.COM }
21959517SBill.Taylor@Sun.COM 
21969517SBill.Taylor@Sun.COM /*
21979517SBill.Taylor@Sun.COM  * hermon_flash_spi_exec_command()
21989517SBill.Taylor@Sun.COM  */
21999517SBill.Taylor@Sun.COM static void
hermon_flash_spi_exec_command(hermon_state_t * state,ddi_acc_handle_t hdl,uint32_t cmd)22009517SBill.Taylor@Sun.COM hermon_flash_spi_exec_command(hermon_state_t *state, ddi_acc_handle_t hdl,
22019517SBill.Taylor@Sun.COM     uint32_t cmd)
22029517SBill.Taylor@Sun.COM {
22039517SBill.Taylor@Sun.COM 	uint32_t data;
22049517SBill.Taylor@Sun.COM 	int timeout = 0;
22059517SBill.Taylor@Sun.COM 
22069517SBill.Taylor@Sun.COM 	cmd |= HERMON_HW_FLASH_SPI_BUSY | HERMON_HW_FLASH_SPI_ENABLE_OFF;
22079517SBill.Taylor@Sun.COM 
22089517SBill.Taylor@Sun.COM 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_SPI_GW, cmd);
22099517SBill.Taylor@Sun.COM 
22109517SBill.Taylor@Sun.COM 	do {
22119517SBill.Taylor@Sun.COM 		data = hermon_flash_read_cfg(state, hdl,
22129517SBill.Taylor@Sun.COM 		    HERMON_HW_FLASH_SPI_GW);
22139517SBill.Taylor@Sun.COM 		timeout++;
22149517SBill.Taylor@Sun.COM 	} while ((data & HERMON_HW_FLASH_SPI_BUSY) &&
22159517SBill.Taylor@Sun.COM 	    (timeout < hermon_hw_flash_timeout_config));
22169517SBill.Taylor@Sun.COM }
22179517SBill.Taylor@Sun.COM 
22189517SBill.Taylor@Sun.COM /*
22199517SBill.Taylor@Sun.COM  * hermon_flash_read()
22209517SBill.Taylor@Sun.COM  */
22219517SBill.Taylor@Sun.COM static uint32_t
hermon_flash_read(hermon_state_t * state,uint32_t addr,int * err)22229517SBill.Taylor@Sun.COM hermon_flash_read(hermon_state_t *state, uint32_t addr, int *err)
22239517SBill.Taylor@Sun.COM {
22249517SBill.Taylor@Sun.COM 	ddi_acc_handle_t	hdl;
22259517SBill.Taylor@Sun.COM 	uint32_t		data = 0;
22269517SBill.Taylor@Sun.COM 	int			timeout, status = 0;
22279517SBill.Taylor@Sun.COM 
22289517SBill.Taylor@Sun.COM 	/* initialize the FMA retry loop */
22299517SBill.Taylor@Sun.COM 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
22309517SBill.Taylor@Sun.COM 
22319517SBill.Taylor@Sun.COM 	hdl = hermon_get_pcihdl(state);
22329517SBill.Taylor@Sun.COM 
22339517SBill.Taylor@Sun.COM 	/* the FMA retry loop starts. */
22349517SBill.Taylor@Sun.COM 	hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status,
22359517SBill.Taylor@Sun.COM 	    fm_test);
22369517SBill.Taylor@Sun.COM 
22379517SBill.Taylor@Sun.COM 	switch (state->hs_fw_cmdset) {
22389517SBill.Taylor@Sun.COM 	case HERMON_FLASH_SPI_CMDSET:
22399517SBill.Taylor@Sun.COM 		/* Set the transaction address */
22409517SBill.Taylor@Sun.COM 		hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_SPI_ADDR,
22419517SBill.Taylor@Sun.COM 		    (addr & HERMON_HW_FLASH_SPI_ADDR_MASK));
22429517SBill.Taylor@Sun.COM 
22439517SBill.Taylor@Sun.COM 		hermon_flash_spi_exec_command(state, hdl,
22449517SBill.Taylor@Sun.COM 		    HERMON_HW_FLASH_SPI_READ_OP |
22459517SBill.Taylor@Sun.COM 		    HERMON_HW_FLASH_SPI_INSTR_PHASE_OFF |
22469517SBill.Taylor@Sun.COM 		    HERMON_HW_FLASH_SPI_ADDR_PHASE_OFF |
22479517SBill.Taylor@Sun.COM 		    HERMON_HW_FLASH_SPI_DATA_PHASE_OFF |
22489517SBill.Taylor@Sun.COM 		    HERMON_HW_FLASH_SPI_TRANS_SZ_4B |
22499517SBill.Taylor@Sun.COM 		    (HERMON_HW_FLASH_SPI_READ <<
22509517SBill.Taylor@Sun.COM 		    HERMON_HW_FLASH_SPI_INSTR_SHIFT));
22519517SBill.Taylor@Sun.COM 
22529517SBill.Taylor@Sun.COM 		data = hermon_flash_read_cfg(state, hdl,
22539517SBill.Taylor@Sun.COM 		    HERMON_HW_FLASH_SPI_DATA);
22549517SBill.Taylor@Sun.COM 		break;
22559517SBill.Taylor@Sun.COM 
22569517SBill.Taylor@Sun.COM 	case HERMON_FLASH_INTEL_CMDSET:
22579517SBill.Taylor@Sun.COM 	case HERMON_FLASH_AMD_CMDSET:
22589517SBill.Taylor@Sun.COM 		/*
22599517SBill.Taylor@Sun.COM 		 * The Read operation does the following:
22609517SBill.Taylor@Sun.COM 		 *   1) Write the masked address to the HERMON_FLASH_ADDR
22619517SBill.Taylor@Sun.COM 		 *	register. Only the least significant 19 bits are valid.
22629517SBill.Taylor@Sun.COM 		 *   2) Read back the register until the command has completed.
22639517SBill.Taylor@Sun.COM 		 *   3) Read the data retrieved from the address at the
22649517SBill.Taylor@Sun.COM 		 *	HERMON_FLASH_DATA register.
22659517SBill.Taylor@Sun.COM 		 */
22669517SBill.Taylor@Sun.COM 		hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_ADDR,
22679517SBill.Taylor@Sun.COM 		    (addr & HERMON_HW_FLASH_ADDR_MASK) | (1 << 29));
22689517SBill.Taylor@Sun.COM 
22699517SBill.Taylor@Sun.COM 		timeout = 0;
22709517SBill.Taylor@Sun.COM 		do {
22719517SBill.Taylor@Sun.COM 			data = hermon_flash_read_cfg(state, hdl,
22729517SBill.Taylor@Sun.COM 			    HERMON_HW_FLASH_ADDR);
22739517SBill.Taylor@Sun.COM 			timeout++;
22749517SBill.Taylor@Sun.COM 		} while ((data & HERMON_HW_FLASH_CMD_MASK) &&
22759517SBill.Taylor@Sun.COM 		    (timeout < hermon_hw_flash_timeout_config));
22769517SBill.Taylor@Sun.COM 
227711951SShantkumar.Hiremath@Sun.COM 		if (timeout == hermon_hw_flash_timeout_config) {
227811951SShantkumar.Hiremath@Sun.COM 			cmn_err(CE_WARN, "hermon_flash_read: command timed "
227911951SShantkumar.Hiremath@Sun.COM 			    "out.\n");
228011951SShantkumar.Hiremath@Sun.COM 			*err = EIO;
228111951SShantkumar.Hiremath@Sun.COM 			hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
228211951SShantkumar.Hiremath@Sun.COM 			return (data);
228311951SShantkumar.Hiremath@Sun.COM 		}
228411951SShantkumar.Hiremath@Sun.COM 
22859517SBill.Taylor@Sun.COM 		data = hermon_flash_read_cfg(state, hdl, HERMON_HW_FLASH_DATA);
22869517SBill.Taylor@Sun.COM 		break;
22879517SBill.Taylor@Sun.COM 
22889517SBill.Taylor@Sun.COM 	case HERMON_FLASH_UNKNOWN_CMDSET:
22899517SBill.Taylor@Sun.COM 	default:
22909517SBill.Taylor@Sun.COM 		cmn_err(CE_CONT, "hermon_flash_read: unknown cmdset: 0x%x\n",
22919517SBill.Taylor@Sun.COM 		    state->hs_fw_cmdset);
22929517SBill.Taylor@Sun.COM 		status = EINVAL;
22939517SBill.Taylor@Sun.COM 		break;
22949517SBill.Taylor@Sun.COM 	}
22959517SBill.Taylor@Sun.COM 
22969517SBill.Taylor@Sun.COM 
22979517SBill.Taylor@Sun.COM 	/* the FMA retry loop ends. */
22989517SBill.Taylor@Sun.COM 	hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status, fm_test);
22999517SBill.Taylor@Sun.COM 	*err = status;
23009517SBill.Taylor@Sun.COM 	return (data);
23019517SBill.Taylor@Sun.COM 
23029517SBill.Taylor@Sun.COM pio_error:
23039517SBill.Taylor@Sun.COM 	*err = EIO;
23049517SBill.Taylor@Sun.COM 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
23059517SBill.Taylor@Sun.COM 	return (data);
23069517SBill.Taylor@Sun.COM }
23079517SBill.Taylor@Sun.COM 
23089517SBill.Taylor@Sun.COM /*
23099517SBill.Taylor@Sun.COM  * hermon_flash_write()
23109517SBill.Taylor@Sun.COM  */
23119517SBill.Taylor@Sun.COM static void
hermon_flash_write(hermon_state_t * state,uint32_t addr,uchar_t data,int * err)23129517SBill.Taylor@Sun.COM hermon_flash_write(hermon_state_t *state, uint32_t addr, uchar_t data, int *err)
23139517SBill.Taylor@Sun.COM {
23149517SBill.Taylor@Sun.COM 	ddi_acc_handle_t	hdl;
23159517SBill.Taylor@Sun.COM 	int			cmd;
23169517SBill.Taylor@Sun.COM 	int			timeout;
23179517SBill.Taylor@Sun.COM 
23189517SBill.Taylor@Sun.COM 	/* initialize the FMA retry loop */
23199517SBill.Taylor@Sun.COM 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
23209517SBill.Taylor@Sun.COM 
23219517SBill.Taylor@Sun.COM 	hdl = hermon_get_pcihdl(state);
23229517SBill.Taylor@Sun.COM 
23239517SBill.Taylor@Sun.COM 	/* the FMA retry loop starts. */
23249517SBill.Taylor@Sun.COM 	hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status,
23259517SBill.Taylor@Sun.COM 	    fm_test);
23269517SBill.Taylor@Sun.COM 
23279517SBill.Taylor@Sun.COM 	/*
23289517SBill.Taylor@Sun.COM 	 * The Write operation does the following:
23299517SBill.Taylor@Sun.COM 	 *   1) Write the data to be written to the HERMON_FLASH_DATA offset.
23309517SBill.Taylor@Sun.COM 	 *   2) Write the address to write the data to to the HERMON_FLASH_ADDR
23319517SBill.Taylor@Sun.COM 	 *	offset.
23329517SBill.Taylor@Sun.COM 	 *   3) Wait until the write completes.
23339517SBill.Taylor@Sun.COM 	 */
23349517SBill.Taylor@Sun.COM 
23359517SBill.Taylor@Sun.COM 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_DATA, data << 24);
23369517SBill.Taylor@Sun.COM 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_ADDR,
23379517SBill.Taylor@Sun.COM 	    (addr & 0x7FFFF) | (2 << 29));
23389517SBill.Taylor@Sun.COM 
23399517SBill.Taylor@Sun.COM 	timeout = 0;
23409517SBill.Taylor@Sun.COM 	do {
23419517SBill.Taylor@Sun.COM 		cmd = hermon_flash_read_cfg(state, hdl, HERMON_HW_FLASH_ADDR);
23429517SBill.Taylor@Sun.COM 		timeout++;
23439517SBill.Taylor@Sun.COM 	} while ((cmd & HERMON_HW_FLASH_CMD_MASK) &&
23449517SBill.Taylor@Sun.COM 	    (timeout < hermon_hw_flash_timeout_config));
23459517SBill.Taylor@Sun.COM 
23469517SBill.Taylor@Sun.COM 	if (timeout == hermon_hw_flash_timeout_config) {
23479517SBill.Taylor@Sun.COM 		cmn_err(CE_WARN, "hermon_flash_write: config cmd timeout.\n");
23489517SBill.Taylor@Sun.COM 		*err = EIO;
23499517SBill.Taylor@Sun.COM 		hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
23509517SBill.Taylor@Sun.COM 		return;
23519517SBill.Taylor@Sun.COM 	}
23529517SBill.Taylor@Sun.COM 
23539517SBill.Taylor@Sun.COM 	/* the FMA retry loop ends. */
23549517SBill.Taylor@Sun.COM 	hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status, fm_test);
23559517SBill.Taylor@Sun.COM 	*err = 0;
23569517SBill.Taylor@Sun.COM 	return;
23579517SBill.Taylor@Sun.COM 
23589517SBill.Taylor@Sun.COM pio_error:
23599517SBill.Taylor@Sun.COM 	*err = EIO;
23609517SBill.Taylor@Sun.COM 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
23619517SBill.Taylor@Sun.COM }
23629517SBill.Taylor@Sun.COM 
23639517SBill.Taylor@Sun.COM /*
23649517SBill.Taylor@Sun.COM  * hermon_flash_init()
23659517SBill.Taylor@Sun.COM  */
23669517SBill.Taylor@Sun.COM static int
hermon_flash_init(hermon_state_t * state)23679517SBill.Taylor@Sun.COM hermon_flash_init(hermon_state_t *state)
23689517SBill.Taylor@Sun.COM {
23699517SBill.Taylor@Sun.COM 	uint32_t		word;
23709517SBill.Taylor@Sun.COM 	ddi_acc_handle_t	hdl;
23719517SBill.Taylor@Sun.COM 	int			sema_cnt;
23729517SBill.Taylor@Sun.COM 	int			gpio;
23739517SBill.Taylor@Sun.COM 
23749517SBill.Taylor@Sun.COM 	/* initialize the FMA retry loop */
23759517SBill.Taylor@Sun.COM 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
23769517SBill.Taylor@Sun.COM 
23779517SBill.Taylor@Sun.COM 	/* Set handle */
23789517SBill.Taylor@Sun.COM 	hdl = hermon_get_pcihdl(state);
23799517SBill.Taylor@Sun.COM 
23809517SBill.Taylor@Sun.COM 	/* the FMA retry loop starts. */
23819517SBill.Taylor@Sun.COM 	hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status,
23829517SBill.Taylor@Sun.COM 	    fm_test);
23839517SBill.Taylor@Sun.COM 
23849517SBill.Taylor@Sun.COM 	/* Init the flash */
23859517SBill.Taylor@Sun.COM 
23869517SBill.Taylor@Sun.COM #ifdef DO_WRCONF
23879517SBill.Taylor@Sun.COM 	/*
23889517SBill.Taylor@Sun.COM 	 * Grab the WRCONF semaphore.
23899517SBill.Taylor@Sun.COM 	 */
23909517SBill.Taylor@Sun.COM 	word = hermon_flash_read_cfg(state, hdl, HERMON_HW_FLASH_WRCONF_SEMA);
23919517SBill.Taylor@Sun.COM #endif
23929517SBill.Taylor@Sun.COM 
23939517SBill.Taylor@Sun.COM 	/*
23949517SBill.Taylor@Sun.COM 	 * Grab the GPIO semaphore.  This allows us exclusive access to the
23959517SBill.Taylor@Sun.COM 	 * GPIO settings on the Hermon for the duration of the flash burning
23969517SBill.Taylor@Sun.COM 	 * procedure.
23979517SBill.Taylor@Sun.COM 	 */
23989517SBill.Taylor@Sun.COM 	sema_cnt = 0;
23999517SBill.Taylor@Sun.COM 	do {
24009517SBill.Taylor@Sun.COM 		word = hermon_flash_read_cfg(state, hdl,
24019517SBill.Taylor@Sun.COM 		    HERMON_HW_FLASH_GPIO_SEMA);
24029517SBill.Taylor@Sun.COM 		if (word == 0) {
24039517SBill.Taylor@Sun.COM 			break;
24049517SBill.Taylor@Sun.COM 		}
24059517SBill.Taylor@Sun.COM 
24069517SBill.Taylor@Sun.COM 		sema_cnt++;
24079517SBill.Taylor@Sun.COM 		drv_usecwait(1);
24089517SBill.Taylor@Sun.COM 
24099517SBill.Taylor@Sun.COM 	} while (sema_cnt < hermon_hw_flash_timeout_gpio_sema);
24109517SBill.Taylor@Sun.COM 
24119517SBill.Taylor@Sun.COM 	/*
24129517SBill.Taylor@Sun.COM 	 * Determine if we timed out trying to grab the GPIO semaphore
24139517SBill.Taylor@Sun.COM 	 */
24149517SBill.Taylor@Sun.COM 	if (sema_cnt == hermon_hw_flash_timeout_gpio_sema) {
24159517SBill.Taylor@Sun.COM 		cmn_err(CE_WARN, "hermon_flash_init: GPIO SEMA timeout\n");
24169517SBill.Taylor@Sun.COM 		cmn_err(CE_WARN, "GPIO_SEMA value: 0x%x\n", word);
24179517SBill.Taylor@Sun.COM 		hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
24189517SBill.Taylor@Sun.COM 		return (EIO);
24199517SBill.Taylor@Sun.COM 	}
24209517SBill.Taylor@Sun.COM 
24219517SBill.Taylor@Sun.COM 	/* Save away original GPIO Values */
24229517SBill.Taylor@Sun.COM 	state->hs_fw_gpio[0] = hermon_flash_read_cfg(state, hdl,
24239517SBill.Taylor@Sun.COM 	    HERMON_HW_FLASH_GPIO_DATA);
24249517SBill.Taylor@Sun.COM 
24259517SBill.Taylor@Sun.COM 	/* Set new GPIO value */
24269517SBill.Taylor@Sun.COM 	gpio = state->hs_fw_gpio[0] | HERMON_HW_FLASH_GPIO_PIN_ENABLE;
24279517SBill.Taylor@Sun.COM 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_DATA, gpio);
24289517SBill.Taylor@Sun.COM 
24299517SBill.Taylor@Sun.COM 	/* Save away original GPIO Values */
24309517SBill.Taylor@Sun.COM 	state->hs_fw_gpio[1] = hermon_flash_read_cfg(state, hdl,
24319517SBill.Taylor@Sun.COM 	    HERMON_HW_FLASH_GPIO_MOD0);
24329517SBill.Taylor@Sun.COM 	state->hs_fw_gpio[2] = hermon_flash_read_cfg(state, hdl,
24339517SBill.Taylor@Sun.COM 	    HERMON_HW_FLASH_GPIO_MOD1);
24349517SBill.Taylor@Sun.COM 
24359517SBill.Taylor@Sun.COM 	/* unlock GPIO */
24369517SBill.Taylor@Sun.COM 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_LOCK,
24379517SBill.Taylor@Sun.COM 	    HERMON_HW_FLASH_GPIO_UNLOCK_VAL);
24389517SBill.Taylor@Sun.COM 
24399517SBill.Taylor@Sun.COM 	/*
24409517SBill.Taylor@Sun.COM 	 * Set new GPIO values
24419517SBill.Taylor@Sun.COM 	 */
24429517SBill.Taylor@Sun.COM 	gpio = state->hs_fw_gpio[1] | HERMON_HW_FLASH_GPIO_PIN_ENABLE;
24439517SBill.Taylor@Sun.COM 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_MOD0, gpio);
24449517SBill.Taylor@Sun.COM 
24459517SBill.Taylor@Sun.COM 	gpio = state->hs_fw_gpio[2] & ~HERMON_HW_FLASH_GPIO_PIN_ENABLE;
24469517SBill.Taylor@Sun.COM 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_MOD1, gpio);
24479517SBill.Taylor@Sun.COM 
24489517SBill.Taylor@Sun.COM 	/* re-lock GPIO */
24499517SBill.Taylor@Sun.COM 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_LOCK, 0);
24509517SBill.Taylor@Sun.COM 
24519517SBill.Taylor@Sun.COM 	/* Set CPUMODE to enable hermon to access the flash device */
24529517SBill.Taylor@Sun.COM 	/* CMJ This code came from arbel.  Hermon doesn't seem to need it. */
24539517SBill.Taylor@Sun.COM 	/*
24549517SBill.Taylor@Sun.COM 	 *	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_CPUMODE,
24559517SBill.Taylor@Sun.COM 	 *	    1 << HERMON_HW_FLASH_CPU_SHIFT);
24569517SBill.Taylor@Sun.COM 	 */
24579517SBill.Taylor@Sun.COM 
24589517SBill.Taylor@Sun.COM 	/* the FMA retry loop ends. */
24599517SBill.Taylor@Sun.COM 	hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status, fm_test);
24609517SBill.Taylor@Sun.COM 	return (0);
24619517SBill.Taylor@Sun.COM 
24629517SBill.Taylor@Sun.COM pio_error:
24639517SBill.Taylor@Sun.COM 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
24649517SBill.Taylor@Sun.COM 	return (EIO);
24659517SBill.Taylor@Sun.COM }
24669517SBill.Taylor@Sun.COM 
24679517SBill.Taylor@Sun.COM /*
24689517SBill.Taylor@Sun.COM  * hermon_flash_cfi_init
24699517SBill.Taylor@Sun.COM  *   Implements access to the CFI (Common Flash Interface) data
24709517SBill.Taylor@Sun.COM  */
24719517SBill.Taylor@Sun.COM static int
hermon_flash_cfi_init(hermon_state_t * state,uint32_t * cfi_info,int * intel_xcmd)24729517SBill.Taylor@Sun.COM hermon_flash_cfi_init(hermon_state_t *state, uint32_t *cfi_info,
24739517SBill.Taylor@Sun.COM     int *intel_xcmd)
24749517SBill.Taylor@Sun.COM {
24759517SBill.Taylor@Sun.COM 	uint32_t	data;
24769517SBill.Taylor@Sun.COM 	uint32_t	sector_sz_bytes;
24779517SBill.Taylor@Sun.COM 	uint32_t	bit_count;
24789517SBill.Taylor@Sun.COM 	uint8_t		cfi_ch_info[HERMON_CFI_INFO_SIZE];
24799517SBill.Taylor@Sun.COM 	uint32_t	cfi_dw_info[HERMON_CFI_INFO_QSIZE];
24809517SBill.Taylor@Sun.COM 	int		i;
24819517SBill.Taylor@Sun.COM 	int		status;
24829517SBill.Taylor@Sun.COM 
24839517SBill.Taylor@Sun.COM 	/* Right now, all hermon cards use SPI. */
2484*12688SWilliam.Taylor@Oracle.COM 	if (hermon_device_mode(state)) {
24859517SBill.Taylor@Sun.COM 		/*
24869517SBill.Taylor@Sun.COM 		 * Don't use CFI for SPI part. Just fill in what we need
24879517SBill.Taylor@Sun.COM 		 * and return.
24889517SBill.Taylor@Sun.COM 		 */
24899517SBill.Taylor@Sun.COM 		state->hs_fw_cmdset = HERMON_FLASH_SPI_CMDSET;
24909517SBill.Taylor@Sun.COM 		state->hs_fw_log_sector_sz = HERMON_FLASH_SPI_LOG_SECTOR_SIZE;
24919517SBill.Taylor@Sun.COM 		state->hs_fw_device_sz = HERMON_FLASH_SPI_DEVICE_SIZE;
24929517SBill.Taylor@Sun.COM 
24939517SBill.Taylor@Sun.COM 		/*
24949517SBill.Taylor@Sun.COM 		 * set this to inform caller of cmdset type.
24959517SBill.Taylor@Sun.COM 		 */
24969517SBill.Taylor@Sun.COM 		cfi_ch_info[0x13] = HERMON_FLASH_SPI_CMDSET;
24979517SBill.Taylor@Sun.COM 		hermon_flash_cfi_dword(&cfi_info[4], cfi_ch_info, 0x10);
24989517SBill.Taylor@Sun.COM 		return (0);
24999517SBill.Taylor@Sun.COM 	}
25009517SBill.Taylor@Sun.COM 
25019517SBill.Taylor@Sun.COM 	/*
25029517SBill.Taylor@Sun.COM 	 * Determine if the user command supports the Intel Extended
25039517SBill.Taylor@Sun.COM 	 * Command Set. The query string is contained in the fourth
25049517SBill.Taylor@Sun.COM 	 * quad word.
25059517SBill.Taylor@Sun.COM 	 */
25069517SBill.Taylor@Sun.COM 	hermon_flash_cfi_byte(cfi_ch_info, cfi_info[0x04], 0x10);
25079517SBill.Taylor@Sun.COM 	if (cfi_ch_info[0x10] == 'M' &&
25089517SBill.Taylor@Sun.COM 	    cfi_ch_info[0x11] == 'X' &&
25099517SBill.Taylor@Sun.COM 	    cfi_ch_info[0x12] == '2') {
25109517SBill.Taylor@Sun.COM 		*intel_xcmd = 1; /* support is there */
25119517SBill.Taylor@Sun.COM 		if (hermon_verbose) {
25129517SBill.Taylor@Sun.COM 			IBTF_DPRINTF_L2("hermon",
25139517SBill.Taylor@Sun.COM 			    "Support for Intel X is present\n");
25149517SBill.Taylor@Sun.COM 		}
25159517SBill.Taylor@Sun.COM 	}
25169517SBill.Taylor@Sun.COM 
25179517SBill.Taylor@Sun.COM 	/* CFI QUERY */
25189517SBill.Taylor@Sun.COM 	hermon_flash_write(state, 0x55, HERMON_FLASH_CFI_INIT, &status);
25199517SBill.Taylor@Sun.COM 	if (status != 0) {
25209517SBill.Taylor@Sun.COM 		return (status);
25219517SBill.Taylor@Sun.COM 	}
25229517SBill.Taylor@Sun.COM 
25239517SBill.Taylor@Sun.COM 	/* temporarily set the cmdset in order to do the initial read */
25249517SBill.Taylor@Sun.COM 	state->hs_fw_cmdset = HERMON_FLASH_INTEL_CMDSET;
25259517SBill.Taylor@Sun.COM 
25269517SBill.Taylor@Sun.COM 	/* Read in CFI data */
25279517SBill.Taylor@Sun.COM 	for (i = 0; i < HERMON_CFI_INFO_SIZE; i += 4) {
25289517SBill.Taylor@Sun.COM 		data = hermon_flash_read(state, i, &status);
25299517SBill.Taylor@Sun.COM 		if (status != 0) {
25309517SBill.Taylor@Sun.COM 			return (status);
25319517SBill.Taylor@Sun.COM 		}
25329517SBill.Taylor@Sun.COM 		cfi_dw_info[i >> 2] = data;
25339517SBill.Taylor@Sun.COM 		hermon_flash_cfi_byte(cfi_ch_info, data, i);
25349517SBill.Taylor@Sun.COM 	}
25359517SBill.Taylor@Sun.COM 
25369517SBill.Taylor@Sun.COM 	/* Determine chip set */
25379517SBill.Taylor@Sun.COM 	state->hs_fw_cmdset = HERMON_FLASH_UNKNOWN_CMDSET;
25389517SBill.Taylor@Sun.COM 	if (cfi_ch_info[0x20] == 'Q' &&
25399517SBill.Taylor@Sun.COM 	    cfi_ch_info[0x22] == 'R' &&
25409517SBill.Taylor@Sun.COM 	    cfi_ch_info[0x24] == 'Y') {
25419517SBill.Taylor@Sun.COM 		/*
25429517SBill.Taylor@Sun.COM 		 * Mode: x16 working in x8 mode (Intel).
25439517SBill.Taylor@Sun.COM 		 * Pack data - skip spacing bytes.
25449517SBill.Taylor@Sun.COM 		 */
25459517SBill.Taylor@Sun.COM 		if (hermon_verbose) {
25469517SBill.Taylor@Sun.COM 			IBTF_DPRINTF_L2("hermon",
25479517SBill.Taylor@Sun.COM 			    "x16 working in x8 mode (Intel)\n");
25489517SBill.Taylor@Sun.COM 		}
25499517SBill.Taylor@Sun.COM 		for (i = 0; i < HERMON_CFI_INFO_SIZE; i += 2) {
25509517SBill.Taylor@Sun.COM 			cfi_ch_info[i/2] = cfi_ch_info[i];
25519517SBill.Taylor@Sun.COM 		}
25529517SBill.Taylor@Sun.COM 	}
25539517SBill.Taylor@Sun.COM 	state->hs_fw_cmdset = cfi_ch_info[0x13];
25549517SBill.Taylor@Sun.COM 
25559517SBill.Taylor@Sun.COM 	if (state->hs_fw_cmdset != HERMON_FLASH_INTEL_CMDSET &&
25569517SBill.Taylor@Sun.COM 	    state->hs_fw_cmdset != HERMON_FLASH_AMD_CMDSET) {
25579517SBill.Taylor@Sun.COM 		cmn_err(CE_WARN,
25589517SBill.Taylor@Sun.COM 		    "hermon_flash_cfi_init: UNKNOWN chip cmd set 0x%04x\n",
25599517SBill.Taylor@Sun.COM 		    state->hs_fw_cmdset);
25609517SBill.Taylor@Sun.COM 		state->hs_fw_cmdset = HERMON_FLASH_UNKNOWN_CMDSET;
25619517SBill.Taylor@Sun.COM 		return (0);
25629517SBill.Taylor@Sun.COM 	}
25639517SBill.Taylor@Sun.COM 
25649517SBill.Taylor@Sun.COM 	/* Determine total bytes in one sector size */
25659517SBill.Taylor@Sun.COM 	sector_sz_bytes = ((cfi_ch_info[0x30] << 8) | cfi_ch_info[0x2F]) << 8;
25669517SBill.Taylor@Sun.COM 
25679517SBill.Taylor@Sun.COM 	/* Calculate equivalent of log2 (n) */
25689517SBill.Taylor@Sun.COM 	for (bit_count = 0; sector_sz_bytes > 1; bit_count++) {
25699517SBill.Taylor@Sun.COM 		sector_sz_bytes >>= 1;
25709517SBill.Taylor@Sun.COM 	}
25719517SBill.Taylor@Sun.COM 
25729517SBill.Taylor@Sun.COM 	/* Set sector size */
25739517SBill.Taylor@Sun.COM 	state->hs_fw_log_sector_sz = bit_count;
25749517SBill.Taylor@Sun.COM 
25759517SBill.Taylor@Sun.COM 	/* Set flash size */
25769517SBill.Taylor@Sun.COM 	state->hs_fw_device_sz = 0x1 << cfi_ch_info[0x27];
25779517SBill.Taylor@Sun.COM 
25789517SBill.Taylor@Sun.COM 	/* Reset to turn off CFI mode */
25799517SBill.Taylor@Sun.COM 	if ((status = hermon_flash_reset(state)) != 0)
25809517SBill.Taylor@Sun.COM 		goto out;
25819517SBill.Taylor@Sun.COM 
25829517SBill.Taylor@Sun.COM 	/* Pass CFI data back to user command. */
25839517SBill.Taylor@Sun.COM 	for (i = 0; i < HERMON_FLASH_CFI_SIZE_QUADLET; i++) {
25849517SBill.Taylor@Sun.COM 		hermon_flash_cfi_dword(&cfi_info[i], cfi_ch_info, i << 2);
25859517SBill.Taylor@Sun.COM 	}
25869517SBill.Taylor@Sun.COM 
25879517SBill.Taylor@Sun.COM 	if (*intel_xcmd == 1) {
25889517SBill.Taylor@Sun.COM 		/*
25899517SBill.Taylor@Sun.COM 		 * Inform the user cmd that this driver does support the
25909517SBill.Taylor@Sun.COM 		 * Intel Extended Command Set.
25919517SBill.Taylor@Sun.COM 		 */
25929517SBill.Taylor@Sun.COM 		cfi_ch_info[0x10] = 'M';
25939517SBill.Taylor@Sun.COM 		cfi_ch_info[0x11] = 'X';
25949517SBill.Taylor@Sun.COM 		cfi_ch_info[0x12] = '2';
25959517SBill.Taylor@Sun.COM 	} else {
25969517SBill.Taylor@Sun.COM 		cfi_ch_info[0x10] = 'Q';
25979517SBill.Taylor@Sun.COM 		cfi_ch_info[0x11] = 'R';
25989517SBill.Taylor@Sun.COM 		cfi_ch_info[0x12] = 'Y';
25999517SBill.Taylor@Sun.COM 	}
26009517SBill.Taylor@Sun.COM 	cfi_ch_info[0x13] = state->hs_fw_cmdset;
26019517SBill.Taylor@Sun.COM 	hermon_flash_cfi_dword(&cfi_info[0x4], cfi_ch_info, 0x10);
26029517SBill.Taylor@Sun.COM out:
26039517SBill.Taylor@Sun.COM 	return (status);
26049517SBill.Taylor@Sun.COM }
26059517SBill.Taylor@Sun.COM 
26069517SBill.Taylor@Sun.COM /*
26079517SBill.Taylor@Sun.COM  * hermon_flash_fini()
26089517SBill.Taylor@Sun.COM  */
26099517SBill.Taylor@Sun.COM static int
hermon_flash_fini(hermon_state_t * state)26109517SBill.Taylor@Sun.COM hermon_flash_fini(hermon_state_t *state)
26119517SBill.Taylor@Sun.COM {
26129517SBill.Taylor@Sun.COM 	int status;
26139517SBill.Taylor@Sun.COM 	ddi_acc_handle_t hdl;
26149517SBill.Taylor@Sun.COM 
26159517SBill.Taylor@Sun.COM 	/* initialize the FMA retry loop */
26169517SBill.Taylor@Sun.COM 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
26179517SBill.Taylor@Sun.COM 
26189517SBill.Taylor@Sun.COM 	/* Set handle */
26199517SBill.Taylor@Sun.COM 	hdl = hermon_get_pcihdl(state);
26209517SBill.Taylor@Sun.COM 
26219517SBill.Taylor@Sun.COM 	if ((status = hermon_flash_bank(state, 0)) != 0)
26229517SBill.Taylor@Sun.COM 		return (status);
26239517SBill.Taylor@Sun.COM 
26249517SBill.Taylor@Sun.COM 	/* the FMA retry loop starts. */
26259517SBill.Taylor@Sun.COM 	hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status,
26269517SBill.Taylor@Sun.COM 	    fm_test);
26279517SBill.Taylor@Sun.COM 
26289517SBill.Taylor@Sun.COM 	/*
26299517SBill.Taylor@Sun.COM 	 * Restore original GPIO Values
26309517SBill.Taylor@Sun.COM 	 */
26319517SBill.Taylor@Sun.COM 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_DATA,
26329517SBill.Taylor@Sun.COM 	    state->hs_fw_gpio[0]);
26339517SBill.Taylor@Sun.COM 
26349517SBill.Taylor@Sun.COM 	/* unlock GPIOs */
26359517SBill.Taylor@Sun.COM 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_LOCK,
26369517SBill.Taylor@Sun.COM 	    HERMON_HW_FLASH_GPIO_UNLOCK_VAL);
26379517SBill.Taylor@Sun.COM 
26389517SBill.Taylor@Sun.COM 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_MOD0,
26399517SBill.Taylor@Sun.COM 	    state->hs_fw_gpio[1]);
26409517SBill.Taylor@Sun.COM 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_MOD1,
26419517SBill.Taylor@Sun.COM 	    state->hs_fw_gpio[2]);
26429517SBill.Taylor@Sun.COM 
26439517SBill.Taylor@Sun.COM 	/* re-lock GPIOs */
26449517SBill.Taylor@Sun.COM 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_LOCK, 0);
26459517SBill.Taylor@Sun.COM 
26469517SBill.Taylor@Sun.COM 	/* Give up gpio semaphore */
26479517SBill.Taylor@Sun.COM 	hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_SEMA, 0);
26489517SBill.Taylor@Sun.COM 
26499517SBill.Taylor@Sun.COM 	/* the FMA retry loop ends. */
26509517SBill.Taylor@Sun.COM 	hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status, fm_test);
26519517SBill.Taylor@Sun.COM 	return (0);
26529517SBill.Taylor@Sun.COM 
26539517SBill.Taylor@Sun.COM pio_error:
26549517SBill.Taylor@Sun.COM 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
26559517SBill.Taylor@Sun.COM 	return (EIO);
26569517SBill.Taylor@Sun.COM }
26579517SBill.Taylor@Sun.COM 
26589517SBill.Taylor@Sun.COM /*
26599517SBill.Taylor@Sun.COM  * hermon_flash_read_cfg
26609517SBill.Taylor@Sun.COM  */
26619517SBill.Taylor@Sun.COM static uint32_t
hermon_flash_read_cfg(hermon_state_t * state,ddi_acc_handle_t pci_config_hdl,uint32_t addr)26629517SBill.Taylor@Sun.COM hermon_flash_read_cfg(hermon_state_t *state, ddi_acc_handle_t pci_config_hdl,
26639517SBill.Taylor@Sun.COM     uint32_t addr)
26649517SBill.Taylor@Sun.COM {
26659517SBill.Taylor@Sun.COM 	uint32_t	read;
26669517SBill.Taylor@Sun.COM 
26679517SBill.Taylor@Sun.COM 	if (do_bar0) {
26689517SBill.Taylor@Sun.COM 		read = ddi_get32(hermon_get_cmdhdl(state), (uint32_t *)(void *)
26699517SBill.Taylor@Sun.COM 		    (state->hs_reg_cmd_baseaddr + addr));
26709517SBill.Taylor@Sun.COM 	} else {
26719517SBill.Taylor@Sun.COM 		/*
26729517SBill.Taylor@Sun.COM 		 * Perform flash read operation:
26739517SBill.Taylor@Sun.COM 		 *   1) Place addr to read from on the HERMON_HW_FLASH_CFG_ADDR
26749517SBill.Taylor@Sun.COM 		 *	register
26759517SBill.Taylor@Sun.COM 		 *   2) Read data at that addr from the HERMON_HW_FLASH_CFG_DATA
26769517SBill.Taylor@Sun.COM 		 *	 register
26779517SBill.Taylor@Sun.COM 		 */
26789517SBill.Taylor@Sun.COM 		pci_config_put32(pci_config_hdl, HERMON_HW_FLASH_CFG_ADDR,
26799517SBill.Taylor@Sun.COM 		    addr);
26809517SBill.Taylor@Sun.COM 		read = pci_config_get32(pci_config_hdl,
26819517SBill.Taylor@Sun.COM 		    HERMON_HW_FLASH_CFG_DATA);
26829517SBill.Taylor@Sun.COM 	}
26839517SBill.Taylor@Sun.COM 
26849517SBill.Taylor@Sun.COM 	return (read);
26859517SBill.Taylor@Sun.COM }
26869517SBill.Taylor@Sun.COM 
26879517SBill.Taylor@Sun.COM #ifdef DO_WRCONF
26889517SBill.Taylor@Sun.COM static void
hermon_flash_write_cfg(hermon_state_t * state,ddi_acc_handle_t pci_config_hdl,uint32_t addr,uint32_t data)26899517SBill.Taylor@Sun.COM hermon_flash_write_cfg(hermon_state_t *state,
26909517SBill.Taylor@Sun.COM     ddi_acc_handle_t pci_config_hdl, uint32_t addr, uint32_t data)
26919517SBill.Taylor@Sun.COM {
26929517SBill.Taylor@Sun.COM 	hermon_flash_write_cfg_helper(state, pci_config_hdl, addr, data);
26939517SBill.Taylor@Sun.COM 	hermon_flash_write_confirm(state, pci_config_hdl);
26949517SBill.Taylor@Sun.COM }
26959517SBill.Taylor@Sun.COM 
26969517SBill.Taylor@Sun.COM static void
hermon_flash_write_confirm(hermon_state_t * state,ddi_acc_handle_t pci_config_hdl)26979517SBill.Taylor@Sun.COM hermon_flash_write_confirm(hermon_state_t *state,
26989517SBill.Taylor@Sun.COM     ddi_acc_handle_t pci_config_hdl)
26999517SBill.Taylor@Sun.COM {
27009517SBill.Taylor@Sun.COM 	uint32_t	sem_value = 1;
27019517SBill.Taylor@Sun.COM 
27029517SBill.Taylor@Sun.COM 	hermon_flash_write_cfg_helper(state, pci_config_hdl,
27039517SBill.Taylor@Sun.COM 	    HERMON_HW_FLASH_WRCONF_SEMA, 0);
27049517SBill.Taylor@Sun.COM 	while (sem_value) {
27059517SBill.Taylor@Sun.COM 		sem_value = hermon_flash_read_cfg(state, pci_config_hdl,
27069517SBill.Taylor@Sun.COM 		    HERMON_HW_FLASH_WRCONF_SEMA);
27079517SBill.Taylor@Sun.COM 	}
27089517SBill.Taylor@Sun.COM }
27099517SBill.Taylor@Sun.COM #endif
27109517SBill.Taylor@Sun.COM 
27119517SBill.Taylor@Sun.COM /*
27129517SBill.Taylor@Sun.COM  * hermon_flash_write_cfg
27139517SBill.Taylor@Sun.COM  */
27149517SBill.Taylor@Sun.COM static void
27159517SBill.Taylor@Sun.COM #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)27169517SBill.Taylor@Sun.COM hermon_flash_write_cfg_helper(hermon_state_t *state,
27179517SBill.Taylor@Sun.COM     ddi_acc_handle_t pci_config_hdl, uint32_t addr, uint32_t data)
27189517SBill.Taylor@Sun.COM #else
27199517SBill.Taylor@Sun.COM hermon_flash_write_cfg(hermon_state_t *state,
27209517SBill.Taylor@Sun.COM     ddi_acc_handle_t pci_config_hdl, uint32_t addr, uint32_t data)
27219517SBill.Taylor@Sun.COM #endif
27229517SBill.Taylor@Sun.COM {
27239517SBill.Taylor@Sun.COM 	if (do_bar0) {
27249517SBill.Taylor@Sun.COM 		ddi_put32(hermon_get_cmdhdl(state), (uint32_t *)(void *)
27259517SBill.Taylor@Sun.COM 		    (state->hs_reg_cmd_baseaddr + addr), data);
27269517SBill.Taylor@Sun.COM 
27279517SBill.Taylor@Sun.COM 	} else {
27289517SBill.Taylor@Sun.COM 
27299517SBill.Taylor@Sun.COM 		/*
27309517SBill.Taylor@Sun.COM 		 * Perform flash write operation:
27319517SBill.Taylor@Sun.COM 		 *   1) Place addr to write to on the HERMON_HW_FLASH_CFG_ADDR
27329517SBill.Taylor@Sun.COM 		 *	register
27339517SBill.Taylor@Sun.COM 		 *   2) Place data to write on to the HERMON_HW_FLASH_CFG_DATA
27349517SBill.Taylor@Sun.COM 		 *	register
27359517SBill.Taylor@Sun.COM 		 */
27369517SBill.Taylor@Sun.COM 		pci_config_put32(pci_config_hdl, HERMON_HW_FLASH_CFG_ADDR,
27379517SBill.Taylor@Sun.COM 		    addr);
27389517SBill.Taylor@Sun.COM 		pci_config_put32(pci_config_hdl, HERMON_HW_FLASH_CFG_DATA,
27399517SBill.Taylor@Sun.COM 		    data);
27409517SBill.Taylor@Sun.COM 	}
27419517SBill.Taylor@Sun.COM }
27429517SBill.Taylor@Sun.COM 
27439517SBill.Taylor@Sun.COM /*
27449517SBill.Taylor@Sun.COM  * Support routines to convert Common Flash Interface (CFI) data
27459517SBill.Taylor@Sun.COM  * from a 32  bit word to a char array, and from a char array to
27469517SBill.Taylor@Sun.COM  * a 32 bit word.
27479517SBill.Taylor@Sun.COM  */
27489517SBill.Taylor@Sun.COM static void
hermon_flash_cfi_byte(uint8_t * ch,uint32_t dword,int i)27499517SBill.Taylor@Sun.COM hermon_flash_cfi_byte(uint8_t *ch, uint32_t dword, int i)
27509517SBill.Taylor@Sun.COM {
27519517SBill.Taylor@Sun.COM 	ch[i] = (uint8_t)((dword & 0xFF000000) >> 24);
27529517SBill.Taylor@Sun.COM 	ch[i+1] = (uint8_t)((dword & 0x00FF0000) >> 16);
27539517SBill.Taylor@Sun.COM 	ch[i+2] = (uint8_t)((dword & 0x0000FF00) >> 8);
27549517SBill.Taylor@Sun.COM 	ch[i+3] = (uint8_t)((dword & 0x000000FF));
27559517SBill.Taylor@Sun.COM }
27569517SBill.Taylor@Sun.COM 
27579517SBill.Taylor@Sun.COM static void
hermon_flash_cfi_dword(uint32_t * dword,uint8_t * ch,int i)27589517SBill.Taylor@Sun.COM hermon_flash_cfi_dword(uint32_t *dword, uint8_t *ch, int i)
27599517SBill.Taylor@Sun.COM {
27609517SBill.Taylor@Sun.COM 	*dword = (uint32_t)
27619517SBill.Taylor@Sun.COM 	    ((uint32_t)ch[i] << 24 |
27629517SBill.Taylor@Sun.COM 	    (uint32_t)ch[i+1] << 16 |
27639517SBill.Taylor@Sun.COM 	    (uint32_t)ch[i+2] << 8 |
27649517SBill.Taylor@Sun.COM 	    (uint32_t)ch[i+3]);
27659517SBill.Taylor@Sun.COM }
27669517SBill.Taylor@Sun.COM 
27679517SBill.Taylor@Sun.COM /*
27689517SBill.Taylor@Sun.COM  * hermon_loopback_free_qps
27699517SBill.Taylor@Sun.COM  */
27709517SBill.Taylor@Sun.COM static void
hermon_loopback_free_qps(hermon_loopback_state_t * lstate)27719517SBill.Taylor@Sun.COM hermon_loopback_free_qps(hermon_loopback_state_t *lstate)
27729517SBill.Taylor@Sun.COM {
27739517SBill.Taylor@Sun.COM 	int i;
27749517SBill.Taylor@Sun.COM 
27759517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lstate))
27769517SBill.Taylor@Sun.COM 
27779517SBill.Taylor@Sun.COM 	if (lstate->hls_tx.hlc_qp_hdl != NULL) {
27789517SBill.Taylor@Sun.COM 		(void) hermon_qp_free(lstate->hls_state,
27799517SBill.Taylor@Sun.COM 		    &lstate->hls_tx.hlc_qp_hdl, IBC_FREE_QP_AND_QPN, NULL,
27809517SBill.Taylor@Sun.COM 		    HERMON_NOSLEEP);
27819517SBill.Taylor@Sun.COM 	}
27829517SBill.Taylor@Sun.COM 	if (lstate->hls_rx.hlc_qp_hdl != NULL) {
27839517SBill.Taylor@Sun.COM 		(void) hermon_qp_free(lstate->hls_state,
27849517SBill.Taylor@Sun.COM 		    &lstate->hls_rx.hlc_qp_hdl, IBC_FREE_QP_AND_QPN, NULL,
27859517SBill.Taylor@Sun.COM 		    HERMON_NOSLEEP);
27869517SBill.Taylor@Sun.COM 	}
27879517SBill.Taylor@Sun.COM 	lstate->hls_tx.hlc_qp_hdl = NULL;
27889517SBill.Taylor@Sun.COM 	lstate->hls_rx.hlc_qp_hdl = NULL;
27899517SBill.Taylor@Sun.COM 	for (i = 0; i < 2; i++) {
27909517SBill.Taylor@Sun.COM 		if (lstate->hls_tx.hlc_cqhdl[i] != NULL) {
27919517SBill.Taylor@Sun.COM 			(void) hermon_cq_free(lstate->hls_state,
27929517SBill.Taylor@Sun.COM 			    &lstate->hls_tx.hlc_cqhdl[i], HERMON_NOSLEEP);
27939517SBill.Taylor@Sun.COM 		}
27949517SBill.Taylor@Sun.COM 		if (lstate->hls_rx.hlc_cqhdl[i] != NULL) {
27959517SBill.Taylor@Sun.COM 			(void) hermon_cq_free(lstate->hls_state,
27969517SBill.Taylor@Sun.COM 			    &lstate->hls_rx.hlc_cqhdl[i], HERMON_NOSLEEP);
27979517SBill.Taylor@Sun.COM 		}
27989517SBill.Taylor@Sun.COM 		lstate->hls_tx.hlc_cqhdl[i] = NULL;
27999517SBill.Taylor@Sun.COM 		lstate->hls_rx.hlc_cqhdl[i] = NULL;
28009517SBill.Taylor@Sun.COM 	}
28019517SBill.Taylor@Sun.COM }
28029517SBill.Taylor@Sun.COM 
28039517SBill.Taylor@Sun.COM /*
28049517SBill.Taylor@Sun.COM  * hermon_loopback_free_state
28059517SBill.Taylor@Sun.COM  */
28069517SBill.Taylor@Sun.COM static void
hermon_loopback_free_state(hermon_loopback_state_t * lstate)28079517SBill.Taylor@Sun.COM hermon_loopback_free_state(hermon_loopback_state_t *lstate)
28089517SBill.Taylor@Sun.COM {
28099517SBill.Taylor@Sun.COM 	hermon_loopback_free_qps(lstate);
28109517SBill.Taylor@Sun.COM 	if (lstate->hls_tx.hlc_mrhdl != NULL) {
28119517SBill.Taylor@Sun.COM 		(void) hermon_mr_deregister(lstate->hls_state,
28129517SBill.Taylor@Sun.COM 		    &lstate->hls_tx.hlc_mrhdl, HERMON_MR_DEREG_ALL,
28139517SBill.Taylor@Sun.COM 		    HERMON_NOSLEEP);
28149517SBill.Taylor@Sun.COM 	}
28159517SBill.Taylor@Sun.COM 	if (lstate->hls_rx.hlc_mrhdl !=  NULL) {
28169517SBill.Taylor@Sun.COM 		(void) hermon_mr_deregister(lstate->hls_state,
28179517SBill.Taylor@Sun.COM 		    &lstate->hls_rx.hlc_mrhdl, HERMON_MR_DEREG_ALL,
28189517SBill.Taylor@Sun.COM 		    HERMON_NOSLEEP);
28199517SBill.Taylor@Sun.COM 	}
28209517SBill.Taylor@Sun.COM 	if (lstate->hls_pd_hdl != NULL) {
28219517SBill.Taylor@Sun.COM 		(void) hermon_pd_free(lstate->hls_state, &lstate->hls_pd_hdl);
28229517SBill.Taylor@Sun.COM 	}
28239517SBill.Taylor@Sun.COM 	if (lstate->hls_tx.hlc_buf != NULL) {
28249517SBill.Taylor@Sun.COM 		kmem_free(lstate->hls_tx.hlc_buf, lstate->hls_tx.hlc_buf_sz);
28259517SBill.Taylor@Sun.COM 	}
28269517SBill.Taylor@Sun.COM 	if (lstate->hls_rx.hlc_buf != NULL) {
28279517SBill.Taylor@Sun.COM 		kmem_free(lstate->hls_rx.hlc_buf, lstate->hls_rx.hlc_buf_sz);
28289517SBill.Taylor@Sun.COM 	}
28299517SBill.Taylor@Sun.COM 	bzero(lstate, sizeof (hermon_loopback_state_t));
28309517SBill.Taylor@Sun.COM }
28319517SBill.Taylor@Sun.COM 
28329517SBill.Taylor@Sun.COM /*
28339517SBill.Taylor@Sun.COM  * hermon_loopback_init
28349517SBill.Taylor@Sun.COM  */
28359517SBill.Taylor@Sun.COM static int
hermon_loopback_init(hermon_state_t * state,hermon_loopback_state_t * lstate)28369517SBill.Taylor@Sun.COM hermon_loopback_init(hermon_state_t *state, hermon_loopback_state_t *lstate)
28379517SBill.Taylor@Sun.COM {
28389517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lstate))
28399517SBill.Taylor@Sun.COM 
28409517SBill.Taylor@Sun.COM 	lstate->hls_hca_hdl = (ibc_hca_hdl_t)state;
28419517SBill.Taylor@Sun.COM 	lstate->hls_status  = hermon_pd_alloc(lstate->hls_state,
28429517SBill.Taylor@Sun.COM 	    &lstate->hls_pd_hdl, HERMON_NOSLEEP);
28439517SBill.Taylor@Sun.COM 	if (lstate->hls_status != IBT_SUCCESS) {
28449517SBill.Taylor@Sun.COM 		lstate->hls_err = HERMON_LOOPBACK_PROT_DOMAIN_ALLOC_FAIL;
28459517SBill.Taylor@Sun.COM 		return (EFAULT);
28469517SBill.Taylor@Sun.COM 	}
28479517SBill.Taylor@Sun.COM 
28489517SBill.Taylor@Sun.COM 	return (0);
28499517SBill.Taylor@Sun.COM }
28509517SBill.Taylor@Sun.COM 
28519517SBill.Taylor@Sun.COM /*
28529517SBill.Taylor@Sun.COM  * hermon_loopback_init_qp_info
28539517SBill.Taylor@Sun.COM  */
28549517SBill.Taylor@Sun.COM static void
hermon_loopback_init_qp_info(hermon_loopback_state_t * lstate,hermon_loopback_comm_t * comm)28559517SBill.Taylor@Sun.COM hermon_loopback_init_qp_info(hermon_loopback_state_t *lstate,
28569517SBill.Taylor@Sun.COM     hermon_loopback_comm_t *comm)
28579517SBill.Taylor@Sun.COM {
28589517SBill.Taylor@Sun.COM 	bzero(&comm->hlc_cq_attr, sizeof (ibt_cq_attr_t));
28599517SBill.Taylor@Sun.COM 	bzero(&comm->hlc_qp_attr, sizeof (ibt_qp_alloc_attr_t));
28609517SBill.Taylor@Sun.COM 	bzero(&comm->hlc_qp_info, sizeof (ibt_qp_info_t));
28619517SBill.Taylor@Sun.COM 
28629517SBill.Taylor@Sun.COM 	comm->hlc_wrid = 1;
28639517SBill.Taylor@Sun.COM 	comm->hlc_cq_attr.cq_size = 128;
28649517SBill.Taylor@Sun.COM 	comm->hlc_qp_attr.qp_sizes.cs_sq_sgl = 3;
28659517SBill.Taylor@Sun.COM 	comm->hlc_qp_attr.qp_sizes.cs_rq_sgl = 3;
28669517SBill.Taylor@Sun.COM 	comm->hlc_qp_attr.qp_sizes.cs_sq = 16;
28679517SBill.Taylor@Sun.COM 	comm->hlc_qp_attr.qp_sizes.cs_rq = 16;
28689517SBill.Taylor@Sun.COM 	comm->hlc_qp_attr.qp_flags = IBT_WR_SIGNALED;
28699517SBill.Taylor@Sun.COM 
28709517SBill.Taylor@Sun.COM 	comm->hlc_qp_info.qp_state = IBT_STATE_RESET;
28719517SBill.Taylor@Sun.COM 	comm->hlc_qp_info.qp_trans = IBT_RC_SRV;
28729517SBill.Taylor@Sun.COM 	comm->hlc_qp_info.qp_flags = IBT_CEP_RDMA_RD | IBT_CEP_RDMA_WR;
28739517SBill.Taylor@Sun.COM 	comm->hlc_qp_info.qp_transport.rc.rc_path.cep_hca_port_num =
28749517SBill.Taylor@Sun.COM 	    lstate->hls_port;
28759517SBill.Taylor@Sun.COM 	comm->hlc_qp_info.qp_transport.rc.rc_path.cep_pkey_ix =
28769517SBill.Taylor@Sun.COM 	    lstate->hls_pkey_ix;
28779517SBill.Taylor@Sun.COM 	comm->hlc_qp_info.qp_transport.rc.rc_path.cep_timeout =
28789517SBill.Taylor@Sun.COM 	    lstate->hls_timeout;
28799517SBill.Taylor@Sun.COM 	comm->hlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_srvl = 0;
28809517SBill.Taylor@Sun.COM 	comm->hlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_srate =
28819517SBill.Taylor@Sun.COM 	    IBT_SRATE_4X;
28829517SBill.Taylor@Sun.COM 	comm->hlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_send_grh = 0;
28839517SBill.Taylor@Sun.COM 	comm->hlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_dlid =
28849517SBill.Taylor@Sun.COM 	    lstate->hls_lid;
28859517SBill.Taylor@Sun.COM 	comm->hlc_qp_info.qp_transport.rc.rc_retry_cnt = lstate->hls_retry;
28869517SBill.Taylor@Sun.COM 	comm->hlc_qp_info.qp_transport.rc.rc_sq_psn = 0;
28879517SBill.Taylor@Sun.COM 	comm->hlc_qp_info.qp_transport.rc.rc_rq_psn = 0;
28889517SBill.Taylor@Sun.COM 	comm->hlc_qp_info.qp_transport.rc.rc_rdma_ra_in	 = 4;
28899517SBill.Taylor@Sun.COM 	comm->hlc_qp_info.qp_transport.rc.rc_rdma_ra_out = 4;
28909517SBill.Taylor@Sun.COM 	comm->hlc_qp_info.qp_transport.rc.rc_dst_qpn = 0;
28919517SBill.Taylor@Sun.COM 	comm->hlc_qp_info.qp_transport.rc.rc_min_rnr_nak = IBT_RNR_NAK_655ms;
28929517SBill.Taylor@Sun.COM 	comm->hlc_qp_info.qp_transport.rc.rc_path_mtu = IB_MTU_1K;
28939517SBill.Taylor@Sun.COM }
28949517SBill.Taylor@Sun.COM 
28959517SBill.Taylor@Sun.COM /*
28969517SBill.Taylor@Sun.COM  * hermon_loopback_alloc_mem
28979517SBill.Taylor@Sun.COM  */
28989517SBill.Taylor@Sun.COM static int
hermon_loopback_alloc_mem(hermon_loopback_state_t * lstate,hermon_loopback_comm_t * comm,int sz)28999517SBill.Taylor@Sun.COM hermon_loopback_alloc_mem(hermon_loopback_state_t *lstate,
29009517SBill.Taylor@Sun.COM     hermon_loopback_comm_t *comm, int sz)
29019517SBill.Taylor@Sun.COM {
29029517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm))
29039517SBill.Taylor@Sun.COM 
29049517SBill.Taylor@Sun.COM 	/* Allocate buffer of specified size */
29059517SBill.Taylor@Sun.COM 	comm->hlc_buf_sz = sz;
29069517SBill.Taylor@Sun.COM 	comm->hlc_buf	 = kmem_zalloc(sz, KM_NOSLEEP);
29079517SBill.Taylor@Sun.COM 	if (comm->hlc_buf == NULL) {
29089517SBill.Taylor@Sun.COM 		return (EFAULT);
29099517SBill.Taylor@Sun.COM 	}
29109517SBill.Taylor@Sun.COM 
29119517SBill.Taylor@Sun.COM 	/* Register the buffer as a memory region */
29129517SBill.Taylor@Sun.COM 	comm->hlc_memattr.mr_vaddr = (uint64_t)(uintptr_t)comm->hlc_buf;
29139517SBill.Taylor@Sun.COM 	comm->hlc_memattr.mr_len   = (ib_msglen_t)sz;
29149517SBill.Taylor@Sun.COM 	comm->hlc_memattr.mr_as	   = NULL;
29159517SBill.Taylor@Sun.COM 	comm->hlc_memattr.mr_flags = IBT_MR_NOSLEEP |
29169517SBill.Taylor@Sun.COM 	    IBT_MR_ENABLE_REMOTE_WRITE | IBT_MR_ENABLE_LOCAL_WRITE;
29179517SBill.Taylor@Sun.COM 
29189517SBill.Taylor@Sun.COM 	comm->hlc_status = hermon_mr_register(lstate->hls_state,
29199517SBill.Taylor@Sun.COM 	    lstate->hls_pd_hdl, &comm->hlc_memattr, &comm->hlc_mrhdl,
29209517SBill.Taylor@Sun.COM 	    NULL, HERMON_MPT_DMPT);
29219517SBill.Taylor@Sun.COM 
29229517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm->hlc_mrhdl))
29239517SBill.Taylor@Sun.COM 
29249517SBill.Taylor@Sun.COM 	comm->hlc_mrdesc.md_vaddr  = comm->hlc_mrhdl->mr_bindinfo.bi_addr;
29259517SBill.Taylor@Sun.COM 	comm->hlc_mrdesc.md_lkey   = comm->hlc_mrhdl->mr_lkey;
29269517SBill.Taylor@Sun.COM 	comm->hlc_mrdesc.md_rkey   = comm->hlc_mrhdl->mr_rkey;
29279517SBill.Taylor@Sun.COM 	if (comm->hlc_status != IBT_SUCCESS) {
29289517SBill.Taylor@Sun.COM 		return (EFAULT);
29299517SBill.Taylor@Sun.COM 	}
29309517SBill.Taylor@Sun.COM 	return (0);
29319517SBill.Taylor@Sun.COM }
29329517SBill.Taylor@Sun.COM 
29339517SBill.Taylor@Sun.COM /*
29349517SBill.Taylor@Sun.COM  * hermon_loopback_alloc_qps
29359517SBill.Taylor@Sun.COM  */
29369517SBill.Taylor@Sun.COM static int
hermon_loopback_alloc_qps(hermon_loopback_state_t * lstate,hermon_loopback_comm_t * comm)29379517SBill.Taylor@Sun.COM hermon_loopback_alloc_qps(hermon_loopback_state_t *lstate,
29389517SBill.Taylor@Sun.COM     hermon_loopback_comm_t *comm)
29399517SBill.Taylor@Sun.COM {
29409517SBill.Taylor@Sun.COM 	uint32_t		i, real_size;
29419517SBill.Taylor@Sun.COM 	hermon_qp_info_t		qpinfo;
29429517SBill.Taylor@Sun.COM 
29439517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm))
29449517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lstate))
29459517SBill.Taylor@Sun.COM 
29469517SBill.Taylor@Sun.COM 	/* Allocate send and recv CQs */
29479517SBill.Taylor@Sun.COM 	for (i = 0; i < 2; i++) {
29489517SBill.Taylor@Sun.COM 		bzero(&comm->hlc_cq_attr, sizeof (ibt_cq_attr_t));
29499517SBill.Taylor@Sun.COM 		comm->hlc_cq_attr.cq_size = 128;
29509517SBill.Taylor@Sun.COM 		comm->hlc_status = hermon_cq_alloc(lstate->hls_state,
29519517SBill.Taylor@Sun.COM 		    (ibt_cq_hdl_t)NULL, &comm->hlc_cq_attr, &real_size,
29529517SBill.Taylor@Sun.COM 		    &comm->hlc_cqhdl[i], HERMON_NOSLEEP);
29539517SBill.Taylor@Sun.COM 		if (comm->hlc_status != IBT_SUCCESS) {
29549517SBill.Taylor@Sun.COM 			lstate->hls_err += i;
29559517SBill.Taylor@Sun.COM 			return (EFAULT);
29569517SBill.Taylor@Sun.COM 		}
29579517SBill.Taylor@Sun.COM 	}
29589517SBill.Taylor@Sun.COM 
29599517SBill.Taylor@Sun.COM 	/* Allocate the QP */
29609517SBill.Taylor@Sun.COM 	hermon_loopback_init_qp_info(lstate, comm);
29619517SBill.Taylor@Sun.COM 	comm->hlc_qp_attr.qp_pd_hdl	 = (ibt_pd_hdl_t)lstate->hls_pd_hdl;
29629517SBill.Taylor@Sun.COM 	comm->hlc_qp_attr.qp_scq_hdl	 = (ibt_cq_hdl_t)comm->hlc_cqhdl[0];
29639517SBill.Taylor@Sun.COM 	comm->hlc_qp_attr.qp_rcq_hdl	 = (ibt_cq_hdl_t)comm->hlc_cqhdl[1];
29649517SBill.Taylor@Sun.COM 	comm->hlc_qp_attr.qp_ibc_scq_hdl = (ibt_opaque1_t)comm->hlc_cqhdl[0];
29659517SBill.Taylor@Sun.COM 	comm->hlc_qp_attr.qp_ibc_rcq_hdl = (ibt_opaque1_t)comm->hlc_cqhdl[1];
29669517SBill.Taylor@Sun.COM 	qpinfo.qpi_attrp	= &comm->hlc_qp_attr;
29679517SBill.Taylor@Sun.COM 	qpinfo.qpi_type		= IBT_RC_RQP;
29689517SBill.Taylor@Sun.COM 	qpinfo.qpi_ibt_qphdl	= NULL;
29699517SBill.Taylor@Sun.COM 	qpinfo.qpi_queueszp	= &comm->hlc_chan_sizes;
29709517SBill.Taylor@Sun.COM 	qpinfo.qpi_qpn		= &comm->hlc_qp_num;
29719517SBill.Taylor@Sun.COM 	comm->hlc_status = hermon_qp_alloc(lstate->hls_state, &qpinfo,
29729517SBill.Taylor@Sun.COM 	    HERMON_NOSLEEP);
29739517SBill.Taylor@Sun.COM 	if (comm->hlc_status == DDI_SUCCESS) {
29749517SBill.Taylor@Sun.COM 		comm->hlc_qp_hdl = qpinfo.qpi_qphdl;
29759517SBill.Taylor@Sun.COM 	}
29769517SBill.Taylor@Sun.COM 
29779517SBill.Taylor@Sun.COM 	if (comm->hlc_status != IBT_SUCCESS) {
29789517SBill.Taylor@Sun.COM 		lstate->hls_err += 2;
29799517SBill.Taylor@Sun.COM 		return (EFAULT);
29809517SBill.Taylor@Sun.COM 	}
29819517SBill.Taylor@Sun.COM 	return (0);
29829517SBill.Taylor@Sun.COM }
29839517SBill.Taylor@Sun.COM 
29849517SBill.Taylor@Sun.COM /*
29859517SBill.Taylor@Sun.COM  * hermon_loopback_modify_qp
29869517SBill.Taylor@Sun.COM  */
29879517SBill.Taylor@Sun.COM static int
hermon_loopback_modify_qp(hermon_loopback_state_t * lstate,hermon_loopback_comm_t * comm,uint_t qp_num)29889517SBill.Taylor@Sun.COM hermon_loopback_modify_qp(hermon_loopback_state_t *lstate,
29899517SBill.Taylor@Sun.COM     hermon_loopback_comm_t *comm, uint_t qp_num)
29909517SBill.Taylor@Sun.COM {
29919517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm))
29929517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lstate))
29939517SBill.Taylor@Sun.COM 
29949517SBill.Taylor@Sun.COM 	/* Modify QP to INIT */
29959517SBill.Taylor@Sun.COM 	hermon_loopback_init_qp_info(lstate, comm);
29969517SBill.Taylor@Sun.COM 	comm->hlc_qp_info.qp_state = IBT_STATE_INIT;
29979517SBill.Taylor@Sun.COM 	comm->hlc_status = hermon_qp_modify(lstate->hls_state, comm->hlc_qp_hdl,
29989517SBill.Taylor@Sun.COM 	    IBT_CEP_SET_STATE, &comm->hlc_qp_info, &comm->hlc_queue_sizes);
29999517SBill.Taylor@Sun.COM 	if (comm->hlc_status != IBT_SUCCESS) {
30009517SBill.Taylor@Sun.COM 		return (EFAULT);
30019517SBill.Taylor@Sun.COM 	}
30029517SBill.Taylor@Sun.COM 
30039517SBill.Taylor@Sun.COM 	/*
30049517SBill.Taylor@Sun.COM 	 * Modify QP to RTR (set destination LID and QP number to local
30059517SBill.Taylor@Sun.COM 	 * LID and QP number)
30069517SBill.Taylor@Sun.COM 	 */
30079517SBill.Taylor@Sun.COM 	comm->hlc_qp_info.qp_state = IBT_STATE_RTR;
30089517SBill.Taylor@Sun.COM 	comm->hlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_dlid
30099517SBill.Taylor@Sun.COM 	    = lstate->hls_lid;
30109517SBill.Taylor@Sun.COM 	comm->hlc_qp_info.qp_transport.rc.rc_dst_qpn = qp_num;
30119517SBill.Taylor@Sun.COM 	comm->hlc_status = hermon_qp_modify(lstate->hls_state, comm->hlc_qp_hdl,
30129517SBill.Taylor@Sun.COM 	    IBT_CEP_SET_STATE, &comm->hlc_qp_info, &comm->hlc_queue_sizes);
30139517SBill.Taylor@Sun.COM 	if (comm->hlc_status != IBT_SUCCESS) {
30149517SBill.Taylor@Sun.COM 		lstate->hls_err += 1;
30159517SBill.Taylor@Sun.COM 		return (EFAULT);
30169517SBill.Taylor@Sun.COM 	}
30179517SBill.Taylor@Sun.COM 
30189517SBill.Taylor@Sun.COM 	/* Modify QP to RTS */
30199517SBill.Taylor@Sun.COM 	comm->hlc_qp_info.qp_current_state = IBT_STATE_RTR;
30209517SBill.Taylor@Sun.COM 	comm->hlc_qp_info.qp_state = IBT_STATE_RTS;
30219517SBill.Taylor@Sun.COM 	comm->hlc_status = hermon_qp_modify(lstate->hls_state, comm->hlc_qp_hdl,
30229517SBill.Taylor@Sun.COM 	    IBT_CEP_SET_STATE, &comm->hlc_qp_info, &comm->hlc_queue_sizes);
30239517SBill.Taylor@Sun.COM 	if (comm->hlc_status != IBT_SUCCESS) {
30249517SBill.Taylor@Sun.COM 		lstate->hls_err += 2;
30259517SBill.Taylor@Sun.COM 		return (EFAULT);
30269517SBill.Taylor@Sun.COM 	}
30279517SBill.Taylor@Sun.COM 	return (0);
30289517SBill.Taylor@Sun.COM }
30299517SBill.Taylor@Sun.COM 
30309517SBill.Taylor@Sun.COM /*
30319517SBill.Taylor@Sun.COM  * hermon_loopback_copyout
30329517SBill.Taylor@Sun.COM  */
30339517SBill.Taylor@Sun.COM static int
hermon_loopback_copyout(hermon_loopback_ioctl_t * lb,intptr_t arg,int mode)30349517SBill.Taylor@Sun.COM hermon_loopback_copyout(hermon_loopback_ioctl_t *lb, intptr_t arg, int mode)
30359517SBill.Taylor@Sun.COM {
30369517SBill.Taylor@Sun.COM #ifdef _MULTI_DATAMODEL
30379517SBill.Taylor@Sun.COM 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
30389517SBill.Taylor@Sun.COM 		hermon_loopback_ioctl32_t lb32;
30399517SBill.Taylor@Sun.COM 
30409517SBill.Taylor@Sun.COM 		lb32.alb_revision	= lb->alb_revision;
30419517SBill.Taylor@Sun.COM 		lb32.alb_send_buf	=
30429517SBill.Taylor@Sun.COM 		    (caddr32_t)(uintptr_t)lb->alb_send_buf;
30439517SBill.Taylor@Sun.COM 		lb32.alb_fail_buf	=
30449517SBill.Taylor@Sun.COM 		    (caddr32_t)(uintptr_t)lb->alb_fail_buf;
30459517SBill.Taylor@Sun.COM 		lb32.alb_buf_sz		= lb->alb_buf_sz;
30469517SBill.Taylor@Sun.COM 		lb32.alb_num_iter	= lb->alb_num_iter;
30479517SBill.Taylor@Sun.COM 		lb32.alb_pass_done	= lb->alb_pass_done;
30489517SBill.Taylor@Sun.COM 		lb32.alb_timeout	= lb->alb_timeout;
30499517SBill.Taylor@Sun.COM 		lb32.alb_error_type	= lb->alb_error_type;
30509517SBill.Taylor@Sun.COM 		lb32.alb_port_num	= lb->alb_port_num;
30519517SBill.Taylor@Sun.COM 		lb32.alb_num_retry	= lb->alb_num_retry;
30529517SBill.Taylor@Sun.COM 
30539517SBill.Taylor@Sun.COM 		if (ddi_copyout(&lb32, (void *)arg,
30549517SBill.Taylor@Sun.COM 		    sizeof (hermon_loopback_ioctl32_t), mode) != 0) {
30559517SBill.Taylor@Sun.COM 			return (EFAULT);
30569517SBill.Taylor@Sun.COM 		}
30579517SBill.Taylor@Sun.COM 	} else
30589517SBill.Taylor@Sun.COM #endif /* _MULTI_DATAMODEL */
30599517SBill.Taylor@Sun.COM 	if (ddi_copyout(lb, (void *)arg, sizeof (hermon_loopback_ioctl_t),
30609517SBill.Taylor@Sun.COM 	    mode) != 0) {
30619517SBill.Taylor@Sun.COM 		return (EFAULT);
30629517SBill.Taylor@Sun.COM 	}
30639517SBill.Taylor@Sun.COM 	return (0);
30649517SBill.Taylor@Sun.COM }
30659517SBill.Taylor@Sun.COM 
30669517SBill.Taylor@Sun.COM /*
30679517SBill.Taylor@Sun.COM  * hermon_loopback_post_send
30689517SBill.Taylor@Sun.COM  */
30699517SBill.Taylor@Sun.COM static int
hermon_loopback_post_send(hermon_loopback_state_t * lstate,hermon_loopback_comm_t * tx,hermon_loopback_comm_t * rx)30709517SBill.Taylor@Sun.COM hermon_loopback_post_send(hermon_loopback_state_t *lstate,
30719517SBill.Taylor@Sun.COM     hermon_loopback_comm_t *tx, hermon_loopback_comm_t *rx)
30729517SBill.Taylor@Sun.COM {
30739517SBill.Taylor@Sun.COM 	int	 ret;
30749517SBill.Taylor@Sun.COM 
30759517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*tx))
30769517SBill.Taylor@Sun.COM 
30779517SBill.Taylor@Sun.COM 	bzero(&tx->hlc_sgl, sizeof (ibt_wr_ds_t));
30789517SBill.Taylor@Sun.COM 	bzero(&tx->hlc_wr, sizeof (ibt_send_wr_t));
30799517SBill.Taylor@Sun.COM 
30809517SBill.Taylor@Sun.COM 	/* Initialize local address for TX buffer */
30819517SBill.Taylor@Sun.COM 	tx->hlc_sgl.ds_va   = tx->hlc_mrdesc.md_vaddr;
30829517SBill.Taylor@Sun.COM 	tx->hlc_sgl.ds_key  = tx->hlc_mrdesc.md_lkey;
30839517SBill.Taylor@Sun.COM 	tx->hlc_sgl.ds_len  = tx->hlc_buf_sz;
30849517SBill.Taylor@Sun.COM 
30859517SBill.Taylor@Sun.COM 	/* Initialize the remaining details of the work request */
30869517SBill.Taylor@Sun.COM 	tx->hlc_wr.wr_id = tx->hlc_wrid++;
30879517SBill.Taylor@Sun.COM 	tx->hlc_wr.wr_flags  = IBT_WR_SEND_SIGNAL;
30889517SBill.Taylor@Sun.COM 	tx->hlc_wr.wr_nds    = 1;
30899517SBill.Taylor@Sun.COM 	tx->hlc_wr.wr_sgl    = &tx->hlc_sgl;
30909517SBill.Taylor@Sun.COM 	tx->hlc_wr.wr_opcode = IBT_WRC_RDMAW;
30919517SBill.Taylor@Sun.COM 	tx->hlc_wr.wr_trans  = IBT_RC_SRV;
30929517SBill.Taylor@Sun.COM 
30939517SBill.Taylor@Sun.COM 	/* Initialize the remote address for RX buffer */
30949517SBill.Taylor@Sun.COM 	tx->hlc_wr.wr.rc.rcwr.rdma.rdma_raddr = rx->hlc_mrdesc.md_vaddr;
30959517SBill.Taylor@Sun.COM 	tx->hlc_wr.wr.rc.rcwr.rdma.rdma_rkey  = rx->hlc_mrdesc.md_rkey;
30969517SBill.Taylor@Sun.COM 	tx->hlc_complete = 0;
30979517SBill.Taylor@Sun.COM 	ret = hermon_post_send(lstate->hls_state, tx->hlc_qp_hdl, &tx->hlc_wr,
30989517SBill.Taylor@Sun.COM 	    1, NULL);
30999517SBill.Taylor@Sun.COM 	if (ret != IBT_SUCCESS) {
31009517SBill.Taylor@Sun.COM 		return (EFAULT);
31019517SBill.Taylor@Sun.COM 	}
31029517SBill.Taylor@Sun.COM 	return (0);
31039517SBill.Taylor@Sun.COM }
31049517SBill.Taylor@Sun.COM 
31059517SBill.Taylor@Sun.COM /*
31069517SBill.Taylor@Sun.COM  * hermon_loopback_poll_cq
31079517SBill.Taylor@Sun.COM  */
31089517SBill.Taylor@Sun.COM static int
hermon_loopback_poll_cq(hermon_loopback_state_t * lstate,hermon_loopback_comm_t * comm)31099517SBill.Taylor@Sun.COM hermon_loopback_poll_cq(hermon_loopback_state_t *lstate,
31109517SBill.Taylor@Sun.COM     hermon_loopback_comm_t *comm)
31119517SBill.Taylor@Sun.COM {
31129517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm))
31139517SBill.Taylor@Sun.COM 
31149517SBill.Taylor@Sun.COM 	comm->hlc_wc.wc_status	= 0;
31159517SBill.Taylor@Sun.COM 	comm->hlc_num_polled	= 0;
31169517SBill.Taylor@Sun.COM 	comm->hlc_status = hermon_cq_poll(lstate->hls_state,
31179517SBill.Taylor@Sun.COM 	    comm->hlc_cqhdl[0], &comm->hlc_wc, 1, &comm->hlc_num_polled);
31189517SBill.Taylor@Sun.COM 	if ((comm->hlc_status == IBT_SUCCESS) &&
31199517SBill.Taylor@Sun.COM 	    (comm->hlc_wc.wc_status != IBT_WC_SUCCESS)) {
31209517SBill.Taylor@Sun.COM 		comm->hlc_status = ibc_get_ci_failure(0);
31219517SBill.Taylor@Sun.COM 	}
31229517SBill.Taylor@Sun.COM 	return (comm->hlc_status);
31239517SBill.Taylor@Sun.COM }
3124