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