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