19e39c5baSBill Taylor /*
29e39c5baSBill Taylor  * CDDL HEADER START
39e39c5baSBill Taylor  *
49e39c5baSBill Taylor  * The contents of this file are subject to the terms of the
59e39c5baSBill Taylor  * Common Development and Distribution License (the "License").
69e39c5baSBill Taylor  * You may not use this file except in compliance with the License.
79e39c5baSBill Taylor  *
89e39c5baSBill Taylor  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99e39c5baSBill Taylor  * or http://www.opensolaris.org/os/licensing.
109e39c5baSBill Taylor  * See the License for the specific language governing permissions
119e39c5baSBill Taylor  * and limitations under the License.
129e39c5baSBill Taylor  *
139e39c5baSBill Taylor  * When distributing Covered Code, include this CDDL HEADER in each
149e39c5baSBill Taylor  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159e39c5baSBill Taylor  * If applicable, add the following below this CDDL HEADER, with the
169e39c5baSBill Taylor  * fields enclosed by brackets "[]" replaced with your own identifying
179e39c5baSBill Taylor  * information: Portions Copyright [yyyy] [name of copyright owner]
189e39c5baSBill Taylor  *
199e39c5baSBill Taylor  * CDDL HEADER END
209e39c5baSBill Taylor  */
219e39c5baSBill Taylor 
229e39c5baSBill Taylor /*
2313cc0a0bSBill Taylor  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
249e39c5baSBill Taylor  */
259e39c5baSBill Taylor 
269e39c5baSBill Taylor /*
279e39c5baSBill Taylor  * hermon.c
289e39c5baSBill Taylor  *    Hermon (InfiniBand) HCA Driver attach/detach Routines
299e39c5baSBill Taylor  *
309e39c5baSBill Taylor  *    Implements all the routines necessary for the attach, setup,
319e39c5baSBill Taylor  *    initialization (and subsequent possible teardown and detach) of the
329e39c5baSBill Taylor  *    Hermon InfiniBand HCA driver.
339e39c5baSBill Taylor  */
349e39c5baSBill Taylor 
359e39c5baSBill Taylor #include <sys/types.h>
369e39c5baSBill Taylor #include <sys/file.h>
379e39c5baSBill Taylor #include <sys/open.h>
389e39c5baSBill Taylor #include <sys/conf.h>
399e39c5baSBill Taylor #include <sys/ddi.h>
409e39c5baSBill Taylor #include <sys/sunddi.h>
419e39c5baSBill Taylor #include <sys/modctl.h>
429e39c5baSBill Taylor #include <sys/stat.h>
439e39c5baSBill Taylor #include <sys/pci.h>
449e39c5baSBill Taylor #include <sys/pci_cap.h>
459e39c5baSBill Taylor #include <sys/bitmap.h>
469e39c5baSBill Taylor #include <sys/policy.h>
479e39c5baSBill Taylor 
489e39c5baSBill Taylor #include <sys/ib/adapters/hermon/hermon.h>
499e39c5baSBill Taylor 
5017a2b317SBill Taylor /* /etc/system can tune this down, if that is desirable. */
5117a2b317SBill Taylor int hermon_msix_max = HERMON_MSIX_MAX;
5217a2b317SBill Taylor 
539e39c5baSBill Taylor /* The following works around a problem in pre-2_7_000 firmware. */
549e39c5baSBill Taylor #define	HERMON_FW_WORKAROUND
559e39c5baSBill Taylor 
569e39c5baSBill Taylor int hermon_verbose = 0;
579e39c5baSBill Taylor 
589e39c5baSBill Taylor /* Hermon HCA State Pointer */
599e39c5baSBill Taylor void *hermon_statep;
609e39c5baSBill Taylor 
61332f545bSEiji Ota int debug_vpd = 0;
629e39c5baSBill Taylor 
63332f545bSEiji Ota /* Disable the internal error-check polling thread */
64332f545bSEiji Ota int hermon_no_inter_err_chk = 0;
659e39c5baSBill Taylor 
669e39c5baSBill Taylor /*
679e39c5baSBill Taylor  * The Hermon "userland resource database" is common to instances of the
689e39c5baSBill Taylor  * Hermon HCA driver.  This structure "hermon_userland_rsrc_db" contains all
699e39c5baSBill Taylor  * the necessary information to maintain it.
709e39c5baSBill Taylor  */
719e39c5baSBill Taylor hermon_umap_db_t hermon_userland_rsrc_db;
729e39c5baSBill Taylor 
739e39c5baSBill Taylor static int hermon_attach(dev_info_t *, ddi_attach_cmd_t);
749e39c5baSBill Taylor static int hermon_detach(dev_info_t *, ddi_detach_cmd_t);
759e39c5baSBill Taylor static int hermon_open(dev_t *, int, int, cred_t *);
769e39c5baSBill Taylor static int hermon_close(dev_t, int, int, cred_t *);
779e39c5baSBill Taylor static int hermon_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
789e39c5baSBill Taylor 
799e39c5baSBill Taylor static int hermon_drv_init(hermon_state_t *state, dev_info_t *dip,
809e39c5baSBill Taylor     int instance);
819e39c5baSBill Taylor static void hermon_drv_fini(hermon_state_t *state);
829e39c5baSBill Taylor static void hermon_drv_fini2(hermon_state_t *state);
839e39c5baSBill Taylor static int hermon_isr_init(hermon_state_t *state);
849e39c5baSBill Taylor static void hermon_isr_fini(hermon_state_t *state);
859e39c5baSBill Taylor 
869e39c5baSBill Taylor static int hermon_hw_init(hermon_state_t *state);
879e39c5baSBill Taylor 
889e39c5baSBill Taylor static void hermon_hw_fini(hermon_state_t *state,
899e39c5baSBill Taylor     hermon_drv_cleanup_level_t cleanup);
909e39c5baSBill Taylor static int hermon_soft_state_init(hermon_state_t *state);
919e39c5baSBill Taylor static void hermon_soft_state_fini(hermon_state_t *state);
929e39c5baSBill Taylor static int hermon_icm_config_setup(hermon_state_t *state,
939e39c5baSBill Taylor     hermon_hw_initqueryhca_t *inithca);
949e39c5baSBill Taylor static void hermon_icm_tables_init(hermon_state_t *state);
959e39c5baSBill Taylor static void hermon_icm_tables_fini(hermon_state_t *state);
969e39c5baSBill Taylor static int hermon_icm_dma_init(hermon_state_t *state);
979e39c5baSBill Taylor static void hermon_icm_dma_fini(hermon_state_t *state);
989e39c5baSBill Taylor static void hermon_inithca_set(hermon_state_t *state,
999e39c5baSBill Taylor     hermon_hw_initqueryhca_t *inithca);
1009e39c5baSBill Taylor static int hermon_hca_port_init(hermon_state_t *state);
1019e39c5baSBill Taylor static int hermon_hca_ports_shutdown(hermon_state_t *state, uint_t num_init);
1029e39c5baSBill Taylor static int hermon_internal_uarpg_init(hermon_state_t *state);
1039e39c5baSBill Taylor static void hermon_internal_uarpg_fini(hermon_state_t *state);
1049e39c5baSBill Taylor static int hermon_special_qp_contexts_reserve(hermon_state_t *state);
1059e39c5baSBill Taylor static void hermon_special_qp_contexts_unreserve(hermon_state_t *state);
1069e39c5baSBill Taylor static int hermon_sw_reset(hermon_state_t *state);
1079e39c5baSBill Taylor static int hermon_mcg_init(hermon_state_t *state);
1089e39c5baSBill Taylor static void hermon_mcg_fini(hermon_state_t *state);
1099e39c5baSBill Taylor static int hermon_fw_version_check(hermon_state_t *state);
1109e39c5baSBill Taylor static void hermon_device_info_report(hermon_state_t *state);
1119e39c5baSBill Taylor static int hermon_pci_capability_list(hermon_state_t *state,
1129e39c5baSBill Taylor     ddi_acc_handle_t hdl);
1139e39c5baSBill Taylor static void hermon_pci_capability_vpd(hermon_state_t *state,
1149e39c5baSBill Taylor     ddi_acc_handle_t hdl, uint_t offset);
1159e39c5baSBill Taylor static int hermon_pci_read_vpd(ddi_acc_handle_t hdl, uint_t offset,
1169e39c5baSBill Taylor     uint32_t addr, uint32_t *data);
1179e39c5baSBill Taylor static int hermon_intr_or_msi_init(hermon_state_t *state);
1189e39c5baSBill Taylor static int hermon_add_intrs(hermon_state_t *state, int intr_type);
1199e39c5baSBill Taylor static int hermon_intr_or_msi_fini(hermon_state_t *state);
1209e39c5baSBill Taylor void hermon_pci_capability_msix(hermon_state_t *state, ddi_acc_handle_t hdl,
1219e39c5baSBill Taylor     uint_t offset);
1229e39c5baSBill Taylor 
1239e39c5baSBill Taylor static uint64_t hermon_size_icm(hermon_state_t *state);
1249e39c5baSBill Taylor 
1259e39c5baSBill Taylor /* X86 fastreboot support */
1269e39c5baSBill Taylor static ushort_t get_msix_ctrl(dev_info_t *);
1279e39c5baSBill Taylor static size_t get_msix_tbl_size(dev_info_t *);
1289e39c5baSBill Taylor static size_t get_msix_pba_size(dev_info_t *);
1299e39c5baSBill Taylor static void hermon_set_msix_info(hermon_state_t *);
1309e39c5baSBill Taylor static int hermon_intr_disable(hermon_state_t *);
1319e39c5baSBill Taylor static int hermon_quiesce(dev_info_t *);
1329e39c5baSBill Taylor 
1339e39c5baSBill Taylor 
1349e39c5baSBill Taylor /* Character/Block Operations */
1359e39c5baSBill Taylor static struct cb_ops hermon_cb_ops = {
1369e39c5baSBill Taylor 	hermon_open,		/* open */
1379e39c5baSBill Taylor 	hermon_close,		/* close */
1389e39c5baSBill Taylor 	nodev,			/* strategy (block) */
1399e39c5baSBill Taylor 	nodev,			/* print (block) */
1409e39c5baSBill Taylor 	nodev,			/* dump (block) */
1419e39c5baSBill Taylor 	nodev,			/* read */
1429e39c5baSBill Taylor 	nodev,			/* write */
1439e39c5baSBill Taylor 	hermon_ioctl,		/* ioctl */
1449e39c5baSBill Taylor 	hermon_devmap,		/* devmap */
1459e39c5baSBill Taylor 	NULL,			/* mmap */
1469e39c5baSBill Taylor 	nodev,			/* segmap */
1479e39c5baSBill Taylor 	nochpoll,		/* chpoll */
1489e39c5baSBill Taylor 	ddi_prop_op,		/* prop_op */
1499e39c5baSBill Taylor 	NULL,			/* streams */
1509e39c5baSBill Taylor 	D_NEW | D_MP |
15113cc0a0bSBill Taylor 	D_64BIT | D_HOTPLUG |
1529e39c5baSBill Taylor 	D_DEVMAP,		/* flags */
1539e39c5baSBill Taylor 	CB_REV			/* rev */
1549e39c5baSBill Taylor };
1559e39c5baSBill Taylor 
1569e39c5baSBill Taylor /* Driver Operations */
1579e39c5baSBill Taylor static struct dev_ops hermon_ops = {
1589e39c5baSBill Taylor 	DEVO_REV,		/* struct rev */
1599e39c5baSBill Taylor 	0,			/* refcnt */
1609e39c5baSBill Taylor 	hermon_getinfo,		/* getinfo */
1619e39c5baSBill Taylor 	nulldev,		/* identify */
1629e39c5baSBill Taylor 	nulldev,		/* probe */
1639e39c5baSBill Taylor 	hermon_attach,		/* attach */
1649e39c5baSBill Taylor 	hermon_detach,		/* detach */
1659e39c5baSBill Taylor 	nodev,			/* reset */
1669e39c5baSBill Taylor 	&hermon_cb_ops,		/* cb_ops */
1679e39c5baSBill Taylor 	NULL,			/* bus_ops */
1689e39c5baSBill Taylor 	nodev,			/* power */
1699e39c5baSBill Taylor 	hermon_quiesce,		/* devo_quiesce */
1709e39c5baSBill Taylor };
1719e39c5baSBill Taylor 
1729e39c5baSBill Taylor /* Module Driver Info */
1739e39c5baSBill Taylor static struct modldrv hermon_modldrv = {
1749e39c5baSBill Taylor 	&mod_driverops,
1759e39c5baSBill Taylor 	"ConnectX IB Driver",
1769e39c5baSBill Taylor 	&hermon_ops
1779e39c5baSBill Taylor };
1789e39c5baSBill Taylor 
1799e39c5baSBill Taylor /* Module Linkage */
1809e39c5baSBill Taylor static struct modlinkage hermon_modlinkage = {
1819e39c5baSBill Taylor 	MODREV_1,
1829e39c5baSBill Taylor 	&hermon_modldrv,
1839e39c5baSBill Taylor 	NULL
1849e39c5baSBill Taylor };
1859e39c5baSBill Taylor 
1869e39c5baSBill Taylor /*
1879e39c5baSBill Taylor  * This extern refers to the ibc_operations_t function vector that is defined
1889e39c5baSBill Taylor  * in the hermon_ci.c file.
1899e39c5baSBill Taylor  */
1909e39c5baSBill Taylor extern ibc_operations_t	hermon_ibc_ops;
1919e39c5baSBill Taylor 
1929e39c5baSBill Taylor /*
1939e39c5baSBill Taylor  * _init()
1949e39c5baSBill Taylor  */
1959e39c5baSBill Taylor int
_init()1969e39c5baSBill Taylor _init()
1979e39c5baSBill Taylor {
1989e39c5baSBill Taylor 	int	status;
1999e39c5baSBill Taylor 
2009e39c5baSBill Taylor 	status = ddi_soft_state_init(&hermon_statep, sizeof (hermon_state_t),
2019e39c5baSBill Taylor 	    (size_t)HERMON_INITIAL_STATES);
2029e39c5baSBill Taylor 	if (status != 0) {
2039e39c5baSBill Taylor 		return (status);
2049e39c5baSBill Taylor 	}
2059e39c5baSBill Taylor 
2069e39c5baSBill Taylor 	status = ibc_init(&hermon_modlinkage);
2079e39c5baSBill Taylor 	if (status != 0) {
2089e39c5baSBill Taylor 		ddi_soft_state_fini(&hermon_statep);
2099e39c5baSBill Taylor 		return (status);
2109e39c5baSBill Taylor 	}
2119e39c5baSBill Taylor 
2129e39c5baSBill Taylor 	status = mod_install(&hermon_modlinkage);
2139e39c5baSBill Taylor 	if (status != 0) {
2149e39c5baSBill Taylor 		ibc_fini(&hermon_modlinkage);
2159e39c5baSBill Taylor 		ddi_soft_state_fini(&hermon_statep);
2169e39c5baSBill Taylor 		return (status);
2179e39c5baSBill Taylor 	}
2189e39c5baSBill Taylor 
2199e39c5baSBill Taylor 	/* Initialize the Hermon "userland resources database" */
2209e39c5baSBill Taylor 	hermon_umap_db_init();
2219e39c5baSBill Taylor 
2229e39c5baSBill Taylor 	return (status);
2239e39c5baSBill Taylor }
2249e39c5baSBill Taylor 
2259e39c5baSBill Taylor 
2269e39c5baSBill Taylor /*
2279e39c5baSBill Taylor  * _info()
2289e39c5baSBill Taylor  */
2299e39c5baSBill Taylor int
_info(struct modinfo * modinfop)2309e39c5baSBill Taylor _info(struct modinfo *modinfop)
2319e39c5baSBill Taylor {
2329e39c5baSBill Taylor 	int	status;
2339e39c5baSBill Taylor 
2349e39c5baSBill Taylor 	status = mod_info(&hermon_modlinkage, modinfop);
2359e39c5baSBill Taylor 	return (status);
2369e39c5baSBill Taylor }
2379e39c5baSBill Taylor 
2389e39c5baSBill Taylor 
2399e39c5baSBill Taylor /*
2409e39c5baSBill Taylor  * _fini()
2419e39c5baSBill Taylor  */
2429e39c5baSBill Taylor int
_fini()2439e39c5baSBill Taylor _fini()
2449e39c5baSBill Taylor {
2459e39c5baSBill Taylor 	int	status;
2469e39c5baSBill Taylor 
2479e39c5baSBill Taylor 	status = mod_remove(&hermon_modlinkage);
2489e39c5baSBill Taylor 	if (status != 0) {
2499e39c5baSBill Taylor 		return (status);
2509e39c5baSBill Taylor 	}
2519e39c5baSBill Taylor 
2529e39c5baSBill Taylor 	/* Destroy the Hermon "userland resources database" */
2539e39c5baSBill Taylor 	hermon_umap_db_fini();
2549e39c5baSBill Taylor 
2559e39c5baSBill Taylor 	ibc_fini(&hermon_modlinkage);
2569e39c5baSBill Taylor 	ddi_soft_state_fini(&hermon_statep);
2579e39c5baSBill Taylor 
2589e39c5baSBill Taylor 	return (status);
2599e39c5baSBill Taylor }
2609e39c5baSBill Taylor 
2619e39c5baSBill Taylor 
2629e39c5baSBill Taylor /*
2639e39c5baSBill Taylor  * hermon_getinfo()
2649e39c5baSBill Taylor  */
2659e39c5baSBill Taylor /* ARGSUSED */
2669e39c5baSBill Taylor static int
hermon_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** result)2679e39c5baSBill Taylor hermon_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
2689e39c5baSBill Taylor {
2699e39c5baSBill Taylor 	dev_t		dev;
270*0b63ccafSToomas Soome 	hermon_state_t	*state;
2719e39c5baSBill Taylor 	minor_t		instance;
2729e39c5baSBill Taylor 
2739e39c5baSBill Taylor 	switch (cmd) {
2749e39c5baSBill Taylor 	case DDI_INFO_DEVT2DEVINFO:
2759e39c5baSBill Taylor 		dev = (dev_t)arg;
2769e39c5baSBill Taylor 		instance = HERMON_DEV_INSTANCE(dev);
2779e39c5baSBill Taylor 		state = ddi_get_soft_state(hermon_statep, instance);
2789e39c5baSBill Taylor 		if (state == NULL) {
2799e39c5baSBill Taylor 			return (DDI_FAILURE);
2809e39c5baSBill Taylor 		}
2819e39c5baSBill Taylor 		*result = (void *)state->hs_dip;
2829e39c5baSBill Taylor 		return (DDI_SUCCESS);
2839e39c5baSBill Taylor 
2849e39c5baSBill Taylor 	case DDI_INFO_DEVT2INSTANCE:
2859e39c5baSBill Taylor 		dev = (dev_t)arg;
2869e39c5baSBill Taylor 		instance = HERMON_DEV_INSTANCE(dev);
2879e39c5baSBill Taylor 		*result = (void *)(uintptr_t)instance;
2889e39c5baSBill Taylor 		return (DDI_SUCCESS);
2899e39c5baSBill Taylor 
2909e39c5baSBill Taylor 	default:
2919e39c5baSBill Taylor 		break;
2929e39c5baSBill Taylor 	}
2939e39c5baSBill Taylor 
2949e39c5baSBill Taylor 	return (DDI_FAILURE);
2959e39c5baSBill Taylor }
2969e39c5baSBill Taylor 
2979e39c5baSBill Taylor 
2989e39c5baSBill Taylor /*
2999e39c5baSBill Taylor  * hermon_open()
3009e39c5baSBill Taylor  */
3019e39c5baSBill Taylor /* ARGSUSED */
3029e39c5baSBill Taylor static int
hermon_open(dev_t * devp,int flag,int otyp,cred_t * credp)3039e39c5baSBill Taylor hermon_open(dev_t *devp, int flag, int otyp, cred_t *credp)
3049e39c5baSBill Taylor {
3059e39c5baSBill Taylor 	hermon_state_t		*state;
306*0b63ccafSToomas Soome 	hermon_rsrc_t		*rsrcp;
3079e39c5baSBill Taylor 	hermon_umap_db_entry_t	*umapdb, *umapdb2;
3089e39c5baSBill Taylor 	minor_t			instance;
3099e39c5baSBill Taylor 	uint64_t		key, value;
3109e39c5baSBill Taylor 	uint_t			hr_indx;
3119e39c5baSBill Taylor 	dev_t			dev;
3129e39c5baSBill Taylor 	int			status;
3139e39c5baSBill Taylor 
3149e39c5baSBill Taylor 	instance = HERMON_DEV_INSTANCE(*devp);
3159e39c5baSBill Taylor 	state = ddi_get_soft_state(hermon_statep, instance);
3169e39c5baSBill Taylor 	if (state == NULL) {
3179e39c5baSBill Taylor 		return (ENXIO);
3189e39c5baSBill Taylor 	}
3199e39c5baSBill Taylor 
3209e39c5baSBill Taylor 	/*
3219e39c5baSBill Taylor 	 * Only allow driver to be opened for character access, and verify
3229e39c5baSBill Taylor 	 * whether exclusive access is allowed.
3239e39c5baSBill Taylor 	 */
3249e39c5baSBill Taylor 	if ((otyp != OTYP_CHR) || ((flag & FEXCL) &&
3259e39c5baSBill Taylor 	    secpolicy_excl_open(credp) != 0)) {
3269e39c5baSBill Taylor 		return (EINVAL);
3279e39c5baSBill Taylor 	}
3289e39c5baSBill Taylor 
3299e39c5baSBill Taylor 	/*
3309e39c5baSBill Taylor 	 * Search for the current process PID in the "userland resources
3319e39c5baSBill Taylor 	 * database".  If it is not found, then attempt to allocate a UAR
3329e39c5baSBill Taylor 	 * page and add the ("key", "value") pair to the database.
3339e39c5baSBill Taylor 	 * Note:  As a last step we always return a devp appropriate for
3349e39c5baSBill Taylor 	 * the open.  Either we return a new minor number (based on the
3359e39c5baSBill Taylor 	 * instance and the UAR page index) or we return the current minor
3369e39c5baSBill Taylor 	 * number for the given client process.
3379e39c5baSBill Taylor 	 *
3389e39c5baSBill Taylor 	 * We also add an entry to the database to allow for lookup from
3399e39c5baSBill Taylor 	 * "dev_t" to the current process PID.  This is necessary because,
3409e39c5baSBill Taylor 	 * under certain circumstance, the process PID that calls the Hermon
3419e39c5baSBill Taylor 	 * close() entry point may not be the same as the one who called
3429e39c5baSBill Taylor 	 * open().  Specifically, this can happen if a child process calls
3439e39c5baSBill Taylor 	 * the Hermon's open() entry point, gets a UAR page, maps it out (using
3449e39c5baSBill Taylor 	 * mmap()), and then exits without calling munmap().  Because mmap()
3459e39c5baSBill Taylor 	 * adds a reference to the file descriptor, at the exit of the child
3469e39c5baSBill Taylor 	 * process the file descriptor is "inherited" by the parent (and will
3479e39c5baSBill Taylor 	 * be close()'d by the parent's PID only when it exits).
3489e39c5baSBill Taylor 	 *
3499e39c5baSBill Taylor 	 * Note: We use the hermon_umap_db_find_nolock() and
3509e39c5baSBill Taylor 	 * hermon_umap_db_add_nolock() database access routines below (with
3519e39c5baSBill Taylor 	 * an explicit mutex_enter of the database lock - "hdl_umapdb_lock")
3529e39c5baSBill Taylor 	 * to ensure that the multiple accesses (in this case searching for,
3539e39c5baSBill Taylor 	 * and then adding _two_ database entries) can be done atomically.
3549e39c5baSBill Taylor 	 */
3559e39c5baSBill Taylor 	key = ddi_get_pid();
3569e39c5baSBill Taylor 	mutex_enter(&hermon_userland_rsrc_db.hdl_umapdb_lock);
3579e39c5baSBill Taylor 	status = hermon_umap_db_find_nolock(instance, key,
3589e39c5baSBill Taylor 	    MLNX_UMAP_UARPG_RSRC, &value, 0, NULL);
3599e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
3609e39c5baSBill Taylor 		/*
3619e39c5baSBill Taylor 		 * If we are in 'maintenance mode', we cannot alloc a UAR page.
3629e39c5baSBill Taylor 		 * But we still need some rsrcp value, and a mostly unique
3639e39c5baSBill Taylor 		 * hr_indx value.  So we set rsrcp to NULL for maintenance
3649e39c5baSBill Taylor 		 * mode, and use a rolling count for hr_indx.  The field
3659e39c5baSBill Taylor 		 * 'hs_open_hr_indx' is used only in this maintenance mode
3669e39c5baSBill Taylor 		 * condition.
3679e39c5baSBill Taylor 		 *
3689e39c5baSBill Taylor 		 * Otherwise, if we are in operational mode then we allocate
3699e39c5baSBill Taylor 		 * the UAR page as normal, and use the rsrcp value and tr_indx
3709e39c5baSBill Taylor 		 * value from that allocation.
3719e39c5baSBill Taylor 		 */
3729e39c5baSBill Taylor 		if (!HERMON_IS_OPERATIONAL(state->hs_operational_mode)) {
3739e39c5baSBill Taylor 			rsrcp = NULL;
3749e39c5baSBill Taylor 			hr_indx = state->hs_open_ar_indx++;
3759e39c5baSBill Taylor 		} else {
3769e39c5baSBill Taylor 			/* Allocate a new UAR page for this process */
3779e39c5baSBill Taylor 			status = hermon_rsrc_alloc(state, HERMON_UARPG, 1,
3789e39c5baSBill Taylor 			    HERMON_NOSLEEP, &rsrcp);
3799e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
3809e39c5baSBill Taylor 				mutex_exit(
3819e39c5baSBill Taylor 				    &hermon_userland_rsrc_db.hdl_umapdb_lock);
3829e39c5baSBill Taylor 				return (EAGAIN);
3839e39c5baSBill Taylor 			}
3849e39c5baSBill Taylor 
3859e39c5baSBill Taylor 			hr_indx = rsrcp->hr_indx;
3869e39c5baSBill Taylor 		}
3879e39c5baSBill Taylor 
3889e39c5baSBill Taylor 		/*
3899e39c5baSBill Taylor 		 * Allocate an entry to track the UAR page resource in the
3909e39c5baSBill Taylor 		 * "userland resources database".
3919e39c5baSBill Taylor 		 */
3929e39c5baSBill Taylor 		umapdb = hermon_umap_db_alloc(instance, key,
3939e39c5baSBill Taylor 		    MLNX_UMAP_UARPG_RSRC, (uint64_t)(uintptr_t)rsrcp);
3949e39c5baSBill Taylor 		if (umapdb == NULL) {
3959e39c5baSBill Taylor 			mutex_exit(&hermon_userland_rsrc_db.hdl_umapdb_lock);
3969e39c5baSBill Taylor 			/* If in "maintenance mode", don't free the rsrc */
3979e39c5baSBill Taylor 			if (HERMON_IS_OPERATIONAL(state->hs_operational_mode)) {
3989e39c5baSBill Taylor 				hermon_rsrc_free(state, &rsrcp);
3999e39c5baSBill Taylor 			}
4009e39c5baSBill Taylor 			return (EAGAIN);
4019e39c5baSBill Taylor 		}
4029e39c5baSBill Taylor 
4039e39c5baSBill Taylor 		/*
4049e39c5baSBill Taylor 		 * Create a new device number.  Minor number is a function of
4059e39c5baSBill Taylor 		 * the UAR page index (15 bits) and the device instance number
4069e39c5baSBill Taylor 		 * (3 bits).
4079e39c5baSBill Taylor 		 */
4089e39c5baSBill Taylor 		dev = makedevice(getmajor(*devp), (hr_indx <<
4099e39c5baSBill Taylor 		    HERMON_MINORNUM_SHIFT) | instance);
4109e39c5baSBill Taylor 
4119e39c5baSBill Taylor 		/*
4129e39c5baSBill Taylor 		 * Allocate another entry in the "userland resources database"
4139e39c5baSBill Taylor 		 * to track the association of the device number (above) to
4149e39c5baSBill Taylor 		 * the current process ID (in "key").
4159e39c5baSBill Taylor 		 */
4169e39c5baSBill Taylor 		umapdb2 = hermon_umap_db_alloc(instance, dev,
4179e39c5baSBill Taylor 		    MLNX_UMAP_PID_RSRC, (uint64_t)key);
4189e39c5baSBill Taylor 		if (umapdb2 == NULL) {
4199e39c5baSBill Taylor 			mutex_exit(&hermon_userland_rsrc_db.hdl_umapdb_lock);
4209e39c5baSBill Taylor 			hermon_umap_db_free(umapdb);
4219e39c5baSBill Taylor 			/* If in "maintenance mode", don't free the rsrc */
4229e39c5baSBill Taylor 			if (HERMON_IS_OPERATIONAL(state->hs_operational_mode)) {
4239e39c5baSBill Taylor 				hermon_rsrc_free(state, &rsrcp);
4249e39c5baSBill Taylor 			}
4259e39c5baSBill Taylor 			return (EAGAIN);
4269e39c5baSBill Taylor 		}
4279e39c5baSBill Taylor 
4289e39c5baSBill Taylor 		/* Add the entries to the database */
4299e39c5baSBill Taylor 		hermon_umap_db_add_nolock(umapdb);
4309e39c5baSBill Taylor 		hermon_umap_db_add_nolock(umapdb2);
4319e39c5baSBill Taylor 
4329e39c5baSBill Taylor 	} else {
4339e39c5baSBill Taylor 		/*
4349e39c5baSBill Taylor 		 * Return the same device number as on the original open()
4359e39c5baSBill Taylor 		 * call.  This was calculated as a function of the UAR page
4369e39c5baSBill Taylor 		 * index (top 16 bits) and the device instance number
4379e39c5baSBill Taylor 		 */
4389e39c5baSBill Taylor 		rsrcp = (hermon_rsrc_t *)(uintptr_t)value;
4399e39c5baSBill Taylor 		dev = makedevice(getmajor(*devp), (rsrcp->hr_indx <<
4409e39c5baSBill Taylor 		    HERMON_MINORNUM_SHIFT) | instance);
4419e39c5baSBill Taylor 	}
4429e39c5baSBill Taylor 	mutex_exit(&hermon_userland_rsrc_db.hdl_umapdb_lock);
4439e39c5baSBill Taylor 
4449e39c5baSBill Taylor 	*devp = dev;
4459e39c5baSBill Taylor 
4469e39c5baSBill Taylor 	return (0);
4479e39c5baSBill Taylor }
4489e39c5baSBill Taylor 
4499e39c5baSBill Taylor 
4509e39c5baSBill Taylor /*
4519e39c5baSBill Taylor  * hermon_close()
4529e39c5baSBill Taylor  */
4539e39c5baSBill Taylor /* ARGSUSED */
4549e39c5baSBill Taylor static int
hermon_close(dev_t dev,int flag,int otyp,cred_t * credp)4559e39c5baSBill Taylor hermon_close(dev_t dev, int flag, int otyp, cred_t *credp)
4569e39c5baSBill Taylor {
4579e39c5baSBill Taylor 	hermon_state_t		*state;
4589e39c5baSBill Taylor 	hermon_rsrc_t		*rsrcp;
4599e39c5baSBill Taylor 	hermon_umap_db_entry_t	*umapdb;
4609e39c5baSBill Taylor 	hermon_umap_db_priv_t	*priv;
4619e39c5baSBill Taylor 	minor_t			instance;
4629e39c5baSBill Taylor 	uint64_t		key, value;
4639e39c5baSBill Taylor 	int			status, reset_status = 0;
4649e39c5baSBill Taylor 
4659e39c5baSBill Taylor 	instance = HERMON_DEV_INSTANCE(dev);
4669e39c5baSBill Taylor 	state = ddi_get_soft_state(hermon_statep, instance);
4679e39c5baSBill Taylor 	if (state == NULL) {
4689e39c5baSBill Taylor 		return (ENXIO);
4699e39c5baSBill Taylor 	}
4709e39c5baSBill Taylor 
4719e39c5baSBill Taylor 	/*
4729e39c5baSBill Taylor 	 * Search for "dev_t" in the "userland resources database".  As
4739e39c5baSBill Taylor 	 * explained above in hermon_open(), we can't depend on using the
4749e39c5baSBill Taylor 	 * current process ID here to do the lookup because the process
4759e39c5baSBill Taylor 	 * that ultimately closes may not be the same one who opened
4769e39c5baSBill Taylor 	 * (because of inheritance).
4779e39c5baSBill Taylor 	 * So we lookup the "dev_t" (which points to the PID of the process
4789e39c5baSBill Taylor 	 * that opened), and we remove the entry from the database (and free
4799e39c5baSBill Taylor 	 * it up).  Then we do another query based on the PID value.  And when
4809e39c5baSBill Taylor 	 * we find that database entry, we free it up too and then free the
4819e39c5baSBill Taylor 	 * Hermon UAR page resource.
4829e39c5baSBill Taylor 	 *
4839e39c5baSBill Taylor 	 * Note: We use the hermon_umap_db_find_nolock() database access
4849e39c5baSBill Taylor 	 * routine below (with an explicit mutex_enter of the database lock)
4859e39c5baSBill Taylor 	 * to ensure that the multiple accesses (which attempt to remove the
4869e39c5baSBill Taylor 	 * two database entries) can be done atomically.
4879e39c5baSBill Taylor 	 *
4889e39c5baSBill Taylor 	 * This works the same in both maintenance mode and HCA mode, except
4899e39c5baSBill Taylor 	 * for the call to hermon_rsrc_free().  In the case of maintenance mode,
4909e39c5baSBill Taylor 	 * this call is not needed, as it was not allocated in hermon_open()
4919e39c5baSBill Taylor 	 * above.
4929e39c5baSBill Taylor 	 */
4939e39c5baSBill Taylor 	key = dev;
4949e39c5baSBill Taylor 	mutex_enter(&hermon_userland_rsrc_db.hdl_umapdb_lock);
4959e39c5baSBill Taylor 	status = hermon_umap_db_find_nolock(instance, key, MLNX_UMAP_PID_RSRC,
4969e39c5baSBill Taylor 	    &value, HERMON_UMAP_DB_REMOVE, &umapdb);
4979e39c5baSBill Taylor 	if (status == DDI_SUCCESS) {
4989e39c5baSBill Taylor 		/*
4999e39c5baSBill Taylor 		 * If the "hdb_priv" field is non-NULL, it indicates that
5009e39c5baSBill Taylor 		 * some "on close" handling is still necessary.  Call
5019e39c5baSBill Taylor 		 * hermon_umap_db_handle_onclose_cb() to do the handling (i.e.
5029e39c5baSBill Taylor 		 * to invoke all the registered callbacks).  Then free up
5039e39c5baSBill Taylor 		 * the resources associated with "hdb_priv" and continue
5049e39c5baSBill Taylor 		 * closing.
5059e39c5baSBill Taylor 		 */
5069e39c5baSBill Taylor 		priv = (hermon_umap_db_priv_t *)umapdb->hdbe_common.hdb_priv;
5079e39c5baSBill Taylor 		if (priv != NULL) {
5089e39c5baSBill Taylor 			reset_status = hermon_umap_db_handle_onclose_cb(priv);
5099e39c5baSBill Taylor 			kmem_free(priv, sizeof (hermon_umap_db_priv_t));
5109e39c5baSBill Taylor 			umapdb->hdbe_common.hdb_priv = (void *)NULL;
5119e39c5baSBill Taylor 		}
5129e39c5baSBill Taylor 
5139e39c5baSBill Taylor 		hermon_umap_db_free(umapdb);
5149e39c5baSBill Taylor 
5159e39c5baSBill Taylor 		/*
5169e39c5baSBill Taylor 		 * Now do another lookup using PID as the key (copy it from
5179e39c5baSBill Taylor 		 * "value").  When this lookup is complete, the "value" field
5189e39c5baSBill Taylor 		 * will contain the hermon_rsrc_t pointer for the UAR page
5199e39c5baSBill Taylor 		 * resource.
5209e39c5baSBill Taylor 		 */
5219e39c5baSBill Taylor 		key = value;
5229e39c5baSBill Taylor 		status = hermon_umap_db_find_nolock(instance, key,
5239e39c5baSBill Taylor 		    MLNX_UMAP_UARPG_RSRC, &value, HERMON_UMAP_DB_REMOVE,
5249e39c5baSBill Taylor 		    &umapdb);
5259e39c5baSBill Taylor 		if (status == DDI_SUCCESS) {
5269e39c5baSBill Taylor 			hermon_umap_db_free(umapdb);
5279e39c5baSBill Taylor 			/* If in "maintenance mode", don't free the rsrc */
5289e39c5baSBill Taylor 			if (HERMON_IS_OPERATIONAL(state->hs_operational_mode)) {
5299e39c5baSBill Taylor 				rsrcp = (hermon_rsrc_t *)(uintptr_t)value;
5309e39c5baSBill Taylor 				hermon_rsrc_free(state, &rsrcp);
5319e39c5baSBill Taylor 			}
5329e39c5baSBill Taylor 		}
5339e39c5baSBill Taylor 	}
5349e39c5baSBill Taylor 	mutex_exit(&hermon_userland_rsrc_db.hdl_umapdb_lock);
5359e39c5baSBill Taylor 	return (reset_status);
5369e39c5baSBill Taylor }
5379e39c5baSBill Taylor 
5389e39c5baSBill Taylor 
5399e39c5baSBill Taylor /*
5409e39c5baSBill Taylor  * hermon_attach()
5419e39c5baSBill Taylor  *    Context: Only called from attach() path context
5429e39c5baSBill Taylor  */
5439e39c5baSBill Taylor static int
hermon_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)5449e39c5baSBill Taylor hermon_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
5459e39c5baSBill Taylor {
5469e39c5baSBill Taylor 	hermon_state_t	*state;
5479e39c5baSBill Taylor 	ibc_clnt_hdl_t	tmp_ibtfpriv;
5489e39c5baSBill Taylor 	ibc_status_t	ibc_status;
5499e39c5baSBill Taylor 	int		instance;
5509e39c5baSBill Taylor 	int		status;
5519e39c5baSBill Taylor 
5529e39c5baSBill Taylor #ifdef __lock_lint
5539e39c5baSBill Taylor 	(void) hermon_quiesce(dip);
5549e39c5baSBill Taylor #endif
5559e39c5baSBill Taylor 
5569e39c5baSBill Taylor 	switch (cmd) {
5579e39c5baSBill Taylor 	case DDI_ATTACH:
5589e39c5baSBill Taylor 		instance = ddi_get_instance(dip);
5599e39c5baSBill Taylor 		status = ddi_soft_state_zalloc(hermon_statep, instance);
5609e39c5baSBill Taylor 		if (status != DDI_SUCCESS) {
5619e39c5baSBill Taylor 			cmn_err(CE_NOTE, "hermon%d: driver failed to attach: "
5629e39c5baSBill Taylor 			    "attach_ssz_fail", instance);
5639e39c5baSBill Taylor 			goto fail_attach_nomsg;
5649e39c5baSBill Taylor 
5659e39c5baSBill Taylor 		}
5669e39c5baSBill Taylor 		state = ddi_get_soft_state(hermon_statep, instance);
5679e39c5baSBill Taylor 		if (state == NULL) {
5689e39c5baSBill Taylor 			ddi_soft_state_free(hermon_statep, instance);
5699e39c5baSBill Taylor 			cmn_err(CE_NOTE, "hermon%d: driver failed to attach: "
5709e39c5baSBill Taylor 			    "attach_gss_fail", instance);
5719e39c5baSBill Taylor 			goto fail_attach_nomsg;
5729e39c5baSBill Taylor 		}
5739e39c5baSBill Taylor 
5749e39c5baSBill Taylor 		/* clear the attach error buffer */
5759e39c5baSBill Taylor 		HERMON_ATTACH_MSG_INIT(state->hs_attach_buf);
5769e39c5baSBill Taylor 
5779e39c5baSBill Taylor 		/* Save away devinfo and instance before hermon_fm_init() */
5789e39c5baSBill Taylor 		state->hs_dip = dip;
5799e39c5baSBill Taylor 		state->hs_instance = instance;
5809e39c5baSBill Taylor 
5819e39c5baSBill Taylor 		hermon_fm_init(state);
5829e39c5baSBill Taylor 
5839e39c5baSBill Taylor 		/*
5849e39c5baSBill Taylor 		 * Initialize Hermon driver and hardware.
5859e39c5baSBill Taylor 		 *
5869e39c5baSBill Taylor 		 * Note: If this initialization fails we may still wish to
5879e39c5baSBill Taylor 		 * create a device node and remain operational so that Hermon
5889e39c5baSBill Taylor 		 * firmware can be updated/flashed (i.e. "maintenance mode").
5899e39c5baSBill Taylor 		 * If this is the case, then "hs_operational_mode" will be
5909e39c5baSBill Taylor 		 * equal to HERMON_MAINTENANCE_MODE.  We will not attempt to
5919e39c5baSBill Taylor 		 * attach to the IBTF or register with the IBMF (i.e. no
5929e39c5baSBill Taylor 		 * InfiniBand interfaces will be enabled).
5939e39c5baSBill Taylor 		 */
5949e39c5baSBill Taylor 		status = hermon_drv_init(state, dip, instance);
5959e39c5baSBill Taylor 		if ((status != DDI_SUCCESS) &&
5969e39c5baSBill Taylor 		    (HERMON_IS_OPERATIONAL(state->hs_operational_mode))) {
5979e39c5baSBill Taylor 			goto fail_attach;
5989e39c5baSBill Taylor 		}
5999e39c5baSBill Taylor 
6009e39c5baSBill Taylor 		/*
6019e39c5baSBill Taylor 		 * Change the Hermon FM mode
6029e39c5baSBill Taylor 		 */
6039e39c5baSBill Taylor 		if ((hermon_get_state(state) & HCA_PIO_FM) &&
6049e39c5baSBill Taylor 		    HERMON_IS_OPERATIONAL(state->hs_operational_mode)) {
6059e39c5baSBill Taylor 			/*
6069e39c5baSBill Taylor 			 * Now we wait for 50ms to give an opportunity
6079e39c5baSBill Taylor 			 * to Solaris FMA so that HW errors can be notified.
6089e39c5baSBill Taylor 			 * Then check if there are HW errors or not. If
6099e39c5baSBill Taylor 			 * a HW error is detected, the Hermon attachment
6109e39c5baSBill Taylor 			 * must be failed.
6119e39c5baSBill Taylor 			 */
6129e39c5baSBill Taylor 			delay(drv_usectohz(50000));
6139e39c5baSBill Taylor 			if (hermon_init_failure(state)) {
6149e39c5baSBill Taylor 				hermon_drv_fini(state);
6159e39c5baSBill Taylor 				HERMON_WARNING(state, "unable to "
6169e39c5baSBill Taylor 				    "attach Hermon due to a HW error");
6179e39c5baSBill Taylor 				HERMON_ATTACH_MSG(state->hs_attach_buf,
6189e39c5baSBill Taylor 				    "hermon_attach_failure");
6199e39c5baSBill Taylor 				goto fail_attach;
6209e39c5baSBill Taylor 			}
6219e39c5baSBill Taylor 
6229e39c5baSBill Taylor 			/*
6239e39c5baSBill Taylor 			 * There seems no HW errors during the attachment,
6249e39c5baSBill Taylor 			 * so let's change the Hermon FM state to the
6259e39c5baSBill Taylor 			 * ereport only mode.
6269e39c5baSBill Taylor 			 */
6279e39c5baSBill Taylor 			if (hermon_fm_ereport_init(state) != DDI_SUCCESS) {
6289e39c5baSBill Taylor 				/* unwind the resources */
6299e39c5baSBill Taylor 				hermon_drv_fini(state);
6309e39c5baSBill Taylor 				HERMON_ATTACH_MSG(state->hs_attach_buf,
6319e39c5baSBill Taylor 				    "hermon_attach_failure");
6329e39c5baSBill Taylor 				goto fail_attach;
6339e39c5baSBill Taylor 			}
6349e39c5baSBill Taylor 		}
6359e39c5baSBill Taylor 
6369e39c5baSBill Taylor 		/* Create the minor node for device */
6379e39c5baSBill Taylor 		status = ddi_create_minor_node(dip, "devctl", S_IFCHR, instance,
6389e39c5baSBill Taylor 		    DDI_PSEUDO, 0);
6399e39c5baSBill Taylor 		if (status != DDI_SUCCESS) {
6409e39c5baSBill Taylor 			hermon_drv_fini(state);
6419e39c5baSBill Taylor 			HERMON_ATTACH_MSG(state->hs_attach_buf,
6429e39c5baSBill Taylor 			    "attach_create_mn_fail");
6439e39c5baSBill Taylor 			goto fail_attach;
6449e39c5baSBill Taylor 		}
6459e39c5baSBill Taylor 
6469e39c5baSBill Taylor 		/*
6479e39c5baSBill Taylor 		 * If we are in "maintenance mode", then we don't want to
6489e39c5baSBill Taylor 		 * register with the IBTF.  All InfiniBand interfaces are
6499e39c5baSBill Taylor 		 * uninitialized, and the device is only capable of handling
6509e39c5baSBill Taylor 		 * requests to update/flash firmware (or test/debug requests).
6519e39c5baSBill Taylor 		 */
6529e39c5baSBill Taylor 		if (HERMON_IS_OPERATIONAL(state->hs_operational_mode)) {
6539e39c5baSBill Taylor 			cmn_err(CE_NOTE, "!Hermon is operational\n");
6549e39c5baSBill Taylor 
6559e39c5baSBill Taylor 			/* Attach to InfiniBand Transport Framework (IBTF) */
6569e39c5baSBill Taylor 			ibc_status = ibc_attach(&tmp_ibtfpriv,
6579e39c5baSBill Taylor 			    &state->hs_ibtfinfo);
6589e39c5baSBill Taylor 			if (ibc_status != IBC_SUCCESS) {
6599e39c5baSBill Taylor 				cmn_err(CE_CONT, "hermon_attach: ibc_attach "
6609e39c5baSBill Taylor 				    "failed\n");
6619e39c5baSBill Taylor 				ddi_remove_minor_node(dip, "devctl");
6629e39c5baSBill Taylor 				hermon_drv_fini(state);
6639e39c5baSBill Taylor 				HERMON_ATTACH_MSG(state->hs_attach_buf,
6649e39c5baSBill Taylor 				    "attach_ibcattach_fail");
6659e39c5baSBill Taylor 				goto fail_attach;
6669e39c5baSBill Taylor 			}
6679e39c5baSBill Taylor 
6689e39c5baSBill Taylor 			/*
6699e39c5baSBill Taylor 			 * Now that we've successfully attached to the IBTF,
6709e39c5baSBill Taylor 			 * we enable all appropriate asynch and CQ events to
6719e39c5baSBill Taylor 			 * be forwarded to the IBTF.
6729e39c5baSBill Taylor 			 */
6739e39c5baSBill Taylor 			HERMON_ENABLE_IBTF_CALLB(state, tmp_ibtfpriv);
6749e39c5baSBill Taylor 
6759e39c5baSBill Taylor 			ibc_post_attach(state->hs_ibtfpriv);
6769e39c5baSBill Taylor 
6779e39c5baSBill Taylor 			/* Register agents with IB Mgmt Framework (IBMF) */
6789e39c5baSBill Taylor 			status = hermon_agent_handlers_init(state);
6799e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
6809e39c5baSBill Taylor 				(void) ibc_pre_detach(tmp_ibtfpriv, DDI_DETACH);
6819e39c5baSBill Taylor 				HERMON_QUIESCE_IBTF_CALLB(state);
6829e39c5baSBill Taylor 				if (state->hs_in_evcallb != 0) {
6839e39c5baSBill Taylor 					HERMON_WARNING(state, "unable to "
6849e39c5baSBill Taylor 					    "quiesce Hermon IBTF callbacks");
6859e39c5baSBill Taylor 				}
6869e39c5baSBill Taylor 				ibc_detach(tmp_ibtfpriv);
6879e39c5baSBill Taylor 				ddi_remove_minor_node(dip, "devctl");
6889e39c5baSBill Taylor 				hermon_drv_fini(state);
6899e39c5baSBill Taylor 				HERMON_ATTACH_MSG(state->hs_attach_buf,
6909e39c5baSBill Taylor 				    "attach_agentinit_fail");
6919e39c5baSBill Taylor 				goto fail_attach;
6929e39c5baSBill Taylor 			}
6939e39c5baSBill Taylor 		}
6949e39c5baSBill Taylor 
6959e39c5baSBill Taylor 		/* Report attach in maintenance mode, if appropriate */
6969e39c5baSBill Taylor 		if (!(HERMON_IS_OPERATIONAL(state->hs_operational_mode))) {
6979e39c5baSBill Taylor 			cmn_err(CE_NOTE, "hermon%d: driver attached "
6989e39c5baSBill Taylor 			    "(for maintenance mode only)", state->hs_instance);
6999e39c5baSBill Taylor 			hermon_fm_ereport(state, HCA_IBA_ERR, HCA_ERR_DEGRADED);
7009e39c5baSBill Taylor 		}
7019e39c5baSBill Taylor 
7029e39c5baSBill Taylor 		/* Report that driver was loaded */
7039e39c5baSBill Taylor 		ddi_report_dev(dip);
7049e39c5baSBill Taylor 
7059e39c5baSBill Taylor 		/* Send device information to log file */
7069e39c5baSBill Taylor 		hermon_device_info_report(state);
7079e39c5baSBill Taylor 
7089e39c5baSBill Taylor 		/* DEBUG PRINT */
7099e39c5baSBill Taylor 		cmn_err(CE_CONT, "!Hermon attach complete\n");
7109e39c5baSBill Taylor 		return (DDI_SUCCESS);
7119e39c5baSBill Taylor 
7129e39c5baSBill Taylor 	case DDI_RESUME:
7139e39c5baSBill Taylor 		/* Add code here for DDI_RESUME XXX */
7149e39c5baSBill Taylor 		return (DDI_FAILURE);
7159e39c5baSBill Taylor 
7169e39c5baSBill Taylor 	default:
7179e39c5baSBill Taylor 		cmn_err(CE_WARN, "hermon_attach: unknown cmd (0x%x)\n", cmd);
7189e39c5baSBill Taylor 		break;
7199e39c5baSBill Taylor 	}
7209e39c5baSBill Taylor 
7219e39c5baSBill Taylor fail_attach:
7229e39c5baSBill Taylor 	cmn_err(CE_NOTE, "hermon%d: driver failed to attach: %s", instance,
7239e39c5baSBill Taylor 	    state->hs_attach_buf);
7249e39c5baSBill Taylor 	if (hermon_get_state(state) & HCA_EREPORT_FM) {
7259e39c5baSBill Taylor 		hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
7269e39c5baSBill Taylor 	}
727e9935355SEiji Ota 	hermon_drv_fini2(state);
7289e39c5baSBill Taylor 	hermon_fm_fini(state);
7299e39c5baSBill Taylor 	ddi_soft_state_free(hermon_statep, instance);
7309e39c5baSBill Taylor 
7319e39c5baSBill Taylor fail_attach_nomsg:
7329e39c5baSBill Taylor 	return (DDI_FAILURE);
7339e39c5baSBill Taylor }
7349e39c5baSBill Taylor 
7359e39c5baSBill Taylor 
7369e39c5baSBill Taylor /*
7379e39c5baSBill Taylor  * hermon_detach()
7389e39c5baSBill Taylor  *    Context: Only called from detach() path context
7399e39c5baSBill Taylor  */
7409e39c5baSBill Taylor static int
hermon_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)7419e39c5baSBill Taylor hermon_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
7429e39c5baSBill Taylor {
7439e39c5baSBill Taylor 	hermon_state_t	*state;
7449e39c5baSBill Taylor 	ibc_clnt_hdl_t	tmp_ibtfpriv;
7459e39c5baSBill Taylor 	ibc_status_t	ibc_status;
7469e39c5baSBill Taylor 	int		instance, status;
7479e39c5baSBill Taylor 
7489e39c5baSBill Taylor 	instance = ddi_get_instance(dip);
7499e39c5baSBill Taylor 	state = ddi_get_soft_state(hermon_statep, instance);
7509e39c5baSBill Taylor 	if (state == NULL) {
7519e39c5baSBill Taylor 		return (DDI_FAILURE);
7529e39c5baSBill Taylor 	}
7539e39c5baSBill Taylor 
7549e39c5baSBill Taylor 	switch (cmd) {
7559e39c5baSBill Taylor 	case DDI_DETACH:
7569e39c5baSBill Taylor 		/*
7579e39c5baSBill Taylor 		 * If we are in "maintenance mode", then we do not want to
7589e39c5baSBill Taylor 		 * do teardown for any of the InfiniBand interfaces.
7599e39c5baSBill Taylor 		 * Specifically, this means not detaching from IBTF (we never
7609e39c5baSBill Taylor 		 * attached to begin with) and not deregistering from IBMF.
7619e39c5baSBill Taylor 		 */
7629e39c5baSBill Taylor 		if (HERMON_IS_OPERATIONAL(state->hs_operational_mode)) {
7639e39c5baSBill Taylor 			/* Unregister agents from IB Mgmt Framework (IBMF) */
7649e39c5baSBill Taylor 			status = hermon_agent_handlers_fini(state);
7659e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
7669e39c5baSBill Taylor 				return (DDI_FAILURE);
7679e39c5baSBill Taylor 			}
7689e39c5baSBill Taylor 
7699e39c5baSBill Taylor 			/*
7709e39c5baSBill Taylor 			 * Attempt the "pre-detach" from InfiniBand Transport
7719e39c5baSBill Taylor 			 * Framework (IBTF).  At this point the IBTF is still
7729e39c5baSBill Taylor 			 * capable of handling incoming asynch and completion
7739e39c5baSBill Taylor 			 * events.  This "pre-detach" is primarily a mechanism
7749e39c5baSBill Taylor 			 * to notify the appropriate IBTF clients that the
7759e39c5baSBill Taylor 			 * HCA is being removed/offlined.
7769e39c5baSBill Taylor 			 */
7779e39c5baSBill Taylor 			ibc_status = ibc_pre_detach(state->hs_ibtfpriv, cmd);
7789e39c5baSBill Taylor 			if (ibc_status != IBC_SUCCESS) {
7799e39c5baSBill Taylor 				status = hermon_agent_handlers_init(state);
7809e39c5baSBill Taylor 				if (status != DDI_SUCCESS) {
7819e39c5baSBill Taylor 					HERMON_WARNING(state, "failed to "
7829e39c5baSBill Taylor 					    "restart Hermon agents");
7839e39c5baSBill Taylor 				}
7849e39c5baSBill Taylor 				return (DDI_FAILURE);
7859e39c5baSBill Taylor 			}
7869e39c5baSBill Taylor 
7879e39c5baSBill Taylor 			/*
7889e39c5baSBill Taylor 			 * Before we can fully detach from the IBTF we need to
7899e39c5baSBill Taylor 			 * ensure that we have handled all outstanding event
7909e39c5baSBill Taylor 			 * callbacks.  This is accomplished by quiescing the
7919e39c5baSBill Taylor 			 * event callback mechanism.  Note: if we are unable
7929e39c5baSBill Taylor 			 * to successfully quiesce the callbacks, then this is
7939e39c5baSBill Taylor 			 * an indication that something has probably gone
7949e39c5baSBill Taylor 			 * seriously wrong.  We print out a warning, but
7959e39c5baSBill Taylor 			 * continue.
7969e39c5baSBill Taylor 			 */
7979e39c5baSBill Taylor 			tmp_ibtfpriv = state->hs_ibtfpriv;
7989e39c5baSBill Taylor 			HERMON_QUIESCE_IBTF_CALLB(state);
7999e39c5baSBill Taylor 			if (state->hs_in_evcallb != 0) {
8009e39c5baSBill Taylor 				HERMON_WARNING(state, "unable to quiesce "
8019e39c5baSBill Taylor 				    "Hermon IBTF callbacks");
8029e39c5baSBill Taylor 			}
8039e39c5baSBill Taylor 
8049e39c5baSBill Taylor 			/* Complete the detach from the IBTF */
8059e39c5baSBill Taylor 			ibc_detach(tmp_ibtfpriv);
8069e39c5baSBill Taylor 		}
8079e39c5baSBill Taylor 
8089e39c5baSBill Taylor 		/* Remove the minor node for device */
8099e39c5baSBill Taylor 		ddi_remove_minor_node(dip, "devctl");
8109e39c5baSBill Taylor 
8119e39c5baSBill Taylor 		/*
8129e39c5baSBill Taylor 		 * Only call hermon_drv_fini() if we are in Hermon HCA mode.
8139e39c5baSBill Taylor 		 * (Because if we are in "maintenance mode", then we never
8149e39c5baSBill Taylor 		 * successfully finished init.)  Only report successful
8159e39c5baSBill Taylor 		 * detach for normal HCA mode.
8169e39c5baSBill Taylor 		 */
8179e39c5baSBill Taylor 		if (HERMON_IS_OPERATIONAL(state->hs_operational_mode)) {
8189e39c5baSBill Taylor 			/* Cleanup driver resources and shutdown hardware */
8199e39c5baSBill Taylor 			hermon_drv_fini(state);
8209e39c5baSBill Taylor 			cmn_err(CE_CONT, "!Hermon driver successfully "
8219e39c5baSBill Taylor 			    "detached\n");
8229e39c5baSBill Taylor 		}
8239e39c5baSBill Taylor 
8249e39c5baSBill Taylor 		hermon_drv_fini2(state);
8259e39c5baSBill Taylor 		hermon_fm_fini(state);
8269e39c5baSBill Taylor 		ddi_soft_state_free(hermon_statep, instance);
8279e39c5baSBill Taylor 
8289e39c5baSBill Taylor 		return (DDI_SUCCESS);
8299e39c5baSBill Taylor 
8309e39c5baSBill Taylor 	case DDI_SUSPEND:
8319e39c5baSBill Taylor 		/* Add code here for DDI_SUSPEND XXX */
8329e39c5baSBill Taylor 		return (DDI_FAILURE);
8339e39c5baSBill Taylor 
8349e39c5baSBill Taylor 	default:
8359e39c5baSBill Taylor 		cmn_err(CE_WARN, "hermon_detach: unknown cmd (0x%x)\n", cmd);
8369e39c5baSBill Taylor 		break;
8379e39c5baSBill Taylor 	}
8389e39c5baSBill Taylor 
8399e39c5baSBill Taylor 	return (DDI_FAILURE);
8409e39c5baSBill Taylor }
8419e39c5baSBill Taylor 
8429e39c5baSBill Taylor /*
8439e39c5baSBill Taylor  * hermon_dma_attr_init()
8449e39c5baSBill Taylor  *    Context: Can be called from interrupt or base context.
8459e39c5baSBill Taylor  */
8469e39c5baSBill Taylor 
8479e39c5baSBill Taylor /* ARGSUSED */
8489e39c5baSBill Taylor void
hermon_dma_attr_init(hermon_state_t * state,ddi_dma_attr_t * dma_attr)8499e39c5baSBill Taylor hermon_dma_attr_init(hermon_state_t *state, ddi_dma_attr_t *dma_attr)
8509e39c5baSBill Taylor {
8519e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dma_attr))
8529e39c5baSBill Taylor 
8539e39c5baSBill Taylor 	dma_attr->dma_attr_version	= DMA_ATTR_V0;
8549e39c5baSBill Taylor 	dma_attr->dma_attr_addr_lo	= 0;
8559e39c5baSBill Taylor 	dma_attr->dma_attr_addr_hi	= 0xFFFFFFFFFFFFFFFFull;
8569e39c5baSBill Taylor 	dma_attr->dma_attr_count_max	= 0xFFFFFFFFFFFFFFFFull;
8579e39c5baSBill Taylor 	dma_attr->dma_attr_align	= HERMON_PAGESIZE;  /* default 4K */
8589e39c5baSBill Taylor 	dma_attr->dma_attr_burstsizes	= 0x3FF;
8599e39c5baSBill Taylor 	dma_attr->dma_attr_minxfer	= 1;
8609e39c5baSBill Taylor 	dma_attr->dma_attr_maxxfer	= 0xFFFFFFFFFFFFFFFFull;
8619e39c5baSBill Taylor 	dma_attr->dma_attr_seg		= 0xFFFFFFFFFFFFFFFFull;
8629e39c5baSBill Taylor 	dma_attr->dma_attr_sgllen	= 0x7FFFFFFF;
8639e39c5baSBill Taylor 	dma_attr->dma_attr_granular	= 1;
8649e39c5baSBill Taylor 	dma_attr->dma_attr_flags	= 0;
8659e39c5baSBill Taylor }
8669e39c5baSBill Taylor 
8679e39c5baSBill Taylor /*
8689e39c5baSBill Taylor  * hermon_dma_alloc()
8699e39c5baSBill Taylor  *    Context: Can be called from base context.
8709e39c5baSBill Taylor  */
8719e39c5baSBill Taylor int
hermon_dma_alloc(hermon_state_t * state,hermon_dma_info_t * dma_info,uint16_t opcode)8729e39c5baSBill Taylor hermon_dma_alloc(hermon_state_t *state, hermon_dma_info_t *dma_info,
8739e39c5baSBill Taylor     uint16_t opcode)
8749e39c5baSBill Taylor {
8759e39c5baSBill Taylor 	ddi_dma_handle_t	dma_hdl;
8769e39c5baSBill Taylor 	ddi_dma_attr_t		dma_attr;
8779e39c5baSBill Taylor 	ddi_acc_handle_t	acc_hdl;
8789e39c5baSBill Taylor 	ddi_dma_cookie_t	cookie;
8799e39c5baSBill Taylor 	uint64_t		kaddr;
8809e39c5baSBill Taylor 	uint64_t		real_len;
8819e39c5baSBill Taylor 	uint_t			ccount;
8829e39c5baSBill Taylor 	int			status;
8839e39c5baSBill Taylor 
8849e39c5baSBill Taylor 	hermon_dma_attr_init(state, &dma_attr);
885c7facc54SBill Taylor #ifdef	__sparc
886c7facc54SBill Taylor 	if (state->hs_cfg_profile->cp_iommu_bypass == HERMON_BINDMEM_BYPASS)
887c7facc54SBill Taylor 		dma_attr.dma_attr_flags = DDI_DMA_FORCE_PHYSICAL;
888c7facc54SBill Taylor #endif
8899e39c5baSBill Taylor 
8909e39c5baSBill Taylor 	/* Allocate a DMA handle */
8919e39c5baSBill Taylor 	status = ddi_dma_alloc_handle(state->hs_dip, &dma_attr, DDI_DMA_SLEEP,
8929e39c5baSBill Taylor 	    NULL, &dma_hdl);
8939e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
8949e39c5baSBill Taylor 		IBTF_DPRINTF_L2("DMA", "alloc handle failed: %d", status);
8959e39c5baSBill Taylor 		cmn_err(CE_CONT, "DMA alloc handle failed(status %d)", status);
8969e39c5baSBill Taylor 		return (DDI_FAILURE);
8979e39c5baSBill Taylor 	}
8989e39c5baSBill Taylor 
8999e39c5baSBill Taylor 	/* Allocate DMA memory */
9009e39c5baSBill Taylor 	status = ddi_dma_mem_alloc(dma_hdl, dma_info->length,
9019e39c5baSBill Taylor 	    &state->hs_reg_accattr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
9029e39c5baSBill Taylor 	    (caddr_t *)&kaddr, (size_t *)&real_len, &acc_hdl);
9039e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
9049e39c5baSBill Taylor 		ddi_dma_free_handle(&dma_hdl);
9059e39c5baSBill Taylor 		IBTF_DPRINTF_L2("DMA", "memory alloc failed: %d", status);
9069e39c5baSBill Taylor 		cmn_err(CE_CONT, "DMA memory alloc failed(status %d)", status);
9079e39c5baSBill Taylor 		return (DDI_FAILURE);
9089e39c5baSBill Taylor 	}
9099e39c5baSBill Taylor 	bzero((caddr_t)(uintptr_t)kaddr, real_len);
9109e39c5baSBill Taylor 
9119e39c5baSBill Taylor 	/* Bind the memory to the handle */
9129e39c5baSBill Taylor 	status = ddi_dma_addr_bind_handle(dma_hdl, NULL,
9139e39c5baSBill Taylor 	    (caddr_t)(uintptr_t)kaddr, (size_t)real_len, DDI_DMA_RDWR |
9149e39c5baSBill Taylor 	    DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &cookie, &ccount);
9159e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
9169e39c5baSBill Taylor 		ddi_dma_mem_free(&acc_hdl);
9179e39c5baSBill Taylor 		ddi_dma_free_handle(&dma_hdl);
9189e39c5baSBill Taylor 		IBTF_DPRINTF_L2("DMA", "bind handle failed: %d", status);
9199e39c5baSBill Taylor 		cmn_err(CE_CONT, "DMA bind handle failed(status %d)", status);
9209e39c5baSBill Taylor 		return (DDI_FAILURE);
9219e39c5baSBill Taylor 	}
9229e39c5baSBill Taylor 
9239e39c5baSBill Taylor 	/* Package the hermon_dma_info contents and return */
9249e39c5baSBill Taylor 	dma_info->vaddr   = kaddr;
9259e39c5baSBill Taylor 	dma_info->dma_hdl = dma_hdl;
9269e39c5baSBill Taylor 	dma_info->acc_hdl = acc_hdl;
9279e39c5baSBill Taylor 
9289e39c5baSBill Taylor 	/* Pass the mapping information to the firmware */
9299e39c5baSBill Taylor 	status = hermon_map_cmd_post(state, dma_info, opcode, cookie, ccount);
9309e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
9319e39c5baSBill Taylor 		char *s;
9329e39c5baSBill Taylor 		hermon_dma_free(dma_info);
9339e39c5baSBill Taylor 		switch (opcode) {
9349e39c5baSBill Taylor 		case MAP_ICM:
9359e39c5baSBill Taylor 			s = "MAP_ICM";
9369e39c5baSBill Taylor 			break;
9379e39c5baSBill Taylor 		case MAP_FA:
9389e39c5baSBill Taylor 			s = "MAP_FA";
9399e39c5baSBill Taylor 			break;
9409e39c5baSBill Taylor 		case MAP_ICM_AUX:
9419e39c5baSBill Taylor 			s = "MAP_ICM_AUX";
9429e39c5baSBill Taylor 			break;
9439e39c5baSBill Taylor 		default:
9449e39c5baSBill Taylor 			s = "UNKNOWN";
9459e39c5baSBill Taylor 		}
9469e39c5baSBill Taylor 		cmn_err(CE_NOTE, "Map cmd '%s' failed, status %08x\n",
9479e39c5baSBill Taylor 		    s, status);
9489e39c5baSBill Taylor 		return (DDI_FAILURE);
9499e39c5baSBill Taylor 	}
9509e39c5baSBill Taylor 
9519e39c5baSBill Taylor 	return (DDI_SUCCESS);
9529e39c5baSBill Taylor }
9539e39c5baSBill Taylor 
9549e39c5baSBill Taylor /*
9559e39c5baSBill Taylor  * hermon_dma_free()
9569e39c5baSBill Taylor  *    Context: Can be called from base context.
9579e39c5baSBill Taylor  */
9589e39c5baSBill Taylor void
hermon_dma_free(hermon_dma_info_t * info)9599e39c5baSBill Taylor hermon_dma_free(hermon_dma_info_t *info)
9609e39c5baSBill Taylor {
9619e39c5baSBill Taylor 	/* Unbind the handles and free the memory */
9629e39c5baSBill Taylor 	(void) ddi_dma_unbind_handle(info->dma_hdl);
9639e39c5baSBill Taylor 	ddi_dma_mem_free(&info->acc_hdl);
9649e39c5baSBill Taylor 	ddi_dma_free_handle(&info->dma_hdl);
9659e39c5baSBill Taylor }
9669e39c5baSBill Taylor 
9679e39c5baSBill Taylor /* These macros are valid for use only in hermon_icm_alloc/hermon_icm_free. */
9689e39c5baSBill Taylor #define	HERMON_ICM_ALLOC(rsrc) \
9699e39c5baSBill Taylor 	hermon_icm_alloc(state, rsrc, index1, index2)
9709e39c5baSBill Taylor #define	HERMON_ICM_FREE(rsrc) \
9719e39c5baSBill Taylor 	hermon_icm_free(state, rsrc, index1, index2)
9729e39c5baSBill Taylor 
9739e39c5baSBill Taylor /*
9749e39c5baSBill Taylor  * hermon_icm_alloc()
9759e39c5baSBill Taylor  *    Context: Can be called from base context.
9769e39c5baSBill Taylor  *
9779e39c5baSBill Taylor  * Only one thread can be here for a given hermon_rsrc_type_t "type".
97817a2b317SBill Taylor  *
97917a2b317SBill Taylor  * "num_to_hdl" is set if there is a need for lookups from resource
98017a2b317SBill Taylor  * number/index to resource handle.  This is needed for QPs/CQs/SRQs
98117a2b317SBill Taylor  * for the various affiliated events/errors.
9829e39c5baSBill Taylor  */
9839e39c5baSBill Taylor int
hermon_icm_alloc(hermon_state_t * state,hermon_rsrc_type_t type,uint32_t index1,uint32_t index2)9849e39c5baSBill Taylor hermon_icm_alloc(hermon_state_t *state, hermon_rsrc_type_t type,
9859e39c5baSBill Taylor     uint32_t index1, uint32_t index2)
9869e39c5baSBill Taylor {
9879e39c5baSBill Taylor 	hermon_icm_table_t	*icm;
9889e39c5baSBill Taylor 	hermon_dma_info_t	*dma_info;
9899e39c5baSBill Taylor 	uint8_t			*bitmap;
9909e39c5baSBill Taylor 	int			status;
99117a2b317SBill Taylor 	int			num_to_hdl = 0;
9929e39c5baSBill Taylor 
9939e39c5baSBill Taylor 	if (hermon_verbose) {
9949e39c5baSBill Taylor 		IBTF_DPRINTF_L2("hermon", "hermon_icm_alloc: rsrc_type (0x%x) "
9959e39c5baSBill Taylor 		    "index1/2 (0x%x/0x%x)", type, index1, index2);
9969e39c5baSBill Taylor 	}
9979e39c5baSBill Taylor 
9989e39c5baSBill Taylor 	icm = &state->hs_icm[type];
9999e39c5baSBill Taylor 
10009e39c5baSBill Taylor 	switch (type) {
10019e39c5baSBill Taylor 	case HERMON_QPC:
10029e39c5baSBill Taylor 		status = HERMON_ICM_ALLOC(HERMON_CMPT_QPC);
10039e39c5baSBill Taylor 		if (status != DDI_SUCCESS) {
10049e39c5baSBill Taylor 			return (status);
10059e39c5baSBill Taylor 		}
10069e39c5baSBill Taylor 		status = HERMON_ICM_ALLOC(HERMON_RDB);
10079e39c5baSBill Taylor 		if (status != DDI_SUCCESS) {	/* undo icm_alloc's */
10089e39c5baSBill Taylor 			HERMON_ICM_FREE(HERMON_CMPT_QPC);
10099e39c5baSBill Taylor 			return (status);
10109e39c5baSBill Taylor 		}
10119e39c5baSBill Taylor 		status = HERMON_ICM_ALLOC(HERMON_ALTC);
10129e39c5baSBill Taylor 		if (status != DDI_SUCCESS) {	/* undo icm_alloc's */
10139e39c5baSBill Taylor 			HERMON_ICM_FREE(HERMON_RDB);
10149e39c5baSBill Taylor 			HERMON_ICM_FREE(HERMON_CMPT_QPC);
10159e39c5baSBill Taylor 			return (status);
10169e39c5baSBill Taylor 		}
10179e39c5baSBill Taylor 		status = HERMON_ICM_ALLOC(HERMON_AUXC);
10189e39c5baSBill Taylor 		if (status != DDI_SUCCESS) {	/* undo icm_alloc's */
10199e39c5baSBill Taylor 			HERMON_ICM_FREE(HERMON_ALTC);
10209e39c5baSBill Taylor 			HERMON_ICM_FREE(HERMON_RDB);
10219e39c5baSBill Taylor 			HERMON_ICM_FREE(HERMON_CMPT_QPC);
10229e39c5baSBill Taylor 			return (status);
10239e39c5baSBill Taylor 		}
102417a2b317SBill Taylor 		num_to_hdl = 1;
10259e39c5baSBill Taylor 		break;
10269e39c5baSBill Taylor 	case HERMON_SRQC:
10279e39c5baSBill Taylor 		status = HERMON_ICM_ALLOC(HERMON_CMPT_SRQC);
10289e39c5baSBill Taylor 		if (status != DDI_SUCCESS) {
10299e39c5baSBill Taylor 			return (status);
10309e39c5baSBill Taylor 		}
103117a2b317SBill Taylor 		num_to_hdl = 1;
10329e39c5baSBill Taylor 		break;
10339e39c5baSBill Taylor 	case HERMON_CQC:
10349e39c5baSBill Taylor 		status = HERMON_ICM_ALLOC(HERMON_CMPT_CQC);
10359e39c5baSBill Taylor 		if (status != DDI_SUCCESS) {
10369e39c5baSBill Taylor 			return (status);
10379e39c5baSBill Taylor 		}
103817a2b317SBill Taylor 		num_to_hdl = 1;
10399e39c5baSBill Taylor 		break;
10409e39c5baSBill Taylor 	case HERMON_EQC:
10419e39c5baSBill Taylor 		status = HERMON_ICM_ALLOC(HERMON_CMPT_EQC);
10429e39c5baSBill Taylor 		if (status != DDI_SUCCESS) {	/* undo icm_alloc's */
10439e39c5baSBill Taylor 			return (status);
10449e39c5baSBill Taylor 		}
10459e39c5baSBill Taylor 		break;
10469e39c5baSBill Taylor 	}
10479e39c5baSBill Taylor 
10489e39c5baSBill Taylor 	/* ensure existence of bitmap and dmainfo, sets "dma_info" */
104917a2b317SBill Taylor 	hermon_bitmap(bitmap, dma_info, icm, index1, num_to_hdl);
10509e39c5baSBill Taylor 
10519e39c5baSBill Taylor 	/* Set up the DMA handle for allocation and mapping */
105217a2b317SBill Taylor 	dma_info += index2;
10539e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dma_info))
10549e39c5baSBill Taylor 	dma_info->length  = icm->span << icm->log_object_size;
10559e39c5baSBill Taylor 	dma_info->icmaddr = icm->icm_baseaddr +
10569e39c5baSBill Taylor 	    (((index1 << icm->split_shift) +
10579e39c5baSBill Taylor 	    (index2 << icm->span_shift)) << icm->log_object_size);
10589e39c5baSBill Taylor 
105917a2b317SBill Taylor 	/* Allocate memory for the num_to_qp/cq/srq pointers */
106017a2b317SBill Taylor 	if (num_to_hdl)
106117a2b317SBill Taylor 		icm->num_to_hdl[index1][index2] =
106217a2b317SBill Taylor 		    kmem_zalloc(HERMON_ICM_SPAN * sizeof (void *), KM_SLEEP);
106317a2b317SBill Taylor 
10649e39c5baSBill Taylor 	if (hermon_verbose) {
10659e39c5baSBill Taylor 		IBTF_DPRINTF_L2("hermon", "alloc DMA: "
10669e39c5baSBill Taylor 		    "rsrc (0x%x) index (%x, %x) "
10679e39c5baSBill Taylor 		    "icm_addr/len (%llx/%x) bitmap %p", type, index1, index2,
10689e39c5baSBill Taylor 		    (longlong_t)dma_info->icmaddr, dma_info->length, bitmap);
10699e39c5baSBill Taylor 	}
10709e39c5baSBill Taylor 
10719e39c5baSBill Taylor 	/* Allocate and map memory for this span */
10729e39c5baSBill Taylor 	status = hermon_dma_alloc(state, dma_info, MAP_ICM);
10739e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
10749e39c5baSBill Taylor 		IBTF_DPRINTF_L2("hermon", "hermon_icm_alloc: DMA "
10759e39c5baSBill Taylor 		    "allocation failed, status 0x%x", status);
10769e39c5baSBill Taylor 		switch (type) {
10779e39c5baSBill Taylor 		case HERMON_QPC:
10789e39c5baSBill Taylor 			HERMON_ICM_FREE(HERMON_AUXC);
10799e39c5baSBill Taylor 			HERMON_ICM_FREE(HERMON_ALTC);
10809e39c5baSBill Taylor 			HERMON_ICM_FREE(HERMON_RDB);
10819e39c5baSBill Taylor 			HERMON_ICM_FREE(HERMON_CMPT_QPC);
10829e39c5baSBill Taylor 			break;
10839e39c5baSBill Taylor 		case HERMON_SRQC:
10849e39c5baSBill Taylor 			HERMON_ICM_FREE(HERMON_CMPT_SRQC);
10859e39c5baSBill Taylor 			break;
10869e39c5baSBill Taylor 		case HERMON_CQC:
10879e39c5baSBill Taylor 			HERMON_ICM_FREE(HERMON_CMPT_CQC);
10889e39c5baSBill Taylor 			break;
10899e39c5baSBill Taylor 		case HERMON_EQC:
10909e39c5baSBill Taylor 			HERMON_ICM_FREE(HERMON_CMPT_EQC);
10919e39c5baSBill Taylor 			break;
10929e39c5baSBill Taylor 		}
10939e39c5baSBill Taylor 
10949e39c5baSBill Taylor 		return (DDI_FAILURE);
10959e39c5baSBill Taylor 	}
10969e39c5baSBill Taylor 	if (hermon_verbose) {
10979e39c5baSBill Taylor 		IBTF_DPRINTF_L2("hermon", "hermon_icm_alloc: mapping ICM: "
10989e39c5baSBill Taylor 		    "rsrc_type (0x%x) index (0x%x, 0x%x) alloc length (0x%x) "
10999e39c5baSBill Taylor 		    "icm_addr (0x%lx)", type, index1, index2, dma_info->length,
11009e39c5baSBill Taylor 		    dma_info->icmaddr);
11019e39c5baSBill Taylor 	}
11029e39c5baSBill Taylor 
11039e39c5baSBill Taylor 	/* Set the bit for this slot in the table bitmap */
11049e39c5baSBill Taylor 	HERMON_BMAP_BIT_SET(icm->icm_bitmap[index1], index2);
11059e39c5baSBill Taylor 
11069e39c5baSBill Taylor 	return (DDI_SUCCESS);
11079e39c5baSBill Taylor }
11089e39c5baSBill Taylor 
11099e39c5baSBill Taylor /*
11109e39c5baSBill Taylor  * hermon_icm_free()
11119e39c5baSBill Taylor  *    Context: Can be called from base context.
11129e39c5baSBill Taylor  *
11139e39c5baSBill Taylor  * ICM resources have been successfully returned from hermon_icm_alloc().
11149e39c5baSBill Taylor  * Associated dma_info is no longer in use.  Free the ICM backing memory.
11159e39c5baSBill Taylor  */
11169e39c5baSBill Taylor void
hermon_icm_free(hermon_state_t * state,hermon_rsrc_type_t type,uint32_t index1,uint32_t index2)11179e39c5baSBill Taylor hermon_icm_free(hermon_state_t *state, hermon_rsrc_type_t type,
11189e39c5baSBill Taylor     uint32_t index1, uint32_t index2)
11199e39c5baSBill Taylor {
11209e39c5baSBill Taylor 	hermon_icm_table_t	*icm;
11219e39c5baSBill Taylor 	hermon_dma_info_t	*dma_info;
11229e39c5baSBill Taylor 	int			status;
11239e39c5baSBill Taylor 
11249e39c5baSBill Taylor 	icm = &state->hs_icm[type];
11259e39c5baSBill Taylor 	ASSERT(icm->icm_dma[index1][index2].icm_refcnt == 0);
11269e39c5baSBill Taylor 
11279e39c5baSBill Taylor 	if (hermon_verbose) {
11289e39c5baSBill Taylor 		IBTF_DPRINTF_L2("hermon", "hermon_icm_free: rsrc_type (0x%x) "
11299e39c5baSBill Taylor 		    "index (0x%x, 0x%x)", type, index1, index2);
11309e39c5baSBill Taylor 	}
11319e39c5baSBill Taylor 
11329e39c5baSBill Taylor 	dma_info = icm->icm_dma[index1] + index2;
11339e39c5baSBill Taylor 
11349e39c5baSBill Taylor 	/* The following only happens if attach() is failing. */
11359e39c5baSBill Taylor 	if (dma_info == NULL)
11369e39c5baSBill Taylor 		return;
11379e39c5baSBill Taylor 
11389e39c5baSBill Taylor 	/* Unmap the ICM allocation, then free the backing DMA memory */
11399e39c5baSBill Taylor 	status = hermon_unmap_icm_cmd_post(state, dma_info);
11409e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
11419e39c5baSBill Taylor 		HERMON_WARNING(state, "UNMAP_ICM failure");
11429e39c5baSBill Taylor 	}
11439e39c5baSBill Taylor 	hermon_dma_free(dma_info);
11449e39c5baSBill Taylor 
11459e39c5baSBill Taylor 	/* Clear the bit in the ICM table bitmap */
11469e39c5baSBill Taylor 	HERMON_BMAP_BIT_CLR(icm->icm_bitmap[index1], index2);
11479e39c5baSBill Taylor 
11489e39c5baSBill Taylor 	switch (type) {
11499e39c5baSBill Taylor 	case HERMON_QPC:
11509e39c5baSBill Taylor 		HERMON_ICM_FREE(HERMON_AUXC);
11519e39c5baSBill Taylor 		HERMON_ICM_FREE(HERMON_ALTC);
11529e39c5baSBill Taylor 		HERMON_ICM_FREE(HERMON_RDB);
11539e39c5baSBill Taylor 		HERMON_ICM_FREE(HERMON_CMPT_QPC);
11549e39c5baSBill Taylor 		break;
11559e39c5baSBill Taylor 	case HERMON_SRQC:
11569e39c5baSBill Taylor 		HERMON_ICM_FREE(HERMON_CMPT_SRQC);
11579e39c5baSBill Taylor 		break;
11589e39c5baSBill Taylor 	case HERMON_CQC:
11599e39c5baSBill Taylor 		HERMON_ICM_FREE(HERMON_CMPT_CQC);
11609e39c5baSBill Taylor 		break;
11619e39c5baSBill Taylor 	case HERMON_EQC:
11629e39c5baSBill Taylor 		HERMON_ICM_FREE(HERMON_CMPT_EQC);
11639e39c5baSBill Taylor 		break;
11649e39c5baSBill Taylor 
11659e39c5baSBill Taylor 	}
11669e39c5baSBill Taylor }
11679e39c5baSBill Taylor 
116813cc0a0bSBill Taylor 
116917a2b317SBill Taylor /*
117017a2b317SBill Taylor  * hermon_icm_num_to_hdl()
117117a2b317SBill Taylor  *    Context: Can be called from base or interrupt context.
117217a2b317SBill Taylor  *
117317a2b317SBill Taylor  * Given an index of a resource, index through the sparsely allocated
117417a2b317SBill Taylor  * arrays to find the pointer to its software handle.  Return NULL if
117517a2b317SBill Taylor  * any of the arrays of pointers has been freed (should never happen).
117617a2b317SBill Taylor  */
117717a2b317SBill Taylor void *
hermon_icm_num_to_hdl(hermon_state_t * state,hermon_rsrc_type_t type,uint32_t idx)117817a2b317SBill Taylor hermon_icm_num_to_hdl(hermon_state_t *state, hermon_rsrc_type_t type,
117917a2b317SBill Taylor     uint32_t idx)
118017a2b317SBill Taylor {
118117a2b317SBill Taylor 	hermon_icm_table_t	*icm;
118217a2b317SBill Taylor 	uint32_t		span_offset;
118317a2b317SBill Taylor 	uint32_t		index1, index2;
118417a2b317SBill Taylor 	void			***p1, **p2;
118517a2b317SBill Taylor 
118617a2b317SBill Taylor 	icm = &state->hs_icm[type];
118717a2b317SBill Taylor 	hermon_index(index1, index2, idx, icm, span_offset);
118817a2b317SBill Taylor 	p1 = icm->num_to_hdl[index1];
118917a2b317SBill Taylor 	if (p1 == NULL) {
119017a2b317SBill Taylor 		IBTF_DPRINTF_L2("hermon", "icm_num_to_hdl failed at level 1"
119117a2b317SBill Taylor 		    ": rsrc_type %d, index 0x%x", type, idx);
119217a2b317SBill Taylor 		return (NULL);
119317a2b317SBill Taylor 	}
119417a2b317SBill Taylor 	p2 = p1[index2];
119517a2b317SBill Taylor 	if (p2 == NULL) {
119617a2b317SBill Taylor 		IBTF_DPRINTF_L2("hermon", "icm_num_to_hdl failed at level 2"
119717a2b317SBill Taylor 		    ": rsrc_type %d, index 0x%x", type, idx);
119817a2b317SBill Taylor 		return (NULL);
119917a2b317SBill Taylor 	}
120017a2b317SBill Taylor 	return (p2[span_offset]);
120117a2b317SBill Taylor }
120217a2b317SBill Taylor 
120317a2b317SBill Taylor /*
120417a2b317SBill Taylor  * hermon_icm_set_num_to_hdl()
120517a2b317SBill Taylor  *    Context: Can be called from base or interrupt context.
120617a2b317SBill Taylor  *
120717a2b317SBill Taylor  * Given an index of a resource, we index through the sparsely allocated
120817a2b317SBill Taylor  * arrays to store the software handle, used by hermon_icm_num_to_hdl().
120917a2b317SBill Taylor  * This function is used to both set and reset (set to NULL) the handle.
121017a2b317SBill Taylor  * This table is allocated during ICM allocation for the given resource,
121117a2b317SBill Taylor  * so its existence is a given, and the store location does not conflict
121217a2b317SBill Taylor  * with any other stores to the table (no locking needed).
121317a2b317SBill Taylor  */
121417a2b317SBill Taylor void
hermon_icm_set_num_to_hdl(hermon_state_t * state,hermon_rsrc_type_t type,uint32_t idx,void * hdl)121517a2b317SBill Taylor hermon_icm_set_num_to_hdl(hermon_state_t *state, hermon_rsrc_type_t type,
121617a2b317SBill Taylor     uint32_t idx, void *hdl)
121717a2b317SBill Taylor {
121817a2b317SBill Taylor 	hermon_icm_table_t	*icm;
121917a2b317SBill Taylor 	uint32_t		span_offset;
122017a2b317SBill Taylor 	uint32_t		index1, index2;
122117a2b317SBill Taylor 
122217a2b317SBill Taylor 	icm = &state->hs_icm[type];
122317a2b317SBill Taylor 	hermon_index(index1, index2, idx, icm, span_offset);
122417a2b317SBill Taylor 	ASSERT((hdl == NULL) ^
122517a2b317SBill Taylor 	    (icm->num_to_hdl[index1][index2][span_offset] == NULL));
122617a2b317SBill Taylor 	icm->num_to_hdl[index1][index2][span_offset] = hdl;
122717a2b317SBill Taylor }
122817a2b317SBill Taylor 
122913cc0a0bSBill Taylor /*
123013cc0a0bSBill Taylor  * hermon_device_mode()
123113cc0a0bSBill Taylor  *    Context: Can be called from base or interrupt context.
123213cc0a0bSBill Taylor  *
123313cc0a0bSBill Taylor  * Return HERMON_HCA_MODE for operational mode
123413cc0a0bSBill Taylor  * Return HERMON_MAINTENANCE_MODE for maintenance mode
123513cc0a0bSBill Taylor  * Return 0 otherwise
123613cc0a0bSBill Taylor  *
123713cc0a0bSBill Taylor  * A non-zero return for either operational or maintenance mode simplifies
123813cc0a0bSBill Taylor  * one of the 2 uses of this function.
123913cc0a0bSBill Taylor  */
124013cc0a0bSBill Taylor int
hermon_device_mode(hermon_state_t * state)124113cc0a0bSBill Taylor hermon_device_mode(hermon_state_t *state)
124213cc0a0bSBill Taylor {
124313cc0a0bSBill Taylor 	if (state->hs_vendor_id != PCI_VENID_MLX)
124413cc0a0bSBill Taylor 		return (0);
124513cc0a0bSBill Taylor 
124613cc0a0bSBill Taylor 	switch (state->hs_device_id) {
124713cc0a0bSBill Taylor 	case PCI_DEVID_HERMON_SDR:
124813cc0a0bSBill Taylor 	case PCI_DEVID_HERMON_DDR:
124913cc0a0bSBill Taylor 	case PCI_DEVID_HERMON_DDRG2:
125013cc0a0bSBill Taylor 	case PCI_DEVID_HERMON_QDRG2:
125113cc0a0bSBill Taylor 	case PCI_DEVID_HERMON_QDRG2V:
125213cc0a0bSBill Taylor 		return (HERMON_HCA_MODE);
125313cc0a0bSBill Taylor 	case PCI_DEVID_HERMON_MAINT:
125413cc0a0bSBill Taylor 		return (HERMON_MAINTENANCE_MODE);
125513cc0a0bSBill Taylor 	default:
125613cc0a0bSBill Taylor 		return (0);
125713cc0a0bSBill Taylor 	}
125813cc0a0bSBill Taylor }
125913cc0a0bSBill Taylor 
12609e39c5baSBill Taylor /*
12619e39c5baSBill Taylor  * hermon_drv_init()
12629e39c5baSBill Taylor  *    Context: Only called from attach() path context
12639e39c5baSBill Taylor  */
12649e39c5baSBill Taylor /* ARGSUSED */
12659e39c5baSBill Taylor static int
hermon_drv_init(hermon_state_t * state,dev_info_t * dip,int instance)12669e39c5baSBill Taylor hermon_drv_init(hermon_state_t *state, dev_info_t *dip, int instance)
12679e39c5baSBill Taylor {
12689e39c5baSBill Taylor 	int	status;
12699e39c5baSBill Taylor 
127013cc0a0bSBill Taylor 	/* Retrieve PCI device, vendor and rev IDs */
127113cc0a0bSBill Taylor 	state->hs_vendor_id	 = HERMON_GET_VENDOR_ID(state->hs_dip);
127213cc0a0bSBill Taylor 	state->hs_device_id	 = HERMON_GET_DEVICE_ID(state->hs_dip);
127313cc0a0bSBill Taylor 	state->hs_revision_id	 = HERMON_GET_REVISION_ID(state->hs_dip);
127413cc0a0bSBill Taylor 
12759e39c5baSBill Taylor 	/*
12769e39c5baSBill Taylor 	 * Check and set the operational mode of the device. If the driver is
12779e39c5baSBill Taylor 	 * bound to the Hermon device in "maintenance mode", then this generally
12789e39c5baSBill Taylor 	 * means that either the device has been specifically jumpered to
12799e39c5baSBill Taylor 	 * start in this mode or the firmware boot process has failed to
12809e39c5baSBill Taylor 	 * successfully load either the primary or the secondary firmware
12819e39c5baSBill Taylor 	 * image.
12829e39c5baSBill Taylor 	 */
128313cc0a0bSBill Taylor 	state->hs_operational_mode = hermon_device_mode(state);
128413cc0a0bSBill Taylor 	switch (state->hs_operational_mode) {
128513cc0a0bSBill Taylor 	case HERMON_HCA_MODE:
12869e39c5baSBill Taylor 		state->hs_cfg_profile_setting = HERMON_CFG_MEMFREE;
128713cc0a0bSBill Taylor 		break;
128813cc0a0bSBill Taylor 	case HERMON_MAINTENANCE_MODE:
12899e39c5baSBill Taylor 		HERMON_FMANOTE(state, HERMON_FMA_MAINT);
129032c5adfdSEiji Ota 		state->hs_fm_degraded_reason = HCA_FW_MISC; /* not fw reason */
12919e39c5baSBill Taylor 		return (DDI_FAILURE);
129213cc0a0bSBill Taylor 	default:
12939e39c5baSBill Taylor 		HERMON_FMANOTE(state, HERMON_FMA_PCIID);
12949e39c5baSBill Taylor 		HERMON_WARNING(state, "unexpected device type detected");
12959e39c5baSBill Taylor 		return (DDI_FAILURE);
12969e39c5baSBill Taylor 	}
12979e39c5baSBill Taylor 
12989e39c5baSBill Taylor 	/*
12999e39c5baSBill Taylor 	 * Initialize the Hermon hardware.
13009e39c5baSBill Taylor 	 *
13019e39c5baSBill Taylor 	 * Note:  If this routine returns an error, it is often a reasonably
13029e39c5baSBill Taylor 	 * good indication that something Hermon firmware-related has caused
13039e39c5baSBill Taylor 	 * the failure or some HW related errors have caused the failure.
13049e39c5baSBill Taylor 	 * (also there are few possibilities that SW (e.g. SW resource
13059e39c5baSBill Taylor 	 * shortage) can cause the failure, but the majority case is due to
13069e39c5baSBill Taylor 	 * either a firmware related error or a HW related one) In order to
13079e39c5baSBill Taylor 	 * give the user an opportunity (if desired) to update or reflash
13089e39c5baSBill Taylor 	 * the Hermon firmware image, we set "hs_operational_mode" flag
13099e39c5baSBill Taylor 	 * (described above) to indicate that we wish to enter maintenance
13109e39c5baSBill Taylor 	 * mode in case of the firmware-related issue.
13119e39c5baSBill Taylor 	 */
13129e39c5baSBill Taylor 	status = hermon_hw_init(state);
13139e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
13149e39c5baSBill Taylor 		cmn_err(CE_NOTE, "hermon%d: error during attach: %s", instance,
13159e39c5baSBill Taylor 		    state->hs_attach_buf);
13169e39c5baSBill Taylor 		return (DDI_FAILURE);
13179e39c5baSBill Taylor 	}
13189e39c5baSBill Taylor 
13199e39c5baSBill Taylor 	/*
13209e39c5baSBill Taylor 	 * Now that the ISR has been setup, arm all the EQs for event
13219e39c5baSBill Taylor 	 * generation.
13229e39c5baSBill Taylor 	 */
13239e39c5baSBill Taylor 
13249e39c5baSBill Taylor 	status = hermon_eq_arm_all(state);
13259e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
13269e39c5baSBill Taylor 		cmn_err(CE_NOTE, "EQ Arm All failed\n");
13279e39c5baSBill Taylor 		hermon_hw_fini(state, HERMON_DRV_CLEANUP_ALL);
13289e39c5baSBill Taylor 		return (DDI_FAILURE);
13299e39c5baSBill Taylor 	}
13309e39c5baSBill Taylor 
13319e39c5baSBill Taylor 	/* test interrupts and event queues */
13329e39c5baSBill Taylor 	status = hermon_nop_post(state, 0x0, 0x0);
13339e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
13349e39c5baSBill Taylor 		cmn_err(CE_NOTE, "Interrupts/EQs failed\n");
13359e39c5baSBill Taylor 		hermon_hw_fini(state, HERMON_DRV_CLEANUP_ALL);
13369e39c5baSBill Taylor 		return (DDI_FAILURE);
13379e39c5baSBill Taylor 	}
13389e39c5baSBill Taylor 
13399e39c5baSBill Taylor 	/* Initialize Hermon softstate */
13409e39c5baSBill Taylor 	status = hermon_soft_state_init(state);
13419e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
13429e39c5baSBill Taylor 		cmn_err(CE_NOTE, "Failed to init soft state\n");
13439e39c5baSBill Taylor 		hermon_hw_fini(state, HERMON_DRV_CLEANUP_ALL);
13449e39c5baSBill Taylor 		return (DDI_FAILURE);
13459e39c5baSBill Taylor 	}
13469e39c5baSBill Taylor 
13479e39c5baSBill Taylor 	return (DDI_SUCCESS);
13489e39c5baSBill Taylor }
13499e39c5baSBill Taylor 
13509e39c5baSBill Taylor 
13519e39c5baSBill Taylor /*
13529e39c5baSBill Taylor  * hermon_drv_fini()
13539e39c5baSBill Taylor  *    Context: Only called from attach() and/or detach() path contexts
13549e39c5baSBill Taylor  */
13559e39c5baSBill Taylor static void
hermon_drv_fini(hermon_state_t * state)13569e39c5baSBill Taylor hermon_drv_fini(hermon_state_t *state)
13579e39c5baSBill Taylor {
13589e39c5baSBill Taylor 	/* Cleanup Hermon softstate */
13599e39c5baSBill Taylor 	hermon_soft_state_fini(state);
13609e39c5baSBill Taylor 
13619e39c5baSBill Taylor 	/* Cleanup Hermon resources and shutdown hardware */
13629e39c5baSBill Taylor 	hermon_hw_fini(state, HERMON_DRV_CLEANUP_ALL);
13639e39c5baSBill Taylor }
13649e39c5baSBill Taylor 
13659e39c5baSBill Taylor 
13669e39c5baSBill Taylor /*
13679e39c5baSBill Taylor  * hermon_drv_fini2()
1368e9935355SEiji Ota  *    Context: Only called from attach() and/or detach() path contexts
13699e39c5baSBill Taylor  */
13709e39c5baSBill Taylor static void
hermon_drv_fini2(hermon_state_t * state)13719e39c5baSBill Taylor hermon_drv_fini2(hermon_state_t *state)
13729e39c5baSBill Taylor {
13739e39c5baSBill Taylor 	if (state->hs_fm_poll_thread) {
13749e39c5baSBill Taylor 		ddi_periodic_delete(state->hs_fm_poll_thread);
13759e39c5baSBill Taylor 		state->hs_fm_poll_thread = NULL;
13769e39c5baSBill Taylor 	}
1377e9935355SEiji Ota 
1378e9935355SEiji Ota 	/* HERMON_DRV_CLEANUP_LEVEL1 */
13799e39c5baSBill Taylor 	if (state->hs_fm_cmdhdl) {
13809e39c5baSBill Taylor 		hermon_regs_map_free(state, &state->hs_fm_cmdhdl);
13819e39c5baSBill Taylor 		state->hs_fm_cmdhdl = NULL;
13829e39c5baSBill Taylor 	}
1383e9935355SEiji Ota 
13849e39c5baSBill Taylor 	if (state->hs_reg_cmdhdl) {
13859e39c5baSBill Taylor 		ddi_regs_map_free(&state->hs_reg_cmdhdl);
13869e39c5baSBill Taylor 		state->hs_reg_cmdhdl = NULL;
13879e39c5baSBill Taylor 	}
1388e9935355SEiji Ota 
1389e9935355SEiji Ota 	/* HERMON_DRV_CLEANUP_LEVEL0 */
1390e9935355SEiji Ota 	if (state->hs_msix_tbl_entries) {
1391e9935355SEiji Ota 		kmem_free(state->hs_msix_tbl_entries,
1392e9935355SEiji Ota 		    state->hs_msix_tbl_size);
1393e9935355SEiji Ota 		state->hs_msix_tbl_entries = NULL;
1394e9935355SEiji Ota 	}
1395e9935355SEiji Ota 
1396e9935355SEiji Ota 	if (state->hs_msix_pba_entries) {
1397e9935355SEiji Ota 		kmem_free(state->hs_msix_pba_entries,
1398e9935355SEiji Ota 		    state->hs_msix_pba_size);
1399e9935355SEiji Ota 		state->hs_msix_pba_entries = NULL;
1400e9935355SEiji Ota 	}
1401e9935355SEiji Ota 
1402e9935355SEiji Ota 	if (state->hs_fm_msix_tblhdl) {
1403e9935355SEiji Ota 		hermon_regs_map_free(state, &state->hs_fm_msix_tblhdl);
1404e9935355SEiji Ota 		state->hs_fm_msix_tblhdl = NULL;
1405e9935355SEiji Ota 	}
1406e9935355SEiji Ota 
1407e9935355SEiji Ota 	if (state->hs_reg_msix_tblhdl) {
1408e9935355SEiji Ota 		ddi_regs_map_free(&state->hs_reg_msix_tblhdl);
1409e9935355SEiji Ota 		state->hs_reg_msix_tblhdl = NULL;
1410e9935355SEiji Ota 	}
1411e9935355SEiji Ota 
1412e9935355SEiji Ota 	if (state->hs_fm_msix_pbahdl) {
1413e9935355SEiji Ota 		hermon_regs_map_free(state, &state->hs_fm_msix_pbahdl);
1414e9935355SEiji Ota 		state->hs_fm_msix_pbahdl = NULL;
1415e9935355SEiji Ota 	}
1416e9935355SEiji Ota 
1417e9935355SEiji Ota 	if (state->hs_reg_msix_pbahdl) {
1418e9935355SEiji Ota 		ddi_regs_map_free(&state->hs_reg_msix_pbahdl);
1419e9935355SEiji Ota 		state->hs_reg_msix_pbahdl = NULL;
1420e9935355SEiji Ota 	}
1421e9935355SEiji Ota 
1422e9935355SEiji Ota 	if (state->hs_fm_pcihdl) {
1423e9935355SEiji Ota 		hermon_pci_config_teardown(state, &state->hs_fm_pcihdl);
1424e9935355SEiji Ota 		state->hs_fm_pcihdl = NULL;
1425e9935355SEiji Ota 	}
1426e9935355SEiji Ota 
1427e9935355SEiji Ota 	if (state->hs_reg_pcihdl) {
1428e9935355SEiji Ota 		pci_config_teardown(&state->hs_reg_pcihdl);
1429e9935355SEiji Ota 		state->hs_reg_pcihdl = NULL;
1430e9935355SEiji Ota 	}
14319e39c5baSBill Taylor }
14329e39c5baSBill Taylor 
14339e39c5baSBill Taylor 
14349e39c5baSBill Taylor /*
14359e39c5baSBill Taylor  * hermon_isr_init()
14369e39c5baSBill Taylor  *    Context: Only called from attach() path context
14379e39c5baSBill Taylor  */
14389e39c5baSBill Taylor static int
hermon_isr_init(hermon_state_t * state)14399e39c5baSBill Taylor hermon_isr_init(hermon_state_t *state)
14409e39c5baSBill Taylor {
14419e39c5baSBill Taylor 	int	status;
14429e39c5baSBill Taylor 	int	intr;
14439e39c5baSBill Taylor 
14449e39c5baSBill Taylor 	for (intr = 0; intr < state->hs_intrmsi_allocd; intr++) {
14459e39c5baSBill Taylor 
14469e39c5baSBill Taylor 		/*
14479e39c5baSBill Taylor 		 * Add a handler for the interrupt or MSI
14489e39c5baSBill Taylor 		 */
14499e39c5baSBill Taylor 		status = ddi_intr_add_handler(state->hs_intrmsi_hdl[intr],
14509e39c5baSBill Taylor 		    hermon_isr, (caddr_t)state, (void *)(uintptr_t)intr);
14519e39c5baSBill Taylor 		if (status  != DDI_SUCCESS) {
14529e39c5baSBill Taylor 			return (DDI_FAILURE);
14539e39c5baSBill Taylor 		}
14549e39c5baSBill Taylor 
14559e39c5baSBill Taylor 		/*
14569e39c5baSBill Taylor 		 * Enable the software interrupt.  Note: depending on the value
14579e39c5baSBill Taylor 		 * returned in the capability flag, we have to call either
14589e39c5baSBill Taylor 		 * ddi_intr_block_enable() or ddi_intr_enable().
14599e39c5baSBill Taylor 		 */
14609e39c5baSBill Taylor 		if (state->hs_intrmsi_cap & DDI_INTR_FLAG_BLOCK) {
14619e39c5baSBill Taylor 			status = ddi_intr_block_enable(
14629e39c5baSBill Taylor 			    &state->hs_intrmsi_hdl[intr], 1);
14639e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
14649e39c5baSBill Taylor 				return (DDI_FAILURE);
14659e39c5baSBill Taylor 			}
14669e39c5baSBill Taylor 		} else {
14679e39c5baSBill Taylor 			status = ddi_intr_enable(state->hs_intrmsi_hdl[intr]);
14689e39c5baSBill Taylor 			if (status != DDI_SUCCESS) {
14699e39c5baSBill Taylor 				return (DDI_FAILURE);
14709e39c5baSBill Taylor 			}
14719e39c5baSBill Taylor 		}
14729e39c5baSBill Taylor 	}
14739e39c5baSBill Taylor 
14749e39c5baSBill Taylor 	/*
14759e39c5baSBill Taylor 	 * Now that the ISR has been enabled, defer arm_all  EQs for event
14769e39c5baSBill Taylor 	 * generation until later, in case MSIX is enabled
14779e39c5baSBill Taylor 	 */
14789e39c5baSBill Taylor 	return (DDI_SUCCESS);
14799e39c5baSBill Taylor }
14809e39c5baSBill Taylor 
14819e39c5baSBill Taylor 
14829e39c5baSBill Taylor /*
14839e39c5baSBill Taylor  * hermon_isr_fini()
14849e39c5baSBill Taylor  *    Context: Only called from attach() and/or detach() path contexts
14859e39c5baSBill Taylor  */
14869e39c5baSBill Taylor static void
hermon_isr_fini(hermon_state_t * state)14879e39c5baSBill Taylor hermon_isr_fini(hermon_state_t *state)
14889e39c5baSBill Taylor {
14899e39c5baSBill Taylor 	int	intr;
14909e39c5baSBill Taylor 
14919e39c5baSBill Taylor 	for (intr = 0; intr < state->hs_intrmsi_allocd; intr++) {
14929e39c5baSBill Taylor 		/* Disable the software interrupt */
14939e39c5baSBill Taylor 		if (state->hs_intrmsi_cap & DDI_INTR_FLAG_BLOCK) {
14949e39c5baSBill Taylor 			(void) ddi_intr_block_disable(
14959e39c5baSBill Taylor 			    &state->hs_intrmsi_hdl[intr], 1);
14969e39c5baSBill Taylor 		} else {
14979e39c5baSBill Taylor 			(void) ddi_intr_disable(state->hs_intrmsi_hdl[intr]);
14989e39c5baSBill Taylor 		}
14999e39c5baSBill Taylor 
15009e39c5baSBill Taylor 		/*
15019e39c5baSBill Taylor 		 * Remove the software handler for the interrupt or MSI
15029e39c5baSBill Taylor 		 */
15039e39c5baSBill Taylor 		(void) ddi_intr_remove_handler(state->hs_intrmsi_hdl[intr]);
15049e39c5baSBill Taylor 	}
15059e39c5baSBill Taylor }
15069e39c5baSBill Taylor 
15079e39c5baSBill Taylor 
15089e39c5baSBill Taylor /*
15099e39c5baSBill Taylor  * Sum of ICM configured values:
15109e39c5baSBill Taylor  *     cMPT, dMPT, MTT, QPC, SRQC, RDB, CQC, ALTC, AUXC, EQC, MCG
15119e39c5baSBill Taylor  *
15129e39c5baSBill Taylor  */
15139e39c5baSBill Taylor static uint64_t
hermon_size_icm(hermon_state_t * state)15149e39c5baSBill Taylor hermon_size_icm(hermon_state_t *state)
15159e39c5baSBill Taylor {
15169e39c5baSBill Taylor 	hermon_hw_querydevlim_t	*devlim;
15179e39c5baSBill Taylor 	hermon_cfg_profile_t	*cfg;
15189e39c5baSBill Taylor 	uint64_t		num_cmpts, num_dmpts, num_mtts;
15199e39c5baSBill Taylor 	uint64_t		num_qpcs, num_srqc, num_rdbs;
15209e39c5baSBill Taylor #ifndef HERMON_FW_WORKAROUND
15219e39c5baSBill Taylor 	uint64_t		num_auxc;
15229e39c5baSBill Taylor #endif
15239e39c5baSBill Taylor 	uint64_t		num_cqcs, num_altc;
15249e39c5baSBill Taylor 	uint64_t		num_eqcs, num_mcgs;
15259e39c5baSBill Taylor 	uint64_t		size;
15269e39c5baSBill Taylor 
15279e39c5baSBill Taylor 	devlim = &state->hs_devlim;
15289e39c5baSBill Taylor 	cfg = state->hs_cfg_profile;
15299e39c5baSBill Taylor 	/* number of respective entries */
15309e39c5baSBill Taylor 	num_cmpts = (uint64_t)0x1 << cfg->cp_log_num_cmpt;
15319e39c5baSBill Taylor 	num_mtts = (uint64_t)0x1 << cfg->cp_log_num_mtt;
15329e39c5baSBill Taylor 	num_dmpts = (uint64_t)0x1 << cfg->cp_log_num_dmpt;
15339e39c5baSBill Taylor 	num_qpcs = (uint64_t)0x1 << cfg->cp_log_num_qp;
15349e39c5baSBill Taylor 	num_srqc = (uint64_t)0x1 << cfg->cp_log_num_srq;
15359e39c5baSBill Taylor 	num_rdbs = (uint64_t)0x1 << cfg->cp_log_num_rdb;
15369e39c5baSBill Taylor 	num_cqcs = (uint64_t)0x1 << cfg->cp_log_num_cq;
15379e39c5baSBill Taylor 	num_altc = (uint64_t)0x1 << cfg->cp_log_num_qp;
15389e39c5baSBill Taylor #ifndef HERMON_FW_WORKAROUND
15399e39c5baSBill Taylor 	num_auxc = (uint64_t)0x1 << cfg->cp_log_num_qp;
15409e39c5baSBill Taylor #endif
15419e39c5baSBill Taylor 	num_eqcs = (uint64_t)0x1 << cfg->cp_log_num_eq;
15429e39c5baSBill Taylor 	num_mcgs = (uint64_t)0x1 << cfg->cp_log_num_mcg;
15439e39c5baSBill Taylor 
15449e39c5baSBill Taylor 	size =
1545*0b63ccafSToomas Soome 	    num_cmpts	* devlim->cmpt_entry_sz +
15469e39c5baSBill Taylor 	    num_dmpts	* devlim->dmpt_entry_sz +
15479e39c5baSBill Taylor 	    num_mtts	* devlim->mtt_entry_sz +
15489e39c5baSBill Taylor 	    num_qpcs	* devlim->qpc_entry_sz +
15499e39c5baSBill Taylor 	    num_srqc	* devlim->srq_entry_sz +
15509e39c5baSBill Taylor 	    num_rdbs	* devlim->rdmardc_entry_sz +
15519e39c5baSBill Taylor 	    num_cqcs	* devlim->cqc_entry_sz +
15529e39c5baSBill Taylor 	    num_altc	* devlim->altc_entry_sz +
15539e39c5baSBill Taylor #ifdef HERMON_FW_WORKAROUND
15549e39c5baSBill Taylor 	    0x80000000ull +
15559e39c5baSBill Taylor #else
15569e39c5baSBill Taylor 	    num_auxc	* devlim->aux_entry_sz	+
15579e39c5baSBill Taylor #endif
15589e39c5baSBill Taylor 	    num_eqcs	* devlim->eqc_entry_sz +
15599e39c5baSBill Taylor 	    num_mcgs	* HERMON_MCGMEM_SZ(state);
15609e39c5baSBill Taylor 	return (size);
15619e39c5baSBill Taylor }
15629e39c5baSBill Taylor 
15639e39c5baSBill Taylor 
15649e39c5baSBill Taylor /*
15659e39c5baSBill Taylor  * hermon_hw_init()
15669e39c5baSBill Taylor  *    Context: Only called from attach() path context
15679e39c5baSBill Taylor  */
15689e39c5baSBill Taylor static int
hermon_hw_init(hermon_state_t * state)15699e39c5baSBill Taylor hermon_hw_init(hermon_state_t *state)
15709e39c5baSBill Taylor {
15719e39c5baSBill Taylor 	hermon_drv_cleanup_level_t	cleanup;
15729e39c5baSBill Taylor 	sm_nodeinfo_t			nodeinfo;
15739e39c5baSBill Taylor 	uint64_t			clr_intr_offset;
15749e39c5baSBill Taylor 	int				status;
15759e39c5baSBill Taylor 	uint32_t			fw_size;	/* in page */
15769e39c5baSBill Taylor 	uint64_t			offset;
15779e39c5baSBill Taylor 
15789e39c5baSBill Taylor 	/* This is where driver initialization begins */
15799e39c5baSBill Taylor 	cleanup = HERMON_DRV_CLEANUP_LEVEL0;
15809e39c5baSBill Taylor 
15819e39c5baSBill Taylor 	/* Setup device access attributes */
1582837c1ac4SStephen Hanson 	state->hs_reg_accattr.devacc_attr_version = DDI_DEVICE_ATTR_V1;
15839e39c5baSBill Taylor 	state->hs_reg_accattr.devacc_attr_endian_flags = DDI_STRUCTURE_BE_ACC;
15849e39c5baSBill Taylor 	state->hs_reg_accattr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
15859e39c5baSBill Taylor 	state->hs_reg_accattr.devacc_attr_access = DDI_DEFAULT_ACC;
15869e39c5baSBill Taylor 
15879e39c5baSBill Taylor 	/* Setup fma-protected access attributes */
15889e39c5baSBill Taylor 	state->hs_fm_accattr.devacc_attr_version =
15899e39c5baSBill Taylor 	    hermon_devacc_attr_version(state);
15909e39c5baSBill Taylor 	state->hs_fm_accattr.devacc_attr_endian_flags = DDI_STRUCTURE_BE_ACC;
15919e39c5baSBill Taylor 	state->hs_fm_accattr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
15929e39c5baSBill Taylor 	/* set acc err protection type */
15939e39c5baSBill Taylor 	state->hs_fm_accattr.devacc_attr_access =
15949e39c5baSBill Taylor 	    hermon_devacc_attr_access(state);
15959e39c5baSBill Taylor 
15969e39c5baSBill Taylor 	/* Setup for PCI config read/write of HCA device */
15979e39c5baSBill Taylor 	status = hermon_pci_config_setup(state, &state->hs_fm_pcihdl);
15989e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
15999e39c5baSBill Taylor 		hermon_hw_fini(state, cleanup);
16009e39c5baSBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf,
16019e39c5baSBill Taylor 		    "hw_init_PCI_config_space_regmap_fail");
16029e39c5baSBill Taylor 		/* This case is not the degraded one */
16039e39c5baSBill Taylor 		return (DDI_FAILURE);
16049e39c5baSBill Taylor 	}
16059e39c5baSBill Taylor 
16069e39c5baSBill Taylor 	/* Map PCI config space and MSI-X tables/pba */
16079e39c5baSBill Taylor 	hermon_set_msix_info(state);
16089e39c5baSBill Taylor 
16099e39c5baSBill Taylor 	/* Map in Hermon registers (CMD, UAR, MSIX) and setup offsets */
16109e39c5baSBill Taylor 	status = hermon_regs_map_setup(state, HERMON_CMD_BAR,
16119e39c5baSBill Taylor 	    &state->hs_reg_cmd_baseaddr, 0, 0, &state->hs_fm_accattr,
16129e39c5baSBill Taylor 	    &state->hs_fm_cmdhdl);
16139e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
16149e39c5baSBill Taylor 		hermon_hw_fini(state, cleanup);
16159e39c5baSBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf,
16169e39c5baSBill Taylor 		    "hw_init_CMD_BAR_regmap_fail");
16179e39c5baSBill Taylor 		/* This case is not the degraded one */
16189e39c5baSBill Taylor 		return (DDI_FAILURE);
16199e39c5baSBill Taylor 	}
16209e39c5baSBill Taylor 
16219e39c5baSBill Taylor 	cleanup = HERMON_DRV_CLEANUP_LEVEL1;
16229e39c5baSBill Taylor 	/*
16239e39c5baSBill Taylor 	 * We defer UAR-BAR mapping until later.  Need to know if
16249e39c5baSBill Taylor 	 * blueflame mapping is to be done, and don't know that until after
16259e39c5baSBill Taylor 	 * we get the dev_caps, so do it right after that
16269e39c5baSBill Taylor 	 */
16279e39c5baSBill Taylor 
16289e39c5baSBill Taylor 	/*
16299e39c5baSBill Taylor 	 * There is a third BAR defined for Hermon - it is for MSIX
16309e39c5baSBill Taylor 	 *
16319e39c5baSBill Taylor 	 * Will need to explore it's possible need/use w/ Mellanox
16329e39c5baSBill Taylor 	 * [es] Temporary mapping maybe
16339e39c5baSBill Taylor 	 */
16349e39c5baSBill Taylor 
16359e39c5baSBill Taylor #ifdef HERMON_SUPPORTS_MSIX_BAR
16369e39c5baSBill Taylor 	status = ddi_regs_map_setup(state->hs_dip, HERMON_MSIX_BAR,
16379e39c5baSBill Taylor 	    &state->hs_reg_msi_baseaddr, 0, 0, &state->hs_reg_accattr,
16389e39c5baSBill Taylor 	    &state->hs_reg_msihdl);
16399e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
16409e39c5baSBill Taylor 		hermon_hw_fini(state, cleanup);
16419e39c5baSBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf,
16429e39c5baSBill Taylor 		    "hw_init_MSIX_BAR_regmap_fail");
16439e39c5baSBill Taylor 		/* This case is not the degraded one */
16449e39c5baSBill Taylor 		return (DDI_FAILURE);
16459e39c5baSBill Taylor 	}
16469e39c5baSBill Taylor #endif
16479e39c5baSBill Taylor 
16489e39c5baSBill Taylor 	cleanup = HERMON_DRV_CLEANUP_LEVEL2;
16499e39c5baSBill Taylor 
16509e39c5baSBill Taylor 	/*
16519e39c5baSBill Taylor 	 * Save interesting registers away. The offsets of the first two
16529e39c5baSBill Taylor 	 * here (HCR and sw_reset) are detailed in the PRM, the others are
16539e39c5baSBill Taylor 	 * derived from values in the QUERY_FW output, so we'll save them
16549e39c5baSBill Taylor 	 * off later.
16559e39c5baSBill Taylor 	 */
16569e39c5baSBill Taylor 	/* Host Command Register (HCR) */
16579e39c5baSBill Taylor 	state->hs_cmd_regs.hcr = (hermon_hw_hcr_t *)
16589e39c5baSBill Taylor 	    ((uintptr_t)state->hs_reg_cmd_baseaddr + HERMON_CMD_HCR_OFFSET);
16599e39c5baSBill Taylor 	state->hs_cmd_toggle = 0;	/* initialize it for use */
16609e39c5baSBill Taylor 
16619e39c5baSBill Taylor 	/* Software Reset register (sw_reset) and semaphore */
16629e39c5baSBill Taylor 	state->hs_cmd_regs.sw_reset = (uint32_t *)
16639e39c5baSBill Taylor 	    ((uintptr_t)state->hs_reg_cmd_baseaddr +
16649e39c5baSBill Taylor 	    HERMON_CMD_SW_RESET_OFFSET);
16659e39c5baSBill Taylor 	state->hs_cmd_regs.sw_semaphore = (uint32_t *)
16669e39c5baSBill Taylor 	    ((uintptr_t)state->hs_reg_cmd_baseaddr +
16679e39c5baSBill Taylor 	    HERMON_CMD_SW_SEMAPHORE_OFFSET);
16689e39c5baSBill Taylor 
16699e39c5baSBill Taylor 	/* make sure init'd before we start filling things in */
16709e39c5baSBill Taylor 	bzero(&state->hs_hcaparams, sizeof (struct hermon_hw_initqueryhca_s));
16719e39c5baSBill Taylor 
16729e39c5baSBill Taylor 	/* Initialize the Phase1 configuration profile */
16739e39c5baSBill Taylor 	status = hermon_cfg_profile_init_phase1(state);
16749e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
16759e39c5baSBill Taylor 		hermon_hw_fini(state, cleanup);
16769e39c5baSBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf,
16779e39c5baSBill Taylor 		    "hw_init_cfginit1_fail");
16789e39c5baSBill Taylor 		/* This case is not the degraded one */
16799e39c5baSBill Taylor 		return (DDI_FAILURE);
16809e39c5baSBill Taylor 	}
16819e39c5baSBill Taylor 	cleanup = HERMON_DRV_CLEANUP_LEVEL3;
16829e39c5baSBill Taylor 
16839e39c5baSBill Taylor 	/* Do a software reset of the adapter to ensure proper state */
16849e39c5baSBill Taylor 	status = hermon_sw_reset(state);
16859e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
16869e39c5baSBill Taylor 		hermon_hw_fini(state, cleanup);
16879e39c5baSBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf,
16889e39c5baSBill Taylor 		    "hw_init_sw_reset_fail");
16899e39c5baSBill Taylor 		/* This case is not the degraded one */
16909e39c5baSBill Taylor 		return (DDI_FAILURE);
16919e39c5baSBill Taylor 	}
16929e39c5baSBill Taylor 
16939e39c5baSBill Taylor 	/* Initialize mailboxes */
16949e39c5baSBill Taylor 	status = hermon_rsrc_init_phase1(state);
16959e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
16969e39c5baSBill Taylor 		hermon_hw_fini(state, cleanup);
16979e39c5baSBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf,
16989e39c5baSBill Taylor 		    "hw_init_rsrcinit1_fail");
16999e39c5baSBill Taylor 		/* This case is not the degraded one */
17009e39c5baSBill Taylor 		return (DDI_FAILURE);
17019e39c5baSBill Taylor 	}
17029e39c5baSBill Taylor 	cleanup = HERMON_DRV_CLEANUP_LEVEL4;
17039e39c5baSBill Taylor 
17049e39c5baSBill Taylor 	/* Post QUERY_FW */
17059e39c5baSBill Taylor 	status = hermon_cmn_query_cmd_post(state, QUERY_FW, 0, 0, &state->hs_fw,
17069e39c5baSBill Taylor 	    sizeof (hermon_hw_queryfw_t), HERMON_CMD_NOSLEEP_SPIN);
17079e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
17089e39c5baSBill Taylor 		cmn_err(CE_NOTE, "QUERY_FW command failed: %08x\n", status);
17099e39c5baSBill Taylor 		hermon_hw_fini(state, cleanup);
17109e39c5baSBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf,
17119e39c5baSBill Taylor 		    "hw_init_query_fw_cmd_fail");
17129e39c5baSBill Taylor 		/* This case is not the degraded one */
17139e39c5baSBill Taylor 		return (DDI_FAILURE);
17149e39c5baSBill Taylor 	}
17159e39c5baSBill Taylor 
17169e39c5baSBill Taylor 	/* Validate what/that HERMON FW version is appropriate */
17179e39c5baSBill Taylor 
17189e39c5baSBill Taylor 	status = hermon_fw_version_check(state);
17199e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
17209e39c5baSBill Taylor 		HERMON_FMANOTE(state, HERMON_FMA_FWVER);
17219e39c5baSBill Taylor 		if (state->hs_operational_mode == HERMON_HCA_MODE) {
17229e39c5baSBill Taylor 			cmn_err(CE_CONT, "Unsupported Hermon FW version: "
17239e39c5baSBill Taylor 			    "expected: %04d.%04d.%04d, "
17249e39c5baSBill Taylor 			    "actual: %04d.%04d.%04d\n",
17259e39c5baSBill Taylor 			    HERMON_FW_VER_MAJOR,
17269e39c5baSBill Taylor 			    HERMON_FW_VER_MINOR,
17279e39c5baSBill Taylor 			    HERMON_FW_VER_SUBMINOR,
17289e39c5baSBill Taylor 			    state->hs_fw.fw_rev_major,
17299e39c5baSBill Taylor 			    state->hs_fw.fw_rev_minor,
17309e39c5baSBill Taylor 			    state->hs_fw.fw_rev_subminor);
17319e39c5baSBill Taylor 		} else {
17329e39c5baSBill Taylor 			cmn_err(CE_CONT, "Unsupported FW version: "
17339e39c5baSBill Taylor 			    "%04d.%04d.%04d\n",
17349e39c5baSBill Taylor 			    state->hs_fw.fw_rev_major,
17359e39c5baSBill Taylor 			    state->hs_fw.fw_rev_minor,
17369e39c5baSBill Taylor 			    state->hs_fw.fw_rev_subminor);
17379e39c5baSBill Taylor 		}
17389e39c5baSBill Taylor 		state->hs_operational_mode = HERMON_MAINTENANCE_MODE;
173932c5adfdSEiji Ota 		state->hs_fm_degraded_reason = HCA_FW_MISMATCH;
17409e39c5baSBill Taylor 		hermon_hw_fini(state, cleanup);
17419e39c5baSBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf,
17429e39c5baSBill Taylor 		    "hw_init_checkfwver_fail");
17439e39c5baSBill Taylor 		/* This case is the degraded one */
17449e39c5baSBill Taylor 		return (HERMON_CMD_BAD_NVMEM);
17459e39c5baSBill Taylor 	}
17469e39c5baSBill Taylor 
17479e39c5baSBill Taylor 	/*
17489e39c5baSBill Taylor 	 * Save off the rest of the interesting registers that we'll be using.
17499e39c5baSBill Taylor 	 * Setup the offsets for the other registers.
17509e39c5baSBill Taylor 	 */
17519e39c5baSBill Taylor 
17529e39c5baSBill Taylor 	/*
17539e39c5baSBill Taylor 	 * Hermon does the intr_offset from the BAR - technically should get the
17549e39c5baSBill Taylor 	 * BAR info from the response, but PRM says it's from BAR0-1, which is
17559e39c5baSBill Taylor 	 * for us the CMD BAR
17569e39c5baSBill Taylor 	 */
17579e39c5baSBill Taylor 
17589e39c5baSBill Taylor 	clr_intr_offset	 = state->hs_fw.clr_intr_offs & HERMON_CMD_OFFSET_MASK;
17599e39c5baSBill Taylor 
17609e39c5baSBill Taylor 	/* Save Clear Interrupt address */
17619e39c5baSBill Taylor 	state->hs_cmd_regs.clr_intr = (uint64_t *)
17629e39c5baSBill Taylor 	    (uintptr_t)(state->hs_reg_cmd_baseaddr + clr_intr_offset);
17639e39c5baSBill Taylor 
17649e39c5baSBill Taylor 	/*
17659e39c5baSBill Taylor 	 * Set the error buffer also into the structure - used in hermon_event.c
17669e39c5baSBill Taylor 	 * to check for internal error on the HCA, not reported in eqe or
17679e39c5baSBill Taylor 	 * (necessarily) by interrupt
17689e39c5baSBill Taylor 	 */
17699e39c5baSBill Taylor 	state->hs_cmd_regs.fw_err_buf = (uint32_t *)(uintptr_t)
17709e39c5baSBill Taylor 	    (state->hs_reg_cmd_baseaddr + state->hs_fw.error_buf_addr);
17719e39c5baSBill Taylor 
17729e39c5baSBill Taylor 	/*
17739e39c5baSBill Taylor 	 * Invoke a polling thread to check the error buffer periodically.
17749e39c5baSBill Taylor 	 */
1775332f545bSEiji Ota 	if (!hermon_no_inter_err_chk) {
1776332f545bSEiji Ota 		state->hs_fm_poll_thread = ddi_periodic_add(
1777332f545bSEiji Ota 		    hermon_inter_err_chk, (void *)state, FM_POLL_INTERVAL,
1778332f545bSEiji Ota 		    DDI_IPL_0);
1779332f545bSEiji Ota 	}
17809e39c5baSBill Taylor 
17819e39c5baSBill Taylor 	cleanup = HERMON_DRV_CLEANUP_LEVEL5;
17829e39c5baSBill Taylor 
17839e39c5baSBill Taylor 	/*
17849e39c5baSBill Taylor 	 * Allocate, map, and run the HCA Firmware.
17859e39c5baSBill Taylor 	 */
17869e39c5baSBill Taylor 
17879e39c5baSBill Taylor 	/* Allocate memory for the firmware to load into and map it */
17889e39c5baSBill Taylor 
17899e39c5baSBill Taylor 	/* get next higher power of 2 */
17909e39c5baSBill Taylor 	fw_size = 1 << highbit(state->hs_fw.fw_pages);
17919e39c5baSBill Taylor 	state->hs_fw_dma.length = fw_size << HERMON_PAGESHIFT;
17929e39c5baSBill Taylor 	status = hermon_dma_alloc(state, &state->hs_fw_dma, MAP_FA);
17939e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
17949e39c5baSBill Taylor 		cmn_err(CE_NOTE, "FW alloc failed\n");
17959e39c5baSBill Taylor 		hermon_hw_fini(state, cleanup);
17969e39c5baSBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf,
17979e39c5baSBill Taylor 		    "hw_init_dma_alloc_fw_fail");
17989e39c5baSBill Taylor 		/* This case is not the degraded one */
17999e39c5baSBill Taylor 		return (DDI_FAILURE);
18009e39c5baSBill Taylor 	}
18019e39c5baSBill Taylor 
18029e39c5baSBill Taylor 	cleanup = HERMON_DRV_CLEANUP_LEVEL6;
18039e39c5baSBill Taylor 
18049e39c5baSBill Taylor 	/* Invoke the RUN_FW cmd to run the firmware */
18059e39c5baSBill Taylor 	status = hermon_run_fw_cmd_post(state);
18069e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
18079e39c5baSBill Taylor 		cmn_err(CE_NOTE, "RUN_FW command failed: 0x%08x\n", status);
18089e39c5baSBill Taylor 		if (status == HERMON_CMD_BAD_NVMEM) {
18099e39c5baSBill Taylor 			state->hs_operational_mode = HERMON_MAINTENANCE_MODE;
181032c5adfdSEiji Ota 			state->hs_fm_degraded_reason = HCA_FW_CORRUPT;
18119e39c5baSBill Taylor 		}
18129e39c5baSBill Taylor 		hermon_hw_fini(state, cleanup);
18139e39c5baSBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf, "hw_init_run_fw_fail");
18149e39c5baSBill Taylor 		/*
18159e39c5baSBill Taylor 		 * If the status is HERMON_CMD_BAD_NVMEM, it's likely the
18169e39c5baSBill Taylor 		 * firmware is corrupted, so the mode falls into the
18179e39c5baSBill Taylor 		 * maintenance mode.
18189e39c5baSBill Taylor 		 */
18199e39c5baSBill Taylor 		return (status == HERMON_CMD_BAD_NVMEM ? HERMON_CMD_BAD_NVMEM :
18209e39c5baSBill Taylor 		    DDI_FAILURE);
18219e39c5baSBill Taylor 	}
18229e39c5baSBill Taylor 
18239e39c5baSBill Taylor 
18249e39c5baSBill Taylor 	/*
18259e39c5baSBill Taylor 	 * QUERY DEVICE LIMITS/CAPABILITIES
18269e39c5baSBill Taylor 	 * NOTE - in Hermon, the command is changed to QUERY_DEV_CAP,
18279e39c5baSBill Taylor 	 * but for familiarity we have kept the structure name the
18289e39c5baSBill Taylor 	 * same as Tavor/Arbel
18299e39c5baSBill Taylor 	 */
18309e39c5baSBill Taylor 
18319e39c5baSBill Taylor 	status = hermon_cmn_query_cmd_post(state, QUERY_DEV_CAP, 0, 0,
18329e39c5baSBill Taylor 	    &state->hs_devlim, sizeof (hermon_hw_querydevlim_t),
18339e39c5baSBill Taylor 	    HERMON_CMD_NOSLEEP_SPIN);
18349e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
18359e39c5baSBill Taylor 		cmn_err(CE_NOTE, "QUERY_DEV_CAP command failed: 0x%08x\n",
18369e39c5baSBill Taylor 		    status);
18379e39c5baSBill Taylor 		hermon_hw_fini(state, cleanup);
18389e39c5baSBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf, "hw_init_devcap_fail");
18399e39c5baSBill Taylor 		/* This case is not the degraded one */
18409e39c5baSBill Taylor 		return (DDI_FAILURE);
18419e39c5baSBill Taylor 	}
18429e39c5baSBill Taylor 
184317a2b317SBill Taylor 	state->hs_rsvd_eqs = max(state->hs_devlim.num_rsvd_eq,
184417a2b317SBill Taylor 	    (4 * state->hs_devlim.num_rsvd_uar));
18459e39c5baSBill Taylor 
18469e39c5baSBill Taylor 	/* now we have enough info to map in the UAR BAR */
18479e39c5baSBill Taylor 	/*
18489e39c5baSBill Taylor 	 * First, we figure out how to map the BAR for UAR - use only half if
18499e39c5baSBill Taylor 	 * BlueFlame is enabled - in that case the mapped length is 1/2 the
18509e39c5baSBill Taylor 	 * log_max_uar_sz (max__uar - 1) * 1MB ( +20).
18519e39c5baSBill Taylor 	 */
18529e39c5baSBill Taylor 
18539e39c5baSBill Taylor 	if (state->hs_devlim.blu_flm) {		/* Blue Flame Enabled */
18549e39c5baSBill Taylor 		offset = (uint64_t)1 << (state->hs_devlim.log_max_uar_sz + 20);
18559e39c5baSBill Taylor 	} else {
18569e39c5baSBill Taylor 		offset = 0;	/* a zero length means map the whole thing */
18579e39c5baSBill Taylor 	}
18589e39c5baSBill Taylor 	status = hermon_regs_map_setup(state, HERMON_UAR_BAR,
18599e39c5baSBill Taylor 	    &state->hs_reg_uar_baseaddr, 0, offset, &state->hs_fm_accattr,
18609e39c5baSBill Taylor 	    &state->hs_fm_uarhdl);
18619e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
18629e39c5baSBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf, "UAR BAR mapping");
18639e39c5baSBill Taylor 		/* This case is not the degraded one */
18649e39c5baSBill Taylor 		return (DDI_FAILURE);
18659e39c5baSBill Taylor 	}
18669e39c5baSBill Taylor 
18679e39c5baSBill Taylor 	/* and if BlueFlame is enabled, map the other half there */
18689e39c5baSBill Taylor 	if (state->hs_devlim.blu_flm) {		/* Blue Flame Enabled */
18699e39c5baSBill Taylor 		offset = (uint64_t)1 << (state->hs_devlim.log_max_uar_sz + 20);
18709e39c5baSBill Taylor 		status = ddi_regs_map_setup(state->hs_dip, HERMON_UAR_BAR,
18719e39c5baSBill Taylor 		    &state->hs_reg_bf_baseaddr, offset, offset,
18729e39c5baSBill Taylor 		    &state->hs_reg_accattr, &state->hs_reg_bfhdl);
18739e39c5baSBill Taylor 		if (status != DDI_SUCCESS) {
18749e39c5baSBill Taylor 			HERMON_ATTACH_MSG(state->hs_attach_buf,
18759e39c5baSBill Taylor 			    "BlueFlame BAR mapping");
18769e39c5baSBill Taylor 			/* This case is not the degraded one */
18779e39c5baSBill Taylor 			return (DDI_FAILURE);
18789e39c5baSBill Taylor 		}
18799e39c5baSBill Taylor 		/* This will be used in hw_fini if we fail to init. */
18809e39c5baSBill Taylor 		state->hs_bf_offset = offset;
18819e39c5baSBill Taylor 	}
18829e39c5baSBill Taylor 	cleanup = HERMON_DRV_CLEANUP_LEVEL7;
18839e39c5baSBill Taylor 
18849e39c5baSBill Taylor 	/* Hermon has a couple of things needed for phase 2 in query port */
18859e39c5baSBill Taylor 
18869e39c5baSBill Taylor 	status = hermon_cmn_query_cmd_post(state, QUERY_PORT, 0, 0x01,
18879e39c5baSBill Taylor 	    &state->hs_queryport, sizeof (hermon_hw_query_port_t),
18889e39c5baSBill Taylor 	    HERMON_CMD_NOSLEEP_SPIN);
18899e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
18909e39c5baSBill Taylor 		cmn_err(CE_NOTE, "QUERY_PORT command failed: 0x%08x\n",
18919e39c5baSBill Taylor 		    status);
18929e39c5baSBill Taylor 		hermon_hw_fini(state, cleanup);
18939e39c5baSBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf,
18949e39c5baSBill Taylor 		    "hw_init_queryport_fail");
18959e39c5baSBill Taylor 		/* This case is not the degraded one */
18969e39c5baSBill Taylor 		return (DDI_FAILURE);
18979e39c5baSBill Taylor 	}
18989e39c5baSBill Taylor 
18999e39c5baSBill Taylor 	/* Initialize the Phase2 Hermon configuration profile */
19009e39c5baSBill Taylor 	status = hermon_cfg_profile_init_phase2(state);
19019e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
19029e39c5baSBill Taylor 		cmn_err(CE_NOTE, "CFG phase 2 failed: 0x%08x\n", status);
19039e39c5baSBill Taylor 		hermon_hw_fini(state, cleanup);
19049e39c5baSBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf,
19059e39c5baSBill Taylor 		    "hw_init_cfginit2_fail");
19069e39c5baSBill Taylor 		/* This case is not the degraded one */
19079e39c5baSBill Taylor 		return (DDI_FAILURE);
19089e39c5baSBill Taylor 	}
19099e39c5baSBill Taylor 
19109e39c5baSBill Taylor 	/* Determine and set the ICM size */
19119e39c5baSBill Taylor 	state->hs_icm_sz = hermon_size_icm(state);
19129e39c5baSBill Taylor 	status		 = hermon_set_icm_size_cmd_post(state);
19139e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
19149e39c5baSBill Taylor 		cmn_err(CE_NOTE, "Hermon: SET_ICM_SIZE cmd failed: 0x%08x\n",
19159e39c5baSBill Taylor 		    status);
19169e39c5baSBill Taylor 		hermon_hw_fini(state, cleanup);
19179e39c5baSBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf,
19189e39c5baSBill Taylor 		    "hw_init_seticmsz_fail");
19199e39c5baSBill Taylor 		/* This case is not the degraded one */
19209e39c5baSBill Taylor 		return (DDI_FAILURE);
19219e39c5baSBill Taylor 	}
19229e39c5baSBill Taylor 	/* alloc icm aux physical memory and map it */
19239e39c5baSBill Taylor 
19249e39c5baSBill Taylor 	state->hs_icma_dma.length = 1 << highbit(state->hs_icma_sz);
19259e39c5baSBill Taylor 
19269e39c5baSBill Taylor 	status = hermon_dma_alloc(state, &state->hs_icma_dma, MAP_ICM_AUX);
19279e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
19289e39c5baSBill Taylor 		cmn_err(CE_NOTE, "failed to alloc (0x%llx) bytes for ICMA\n",
19299e39c5baSBill Taylor 		    (longlong_t)state->hs_icma_dma.length);
19309e39c5baSBill Taylor 		hermon_hw_fini(state, cleanup);
19319e39c5baSBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf,
19329e39c5baSBill Taylor 		    "hw_init_dma_alloc_icm_aux_fail");
19339e39c5baSBill Taylor 		/* This case is not the degraded one */
19349e39c5baSBill Taylor 		return (DDI_FAILURE);
19359e39c5baSBill Taylor 	}
19369e39c5baSBill Taylor 	cleanup = HERMON_DRV_CLEANUP_LEVEL8;
19379e39c5baSBill Taylor 
19389e39c5baSBill Taylor 	cleanup = HERMON_DRV_CLEANUP_LEVEL9;
19399e39c5baSBill Taylor 
19409e39c5baSBill Taylor 	/* Allocate an array of structures to house the ICM tables */
19419e39c5baSBill Taylor 	state->hs_icm = kmem_zalloc(HERMON_NUM_ICM_RESOURCES *
19429e39c5baSBill Taylor 	    sizeof (hermon_icm_table_t), KM_SLEEP);
19439e39c5baSBill Taylor 
19449e39c5baSBill Taylor 	/* Set up the ICM address space and the INIT_HCA command input */
19459e39c5baSBill Taylor 	status = hermon_icm_config_setup(state, &state->hs_hcaparams);
19469e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
19479e39c5baSBill Taylor 		cmn_err(CE_NOTE, "ICM configuration failed\n");
19489e39c5baSBill Taylor 		hermon_hw_fini(state, cleanup);
19499e39c5baSBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf,
19509e39c5baSBill Taylor 		    "hw_init_icm_config_setup_fail");
19519e39c5baSBill Taylor 		/* This case is not the degraded one */
19529e39c5baSBill Taylor 		return (DDI_FAILURE);
19539e39c5baSBill Taylor 	}
19549e39c5baSBill Taylor 	cleanup = HERMON_DRV_CLEANUP_LEVEL10;
19559e39c5baSBill Taylor 
19569e39c5baSBill Taylor 	/* Initialize the adapter with the INIT_HCA cmd */
19579e39c5baSBill Taylor 	status = hermon_init_hca_cmd_post(state, &state->hs_hcaparams,
19589e39c5baSBill Taylor 	    HERMON_CMD_NOSLEEP_SPIN);
19599e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
19609e39c5baSBill Taylor 		cmn_err(CE_NOTE, "INIT_HCA command failed: %08x\n", status);
19619e39c5baSBill Taylor 		hermon_hw_fini(state, cleanup);
19629e39c5baSBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf, "hw_init_hca_fail");
19639e39c5baSBill Taylor 		/* This case is not the degraded one */
19649e39c5baSBill Taylor 		return (DDI_FAILURE);
19659e39c5baSBill Taylor 	}
19669e39c5baSBill Taylor 	cleanup = HERMON_DRV_CLEANUP_LEVEL11;
19679e39c5baSBill Taylor 
19689e39c5baSBill Taylor 	/* Enter the second phase of init for Hermon configuration/resources */
19699e39c5baSBill Taylor 	status = hermon_rsrc_init_phase2(state);
19709e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
19719e39c5baSBill Taylor 		hermon_hw_fini(state, cleanup);
19729e39c5baSBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf,
19739e39c5baSBill Taylor 		    "hw_init_rsrcinit2_fail");
19749e39c5baSBill Taylor 		/* This case is not the degraded one */
19759e39c5baSBill Taylor 		return (DDI_FAILURE);
19769e39c5baSBill Taylor 	}
19779e39c5baSBill Taylor 	cleanup = HERMON_DRV_CLEANUP_LEVEL12;
19789e39c5baSBill Taylor 
19799e39c5baSBill Taylor 	/* Query the adapter via QUERY_ADAPTER */
19809e39c5baSBill Taylor 	status = hermon_cmn_query_cmd_post(state, QUERY_ADAPTER, 0, 0,
19819e39c5baSBill Taylor 	    &state->hs_adapter, sizeof (hermon_hw_queryadapter_t),
19829e39c5baSBill Taylor 	    HERMON_CMD_NOSLEEP_SPIN);
19839e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
19849e39c5baSBill Taylor 		cmn_err(CE_NOTE, "Hermon: QUERY_ADAPTER command failed: %08x\n",
19859e39c5baSBill Taylor 		    status);
19869e39c5baSBill Taylor 		hermon_hw_fini(state, cleanup);
19879e39c5baSBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf,
19889e39c5baSBill Taylor 		    "hw_init_query_adapter_fail");
19899e39c5baSBill Taylor 		/* This case is not the degraded one */
19909e39c5baSBill Taylor 		return (DDI_FAILURE);
19919e39c5baSBill Taylor 	}
19929e39c5baSBill Taylor 
19939e39c5baSBill Taylor 	/* Allocate protection domain (PD) for Hermon internal use */
19949e39c5baSBill Taylor 	status = hermon_pd_alloc(state, &state->hs_pdhdl_internal,
19959e39c5baSBill Taylor 	    HERMON_SLEEP);
19969e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
19979e39c5baSBill Taylor 		cmn_err(CE_NOTE, "failed to alloc internal PD\n");
19989e39c5baSBill Taylor 		hermon_hw_fini(state, cleanup);
19999e39c5baSBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf,
20009e39c5baSBill Taylor 		    "hw_init_internal_pd_alloc_fail");
20019e39c5baSBill Taylor 		/* This case is not the degraded one */
20029e39c5baSBill Taylor 		return (DDI_FAILURE);
20039e39c5baSBill Taylor 	}
20049e39c5baSBill Taylor 	cleanup = HERMON_DRV_CLEANUP_LEVEL13;
20059e39c5baSBill Taylor 
20069e39c5baSBill Taylor 	/* Setup UAR page for kernel use */
20079e39c5baSBill Taylor 	status = hermon_internal_uarpg_init(state);
20089e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
20099e39c5baSBill Taylor 		cmn_err(CE_NOTE, "failed to setup internal UAR\n");
20109e39c5baSBill Taylor 		hermon_hw_fini(state, cleanup);
20119e39c5baSBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf,
20129e39c5baSBill Taylor 		    "hw_init_internal_uarpg_alloc_fail");
20139e39c5baSBill Taylor 		/* This case is not the degraded one */
20149e39c5baSBill Taylor 		return (DDI_FAILURE);
20159e39c5baSBill Taylor 	}
20169e39c5baSBill Taylor 	cleanup = HERMON_DRV_CLEANUP_LEVEL14;
20179e39c5baSBill Taylor 
20189e39c5baSBill Taylor 	/* Query and initialize the Hermon interrupt/MSI information */
20199e39c5baSBill Taylor 	status = hermon_intr_or_msi_init(state);
20209e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
20219e39c5baSBill Taylor 		cmn_err(CE_NOTE, "failed to setup INTR/MSI\n");
20229e39c5baSBill Taylor 		hermon_hw_fini(state, cleanup);
20239e39c5baSBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf,
20249e39c5baSBill Taylor 		    "hw_init_intr_or_msi_init_fail");
20259e39c5baSBill Taylor 		/* This case is not the degraded one */
20269e39c5baSBill Taylor 		return (DDI_FAILURE);
20279e39c5baSBill Taylor 	}
20289e39c5baSBill Taylor 	cleanup = HERMON_DRV_CLEANUP_LEVEL15;
20299e39c5baSBill Taylor 
20309e39c5baSBill Taylor 	status = hermon_isr_init(state);	/* set up the isr */
20319e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
20329e39c5baSBill Taylor 		cmn_err(CE_NOTE, "failed to init isr\n");
20339e39c5baSBill Taylor 		hermon_hw_fini(state, cleanup);
20349e39c5baSBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf,
20359e39c5baSBill Taylor 		    "hw_init_isrinit_fail");
20369e39c5baSBill Taylor 		/* This case is not the degraded one */
20379e39c5baSBill Taylor 		return (DDI_FAILURE);
20389e39c5baSBill Taylor 	}
20399e39c5baSBill Taylor 	cleanup = HERMON_DRV_CLEANUP_LEVEL16;
20409e39c5baSBill Taylor 
20419e39c5baSBill Taylor 	/* Setup the event queues */
20429e39c5baSBill Taylor 	status = hermon_eq_init_all(state);
20439e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
20449e39c5baSBill Taylor 		cmn_err(CE_NOTE, "failed to init EQs\n");
20459e39c5baSBill Taylor 		hermon_hw_fini(state, cleanup);
20469e39c5baSBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf,
20479e39c5baSBill Taylor 		    "hw_init_eqinitall_fail");
20489e39c5baSBill Taylor 		/* This case is not the degraded one */
20499e39c5baSBill Taylor 		return (DDI_FAILURE);
20509e39c5baSBill Taylor 	}
20519e39c5baSBill Taylor 	cleanup = HERMON_DRV_CLEANUP_LEVEL17;
20529e39c5baSBill Taylor 
20539e39c5baSBill Taylor 
20549e39c5baSBill Taylor 
20559e39c5baSBill Taylor 	/* Reserve contexts for QP0 and QP1 */
20569e39c5baSBill Taylor 	status = hermon_special_qp_contexts_reserve(state);
20579e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
20589e39c5baSBill Taylor 		cmn_err(CE_NOTE, "failed to init special QPs\n");
20599e39c5baSBill Taylor 		hermon_hw_fini(state, cleanup);
20609e39c5baSBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf,
20619e39c5baSBill Taylor 		    "hw_init_rsrv_sqp_fail");
20629e39c5baSBill Taylor 		/* This case is not the degraded one */
20639e39c5baSBill Taylor 		return (DDI_FAILURE);
20649e39c5baSBill Taylor 	}
20659e39c5baSBill Taylor 	cleanup = HERMON_DRV_CLEANUP_LEVEL18;
20669e39c5baSBill Taylor 
20679e39c5baSBill Taylor 	/* Initialize for multicast group handling */
20689e39c5baSBill Taylor 	status = hermon_mcg_init(state);
20699e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
20709e39c5baSBill Taylor 		cmn_err(CE_NOTE, "failed to init multicast\n");
20719e39c5baSBill Taylor 		hermon_hw_fini(state, cleanup);
20729e39c5baSBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf,
20739e39c5baSBill Taylor 		    "hw_init_mcg_init_fail");
20749e39c5baSBill Taylor 		/* This case is not the degraded one */
20759e39c5baSBill Taylor 		return (DDI_FAILURE);
20769e39c5baSBill Taylor 	}
20779e39c5baSBill Taylor 	cleanup = HERMON_DRV_CLEANUP_LEVEL19;
20789e39c5baSBill Taylor 
20799e39c5baSBill Taylor 	/* Initialize the Hermon IB port(s) */
20809e39c5baSBill Taylor 	status = hermon_hca_port_init(state);
20819e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
20829e39c5baSBill Taylor 		cmn_err(CE_NOTE, "failed to init HCA Port\n");
20839e39c5baSBill Taylor 		hermon_hw_fini(state, cleanup);
20849e39c5baSBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf,
20859e39c5baSBill Taylor 		    "hw_init_hca_port_init_fail");
20869e39c5baSBill Taylor 		/* This case is not the degraded one */
20879e39c5baSBill Taylor 		return (DDI_FAILURE);
20889e39c5baSBill Taylor 	}
20899e39c5baSBill Taylor 
20909e39c5baSBill Taylor 	cleanup = HERMON_DRV_CLEANUP_ALL;
20919e39c5baSBill Taylor 
20929e39c5baSBill Taylor 	/* Determine NodeGUID and SystemImageGUID */
20939e39c5baSBill Taylor 	status = hermon_getnodeinfo_cmd_post(state, HERMON_CMD_NOSLEEP_SPIN,
20949e39c5baSBill Taylor 	    &nodeinfo);
20959e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
20969e39c5baSBill Taylor 		cmn_err(CE_NOTE, "GetNodeInfo command failed: %08x\n", status);
20979e39c5baSBill Taylor 		hermon_hw_fini(state, cleanup);
20989e39c5baSBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf,
20999e39c5baSBill Taylor 		    "hw_init_getnodeinfo_cmd_fail");
21009e39c5baSBill Taylor 		/* This case is not the degraded one */
21019e39c5baSBill Taylor 		return (DDI_FAILURE);
21029e39c5baSBill Taylor 	}
21039e39c5baSBill Taylor 
21049e39c5baSBill Taylor 	/*
21059e39c5baSBill Taylor 	 * If the NodeGUID value was set in OBP properties, then we use that
21069e39c5baSBill Taylor 	 * value.  But we still print a message if the value we queried from
21079e39c5baSBill Taylor 	 * firmware does not match this value.
21089e39c5baSBill Taylor 	 *
21099e39c5baSBill Taylor 	 * Otherwise if OBP value is not set then we use the value from
21109e39c5baSBill Taylor 	 * firmware unconditionally.
21119e39c5baSBill Taylor 	 */
21129e39c5baSBill Taylor 	if (state->hs_cfg_profile->cp_nodeguid) {
21139e39c5baSBill Taylor 		state->hs_nodeguid   = state->hs_cfg_profile->cp_nodeguid;
21149e39c5baSBill Taylor 	} else {
21159e39c5baSBill Taylor 		state->hs_nodeguid = nodeinfo.NodeGUID;
21169e39c5baSBill Taylor 	}
21179e39c5baSBill Taylor 
21189e39c5baSBill Taylor 	if (state->hs_nodeguid != nodeinfo.NodeGUID) {
21199e39c5baSBill Taylor 		cmn_err(CE_NOTE, "!NodeGUID value queried from firmware "
21209e39c5baSBill Taylor 		    "does not match value set by device property");
21219e39c5baSBill Taylor 	}
21229e39c5baSBill Taylor 
21239e39c5baSBill Taylor 	/*
21249e39c5baSBill Taylor 	 * If the SystemImageGUID value was set in OBP properties, then we use
21259e39c5baSBill Taylor 	 * that value.  But we still print a message if the value we queried
21269e39c5baSBill Taylor 	 * from firmware does not match this value.
21279e39c5baSBill Taylor 	 *
21289e39c5baSBill Taylor 	 * Otherwise if OBP value is not set then we use the value from
21299e39c5baSBill Taylor 	 * firmware unconditionally.
21309e39c5baSBill Taylor 	 */
21319e39c5baSBill Taylor 	if (state->hs_cfg_profile->cp_sysimgguid) {
21329e39c5baSBill Taylor 		state->hs_sysimgguid = state->hs_cfg_profile->cp_sysimgguid;
21339e39c5baSBill Taylor 	} else {
21349e39c5baSBill Taylor 		state->hs_sysimgguid = nodeinfo.SystemImageGUID;
21359e39c5baSBill Taylor 	}
21369e39c5baSBill Taylor 
21379e39c5baSBill Taylor 	if (state->hs_sysimgguid != nodeinfo.SystemImageGUID) {
21389e39c5baSBill Taylor 		cmn_err(CE_NOTE, "!SystemImageGUID value queried from firmware "
21399e39c5baSBill Taylor 		    "does not match value set by device property");
21409e39c5baSBill Taylor 	}
21419e39c5baSBill Taylor 
21429e39c5baSBill Taylor 	/* Get NodeDescription */
21439e39c5baSBill Taylor 	status = hermon_getnodedesc_cmd_post(state, HERMON_CMD_NOSLEEP_SPIN,
21449e39c5baSBill Taylor 	    (sm_nodedesc_t *)&state->hs_nodedesc);
21459e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
21469e39c5baSBill Taylor 		cmn_err(CE_CONT, "GetNodeDesc command failed: %08x\n", status);
21479e39c5baSBill Taylor 		hermon_hw_fini(state, cleanup);
21489e39c5baSBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf,
21499e39c5baSBill Taylor 		    "hw_init_getnodedesc_cmd_fail");
21509e39c5baSBill Taylor 		/* This case is not the degraded one */
21519e39c5baSBill Taylor 		return (DDI_FAILURE);
21529e39c5baSBill Taylor 	}
21539e39c5baSBill Taylor 
21549e39c5baSBill Taylor 	return (DDI_SUCCESS);
21559e39c5baSBill Taylor }
21569e39c5baSBill Taylor 
21579e39c5baSBill Taylor 
21589e39c5baSBill Taylor /*
21599e39c5baSBill Taylor  * hermon_hw_fini()
21609e39c5baSBill Taylor  *    Context: Only called from attach() and/or detach() path contexts
21619e39c5baSBill Taylor  */
21629e39c5baSBill Taylor static void
hermon_hw_fini(hermon_state_t * state,hermon_drv_cleanup_level_t cleanup)21639e39c5baSBill Taylor hermon_hw_fini(hermon_state_t *state, hermon_drv_cleanup_level_t cleanup)
21649e39c5baSBill Taylor {
21659e39c5baSBill Taylor 	uint_t		num_ports;
21669e39c5baSBill Taylor 	int		i, status;
21679e39c5baSBill Taylor 
21689e39c5baSBill Taylor 
21699e39c5baSBill Taylor 	/*
21709e39c5baSBill Taylor 	 * JBDB - We might not want to run these returns in all cases of
21719e39c5baSBill Taylor 	 * Bad News. We should still attempt to free all of the DMA memory
21729e39c5baSBill Taylor 	 * resources...  This needs to be worked last, after all allocations
21739e39c5baSBill Taylor 	 * are implemented. For now, and possibly for later, this works.
21749e39c5baSBill Taylor 	 */
21759e39c5baSBill Taylor 
21769e39c5baSBill Taylor 	switch (cleanup) {
21779e39c5baSBill Taylor 	/*
21789e39c5baSBill Taylor 	 * If we add more driver initialization steps that should be cleaned
21799e39c5baSBill Taylor 	 * up here, we need to ensure that HERMON_DRV_CLEANUP_ALL is still the
21809e39c5baSBill Taylor 	 * first entry (i.e. corresponds to the last init step).
21819e39c5baSBill Taylor 	 */
21829e39c5baSBill Taylor 	case HERMON_DRV_CLEANUP_ALL:
21839e39c5baSBill Taylor 		/* Shutdown the Hermon IB port(s) */
21849e39c5baSBill Taylor 		num_ports = state->hs_cfg_profile->cp_num_ports;
21859e39c5baSBill Taylor 		(void) hermon_hca_ports_shutdown(state, num_ports);
21869e39c5baSBill Taylor 		/* FALLTHROUGH */
21879e39c5baSBill Taylor 
21889e39c5baSBill Taylor 	case HERMON_DRV_CLEANUP_LEVEL19:
21899e39c5baSBill Taylor 		/* Teardown resources used for multicast group handling */
21909e39c5baSBill Taylor 		hermon_mcg_fini(state);
21919e39c5baSBill Taylor 		/* FALLTHROUGH */
21929e39c5baSBill Taylor 
21939e39c5baSBill Taylor 	case HERMON_DRV_CLEANUP_LEVEL18:
21949e39c5baSBill Taylor 		/* Unreserve the special QP contexts */
21959e39c5baSBill Taylor 		hermon_special_qp_contexts_unreserve(state);
21969e39c5baSBill Taylor 		/* FALLTHROUGH */
21979e39c5baSBill Taylor 
21989e39c5baSBill Taylor 	case HERMON_DRV_CLEANUP_LEVEL17:
21999e39c5baSBill Taylor 		/*
22009e39c5baSBill Taylor 		 * Attempt to teardown all event queues (EQ).  If we fail
22019e39c5baSBill Taylor 		 * here then print a warning message and return.  Something
22029e39c5baSBill Taylor 		 * (either in HW or SW) has gone seriously wrong.
22039e39c5baSBill Taylor 		 */
22049e39c5baSBill Taylor 		status = hermon_eq_fini_all(state);
22059e39c5baSBill Taylor 		if (status != DDI_SUCCESS) {
22069e39c5baSBill Taylor 			HERMON_WARNING(state, "failed to teardown EQs");
22079e39c5baSBill Taylor 			return;
22089e39c5baSBill Taylor 		}
22099e39c5baSBill Taylor 		/* FALLTHROUGH */
22109e39c5baSBill Taylor 	case HERMON_DRV_CLEANUP_LEVEL16:
22119e39c5baSBill Taylor 		/* Teardown Hermon interrupts */
22129e39c5baSBill Taylor 		hermon_isr_fini(state);
22139e39c5baSBill Taylor 		/* FALLTHROUGH */
22149e39c5baSBill Taylor 
22159e39c5baSBill Taylor 	case HERMON_DRV_CLEANUP_LEVEL15:
22169e39c5baSBill Taylor 		status = hermon_intr_or_msi_fini(state);
22179e39c5baSBill Taylor 		if (status != DDI_SUCCESS) {
22189e39c5baSBill Taylor 			HERMON_WARNING(state, "failed to free intr/MSI");
22199e39c5baSBill Taylor 			return;
22209e39c5baSBill Taylor 		}
22219e39c5baSBill Taylor 		/* FALLTHROUGH */
22229e39c5baSBill Taylor 
22239e39c5baSBill Taylor 	case HERMON_DRV_CLEANUP_LEVEL14:
22249e39c5baSBill Taylor 		/* Free the resources for the Hermon internal UAR pages */
22259e39c5baSBill Taylor 		hermon_internal_uarpg_fini(state);
22269e39c5baSBill Taylor 		/* FALLTHROUGH */
22279e39c5baSBill Taylor 
22289e39c5baSBill Taylor 	case HERMON_DRV_CLEANUP_LEVEL13:
22299e39c5baSBill Taylor 		/*
22309e39c5baSBill Taylor 		 * Free the PD that was used internally by Hermon software.  If
22319e39c5baSBill Taylor 		 * we fail here then print a warning and return.  Something
22329e39c5baSBill Taylor 		 * (probably software-related, but perhaps HW) has gone wrong.
22339e39c5baSBill Taylor 		 */
22349e39c5baSBill Taylor 		status = hermon_pd_free(state, &state->hs_pdhdl_internal);
22359e39c5baSBill Taylor 		if (status != DDI_SUCCESS) {
22369e39c5baSBill Taylor 			HERMON_WARNING(state, "failed to free internal PD");
22379e39c5baSBill Taylor 			return;
22389e39c5baSBill Taylor 		}
22399e39c5baSBill Taylor 		/* FALLTHROUGH */
22409e39c5baSBill Taylor 
22419e39c5baSBill Taylor 	case HERMON_DRV_CLEANUP_LEVEL12:
22429e39c5baSBill Taylor 		/* Cleanup all the phase2 resources first */
22439e39c5baSBill Taylor 		hermon_rsrc_fini(state, HERMON_RSRC_CLEANUP_ALL);
22449e39c5baSBill Taylor 		/* FALLTHROUGH */
22459e39c5baSBill Taylor 
22469e39c5baSBill Taylor 	case HERMON_DRV_CLEANUP_LEVEL11:
22479e39c5baSBill Taylor 		/* LEVEL11 is after INIT_HCA */
22489e39c5baSBill Taylor 		/* FALLTHROUGH */
22499e39c5baSBill Taylor 
22509e39c5baSBill Taylor 
22519e39c5baSBill Taylor 	case HERMON_DRV_CLEANUP_LEVEL10:
22529e39c5baSBill Taylor 		/*
22539e39c5baSBill Taylor 		 * Unmap the ICM memory area with UNMAP_ICM command.
22549e39c5baSBill Taylor 		 */
22559e39c5baSBill Taylor 		status = hermon_unmap_icm_cmd_post(state, NULL);
22569e39c5baSBill Taylor 		if (status != DDI_SUCCESS) {
22579e39c5baSBill Taylor 			cmn_err(CE_WARN,
22589e39c5baSBill Taylor 			    "hermon_hw_fini: failed to unmap ICM\n");
22599e39c5baSBill Taylor 		}
22609e39c5baSBill Taylor 
22619e39c5baSBill Taylor 		/* Free the initial ICM DMA handles */
22629e39c5baSBill Taylor 		hermon_icm_dma_fini(state);
22639e39c5baSBill Taylor 
22649e39c5baSBill Taylor 		/* Free the ICM table structures */
22659e39c5baSBill Taylor 		hermon_icm_tables_fini(state);
22669e39c5baSBill Taylor 
22679e39c5baSBill Taylor 		/* Free the ICM table handles */
22689e39c5baSBill Taylor 		kmem_free(state->hs_icm, HERMON_NUM_ICM_RESOURCES *
22699e39c5baSBill Taylor 		    sizeof (hermon_icm_table_t));
22709e39c5baSBill Taylor 
22719e39c5baSBill Taylor 		/* FALLTHROUGH */
22729e39c5baSBill Taylor 
22739e39c5baSBill Taylor 	case HERMON_DRV_CLEANUP_LEVEL9:
22749e39c5baSBill Taylor 		/*
22759e39c5baSBill Taylor 		 * Unmap the ICM Aux memory area with UNMAP_ICM_AUX command.
22769e39c5baSBill Taylor 		 */
22779e39c5baSBill Taylor 		status = hermon_unmap_icm_aux_cmd_post(state);
22789e39c5baSBill Taylor 		if (status != HERMON_CMD_SUCCESS) {
22799e39c5baSBill Taylor 			cmn_err(CE_NOTE,
22809e39c5baSBill Taylor 			    "hermon_hw_fini: failed to unmap ICMA\n");
22819e39c5baSBill Taylor 		}
22829e39c5baSBill Taylor 		/* FALLTHROUGH */
22839e39c5baSBill Taylor 
22849e39c5baSBill Taylor 	case HERMON_DRV_CLEANUP_LEVEL8:
22859e39c5baSBill Taylor 		/*
22869e39c5baSBill Taylor 		 * Deallocate ICM Aux DMA memory.
22879e39c5baSBill Taylor 		 */
22889e39c5baSBill Taylor 		hermon_dma_free(&state->hs_icma_dma);
22899e39c5baSBill Taylor 		/* FALLTHROUGH */
22909e39c5baSBill Taylor 
22919e39c5baSBill Taylor 	case HERMON_DRV_CLEANUP_LEVEL7:
22929e39c5baSBill Taylor 		if (state->hs_fm_uarhdl) {
22939e39c5baSBill Taylor 			hermon_regs_map_free(state, &state->hs_fm_uarhdl);
22949e39c5baSBill Taylor 			state->hs_fm_uarhdl = NULL;
22959e39c5baSBill Taylor 		}
22969e39c5baSBill Taylor 
22979e39c5baSBill Taylor 		if (state->hs_reg_uarhdl) {
22989e39c5baSBill Taylor 			ddi_regs_map_free(&state->hs_reg_uarhdl);
22999e39c5baSBill Taylor 			state->hs_reg_uarhdl = NULL;
23009e39c5baSBill Taylor 		}
23019e39c5baSBill Taylor 
23029e39c5baSBill Taylor 		if (state->hs_bf_offset != 0 && state->hs_reg_bfhdl) {
23039e39c5baSBill Taylor 			ddi_regs_map_free(&state->hs_reg_bfhdl);
23049e39c5baSBill Taylor 			state->hs_reg_bfhdl = NULL;
23059e39c5baSBill Taylor 		}
23069e39c5baSBill Taylor 
23079e39c5baSBill Taylor 		for (i = 0; i < HERMON_MAX_PORTS; i++) {
23089e39c5baSBill Taylor 			if (state->hs_pkey[i]) {
23099e39c5baSBill Taylor 				kmem_free(state->hs_pkey[i], (1 <<
23109e39c5baSBill Taylor 				    state->hs_cfg_profile->cp_log_max_pkeytbl) *
23119e39c5baSBill Taylor 				    sizeof (ib_pkey_t));
23129e39c5baSBill Taylor 				state->hs_pkey[i] = NULL;
23139e39c5baSBill Taylor 			}
23149e39c5baSBill Taylor 			if (state->hs_guid[i]) {
23159e39c5baSBill Taylor 				kmem_free(state->hs_guid[i], (1 <<
23169e39c5baSBill Taylor 				    state->hs_cfg_profile->cp_log_max_gidtbl) *
23179e39c5baSBill Taylor 				    sizeof (ib_guid_t));
23189e39c5baSBill Taylor 				state->hs_guid[i] = NULL;
23199e39c5baSBill Taylor 			}
23209e39c5baSBill Taylor 		}
23219e39c5baSBill Taylor 		/* FALLTHROUGH */
23229e39c5baSBill Taylor 
23239e39c5baSBill Taylor 	case HERMON_DRV_CLEANUP_LEVEL6:
23249e39c5baSBill Taylor 		/*
23259e39c5baSBill Taylor 		 * Unmap the firmware memory area with UNMAP_FA command.
23269e39c5baSBill Taylor 		 */
23279e39c5baSBill Taylor 		status = hermon_unmap_fa_cmd_post(state);
23289e39c5baSBill Taylor 
23299e39c5baSBill Taylor 		if (status != HERMON_CMD_SUCCESS) {
23309e39c5baSBill Taylor 			cmn_err(CE_NOTE,
23319e39c5baSBill Taylor 			    "hermon_hw_fini: failed to unmap FW\n");
23329e39c5baSBill Taylor 		}
23339e39c5baSBill Taylor 
23349e39c5baSBill Taylor 		/*
23359e39c5baSBill Taylor 		 * Deallocate firmware DMA memory.
23369e39c5baSBill Taylor 		 */
23379e39c5baSBill Taylor 		hermon_dma_free(&state->hs_fw_dma);
23389e39c5baSBill Taylor 		/* FALLTHROUGH */
23399e39c5baSBill Taylor 
23409e39c5baSBill Taylor 	case HERMON_DRV_CLEANUP_LEVEL5:
23419e39c5baSBill Taylor 		/* stop the poll thread */
23429e39c5baSBill Taylor 		if (state->hs_fm_poll_thread) {
23439e39c5baSBill Taylor 			ddi_periodic_delete(state->hs_fm_poll_thread);
23449e39c5baSBill Taylor 			state->hs_fm_poll_thread = NULL;
23459e39c5baSBill Taylor 		}
23469e39c5baSBill Taylor 		/* FALLTHROUGH */
23479e39c5baSBill Taylor 
23489e39c5baSBill Taylor 	case HERMON_DRV_CLEANUP_LEVEL4:
23499e39c5baSBill Taylor 		/* Then cleanup the phase1 resources */
23509e39c5baSBill Taylor 		hermon_rsrc_fini(state, HERMON_RSRC_CLEANUP_PHASE1_COMPLETE);
23519e39c5baSBill Taylor 		/* FALLTHROUGH */
23529e39c5baSBill Taylor 
23539e39c5baSBill Taylor 	case HERMON_DRV_CLEANUP_LEVEL3:
23549e39c5baSBill Taylor 		/* Teardown any resources allocated for the config profile */
23559e39c5baSBill Taylor 		hermon_cfg_profile_fini(state);
23569e39c5baSBill Taylor 		/* FALLTHROUGH */
23579e39c5baSBill Taylor 
23589e39c5baSBill Taylor 	case HERMON_DRV_CLEANUP_LEVEL2:
23599e39c5baSBill Taylor #ifdef HERMON_SUPPORTS_MSIX_BAR
23609e39c5baSBill Taylor 		/*
23619e39c5baSBill Taylor 		 * unmap 3rd BAR, MSIX BAR
23629e39c5baSBill Taylor 		 */
23639e39c5baSBill Taylor 		if (state->hs_reg_msihdl) {
23649e39c5baSBill Taylor 			ddi_regs_map_free(&state->hs_reg_msihdl);
23659e39c5baSBill Taylor 			state->hs_reg_msihdl = NULL;
23669e39c5baSBill Taylor 		}
23679e39c5baSBill Taylor 		/* FALLTHROUGH */
23689e39c5baSBill Taylor #endif
23699e39c5baSBill Taylor 	case HERMON_DRV_CLEANUP_LEVEL1:
23709e39c5baSBill Taylor 	case HERMON_DRV_CLEANUP_LEVEL0:
2371e9935355SEiji Ota 		/*
2372e9935355SEiji Ota 		 * LEVEL1 and LEVEL0 resources are freed in
2373e9935355SEiji Ota 		 * hermon_drv_fini2().
2374e9935355SEiji Ota 		 */
23759e39c5baSBill Taylor 		break;
23769e39c5baSBill Taylor 
23779e39c5baSBill Taylor 	default:
23789e39c5baSBill Taylor 		HERMON_WARNING(state, "unexpected driver cleanup level");
23799e39c5baSBill Taylor 		return;
23809e39c5baSBill Taylor 	}
23819e39c5baSBill Taylor }
23829e39c5baSBill Taylor 
23839e39c5baSBill Taylor 
23849e39c5baSBill Taylor /*
23859e39c5baSBill Taylor  * hermon_soft_state_init()
23869e39c5baSBill Taylor  *    Context: Only called from attach() path context
23879e39c5baSBill Taylor  */
23889e39c5baSBill Taylor static int
hermon_soft_state_init(hermon_state_t * state)23899e39c5baSBill Taylor hermon_soft_state_init(hermon_state_t *state)
23909e39c5baSBill Taylor {
23919e39c5baSBill Taylor 	ibt_hca_attr_t		*hca_attr;
23929e39c5baSBill Taylor 	uint64_t		maxval, val;
23939e39c5baSBill Taylor 	ibt_hca_flags_t		caps = IBT_HCA_NO_FLAGS;
23949e39c5baSBill Taylor 	ibt_hca_flags2_t	caps2 = IBT_HCA2_NO_FLAGS;
23959e39c5baSBill Taylor 	int			status;
23969e39c5baSBill Taylor 	int			max_send_wqe_bytes;
23979e39c5baSBill Taylor 	int			max_recv_wqe_bytes;
23989e39c5baSBill Taylor 
23999e39c5baSBill Taylor 	/*
24009e39c5baSBill Taylor 	 * The ibc_hca_info_t struct is passed to the IBTF.  This is the
24019e39c5baSBill Taylor 	 * routine where we initialize it.  Many of the init values come from
24029e39c5baSBill Taylor 	 * either configuration variables or successful queries of the Hermon
24039e39c5baSBill Taylor 	 * hardware abilities
24049e39c5baSBill Taylor 	 */
240517a2b317SBill Taylor 	state->hs_ibtfinfo.hca_ci_vers	= IBCI_V4;
24069e39c5baSBill Taylor 	state->hs_ibtfinfo.hca_handle	= (ibc_hca_hdl_t)state;
24079e39c5baSBill Taylor 	state->hs_ibtfinfo.hca_ops	= &hermon_ibc_ops;
24089e39c5baSBill Taylor 
24099e39c5baSBill Taylor 	hca_attr = kmem_zalloc(sizeof (ibt_hca_attr_t), KM_SLEEP);
24109e39c5baSBill Taylor 	state->hs_ibtfinfo.hca_attr = hca_attr;
24119e39c5baSBill Taylor 
241217a2b317SBill Taylor 	hca_attr->hca_dip = state->hs_dip;
24139e39c5baSBill Taylor 	hca_attr->hca_fw_major_version = state->hs_fw.fw_rev_major;
24149e39c5baSBill Taylor 	hca_attr->hca_fw_minor_version = state->hs_fw.fw_rev_minor;
24159e39c5baSBill Taylor 	hca_attr->hca_fw_micro_version = state->hs_fw.fw_rev_subminor;
24169e39c5baSBill Taylor 
24179e39c5baSBill Taylor 	/* CQ interrupt moderation maximums - each limited to 16 bits */
24189e39c5baSBill Taylor 	hca_attr->hca_max_cq_mod_count = 0xFFFF;
24199e39c5baSBill Taylor 	hca_attr->hca_max_cq_mod_usec = 0xFFFF;
242017a2b317SBill Taylor 	hca_attr->hca_max_cq_handlers = state->hs_intrmsi_allocd;
24219e39c5baSBill Taylor 
24229e39c5baSBill Taylor 
24239e39c5baSBill Taylor 	/*
24249e39c5baSBill Taylor 	 * Determine HCA capabilities:
24259e39c5baSBill Taylor 	 * No default support for IBT_HCA_RD, IBT_HCA_RAW_MULTICAST,
24269e39c5baSBill Taylor 	 *    IBT_HCA_ATOMICS_GLOBAL, IBT_HCA_RESIZE_CHAN, IBT_HCA_INIT_TYPE,
24279e39c5baSBill Taylor 	 *    or IBT_HCA_SHUTDOWN_PORT
24289e39c5baSBill Taylor 	 * But IBT_HCA_AH_PORT_CHECK, IBT_HCA_SQD_RTS_PORT, IBT_HCA_SI_GUID,
24299e39c5baSBill Taylor 	 *    IBT_HCA_RNR_NAK, IBT_HCA_CURRENT_QP_STATE, IBT_HCA_PORT_UP,
24309e39c5baSBill Taylor 	 *    IBT_HCA_SRQ, IBT_HCA_RESIZE_SRQ and IBT_HCA_FMR are always
24319e39c5baSBill Taylor 	 *    supported
24329e39c5baSBill Taylor 	 * All other features are conditionally supported, depending on the
24339e39c5baSBill Taylor 	 *    status return by the Hermon HCA in QUERY_DEV_LIM.
24349e39c5baSBill Taylor 	 */
24359e39c5baSBill Taylor 	if (state->hs_devlim.ud_multi) {
24369e39c5baSBill Taylor 		caps |= IBT_HCA_UD_MULTICAST;
24379e39c5baSBill Taylor 	}
24389e39c5baSBill Taylor 	if (state->hs_devlim.atomic) {
24399e39c5baSBill Taylor 		caps |= IBT_HCA_ATOMICS_HCA;
24409e39c5baSBill Taylor 	}
24419e39c5baSBill Taylor 	if (state->hs_devlim.apm) {
24429e39c5baSBill Taylor 		caps |= IBT_HCA_AUTO_PATH_MIG;
24439e39c5baSBill Taylor 	}
24449e39c5baSBill Taylor 	if (state->hs_devlim.pkey_v) {
24459e39c5baSBill Taylor 		caps |= IBT_HCA_PKEY_CNTR;
24469e39c5baSBill Taylor 	}
24479e39c5baSBill Taylor 	if (state->hs_devlim.qkey_v) {
24489e39c5baSBill Taylor 		caps |= IBT_HCA_QKEY_CNTR;
24499e39c5baSBill Taylor 	}
24509e39c5baSBill Taylor 	if (state->hs_devlim.ipoib_cksm) {
24519e39c5baSBill Taylor 		caps |= IBT_HCA_CKSUM_FULL;
24529e39c5baSBill Taylor 		caps2 |= IBT_HCA2_IP_CLASS;
24539e39c5baSBill Taylor 	}
24549e39c5baSBill Taylor 	if (state->hs_devlim.mod_wr_srq) {
24559e39c5baSBill Taylor 		caps |= IBT_HCA_RESIZE_SRQ;
24569e39c5baSBill Taylor 	}
24579e39c5baSBill Taylor 	if (state->hs_devlim.lif) {
24589e39c5baSBill Taylor 		caps |= IBT_HCA_LOCAL_INVAL_FENCE;
24599e39c5baSBill Taylor 	}
24609e39c5baSBill Taylor 	if (state->hs_devlim.reserved_lkey) {
24619e39c5baSBill Taylor 		caps2 |= IBT_HCA2_RES_LKEY;
24629e39c5baSBill Taylor 		hca_attr->hca_reserved_lkey = state->hs_devlim.rsv_lkey;
24639e39c5baSBill Taylor 	}
24649e39c5baSBill Taylor 	if (state->hs_devlim.local_inv && state->hs_devlim.remote_inv &&
246517a2b317SBill Taylor 	    state->hs_devlim.fast_reg_wr) {	/* fw needs to be >= 2.7.000 */
246617a2b317SBill Taylor 		if ((state->hs_fw.fw_rev_major > 2) ||
246717a2b317SBill Taylor 		    ((state->hs_fw.fw_rev_major == 2) &&
246817a2b317SBill Taylor 		    (state->hs_fw.fw_rev_minor >= 7)))
24699e39c5baSBill Taylor 			caps2 |= IBT_HCA2_MEM_MGT_EXT;
247017a2b317SBill Taylor 	}
247117a2b317SBill Taylor 	if (state->hs_devlim.log_max_rss_tbl_sz) {
247217a2b317SBill Taylor 		hca_attr->hca_rss_max_log2_table =
247317a2b317SBill Taylor 		    state->hs_devlim.log_max_rss_tbl_sz;
247417a2b317SBill Taylor 		if (state->hs_devlim.rss_xor)
247517a2b317SBill Taylor 			caps2 |= IBT_HCA2_RSS_XOR_ALG;
247617a2b317SBill Taylor 		if (state->hs_devlim.rss_toep)
247717a2b317SBill Taylor 			caps2 |= IBT_HCA2_RSS_TPL_ALG;
24789e39c5baSBill Taylor 	}
24799e39c5baSBill Taylor 	if (state->hs_devlim.mps) {
24809e39c5baSBill Taylor 		caps |= IBT_HCA_ZERO_BASED_VA;
24819e39c5baSBill Taylor 	}
24829e39c5baSBill Taylor 	if (state->hs_devlim.zb) {
24839e39c5baSBill Taylor 		caps |= IBT_HCA_MULT_PAGE_SZ_MR;
24849e39c5baSBill Taylor 	}
24859e39c5baSBill Taylor 	caps |= (IBT_HCA_AH_PORT_CHECK | IBT_HCA_SQD_SQD_PORT |
24869e39c5baSBill Taylor 	    IBT_HCA_SI_GUID | IBT_HCA_RNR_NAK | IBT_HCA_CURRENT_QP_STATE |
24879e39c5baSBill Taylor 	    IBT_HCA_PORT_UP | IBT_HCA_RC_SRQ | IBT_HCA_UD_SRQ | IBT_HCA_FMR);
248817a2b317SBill Taylor 	caps2 |= IBT_HCA2_DMA_MR;
24899e39c5baSBill Taylor 
24909e39c5baSBill Taylor 	if (state->hs_devlim.log_max_gso_sz) {
24919e39c5baSBill Taylor 		hca_attr->hca_max_lso_size =
24929e39c5baSBill Taylor 		    (1 << state->hs_devlim.log_max_gso_sz);
24939c865d64SRajkumar Sivaprakasam 		/* 64 = ctrl & datagram seg, 4 = LSO seg, 16 = 1 SGL */
24949c865d64SRajkumar Sivaprakasam 		hca_attr->hca_max_lso_hdr_size =
24959c865d64SRajkumar Sivaprakasam 		    state->hs_devlim.max_desc_sz_sq - (64 + 4 + 16);
24969e39c5baSBill Taylor 	}
24979e39c5baSBill Taylor 
24989e39c5baSBill Taylor 	caps |= IBT_HCA_WQE_SIZE_INFO;
24999e39c5baSBill Taylor 	max_send_wqe_bytes = state->hs_devlim.max_desc_sz_sq;
25009e39c5baSBill Taylor 	max_recv_wqe_bytes = state->hs_devlim.max_desc_sz_rq;
25019e39c5baSBill Taylor 	hca_attr->hca_ud_send_sgl_sz = (max_send_wqe_bytes / 16) - 4;
25029e39c5baSBill Taylor 	hca_attr->hca_conn_send_sgl_sz = (max_send_wqe_bytes / 16) - 1;
25039e39c5baSBill Taylor 	hca_attr->hca_conn_rdma_sgl_overhead = 1;
250417a2b317SBill Taylor 	hca_attr->hca_conn_rdma_write_sgl_sz = (max_send_wqe_bytes / 16) - 2;
250517a2b317SBill Taylor 	hca_attr->hca_conn_rdma_read_sgl_sz = (512 / 16) - 2; /* see PRM */
25069e39c5baSBill Taylor 	hca_attr->hca_recv_sgl_sz = max_recv_wqe_bytes / 16;
25079e39c5baSBill Taylor 
25089e39c5baSBill Taylor 	/* We choose not to support "inline" unless it improves performance */
25099e39c5baSBill Taylor 	hca_attr->hca_max_inline_size = 0;
25109e39c5baSBill Taylor 	hca_attr->hca_ud_send_inline_sz = 0;
25119e39c5baSBill Taylor 	hca_attr->hca_conn_send_inline_sz = 0;
25129e39c5baSBill Taylor 	hca_attr->hca_conn_rdmaw_inline_overhead = 4;
25139e39c5baSBill Taylor 
2514f35eb4e6SBill Taylor #if defined(_ELF64)
2515f35eb4e6SBill Taylor 	/* 32-bit kernels are too small for Fibre Channel over IB */
251617a2b317SBill Taylor 	if (state->hs_devlim.fcoib && (caps2 & IBT_HCA2_MEM_MGT_EXT)) {
251717a2b317SBill Taylor 		caps2 |= IBT_HCA2_FC;
251817a2b317SBill Taylor 		hca_attr->hca_rfci_max_log2_qp = 7;	/* 128 per port */
251917a2b317SBill Taylor 		hca_attr->hca_fexch_max_log2_qp = 16;	/* 64K per port */
2520f35eb4e6SBill Taylor 		hca_attr->hca_fexch_max_log2_mem = 20;	/* 1MB per MPT */
252117a2b317SBill Taylor 	}
2522f35eb4e6SBill Taylor #endif
252317a2b317SBill Taylor 
25249e39c5baSBill Taylor 	hca_attr->hca_flags = caps;
25259e39c5baSBill Taylor 	hca_attr->hca_flags2 = caps2;
25269e39c5baSBill Taylor 
25279e39c5baSBill Taylor 	/*
25289e39c5baSBill Taylor 	 * Set hca_attr's IDs
25299e39c5baSBill Taylor 	 */
25309e39c5baSBill Taylor 	hca_attr->hca_vendor_id	 = state->hs_vendor_id;
25319e39c5baSBill Taylor 	hca_attr->hca_device_id	 = state->hs_device_id;
25329e39c5baSBill Taylor 	hca_attr->hca_version_id = state->hs_revision_id;
25339e39c5baSBill Taylor 
25349e39c5baSBill Taylor 	/*
25359e39c5baSBill Taylor 	 * Determine number of available QPs and max QP size.  Number of
25369e39c5baSBill Taylor 	 * available QPs is determined by subtracting the number of
25379e39c5baSBill Taylor 	 * "reserved QPs" (i.e. reserved for firmware use) from the
25389e39c5baSBill Taylor 	 * total number configured.
25399e39c5baSBill Taylor 	 */
25409e39c5baSBill Taylor 	val = ((uint64_t)1 << state->hs_cfg_profile->cp_log_num_qp);
25419e39c5baSBill Taylor 	hca_attr->hca_max_qp = val - ((uint64_t)1 <<
25429e39c5baSBill Taylor 	    state->hs_devlim.log_rsvd_qp);
25439e39c5baSBill Taylor 	maxval	= ((uint64_t)1 << state->hs_devlim.log_max_qp_sz);
25449e39c5baSBill Taylor 	val	= ((uint64_t)1 << state->hs_cfg_profile->cp_log_max_qp_sz);
25459e39c5baSBill Taylor 	if (val > maxval) {
25469e39c5baSBill Taylor 		kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
25479e39c5baSBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf,
25489e39c5baSBill Taylor 		    "soft_state_init_maxqpsz_toobig_fail");
25499e39c5baSBill Taylor 		return (DDI_FAILURE);
25509e39c5baSBill Taylor 	}
25519e39c5baSBill Taylor 	/* we need to reduce this by the max space needed for headroom */
25529e39c5baSBill Taylor 	hca_attr->hca_max_qp_sz = (uint_t)val - (HERMON_QP_OH_SIZE >>
25539e39c5baSBill Taylor 	    HERMON_QP_WQE_LOG_MINIMUM) - 1;
25549e39c5baSBill Taylor 
25559e39c5baSBill Taylor 	/*
25569e39c5baSBill Taylor 	 * Determine max scatter-gather size in WQEs. The HCA has split
25579e39c5baSBill Taylor 	 * the max sgl into rec'v Q and send Q values. Use the least.
25589e39c5baSBill Taylor 	 *
25599e39c5baSBill Taylor 	 * This is mainly useful for legacy clients.  Smart clients
25609e39c5baSBill Taylor 	 * such as IPoIB will use the IBT_HCA_WQE_SIZE_INFO sgl info.
25619e39c5baSBill Taylor 	 */
25629e39c5baSBill Taylor 	if (state->hs_devlim.max_sg_rq <= state->hs_devlim.max_sg_sq) {
25639e39c5baSBill Taylor 		maxval = state->hs_devlim.max_sg_rq;
25649e39c5baSBill Taylor 	} else {
25659e39c5baSBill Taylor 		maxval = state->hs_devlim.max_sg_sq;
25669e39c5baSBill Taylor 	}
25679e39c5baSBill Taylor 	val	= state->hs_cfg_profile->cp_wqe_max_sgl;
25689e39c5baSBill Taylor 	if (val > maxval) {
25699e39c5baSBill Taylor 		kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
25709e39c5baSBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf,
25719e39c5baSBill Taylor 		    "soft_state_init_toomanysgl_fail");
25729e39c5baSBill Taylor 		return (DDI_FAILURE);
25739e39c5baSBill Taylor 	}
25749e39c5baSBill Taylor 	/* If the rounded value for max SGL is too large, cap it */
25759e39c5baSBill Taylor 	if (state->hs_cfg_profile->cp_wqe_real_max_sgl > maxval) {
25769e39c5baSBill Taylor 		state->hs_cfg_profile->cp_wqe_real_max_sgl = (uint32_t)maxval;
25779e39c5baSBill Taylor 		val = maxval;
25789e39c5baSBill Taylor 	} else {
25799e39c5baSBill Taylor 		val = state->hs_cfg_profile->cp_wqe_real_max_sgl;
25809e39c5baSBill Taylor 	}
25819e39c5baSBill Taylor 
25829e39c5baSBill Taylor 	hca_attr->hca_max_sgl	 = (uint_t)val;
25839e39c5baSBill Taylor 	hca_attr->hca_max_rd_sgl = 0;	/* zero because RD is unsupported */
25849e39c5baSBill Taylor 
25859e39c5baSBill Taylor 	/*
25869e39c5baSBill Taylor 	 * Determine number of available CQs and max CQ size. Number of
25879e39c5baSBill Taylor 	 * available CQs is determined by subtracting the number of
25889e39c5baSBill Taylor 	 * "reserved CQs" (i.e. reserved for firmware use) from the
25899e39c5baSBill Taylor 	 * total number configured.
25909e39c5baSBill Taylor 	 */
25919e39c5baSBill Taylor 	val = ((uint64_t)1 << state->hs_cfg_profile->cp_log_num_cq);
25929e39c5baSBill Taylor 	hca_attr->hca_max_cq = val - ((uint64_t)1 <<
25939e39c5baSBill Taylor 	    state->hs_devlim.log_rsvd_cq);
25949e39c5baSBill Taylor 	maxval	= ((uint64_t)1 << state->hs_devlim.log_max_cq_sz);
25959e39c5baSBill Taylor 	val	= ((uint64_t)1 << state->hs_cfg_profile->cp_log_max_cq_sz) - 1;
25969e39c5baSBill Taylor 	if (val > maxval) {
25979e39c5baSBill Taylor 		kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
25989e39c5baSBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf,
25999e39c5baSBill Taylor 		    "soft_state_init_maxcqsz_toobig_fail");
26009e39c5baSBill Taylor 		return (DDI_FAILURE);
26019e39c5baSBill Taylor 	}
26029e39c5baSBill Taylor 	hca_attr->hca_max_cq_sz = (uint_t)val;
26039e39c5baSBill Taylor 
26049e39c5baSBill Taylor 	/*
26059e39c5baSBill Taylor 	 * Determine number of available SRQs and max SRQ size. Number of
26069e39c5baSBill Taylor 	 * available SRQs is determined by subtracting the number of
26079e39c5baSBill Taylor 	 * "reserved SRQs" (i.e. reserved for firmware use) from the
26089e39c5baSBill Taylor 	 * total number configured.
26099e39c5baSBill Taylor 	 */
26109e39c5baSBill Taylor 	val = ((uint64_t)1 << state->hs_cfg_profile->cp_log_num_srq);
26119e39c5baSBill Taylor 	hca_attr->hca_max_srqs = val - ((uint64_t)1 <<
26129e39c5baSBill Taylor 	    state->hs_devlim.log_rsvd_srq);
26139e39c5baSBill Taylor 	maxval  = ((uint64_t)1 << state->hs_devlim.log_max_srq_sz);
26149e39c5baSBill Taylor 	val	= ((uint64_t)1 << state->hs_cfg_profile->cp_log_max_srq_sz);
26159e39c5baSBill Taylor 
26169e39c5baSBill Taylor 	if (val > maxval) {
26179e39c5baSBill Taylor 		kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
26189e39c5baSBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf,
26199e39c5baSBill Taylor 		    "soft_state_init_maxsrqsz_toobig_fail");
26209e39c5baSBill Taylor 		return (DDI_FAILURE);
26219e39c5baSBill Taylor 	}
26229e39c5baSBill Taylor 	hca_attr->hca_max_srqs_sz = (uint_t)val;
26239e39c5baSBill Taylor 
26249e39c5baSBill Taylor 	val	= hca_attr->hca_recv_sgl_sz - 1; /* SRQ has a list link */
26259e39c5baSBill Taylor 	maxval	= state->hs_devlim.max_sg_rq - 1;
26269e39c5baSBill Taylor 	if (val > maxval) {
26279e39c5baSBill Taylor 		kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
26289e39c5baSBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf,
26299e39c5baSBill Taylor 		    "soft_state_init_toomanysrqsgl_fail");
26309e39c5baSBill Taylor 		return (DDI_FAILURE);
26319e39c5baSBill Taylor 	}
26329e39c5baSBill Taylor 	hca_attr->hca_max_srq_sgl = (uint_t)val;
26339e39c5baSBill Taylor 
26349e39c5baSBill Taylor 	/*
26359e39c5baSBill Taylor 	 * Determine supported HCA page sizes
26369e39c5baSBill Taylor 	 * XXX
26379e39c5baSBill Taylor 	 * For now we simply return the system pagesize as the only supported
26389e39c5baSBill Taylor 	 * pagesize
26399e39c5baSBill Taylor 	 */
26409e39c5baSBill Taylor 	hca_attr->hca_page_sz = ((PAGESIZE == (1 << 13)) ? IBT_PAGE_8K :
26419e39c5baSBill Taylor 	    IBT_PAGE_4K);
26429e39c5baSBill Taylor 
26439e39c5baSBill Taylor 	/*
26449e39c5baSBill Taylor 	 * Determine number of available MemReg, MemWin, and their max size.
26459e39c5baSBill Taylor 	 * Number of available MRs and MWs is determined by subtracting
26469e39c5baSBill Taylor 	 * the number of "reserved MPTs" (i.e. reserved for firmware use)
26479e39c5baSBill Taylor 	 * from the total number configured for each.
26489e39c5baSBill Taylor 	 */
26499e39c5baSBill Taylor 	val = ((uint64_t)1 << state->hs_cfg_profile->cp_log_num_dmpt);
26509e39c5baSBill Taylor 	hca_attr->hca_max_memr	  = val - ((uint64_t)1 <<
26519e39c5baSBill Taylor 	    state->hs_devlim.log_rsvd_dmpt);
26529e39c5baSBill Taylor 	hca_attr->hca_max_mem_win = state->hs_devlim.mem_win ? (val -
26539e39c5baSBill Taylor 	    ((uint64_t)1 << state->hs_devlim.log_rsvd_dmpt)) : 0;
26549e39c5baSBill Taylor 	maxval	= state->hs_devlim.log_max_mrw_sz;
26559e39c5baSBill Taylor 	val	= state->hs_cfg_profile->cp_log_max_mrw_sz;
26569e39c5baSBill Taylor 	if (val > maxval) {
26579e39c5baSBill Taylor 		kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
26589e39c5baSBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf,
26599e39c5baSBill Taylor 		    "soft_state_init_maxmrwsz_toobig_fail");
26609e39c5baSBill Taylor 		return (DDI_FAILURE);
26619e39c5baSBill Taylor 	}
26629e39c5baSBill Taylor 	hca_attr->hca_max_memr_len = ((uint64_t)1 << val);
26639e39c5baSBill Taylor 
26649e39c5baSBill Taylor 	/* Determine RDMA/Atomic properties */
26659e39c5baSBill Taylor 	val = ((uint64_t)1 << state->hs_cfg_profile->cp_log_num_rdb);
26669e39c5baSBill Taylor 	hca_attr->hca_max_rsc = (uint_t)val;
26679e39c5baSBill Taylor 	val = state->hs_cfg_profile->cp_hca_max_rdma_in_qp;
26689e39c5baSBill Taylor 	hca_attr->hca_max_rdma_in_qp  = (uint8_t)val;
26699e39c5baSBill Taylor 	val = state->hs_cfg_profile->cp_hca_max_rdma_out_qp;
26709e39c5baSBill Taylor 	hca_attr->hca_max_rdma_out_qp = (uint8_t)val;
26719e39c5baSBill Taylor 	hca_attr->hca_max_rdma_in_ee  = 0;
26729e39c5baSBill Taylor 	hca_attr->hca_max_rdma_out_ee = 0;
26739e39c5baSBill Taylor 
26749e39c5baSBill Taylor 	/*
26759e39c5baSBill Taylor 	 * Determine maximum number of raw IPv6 and Ether QPs.  Set to 0
26769e39c5baSBill Taylor 	 * because neither type of raw QP is supported
26779e39c5baSBill Taylor 	 */
26789e39c5baSBill Taylor 	hca_attr->hca_max_ipv6_qp  = 0;
26799e39c5baSBill Taylor 	hca_attr->hca_max_ether_qp = 0;
26809e39c5baSBill Taylor 
26819e39c5baSBill Taylor 	/* Determine max number of MCGs and max QP-per-MCG */
26829e39c5baSBill Taylor 	val = ((uint64_t)1 << state->hs_cfg_profile->cp_log_num_qp);
26839e39c5baSBill Taylor 	hca_attr->hca_max_mcg_qps   = (uint_t)val;
26849e39c5baSBill Taylor 	val = ((uint64_t)1 << state->hs_cfg_profile->cp_log_num_mcg);
26859e39c5baSBill Taylor 	hca_attr->hca_max_mcg	    = (uint_t)val;
26869e39c5baSBill Taylor 	val = state->hs_cfg_profile->cp_num_qp_per_mcg;
26879e39c5baSBill Taylor 	hca_attr->hca_max_qp_per_mcg = (uint_t)val;
26889e39c5baSBill Taylor 
26899e39c5baSBill Taylor 	/* Determine max number partitions (i.e. PKeys) */
26909e39c5baSBill Taylor 	maxval	= ((uint64_t)state->hs_cfg_profile->cp_num_ports <<
26919e39c5baSBill Taylor 	    state->hs_queryport.log_max_pkey);
26929e39c5baSBill Taylor 	val	= ((uint64_t)state->hs_cfg_profile->cp_num_ports <<
26939e39c5baSBill Taylor 	    state->hs_cfg_profile->cp_log_max_pkeytbl);
26949e39c5baSBill Taylor 
26959e39c5baSBill Taylor 	if (val > maxval) {
26969e39c5baSBill Taylor 		kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
26979e39c5baSBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf,
26989e39c5baSBill Taylor 		    "soft_state_init_toomanypkey_fail");
26999e39c5baSBill Taylor 		return (DDI_FAILURE);
27009e39c5baSBill Taylor 	}
27019e39c5baSBill Taylor 	hca_attr->hca_max_partitions = (uint16_t)val;
27029e39c5baSBill Taylor 
27039e39c5baSBill Taylor 	/* Determine number of ports */
27049e39c5baSBill Taylor 	maxval = state->hs_devlim.num_ports;
27059e39c5baSBill Taylor 	val = state->hs_cfg_profile->cp_num_ports;
27069e39c5baSBill Taylor 	if ((val > maxval) || (val == 0)) {
27079e39c5baSBill Taylor 		kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
27089e39c5baSBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf,
27099e39c5baSBill Taylor 		    "soft_state_init_toomanyports_fail");
27109e39c5baSBill Taylor 		return (DDI_FAILURE);
27119e39c5baSBill Taylor 	}
27129e39c5baSBill Taylor 	hca_attr->hca_nports = (uint8_t)val;
27139e39c5baSBill Taylor 
27149e39c5baSBill Taylor 	/* Copy NodeGUID and SystemImageGUID from softstate */
27159e39c5baSBill Taylor 	hca_attr->hca_node_guid = state->hs_nodeguid;
27169e39c5baSBill Taylor 	hca_attr->hca_si_guid	= state->hs_sysimgguid;
27179e39c5baSBill Taylor 
27189e39c5baSBill Taylor 	/*
27199e39c5baSBill Taylor 	 * Determine local ACK delay.  Use the value suggested by the Hermon
27209e39c5baSBill Taylor 	 * hardware (from the QUERY_DEV_CAP command)
27219e39c5baSBill Taylor 	 */
27229e39c5baSBill Taylor 	hca_attr->hca_local_ack_delay = state->hs_devlim.ca_ack_delay;
27239e39c5baSBill Taylor 
27249e39c5baSBill Taylor 	/* Determine max SGID table and PKey table sizes */
27259e39c5baSBill Taylor 	val	= ((uint64_t)1 << state->hs_cfg_profile->cp_log_max_gidtbl);
27269e39c5baSBill Taylor 	hca_attr->hca_max_port_sgid_tbl_sz = (uint_t)val;
27279e39c5baSBill Taylor 	val	= ((uint64_t)1 << state->hs_cfg_profile->cp_log_max_pkeytbl);
27289e39c5baSBill Taylor 	hca_attr->hca_max_port_pkey_tbl_sz = (uint16_t)val;
27299e39c5baSBill Taylor 
27309e39c5baSBill Taylor 	/* Determine max number of PDs */
27319e39c5baSBill Taylor 	maxval	= ((uint64_t)1 << state->hs_devlim.log_max_pd);
27329e39c5baSBill Taylor 	val	= ((uint64_t)1 << state->hs_cfg_profile->cp_log_num_pd);
27339e39c5baSBill Taylor 	if (val > maxval) {
27349e39c5baSBill Taylor 		kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
27359e39c5baSBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf,
27369e39c5baSBill Taylor 		    "soft_state_init_toomanypd_fail");
27379e39c5baSBill Taylor 		return (DDI_FAILURE);
27389e39c5baSBill Taylor 	}
27399e39c5baSBill Taylor 	hca_attr->hca_max_pd = (uint_t)val;
27409e39c5baSBill Taylor 
27419e39c5baSBill Taylor 	/* Determine max number of Address Handles (NOT IN ARBEL or HERMON) */
27429e39c5baSBill Taylor 	hca_attr->hca_max_ah = 0;
27439e39c5baSBill Taylor 
27449e39c5baSBill Taylor 	/* No RDDs or EECs (since Reliable Datagram is not supported) */
27459e39c5baSBill Taylor 	hca_attr->hca_max_rdd = 0;
27469e39c5baSBill Taylor 	hca_attr->hca_max_eec = 0;
27479e39c5baSBill Taylor 
27489e39c5baSBill Taylor 	/* Initialize lock for reserved UAR page access */
27499e39c5baSBill Taylor 	mutex_init(&state->hs_uar_lock, NULL, MUTEX_DRIVER,
27509e39c5baSBill Taylor 	    DDI_INTR_PRI(state->hs_intrmsi_pri));
27519e39c5baSBill Taylor 
27529e39c5baSBill Taylor 	/* Initialize the flash fields */
27539e39c5baSBill Taylor 	state->hs_fw_flashstarted = 0;
27549e39c5baSBill Taylor 	mutex_init(&state->hs_fw_flashlock, NULL, MUTEX_DRIVER,
27559e39c5baSBill Taylor 	    DDI_INTR_PRI(state->hs_intrmsi_pri));
27569e39c5baSBill Taylor 
27579e39c5baSBill Taylor 	/* Initialize the lock for the info ioctl */
27589e39c5baSBill Taylor 	mutex_init(&state->hs_info_lock, NULL, MUTEX_DRIVER,
27599e39c5baSBill Taylor 	    DDI_INTR_PRI(state->hs_intrmsi_pri));
27609e39c5baSBill Taylor 
27619e39c5baSBill Taylor 	/* Initialize the AVL tree for QP number support */
27629e39c5baSBill Taylor 	hermon_qpn_avl_init(state);
27639e39c5baSBill Taylor 
276417a2b317SBill Taylor 	/* Initialize the cq_sched info structure */
276517a2b317SBill Taylor 	status = hermon_cq_sched_init(state);
276617a2b317SBill Taylor 	if (status != DDI_SUCCESS) {
276717a2b317SBill Taylor 		hermon_qpn_avl_fini(state);
276817a2b317SBill Taylor 		mutex_destroy(&state->hs_info_lock);
276917a2b317SBill Taylor 		mutex_destroy(&state->hs_fw_flashlock);
277017a2b317SBill Taylor 		mutex_destroy(&state->hs_uar_lock);
277117a2b317SBill Taylor 		kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
277217a2b317SBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf,
277317a2b317SBill Taylor 		    "soft_state_init_cqsched_init_fail");
277417a2b317SBill Taylor 		return (DDI_FAILURE);
277517a2b317SBill Taylor 	}
277617a2b317SBill Taylor 
277717a2b317SBill Taylor 	/* Initialize the fcoib info structure */
277817a2b317SBill Taylor 	status = hermon_fcoib_init(state);
277917a2b317SBill Taylor 	if (status != DDI_SUCCESS) {
278017a2b317SBill Taylor 		hermon_cq_sched_fini(state);
278117a2b317SBill Taylor 		hermon_qpn_avl_fini(state);
278217a2b317SBill Taylor 		mutex_destroy(&state->hs_info_lock);
278317a2b317SBill Taylor 		mutex_destroy(&state->hs_fw_flashlock);
278417a2b317SBill Taylor 		mutex_destroy(&state->hs_uar_lock);
278517a2b317SBill Taylor 		kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
278617a2b317SBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf,
278717a2b317SBill Taylor 		    "soft_state_init_fcoibinit_fail");
278817a2b317SBill Taylor 		return (DDI_FAILURE);
278917a2b317SBill Taylor 	}
279017a2b317SBill Taylor 
27919e39c5baSBill Taylor 	/* Initialize the kstat info structure */
27929e39c5baSBill Taylor 	status = hermon_kstat_init(state);
27939e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
279417a2b317SBill Taylor 		hermon_fcoib_fini(state);
279517a2b317SBill Taylor 		hermon_cq_sched_fini(state);
27969e39c5baSBill Taylor 		hermon_qpn_avl_fini(state);
27979e39c5baSBill Taylor 		mutex_destroy(&state->hs_info_lock);
27989e39c5baSBill Taylor 		mutex_destroy(&state->hs_fw_flashlock);
27999e39c5baSBill Taylor 		mutex_destroy(&state->hs_uar_lock);
28009e39c5baSBill Taylor 		kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
28019e39c5baSBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf,
28029e39c5baSBill Taylor 		    "soft_state_init_kstatinit_fail");
28039e39c5baSBill Taylor 		return (DDI_FAILURE);
28049e39c5baSBill Taylor 	}
28059e39c5baSBill Taylor 
28069e39c5baSBill Taylor 	return (DDI_SUCCESS);
28079e39c5baSBill Taylor }
28089e39c5baSBill Taylor 
28099e39c5baSBill Taylor 
28109e39c5baSBill Taylor /*
28119e39c5baSBill Taylor  * hermon_soft_state_fini()
28129e39c5baSBill Taylor  *    Context: Called only from detach() path context
28139e39c5baSBill Taylor  */
28149e39c5baSBill Taylor static void
hermon_soft_state_fini(hermon_state_t * state)28159e39c5baSBill Taylor hermon_soft_state_fini(hermon_state_t *state)
28169e39c5baSBill Taylor {
28179e39c5baSBill Taylor 
28189e39c5baSBill Taylor 	/* Teardown the kstat info */
28199e39c5baSBill Taylor 	hermon_kstat_fini(state);
28209e39c5baSBill Taylor 
282117a2b317SBill Taylor 	/* Teardown the fcoib info */
282217a2b317SBill Taylor 	hermon_fcoib_fini(state);
282317a2b317SBill Taylor 
282417a2b317SBill Taylor 	/* Teardown the cq_sched info */
282517a2b317SBill Taylor 	hermon_cq_sched_fini(state);
282617a2b317SBill Taylor 
28279e39c5baSBill Taylor 	/* Teardown the AVL tree for QP number support */
28289e39c5baSBill Taylor 	hermon_qpn_avl_fini(state);
28299e39c5baSBill Taylor 
28309e39c5baSBill Taylor 	/* Free up info ioctl mutex */
28319e39c5baSBill Taylor 	mutex_destroy(&state->hs_info_lock);
28329e39c5baSBill Taylor 
28339e39c5baSBill Taylor 	/* Free up flash mutex */
28349e39c5baSBill Taylor 	mutex_destroy(&state->hs_fw_flashlock);
28359e39c5baSBill Taylor 
28369e39c5baSBill Taylor 	/* Free up the UAR page access mutex */
28379e39c5baSBill Taylor 	mutex_destroy(&state->hs_uar_lock);
28389e39c5baSBill Taylor 
28399e39c5baSBill Taylor 	/* Free up the hca_attr struct */
28409e39c5baSBill Taylor 	kmem_free(state->hs_ibtfinfo.hca_attr, sizeof (ibt_hca_attr_t));
28419e39c5baSBill Taylor 
28429e39c5baSBill Taylor }
28439e39c5baSBill Taylor 
28449e39c5baSBill Taylor /*
28459e39c5baSBill Taylor  * hermon_icm_config_setup()
28469e39c5baSBill Taylor  *    Context: Only called from attach() path context
28479e39c5baSBill Taylor  */
28489e39c5baSBill Taylor static int
hermon_icm_config_setup(hermon_state_t * state,hermon_hw_initqueryhca_t * inithca)28499e39c5baSBill Taylor hermon_icm_config_setup(hermon_state_t *state,
28509e39c5baSBill Taylor     hermon_hw_initqueryhca_t *inithca)
28519e39c5baSBill Taylor {
28529e39c5baSBill Taylor 	hermon_hw_querydevlim_t	*devlim;
28539e39c5baSBill Taylor 	hermon_cfg_profile_t	*cfg;
28549e39c5baSBill Taylor 	hermon_icm_table_t	*icm_p[HERMON_NUM_ICM_RESOURCES];
28559e39c5baSBill Taylor 	hermon_icm_table_t	*icm;
28569e39c5baSBill Taylor 	hermon_icm_table_t	*tmp;
28579e39c5baSBill Taylor 	uint64_t		icm_addr;
28589e39c5baSBill Taylor 	uint64_t		icm_size;
28599e39c5baSBill Taylor 	int			status, i, j;
28609e39c5baSBill Taylor 
28619e39c5baSBill Taylor 
28629e39c5baSBill Taylor 	/* Bring in local devlims, cfg_profile and hs_icm table list */
28639e39c5baSBill Taylor 	devlim = &state->hs_devlim;
28649e39c5baSBill Taylor 	cfg = state->hs_cfg_profile;
28659e39c5baSBill Taylor 	icm = state->hs_icm;
28669e39c5baSBill Taylor 
28679e39c5baSBill Taylor 	/*
28689e39c5baSBill Taylor 	 * Assign each ICM table's entry size from data in the devlims,
28699e39c5baSBill Taylor 	 * except for RDB and MCG sizes, which are not returned in devlims
28709e39c5baSBill Taylor 	 * but do have a fixed size, and the UAR context entry size, which
28719e39c5baSBill Taylor 	 * we determine. For this, we use the "cp_num_pgs_per_uce" value
28729e39c5baSBill Taylor 	 * from our hs_cfg_profile.
28739e39c5baSBill Taylor 	 */
28749e39c5baSBill Taylor 	icm[HERMON_CMPT].object_size	= devlim->cmpt_entry_sz;
28759e39c5baSBill Taylor 	icm[HERMON_CMPT_QPC].object_size	= devlim->cmpt_entry_sz;
28769e39c5baSBill Taylor 	icm[HERMON_CMPT_SRQC].object_size	= devlim->cmpt_entry_sz;
28779e39c5baSBill Taylor 	icm[HERMON_CMPT_CQC].object_size	= devlim->cmpt_entry_sz;
28789e39c5baSBill Taylor 	icm[HERMON_CMPT_EQC].object_size	= devlim->cmpt_entry_sz;
28799e39c5baSBill Taylor 	icm[HERMON_MTT].object_size	= devlim->mtt_entry_sz;
28809e39c5baSBill Taylor 	icm[HERMON_DMPT].object_size	= devlim->dmpt_entry_sz;
28819e39c5baSBill Taylor 	icm[HERMON_QPC].object_size	= devlim->qpc_entry_sz;
28829e39c5baSBill Taylor 	icm[HERMON_CQC].object_size	= devlim->cqc_entry_sz;
28839e39c5baSBill Taylor 	icm[HERMON_SRQC].object_size	= devlim->srq_entry_sz;
28849e39c5baSBill Taylor 	icm[HERMON_EQC].object_size	= devlim->eqc_entry_sz;
28859e39c5baSBill Taylor 	icm[HERMON_RDB].object_size	= devlim->rdmardc_entry_sz *
28869e39c5baSBill Taylor 	    cfg->cp_hca_max_rdma_in_qp;
28879fa01fafSagiri 	icm[HERMON_MCG].object_size	= HERMON_MCGMEM_SZ(state);
28889e39c5baSBill Taylor 	icm[HERMON_ALTC].object_size	= devlim->altc_entry_sz;
28899e39c5baSBill Taylor 	icm[HERMON_AUXC].object_size	= devlim->aux_entry_sz;
28909e39c5baSBill Taylor 
28919e39c5baSBill Taylor 	/* Assign each ICM table's log2 number of entries */
28929e39c5baSBill Taylor 	icm[HERMON_CMPT].log_num_entries = cfg->cp_log_num_cmpt;
28939e39c5baSBill Taylor 	icm[HERMON_CMPT_QPC].log_num_entries = cfg->cp_log_num_qp;
28949e39c5baSBill Taylor 	icm[HERMON_CMPT_SRQC].log_num_entries = cfg->cp_log_num_srq;
28959e39c5baSBill Taylor 	icm[HERMON_CMPT_CQC].log_num_entries = cfg->cp_log_num_cq;
28969e39c5baSBill Taylor 	icm[HERMON_CMPT_EQC].log_num_entries = HERMON_NUM_EQ_SHIFT;
28979e39c5baSBill Taylor 	icm[HERMON_MTT].log_num_entries	= cfg->cp_log_num_mtt;
28989e39c5baSBill Taylor 	icm[HERMON_DMPT].log_num_entries = cfg->cp_log_num_dmpt;
28999e39c5baSBill Taylor 	icm[HERMON_QPC].log_num_entries	= cfg->cp_log_num_qp;
29009e39c5baSBill Taylor 	icm[HERMON_SRQC].log_num_entries = cfg->cp_log_num_srq;
29019e39c5baSBill Taylor 	icm[HERMON_CQC].log_num_entries	= cfg->cp_log_num_cq;
29029e39c5baSBill Taylor 	icm[HERMON_EQC].log_num_entries	= HERMON_NUM_EQ_SHIFT;
29039e39c5baSBill Taylor 	icm[HERMON_RDB].log_num_entries	= cfg->cp_log_num_qp;
29049e39c5baSBill Taylor 	icm[HERMON_MCG].log_num_entries	= cfg->cp_log_num_mcg;
29059e39c5baSBill Taylor 	icm[HERMON_ALTC].log_num_entries = cfg->cp_log_num_qp;
29069e39c5baSBill Taylor 	icm[HERMON_AUXC].log_num_entries = cfg->cp_log_num_qp;
29079e39c5baSBill Taylor 
29089e39c5baSBill Taylor 	/* Initialize the ICM tables */
29099e39c5baSBill Taylor 	hermon_icm_tables_init(state);
29109e39c5baSBill Taylor 
29119e39c5baSBill Taylor 	/*
29129e39c5baSBill Taylor 	 * ICM tables must be aligned on their size in the ICM address
29139e39c5baSBill Taylor 	 * space. So, here we order the tables from largest total table
29149e39c5baSBill Taylor 	 * size to the smallest. All tables are a power of 2 in size, so
29159e39c5baSBill Taylor 	 * this will ensure that all tables are aligned on their own size
29169e39c5baSBill Taylor 	 * without wasting space in the ICM.
29179e39c5baSBill Taylor 	 *
29189e39c5baSBill Taylor 	 * In order to easily set the ICM addresses without needing to
29199e39c5baSBill Taylor 	 * worry about the ordering of our table indices as relates to
29209e39c5baSBill Taylor 	 * the hermon_rsrc_type_t enum, we will use a list of pointers
29219e39c5baSBill Taylor 	 * representing the tables for the sort, then assign ICM addresses
29229e39c5baSBill Taylor 	 * below using it.
29239e39c5baSBill Taylor 	 */
29249e39c5baSBill Taylor 	for (i = 0; i < HERMON_NUM_ICM_RESOURCES; i++) {
29259e39c5baSBill Taylor 		icm_p[i] = &icm[i];
29269e39c5baSBill Taylor 	}
29279e39c5baSBill Taylor 	for (i = HERMON_NUM_ICM_RESOURCES; i > 0; i--) {
29289e39c5baSBill Taylor 		switch (i) {
29299e39c5baSBill Taylor 		case HERMON_CMPT_QPC:
29309e39c5baSBill Taylor 		case HERMON_CMPT_SRQC:
29319e39c5baSBill Taylor 		case HERMON_CMPT_CQC:
29329e39c5baSBill Taylor 		case HERMON_CMPT_EQC:
29339e39c5baSBill Taylor 			continue;
29349e39c5baSBill Taylor 		}
29359e39c5baSBill Taylor 		for (j = 1; j < i; j++) {
29369e39c5baSBill Taylor 			if (icm_p[j]->table_size > icm_p[j - 1]->table_size) {
29379e39c5baSBill Taylor 				tmp		= icm_p[j];
29389e39c5baSBill Taylor 				icm_p[j]	= icm_p[j - 1];
29399e39c5baSBill Taylor 				icm_p[j - 1]	= tmp;
29409e39c5baSBill Taylor 			}
29419e39c5baSBill Taylor 		}
29429e39c5baSBill Taylor 	}
29439e39c5baSBill Taylor 
29449e39c5baSBill Taylor 	/* Initialize the ICM address and ICM size */
29459e39c5baSBill Taylor 	icm_addr = icm_size = 0;
29469e39c5baSBill Taylor 
29479e39c5baSBill Taylor 	/*
29489e39c5baSBill Taylor 	 * Set the ICM base address of each table, using our sorted
29499e39c5baSBill Taylor 	 * list of pointers from above.
29509e39c5baSBill Taylor 	 */
29519e39c5baSBill Taylor 	for (i = 0; i < HERMON_NUM_ICM_RESOURCES; i++) {
29529e39c5baSBill Taylor 		j = icm_p[i]->icm_type;
29539e39c5baSBill Taylor 		switch (j) {
29549e39c5baSBill Taylor 		case HERMON_CMPT_QPC:
29559e39c5baSBill Taylor 		case HERMON_CMPT_SRQC:
29569e39c5baSBill Taylor 		case HERMON_CMPT_CQC:
29579e39c5baSBill Taylor 		case HERMON_CMPT_EQC:
29589e39c5baSBill Taylor 			continue;
29599e39c5baSBill Taylor 		}
29609e39c5baSBill Taylor 		if (icm[j].table_size) {
29619e39c5baSBill Taylor 			/*
29629e39c5baSBill Taylor 			 * Set the ICM base address in the table, save the
29639e39c5baSBill Taylor 			 * ICM offset in the rsrc pool and increment the
29649e39c5baSBill Taylor 			 * total ICM allocation.
29659e39c5baSBill Taylor 			 */
29669e39c5baSBill Taylor 			icm[j].icm_baseaddr = icm_addr;
29679e39c5baSBill Taylor 			if (hermon_verbose) {
29689e39c5baSBill Taylor 				IBTF_DPRINTF_L2("ICMADDR", "rsrc %x @ %p"
29699e39c5baSBill Taylor 				    " size %llx", j, icm[j].icm_baseaddr,
29709e39c5baSBill Taylor 				    icm[j].table_size);
29719e39c5baSBill Taylor 			}
29729e39c5baSBill Taylor 			icm_size += icm[j].table_size;
29739e39c5baSBill Taylor 		}
29749e39c5baSBill Taylor 
29759e39c5baSBill Taylor 		/* Verify that we don't exceed maximum ICM size */
29769e39c5baSBill Taylor 		if (icm_size > devlim->max_icm_size) {
29779e39c5baSBill Taylor 			/* free the ICM table memory resources */
29789e39c5baSBill Taylor 			hermon_icm_tables_fini(state);
29799e39c5baSBill Taylor 			cmn_err(CE_WARN, "ICM configuration exceeds maximum "
29809e39c5baSBill Taylor 			    "configuration: max (0x%lx) requested (0x%lx)\n",
29819e39c5baSBill Taylor 			    (ulong_t)devlim->max_icm_size, (ulong_t)icm_size);
29829e39c5baSBill Taylor 			HERMON_ATTACH_MSG(state->hs_attach_buf,
29839e39c5baSBill Taylor 			    "icm_config_toobig_fail");
29849e39c5baSBill Taylor 			return (DDI_FAILURE);
29859e39c5baSBill Taylor 		}
29869e39c5baSBill Taylor 
29879e39c5baSBill Taylor 		/* assign address to the 4 pieces of the CMPT */
29889e39c5baSBill Taylor 		if (j == HERMON_CMPT) {
29899e39c5baSBill Taylor 			uint64_t cmpt_size = icm[j].table_size >> 2;
29909e39c5baSBill Taylor #define	init_cmpt_icm_baseaddr(rsrc, indx)				\
29919e39c5baSBill Taylor 	icm[rsrc].icm_baseaddr	= icm_addr + (indx * cmpt_size);
29929e39c5baSBill Taylor 			init_cmpt_icm_baseaddr(HERMON_CMPT_QPC, 0);
29939e39c5baSBill Taylor 			init_cmpt_icm_baseaddr(HERMON_CMPT_SRQC, 1);
29949e39c5baSBill Taylor 			init_cmpt_icm_baseaddr(HERMON_CMPT_CQC, 2);
29959e39c5baSBill Taylor 			init_cmpt_icm_baseaddr(HERMON_CMPT_EQC, 3);
29969e39c5baSBill Taylor 		}
29979e39c5baSBill Taylor 
29989e39c5baSBill Taylor 		/* Increment the ICM address for the next table */
29999e39c5baSBill Taylor 		icm_addr += icm[j].table_size;
30009e39c5baSBill Taylor 	}
30019e39c5baSBill Taylor 
30029e39c5baSBill Taylor 	/* Populate the structure for the INIT_HCA command */
30039e39c5baSBill Taylor 	hermon_inithca_set(state, inithca);
30049e39c5baSBill Taylor 
30059e39c5baSBill Taylor 	/*
30069e39c5baSBill Taylor 	 * Prior to invoking INIT_HCA, we must have ICM memory in place
30079e39c5baSBill Taylor 	 * for the reserved objects in each table. We will allocate and map
30089e39c5baSBill Taylor 	 * this initial ICM memory here. Note that given the assignment
30099e39c5baSBill Taylor 	 * of span_size above, tables that are smaller or equal in total
30109e39c5baSBill Taylor 	 * size to the default span_size will be mapped in full.
30119e39c5baSBill Taylor 	 */
30129e39c5baSBill Taylor 	status = hermon_icm_dma_init(state);
30139e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
30149e39c5baSBill Taylor 		/* free the ICM table memory resources */
30159e39c5baSBill Taylor 		hermon_icm_tables_fini(state);
30169e39c5baSBill Taylor 		HERMON_WARNING(state, "Failed to allocate initial ICM");
30179e39c5baSBill Taylor 		HERMON_ATTACH_MSG(state->hs_attach_buf,
30189e39c5baSBill Taylor 		    "icm_config_dma_init_fail");
30199e39c5baSBill Taylor 		return (DDI_FAILURE);
30209e39c5baSBill Taylor 	}
30219e39c5baSBill Taylor 
30229e39c5baSBill Taylor 	return (DDI_SUCCESS);
30239e39c5baSBill Taylor }
30249e39c5baSBill Taylor 
30259e39c5baSBill Taylor /*
30269e39c5baSBill Taylor  * hermon_inithca_set()
30279e39c5baSBill Taylor  *    Context: Only called from attach() path context
30289e39c5baSBill Taylor  */
30299e39c5baSBill Taylor static void
hermon_inithca_set(hermon_state_t * state,hermon_hw_initqueryhca_t * inithca)30309e39c5baSBill Taylor hermon_inithca_set(hermon_state_t *state, hermon_hw_initqueryhca_t *inithca)
30319e39c5baSBill Taylor {
30329e39c5baSBill Taylor 	hermon_cfg_profile_t	*cfg;
30339e39c5baSBill Taylor 	hermon_icm_table_t	*icm;
30349e39c5baSBill Taylor 	int			i;
30359e39c5baSBill Taylor 
30369e39c5baSBill Taylor 
30379e39c5baSBill Taylor 	/* Populate the INIT_HCA structure */
30389e39c5baSBill Taylor 	icm = state->hs_icm;
30399e39c5baSBill Taylor 	cfg = state->hs_cfg_profile;
30409e39c5baSBill Taylor 
30419e39c5baSBill Taylor 	/* set version */
30429e39c5baSBill Taylor 	inithca->version = 0x02;	/* PRM 0.36 */
30439e39c5baSBill Taylor 	/* set cacheline - log2 in 16-byte chunks */
30449e39c5baSBill Taylor 	inithca->log2_cacheline = 0x2;	/* optimized for 64 byte cache */
30459e39c5baSBill Taylor 
30469e39c5baSBill Taylor 	/* we need to update the inithca info with thie UAR info too */
30479e39c5baSBill Taylor 	inithca->uar.log_max_uars = highbit(cfg->cp_log_num_uar);
30489e39c5baSBill Taylor 	inithca->uar.uar_pg_sz = PAGESHIFT - HERMON_PAGESHIFT;
30499e39c5baSBill Taylor 
30509e39c5baSBill Taylor 	/* Set endianess */
30519e39c5baSBill Taylor #ifdef	_LITTLE_ENDIAN
30529e39c5baSBill Taylor 	inithca->big_endian	= 0;
30539e39c5baSBill Taylor #else
30549e39c5baSBill Taylor 	inithca->big_endian	= 1;
30559e39c5baSBill Taylor #endif
30569e39c5baSBill Taylor 
30579e39c5baSBill Taylor 	/* Port Checking is on by default */
30589e39c5baSBill Taylor 	inithca->udav_port_chk	= HERMON_UDAV_PORTCHK_ENABLED;
30599e39c5baSBill Taylor 
30609e39c5baSBill Taylor 	/* Enable IPoIB checksum */
30619e39c5baSBill Taylor 	if (state->hs_devlim.ipoib_cksm)
30629e39c5baSBill Taylor 		inithca->chsum_en = 1;
30639e39c5baSBill Taylor 
30649e39c5baSBill Taylor 	/* Set each ICM table's attributes */
30659e39c5baSBill Taylor 	for (i = 0; i < HERMON_NUM_ICM_RESOURCES; i++) {
30669e39c5baSBill Taylor 		switch (icm[i].icm_type) {
30679e39c5baSBill Taylor 		case HERMON_CMPT:
30689e39c5baSBill Taylor 			inithca->tpt.cmpt_baseaddr = icm[i].icm_baseaddr;
30699e39c5baSBill Taylor 			break;
30709e39c5baSBill Taylor 
30719e39c5baSBill Taylor 		case HERMON_MTT:
30729e39c5baSBill Taylor 			inithca->tpt.mtt_baseaddr = icm[i].icm_baseaddr;
30739e39c5baSBill Taylor 			break;
30749e39c5baSBill Taylor 
30759e39c5baSBill Taylor 		case HERMON_DMPT:
30769e39c5baSBill Taylor 			inithca->tpt.dmpt_baseaddr = icm[i].icm_baseaddr;
30779e39c5baSBill Taylor 			inithca->tpt.log_dmpt_sz   = icm[i].log_num_entries;
30789e39c5baSBill Taylor 			inithca->tpt.pgfault_rnr_to = 0; /* just in case */
30799e39c5baSBill Taylor 			break;
30809e39c5baSBill Taylor 
30819e39c5baSBill Taylor 		case HERMON_QPC:
30829e39c5baSBill Taylor 			inithca->context.log_num_qp = icm[i].log_num_entries;
30839e39c5baSBill Taylor 			inithca->context.qpc_baseaddr_h =
30849e39c5baSBill Taylor 			    icm[i].icm_baseaddr >> 32;
30859e39c5baSBill Taylor 			inithca->context.qpc_baseaddr_l =
30869e39c5baSBill Taylor 			    (icm[i].icm_baseaddr & 0xFFFFFFFF) >> 5;
30879e39c5baSBill Taylor 			break;
30889e39c5baSBill Taylor 
30899e39c5baSBill Taylor 		case HERMON_CQC:
30909e39c5baSBill Taylor 			inithca->context.log_num_cq = icm[i].log_num_entries;
30919e39c5baSBill Taylor 			inithca->context.cqc_baseaddr_h =
30929e39c5baSBill Taylor 			    icm[i].icm_baseaddr >> 32;
30939e39c5baSBill Taylor 			inithca->context.cqc_baseaddr_l =
30949e39c5baSBill Taylor 			    (icm[i].icm_baseaddr & 0xFFFFFFFF) >> 5;
30959e39c5baSBill Taylor 			break;
30969e39c5baSBill Taylor 
30979e39c5baSBill Taylor 		case HERMON_SRQC:
30989e39c5baSBill Taylor 			inithca->context.log_num_srq = icm[i].log_num_entries;
30999e39c5baSBill Taylor 			inithca->context.srqc_baseaddr_h =
31009e39c5baSBill Taylor 			    icm[i].icm_baseaddr >> 32;
31019e39c5baSBill Taylor 			inithca->context.srqc_baseaddr_l =
31029e39c5baSBill Taylor 			    (icm[i].icm_baseaddr & 0xFFFFFFFF) >> 5;
31039e39c5baSBill Taylor 			break;
31049e39c5baSBill Taylor 
31059e39c5baSBill Taylor 		case HERMON_EQC:
31069e39c5baSBill Taylor 			inithca->context.log_num_eq = icm[i].log_num_entries;
31079e39c5baSBill Taylor 			inithca->context.eqc_baseaddr_h =
31089e39c5baSBill Taylor 			    icm[i].icm_baseaddr >> 32;
31099e39c5baSBill Taylor 			inithca->context.eqc_baseaddr_l =
31109e39c5baSBill Taylor 			    (icm[i].icm_baseaddr & 0xFFFFFFFF) >> 5;
31119e39c5baSBill Taylor 			break;
31129e39c5baSBill Taylor 
31139e39c5baSBill Taylor 		case HERMON_RDB:
31149e39c5baSBill Taylor 			inithca->context.rdmardc_baseaddr_h =
31159e39c5baSBill Taylor 			    icm[i].icm_baseaddr >> 32;
31169e39c5baSBill Taylor 			inithca->context.rdmardc_baseaddr_l =
31179e39c5baSBill Taylor 			    (icm[i].icm_baseaddr & 0xFFFFFFFF) >> 5;
31189e39c5baSBill Taylor 			inithca->context.log_num_rdmardc =
311980ba5585SBill Taylor 			    cfg->cp_log_num_rdb - cfg->cp_log_num_qp;
31209e39c5baSBill Taylor 			break;
31219e39c5baSBill Taylor 
31229e39c5baSBill Taylor 		case HERMON_MCG:
31239e39c5baSBill Taylor 			inithca->multi.mc_baseaddr    = icm[i].icm_baseaddr;
31249e39c5baSBill Taylor 			inithca->multi.log_mc_tbl_sz  = icm[i].log_num_entries;
31259e39c5baSBill Taylor 			inithca->multi.log_mc_tbl_ent =
31269e39c5baSBill Taylor 			    highbit(HERMON_MCGMEM_SZ(state)) - 1;
31279e39c5baSBill Taylor 			inithca->multi.log_mc_tbl_hash_sz =
31289e39c5baSBill Taylor 			    cfg->cp_log_num_mcg_hash;
31299e39c5baSBill Taylor 			inithca->multi.mc_hash_fn = HERMON_MCG_DEFAULT_HASH_FN;
31309e39c5baSBill Taylor 			break;
31319e39c5baSBill Taylor 
31329e39c5baSBill Taylor 		case HERMON_ALTC:
31339e39c5baSBill Taylor 			inithca->context.altc_baseaddr = icm[i].icm_baseaddr;
31349e39c5baSBill Taylor 			break;
31359e39c5baSBill Taylor 
31369e39c5baSBill Taylor 		case HERMON_AUXC:
31379e39c5baSBill Taylor 			inithca->context.auxc_baseaddr = icm[i].icm_baseaddr;
31389e39c5baSBill Taylor 			break;
31399e39c5baSBill Taylor 
31409e39c5baSBill Taylor 		default:
31419e39c5baSBill Taylor 			break;
31429e39c5baSBill Taylor 
31439e39c5baSBill Taylor 		}
31449e39c5baSBill Taylor 	}
31459e39c5baSBill Taylor 
31469e39c5baSBill Taylor }
31479e39c5baSBill Taylor 
31489e39c5baSBill Taylor /*
31499e39c5baSBill Taylor  * hermon_icm_tables_init()
31509e39c5baSBill Taylor  *    Context: Only called from attach() path context
31519e39c5baSBill Taylor  *
31529e39c5baSBill Taylor  * Dynamic ICM breaks the various ICM tables into "span_size" chunks
31539e39c5baSBill Taylor  * to enable allocation of backing memory on demand.  Arbel used a
31549e39c5baSBill Taylor  * fixed size ARBEL_ICM_SPAN_SIZE (initially was 512KB) as the
31559e39c5baSBill Taylor  * span_size for all ICM chunks.  Hermon has other considerations,
31569e39c5baSBill Taylor  * so the span_size used differs from Arbel.
31579e39c5baSBill Taylor  *
31589e39c5baSBill Taylor  * The basic considerations for why Hermon differs are:
31599e39c5baSBill Taylor  *
31609e39c5baSBill Taylor  *	1) ICM memory is in units of HERMON pages.
31619e39c5baSBill Taylor  *
31629e39c5baSBill Taylor  *	2) The AUXC table is approximately 1 byte per QP.
31639e39c5baSBill Taylor  *
31649e39c5baSBill Taylor  *	3) ICM memory for AUXC, ALTC, and RDB is allocated when
31659e39c5baSBill Taylor  *	the ICM memory for the corresponding QPC is allocated.
31669e39c5baSBill Taylor  *
31679e39c5baSBill Taylor  *	4) ICM memory for the CMPT corresponding to the various primary
31689e39c5baSBill Taylor  *	resources (QPC, SRQC, CQC, and EQC) is allocated when the ICM
31699e39c5baSBill Taylor  *	memory for the primary resource is allocated.
31709e39c5baSBill Taylor  *
31719e39c5baSBill Taylor  * One HERMON page (4KB) would typically map 4K QPs worth of AUXC.
31729e39c5baSBill Taylor  * So, the minimum chunk for the various QPC related ICM memory should
31739e39c5baSBill Taylor  * all be allocated to support the 4K QPs.  Currently, this means the
31749e39c5baSBill Taylor  * amount of memory for the various QP chunks is:
31759e39c5baSBill Taylor  *
31769e39c5baSBill Taylor  *	QPC	256*4K bytes
31779e39c5baSBill Taylor  *	RDB	128*4K bytes
31789e39c5baSBill Taylor  *	CMPT	 64*4K bytes
31799e39c5baSBill Taylor  *	ALTC	 64*4K bytes
31809e39c5baSBill Taylor  *	AUXC	  1*4K bytes
31819e39c5baSBill Taylor  *
31829e39c5baSBill Taylor  * The span_size chosen for the QP resource is 4KB of AUXC entries,
31839e39c5baSBill Taylor  * or 1 HERMON_PAGESIZE worth, which is the minimum ICM mapping size.
31849e39c5baSBill Taylor  *
31859e39c5baSBill Taylor  * Other ICM resources can have their span_size be more arbitrary.
31869e39c5baSBill Taylor  * This is 4K (HERMON_ICM_SPAN), except for MTTs because they are tiny.
31879e39c5baSBill Taylor  */
31889e39c5baSBill Taylor 
31899e39c5baSBill Taylor /* macro to make the code below cleaner */
31909e39c5baSBill Taylor #define	init_dependent(rsrc, dep)				\
31919e39c5baSBill Taylor 	icm[dep].span		= icm[rsrc].span;		\
31929e39c5baSBill Taylor 	icm[dep].num_spans	= icm[rsrc].num_spans;		\
31939e39c5baSBill Taylor 	icm[dep].split_shift	= icm[rsrc].split_shift;	\
31949e39c5baSBill Taylor 	icm[dep].span_mask	= icm[rsrc].span_mask;		\
31959e39c5baSBill Taylor 	icm[dep].span_shift	= icm[rsrc].span_shift;		\
31969e39c5baSBill Taylor 	icm[dep].rsrc_mask	= icm[rsrc].rsrc_mask;		\
31979e39c5baSBill Taylor 	if (hermon_verbose) {					\
31989e39c5baSBill Taylor 		IBTF_DPRINTF_L2("hermon", "tables_init: "	\
31999e39c5baSBill Taylor 		    "rsrc (0x%x) size (0x%lx) span (0x%x) "	\
32009e39c5baSBill Taylor 		    "num_spans (0x%x)", dep, icm[dep].table_size, \
32019e39c5baSBill Taylor 		    icm[dep].span, icm[dep].num_spans);		\
32029e39c5baSBill Taylor 		IBTF_DPRINTF_L2("hermon", "tables_init: "	\
32039e39c5baSBill Taylor 		    "span_shift (0x%x) split_shift (0x%x)",	\
32049e39c5baSBill Taylor 		    icm[dep].span_shift, icm[dep].split_shift);	\
32059e39c5baSBill Taylor 		IBTF_DPRINTF_L2("hermon", "tables_init: "	\
32069e39c5baSBill Taylor 		    "span_mask (0x%x)  rsrc_mask   (0x%x)",	\
32079e39c5baSBill Taylor 		    icm[dep].span_mask, icm[dep].rsrc_mask);	\
32089e39c5baSBill Taylor 	}
32099e39c5baSBill Taylor 
32109e39c5baSBill Taylor static void
hermon_icm_tables_init(hermon_state_t * state)32119e39c5baSBill Taylor hermon_icm_tables_init(hermon_state_t *state)
32129e39c5baSBill Taylor {
32139e39c5baSBill Taylor 	hermon_icm_table_t	*icm;
32149e39c5baSBill Taylor 	int			i, k;
32159e39c5baSBill Taylor 	uint32_t		per_split;
32169e39c5baSBill Taylor 
32179e39c5baSBill Taylor 
32189e39c5baSBill Taylor 	icm = state->hs_icm;
32199e39c5baSBill Taylor 
32209e39c5baSBill Taylor 	for (i = 0; i < HERMON_NUM_ICM_RESOURCES; i++) {
32219e39c5baSBill Taylor 		icm[i].icm_type		= i;
32229e39c5baSBill Taylor 		icm[i].num_entries	= 1 << icm[i].log_num_entries;
32239e39c5baSBill Taylor 		icm[i].log_object_size	= highbit(icm[i].object_size) - 1;
32249e39c5baSBill Taylor 		icm[i].table_size	= icm[i].num_entries <<
32259e39c5baSBill Taylor 		    icm[i].log_object_size;
32269e39c5baSBill Taylor 
32279e39c5baSBill Taylor 		/* deal with "dependent" resource types */
32289e39c5baSBill Taylor 		switch (i) {
32299e39c5baSBill Taylor 		case HERMON_AUXC:
32309e39c5baSBill Taylor #ifdef HERMON_FW_WORKAROUND
32319e39c5baSBill Taylor 			icm[i].table_size = 0x80000000ull;
32329e39c5baSBill Taylor #endif
323399164022SToomas Soome 			/* FALLTHROUGH */
32349e39c5baSBill Taylor 		case HERMON_CMPT_QPC:
32359e39c5baSBill Taylor 		case HERMON_RDB:
32369e39c5baSBill Taylor 		case HERMON_ALTC:
32379e39c5baSBill Taylor 			init_dependent(HERMON_QPC, i);
32389e39c5baSBill Taylor 			continue;
32399e39c5baSBill Taylor 		case HERMON_CMPT_SRQC:
32409e39c5baSBill Taylor 			init_dependent(HERMON_SRQC, i);
32419e39c5baSBill Taylor 			continue;
32429e39c5baSBill Taylor 		case HERMON_CMPT_CQC:
32439e39c5baSBill Taylor 			init_dependent(HERMON_CQC, i);
32449e39c5baSBill Taylor 			continue;
32459e39c5baSBill Taylor 		case HERMON_CMPT_EQC:
32469e39c5baSBill Taylor 			init_dependent(HERMON_EQC, i);
32479e39c5baSBill Taylor 			continue;
32489e39c5baSBill Taylor 		}
32499e39c5baSBill Taylor 
32509e39c5baSBill Taylor 		icm[i].span = HERMON_ICM_SPAN;	/* default #rsrc's in 1 span */
32519e39c5baSBill Taylor 		if (i == HERMON_MTT) /* Alloc enough MTTs to map 256MB */
32529e39c5baSBill Taylor 			icm[i].span = HERMON_ICM_SPAN * 16;
32539e39c5baSBill Taylor 		icm[i].num_spans = icm[i].num_entries / icm[i].span;
32549e39c5baSBill Taylor 		if (icm[i].num_spans == 0) {
32559e39c5baSBill Taylor 			icm[i].span = icm[i].num_entries;
32569e39c5baSBill Taylor 			per_split = 1;
32579e39c5baSBill Taylor 			icm[i].num_spans = icm[i].num_entries / icm[i].span;
32589e39c5baSBill Taylor 		} else {
32599e39c5baSBill Taylor 			per_split = icm[i].num_spans / HERMON_ICM_SPLIT;
32609e39c5baSBill Taylor 			if (per_split == 0) {
32619e39c5baSBill Taylor 				per_split = 1;
32629e39c5baSBill Taylor 			}
32639e39c5baSBill Taylor 		}
32649e39c5baSBill Taylor 		if (hermon_verbose)
32659e39c5baSBill Taylor 			IBTF_DPRINTF_L2("ICM", "rsrc %x  span %x  num_spans %x",
32669e39c5baSBill Taylor 			    i, icm[i].span, icm[i].num_spans);
32679e39c5baSBill Taylor 
32689e39c5baSBill Taylor 		/*
32699e39c5baSBill Taylor 		 * Ensure a minimum table size of an ICM page, and a
32709e39c5baSBill Taylor 		 * maximum span size of the ICM table size.  This ensures
32719e39c5baSBill Taylor 		 * that we don't have less than an ICM page to map, which is
32729e39c5baSBill Taylor 		 * impossible, and that we will map an entire table at
32739e39c5baSBill Taylor 		 * once if it's total size is less than the span size.
32749e39c5baSBill Taylor 		 */
32759e39c5baSBill Taylor 		icm[i].table_size = max(icm[i].table_size, HERMON_PAGESIZE);
32769e39c5baSBill Taylor 
32779e39c5baSBill Taylor 		icm[i].span_shift = 0;
32789e39c5baSBill Taylor 		for (k = icm[i].span; k != 1; k >>= 1)
32799e39c5baSBill Taylor 			icm[i].span_shift++;
32809e39c5baSBill Taylor 		icm[i].split_shift = icm[i].span_shift;
32819e39c5baSBill Taylor 		for (k = per_split; k != 1; k >>= 1)
32829e39c5baSBill Taylor 			icm[i].split_shift++;
32839e39c5baSBill Taylor 		icm[i].span_mask = (1 << icm[i].split_shift) -
32849e39c5baSBill Taylor 		    (1 << icm[i].span_shift);
32859e39c5baSBill Taylor 		icm[i].rsrc_mask = (1 << icm[i].span_shift) - 1;
32869e39c5baSBill Taylor 
32879e39c5baSBill Taylor 
32889e39c5baSBill Taylor 		/* Initialize the table lock */
32899e39c5baSBill Taylor 		mutex_init(&icm[i].icm_table_lock, NULL, MUTEX_DRIVER,
32909e39c5baSBill Taylor 		    DDI_INTR_PRI(state->hs_intrmsi_pri));
32919e39c5baSBill Taylor 		cv_init(&icm[i].icm_table_cv, NULL, CV_DRIVER, NULL);
32929e39c5baSBill Taylor 
32939e39c5baSBill Taylor 		if (hermon_verbose) {
32949e39c5baSBill Taylor 			IBTF_DPRINTF_L2("hermon", "tables_init: "
32959e39c5baSBill Taylor 			    "rsrc (0x%x) size (0x%lx)", i, icm[i].table_size);
32969e39c5baSBill Taylor 			IBTF_DPRINTF_L2("hermon", "tables_init: "
32979e39c5baSBill Taylor 			    "span (0x%x) num_spans (0x%x)",
32989e39c5baSBill Taylor 			    icm[i].span, icm[i].num_spans);
32999e39c5baSBill Taylor 			IBTF_DPRINTF_L2("hermon", "tables_init: "
33009e39c5baSBill Taylor 			    "span_shift (0x%x) split_shift (0x%x)",
33019e39c5baSBill Taylor 			    icm[i].span_shift, icm[i].split_shift);
33029e39c5baSBill Taylor 			IBTF_DPRINTF_L2("hermon", "tables_init: "
33039e39c5baSBill Taylor 			    "span_mask (0x%x)  rsrc_mask   (0x%x)",
33049e39c5baSBill Taylor 			    icm[i].span_mask, icm[i].rsrc_mask);
33059e39c5baSBill Taylor 		}
33069e39c5baSBill Taylor 	}
33079e39c5baSBill Taylor 
33089e39c5baSBill Taylor }
33099e39c5baSBill Taylor 
33109e39c5baSBill Taylor /*
33119e39c5baSBill Taylor  * hermon_icm_tables_fini()
33129e39c5baSBill Taylor  *    Context: Only called from attach() path context
33139e39c5baSBill Taylor  *
33149e39c5baSBill Taylor  * Clean up all icm_tables.  Free the bitmap and dma_info arrays.
33159e39c5baSBill Taylor  */
33169e39c5baSBill Taylor static void
hermon_icm_tables_fini(hermon_state_t * state)33179e39c5baSBill Taylor hermon_icm_tables_fini(hermon_state_t *state)
33189e39c5baSBill Taylor {
33199e39c5baSBill Taylor 	hermon_icm_table_t	*icm;
33209e39c5baSBill Taylor 	int			nspans;
33219e39c5baSBill Taylor 	int			i, j;
33229e39c5baSBill Taylor 
33239e39c5baSBill Taylor 
33249e39c5baSBill Taylor 	icm = state->hs_icm;
33259e39c5baSBill Taylor 
33269e39c5baSBill Taylor 	for (i = 0; i < HERMON_NUM_ICM_RESOURCES; i++) {
33279e39c5baSBill Taylor 
33289e39c5baSBill Taylor 		mutex_enter(&icm[i].icm_table_lock);
33299e39c5baSBill Taylor 		nspans = icm[i].num_spans;
33309e39c5baSBill Taylor 
33319e39c5baSBill Taylor 		for (j = 0; j < HERMON_ICM_SPLIT; j++) {
33329e39c5baSBill Taylor 			if (icm[i].icm_dma[j])
33339e39c5baSBill Taylor 				/* Free the ICM DMA slots */
33349e39c5baSBill Taylor 				kmem_free(icm[i].icm_dma[j],
33359e39c5baSBill Taylor 				    nspans * sizeof (hermon_dma_info_t));
33369e39c5baSBill Taylor 
33379e39c5baSBill Taylor 			if (icm[i].icm_bitmap[j])
33389e39c5baSBill Taylor 				/* Free the table bitmap */
33399e39c5baSBill Taylor 				kmem_free(icm[i].icm_bitmap[j],
33409e39c5baSBill Taylor 				    (nspans + 7) / 8);
33419e39c5baSBill Taylor 		}
33429e39c5baSBill Taylor 		/* Destroy the table lock */
33439e39c5baSBill Taylor 		cv_destroy(&icm[i].icm_table_cv);
33449e39c5baSBill Taylor 		mutex_exit(&icm[i].icm_table_lock);
33459e39c5baSBill Taylor 		mutex_destroy(&icm[i].icm_table_lock);
33469e39c5baSBill Taylor 	}
33479e39c5baSBill Taylor 
33489e39c5baSBill Taylor }
33499e39c5baSBill Taylor 
33509e39c5baSBill Taylor /*
33519e39c5baSBill Taylor  * hermon_icm_dma_init()
33529e39c5baSBill Taylor  *    Context: Only called from attach() path context
33539e39c5baSBill Taylor  */
33549e39c5baSBill Taylor static int
hermon_icm_dma_init(hermon_state_t * state)33559e39c5baSBill Taylor hermon_icm_dma_init(hermon_state_t *state)
33569e39c5baSBill Taylor {
33579e39c5baSBill Taylor 	hermon_icm_table_t	*icm;
33589e39c5baSBill Taylor 	hermon_rsrc_type_t	type;
33599e39c5baSBill Taylor 	int			status;
33609e39c5baSBill Taylor 
33619e39c5baSBill Taylor 
33629e39c5baSBill Taylor 	/*
33639e39c5baSBill Taylor 	 * This routine will allocate initial ICM DMA resources for ICM
33649e39c5baSBill Taylor 	 * tables that have reserved ICM objects. This is the only routine
33659e39c5baSBill Taylor 	 * where we should have to allocate ICM outside of hermon_rsrc_alloc().
33669e39c5baSBill Taylor 	 * We need to allocate ICM here explicitly, rather than in
33679e39c5baSBill Taylor 	 * hermon_rsrc_alloc(), because we've not yet completed the resource
33689e39c5baSBill Taylor 	 * pool initialization. When the resource pools are initialized
33699e39c5baSBill Taylor 	 * (in hermon_rsrc_init_phase2(), see hermon_rsrc.c for more
33709e39c5baSBill Taylor 	 * information), resource preallocations will be invoked to match
33719e39c5baSBill Taylor 	 * the ICM allocations seen here. We will then be able to use the
33729e39c5baSBill Taylor 	 * normal allocation path.  Note we don't need to set a refcnt on
33739e39c5baSBill Taylor 	 * these initial allocations because that will be done in the calls
33749e39c5baSBill Taylor 	 * to hermon_rsrc_alloc() from hermon_hw_entries_init() for the
33759e39c5baSBill Taylor 	 * "prealloc" objects (see hermon_rsrc.c for more information).
33769e39c5baSBill Taylor 	 */
33779e39c5baSBill Taylor 	for (type = 0; type < HERMON_NUM_ICM_RESOURCES; type++) {
33789e39c5baSBill Taylor 
33799e39c5baSBill Taylor 		/* ICM for these is allocated within hermon_icm_alloc() */
33809e39c5baSBill Taylor 		switch (type) {
33819e39c5baSBill Taylor 		case HERMON_CMPT:
33829e39c5baSBill Taylor 		case HERMON_CMPT_QPC:
33839e39c5baSBill Taylor 		case HERMON_CMPT_SRQC:
33849e39c5baSBill Taylor 		case HERMON_CMPT_CQC:
33859e39c5baSBill Taylor 		case HERMON_CMPT_EQC:
33869e39c5baSBill Taylor 		case HERMON_AUXC:
33879e39c5baSBill Taylor 		case HERMON_ALTC:
33889e39c5baSBill Taylor 		case HERMON_RDB:
33899e39c5baSBill Taylor 			continue;
33909e39c5baSBill Taylor 		}
33919e39c5baSBill Taylor 
33929e39c5baSBill Taylor 		icm = &state->hs_icm[type];
33939e39c5baSBill Taylor 
33949e39c5baSBill Taylor 		mutex_enter(&icm->icm_table_lock);
33959e39c5baSBill Taylor 		status = hermon_icm_alloc(state, type, 0, 0);
33969e39c5baSBill Taylor 		mutex_exit(&icm->icm_table_lock);
33979e39c5baSBill Taylor 		if (status != DDI_SUCCESS) {
33989e39c5baSBill Taylor 			while (type--) {
33999e39c5baSBill Taylor 				icm = &state->hs_icm[type];
34009e39c5baSBill Taylor 				mutex_enter(&icm->icm_table_lock);
34019e39c5baSBill Taylor 				hermon_icm_free(state, type, 0, 0);
34029e39c5baSBill Taylor 				mutex_exit(&icm->icm_table_lock);
34039e39c5baSBill Taylor 			}
34049e39c5baSBill Taylor 			return (DDI_FAILURE);
34059e39c5baSBill Taylor 		}
34069e39c5baSBill Taylor 
34079e39c5baSBill Taylor 		if (hermon_verbose) {
34089e39c5baSBill Taylor 			IBTF_DPRINTF_L2("hermon", "hermon_icm_dma_init: "
34099e39c5baSBill Taylor 			    "table (0x%x) index (0x%x) allocated", type, 0);
34109e39c5baSBill Taylor 		}
34119e39c5baSBill Taylor 	}
34129e39c5baSBill Taylor 
34139e39c5baSBill Taylor 	return (DDI_SUCCESS);
34149e39c5baSBill Taylor }
34159e39c5baSBill Taylor 
34169e39c5baSBill Taylor /*
34179e39c5baSBill Taylor  * hermon_icm_dma_fini()
34189e39c5baSBill Taylor  *    Context: Only called from attach() path context
34199e39c5baSBill Taylor  *
34209e39c5baSBill Taylor  * ICM has been completely unmapped.  We just free the memory here.
34219e39c5baSBill Taylor  */
34229e39c5baSBill Taylor static void
hermon_icm_dma_fini(hermon_state_t * state)34239e39c5baSBill Taylor hermon_icm_dma_fini(hermon_state_t *state)
34249e39c5baSBill Taylor {
34259e39c5baSBill Taylor 	hermon_icm_table_t	*icm;
34269e39c5baSBill Taylor 	hermon_dma_info_t	*dma_info;
34279e39c5baSBill Taylor 	hermon_rsrc_type_t	type;
34289e39c5baSBill Taylor 	int			index1, index2;
34299e39c5baSBill Taylor 
34309e39c5baSBill Taylor 
34319e39c5baSBill Taylor 	for (type = 0; type < HERMON_NUM_ICM_RESOURCES; type++) {
34329e39c5baSBill Taylor 		icm = &state->hs_icm[type];
34339e39c5baSBill Taylor 		for (index1 = 0; index1 < HERMON_ICM_SPLIT; index1++) {
34349e39c5baSBill Taylor 			dma_info = icm->icm_dma[index1];
34359e39c5baSBill Taylor 			if (dma_info == NULL)
34369e39c5baSBill Taylor 				continue;
34379e39c5baSBill Taylor 			for (index2 = 0; index2 < icm->num_spans; index2++) {
34389e39c5baSBill Taylor 				if (dma_info[index2].dma_hdl)
34399e39c5baSBill Taylor 					hermon_dma_free(&dma_info[index2]);
34409e39c5baSBill Taylor 				dma_info[index2].dma_hdl = NULL;
34419e39c5baSBill Taylor 			}
34429e39c5baSBill Taylor 		}
34439e39c5baSBill Taylor 	}
34449e39c5baSBill Taylor 
34459e39c5baSBill Taylor }
34469e39c5baSBill Taylor 
34479e39c5baSBill Taylor /*
34489e39c5baSBill Taylor  * hermon_hca_port_init()
34499e39c5baSBill Taylor  *    Context: Only called from attach() path context
34509e39c5baSBill Taylor  */
34519e39c5baSBill Taylor static int
hermon_hca_port_init(hermon_state_t * state)34529e39c5baSBill Taylor hermon_hca_port_init(hermon_state_t *state)
34539e39c5baSBill Taylor {
34549e39c5baSBill Taylor 	hermon_hw_set_port_t	*portinits, *initport;
34559e39c5baSBill Taylor 	hermon_cfg_profile_t	*cfgprof;
34569e39c5baSBill Taylor 	uint_t			num_ports;
34579e39c5baSBill Taylor 	int			i = 0, status;
34589e39c5baSBill Taylor 	uint64_t		maxval, val;
34599e39c5baSBill Taylor 	uint64_t		sysimgguid, nodeguid, portguid;
34609e39c5baSBill Taylor 
34619e39c5baSBill Taylor 
34629e39c5baSBill Taylor 	cfgprof = state->hs_cfg_profile;
34639e39c5baSBill Taylor 
34649e39c5baSBill Taylor 	/* Get number of HCA ports */
34659e39c5baSBill Taylor 	num_ports = cfgprof->cp_num_ports;
34669e39c5baSBill Taylor 
34679e39c5baSBill Taylor 	/* Allocate space for Hermon set port  struct(s) */
34689e39c5baSBill Taylor 	portinits = (hermon_hw_set_port_t *)kmem_zalloc(num_ports *
34699e39c5baSBill Taylor 	    sizeof (hermon_hw_set_port_t), KM_SLEEP);
34709e39c5baSBill Taylor 
34719e39c5baSBill Taylor 
34729e39c5baSBill Taylor 
34739e39c5baSBill Taylor 	/* Post commands to initialize each Hermon HCA port */
34749e39c5baSBill Taylor 	/*
34759e39c5baSBill Taylor 	 * In Hermon, the process is different than in previous HCAs.
34769e39c5baSBill Taylor 	 * Here, you have to:
34779e39c5baSBill Taylor 	 *	QUERY_PORT - to get basic information from the HCA
34789e39c5baSBill Taylor 	 *	set the fields accordingly
34799e39c5baSBill Taylor 	 *	SET_PORT - to change/set everything as desired
34809e39c5baSBill Taylor 	 *	INIT_PORT - to bring the port up
34819e39c5baSBill Taylor 	 *
34829e39c5baSBill Taylor 	 * Needs to be done for each port in turn
34839e39c5baSBill Taylor 	 */
34849e39c5baSBill Taylor 
34859e39c5baSBill Taylor 	for (i = 0; i < num_ports; i++) {
34869e39c5baSBill Taylor 		bzero(&state->hs_queryport, sizeof (hermon_hw_query_port_t));
34879e39c5baSBill Taylor 		status = hermon_cmn_query_cmd_post(state, QUERY_PORT, 0,
34889e39c5baSBill Taylor 		    (i + 1), &state->hs_queryport,
34899e39c5baSBill Taylor 		    sizeof (hermon_hw_query_port_t), HERMON_CMD_NOSLEEP_SPIN);
34909e39c5baSBill Taylor 		if (status != HERMON_CMD_SUCCESS) {
34919e39c5baSBill Taylor 			cmn_err(CE_CONT, "Hermon: QUERY_PORT (port %02d) "
34929e39c5baSBill Taylor 			    "command failed: %08x\n", i + 1, status);
34939e39c5baSBill Taylor 			goto init_ports_fail;
34949e39c5baSBill Taylor 		}
34959e39c5baSBill Taylor 		initport = &portinits[i];
34969e39c5baSBill Taylor 		state->hs_initport = &portinits[i];
34979e39c5baSBill Taylor 
34989e39c5baSBill Taylor 		bzero(initport, sizeof (hermon_hw_query_port_t));
34999e39c5baSBill Taylor 
35009e39c5baSBill Taylor 		/*
35019e39c5baSBill Taylor 		 * Determine whether we need to override the firmware's
35029e39c5baSBill Taylor 		 * default SystemImageGUID setting.
35039e39c5baSBill Taylor 		 */
35049e39c5baSBill Taylor 		sysimgguid = cfgprof->cp_sysimgguid;
35059e39c5baSBill Taylor 		if (sysimgguid != 0) {
35069e39c5baSBill Taylor 			initport->sig		= 1;
35079e39c5baSBill Taylor 			initport->sys_img_guid	= sysimgguid;
35089e39c5baSBill Taylor 		}
35099e39c5baSBill Taylor 
35109e39c5baSBill Taylor 		/*
35119e39c5baSBill Taylor 		 * Determine whether we need to override the firmware's
35129e39c5baSBill Taylor 		 * default NodeGUID setting.
35139e39c5baSBill Taylor 		 */
35149e39c5baSBill Taylor 		nodeguid = cfgprof->cp_nodeguid;
35159e39c5baSBill Taylor 		if (nodeguid != 0) {
35169e39c5baSBill Taylor 			initport->ng		= 1;
35179e39c5baSBill Taylor 			initport->node_guid	= nodeguid;
35189e39c5baSBill Taylor 		}
35199e39c5baSBill Taylor 
35209e39c5baSBill Taylor 		/*
35219e39c5baSBill Taylor 		 * Determine whether we need to override the firmware's
35229e39c5baSBill Taylor 		 * default PortGUID setting.
35239e39c5baSBill Taylor 		 */
35249e39c5baSBill Taylor 		portguid = cfgprof->cp_portguid[i];
35259e39c5baSBill Taylor 		if (portguid != 0) {
35269e39c5baSBill Taylor 			initport->g0		= 1;
35279e39c5baSBill Taylor 			initport->guid0		= portguid;
35289e39c5baSBill Taylor 		}
35299e39c5baSBill Taylor 
35309e39c5baSBill Taylor 		/* Validate max MTU size */
35319e39c5baSBill Taylor 		maxval  = state->hs_queryport.ib_mtu;
35329e39c5baSBill Taylor 		val	= cfgprof->cp_max_mtu;
35339e39c5baSBill Taylor 		if (val > maxval) {
35349e39c5baSBill Taylor 			goto init_ports_fail;
35359e39c5baSBill Taylor 		}
35369e39c5baSBill Taylor 
353771be8d8fSBill Taylor 		/* Set mtu_cap to 4096 bytes */
353871be8d8fSBill Taylor 		initport->mmc = 1;	/* set the change bit */
353971be8d8fSBill Taylor 		initport->mtu_cap = 5;	/* for 4096 bytes */
354071be8d8fSBill Taylor 
35419e39c5baSBill Taylor 		/* Validate the max port width */
35429e39c5baSBill Taylor 		maxval  = state->hs_queryport.ib_port_wid;
35439e39c5baSBill Taylor 		val	= cfgprof->cp_max_port_width;
35449e39c5baSBill Taylor 		if (val > maxval) {
35459e39c5baSBill Taylor 			goto init_ports_fail;
35469e39c5baSBill Taylor 		}
35479e39c5baSBill Taylor 
35489e39c5baSBill Taylor 		/* Validate max VL cap size */
35499e39c5baSBill Taylor 		maxval  = state->hs_queryport.max_vl;
35509e39c5baSBill Taylor 		val	= cfgprof->cp_max_vlcap;
35519e39c5baSBill Taylor 		if (val > maxval) {
35529e39c5baSBill Taylor 			goto init_ports_fail;
35539e39c5baSBill Taylor 		}
35549e39c5baSBill Taylor 
355571be8d8fSBill Taylor 		/* Since we're doing mtu_cap, cut vl_cap down */
355671be8d8fSBill Taylor 		initport->mvc = 1;	/* set this change bit */
355771be8d8fSBill Taylor 		initport->vl_cap = 3;	/* 3 means vl0-vl3, 4 total */
355871be8d8fSBill Taylor 
35599e39c5baSBill Taylor 		/* Validate max GID table size */
35609e39c5baSBill Taylor 		maxval  = ((uint64_t)1 << state->hs_queryport.log_max_gid);
35619e39c5baSBill Taylor 		val	= ((uint64_t)1 << cfgprof->cp_log_max_gidtbl);
35629e39c5baSBill Taylor 		if (val > maxval) {
35639e39c5baSBill Taylor 			goto init_ports_fail;
35649e39c5baSBill Taylor 		}
356517a2b317SBill Taylor 		initport->max_gid = (uint16_t)val;
35669e39c5baSBill Taylor 		initport->mg = 1;
35679e39c5baSBill Taylor 
35689e39c5baSBill Taylor 		/* Validate max PKey table size */
35699e39c5baSBill Taylor 		maxval	= ((uint64_t)1 << state->hs_queryport.log_max_pkey);
35709e39c5baSBill Taylor 		val	= ((uint64_t)1 << cfgprof->cp_log_max_pkeytbl);
35719e39c5baSBill Taylor 		if (val > maxval) {
35729e39c5baSBill Taylor 			goto init_ports_fail;
35739e39c5baSBill Taylor 		}
35749e39c5baSBill Taylor 		initport->max_pkey = (uint16_t)val;
35759e39c5baSBill Taylor 		initport->mp = 1;
35769e39c5baSBill Taylor 		/*
35779e39c5baSBill Taylor 		 * Post the SET_PORT cmd to Hermon firmware. This sets
35789e39c5baSBill Taylor 		 * the parameters of the port.
35799e39c5baSBill Taylor 		 */
35809e39c5baSBill Taylor 		status = hermon_set_port_cmd_post(state, initport, i + 1,
35819e39c5baSBill Taylor 		    HERMON_CMD_NOSLEEP_SPIN);
35829e39c5baSBill Taylor 		if (status != HERMON_CMD_SUCCESS) {
35839e39c5baSBill Taylor 			cmn_err(CE_CONT, "Hermon: SET_PORT (port %02d) command "
35849e39c5baSBill Taylor 			    "failed: %08x\n", i + 1, status);
35859e39c5baSBill Taylor 			goto init_ports_fail;
35869e39c5baSBill Taylor 		}
35879e39c5baSBill Taylor 		/* issue another SET_PORT cmd - performance fix/workaround */
35889e39c5baSBill Taylor 		/* XXX - need to discuss with Mellanox */
35899e39c5baSBill Taylor 		bzero(initport, sizeof (hermon_hw_query_port_t));
35909e39c5baSBill Taylor 		initport->cap_mask = 0x02500868;
35919e39c5baSBill Taylor 		status = hermon_set_port_cmd_post(state, initport, i + 1,
35929e39c5baSBill Taylor 		    HERMON_CMD_NOSLEEP_SPIN);
35939e39c5baSBill Taylor 		if (status != HERMON_CMD_SUCCESS) {
35949e39c5baSBill Taylor 			cmn_err(CE_CONT, "Hermon: SET_PORT (port %02d) command "
35959e39c5baSBill Taylor 			    "failed: %08x\n", i + 1, status);
35969e39c5baSBill Taylor 			goto init_ports_fail;
35979e39c5baSBill Taylor 		}
35989e39c5baSBill Taylor 	}
35999e39c5baSBill Taylor 
36009e39c5baSBill Taylor 	/*
36019e39c5baSBill Taylor 	 * Finally, do the INIT_PORT for each port in turn
36029e39c5baSBill Taylor 	 * When this command completes, the corresponding Hermon port
36039e39c5baSBill Taylor 	 * will be physically "Up" and initialized.
36049e39c5baSBill Taylor 	 */
36059e39c5baSBill Taylor 	for (i = 0; i < num_ports; i++) {
36069e39c5baSBill Taylor 		status = hermon_init_port_cmd_post(state, i + 1,
36079e39c5baSBill Taylor 		    HERMON_CMD_NOSLEEP_SPIN);
36089e39c5baSBill Taylor 		if (status != HERMON_CMD_SUCCESS) {
36099e39c5baSBill Taylor 			cmn_err(CE_CONT, "Hermon: INIT_PORT (port %02d) "
36109e39c5baSBill Taylor 			    "comman failed: %08x\n", i + 1, status);
36119e39c5baSBill Taylor 			goto init_ports_fail;
36129e39c5baSBill Taylor 		}
36139e39c5baSBill Taylor 	}
36149e39c5baSBill Taylor 
36159e39c5baSBill Taylor 	/* Free up the memory for Hermon port init struct(s), return success */
36169e39c5baSBill Taylor 	kmem_free(portinits, num_ports * sizeof (hermon_hw_set_port_t));
36179e39c5baSBill Taylor 	return (DDI_SUCCESS);
36189e39c5baSBill Taylor 
36199e39c5baSBill Taylor init_ports_fail:
36209e39c5baSBill Taylor 	/*
36219e39c5baSBill Taylor 	 * Free up the memory for Hermon port init struct(s), shutdown any
36229e39c5baSBill Taylor 	 * successfully initialized ports, and return failure
36239e39c5baSBill Taylor 	 */
36249e39c5baSBill Taylor 	kmem_free(portinits, num_ports * sizeof (hermon_hw_set_port_t));
36259e39c5baSBill Taylor 	(void) hermon_hca_ports_shutdown(state, i);
36269e39c5baSBill Taylor 
36279e39c5baSBill Taylor 	return (DDI_FAILURE);
36289e39c5baSBill Taylor }
36299e39c5baSBill Taylor 
36309e39c5baSBill Taylor 
36319e39c5baSBill Taylor /*
36329e39c5baSBill Taylor  * hermon_hca_ports_shutdown()
36339e39c5baSBill Taylor  *    Context: Only called from attach() and/or detach() path contexts
36349e39c5baSBill Taylor  */
36359e39c5baSBill Taylor static int
hermon_hca_ports_shutdown(hermon_state_t * state,uint_t num_init)36369e39c5baSBill Taylor hermon_hca_ports_shutdown(hermon_state_t *state, uint_t num_init)
36379e39c5baSBill Taylor {
36389e39c5baSBill Taylor 	int	i, status;
36399e39c5baSBill Taylor 
36409e39c5baSBill Taylor 	/*
36419e39c5baSBill Taylor 	 * Post commands to shutdown all init'd Hermon HCA ports.  Note: if
36429e39c5baSBill Taylor 	 * any of these commands fail for any reason, it would be entirely
36439e39c5baSBill Taylor 	 * unexpected and probably indicative a serious problem (HW or SW).
36449e39c5baSBill Taylor 	 * Although we do return void from this function, this type of failure
36459e39c5baSBill Taylor 	 * should not go unreported.  That is why we have the warning message.
36469e39c5baSBill Taylor 	 */
36479e39c5baSBill Taylor 	for (i = 0; i < num_init; i++) {
36489e39c5baSBill Taylor 		status = hermon_close_port_cmd_post(state, i + 1,
36499e39c5baSBill Taylor 		    HERMON_CMD_NOSLEEP_SPIN);
36509e39c5baSBill Taylor 		if (status != HERMON_CMD_SUCCESS) {
36519e39c5baSBill Taylor 			HERMON_WARNING(state, "failed to shutdown HCA port");
36529e39c5baSBill Taylor 			return (status);
36539e39c5baSBill Taylor 		}
36549e39c5baSBill Taylor 	}
36559e39c5baSBill Taylor 	return (HERMON_CMD_SUCCESS);
36569e39c5baSBill Taylor }
36579e39c5baSBill Taylor 
36589e39c5baSBill Taylor 
36599e39c5baSBill Taylor /*
36609e39c5baSBill Taylor  * hermon_internal_uarpg_init
36619e39c5baSBill Taylor  *    Context: Only called from attach() path context
36629e39c5baSBill Taylor  */
36639e39c5baSBill Taylor static int
hermon_internal_uarpg_init(hermon_state_t * state)36649e39c5baSBill Taylor hermon_internal_uarpg_init(hermon_state_t *state)
36659e39c5baSBill Taylor {
36669e39c5baSBill Taylor 	int	status;
3667*0b63ccafSToomas Soome 	hermon_dbr_info_t	*info;
36689e39c5baSBill Taylor 
36699e39c5baSBill Taylor 	/*
36709e39c5baSBill Taylor 	 * Allocate the UAR page for kernel use. This UAR page is
36719e39c5baSBill Taylor 	 * the privileged UAR page through which all kernel generated
36729e39c5baSBill Taylor 	 * doorbells will be rung. There are a number of UAR pages
36739e39c5baSBill Taylor 	 * reserved by hardware at the front of the UAR BAR, indicated
36749e39c5baSBill Taylor 	 * by DEVCAP.num_rsvd_uar, which we have already allocated. So,
36759e39c5baSBill Taylor 	 * the kernel page, or UAR page index num_rsvd_uar, will be
36769e39c5baSBill Taylor 	 * allocated here for kernel use.
36779e39c5baSBill Taylor 	 */
36789e39c5baSBill Taylor 
36799e39c5baSBill Taylor 	status = hermon_rsrc_alloc(state, HERMON_UARPG, 1, HERMON_SLEEP,
36809e39c5baSBill Taylor 	    &state->hs_uarkpg_rsrc);
36819e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
36829e39c5baSBill Taylor 		return (DDI_FAILURE);
36839e39c5baSBill Taylor 	}
36849e39c5baSBill Taylor 
36859e39c5baSBill Taylor 	/* Setup pointer to kernel UAR page */
36869e39c5baSBill Taylor 	state->hs_uar = (hermon_hw_uar_t *)state->hs_uarkpg_rsrc->hr_addr;
36879e39c5baSBill Taylor 
36889e39c5baSBill Taylor 	/* need to set up DBr tracking as well */
36899e39c5baSBill Taylor 	status = hermon_dbr_page_alloc(state, &info);
36909e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
36919e39c5baSBill Taylor 		return (DDI_FAILURE);
36929e39c5baSBill Taylor 	}
3693dd9e16daSagiri 	state->hs_kern_dbr = info;
36949e39c5baSBill Taylor 	return (DDI_SUCCESS);
36959e39c5baSBill Taylor }
36969e39c5baSBill Taylor 
36979e39c5baSBill Taylor 
36989e39c5baSBill Taylor /*
36999e39c5baSBill Taylor  * hermon_internal_uarpg_fini
37009e39c5baSBill Taylor  *    Context: Only called from attach() and/or detach() path contexts
37019e39c5baSBill Taylor  */
37029e39c5baSBill Taylor static void
hermon_internal_uarpg_fini(hermon_state_t * state)37039e39c5baSBill Taylor hermon_internal_uarpg_fini(hermon_state_t *state)
37049e39c5baSBill Taylor {
37059e39c5baSBill Taylor 	/* Free up Hermon UAR page #1 (kernel driver doorbells) */
37069e39c5baSBill Taylor 	hermon_rsrc_free(state, &state->hs_uarkpg_rsrc);
37079e39c5baSBill Taylor }
37089e39c5baSBill Taylor 
37099e39c5baSBill Taylor 
37109e39c5baSBill Taylor /*
37119e39c5baSBill Taylor  * hermon_special_qp_contexts_reserve()
37129e39c5baSBill Taylor  *    Context: Only called from attach() path context
37139e39c5baSBill Taylor  */
37149e39c5baSBill Taylor static int
hermon_special_qp_contexts_reserve(hermon_state_t * state)37159e39c5baSBill Taylor hermon_special_qp_contexts_reserve(hermon_state_t *state)
37169e39c5baSBill Taylor {
37179e39c5baSBill Taylor 	hermon_rsrc_t	*qp0_rsrc, *qp1_rsrc, *qp_resvd;
37189e39c5baSBill Taylor 	int		status;
37199e39c5baSBill Taylor 
37209e39c5baSBill Taylor 	/* Initialize the lock used for special QP rsrc management */
37219e39c5baSBill Taylor 	mutex_init(&state->hs_spec_qplock, NULL, MUTEX_DRIVER,
37229e39c5baSBill Taylor 	    DDI_INTR_PRI(state->hs_intrmsi_pri));
37239e39c5baSBill Taylor 
37249e39c5baSBill Taylor 	/*
37259e39c5baSBill Taylor 	 * Reserve contexts for QP0.  These QP contexts will be setup to
37269e39c5baSBill Taylor 	 * act as aliases for the real QP0.  Note: We are required to grab
37279e39c5baSBill Taylor 	 * two QPs (one per port) even if we are operating in single-port
37289e39c5baSBill Taylor 	 * mode.
37299e39c5baSBill Taylor 	 */
37309e39c5baSBill Taylor 	status = hermon_rsrc_alloc(state, HERMON_QPC, 2,
37319e39c5baSBill Taylor 	    HERMON_SLEEP, &qp0_rsrc);
37329e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
37339e39c5baSBill Taylor 		mutex_destroy(&state->hs_spec_qplock);
37349e39c5baSBill Taylor 		return (DDI_FAILURE);
37359e39c5baSBill Taylor 	}
37369e39c5baSBill Taylor 	state->hs_spec_qp0 = qp0_rsrc;
37379e39c5baSBill Taylor 
37389e39c5baSBill Taylor 	/*
37399e39c5baSBill Taylor 	 * Reserve contexts for QP1.  These QP contexts will be setup to
37409e39c5baSBill Taylor 	 * act as aliases for the real QP1.  Note: We are required to grab
37419e39c5baSBill Taylor 	 * two QPs (one per port) even if we are operating in single-port
37429e39c5baSBill Taylor 	 * mode.
37439e39c5baSBill Taylor 	 */
37449e39c5baSBill Taylor 	status = hermon_rsrc_alloc(state, HERMON_QPC, 2,
37459e39c5baSBill Taylor 	    HERMON_SLEEP, &qp1_rsrc);
37469e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
37479e39c5baSBill Taylor 		hermon_rsrc_free(state, &qp0_rsrc);
37489e39c5baSBill Taylor 		mutex_destroy(&state->hs_spec_qplock);
37499e39c5baSBill Taylor 		return (DDI_FAILURE);
37509e39c5baSBill Taylor 	}
37519e39c5baSBill Taylor 	state->hs_spec_qp1 = qp1_rsrc;
37529e39c5baSBill Taylor 
37539e39c5baSBill Taylor 	status = hermon_rsrc_alloc(state, HERMON_QPC, 4,
37549e39c5baSBill Taylor 	    HERMON_SLEEP, &qp_resvd);
37559e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
37569e39c5baSBill Taylor 		hermon_rsrc_free(state, &qp1_rsrc);
37579e39c5baSBill Taylor 		hermon_rsrc_free(state, &qp0_rsrc);
37589e39c5baSBill Taylor 		mutex_destroy(&state->hs_spec_qplock);
37599e39c5baSBill Taylor 		return (DDI_FAILURE);
37609e39c5baSBill Taylor 	}
37619e39c5baSBill Taylor 	state->hs_spec_qp_unused = qp_resvd;
37629e39c5baSBill Taylor 
37639e39c5baSBill Taylor 	return (DDI_SUCCESS);
37649e39c5baSBill Taylor }
37659e39c5baSBill Taylor 
37669e39c5baSBill Taylor 
37679e39c5baSBill Taylor /*
37689e39c5baSBill Taylor  * hermon_special_qp_contexts_unreserve()
37699e39c5baSBill Taylor  *    Context: Only called from attach() and/or detach() path contexts
37709e39c5baSBill Taylor  */
37719e39c5baSBill Taylor static void
hermon_special_qp_contexts_unreserve(hermon_state_t * state)37729e39c5baSBill Taylor hermon_special_qp_contexts_unreserve(hermon_state_t *state)
37739e39c5baSBill Taylor {
37749e39c5baSBill Taylor 
37759e39c5baSBill Taylor 	/* Unreserve contexts for spec_qp_unused */
37769e39c5baSBill Taylor 	hermon_rsrc_free(state, &state->hs_spec_qp_unused);
37779e39c5baSBill Taylor 
37789e39c5baSBill Taylor 	/* Unreserve contexts for QP1 */
37799e39c5baSBill Taylor 	hermon_rsrc_free(state, &state->hs_spec_qp1);
37809e39c5baSBill Taylor 
37819e39c5baSBill Taylor 	/* Unreserve contexts for QP0 */
37829e39c5baSBill Taylor 	hermon_rsrc_free(state, &state->hs_spec_qp0);
37839e39c5baSBill Taylor 
37849e39c5baSBill Taylor 	/* Destroy the lock used for special QP rsrc management */
37859e39c5baSBill Taylor 	mutex_destroy(&state->hs_spec_qplock);
37869e39c5baSBill Taylor 
37879e39c5baSBill Taylor }
37889e39c5baSBill Taylor 
37899e39c5baSBill Taylor 
37909e39c5baSBill Taylor /*
37919e39c5baSBill Taylor  * hermon_sw_reset()
37929e39c5baSBill Taylor  *    Context: Currently called only from attach() path context
37939e39c5baSBill Taylor  */
37949e39c5baSBill Taylor static int
hermon_sw_reset(hermon_state_t * state)37959e39c5baSBill Taylor hermon_sw_reset(hermon_state_t *state)
37969e39c5baSBill Taylor {
37979e39c5baSBill Taylor 	ddi_acc_handle_t	hdl = hermon_get_pcihdl(state);
37989e39c5baSBill Taylor 	ddi_acc_handle_t	cmdhdl = hermon_get_cmdhdl(state);
37999e39c5baSBill Taylor 	uint32_t		reset_delay;
38009e39c5baSBill Taylor 	int			status, i;
38019e39c5baSBill Taylor 	uint32_t		sem;
38029e39c5baSBill Taylor 	uint_t			offset;
38039e39c5baSBill Taylor 	uint32_t		data32;		/* for devctl & linkctl */
38049e39c5baSBill Taylor 	int			loopcnt;
38059e39c5baSBill Taylor 
38069e39c5baSBill Taylor 	/* initialize the FMA retry loop */
38079e39c5baSBill Taylor 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
38089e39c5baSBill Taylor 	hermon_pio_init(fm_loop_cnt2, fm_status2, fm_test2);
38099e39c5baSBill Taylor 
38109e39c5baSBill Taylor 	/*
38119e39c5baSBill Taylor 	 * If the configured software reset delay is set to zero, then we
38129e39c5baSBill Taylor 	 * will not attempt a software reset of the Hermon device.
38139e39c5baSBill Taylor 	 */
38149e39c5baSBill Taylor 	reset_delay = state->hs_cfg_profile->cp_sw_reset_delay;
38159e39c5baSBill Taylor 	if (reset_delay == 0) {
38169e39c5baSBill Taylor 		return (DDI_SUCCESS);
38179e39c5baSBill Taylor 	}
38189e39c5baSBill Taylor 
38199e39c5baSBill Taylor 	/* the FMA retry loop starts. */
38209e39c5baSBill Taylor 	hermon_pio_start(state, cmdhdl, pio_error, fm_loop_cnt, fm_status,
38219e39c5baSBill Taylor 	    fm_test);
38229e39c5baSBill Taylor 	hermon_pio_start(state, hdl, pio_error2, fm_loop_cnt2, fm_status2,
38239e39c5baSBill Taylor 	    fm_test2);
38249e39c5baSBill Taylor 
38259e39c5baSBill Taylor 	/* Query the PCI capabilities of the HCA device */
38269e39c5baSBill Taylor 	/* but don't process the VPD until after reset */
38279e39c5baSBill Taylor 	status = hermon_pci_capability_list(state, hdl);
38289e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
38299e39c5baSBill Taylor 		cmn_err(CE_NOTE, "failed to get pci capabilities list(0x%x)\n",
38309e39c5baSBill Taylor 		    status);
38319e39c5baSBill Taylor 		return (DDI_FAILURE);
38329e39c5baSBill Taylor 	}
38339e39c5baSBill Taylor 
38349e39c5baSBill Taylor 	/*
38359e39c5baSBill Taylor 	 * Read all PCI config info (reg0...reg63).  Note: According to the
38369e39c5baSBill Taylor 	 * Hermon software reset application note, we should not read or
38379e39c5baSBill Taylor 	 * restore the values in reg22 and reg23.
38389e39c5baSBill Taylor 	 * NOTE:  For Hermon (and Arbel too) it says to restore the command
38399e39c5baSBill Taylor 	 * register LAST, and technically, you need to restore the
38409e39c5baSBill Taylor 	 * PCIE Capability "device control" and "link control" (word-sized,
38419e39c5baSBill Taylor 	 * at offsets 0x08 and 0x10 from the capbility ID respectively).
38429e39c5baSBill Taylor 	 * We hold off restoring the command register - offset 0x4 - till last
38439e39c5baSBill Taylor 	 */
38449e39c5baSBill Taylor 
38459e39c5baSBill Taylor 	/* 1st, wait for the semaphore assure accessibility - per PRM */
38469e39c5baSBill Taylor 	status = -1;
38479e39c5baSBill Taylor 	for (i = 0; i < NANOSEC/MICROSEC /* 1sec timeout */; i++) {
38489e39c5baSBill Taylor 		sem = ddi_get32(cmdhdl, state->hs_cmd_regs.sw_semaphore);
38499e39c5baSBill Taylor 		if (sem == 0) {
38509e39c5baSBill Taylor 			status = 0;
38519e39c5baSBill Taylor 			break;
38529e39c5baSBill Taylor 		}
38539e39c5baSBill Taylor 		drv_usecwait(1);
38549e39c5baSBill Taylor 	}
38559e39c5baSBill Taylor 
38569e39c5baSBill Taylor 	/* Check if timeout happens */
38579e39c5baSBill Taylor 	if (status == -1) {
38589e39c5baSBill Taylor 		/*
38599e39c5baSBill Taylor 		 * Remove this acc handle from Hermon, then log
38609e39c5baSBill Taylor 		 * the error.
38619e39c5baSBill Taylor 		 */
38629e39c5baSBill Taylor 		hermon_pci_config_teardown(state, &hdl);
38639e39c5baSBill Taylor 
38649e39c5baSBill Taylor 		cmn_err(CE_WARN, "hermon_sw_reset timeout: "
38659e39c5baSBill Taylor 		    "failed to get the semaphore(0x%p)\n",
38669e39c5baSBill Taylor 		    (void *)state->hs_cmd_regs.sw_semaphore);
38679e39c5baSBill Taylor 
38689e39c5baSBill Taylor 		hermon_fm_ereport(state, HCA_IBA_ERR, HCA_ERR_NON_FATAL);
38699e39c5baSBill Taylor 		return (DDI_FAILURE);
38709e39c5baSBill Taylor 	}
38719e39c5baSBill Taylor 
38729e39c5baSBill Taylor 	for (i = 0; i < HERMON_SW_RESET_NUMREGS; i++) {
38739e39c5baSBill Taylor 		if ((i != HERMON_SW_RESET_REG22_RSVD) &&
38749e39c5baSBill Taylor 		    (i != HERMON_SW_RESET_REG23_RSVD)) {
38759e39c5baSBill Taylor 			state->hs_cfg_data[i]  = pci_config_get32(hdl, i << 2);
38769e39c5baSBill Taylor 		}
38779e39c5baSBill Taylor 	}
38789e39c5baSBill Taylor 
38799e39c5baSBill Taylor 	/*
38809e39c5baSBill Taylor 	 * Perform the software reset (by writing 1 at offset 0xF0010)
38819e39c5baSBill Taylor 	 */
38829e39c5baSBill Taylor 	ddi_put32(cmdhdl, state->hs_cmd_regs.sw_reset, HERMON_SW_RESET_START);
38839e39c5baSBill Taylor 
38849e39c5baSBill Taylor 	/*
38859e39c5baSBill Taylor 	 * This delay is required so as not to cause a panic here. If the
38869e39c5baSBill Taylor 	 * device is accessed too soon after reset it will not respond to
38879e39c5baSBill Taylor 	 * config cycles, causing a Master Abort and panic.
38889e39c5baSBill Taylor 	 */
38899e39c5baSBill Taylor 	drv_usecwait(reset_delay);
38909e39c5baSBill Taylor 
38919e39c5baSBill Taylor 	/*
38929e39c5baSBill Taylor 	 * Poll waiting for the device to finish resetting.
38939e39c5baSBill Taylor 	 */
38949e39c5baSBill Taylor 	loopcnt = 100;	/* 100 times @ 100 usec - total delay 10 msec */
38959e39c5baSBill Taylor 	while ((pci_config_get32(hdl, 0) & 0x0000FFFF) != PCI_VENID_MLX) {
38969e39c5baSBill Taylor 		drv_usecwait(HERMON_SW_RESET_POLL_DELAY);
38979e39c5baSBill Taylor 		if (--loopcnt == 0)
38989e39c5baSBill Taylor 			break;	/* just in case, break and go on */
38999e39c5baSBill Taylor 	}
39009e39c5baSBill Taylor 	if (loopcnt == 0)
39019e39c5baSBill Taylor 		cmn_err(CE_CONT, "!Never see VEND_ID - read == %X",
39029e39c5baSBill Taylor 		    pci_config_get32(hdl, 0));
39039e39c5baSBill Taylor 
39049e39c5baSBill Taylor 	/*
39059e39c5baSBill Taylor 	 * Restore the config info
39069e39c5baSBill Taylor 	 */
39079e39c5baSBill Taylor 	for (i = 0; i < HERMON_SW_RESET_NUMREGS; i++) {
39089e39c5baSBill Taylor 		if (i == 1) continue;	/* skip the status/ctrl reg */
39099e39c5baSBill Taylor 		if ((i != HERMON_SW_RESET_REG22_RSVD) &&
39109e39c5baSBill Taylor 		    (i != HERMON_SW_RESET_REG23_RSVD)) {
39119e39c5baSBill Taylor 			pci_config_put32(hdl, i << 2, state->hs_cfg_data[i]);
39129e39c5baSBill Taylor 		}
39139e39c5baSBill Taylor 	}
39149e39c5baSBill Taylor 
39159e39c5baSBill Taylor 	/*
39169e39c5baSBill Taylor 	 * PCI Express Capability - we saved during capability list, and
39179e39c5baSBill Taylor 	 * we'll restore them here.
39189e39c5baSBill Taylor 	 */
39199e39c5baSBill Taylor 	offset = state->hs_pci_cap_offset;
39209e39c5baSBill Taylor 	data32 = state->hs_pci_cap_devctl;
39219e39c5baSBill Taylor 	pci_config_put32(hdl, offset + HERMON_PCI_CAP_DEV_OFFS, data32);
39229e39c5baSBill Taylor 	data32 = state->hs_pci_cap_lnkctl;
39239e39c5baSBill Taylor 	pci_config_put32(hdl, offset + HERMON_PCI_CAP_LNK_OFFS, data32);
39249e39c5baSBill Taylor 
39259e39c5baSBill Taylor 	pci_config_put32(hdl, 0x04, (state->hs_cfg_data[1] | 0x0006));
39269e39c5baSBill Taylor 
39279e39c5baSBill Taylor 	/* the FMA retry loop ends. */
39289e39c5baSBill Taylor 	hermon_pio_end(state, hdl, pio_error2, fm_loop_cnt2, fm_status2,
39299e39c5baSBill Taylor 	    fm_test2);
39309e39c5baSBill Taylor 	hermon_pio_end(state, cmdhdl, pio_error, fm_loop_cnt, fm_status,
39319e39c5baSBill Taylor 	    fm_test);
39329e39c5baSBill Taylor 
39339e39c5baSBill Taylor 	return (DDI_SUCCESS);
39349e39c5baSBill Taylor 
39359e39c5baSBill Taylor pio_error2:
39369e39c5baSBill Taylor 	/* fall through */
39379e39c5baSBill Taylor pio_error:
39389e39c5baSBill Taylor 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_NON_FATAL);
39399e39c5baSBill Taylor 	return (DDI_FAILURE);
39409e39c5baSBill Taylor }
39419e39c5baSBill Taylor 
39429e39c5baSBill Taylor 
39439e39c5baSBill Taylor /*
39449e39c5baSBill Taylor  * hermon_mcg_init()
39459e39c5baSBill Taylor  *    Context: Only called from attach() path context
39469e39c5baSBill Taylor  */
39479e39c5baSBill Taylor static int
hermon_mcg_init(hermon_state_t * state)39489e39c5baSBill Taylor hermon_mcg_init(hermon_state_t *state)
39499e39c5baSBill Taylor {
39509e39c5baSBill Taylor 	uint_t		mcg_tmp_sz;
39519e39c5baSBill Taylor 
39529e39c5baSBill Taylor 
39539e39c5baSBill Taylor 	/*
39549e39c5baSBill Taylor 	 * Allocate space for the MCG temporary copy buffer.  This is
39559e39c5baSBill Taylor 	 * used by the Attach/Detach Multicast Group code
39569e39c5baSBill Taylor 	 */
39579e39c5baSBill Taylor 	mcg_tmp_sz = HERMON_MCGMEM_SZ(state);
39589e39c5baSBill Taylor 	state->hs_mcgtmp = kmem_zalloc(mcg_tmp_sz, KM_SLEEP);
39599e39c5baSBill Taylor 
39609e39c5baSBill Taylor 	/*
39619e39c5baSBill Taylor 	 * Initialize the multicast group mutex.  This ensures atomic
39629e39c5baSBill Taylor 	 * access to add, modify, and remove entries in the multicast
39639e39c5baSBill Taylor 	 * group hash lists.
39649e39c5baSBill Taylor 	 */
39659e39c5baSBill Taylor 	mutex_init(&state->hs_mcglock, NULL, MUTEX_DRIVER,
39669e39c5baSBill Taylor 	    DDI_INTR_PRI(state->hs_intrmsi_pri));
39679e39c5baSBill Taylor 
39689e39c5baSBill Taylor 	return (DDI_SUCCESS);
39699e39c5baSBill Taylor }
39709e39c5baSBill Taylor 
39719e39c5baSBill Taylor 
39729e39c5baSBill Taylor /*
39739e39c5baSBill Taylor  * hermon_mcg_fini()
39749e39c5baSBill Taylor  *    Context: Only called from attach() and/or detach() path contexts
39759e39c5baSBill Taylor  */
39769e39c5baSBill Taylor static void
hermon_mcg_fini(hermon_state_t * state)39779e39c5baSBill Taylor hermon_mcg_fini(hermon_state_t *state)
39789e39c5baSBill Taylor {
39799e39c5baSBill Taylor 	uint_t		mcg_tmp_sz;
39809e39c5baSBill Taylor 
39819e39c5baSBill Taylor 
39829e39c5baSBill Taylor 	/* Free up the space used for the MCG temporary copy buffer */
39839e39c5baSBill Taylor 	mcg_tmp_sz = HERMON_MCGMEM_SZ(state);
39849e39c5baSBill Taylor 	kmem_free(state->hs_mcgtmp, mcg_tmp_sz);
39859e39c5baSBill Taylor 
39869e39c5baSBill Taylor 	/* Destroy the multicast group mutex */
39879e39c5baSBill Taylor 	mutex_destroy(&state->hs_mcglock);
39889e39c5baSBill Taylor 
39899e39c5baSBill Taylor }
39909e39c5baSBill Taylor 
39919e39c5baSBill Taylor 
39929e39c5baSBill Taylor /*
39939e39c5baSBill Taylor  * hermon_fw_version_check()
39949e39c5baSBill Taylor  *    Context: Only called from attach() path context
39959e39c5baSBill Taylor  */
39969e39c5baSBill Taylor static int
hermon_fw_version_check(hermon_state_t * state)39979e39c5baSBill Taylor hermon_fw_version_check(hermon_state_t *state)
39989e39c5baSBill Taylor {
39999e39c5baSBill Taylor 
40009e39c5baSBill Taylor 	uint_t	hermon_fw_ver_major;
40019e39c5baSBill Taylor 	uint_t	hermon_fw_ver_minor;
40029e39c5baSBill Taylor 	uint_t	hermon_fw_ver_subminor;
40039e39c5baSBill Taylor 
40049e39c5baSBill Taylor #ifdef FMA_TEST
40059e39c5baSBill Taylor 	if (hermon_test_num == -1) {
40069e39c5baSBill Taylor 		return (DDI_FAILURE);
40079e39c5baSBill Taylor 	}
40089e39c5baSBill Taylor #endif
40099e39c5baSBill Taylor 
40109e39c5baSBill Taylor 	/*
40119e39c5baSBill Taylor 	 * Depending on which version of driver we have attached, and which
40129e39c5baSBill Taylor 	 * HCA we've attached, the firmware version checks will be different.
40139e39c5baSBill Taylor 	 * We set up the comparison values for both Arbel and Sinai HCAs.
40149e39c5baSBill Taylor 	 */
40159e39c5baSBill Taylor 	switch (state->hs_operational_mode) {
40169e39c5baSBill Taylor 	case HERMON_HCA_MODE:
40179e39c5baSBill Taylor 		hermon_fw_ver_major = HERMON_FW_VER_MAJOR;
40189e39c5baSBill Taylor 		hermon_fw_ver_minor = HERMON_FW_VER_MINOR;
40199e39c5baSBill Taylor 		hermon_fw_ver_subminor = HERMON_FW_VER_SUBMINOR;
40209e39c5baSBill Taylor 		break;
40219e39c5baSBill Taylor 
40229e39c5baSBill Taylor 	default:
40239e39c5baSBill Taylor 		return (DDI_FAILURE);
40249e39c5baSBill Taylor 	}
40259e39c5baSBill Taylor 
40269e39c5baSBill Taylor 	/*
40279e39c5baSBill Taylor 	 * If FW revision major number is less than acceptable,
40289e39c5baSBill Taylor 	 * return failure, else if greater return success.  If
40299e39c5baSBill Taylor 	 * the major numbers are equal than check the minor number
40309e39c5baSBill Taylor 	 */
40319e39c5baSBill Taylor 	if (state->hs_fw.fw_rev_major < hermon_fw_ver_major) {
40329e39c5baSBill Taylor 		return (DDI_FAILURE);
40339e39c5baSBill Taylor 	} else if (state->hs_fw.fw_rev_major > hermon_fw_ver_major) {
40349e39c5baSBill Taylor 		return (DDI_SUCCESS);
40359e39c5baSBill Taylor 	}
40369e39c5baSBill Taylor 
40379e39c5baSBill Taylor 	/*
40389e39c5baSBill Taylor 	 * Do the same check as above, except for minor revision numbers
40399e39c5baSBill Taylor 	 * If the minor numbers are equal than check the subminor number
40409e39c5baSBill Taylor 	 */
40419e39c5baSBill Taylor 	if (state->hs_fw.fw_rev_minor < hermon_fw_ver_minor) {
40429e39c5baSBill Taylor 		return (DDI_FAILURE);
40439e39c5baSBill Taylor 	} else if (state->hs_fw.fw_rev_minor > hermon_fw_ver_minor) {
40449e39c5baSBill Taylor 		return (DDI_SUCCESS);
40459e39c5baSBill Taylor 	}
40469e39c5baSBill Taylor 
40479e39c5baSBill Taylor 	/*
40489e39c5baSBill Taylor 	 * Once again we do the same check as above, except for the subminor
40499e39c5baSBill Taylor 	 * revision number.  If the subminor numbers are equal here, then
40509e39c5baSBill Taylor 	 * these are the same firmware version, return success
40519e39c5baSBill Taylor 	 */
40529e39c5baSBill Taylor 	if (state->hs_fw.fw_rev_subminor < hermon_fw_ver_subminor) {
40539e39c5baSBill Taylor 		return (DDI_FAILURE);
40549e39c5baSBill Taylor 	} else if (state->hs_fw.fw_rev_subminor > hermon_fw_ver_subminor) {
40559e39c5baSBill Taylor 		return (DDI_SUCCESS);
40569e39c5baSBill Taylor 	}
40579e39c5baSBill Taylor 
40589e39c5baSBill Taylor 	return (DDI_SUCCESS);
40599e39c5baSBill Taylor }
40609e39c5baSBill Taylor 
40619e39c5baSBill Taylor 
40629e39c5baSBill Taylor /*
40639e39c5baSBill Taylor  * hermon_device_info_report()
40649e39c5baSBill Taylor  *    Context: Only called from attach() path context
40659e39c5baSBill Taylor  */
40669e39c5baSBill Taylor static void
hermon_device_info_report(hermon_state_t * state)40679e39c5baSBill Taylor hermon_device_info_report(hermon_state_t *state)
40689e39c5baSBill Taylor {
40699e39c5baSBill Taylor 
40709e39c5baSBill Taylor 	cmn_err(CE_CONT, "?hermon%d: FW ver: %04d.%04d.%04d, "
40719e39c5baSBill Taylor 	    "HW rev: %02d\n", state->hs_instance, state->hs_fw.fw_rev_major,
40729e39c5baSBill Taylor 	    state->hs_fw.fw_rev_minor, state->hs_fw.fw_rev_subminor,
40739e39c5baSBill Taylor 	    state->hs_revision_id);
40749e39c5baSBill Taylor 	cmn_err(CE_CONT, "?hermon%d: %64s (0x%016" PRIx64 ")\n",
40759e39c5baSBill Taylor 	    state->hs_instance, state->hs_nodedesc, state->hs_nodeguid);
40769e39c5baSBill Taylor 
40779e39c5baSBill Taylor }
40789e39c5baSBill Taylor 
40799e39c5baSBill Taylor 
40809e39c5baSBill Taylor /*
40819e39c5baSBill Taylor  * hermon_pci_capability_list()
40829e39c5baSBill Taylor  *    Context: Only called from attach() path context
40839e39c5baSBill Taylor  */
40849e39c5baSBill Taylor static int
hermon_pci_capability_list(hermon_state_t * state,ddi_acc_handle_t hdl)40859e39c5baSBill Taylor hermon_pci_capability_list(hermon_state_t *state, ddi_acc_handle_t hdl)
40869e39c5baSBill Taylor {
40879e39c5baSBill Taylor 	uint_t		offset, data;
40889e39c5baSBill Taylor 	uint32_t	data32;
40899e39c5baSBill Taylor 
40909e39c5baSBill Taylor 	state->hs_pci_cap_offset = 0;		/* make sure it's cleared */
40919e39c5baSBill Taylor 
40929e39c5baSBill Taylor 	/*
40939e39c5baSBill Taylor 	 * Check for the "PCI Capabilities" bit in the "Status Register".
40949e39c5baSBill Taylor 	 * Bit 4 in this register indicates the presence of a "PCI
40959e39c5baSBill Taylor 	 * Capabilities" list.
40969e39c5baSBill Taylor 	 *
40979e39c5baSBill Taylor 	 * PCI-Express requires this bit to be set to 1.
40989e39c5baSBill Taylor 	 */
40999e39c5baSBill Taylor 	data = pci_config_get16(hdl, 0x06);
41009e39c5baSBill Taylor 	if ((data & 0x10) == 0) {
41019e39c5baSBill Taylor 		return (DDI_FAILURE);
41029e39c5baSBill Taylor 	}
41039e39c5baSBill Taylor 
41049e39c5baSBill Taylor 	/*
41059e39c5baSBill Taylor 	 * Starting from offset 0x34 in PCI config space, find the
41069e39c5baSBill Taylor 	 * head of "PCI capabilities" list, and walk the list.  If
41079e39c5baSBill Taylor 	 * capabilities of a known type are encountered (e.g.
41089e39c5baSBill Taylor 	 * "PCI-X Capability"), then call the appropriate handler
41099e39c5baSBill Taylor 	 * function.
41109e39c5baSBill Taylor 	 */
41119e39c5baSBill Taylor 	offset = pci_config_get8(hdl, 0x34);
41129e39c5baSBill Taylor 	while (offset != 0x0) {
41139e39c5baSBill Taylor 		data = pci_config_get8(hdl, offset);
41149e39c5baSBill Taylor 		/*
41159e39c5baSBill Taylor 		 * Check for known capability types.  Hermon has the
41169e39c5baSBill Taylor 		 * following:
41179e39c5baSBill Taylor 		 *    o Power Mgmt	 (0x02)
41189e39c5baSBill Taylor 		 *    o VPD Capability   (0x03)
41199e39c5baSBill Taylor 		 *    o PCI-E Capability (0x10)
41209e39c5baSBill Taylor 		 *    o MSIX Capability  (0x11)
41219e39c5baSBill Taylor 		 */
41229e39c5baSBill Taylor 		switch (data) {
41239e39c5baSBill Taylor 		case 0x01:
41249e39c5baSBill Taylor 			/* power mgmt handling */
41259e39c5baSBill Taylor 			break;
41269e39c5baSBill Taylor 		case 0x03:
41279e39c5baSBill Taylor 
41289e39c5baSBill Taylor /*
41299e39c5baSBill Taylor  * Reading the PCIe VPD is inconsistent - that is, sometimes causes
41309e39c5baSBill Taylor  * problems on (mostly) X64, though we've also seen problems w/ Sparc
41319e39c5baSBill Taylor  * and Tavor --- so, for now until it's root caused, don't try and
41329e39c5baSBill Taylor  * read it
41339e39c5baSBill Taylor  */
41349e39c5baSBill Taylor #ifdef HERMON_VPD_WORKS
41359e39c5baSBill Taylor 			hermon_pci_capability_vpd(state, hdl, offset);
41369e39c5baSBill Taylor #else
41379e39c5baSBill Taylor 			delay(100);
41389e39c5baSBill Taylor 			hermon_pci_capability_vpd(state, hdl, offset);
41399e39c5baSBill Taylor #endif
41409e39c5baSBill Taylor 			break;
41419e39c5baSBill Taylor 		case 0x10:
41429e39c5baSBill Taylor 			/*
41439e39c5baSBill Taylor 			 * PCI Express Capability - save offset & contents
41449e39c5baSBill Taylor 			 * for later in reset
41459e39c5baSBill Taylor 			 */
41469e39c5baSBill Taylor 			state->hs_pci_cap_offset = offset;
41479e39c5baSBill Taylor 			data32 = pci_config_get32(hdl,
41489e39c5baSBill Taylor 			    offset + HERMON_PCI_CAP_DEV_OFFS);
41499e39c5baSBill Taylor 			state->hs_pci_cap_devctl = data32;
41509e39c5baSBill Taylor 			data32 = pci_config_get32(hdl,
41519e39c5baSBill Taylor 			    offset + HERMON_PCI_CAP_LNK_OFFS);
41529e39c5baSBill Taylor 			state->hs_pci_cap_lnkctl = data32;
41539e39c5baSBill Taylor 			break;
41549e39c5baSBill Taylor 		case 0x11:
41559e39c5baSBill Taylor 			/*
41569e39c5baSBill Taylor 			 * MSIX support - nothing to do, taken care of in the
41579e39c5baSBill Taylor 			 * MSI/MSIX interrupt frameworkd
41589e39c5baSBill Taylor 			 */
41599e39c5baSBill Taylor 			break;
41609e39c5baSBill Taylor 		default:
41619e39c5baSBill Taylor 			/* just go on to the next */
41629e39c5baSBill Taylor 			break;
41639e39c5baSBill Taylor 		}
41649e39c5baSBill Taylor 
41659e39c5baSBill Taylor 		/* Get offset of next entry in list */
41669e39c5baSBill Taylor 		offset = pci_config_get8(hdl, offset + 1);
41679e39c5baSBill Taylor 	}
41689e39c5baSBill Taylor 
41699e39c5baSBill Taylor 	return (DDI_SUCCESS);
41709e39c5baSBill Taylor }
41719e39c5baSBill Taylor 
41729e39c5baSBill Taylor /*
41739e39c5baSBill Taylor  * hermon_pci_read_vpd()
41749e39c5baSBill Taylor  *    Context: Only called from attach() path context
41759e39c5baSBill Taylor  *    utility routine for hermon_pci_capability_vpd()
41769e39c5baSBill Taylor  */
41779e39c5baSBill Taylor static int
hermon_pci_read_vpd(ddi_acc_handle_t hdl,uint_t offset,uint32_t addr,uint32_t * data)41789e39c5baSBill Taylor hermon_pci_read_vpd(ddi_acc_handle_t hdl, uint_t offset, uint32_t addr,
41799e39c5baSBill Taylor     uint32_t *data)
41809e39c5baSBill Taylor {
41819e39c5baSBill Taylor 	int		retry = 40;  /* retry counter for EEPROM poll */
41829e39c5baSBill Taylor 	uint32_t	val;
41839e39c5baSBill Taylor 	int		vpd_addr = offset + 2;
41849e39c5baSBill Taylor 	int		vpd_data = offset + 4;
41859e39c5baSBill Taylor 
41869e39c5baSBill Taylor 	/*
41879e39c5baSBill Taylor 	 * In order to read a 32-bit value from VPD, we are to write down
41889e39c5baSBill Taylor 	 * the address (offset in the VPD itself) to the address register.
41899e39c5baSBill Taylor 	 * To signal the read, we also clear bit 31.  We then poll on bit 31
41909e39c5baSBill Taylor 	 * and when it is set, we can then read our 4 bytes from the data
41919e39c5baSBill Taylor 	 * register.
41929e39c5baSBill Taylor 	 */
41939e39c5baSBill Taylor 	(void) pci_config_put32(hdl, offset, addr << 16);
41949e39c5baSBill Taylor 	do {
41959e39c5baSBill Taylor 		drv_usecwait(1000);
41969e39c5baSBill Taylor 		val = pci_config_get16(hdl, vpd_addr);
41979e39c5baSBill Taylor 		if (val & 0x8000) {		/* flag bit set */
41989e39c5baSBill Taylor 			*data = pci_config_get32(hdl, vpd_data);
41999e39c5baSBill Taylor 			return (DDI_SUCCESS);
42009e39c5baSBill Taylor 		}
42019e39c5baSBill Taylor 	} while (--retry);
42029e39c5baSBill Taylor 	/* read of flag failed write one message but count the failures */
42039e39c5baSBill Taylor 	if (debug_vpd == 0)
42049e39c5baSBill Taylor 		cmn_err(CE_NOTE,
42059e39c5baSBill Taylor 		    "!Failed to see flag bit after VPD addr write\n");
42069e39c5baSBill Taylor 	debug_vpd++;
42079e39c5baSBill Taylor 
42089e39c5baSBill Taylor 
42099e39c5baSBill Taylor vpd_read_fail:
42109e39c5baSBill Taylor 	return (DDI_FAILURE);
42119e39c5baSBill Taylor }
42129e39c5baSBill Taylor 
42139e39c5baSBill Taylor 
42149e39c5baSBill Taylor 
42159e39c5baSBill Taylor /*
42169e39c5baSBill Taylor  *   hermon_pci_capability_vpd()
42179e39c5baSBill Taylor  *    Context: Only called from attach() path context
42189e39c5baSBill Taylor  */
42199e39c5baSBill Taylor static void
hermon_pci_capability_vpd(hermon_state_t * state,ddi_acc_handle_t hdl,uint_t offset)42209e39c5baSBill Taylor hermon_pci_capability_vpd(hermon_state_t *state, ddi_acc_handle_t hdl,
42219e39c5baSBill Taylor     uint_t offset)
42229e39c5baSBill Taylor {
42239e39c5baSBill Taylor 	uint8_t			name_length;
42249e39c5baSBill Taylor 	uint8_t			pn_length;
42259e39c5baSBill Taylor 	int			i, err = 0;
42269e39c5baSBill Taylor 	int			vpd_str_id = 0;
42279e39c5baSBill Taylor 	int			vpd_ro_desc;
42289e39c5baSBill Taylor 	int			vpd_ro_pn_desc;
42299e39c5baSBill Taylor #ifdef _BIG_ENDIAN
42309e39c5baSBill Taylor 	uint32_t		data32;
42319e39c5baSBill Taylor #endif /* _BIG_ENDIAN */
42329e39c5baSBill Taylor 	union {
42339e39c5baSBill Taylor 		uint32_t	vpd_int[HERMON_VPD_HDR_DWSIZE];
42349e39c5baSBill Taylor 		uchar_t		vpd_char[HERMON_VPD_HDR_BSIZE];
42359e39c5baSBill Taylor 	} vpd;
42369e39c5baSBill Taylor 
42379e39c5baSBill Taylor 
42389e39c5baSBill Taylor 	/*
42399e39c5baSBill Taylor 	 * Read in the Vital Product Data (VPD) to the extend needed
42409e39c5baSBill Taylor 	 * by the fwflash utility
42419e39c5baSBill Taylor 	 */
42429e39c5baSBill Taylor 	for (i = 0; i < HERMON_VPD_HDR_DWSIZE; i++) {
42439e39c5baSBill Taylor 		err = hermon_pci_read_vpd(hdl, offset, i << 2, &vpd.vpd_int[i]);
42449e39c5baSBill Taylor 		if (err != DDI_SUCCESS) {
42459e39c5baSBill Taylor 			cmn_err(CE_NOTE, "!VPD read failed\n");
42469e39c5baSBill Taylor 			goto out;
42479e39c5baSBill Taylor 		}
42489e39c5baSBill Taylor 	}
42499e39c5baSBill Taylor 
42509e39c5baSBill Taylor #ifdef _BIG_ENDIAN
42519e39c5baSBill Taylor 	/* Need to swap bytes for big endian. */
42529e39c5baSBill Taylor 	for (i = 0; i < HERMON_VPD_HDR_DWSIZE; i++) {
42539e39c5baSBill Taylor 		data32 = vpd.vpd_int[i];
42549e39c5baSBill Taylor 		vpd.vpd_char[(i << 2) + 3] =
42559e39c5baSBill Taylor 		    (uchar_t)((data32 & 0xFF000000) >> 24);
42569e39c5baSBill Taylor 		vpd.vpd_char[(i << 2) + 2] =
42579e39c5baSBill Taylor 		    (uchar_t)((data32 & 0x00FF0000) >> 16);
42589e39c5baSBill Taylor 		vpd.vpd_char[(i << 2) + 1] =
42599e39c5baSBill Taylor 		    (uchar_t)((data32 & 0x0000FF00) >> 8);
42609e39c5baSBill Taylor 		vpd.vpd_char[i << 2] = (uchar_t)(data32 & 0x000000FF);
42619e39c5baSBill Taylor 	}
42629e39c5baSBill Taylor #endif	/* _BIG_ENDIAN */
42639e39c5baSBill Taylor 
42649e39c5baSBill Taylor 	/* Check for VPD String ID Tag */
42659e39c5baSBill Taylor 	if (vpd.vpd_char[vpd_str_id] == 0x82) {
42669e39c5baSBill Taylor 		/* get the product name */
42679e39c5baSBill Taylor 		name_length = (uint8_t)vpd.vpd_char[vpd_str_id + 1];
42689e39c5baSBill Taylor 		if (name_length > sizeof (state->hs_hca_name)) {
42699e39c5baSBill Taylor 			cmn_err(CE_NOTE, "!VPD name too large (0x%x)\n",
42709e39c5baSBill Taylor 			    name_length);
42719e39c5baSBill Taylor 			goto out;
42729e39c5baSBill Taylor 		}
42739e39c5baSBill Taylor 		(void) memcpy(state->hs_hca_name, &vpd.vpd_char[vpd_str_id + 3],
42749e39c5baSBill Taylor 		    name_length);
42759e39c5baSBill Taylor 		state->hs_hca_name[name_length] = 0;
42769e39c5baSBill Taylor 
42779e39c5baSBill Taylor 		/* get the part number */
42789e39c5baSBill Taylor 		vpd_ro_desc = name_length + 3; /* read-only tag location */
42799e39c5baSBill Taylor 		vpd_ro_pn_desc = vpd_ro_desc + 3; /* P/N keyword location */
42809e39c5baSBill Taylor 
42819e39c5baSBill Taylor 		/* Verify read-only tag and Part Number keyword. */
42829e39c5baSBill Taylor 		if (vpd.vpd_char[vpd_ro_desc] != 0x90 ||
42839e39c5baSBill Taylor 		    (vpd.vpd_char[vpd_ro_pn_desc] != 'P' &&
42849e39c5baSBill Taylor 		    vpd.vpd_char[vpd_ro_pn_desc + 1] != 'N')) {
42859e39c5baSBill Taylor 			cmn_err(CE_NOTE, "!VPD Part Number not found\n");
42869e39c5baSBill Taylor 			goto out;
42879e39c5baSBill Taylor 		}
42889e39c5baSBill Taylor 
42899e39c5baSBill Taylor 		pn_length = (uint8_t)vpd.vpd_char[vpd_ro_pn_desc + 2];
42909e39c5baSBill Taylor 		if (pn_length > sizeof (state->hs_hca_pn)) {
42919e39c5baSBill Taylor 			cmn_err(CE_NOTE, "!VPD part number too large (0x%x)\n",
42929e39c5baSBill Taylor 			    name_length);
42939e39c5baSBill Taylor 			goto out;
42949e39c5baSBill Taylor 		}
42959e39c5baSBill Taylor 		(void) memcpy(state->hs_hca_pn,
42969e39c5baSBill Taylor 		    &vpd.vpd_char[vpd_ro_pn_desc + 3],
42979e39c5baSBill Taylor 		    pn_length);
42989e39c5baSBill Taylor 		state->hs_hca_pn[pn_length] = 0;
42999e39c5baSBill Taylor 		state->hs_hca_pn_len = pn_length;
43009e39c5baSBill Taylor 		cmn_err(CE_CONT, "!vpd %s\n", state->hs_hca_pn);
43019e39c5baSBill Taylor 	} else {
43029e39c5baSBill Taylor 		/* Wrong VPD String ID Tag */
43039e39c5baSBill Taylor 		cmn_err(CE_NOTE, "!VPD String ID Tag not found, tag: %02x\n",
43049e39c5baSBill Taylor 		    vpd.vpd_char[0]);
43059e39c5baSBill Taylor 		goto out;
43069e39c5baSBill Taylor 	}
43079e39c5baSBill Taylor 	return;
43089e39c5baSBill Taylor out:
43099e39c5baSBill Taylor 	state->hs_hca_pn_len = 0;
43109e39c5baSBill Taylor }
43119e39c5baSBill Taylor 
43129e39c5baSBill Taylor 
43139e39c5baSBill Taylor 
43149e39c5baSBill Taylor /*
43159e39c5baSBill Taylor  * hermon_intr_or_msi_init()
43169e39c5baSBill Taylor  *    Context: Only called from attach() path context
43179e39c5baSBill Taylor  */
43189e39c5baSBill Taylor static int
hermon_intr_or_msi_init(hermon_state_t * state)43199e39c5baSBill Taylor hermon_intr_or_msi_init(hermon_state_t *state)
43209e39c5baSBill Taylor {
43219e39c5baSBill Taylor 	int	status;
43229e39c5baSBill Taylor 
43239e39c5baSBill Taylor 	/* Query for the list of supported interrupt event types */
43249e39c5baSBill Taylor 	status = ddi_intr_get_supported_types(state->hs_dip,
43259e39c5baSBill Taylor 	    &state->hs_intr_types_avail);
43269e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
43279e39c5baSBill Taylor 		return (DDI_FAILURE);
43289e39c5baSBill Taylor 	}
43299e39c5baSBill Taylor 
43309e39c5baSBill Taylor 	/*
43319e39c5baSBill Taylor 	 * If Hermon supports MSI-X in this system (and, if it
43329e39c5baSBill Taylor 	 * hasn't been overridden by a configuration variable), then
43339e39c5baSBill Taylor 	 * the default behavior is to use a single MSI-X.  Otherwise,
43349e39c5baSBill Taylor 	 * fallback to using legacy interrupts.  Also, if MSI-X is chosen,
43359e39c5baSBill Taylor 	 * but fails for whatever reasons, then next try MSI
43369e39c5baSBill Taylor 	 */
43379e39c5baSBill Taylor 	if ((state->hs_cfg_profile->cp_use_msi_if_avail != 0) &&
43389e39c5baSBill Taylor 	    (state->hs_intr_types_avail & DDI_INTR_TYPE_MSIX)) {
43399e39c5baSBill Taylor 		status = hermon_add_intrs(state, DDI_INTR_TYPE_MSIX);
43409e39c5baSBill Taylor 		if (status == DDI_SUCCESS) {
43419e39c5baSBill Taylor 			state->hs_intr_type_chosen = DDI_INTR_TYPE_MSIX;
43429e39c5baSBill Taylor 			return (DDI_SUCCESS);
43439e39c5baSBill Taylor 		}
43449e39c5baSBill Taylor 	}
43459e39c5baSBill Taylor 
43469e39c5baSBill Taylor 	/*
43479e39c5baSBill Taylor 	 * If Hermon supports MSI in this system (and, if it
43489e39c5baSBill Taylor 	 * hasn't been overridden by a configuration variable), then
43499e39c5baSBill Taylor 	 * the default behavior is to use a single MSIX.  Otherwise,
43509e39c5baSBill Taylor 	 * fallback to using legacy interrupts.  Also, if MSI is chosen,
43519e39c5baSBill Taylor 	 * but fails for whatever reasons, then fallback to using legacy
43529e39c5baSBill Taylor 	 * interrupts.
43539e39c5baSBill Taylor 	 */
43549e39c5baSBill Taylor 	if ((state->hs_cfg_profile->cp_use_msi_if_avail != 0) &&
43559e39c5baSBill Taylor 	    (state->hs_intr_types_avail & DDI_INTR_TYPE_MSI)) {
43569e39c5baSBill Taylor 		status = hermon_add_intrs(state, DDI_INTR_TYPE_MSI);
43579e39c5baSBill Taylor 		if (status == DDI_SUCCESS) {
43589e39c5baSBill Taylor 			state->hs_intr_type_chosen = DDI_INTR_TYPE_MSI;
43599e39c5baSBill Taylor 			return (DDI_SUCCESS);
43609e39c5baSBill Taylor 		}
43619e39c5baSBill Taylor 	}
43629e39c5baSBill Taylor 
43639e39c5baSBill Taylor 	/*
43649e39c5baSBill Taylor 	 * MSI interrupt allocation failed, or was not available.  Fallback to
43659e39c5baSBill Taylor 	 * legacy interrupt support.
43669e39c5baSBill Taylor 	 */
43679e39c5baSBill Taylor 	if (state->hs_intr_types_avail & DDI_INTR_TYPE_FIXED) {
43689e39c5baSBill Taylor 		status = hermon_add_intrs(state, DDI_INTR_TYPE_FIXED);
43699e39c5baSBill Taylor 		if (status == DDI_SUCCESS) {
43709e39c5baSBill Taylor 			state->hs_intr_type_chosen = DDI_INTR_TYPE_FIXED;
43719e39c5baSBill Taylor 			return (DDI_SUCCESS);
43729e39c5baSBill Taylor 		}
43739e39c5baSBill Taylor 	}
43749e39c5baSBill Taylor 
43759e39c5baSBill Taylor 	/*
43769e39c5baSBill Taylor 	 * None of MSI, MSI-X, nor legacy interrupts were successful.
43779e39c5baSBill Taylor 	 * Return failure.
43789e39c5baSBill Taylor 	 */
43799e39c5baSBill Taylor 	return (DDI_FAILURE);
43809e39c5baSBill Taylor }
43819e39c5baSBill Taylor 
438217a2b317SBill Taylor /* ARGSUSED */
438317a2b317SBill Taylor static int
hermon_intr_cb_handler(dev_info_t * dip,ddi_cb_action_t action,void * cbarg,void * arg1,void * arg2)438417a2b317SBill Taylor hermon_intr_cb_handler(dev_info_t *dip, ddi_cb_action_t action, void *cbarg,
438517a2b317SBill Taylor     void *arg1, void *arg2)
438617a2b317SBill Taylor {
438717a2b317SBill Taylor 	hermon_state_t *state = (hermon_state_t *)arg1;
438817a2b317SBill Taylor 
438917a2b317SBill Taylor 	IBTF_DPRINTF_L2("hermon", "interrupt callback: instance %d, "
439017a2b317SBill Taylor 	    "action %d, cbarg %d\n", state->hs_instance, action,
439117a2b317SBill Taylor 	    (uint32_t)(uintptr_t)cbarg);
439217a2b317SBill Taylor 	return (DDI_SUCCESS);
439317a2b317SBill Taylor }
439417a2b317SBill Taylor 
43959e39c5baSBill Taylor /*
43969e39c5baSBill Taylor  * hermon_add_intrs()
43979e39c5baSBill Taylor  *    Context: Only called from attach() patch context
43989e39c5baSBill Taylor  */
43999e39c5baSBill Taylor static int
hermon_add_intrs(hermon_state_t * state,int intr_type)44009e39c5baSBill Taylor hermon_add_intrs(hermon_state_t *state, int intr_type)
44019e39c5baSBill Taylor {
44029e39c5baSBill Taylor 	int	status;
44039e39c5baSBill Taylor 
440417a2b317SBill Taylor 	if (state->hs_intr_cb_hdl == NULL) {
440517a2b317SBill Taylor 		status = ddi_cb_register(state->hs_dip, DDI_CB_FLAG_INTR,
440617a2b317SBill Taylor 		    hermon_intr_cb_handler, state, NULL,
440717a2b317SBill Taylor 		    &state->hs_intr_cb_hdl);
440817a2b317SBill Taylor 		if (status != DDI_SUCCESS) {
440917a2b317SBill Taylor 			cmn_err(CE_CONT, "ddi_cb_register failed: 0x%x\n",
441017a2b317SBill Taylor 			    status);
441117a2b317SBill Taylor 			state->hs_intr_cb_hdl = NULL;
441217a2b317SBill Taylor 			return (DDI_FAILURE);
441317a2b317SBill Taylor 		}
441417a2b317SBill Taylor 	}
44159e39c5baSBill Taylor 
44169e39c5baSBill Taylor 	/* Get number of interrupts/MSI supported */
44179e39c5baSBill Taylor 	status = ddi_intr_get_nintrs(state->hs_dip, intr_type,
44189e39c5baSBill Taylor 	    &state->hs_intrmsi_count);
44199e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
442017a2b317SBill Taylor 		(void) ddi_cb_unregister(state->hs_intr_cb_hdl);
442117a2b317SBill Taylor 		state->hs_intr_cb_hdl = NULL;
44229e39c5baSBill Taylor 		return (DDI_FAILURE);
44239e39c5baSBill Taylor 	}
44249e39c5baSBill Taylor 
44259e39c5baSBill Taylor 	/* Get number of available interrupts/MSI */
44269e39c5baSBill Taylor 	status = ddi_intr_get_navail(state->hs_dip, intr_type,
44279e39c5baSBill Taylor 	    &state->hs_intrmsi_avail);
44289e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
442917a2b317SBill Taylor 		(void) ddi_cb_unregister(state->hs_intr_cb_hdl);
443017a2b317SBill Taylor 		state->hs_intr_cb_hdl = NULL;
44319e39c5baSBill Taylor 		return (DDI_FAILURE);
44329e39c5baSBill Taylor 	}
44339e39c5baSBill Taylor 
44349e39c5baSBill Taylor 	/* Ensure that we have at least one (1) usable MSI or interrupt */
44359e39c5baSBill Taylor 	if ((state->hs_intrmsi_avail < 1) || (state->hs_intrmsi_count < 1)) {
443617a2b317SBill Taylor 		(void) ddi_cb_unregister(state->hs_intr_cb_hdl);
443717a2b317SBill Taylor 		state->hs_intr_cb_hdl = NULL;
44389e39c5baSBill Taylor 		return (DDI_FAILURE);
44399e39c5baSBill Taylor 	}
44409e39c5baSBill Taylor 
444117a2b317SBill Taylor 	/*
444217a2b317SBill Taylor 	 * Allocate the #interrupt/MSI handles.
444317a2b317SBill Taylor 	 * The number we request is the minimum of these three values:
444417a2b317SBill Taylor 	 *	HERMON_MSIX_MAX			driver maximum (array size)
444517a2b317SBill Taylor 	 *	hermon_msix_max			/etc/system override to...
444617a2b317SBill Taylor 	 *						HERMON_MSIX_MAX
444717a2b317SBill Taylor 	 *	state->hs_intrmsi_avail		Maximum the ddi provides.
444817a2b317SBill Taylor 	 */
44499e39c5baSBill Taylor 	status = ddi_intr_alloc(state->hs_dip, &state->hs_intrmsi_hdl[0],
445017a2b317SBill Taylor 	    intr_type, 0, min(min(HERMON_MSIX_MAX, state->hs_intrmsi_avail),
445117a2b317SBill Taylor 	    hermon_msix_max), &state->hs_intrmsi_allocd, DDI_INTR_ALLOC_NORMAL);
44529e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
445317a2b317SBill Taylor 		(void) ddi_cb_unregister(state->hs_intr_cb_hdl);
445417a2b317SBill Taylor 		state->hs_intr_cb_hdl = NULL;
44559e39c5baSBill Taylor 		return (DDI_FAILURE);
44569e39c5baSBill Taylor 	}
44579e39c5baSBill Taylor 
44589e39c5baSBill Taylor 	/* Ensure that we have allocated at least one (1) MSI or interrupt */
44599e39c5baSBill Taylor 	if (state->hs_intrmsi_allocd < 1) {
446017a2b317SBill Taylor 		(void) ddi_cb_unregister(state->hs_intr_cb_hdl);
446117a2b317SBill Taylor 		state->hs_intr_cb_hdl = NULL;
44629e39c5baSBill Taylor 		return (DDI_FAILURE);
44639e39c5baSBill Taylor 	}
44649e39c5baSBill Taylor 
44659e39c5baSBill Taylor 	/*
44669e39c5baSBill Taylor 	 * Extract the priority for the allocated interrupt/MSI.  This
44679e39c5baSBill Taylor 	 * will be used later when initializing certain mutexes.
44689e39c5baSBill Taylor 	 */
44699e39c5baSBill Taylor 	status = ddi_intr_get_pri(state->hs_intrmsi_hdl[0],
44709e39c5baSBill Taylor 	    &state->hs_intrmsi_pri);
44719e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
44729e39c5baSBill Taylor 		/* Free the allocated interrupt/MSI handle */
44739e39c5baSBill Taylor 		(void) ddi_intr_free(state->hs_intrmsi_hdl[0]);
44749e39c5baSBill Taylor 
447517a2b317SBill Taylor 		(void) ddi_cb_unregister(state->hs_intr_cb_hdl);
447617a2b317SBill Taylor 		state->hs_intr_cb_hdl = NULL;
44779e39c5baSBill Taylor 		return (DDI_FAILURE);
44789e39c5baSBill Taylor 	}
44799e39c5baSBill Taylor 
44809e39c5baSBill Taylor 	/* Make sure the interrupt/MSI priority is below 'high level' */
44819e39c5baSBill Taylor 	if (state->hs_intrmsi_pri >= ddi_intr_get_hilevel_pri()) {
44829e39c5baSBill Taylor 		/* Free the allocated interrupt/MSI handle */
44839e39c5baSBill Taylor 		(void) ddi_intr_free(state->hs_intrmsi_hdl[0]);
44849e39c5baSBill Taylor 
44859e39c5baSBill Taylor 		return (DDI_FAILURE);
44869e39c5baSBill Taylor 	}
44879e39c5baSBill Taylor 
44889e39c5baSBill Taylor 	/* Get add'l capability information regarding interrupt/MSI */
44899e39c5baSBill Taylor 	status = ddi_intr_get_cap(state->hs_intrmsi_hdl[0],
44909e39c5baSBill Taylor 	    &state->hs_intrmsi_cap);
44919e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
44929e39c5baSBill Taylor 		/* Free the allocated interrupt/MSI handle */
44939e39c5baSBill Taylor 		(void) ddi_intr_free(state->hs_intrmsi_hdl[0]);
44949e39c5baSBill Taylor 
44959e39c5baSBill Taylor 		return (DDI_FAILURE);
44969e39c5baSBill Taylor 	}
44979e39c5baSBill Taylor 
44989e39c5baSBill Taylor 	return (DDI_SUCCESS);
44999e39c5baSBill Taylor }
45009e39c5baSBill Taylor 
45019e39c5baSBill Taylor 
45029e39c5baSBill Taylor /*
45039e39c5baSBill Taylor  * hermon_intr_or_msi_fini()
45049e39c5baSBill Taylor  *    Context: Only called from attach() and/or detach() path contexts
45059e39c5baSBill Taylor  */
45069e39c5baSBill Taylor static int
hermon_intr_or_msi_fini(hermon_state_t * state)45079e39c5baSBill Taylor hermon_intr_or_msi_fini(hermon_state_t *state)
45089e39c5baSBill Taylor {
45099e39c5baSBill Taylor 	int	status;
45109e39c5baSBill Taylor 	int	intr;
45119e39c5baSBill Taylor 
45129e39c5baSBill Taylor 	for (intr = 0; intr < state->hs_intrmsi_allocd; intr++) {
45139e39c5baSBill Taylor 
45149e39c5baSBill Taylor 		/* Free the allocated interrupt/MSI handle */
45159e39c5baSBill Taylor 		status = ddi_intr_free(state->hs_intrmsi_hdl[intr]);
45169e39c5baSBill Taylor 		if (status != DDI_SUCCESS) {
45179e39c5baSBill Taylor 			return (DDI_FAILURE);
45189e39c5baSBill Taylor 		}
45199e39c5baSBill Taylor 	}
452017a2b317SBill Taylor 	if (state->hs_intr_cb_hdl) {
452117a2b317SBill Taylor 		(void) ddi_cb_unregister(state->hs_intr_cb_hdl);
452217a2b317SBill Taylor 		state->hs_intr_cb_hdl = NULL;
452317a2b317SBill Taylor 	}
45249e39c5baSBill Taylor 	return (DDI_SUCCESS);
45259e39c5baSBill Taylor }
45269e39c5baSBill Taylor 
45279e39c5baSBill Taylor 
45289e39c5baSBill Taylor /*ARGSUSED*/
45299e39c5baSBill Taylor void
hermon_pci_capability_msix(hermon_state_t * state,ddi_acc_handle_t hdl,uint_t offset)45309e39c5baSBill Taylor hermon_pci_capability_msix(hermon_state_t *state, ddi_acc_handle_t hdl,
45319e39c5baSBill Taylor     uint_t offset)
45329e39c5baSBill Taylor {
45339e39c5baSBill Taylor 	uint32_t	msix_data;
45349e39c5baSBill Taylor 	uint16_t	msg_cntr;
45359e39c5baSBill Taylor 	uint32_t	t_offset;	/* table offset */
45369e39c5baSBill Taylor 	uint32_t	t_bir;
45379e39c5baSBill Taylor 	uint32_t	p_offset;	/* pba */
45389e39c5baSBill Taylor 	uint32_t	p_bir;
45399e39c5baSBill Taylor 	int		t_size;		/* size in entries - each is 4 dwords */
45409e39c5baSBill Taylor 
45419e39c5baSBill Taylor 	/* come in with offset pointing at the capability structure */
45429e39c5baSBill Taylor 
45439e39c5baSBill Taylor 	msix_data = pci_config_get32(hdl, offset);
45449e39c5baSBill Taylor 	cmn_err(CE_CONT, "Full cap structure dword = %X\n", msix_data);
45459e39c5baSBill Taylor 	msg_cntr =  pci_config_get16(hdl, offset+2);
45469e39c5baSBill Taylor 	cmn_err(CE_CONT, "MSIX msg_control = %X\n", msg_cntr);
45479e39c5baSBill Taylor 	offset += 4;
45489e39c5baSBill Taylor 	msix_data = pci_config_get32(hdl, offset);	/* table info */
45499e39c5baSBill Taylor 	t_offset = (msix_data & 0xFFF8) >> 3;
45509e39c5baSBill Taylor 	t_bir = msix_data & 0x07;
45519e39c5baSBill Taylor 	offset += 4;
45529e39c5baSBill Taylor 	cmn_err(CE_CONT, "  table %X --offset = %X, bir(bar) = %X\n",
45539e39c5baSBill Taylor 	    msix_data, t_offset, t_bir);
45549e39c5baSBill Taylor 	msix_data = pci_config_get32(hdl, offset);	/* PBA info */
45559e39c5baSBill Taylor 	p_offset = (msix_data & 0xFFF8) >> 3;
45569e39c5baSBill Taylor 	p_bir = msix_data & 0x07;
45579e39c5baSBill Taylor 
45589e39c5baSBill Taylor 	cmn_err(CE_CONT, "  PBA   %X --offset = %X, bir(bar) = %X\n",
45599e39c5baSBill Taylor 	    msix_data, p_offset, p_bir);
45609e39c5baSBill Taylor 	t_size = msg_cntr & 0x7FF;		/* low eleven bits */
45619e39c5baSBill Taylor 	cmn_err(CE_CONT, "    table size = %X entries\n", t_size);
45629e39c5baSBill Taylor 
45639e39c5baSBill Taylor 	offset = t_offset;		/* reuse this for offset from BAR */
45649e39c5baSBill Taylor #ifdef HERMON_SUPPORTS_MSIX_BAR
45659e39c5baSBill Taylor 	cmn_err(CE_CONT, "First 2 table entries behind BAR2 \n");
45669e39c5baSBill Taylor 	for (i = 0; i < 2; i++) {
45679e39c5baSBill Taylor 		for (j = 0; j < 4; j++, offset += 4) {
45689e39c5baSBill Taylor 			msix_data = ddi_get32(state->hs_reg_msihdl,
45699e39c5baSBill Taylor 			    (uint32_t *)((uintptr_t)state->hs_reg_msi_baseaddr
45709e39c5baSBill Taylor 			    + offset));
45719e39c5baSBill Taylor 			cmn_err(CE_CONT, "MSI table entry %d, dword %d == %X\n",
45729e39c5baSBill Taylor 			    i, j, msix_data);
45739e39c5baSBill Taylor 		}
45749e39c5baSBill Taylor 	}
45759e39c5baSBill Taylor #endif
45769e39c5baSBill Taylor 
45779e39c5baSBill Taylor }
45789e39c5baSBill Taylor 
45799e39c5baSBill Taylor /*
45809e39c5baSBill Taylor  * X86 fastreboot support functions.
45819e39c5baSBill Taylor  * These functions are used to save/restore MSI-X table/PBA and also
45829e39c5baSBill Taylor  * to disable MSI-X interrupts in hermon_quiesce().
45839e39c5baSBill Taylor  */
45849e39c5baSBill Taylor 
45859e39c5baSBill Taylor /* Return the message control for MSI-X */
45869e39c5baSBill Taylor static ushort_t
get_msix_ctrl(dev_info_t * dip)45879e39c5baSBill Taylor get_msix_ctrl(dev_info_t *dip)
45889e39c5baSBill Taylor {
45899e39c5baSBill Taylor 	ushort_t msix_ctrl = 0, caps_ctrl = 0;
45909e39c5baSBill Taylor 	hermon_state_t *state = ddi_get_soft_state(hermon_statep,
45919e39c5baSBill Taylor 	    DEVI(dip)->devi_instance);
45929e39c5baSBill Taylor 	ddi_acc_handle_t pci_cfg_hdl = hermon_get_pcihdl(state);
45939e39c5baSBill Taylor 	ASSERT(pci_cfg_hdl != NULL);
45949e39c5baSBill Taylor 
45959e39c5baSBill Taylor 	if ((PCI_CAP_LOCATE(pci_cfg_hdl,
45969e39c5baSBill Taylor 	    PCI_CAP_ID_MSI_X, &caps_ctrl) == DDI_SUCCESS)) {
4597*0b63ccafSToomas Soome 		if ((msix_ctrl = PCI_CAP_GET16(pci_cfg_hdl, 0, caps_ctrl,
45989e39c5baSBill Taylor 		    PCI_MSIX_CTRL)) == PCI_CAP_EINVAL16)
45999e39c5baSBill Taylor 			return (0);
46009e39c5baSBill Taylor 	}
46019e39c5baSBill Taylor 	ASSERT(msix_ctrl != 0);
46029e39c5baSBill Taylor 
46039e39c5baSBill Taylor 	return (msix_ctrl);
46049e39c5baSBill Taylor }
46059e39c5baSBill Taylor 
46069e39c5baSBill Taylor /* Return the MSI-X table size */
46079e39c5baSBill Taylor static size_t
get_msix_tbl_size(dev_info_t * dip)46089e39c5baSBill Taylor get_msix_tbl_size(dev_info_t *dip)
46099e39c5baSBill Taylor {
46109e39c5baSBill Taylor 	ushort_t msix_ctrl = get_msix_ctrl(dip);
46119e39c5baSBill Taylor 	ASSERT(msix_ctrl != 0);
46129e39c5baSBill Taylor 
46139e39c5baSBill Taylor 	return (((msix_ctrl & PCI_MSIX_TBL_SIZE_MASK) + 1) *
46149e39c5baSBill Taylor 	    PCI_MSIX_VECTOR_SIZE);
46159e39c5baSBill Taylor }
46169e39c5baSBill Taylor 
46179e39c5baSBill Taylor /* Return the MSI-X PBA size */
46189e39c5baSBill Taylor static size_t
get_msix_pba_size(dev_info_t * dip)46199e39c5baSBill Taylor get_msix_pba_size(dev_info_t *dip)
46209e39c5baSBill Taylor {
46219e39c5baSBill Taylor 	ushort_t msix_ctrl = get_msix_ctrl(dip);
46229e39c5baSBill Taylor 	ASSERT(msix_ctrl != 0);
46239e39c5baSBill Taylor 
46249e39c5baSBill Taylor 	return (((msix_ctrl & PCI_MSIX_TBL_SIZE_MASK) + 64) / 64 * 8);
46259e39c5baSBill Taylor }
46269e39c5baSBill Taylor 
46279e39c5baSBill Taylor /* Set up the MSI-X table/PBA save area */
46289e39c5baSBill Taylor static void
hermon_set_msix_info(hermon_state_t * state)46299e39c5baSBill Taylor hermon_set_msix_info(hermon_state_t *state)
46309e39c5baSBill Taylor {
46319e39c5baSBill Taylor 	uint_t			rnumber, breg, nregs;
46329e39c5baSBill Taylor 	ushort_t		caps_ctrl, msix_ctrl;
46339e39c5baSBill Taylor 	pci_regspec_t		*rp;
46349e39c5baSBill Taylor 	int			reg_size, addr_space, offset, *regs_list, i;
46359e39c5baSBill Taylor 
46369e39c5baSBill Taylor 	/*
46379e39c5baSBill Taylor 	 * MSI-X BIR Index Table:
46389e39c5baSBill Taylor 	 * BAR indicator register (BIR) to Base Address register.
46399e39c5baSBill Taylor 	 */
46409e39c5baSBill Taylor 	uchar_t pci_msix_bir_index[8] = {0x10, 0x14, 0x18, 0x1c,
46419e39c5baSBill Taylor 	    0x20, 0x24, 0xff, 0xff};
46429e39c5baSBill Taylor 
46439e39c5baSBill Taylor 	/* Fastreboot data access  attribute */
46449e39c5baSBill Taylor 	ddi_device_acc_attr_t	dev_attr = {
46459e39c5baSBill Taylor 		0,				/* version */
46469e39c5baSBill Taylor 		DDI_STRUCTURE_LE_ACC,
46479e39c5baSBill Taylor 		DDI_STRICTORDER_ACC,		/* attr access */
46489e39c5baSBill Taylor 		0
46499e39c5baSBill Taylor 	};
46509e39c5baSBill Taylor 
46519e39c5baSBill Taylor 	ddi_acc_handle_t pci_cfg_hdl = hermon_get_pcihdl(state);
46529e39c5baSBill Taylor 	ASSERT(pci_cfg_hdl != NULL);
46539e39c5baSBill Taylor 
46549e39c5baSBill Taylor 	if ((PCI_CAP_LOCATE(pci_cfg_hdl,
46559e39c5baSBill Taylor 	    PCI_CAP_ID_MSI_X, &caps_ctrl) == DDI_SUCCESS)) {
4656*0b63ccafSToomas Soome 		if ((msix_ctrl = PCI_CAP_GET16(pci_cfg_hdl, 0, caps_ctrl,
46579e39c5baSBill Taylor 		    PCI_MSIX_CTRL)) == PCI_CAP_EINVAL16)
46589e39c5baSBill Taylor 			return;
46599e39c5baSBill Taylor 	}
46609e39c5baSBill Taylor 	ASSERT(msix_ctrl != 0);
46619e39c5baSBill Taylor 
4662*0b63ccafSToomas Soome 	state->hs_msix_tbl_offset = PCI_CAP_GET32(pci_cfg_hdl, 0, caps_ctrl,
46639e39c5baSBill Taylor 	    PCI_MSIX_TBL_OFFSET);
46649e39c5baSBill Taylor 
46659e39c5baSBill Taylor 	/* Get the BIR for MSI-X table */
46669e39c5baSBill Taylor 	breg = pci_msix_bir_index[state->hs_msix_tbl_offset &
46679e39c5baSBill Taylor 	    PCI_MSIX_TBL_BIR_MASK];
46689e39c5baSBill Taylor 	ASSERT(breg != 0xFF);
46699e39c5baSBill Taylor 
46709e39c5baSBill Taylor 	/* Set the MSI-X table offset */
46719e39c5baSBill Taylor 	state->hs_msix_tbl_offset = state->hs_msix_tbl_offset &
46729e39c5baSBill Taylor 	    ~PCI_MSIX_TBL_BIR_MASK;
46739e39c5baSBill Taylor 
46749e39c5baSBill Taylor 	/* Set the MSI-X table size */
46759e39c5baSBill Taylor 	state->hs_msix_tbl_size = ((msix_ctrl & PCI_MSIX_TBL_SIZE_MASK) + 1) *
46769e39c5baSBill Taylor 	    PCI_MSIX_VECTOR_SIZE;
46779e39c5baSBill Taylor 
46789e39c5baSBill Taylor 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, state->hs_dip,
46799e39c5baSBill Taylor 	    DDI_PROP_DONTPASS, "reg", (int **)&regs_list, &nregs) !=
46809e39c5baSBill Taylor 	    DDI_PROP_SUCCESS) {
46819e39c5baSBill Taylor 		return;
46829e39c5baSBill Taylor 	}
46839e39c5baSBill Taylor 	reg_size = sizeof (pci_regspec_t) / sizeof (int);
46849e39c5baSBill Taylor 
46859e39c5baSBill Taylor 	/* Check the register number for MSI-X table */
46869e39c5baSBill Taylor 	for (i = 1, rnumber = 0; i < nregs/reg_size; i++) {
46879e39c5baSBill Taylor 		rp = (pci_regspec_t *)&regs_list[i * reg_size];
46889e39c5baSBill Taylor 		addr_space = rp->pci_phys_hi & PCI_ADDR_MASK;
46899e39c5baSBill Taylor 		offset = PCI_REG_REG_G(rp->pci_phys_hi);
46909e39c5baSBill Taylor 
46919e39c5baSBill Taylor 		if ((offset == breg) && ((addr_space == PCI_ADDR_MEM32) ||
46929e39c5baSBill Taylor 		    (addr_space == PCI_ADDR_MEM64))) {
46939e39c5baSBill Taylor 			rnumber = i;
46949e39c5baSBill Taylor 			break;
46959e39c5baSBill Taylor 		}
46969e39c5baSBill Taylor 	}
46979e39c5baSBill Taylor 	ASSERT(rnumber != 0);
46989e39c5baSBill Taylor 	state->hs_msix_tbl_rnumber = rnumber;
46999e39c5baSBill Taylor 
47009e39c5baSBill Taylor 	/* Set device attribute version and access according to Hermon FM */
47019e39c5baSBill Taylor 	dev_attr.devacc_attr_version = hermon_devacc_attr_version(state);
47029e39c5baSBill Taylor 	dev_attr.devacc_attr_access = hermon_devacc_attr_access(state);
47039e39c5baSBill Taylor 
47049e39c5baSBill Taylor 	/* Map the entire MSI-X vector table */
47059e39c5baSBill Taylor 	if (hermon_regs_map_setup(state, state->hs_msix_tbl_rnumber,
47069e39c5baSBill Taylor 	    (caddr_t *)&state->hs_msix_tbl_addr, state->hs_msix_tbl_offset,
47079e39c5baSBill Taylor 	    state->hs_msix_tbl_size, &dev_attr,
47089e39c5baSBill Taylor 	    &state->hs_fm_msix_tblhdl) != DDI_SUCCESS) {
47099e39c5baSBill Taylor 		return;
47109e39c5baSBill Taylor 	}
47119e39c5baSBill Taylor 
4712*0b63ccafSToomas Soome 	state->hs_msix_pba_offset = PCI_CAP_GET32(pci_cfg_hdl, 0, caps_ctrl,
47139e39c5baSBill Taylor 	    PCI_MSIX_PBA_OFFSET);
47149e39c5baSBill Taylor 
47159e39c5baSBill Taylor 	/* Get the BIR for MSI-X PBA */
47169e39c5baSBill Taylor 	breg = pci_msix_bir_index[state->hs_msix_pba_offset &
47179e39c5baSBill Taylor 	    PCI_MSIX_PBA_BIR_MASK];
47189e39c5baSBill Taylor 	ASSERT(breg != 0xFF);
47199e39c5baSBill Taylor 
47209e39c5baSBill Taylor 	/* Set the MSI-X PBA offset */
47219e39c5baSBill Taylor 	state->hs_msix_pba_offset = state->hs_msix_pba_offset &
47229e39c5baSBill Taylor 	    ~PCI_MSIX_PBA_BIR_MASK;
47239e39c5baSBill Taylor 
47249e39c5baSBill Taylor 	/* Set the MSI-X PBA size */
47259e39c5baSBill Taylor 	state->hs_msix_pba_size =
47269e39c5baSBill Taylor 	    ((msix_ctrl & PCI_MSIX_TBL_SIZE_MASK) + 64) / 64 * 8;
47279e39c5baSBill Taylor 
47289e39c5baSBill Taylor 	/* Check the register number for MSI-X PBA */
47299e39c5baSBill Taylor 	for (i = 1, rnumber = 0; i < nregs/reg_size; i++) {
47309e39c5baSBill Taylor 		rp = (pci_regspec_t *)&regs_list[i * reg_size];
47319e39c5baSBill Taylor 		addr_space = rp->pci_phys_hi & PCI_ADDR_MASK;
47329e39c5baSBill Taylor 		offset = PCI_REG_REG_G(rp->pci_phys_hi);
47339e39c5baSBill Taylor 
47349e39c5baSBill Taylor 		if ((offset == breg) && ((addr_space == PCI_ADDR_MEM32) ||
47359e39c5baSBill Taylor 		    (addr_space == PCI_ADDR_MEM64))) {
47369e39c5baSBill Taylor 			rnumber = i;
47379e39c5baSBill Taylor 			break;
47389e39c5baSBill Taylor 		}
47399e39c5baSBill Taylor 	}
47409e39c5baSBill Taylor 	ASSERT(rnumber != 0);
47419e39c5baSBill Taylor 	state->hs_msix_pba_rnumber = rnumber;
474213cc0a0bSBill Taylor 	ddi_prop_free(regs_list);
47439e39c5baSBill Taylor 
47449e39c5baSBill Taylor 	/* Map in the MSI-X Pending Bit Array */
47459e39c5baSBill Taylor 	if (hermon_regs_map_setup(state, state->hs_msix_pba_rnumber,
47469e39c5baSBill Taylor 	    (caddr_t *)&state->hs_msix_pba_addr, state->hs_msix_pba_offset,
47479e39c5baSBill Taylor 	    state->hs_msix_pba_size, &dev_attr,
47489e39c5baSBill Taylor 	    &state->hs_fm_msix_pbahdl) != DDI_SUCCESS) {
47499e39c5baSBill Taylor 		hermon_regs_map_free(state, &state->hs_fm_msix_tblhdl);
47509e39c5baSBill Taylor 		state->hs_fm_msix_tblhdl = NULL;
47519e39c5baSBill Taylor 		return;
47529e39c5baSBill Taylor 	}
47539e39c5baSBill Taylor 
47549e39c5baSBill Taylor 	/* Set the MSI-X table save area */
47559e39c5baSBill Taylor 	state->hs_msix_tbl_entries = kmem_alloc(state->hs_msix_tbl_size,
47569e39c5baSBill Taylor 	    KM_SLEEP);
47579e39c5baSBill Taylor 
47589e39c5baSBill Taylor 	/* Set the MSI-X PBA save area */
47599e39c5baSBill Taylor 	state->hs_msix_pba_entries = kmem_alloc(state->hs_msix_pba_size,
47609e39c5baSBill Taylor 	    KM_SLEEP);
47619e39c5baSBill Taylor }
47629e39c5baSBill Taylor 
47639e39c5baSBill Taylor /* Disable Hermon interrupts */
47649e39c5baSBill Taylor static int
hermon_intr_disable(hermon_state_t * state)47659e39c5baSBill Taylor hermon_intr_disable(hermon_state_t *state)
47669e39c5baSBill Taylor {
47679e39c5baSBill Taylor 	ushort_t msix_ctrl = 0, caps_ctrl = 0;
47689e39c5baSBill Taylor 	ddi_acc_handle_t pci_cfg_hdl = hermon_get_pcihdl(state);
47699e39c5baSBill Taylor 	ddi_acc_handle_t msix_tblhdl = hermon_get_msix_tblhdl(state);
47709e39c5baSBill Taylor 	int i, j;
47719e39c5baSBill Taylor 	ASSERT(pci_cfg_hdl != NULL && msix_tblhdl != NULL);
47729e39c5baSBill Taylor 	ASSERT(state->hs_intr_types_avail &
47739e39c5baSBill Taylor 	    (DDI_INTR_TYPE_FIXED | DDI_INTR_TYPE_MSI | DDI_INTR_TYPE_MSIX));
47749e39c5baSBill Taylor 
47759e39c5baSBill Taylor 	/*
47769e39c5baSBill Taylor 	 * Check if MSI-X interrupts are used. If so, disable MSI-X interupts.
47779e39c5baSBill Taylor 	 * If not, since Hermon doesn't support MSI interrupts, assuming the
47789e39c5baSBill Taylor 	 * legacy interrupt is used instead, disable the legacy interrupt.
47799e39c5baSBill Taylor 	 */
47809e39c5baSBill Taylor 	if ((state->hs_cfg_profile->cp_use_msi_if_avail != 0) &&
47819e39c5baSBill Taylor 	    (state->hs_intr_types_avail & DDI_INTR_TYPE_MSIX)) {
47829e39c5baSBill Taylor 
47839e39c5baSBill Taylor 		if ((PCI_CAP_LOCATE(pci_cfg_hdl,
47849e39c5baSBill Taylor 		    PCI_CAP_ID_MSI_X, &caps_ctrl) == DDI_SUCCESS)) {
4785*0b63ccafSToomas Soome 			if ((msix_ctrl = PCI_CAP_GET16(pci_cfg_hdl, 0,
47869e39c5baSBill Taylor 			    caps_ctrl, PCI_MSIX_CTRL)) == PCI_CAP_EINVAL16)
47879e39c5baSBill Taylor 				return (DDI_FAILURE);
47889e39c5baSBill Taylor 		}
47899e39c5baSBill Taylor 		ASSERT(msix_ctrl != 0);
47909e39c5baSBill Taylor 
47919e39c5baSBill Taylor 		if (!(msix_ctrl & PCI_MSIX_ENABLE_BIT))
47929e39c5baSBill Taylor 			return (DDI_SUCCESS);
47939e39c5baSBill Taylor 
47949e39c5baSBill Taylor 		/* Clear all inums in MSI-X table */
47959e39c5baSBill Taylor 		for (i = 0; i < get_msix_tbl_size(state->hs_dip);
47969e39c5baSBill Taylor 		    i += PCI_MSIX_VECTOR_SIZE) {
47979e39c5baSBill Taylor 			for (j = 0; j < PCI_MSIX_VECTOR_SIZE; j += 4) {
47989e39c5baSBill Taylor 				char *addr = state->hs_msix_tbl_addr + i + j;
47999e39c5baSBill Taylor 				ddi_put32(msix_tblhdl,
48009e39c5baSBill Taylor 				    (uint32_t *)(uintptr_t)addr, 0x0);
48019e39c5baSBill Taylor 			}
48029e39c5baSBill Taylor 		}
48039e39c5baSBill Taylor 
48049e39c5baSBill Taylor 		/* Disable MSI-X interrupts */
48059e39c5baSBill Taylor 		msix_ctrl &= ~PCI_MSIX_ENABLE_BIT;
4806*0b63ccafSToomas Soome 		PCI_CAP_PUT16(pci_cfg_hdl, 0, caps_ctrl, PCI_MSIX_CTRL,
48079e39c5baSBill Taylor 		    msix_ctrl);
48089e39c5baSBill Taylor 
48099e39c5baSBill Taylor 	} else {
48109e39c5baSBill Taylor 		uint16_t cmdreg = pci_config_get16(pci_cfg_hdl, PCI_CONF_COMM);
48119e39c5baSBill Taylor 		ASSERT(state->hs_intr_types_avail & DDI_INTR_TYPE_FIXED);
48129e39c5baSBill Taylor 
48139e39c5baSBill Taylor 		/* Disable the legacy interrupts */
48149e39c5baSBill Taylor 		cmdreg |= PCI_COMM_INTX_DISABLE;
48159e39c5baSBill Taylor 		pci_config_put16(pci_cfg_hdl, PCI_CONF_COMM, cmdreg);
48169e39c5baSBill Taylor 	}
48179e39c5baSBill Taylor 
48189e39c5baSBill Taylor 	return (DDI_SUCCESS);
48199e39c5baSBill Taylor }
48209e39c5baSBill Taylor 
48219e39c5baSBill Taylor /* Hermon quiesce(9F) entry */
48229e39c5baSBill Taylor static int
hermon_quiesce(dev_info_t * dip)48239e39c5baSBill Taylor hermon_quiesce(dev_info_t *dip)
48249e39c5baSBill Taylor {
48259e39c5baSBill Taylor 	hermon_state_t *state = ddi_get_soft_state(hermon_statep,
48269e39c5baSBill Taylor 	    DEVI(dip)->devi_instance);
48279e39c5baSBill Taylor 	ddi_acc_handle_t pcihdl = hermon_get_pcihdl(state);
48289e39c5baSBill Taylor 	ddi_acc_handle_t cmdhdl = hermon_get_cmdhdl(state);
48299e39c5baSBill Taylor 	ddi_acc_handle_t msix_tbl_hdl = hermon_get_msix_tblhdl(state);
48309e39c5baSBill Taylor 	ddi_acc_handle_t msix_pba_hdl = hermon_get_msix_pbahdl(state);
48319e39c5baSBill Taylor 	uint32_t sem, reset_delay = state->hs_cfg_profile->cp_sw_reset_delay;
48329e39c5baSBill Taylor 	uint64_t data64;
48339e39c5baSBill Taylor 	uint32_t data32;
48349e39c5baSBill Taylor 	int status, i, j, loopcnt;
48359e39c5baSBill Taylor 	uint_t offset;
48369e39c5baSBill Taylor 
48379e39c5baSBill Taylor 	ASSERT(state != NULL);
48389e39c5baSBill Taylor 
48399e39c5baSBill Taylor 	/* start fastreboot */
48409e39c5baSBill Taylor 	state->hs_quiescing = B_TRUE;
48419e39c5baSBill Taylor 
4842332f545bSEiji Ota 	/* If it's in maintenance mode, do nothing but return with SUCCESS */
4843332f545bSEiji Ota 	if (!HERMON_IS_OPERATIONAL(state->hs_operational_mode)) {
4844332f545bSEiji Ota 		return (DDI_SUCCESS);
4845332f545bSEiji Ota 	}
4846332f545bSEiji Ota 
48479e39c5baSBill Taylor 	/* suppress Hermon FM ereports */
48489e39c5baSBill Taylor 	if (hermon_get_state(state) & HCA_EREPORT_FM) {
48499e39c5baSBill Taylor 		hermon_clr_state_nolock(state, HCA_EREPORT_FM);
48509e39c5baSBill Taylor 	}
48519e39c5baSBill Taylor 
48529e39c5baSBill Taylor 	/* Shutdown HCA ports */
48539e39c5baSBill Taylor 	if (hermon_hca_ports_shutdown(state,
48549e39c5baSBill Taylor 	    state->hs_cfg_profile->cp_num_ports) != HERMON_CMD_SUCCESS) {
48559e39c5baSBill Taylor 		state->hs_quiescing = B_FALSE;
48569e39c5baSBill Taylor 		return (DDI_FAILURE);
48579e39c5baSBill Taylor 	}
48589e39c5baSBill Taylor 
48599e39c5baSBill Taylor 	/* Close HCA */
48609e39c5baSBill Taylor 	if (hermon_close_hca_cmd_post(state, HERMON_CMD_NOSLEEP_SPIN) !=
48619e39c5baSBill Taylor 	    HERMON_CMD_SUCCESS) {
48629e39c5baSBill Taylor 		state->hs_quiescing = B_FALSE;
48639e39c5baSBill Taylor 		return (DDI_FAILURE);
48649e39c5baSBill Taylor 	}
48659e39c5baSBill Taylor 
48669e39c5baSBill Taylor 	/* Disable interrupts */
48679e39c5baSBill Taylor 	if (hermon_intr_disable(state) != DDI_SUCCESS) {
48689e39c5baSBill Taylor 		state->hs_quiescing = B_FALSE;
48699e39c5baSBill Taylor 		return (DDI_FAILURE);
48709e39c5baSBill Taylor 	}
48719e39c5baSBill Taylor 
48729e39c5baSBill Taylor 	/*
48739e39c5baSBill Taylor 	 * Query the PCI capabilities of the HCA device, but don't process
48749e39c5baSBill Taylor 	 * the VPD until after reset.
48759e39c5baSBill Taylor 	 */
48769e39c5baSBill Taylor 	if (hermon_pci_capability_list(state, pcihdl) != DDI_SUCCESS) {
48779e39c5baSBill Taylor 		state->hs_quiescing = B_FALSE;
48789e39c5baSBill Taylor 		return (DDI_FAILURE);
48799e39c5baSBill Taylor 	}
48809e39c5baSBill Taylor 
48819e39c5baSBill Taylor 	/*
48829e39c5baSBill Taylor 	 * Read all PCI config info (reg0...reg63).  Note: According to the
48839e39c5baSBill Taylor 	 * Hermon software reset application note, we should not read or
48849e39c5baSBill Taylor 	 * restore the values in reg22 and reg23.
48859e39c5baSBill Taylor 	 * NOTE:  For Hermon (and Arbel too) it says to restore the command
48869e39c5baSBill Taylor 	 * register LAST, and technically, you need to restore the
48879e39c5baSBill Taylor 	 * PCIE Capability "device control" and "link control" (word-sized,
48889e39c5baSBill Taylor 	 * at offsets 0x08 and 0x10 from the capbility ID respectively).
48899e39c5baSBill Taylor 	 * We hold off restoring the command register - offset 0x4 - till last
48909e39c5baSBill Taylor 	 */
48919e39c5baSBill Taylor 
48929e39c5baSBill Taylor 	/* 1st, wait for the semaphore assure accessibility - per PRM */
48939e39c5baSBill Taylor 	status = -1;
48949e39c5baSBill Taylor 	for (i = 0; i < NANOSEC/MICROSEC /* 1sec timeout */; i++) {
48959e39c5baSBill Taylor 		sem = ddi_get32(cmdhdl, state->hs_cmd_regs.sw_semaphore);
48969e39c5baSBill Taylor 		if (sem == 0) {
48979e39c5baSBill Taylor 			status = 0;
48989e39c5baSBill Taylor 			break;
48999e39c5baSBill Taylor 		}
49009e39c5baSBill Taylor 		drv_usecwait(1);
49019e39c5baSBill Taylor 	}
49029e39c5baSBill Taylor 
49039e39c5baSBill Taylor 	/* Check if timeout happens */
49049e39c5baSBill Taylor 	if (status == -1) {
49059e39c5baSBill Taylor 		state->hs_quiescing = B_FALSE;
49069e39c5baSBill Taylor 		return (DDI_FAILURE);
49079e39c5baSBill Taylor 	}
49089e39c5baSBill Taylor 
49099e39c5baSBill Taylor 	/* MSI-X interrupts are used, save the MSI-X table */
49109e39c5baSBill Taylor 	if (msix_tbl_hdl && msix_pba_hdl) {
49119e39c5baSBill Taylor 		/* save MSI-X table */
49129e39c5baSBill Taylor 		for (i = 0; i < get_msix_tbl_size(state->hs_dip);
49139e39c5baSBill Taylor 		    i += PCI_MSIX_VECTOR_SIZE) {
49149e39c5baSBill Taylor 			for (j = 0; j < PCI_MSIX_VECTOR_SIZE; j += 4) {
49159e39c5baSBill Taylor 				char *addr = state->hs_msix_tbl_addr + i + j;
49169e39c5baSBill Taylor 				data32 = ddi_get32(msix_tbl_hdl,
49179e39c5baSBill Taylor 				    (uint32_t *)(uintptr_t)addr);
49189e39c5baSBill Taylor 				*(uint32_t *)(uintptr_t)(state->
49199e39c5baSBill Taylor 				    hs_msix_tbl_entries + i + j) = data32;
49209e39c5baSBill Taylor 			}
49219e39c5baSBill Taylor 		}
49229e39c5baSBill Taylor 		/* save MSI-X PBA */
49239e39c5baSBill Taylor 		for (i = 0; i < get_msix_pba_size(state->hs_dip); i += 8) {
49249e39c5baSBill Taylor 			char *addr = state->hs_msix_pba_addr + i;
49259e39c5baSBill Taylor 			data64 = ddi_get64(msix_pba_hdl,
49269e39c5baSBill Taylor 			    (uint64_t *)(uintptr_t)addr);
49279e39c5baSBill Taylor 			*(uint64_t *)(uintptr_t)(state->
49289e39c5baSBill Taylor 			    hs_msix_pba_entries + i) = data64;
49299e39c5baSBill Taylor 		}
49309e39c5baSBill Taylor 	}
49319e39c5baSBill Taylor 
49329e39c5baSBill Taylor 	/* save PCI config space */
49339e39c5baSBill Taylor 	for (i = 0; i < HERMON_SW_RESET_NUMREGS; i++) {
49349e39c5baSBill Taylor 		if ((i != HERMON_SW_RESET_REG22_RSVD) &&
49359e39c5baSBill Taylor 		    (i != HERMON_SW_RESET_REG23_RSVD)) {
49369e39c5baSBill Taylor 			state->hs_cfg_data[i]  =
49379e39c5baSBill Taylor 			    pci_config_get32(pcihdl, i << 2);
49389e39c5baSBill Taylor 		}
49399e39c5baSBill Taylor 	}
49409e39c5baSBill Taylor 
49419e39c5baSBill Taylor 	/* SW-reset HCA */
49429e39c5baSBill Taylor 	ddi_put32(cmdhdl, state->hs_cmd_regs.sw_reset, HERMON_SW_RESET_START);
49439e39c5baSBill Taylor 
49449e39c5baSBill Taylor 	/*
49459e39c5baSBill Taylor 	 * This delay is required so as not to cause a panic here. If the
49469e39c5baSBill Taylor 	 * device is accessed too soon after reset it will not respond to
49479e39c5baSBill Taylor 	 * config cycles, causing a Master Abort and panic.
49489e39c5baSBill Taylor 	 */
49499e39c5baSBill Taylor 	drv_usecwait(reset_delay);
49509e39c5baSBill Taylor 
49519e39c5baSBill Taylor 	/* Poll waiting for the device to finish resetting */
49529e39c5baSBill Taylor 	loopcnt = 100;	/* 100 times @ 100 usec - total delay 10 msec */
49539e39c5baSBill Taylor 	while ((pci_config_get32(pcihdl, 0) & 0x0000FFFF) != PCI_VENID_MLX) {
49549e39c5baSBill Taylor 		drv_usecwait(HERMON_SW_RESET_POLL_DELAY);
49559e39c5baSBill Taylor 		if (--loopcnt == 0)
49569e39c5baSBill Taylor 			break;	/* just in case, break and go on */
49579e39c5baSBill Taylor 	}
49589e39c5baSBill Taylor 	if (loopcnt == 0) {
49599e39c5baSBill Taylor 		state->hs_quiescing = B_FALSE;
49609e39c5baSBill Taylor 		return (DDI_FAILURE);
49619e39c5baSBill Taylor 	}
49629e39c5baSBill Taylor 
49639e39c5baSBill Taylor 	/* Restore the config info */
49649e39c5baSBill Taylor 	for (i = 0; i < HERMON_SW_RESET_NUMREGS; i++) {
49659e39c5baSBill Taylor 		if (i == 1) continue;	/* skip the status/ctrl reg */
49669e39c5baSBill Taylor 		if ((i != HERMON_SW_RESET_REG22_RSVD) &&
49679e39c5baSBill Taylor 		    (i != HERMON_SW_RESET_REG23_RSVD)) {
49689e39c5baSBill Taylor 			pci_config_put32(pcihdl, i << 2, state->hs_cfg_data[i]);
49699e39c5baSBill Taylor 		}
49709e39c5baSBill Taylor 	}
49719e39c5baSBill Taylor 
49729e39c5baSBill Taylor 	/* If MSI-X interrupts are used, restore the MSI-X table */
49739e39c5baSBill Taylor 	if (msix_tbl_hdl && msix_pba_hdl) {
49749e39c5baSBill Taylor 		/* restore MSI-X PBA */
49759e39c5baSBill Taylor 		for (i = 0; i < get_msix_pba_size(state->hs_dip); i += 8) {
49769e39c5baSBill Taylor 			char *addr = state->hs_msix_pba_addr + i;
49779e39c5baSBill Taylor 			data64 = *(uint64_t *)(uintptr_t)
49789e39c5baSBill Taylor 			    (state->hs_msix_pba_entries + i);
49799e39c5baSBill Taylor 			ddi_put64(msix_pba_hdl,
49809e39c5baSBill Taylor 			    (uint64_t *)(uintptr_t)addr, data64);
49819e39c5baSBill Taylor 		}
49829e39c5baSBill Taylor 		/* restore MSI-X table */
49839e39c5baSBill Taylor 		for (i = 0; i < get_msix_tbl_size(state->hs_dip);
49849e39c5baSBill Taylor 		    i += PCI_MSIX_VECTOR_SIZE) {
49859e39c5baSBill Taylor 			for (j = 0; j < PCI_MSIX_VECTOR_SIZE; j += 4) {
49869e39c5baSBill Taylor 				char *addr = state->hs_msix_tbl_addr + i + j;
49879e39c5baSBill Taylor 				data32 = *(uint32_t *)(uintptr_t)
49889e39c5baSBill Taylor 				    (state->hs_msix_tbl_entries + i + j);
49899e39c5baSBill Taylor 				ddi_put32(msix_tbl_hdl,
49909e39c5baSBill Taylor 				    (uint32_t *)(uintptr_t)addr, data32);
49919e39c5baSBill Taylor 			}
49929e39c5baSBill Taylor 		}
49939e39c5baSBill Taylor 	}
49949e39c5baSBill Taylor 
49959e39c5baSBill Taylor 	/*
49969e39c5baSBill Taylor 	 * PCI Express Capability - we saved during capability list, and
49979e39c5baSBill Taylor 	 * we'll restore them here.
49989e39c5baSBill Taylor 	 */
49999e39c5baSBill Taylor 	offset = state->hs_pci_cap_offset;
50009e39c5baSBill Taylor 	data32 = state->hs_pci_cap_devctl;
50019e39c5baSBill Taylor 	pci_config_put32(pcihdl, offset + HERMON_PCI_CAP_DEV_OFFS, data32);
50029e39c5baSBill Taylor 	data32 = state->hs_pci_cap_lnkctl;
50039e39c5baSBill Taylor 	pci_config_put32(pcihdl, offset + HERMON_PCI_CAP_LNK_OFFS, data32);
50049e39c5baSBill Taylor 
50059e39c5baSBill Taylor 	/* restore the command register */
50069e39c5baSBill Taylor 	pci_config_put32(pcihdl, 0x04, (state->hs_cfg_data[1] | 0x0006));
50079e39c5baSBill Taylor 
50089e39c5baSBill Taylor 	return (DDI_SUCCESS);
50099e39c5baSBill Taylor }
5010