ibdm.c revision 43ed929a6988c3778f00123f4a4a8541e515ec16
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* ibdm.c
*
* This file contains the InifiniBand Device Manager (IBDM) support functions.
* IB nexus driver will only be the client for the IBDM module.
*
* IBDM registers with SA access to send DM MADs to discover the IOC's behind
* the IOU's.
*
* IB nexus driver registers with IBDM to find the information about the
* HCA's and IOC's (behind the IOU) present on the IB fabric.
*/
/* Function Prototype declarations */
static int ibdm_free_iou_info(ibdm_dp_gidinfo_t *);
static int ibdm_fini(void);
static int ibdm_init(void);
static int ibdm_get_reachable_ports(ibdm_port_attr_t *,
ibdm_hca_list_t *);
static int ibdm_send_classportinfo(ibdm_dp_gidinfo_t *);
static int ibdm_send_iounitinfo(ibdm_dp_gidinfo_t *);
static int ibdm_is_dev_mgt_supported(ibdm_dp_gidinfo_t *);
static int ibdm_retry_command(ibdm_timeout_cb_args_t *);
static int ibdm_get_diagcode(ibdm_dp_gidinfo_t *, int);
static int ibdm_verify_mad_status(ib_mad_hdr_t *);
static int ibdm_handle_redirection(ibmf_msg_t *,
ibdm_dp_gidinfo_t *, int *);
static void ibdm_wait_probe_completion(void);
static void ibdm_sweep_fabric(int);
static void ibdm_probe_gid_thread(void *);
static void ibdm_wakeup_probe_gid_cv(void);
static int ibdm_port_attr_ibmf_fini(ibdm_port_attr_t *, int);
static void ibdm_update_port_attr(ibdm_port_attr_t *);
static void ibdm_handle_hca_attach(ib_guid_t);
static void ibdm_handle_srventry_mad(ibmf_msg_t *,
ibdm_dp_gidinfo_t *, int *);
static void ibdm_recv_incoming_mad(void *);
static void ibdm_pkt_timeout_hdlr(void *arg);
static void ibdm_initialize_port(ibdm_port_attr_t *);
static void ibdm_probe_gid(ibdm_dp_gidinfo_t *);
static void ibdm_alloc_send_buffers(ibmf_msg_t *);
static void ibdm_free_send_buffers(ibmf_msg_t *);
static void ibdm_handle_hca_detach(ib_guid_t);
static int ibdm_fini_port(ibdm_port_attr_t *);
static int ibdm_uninit_hca(ibdm_hca_list_t *);
static void ibdm_handle_iounitinfo(ibmf_handle_t,
ibmf_msg_t *, ibdm_dp_gidinfo_t *, int *);
static void ibdm_handle_ioc_profile(ibmf_handle_t,
ibmf_msg_t *, ibdm_dp_gidinfo_t *, int *);
static void ibdm_event_hdlr(void *, ibt_hca_hdl_t,
static void ibdm_handle_classportinfo(ibmf_handle_t,
ibmf_msg_t *, ibdm_dp_gidinfo_t *, int *);
static void ibdm_update_ioc_port_gidlist(ibdm_ioc_info_t *,
ibdm_dp_gidinfo_t *, int *);
ibdm_hca_list_t **);
ib_lid_t);
ibmf_saa_event_details_t *, void *);
static void ibdm_reprobe_update_port_srv(ibdm_ioc_info_t *,
static void ibdm_rmfrom_glgid_list(ibdm_dp_gidinfo_t *,
static void ibdm_free_gid_list(ibdm_gid_t *);
static void ibdm_notify_newgid_iocs(ibdm_dp_gidinfo_t *);
static void ibdm_saa_event_taskq(void *);
static void ibdm_free_saa_event_arg(ibdm_saa_event_arg_t *);
static void ibdm_get_next_port(ibdm_hca_list_t **,
ibdm_port_attr_t **, int);
static void ibdm_add_to_gl_gid(ibdm_dp_gidinfo_t *,
static void ibdm_addto_glhcalist(ibdm_dp_gidinfo_t *,
ibdm_hca_list_t *);
static void ibdm_delete_glhca_list(ibdm_dp_gidinfo_t *);
static void ibdm_saa_handle_new_gid(void *);
static void ibdm_reset_all_dgids(ibmf_saa_handle_t);
static void ibdm_reset_gidinfo(ibdm_dp_gidinfo_t *);
static void ibdm_delete_gidinfo(ibdm_dp_gidinfo_t *);
int ibdm_dft_timeout = IBDM_DFT_TIMEOUT;
#ifdef DEBUG
int ibdm_ignore_saa_event = 0;
#endif
/* Modload support */
static struct modlmisc ibdm_modlmisc = {
"InfiniBand Device Manager %I%",
};
struct modlinkage ibdm_modlinkage = {
(void *)&ibdm_modlmisc,
};
static ibt_clnt_modinfo_t ibdm_ibt_modinfo = {
NULL,
"ibdm"
};
/* Global variables */
char *ibdm_string = "ibdm";
/*
* _init
* Loadable module init, called before any other module.
* Initialize mutex
* Register with IBTF
*/
int
_init(void)
{
int err;
(void) ibdm_fini();
return (DDI_FAILURE);
}
(void) ibdm_fini();
}
return (err);
}
int
_fini(void)
{
int err;
(void) ibdm_init();
return (EBUSY);
}
(void) ibdm_init();
}
return (err);
}
int
{
}
/*
* ibdm_init():
* Register with IBTF
* Allocate memory for the HCAs
* Allocate minor-nodes for the HCAs
*/
static int
ibdm_init(void)
{
int i, hca_count;
}
"failed %x", status);
return (IBDM_FAILURE);
}
}
for (i = 0; i < hca_count; i++)
(void) ibdm_handle_hca_attach(hca_guids[i]);
if (hca_count)
}
}
return (IBDM_SUCCESS);
}
static int
{
return (0);
}
/* handle the case where an ioc_timeout_id is scheduled */
if (ioc->ioc_timeout_id) {
"ioc_timeout_id = 0x%x", timeout_id);
"untimeout ioc_timeout_id failed");
return (-1);
}
ioc->ioc_timeout_id = 0;
}
/* handle the case where an ioc_dc_timeout_id is scheduled */
if (ioc->ioc_dc_timeout_id) {
"ioc_dc_timeout_id = 0x%x", timeout_id);
"untimeout ioc_dc_timeout_id failed");
return (-1);
}
ioc->ioc_dc_timeout_id = 0;
}
/* handle the case where serv[k].se_timeout_id is scheduled */
"ioc->ioc_serv[%d].se_timeout_id = 0x%x",
k, timeout_id);
" untimeout se_timeout_id failed");
return (-1);
}
}
}
/* delete GID list */
while (head) {
"Deleting gid_list struct %p", head);
}
/* delete ioc_serv */
sizeof (ibdm_srvents_info_t);
}
}
return (0);
}
/*
* ibdm_fini():
* Un-register with IBTF
* De allocate memory for the GID info
*/
static int
{
int ii;
return (IBDM_FAILURE);
}
}
"uninit_hca %p failed", temp);
return (IBDM_FAILURE);
}
}
while (gid_info) {
(void) ibdm_free_iou_info(gid_info);
while (head) {
IBTF_DPRINTF_L4("ibdm",
"\tibdm_fini: Deleting gid structs");
}
}
}
}
return (IBDM_SUCCESS);
}
/*
* ibdm_event_hdlr()
*
* IBDM registers this asynchronous event handler at the time of
* ibt_attach. IBDM support the following async events. For other
* event, simply returns success.
* IBT_HCA_ATTACH_EVENT:
* Retrieves the information about all the port that are
* present on this HCA, allocates the port attributes
* structure and calls IB nexus callback routine with
* the port attributes structure as an input argument.
* IBT_HCA_DETACH_EVENT:
* Retrieves the information about all the ports that are
* present on this HCA and calls IB nexus callback with
* port guid as an argument
* IBT_EVENT_PORT_UP:
* Register with IBMF and SA access
* Setup IBMF receive callback routine
* IBT_EVENT_PORT_DOWN:
* Un-Register with IBMF and SA access
* Teardown IBMF receive callback routine
*/
/*ARGSUSED*/
static void
ibdm_event_hdlr(void *clnt_hdl,
{
switch (code) {
case IBT_HCA_ATTACH_EVENT: /* New HCA registered with IBTF */
break;
case IBT_HCA_DETACH_EVENT: /* HCA unregistered with IBTF */
(*ibdm.ibdm_ibnex_callback)((void *)
}
break;
case IBT_EVENT_PORT_UP:
IBTF_DPRINTF_L2("ibdm",
"\tevent_hdlr: HCA not present");
break;
}
break;
case IBT_ERROR_PORT_DOWN:
IBTF_DPRINTF_L2("ibdm",
"\tevent_hdlr: HCA not present");
break;
}
(void) ibdm_fini_port(port);
break;
break;
}
}
/*
* ibdm_initialize_port()
* Register with IBMF
* Register with SA access
* Register a receive callback routine with IBMF. IBMF invokes
* this routine whenever a MAD arrives at this port.
* Update the port attributes
*/
static void
{
int ii;
/* Check whether the port is active */
NULL) != IBT_SUCCESS)
return;
return;
/* This should not occur */
return;
}
"sa access registration failed");
return;
}
"IBMF registration failed");
(void) ibdm_fini_port(port);
return;
}
ibdm_ibmf_recv_cb, 0, 0) != IBMF_SUCCESS) {
"IBMF setup recv cb failed");
(void) ibdm_fini_port(port);
return;
}
if (IBDM_INVALID_PKEY(pkey)) {
continue;
}
}
}
/*
* ibdm_port_attr_ibmf_init:
* With IBMF - Alloc QP Handle and Setup Async callback
*/
static void
{
int ret;
IBMF_SUCCESS) {
"IBMF failed to alloc qp %d", ret);
return;
}
port->pa_ibmf_hdl);
IBMF_SUCCESS) {
"IBMF setup recv cb failed %d", ret);
}
}
/*
* ibdm_get_port_attr()
* Get port attributes from HCA guid and port number
* Return pointer to ibdm_port_attr_t on Success
* and NULL on failure
*/
static ibdm_port_attr_t *
{
int ii;
while (hca_list) {
return (port_attr);
}
}
}
}
return (NULL);
}
/*
* ibdm_update_port_attr()
* Update the port attributes
*/
static void
{
/* This should not occur */
return;
}
/*
* PKey information in portinfo valid only if port is
* ACTIVE. Bail out if not.
*/
return;
}
}
}
/*
* ibdm_handle_hca_attach()
*/
static void
{
IBTF_DPRINTF_L4("ibdm",
"\thandle_hca_attach: hca_guid = 0x%llX", hca_guid);
/* open the HCA first */
&hca_hdl)) != IBT_SUCCESS) {
"open_hca failed, status 0x%x", status);
return;
}
hca_attr = (ibt_hca_attr_t *)
/* ibt_query_hca always returns IBT_SUCCESS */
&size)) != IBT_SUCCESS) {
"ibt_query_hca_ports failed, status 0x%x", status);
(void) ibt_close_hca(hca_hdl);
return;
}
hca_list = (ibdm_hca_list_t *)
/*
* Init a dummy port attribute for the HCA node
* This is for Per-HCA Node. Initialize port_attr :
* hca_guid & port_guid -> hca_guid
* npkeys, pkey_tbl is NULL
* port_num, sn_prefix is 0
* vendorid, product_id, dev_version from HCA
* pa_state is IBT_PORT_ACTIVE
*/
sizeof (ibdm_port_attr_t), KM_SLEEP);
/*
* Register with IBMF, SA access when the port is in
* ACTIVE state. Also register a callback routine
* with IBMF to receive incoming DM MAD's.
* The IBDM event handler takes care of registration of
* port which are not active.
*/
IBTF_DPRINTF_L4("ibdm",
"\thandle_hca_attach: port guid %llx Port state 0x%x",
}
}
"already seen by IBDM", hca_guid);
(void) ibdm_uninit_hca(hca_list);
return;
}
}
} else {
}
(*ibdm.ibdm_ibnex_callback)((void *)
}
}
/*
* ibdm_handle_hca_detach()
*/
static void
{
IBTF_DPRINTF_L4("ibdm",
"\thandle_hca_detach: hca_guid = 0x%llx", hca_guid);
/* Make sure no probes are running */
while (head) {
else
break;
}
}
(void) ibdm_handle_hca_attach(hca_guid);
}
static int
{
int ii;
return (IBDM_FAILURE);
}
}
if (head->hl_hca_hdl)
return (IBDM_FAILURE);
return (IBDM_SUCCESS);
}
/*
* For each port on the HCA,
* 1) Teardown IBMF receive callback function
* 2) Unregister with IBMF
* 3) Unregister with SA access
*/
static int
{
int ii, ibmf_status;
break;
continue;
"ibdm_port_attr_ibmf_fini failed for "
"port pkey 0x%x", ii);
return (IBDM_FAILURE);
}
}
if (port_attr->pa_ibmf_hdl) {
if (ibmf_status != IBMF_SUCCESS) {
"ibmf_tear_down_async_cb failed %d", ibmf_status);
return (IBDM_FAILURE);
}
if (ibmf_status != IBMF_SUCCESS) {
"ibmf_unregister failed %d", ibmf_status);
return (IBDM_FAILURE);
}
}
if (ibmf_status != IBMF_SUCCESS) {
"ibmf_sa_session_close failed %d", ibmf_status);
return (IBDM_FAILURE);
}
}
}
return (IBDM_SUCCESS);
}
/*
* ibdm_port_attr_ibmf_fini:
* With IBMF - Tear down Async callback and free QP Handle
*/
static int
{
int ibmf_status;
if (ibmf_status != IBMF_SUCCESS) {
"ibmf_tear_down_async_cb failed %d", ibmf_status);
return (IBDM_FAILURE);
}
if (ibmf_status != IBMF_SUCCESS) {
"ibmf_free_qp failed %d", ibmf_status);
return (IBDM_FAILURE);
}
}
return (IBDM_SUCCESS);
}
/*
* ibdm_gid_decr_pending:
* decrement gl_pending_cmds. If zero wakeup sleeping threads
*/
static void
{
if (--gidinfo->gl_pending_cmds == 0) {
/*
* Handle DGID getting removed.
*/
if (gidinfo->gl_disconnected) {
"gidinfo %p hot removal", gidinfo);
return;
}
}
}
/*
* ibdm_wait_probe_completion:
* wait for probing to complete
*/
static void
{
if (ibdm.ibdm_ngid_probes_in_progress) {
}
}
/*
* ibdm_wakeup_probe_gid_cv:
* wakeup waiting threads (based on ibdm_ngid_probes_in_progress)
*/
static void
ibdm_wakeup_probe_gid_cv(void)
{
if (!ibdm.ibdm_ngid_probes_in_progress) {
}
}
/*
* ibdm_sweep_fabric(reprobe_flag)
* Find all possible Managed IOU's and their IOC's that are visible
* to the host. The algorithm used is as follows
*
* Send a "bus walk" request for each port on the host HCA to SA access
* SA returns complete set of GID's that are reachable from
* source port. This is done in parallel.
*
* Initialize GID state to IBDM_GID_PROBE_NOT_DONE
*
* Sort the GID list and eliminate duplicate GID's
* 1) Use DGID for sorting
* 2) use PortGuid for sorting
* Send SA query to retrieve NodeRecord and
* extract PortGuid from that.
*
* Set GID state to IBDM_GID_PROBE_FAILED to all the ports that dont
* support DM MAD's
* Send a "Portinfo" query to get the port capabilities and
* then check for DM MAD's support
*
* Send "ClassPortInfo" request for all the GID's in parallel,
* set the GID state to IBDM_GET_CLASSPORTINFO and wait on the
* cv_signal to complete.
*
* When DM agent on the remote GID sends back the response, IBMF
* invokes DM callback routine.
*
* If the response is proper, send "IOUnitInfo" request and set
* GID state to IBDM_GET_IOUNITINFO.
*
* If the response is proper, send "IocProfileInfo" request to
* all the IOC simultaneously and set GID state to IBDM_GET_IOC_DETAILS.
*
* Send request to get Service entries simultaneously
*
* Signal the waiting thread when received response for all the commands.
*
* Set the GID state to IBDM_GID_PROBE_FAILED when received a error
* response during the probing period.
*
* Note:
* ibdm.ibdm_ngid_probes_in_progress and ibdm_gid_list_t:gl_pending_cmds
* keep track of number commands in progress at any point of time.
* MAD transaction ID is used to identify a particular GID
* TBD: Consider registering the IBMF receive callback on demand
*
* Note: This routine must be called with ibdm.ibdm_mutex held
* TBD: Re probe the failure GID (for certain failures) when requested
* for fabric sweep next time
*
* Parameters : If reprobe_flag is set, All IOCs will be reprobed.
*/
static void
{
int ii;
int new_paths = 0;
/*
* Check whether a sweep already in progress. If so, just
* wait for the fabric sweep to complete
*/
/* Rescan the GID list for any removed GIDs for reprobe */
if (reprobe_flag)
/*
* Get list of all the ports reachable from the local known HCA
* ports which are active
*/
/*
* Get PATHS to all the reachable ports from
* SGID and update the global ibdm structure.
*/
}
/* Send a request to probe GIDs asynchronously. */
/* process newly encountered GIDs */
(void *)gid_info, TQ_NOSLEEP);
/* taskq failed to dispatch call it directly */
ibdm_probe_gid_thread((void *)gid_info);
}
/*
* Update the properties, if reprobe_flag is set
* Skip if gl_reprobe_flag is set, this will be
* a re-inserted / new GID, for which notifications
* have already been send.
*/
if (reprobe_flag) {
continue;
if (gid_info->gl_reprobe_flag) {
gid_info->gl_reprobe_flag = 0;
continue;
}
if (ioc)
gid_info);
}
}
}
}
/*
* ibdm_probe_gid_thread:
* thread that does the actual work for sweeping the fabric
* for a given GID
*/
static void
ibdm_probe_gid_thread(void *args)
{
int reprobe_flag;
reprobe_flag == 0) {
/*
* This GID may have been already probed. Send
* in a CLP to check if IOUnitInfo changed?
* Explicitly set gl_reprobe_flag to 0 so that
* IBnex is not notified on completion
*/
"get new IOCs information");
gid_info->gl_reprobe_flag = 0;
gid_info->gl_pending_cmds = 0;
}
} else {
}
return;
/*
* Reprobe all IOCs for the GID which has completed
* probe. Skip other port GIDs to same IOU.
* Explicitly set gl_reprobe_flag to 0 so that
* IBnex is not notified on completion
*/
gid_info->gl_reprobe_flag = 0;
/*
* Check whether IOC is present in the slot
* Series of nibbles (in the field
* iou_ctrl_list) represents a slot in the
* IOU.
* Byte format: 76543210
* Bits 0-3 of first byte represent Slot 2
* bits 4-7 of first byte represent slot 1,
* bits 0-3 of second byte represent slot 4
* and so on
* Each 4-bit nibble has the following meaning
* 0x0 : IOC not installed
* 0x1 : IOC is present
* 0xf : Slot does not exist
* and all other values are reserved.
*/
if ((ii % 2) == 0)
continue;
}
IBDM_SUCCESS) {
}
}
return;
return;
}
/*
* Check whether the destination GID supports DM agents. If
* not, stop probing the GID and continue with the next GID
* in the list.
*/
gid_info->gl_pending_cmds = 0;
return;
}
/* Get the nodeguid and portguid of the port */
gid_info->gl_pending_cmds = 0;
return;
}
/*
* Check whether we already knew about this NodeGuid
* If so, do not probe the GID and continue with the
* next GID in the gid list. Set the GID state to
* probing done.
*/
gid_info->gl_pending_cmds = 0;
return;
}
/*
* New or reinserted GID : Enable notification to IBnex
*/
/*
* Send ClassPortInfo request to the GID asynchronously.
*/
gid_info->gl_pending_cmds = 0;
return;
}
}
/*
* ibdm_check_dest_nodeguid
* Searches for the NodeGuid in the GID list
* Returns matching gid_info if found and otherwise NULL
*
* This function is called to handle new GIDs discovered
* during device sweep / probe or for GID_AVAILABLE event.
*
* Parameter :
* gid_info GID to check
*/
static ibdm_dp_gidinfo_t *
{
while (gid_list) {
IBTF_DPRINTF_L4("ibdm",
"\tcheck_dest_nodeguid: NodeGuid is present");
/* Add to gid_list */
KM_SLEEP);
return (gid_list);
}
}
return (NULL);
}
/*
* ibdm_is_dev_mgt_supported
* Get the PortInfo attribute (SA Query)
* Check "CompatabilityMask" field in the Portinfo.
* Return IBDM_SUCCESS if DM MAD's supported (if bit 19 set)
* by the port, otherwise IBDM_FAILURE
*/
static int
{
int ret;
"failed to get PORTINFO attribute %d", ret);
return (IBDM_FAILURE);
}
ret = IBDM_SUCCESS;
} else {
ret = IBDM_FAILURE;
}
return (ret);
}
/*
* ibdm_get_node_port_guids()
* Get the NodeInfoRecord of the port
* Save NodeGuid and PortGUID values in the GID list structure.
* Return IBDM_SUCCESS/IBDM_FAILURE
*/
static int
{
int ret;
" SA Retrieve Failed: %d", ret);
return (IBDM_FAILURE);
}
return (IBDM_SUCCESS);
}
/*
* ibdm_get_reachable_ports()
* Get list of the destination GID (and its path records) by
* querying the SA access.
*
* Returns Number paths
*/
static int
{
/* get reversible paths */
!= IBMF_SUCCESS) {
IBTF_DPRINTF_L2("ibdm",
"\tget_reachable_ports: Getting path records failed");
return (0);
}
continue;
}
/*
* This is a new GID. Allocate a GID structure and
* initialize the structure
* gl_state is initialized to IBDM_GID_PROBE_NOT_DONE (0)
* by kmem_zalloc call
*/
break;
break;
}
}
continue;
}
} else {
}
npaths++;
}
return (npaths);
}
/*
* ibdm_check_dgid()
* Look in the global list to check whether we know this DGID already
* Return IBDM_GID_PRESENT/IBDM_GID_NOT_PRESENT
*/
static ibdm_dp_gidinfo_t *
{
break;
}
}
return (gid_list);
}
/*
* ibdm_find_gid()
* Look in the global list to find a GID entry with matching
* port & node GUID.
* Return pointer to gidinfo if found, else return NULL
*/
static ibdm_dp_gidinfo_t *
{
break;
}
}
gid_list);
return (gid_list);
}
/*
* ibdm_send_classportinfo()
* Send classportinfo request. When the request is completed
* IBMF calls ibdm_classportinfo_cb routine to inform about
* the completion.
* Returns IBDM_SUCCESS/IBDM_FAILURE
*/
static int
{
IBTF_DPRINTF_L4("ibdm",
"\tsend_classportinfo: gid info 0x%p", gid_info);
/*
* Send command to get classportinfo attribute. Allocate a IBMF
* packet and initialize the packet.
*/
&msg) != IBMF_SUCCESS) {
return (IBDM_FAILURE);
}
hdr->AttributeModifier = 0;
IBTF_DPRINTF_L2("ibdm",
"\tsend_classportinfo: ibmf send failed");
}
return (IBDM_SUCCESS);
}
/*
* ibdm_handle_classportinfo()
* Invoked by the IBMF when the classportinfo request is completed.
*/
static void
{
void *data;
"Not a ClassPortInfo resp");
return;
}
/*
* If created/ active, cancel the timeout handler
*/
return;
}
if (gid_info->gl_timeout_id) {
"gl_timeout_id = 0x%x", timeout_id);
"untimeout gl_timeout_id failed");
}
gid_info->gl_timeout_id = 0;
}
/*
* Cache the "RespTimeValue" and redirection information in the
* global gid list data structure. This cached information will
* be used to send any further requests to the GID.
*/
/*
* Send IOUnitInfo request
* Reuse previously allocated IBMF packet for sending ClassPortInfo
* Check whether DM agent on the remote node requested redirection
*/
if (gid_info->gl_redirect_dlid != 0) {
}
} else {
}
hdr->AttributeModifier = 0;
IBTF_DPRINTF_L2("ibdm",
"\thandle_classportinfo: msg transport failed");
}
(*flag) |= IBDM_IBMF_PKT_REUSED;
}
/*
* ibdm_send_iounitinfo:
* Sends a DM request to get IOU unitinfo.
*/
static int
{
/*
* Send command to get iounitinfo attribute. Allocate a IBMF
* packet and initialize the packet.
*/
IBMF_SUCCESS) {
return (IBDM_FAILURE);
}
hdr->AttributeModifier = 0;
IBMF_SUCCESS) {
}
return (IBDM_SUCCESS);
}
/*
* ibdm_handle_iounitinfo()
* Invoked by the IBMF when IO Unitinfo request is completed.
*/
static void
{
int num_iocs;
"Unexpected response");
(*flag) |= IBDM_IBMF_PKT_UNEXP_RESP;
return;
}
IBTF_DPRINTF_L4("ibdm",
"\thandle_iounitinfo: DUP resp");
(*flag) = IBDM_IBMF_PKT_DUP_RESP;
return;
}
if (gid_info->gl_timeout_id) {
"gl_timeout_id = 0x%x", timeout_id);
"untimeout gl_timeout_id failed");
}
gid_info->gl_timeout_id = 0;
}
/*
* check if number of IOCs reported is zero? if yes, return.
* when num_iocs are reported zero internal IOC database needs
* to be updated. To ensure that save the number of IOCs in
* the new field "gl_num_iocs". Use a new field instead of
* "giou_info->iou_num_ctrl_slots" as that would prevent
* an unnecessary kmem_alloc/kmem_free when num_iocs is 0.
*/
return;
}
/*
* if there is an existing gl_iou (IOU has been probed before)
* check if the "iou_changeid" is same as saved entry in
* "giou_info->iou_changeid".
* (note: this logic can prevent IOC enumeration if a given
* vendor doesn't support setting iou_changeid field for its IOU)
*
* if there is an existing gl_iou and iou_changeid has changed :
* free up existing gl_iou info and its related structures.
* reallocate gl_iou info all over again.
* if we donot free this up; then this leads to memory leaks
*/
IBTF_DPRINTF_L3("ibdm",
"\thandle_iounitinfo: no IOCs changed");
return;
}
if (ibdm_free_iou_info(gid_info)) {
IBTF_DPRINTF_L3("ibdm",
"\thandle_iounitinfo: failed to cleanup resources");
return;
}
}
}
/*
* Parallelize getting IOC controller profiles from here.
* Allocate IBMF packets and send commands to get IOC profile for
* each IOC present on the IOU.
*/
/*
* Check whether IOC is present in the slot
* Series of nibbles (in the field iou_ctrl_list) represents
* a slot in the IOU.
* Byte format: 76543210
* Bits 0-3 of first byte represent Slot 2
* bits 4-7 of first byte represent slot 1,
* bits 0-3 of second byte represent slot 4 and so on
* Each 4-bit nibble has the following meaning
* 0x0 : IOC not installed
* 0x1 : IOC is present
* 0xf : Slot does not exist
* and all other values are reserved.
*/
if ((ii % 2) == 0)
"No IOC is present in the slot = %d", ii);
continue;
}
/*
* Re use the already allocated packet (for IOUnitinfo) to
* send the first IOC controller attribute. Allocate new
* IBMF packets for the rest of the IOC's
*/
&msg) != IBMF_SUCCESS) {
"IBMF packet allocation failed");
continue;
}
}
/* allocate send buffers for all messages */
if (gid_info->gl_redirect_dlid != 0) {
}
} else {
}
IBTF_DPRINTF_L2("ibdm",
"\thandle_iounitinfo: msg transport failed");
}
(*flag) |= IBDM_IBMF_PKT_REUSED;
}
}
/*
* ibdm_handle_ioc_profile()
* Invoked by the IBMF when the IOCControllerProfile request
* gets completed
*/
static void
{
/*
* Check whether we know this IOC already
* This will return NULL if reprobe is in progress
* IBDM_IOC_STATE_REPROBE_PROGRESS will be set.
* Do not hold mutexes here.
*/
return;
}
/* Make sure that IOC index is with the valid range */
"IOC index Out of range, index %d", ioc);
(*flag) |= IBDM_IBMF_PKT_UNEXP_RESP;
return;
}
reprobe = 1;
(*flag) |= IBDM_IBMF_PKT_DUP_RESP;
return;
}
if (ioc_info->ioc_timeout_id) {
"ioc_timeout_id = 0x%x", timeout_id);
"untimeout ioc_timeout_id failed");
}
ioc_info->ioc_timeout_id = 0;
}
if (reprobe == 0) {
}
/*
* Save all the IOC information in the global structures.
* Note the wire format is Big Endian and the Sparc process also
* big endian. So, there is no need to convert the data fields
* The conversion routines used below are ineffective on Sparc
* machines where as they will be effective on little endian
* machines such as Intel processors.
*/
/*
* Restrict updates to onlyport GIDs and service entries during reprobe
*/
if (reprobe == 0) {
gioc->ioc_vendorid =
}
}
}
KM_SLEEP);
/*
* In one single request, maximum number of requests that can be
* obtained is 4. If number of service entries are more than four,
* calculate number requests needed and send them parallelly.
*/
ii = 0;
while (nserv_entries) {
&msg) != IBMF_SUCCESS) {
continue;
}
}
if (gid_info->gl_redirect_dlid != 0) {
}
} else {
}
if (nserv_entries >= IBDM_MAX_SERV_ENTRIES_PER_REQ) {
} else {
(nserv_entries -1))));
nserv_entries = 0;
}
"timeout %x, ioc %d srv %d",
IBTF_DPRINTF_L2("ibdm",
"\thandle_ioc_profile: msg send failed");
}
(*flag) |= IBDM_IBMF_PKT_REUSED;
ii++;
}
}
/*
* ibdm_handle_srventry_mad()
*/
static void
{
/*
* Get the start and end index of the service entries
* Upper 16 bits identify the IOC
* Lower 16 bits specify the range of service entries
* LSB specifies (Big endian) end of the range
* MSB specifies (Big endian) start of the range
*/
/* Make sure that IOC index is with the valid range */
if ((ioc_no < 1) |
"IOC index Out of range, index %d", ioc_no);
(*flag) |= IBDM_IBMF_PKT_UNEXP_RESP;
return;
}
/*
* Make sure that the "start" and "end" service indexes are
* with in the valid range
*/
(*flag) |= IBDM_IBMF_PKT_UNEXP_RESP;
return;
}
"already known, ioc %d, srv %d, se_state %x",
(*flag) |= IBDM_IBMF_PKT_DUP_RESP;
return;
}
IBTF_DPRINTF_L2("ibdm",
"se_timeout_id = 0x%x", timeout_id);
"untimeout se_timeout_id failed");
}
}
}
}
/*
* ibdm_get_diagcode:
* Returns IBDM_SUCCESS/IBDM_FAILURE
*/
static int
{
&msg) != IBMF_SUCCESS) {
return (IBDM_FAILURE);
}
if (gid_info->gl_redirect_dlid != 0) {
}
} else {
}
if (attr == 0) {
cb_args->cb_ioc_num = 0;
} else {
}
cb_args->cb_srvents_start = 0;
}
return (IBDM_SUCCESS);
}
/*
* ibdm_handle_diagcode:
* Process the DiagCode MAD response and update local DM
* data structure.
*/
static void
{
if (attrmod == 0) {
(*flag) |= IBDM_IBMF_PKT_DUP_RESP;
IBTF_DPRINTF_L4("ibdm",
"\thandle_diagcode: Duplicate IOU DiagCode");
return;
}
cb_args->cb_req_type = 0;
if (gid_info->gl_timeout_id) {
"gl_timeout_id = 0x%x", timeout_id);
"untimeout gl_timeout_id failed");
}
gid_info->gl_timeout_id = 0;
}
} else {
(*flag) |= IBDM_IBMF_PKT_DUP_RESP;
IBTF_DPRINTF_L4("ibdm",
"\thandle_diagcode: Duplicate IOC DiagCode");
return;
}
cb_args->cb_req_type = 0;
if (timeout_id) {
"timeout_id = 0x%x", timeout_id);
"untimeout ioc_dc_timeout_id failed");
}
}
}
}
/*
* ibdm_is_ioc_present()
* Return ibdm_ioc_info_t if IOC guid is found in the global gid list
*/
static ibdm_ioc_info_t *
{
int ii;
while (head) {
continue;
}
"present: gid not present");
}
return (ioc);
}
}
}
return (NULL);
}
/*
* ibdm_ibmf_send_cb()
* IBMF invokes this callback routine after posting the DM MAD to
* the HCA.
*/
/*ARGSUSED*/
static void
{
IBTF_DPRINTF_L4("ibdm",
"\tibmf_send_cb: IBMF free msg failed");
}
}
/*
* ibdm_ibmf_recv_cb()
* Invoked by the IBMF when a response to the one of the DM requests
* is received.
*/
/*ARGSUSED*/
static void
{
/*
* If the taskq enable is set then dispatch a taskq to process
* the MAD, otherwise just process it on this thread
*/
if (ibdm_taskq_enable != IBDM_ENABLE_TASKQ_HANDLING) {
return;
}
/*
* create a taskq and dispatch it to process the incoming MAD
*/
if (taskq_args == NULL) {
"taskq_args");
IBTF_DPRINTF_L4("ibmf_recv_cb",
"\tibmf_recv_cb: IBMF free msg failed");
}
return;
}
TQ_NOSLEEP) == 0) {
IBTF_DPRINTF_L4("ibmf_recv_cb",
"\tibmf_recv_cb: IBMF free msg failed");
}
return;
}
/* taskq_args are deleted in ibdm_recv_incoming_mad() */
}
void
ibdm_recv_incoming_mad(void *args)
{
"Processing incoming MAD via taskq");
}
/*
* Calls ibdm_process_incoming_mad with all function arguments extracted
* from args
*/
/*ARGSUSED*/
static void
{
int flag = 0;
int ret;
IBTF_DPRINTF_L4("ibdm",
ibdm_dump_ibmf_msg(msg, 0);
/*
* IBMF calls this routine for every DM MAD that arrives at this port.
* But we handle only the responses for requests we sent. We drop all
* the DM packets that does not have response bit set in the MAD
* header(this eliminates all the requests sent to this port).
* We handle only DM class version 1 MAD's
*/
"IBMF free msg failed DM request drop it");
}
return;
}
while (gid_info) {
break;
}
/* Drop the packet */
" does not match: 0x%llx", transaction_id);
"IBMF free msg failed DM request drop it");
}
return;
}
/* Handle redirection for all the MAD's, except ClassPortInfo */
if (ret == IBDM_SUCCESS) {
return;
}
} else {
switch (gl_state) {
case IBDM_GET_CLASSPORTINFO:
break;
case IBDM_GET_IOUNITINFO:
break;
case IBDM_GET_IOC_DETAILS:
switch (IBDM_IN_IBMFMSG_ATTR(msg)) {
break;
break;
case IB_DM_ATTR_DIAG_CODE:
break;
default:
"Error state, wrong attribute :-(");
return;
}
break;
default:
IBTF_DPRINTF_L2("ibdm",
"process_incoming_mad: Dropping the packet"
" gl_state %x", gl_state);
"IBMF free msg failed DM request drop it");
}
return;
}
}
if ((flag & IBDM_IBMF_PKT_DUP_RESP) ||
(flag & IBDM_IBMF_PKT_UNEXP_RESP)) {
IBTF_DPRINTF_L2("ibdm",
"IBMF free msg failed DM request drop it");
}
return;
}
IBTF_DPRINTF_L2("ibdm",
"\tprocess_incoming_mad: pending commands negative");
}
if (--gid_info->gl_pending_cmds) {
"gid_info %p pending cmds %d",
} else {
if (--ibdm.ibdm_ngid_probes_in_progress == 0) {
IBTF_DPRINTF_L4("ibdm",
"\tprocess_incoming_mad: Wakeup");
}
}
/*
* Do not deallocate the IBMF packet if atleast one request
* is posted. IBMF packet is reused.
*/
if (!(flag & IBDM_IBMF_PKT_REUSED)) {
"IBMF free msg failed DM request drop it");
}
}
}
/*
* ibdm_verify_mad_status()
* Verifies the MAD status
* Returns IBDM_SUCCESS if status is correct
* Returns IBDM_FAILURE for bogus MAD status
*/
static int
{
int ret = 0;
return (IBDM_FAILURE);
}
ret = IBDM_SUCCESS;
ret = IBDM_SUCCESS;
else {
IBTF_DPRINTF_L4("ibdm",
ret = IBDM_FAILURE;
}
return (ret);
}
/*
* ibdm_handle_redirection()
* Returns IBDM_SUCCESS/IBDM_FAILURE
*/
static int
{
void *data;
case IBDM_GET_IOUNITINFO:
break;
case IBDM_GET_IOC_DETAILS:
switch (IBDM_IN_IBMFMSG_ATTR(msg)) {
case IB_DM_ATTR_DIAG_CODE:
if (attrmod == 0) {
break;
}
"IOC# Out of range %d", attrmod);
(*flag) |= IBDM_IBMF_PKT_UNEXP_RESP;
return (IBDM_FAILURE);
}
break;
"IOC# Out of range %d", attrmod);
(*flag) |= IBDM_IBMF_PKT_UNEXP_RESP;
return (IBDM_FAILURE);
}
break;
"IOC# Out of range %d", ioc_no);
(*flag) |= IBDM_IBMF_PKT_UNEXP_RESP;
return (IBDM_FAILURE);
}
" SE index Out of range %d", start);
(*flag) |= IBDM_IBMF_PKT_UNEXP_RESP;
return (IBDM_FAILURE);
}
break;
default:
/* ERROR State */
IBTF_DPRINTF_L2("ibdm",
"\thandle_redirection: wrong attribute :-(");
(*flag) |= IBDM_IBMF_PKT_UNEXP_RESP;
return (IBDM_FAILURE);
}
break;
default:
/* ERROR State */
IBTF_DPRINTF_L2("ibdm",
"\thandle_redirection: Error state :-(");
(*flag) |= IBDM_IBMF_PKT_UNEXP_RESP;
return (IBDM_FAILURE);
}
if ((*timeout_id) != 0) {
"untimeout failed %x", *timeout_id);
} else {
IBTF_DPRINTF_L5("ibdm",
"\thandle_redirection: timeout %x", *timeout_id);
}
*timeout_id = 0;
}
if (gid_info->gl_redirect_dlid != 0) {
}
hdr->AttributeID =
"timeout %x", *timeout_id);
"message transport failed");
}
(*flag) |= IBDM_IBMF_PKT_REUSED;
return (IBDM_SUCCESS);
}
/*
* ibdm_pkt_timeout_hdlr
* This timeout handler is registed for every IBMF packet that is
* sent through the IBMF. It gets called when no response is received
* within the specified time for the packet. No retries for the failed
* commands currently. Drops the failed IBMF packet and update the
* pending list commands.
*/
static void
ibdm_pkt_timeout_hdlr(void *arg)
{
int probe_done = B_FALSE;
int srv_ent;
(cb_args->cb_req_type == 0)) {
if (gid_info->gl_timeout_id)
gid_info->gl_timeout_id = 0;
return;
}
if (cb_args->cb_retry_count) {
if (gid_info->gl_timeout_id)
gid_info->gl_timeout_id = 0;
return;
}
cb_args->cb_retry_count = 0;
}
switch (cb_args->cb_req_type) {
case IBDM_REQ_TYPE_IOUINFO:
if (--gid_info->gl_pending_cmds == 0)
probe_done = B_TRUE;
if (gid_info->gl_timeout_id)
gid_info->gl_timeout_id = 0;
break;
case IBDM_REQ_TYPE_IOCINFO:
if (--gid_info->gl_pending_cmds == 0)
probe_done = B_TRUE;
#ifndef __lock_lint
if (ioc->ioc_timeout_id)
ioc->ioc_timeout_id = 0;
#endif
break;
case IBDM_REQ_TYPE_SRVENTS:
if (--gid_info->gl_pending_cmds == 0)
probe_done = B_TRUE;
#ifndef __lock_lint
#endif
break;
if (--gid_info->gl_pending_cmds == 0)
probe_done = B_TRUE;
if (gid_info->gl_timeout_id)
gid_info->gl_timeout_id = 0;
break;
if (--gid_info->gl_pending_cmds == 0)
probe_done = B_TRUE;
#ifndef __lock_lint
if (ioc->ioc_dc_timeout_id)
ioc->ioc_dc_timeout_id = 0;
#endif
break;
}
if (probe_done == B_TRUE) {
if (--ibdm.ibdm_ngid_probes_in_progress == 0) {
}
} else
}
/*
* ibdm_retry_command()
* Retries the failed command.
* Returns IBDM_FAILURE/IBDM_SUCCESS
*/
static int
{
int ioc_no;
/*
* Reset the gid if alloc_msg failed with BAD_HANDLE
* ibdm_reset_gidinfo reinits the gid_info
*/
if (ret == IBMF_BAD_HANDLE) {
gid_info);
/* Retry alloc */
&msg);
}
if (ret != IBDM_SUCCESS) {
return (IBDM_FAILURE);
}
if (gid_info->gl_redirect_dlid != 0) {
}
} else {
}
switch (cb_args->cb_req_type) {
hdr->AttributeModifier = 0;
break;
case IBDM_REQ_TYPE_IOUINFO:
hdr->AttributeModifier = 0;
break;
case IBDM_REQ_TYPE_IOCINFO:
break;
case IBDM_REQ_TYPE_SRVENTS:
(cb_args->cb_srvents_end))));
break;
hdr->AttributeModifier = 0;
break;
break;
}
cb_args, 0)) != IBMF_SUCCESS) {
rval = IBDM_FAILURE;
}
return (rval);
}
/*
* ibdm_update_ioc_port_gidlist()
*/
static void
{
}
while (gid_hca_head) {
}
}
/*
* ibdm_alloc_send_buffers()
* Allocates memory for the IBMF send buffer
*/
static void
{
IBDM_MAD_SIZE - sizeof (ib_mad_hdr_t);
}
/*
* ibdm_alloc_send_buffers()
* De-allocates memory for the IBMF send buffer
*/
static void
{
}
/*
* ibdm_probe_ioc()
* 1. Gets the node records for the port GUID. This detects all the port
* to the IOU.
* 2. Selectively probes all the IOC, given it's node GUID
* 3. In case of reprobe, only the IOC to be reprobed is send the IOC
* Controller Profile asynchronously
*/
/*ARGSUSED*/
static void
{
/* Rescan the GID list for any removed GIDs for reprobe */
if (reprobe_flag)
continue;
}
/*
* For reprobes: Check if GID, already in
* the list. If so, set the state to SKIPPED
*/
temp_gidinfo->gl_state ==
hca_list);
continue;
} else if (temp_gidinfo != NULL) {
hca_list);
continue;
}
"create_gid : prefix %llx, guid %llx\n",
dgid);
"create_gid_info failed\n");
continue;
}
} else {
IBTF_DPRINTF_L4("ibdm",
"\tprobe_ioc: new gid");
sizeof (ibdm_gid_t), KM_SLEEP);
}
/*
* Set the state to skipped as all these
* gids point to the same node.
* We (re)probe only one GID below and reset
* state appropriately
*/
}
}
"reprobe_gid %p new_gid %p node_gid %p",
int ioc_matched = 0;
niocs =
tmp_ioc =
continue;
ioc_matched = 1;
/*
* Explicitly set gl_reprobe_flag to 0 so that
* IBnex is not notified on completion
*/
reprobe_gid->gl_reprobe_flag = 0;
IBDM_SUCCESS) {
IBTF_DPRINTF_L4("ibdm",
"\tprobe_ioc: "
"send_ioc_profile failed "
"for ioc %d", jj);
break;
}
break;
}
if (ioc_matched == 0)
else {
break;
}
/*
* New or reinserted GID : Enable notification
* to IBnex
*/
} else {
"Invalid state!");
}
}
}
/*
* ibdm_probe_gid()
* Selectively probes the GID
*/
static void
{
return;
}
}
/*
* ibdm_create_gid_info()
* Allocates a gid_info structure and initializes
* Returns pointer to the structure on success
* and NULL on failure
*/
static ibdm_dp_gidinfo_t *
{
int ret;
npaths = 1;
/* query for reversible paths */
else
return (NULL);
sizeof (ibdm_dp_gidinfo_t), KM_SLEEP);
break;
break;
}
}
ibdm.ibdm_ngids++;
} else {
}
}
return (gid_info);
}
/*
* ibdm_get_node_records
* Sends a SA query to get the NODE record
* Returns pointer to the sa_node_record_t on success
* and NULL on failure
*/
static sa_node_record_t *
{
int ret;
if (ret != IBMF_SUCCESS) {
" SA Retrieve Failed: %d", ret);
return (NULL);
}
return (NULL);
}
return (resp);
}
/*
* ibdm_get_portinfo()
* Sends a SA query to get the PortInfo record
* Returns pointer to the sa_portinfo_record_t on success
* and NULL on failure
*/
static sa_portinfo_record_t *
{
int ret;
if (ret != IBMF_SUCCESS) {
" SA Retrieve Failed: 0x%X", ret);
return (NULL);
}
return (NULL);
return (resp);
}
/*
* ibdm_ibnex_register_callback
* IB nexus callback routine for HCA attach and detach notification
*/
void
{
}
/*
* ibdm_ibnex_unregister_callbacks
*/
void
{
}
/*
* ibdm_ibnex_get_waittime()
* Calculates the wait time based on the last HCA attach time
*/
{
int ii;
if (hca_guid) {
break;
}
}
return (wait_time);
}
}
}
return (wait_time);
}
/*
* ibdm_ibnex_probe_hcaport
* Probes the presence of HCA port (with HCA dip and port number)
* Returns port attributes structure on SUCCESS
*/
{
port_num) {
break;
}
}
break;
}
}
return (NULL);
}
sizeof (ibdm_port_attr_t), KM_SLEEP);
port_attr, sizeof (ibdm_port_attr_t));
return (port_attr);
}
/*
* ibdm_ibnex_get_port_attrs
* Scan all HCAs for a matching port_guid.
* Returns "port attributes" structure on success.
*/
{
port_guid) {
break;
}
}
break;
}
return (NULL);
}
KM_SLEEP);
sizeof (ibdm_port_attr_t));
return (port_attr);
}
/*
* ibdm_ibnex_free_port_attr()
*/
void
{
if (port_attr) {
}
}
}
/*
* ibdm_ibnex_get_hca_list()
* Returns portinfo for all the port for all the HCA's
*/
void
{
int ii;
}
}
/*
* ibdm_ibnex_get_hca_info_by_guid()
*/
{
while (head) {
break;
}
}
return (hca);
}
/*
* ibdm_dup_hca_attr()
* Allocate a new HCA attribute strucuture and initialize
* hca attribute structure with the incoming HCA attributes
* returned the allocated hca attributes.
*/
static ibdm_hca_list_t *
{
int len;
len = sizeof (ibdm_hca_list_t) +
(char *)out_hca, sizeof (ibdm_hca_list_t));
((char *)out_hca + sizeof (ibdm_hca_list_t));
(char *)out_hca->hl_port_attr,
}
return (out_hca);
}
/*
* ibdm_ibnex_free_hca_list()
*/
void
{
while (hca_list) {
if (len != 0)
}
sizeof (ibdm_port_attr_t));
}
}
/*
* ibdm_ibnex_probe_iocguid()
* Probes the IOC on the fabric and returns the IOC information
* if present. Otherwise, NULL is returned
*/
/* ARGSUSED */
{
int k;
/* Check whether we know this already */
} else if (reprobe_flag) { /* Handle Reprobe for the IOC */
/* Free the ioc_list before reprobe; and cancel any timers */
if (ioc_info->ioc_timeout_id) {
"ioc_timeout_id = 0x%x",
"untimeout ioc_timeout_id failed");
}
ioc_info->ioc_timeout_id = 0;
}
if (ioc_info->ioc_dc_timeout_id) {
"ioc_dc_timeout_id = 0x%x",
"untimeout ioc_dc_timeout_id failed");
}
ioc_info->ioc_dc_timeout_id = 0;
}
"ioc_info->ioc_serv[k].se_timeout_id = %x",
se_timeout_id) == -1) {
"untimeout se_timeout_id %d "
"failed", k);
}
}
/*
* Skip if gl_reprobe_flag is set, this will be
* a re-inserted / new GID, for which notifications
* have already been send.
*/
continue;
if (gid_info->gl_reprobe_flag) {
gid_info->gl_reprobe_flag = 0;
continue;
}
gid_info);
}
}
}
}
return (ioc_info);
}
/*
* ibdm_ibnex_get_ioc_info()
* Returns pointer to ibdm_ioc_info_t if it finds
* matching record for the ioc_guid, otherwise NULL
* is returned
*/
{
int ii;
while (gid_list) {
continue;
}
IBTF_DPRINTF_L2("ibdm",
"\tget_ioc_info: No IOU info");
continue;
}
return (ioc);
}
}
}
return (ioc);
}
/*
* ibdm_ibnex_get_ioc_count()
* Returns number of ibdm_ioc_info_t it finds
*/
int
ibdm_ibnex_get_ioc_count(void)
{
int count = 0, k;
continue;
}
k++) {
++count;
}
}
return (count);
}
/*
* ibdm_ibnex_get_ioc_list()
* Returns information about all the IOCs present on the fabric.
* Reprobes the IOCs and the GID list if list_flag is set to REPROBE_ALL.
* Does not sweep fabric if DONOT_PROBE is set
*/
{
int ii;
if (list_flag != IBDM_IBNEX_DONOT_PROBE)
while (gid_list) {
continue;
}
IBTF_DPRINTF_L2("ibdm",
"\tget_ioc_list: No IOU info");
continue;
}
}
}
}
return (ioc_list);
}
/*
* ibdm_dup_ioc_info()
* Duplicate the IOC information and return the IOC
* information.
*/
static ibdm_ioc_info_t *
{
return (out_ioc);
}
/*
* ibdm_free_ioc_list()
* Deallocate memory for IOC list structure
*/
void
{
while (ioc) {
if (temp->ioc_hca_list)
}
}
/*
* ibdm_ibnex_update_pkey_tbls
* Updates the DM P_Key database.
* NOTE: Two cases are handled here: P_Key being added or removed.
*
* Arguments : NONE
* Return Values : NONE
*/
void
{
for (h = 0; h < ibdm.ibdm_hca_count; h++) {
/* This updates P_Key Tables for all ports of this HCA */
/* number of ports shouldn't have changed */
/*
* First figure out the P_Keys from IBTL.
* Three things could have happened:
* New P_Keys added
* Existing P_Keys removed
* Both of the above two
*
* Loop through the P_Key Indices and check if a
* give P_Key_Ix matches that of the one seen by
* IBDM. If they match no action is needed.
*
* If they don't match:
* 1. if orig_pkey is invalid and new_pkey is valid
* ---> add new_pkey to DM database
* 2. if orig_pkey is valid and new_pkey is invalid
* ---> remove orig_pkey from DM database
* 3. if orig_pkey and new_pkey are both valid:
* ---> remov orig_pkey from DM database
* ---> add new_pkey to DM database
* 4. if orig_pkey and new_pkey are both invalid:
* ---> do nothing. Updated DM database.
*/
/* keys match - do nothing */
continue;
if (IBDM_INVALID_PKEY(*orig_pkey) &&
/* P_Key was added */
IBTF_DPRINTF_L5("ibdm",
"\tibnex_update_pkey_tbls: new "
"P_Key added = 0x%x", new_pkey);
} else if (!IBDM_INVALID_PKEY(*orig_pkey) &&
/* P_Key was removed */
IBTF_DPRINTF_L5("ibdm",
"\tibnex_update_pkey_tbls: P_Key "
"removed = 0x%x", *orig_pkey);
(void) ibdm_port_attr_ibmf_fini(port,
pidx);
} else if (!IBDM_INVALID_PKEY(*orig_pkey) &&
/* P_Key were replaced */
IBTF_DPRINTF_L5("ibdm",
"\tibnex_update_pkey_tbls: P_Key "
"replaced 0x%x with 0x%x",
(void) ibdm_port_attr_ibmf_fini(port,
pidx);
} else {
/*
* P_Keys are invalid
* set anyway to reflect if
* INVALID_FULL was changed to
* INVALID_LIMITED or vice-versa.
*/
} /* end of else */
} /* loop of p_key index */
} /* loop of #ports of HCA */
} /* loop for all HCAs in the system */
}
/*
* ibdm_send_ioc_profile()
* Send IOC Controller Profile request. When the request is completed
* IBMF calls ibdm_process_incoming_mad routine to inform about
* the completion.
*/
static int
{
/*
* Send command to get IOC profile.
* Allocate a IBMF packet and initialize the packet.
*/
&msg) != IBMF_SUCCESS) {
return (IBDM_FAILURE);
}
if (gid_info->gl_redirect_dlid != 0) {
}
} else {
}
IBTF_DPRINTF_L2("ibdm",
"\tsend_ioc_profile: msg transport failed");
}
return (IBDM_SUCCESS);
}
/*
* ibdm_port_reachable
* Sends a SA query to get the NODE record for port GUID
* Returns IBDM_SUCCESS if the port GID is reachable
*/
static int
{
int ret;
guid);
if (ret != IBMF_SUCCESS) {
" SA Retrieve Failed: %d", ret);
return (IBDM_FAILURE);
}
return (IBDM_FAILURE);
}
return (IBDM_SUCCESS);
}
/*
* Update the gidlist for all affected IOCs when GID becomes
*
* Parameters :
* gidinfo - Incoming / Outgoing GID.
* add_flag - 1 for GID added, 0 for GID removed.
* - (-1) : IOC gid list updated, ioc_list required.
*
* This function gets the GID for the node GUID corresponding to the
* port GID. Gets the IOU info
*/
static ibdm_ioc_info_t *
{
switch (avail_flag) {
case 1 :
break;
case 0 :
break;
case -1 :
break;
default :
break;
}
"No node GID found, port gid 0x%p, avail_flag %d",
return (NULL);
}
return (NULL);
}
niocs);
/*
* Skip IOCs for which probe is not complete or
* reprobe is progress
*/
}
}
ioc_list);
return (ioc_list);
}
/*
* ibdm_saa_event_cb :
* Event handling which does *not* require ibdm_hl_mutex to be
* held are executed in the same thread. This is to prevent
* deadlocks with HCA port down notifications which hold the
* ibdm_hl_mutex.
*
* GID_AVAILABLE event is handled here. A taskq is spawned to
* handle GID_UNAVAILABLE.
*
* A new mutex ibdm_ibnex_mutex has been introduced to protect
* ibnex_callback. This has been done to prevent any possible
* deadlock (described above) while handling GID_AVAILABLE.
*
* IBMF calls the event callback for a HCA port. The SA handle
* for this port would be valid, till the callback returns.
* IBDM calling IBDM using the above SA handle should be valid.
*
* IBDM will additionally check (SA handle != NULL), before
* calling IBMF.
*/
/*ARGSUSED*/
static void
{
#ifdef DEBUG
return;
#endif
if (ibmf_saa_event == IBMF_SAA_EVENT_GID_AVAILABLE) {
/*
* Ensure no other probe / sweep fabric is in
* progress.
*/
/*
* If we already know about this GID, return.
* GID_AVAILABLE may be reported for multiple HCA
* ports.
*/
return;
}
"Insertion notified",
/* This is a new gid, insert it to GID list */
"create_gid_info returned NULL");
return;
}
/* Get the node GUID */
&nodeguid) != IBDM_SUCCESS) {
/*
* Set the state to PROBE_NOT_DONE for the
* next sweep to probe it
*/
"Skipping GID : port GUID not found");
return;
}
/*
* Get the gid info with the same node GUID.
*/
while (node_gid_info) {
if (node_gid_info->gl_nodeguid ==
gid_info->gl_nodeguid &&
break;
}
}
/*
* Handling a new GID requires filling of gl_hca_list.
* This require ibdm hca_list to be parsed and hence
* holding the ibdm_hl_mutex. Spawning a new thread to
* handle this.
*/
if (node_gid_info == NULL) {
ibdm_saa_handle_new_gid, (void *)gid_info,
TQ_NOSLEEP) == NULL) {
"new_gid taskq_dispatch failed");
return;
}
}
return;
}
return;
sizeof (ibdm_saa_event_arg_t), KM_SLEEP);
sizeof (ibmf_saa_event_details_t));
"taskq_dispatch failed");
return;
}
}
/*
* Handle a new GID discovered by GID_AVAILABLE saa event.
*/
void
ibdm_saa_handle_new_gid(void *arg)
{
/*
* Ensure that no other sweep / probe has completed
* probing this gid.
*/
return;
}
/*
* Parse HCAs to fill gl_hca_list
*/
IBDM_SUCCESS) {
}
}
/*
* Ensure no other probe / sweep fabric is in
* progress.
*/
/*
* New IOU probe it, to check if new IOCs
*/
"new GID : probing");
gid_info->gl_reprobe_flag = 0;
ibdm_probe_gid_thread((void *)gid_info);
return;
}
/*
* Update GID list in all IOCs affected by this
*/
/*
* Pass on the IOCs with updated GIDs to IBnexus
*/
if (ioc_list) {
}
}
}
/*
* ibdm_saa_event_taskq :
* GID_UNAVAILABLE Event handling requires ibdm_hl_mutex to be
* held. The GID_UNAVAILABLE handling is done in a taskq to
* prevent deadlocks with HCA port down notifications which hold
* ibdm_hl_mutex.
*/
void
ibdm_saa_event_taskq(void *arg)
{
void *callback_arg;
int sa_handle_valid = 0;
/* Check if the port_attr is still valid */
hca_port->pa_port_guid) {
sa_handle_valid = 1;
break;
}
}
if (sa_handle_valid == 0) {
return;
}
return;
}
/*
* Check if the GID is visible to other HCA ports.
* Return if so.
*/
IBDM_SUCCESS) {
return;
}
}
/*
* Ensure no other probe / sweep fabric is in
* progress.
*/
/*
* If this GID is no longer in GID list, return
* GID_UNAVAILABLE may be reported for multiple HCA
* ports.
*/
while (gid_info) {
if (gid_info->gl_portguid ==
break;
}
}
return;
}
"Unavailable notification",
/*
* Update GID list in all IOCs affected by this
*/
/*
* Remove GID from the global GID list
* Handle the case where all port GIDs for an
* IOU have been hot-removed. Check both gid_info
* & ioc_info for checking ngids.
*/
(void) ibdm_free_iou_info(gid_info);
}
ibdm.ibdm_ngids--;
/*
* Pass on the IOCs with updated GIDs to IBnexus
*/
if (ioc_list) {
"IOC_PROP_UPDATE for %p\n", ioc_list);
(*ibdm.ibdm_ibnex_callback)((void *)
}
}
}
static int
{
int cmp_failed = 0;
/*
* Search for each new gid anywhere in the prev GID list.
* Note that the gid list could have been re-ordered.
*/
cmp_failed = 0;
break;
}
}
if (cmp_failed)
return (1);
}
return (0);
}
/*
* This is always called in a single thread
* This function updates the gid_list and serv_list of IOC
* The current gid_list is in ioc_info_t(contains only port
* guids for which probe is done) & gidinfo_t(other port gids)
* The gids in both locations are used for comparision.
*/
static void
{
/* Current GID list in gid_info only */
/*
* Service entry names and IDs are not compared currently.
* This may require change.
*/
}
/* Zero out previous entries */
if (ioc->ioc_prev_serv)
sizeof (ibdm_srvents_info_t));
ioc->ioc_prev_serv_cnt = 0;
ioc->ioc_prev_nportgids = 0;
}
/*
* Handle GID removal. This returns gid_info of an GID for the same
* node GUID, if found. For an GID with IOU information, the same
* gid_info is returned if no gid_info with same node_guid is found.
*/
static ibdm_dp_gidinfo_t *
{
/*
* Search for a GID with same node_guid and
* gl_iou != NULL
*/
== rm_gid->gl_nodeguid))
break;
}
if (gid_list)
return (gid_list);
} else {
/*
* Search for a GID with same node_guid and
* gl_iou == NULL
*/
== rm_gid->gl_nodeguid))
break;
}
if (gid_list) {
/*
* Copy the following fields from rm_gid :
* 1. gl_state
* 2. gl_iou
* 3. gl_gid & gl_ngids
*
* Note : Function is synchronized by
* ibdm_busy flag.
*
* Note : Redirect info is initialized if
* any MADs for the GID fail
*/
"copying info to GID with gl_iou != NULl");
/* Remove the GID from gl_gid list */
} else {
/*
* Handle a case where all GIDs to the IOU have
* been removed.
*/
"to IOU");
return (rm_gid);
}
return (gid_list);
}
}
static void
{
else
break;
} else {
}
}
}
static void
{
/* First copy the destination */
}
/* Insert this to the source */
else {
;
}
}
static void
{
}
}
/*
* This function rescans the DM capable GIDs (gl_state is
* GID_PROBE_COMPLETE or IBDM_GID_PROBING_SKIPPED.This
* basically checks if the DM capable GID is reachable. If
* not this is handled the same way as GID_UNAVAILABLE,
* except that notifications are not send to IBnexus.
*
* This function also initializes the ioc_prev_list for
* a particular IOC (when called from probe_ioc, with
* ioc_guidp != NULL) or all IOCs for the gid (called from
* sweep_fabric, ioc_guidp == NULL).
*/
static void
{
found = 0;
continue;
}
/*
* Check if the GID is visible to any HCA ports.
* Return if so.
*/
found = 1;
break;
}
}
if (found) {
continue;
}
/* Intialize the ioc_prev_gid_list */
niocs =
/* Add info of GIDs in gid_info also */
}
}
continue;
}
"deleted port GUID %llx",
/*
* Update GID list in all IOCs affected by this
*/
/*
* Remove GID from the global GID list
* Handle the case where all port GIDs for an
* IOU have been hot-removed.
*/
(void) ibdm_free_iou_info(gid_info);
}
ibdm.ibdm_ngids--;
/*
* Pass on the IOCs with updated GIDs to IBnexus
*/
if (ioc_list) {
"IOC_PROP_UPDATE for %p\n", ioc_list);
(*ibdm.ibdm_ibnex_callback)((void *)
}
}
}
}
/*
* This function notifies IBnex of IOCs on this GID.
* Notification is for GIDs with gl_reprobe_flag set.
* The flag is set when IOC probe / fabric sweep
* probes a GID starting from CLASS port info.
*
* IBnexus will have information of a reconnected IOC
* if it had probed it before. If this is a new IOC,
* IBnexus ignores the notification.
*
* This function should be called with no locks held.
*/
static void
{
if (gid_info->gl_reprobe_flag == 0 ||
return;
/*
* Pass on the IOCs with updated GIDs to IBnexus
*/
if (ioc_list) {
}
}
}
static void
{
}
/*
* This function parses the list of HCAs and HCA ports
* to return the port_attr of the next HCA port. A port
* connected to IB fabric (port_state active) is returned,
* if connected_flag is set.
*/
static void
{
int ii;
int found = 0;
/*
* inp_port != NULL;
* Skip till we find the matching port
*/
found = 1;
continue;
}
if (!connect_flag) {
break;
}
(void) ibdm_fini_port(port);
break;
}
}
if (next_port)
break;
}
}
static void
{
}
static void
{
"gid %p, gl_hca_list %p", gid_info,
return;
}
/* Check if already in the list */
while (head) {
"\taddto_glhcalist : gid %x hca %x dup",
return;
}
}
/* Add this HCA to gl_hca_list */
}
static void
{
if (gid_info->gl_hca_list)
}
static void
{
/* Check : Not busy in another probe / sweep */
/*
* Check if any GID is using the SA & IBMF handle
* of HCA port going down. Reset ibdm_dp_gidinfo_t
* using another HCA port which can reach the GID.
* This is for DM capable GIDs only, no need to do
* this for others
*
* Delete the GID if no alternate HCA port to reach
* it is found.
*/
"checking gidinfo %p", gid_info);
if (gid_info->gl_nodeguid != 0 &&
"\tevent_hdlr: down HCA port hdl "
"matches gid %p", gid_info);
if (gid_info->gl_disconnected) {
"\tevent_hdlr: deleting"
" gid %p", gid_info);
} else
} else
}
}
}
static void
{
int gid_reinited = 0;
/*
* Get list of all the ports reachable from the local known HCA
* ports which are active
*/
/*
* Get the path and re-populate the gidinfo.
* Getting the path is the same probe_ioc
* Init the gid info as in ibdm_create_gidinfo()
*/
"\treset_gidinfo : no records");
continue;
}
break;
}
"\treset_gidinfo : no record for portguid");
continue;
}
"\treset_gidinfo : no portinfo");
continue;
}
"\treset_gidinfo : no paths");
continue;
}
/* Reset redirect info, next MAD will set if redirected */
gidinfo->gl_redirected = 0;
gid_reinited = 1;
break;
}
if (!gid_reinited)
}
static void
{
/*
* Remove GID from the global GID list
* Handle the case where all port GIDs for an
* IOU have been hot-removed.
*/
(void) ibdm_free_iou_info(gidinfo);
}
ibdm.ibdm_ngids--;
/*
* Pass on the IOCs with updated GIDs to IBnexus
*/
if (ioc_list) {
"IOC_PROP_UPDATE for %p\n", ioc_list);
(*ibdm.ibdm_ibnex_callback)((void *)
}
}
}
/* For debugging purpose only */
#ifdef DEBUG
void
{
if (flag)
else
"\tR Method : 0x%x",
"\tTransaction ID : 0x%llx",
"\tAttribute Modified : 0x%x",
}
void
{
}
void
{
}
void
{
iou_info->iou_ctrl_list[0]);
}
void
{
}
void
{
IBTF_DPRINTF_L4("ibdm",
}
int ibdm_allow_sweep_fabric_timestamp = 1;
void
{
static hrtime_t x;
if (flag) {
}
x = 0;
} else
x = gethrtime();
}
#endif