xref: /onnv-gate/usr/src/uts/common/io/ib/adapters/hermon/hermon_event.c (revision 12965:b65a8427f8fe)
19517SBill.Taylor@Sun.COM /*
29517SBill.Taylor@Sun.COM  * CDDL HEADER START
39517SBill.Taylor@Sun.COM  *
49517SBill.Taylor@Sun.COM  * The contents of this file are subject to the terms of the
59517SBill.Taylor@Sun.COM  * Common Development and Distribution License (the "License").
69517SBill.Taylor@Sun.COM  * You may not use this file except in compliance with the License.
79517SBill.Taylor@Sun.COM  *
89517SBill.Taylor@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99517SBill.Taylor@Sun.COM  * or http://www.opensolaris.org/os/licensing.
109517SBill.Taylor@Sun.COM  * See the License for the specific language governing permissions
119517SBill.Taylor@Sun.COM  * and limitations under the License.
129517SBill.Taylor@Sun.COM  *
139517SBill.Taylor@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
149517SBill.Taylor@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159517SBill.Taylor@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
169517SBill.Taylor@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
179517SBill.Taylor@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
189517SBill.Taylor@Sun.COM  *
199517SBill.Taylor@Sun.COM  * CDDL HEADER END
209517SBill.Taylor@Sun.COM  */
219517SBill.Taylor@Sun.COM 
229517SBill.Taylor@Sun.COM /*
23*12965SWilliam.Taylor@Oracle.COM  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
249517SBill.Taylor@Sun.COM  */
259517SBill.Taylor@Sun.COM 
269517SBill.Taylor@Sun.COM /*
279517SBill.Taylor@Sun.COM  * hermon_event.c
289517SBill.Taylor@Sun.COM  *    Hermon Interrupt and Event Processing Routines
299517SBill.Taylor@Sun.COM  *
309517SBill.Taylor@Sun.COM  *    Implements all the routines necessary for allocating, freeing, and
319517SBill.Taylor@Sun.COM  *    handling all of the various event types that the Hermon hardware can
329517SBill.Taylor@Sun.COM  *    generate.
339517SBill.Taylor@Sun.COM  *    These routines include the main Hermon interrupt service routine
349517SBill.Taylor@Sun.COM  *    (hermon_isr()) as well as all the code necessary to setup and handle
359517SBill.Taylor@Sun.COM  *    events from each of the many event queues used by the Hermon device.
369517SBill.Taylor@Sun.COM  */
379517SBill.Taylor@Sun.COM 
389517SBill.Taylor@Sun.COM #include <sys/types.h>
399517SBill.Taylor@Sun.COM #include <sys/conf.h>
409517SBill.Taylor@Sun.COM #include <sys/ddi.h>
419517SBill.Taylor@Sun.COM #include <sys/sunddi.h>
429517SBill.Taylor@Sun.COM #include <sys/modctl.h>
439517SBill.Taylor@Sun.COM 
449517SBill.Taylor@Sun.COM #include <sys/ib/adapters/hermon/hermon.h>
459517SBill.Taylor@Sun.COM 
469517SBill.Taylor@Sun.COM static void hermon_eq_poll(hermon_state_t *state, hermon_eqhdl_t eq);
479517SBill.Taylor@Sun.COM static void hermon_eq_catastrophic(hermon_state_t *state);
489517SBill.Taylor@Sun.COM static int hermon_eq_alloc(hermon_state_t *state, uint32_t log_eq_size,
499517SBill.Taylor@Sun.COM     uint_t intr, hermon_eqhdl_t *eqhdl);
509517SBill.Taylor@Sun.COM static int hermon_eq_free(hermon_state_t *state, hermon_eqhdl_t *eqhdl);
519517SBill.Taylor@Sun.COM static int hermon_eq_handler_init(hermon_state_t *state, hermon_eqhdl_t eq,
529517SBill.Taylor@Sun.COM     uint_t evt_type_mask, int (*eqfunc)(hermon_state_t *state,
539517SBill.Taylor@Sun.COM     hermon_eqhdl_t eq, hermon_hw_eqe_t *eqe));
549517SBill.Taylor@Sun.COM static int hermon_eq_handler_fini(hermon_state_t *state, hermon_eqhdl_t eq);
559517SBill.Taylor@Sun.COM static int hermon_port_state_change_handler(hermon_state_t *state,
569517SBill.Taylor@Sun.COM     hermon_eqhdl_t eq, hermon_hw_eqe_t *eqe);
579517SBill.Taylor@Sun.COM static int hermon_comm_estbl_handler(hermon_state_t *state,
589517SBill.Taylor@Sun.COM     hermon_eqhdl_t eq, hermon_hw_eqe_t *eqe);
599517SBill.Taylor@Sun.COM static int hermon_local_wq_cat_err_handler(hermon_state_t *state,
609517SBill.Taylor@Sun.COM     hermon_eqhdl_t eq, hermon_hw_eqe_t *eqe);
619517SBill.Taylor@Sun.COM static int hermon_invreq_local_wq_err_handler(hermon_state_t *state,
629517SBill.Taylor@Sun.COM     hermon_eqhdl_t eq, hermon_hw_eqe_t *eqe);
639517SBill.Taylor@Sun.COM static int hermon_local_acc_vio_wq_err_handler(hermon_state_t *state,
649517SBill.Taylor@Sun.COM     hermon_eqhdl_t eq, hermon_hw_eqe_t *eqe);
659517SBill.Taylor@Sun.COM static int hermon_sendq_drained_handler(hermon_state_t *state,
669517SBill.Taylor@Sun.COM     hermon_eqhdl_t eq, hermon_hw_eqe_t *eqe);
679517SBill.Taylor@Sun.COM static int hermon_path_mig_handler(hermon_state_t *state,
689517SBill.Taylor@Sun.COM     hermon_eqhdl_t eq, hermon_hw_eqe_t *eqe);
699517SBill.Taylor@Sun.COM static int hermon_path_mig_err_handler(hermon_state_t *state,
709517SBill.Taylor@Sun.COM     hermon_eqhdl_t eq, hermon_hw_eqe_t *eqe);
719517SBill.Taylor@Sun.COM static int hermon_catastrophic_handler(hermon_state_t *state,
729517SBill.Taylor@Sun.COM     hermon_eqhdl_t eq, hermon_hw_eqe_t *eqe);
739517SBill.Taylor@Sun.COM static int hermon_srq_last_wqe_reached_handler(hermon_state_t *state,
749517SBill.Taylor@Sun.COM     hermon_eqhdl_t eq, hermon_hw_eqe_t *eqe);
75*12965SWilliam.Taylor@Oracle.COM static int hermon_fexch_error_handler(hermon_state_t *state,
769517SBill.Taylor@Sun.COM     hermon_eqhdl_t eq, hermon_hw_eqe_t *eqe);
779517SBill.Taylor@Sun.COM static int hermon_no_eqhandler(hermon_state_t *state, hermon_eqhdl_t eq,
789517SBill.Taylor@Sun.COM     hermon_hw_eqe_t *eqe);
799517SBill.Taylor@Sun.COM static int hermon_eq_demux(hermon_state_t *state, hermon_eqhdl_t eq,
809517SBill.Taylor@Sun.COM     hermon_hw_eqe_t *eqe);
819517SBill.Taylor@Sun.COM 
829517SBill.Taylor@Sun.COM /*
839517SBill.Taylor@Sun.COM  * hermon_eq_init_all
849517SBill.Taylor@Sun.COM  *    Context: Only called from attach() path context
859517SBill.Taylor@Sun.COM  */
869517SBill.Taylor@Sun.COM int
hermon_eq_init_all(hermon_state_t * state)879517SBill.Taylor@Sun.COM hermon_eq_init_all(hermon_state_t *state)
889517SBill.Taylor@Sun.COM {
899517SBill.Taylor@Sun.COM 	uint_t		log_eq_size, intr_num;
909517SBill.Taylor@Sun.COM 	uint_t		num_eq, num_eq_init, num_eq_unmap, num_eq_rsvd;
919517SBill.Taylor@Sun.COM 	uint32_t	event_mask;	/* used for multiple event types */
929517SBill.Taylor@Sun.COM 	int		status, i, num_extra;
93*12965SWilliam.Taylor@Oracle.COM 	struct hermon_sw_eq_s **eq;
949517SBill.Taylor@Sun.COM 	ddi_acc_handle_t uarhdl = hermon_get_uarhdl(state);
959517SBill.Taylor@Sun.COM 
969517SBill.Taylor@Sun.COM 	/* initialize the FMA retry loop */
979517SBill.Taylor@Sun.COM 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
989517SBill.Taylor@Sun.COM 
999517SBill.Taylor@Sun.COM 	/*
1009517SBill.Taylor@Sun.COM 	 * For now, all Event Queues default to the same size (pulled from
1019517SBill.Taylor@Sun.COM 	 * the current configuration profile) and are all assigned to the
1029517SBill.Taylor@Sun.COM 	 * same interrupt or MSI.  In the future we may support assigning
1039517SBill.Taylor@Sun.COM 	 * EQs to specific interrupts or MSIs XXX
1049517SBill.Taylor@Sun.COM 	 */
1059517SBill.Taylor@Sun.COM 	log_eq_size = state->hs_cfg_profile->cp_log_eq_sz;
1069517SBill.Taylor@Sun.COM 
1079517SBill.Taylor@Sun.COM 	/*
1089517SBill.Taylor@Sun.COM 	 * Total number of supported EQs is fixed.  Hermon hardware
1099517SBill.Taylor@Sun.COM 	 * supports up to 512 EQs, though in theory they will one day be
1109517SBill.Taylor@Sun.COM 	 * alloc'd to virtual HCA's.  We are currently using only 47 of them
1119517SBill.Taylor@Sun.COM 	 * - that is, in Arbel and Tavor, before HERMON, where
1129517SBill.Taylor@Sun.COM 	 * we had set aside the first 32 for use with Completion Queues (CQ)
1139517SBill.Taylor@Sun.COM 	 * and reserved a few of the other 32 for each specific class of event
1149517SBill.Taylor@Sun.COM 	 *
1159517SBill.Taylor@Sun.COM 	 * However, with the coming of vitualization, we'll have only 4 per
1169517SBill.Taylor@Sun.COM 	 * potential guest - so, we'll try alloc'ing them differntly
1179517SBill.Taylor@Sun.COM 	 * (see below for more details).
1189517SBill.Taylor@Sun.COM 	 */
1199517SBill.Taylor@Sun.COM 	num_eq = HERMON_NUM_EQ_USED;
120*12965SWilliam.Taylor@Oracle.COM 	num_eq_rsvd = state->hs_rsvd_eqs;
121*12965SWilliam.Taylor@Oracle.COM 	eq = &state->hs_eqhdl[num_eq_rsvd];
1229517SBill.Taylor@Sun.COM 
1239517SBill.Taylor@Sun.COM 	/*
1249517SBill.Taylor@Sun.COM 	 * If MSI is to be used, then set intr_num to the MSI number.
1259517SBill.Taylor@Sun.COM 	 * Otherwise, for fixed (i.e. 'legacy') interrupts,
1269517SBill.Taylor@Sun.COM 	 * it is what the card tells us in 'inta_pin'.
1279517SBill.Taylor@Sun.COM 	 */
1289517SBill.Taylor@Sun.COM 	if (state->hs_intr_type_chosen == DDI_INTR_TYPE_FIXED) {
1299517SBill.Taylor@Sun.COM 		intr_num = state->hs_adapter.inta_pin;
1309517SBill.Taylor@Sun.COM 		num_extra = 0;
1319517SBill.Taylor@Sun.COM 	} else {
1329517SBill.Taylor@Sun.COM 		/* If we have more than one MSI-X vector, init them. */
1339517SBill.Taylor@Sun.COM 		for (i = 0; i + 1 < state->hs_intrmsi_allocd; i++) {
134*12965SWilliam.Taylor@Oracle.COM 			status = hermon_eq_alloc(state, log_eq_size, i, &eq[i]);
1359517SBill.Taylor@Sun.COM 			if (status != DDI_SUCCESS) {
1369517SBill.Taylor@Sun.COM 				while (--i >= 0) {
1379517SBill.Taylor@Sun.COM 					(void) hermon_eq_handler_fini(state,
138*12965SWilliam.Taylor@Oracle.COM 					    eq[i]);
139*12965SWilliam.Taylor@Oracle.COM 					(void) hermon_eq_free(state, &eq[i]);
1409517SBill.Taylor@Sun.COM 				}
1419517SBill.Taylor@Sun.COM 				return (DDI_FAILURE);
1429517SBill.Taylor@Sun.COM 			}
1439517SBill.Taylor@Sun.COM 
144*12965SWilliam.Taylor@Oracle.COM 			(void) hermon_eq_handler_init(state, eq[i],
1459517SBill.Taylor@Sun.COM 			    HERMON_EVT_NO_MASK, hermon_cq_handler);
1469517SBill.Taylor@Sun.COM 		}
1479517SBill.Taylor@Sun.COM 		intr_num = i;
1489517SBill.Taylor@Sun.COM 		num_extra = i;
1499517SBill.Taylor@Sun.COM 	}
1509517SBill.Taylor@Sun.COM 
1519517SBill.Taylor@Sun.COM 	/*
1529517SBill.Taylor@Sun.COM 	 * Allocate and initialize the rest of the Event Queues to be used.
1539517SBill.Taylor@Sun.COM 	 * If any of these EQ allocations fail then jump to the end, cleanup
1549517SBill.Taylor@Sun.COM 	 * what had been successfully initialized, and return an error.
1559517SBill.Taylor@Sun.COM 	 */
1569517SBill.Taylor@Sun.COM 	for (i = 0; i < num_eq; i++) {
1579517SBill.Taylor@Sun.COM 		status = hermon_eq_alloc(state, log_eq_size, intr_num,
158*12965SWilliam.Taylor@Oracle.COM 		    &eq[num_extra + i]);
1599517SBill.Taylor@Sun.COM 		if (status != DDI_SUCCESS) {
1609517SBill.Taylor@Sun.COM 			num_eq_init = i;
1619517SBill.Taylor@Sun.COM 			goto all_eq_init_fail;
1629517SBill.Taylor@Sun.COM 		}
1639517SBill.Taylor@Sun.COM 	}
1649517SBill.Taylor@Sun.COM 	num_eq_init = num_eq;
1659517SBill.Taylor@Sun.COM 	/*
1669517SBill.Taylor@Sun.COM 	 * The "num_eq_unmap" variable is used in any possible failure
1679517SBill.Taylor@Sun.COM 	 * cleanup (below) to indicate which events queues might require
1689517SBill.Taylor@Sun.COM 	 * possible event class unmapping.
1699517SBill.Taylor@Sun.COM 	 */
1709517SBill.Taylor@Sun.COM 	num_eq_unmap = 0;
171*12965SWilliam.Taylor@Oracle.COM 
1729517SBill.Taylor@Sun.COM 	/*
1739517SBill.Taylor@Sun.COM 	 * Setup EQ0 (first avail) for use with Completion Queues.  Note: We can
1749517SBill.Taylor@Sun.COM 	 * cast the return value to void here because, when we use the
1759517SBill.Taylor@Sun.COM 	 * HERMON_EVT_NO_MASK flag, it is not possible for
1769517SBill.Taylor@Sun.COM 	 * hermon_eq_handler_init() to return an error.
1779517SBill.Taylor@Sun.COM 	 */
178*12965SWilliam.Taylor@Oracle.COM 	(void) hermon_eq_handler_init(state, eq[num_eq_unmap + num_extra],
1799517SBill.Taylor@Sun.COM 	    HERMON_EVT_NO_MASK, hermon_cq_handler);
1809517SBill.Taylor@Sun.COM 
1819517SBill.Taylor@Sun.COM 	num_eq_unmap++;
1829517SBill.Taylor@Sun.COM 
1839517SBill.Taylor@Sun.COM 	/*
1849517SBill.Taylor@Sun.COM 	 * Setup EQ1 for handling Completion Queue Error Events.
1859517SBill.Taylor@Sun.COM 	 *
1869517SBill.Taylor@Sun.COM 	 * These events include things like CQ overflow or CQ access
1879517SBill.Taylor@Sun.COM 	 * violation errors.  If this setup fails for any reason (which, in
1889517SBill.Taylor@Sun.COM 	 * general, it really never should), then jump to the end, cleanup
1899517SBill.Taylor@Sun.COM 	 * everything that has been successfully initialized, and return an
1909517SBill.Taylor@Sun.COM 	 * error.
1919517SBill.Taylor@Sun.COM 	 */
192*12965SWilliam.Taylor@Oracle.COM 	status = hermon_eq_handler_init(state, eq[num_eq_unmap + num_extra],
1939517SBill.Taylor@Sun.COM 	    HERMON_EVT_MSK_CQ_ERRORS, hermon_cq_err_handler);
1949517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
1959517SBill.Taylor@Sun.COM 		goto all_eq_init_fail;
1969517SBill.Taylor@Sun.COM 	}
197*12965SWilliam.Taylor@Oracle.COM 	state->hs_cq_erreqnum = num_eq_unmap + num_extra + num_eq_rsvd;
1989517SBill.Taylor@Sun.COM 	num_eq_unmap++;
1999517SBill.Taylor@Sun.COM 
2009517SBill.Taylor@Sun.COM 	/*
2019517SBill.Taylor@Sun.COM 	 * Setup EQ2 for handling most other things including:
2029517SBill.Taylor@Sun.COM 	 *
2039517SBill.Taylor@Sun.COM 	 * Port State Change Events
2049517SBill.Taylor@Sun.COM 	 *   These events include things like Port Up and Port Down events.
2059517SBill.Taylor@Sun.COM 	 *
2069517SBill.Taylor@Sun.COM 	 * Communication Established Events
2079517SBill.Taylor@Sun.COM 	 *   These events correspond to the IB affiliated asynchronous events
2089517SBill.Taylor@Sun.COM 	 *   that are used for connection management
2099517SBill.Taylor@Sun.COM 	 *
2109517SBill.Taylor@Sun.COM 	 * Path Migration Succeeded Events
2119517SBill.Taylor@Sun.COM 	 *   These evens corresponid to the IB affiliated asynchronous events
2129517SBill.Taylor@Sun.COM 	 *   that are used to indicate successful completion of a
2139517SBill.Taylor@Sun.COM 	 *   Path Migration.
2149517SBill.Taylor@Sun.COM 	 *
2159517SBill.Taylor@Sun.COM 	 * Command Completion Events
2169517SBill.Taylor@Sun.COM 	 *   These events correspond to the Arbel generated events that are used
2179517SBill.Taylor@Sun.COM 	 *   to indicate Arbel firmware command completion.
2189517SBill.Taylor@Sun.COM 	 *
2199517SBill.Taylor@Sun.COM 	 * Local WQ Catastrophic Error Events
2209517SBill.Taylor@Sun.COM 	 * Invalid Req Local WQ Error Events
2219517SBill.Taylor@Sun.COM 	 * Local Access Violation WQ Error Events
2229517SBill.Taylor@Sun.COM 	 * SRQ Catastrophic Error Events
2239517SBill.Taylor@Sun.COM 	 * SRQ Last WQE Reached Events
2249517SBill.Taylor@Sun.COM 	 * ECC error detection events
2259517SBill.Taylor@Sun.COM 	 *   These events also correspond to the similarly-named IB affiliated
2269517SBill.Taylor@Sun.COM 	 *   asynchronous error type.
2279517SBill.Taylor@Sun.COM 	 *
2289517SBill.Taylor@Sun.COM 	 * Send Queue Drained Events
2299517SBill.Taylor@Sun.COM 	 *   These events correspond to the IB affiliated asynchronous events
2309517SBill.Taylor@Sun.COM 	 *   that are used to indicate completion of a Send Queue Drained QP
2319517SBill.Taylor@Sun.COM 	 *   state transition.
2329517SBill.Taylor@Sun.COM 	 *
2339517SBill.Taylor@Sun.COM 	 * Path Migration Failed Events
2349517SBill.Taylor@Sun.COM 	 *   These events correspond to the IB affiliated asynchronous events
2359517SBill.Taylor@Sun.COM 	 *   that are used to indicate that path migration was not successful.
2369517SBill.Taylor@Sun.COM 	 *
237*12965SWilliam.Taylor@Oracle.COM 	 * Fibre Channel Error Event
238*12965SWilliam.Taylor@Oracle.COM 	 *   This event is affiliated with an Fexch QP.
239*12965SWilliam.Taylor@Oracle.COM 	 *
2409517SBill.Taylor@Sun.COM 	 * NOTE: When an event fires on this EQ, it will demux the type and
2419517SBill.Taylor@Sun.COM 	 * 	send it to the right specific handler routine
2429517SBill.Taylor@Sun.COM 	 *
2439517SBill.Taylor@Sun.COM 	 */
2449517SBill.Taylor@Sun.COM 	event_mask =
2459517SBill.Taylor@Sun.COM 	    HERMON_EVT_MSK_PORT_STATE_CHANGE |
2469517SBill.Taylor@Sun.COM 	    HERMON_EVT_MSK_COMM_ESTABLISHED |
2479517SBill.Taylor@Sun.COM 	    HERMON_EVT_MSK_COMMAND_INTF_COMP |
2489517SBill.Taylor@Sun.COM 	    HERMON_EVT_MSK_LOCAL_WQ_CAT_ERROR |
2499517SBill.Taylor@Sun.COM 	    HERMON_EVT_MSK_INV_REQ_LOCAL_WQ_ERROR |
2509517SBill.Taylor@Sun.COM 	    HERMON_EVT_MSK_LOCAL_ACC_VIO_WQ_ERROR |
2519517SBill.Taylor@Sun.COM 	    HERMON_EVT_MSK_SEND_QUEUE_DRAINED |
2529517SBill.Taylor@Sun.COM 	    HERMON_EVT_MSK_PATH_MIGRATED |
2539517SBill.Taylor@Sun.COM 	    HERMON_EVT_MSK_PATH_MIGRATE_FAILED |
2549517SBill.Taylor@Sun.COM 	    HERMON_EVT_MSK_SRQ_CATASTROPHIC_ERROR |
2559517SBill.Taylor@Sun.COM 	    HERMON_EVT_MSK_SRQ_LAST_WQE_REACHED |
256*12965SWilliam.Taylor@Oracle.COM 	    HERMON_EVT_MSK_FEXCH_ERROR;
2579517SBill.Taylor@Sun.COM 
258*12965SWilliam.Taylor@Oracle.COM 	status = hermon_eq_handler_init(state, eq[num_eq_unmap + num_extra],
2599517SBill.Taylor@Sun.COM 	    event_mask, hermon_eq_demux);
2609517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
2619517SBill.Taylor@Sun.COM 		goto all_eq_init_fail;
2629517SBill.Taylor@Sun.COM 	}
2639517SBill.Taylor@Sun.COM 	num_eq_unmap++;
2649517SBill.Taylor@Sun.COM 
2659517SBill.Taylor@Sun.COM 	/*
2669517SBill.Taylor@Sun.COM 	 * Setup EQ3 to catch all other types of events.  Specifically, we
2679517SBill.Taylor@Sun.COM 	 * do not catch the "Local EEC Catastrophic Error Event" because we
2689517SBill.Taylor@Sun.COM 	 * should have no EEC (the Arbel driver does not support RD).  We also
2699517SBill.Taylor@Sun.COM 	 * choose not to handle any of the address translation page fault
2709517SBill.Taylor@Sun.COM 	 * event types.  Since we are not doing any page fault handling (and
2719517SBill.Taylor@Sun.COM 	 * since the Arbel firmware does not currently support any such
2729517SBill.Taylor@Sun.COM 	 * handling), we allow these events to go to the catch-all handler.
2739517SBill.Taylor@Sun.COM 	 */
274*12965SWilliam.Taylor@Oracle.COM 	status = hermon_eq_handler_init(state, eq[num_eq_unmap + num_extra],
2759517SBill.Taylor@Sun.COM 	    HERMON_EVT_CATCHALL_MASK, hermon_no_eqhandler);
2769517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
2779517SBill.Taylor@Sun.COM 		goto all_eq_init_fail;
2789517SBill.Taylor@Sun.COM 	}
2799517SBill.Taylor@Sun.COM 	num_eq_unmap++;
2809517SBill.Taylor@Sun.COM 
2819517SBill.Taylor@Sun.COM 	/* the FMA retry loop starts. */
2829517SBill.Taylor@Sun.COM 	hermon_pio_start(state, uarhdl, all_eq_init_fail, fm_loop_cnt,
2839517SBill.Taylor@Sun.COM 	    fm_status, fm_test);
2849517SBill.Taylor@Sun.COM 
2859517SBill.Taylor@Sun.COM 	/*
2869517SBill.Taylor@Sun.COM 	 * Run through and initialize the Consumer Index for each EQC.
2879517SBill.Taylor@Sun.COM 	 */
2889517SBill.Taylor@Sun.COM 	for (i = 0; i < num_eq + num_extra; i++) {
289*12965SWilliam.Taylor@Oracle.COM 		ddi_put32(uarhdl, eq[i]->eq_doorbell, 0x0);
2909517SBill.Taylor@Sun.COM 	}
2919517SBill.Taylor@Sun.COM 
2929517SBill.Taylor@Sun.COM 	/* the FMA retry loop ends. */
2939517SBill.Taylor@Sun.COM 	hermon_pio_end(state, uarhdl, all_eq_init_fail, fm_loop_cnt,
2949517SBill.Taylor@Sun.COM 	    fm_status, fm_test);
2959517SBill.Taylor@Sun.COM 
2969517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
2979517SBill.Taylor@Sun.COM 
2989517SBill.Taylor@Sun.COM all_eq_init_fail:
2999517SBill.Taylor@Sun.COM 
3009517SBill.Taylor@Sun.COM 	/* Unmap any of the partially mapped EQs from above */
3019517SBill.Taylor@Sun.COM 	for (i = 0; i < num_eq_unmap + num_extra; i++) {
302*12965SWilliam.Taylor@Oracle.COM 		(void) hermon_eq_handler_fini(state, eq[i]);
3039517SBill.Taylor@Sun.COM 	}
3049517SBill.Taylor@Sun.COM 
3059517SBill.Taylor@Sun.COM 	/* Free up any of the partially allocated EQs from above */
3069517SBill.Taylor@Sun.COM 	for (i = 0; i < num_eq_init + num_extra; i++) {
307*12965SWilliam.Taylor@Oracle.COM 		(void) hermon_eq_free(state, &eq[i]);
3089517SBill.Taylor@Sun.COM 	}
3099517SBill.Taylor@Sun.COM 
3109517SBill.Taylor@Sun.COM 	/* If a HW error happen during ddi_pio, return DDI_FAILURE */
3119517SBill.Taylor@Sun.COM 	if (fm_status == HCA_PIO_PERSISTENT) {
3129517SBill.Taylor@Sun.COM 		hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_NON_FATAL);
3139517SBill.Taylor@Sun.COM 		status = DDI_FAILURE;
3149517SBill.Taylor@Sun.COM 	}
3159517SBill.Taylor@Sun.COM 
3169517SBill.Taylor@Sun.COM 	return (status);
3179517SBill.Taylor@Sun.COM }
3189517SBill.Taylor@Sun.COM 
3199517SBill.Taylor@Sun.COM 
3209517SBill.Taylor@Sun.COM /*
3219517SBill.Taylor@Sun.COM  * hermon_eq_fini_all
3229517SBill.Taylor@Sun.COM  *    Context: Only called from attach() and/or detach() path contexts
3239517SBill.Taylor@Sun.COM  */
3249517SBill.Taylor@Sun.COM int
hermon_eq_fini_all(hermon_state_t * state)3259517SBill.Taylor@Sun.COM hermon_eq_fini_all(hermon_state_t *state)
3269517SBill.Taylor@Sun.COM {
3279517SBill.Taylor@Sun.COM 	uint_t		num_eq, num_eq_rsvd;
3289517SBill.Taylor@Sun.COM 	int		status, i;
329*12965SWilliam.Taylor@Oracle.COM 	struct hermon_sw_eq_s **eq;
3309517SBill.Taylor@Sun.COM 
3319517SBill.Taylor@Sun.COM 	/*
3329517SBill.Taylor@Sun.COM 	 * Grab the total number of supported EQs again.  This is the same
3339517SBill.Taylor@Sun.COM 	 * hardcoded value that was used above (during the event queue
3349517SBill.Taylor@Sun.COM 	 * initialization.)
3359517SBill.Taylor@Sun.COM 	 */
3369517SBill.Taylor@Sun.COM 	num_eq = HERMON_NUM_EQ_USED + state->hs_intrmsi_allocd - 1;
337*12965SWilliam.Taylor@Oracle.COM 	num_eq_rsvd = state->hs_rsvd_eqs;
338*12965SWilliam.Taylor@Oracle.COM 	eq = &state->hs_eqhdl[num_eq_rsvd];
3399517SBill.Taylor@Sun.COM 
3409517SBill.Taylor@Sun.COM 	/*
3419517SBill.Taylor@Sun.COM 	 * For each of the event queues that we initialized and mapped
3429517SBill.Taylor@Sun.COM 	 * earlier, attempt to unmap the events from the EQ.
3439517SBill.Taylor@Sun.COM 	 */
3449517SBill.Taylor@Sun.COM 	for (i = 0; i < num_eq; i++) {
345*12965SWilliam.Taylor@Oracle.COM 		status = hermon_eq_handler_fini(state, eq[i]);
3469517SBill.Taylor@Sun.COM 		if (status != DDI_SUCCESS) {
3479517SBill.Taylor@Sun.COM 			return (DDI_FAILURE);
3489517SBill.Taylor@Sun.COM 		}
3499517SBill.Taylor@Sun.COM 	}
3509517SBill.Taylor@Sun.COM 
3519517SBill.Taylor@Sun.COM 	/*
3529517SBill.Taylor@Sun.COM 	 * Teardown and free up all the Event Queues that were allocated
3539517SBill.Taylor@Sun.COM 	 * earlier.
3549517SBill.Taylor@Sun.COM 	 */
3559517SBill.Taylor@Sun.COM 	for (i = 0; i < num_eq; i++) {
356*12965SWilliam.Taylor@Oracle.COM 		status = hermon_eq_free(state, &eq[i]);
3579517SBill.Taylor@Sun.COM 		if (status != DDI_SUCCESS) {
3589517SBill.Taylor@Sun.COM 			return (DDI_FAILURE);
3599517SBill.Taylor@Sun.COM 		}
3609517SBill.Taylor@Sun.COM 	}
3619517SBill.Taylor@Sun.COM 
3629517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
3639517SBill.Taylor@Sun.COM }
3649517SBill.Taylor@Sun.COM 
365*12965SWilliam.Taylor@Oracle.COM 
3669517SBill.Taylor@Sun.COM /*
367*12965SWilliam.Taylor@Oracle.COM  * hermon_eq_reset_uar_baseaddr
368*12965SWilliam.Taylor@Oracle.COM  *    Context: Only called from attach()
3699517SBill.Taylor@Sun.COM  */
3709517SBill.Taylor@Sun.COM void
hermon_eq_reset_uar_baseaddr(hermon_state_t * state)371*12965SWilliam.Taylor@Oracle.COM hermon_eq_reset_uar_baseaddr(hermon_state_t *state)
3729517SBill.Taylor@Sun.COM {
373*12965SWilliam.Taylor@Oracle.COM 	int i, num_eq;
374*12965SWilliam.Taylor@Oracle.COM 	hermon_eqhdl_t eq, *eqh;
3759517SBill.Taylor@Sun.COM 
376*12965SWilliam.Taylor@Oracle.COM 	num_eq = HERMON_NUM_EQ_USED + state->hs_intrmsi_allocd - 1;
377*12965SWilliam.Taylor@Oracle.COM 	eqh = &state->hs_eqhdl[state->hs_rsvd_eqs];
378*12965SWilliam.Taylor@Oracle.COM 	for (i = 0; i < num_eq; i++) {
379*12965SWilliam.Taylor@Oracle.COM 		eq = eqh[i];
380*12965SWilliam.Taylor@Oracle.COM 		eq->eq_doorbell = (uint32_t *)
381*12965SWilliam.Taylor@Oracle.COM 		    ((uintptr_t)state->hs_reg_uar_baseaddr +
382*12965SWilliam.Taylor@Oracle.COM 		    (uint32_t)ARM_EQ_INDEX(eq->eq_eqnum));
383*12965SWilliam.Taylor@Oracle.COM 	}
3849517SBill.Taylor@Sun.COM }
3859517SBill.Taylor@Sun.COM 
3869517SBill.Taylor@Sun.COM 
3879517SBill.Taylor@Sun.COM /*
3889517SBill.Taylor@Sun.COM  * hermon_eq_arm_all
3899517SBill.Taylor@Sun.COM  *    Context: Only called from attach() and/or detach() path contexts
3909517SBill.Taylor@Sun.COM  */
3919517SBill.Taylor@Sun.COM int
hermon_eq_arm_all(hermon_state_t * state)3929517SBill.Taylor@Sun.COM hermon_eq_arm_all(hermon_state_t *state)
3939517SBill.Taylor@Sun.COM {
3949517SBill.Taylor@Sun.COM 	uint_t		num_eq, num_eq_rsvd;
3959517SBill.Taylor@Sun.COM 	uint64_t	offset;
3969517SBill.Taylor@Sun.COM 	hermon_eqhdl_t	eq;
3979517SBill.Taylor@Sun.COM 	uint32_t	eq_ci;
3989517SBill.Taylor@Sun.COM 	int		i;
3999517SBill.Taylor@Sun.COM 	ddi_acc_handle_t uarhdl = hermon_get_uarhdl(state);
4009517SBill.Taylor@Sun.COM 
4019517SBill.Taylor@Sun.COM 	/* initialize the FMA retry loop */
4029517SBill.Taylor@Sun.COM 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
4039517SBill.Taylor@Sun.COM 
404*12965SWilliam.Taylor@Oracle.COM 	num_eq = HERMON_NUM_EQ_USED + state->hs_intrmsi_allocd - 1;
405*12965SWilliam.Taylor@Oracle.COM 	num_eq_rsvd = state->hs_rsvd_eqs;
4069517SBill.Taylor@Sun.COM 
4079517SBill.Taylor@Sun.COM 	/* the FMA retry loop starts. */
4089517SBill.Taylor@Sun.COM 	hermon_pio_start(state, uarhdl, pio_error, fm_loop_cnt, fm_status,
4099517SBill.Taylor@Sun.COM 	    fm_test);
4109517SBill.Taylor@Sun.COM 
4119517SBill.Taylor@Sun.COM 	for (i = 0; i < num_eq; i++) {
4129517SBill.Taylor@Sun.COM 		offset = ARM_EQ_INDEX(i + num_eq_rsvd);
4139517SBill.Taylor@Sun.COM 		eq = state->hs_eqhdl[i + num_eq_rsvd];
4149517SBill.Taylor@Sun.COM 		eq_ci = (eq->eq_consindx & HERMON_EQ_CI_MASK) | EQ_ARM_BIT;
4159517SBill.Taylor@Sun.COM 		ddi_put32(uarhdl,
4169517SBill.Taylor@Sun.COM 		    (uint32_t *)((uintptr_t)state->hs_reg_uar_baseaddr +
4179517SBill.Taylor@Sun.COM 		    (uint32_t)offset), eq_ci);
4189517SBill.Taylor@Sun.COM 	}
4199517SBill.Taylor@Sun.COM 
4209517SBill.Taylor@Sun.COM 	/* the FMA retry loop ends. */
4219517SBill.Taylor@Sun.COM 	hermon_pio_end(state, uarhdl, pio_error, fm_loop_cnt, fm_status,
4229517SBill.Taylor@Sun.COM 	    fm_test);
4239517SBill.Taylor@Sun.COM 
4249517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
4259517SBill.Taylor@Sun.COM 
4269517SBill.Taylor@Sun.COM pio_error:
4279517SBill.Taylor@Sun.COM 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_NON_FATAL);
4289517SBill.Taylor@Sun.COM 	return (DDI_FAILURE);
4299517SBill.Taylor@Sun.COM }
4309517SBill.Taylor@Sun.COM 
4319517SBill.Taylor@Sun.COM 
4329517SBill.Taylor@Sun.COM /*
4339517SBill.Taylor@Sun.COM  * hermon_isr()
4349517SBill.Taylor@Sun.COM  *    Context: Only called from interrupt context (and during panic)
4359517SBill.Taylor@Sun.COM  */
4369517SBill.Taylor@Sun.COM uint_t
hermon_isr(caddr_t arg1,caddr_t arg2)4379517SBill.Taylor@Sun.COM hermon_isr(caddr_t arg1, caddr_t arg2)
4389517SBill.Taylor@Sun.COM {
4399517SBill.Taylor@Sun.COM 	hermon_state_t	*state;
4409517SBill.Taylor@Sun.COM 	int		i, r;
4419517SBill.Taylor@Sun.COM 	int		intr;
4429517SBill.Taylor@Sun.COM 
4439517SBill.Taylor@Sun.COM 	/*
4449517SBill.Taylor@Sun.COM 	 * Grab the Hermon softstate pointer from the input parameter
4459517SBill.Taylor@Sun.COM 	 */
4469517SBill.Taylor@Sun.COM 	state	= (hermon_state_t *)(void *)arg1;
4479517SBill.Taylor@Sun.COM 
4489517SBill.Taylor@Sun.COM 	/* Get the interrupt number */
4499517SBill.Taylor@Sun.COM 	intr = (int)(uintptr_t)arg2;
4509517SBill.Taylor@Sun.COM 
4519517SBill.Taylor@Sun.COM 	/*
4529517SBill.Taylor@Sun.COM 	 * Clear the interrupt.  Note: This is only needed for
4539517SBill.Taylor@Sun.COM 	 * fixed interrupts as the framework does what is needed for
4549517SBill.Taylor@Sun.COM 	 * MSI-X interrupts.
4559517SBill.Taylor@Sun.COM 	 */
4569517SBill.Taylor@Sun.COM 	if (state->hs_intr_type_chosen == DDI_INTR_TYPE_FIXED) {
4579517SBill.Taylor@Sun.COM 		ddi_acc_handle_t cmdhdl = hermon_get_cmdhdl(state);
4589517SBill.Taylor@Sun.COM 
4599517SBill.Taylor@Sun.COM 		/* initialize the FMA retry loop */
4609517SBill.Taylor@Sun.COM 		hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
4619517SBill.Taylor@Sun.COM 
4629517SBill.Taylor@Sun.COM 		/* the FMA retry loop starts. */
4639517SBill.Taylor@Sun.COM 		hermon_pio_start(state, cmdhdl, pio_error, fm_loop_cnt,
4649517SBill.Taylor@Sun.COM 		    fm_status, fm_test);
4659517SBill.Taylor@Sun.COM 
4669517SBill.Taylor@Sun.COM 		ddi_put64(cmdhdl, state->hs_cmd_regs.clr_intr,
4679517SBill.Taylor@Sun.COM 		    (uint64_t)1 << state->hs_adapter.inta_pin);
4689517SBill.Taylor@Sun.COM 
4699517SBill.Taylor@Sun.COM 		/* the FMA retry loop ends. */
4709517SBill.Taylor@Sun.COM 		hermon_pio_end(state, cmdhdl, pio_error, fm_loop_cnt, fm_status,
4719517SBill.Taylor@Sun.COM 		    fm_test);
4729517SBill.Taylor@Sun.COM 	}
4739517SBill.Taylor@Sun.COM 
4749517SBill.Taylor@Sun.COM 	/*
4759517SBill.Taylor@Sun.COM 	 * Loop through all the EQs looking for ones that have "fired".
4769517SBill.Taylor@Sun.COM 	 * To determine if an EQ is fired, the ownership will be the SW
4779517SBill.Taylor@Sun.COM 	 * (the HW will set the owner appropriately). Update the Consumer Index
4789517SBill.Taylor@Sun.COM 	 * of the Event Queue Entry (EQE) and pass it to HW by writing it
4799517SBill.Taylor@Sun.COM 	 * to the respective Set CI DB Register.
4809517SBill.Taylor@Sun.COM 	 *
4819517SBill.Taylor@Sun.COM 	 * The "else" case handles the extra EQs used only for completion
4829517SBill.Taylor@Sun.COM 	 * events, whereas the "if" case deals with the required interrupt
4839517SBill.Taylor@Sun.COM 	 * vector that is used for all classes of events.
4849517SBill.Taylor@Sun.COM 	 */
485*12965SWilliam.Taylor@Oracle.COM 	r = state->hs_rsvd_eqs;
4869517SBill.Taylor@Sun.COM 
4879517SBill.Taylor@Sun.COM 	if (intr + 1 == state->hs_intrmsi_allocd) {	/* last intr */
4889517SBill.Taylor@Sun.COM 		r += state->hs_intrmsi_allocd - 1;
4899517SBill.Taylor@Sun.COM 		for (i = 0; i < HERMON_NUM_EQ_USED; i++) {
4909517SBill.Taylor@Sun.COM 			hermon_eq_poll(state, state->hs_eqhdl[i + r]);
4919517SBill.Taylor@Sun.COM 		}
4929517SBill.Taylor@Sun.COM 	} else {	/* only poll the one EQ */
4939517SBill.Taylor@Sun.COM 		hermon_eq_poll(state, state->hs_eqhdl[intr + r]);
4949517SBill.Taylor@Sun.COM 	}
4959517SBill.Taylor@Sun.COM 
4969517SBill.Taylor@Sun.COM 	return (DDI_INTR_CLAIMED);
4979517SBill.Taylor@Sun.COM 
4989517SBill.Taylor@Sun.COM pio_error:
4999517SBill.Taylor@Sun.COM 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_FATAL);
5009517SBill.Taylor@Sun.COM 	return (DDI_INTR_UNCLAIMED);
5019517SBill.Taylor@Sun.COM }
5029517SBill.Taylor@Sun.COM 
5039517SBill.Taylor@Sun.COM 
5049517SBill.Taylor@Sun.COM /*
5059517SBill.Taylor@Sun.COM  * hermon_eq_poll
5069517SBill.Taylor@Sun.COM  *    Context: Only called from interrupt context (and during panic)
5079517SBill.Taylor@Sun.COM  */
5089517SBill.Taylor@Sun.COM static void
hermon_eq_poll(hermon_state_t * state,hermon_eqhdl_t eq)5099517SBill.Taylor@Sun.COM hermon_eq_poll(hermon_state_t *state, hermon_eqhdl_t eq)
5109517SBill.Taylor@Sun.COM {
5119517SBill.Taylor@Sun.COM 	hermon_hw_eqe_t	*eqe;
5129517SBill.Taylor@Sun.COM 	int		polled_some;
513*12965SWilliam.Taylor@Oracle.COM 	uint32_t	cons_indx, wrap_around_mask, shift;
5149517SBill.Taylor@Sun.COM 	int (*eqfunction)(hermon_state_t *state, hermon_eqhdl_t eq,
5159517SBill.Taylor@Sun.COM 	    hermon_hw_eqe_t *eqe);
5169517SBill.Taylor@Sun.COM 	ddi_acc_handle_t uarhdl = hermon_get_uarhdl(state);
5179517SBill.Taylor@Sun.COM 
5189517SBill.Taylor@Sun.COM 	/* initialize the FMA retry loop */
5199517SBill.Taylor@Sun.COM 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
5209517SBill.Taylor@Sun.COM 
5219517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*eq))
5229517SBill.Taylor@Sun.COM 
5239517SBill.Taylor@Sun.COM 	/* Get the consumer pointer index */
5249517SBill.Taylor@Sun.COM 	cons_indx = eq->eq_consindx;
525*12965SWilliam.Taylor@Oracle.COM 	shift = eq->eq_log_eqsz - HERMON_EQE_OWNER_SHIFT;
5269517SBill.Taylor@Sun.COM 
5279517SBill.Taylor@Sun.COM 	/*
5289517SBill.Taylor@Sun.COM 	 * Calculate the wrap around mask.  Note: This operation only works
5299517SBill.Taylor@Sun.COM 	 * because all Hermon event queues have power-of-2 sizes
5309517SBill.Taylor@Sun.COM 	 */
5319517SBill.Taylor@Sun.COM 	wrap_around_mask = (eq->eq_bufsz - 1);
5329517SBill.Taylor@Sun.COM 
5339517SBill.Taylor@Sun.COM 	/* Calculate the pointer to the first EQ entry */
5349517SBill.Taylor@Sun.COM 	eqe = &eq->eq_buf[(cons_indx & wrap_around_mask)];
5359517SBill.Taylor@Sun.COM 
5369517SBill.Taylor@Sun.COM 
5379517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*eqe))
5389517SBill.Taylor@Sun.COM 
5399517SBill.Taylor@Sun.COM 	/*
5409517SBill.Taylor@Sun.COM 	 * Pull the handler function for this EQ from the Hermon Event Queue
5419517SBill.Taylor@Sun.COM 	 * handle
5429517SBill.Taylor@Sun.COM 	 */
5439517SBill.Taylor@Sun.COM 	eqfunction = eq->eq_func;
5449517SBill.Taylor@Sun.COM 
5459517SBill.Taylor@Sun.COM 	for (;;) {
5469517SBill.Taylor@Sun.COM 		polled_some = 0;
547*12965SWilliam.Taylor@Oracle.COM 		while (HERMON_EQE_OWNER_IS_SW(eq, eqe, cons_indx, shift)) {
5489517SBill.Taylor@Sun.COM 
5499517SBill.Taylor@Sun.COM 			/*
5509517SBill.Taylor@Sun.COM 			 * Call the EQ handler function.  But only call if we
5519517SBill.Taylor@Sun.COM 			 * are not in polled I/O mode (i.e. not processing
5529517SBill.Taylor@Sun.COM 			 * because of a system panic).  Note: We don't call
5539517SBill.Taylor@Sun.COM 			 * the EQ handling functions from a system panic
5549517SBill.Taylor@Sun.COM 			 * because we are primarily concerned only with
5559517SBill.Taylor@Sun.COM 			 * ensuring that the event queues do not overflow (or,
5569517SBill.Taylor@Sun.COM 			 * more specifically, the event queue associated with
5579517SBill.Taylor@Sun.COM 			 * the CQ that is being used in the sync/dump process).
5589517SBill.Taylor@Sun.COM 			 * Also, we don't want to make any upcalls (to the
5599517SBill.Taylor@Sun.COM 			 * IBTF) because we can't guarantee when/if those
5609517SBill.Taylor@Sun.COM 			 * calls would ever return.  And, if we're in panic,
5619517SBill.Taylor@Sun.COM 			 * then we reached here through a PollCQ() call (from
5629517SBill.Taylor@Sun.COM 			 * hermon_cq_poll()), and we need to ensure that we
5639517SBill.Taylor@Sun.COM 			 * successfully return any work completions to the
5649517SBill.Taylor@Sun.COM 			 * caller.
5659517SBill.Taylor@Sun.COM 			 */
5669517SBill.Taylor@Sun.COM 			if (ddi_in_panic() == 0) {
5679517SBill.Taylor@Sun.COM 				eqfunction(state, eq, eqe);
5689517SBill.Taylor@Sun.COM 			}
5699517SBill.Taylor@Sun.COM 
5709517SBill.Taylor@Sun.COM 			/* Reset to hardware ownership is implicit */
5719517SBill.Taylor@Sun.COM 
5729517SBill.Taylor@Sun.COM 			/* Increment the consumer index */
5739517SBill.Taylor@Sun.COM 			cons_indx++;
5749517SBill.Taylor@Sun.COM 
5759517SBill.Taylor@Sun.COM 			/* Update the pointer to the next EQ entry */
5769517SBill.Taylor@Sun.COM 			eqe = &eq->eq_buf[(cons_indx & wrap_around_mask)];
5779517SBill.Taylor@Sun.COM 
5789517SBill.Taylor@Sun.COM 			polled_some = 1;
5799517SBill.Taylor@Sun.COM 		}
5809517SBill.Taylor@Sun.COM 
5819517SBill.Taylor@Sun.COM 		/*
5829517SBill.Taylor@Sun.COM 		 * write consumer index via EQ set CI Doorbell, to keep overflow
5839517SBill.Taylor@Sun.COM 		 * from occuring during poll
5849517SBill.Taylor@Sun.COM 		 */
5859517SBill.Taylor@Sun.COM 
5869517SBill.Taylor@Sun.COM 		eq->eq_consindx = cons_indx;
5879517SBill.Taylor@Sun.COM 
5889517SBill.Taylor@Sun.COM 		/* the FMA retry loop starts. */
5899517SBill.Taylor@Sun.COM 		hermon_pio_start(state, uarhdl, pio_error, fm_loop_cnt,
5909517SBill.Taylor@Sun.COM 		    fm_status, fm_test);
5919517SBill.Taylor@Sun.COM 
592*12965SWilliam.Taylor@Oracle.COM 		ddi_put32(uarhdl, eq->eq_doorbell,
593*12965SWilliam.Taylor@Oracle.COM 		    (cons_indx & HERMON_EQ_CI_MASK) | EQ_ARM_BIT);
5949517SBill.Taylor@Sun.COM 
5959517SBill.Taylor@Sun.COM 		/* the FMA retry loop starts. */
5969517SBill.Taylor@Sun.COM 		hermon_pio_end(state, uarhdl, pio_error, fm_loop_cnt,
5979517SBill.Taylor@Sun.COM 		    fm_status, fm_test);
5989517SBill.Taylor@Sun.COM 
5999517SBill.Taylor@Sun.COM 		if (polled_some == 0)
6009517SBill.Taylor@Sun.COM 			break;
6019517SBill.Taylor@Sun.COM 	};
6029517SBill.Taylor@Sun.COM 	return;
6039517SBill.Taylor@Sun.COM 
6049517SBill.Taylor@Sun.COM pio_error:
6059517SBill.Taylor@Sun.COM 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_FATAL);
6069517SBill.Taylor@Sun.COM }
6079517SBill.Taylor@Sun.COM 
6089517SBill.Taylor@Sun.COM 
6099517SBill.Taylor@Sun.COM /*
6109517SBill.Taylor@Sun.COM  * hermon_eq_catastrophic
6119517SBill.Taylor@Sun.COM  *    Context: Only called from interrupt context (and during panic)
6129517SBill.Taylor@Sun.COM  */
6139517SBill.Taylor@Sun.COM static void
hermon_eq_catastrophic(hermon_state_t * state)6149517SBill.Taylor@Sun.COM hermon_eq_catastrophic(hermon_state_t *state)
6159517SBill.Taylor@Sun.COM {
6169517SBill.Taylor@Sun.COM 	ddi_acc_handle_t	cmdhdl = hermon_get_cmdhdl(state);
6179517SBill.Taylor@Sun.COM 	ibt_async_code_t	type;
6189517SBill.Taylor@Sun.COM 	ibc_async_event_t	event;
6199517SBill.Taylor@Sun.COM 	uint32_t		*base_addr;
6209517SBill.Taylor@Sun.COM 	uint32_t		buf_size;
6219517SBill.Taylor@Sun.COM 	uint32_t		word;
6229517SBill.Taylor@Sun.COM 	uint8_t			err_type;
6239517SBill.Taylor@Sun.COM 	uint32_t		err_buf;
6249517SBill.Taylor@Sun.COM 	int			i;
6259517SBill.Taylor@Sun.COM 
6269517SBill.Taylor@Sun.COM 	/* initialize the FMA retry loop */
6279517SBill.Taylor@Sun.COM 	hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
6289517SBill.Taylor@Sun.COM 
6299517SBill.Taylor@Sun.COM 	bzero(&event, sizeof (ibc_async_event_t));
6309517SBill.Taylor@Sun.COM 	base_addr = state->hs_cmd_regs.fw_err_buf;
6319517SBill.Taylor@Sun.COM 
6329517SBill.Taylor@Sun.COM 	buf_size = state->hs_fw.error_buf_sz;	/* in #dwords */
6339517SBill.Taylor@Sun.COM 
6349517SBill.Taylor@Sun.COM 	/* the FMA retry loop starts. */
6359517SBill.Taylor@Sun.COM 	hermon_pio_start(state, cmdhdl, pio_error, fm_loop_cnt, fm_status,
6369517SBill.Taylor@Sun.COM 	    fm_test);
6379517SBill.Taylor@Sun.COM 
6389517SBill.Taylor@Sun.COM 	word = ddi_get32(cmdhdl, base_addr);
6399517SBill.Taylor@Sun.COM 
6409517SBill.Taylor@Sun.COM 	/* the FMA retry loop ends. */
6419517SBill.Taylor@Sun.COM 	hermon_pio_end(state, cmdhdl, pio_error, fm_loop_cnt, fm_status,
6429517SBill.Taylor@Sun.COM 	    fm_test);
6439517SBill.Taylor@Sun.COM 
6449517SBill.Taylor@Sun.COM 	err_type = (word & 0xFF000000) >> 24;
6459517SBill.Taylor@Sun.COM 	type	 = IBT_ERROR_LOCAL_CATASTROPHIC;
6469517SBill.Taylor@Sun.COM 
6479517SBill.Taylor@Sun.COM 	switch (err_type) {
6489517SBill.Taylor@Sun.COM 	case HERMON_CATASTROPHIC_INTERNAL_ERROR:
6499517SBill.Taylor@Sun.COM 		cmn_err(CE_WARN, "Catastrophic Internal Error: 0x%02x",
6509517SBill.Taylor@Sun.COM 		    err_type);
6519517SBill.Taylor@Sun.COM 
6529517SBill.Taylor@Sun.COM 		break;
6539517SBill.Taylor@Sun.COM 
6549517SBill.Taylor@Sun.COM 	case HERMON_CATASTROPHIC_UPLINK_BUS_ERROR:
6559517SBill.Taylor@Sun.COM 		cmn_err(CE_WARN, "Catastrophic Uplink Bus Error: 0x%02x",
6569517SBill.Taylor@Sun.COM 		    err_type);
6579517SBill.Taylor@Sun.COM 
6589517SBill.Taylor@Sun.COM 		break;
6599517SBill.Taylor@Sun.COM 
6609517SBill.Taylor@Sun.COM 	case HERMON_CATASTROPHIC_DDR_DATA_ERROR:
6619517SBill.Taylor@Sun.COM 		cmn_err(CE_WARN, "Catastrophic DDR Data Error: 0x%02x",
6629517SBill.Taylor@Sun.COM 		    err_type);
6639517SBill.Taylor@Sun.COM 
6649517SBill.Taylor@Sun.COM 		break;
6659517SBill.Taylor@Sun.COM 
6669517SBill.Taylor@Sun.COM 	case HERMON_CATASTROPHIC_INTERNAL_PARITY_ERROR:
6679517SBill.Taylor@Sun.COM 		cmn_err(CE_WARN, "Catastrophic Internal Parity Error: 0x%02x",
6689517SBill.Taylor@Sun.COM 		    err_type);
6699517SBill.Taylor@Sun.COM 
6709517SBill.Taylor@Sun.COM 		break;
6719517SBill.Taylor@Sun.COM 
6729517SBill.Taylor@Sun.COM 	default:
6739517SBill.Taylor@Sun.COM 		/* Unknown type of Catastrophic error */
6749517SBill.Taylor@Sun.COM 		cmn_err(CE_WARN, "Catastrophic Unknown Error: 0x%02x",
6759517SBill.Taylor@Sun.COM 		    err_type);
6769517SBill.Taylor@Sun.COM 
6779517SBill.Taylor@Sun.COM 		break;
6789517SBill.Taylor@Sun.COM 	}
6799517SBill.Taylor@Sun.COM 
6809517SBill.Taylor@Sun.COM 	/* the FMA retry loop starts. */
6819517SBill.Taylor@Sun.COM 	hermon_pio_start(state, cmdhdl, pio_error, fm_loop_cnt, fm_status,
6829517SBill.Taylor@Sun.COM 	    fm_test);
6839517SBill.Taylor@Sun.COM 
6849517SBill.Taylor@Sun.COM 	/*
6859517SBill.Taylor@Sun.COM 	 * Read in the catastrophic error buffer from the hardware.
6869517SBill.Taylor@Sun.COM 	 */
6879517SBill.Taylor@Sun.COM 	for (i = 0; i < buf_size; i++) {
6889517SBill.Taylor@Sun.COM 		base_addr =
6899517SBill.Taylor@Sun.COM 		    (state->hs_cmd_regs.fw_err_buf + i);
6909517SBill.Taylor@Sun.COM 		err_buf = ddi_get32(cmdhdl, base_addr);
6919517SBill.Taylor@Sun.COM 		cmn_err(CE_NOTE, "hermon%d: catastrophic_error[%02x]: %08X",
6929517SBill.Taylor@Sun.COM 		    state->hs_instance, i, err_buf);
6939517SBill.Taylor@Sun.COM 	}
6949517SBill.Taylor@Sun.COM 
6959517SBill.Taylor@Sun.COM 	/* the FMA retry loop ends. */
6969517SBill.Taylor@Sun.COM 	hermon_pio_end(state, cmdhdl, pio_error, fm_loop_cnt, fm_status,
6979517SBill.Taylor@Sun.COM 	    fm_test);
6989517SBill.Taylor@Sun.COM 
6999517SBill.Taylor@Sun.COM 	/*
7009517SBill.Taylor@Sun.COM 	 * We also call the IBTF here to inform it of the catastrophic error.
7019517SBill.Taylor@Sun.COM 	 * Note: Since no event information (i.e. QP handles, CQ handles,
7029517SBill.Taylor@Sun.COM 	 * etc.) is necessary, we pass a NULL pointer instead of a pointer to
7039517SBill.Taylor@Sun.COM 	 * an empty ibc_async_event_t struct.
7049517SBill.Taylor@Sun.COM 	 *
7059517SBill.Taylor@Sun.COM 	 * But we also check if "hs_ibtfpriv" is NULL.  If it is then it
7069517SBill.Taylor@Sun.COM 	 * means that we've have either received this event before we
7079517SBill.Taylor@Sun.COM 	 * finished attaching to the IBTF or we've received it while we
7089517SBill.Taylor@Sun.COM 	 * are in the process of detaching.
7099517SBill.Taylor@Sun.COM 	 */
7109517SBill.Taylor@Sun.COM 	if (state->hs_ibtfpriv != NULL) {
7119517SBill.Taylor@Sun.COM 		HERMON_DO_IBTF_ASYNC_CALLB(state, type, &event);
7129517SBill.Taylor@Sun.COM 	}
7139517SBill.Taylor@Sun.COM 
7149517SBill.Taylor@Sun.COM pio_error:
7159517SBill.Taylor@Sun.COM 	/* ignore these errors but log them because they're harmless. */
7169517SBill.Taylor@Sun.COM 	hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_NON_FATAL);
7179517SBill.Taylor@Sun.COM }
7189517SBill.Taylor@Sun.COM 
7199517SBill.Taylor@Sun.COM 
7209517SBill.Taylor@Sun.COM /*
7219517SBill.Taylor@Sun.COM  * hermon_eq_alloc()
7229517SBill.Taylor@Sun.COM  *    Context: Only called from attach() path context
7239517SBill.Taylor@Sun.COM  */
7249517SBill.Taylor@Sun.COM static int
hermon_eq_alloc(hermon_state_t * state,uint32_t log_eq_size,uint_t intr,hermon_eqhdl_t * eqhdl)7259517SBill.Taylor@Sun.COM hermon_eq_alloc(hermon_state_t *state, uint32_t log_eq_size, uint_t intr,
7269517SBill.Taylor@Sun.COM     hermon_eqhdl_t *eqhdl)
7279517SBill.Taylor@Sun.COM {
7289517SBill.Taylor@Sun.COM 	hermon_rsrc_t		*eqc, *rsrc;
7299517SBill.Taylor@Sun.COM 	hermon_hw_eqc_t		eqc_entry;
7309517SBill.Taylor@Sun.COM 	hermon_eqhdl_t		eq;
7319517SBill.Taylor@Sun.COM 	ibt_mr_attr_t		mr_attr;
7329517SBill.Taylor@Sun.COM 	hermon_mr_options_t	op;
7339517SBill.Taylor@Sun.COM 	hermon_pdhdl_t		pd;
7349517SBill.Taylor@Sun.COM 	hermon_mrhdl_t		mr;
7359517SBill.Taylor@Sun.COM 	hermon_hw_eqe_t		*buf;
7369517SBill.Taylor@Sun.COM 	int			status;
7379517SBill.Taylor@Sun.COM 
7389517SBill.Taylor@Sun.COM 	/* Use the internal protection domain (PD) for setting up EQs */
7399517SBill.Taylor@Sun.COM 	pd = state->hs_pdhdl_internal;
7409517SBill.Taylor@Sun.COM 
7419517SBill.Taylor@Sun.COM 	/* Increment the reference count on the protection domain (PD) */
7429517SBill.Taylor@Sun.COM 	hermon_pd_refcnt_inc(pd);
7439517SBill.Taylor@Sun.COM 
7449517SBill.Taylor@Sun.COM 	/*
7459517SBill.Taylor@Sun.COM 	 * Allocate an EQ context entry.  This will be filled in with all
7469517SBill.Taylor@Sun.COM 	 * the necessary parameters to define the Event Queue.  And then
7479517SBill.Taylor@Sun.COM 	 * ownership will be passed to the hardware in the final step
7489517SBill.Taylor@Sun.COM 	 * below.  If we fail here, we must undo the protection domain
7499517SBill.Taylor@Sun.COM 	 * reference count.
7509517SBill.Taylor@Sun.COM 	 */
7519517SBill.Taylor@Sun.COM 	status = hermon_rsrc_alloc(state, HERMON_EQC, 1, HERMON_SLEEP, &eqc);
7529517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
7539517SBill.Taylor@Sun.COM 		status = DDI_FAILURE;
7549517SBill.Taylor@Sun.COM 		goto eqalloc_fail1;
7559517SBill.Taylor@Sun.COM 	}
7569517SBill.Taylor@Sun.COM 
7579517SBill.Taylor@Sun.COM 	/*
7589517SBill.Taylor@Sun.COM 	 * Allocate the software structure for tracking the event queue (i.e.
7599517SBill.Taylor@Sun.COM 	 * the Hermon Event Queue handle).  If we fail here, we must undo the
7609517SBill.Taylor@Sun.COM 	 * protection domain reference count and the previous resource
7619517SBill.Taylor@Sun.COM 	 * allocation.
7629517SBill.Taylor@Sun.COM 	 */
7639517SBill.Taylor@Sun.COM 	status = hermon_rsrc_alloc(state, HERMON_EQHDL, 1, HERMON_SLEEP, &rsrc);
7649517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
7659517SBill.Taylor@Sun.COM 		status = DDI_FAILURE;
7669517SBill.Taylor@Sun.COM 		goto eqalloc_fail2;
7679517SBill.Taylor@Sun.COM 	}
7689517SBill.Taylor@Sun.COM 
7699517SBill.Taylor@Sun.COM 	eq = (hermon_eqhdl_t)rsrc->hr_addr;
7709517SBill.Taylor@Sun.COM 
7719517SBill.Taylor@Sun.COM 	/*
7729517SBill.Taylor@Sun.COM 	 * Allocate the memory for Event Queue.
7739517SBill.Taylor@Sun.COM 	 */
7749517SBill.Taylor@Sun.COM 	eq->eq_eqinfo.qa_size = (1 << log_eq_size) * sizeof (hermon_hw_eqe_t);
775*12965SWilliam.Taylor@Oracle.COM 	eq->eq_eqinfo.qa_alloc_align = eq->eq_eqinfo.qa_bind_align = PAGESIZE;
7769517SBill.Taylor@Sun.COM 
7779517SBill.Taylor@Sun.COM 	eq->eq_eqinfo.qa_location = HERMON_QUEUE_LOCATION_NORMAL;
7789517SBill.Taylor@Sun.COM 	status = hermon_queue_alloc(state, &eq->eq_eqinfo, HERMON_SLEEP);
7799517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
7809517SBill.Taylor@Sun.COM 		status = DDI_FAILURE;
7819517SBill.Taylor@Sun.COM 		goto eqalloc_fail3;
7829517SBill.Taylor@Sun.COM 	}
7839517SBill.Taylor@Sun.COM 
7849517SBill.Taylor@Sun.COM 	buf = (hermon_hw_eqe_t *)eq->eq_eqinfo.qa_buf_aligned;
7859517SBill.Taylor@Sun.COM 	/*
7869517SBill.Taylor@Sun.COM 	 * Initializing each of the Event Queue Entries (EQE) by setting their
7879517SBill.Taylor@Sun.COM 	 * ownership to hardware ("owner" bit set to HW) is now done by HW
7889517SBill.Taylor@Sun.COM 	 * when the transfer of ownership (below) of the
7899517SBill.Taylor@Sun.COM 	 * EQ context itself is done.
7909517SBill.Taylor@Sun.COM 	 */
7919517SBill.Taylor@Sun.COM 
7929517SBill.Taylor@Sun.COM 	/*
7939517SBill.Taylor@Sun.COM 	 * Register the memory for the EQ.
7949517SBill.Taylor@Sun.COM 	 *
7959517SBill.Taylor@Sun.COM 	 * Because we are in the attach path we use NOSLEEP here so that we
7969517SBill.Taylor@Sun.COM 	 * SPIN in the HCR since the event queues are not setup yet, and we
7979517SBill.Taylor@Sun.COM 	 * cannot NOSPIN at this point in time.
7989517SBill.Taylor@Sun.COM 	 */
7999517SBill.Taylor@Sun.COM 
8009517SBill.Taylor@Sun.COM 	mr_attr.mr_vaddr = (uint64_t)(uintptr_t)buf;
8019517SBill.Taylor@Sun.COM 	mr_attr.mr_len	 = eq->eq_eqinfo.qa_size;
8029517SBill.Taylor@Sun.COM 	mr_attr.mr_as	 = NULL;
8039517SBill.Taylor@Sun.COM 	mr_attr.mr_flags = IBT_MR_NOSLEEP | IBT_MR_ENABLE_LOCAL_WRITE;
8049517SBill.Taylor@Sun.COM 	op.mro_bind_type   = state->hs_cfg_profile->cp_iommu_bypass;
8059517SBill.Taylor@Sun.COM 	op.mro_bind_dmahdl = eq->eq_eqinfo.qa_dmahdl;
8069517SBill.Taylor@Sun.COM 	op.mro_bind_override_addr = 0;
8079517SBill.Taylor@Sun.COM 	status = hermon_mr_register(state, pd, &mr_attr, &mr, &op,
8089517SBill.Taylor@Sun.COM 	    HERMON_EQ_CMPT);
8099517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
8109517SBill.Taylor@Sun.COM 		status = DDI_FAILURE;
8119517SBill.Taylor@Sun.COM 		goto eqalloc_fail4;
8129517SBill.Taylor@Sun.COM 	}
8139517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mr))
8149517SBill.Taylor@Sun.COM 
8159517SBill.Taylor@Sun.COM 	/*
8169517SBill.Taylor@Sun.COM 	 * Fill in the EQC entry.  This is the final step before passing
8179517SBill.Taylor@Sun.COM 	 * ownership of the EQC entry to the Hermon hardware.  We use all of
8189517SBill.Taylor@Sun.COM 	 * the information collected/calculated above to fill in the
8199517SBill.Taylor@Sun.COM 	 * requisite portions of the EQC.  Note:  We create all EQs in the
8209517SBill.Taylor@Sun.COM 	 * "fired" state.  We will arm them later (after our interrupt
8219517SBill.Taylor@Sun.COM 	 * routine had been registered.)
8229517SBill.Taylor@Sun.COM 	 */
8239517SBill.Taylor@Sun.COM 	bzero(&eqc_entry, sizeof (hermon_hw_eqc_t));
8249517SBill.Taylor@Sun.COM 	eqc_entry.state		= HERMON_EQ_ARMED;
8259517SBill.Taylor@Sun.COM 	eqc_entry.log_eq_sz	= log_eq_size;
8269517SBill.Taylor@Sun.COM 	eqc_entry.intr		= intr;
8279517SBill.Taylor@Sun.COM 	eqc_entry.log2_pgsz	= mr->mr_log2_pgsz;
8289517SBill.Taylor@Sun.COM 	eqc_entry.pg_offs	= eq->eq_eqinfo.qa_pgoffs >> 5;
8299517SBill.Taylor@Sun.COM 	eqc_entry.mtt_base_addrh = (uint32_t)((mr->mr_mttaddr >> 32) & 0xFF);
8309517SBill.Taylor@Sun.COM 	eqc_entry.mtt_base_addrl =  mr->mr_mttaddr >> 3;
8319517SBill.Taylor@Sun.COM 	eqc_entry.cons_indx	= 0x0;
8329517SBill.Taylor@Sun.COM 	eqc_entry.prod_indx	= 0x0;
8339517SBill.Taylor@Sun.COM 
8349517SBill.Taylor@Sun.COM 	/*
8359517SBill.Taylor@Sun.COM 	 * Write the EQC entry to hardware.  Lastly, we pass ownership of
8369517SBill.Taylor@Sun.COM 	 * the entry to the hardware (using the Hermon SW2HW_EQ firmware
8379517SBill.Taylor@Sun.COM 	 * command).  Note: in general, this operation shouldn't fail.  But
8389517SBill.Taylor@Sun.COM 	 * if it does, we have to undo everything we've done above before
8399517SBill.Taylor@Sun.COM 	 * returning error.
8409517SBill.Taylor@Sun.COM 	 */
8419517SBill.Taylor@Sun.COM 	status = hermon_cmn_ownership_cmd_post(state, SW2HW_EQ, &eqc_entry,
8429517SBill.Taylor@Sun.COM 	    sizeof (hermon_hw_eqc_t), eqc->hr_indx, HERMON_CMD_NOSLEEP_SPIN);
8439517SBill.Taylor@Sun.COM 	if (status != HERMON_CMD_SUCCESS) {
8449517SBill.Taylor@Sun.COM 		cmn_err(CE_NOTE, "hermon%d: SW2HW_EQ command failed: %08x\n",
8459517SBill.Taylor@Sun.COM 		    state->hs_instance, status);
8469517SBill.Taylor@Sun.COM 		if (status == HERMON_CMD_INVALID_STATUS) {
8479517SBill.Taylor@Sun.COM 			hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
8489517SBill.Taylor@Sun.COM 		}
8499517SBill.Taylor@Sun.COM 		status = ibc_get_ci_failure(0);
8509517SBill.Taylor@Sun.COM 		goto eqalloc_fail5;
8519517SBill.Taylor@Sun.COM 	}
8529517SBill.Taylor@Sun.COM 
8539517SBill.Taylor@Sun.COM 	/*
8549517SBill.Taylor@Sun.COM 	 * Fill in the rest of the Hermon Event Queue handle.  Having
8559517SBill.Taylor@Sun.COM 	 * successfully transferred ownership of the EQC, we can update the
8569517SBill.Taylor@Sun.COM 	 * following fields for use in further operations on the EQ.
8579517SBill.Taylor@Sun.COM 	 */
8589517SBill.Taylor@Sun.COM 	eq->eq_eqcrsrcp	 = eqc;
8599517SBill.Taylor@Sun.COM 	eq->eq_rsrcp	 = rsrc;
8609517SBill.Taylor@Sun.COM 	eq->eq_consindx	 = 0;
8619517SBill.Taylor@Sun.COM 	eq->eq_eqnum	 = eqc->hr_indx;
8629517SBill.Taylor@Sun.COM 	eq->eq_buf	 = buf;
8639517SBill.Taylor@Sun.COM 	eq->eq_bufsz	 = (1 << log_eq_size);
8649517SBill.Taylor@Sun.COM 	eq->eq_log_eqsz	 = log_eq_size;
8659517SBill.Taylor@Sun.COM 	eq->eq_mrhdl	 = mr;
866*12965SWilliam.Taylor@Oracle.COM 	eq->eq_doorbell	 = (uint32_t *)((uintptr_t)state->hs_reg_uar_baseaddr +
867*12965SWilliam.Taylor@Oracle.COM 	    (uint32_t)ARM_EQ_INDEX(eq->eq_eqnum));
8689517SBill.Taylor@Sun.COM 	*eqhdl		 = eq;
8699517SBill.Taylor@Sun.COM 
8709517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
8719517SBill.Taylor@Sun.COM 
8729517SBill.Taylor@Sun.COM /*
8739517SBill.Taylor@Sun.COM  * The following is cleanup for all possible failure cases in this routine
8749517SBill.Taylor@Sun.COM  */
8759517SBill.Taylor@Sun.COM eqalloc_fail5:
8769517SBill.Taylor@Sun.COM 	if (hermon_mr_deregister(state, &mr, HERMON_MR_DEREG_ALL,
8779517SBill.Taylor@Sun.COM 	    HERMON_NOSLEEP) != DDI_SUCCESS) {
8789517SBill.Taylor@Sun.COM 		HERMON_WARNING(state, "failed to deregister EQ memory");
8799517SBill.Taylor@Sun.COM 	}
8809517SBill.Taylor@Sun.COM eqalloc_fail4:
8819517SBill.Taylor@Sun.COM 	hermon_queue_free(&eq->eq_eqinfo);
8829517SBill.Taylor@Sun.COM eqalloc_fail3:
8839517SBill.Taylor@Sun.COM 	hermon_rsrc_free(state, &rsrc);
8849517SBill.Taylor@Sun.COM eqalloc_fail2:
8859517SBill.Taylor@Sun.COM 	hermon_rsrc_free(state, &eqc);
8869517SBill.Taylor@Sun.COM eqalloc_fail1:
8879517SBill.Taylor@Sun.COM 	hermon_pd_refcnt_dec(pd);
8889517SBill.Taylor@Sun.COM eqalloc_fail:
8899517SBill.Taylor@Sun.COM 	return (status);
8909517SBill.Taylor@Sun.COM }
8919517SBill.Taylor@Sun.COM 
8929517SBill.Taylor@Sun.COM 
8939517SBill.Taylor@Sun.COM /*
8949517SBill.Taylor@Sun.COM  * hermon_eq_free()
8959517SBill.Taylor@Sun.COM  *    Context: Only called from attach() and/or detach() path contexts
8969517SBill.Taylor@Sun.COM  */
8979517SBill.Taylor@Sun.COM static int
hermon_eq_free(hermon_state_t * state,hermon_eqhdl_t * eqhdl)8989517SBill.Taylor@Sun.COM hermon_eq_free(hermon_state_t *state, hermon_eqhdl_t *eqhdl)
8999517SBill.Taylor@Sun.COM {
9009517SBill.Taylor@Sun.COM 	hermon_rsrc_t		*eqc, *rsrc;
9019517SBill.Taylor@Sun.COM 	hermon_hw_eqc_t		eqc_entry;
9029517SBill.Taylor@Sun.COM 	hermon_pdhdl_t		pd;
9039517SBill.Taylor@Sun.COM 	hermon_mrhdl_t		mr;
9049517SBill.Taylor@Sun.COM 	hermon_eqhdl_t		eq;
9059517SBill.Taylor@Sun.COM 	uint32_t		eqnum;
9069517SBill.Taylor@Sun.COM 	int			status;
9079517SBill.Taylor@Sun.COM 
9089517SBill.Taylor@Sun.COM 	/*
9099517SBill.Taylor@Sun.COM 	 * Pull all the necessary information from the Hermon Event Queue
9109517SBill.Taylor@Sun.COM 	 * handle.  This is necessary here because the resource for the
9119517SBill.Taylor@Sun.COM 	 * EQ handle is going to be freed up as part of this operation.
9129517SBill.Taylor@Sun.COM 	 */
9139517SBill.Taylor@Sun.COM 	eq	= *eqhdl;
9149517SBill.Taylor@Sun.COM 	eqc	= eq->eq_eqcrsrcp;
9159517SBill.Taylor@Sun.COM 	rsrc	= eq->eq_rsrcp;
9169517SBill.Taylor@Sun.COM 	pd	= state->hs_pdhdl_internal;
9179517SBill.Taylor@Sun.COM 	mr	= eq->eq_mrhdl;
9189517SBill.Taylor@Sun.COM 	eqnum	= eq->eq_eqnum;
9199517SBill.Taylor@Sun.COM 
9209517SBill.Taylor@Sun.COM 	/*
9219517SBill.Taylor@Sun.COM 	 * Reclaim EQC entry from hardware (using the Hermon HW2SW_EQ
9229517SBill.Taylor@Sun.COM 	 * firmware command).  If the ownership transfer fails for any reason,
9239517SBill.Taylor@Sun.COM 	 * then it is an indication that something (either in HW or SW) has
9249517SBill.Taylor@Sun.COM 	 * gone seriously wrong.
9259517SBill.Taylor@Sun.COM 	 */
9269517SBill.Taylor@Sun.COM 	status = hermon_cmn_ownership_cmd_post(state, HW2SW_EQ, &eqc_entry,
9279517SBill.Taylor@Sun.COM 	    sizeof (hermon_hw_eqc_t), eqnum, HERMON_CMD_NOSLEEP_SPIN);
9289517SBill.Taylor@Sun.COM 	if (status != HERMON_CMD_SUCCESS) {
9299517SBill.Taylor@Sun.COM 		HERMON_WARNING(state, "failed to reclaim EQC ownership");
9309517SBill.Taylor@Sun.COM 		cmn_err(CE_CONT, "Hermon: HW2SW_EQ command failed: %08x\n",
9319517SBill.Taylor@Sun.COM 		    status);
9329517SBill.Taylor@Sun.COM 		return (DDI_FAILURE);
9339517SBill.Taylor@Sun.COM 	}
9349517SBill.Taylor@Sun.COM 
9359517SBill.Taylor@Sun.COM 	/*
9369517SBill.Taylor@Sun.COM 	 * Deregister the memory for the Event Queue.  If this fails
9379517SBill.Taylor@Sun.COM 	 * for any reason, then it is an indication that something (either
9389517SBill.Taylor@Sun.COM 	 * in HW or SW) has gone seriously wrong.  So we print a warning
9399517SBill.Taylor@Sun.COM 	 * message and continue.
9409517SBill.Taylor@Sun.COM 	 */
9419517SBill.Taylor@Sun.COM 	status = hermon_mr_deregister(state, &mr, HERMON_MR_DEREG_ALL,
9429517SBill.Taylor@Sun.COM 	    HERMON_NOSLEEP);
9439517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
9449517SBill.Taylor@Sun.COM 		HERMON_WARNING(state, "failed to deregister EQ memory");
9459517SBill.Taylor@Sun.COM 	}
9469517SBill.Taylor@Sun.COM 
9479517SBill.Taylor@Sun.COM 	/* Free the memory for the EQ */
9489517SBill.Taylor@Sun.COM 	hermon_queue_free(&eq->eq_eqinfo);
9499517SBill.Taylor@Sun.COM 
9509517SBill.Taylor@Sun.COM 	/* Free the Hermon Event Queue handle */
9519517SBill.Taylor@Sun.COM 	hermon_rsrc_free(state, &rsrc);
9529517SBill.Taylor@Sun.COM 
9539517SBill.Taylor@Sun.COM 	/* Free up the EQC entry resource */
9549517SBill.Taylor@Sun.COM 	hermon_rsrc_free(state, &eqc);
9559517SBill.Taylor@Sun.COM 
9569517SBill.Taylor@Sun.COM 	/* Decrement the reference count on the protection domain (PD) */
9579517SBill.Taylor@Sun.COM 	hermon_pd_refcnt_dec(pd);
9589517SBill.Taylor@Sun.COM 
9599517SBill.Taylor@Sun.COM 	/* Set the eqhdl pointer to NULL and return success */
9609517SBill.Taylor@Sun.COM 	*eqhdl = NULL;
9619517SBill.Taylor@Sun.COM 
9629517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
9639517SBill.Taylor@Sun.COM }
9649517SBill.Taylor@Sun.COM 
9659517SBill.Taylor@Sun.COM 
9669517SBill.Taylor@Sun.COM /*
9679517SBill.Taylor@Sun.COM  * hermon_eq_handler_init
9689517SBill.Taylor@Sun.COM  *    Context: Only called from attach() path context
9699517SBill.Taylor@Sun.COM  */
9709517SBill.Taylor@Sun.COM static int
hermon_eq_handler_init(hermon_state_t * state,hermon_eqhdl_t eq,uint_t evt_type_mask,int (* eq_func)(hermon_state_t * state,hermon_eqhdl_t eq,hermon_hw_eqe_t * eqe))9719517SBill.Taylor@Sun.COM hermon_eq_handler_init(hermon_state_t *state, hermon_eqhdl_t eq,
9729517SBill.Taylor@Sun.COM     uint_t evt_type_mask, int (*eq_func)(hermon_state_t *state,
9739517SBill.Taylor@Sun.COM     hermon_eqhdl_t eq, hermon_hw_eqe_t *eqe))
9749517SBill.Taylor@Sun.COM {
9759517SBill.Taylor@Sun.COM 	int		status;
9769517SBill.Taylor@Sun.COM 
9779517SBill.Taylor@Sun.COM 	/*
9789517SBill.Taylor@Sun.COM 	 * Save away the EQ handler function and the event type mask.  These
9799517SBill.Taylor@Sun.COM 	 * will be used later during interrupt and event queue processing.
9809517SBill.Taylor@Sun.COM 	 */
9819517SBill.Taylor@Sun.COM 	eq->eq_func	   = eq_func;
9829517SBill.Taylor@Sun.COM 	eq->eq_evttypemask = evt_type_mask;
9839517SBill.Taylor@Sun.COM 
9849517SBill.Taylor@Sun.COM 	/*
9859517SBill.Taylor@Sun.COM 	 * Map the EQ to a specific class of event (or events) depending
9869517SBill.Taylor@Sun.COM 	 * on the mask value passed in.  The HERMON_EVT_NO_MASK means not
9879517SBill.Taylor@Sun.COM 	 * to attempt associating the EQ with any specific class of event.
9889517SBill.Taylor@Sun.COM 	 * This is particularly useful when initializing the events queues
9899517SBill.Taylor@Sun.COM 	 * used for CQ events.   The mapping is done using the Hermon MAP_EQ
9909517SBill.Taylor@Sun.COM 	 * firmware command.  Note: This command should not, in general, fail.
9919517SBill.Taylor@Sun.COM 	 * If it does, then something (probably HW related) has gone seriously
9929517SBill.Taylor@Sun.COM 	 * wrong.
9939517SBill.Taylor@Sun.COM 	 */
9949517SBill.Taylor@Sun.COM 	if (evt_type_mask != HERMON_EVT_NO_MASK) {
9959517SBill.Taylor@Sun.COM 		status = hermon_map_eq_cmd_post(state,
9969517SBill.Taylor@Sun.COM 		    HERMON_CMD_MAP_EQ_EVT_MAP, eq->eq_eqnum, evt_type_mask,
9979517SBill.Taylor@Sun.COM 		    HERMON_CMD_NOSLEEP_SPIN);
9989517SBill.Taylor@Sun.COM 		if (status != HERMON_CMD_SUCCESS) {
9999517SBill.Taylor@Sun.COM 			cmn_err(CE_NOTE, "hermon%d: MAP_EQ command failed: "
10009517SBill.Taylor@Sun.COM 			    "%08x\n", state->hs_instance, status);
10019517SBill.Taylor@Sun.COM 			return (DDI_FAILURE);
10029517SBill.Taylor@Sun.COM 		}
10039517SBill.Taylor@Sun.COM 	}
10049517SBill.Taylor@Sun.COM 
10059517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
10069517SBill.Taylor@Sun.COM }
10079517SBill.Taylor@Sun.COM 
10089517SBill.Taylor@Sun.COM 
10099517SBill.Taylor@Sun.COM /*
10109517SBill.Taylor@Sun.COM  * hermon_eq_handler_fini
10119517SBill.Taylor@Sun.COM  *    Context: Only called from attach() and/or detach() path contexts
10129517SBill.Taylor@Sun.COM  */
10139517SBill.Taylor@Sun.COM static int
hermon_eq_handler_fini(hermon_state_t * state,hermon_eqhdl_t eq)10149517SBill.Taylor@Sun.COM hermon_eq_handler_fini(hermon_state_t *state, hermon_eqhdl_t eq)
10159517SBill.Taylor@Sun.COM {
10169517SBill.Taylor@Sun.COM 	int			status;
10179517SBill.Taylor@Sun.COM 
10189517SBill.Taylor@Sun.COM 	/*
10199517SBill.Taylor@Sun.COM 	 * Unmap the EQ from the event class to which it had been previously
10209517SBill.Taylor@Sun.COM 	 * mapped.  The unmapping is done using the Hermon MAP_EQ (in much
10219517SBill.Taylor@Sun.COM 	 * the same way that the initial mapping was done).  The difference,
10229517SBill.Taylor@Sun.COM 	 * however, is in the HERMON_EQ_EVT_UNMAP flag that is passed to the
10239517SBill.Taylor@Sun.COM 	 * MAP_EQ firmware command.  The HERMON_EVT_NO_MASK (which may have
10249517SBill.Taylor@Sun.COM 	 * been passed in at init time) still means that no association has
10259517SBill.Taylor@Sun.COM 	 * been made between the EQ and any specific class of event (and,
10269517SBill.Taylor@Sun.COM 	 * hence, no unmapping is necessary).  Note: This command should not,
10279517SBill.Taylor@Sun.COM 	 * in general, fail.  If it does, then something (probably HW related)
10289517SBill.Taylor@Sun.COM 	 * has gone seriously wrong.
10299517SBill.Taylor@Sun.COM 	 */
10309517SBill.Taylor@Sun.COM 	if (eq->eq_evttypemask != HERMON_EVT_NO_MASK) {
10319517SBill.Taylor@Sun.COM 		status = hermon_map_eq_cmd_post(state,
10329517SBill.Taylor@Sun.COM 		    HERMON_CMD_MAP_EQ_EVT_UNMAP, eq->eq_eqnum,
10339517SBill.Taylor@Sun.COM 		    eq->eq_evttypemask, HERMON_CMD_NOSLEEP_SPIN);
10349517SBill.Taylor@Sun.COM 		if (status != HERMON_CMD_SUCCESS) {
10359517SBill.Taylor@Sun.COM 			cmn_err(CE_NOTE, "hermon%d: MAP_EQ command failed: "
10369517SBill.Taylor@Sun.COM 			    "%08x\n", state->hs_instance, status);
10379517SBill.Taylor@Sun.COM 			return (DDI_FAILURE);
10389517SBill.Taylor@Sun.COM 		}
10399517SBill.Taylor@Sun.COM 	}
10409517SBill.Taylor@Sun.COM 
10419517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
10429517SBill.Taylor@Sun.COM }
10439517SBill.Taylor@Sun.COM 
10449517SBill.Taylor@Sun.COM 
10459517SBill.Taylor@Sun.COM /*
10469517SBill.Taylor@Sun.COM  * hermon_eq_demux()
10479517SBill.Taylor@Sun.COM  *	Context: Called only from interrupt context
10489517SBill.Taylor@Sun.COM  *	Usage:  to demux the various type reported on one EQ
10499517SBill.Taylor@Sun.COM  */
10509517SBill.Taylor@Sun.COM static int
hermon_eq_demux(hermon_state_t * state,hermon_eqhdl_t eq,hermon_hw_eqe_t * eqe)10519517SBill.Taylor@Sun.COM hermon_eq_demux(hermon_state_t *state, hermon_eqhdl_t eq,
10529517SBill.Taylor@Sun.COM     hermon_hw_eqe_t *eqe)
10539517SBill.Taylor@Sun.COM {
10549517SBill.Taylor@Sun.COM 	uint_t			eqe_evttype;
10559517SBill.Taylor@Sun.COM 	int			status = DDI_FAILURE;
10569517SBill.Taylor@Sun.COM 
10579517SBill.Taylor@Sun.COM 	eqe_evttype = HERMON_EQE_EVTTYPE_GET(eq, eqe);
10589517SBill.Taylor@Sun.COM 
10599517SBill.Taylor@Sun.COM 	switch (eqe_evttype) {
10609517SBill.Taylor@Sun.COM 
10619517SBill.Taylor@Sun.COM 	case HERMON_EVT_PORT_STATE_CHANGE:
10629517SBill.Taylor@Sun.COM 		status = hermon_port_state_change_handler(state, eq, eqe);
10639517SBill.Taylor@Sun.COM 		break;
10649517SBill.Taylor@Sun.COM 
10659517SBill.Taylor@Sun.COM 	case HERMON_EVT_COMM_ESTABLISHED:
10669517SBill.Taylor@Sun.COM 		status = hermon_comm_estbl_handler(state, eq, eqe);
10679517SBill.Taylor@Sun.COM 		break;
10689517SBill.Taylor@Sun.COM 
10699517SBill.Taylor@Sun.COM 	case HERMON_EVT_COMMAND_INTF_COMP:
10709517SBill.Taylor@Sun.COM 		status = hermon_cmd_complete_handler(state, eq, eqe);
10719517SBill.Taylor@Sun.COM 		break;
10729517SBill.Taylor@Sun.COM 
10739517SBill.Taylor@Sun.COM 	case HERMON_EVT_LOCAL_WQ_CAT_ERROR:
1074*12965SWilliam.Taylor@Oracle.COM 		HERMON_WARNING(state, HERMON_FMA_LOCCAT);
10759517SBill.Taylor@Sun.COM 		status = hermon_local_wq_cat_err_handler(state, eq, eqe);
10769517SBill.Taylor@Sun.COM 		break;
10779517SBill.Taylor@Sun.COM 
10789517SBill.Taylor@Sun.COM 	case HERMON_EVT_INV_REQ_LOCAL_WQ_ERROR:
1079*12965SWilliam.Taylor@Oracle.COM 		HERMON_WARNING(state, HERMON_FMA_LOCINV);
10809517SBill.Taylor@Sun.COM 		status = hermon_invreq_local_wq_err_handler(state, eq, eqe);
10819517SBill.Taylor@Sun.COM 		break;
10829517SBill.Taylor@Sun.COM 
10839517SBill.Taylor@Sun.COM 	case HERMON_EVT_LOCAL_ACC_VIO_WQ_ERROR:
1084*12965SWilliam.Taylor@Oracle.COM 		HERMON_WARNING(state, HERMON_FMA_LOCACEQ);
108511972SBill.Taylor@Sun.COM 		IBTF_DPRINTF_L2("async", HERMON_FMA_LOCACEQ);
10869517SBill.Taylor@Sun.COM 		status = hermon_local_acc_vio_wq_err_handler(state, eq, eqe);
10879517SBill.Taylor@Sun.COM 		break;
10889517SBill.Taylor@Sun.COM 	case HERMON_EVT_SEND_QUEUE_DRAINED:
10899517SBill.Taylor@Sun.COM 		status = hermon_sendq_drained_handler(state, eq, eqe);
10909517SBill.Taylor@Sun.COM 		break;
10919517SBill.Taylor@Sun.COM 
10929517SBill.Taylor@Sun.COM 	case HERMON_EVT_PATH_MIGRATED:
10939517SBill.Taylor@Sun.COM 		status = hermon_path_mig_handler(state, eq, eqe);
10949517SBill.Taylor@Sun.COM 		break;
10959517SBill.Taylor@Sun.COM 
10969517SBill.Taylor@Sun.COM 	case HERMON_EVT_PATH_MIGRATE_FAILED:
1097*12965SWilliam.Taylor@Oracle.COM 		HERMON_WARNING(state, HERMON_FMA_PATHMIG);
10989517SBill.Taylor@Sun.COM 		status = hermon_path_mig_err_handler(state, eq, eqe);
10999517SBill.Taylor@Sun.COM 		break;
11009517SBill.Taylor@Sun.COM 
11019517SBill.Taylor@Sun.COM 	case HERMON_EVT_SRQ_CATASTROPHIC_ERROR:
1102*12965SWilliam.Taylor@Oracle.COM 		HERMON_WARNING(state, HERMON_FMA_SRQCAT);
11039517SBill.Taylor@Sun.COM 		status = hermon_catastrophic_handler(state, eq, eqe);
11049517SBill.Taylor@Sun.COM 		break;
11059517SBill.Taylor@Sun.COM 
11069517SBill.Taylor@Sun.COM 	case HERMON_EVT_SRQ_LAST_WQE_REACHED:
11079517SBill.Taylor@Sun.COM 		status = hermon_srq_last_wqe_reached_handler(state, eq, eqe);
11089517SBill.Taylor@Sun.COM 		break;
11099517SBill.Taylor@Sun.COM 
1110*12965SWilliam.Taylor@Oracle.COM 	case HERMON_EVT_FEXCH_ERROR:
1111*12965SWilliam.Taylor@Oracle.COM 		status = hermon_fexch_error_handler(state, eq, eqe);
11129517SBill.Taylor@Sun.COM 		break;
11139517SBill.Taylor@Sun.COM 
11149517SBill.Taylor@Sun.COM 	default:
11159517SBill.Taylor@Sun.COM 		break;
11169517SBill.Taylor@Sun.COM 	}
11179517SBill.Taylor@Sun.COM 	return (status);
11189517SBill.Taylor@Sun.COM }
11199517SBill.Taylor@Sun.COM 
11209517SBill.Taylor@Sun.COM /*
11219517SBill.Taylor@Sun.COM  * hermon_port_state_change_handler()
11229517SBill.Taylor@Sun.COM  *    Context: Only called from interrupt context
11239517SBill.Taylor@Sun.COM  */
1124*12965SWilliam.Taylor@Oracle.COM /* ARGSUSED */
11259517SBill.Taylor@Sun.COM static int
hermon_port_state_change_handler(hermon_state_t * state,hermon_eqhdl_t eq,hermon_hw_eqe_t * eqe)11269517SBill.Taylor@Sun.COM hermon_port_state_change_handler(hermon_state_t *state, hermon_eqhdl_t eq,
11279517SBill.Taylor@Sun.COM     hermon_hw_eqe_t *eqe)
11289517SBill.Taylor@Sun.COM {
11299517SBill.Taylor@Sun.COM 	ibc_async_event_t	event;
11309517SBill.Taylor@Sun.COM 	ibt_async_code_t	type;
11319517SBill.Taylor@Sun.COM 	uint_t			subtype;
11329517SBill.Taylor@Sun.COM 	uint8_t			port;
11339517SBill.Taylor@Sun.COM 	char			link_msg[24];
11349517SBill.Taylor@Sun.COM 
11359517SBill.Taylor@Sun.COM 	/*
11369517SBill.Taylor@Sun.COM 	 * Depending on the type of Port State Change event, pass the
11379517SBill.Taylor@Sun.COM 	 * appropriate asynch event to the IBTF.
11389517SBill.Taylor@Sun.COM 	 */
11399517SBill.Taylor@Sun.COM 	port = (uint8_t)HERMON_EQE_PORTNUM_GET(eq, eqe);
11409517SBill.Taylor@Sun.COM 
11419517SBill.Taylor@Sun.COM 	/* Check for valid port number in event */
11429517SBill.Taylor@Sun.COM 	if ((port == 0) || (port > state->hs_cfg_profile->cp_num_ports)) {
11439517SBill.Taylor@Sun.COM 		HERMON_WARNING(state, "Unexpected port number in port state "
11449517SBill.Taylor@Sun.COM 		    "change event");
11459517SBill.Taylor@Sun.COM 		cmn_err(CE_CONT, "  Port number: %02x\n", port);
11469517SBill.Taylor@Sun.COM 		return (DDI_FAILURE);
11479517SBill.Taylor@Sun.COM 	}
11489517SBill.Taylor@Sun.COM 
11499517SBill.Taylor@Sun.COM 	subtype = HERMON_EQE_EVTSUBTYPE_GET(eq, eqe);
11509517SBill.Taylor@Sun.COM 	if (subtype == HERMON_PORT_LINK_ACTIVE) {
11519517SBill.Taylor@Sun.COM 		event.ev_port 	= port;
11529517SBill.Taylor@Sun.COM 		type		= IBT_EVENT_PORT_UP;
11539517SBill.Taylor@Sun.COM 
11549517SBill.Taylor@Sun.COM 		(void) snprintf(link_msg, 23, "port %d up", port);
11559517SBill.Taylor@Sun.COM 		ddi_dev_report_fault(state->hs_dip, DDI_SERVICE_RESTORED,
11569517SBill.Taylor@Sun.COM 		    DDI_EXTERNAL_FAULT, link_msg);
11579517SBill.Taylor@Sun.COM 	} else if (subtype == HERMON_PORT_LINK_DOWN) {
11589517SBill.Taylor@Sun.COM 		event.ev_port	= port;
11599517SBill.Taylor@Sun.COM 		type		= IBT_ERROR_PORT_DOWN;
11609517SBill.Taylor@Sun.COM 
11619517SBill.Taylor@Sun.COM 		(void) snprintf(link_msg, 23, "port %d down", port);
11629517SBill.Taylor@Sun.COM 		ddi_dev_report_fault(state->hs_dip, DDI_SERVICE_LOST,
11639517SBill.Taylor@Sun.COM 		    DDI_EXTERNAL_FAULT, link_msg);
11649517SBill.Taylor@Sun.COM 	} else {
11659517SBill.Taylor@Sun.COM 		HERMON_WARNING(state, "Unexpected subtype in port state change "
11669517SBill.Taylor@Sun.COM 		    "event");
11679517SBill.Taylor@Sun.COM 		cmn_err(CE_CONT, "  Event type: %02x, subtype: %02x\n",
11689517SBill.Taylor@Sun.COM 		    HERMON_EQE_EVTTYPE_GET(eq, eqe), subtype);
11699517SBill.Taylor@Sun.COM 		return (DDI_FAILURE);
11709517SBill.Taylor@Sun.COM 	}
11719517SBill.Taylor@Sun.COM 
11729517SBill.Taylor@Sun.COM 	/*
11739517SBill.Taylor@Sun.COM 	 * Deliver the event to the IBTF.  Note: If "hs_ibtfpriv" is NULL,
11749517SBill.Taylor@Sun.COM 	 * then we have either received this event before we finished
11759517SBill.Taylor@Sun.COM 	 * attaching to the IBTF or we've received it while we are in the
11769517SBill.Taylor@Sun.COM 	 * process of detaching.
11779517SBill.Taylor@Sun.COM 	 */
11789517SBill.Taylor@Sun.COM 	if (state->hs_ibtfpriv != NULL) {
11799517SBill.Taylor@Sun.COM 		HERMON_DO_IBTF_ASYNC_CALLB(state, type, &event);
11809517SBill.Taylor@Sun.COM 	}
11819517SBill.Taylor@Sun.COM 
11829517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
11839517SBill.Taylor@Sun.COM }
11849517SBill.Taylor@Sun.COM 
11859517SBill.Taylor@Sun.COM 
11869517SBill.Taylor@Sun.COM /*
11879517SBill.Taylor@Sun.COM  * hermon_comm_estbl_handler()
11889517SBill.Taylor@Sun.COM  *    Context: Only called from interrupt context
11899517SBill.Taylor@Sun.COM  */
1190*12965SWilliam.Taylor@Oracle.COM /* ARGSUSED */
11919517SBill.Taylor@Sun.COM static int
hermon_comm_estbl_handler(hermon_state_t * state,hermon_eqhdl_t eq,hermon_hw_eqe_t * eqe)11929517SBill.Taylor@Sun.COM hermon_comm_estbl_handler(hermon_state_t *state, hermon_eqhdl_t eq,
11939517SBill.Taylor@Sun.COM     hermon_hw_eqe_t *eqe)
11949517SBill.Taylor@Sun.COM {
11959517SBill.Taylor@Sun.COM 	hermon_qphdl_t		qp;
11969517SBill.Taylor@Sun.COM 	uint_t			qpnum;
11979517SBill.Taylor@Sun.COM 	ibc_async_event_t	event;
11989517SBill.Taylor@Sun.COM 	ibt_async_code_t	type;
11999517SBill.Taylor@Sun.COM 
12009517SBill.Taylor@Sun.COM 	/* Get the QP handle from QP number in event descriptor */
12019517SBill.Taylor@Sun.COM 	qpnum = HERMON_EQE_QPNUM_GET(eq, eqe);
12029517SBill.Taylor@Sun.COM 	qp = hermon_qphdl_from_qpnum(state, qpnum);
12039517SBill.Taylor@Sun.COM 
12049517SBill.Taylor@Sun.COM 	/*
12059517SBill.Taylor@Sun.COM 	 * If the QP handle is NULL, this is probably an indication
12069517SBill.Taylor@Sun.COM 	 * that the QP has been freed already.  In which case, we
12079517SBill.Taylor@Sun.COM 	 * should not deliver this event.
12089517SBill.Taylor@Sun.COM 	 *
12099517SBill.Taylor@Sun.COM 	 * We also check that the QP number in the handle is the
12109517SBill.Taylor@Sun.COM 	 * same as the QP number in the event queue entry.  This
12119517SBill.Taylor@Sun.COM 	 * extra check allows us to handle the case where a QP was
12129517SBill.Taylor@Sun.COM 	 * freed and then allocated again in the time it took to
12139517SBill.Taylor@Sun.COM 	 * handle the event queue processing.  By constantly incrementing
12149517SBill.Taylor@Sun.COM 	 * the non-constrained portion of the QP number every time
12159517SBill.Taylor@Sun.COM 	 * a new QP is allocated, we mitigate (somewhat) the chance
12169517SBill.Taylor@Sun.COM 	 * that a stale event could be passed to the client's QP
12179517SBill.Taylor@Sun.COM 	 * handler.
12189517SBill.Taylor@Sun.COM 	 *
12199517SBill.Taylor@Sun.COM 	 * Lastly, we check if "hs_ibtfpriv" is NULL.  If it is then it
12209517SBill.Taylor@Sun.COM 	 * means that we've have either received this event before we
12219517SBill.Taylor@Sun.COM 	 * finished attaching to the IBTF or we've received it while we
12229517SBill.Taylor@Sun.COM 	 * are in the process of detaching.
12239517SBill.Taylor@Sun.COM 	 */
12249517SBill.Taylor@Sun.COM 	if ((qp != NULL) && (qp->qp_qpnum == qpnum) &&
12259517SBill.Taylor@Sun.COM 	    (state->hs_ibtfpriv != NULL)) {
12269517SBill.Taylor@Sun.COM 		event.ev_qp_hdl = (ibtl_qp_hdl_t)qp->qp_hdlrarg;
12279517SBill.Taylor@Sun.COM 		type		= IBT_EVENT_COM_EST_QP;
12289517SBill.Taylor@Sun.COM 
12299517SBill.Taylor@Sun.COM 		HERMON_DO_IBTF_ASYNC_CALLB(state, type, &event);
12309517SBill.Taylor@Sun.COM 	}
12319517SBill.Taylor@Sun.COM 
12329517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
12339517SBill.Taylor@Sun.COM }
12349517SBill.Taylor@Sun.COM 
12359517SBill.Taylor@Sun.COM 
12369517SBill.Taylor@Sun.COM /*
12379517SBill.Taylor@Sun.COM  * hermon_local_wq_cat_err_handler()
12389517SBill.Taylor@Sun.COM  *    Context: Only called from interrupt context
12399517SBill.Taylor@Sun.COM  */
1240*12965SWilliam.Taylor@Oracle.COM /* ARGSUSED */
12419517SBill.Taylor@Sun.COM static int
hermon_local_wq_cat_err_handler(hermon_state_t * state,hermon_eqhdl_t eq,hermon_hw_eqe_t * eqe)12429517SBill.Taylor@Sun.COM hermon_local_wq_cat_err_handler(hermon_state_t *state, hermon_eqhdl_t eq,
12439517SBill.Taylor@Sun.COM     hermon_hw_eqe_t *eqe)
12449517SBill.Taylor@Sun.COM {
12459517SBill.Taylor@Sun.COM 	hermon_qphdl_t		qp;
12469517SBill.Taylor@Sun.COM 	uint_t			qpnum;
12479517SBill.Taylor@Sun.COM 	ibc_async_event_t	event;
12489517SBill.Taylor@Sun.COM 	ibt_async_code_t	type;
12499517SBill.Taylor@Sun.COM 
12509517SBill.Taylor@Sun.COM 	/* Get the QP handle from QP number in event descriptor */
12519517SBill.Taylor@Sun.COM 	qpnum = HERMON_EQE_QPNUM_GET(eq, eqe);
12529517SBill.Taylor@Sun.COM 	qp = hermon_qphdl_from_qpnum(state, qpnum);
12539517SBill.Taylor@Sun.COM 
12549517SBill.Taylor@Sun.COM 	/*
12559517SBill.Taylor@Sun.COM 	 * If the QP handle is NULL, this is probably an indication
12569517SBill.Taylor@Sun.COM 	 * that the QP has been freed already.  In which case, we
12579517SBill.Taylor@Sun.COM 	 * should not deliver this event.
12589517SBill.Taylor@Sun.COM 	 *
12599517SBill.Taylor@Sun.COM 	 * We also check that the QP number in the handle is the
12609517SBill.Taylor@Sun.COM 	 * same as the QP number in the event queue entry.  This
12619517SBill.Taylor@Sun.COM 	 * extra check allows us to handle the case where a QP was
12629517SBill.Taylor@Sun.COM 	 * freed and then allocated again in the time it took to
12639517SBill.Taylor@Sun.COM 	 * handle the event queue processing.  By constantly incrementing
12649517SBill.Taylor@Sun.COM 	 * the non-constrained portion of the QP number every time
12659517SBill.Taylor@Sun.COM 	 * a new QP is allocated, we mitigate (somewhat) the chance
12669517SBill.Taylor@Sun.COM 	 * that a stale event could be passed to the client's QP
12679517SBill.Taylor@Sun.COM 	 * handler.
12689517SBill.Taylor@Sun.COM 	 *
12699517SBill.Taylor@Sun.COM 	 * Lastly, we check if "hs_ibtfpriv" is NULL.  If it is then it
12709517SBill.Taylor@Sun.COM 	 * means that we've have either received this event before we
12719517SBill.Taylor@Sun.COM 	 * finished attaching to the IBTF or we've received it while we
12729517SBill.Taylor@Sun.COM 	 * are in the process of detaching.
12739517SBill.Taylor@Sun.COM 	 */
12749517SBill.Taylor@Sun.COM 	if ((qp != NULL) && (qp->qp_qpnum == qpnum) &&
12759517SBill.Taylor@Sun.COM 	    (state->hs_ibtfpriv != NULL)) {
12769517SBill.Taylor@Sun.COM 		event.ev_qp_hdl = (ibtl_qp_hdl_t)qp->qp_hdlrarg;
12779517SBill.Taylor@Sun.COM 		type		= IBT_ERROR_CATASTROPHIC_QP;
12789517SBill.Taylor@Sun.COM 
12799517SBill.Taylor@Sun.COM 		HERMON_DO_IBTF_ASYNC_CALLB(state, type, &event);
12809517SBill.Taylor@Sun.COM 	}
12819517SBill.Taylor@Sun.COM 
12829517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
12839517SBill.Taylor@Sun.COM }
12849517SBill.Taylor@Sun.COM 
12859517SBill.Taylor@Sun.COM 
12869517SBill.Taylor@Sun.COM /*
12879517SBill.Taylor@Sun.COM  * hermon_invreq_local_wq_err_handler()
12889517SBill.Taylor@Sun.COM  *    Context: Only called from interrupt context
12899517SBill.Taylor@Sun.COM  */
1290*12965SWilliam.Taylor@Oracle.COM /* ARGSUSED */
12919517SBill.Taylor@Sun.COM static int
hermon_invreq_local_wq_err_handler(hermon_state_t * state,hermon_eqhdl_t eq,hermon_hw_eqe_t * eqe)12929517SBill.Taylor@Sun.COM hermon_invreq_local_wq_err_handler(hermon_state_t *state, hermon_eqhdl_t eq,
12939517SBill.Taylor@Sun.COM     hermon_hw_eqe_t *eqe)
12949517SBill.Taylor@Sun.COM {
12959517SBill.Taylor@Sun.COM 	hermon_qphdl_t		qp;
12969517SBill.Taylor@Sun.COM 	uint_t			qpnum;
12979517SBill.Taylor@Sun.COM 	ibc_async_event_t	event;
12989517SBill.Taylor@Sun.COM 	ibt_async_code_t	type;
12999517SBill.Taylor@Sun.COM 
13009517SBill.Taylor@Sun.COM 	/* Get the QP handle from QP number in event descriptor */
13019517SBill.Taylor@Sun.COM 	qpnum = HERMON_EQE_QPNUM_GET(eq, eqe);
13029517SBill.Taylor@Sun.COM 	qp = hermon_qphdl_from_qpnum(state, qpnum);
13039517SBill.Taylor@Sun.COM 
13049517SBill.Taylor@Sun.COM 	/*
13059517SBill.Taylor@Sun.COM 	 * If the QP handle is NULL, this is probably an indication
13069517SBill.Taylor@Sun.COM 	 * that the QP has been freed already.  In which case, we
13079517SBill.Taylor@Sun.COM 	 * should not deliver this event.
13089517SBill.Taylor@Sun.COM 	 *
13099517SBill.Taylor@Sun.COM 	 * We also check that the QP number in the handle is the
13109517SBill.Taylor@Sun.COM 	 * same as the QP number in the event queue entry.  This
13119517SBill.Taylor@Sun.COM 	 * extra check allows us to handle the case where a QP was
13129517SBill.Taylor@Sun.COM 	 * freed and then allocated again in the time it took to
13139517SBill.Taylor@Sun.COM 	 * handle the event queue processing.  By constantly incrementing
13149517SBill.Taylor@Sun.COM 	 * the non-constrained portion of the QP number every time
13159517SBill.Taylor@Sun.COM 	 * a new QP is allocated, we mitigate (somewhat) the chance
13169517SBill.Taylor@Sun.COM 	 * that a stale event could be passed to the client's QP
13179517SBill.Taylor@Sun.COM 	 * handler.
13189517SBill.Taylor@Sun.COM 	 *
13199517SBill.Taylor@Sun.COM 	 * Lastly, we check if "hs_ibtfpriv" is NULL.  If it is then it
13209517SBill.Taylor@Sun.COM 	 * means that we've have either received this event before we
13219517SBill.Taylor@Sun.COM 	 * finished attaching to the IBTF or we've received it while we
13229517SBill.Taylor@Sun.COM 	 * are in the process of detaching.
13239517SBill.Taylor@Sun.COM 	 */
13249517SBill.Taylor@Sun.COM 	if ((qp != NULL) && (qp->qp_qpnum == qpnum) &&
13259517SBill.Taylor@Sun.COM 	    (state->hs_ibtfpriv != NULL)) {
13269517SBill.Taylor@Sun.COM 		event.ev_qp_hdl = (ibtl_qp_hdl_t)qp->qp_hdlrarg;
13279517SBill.Taylor@Sun.COM 		type		= IBT_ERROR_INVALID_REQUEST_QP;
13289517SBill.Taylor@Sun.COM 
13299517SBill.Taylor@Sun.COM 		HERMON_DO_IBTF_ASYNC_CALLB(state, type, &event);
13309517SBill.Taylor@Sun.COM 	}
13319517SBill.Taylor@Sun.COM 
13329517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
13339517SBill.Taylor@Sun.COM }
13349517SBill.Taylor@Sun.COM 
13359517SBill.Taylor@Sun.COM 
13369517SBill.Taylor@Sun.COM /*
13379517SBill.Taylor@Sun.COM  * hermon_local_acc_vio_wq_err_handler()
13389517SBill.Taylor@Sun.COM  *    Context: Only called from interrupt context
13399517SBill.Taylor@Sun.COM  */
1340*12965SWilliam.Taylor@Oracle.COM /* ARGSUSED */
13419517SBill.Taylor@Sun.COM static int
hermon_local_acc_vio_wq_err_handler(hermon_state_t * state,hermon_eqhdl_t eq,hermon_hw_eqe_t * eqe)13429517SBill.Taylor@Sun.COM hermon_local_acc_vio_wq_err_handler(hermon_state_t *state, hermon_eqhdl_t eq,
13439517SBill.Taylor@Sun.COM     hermon_hw_eqe_t *eqe)
13449517SBill.Taylor@Sun.COM {
13459517SBill.Taylor@Sun.COM 	hermon_qphdl_t		qp;
13469517SBill.Taylor@Sun.COM 	uint_t			qpnum;
13479517SBill.Taylor@Sun.COM 	ibc_async_event_t	event;
13489517SBill.Taylor@Sun.COM 	ibt_async_code_t	type;
13499517SBill.Taylor@Sun.COM 
13509517SBill.Taylor@Sun.COM 	/* Get the QP handle from QP number in event descriptor */
13519517SBill.Taylor@Sun.COM 	qpnum = HERMON_EQE_QPNUM_GET(eq, eqe);
13529517SBill.Taylor@Sun.COM 	qp = hermon_qphdl_from_qpnum(state, qpnum);
13539517SBill.Taylor@Sun.COM 
13549517SBill.Taylor@Sun.COM 	/*
13559517SBill.Taylor@Sun.COM 	 * If the QP handle is NULL, this is probably an indication
13569517SBill.Taylor@Sun.COM 	 * that the QP has been freed already.  In which case, we
13579517SBill.Taylor@Sun.COM 	 * should not deliver this event.
13589517SBill.Taylor@Sun.COM 	 *
13599517SBill.Taylor@Sun.COM 	 * We also check that the QP number in the handle is the
13609517SBill.Taylor@Sun.COM 	 * same as the QP number in the event queue entry.  This
13619517SBill.Taylor@Sun.COM 	 * extra check allows us to handle the case where a QP was
13629517SBill.Taylor@Sun.COM 	 * freed and then allocated again in the time it took to
13639517SBill.Taylor@Sun.COM 	 * handle the event queue processing.  By constantly incrementing
13649517SBill.Taylor@Sun.COM 	 * the non-constrained portion of the QP number every time
13659517SBill.Taylor@Sun.COM 	 * a new QP is allocated, we mitigate (somewhat) the chance
13669517SBill.Taylor@Sun.COM 	 * that a stale event could be passed to the client's QP
13679517SBill.Taylor@Sun.COM 	 * handler.
13689517SBill.Taylor@Sun.COM 	 *
13699517SBill.Taylor@Sun.COM 	 * Lastly, we check if "hs_ibtfpriv" is NULL.  If it is then it
13709517SBill.Taylor@Sun.COM 	 * means that we've have either received this event before we
13719517SBill.Taylor@Sun.COM 	 * finished attaching to the IBTF or we've received it while we
13729517SBill.Taylor@Sun.COM 	 * are in the process of detaching.
13739517SBill.Taylor@Sun.COM 	 */
13749517SBill.Taylor@Sun.COM 	if ((qp != NULL) && (qp->qp_qpnum == qpnum) &&
13759517SBill.Taylor@Sun.COM 	    (state->hs_ibtfpriv != NULL)) {
13769517SBill.Taylor@Sun.COM 		event.ev_qp_hdl = (ibtl_qp_hdl_t)qp->qp_hdlrarg;
13779517SBill.Taylor@Sun.COM 		type		= IBT_ERROR_ACCESS_VIOLATION_QP;
13789517SBill.Taylor@Sun.COM 
13799517SBill.Taylor@Sun.COM 		HERMON_DO_IBTF_ASYNC_CALLB(state, type, &event);
13809517SBill.Taylor@Sun.COM 	}
13819517SBill.Taylor@Sun.COM 
13829517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
13839517SBill.Taylor@Sun.COM }
13849517SBill.Taylor@Sun.COM 
13859517SBill.Taylor@Sun.COM 
13869517SBill.Taylor@Sun.COM /*
13879517SBill.Taylor@Sun.COM  * hermon_sendq_drained_handler()
13889517SBill.Taylor@Sun.COM  *    Context: Only called from interrupt context
13899517SBill.Taylor@Sun.COM  */
1390*12965SWilliam.Taylor@Oracle.COM /* ARGSUSED */
13919517SBill.Taylor@Sun.COM static int
hermon_sendq_drained_handler(hermon_state_t * state,hermon_eqhdl_t eq,hermon_hw_eqe_t * eqe)13929517SBill.Taylor@Sun.COM hermon_sendq_drained_handler(hermon_state_t *state, hermon_eqhdl_t eq,
13939517SBill.Taylor@Sun.COM     hermon_hw_eqe_t *eqe)
13949517SBill.Taylor@Sun.COM {
13959517SBill.Taylor@Sun.COM 	hermon_qphdl_t		qp;
13969517SBill.Taylor@Sun.COM 	uint_t			qpnum;
13979517SBill.Taylor@Sun.COM 	ibc_async_event_t	event;
13989517SBill.Taylor@Sun.COM 	uint_t			forward_sqd_event;
13999517SBill.Taylor@Sun.COM 	ibt_async_code_t	type;
14009517SBill.Taylor@Sun.COM 
14019517SBill.Taylor@Sun.COM 	/* Get the QP handle from QP number in event descriptor */
14029517SBill.Taylor@Sun.COM 	qpnum = HERMON_EQE_QPNUM_GET(eq, eqe);
14039517SBill.Taylor@Sun.COM 	qp = hermon_qphdl_from_qpnum(state, qpnum);
14049517SBill.Taylor@Sun.COM 
14059517SBill.Taylor@Sun.COM 	/*
14069517SBill.Taylor@Sun.COM 	 * If the QP handle is NULL, this is probably an indication
14079517SBill.Taylor@Sun.COM 	 * that the QP has been freed already.  In which case, we
14089517SBill.Taylor@Sun.COM 	 * should not deliver this event.
14099517SBill.Taylor@Sun.COM 	 *
14109517SBill.Taylor@Sun.COM 	 * We also check that the QP number in the handle is the
14119517SBill.Taylor@Sun.COM 	 * same as the QP number in the event queue entry.  This
14129517SBill.Taylor@Sun.COM 	 * extra check allows us to handle the case where a QP was
14139517SBill.Taylor@Sun.COM 	 * freed and then allocated again in the time it took to
14149517SBill.Taylor@Sun.COM 	 * handle the event queue processing.  By constantly incrementing
14159517SBill.Taylor@Sun.COM 	 * the non-constrained portion of the QP number every time
14169517SBill.Taylor@Sun.COM 	 * a new QP is allocated, we mitigate (somewhat) the chance
14179517SBill.Taylor@Sun.COM 	 * that a stale event could be passed to the client's QP
14189517SBill.Taylor@Sun.COM 	 * handler.
14199517SBill.Taylor@Sun.COM 	 *
14209517SBill.Taylor@Sun.COM 	 * And then we check if "hs_ibtfpriv" is NULL.  If it is then it
14219517SBill.Taylor@Sun.COM 	 * means that we've have either received this event before we
14229517SBill.Taylor@Sun.COM 	 * finished attaching to the IBTF or we've received it while we
14239517SBill.Taylor@Sun.COM 	 * are in the process of detaching.
14249517SBill.Taylor@Sun.COM 	 */
14259517SBill.Taylor@Sun.COM 	if ((qp != NULL) && (qp->qp_qpnum == qpnum) &&
14269517SBill.Taylor@Sun.COM 	    (state->hs_ibtfpriv != NULL)) {
14279517SBill.Taylor@Sun.COM 		event.ev_qp_hdl = (ibtl_qp_hdl_t)qp->qp_hdlrarg;
14289517SBill.Taylor@Sun.COM 		type		= IBT_EVENT_SQD;
14299517SBill.Taylor@Sun.COM 
14309517SBill.Taylor@Sun.COM 		/*
14319517SBill.Taylor@Sun.COM 		 * Grab the QP lock and update the QP state to reflect that
14329517SBill.Taylor@Sun.COM 		 * the Send Queue Drained event has arrived.  Also determine
14339517SBill.Taylor@Sun.COM 		 * whether the event is intended to be forwarded on to the
14349517SBill.Taylor@Sun.COM 		 * consumer or not.  This information is used below in
14359517SBill.Taylor@Sun.COM 		 * determining whether or not to call the IBTF.
14369517SBill.Taylor@Sun.COM 		 */
14379517SBill.Taylor@Sun.COM 		mutex_enter(&qp->qp_lock);
14389517SBill.Taylor@Sun.COM 		forward_sqd_event = qp->qp_forward_sqd_event;
14399517SBill.Taylor@Sun.COM 		qp->qp_forward_sqd_event  = 0;
14409517SBill.Taylor@Sun.COM 		qp->qp_sqd_still_draining = 0;
14419517SBill.Taylor@Sun.COM 		mutex_exit(&qp->qp_lock);
14429517SBill.Taylor@Sun.COM 
14439517SBill.Taylor@Sun.COM 		if (forward_sqd_event != 0) {
14449517SBill.Taylor@Sun.COM 			HERMON_DO_IBTF_ASYNC_CALLB(state, type, &event);
14459517SBill.Taylor@Sun.COM 		}
14469517SBill.Taylor@Sun.COM 	}
14479517SBill.Taylor@Sun.COM 
14489517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
14499517SBill.Taylor@Sun.COM }
14509517SBill.Taylor@Sun.COM 
14519517SBill.Taylor@Sun.COM 
14529517SBill.Taylor@Sun.COM /*
14539517SBill.Taylor@Sun.COM  * hermon_path_mig_handler()
14549517SBill.Taylor@Sun.COM  *    Context: Only called from interrupt context
14559517SBill.Taylor@Sun.COM  */
1456*12965SWilliam.Taylor@Oracle.COM /* ARGSUSED */
14579517SBill.Taylor@Sun.COM static int
hermon_path_mig_handler(hermon_state_t * state,hermon_eqhdl_t eq,hermon_hw_eqe_t * eqe)14589517SBill.Taylor@Sun.COM hermon_path_mig_handler(hermon_state_t *state, hermon_eqhdl_t eq,
14599517SBill.Taylor@Sun.COM     hermon_hw_eqe_t *eqe)
14609517SBill.Taylor@Sun.COM {
14619517SBill.Taylor@Sun.COM 	hermon_qphdl_t		qp;
14629517SBill.Taylor@Sun.COM 	uint_t			qpnum;
14639517SBill.Taylor@Sun.COM 	ibc_async_event_t	event;
14649517SBill.Taylor@Sun.COM 	ibt_async_code_t	type;
14659517SBill.Taylor@Sun.COM 
14669517SBill.Taylor@Sun.COM 	/* Get the QP handle from QP number in event descriptor */
14679517SBill.Taylor@Sun.COM 	qpnum = HERMON_EQE_QPNUM_GET(eq, eqe);
14689517SBill.Taylor@Sun.COM 	qp = hermon_qphdl_from_qpnum(state, qpnum);
14699517SBill.Taylor@Sun.COM 
14709517SBill.Taylor@Sun.COM 	/*
14719517SBill.Taylor@Sun.COM 	 * If the QP handle is NULL, this is probably an indication
14729517SBill.Taylor@Sun.COM 	 * that the QP has been freed already.  In which case, we
14739517SBill.Taylor@Sun.COM 	 * should not deliver this event.
14749517SBill.Taylor@Sun.COM 	 *
14759517SBill.Taylor@Sun.COM 	 * We also check that the QP number in the handle is the
14769517SBill.Taylor@Sun.COM 	 * same as the QP number in the event queue entry.  This
14779517SBill.Taylor@Sun.COM 	 * extra check allows us to handle the case where a QP was
14789517SBill.Taylor@Sun.COM 	 * freed and then allocated again in the time it took to
14799517SBill.Taylor@Sun.COM 	 * handle the event queue processing.  By constantly incrementing
14809517SBill.Taylor@Sun.COM 	 * the non-constrained portion of the QP number every time
14819517SBill.Taylor@Sun.COM 	 * a new QP is allocated, we mitigate (somewhat) the chance
14829517SBill.Taylor@Sun.COM 	 * that a stale event could be passed to the client's QP
14839517SBill.Taylor@Sun.COM 	 * handler.
14849517SBill.Taylor@Sun.COM 	 *
14859517SBill.Taylor@Sun.COM 	 * Lastly, we check if "hs_ibtfpriv" is NULL.  If it is then it
14869517SBill.Taylor@Sun.COM 	 * means that we've have either received this event before we
14879517SBill.Taylor@Sun.COM 	 * finished attaching to the IBTF or we've received it while we
14889517SBill.Taylor@Sun.COM 	 * are in the process of detaching.
14899517SBill.Taylor@Sun.COM 	 */
14909517SBill.Taylor@Sun.COM 	if ((qp != NULL) && (qp->qp_qpnum == qpnum) &&
14919517SBill.Taylor@Sun.COM 	    (state->hs_ibtfpriv != NULL)) {
14929517SBill.Taylor@Sun.COM 		event.ev_qp_hdl = (ibtl_qp_hdl_t)qp->qp_hdlrarg;
14939517SBill.Taylor@Sun.COM 		type		= IBT_EVENT_PATH_MIGRATED_QP;
14949517SBill.Taylor@Sun.COM 
14959517SBill.Taylor@Sun.COM 		HERMON_DO_IBTF_ASYNC_CALLB(state, type, &event);
14969517SBill.Taylor@Sun.COM 	}
14979517SBill.Taylor@Sun.COM 
14989517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
14999517SBill.Taylor@Sun.COM }
15009517SBill.Taylor@Sun.COM 
15019517SBill.Taylor@Sun.COM 
15029517SBill.Taylor@Sun.COM /*
15039517SBill.Taylor@Sun.COM  * hermon_path_mig_err_handler()
15049517SBill.Taylor@Sun.COM  *    Context: Only called from interrupt context
15059517SBill.Taylor@Sun.COM  */
1506*12965SWilliam.Taylor@Oracle.COM /* ARGSUSED */
15079517SBill.Taylor@Sun.COM static int
hermon_path_mig_err_handler(hermon_state_t * state,hermon_eqhdl_t eq,hermon_hw_eqe_t * eqe)15089517SBill.Taylor@Sun.COM hermon_path_mig_err_handler(hermon_state_t *state, hermon_eqhdl_t eq,
15099517SBill.Taylor@Sun.COM     hermon_hw_eqe_t *eqe)
15109517SBill.Taylor@Sun.COM {
15119517SBill.Taylor@Sun.COM 	hermon_qphdl_t		qp;
15129517SBill.Taylor@Sun.COM 	uint_t			qpnum;
15139517SBill.Taylor@Sun.COM 	ibc_async_event_t	event;
15149517SBill.Taylor@Sun.COM 	ibt_async_code_t	type;
15159517SBill.Taylor@Sun.COM 
15169517SBill.Taylor@Sun.COM 	/* Get the QP handle from QP number in event descriptor */
15179517SBill.Taylor@Sun.COM 	qpnum = HERMON_EQE_QPNUM_GET(eq, eqe);
15189517SBill.Taylor@Sun.COM 	qp = hermon_qphdl_from_qpnum(state, qpnum);
15199517SBill.Taylor@Sun.COM 
15209517SBill.Taylor@Sun.COM 	/*
15219517SBill.Taylor@Sun.COM 	 * If the QP handle is NULL, this is probably an indication
15229517SBill.Taylor@Sun.COM 	 * that the QP has been freed already.  In which case, we
15239517SBill.Taylor@Sun.COM 	 * should not deliver this event.
15249517SBill.Taylor@Sun.COM 	 *
15259517SBill.Taylor@Sun.COM 	 * We also check that the QP number in the handle is the
15269517SBill.Taylor@Sun.COM 	 * same as the QP number in the event queue entry.  This
15279517SBill.Taylor@Sun.COM 	 * extra check allows us to handle the case where a QP was
15289517SBill.Taylor@Sun.COM 	 * freed and then allocated again in the time it took to
15299517SBill.Taylor@Sun.COM 	 * handle the event queue processing.  By constantly incrementing
15309517SBill.Taylor@Sun.COM 	 * the non-constrained portion of the QP number every time
15319517SBill.Taylor@Sun.COM 	 * a new QP is allocated, we mitigate (somewhat) the chance
15329517SBill.Taylor@Sun.COM 	 * that a stale event could be passed to the client's QP
15339517SBill.Taylor@Sun.COM 	 * handler.
15349517SBill.Taylor@Sun.COM 	 *
15359517SBill.Taylor@Sun.COM 	 * Lastly, we check if "hs_ibtfpriv" is NULL.  If it is then it
15369517SBill.Taylor@Sun.COM 	 * means that we've have either received this event before we
15379517SBill.Taylor@Sun.COM 	 * finished attaching to the IBTF or we've received it while we
15389517SBill.Taylor@Sun.COM 	 * are in the process of detaching.
15399517SBill.Taylor@Sun.COM 	 */
15409517SBill.Taylor@Sun.COM 	if ((qp != NULL) && (qp->qp_qpnum == qpnum) &&
15419517SBill.Taylor@Sun.COM 	    (state->hs_ibtfpriv != NULL)) {
15429517SBill.Taylor@Sun.COM 		event.ev_qp_hdl = (ibtl_qp_hdl_t)qp->qp_hdlrarg;
15439517SBill.Taylor@Sun.COM 		type		= IBT_ERROR_PATH_MIGRATE_REQ_QP;
15449517SBill.Taylor@Sun.COM 
15459517SBill.Taylor@Sun.COM 		HERMON_DO_IBTF_ASYNC_CALLB(state, type, &event);
15469517SBill.Taylor@Sun.COM 	}
15479517SBill.Taylor@Sun.COM 
15489517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
15499517SBill.Taylor@Sun.COM }
15509517SBill.Taylor@Sun.COM 
15519517SBill.Taylor@Sun.COM 
15529517SBill.Taylor@Sun.COM /*
15539517SBill.Taylor@Sun.COM  * hermon_catastrophic_handler()
15549517SBill.Taylor@Sun.COM  *    Context: Only called from interrupt context
15559517SBill.Taylor@Sun.COM  */
1556*12965SWilliam.Taylor@Oracle.COM /* ARGSUSED */
15579517SBill.Taylor@Sun.COM static int
hermon_catastrophic_handler(hermon_state_t * state,hermon_eqhdl_t eq,hermon_hw_eqe_t * eqe)15589517SBill.Taylor@Sun.COM hermon_catastrophic_handler(hermon_state_t *state, hermon_eqhdl_t eq,
15599517SBill.Taylor@Sun.COM     hermon_hw_eqe_t *eqe)
15609517SBill.Taylor@Sun.COM {
15619517SBill.Taylor@Sun.COM 	hermon_qphdl_t		qp;
15629517SBill.Taylor@Sun.COM 	uint_t			qpnum;
15639517SBill.Taylor@Sun.COM 	ibc_async_event_t	event;
15649517SBill.Taylor@Sun.COM 	ibt_async_code_t	type;
15659517SBill.Taylor@Sun.COM 
15669517SBill.Taylor@Sun.COM 	if (eq->eq_evttypemask == HERMON_EVT_MSK_LOCAL_CAT_ERROR) {
15679517SBill.Taylor@Sun.COM 		HERMON_FMANOTE(state, HERMON_FMA_INTERNAL);
15689517SBill.Taylor@Sun.COM 		hermon_eq_catastrophic(state);
15699517SBill.Taylor@Sun.COM 		return (DDI_SUCCESS);
15709517SBill.Taylor@Sun.COM 	}
15719517SBill.Taylor@Sun.COM 
15729517SBill.Taylor@Sun.COM 	/* Get the QP handle from QP number in event descriptor */
15739517SBill.Taylor@Sun.COM 	qpnum = HERMON_EQE_QPNUM_GET(eq, eqe);
15749517SBill.Taylor@Sun.COM 	qp = hermon_qphdl_from_qpnum(state, qpnum);
15759517SBill.Taylor@Sun.COM 
15769517SBill.Taylor@Sun.COM 	/*
15779517SBill.Taylor@Sun.COM 	 * If the QP handle is NULL, this is probably an indication
15789517SBill.Taylor@Sun.COM 	 * that the QP has been freed already.  In which case, we
15799517SBill.Taylor@Sun.COM 	 * should not deliver this event.
15809517SBill.Taylor@Sun.COM 	 *
15819517SBill.Taylor@Sun.COM 	 * We also check that the QP number in the handle is the
15829517SBill.Taylor@Sun.COM 	 * same as the QP number in the event queue entry.  This
15839517SBill.Taylor@Sun.COM 	 * extra check allows us to handle the case where a QP was
15849517SBill.Taylor@Sun.COM 	 * freed and then allocated again in the time it took to
15859517SBill.Taylor@Sun.COM 	 * handle the event queue processing.  By constantly incrementing
15869517SBill.Taylor@Sun.COM 	 * the non-constrained portion of the QP number every time
15879517SBill.Taylor@Sun.COM 	 * a new QP is allocated, we mitigate (somewhat) the chance
15889517SBill.Taylor@Sun.COM 	 * that a stale event could be passed to the client's QP
15899517SBill.Taylor@Sun.COM 	 * handler.
15909517SBill.Taylor@Sun.COM 	 *
15919517SBill.Taylor@Sun.COM 	 * Lastly, we check if "hs_ibtfpriv" is NULL.  If it is then it
15929517SBill.Taylor@Sun.COM 	 * means that we've have either received this event before we
15939517SBill.Taylor@Sun.COM 	 * finished attaching to the IBTF or we've received it while we
15949517SBill.Taylor@Sun.COM 	 * are in the process of detaching.
15959517SBill.Taylor@Sun.COM 	 */
15969517SBill.Taylor@Sun.COM 	if ((qp != NULL) && (qp->qp_qpnum == qpnum) &&
15979517SBill.Taylor@Sun.COM 	    (state->hs_ibtfpriv != NULL)) {
15989517SBill.Taylor@Sun.COM 		event.ev_srq_hdl = (ibt_srq_hdl_t)qp->qp_srqhdl->srq_hdlrarg;
15999517SBill.Taylor@Sun.COM 		type		= IBT_ERROR_CATASTROPHIC_SRQ;
16009517SBill.Taylor@Sun.COM 
16019517SBill.Taylor@Sun.COM 		mutex_enter(&qp->qp_srqhdl->srq_lock);
16029517SBill.Taylor@Sun.COM 		qp->qp_srqhdl->srq_state = HERMON_SRQ_STATE_ERROR;
16039517SBill.Taylor@Sun.COM 		mutex_exit(&qp->qp_srqhdl->srq_lock);
16049517SBill.Taylor@Sun.COM 
16059517SBill.Taylor@Sun.COM 		HERMON_DO_IBTF_ASYNC_CALLB(state, type, &event);
16069517SBill.Taylor@Sun.COM 	}
16079517SBill.Taylor@Sun.COM 
16089517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
16099517SBill.Taylor@Sun.COM }
16109517SBill.Taylor@Sun.COM 
16119517SBill.Taylor@Sun.COM 
16129517SBill.Taylor@Sun.COM /*
16139517SBill.Taylor@Sun.COM  * hermon_srq_last_wqe_reached_handler()
16149517SBill.Taylor@Sun.COM  *    Context: Only called from interrupt context
16159517SBill.Taylor@Sun.COM  */
1616*12965SWilliam.Taylor@Oracle.COM /* ARGSUSED */
16179517SBill.Taylor@Sun.COM static int
hermon_srq_last_wqe_reached_handler(hermon_state_t * state,hermon_eqhdl_t eq,hermon_hw_eqe_t * eqe)16189517SBill.Taylor@Sun.COM hermon_srq_last_wqe_reached_handler(hermon_state_t *state, hermon_eqhdl_t eq,
16199517SBill.Taylor@Sun.COM     hermon_hw_eqe_t *eqe)
16209517SBill.Taylor@Sun.COM {
16219517SBill.Taylor@Sun.COM 	hermon_qphdl_t		qp;
16229517SBill.Taylor@Sun.COM 	uint_t			qpnum;
16239517SBill.Taylor@Sun.COM 	ibc_async_event_t	event;
16249517SBill.Taylor@Sun.COM 	ibt_async_code_t	type;
16259517SBill.Taylor@Sun.COM 
16269517SBill.Taylor@Sun.COM 	/* Get the QP handle from QP number in event descriptor */
16279517SBill.Taylor@Sun.COM 	qpnum = HERMON_EQE_QPNUM_GET(eq, eqe);
16289517SBill.Taylor@Sun.COM 	qp = hermon_qphdl_from_qpnum(state, qpnum);
16299517SBill.Taylor@Sun.COM 
16309517SBill.Taylor@Sun.COM 	/*
16319517SBill.Taylor@Sun.COM 	 * If the QP handle is NULL, this is probably an indication
16329517SBill.Taylor@Sun.COM 	 * that the QP has been freed already.  In which case, we
16339517SBill.Taylor@Sun.COM 	 * should not deliver this event.
16349517SBill.Taylor@Sun.COM 	 *
16359517SBill.Taylor@Sun.COM 	 * We also check that the QP number in the handle is the
16369517SBill.Taylor@Sun.COM 	 * same as the QP number in the event queue entry.  This
16379517SBill.Taylor@Sun.COM 	 * extra check allows us to handle the case where a QP was
16389517SBill.Taylor@Sun.COM 	 * freed and then allocated again in the time it took to
16399517SBill.Taylor@Sun.COM 	 * handle the event queue processing.  By constantly incrementing
16409517SBill.Taylor@Sun.COM 	 * the non-constrained portion of the QP number every time
16419517SBill.Taylor@Sun.COM 	 * a new QP is allocated, we mitigate (somewhat) the chance
16429517SBill.Taylor@Sun.COM 	 * that a stale event could be passed to the client's QP
16439517SBill.Taylor@Sun.COM 	 * handler.
16449517SBill.Taylor@Sun.COM 	 *
16459517SBill.Taylor@Sun.COM 	 * Lastly, we check if "hs_ibtfpriv" is NULL.  If it is then it
16469517SBill.Taylor@Sun.COM 	 * means that we've have either received this event before we
16479517SBill.Taylor@Sun.COM 	 * finished attaching to the IBTF or we've received it while we
16489517SBill.Taylor@Sun.COM 	 * are in the process of detaching.
16499517SBill.Taylor@Sun.COM 	 */
16509517SBill.Taylor@Sun.COM 	if ((qp != NULL) && (qp->qp_qpnum == qpnum) &&
16519517SBill.Taylor@Sun.COM 	    (state->hs_ibtfpriv != NULL)) {
16529517SBill.Taylor@Sun.COM 		event.ev_qp_hdl = (ibtl_qp_hdl_t)qp->qp_hdlrarg;
16539517SBill.Taylor@Sun.COM 		type		= IBT_EVENT_EMPTY_CHAN;
16549517SBill.Taylor@Sun.COM 
16559517SBill.Taylor@Sun.COM 		HERMON_DO_IBTF_ASYNC_CALLB(state, type, &event);
16569517SBill.Taylor@Sun.COM 	}
16579517SBill.Taylor@Sun.COM 
16589517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
16599517SBill.Taylor@Sun.COM }
16609517SBill.Taylor@Sun.COM 
16619517SBill.Taylor@Sun.COM 
1662*12965SWilliam.Taylor@Oracle.COM /* ARGSUSED */
hermon_fexch_error_handler(hermon_state_t * state,hermon_eqhdl_t eq,hermon_hw_eqe_t * eqe)1663*12965SWilliam.Taylor@Oracle.COM static int hermon_fexch_error_handler(hermon_state_t *state,
1664*12965SWilliam.Taylor@Oracle.COM     hermon_eqhdl_t eq, hermon_hw_eqe_t *eqe)
16659517SBill.Taylor@Sun.COM {
1666*12965SWilliam.Taylor@Oracle.COM 	hermon_qphdl_t		qp;
1667*12965SWilliam.Taylor@Oracle.COM 	uint_t			qpnum;
1668*12965SWilliam.Taylor@Oracle.COM 	ibc_async_event_t	event;
1669*12965SWilliam.Taylor@Oracle.COM 	ibt_async_code_t	type;
16709517SBill.Taylor@Sun.COM 
1671*12965SWilliam.Taylor@Oracle.COM 	/* Get the QP handle from QP number in event descriptor */
1672*12965SWilliam.Taylor@Oracle.COM 	event.ev_port = HERMON_EQE_FEXCH_PORTNUM_GET(eq, eqe);
1673*12965SWilliam.Taylor@Oracle.COM 	qpnum = hermon_fcoib_qpnum_from_fexch(state,
1674*12965SWilliam.Taylor@Oracle.COM 	    event.ev_port, HERMON_EQE_FEXCH_FEXCH_GET(eq, eqe));
1675*12965SWilliam.Taylor@Oracle.COM 	qp = hermon_qphdl_from_qpnum(state, qpnum);
16769517SBill.Taylor@Sun.COM 
1677*12965SWilliam.Taylor@Oracle.COM 	event.ev_fc = HERMON_EQE_FEXCH_SYNDROME_GET(eq, eqe);
16789517SBill.Taylor@Sun.COM 
16799517SBill.Taylor@Sun.COM 	/*
1680*12965SWilliam.Taylor@Oracle.COM 	 * If the QP handle is NULL, this is probably an indication
1681*12965SWilliam.Taylor@Oracle.COM 	 * that the QP has been freed already.  In which case, we
1682*12965SWilliam.Taylor@Oracle.COM 	 * should not deliver this event.
1683*12965SWilliam.Taylor@Oracle.COM 	 *
1684*12965SWilliam.Taylor@Oracle.COM 	 * We also check that the QP number in the handle is the
1685*12965SWilliam.Taylor@Oracle.COM 	 * same as the QP number in the event queue entry.  This
1686*12965SWilliam.Taylor@Oracle.COM 	 * extra check allows us to handle the case where a QP was
1687*12965SWilliam.Taylor@Oracle.COM 	 * freed and then allocated again in the time it took to
1688*12965SWilliam.Taylor@Oracle.COM 	 * handle the event queue processing.  By constantly incrementing
1689*12965SWilliam.Taylor@Oracle.COM 	 * the non-constrained portion of the QP number every time
1690*12965SWilliam.Taylor@Oracle.COM 	 * a new QP is allocated, we mitigate (somewhat) the chance
1691*12965SWilliam.Taylor@Oracle.COM 	 * that a stale event could be passed to the client's QP
1692*12965SWilliam.Taylor@Oracle.COM 	 * handler.
1693*12965SWilliam.Taylor@Oracle.COM 	 *
1694*12965SWilliam.Taylor@Oracle.COM 	 * Lastly, we check if "hs_ibtfpriv" is NULL.  If it is then it
1695*12965SWilliam.Taylor@Oracle.COM 	 * means that we've have either received this event before we
1696*12965SWilliam.Taylor@Oracle.COM 	 * finished attaching to the IBTF or we've received it while we
1697*12965SWilliam.Taylor@Oracle.COM 	 * are in the process of detaching.
16989517SBill.Taylor@Sun.COM 	 */
1699*12965SWilliam.Taylor@Oracle.COM 	if ((qp != NULL) && (qp->qp_qpnum == qpnum) &&
1700*12965SWilliam.Taylor@Oracle.COM 	    (state->hs_ibtfpriv != NULL)) {
1701*12965SWilliam.Taylor@Oracle.COM 		event.ev_qp_hdl = (ibtl_qp_hdl_t)qp->qp_hdlrarg;
1702*12965SWilliam.Taylor@Oracle.COM 		type		= IBT_FEXCH_ERROR;
1703*12965SWilliam.Taylor@Oracle.COM 
1704*12965SWilliam.Taylor@Oracle.COM 		HERMON_DO_IBTF_ASYNC_CALLB(state, type, &event);
17059517SBill.Taylor@Sun.COM 	}
17069517SBill.Taylor@Sun.COM 
17079517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
17089517SBill.Taylor@Sun.COM }
17099517SBill.Taylor@Sun.COM 
17109517SBill.Taylor@Sun.COM 
17119517SBill.Taylor@Sun.COM /*
17129517SBill.Taylor@Sun.COM  * hermon_no_eqhandler
17139517SBill.Taylor@Sun.COM  *    Context: Only called from interrupt context
17149517SBill.Taylor@Sun.COM  */
17159517SBill.Taylor@Sun.COM /* ARGSUSED */
17169517SBill.Taylor@Sun.COM static int
hermon_no_eqhandler(hermon_state_t * state,hermon_eqhdl_t eq,hermon_hw_eqe_t * eqe)17179517SBill.Taylor@Sun.COM hermon_no_eqhandler(hermon_state_t *state, hermon_eqhdl_t eq,
17189517SBill.Taylor@Sun.COM     hermon_hw_eqe_t *eqe)
17199517SBill.Taylor@Sun.COM {
17209517SBill.Taylor@Sun.COM 	uint_t		data;
17219517SBill.Taylor@Sun.COM 	int		i;
17229517SBill.Taylor@Sun.COM 
17239517SBill.Taylor@Sun.COM 	/*
17249517SBill.Taylor@Sun.COM 	 * This "unexpected event" handler (or "catch-all" handler) will
17259517SBill.Taylor@Sun.COM 	 * receive all events for which no other handler has been registered.
17269517SBill.Taylor@Sun.COM 	 * If we end up here, then something has probably gone seriously wrong
17279517SBill.Taylor@Sun.COM 	 * with the Hermon hardware (or, perhaps, with the software... though
17289517SBill.Taylor@Sun.COM 	 * it's unlikely in this case).  The EQE provides all the information
17299517SBill.Taylor@Sun.COM 	 * about the event.  So we print a warning message here along with
17309517SBill.Taylor@Sun.COM 	 * the contents of the EQE.
17319517SBill.Taylor@Sun.COM 	 */
17329517SBill.Taylor@Sun.COM 	HERMON_WARNING(state, "Unexpected Event handler");
17339517SBill.Taylor@Sun.COM 	cmn_err(CE_CONT, "  Event type: %02x, subtype: %02x\n",
17349517SBill.Taylor@Sun.COM 	    HERMON_EQE_EVTTYPE_GET(eq, eqe),
17359517SBill.Taylor@Sun.COM 	    HERMON_EQE_EVTSUBTYPE_GET(eq, eqe));
17369517SBill.Taylor@Sun.COM 	for (i = 0; i < sizeof (hermon_hw_eqe_t) >> 2; i++) {
17379517SBill.Taylor@Sun.COM 		data = ((uint_t *)eqe)[i];
17389517SBill.Taylor@Sun.COM 		cmn_err(CE_CONT, "  EQE[%02x]: %08x\n", i, data);
17399517SBill.Taylor@Sun.COM 	}
17409517SBill.Taylor@Sun.COM 
17419517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
17429517SBill.Taylor@Sun.COM }
1743