19517SBill.Taylor@Sun.COM /*
29517SBill.Taylor@Sun.COM * CDDL HEADER START
39517SBill.Taylor@Sun.COM *
49517SBill.Taylor@Sun.COM * The contents of this file are subject to the terms of the
59517SBill.Taylor@Sun.COM * Common Development and Distribution License (the "License").
69517SBill.Taylor@Sun.COM * You may not use this file except in compliance with the License.
79517SBill.Taylor@Sun.COM *
89517SBill.Taylor@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99517SBill.Taylor@Sun.COM * or http://www.opensolaris.org/os/licensing.
109517SBill.Taylor@Sun.COM * See the License for the specific language governing permissions
119517SBill.Taylor@Sun.COM * and limitations under the License.
129517SBill.Taylor@Sun.COM *
139517SBill.Taylor@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
149517SBill.Taylor@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159517SBill.Taylor@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
169517SBill.Taylor@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
179517SBill.Taylor@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
189517SBill.Taylor@Sun.COM *
199517SBill.Taylor@Sun.COM * CDDL HEADER END
209517SBill.Taylor@Sun.COM */
219517SBill.Taylor@Sun.COM
229517SBill.Taylor@Sun.COM /*
23*12965SWilliam.Taylor@Oracle.COM * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
249517SBill.Taylor@Sun.COM */
259517SBill.Taylor@Sun.COM
269517SBill.Taylor@Sun.COM /*
279517SBill.Taylor@Sun.COM * hermon_fm.c
289517SBill.Taylor@Sun.COM * Hermon (InfiniBand) HCA Driver Fault Management Routines
299517SBill.Taylor@Sun.COM *
309517SBill.Taylor@Sun.COM * [Hermon FM Implementation]
319517SBill.Taylor@Sun.COM *
329517SBill.Taylor@Sun.COM * Hermon FM recovers the system from a HW error situation and/or isolates a
339517SBill.Taylor@Sun.COM * HW error by calling the FMA acc handle check functions. (calling
349517SBill.Taylor@Sun.COM * ddi_fm_acc_err_get()) If a HW error is detected when either
359517SBill.Taylor@Sun.COM * ddi_fm_acc_err_get() is called, to determine whether or not the error is
369517SBill.Taylor@Sun.COM * transient, the I/O operation causing the error will retry up to three times.
379517SBill.Taylor@Sun.COM *
389517SBill.Taylor@Sun.COM * (Basic HW error recovery)
399517SBill.Taylor@Sun.COM *
409517SBill.Taylor@Sun.COM * |
419517SBill.Taylor@Sun.COM * .---->*
429517SBill.Taylor@Sun.COM * | |
439517SBill.Taylor@Sun.COM * | issue an I/O request via PIO
449517SBill.Taylor@Sun.COM * | |
459517SBill.Taylor@Sun.COM * | |
469517SBill.Taylor@Sun.COM * | check acc handle
479517SBill.Taylor@Sun.COM * | |
489517SBill.Taylor@Sun.COM * | |
499517SBill.Taylor@Sun.COM * `--< a HW error detected && retry count < 3 >
509517SBill.Taylor@Sun.COM * |
519517SBill.Taylor@Sun.COM * v
529517SBill.Taylor@Sun.COM *
539517SBill.Taylor@Sun.COM * When a HW error is detected, to provide the error information for users to
549517SBill.Taylor@Sun.COM * isolate the faulted HW, Hermon FM issues Solaris FMA ereports as follows.
559517SBill.Taylor@Sun.COM *
569517SBill.Taylor@Sun.COM * * PIO transient error
579517SBill.Taylor@Sun.COM * invalid_state => unaffected
589517SBill.Taylor@Sun.COM *
599517SBill.Taylor@Sun.COM * * PIO persistent error
609517SBill.Taylor@Sun.COM * invalid_state => lost
619517SBill.Taylor@Sun.COM *
629517SBill.Taylor@Sun.COM * * PIO fatal error
639517SBill.Taylor@Sun.COM * invalid_state => lost => panic
649517SBill.Taylor@Sun.COM *
659517SBill.Taylor@Sun.COM * * Hermon HCA firmware error
669517SBill.Taylor@Sun.COM * invalid_state => degraded
679517SBill.Taylor@Sun.COM *
689517SBill.Taylor@Sun.COM * * Other Hermon HCA specific errors
699517SBill.Taylor@Sun.COM * uncorrect => unaffected
709517SBill.Taylor@Sun.COM * or
719517SBill.Taylor@Sun.COM * correct => unaffected
729517SBill.Taylor@Sun.COM *
739517SBill.Taylor@Sun.COM * (Restrictions)
749517SBill.Taylor@Sun.COM *
759517SBill.Taylor@Sun.COM * The current implementation has the following restrictions.
769517SBill.Taylor@Sun.COM * * No runtime check/protection
779517SBill.Taylor@Sun.COM * * No detach time check/protection
789517SBill.Taylor@Sun.COM * * No DMA check/protection
799517SBill.Taylor@Sun.COM *
809517SBill.Taylor@Sun.COM * See the Hermon FMA portfolio in detail.
819517SBill.Taylor@Sun.COM */
829517SBill.Taylor@Sun.COM
839517SBill.Taylor@Sun.COM #include <sys/types.h>
849517SBill.Taylor@Sun.COM #include <sys/conf.h>
859517SBill.Taylor@Sun.COM #include <sys/ddi.h>
869517SBill.Taylor@Sun.COM #include <sys/sunddi.h>
879517SBill.Taylor@Sun.COM #include <sys/sysmacros.h>
889517SBill.Taylor@Sun.COM #include <sys/list.h>
899517SBill.Taylor@Sun.COM #include <sys/modhash.h>
909517SBill.Taylor@Sun.COM
919517SBill.Taylor@Sun.COM #include <sys/ib/adapters/hermon/hermon.h>
929517SBill.Taylor@Sun.COM
939517SBill.Taylor@Sun.COM /*
949517SBill.Taylor@Sun.COM * Hermon driver has to disable its FM functionality
959517SBill.Taylor@Sun.COM * if this "fm_capable" variable is defined or has a value
969517SBill.Taylor@Sun.COM * in /kernel/drv/hermon.conf.
979517SBill.Taylor@Sun.COM */
989517SBill.Taylor@Sun.COM static char *fm_cap = "fm-capable"; /* FM capability */
999517SBill.Taylor@Sun.COM
1009517SBill.Taylor@Sun.COM static hermon_hca_fm_t hca_fm; /* Hermon HCA FM Structure */
1019517SBill.Taylor@Sun.COM
1029517SBill.Taylor@Sun.COM static void i_hca_fm_ereport(dev_info_t *, int, char *);
1039517SBill.Taylor@Sun.COM static void i_hca_fm_init(struct i_hca_fm *);
1049517SBill.Taylor@Sun.COM static void i_hca_fm_fini(struct i_hca_fm *);
1059517SBill.Taylor@Sun.COM static int i_hca_regs_map_setup(struct i_hca_fm *, dev_info_t *, uint_t,
1069517SBill.Taylor@Sun.COM caddr_t *, offset_t, offset_t, ddi_device_acc_attr_t *, ddi_acc_handle_t *);
1079517SBill.Taylor@Sun.COM static void i_hca_regs_map_free(struct i_hca_fm *, ddi_acc_handle_t *);
1089517SBill.Taylor@Sun.COM static int i_hca_pci_config_setup(struct i_hca_fm *, dev_info_t *,
1099517SBill.Taylor@Sun.COM ddi_acc_handle_t *);
1109517SBill.Taylor@Sun.COM static void i_hca_pci_config_teardown(struct i_hca_fm *, ddi_acc_handle_t *);
1119517SBill.Taylor@Sun.COM static int i_hca_pio_start(dev_info_t *, struct i_hca_acc_handle *,
1129517SBill.Taylor@Sun.COM hermon_test_t *);
1139517SBill.Taylor@Sun.COM static int i_hca_pio_end(dev_info_t *, struct i_hca_acc_handle *, int *,
1149517SBill.Taylor@Sun.COM hermon_test_t *);
1159517SBill.Taylor@Sun.COM static struct i_hca_acc_handle *i_hca_get_acc_handle(struct i_hca_fm *,
1169517SBill.Taylor@Sun.COM ddi_acc_handle_t);
1179517SBill.Taylor@Sun.COM
1189517SBill.Taylor@Sun.COM /* forward declaration for hermon_fm_{init, fini}() */
1199517SBill.Taylor@Sun.COM #ifdef FMA_TEST
1209517SBill.Taylor@Sun.COM static void i_hca_test_init(mod_hash_t **, mod_hash_t **);
1219517SBill.Taylor@Sun.COM static void i_hca_test_fini(mod_hash_t **, mod_hash_t **);
1229517SBill.Taylor@Sun.COM #endif /* FMA_TEST */
1239517SBill.Taylor@Sun.COM
1249517SBill.Taylor@Sun.COM /*
1259517SBill.Taylor@Sun.COM * Hermon FM Functions
1269517SBill.Taylor@Sun.COM *
1279517SBill.Taylor@Sun.COM * These functions are based on the HCA FM common interface
1289517SBill.Taylor@Sun.COM * defined below, but specific to the Hermon HCA FM capabilities.
1299517SBill.Taylor@Sun.COM */
1309517SBill.Taylor@Sun.COM
1319517SBill.Taylor@Sun.COM /*
1329517SBill.Taylor@Sun.COM * void
1339517SBill.Taylor@Sun.COM * hermon_hca_fm_init(hermon_state_t *state, hermon_hca_fm_t *hca)
1349517SBill.Taylor@Sun.COM *
1359517SBill.Taylor@Sun.COM * Overview
1369517SBill.Taylor@Sun.COM * hermon_hca_fm_init() initializes the Hermon FM resources.
1379517SBill.Taylor@Sun.COM *
1389517SBill.Taylor@Sun.COM * Argument
1399517SBill.Taylor@Sun.COM * state: pointer to Hermon state structure
1409517SBill.Taylor@Sun.COM * hca: pointer to Hermon FM structure
1419517SBill.Taylor@Sun.COM *
1429517SBill.Taylor@Sun.COM * Return value
1439517SBill.Taylor@Sun.COM * Nothing
1449517SBill.Taylor@Sun.COM *
1459517SBill.Taylor@Sun.COM * Caller's context
1469517SBill.Taylor@Sun.COM * hermon_hca_fm_init() can be called in user or kernel context only.
1479517SBill.Taylor@Sun.COM */
1489517SBill.Taylor@Sun.COM static void
hermon_hca_fm_init(hermon_state_t * state,hermon_hca_fm_t * hca_fm)1499517SBill.Taylor@Sun.COM hermon_hca_fm_init(hermon_state_t *state, hermon_hca_fm_t *hca_fm)
1509517SBill.Taylor@Sun.COM {
1519517SBill.Taylor@Sun.COM state->hs_fm_hca_fm = hca_fm;
1529517SBill.Taylor@Sun.COM i_hca_fm_init((struct i_hca_fm *)hca_fm);
1539517SBill.Taylor@Sun.COM }
1549517SBill.Taylor@Sun.COM
1559517SBill.Taylor@Sun.COM
1569517SBill.Taylor@Sun.COM /*
1579517SBill.Taylor@Sun.COM * void
1589517SBill.Taylor@Sun.COM * hermon_hca_fm_fini(hermon_state_t *state)
1599517SBill.Taylor@Sun.COM *
1609517SBill.Taylor@Sun.COM * Overview
1619517SBill.Taylor@Sun.COM * hermon_hca_fm_fini() releases the Hermon FM resources.
1629517SBill.Taylor@Sun.COM *
1639517SBill.Taylor@Sun.COM * Argument
1649517SBill.Taylor@Sun.COM * state: pointer to Hermon state structure
1659517SBill.Taylor@Sun.COM *
1669517SBill.Taylor@Sun.COM * Return value
1679517SBill.Taylor@Sun.COM * Nothing
1689517SBill.Taylor@Sun.COM *
1699517SBill.Taylor@Sun.COM * Caller's context
1709517SBill.Taylor@Sun.COM * hermon_hca_fm_fini() can be called in user or kernel context only.
1719517SBill.Taylor@Sun.COM */
1729517SBill.Taylor@Sun.COM static void
hermon_hca_fm_fini(hermon_state_t * state)1739517SBill.Taylor@Sun.COM hermon_hca_fm_fini(hermon_state_t *state)
1749517SBill.Taylor@Sun.COM {
1759517SBill.Taylor@Sun.COM i_hca_fm_fini((struct i_hca_fm *)state->hs_fm_hca_fm);
1769517SBill.Taylor@Sun.COM state->hs_fm_hca_fm = NULL;
1779517SBill.Taylor@Sun.COM }
1789517SBill.Taylor@Sun.COM
1799517SBill.Taylor@Sun.COM /*
1809517SBill.Taylor@Sun.COM * void
1819517SBill.Taylor@Sun.COM * hermon_clr_state_nolock(hermon_state_t *state, int fm_state)
1829517SBill.Taylor@Sun.COM *
1839517SBill.Taylor@Sun.COM * Overview
1849517SBill.Taylor@Sun.COM * hermon_clr_state() drops the specified state from Hermon FM state
1859517SBill.Taylor@Sun.COM * without the mutex locks.
1869517SBill.Taylor@Sun.COM *
1879517SBill.Taylor@Sun.COM * Argument
1889517SBill.Taylor@Sun.COM * state: pointer to Hermon state structure
1899517SBill.Taylor@Sun.COM * fm_state: Hermon FM state, which is composed of:
1909517SBill.Taylor@Sun.COM * HCA_NO_FM Hermom FM is not supported
1919517SBill.Taylor@Sun.COM * HCA_PIO_FM PIO is fma-protected
1929517SBill.Taylor@Sun.COM * HCA_DMA_FM DMA is fma-protected
1939517SBill.Taylor@Sun.COM * HCA_EREPORT_FM FMA ereport is available
1949517SBill.Taylor@Sun.COM * HCA_ERRCB_FM FMA error callback is supported
1959517SBill.Taylor@Sun.COM * HCA_ATTCH_FM HCA FM attach mode
1969517SBill.Taylor@Sun.COM * HCA_RUNTM_FM HCA FM runtime mode
1979517SBill.Taylor@Sun.COM *
1989517SBill.Taylor@Sun.COM * Return value
1999517SBill.Taylor@Sun.COM * Nothing
2009517SBill.Taylor@Sun.COM *
2019517SBill.Taylor@Sun.COM * Caller's context
2029517SBill.Taylor@Sun.COM * hermon_clr_state() can be called in user, kernel, interrupt context
2039517SBill.Taylor@Sun.COM * or high interrupt context.
2049517SBill.Taylor@Sun.COM */
2059517SBill.Taylor@Sun.COM void
hermon_clr_state_nolock(hermon_state_t * state,int fm_state)2069517SBill.Taylor@Sun.COM hermon_clr_state_nolock(hermon_state_t *state, int fm_state)
2079517SBill.Taylor@Sun.COM {
2089517SBill.Taylor@Sun.COM extern void membar_sync(void);
2099517SBill.Taylor@Sun.COM
2109517SBill.Taylor@Sun.COM state->hs_fm_state &= ~fm_state;
2119517SBill.Taylor@Sun.COM membar_sync();
2129517SBill.Taylor@Sun.COM }
2139517SBill.Taylor@Sun.COM
2149517SBill.Taylor@Sun.COM
2159517SBill.Taylor@Sun.COM /*
2169517SBill.Taylor@Sun.COM * void
2179517SBill.Taylor@Sun.COM * hermon_clr_state(hermon_state_t *state, int fm_state)
2189517SBill.Taylor@Sun.COM *
2199517SBill.Taylor@Sun.COM * Overview
2209517SBill.Taylor@Sun.COM * hermon_clr_state() drops the specified state from Hermon FM state.
2219517SBill.Taylor@Sun.COM *
2229517SBill.Taylor@Sun.COM * Argument
2239517SBill.Taylor@Sun.COM * state: pointer to Hermon state structure
2249517SBill.Taylor@Sun.COM * fm_state: Hermon FM state, which is composed of:
2259517SBill.Taylor@Sun.COM * HCA_NO_FM Hermom FM is not supported
2269517SBill.Taylor@Sun.COM * HCA_PIO_FM PIO is fma-protected
2279517SBill.Taylor@Sun.COM * HCA_DMA_FM DMA is fma-protected
2289517SBill.Taylor@Sun.COM * HCA_EREPORT_FM FMA ereport is available
2299517SBill.Taylor@Sun.COM * HCA_ERRCB_FM FMA error callback is supported
2309517SBill.Taylor@Sun.COM * HCA_ATTCH_FM HCA FM attach mode
2319517SBill.Taylor@Sun.COM * HCA_RUNTM_FM HCA FM runtime mode
2329517SBill.Taylor@Sun.COM *
2339517SBill.Taylor@Sun.COM * Return value
2349517SBill.Taylor@Sun.COM * Nothing
2359517SBill.Taylor@Sun.COM *
2369517SBill.Taylor@Sun.COM * Caller's context
2379517SBill.Taylor@Sun.COM * hermon_clr_state() can be called in user, kernel or interrupt context.
2389517SBill.Taylor@Sun.COM */
2399517SBill.Taylor@Sun.COM static void
hermon_clr_state(hermon_state_t * state,int fm_state)2409517SBill.Taylor@Sun.COM hermon_clr_state(hermon_state_t *state, int fm_state)
2419517SBill.Taylor@Sun.COM {
2429517SBill.Taylor@Sun.COM ASSERT(fm_state != HCA_NO_FM);
2439517SBill.Taylor@Sun.COM
2449517SBill.Taylor@Sun.COM mutex_enter(&state->hs_fm_lock);
2459517SBill.Taylor@Sun.COM hermon_clr_state_nolock(state, fm_state);
2469517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fm_lock);
2479517SBill.Taylor@Sun.COM }
2489517SBill.Taylor@Sun.COM
2499517SBill.Taylor@Sun.COM
2509517SBill.Taylor@Sun.COM /*
2519517SBill.Taylor@Sun.COM * void
2529517SBill.Taylor@Sun.COM * hermon_set_state(hermon_state_t *state, int fm_state)
2539517SBill.Taylor@Sun.COM *
2549517SBill.Taylor@Sun.COM * Overview
2559517SBill.Taylor@Sun.COM * hermon_set_state() sets Hermon FM state.
2569517SBill.Taylor@Sun.COM *
2579517SBill.Taylor@Sun.COM * Argument
2589517SBill.Taylor@Sun.COM * state: pointer to Hermon state structure
2599517SBill.Taylor@Sun.COM * fm_state: Hermon FM state, which is composed of:
2609517SBill.Taylor@Sun.COM * HCA_NO_FM Hermom FM is not supported
2619517SBill.Taylor@Sun.COM * HCA_PIO_FM PIO is fma-protected
2629517SBill.Taylor@Sun.COM * HCA_DMA_FM DMA is fma-protected
2639517SBill.Taylor@Sun.COM * HCA_EREPORT_FM FMA ereport is available
2649517SBill.Taylor@Sun.COM * HCA_ERRCB_FM FMA error callback is supported
2659517SBill.Taylor@Sun.COM * HCA_ATTCH_FM HCA FM attach mode
2669517SBill.Taylor@Sun.COM * HCA_RUNTM_FM HCA FM runtime mode
2679517SBill.Taylor@Sun.COM *
2689517SBill.Taylor@Sun.COM * Return value
2699517SBill.Taylor@Sun.COM * Nothing
2709517SBill.Taylor@Sun.COM *
2719517SBill.Taylor@Sun.COM * Caller's context
2729517SBill.Taylor@Sun.COM * hermon_set_state() can be called in user, kernel or interrupt context.
2739517SBill.Taylor@Sun.COM */
2749517SBill.Taylor@Sun.COM static void
hermon_set_state(hermon_state_t * state,int fm_state)2759517SBill.Taylor@Sun.COM hermon_set_state(hermon_state_t *state, int fm_state)
2769517SBill.Taylor@Sun.COM {
2779517SBill.Taylor@Sun.COM extern void membar_sync(void);
2789517SBill.Taylor@Sun.COM
2799517SBill.Taylor@Sun.COM mutex_enter(&state->hs_fm_lock);
2809517SBill.Taylor@Sun.COM if (fm_state == HCA_NO_FM) {
2819517SBill.Taylor@Sun.COM state->hs_fm_state = HCA_NO_FM;
2829517SBill.Taylor@Sun.COM } else {
2839517SBill.Taylor@Sun.COM state->hs_fm_state |= fm_state;
2849517SBill.Taylor@Sun.COM }
2859517SBill.Taylor@Sun.COM membar_sync();
2869517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fm_lock);
2879517SBill.Taylor@Sun.COM }
2889517SBill.Taylor@Sun.COM
2899517SBill.Taylor@Sun.COM
2909517SBill.Taylor@Sun.COM /*
2919517SBill.Taylor@Sun.COM * int
2929517SBill.Taylor@Sun.COM * hermon_get_state(hermon_state_t *state)
2939517SBill.Taylor@Sun.COM *
2949517SBill.Taylor@Sun.COM * Overview
2959517SBill.Taylor@Sun.COM * hermon_get_state() returns the current Hermon FM state.
2969517SBill.Taylor@Sun.COM *
2979517SBill.Taylor@Sun.COM * Argument
2989517SBill.Taylor@Sun.COM * state: pointer to Hermon state structure
2999517SBill.Taylor@Sun.COM *
3009517SBill.Taylor@Sun.COM * Return value
3019517SBill.Taylor@Sun.COM * fm_state: Hermon FM state, which is composed of:
3029517SBill.Taylor@Sun.COM * HCA_NO_FM Hermom FM is not supported
3039517SBill.Taylor@Sun.COM * HCA_PIO_FM PIO is fma-protected
3049517SBill.Taylor@Sun.COM * HCA_DMA_FM DMA is fma-protected
3059517SBill.Taylor@Sun.COM * HCA_EREPORT_FM FMA ereport is available
3069517SBill.Taylor@Sun.COM * HCA_ERRCB_FM FMA error callback is supported
3079517SBill.Taylor@Sun.COM * HCA_ATTCH_FM HCA FM attach mode
3089517SBill.Taylor@Sun.COM * HCA_RUNTM_FM HCA FM runtime mode
3099517SBill.Taylor@Sun.COM *
3109517SBill.Taylor@Sun.COM * Caller's context
3119517SBill.Taylor@Sun.COM * hermon_get_state() can be called in user, kernel or interrupt context.
3129517SBill.Taylor@Sun.COM */
3139517SBill.Taylor@Sun.COM int
hermon_get_state(hermon_state_t * state)3149517SBill.Taylor@Sun.COM hermon_get_state(hermon_state_t *state)
3159517SBill.Taylor@Sun.COM {
3169517SBill.Taylor@Sun.COM return (state->hs_fm_state);
3179517SBill.Taylor@Sun.COM }
3189517SBill.Taylor@Sun.COM
3199517SBill.Taylor@Sun.COM
3209517SBill.Taylor@Sun.COM /*
3219517SBill.Taylor@Sun.COM * void
3229517SBill.Taylor@Sun.COM * hermon_fm_init(hermon_state_t *state)
3239517SBill.Taylor@Sun.COM *
3249517SBill.Taylor@Sun.COM * Overview
3259517SBill.Taylor@Sun.COM * hermon_fm_init() is a Hermon FM initialization function which registers
3269517SBill.Taylor@Sun.COM * some FMA functions such as the ereport and the acc check capabilities
3279517SBill.Taylor@Sun.COM * for Hermon. If the "fm_disable" property in /kernel/drv/hermon.conf is
3289517SBill.Taylor@Sun.COM * defined (and/or its value is set), then the Hermon FM capabilities will
3299517SBill.Taylor@Sun.COM * drop, and only the default capabilities (the ereport and error callback
3309517SBill.Taylor@Sun.COM * capabilities) are available (and the action against HW errors is
3319517SBill.Taylor@Sun.COM * issuing an ereport then panicking the system).
3329517SBill.Taylor@Sun.COM *
3339517SBill.Taylor@Sun.COM * Argument
3349517SBill.Taylor@Sun.COM * state: pointer to Hermon state structure
3359517SBill.Taylor@Sun.COM *
3369517SBill.Taylor@Sun.COM * Return value
3379517SBill.Taylor@Sun.COM * Nothing
3389517SBill.Taylor@Sun.COM *
3399517SBill.Taylor@Sun.COM * Caller's context
3409517SBill.Taylor@Sun.COM * hermon_fm_init() can be called in user or kernel context only.
3419517SBill.Taylor@Sun.COM */
3429517SBill.Taylor@Sun.COM void
hermon_fm_init(hermon_state_t * state)3439517SBill.Taylor@Sun.COM hermon_fm_init(hermon_state_t *state)
3449517SBill.Taylor@Sun.COM {
3459517SBill.Taylor@Sun.COM ddi_iblock_cookie_t iblk;
3469517SBill.Taylor@Sun.COM
3479517SBill.Taylor@Sun.COM /*
3489517SBill.Taylor@Sun.COM * Check the "fm_disable" property. If it's defined,
3499517SBill.Taylor@Sun.COM * use the Solaris FMA default action for Hermon.
3509517SBill.Taylor@Sun.COM */
3519517SBill.Taylor@Sun.COM if (ddi_getprop(DDI_DEV_T_NONE, state->hs_dip, DDI_PROP_DONTPASS,
3529517SBill.Taylor@Sun.COM "fm_disable", 0) != 0) {
3539517SBill.Taylor@Sun.COM state->hs_fm_disable = 1;
3549517SBill.Taylor@Sun.COM }
3559517SBill.Taylor@Sun.COM
3569517SBill.Taylor@Sun.COM /* If hs_fm_diable is set, then skip the rest */
3579517SBill.Taylor@Sun.COM if (state->hs_fm_disable) {
3589517SBill.Taylor@Sun.COM hermon_set_state(state, HCA_NO_FM);
3599517SBill.Taylor@Sun.COM return;
3609517SBill.Taylor@Sun.COM }
3619517SBill.Taylor@Sun.COM
3629517SBill.Taylor@Sun.COM /* Set the Hermon FM attach mode */
3639517SBill.Taylor@Sun.COM hermon_set_state(state, HCA_ATTCH_FM);
3649517SBill.Taylor@Sun.COM
3659517SBill.Taylor@Sun.COM /* Initialize the Solaris FMA capabilities for the Hermon FM support */
3669517SBill.Taylor@Sun.COM state->hs_fm_capabilities = ddi_prop_get_int(DDI_DEV_T_ANY,
3679517SBill.Taylor@Sun.COM state->hs_dip, DDI_PROP_DONTPASS, fm_cap,
3689517SBill.Taylor@Sun.COM DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE);
3699517SBill.Taylor@Sun.COM
3709517SBill.Taylor@Sun.COM /*
3719517SBill.Taylor@Sun.COM * The Hermon FM uses the ereport and acc check capabilites only,
3729517SBill.Taylor@Sun.COM * but both of them should be available. If either is not, turn
3739517SBill.Taylor@Sun.COM * hs_fm_disable on and behave in the same way as the "fm_diable"
3749517SBill.Taylor@Sun.COM * property is set.
3759517SBill.Taylor@Sun.COM */
3769517SBill.Taylor@Sun.COM if (state->hs_fm_capabilities !=
3779517SBill.Taylor@Sun.COM (DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE)) {
3789517SBill.Taylor@Sun.COM state->hs_fm_disable = 1;
3799517SBill.Taylor@Sun.COM hermon_set_state(state, HCA_NO_FM);
3809517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
3819517SBill.Taylor@Sun.COM "Hermon FM capability fails");
3829517SBill.Taylor@Sun.COM return;
3839517SBill.Taylor@Sun.COM }
3849517SBill.Taylor@Sun.COM
3859517SBill.Taylor@Sun.COM /* Initialize the HCA FM resources */
3869517SBill.Taylor@Sun.COM hermon_hca_fm_init(state, &hca_fm);
3879517SBill.Taylor@Sun.COM
3889517SBill.Taylor@Sun.COM /* Initialize the fm state lock */
3899517SBill.Taylor@Sun.COM mutex_init(&state->hs_fm_lock, NULL, MUTEX_DRIVER, NULL);
3909517SBill.Taylor@Sun.COM
3919517SBill.Taylor@Sun.COM /* Register the capabilities with the IO fault services */
3929517SBill.Taylor@Sun.COM ddi_fm_init(state->hs_dip, &state->hs_fm_capabilities, &iblk);
3939517SBill.Taylor@Sun.COM
3949517SBill.Taylor@Sun.COM /* Set up the pci ereport capabilities if the ereport is capable */
3959517SBill.Taylor@Sun.COM if (DDI_FM_EREPORT_CAP(state->hs_fm_capabilities)) {
3969517SBill.Taylor@Sun.COM pci_ereport_setup(state->hs_dip);
3979517SBill.Taylor@Sun.COM }
3989517SBill.Taylor@Sun.COM
3999517SBill.Taylor@Sun.COM /* Set the Hermon FM state */
4009517SBill.Taylor@Sun.COM hermon_set_state(state, HCA_PIO_FM | HCA_EREPORT_FM);
4019517SBill.Taylor@Sun.COM
4029517SBill.Taylor@Sun.COM #ifdef FMA_TEST
4039517SBill.Taylor@Sun.COM i_hca_test_init(&state->hs_fm_test_hash, &state->hs_fm_id_hash);
4049517SBill.Taylor@Sun.COM #endif /* FMA_TEST */
4059517SBill.Taylor@Sun.COM }
4069517SBill.Taylor@Sun.COM
4079517SBill.Taylor@Sun.COM
4089517SBill.Taylor@Sun.COM /*
4099517SBill.Taylor@Sun.COM * void
4109517SBill.Taylor@Sun.COM * hermon_fm_fini(hermon_state_t *state)
4119517SBill.Taylor@Sun.COM *
4129517SBill.Taylor@Sun.COM * Overview
4139517SBill.Taylor@Sun.COM * hermon_fm_fini() is a Hermon FM finalization function which de-registers
4149517SBill.Taylor@Sun.COM * Solaris FMA functions set to Hermon.
4159517SBill.Taylor@Sun.COM *
4169517SBill.Taylor@Sun.COM * Argument
4179517SBill.Taylor@Sun.COM * state: pointer to Hermon state structure
4189517SBill.Taylor@Sun.COM *
4199517SBill.Taylor@Sun.COM * Return value
4209517SBill.Taylor@Sun.COM * Nothing
4219517SBill.Taylor@Sun.COM *
4229517SBill.Taylor@Sun.COM * Caller's context
4239517SBill.Taylor@Sun.COM * hermon_fm_fini() can be called in user or kernel context only.
4249517SBill.Taylor@Sun.COM */
4259517SBill.Taylor@Sun.COM void
hermon_fm_fini(hermon_state_t * state)4269517SBill.Taylor@Sun.COM hermon_fm_fini(hermon_state_t *state)
4279517SBill.Taylor@Sun.COM {
4289517SBill.Taylor@Sun.COM /*
4299517SBill.Taylor@Sun.COM * If hermon_fm_diable is set or there is no FM service provided,
4309517SBill.Taylor@Sun.COM * then skip the rest.
4319517SBill.Taylor@Sun.COM */
4329517SBill.Taylor@Sun.COM if (state->hs_fm_disable || hermon_get_state(state) == HCA_NO_FM) {
4339517SBill.Taylor@Sun.COM return;
4349517SBill.Taylor@Sun.COM }
4359517SBill.Taylor@Sun.COM
4369517SBill.Taylor@Sun.COM ASSERT(!(hermon_get_state(state) & HCA_ERRCB_FM));
4379517SBill.Taylor@Sun.COM
4389517SBill.Taylor@Sun.COM #ifdef FMA_TEST
4399517SBill.Taylor@Sun.COM i_hca_test_fini(&state->hs_fm_test_hash, &state->hs_fm_id_hash);
4409517SBill.Taylor@Sun.COM #endif /* FMA_TEST */
4419517SBill.Taylor@Sun.COM
4429517SBill.Taylor@Sun.COM /* Set the Hermon FM state to no support */
4439517SBill.Taylor@Sun.COM hermon_set_state(state, HCA_NO_FM);
4449517SBill.Taylor@Sun.COM
4459517SBill.Taylor@Sun.COM /* Release HCA FM resources */
4469517SBill.Taylor@Sun.COM hermon_hca_fm_fini(state);
4479517SBill.Taylor@Sun.COM
4489517SBill.Taylor@Sun.COM /*
4499517SBill.Taylor@Sun.COM * Release any resources allocated by pci_ereport_setup()
4509517SBill.Taylor@Sun.COM */
4519517SBill.Taylor@Sun.COM if (DDI_FM_EREPORT_CAP(state->hs_fm_capabilities)) {
4529517SBill.Taylor@Sun.COM pci_ereport_teardown(state->hs_dip);
4539517SBill.Taylor@Sun.COM }
4549517SBill.Taylor@Sun.COM
4559517SBill.Taylor@Sun.COM /* De-register the Hermon FM from the IO fault services */
4569517SBill.Taylor@Sun.COM ddi_fm_fini(state->hs_dip);
4579517SBill.Taylor@Sun.COM }
4589517SBill.Taylor@Sun.COM
4599517SBill.Taylor@Sun.COM
4609517SBill.Taylor@Sun.COM /*
4619517SBill.Taylor@Sun.COM * int
4629517SBill.Taylor@Sun.COM * hermon_fm_ereport_init(hermon_state_t *state)
4639517SBill.Taylor@Sun.COM *
4649517SBill.Taylor@Sun.COM * Overview
4659517SBill.Taylor@Sun.COM * hermon_fm_ereport_init() changes the Hermon FM state to the ereport
4669517SBill.Taylor@Sun.COM * only mode during the driver attach.
4679517SBill.Taylor@Sun.COM *
4689517SBill.Taylor@Sun.COM * Argument
4699517SBill.Taylor@Sun.COM * state: pointer to Hermon state structure
4709517SBill.Taylor@Sun.COM *
4719517SBill.Taylor@Sun.COM * Return value
4729517SBill.Taylor@Sun.COM * DDI_SUCCESS
4739517SBill.Taylor@Sun.COM * DDI_FAILURE
4749517SBill.Taylor@Sun.COM *
4759517SBill.Taylor@Sun.COM * Caller's context
4769517SBill.Taylor@Sun.COM * hermon_fm_ereport_init() can be called in user or kernel context only.
4779517SBill.Taylor@Sun.COM */
4789517SBill.Taylor@Sun.COM int
hermon_fm_ereport_init(hermon_state_t * state)4799517SBill.Taylor@Sun.COM hermon_fm_ereport_init(hermon_state_t *state)
4809517SBill.Taylor@Sun.COM {
4819517SBill.Taylor@Sun.COM ddi_iblock_cookie_t iblk;
4829517SBill.Taylor@Sun.COM hermon_cfg_profile_t *cfgprof;
4839517SBill.Taylor@Sun.COM hermon_hw_querydevlim_t *devlim;
4849517SBill.Taylor@Sun.COM hermon_rsrc_hw_entry_info_t entry_info;
4859517SBill.Taylor@Sun.COM hermon_rsrc_pool_info_t *rsrc_pool;
4869517SBill.Taylor@Sun.COM uint64_t offset, num, max, num_prealloc;
4879517SBill.Taylor@Sun.COM ddi_device_acc_attr_t dev_attr = {
4889517SBill.Taylor@Sun.COM DDI_DEVICE_ATTR_V0,
4899517SBill.Taylor@Sun.COM DDI_STRUCTURE_LE_ACC,
4909517SBill.Taylor@Sun.COM DDI_STRICTORDER_ACC,
4919517SBill.Taylor@Sun.COM DDI_DEFAULT_ACC
4929517SBill.Taylor@Sun.COM };
4939517SBill.Taylor@Sun.COM char *rsrc_name;
4949517SBill.Taylor@Sun.COM extern void membar_sync(void);
4959517SBill.Taylor@Sun.COM
4969517SBill.Taylor@Sun.COM /* Stop the poll thread while the FM state is being changed */
4979517SBill.Taylor@Sun.COM state->hs_fm_poll_suspend = B_TRUE;
4989517SBill.Taylor@Sun.COM membar_sync();
4999517SBill.Taylor@Sun.COM
5009517SBill.Taylor@Sun.COM /*
5019517SBill.Taylor@Sun.COM * Disable the Hermon interrupt after the interrupt capability flag
5029517SBill.Taylor@Sun.COM * is checked.
5039517SBill.Taylor@Sun.COM */
5049517SBill.Taylor@Sun.COM if (state->hs_intrmsi_cap & DDI_INTR_FLAG_BLOCK) {
5059517SBill.Taylor@Sun.COM if (ddi_intr_block_disable
5069517SBill.Taylor@Sun.COM (&state->hs_intrmsi_hdl[0], 1) != DDI_SUCCESS) {
5079517SBill.Taylor@Sun.COM return (DDI_FAILURE);
5089517SBill.Taylor@Sun.COM }
5099517SBill.Taylor@Sun.COM } else {
5109517SBill.Taylor@Sun.COM if (ddi_intr_disable
5119517SBill.Taylor@Sun.COM (state->hs_intrmsi_hdl[0]) != DDI_SUCCESS) {
5129517SBill.Taylor@Sun.COM return (DDI_FAILURE);
5139517SBill.Taylor@Sun.COM }
5149517SBill.Taylor@Sun.COM }
5159517SBill.Taylor@Sun.COM
5169517SBill.Taylor@Sun.COM /*
5179517SBill.Taylor@Sun.COM * Release any resources allocated by pci_ereport_setup()
5189517SBill.Taylor@Sun.COM */
5199517SBill.Taylor@Sun.COM if (DDI_FM_EREPORT_CAP(state->hs_fm_capabilities)) {
5209517SBill.Taylor@Sun.COM pci_ereport_teardown(state->hs_dip);
5219517SBill.Taylor@Sun.COM }
5229517SBill.Taylor@Sun.COM
5239517SBill.Taylor@Sun.COM /* De-register the Hermon FM from the IO fault services */
5249517SBill.Taylor@Sun.COM ddi_fm_fini(state->hs_dip);
5259517SBill.Taylor@Sun.COM
5269517SBill.Taylor@Sun.COM /* Re-initialize fm ereport with the ereport only */
5279517SBill.Taylor@Sun.COM state->hs_fm_capabilities = ddi_prop_get_int(DDI_DEV_T_ANY,
5289517SBill.Taylor@Sun.COM state->hs_dip, DDI_PROP_DONTPASS, fm_cap,
5299517SBill.Taylor@Sun.COM DDI_FM_EREPORT_CAPABLE);
5309517SBill.Taylor@Sun.COM
5319517SBill.Taylor@Sun.COM /*
5329517SBill.Taylor@Sun.COM * Now that the Hermon FM uses the ereport capability only,
5339517SBill.Taylor@Sun.COM * If it's not set, turn hs_fm_disable on and behave in the
5349517SBill.Taylor@Sun.COM * same way as the "fm_diable" property is set.
5359517SBill.Taylor@Sun.COM */
5369517SBill.Taylor@Sun.COM if (state->hs_fm_capabilities != DDI_FM_EREPORT_CAPABLE) {
5379517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
5389517SBill.Taylor@Sun.COM "Hermon FM ereport fails (ereport mode)");
5399517SBill.Taylor@Sun.COM goto error;
5409517SBill.Taylor@Sun.COM }
5419517SBill.Taylor@Sun.COM
5429517SBill.Taylor@Sun.COM /* Re-register the ereport capability with the IO fault services */
5439517SBill.Taylor@Sun.COM ddi_fm_init(state->hs_dip, &state->hs_fm_capabilities, &iblk);
5449517SBill.Taylor@Sun.COM
5459517SBill.Taylor@Sun.COM /* Initialize the pci ereport capabilities if the ereport is capable */
5469517SBill.Taylor@Sun.COM if (DDI_FM_EREPORT_CAP(state->hs_fm_capabilities)) {
5479517SBill.Taylor@Sun.COM pci_ereport_setup(state->hs_dip);
5489517SBill.Taylor@Sun.COM }
5499517SBill.Taylor@Sun.COM
5509517SBill.Taylor@Sun.COM /* Setup for PCI config read/write of HCA device */
5519517SBill.Taylor@Sun.COM if (pci_config_setup(state->hs_dip, &state->hs_reg_pcihdl) !=
5529517SBill.Taylor@Sun.COM DDI_SUCCESS) {
5539517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
5549517SBill.Taylor@Sun.COM "PCI config mapping fails (ereport mode)");
5559517SBill.Taylor@Sun.COM goto error;
5569517SBill.Taylor@Sun.COM }
5579517SBill.Taylor@Sun.COM
5589517SBill.Taylor@Sun.COM /* Allocate the regular access handle for MSI-X tables */
5599517SBill.Taylor@Sun.COM if (ddi_regs_map_setup(state->hs_dip, state->hs_msix_tbl_rnumber,
5609517SBill.Taylor@Sun.COM (caddr_t *)&state->hs_msix_tbl_addr, state->hs_msix_tbl_offset,
5619517SBill.Taylor@Sun.COM state->hs_msix_tbl_size, &dev_attr,
5629517SBill.Taylor@Sun.COM &state->hs_reg_msix_tblhdl) != DDI_SUCCESS) {
5639517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
5649517SBill.Taylor@Sun.COM "MSI-X Table mapping fails (ereport mode)");
5659517SBill.Taylor@Sun.COM goto error;
5669517SBill.Taylor@Sun.COM }
5679517SBill.Taylor@Sun.COM
5689517SBill.Taylor@Sun.COM /* Allocate the regular access handle for MSI-X PBA */
5699517SBill.Taylor@Sun.COM if (ddi_regs_map_setup(state->hs_dip, state->hs_msix_pba_rnumber,
5709517SBill.Taylor@Sun.COM (caddr_t *)&state->hs_msix_pba_addr, state->hs_msix_pba_offset,
5719517SBill.Taylor@Sun.COM state->hs_msix_pba_size, &dev_attr,
5729517SBill.Taylor@Sun.COM &state->hs_reg_msix_pbahdl) != DDI_SUCCESS) {
5739517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
5749517SBill.Taylor@Sun.COM "MSI-X PBA mapping fails (ereport mode)");
5759517SBill.Taylor@Sun.COM goto error;
5769517SBill.Taylor@Sun.COM }
5779517SBill.Taylor@Sun.COM
5789517SBill.Taylor@Sun.COM /* Allocate the regular access handle for Hermon CMD I/O space */
5799517SBill.Taylor@Sun.COM if (ddi_regs_map_setup(state->hs_dip, HERMON_CMD_BAR,
5809517SBill.Taylor@Sun.COM &state->hs_reg_cmd_baseaddr, 0, 0, &state->hs_reg_accattr,
5819517SBill.Taylor@Sun.COM &state->hs_reg_cmdhdl) != DDI_SUCCESS) {
5829517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
5839517SBill.Taylor@Sun.COM "CMD_BAR mapping fails (ereport mode)");
5849517SBill.Taylor@Sun.COM goto error;
5859517SBill.Taylor@Sun.COM }
5869517SBill.Taylor@Sun.COM
5879517SBill.Taylor@Sun.COM /* Reset the host command register */
5889517SBill.Taylor@Sun.COM state->hs_cmd_regs.hcr = (hermon_hw_hcr_t *)
5899517SBill.Taylor@Sun.COM ((uintptr_t)state->hs_reg_cmd_baseaddr + HERMON_CMD_HCR_OFFSET);
5909517SBill.Taylor@Sun.COM
5919517SBill.Taylor@Sun.COM /* Reset the software reset register */
5929517SBill.Taylor@Sun.COM state->hs_cmd_regs.sw_reset = (uint32_t *)
5939517SBill.Taylor@Sun.COM ((uintptr_t)state->hs_reg_cmd_baseaddr +
5949517SBill.Taylor@Sun.COM HERMON_CMD_SW_RESET_OFFSET);
5959517SBill.Taylor@Sun.COM
5969517SBill.Taylor@Sun.COM /* Reset the software reset register semaphore */
5979517SBill.Taylor@Sun.COM state->hs_cmd_regs.sw_semaphore = (uint32_t *)
5989517SBill.Taylor@Sun.COM ((uintptr_t)state->hs_reg_cmd_baseaddr +
5999517SBill.Taylor@Sun.COM HERMON_CMD_SW_SEMAPHORE_OFFSET);
6009517SBill.Taylor@Sun.COM
6019517SBill.Taylor@Sun.COM /* Calculate the clear interrupt register offset */
6029517SBill.Taylor@Sun.COM offset = state->hs_fw.clr_intr_offs & HERMON_CMD_OFFSET_MASK;
6039517SBill.Taylor@Sun.COM
6049517SBill.Taylor@Sun.COM /* Reset the clear interrupt address */
6059517SBill.Taylor@Sun.COM state->hs_cmd_regs.clr_intr = (uint64_t *)
6069517SBill.Taylor@Sun.COM (uintptr_t)(state->hs_reg_cmd_baseaddr + offset);
6079517SBill.Taylor@Sun.COM
6089517SBill.Taylor@Sun.COM /* Reset the internal error buffer address */
6099517SBill.Taylor@Sun.COM state->hs_cmd_regs.fw_err_buf = (uint32_t *)(uintptr_t)
6109517SBill.Taylor@Sun.COM (state->hs_reg_cmd_baseaddr + state->hs_fw.error_buf_addr);
6119517SBill.Taylor@Sun.COM
6129517SBill.Taylor@Sun.COM /* Check if the blue flame is enabled, and set the offset value */
6139517SBill.Taylor@Sun.COM if (state->hs_devlim.blu_flm) {
6149517SBill.Taylor@Sun.COM offset = (uint64_t)1 <<
6159517SBill.Taylor@Sun.COM (state->hs_devlim.log_max_uar_sz + 20);
6169517SBill.Taylor@Sun.COM } else {
6179517SBill.Taylor@Sun.COM offset = 0;
6189517SBill.Taylor@Sun.COM }
6199517SBill.Taylor@Sun.COM
6209517SBill.Taylor@Sun.COM /* Allocate the regular access handle for Hermon UAR I/O space */
6219517SBill.Taylor@Sun.COM if (ddi_regs_map_setup(state->hs_dip, HERMON_UAR_BAR,
6229517SBill.Taylor@Sun.COM &state->hs_reg_uar_baseaddr, 0, offset,
6239517SBill.Taylor@Sun.COM &state->hs_reg_accattr, &state->hs_reg_uarhdl) != DDI_SUCCESS) {
6249517SBill.Taylor@Sun.COM HERMON_ATTACH_MSG(state->hs_attach_buf,
6259517SBill.Taylor@Sun.COM "UAR BAR mapping fails (ereport mode)");
6269517SBill.Taylor@Sun.COM goto error;
6279517SBill.Taylor@Sun.COM }
6289517SBill.Taylor@Sun.COM
629*12965SWilliam.Taylor@Oracle.COM hermon_eq_reset_uar_baseaddr(state);
630*12965SWilliam.Taylor@Oracle.COM
6319517SBill.Taylor@Sun.COM /* Drop the Hermon FM Attach Mode */
6329517SBill.Taylor@Sun.COM hermon_clr_state(state, HCA_ATTCH_FM);
6339517SBill.Taylor@Sun.COM
6349517SBill.Taylor@Sun.COM /* Set the Hermon FM Runtime Mode */
6359517SBill.Taylor@Sun.COM hermon_set_state(state, HCA_RUNTM_FM);
6369517SBill.Taylor@Sun.COM
6379517SBill.Taylor@Sun.COM /* Free up Hermon UAR page #1 */
6389517SBill.Taylor@Sun.COM hermon_rsrc_free(state, &state->hs_uarkpg_rsrc);
6399517SBill.Taylor@Sun.COM
6409517SBill.Taylor@Sun.COM /* Free up the UAR pool */
6419517SBill.Taylor@Sun.COM entry_info.hwi_rsrcpool = &state->hs_rsrc_hdl[HERMON_UARPG];
6429517SBill.Taylor@Sun.COM hermon_rsrc_hw_entries_fini(state, &entry_info);
6439517SBill.Taylor@Sun.COM
6449517SBill.Taylor@Sun.COM /* Re-allocate the UAR pool */
6459517SBill.Taylor@Sun.COM cfgprof = state->hs_cfg_profile;
6469517SBill.Taylor@Sun.COM devlim = &state->hs_devlim;
6479517SBill.Taylor@Sun.COM num = ((uint64_t)1 << cfgprof->cp_log_num_uar);
6489517SBill.Taylor@Sun.COM max = num;
6499517SBill.Taylor@Sun.COM num_prealloc = max(devlim->num_rsvd_uar, 128);
6509517SBill.Taylor@Sun.COM rsrc_pool = &state->hs_rsrc_hdl[HERMON_UARPG];
6519517SBill.Taylor@Sun.COM rsrc_pool->rsrc_type = HERMON_UARPG;
6529517SBill.Taylor@Sun.COM rsrc_pool->rsrc_loc = HERMON_IN_UAR;
6539517SBill.Taylor@Sun.COM rsrc_pool->rsrc_pool_size = (num << PAGESHIFT);
6549517SBill.Taylor@Sun.COM rsrc_pool->rsrc_shift = PAGESHIFT;
6559517SBill.Taylor@Sun.COM rsrc_pool->rsrc_quantum = (uint_t)PAGESIZE;
6569517SBill.Taylor@Sun.COM rsrc_pool->rsrc_align = PAGESIZE;
6579517SBill.Taylor@Sun.COM rsrc_pool->rsrc_state = state;
6589517SBill.Taylor@Sun.COM rsrc_pool->rsrc_start = (void *)state->hs_reg_uar_baseaddr;
6599517SBill.Taylor@Sun.COM rsrc_name = (char *)kmem_zalloc(HERMON_RSRC_NAME_MAXLEN, KM_SLEEP);
6609517SBill.Taylor@Sun.COM HERMON_RSRC_NAME(rsrc_name, HERMON_UAR_PAGE_VMEM_RUNTM);
6619517SBill.Taylor@Sun.COM entry_info.hwi_num = num;
6629517SBill.Taylor@Sun.COM entry_info.hwi_max = max;
6639517SBill.Taylor@Sun.COM entry_info.hwi_prealloc = num_prealloc;
6649517SBill.Taylor@Sun.COM entry_info.hwi_rsrcpool = rsrc_pool;
6659517SBill.Taylor@Sun.COM entry_info.hwi_rsrcname = rsrc_name;
6669517SBill.Taylor@Sun.COM if (hermon_rsrc_hw_entries_init(state, &entry_info) != DDI_SUCCESS) {
6679517SBill.Taylor@Sun.COM kmem_free(rsrc_name, HERMON_RSRC_NAME_MAXLEN);
6689517SBill.Taylor@Sun.COM goto error;
6699517SBill.Taylor@Sun.COM }
6709517SBill.Taylor@Sun.COM kmem_free(rsrc_name, HERMON_RSRC_NAME_MAXLEN);
6719517SBill.Taylor@Sun.COM
6729517SBill.Taylor@Sun.COM /* Re-allocate the kernel UAR page */
6739517SBill.Taylor@Sun.COM if (hermon_rsrc_alloc(state, HERMON_UARPG, 1, HERMON_SLEEP,
6749517SBill.Taylor@Sun.COM &state->hs_uarkpg_rsrc) != DDI_SUCCESS) {
6759517SBill.Taylor@Sun.COM goto error;
6769517SBill.Taylor@Sun.COM }
6779517SBill.Taylor@Sun.COM
6789517SBill.Taylor@Sun.COM /* Setup pointer to kernel UAR page */
6799517SBill.Taylor@Sun.COM state->hs_uar = (hermon_hw_uar_t *)state->hs_uarkpg_rsrc->hr_addr;
6809517SBill.Taylor@Sun.COM
6819517SBill.Taylor@Sun.COM /* Now drop the the Hermon PIO FM */
6829517SBill.Taylor@Sun.COM hermon_clr_state(state, HCA_PIO_FM);
6839517SBill.Taylor@Sun.COM
6849517SBill.Taylor@Sun.COM /* Release the MSI-X Table access handle */
6859517SBill.Taylor@Sun.COM if (state->hs_fm_msix_tblhdl) {
6869517SBill.Taylor@Sun.COM hermon_regs_map_free(state, &state->hs_fm_msix_tblhdl);
6879517SBill.Taylor@Sun.COM state->hs_fm_msix_tblhdl = NULL;
6889517SBill.Taylor@Sun.COM }
6899517SBill.Taylor@Sun.COM
6909517SBill.Taylor@Sun.COM /* Release the MSI-X PBA access handle */
6919517SBill.Taylor@Sun.COM if (state->hs_fm_msix_pbahdl) {
6929517SBill.Taylor@Sun.COM hermon_regs_map_free(state, &state->hs_fm_msix_pbahdl);
6939517SBill.Taylor@Sun.COM state->hs_fm_msix_pbahdl = NULL;
6949517SBill.Taylor@Sun.COM }
6959517SBill.Taylor@Sun.COM
6969517SBill.Taylor@Sun.COM /* Release the pci config space access handle */
6979517SBill.Taylor@Sun.COM if (state->hs_fm_pcihdl) {
6989517SBill.Taylor@Sun.COM hermon_regs_map_free(state, &state->hs_fm_pcihdl);
6999517SBill.Taylor@Sun.COM state->hs_fm_pcihdl = NULL;
7009517SBill.Taylor@Sun.COM }
7019517SBill.Taylor@Sun.COM
7029517SBill.Taylor@Sun.COM /* Release the cmd protected access handle */
7039517SBill.Taylor@Sun.COM if (state->hs_fm_cmdhdl) {
7049517SBill.Taylor@Sun.COM hermon_regs_map_free(state, &state->hs_fm_cmdhdl);
7059517SBill.Taylor@Sun.COM state->hs_fm_cmdhdl = NULL;
7069517SBill.Taylor@Sun.COM }
7079517SBill.Taylor@Sun.COM
7089517SBill.Taylor@Sun.COM /* Release the uar fma-protected access handle */
7099517SBill.Taylor@Sun.COM if (state->hs_fm_uarhdl) {
7109517SBill.Taylor@Sun.COM hermon_regs_map_free(state, &state->hs_fm_uarhdl);
7119517SBill.Taylor@Sun.COM state->hs_fm_uarhdl = NULL;
7129517SBill.Taylor@Sun.COM }
7139517SBill.Taylor@Sun.COM
7149517SBill.Taylor@Sun.COM /* Enable the Hermon interrupt again */
7159517SBill.Taylor@Sun.COM if (state->hs_intrmsi_cap & DDI_INTR_FLAG_BLOCK) {
7169517SBill.Taylor@Sun.COM if (ddi_intr_block_enable
7179517SBill.Taylor@Sun.COM (&state->hs_intrmsi_hdl[0], 1) != DDI_SUCCESS) {
7189517SBill.Taylor@Sun.COM return (DDI_FAILURE);
7199517SBill.Taylor@Sun.COM }
7209517SBill.Taylor@Sun.COM } else {
7219517SBill.Taylor@Sun.COM if (ddi_intr_enable
7229517SBill.Taylor@Sun.COM (state->hs_intrmsi_hdl[0]) != DDI_SUCCESS) {
7239517SBill.Taylor@Sun.COM return (DDI_FAILURE);
7249517SBill.Taylor@Sun.COM }
7259517SBill.Taylor@Sun.COM }
7269517SBill.Taylor@Sun.COM
7279517SBill.Taylor@Sun.COM /* Restart the poll thread */
7289517SBill.Taylor@Sun.COM state->hs_fm_poll_suspend = B_FALSE;
7299517SBill.Taylor@Sun.COM
7309517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
7319517SBill.Taylor@Sun.COM
7329517SBill.Taylor@Sun.COM error:
7339517SBill.Taylor@Sun.COM /* Enable the Hermon interrupt again */
7349517SBill.Taylor@Sun.COM if (state->hs_intrmsi_cap & DDI_INTR_FLAG_BLOCK) {
7359517SBill.Taylor@Sun.COM (void) ddi_intr_block_enable(&state->hs_intrmsi_hdl[0], 1);
7369517SBill.Taylor@Sun.COM } else {
7379517SBill.Taylor@Sun.COM (void) ddi_intr_enable(state->hs_intrmsi_hdl[0]);
7389517SBill.Taylor@Sun.COM }
7399517SBill.Taylor@Sun.COM return (DDI_FAILURE);
7409517SBill.Taylor@Sun.COM }
7419517SBill.Taylor@Sun.COM
7429517SBill.Taylor@Sun.COM
7439517SBill.Taylor@Sun.COM /*
7449517SBill.Taylor@Sun.COM * int
7459517SBill.Taylor@Sun.COM * hermon_regs_map_setup(hermon_state_t *state, uint_t rnumber, caddr_t *addrp,
7469517SBill.Taylor@Sun.COM * offset_t offset, offset_t len, ddi_device_acc_attr_t *accattrp,
7479517SBill.Taylor@Sun.COM * ddi_acc_handle_t *handle)
7489517SBill.Taylor@Sun.COM *
7499517SBill.Taylor@Sun.COM * Overview
7509517SBill.Taylor@Sun.COM * This is a wrapper function of i_hca_regs_map_setup() for Hermon FM so
7519517SBill.Taylor@Sun.COM * that it calls i_hca_regs_map_setup() inside after it checks the
7529517SBill.Taylor@Sun.COM * "fm_disable" configuration property. If the "fm_disable" is described
7539517SBill.Taylor@Sun.COM * in /kernel/drv/hermon.conf, the function calls ddi_regs_map_setup()
7549517SBill.Taylor@Sun.COM * directly instead.
7559517SBill.Taylor@Sun.COM * See i_hca_regs_map_setup() in detail.
7569517SBill.Taylor@Sun.COM *
7579517SBill.Taylor@Sun.COM * Argument
7589517SBill.Taylor@Sun.COM * state: pointer to Hermon state structure
7599517SBill.Taylor@Sun.COM * rnumber: index number to the register address space set
7609517SBill.Taylor@Sun.COM * addrp: platform-dependent value (same as ddi_regs_map_setup())
7619517SBill.Taylor@Sun.COM * offset: offset into the register address space
7629517SBill.Taylor@Sun.COM * len: address space length to be mapped
7639517SBill.Taylor@Sun.COM * accattrp: pointer to device access attribute structure
7649517SBill.Taylor@Sun.COM * handle: pointer to ddi_acc_handle_t used for HCA FM
7659517SBill.Taylor@Sun.COM *
7669517SBill.Taylor@Sun.COM * Return value
7679517SBill.Taylor@Sun.COM * ddi function status value which are:
7689517SBill.Taylor@Sun.COM * DDI_SUCCESS
7699517SBill.Taylor@Sun.COM * DDI_FAILURE
7709517SBill.Taylor@Sun.COM * DDI_ME_RNUMBER_RNGE
7719517SBill.Taylor@Sun.COM * DDI_REGS_ACC_CONFLICT
7729517SBill.Taylor@Sun.COM *
7739517SBill.Taylor@Sun.COM * Caller's context
7749517SBill.Taylor@Sun.COM * hermon_regs_map_setup() can be called in user or kernel context only.
7759517SBill.Taylor@Sun.COM */
7769517SBill.Taylor@Sun.COM int
hermon_regs_map_setup(hermon_state_t * state,uint_t rnumber,caddr_t * addrp,offset_t offset,offset_t len,ddi_device_acc_attr_t * accattrp,ddi_acc_handle_t * handle)7779517SBill.Taylor@Sun.COM hermon_regs_map_setup(hermon_state_t *state, uint_t rnumber, caddr_t *addrp,
7789517SBill.Taylor@Sun.COM offset_t offset, offset_t len, ddi_device_acc_attr_t *accattrp,
7799517SBill.Taylor@Sun.COM ddi_acc_handle_t *handle)
7809517SBill.Taylor@Sun.COM {
7819517SBill.Taylor@Sun.COM if (state->hs_fm_disable) {
7829517SBill.Taylor@Sun.COM return (ddi_regs_map_setup(state->hs_dip, rnumber, addrp,
7839517SBill.Taylor@Sun.COM offset, len, accattrp, handle));
7849517SBill.Taylor@Sun.COM } else {
7859517SBill.Taylor@Sun.COM return (i_hca_regs_map_setup(state->hs_fm_hca_fm, state->hs_dip,
7869517SBill.Taylor@Sun.COM rnumber, addrp, offset, len, accattrp, handle));
7879517SBill.Taylor@Sun.COM }
7889517SBill.Taylor@Sun.COM }
7899517SBill.Taylor@Sun.COM
7909517SBill.Taylor@Sun.COM
7919517SBill.Taylor@Sun.COM /*
7929517SBill.Taylor@Sun.COM * void
7939517SBill.Taylor@Sun.COM * hermon_regs_map_free(hermon_state_t *state, ddi_acc_handle_t *handlep)
7949517SBill.Taylor@Sun.COM *
7959517SBill.Taylor@Sun.COM * Overview
7969517SBill.Taylor@Sun.COM * This is a wrapper function of i_hca_regs_map_free() for Hermon FM so
7979517SBill.Taylor@Sun.COM * that it calls i_hca_regs_map_free() inside after it checks the
7989517SBill.Taylor@Sun.COM * "fm_disable" configuration property. If the "fm_disable" is described
7999517SBill.Taylor@Sun.COM * in /kernel/drv/hermon.conf, the function calls ddi_regs_map_fre()
8009517SBill.Taylor@Sun.COM * directly instead. See i_hca_regs_map_free() in detail.
8019517SBill.Taylor@Sun.COM *
8029517SBill.Taylor@Sun.COM * Argument
8039517SBill.Taylor@Sun.COM * state: pointer to Hermon state structure
8049517SBill.Taylor@Sun.COM * handle: pointer to ddi_acc_handle_t used for HCA FM
8059517SBill.Taylor@Sun.COM *
8069517SBill.Taylor@Sun.COM * Return value
8079517SBill.Taylor@Sun.COM * Nothing
8089517SBill.Taylor@Sun.COM *
8099517SBill.Taylor@Sun.COM * Caller's context
8109517SBill.Taylor@Sun.COM * hermon_regs_map_free() can be called in user or kernel context only.
8119517SBill.Taylor@Sun.COM *
8129517SBill.Taylor@Sun.COM * Note that the handle passed to hermon_regs_map_free() is NULL-cleared
8139517SBill.Taylor@Sun.COM * after this function is called.
8149517SBill.Taylor@Sun.COM */
8159517SBill.Taylor@Sun.COM void
hermon_regs_map_free(hermon_state_t * state,ddi_acc_handle_t * handle)8169517SBill.Taylor@Sun.COM hermon_regs_map_free(hermon_state_t *state, ddi_acc_handle_t *handle)
8179517SBill.Taylor@Sun.COM {
8189517SBill.Taylor@Sun.COM if (state->hs_fm_disable) {
8199517SBill.Taylor@Sun.COM ddi_regs_map_free(handle);
8209517SBill.Taylor@Sun.COM *handle = NULL;
8219517SBill.Taylor@Sun.COM } else {
8229517SBill.Taylor@Sun.COM i_hca_regs_map_free(state->hs_fm_hca_fm, handle);
8239517SBill.Taylor@Sun.COM }
8249517SBill.Taylor@Sun.COM }
8259517SBill.Taylor@Sun.COM
8269517SBill.Taylor@Sun.COM
8279517SBill.Taylor@Sun.COM /*
8289517SBill.Taylor@Sun.COM * int
8299517SBill.Taylor@Sun.COM * hermon_pci_config_setup(hermon_state_t *state, ddi_acc_handle_t *handle)
8309517SBill.Taylor@Sun.COM *
8319517SBill.Taylor@Sun.COM * Overview
8329517SBill.Taylor@Sun.COM * This is a wrapper function of i_hca_pci_config_setup() for Hermon FM so
8339517SBill.Taylor@Sun.COM * that it calls i_hca_pci_config_setup() inside after it checks the
8349517SBill.Taylor@Sun.COM * "fm-disable" configuration property. If the "fm_disable" is described
8359517SBill.Taylor@Sun.COM * in /kernel/drv/hermon.conf, the function calls pci_config_setup()
8369517SBill.Taylor@Sun.COM * directly instead. See i_hca_pci_config_setup() in detail.
8379517SBill.Taylor@Sun.COM *
8389517SBill.Taylor@Sun.COM * Argument
8399517SBill.Taylor@Sun.COM * state: pointer to Hermon state structure
8409517SBill.Taylor@Sun.COM * handle: pointer to ddi_acc_handle_t used for HCA FM
8419517SBill.Taylor@Sun.COM *
8429517SBill.Taylor@Sun.COM * Return value
8439517SBill.Taylor@Sun.COM * ddi function status value which are:
8449517SBill.Taylor@Sun.COM * DDI_SUCCESS
8459517SBill.Taylor@Sun.COM * DDI_FAILURE
8469517SBill.Taylor@Sun.COM *
8479517SBill.Taylor@Sun.COM * Caller's context
8489517SBill.Taylor@Sun.COM * hermon_pci_config_setup() can be called in user or kernel context only.
8499517SBill.Taylor@Sun.COM */
8509517SBill.Taylor@Sun.COM int
hermon_pci_config_setup(hermon_state_t * state,ddi_acc_handle_t * handle)8519517SBill.Taylor@Sun.COM hermon_pci_config_setup(hermon_state_t *state, ddi_acc_handle_t *handle)
8529517SBill.Taylor@Sun.COM {
8539517SBill.Taylor@Sun.COM if (state->hs_fm_disable) {
8549517SBill.Taylor@Sun.COM return (pci_config_setup(state->hs_dip, handle));
8559517SBill.Taylor@Sun.COM } else {
8569517SBill.Taylor@Sun.COM /* Check Hermon FM and Solaris FMA capability flags */
8579517SBill.Taylor@Sun.COM ASSERT((hermon_get_state(state) & HCA_PIO_FM &&
8589517SBill.Taylor@Sun.COM DDI_FM_ACC_ERR_CAP(ddi_fm_capable(state->hs_dip))) ||
8599517SBill.Taylor@Sun.COM (!(hermon_get_state(state) & HCA_PIO_FM) &&
8609517SBill.Taylor@Sun.COM !DDI_FM_ACC_ERR_CAP(ddi_fm_capable(state->hs_dip))));
8619517SBill.Taylor@Sun.COM return (i_hca_pci_config_setup(state->hs_fm_hca_fm,
8629517SBill.Taylor@Sun.COM state->hs_dip, handle));
8639517SBill.Taylor@Sun.COM }
8649517SBill.Taylor@Sun.COM }
8659517SBill.Taylor@Sun.COM
8669517SBill.Taylor@Sun.COM
8679517SBill.Taylor@Sun.COM /*
8689517SBill.Taylor@Sun.COM * void
8699517SBill.Taylor@Sun.COM * hermon_pci_config_teardown(hermon_state_t *state, ddi_acc_handle_t *handle)
8709517SBill.Taylor@Sun.COM *
8719517SBill.Taylor@Sun.COM * Overview
8729517SBill.Taylor@Sun.COM * This is a wrapper function of i_hca_pci_config_teardown() for Hermon
8739517SBill.Taylor@Sun.COM * FM so that it calls i_hca_pci_config_teardown() inside after it checks
8749517SBill.Taylor@Sun.COM * the "fm-disable" configuration property. If the "fm_disable" is
8759517SBill.Taylor@Sun.COM * described in /kernel/drv/hermon.conf, the function calls
8769517SBill.Taylor@Sun.COM * pci_config_teardown() directly instead.
8779517SBill.Taylor@Sun.COM * See i_hca_pci_config_teardown() in detail.
8789517SBill.Taylor@Sun.COM *
8799517SBill.Taylor@Sun.COM * Argument
8809517SBill.Taylor@Sun.COM * state: pointer to Hermon state structure
8819517SBill.Taylor@Sun.COM * handle: pointer to ddi_acc_handle_t used for HCA FM
8829517SBill.Taylor@Sun.COM *
8839517SBill.Taylor@Sun.COM * Return value
8849517SBill.Taylor@Sun.COM * Nothing
8859517SBill.Taylor@Sun.COM *
8869517SBill.Taylor@Sun.COM * Caller's context
8879517SBill.Taylor@Sun.COM * hermon_pci_config_teardown() can be called in user or kernel context
8889517SBill.Taylor@Sun.COM * only.
8899517SBill.Taylor@Sun.COM */
8909517SBill.Taylor@Sun.COM void
hermon_pci_config_teardown(hermon_state_t * state,ddi_acc_handle_t * handle)8919517SBill.Taylor@Sun.COM hermon_pci_config_teardown(hermon_state_t *state, ddi_acc_handle_t *handle)
8929517SBill.Taylor@Sun.COM {
8939517SBill.Taylor@Sun.COM if (state->hs_fm_disable) {
8949517SBill.Taylor@Sun.COM pci_config_teardown(handle);
8959517SBill.Taylor@Sun.COM *handle = NULL;
8969517SBill.Taylor@Sun.COM } else {
8979517SBill.Taylor@Sun.COM i_hca_pci_config_teardown(state->hs_fm_hca_fm, handle);
8989517SBill.Taylor@Sun.COM }
8999517SBill.Taylor@Sun.COM }
9009517SBill.Taylor@Sun.COM
9019517SBill.Taylor@Sun.COM
9029517SBill.Taylor@Sun.COM /*
9039517SBill.Taylor@Sun.COM * boolean_t
9049517SBill.Taylor@Sun.COM * hermon_init_failure(hermon_state_t *state)
9059517SBill.Taylor@Sun.COM *
9069517SBill.Taylor@Sun.COM * Overview
9079517SBill.Taylor@Sun.COM * hermon_init_failure() tells if HW errors are detected in
9089517SBill.Taylor@Sun.COM * the Hermon driver attach.
9099517SBill.Taylor@Sun.COM *
9109517SBill.Taylor@Sun.COM * Argument
9119517SBill.Taylor@Sun.COM * state: pointer to Hermon state structure
9129517SBill.Taylor@Sun.COM *
9139517SBill.Taylor@Sun.COM * Return value
9149517SBill.Taylor@Sun.COM * B_TRUE HW errors detected during attach
9159517SBill.Taylor@Sun.COM * B_FALSE No HW errors during attach
9169517SBill.Taylor@Sun.COM *
9179517SBill.Taylor@Sun.COM * Caller's context
9189517SBill.Taylor@Sun.COM * hermon_init_failure() can be called in user, kernel, interrupt
9199517SBill.Taylor@Sun.COM * context or high interrupt context.
9209517SBill.Taylor@Sun.COM */
9219517SBill.Taylor@Sun.COM boolean_t
hermon_init_failure(hermon_state_t * state)9229517SBill.Taylor@Sun.COM hermon_init_failure(hermon_state_t *state)
9239517SBill.Taylor@Sun.COM {
9249517SBill.Taylor@Sun.COM ddi_acc_handle_t hdl;
9259517SBill.Taylor@Sun.COM ddi_fm_error_t derr;
9269517SBill.Taylor@Sun.COM
9279517SBill.Taylor@Sun.COM if (!(hermon_get_state(state) & HCA_PIO_FM))
9289517SBill.Taylor@Sun.COM return (B_FALSE);
9299517SBill.Taylor@Sun.COM
9309778SEiji.Ota@Sun.COM /* check if fatal errors occur during attach */
9319778SEiji.Ota@Sun.COM if (state->hs_fm_async_fatal)
9329778SEiji.Ota@Sun.COM return (B_TRUE);
9339778SEiji.Ota@Sun.COM
9349517SBill.Taylor@Sun.COM hdl = hermon_get_uarhdl(state);
9359517SBill.Taylor@Sun.COM /* Get the PIO error against UAR I/O space */
9369517SBill.Taylor@Sun.COM ddi_fm_acc_err_get(hdl, &derr, DDI_FME_VERSION);
9379517SBill.Taylor@Sun.COM if (derr.fme_status != DDI_FM_OK) {
9389517SBill.Taylor@Sun.COM return (B_TRUE);
9399517SBill.Taylor@Sun.COM }
9409517SBill.Taylor@Sun.COM
9419517SBill.Taylor@Sun.COM hdl = hermon_get_cmdhdl(state);
9429517SBill.Taylor@Sun.COM /* Get the PIO error againsts CMD I/O space */
9439517SBill.Taylor@Sun.COM ddi_fm_acc_err_get(hdl, &derr, DDI_FME_VERSION);
9449517SBill.Taylor@Sun.COM if (derr.fme_status != DDI_FM_OK) {
9459517SBill.Taylor@Sun.COM return (B_TRUE);
9469517SBill.Taylor@Sun.COM }
9479517SBill.Taylor@Sun.COM
9489517SBill.Taylor@Sun.COM return (B_FALSE);
9499517SBill.Taylor@Sun.COM }
9509517SBill.Taylor@Sun.COM
9519517SBill.Taylor@Sun.COM
9529517SBill.Taylor@Sun.COM /*
9539517SBill.Taylor@Sun.COM * void
9549517SBill.Taylor@Sun.COM * hermon_fm_ereport(hermon_state_t *state, int type, int detail)
9559517SBill.Taylor@Sun.COM *
9569517SBill.Taylor@Sun.COM * Overview
9579517SBill.Taylor@Sun.COM * hermon_fm_ereport() is a Hermon FM ereport function used
9589517SBill.Taylor@Sun.COM * to issue a Solaris FMA ereport. See Hermon FM comments at the
9599517SBill.Taylor@Sun.COM * beginning of this file in detail.
9609517SBill.Taylor@Sun.COM *
9619517SBill.Taylor@Sun.COM * Argument
9629517SBill.Taylor@Sun.COM * state: pointer to Hermon state structure
9639517SBill.Taylor@Sun.COM * type: error type
9649517SBill.Taylor@Sun.COM * HCA_SYS_ERR FMA reporting HW error
9659517SBill.Taylor@Sun.COM * HCA_IBA_ERR HCA specific HW error
9669517SBill.Taylor@Sun.COM * detail: HW error hint implying which ereport is issued
9679517SBill.Taylor@Sun.COM * HCA_ERR_TRANSIENT HW transienet error
9689517SBill.Taylor@Sun.COM * HCA_ERR_NON_FATAL HW persistent error
9699517SBill.Taylor@Sun.COM * HCA_ERR_FATAL HW fatal error
9709517SBill.Taylor@Sun.COM * HCA_ERR_SRV_LOST IB service lost due to HW error
9719517SBill.Taylor@Sun.COM * HCA_ERR_DEGRADED Hermon driver and/or uDAPL degraded
9729517SBill.Taylor@Sun.COM * due to HW error
9739517SBill.Taylor@Sun.COM * HCA_ERR_IOCTL HW error detected in user conetxt
9749517SBill.Taylor@Sun.COM * (especially in ioctl())
9759517SBill.Taylor@Sun.COM *
9769517SBill.Taylor@Sun.COM * Return value
9779517SBill.Taylor@Sun.COM * Nothing
9789517SBill.Taylor@Sun.COM *
9799517SBill.Taylor@Sun.COM * Caller's context
9809517SBill.Taylor@Sun.COM * hermon_fm_ereport() can be called in user, kernel, interrupt context
9819517SBill.Taylor@Sun.COM * or high interrupt context.
9829517SBill.Taylor@Sun.COM */
9839517SBill.Taylor@Sun.COM void
hermon_fm_ereport(hermon_state_t * state,int type,int detail)9849517SBill.Taylor@Sun.COM hermon_fm_ereport(hermon_state_t *state, int type, int detail)
9859517SBill.Taylor@Sun.COM {
9869517SBill.Taylor@Sun.COM /*
9879517SBill.Taylor@Sun.COM * If hermon_fm_diable is set or there is no FM ereport service
9889517SBill.Taylor@Sun.COM * provided, then skip the rest.
9899517SBill.Taylor@Sun.COM */
9909517SBill.Taylor@Sun.COM if (state->hs_fm_disable ||
9919517SBill.Taylor@Sun.COM !(hermon_get_state(state) & HCA_EREPORT_FM)) {
9929517SBill.Taylor@Sun.COM return;
9939517SBill.Taylor@Sun.COM }
9949517SBill.Taylor@Sun.COM
9959517SBill.Taylor@Sun.COM switch (type) {
9969517SBill.Taylor@Sun.COM
9979517SBill.Taylor@Sun.COM case HCA_SYS_ERR:
9989517SBill.Taylor@Sun.COM switch (detail) {
9999517SBill.Taylor@Sun.COM case HCA_ERR_TRANSIENT:
10009517SBill.Taylor@Sun.COM case HCA_ERR_IOCTL:
10019517SBill.Taylor@Sun.COM ddi_fm_service_impact(state->hs_dip,
10029517SBill.Taylor@Sun.COM DDI_SERVICE_UNAFFECTED);
10039517SBill.Taylor@Sun.COM break;
10049517SBill.Taylor@Sun.COM case HCA_ERR_NON_FATAL:
10059517SBill.Taylor@Sun.COM /* Nothing */
10069517SBill.Taylor@Sun.COM break;
10079517SBill.Taylor@Sun.COM case HCA_ERR_SRV_LOST:
10089517SBill.Taylor@Sun.COM ddi_fm_service_impact(state->hs_dip,
10099517SBill.Taylor@Sun.COM DDI_SERVICE_LOST);
10109517SBill.Taylor@Sun.COM break;
10119517SBill.Taylor@Sun.COM case HCA_ERR_DEGRADED:
101210125SEiji.Ota@Sun.COM switch (state->hs_fm_degraded_reason) {
101310125SEiji.Ota@Sun.COM case HCA_FW_CORRUPT:
101410125SEiji.Ota@Sun.COM i_hca_fm_ereport(state->hs_dip, type,
101510125SEiji.Ota@Sun.COM DDI_FM_DEVICE_FW_CORRUPT);
101610125SEiji.Ota@Sun.COM break;
101710125SEiji.Ota@Sun.COM case HCA_FW_MISMATCH:
101810125SEiji.Ota@Sun.COM i_hca_fm_ereport(state->hs_dip, type,
101910125SEiji.Ota@Sun.COM DDI_FM_DEVICE_FW_MISMATCH);
102010125SEiji.Ota@Sun.COM break;
102110125SEiji.Ota@Sun.COM case HCA_FW_MISC:
102210125SEiji.Ota@Sun.COM default:
102310125SEiji.Ota@Sun.COM i_hca_fm_ereport(state->hs_dip, type,
102410125SEiji.Ota@Sun.COM DDI_FM_DEVICE_INTERN_UNCORR);
102510125SEiji.Ota@Sun.COM break;
102610125SEiji.Ota@Sun.COM }
10279517SBill.Taylor@Sun.COM ddi_fm_service_impact(state->hs_dip,
10289517SBill.Taylor@Sun.COM DDI_SERVICE_DEGRADED);
10299517SBill.Taylor@Sun.COM break;
10309517SBill.Taylor@Sun.COM case HCA_ERR_FATAL:
10319517SBill.Taylor@Sun.COM ddi_fm_service_impact(state->hs_dip,
10329517SBill.Taylor@Sun.COM DDI_SERVICE_LOST);
10339517SBill.Taylor@Sun.COM state->hs_fm_async_fatal = B_TRUE;
10349517SBill.Taylor@Sun.COM break;
10359517SBill.Taylor@Sun.COM default:
10369517SBill.Taylor@Sun.COM cmn_err(CE_WARN, "hermon_fm_ereport: Unknown error. "
10379517SBill.Taylor@Sun.COM "type = %d, detail = %d\n.", type, detail);
10389517SBill.Taylor@Sun.COM }
10399517SBill.Taylor@Sun.COM break;
10409517SBill.Taylor@Sun.COM
10419517SBill.Taylor@Sun.COM case HCA_IBA_ERR:
10429517SBill.Taylor@Sun.COM switch (detail) {
10439517SBill.Taylor@Sun.COM case HCA_ERR_TRANSIENT:
10449517SBill.Taylor@Sun.COM i_hca_fm_ereport(state->hs_dip, type,
10459517SBill.Taylor@Sun.COM DDI_FM_DEVICE_INTERN_UNCORR);
10469517SBill.Taylor@Sun.COM ddi_fm_service_impact(state->hs_dip,
10479517SBill.Taylor@Sun.COM DDI_SERVICE_UNAFFECTED);
10489517SBill.Taylor@Sun.COM break;
10499517SBill.Taylor@Sun.COM case HCA_ERR_SRV_LOST:
10509517SBill.Taylor@Sun.COM cmn_err(CE_WARN, "hermon_fm_ereport: not supported "
10519517SBill.Taylor@Sun.COM "error. type = %d, detail = %d\n.", type, detail);
10529517SBill.Taylor@Sun.COM break;
10539517SBill.Taylor@Sun.COM case HCA_ERR_DEGRADED:
105410125SEiji.Ota@Sun.COM switch (state->hs_fm_degraded_reason) {
105510125SEiji.Ota@Sun.COM case HCA_FW_CORRUPT:
105610125SEiji.Ota@Sun.COM i_hca_fm_ereport(state->hs_dip, type,
105710125SEiji.Ota@Sun.COM DDI_FM_DEVICE_FW_CORRUPT);
105810125SEiji.Ota@Sun.COM break;
105910125SEiji.Ota@Sun.COM case HCA_FW_MISMATCH:
106010125SEiji.Ota@Sun.COM i_hca_fm_ereport(state->hs_dip, type,
106110125SEiji.Ota@Sun.COM DDI_FM_DEVICE_FW_MISMATCH);
106210125SEiji.Ota@Sun.COM break;
106310125SEiji.Ota@Sun.COM case HCA_FW_MISC:
106410125SEiji.Ota@Sun.COM default:
106510125SEiji.Ota@Sun.COM i_hca_fm_ereport(state->hs_dip, type,
106610125SEiji.Ota@Sun.COM DDI_FM_DEVICE_INTERN_UNCORR);
106710125SEiji.Ota@Sun.COM break;
106810125SEiji.Ota@Sun.COM }
10699517SBill.Taylor@Sun.COM ddi_fm_service_impact(state->hs_dip,
10709517SBill.Taylor@Sun.COM DDI_SERVICE_DEGRADED);
10719517SBill.Taylor@Sun.COM break;
10729517SBill.Taylor@Sun.COM case HCA_ERR_IOCTL:
10739517SBill.Taylor@Sun.COM case HCA_ERR_NON_FATAL:
10749517SBill.Taylor@Sun.COM i_hca_fm_ereport(state->hs_dip, type,
10759517SBill.Taylor@Sun.COM DDI_FM_DEVICE_INTERN_UNCORR);
10769517SBill.Taylor@Sun.COM ddi_fm_service_impact(state->hs_dip,
10779517SBill.Taylor@Sun.COM DDI_SERVICE_UNAFFECTED);
10789517SBill.Taylor@Sun.COM break;
10799517SBill.Taylor@Sun.COM case HCA_ERR_FATAL:
10809517SBill.Taylor@Sun.COM if (hermon_get_state(state) & HCA_PIO_FM) {
10819517SBill.Taylor@Sun.COM if (servicing_interrupt()) {
10829517SBill.Taylor@Sun.COM atomic_inc_32(&state->
10839517SBill.Taylor@Sun.COM hs_fm_async_errcnt);
10849517SBill.Taylor@Sun.COM } else {
10859517SBill.Taylor@Sun.COM i_hca_fm_ereport(state->hs_dip, type,
10869517SBill.Taylor@Sun.COM DDI_FM_DEVICE_INTERN_UNCORR);
10879517SBill.Taylor@Sun.COM ddi_fm_service_impact(state->hs_dip,
10889517SBill.Taylor@Sun.COM DDI_SERVICE_LOST);
10899517SBill.Taylor@Sun.COM }
10909517SBill.Taylor@Sun.COM state->hs_fm_async_fatal = B_TRUE;
10919517SBill.Taylor@Sun.COM } else {
10929517SBill.Taylor@Sun.COM i_hca_fm_ereport(state->hs_dip, type,
10939517SBill.Taylor@Sun.COM DDI_FM_DEVICE_INTERN_UNCORR);
10949517SBill.Taylor@Sun.COM ddi_fm_service_impact(state->hs_dip,
10959517SBill.Taylor@Sun.COM DDI_SERVICE_LOST);
10969517SBill.Taylor@Sun.COM cmn_err(CE_PANIC,
10979517SBill.Taylor@Sun.COM "Hermon Fatal Internal Error. "
10989517SBill.Taylor@Sun.COM "Hermon state=0x%p", (void *)state);
10999517SBill.Taylor@Sun.COM }
11009517SBill.Taylor@Sun.COM break;
11019517SBill.Taylor@Sun.COM default:
11029517SBill.Taylor@Sun.COM cmn_err(CE_WARN, "hermon_fm_ereport: Unknown error. "
11039517SBill.Taylor@Sun.COM "type = %d, detail = %d\n.", type, detail);
11049517SBill.Taylor@Sun.COM }
11059517SBill.Taylor@Sun.COM break;
11069517SBill.Taylor@Sun.COM
11079517SBill.Taylor@Sun.COM default:
11089517SBill.Taylor@Sun.COM cmn_err(CE_WARN, "hermon_fm_ereport: Unknown type "
11099517SBill.Taylor@Sun.COM "type = %d, detail = %d\n.", type, detail);
11109517SBill.Taylor@Sun.COM break;
11119517SBill.Taylor@Sun.COM }
11129517SBill.Taylor@Sun.COM }
11139517SBill.Taylor@Sun.COM
11149517SBill.Taylor@Sun.COM
11159517SBill.Taylor@Sun.COM /*
11169517SBill.Taylor@Sun.COM * uchar_t
11179517SBill.Taylor@Sun.COM * hermon_devacc_attr_version(hermon_state_t *)
11189517SBill.Taylor@Sun.COM *
11199517SBill.Taylor@Sun.COM * Overview
11209517SBill.Taylor@Sun.COM * hermon_devacc_attr_version() returns the ddi device attribute
11219517SBill.Taylor@Sun.COM * version.
11229517SBill.Taylor@Sun.COM *
11239517SBill.Taylor@Sun.COM * Argument
11249517SBill.Taylor@Sun.COM * state: pointer to Hermon state structure
11259517SBill.Taylor@Sun.COM *
11269517SBill.Taylor@Sun.COM * Return value
11279517SBill.Taylor@Sun.COM * dev_acc_attr_version value
11289517SBill.Taylor@Sun.COM * DDI_DEVICE_ATTR_V0 Hermon FM disabled
11299517SBill.Taylor@Sun.COM * DDI_DEVICE_ATTR_V1 Hermon FM enabled
11309517SBill.Taylor@Sun.COM *
11319517SBill.Taylor@Sun.COM * Caller's context
11329517SBill.Taylor@Sun.COM * hermon_devacc_attr_version() can be called in user, kernel, interrupt
11339517SBill.Taylor@Sun.COM * context or high interrupt context.
11349517SBill.Taylor@Sun.COM */
11359517SBill.Taylor@Sun.COM ushort_t
hermon_devacc_attr_version(hermon_state_t * state)11369517SBill.Taylor@Sun.COM hermon_devacc_attr_version(hermon_state_t *state)
11379517SBill.Taylor@Sun.COM {
11389517SBill.Taylor@Sun.COM if (state->hs_fm_disable) {
11399517SBill.Taylor@Sun.COM return (DDI_DEVICE_ATTR_V0);
11409517SBill.Taylor@Sun.COM } else {
11419517SBill.Taylor@Sun.COM return (DDI_DEVICE_ATTR_V1);
11429517SBill.Taylor@Sun.COM }
11439517SBill.Taylor@Sun.COM }
11449517SBill.Taylor@Sun.COM
11459517SBill.Taylor@Sun.COM
11469517SBill.Taylor@Sun.COM /*
11479517SBill.Taylor@Sun.COM * uchar_t
11489517SBill.Taylor@Sun.COM * hermon_devacc_attr_access(hermon_state_t *)
11499517SBill.Taylor@Sun.COM *
11509517SBill.Taylor@Sun.COM * Overview
11519517SBill.Taylor@Sun.COM * hermon_devacc_attr_access() returns devacc_attr_access error
11529517SBill.Taylor@Sun.COM * protection types.
11539517SBill.Taylor@Sun.COM *
11549517SBill.Taylor@Sun.COM * Argument
11559517SBill.Taylor@Sun.COM * state: pointer to Hermon state structure
11569517SBill.Taylor@Sun.COM *
11579517SBill.Taylor@Sun.COM * Return value
11589517SBill.Taylor@Sun.COM * dev_acc_attr_access error protection type
11599517SBill.Taylor@Sun.COM * DDI_DEFAULT_ACC Hermon FM disabled for PIO
11609517SBill.Taylor@Sun.COM * DDI_FLAGERR_ACC Hermon FM enabled for PIO
11619517SBill.Taylor@Sun.COM *
11629517SBill.Taylor@Sun.COM * Caller's context
11639517SBill.Taylor@Sun.COM * hermon_devacc_attr_access() can be called in user, kernel, interrupt
11649517SBill.Taylor@Sun.COM * context or high interrupt context.
11659517SBill.Taylor@Sun.COM */
11669517SBill.Taylor@Sun.COM uchar_t
hermon_devacc_attr_access(hermon_state_t * state)11679517SBill.Taylor@Sun.COM hermon_devacc_attr_access(hermon_state_t *state)
11689517SBill.Taylor@Sun.COM {
11699517SBill.Taylor@Sun.COM if (state->hs_fm_disable) {
11709517SBill.Taylor@Sun.COM return (DDI_DEFAULT_ACC);
11719517SBill.Taylor@Sun.COM } else {
11729517SBill.Taylor@Sun.COM return (DDI_FLAGERR_ACC);
11739517SBill.Taylor@Sun.COM }
11749517SBill.Taylor@Sun.COM }
11759517SBill.Taylor@Sun.COM
11769517SBill.Taylor@Sun.COM
11779517SBill.Taylor@Sun.COM /*
11789517SBill.Taylor@Sun.COM * int
11799517SBill.Taylor@Sun.COM * hermon_PIO_start(hermon_state_t *state, ddi_acc_handle_t handle,
11809517SBill.Taylor@Sun.COM * hermon_test_t *tst)
11819517SBill.Taylor@Sun.COM *
11829517SBill.Taylor@Sun.COM * Overview
11839517SBill.Taylor@Sun.COM * hermon_PIO_start() should be called before Hermon driver issues PIOs
11849517SBill.Taylor@Sun.COM * against I/O space. If Hermon FM is disabled, this function returns
11859517SBill.Taylor@Sun.COM * HCA_PIO_OK always. See i_hca_pio_start() in detail.
11869517SBill.Taylor@Sun.COM *
11879517SBill.Taylor@Sun.COM * Argument
11889517SBill.Taylor@Sun.COM * state: pointer to Hermon state structure
11899517SBill.Taylor@Sun.COM * handle: pointer to ddi_acc_handle_t used for HCA FM
11909517SBill.Taylor@Sun.COM * tst: pointer to HCA FM function test structure. If the structure
11919517SBill.Taylor@Sun.COM * is not used, the NULL value must be passed instead.
11929517SBill.Taylor@Sun.COM *
11939517SBill.Taylor@Sun.COM * Return value
11949517SBill.Taylor@Sun.COM * error status showing whether or not this error can retry
11959517SBill.Taylor@Sun.COM * HCA_PIO_OK No HW errors
11969517SBill.Taylor@Sun.COM * HCA_PIO_TRANSIENT This error could be transient
11979517SBill.Taylor@Sun.COM * HCA_PIO_PERSISTENT This error is persistent
11989517SBill.Taylor@Sun.COM *
11999517SBill.Taylor@Sun.COM * Caller's context
12009517SBill.Taylor@Sun.COM * hermon_PIO_start() can be called in user, kernel or interrupt context.
12019517SBill.Taylor@Sun.COM */
12029517SBill.Taylor@Sun.COM int
hermon_PIO_start(hermon_state_t * state,ddi_acc_handle_t handle,hermon_test_t * tst)12039517SBill.Taylor@Sun.COM hermon_PIO_start(hermon_state_t *state, ddi_acc_handle_t handle,
12049517SBill.Taylor@Sun.COM hermon_test_t *tst)
12059517SBill.Taylor@Sun.COM {
12069517SBill.Taylor@Sun.COM if (state->hs_fm_disable) {
12079517SBill.Taylor@Sun.COM return (HCA_PIO_OK);
12089517SBill.Taylor@Sun.COM } else {
12099517SBill.Taylor@Sun.COM struct i_hca_acc_handle *handlep =
12109517SBill.Taylor@Sun.COM i_hca_get_acc_handle(state->hs_fm_hca_fm, handle);
12119517SBill.Taylor@Sun.COM ASSERT(handlep != NULL);
12129517SBill.Taylor@Sun.COM return (i_hca_pio_start(state->hs_dip, handlep, tst));
12139517SBill.Taylor@Sun.COM }
12149517SBill.Taylor@Sun.COM }
12159517SBill.Taylor@Sun.COM
12169517SBill.Taylor@Sun.COM
12179517SBill.Taylor@Sun.COM /*
12189517SBill.Taylor@Sun.COM * int
12199517SBill.Taylor@Sun.COM * hermon_PIO_end(hermon_state_t *state, ddi_acc_handle_t handle, int *cnt,
12209517SBill.Taylor@Sun.COM * hermon_test_t *tst)
12219517SBill.Taylor@Sun.COM *
12229517SBill.Taylor@Sun.COM * Overview
12239517SBill.Taylor@Sun.COM * hermon_PIO_end() should be called after Hermon driver issues PIOs
12249517SBill.Taylor@Sun.COM * against I/O space. If Hermon FM is disabled, this function returns
12259517SBill.Taylor@Sun.COM * HCA_PIO_OK always. See i_hca_pio_end() in detail.
12269517SBill.Taylor@Sun.COM *
12279517SBill.Taylor@Sun.COM * Argument
12289517SBill.Taylor@Sun.COM * state: pointer to Hermon state structure
12299517SBill.Taylor@Sun.COM * handle: pointer to ddi_acc_handle_t used for HCA FM
12309517SBill.Taylor@Sun.COM * cnt: pointer to the counter variable which holds the nubmer of retry
12319517SBill.Taylor@Sun.COM * (HCA_PIO_RETRY_CNT) when a HW error is detected.
12329517SBill.Taylor@Sun.COM * tst: pointer to HCA FM function test structure. If the structure
12339517SBill.Taylor@Sun.COM * is not used, the NULL value must be passed instead.
12349517SBill.Taylor@Sun.COM *
12359517SBill.Taylor@Sun.COM * Return value
12369517SBill.Taylor@Sun.COM * error status showing whether or not this error can retry
12379517SBill.Taylor@Sun.COM * HCA_PIO_OK No HW errors
12389517SBill.Taylor@Sun.COM * HCA_PIO_TRANSIENT This error could be transient
12399517SBill.Taylor@Sun.COM * HCA_PIO_PERSISTENT This error is persistent
12409517SBill.Taylor@Sun.COM *
12419517SBill.Taylor@Sun.COM * Caller's context
12429517SBill.Taylor@Sun.COM * hermon_PIO_end() can be called in user, kernel or interrupt context.
12439517SBill.Taylor@Sun.COM */
12449517SBill.Taylor@Sun.COM int
hermon_PIO_end(hermon_state_t * state,ddi_acc_handle_t handle,int * cnt,hermon_test_t * tst)12459517SBill.Taylor@Sun.COM hermon_PIO_end(hermon_state_t *state, ddi_acc_handle_t handle, int *cnt,
12469517SBill.Taylor@Sun.COM hermon_test_t *tst)
12479517SBill.Taylor@Sun.COM {
12489517SBill.Taylor@Sun.COM if (state->hs_fm_disable) {
12499517SBill.Taylor@Sun.COM return (HCA_PIO_OK);
12509517SBill.Taylor@Sun.COM } else {
12519517SBill.Taylor@Sun.COM struct i_hca_acc_handle *handlep =
12529517SBill.Taylor@Sun.COM i_hca_get_acc_handle(state->hs_fm_hca_fm, handle);
12539517SBill.Taylor@Sun.COM ASSERT(handlep != NULL);
12549517SBill.Taylor@Sun.COM return (i_hca_pio_end(state->hs_dip, handlep, cnt, tst));
12559517SBill.Taylor@Sun.COM }
12569517SBill.Taylor@Sun.COM }
12579517SBill.Taylor@Sun.COM
12589517SBill.Taylor@Sun.COM
12599517SBill.Taylor@Sun.COM /*
12609517SBill.Taylor@Sun.COM * ddi_acc_handle_t
12619517SBill.Taylor@Sun.COM * hermon_get_cmdhdl(hermon_state_t *state)
12629517SBill.Taylor@Sun.COM *
12639517SBill.Taylor@Sun.COM * Overview
12649517SBill.Taylor@Sun.COM * hermon_get_cmdhdl() returns either the fma-protected access handle or
12659517SBill.Taylor@Sun.COM * the regular ddi-access handle depending on the Hermon FM state for
12669517SBill.Taylor@Sun.COM * Hermon command I/O space.
12679517SBill.Taylor@Sun.COM *
12689517SBill.Taylor@Sun.COM * Argument
12699517SBill.Taylor@Sun.COM * state: pointer to Hermon state structure
12709517SBill.Taylor@Sun.COM *
12719517SBill.Taylor@Sun.COM * Return value
12729517SBill.Taylor@Sun.COM * the access handle for pio requests
12739517SBill.Taylor@Sun.COM *
12749517SBill.Taylor@Sun.COM * Caller's context
12759517SBill.Taylor@Sun.COM * hermon_get_cmdhdl() can be called in user, kernel, interrupt context
12769517SBill.Taylor@Sun.COM * or high interrupt context.
12779517SBill.Taylor@Sun.COM */
12789517SBill.Taylor@Sun.COM ddi_acc_handle_t
hermon_get_cmdhdl(hermon_state_t * state)12799517SBill.Taylor@Sun.COM hermon_get_cmdhdl(hermon_state_t *state)
12809517SBill.Taylor@Sun.COM {
12819517SBill.Taylor@Sun.COM return (state->hs_fm_disable || hermon_get_state(state) & HCA_PIO_FM ?
12829517SBill.Taylor@Sun.COM state->hs_fm_cmdhdl : state->hs_reg_cmdhdl);
12839517SBill.Taylor@Sun.COM }
12849517SBill.Taylor@Sun.COM
12859517SBill.Taylor@Sun.COM
12869517SBill.Taylor@Sun.COM /*
12879517SBill.Taylor@Sun.COM * ddi_acc_handle_t
12889517SBill.Taylor@Sun.COM * hermon_get_uarhdl(hermon_state_t *state)
12899517SBill.Taylor@Sun.COM *
12909517SBill.Taylor@Sun.COM * Overview
12919517SBill.Taylor@Sun.COM * hermon_get_uarhdl() returns either the fma-protected access handle or
12929517SBill.Taylor@Sun.COM * the regular ddi-access handle depending on the Hermon FM state for
12939517SBill.Taylor@Sun.COM * Hermon UAR I/O space.
12949517SBill.Taylor@Sun.COM *
12959517SBill.Taylor@Sun.COM * Argument
12969517SBill.Taylor@Sun.COM * state: pointer to Hermon state structure
12979517SBill.Taylor@Sun.COM *
12989517SBill.Taylor@Sun.COM * Return value
12999517SBill.Taylor@Sun.COM * the access handle for pio requests
13009517SBill.Taylor@Sun.COM *
13019517SBill.Taylor@Sun.COM * Caller's context
13029517SBill.Taylor@Sun.COM * hermon_get_uarhdl() can be called in user, kernel, interrupt context
13039517SBill.Taylor@Sun.COM * or high interrupt context.
13049517SBill.Taylor@Sun.COM */
13059517SBill.Taylor@Sun.COM ddi_acc_handle_t
hermon_get_uarhdl(hermon_state_t * state)13069517SBill.Taylor@Sun.COM hermon_get_uarhdl(hermon_state_t *state)
13079517SBill.Taylor@Sun.COM {
13089517SBill.Taylor@Sun.COM return (state->hs_fm_disable || hermon_get_state(state) & HCA_PIO_FM ?
13099517SBill.Taylor@Sun.COM state->hs_fm_uarhdl : state->hs_reg_uarhdl);
13109517SBill.Taylor@Sun.COM }
13119517SBill.Taylor@Sun.COM
13129517SBill.Taylor@Sun.COM
13139517SBill.Taylor@Sun.COM /*
13149517SBill.Taylor@Sun.COM * ddi_acc_handle_t
13159517SBill.Taylor@Sun.COM * hermon_rsrc_alloc_uarhdl(hermon_state_t *state)
13169517SBill.Taylor@Sun.COM *
13179517SBill.Taylor@Sun.COM * Overview
13189517SBill.Taylor@Sun.COM * hermon_rsrc_alloc_uarhdl() returns either the fma-protected access
13199517SBill.Taylor@Sun.COM * handle or the regular ddi-access handle depending on the Hermon FM
13209517SBill.Taylor@Sun.COM * state for Hermon UAR I/O space as well as hermon_get_uarhdl(), but
13219517SBill.Taylor@Sun.COM * this function is dedicated to the UAR resource allocator.
13229517SBill.Taylor@Sun.COM *
13239517SBill.Taylor@Sun.COM * Argument
13249517SBill.Taylor@Sun.COM * state: pointer to Hermon state structure
13259517SBill.Taylor@Sun.COM *
13269517SBill.Taylor@Sun.COM * Return value
13279517SBill.Taylor@Sun.COM * the access handle for pio requests
13289517SBill.Taylor@Sun.COM *
13299517SBill.Taylor@Sun.COM * Caller's context
13309517SBill.Taylor@Sun.COM * hermon_rsrc_alloc_uarhdl() can be called in user, kernel, interrupt
13319517SBill.Taylor@Sun.COM * or high interrupt context.
13329517SBill.Taylor@Sun.COM */
13339517SBill.Taylor@Sun.COM ddi_acc_handle_t
hermon_rsrc_alloc_uarhdl(hermon_state_t * state)13349517SBill.Taylor@Sun.COM hermon_rsrc_alloc_uarhdl(hermon_state_t *state)
13359517SBill.Taylor@Sun.COM {
13369517SBill.Taylor@Sun.COM return (state->hs_fm_disable || hermon_get_state(state) & HCA_ATTCH_FM ?
13379517SBill.Taylor@Sun.COM state->hs_fm_uarhdl : state->hs_reg_uarhdl);
13389517SBill.Taylor@Sun.COM }
13399517SBill.Taylor@Sun.COM
13409517SBill.Taylor@Sun.COM /*
13419517SBill.Taylor@Sun.COM * ddi_acc_handle_t
13429517SBill.Taylor@Sun.COM * hermon_get_pcihdl(hermon_state_t *state)
13439517SBill.Taylor@Sun.COM *
13449517SBill.Taylor@Sun.COM * Overview
13459517SBill.Taylor@Sun.COM * hermon_get_pcihdl() returns either the fma-protected access
13469517SBill.Taylor@Sun.COM * handle or the regular ddi-access handle to access the PCI config
13479517SBill.Taylor@Sun.COM * space. Whether or not which handle is returned at the moment depends
13489517SBill.Taylor@Sun.COM * on the Hermon FM state.
13499517SBill.Taylor@Sun.COM *
13509517SBill.Taylor@Sun.COM * Argument
13519517SBill.Taylor@Sun.COM * state: pointer to Hermon state structure
13529517SBill.Taylor@Sun.COM *
13539517SBill.Taylor@Sun.COM * Return value
13549517SBill.Taylor@Sun.COM * the access handle to PCI config space
13559517SBill.Taylor@Sun.COM *
13569517SBill.Taylor@Sun.COM * Caller's context
13579517SBill.Taylor@Sun.COM * hermon_get_pcihdl() can be called in user, kernel, interrupt
13589517SBill.Taylor@Sun.COM * or high interrupt context.
13599517SBill.Taylor@Sun.COM */
13609517SBill.Taylor@Sun.COM ddi_acc_handle_t
hermon_get_pcihdl(hermon_state_t * state)13619517SBill.Taylor@Sun.COM hermon_get_pcihdl(hermon_state_t *state)
13629517SBill.Taylor@Sun.COM {
13639517SBill.Taylor@Sun.COM return (state->hs_fm_disable || hermon_get_state(state) & HCA_ATTCH_FM ?
13649517SBill.Taylor@Sun.COM state->hs_fm_pcihdl : state->hs_reg_pcihdl);
13659517SBill.Taylor@Sun.COM }
13669517SBill.Taylor@Sun.COM
13679517SBill.Taylor@Sun.COM
13689517SBill.Taylor@Sun.COM /*
13699517SBill.Taylor@Sun.COM * ddi_acc_handle_t
13709517SBill.Taylor@Sun.COM * hermon_get_msix_tblhdl(hermon_state_t *state)
13719517SBill.Taylor@Sun.COM *
13729517SBill.Taylor@Sun.COM * Overview
13739517SBill.Taylor@Sun.COM * hermon_get_msix_tblhdl() returns either the fma-protected access
13749517SBill.Taylor@Sun.COM * handle or the regular ddi-access handle to access the MSI-X tables.
13759517SBill.Taylor@Sun.COM * Whether or not which handle is returned at the moment depends on
13769517SBill.Taylor@Sun.COM * the Hermon FM state.
13779517SBill.Taylor@Sun.COM *
13789517SBill.Taylor@Sun.COM * Argument
13799517SBill.Taylor@Sun.COM * state: pointer to Hermon state structure
13809517SBill.Taylor@Sun.COM *
13819517SBill.Taylor@Sun.COM * Return value
13829517SBill.Taylor@Sun.COM * the access handle to MSI-X tables
13839517SBill.Taylor@Sun.COM *
13849517SBill.Taylor@Sun.COM * Caller's context
13859517SBill.Taylor@Sun.COM * hermon_get_msix_tblhdl() can be called in user, kernel, interrupt
13869517SBill.Taylor@Sun.COM * context or high interrupt context.
13879517SBill.Taylor@Sun.COM */
13889517SBill.Taylor@Sun.COM ddi_acc_handle_t
hermon_get_msix_tblhdl(hermon_state_t * state)13899517SBill.Taylor@Sun.COM hermon_get_msix_tblhdl(hermon_state_t *state)
13909517SBill.Taylor@Sun.COM {
13919517SBill.Taylor@Sun.COM return (state->hs_fm_disable || hermon_get_state(state) & HCA_ATTCH_FM ?
13929517SBill.Taylor@Sun.COM state->hs_fm_msix_tblhdl : state->hs_reg_msix_tblhdl);
13939517SBill.Taylor@Sun.COM }
13949517SBill.Taylor@Sun.COM
13959517SBill.Taylor@Sun.COM
13969517SBill.Taylor@Sun.COM /*
13979517SBill.Taylor@Sun.COM * ddi_acc_handle_t
13989517SBill.Taylor@Sun.COM * hermon_get_msix_pbahdl(hermon_state_t *state)
13999517SBill.Taylor@Sun.COM *
14009517SBill.Taylor@Sun.COM * Overview
14019517SBill.Taylor@Sun.COM * hermon_get_msix_pbahdl() returns either the fma-protected access
14029517SBill.Taylor@Sun.COM * handle or the regular ddi-access handle to access the MSI-X PBA.
14039517SBill.Taylor@Sun.COM * Whether or not which handle is returned at the moment depends on
14049517SBill.Taylor@Sun.COM * the Hermon FM state.
14059517SBill.Taylor@Sun.COM *
14069517SBill.Taylor@Sun.COM * Argument
14079517SBill.Taylor@Sun.COM * state: pointer to Hermon state structure
14089517SBill.Taylor@Sun.COM *
14099517SBill.Taylor@Sun.COM * Return value
14109517SBill.Taylor@Sun.COM * the access handle to MSI-X PBA
14119517SBill.Taylor@Sun.COM *
14129517SBill.Taylor@Sun.COM * Caller's context
14139517SBill.Taylor@Sun.COM * hermon_get_msix_pbahdl() can be called in user, kernel, interrupt
14149517SBill.Taylor@Sun.COM * context or high interrupt context.
14159517SBill.Taylor@Sun.COM */
14169517SBill.Taylor@Sun.COM ddi_acc_handle_t
hermon_get_msix_pbahdl(hermon_state_t * state)14179517SBill.Taylor@Sun.COM hermon_get_msix_pbahdl(hermon_state_t *state)
14189517SBill.Taylor@Sun.COM {
14199517SBill.Taylor@Sun.COM return (state->hs_fm_disable || hermon_get_state(state) & HCA_ATTCH_FM ?
14209517SBill.Taylor@Sun.COM state->hs_fm_msix_pbahdl : state->hs_reg_msix_pbahdl);
14219517SBill.Taylor@Sun.COM }
14229517SBill.Taylor@Sun.COM
14239517SBill.Taylor@Sun.COM
14249517SBill.Taylor@Sun.COM /*
14259517SBill.Taylor@Sun.COM * void
14269517SBill.Taylor@Sun.COM * hermon_inter_err_chk(void *arg)
14279517SBill.Taylor@Sun.COM *
14289517SBill.Taylor@Sun.COM * Overview
14299517SBill.Taylor@Sun.COM * hermon_inter_err_chk() periodically checks the internal error buffer
14309517SBill.Taylor@Sun.COM * to pick up a Hermon asynchronous internal error.
14319517SBill.Taylor@Sun.COM *
14329517SBill.Taylor@Sun.COM * Note that this internal error can be notified if the interrupt is
14339517SBill.Taylor@Sun.COM * registered, but even so there are some cases that an interrupt against
14349517SBill.Taylor@Sun.COM * it cannot be raised so that Hermon RPM recommeds to poll this internal
14359517SBill.Taylor@Sun.COM * error buffer periodically instead. This function is invoked at
14369517SBill.Taylor@Sun.COM * 10ms interval in kernel context though the function itself can be
14379517SBill.Taylor@Sun.COM * called in interrupt context.
14389517SBill.Taylor@Sun.COM *
14399517SBill.Taylor@Sun.COM * Argument
14409517SBill.Taylor@Sun.COM * arg: pointer to Hermon state structure
14419517SBill.Taylor@Sun.COM *
14429517SBill.Taylor@Sun.COM * Return value
14439517SBill.Taylor@Sun.COM * Nothing
14449517SBill.Taylor@Sun.COM *
14459517SBill.Taylor@Sun.COM * Caller's context
14469517SBill.Taylor@Sun.COM * hermon_inter_err_chk() can be called in user, kernel, interrupt
14479517SBill.Taylor@Sun.COM * context or high interrupt context.
14489517SBill.Taylor@Sun.COM *
14499517SBill.Taylor@Sun.COM */
14509517SBill.Taylor@Sun.COM void
hermon_inter_err_chk(void * arg)14519517SBill.Taylor@Sun.COM hermon_inter_err_chk(void *arg)
14529517SBill.Taylor@Sun.COM {
14539517SBill.Taylor@Sun.COM uint32_t word;
14549517SBill.Taylor@Sun.COM ddi_acc_handle_t cmdhdl;
14559517SBill.Taylor@Sun.COM hermon_state_t *state = (hermon_state_t *)arg;
14569517SBill.Taylor@Sun.COM
14579517SBill.Taylor@Sun.COM /* initialize the FMA retry loop */
14589517SBill.Taylor@Sun.COM hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
14599517SBill.Taylor@Sun.COM
14609517SBill.Taylor@Sun.COM #ifdef FMA_TEST
14619517SBill.Taylor@Sun.COM if (hermon_test_num != 0) {
14629517SBill.Taylor@Sun.COM return;
14639517SBill.Taylor@Sun.COM }
14649517SBill.Taylor@Sun.COM #endif
14659517SBill.Taylor@Sun.COM if (state->hs_fm_poll_suspend) {
14669517SBill.Taylor@Sun.COM return;
14679517SBill.Taylor@Sun.COM }
14689517SBill.Taylor@Sun.COM
14699517SBill.Taylor@Sun.COM /* Get the access handle for Hermon CMD I/O space */
14709517SBill.Taylor@Sun.COM cmdhdl = hermon_get_cmdhdl(state);
14719517SBill.Taylor@Sun.COM
14729517SBill.Taylor@Sun.COM /* the FMA retry loop starts. */
14739517SBill.Taylor@Sun.COM hermon_pio_start(state, cmdhdl, pio_error, fm_loop_cnt, fm_status,
14749517SBill.Taylor@Sun.COM fm_test);
14759517SBill.Taylor@Sun.COM
14769517SBill.Taylor@Sun.COM word = ddi_get32(cmdhdl, state->hs_cmd_regs.fw_err_buf);
14779517SBill.Taylor@Sun.COM
14789517SBill.Taylor@Sun.COM /* the FMA retry loop ends. */
14799517SBill.Taylor@Sun.COM hermon_pio_end(state, cmdhdl, pio_error, fm_loop_cnt, fm_status,
14809517SBill.Taylor@Sun.COM fm_test);
14819517SBill.Taylor@Sun.COM
14829517SBill.Taylor@Sun.COM if (word != 0) {
14839517SBill.Taylor@Sun.COM HERMON_FMANOTE(state, HERMON_FMA_INTERNAL);
14849778SEiji.Ota@Sun.COM /* if fm_disable is on, Hermon FM functions don't work */
14859778SEiji.Ota@Sun.COM if (state->hs_fm_disable) {
14869778SEiji.Ota@Sun.COM cmn_err(CE_PANIC,
14879778SEiji.Ota@Sun.COM "Hermon Fatal Internal Error. "
14889778SEiji.Ota@Sun.COM "Hermon state=0x%p", (void *)state);
14899778SEiji.Ota@Sun.COM } else {
14909778SEiji.Ota@Sun.COM hermon_fm_ereport(state, HCA_IBA_ERR, HCA_ERR_FATAL);
14919778SEiji.Ota@Sun.COM }
14929517SBill.Taylor@Sun.COM }
14939517SBill.Taylor@Sun.COM
14949517SBill.Taylor@Sun.COM /* issue the ereport pended in the interrupt context */
14959517SBill.Taylor@Sun.COM if (state->hs_fm_async_errcnt > 0) {
14969517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_IBA_ERR, HCA_ERR_FATAL);
14979517SBill.Taylor@Sun.COM atomic_dec_32(&state->hs_fm_async_errcnt);
14989517SBill.Taylor@Sun.COM }
14999517SBill.Taylor@Sun.COM
15009517SBill.Taylor@Sun.COM return;
15019517SBill.Taylor@Sun.COM
15029517SBill.Taylor@Sun.COM pio_error:
15039517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_FATAL);
15049517SBill.Taylor@Sun.COM }
15059517SBill.Taylor@Sun.COM
15069517SBill.Taylor@Sun.COM
15079517SBill.Taylor@Sun.COM /*
15089517SBill.Taylor@Sun.COM * boolean_t
15099517SBill.Taylor@Sun.COM * hermon_cmd_retry_ok(hermon_cmd_post_t *cmd, int status)
15109517SBill.Taylor@Sun.COM *
15119517SBill.Taylor@Sun.COM * Overview
15129517SBill.Taylor@Sun.COM * In the case that a HW error is detected, if it can be isolated
15139517SBill.Taylor@Sun.COM * enough, Hermon FM retries the operation which caused the error.
15149517SBill.Taylor@Sun.COM * However, this retry can induce another error; since the retry is
15159517SBill.Taylor@Sun.COM * achieved as a block basis, not a statement basis, once the state
15169517SBill.Taylor@Sun.COM * was set inside the Hermon HW already in the previous operation, the
15179517SBill.Taylor@Sun.COM * retry can cause for example, a CMD_BAD_SYS_STATE error, as a result.
15189517SBill.Taylor@Sun.COM * In this case, CMD_BAD_SYS_STATE should be taken as a side effect
15199517SBill.Taylor@Sun.COM * but a harmless result. hermon_cmd_retry_ok() checks this kind of
15209517SBill.Taylor@Sun.COM * situation then returns if the state Hermon CMD returns is OK or not.
15219517SBill.Taylor@Sun.COM *
15229517SBill.Taylor@Sun.COM * Argument
15239517SBill.Taylor@Sun.COM * cmd: pointer to hermon_cmd_post_t structure
15249517SBill.Taylor@Sun.COM * status: Hermon CMD status
15259517SBill.Taylor@Sun.COM *
15269517SBill.Taylor@Sun.COM * Return value
15279517SBill.Taylor@Sun.COM * B_TRUE this state is no problem
15289517SBill.Taylor@Sun.COM * B_FALSE this state should be taken as an error
15299517SBill.Taylor@Sun.COM *
15309517SBill.Taylor@Sun.COM * Caller's context
15319517SBill.Taylor@Sun.COM * hermon_cmd_retry_ok() can be called in user, kernel, interrupt
15329517SBill.Taylor@Sun.COM * context or high interrupt context.
15339517SBill.Taylor@Sun.COM *
15349517SBill.Taylor@Sun.COM * Note that status except for HERMON_CMD_SUCCESS shouldn't be accepted
15359517SBill.Taylor@Sun.COM * in the debug module to catch a hidden software bug, so that ASSERT()
15369517SBill.Taylor@Sun.COM * is enabled in the case.
15379517SBill.Taylor@Sun.COM */
15389517SBill.Taylor@Sun.COM boolean_t
hermon_cmd_retry_ok(hermon_cmd_post_t * cmd,int status)15399517SBill.Taylor@Sun.COM hermon_cmd_retry_ok(hermon_cmd_post_t *cmd, int status)
15409517SBill.Taylor@Sun.COM {
15419517SBill.Taylor@Sun.COM if (status == HERMON_CMD_SUCCESS)
15429517SBill.Taylor@Sun.COM return (B_TRUE);
15439517SBill.Taylor@Sun.COM
15449517SBill.Taylor@Sun.COM /*
15459517SBill.Taylor@Sun.COM * The wrong status such as HERMON_CMD_BAD_SYS_STATE or
15469517SBill.Taylor@Sun.COM * HERMON_CMD_BAD_RES_STATE can return as a side effect
15479517SBill.Taylor@Sun.COM * because of the Hermon FM operation retry when a PIO
15489517SBill.Taylor@Sun.COM * error is detected during the I/O transaction. In the
15499517SBill.Taylor@Sun.COM * case, the driver may set the same value in Hermon
15509517SBill.Taylor@Sun.COM * though it was set already, then Hermon returns HERMON_
15519517SBill.Taylor@Sun.COM * CMD_BAD_{RES,SYS}_STATE as a result, which should be
15529517SBill.Taylor@Sun.COM * taken as OK.
15539517SBill.Taylor@Sun.COM */
15549517SBill.Taylor@Sun.COM switch (cmd->cp_opcode) {
15559517SBill.Taylor@Sun.COM case INIT_HCA:
15569517SBill.Taylor@Sun.COM /*
15579517SBill.Taylor@Sun.COM * HERMON_CMD_BAD_SYS_STATE can be gotten in case of
15589517SBill.Taylor@Sun.COM * ICM not mapped or HCA already initialized.
15599517SBill.Taylor@Sun.COM */
15609517SBill.Taylor@Sun.COM if (status == HERMON_CMD_BAD_SYS_STATE)
15619517SBill.Taylor@Sun.COM return (B_TRUE);
15629517SBill.Taylor@Sun.COM return (B_FALSE);
15639517SBill.Taylor@Sun.COM
15649517SBill.Taylor@Sun.COM case CLOSE_HCA:
15659517SBill.Taylor@Sun.COM /*
15669517SBill.Taylor@Sun.COM * HERMON_CMD_BAD_SYS_STATE can be gotten in case of Firmware
15679517SBill.Taylor@Sun.COM * area is not mapped or HCA already closed.
15689517SBill.Taylor@Sun.COM */
15699517SBill.Taylor@Sun.COM if (status == HERMON_CMD_BAD_SYS_STATE)
15709517SBill.Taylor@Sun.COM return (B_TRUE);
15719517SBill.Taylor@Sun.COM return (B_FALSE);
15729517SBill.Taylor@Sun.COM
15739517SBill.Taylor@Sun.COM case CLOSE_PORT:
15749517SBill.Taylor@Sun.COM /*
15759517SBill.Taylor@Sun.COM * HERMON_CMD_BAD_SYS_STATE can be gotten in case of HCA not
15769517SBill.Taylor@Sun.COM * initialized or in case that IB ports are already down.
15779517SBill.Taylor@Sun.COM */
15789517SBill.Taylor@Sun.COM if (status == HERMON_CMD_BAD_SYS_STATE)
15799517SBill.Taylor@Sun.COM return (B_TRUE);
15809517SBill.Taylor@Sun.COM return (B_FALSE);
15819517SBill.Taylor@Sun.COM
15829517SBill.Taylor@Sun.COM case SW2HW_MPT:
15839517SBill.Taylor@Sun.COM /*
15849517SBill.Taylor@Sun.COM * HERMON_CMD_BAD_RES_STATE can be gotten in case of MPT
15859517SBill.Taylor@Sun.COM * entry already in hardware ownership.
15869517SBill.Taylor@Sun.COM */
15879517SBill.Taylor@Sun.COM if (status == HERMON_CMD_BAD_RES_STATE)
15889517SBill.Taylor@Sun.COM return (B_TRUE);
15899517SBill.Taylor@Sun.COM return (B_FALSE);
15909517SBill.Taylor@Sun.COM
15919517SBill.Taylor@Sun.COM case HW2SW_MPT:
15929517SBill.Taylor@Sun.COM /*
15939517SBill.Taylor@Sun.COM * HERMON_CMD_BAD_RES_STATE can be gotten in case of MPT
15949517SBill.Taylor@Sun.COM * entry already in software ownership.
15959517SBill.Taylor@Sun.COM */
15969517SBill.Taylor@Sun.COM if (status == HERMON_CMD_BAD_RES_STATE)
15979517SBill.Taylor@Sun.COM return (B_TRUE);
15989517SBill.Taylor@Sun.COM return (B_FALSE);
15999517SBill.Taylor@Sun.COM
16009517SBill.Taylor@Sun.COM case SW2HW_EQ:
16019517SBill.Taylor@Sun.COM /*
16029517SBill.Taylor@Sun.COM * HERMON_CMD_BAD_RES_STATE can be gotten in case of EQ
16039517SBill.Taylor@Sun.COM * entry already in hardware ownership.
16049517SBill.Taylor@Sun.COM */
16059517SBill.Taylor@Sun.COM if (status == HERMON_CMD_BAD_RES_STATE)
16069517SBill.Taylor@Sun.COM return (B_TRUE);
16079517SBill.Taylor@Sun.COM return (B_FALSE);
16089517SBill.Taylor@Sun.COM
16099517SBill.Taylor@Sun.COM case HW2SW_EQ:
16109517SBill.Taylor@Sun.COM /*
16119517SBill.Taylor@Sun.COM * HERMON_CMD_BAD_RES_STATE can be gotten in case of EQ
16129517SBill.Taylor@Sun.COM * entry already in software ownership.
16139517SBill.Taylor@Sun.COM */
16149517SBill.Taylor@Sun.COM if (status == HERMON_CMD_BAD_RES_STATE)
16159517SBill.Taylor@Sun.COM return (B_TRUE);
16169517SBill.Taylor@Sun.COM return (B_FALSE);
16179517SBill.Taylor@Sun.COM
16189517SBill.Taylor@Sun.COM case SW2HW_CQ:
16199517SBill.Taylor@Sun.COM /*
16209517SBill.Taylor@Sun.COM * HERMON_CMD_BAD_RES_STATE can be gotten in case of CQ
16219517SBill.Taylor@Sun.COM * entry already in hardware ownership.
16229517SBill.Taylor@Sun.COM */
16239517SBill.Taylor@Sun.COM if (status == HERMON_CMD_BAD_RES_STATE)
16249517SBill.Taylor@Sun.COM return (B_TRUE);
16259517SBill.Taylor@Sun.COM return (B_FALSE);
16269517SBill.Taylor@Sun.COM
16279517SBill.Taylor@Sun.COM case HW2SW_CQ:
16289517SBill.Taylor@Sun.COM /*
16299517SBill.Taylor@Sun.COM * HERMON_CMD_BAD_RES_STATE can be gotten in case of CQ
16309517SBill.Taylor@Sun.COM * entry already in software ownership.
16319517SBill.Taylor@Sun.COM */
16329517SBill.Taylor@Sun.COM if (status == HERMON_CMD_BAD_RES_STATE)
16339517SBill.Taylor@Sun.COM return (B_TRUE);
16349517SBill.Taylor@Sun.COM return (B_FALSE);
16359517SBill.Taylor@Sun.COM
16369517SBill.Taylor@Sun.COM case SW2HW_SRQ:
16379517SBill.Taylor@Sun.COM /*
16389517SBill.Taylor@Sun.COM * HERMON_CMD_BAD_RES_STATE can be gotten in case of SRQ
16399517SBill.Taylor@Sun.COM * entry already in hardware ownership.
16409517SBill.Taylor@Sun.COM */
16419517SBill.Taylor@Sun.COM if (status == HERMON_CMD_BAD_RES_STATE)
16429517SBill.Taylor@Sun.COM return (B_TRUE);
16439517SBill.Taylor@Sun.COM return (B_FALSE);
16449517SBill.Taylor@Sun.COM
16459517SBill.Taylor@Sun.COM case HW2SW_SRQ:
16469517SBill.Taylor@Sun.COM /*
16479517SBill.Taylor@Sun.COM * HERMON_CMD_BAD_RES_STATE can be gotten in case of SRQ
16489517SBill.Taylor@Sun.COM * entry already in software ownership.
16499517SBill.Taylor@Sun.COM */
16509517SBill.Taylor@Sun.COM if (status == HERMON_CMD_BAD_RES_STATE)
16519517SBill.Taylor@Sun.COM return (B_TRUE);
16529517SBill.Taylor@Sun.COM return (B_FALSE);
16539517SBill.Taylor@Sun.COM default:
16549517SBill.Taylor@Sun.COM break;
16559517SBill.Taylor@Sun.COM }
16569517SBill.Taylor@Sun.COM
16579517SBill.Taylor@Sun.COM /* other cases */
16589517SBill.Taylor@Sun.COM return (B_FALSE);
16599517SBill.Taylor@Sun.COM }
16609517SBill.Taylor@Sun.COM
16619517SBill.Taylor@Sun.COM
16629517SBill.Taylor@Sun.COM #ifdef FMA_TEST
16639517SBill.Taylor@Sun.COM
16649517SBill.Taylor@Sun.COM /*
16659517SBill.Taylor@Sun.COM * Hermon FMA test variables
16669517SBill.Taylor@Sun.COM */
16679517SBill.Taylor@Sun.COM #define FMA_TEST_HASHSZ 64
16689517SBill.Taylor@Sun.COM int hermon_test_num; /* predefined testset */
16699517SBill.Taylor@Sun.COM
16709517SBill.Taylor@Sun.COM static struct i_hca_fm_test *i_hca_test_register(char *, int, int,
16719517SBill.Taylor@Sun.COM void (*)(struct i_hca_fm_test *, ddi_fm_error_t *),
16729517SBill.Taylor@Sun.COM void *, mod_hash_t *, mod_hash_t *, int);
16739517SBill.Taylor@Sun.COM static void i_hca_test_free_item(mod_hash_val_t);
16749517SBill.Taylor@Sun.COM static void i_hca_test_set_item(int, struct i_hca_fm_test *);
16759517SBill.Taylor@Sun.COM static void hermon_trigger_pio_error(hermon_test_t *, ddi_fm_error_t *);
16769517SBill.Taylor@Sun.COM
16779517SBill.Taylor@Sun.COM /*
16789517SBill.Taylor@Sun.COM * Hermon FMA Function Test Interface
16799517SBill.Taylor@Sun.COM */
16809517SBill.Taylor@Sun.COM
16819517SBill.Taylor@Sun.COM /* Attach Errors */
16829517SBill.Taylor@Sun.COM
16839517SBill.Taylor@Sun.COM #define ATTACH_TS (HCA_TEST_TRANSIENT | HCA_TEST_ATTACH | HCA_TEST_START)
16849517SBill.Taylor@Sun.COM #define ATTACH_TE (HCA_TEST_TRANSIENT | HCA_TEST_ATTACH | HCA_TEST_END)
16859517SBill.Taylor@Sun.COM
16869517SBill.Taylor@Sun.COM #define ATTACH_PS (HCA_TEST_PERSISTENT | HCA_TEST_ATTACH | HCA_TEST_START)
16879517SBill.Taylor@Sun.COM #define ATTACH_PE (HCA_TEST_PERSISTENT | HCA_TEST_ATTACH | HCA_TEST_END)
16889517SBill.Taylor@Sun.COM
16899517SBill.Taylor@Sun.COM static hermon_test_t testset[] = {
16909517SBill.Taylor@Sun.COM /* Initial Value */
16919517SBill.Taylor@Sun.COM {0, 0, 0, NULL, 0, 0, NULL, NULL, NULL}, /* 0 */
16929517SBill.Taylor@Sun.COM
16939517SBill.Taylor@Sun.COM /* PIO Transient Errors */
16949517SBill.Taylor@Sun.COM {0, HCA_TEST_PIO, ATTACH_TS, NULL, /* attach/transient/start/propagate */
16959517SBill.Taylor@Sun.COM HCA_PIO_RETRY_CNT, 0, NULL, NULL, NULL}, /* 1 */
16969517SBill.Taylor@Sun.COM {0, HCA_TEST_PIO, ATTACH_TE, NULL, /* attach/transient/end/propagate */
16979517SBill.Taylor@Sun.COM HCA_PIO_RETRY_CNT, 0, NULL, NULL, NULL}, /* 2 */
16989517SBill.Taylor@Sun.COM
16999517SBill.Taylor@Sun.COM /* PIO Persistent Errors */
17009517SBill.Taylor@Sun.COM {0, HCA_TEST_PIO, ATTACH_PS, NULL, /* attach/persistent/start/propagate */
17019517SBill.Taylor@Sun.COM 0, 0, NULL, NULL, NULL}, /* 3 */
17029517SBill.Taylor@Sun.COM {0, HCA_TEST_PIO, ATTACH_PE, NULL, /* attach/persistent/end/propagate */
17039517SBill.Taylor@Sun.COM 0, 0, NULL, NULL, NULL}, /* 4 */
17049517SBill.Taylor@Sun.COM
17059517SBill.Taylor@Sun.COM };
17069517SBill.Taylor@Sun.COM
17079517SBill.Taylor@Sun.COM
17089517SBill.Taylor@Sun.COM /*
17099517SBill.Taylor@Sun.COM * void
17109517SBill.Taylor@Sun.COM * hermon_trigger_pio_error(hermon_test_t *tst, ddi_fm_error_t *derr)
17119517SBill.Taylor@Sun.COM *
17129517SBill.Taylor@Sun.COM * Overview
17139517SBill.Taylor@Sun.COM * hermon_trigger_pio_error() is a PIO error injection function
17149517SBill.Taylor@Sun.COM * to cause a pseduo PIO error.
17159517SBill.Taylor@Sun.COM *
17169517SBill.Taylor@Sun.COM * Argument
17179517SBill.Taylor@Sun.COM * tst: pointer to HCA FM function test structure. If the structure
17189517SBill.Taylor@Sun.COM * is not used, the NULL value must be passed instead.
17199517SBill.Taylor@Sun.COM * derr: pointer to ddi_fm_error_t structure
17209517SBill.Taylor@Sun.COM *
17219517SBill.Taylor@Sun.COM * Return value
17229517SBill.Taylor@Sun.COM * Nothing
17239517SBill.Taylor@Sun.COM *
17249517SBill.Taylor@Sun.COM * Caller's context
17259517SBill.Taylor@Sun.COM * hermon_trigger_pio_error() can be called in user, kernel, interrupt
17269517SBill.Taylor@Sun.COM * context or high interrupt context.
17279517SBill.Taylor@Sun.COM */
17289517SBill.Taylor@Sun.COM static void
hermon_trigger_pio_error(hermon_test_t * tst,ddi_fm_error_t * derr)17299517SBill.Taylor@Sun.COM hermon_trigger_pio_error(hermon_test_t *tst, ddi_fm_error_t *derr)
17309517SBill.Taylor@Sun.COM {
17319517SBill.Taylor@Sun.COM hermon_state_t *state = (hermon_state_t *)tst->private;
17329517SBill.Taylor@Sun.COM derr->fme_status = DDI_FM_OK;
17339517SBill.Taylor@Sun.COM
17349517SBill.Taylor@Sun.COM if (tst->type != HCA_TEST_PIO) {
17359517SBill.Taylor@Sun.COM return;
17369517SBill.Taylor@Sun.COM }
17379517SBill.Taylor@Sun.COM
17389517SBill.Taylor@Sun.COM if ((tst->trigger & HCA_TEST_ATTACH &&
17399517SBill.Taylor@Sun.COM i_ddi_node_state(state->hs_dip) < DS_ATTACHED &&
17409517SBill.Taylor@Sun.COM hermon_get_state(state) & HCA_PIO_FM)) {
17419517SBill.Taylor@Sun.COM if (tst->trigger & HCA_TEST_PERSISTENT) {
17429517SBill.Taylor@Sun.COM i_hca_fm_ereport(state->hs_dip, HCA_IBA_ERR,
17439517SBill.Taylor@Sun.COM DDI_FM_DEVICE_INVAL_STATE);
17449517SBill.Taylor@Sun.COM derr->fme_status = DDI_FM_NONFATAL;
17459517SBill.Taylor@Sun.COM return;
17469517SBill.Taylor@Sun.COM } else if (tst->trigger & HCA_TEST_TRANSIENT &&
17479517SBill.Taylor@Sun.COM tst->errcnt) {
17489517SBill.Taylor@Sun.COM i_hca_fm_ereport(state->hs_dip, HCA_IBA_ERR,
17499517SBill.Taylor@Sun.COM DDI_FM_DEVICE_INVAL_STATE);
17509517SBill.Taylor@Sun.COM derr->fme_status = DDI_FM_NONFATAL;
17519517SBill.Taylor@Sun.COM tst->errcnt--;
17529517SBill.Taylor@Sun.COM return;
17539517SBill.Taylor@Sun.COM }
17549517SBill.Taylor@Sun.COM }
17559517SBill.Taylor@Sun.COM }
17569517SBill.Taylor@Sun.COM
17579517SBill.Taylor@Sun.COM
17589517SBill.Taylor@Sun.COM /*
17599517SBill.Taylor@Sun.COM * struct hermon_fm_test *
17609517SBill.Taylor@Sun.COM * hermon_test_register(hermon_state_t *state, char *filename, int linenum,
17619517SBill.Taylor@Sun.COM * int type)
17629517SBill.Taylor@Sun.COM *
17639517SBill.Taylor@Sun.COM * Overview
17649517SBill.Taylor@Sun.COM * hermon_test_register() registers a Hermon FM test item for the
17659517SBill.Taylor@Sun.COM * function test.
17669517SBill.Taylor@Sun.COM *
17679517SBill.Taylor@Sun.COM * Argument
17689517SBill.Taylor@Sun.COM * state: pointer to Hermon state structure
17699517SBill.Taylor@Sun.COM * filename: source file name where the function call is implemented
17709517SBill.Taylor@Sun.COM * This value is usually a __FILE__ pre-defined macro.
17719517SBill.Taylor@Sun.COM * linenum: line number where the function call is described in the
17729517SBill.Taylor@Sun.COM * file specified above.
17739517SBill.Taylor@Sun.COM * This value is usually a __LINE__ pre-defined macro.
17749517SBill.Taylor@Sun.COM * type: HW error type
17759517SBill.Taylor@Sun.COM * HCA_TEST_PIO pio error
17769517SBill.Taylor@Sun.COM * HCA_TEST_IBA ib specific error
17779517SBill.Taylor@Sun.COM *
17789517SBill.Taylor@Sun.COM * Return value
17799517SBill.Taylor@Sun.COM * pointer to Hermon FM function test structure registered.
17809517SBill.Taylor@Sun.COM *
17819517SBill.Taylor@Sun.COM * Caller's context
17829517SBill.Taylor@Sun.COM * hermon_test_register() can be called in user, kernel or interrupt
17839517SBill.Taylor@Sun.COM * context.
17849517SBill.Taylor@Sun.COM *
17859517SBill.Taylor@Sun.COM * Note that no test item is registered if Hermon FM is disabled.
17869517SBill.Taylor@Sun.COM */
17879517SBill.Taylor@Sun.COM hermon_test_t *
hermon_test_register(hermon_state_t * state,char * filename,int linenum,int type)17889517SBill.Taylor@Sun.COM hermon_test_register(hermon_state_t *state, char *filename, int linenum,
17899517SBill.Taylor@Sun.COM int type)
17909517SBill.Taylor@Sun.COM {
17919517SBill.Taylor@Sun.COM void (*pio_injection)(struct i_hca_fm_test *, ddi_fm_error_t *) =
17929517SBill.Taylor@Sun.COM (void (*)(struct i_hca_fm_test *, ddi_fm_error_t *))
17939517SBill.Taylor@Sun.COM hermon_trigger_pio_error;
17949517SBill.Taylor@Sun.COM
17959517SBill.Taylor@Sun.COM if (state->hs_fm_disable)
17969517SBill.Taylor@Sun.COM return (NULL);
17979517SBill.Taylor@Sun.COM
17989517SBill.Taylor@Sun.COM return ((hermon_test_t *)i_hca_test_register(filename, linenum, type,
17999517SBill.Taylor@Sun.COM pio_injection, (void *)state, state->hs_fm_test_hash,
18009517SBill.Taylor@Sun.COM state->hs_fm_id_hash, hermon_test_num));
18019517SBill.Taylor@Sun.COM }
18029517SBill.Taylor@Sun.COM #endif /* FMA_TEST */
18039517SBill.Taylor@Sun.COM
18049517SBill.Taylor@Sun.COM
18059517SBill.Taylor@Sun.COM /*
18069517SBill.Taylor@Sun.COM * HCA FM Common Interface
18079517SBill.Taylor@Sun.COM *
18089517SBill.Taylor@Sun.COM * These functions should be used for any HCA drivers, but probably
18099517SBill.Taylor@Sun.COM * customized for their own HW design and/or FM implementation.
18109517SBill.Taylor@Sun.COM * Customized functins should have the driver name prefix such as
18119517SBill.Taylor@Sun.COM * hermon_xxxx() and be defined separately but whose functions should
18129517SBill.Taylor@Sun.COM * call the common interface inside.
18139517SBill.Taylor@Sun.COM */
18149517SBill.Taylor@Sun.COM
18159517SBill.Taylor@Sun.COM /*
18169517SBill.Taylor@Sun.COM * void
18179517SBill.Taylor@Sun.COM * i_hca_fm_init(struct i_hca_fm *hca_fm)
18189517SBill.Taylor@Sun.COM *
18199517SBill.Taylor@Sun.COM * Overview
18209517SBill.Taylor@Sun.COM * i_hca_fm_init() is an initialization function which sets up the acc
18219517SBill.Taylor@Sun.COM * handle kmem_cache if this function is called the first time.
18229517SBill.Taylor@Sun.COM *
18239517SBill.Taylor@Sun.COM * Argument
18249517SBill.Taylor@Sun.COM * hca_fm: pointer to HCA FM structure
18259517SBill.Taylor@Sun.COM *
18269517SBill.Taylor@Sun.COM * Return value
18279517SBill.Taylor@Sun.COM * Nothing
18289517SBill.Taylor@Sun.COM *
18299517SBill.Taylor@Sun.COM * Caller's context
18309517SBill.Taylor@Sun.COM * i_hca_fm_init() can be called in user or kernel context, but cannot
18319517SBill.Taylor@Sun.COM * be called in interrupt context.
18329517SBill.Taylor@Sun.COM */
18339517SBill.Taylor@Sun.COM static void
i_hca_fm_init(struct i_hca_fm * hca_fm)18349517SBill.Taylor@Sun.COM i_hca_fm_init(struct i_hca_fm *hca_fm)
18359517SBill.Taylor@Sun.COM {
18369517SBill.Taylor@Sun.COM
18379517SBill.Taylor@Sun.COM mutex_enter(&hca_fm->lock);
18389517SBill.Taylor@Sun.COM
18399517SBill.Taylor@Sun.COM ++hca_fm->ref_cnt;
18409517SBill.Taylor@Sun.COM if (hca_fm->fm_acc_cache == NULL) {
18419517SBill.Taylor@Sun.COM hca_fm->fm_acc_cache = kmem_cache_create("hca_fm_acc_handle",
18429517SBill.Taylor@Sun.COM sizeof (struct i_hca_acc_handle), 0, NULL,
18439517SBill.Taylor@Sun.COM NULL, NULL, NULL, NULL, 0);
18449517SBill.Taylor@Sun.COM }
18459517SBill.Taylor@Sun.COM
18469517SBill.Taylor@Sun.COM mutex_exit(&hca_fm->lock);
18479517SBill.Taylor@Sun.COM }
18489517SBill.Taylor@Sun.COM
18499517SBill.Taylor@Sun.COM
18509517SBill.Taylor@Sun.COM /*
18519517SBill.Taylor@Sun.COM * void
18529517SBill.Taylor@Sun.COM * i_hca_fm_fini(struct i_hca_fm *hca_fm)
18539517SBill.Taylor@Sun.COM *
18549517SBill.Taylor@Sun.COM * Overview
18559517SBill.Taylor@Sun.COM * i_hca_fm_fini() is a finalization function which frees up the acc
18569517SBill.Taylor@Sun.COM * handle kmem_cache if this function is called the last time.
18579517SBill.Taylor@Sun.COM *
18589517SBill.Taylor@Sun.COM * Argument
18599517SBill.Taylor@Sun.COM * hca_fm: pointer to HCA FM structure
18609517SBill.Taylor@Sun.COM *
18619517SBill.Taylor@Sun.COM * Return value
18629517SBill.Taylor@Sun.COM * Nothing
18639517SBill.Taylor@Sun.COM *
18649517SBill.Taylor@Sun.COM * Caller's context
18659517SBill.Taylor@Sun.COM * i_hca_fm_fini() can be called in user or kernel context, but cannot
18669517SBill.Taylor@Sun.COM * be called in interrupt context.
18679517SBill.Taylor@Sun.COM */
18689517SBill.Taylor@Sun.COM static void
i_hca_fm_fini(struct i_hca_fm * hca_fm)18699517SBill.Taylor@Sun.COM i_hca_fm_fini(struct i_hca_fm *hca_fm)
18709517SBill.Taylor@Sun.COM {
18719517SBill.Taylor@Sun.COM mutex_enter(&hca_fm->lock);
18729517SBill.Taylor@Sun.COM
18739517SBill.Taylor@Sun.COM if (--hca_fm->ref_cnt == 0) {
18749517SBill.Taylor@Sun.COM
18759517SBill.Taylor@Sun.COM if (hca_fm->fm_acc_cache) {
18769517SBill.Taylor@Sun.COM kmem_cache_destroy(hca_fm->fm_acc_cache);
18779517SBill.Taylor@Sun.COM hca_fm->fm_acc_cache = NULL;
18789517SBill.Taylor@Sun.COM }
18799517SBill.Taylor@Sun.COM }
18809517SBill.Taylor@Sun.COM
18819517SBill.Taylor@Sun.COM mutex_exit(&hca_fm->lock);
18829517SBill.Taylor@Sun.COM }
18839517SBill.Taylor@Sun.COM
18849517SBill.Taylor@Sun.COM
18859517SBill.Taylor@Sun.COM /*
18869517SBill.Taylor@Sun.COM * void
18879517SBill.Taylor@Sun.COM * i_hca_fm_ereport(dev_info_t *dip, int type, char *detail)
18889517SBill.Taylor@Sun.COM *
18899517SBill.Taylor@Sun.COM * Overview
18909517SBill.Taylor@Sun.COM * i_hca_fm_ereport() is a wrapper function of ddi_fm_ereport_post() but
18919517SBill.Taylor@Sun.COM * generates an ena before it calls ddi_fm_ereport_post() for HCA
18929517SBill.Taylor@Sun.COM * specific HW errors.
18939517SBill.Taylor@Sun.COM *
18949517SBill.Taylor@Sun.COM * Argument
18959517SBill.Taylor@Sun.COM * dip: pointer to this device dev_info structure
18969517SBill.Taylor@Sun.COM * type: error type
18979517SBill.Taylor@Sun.COM * HCA_SYS_ERR FMA reporting HW error
18989517SBill.Taylor@Sun.COM * HCA_IBA_ERR HCA specific HW error
18999517SBill.Taylor@Sun.COM * detail: definition of leaf driver detected ereports which is one of:
19009517SBill.Taylor@Sun.COM * DDI_FM_DEVICE_INVAL_STATE
19019517SBill.Taylor@Sun.COM * DDI_FM_DEVICE_NO_RESPONSE
19029517SBill.Taylor@Sun.COM * DDI_FM_DEVICE_STALL
19039517SBill.Taylor@Sun.COM * DDI_FM_DEVICE_BADINT_LIMIT
19049517SBill.Taylor@Sun.COM * DDI_FM_DEVICE_INTERN_CORR
19059517SBill.Taylor@Sun.COM * DDI_FM_DEVICE_INTERN_UNCORR
19069517SBill.Taylor@Sun.COM *
19079517SBill.Taylor@Sun.COM * Return value
19089517SBill.Taylor@Sun.COM * Nothing
19099517SBill.Taylor@Sun.COM *
19109517SBill.Taylor@Sun.COM * Caller's context
19119517SBill.Taylor@Sun.COM * i_hca_fm_ereport() can be called in user, kernel or interrupt context.
19129517SBill.Taylor@Sun.COM */
19139517SBill.Taylor@Sun.COM static void
i_hca_fm_ereport(dev_info_t * dip,int type,char * detail)19149517SBill.Taylor@Sun.COM i_hca_fm_ereport(dev_info_t *dip, int type, char *detail)
19159517SBill.Taylor@Sun.COM {
19169517SBill.Taylor@Sun.COM uint64_t ena;
19179517SBill.Taylor@Sun.COM char buf[FM_MAX_CLASS];
19189517SBill.Taylor@Sun.COM
19199517SBill.Taylor@Sun.COM (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail);
19209517SBill.Taylor@Sun.COM
19219517SBill.Taylor@Sun.COM ena = fm_ena_generate(0, FM_ENA_FMT1);
19229517SBill.Taylor@Sun.COM if (type == HCA_IBA_ERR) {
19239517SBill.Taylor@Sun.COM /* this is an error of its own */
19249517SBill.Taylor@Sun.COM ena = fm_ena_increment(ena);
19259517SBill.Taylor@Sun.COM }
19269517SBill.Taylor@Sun.COM
19279517SBill.Taylor@Sun.COM ddi_fm_ereport_post(dip, buf, ena, DDI_NOSLEEP,
19289517SBill.Taylor@Sun.COM FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0, NULL);
19299517SBill.Taylor@Sun.COM }
19309517SBill.Taylor@Sun.COM
19319517SBill.Taylor@Sun.COM
19329517SBill.Taylor@Sun.COM /*
19339517SBill.Taylor@Sun.COM * struct i_hca_acc_handle *
19349517SBill.Taylor@Sun.COM * i_hca_get_acc_handle(struct i_hca_fm *hca_fm, ddi_acc_handle_t handle)
19359517SBill.Taylor@Sun.COM *
19369517SBill.Taylor@Sun.COM * Overview
19379517SBill.Taylor@Sun.COM * i_hca_get_acc_handle() returns ddi_acc_handle_t used for HCA FM.
19389517SBill.Taylor@Sun.COM *
19399517SBill.Taylor@Sun.COM * Argument
19409517SBill.Taylor@Sun.COM * hca_fm: pointer to HCA FM structure
19419517SBill.Taylor@Sun.COM * handle: ddi_acc_handle_t
19429517SBill.Taylor@Sun.COM *
19439517SBill.Taylor@Sun.COM * Return value
19449517SBill.Taylor@Sun.COM * handle: pointer to ddi_acc_handle_t used for HCA FM
19459517SBill.Taylor@Sun.COM *
19469517SBill.Taylor@Sun.COM * Caller's context
19479517SBill.Taylor@Sun.COM * i_hca_get_acc_handle() can be called in user, kernel or interrupt
19489517SBill.Taylor@Sun.COM * context.
19499517SBill.Taylor@Sun.COM */
19509517SBill.Taylor@Sun.COM static struct i_hca_acc_handle *
i_hca_get_acc_handle(struct i_hca_fm * hca_fm,ddi_acc_handle_t handle)19519517SBill.Taylor@Sun.COM i_hca_get_acc_handle(struct i_hca_fm *hca_fm, ddi_acc_handle_t handle)
19529517SBill.Taylor@Sun.COM {
19539517SBill.Taylor@Sun.COM struct i_hca_acc_handle *hdlp;
19549517SBill.Taylor@Sun.COM
19559517SBill.Taylor@Sun.COM /* Retrieve the HCA FM access handle */
19569517SBill.Taylor@Sun.COM mutex_enter(&hca_fm->lock);
19579517SBill.Taylor@Sun.COM
19589517SBill.Taylor@Sun.COM for (hdlp = hca_fm->hdl; hdlp != NULL; hdlp = hdlp->next) {
19599517SBill.Taylor@Sun.COM if (hdlp->save_hdl == handle) {
19609517SBill.Taylor@Sun.COM mutex_exit(&hca_fm->lock);
19619517SBill.Taylor@Sun.COM return (hdlp);
19629517SBill.Taylor@Sun.COM }
19639517SBill.Taylor@Sun.COM }
19649517SBill.Taylor@Sun.COM
19659517SBill.Taylor@Sun.COM mutex_exit(&hca_fm->lock);
19669517SBill.Taylor@Sun.COM return (hdlp);
19679517SBill.Taylor@Sun.COM }
19689517SBill.Taylor@Sun.COM
19699517SBill.Taylor@Sun.COM
19709517SBill.Taylor@Sun.COM /*
19719517SBill.Taylor@Sun.COM * int
19729517SBill.Taylor@Sun.COM * i_hca_regs_map_setup(struct i_hca_fm *hca_fm, dev_info_t *dip,
19739517SBill.Taylor@Sun.COM * uint_t rnumber, caddr_t *addrp, offset_t offset, offset_t len,
19749517SBill.Taylor@Sun.COM * ddi_device_acc_attr_t *accattrp, ddi_acc_handle_t *handle)
19759517SBill.Taylor@Sun.COM *
19769517SBill.Taylor@Sun.COM * Overview
19779517SBill.Taylor@Sun.COM * i_hca_regs_map_setup() is a wrapper function of ddi_regs_map_setup(),
19789517SBill.Taylor@Sun.COM * but allocates the HCA FM acc handle structure and initializes it.
19799517SBill.Taylor@Sun.COM *
19809517SBill.Taylor@Sun.COM * Argument
19819517SBill.Taylor@Sun.COM * hca_fm: pointer to HCA FM structure
19829517SBill.Taylor@Sun.COM * dip: pointer to this device dev_info structure
19839517SBill.Taylor@Sun.COM * rnumber: index number to the register address space set
19849517SBill.Taylor@Sun.COM * addrp: platform-dependent value (same as ddi_regs_map_setup())
19859517SBill.Taylor@Sun.COM * offset: offset into the register address space
19869517SBill.Taylor@Sun.COM * len: address space length to be mapped
19879517SBill.Taylor@Sun.COM * accattrp: pointer to device access attribute structure
19889517SBill.Taylor@Sun.COM * handle: pointer to ddi_acc_handle_t used for HCA FM
19899517SBill.Taylor@Sun.COM *
19909517SBill.Taylor@Sun.COM * Return value
19919517SBill.Taylor@Sun.COM * ddi function status value which are:
19929517SBill.Taylor@Sun.COM * DDI_SUCCESS
19939517SBill.Taylor@Sun.COM * DDI_FAILURE
19949517SBill.Taylor@Sun.COM * DDI_ME_RNUMBER_RNGE
19959517SBill.Taylor@Sun.COM * DDI_REGS_ACC_CONFLICT
19969517SBill.Taylor@Sun.COM *
19979517SBill.Taylor@Sun.COM * Caller's context
19989517SBill.Taylor@Sun.COM * i_hca_regs_map_setup() can be called in user or kernel context only.
19999517SBill.Taylor@Sun.COM */
20009517SBill.Taylor@Sun.COM static int
i_hca_regs_map_setup(struct i_hca_fm * hca_fm,dev_info_t * dip,uint_t rnumber,caddr_t * addrp,offset_t offset,offset_t len,ddi_device_acc_attr_t * accattrp,ddi_acc_handle_t * handle)20019517SBill.Taylor@Sun.COM i_hca_regs_map_setup(struct i_hca_fm *hca_fm, dev_info_t *dip, uint_t rnumber,
20029517SBill.Taylor@Sun.COM caddr_t *addrp, offset_t offset, offset_t len,
20039517SBill.Taylor@Sun.COM ddi_device_acc_attr_t *accattrp, ddi_acc_handle_t *handle)
20049517SBill.Taylor@Sun.COM {
20059517SBill.Taylor@Sun.COM int status;
20069517SBill.Taylor@Sun.COM struct i_hca_acc_handle *handlep, *hdlp, *last;
20079517SBill.Taylor@Sun.COM
20089517SBill.Taylor@Sun.COM /* Allocate an access handle */
20099517SBill.Taylor@Sun.COM if ((status = ddi_regs_map_setup(dip, rnumber, addrp, offset,
20109517SBill.Taylor@Sun.COM len, accattrp, handle)) != DDI_SUCCESS) {
20119517SBill.Taylor@Sun.COM return (status);
20129517SBill.Taylor@Sun.COM }
20139517SBill.Taylor@Sun.COM
20149517SBill.Taylor@Sun.COM /* Allocate HCA FM acc handle structure */
20159517SBill.Taylor@Sun.COM handlep = kmem_cache_alloc(hca_fm->fm_acc_cache, KM_SLEEP);
20169517SBill.Taylor@Sun.COM
20179517SBill.Taylor@Sun.COM /* Initialize fields */
20189517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*handlep))
20199517SBill.Taylor@Sun.COM handlep->next = NULL;
20209517SBill.Taylor@Sun.COM handlep->save_hdl = (*handle);
20219517SBill.Taylor@Sun.COM handlep->thread_cnt = 0;
20229517SBill.Taylor@Sun.COM mutex_init(&handlep->lock, NULL, MUTEX_DRIVER, NULL);
20239517SBill.Taylor@Sun.COM
20249517SBill.Taylor@Sun.COM /* Register this handle */
20259517SBill.Taylor@Sun.COM mutex_enter(&hca_fm->lock);
20269517SBill.Taylor@Sun.COM for (last = hdlp = hca_fm->hdl; hdlp != NULL; hdlp = hdlp->next) {
20279517SBill.Taylor@Sun.COM last = hdlp;
20289517SBill.Taylor@Sun.COM }
20299517SBill.Taylor@Sun.COM if (last == NULL) {
20309517SBill.Taylor@Sun.COM hca_fm->hdl = handlep;
20319517SBill.Taylor@Sun.COM } else {
20329517SBill.Taylor@Sun.COM last->next = handlep;
20339517SBill.Taylor@Sun.COM }
20349517SBill.Taylor@Sun.COM mutex_exit(&hca_fm->lock);
20359517SBill.Taylor@Sun.COM
20369517SBill.Taylor@Sun.COM return (status);
20379517SBill.Taylor@Sun.COM }
20389517SBill.Taylor@Sun.COM
20399517SBill.Taylor@Sun.COM
20409517SBill.Taylor@Sun.COM /*
20419517SBill.Taylor@Sun.COM * void
20429517SBill.Taylor@Sun.COM * i_hca_regs_map_free(struct i_hca_fm *hca_fm, ddi_acc_handle_t *handlep)
20439517SBill.Taylor@Sun.COM *
20449517SBill.Taylor@Sun.COM * Overview
20459517SBill.Taylor@Sun.COM * i_hca_regs_map_setup() is a wrapper function of ddi_regs_map_free(),
20469517SBill.Taylor@Sun.COM * and frees the HCA FM acc handle structure allocated by
20479517SBill.Taylor@Sun.COM * i_hca_regs_map_setup().
20489517SBill.Taylor@Sun.COM *
20499517SBill.Taylor@Sun.COM * Argument
20509517SBill.Taylor@Sun.COM * hca_fm: pointer to HCA FM structure
20519517SBill.Taylor@Sun.COM * handle: pointer to ddi_acc_handle_t used for HCA FM
20529517SBill.Taylor@Sun.COM *
20539517SBill.Taylor@Sun.COM * Return value
20549517SBill.Taylor@Sun.COM * Nothing
20559517SBill.Taylor@Sun.COM *
20569517SBill.Taylor@Sun.COM * Caller's context
20579517SBill.Taylor@Sun.COM * i_hca_regs_map_free() can be called in user or kernel context only.
20589517SBill.Taylor@Sun.COM *
20599517SBill.Taylor@Sun.COM * Note that the handle passed to i_hca_regs_map_free() is NULL-cleared
20609517SBill.Taylor@Sun.COM * after this function is called.
20619517SBill.Taylor@Sun.COM */
20629517SBill.Taylor@Sun.COM static void
i_hca_regs_map_free(struct i_hca_fm * hca_fm,ddi_acc_handle_t * handle)20639517SBill.Taylor@Sun.COM i_hca_regs_map_free(struct i_hca_fm *hca_fm, ddi_acc_handle_t *handle)
20649517SBill.Taylor@Sun.COM {
20659517SBill.Taylor@Sun.COM struct i_hca_acc_handle *handlep, *hdlp, *prev;
20669517SBill.Taylor@Sun.COM
20679517SBill.Taylor@Sun.COM /* De-register this handle */
20689517SBill.Taylor@Sun.COM mutex_enter(&hca_fm->lock);
20699517SBill.Taylor@Sun.COM for (prev = hdlp = hca_fm->hdl; hdlp != NULL; hdlp = hdlp->next) {
20709517SBill.Taylor@Sun.COM if (hdlp->save_hdl == *handle)
20719517SBill.Taylor@Sun.COM break;
20729517SBill.Taylor@Sun.COM prev = hdlp;
20739517SBill.Taylor@Sun.COM }
20749517SBill.Taylor@Sun.COM ASSERT(prev != NULL && hdlp != NULL);
20759517SBill.Taylor@Sun.COM if (hdlp != prev) {
20769517SBill.Taylor@Sun.COM prev->next = hdlp->next;
20779517SBill.Taylor@Sun.COM } else {
20789517SBill.Taylor@Sun.COM hca_fm->hdl = hdlp->next;
20799517SBill.Taylor@Sun.COM }
20809517SBill.Taylor@Sun.COM handlep = hdlp;
20819517SBill.Taylor@Sun.COM mutex_exit(&hca_fm->lock);
20829517SBill.Taylor@Sun.COM
20839517SBill.Taylor@Sun.COM mutex_destroy(&handlep->lock);
20849517SBill.Taylor@Sun.COM handlep->save_hdl = NULL;
20859517SBill.Taylor@Sun.COM kmem_cache_free(hca_fm->fm_acc_cache, handlep);
20869517SBill.Taylor@Sun.COM
20879517SBill.Taylor@Sun.COM /* Release this handle */
20889517SBill.Taylor@Sun.COM ddi_regs_map_free(handle);
20899517SBill.Taylor@Sun.COM *handle = NULL;
20909517SBill.Taylor@Sun.COM }
20919517SBill.Taylor@Sun.COM
20929517SBill.Taylor@Sun.COM
20939517SBill.Taylor@Sun.COM /*
20949517SBill.Taylor@Sun.COM * int
20959517SBill.Taylor@Sun.COM * i_hca_pci_config_setup(struct i_hca_fm *hca_fm, dev_info_t *dip,
20969517SBill.Taylor@Sun.COM * ddi_acc_handle_t *handle, boolean_t fm_protect)
20979517SBill.Taylor@Sun.COM *
20989517SBill.Taylor@Sun.COM * Overview
20999517SBill.Taylor@Sun.COM * i_hca_pci_config_setup() is a wrapper function of pci_config_setup(),
21009517SBill.Taylor@Sun.COM * but allocates the HCA FM acc handle structure and initializes it.
21019517SBill.Taylor@Sun.COM *
21029517SBill.Taylor@Sun.COM * Argument
21039517SBill.Taylor@Sun.COM * hca_fm: pointer to HCA FM structure
21049517SBill.Taylor@Sun.COM * dip: pointer to this device dev_info structure
21059517SBill.Taylor@Sun.COM * handle: pointer to ddi_acc_handle_t used for HCA PCI config space
21069517SBill.Taylor@Sun.COM * with FMA
21079517SBill.Taylor@Sun.COM * fm_protect: flag to tell if an fma-protected access handle should
21089517SBill.Taylor@Sun.COM * be used
21099517SBill.Taylor@Sun.COM *
21109517SBill.Taylor@Sun.COM * Return value
21119517SBill.Taylor@Sun.COM * ddi function status value which are:
21129517SBill.Taylor@Sun.COM * DDI_SUCCESS
21139517SBill.Taylor@Sun.COM * DDI_FAILURE
21149517SBill.Taylor@Sun.COM *
21159517SBill.Taylor@Sun.COM * Caller's context
21169517SBill.Taylor@Sun.COM * i_hca_pci_config_setup() can be called in user or kernel context only.
21179517SBill.Taylor@Sun.COM */
21189517SBill.Taylor@Sun.COM static int
i_hca_pci_config_setup(struct i_hca_fm * hca_fm,dev_info_t * dip,ddi_acc_handle_t * handle)21199517SBill.Taylor@Sun.COM i_hca_pci_config_setup(struct i_hca_fm *hca_fm, dev_info_t *dip,
21209517SBill.Taylor@Sun.COM ddi_acc_handle_t *handle)
21219517SBill.Taylor@Sun.COM {
21229517SBill.Taylor@Sun.COM int status;
21239517SBill.Taylor@Sun.COM struct i_hca_acc_handle *handlep, *hdlp, *last;
21249517SBill.Taylor@Sun.COM
21259517SBill.Taylor@Sun.COM /* Allocate an access handle */
21269517SBill.Taylor@Sun.COM if ((status = pci_config_setup(dip, handle)) != DDI_SUCCESS) {
21279517SBill.Taylor@Sun.COM return (status);
21289517SBill.Taylor@Sun.COM }
21299517SBill.Taylor@Sun.COM
21309517SBill.Taylor@Sun.COM /* Allocate HCA FM acc handle structure */
21319517SBill.Taylor@Sun.COM handlep = kmem_cache_alloc(hca_fm->fm_acc_cache, KM_SLEEP);
21329517SBill.Taylor@Sun.COM
21339517SBill.Taylor@Sun.COM /* Initialize fields */
21349517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*handlep))
21359517SBill.Taylor@Sun.COM handlep->next = NULL;
21369517SBill.Taylor@Sun.COM handlep->save_hdl = (*handle);
21379517SBill.Taylor@Sun.COM handlep->thread_cnt = 0;
21389517SBill.Taylor@Sun.COM mutex_init(&handlep->lock, NULL, MUTEX_DRIVER, NULL);
21399517SBill.Taylor@Sun.COM
21409517SBill.Taylor@Sun.COM /* Register this handle */
21419517SBill.Taylor@Sun.COM mutex_enter(&hca_fm->lock);
21429517SBill.Taylor@Sun.COM for (last = hdlp = hca_fm->hdl; hdlp != NULL; hdlp = hdlp->next) {
21439517SBill.Taylor@Sun.COM last = hdlp;
21449517SBill.Taylor@Sun.COM }
21459517SBill.Taylor@Sun.COM if (last == NULL) {
21469517SBill.Taylor@Sun.COM hca_fm->hdl = handlep;
21479517SBill.Taylor@Sun.COM } else {
21489517SBill.Taylor@Sun.COM last->next = handlep;
21499517SBill.Taylor@Sun.COM }
21509517SBill.Taylor@Sun.COM mutex_exit(&hca_fm->lock);
21519517SBill.Taylor@Sun.COM
21529517SBill.Taylor@Sun.COM return (status);
21539517SBill.Taylor@Sun.COM }
21549517SBill.Taylor@Sun.COM
21559517SBill.Taylor@Sun.COM
21569517SBill.Taylor@Sun.COM /*
21579517SBill.Taylor@Sun.COM * void
21589517SBill.Taylor@Sun.COM * i_hca_pci_config_teardown(struct i_hca_fm *hca_fm,
21599517SBill.Taylor@Sun.COM * ddi_acc_handle_t *handlep)
21609517SBill.Taylor@Sun.COM *
21619517SBill.Taylor@Sun.COM * Overview
21629517SBill.Taylor@Sun.COM * i_hca_pci_config_teardown() is a wrapper function of
21639517SBill.Taylor@Sun.COM * pci_config_teardown(), and frees the HCA FM acc handle structure
21649517SBill.Taylor@Sun.COM * allocated by i_hca_pci_config_setup().
21659517SBill.Taylor@Sun.COM *
21669517SBill.Taylor@Sun.COM * Argument
21679517SBill.Taylor@Sun.COM * hca_fm: pointer to HCA FM structure
21689517SBill.Taylor@Sun.COM * handle: pointer to ddi_acc_handle_t used for HCA FM
21699517SBill.Taylor@Sun.COM *
21709517SBill.Taylor@Sun.COM * Return value
21719517SBill.Taylor@Sun.COM * Nothing
21729517SBill.Taylor@Sun.COM *
21739517SBill.Taylor@Sun.COM * Caller's context
21749517SBill.Taylor@Sun.COM * i_hca_pci_config_teardown() can be called in user or kernel context
21759517SBill.Taylor@Sun.COM * only.
21769517SBill.Taylor@Sun.COM *
21779517SBill.Taylor@Sun.COM * Note that the handle passed to i_hca_pci_config_teardown() is NULL-cleared
21789517SBill.Taylor@Sun.COM * after this function is called.
21799517SBill.Taylor@Sun.COM */
21809517SBill.Taylor@Sun.COM static void
i_hca_pci_config_teardown(struct i_hca_fm * hca_fm,ddi_acc_handle_t * handle)21819517SBill.Taylor@Sun.COM i_hca_pci_config_teardown(struct i_hca_fm *hca_fm, ddi_acc_handle_t *handle)
21829517SBill.Taylor@Sun.COM {
21839517SBill.Taylor@Sun.COM struct i_hca_acc_handle *handlep, *hdlp, *prev;
21849517SBill.Taylor@Sun.COM
21859517SBill.Taylor@Sun.COM /* De-register this handle */
21869517SBill.Taylor@Sun.COM mutex_enter(&hca_fm->lock);
21879517SBill.Taylor@Sun.COM for (prev = hdlp = hca_fm->hdl; hdlp != NULL; hdlp = hdlp->next) {
21889517SBill.Taylor@Sun.COM if (hdlp->save_hdl == *handle)
21899517SBill.Taylor@Sun.COM break;
21909517SBill.Taylor@Sun.COM prev = hdlp;
21919517SBill.Taylor@Sun.COM }
21929517SBill.Taylor@Sun.COM ASSERT(prev != NULL && hdlp != NULL);
21939517SBill.Taylor@Sun.COM if (hdlp != prev) {
21949517SBill.Taylor@Sun.COM prev->next = hdlp->next;
21959517SBill.Taylor@Sun.COM } else {
21969517SBill.Taylor@Sun.COM hca_fm->hdl = hdlp->next;
21979517SBill.Taylor@Sun.COM }
21989517SBill.Taylor@Sun.COM handlep = hdlp;
21999517SBill.Taylor@Sun.COM mutex_exit(&hca_fm->lock);
22009517SBill.Taylor@Sun.COM
22019517SBill.Taylor@Sun.COM mutex_destroy(&handlep->lock);
22029517SBill.Taylor@Sun.COM handlep->save_hdl = NULL;
22039517SBill.Taylor@Sun.COM kmem_cache_free(hca_fm->fm_acc_cache, handlep);
22049517SBill.Taylor@Sun.COM
22059517SBill.Taylor@Sun.COM /* Release this handle */
22069517SBill.Taylor@Sun.COM pci_config_teardown(handle);
22079517SBill.Taylor@Sun.COM *handle = NULL;
22089517SBill.Taylor@Sun.COM }
22099517SBill.Taylor@Sun.COM
22109517SBill.Taylor@Sun.COM
22119517SBill.Taylor@Sun.COM /*
22129517SBill.Taylor@Sun.COM * int
22139517SBill.Taylor@Sun.COM * i_hca_pio_start(dev_info_t *dip, struct i_acc_handle *handle,
22149517SBill.Taylor@Sun.COM * struct i_hca_fm_test *tst)
22159517SBill.Taylor@Sun.COM *
22169517SBill.Taylor@Sun.COM * Overview
22179517SBill.Taylor@Sun.COM * i_hca_pio_start() is one of a pair of HCA FM fuctions for PIO, which
22189517SBill.Taylor@Sun.COM * should be called before HCA drivers issue PIOs against I/O space.
22199517SBill.Taylor@Sun.COM * See HCA FM comments at the beginning of this file in detail.
22209517SBill.Taylor@Sun.COM *
22219517SBill.Taylor@Sun.COM * Argument
22229517SBill.Taylor@Sun.COM * dip: pointer to this device dev_info structure
22239517SBill.Taylor@Sun.COM * handle: pointer to ddi_acc_handle_t used for HCA FM
22249517SBill.Taylor@Sun.COM * tst: pointer to HCA FM function test structure. If the structure
22259517SBill.Taylor@Sun.COM * is not used, the NULL value must be passed instead.
22269517SBill.Taylor@Sun.COM *
22279517SBill.Taylor@Sun.COM * Return value
22289517SBill.Taylor@Sun.COM * error status showing whether or not this error can retry
22299517SBill.Taylor@Sun.COM * HCA_PIO_OK No HW errors
22309517SBill.Taylor@Sun.COM * HCA_PIO_TRANSIENT This error could be transient
22319517SBill.Taylor@Sun.COM * HCA_PIO_PERSISTENT This error is persistent
22329517SBill.Taylor@Sun.COM *
22339517SBill.Taylor@Sun.COM * Caller's context
22349517SBill.Taylor@Sun.COM * i_hca_pio_start() can be called in user, kernel or interrupt context.
22359517SBill.Taylor@Sun.COM */
22369517SBill.Taylor@Sun.COM /* ARGSUSED */
22379517SBill.Taylor@Sun.COM static int
i_hca_pio_start(dev_info_t * dip,struct i_hca_acc_handle * hdlp,struct i_hca_fm_test * tst)22389517SBill.Taylor@Sun.COM i_hca_pio_start(dev_info_t *dip, struct i_hca_acc_handle *hdlp,
22399517SBill.Taylor@Sun.COM struct i_hca_fm_test *tst)
22409517SBill.Taylor@Sun.COM {
22419517SBill.Taylor@Sun.COM ddi_fm_error_t derr;
22429517SBill.Taylor@Sun.COM
22439517SBill.Taylor@Sun.COM /* Count up the number of threads issuing this PIO */
22449517SBill.Taylor@Sun.COM mutex_enter(&hdlp->lock);
22459517SBill.Taylor@Sun.COM hdlp->thread_cnt++;
22469517SBill.Taylor@Sun.COM mutex_exit(&hdlp->lock);
22479517SBill.Taylor@Sun.COM
22489517SBill.Taylor@Sun.COM /* Get the PIO error via FMA */
22499517SBill.Taylor@Sun.COM ddi_fm_acc_err_get(fm_acc_hdl(hdlp), &derr, DDI_FME_VERSION);
22509517SBill.Taylor@Sun.COM
22519517SBill.Taylor@Sun.COM #ifdef FMA_TEST
22529517SBill.Taylor@Sun.COM /* Trigger PIO errors */
22539517SBill.Taylor@Sun.COM if (tst != NULL && tst->trigger & HCA_TEST_START) {
22549517SBill.Taylor@Sun.COM (*tst->pio_injection)(tst, &derr);
22559517SBill.Taylor@Sun.COM }
22569517SBill.Taylor@Sun.COM #endif /* FMA_TEST */
22579517SBill.Taylor@Sun.COM
22589517SBill.Taylor@Sun.COM switch (derr.fme_status) {
22599517SBill.Taylor@Sun.COM case DDI_FM_OK:
22609517SBill.Taylor@Sun.COM /* Not have to clear the fma error log */
22619517SBill.Taylor@Sun.COM return (HCA_PIO_OK);
22629517SBill.Taylor@Sun.COM
22639517SBill.Taylor@Sun.COM case DDI_FM_NONFATAL:
22649517SBill.Taylor@Sun.COM /* Now clear this error */
22659517SBill.Taylor@Sun.COM ddi_fm_acc_err_clear(fm_acc_hdl(hdlp), DDI_FME_VERSION);
22669517SBill.Taylor@Sun.COM
22679517SBill.Taylor@Sun.COM /* Log this error and notify it as a persistent error */
22689517SBill.Taylor@Sun.COM ddi_fm_service_impact(dip, DDI_SERVICE_LOST);
22699517SBill.Taylor@Sun.COM return (HCA_PIO_PERSISTENT);
22709517SBill.Taylor@Sun.COM
22719517SBill.Taylor@Sun.COM /* In theory, this shouldn't happen */
22729517SBill.Taylor@Sun.COM case DDI_FM_FATAL:
22739517SBill.Taylor@Sun.COM case DDI_FM_UNKNOWN:
22749517SBill.Taylor@Sun.COM default:
22759517SBill.Taylor@Sun.COM cmn_err(CE_WARN, "Unknown HCA HW error status (%d)",
22769517SBill.Taylor@Sun.COM derr.fme_status);
22779517SBill.Taylor@Sun.COM /* Return this as a persistent error */
22789517SBill.Taylor@Sun.COM return (HCA_PIO_PERSISTENT);
22799517SBill.Taylor@Sun.COM }
22809517SBill.Taylor@Sun.COM }
22819517SBill.Taylor@Sun.COM
22829517SBill.Taylor@Sun.COM
22839517SBill.Taylor@Sun.COM /*
22849517SBill.Taylor@Sun.COM * int
22859517SBill.Taylor@Sun.COM * i_hca_pio_end(dev_info_t *dip, ddi_acc_handle_t handle, int *cnt,
22869517SBill.Taylor@Sun.COM * struct i_hca_fm_test *tst)
22879517SBill.Taylor@Sun.COM *
22889517SBill.Taylor@Sun.COM * Overview
22899517SBill.Taylor@Sun.COM * i_hca_pio_end() is the other of a pair of HCA FM fuctions for PIO,
22909517SBill.Taylor@Sun.COM * which should be called after HCA drivers issue PIOs against I/O space.
22919517SBill.Taylor@Sun.COM * See HCA FM comments at the beginning of this file in detail.
22929517SBill.Taylor@Sun.COM *
22939517SBill.Taylor@Sun.COM * Argument
22949517SBill.Taylor@Sun.COM * dip: pointer to this device dev_info structure
22959517SBill.Taylor@Sun.COM * handle: pointer to ddi_acc_handle_t used for HCA FM
22969517SBill.Taylor@Sun.COM * cnt: pointer to the counter variable which holds the nubmer of retry
22979517SBill.Taylor@Sun.COM * when a HW error is detected.
22989517SBill.Taylor@Sun.COM * tst: pointer to HCA FM function test structure. If the structure
22999517SBill.Taylor@Sun.COM * is not used, the NULL value must be passed instead.
23009517SBill.Taylor@Sun.COM *
23019517SBill.Taylor@Sun.COM * Return value
23029517SBill.Taylor@Sun.COM * error status showing whether or not this error can retry
23039517SBill.Taylor@Sun.COM * HCA_PIO_OK No HW errors
23049517SBill.Taylor@Sun.COM * HCA_PIO_TRANSIENT This error could be transient
23059517SBill.Taylor@Sun.COM * HCA_PIO_PERSISTENT This error is persistent
23069517SBill.Taylor@Sun.COM *
23079517SBill.Taylor@Sun.COM * Caller's context
23089517SBill.Taylor@Sun.COM * i_hca_pio_end() can be called in user, kernel or interrupt context.
23099517SBill.Taylor@Sun.COM */
23109517SBill.Taylor@Sun.COM /* ARGSUSED */
23119517SBill.Taylor@Sun.COM static int
i_hca_pio_end(dev_info_t * dip,struct i_hca_acc_handle * hdlp,int * cnt,struct i_hca_fm_test * tst)23129517SBill.Taylor@Sun.COM i_hca_pio_end(dev_info_t *dip, struct i_hca_acc_handle *hdlp, int *cnt,
23139517SBill.Taylor@Sun.COM struct i_hca_fm_test *tst)
23149517SBill.Taylor@Sun.COM {
23159517SBill.Taylor@Sun.COM ddi_fm_error_t derr;
23169517SBill.Taylor@Sun.COM
23179517SBill.Taylor@Sun.COM /* Get the PIO error via FMA */
23189517SBill.Taylor@Sun.COM ddi_fm_acc_err_get(fm_acc_hdl(hdlp), &derr, DDI_FME_VERSION);
23199517SBill.Taylor@Sun.COM
23209517SBill.Taylor@Sun.COM #ifdef FMA_TEST
23219517SBill.Taylor@Sun.COM /* Trigger PIO errors */
23229517SBill.Taylor@Sun.COM if (tst != NULL && tst->trigger & HCA_TEST_END) {
23239517SBill.Taylor@Sun.COM (*tst->pio_injection)(tst, &derr);
23249517SBill.Taylor@Sun.COM }
23259517SBill.Taylor@Sun.COM #endif /* FMA_TEST */
23269517SBill.Taylor@Sun.COM
23279517SBill.Taylor@Sun.COM /* Evaluate the PIO error */
23289517SBill.Taylor@Sun.COM switch (derr.fme_status) {
23299517SBill.Taylor@Sun.COM case DDI_FM_OK:
23309517SBill.Taylor@Sun.COM /* Count down the number of threads issuing this PIO */
23319517SBill.Taylor@Sun.COM mutex_enter(&hdlp->lock);
23329517SBill.Taylor@Sun.COM hdlp->thread_cnt--;
23339517SBill.Taylor@Sun.COM mutex_exit(&hdlp->lock);
23349517SBill.Taylor@Sun.COM
23359517SBill.Taylor@Sun.COM /* Not have to clear the fma error log */
23369517SBill.Taylor@Sun.COM return (HCA_PIO_OK);
23379517SBill.Taylor@Sun.COM
23389517SBill.Taylor@Sun.COM case DDI_FM_NONFATAL:
23399517SBill.Taylor@Sun.COM /* Now clear this error */
23409517SBill.Taylor@Sun.COM ddi_fm_acc_err_clear(fm_acc_hdl(hdlp), DDI_FME_VERSION);
23419517SBill.Taylor@Sun.COM
23429517SBill.Taylor@Sun.COM /*
23439517SBill.Taylor@Sun.COM * Check if this error comes from another thread running
23449517SBill.Taylor@Sun.COM * with the same handle almost at the same time.
23459517SBill.Taylor@Sun.COM */
23469517SBill.Taylor@Sun.COM mutex_enter(&hdlp->lock);
23479517SBill.Taylor@Sun.COM if (hdlp->thread_cnt > 1) {
23489517SBill.Taylor@Sun.COM /* Count down the number of threads */
23499517SBill.Taylor@Sun.COM hdlp->thread_cnt--;
23509517SBill.Taylor@Sun.COM mutex_exit(&hdlp->lock);
23519517SBill.Taylor@Sun.COM
23529517SBill.Taylor@Sun.COM /* Return this as a persistent error */
23539517SBill.Taylor@Sun.COM return (HCA_PIO_PERSISTENT);
23549517SBill.Taylor@Sun.COM }
23559517SBill.Taylor@Sun.COM mutex_exit(&hdlp->lock);
23569517SBill.Taylor@Sun.COM
23579517SBill.Taylor@Sun.COM /* Now determine if this error is persistent or not */
23589517SBill.Taylor@Sun.COM if (--(*cnt) >= 0) {
23599517SBill.Taylor@Sun.COM return (HCA_PIO_TRANSIENT);
23609517SBill.Taylor@Sun.COM } else {
23619517SBill.Taylor@Sun.COM /* Count down the number of threads */
23629517SBill.Taylor@Sun.COM mutex_enter(&hdlp->lock);
23639517SBill.Taylor@Sun.COM hdlp->thread_cnt--;
23649517SBill.Taylor@Sun.COM mutex_exit(&hdlp->lock);
23659517SBill.Taylor@Sun.COM return (HCA_PIO_PERSISTENT);
23669517SBill.Taylor@Sun.COM }
23679517SBill.Taylor@Sun.COM
23689517SBill.Taylor@Sun.COM /* In theory, this shouldn't happen */
23699517SBill.Taylor@Sun.COM case DDI_FM_FATAL:
23709517SBill.Taylor@Sun.COM case DDI_FM_UNKNOWN:
23719517SBill.Taylor@Sun.COM default:
23729517SBill.Taylor@Sun.COM cmn_err(CE_WARN, "Unknown HCA HW error status (%d)",
23739517SBill.Taylor@Sun.COM derr.fme_status);
23749517SBill.Taylor@Sun.COM /* Return this as a persistent error */
23759517SBill.Taylor@Sun.COM return (HCA_PIO_PERSISTENT);
23769517SBill.Taylor@Sun.COM }
23779517SBill.Taylor@Sun.COM }
23789517SBill.Taylor@Sun.COM
23799517SBill.Taylor@Sun.COM
23809517SBill.Taylor@Sun.COM /*
23819517SBill.Taylor@Sun.COM * HCA FM Test Interface
23829517SBill.Taylor@Sun.COM *
23839517SBill.Taylor@Sun.COM * These functions should be used for any HCA drivers, but probably
23849517SBill.Taylor@Sun.COM * customized for their own HW design and/or FM implementation.
23859517SBill.Taylor@Sun.COM * Customized functins should have the driver name prefix such as
23869517SBill.Taylor@Sun.COM * hermon_xxxx() and be defined separately but whose function should
23879517SBill.Taylor@Sun.COM * call the common interface inside.
23889517SBill.Taylor@Sun.COM */
23899517SBill.Taylor@Sun.COM
23909517SBill.Taylor@Sun.COM #ifdef FMA_TEST
23919517SBill.Taylor@Sun.COM static int test_num; /* serial number */
23929517SBill.Taylor@Sun.COM static kmutex_t i_hca_test_lock; /* lock for serial numer */
23939517SBill.Taylor@Sun.COM
23949517SBill.Taylor@Sun.COM /*
23959517SBill.Taylor@Sun.COM * void
23969517SBill.Taylor@Sun.COM * i_hca_test_init(mod_hash_t **strHashp, mod_hash_t **idHashp)
23979517SBill.Taylor@Sun.COM *
23989517SBill.Taylor@Sun.COM * Overview
23999517SBill.Taylor@Sun.COM * i_hca_test_init() creates two hash tables, one of which is for string,
24009517SBill.Taylor@Sun.COM * and the other of which is for ID, then saves pointers to arguments
24019517SBill.Taylor@Sun.COM * passed. This function uses the mod_hash utilities to manage the
24029517SBill.Taylor@Sun.COM * hash tables. About the mod_hash, see common/os/modhash.c.
24039517SBill.Taylor@Sun.COM *
24049517SBill.Taylor@Sun.COM * Argument
24059517SBill.Taylor@Sun.COM * strHashp: pointer to String hash table pointer
24069517SBill.Taylor@Sun.COM * idHashp: pointer to ID hash table pointer
24079517SBill.Taylor@Sun.COM *
24089517SBill.Taylor@Sun.COM * Return value
24099517SBill.Taylor@Sun.COM * Nothing
24109517SBill.Taylor@Sun.COM *
24119517SBill.Taylor@Sun.COM * Caller's context
24129517SBill.Taylor@Sun.COM * i_hca_test_init() can be called in user or kernel context only.
24139517SBill.Taylor@Sun.COM */
24149517SBill.Taylor@Sun.COM static void
i_hca_test_init(mod_hash_t ** strHashp,mod_hash_t ** idHashp)24159517SBill.Taylor@Sun.COM i_hca_test_init(mod_hash_t **strHashp, mod_hash_t **idHashp)
24169517SBill.Taylor@Sun.COM {
24179517SBill.Taylor@Sun.COM *idHashp = mod_hash_create_idhash("HCA_FMA_id_hash",
24189517SBill.Taylor@Sun.COM FMA_TEST_HASHSZ, mod_hash_null_valdtor);
24199517SBill.Taylor@Sun.COM
24209517SBill.Taylor@Sun.COM *strHashp = mod_hash_create_strhash("HCA_FMA_test_hash",
24219517SBill.Taylor@Sun.COM FMA_TEST_HASHSZ, i_hca_test_free_item);
24229517SBill.Taylor@Sun.COM }
24239517SBill.Taylor@Sun.COM
24249517SBill.Taylor@Sun.COM
24259517SBill.Taylor@Sun.COM /*
24269517SBill.Taylor@Sun.COM * void
24279517SBill.Taylor@Sun.COM * i_hca_test_fini(mod_hash_t **strHashp, mod_hash_t **idHashp)
24289517SBill.Taylor@Sun.COM *
24299517SBill.Taylor@Sun.COM * Overview
24309517SBill.Taylor@Sun.COM * i_hca_test_fini() releases two hash tables used for HCA FM test.
24319517SBill.Taylor@Sun.COM *
24329517SBill.Taylor@Sun.COM * Argument
24339517SBill.Taylor@Sun.COM * strHashp: pointer to String hash table pointer
24349517SBill.Taylor@Sun.COM * idHashp: pointer to ID hash table pointer
24359517SBill.Taylor@Sun.COM *
24369517SBill.Taylor@Sun.COM * Return value
24379517SBill.Taylor@Sun.COM * Nothing
24389517SBill.Taylor@Sun.COM *
24399517SBill.Taylor@Sun.COM * Caller's context
24409517SBill.Taylor@Sun.COM * i_hca_test_fini() can be called in user, kernel or interrupt context.
24419517SBill.Taylor@Sun.COM *
24429517SBill.Taylor@Sun.COM */
24439517SBill.Taylor@Sun.COM static void
i_hca_test_fini(mod_hash_t ** strHashp,mod_hash_t ** idHashp)24449517SBill.Taylor@Sun.COM i_hca_test_fini(mod_hash_t **strHashp, mod_hash_t **idHashp)
24459517SBill.Taylor@Sun.COM {
24469517SBill.Taylor@Sun.COM mod_hash_destroy_hash(*strHashp);
24479517SBill.Taylor@Sun.COM *strHashp = NULL;
24489517SBill.Taylor@Sun.COM
24499517SBill.Taylor@Sun.COM mod_hash_destroy_hash(*idHashp);
24509517SBill.Taylor@Sun.COM *idHashp = NULL;
24519517SBill.Taylor@Sun.COM }
24529517SBill.Taylor@Sun.COM
24539517SBill.Taylor@Sun.COM
24549517SBill.Taylor@Sun.COM /*
24559517SBill.Taylor@Sun.COM * struct i_hca_fm_test *
24569517SBill.Taylor@Sun.COM * i_hca_test_register(char *filename, int linenum, int type,
24579517SBill.Taylor@Sun.COM * void (*pio_injection)(struct i_hca_fm_test *, ddi_fm_error_t *),
24589517SBill.Taylor@Sun.COM * void *private, mod_hash_t *strHash, mod_hash_t *idHash, int preTestNum)
24599517SBill.Taylor@Sun.COM *
24609517SBill.Taylor@Sun.COM * Overview
24619517SBill.Taylor@Sun.COM * i_hca_test_register() registers an HCA FM test item against HCA FM
24629517SBill.Taylor@Sun.COM * function callings specified with the file name and the line number
24639517SBill.Taylor@Sun.COM * (passed as the arguments).
24649517SBill.Taylor@Sun.COM *
24659517SBill.Taylor@Sun.COM * Argument
24669517SBill.Taylor@Sun.COM * filename: source file name where the function call is implemented
24679517SBill.Taylor@Sun.COM * This value is usually a __FILE__ pre-defined macro.
24689517SBill.Taylor@Sun.COM * linenum: line number where the function call is described in the
24699517SBill.Taylor@Sun.COM * file specified above.
24709517SBill.Taylor@Sun.COM * This value is usually a __LINE__ pre-defined macro.
24719517SBill.Taylor@Sun.COM * type: HW error type
24729517SBill.Taylor@Sun.COM * HCA_TEST_PIO pio error
24739517SBill.Taylor@Sun.COM * HCA_TEST_IBA ib specific error
24749517SBill.Taylor@Sun.COM * pio_injection: pio error injection callback function invoked when the
24759517SBill.Taylor@Sun.COM * function specified above (with the file name and the
24769517SBill.Taylor@Sun.COM * line number) is executed. If the function is not a PIO,
24779517SBill.Taylor@Sun.COM * request, this parameter should be NULL.
24789517SBill.Taylor@Sun.COM * private: the argument passed to either of injection functions when
24799517SBill.Taylor@Sun.COM * they're invoked.
24809517SBill.Taylor@Sun.COM * strHashp: pointer to String hash table
24819517SBill.Taylor@Sun.COM * idHashp: pointer to ID hash table
24829517SBill.Taylor@Sun.COM * preTestNum: the index of the pre-defined testset for this test item.
24839517SBill.Taylor@Sun.COM *
24849517SBill.Taylor@Sun.COM * Return value
24859517SBill.Taylor@Sun.COM * pointer to HCA FM function test structure registered.
24869517SBill.Taylor@Sun.COM *
24879517SBill.Taylor@Sun.COM * Caller's context
24889517SBill.Taylor@Sun.COM * i_hca_test_register() can be called in user, kernel or interrupt
24899517SBill.Taylor@Sun.COM * context.
24909517SBill.Taylor@Sun.COM *
24919517SBill.Taylor@Sun.COM */
24929517SBill.Taylor@Sun.COM static struct i_hca_fm_test *
i_hca_test_register(char * filename,int linenum,int type,void (* pio_injection)(struct i_hca_fm_test *,ddi_fm_error_t *),void * private,mod_hash_t * strHash,mod_hash_t * idHash,int preTestNum)24939517SBill.Taylor@Sun.COM i_hca_test_register(char *filename, int linenum, int type,
24949517SBill.Taylor@Sun.COM void (*pio_injection)(struct i_hca_fm_test *, ddi_fm_error_t *),
24959517SBill.Taylor@Sun.COM void *private, mod_hash_t *strHash, mod_hash_t *idHash, int preTestNum)
24969517SBill.Taylor@Sun.COM {
24979517SBill.Taylor@Sun.COM struct i_hca_fm_test *t_item;
24989517SBill.Taylor@Sun.COM char key_buf[255], *hash_key;
24999517SBill.Taylor@Sun.COM int status;
25009517SBill.Taylor@Sun.COM
25019517SBill.Taylor@Sun.COM (void) sprintf(key_buf, "%s:%d", filename, linenum);
25029517SBill.Taylor@Sun.COM hash_key = kmem_zalloc(strlen(key_buf) + 1, KM_NOSLEEP);
25039517SBill.Taylor@Sun.COM
25049517SBill.Taylor@Sun.COM if (hash_key == NULL)
25059517SBill.Taylor@Sun.COM cmn_err(CE_PANIC, "No memory for HCA FMA Test.");
25069517SBill.Taylor@Sun.COM
25079517SBill.Taylor@Sun.COM bcopy(key_buf, hash_key, strlen(key_buf));
25089517SBill.Taylor@Sun.COM
25099517SBill.Taylor@Sun.COM status = mod_hash_find(strHash, (mod_hash_key_t)hash_key,
25109517SBill.Taylor@Sun.COM (mod_hash_val_t *)&t_item);
25119517SBill.Taylor@Sun.COM
25129517SBill.Taylor@Sun.COM switch (status) {
25139517SBill.Taylor@Sun.COM case MH_ERR_NOTFOUND:
25149517SBill.Taylor@Sun.COM t_item = (struct i_hca_fm_test *)
25159517SBill.Taylor@Sun.COM kmem_alloc(sizeof (struct i_hca_fm_test), KM_NOSLEEP);
25169517SBill.Taylor@Sun.COM if (t_item == NULL)
25179517SBill.Taylor@Sun.COM cmn_err(CE_PANIC, "No memory for HCA FMA Test.");
25189517SBill.Taylor@Sun.COM
25199517SBill.Taylor@Sun.COM /* Set the error number */
25209517SBill.Taylor@Sun.COM mutex_enter(&i_hca_test_lock);
25219517SBill.Taylor@Sun.COM t_item->num = test_num++;
25229517SBill.Taylor@Sun.COM mutex_exit(&i_hca_test_lock);
25239517SBill.Taylor@Sun.COM
25249517SBill.Taylor@Sun.COM /* Set type and other static information */
25259517SBill.Taylor@Sun.COM t_item->type = type;
25269517SBill.Taylor@Sun.COM t_item->line_num = linenum;
25279517SBill.Taylor@Sun.COM t_item->file_name = filename;
25289517SBill.Taylor@Sun.COM t_item->hash_key = hash_key;
25299517SBill.Taylor@Sun.COM t_item->private = private;
25309517SBill.Taylor@Sun.COM t_item->pio_injection = pio_injection;
25319517SBill.Taylor@Sun.COM
25329517SBill.Taylor@Sun.COM /* Set the pre-defined hermon test item */
25339517SBill.Taylor@Sun.COM i_hca_test_set_item(preTestNum, (struct i_hca_fm_test *)t_item);
25349517SBill.Taylor@Sun.COM
25359517SBill.Taylor@Sun.COM status = mod_hash_insert(strHash, (mod_hash_key_t)
25369517SBill.Taylor@Sun.COM hash_key, (mod_hash_val_t)t_item);
25379517SBill.Taylor@Sun.COM ASSERT(status == 0);
25389517SBill.Taylor@Sun.COM
25399517SBill.Taylor@Sun.COM status = mod_hash_insert(idHash, (mod_hash_key_t)
25409517SBill.Taylor@Sun.COM (uintptr_t)t_item->num, (mod_hash_val_t)t_item);
25419517SBill.Taylor@Sun.COM ASSERT(status == 0);
25429517SBill.Taylor@Sun.COM break;
25439517SBill.Taylor@Sun.COM
25449517SBill.Taylor@Sun.COM case MH_ERR_NOMEM:
25459517SBill.Taylor@Sun.COM cmn_err(CE_PANIC, "No memory for HCA FMA Test.");
25469517SBill.Taylor@Sun.COM break;
25479517SBill.Taylor@Sun.COM
25489517SBill.Taylor@Sun.COM case MH_ERR_DUPLICATE:
25499517SBill.Taylor@Sun.COM cmn_err(CE_PANIC, "HCA FMA Test Internal Error.");
25509517SBill.Taylor@Sun.COM break;
25519517SBill.Taylor@Sun.COM default:
25529517SBill.Taylor@Sun.COM /* OK, this is already registered. */
25539517SBill.Taylor@Sun.COM kmem_free(hash_key, strlen(key_buf) + 1);
25549517SBill.Taylor@Sun.COM break;
25559517SBill.Taylor@Sun.COM }
25569517SBill.Taylor@Sun.COM return (t_item);
25579517SBill.Taylor@Sun.COM }
25589517SBill.Taylor@Sun.COM
25599517SBill.Taylor@Sun.COM
25609517SBill.Taylor@Sun.COM /*
25619517SBill.Taylor@Sun.COM * void
25629517SBill.Taylor@Sun.COM * i_hca_test_set_item(int num, struct i_hca_fm_test *t_item)
25639517SBill.Taylor@Sun.COM *
25649517SBill.Taylor@Sun.COM * Overview
25659517SBill.Taylor@Sun.COM * i_hca_test_set_item() is a private function used in
25669517SBill.Taylor@Sun.COM * i_hca_test_register() above. This function sets the testset specified
25679517SBill.Taylor@Sun.COM * (with the index number) to HCA FM function test structure.
25689517SBill.Taylor@Sun.COM *
25699517SBill.Taylor@Sun.COM * Argument
25709517SBill.Taylor@Sun.COM * num: index to test set (testset structure array)
25719517SBill.Taylor@Sun.COM * t_item: pointer to HCA fM function test structure
25729517SBill.Taylor@Sun.COM *
25739517SBill.Taylor@Sun.COM * Return value
25749517SBill.Taylor@Sun.COM * Nothing
25759517SBill.Taylor@Sun.COM *
25769517SBill.Taylor@Sun.COM * Caller's context
25779517SBill.Taylor@Sun.COM * i_hca_test_set_item() can be called in user, kernel, interrupt
25789517SBill.Taylor@Sun.COM * context or hight interrupt context.
25799517SBill.Taylor@Sun.COM *
25809517SBill.Taylor@Sun.COM */
25819517SBill.Taylor@Sun.COM static void
i_hca_test_set_item(int num,struct i_hca_fm_test * t_item)25829517SBill.Taylor@Sun.COM i_hca_test_set_item(int num, struct i_hca_fm_test *t_item)
25839517SBill.Taylor@Sun.COM {
25849517SBill.Taylor@Sun.COM if (num < 0 || num >= sizeof (testset) / sizeof (hermon_test_t) ||
25859517SBill.Taylor@Sun.COM testset[num].type != t_item->type) {
25869517SBill.Taylor@Sun.COM t_item->trigger = testset[0].trigger;
25879517SBill.Taylor@Sun.COM t_item->errcnt = testset[0].errcnt;
25889517SBill.Taylor@Sun.COM return;
25899517SBill.Taylor@Sun.COM }
25909517SBill.Taylor@Sun.COM
25919517SBill.Taylor@Sun.COM /* Set the testsuite */
25929517SBill.Taylor@Sun.COM t_item->trigger = testset[num].trigger;
25939517SBill.Taylor@Sun.COM t_item->errcnt = testset[num].errcnt;
25949517SBill.Taylor@Sun.COM }
25959517SBill.Taylor@Sun.COM
25969517SBill.Taylor@Sun.COM
25979517SBill.Taylor@Sun.COM /*
25989517SBill.Taylor@Sun.COM * void
25999517SBill.Taylor@Sun.COM * i_hca_test_free_item(mod_hash_val_t val)
26009517SBill.Taylor@Sun.COM *
26019517SBill.Taylor@Sun.COM * Overview
26029517SBill.Taylor@Sun.COM * i_hca_test_free_item() is a private function used to free HCA FM
26039517SBill.Taylor@Sun.COM * function test structure when i_hca_test_fini() is called. This function
26049517SBill.Taylor@Sun.COM * is registered as a destructor when the hash table is created in
26059517SBill.Taylor@Sun.COM * i_hca_test_init().
26069517SBill.Taylor@Sun.COM *
26079517SBill.Taylor@Sun.COM * Argument
26089517SBill.Taylor@Sun.COM * val: pointer to the value stored in hash table (pointer to HCA FM
26099517SBill.Taylor@Sun.COM * function test structure)
26109517SBill.Taylor@Sun.COM *
26119517SBill.Taylor@Sun.COM * Return value
26129517SBill.Taylor@Sun.COM * Nothing
26139517SBill.Taylor@Sun.COM *
26149517SBill.Taylor@Sun.COM * Caller's context
26159517SBill.Taylor@Sun.COM * i_hca_test_free_item() can be called in user, kernel or interrupt
26169517SBill.Taylor@Sun.COM * context.
26179517SBill.Taylor@Sun.COM *
26189517SBill.Taylor@Sun.COM */
26199517SBill.Taylor@Sun.COM static void
i_hca_test_free_item(mod_hash_val_t val)26209517SBill.Taylor@Sun.COM i_hca_test_free_item(mod_hash_val_t val)
26219517SBill.Taylor@Sun.COM {
26229517SBill.Taylor@Sun.COM struct i_hca_fm_test *t_item = (struct i_hca_fm_test *)val;
26239517SBill.Taylor@Sun.COM kmem_free(t_item, sizeof (struct i_hca_fm_test));
26249517SBill.Taylor@Sun.COM }
26259517SBill.Taylor@Sun.COM #endif /* FMA_TEST */
2626