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