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