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