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 **)®s_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 *)®s_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 *)®s_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