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