xref: /onnv-gate/usr/src/uts/common/io/ib/adapters/hermon/hermon_agents.c (revision 9891:f5fce101fa1c)
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 /*
239517SBill.Taylor@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
249517SBill.Taylor@Sun.COM  * Use is subject to license terms.
259517SBill.Taylor@Sun.COM  */
269517SBill.Taylor@Sun.COM 
279517SBill.Taylor@Sun.COM /*
289517SBill.Taylor@Sun.COM  * hermon_agents.c
299517SBill.Taylor@Sun.COM  *    Hermon InfiniBand Management Agent (SMA, PMA, BMA) routines
309517SBill.Taylor@Sun.COM  *
319517SBill.Taylor@Sun.COM  *    Implements all the routines necessary for initializing, handling,
329517SBill.Taylor@Sun.COM  *    and (later) tearing down all the infrastructure necessary for Hermon
339517SBill.Taylor@Sun.COM  *    MAD processing.
349517SBill.Taylor@Sun.COM  */
359517SBill.Taylor@Sun.COM 
369517SBill.Taylor@Sun.COM #include <sys/types.h>
379517SBill.Taylor@Sun.COM #include <sys/conf.h>
389517SBill.Taylor@Sun.COM #include <sys/ddi.h>
399517SBill.Taylor@Sun.COM #include <sys/sunddi.h>
409517SBill.Taylor@Sun.COM #include <sys/modctl.h>
419517SBill.Taylor@Sun.COM 
429517SBill.Taylor@Sun.COM #include <sys/ib/adapters/hermon/hermon.h>
439517SBill.Taylor@Sun.COM #include <sys/ib/mgt/ibmf/ibmf.h>
449517SBill.Taylor@Sun.COM #include <sys/disp.h>
459517SBill.Taylor@Sun.COM 
469517SBill.Taylor@Sun.COM static void hermon_agent_request_cb(ibmf_handle_t ibmf_handle,
479517SBill.Taylor@Sun.COM     ibmf_msg_t *msgp, void *args);
489517SBill.Taylor@Sun.COM static void hermon_agent_handle_req(void *cb_args);
499517SBill.Taylor@Sun.COM static void hermon_agent_response_cb(ibmf_handle_t ibmf_handle,
509517SBill.Taylor@Sun.COM     ibmf_msg_t *msgp, void *args);
519517SBill.Taylor@Sun.COM static int hermon_agent_list_init(hermon_state_t *state);
529517SBill.Taylor@Sun.COM static void hermon_agent_list_fini(hermon_state_t *state);
539517SBill.Taylor@Sun.COM static int hermon_agent_register_all(hermon_state_t *state);
549517SBill.Taylor@Sun.COM static int hermon_agent_unregister_all(hermon_state_t *state, int num_reg);
559517SBill.Taylor@Sun.COM static void hermon_agent_mad_resp_handling(hermon_state_t *state,
569517SBill.Taylor@Sun.COM     ibmf_msg_t *msgp, uint_t port);
579517SBill.Taylor@Sun.COM 
589517SBill.Taylor@Sun.COM /*
599517SBill.Taylor@Sun.COM  * hermon_agent_handlers_init()
609517SBill.Taylor@Sun.COM  *    Context: Only called from attach() and/or detach() path contexts
619517SBill.Taylor@Sun.COM  */
629517SBill.Taylor@Sun.COM int
hermon_agent_handlers_init(hermon_state_t * state)639517SBill.Taylor@Sun.COM hermon_agent_handlers_init(hermon_state_t *state)
649517SBill.Taylor@Sun.COM {
659517SBill.Taylor@Sun.COM 	int		status;
669517SBill.Taylor@Sun.COM 	char		*rsrc_name;
679517SBill.Taylor@Sun.COM 
689517SBill.Taylor@Sun.COM 	/* Determine if we need to register any agents with the IBMF */
699517SBill.Taylor@Sun.COM 	if ((state->hs_cfg_profile->cp_qp0_agents_in_fw) &&
709517SBill.Taylor@Sun.COM 	    (state->hs_cfg_profile->cp_qp1_agents_in_fw)) {
719517SBill.Taylor@Sun.COM 		return (DDI_SUCCESS);
729517SBill.Taylor@Sun.COM 	}
739517SBill.Taylor@Sun.COM 
749517SBill.Taylor@Sun.COM 	/*
759517SBill.Taylor@Sun.COM 	 * Build a unique name for the Hermon task queue from the Hermon driver
769517SBill.Taylor@Sun.COM 	 * instance number and HERMON_TASKQ_NAME
779517SBill.Taylor@Sun.COM 	 */
789517SBill.Taylor@Sun.COM 	rsrc_name = (char *)kmem_zalloc(HERMON_RSRC_NAME_MAXLEN, KM_SLEEP);
799517SBill.Taylor@Sun.COM 	HERMON_RSRC_NAME(rsrc_name, HERMON_TASKQ_NAME);
809517SBill.Taylor@Sun.COM 
819517SBill.Taylor@Sun.COM 	/* Initialize the Hermon IB management agent list */
829517SBill.Taylor@Sun.COM 	status = hermon_agent_list_init(state);
839517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
849517SBill.Taylor@Sun.COM 		goto agentsinit_fail;
859517SBill.Taylor@Sun.COM 	}
869517SBill.Taylor@Sun.COM 
879517SBill.Taylor@Sun.COM 	/*
889517SBill.Taylor@Sun.COM 	 * Initialize the agent handling task queue.  Note: We set the task
899517SBill.Taylor@Sun.COM 	 * queue priority to the minimum system priority.  At this point this
909517SBill.Taylor@Sun.COM 	 * is considered acceptable because MADs are unreliable datagrams
919517SBill.Taylor@Sun.COM 	 * and could get lost (in general) anyway.
929517SBill.Taylor@Sun.COM 	 */
939517SBill.Taylor@Sun.COM 	state->hs_taskq_agents = ddi_taskq_create(state->hs_dip,
949517SBill.Taylor@Sun.COM 	    rsrc_name, HERMON_TASKQ_NTHREADS, TASKQ_DEFAULTPRI, 0);
959517SBill.Taylor@Sun.COM 	if (state->hs_taskq_agents == NULL) {
969517SBill.Taylor@Sun.COM 		hermon_agent_list_fini(state);
979517SBill.Taylor@Sun.COM 		goto agentsinit_fail;
989517SBill.Taylor@Sun.COM 	}
999517SBill.Taylor@Sun.COM 
1009517SBill.Taylor@Sun.COM 	/* Now attempt to register all of the agents with the IBMF */
1019517SBill.Taylor@Sun.COM 	status = hermon_agent_register_all(state);
1029517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
1039517SBill.Taylor@Sun.COM 		ddi_taskq_destroy(state->hs_taskq_agents);
1049517SBill.Taylor@Sun.COM 		hermon_agent_list_fini(state);
1059517SBill.Taylor@Sun.COM 		goto agentsinit_fail;
1069517SBill.Taylor@Sun.COM 	}
1079517SBill.Taylor@Sun.COM 
1089517SBill.Taylor@Sun.COM 	kmem_free(rsrc_name, HERMON_RSRC_NAME_MAXLEN);
1099517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
1109517SBill.Taylor@Sun.COM 
1119517SBill.Taylor@Sun.COM agentsinit_fail:
1129517SBill.Taylor@Sun.COM 	kmem_free(rsrc_name, HERMON_RSRC_NAME_MAXLEN);
1139517SBill.Taylor@Sun.COM 	return (status);
1149517SBill.Taylor@Sun.COM }
1159517SBill.Taylor@Sun.COM 
1169517SBill.Taylor@Sun.COM 
1179517SBill.Taylor@Sun.COM /*
1189517SBill.Taylor@Sun.COM  * hermon_agent_handlers_fini()
1199517SBill.Taylor@Sun.COM  *    Context: Only called from detach() path context
1209517SBill.Taylor@Sun.COM  */
1219517SBill.Taylor@Sun.COM int
hermon_agent_handlers_fini(hermon_state_t * state)1229517SBill.Taylor@Sun.COM hermon_agent_handlers_fini(hermon_state_t *state)
1239517SBill.Taylor@Sun.COM {
1249517SBill.Taylor@Sun.COM 	int		status;
1259517SBill.Taylor@Sun.COM 
1269517SBill.Taylor@Sun.COM 	/* Determine if we need to unregister any agents from the IBMF */
1279517SBill.Taylor@Sun.COM 	if ((state->hs_cfg_profile->cp_qp0_agents_in_fw) &&
1289517SBill.Taylor@Sun.COM 	    (state->hs_cfg_profile->cp_qp1_agents_in_fw)) {
1299517SBill.Taylor@Sun.COM 		return (DDI_SUCCESS);
1309517SBill.Taylor@Sun.COM 	}
1319517SBill.Taylor@Sun.COM 
1329517SBill.Taylor@Sun.COM 	/* Now attempt to unregister all of the agents from the IBMF */
1339517SBill.Taylor@Sun.COM 	status = hermon_agent_unregister_all(state, state->hs_num_agents);
1349517SBill.Taylor@Sun.COM 	if (status != DDI_SUCCESS) {
1359517SBill.Taylor@Sun.COM 		return (DDI_FAILURE);
1369517SBill.Taylor@Sun.COM 	}
1379517SBill.Taylor@Sun.COM 
1389517SBill.Taylor@Sun.COM 	/*
1399517SBill.Taylor@Sun.COM 	 * Destroy the task queue.  The task queue destroy is guaranteed to
1409517SBill.Taylor@Sun.COM 	 * wait until any scheduled tasks have completed.  We are able to
1419517SBill.Taylor@Sun.COM 	 * guarantee that no _new_ tasks will be added the task queue while
1429517SBill.Taylor@Sun.COM 	 * we are in the ddi_taskq_destroy() call because we have
1439517SBill.Taylor@Sun.COM 	 * (at this point) successfully unregistered from IBMF (in
1449517SBill.Taylor@Sun.COM 	 * hermon_agent_unregister_all() above).
1459517SBill.Taylor@Sun.COM 	 */
1469517SBill.Taylor@Sun.COM 	ddi_taskq_destroy(state->hs_taskq_agents);
1479517SBill.Taylor@Sun.COM 
1489517SBill.Taylor@Sun.COM 	/* Teardown the Hermon IB management agent list */
1499517SBill.Taylor@Sun.COM 	hermon_agent_list_fini(state);
1509517SBill.Taylor@Sun.COM 
1519517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
1529517SBill.Taylor@Sun.COM }
1539517SBill.Taylor@Sun.COM 
1549517SBill.Taylor@Sun.COM 
1559517SBill.Taylor@Sun.COM /*
1569517SBill.Taylor@Sun.COM  * hermon_agent_request_cb()
1579517SBill.Taylor@Sun.COM  *    Context: Called from the IBMF context
1589517SBill.Taylor@Sun.COM  */
1599517SBill.Taylor@Sun.COM static void
hermon_agent_request_cb(ibmf_handle_t ibmf_handle,ibmf_msg_t * msgp,void * args)1609517SBill.Taylor@Sun.COM hermon_agent_request_cb(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp,
1619517SBill.Taylor@Sun.COM     void *args)
1629517SBill.Taylor@Sun.COM {
1639517SBill.Taylor@Sun.COM 	hermon_agent_handler_arg_t	*cb_args;
1649517SBill.Taylor@Sun.COM 	hermon_agent_list_t		*curr;
1659517SBill.Taylor@Sun.COM 	hermon_state_t			*state;
1669517SBill.Taylor@Sun.COM 	int				status;
1679517SBill.Taylor@Sun.COM 
1689517SBill.Taylor@Sun.COM 	curr  = (hermon_agent_list_t *)args;
1699517SBill.Taylor@Sun.COM 	state = curr->agl_state;
1709517SBill.Taylor@Sun.COM 
1719517SBill.Taylor@Sun.COM 	/*
1729517SBill.Taylor@Sun.COM 	 * Allocate space to hold the callback args (for passing to the
1739517SBill.Taylor@Sun.COM 	 * task queue).  Note: If we are unable to allocate space for the
1749517SBill.Taylor@Sun.COM 	 * the callback args here, then we just return.  But we must ensure
1759517SBill.Taylor@Sun.COM 	 * that we call ibmf_free_msg() to free up the message.
1769517SBill.Taylor@Sun.COM 	 */
1779517SBill.Taylor@Sun.COM 	cb_args = (hermon_agent_handler_arg_t *)kmem_zalloc(
1789517SBill.Taylor@Sun.COM 	    sizeof (hermon_agent_handler_arg_t), KM_NOSLEEP);
1799517SBill.Taylor@Sun.COM 	if (cb_args == NULL) {
1809517SBill.Taylor@Sun.COM 		(void) ibmf_free_msg(ibmf_handle, &msgp);
1819517SBill.Taylor@Sun.COM 		return;
1829517SBill.Taylor@Sun.COM 	}
1839517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*cb_args))
1849517SBill.Taylor@Sun.COM 
1859517SBill.Taylor@Sun.COM 	/* Fill in the callback args */
1869517SBill.Taylor@Sun.COM 	cb_args->ahd_ibmfhdl	= ibmf_handle;
1879517SBill.Taylor@Sun.COM 	cb_args->ahd_ibmfmsg	= msgp;
1889517SBill.Taylor@Sun.COM 	cb_args->ahd_agentlist	= args;
1899517SBill.Taylor@Sun.COM 
1909517SBill.Taylor@Sun.COM 	/*
1919517SBill.Taylor@Sun.COM 	 * Dispatch the message to the task queue.  Note: Just like above,
1929517SBill.Taylor@Sun.COM 	 * if this request fails for any reason then make sure to free up
1939517SBill.Taylor@Sun.COM 	 * the IBMF message and then return
1949517SBill.Taylor@Sun.COM 	 */
1959517SBill.Taylor@Sun.COM 	status = ddi_taskq_dispatch(state->hs_taskq_agents,
1969517SBill.Taylor@Sun.COM 	    hermon_agent_handle_req, cb_args, DDI_NOSLEEP);
1979517SBill.Taylor@Sun.COM 	if (status == DDI_FAILURE) {
1989517SBill.Taylor@Sun.COM 		kmem_free(cb_args, sizeof (hermon_agent_handler_arg_t));
1999517SBill.Taylor@Sun.COM 		(void) ibmf_free_msg(ibmf_handle, &msgp);
2009517SBill.Taylor@Sun.COM 	}
2019517SBill.Taylor@Sun.COM }
2029517SBill.Taylor@Sun.COM 
2039517SBill.Taylor@Sun.COM /*
2049517SBill.Taylor@Sun.COM  * hermon_get_smlid()
2059517SBill.Taylor@Sun.COM  *	Simple helper function for hermon_agent_handle_req() below.
2069517SBill.Taylor@Sun.COM  *	Get the portinfo and extract the smlid.
2079517SBill.Taylor@Sun.COM  */
2089517SBill.Taylor@Sun.COM static ib_lid_t
hermon_get_smlid(hermon_state_t * state,uint_t port)2099517SBill.Taylor@Sun.COM hermon_get_smlid(hermon_state_t *state, uint_t port)
2109517SBill.Taylor@Sun.COM {
2119517SBill.Taylor@Sun.COM 	sm_portinfo_t			portinfo;
2129517SBill.Taylor@Sun.COM 	int				status;
2139517SBill.Taylor@Sun.COM 
2149517SBill.Taylor@Sun.COM 	status = hermon_getportinfo_cmd_post(state, port,
2159517SBill.Taylor@Sun.COM 	    HERMON_SLEEPFLAG_FOR_CONTEXT(), &portinfo);
2169517SBill.Taylor@Sun.COM 	if (status != HERMON_CMD_SUCCESS) {
2179517SBill.Taylor@Sun.COM 		cmn_err(CE_CONT, "Hermon: GetPortInfo (port %02d) command "
2189517SBill.Taylor@Sun.COM 		    "failed: %08x\n", port, status);
2199517SBill.Taylor@Sun.COM 		return (0);
2209517SBill.Taylor@Sun.COM 	}
2219517SBill.Taylor@Sun.COM 	return (portinfo.MasterSMLID);
2229517SBill.Taylor@Sun.COM }
2239517SBill.Taylor@Sun.COM 
2249517SBill.Taylor@Sun.COM /*
225*9891SRajkumar.Sivaprakasam@Sun.COM  * hermon_get_port_change_flags()
226*9891SRajkumar.Sivaprakasam@Sun.COM  * 	Helper function to determine the changes in the incoming MAD's portinfo
227*9891SRajkumar.Sivaprakasam@Sun.COM  * 	for the Port Change event.
228*9891SRajkumar.Sivaprakasam@Sun.COM  */
229*9891SRajkumar.Sivaprakasam@Sun.COM static ibt_port_change_t
hermon_port_change_flags(sm_portinfo_t * curpinfo,sm_portinfo_t * madpinfo)230*9891SRajkumar.Sivaprakasam@Sun.COM hermon_port_change_flags(sm_portinfo_t *curpinfo, sm_portinfo_t *madpinfo)
231*9891SRajkumar.Sivaprakasam@Sun.COM {
232*9891SRajkumar.Sivaprakasam@Sun.COM 	int SMDisabled, ReregSuppd;
233*9891SRajkumar.Sivaprakasam@Sun.COM 	ibt_port_change_t flags = 0;
234*9891SRajkumar.Sivaprakasam@Sun.COM 
235*9891SRajkumar.Sivaprakasam@Sun.COM 	SMDisabled = curpinfo->CapabilityMask & SM_CAP_MASK_IS_SM_DISABLED;
236*9891SRajkumar.Sivaprakasam@Sun.COM 	ReregSuppd = curpinfo->CapabilityMask & SM_CAP_MASK_IS_CLNT_REREG_SUPPD;
237*9891SRajkumar.Sivaprakasam@Sun.COM 
238*9891SRajkumar.Sivaprakasam@Sun.COM 	if (curpinfo->MasterSMLID != madpinfo->MasterSMLID) {
239*9891SRajkumar.Sivaprakasam@Sun.COM 		flags |= IBT_PORT_CHANGE_SM_LID;
240*9891SRajkumar.Sivaprakasam@Sun.COM 	}
241*9891SRajkumar.Sivaprakasam@Sun.COM 	if (curpinfo->MasterSMSL != madpinfo->MasterSMSL) {
242*9891SRajkumar.Sivaprakasam@Sun.COM 		flags |= IBT_PORT_CHANGE_SM_SL;
243*9891SRajkumar.Sivaprakasam@Sun.COM 	}
244*9891SRajkumar.Sivaprakasam@Sun.COM 	if (curpinfo->SubnetTimeOut != madpinfo->SubnetTimeOut) {
245*9891SRajkumar.Sivaprakasam@Sun.COM 		flags |= IBT_PORT_CHANGE_SUB_TIMEOUT;
246*9891SRajkumar.Sivaprakasam@Sun.COM 	}
247*9891SRajkumar.Sivaprakasam@Sun.COM 	if ((madpinfo->CapabilityMask & SM_CAP_MASK_IS_SM_DISABLED)
248*9891SRajkumar.Sivaprakasam@Sun.COM 	    ^ SMDisabled) {
249*9891SRajkumar.Sivaprakasam@Sun.COM 		flags |= IBT_PORT_CHANGE_SM_FLAG;
250*9891SRajkumar.Sivaprakasam@Sun.COM 	}
251*9891SRajkumar.Sivaprakasam@Sun.COM 	if ((madpinfo->CapabilityMask & SM_CAP_MASK_IS_CLNT_REREG_SUPPD)
252*9891SRajkumar.Sivaprakasam@Sun.COM 	    ^ ReregSuppd) {
253*9891SRajkumar.Sivaprakasam@Sun.COM 		flags |= IBT_PORT_CHANGE_REREG;
254*9891SRajkumar.Sivaprakasam@Sun.COM 	}
255*9891SRajkumar.Sivaprakasam@Sun.COM 	return (flags);
256*9891SRajkumar.Sivaprakasam@Sun.COM }
257*9891SRajkumar.Sivaprakasam@Sun.COM 
258*9891SRajkumar.Sivaprakasam@Sun.COM int
hermon_set_port_capability(hermon_state_t * state,uint8_t port,sm_portinfo_t * portinfo,ibt_port_change_t flags)259*9891SRajkumar.Sivaprakasam@Sun.COM hermon_set_port_capability(hermon_state_t *state, uint8_t port,
260*9891SRajkumar.Sivaprakasam@Sun.COM     sm_portinfo_t *portinfo, ibt_port_change_t flags)
261*9891SRajkumar.Sivaprakasam@Sun.COM {
262*9891SRajkumar.Sivaprakasam@Sun.COM 	uint32_t		capmask;
263*9891SRajkumar.Sivaprakasam@Sun.COM 	int			status;
264*9891SRajkumar.Sivaprakasam@Sun.COM 	hermon_hw_set_port_t	set_port;
265*9891SRajkumar.Sivaprakasam@Sun.COM 
266*9891SRajkumar.Sivaprakasam@Sun.COM 	bzero(&set_port, sizeof (set_port));
267*9891SRajkumar.Sivaprakasam@Sun.COM 
268*9891SRajkumar.Sivaprakasam@Sun.COM 	/* Validate that specified port number is legal */
269*9891SRajkumar.Sivaprakasam@Sun.COM 	if (!hermon_portnum_is_valid(state, port)) {
270*9891SRajkumar.Sivaprakasam@Sun.COM 		return (IBT_HCA_PORT_INVALID);
271*9891SRajkumar.Sivaprakasam@Sun.COM 	}
272*9891SRajkumar.Sivaprakasam@Sun.COM 
273*9891SRajkumar.Sivaprakasam@Sun.COM 	/*
274*9891SRajkumar.Sivaprakasam@Sun.COM 	 * Convert InfiniBand-defined port capability flags to the format
275*9891SRajkumar.Sivaprakasam@Sun.COM 	 * specified by the IBTF.  Specifically, we modify the capability
276*9891SRajkumar.Sivaprakasam@Sun.COM 	 * mask based on the specified values.
277*9891SRajkumar.Sivaprakasam@Sun.COM 	 */
278*9891SRajkumar.Sivaprakasam@Sun.COM 	capmask = portinfo->CapabilityMask;
279*9891SRajkumar.Sivaprakasam@Sun.COM 
280*9891SRajkumar.Sivaprakasam@Sun.COM 	if (flags & IBT_PORT_CHANGE_SM_FLAG)
281*9891SRajkumar.Sivaprakasam@Sun.COM 		capmask ^= SM_CAP_MASK_IS_SM;
282*9891SRajkumar.Sivaprakasam@Sun.COM 
283*9891SRajkumar.Sivaprakasam@Sun.COM 	if (flags & IBT_PORT_CHANGE_REREG)
284*9891SRajkumar.Sivaprakasam@Sun.COM 		capmask ^= SM_CAP_MASK_IS_CLNT_REREG_SUPPD;
285*9891SRajkumar.Sivaprakasam@Sun.COM 	set_port.cap_mask = capmask;
286*9891SRajkumar.Sivaprakasam@Sun.COM 
287*9891SRajkumar.Sivaprakasam@Sun.COM 	/*
288*9891SRajkumar.Sivaprakasam@Sun.COM 	 * Use the Hermon SET_PORT command to update the capability mask and
289*9891SRajkumar.Sivaprakasam@Sun.COM 	 * (possibly) reset the QKey violation counter for the specified port.
290*9891SRajkumar.Sivaprakasam@Sun.COM 	 * Note: In general, this operation shouldn't fail.  If it does, then
291*9891SRajkumar.Sivaprakasam@Sun.COM 	 * it is an indication that something (probably in HW, but maybe in
292*9891SRajkumar.Sivaprakasam@Sun.COM 	 * SW) has gone seriously wrong.
293*9891SRajkumar.Sivaprakasam@Sun.COM 	 */
294*9891SRajkumar.Sivaprakasam@Sun.COM 	status = hermon_set_port_cmd_post(state, &set_port, port,
295*9891SRajkumar.Sivaprakasam@Sun.COM 	    HERMON_SLEEPFLAG_FOR_CONTEXT());
296*9891SRajkumar.Sivaprakasam@Sun.COM 	if (status != HERMON_CMD_SUCCESS) {
297*9891SRajkumar.Sivaprakasam@Sun.COM 		HERMON_WARNING(state, "failed to modify port capabilities");
298*9891SRajkumar.Sivaprakasam@Sun.COM 		cmn_err(CE_CONT, "Hermon: SET_IB (port %02d) command failed: "
299*9891SRajkumar.Sivaprakasam@Sun.COM 		    "%08x\n", port, status);
300*9891SRajkumar.Sivaprakasam@Sun.COM 		return (DDI_FAILURE);
301*9891SRajkumar.Sivaprakasam@Sun.COM 	}
302*9891SRajkumar.Sivaprakasam@Sun.COM 
303*9891SRajkumar.Sivaprakasam@Sun.COM 	return (DDI_SUCCESS);
304*9891SRajkumar.Sivaprakasam@Sun.COM }
305*9891SRajkumar.Sivaprakasam@Sun.COM 
306*9891SRajkumar.Sivaprakasam@Sun.COM /*
3079517SBill.Taylor@Sun.COM  * hermon_agent_handle_req()
3089517SBill.Taylor@Sun.COM  *    Context: Called with priority of taskQ thread
3099517SBill.Taylor@Sun.COM  */
3109517SBill.Taylor@Sun.COM static void
hermon_agent_handle_req(void * cb_args)3119517SBill.Taylor@Sun.COM hermon_agent_handle_req(void *cb_args)
3129517SBill.Taylor@Sun.COM {
3139517SBill.Taylor@Sun.COM 	hermon_agent_handler_arg_t	*agent_args;
3149517SBill.Taylor@Sun.COM 	hermon_agent_list_t		*curr;
315*9891SRajkumar.Sivaprakasam@Sun.COM 	ibc_async_event_t		event;
316*9891SRajkumar.Sivaprakasam@Sun.COM 	ibt_async_code_t		type, code;
317*9891SRajkumar.Sivaprakasam@Sun.COM 	sm_portinfo_t			curpinfo, tmadpinfo;
318*9891SRajkumar.Sivaprakasam@Sun.COM 	sm_portinfo_t			*madpinfop;
3199517SBill.Taylor@Sun.COM 	hermon_state_t			*state;
3209517SBill.Taylor@Sun.COM 	ibmf_handle_t			ibmf_handle;
3219517SBill.Taylor@Sun.COM 	ibmf_msg_t			*msgp;
3229517SBill.Taylor@Sun.COM 	ibmf_msg_bufs_t			*recv_msgbufp;
3239517SBill.Taylor@Sun.COM 	ibmf_msg_bufs_t			*send_msgbufp;
324*9891SRajkumar.Sivaprakasam@Sun.COM 	ib_mad_hdr_t			*madhdrp;
3259517SBill.Taylor@Sun.COM 	ibmf_retrans_t			retrans;
3269517SBill.Taylor@Sun.COM 	uint_t				port;
3279517SBill.Taylor@Sun.COM 	int				status;
3289517SBill.Taylor@Sun.COM 
329*9891SRajkumar.Sivaprakasam@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*((sm_portinfo_t *)madpinfop)))
330*9891SRajkumar.Sivaprakasam@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(curpinfo))
331*9891SRajkumar.Sivaprakasam@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(tmadpinfo))
3329517SBill.Taylor@Sun.COM 	/* Extract the necessary info from the callback args parameter */
3339517SBill.Taylor@Sun.COM 	agent_args  = (hermon_agent_handler_arg_t *)cb_args;
3349517SBill.Taylor@Sun.COM 	ibmf_handle = agent_args->ahd_ibmfhdl;
3359517SBill.Taylor@Sun.COM 	msgp	    = agent_args->ahd_ibmfmsg;
3369517SBill.Taylor@Sun.COM 	curr	    = agent_args->ahd_agentlist;
3379517SBill.Taylor@Sun.COM 	state	    = curr->agl_state;
3389517SBill.Taylor@Sun.COM 	port	    = curr->agl_port;
3399517SBill.Taylor@Sun.COM 
3409517SBill.Taylor@Sun.COM 	/*
3419517SBill.Taylor@Sun.COM 	 * Set the message send buffer pointers to the message receive buffer
3429517SBill.Taylor@Sun.COM 	 * pointers to reuse the IBMF provided buffers for the sender
3439517SBill.Taylor@Sun.COM 	 * information.
3449517SBill.Taylor@Sun.COM 	 */
3459517SBill.Taylor@Sun.COM 	recv_msgbufp = &msgp->im_msgbufs_recv;
3469517SBill.Taylor@Sun.COM 	send_msgbufp = &msgp->im_msgbufs_send;
3479517SBill.Taylor@Sun.COM 	bcopy(recv_msgbufp, send_msgbufp, sizeof (ibmf_msg_bufs_t));
3489517SBill.Taylor@Sun.COM 
3499517SBill.Taylor@Sun.COM 	/*
3509517SBill.Taylor@Sun.COM 	 * Check if the incoming packet is a special "Hermon Trap" MAD.  If it
3519517SBill.Taylor@Sun.COM 	 * is, then do the special handling.  If it isn't, then simply pass it
3529517SBill.Taylor@Sun.COM 	 * on to the firmware and forward the response back to the IBMF.
3539517SBill.Taylor@Sun.COM 	 *
3549517SBill.Taylor@Sun.COM 	 * Note: Hermon has a unique method for handling internally generated
3559517SBill.Taylor@Sun.COM 	 * Traps.  All internally detected/generated Trap messages are
3569517SBill.Taylor@Sun.COM 	 * automatically received by the IBMF (as receive completions on QP0),
3579517SBill.Taylor@Sun.COM 	 * which (because all Hermon Trap MADs have SLID == 0) detects it as a
3589517SBill.Taylor@Sun.COM 	 * special "Hermon Trap" and forwards it here to the driver's SMA.
3599517SBill.Taylor@Sun.COM 	 * It is then our responsibility here to fill in the Trap MAD's DLID
3609517SBill.Taylor@Sun.COM 	 * for forwarding to the real Master SM (as programmed in the port's
3619517SBill.Taylor@Sun.COM 	 * PortInfo.MasterSMLID field.)
3629517SBill.Taylor@Sun.COM 	 */
3639517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(msgp->im_local_addr))
3649517SBill.Taylor@Sun.COM 	if (HERMON_IS_SPECIAL_TRAP_MAD(msgp)) {
3659517SBill.Taylor@Sun.COM 		msgp->im_local_addr.ia_remote_lid =
3669517SBill.Taylor@Sun.COM 		    hermon_get_smlid(state, port);
3679517SBill.Taylor@Sun.COM 	} else {
368*9891SRajkumar.Sivaprakasam@Sun.COM 		int isSMSet, isReregSuppd;
369*9891SRajkumar.Sivaprakasam@Sun.COM 		uint_t attr_id, method, mgmt_class;
370*9891SRajkumar.Sivaprakasam@Sun.COM 
371*9891SRajkumar.Sivaprakasam@Sun.COM 		madhdrp = recv_msgbufp->im_bufs_mad_hdr;
372*9891SRajkumar.Sivaprakasam@Sun.COM 		method = madhdrp->R_Method;
373*9891SRajkumar.Sivaprakasam@Sun.COM 		attr_id = b2h16(madhdrp->AttributeID);
374*9891SRajkumar.Sivaprakasam@Sun.COM 		mgmt_class = madhdrp->MgmtClass;
375*9891SRajkumar.Sivaprakasam@Sun.COM 
376*9891SRajkumar.Sivaprakasam@Sun.COM 		/*
377*9891SRajkumar.Sivaprakasam@Sun.COM 		 * Is this a Subnet Manager MAD with SET method ? If so
378*9891SRajkumar.Sivaprakasam@Sun.COM 		 * we will have to get the current portinfo to generate
379*9891SRajkumar.Sivaprakasam@Sun.COM 		 * events based on what has changed in portinfo.
380*9891SRajkumar.Sivaprakasam@Sun.COM 		 */
381*9891SRajkumar.Sivaprakasam@Sun.COM 		isSMSet = (((mgmt_class == MAD_MGMT_CLASS_SUBN_LID_ROUTED)||
382*9891SRajkumar.Sivaprakasam@Sun.COM 		    (mgmt_class == MAD_MGMT_CLASS_SUBN_DIRECT_ROUTE)) &&
383*9891SRajkumar.Sivaprakasam@Sun.COM 		    (method == MAD_METHOD_SET));
384*9891SRajkumar.Sivaprakasam@Sun.COM 
385*9891SRajkumar.Sivaprakasam@Sun.COM 		/*
386*9891SRajkumar.Sivaprakasam@Sun.COM 		 * Get the current portinfo to compare with the portinfo
387*9891SRajkumar.Sivaprakasam@Sun.COM 		 * received in the MAD for PortChange event.
388*9891SRajkumar.Sivaprakasam@Sun.COM 		 */
389*9891SRajkumar.Sivaprakasam@Sun.COM 		if (isSMSet && (attr_id == SM_PORTINFO_ATTRID) ||
390*9891SRajkumar.Sivaprakasam@Sun.COM 		    (attr_id == SM_PKEY_TABLE_ATTRID) ||
391*9891SRajkumar.Sivaprakasam@Sun.COM 		    (attr_id == SM_GUIDINFO_ATTRID)) {
392*9891SRajkumar.Sivaprakasam@Sun.COM 			madpinfop = recv_msgbufp->im_bufs_cl_data;
393*9891SRajkumar.Sivaprakasam@Sun.COM 			tmadpinfo = *madpinfop;
394*9891SRajkumar.Sivaprakasam@Sun.COM 			HERMON_GETPORTINFO_SWAP(&tmadpinfo);
395*9891SRajkumar.Sivaprakasam@Sun.COM 			status = hermon_getportinfo_cmd_post(state, port,
396*9891SRajkumar.Sivaprakasam@Sun.COM 			    HERMON_SLEEPFLAG_FOR_CONTEXT(), &curpinfo);
397*9891SRajkumar.Sivaprakasam@Sun.COM 			if (status != HERMON_CMD_SUCCESS) {
398*9891SRajkumar.Sivaprakasam@Sun.COM 				cmn_err(CE_CONT, "Hermon: GetPortInfo "
399*9891SRajkumar.Sivaprakasam@Sun.COM 				    "(port %02d) command failed: %08x\n", port,
400*9891SRajkumar.Sivaprakasam@Sun.COM 				    status);
401*9891SRajkumar.Sivaprakasam@Sun.COM 				goto hermon_agent_handle_req_skip_response;
402*9891SRajkumar.Sivaprakasam@Sun.COM 			}
403*9891SRajkumar.Sivaprakasam@Sun.COM 		}
404*9891SRajkumar.Sivaprakasam@Sun.COM 
4059517SBill.Taylor@Sun.COM 		/*
4069517SBill.Taylor@Sun.COM 		 * Post the command to the firmware (using the MAD_IFC
4079517SBill.Taylor@Sun.COM 		 * command).  Note: We also reuse the command that was passed
4089517SBill.Taylor@Sun.COM 		 * in.  We pass the pointer to the original MAD payload as if
4099517SBill.Taylor@Sun.COM 		 * it were both the source of the incoming MAD as well as the
4109517SBill.Taylor@Sun.COM 		 * destination for the response.  This is acceptable and saves
4119517SBill.Taylor@Sun.COM 		 * us the step of one additional copy.  Note:  If this command
4129517SBill.Taylor@Sun.COM 		 * fails for any reason other than HERMON_CMD_BAD_PKT, it
4139517SBill.Taylor@Sun.COM 		 * probably indicates a serious problem.
4149517SBill.Taylor@Sun.COM 		 */
4159517SBill.Taylor@Sun.COM 		status = hermon_mad_ifc_cmd_post(state, port,
4169517SBill.Taylor@Sun.COM 		    HERMON_CMD_SLEEP_NOSPIN,
4179517SBill.Taylor@Sun.COM 		    (uint32_t *)recv_msgbufp->im_bufs_mad_hdr,
4189517SBill.Taylor@Sun.COM 		    (uint32_t *)send_msgbufp->im_bufs_mad_hdr);
4199517SBill.Taylor@Sun.COM 		if (status != HERMON_CMD_SUCCESS) {
4209517SBill.Taylor@Sun.COM 			if ((status != HERMON_CMD_BAD_PKT) &&
4219517SBill.Taylor@Sun.COM 			    (status != HERMON_CMD_INSUFF_RSRC)) {
4229517SBill.Taylor@Sun.COM 				cmn_err(CE_CONT, "Hermon: MAD_IFC (port %02d) "
4239517SBill.Taylor@Sun.COM 				    "command failed: %08x\n", port, status);
4249517SBill.Taylor@Sun.COM 			}
4259517SBill.Taylor@Sun.COM 
4269517SBill.Taylor@Sun.COM 			/* finish cleanup */
4279517SBill.Taylor@Sun.COM 			goto hermon_agent_handle_req_skip_response;
4289517SBill.Taylor@Sun.COM 		}
429*9891SRajkumar.Sivaprakasam@Sun.COM 
430*9891SRajkumar.Sivaprakasam@Sun.COM 		if (isSMSet) {
431*9891SRajkumar.Sivaprakasam@Sun.COM 			event.ev_port_flags = 0;
432*9891SRajkumar.Sivaprakasam@Sun.COM 			type = 0;
433*9891SRajkumar.Sivaprakasam@Sun.COM 			event.ev_port = (uint8_t)port;
434*9891SRajkumar.Sivaprakasam@Sun.COM 
435*9891SRajkumar.Sivaprakasam@Sun.COM 			switch (attr_id) {
436*9891SRajkumar.Sivaprakasam@Sun.COM 			case SM_PORTINFO_ATTRID:
437*9891SRajkumar.Sivaprakasam@Sun.COM 				/*
438*9891SRajkumar.Sivaprakasam@Sun.COM 				 * This is a SM SET method with portinfo
439*9891SRajkumar.Sivaprakasam@Sun.COM 				 * attribute. If ClientRereg bit was set in
440*9891SRajkumar.Sivaprakasam@Sun.COM 				 * the MADs portinfo this is a REREG event
441*9891SRajkumar.Sivaprakasam@Sun.COM 				 * (see section 14.4.11 in IB Spec 1.2.1). Else
442*9891SRajkumar.Sivaprakasam@Sun.COM 				 * compare the current (before MAD_IFC command)
443*9891SRajkumar.Sivaprakasam@Sun.COM 				 * portinfo with the portinfo in the MAD and
444*9891SRajkumar.Sivaprakasam@Sun.COM 				 * signal PORT_CHANGE event with the proper
445*9891SRajkumar.Sivaprakasam@Sun.COM 				 * ev_port_flags.
446*9891SRajkumar.Sivaprakasam@Sun.COM 				 *
447*9891SRajkumar.Sivaprakasam@Sun.COM 				 */
448*9891SRajkumar.Sivaprakasam@Sun.COM 				isReregSuppd = curpinfo.CapabilityMask &
449*9891SRajkumar.Sivaprakasam@Sun.COM 				    SM_CAP_MASK_IS_CLNT_REREG_SUPPD;
450*9891SRajkumar.Sivaprakasam@Sun.COM 
451*9891SRajkumar.Sivaprakasam@Sun.COM 				madpinfop = recv_msgbufp->im_bufs_cl_data;
452*9891SRajkumar.Sivaprakasam@Sun.COM 				if (tmadpinfo.ClientRereg && isReregSuppd) {
453*9891SRajkumar.Sivaprakasam@Sun.COM 					type |= IBT_CLNT_REREG_EVENT;
454*9891SRajkumar.Sivaprakasam@Sun.COM 				}
455*9891SRajkumar.Sivaprakasam@Sun.COM 
456*9891SRajkumar.Sivaprakasam@Sun.COM 				type |= IBT_PORT_CHANGE_EVENT;
457*9891SRajkumar.Sivaprakasam@Sun.COM 				event.ev_port_flags = hermon_port_change_flags(
458*9891SRajkumar.Sivaprakasam@Sun.COM 				    &curpinfo, &tmadpinfo);
459*9891SRajkumar.Sivaprakasam@Sun.COM 				if (event.ev_port_flags &
460*9891SRajkumar.Sivaprakasam@Sun.COM 				    (IBT_PORT_CHANGE_REREG |
461*9891SRajkumar.Sivaprakasam@Sun.COM 				    IBT_PORT_CHANGE_SM_FLAG)) {
462*9891SRajkumar.Sivaprakasam@Sun.COM 					if (hermon_set_port_capability(state,
463*9891SRajkumar.Sivaprakasam@Sun.COM 					    port, &curpinfo,
464*9891SRajkumar.Sivaprakasam@Sun.COM 					    event.ev_port_flags)
465*9891SRajkumar.Sivaprakasam@Sun.COM 					    != DDI_SUCCESS) {
466*9891SRajkumar.Sivaprakasam@Sun.COM 						cmn_err(CE_CONT, "HERMON: Port "
467*9891SRajkumar.Sivaprakasam@Sun.COM 						    "%d capability reset "
468*9891SRajkumar.Sivaprakasam@Sun.COM 						    "failed\n", port);
469*9891SRajkumar.Sivaprakasam@Sun.COM 					}
470*9891SRajkumar.Sivaprakasam@Sun.COM 				}
471*9891SRajkumar.Sivaprakasam@Sun.COM 
472*9891SRajkumar.Sivaprakasam@Sun.COM 				/*
473*9891SRajkumar.Sivaprakasam@Sun.COM 				 * If we have a SMLID change event but
474*9891SRajkumar.Sivaprakasam@Sun.COM 				 * capability mask doesn't have Rereg support
475*9891SRajkumar.Sivaprakasam@Sun.COM 				 * bit set, we have to do the Rereg part too.
476*9891SRajkumar.Sivaprakasam@Sun.COM 				 */
477*9891SRajkumar.Sivaprakasam@Sun.COM 				if ((event.ev_port_flags &
478*9891SRajkumar.Sivaprakasam@Sun.COM 				    IBT_PORT_CHANGE_SM_LID) && !isReregSuppd)
479*9891SRajkumar.Sivaprakasam@Sun.COM 					type |= IBT_CLNT_REREG_EVENT;
480*9891SRajkumar.Sivaprakasam@Sun.COM 				break;
481*9891SRajkumar.Sivaprakasam@Sun.COM 			case SM_PKEY_TABLE_ATTRID:
482*9891SRajkumar.Sivaprakasam@Sun.COM 				type |= IBT_PORT_CHANGE_EVENT;
483*9891SRajkumar.Sivaprakasam@Sun.COM 				event.ev_port_flags = IBT_PORT_CHANGE_PKEY;
484*9891SRajkumar.Sivaprakasam@Sun.COM 				break;
485*9891SRajkumar.Sivaprakasam@Sun.COM 			case SM_GUIDINFO_ATTRID:
486*9891SRajkumar.Sivaprakasam@Sun.COM 				type |= IBT_PORT_CHANGE_EVENT;
487*9891SRajkumar.Sivaprakasam@Sun.COM 				event.ev_port_flags = IBT_PORT_CHANGE_SGID;
488*9891SRajkumar.Sivaprakasam@Sun.COM 				break;
489*9891SRajkumar.Sivaprakasam@Sun.COM 			default:
490*9891SRajkumar.Sivaprakasam@Sun.COM 				break;
491*9891SRajkumar.Sivaprakasam@Sun.COM 
492*9891SRajkumar.Sivaprakasam@Sun.COM 			}
493*9891SRajkumar.Sivaprakasam@Sun.COM 
494*9891SRajkumar.Sivaprakasam@Sun.COM 			/*
495*9891SRajkumar.Sivaprakasam@Sun.COM 			 * NOTE: here we call ibc_async_handler directly without
496*9891SRajkumar.Sivaprakasam@Sun.COM 			 * using the HERMON_DO_IBTF_ASYNC_CALLB, since hermon
497*9891SRajkumar.Sivaprakasam@Sun.COM 			 * can not be unloaded till ibmf_unregiter is done and
498*9891SRajkumar.Sivaprakasam@Sun.COM 			 * this thread (hs_taskq_agents) will be destroyed
499*9891SRajkumar.Sivaprakasam@Sun.COM 			 * before ibmf_uregister is called.
500*9891SRajkumar.Sivaprakasam@Sun.COM 			 *
501*9891SRajkumar.Sivaprakasam@Sun.COM 			 * The hermon event queue based hs_in_evcallb flag
502*9891SRajkumar.Sivaprakasam@Sun.COM 			 * assumes that we will pick one event after another
503*9891SRajkumar.Sivaprakasam@Sun.COM 			 * and dispatch them sequentially. If we use
504*9891SRajkumar.Sivaprakasam@Sun.COM 			 * HERMON_DO_IBTF_ASYNC_CALLB, we will break this
505*9891SRajkumar.Sivaprakasam@Sun.COM 			 * assumption make hs_in_evcallb inconsistent.
506*9891SRajkumar.Sivaprakasam@Sun.COM 			 */
507*9891SRajkumar.Sivaprakasam@Sun.COM 			while (type != 0) {
508*9891SRajkumar.Sivaprakasam@Sun.COM 				if (type & IBT_PORT_CHANGE_EVENT) {
509*9891SRajkumar.Sivaprakasam@Sun.COM 					code = IBT_PORT_CHANGE_EVENT;
510*9891SRajkumar.Sivaprakasam@Sun.COM 					type &= ~IBT_PORT_CHANGE_EVENT;
511*9891SRajkumar.Sivaprakasam@Sun.COM 				} else {
512*9891SRajkumar.Sivaprakasam@Sun.COM 					code = IBT_CLNT_REREG_EVENT;
513*9891SRajkumar.Sivaprakasam@Sun.COM 					type = 0;
514*9891SRajkumar.Sivaprakasam@Sun.COM 				}
515*9891SRajkumar.Sivaprakasam@Sun.COM 				ibc_async_handler(state->hs_ibtfpriv, code,
516*9891SRajkumar.Sivaprakasam@Sun.COM 				    &event);
517*9891SRajkumar.Sivaprakasam@Sun.COM 			}
518*9891SRajkumar.Sivaprakasam@Sun.COM 		}
5199517SBill.Taylor@Sun.COM 	}
5209517SBill.Taylor@Sun.COM 
5219517SBill.Taylor@Sun.COM 	/*
5229517SBill.Taylor@Sun.COM 	 * If incoming MAD was "TrapRepress", then no response is necessary.
5239517SBill.Taylor@Sun.COM 	 * Free the IBMF message and return.
5249517SBill.Taylor@Sun.COM 	 */
5259517SBill.Taylor@Sun.COM 	if (HERMON_IS_TRAP_REPRESS_MAD(msgp)) {
5269517SBill.Taylor@Sun.COM 		goto hermon_agent_handle_req_skip_response;
5279517SBill.Taylor@Sun.COM 	}
5289517SBill.Taylor@Sun.COM 
5299517SBill.Taylor@Sun.COM 	/*
5309517SBill.Taylor@Sun.COM 	 * Modify the response MAD as necessary (for any special cases).
5319517SBill.Taylor@Sun.COM 	 * Specifically, if this MAD was a directed route MAD, then some
5329517SBill.Taylor@Sun.COM 	 * additional packet manipulation may be necessary because the Hermon
5339517SBill.Taylor@Sun.COM 	 * firmware does not do all the required steps to respond to the
5349517SBill.Taylor@Sun.COM 	 * MAD.
5359517SBill.Taylor@Sun.COM 	 */
5369517SBill.Taylor@Sun.COM 	hermon_agent_mad_resp_handling(state, msgp, port);
5379517SBill.Taylor@Sun.COM 
5389517SBill.Taylor@Sun.COM 	/*
5399517SBill.Taylor@Sun.COM 	 * Send response (or forwarded "Trap" MAD) back to IBMF.  We use the
5409517SBill.Taylor@Sun.COM 	 * "response callback" to indicate when it is appropriate (later) to
5419517SBill.Taylor@Sun.COM 	 * free the IBMF msg.
5429517SBill.Taylor@Sun.COM 	 */
5439517SBill.Taylor@Sun.COM 	status = ibmf_msg_transport(ibmf_handle, IBMF_QP_HANDLE_DEFAULT,
5449517SBill.Taylor@Sun.COM 	    msgp, &retrans, hermon_agent_response_cb, state, 0);
5459517SBill.Taylor@Sun.COM 	if (status != IBMF_SUCCESS) {
5469517SBill.Taylor@Sun.COM 		goto hermon_agent_handle_req_skip_response;
5479517SBill.Taylor@Sun.COM 	}
5489517SBill.Taylor@Sun.COM 
5499517SBill.Taylor@Sun.COM 	/* Free up the callback args parameter */
5509517SBill.Taylor@Sun.COM 	kmem_free(agent_args, sizeof (hermon_agent_handler_arg_t));
5519517SBill.Taylor@Sun.COM 	return;
5529517SBill.Taylor@Sun.COM 
5539517SBill.Taylor@Sun.COM hermon_agent_handle_req_skip_response:
5549517SBill.Taylor@Sun.COM 	/* Free up the ibmf message */
5559517SBill.Taylor@Sun.COM 	(void) ibmf_free_msg(ibmf_handle, &msgp);
5569517SBill.Taylor@Sun.COM 
5579517SBill.Taylor@Sun.COM 	/* Free up the callback args parameter */
5589517SBill.Taylor@Sun.COM 	kmem_free(agent_args, sizeof (hermon_agent_handler_arg_t));
5599517SBill.Taylor@Sun.COM }
5609517SBill.Taylor@Sun.COM 
5619517SBill.Taylor@Sun.COM 
5629517SBill.Taylor@Sun.COM /*
5639517SBill.Taylor@Sun.COM  * hermon_agent_response_cb()
5649517SBill.Taylor@Sun.COM  *    Context: Called from the IBMF context
5659517SBill.Taylor@Sun.COM  */
5669517SBill.Taylor@Sun.COM /* ARGSUSED */
5679517SBill.Taylor@Sun.COM static void
hermon_agent_response_cb(ibmf_handle_t ibmf_handle,ibmf_msg_t * msgp,void * args)5689517SBill.Taylor@Sun.COM hermon_agent_response_cb(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp,
5699517SBill.Taylor@Sun.COM     void *args)
5709517SBill.Taylor@Sun.COM {
5719517SBill.Taylor@Sun.COM 	/*
5729517SBill.Taylor@Sun.COM 	 * It is the responsibility of each IBMF callback recipient to free
5739517SBill.Taylor@Sun.COM 	 * the packets that it has been given.  Now that we are in the
5749517SBill.Taylor@Sun.COM 	 * response callback, we can be assured that it is safe to do so.
5759517SBill.Taylor@Sun.COM 	 */
5769517SBill.Taylor@Sun.COM 	(void) ibmf_free_msg(ibmf_handle, &msgp);
5779517SBill.Taylor@Sun.COM }
5789517SBill.Taylor@Sun.COM 
5799517SBill.Taylor@Sun.COM 
5809517SBill.Taylor@Sun.COM /*
5819517SBill.Taylor@Sun.COM  * hermon_agent_list_init()
5829517SBill.Taylor@Sun.COM  *    Context: Only called from attach() path context
5839517SBill.Taylor@Sun.COM  */
5849517SBill.Taylor@Sun.COM static int
hermon_agent_list_init(hermon_state_t * state)5859517SBill.Taylor@Sun.COM hermon_agent_list_init(hermon_state_t *state)
5869517SBill.Taylor@Sun.COM {
5879517SBill.Taylor@Sun.COM 	hermon_agent_list_t	*curr;
5889517SBill.Taylor@Sun.COM 	uint_t			num_ports, num_agents, num_agents_per_port;
5899517SBill.Taylor@Sun.COM 	uint_t			num_sma_agents = 0;
5909517SBill.Taylor@Sun.COM 	uint_t			num_pma_agents = 0;
5919517SBill.Taylor@Sun.COM 	uint_t			num_bma_agents = 0;
5929517SBill.Taylor@Sun.COM 	uint_t			do_qp0, do_qp1;
5939517SBill.Taylor@Sun.COM 	int			i, j, indx;
5949517SBill.Taylor@Sun.COM 
5959517SBill.Taylor@Sun.COM 	/*
5969517SBill.Taylor@Sun.COM 	 * Calculate the number of registered agents for each port
5979517SBill.Taylor@Sun.COM 	 * (SMA, PMA, and BMA) and determine whether or not to register
5989517SBill.Taylor@Sun.COM 	 * a given agent with the IBMF (or whether to let the Hermon firmware
5999517SBill.Taylor@Sun.COM 	 * handle it)
6009517SBill.Taylor@Sun.COM 	 */
6019517SBill.Taylor@Sun.COM 	num_ports	    = state->hs_cfg_profile->cp_num_ports;
6029517SBill.Taylor@Sun.COM 	num_agents	    = 0;
6039517SBill.Taylor@Sun.COM 	num_agents_per_port = 0;
6049517SBill.Taylor@Sun.COM 	do_qp0		    = state->hs_cfg_profile->cp_qp0_agents_in_fw;
6059517SBill.Taylor@Sun.COM 	do_qp1		    = state->hs_cfg_profile->cp_qp1_agents_in_fw;
6069517SBill.Taylor@Sun.COM 	if (do_qp0 == 0) {
6079517SBill.Taylor@Sun.COM 		num_agents += (num_ports * HERMON_NUM_QP0_AGENTS_PER_PORT);
6089517SBill.Taylor@Sun.COM 		num_agents_per_port += HERMON_NUM_QP0_AGENTS_PER_PORT;
6099517SBill.Taylor@Sun.COM 		num_sma_agents = num_ports;
6109517SBill.Taylor@Sun.COM 	}
6119517SBill.Taylor@Sun.COM 	if (do_qp1 == 0) {
6129517SBill.Taylor@Sun.COM 		num_agents += (num_ports * HERMON_NUM_QP1_AGENTS_PER_PORT);
6139517SBill.Taylor@Sun.COM 		num_agents_per_port += HERMON_NUM_QP1_AGENTS_PER_PORT;
6149517SBill.Taylor@Sun.COM 		num_pma_agents = num_ports;
6159517SBill.Taylor@Sun.COM 		/*
6169517SBill.Taylor@Sun.COM 		 * The following line is commented out because the Hermon
6179517SBill.Taylor@Sun.COM 		 * firmware does not currently support a BMA.  If it did,
6189517SBill.Taylor@Sun.COM 		 * then we would want to register the agent with the IBMF.
6199517SBill.Taylor@Sun.COM 		 * (We would also need to have HERMON_NUM_QP1_AGENTS_PER_PORT
6209517SBill.Taylor@Sun.COM 		 * set to 2, instead of 1.)
6219517SBill.Taylor@Sun.COM 		 *
6229517SBill.Taylor@Sun.COM 		 * num_bma_agents = num_ports;
6239517SBill.Taylor@Sun.COM 		 */
6249517SBill.Taylor@Sun.COM 	}
6259517SBill.Taylor@Sun.COM 
6269517SBill.Taylor@Sun.COM 	state->hs_num_agents = num_agents;
6279517SBill.Taylor@Sun.COM 
6289517SBill.Taylor@Sun.COM 	/*
6299517SBill.Taylor@Sun.COM 	 * Allocate the memory for all of the agent list entries
6309517SBill.Taylor@Sun.COM 	 */
6319517SBill.Taylor@Sun.COM 	state->hs_agents = (hermon_agent_list_t *)kmem_zalloc(num_agents *
6329517SBill.Taylor@Sun.COM 	    sizeof (hermon_agent_list_t), KM_SLEEP);
6339517SBill.Taylor@Sun.COM 	if (state->hs_agents == NULL) {
6349517SBill.Taylor@Sun.COM 		return (DDI_FAILURE);
6359517SBill.Taylor@Sun.COM 	}
6369517SBill.Taylor@Sun.COM 
6379517SBill.Taylor@Sun.COM 	/*
6389517SBill.Taylor@Sun.COM 	 * Fill in each of the agent list entries with the agent's
6399517SBill.Taylor@Sun.COM 	 * MgmtClass, port number, and Hermon softstate pointer
6409517SBill.Taylor@Sun.COM 	 */
6419517SBill.Taylor@Sun.COM 	indx = 0;
6429517SBill.Taylor@Sun.COM 	for (i = 0; i < num_agents_per_port; i++) {
6439517SBill.Taylor@Sun.COM 		for (j = 0; j < num_ports; j++) {
6449517SBill.Taylor@Sun.COM 			curr = &state->hs_agents[indx];
6459517SBill.Taylor@Sun.COM 			curr->agl_state = state;
6469517SBill.Taylor@Sun.COM 			curr->agl_port  = j + 1;
6479517SBill.Taylor@Sun.COM 
6489517SBill.Taylor@Sun.COM 			if ((do_qp0 == 0) && num_sma_agents) {
6499517SBill.Taylor@Sun.COM 				curr->agl_mgmtclass = SUBN_AGENT;
6509517SBill.Taylor@Sun.COM 				num_sma_agents--;
6519517SBill.Taylor@Sun.COM 				indx++;
6529517SBill.Taylor@Sun.COM 			} else if ((do_qp1 == 0) && (num_pma_agents)) {
6539517SBill.Taylor@Sun.COM 				curr->agl_mgmtclass = PERF_AGENT;
6549517SBill.Taylor@Sun.COM 				num_pma_agents--;
6559517SBill.Taylor@Sun.COM 				indx++;
6569517SBill.Taylor@Sun.COM 			} else if ((do_qp1 == 0) && (num_bma_agents)) {
6579517SBill.Taylor@Sun.COM 				curr->agl_mgmtclass = BM_AGENT;
6589517SBill.Taylor@Sun.COM 				num_bma_agents--;
6599517SBill.Taylor@Sun.COM 				indx++;
6609517SBill.Taylor@Sun.COM 			}
6619517SBill.Taylor@Sun.COM 		}
6629517SBill.Taylor@Sun.COM 	}
6639517SBill.Taylor@Sun.COM 
6649517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
6659517SBill.Taylor@Sun.COM }
6669517SBill.Taylor@Sun.COM 
6679517SBill.Taylor@Sun.COM 
6689517SBill.Taylor@Sun.COM /*
6699517SBill.Taylor@Sun.COM  * hermon_agent_list_fini()
6709517SBill.Taylor@Sun.COM  *    Context: Only called from attach() and/or detach() path contexts
6719517SBill.Taylor@Sun.COM  */
6729517SBill.Taylor@Sun.COM static void
hermon_agent_list_fini(hermon_state_t * state)6739517SBill.Taylor@Sun.COM hermon_agent_list_fini(hermon_state_t *state)
6749517SBill.Taylor@Sun.COM {
6759517SBill.Taylor@Sun.COM 	/* Free up the memory for the agent list entries */
6769517SBill.Taylor@Sun.COM 	kmem_free(state->hs_agents,
6779517SBill.Taylor@Sun.COM 	    state->hs_num_agents * sizeof (hermon_agent_list_t));
6789517SBill.Taylor@Sun.COM }
6799517SBill.Taylor@Sun.COM 
6809517SBill.Taylor@Sun.COM 
6819517SBill.Taylor@Sun.COM /*
6829517SBill.Taylor@Sun.COM  * hermon_agent_register_all()
6839517SBill.Taylor@Sun.COM  *    Context: Only called from attach() path context
6849517SBill.Taylor@Sun.COM  */
6859517SBill.Taylor@Sun.COM static int
hermon_agent_register_all(hermon_state_t * state)6869517SBill.Taylor@Sun.COM hermon_agent_register_all(hermon_state_t *state)
6879517SBill.Taylor@Sun.COM {
6889517SBill.Taylor@Sun.COM 	hermon_agent_list_t	*curr;
6899517SBill.Taylor@Sun.COM 	ibmf_register_info_t	ibmf_reg;
6909517SBill.Taylor@Sun.COM 	ibmf_impl_caps_t	impl_caps;
6919517SBill.Taylor@Sun.COM 	ib_guid_t		nodeguid;
6929517SBill.Taylor@Sun.COM 	int			i, status, num_registered;
6939517SBill.Taylor@Sun.COM 
6949517SBill.Taylor@Sun.COM 	/* Get the Hermon NodeGUID from the softstate */
6959517SBill.Taylor@Sun.COM 	nodeguid = state->hs_ibtfinfo.hca_attr->hca_node_guid;
6969517SBill.Taylor@Sun.COM 
6979517SBill.Taylor@Sun.COM 	/*
6989517SBill.Taylor@Sun.COM 	 * Register each of the agents with the IBMF (and add callbacks for
6999517SBill.Taylor@Sun.COM 	 * each to the hermon_agent_request_cb() routine).  Note:  If we
7009517SBill.Taylor@Sun.COM 	 * fail somewhere along the line here, we attempt to cleanup as much
7019517SBill.Taylor@Sun.COM 	 * of the mess as we can and then jump to hermon_agent_unregister_all()
7029517SBill.Taylor@Sun.COM 	 * to cleanup the rest.
7039517SBill.Taylor@Sun.COM 	 */
7049517SBill.Taylor@Sun.COM 	num_registered = 0;
7059517SBill.Taylor@Sun.COM 
7069517SBill.Taylor@Sun.COM 	if (state->hs_num_agents == 0) {
7079517SBill.Taylor@Sun.COM 		return (DDI_SUCCESS);
7089517SBill.Taylor@Sun.COM 	}
7099517SBill.Taylor@Sun.COM 
7109517SBill.Taylor@Sun.COM 	for (i = 0; i < state->hs_num_agents; i++) {
7119517SBill.Taylor@Sun.COM 		/* Register each agent with the IBMF */
7129517SBill.Taylor@Sun.COM 		curr = &state->hs_agents[i];
7139517SBill.Taylor@Sun.COM 		ibmf_reg.ir_ci_guid	 = nodeguid;
7149517SBill.Taylor@Sun.COM 		ibmf_reg.ir_port_num	 = curr->agl_port;
7159517SBill.Taylor@Sun.COM 		ibmf_reg.ir_client_class = curr->agl_mgmtclass;
7169517SBill.Taylor@Sun.COM 
7179517SBill.Taylor@Sun.COM 		status = ibmf_register(&ibmf_reg, IBMF_VERSION, 0,
7189517SBill.Taylor@Sun.COM 		    NULL, NULL, &curr->agl_ibmfhdl, &impl_caps);
7199517SBill.Taylor@Sun.COM 		if (status != IBMF_SUCCESS) {
7209517SBill.Taylor@Sun.COM 			goto agents_reg_fail;
7219517SBill.Taylor@Sun.COM 		}
7229517SBill.Taylor@Sun.COM 
7239517SBill.Taylor@Sun.COM 		/* Setup callbacks with the IBMF */
7249517SBill.Taylor@Sun.COM 		status  = ibmf_setup_async_cb(curr->agl_ibmfhdl,
7259517SBill.Taylor@Sun.COM 		    IBMF_QP_HANDLE_DEFAULT, hermon_agent_request_cb, curr, 0);
7269517SBill.Taylor@Sun.COM 		if (status != IBMF_SUCCESS) {
7279517SBill.Taylor@Sun.COM 			(void) ibmf_unregister(&curr->agl_ibmfhdl, 0);
7289517SBill.Taylor@Sun.COM 			goto agents_reg_fail;
7299517SBill.Taylor@Sun.COM 		}
7309517SBill.Taylor@Sun.COM 		num_registered++;
7319517SBill.Taylor@Sun.COM 	}
7329517SBill.Taylor@Sun.COM 
7339517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
7349517SBill.Taylor@Sun.COM 
7359517SBill.Taylor@Sun.COM agents_reg_fail:
7369517SBill.Taylor@Sun.COM 	(void) hermon_agent_unregister_all(state, num_registered);
7379517SBill.Taylor@Sun.COM 	return (DDI_FAILURE);
7389517SBill.Taylor@Sun.COM }
7399517SBill.Taylor@Sun.COM 
7409517SBill.Taylor@Sun.COM 
7419517SBill.Taylor@Sun.COM /*
7429517SBill.Taylor@Sun.COM  * hermon_agent_unregister_all()
7439517SBill.Taylor@Sun.COM  *    Context: Only called from detach() path context
7449517SBill.Taylor@Sun.COM  */
7459517SBill.Taylor@Sun.COM static int
hermon_agent_unregister_all(hermon_state_t * state,int num_reg)7469517SBill.Taylor@Sun.COM hermon_agent_unregister_all(hermon_state_t *state, int num_reg)
7479517SBill.Taylor@Sun.COM {
7489517SBill.Taylor@Sun.COM 	hermon_agent_list_t	*curr;
7499517SBill.Taylor@Sun.COM 	int			i, status;
7509517SBill.Taylor@Sun.COM 
7519517SBill.Taylor@Sun.COM 	if (num_reg == 0) {
7529517SBill.Taylor@Sun.COM 		return (DDI_SUCCESS);
7539517SBill.Taylor@Sun.COM 	}
7549517SBill.Taylor@Sun.COM 
7559517SBill.Taylor@Sun.COM 	/*
7569517SBill.Taylor@Sun.COM 	 * For each registered agent in the agent list, teardown the
7579517SBill.Taylor@Sun.COM 	 * callbacks from the IBMF and unregister.
7589517SBill.Taylor@Sun.COM 	 */
7599517SBill.Taylor@Sun.COM 	for (i = 0; i < num_reg; i++) {
7609517SBill.Taylor@Sun.COM 		curr = &state->hs_agents[i];
7619517SBill.Taylor@Sun.COM 
7629517SBill.Taylor@Sun.COM 		/* Teardown the IBMF callback */
7639517SBill.Taylor@Sun.COM 		status = ibmf_tear_down_async_cb(curr->agl_ibmfhdl,
7649517SBill.Taylor@Sun.COM 		    IBMF_QP_HANDLE_DEFAULT, 0);
7659517SBill.Taylor@Sun.COM 		if (status != IBMF_SUCCESS) {
7669517SBill.Taylor@Sun.COM 			return (DDI_FAILURE);
7679517SBill.Taylor@Sun.COM 		}
7689517SBill.Taylor@Sun.COM 
7699517SBill.Taylor@Sun.COM 		/* Unregister the agent from the IBMF */
7709517SBill.Taylor@Sun.COM 		status = ibmf_unregister(&curr->agl_ibmfhdl, 0);
7719517SBill.Taylor@Sun.COM 		if (status != IBMF_SUCCESS) {
7729517SBill.Taylor@Sun.COM 			return (DDI_FAILURE);
7739517SBill.Taylor@Sun.COM 		}
7749517SBill.Taylor@Sun.COM 	}
7759517SBill.Taylor@Sun.COM 
7769517SBill.Taylor@Sun.COM 	return (DDI_SUCCESS);
7779517SBill.Taylor@Sun.COM }
7789517SBill.Taylor@Sun.COM 
7799517SBill.Taylor@Sun.COM 
7809517SBill.Taylor@Sun.COM /*
7819517SBill.Taylor@Sun.COM  * hermon_agent_mad_resp_handling()
7829517SBill.Taylor@Sun.COM  *    Context: Called with priority of taskQ thread
7839517SBill.Taylor@Sun.COM  */
7849517SBill.Taylor@Sun.COM /* ARGSUSED */
7859517SBill.Taylor@Sun.COM static void
hermon_agent_mad_resp_handling(hermon_state_t * state,ibmf_msg_t * msgp,uint_t port)7869517SBill.Taylor@Sun.COM hermon_agent_mad_resp_handling(hermon_state_t *state, ibmf_msg_t *msgp,
7879517SBill.Taylor@Sun.COM     uint_t port)
7889517SBill.Taylor@Sun.COM {
7899517SBill.Taylor@Sun.COM 	ib_mad_hdr_t	*rmadhdrp = msgp->im_msgbufs_recv.im_bufs_mad_hdr;
7909517SBill.Taylor@Sun.COM 	ib_mad_hdr_t	*smadhdrp = msgp->im_msgbufs_send.im_bufs_mad_hdr;
7919517SBill.Taylor@Sun.COM 	uint_t		hop_count, hop_point;
7929517SBill.Taylor@Sun.COM 	uchar_t		*resp, *ret_path;
7939517SBill.Taylor@Sun.COM 
7949517SBill.Taylor@Sun.COM 	resp = (uchar_t *)msgp->im_msgbufs_send.im_bufs_cl_data;
7959517SBill.Taylor@Sun.COM 
7969517SBill.Taylor@Sun.COM 	/*
7979517SBill.Taylor@Sun.COM 	 * Handle directed route MADs as a special case.  Hermon firmware
7989517SBill.Taylor@Sun.COM 	 * does not update the "direction" bit, "hop pointer", "Return
7999517SBill.Taylor@Sun.COM 	 * Path" or, in fact, any of the "directed route" parameters.  So
8009517SBill.Taylor@Sun.COM 	 * the responsibility falls on Hermon driver software to inspect the
8019517SBill.Taylor@Sun.COM 	 * MADs and update those fields as appropriate (see section 14.2.2
8029517SBill.Taylor@Sun.COM 	 * of the IBA specification, rev 1.1)
8039517SBill.Taylor@Sun.COM 	 */
8049517SBill.Taylor@Sun.COM 	if (HERMON_MAD_IS_DR(rmadhdrp)) {
8059517SBill.Taylor@Sun.COM 
8069517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*((sm_dr_mad_hdr_t *)rmadhdrp)))
8079517SBill.Taylor@Sun.COM 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*((sm_dr_mad_hdr_t *)smadhdrp)))
8089517SBill.Taylor@Sun.COM 
8099517SBill.Taylor@Sun.COM 		/*
8109517SBill.Taylor@Sun.COM 		 * Set the "Direction" bit to one.  This indicates that this
8119517SBill.Taylor@Sun.COM 		 * is now directed route response
8129517SBill.Taylor@Sun.COM 		 */
8139517SBill.Taylor@Sun.COM 		HERMON_DRMAD_SET_DIRECTION(rmadhdrp);
8149517SBill.Taylor@Sun.COM 
8159517SBill.Taylor@Sun.COM 		/* Extract the "hop pointer" and "hop count" from the MAD */
8169517SBill.Taylor@Sun.COM 		hop_count = HERMON_DRMAD_GET_HOPCOUNT(rmadhdrp);
8179517SBill.Taylor@Sun.COM 		hop_point = HERMON_DRMAD_GET_HOPPOINTER(rmadhdrp);
8189517SBill.Taylor@Sun.COM 
8199517SBill.Taylor@Sun.COM 		/* Append the port we came in on to the "Return Path" */
8209517SBill.Taylor@Sun.COM 		if ((hop_count != 0) && ((hop_point == hop_count) ||
8219517SBill.Taylor@Sun.COM 		    (hop_point == hop_count + 1))) {
8229517SBill.Taylor@Sun.COM 			ret_path = &resp[HERMON_DRMAD_RETURN_PATH_OFFSET];
8239517SBill.Taylor@Sun.COM 			ret_path[hop_point] = (uchar_t)port;
8249517SBill.Taylor@Sun.COM 		}
8259517SBill.Taylor@Sun.COM 
8269517SBill.Taylor@Sun.COM 		/* Then increment the "hop pointer" in the MAD */
8279517SBill.Taylor@Sun.COM 		hop_point++;
8289517SBill.Taylor@Sun.COM 		HERMON_DRMAD_SET_HOPPOINTER(smadhdrp, (uint8_t)hop_point);
8299517SBill.Taylor@Sun.COM 	}
8309517SBill.Taylor@Sun.COM }
831