Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / uts / common / io / ib / adapters / hermon / hermon_fm.c
bloba77fa4f15c4a729a1660aead0fc9e7aa4293c733
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
27 * hermon_fm.c
28 * Hermon (InfiniBand) HCA Driver Fault Management Routines
30 * [Hermon FM Implementation]
32 * Hermon FM recovers the system from a HW error situation and/or isolates a
33 * HW error by calling the FMA acc handle check functions. (calling
34 * ddi_fm_acc_err_get()) If a HW error is detected when either
35 * ddi_fm_acc_err_get() is called, to determine whether or not the error is
36 * transient, the I/O operation causing the error will retry up to three times.
38 * (Basic HW error recovery)
40 * |
41 * .---->*
42 * | |
43 * | issue an I/O request via PIO
44 * | |
45 * | |
46 * | check acc handle
47 * | |
48 * | |
49 * `--< a HW error detected && retry count < 3 >
50 * |
51 * v
53 * When a HW error is detected, to provide the error information for users to
54 * isolate the faulted HW, Hermon FM issues Solaris FMA ereports as follows.
56 * * PIO transient error
57 * invalid_state => unaffected
59 * * PIO persistent error
60 * invalid_state => lost
62 * * PIO fatal error
63 * invalid_state => lost => panic
65 * * Hermon HCA firmware error
66 * invalid_state => degraded
68 * * Other Hermon HCA specific errors
69 * uncorrect => unaffected
70 * or
71 * correct => unaffected
73 * (Restrictions)
75 * The current implementation has the following restrictions.
76 * * No runtime check/protection
77 * * No detach time check/protection
78 * * No DMA check/protection
80 * See the Hermon FMA portfolio in detail.
83 #include <sys/types.h>
84 #include <sys/conf.h>
85 #include <sys/ddi.h>
86 #include <sys/sunddi.h>
87 #include <sys/sysmacros.h>
88 #include <sys/list.h>
89 #include <sys/modhash.h>
91 #include <sys/ib/adapters/hermon/hermon.h>
94 * Hermon driver has to disable its FM functionality
95 * if this "fm_capable" variable is defined or has a value
96 * in /kernel/drv/hermon.conf.
98 static char *fm_cap = "fm-capable"; /* FM capability */
100 static hermon_hca_fm_t hca_fm; /* Hermon HCA FM Structure */
102 static void i_hca_fm_ereport(dev_info_t *, int, char *);
103 static void i_hca_fm_init(struct i_hca_fm *);
104 static void i_hca_fm_fini(struct i_hca_fm *);
105 static int i_hca_regs_map_setup(struct i_hca_fm *, dev_info_t *, uint_t,
106 caddr_t *, offset_t, offset_t, ddi_device_acc_attr_t *, ddi_acc_handle_t *);
107 static void i_hca_regs_map_free(struct i_hca_fm *, ddi_acc_handle_t *);
108 static int i_hca_pci_config_setup(struct i_hca_fm *, dev_info_t *,
109 ddi_acc_handle_t *);
110 static void i_hca_pci_config_teardown(struct i_hca_fm *, ddi_acc_handle_t *);
111 static int i_hca_pio_start(dev_info_t *, struct i_hca_acc_handle *,
112 hermon_test_t *);
113 static int i_hca_pio_end(dev_info_t *, struct i_hca_acc_handle *, int *,
114 hermon_test_t *);
115 static struct i_hca_acc_handle *i_hca_get_acc_handle(struct i_hca_fm *,
116 ddi_acc_handle_t);
118 /* forward declaration for hermon_fm_{init, fini}() */
119 #ifdef FMA_TEST
120 static void i_hca_test_init(mod_hash_t **, mod_hash_t **);
121 static void i_hca_test_fini(mod_hash_t **, mod_hash_t **);
122 #endif /* FMA_TEST */
125 * Hermon FM Functions
127 * These functions are based on the HCA FM common interface
128 * defined below, but specific to the Hermon HCA FM capabilities.
132 * void
133 * hermon_hca_fm_init(hermon_state_t *state, hermon_hca_fm_t *hca)
135 * Overview
136 * hermon_hca_fm_init() initializes the Hermon FM resources.
138 * Argument
139 * state: pointer to Hermon state structure
140 * hca: pointer to Hermon FM structure
142 * Return value
143 * Nothing
145 * Caller's context
146 * hermon_hca_fm_init() can be called in user or kernel context only.
148 static void
149 hermon_hca_fm_init(hermon_state_t *state, hermon_hca_fm_t *hca_fm)
151 state->hs_fm_hca_fm = hca_fm;
152 i_hca_fm_init((struct i_hca_fm *)hca_fm);
157 * void
158 * hermon_hca_fm_fini(hermon_state_t *state)
160 * Overview
161 * hermon_hca_fm_fini() releases the Hermon FM resources.
163 * Argument
164 * state: pointer to Hermon state structure
166 * Return value
167 * Nothing
169 * Caller's context
170 * hermon_hca_fm_fini() can be called in user or kernel context only.
172 static void
173 hermon_hca_fm_fini(hermon_state_t *state)
175 i_hca_fm_fini((struct i_hca_fm *)state->hs_fm_hca_fm);
176 state->hs_fm_hca_fm = NULL;
180 * void
181 * hermon_clr_state_nolock(hermon_state_t *state, int fm_state)
183 * Overview
184 * hermon_clr_state() drops the specified state from Hermon FM state
185 * without the mutex locks.
187 * Argument
188 * state: pointer to Hermon state structure
189 * fm_state: Hermon FM state, which is composed of:
190 * HCA_NO_FM Hermom FM is not supported
191 * HCA_PIO_FM PIO is fma-protected
192 * HCA_DMA_FM DMA is fma-protected
193 * HCA_EREPORT_FM FMA ereport is available
194 * HCA_ERRCB_FM FMA error callback is supported
195 * HCA_ATTCH_FM HCA FM attach mode
196 * HCA_RUNTM_FM HCA FM runtime mode
198 * Return value
199 * Nothing
201 * Caller's context
202 * hermon_clr_state() can be called in user, kernel, interrupt context
203 * or high interrupt context.
205 void
206 hermon_clr_state_nolock(hermon_state_t *state, int fm_state)
208 extern void membar_sync(void);
210 state->hs_fm_state &= ~fm_state;
211 membar_sync();
216 * void
217 * hermon_clr_state(hermon_state_t *state, int fm_state)
219 * Overview
220 * hermon_clr_state() drops the specified state from Hermon FM state.
222 * Argument
223 * state: pointer to Hermon state structure
224 * fm_state: Hermon FM state, which is composed of:
225 * HCA_NO_FM Hermom FM is not supported
226 * HCA_PIO_FM PIO is fma-protected
227 * HCA_DMA_FM DMA is fma-protected
228 * HCA_EREPORT_FM FMA ereport is available
229 * HCA_ERRCB_FM FMA error callback is supported
230 * HCA_ATTCH_FM HCA FM attach mode
231 * HCA_RUNTM_FM HCA FM runtime mode
233 * Return value
234 * Nothing
236 * Caller's context
237 * hermon_clr_state() can be called in user, kernel or interrupt context.
239 static void
240 hermon_clr_state(hermon_state_t *state, int fm_state)
242 ASSERT(fm_state != HCA_NO_FM);
244 mutex_enter(&state->hs_fm_lock);
245 hermon_clr_state_nolock(state, fm_state);
246 mutex_exit(&state->hs_fm_lock);
251 * void
252 * hermon_set_state(hermon_state_t *state, int fm_state)
254 * Overview
255 * hermon_set_state() sets Hermon FM state.
257 * Argument
258 * state: pointer to Hermon state structure
259 * fm_state: Hermon FM state, which is composed of:
260 * HCA_NO_FM Hermom FM is not supported
261 * HCA_PIO_FM PIO is fma-protected
262 * HCA_DMA_FM DMA is fma-protected
263 * HCA_EREPORT_FM FMA ereport is available
264 * HCA_ERRCB_FM FMA error callback is supported
265 * HCA_ATTCH_FM HCA FM attach mode
266 * HCA_RUNTM_FM HCA FM runtime mode
268 * Return value
269 * Nothing
271 * Caller's context
272 * hermon_set_state() can be called in user, kernel or interrupt context.
274 static void
275 hermon_set_state(hermon_state_t *state, int fm_state)
277 extern void membar_sync(void);
279 mutex_enter(&state->hs_fm_lock);
280 if (fm_state == HCA_NO_FM) {
281 state->hs_fm_state = HCA_NO_FM;
282 } else {
283 state->hs_fm_state |= fm_state;
285 membar_sync();
286 mutex_exit(&state->hs_fm_lock);
291 * int
292 * hermon_get_state(hermon_state_t *state)
294 * Overview
295 * hermon_get_state() returns the current Hermon FM state.
297 * Argument
298 * state: pointer to Hermon state structure
300 * Return value
301 * fm_state: Hermon FM state, which is composed of:
302 * HCA_NO_FM Hermom FM is not supported
303 * HCA_PIO_FM PIO is fma-protected
304 * HCA_DMA_FM DMA is fma-protected
305 * HCA_EREPORT_FM FMA ereport is available
306 * HCA_ERRCB_FM FMA error callback is supported
307 * HCA_ATTCH_FM HCA FM attach mode
308 * HCA_RUNTM_FM HCA FM runtime mode
310 * Caller's context
311 * hermon_get_state() can be called in user, kernel or interrupt context.
314 hermon_get_state(hermon_state_t *state)
316 return (state->hs_fm_state);
321 * void
322 * hermon_fm_init(hermon_state_t *state)
324 * Overview
325 * hermon_fm_init() is a Hermon FM initialization function which registers
326 * some FMA functions such as the ereport and the acc check capabilities
327 * for Hermon. If the "fm_disable" property in /kernel/drv/hermon.conf is
328 * defined (and/or its value is set), then the Hermon FM capabilities will
329 * drop, and only the default capabilities (the ereport and error callback
330 * capabilities) are available (and the action against HW errors is
331 * issuing an ereport then panicking the system).
333 * Argument
334 * state: pointer to Hermon state structure
336 * Return value
337 * Nothing
339 * Caller's context
340 * hermon_fm_init() can be called in user or kernel context only.
342 void
343 hermon_fm_init(hermon_state_t *state)
345 ddi_iblock_cookie_t iblk;
348 * Check the "fm_disable" property. If it's defined,
349 * use the Solaris FMA default action for Hermon.
351 if (ddi_getprop(DDI_DEV_T_NONE, state->hs_dip, DDI_PROP_DONTPASS,
352 "fm_disable", 0) != 0) {
353 state->hs_fm_disable = 1;
356 /* If hs_fm_diable is set, then skip the rest */
357 if (state->hs_fm_disable) {
358 hermon_set_state(state, HCA_NO_FM);
359 return;
362 /* Set the Hermon FM attach mode */
363 hermon_set_state(state, HCA_ATTCH_FM);
365 /* Initialize the Solaris FMA capabilities for the Hermon FM support */
366 state->hs_fm_capabilities = ddi_prop_get_int(DDI_DEV_T_ANY,
367 state->hs_dip, DDI_PROP_DONTPASS, fm_cap,
368 DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE);
371 * The Hermon FM uses the ereport and acc check capabilites only,
372 * but both of them should be available. If either is not, turn
373 * hs_fm_disable on and behave in the same way as the "fm_diable"
374 * property is set.
376 if (state->hs_fm_capabilities !=
377 (DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE)) {
378 state->hs_fm_disable = 1;
379 hermon_set_state(state, HCA_NO_FM);
380 HERMON_ATTACH_MSG(state->hs_attach_buf,
381 "Hermon FM capability fails");
382 return;
385 /* Initialize the HCA FM resources */
386 hermon_hca_fm_init(state, &hca_fm);
388 /* Initialize the fm state lock */
389 mutex_init(&state->hs_fm_lock, NULL, MUTEX_DRIVER, NULL);
391 /* Register the capabilities with the IO fault services */
392 ddi_fm_init(state->hs_dip, &state->hs_fm_capabilities, &iblk);
394 /* Set up the pci ereport capabilities if the ereport is capable */
395 if (DDI_FM_EREPORT_CAP(state->hs_fm_capabilities)) {
396 pci_ereport_setup(state->hs_dip);
399 /* Set the Hermon FM state */
400 hermon_set_state(state, HCA_PIO_FM | HCA_EREPORT_FM);
402 #ifdef FMA_TEST
403 i_hca_test_init(&state->hs_fm_test_hash, &state->hs_fm_id_hash);
404 #endif /* FMA_TEST */
409 * void
410 * hermon_fm_fini(hermon_state_t *state)
412 * Overview
413 * hermon_fm_fini() is a Hermon FM finalization function which de-registers
414 * Solaris FMA functions set to Hermon.
416 * Argument
417 * state: pointer to Hermon state structure
419 * Return value
420 * Nothing
422 * Caller's context
423 * hermon_fm_fini() can be called in user or kernel context only.
425 void
426 hermon_fm_fini(hermon_state_t *state)
429 * If hermon_fm_diable is set or there is no FM service provided,
430 * then skip the rest.
432 if (state->hs_fm_disable || hermon_get_state(state) == HCA_NO_FM) {
433 return;
436 ASSERT(!(hermon_get_state(state) & HCA_ERRCB_FM));
438 #ifdef FMA_TEST
439 i_hca_test_fini(&state->hs_fm_test_hash, &state->hs_fm_id_hash);
440 #endif /* FMA_TEST */
442 /* Set the Hermon FM state to no support */
443 hermon_set_state(state, HCA_NO_FM);
445 /* Release HCA FM resources */
446 hermon_hca_fm_fini(state);
449 * Release any resources allocated by pci_ereport_setup()
451 if (DDI_FM_EREPORT_CAP(state->hs_fm_capabilities)) {
452 pci_ereport_teardown(state->hs_dip);
455 /* De-register the Hermon FM from the IO fault services */
456 ddi_fm_fini(state->hs_dip);
461 * int
462 * hermon_fm_ereport_init(hermon_state_t *state)
464 * Overview
465 * hermon_fm_ereport_init() changes the Hermon FM state to the ereport
466 * only mode during the driver attach.
468 * Argument
469 * state: pointer to Hermon state structure
471 * Return value
472 * DDI_SUCCESS
473 * DDI_FAILURE
475 * Caller's context
476 * hermon_fm_ereport_init() can be called in user or kernel context only.
479 hermon_fm_ereport_init(hermon_state_t *state)
481 ddi_iblock_cookie_t iblk;
482 hermon_cfg_profile_t *cfgprof;
483 hermon_hw_querydevlim_t *devlim;
484 hermon_rsrc_hw_entry_info_t entry_info;
485 hermon_rsrc_pool_info_t *rsrc_pool;
486 uint64_t offset, num, max, num_prealloc;
487 ddi_device_acc_attr_t dev_attr = {
488 DDI_DEVICE_ATTR_V0,
489 DDI_STRUCTURE_LE_ACC,
490 DDI_STRICTORDER_ACC,
491 DDI_DEFAULT_ACC
493 char *rsrc_name;
494 extern void membar_sync(void);
496 /* Stop the poll thread while the FM state is being changed */
497 state->hs_fm_poll_suspend = B_TRUE;
498 membar_sync();
501 * Disable the Hermon interrupt after the interrupt capability flag
502 * is checked.
504 if (state->hs_intrmsi_cap & DDI_INTR_FLAG_BLOCK) {
505 if (ddi_intr_block_disable
506 (&state->hs_intrmsi_hdl[0], 1) != DDI_SUCCESS) {
507 return (DDI_FAILURE);
509 } else {
510 if (ddi_intr_disable
511 (state->hs_intrmsi_hdl[0]) != DDI_SUCCESS) {
512 return (DDI_FAILURE);
517 * Release any resources allocated by pci_ereport_setup()
519 if (DDI_FM_EREPORT_CAP(state->hs_fm_capabilities)) {
520 pci_ereport_teardown(state->hs_dip);
523 /* De-register the Hermon FM from the IO fault services */
524 ddi_fm_fini(state->hs_dip);
526 /* Re-initialize fm ereport with the ereport only */
527 state->hs_fm_capabilities = ddi_prop_get_int(DDI_DEV_T_ANY,
528 state->hs_dip, DDI_PROP_DONTPASS, fm_cap,
529 DDI_FM_EREPORT_CAPABLE);
532 * Now that the Hermon FM uses the ereport capability only,
533 * If it's not set, turn hs_fm_disable on and behave in the
534 * same way as the "fm_diable" property is set.
536 if (state->hs_fm_capabilities != DDI_FM_EREPORT_CAPABLE) {
537 HERMON_ATTACH_MSG(state->hs_attach_buf,
538 "Hermon FM ereport fails (ereport mode)");
539 goto error;
542 /* Re-register the ereport capability with the IO fault services */
543 ddi_fm_init(state->hs_dip, &state->hs_fm_capabilities, &iblk);
545 /* Initialize the pci ereport capabilities if the ereport is capable */
546 if (DDI_FM_EREPORT_CAP(state->hs_fm_capabilities)) {
547 pci_ereport_setup(state->hs_dip);
550 /* Setup for PCI config read/write of HCA device */
551 if (pci_config_setup(state->hs_dip, &state->hs_reg_pcihdl) !=
552 DDI_SUCCESS) {
553 HERMON_ATTACH_MSG(state->hs_attach_buf,
554 "PCI config mapping fails (ereport mode)");
555 goto error;
558 /* Allocate the regular access handle for MSI-X tables */
559 if (ddi_regs_map_setup(state->hs_dip, state->hs_msix_tbl_rnumber,
560 (caddr_t *)&state->hs_msix_tbl_addr, state->hs_msix_tbl_offset,
561 state->hs_msix_tbl_size, &dev_attr,
562 &state->hs_reg_msix_tblhdl) != DDI_SUCCESS) {
563 HERMON_ATTACH_MSG(state->hs_attach_buf,
564 "MSI-X Table mapping fails (ereport mode)");
565 goto error;
568 /* Allocate the regular access handle for MSI-X PBA */
569 if (ddi_regs_map_setup(state->hs_dip, state->hs_msix_pba_rnumber,
570 (caddr_t *)&state->hs_msix_pba_addr, state->hs_msix_pba_offset,
571 state->hs_msix_pba_size, &dev_attr,
572 &state->hs_reg_msix_pbahdl) != DDI_SUCCESS) {
573 HERMON_ATTACH_MSG(state->hs_attach_buf,
574 "MSI-X PBA mapping fails (ereport mode)");
575 goto error;
578 /* Allocate the regular access handle for Hermon CMD I/O space */
579 if (ddi_regs_map_setup(state->hs_dip, HERMON_CMD_BAR,
580 &state->hs_reg_cmd_baseaddr, 0, 0, &state->hs_reg_accattr,
581 &state->hs_reg_cmdhdl) != DDI_SUCCESS) {
582 HERMON_ATTACH_MSG(state->hs_attach_buf,
583 "CMD_BAR mapping fails (ereport mode)");
584 goto error;
587 /* Reset the host command register */
588 state->hs_cmd_regs.hcr = (hermon_hw_hcr_t *)
589 ((uintptr_t)state->hs_reg_cmd_baseaddr + HERMON_CMD_HCR_OFFSET);
591 /* Reset the software reset register */
592 state->hs_cmd_regs.sw_reset = (uint32_t *)
593 ((uintptr_t)state->hs_reg_cmd_baseaddr +
594 HERMON_CMD_SW_RESET_OFFSET);
596 /* Reset the software reset register semaphore */
597 state->hs_cmd_regs.sw_semaphore = (uint32_t *)
598 ((uintptr_t)state->hs_reg_cmd_baseaddr +
599 HERMON_CMD_SW_SEMAPHORE_OFFSET);
601 /* Calculate the clear interrupt register offset */
602 offset = state->hs_fw.clr_intr_offs & HERMON_CMD_OFFSET_MASK;
604 /* Reset the clear interrupt address */
605 state->hs_cmd_regs.clr_intr = (uint64_t *)
606 (uintptr_t)(state->hs_reg_cmd_baseaddr + offset);
608 /* Reset the internal error buffer address */
609 state->hs_cmd_regs.fw_err_buf = (uint32_t *)(uintptr_t)
610 (state->hs_reg_cmd_baseaddr + state->hs_fw.error_buf_addr);
612 /* Check if the blue flame is enabled, and set the offset value */
613 if (state->hs_devlim.blu_flm) {
614 offset = (uint64_t)1 <<
615 (state->hs_devlim.log_max_uar_sz + 20);
616 } else {
617 offset = 0;
620 /* Allocate the regular access handle for Hermon UAR I/O space */
621 if (ddi_regs_map_setup(state->hs_dip, HERMON_UAR_BAR,
622 &state->hs_reg_uar_baseaddr, 0, offset,
623 &state->hs_reg_accattr, &state->hs_reg_uarhdl) != DDI_SUCCESS) {
624 HERMON_ATTACH_MSG(state->hs_attach_buf,
625 "UAR BAR mapping fails (ereport mode)");
626 goto error;
629 hermon_eq_reset_uar_baseaddr(state);
631 /* Drop the Hermon FM Attach Mode */
632 hermon_clr_state(state, HCA_ATTCH_FM);
634 /* Set the Hermon FM Runtime Mode */
635 hermon_set_state(state, HCA_RUNTM_FM);
637 /* Free up Hermon UAR page #1 */
638 hermon_rsrc_free(state, &state->hs_uarkpg_rsrc);
640 /* Free up the UAR pool */
641 entry_info.hwi_rsrcpool = &state->hs_rsrc_hdl[HERMON_UARPG];
642 hermon_rsrc_hw_entries_fini(state, &entry_info);
644 /* Re-allocate the UAR pool */
645 cfgprof = state->hs_cfg_profile;
646 devlim = &state->hs_devlim;
647 num = ((uint64_t)1 << cfgprof->cp_log_num_uar);
648 max = num;
649 num_prealloc = max(devlim->num_rsvd_uar, 128);
650 rsrc_pool = &state->hs_rsrc_hdl[HERMON_UARPG];
651 rsrc_pool->rsrc_type = HERMON_UARPG;
652 rsrc_pool->rsrc_loc = HERMON_IN_UAR;
653 rsrc_pool->rsrc_pool_size = (num << PAGESHIFT);
654 rsrc_pool->rsrc_shift = PAGESHIFT;
655 rsrc_pool->rsrc_quantum = (uint_t)PAGESIZE;
656 rsrc_pool->rsrc_align = PAGESIZE;
657 rsrc_pool->rsrc_state = state;
658 rsrc_pool->rsrc_start = (void *)state->hs_reg_uar_baseaddr;
659 rsrc_name = kmem_zalloc(HERMON_RSRC_NAME_MAXLEN, KM_SLEEP);
660 HERMON_RSRC_NAME(rsrc_name, HERMON_UAR_PAGE_VMEM_RUNTM);
661 entry_info.hwi_num = num;
662 entry_info.hwi_max = max;
663 entry_info.hwi_prealloc = num_prealloc;
664 entry_info.hwi_rsrcpool = rsrc_pool;
665 entry_info.hwi_rsrcname = rsrc_name;
666 if (hermon_rsrc_hw_entries_init(state, &entry_info) != DDI_SUCCESS) {
667 kmem_free(rsrc_name, HERMON_RSRC_NAME_MAXLEN);
668 goto error;
670 kmem_free(rsrc_name, HERMON_RSRC_NAME_MAXLEN);
672 /* Re-allocate the kernel UAR page */
673 if (hermon_rsrc_alloc(state, HERMON_UARPG, 1, HERMON_SLEEP,
674 &state->hs_uarkpg_rsrc) != DDI_SUCCESS) {
675 goto error;
678 /* Setup pointer to kernel UAR page */
679 state->hs_uar = (hermon_hw_uar_t *)state->hs_uarkpg_rsrc->hr_addr;
681 /* Now drop the the Hermon PIO FM */
682 hermon_clr_state(state, HCA_PIO_FM);
684 /* Release the MSI-X Table access handle */
685 if (state->hs_fm_msix_tblhdl) {
686 hermon_regs_map_free(state, &state->hs_fm_msix_tblhdl);
687 state->hs_fm_msix_tblhdl = NULL;
690 /* Release the MSI-X PBA access handle */
691 if (state->hs_fm_msix_pbahdl) {
692 hermon_regs_map_free(state, &state->hs_fm_msix_pbahdl);
693 state->hs_fm_msix_pbahdl = NULL;
696 /* Release the pci config space access handle */
697 if (state->hs_fm_pcihdl) {
698 hermon_regs_map_free(state, &state->hs_fm_pcihdl);
699 state->hs_fm_pcihdl = NULL;
702 /* Release the cmd protected access handle */
703 if (state->hs_fm_cmdhdl) {
704 hermon_regs_map_free(state, &state->hs_fm_cmdhdl);
705 state->hs_fm_cmdhdl = NULL;
708 /* Release the uar fma-protected access handle */
709 if (state->hs_fm_uarhdl) {
710 hermon_regs_map_free(state, &state->hs_fm_uarhdl);
711 state->hs_fm_uarhdl = NULL;
714 /* Enable the Hermon interrupt again */
715 if (state->hs_intrmsi_cap & DDI_INTR_FLAG_BLOCK) {
716 if (ddi_intr_block_enable
717 (&state->hs_intrmsi_hdl[0], 1) != DDI_SUCCESS) {
718 return (DDI_FAILURE);
720 } else {
721 if (ddi_intr_enable
722 (state->hs_intrmsi_hdl[0]) != DDI_SUCCESS) {
723 return (DDI_FAILURE);
727 /* Restart the poll thread */
728 state->hs_fm_poll_suspend = B_FALSE;
730 return (DDI_SUCCESS);
732 error:
733 /* Enable the Hermon interrupt again */
734 if (state->hs_intrmsi_cap & DDI_INTR_FLAG_BLOCK) {
735 (void) ddi_intr_block_enable(&state->hs_intrmsi_hdl[0], 1);
736 } else {
737 (void) ddi_intr_enable(state->hs_intrmsi_hdl[0]);
739 return (DDI_FAILURE);
744 * int
745 * hermon_regs_map_setup(hermon_state_t *state, uint_t rnumber, caddr_t *addrp,
746 * offset_t offset, offset_t len, ddi_device_acc_attr_t *accattrp,
747 * ddi_acc_handle_t *handle)
749 * Overview
750 * This is a wrapper function of i_hca_regs_map_setup() for Hermon FM so
751 * that it calls i_hca_regs_map_setup() inside after it checks the
752 * "fm_disable" configuration property. If the "fm_disable" is described
753 * in /kernel/drv/hermon.conf, the function calls ddi_regs_map_setup()
754 * directly instead.
755 * See i_hca_regs_map_setup() in detail.
757 * Argument
758 * state: pointer to Hermon state structure
759 * rnumber: index number to the register address space set
760 * addrp: platform-dependent value (same as ddi_regs_map_setup())
761 * offset: offset into the register address space
762 * len: address space length to be mapped
763 * accattrp: pointer to device access attribute structure
764 * handle: pointer to ddi_acc_handle_t used for HCA FM
766 * Return value
767 * ddi function status value which are:
768 * DDI_SUCCESS
769 * DDI_FAILURE
770 * DDI_ME_RNUMBER_RNGE
771 * DDI_REGS_ACC_CONFLICT
773 * Caller's context
774 * hermon_regs_map_setup() can be called in user or kernel context only.
777 hermon_regs_map_setup(hermon_state_t *state, uint_t rnumber, caddr_t *addrp,
778 offset_t offset, offset_t len, ddi_device_acc_attr_t *accattrp,
779 ddi_acc_handle_t *handle)
781 if (state->hs_fm_disable) {
782 return (ddi_regs_map_setup(state->hs_dip, rnumber, addrp,
783 offset, len, accattrp, handle));
784 } else {
785 return (i_hca_regs_map_setup(state->hs_fm_hca_fm, state->hs_dip,
786 rnumber, addrp, offset, len, accattrp, handle));
792 * void
793 * hermon_regs_map_free(hermon_state_t *state, ddi_acc_handle_t *handlep)
795 * Overview
796 * This is a wrapper function of i_hca_regs_map_free() for Hermon FM so
797 * that it calls i_hca_regs_map_free() inside after it checks the
798 * "fm_disable" configuration property. If the "fm_disable" is described
799 * in /kernel/drv/hermon.conf, the function calls ddi_regs_map_fre()
800 * directly instead. See i_hca_regs_map_free() in detail.
802 * Argument
803 * state: pointer to Hermon state structure
804 * handle: pointer to ddi_acc_handle_t used for HCA FM
806 * Return value
807 * Nothing
809 * Caller's context
810 * hermon_regs_map_free() can be called in user or kernel context only.
812 * Note that the handle passed to hermon_regs_map_free() is NULL-cleared
813 * after this function is called.
815 void
816 hermon_regs_map_free(hermon_state_t *state, ddi_acc_handle_t *handle)
818 if (state->hs_fm_disable) {
819 ddi_regs_map_free(handle);
820 *handle = NULL;
821 } else {
822 i_hca_regs_map_free(state->hs_fm_hca_fm, handle);
828 * int
829 * hermon_pci_config_setup(hermon_state_t *state, ddi_acc_handle_t *handle)
831 * Overview
832 * This is a wrapper function of i_hca_pci_config_setup() for Hermon FM so
833 * that it calls i_hca_pci_config_setup() inside after it checks the
834 * "fm-disable" configuration property. If the "fm_disable" is described
835 * in /kernel/drv/hermon.conf, the function calls pci_config_setup()
836 * directly instead. See i_hca_pci_config_setup() in detail.
838 * Argument
839 * state: pointer to Hermon state structure
840 * handle: pointer to ddi_acc_handle_t used for HCA FM
842 * Return value
843 * ddi function status value which are:
844 * DDI_SUCCESS
845 * DDI_FAILURE
847 * Caller's context
848 * hermon_pci_config_setup() can be called in user or kernel context only.
851 hermon_pci_config_setup(hermon_state_t *state, ddi_acc_handle_t *handle)
853 if (state->hs_fm_disable) {
854 return (pci_config_setup(state->hs_dip, handle));
855 } else {
856 /* Check Hermon FM and Solaris FMA capability flags */
857 ASSERT((hermon_get_state(state) & HCA_PIO_FM &&
858 DDI_FM_ACC_ERR_CAP(ddi_fm_capable(state->hs_dip))) ||
859 (!(hermon_get_state(state) & HCA_PIO_FM) &&
860 !DDI_FM_ACC_ERR_CAP(ddi_fm_capable(state->hs_dip))));
861 return (i_hca_pci_config_setup(state->hs_fm_hca_fm,
862 state->hs_dip, handle));
868 * void
869 * hermon_pci_config_teardown(hermon_state_t *state, ddi_acc_handle_t *handle)
871 * Overview
872 * This is a wrapper function of i_hca_pci_config_teardown() for Hermon
873 * FM so that it calls i_hca_pci_config_teardown() inside after it checks
874 * the "fm-disable" configuration property. If the "fm_disable" is
875 * described in /kernel/drv/hermon.conf, the function calls
876 * pci_config_teardown() directly instead.
877 * See i_hca_pci_config_teardown() in detail.
879 * Argument
880 * state: pointer to Hermon state structure
881 * handle: pointer to ddi_acc_handle_t used for HCA FM
883 * Return value
884 * Nothing
886 * Caller's context
887 * hermon_pci_config_teardown() can be called in user or kernel context
888 * only.
890 void
891 hermon_pci_config_teardown(hermon_state_t *state, ddi_acc_handle_t *handle)
893 if (state->hs_fm_disable) {
894 pci_config_teardown(handle);
895 *handle = NULL;
896 } else {
897 i_hca_pci_config_teardown(state->hs_fm_hca_fm, handle);
903 * boolean_t
904 * hermon_init_failure(hermon_state_t *state)
906 * Overview
907 * hermon_init_failure() tells if HW errors are detected in
908 * the Hermon driver attach.
910 * Argument
911 * state: pointer to Hermon state structure
913 * Return value
914 * B_TRUE HW errors detected during attach
915 * B_FALSE No HW errors during attach
917 * Caller's context
918 * hermon_init_failure() can be called in user, kernel, interrupt
919 * context or high interrupt context.
921 boolean_t
922 hermon_init_failure(hermon_state_t *state)
924 ddi_acc_handle_t hdl;
925 ddi_fm_error_t derr;
927 if (!(hermon_get_state(state) & HCA_PIO_FM))
928 return (B_FALSE);
930 /* check if fatal errors occur during attach */
931 if (state->hs_fm_async_fatal)
932 return (B_TRUE);
934 hdl = hermon_get_uarhdl(state);
935 /* Get the PIO error against UAR I/O space */
936 ddi_fm_acc_err_get(hdl, &derr, DDI_FME_VERSION);
937 if (derr.fme_status != DDI_FM_OK) {
938 return (B_TRUE);
941 hdl = hermon_get_cmdhdl(state);
942 /* Get the PIO error againsts CMD I/O space */
943 ddi_fm_acc_err_get(hdl, &derr, DDI_FME_VERSION);
944 if (derr.fme_status != DDI_FM_OK) {
945 return (B_TRUE);
948 return (B_FALSE);
953 * void
954 * hermon_fm_ereport(hermon_state_t *state, int type, int detail)
956 * Overview
957 * hermon_fm_ereport() is a Hermon FM ereport function used
958 * to issue a Solaris FMA ereport. See Hermon FM comments at the
959 * beginning of this file in detail.
961 * Argument
962 * state: pointer to Hermon state structure
963 * type: error type
964 * HCA_SYS_ERR FMA reporting HW error
965 * HCA_IBA_ERR HCA specific HW error
966 * detail: HW error hint implying which ereport is issued
967 * HCA_ERR_TRANSIENT HW transienet error
968 * HCA_ERR_NON_FATAL HW persistent error
969 * HCA_ERR_FATAL HW fatal error
970 * HCA_ERR_SRV_LOST IB service lost due to HW error
971 * HCA_ERR_DEGRADED Hermon driver and/or uDAPL degraded
972 * due to HW error
973 * HCA_ERR_IOCTL HW error detected in user conetxt
974 * (especially in ioctl())
976 * Return value
977 * Nothing
979 * Caller's context
980 * hermon_fm_ereport() can be called in user, kernel, interrupt context
981 * or high interrupt context.
983 void
984 hermon_fm_ereport(hermon_state_t *state, int type, int detail)
987 * If hermon_fm_diable is set or there is no FM ereport service
988 * provided, then skip the rest.
990 if (state->hs_fm_disable ||
991 !(hermon_get_state(state) & HCA_EREPORT_FM)) {
992 return;
995 switch (type) {
997 case HCA_SYS_ERR:
998 switch (detail) {
999 case HCA_ERR_TRANSIENT:
1000 case HCA_ERR_IOCTL:
1001 ddi_fm_service_impact(state->hs_dip,
1002 DDI_SERVICE_UNAFFECTED);
1003 break;
1004 case HCA_ERR_NON_FATAL:
1005 /* Nothing */
1006 break;
1007 case HCA_ERR_SRV_LOST:
1008 ddi_fm_service_impact(state->hs_dip,
1009 DDI_SERVICE_LOST);
1010 break;
1011 case HCA_ERR_DEGRADED:
1012 switch (state->hs_fm_degraded_reason) {
1013 case HCA_FW_CORRUPT:
1014 i_hca_fm_ereport(state->hs_dip, type,
1015 DDI_FM_DEVICE_FW_CORRUPT);
1016 break;
1017 case HCA_FW_MISMATCH:
1018 i_hca_fm_ereport(state->hs_dip, type,
1019 DDI_FM_DEVICE_FW_MISMATCH);
1020 break;
1021 case HCA_FW_MISC:
1022 default:
1023 i_hca_fm_ereport(state->hs_dip, type,
1024 DDI_FM_DEVICE_INTERN_UNCORR);
1025 break;
1027 ddi_fm_service_impact(state->hs_dip,
1028 DDI_SERVICE_DEGRADED);
1029 break;
1030 case HCA_ERR_FATAL:
1031 ddi_fm_service_impact(state->hs_dip,
1032 DDI_SERVICE_LOST);
1033 state->hs_fm_async_fatal = B_TRUE;
1034 break;
1035 default:
1036 cmn_err(CE_WARN, "hermon_fm_ereport: Unknown error. "
1037 "type = %d, detail = %d\n.", type, detail);
1039 break;
1041 case HCA_IBA_ERR:
1042 switch (detail) {
1043 case HCA_ERR_TRANSIENT:
1044 i_hca_fm_ereport(state->hs_dip, type,
1045 DDI_FM_DEVICE_INTERN_UNCORR);
1046 ddi_fm_service_impact(state->hs_dip,
1047 DDI_SERVICE_UNAFFECTED);
1048 break;
1049 case HCA_ERR_SRV_LOST:
1050 cmn_err(CE_WARN, "hermon_fm_ereport: not supported "
1051 "error. type = %d, detail = %d\n.", type, detail);
1052 break;
1053 case HCA_ERR_DEGRADED:
1054 switch (state->hs_fm_degraded_reason) {
1055 case HCA_FW_CORRUPT:
1056 i_hca_fm_ereport(state->hs_dip, type,
1057 DDI_FM_DEVICE_FW_CORRUPT);
1058 break;
1059 case HCA_FW_MISMATCH:
1060 i_hca_fm_ereport(state->hs_dip, type,
1061 DDI_FM_DEVICE_FW_MISMATCH);
1062 break;
1063 case HCA_FW_MISC:
1064 default:
1065 i_hca_fm_ereport(state->hs_dip, type,
1066 DDI_FM_DEVICE_INTERN_UNCORR);
1067 break;
1069 ddi_fm_service_impact(state->hs_dip,
1070 DDI_SERVICE_DEGRADED);
1071 break;
1072 case HCA_ERR_IOCTL:
1073 case HCA_ERR_NON_FATAL:
1074 i_hca_fm_ereport(state->hs_dip, type,
1075 DDI_FM_DEVICE_INTERN_UNCORR);
1076 ddi_fm_service_impact(state->hs_dip,
1077 DDI_SERVICE_UNAFFECTED);
1078 break;
1079 case HCA_ERR_FATAL:
1080 if (hermon_get_state(state) & HCA_PIO_FM) {
1081 if (servicing_interrupt()) {
1082 atomic_inc_32(&state->
1083 hs_fm_async_errcnt);
1084 } else {
1085 i_hca_fm_ereport(state->hs_dip, type,
1086 DDI_FM_DEVICE_INTERN_UNCORR);
1087 ddi_fm_service_impact(state->hs_dip,
1088 DDI_SERVICE_LOST);
1090 state->hs_fm_async_fatal = B_TRUE;
1091 } else {
1092 i_hca_fm_ereport(state->hs_dip, type,
1093 DDI_FM_DEVICE_INTERN_UNCORR);
1094 ddi_fm_service_impact(state->hs_dip,
1095 DDI_SERVICE_LOST);
1096 cmn_err(CE_PANIC,
1097 "Hermon Fatal Internal Error. "
1098 "Hermon state=0x%p", (void *)state);
1100 break;
1101 default:
1102 cmn_err(CE_WARN, "hermon_fm_ereport: Unknown error. "
1103 "type = %d, detail = %d\n.", type, detail);
1105 break;
1107 default:
1108 cmn_err(CE_WARN, "hermon_fm_ereport: Unknown type "
1109 "type = %d, detail = %d\n.", type, detail);
1110 break;
1116 * uchar_t
1117 * hermon_devacc_attr_version(hermon_state_t *)
1119 * Overview
1120 * hermon_devacc_attr_version() returns the ddi device attribute
1121 * version.
1123 * Argument
1124 * state: pointer to Hermon state structure
1126 * Return value
1127 * dev_acc_attr_version value
1128 * DDI_DEVICE_ATTR_V0 Hermon FM disabled
1129 * DDI_DEVICE_ATTR_V1 Hermon FM enabled
1131 * Caller's context
1132 * hermon_devacc_attr_version() can be called in user, kernel, interrupt
1133 * context or high interrupt context.
1135 ushort_t
1136 hermon_devacc_attr_version(hermon_state_t *state)
1138 if (state->hs_fm_disable) {
1139 return (DDI_DEVICE_ATTR_V0);
1140 } else {
1141 return (DDI_DEVICE_ATTR_V1);
1147 * uchar_t
1148 * hermon_devacc_attr_access(hermon_state_t *)
1150 * Overview
1151 * hermon_devacc_attr_access() returns devacc_attr_access error
1152 * protection types.
1154 * Argument
1155 * state: pointer to Hermon state structure
1157 * Return value
1158 * dev_acc_attr_access error protection type
1159 * DDI_DEFAULT_ACC Hermon FM disabled for PIO
1160 * DDI_FLAGERR_ACC Hermon FM enabled for PIO
1162 * Caller's context
1163 * hermon_devacc_attr_access() can be called in user, kernel, interrupt
1164 * context or high interrupt context.
1166 uchar_t
1167 hermon_devacc_attr_access(hermon_state_t *state)
1169 if (state->hs_fm_disable) {
1170 return (DDI_DEFAULT_ACC);
1171 } else {
1172 return (DDI_FLAGERR_ACC);
1178 * int
1179 * hermon_PIO_start(hermon_state_t *state, ddi_acc_handle_t handle,
1180 * hermon_test_t *tst)
1182 * Overview
1183 * hermon_PIO_start() should be called before Hermon driver issues PIOs
1184 * against I/O space. If Hermon FM is disabled, this function returns
1185 * HCA_PIO_OK always. See i_hca_pio_start() in detail.
1187 * Argument
1188 * state: pointer to Hermon state structure
1189 * handle: pointer to ddi_acc_handle_t used for HCA FM
1190 * tst: pointer to HCA FM function test structure. If the structure
1191 * is not used, the NULL value must be passed instead.
1193 * Return value
1194 * error status showing whether or not this error can retry
1195 * HCA_PIO_OK No HW errors
1196 * HCA_PIO_TRANSIENT This error could be transient
1197 * HCA_PIO_PERSISTENT This error is persistent
1199 * Caller's context
1200 * hermon_PIO_start() can be called in user, kernel or interrupt context.
1203 hermon_PIO_start(hermon_state_t *state, ddi_acc_handle_t handle,
1204 hermon_test_t *tst)
1206 if (state->hs_fm_disable) {
1207 return (HCA_PIO_OK);
1208 } else {
1209 struct i_hca_acc_handle *handlep =
1210 i_hca_get_acc_handle(state->hs_fm_hca_fm, handle);
1211 ASSERT(handlep != NULL);
1212 return (i_hca_pio_start(state->hs_dip, handlep, tst));
1218 * int
1219 * hermon_PIO_end(hermon_state_t *state, ddi_acc_handle_t handle, int *cnt,
1220 * hermon_test_t *tst)
1222 * Overview
1223 * hermon_PIO_end() should be called after Hermon driver issues PIOs
1224 * against I/O space. If Hermon FM is disabled, this function returns
1225 * HCA_PIO_OK always. See i_hca_pio_end() in detail.
1227 * Argument
1228 * state: pointer to Hermon state structure
1229 * handle: pointer to ddi_acc_handle_t used for HCA FM
1230 * cnt: pointer to the counter variable which holds the nubmer of retry
1231 * (HCA_PIO_RETRY_CNT) when a HW error is detected.
1232 * tst: pointer to HCA FM function test structure. If the structure
1233 * is not used, the NULL value must be passed instead.
1235 * Return value
1236 * error status showing whether or not this error can retry
1237 * HCA_PIO_OK No HW errors
1238 * HCA_PIO_TRANSIENT This error could be transient
1239 * HCA_PIO_PERSISTENT This error is persistent
1241 * Caller's context
1242 * hermon_PIO_end() can be called in user, kernel or interrupt context.
1245 hermon_PIO_end(hermon_state_t *state, ddi_acc_handle_t handle, int *cnt,
1246 hermon_test_t *tst)
1248 if (state->hs_fm_disable) {
1249 return (HCA_PIO_OK);
1250 } else {
1251 struct i_hca_acc_handle *handlep =
1252 i_hca_get_acc_handle(state->hs_fm_hca_fm, handle);
1253 ASSERT(handlep != NULL);
1254 return (i_hca_pio_end(state->hs_dip, handlep, cnt, tst));
1260 * ddi_acc_handle_t
1261 * hermon_get_cmdhdl(hermon_state_t *state)
1263 * Overview
1264 * hermon_get_cmdhdl() returns either the fma-protected access handle or
1265 * the regular ddi-access handle depending on the Hermon FM state for
1266 * Hermon command I/O space.
1268 * Argument
1269 * state: pointer to Hermon state structure
1271 * Return value
1272 * the access handle for pio requests
1274 * Caller's context
1275 * hermon_get_cmdhdl() can be called in user, kernel, interrupt context
1276 * or high interrupt context.
1278 ddi_acc_handle_t
1279 hermon_get_cmdhdl(hermon_state_t *state)
1281 return (state->hs_fm_disable || hermon_get_state(state) & HCA_PIO_FM ?
1282 state->hs_fm_cmdhdl : state->hs_reg_cmdhdl);
1287 * ddi_acc_handle_t
1288 * hermon_get_uarhdl(hermon_state_t *state)
1290 * Overview
1291 * hermon_get_uarhdl() returns either the fma-protected access handle or
1292 * the regular ddi-access handle depending on the Hermon FM state for
1293 * Hermon UAR I/O space.
1295 * Argument
1296 * state: pointer to Hermon state structure
1298 * Return value
1299 * the access handle for pio requests
1301 * Caller's context
1302 * hermon_get_uarhdl() can be called in user, kernel, interrupt context
1303 * or high interrupt context.
1305 ddi_acc_handle_t
1306 hermon_get_uarhdl(hermon_state_t *state)
1308 return (state->hs_fm_disable || hermon_get_state(state) & HCA_PIO_FM ?
1309 state->hs_fm_uarhdl : state->hs_reg_uarhdl);
1314 * ddi_acc_handle_t
1315 * hermon_rsrc_alloc_uarhdl(hermon_state_t *state)
1317 * Overview
1318 * hermon_rsrc_alloc_uarhdl() returns either the fma-protected access
1319 * handle or the regular ddi-access handle depending on the Hermon FM
1320 * state for Hermon UAR I/O space as well as hermon_get_uarhdl(), but
1321 * this function is dedicated to the UAR resource allocator.
1323 * Argument
1324 * state: pointer to Hermon state structure
1326 * Return value
1327 * the access handle for pio requests
1329 * Caller's context
1330 * hermon_rsrc_alloc_uarhdl() can be called in user, kernel, interrupt
1331 * or high interrupt context.
1333 ddi_acc_handle_t
1334 hermon_rsrc_alloc_uarhdl(hermon_state_t *state)
1336 return (state->hs_fm_disable || hermon_get_state(state) & HCA_ATTCH_FM ?
1337 state->hs_fm_uarhdl : state->hs_reg_uarhdl);
1341 * ddi_acc_handle_t
1342 * hermon_get_pcihdl(hermon_state_t *state)
1344 * Overview
1345 * hermon_get_pcihdl() returns either the fma-protected access
1346 * handle or the regular ddi-access handle to access the PCI config
1347 * space. Whether or not which handle is returned at the moment depends
1348 * on the Hermon FM state.
1350 * Argument
1351 * state: pointer to Hermon state structure
1353 * Return value
1354 * the access handle to PCI config space
1356 * Caller's context
1357 * hermon_get_pcihdl() can be called in user, kernel, interrupt
1358 * or high interrupt context.
1360 ddi_acc_handle_t
1361 hermon_get_pcihdl(hermon_state_t *state)
1363 return (state->hs_fm_disable || hermon_get_state(state) & HCA_ATTCH_FM ?
1364 state->hs_fm_pcihdl : state->hs_reg_pcihdl);
1369 * ddi_acc_handle_t
1370 * hermon_get_msix_tblhdl(hermon_state_t *state)
1372 * Overview
1373 * hermon_get_msix_tblhdl() returns either the fma-protected access
1374 * handle or the regular ddi-access handle to access the MSI-X tables.
1375 * Whether or not which handle is returned at the moment depends on
1376 * the Hermon FM state.
1378 * Argument
1379 * state: pointer to Hermon state structure
1381 * Return value
1382 * the access handle to MSI-X tables
1384 * Caller's context
1385 * hermon_get_msix_tblhdl() can be called in user, kernel, interrupt
1386 * context or high interrupt context.
1388 ddi_acc_handle_t
1389 hermon_get_msix_tblhdl(hermon_state_t *state)
1391 return (state->hs_fm_disable || hermon_get_state(state) & HCA_ATTCH_FM ?
1392 state->hs_fm_msix_tblhdl : state->hs_reg_msix_tblhdl);
1397 * ddi_acc_handle_t
1398 * hermon_get_msix_pbahdl(hermon_state_t *state)
1400 * Overview
1401 * hermon_get_msix_pbahdl() returns either the fma-protected access
1402 * handle or the regular ddi-access handle to access the MSI-X PBA.
1403 * Whether or not which handle is returned at the moment depends on
1404 * the Hermon FM state.
1406 * Argument
1407 * state: pointer to Hermon state structure
1409 * Return value
1410 * the access handle to MSI-X PBA
1412 * Caller's context
1413 * hermon_get_msix_pbahdl() can be called in user, kernel, interrupt
1414 * context or high interrupt context.
1416 ddi_acc_handle_t
1417 hermon_get_msix_pbahdl(hermon_state_t *state)
1419 return (state->hs_fm_disable || hermon_get_state(state) & HCA_ATTCH_FM ?
1420 state->hs_fm_msix_pbahdl : state->hs_reg_msix_pbahdl);
1425 * void
1426 * hermon_inter_err_chk(void *arg)
1428 * Overview
1429 * hermon_inter_err_chk() periodically checks the internal error buffer
1430 * to pick up a Hermon asynchronous internal error.
1432 * Note that this internal error can be notified if the interrupt is
1433 * registered, but even so there are some cases that an interrupt against
1434 * it cannot be raised so that Hermon RPM recommeds to poll this internal
1435 * error buffer periodically instead. This function is invoked at
1436 * 10ms interval in kernel context though the function itself can be
1437 * called in interrupt context.
1439 * Argument
1440 * arg: pointer to Hermon state structure
1442 * Return value
1443 * Nothing
1445 * Caller's context
1446 * hermon_inter_err_chk() can be called in user, kernel, interrupt
1447 * context or high interrupt context.
1450 void
1451 hermon_inter_err_chk(void *arg)
1453 uint32_t word;
1454 ddi_acc_handle_t cmdhdl;
1455 hermon_state_t *state = (hermon_state_t *)arg;
1457 /* initialize the FMA retry loop */
1458 hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
1460 #ifdef FMA_TEST
1461 if (hermon_test_num != 0) {
1462 return;
1464 #endif
1465 if (state->hs_fm_poll_suspend) {
1466 return;
1469 /* Get the access handle for Hermon CMD I/O space */
1470 cmdhdl = hermon_get_cmdhdl(state);
1472 /* the FMA retry loop starts. */
1473 hermon_pio_start(state, cmdhdl, pio_error, fm_loop_cnt, fm_status,
1474 fm_test);
1476 word = ddi_get32(cmdhdl, state->hs_cmd_regs.fw_err_buf);
1478 /* the FMA retry loop ends. */
1479 hermon_pio_end(state, cmdhdl, pio_error, fm_loop_cnt, fm_status,
1480 fm_test);
1482 if (word != 0) {
1483 HERMON_FMANOTE(state, HERMON_FMA_INTERNAL);
1484 /* if fm_disable is on, Hermon FM functions don't work */
1485 if (state->hs_fm_disable) {
1486 cmn_err(CE_PANIC,
1487 "Hermon Fatal Internal Error. "
1488 "Hermon state=0x%p", (void *)state);
1489 } else {
1490 hermon_fm_ereport(state, HCA_IBA_ERR, HCA_ERR_FATAL);
1494 /* issue the ereport pended in the interrupt context */
1495 if (state->hs_fm_async_errcnt > 0) {
1496 hermon_fm_ereport(state, HCA_IBA_ERR, HCA_ERR_FATAL);
1497 atomic_dec_32(&state->hs_fm_async_errcnt);
1500 return;
1502 pio_error:
1503 hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_FATAL);
1508 * boolean_t
1509 * hermon_cmd_retry_ok(hermon_cmd_post_t *cmd, int status)
1511 * Overview
1512 * In the case that a HW error is detected, if it can be isolated
1513 * enough, Hermon FM retries the operation which caused the error.
1514 * However, this retry can induce another error; since the retry is
1515 * achieved as a block basis, not a statement basis, once the state
1516 * was set inside the Hermon HW already in the previous operation, the
1517 * retry can cause for example, a CMD_BAD_SYS_STATE error, as a result.
1518 * In this case, CMD_BAD_SYS_STATE should be taken as a side effect
1519 * but a harmless result. hermon_cmd_retry_ok() checks this kind of
1520 * situation then returns if the state Hermon CMD returns is OK or not.
1522 * Argument
1523 * cmd: pointer to hermon_cmd_post_t structure
1524 * status: Hermon CMD status
1526 * Return value
1527 * B_TRUE this state is no problem
1528 * B_FALSE this state should be taken as an error
1530 * Caller's context
1531 * hermon_cmd_retry_ok() can be called in user, kernel, interrupt
1532 * context or high interrupt context.
1534 * Note that status except for HERMON_CMD_SUCCESS shouldn't be accepted
1535 * in the debug module to catch a hidden software bug, so that ASSERT()
1536 * is enabled in the case.
1538 boolean_t
1539 hermon_cmd_retry_ok(hermon_cmd_post_t *cmd, int status)
1541 if (status == HERMON_CMD_SUCCESS)
1542 return (B_TRUE);
1545 * The wrong status such as HERMON_CMD_BAD_SYS_STATE or
1546 * HERMON_CMD_BAD_RES_STATE can return as a side effect
1547 * because of the Hermon FM operation retry when a PIO
1548 * error is detected during the I/O transaction. In the
1549 * case, the driver may set the same value in Hermon
1550 * though it was set already, then Hermon returns HERMON_
1551 * CMD_BAD_{RES,SYS}_STATE as a result, which should be
1552 * taken as OK.
1554 switch (cmd->cp_opcode) {
1555 case INIT_HCA:
1557 * HERMON_CMD_BAD_SYS_STATE can be gotten in case of
1558 * ICM not mapped or HCA already initialized.
1560 if (status == HERMON_CMD_BAD_SYS_STATE)
1561 return (B_TRUE);
1562 return (B_FALSE);
1564 case CLOSE_HCA:
1566 * HERMON_CMD_BAD_SYS_STATE can be gotten in case of Firmware
1567 * area is not mapped or HCA already closed.
1569 if (status == HERMON_CMD_BAD_SYS_STATE)
1570 return (B_TRUE);
1571 return (B_FALSE);
1573 case CLOSE_PORT:
1575 * HERMON_CMD_BAD_SYS_STATE can be gotten in case of HCA not
1576 * initialized or in case that IB ports are already down.
1578 if (status == HERMON_CMD_BAD_SYS_STATE)
1579 return (B_TRUE);
1580 return (B_FALSE);
1582 case SW2HW_MPT:
1584 * HERMON_CMD_BAD_RES_STATE can be gotten in case of MPT
1585 * entry already in hardware ownership.
1587 if (status == HERMON_CMD_BAD_RES_STATE)
1588 return (B_TRUE);
1589 return (B_FALSE);
1591 case HW2SW_MPT:
1593 * HERMON_CMD_BAD_RES_STATE can be gotten in case of MPT
1594 * entry already in software ownership.
1596 if (status == HERMON_CMD_BAD_RES_STATE)
1597 return (B_TRUE);
1598 return (B_FALSE);
1600 case SW2HW_EQ:
1602 * HERMON_CMD_BAD_RES_STATE can be gotten in case of EQ
1603 * entry already in hardware ownership.
1605 if (status == HERMON_CMD_BAD_RES_STATE)
1606 return (B_TRUE);
1607 return (B_FALSE);
1609 case HW2SW_EQ:
1611 * HERMON_CMD_BAD_RES_STATE can be gotten in case of EQ
1612 * entry already in software ownership.
1614 if (status == HERMON_CMD_BAD_RES_STATE)
1615 return (B_TRUE);
1616 return (B_FALSE);
1618 case SW2HW_CQ:
1620 * HERMON_CMD_BAD_RES_STATE can be gotten in case of CQ
1621 * entry already in hardware ownership.
1623 if (status == HERMON_CMD_BAD_RES_STATE)
1624 return (B_TRUE);
1625 return (B_FALSE);
1627 case HW2SW_CQ:
1629 * HERMON_CMD_BAD_RES_STATE can be gotten in case of CQ
1630 * entry already in software ownership.
1632 if (status == HERMON_CMD_BAD_RES_STATE)
1633 return (B_TRUE);
1634 return (B_FALSE);
1636 case SW2HW_SRQ:
1638 * HERMON_CMD_BAD_RES_STATE can be gotten in case of SRQ
1639 * entry already in hardware ownership.
1641 if (status == HERMON_CMD_BAD_RES_STATE)
1642 return (B_TRUE);
1643 return (B_FALSE);
1645 case HW2SW_SRQ:
1647 * HERMON_CMD_BAD_RES_STATE can be gotten in case of SRQ
1648 * entry already in software ownership.
1650 if (status == HERMON_CMD_BAD_RES_STATE)
1651 return (B_TRUE);
1652 return (B_FALSE);
1653 default:
1654 break;
1657 /* other cases */
1658 return (B_FALSE);
1662 #ifdef FMA_TEST
1665 * Hermon FMA test variables
1667 #define FMA_TEST_HASHSZ 64
1668 int hermon_test_num; /* predefined testset */
1670 static struct i_hca_fm_test *i_hca_test_register(char *, int, int,
1671 void (*)(struct i_hca_fm_test *, ddi_fm_error_t *),
1672 void *, mod_hash_t *, mod_hash_t *, int);
1673 static void i_hca_test_free_item(mod_hash_val_t);
1674 static void i_hca_test_set_item(int, struct i_hca_fm_test *);
1675 static void hermon_trigger_pio_error(hermon_test_t *, ddi_fm_error_t *);
1678 * Hermon FMA Function Test Interface
1681 /* Attach Errors */
1683 #define ATTACH_TS (HCA_TEST_TRANSIENT | HCA_TEST_ATTACH | HCA_TEST_START)
1684 #define ATTACH_TE (HCA_TEST_TRANSIENT | HCA_TEST_ATTACH | HCA_TEST_END)
1686 #define ATTACH_PS (HCA_TEST_PERSISTENT | HCA_TEST_ATTACH | HCA_TEST_START)
1687 #define ATTACH_PE (HCA_TEST_PERSISTENT | HCA_TEST_ATTACH | HCA_TEST_END)
1689 static hermon_test_t testset[] = {
1690 /* Initial Value */
1691 {0, 0, 0, NULL, 0, 0, NULL, NULL, NULL}, /* 0 */
1693 /* PIO Transient Errors */
1694 {0, HCA_TEST_PIO, ATTACH_TS, NULL, /* attach/transient/start/propagate */
1695 HCA_PIO_RETRY_CNT, 0, NULL, NULL, NULL}, /* 1 */
1696 {0, HCA_TEST_PIO, ATTACH_TE, NULL, /* attach/transient/end/propagate */
1697 HCA_PIO_RETRY_CNT, 0, NULL, NULL, NULL}, /* 2 */
1699 /* PIO Persistent Errors */
1700 {0, HCA_TEST_PIO, ATTACH_PS, NULL, /* attach/persistent/start/propagate */
1701 0, 0, NULL, NULL, NULL}, /* 3 */
1702 {0, HCA_TEST_PIO, ATTACH_PE, NULL, /* attach/persistent/end/propagate */
1703 0, 0, NULL, NULL, NULL}, /* 4 */
1709 * void
1710 * hermon_trigger_pio_error(hermon_test_t *tst, ddi_fm_error_t *derr)
1712 * Overview
1713 * hermon_trigger_pio_error() is a PIO error injection function
1714 * to cause a pseduo PIO error.
1716 * Argument
1717 * tst: pointer to HCA FM function test structure. If the structure
1718 * is not used, the NULL value must be passed instead.
1719 * derr: pointer to ddi_fm_error_t structure
1721 * Return value
1722 * Nothing
1724 * Caller's context
1725 * hermon_trigger_pio_error() can be called in user, kernel, interrupt
1726 * context or high interrupt context.
1728 static void
1729 hermon_trigger_pio_error(hermon_test_t *tst, ddi_fm_error_t *derr)
1731 hermon_state_t *state = (hermon_state_t *)tst->private;
1732 derr->fme_status = DDI_FM_OK;
1734 if (tst->type != HCA_TEST_PIO) {
1735 return;
1738 if ((tst->trigger & HCA_TEST_ATTACH &&
1739 i_ddi_node_state(state->hs_dip) < DS_ATTACHED &&
1740 hermon_get_state(state) & HCA_PIO_FM)) {
1741 if (tst->trigger & HCA_TEST_PERSISTENT) {
1742 i_hca_fm_ereport(state->hs_dip, HCA_IBA_ERR,
1743 DDI_FM_DEVICE_INVAL_STATE);
1744 derr->fme_status = DDI_FM_NONFATAL;
1745 return;
1746 } else if (tst->trigger & HCA_TEST_TRANSIENT &&
1747 tst->errcnt) {
1748 i_hca_fm_ereport(state->hs_dip, HCA_IBA_ERR,
1749 DDI_FM_DEVICE_INVAL_STATE);
1750 derr->fme_status = DDI_FM_NONFATAL;
1751 tst->errcnt--;
1752 return;
1759 * struct hermon_fm_test *
1760 * hermon_test_register(hermon_state_t *state, char *filename, int linenum,
1761 * int type)
1763 * Overview
1764 * hermon_test_register() registers a Hermon FM test item for the
1765 * function test.
1767 * Argument
1768 * state: pointer to Hermon state structure
1769 * filename: source file name where the function call is implemented
1770 * This value is usually a __FILE__ pre-defined macro.
1771 * linenum: line number where the function call is described in the
1772 * file specified above.
1773 * This value is usually a __LINE__ pre-defined macro.
1774 * type: HW error type
1775 * HCA_TEST_PIO pio error
1776 * HCA_TEST_IBA ib specific error
1778 * Return value
1779 * pointer to Hermon FM function test structure registered.
1781 * Caller's context
1782 * hermon_test_register() can be called in user, kernel or interrupt
1783 * context.
1785 * Note that no test item is registered if Hermon FM is disabled.
1787 hermon_test_t *
1788 hermon_test_register(hermon_state_t *state, char *filename, int linenum,
1789 int type)
1791 void (*pio_injection)(struct i_hca_fm_test *, ddi_fm_error_t *) =
1792 (void (*)(struct i_hca_fm_test *, ddi_fm_error_t *))
1793 hermon_trigger_pio_error;
1795 if (state->hs_fm_disable)
1796 return (NULL);
1798 return ((hermon_test_t *)i_hca_test_register(filename, linenum, type,
1799 pio_injection, (void *)state, state->hs_fm_test_hash,
1800 state->hs_fm_id_hash, hermon_test_num));
1802 #endif /* FMA_TEST */
1806 * HCA FM Common Interface
1808 * These functions should be used for any HCA drivers, but probably
1809 * customized for their own HW design and/or FM implementation.
1810 * Customized functins should have the driver name prefix such as
1811 * hermon_xxxx() and be defined separately but whose functions should
1812 * call the common interface inside.
1816 * void
1817 * i_hca_fm_init(struct i_hca_fm *hca_fm)
1819 * Overview
1820 * i_hca_fm_init() is an initialization function which sets up the acc
1821 * handle kmem_cache if this function is called the first time.
1823 * Argument
1824 * hca_fm: pointer to HCA FM structure
1826 * Return value
1827 * Nothing
1829 * Caller's context
1830 * i_hca_fm_init() can be called in user or kernel context, but cannot
1831 * be called in interrupt context.
1833 static void
1834 i_hca_fm_init(struct i_hca_fm *hca_fm)
1837 mutex_enter(&hca_fm->lock);
1839 ++hca_fm->ref_cnt;
1840 if (hca_fm->fm_acc_cache == NULL) {
1841 hca_fm->fm_acc_cache = kmem_cache_create("hca_fm_acc_handle",
1842 sizeof (struct i_hca_acc_handle), 0, NULL,
1843 NULL, NULL, NULL, NULL, 0);
1846 mutex_exit(&hca_fm->lock);
1851 * void
1852 * i_hca_fm_fini(struct i_hca_fm *hca_fm)
1854 * Overview
1855 * i_hca_fm_fini() is a finalization function which frees up the acc
1856 * handle kmem_cache if this function is called the last time.
1858 * Argument
1859 * hca_fm: pointer to HCA FM structure
1861 * Return value
1862 * Nothing
1864 * Caller's context
1865 * i_hca_fm_fini() can be called in user or kernel context, but cannot
1866 * be called in interrupt context.
1868 static void
1869 i_hca_fm_fini(struct i_hca_fm *hca_fm)
1871 mutex_enter(&hca_fm->lock);
1873 if (--hca_fm->ref_cnt == 0) {
1875 if (hca_fm->fm_acc_cache) {
1876 kmem_cache_destroy(hca_fm->fm_acc_cache);
1877 hca_fm->fm_acc_cache = NULL;
1881 mutex_exit(&hca_fm->lock);
1886 * void
1887 * i_hca_fm_ereport(dev_info_t *dip, int type, char *detail)
1889 * Overview
1890 * i_hca_fm_ereport() is a wrapper function of ddi_fm_ereport_post() but
1891 * generates an ena before it calls ddi_fm_ereport_post() for HCA
1892 * specific HW errors.
1894 * Argument
1895 * dip: pointer to this device dev_info structure
1896 * type: error type
1897 * HCA_SYS_ERR FMA reporting HW error
1898 * HCA_IBA_ERR HCA specific HW error
1899 * detail: definition of leaf driver detected ereports which is one of:
1900 * DDI_FM_DEVICE_INVAL_STATE
1901 * DDI_FM_DEVICE_NO_RESPONSE
1902 * DDI_FM_DEVICE_STALL
1903 * DDI_FM_DEVICE_BADINT_LIMIT
1904 * DDI_FM_DEVICE_INTERN_CORR
1905 * DDI_FM_DEVICE_INTERN_UNCORR
1907 * Return value
1908 * Nothing
1910 * Caller's context
1911 * i_hca_fm_ereport() can be called in user, kernel or interrupt context.
1913 static void
1914 i_hca_fm_ereport(dev_info_t *dip, int type, char *detail)
1916 uint64_t ena;
1917 char buf[FM_MAX_CLASS];
1919 (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail);
1921 ena = fm_ena_generate(0, FM_ENA_FMT1);
1922 if (type == HCA_IBA_ERR) {
1923 /* this is an error of its own */
1924 ena = fm_ena_increment(ena);
1927 ddi_fm_ereport_post(dip, buf, ena, DDI_NOSLEEP,
1928 FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0, NULL);
1933 * struct i_hca_acc_handle *
1934 * i_hca_get_acc_handle(struct i_hca_fm *hca_fm, ddi_acc_handle_t handle)
1936 * Overview
1937 * i_hca_get_acc_handle() returns ddi_acc_handle_t used for HCA FM.
1939 * Argument
1940 * hca_fm: pointer to HCA FM structure
1941 * handle: ddi_acc_handle_t
1943 * Return value
1944 * handle: pointer to ddi_acc_handle_t used for HCA FM
1946 * Caller's context
1947 * i_hca_get_acc_handle() can be called in user, kernel or interrupt
1948 * context.
1950 static struct i_hca_acc_handle *
1951 i_hca_get_acc_handle(struct i_hca_fm *hca_fm, ddi_acc_handle_t handle)
1953 struct i_hca_acc_handle *hdlp;
1955 /* Retrieve the HCA FM access handle */
1956 mutex_enter(&hca_fm->lock);
1958 for (hdlp = hca_fm->hdl; hdlp != NULL; hdlp = hdlp->next) {
1959 if (hdlp->save_hdl == handle) {
1960 mutex_exit(&hca_fm->lock);
1961 return (hdlp);
1965 mutex_exit(&hca_fm->lock);
1966 return (hdlp);
1971 * int
1972 * i_hca_regs_map_setup(struct i_hca_fm *hca_fm, dev_info_t *dip,
1973 * uint_t rnumber, caddr_t *addrp, offset_t offset, offset_t len,
1974 * ddi_device_acc_attr_t *accattrp, ddi_acc_handle_t *handle)
1976 * Overview
1977 * i_hca_regs_map_setup() is a wrapper function of ddi_regs_map_setup(),
1978 * but allocates the HCA FM acc handle structure and initializes it.
1980 * Argument
1981 * hca_fm: pointer to HCA FM structure
1982 * dip: pointer to this device dev_info structure
1983 * rnumber: index number to the register address space set
1984 * addrp: platform-dependent value (same as ddi_regs_map_setup())
1985 * offset: offset into the register address space
1986 * len: address space length to be mapped
1987 * accattrp: pointer to device access attribute structure
1988 * handle: pointer to ddi_acc_handle_t used for HCA FM
1990 * Return value
1991 * ddi function status value which are:
1992 * DDI_SUCCESS
1993 * DDI_FAILURE
1994 * DDI_ME_RNUMBER_RNGE
1995 * DDI_REGS_ACC_CONFLICT
1997 * Caller's context
1998 * i_hca_regs_map_setup() can be called in user or kernel context only.
2000 static int
2001 i_hca_regs_map_setup(struct i_hca_fm *hca_fm, dev_info_t *dip, uint_t rnumber,
2002 caddr_t *addrp, offset_t offset, offset_t len,
2003 ddi_device_acc_attr_t *accattrp, ddi_acc_handle_t *handle)
2005 int status;
2006 struct i_hca_acc_handle *handlep, *hdlp, *last;
2008 /* Allocate an access handle */
2009 if ((status = ddi_regs_map_setup(dip, rnumber, addrp, offset,
2010 len, accattrp, handle)) != DDI_SUCCESS) {
2011 return (status);
2014 /* Allocate HCA FM acc handle structure */
2015 handlep = kmem_cache_alloc(hca_fm->fm_acc_cache, KM_SLEEP);
2017 /* Initialize fields */
2018 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*handlep))
2019 handlep->next = NULL;
2020 handlep->save_hdl = (*handle);
2021 handlep->thread_cnt = 0;
2022 mutex_init(&handlep->lock, NULL, MUTEX_DRIVER, NULL);
2024 /* Register this handle */
2025 mutex_enter(&hca_fm->lock);
2026 for (last = hdlp = hca_fm->hdl; hdlp != NULL; hdlp = hdlp->next) {
2027 last = hdlp;
2029 if (last == NULL) {
2030 hca_fm->hdl = handlep;
2031 } else {
2032 last->next = handlep;
2034 mutex_exit(&hca_fm->lock);
2036 return (status);
2041 * void
2042 * i_hca_regs_map_free(struct i_hca_fm *hca_fm, ddi_acc_handle_t *handlep)
2044 * Overview
2045 * i_hca_regs_map_setup() is a wrapper function of ddi_regs_map_free(),
2046 * and frees the HCA FM acc handle structure allocated by
2047 * i_hca_regs_map_setup().
2049 * Argument
2050 * hca_fm: pointer to HCA FM structure
2051 * handle: pointer to ddi_acc_handle_t used for HCA FM
2053 * Return value
2054 * Nothing
2056 * Caller's context
2057 * i_hca_regs_map_free() can be called in user or kernel context only.
2059 * Note that the handle passed to i_hca_regs_map_free() is NULL-cleared
2060 * after this function is called.
2062 static void
2063 i_hca_regs_map_free(struct i_hca_fm *hca_fm, ddi_acc_handle_t *handle)
2065 struct i_hca_acc_handle *handlep, *hdlp, *prev;
2067 /* De-register this handle */
2068 mutex_enter(&hca_fm->lock);
2069 for (prev = hdlp = hca_fm->hdl; hdlp != NULL; hdlp = hdlp->next) {
2070 if (hdlp->save_hdl == *handle)
2071 break;
2072 prev = hdlp;
2074 ASSERT(prev != NULL && hdlp != NULL);
2075 if (hdlp != prev) {
2076 prev->next = hdlp->next;
2077 } else {
2078 hca_fm->hdl = hdlp->next;
2080 handlep = hdlp;
2081 mutex_exit(&hca_fm->lock);
2083 mutex_destroy(&handlep->lock);
2084 handlep->save_hdl = NULL;
2085 kmem_cache_free(hca_fm->fm_acc_cache, handlep);
2087 /* Release this handle */
2088 ddi_regs_map_free(handle);
2089 *handle = NULL;
2094 * int
2095 * i_hca_pci_config_setup(struct i_hca_fm *hca_fm, dev_info_t *dip,
2096 * ddi_acc_handle_t *handle, boolean_t fm_protect)
2098 * Overview
2099 * i_hca_pci_config_setup() is a wrapper function of pci_config_setup(),
2100 * but allocates the HCA FM acc handle structure and initializes it.
2102 * Argument
2103 * hca_fm: pointer to HCA FM structure
2104 * dip: pointer to this device dev_info structure
2105 * handle: pointer to ddi_acc_handle_t used for HCA PCI config space
2106 * with FMA
2107 * fm_protect: flag to tell if an fma-protected access handle should
2108 * be used
2110 * Return value
2111 * ddi function status value which are:
2112 * DDI_SUCCESS
2113 * DDI_FAILURE
2115 * Caller's context
2116 * i_hca_pci_config_setup() can be called in user or kernel context only.
2118 static int
2119 i_hca_pci_config_setup(struct i_hca_fm *hca_fm, dev_info_t *dip,
2120 ddi_acc_handle_t *handle)
2122 int status;
2123 struct i_hca_acc_handle *handlep, *hdlp, *last;
2125 /* Allocate an access handle */
2126 if ((status = pci_config_setup(dip, handle)) != DDI_SUCCESS) {
2127 return (status);
2130 /* Allocate HCA FM acc handle structure */
2131 handlep = kmem_cache_alloc(hca_fm->fm_acc_cache, KM_SLEEP);
2133 /* Initialize fields */
2134 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*handlep))
2135 handlep->next = NULL;
2136 handlep->save_hdl = (*handle);
2137 handlep->thread_cnt = 0;
2138 mutex_init(&handlep->lock, NULL, MUTEX_DRIVER, NULL);
2140 /* Register this handle */
2141 mutex_enter(&hca_fm->lock);
2142 for (last = hdlp = hca_fm->hdl; hdlp != NULL; hdlp = hdlp->next) {
2143 last = hdlp;
2145 if (last == NULL) {
2146 hca_fm->hdl = handlep;
2147 } else {
2148 last->next = handlep;
2150 mutex_exit(&hca_fm->lock);
2152 return (status);
2157 * void
2158 * i_hca_pci_config_teardown(struct i_hca_fm *hca_fm,
2159 * ddi_acc_handle_t *handlep)
2161 * Overview
2162 * i_hca_pci_config_teardown() is a wrapper function of
2163 * pci_config_teardown(), and frees the HCA FM acc handle structure
2164 * allocated by i_hca_pci_config_setup().
2166 * Argument
2167 * hca_fm: pointer to HCA FM structure
2168 * handle: pointer to ddi_acc_handle_t used for HCA FM
2170 * Return value
2171 * Nothing
2173 * Caller's context
2174 * i_hca_pci_config_teardown() can be called in user or kernel context
2175 * only.
2177 * Note that the handle passed to i_hca_pci_config_teardown() is NULL-cleared
2178 * after this function is called.
2180 static void
2181 i_hca_pci_config_teardown(struct i_hca_fm *hca_fm, ddi_acc_handle_t *handle)
2183 struct i_hca_acc_handle *handlep, *hdlp, *prev;
2185 /* De-register this handle */
2186 mutex_enter(&hca_fm->lock);
2187 for (prev = hdlp = hca_fm->hdl; hdlp != NULL; hdlp = hdlp->next) {
2188 if (hdlp->save_hdl == *handle)
2189 break;
2190 prev = hdlp;
2192 ASSERT(prev != NULL && hdlp != NULL);
2193 if (hdlp != prev) {
2194 prev->next = hdlp->next;
2195 } else {
2196 hca_fm->hdl = hdlp->next;
2198 handlep = hdlp;
2199 mutex_exit(&hca_fm->lock);
2201 mutex_destroy(&handlep->lock);
2202 handlep->save_hdl = NULL;
2203 kmem_cache_free(hca_fm->fm_acc_cache, handlep);
2205 /* Release this handle */
2206 pci_config_teardown(handle);
2207 *handle = NULL;
2212 * int
2213 * i_hca_pio_start(dev_info_t *dip, struct i_acc_handle *handle,
2214 * struct i_hca_fm_test *tst)
2216 * Overview
2217 * i_hca_pio_start() is one of a pair of HCA FM fuctions for PIO, which
2218 * should be called before HCA drivers issue PIOs against I/O space.
2219 * See HCA FM comments at the beginning of this file in detail.
2221 * Argument
2222 * dip: pointer to this device dev_info structure
2223 * handle: pointer to ddi_acc_handle_t used for HCA FM
2224 * tst: pointer to HCA FM function test structure. If the structure
2225 * is not used, the NULL value must be passed instead.
2227 * Return value
2228 * error status showing whether or not this error can retry
2229 * HCA_PIO_OK No HW errors
2230 * HCA_PIO_TRANSIENT This error could be transient
2231 * HCA_PIO_PERSISTENT This error is persistent
2233 * Caller's context
2234 * i_hca_pio_start() can be called in user, kernel or interrupt context.
2236 /* ARGSUSED */
2237 static int
2238 i_hca_pio_start(dev_info_t *dip, struct i_hca_acc_handle *hdlp,
2239 struct i_hca_fm_test *tst)
2241 ddi_fm_error_t derr;
2243 /* Count up the number of threads issuing this PIO */
2244 mutex_enter(&hdlp->lock);
2245 hdlp->thread_cnt++;
2246 mutex_exit(&hdlp->lock);
2248 /* Get the PIO error via FMA */
2249 ddi_fm_acc_err_get(fm_acc_hdl(hdlp), &derr, DDI_FME_VERSION);
2251 #ifdef FMA_TEST
2252 /* Trigger PIO errors */
2253 if (tst != NULL && tst->trigger & HCA_TEST_START) {
2254 (*tst->pio_injection)(tst, &derr);
2256 #endif /* FMA_TEST */
2258 switch (derr.fme_status) {
2259 case DDI_FM_OK:
2260 /* Not have to clear the fma error log */
2261 return (HCA_PIO_OK);
2263 case DDI_FM_NONFATAL:
2264 /* Now clear this error */
2265 ddi_fm_acc_err_clear(fm_acc_hdl(hdlp), DDI_FME_VERSION);
2267 /* Log this error and notify it as a persistent error */
2268 ddi_fm_service_impact(dip, DDI_SERVICE_LOST);
2269 return (HCA_PIO_PERSISTENT);
2271 /* In theory, this shouldn't happen */
2272 case DDI_FM_FATAL:
2273 case DDI_FM_UNKNOWN:
2274 default:
2275 cmn_err(CE_WARN, "Unknown HCA HW error status (%d)",
2276 derr.fme_status);
2277 /* Return this as a persistent error */
2278 return (HCA_PIO_PERSISTENT);
2284 * int
2285 * i_hca_pio_end(dev_info_t *dip, ddi_acc_handle_t handle, int *cnt,
2286 * struct i_hca_fm_test *tst)
2288 * Overview
2289 * i_hca_pio_end() is the other of a pair of HCA FM fuctions for PIO,
2290 * which should be called after HCA drivers issue PIOs against I/O space.
2291 * See HCA FM comments at the beginning of this file in detail.
2293 * Argument
2294 * dip: pointer to this device dev_info structure
2295 * handle: pointer to ddi_acc_handle_t used for HCA FM
2296 * cnt: pointer to the counter variable which holds the nubmer of retry
2297 * when a HW error is detected.
2298 * tst: pointer to HCA FM function test structure. If the structure
2299 * is not used, the NULL value must be passed instead.
2301 * Return value
2302 * error status showing whether or not this error can retry
2303 * HCA_PIO_OK No HW errors
2304 * HCA_PIO_TRANSIENT This error could be transient
2305 * HCA_PIO_PERSISTENT This error is persistent
2307 * Caller's context
2308 * i_hca_pio_end() can be called in user, kernel or interrupt context.
2310 /* ARGSUSED */
2311 static int
2312 i_hca_pio_end(dev_info_t *dip, struct i_hca_acc_handle *hdlp, int *cnt,
2313 struct i_hca_fm_test *tst)
2315 ddi_fm_error_t derr;
2317 /* Get the PIO error via FMA */
2318 ddi_fm_acc_err_get(fm_acc_hdl(hdlp), &derr, DDI_FME_VERSION);
2320 #ifdef FMA_TEST
2321 /* Trigger PIO errors */
2322 if (tst != NULL && tst->trigger & HCA_TEST_END) {
2323 (*tst->pio_injection)(tst, &derr);
2325 #endif /* FMA_TEST */
2327 /* Evaluate the PIO error */
2328 switch (derr.fme_status) {
2329 case DDI_FM_OK:
2330 /* Count down the number of threads issuing this PIO */
2331 mutex_enter(&hdlp->lock);
2332 hdlp->thread_cnt--;
2333 mutex_exit(&hdlp->lock);
2335 /* Not have to clear the fma error log */
2336 return (HCA_PIO_OK);
2338 case DDI_FM_NONFATAL:
2339 /* Now clear this error */
2340 ddi_fm_acc_err_clear(fm_acc_hdl(hdlp), DDI_FME_VERSION);
2343 * Check if this error comes from another thread running
2344 * with the same handle almost at the same time.
2346 mutex_enter(&hdlp->lock);
2347 if (hdlp->thread_cnt > 1) {
2348 /* Count down the number of threads */
2349 hdlp->thread_cnt--;
2350 mutex_exit(&hdlp->lock);
2352 /* Return this as a persistent error */
2353 return (HCA_PIO_PERSISTENT);
2355 mutex_exit(&hdlp->lock);
2357 /* Now determine if this error is persistent or not */
2358 if (--(*cnt) >= 0) {
2359 return (HCA_PIO_TRANSIENT);
2360 } else {
2361 /* Count down the number of threads */
2362 mutex_enter(&hdlp->lock);
2363 hdlp->thread_cnt--;
2364 mutex_exit(&hdlp->lock);
2365 return (HCA_PIO_PERSISTENT);
2368 /* In theory, this shouldn't happen */
2369 case DDI_FM_FATAL:
2370 case DDI_FM_UNKNOWN:
2371 default:
2372 cmn_err(CE_WARN, "Unknown HCA HW error status (%d)",
2373 derr.fme_status);
2374 /* Return this as a persistent error */
2375 return (HCA_PIO_PERSISTENT);
2381 * HCA FM Test Interface
2383 * These functions should be used for any HCA drivers, but probably
2384 * customized for their own HW design and/or FM implementation.
2385 * Customized functins should have the driver name prefix such as
2386 * hermon_xxxx() and be defined separately but whose function should
2387 * call the common interface inside.
2390 #ifdef FMA_TEST
2391 static int test_num; /* serial number */
2392 static kmutex_t i_hca_test_lock; /* lock for serial numer */
2395 * void
2396 * i_hca_test_init(mod_hash_t **strHashp, mod_hash_t **idHashp)
2398 * Overview
2399 * i_hca_test_init() creates two hash tables, one of which is for string,
2400 * and the other of which is for ID, then saves pointers to arguments
2401 * passed. This function uses the mod_hash utilities to manage the
2402 * hash tables. About the mod_hash, see kernel/os/modhash.c.
2404 * Argument
2405 * strHashp: pointer to String hash table pointer
2406 * idHashp: pointer to ID hash table pointer
2408 * Return value
2409 * Nothing
2411 * Caller's context
2412 * i_hca_test_init() can be called in user or kernel context only.
2414 static void
2415 i_hca_test_init(mod_hash_t **strHashp, mod_hash_t **idHashp)
2417 *idHashp = mod_hash_create_idhash("HCA_FMA_id_hash",
2418 FMA_TEST_HASHSZ, mod_hash_null_valdtor);
2420 *strHashp = mod_hash_create_strhash("HCA_FMA_test_hash",
2421 FMA_TEST_HASHSZ, i_hca_test_free_item);
2426 * void
2427 * i_hca_test_fini(mod_hash_t **strHashp, mod_hash_t **idHashp)
2429 * Overview
2430 * i_hca_test_fini() releases two hash tables used for HCA FM test.
2432 * Argument
2433 * strHashp: pointer to String hash table pointer
2434 * idHashp: pointer to ID hash table pointer
2436 * Return value
2437 * Nothing
2439 * Caller's context
2440 * i_hca_test_fini() can be called in user, kernel or interrupt context.
2443 static void
2444 i_hca_test_fini(mod_hash_t **strHashp, mod_hash_t **idHashp)
2446 mod_hash_destroy_hash(*strHashp);
2447 *strHashp = NULL;
2449 mod_hash_destroy_hash(*idHashp);
2450 *idHashp = NULL;
2455 * struct i_hca_fm_test *
2456 * i_hca_test_register(char *filename, int linenum, int type,
2457 * void (*pio_injection)(struct i_hca_fm_test *, ddi_fm_error_t *),
2458 * void *private, mod_hash_t *strHash, mod_hash_t *idHash, int preTestNum)
2460 * Overview
2461 * i_hca_test_register() registers an HCA FM test item against HCA FM
2462 * function callings specified with the file name and the line number
2463 * (passed as the arguments).
2465 * Argument
2466 * filename: source file name where the function call is implemented
2467 * This value is usually a __FILE__ pre-defined macro.
2468 * linenum: line number where the function call is described in the
2469 * file specified above.
2470 * This value is usually a __LINE__ pre-defined macro.
2471 * type: HW error type
2472 * HCA_TEST_PIO pio error
2473 * HCA_TEST_IBA ib specific error
2474 * pio_injection: pio error injection callback function invoked when the
2475 * function specified above (with the file name and the
2476 * line number) is executed. If the function is not a PIO,
2477 * request, this parameter should be NULL.
2478 * private: the argument passed to either of injection functions when
2479 * they're invoked.
2480 * strHashp: pointer to String hash table
2481 * idHashp: pointer to ID hash table
2482 * preTestNum: the index of the pre-defined testset for this test item.
2484 * Return value
2485 * pointer to HCA FM function test structure registered.
2487 * Caller's context
2488 * i_hca_test_register() can be called in user, kernel or interrupt
2489 * context.
2492 static struct i_hca_fm_test *
2493 i_hca_test_register(char *filename, int linenum, int type,
2494 void (*pio_injection)(struct i_hca_fm_test *, ddi_fm_error_t *),
2495 void *private, mod_hash_t *strHash, mod_hash_t *idHash, int preTestNum)
2497 struct i_hca_fm_test *t_item;
2498 char key_buf[255], *hash_key;
2499 int status;
2501 (void) sprintf(key_buf, "%s:%d", filename, linenum);
2502 hash_key = kmem_zalloc(strlen(key_buf) + 1, KM_NOSLEEP);
2504 if (hash_key == NULL)
2505 cmn_err(CE_PANIC, "No memory for HCA FMA Test.");
2507 bcopy(key_buf, hash_key, strlen(key_buf));
2509 status = mod_hash_find(strHash, (mod_hash_key_t)hash_key,
2510 (mod_hash_val_t *)&t_item);
2512 switch (status) {
2513 case MH_ERR_NOTFOUND:
2514 t_item = (struct i_hca_fm_test *)
2515 kmem_alloc(sizeof (struct i_hca_fm_test), KM_NOSLEEP);
2516 if (t_item == NULL)
2517 cmn_err(CE_PANIC, "No memory for HCA FMA Test.");
2519 /* Set the error number */
2520 mutex_enter(&i_hca_test_lock);
2521 t_item->num = test_num++;
2522 mutex_exit(&i_hca_test_lock);
2524 /* Set type and other static information */
2525 t_item->type = type;
2526 t_item->line_num = linenum;
2527 t_item->file_name = filename;
2528 t_item->hash_key = hash_key;
2529 t_item->private = private;
2530 t_item->pio_injection = pio_injection;
2532 /* Set the pre-defined hermon test item */
2533 i_hca_test_set_item(preTestNum, (struct i_hca_fm_test *)t_item);
2535 status = mod_hash_insert(strHash, (mod_hash_key_t)
2536 hash_key, (mod_hash_val_t)t_item);
2537 ASSERT(status == 0);
2539 status = mod_hash_insert(idHash, (mod_hash_key_t)
2540 (uintptr_t)t_item->num, (mod_hash_val_t)t_item);
2541 ASSERT(status == 0);
2542 break;
2544 case MH_ERR_NOMEM:
2545 cmn_err(CE_PANIC, "No memory for HCA FMA Test.");
2546 break;
2548 case MH_ERR_DUPLICATE:
2549 cmn_err(CE_PANIC, "HCA FMA Test Internal Error.");
2550 break;
2551 default:
2552 /* OK, this is already registered. */
2553 kmem_free(hash_key, strlen(key_buf) + 1);
2554 break;
2556 return (t_item);
2561 * void
2562 * i_hca_test_set_item(int num, struct i_hca_fm_test *t_item)
2564 * Overview
2565 * i_hca_test_set_item() is a private function used in
2566 * i_hca_test_register() above. This function sets the testset specified
2567 * (with the index number) to HCA FM function test structure.
2569 * Argument
2570 * num: index to test set (testset structure array)
2571 * t_item: pointer to HCA fM function test structure
2573 * Return value
2574 * Nothing
2576 * Caller's context
2577 * i_hca_test_set_item() can be called in user, kernel, interrupt
2578 * context or hight interrupt context.
2581 static void
2582 i_hca_test_set_item(int num, struct i_hca_fm_test *t_item)
2584 if (num < 0 || num >= sizeof (testset) / sizeof (hermon_test_t) ||
2585 testset[num].type != t_item->type) {
2586 t_item->trigger = testset[0].trigger;
2587 t_item->errcnt = testset[0].errcnt;
2588 return;
2591 /* Set the testsuite */
2592 t_item->trigger = testset[num].trigger;
2593 t_item->errcnt = testset[num].errcnt;
2598 * void
2599 * i_hca_test_free_item(mod_hash_val_t val)
2601 * Overview
2602 * i_hca_test_free_item() is a private function used to free HCA FM
2603 * function test structure when i_hca_test_fini() is called. This function
2604 * is registered as a destructor when the hash table is created in
2605 * i_hca_test_init().
2607 * Argument
2608 * val: pointer to the value stored in hash table (pointer to HCA FM
2609 * function test structure)
2611 * Return value
2612 * Nothing
2614 * Caller's context
2615 * i_hca_test_free_item() can be called in user, kernel or interrupt
2616 * context.
2619 static void
2620 i_hca_test_free_item(mod_hash_val_t val)
2622 struct i_hca_fm_test *t_item = (struct i_hca_fm_test *)val;
2623 kmem_free(t_item, sizeof (struct i_hca_fm_test));
2625 #endif /* FMA_TEST */