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 switch (state->hs_fm_degraded_reason) { 1012 case HCA_FW_CORRUPT: 1013 i_hca_fm_ereport(state->hs_dip, type, 1014 DDI_FM_DEVICE_FW_CORRUPT); 1015 break; 1016 case HCA_FW_MISMATCH: 1017 i_hca_fm_ereport(state->hs_dip, type, 1018 DDI_FM_DEVICE_FW_MISMATCH); 1019 break; 1020 case HCA_FW_MISC: 1021 default: 1022 i_hca_fm_ereport(state->hs_dip, type, 1023 DDI_FM_DEVICE_INTERN_UNCORR); 1024 break; 1025 } 1026 ddi_fm_service_impact(state->hs_dip, 1027 DDI_SERVICE_DEGRADED); 1028 break; 1029 case HCA_ERR_FATAL: 1030 ddi_fm_service_impact(state->hs_dip, 1031 DDI_SERVICE_LOST); 1032 state->hs_fm_async_fatal = B_TRUE; 1033 break; 1034 default: 1035 cmn_err(CE_WARN, "hermon_fm_ereport: Unknown error. " 1036 "type = %d, detail = %d\n.", type, detail); 1037 } 1038 break; 1039 1040 case HCA_IBA_ERR: 1041 switch (detail) { 1042 case HCA_ERR_TRANSIENT: 1043 i_hca_fm_ereport(state->hs_dip, type, 1044 DDI_FM_DEVICE_INTERN_UNCORR); 1045 ddi_fm_service_impact(state->hs_dip, 1046 DDI_SERVICE_UNAFFECTED); 1047 break; 1048 case HCA_ERR_SRV_LOST: 1049 cmn_err(CE_WARN, "hermon_fm_ereport: not supported " 1050 "error. type = %d, detail = %d\n.", type, detail); 1051 break; 1052 case HCA_ERR_DEGRADED: 1053 switch (state->hs_fm_degraded_reason) { 1054 case HCA_FW_CORRUPT: 1055 i_hca_fm_ereport(state->hs_dip, type, 1056 DDI_FM_DEVICE_FW_CORRUPT); 1057 break; 1058 case HCA_FW_MISMATCH: 1059 i_hca_fm_ereport(state->hs_dip, type, 1060 DDI_FM_DEVICE_FW_MISMATCH); 1061 break; 1062 case HCA_FW_MISC: 1063 default: 1064 i_hca_fm_ereport(state->hs_dip, type, 1065 DDI_FM_DEVICE_INTERN_UNCORR); 1066 break; 1067 } 1068 ddi_fm_service_impact(state->hs_dip, 1069 DDI_SERVICE_DEGRADED); 1070 break; 1071 case HCA_ERR_IOCTL: 1072 case HCA_ERR_NON_FATAL: 1073 i_hca_fm_ereport(state->hs_dip, type, 1074 DDI_FM_DEVICE_INTERN_UNCORR); 1075 ddi_fm_service_impact(state->hs_dip, 1076 DDI_SERVICE_UNAFFECTED); 1077 break; 1078 case HCA_ERR_FATAL: 1079 if (hermon_get_state(state) & HCA_PIO_FM) { 1080 if (servicing_interrupt()) { 1081 atomic_inc_32(&state-> 1082 hs_fm_async_errcnt); 1083 } else { 1084 i_hca_fm_ereport(state->hs_dip, type, 1085 DDI_FM_DEVICE_INTERN_UNCORR); 1086 ddi_fm_service_impact(state->hs_dip, 1087 DDI_SERVICE_LOST); 1088 } 1089 state->hs_fm_async_fatal = B_TRUE; 1090 } else { 1091 i_hca_fm_ereport(state->hs_dip, type, 1092 DDI_FM_DEVICE_INTERN_UNCORR); 1093 ddi_fm_service_impact(state->hs_dip, 1094 DDI_SERVICE_LOST); 1095 cmn_err(CE_PANIC, 1096 "Hermon Fatal Internal Error. " 1097 "Hermon state=0x%p", (void *)state); 1098 } 1099 break; 1100 default: 1101 cmn_err(CE_WARN, "hermon_fm_ereport: Unknown error. " 1102 "type = %d, detail = %d\n.", type, detail); 1103 } 1104 break; 1105 1106 default: 1107 cmn_err(CE_WARN, "hermon_fm_ereport: Unknown type " 1108 "type = %d, detail = %d\n.", type, detail); 1109 break; 1110 } 1111 } 1112 1113 1114 /* 1115 * uchar_t 1116 * hermon_devacc_attr_version(hermon_state_t *) 1117 * 1118 * Overview 1119 * hermon_devacc_attr_version() returns the ddi device attribute 1120 * version. 1121 * 1122 * Argument 1123 * state: pointer to Hermon state structure 1124 * 1125 * Return value 1126 * dev_acc_attr_version value 1127 * DDI_DEVICE_ATTR_V0 Hermon FM disabled 1128 * DDI_DEVICE_ATTR_V1 Hermon FM enabled 1129 * 1130 * Caller's context 1131 * hermon_devacc_attr_version() can be called in user, kernel, interrupt 1132 * context or high interrupt context. 1133 */ 1134 ushort_t 1135 hermon_devacc_attr_version(hermon_state_t *state) 1136 { 1137 if (state->hs_fm_disable) { 1138 return (DDI_DEVICE_ATTR_V0); 1139 } else { 1140 return (DDI_DEVICE_ATTR_V1); 1141 } 1142 } 1143 1144 1145 /* 1146 * uchar_t 1147 * hermon_devacc_attr_access(hermon_state_t *) 1148 * 1149 * Overview 1150 * hermon_devacc_attr_access() returns devacc_attr_access error 1151 * protection types. 1152 * 1153 * Argument 1154 * state: pointer to Hermon state structure 1155 * 1156 * Return value 1157 * dev_acc_attr_access error protection type 1158 * DDI_DEFAULT_ACC Hermon FM disabled for PIO 1159 * DDI_FLAGERR_ACC Hermon FM enabled for PIO 1160 * 1161 * Caller's context 1162 * hermon_devacc_attr_access() can be called in user, kernel, interrupt 1163 * context or high interrupt context. 1164 */ 1165 uchar_t 1166 hermon_devacc_attr_access(hermon_state_t *state) 1167 { 1168 if (state->hs_fm_disable) { 1169 return (DDI_DEFAULT_ACC); 1170 } else { 1171 return (DDI_FLAGERR_ACC); 1172 } 1173 } 1174 1175 1176 /* 1177 * int 1178 * hermon_PIO_start(hermon_state_t *state, ddi_acc_handle_t handle, 1179 * hermon_test_t *tst) 1180 * 1181 * Overview 1182 * hermon_PIO_start() should be called before Hermon driver issues PIOs 1183 * against I/O space. If Hermon FM is disabled, this function returns 1184 * HCA_PIO_OK always. See i_hca_pio_start() in detail. 1185 * 1186 * Argument 1187 * state: pointer to Hermon state structure 1188 * handle: pointer to ddi_acc_handle_t used for HCA FM 1189 * tst: pointer to HCA FM function test structure. If the structure 1190 * is not used, the NULL value must be passed instead. 1191 * 1192 * Return value 1193 * error status showing whether or not this error can retry 1194 * HCA_PIO_OK No HW errors 1195 * HCA_PIO_TRANSIENT This error could be transient 1196 * HCA_PIO_PERSISTENT This error is persistent 1197 * 1198 * Caller's context 1199 * hermon_PIO_start() can be called in user, kernel or interrupt context. 1200 */ 1201 int 1202 hermon_PIO_start(hermon_state_t *state, ddi_acc_handle_t handle, 1203 hermon_test_t *tst) 1204 { 1205 if (state->hs_fm_disable) { 1206 return (HCA_PIO_OK); 1207 } else { 1208 struct i_hca_acc_handle *handlep = 1209 i_hca_get_acc_handle(state->hs_fm_hca_fm, handle); 1210 ASSERT(handlep != NULL); 1211 return (i_hca_pio_start(state->hs_dip, handlep, tst)); 1212 } 1213 } 1214 1215 1216 /* 1217 * int 1218 * hermon_PIO_end(hermon_state_t *state, ddi_acc_handle_t handle, int *cnt, 1219 * hermon_test_t *tst) 1220 * 1221 * Overview 1222 * hermon_PIO_end() should be called after Hermon driver issues PIOs 1223 * against I/O space. If Hermon FM is disabled, this function returns 1224 * HCA_PIO_OK always. See i_hca_pio_end() in detail. 1225 * 1226 * Argument 1227 * state: pointer to Hermon state structure 1228 * handle: pointer to ddi_acc_handle_t used for HCA FM 1229 * cnt: pointer to the counter variable which holds the nubmer of retry 1230 * (HCA_PIO_RETRY_CNT) when a HW error is detected. 1231 * tst: pointer to HCA FM function test structure. If the structure 1232 * is not used, the NULL value must be passed instead. 1233 * 1234 * Return value 1235 * error status showing whether or not this error can retry 1236 * HCA_PIO_OK No HW errors 1237 * HCA_PIO_TRANSIENT This error could be transient 1238 * HCA_PIO_PERSISTENT This error is persistent 1239 * 1240 * Caller's context 1241 * hermon_PIO_end() can be called in user, kernel or interrupt context. 1242 */ 1243 int 1244 hermon_PIO_end(hermon_state_t *state, ddi_acc_handle_t handle, int *cnt, 1245 hermon_test_t *tst) 1246 { 1247 if (state->hs_fm_disable) { 1248 return (HCA_PIO_OK); 1249 } else { 1250 struct i_hca_acc_handle *handlep = 1251 i_hca_get_acc_handle(state->hs_fm_hca_fm, handle); 1252 ASSERT(handlep != NULL); 1253 return (i_hca_pio_end(state->hs_dip, handlep, cnt, tst)); 1254 } 1255 } 1256 1257 1258 /* 1259 * ddi_acc_handle_t 1260 * hermon_get_cmdhdl(hermon_state_t *state) 1261 * 1262 * Overview 1263 * hermon_get_cmdhdl() returns either the fma-protected access handle or 1264 * the regular ddi-access handle depending on the Hermon FM state for 1265 * Hermon command I/O space. 1266 * 1267 * Argument 1268 * state: pointer to Hermon state structure 1269 * 1270 * Return value 1271 * the access handle for pio requests 1272 * 1273 * Caller's context 1274 * hermon_get_cmdhdl() can be called in user, kernel, interrupt context 1275 * or high interrupt context. 1276 */ 1277 ddi_acc_handle_t 1278 hermon_get_cmdhdl(hermon_state_t *state) 1279 { 1280 return (state->hs_fm_disable || hermon_get_state(state) & HCA_PIO_FM ? 1281 state->hs_fm_cmdhdl : state->hs_reg_cmdhdl); 1282 } 1283 1284 1285 /* 1286 * ddi_acc_handle_t 1287 * hermon_get_uarhdl(hermon_state_t *state) 1288 * 1289 * Overview 1290 * hermon_get_uarhdl() returns either the fma-protected access handle or 1291 * the regular ddi-access handle depending on the Hermon FM state for 1292 * Hermon UAR I/O space. 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_get_uarhdl() can be called in user, kernel, interrupt context 1302 * or high interrupt context. 1303 */ 1304 ddi_acc_handle_t 1305 hermon_get_uarhdl(hermon_state_t *state) 1306 { 1307 return (state->hs_fm_disable || hermon_get_state(state) & HCA_PIO_FM ? 1308 state->hs_fm_uarhdl : state->hs_reg_uarhdl); 1309 } 1310 1311 1312 /* 1313 * ddi_acc_handle_t 1314 * hermon_rsrc_alloc_uarhdl(hermon_state_t *state) 1315 * 1316 * Overview 1317 * hermon_rsrc_alloc_uarhdl() returns either the fma-protected access 1318 * handle or the regular ddi-access handle depending on the Hermon FM 1319 * state for Hermon UAR I/O space as well as hermon_get_uarhdl(), but 1320 * this function is dedicated to the UAR resource allocator. 1321 * 1322 * Argument 1323 * state: pointer to Hermon state structure 1324 * 1325 * Return value 1326 * the access handle for pio requests 1327 * 1328 * Caller's context 1329 * hermon_rsrc_alloc_uarhdl() can be called in user, kernel, interrupt 1330 * or high interrupt context. 1331 */ 1332 ddi_acc_handle_t 1333 hermon_rsrc_alloc_uarhdl(hermon_state_t *state) 1334 { 1335 return (state->hs_fm_disable || hermon_get_state(state) & HCA_ATTCH_FM ? 1336 state->hs_fm_uarhdl : state->hs_reg_uarhdl); 1337 } 1338 1339 /* 1340 * ddi_acc_handle_t 1341 * hermon_get_pcihdl(hermon_state_t *state) 1342 * 1343 * Overview 1344 * hermon_get_pcihdl() returns either the fma-protected access 1345 * handle or the regular ddi-access handle to access the PCI config 1346 * space. Whether or not which handle is returned at the moment depends 1347 * on the Hermon FM state. 1348 * 1349 * Argument 1350 * state: pointer to Hermon state structure 1351 * 1352 * Return value 1353 * the access handle to PCI config space 1354 * 1355 * Caller's context 1356 * hermon_get_pcihdl() can be called in user, kernel, interrupt 1357 * or high interrupt context. 1358 */ 1359 ddi_acc_handle_t 1360 hermon_get_pcihdl(hermon_state_t *state) 1361 { 1362 return (state->hs_fm_disable || hermon_get_state(state) & HCA_ATTCH_FM ? 1363 state->hs_fm_pcihdl : state->hs_reg_pcihdl); 1364 } 1365 1366 1367 /* 1368 * ddi_acc_handle_t 1369 * hermon_get_msix_tblhdl(hermon_state_t *state) 1370 * 1371 * Overview 1372 * hermon_get_msix_tblhdl() returns either the fma-protected access 1373 * handle or the regular ddi-access handle to access the MSI-X tables. 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 tables 1382 * 1383 * Caller's context 1384 * hermon_get_msix_tblhdl() can be called in user, kernel, interrupt 1385 * context or high interrupt context. 1386 */ 1387 ddi_acc_handle_t 1388 hermon_get_msix_tblhdl(hermon_state_t *state) 1389 { 1390 return (state->hs_fm_disable || hermon_get_state(state) & HCA_ATTCH_FM ? 1391 state->hs_fm_msix_tblhdl : state->hs_reg_msix_tblhdl); 1392 } 1393 1394 1395 /* 1396 * ddi_acc_handle_t 1397 * hermon_get_msix_pbahdl(hermon_state_t *state) 1398 * 1399 * Overview 1400 * hermon_get_msix_pbahdl() returns either the fma-protected access 1401 * handle or the regular ddi-access handle to access the MSI-X PBA. 1402 * Whether or not which handle is returned at the moment depends on 1403 * the Hermon FM state. 1404 * 1405 * Argument 1406 * state: pointer to Hermon state structure 1407 * 1408 * Return value 1409 * the access handle to MSI-X PBA 1410 * 1411 * Caller's context 1412 * hermon_get_msix_pbahdl() can be called in user, kernel, interrupt 1413 * context or high interrupt context. 1414 */ 1415 ddi_acc_handle_t 1416 hermon_get_msix_pbahdl(hermon_state_t *state) 1417 { 1418 return (state->hs_fm_disable || hermon_get_state(state) & HCA_ATTCH_FM ? 1419 state->hs_fm_msix_pbahdl : state->hs_reg_msix_pbahdl); 1420 } 1421 1422 1423 /* 1424 * void 1425 * hermon_inter_err_chk(void *arg) 1426 * 1427 * Overview 1428 * hermon_inter_err_chk() periodically checks the internal error buffer 1429 * to pick up a Hermon asynchronous internal error. 1430 * 1431 * Note that this internal error can be notified if the interrupt is 1432 * registered, but even so there are some cases that an interrupt against 1433 * it cannot be raised so that Hermon RPM recommeds to poll this internal 1434 * error buffer periodically instead. This function is invoked at 1435 * 10ms interval in kernel context though the function itself can be 1436 * called in interrupt context. 1437 * 1438 * Argument 1439 * arg: pointer to Hermon state structure 1440 * 1441 * Return value 1442 * Nothing 1443 * 1444 * Caller's context 1445 * hermon_inter_err_chk() can be called in user, kernel, interrupt 1446 * context or high interrupt context. 1447 * 1448 */ 1449 void 1450 hermon_inter_err_chk(void *arg) 1451 { 1452 uint32_t word; 1453 ddi_acc_handle_t cmdhdl; 1454 hermon_state_t *state = (hermon_state_t *)arg; 1455 1456 /* initialize the FMA retry loop */ 1457 hermon_pio_init(fm_loop_cnt, fm_status, fm_test); 1458 1459 #ifdef FMA_TEST 1460 if (hermon_test_num != 0) { 1461 return; 1462 } 1463 #endif 1464 if (state->hs_fm_poll_suspend) { 1465 return; 1466 } 1467 1468 /* Get the access handle for Hermon CMD I/O space */ 1469 cmdhdl = hermon_get_cmdhdl(state); 1470 1471 /* the FMA retry loop starts. */ 1472 hermon_pio_start(state, cmdhdl, pio_error, fm_loop_cnt, fm_status, 1473 fm_test); 1474 1475 word = ddi_get32(cmdhdl, state->hs_cmd_regs.fw_err_buf); 1476 1477 /* the FMA retry loop ends. */ 1478 hermon_pio_end(state, cmdhdl, pio_error, fm_loop_cnt, fm_status, 1479 fm_test); 1480 1481 if (word != 0) { 1482 HERMON_FMANOTE(state, HERMON_FMA_INTERNAL); 1483 /* if fm_disable is on, Hermon FM functions don't work */ 1484 if (state->hs_fm_disable) { 1485 cmn_err(CE_PANIC, 1486 "Hermon Fatal Internal Error. " 1487 "Hermon state=0x%p", (void *)state); 1488 } else { 1489 hermon_fm_ereport(state, HCA_IBA_ERR, HCA_ERR_FATAL); 1490 } 1491 } 1492 1493 /* issue the ereport pended in the interrupt context */ 1494 if (state->hs_fm_async_errcnt > 0) { 1495 hermon_fm_ereport(state, HCA_IBA_ERR, HCA_ERR_FATAL); 1496 atomic_dec_32(&state->hs_fm_async_errcnt); 1497 } 1498 1499 return; 1500 1501 pio_error: 1502 hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_FATAL); 1503 } 1504 1505 1506 /* 1507 * boolean_t 1508 * hermon_cmd_retry_ok(hermon_cmd_post_t *cmd, int status) 1509 * 1510 * Overview 1511 * In the case that a HW error is detected, if it can be isolated 1512 * enough, Hermon FM retries the operation which caused the error. 1513 * However, this retry can induce another error; since the retry is 1514 * achieved as a block basis, not a statement basis, once the state 1515 * was set inside the Hermon HW already in the previous operation, the 1516 * retry can cause for example, a CMD_BAD_SYS_STATE error, as a result. 1517 * In this case, CMD_BAD_SYS_STATE should be taken as a side effect 1518 * but a harmless result. hermon_cmd_retry_ok() checks this kind of 1519 * situation then returns if the state Hermon CMD returns is OK or not. 1520 * 1521 * Argument 1522 * cmd: pointer to hermon_cmd_post_t structure 1523 * status: Hermon CMD status 1524 * 1525 * Return value 1526 * B_TRUE this state is no problem 1527 * B_FALSE this state should be taken as an error 1528 * 1529 * Caller's context 1530 * hermon_cmd_retry_ok() can be called in user, kernel, interrupt 1531 * context or high interrupt context. 1532 * 1533 * Note that status except for HERMON_CMD_SUCCESS shouldn't be accepted 1534 * in the debug module to catch a hidden software bug, so that ASSERT() 1535 * is enabled in the case. 1536 */ 1537 boolean_t 1538 hermon_cmd_retry_ok(hermon_cmd_post_t *cmd, int status) 1539 { 1540 if (status == HERMON_CMD_SUCCESS) 1541 return (B_TRUE); 1542 1543 /* 1544 * The wrong status such as HERMON_CMD_BAD_SYS_STATE or 1545 * HERMON_CMD_BAD_RES_STATE can return as a side effect 1546 * because of the Hermon FM operation retry when a PIO 1547 * error is detected during the I/O transaction. In the 1548 * case, the driver may set the same value in Hermon 1549 * though it was set already, then Hermon returns HERMON_ 1550 * CMD_BAD_{RES,SYS}_STATE as a result, which should be 1551 * taken as OK. 1552 */ 1553 switch (cmd->cp_opcode) { 1554 case INIT_HCA: 1555 /* 1556 * HERMON_CMD_BAD_SYS_STATE can be gotten in case of 1557 * ICM not mapped or HCA already initialized. 1558 */ 1559 if (status == HERMON_CMD_BAD_SYS_STATE) 1560 return (B_TRUE); 1561 return (B_FALSE); 1562 1563 case CLOSE_HCA: 1564 /* 1565 * HERMON_CMD_BAD_SYS_STATE can be gotten in case of Firmware 1566 * area is not mapped or HCA already closed. 1567 */ 1568 if (status == HERMON_CMD_BAD_SYS_STATE) 1569 return (B_TRUE); 1570 return (B_FALSE); 1571 1572 case CLOSE_PORT: 1573 /* 1574 * HERMON_CMD_BAD_SYS_STATE can be gotten in case of HCA not 1575 * initialized or in case that IB ports are already down. 1576 */ 1577 if (status == HERMON_CMD_BAD_SYS_STATE) 1578 return (B_TRUE); 1579 return (B_FALSE); 1580 1581 case SW2HW_MPT: 1582 /* 1583 * HERMON_CMD_BAD_RES_STATE can be gotten in case of MPT 1584 * entry already in hardware ownership. 1585 */ 1586 if (status == HERMON_CMD_BAD_RES_STATE) 1587 return (B_TRUE); 1588 return (B_FALSE); 1589 1590 case HW2SW_MPT: 1591 /* 1592 * HERMON_CMD_BAD_RES_STATE can be gotten in case of MPT 1593 * entry already in software ownership. 1594 */ 1595 if (status == HERMON_CMD_BAD_RES_STATE) 1596 return (B_TRUE); 1597 return (B_FALSE); 1598 1599 case SW2HW_EQ: 1600 /* 1601 * HERMON_CMD_BAD_RES_STATE can be gotten in case of EQ 1602 * entry already in hardware ownership. 1603 */ 1604 if (status == HERMON_CMD_BAD_RES_STATE) 1605 return (B_TRUE); 1606 return (B_FALSE); 1607 1608 case HW2SW_EQ: 1609 /* 1610 * HERMON_CMD_BAD_RES_STATE can be gotten in case of EQ 1611 * entry already in software ownership. 1612 */ 1613 if (status == HERMON_CMD_BAD_RES_STATE) 1614 return (B_TRUE); 1615 return (B_FALSE); 1616 1617 case SW2HW_CQ: 1618 /* 1619 * HERMON_CMD_BAD_RES_STATE can be gotten in case of CQ 1620 * entry already in hardware ownership. 1621 */ 1622 if (status == HERMON_CMD_BAD_RES_STATE) 1623 return (B_TRUE); 1624 return (B_FALSE); 1625 1626 case HW2SW_CQ: 1627 /* 1628 * HERMON_CMD_BAD_RES_STATE can be gotten in case of CQ 1629 * entry already in software ownership. 1630 */ 1631 if (status == HERMON_CMD_BAD_RES_STATE) 1632 return (B_TRUE); 1633 return (B_FALSE); 1634 1635 case SW2HW_SRQ: 1636 /* 1637 * HERMON_CMD_BAD_RES_STATE can be gotten in case of SRQ 1638 * entry already in hardware ownership. 1639 */ 1640 if (status == HERMON_CMD_BAD_RES_STATE) 1641 return (B_TRUE); 1642 return (B_FALSE); 1643 1644 case HW2SW_SRQ: 1645 /* 1646 * HERMON_CMD_BAD_RES_STATE can be gotten in case of SRQ 1647 * entry already in software ownership. 1648 */ 1649 if (status == HERMON_CMD_BAD_RES_STATE) 1650 return (B_TRUE); 1651 return (B_FALSE); 1652 default: 1653 break; 1654 } 1655 1656 /* other cases */ 1657 return (B_FALSE); 1658 } 1659 1660 1661 #ifdef FMA_TEST 1662 1663 /* 1664 * Hermon FMA test variables 1665 */ 1666 #define FMA_TEST_HASHSZ 64 1667 int hermon_test_num; /* predefined testset */ 1668 1669 static struct i_hca_fm_test *i_hca_test_register(char *, int, int, 1670 void (*)(struct i_hca_fm_test *, ddi_fm_error_t *), 1671 void *, mod_hash_t *, mod_hash_t *, int); 1672 static void i_hca_test_free_item(mod_hash_val_t); 1673 static void i_hca_test_set_item(int, struct i_hca_fm_test *); 1674 static void hermon_trigger_pio_error(hermon_test_t *, ddi_fm_error_t *); 1675 1676 /* 1677 * Hermon FMA Function Test Interface 1678 */ 1679 1680 /* Attach Errors */ 1681 1682 #define ATTACH_TS (HCA_TEST_TRANSIENT | HCA_TEST_ATTACH | HCA_TEST_START) 1683 #define ATTACH_TE (HCA_TEST_TRANSIENT | HCA_TEST_ATTACH | HCA_TEST_END) 1684 1685 #define ATTACH_PS (HCA_TEST_PERSISTENT | HCA_TEST_ATTACH | HCA_TEST_START) 1686 #define ATTACH_PE (HCA_TEST_PERSISTENT | HCA_TEST_ATTACH | HCA_TEST_END) 1687 1688 static hermon_test_t testset[] = { 1689 /* Initial Value */ 1690 {0, 0, 0, NULL, 0, 0, NULL, NULL, NULL}, /* 0 */ 1691 1692 /* PIO Transient Errors */ 1693 {0, HCA_TEST_PIO, ATTACH_TS, NULL, /* attach/transient/start/propagate */ 1694 HCA_PIO_RETRY_CNT, 0, NULL, NULL, NULL}, /* 1 */ 1695 {0, HCA_TEST_PIO, ATTACH_TE, NULL, /* attach/transient/end/propagate */ 1696 HCA_PIO_RETRY_CNT, 0, NULL, NULL, NULL}, /* 2 */ 1697 1698 /* PIO Persistent Errors */ 1699 {0, HCA_TEST_PIO, ATTACH_PS, NULL, /* attach/persistent/start/propagate */ 1700 0, 0, NULL, NULL, NULL}, /* 3 */ 1701 {0, HCA_TEST_PIO, ATTACH_PE, NULL, /* attach/persistent/end/propagate */ 1702 0, 0, NULL, NULL, NULL}, /* 4 */ 1703 1704 }; 1705 1706 1707 /* 1708 * void 1709 * hermon_trigger_pio_error(hermon_test_t *tst, ddi_fm_error_t *derr) 1710 * 1711 * Overview 1712 * hermon_trigger_pio_error() is a PIO error injection function 1713 * to cause a pseduo PIO error. 1714 * 1715 * Argument 1716 * tst: pointer to HCA FM function test structure. If the structure 1717 * is not used, the NULL value must be passed instead. 1718 * derr: pointer to ddi_fm_error_t structure 1719 * 1720 * Return value 1721 * Nothing 1722 * 1723 * Caller's context 1724 * hermon_trigger_pio_error() can be called in user, kernel, interrupt 1725 * context or high interrupt context. 1726 */ 1727 static void 1728 hermon_trigger_pio_error(hermon_test_t *tst, ddi_fm_error_t *derr) 1729 { 1730 hermon_state_t *state = (hermon_state_t *)tst->private; 1731 derr->fme_status = DDI_FM_OK; 1732 1733 if (tst->type != HCA_TEST_PIO) { 1734 return; 1735 } 1736 1737 if ((tst->trigger & HCA_TEST_ATTACH && 1738 i_ddi_node_state(state->hs_dip) < DS_ATTACHED && 1739 hermon_get_state(state) & HCA_PIO_FM)) { 1740 if (tst->trigger & HCA_TEST_PERSISTENT) { 1741 i_hca_fm_ereport(state->hs_dip, HCA_IBA_ERR, 1742 DDI_FM_DEVICE_INVAL_STATE); 1743 derr->fme_status = DDI_FM_NONFATAL; 1744 return; 1745 } else if (tst->trigger & HCA_TEST_TRANSIENT && 1746 tst->errcnt) { 1747 i_hca_fm_ereport(state->hs_dip, HCA_IBA_ERR, 1748 DDI_FM_DEVICE_INVAL_STATE); 1749 derr->fme_status = DDI_FM_NONFATAL; 1750 tst->errcnt--; 1751 return; 1752 } 1753 } 1754 } 1755 1756 1757 /* 1758 * struct hermon_fm_test * 1759 * hermon_test_register(hermon_state_t *state, char *filename, int linenum, 1760 * int type) 1761 * 1762 * Overview 1763 * hermon_test_register() registers a Hermon FM test item for the 1764 * function test. 1765 * 1766 * Argument 1767 * state: pointer to Hermon state structure 1768 * filename: source file name where the function call is implemented 1769 * This value is usually a __FILE__ pre-defined macro. 1770 * linenum: line number where the function call is described in the 1771 * file specified above. 1772 * This value is usually a __LINE__ pre-defined macro. 1773 * type: HW error type 1774 * HCA_TEST_PIO pio error 1775 * HCA_TEST_IBA ib specific error 1776 * 1777 * Return value 1778 * pointer to Hermon FM function test structure registered. 1779 * 1780 * Caller's context 1781 * hermon_test_register() can be called in user, kernel or interrupt 1782 * context. 1783 * 1784 * Note that no test item is registered if Hermon FM is disabled. 1785 */ 1786 hermon_test_t * 1787 hermon_test_register(hermon_state_t *state, char *filename, int linenum, 1788 int type) 1789 { 1790 void (*pio_injection)(struct i_hca_fm_test *, ddi_fm_error_t *) = 1791 (void (*)(struct i_hca_fm_test *, ddi_fm_error_t *)) 1792 hermon_trigger_pio_error; 1793 1794 if (state->hs_fm_disable) 1795 return (NULL); 1796 1797 return ((hermon_test_t *)i_hca_test_register(filename, linenum, type, 1798 pio_injection, (void *)state, state->hs_fm_test_hash, 1799 state->hs_fm_id_hash, hermon_test_num)); 1800 } 1801 #endif /* FMA_TEST */ 1802 1803 1804 /* 1805 * HCA FM Common Interface 1806 * 1807 * These functions should be used for any HCA drivers, but probably 1808 * customized for their own HW design and/or FM implementation. 1809 * Customized functins should have the driver name prefix such as 1810 * hermon_xxxx() and be defined separately but whose functions should 1811 * call the common interface inside. 1812 */ 1813 1814 /* 1815 * void 1816 * i_hca_fm_init(struct i_hca_fm *hca_fm) 1817 * 1818 * Overview 1819 * i_hca_fm_init() is an initialization function which sets up the acc 1820 * handle kmem_cache if this function is called the first time. 1821 * 1822 * Argument 1823 * hca_fm: pointer to HCA FM structure 1824 * 1825 * Return value 1826 * Nothing 1827 * 1828 * Caller's context 1829 * i_hca_fm_init() can be called in user or kernel context, but cannot 1830 * be called in interrupt context. 1831 */ 1832 static void 1833 i_hca_fm_init(struct i_hca_fm *hca_fm) 1834 { 1835 1836 mutex_enter(&hca_fm->lock); 1837 1838 ++hca_fm->ref_cnt; 1839 if (hca_fm->fm_acc_cache == NULL) { 1840 hca_fm->fm_acc_cache = kmem_cache_create("hca_fm_acc_handle", 1841 sizeof (struct i_hca_acc_handle), 0, NULL, 1842 NULL, NULL, NULL, NULL, 0); 1843 } 1844 1845 mutex_exit(&hca_fm->lock); 1846 } 1847 1848 1849 /* 1850 * void 1851 * i_hca_fm_fini(struct i_hca_fm *hca_fm) 1852 * 1853 * Overview 1854 * i_hca_fm_fini() is a finalization function which frees up the acc 1855 * handle kmem_cache if this function is called the last time. 1856 * 1857 * Argument 1858 * hca_fm: pointer to HCA FM structure 1859 * 1860 * Return value 1861 * Nothing 1862 * 1863 * Caller's context 1864 * i_hca_fm_fini() can be called in user or kernel context, but cannot 1865 * be called in interrupt context. 1866 */ 1867 static void 1868 i_hca_fm_fini(struct i_hca_fm *hca_fm) 1869 { 1870 mutex_enter(&hca_fm->lock); 1871 1872 if (--hca_fm->ref_cnt == 0) { 1873 1874 if (hca_fm->fm_acc_cache) { 1875 kmem_cache_destroy(hca_fm->fm_acc_cache); 1876 hca_fm->fm_acc_cache = NULL; 1877 } 1878 } 1879 1880 mutex_exit(&hca_fm->lock); 1881 } 1882 1883 1884 /* 1885 * void 1886 * i_hca_fm_ereport(dev_info_t *dip, int type, char *detail) 1887 * 1888 * Overview 1889 * i_hca_fm_ereport() is a wrapper function of ddi_fm_ereport_post() but 1890 * generates an ena before it calls ddi_fm_ereport_post() for HCA 1891 * specific HW errors. 1892 * 1893 * Argument 1894 * dip: pointer to this device dev_info structure 1895 * type: error type 1896 * HCA_SYS_ERR FMA reporting HW error 1897 * HCA_IBA_ERR HCA specific HW error 1898 * detail: definition of leaf driver detected ereports which is one of: 1899 * DDI_FM_DEVICE_INVAL_STATE 1900 * DDI_FM_DEVICE_NO_RESPONSE 1901 * DDI_FM_DEVICE_STALL 1902 * DDI_FM_DEVICE_BADINT_LIMIT 1903 * DDI_FM_DEVICE_INTERN_CORR 1904 * DDI_FM_DEVICE_INTERN_UNCORR 1905 * 1906 * Return value 1907 * Nothing 1908 * 1909 * Caller's context 1910 * i_hca_fm_ereport() can be called in user, kernel or interrupt context. 1911 */ 1912 static void 1913 i_hca_fm_ereport(dev_info_t *dip, int type, char *detail) 1914 { 1915 uint64_t ena; 1916 char buf[FM_MAX_CLASS]; 1917 1918 (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail); 1919 1920 ena = fm_ena_generate(0, FM_ENA_FMT1); 1921 if (type == HCA_IBA_ERR) { 1922 /* this is an error of its own */ 1923 ena = fm_ena_increment(ena); 1924 } 1925 1926 ddi_fm_ereport_post(dip, buf, ena, DDI_NOSLEEP, 1927 FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0, NULL); 1928 } 1929 1930 1931 /* 1932 * struct i_hca_acc_handle * 1933 * i_hca_get_acc_handle(struct i_hca_fm *hca_fm, ddi_acc_handle_t handle) 1934 * 1935 * Overview 1936 * i_hca_get_acc_handle() returns ddi_acc_handle_t used for HCA FM. 1937 * 1938 * Argument 1939 * hca_fm: pointer to HCA FM structure 1940 * handle: ddi_acc_handle_t 1941 * 1942 * Return value 1943 * handle: pointer to ddi_acc_handle_t used for HCA FM 1944 * 1945 * Caller's context 1946 * i_hca_get_acc_handle() can be called in user, kernel or interrupt 1947 * context. 1948 */ 1949 static struct i_hca_acc_handle * 1950 i_hca_get_acc_handle(struct i_hca_fm *hca_fm, ddi_acc_handle_t handle) 1951 { 1952 struct i_hca_acc_handle *hdlp; 1953 1954 /* Retrieve the HCA FM access handle */ 1955 mutex_enter(&hca_fm->lock); 1956 1957 for (hdlp = hca_fm->hdl; hdlp != NULL; hdlp = hdlp->next) { 1958 if (hdlp->save_hdl == handle) { 1959 mutex_exit(&hca_fm->lock); 1960 return (hdlp); 1961 } 1962 } 1963 1964 mutex_exit(&hca_fm->lock); 1965 return (hdlp); 1966 } 1967 1968 1969 /* 1970 * int 1971 * i_hca_regs_map_setup(struct i_hca_fm *hca_fm, dev_info_t *dip, 1972 * uint_t rnumber, caddr_t *addrp, offset_t offset, offset_t len, 1973 * ddi_device_acc_attr_t *accattrp, ddi_acc_handle_t *handle) 1974 * 1975 * Overview 1976 * i_hca_regs_map_setup() is a wrapper function of ddi_regs_map_setup(), 1977 * but allocates the HCA FM acc handle structure and initializes it. 1978 * 1979 * Argument 1980 * hca_fm: pointer to HCA FM structure 1981 * dip: pointer to this device dev_info structure 1982 * rnumber: index number to the register address space set 1983 * addrp: platform-dependent value (same as ddi_regs_map_setup()) 1984 * offset: offset into the register address space 1985 * len: address space length to be mapped 1986 * accattrp: pointer to device access attribute structure 1987 * handle: pointer to ddi_acc_handle_t used for HCA FM 1988 * 1989 * Return value 1990 * ddi function status value which are: 1991 * DDI_SUCCESS 1992 * DDI_FAILURE 1993 * DDI_ME_RNUMBER_RNGE 1994 * DDI_REGS_ACC_CONFLICT 1995 * 1996 * Caller's context 1997 * i_hca_regs_map_setup() can be called in user or kernel context only. 1998 */ 1999 static int 2000 i_hca_regs_map_setup(struct i_hca_fm *hca_fm, dev_info_t *dip, uint_t rnumber, 2001 caddr_t *addrp, offset_t offset, offset_t len, 2002 ddi_device_acc_attr_t *accattrp, ddi_acc_handle_t *handle) 2003 { 2004 int status; 2005 struct i_hca_acc_handle *handlep, *hdlp, *last; 2006 2007 /* Allocate an access handle */ 2008 if ((status = ddi_regs_map_setup(dip, rnumber, addrp, offset, 2009 len, accattrp, handle)) != DDI_SUCCESS) { 2010 return (status); 2011 } 2012 2013 /* Allocate HCA FM acc handle structure */ 2014 handlep = kmem_cache_alloc(hca_fm->fm_acc_cache, KM_SLEEP); 2015 2016 /* Initialize fields */ 2017 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*handlep)) 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 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*handlep)) 2134 handlep->next = NULL; 2135 handlep->save_hdl = (*handle); 2136 handlep->thread_cnt = 0; 2137 mutex_init(&handlep->lock, NULL, MUTEX_DRIVER, NULL); 2138 2139 /* Register this handle */ 2140 mutex_enter(&hca_fm->lock); 2141 for (last = hdlp = hca_fm->hdl; hdlp != NULL; hdlp = hdlp->next) { 2142 last = hdlp; 2143 } 2144 if (last == NULL) { 2145 hca_fm->hdl = handlep; 2146 } else { 2147 last->next = handlep; 2148 } 2149 mutex_exit(&hca_fm->lock); 2150 2151 return (status); 2152 } 2153 2154 2155 /* 2156 * void 2157 * i_hca_pci_config_teardown(struct i_hca_fm *hca_fm, 2158 * ddi_acc_handle_t *handlep) 2159 * 2160 * Overview 2161 * i_hca_pci_config_teardown() is a wrapper function of 2162 * pci_config_teardown(), and frees the HCA FM acc handle structure 2163 * allocated by i_hca_pci_config_setup(). 2164 * 2165 * Argument 2166 * hca_fm: pointer to HCA FM structure 2167 * handle: pointer to ddi_acc_handle_t used for HCA FM 2168 * 2169 * Return value 2170 * Nothing 2171 * 2172 * Caller's context 2173 * i_hca_pci_config_teardown() can be called in user or kernel context 2174 * only. 2175 * 2176 * Note that the handle passed to i_hca_pci_config_teardown() is NULL-cleared 2177 * after this function is called. 2178 */ 2179 static void 2180 i_hca_pci_config_teardown(struct i_hca_fm *hca_fm, ddi_acc_handle_t *handle) 2181 { 2182 struct i_hca_acc_handle *handlep, *hdlp, *prev; 2183 2184 /* De-register this handle */ 2185 mutex_enter(&hca_fm->lock); 2186 for (prev = hdlp = hca_fm->hdl; hdlp != NULL; hdlp = hdlp->next) { 2187 if (hdlp->save_hdl == *handle) 2188 break; 2189 prev = hdlp; 2190 } 2191 ASSERT(prev != NULL && hdlp != NULL); 2192 if (hdlp != prev) { 2193 prev->next = hdlp->next; 2194 } else { 2195 hca_fm->hdl = hdlp->next; 2196 } 2197 handlep = hdlp; 2198 mutex_exit(&hca_fm->lock); 2199 2200 mutex_destroy(&handlep->lock); 2201 handlep->save_hdl = NULL; 2202 kmem_cache_free(hca_fm->fm_acc_cache, handlep); 2203 2204 /* Release this handle */ 2205 pci_config_teardown(handle); 2206 *handle = NULL; 2207 } 2208 2209 2210 /* 2211 * int 2212 * i_hca_pio_start(dev_info_t *dip, struct i_acc_handle *handle, 2213 * struct i_hca_fm_test *tst) 2214 * 2215 * Overview 2216 * i_hca_pio_start() is one of a pair of HCA FM fuctions for PIO, which 2217 * should be called before HCA drivers issue PIOs against I/O space. 2218 * See HCA FM comments at the beginning of this file in detail. 2219 * 2220 * Argument 2221 * dip: pointer to this device dev_info structure 2222 * handle: pointer to ddi_acc_handle_t used for HCA FM 2223 * tst: pointer to HCA FM function test structure. If the structure 2224 * is not used, the NULL value must be passed instead. 2225 * 2226 * Return value 2227 * error status showing whether or not this error can retry 2228 * HCA_PIO_OK No HW errors 2229 * HCA_PIO_TRANSIENT This error could be transient 2230 * HCA_PIO_PERSISTENT This error is persistent 2231 * 2232 * Caller's context 2233 * i_hca_pio_start() can be called in user, kernel or interrupt context. 2234 */ 2235 /* ARGSUSED */ 2236 static int 2237 i_hca_pio_start(dev_info_t *dip, struct i_hca_acc_handle *hdlp, 2238 struct i_hca_fm_test *tst) 2239 { 2240 ddi_fm_error_t derr; 2241 2242 /* Count up the number of threads issuing this PIO */ 2243 mutex_enter(&hdlp->lock); 2244 hdlp->thread_cnt++; 2245 mutex_exit(&hdlp->lock); 2246 2247 /* Get the PIO error via FMA */ 2248 ddi_fm_acc_err_get(fm_acc_hdl(hdlp), &derr, DDI_FME_VERSION); 2249 2250 #ifdef FMA_TEST 2251 /* Trigger PIO errors */ 2252 if (tst != NULL && tst->trigger & HCA_TEST_START) { 2253 (*tst->pio_injection)(tst, &derr); 2254 } 2255 #endif /* FMA_TEST */ 2256 2257 switch (derr.fme_status) { 2258 case DDI_FM_OK: 2259 /* Not have to clear the fma error log */ 2260 return (HCA_PIO_OK); 2261 2262 case DDI_FM_NONFATAL: 2263 /* Now clear this error */ 2264 ddi_fm_acc_err_clear(fm_acc_hdl(hdlp), DDI_FME_VERSION); 2265 2266 /* Log this error and notify it as a persistent error */ 2267 ddi_fm_service_impact(dip, DDI_SERVICE_LOST); 2268 return (HCA_PIO_PERSISTENT); 2269 2270 /* In theory, this shouldn't happen */ 2271 case DDI_FM_FATAL: 2272 case DDI_FM_UNKNOWN: 2273 default: 2274 cmn_err(CE_WARN, "Unknown HCA HW error status (%d)", 2275 derr.fme_status); 2276 /* Return this as a persistent error */ 2277 return (HCA_PIO_PERSISTENT); 2278 } 2279 } 2280 2281 2282 /* 2283 * int 2284 * i_hca_pio_end(dev_info_t *dip, ddi_acc_handle_t handle, int *cnt, 2285 * struct i_hca_fm_test *tst) 2286 * 2287 * Overview 2288 * i_hca_pio_end() is the other of a pair of HCA FM fuctions for PIO, 2289 * which should be called after HCA drivers issue PIOs against I/O space. 2290 * See HCA FM comments at the beginning of this file in detail. 2291 * 2292 * Argument 2293 * dip: pointer to this device dev_info structure 2294 * handle: pointer to ddi_acc_handle_t used for HCA FM 2295 * cnt: pointer to the counter variable which holds the nubmer of retry 2296 * when a HW error is detected. 2297 * tst: pointer to HCA FM function test structure. If the structure 2298 * is not used, the NULL value must be passed instead. 2299 * 2300 * Return value 2301 * error status showing whether or not this error can retry 2302 * HCA_PIO_OK No HW errors 2303 * HCA_PIO_TRANSIENT This error could be transient 2304 * HCA_PIO_PERSISTENT This error is persistent 2305 * 2306 * Caller's context 2307 * i_hca_pio_end() can be called in user, kernel or interrupt context. 2308 */ 2309 /* ARGSUSED */ 2310 static int 2311 i_hca_pio_end(dev_info_t *dip, struct i_hca_acc_handle *hdlp, int *cnt, 2312 struct i_hca_fm_test *tst) 2313 { 2314 ddi_fm_error_t derr; 2315 2316 /* Get the PIO error via FMA */ 2317 ddi_fm_acc_err_get(fm_acc_hdl(hdlp), &derr, DDI_FME_VERSION); 2318 2319 #ifdef FMA_TEST 2320 /* Trigger PIO errors */ 2321 if (tst != NULL && tst->trigger & HCA_TEST_END) { 2322 (*tst->pio_injection)(tst, &derr); 2323 } 2324 #endif /* FMA_TEST */ 2325 2326 /* Evaluate the PIO error */ 2327 switch (derr.fme_status) { 2328 case DDI_FM_OK: 2329 /* Count down the number of threads issuing this PIO */ 2330 mutex_enter(&hdlp->lock); 2331 hdlp->thread_cnt--; 2332 mutex_exit(&hdlp->lock); 2333 2334 /* Not have to clear the fma error log */ 2335 return (HCA_PIO_OK); 2336 2337 case DDI_FM_NONFATAL: 2338 /* Now clear this error */ 2339 ddi_fm_acc_err_clear(fm_acc_hdl(hdlp), DDI_FME_VERSION); 2340 2341 /* 2342 * Check if this error comes from another thread running 2343 * with the same handle almost at the same time. 2344 */ 2345 mutex_enter(&hdlp->lock); 2346 if (hdlp->thread_cnt > 1) { 2347 /* Count down the number of threads */ 2348 hdlp->thread_cnt--; 2349 mutex_exit(&hdlp->lock); 2350 2351 /* Return this as a persistent error */ 2352 return (HCA_PIO_PERSISTENT); 2353 } 2354 mutex_exit(&hdlp->lock); 2355 2356 /* Now determine if this error is persistent or not */ 2357 if (--(*cnt) >= 0) { 2358 return (HCA_PIO_TRANSIENT); 2359 } else { 2360 /* Count down the number of threads */ 2361 mutex_enter(&hdlp->lock); 2362 hdlp->thread_cnt--; 2363 mutex_exit(&hdlp->lock); 2364 return (HCA_PIO_PERSISTENT); 2365 } 2366 2367 /* In theory, this shouldn't happen */ 2368 case DDI_FM_FATAL: 2369 case DDI_FM_UNKNOWN: 2370 default: 2371 cmn_err(CE_WARN, "Unknown HCA HW error status (%d)", 2372 derr.fme_status); 2373 /* Return this as a persistent error */ 2374 return (HCA_PIO_PERSISTENT); 2375 } 2376 } 2377 2378 2379 /* 2380 * HCA FM Test Interface 2381 * 2382 * These functions should be used for any HCA drivers, but probably 2383 * customized for their own HW design and/or FM implementation. 2384 * Customized functins should have the driver name prefix such as 2385 * hermon_xxxx() and be defined separately but whose function should 2386 * call the common interface inside. 2387 */ 2388 2389 #ifdef FMA_TEST 2390 static int test_num; /* serial number */ 2391 static kmutex_t i_hca_test_lock; /* lock for serial numer */ 2392 2393 /* 2394 * void 2395 * i_hca_test_init(mod_hash_t **strHashp, mod_hash_t **idHashp) 2396 * 2397 * Overview 2398 * i_hca_test_init() creates two hash tables, one of which is for string, 2399 * and the other of which is for ID, then saves pointers to arguments 2400 * passed. This function uses the mod_hash utilities to manage the 2401 * hash tables. About the mod_hash, see common/os/modhash.c. 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_init() can be called in user or kernel context only. 2412 */ 2413 static void 2414 i_hca_test_init(mod_hash_t **strHashp, mod_hash_t **idHashp) 2415 { 2416 *idHashp = mod_hash_create_idhash("HCA_FMA_id_hash", 2417 FMA_TEST_HASHSZ, mod_hash_null_valdtor); 2418 2419 *strHashp = mod_hash_create_strhash("HCA_FMA_test_hash", 2420 FMA_TEST_HASHSZ, i_hca_test_free_item); 2421 } 2422 2423 2424 /* 2425 * void 2426 * i_hca_test_fini(mod_hash_t **strHashp, mod_hash_t **idHashp) 2427 * 2428 * Overview 2429 * i_hca_test_fini() releases two hash tables used for HCA FM test. 2430 * 2431 * Argument 2432 * strHashp: pointer to String hash table pointer 2433 * idHashp: pointer to ID hash table pointer 2434 * 2435 * Return value 2436 * Nothing 2437 * 2438 * Caller's context 2439 * i_hca_test_fini() can be called in user, kernel or interrupt context. 2440 * 2441 */ 2442 static void 2443 i_hca_test_fini(mod_hash_t **strHashp, mod_hash_t **idHashp) 2444 { 2445 mod_hash_destroy_hash(*strHashp); 2446 *strHashp = NULL; 2447 2448 mod_hash_destroy_hash(*idHashp); 2449 *idHashp = NULL; 2450 } 2451 2452 2453 /* 2454 * struct i_hca_fm_test * 2455 * i_hca_test_register(char *filename, int linenum, int type, 2456 * void (*pio_injection)(struct i_hca_fm_test *, ddi_fm_error_t *), 2457 * void *private, mod_hash_t *strHash, mod_hash_t *idHash, int preTestNum) 2458 * 2459 * Overview 2460 * i_hca_test_register() registers an HCA FM test item against HCA FM 2461 * function callings specified with the file name and the line number 2462 * (passed as the arguments). 2463 * 2464 * Argument 2465 * filename: source file name where the function call is implemented 2466 * This value is usually a __FILE__ pre-defined macro. 2467 * linenum: line number where the function call is described in the 2468 * file specified above. 2469 * This value is usually a __LINE__ pre-defined macro. 2470 * type: HW error type 2471 * HCA_TEST_PIO pio error 2472 * HCA_TEST_IBA ib specific error 2473 * pio_injection: pio error injection callback function invoked when the 2474 * function specified above (with the file name and the 2475 * line number) is executed. If the function is not a PIO, 2476 * request, this parameter should be NULL. 2477 * private: the argument passed to either of injection functions when 2478 * they're invoked. 2479 * strHashp: pointer to String hash table 2480 * idHashp: pointer to ID hash table 2481 * preTestNum: the index of the pre-defined testset for this test item. 2482 * 2483 * Return value 2484 * pointer to HCA FM function test structure registered. 2485 * 2486 * Caller's context 2487 * i_hca_test_register() can be called in user, kernel or interrupt 2488 * context. 2489 * 2490 */ 2491 static struct i_hca_fm_test * 2492 i_hca_test_register(char *filename, int linenum, int type, 2493 void (*pio_injection)(struct i_hca_fm_test *, ddi_fm_error_t *), 2494 void *private, mod_hash_t *strHash, mod_hash_t *idHash, int preTestNum) 2495 { 2496 struct i_hca_fm_test *t_item; 2497 char key_buf[255], *hash_key; 2498 int status; 2499 2500 (void) sprintf(key_buf, "%s:%d", filename, linenum); 2501 hash_key = kmem_zalloc(strlen(key_buf) + 1, KM_NOSLEEP); 2502 2503 if (hash_key == NULL) 2504 cmn_err(CE_PANIC, "No memory for HCA FMA Test."); 2505 2506 bcopy(key_buf, hash_key, strlen(key_buf)); 2507 2508 status = mod_hash_find(strHash, (mod_hash_key_t)hash_key, 2509 (mod_hash_val_t *)&t_item); 2510 2511 switch (status) { 2512 case MH_ERR_NOTFOUND: 2513 t_item = (struct i_hca_fm_test *) 2514 kmem_alloc(sizeof (struct i_hca_fm_test), KM_NOSLEEP); 2515 if (t_item == NULL) 2516 cmn_err(CE_PANIC, "No memory for HCA FMA Test."); 2517 2518 /* Set the error number */ 2519 mutex_enter(&i_hca_test_lock); 2520 t_item->num = test_num++; 2521 mutex_exit(&i_hca_test_lock); 2522 2523 /* Set type and other static information */ 2524 t_item->type = type; 2525 t_item->line_num = linenum; 2526 t_item->file_name = filename; 2527 t_item->hash_key = hash_key; 2528 t_item->private = private; 2529 t_item->pio_injection = pio_injection; 2530 2531 /* Set the pre-defined hermon test item */ 2532 i_hca_test_set_item(preTestNum, (struct i_hca_fm_test *)t_item); 2533 2534 status = mod_hash_insert(strHash, (mod_hash_key_t) 2535 hash_key, (mod_hash_val_t)t_item); 2536 ASSERT(status == 0); 2537 2538 status = mod_hash_insert(idHash, (mod_hash_key_t) 2539 (uintptr_t)t_item->num, (mod_hash_val_t)t_item); 2540 ASSERT(status == 0); 2541 break; 2542 2543 case MH_ERR_NOMEM: 2544 cmn_err(CE_PANIC, "No memory for HCA FMA Test."); 2545 break; 2546 2547 case MH_ERR_DUPLICATE: 2548 cmn_err(CE_PANIC, "HCA FMA Test Internal Error."); 2549 break; 2550 default: 2551 /* OK, this is already registered. */ 2552 kmem_free(hash_key, strlen(key_buf) + 1); 2553 break; 2554 } 2555 return (t_item); 2556 } 2557 2558 2559 /* 2560 * void 2561 * i_hca_test_set_item(int num, struct i_hca_fm_test *t_item) 2562 * 2563 * Overview 2564 * i_hca_test_set_item() is a private function used in 2565 * i_hca_test_register() above. This function sets the testset specified 2566 * (with the index number) to HCA FM function test structure. 2567 * 2568 * Argument 2569 * num: index to test set (testset structure array) 2570 * t_item: pointer to HCA fM function test structure 2571 * 2572 * Return value 2573 * Nothing 2574 * 2575 * Caller's context 2576 * i_hca_test_set_item() can be called in user, kernel, interrupt 2577 * context or hight interrupt context. 2578 * 2579 */ 2580 static void 2581 i_hca_test_set_item(int num, struct i_hca_fm_test *t_item) 2582 { 2583 if (num < 0 || num >= sizeof (testset) / sizeof (hermon_test_t) || 2584 testset[num].type != t_item->type) { 2585 t_item->trigger = testset[0].trigger; 2586 t_item->errcnt = testset[0].errcnt; 2587 return; 2588 } 2589 2590 /* Set the testsuite */ 2591 t_item->trigger = testset[num].trigger; 2592 t_item->errcnt = testset[num].errcnt; 2593 } 2594 2595 2596 /* 2597 * void 2598 * i_hca_test_free_item(mod_hash_val_t val) 2599 * 2600 * Overview 2601 * i_hca_test_free_item() is a private function used to free HCA FM 2602 * function test structure when i_hca_test_fini() is called. This function 2603 * is registered as a destructor when the hash table is created in 2604 * i_hca_test_init(). 2605 * 2606 * Argument 2607 * val: pointer to the value stored in hash table (pointer to HCA FM 2608 * function test structure) 2609 * 2610 * Return value 2611 * Nothing 2612 * 2613 * Caller's context 2614 * i_hca_test_free_item() can be called in user, kernel or interrupt 2615 * context. 2616 * 2617 */ 2618 static void 2619 i_hca_test_free_item(mod_hash_val_t val) 2620 { 2621 struct i_hca_fm_test *t_item = (struct i_hca_fm_test *)val; 2622 kmem_free(t_item, sizeof (struct i_hca_fm_test)); 2623 } 2624 #endif /* FMA_TEST */ 2625