19e39c5baSBill Taylor /*
29e39c5baSBill Taylor  * CDDL HEADER START
39e39c5baSBill Taylor  *
49e39c5baSBill Taylor  * The contents of this file are subject to the terms of the
59e39c5baSBill Taylor  * Common Development and Distribution License (the "License").
69e39c5baSBill Taylor  * You may not use this file except in compliance with the License.
79e39c5baSBill Taylor  *
89e39c5baSBill Taylor  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99e39c5baSBill Taylor  * or http://www.opensolaris.org/os/licensing.
109e39c5baSBill Taylor  * See the License for the specific language governing permissions
119e39c5baSBill Taylor  * and limitations under the License.
129e39c5baSBill Taylor  *
139e39c5baSBill Taylor  * When distributing Covered Code, include this CDDL HEADER in each
149e39c5baSBill Taylor  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159e39c5baSBill Taylor  * If applicable, add the following below this CDDL HEADER, with the
169e39c5baSBill Taylor  * fields enclosed by brackets "[]" replaced with your own identifying
179e39c5baSBill Taylor  * information: Portions Copyright [yyyy] [name of copyright owner]
189e39c5baSBill Taylor  *
199e39c5baSBill Taylor  * CDDL HEADER END
209e39c5baSBill Taylor  */
219e39c5baSBill Taylor 
229e39c5baSBill Taylor /*
239e39c5baSBill Taylor  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
249e39c5baSBill Taylor  * Use is subject to license terms.
259e39c5baSBill Taylor  */
269e39c5baSBill Taylor 
279e39c5baSBill Taylor /*
289e39c5baSBill Taylor  * hermon_agents.c
299e39c5baSBill Taylor  *    Hermon InfiniBand Management Agent (SMA, PMA, BMA) routines
309e39c5baSBill Taylor  *
319e39c5baSBill Taylor  *    Implements all the routines necessary for initializing, handling,
329e39c5baSBill Taylor  *    and (later) tearing down all the infrastructure necessary for Hermon
339e39c5baSBill Taylor  *    MAD processing.
349e39c5baSBill Taylor  */
359e39c5baSBill Taylor 
369e39c5baSBill Taylor #include <sys/types.h>
379e39c5baSBill Taylor #include <sys/conf.h>
389e39c5baSBill Taylor #include <sys/ddi.h>
399e39c5baSBill Taylor #include <sys/sunddi.h>
409e39c5baSBill Taylor #include <sys/modctl.h>
419e39c5baSBill Taylor 
429e39c5baSBill Taylor #include <sys/ib/adapters/hermon/hermon.h>
439e39c5baSBill Taylor #include <sys/ib/mgt/ibmf/ibmf.h>
449e39c5baSBill Taylor #include <sys/disp.h>
459e39c5baSBill Taylor 
469e39c5baSBill Taylor static void hermon_agent_request_cb(ibmf_handle_t ibmf_handle,
479e39c5baSBill Taylor     ibmf_msg_t *msgp, void *args);
489e39c5baSBill Taylor static void hermon_agent_handle_req(void *cb_args);
499e39c5baSBill Taylor static void hermon_agent_response_cb(ibmf_handle_t ibmf_handle,
509e39c5baSBill Taylor     ibmf_msg_t *msgp, void *args);
519e39c5baSBill Taylor static int hermon_agent_list_init(hermon_state_t *state);
529e39c5baSBill Taylor static void hermon_agent_list_fini(hermon_state_t *state);
539e39c5baSBill Taylor static int hermon_agent_register_all(hermon_state_t *state);
549e39c5baSBill Taylor static int hermon_agent_unregister_all(hermon_state_t *state, int num_reg);
559e39c5baSBill Taylor static void hermon_agent_mad_resp_handling(hermon_state_t *state,
569e39c5baSBill Taylor     ibmf_msg_t *msgp, uint_t port);
579e39c5baSBill Taylor 
589e39c5baSBill Taylor /*
599e39c5baSBill Taylor  * hermon_agent_handlers_init()
609e39c5baSBill Taylor  *    Context: Only called from attach() and/or detach() path contexts
619e39c5baSBill Taylor  */
629e39c5baSBill Taylor int
hermon_agent_handlers_init(hermon_state_t * state)639e39c5baSBill Taylor hermon_agent_handlers_init(hermon_state_t *state)
649e39c5baSBill Taylor {
659e39c5baSBill Taylor 	int		status;
669e39c5baSBill Taylor 	char		*rsrc_name;
679e39c5baSBill Taylor 
689e39c5baSBill Taylor 	/* Determine if we need to register any agents with the IBMF */
699e39c5baSBill Taylor 	if ((state->hs_cfg_profile->cp_qp0_agents_in_fw) &&
709e39c5baSBill Taylor 	    (state->hs_cfg_profile->cp_qp1_agents_in_fw)) {
719e39c5baSBill Taylor 		return (DDI_SUCCESS);
729e39c5baSBill Taylor 	}
739e39c5baSBill Taylor 
749e39c5baSBill Taylor 	/*
759e39c5baSBill Taylor 	 * Build a unique name for the Hermon task queue from the Hermon driver
769e39c5baSBill Taylor 	 * instance number and HERMON_TASKQ_NAME
779e39c5baSBill Taylor 	 */
789e39c5baSBill Taylor 	rsrc_name = (char *)kmem_zalloc(HERMON_RSRC_NAME_MAXLEN, KM_SLEEP);
799e39c5baSBill Taylor 	HERMON_RSRC_NAME(rsrc_name, HERMON_TASKQ_NAME);
809e39c5baSBill Taylor 
819e39c5baSBill Taylor 	/* Initialize the Hermon IB management agent list */
829e39c5baSBill Taylor 	status = hermon_agent_list_init(state);
839e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
849e39c5baSBill Taylor 		goto agentsinit_fail;
859e39c5baSBill Taylor 	}
869e39c5baSBill Taylor 
879e39c5baSBill Taylor 	/*
889e39c5baSBill Taylor 	 * Initialize the agent handling task queue.  Note: We set the task
899e39c5baSBill Taylor 	 * queue priority to the minimum system priority.  At this point this
909e39c5baSBill Taylor 	 * is considered acceptable because MADs are unreliable datagrams
919e39c5baSBill Taylor 	 * and could get lost (in general) anyway.
929e39c5baSBill Taylor 	 */
939e39c5baSBill Taylor 	state->hs_taskq_agents = ddi_taskq_create(state->hs_dip,
949e39c5baSBill Taylor 	    rsrc_name, HERMON_TASKQ_NTHREADS, TASKQ_DEFAULTPRI, 0);
959e39c5baSBill Taylor 	if (state->hs_taskq_agents == NULL) {
969e39c5baSBill Taylor 		hermon_agent_list_fini(state);
979e39c5baSBill Taylor 		goto agentsinit_fail;
989e39c5baSBill Taylor 	}
999e39c5baSBill Taylor 
1009e39c5baSBill Taylor 	/* Now attempt to register all of the agents with the IBMF */
1019e39c5baSBill Taylor 	status = hermon_agent_register_all(state);
1029e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
1039e39c5baSBill Taylor 		ddi_taskq_destroy(state->hs_taskq_agents);
1049e39c5baSBill Taylor 		hermon_agent_list_fini(state);
1059e39c5baSBill Taylor 		goto agentsinit_fail;
1069e39c5baSBill Taylor 	}
1079e39c5baSBill Taylor 
1089e39c5baSBill Taylor 	kmem_free(rsrc_name, HERMON_RSRC_NAME_MAXLEN);
1099e39c5baSBill Taylor 	return (DDI_SUCCESS);
1109e39c5baSBill Taylor 
1119e39c5baSBill Taylor agentsinit_fail:
1129e39c5baSBill Taylor 	kmem_free(rsrc_name, HERMON_RSRC_NAME_MAXLEN);
1139e39c5baSBill Taylor 	return (status);
1149e39c5baSBill Taylor }
1159e39c5baSBill Taylor 
1169e39c5baSBill Taylor 
1179e39c5baSBill Taylor /*
1189e39c5baSBill Taylor  * hermon_agent_handlers_fini()
1199e39c5baSBill Taylor  *    Context: Only called from detach() path context
1209e39c5baSBill Taylor  */
1219e39c5baSBill Taylor int
hermon_agent_handlers_fini(hermon_state_t * state)1229e39c5baSBill Taylor hermon_agent_handlers_fini(hermon_state_t *state)
1239e39c5baSBill Taylor {
1249e39c5baSBill Taylor 	int		status;
1259e39c5baSBill Taylor 
1269e39c5baSBill Taylor 	/* Determine if we need to unregister any agents from the IBMF */
1279e39c5baSBill Taylor 	if ((state->hs_cfg_profile->cp_qp0_agents_in_fw) &&
1289e39c5baSBill Taylor 	    (state->hs_cfg_profile->cp_qp1_agents_in_fw)) {
1299e39c5baSBill Taylor 		return (DDI_SUCCESS);
1309e39c5baSBill Taylor 	}
1319e39c5baSBill Taylor 
1329e39c5baSBill Taylor 	/* Now attempt to unregister all of the agents from the IBMF */
1339e39c5baSBill Taylor 	status = hermon_agent_unregister_all(state, state->hs_num_agents);
1349e39c5baSBill Taylor 	if (status != DDI_SUCCESS) {
1359e39c5baSBill Taylor 		return (DDI_FAILURE);
1369e39c5baSBill Taylor 	}
1379e39c5baSBill Taylor 
1389e39c5baSBill Taylor 	/*
1399e39c5baSBill Taylor 	 * Destroy the task queue.  The task queue destroy is guaranteed to
1409e39c5baSBill Taylor 	 * wait until any scheduled tasks have completed.  We are able to
1419e39c5baSBill Taylor 	 * guarantee that no _new_ tasks will be added the task queue while
1429e39c5baSBill Taylor 	 * we are in the ddi_taskq_destroy() call because we have
1439e39c5baSBill Taylor 	 * (at this point) successfully unregistered from IBMF (in
1449e39c5baSBill Taylor 	 * hermon_agent_unregister_all() above).
1459e39c5baSBill Taylor 	 */
1469e39c5baSBill Taylor 	ddi_taskq_destroy(state->hs_taskq_agents);
1479e39c5baSBill Taylor 
1489e39c5baSBill Taylor 	/* Teardown the Hermon IB management agent list */
1499e39c5baSBill Taylor 	hermon_agent_list_fini(state);
1509e39c5baSBill Taylor 
1519e39c5baSBill Taylor 	return (DDI_SUCCESS);
1529e39c5baSBill Taylor }
1539e39c5baSBill Taylor 
1549e39c5baSBill Taylor 
1559e39c5baSBill Taylor /*
1569e39c5baSBill Taylor  * hermon_agent_request_cb()
1579e39c5baSBill Taylor  *    Context: Called from the IBMF context
1589e39c5baSBill Taylor  */
1599e39c5baSBill Taylor static void
hermon_agent_request_cb(ibmf_handle_t ibmf_handle,ibmf_msg_t * msgp,void * args)1609e39c5baSBill Taylor hermon_agent_request_cb(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp,
1619e39c5baSBill Taylor     void *args)
1629e39c5baSBill Taylor {
1639e39c5baSBill Taylor 	hermon_agent_handler_arg_t	*cb_args;
1649e39c5baSBill Taylor 	hermon_agent_list_t		*curr;
1659e39c5baSBill Taylor 	hermon_state_t			*state;
1669e39c5baSBill Taylor 	int				status;
1679e39c5baSBill Taylor 
1689e39c5baSBill Taylor 	curr  = (hermon_agent_list_t *)args;
1699e39c5baSBill Taylor 	state = curr->agl_state;
1709e39c5baSBill Taylor 
1719e39c5baSBill Taylor 	/*
1729e39c5baSBill Taylor 	 * Allocate space to hold the callback args (for passing to the
1739e39c5baSBill Taylor 	 * task queue).  Note: If we are unable to allocate space for the
1749e39c5baSBill Taylor 	 * the callback args here, then we just return.  But we must ensure
1759e39c5baSBill Taylor 	 * that we call ibmf_free_msg() to free up the message.
1769e39c5baSBill Taylor 	 */
1779e39c5baSBill Taylor 	cb_args = (hermon_agent_handler_arg_t *)kmem_zalloc(
1789e39c5baSBill Taylor 	    sizeof (hermon_agent_handler_arg_t), KM_NOSLEEP);
1799e39c5baSBill Taylor 	if (cb_args == NULL) {
1809e39c5baSBill Taylor 		(void) ibmf_free_msg(ibmf_handle, &msgp);
1819e39c5baSBill Taylor 		return;
1829e39c5baSBill Taylor 	}
1839e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*cb_args))
1849e39c5baSBill Taylor 
1859e39c5baSBill Taylor 	/* Fill in the callback args */
1869e39c5baSBill Taylor 	cb_args->ahd_ibmfhdl	= ibmf_handle;
1879e39c5baSBill Taylor 	cb_args->ahd_ibmfmsg	= msgp;
1889e39c5baSBill Taylor 	cb_args->ahd_agentlist	= args;
1899e39c5baSBill Taylor 
1909e39c5baSBill Taylor 	/*
1919e39c5baSBill Taylor 	 * Dispatch the message to the task queue.  Note: Just like above,
1929e39c5baSBill Taylor 	 * if this request fails for any reason then make sure to free up
1939e39c5baSBill Taylor 	 * the IBMF message and then return
1949e39c5baSBill Taylor 	 */
1959e39c5baSBill Taylor 	status = ddi_taskq_dispatch(state->hs_taskq_agents,
1969e39c5baSBill Taylor 	    hermon_agent_handle_req, cb_args, DDI_NOSLEEP);
1979e39c5baSBill Taylor 	if (status == DDI_FAILURE) {
1989e39c5baSBill Taylor 		kmem_free(cb_args, sizeof (hermon_agent_handler_arg_t));
1999e39c5baSBill Taylor 		(void) ibmf_free_msg(ibmf_handle, &msgp);
2009e39c5baSBill Taylor 	}
2019e39c5baSBill Taylor }
2029e39c5baSBill Taylor 
2039e39c5baSBill Taylor /*
2049e39c5baSBill Taylor  * hermon_get_smlid()
2059e39c5baSBill Taylor  *	Simple helper function for hermon_agent_handle_req() below.
2069e39c5baSBill Taylor  *	Get the portinfo and extract the smlid.
2079e39c5baSBill Taylor  */
2089e39c5baSBill Taylor static ib_lid_t
hermon_get_smlid(hermon_state_t * state,uint_t port)2099e39c5baSBill Taylor hermon_get_smlid(hermon_state_t *state, uint_t port)
2109e39c5baSBill Taylor {
2119e39c5baSBill Taylor 	sm_portinfo_t			portinfo;
2129e39c5baSBill Taylor 	int				status;
2139e39c5baSBill Taylor 
2149e39c5baSBill Taylor 	status = hermon_getportinfo_cmd_post(state, port,
2159e39c5baSBill Taylor 	    HERMON_SLEEPFLAG_FOR_CONTEXT(), &portinfo);
2169e39c5baSBill Taylor 	if (status != HERMON_CMD_SUCCESS) {
2179e39c5baSBill Taylor 		cmn_err(CE_CONT, "Hermon: GetPortInfo (port %02d) command "
2189e39c5baSBill Taylor 		    "failed: %08x\n", port, status);
2199e39c5baSBill Taylor 		return (0);
2209e39c5baSBill Taylor 	}
2219e39c5baSBill Taylor 	return (portinfo.MasterSMLID);
2229e39c5baSBill Taylor }
2239e39c5baSBill Taylor 
224*76c04273SRajkumar Sivaprakasam /*
225*76c04273SRajkumar Sivaprakasam  * hermon_get_port_change_flags()
226*76c04273SRajkumar Sivaprakasam  * 	Helper function to determine the changes in the incoming MAD's portinfo
227*76c04273SRajkumar Sivaprakasam  * 	for the Port Change event.
228*76c04273SRajkumar Sivaprakasam  */
229*76c04273SRajkumar Sivaprakasam static ibt_port_change_t
hermon_port_change_flags(sm_portinfo_t * curpinfo,sm_portinfo_t * madpinfo)230*76c04273SRajkumar Sivaprakasam hermon_port_change_flags(sm_portinfo_t *curpinfo, sm_portinfo_t *madpinfo)
231*76c04273SRajkumar Sivaprakasam {
232*76c04273SRajkumar Sivaprakasam 	int SMDisabled, ReregSuppd;
233*76c04273SRajkumar Sivaprakasam 	ibt_port_change_t flags = 0;
234*76c04273SRajkumar Sivaprakasam 
235*76c04273SRajkumar Sivaprakasam 	SMDisabled = curpinfo->CapabilityMask & SM_CAP_MASK_IS_SM_DISABLED;
236*76c04273SRajkumar Sivaprakasam 	ReregSuppd = curpinfo->CapabilityMask & SM_CAP_MASK_IS_CLNT_REREG_SUPPD;
237*76c04273SRajkumar Sivaprakasam 
238*76c04273SRajkumar Sivaprakasam 	if (curpinfo->MasterSMLID != madpinfo->MasterSMLID) {
239*76c04273SRajkumar Sivaprakasam 		flags |= IBT_PORT_CHANGE_SM_LID;
240*76c04273SRajkumar Sivaprakasam 	}
241*76c04273SRajkumar Sivaprakasam 	if (curpinfo->MasterSMSL != madpinfo->MasterSMSL) {
242*76c04273SRajkumar Sivaprakasam 		flags |= IBT_PORT_CHANGE_SM_SL;
243*76c04273SRajkumar Sivaprakasam 	}
244*76c04273SRajkumar Sivaprakasam 	if (curpinfo->SubnetTimeOut != madpinfo->SubnetTimeOut) {
245*76c04273SRajkumar Sivaprakasam 		flags |= IBT_PORT_CHANGE_SUB_TIMEOUT;
246*76c04273SRajkumar Sivaprakasam 	}
247*76c04273SRajkumar Sivaprakasam 	if ((madpinfo->CapabilityMask & SM_CAP_MASK_IS_SM_DISABLED)
248*76c04273SRajkumar Sivaprakasam 	    ^ SMDisabled) {
249*76c04273SRajkumar Sivaprakasam 		flags |= IBT_PORT_CHANGE_SM_FLAG;
250*76c04273SRajkumar Sivaprakasam 	}
251*76c04273SRajkumar Sivaprakasam 	if ((madpinfo->CapabilityMask & SM_CAP_MASK_IS_CLNT_REREG_SUPPD)
252*76c04273SRajkumar Sivaprakasam 	    ^ ReregSuppd) {
253*76c04273SRajkumar Sivaprakasam 		flags |= IBT_PORT_CHANGE_REREG;
254*76c04273SRajkumar Sivaprakasam 	}
255*76c04273SRajkumar Sivaprakasam 	return (flags);
256*76c04273SRajkumar Sivaprakasam }
257*76c04273SRajkumar Sivaprakasam 
258*76c04273SRajkumar Sivaprakasam int
hermon_set_port_capability(hermon_state_t * state,uint8_t port,sm_portinfo_t * portinfo,ibt_port_change_t flags)259*76c04273SRajkumar Sivaprakasam hermon_set_port_capability(hermon_state_t *state, uint8_t port,
260*76c04273SRajkumar Sivaprakasam     sm_portinfo_t *portinfo, ibt_port_change_t flags)
261*76c04273SRajkumar Sivaprakasam {
262*76c04273SRajkumar Sivaprakasam 	uint32_t		capmask;
263*76c04273SRajkumar Sivaprakasam 	int			status;
264*76c04273SRajkumar Sivaprakasam 	hermon_hw_set_port_t	set_port;
265*76c04273SRajkumar Sivaprakasam 
266*76c04273SRajkumar Sivaprakasam 	bzero(&set_port, sizeof (set_port));
267*76c04273SRajkumar Sivaprakasam 
268*76c04273SRajkumar Sivaprakasam 	/* Validate that specified port number is legal */
269*76c04273SRajkumar Sivaprakasam 	if (!hermon_portnum_is_valid(state, port)) {
270*76c04273SRajkumar Sivaprakasam 		return (IBT_HCA_PORT_INVALID);
271*76c04273SRajkumar Sivaprakasam 	}
272*76c04273SRajkumar Sivaprakasam 
273*76c04273SRajkumar Sivaprakasam 	/*
274*76c04273SRajkumar Sivaprakasam 	 * Convert InfiniBand-defined port capability flags to the format
275*76c04273SRajkumar Sivaprakasam 	 * specified by the IBTF.  Specifically, we modify the capability
276*76c04273SRajkumar Sivaprakasam 	 * mask based on the specified values.
277*76c04273SRajkumar Sivaprakasam 	 */
278*76c04273SRajkumar Sivaprakasam 	capmask = portinfo->CapabilityMask;
279*76c04273SRajkumar Sivaprakasam 
280*76c04273SRajkumar Sivaprakasam 	if (flags & IBT_PORT_CHANGE_SM_FLAG)
281*76c04273SRajkumar Sivaprakasam 		capmask ^= SM_CAP_MASK_IS_SM;
282*76c04273SRajkumar Sivaprakasam 
283*76c04273SRajkumar Sivaprakasam 	if (flags & IBT_PORT_CHANGE_REREG)
284*76c04273SRajkumar Sivaprakasam 		capmask ^= SM_CAP_MASK_IS_CLNT_REREG_SUPPD;
285*76c04273SRajkumar Sivaprakasam 	set_port.cap_mask = capmask;
286*76c04273SRajkumar Sivaprakasam 
287*76c04273SRajkumar Sivaprakasam 	/*
288*76c04273SRajkumar Sivaprakasam 	 * Use the Hermon SET_PORT command to update the capability mask and
289*76c04273SRajkumar Sivaprakasam 	 * (possibly) reset the QKey violation counter for the specified port.
290*76c04273SRajkumar Sivaprakasam 	 * Note: In general, this operation shouldn't fail.  If it does, then
291*76c04273SRajkumar Sivaprakasam 	 * it is an indication that something (probably in HW, but maybe in
292*76c04273SRajkumar Sivaprakasam 	 * SW) has gone seriously wrong.
293*76c04273SRajkumar Sivaprakasam 	 */
294*76c04273SRajkumar Sivaprakasam 	status = hermon_set_port_cmd_post(state, &set_port, port,
295*76c04273SRajkumar Sivaprakasam 	    HERMON_SLEEPFLAG_FOR_CONTEXT());
296*76c04273SRajkumar Sivaprakasam 	if (status != HERMON_CMD_SUCCESS) {
297*76c04273SRajkumar Sivaprakasam 		HERMON_WARNING(state, "failed to modify port capabilities");
298*76c04273SRajkumar Sivaprakasam 		cmn_err(CE_CONT, "Hermon: SET_IB (port %02d) command failed: "
299*76c04273SRajkumar Sivaprakasam 		    "%08x\n", port, status);
300*76c04273SRajkumar Sivaprakasam 		return (DDI_FAILURE);
301*76c04273SRajkumar Sivaprakasam 	}
302*76c04273SRajkumar Sivaprakasam 
303*76c04273SRajkumar Sivaprakasam 	return (DDI_SUCCESS);
304*76c04273SRajkumar Sivaprakasam }
305*76c04273SRajkumar Sivaprakasam 
3069e39c5baSBill Taylor /*
3079e39c5baSBill Taylor  * hermon_agent_handle_req()
3089e39c5baSBill Taylor  *    Context: Called with priority of taskQ thread
3099e39c5baSBill Taylor  */
3109e39c5baSBill Taylor static void
hermon_agent_handle_req(void * cb_args)3119e39c5baSBill Taylor hermon_agent_handle_req(void *cb_args)
3129e39c5baSBill Taylor {
3139e39c5baSBill Taylor 	hermon_agent_handler_arg_t	*agent_args;
3149e39c5baSBill Taylor 	hermon_agent_list_t		*curr;
315*76c04273SRajkumar Sivaprakasam 	ibc_async_event_t		event;
316*76c04273SRajkumar Sivaprakasam 	ibt_async_code_t		type, code;
317*76c04273SRajkumar Sivaprakasam 	sm_portinfo_t			curpinfo, tmadpinfo;
318*76c04273SRajkumar Sivaprakasam 	sm_portinfo_t			*madpinfop;
3199e39c5baSBill Taylor 	hermon_state_t			*state;
3209e39c5baSBill Taylor 	ibmf_handle_t			ibmf_handle;
3219e39c5baSBill Taylor 	ibmf_msg_t			*msgp;
3229e39c5baSBill Taylor 	ibmf_msg_bufs_t			*recv_msgbufp;
3239e39c5baSBill Taylor 	ibmf_msg_bufs_t			*send_msgbufp;
324*76c04273SRajkumar Sivaprakasam 	ib_mad_hdr_t			*madhdrp;
3259e39c5baSBill Taylor 	ibmf_retrans_t			retrans;
3269e39c5baSBill Taylor 	uint_t				port;
3279e39c5baSBill Taylor 	int				status;
3289e39c5baSBill Taylor 
329*76c04273SRajkumar Sivaprakasam 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*((sm_portinfo_t *)madpinfop)))
330*76c04273SRajkumar Sivaprakasam 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(curpinfo))
331*76c04273SRajkumar Sivaprakasam 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(tmadpinfo))
3329e39c5baSBill Taylor 	/* Extract the necessary info from the callback args parameter */
3339e39c5baSBill Taylor 	agent_args  = (hermon_agent_handler_arg_t *)cb_args;
3349e39c5baSBill Taylor 	ibmf_handle = agent_args->ahd_ibmfhdl;
3359e39c5baSBill Taylor 	msgp	    = agent_args->ahd_ibmfmsg;
3369e39c5baSBill Taylor 	curr	    = agent_args->ahd_agentlist;
3379e39c5baSBill Taylor 	state	    = curr->agl_state;
3389e39c5baSBill Taylor 	port	    = curr->agl_port;
3399e39c5baSBill Taylor 
3409e39c5baSBill Taylor 	/*
3419e39c5baSBill Taylor 	 * Set the message send buffer pointers to the message receive buffer
3429e39c5baSBill Taylor 	 * pointers to reuse the IBMF provided buffers for the sender
3439e39c5baSBill Taylor 	 * information.
3449e39c5baSBill Taylor 	 */
3459e39c5baSBill Taylor 	recv_msgbufp = &msgp->im_msgbufs_recv;
3469e39c5baSBill Taylor 	send_msgbufp = &msgp->im_msgbufs_send;
3479e39c5baSBill Taylor 	bcopy(recv_msgbufp, send_msgbufp, sizeof (ibmf_msg_bufs_t));
3489e39c5baSBill Taylor 
3499e39c5baSBill Taylor 	/*
3509e39c5baSBill Taylor 	 * Check if the incoming packet is a special "Hermon Trap" MAD.  If it
3519e39c5baSBill Taylor 	 * is, then do the special handling.  If it isn't, then simply pass it
3529e39c5baSBill Taylor 	 * on to the firmware and forward the response back to the IBMF.
3539e39c5baSBill Taylor 	 *
3549e39c5baSBill Taylor 	 * Note: Hermon has a unique method for handling internally generated
3559e39c5baSBill Taylor 	 * Traps.  All internally detected/generated Trap messages are
3569e39c5baSBill Taylor 	 * automatically received by the IBMF (as receive completions on QP0),
3579e39c5baSBill Taylor 	 * which (because all Hermon Trap MADs have SLID == 0) detects it as a
3589e39c5baSBill Taylor 	 * special "Hermon Trap" and forwards it here to the driver's SMA.
3599e39c5baSBill Taylor 	 * It is then our responsibility here to fill in the Trap MAD's DLID
3609e39c5baSBill Taylor 	 * for forwarding to the real Master SM (as programmed in the port's
3619e39c5baSBill Taylor 	 * PortInfo.MasterSMLID field.)
3629e39c5baSBill Taylor 	 */
3639e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(msgp->im_local_addr))
3649e39c5baSBill Taylor 	if (HERMON_IS_SPECIAL_TRAP_MAD(msgp)) {
3659e39c5baSBill Taylor 		msgp->im_local_addr.ia_remote_lid =
3669e39c5baSBill Taylor 		    hermon_get_smlid(state, port);
3679e39c5baSBill Taylor 	} else {
368*76c04273SRajkumar Sivaprakasam 		int isSMSet, isReregSuppd;
369*76c04273SRajkumar Sivaprakasam 		uint_t attr_id, method, mgmt_class;
370*76c04273SRajkumar Sivaprakasam 
371*76c04273SRajkumar Sivaprakasam 		madhdrp = recv_msgbufp->im_bufs_mad_hdr;
372*76c04273SRajkumar Sivaprakasam 		method = madhdrp->R_Method;
373*76c04273SRajkumar Sivaprakasam 		attr_id = b2h16(madhdrp->AttributeID);
374*76c04273SRajkumar Sivaprakasam 		mgmt_class = madhdrp->MgmtClass;
375*76c04273SRajkumar Sivaprakasam 
376*76c04273SRajkumar Sivaprakasam 		/*
377*76c04273SRajkumar Sivaprakasam 		 * Is this a Subnet Manager MAD with SET method ? If so
378*76c04273SRajkumar Sivaprakasam 		 * we will have to get the current portinfo to generate
379*76c04273SRajkumar Sivaprakasam 		 * events based on what has changed in portinfo.
380*76c04273SRajkumar Sivaprakasam 		 */
381*76c04273SRajkumar Sivaprakasam 		isSMSet = (((mgmt_class == MAD_MGMT_CLASS_SUBN_LID_ROUTED)||
382*76c04273SRajkumar Sivaprakasam 		    (mgmt_class == MAD_MGMT_CLASS_SUBN_DIRECT_ROUTE)) &&
383*76c04273SRajkumar Sivaprakasam 		    (method == MAD_METHOD_SET));
384*76c04273SRajkumar Sivaprakasam 
385*76c04273SRajkumar Sivaprakasam 		/*
386*76c04273SRajkumar Sivaprakasam 		 * Get the current portinfo to compare with the portinfo
387*76c04273SRajkumar Sivaprakasam 		 * received in the MAD for PortChange event.
388*76c04273SRajkumar Sivaprakasam 		 */
389*76c04273SRajkumar Sivaprakasam 		if (isSMSet && (attr_id == SM_PORTINFO_ATTRID) ||
390*76c04273SRajkumar Sivaprakasam 		    (attr_id == SM_PKEY_TABLE_ATTRID) ||
391*76c04273SRajkumar Sivaprakasam 		    (attr_id == SM_GUIDINFO_ATTRID)) {
392*76c04273SRajkumar Sivaprakasam 			madpinfop = recv_msgbufp->im_bufs_cl_data;
393*76c04273SRajkumar Sivaprakasam 			tmadpinfo = *madpinfop;
394*76c04273SRajkumar Sivaprakasam 			HERMON_GETPORTINFO_SWAP(&tmadpinfo);
395*76c04273SRajkumar Sivaprakasam 			status = hermon_getportinfo_cmd_post(state, port,
396*76c04273SRajkumar Sivaprakasam 			    HERMON_SLEEPFLAG_FOR_CONTEXT(), &curpinfo);
397*76c04273SRajkumar Sivaprakasam 			if (status != HERMON_CMD_SUCCESS) {
398*76c04273SRajkumar Sivaprakasam 				cmn_err(CE_CONT, "Hermon: GetPortInfo "
399*76c04273SRajkumar Sivaprakasam 				    "(port %02d) command failed: %08x\n", port,
400*76c04273SRajkumar Sivaprakasam 				    status);
401*76c04273SRajkumar Sivaprakasam 				goto hermon_agent_handle_req_skip_response;
402*76c04273SRajkumar Sivaprakasam 			}
403*76c04273SRajkumar Sivaprakasam 		}
404*76c04273SRajkumar Sivaprakasam 
4059e39c5baSBill Taylor 		/*
4069e39c5baSBill Taylor 		 * Post the command to the firmware (using the MAD_IFC
4079e39c5baSBill Taylor 		 * command).  Note: We also reuse the command that was passed
4089e39c5baSBill Taylor 		 * in.  We pass the pointer to the original MAD payload as if
4099e39c5baSBill Taylor 		 * it were both the source of the incoming MAD as well as the
4109e39c5baSBill Taylor 		 * destination for the response.  This is acceptable and saves
4119e39c5baSBill Taylor 		 * us the step of one additional copy.  Note:  If this command
4129e39c5baSBill Taylor 		 * fails for any reason other than HERMON_CMD_BAD_PKT, it
4139e39c5baSBill Taylor 		 * probably indicates a serious problem.
4149e39c5baSBill Taylor 		 */
4159e39c5baSBill Taylor 		status = hermon_mad_ifc_cmd_post(state, port,
4169e39c5baSBill Taylor 		    HERMON_CMD_SLEEP_NOSPIN,
4179e39c5baSBill Taylor 		    (uint32_t *)recv_msgbufp->im_bufs_mad_hdr,
4189e39c5baSBill Taylor 		    (uint32_t *)send_msgbufp->im_bufs_mad_hdr);
4199e39c5baSBill Taylor 		if (status != HERMON_CMD_SUCCESS) {
4209e39c5baSBill Taylor 			if ((status != HERMON_CMD_BAD_PKT) &&
4219e39c5baSBill Taylor 			    (status != HERMON_CMD_INSUFF_RSRC)) {
4229e39c5baSBill Taylor 				cmn_err(CE_CONT, "Hermon: MAD_IFC (port %02d) "
4239e39c5baSBill Taylor 				    "command failed: %08x\n", port, status);
4249e39c5baSBill Taylor 			}
4259e39c5baSBill Taylor 
4269e39c5baSBill Taylor 			/* finish cleanup */
4279e39c5baSBill Taylor 			goto hermon_agent_handle_req_skip_response;
4289e39c5baSBill Taylor 		}
429*76c04273SRajkumar Sivaprakasam 
430*76c04273SRajkumar Sivaprakasam 		if (isSMSet) {
431*76c04273SRajkumar Sivaprakasam 			event.ev_port_flags = 0;
432*76c04273SRajkumar Sivaprakasam 			type = 0;
433*76c04273SRajkumar Sivaprakasam 			event.ev_port = (uint8_t)port;
434*76c04273SRajkumar Sivaprakasam 
435*76c04273SRajkumar Sivaprakasam 			switch (attr_id) {
436*76c04273SRajkumar Sivaprakasam 			case SM_PORTINFO_ATTRID:
437*76c04273SRajkumar Sivaprakasam 				/*
438*76c04273SRajkumar Sivaprakasam 				 * This is a SM SET method with portinfo
439*76c04273SRajkumar Sivaprakasam 				 * attribute. If ClientRereg bit was set in
440*76c04273SRajkumar Sivaprakasam 				 * the MADs portinfo this is a REREG event
441*76c04273SRajkumar Sivaprakasam 				 * (see section 14.4.11 in IB Spec 1.2.1). Else
442*76c04273SRajkumar Sivaprakasam 				 * compare the current (before MAD_IFC command)
443*76c04273SRajkumar Sivaprakasam 				 * portinfo with the portinfo in the MAD and
444*76c04273SRajkumar Sivaprakasam 				 * signal PORT_CHANGE event with the proper
445*76c04273SRajkumar Sivaprakasam 				 * ev_port_flags.
446*76c04273SRajkumar Sivaprakasam 				 *
447*76c04273SRajkumar Sivaprakasam 				 */
448*76c04273SRajkumar Sivaprakasam 				isReregSuppd = curpinfo.CapabilityMask &
449*76c04273SRajkumar Sivaprakasam 				    SM_CAP_MASK_IS_CLNT_REREG_SUPPD;
450*76c04273SRajkumar Sivaprakasam 
451*76c04273SRajkumar Sivaprakasam 				madpinfop = recv_msgbufp->im_bufs_cl_data;
452*76c04273SRajkumar Sivaprakasam 				if (tmadpinfo.ClientRereg && isReregSuppd) {
453*76c04273SRajkumar Sivaprakasam 					type |= IBT_CLNT_REREG_EVENT;
454*76c04273SRajkumar Sivaprakasam 				}
455*76c04273SRajkumar Sivaprakasam 
456*76c04273SRajkumar Sivaprakasam 				type |= IBT_PORT_CHANGE_EVENT;
457*76c04273SRajkumar Sivaprakasam 				event.ev_port_flags = hermon_port_change_flags(
458*76c04273SRajkumar Sivaprakasam 				    &curpinfo, &tmadpinfo);
459*76c04273SRajkumar Sivaprakasam 				if (event.ev_port_flags &
460*76c04273SRajkumar Sivaprakasam 				    (IBT_PORT_CHANGE_REREG |
461*76c04273SRajkumar Sivaprakasam 				    IBT_PORT_CHANGE_SM_FLAG)) {
462*76c04273SRajkumar Sivaprakasam 					if (hermon_set_port_capability(state,
463*76c04273SRajkumar Sivaprakasam 					    port, &curpinfo,
464*76c04273SRajkumar Sivaprakasam 					    event.ev_port_flags)
465*76c04273SRajkumar Sivaprakasam 					    != DDI_SUCCESS) {
466*76c04273SRajkumar Sivaprakasam 						cmn_err(CE_CONT, "HERMON: Port "
467*76c04273SRajkumar Sivaprakasam 						    "%d capability reset "
468*76c04273SRajkumar Sivaprakasam 						    "failed\n", port);
469*76c04273SRajkumar Sivaprakasam 					}
470*76c04273SRajkumar Sivaprakasam 				}
471*76c04273SRajkumar Sivaprakasam 
472*76c04273SRajkumar Sivaprakasam 				/*
473*76c04273SRajkumar Sivaprakasam 				 * If we have a SMLID change event but
474*76c04273SRajkumar Sivaprakasam 				 * capability mask doesn't have Rereg support
475*76c04273SRajkumar Sivaprakasam 				 * bit set, we have to do the Rereg part too.
476*76c04273SRajkumar Sivaprakasam 				 */
477*76c04273SRajkumar Sivaprakasam 				if ((event.ev_port_flags &
478*76c04273SRajkumar Sivaprakasam 				    IBT_PORT_CHANGE_SM_LID) && !isReregSuppd)
479*76c04273SRajkumar Sivaprakasam 					type |= IBT_CLNT_REREG_EVENT;
480*76c04273SRajkumar Sivaprakasam 				break;
481*76c04273SRajkumar Sivaprakasam 			case SM_PKEY_TABLE_ATTRID:
482*76c04273SRajkumar Sivaprakasam 				type |= IBT_PORT_CHANGE_EVENT;
483*76c04273SRajkumar Sivaprakasam 				event.ev_port_flags = IBT_PORT_CHANGE_PKEY;
484*76c04273SRajkumar Sivaprakasam 				break;
485*76c04273SRajkumar Sivaprakasam 			case SM_GUIDINFO_ATTRID:
486*76c04273SRajkumar Sivaprakasam 				type |= IBT_PORT_CHANGE_EVENT;
487*76c04273SRajkumar Sivaprakasam 				event.ev_port_flags = IBT_PORT_CHANGE_SGID;
488*76c04273SRajkumar Sivaprakasam 				break;
489*76c04273SRajkumar Sivaprakasam 			default:
490*76c04273SRajkumar Sivaprakasam 				break;
491*76c04273SRajkumar Sivaprakasam 
492*76c04273SRajkumar Sivaprakasam 			}
493*76c04273SRajkumar Sivaprakasam 
494*76c04273SRajkumar Sivaprakasam 			/*
495*76c04273SRajkumar Sivaprakasam 			 * NOTE: here we call ibc_async_handler directly without
496*76c04273SRajkumar Sivaprakasam 			 * using the HERMON_DO_IBTF_ASYNC_CALLB, since hermon
497*76c04273SRajkumar Sivaprakasam 			 * can not be unloaded till ibmf_unregiter is done and
498*76c04273SRajkumar Sivaprakasam 			 * this thread (hs_taskq_agents) will be destroyed
499*76c04273SRajkumar Sivaprakasam 			 * before ibmf_uregister is called.
500*76c04273SRajkumar Sivaprakasam 			 *
501*76c04273SRajkumar Sivaprakasam 			 * The hermon event queue based hs_in_evcallb flag
502*76c04273SRajkumar Sivaprakasam 			 * assumes that we will pick one event after another
503*76c04273SRajkumar Sivaprakasam 			 * and dispatch them sequentially. If we use
504*76c04273SRajkumar Sivaprakasam 			 * HERMON_DO_IBTF_ASYNC_CALLB, we will break this
505*76c04273SRajkumar Sivaprakasam 			 * assumption make hs_in_evcallb inconsistent.
506*76c04273SRajkumar Sivaprakasam 			 */
507*76c04273SRajkumar Sivaprakasam 			while (type != 0) {
508*76c04273SRajkumar Sivaprakasam 				if (type & IBT_PORT_CHANGE_EVENT) {
509*76c04273SRajkumar Sivaprakasam 					code = IBT_PORT_CHANGE_EVENT;
510*76c04273SRajkumar Sivaprakasam 					type &= ~IBT_PORT_CHANGE_EVENT;
511*76c04273SRajkumar Sivaprakasam 				} else {
512*76c04273SRajkumar Sivaprakasam 					code = IBT_CLNT_REREG_EVENT;
513*76c04273SRajkumar Sivaprakasam 					type = 0;
514*76c04273SRajkumar Sivaprakasam 				}
515*76c04273SRajkumar Sivaprakasam 				ibc_async_handler(state->hs_ibtfpriv, code,
516*76c04273SRajkumar Sivaprakasam 				    &event);
517*76c04273SRajkumar Sivaprakasam 			}
518*76c04273SRajkumar Sivaprakasam 		}
5199e39c5baSBill Taylor 	}
5209e39c5baSBill Taylor 
5219e39c5baSBill Taylor 	/*
5229e39c5baSBill Taylor 	 * If incoming MAD was "TrapRepress", then no response is necessary.
5239e39c5baSBill Taylor 	 * Free the IBMF message and return.
5249e39c5baSBill Taylor 	 */
5259e39c5baSBill Taylor 	if (HERMON_IS_TRAP_REPRESS_MAD(msgp)) {
5269e39c5baSBill Taylor 		goto hermon_agent_handle_req_skip_response;
5279e39c5baSBill Taylor 	}
5289e39c5baSBill Taylor 
5299e39c5baSBill Taylor 	/*
5309e39c5baSBill Taylor 	 * Modify the response MAD as necessary (for any special cases).
5319e39c5baSBill Taylor 	 * Specifically, if this MAD was a directed route MAD, then some
5329e39c5baSBill Taylor 	 * additional packet manipulation may be necessary because the Hermon
5339e39c5baSBill Taylor 	 * firmware does not do all the required steps to respond to the
5349e39c5baSBill Taylor 	 * MAD.
5359e39c5baSBill Taylor 	 */
5369e39c5baSBill Taylor 	hermon_agent_mad_resp_handling(state, msgp, port);
5379e39c5baSBill Taylor 
5389e39c5baSBill Taylor 	/*
5399e39c5baSBill Taylor 	 * Send response (or forwarded "Trap" MAD) back to IBMF.  We use the
5409e39c5baSBill Taylor 	 * "response callback" to indicate when it is appropriate (later) to
5419e39c5baSBill Taylor 	 * free the IBMF msg.
5429e39c5baSBill Taylor 	 */
5439e39c5baSBill Taylor 	status = ibmf_msg_transport(ibmf_handle, IBMF_QP_HANDLE_DEFAULT,
5449e39c5baSBill Taylor 	    msgp, &retrans, hermon_agent_response_cb, state, 0);
5459e39c5baSBill Taylor 	if (status != IBMF_SUCCESS) {
5469e39c5baSBill Taylor 		goto hermon_agent_handle_req_skip_response;
5479e39c5baSBill Taylor 	}
5489e39c5baSBill Taylor 
5499e39c5baSBill Taylor 	/* Free up the callback args parameter */
5509e39c5baSBill Taylor 	kmem_free(agent_args, sizeof (hermon_agent_handler_arg_t));
5519e39c5baSBill Taylor 	return;
5529e39c5baSBill Taylor 
5539e39c5baSBill Taylor hermon_agent_handle_req_skip_response:
5549e39c5baSBill Taylor 	/* Free up the ibmf message */
5559e39c5baSBill Taylor 	(void) ibmf_free_msg(ibmf_handle, &msgp);
5569e39c5baSBill Taylor 
5579e39c5baSBill Taylor 	/* Free up the callback args parameter */
5589e39c5baSBill Taylor 	kmem_free(agent_args, sizeof (hermon_agent_handler_arg_t));
5599e39c5baSBill Taylor }
5609e39c5baSBill Taylor 
5619e39c5baSBill Taylor 
5629e39c5baSBill Taylor /*
5639e39c5baSBill Taylor  * hermon_agent_response_cb()
5649e39c5baSBill Taylor  *    Context: Called from the IBMF context
5659e39c5baSBill Taylor  */
5669e39c5baSBill Taylor /* ARGSUSED */
5679e39c5baSBill Taylor static void
hermon_agent_response_cb(ibmf_handle_t ibmf_handle,ibmf_msg_t * msgp,void * args)5689e39c5baSBill Taylor hermon_agent_response_cb(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp,
5699e39c5baSBill Taylor     void *args)
5709e39c5baSBill Taylor {
5719e39c5baSBill Taylor 	/*
5729e39c5baSBill Taylor 	 * It is the responsibility of each IBMF callback recipient to free
5739e39c5baSBill Taylor 	 * the packets that it has been given.  Now that we are in the
5749e39c5baSBill Taylor 	 * response callback, we can be assured that it is safe to do so.
5759e39c5baSBill Taylor 	 */
5769e39c5baSBill Taylor 	(void) ibmf_free_msg(ibmf_handle, &msgp);
5779e39c5baSBill Taylor }
5789e39c5baSBill Taylor 
5799e39c5baSBill Taylor 
5809e39c5baSBill Taylor /*
5819e39c5baSBill Taylor  * hermon_agent_list_init()
5829e39c5baSBill Taylor  *    Context: Only called from attach() path context
5839e39c5baSBill Taylor  */
5849e39c5baSBill Taylor static int
hermon_agent_list_init(hermon_state_t * state)5859e39c5baSBill Taylor hermon_agent_list_init(hermon_state_t *state)
5869e39c5baSBill Taylor {
5879e39c5baSBill Taylor 	hermon_agent_list_t	*curr;
5889e39c5baSBill Taylor 	uint_t			num_ports, num_agents, num_agents_per_port;
5899e39c5baSBill Taylor 	uint_t			num_sma_agents = 0;
5909e39c5baSBill Taylor 	uint_t			num_pma_agents = 0;
5919e39c5baSBill Taylor 	uint_t			num_bma_agents = 0;
5929e39c5baSBill Taylor 	uint_t			do_qp0, do_qp1;
5939e39c5baSBill Taylor 	int			i, j, indx;
5949e39c5baSBill Taylor 
5959e39c5baSBill Taylor 	/*
5969e39c5baSBill Taylor 	 * Calculate the number of registered agents for each port
5979e39c5baSBill Taylor 	 * (SMA, PMA, and BMA) and determine whether or not to register
5989e39c5baSBill Taylor 	 * a given agent with the IBMF (or whether to let the Hermon firmware
5999e39c5baSBill Taylor 	 * handle it)
6009e39c5baSBill Taylor 	 */
6019e39c5baSBill Taylor 	num_ports	    = state->hs_cfg_profile->cp_num_ports;
6029e39c5baSBill Taylor 	num_agents	    = 0;
6039e39c5baSBill Taylor 	num_agents_per_port = 0;
6049e39c5baSBill Taylor 	do_qp0		    = state->hs_cfg_profile->cp_qp0_agents_in_fw;
6059e39c5baSBill Taylor 	do_qp1		    = state->hs_cfg_profile->cp_qp1_agents_in_fw;
6069e39c5baSBill Taylor 	if (do_qp0 == 0) {
6079e39c5baSBill Taylor 		num_agents += (num_ports * HERMON_NUM_QP0_AGENTS_PER_PORT);
6089e39c5baSBill Taylor 		num_agents_per_port += HERMON_NUM_QP0_AGENTS_PER_PORT;
6099e39c5baSBill Taylor 		num_sma_agents = num_ports;
6109e39c5baSBill Taylor 	}
6119e39c5baSBill Taylor 	if (do_qp1 == 0) {
6129e39c5baSBill Taylor 		num_agents += (num_ports * HERMON_NUM_QP1_AGENTS_PER_PORT);
6139e39c5baSBill Taylor 		num_agents_per_port += HERMON_NUM_QP1_AGENTS_PER_PORT;
6149e39c5baSBill Taylor 		num_pma_agents = num_ports;
6159e39c5baSBill Taylor 		/*
6169e39c5baSBill Taylor 		 * The following line is commented out because the Hermon
6179e39c5baSBill Taylor 		 * firmware does not currently support a BMA.  If it did,
6189e39c5baSBill Taylor 		 * then we would want to register the agent with the IBMF.
6199e39c5baSBill Taylor 		 * (We would also need to have HERMON_NUM_QP1_AGENTS_PER_PORT
6209e39c5baSBill Taylor 		 * set to 2, instead of 1.)
6219e39c5baSBill Taylor 		 *
6229e39c5baSBill Taylor 		 * num_bma_agents = num_ports;
6239e39c5baSBill Taylor 		 */
6249e39c5baSBill Taylor 	}
6259e39c5baSBill Taylor 
6269e39c5baSBill Taylor 	state->hs_num_agents = num_agents;
6279e39c5baSBill Taylor 
6289e39c5baSBill Taylor 	/*
6299e39c5baSBill Taylor 	 * Allocate the memory for all of the agent list entries
6309e39c5baSBill Taylor 	 */
6319e39c5baSBill Taylor 	state->hs_agents = (hermon_agent_list_t *)kmem_zalloc(num_agents *
6329e39c5baSBill Taylor 	    sizeof (hermon_agent_list_t), KM_SLEEP);
6339e39c5baSBill Taylor 	if (state->hs_agents == NULL) {
6349e39c5baSBill Taylor 		return (DDI_FAILURE);
6359e39c5baSBill Taylor 	}
6369e39c5baSBill Taylor 
6379e39c5baSBill Taylor 	/*
6389e39c5baSBill Taylor 	 * Fill in each of the agent list entries with the agent's
6399e39c5baSBill Taylor 	 * MgmtClass, port number, and Hermon softstate pointer
6409e39c5baSBill Taylor 	 */
6419e39c5baSBill Taylor 	indx = 0;
6429e39c5baSBill Taylor 	for (i = 0; i < num_agents_per_port; i++) {
6439e39c5baSBill Taylor 		for (j = 0; j < num_ports; j++) {
6449e39c5baSBill Taylor 			curr = &state->hs_agents[indx];
6459e39c5baSBill Taylor 			curr->agl_state = state;
6469e39c5baSBill Taylor 			curr->agl_port  = j + 1;
6479e39c5baSBill Taylor 
6489e39c5baSBill Taylor 			if ((do_qp0 == 0) && num_sma_agents) {
6499e39c5baSBill Taylor 				curr->agl_mgmtclass = SUBN_AGENT;
6509e39c5baSBill Taylor 				num_sma_agents--;
6519e39c5baSBill Taylor 				indx++;
6529e39c5baSBill Taylor 			} else if ((do_qp1 == 0) && (num_pma_agents)) {
6539e39c5baSBill Taylor 				curr->agl_mgmtclass = PERF_AGENT;
6549e39c5baSBill Taylor 				num_pma_agents--;
6559e39c5baSBill Taylor 				indx++;
6569e39c5baSBill Taylor 			} else if ((do_qp1 == 0) && (num_bma_agents)) {
6579e39c5baSBill Taylor 				curr->agl_mgmtclass = BM_AGENT;
6589e39c5baSBill Taylor 				num_bma_agents--;
6599e39c5baSBill Taylor 				indx++;
6609e39c5baSBill Taylor 			}
6619e39c5baSBill Taylor 		}
6629e39c5baSBill Taylor 	}
6639e39c5baSBill Taylor 
6649e39c5baSBill Taylor 	return (DDI_SUCCESS);
6659e39c5baSBill Taylor }
6669e39c5baSBill Taylor 
6679e39c5baSBill Taylor 
6689e39c5baSBill Taylor /*
6699e39c5baSBill Taylor  * hermon_agent_list_fini()
6709e39c5baSBill Taylor  *    Context: Only called from attach() and/or detach() path contexts
6719e39c5baSBill Taylor  */
6729e39c5baSBill Taylor static void
hermon_agent_list_fini(hermon_state_t * state)6739e39c5baSBill Taylor hermon_agent_list_fini(hermon_state_t *state)
6749e39c5baSBill Taylor {
6759e39c5baSBill Taylor 	/* Free up the memory for the agent list entries */
6769e39c5baSBill Taylor 	kmem_free(state->hs_agents,
6779e39c5baSBill Taylor 	    state->hs_num_agents * sizeof (hermon_agent_list_t));
6789e39c5baSBill Taylor }
6799e39c5baSBill Taylor 
6809e39c5baSBill Taylor 
6819e39c5baSBill Taylor /*
6829e39c5baSBill Taylor  * hermon_agent_register_all()
6839e39c5baSBill Taylor  *    Context: Only called from attach() path context
6849e39c5baSBill Taylor  */
6859e39c5baSBill Taylor static int
hermon_agent_register_all(hermon_state_t * state)6869e39c5baSBill Taylor hermon_agent_register_all(hermon_state_t *state)
6879e39c5baSBill Taylor {
6889e39c5baSBill Taylor 	hermon_agent_list_t	*curr;
6899e39c5baSBill Taylor 	ibmf_register_info_t	ibmf_reg;
6909e39c5baSBill Taylor 	ibmf_impl_caps_t	impl_caps;
6919e39c5baSBill Taylor 	ib_guid_t		nodeguid;
6929e39c5baSBill Taylor 	int			i, status, num_registered;
6939e39c5baSBill Taylor 
6949e39c5baSBill Taylor 	/* Get the Hermon NodeGUID from the softstate */
6959e39c5baSBill Taylor 	nodeguid = state->hs_ibtfinfo.hca_attr->hca_node_guid;
6969e39c5baSBill Taylor 
6979e39c5baSBill Taylor 	/*
6989e39c5baSBill Taylor 	 * Register each of the agents with the IBMF (and add callbacks for
6999e39c5baSBill Taylor 	 * each to the hermon_agent_request_cb() routine).  Note:  If we
7009e39c5baSBill Taylor 	 * fail somewhere along the line here, we attempt to cleanup as much
7019e39c5baSBill Taylor 	 * of the mess as we can and then jump to hermon_agent_unregister_all()
7029e39c5baSBill Taylor 	 * to cleanup the rest.
7039e39c5baSBill Taylor 	 */
7049e39c5baSBill Taylor 	num_registered = 0;
7059e39c5baSBill Taylor 
7069e39c5baSBill Taylor 	if (state->hs_num_agents == 0) {
7079e39c5baSBill Taylor 		return (DDI_SUCCESS);
7089e39c5baSBill Taylor 	}
7099e39c5baSBill Taylor 
7109e39c5baSBill Taylor 	for (i = 0; i < state->hs_num_agents; i++) {
7119e39c5baSBill Taylor 		/* Register each agent with the IBMF */
7129e39c5baSBill Taylor 		curr = &state->hs_agents[i];
7139e39c5baSBill Taylor 		ibmf_reg.ir_ci_guid	 = nodeguid;
7149e39c5baSBill Taylor 		ibmf_reg.ir_port_num	 = curr->agl_port;
7159e39c5baSBill Taylor 		ibmf_reg.ir_client_class = curr->agl_mgmtclass;
7169e39c5baSBill Taylor 
7179e39c5baSBill Taylor 		status = ibmf_register(&ibmf_reg, IBMF_VERSION, 0,
7189e39c5baSBill Taylor 		    NULL, NULL, &curr->agl_ibmfhdl, &impl_caps);
7199e39c5baSBill Taylor 		if (status != IBMF_SUCCESS) {
7209e39c5baSBill Taylor 			goto agents_reg_fail;
7219e39c5baSBill Taylor 		}
7229e39c5baSBill Taylor 
7239e39c5baSBill Taylor 		/* Setup callbacks with the IBMF */
7249e39c5baSBill Taylor 		status  = ibmf_setup_async_cb(curr->agl_ibmfhdl,
7259e39c5baSBill Taylor 		    IBMF_QP_HANDLE_DEFAULT, hermon_agent_request_cb, curr, 0);
7269e39c5baSBill Taylor 		if (status != IBMF_SUCCESS) {
7279e39c5baSBill Taylor 			(void) ibmf_unregister(&curr->agl_ibmfhdl, 0);
7289e39c5baSBill Taylor 			goto agents_reg_fail;
7299e39c5baSBill Taylor 		}
7309e39c5baSBill Taylor 		num_registered++;
7319e39c5baSBill Taylor 	}
7329e39c5baSBill Taylor 
7339e39c5baSBill Taylor 	return (DDI_SUCCESS);
7349e39c5baSBill Taylor 
7359e39c5baSBill Taylor agents_reg_fail:
7369e39c5baSBill Taylor 	(void) hermon_agent_unregister_all(state, num_registered);
7379e39c5baSBill Taylor 	return (DDI_FAILURE);
7389e39c5baSBill Taylor }
7399e39c5baSBill Taylor 
7409e39c5baSBill Taylor 
7419e39c5baSBill Taylor /*
7429e39c5baSBill Taylor  * hermon_agent_unregister_all()
7439e39c5baSBill Taylor  *    Context: Only called from detach() path context
7449e39c5baSBill Taylor  */
7459e39c5baSBill Taylor static int
hermon_agent_unregister_all(hermon_state_t * state,int num_reg)7469e39c5baSBill Taylor hermon_agent_unregister_all(hermon_state_t *state, int num_reg)
7479e39c5baSBill Taylor {
7489e39c5baSBill Taylor 	hermon_agent_list_t	*curr;
7499e39c5baSBill Taylor 	int			i, status;
7509e39c5baSBill Taylor 
7519e39c5baSBill Taylor 	if (num_reg == 0) {
7529e39c5baSBill Taylor 		return (DDI_SUCCESS);
7539e39c5baSBill Taylor 	}
7549e39c5baSBill Taylor 
7559e39c5baSBill Taylor 	/*
7569e39c5baSBill Taylor 	 * For each registered agent in the agent list, teardown the
7579e39c5baSBill Taylor 	 * callbacks from the IBMF and unregister.
7589e39c5baSBill Taylor 	 */
7599e39c5baSBill Taylor 	for (i = 0; i < num_reg; i++) {
7609e39c5baSBill Taylor 		curr = &state->hs_agents[i];
7619e39c5baSBill Taylor 
7629e39c5baSBill Taylor 		/* Teardown the IBMF callback */
7639e39c5baSBill Taylor 		status = ibmf_tear_down_async_cb(curr->agl_ibmfhdl,
7649e39c5baSBill Taylor 		    IBMF_QP_HANDLE_DEFAULT, 0);
7659e39c5baSBill Taylor 		if (status != IBMF_SUCCESS) {
7669e39c5baSBill Taylor 			return (DDI_FAILURE);
7679e39c5baSBill Taylor 		}
7689e39c5baSBill Taylor 
7699e39c5baSBill Taylor 		/* Unregister the agent from the IBMF */
7709e39c5baSBill Taylor 		status = ibmf_unregister(&curr->agl_ibmfhdl, 0);
7719e39c5baSBill Taylor 		if (status != IBMF_SUCCESS) {
7729e39c5baSBill Taylor 			return (DDI_FAILURE);
7739e39c5baSBill Taylor 		}
7749e39c5baSBill Taylor 	}
7759e39c5baSBill Taylor 
7769e39c5baSBill Taylor 	return (DDI_SUCCESS);
7779e39c5baSBill Taylor }
7789e39c5baSBill Taylor 
7799e39c5baSBill Taylor 
7809e39c5baSBill Taylor /*
7819e39c5baSBill Taylor  * hermon_agent_mad_resp_handling()
7829e39c5baSBill Taylor  *    Context: Called with priority of taskQ thread
7839e39c5baSBill Taylor  */
7849e39c5baSBill Taylor /* ARGSUSED */
7859e39c5baSBill Taylor static void
hermon_agent_mad_resp_handling(hermon_state_t * state,ibmf_msg_t * msgp,uint_t port)7869e39c5baSBill Taylor hermon_agent_mad_resp_handling(hermon_state_t *state, ibmf_msg_t *msgp,
7879e39c5baSBill Taylor     uint_t port)
7889e39c5baSBill Taylor {
7899e39c5baSBill Taylor 	ib_mad_hdr_t	*rmadhdrp = msgp->im_msgbufs_recv.im_bufs_mad_hdr;
7909e39c5baSBill Taylor 	ib_mad_hdr_t	*smadhdrp = msgp->im_msgbufs_send.im_bufs_mad_hdr;
7919e39c5baSBill Taylor 	uint_t		hop_count, hop_point;
7929e39c5baSBill Taylor 	uchar_t		*resp, *ret_path;
7939e39c5baSBill Taylor 
7949e39c5baSBill Taylor 	resp = (uchar_t *)msgp->im_msgbufs_send.im_bufs_cl_data;
7959e39c5baSBill Taylor 
7969e39c5baSBill Taylor 	/*
7979e39c5baSBill Taylor 	 * Handle directed route MADs as a special case.  Hermon firmware
7989e39c5baSBill Taylor 	 * does not update the "direction" bit, "hop pointer", "Return
7999e39c5baSBill Taylor 	 * Path" or, in fact, any of the "directed route" parameters.  So
8009e39c5baSBill Taylor 	 * the responsibility falls on Hermon driver software to inspect the
8019e39c5baSBill Taylor 	 * MADs and update those fields as appropriate (see section 14.2.2
8029e39c5baSBill Taylor 	 * of the IBA specification, rev 1.1)
8039e39c5baSBill Taylor 	 */
8049e39c5baSBill Taylor 	if (HERMON_MAD_IS_DR(rmadhdrp)) {
8059e39c5baSBill Taylor 
8069e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*((sm_dr_mad_hdr_t *)rmadhdrp)))
8079e39c5baSBill Taylor 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*((sm_dr_mad_hdr_t *)smadhdrp)))
8089e39c5baSBill Taylor 
8099e39c5baSBill Taylor 		/*
8109e39c5baSBill Taylor 		 * Set the "Direction" bit to one.  This indicates that this
8119e39c5baSBill Taylor 		 * is now directed route response
8129e39c5baSBill Taylor 		 */
8139e39c5baSBill Taylor 		HERMON_DRMAD_SET_DIRECTION(rmadhdrp);
8149e39c5baSBill Taylor 
8159e39c5baSBill Taylor 		/* Extract the "hop pointer" and "hop count" from the MAD */
8169e39c5baSBill Taylor 		hop_count = HERMON_DRMAD_GET_HOPCOUNT(rmadhdrp);
8179e39c5baSBill Taylor 		hop_point = HERMON_DRMAD_GET_HOPPOINTER(rmadhdrp);
8189e39c5baSBill Taylor 
8199e39c5baSBill Taylor 		/* Append the port we came in on to the "Return Path" */
8209e39c5baSBill Taylor 		if ((hop_count != 0) && ((hop_point == hop_count) ||
8219e39c5baSBill Taylor 		    (hop_point == hop_count + 1))) {
8229e39c5baSBill Taylor 			ret_path = &resp[HERMON_DRMAD_RETURN_PATH_OFFSET];
8239e39c5baSBill Taylor 			ret_path[hop_point] = (uchar_t)port;
8249e39c5baSBill Taylor 		}
8259e39c5baSBill Taylor 
8269e39c5baSBill Taylor 		/* Then increment the "hop pointer" in the MAD */
8279e39c5baSBill Taylor 		hop_point++;
8289e39c5baSBill Taylor 		HERMON_DRMAD_SET_HOPPOINTER(smadhdrp, (uint8_t)hop_point);
8299e39c5baSBill Taylor 	}
8309e39c5baSBill Taylor }
831