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