1*9e39c5baSBill Taylor /* 2*9e39c5baSBill Taylor * CDDL HEADER START 3*9e39c5baSBill Taylor * 4*9e39c5baSBill Taylor * The contents of this file are subject to the terms of the 5*9e39c5baSBill Taylor * Common Development and Distribution License (the "License"). 6*9e39c5baSBill Taylor * You may not use this file except in compliance with the License. 7*9e39c5baSBill Taylor * 8*9e39c5baSBill Taylor * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*9e39c5baSBill Taylor * or http://www.opensolaris.org/os/licensing. 10*9e39c5baSBill Taylor * See the License for the specific language governing permissions 11*9e39c5baSBill Taylor * and limitations under the License. 12*9e39c5baSBill Taylor * 13*9e39c5baSBill Taylor * When distributing Covered Code, include this CDDL HEADER in each 14*9e39c5baSBill Taylor * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*9e39c5baSBill Taylor * If applicable, add the following below this CDDL HEADER, with the 16*9e39c5baSBill Taylor * fields enclosed by brackets "[]" replaced with your own identifying 17*9e39c5baSBill Taylor * information: Portions Copyright [yyyy] [name of copyright owner] 18*9e39c5baSBill Taylor * 19*9e39c5baSBill Taylor * CDDL HEADER END 20*9e39c5baSBill Taylor */ 21*9e39c5baSBill Taylor 22*9e39c5baSBill Taylor /* 23*9e39c5baSBill Taylor * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24*9e39c5baSBill Taylor * Use is subject to license terms. 25*9e39c5baSBill Taylor */ 26*9e39c5baSBill Taylor 27*9e39c5baSBill Taylor /* 28*9e39c5baSBill Taylor * hermon_fm.c 29*9e39c5baSBill Taylor * Hermon (InfiniBand) HCA Driver Fault Management Routines 30*9e39c5baSBill Taylor * 31*9e39c5baSBill Taylor * [Hermon FM Implementation] 32*9e39c5baSBill Taylor * 33*9e39c5baSBill Taylor * Hermon FM recovers the system from a HW error situation and/or isolates a 34*9e39c5baSBill Taylor * HW error by calling the FMA acc handle check functions. (calling 35*9e39c5baSBill Taylor * ddi_fm_acc_err_get()) If a HW error is detected when either 36*9e39c5baSBill Taylor * ddi_fm_acc_err_get() is called, to determine whether or not the error is 37*9e39c5baSBill Taylor * transient, the I/O operation causing the error will retry up to three times. 38*9e39c5baSBill Taylor * 39*9e39c5baSBill Taylor * (Basic HW error recovery) 40*9e39c5baSBill Taylor * 41*9e39c5baSBill Taylor * | 42*9e39c5baSBill Taylor * .---->* 43*9e39c5baSBill Taylor * | | 44*9e39c5baSBill Taylor * | issue an I/O request via PIO 45*9e39c5baSBill Taylor * | | 46*9e39c5baSBill Taylor * | | 47*9e39c5baSBill Taylor * | check acc handle 48*9e39c5baSBill Taylor * | | 49*9e39c5baSBill Taylor * | | 50*9e39c5baSBill Taylor * `--< a HW error detected && retry count < 3 > 51*9e39c5baSBill Taylor * | 52*9e39c5baSBill Taylor * v 53*9e39c5baSBill Taylor * 54*9e39c5baSBill Taylor * When a HW error is detected, to provide the error information for users to 55*9e39c5baSBill Taylor * isolate the faulted HW, Hermon FM issues Solaris FMA ereports as follows. 56*9e39c5baSBill Taylor * 57*9e39c5baSBill Taylor * * PIO transient error 58*9e39c5baSBill Taylor * invalid_state => unaffected 59*9e39c5baSBill Taylor * 60*9e39c5baSBill Taylor * * PIO persistent error 61*9e39c5baSBill Taylor * invalid_state => lost 62*9e39c5baSBill Taylor * 63*9e39c5baSBill Taylor * * PIO fatal error 64*9e39c5baSBill Taylor * invalid_state => lost => panic 65*9e39c5baSBill Taylor * 66*9e39c5baSBill Taylor * * Hermon HCA firmware error 67*9e39c5baSBill Taylor * invalid_state => degraded 68*9e39c5baSBill Taylor * 69*9e39c5baSBill Taylor * * Other Hermon HCA specific errors 70*9e39c5baSBill Taylor * uncorrect => unaffected 71*9e39c5baSBill Taylor * or 72*9e39c5baSBill Taylor * correct => unaffected 73*9e39c5baSBill Taylor * 74*9e39c5baSBill Taylor * (Restrictions) 75*9e39c5baSBill Taylor * 76*9e39c5baSBill Taylor * The current implementation has the following restrictions. 77*9e39c5baSBill Taylor * * No runtime check/protection 78*9e39c5baSBill Taylor * * No detach time check/protection 79*9e39c5baSBill Taylor * * No DMA check/protection 80*9e39c5baSBill Taylor * 81*9e39c5baSBill Taylor * See the Hermon FMA portfolio in detail. 82*9e39c5baSBill Taylor */ 83*9e39c5baSBill Taylor 84*9e39c5baSBill Taylor #include <sys/types.h> 85*9e39c5baSBill Taylor #include <sys/conf.h> 86*9e39c5baSBill Taylor #include <sys/ddi.h> 87*9e39c5baSBill Taylor #include <sys/sunddi.h> 88*9e39c5baSBill Taylor #include <sys/sysmacros.h> 89*9e39c5baSBill Taylor #include <sys/list.h> 90*9e39c5baSBill Taylor #include <sys/modhash.h> 91*9e39c5baSBill Taylor 92*9e39c5baSBill Taylor #include <sys/ib/adapters/hermon/hermon.h> 93*9e39c5baSBill Taylor 94*9e39c5baSBill Taylor /* 95*9e39c5baSBill Taylor * Hermon driver has to disable its FM functionality 96*9e39c5baSBill Taylor * if this "fm_capable" variable is defined or has a value 97*9e39c5baSBill Taylor * in /kernel/drv/hermon.conf. 98*9e39c5baSBill Taylor */ 99*9e39c5baSBill Taylor static char *fm_cap = "fm-capable"; /* FM capability */ 100*9e39c5baSBill Taylor 101*9e39c5baSBill Taylor static hermon_hca_fm_t hca_fm; /* Hermon HCA FM Structure */ 102*9e39c5baSBill Taylor 103*9e39c5baSBill Taylor static void i_hca_fm_ereport(dev_info_t *, int, char *); 104*9e39c5baSBill Taylor static void i_hca_fm_init(struct i_hca_fm *); 105*9e39c5baSBill Taylor static void i_hca_fm_fini(struct i_hca_fm *); 106*9e39c5baSBill Taylor static int i_hca_regs_map_setup(struct i_hca_fm *, dev_info_t *, uint_t, 107*9e39c5baSBill Taylor caddr_t *, offset_t, offset_t, ddi_device_acc_attr_t *, ddi_acc_handle_t *); 108*9e39c5baSBill Taylor static void i_hca_regs_map_free(struct i_hca_fm *, ddi_acc_handle_t *); 109*9e39c5baSBill Taylor static int i_hca_pci_config_setup(struct i_hca_fm *, dev_info_t *, 110*9e39c5baSBill Taylor ddi_acc_handle_t *); 111*9e39c5baSBill Taylor static void i_hca_pci_config_teardown(struct i_hca_fm *, ddi_acc_handle_t *); 112*9e39c5baSBill Taylor static int i_hca_pio_start(dev_info_t *, struct i_hca_acc_handle *, 113*9e39c5baSBill Taylor hermon_test_t *); 114*9e39c5baSBill Taylor static int i_hca_pio_end(dev_info_t *, struct i_hca_acc_handle *, int *, 115*9e39c5baSBill Taylor hermon_test_t *); 116*9e39c5baSBill Taylor static struct i_hca_acc_handle *i_hca_get_acc_handle(struct i_hca_fm *, 117*9e39c5baSBill Taylor ddi_acc_handle_t); 118*9e39c5baSBill Taylor 119*9e39c5baSBill Taylor /* forward declaration for hermon_fm_{init, fini}() */ 120*9e39c5baSBill Taylor #ifdef FMA_TEST 121*9e39c5baSBill Taylor static void i_hca_test_init(mod_hash_t **, mod_hash_t **); 122*9e39c5baSBill Taylor static void i_hca_test_fini(mod_hash_t **, mod_hash_t **); 123*9e39c5baSBill Taylor #endif /* FMA_TEST */ 124*9e39c5baSBill Taylor 125*9e39c5baSBill Taylor /* 126*9e39c5baSBill Taylor * Hermon FM Functions 127*9e39c5baSBill Taylor * 128*9e39c5baSBill Taylor * These functions are based on the HCA FM common interface 129*9e39c5baSBill Taylor * defined below, but specific to the Hermon HCA FM capabilities. 130*9e39c5baSBill Taylor */ 131*9e39c5baSBill Taylor 132*9e39c5baSBill Taylor /* 133*9e39c5baSBill Taylor * void 134*9e39c5baSBill Taylor * hermon_hca_fm_init(hermon_state_t *state, hermon_hca_fm_t *hca) 135*9e39c5baSBill Taylor * 136*9e39c5baSBill Taylor * Overview 137*9e39c5baSBill Taylor * hermon_hca_fm_init() initializes the Hermon FM resources. 138*9e39c5baSBill Taylor * 139*9e39c5baSBill Taylor * Argument 140*9e39c5baSBill Taylor * state: pointer to Hermon state structure 141*9e39c5baSBill Taylor * hca: pointer to Hermon FM structure 142*9e39c5baSBill Taylor * 143*9e39c5baSBill Taylor * Return value 144*9e39c5baSBill Taylor * Nothing 145*9e39c5baSBill Taylor * 146*9e39c5baSBill Taylor * Caller's context 147*9e39c5baSBill Taylor * hermon_hca_fm_init() can be called in user or kernel context only. 148*9e39c5baSBill Taylor */ 149*9e39c5baSBill Taylor static void 150*9e39c5baSBill Taylor hermon_hca_fm_init(hermon_state_t *state, hermon_hca_fm_t *hca_fm) 151*9e39c5baSBill Taylor { 152*9e39c5baSBill Taylor state->hs_fm_hca_fm = hca_fm; 153*9e39c5baSBill Taylor i_hca_fm_init((struct i_hca_fm *)hca_fm); 154*9e39c5baSBill Taylor } 155*9e39c5baSBill Taylor 156*9e39c5baSBill Taylor 157*9e39c5baSBill Taylor /* 158*9e39c5baSBill Taylor * void 159*9e39c5baSBill Taylor * hermon_hca_fm_fini(hermon_state_t *state) 160*9e39c5baSBill Taylor * 161*9e39c5baSBill Taylor * Overview 162*9e39c5baSBill Taylor * hermon_hca_fm_fini() releases the Hermon FM resources. 163*9e39c5baSBill Taylor * 164*9e39c5baSBill Taylor * Argument 165*9e39c5baSBill Taylor * state: pointer to Hermon state structure 166*9e39c5baSBill Taylor * 167*9e39c5baSBill Taylor * Return value 168*9e39c5baSBill Taylor * Nothing 169*9e39c5baSBill Taylor * 170*9e39c5baSBill Taylor * Caller's context 171*9e39c5baSBill Taylor * hermon_hca_fm_fini() can be called in user or kernel context only. 172*9e39c5baSBill Taylor */ 173*9e39c5baSBill Taylor static void 174*9e39c5baSBill Taylor hermon_hca_fm_fini(hermon_state_t *state) 175*9e39c5baSBill Taylor { 176*9e39c5baSBill Taylor i_hca_fm_fini((struct i_hca_fm *)state->hs_fm_hca_fm); 177*9e39c5baSBill Taylor state->hs_fm_hca_fm = NULL; 178*9e39c5baSBill Taylor } 179*9e39c5baSBill Taylor 180*9e39c5baSBill Taylor /* 181*9e39c5baSBill Taylor * void 182*9e39c5baSBill Taylor * hermon_clr_state_nolock(hermon_state_t *state, int fm_state) 183*9e39c5baSBill Taylor * 184*9e39c5baSBill Taylor * Overview 185*9e39c5baSBill Taylor * hermon_clr_state() drops the specified state from Hermon FM state 186*9e39c5baSBill Taylor * without the mutex locks. 187*9e39c5baSBill Taylor * 188*9e39c5baSBill Taylor * Argument 189*9e39c5baSBill Taylor * state: pointer to Hermon state structure 190*9e39c5baSBill Taylor * fm_state: Hermon FM state, which is composed of: 191*9e39c5baSBill Taylor * HCA_NO_FM Hermom FM is not supported 192*9e39c5baSBill Taylor * HCA_PIO_FM PIO is fma-protected 193*9e39c5baSBill Taylor * HCA_DMA_FM DMA is fma-protected 194*9e39c5baSBill Taylor * HCA_EREPORT_FM FMA ereport is available 195*9e39c5baSBill Taylor * HCA_ERRCB_FM FMA error callback is supported 196*9e39c5baSBill Taylor * HCA_ATTCH_FM HCA FM attach mode 197*9e39c5baSBill Taylor * HCA_RUNTM_FM HCA FM runtime mode 198*9e39c5baSBill Taylor * 199*9e39c5baSBill Taylor * Return value 200*9e39c5baSBill Taylor * Nothing 201*9e39c5baSBill Taylor * 202*9e39c5baSBill Taylor * Caller's context 203*9e39c5baSBill Taylor * hermon_clr_state() can be called in user, kernel, interrupt context 204*9e39c5baSBill Taylor * or high interrupt context. 205*9e39c5baSBill Taylor */ 206*9e39c5baSBill Taylor void 207*9e39c5baSBill Taylor hermon_clr_state_nolock(hermon_state_t *state, int fm_state) 208*9e39c5baSBill Taylor { 209*9e39c5baSBill Taylor extern void membar_sync(void); 210*9e39c5baSBill Taylor 211*9e39c5baSBill Taylor state->hs_fm_state &= ~fm_state; 212*9e39c5baSBill Taylor membar_sync(); 213*9e39c5baSBill Taylor } 214*9e39c5baSBill Taylor 215*9e39c5baSBill Taylor 216*9e39c5baSBill Taylor /* 217*9e39c5baSBill Taylor * void 218*9e39c5baSBill Taylor * hermon_clr_state(hermon_state_t *state, int fm_state) 219*9e39c5baSBill Taylor * 220*9e39c5baSBill Taylor * Overview 221*9e39c5baSBill Taylor * hermon_clr_state() drops the specified state from Hermon FM state. 222*9e39c5baSBill Taylor * 223*9e39c5baSBill Taylor * Argument 224*9e39c5baSBill Taylor * state: pointer to Hermon state structure 225*9e39c5baSBill Taylor * fm_state: Hermon FM state, which is composed of: 226*9e39c5baSBill Taylor * HCA_NO_FM Hermom FM is not supported 227*9e39c5baSBill Taylor * HCA_PIO_FM PIO is fma-protected 228*9e39c5baSBill Taylor * HCA_DMA_FM DMA is fma-protected 229*9e39c5baSBill Taylor * HCA_EREPORT_FM FMA ereport is available 230*9e39c5baSBill Taylor * HCA_ERRCB_FM FMA error callback is supported 231*9e39c5baSBill Taylor * HCA_ATTCH_FM HCA FM attach mode 232*9e39c5baSBill Taylor * HCA_RUNTM_FM HCA FM runtime mode 233*9e39c5baSBill Taylor * 234*9e39c5baSBill Taylor * Return value 235*9e39c5baSBill Taylor * Nothing 236*9e39c5baSBill Taylor * 237*9e39c5baSBill Taylor * Caller's context 238*9e39c5baSBill Taylor * hermon_clr_state() can be called in user, kernel or interrupt context. 239*9e39c5baSBill Taylor */ 240*9e39c5baSBill Taylor static void 241*9e39c5baSBill Taylor hermon_clr_state(hermon_state_t *state, int fm_state) 242*9e39c5baSBill Taylor { 243*9e39c5baSBill Taylor ASSERT(fm_state != HCA_NO_FM); 244*9e39c5baSBill Taylor 245*9e39c5baSBill Taylor mutex_enter(&state->hs_fm_lock); 246*9e39c5baSBill Taylor hermon_clr_state_nolock(state, fm_state); 247*9e39c5baSBill Taylor mutex_exit(&state->hs_fm_lock); 248*9e39c5baSBill Taylor } 249*9e39c5baSBill Taylor 250*9e39c5baSBill Taylor 251*9e39c5baSBill Taylor /* 252*9e39c5baSBill Taylor * void 253*9e39c5baSBill Taylor * hermon_set_state(hermon_state_t *state, int fm_state) 254*9e39c5baSBill Taylor * 255*9e39c5baSBill Taylor * Overview 256*9e39c5baSBill Taylor * hermon_set_state() sets Hermon FM state. 257*9e39c5baSBill Taylor * 258*9e39c5baSBill Taylor * Argument 259*9e39c5baSBill Taylor * state: pointer to Hermon state structure 260*9e39c5baSBill Taylor * fm_state: Hermon FM state, which is composed of: 261*9e39c5baSBill Taylor * HCA_NO_FM Hermom FM is not supported 262*9e39c5baSBill Taylor * HCA_PIO_FM PIO is fma-protected 263*9e39c5baSBill Taylor * HCA_DMA_FM DMA is fma-protected 264*9e39c5baSBill Taylor * HCA_EREPORT_FM FMA ereport is available 265*9e39c5baSBill Taylor * HCA_ERRCB_FM FMA error callback is supported 266*9e39c5baSBill Taylor * HCA_ATTCH_FM HCA FM attach mode 267*9e39c5baSBill Taylor * HCA_RUNTM_FM HCA FM runtime mode 268*9e39c5baSBill Taylor * 269*9e39c5baSBill Taylor * Return value 270*9e39c5baSBill Taylor * Nothing 271*9e39c5baSBill Taylor * 272*9e39c5baSBill Taylor * Caller's context 273*9e39c5baSBill Taylor * hermon_set_state() can be called in user, kernel or interrupt context. 274*9e39c5baSBill Taylor */ 275*9e39c5baSBill Taylor static void 276*9e39c5baSBill Taylor hermon_set_state(hermon_state_t *state, int fm_state) 277*9e39c5baSBill Taylor { 278*9e39c5baSBill Taylor extern void membar_sync(void); 279*9e39c5baSBill Taylor 280*9e39c5baSBill Taylor mutex_enter(&state->hs_fm_lock); 281*9e39c5baSBill Taylor if (fm_state == HCA_NO_FM) { 282*9e39c5baSBill Taylor state->hs_fm_state = HCA_NO_FM; 283*9e39c5baSBill Taylor } else { 284*9e39c5baSBill Taylor state->hs_fm_state |= fm_state; 285*9e39c5baSBill Taylor } 286*9e39c5baSBill Taylor membar_sync(); 287*9e39c5baSBill Taylor mutex_exit(&state->hs_fm_lock); 288*9e39c5baSBill Taylor } 289*9e39c5baSBill Taylor 290*9e39c5baSBill Taylor 291*9e39c5baSBill Taylor /* 292*9e39c5baSBill Taylor * int 293*9e39c5baSBill Taylor * hermon_get_state(hermon_state_t *state) 294*9e39c5baSBill Taylor * 295*9e39c5baSBill Taylor * Overview 296*9e39c5baSBill Taylor * hermon_get_state() returns the current Hermon FM state. 297*9e39c5baSBill Taylor * 298*9e39c5baSBill Taylor * Argument 299*9e39c5baSBill Taylor * state: pointer to Hermon state structure 300*9e39c5baSBill Taylor * 301*9e39c5baSBill Taylor * Return value 302*9e39c5baSBill Taylor * fm_state: Hermon FM state, which is composed of: 303*9e39c5baSBill Taylor * HCA_NO_FM Hermom FM is not supported 304*9e39c5baSBill Taylor * HCA_PIO_FM PIO is fma-protected 305*9e39c5baSBill Taylor * HCA_DMA_FM DMA is fma-protected 306*9e39c5baSBill Taylor * HCA_EREPORT_FM FMA ereport is available 307*9e39c5baSBill Taylor * HCA_ERRCB_FM FMA error callback is supported 308*9e39c5baSBill Taylor * HCA_ATTCH_FM HCA FM attach mode 309*9e39c5baSBill Taylor * HCA_RUNTM_FM HCA FM runtime mode 310*9e39c5baSBill Taylor * 311*9e39c5baSBill Taylor * Caller's context 312*9e39c5baSBill Taylor * hermon_get_state() can be called in user, kernel or interrupt context. 313*9e39c5baSBill Taylor */ 314*9e39c5baSBill Taylor int 315*9e39c5baSBill Taylor hermon_get_state(hermon_state_t *state) 316*9e39c5baSBill Taylor { 317*9e39c5baSBill Taylor return (state->hs_fm_state); 318*9e39c5baSBill Taylor } 319*9e39c5baSBill Taylor 320*9e39c5baSBill Taylor 321*9e39c5baSBill Taylor /* 322*9e39c5baSBill Taylor * void 323*9e39c5baSBill Taylor * hermon_fm_init(hermon_state_t *state) 324*9e39c5baSBill Taylor * 325*9e39c5baSBill Taylor * Overview 326*9e39c5baSBill Taylor * hermon_fm_init() is a Hermon FM initialization function which registers 327*9e39c5baSBill Taylor * some FMA functions such as the ereport and the acc check capabilities 328*9e39c5baSBill Taylor * for Hermon. If the "fm_disable" property in /kernel/drv/hermon.conf is 329*9e39c5baSBill Taylor * defined (and/or its value is set), then the Hermon FM capabilities will 330*9e39c5baSBill Taylor * drop, and only the default capabilities (the ereport and error callback 331*9e39c5baSBill Taylor * capabilities) are available (and the action against HW errors is 332*9e39c5baSBill Taylor * issuing an ereport then panicking the system). 333*9e39c5baSBill Taylor * 334*9e39c5baSBill Taylor * Argument 335*9e39c5baSBill Taylor * state: pointer to Hermon state structure 336*9e39c5baSBill Taylor * 337*9e39c5baSBill Taylor * Return value 338*9e39c5baSBill Taylor * Nothing 339*9e39c5baSBill Taylor * 340*9e39c5baSBill Taylor * Caller's context 341*9e39c5baSBill Taylor * hermon_fm_init() can be called in user or kernel context only. 342*9e39c5baSBill Taylor */ 343*9e39c5baSBill Taylor void 344*9e39c5baSBill Taylor hermon_fm_init(hermon_state_t *state) 345*9e39c5baSBill Taylor { 346*9e39c5baSBill Taylor ddi_iblock_cookie_t iblk; 347*9e39c5baSBill Taylor 348*9e39c5baSBill Taylor /* 349*9e39c5baSBill Taylor * Check the "fm_disable" property. If it's defined, 350*9e39c5baSBill Taylor * use the Solaris FMA default action for Hermon. 351*9e39c5baSBill Taylor */ 352*9e39c5baSBill Taylor if (ddi_getprop(DDI_DEV_T_NONE, state->hs_dip, DDI_PROP_DONTPASS, 353*9e39c5baSBill Taylor "fm_disable", 0) != 0) { 354*9e39c5baSBill Taylor state->hs_fm_disable = 1; 355*9e39c5baSBill Taylor } 356*9e39c5baSBill Taylor 357*9e39c5baSBill Taylor /* If hs_fm_diable is set, then skip the rest */ 358*9e39c5baSBill Taylor if (state->hs_fm_disable) { 359*9e39c5baSBill Taylor hermon_set_state(state, HCA_NO_FM); 360*9e39c5baSBill Taylor return; 361*9e39c5baSBill Taylor } 362*9e39c5baSBill Taylor 363*9e39c5baSBill Taylor /* Set the Hermon FM attach mode */ 364*9e39c5baSBill Taylor hermon_set_state(state, HCA_ATTCH_FM); 365*9e39c5baSBill Taylor 366*9e39c5baSBill Taylor /* Initialize the Solaris FMA capabilities for the Hermon FM support */ 367*9e39c5baSBill Taylor state->hs_fm_capabilities = ddi_prop_get_int(DDI_DEV_T_ANY, 368*9e39c5baSBill Taylor state->hs_dip, DDI_PROP_DONTPASS, fm_cap, 369*9e39c5baSBill Taylor DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE); 370*9e39c5baSBill Taylor 371*9e39c5baSBill Taylor /* 372*9e39c5baSBill Taylor * The Hermon FM uses the ereport and acc check capabilites only, 373*9e39c5baSBill Taylor * but both of them should be available. If either is not, turn 374*9e39c5baSBill Taylor * hs_fm_disable on and behave in the same way as the "fm_diable" 375*9e39c5baSBill Taylor * property is set. 376*9e39c5baSBill Taylor */ 377*9e39c5baSBill Taylor if (state->hs_fm_capabilities != 378*9e39c5baSBill Taylor (DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE)) { 379*9e39c5baSBill Taylor state->hs_fm_disable = 1; 380*9e39c5baSBill Taylor hermon_set_state(state, HCA_NO_FM); 381*9e39c5baSBill Taylor HERMON_ATTACH_MSG(state->hs_attach_buf, 382*9e39c5baSBill Taylor "Hermon FM capability fails"); 383*9e39c5baSBill Taylor return; 384*9e39c5baSBill Taylor } 385*9e39c5baSBill Taylor 386*9e39c5baSBill Taylor /* Initialize the HCA FM resources */ 387*9e39c5baSBill Taylor hermon_hca_fm_init(state, &hca_fm); 388*9e39c5baSBill Taylor 389*9e39c5baSBill Taylor /* Initialize the fm state lock */ 390*9e39c5baSBill Taylor mutex_init(&state->hs_fm_lock, NULL, MUTEX_DRIVER, NULL); 391*9e39c5baSBill Taylor 392*9e39c5baSBill Taylor /* Register the capabilities with the IO fault services */ 393*9e39c5baSBill Taylor ddi_fm_init(state->hs_dip, &state->hs_fm_capabilities, &iblk); 394*9e39c5baSBill Taylor 395*9e39c5baSBill Taylor /* Set up the pci ereport capabilities if the ereport is capable */ 396*9e39c5baSBill Taylor if (DDI_FM_EREPORT_CAP(state->hs_fm_capabilities)) { 397*9e39c5baSBill Taylor pci_ereport_setup(state->hs_dip); 398*9e39c5baSBill Taylor } 399*9e39c5baSBill Taylor 400*9e39c5baSBill Taylor /* Set the Hermon FM state */ 401*9e39c5baSBill Taylor hermon_set_state(state, HCA_PIO_FM | HCA_EREPORT_FM); 402*9e39c5baSBill Taylor 403*9e39c5baSBill Taylor #ifdef FMA_TEST 404*9e39c5baSBill Taylor i_hca_test_init(&state->hs_fm_test_hash, &state->hs_fm_id_hash); 405*9e39c5baSBill Taylor #endif /* FMA_TEST */ 406*9e39c5baSBill Taylor } 407*9e39c5baSBill Taylor 408*9e39c5baSBill Taylor 409*9e39c5baSBill Taylor /* 410*9e39c5baSBill Taylor * void 411*9e39c5baSBill Taylor * hermon_fm_fini(hermon_state_t *state) 412*9e39c5baSBill Taylor * 413*9e39c5baSBill Taylor * Overview 414*9e39c5baSBill Taylor * hermon_fm_fini() is a Hermon FM finalization function which de-registers 415*9e39c5baSBill Taylor * Solaris FMA functions set to Hermon. 416*9e39c5baSBill Taylor * 417*9e39c5baSBill Taylor * Argument 418*9e39c5baSBill Taylor * state: pointer to Hermon state structure 419*9e39c5baSBill Taylor * 420*9e39c5baSBill Taylor * Return value 421*9e39c5baSBill Taylor * Nothing 422*9e39c5baSBill Taylor * 423*9e39c5baSBill Taylor * Caller's context 424*9e39c5baSBill Taylor * hermon_fm_fini() can be called in user or kernel context only. 425*9e39c5baSBill Taylor */ 426*9e39c5baSBill Taylor void 427*9e39c5baSBill Taylor hermon_fm_fini(hermon_state_t *state) 428*9e39c5baSBill Taylor { 429*9e39c5baSBill Taylor /* 430*9e39c5baSBill Taylor * If hermon_fm_diable is set or there is no FM service provided, 431*9e39c5baSBill Taylor * then skip the rest. 432*9e39c5baSBill Taylor */ 433*9e39c5baSBill Taylor if (state->hs_fm_disable || hermon_get_state(state) == HCA_NO_FM) { 434*9e39c5baSBill Taylor return; 435*9e39c5baSBill Taylor } 436*9e39c5baSBill Taylor 437*9e39c5baSBill Taylor ASSERT(!(hermon_get_state(state) & HCA_ERRCB_FM)); 438*9e39c5baSBill Taylor 439*9e39c5baSBill Taylor #ifdef FMA_TEST 440*9e39c5baSBill Taylor i_hca_test_fini(&state->hs_fm_test_hash, &state->hs_fm_id_hash); 441*9e39c5baSBill Taylor #endif /* FMA_TEST */ 442*9e39c5baSBill Taylor 443*9e39c5baSBill Taylor /* Set the Hermon FM state to no support */ 444*9e39c5baSBill Taylor hermon_set_state(state, HCA_NO_FM); 445*9e39c5baSBill Taylor 446*9e39c5baSBill Taylor /* Release HCA FM resources */ 447*9e39c5baSBill Taylor hermon_hca_fm_fini(state); 448*9e39c5baSBill Taylor 449*9e39c5baSBill Taylor /* 450*9e39c5baSBill Taylor * Release any resources allocated by pci_ereport_setup() 451*9e39c5baSBill Taylor */ 452*9e39c5baSBill Taylor if (DDI_FM_EREPORT_CAP(state->hs_fm_capabilities)) { 453*9e39c5baSBill Taylor pci_ereport_teardown(state->hs_dip); 454*9e39c5baSBill Taylor } 455*9e39c5baSBill Taylor 456*9e39c5baSBill Taylor /* De-register the Hermon FM from the IO fault services */ 457*9e39c5baSBill Taylor ddi_fm_fini(state->hs_dip); 458*9e39c5baSBill Taylor } 459*9e39c5baSBill Taylor 460*9e39c5baSBill Taylor 461*9e39c5baSBill Taylor /* 462*9e39c5baSBill Taylor * int 463*9e39c5baSBill Taylor * hermon_fm_ereport_init(hermon_state_t *state) 464*9e39c5baSBill Taylor * 465*9e39c5baSBill Taylor * Overview 466*9e39c5baSBill Taylor * hermon_fm_ereport_init() changes the Hermon FM state to the ereport 467*9e39c5baSBill Taylor * only mode during the driver attach. 468*9e39c5baSBill Taylor * 469*9e39c5baSBill Taylor * Argument 470*9e39c5baSBill Taylor * state: pointer to Hermon state structure 471*9e39c5baSBill Taylor * 472*9e39c5baSBill Taylor * Return value 473*9e39c5baSBill Taylor * DDI_SUCCESS 474*9e39c5baSBill Taylor * DDI_FAILURE 475*9e39c5baSBill Taylor * 476*9e39c5baSBill Taylor * Caller's context 477*9e39c5baSBill Taylor * hermon_fm_ereport_init() can be called in user or kernel context only. 478*9e39c5baSBill Taylor */ 479*9e39c5baSBill Taylor int 480*9e39c5baSBill Taylor hermon_fm_ereport_init(hermon_state_t *state) 481*9e39c5baSBill Taylor { 482*9e39c5baSBill Taylor ddi_iblock_cookie_t iblk; 483*9e39c5baSBill Taylor hermon_cfg_profile_t *cfgprof; 484*9e39c5baSBill Taylor hermon_hw_querydevlim_t *devlim; 485*9e39c5baSBill Taylor hermon_rsrc_hw_entry_info_t entry_info; 486*9e39c5baSBill Taylor hermon_rsrc_pool_info_t *rsrc_pool; 487*9e39c5baSBill Taylor uint64_t offset, num, max, num_prealloc; 488*9e39c5baSBill Taylor ddi_device_acc_attr_t dev_attr = { 489*9e39c5baSBill Taylor DDI_DEVICE_ATTR_V0, 490*9e39c5baSBill Taylor DDI_STRUCTURE_LE_ACC, 491*9e39c5baSBill Taylor DDI_STRICTORDER_ACC, 492*9e39c5baSBill Taylor DDI_DEFAULT_ACC 493*9e39c5baSBill Taylor }; 494*9e39c5baSBill Taylor char *rsrc_name; 495*9e39c5baSBill Taylor extern void membar_sync(void); 496*9e39c5baSBill Taylor 497*9e39c5baSBill Taylor /* Stop the poll thread while the FM state is being changed */ 498*9e39c5baSBill Taylor state->hs_fm_poll_suspend = B_TRUE; 499*9e39c5baSBill Taylor membar_sync(); 500*9e39c5baSBill Taylor 501*9e39c5baSBill Taylor /* 502*9e39c5baSBill Taylor * Disable the Hermon interrupt after the interrupt capability flag 503*9e39c5baSBill Taylor * is checked. 504*9e39c5baSBill Taylor */ 505*9e39c5baSBill Taylor if (state->hs_intrmsi_cap & DDI_INTR_FLAG_BLOCK) { 506*9e39c5baSBill Taylor if (ddi_intr_block_disable 507*9e39c5baSBill Taylor (&state->hs_intrmsi_hdl[0], 1) != DDI_SUCCESS) { 508*9e39c5baSBill Taylor return (DDI_FAILURE); 509*9e39c5baSBill Taylor } 510*9e39c5baSBill Taylor } else { 511*9e39c5baSBill Taylor if (ddi_intr_disable 512*9e39c5baSBill Taylor (state->hs_intrmsi_hdl[0]) != DDI_SUCCESS) { 513*9e39c5baSBill Taylor return (DDI_FAILURE); 514*9e39c5baSBill Taylor } 515*9e39c5baSBill Taylor } 516*9e39c5baSBill Taylor 517*9e39c5baSBill Taylor /* 518*9e39c5baSBill Taylor * Release any resources allocated by pci_ereport_setup() 519*9e39c5baSBill Taylor */ 520*9e39c5baSBill Taylor if (DDI_FM_EREPORT_CAP(state->hs_fm_capabilities)) { 521*9e39c5baSBill Taylor pci_ereport_teardown(state->hs_dip); 522*9e39c5baSBill Taylor } 523*9e39c5baSBill Taylor 524*9e39c5baSBill Taylor /* De-register the Hermon FM from the IO fault services */ 525*9e39c5baSBill Taylor ddi_fm_fini(state->hs_dip); 526*9e39c5baSBill Taylor 527*9e39c5baSBill Taylor /* Re-initialize fm ereport with the ereport only */ 528*9e39c5baSBill Taylor state->hs_fm_capabilities = ddi_prop_get_int(DDI_DEV_T_ANY, 529*9e39c5baSBill Taylor state->hs_dip, DDI_PROP_DONTPASS, fm_cap, 530*9e39c5baSBill Taylor DDI_FM_EREPORT_CAPABLE); 531*9e39c5baSBill Taylor 532*9e39c5baSBill Taylor /* 533*9e39c5baSBill Taylor * Now that the Hermon FM uses the ereport capability only, 534*9e39c5baSBill Taylor * If it's not set, turn hs_fm_disable on and behave in the 535*9e39c5baSBill Taylor * same way as the "fm_diable" property is set. 536*9e39c5baSBill Taylor */ 537*9e39c5baSBill Taylor if (state->hs_fm_capabilities != DDI_FM_EREPORT_CAPABLE) { 538*9e39c5baSBill Taylor HERMON_ATTACH_MSG(state->hs_attach_buf, 539*9e39c5baSBill Taylor "Hermon FM ereport fails (ereport mode)"); 540*9e39c5baSBill Taylor goto error; 541*9e39c5baSBill Taylor } 542*9e39c5baSBill Taylor 543*9e39c5baSBill Taylor /* Re-register the ereport capability with the IO fault services */ 544*9e39c5baSBill Taylor ddi_fm_init(state->hs_dip, &state->hs_fm_capabilities, &iblk); 545*9e39c5baSBill Taylor 546*9e39c5baSBill Taylor /* Initialize the pci ereport capabilities if the ereport is capable */ 547*9e39c5baSBill Taylor if (DDI_FM_EREPORT_CAP(state->hs_fm_capabilities)) { 548*9e39c5baSBill Taylor pci_ereport_setup(state->hs_dip); 549*9e39c5baSBill Taylor } 550*9e39c5baSBill Taylor 551*9e39c5baSBill Taylor /* Setup for PCI config read/write of HCA device */ 552*9e39c5baSBill Taylor if (pci_config_setup(state->hs_dip, &state->hs_reg_pcihdl) != 553*9e39c5baSBill Taylor DDI_SUCCESS) { 554*9e39c5baSBill Taylor HERMON_ATTACH_MSG(state->hs_attach_buf, 555*9e39c5baSBill Taylor "PCI config mapping fails (ereport mode)"); 556*9e39c5baSBill Taylor goto error; 557*9e39c5baSBill Taylor } 558*9e39c5baSBill Taylor 559*9e39c5baSBill Taylor /* Allocate the regular access handle for MSI-X tables */ 560*9e39c5baSBill Taylor if (ddi_regs_map_setup(state->hs_dip, state->hs_msix_tbl_rnumber, 561*9e39c5baSBill Taylor (caddr_t *)&state->hs_msix_tbl_addr, state->hs_msix_tbl_offset, 562*9e39c5baSBill Taylor state->hs_msix_tbl_size, &dev_attr, 563*9e39c5baSBill Taylor &state->hs_reg_msix_tblhdl) != DDI_SUCCESS) { 564*9e39c5baSBill Taylor HERMON_ATTACH_MSG(state->hs_attach_buf, 565*9e39c5baSBill Taylor "MSI-X Table mapping fails (ereport mode)"); 566*9e39c5baSBill Taylor goto error; 567*9e39c5baSBill Taylor } 568*9e39c5baSBill Taylor 569*9e39c5baSBill Taylor /* Allocate the regular access handle for MSI-X PBA */ 570*9e39c5baSBill Taylor if (ddi_regs_map_setup(state->hs_dip, state->hs_msix_pba_rnumber, 571*9e39c5baSBill Taylor (caddr_t *)&state->hs_msix_pba_addr, state->hs_msix_pba_offset, 572*9e39c5baSBill Taylor state->hs_msix_pba_size, &dev_attr, 573*9e39c5baSBill Taylor &state->hs_reg_msix_pbahdl) != DDI_SUCCESS) { 574*9e39c5baSBill Taylor HERMON_ATTACH_MSG(state->hs_attach_buf, 575*9e39c5baSBill Taylor "MSI-X PBA mapping fails (ereport mode)"); 576*9e39c5baSBill Taylor goto error; 577*9e39c5baSBill Taylor } 578*9e39c5baSBill Taylor 579*9e39c5baSBill Taylor /* Allocate the regular access handle for Hermon CMD I/O space */ 580*9e39c5baSBill Taylor if (ddi_regs_map_setup(state->hs_dip, HERMON_CMD_BAR, 581*9e39c5baSBill Taylor &state->hs_reg_cmd_baseaddr, 0, 0, &state->hs_reg_accattr, 582*9e39c5baSBill Taylor &state->hs_reg_cmdhdl) != DDI_SUCCESS) { 583*9e39c5baSBill Taylor HERMON_ATTACH_MSG(state->hs_attach_buf, 584*9e39c5baSBill Taylor "CMD_BAR mapping fails (ereport mode)"); 585*9e39c5baSBill Taylor goto error; 586*9e39c5baSBill Taylor } 587*9e39c5baSBill Taylor 588*9e39c5baSBill Taylor /* Reset the host command register */ 589*9e39c5baSBill Taylor state->hs_cmd_regs.hcr = (hermon_hw_hcr_t *) 590*9e39c5baSBill Taylor ((uintptr_t)state->hs_reg_cmd_baseaddr + HERMON_CMD_HCR_OFFSET); 591*9e39c5baSBill Taylor 592*9e39c5baSBill Taylor /* Reset the software reset register */ 593*9e39c5baSBill Taylor state->hs_cmd_regs.sw_reset = (uint32_t *) 594*9e39c5baSBill Taylor ((uintptr_t)state->hs_reg_cmd_baseaddr + 595*9e39c5baSBill Taylor HERMON_CMD_SW_RESET_OFFSET); 596*9e39c5baSBill Taylor 597*9e39c5baSBill Taylor /* Reset the software reset register semaphore */ 598*9e39c5baSBill Taylor state->hs_cmd_regs.sw_semaphore = (uint32_t *) 599*9e39c5baSBill Taylor ((uintptr_t)state->hs_reg_cmd_baseaddr + 600*9e39c5baSBill Taylor HERMON_CMD_SW_SEMAPHORE_OFFSET); 601*9e39c5baSBill Taylor 602*9e39c5baSBill Taylor /* Calculate the clear interrupt register offset */ 603*9e39c5baSBill Taylor offset = state->hs_fw.clr_intr_offs & HERMON_CMD_OFFSET_MASK; 604*9e39c5baSBill Taylor 605*9e39c5baSBill Taylor /* Reset the clear interrupt address */ 606*9e39c5baSBill Taylor state->hs_cmd_regs.clr_intr = (uint64_t *) 607*9e39c5baSBill Taylor (uintptr_t)(state->hs_reg_cmd_baseaddr + offset); 608*9e39c5baSBill Taylor 609*9e39c5baSBill Taylor /* Reset the internal error buffer address */ 610*9e39c5baSBill Taylor state->hs_cmd_regs.fw_err_buf = (uint32_t *)(uintptr_t) 611*9e39c5baSBill Taylor (state->hs_reg_cmd_baseaddr + state->hs_fw.error_buf_addr); 612*9e39c5baSBill Taylor 613*9e39c5baSBill Taylor /* Check if the blue flame is enabled, and set the offset value */ 614*9e39c5baSBill Taylor if (state->hs_devlim.blu_flm) { 615*9e39c5baSBill Taylor offset = (uint64_t)1 << 616*9e39c5baSBill Taylor (state->hs_devlim.log_max_uar_sz + 20); 617*9e39c5baSBill Taylor } else { 618*9e39c5baSBill Taylor offset = 0; 619*9e39c5baSBill Taylor } 620*9e39c5baSBill Taylor 621*9e39c5baSBill Taylor /* Allocate the regular access handle for Hermon UAR I/O space */ 622*9e39c5baSBill Taylor if (ddi_regs_map_setup(state->hs_dip, HERMON_UAR_BAR, 623*9e39c5baSBill Taylor &state->hs_reg_uar_baseaddr, 0, offset, 624*9e39c5baSBill Taylor &state->hs_reg_accattr, &state->hs_reg_uarhdl) != DDI_SUCCESS) { 625*9e39c5baSBill Taylor HERMON_ATTACH_MSG(state->hs_attach_buf, 626*9e39c5baSBill Taylor "UAR BAR mapping fails (ereport mode)"); 627*9e39c5baSBill Taylor goto error; 628*9e39c5baSBill Taylor } 629*9e39c5baSBill Taylor 630*9e39c5baSBill Taylor /* Drop the Hermon FM Attach Mode */ 631*9e39c5baSBill Taylor hermon_clr_state(state, HCA_ATTCH_FM); 632*9e39c5baSBill Taylor 633*9e39c5baSBill Taylor /* Set the Hermon FM Runtime Mode */ 634*9e39c5baSBill Taylor hermon_set_state(state, HCA_RUNTM_FM); 635*9e39c5baSBill Taylor 636*9e39c5baSBill Taylor /* Free up Hermon UAR page #1 */ 637*9e39c5baSBill Taylor hermon_rsrc_free(state, &state->hs_uarkpg_rsrc); 638*9e39c5baSBill Taylor 639*9e39c5baSBill Taylor /* Free up the UAR pool */ 640*9e39c5baSBill Taylor entry_info.hwi_rsrcpool = &state->hs_rsrc_hdl[HERMON_UARPG]; 641*9e39c5baSBill Taylor hermon_rsrc_hw_entries_fini(state, &entry_info); 642*9e39c5baSBill Taylor 643*9e39c5baSBill Taylor /* Re-allocate the UAR pool */ 644*9e39c5baSBill Taylor cfgprof = state->hs_cfg_profile; 645*9e39c5baSBill Taylor devlim = &state->hs_devlim; 646*9e39c5baSBill Taylor num = ((uint64_t)1 << cfgprof->cp_log_num_uar); 647*9e39c5baSBill Taylor max = num; 648*9e39c5baSBill Taylor num_prealloc = max(devlim->num_rsvd_uar, 128); 649*9e39c5baSBill Taylor rsrc_pool = &state->hs_rsrc_hdl[HERMON_UARPG]; 650*9e39c5baSBill Taylor rsrc_pool->rsrc_type = HERMON_UARPG; 651*9e39c5baSBill Taylor rsrc_pool->rsrc_loc = HERMON_IN_UAR; 652*9e39c5baSBill Taylor rsrc_pool->rsrc_pool_size = (num << PAGESHIFT); 653*9e39c5baSBill Taylor rsrc_pool->rsrc_shift = PAGESHIFT; 654*9e39c5baSBill Taylor rsrc_pool->rsrc_quantum = (uint_t)PAGESIZE; 655*9e39c5baSBill Taylor rsrc_pool->rsrc_align = PAGESIZE; 656*9e39c5baSBill Taylor rsrc_pool->rsrc_state = state; 657*9e39c5baSBill Taylor rsrc_pool->rsrc_start = (void *)state->hs_reg_uar_baseaddr; 658*9e39c5baSBill Taylor rsrc_name = (char *)kmem_zalloc(HERMON_RSRC_NAME_MAXLEN, KM_SLEEP); 659*9e39c5baSBill Taylor HERMON_RSRC_NAME(rsrc_name, HERMON_UAR_PAGE_VMEM_RUNTM); 660*9e39c5baSBill Taylor entry_info.hwi_num = num; 661*9e39c5baSBill Taylor entry_info.hwi_max = max; 662*9e39c5baSBill Taylor entry_info.hwi_prealloc = num_prealloc; 663*9e39c5baSBill Taylor entry_info.hwi_rsrcpool = rsrc_pool; 664*9e39c5baSBill Taylor entry_info.hwi_rsrcname = rsrc_name; 665*9e39c5baSBill Taylor if (hermon_rsrc_hw_entries_init(state, &entry_info) != DDI_SUCCESS) { 666*9e39c5baSBill Taylor kmem_free(rsrc_name, HERMON_RSRC_NAME_MAXLEN); 667*9e39c5baSBill Taylor goto error; 668*9e39c5baSBill Taylor } 669*9e39c5baSBill Taylor kmem_free(rsrc_name, HERMON_RSRC_NAME_MAXLEN); 670*9e39c5baSBill Taylor 671*9e39c5baSBill Taylor /* Re-allocate the kernel UAR page */ 672*9e39c5baSBill Taylor if (hermon_rsrc_alloc(state, HERMON_UARPG, 1, HERMON_SLEEP, 673*9e39c5baSBill Taylor &state->hs_uarkpg_rsrc) != DDI_SUCCESS) { 674*9e39c5baSBill Taylor goto error; 675*9e39c5baSBill Taylor } 676*9e39c5baSBill Taylor 677*9e39c5baSBill Taylor /* Setup pointer to kernel UAR page */ 678*9e39c5baSBill Taylor state->hs_uar = (hermon_hw_uar_t *)state->hs_uarkpg_rsrc->hr_addr; 679*9e39c5baSBill Taylor 680*9e39c5baSBill Taylor /* Now drop the the Hermon PIO FM */ 681*9e39c5baSBill Taylor hermon_clr_state(state, HCA_PIO_FM); 682*9e39c5baSBill Taylor 683*9e39c5baSBill Taylor /* Release the MSI-X Table access handle */ 684*9e39c5baSBill Taylor if (state->hs_fm_msix_tblhdl) { 685*9e39c5baSBill Taylor hermon_regs_map_free(state, &state->hs_fm_msix_tblhdl); 686*9e39c5baSBill Taylor state->hs_fm_msix_tblhdl = NULL; 687*9e39c5baSBill Taylor } 688*9e39c5baSBill Taylor 689*9e39c5baSBill Taylor /* Release the MSI-X PBA access handle */ 690*9e39c5baSBill Taylor if (state->hs_fm_msix_pbahdl) { 691*9e39c5baSBill Taylor hermon_regs_map_free(state, &state->hs_fm_msix_pbahdl); 692*9e39c5baSBill Taylor state->hs_fm_msix_pbahdl = NULL; 693*9e39c5baSBill Taylor } 694*9e39c5baSBill Taylor 695*9e39c5baSBill Taylor /* Release the pci config space access handle */ 696*9e39c5baSBill Taylor if (state->hs_fm_pcihdl) { 697*9e39c5baSBill Taylor hermon_regs_map_free(state, &state->hs_fm_pcihdl); 698*9e39c5baSBill Taylor state->hs_fm_pcihdl = NULL; 699*9e39c5baSBill Taylor } 700*9e39c5baSBill Taylor 701*9e39c5baSBill Taylor /* Release the cmd protected access handle */ 702*9e39c5baSBill Taylor if (state->hs_fm_cmdhdl) { 703*9e39c5baSBill Taylor hermon_regs_map_free(state, &state->hs_fm_cmdhdl); 704*9e39c5baSBill Taylor state->hs_fm_cmdhdl = NULL; 705*9e39c5baSBill Taylor } 706*9e39c5baSBill Taylor 707*9e39c5baSBill Taylor /* Release the uar fma-protected access handle */ 708*9e39c5baSBill Taylor if (state->hs_fm_uarhdl) { 709*9e39c5baSBill Taylor hermon_regs_map_free(state, &state->hs_fm_uarhdl); 710*9e39c5baSBill Taylor state->hs_fm_uarhdl = NULL; 711*9e39c5baSBill Taylor } 712*9e39c5baSBill Taylor 713*9e39c5baSBill Taylor /* Enable the Hermon interrupt again */ 714*9e39c5baSBill Taylor if (state->hs_intrmsi_cap & DDI_INTR_FLAG_BLOCK) { 715*9e39c5baSBill Taylor if (ddi_intr_block_enable 716*9e39c5baSBill Taylor (&state->hs_intrmsi_hdl[0], 1) != DDI_SUCCESS) { 717*9e39c5baSBill Taylor return (DDI_FAILURE); 718*9e39c5baSBill Taylor } 719*9e39c5baSBill Taylor } else { 720*9e39c5baSBill Taylor if (ddi_intr_enable 721*9e39c5baSBill Taylor (state->hs_intrmsi_hdl[0]) != DDI_SUCCESS) { 722*9e39c5baSBill Taylor return (DDI_FAILURE); 723*9e39c5baSBill Taylor } 724*9e39c5baSBill Taylor } 725*9e39c5baSBill Taylor 726*9e39c5baSBill Taylor /* Restart the poll thread */ 727*9e39c5baSBill Taylor state->hs_fm_poll_suspend = B_FALSE; 728*9e39c5baSBill Taylor 729*9e39c5baSBill Taylor return (DDI_SUCCESS); 730*9e39c5baSBill Taylor 731*9e39c5baSBill Taylor error: 732*9e39c5baSBill Taylor /* Enable the Hermon interrupt again */ 733*9e39c5baSBill Taylor if (state->hs_intrmsi_cap & DDI_INTR_FLAG_BLOCK) { 734*9e39c5baSBill Taylor (void) ddi_intr_block_enable(&state->hs_intrmsi_hdl[0], 1); 735*9e39c5baSBill Taylor } else { 736*9e39c5baSBill Taylor (void) ddi_intr_enable(state->hs_intrmsi_hdl[0]); 737*9e39c5baSBill Taylor } 738*9e39c5baSBill Taylor return (DDI_FAILURE); 739*9e39c5baSBill Taylor } 740*9e39c5baSBill Taylor 741*9e39c5baSBill Taylor 742*9e39c5baSBill Taylor /* 743*9e39c5baSBill Taylor * int 744*9e39c5baSBill Taylor * hermon_regs_map_setup(hermon_state_t *state, uint_t rnumber, caddr_t *addrp, 745*9e39c5baSBill Taylor * offset_t offset, offset_t len, ddi_device_acc_attr_t *accattrp, 746*9e39c5baSBill Taylor * ddi_acc_handle_t *handle) 747*9e39c5baSBill Taylor * 748*9e39c5baSBill Taylor * Overview 749*9e39c5baSBill Taylor * This is a wrapper function of i_hca_regs_map_setup() for Hermon FM so 750*9e39c5baSBill Taylor * that it calls i_hca_regs_map_setup() inside after it checks the 751*9e39c5baSBill Taylor * "fm_disable" configuration property. If the "fm_disable" is described 752*9e39c5baSBill Taylor * in /kernel/drv/hermon.conf, the function calls ddi_regs_map_setup() 753*9e39c5baSBill Taylor * directly instead. 754*9e39c5baSBill Taylor * See i_hca_regs_map_setup() in detail. 755*9e39c5baSBill Taylor * 756*9e39c5baSBill Taylor * Argument 757*9e39c5baSBill Taylor * state: pointer to Hermon state structure 758*9e39c5baSBill Taylor * rnumber: index number to the register address space set 759*9e39c5baSBill Taylor * addrp: platform-dependent value (same as ddi_regs_map_setup()) 760*9e39c5baSBill Taylor * offset: offset into the register address space 761*9e39c5baSBill Taylor * len: address space length to be mapped 762*9e39c5baSBill Taylor * accattrp: pointer to device access attribute structure 763*9e39c5baSBill Taylor * handle: pointer to ddi_acc_handle_t used for HCA FM 764*9e39c5baSBill Taylor * 765*9e39c5baSBill Taylor * Return value 766*9e39c5baSBill Taylor * ddi function status value which are: 767*9e39c5baSBill Taylor * DDI_SUCCESS 768*9e39c5baSBill Taylor * DDI_FAILURE 769*9e39c5baSBill Taylor * DDI_ME_RNUMBER_RNGE 770*9e39c5baSBill Taylor * DDI_REGS_ACC_CONFLICT 771*9e39c5baSBill Taylor * 772*9e39c5baSBill Taylor * Caller's context 773*9e39c5baSBill Taylor * hermon_regs_map_setup() can be called in user or kernel context only. 774*9e39c5baSBill Taylor */ 775*9e39c5baSBill Taylor int 776*9e39c5baSBill Taylor hermon_regs_map_setup(hermon_state_t *state, uint_t rnumber, caddr_t *addrp, 777*9e39c5baSBill Taylor offset_t offset, offset_t len, ddi_device_acc_attr_t *accattrp, 778*9e39c5baSBill Taylor ddi_acc_handle_t *handle) 779*9e39c5baSBill Taylor { 780*9e39c5baSBill Taylor if (state->hs_fm_disable) { 781*9e39c5baSBill Taylor return (ddi_regs_map_setup(state->hs_dip, rnumber, addrp, 782*9e39c5baSBill Taylor offset, len, accattrp, handle)); 783*9e39c5baSBill Taylor } else { 784*9e39c5baSBill Taylor return (i_hca_regs_map_setup(state->hs_fm_hca_fm, state->hs_dip, 785*9e39c5baSBill Taylor rnumber, addrp, offset, len, accattrp, handle)); 786*9e39c5baSBill Taylor } 787*9e39c5baSBill Taylor } 788*9e39c5baSBill Taylor 789*9e39c5baSBill Taylor 790*9e39c5baSBill Taylor /* 791*9e39c5baSBill Taylor * void 792*9e39c5baSBill Taylor * hermon_regs_map_free(hermon_state_t *state, ddi_acc_handle_t *handlep) 793*9e39c5baSBill Taylor * 794*9e39c5baSBill Taylor * Overview 795*9e39c5baSBill Taylor * This is a wrapper function of i_hca_regs_map_free() for Hermon FM so 796*9e39c5baSBill Taylor * that it calls i_hca_regs_map_free() inside after it checks the 797*9e39c5baSBill Taylor * "fm_disable" configuration property. If the "fm_disable" is described 798*9e39c5baSBill Taylor * in /kernel/drv/hermon.conf, the function calls ddi_regs_map_fre() 799*9e39c5baSBill Taylor * directly instead. See i_hca_regs_map_free() in detail. 800*9e39c5baSBill Taylor * 801*9e39c5baSBill Taylor * Argument 802*9e39c5baSBill Taylor * state: pointer to Hermon state structure 803*9e39c5baSBill Taylor * handle: pointer to ddi_acc_handle_t used for HCA FM 804*9e39c5baSBill Taylor * 805*9e39c5baSBill Taylor * Return value 806*9e39c5baSBill Taylor * Nothing 807*9e39c5baSBill Taylor * 808*9e39c5baSBill Taylor * Caller's context 809*9e39c5baSBill Taylor * hermon_regs_map_free() can be called in user or kernel context only. 810*9e39c5baSBill Taylor * 811*9e39c5baSBill Taylor * Note that the handle passed to hermon_regs_map_free() is NULL-cleared 812*9e39c5baSBill Taylor * after this function is called. 813*9e39c5baSBill Taylor */ 814*9e39c5baSBill Taylor void 815*9e39c5baSBill Taylor hermon_regs_map_free(hermon_state_t *state, ddi_acc_handle_t *handle) 816*9e39c5baSBill Taylor { 817*9e39c5baSBill Taylor if (state->hs_fm_disable) { 818*9e39c5baSBill Taylor ddi_regs_map_free(handle); 819*9e39c5baSBill Taylor *handle = NULL; 820*9e39c5baSBill Taylor } else { 821*9e39c5baSBill Taylor i_hca_regs_map_free(state->hs_fm_hca_fm, handle); 822*9e39c5baSBill Taylor } 823*9e39c5baSBill Taylor } 824*9e39c5baSBill Taylor 825*9e39c5baSBill Taylor 826*9e39c5baSBill Taylor /* 827*9e39c5baSBill Taylor * int 828*9e39c5baSBill Taylor * hermon_pci_config_setup(hermon_state_t *state, ddi_acc_handle_t *handle) 829*9e39c5baSBill Taylor * 830*9e39c5baSBill Taylor * Overview 831*9e39c5baSBill Taylor * This is a wrapper function of i_hca_pci_config_setup() for Hermon FM so 832*9e39c5baSBill Taylor * that it calls i_hca_pci_config_setup() inside after it checks the 833*9e39c5baSBill Taylor * "fm-disable" configuration property. If the "fm_disable" is described 834*9e39c5baSBill Taylor * in /kernel/drv/hermon.conf, the function calls pci_config_setup() 835*9e39c5baSBill Taylor * directly instead. See i_hca_pci_config_setup() in detail. 836*9e39c5baSBill Taylor * 837*9e39c5baSBill Taylor * Argument 838*9e39c5baSBill Taylor * state: pointer to Hermon state structure 839*9e39c5baSBill Taylor * handle: pointer to ddi_acc_handle_t used for HCA FM 840*9e39c5baSBill Taylor * 841*9e39c5baSBill Taylor * Return value 842*9e39c5baSBill Taylor * ddi function status value which are: 843*9e39c5baSBill Taylor * DDI_SUCCESS 844*9e39c5baSBill Taylor * DDI_FAILURE 845*9e39c5baSBill Taylor * 846*9e39c5baSBill Taylor * Caller's context 847*9e39c5baSBill Taylor * hermon_pci_config_setup() can be called in user or kernel context only. 848*9e39c5baSBill Taylor */ 849*9e39c5baSBill Taylor int 850*9e39c5baSBill Taylor hermon_pci_config_setup(hermon_state_t *state, ddi_acc_handle_t *handle) 851*9e39c5baSBill Taylor { 852*9e39c5baSBill Taylor if (state->hs_fm_disable) { 853*9e39c5baSBill Taylor return (pci_config_setup(state->hs_dip, handle)); 854*9e39c5baSBill Taylor } else { 855*9e39c5baSBill Taylor /* Check Hermon FM and Solaris FMA capability flags */ 856*9e39c5baSBill Taylor ASSERT((hermon_get_state(state) & HCA_PIO_FM && 857*9e39c5baSBill Taylor DDI_FM_ACC_ERR_CAP(ddi_fm_capable(state->hs_dip))) || 858*9e39c5baSBill Taylor (!(hermon_get_state(state) & HCA_PIO_FM) && 859*9e39c5baSBill Taylor !DDI_FM_ACC_ERR_CAP(ddi_fm_capable(state->hs_dip)))); 860*9e39c5baSBill Taylor return (i_hca_pci_config_setup(state->hs_fm_hca_fm, 861*9e39c5baSBill Taylor state->hs_dip, handle)); 862*9e39c5baSBill Taylor } 863*9e39c5baSBill Taylor } 864*9e39c5baSBill Taylor 865*9e39c5baSBill Taylor 866*9e39c5baSBill Taylor /* 867*9e39c5baSBill Taylor * void 868*9e39c5baSBill Taylor * hermon_pci_config_teardown(hermon_state_t *state, ddi_acc_handle_t *handle) 869*9e39c5baSBill Taylor * 870*9e39c5baSBill Taylor * Overview 871*9e39c5baSBill Taylor * This is a wrapper function of i_hca_pci_config_teardown() for Hermon 872*9e39c5baSBill Taylor * FM so that it calls i_hca_pci_config_teardown() inside after it checks 873*9e39c5baSBill Taylor * the "fm-disable" configuration property. If the "fm_disable" is 874*9e39c5baSBill Taylor * described in /kernel/drv/hermon.conf, the function calls 875*9e39c5baSBill Taylor * pci_config_teardown() directly instead. 876*9e39c5baSBill Taylor * See i_hca_pci_config_teardown() in detail. 877*9e39c5baSBill Taylor * 878*9e39c5baSBill Taylor * Argument 879*9e39c5baSBill Taylor * state: pointer to Hermon state structure 880*9e39c5baSBill Taylor * handle: pointer to ddi_acc_handle_t used for HCA FM 881*9e39c5baSBill Taylor * 882*9e39c5baSBill Taylor * Return value 883*9e39c5baSBill Taylor * Nothing 884*9e39c5baSBill Taylor * 885*9e39c5baSBill Taylor * Caller's context 886*9e39c5baSBill Taylor * hermon_pci_config_teardown() can be called in user or kernel context 887*9e39c5baSBill Taylor * only. 888*9e39c5baSBill Taylor */ 889*9e39c5baSBill Taylor void 890*9e39c5baSBill Taylor hermon_pci_config_teardown(hermon_state_t *state, ddi_acc_handle_t *handle) 891*9e39c5baSBill Taylor { 892*9e39c5baSBill Taylor if (state->hs_fm_disable) { 893*9e39c5baSBill Taylor pci_config_teardown(handle); 894*9e39c5baSBill Taylor *handle = NULL; 895*9e39c5baSBill Taylor } else { 896*9e39c5baSBill Taylor i_hca_pci_config_teardown(state->hs_fm_hca_fm, handle); 897*9e39c5baSBill Taylor } 898*9e39c5baSBill Taylor } 899*9e39c5baSBill Taylor 900*9e39c5baSBill Taylor 901*9e39c5baSBill Taylor /* 902*9e39c5baSBill Taylor * boolean_t 903*9e39c5baSBill Taylor * hermon_init_failure(hermon_state_t *state) 904*9e39c5baSBill Taylor * 905*9e39c5baSBill Taylor * Overview 906*9e39c5baSBill Taylor * hermon_init_failure() tells if HW errors are detected in 907*9e39c5baSBill Taylor * the Hermon driver attach. 908*9e39c5baSBill Taylor * 909*9e39c5baSBill Taylor * Argument 910*9e39c5baSBill Taylor * state: pointer to Hermon state structure 911*9e39c5baSBill Taylor * 912*9e39c5baSBill Taylor * Return value 913*9e39c5baSBill Taylor * B_TRUE HW errors detected during attach 914*9e39c5baSBill Taylor * B_FALSE No HW errors during attach 915*9e39c5baSBill Taylor * 916*9e39c5baSBill Taylor * Caller's context 917*9e39c5baSBill Taylor * hermon_init_failure() can be called in user, kernel, interrupt 918*9e39c5baSBill Taylor * context or high interrupt context. 919*9e39c5baSBill Taylor */ 920*9e39c5baSBill Taylor boolean_t 921*9e39c5baSBill Taylor hermon_init_failure(hermon_state_t *state) 922*9e39c5baSBill Taylor { 923*9e39c5baSBill Taylor ddi_acc_handle_t hdl; 924*9e39c5baSBill Taylor ddi_fm_error_t derr; 925*9e39c5baSBill Taylor 926*9e39c5baSBill Taylor if (!(hermon_get_state(state) & HCA_PIO_FM)) 927*9e39c5baSBill Taylor return (B_FALSE); 928*9e39c5baSBill Taylor 929*9e39c5baSBill Taylor hdl = hermon_get_uarhdl(state); 930*9e39c5baSBill Taylor /* Get the PIO error against UAR I/O space */ 931*9e39c5baSBill Taylor ddi_fm_acc_err_get(hdl, &derr, DDI_FME_VERSION); 932*9e39c5baSBill Taylor if (derr.fme_status != DDI_FM_OK) { 933*9e39c5baSBill Taylor return (B_TRUE); 934*9e39c5baSBill Taylor } 935*9e39c5baSBill Taylor 936*9e39c5baSBill Taylor hdl = hermon_get_cmdhdl(state); 937*9e39c5baSBill Taylor /* Get the PIO error againsts CMD I/O space */ 938*9e39c5baSBill Taylor ddi_fm_acc_err_get(hdl, &derr, DDI_FME_VERSION); 939*9e39c5baSBill Taylor if (derr.fme_status != DDI_FM_OK) { 940*9e39c5baSBill Taylor return (B_TRUE); 941*9e39c5baSBill Taylor } 942*9e39c5baSBill Taylor 943*9e39c5baSBill Taylor return (B_FALSE); 944*9e39c5baSBill Taylor } 945*9e39c5baSBill Taylor 946*9e39c5baSBill Taylor 947*9e39c5baSBill Taylor /* 948*9e39c5baSBill Taylor * void 949*9e39c5baSBill Taylor * hermon_fm_ereport(hermon_state_t *state, int type, int detail) 950*9e39c5baSBill Taylor * 951*9e39c5baSBill Taylor * Overview 952*9e39c5baSBill Taylor * hermon_fm_ereport() is a Hermon FM ereport function used 953*9e39c5baSBill Taylor * to issue a Solaris FMA ereport. See Hermon FM comments at the 954*9e39c5baSBill Taylor * beginning of this file in detail. 955*9e39c5baSBill Taylor * 956*9e39c5baSBill Taylor * Argument 957*9e39c5baSBill Taylor * state: pointer to Hermon state structure 958*9e39c5baSBill Taylor * type: error type 959*9e39c5baSBill Taylor * HCA_SYS_ERR FMA reporting HW error 960*9e39c5baSBill Taylor * HCA_IBA_ERR HCA specific HW error 961*9e39c5baSBill Taylor * detail: HW error hint implying which ereport is issued 962*9e39c5baSBill Taylor * HCA_ERR_TRANSIENT HW transienet error 963*9e39c5baSBill Taylor * HCA_ERR_NON_FATAL HW persistent error 964*9e39c5baSBill Taylor * HCA_ERR_FATAL HW fatal error 965*9e39c5baSBill Taylor * HCA_ERR_SRV_LOST IB service lost due to HW error 966*9e39c5baSBill Taylor * HCA_ERR_DEGRADED Hermon driver and/or uDAPL degraded 967*9e39c5baSBill Taylor * due to HW error 968*9e39c5baSBill Taylor * HCA_ERR_IOCTL HW error detected in user conetxt 969*9e39c5baSBill Taylor * (especially in ioctl()) 970*9e39c5baSBill Taylor * 971*9e39c5baSBill Taylor * Return value 972*9e39c5baSBill Taylor * Nothing 973*9e39c5baSBill Taylor * 974*9e39c5baSBill Taylor * Caller's context 975*9e39c5baSBill Taylor * hermon_fm_ereport() can be called in user, kernel, interrupt context 976*9e39c5baSBill Taylor * or high interrupt context. 977*9e39c5baSBill Taylor */ 978*9e39c5baSBill Taylor void 979*9e39c5baSBill Taylor hermon_fm_ereport(hermon_state_t *state, int type, int detail) 980*9e39c5baSBill Taylor { 981*9e39c5baSBill Taylor /* 982*9e39c5baSBill Taylor * If hermon_fm_diable is set or there is no FM ereport service 983*9e39c5baSBill Taylor * provided, then skip the rest. 984*9e39c5baSBill Taylor */ 985*9e39c5baSBill Taylor if (state->hs_fm_disable || 986*9e39c5baSBill Taylor !(hermon_get_state(state) & HCA_EREPORT_FM)) { 987*9e39c5baSBill Taylor return; 988*9e39c5baSBill Taylor } 989*9e39c5baSBill Taylor 990*9e39c5baSBill Taylor switch (type) { 991*9e39c5baSBill Taylor 992*9e39c5baSBill Taylor case HCA_SYS_ERR: 993*9e39c5baSBill Taylor switch (detail) { 994*9e39c5baSBill Taylor case HCA_ERR_TRANSIENT: 995*9e39c5baSBill Taylor case HCA_ERR_IOCTL: 996*9e39c5baSBill Taylor ddi_fm_service_impact(state->hs_dip, 997*9e39c5baSBill Taylor DDI_SERVICE_UNAFFECTED); 998*9e39c5baSBill Taylor break; 999*9e39c5baSBill Taylor case HCA_ERR_NON_FATAL: 1000*9e39c5baSBill Taylor /* Nothing */ 1001*9e39c5baSBill Taylor break; 1002*9e39c5baSBill Taylor case HCA_ERR_SRV_LOST: 1003*9e39c5baSBill Taylor ddi_fm_service_impact(state->hs_dip, 1004*9e39c5baSBill Taylor DDI_SERVICE_LOST); 1005*9e39c5baSBill Taylor break; 1006*9e39c5baSBill Taylor case HCA_ERR_DEGRADED: 1007*9e39c5baSBill Taylor ddi_fm_service_impact(state->hs_dip, 1008*9e39c5baSBill Taylor DDI_SERVICE_DEGRADED); 1009*9e39c5baSBill Taylor break; 1010*9e39c5baSBill Taylor case HCA_ERR_FATAL: 1011*9e39c5baSBill Taylor ddi_fm_service_impact(state->hs_dip, 1012*9e39c5baSBill Taylor DDI_SERVICE_LOST); 1013*9e39c5baSBill Taylor state->hs_fm_async_fatal = B_TRUE; 1014*9e39c5baSBill Taylor break; 1015*9e39c5baSBill Taylor default: 1016*9e39c5baSBill Taylor cmn_err(CE_WARN, "hermon_fm_ereport: Unknown error. " 1017*9e39c5baSBill Taylor "type = %d, detail = %d\n.", type, detail); 1018*9e39c5baSBill Taylor } 1019*9e39c5baSBill Taylor break; 1020*9e39c5baSBill Taylor 1021*9e39c5baSBill Taylor case HCA_IBA_ERR: 1022*9e39c5baSBill Taylor switch (detail) { 1023*9e39c5baSBill Taylor case HCA_ERR_TRANSIENT: 1024*9e39c5baSBill Taylor i_hca_fm_ereport(state->hs_dip, type, 1025*9e39c5baSBill Taylor DDI_FM_DEVICE_INTERN_UNCORR); 1026*9e39c5baSBill Taylor ddi_fm_service_impact(state->hs_dip, 1027*9e39c5baSBill Taylor DDI_SERVICE_UNAFFECTED); 1028*9e39c5baSBill Taylor break; 1029*9e39c5baSBill Taylor case HCA_ERR_SRV_LOST: 1030*9e39c5baSBill Taylor cmn_err(CE_WARN, "hermon_fm_ereport: not supported " 1031*9e39c5baSBill Taylor "error. type = %d, detail = %d\n.", type, detail); 1032*9e39c5baSBill Taylor break; 1033*9e39c5baSBill Taylor case HCA_ERR_DEGRADED: 1034*9e39c5baSBill Taylor i_hca_fm_ereport(state->hs_dip, type, 1035*9e39c5baSBill Taylor DDI_FM_DEVICE_INTERN_UNCORR); 1036*9e39c5baSBill Taylor ddi_fm_service_impact(state->hs_dip, 1037*9e39c5baSBill Taylor DDI_SERVICE_DEGRADED); 1038*9e39c5baSBill Taylor break; 1039*9e39c5baSBill Taylor case HCA_ERR_IOCTL: 1040*9e39c5baSBill Taylor case HCA_ERR_NON_FATAL: 1041*9e39c5baSBill Taylor i_hca_fm_ereport(state->hs_dip, type, 1042*9e39c5baSBill Taylor DDI_FM_DEVICE_INTERN_UNCORR); 1043*9e39c5baSBill Taylor ddi_fm_service_impact(state->hs_dip, 1044*9e39c5baSBill Taylor DDI_SERVICE_UNAFFECTED); 1045*9e39c5baSBill Taylor break; 1046*9e39c5baSBill Taylor case HCA_ERR_FATAL: 1047*9e39c5baSBill Taylor if (hermon_get_state(state) & HCA_PIO_FM) { 1048*9e39c5baSBill Taylor if (servicing_interrupt()) { 1049*9e39c5baSBill Taylor atomic_inc_32(&state-> 1050*9e39c5baSBill Taylor hs_fm_async_errcnt); 1051*9e39c5baSBill Taylor } else { 1052*9e39c5baSBill Taylor i_hca_fm_ereport(state->hs_dip, type, 1053*9e39c5baSBill Taylor DDI_FM_DEVICE_INTERN_UNCORR); 1054*9e39c5baSBill Taylor ddi_fm_service_impact(state->hs_dip, 1055*9e39c5baSBill Taylor DDI_SERVICE_LOST); 1056*9e39c5baSBill Taylor } 1057*9e39c5baSBill Taylor state->hs_fm_async_fatal = B_TRUE; 1058*9e39c5baSBill Taylor } else { 1059*9e39c5baSBill Taylor i_hca_fm_ereport(state->hs_dip, type, 1060*9e39c5baSBill Taylor DDI_FM_DEVICE_INTERN_UNCORR); 1061*9e39c5baSBill Taylor ddi_fm_service_impact(state->hs_dip, 1062*9e39c5baSBill Taylor DDI_SERVICE_LOST); 1063*9e39c5baSBill Taylor cmn_err(CE_PANIC, 1064*9e39c5baSBill Taylor "Hermon Fatal Internal Error. " 1065*9e39c5baSBill Taylor "Hermon state=0x%p", (void *)state); 1066*9e39c5baSBill Taylor } 1067*9e39c5baSBill Taylor break; 1068*9e39c5baSBill Taylor default: 1069*9e39c5baSBill Taylor cmn_err(CE_WARN, "hermon_fm_ereport: Unknown error. " 1070*9e39c5baSBill Taylor "type = %d, detail = %d\n.", type, detail); 1071*9e39c5baSBill Taylor } 1072*9e39c5baSBill Taylor break; 1073*9e39c5baSBill Taylor 1074*9e39c5baSBill Taylor default: 1075*9e39c5baSBill Taylor cmn_err(CE_WARN, "hermon_fm_ereport: Unknown type " 1076*9e39c5baSBill Taylor "type = %d, detail = %d\n.", type, detail); 1077*9e39c5baSBill Taylor break; 1078*9e39c5baSBill Taylor } 1079*9e39c5baSBill Taylor } 1080*9e39c5baSBill Taylor 1081*9e39c5baSBill Taylor 1082*9e39c5baSBill Taylor /* 1083*9e39c5baSBill Taylor * uchar_t 1084*9e39c5baSBill Taylor * hermon_devacc_attr_version(hermon_state_t *) 1085*9e39c5baSBill Taylor * 1086*9e39c5baSBill Taylor * Overview 1087*9e39c5baSBill Taylor * hermon_devacc_attr_version() returns the ddi device attribute 1088*9e39c5baSBill Taylor * version. 1089*9e39c5baSBill Taylor * 1090*9e39c5baSBill Taylor * Argument 1091*9e39c5baSBill Taylor * state: pointer to Hermon state structure 1092*9e39c5baSBill Taylor * 1093*9e39c5baSBill Taylor * Return value 1094*9e39c5baSBill Taylor * dev_acc_attr_version value 1095*9e39c5baSBill Taylor * DDI_DEVICE_ATTR_V0 Hermon FM disabled 1096*9e39c5baSBill Taylor * DDI_DEVICE_ATTR_V1 Hermon FM enabled 1097*9e39c5baSBill Taylor * 1098*9e39c5baSBill Taylor * Caller's context 1099*9e39c5baSBill Taylor * hermon_devacc_attr_version() can be called in user, kernel, interrupt 1100*9e39c5baSBill Taylor * context or high interrupt context. 1101*9e39c5baSBill Taylor */ 1102*9e39c5baSBill Taylor ushort_t 1103*9e39c5baSBill Taylor hermon_devacc_attr_version(hermon_state_t *state) 1104*9e39c5baSBill Taylor { 1105*9e39c5baSBill Taylor if (state->hs_fm_disable) { 1106*9e39c5baSBill Taylor return (DDI_DEVICE_ATTR_V0); 1107*9e39c5baSBill Taylor } else { 1108*9e39c5baSBill Taylor return (DDI_DEVICE_ATTR_V1); 1109*9e39c5baSBill Taylor } 1110*9e39c5baSBill Taylor } 1111*9e39c5baSBill Taylor 1112*9e39c5baSBill Taylor 1113*9e39c5baSBill Taylor /* 1114*9e39c5baSBill Taylor * uchar_t 1115*9e39c5baSBill Taylor * hermon_devacc_attr_access(hermon_state_t *) 1116*9e39c5baSBill Taylor * 1117*9e39c5baSBill Taylor * Overview 1118*9e39c5baSBill Taylor * hermon_devacc_attr_access() returns devacc_attr_access error 1119*9e39c5baSBill Taylor * protection types. 1120*9e39c5baSBill Taylor * 1121*9e39c5baSBill Taylor * Argument 1122*9e39c5baSBill Taylor * state: pointer to Hermon state structure 1123*9e39c5baSBill Taylor * 1124*9e39c5baSBill Taylor * Return value 1125*9e39c5baSBill Taylor * dev_acc_attr_access error protection type 1126*9e39c5baSBill Taylor * DDI_DEFAULT_ACC Hermon FM disabled for PIO 1127*9e39c5baSBill Taylor * DDI_FLAGERR_ACC Hermon FM enabled for PIO 1128*9e39c5baSBill Taylor * 1129*9e39c5baSBill Taylor * Caller's context 1130*9e39c5baSBill Taylor * hermon_devacc_attr_access() can be called in user, kernel, interrupt 1131*9e39c5baSBill Taylor * context or high interrupt context. 1132*9e39c5baSBill Taylor */ 1133*9e39c5baSBill Taylor uchar_t 1134*9e39c5baSBill Taylor hermon_devacc_attr_access(hermon_state_t *state) 1135*9e39c5baSBill Taylor { 1136*9e39c5baSBill Taylor if (state->hs_fm_disable) { 1137*9e39c5baSBill Taylor return (DDI_DEFAULT_ACC); 1138*9e39c5baSBill Taylor } else { 1139*9e39c5baSBill Taylor return (DDI_FLAGERR_ACC); 1140*9e39c5baSBill Taylor } 1141*9e39c5baSBill Taylor } 1142*9e39c5baSBill Taylor 1143*9e39c5baSBill Taylor 1144*9e39c5baSBill Taylor /* 1145*9e39c5baSBill Taylor * int 1146*9e39c5baSBill Taylor * hermon_PIO_start(hermon_state_t *state, ddi_acc_handle_t handle, 1147*9e39c5baSBill Taylor * hermon_test_t *tst) 1148*9e39c5baSBill Taylor * 1149*9e39c5baSBill Taylor * Overview 1150*9e39c5baSBill Taylor * hermon_PIO_start() should be called before Hermon driver issues PIOs 1151*9e39c5baSBill Taylor * against I/O space. If Hermon FM is disabled, this function returns 1152*9e39c5baSBill Taylor * HCA_PIO_OK always. See i_hca_pio_start() in detail. 1153*9e39c5baSBill Taylor * 1154*9e39c5baSBill Taylor * Argument 1155*9e39c5baSBill Taylor * state: pointer to Hermon state structure 1156*9e39c5baSBill Taylor * handle: pointer to ddi_acc_handle_t used for HCA FM 1157*9e39c5baSBill Taylor * tst: pointer to HCA FM function test structure. If the structure 1158*9e39c5baSBill Taylor * is not used, the NULL value must be passed instead. 1159*9e39c5baSBill Taylor * 1160*9e39c5baSBill Taylor * Return value 1161*9e39c5baSBill Taylor * error status showing whether or not this error can retry 1162*9e39c5baSBill Taylor * HCA_PIO_OK No HW errors 1163*9e39c5baSBill Taylor * HCA_PIO_TRANSIENT This error could be transient 1164*9e39c5baSBill Taylor * HCA_PIO_PERSISTENT This error is persistent 1165*9e39c5baSBill Taylor * 1166*9e39c5baSBill Taylor * Caller's context 1167*9e39c5baSBill Taylor * hermon_PIO_start() can be called in user, kernel or interrupt context. 1168*9e39c5baSBill Taylor */ 1169*9e39c5baSBill Taylor int 1170*9e39c5baSBill Taylor hermon_PIO_start(hermon_state_t *state, ddi_acc_handle_t handle, 1171*9e39c5baSBill Taylor hermon_test_t *tst) 1172*9e39c5baSBill Taylor { 1173*9e39c5baSBill Taylor if (state->hs_fm_disable) { 1174*9e39c5baSBill Taylor return (HCA_PIO_OK); 1175*9e39c5baSBill Taylor } else { 1176*9e39c5baSBill Taylor struct i_hca_acc_handle *handlep = 1177*9e39c5baSBill Taylor i_hca_get_acc_handle(state->hs_fm_hca_fm, handle); 1178*9e39c5baSBill Taylor ASSERT(handlep != NULL); 1179*9e39c5baSBill Taylor return (i_hca_pio_start(state->hs_dip, handlep, tst)); 1180*9e39c5baSBill Taylor } 1181*9e39c5baSBill Taylor } 1182*9e39c5baSBill Taylor 1183*9e39c5baSBill Taylor 1184*9e39c5baSBill Taylor /* 1185*9e39c5baSBill Taylor * int 1186*9e39c5baSBill Taylor * hermon_PIO_end(hermon_state_t *state, ddi_acc_handle_t handle, int *cnt, 1187*9e39c5baSBill Taylor * hermon_test_t *tst) 1188*9e39c5baSBill Taylor * 1189*9e39c5baSBill Taylor * Overview 1190*9e39c5baSBill Taylor * hermon_PIO_end() should be called after Hermon driver issues PIOs 1191*9e39c5baSBill Taylor * against I/O space. If Hermon FM is disabled, this function returns 1192*9e39c5baSBill Taylor * HCA_PIO_OK always. See i_hca_pio_end() in detail. 1193*9e39c5baSBill Taylor * 1194*9e39c5baSBill Taylor * Argument 1195*9e39c5baSBill Taylor * state: pointer to Hermon state structure 1196*9e39c5baSBill Taylor * handle: pointer to ddi_acc_handle_t used for HCA FM 1197*9e39c5baSBill Taylor * cnt: pointer to the counter variable which holds the nubmer of retry 1198*9e39c5baSBill Taylor * (HCA_PIO_RETRY_CNT) when a HW error is detected. 1199*9e39c5baSBill Taylor * tst: pointer to HCA FM function test structure. If the structure 1200*9e39c5baSBill Taylor * is not used, the NULL value must be passed instead. 1201*9e39c5baSBill Taylor * 1202*9e39c5baSBill Taylor * Return value 1203*9e39c5baSBill Taylor * error status showing whether or not this error can retry 1204*9e39c5baSBill Taylor * HCA_PIO_OK No HW errors 1205*9e39c5baSBill Taylor * HCA_PIO_TRANSIENT This error could be transient 1206*9e39c5baSBill Taylor * HCA_PIO_PERSISTENT This error is persistent 1207*9e39c5baSBill Taylor * 1208*9e39c5baSBill Taylor * Caller's context 1209*9e39c5baSBill Taylor * hermon_PIO_end() can be called in user, kernel or interrupt context. 1210*9e39c5baSBill Taylor */ 1211*9e39c5baSBill Taylor int 1212*9e39c5baSBill Taylor hermon_PIO_end(hermon_state_t *state, ddi_acc_handle_t handle, int *cnt, 1213*9e39c5baSBill Taylor hermon_test_t *tst) 1214*9e39c5baSBill Taylor { 1215*9e39c5baSBill Taylor if (state->hs_fm_disable) { 1216*9e39c5baSBill Taylor return (HCA_PIO_OK); 1217*9e39c5baSBill Taylor } else { 1218*9e39c5baSBill Taylor struct i_hca_acc_handle *handlep = 1219*9e39c5baSBill Taylor i_hca_get_acc_handle(state->hs_fm_hca_fm, handle); 1220*9e39c5baSBill Taylor ASSERT(handlep != NULL); 1221*9e39c5baSBill Taylor return (i_hca_pio_end(state->hs_dip, handlep, cnt, tst)); 1222*9e39c5baSBill Taylor } 1223*9e39c5baSBill Taylor } 1224*9e39c5baSBill Taylor 1225*9e39c5baSBill Taylor 1226*9e39c5baSBill Taylor /* 1227*9e39c5baSBill Taylor * ddi_acc_handle_t 1228*9e39c5baSBill Taylor * hermon_get_cmdhdl(hermon_state_t *state) 1229*9e39c5baSBill Taylor * 1230*9e39c5baSBill Taylor * Overview 1231*9e39c5baSBill Taylor * hermon_get_cmdhdl() returns either the fma-protected access handle or 1232*9e39c5baSBill Taylor * the regular ddi-access handle depending on the Hermon FM state for 1233*9e39c5baSBill Taylor * Hermon command I/O space. 1234*9e39c5baSBill Taylor * 1235*9e39c5baSBill Taylor * Argument 1236*9e39c5baSBill Taylor * state: pointer to Hermon state structure 1237*9e39c5baSBill Taylor * 1238*9e39c5baSBill Taylor * Return value 1239*9e39c5baSBill Taylor * the access handle for pio requests 1240*9e39c5baSBill Taylor * 1241*9e39c5baSBill Taylor * Caller's context 1242*9e39c5baSBill Taylor * hermon_get_cmdhdl() can be called in user, kernel, interrupt context 1243*9e39c5baSBill Taylor * or high interrupt context. 1244*9e39c5baSBill Taylor */ 1245*9e39c5baSBill Taylor ddi_acc_handle_t 1246*9e39c5baSBill Taylor hermon_get_cmdhdl(hermon_state_t *state) 1247*9e39c5baSBill Taylor { 1248*9e39c5baSBill Taylor return (state->hs_fm_disable || hermon_get_state(state) & HCA_PIO_FM ? 1249*9e39c5baSBill Taylor state->hs_fm_cmdhdl : state->hs_reg_cmdhdl); 1250*9e39c5baSBill Taylor } 1251*9e39c5baSBill Taylor 1252*9e39c5baSBill Taylor 1253*9e39c5baSBill Taylor /* 1254*9e39c5baSBill Taylor * ddi_acc_handle_t 1255*9e39c5baSBill Taylor * hermon_get_uarhdl(hermon_state_t *state) 1256*9e39c5baSBill Taylor * 1257*9e39c5baSBill Taylor * Overview 1258*9e39c5baSBill Taylor * hermon_get_uarhdl() returns either the fma-protected access handle or 1259*9e39c5baSBill Taylor * the regular ddi-access handle depending on the Hermon FM state for 1260*9e39c5baSBill Taylor * Hermon UAR I/O space. 1261*9e39c5baSBill Taylor * 1262*9e39c5baSBill Taylor * Argument 1263*9e39c5baSBill Taylor * state: pointer to Hermon state structure 1264*9e39c5baSBill Taylor * 1265*9e39c5baSBill Taylor * Return value 1266*9e39c5baSBill Taylor * the access handle for pio requests 1267*9e39c5baSBill Taylor * 1268*9e39c5baSBill Taylor * Caller's context 1269*9e39c5baSBill Taylor * hermon_get_uarhdl() can be called in user, kernel, interrupt context 1270*9e39c5baSBill Taylor * or high interrupt context. 1271*9e39c5baSBill Taylor */ 1272*9e39c5baSBill Taylor ddi_acc_handle_t 1273*9e39c5baSBill Taylor hermon_get_uarhdl(hermon_state_t *state) 1274*9e39c5baSBill Taylor { 1275*9e39c5baSBill Taylor return (state->hs_fm_disable || hermon_get_state(state) & HCA_PIO_FM ? 1276*9e39c5baSBill Taylor state->hs_fm_uarhdl : state->hs_reg_uarhdl); 1277*9e39c5baSBill Taylor } 1278*9e39c5baSBill Taylor 1279*9e39c5baSBill Taylor 1280*9e39c5baSBill Taylor /* 1281*9e39c5baSBill Taylor * ddi_acc_handle_t 1282*9e39c5baSBill Taylor * hermon_rsrc_alloc_uarhdl(hermon_state_t *state) 1283*9e39c5baSBill Taylor * 1284*9e39c5baSBill Taylor * Overview 1285*9e39c5baSBill Taylor * hermon_rsrc_alloc_uarhdl() returns either the fma-protected access 1286*9e39c5baSBill Taylor * handle or the regular ddi-access handle depending on the Hermon FM 1287*9e39c5baSBill Taylor * state for Hermon UAR I/O space as well as hermon_get_uarhdl(), but 1288*9e39c5baSBill Taylor * this function is dedicated to the UAR resource allocator. 1289*9e39c5baSBill Taylor * 1290*9e39c5baSBill Taylor * Argument 1291*9e39c5baSBill Taylor * state: pointer to Hermon state structure 1292*9e39c5baSBill Taylor * 1293*9e39c5baSBill Taylor * Return value 1294*9e39c5baSBill Taylor * the access handle for pio requests 1295*9e39c5baSBill Taylor * 1296*9e39c5baSBill Taylor * Caller's context 1297*9e39c5baSBill Taylor * hermon_rsrc_alloc_uarhdl() can be called in user, kernel, interrupt 1298*9e39c5baSBill Taylor * or high interrupt context. 1299*9e39c5baSBill Taylor */ 1300*9e39c5baSBill Taylor ddi_acc_handle_t 1301*9e39c5baSBill Taylor hermon_rsrc_alloc_uarhdl(hermon_state_t *state) 1302*9e39c5baSBill Taylor { 1303*9e39c5baSBill Taylor return (state->hs_fm_disable || hermon_get_state(state) & HCA_ATTCH_FM ? 1304*9e39c5baSBill Taylor state->hs_fm_uarhdl : state->hs_reg_uarhdl); 1305*9e39c5baSBill Taylor } 1306*9e39c5baSBill Taylor 1307*9e39c5baSBill Taylor /* 1308*9e39c5baSBill Taylor * ddi_acc_handle_t 1309*9e39c5baSBill Taylor * hermon_get_pcihdl(hermon_state_t *state) 1310*9e39c5baSBill Taylor * 1311*9e39c5baSBill Taylor * Overview 1312*9e39c5baSBill Taylor * hermon_get_pcihdl() returns either the fma-protected access 1313*9e39c5baSBill Taylor * handle or the regular ddi-access handle to access the PCI config 1314*9e39c5baSBill Taylor * space. Whether or not which handle is returned at the moment depends 1315*9e39c5baSBill Taylor * on the Hermon FM state. 1316*9e39c5baSBill Taylor * 1317*9e39c5baSBill Taylor * Argument 1318*9e39c5baSBill Taylor * state: pointer to Hermon state structure 1319*9e39c5baSBill Taylor * 1320*9e39c5baSBill Taylor * Return value 1321*9e39c5baSBill Taylor * the access handle to PCI config space 1322*9e39c5baSBill Taylor * 1323*9e39c5baSBill Taylor * Caller's context 1324*9e39c5baSBill Taylor * hermon_get_pcihdl() can be called in user, kernel, interrupt 1325*9e39c5baSBill Taylor * or high interrupt context. 1326*9e39c5baSBill Taylor */ 1327*9e39c5baSBill Taylor ddi_acc_handle_t 1328*9e39c5baSBill Taylor hermon_get_pcihdl(hermon_state_t *state) 1329*9e39c5baSBill Taylor { 1330*9e39c5baSBill Taylor return (state->hs_fm_disable || hermon_get_state(state) & HCA_ATTCH_FM ? 1331*9e39c5baSBill Taylor state->hs_fm_pcihdl : state->hs_reg_pcihdl); 1332*9e39c5baSBill Taylor } 1333*9e39c5baSBill Taylor 1334*9e39c5baSBill Taylor 1335*9e39c5baSBill Taylor /* 1336*9e39c5baSBill Taylor * ddi_acc_handle_t 1337*9e39c5baSBill Taylor * hermon_get_msix_tblhdl(hermon_state_t *state) 1338*9e39c5baSBill Taylor * 1339*9e39c5baSBill Taylor * Overview 1340*9e39c5baSBill Taylor * hermon_get_msix_tblhdl() returns either the fma-protected access 1341*9e39c5baSBill Taylor * handle or the regular ddi-access handle to access the MSI-X tables. 1342*9e39c5baSBill Taylor * Whether or not which handle is returned at the moment depends on 1343*9e39c5baSBill Taylor * the Hermon FM state. 1344*9e39c5baSBill Taylor * 1345*9e39c5baSBill Taylor * Argument 1346*9e39c5baSBill Taylor * state: pointer to Hermon state structure 1347*9e39c5baSBill Taylor * 1348*9e39c5baSBill Taylor * Return value 1349*9e39c5baSBill Taylor * the access handle to MSI-X tables 1350*9e39c5baSBill Taylor * 1351*9e39c5baSBill Taylor * Caller's context 1352*9e39c5baSBill Taylor * hermon_get_msix_tblhdl() can be called in user, kernel, interrupt 1353*9e39c5baSBill Taylor * context or high interrupt context. 1354*9e39c5baSBill Taylor */ 1355*9e39c5baSBill Taylor ddi_acc_handle_t 1356*9e39c5baSBill Taylor hermon_get_msix_tblhdl(hermon_state_t *state) 1357*9e39c5baSBill Taylor { 1358*9e39c5baSBill Taylor return (state->hs_fm_disable || hermon_get_state(state) & HCA_ATTCH_FM ? 1359*9e39c5baSBill Taylor state->hs_fm_msix_tblhdl : state->hs_reg_msix_tblhdl); 1360*9e39c5baSBill Taylor } 1361*9e39c5baSBill Taylor 1362*9e39c5baSBill Taylor 1363*9e39c5baSBill Taylor /* 1364*9e39c5baSBill Taylor * ddi_acc_handle_t 1365*9e39c5baSBill Taylor * hermon_get_msix_pbahdl(hermon_state_t *state) 1366*9e39c5baSBill Taylor * 1367*9e39c5baSBill Taylor * Overview 1368*9e39c5baSBill Taylor * hermon_get_msix_pbahdl() returns either the fma-protected access 1369*9e39c5baSBill Taylor * handle or the regular ddi-access handle to access the MSI-X PBA. 1370*9e39c5baSBill Taylor * Whether or not which handle is returned at the moment depends on 1371*9e39c5baSBill Taylor * the Hermon FM state. 1372*9e39c5baSBill Taylor * 1373*9e39c5baSBill Taylor * Argument 1374*9e39c5baSBill Taylor * state: pointer to Hermon state structure 1375*9e39c5baSBill Taylor * 1376*9e39c5baSBill Taylor * Return value 1377*9e39c5baSBill Taylor * the access handle to MSI-X PBA 1378*9e39c5baSBill Taylor * 1379*9e39c5baSBill Taylor * Caller's context 1380*9e39c5baSBill Taylor * hermon_get_msix_pbahdl() can be called in user, kernel, interrupt 1381*9e39c5baSBill Taylor * context or high interrupt context. 1382*9e39c5baSBill Taylor */ 1383*9e39c5baSBill Taylor ddi_acc_handle_t 1384*9e39c5baSBill Taylor hermon_get_msix_pbahdl(hermon_state_t *state) 1385*9e39c5baSBill Taylor { 1386*9e39c5baSBill Taylor return (state->hs_fm_disable || hermon_get_state(state) & HCA_ATTCH_FM ? 1387*9e39c5baSBill Taylor state->hs_fm_msix_pbahdl : state->hs_reg_msix_pbahdl); 1388*9e39c5baSBill Taylor } 1389*9e39c5baSBill Taylor 1390*9e39c5baSBill Taylor 1391*9e39c5baSBill Taylor /* 1392*9e39c5baSBill Taylor * void 1393*9e39c5baSBill Taylor * hermon_inter_err_chk(void *arg) 1394*9e39c5baSBill Taylor * 1395*9e39c5baSBill Taylor * Overview 1396*9e39c5baSBill Taylor * hermon_inter_err_chk() periodically checks the internal error buffer 1397*9e39c5baSBill Taylor * to pick up a Hermon asynchronous internal error. 1398*9e39c5baSBill Taylor * 1399*9e39c5baSBill Taylor * Note that this internal error can be notified if the interrupt is 1400*9e39c5baSBill Taylor * registered, but even so there are some cases that an interrupt against 1401*9e39c5baSBill Taylor * it cannot be raised so that Hermon RPM recommeds to poll this internal 1402*9e39c5baSBill Taylor * error buffer periodically instead. This function is invoked at 1403*9e39c5baSBill Taylor * 10ms interval in kernel context though the function itself can be 1404*9e39c5baSBill Taylor * called in interrupt context. 1405*9e39c5baSBill Taylor * 1406*9e39c5baSBill Taylor * Argument 1407*9e39c5baSBill Taylor * arg: pointer to Hermon state structure 1408*9e39c5baSBill Taylor * 1409*9e39c5baSBill Taylor * Return value 1410*9e39c5baSBill Taylor * Nothing 1411*9e39c5baSBill Taylor * 1412*9e39c5baSBill Taylor * Caller's context 1413*9e39c5baSBill Taylor * hermon_inter_err_chk() can be called in user, kernel, interrupt 1414*9e39c5baSBill Taylor * context or high interrupt context. 1415*9e39c5baSBill Taylor * 1416*9e39c5baSBill Taylor */ 1417*9e39c5baSBill Taylor void 1418*9e39c5baSBill Taylor hermon_inter_err_chk(void *arg) 1419*9e39c5baSBill Taylor { 1420*9e39c5baSBill Taylor uint32_t word; 1421*9e39c5baSBill Taylor ddi_acc_handle_t cmdhdl; 1422*9e39c5baSBill Taylor hermon_state_t *state = (hermon_state_t *)arg; 1423*9e39c5baSBill Taylor 1424*9e39c5baSBill Taylor /* initialize the FMA retry loop */ 1425*9e39c5baSBill Taylor hermon_pio_init(fm_loop_cnt, fm_status, fm_test); 1426*9e39c5baSBill Taylor 1427*9e39c5baSBill Taylor #ifdef FMA_TEST 1428*9e39c5baSBill Taylor if (hermon_test_num != 0) { 1429*9e39c5baSBill Taylor return; 1430*9e39c5baSBill Taylor } 1431*9e39c5baSBill Taylor #endif 1432*9e39c5baSBill Taylor if (state->hs_fm_poll_suspend) { 1433*9e39c5baSBill Taylor return; 1434*9e39c5baSBill Taylor } 1435*9e39c5baSBill Taylor 1436*9e39c5baSBill Taylor /* Get the access handle for Hermon CMD I/O space */ 1437*9e39c5baSBill Taylor cmdhdl = hermon_get_cmdhdl(state); 1438*9e39c5baSBill Taylor 1439*9e39c5baSBill Taylor /* the FMA retry loop starts. */ 1440*9e39c5baSBill Taylor hermon_pio_start(state, cmdhdl, pio_error, fm_loop_cnt, fm_status, 1441*9e39c5baSBill Taylor fm_test); 1442*9e39c5baSBill Taylor 1443*9e39c5baSBill Taylor word = ddi_get32(cmdhdl, state->hs_cmd_regs.fw_err_buf); 1444*9e39c5baSBill Taylor 1445*9e39c5baSBill Taylor /* the FMA retry loop ends. */ 1446*9e39c5baSBill Taylor hermon_pio_end(state, cmdhdl, pio_error, fm_loop_cnt, fm_status, 1447*9e39c5baSBill Taylor fm_test); 1448*9e39c5baSBill Taylor 1449*9e39c5baSBill Taylor if (word != 0) { 1450*9e39c5baSBill Taylor HERMON_FMANOTE(state, HERMON_FMA_INTERNAL); 1451*9e39c5baSBill Taylor hermon_fm_ereport(state, HCA_IBA_ERR, HCA_ERR_FATAL); 1452*9e39c5baSBill Taylor } 1453*9e39c5baSBill Taylor 1454*9e39c5baSBill Taylor /* issue the ereport pended in the interrupt context */ 1455*9e39c5baSBill Taylor if (state->hs_fm_async_errcnt > 0) { 1456*9e39c5baSBill Taylor hermon_fm_ereport(state, HCA_IBA_ERR, HCA_ERR_FATAL); 1457*9e39c5baSBill Taylor atomic_dec_32(&state->hs_fm_async_errcnt); 1458*9e39c5baSBill Taylor } 1459*9e39c5baSBill Taylor 1460*9e39c5baSBill Taylor return; 1461*9e39c5baSBill Taylor 1462*9e39c5baSBill Taylor pio_error: 1463*9e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_FATAL); 1464*9e39c5baSBill Taylor } 1465*9e39c5baSBill Taylor 1466*9e39c5baSBill Taylor 1467*9e39c5baSBill Taylor /* 1468*9e39c5baSBill Taylor * boolean_t 1469*9e39c5baSBill Taylor * hermon_cmd_retry_ok(hermon_cmd_post_t *cmd, int status) 1470*9e39c5baSBill Taylor * 1471*9e39c5baSBill Taylor * Overview 1472*9e39c5baSBill Taylor * In the case that a HW error is detected, if it can be isolated 1473*9e39c5baSBill Taylor * enough, Hermon FM retries the operation which caused the error. 1474*9e39c5baSBill Taylor * However, this retry can induce another error; since the retry is 1475*9e39c5baSBill Taylor * achieved as a block basis, not a statement basis, once the state 1476*9e39c5baSBill Taylor * was set inside the Hermon HW already in the previous operation, the 1477*9e39c5baSBill Taylor * retry can cause for example, a CMD_BAD_SYS_STATE error, as a result. 1478*9e39c5baSBill Taylor * In this case, CMD_BAD_SYS_STATE should be taken as a side effect 1479*9e39c5baSBill Taylor * but a harmless result. hermon_cmd_retry_ok() checks this kind of 1480*9e39c5baSBill Taylor * situation then returns if the state Hermon CMD returns is OK or not. 1481*9e39c5baSBill Taylor * 1482*9e39c5baSBill Taylor * Argument 1483*9e39c5baSBill Taylor * cmd: pointer to hermon_cmd_post_t structure 1484*9e39c5baSBill Taylor * status: Hermon CMD status 1485*9e39c5baSBill Taylor * 1486*9e39c5baSBill Taylor * Return value 1487*9e39c5baSBill Taylor * B_TRUE this state is no problem 1488*9e39c5baSBill Taylor * B_FALSE this state should be taken as an error 1489*9e39c5baSBill Taylor * 1490*9e39c5baSBill Taylor * Caller's context 1491*9e39c5baSBill Taylor * hermon_cmd_retry_ok() can be called in user, kernel, interrupt 1492*9e39c5baSBill Taylor * context or high interrupt context. 1493*9e39c5baSBill Taylor * 1494*9e39c5baSBill Taylor * Note that status except for HERMON_CMD_SUCCESS shouldn't be accepted 1495*9e39c5baSBill Taylor * in the debug module to catch a hidden software bug, so that ASSERT() 1496*9e39c5baSBill Taylor * is enabled in the case. 1497*9e39c5baSBill Taylor */ 1498*9e39c5baSBill Taylor boolean_t 1499*9e39c5baSBill Taylor hermon_cmd_retry_ok(hermon_cmd_post_t *cmd, int status) 1500*9e39c5baSBill Taylor { 1501*9e39c5baSBill Taylor if (status == HERMON_CMD_SUCCESS) 1502*9e39c5baSBill Taylor return (B_TRUE); 1503*9e39c5baSBill Taylor 1504*9e39c5baSBill Taylor /* 1505*9e39c5baSBill Taylor * The wrong status such as HERMON_CMD_BAD_SYS_STATE or 1506*9e39c5baSBill Taylor * HERMON_CMD_BAD_RES_STATE can return as a side effect 1507*9e39c5baSBill Taylor * because of the Hermon FM operation retry when a PIO 1508*9e39c5baSBill Taylor * error is detected during the I/O transaction. In the 1509*9e39c5baSBill Taylor * case, the driver may set the same value in Hermon 1510*9e39c5baSBill Taylor * though it was set already, then Hermon returns HERMON_ 1511*9e39c5baSBill Taylor * CMD_BAD_{RES,SYS}_STATE as a result, which should be 1512*9e39c5baSBill Taylor * taken as OK. 1513*9e39c5baSBill Taylor */ 1514*9e39c5baSBill Taylor switch (cmd->cp_opcode) { 1515*9e39c5baSBill Taylor case INIT_HCA: 1516*9e39c5baSBill Taylor /* 1517*9e39c5baSBill Taylor * HERMON_CMD_BAD_SYS_STATE can be gotten in case of 1518*9e39c5baSBill Taylor * ICM not mapped or HCA already initialized. 1519*9e39c5baSBill Taylor */ 1520*9e39c5baSBill Taylor if (status == HERMON_CMD_BAD_SYS_STATE) 1521*9e39c5baSBill Taylor return (B_TRUE); 1522*9e39c5baSBill Taylor return (B_FALSE); 1523*9e39c5baSBill Taylor 1524*9e39c5baSBill Taylor case CLOSE_HCA: 1525*9e39c5baSBill Taylor /* 1526*9e39c5baSBill Taylor * HERMON_CMD_BAD_SYS_STATE can be gotten in case of Firmware 1527*9e39c5baSBill Taylor * area is not mapped or HCA already closed. 1528*9e39c5baSBill Taylor */ 1529*9e39c5baSBill Taylor if (status == HERMON_CMD_BAD_SYS_STATE) 1530*9e39c5baSBill Taylor return (B_TRUE); 1531*9e39c5baSBill Taylor return (B_FALSE); 1532*9e39c5baSBill Taylor 1533*9e39c5baSBill Taylor case CLOSE_PORT: 1534*9e39c5baSBill Taylor /* 1535*9e39c5baSBill Taylor * HERMON_CMD_BAD_SYS_STATE can be gotten in case of HCA not 1536*9e39c5baSBill Taylor * initialized or in case that IB ports are already down. 1537*9e39c5baSBill Taylor */ 1538*9e39c5baSBill Taylor if (status == HERMON_CMD_BAD_SYS_STATE) 1539*9e39c5baSBill Taylor return (B_TRUE); 1540*9e39c5baSBill Taylor return (B_FALSE); 1541*9e39c5baSBill Taylor 1542*9e39c5baSBill Taylor case SW2HW_MPT: 1543*9e39c5baSBill Taylor /* 1544*9e39c5baSBill Taylor * HERMON_CMD_BAD_RES_STATE can be gotten in case of MPT 1545*9e39c5baSBill Taylor * entry already in hardware ownership. 1546*9e39c5baSBill Taylor */ 1547*9e39c5baSBill Taylor if (status == HERMON_CMD_BAD_RES_STATE) 1548*9e39c5baSBill Taylor return (B_TRUE); 1549*9e39c5baSBill Taylor return (B_FALSE); 1550*9e39c5baSBill Taylor 1551*9e39c5baSBill Taylor case HW2SW_MPT: 1552*9e39c5baSBill Taylor /* 1553*9e39c5baSBill Taylor * HERMON_CMD_BAD_RES_STATE can be gotten in case of MPT 1554*9e39c5baSBill Taylor * entry already in software ownership. 1555*9e39c5baSBill Taylor */ 1556*9e39c5baSBill Taylor if (status == HERMON_CMD_BAD_RES_STATE) 1557*9e39c5baSBill Taylor return (B_TRUE); 1558*9e39c5baSBill Taylor return (B_FALSE); 1559*9e39c5baSBill Taylor 1560*9e39c5baSBill Taylor case SW2HW_EQ: 1561*9e39c5baSBill Taylor /* 1562*9e39c5baSBill Taylor * HERMON_CMD_BAD_RES_STATE can be gotten in case of EQ 1563*9e39c5baSBill Taylor * entry already in hardware ownership. 1564*9e39c5baSBill Taylor */ 1565*9e39c5baSBill Taylor if (status == HERMON_CMD_BAD_RES_STATE) 1566*9e39c5baSBill Taylor return (B_TRUE); 1567*9e39c5baSBill Taylor return (B_FALSE); 1568*9e39c5baSBill Taylor 1569*9e39c5baSBill Taylor case HW2SW_EQ: 1570*9e39c5baSBill Taylor /* 1571*9e39c5baSBill Taylor * HERMON_CMD_BAD_RES_STATE can be gotten in case of EQ 1572*9e39c5baSBill Taylor * entry already in software ownership. 1573*9e39c5baSBill Taylor */ 1574*9e39c5baSBill Taylor if (status == HERMON_CMD_BAD_RES_STATE) 1575*9e39c5baSBill Taylor return (B_TRUE); 1576*9e39c5baSBill Taylor return (B_FALSE); 1577*9e39c5baSBill Taylor 1578*9e39c5baSBill Taylor case SW2HW_CQ: 1579*9e39c5baSBill Taylor /* 1580*9e39c5baSBill Taylor * HERMON_CMD_BAD_RES_STATE can be gotten in case of CQ 1581*9e39c5baSBill Taylor * entry already in hardware ownership. 1582*9e39c5baSBill Taylor */ 1583*9e39c5baSBill Taylor if (status == HERMON_CMD_BAD_RES_STATE) 1584*9e39c5baSBill Taylor return (B_TRUE); 1585*9e39c5baSBill Taylor return (B_FALSE); 1586*9e39c5baSBill Taylor 1587*9e39c5baSBill Taylor case HW2SW_CQ: 1588*9e39c5baSBill Taylor /* 1589*9e39c5baSBill Taylor * HERMON_CMD_BAD_RES_STATE can be gotten in case of CQ 1590*9e39c5baSBill Taylor * entry already in software ownership. 1591*9e39c5baSBill Taylor */ 1592*9e39c5baSBill Taylor if (status == HERMON_CMD_BAD_RES_STATE) 1593*9e39c5baSBill Taylor return (B_TRUE); 1594*9e39c5baSBill Taylor return (B_FALSE); 1595*9e39c5baSBill Taylor 1596*9e39c5baSBill Taylor case SW2HW_SRQ: 1597*9e39c5baSBill Taylor /* 1598*9e39c5baSBill Taylor * HERMON_CMD_BAD_RES_STATE can be gotten in case of SRQ 1599*9e39c5baSBill Taylor * entry already in hardware ownership. 1600*9e39c5baSBill Taylor */ 1601*9e39c5baSBill Taylor if (status == HERMON_CMD_BAD_RES_STATE) 1602*9e39c5baSBill Taylor return (B_TRUE); 1603*9e39c5baSBill Taylor return (B_FALSE); 1604*9e39c5baSBill Taylor 1605*9e39c5baSBill Taylor case HW2SW_SRQ: 1606*9e39c5baSBill Taylor /* 1607*9e39c5baSBill Taylor * HERMON_CMD_BAD_RES_STATE can be gotten in case of SRQ 1608*9e39c5baSBill Taylor * entry already in software ownership. 1609*9e39c5baSBill Taylor */ 1610*9e39c5baSBill Taylor if (status == HERMON_CMD_BAD_RES_STATE) 1611*9e39c5baSBill Taylor return (B_TRUE); 1612*9e39c5baSBill Taylor return (B_FALSE); 1613*9e39c5baSBill Taylor default: 1614*9e39c5baSBill Taylor break; 1615*9e39c5baSBill Taylor } 1616*9e39c5baSBill Taylor 1617*9e39c5baSBill Taylor /* other cases */ 1618*9e39c5baSBill Taylor return (B_FALSE); 1619*9e39c5baSBill Taylor } 1620*9e39c5baSBill Taylor 1621*9e39c5baSBill Taylor 1622*9e39c5baSBill Taylor #ifdef FMA_TEST 1623*9e39c5baSBill Taylor 1624*9e39c5baSBill Taylor /* 1625*9e39c5baSBill Taylor * Hermon FMA test variables 1626*9e39c5baSBill Taylor */ 1627*9e39c5baSBill Taylor #define FMA_TEST_HASHSZ 64 1628*9e39c5baSBill Taylor int hermon_test_num; /* predefined testset */ 1629*9e39c5baSBill Taylor 1630*9e39c5baSBill Taylor static struct i_hca_fm_test *i_hca_test_register(char *, int, int, 1631*9e39c5baSBill Taylor void (*)(struct i_hca_fm_test *, ddi_fm_error_t *), 1632*9e39c5baSBill Taylor void *, mod_hash_t *, mod_hash_t *, int); 1633*9e39c5baSBill Taylor static void i_hca_test_free_item(mod_hash_val_t); 1634*9e39c5baSBill Taylor static void i_hca_test_set_item(int, struct i_hca_fm_test *); 1635*9e39c5baSBill Taylor static void hermon_trigger_pio_error(hermon_test_t *, ddi_fm_error_t *); 1636*9e39c5baSBill Taylor 1637*9e39c5baSBill Taylor /* 1638*9e39c5baSBill Taylor * Hermon FMA Function Test Interface 1639*9e39c5baSBill Taylor */ 1640*9e39c5baSBill Taylor 1641*9e39c5baSBill Taylor /* Attach Errors */ 1642*9e39c5baSBill Taylor 1643*9e39c5baSBill Taylor #define ATTACH_TS (HCA_TEST_TRANSIENT | HCA_TEST_ATTACH | HCA_TEST_START) 1644*9e39c5baSBill Taylor #define ATTACH_TE (HCA_TEST_TRANSIENT | HCA_TEST_ATTACH | HCA_TEST_END) 1645*9e39c5baSBill Taylor 1646*9e39c5baSBill Taylor #define ATTACH_PS (HCA_TEST_PERSISTENT | HCA_TEST_ATTACH | HCA_TEST_START) 1647*9e39c5baSBill Taylor #define ATTACH_PE (HCA_TEST_PERSISTENT | HCA_TEST_ATTACH | HCA_TEST_END) 1648*9e39c5baSBill Taylor 1649*9e39c5baSBill Taylor static hermon_test_t testset[] = { 1650*9e39c5baSBill Taylor /* Initial Value */ 1651*9e39c5baSBill Taylor {0, 0, 0, NULL, 0, 0, NULL, NULL, NULL}, /* 0 */ 1652*9e39c5baSBill Taylor 1653*9e39c5baSBill Taylor /* PIO Transient Errors */ 1654*9e39c5baSBill Taylor {0, HCA_TEST_PIO, ATTACH_TS, NULL, /* attach/transient/start/propagate */ 1655*9e39c5baSBill Taylor HCA_PIO_RETRY_CNT, 0, NULL, NULL, NULL}, /* 1 */ 1656*9e39c5baSBill Taylor {0, HCA_TEST_PIO, ATTACH_TE, NULL, /* attach/transient/end/propagate */ 1657*9e39c5baSBill Taylor HCA_PIO_RETRY_CNT, 0, NULL, NULL, NULL}, /* 2 */ 1658*9e39c5baSBill Taylor 1659*9e39c5baSBill Taylor /* PIO Persistent Errors */ 1660*9e39c5baSBill Taylor {0, HCA_TEST_PIO, ATTACH_PS, NULL, /* attach/persistent/start/propagate */ 1661*9e39c5baSBill Taylor 0, 0, NULL, NULL, NULL}, /* 3 */ 1662*9e39c5baSBill Taylor {0, HCA_TEST_PIO, ATTACH_PE, NULL, /* attach/persistent/end/propagate */ 1663*9e39c5baSBill Taylor 0, 0, NULL, NULL, NULL}, /* 4 */ 1664*9e39c5baSBill Taylor 1665*9e39c5baSBill Taylor }; 1666*9e39c5baSBill Taylor 1667*9e39c5baSBill Taylor 1668*9e39c5baSBill Taylor /* 1669*9e39c5baSBill Taylor * void 1670*9e39c5baSBill Taylor * hermon_trigger_pio_error(hermon_test_t *tst, ddi_fm_error_t *derr) 1671*9e39c5baSBill Taylor * 1672*9e39c5baSBill Taylor * Overview 1673*9e39c5baSBill Taylor * hermon_trigger_pio_error() is a PIO error injection function 1674*9e39c5baSBill Taylor * to cause a pseduo PIO error. 1675*9e39c5baSBill Taylor * 1676*9e39c5baSBill Taylor * Argument 1677*9e39c5baSBill Taylor * tst: pointer to HCA FM function test structure. If the structure 1678*9e39c5baSBill Taylor * is not used, the NULL value must be passed instead. 1679*9e39c5baSBill Taylor * derr: pointer to ddi_fm_error_t structure 1680*9e39c5baSBill Taylor * 1681*9e39c5baSBill Taylor * Return value 1682*9e39c5baSBill Taylor * Nothing 1683*9e39c5baSBill Taylor * 1684*9e39c5baSBill Taylor * Caller's context 1685*9e39c5baSBill Taylor * hermon_trigger_pio_error() can be called in user, kernel, interrupt 1686*9e39c5baSBill Taylor * context or high interrupt context. 1687*9e39c5baSBill Taylor */ 1688*9e39c5baSBill Taylor static void 1689*9e39c5baSBill Taylor hermon_trigger_pio_error(hermon_test_t *tst, ddi_fm_error_t *derr) 1690*9e39c5baSBill Taylor { 1691*9e39c5baSBill Taylor hermon_state_t *state = (hermon_state_t *)tst->private; 1692*9e39c5baSBill Taylor derr->fme_status = DDI_FM_OK; 1693*9e39c5baSBill Taylor 1694*9e39c5baSBill Taylor if (tst->type != HCA_TEST_PIO) { 1695*9e39c5baSBill Taylor return; 1696*9e39c5baSBill Taylor } 1697*9e39c5baSBill Taylor 1698*9e39c5baSBill Taylor if ((tst->trigger & HCA_TEST_ATTACH && 1699*9e39c5baSBill Taylor i_ddi_node_state(state->hs_dip) < DS_ATTACHED && 1700*9e39c5baSBill Taylor hermon_get_state(state) & HCA_PIO_FM)) { 1701*9e39c5baSBill Taylor if (tst->trigger & HCA_TEST_PERSISTENT) { 1702*9e39c5baSBill Taylor i_hca_fm_ereport(state->hs_dip, HCA_IBA_ERR, 1703*9e39c5baSBill Taylor DDI_FM_DEVICE_INVAL_STATE); 1704*9e39c5baSBill Taylor derr->fme_status = DDI_FM_NONFATAL; 1705*9e39c5baSBill Taylor return; 1706*9e39c5baSBill Taylor } else if (tst->trigger & HCA_TEST_TRANSIENT && 1707*9e39c5baSBill Taylor tst->errcnt) { 1708*9e39c5baSBill Taylor i_hca_fm_ereport(state->hs_dip, HCA_IBA_ERR, 1709*9e39c5baSBill Taylor DDI_FM_DEVICE_INVAL_STATE); 1710*9e39c5baSBill Taylor derr->fme_status = DDI_FM_NONFATAL; 1711*9e39c5baSBill Taylor tst->errcnt--; 1712*9e39c5baSBill Taylor return; 1713*9e39c5baSBill Taylor } 1714*9e39c5baSBill Taylor } 1715*9e39c5baSBill Taylor } 1716*9e39c5baSBill Taylor 1717*9e39c5baSBill Taylor 1718*9e39c5baSBill Taylor /* 1719*9e39c5baSBill Taylor * struct hermon_fm_test * 1720*9e39c5baSBill Taylor * hermon_test_register(hermon_state_t *state, char *filename, int linenum, 1721*9e39c5baSBill Taylor * int type) 1722*9e39c5baSBill Taylor * 1723*9e39c5baSBill Taylor * Overview 1724*9e39c5baSBill Taylor * hermon_test_register() registers a Hermon FM test item for the 1725*9e39c5baSBill Taylor * function test. 1726*9e39c5baSBill Taylor * 1727*9e39c5baSBill Taylor * Argument 1728*9e39c5baSBill Taylor * state: pointer to Hermon state structure 1729*9e39c5baSBill Taylor * filename: source file name where the function call is implemented 1730*9e39c5baSBill Taylor * This value is usually a __FILE__ pre-defined macro. 1731*9e39c5baSBill Taylor * linenum: line number where the function call is described in the 1732*9e39c5baSBill Taylor * file specified above. 1733*9e39c5baSBill Taylor * This value is usually a __LINE__ pre-defined macro. 1734*9e39c5baSBill Taylor * type: HW error type 1735*9e39c5baSBill Taylor * HCA_TEST_PIO pio error 1736*9e39c5baSBill Taylor * HCA_TEST_IBA ib specific error 1737*9e39c5baSBill Taylor * 1738*9e39c5baSBill Taylor * Return value 1739*9e39c5baSBill Taylor * pointer to Hermon FM function test structure registered. 1740*9e39c5baSBill Taylor * 1741*9e39c5baSBill Taylor * Caller's context 1742*9e39c5baSBill Taylor * hermon_test_register() can be called in user, kernel or interrupt 1743*9e39c5baSBill Taylor * context. 1744*9e39c5baSBill Taylor * 1745*9e39c5baSBill Taylor * Note that no test item is registered if Hermon FM is disabled. 1746*9e39c5baSBill Taylor */ 1747*9e39c5baSBill Taylor hermon_test_t * 1748*9e39c5baSBill Taylor hermon_test_register(hermon_state_t *state, char *filename, int linenum, 1749*9e39c5baSBill Taylor int type) 1750*9e39c5baSBill Taylor { 1751*9e39c5baSBill Taylor void (*pio_injection)(struct i_hca_fm_test *, ddi_fm_error_t *) = 1752*9e39c5baSBill Taylor (void (*)(struct i_hca_fm_test *, ddi_fm_error_t *)) 1753*9e39c5baSBill Taylor hermon_trigger_pio_error; 1754*9e39c5baSBill Taylor 1755*9e39c5baSBill Taylor if (state->hs_fm_disable) 1756*9e39c5baSBill Taylor return (NULL); 1757*9e39c5baSBill Taylor 1758*9e39c5baSBill Taylor return ((hermon_test_t *)i_hca_test_register(filename, linenum, type, 1759*9e39c5baSBill Taylor pio_injection, (void *)state, state->hs_fm_test_hash, 1760*9e39c5baSBill Taylor state->hs_fm_id_hash, hermon_test_num)); 1761*9e39c5baSBill Taylor } 1762*9e39c5baSBill Taylor #endif /* FMA_TEST */ 1763*9e39c5baSBill Taylor 1764*9e39c5baSBill Taylor 1765*9e39c5baSBill Taylor /* 1766*9e39c5baSBill Taylor * HCA FM Common Interface 1767*9e39c5baSBill Taylor * 1768*9e39c5baSBill Taylor * These functions should be used for any HCA drivers, but probably 1769*9e39c5baSBill Taylor * customized for their own HW design and/or FM implementation. 1770*9e39c5baSBill Taylor * Customized functins should have the driver name prefix such as 1771*9e39c5baSBill Taylor * hermon_xxxx() and be defined separately but whose functions should 1772*9e39c5baSBill Taylor * call the common interface inside. 1773*9e39c5baSBill Taylor */ 1774*9e39c5baSBill Taylor 1775*9e39c5baSBill Taylor /* 1776*9e39c5baSBill Taylor * void 1777*9e39c5baSBill Taylor * i_hca_fm_init(struct i_hca_fm *hca_fm) 1778*9e39c5baSBill Taylor * 1779*9e39c5baSBill Taylor * Overview 1780*9e39c5baSBill Taylor * i_hca_fm_init() is an initialization function which sets up the acc 1781*9e39c5baSBill Taylor * handle kmem_cache if this function is called the first time. 1782*9e39c5baSBill Taylor * 1783*9e39c5baSBill Taylor * Argument 1784*9e39c5baSBill Taylor * hca_fm: pointer to HCA FM structure 1785*9e39c5baSBill Taylor * 1786*9e39c5baSBill Taylor * Return value 1787*9e39c5baSBill Taylor * Nothing 1788*9e39c5baSBill Taylor * 1789*9e39c5baSBill Taylor * Caller's context 1790*9e39c5baSBill Taylor * i_hca_fm_init() can be called in user or kernel context, but cannot 1791*9e39c5baSBill Taylor * be called in interrupt context. 1792*9e39c5baSBill Taylor */ 1793*9e39c5baSBill Taylor static void 1794*9e39c5baSBill Taylor i_hca_fm_init(struct i_hca_fm *hca_fm) 1795*9e39c5baSBill Taylor { 1796*9e39c5baSBill Taylor 1797*9e39c5baSBill Taylor mutex_enter(&hca_fm->lock); 1798*9e39c5baSBill Taylor 1799*9e39c5baSBill Taylor ++hca_fm->ref_cnt; 1800*9e39c5baSBill Taylor if (hca_fm->fm_acc_cache == NULL) { 1801*9e39c5baSBill Taylor hca_fm->fm_acc_cache = kmem_cache_create("hca_fm_acc_handle", 1802*9e39c5baSBill Taylor sizeof (struct i_hca_acc_handle), 0, NULL, 1803*9e39c5baSBill Taylor NULL, NULL, NULL, NULL, 0); 1804*9e39c5baSBill Taylor } 1805*9e39c5baSBill Taylor 1806*9e39c5baSBill Taylor mutex_exit(&hca_fm->lock); 1807*9e39c5baSBill Taylor } 1808*9e39c5baSBill Taylor 1809*9e39c5baSBill Taylor 1810*9e39c5baSBill Taylor /* 1811*9e39c5baSBill Taylor * void 1812*9e39c5baSBill Taylor * i_hca_fm_fini(struct i_hca_fm *hca_fm) 1813*9e39c5baSBill Taylor * 1814*9e39c5baSBill Taylor * Overview 1815*9e39c5baSBill Taylor * i_hca_fm_fini() is a finalization function which frees up the acc 1816*9e39c5baSBill Taylor * handle kmem_cache if this function is called the last time. 1817*9e39c5baSBill Taylor * 1818*9e39c5baSBill Taylor * Argument 1819*9e39c5baSBill Taylor * hca_fm: pointer to HCA FM structure 1820*9e39c5baSBill Taylor * 1821*9e39c5baSBill Taylor * Return value 1822*9e39c5baSBill Taylor * Nothing 1823*9e39c5baSBill Taylor * 1824*9e39c5baSBill Taylor * Caller's context 1825*9e39c5baSBill Taylor * i_hca_fm_fini() can be called in user or kernel context, but cannot 1826*9e39c5baSBill Taylor * be called in interrupt context. 1827*9e39c5baSBill Taylor */ 1828*9e39c5baSBill Taylor static void 1829*9e39c5baSBill Taylor i_hca_fm_fini(struct i_hca_fm *hca_fm) 1830*9e39c5baSBill Taylor { 1831*9e39c5baSBill Taylor mutex_enter(&hca_fm->lock); 1832*9e39c5baSBill Taylor 1833*9e39c5baSBill Taylor if (--hca_fm->ref_cnt == 0) { 1834*9e39c5baSBill Taylor 1835*9e39c5baSBill Taylor if (hca_fm->fm_acc_cache) { 1836*9e39c5baSBill Taylor kmem_cache_destroy(hca_fm->fm_acc_cache); 1837*9e39c5baSBill Taylor hca_fm->fm_acc_cache = NULL; 1838*9e39c5baSBill Taylor } 1839*9e39c5baSBill Taylor } 1840*9e39c5baSBill Taylor 1841*9e39c5baSBill Taylor mutex_exit(&hca_fm->lock); 1842*9e39c5baSBill Taylor } 1843*9e39c5baSBill Taylor 1844*9e39c5baSBill Taylor 1845*9e39c5baSBill Taylor /* 1846*9e39c5baSBill Taylor * void 1847*9e39c5baSBill Taylor * i_hca_fm_ereport(dev_info_t *dip, int type, char *detail) 1848*9e39c5baSBill Taylor * 1849*9e39c5baSBill Taylor * Overview 1850*9e39c5baSBill Taylor * i_hca_fm_ereport() is a wrapper function of ddi_fm_ereport_post() but 1851*9e39c5baSBill Taylor * generates an ena before it calls ddi_fm_ereport_post() for HCA 1852*9e39c5baSBill Taylor * specific HW errors. 1853*9e39c5baSBill Taylor * 1854*9e39c5baSBill Taylor * Argument 1855*9e39c5baSBill Taylor * dip: pointer to this device dev_info structure 1856*9e39c5baSBill Taylor * type: error type 1857*9e39c5baSBill Taylor * HCA_SYS_ERR FMA reporting HW error 1858*9e39c5baSBill Taylor * HCA_IBA_ERR HCA specific HW error 1859*9e39c5baSBill Taylor * detail: definition of leaf driver detected ereports which is one of: 1860*9e39c5baSBill Taylor * DDI_FM_DEVICE_INVAL_STATE 1861*9e39c5baSBill Taylor * DDI_FM_DEVICE_NO_RESPONSE 1862*9e39c5baSBill Taylor * DDI_FM_DEVICE_STALL 1863*9e39c5baSBill Taylor * DDI_FM_DEVICE_BADINT_LIMIT 1864*9e39c5baSBill Taylor * DDI_FM_DEVICE_INTERN_CORR 1865*9e39c5baSBill Taylor * DDI_FM_DEVICE_INTERN_UNCORR 1866*9e39c5baSBill Taylor * 1867*9e39c5baSBill Taylor * Return value 1868*9e39c5baSBill Taylor * Nothing 1869*9e39c5baSBill Taylor * 1870*9e39c5baSBill Taylor * Caller's context 1871*9e39c5baSBill Taylor * i_hca_fm_ereport() can be called in user, kernel or interrupt context. 1872*9e39c5baSBill Taylor */ 1873*9e39c5baSBill Taylor static void 1874*9e39c5baSBill Taylor i_hca_fm_ereport(dev_info_t *dip, int type, char *detail) 1875*9e39c5baSBill Taylor { 1876*9e39c5baSBill Taylor uint64_t ena; 1877*9e39c5baSBill Taylor char buf[FM_MAX_CLASS]; 1878*9e39c5baSBill Taylor 1879*9e39c5baSBill Taylor (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail); 1880*9e39c5baSBill Taylor 1881*9e39c5baSBill Taylor ena = fm_ena_generate(0, FM_ENA_FMT1); 1882*9e39c5baSBill Taylor if (type == HCA_IBA_ERR) { 1883*9e39c5baSBill Taylor /* this is an error of its own */ 1884*9e39c5baSBill Taylor ena = fm_ena_increment(ena); 1885*9e39c5baSBill Taylor } 1886*9e39c5baSBill Taylor 1887*9e39c5baSBill Taylor ddi_fm_ereport_post(dip, buf, ena, DDI_NOSLEEP, 1888*9e39c5baSBill Taylor FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0, NULL); 1889*9e39c5baSBill Taylor } 1890*9e39c5baSBill Taylor 1891*9e39c5baSBill Taylor 1892*9e39c5baSBill Taylor /* 1893*9e39c5baSBill Taylor * struct i_hca_acc_handle * 1894*9e39c5baSBill Taylor * i_hca_get_acc_handle(struct i_hca_fm *hca_fm, ddi_acc_handle_t handle) 1895*9e39c5baSBill Taylor * 1896*9e39c5baSBill Taylor * Overview 1897*9e39c5baSBill Taylor * i_hca_get_acc_handle() returns ddi_acc_handle_t used for HCA FM. 1898*9e39c5baSBill Taylor * 1899*9e39c5baSBill Taylor * Argument 1900*9e39c5baSBill Taylor * hca_fm: pointer to HCA FM structure 1901*9e39c5baSBill Taylor * handle: ddi_acc_handle_t 1902*9e39c5baSBill Taylor * 1903*9e39c5baSBill Taylor * Return value 1904*9e39c5baSBill Taylor * handle: pointer to ddi_acc_handle_t used for HCA FM 1905*9e39c5baSBill Taylor * 1906*9e39c5baSBill Taylor * Caller's context 1907*9e39c5baSBill Taylor * i_hca_get_acc_handle() can be called in user, kernel or interrupt 1908*9e39c5baSBill Taylor * context. 1909*9e39c5baSBill Taylor */ 1910*9e39c5baSBill Taylor static struct i_hca_acc_handle * 1911*9e39c5baSBill Taylor i_hca_get_acc_handle(struct i_hca_fm *hca_fm, ddi_acc_handle_t handle) 1912*9e39c5baSBill Taylor { 1913*9e39c5baSBill Taylor struct i_hca_acc_handle *hdlp; 1914*9e39c5baSBill Taylor 1915*9e39c5baSBill Taylor /* Retrieve the HCA FM access handle */ 1916*9e39c5baSBill Taylor mutex_enter(&hca_fm->lock); 1917*9e39c5baSBill Taylor 1918*9e39c5baSBill Taylor for (hdlp = hca_fm->hdl; hdlp != NULL; hdlp = hdlp->next) { 1919*9e39c5baSBill Taylor if (hdlp->save_hdl == handle) { 1920*9e39c5baSBill Taylor mutex_exit(&hca_fm->lock); 1921*9e39c5baSBill Taylor return (hdlp); 1922*9e39c5baSBill Taylor } 1923*9e39c5baSBill Taylor } 1924*9e39c5baSBill Taylor 1925*9e39c5baSBill Taylor mutex_exit(&hca_fm->lock); 1926*9e39c5baSBill Taylor return (hdlp); 1927*9e39c5baSBill Taylor } 1928*9e39c5baSBill Taylor 1929*9e39c5baSBill Taylor 1930*9e39c5baSBill Taylor /* 1931*9e39c5baSBill Taylor * int 1932*9e39c5baSBill Taylor * i_hca_regs_map_setup(struct i_hca_fm *hca_fm, dev_info_t *dip, 1933*9e39c5baSBill Taylor * uint_t rnumber, caddr_t *addrp, offset_t offset, offset_t len, 1934*9e39c5baSBill Taylor * ddi_device_acc_attr_t *accattrp, ddi_acc_handle_t *handle) 1935*9e39c5baSBill Taylor * 1936*9e39c5baSBill Taylor * Overview 1937*9e39c5baSBill Taylor * i_hca_regs_map_setup() is a wrapper function of ddi_regs_map_setup(), 1938*9e39c5baSBill Taylor * but allocates the HCA FM acc handle structure and initializes it. 1939*9e39c5baSBill Taylor * 1940*9e39c5baSBill Taylor * Argument 1941*9e39c5baSBill Taylor * hca_fm: pointer to HCA FM structure 1942*9e39c5baSBill Taylor * dip: pointer to this device dev_info structure 1943*9e39c5baSBill Taylor * rnumber: index number to the register address space set 1944*9e39c5baSBill Taylor * addrp: platform-dependent value (same as ddi_regs_map_setup()) 1945*9e39c5baSBill Taylor * offset: offset into the register address space 1946*9e39c5baSBill Taylor * len: address space length to be mapped 1947*9e39c5baSBill Taylor * accattrp: pointer to device access attribute structure 1948*9e39c5baSBill Taylor * handle: pointer to ddi_acc_handle_t used for HCA FM 1949*9e39c5baSBill Taylor * 1950*9e39c5baSBill Taylor * Return value 1951*9e39c5baSBill Taylor * ddi function status value which are: 1952*9e39c5baSBill Taylor * DDI_SUCCESS 1953*9e39c5baSBill Taylor * DDI_FAILURE 1954*9e39c5baSBill Taylor * DDI_ME_RNUMBER_RNGE 1955*9e39c5baSBill Taylor * DDI_REGS_ACC_CONFLICT 1956*9e39c5baSBill Taylor * 1957*9e39c5baSBill Taylor * Caller's context 1958*9e39c5baSBill Taylor * i_hca_regs_map_setup() can be called in user or kernel context only. 1959*9e39c5baSBill Taylor */ 1960*9e39c5baSBill Taylor static int 1961*9e39c5baSBill Taylor i_hca_regs_map_setup(struct i_hca_fm *hca_fm, dev_info_t *dip, uint_t rnumber, 1962*9e39c5baSBill Taylor caddr_t *addrp, offset_t offset, offset_t len, 1963*9e39c5baSBill Taylor ddi_device_acc_attr_t *accattrp, ddi_acc_handle_t *handle) 1964*9e39c5baSBill Taylor { 1965*9e39c5baSBill Taylor int status; 1966*9e39c5baSBill Taylor struct i_hca_acc_handle *handlep, *hdlp, *last; 1967*9e39c5baSBill Taylor 1968*9e39c5baSBill Taylor /* Allocate an access handle */ 1969*9e39c5baSBill Taylor if ((status = ddi_regs_map_setup(dip, rnumber, addrp, offset, 1970*9e39c5baSBill Taylor len, accattrp, handle)) != DDI_SUCCESS) { 1971*9e39c5baSBill Taylor return (status); 1972*9e39c5baSBill Taylor } 1973*9e39c5baSBill Taylor 1974*9e39c5baSBill Taylor /* Allocate HCA FM acc handle structure */ 1975*9e39c5baSBill Taylor handlep = kmem_cache_alloc(hca_fm->fm_acc_cache, KM_SLEEP); 1976*9e39c5baSBill Taylor 1977*9e39c5baSBill Taylor /* Initialize fields */ 1978*9e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*handlep)) 1979*9e39c5baSBill Taylor handlep->next = NULL; 1980*9e39c5baSBill Taylor handlep->save_hdl = (*handle); 1981*9e39c5baSBill Taylor handlep->thread_cnt = 0; 1982*9e39c5baSBill Taylor mutex_init(&handlep->lock, NULL, MUTEX_DRIVER, NULL); 1983*9e39c5baSBill Taylor 1984*9e39c5baSBill Taylor /* Register this handle */ 1985*9e39c5baSBill Taylor mutex_enter(&hca_fm->lock); 1986*9e39c5baSBill Taylor for (last = hdlp = hca_fm->hdl; hdlp != NULL; hdlp = hdlp->next) { 1987*9e39c5baSBill Taylor last = hdlp; 1988*9e39c5baSBill Taylor } 1989*9e39c5baSBill Taylor if (last == NULL) { 1990*9e39c5baSBill Taylor hca_fm->hdl = handlep; 1991*9e39c5baSBill Taylor } else { 1992*9e39c5baSBill Taylor last->next = handlep; 1993*9e39c5baSBill Taylor } 1994*9e39c5baSBill Taylor mutex_exit(&hca_fm->lock); 1995*9e39c5baSBill Taylor 1996*9e39c5baSBill Taylor return (status); 1997*9e39c5baSBill Taylor } 1998*9e39c5baSBill Taylor 1999*9e39c5baSBill Taylor 2000*9e39c5baSBill Taylor /* 2001*9e39c5baSBill Taylor * void 2002*9e39c5baSBill Taylor * i_hca_regs_map_free(struct i_hca_fm *hca_fm, ddi_acc_handle_t *handlep) 2003*9e39c5baSBill Taylor * 2004*9e39c5baSBill Taylor * Overview 2005*9e39c5baSBill Taylor * i_hca_regs_map_setup() is a wrapper function of ddi_regs_map_free(), 2006*9e39c5baSBill Taylor * and frees the HCA FM acc handle structure allocated by 2007*9e39c5baSBill Taylor * i_hca_regs_map_setup(). 2008*9e39c5baSBill Taylor * 2009*9e39c5baSBill Taylor * Argument 2010*9e39c5baSBill Taylor * hca_fm: pointer to HCA FM structure 2011*9e39c5baSBill Taylor * handle: pointer to ddi_acc_handle_t used for HCA FM 2012*9e39c5baSBill Taylor * 2013*9e39c5baSBill Taylor * Return value 2014*9e39c5baSBill Taylor * Nothing 2015*9e39c5baSBill Taylor * 2016*9e39c5baSBill Taylor * Caller's context 2017*9e39c5baSBill Taylor * i_hca_regs_map_free() can be called in user or kernel context only. 2018*9e39c5baSBill Taylor * 2019*9e39c5baSBill Taylor * Note that the handle passed to i_hca_regs_map_free() is NULL-cleared 2020*9e39c5baSBill Taylor * after this function is called. 2021*9e39c5baSBill Taylor */ 2022*9e39c5baSBill Taylor static void 2023*9e39c5baSBill Taylor i_hca_regs_map_free(struct i_hca_fm *hca_fm, ddi_acc_handle_t *handle) 2024*9e39c5baSBill Taylor { 2025*9e39c5baSBill Taylor struct i_hca_acc_handle *handlep, *hdlp, *prev; 2026*9e39c5baSBill Taylor 2027*9e39c5baSBill Taylor /* De-register this handle */ 2028*9e39c5baSBill Taylor mutex_enter(&hca_fm->lock); 2029*9e39c5baSBill Taylor for (prev = hdlp = hca_fm->hdl; hdlp != NULL; hdlp = hdlp->next) { 2030*9e39c5baSBill Taylor if (hdlp->save_hdl == *handle) 2031*9e39c5baSBill Taylor break; 2032*9e39c5baSBill Taylor prev = hdlp; 2033*9e39c5baSBill Taylor } 2034*9e39c5baSBill Taylor ASSERT(prev != NULL && hdlp != NULL); 2035*9e39c5baSBill Taylor if (hdlp != prev) { 2036*9e39c5baSBill Taylor prev->next = hdlp->next; 2037*9e39c5baSBill Taylor } else { 2038*9e39c5baSBill Taylor hca_fm->hdl = hdlp->next; 2039*9e39c5baSBill Taylor } 2040*9e39c5baSBill Taylor handlep = hdlp; 2041*9e39c5baSBill Taylor mutex_exit(&hca_fm->lock); 2042*9e39c5baSBill Taylor 2043*9e39c5baSBill Taylor mutex_destroy(&handlep->lock); 2044*9e39c5baSBill Taylor handlep->save_hdl = NULL; 2045*9e39c5baSBill Taylor kmem_cache_free(hca_fm->fm_acc_cache, handlep); 2046*9e39c5baSBill Taylor 2047*9e39c5baSBill Taylor /* Release this handle */ 2048*9e39c5baSBill Taylor ddi_regs_map_free(handle); 2049*9e39c5baSBill Taylor *handle = NULL; 2050*9e39c5baSBill Taylor } 2051*9e39c5baSBill Taylor 2052*9e39c5baSBill Taylor 2053*9e39c5baSBill Taylor /* 2054*9e39c5baSBill Taylor * int 2055*9e39c5baSBill Taylor * i_hca_pci_config_setup(struct i_hca_fm *hca_fm, dev_info_t *dip, 2056*9e39c5baSBill Taylor * ddi_acc_handle_t *handle, boolean_t fm_protect) 2057*9e39c5baSBill Taylor * 2058*9e39c5baSBill Taylor * Overview 2059*9e39c5baSBill Taylor * i_hca_pci_config_setup() is a wrapper function of pci_config_setup(), 2060*9e39c5baSBill Taylor * but allocates the HCA FM acc handle structure and initializes it. 2061*9e39c5baSBill Taylor * 2062*9e39c5baSBill Taylor * Argument 2063*9e39c5baSBill Taylor * hca_fm: pointer to HCA FM structure 2064*9e39c5baSBill Taylor * dip: pointer to this device dev_info structure 2065*9e39c5baSBill Taylor * handle: pointer to ddi_acc_handle_t used for HCA PCI config space 2066*9e39c5baSBill Taylor * with FMA 2067*9e39c5baSBill Taylor * fm_protect: flag to tell if an fma-protected access handle should 2068*9e39c5baSBill Taylor * be used 2069*9e39c5baSBill Taylor * 2070*9e39c5baSBill Taylor * Return value 2071*9e39c5baSBill Taylor * ddi function status value which are: 2072*9e39c5baSBill Taylor * DDI_SUCCESS 2073*9e39c5baSBill Taylor * DDI_FAILURE 2074*9e39c5baSBill Taylor * 2075*9e39c5baSBill Taylor * Caller's context 2076*9e39c5baSBill Taylor * i_hca_pci_config_setup() can be called in user or kernel context only. 2077*9e39c5baSBill Taylor */ 2078*9e39c5baSBill Taylor static int 2079*9e39c5baSBill Taylor i_hca_pci_config_setup(struct i_hca_fm *hca_fm, dev_info_t *dip, 2080*9e39c5baSBill Taylor ddi_acc_handle_t *handle) 2081*9e39c5baSBill Taylor { 2082*9e39c5baSBill Taylor int status; 2083*9e39c5baSBill Taylor struct i_hca_acc_handle *handlep, *hdlp, *last; 2084*9e39c5baSBill Taylor 2085*9e39c5baSBill Taylor /* Allocate an access handle */ 2086*9e39c5baSBill Taylor if ((status = pci_config_setup(dip, handle)) != DDI_SUCCESS) { 2087*9e39c5baSBill Taylor return (status); 2088*9e39c5baSBill Taylor } 2089*9e39c5baSBill Taylor 2090*9e39c5baSBill Taylor /* Allocate HCA FM acc handle structure */ 2091*9e39c5baSBill Taylor handlep = kmem_cache_alloc(hca_fm->fm_acc_cache, KM_SLEEP); 2092*9e39c5baSBill Taylor 2093*9e39c5baSBill Taylor /* Initialize fields */ 2094*9e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*handlep)) 2095*9e39c5baSBill Taylor handlep->next = NULL; 2096*9e39c5baSBill Taylor handlep->save_hdl = (*handle); 2097*9e39c5baSBill Taylor handlep->thread_cnt = 0; 2098*9e39c5baSBill Taylor mutex_init(&handlep->lock, NULL, MUTEX_DRIVER, NULL); 2099*9e39c5baSBill Taylor 2100*9e39c5baSBill Taylor /* Register this handle */ 2101*9e39c5baSBill Taylor mutex_enter(&hca_fm->lock); 2102*9e39c5baSBill Taylor for (last = hdlp = hca_fm->hdl; hdlp != NULL; hdlp = hdlp->next) { 2103*9e39c5baSBill Taylor last = hdlp; 2104*9e39c5baSBill Taylor } 2105*9e39c5baSBill Taylor if (last == NULL) { 2106*9e39c5baSBill Taylor hca_fm->hdl = handlep; 2107*9e39c5baSBill Taylor } else { 2108*9e39c5baSBill Taylor last->next = handlep; 2109*9e39c5baSBill Taylor } 2110*9e39c5baSBill Taylor mutex_exit(&hca_fm->lock); 2111*9e39c5baSBill Taylor 2112*9e39c5baSBill Taylor return (status); 2113*9e39c5baSBill Taylor } 2114*9e39c5baSBill Taylor 2115*9e39c5baSBill Taylor 2116*9e39c5baSBill Taylor /* 2117*9e39c5baSBill Taylor * void 2118*9e39c5baSBill Taylor * i_hca_pci_config_teardown(struct i_hca_fm *hca_fm, 2119*9e39c5baSBill Taylor * ddi_acc_handle_t *handlep) 2120*9e39c5baSBill Taylor * 2121*9e39c5baSBill Taylor * Overview 2122*9e39c5baSBill Taylor * i_hca_pci_config_teardown() is a wrapper function of 2123*9e39c5baSBill Taylor * pci_config_teardown(), and frees the HCA FM acc handle structure 2124*9e39c5baSBill Taylor * allocated by i_hca_pci_config_setup(). 2125*9e39c5baSBill Taylor * 2126*9e39c5baSBill Taylor * Argument 2127*9e39c5baSBill Taylor * hca_fm: pointer to HCA FM structure 2128*9e39c5baSBill Taylor * handle: pointer to ddi_acc_handle_t used for HCA FM 2129*9e39c5baSBill Taylor * 2130*9e39c5baSBill Taylor * Return value 2131*9e39c5baSBill Taylor * Nothing 2132*9e39c5baSBill Taylor * 2133*9e39c5baSBill Taylor * Caller's context 2134*9e39c5baSBill Taylor * i_hca_pci_config_teardown() can be called in user or kernel context 2135*9e39c5baSBill Taylor * only. 2136*9e39c5baSBill Taylor * 2137*9e39c5baSBill Taylor * Note that the handle passed to i_hca_pci_config_teardown() is NULL-cleared 2138*9e39c5baSBill Taylor * after this function is called. 2139*9e39c5baSBill Taylor */ 2140*9e39c5baSBill Taylor static void 2141*9e39c5baSBill Taylor i_hca_pci_config_teardown(struct i_hca_fm *hca_fm, ddi_acc_handle_t *handle) 2142*9e39c5baSBill Taylor { 2143*9e39c5baSBill Taylor struct i_hca_acc_handle *handlep, *hdlp, *prev; 2144*9e39c5baSBill Taylor 2145*9e39c5baSBill Taylor /* De-register this handle */ 2146*9e39c5baSBill Taylor mutex_enter(&hca_fm->lock); 2147*9e39c5baSBill Taylor for (prev = hdlp = hca_fm->hdl; hdlp != NULL; hdlp = hdlp->next) { 2148*9e39c5baSBill Taylor if (hdlp->save_hdl == *handle) 2149*9e39c5baSBill Taylor break; 2150*9e39c5baSBill Taylor prev = hdlp; 2151*9e39c5baSBill Taylor } 2152*9e39c5baSBill Taylor ASSERT(prev != NULL && hdlp != NULL); 2153*9e39c5baSBill Taylor if (hdlp != prev) { 2154*9e39c5baSBill Taylor prev->next = hdlp->next; 2155*9e39c5baSBill Taylor } else { 2156*9e39c5baSBill Taylor hca_fm->hdl = hdlp->next; 2157*9e39c5baSBill Taylor } 2158*9e39c5baSBill Taylor handlep = hdlp; 2159*9e39c5baSBill Taylor mutex_exit(&hca_fm->lock); 2160*9e39c5baSBill Taylor 2161*9e39c5baSBill Taylor mutex_destroy(&handlep->lock); 2162*9e39c5baSBill Taylor handlep->save_hdl = NULL; 2163*9e39c5baSBill Taylor kmem_cache_free(hca_fm->fm_acc_cache, handlep); 2164*9e39c5baSBill Taylor 2165*9e39c5baSBill Taylor /* Release this handle */ 2166*9e39c5baSBill Taylor pci_config_teardown(handle); 2167*9e39c5baSBill Taylor *handle = NULL; 2168*9e39c5baSBill Taylor } 2169*9e39c5baSBill Taylor 2170*9e39c5baSBill Taylor 2171*9e39c5baSBill Taylor /* 2172*9e39c5baSBill Taylor * int 2173*9e39c5baSBill Taylor * i_hca_pio_start(dev_info_t *dip, struct i_acc_handle *handle, 2174*9e39c5baSBill Taylor * struct i_hca_fm_test *tst) 2175*9e39c5baSBill Taylor * 2176*9e39c5baSBill Taylor * Overview 2177*9e39c5baSBill Taylor * i_hca_pio_start() is one of a pair of HCA FM fuctions for PIO, which 2178*9e39c5baSBill Taylor * should be called before HCA drivers issue PIOs against I/O space. 2179*9e39c5baSBill Taylor * See HCA FM comments at the beginning of this file in detail. 2180*9e39c5baSBill Taylor * 2181*9e39c5baSBill Taylor * Argument 2182*9e39c5baSBill Taylor * dip: pointer to this device dev_info structure 2183*9e39c5baSBill Taylor * handle: pointer to ddi_acc_handle_t used for HCA FM 2184*9e39c5baSBill Taylor * tst: pointer to HCA FM function test structure. If the structure 2185*9e39c5baSBill Taylor * is not used, the NULL value must be passed instead. 2186*9e39c5baSBill Taylor * 2187*9e39c5baSBill Taylor * Return value 2188*9e39c5baSBill Taylor * error status showing whether or not this error can retry 2189*9e39c5baSBill Taylor * HCA_PIO_OK No HW errors 2190*9e39c5baSBill Taylor * HCA_PIO_TRANSIENT This error could be transient 2191*9e39c5baSBill Taylor * HCA_PIO_PERSISTENT This error is persistent 2192*9e39c5baSBill Taylor * 2193*9e39c5baSBill Taylor * Caller's context 2194*9e39c5baSBill Taylor * i_hca_pio_start() can be called in user, kernel or interrupt context. 2195*9e39c5baSBill Taylor */ 2196*9e39c5baSBill Taylor /* ARGSUSED */ 2197*9e39c5baSBill Taylor static int 2198*9e39c5baSBill Taylor i_hca_pio_start(dev_info_t *dip, struct i_hca_acc_handle *hdlp, 2199*9e39c5baSBill Taylor struct i_hca_fm_test *tst) 2200*9e39c5baSBill Taylor { 2201*9e39c5baSBill Taylor ddi_fm_error_t derr; 2202*9e39c5baSBill Taylor 2203*9e39c5baSBill Taylor /* Count up the number of threads issuing this PIO */ 2204*9e39c5baSBill Taylor mutex_enter(&hdlp->lock); 2205*9e39c5baSBill Taylor hdlp->thread_cnt++; 2206*9e39c5baSBill Taylor mutex_exit(&hdlp->lock); 2207*9e39c5baSBill Taylor 2208*9e39c5baSBill Taylor /* Get the PIO error via FMA */ 2209*9e39c5baSBill Taylor ddi_fm_acc_err_get(fm_acc_hdl(hdlp), &derr, DDI_FME_VERSION); 2210*9e39c5baSBill Taylor 2211*9e39c5baSBill Taylor #ifdef FMA_TEST 2212*9e39c5baSBill Taylor /* Trigger PIO errors */ 2213*9e39c5baSBill Taylor if (tst != NULL && tst->trigger & HCA_TEST_START) { 2214*9e39c5baSBill Taylor (*tst->pio_injection)(tst, &derr); 2215*9e39c5baSBill Taylor } 2216*9e39c5baSBill Taylor #endif /* FMA_TEST */ 2217*9e39c5baSBill Taylor 2218*9e39c5baSBill Taylor switch (derr.fme_status) { 2219*9e39c5baSBill Taylor case DDI_FM_OK: 2220*9e39c5baSBill Taylor /* Not have to clear the fma error log */ 2221*9e39c5baSBill Taylor return (HCA_PIO_OK); 2222*9e39c5baSBill Taylor 2223*9e39c5baSBill Taylor case DDI_FM_NONFATAL: 2224*9e39c5baSBill Taylor /* Now clear this error */ 2225*9e39c5baSBill Taylor ddi_fm_acc_err_clear(fm_acc_hdl(hdlp), DDI_FME_VERSION); 2226*9e39c5baSBill Taylor 2227*9e39c5baSBill Taylor /* Log this error and notify it as a persistent error */ 2228*9e39c5baSBill Taylor ddi_fm_service_impact(dip, DDI_SERVICE_LOST); 2229*9e39c5baSBill Taylor return (HCA_PIO_PERSISTENT); 2230*9e39c5baSBill Taylor 2231*9e39c5baSBill Taylor /* In theory, this shouldn't happen */ 2232*9e39c5baSBill Taylor case DDI_FM_FATAL: 2233*9e39c5baSBill Taylor case DDI_FM_UNKNOWN: 2234*9e39c5baSBill Taylor default: 2235*9e39c5baSBill Taylor cmn_err(CE_WARN, "Unknown HCA HW error status (%d)", 2236*9e39c5baSBill Taylor derr.fme_status); 2237*9e39c5baSBill Taylor /* Return this as a persistent error */ 2238*9e39c5baSBill Taylor return (HCA_PIO_PERSISTENT); 2239*9e39c5baSBill Taylor } 2240*9e39c5baSBill Taylor } 2241*9e39c5baSBill Taylor 2242*9e39c5baSBill Taylor 2243*9e39c5baSBill Taylor /* 2244*9e39c5baSBill Taylor * int 2245*9e39c5baSBill Taylor * i_hca_pio_end(dev_info_t *dip, ddi_acc_handle_t handle, int *cnt, 2246*9e39c5baSBill Taylor * struct i_hca_fm_test *tst) 2247*9e39c5baSBill Taylor * 2248*9e39c5baSBill Taylor * Overview 2249*9e39c5baSBill Taylor * i_hca_pio_end() is the other of a pair of HCA FM fuctions for PIO, 2250*9e39c5baSBill Taylor * which should be called after HCA drivers issue PIOs against I/O space. 2251*9e39c5baSBill Taylor * See HCA FM comments at the beginning of this file in detail. 2252*9e39c5baSBill Taylor * 2253*9e39c5baSBill Taylor * Argument 2254*9e39c5baSBill Taylor * dip: pointer to this device dev_info structure 2255*9e39c5baSBill Taylor * handle: pointer to ddi_acc_handle_t used for HCA FM 2256*9e39c5baSBill Taylor * cnt: pointer to the counter variable which holds the nubmer of retry 2257*9e39c5baSBill Taylor * when a HW error is detected. 2258*9e39c5baSBill Taylor * tst: pointer to HCA FM function test structure. If the structure 2259*9e39c5baSBill Taylor * is not used, the NULL value must be passed instead. 2260*9e39c5baSBill Taylor * 2261*9e39c5baSBill Taylor * Return value 2262*9e39c5baSBill Taylor * error status showing whether or not this error can retry 2263*9e39c5baSBill Taylor * HCA_PIO_OK No HW errors 2264*9e39c5baSBill Taylor * HCA_PIO_TRANSIENT This error could be transient 2265*9e39c5baSBill Taylor * HCA_PIO_PERSISTENT This error is persistent 2266*9e39c5baSBill Taylor * 2267*9e39c5baSBill Taylor * Caller's context 2268*9e39c5baSBill Taylor * i_hca_pio_end() can be called in user, kernel or interrupt context. 2269*9e39c5baSBill Taylor */ 2270*9e39c5baSBill Taylor /* ARGSUSED */ 2271*9e39c5baSBill Taylor static int 2272*9e39c5baSBill Taylor i_hca_pio_end(dev_info_t *dip, struct i_hca_acc_handle *hdlp, int *cnt, 2273*9e39c5baSBill Taylor struct i_hca_fm_test *tst) 2274*9e39c5baSBill Taylor { 2275*9e39c5baSBill Taylor ddi_fm_error_t derr; 2276*9e39c5baSBill Taylor 2277*9e39c5baSBill Taylor /* Get the PIO error via FMA */ 2278*9e39c5baSBill Taylor ddi_fm_acc_err_get(fm_acc_hdl(hdlp), &derr, DDI_FME_VERSION); 2279*9e39c5baSBill Taylor 2280*9e39c5baSBill Taylor #ifdef FMA_TEST 2281*9e39c5baSBill Taylor /* Trigger PIO errors */ 2282*9e39c5baSBill Taylor if (tst != NULL && tst->trigger & HCA_TEST_END) { 2283*9e39c5baSBill Taylor (*tst->pio_injection)(tst, &derr); 2284*9e39c5baSBill Taylor } 2285*9e39c5baSBill Taylor #endif /* FMA_TEST */ 2286*9e39c5baSBill Taylor 2287*9e39c5baSBill Taylor /* Evaluate the PIO error */ 2288*9e39c5baSBill Taylor switch (derr.fme_status) { 2289*9e39c5baSBill Taylor case DDI_FM_OK: 2290*9e39c5baSBill Taylor /* Count down the number of threads issuing this PIO */ 2291*9e39c5baSBill Taylor mutex_enter(&hdlp->lock); 2292*9e39c5baSBill Taylor hdlp->thread_cnt--; 2293*9e39c5baSBill Taylor mutex_exit(&hdlp->lock); 2294*9e39c5baSBill Taylor 2295*9e39c5baSBill Taylor /* Not have to clear the fma error log */ 2296*9e39c5baSBill Taylor return (HCA_PIO_OK); 2297*9e39c5baSBill Taylor 2298*9e39c5baSBill Taylor case DDI_FM_NONFATAL: 2299*9e39c5baSBill Taylor /* Now clear this error */ 2300*9e39c5baSBill Taylor ddi_fm_acc_err_clear(fm_acc_hdl(hdlp), DDI_FME_VERSION); 2301*9e39c5baSBill Taylor 2302*9e39c5baSBill Taylor /* 2303*9e39c5baSBill Taylor * Check if this error comes from another thread running 2304*9e39c5baSBill Taylor * with the same handle almost at the same time. 2305*9e39c5baSBill Taylor */ 2306*9e39c5baSBill Taylor mutex_enter(&hdlp->lock); 2307*9e39c5baSBill Taylor if (hdlp->thread_cnt > 1) { 2308*9e39c5baSBill Taylor /* Count down the number of threads */ 2309*9e39c5baSBill Taylor hdlp->thread_cnt--; 2310*9e39c5baSBill Taylor mutex_exit(&hdlp->lock); 2311*9e39c5baSBill Taylor 2312*9e39c5baSBill Taylor /* Return this as a persistent error */ 2313*9e39c5baSBill Taylor return (HCA_PIO_PERSISTENT); 2314*9e39c5baSBill Taylor } 2315*9e39c5baSBill Taylor mutex_exit(&hdlp->lock); 2316*9e39c5baSBill Taylor 2317*9e39c5baSBill Taylor /* Now determine if this error is persistent or not */ 2318*9e39c5baSBill Taylor if (--(*cnt) >= 0) { 2319*9e39c5baSBill Taylor return (HCA_PIO_TRANSIENT); 2320*9e39c5baSBill Taylor } else { 2321*9e39c5baSBill Taylor /* Count down the number of threads */ 2322*9e39c5baSBill Taylor mutex_enter(&hdlp->lock); 2323*9e39c5baSBill Taylor hdlp->thread_cnt--; 2324*9e39c5baSBill Taylor mutex_exit(&hdlp->lock); 2325*9e39c5baSBill Taylor return (HCA_PIO_PERSISTENT); 2326*9e39c5baSBill Taylor } 2327*9e39c5baSBill Taylor 2328*9e39c5baSBill Taylor /* In theory, this shouldn't happen */ 2329*9e39c5baSBill Taylor case DDI_FM_FATAL: 2330*9e39c5baSBill Taylor case DDI_FM_UNKNOWN: 2331*9e39c5baSBill Taylor default: 2332*9e39c5baSBill Taylor cmn_err(CE_WARN, "Unknown HCA HW error status (%d)", 2333*9e39c5baSBill Taylor derr.fme_status); 2334*9e39c5baSBill Taylor /* Return this as a persistent error */ 2335*9e39c5baSBill Taylor return (HCA_PIO_PERSISTENT); 2336*9e39c5baSBill Taylor } 2337*9e39c5baSBill Taylor } 2338*9e39c5baSBill Taylor 2339*9e39c5baSBill Taylor 2340*9e39c5baSBill Taylor /* 2341*9e39c5baSBill Taylor * HCA FM Test Interface 2342*9e39c5baSBill Taylor * 2343*9e39c5baSBill Taylor * These functions should be used for any HCA drivers, but probably 2344*9e39c5baSBill Taylor * customized for their own HW design and/or FM implementation. 2345*9e39c5baSBill Taylor * Customized functins should have the driver name prefix such as 2346*9e39c5baSBill Taylor * hermon_xxxx() and be defined separately but whose function should 2347*9e39c5baSBill Taylor * call the common interface inside. 2348*9e39c5baSBill Taylor */ 2349*9e39c5baSBill Taylor 2350*9e39c5baSBill Taylor #ifdef FMA_TEST 2351*9e39c5baSBill Taylor static int test_num; /* serial number */ 2352*9e39c5baSBill Taylor static kmutex_t i_hca_test_lock; /* lock for serial numer */ 2353*9e39c5baSBill Taylor 2354*9e39c5baSBill Taylor /* 2355*9e39c5baSBill Taylor * void 2356*9e39c5baSBill Taylor * i_hca_test_init(mod_hash_t **strHashp, mod_hash_t **idHashp) 2357*9e39c5baSBill Taylor * 2358*9e39c5baSBill Taylor * Overview 2359*9e39c5baSBill Taylor * i_hca_test_init() creates two hash tables, one of which is for string, 2360*9e39c5baSBill Taylor * and the other of which is for ID, then saves pointers to arguments 2361*9e39c5baSBill Taylor * passed. This function uses the mod_hash utilities to manage the 2362*9e39c5baSBill Taylor * hash tables. About the mod_hash, see common/os/modhash.c. 2363*9e39c5baSBill Taylor * 2364*9e39c5baSBill Taylor * Argument 2365*9e39c5baSBill Taylor * strHashp: pointer to String hash table pointer 2366*9e39c5baSBill Taylor * idHashp: pointer to ID hash table pointer 2367*9e39c5baSBill Taylor * 2368*9e39c5baSBill Taylor * Return value 2369*9e39c5baSBill Taylor * Nothing 2370*9e39c5baSBill Taylor * 2371*9e39c5baSBill Taylor * Caller's context 2372*9e39c5baSBill Taylor * i_hca_test_init() can be called in user or kernel context only. 2373*9e39c5baSBill Taylor */ 2374*9e39c5baSBill Taylor static void 2375*9e39c5baSBill Taylor i_hca_test_init(mod_hash_t **strHashp, mod_hash_t **idHashp) 2376*9e39c5baSBill Taylor { 2377*9e39c5baSBill Taylor *idHashp = mod_hash_create_idhash("HCA_FMA_id_hash", 2378*9e39c5baSBill Taylor FMA_TEST_HASHSZ, mod_hash_null_valdtor); 2379*9e39c5baSBill Taylor 2380*9e39c5baSBill Taylor *strHashp = mod_hash_create_strhash("HCA_FMA_test_hash", 2381*9e39c5baSBill Taylor FMA_TEST_HASHSZ, i_hca_test_free_item); 2382*9e39c5baSBill Taylor } 2383*9e39c5baSBill Taylor 2384*9e39c5baSBill Taylor 2385*9e39c5baSBill Taylor /* 2386*9e39c5baSBill Taylor * void 2387*9e39c5baSBill Taylor * i_hca_test_fini(mod_hash_t **strHashp, mod_hash_t **idHashp) 2388*9e39c5baSBill Taylor * 2389*9e39c5baSBill Taylor * Overview 2390*9e39c5baSBill Taylor * i_hca_test_fini() releases two hash tables used for HCA FM test. 2391*9e39c5baSBill Taylor * 2392*9e39c5baSBill Taylor * Argument 2393*9e39c5baSBill Taylor * strHashp: pointer to String hash table pointer 2394*9e39c5baSBill Taylor * idHashp: pointer to ID hash table pointer 2395*9e39c5baSBill Taylor * 2396*9e39c5baSBill Taylor * Return value 2397*9e39c5baSBill Taylor * Nothing 2398*9e39c5baSBill Taylor * 2399*9e39c5baSBill Taylor * Caller's context 2400*9e39c5baSBill Taylor * i_hca_test_fini() can be called in user, kernel or interrupt context. 2401*9e39c5baSBill Taylor * 2402*9e39c5baSBill Taylor */ 2403*9e39c5baSBill Taylor static void 2404*9e39c5baSBill Taylor i_hca_test_fini(mod_hash_t **strHashp, mod_hash_t **idHashp) 2405*9e39c5baSBill Taylor { 2406*9e39c5baSBill Taylor mod_hash_destroy_hash(*strHashp); 2407*9e39c5baSBill Taylor *strHashp = NULL; 2408*9e39c5baSBill Taylor 2409*9e39c5baSBill Taylor mod_hash_destroy_hash(*idHashp); 2410*9e39c5baSBill Taylor *idHashp = NULL; 2411*9e39c5baSBill Taylor } 2412*9e39c5baSBill Taylor 2413*9e39c5baSBill Taylor 2414*9e39c5baSBill Taylor /* 2415*9e39c5baSBill Taylor * struct i_hca_fm_test * 2416*9e39c5baSBill Taylor * i_hca_test_register(char *filename, int linenum, int type, 2417*9e39c5baSBill Taylor * void (*pio_injection)(struct i_hca_fm_test *, ddi_fm_error_t *), 2418*9e39c5baSBill Taylor * void *private, mod_hash_t *strHash, mod_hash_t *idHash, int preTestNum) 2419*9e39c5baSBill Taylor * 2420*9e39c5baSBill Taylor * Overview 2421*9e39c5baSBill Taylor * i_hca_test_register() registers an HCA FM test item against HCA FM 2422*9e39c5baSBill Taylor * function callings specified with the file name and the line number 2423*9e39c5baSBill Taylor * (passed as the arguments). 2424*9e39c5baSBill Taylor * 2425*9e39c5baSBill Taylor * Argument 2426*9e39c5baSBill Taylor * filename: source file name where the function call is implemented 2427*9e39c5baSBill Taylor * This value is usually a __FILE__ pre-defined macro. 2428*9e39c5baSBill Taylor * linenum: line number where the function call is described in the 2429*9e39c5baSBill Taylor * file specified above. 2430*9e39c5baSBill Taylor * This value is usually a __LINE__ pre-defined macro. 2431*9e39c5baSBill Taylor * type: HW error type 2432*9e39c5baSBill Taylor * HCA_TEST_PIO pio error 2433*9e39c5baSBill Taylor * HCA_TEST_IBA ib specific error 2434*9e39c5baSBill Taylor * pio_injection: pio error injection callback function invoked when the 2435*9e39c5baSBill Taylor * function specified above (with the file name and the 2436*9e39c5baSBill Taylor * line number) is executed. If the function is not a PIO, 2437*9e39c5baSBill Taylor * request, this parameter should be NULL. 2438*9e39c5baSBill Taylor * private: the argument passed to either of injection functions when 2439*9e39c5baSBill Taylor * they're invoked. 2440*9e39c5baSBill Taylor * strHashp: pointer to String hash table 2441*9e39c5baSBill Taylor * idHashp: pointer to ID hash table 2442*9e39c5baSBill Taylor * preTestNum: the index of the pre-defined testset for this test item. 2443*9e39c5baSBill Taylor * 2444*9e39c5baSBill Taylor * Return value 2445*9e39c5baSBill Taylor * pointer to HCA FM function test structure registered. 2446*9e39c5baSBill Taylor * 2447*9e39c5baSBill Taylor * Caller's context 2448*9e39c5baSBill Taylor * i_hca_test_register() can be called in user, kernel or interrupt 2449*9e39c5baSBill Taylor * context. 2450*9e39c5baSBill Taylor * 2451*9e39c5baSBill Taylor */ 2452*9e39c5baSBill Taylor static struct i_hca_fm_test * 2453*9e39c5baSBill Taylor i_hca_test_register(char *filename, int linenum, int type, 2454*9e39c5baSBill Taylor void (*pio_injection)(struct i_hca_fm_test *, ddi_fm_error_t *), 2455*9e39c5baSBill Taylor void *private, mod_hash_t *strHash, mod_hash_t *idHash, int preTestNum) 2456*9e39c5baSBill Taylor { 2457*9e39c5baSBill Taylor struct i_hca_fm_test *t_item; 2458*9e39c5baSBill Taylor char key_buf[255], *hash_key; 2459*9e39c5baSBill Taylor int status; 2460*9e39c5baSBill Taylor 2461*9e39c5baSBill Taylor (void) sprintf(key_buf, "%s:%d", filename, linenum); 2462*9e39c5baSBill Taylor hash_key = kmem_zalloc(strlen(key_buf) + 1, KM_NOSLEEP); 2463*9e39c5baSBill Taylor 2464*9e39c5baSBill Taylor if (hash_key == NULL) 2465*9e39c5baSBill Taylor cmn_err(CE_PANIC, "No memory for HCA FMA Test."); 2466*9e39c5baSBill Taylor 2467*9e39c5baSBill Taylor bcopy(key_buf, hash_key, strlen(key_buf)); 2468*9e39c5baSBill Taylor 2469*9e39c5baSBill Taylor status = mod_hash_find(strHash, (mod_hash_key_t)hash_key, 2470*9e39c5baSBill Taylor (mod_hash_val_t *)&t_item); 2471*9e39c5baSBill Taylor 2472*9e39c5baSBill Taylor switch (status) { 2473*9e39c5baSBill Taylor case MH_ERR_NOTFOUND: 2474*9e39c5baSBill Taylor t_item = (struct i_hca_fm_test *) 2475*9e39c5baSBill Taylor kmem_alloc(sizeof (struct i_hca_fm_test), KM_NOSLEEP); 2476*9e39c5baSBill Taylor if (t_item == NULL) 2477*9e39c5baSBill Taylor cmn_err(CE_PANIC, "No memory for HCA FMA Test."); 2478*9e39c5baSBill Taylor 2479*9e39c5baSBill Taylor /* Set the error number */ 2480*9e39c5baSBill Taylor mutex_enter(&i_hca_test_lock); 2481*9e39c5baSBill Taylor t_item->num = test_num++; 2482*9e39c5baSBill Taylor mutex_exit(&i_hca_test_lock); 2483*9e39c5baSBill Taylor 2484*9e39c5baSBill Taylor /* Set type and other static information */ 2485*9e39c5baSBill Taylor t_item->type = type; 2486*9e39c5baSBill Taylor t_item->line_num = linenum; 2487*9e39c5baSBill Taylor t_item->file_name = filename; 2488*9e39c5baSBill Taylor t_item->hash_key = hash_key; 2489*9e39c5baSBill Taylor t_item->private = private; 2490*9e39c5baSBill Taylor t_item->pio_injection = pio_injection; 2491*9e39c5baSBill Taylor 2492*9e39c5baSBill Taylor /* Set the pre-defined hermon test item */ 2493*9e39c5baSBill Taylor i_hca_test_set_item(preTestNum, (struct i_hca_fm_test *)t_item); 2494*9e39c5baSBill Taylor 2495*9e39c5baSBill Taylor status = mod_hash_insert(strHash, (mod_hash_key_t) 2496*9e39c5baSBill Taylor hash_key, (mod_hash_val_t)t_item); 2497*9e39c5baSBill Taylor ASSERT(status == 0); 2498*9e39c5baSBill Taylor 2499*9e39c5baSBill Taylor status = mod_hash_insert(idHash, (mod_hash_key_t) 2500*9e39c5baSBill Taylor (uintptr_t)t_item->num, (mod_hash_val_t)t_item); 2501*9e39c5baSBill Taylor ASSERT(status == 0); 2502*9e39c5baSBill Taylor break; 2503*9e39c5baSBill Taylor 2504*9e39c5baSBill Taylor case MH_ERR_NOMEM: 2505*9e39c5baSBill Taylor cmn_err(CE_PANIC, "No memory for HCA FMA Test."); 2506*9e39c5baSBill Taylor break; 2507*9e39c5baSBill Taylor 2508*9e39c5baSBill Taylor case MH_ERR_DUPLICATE: 2509*9e39c5baSBill Taylor cmn_err(CE_PANIC, "HCA FMA Test Internal Error."); 2510*9e39c5baSBill Taylor break; 2511*9e39c5baSBill Taylor default: 2512*9e39c5baSBill Taylor /* OK, this is already registered. */ 2513*9e39c5baSBill Taylor kmem_free(hash_key, strlen(key_buf) + 1); 2514*9e39c5baSBill Taylor break; 2515*9e39c5baSBill Taylor } 2516*9e39c5baSBill Taylor return (t_item); 2517*9e39c5baSBill Taylor } 2518*9e39c5baSBill Taylor 2519*9e39c5baSBill Taylor 2520*9e39c5baSBill Taylor /* 2521*9e39c5baSBill Taylor * void 2522*9e39c5baSBill Taylor * i_hca_test_set_item(int num, struct i_hca_fm_test *t_item) 2523*9e39c5baSBill Taylor * 2524*9e39c5baSBill Taylor * Overview 2525*9e39c5baSBill Taylor * i_hca_test_set_item() is a private function used in 2526*9e39c5baSBill Taylor * i_hca_test_register() above. This function sets the testset specified 2527*9e39c5baSBill Taylor * (with the index number) to HCA FM function test structure. 2528*9e39c5baSBill Taylor * 2529*9e39c5baSBill Taylor * Argument 2530*9e39c5baSBill Taylor * num: index to test set (testset structure array) 2531*9e39c5baSBill Taylor * t_item: pointer to HCA fM function test structure 2532*9e39c5baSBill Taylor * 2533*9e39c5baSBill Taylor * Return value 2534*9e39c5baSBill Taylor * Nothing 2535*9e39c5baSBill Taylor * 2536*9e39c5baSBill Taylor * Caller's context 2537*9e39c5baSBill Taylor * i_hca_test_set_item() can be called in user, kernel, interrupt 2538*9e39c5baSBill Taylor * context or hight interrupt context. 2539*9e39c5baSBill Taylor * 2540*9e39c5baSBill Taylor */ 2541*9e39c5baSBill Taylor static void 2542*9e39c5baSBill Taylor i_hca_test_set_item(int num, struct i_hca_fm_test *t_item) 2543*9e39c5baSBill Taylor { 2544*9e39c5baSBill Taylor if (num < 0 || num >= sizeof (testset) / sizeof (hermon_test_t) || 2545*9e39c5baSBill Taylor testset[num].type != t_item->type) { 2546*9e39c5baSBill Taylor t_item->trigger = testset[0].trigger; 2547*9e39c5baSBill Taylor t_item->errcnt = testset[0].errcnt; 2548*9e39c5baSBill Taylor return; 2549*9e39c5baSBill Taylor } 2550*9e39c5baSBill Taylor 2551*9e39c5baSBill Taylor /* Set the testsuite */ 2552*9e39c5baSBill Taylor t_item->trigger = testset[num].trigger; 2553*9e39c5baSBill Taylor t_item->errcnt = testset[num].errcnt; 2554*9e39c5baSBill Taylor } 2555*9e39c5baSBill Taylor 2556*9e39c5baSBill Taylor 2557*9e39c5baSBill Taylor /* 2558*9e39c5baSBill Taylor * void 2559*9e39c5baSBill Taylor * i_hca_test_free_item(mod_hash_val_t val) 2560*9e39c5baSBill Taylor * 2561*9e39c5baSBill Taylor * Overview 2562*9e39c5baSBill Taylor * i_hca_test_free_item() is a private function used to free HCA FM 2563*9e39c5baSBill Taylor * function test structure when i_hca_test_fini() is called. This function 2564*9e39c5baSBill Taylor * is registered as a destructor when the hash table is created in 2565*9e39c5baSBill Taylor * i_hca_test_init(). 2566*9e39c5baSBill Taylor * 2567*9e39c5baSBill Taylor * Argument 2568*9e39c5baSBill Taylor * val: pointer to the value stored in hash table (pointer to HCA FM 2569*9e39c5baSBill Taylor * function test structure) 2570*9e39c5baSBill Taylor * 2571*9e39c5baSBill Taylor * Return value 2572*9e39c5baSBill Taylor * Nothing 2573*9e39c5baSBill Taylor * 2574*9e39c5baSBill Taylor * Caller's context 2575*9e39c5baSBill Taylor * i_hca_test_free_item() can be called in user, kernel or interrupt 2576*9e39c5baSBill Taylor * context. 2577*9e39c5baSBill Taylor * 2578*9e39c5baSBill Taylor */ 2579*9e39c5baSBill Taylor static void 2580*9e39c5baSBill Taylor i_hca_test_free_item(mod_hash_val_t val) 2581*9e39c5baSBill Taylor { 2582*9e39c5baSBill Taylor struct i_hca_fm_test *t_item = (struct i_hca_fm_test *)val; 2583*9e39c5baSBill Taylor kmem_free(t_item, sizeof (struct i_hca_fm_test)); 2584*9e39c5baSBill Taylor } 2585*9e39c5baSBill Taylor #endif /* FMA_TEST */ 2586