Home | History | Annotate | Download | only in ibdm
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 /*
     27  * ibdm.c
     28  *
     29  * This file contains the InifiniBand Device Manager (IBDM) support functions.
     30  * IB nexus driver will only be the client for the IBDM module.
     31  *
     32  * IBDM registers with IBTF for HCA arrival/removal notification.
     33  * IBDM registers with SA access to send DM MADs to discover the IOC's behind
     34  * the IOU's.
     35  *
     36  * IB nexus driver registers with IBDM to find the information about the
     37  * HCA's and IOC's (behind the IOU) present on the IB fabric.
     38  */
     39 
     40 #include <sys/systm.h>
     41 #include <sys/taskq.h>
     42 #include <sys/ib/mgt/ibdm/ibdm_impl.h>
     43 #include <sys/ib/mgt/ibmf/ibmf_impl.h>
     44 #include <sys/ib/ibtl/impl/ibtl_ibnex.h>
     45 #include <sys/modctl.h>
     46 
     47 /* Function Prototype declarations */
     48 static int	ibdm_free_iou_info(ibdm_dp_gidinfo_t *, ibdm_iou_info_t **);
     49 static int	ibdm_fini(void);
     50 static int	ibdm_init(void);
     51 static int	ibdm_get_reachable_ports(ibdm_port_attr_t *,
     52 			ibdm_hca_list_t *);
     53 static ibdm_dp_gidinfo_t *ibdm_check_dgid(ib_guid_t, ib_sn_prefix_t);
     54 static ibdm_dp_gidinfo_t *ibdm_check_dest_nodeguid(ibdm_dp_gidinfo_t *);
     55 static boolean_t ibdm_is_cisco(ib_guid_t);
     56 static boolean_t ibdm_is_cisco_switch(ibdm_dp_gidinfo_t *);
     57 static void	ibdm_wait_cisco_probe_completion(ibdm_dp_gidinfo_t *);
     58 static int	ibdm_set_classportinfo(ibdm_dp_gidinfo_t *);
     59 static int	ibdm_send_classportinfo(ibdm_dp_gidinfo_t *);
     60 static int	ibdm_send_iounitinfo(ibdm_dp_gidinfo_t *);
     61 static int	ibdm_is_dev_mgt_supported(ibdm_dp_gidinfo_t *);
     62 static int	ibdm_get_node_port_guids(ibmf_saa_handle_t, ib_lid_t,
     63 		    ib_guid_t *, ib_guid_t *);
     64 static int	ibdm_retry_command(ibdm_timeout_cb_args_t *);
     65 static int	ibdm_get_diagcode(ibdm_dp_gidinfo_t *, int);
     66 static int	ibdm_verify_mad_status(ib_mad_hdr_t *);
     67 static int	ibdm_handle_redirection(ibmf_msg_t *,
     68 		    ibdm_dp_gidinfo_t *, int *);
     69 static void	ibdm_wait_probe_completion(void);
     70 static void	ibdm_sweep_fabric(int);
     71 static void	ibdm_probe_gid_thread(void *);
     72 static void	ibdm_wakeup_probe_gid_cv(void);
     73 static void	ibdm_port_attr_ibmf_init(ibdm_port_attr_t *, ib_pkey_t, int);
     74 static int	ibdm_port_attr_ibmf_fini(ibdm_port_attr_t *, int);
     75 static void	ibdm_update_port_attr(ibdm_port_attr_t *);
     76 static void	ibdm_handle_hca_attach(ib_guid_t);
     77 static void	ibdm_handle_srventry_mad(ibmf_msg_t *,
     78 		    ibdm_dp_gidinfo_t *, int *);
     79 static void	ibdm_ibmf_recv_cb(ibmf_handle_t, ibmf_msg_t *, void *);
     80 static void	ibdm_recv_incoming_mad(void *);
     81 static void	ibdm_process_incoming_mad(ibmf_handle_t, ibmf_msg_t *, void *);
     82 static void	ibdm_ibmf_send_cb(ibmf_handle_t, ibmf_msg_t *, void *);
     83 static void	ibdm_pkt_timeout_hdlr(void *arg);
     84 static void	ibdm_initialize_port(ibdm_port_attr_t *);
     85 static void	ibdm_update_port_pkeys(ibdm_port_attr_t *port);
     86 static void	ibdm_handle_diagcode(ibmf_msg_t *, ibdm_dp_gidinfo_t *, int *);
     87 static void	ibdm_probe_gid(ibdm_dp_gidinfo_t *);
     88 static void	ibdm_alloc_send_buffers(ibmf_msg_t *);
     89 static void	ibdm_free_send_buffers(ibmf_msg_t *);
     90 static void	ibdm_handle_hca_detach(ib_guid_t);
     91 static void	ibdm_handle_port_change_event(ibt_async_event_t *);
     92 static int	ibdm_fini_port(ibdm_port_attr_t *);
     93 static int	ibdm_uninit_hca(ibdm_hca_list_t *);
     94 static void	ibdm_handle_setclassportinfo(ibmf_handle_t, ibmf_msg_t *,
     95 		    ibdm_dp_gidinfo_t *, int *);
     96 static void	ibdm_handle_iounitinfo(ibmf_handle_t,
     97 		    ibmf_msg_t *, ibdm_dp_gidinfo_t *, int *);
     98 static void	ibdm_handle_ioc_profile(ibmf_handle_t,
     99 		    ibmf_msg_t *, ibdm_dp_gidinfo_t *, int *);
    100 static void	ibdm_event_hdlr(void *, ibt_hca_hdl_t,
    101 		    ibt_async_code_t, ibt_async_event_t *);
    102 static void	ibdm_handle_classportinfo(ibmf_handle_t,
    103 		    ibmf_msg_t *, ibdm_dp_gidinfo_t *, int *);
    104 static void	ibdm_update_ioc_port_gidlist(ibdm_ioc_info_t *,
    105 		    ibdm_dp_gidinfo_t *);
    106 
    107 static ibdm_hca_list_t		*ibdm_dup_hca_attr(ibdm_hca_list_t *);
    108 static ibdm_ioc_info_t		*ibdm_dup_ioc_info(ibdm_ioc_info_t *,
    109 				    ibdm_dp_gidinfo_t *gid_list);
    110 static void			ibdm_probe_ioc(ib_guid_t, ib_guid_t, int);
    111 static ibdm_ioc_info_t		*ibdm_is_ioc_present(ib_guid_t,
    112 				    ibdm_dp_gidinfo_t *, int *);
    113 static ibdm_port_attr_t		*ibdm_get_port_attr(ibt_async_event_t *,
    114 				    ibdm_hca_list_t **);
    115 static sa_node_record_t		*ibdm_get_node_records(ibmf_saa_handle_t,
    116 				    size_t *, ib_guid_t);
    117 static int			ibdm_get_node_record_by_port(ibmf_saa_handle_t,
    118 				    ib_guid_t, sa_node_record_t **, size_t *);
    119 static sa_portinfo_record_t	*ibdm_get_portinfo(ibmf_saa_handle_t, size_t *,
    120 				    ib_lid_t);
    121 static ibdm_dp_gidinfo_t	*ibdm_create_gid_info(ibdm_port_attr_t *,
    122 				    ib_gid_t, ib_gid_t);
    123 static ibdm_dp_gidinfo_t	*ibdm_find_gid(ib_guid_t, ib_guid_t);
    124 static int	ibdm_send_ioc_profile(ibdm_dp_gidinfo_t *, uint8_t);
    125 static ibdm_ioc_info_t	*ibdm_update_ioc_gidlist(ibdm_dp_gidinfo_t *, int);
    126 static void	ibdm_saa_event_cb(ibmf_saa_handle_t, ibmf_saa_subnet_event_t,
    127 		    ibmf_saa_event_details_t *, void *);
    128 static void	ibdm_reprobe_update_port_srv(ibdm_ioc_info_t *,
    129     ibdm_dp_gidinfo_t *);
    130 static ibdm_dp_gidinfo_t *ibdm_handle_gid_rm(ibdm_dp_gidinfo_t *);
    131 static void ibdm_rmfrom_glgid_list(ibdm_dp_gidinfo_t *,
    132     ibdm_dp_gidinfo_t *);
    133 static void ibdm_addto_gidlist(ibdm_gid_t **, ibdm_gid_t *);
    134 static void ibdm_free_gid_list(ibdm_gid_t *);
    135 static void ibdm_rescan_gidlist(ib_guid_t *ioc_guid);
    136 static void ibdm_notify_newgid_iocs(ibdm_dp_gidinfo_t *);
    137 static void ibdm_saa_event_taskq(void *);
    138 static void ibdm_free_saa_event_arg(ibdm_saa_event_arg_t *);
    139 static void ibdm_get_next_port(ibdm_hca_list_t **,
    140     ibdm_port_attr_t **, int);
    141 static void ibdm_add_to_gl_gid(ibdm_dp_gidinfo_t *,
    142     ibdm_dp_gidinfo_t *);
    143 static void ibdm_addto_glhcalist(ibdm_dp_gidinfo_t *,
    144     ibdm_hca_list_t *);
    145 static void ibdm_delete_glhca_list(ibdm_dp_gidinfo_t *);
    146 static void ibdm_saa_handle_new_gid(void *);
    147 static void ibdm_reset_all_dgids(ibmf_saa_handle_t);
    148 static void ibdm_reset_gidinfo(ibdm_dp_gidinfo_t *);
    149 static void ibdm_delete_gidinfo(ibdm_dp_gidinfo_t *);
    150 static void ibdm_fill_srv_attr_mod(ib_mad_hdr_t *, ibdm_timeout_cb_args_t *);
    151 static void ibdm_bump_transactionID(ibdm_dp_gidinfo_t *);
    152 static ibdm_ioc_info_t	*ibdm_handle_prev_iou();
    153 static int ibdm_serv_cmp(ibdm_srvents_info_t *, ibdm_srvents_info_t *,
    154     int);
    155 static ibdm_ioc_info_t *ibdm_get_ioc_info_with_gid(ib_guid_t,
    156     ibdm_dp_gidinfo_t **);
    157 
    158 int	ibdm_dft_timeout	= IBDM_DFT_TIMEOUT;
    159 int	ibdm_dft_retry_cnt	= IBDM_DFT_NRETRIES;
    160 #ifdef DEBUG
    161 int	ibdm_ignore_saa_event = 0;
    162 #endif
    163 
    164 /* Modload support */
    165 static struct modlmisc ibdm_modlmisc	= {
    166 	&mod_miscops,
    167 	"InfiniBand Device Manager"
    168 };
    169 
    170 struct modlinkage ibdm_modlinkage = {
    171 	MODREV_1,
    172 	(void *)&ibdm_modlmisc,
    173 	NULL
    174 };
    175 
    176 static ibt_clnt_modinfo_t ibdm_ibt_modinfo = {
    177 	IBTI_V_CURR,
    178 	IBT_DM,
    179 	ibdm_event_hdlr,
    180 	NULL,
    181 	"ibdm"
    182 };
    183 
    184 /* Global variables */
    185 ibdm_t	ibdm;
    186 int	ibdm_taskq_enable = IBDM_ENABLE_TASKQ_HANDLING;
    187 char	*ibdm_string = "ibdm";
    188 
    189 _NOTE(SCHEME_PROTECTS_DATA("Serialized access by cv",
    190     ibdm.ibdm_dp_gidlist_head))
    191 
    192 /*
    193  * _init
    194  *	Loadable module init, called before any other module.
    195  *	Initialize mutex
    196  *	Register with IBTF
    197  */
    198 int
    199 _init(void)
    200 {
    201 	int		err;
    202 
    203 	IBTF_DPRINTF_L4("ibdm", "\t_init: addr of ibdm %p", &ibdm);
    204 
    205 	if ((err = ibdm_init()) != IBDM_SUCCESS) {
    206 		IBTF_DPRINTF_L2("ibdm", "_init: ibdm_init failed 0x%x", err);
    207 		(void) ibdm_fini();
    208 		return (DDI_FAILURE);
    209 	}
    210 
    211 	if ((err = mod_install(&ibdm_modlinkage)) != 0) {
    212 		IBTF_DPRINTF_L2("ibdm", "_init: mod_install failed 0x%x", err);
    213 		(void) ibdm_fini();
    214 	}
    215 	return (err);
    216 }
    217 
    218 
    219 int
    220 _fini(void)
    221 {
    222 	int err;
    223 
    224 	if ((err = ibdm_fini()) != IBDM_SUCCESS) {
    225 		IBTF_DPRINTF_L2("ibdm", "_fini: ibdm_fini failed 0x%x", err);
    226 		(void) ibdm_init();
    227 		return (EBUSY);
    228 	}
    229 
    230 	if ((err = mod_remove(&ibdm_modlinkage)) != 0) {
    231 		IBTF_DPRINTF_L2("ibdm", "_fini: mod_remove failed 0x%x", err);
    232 		(void) ibdm_init();
    233 	}
    234 	return (err);
    235 }
    236 
    237 
    238 int
    239 _info(struct modinfo *modinfop)
    240 {
    241 	return (mod_info(&ibdm_modlinkage, modinfop));
    242 }
    243 
    244 
    245 /*
    246  * ibdm_init():
    247  * 	Register with IBTF
    248  *	Allocate memory for the HCAs
    249  *	Allocate minor-nodes for the HCAs
    250  */
    251 static int
    252 ibdm_init(void)
    253 {
    254 	int			i, hca_count;
    255 	ib_guid_t		*hca_guids;
    256 	ibt_status_t		status;
    257 
    258 	IBTF_DPRINTF_L4("ibdm", "\tibdm_init:");
    259 	if (!(ibdm.ibdm_state & IBDM_LOCKS_ALLOCED)) {
    260 		mutex_init(&ibdm.ibdm_mutex, NULL, MUTEX_DEFAULT, NULL);
    261 		mutex_init(&ibdm.ibdm_hl_mutex, NULL, MUTEX_DEFAULT, NULL);
    262 		mutex_init(&ibdm.ibdm_ibnex_mutex, NULL, MUTEX_DEFAULT, NULL);
    263 		cv_init(&ibdm.ibdm_port_settle_cv, NULL, CV_DRIVER, NULL);
    264 		mutex_enter(&ibdm.ibdm_mutex);
    265 		ibdm.ibdm_state |= IBDM_LOCKS_ALLOCED;
    266 	}
    267 
    268 	if (!(ibdm.ibdm_state & IBDM_IBT_ATTACHED)) {
    269 		if ((status = ibt_attach(&ibdm_ibt_modinfo, NULL, NULL,
    270 		    (void *)&ibdm.ibdm_ibt_clnt_hdl)) != IBT_SUCCESS) {
    271 			IBTF_DPRINTF_L2("ibdm", "ibdm_init: ibt_attach "
    272 			    "failed %x", status);
    273 			mutex_exit(&ibdm.ibdm_mutex);
    274 			return (IBDM_FAILURE);
    275 		}
    276 
    277 		ibdm.ibdm_state |= IBDM_IBT_ATTACHED;
    278 		mutex_exit(&ibdm.ibdm_mutex);
    279 	}
    280 
    281 
    282 	if (!(ibdm.ibdm_state & IBDM_HCA_ATTACHED)) {
    283 		hca_count = ibt_get_hca_list(&hca_guids);
    284 		IBTF_DPRINTF_L4("ibdm", "ibdm_init: num_hcas = %d", hca_count);
    285 		for (i = 0; i < hca_count; i++)
    286 			(void) ibdm_handle_hca_attach(hca_guids[i]);
    287 		if (hca_count)
    288 			ibt_free_hca_list(hca_guids, hca_count);
    289 
    290 		mutex_enter(&ibdm.ibdm_mutex);
    291 		ibdm.ibdm_state |= IBDM_HCA_ATTACHED;
    292 		mutex_exit(&ibdm.ibdm_mutex);
    293 	}
    294 
    295 	if (!(ibdm.ibdm_state & IBDM_CVS_ALLOCED)) {
    296 		cv_init(&ibdm.ibdm_probe_cv, NULL, CV_DRIVER, NULL);
    297 		cv_init(&ibdm.ibdm_busy_cv, NULL, CV_DRIVER, NULL);
    298 		mutex_enter(&ibdm.ibdm_mutex);
    299 		ibdm.ibdm_state |= IBDM_CVS_ALLOCED;
    300 		mutex_exit(&ibdm.ibdm_mutex);
    301 	}
    302 	return (IBDM_SUCCESS);
    303 }
    304 
    305 
    306 static int
    307 ibdm_free_iou_info(ibdm_dp_gidinfo_t *gid_info, ibdm_iou_info_t **ioup)
    308 {
    309 	int			ii, k, niocs;
    310 	size_t			size;
    311 	ibdm_gid_t		*delete, *head;
    312 	timeout_id_t		timeout_id;
    313 	ibdm_ioc_info_t		*ioc;
    314 	ibdm_iou_info_t		*gl_iou = *ioup;
    315 
    316 	ASSERT(mutex_owned(&gid_info->gl_mutex));
    317 	if (gl_iou == NULL) {
    318 		IBTF_DPRINTF_L4("ibdm", "\tibdm_free_iou_info: No IOU");
    319 		return (0);
    320 	}
    321 
    322 	niocs = gl_iou->iou_info.iou_num_ctrl_slots;
    323 	IBTF_DPRINTF_L4("ibdm", "\tfree_iou_info: gid_info = %p, niocs %d",
    324 	    gid_info, niocs);
    325 
    326 	for (ii = 0; ii < niocs; ii++) {
    327 		ioc = (ibdm_ioc_info_t *)&gl_iou->iou_ioc_info[ii];
    328 
    329 		/* handle the case where an ioc_timeout_id is scheduled */
    330 		if (ioc->ioc_timeout_id) {
    331 			timeout_id = ioc->ioc_timeout_id;
    332 			ioc->ioc_timeout_id = 0;
    333 			mutex_exit(&gid_info->gl_mutex);
    334 			IBTF_DPRINTF_L5("ibdm", "free_iou_info: "
    335 			    "ioc_timeout_id = 0x%x", timeout_id);
    336 			if (untimeout(timeout_id) == -1) {
    337 				IBTF_DPRINTF_L2("ibdm", "free_iou_info: "
    338 				    "untimeout ioc_timeout_id failed");
    339 				mutex_enter(&gid_info->gl_mutex);
    340 				return (-1);
    341 			}
    342 			mutex_enter(&gid_info->gl_mutex);
    343 		}
    344 
    345 		/* handle the case where an ioc_dc_timeout_id is scheduled */
    346 		if (ioc->ioc_dc_timeout_id) {
    347 			timeout_id = ioc->ioc_dc_timeout_id;
    348 			ioc->ioc_dc_timeout_id = 0;
    349 			mutex_exit(&gid_info->gl_mutex);
    350 			IBTF_DPRINTF_L5("ibdm", "free_iou_info: "
    351 			    "ioc_dc_timeout_id = 0x%x", timeout_id);
    352 			if (untimeout(timeout_id) == -1) {
    353 				IBTF_DPRINTF_L2("ibdm", "free_iou_info: "
    354 				    "untimeout ioc_dc_timeout_id failed");
    355 				mutex_enter(&gid_info->gl_mutex);
    356 				return (-1);
    357 			}
    358 			mutex_enter(&gid_info->gl_mutex);
    359 		}
    360 
    361 		/* handle the case where serv[k].se_timeout_id is scheduled */
    362 		for (k = 0; k < ioc->ioc_profile.ioc_service_entries; k++) {
    363 			if (ioc->ioc_serv[k].se_timeout_id) {
    364 				timeout_id = ioc->ioc_serv[k].se_timeout_id;
    365 				ioc->ioc_serv[k].se_timeout_id = 0;
    366 				mutex_exit(&gid_info->gl_mutex);
    367 				IBTF_DPRINTF_L5("ibdm", "free_iou_info: "
    368 				    "ioc->ioc_serv[%d].se_timeout_id = 0x%x",
    369 				    k, timeout_id);
    370 				if (untimeout(timeout_id) == -1) {
    371 					IBTF_DPRINTF_L2("ibdm", "free_iou_info:"
    372 					    " untimeout se_timeout_id failed");
    373 					mutex_enter(&gid_info->gl_mutex);
    374 					return (-1);
    375 				}
    376 				mutex_enter(&gid_info->gl_mutex);
    377 			}
    378 		}
    379 
    380 		/* delete GID list in IOC */
    381 		head = ioc->ioc_gid_list;
    382 		while (head) {
    383 			IBTF_DPRINTF_L4("ibdm", "\tibdm_free_iou_info: "
    384 			    "Deleting gid_list struct %p", head);
    385 			delete = head;
    386 			head = head->gid_next;
    387 			kmem_free(delete, sizeof (ibdm_gid_t));
    388 		}
    389 		ioc->ioc_gid_list = NULL;
    390 
    391 		/* delete ioc_serv */
    392 		size = ioc->ioc_profile.ioc_service_entries *
    393 		    sizeof (ibdm_srvents_info_t);
    394 		if (ioc->ioc_serv && size) {
    395 			kmem_free(ioc->ioc_serv, size);
    396 			ioc->ioc_serv = NULL;
    397 		}
    398 	}
    399 	/*
    400 	 * Clear the IBDM_CISCO_PROBE_DONE flag to get the IO Unit information
    401 	 * via the switch during the probe process.
    402 	 */
    403 	gid_info->gl_flag &= ~IBDM_CISCO_PROBE_DONE;
    404 
    405 	IBTF_DPRINTF_L4("ibdm", "\tibdm_free_iou_info: deleting IOU & IOC");
    406 	size = sizeof (ibdm_iou_info_t) + niocs * sizeof (ibdm_ioc_info_t);
    407 	kmem_free(gl_iou, size);
    408 	*ioup = NULL;
    409 	return (0);
    410 }
    411 
    412 
    413 /*
    414  * ibdm_fini():
    415  * 	Un-register with IBTF
    416  *	De allocate memory for the GID info
    417  */
    418 static int
    419 ibdm_fini()
    420 {
    421 	int			ii;
    422 	ibdm_hca_list_t		*hca_list, *temp;
    423 	ibdm_dp_gidinfo_t	*gid_info, *tmp;
    424 	ibdm_gid_t		*head, *delete;
    425 
    426 	IBTF_DPRINTF_L4("ibdm", "\tibdm_fini");
    427 
    428 	mutex_enter(&ibdm.ibdm_hl_mutex);
    429 	if (ibdm.ibdm_state & IBDM_IBT_ATTACHED) {
    430 		if (ibt_detach(ibdm.ibdm_ibt_clnt_hdl) != IBT_SUCCESS) {
    431 			IBTF_DPRINTF_L2("ibdm", "\t_fini: ibt_detach failed");
    432 			mutex_exit(&ibdm.ibdm_hl_mutex);
    433 			return (IBDM_FAILURE);
    434 		}
    435 		ibdm.ibdm_state &= ~IBDM_IBT_ATTACHED;
    436 		ibdm.ibdm_ibt_clnt_hdl = NULL;
    437 	}
    438 
    439 	hca_list = ibdm.ibdm_hca_list_head;
    440 	IBTF_DPRINTF_L4("ibdm", "\tibdm_fini: nhcas %d", ibdm.ibdm_hca_count);
    441 	for (ii = 0; ii < ibdm.ibdm_hca_count; ii++) {
    442 		temp = hca_list;
    443 		hca_list = hca_list->hl_next;
    444 		IBTF_DPRINTF_L4("ibdm", "\tibdm_fini: hca %p", temp);
    445 		if (ibdm_uninit_hca(temp) != IBDM_SUCCESS) {
    446 			IBTF_DPRINTF_L2("ibdm", "\tibdm_fini: "
    447 			    "uninit_hca %p failed", temp);
    448 			mutex_exit(&ibdm.ibdm_hl_mutex);
    449 			return (IBDM_FAILURE);
    450 		}
    451 	}
    452 	mutex_exit(&ibdm.ibdm_hl_mutex);
    453 
    454 	mutex_enter(&ibdm.ibdm_mutex);
    455 	if (ibdm.ibdm_state & IBDM_HCA_ATTACHED)
    456 		ibdm.ibdm_state &= ~IBDM_HCA_ATTACHED;
    457 
    458 	gid_info = ibdm.ibdm_dp_gidlist_head;
    459 	while (gid_info) {
    460 		mutex_enter(&gid_info->gl_mutex);
    461 		(void) ibdm_free_iou_info(gid_info, &gid_info->gl_iou);
    462 		mutex_exit(&gid_info->gl_mutex);
    463 		ibdm_delete_glhca_list(gid_info);
    464 
    465 		tmp = gid_info;
    466 		gid_info = gid_info->gl_next;
    467 		mutex_destroy(&tmp->gl_mutex);
    468 		head = tmp->gl_gid;
    469 		while (head) {
    470 			IBTF_DPRINTF_L4("ibdm",
    471 			    "\tibdm_fini: Deleting gid structs");
    472 			delete = head;
    473 			head = head->gid_next;
    474 			kmem_free(delete, sizeof (ibdm_gid_t));
    475 		}
    476 		kmem_free(tmp, sizeof (ibdm_dp_gidinfo_t));
    477 	}
    478 	mutex_exit(&ibdm.ibdm_mutex);
    479 
    480 	if (ibdm.ibdm_state & IBDM_LOCKS_ALLOCED) {
    481 		ibdm.ibdm_state &= ~IBDM_LOCKS_ALLOCED;
    482 		mutex_destroy(&ibdm.ibdm_mutex);
    483 		mutex_destroy(&ibdm.ibdm_hl_mutex);
    484 		mutex_destroy(&ibdm.ibdm_ibnex_mutex);
    485 		cv_destroy(&ibdm.ibdm_port_settle_cv);
    486 	}
    487 	if (ibdm.ibdm_state & IBDM_CVS_ALLOCED) {
    488 		ibdm.ibdm_state &= ~IBDM_CVS_ALLOCED;
    489 		cv_destroy(&ibdm.ibdm_probe_cv);
    490 		cv_destroy(&ibdm.ibdm_busy_cv);
    491 	}
    492 	return (IBDM_SUCCESS);
    493 }
    494 
    495 
    496 /*
    497  * ibdm_event_hdlr()
    498  *
    499  *	IBDM registers  this asynchronous event handler at the time of
    500  *	ibt_attach. IBDM support the following async events. For other
    501  *	event, simply returns success.
    502  *	IBT_HCA_ATTACH_EVENT:
    503  *		Retrieves the  information about all the port that are
    504  *		present on this HCA,  allocates  the  port  attributes
    505  *		structure  and calls IB  nexus  callback  routine with
    506  *		the port attributes structure as an input argument.
    507  *	IBT_HCA_DETACH_EVENT:
    508  *		Retrieves the information about all the ports that are
    509  *		present on  this HCA and  calls IB nexus callback with
    510  *		port guid as an argument
    511  *	IBT_EVENT_PORT_UP:
    512  *		Register with IBMF and SA access
    513  *		Setup IBMF receive callback routine
    514  *	IBT_EVENT_PORT_DOWN:
    515  *		Un-Register with IBMF and SA access
    516  *		Teardown IBMF receive callback routine
    517  */
    518 /*ARGSUSED*/
    519 static void
    520 ibdm_event_hdlr(void *clnt_hdl,
    521     ibt_hca_hdl_t hca_hdl, ibt_async_code_t code, ibt_async_event_t *event)
    522 {
    523 	ibdm_hca_list_t		*hca_list;
    524 	ibdm_port_attr_t	*port;
    525 	ibmf_saa_handle_t	port_sa_hdl;
    526 
    527 	IBTF_DPRINTF_L4("ibdm", "\tevent_hdlr: async code 0x%x", code);
    528 
    529 	switch (code) {
    530 	case IBT_HCA_ATTACH_EVENT:	/* New HCA registered with IBTF */
    531 		ibdm_handle_hca_attach(event->ev_hca_guid);
    532 		break;
    533 
    534 	case IBT_HCA_DETACH_EVENT:	/* HCA unregistered with IBTF */
    535 		ibdm_handle_hca_detach(event->ev_hca_guid);
    536 		mutex_enter(&ibdm.ibdm_ibnex_mutex);
    537 		if (ibdm.ibdm_ibnex_callback != NULL) {
    538 			(*ibdm.ibdm_ibnex_callback)((void *)
    539 			    &event->ev_hca_guid, IBDM_EVENT_HCA_REMOVED);
    540 		}
    541 		mutex_exit(&ibdm.ibdm_ibnex_mutex);
    542 		break;
    543 
    544 	case IBT_EVENT_PORT_UP:
    545 		IBTF_DPRINTF_L4("ibdm", "\tevent_hdlr: PORT_UP");
    546 		mutex_enter(&ibdm.ibdm_hl_mutex);
    547 		port = ibdm_get_port_attr(event, &hca_list);
    548 		if (port == NULL) {
    549 			IBTF_DPRINTF_L2("ibdm",
    550 			    "\tevent_hdlr: HCA not present");
    551 			mutex_exit(&ibdm.ibdm_hl_mutex);
    552 			break;
    553 		}
    554 		ibdm_initialize_port(port);
    555 		hca_list->hl_nports_active++;
    556 		cv_broadcast(&ibdm.ibdm_port_settle_cv);
    557 		mutex_exit(&ibdm.ibdm_hl_mutex);
    558 
    559 		/* Inform IB nexus driver */
    560 		mutex_enter(&ibdm.ibdm_ibnex_mutex);
    561 		if (ibdm.ibdm_ibnex_callback != NULL) {
    562 			(*ibdm.ibdm_ibnex_callback)((void *)
    563 			    &event->ev_hca_guid, IBDM_EVENT_PORT_UP);
    564 		}
    565 		mutex_exit(&ibdm.ibdm_ibnex_mutex);
    566 		break;
    567 
    568 	case IBT_ERROR_PORT_DOWN:
    569 		IBTF_DPRINTF_L4("ibdm", "\tevent_hdlr: PORT_DOWN");
    570 		mutex_enter(&ibdm.ibdm_hl_mutex);
    571 		port = ibdm_get_port_attr(event, &hca_list);
    572 		if (port == NULL) {
    573 			IBTF_DPRINTF_L2("ibdm",
    574 			    "\tevent_hdlr: HCA not present");
    575 			mutex_exit(&ibdm.ibdm_hl_mutex);
    576 			break;
    577 		}
    578 		hca_list->hl_nports_active--;
    579 		port_sa_hdl = port->pa_sa_hdl;
    580 		(void) ibdm_fini_port(port);
    581 		port->pa_state = IBT_PORT_DOWN;
    582 		cv_broadcast(&ibdm.ibdm_port_settle_cv);
    583 		mutex_exit(&ibdm.ibdm_hl_mutex);
    584 		ibdm_reset_all_dgids(port_sa_hdl);
    585 		break;
    586 
    587 	case IBT_PORT_CHANGE_EVENT:
    588 		IBTF_DPRINTF_L4("ibdm", "\tevent_hdlr: PORT_CHANGE");
    589 		if (event->ev_port_flags & IBT_PORT_CHANGE_PKEY)
    590 			ibdm_handle_port_change_event(event);
    591 		break;
    592 
    593 	default:		/* Ignore all other events/errors */
    594 		break;
    595 	}
    596 }
    597 
    598 static void
    599 ibdm_handle_port_change_event(ibt_async_event_t *event)
    600 {
    601 	ibdm_port_attr_t	*port;
    602 	ibdm_hca_list_t		*hca_list;
    603 
    604 	IBTF_DPRINTF_L2("ibdm", "\tibdm_handle_port_change_event:"
    605 	    " HCA guid  %llx", event->ev_hca_guid);
    606 	mutex_enter(&ibdm.ibdm_hl_mutex);
    607 	port = ibdm_get_port_attr(event, &hca_list);
    608 	if (port == NULL) {
    609 		IBTF_DPRINTF_L2("ibdm", "\tevent_hdlr: HCA not present");
    610 		mutex_exit(&ibdm.ibdm_hl_mutex);
    611 		return;
    612 	}
    613 	ibdm_update_port_pkeys(port);
    614 	cv_broadcast(&ibdm.ibdm_port_settle_cv);
    615 	mutex_exit(&ibdm.ibdm_hl_mutex);
    616 
    617 	/* Inform IB nexus driver */
    618 	mutex_enter(&ibdm.ibdm_ibnex_mutex);
    619 	if (ibdm.ibdm_ibnex_callback != NULL) {
    620 		(*ibdm.ibdm_ibnex_callback)((void *)
    621 		    &event->ev_hca_guid, IBDM_EVENT_PORT_PKEY_CHANGE);
    622 	}
    623 	mutex_exit(&ibdm.ibdm_ibnex_mutex);
    624 }
    625 
    626 /*
    627  * ibdm_update_port_pkeys()
    628  *	Update the pkey table
    629  *	Update the port attributes
    630  */
    631 static void
    632 ibdm_update_port_pkeys(ibdm_port_attr_t *port)
    633 {
    634 	uint_t				nports, size;
    635 	uint_t				pkey_idx, opkey_idx;
    636 	uint16_t			npkeys;
    637 	ibt_hca_portinfo_t		*pinfop;
    638 	ib_pkey_t			pkey;
    639 	ibdm_pkey_tbl_t			*pkey_tbl;
    640 	ibdm_port_attr_t		newport;
    641 
    642 	IBTF_DPRINTF_L4("ibdm", "\tupdate_port_pkeys:");
    643 	ASSERT(MUTEX_HELD(&ibdm.ibdm_hl_mutex));
    644 
    645 	/* Check whether the port is active */
    646 	if (ibt_get_port_state(port->pa_hca_hdl, port->pa_port_num, NULL,
    647 	    NULL) != IBT_SUCCESS)
    648 		return;
    649 
    650 	if (ibt_query_hca_ports(port->pa_hca_hdl, port->pa_port_num,
    651 	    &pinfop, &nports, &size) != IBT_SUCCESS) {
    652 		/* This should not occur */
    653 		port->pa_npkeys = 0;
    654 		port->pa_pkey_tbl = NULL;
    655 		return;
    656 	}
    657 
    658 	npkeys = pinfop->p_pkey_tbl_sz;
    659 	pkey_tbl = kmem_zalloc(npkeys * sizeof (ibdm_pkey_tbl_t), KM_SLEEP);
    660 	newport.pa_pkey_tbl = pkey_tbl;
    661 	newport.pa_ibmf_hdl = port->pa_ibmf_hdl;
    662 
    663 	for (pkey_idx = 0; pkey_idx < npkeys; pkey_idx++) {
    664 		pkey = pkey_tbl[pkey_idx].pt_pkey =
    665 		    pinfop->p_pkey_tbl[pkey_idx];
    666 		/*
    667 		 * Is this pkey present in the current table ?
    668 		 */
    669 		for (opkey_idx = 0; opkey_idx < port->pa_npkeys; opkey_idx++) {
    670 			if (pkey == port->pa_pkey_tbl[opkey_idx].pt_pkey) {
    671 				pkey_tbl[pkey_idx].pt_qp_hdl =
    672 				    port->pa_pkey_tbl[opkey_idx].pt_qp_hdl;
    673 				port->pa_pkey_tbl[opkey_idx].pt_qp_hdl = NULL;
    674 				break;
    675 			}
    676 		}
    677 
    678 		if (opkey_idx == port->pa_npkeys) {
    679 			pkey = pkey_tbl[pkey_idx].pt_pkey;
    680 			if (IBDM_INVALID_PKEY(pkey)) {
    681 				pkey_tbl[pkey_idx].pt_qp_hdl = NULL;
    682 				continue;
    683 			}
    684 			ibdm_port_attr_ibmf_init(&newport, pkey, pkey_idx);
    685 		}
    686 	}
    687 
    688 	for (opkey_idx = 0; opkey_idx < port->pa_npkeys; opkey_idx++) {
    689 		if (port->pa_pkey_tbl[opkey_idx].pt_qp_hdl != NULL) {
    690 			if (ibdm_port_attr_ibmf_fini(port, opkey_idx) !=
    691 			    IBDM_SUCCESS) {
    692 				IBTF_DPRINTF_L2("ibdm", "\tupdate_port_pkeys: "
    693 				    "ibdm_port_attr_ibmf_fini failed for "
    694 				    "port pkey 0x%x",
    695 				    port->pa_pkey_tbl[opkey_idx].pt_pkey);
    696 			}
    697 		}
    698 	}
    699 
    700 	if (port->pa_pkey_tbl != NULL) {
    701 		kmem_free(port->pa_pkey_tbl,
    702 		    port->pa_npkeys * sizeof (ibdm_pkey_tbl_t));
    703 	}
    704 
    705 	port->pa_npkeys = npkeys;
    706 	port->pa_pkey_tbl = pkey_tbl;
    707 	port->pa_sn_prefix = pinfop->p_sgid_tbl[0].gid_prefix;
    708 	port->pa_state = pinfop->p_linkstate;
    709 	ibt_free_portinfo(pinfop, size);
    710 }
    711 
    712 /*
    713  * ibdm_initialize_port()
    714  *	Register with IBMF
    715  *	Register with SA access
    716  *	Register a receive callback routine with IBMF. IBMF invokes
    717  *	this routine whenever a MAD arrives at this port.
    718  *	Update the port attributes
    719  */
    720 static void
    721 ibdm_initialize_port(ibdm_port_attr_t *port)
    722 {
    723 	int				ii;
    724 	uint_t				nports, size;
    725 	uint_t				pkey_idx;
    726 	ib_pkey_t			pkey;
    727 	ibt_hca_portinfo_t		*pinfop;
    728 	ibmf_register_info_t		ibmf_reg;
    729 	ibmf_saa_subnet_event_args_t	event_args;
    730 
    731 	IBTF_DPRINTF_L4("ibdm", "\tinitialize_port:");
    732 	ASSERT(MUTEX_HELD(&ibdm.ibdm_hl_mutex));
    733 
    734 	/* Check whether the port is active */
    735 	if (ibt_get_port_state(port->pa_hca_hdl, port->pa_port_num, NULL,
    736 	    NULL) != IBT_SUCCESS)
    737 		return;
    738 
    739 	if (port->pa_sa_hdl != NULL)
    740 		return;
    741 
    742 	if (ibt_query_hca_ports(port->pa_hca_hdl, port->pa_port_num,
    743 	    &pinfop, &nports, &size) != IBT_SUCCESS) {
    744 		/* This should not occur */
    745 		port->pa_npkeys		= 0;
    746 		port->pa_pkey_tbl	= NULL;
    747 		return;
    748 	}
    749 	port->pa_sn_prefix = pinfop->p_sgid_tbl[0].gid_prefix;
    750 
    751 	port->pa_state		= pinfop->p_linkstate;
    752 	port->pa_npkeys		= pinfop->p_pkey_tbl_sz;
    753 	port->pa_pkey_tbl	= (ibdm_pkey_tbl_t *)kmem_zalloc(
    754 	    port->pa_npkeys * sizeof (ibdm_pkey_tbl_t), KM_SLEEP);
    755 
    756 	for (pkey_idx = 0; pkey_idx < port->pa_npkeys; pkey_idx++)
    757 		port->pa_pkey_tbl[pkey_idx].pt_pkey =
    758 		    pinfop->p_pkey_tbl[pkey_idx];
    759 
    760 	ibt_free_portinfo(pinfop, size);
    761 
    762 	event_args.is_event_callback = ibdm_saa_event_cb;
    763 	event_args.is_event_callback_arg = port;
    764 	if (ibmf_sa_session_open(port->pa_port_guid, 0, &event_args,
    765 	    IBMF_VERSION, 0, &port->pa_sa_hdl) != IBMF_SUCCESS) {
    766 		IBTF_DPRINTF_L2("ibdm", "\tinitialize_port: "
    767 		    "sa access registration failed");
    768 		return;
    769 	}
    770 	ibmf_reg.ir_ci_guid		= port->pa_hca_guid;
    771 	ibmf_reg.ir_port_num		= port->pa_port_num;
    772 	ibmf_reg.ir_client_class	= DEV_MGT_MANAGER;
    773 
    774 	if (ibmf_register(&ibmf_reg, IBMF_VERSION, 0, NULL, NULL,
    775 	    &port->pa_ibmf_hdl, &port->pa_ibmf_caps) != IBMF_SUCCESS) {
    776 		IBTF_DPRINTF_L2("ibdm", "\tinitialize_port: "
    777 		    "IBMF registration failed");
    778 		(void) ibdm_fini_port(port);
    779 		return;
    780 	}
    781 	if (ibmf_setup_async_cb(port->pa_ibmf_hdl, IBMF_QP_HANDLE_DEFAULT,
    782 	    ibdm_ibmf_recv_cb, 0, 0) != IBMF_SUCCESS) {
    783 		IBTF_DPRINTF_L2("ibdm", "\tinitialize_port: "
    784 		    "IBMF setup recv cb failed");
    785 		(void) ibdm_fini_port(port);
    786 		return;
    787 	}
    788 
    789 	for (ii = 0; ii < port->pa_npkeys; ii++) {
    790 		pkey = port->pa_pkey_tbl[ii].pt_pkey;
    791 		if (IBDM_INVALID_PKEY(pkey)) {
    792 			port->pa_pkey_tbl[ii].pt_qp_hdl = NULL;
    793 			continue;
    794 		}
    795 		ibdm_port_attr_ibmf_init(port, pkey, ii);
    796 	}
    797 }
    798 
    799 
    800 /*
    801  * ibdm_port_attr_ibmf_init:
    802  *	With IBMF - Alloc QP Handle and Setup Async callback
    803  */
    804 static void
    805 ibdm_port_attr_ibmf_init(ibdm_port_attr_t *port, ib_pkey_t pkey, int ii)
    806 {
    807 	int ret;
    808 
    809 	if ((ret = ibmf_alloc_qp(port->pa_ibmf_hdl, pkey, IB_GSI_QKEY,
    810 	    IBMF_ALT_QP_MAD_NO_RMPP, &port->pa_pkey_tbl[ii].pt_qp_hdl)) !=
    811 	    IBMF_SUCCESS) {
    812 		IBTF_DPRINTF_L2("ibdm", "\tport_attr_ibmf_init: "
    813 		    "IBMF failed to alloc qp %d", ret);
    814 		port->pa_pkey_tbl[ii].pt_qp_hdl = NULL;
    815 		return;
    816 	}
    817 
    818 	IBTF_DPRINTF_L4("ibdm", "\tport_attr_ibmf_init: QP handle is %p",
    819 	    port->pa_ibmf_hdl);
    820 
    821 	if ((ret = ibmf_setup_async_cb(port->pa_ibmf_hdl,
    822 	    port->pa_pkey_tbl[ii].pt_qp_hdl, ibdm_ibmf_recv_cb, 0, 0)) !=
    823 	    IBMF_SUCCESS) {
    824 		IBTF_DPRINTF_L2("ibdm", "\tport_attr_ibmf_init: "
    825 		    "IBMF setup recv cb failed %d", ret);
    826 		(void) ibmf_free_qp(port->pa_ibmf_hdl,
    827 		    &port->pa_pkey_tbl[ii].pt_qp_hdl, 0);
    828 		port->pa_pkey_tbl[ii].pt_qp_hdl = NULL;
    829 	}
    830 }
    831 
    832 
    833 /*
    834  * ibdm_get_port_attr()
    835  *	Get port attributes from HCA guid and port number
    836  *	Return pointer to ibdm_port_attr_t on Success
    837  *	and NULL on failure
    838  */
    839 static ibdm_port_attr_t *
    840 ibdm_get_port_attr(ibt_async_event_t *event, ibdm_hca_list_t **retval)
    841 {
    842 	ibdm_hca_list_t		*hca_list;
    843 	ibdm_port_attr_t	*port_attr;
    844 	int			ii;
    845 
    846 	IBTF_DPRINTF_L4("ibdm", "\tget_port_attr: port# %d", event->ev_port);
    847 	ASSERT(MUTEX_HELD(&ibdm.ibdm_hl_mutex));
    848 	hca_list = ibdm.ibdm_hca_list_head;
    849 	while (hca_list) {
    850 		if (hca_list->hl_hca_guid == event->ev_hca_guid) {
    851 			for (ii = 0; ii < hca_list->hl_nports; ii++) {
    852 				port_attr = &hca_list->hl_port_attr[ii];
    853 				if (port_attr->pa_port_num == event->ev_port) {
    854 					*retval = hca_list;
    855 					return (port_attr);
    856 				}
    857 			}
    858 		}
    859 		hca_list = hca_list->hl_next;
    860 	}
    861 	return (NULL);
    862 }
    863 
    864 
    865 /*
    866  * ibdm_update_port_attr()
    867  *	Update the port attributes
    868  */
    869 static void
    870 ibdm_update_port_attr(ibdm_port_attr_t *port)
    871 {
    872 	uint_t			nports, size;
    873 	uint_t			pkey_idx;
    874 	ibt_hca_portinfo_t	*portinfop;
    875 
    876 	IBTF_DPRINTF_L4("ibdm", "\tupdate_port_attr: Begin");
    877 	if (ibt_query_hca_ports(port->pa_hca_hdl,
    878 	    port->pa_port_num, &portinfop, &nports, &size) != IBT_SUCCESS) {
    879 		/* This should not occur */
    880 		port->pa_npkeys		= 0;
    881 		port->pa_pkey_tbl	= NULL;
    882 		return;
    883 	}
    884 	port->pa_sn_prefix = portinfop->p_sgid_tbl[0].gid_prefix;
    885 
    886 	port->pa_state		= portinfop->p_linkstate;
    887 
    888 	/*
    889 	 * PKey information in portinfo valid only if port is
    890 	 * ACTIVE. Bail out if not.
    891 	 */
    892 	if (port->pa_state != IBT_PORT_ACTIVE) {
    893 		port->pa_npkeys		= 0;
    894 		port->pa_pkey_tbl	= NULL;
    895 		ibt_free_portinfo(portinfop, size);
    896 		return;
    897 	}
    898 
    899 	port->pa_npkeys		= portinfop->p_pkey_tbl_sz;
    900 	port->pa_pkey_tbl	= (ibdm_pkey_tbl_t *)kmem_zalloc(
    901 	    port->pa_npkeys * sizeof (ibdm_pkey_tbl_t), KM_SLEEP);
    902 
    903 	for (pkey_idx = 0; pkey_idx < port->pa_npkeys; pkey_idx++) {
    904 		port->pa_pkey_tbl[pkey_idx].pt_pkey =
    905 		    portinfop->p_pkey_tbl[pkey_idx];
    906 	}
    907 	ibt_free_portinfo(portinfop, size);
    908 }
    909 
    910 
    911 /*
    912  * ibdm_handle_hca_attach()
    913  */
    914 static void
    915 ibdm_handle_hca_attach(ib_guid_t hca_guid)
    916 {
    917 	uint_t			size;
    918 	uint_t			ii, nports;
    919 	ibt_status_t		status;
    920 	ibt_hca_hdl_t		hca_hdl;
    921 	ibt_hca_attr_t		*hca_attr;
    922 	ibdm_hca_list_t		*hca_list, *temp;
    923 	ibdm_port_attr_t	*port_attr;
    924 	ibt_hca_portinfo_t	*portinfop;
    925 
    926 	IBTF_DPRINTF_L4("ibdm",
    927 	    "\thandle_hca_attach: hca_guid = 0x%llX", hca_guid);
    928 
    929 	/* open the HCA first */
    930 	if ((status = ibt_open_hca(ibdm.ibdm_ibt_clnt_hdl, hca_guid,
    931 	    &hca_hdl)) != IBT_SUCCESS) {
    932 		IBTF_DPRINTF_L2("ibdm", "\thandle_hca_attach: "
    933 		    "open_hca failed, status 0x%x", status);
    934 		return;
    935 	}
    936 
    937 	hca_attr = (ibt_hca_attr_t *)
    938 	    kmem_alloc(sizeof (ibt_hca_attr_t), KM_SLEEP);
    939 	/* ibt_query_hca always returns IBT_SUCCESS */
    940 	(void) ibt_query_hca(hca_hdl, hca_attr);
    941 
    942 	IBTF_DPRINTF_L4("ibdm", "\tvid: 0x%x, pid: 0x%x, ver: 0x%x,"
    943 	    " #ports: %d", hca_attr->hca_vendor_id, hca_attr->hca_device_id,
    944 	    hca_attr->hca_version_id, hca_attr->hca_nports);
    945 
    946 	if ((status = ibt_query_hca_ports(hca_hdl, 0, &portinfop, &nports,
    947 	    &size)) != IBT_SUCCESS) {
    948 		IBTF_DPRINTF_L2("ibdm", "\thandle_hca_attach: "
    949 		    "ibt_query_hca_ports failed, status 0x%x", status);
    950 		kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
    951 		(void) ibt_close_hca(hca_hdl);
    952 		return;
    953 	}
    954 	hca_list = (ibdm_hca_list_t *)
    955 	    kmem_zalloc((sizeof (ibdm_hca_list_t)), KM_SLEEP);
    956 	hca_list->hl_port_attr = (ibdm_port_attr_t *)kmem_zalloc(
    957 	    (sizeof (ibdm_port_attr_t) * hca_attr->hca_nports), KM_SLEEP);
    958 	hca_list->hl_hca_guid = hca_attr->hca_node_guid;
    959 	hca_list->hl_nports = hca_attr->hca_nports;
    960 	hca_list->hl_attach_time = ddi_get_time();
    961 	hca_list->hl_hca_hdl = hca_hdl;
    962 
    963 	/*
    964 	 * Init a dummy port attribute for the HCA node
    965 	 * This is for Per-HCA Node. Initialize port_attr :
    966 	 * 	hca_guid & port_guid -> hca_guid
    967 	 *	npkeys, pkey_tbl is NULL
    968 	 *	port_num, sn_prefix is 0
    969 	 *	vendorid, product_id, dev_version from HCA
    970 	 *	pa_state is IBT_PORT_ACTIVE
    971 	 */
    972 	hca_list->hl_hca_port_attr = (ibdm_port_attr_t *)kmem_zalloc(
    973 	    sizeof (ibdm_port_attr_t), KM_SLEEP);
    974 	port_attr = hca_list->hl_hca_port_attr;
    975 	port_attr->pa_vendorid  = hca_attr->hca_vendor_id;
    976 	port_attr->pa_productid	= hca_attr->hca_device_id;
    977 	port_attr->pa_dev_version = hca_attr->hca_version_id;
    978 	port_attr->pa_hca_guid	= hca_attr->hca_node_guid;
    979 	port_attr->pa_hca_hdl	= hca_list->hl_hca_hdl;
    980 	port_attr->pa_port_guid	= hca_attr->hca_node_guid;
    981 	port_attr->pa_state	= IBT_PORT_ACTIVE;
    982 
    983 
    984 	for (ii = 0; ii < nports; ii++) {
    985 		port_attr		= &hca_list->hl_port_attr[ii];
    986 		port_attr->pa_vendorid	= hca_attr->hca_vendor_id;
    987 		port_attr->pa_productid	= hca_attr->hca_device_id;
    988 		port_attr->pa_dev_version = hca_attr->hca_version_id;
    989 		port_attr->pa_hca_guid	= hca_attr->hca_node_guid;
    990 		port_attr->pa_hca_hdl	= hca_list->hl_hca_hdl;
    991 		port_attr->pa_port_guid	= portinfop[ii].p_sgid_tbl->gid_guid;
    992 		port_attr->pa_sn_prefix	= portinfop[ii].p_sgid_tbl->gid_prefix;
    993 		port_attr->pa_port_num	= portinfop[ii].p_port_num;
    994 		port_attr->pa_state	= portinfop[ii].p_linkstate;
    995 
    996 		/*
    997 		 * Register with IBMF, SA access when the port is in
    998 		 * ACTIVE state. Also register a callback routine
    999 		 * with IBMF to receive incoming DM MAD's.
   1000 		 * The IBDM event handler takes care of registration of
   1001 		 * port which are not active.
   1002 		 */
   1003 		IBTF_DPRINTF_L4("ibdm",
   1004 		    "\thandle_hca_attach: port guid %llx Port state 0x%x",
   1005 		    port_attr->pa_port_guid, portinfop[ii].p_linkstate);
   1006 
   1007 		if (portinfop[ii].p_linkstate == IBT_PORT_ACTIVE) {
   1008 			mutex_enter(&ibdm.ibdm_hl_mutex);
   1009 			hca_list->hl_nports_active++;
   1010 			ibdm_initialize_port(port_attr);
   1011 			cv_broadcast(&ibdm.ibdm_port_settle_cv);
   1012 			mutex_exit(&ibdm.ibdm_hl_mutex);
   1013 		}
   1014 	}
   1015 	mutex_enter(&ibdm.ibdm_hl_mutex);
   1016 	for (temp = ibdm.ibdm_hca_list_head; temp; temp = temp->hl_next) {
   1017 		if (temp->hl_hca_guid == hca_guid) {
   1018 			IBTF_DPRINTF_L2("ibdm", "hca_attach: HCA %llX "
   1019 			    "already seen by IBDM", hca_guid);
   1020 			mutex_exit(&ibdm.ibdm_hl_mutex);
   1021 			(void) ibdm_uninit_hca(hca_list);
   1022 			return;
   1023 		}
   1024 	}
   1025 	ibdm.ibdm_hca_count++;
   1026 	if (ibdm.ibdm_hca_list_head == NULL) {
   1027 		ibdm.ibdm_hca_list_head = hca_list;
   1028 		ibdm.ibdm_hca_list_tail = hca_list;
   1029 	} else {
   1030 		ibdm.ibdm_hca_list_tail->hl_next = hca_list;
   1031 		ibdm.ibdm_hca_list_tail = hca_list;
   1032 	}
   1033 	mutex_exit(&ibdm.ibdm_hl_mutex);
   1034 	mutex_enter(&ibdm.ibdm_ibnex_mutex);
   1035 	if (ibdm.ibdm_ibnex_callback != NULL) {
   1036 		(*ibdm.ibdm_ibnex_callback)((void *)
   1037 		    &hca_guid, IBDM_EVENT_HCA_ADDED);
   1038 	}
   1039 	mutex_exit(&ibdm.ibdm_ibnex_mutex);
   1040 
   1041 	kmem_free(hca_attr, sizeof (ibt_hca_attr_t));
   1042 	ibt_free_portinfo(portinfop, size);
   1043 }
   1044 
   1045 
   1046 /*
   1047  * ibdm_handle_hca_detach()
   1048  */
   1049 static void
   1050 ibdm_handle_hca_detach(ib_guid_t hca_guid)
   1051 {
   1052 	ibdm_hca_list_t		*head, *prev = NULL;
   1053 	size_t			len;
   1054 	ibdm_dp_gidinfo_t	*gidinfo;
   1055 
   1056 	IBTF_DPRINTF_L4("ibdm",
   1057 	    "\thandle_hca_detach: hca_guid = 0x%llx", hca_guid);
   1058 
   1059 	/* Make sure no probes are running */
   1060 	mutex_enter(&ibdm.ibdm_mutex);
   1061 	while (ibdm.ibdm_busy & IBDM_BUSY)
   1062 		cv_wait(&ibdm.ibdm_busy_cv, &ibdm.ibdm_mutex);
   1063 	ibdm.ibdm_busy |= IBDM_BUSY;
   1064 	mutex_exit(&ibdm.ibdm_mutex);
   1065 
   1066 	mutex_enter(&ibdm.ibdm_hl_mutex);
   1067 	head = ibdm.ibdm_hca_list_head;
   1068 	while (head) {
   1069 		if (head->hl_hca_guid == hca_guid) {
   1070 			if (prev == NULL)
   1071 				ibdm.ibdm_hca_list_head = head->hl_next;
   1072 			else
   1073 				prev->hl_next = head->hl_next;
   1074 			if (ibdm.ibdm_hca_list_tail == head)
   1075 				ibdm.ibdm_hca_list_tail = prev;
   1076 			ibdm.ibdm_hca_count--;
   1077 			break;
   1078 		}
   1079 		prev = head;
   1080 		head = head->hl_next;
   1081 	}
   1082 	mutex_exit(&ibdm.ibdm_hl_mutex);
   1083 	if (ibdm_uninit_hca(head) != IBDM_SUCCESS)
   1084 		(void) ibdm_handle_hca_attach(hca_guid);
   1085 
   1086 	/*
   1087 	 * Now clean up the HCA lists in the gidlist.
   1088 	 */
   1089 	for (gidinfo = ibdm.ibdm_dp_gidlist_head; gidinfo; gidinfo =
   1090 	    gidinfo->gl_next) {
   1091 		prev = NULL;
   1092 		head = gidinfo->gl_hca_list;
   1093 		while (head) {
   1094 			if (head->hl_hca_guid == hca_guid) {
   1095 				if (prev == NULL)
   1096 					gidinfo->gl_hca_list =
   1097 					    head->hl_next;
   1098 				else
   1099 					prev->hl_next = head->hl_next;
   1100 
   1101 				len = sizeof (ibdm_hca_list_t) +
   1102 				    (head->hl_nports *
   1103 				    sizeof (ibdm_port_attr_t));
   1104 				kmem_free(head, len);
   1105 
   1106 				break;
   1107 			}
   1108 			prev = head;
   1109 			head = head->hl_next;
   1110 		}
   1111 	}
   1112 
   1113 	mutex_enter(&ibdm.ibdm_mutex);
   1114 	ibdm.ibdm_busy &= ~IBDM_BUSY;
   1115 	cv_broadcast(&ibdm.ibdm_busy_cv);
   1116 	mutex_exit(&ibdm.ibdm_mutex);
   1117 }
   1118 
   1119 
   1120 static int
   1121 ibdm_uninit_hca(ibdm_hca_list_t *head)
   1122 {
   1123 	int			ii;
   1124 	ibdm_port_attr_t	*port_attr;
   1125 
   1126 	for (ii = 0; ii < head->hl_nports; ii++) {
   1127 		port_attr = &head->hl_port_attr[ii];
   1128 		if (ibdm_fini_port(port_attr) != IBDM_SUCCESS) {
   1129 			IBTF_DPRINTF_L2("ibdm", "uninit_hca: HCA %p port 0x%x "
   1130 			    "ibdm_fini_port() failed", head, ii);
   1131 			return (IBDM_FAILURE);
   1132 		}
   1133 	}
   1134 	if (head->hl_hca_hdl)
   1135 		if (ibt_close_hca(head->hl_hca_hdl) != IBT_SUCCESS) {
   1136 			IBTF_DPRINTF_L2("ibdm", "uninit_hca: "
   1137 			    "ibt_close_hca() failed");
   1138 			return (IBDM_FAILURE);
   1139 		}
   1140 	kmem_free(head->hl_port_attr,
   1141 	    head->hl_nports * sizeof (ibdm_port_attr_t));
   1142 	kmem_free(head->hl_hca_port_attr, sizeof (ibdm_port_attr_t));
   1143 	kmem_free(head, sizeof (ibdm_hca_list_t));
   1144 	return (IBDM_SUCCESS);
   1145 }
   1146 
   1147 
   1148 /*
   1149  * For each port on the HCA,
   1150  *	1) Teardown IBMF receive callback function
   1151  *	2) Unregister with IBMF
   1152  *	3) Unregister with SA access
   1153  */
   1154 static int
   1155 ibdm_fini_port(ibdm_port_attr_t *port_attr)
   1156 {
   1157 	int	ii, ibmf_status;
   1158 
   1159 	for (ii = 0; ii < port_attr->pa_npkeys; ii++) {
   1160 		if (port_attr->pa_pkey_tbl == NULL)
   1161 			break;
   1162 		if (!port_attr->pa_pkey_tbl[ii].pt_qp_hdl)
   1163 			continue;
   1164 		if (ibdm_port_attr_ibmf_fini(port_attr, ii) != IBDM_SUCCESS) {
   1165 			IBTF_DPRINTF_L4("ibdm", "\tfini_port: "
   1166 			    "ibdm_port_attr_ibmf_fini failed for "
   1167 			    "port pkey 0x%x", ii);
   1168 			return (IBDM_FAILURE);
   1169 		}
   1170 	}
   1171 
   1172 	if (port_attr->pa_ibmf_hdl) {
   1173 		ibmf_status = ibmf_tear_down_async_cb(port_attr->pa_ibmf_hdl,
   1174 		    IBMF_QP_HANDLE_DEFAULT, 0);
   1175 		if (ibmf_status != IBMF_SUCCESS) {
   1176 			IBTF_DPRINTF_L4("ibdm", "\tfini_port: "
   1177 			    "ibmf_tear_down_async_cb failed %d", ibmf_status);
   1178 			return (IBDM_FAILURE);
   1179 		}
   1180 
   1181 		ibmf_status = ibmf_unregister(&port_attr->pa_ibmf_hdl, 0);
   1182 		if (ibmf_status != IBMF_SUCCESS) {
   1183 			IBTF_DPRINTF_L2("ibdm", "\tfini_port: "
   1184 			    "ibmf_unregister failed %d", ibmf_status);
   1185 			return (IBDM_FAILURE);
   1186 		}
   1187 
   1188 		port_attr->pa_ibmf_hdl = NULL;
   1189 	}
   1190 
   1191 	if (port_attr->pa_sa_hdl) {
   1192 		ibmf_status = ibmf_sa_session_close(&port_attr->pa_sa_hdl, 0);
   1193 		if (ibmf_status != IBMF_SUCCESS) {
   1194 			IBTF_DPRINTF_L2("ibdm", "\tfini_port: "
   1195 			    "ibmf_sa_session_close failed %d", ibmf_status);
   1196 			return (IBDM_FAILURE);
   1197 		}
   1198 		port_attr->pa_sa_hdl = NULL;
   1199 	}
   1200 
   1201 	if (port_attr->pa_pkey_tbl != NULL) {
   1202 		kmem_free(port_attr->pa_pkey_tbl,
   1203 		    port_attr->pa_npkeys * sizeof (ibdm_pkey_tbl_t));
   1204 		port_attr->pa_pkey_tbl = NULL;
   1205 		port_attr->pa_npkeys = 0;
   1206 	}
   1207 
   1208 	return (IBDM_SUCCESS);
   1209 }
   1210 
   1211 
   1212 /*
   1213  * ibdm_port_attr_ibmf_fini:
   1214  *	With IBMF - Tear down Async callback and free QP Handle
   1215  */
   1216 static int
   1217 ibdm_port_attr_ibmf_fini(ibdm_port_attr_t *port_attr, int ii)
   1218 {
   1219 	int ibmf_status;
   1220 
   1221 	IBTF_DPRINTF_L5("ibdm", "\tport_attr_ibmf_fini:");
   1222 
   1223 	if (port_attr->pa_pkey_tbl[ii].pt_qp_hdl) {
   1224 		ibmf_status = ibmf_tear_down_async_cb(port_attr->pa_ibmf_hdl,
   1225 		    port_attr->pa_pkey_tbl[ii].pt_qp_hdl, 0);
   1226 		if (ibmf_status != IBMF_SUCCESS) {
   1227 			IBTF_DPRINTF_L4("ibdm", "\tport_attr_ibmf_fini: "
   1228 			    "ibmf_tear_down_async_cb failed %d", ibmf_status);
   1229 			return (IBDM_FAILURE);
   1230 		}
   1231 		ibmf_status = ibmf_free_qp(port_attr->pa_ibmf_hdl,
   1232 		    &port_attr->pa_pkey_tbl[ii].pt_qp_hdl, 0);
   1233 		if (ibmf_status != IBMF_SUCCESS) {
   1234 			IBTF_DPRINTF_L4("ibdm", "\tport_attr_ibmf_fini: "
   1235 			    "ibmf_free_qp failed %d", ibmf_status);
   1236 			return (IBDM_FAILURE);
   1237 		}
   1238 		port_attr->pa_pkey_tbl[ii].pt_qp_hdl = NULL;
   1239 	}
   1240 	return (IBDM_SUCCESS);
   1241 }
   1242 
   1243 
   1244 /*
   1245  * ibdm_gid_decr_pending:
   1246  *	decrement gl_pending_cmds. If zero wakeup sleeping threads
   1247  */
   1248 static void
   1249 ibdm_gid_decr_pending(ibdm_dp_gidinfo_t *gidinfo)
   1250 {
   1251 	mutex_enter(&ibdm.ibdm_mutex);
   1252 	mutex_enter(&gidinfo->gl_mutex);
   1253 	if (--gidinfo->gl_pending_cmds == 0) {
   1254 		/*
   1255 		 * Handle DGID getting removed.
   1256 		 */
   1257 		if (gidinfo->gl_disconnected) {
   1258 			mutex_exit(&gidinfo->gl_mutex);
   1259 			mutex_exit(&ibdm.ibdm_mutex);
   1260 
   1261 			IBTF_DPRINTF_L3(ibdm_string, "\tgid_decr_pending: "
   1262 			    "gidinfo %p hot removal", gidinfo);
   1263 			ibdm_delete_gidinfo(gidinfo);
   1264 
   1265 			mutex_enter(&ibdm.ibdm_mutex);
   1266 			ibdm.ibdm_ngid_probes_in_progress--;
   1267 			ibdm_wait_probe_completion();
   1268 			mutex_exit(&ibdm.ibdm_mutex);
   1269 			return;
   1270 		}
   1271 		mutex_exit(&gidinfo->gl_mutex);
   1272 		mutex_exit(&ibdm.ibdm_mutex);
   1273 		ibdm_notify_newgid_iocs(gidinfo);
   1274 		mutex_enter(&ibdm.ibdm_mutex);
   1275 		mutex_enter(&gidinfo->gl_mutex);
   1276 
   1277 		ibdm.ibdm_ngid_probes_in_progress--;
   1278 		ibdm_wait_probe_completion();
   1279 	}
   1280 	mutex_exit(&gidinfo->gl_mutex);
   1281 	mutex_exit(&ibdm.ibdm_mutex);
   1282 }
   1283 
   1284 
   1285 /*
   1286  * ibdm_wait_probe_completion:
   1287  *	wait for probing to complete
   1288  */
   1289 static void
   1290 ibdm_wait_probe_completion(void)
   1291 {
   1292 	ASSERT(MUTEX_HELD(&ibdm.ibdm_mutex));
   1293 	if (ibdm.ibdm_ngid_probes_in_progress) {
   1294 		IBTF_DPRINTF_L4("ibdm",	"\twait for probe complete");
   1295 		ibdm.ibdm_busy |= IBDM_PROBE_IN_PROGRESS;
   1296 		while (ibdm.ibdm_busy & IBDM_PROBE_IN_PROGRESS)
   1297 			cv_wait(&ibdm.ibdm_probe_cv, &ibdm.ibdm_mutex);
   1298 	}
   1299 }
   1300 
   1301 
   1302 /*
   1303  * ibdm_wait_cisco_probe_completion:
   1304  *	wait for the reply from the Cisco FC GW switch after a setclassportinfo
   1305  *	request is sent. This wait can be achieved on each gid.
   1306  */
   1307 static void
   1308 ibdm_wait_cisco_probe_completion(ibdm_dp_gidinfo_t *gidinfo)
   1309 {
   1310 	ASSERT(MUTEX_HELD(&gidinfo->gl_mutex));
   1311 	IBTF_DPRINTF_L4("ibdm",	"\twait for cisco probe complete");
   1312 	gidinfo->gl_flag |= IBDM_CISCO_PROBE;
   1313 	while (gidinfo->gl_flag & IBDM_CISCO_PROBE)
   1314 		cv_wait(&gidinfo->gl_probe_cv, &gidinfo->gl_mutex);
   1315 }
   1316 
   1317 
   1318 /*
   1319  * ibdm_wakeup_probe_gid_cv:
   1320  *	wakeup waiting threads (based on ibdm_ngid_probes_in_progress)
   1321  */
   1322 static void
   1323 ibdm_wakeup_probe_gid_cv(void)
   1324 {
   1325 	ASSERT(MUTEX_HELD(&ibdm.ibdm_mutex));
   1326 	if (!ibdm.ibdm_ngid_probes_in_progress) {
   1327 		IBTF_DPRINTF_L4("ibdm", "wakeup_probe_gid_thread: Wakeup");
   1328 		ibdm.ibdm_busy &= ~IBDM_PROBE_IN_PROGRESS;
   1329 		cv_broadcast(&ibdm.ibdm_probe_cv);
   1330 	}
   1331 
   1332 }
   1333 
   1334 
   1335 /*
   1336  * ibdm_sweep_fabric(reprobe_flag)
   1337  *	Find all possible Managed IOU's and their IOC's that are visible
   1338  *	to the host. The algorithm used is as follows
   1339  *
   1340  *	Send a "bus walk" request for each port on the host HCA to SA access
   1341  *	SA returns complete set of GID's that are reachable from
   1342  *	source port. This is done in parallel.
   1343  *
   1344  *	Initialize GID state to IBDM_GID_PROBE_NOT_DONE
   1345  *
   1346  *	Sort the GID list and eliminate duplicate GID's
   1347  *		1) Use DGID for sorting
   1348  *		2) use PortGuid for sorting
   1349  *			Send SA query to retrieve NodeRecord and
   1350  *			extract PortGuid from that.
   1351  *
   1352  *	Set GID state to IBDM_GID_PROBE_FAILED to all the ports that dont
   1353  *	support DM MAD's
   1354  *		Send a "Portinfo" query to get the port capabilities and
   1355  *		then check for DM MAD's support
   1356  *
   1357  *	Send "ClassPortInfo" request for all the GID's in parallel,
   1358  *	set the GID state to IBDM_GET_CLASSPORTINFO and wait on the
   1359  *	cv_signal to complete.
   1360  *
   1361  *	When DM agent on the remote GID sends back the response, IBMF
   1362  *	invokes DM callback routine.
   1363  *
   1364  *	If the response is proper, send "IOUnitInfo" request and set
   1365  *	GID state to IBDM_GET_IOUNITINFO.
   1366  *
   1367  *	If the response is proper, send "IocProfileInfo" request to
   1368  *	all the IOC simultaneously and set GID state to IBDM_GET_IOC_DETAILS.
   1369  *
   1370  *	Send request to get Service entries simultaneously
   1371  *
   1372  *	Signal the waiting thread when received response for all the commands.
   1373  *
   1374  *	Set the GID state to IBDM_GID_PROBE_FAILED when received a error
   1375  *	response during the probing period.
   1376  *
   1377  *	Note:
   1378  *	ibdm.ibdm_ngid_probes_in_progress and ibdm_gid_list_t:gl_pending_cmds
   1379  *	keep track of number commands in progress at any point of time.
   1380  *	MAD transaction ID is used to identify a particular GID
   1381  *	TBD: Consider registering the IBMF receive callback on demand
   1382  *
   1383  *	Note: This routine must be called with ibdm.ibdm_mutex held
   1384  *	TBD: Re probe the failure GID (for certain failures) when requested
   1385  *	     for fabric sweep next time
   1386  *
   1387  *	Parameters : If reprobe_flag is set, All IOCs will be reprobed.
   1388  */
   1389 static void
   1390 ibdm_sweep_fabric(int reprobe_flag)
   1391 {
   1392 	int			ii;
   1393 	int			new_paths = 0;
   1394 	uint8_t			niocs;
   1395 	taskqid_t		tid;
   1396 	ibdm_ioc_info_t		*ioc;
   1397 	ibdm_hca_list_t		*hca_list = NULL;
   1398 	ibdm_port_attr_t	*port = NULL;
   1399 	ibdm_dp_gidinfo_t 	*gid_info;
   1400 
   1401 	IBTF_DPRINTF_L4("ibdm", "\tsweep_fabric: Enter");
   1402 	ASSERT(MUTEX_HELD(&ibdm.ibdm_mutex));
   1403 
   1404 	/*
   1405 	 * Check whether a sweep already in progress. If so, just
   1406 	 * wait for the fabric sweep to complete
   1407 	 */
   1408 	while (ibdm.ibdm_busy & IBDM_BUSY)
   1409 		cv_wait(&ibdm.ibdm_busy_cv, &ibdm.ibdm_mutex);
   1410 	ibdm.ibdm_busy |= IBDM_BUSY;
   1411 	mutex_exit(&ibdm.ibdm_mutex);
   1412 
   1413 	ibdm_dump_sweep_fabric_timestamp(0);
   1414 
   1415 	/* Rescan the GID list for any removed GIDs for reprobe */
   1416 	if (reprobe_flag)
   1417 		ibdm_rescan_gidlist(NULL);
   1418 
   1419 	/*
   1420 	 * Get list of all the ports reachable from the local known HCA
   1421 	 * ports which are active
   1422 	 */
   1423 	mutex_enter(&ibdm.ibdm_hl_mutex);
   1424 	for (ibdm_get_next_port(&hca_list, &port, 1); port;
   1425 	    ibdm_get_next_port(&hca_list, &port, 1)) {
   1426 		/*
   1427 		 * Get PATHS to all the reachable ports from
   1428 		 * SGID and update the global ibdm structure.
   1429 		 */
   1430 		new_paths = ibdm_get_reachable_ports(port, hca_list);
   1431 		ibdm.ibdm_ngids += new_paths;
   1432 	}
   1433 	mutex_exit(&ibdm.ibdm_hl_mutex);
   1434 
   1435 	mutex_enter(&ibdm.ibdm_mutex);
   1436 	ibdm.ibdm_ngid_probes_in_progress += ibdm.ibdm_ngids;
   1437 	mutex_exit(&ibdm.ibdm_mutex);
   1438 
   1439 	/* Send a request to probe GIDs asynchronously. */
   1440 	for (gid_info = ibdm.ibdm_dp_gidlist_head; gid_info;
   1441 	    gid_info = gid_info->gl_next) {
   1442 		mutex_enter(&gid_info->gl_mutex);
   1443 		gid_info->gl_reprobe_flag = reprobe_flag;
   1444 		mutex_exit(&gid_info->gl_mutex);
   1445 
   1446 		/* process newly encountered GIDs */
   1447 		tid = taskq_dispatch(system_taskq, ibdm_probe_gid_thread,
   1448 		    (void *)gid_info, TQ_NOSLEEP);
   1449 		IBTF_DPRINTF_L4("ibdm", "\tsweep_fabric: gid_info = %p"
   1450 		    " taskq_id = %x", gid_info, tid);
   1451 		/* taskq failed to dispatch call it directly */
   1452 		if (tid == NULL)
   1453 			ibdm_probe_gid_thread((void *)gid_info);
   1454 	}
   1455 
   1456 	mutex_enter(&ibdm.ibdm_mutex);
   1457 	ibdm_wait_probe_completion();
   1458 
   1459 	/*
   1460 	 * Update the properties, if reprobe_flag is set
   1461 	 * Skip if gl_reprobe_flag is set, this will be
   1462 	 * a re-inserted / new GID, for which notifications
   1463 	 * have already been send.
   1464 	 */
   1465 	if (reprobe_flag) {
   1466 		for (gid_info = ibdm.ibdm_dp_gidlist_head; gid_info;
   1467 		    gid_info = gid_info->gl_next) {
   1468 			if (gid_info->gl_iou == NULL)
   1469 				continue;
   1470 			if (gid_info->gl_reprobe_flag) {
   1471 				gid_info->gl_reprobe_flag = 0;
   1472 				continue;
   1473 			}
   1474 
   1475 			niocs = gid_info->gl_iou->iou_info.iou_num_ctrl_slots;
   1476 			for (ii = 0; ii < niocs; ii++) {
   1477 				ioc = IBDM_GIDINFO2IOCINFO(gid_info, ii);
   1478 				if (ioc)
   1479 					ibdm_reprobe_update_port_srv(ioc,
   1480 					    gid_info);
   1481 			}
   1482 		}
   1483 	} else if (ibdm.ibdm_prev_iou) {
   1484 		ibdm_ioc_info_t	*ioc_list;
   1485 
   1486 		/*
   1487 		 * Get the list of IOCs which have changed.
   1488 		 * If any IOCs have changed, Notify IBNexus
   1489 		 */
   1490 		ibdm.ibdm_prev_iou = 0;
   1491 		ioc_list = ibdm_handle_prev_iou();
   1492 		if (ioc_list) {
   1493 			if (ibdm.ibdm_ibnex_callback != NULL) {
   1494 				(*ibdm.ibdm_ibnex_callback)(
   1495 				    (void *)ioc_list,
   1496 				    IBDM_EVENT_IOC_PROP_UPDATE);
   1497 			}
   1498 		}
   1499 	}
   1500 
   1501 	ibdm_dump_sweep_fabric_timestamp(1);
   1502 
   1503 	ibdm.ibdm_busy &= ~IBDM_BUSY;
   1504 	cv_broadcast(&ibdm.ibdm_busy_cv);
   1505 	IBTF_DPRINTF_L5("ibdm", "\tsweep_fabric: EXIT");
   1506 }
   1507 
   1508 
   1509 /*
   1510  * ibdm_is_cisco:
   1511  * 	Check if this is a Cisco device or not.
   1512  */
   1513 static boolean_t
   1514 ibdm_is_cisco(ib_guid_t guid)
   1515 {
   1516 	if ((guid >> IBDM_OUI_GUID_SHIFT) == IBDM_CISCO_COMPANY_ID)
   1517 		return (B_TRUE);
   1518 	return (B_FALSE);
   1519 }
   1520 
   1521 
   1522 /*
   1523  * ibdm_is_cisco_switch:
   1524  * 	Check if this switch is a CISCO switch or not.
   1525  * 	Note that if this switch is already activated, ibdm_is_cisco_switch()
   1526  * 	returns B_FALSE not to re-activate it again.
   1527  */
   1528 static boolean_t
   1529 ibdm_is_cisco_switch(ibdm_dp_gidinfo_t *gid_info)
   1530 {
   1531 	int company_id, device_id;
   1532 	ASSERT(gid_info != 0);
   1533 	ASSERT(MUTEX_HELD(&gid_info->gl_mutex));
   1534 
   1535 	/*
   1536 	 * If this switch is already activated, don't re-activate it.
   1537 	 */
   1538 	if (gid_info->gl_flag & IBDM_CISCO_PROBE_DONE)
   1539 		return (B_FALSE);
   1540 
   1541 	/*
   1542 	 * Check if this switch is a Cisco FC GW or not.
   1543 	 * Use the node guid (the OUI part) instead of the vendor id
   1544 	 * since the vendor id is zero in practice.
   1545 	 */
   1546 	company_id = gid_info->gl_nodeguid >> IBDM_OUI_GUID_SHIFT;
   1547 	device_id = gid_info->gl_devid;
   1548 
   1549 	if (company_id == IBDM_CISCO_COMPANY_ID &&
   1550 	    device_id == IBDM_CISCO_DEVICE_ID)
   1551 		return (B_TRUE);
   1552 	return (B_FALSE);
   1553 }
   1554 
   1555 
   1556 /*
   1557  * ibdm_probe_gid_thread:
   1558  *	thread that does the actual work for sweeping the fabric
   1559  *	for a given GID
   1560  */
   1561 static void
   1562 ibdm_probe_gid_thread(void *args)
   1563 {
   1564 	int			reprobe_flag;
   1565 	ib_guid_t		node_guid;
   1566 	ib_guid_t		port_guid;
   1567 	ibdm_dp_gidinfo_t	*gid_info;
   1568 
   1569 	gid_info = (ibdm_dp_gidinfo_t *)args;
   1570 	reprobe_flag = gid_info->gl_reprobe_flag;
   1571 	IBTF_DPRINTF_L4("ibdm", "\tprobe_gid_thread: gid_info = %p, flag = %d",
   1572 	    gid_info, reprobe_flag);
   1573 	ASSERT(gid_info != NULL);
   1574 	ASSERT(gid_info->gl_pending_cmds == 0);
   1575 
   1576 	if (gid_info->gl_state != IBDM_GID_PROBE_NOT_DONE &&
   1577 	    reprobe_flag == 0) {
   1578 		/*
   1579 		 * This GID may have been already probed. Send
   1580 		 * in a CLP to check if IOUnitInfo changed?
   1581 		 * Explicitly set gl_reprobe_flag to 0 so that
   1582 		 * IBnex is not notified on completion
   1583 		 */
   1584 		if (gid_info->gl_state == IBDM_GID_PROBING_COMPLETE) {
   1585 			IBTF_DPRINTF_L4("ibdm", "\tprobe_gid_thread: "
   1586 			    "get new IOCs information");
   1587 			mutex_enter(&gid_info->gl_mutex);
   1588 			gid_info->gl_pending_cmds++;
   1589 			gid_info->gl_state = IBDM_GET_IOUNITINFO;
   1590 			gid_info->gl_reprobe_flag = 0;
   1591 			mutex_exit(&gid_info->gl_mutex);
   1592 			if (ibdm_send_iounitinfo(gid_info) != IBDM_SUCCESS) {
   1593 				mutex_enter(&gid_info->gl_mutex);
   1594 				--gid_info->gl_pending_cmds;
   1595 				mutex_exit(&gid_info->gl_mutex);
   1596 				mutex_enter(&ibdm.ibdm_mutex);
   1597 				--ibdm.ibdm_ngid_probes_in_progress;
   1598 				ibdm_wakeup_probe_gid_cv();
   1599 				mutex_exit(&ibdm.ibdm_mutex);
   1600 			}
   1601 		} else {
   1602 			mutex_enter(&ibdm.ibdm_mutex);
   1603 			--ibdm.ibdm_ngid_probes_in_progress;
   1604 			ibdm_wakeup_probe_gid_cv();
   1605 			mutex_exit(&ibdm.ibdm_mutex);
   1606 		}
   1607 		return;
   1608 	} else if (reprobe_flag && gid_info->gl_state ==
   1609 	    IBDM_GID_PROBING_COMPLETE) {
   1610 		/*
   1611 		 * Reprobe all IOCs for the GID which has completed
   1612 		 * probe. Skip other port GIDs to same IOU.
   1613 		 * Explicitly set gl_reprobe_flag to 0 so that
   1614 		 * IBnex is not notified on completion
   1615 		 */
   1616 		ibdm_ioc_info_t *ioc_info;
   1617 		uint8_t		niocs, ii;
   1618 
   1619 		ASSERT(gid_info->gl_iou);
   1620 		mutex_enter(&gid_info->gl_mutex);
   1621 		niocs = gid_info->gl_iou->iou_info.iou_num_ctrl_slots;
   1622 		gid_info->gl_state = IBDM_GET_IOC_DETAILS;
   1623 		gid_info->gl_pending_cmds += niocs;
   1624 		gid_info->gl_reprobe_flag = 0;
   1625 		mutex_exit(&gid_info->gl_mutex);
   1626 		for (ii = 0; ii < niocs; ii++) {
   1627 			uchar_t			slot_info;
   1628 			ib_dm_io_unitinfo_t	*giou_info;
   1629 
   1630 			/*
   1631 			 * Check whether IOC is present in the slot
   1632 			 * Series of nibbles (in the field
   1633 			 * iou_ctrl_list) represents a slot in the
   1634 			 * IOU.
   1635 			 * Byte format: 76543210
   1636 			 * Bits 0-3 of first byte represent Slot 2
   1637 			 * bits 4-7 of first byte represent slot 1,
   1638 			 * bits 0-3 of second byte represent slot 4
   1639 			 * and so on
   1640 			 * Each 4-bit nibble has the following meaning
   1641 			 * 0x0 : IOC not installed
   1642 			 * 0x1 : IOC is present
   1643 			 * 0xf : Slot does not exist
   1644 			 * and all other values are reserved.
   1645 			 */
   1646 			ioc_info = IBDM_GIDINFO2IOCINFO(gid_info, ii);
   1647 			giou_info = &gid_info->gl_iou->iou_info;
   1648 			slot_info = giou_info->iou_ctrl_list[(ii/2)];
   1649 			if ((ii % 2) == 0)
   1650 				slot_info = (slot_info >> 4);
   1651 
   1652 			if ((slot_info & 0xf) != 1) {
   1653 				ioc_info->ioc_state =
   1654 				    IBDM_IOC_STATE_PROBE_FAILED;
   1655 				ibdm_gid_decr_pending(gid_info);
   1656 				continue;
   1657 			}
   1658 
   1659 			if (ibdm_send_ioc_profile(gid_info, ii) !=
   1660 			    IBDM_SUCCESS) {
   1661 				ibdm_gid_decr_pending(gid_info);
   1662 			}
   1663 		}
   1664 
   1665 		return;
   1666 	} else if (gid_info->gl_state != IBDM_GID_PROBE_NOT_DONE) {
   1667 		mutex_enter(&ibdm.ibdm_mutex);
   1668 		--ibdm.ibdm_ngid_probes_in_progress;
   1669 		ibdm_wakeup_probe_gid_cv();
   1670 		mutex_exit(&ibdm.ibdm_mutex);
   1671 		return;
   1672 	}
   1673 
   1674 	/*
   1675 	 * Check whether the destination GID supports DM agents. If
   1676 	 * not, stop probing the GID and continue with the next GID
   1677 	 * in the list.
   1678 	 */
   1679 	if (ibdm_is_dev_mgt_supported(gid_info) != IBDM_SUCCESS) {
   1680 		mutex_enter(&gid_info->gl_mutex);
   1681 		gid_info->gl_state = IBDM_GID_PROBING_FAILED;
   1682 		gid_info->gl_is_dm_capable = B_FALSE;
   1683 		mutex_exit(&gid_info->gl_mutex);
   1684 		ibdm_delete_glhca_list(gid_info);
   1685 		mutex_enter(&ibdm.ibdm_mutex);
   1686 		--ibdm.ibdm_ngid_probes_in_progress;
   1687 		ibdm_wakeup_probe_gid_cv();
   1688 		mutex_exit(&ibdm.ibdm_mutex);
   1689 		return;
   1690 	}
   1691 
   1692 	/*
   1693 	 * This GID is Device management capable
   1694 	 */
   1695 	mutex_enter(&gid_info->gl_mutex);
   1696 	gid_info->gl_is_dm_capable = B_TRUE;
   1697 	mutex_exit(&gid_info->gl_mutex);
   1698 
   1699 	/* Get the nodeguid and portguid of the port */
   1700 	if (ibdm_get_node_port_guids(gid_info->gl_sa_hdl, gid_info->gl_dlid,
   1701 	    &node_guid, &port_guid) != IBDM_SUCCESS) {
   1702 		mutex_enter(&gid_info->gl_mutex);
   1703 		gid_info->gl_state = IBDM_GID_PROBING_FAILED;
   1704 		mutex_exit(&gid_info->gl_mutex);
   1705 		ibdm_delete_glhca_list(gid_info);
   1706 		mutex_enter(&ibdm.ibdm_mutex);
   1707 		--ibdm.ibdm_ngid_probes_in_progress;
   1708 		ibdm_wakeup_probe_gid_cv();
   1709 		mutex_exit(&ibdm.ibdm_mutex);
   1710 		return;
   1711 	}
   1712 
   1713 	/*
   1714 	 * Check whether we already knew about this NodeGuid
   1715 	 * If so, do not probe the GID and continue with the
   1716 	 * next  GID  in the gid  list. Set the GID state to
   1717 	 * probing done.
   1718 	 */
   1719 	mutex_enter(&ibdm.ibdm_mutex);
   1720 	gid_info->gl_nodeguid = node_guid;
   1721 	gid_info->gl_portguid = port_guid;
   1722 	if (ibdm_check_dest_nodeguid(gid_info) != NULL) {
   1723 		mutex_exit(&ibdm.ibdm_mutex);
   1724 		mutex_enter(&gid_info->gl_mutex);
   1725 		gid_info->gl_state = IBDM_GID_PROBING_SKIPPED;
   1726 		mutex_exit(&gid_info->gl_mutex);
   1727 		ibdm_delete_glhca_list(gid_info);
   1728 		mutex_enter(&ibdm.ibdm_mutex);
   1729 		--ibdm.ibdm_ngid_probes_in_progress;
   1730 		ibdm_wakeup_probe_gid_cv();
   1731 		mutex_exit(&ibdm.ibdm_mutex);
   1732 		return;
   1733 	}
   1734 	ibdm_add_to_gl_gid(gid_info, gid_info);
   1735 	mutex_exit(&ibdm.ibdm_mutex);
   1736 
   1737 	/*
   1738 	 * New or reinserted GID : Enable notification to IBnex
   1739 	 */
   1740 	mutex_enter(&gid_info->gl_mutex);
   1741 	gid_info->gl_reprobe_flag = 1;
   1742 
   1743 	/*
   1744 	 * A Cisco FC GW needs the special handling to get IOUnitInfo.
   1745 	 */
   1746 	if (ibdm_is_cisco_switch(gid_info)) {
   1747 		gid_info->gl_pending_cmds++;
   1748 		gid_info->gl_state = IBDM_SET_CLASSPORTINFO;
   1749 		mutex_exit(&gid_info->gl_mutex);
   1750 
   1751 		if (ibdm_set_classportinfo(gid_info) != IBDM_SUCCESS) {
   1752 			mutex_enter(&gid_info->gl_mutex);
   1753 			gid_info->gl_state = IBDM_GID_PROBING_FAILED;
   1754 			--gid_info->gl_pending_cmds;
   1755 			mutex_exit(&gid_info->gl_mutex);
   1756 
   1757 			/* free the hca_list on this gid_info */
   1758 			ibdm_delete_glhca_list(gid_info);
   1759 
   1760 			mutex_enter(&ibdm.ibdm_mutex);
   1761 			--ibdm.ibdm_ngid_probes_in_progress;
   1762 			ibdm_wakeup_probe_gid_cv();
   1763 			mutex_exit(&ibdm.ibdm_mutex);
   1764 
   1765 			return;
   1766 		}
   1767 
   1768 		mutex_enter(&gid_info->gl_mutex);
   1769 		ibdm_wait_cisco_probe_completion(gid_info);
   1770 
   1771 		IBTF_DPRINTF_L4("ibdm", "\tibdm_probe_gid_thread: "
   1772 		    "CISCO Wakeup signal received");
   1773 	}
   1774 
   1775 	/* move on to the 'GET_CLASSPORTINFO' stage */
   1776 	gid_info->gl_pending_cmds++;
   1777 	gid_info->gl_state = IBDM_GET_CLASSPORTINFO;
   1778 	mutex_exit(&gid_info->gl_mutex);
   1779 
   1780 	IBTF_DPRINTF_L3(ibdm_string, "\tibdm_probe_gid_thread: "
   1781 	    "%d: gid_info %p gl_state %d pending_cmds %d",
   1782 	    __LINE__, gid_info, gid_info->gl_state,
   1783 	    gid_info->gl_pending_cmds);
   1784 
   1785 	/*
   1786 	 * Send ClassPortInfo request to the GID asynchronously.
   1787 	 */
   1788 	if (ibdm_send_classportinfo(gid_info) != IBDM_SUCCESS) {
   1789 
   1790 		mutex_enter(&gid_info->gl_mutex);
   1791 		gid_info->gl_state = IBDM_GID_PROBING_FAILED;
   1792 		--gid_info->gl_pending_cmds;
   1793 		mutex_exit(&gid_info->gl_mutex);
   1794 
   1795 		/* free the hca_list on this gid_info */
   1796 		ibdm_delete_glhca_list(gid_info);
   1797 
   1798 		mutex_enter(&ibdm.ibdm_mutex);
   1799 		--ibdm.ibdm_ngid_probes_in_progress;
   1800 		ibdm_wakeup_probe_gid_cv();
   1801 		mutex_exit(&ibdm.ibdm_mutex);
   1802 
   1803 		return;
   1804 	}
   1805 }
   1806 
   1807 
   1808 /*
   1809  * ibdm_check_dest_nodeguid
   1810  *	Searches for the NodeGuid in the GID list
   1811  *	Returns matching gid_info if found and otherwise NULL
   1812  *
   1813  *	This function is called to handle new GIDs discovered
   1814  *	during device sweep / probe or for GID_AVAILABLE event.
   1815  *
   1816  *	Parameter :
   1817  *		gid_info	GID to check
   1818  */
   1819 static ibdm_dp_gidinfo_t *
   1820 ibdm_check_dest_nodeguid(ibdm_dp_gidinfo_t *gid_info)
   1821 {
   1822 	ibdm_dp_gidinfo_t	*gid_list;
   1823 	ibdm_gid_t		*tmp;
   1824 
   1825 	IBTF_DPRINTF_L4("ibdm", "\tcheck_dest_nodeguid");
   1826 
   1827 	gid_list = ibdm.ibdm_dp_gidlist_head;
   1828 	while (gid_list) {
   1829 		if ((gid_list != gid_info) &&
   1830 		    (gid_info->gl_nodeguid == gid_list->gl_nodeguid)) {
   1831 			IBTF_DPRINTF_L4("ibdm",
   1832 			    "\tcheck_dest_nodeguid: NodeGuid is present");
   1833 
   1834 			/* Add to gid_list */
   1835 			tmp = kmem_zalloc(sizeof (ibdm_gid_t),
   1836 			    KM_SLEEP);
   1837 			tmp->gid_dgid_hi = gid_info->gl_dgid_hi;
   1838 			tmp->gid_dgid_lo = gid_info->gl_dgid_lo;
   1839 			tmp->gid_next = gid_list->gl_gid;
   1840 			gid_list->gl_gid = tmp;
   1841 			gid_list->gl_ngids++;
   1842 			return (gid_list);
   1843 		}
   1844 
   1845 		gid_list = gid_list->gl_next;
   1846 	}
   1847 
   1848 	return (NULL);
   1849 }
   1850 
   1851 
   1852 /*
   1853  * ibdm_is_dev_mgt_supported
   1854  *	Get the PortInfo attribute (SA Query)
   1855  *	Check "CompatabilityMask" field in the Portinfo.
   1856  *	Return IBDM_SUCCESS if DM MAD's supported (if bit 19 set)
   1857  *	by the port, otherwise IBDM_FAILURE
   1858  */
   1859 static int
   1860 ibdm_is_dev_mgt_supported(ibdm_dp_gidinfo_t *gid_info)
   1861 {
   1862 	int			ret;
   1863 	size_t			length = 0;
   1864 	sa_portinfo_record_t	req, *resp = NULL;
   1865 	ibmf_saa_access_args_t	qargs;
   1866 
   1867 	bzero(&req, sizeof (sa_portinfo_record_t));
   1868 	req.EndportLID	= gid_info->gl_dlid;
   1869 
   1870 	qargs.sq_attr_id	= SA_PORTINFORECORD_ATTRID;
   1871 	qargs.sq_access_type	= IBMF_SAA_RETRIEVE;
   1872 	qargs.sq_component_mask = SA_PORTINFO_COMPMASK_PORTLID;
   1873 	qargs.sq_template	= &req;
   1874 	qargs.sq_callback	= NULL;
   1875 	qargs.sq_callback_arg	= NULL;
   1876 
   1877 	ret = ibmf_sa_access(gid_info->gl_sa_hdl,
   1878 	    &qargs, 0, &length, (void **)&resp);
   1879 
   1880 	if ((ret != IBMF_SUCCESS) || (length == 0) || (resp == NULL)) {
   1881 		IBTF_DPRINTF_L2("ibdm", "\tis_dev_mgt_supported:"
   1882 		    "failed to get PORTINFO attribute %d", ret);
   1883 		return (IBDM_FAILURE);
   1884 	}
   1885 
   1886 	if (resp->PortInfo.CapabilityMask & SM_CAP_MASK_IS_DM_SUPPD) {
   1887 		IBTF_DPRINTF_L4("ibdm", "\tis_dev_mgt_supported: SUPPD !!");
   1888 		ret = IBDM_SUCCESS;
   1889 	} else {
   1890 		IBTF_DPRINTF_L4("ibdm", "\tis_dev_mgt_supported: "
   1891 		    "Not SUPPD !!, cap 0x%x", resp->PortInfo.CapabilityMask);
   1892 		ret = IBDM_FAILURE;
   1893 	}
   1894 	kmem_free(resp, length);
   1895 	return (ret);
   1896 }
   1897 
   1898 
   1899 /*
   1900  * ibdm_get_node_port_guids()
   1901  *	Get the NodeInfoRecord of the port
   1902  *	Save NodeGuid and PortGUID values in the GID list structure.
   1903  *	Return IBDM_SUCCESS/IBDM_FAILURE
   1904  */
   1905 static int
   1906 ibdm_get_node_port_guids(ibmf_saa_handle_t sa_hdl, ib_lid_t dlid,
   1907     ib_guid_t *node_guid, ib_guid_t *port_guid)
   1908 {
   1909 	int			ret;
   1910 	size_t			length = 0;
   1911 	sa_node_record_t	req, *resp = NULL;
   1912 	ibmf_saa_access_args_t	qargs;
   1913 
   1914 	IBTF_DPRINTF_L4("ibdm", "\tget_node_port_guids");
   1915 
   1916 	bzero(&req, sizeof (sa_node_record_t));
   1917 	req.LID = dlid;
   1918 
   1919 	qargs.sq_attr_id	= SA_NODERECORD_ATTRID;
   1920 	qargs.sq_access_type	= IBMF_SAA_RETRIEVE;
   1921 	qargs.sq_component_mask = SA_NODEINFO_COMPMASK_NODELID;
   1922 	qargs.sq_template	= &req;
   1923 	qargs.sq_callback	= NULL;
   1924 	qargs.sq_callback_arg	= NULL;
   1925 
   1926 	ret = ibmf_sa_access(sa_hdl, &qargs, 0, &length, (void **)&resp);
   1927 	if ((ret != IBMF_SUCCESS) || (length == 0) || (resp == NULL)) {
   1928 		IBTF_DPRINTF_L2("ibdm", "\tget_node_port_guids:"
   1929 		    " SA Retrieve Failed: %d", ret);
   1930 		return (IBDM_FAILURE);
   1931 	}
   1932 	IBTF_DPRINTF_L4("ibdm", "\tget_node_port_guids: NodeGuid %llx Port"
   1933 	    "GUID %llx", resp->NodeInfo.NodeGUID, resp->NodeInfo.NodeGUID);
   1934 
   1935 	*node_guid = resp->NodeInfo.NodeGUID;
   1936 	*port_guid = resp->NodeInfo.PortGUID;
   1937 	kmem_free(resp, length);
   1938 	return (IBDM_SUCCESS);
   1939 }
   1940 
   1941 
   1942 /*
   1943  * ibdm_get_reachable_ports()
   1944  *	Get list of the destination GID (and its path  records) by
   1945  *	querying the SA access.
   1946  *
   1947  *	Returns Number paths
   1948  */
   1949 static int
   1950 ibdm_get_reachable_ports(ibdm_port_attr_t *portinfo, ibdm_hca_list_t *hca)
   1951 {
   1952 	uint_t			ii, jj, nrecs;
   1953 	uint_t			npaths = 0;
   1954 	size_t			length;
   1955 	ib_gid_t		sgid;
   1956 	ibdm_pkey_tbl_t		*pkey_tbl;
   1957 	sa_path_record_t	*result;
   1958 	sa_path_record_t	*precp;
   1959 	ibdm_dp_gidinfo_t	*gid_info;
   1960 
   1961 	ASSERT(MUTEX_HELD(&ibdm.ibdm_hl_mutex));
   1962 	IBTF_DPRINTF_L4("ibdm", "\tget_reachable_ports: portinfo %p", portinfo);
   1963 
   1964 	sgid.gid_prefix = portinfo->pa_sn_prefix;
   1965 	sgid.gid_guid	= portinfo->pa_port_guid;
   1966 
   1967 	/* get reversible paths */
   1968 	if (portinfo->pa_sa_hdl && ibmf_saa_paths_from_gid(portinfo->pa_sa_hdl,
   1969 	    sgid, IBMF_SAA_PKEY_WC, B_TRUE, 0, &nrecs, &length, &result)
   1970 	    != IBMF_SUCCESS) {
   1971 		IBTF_DPRINTF_L2("ibdm",
   1972 		    "\tget_reachable_ports: Getting path records failed");
   1973 		return (0);
   1974 	}
   1975 
   1976 	for (ii = 0; ii < nrecs; ii++) {
   1977 		sa_node_record_t *nrec;
   1978 		size_t length;
   1979 
   1980 		precp = &result[ii];
   1981 		if ((gid_info = ibdm_check_dgid(precp->DGID.gid_guid,
   1982 		    precp->DGID.gid_prefix)) != NULL) {
   1983 			IBTF_DPRINTF_L5("ibdm", "\tget_reachable_ports: "
   1984 			    "Already exists nrecs %d, ii %d", nrecs, ii);
   1985 			ibdm_addto_glhcalist(gid_info, hca);
   1986 			continue;
   1987 		}
   1988 		/*
   1989 		 * This is a new GID. Allocate a GID structure and
   1990 		 * initialize the structure
   1991 		 * gl_state is initialized to IBDM_GID_PROBE_NOT_DONE (0)
   1992 		 * by kmem_zalloc call
   1993 		 */
   1994 		gid_info = kmem_zalloc(sizeof (ibdm_dp_gidinfo_t), KM_SLEEP);
   1995 		mutex_init(&gid_info->gl_mutex, NULL, MUTEX_DEFAULT, NULL);
   1996 		cv_init(&gid_info->gl_probe_cv, NULL, CV_DRIVER, NULL);
   1997 		gid_info->gl_dgid_hi		= precp->DGID.gid_prefix;
   1998 		gid_info->gl_dgid_lo		= precp->DGID.gid_guid;
   1999 		gid_info->gl_sgid_hi		= precp->SGID.gid_prefix;
   2000 		gid_info->gl_sgid_lo		= precp->SGID.gid_guid;
   2001 		gid_info->gl_p_key		= precp->P_Key;
   2002 		gid_info->gl_sa_hdl		= portinfo->pa_sa_hdl;
   2003 		gid_info->gl_ibmf_hdl		= portinfo->pa_ibmf_hdl;
   2004 		gid_info->gl_slid		= precp->SLID;
   2005 		gid_info->gl_dlid		= precp->DLID;
   2006 		gid_info->gl_transactionID	= (++ibdm.ibdm_transactionID)
   2007 		    << IBDM_GID_TRANSACTIONID_SHIFT;
   2008 		gid_info->gl_min_transactionID  = gid_info->gl_transactionID;
   2009 		gid_info->gl_max_transactionID  = (ibdm.ibdm_transactionID +1)
   2010 		    << IBDM_GID_TRANSACTIONID_SHIFT;
   2011 		gid_info->gl_SL			= precp->SL;
   2012 
   2013 		/*
   2014 		 * get the node record with this guid if the destination
   2015 		 * device is a Cisco one.
   2016 		 */
   2017 		if (ibdm_is_cisco(precp->DGID.gid_guid) &&
   2018 		    (gid_info->gl_nodeguid == 0 || gid_info->gl_devid == 0) &&
   2019 		    ibdm_get_node_record_by_port(portinfo->pa_sa_hdl,
   2020 		    precp->DGID.gid_guid, &nrec, &length) == IBDM_SUCCESS) {
   2021 			gid_info->gl_nodeguid = nrec->NodeInfo.NodeGUID;
   2022 			gid_info->gl_devid = nrec->NodeInfo.DeviceID;
   2023 			kmem_free(nrec, length);
   2024 		}
   2025 
   2026 		ibdm_addto_glhcalist(gid_info,  hca);
   2027 
   2028 		ibdm_dump_path_info(precp);
   2029 
   2030 		gid_info->gl_qp_hdl = NULL;
   2031 		ASSERT(portinfo->pa_pkey_tbl != NULL &&
   2032 		    portinfo->pa_npkeys != 0);
   2033 
   2034 		for (jj = 0; jj < portinfo->pa_npkeys; jj++) {
   2035 			pkey_tbl = &portinfo->pa_pkey_tbl[jj];
   2036 			if ((gid_info->gl_p_key == pkey_tbl->pt_pkey) &&
   2037 			    (pkey_tbl->pt_qp_hdl != NULL)) {
   2038 				gid_info->gl_qp_hdl = pkey_tbl->pt_qp_hdl;
   2039 				break;
   2040 			}
   2041 		}
   2042 
   2043 		/*
   2044 		 * QP handle for GID not initialized. No matching Pkey
   2045 		 * was found!! ibdm should *not* hit this case. Flag an
   2046 		 * error and drop the GID if ibdm does encounter this.
   2047 		 */
   2048 		if (gid_info->gl_qp_hdl == NULL) {
   2049 			IBTF_DPRINTF_L2(ibdm_string,
   2050 			    "\tget_reachable_ports: No matching Pkey");
   2051 			ibdm_delete_gidinfo(gid_info);
   2052 			continue;
   2053 		}
   2054 		if (ibdm.ibdm_dp_gidlist_head == NULL) {
   2055 			ibdm.ibdm_dp_gidlist_head = gid_info;
   2056 			ibdm.ibdm_dp_gidlist_tail = gid_info;
   2057 		} else {
   2058 			ibdm.ibdm_dp_gidlist_tail->gl_next = gid_info;
   2059 			gid_info->gl_prev = ibdm.ibdm_dp_gidlist_tail;
   2060 			ibdm.ibdm_dp_gidlist_tail = gid_info;
   2061 		}
   2062 		npaths++;
   2063 	}
   2064 	kmem_free(result, length);
   2065 	IBTF_DPRINTF_L4("ibdm", "\tget_reachable_ports: npaths = %d", npaths);
   2066 	return (npaths);
   2067 }
   2068 
   2069 
   2070 /*
   2071  * ibdm_check_dgid()
   2072  *	Look in the global list to check whether we know this DGID already
   2073  *	Return IBDM_GID_PRESENT/IBDM_GID_NOT_PRESENT
   2074  */
   2075 static ibdm_dp_gidinfo_t *
   2076 ibdm_check_dgid(ib_guid_t guid, ib_sn_prefix_t prefix)
   2077 {
   2078 	ibdm_dp_gidinfo_t	*gid_list;
   2079 
   2080 	for (gid_list = ibdm.ibdm_dp_gidlist_head; gid_list;
   2081 	    gid_list = gid_list->gl_next) {
   2082 		if ((guid == gid_list->gl_dgid_lo) &&
   2083 		    (prefix == gid_list->gl_dgid_hi)) {
   2084 			break;
   2085 		}
   2086 	}
   2087 	return (gid_list);
   2088 }
   2089 
   2090 
   2091 /*
   2092  * ibdm_find_gid()
   2093  *	Look in the global list to find a GID entry with matching
   2094  *	port & node GUID.
   2095  *	Return pointer to gidinfo if found, else return NULL
   2096  */
   2097 static ibdm_dp_gidinfo_t *
   2098 ibdm_find_gid(ib_guid_t nodeguid, ib_guid_t portguid)
   2099 {
   2100 	ibdm_dp_gidinfo_t	*gid_list;
   2101 
   2102 	IBTF_DPRINTF_L4("ibdm", "ibdm_find_gid(%llx, %llx)\n",
   2103 	    nodeguid, portguid);
   2104 
   2105 	for (gid_list = ibdm.ibdm_dp_gidlist_head; gid_list;
   2106 	    gid_list = gid_list->gl_next) {
   2107 		if ((portguid == gid_list->gl_portguid) &&
   2108 		    (nodeguid == gid_list->gl_nodeguid)) {
   2109 			break;
   2110 		}
   2111 	}
   2112 
   2113 	IBTF_DPRINTF_L4("ibdm", "ibdm_find_gid : returned %p\n",
   2114 	    gid_list);
   2115 	return (gid_list);
   2116 }
   2117 
   2118 
   2119 /*
   2120  * ibdm_set_classportinfo()
   2121  *	ibdm_set_classportinfo() is a function to activate a Cisco FC GW
   2122  *	by sending the setClassPortInfo request with the trapLID, trapGID
   2123  *	and etc. to the gateway since the gateway doesn't provide the IO
   2124  *	Unit Information othewise. This behavior is the Cisco specific one,
   2125  *	and this function is called to a Cisco FC GW only.
   2126  *	Returns IBDM_SUCCESS/IBDM_FAILURE
   2127  */
   2128 static int
   2129 ibdm_set_classportinfo(ibdm_dp_gidinfo_t *gid_info)
   2130 {
   2131 	ibmf_msg_t		*msg;
   2132 	ib_mad_hdr_t		*hdr;
   2133 	ibdm_timeout_cb_args_t	*cb_args;
   2134 	void			*data;
   2135 	ib_mad_classportinfo_t *cpi;
   2136 
   2137 	IBTF_DPRINTF_L4("ibdm",
   2138 	    "\tset_classportinfo: gid info 0x%p", gid_info);
   2139 
   2140 	/*
   2141 	 * Send command to set classportinfo attribute. Allocate a IBMF
   2142 	 * packet and initialize the packet.
   2143 	 */
   2144 	if (ibmf_alloc_msg(gid_info->gl_ibmf_hdl, IBMF_ALLOC_SLEEP,
   2145 	    &msg) != IBMF_SUCCESS) {
   2146 		IBTF_DPRINTF_L4("ibdm", "\tset_classportinfo: pkt alloc fail");
   2147 		return (IBDM_FAILURE);
   2148 	}
   2149 
   2150 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*msg))
   2151 	ibdm_alloc_send_buffers(msg);
   2152 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*msg))
   2153 
   2154 	msg->im_local_addr.ia_local_lid		= gid_info->gl_slid;
   2155 	msg->im_local_addr.ia_remote_lid	= gid_info->gl_dlid;
   2156 	msg->im_local_addr.ia_remote_qno	= 1;
   2157 	msg->im_local_addr.ia_p_key		= gid_info->gl_p_key;
   2158 	msg->im_local_addr.ia_q_key		= IB_GSI_QKEY;
   2159 	msg->im_local_addr.ia_service_level	= gid_info->gl_SL;
   2160 
   2161 	hdr			= IBDM_OUT_IBMFMSG_MADHDR(msg);
   2162 	hdr->BaseVersion	= MAD_CLASS_BASE_VERS_1;
   2163 	hdr->MgmtClass		= MAD_MGMT_CLASS_DEV_MGT;
   2164 	hdr->ClassVersion	= IB_DM_CLASS_VERSION_1;
   2165 	hdr->R_Method		= IB_DM_DEVMGT_METHOD_SET;
   2166 	hdr->Status		= 0;
   2167 	hdr->TransactionID	= h2b64(gid_info->gl_transactionID);
   2168 	hdr->AttributeID	= h2b16(IB_DM_ATTR_CLASSPORTINFO);
   2169 	hdr->AttributeModifier	= 0;
   2170 
   2171 	data = msg->im_msgbufs_send.im_bufs_cl_data;
   2172 	cpi = (ib_mad_classportinfo_t *)data;
   2173 
   2174 	/*
   2175 	 * Set the classportinfo values to activate this Cisco FC GW.
   2176 	 */
   2177 	cpi->TrapGID_hi = h2b64(gid_info->gl_sgid_hi);
   2178 	cpi->TrapGID_lo = h2b64(gid_info->gl_sgid_lo);
   2179 	cpi->TrapLID = h2b16(gid_info->gl_slid);
   2180 	cpi->TrapSL = gid_info->gl_SL;
   2181 	cpi->TrapP_Key = h2b16(gid_info->gl_p_key);
   2182 	cpi->TrapQP = h2b32((((ibmf_alt_qp_t *)gid_info->gl_qp_hdl)->isq_qpn));
   2183 	cpi->TrapQ_Key = h2b32((((ibmf_alt_qp_t *)
   2184 	    gid_info->gl_qp_hdl)->isq_qkey));
   2185 
   2186 	cb_args = &gid_info->gl_cpi_cb_args;
   2187 	cb_args->cb_gid_info = gid_info;
   2188 	cb_args->cb_retry_count	= ibdm_dft_retry_cnt;
   2189 	cb_args->cb_req_type = IBDM_REQ_TYPE_CLASSPORTINFO;
   2190 
   2191 	mutex_enter(&gid_info->gl_mutex);
   2192 	gid_info->gl_timeout_id = timeout(ibdm_pkt_timeout_hdlr,
   2193 	    cb_args, IBDM_TIMEOUT_VALUE(ibdm_dft_timeout));
   2194 	mutex_exit(&gid_info->gl_mutex);
   2195 
   2196 	IBTF_DPRINTF_L5("ibdm", "\tset_classportinfo: "
   2197 	    "timeout id %x", gid_info->gl_timeout_id);
   2198 
   2199 	if (ibmf_msg_transport(gid_info->gl_ibmf_hdl, gid_info->gl_qp_hdl,
   2200 	    msg, NULL, ibdm_ibmf_send_cb, cb_args, 0) != IBMF_SUCCESS) {
   2201 		IBTF_DPRINTF_L2("ibdm",
   2202 		    "\tset_classportinfo: ibmf send failed");
   2203 		ibdm_ibmf_send_cb(gid_info->gl_ibmf_hdl, msg, cb_args);
   2204 	}
   2205 
   2206 	return (IBDM_SUCCESS);
   2207 }
   2208 
   2209 
   2210 /*
   2211  * ibdm_send_classportinfo()
   2212  *	Send classportinfo request. When the request is completed
   2213  *	IBMF calls ibdm_classportinfo_cb routine to inform about
   2214  *	the completion.
   2215  *	Returns IBDM_SUCCESS/IBDM_FAILURE
   2216  */
   2217 static int
   2218 ibdm_send_classportinfo(ibdm_dp_gidinfo_t *gid_info)
   2219 {
   2220 	ibmf_msg_t		*msg;
   2221 	ib_mad_hdr_t		*hdr;
   2222 	ibdm_timeout_cb_args_t	*cb_args;
   2223 
   2224 	IBTF_DPRINTF_L4("ibdm",
   2225 	    "\tsend_classportinfo: gid info 0x%p", gid_info);
   2226 
   2227 	/*
   2228 	 * Send command to get classportinfo attribute. Allocate a IBMF
   2229 	 * packet and initialize the packet.
   2230 	 */
   2231 	if (ibmf_alloc_msg(gid_info->gl_ibmf_hdl, IBMF_ALLOC_SLEEP,
   2232 	    &msg) != IBMF_SUCCESS) {
   2233 		IBTF_DPRINTF_L4("ibdm", "\tsend_classportinfo: pkt alloc fail");
   2234 		return (IBDM_FAILURE);
   2235 	}
   2236 
   2237 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*msg))
   2238 	ibdm_alloc_send_buffers(msg);
   2239 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*msg))
   2240 
   2241 	msg->im_local_addr.ia_local_lid		= gid_info->gl_slid;
   2242 	msg->im_local_addr.ia_remote_lid	= gid_info->gl_dlid;
   2243 	msg->im_local_addr.ia_remote_qno	= 1;
   2244 	msg->im_local_addr.ia_p_key		= gid_info->gl_p_key;
   2245 	msg->im_local_addr.ia_q_key		= IB_GSI_QKEY;
   2246 	msg->im_local_addr.ia_service_level	= gid_info->gl_SL;
   2247 
   2248 	hdr			= IBDM_OUT_IBMFMSG_MADHDR(msg);
   2249 	hdr->BaseVersion	= MAD_CLASS_BASE_VERS_1;
   2250 	hdr->MgmtClass		= MAD_MGMT_CLASS_DEV_MGT;
   2251 	hdr->ClassVersion	= IB_DM_CLASS_VERSION_1;
   2252 	hdr->R_Method		= IB_DM_DEVMGT_METHOD_GET;
   2253 	hdr->Status		= 0;
   2254 	hdr->TransactionID	= h2b64(gid_info->gl_transactionID);
   2255 	hdr->AttributeID	= h2b16(IB_DM_ATTR_CLASSPORTINFO);
   2256 	hdr->AttributeModifier	= 0;
   2257 
   2258 	cb_args = &gid_info->gl_cpi_cb_args;
   2259 	cb_args->cb_gid_info = gid_info;
   2260 	cb_args->cb_retry_count	= ibdm_dft_retry_cnt;
   2261 	cb_args->cb_req_type = IBDM_REQ_TYPE_CLASSPORTINFO;
   2262 
   2263 	mutex_enter(&gid_info->gl_mutex);
   2264 	gid_info->gl_timeout_id = timeout(ibdm_pkt_timeout_hdlr,
   2265 	    cb_args, IBDM_TIMEOUT_VALUE(ibdm_dft_timeout));
   2266 	mutex_exit(&gid_info->gl_mutex);
   2267 
   2268 	IBTF_DPRINTF_L5("ibdm", "\tsend_classportinfo: "
   2269 	    "timeout id %x", gid_info->gl_timeout_id);
   2270 
   2271 	if (ibmf_msg_transport(gid_info->gl_ibmf_hdl, gid_info->gl_qp_hdl,
   2272 	    msg, NULL, ibdm_ibmf_send_cb, cb_args, 0) != IBMF_SUCCESS) {
   2273 		IBTF_DPRINTF_L2("ibdm",
   2274 		    "\tsend_classportinfo: ibmf send failed");
   2275 		ibdm_ibmf_send_cb(gid_info->gl_ibmf_hdl, msg, cb_args);
   2276 	}
   2277 
   2278 	return (IBDM_SUCCESS);
   2279 }
   2280 
   2281 
   2282 /*
   2283  * ibdm_handle_setclassportinfo()
   2284  *	Invoked by the IBMF when setClassPortInfo request is completed.
   2285  */
   2286 static void
   2287 ibdm_handle_setclassportinfo(ibmf_handle_t ibmf_hdl,
   2288     ibmf_msg_t *msg, ibdm_dp_gidinfo_t *gid_info, int *flag)
   2289 {
   2290 	void			*data;
   2291 	timeout_id_t		timeout_id;
   2292 	ib_mad_classportinfo_t *cpi;
   2293 
   2294 	IBTF_DPRINTF_L4("ibdm", "\thandle_setclassportinfo:ibmf hdl "
   2295 	    "%p msg %p gid info %p", ibmf_hdl, msg, gid_info);
   2296 
   2297 	if (IBDM_IN_IBMFMSG_ATTR(msg) != IB_DM_ATTR_CLASSPORTINFO) {
   2298 		IBTF_DPRINTF_L4("ibdm", "\thandle_setclassportinfo: "
   2299 		    "Not a ClassPortInfo resp");
   2300 		*flag |= IBDM_IBMF_PKT_UNEXP_RESP;
   2301 		return;
   2302 	}
   2303 
   2304 	/*
   2305 	 * Verify whether timeout handler is created/active.
   2306 	 * If created/ active,  cancel the timeout  handler
   2307 	 */
   2308 	mutex_enter(&gid_info->gl_mutex);
   2309 	if (gid_info->gl_state != IBDM_SET_CLASSPORTINFO) {
   2310 		IBTF_DPRINTF_L2("ibdm", "\thandle_setclassportinfo:DUP resp");
   2311 		*flag |= IBDM_IBMF_PKT_DUP_RESP;
   2312 		mutex_exit(&gid_info->gl_mutex);
   2313 		return;
   2314 	}
   2315 	ibdm_bump_transactionID(gid_info);
   2316 
   2317 	gid_info->gl_iou_cb_args.cb_req_type = 0;
   2318 	if (gid_info->gl_timeout_id) {
   2319 		timeout_id = gid_info->gl_timeout_id;
   2320 		mutex_exit(&gid_info->gl_mutex);
   2321 		IBTF_DPRINTF_L5("ibdm", "handle_setlassportinfo: "
   2322 		    "gl_timeout_id = 0x%x", timeout_id);
   2323 		if (untimeout(timeout_id) == -1) {
   2324 			IBTF_DPRINTF_L2("ibdm", "handle_setclassportinfo: "
   2325 			    "untimeout gl_timeout_id failed");
   2326 		}
   2327 		mutex_enter(&gid_info->gl_mutex);
   2328 		gid_info->gl_timeout_id = 0;
   2329 	}
   2330 	mutex_exit(&gid_info->gl_mutex);
   2331 
   2332 	data = msg->im_msgbufs_recv.im_bufs_cl_data;
   2333 	cpi = (ib_mad_classportinfo_t *)data;
   2334 
   2335 	ibdm_dump_classportinfo(cpi);
   2336 }
   2337 
   2338 
   2339 /*
   2340  * ibdm_handle_classportinfo()
   2341  *	Invoked by the IBMF when the classportinfo request is completed.
   2342  */
   2343 static void
   2344 ibdm_handle_classportinfo(ibmf_handle_t ibmf_hdl,
   2345     ibmf_msg_t *msg, ibdm_dp_gidinfo_t *gid_info, int *flag)
   2346 {
   2347 	void			*data;
   2348 	timeout_id_t		timeout_id;
   2349 	ib_mad_hdr_t		*hdr;
   2350 	ib_mad_classportinfo_t *cpi;
   2351 
   2352 	IBTF_DPRINTF_L4("ibdm", "\thandle_classportinfo:ibmf hdl "
   2353 	    "%p msg %p gid info %p", ibmf_hdl, msg, gid_info);
   2354 
   2355 	if (IBDM_IN_IBMFMSG_ATTR(msg) != IB_DM_ATTR_CLASSPORTINFO) {
   2356 		IBTF_DPRINTF_L4("ibdm", "\thandle_classportinfo: "
   2357 		    "Not a ClassPortInfo resp");
   2358 		*flag |= IBDM_IBMF_PKT_UNEXP_RESP;
   2359 		return;
   2360 	}
   2361 
   2362 	/*
   2363 	 * Verify whether timeout handler is created/active.
   2364 	 * If created/ active,  cancel the timeout  handler
   2365 	 */
   2366 	mutex_enter(&gid_info->gl_mutex);
   2367 	ibdm_bump_transactionID(gid_info);
   2368 	if (gid_info->gl_state != IBDM_GET_CLASSPORTINFO) {
   2369 		IBTF_DPRINTF_L2("ibdm", "\thandle_classportinfo:DUP resp");
   2370 		*flag |= IBDM_IBMF_PKT_DUP_RESP;
   2371 		mutex_exit(&gid_info->gl_mutex);
   2372 		return;
   2373 	}
   2374 	gid_info->gl_iou_cb_args.cb_req_type = 0;
   2375 	if (gid_info->gl_timeout_id) {
   2376 		timeout_id = gid_info->gl_timeout_id;
   2377 		mutex_exit(&gid_info->gl_mutex);
   2378 		IBTF_DPRINTF_L5("ibdm", "handle_ioclassportinfo: "
   2379 		    "gl_timeout_id = 0x%x", timeout_id);
   2380 		if (untimeout(timeout_id) == -1) {
   2381 			IBTF_DPRINTF_L2("ibdm", "handle_classportinfo: "
   2382 			    "untimeout gl_timeout_id failed");
   2383 		}
   2384 		mutex_enter(&gid_info->gl_mutex);
   2385 		gid_info->gl_timeout_id = 0;
   2386 	}
   2387 	gid_info->gl_state = IBDM_GET_IOUNITINFO;
   2388 	gid_info->gl_pending_cmds++;
   2389 	mutex_exit(&gid_info->gl_mutex);
   2390 
   2391 	data = msg->im_msgbufs_recv.im_bufs_cl_data;
   2392 	cpi = (ib_mad_classportinfo_t *)data;
   2393 
   2394 	/*
   2395 	 * Cache the "RespTimeValue" and redirection information in the
   2396 	 * global gid list data structure. This cached information will
   2397 	 * be used to send any further requests to the GID.
   2398 	 */
   2399 	gid_info->gl_resp_timeout	=
   2400 	    (b2h32(cpi->RespTimeValue) & 0x1F);
   2401 
   2402 	gid_info->gl_redirected		= ((IBDM_IN_IBMFMSG_STATUS(msg) &
   2403 	    MAD_STATUS_REDIRECT_REQUIRED) ? B_TRUE: B_FALSE);
   2404 	gid_info->gl_redirect_dlid	= b2h16(cpi->RedirectLID);
   2405 	gid_info->gl_redirect_QP	= (b2h32(cpi->RedirectQP) & 0xffffff);
   2406 	gid_info->gl_redirect_pkey	= b2h16(cpi->RedirectP_Key);
   2407 	gid_info->gl_redirect_qkey	= b2h32(cpi->RedirectQ_Key);
   2408 	gid_info->gl_redirectGID_hi	= b2h64(cpi->RedirectGID_hi);
   2409 	gid_info->gl_redirectGID_lo	= b2h64(cpi->RedirectGID_lo);
   2410 	gid_info->gl_redirectSL		= cpi->RedirectSL;
   2411 
   2412 	ibdm_dump_classportinfo(cpi);
   2413 
   2414 	/*
   2415 	 * Send IOUnitInfo request
   2416 	 * Reuse previously allocated IBMF packet for sending ClassPortInfo
   2417 	 * Check whether DM agent on the remote node requested redirection
   2418 	 * If so, send the request to the redirect DGID/DLID/PKEY/QP.
   2419 	 */
   2420 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*msg))
   2421 	ibdm_alloc_send_buffers(msg);
   2422 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*msg))
   2423 	msg->im_local_addr.ia_local_lid	= gid_info->gl_slid;
   2424 	msg->im_local_addr.ia_remote_lid	= gid_info->gl_dlid;
   2425 
   2426 	if (gid_info->gl_redirected == B_TRUE) {
   2427 		if (gid_info->gl_redirect_dlid != 0) {
   2428 			msg->im_local_addr.ia_remote_lid =
   2429 			    gid_info->gl_redirect_dlid;
   2430 		}
   2431 		msg->im_local_addr.ia_remote_qno = gid_info->gl_redirect_QP;
   2432 		msg->im_local_addr.ia_p_key = gid_info->gl_redirect_pkey;
   2433 		msg->im_local_addr.ia_q_key = gid_info->gl_redirect_qkey;
   2434 		msg->im_local_addr.ia_service_level = gid_info->gl_redirectSL;
   2435 	} else {
   2436 		msg->im_local_addr.ia_remote_qno = 1;
   2437 		msg->im_local_addr.ia_p_key = gid_info->gl_p_key;
   2438 		msg->im_local_addr.ia_q_key = IB_GSI_QKEY;
   2439 		msg->im_local_addr.ia_service_level = gid_info->gl_SL;
   2440 	}
   2441 
   2442 	hdr			= IBDM_OUT_IBMFMSG_MADHDR(msg);
   2443 	hdr->BaseVersion	= MAD_CLASS_BASE_VERS_1;
   2444 	hdr->MgmtClass		= MAD_MGMT_CLASS_DEV_MGT;
   2445 	hdr->ClassVersion	= IB_DM_CLASS_VERSION_1;
   2446 	hdr->R_Method		= IB_DM_DEVMGT_METHOD_GET;
   2447 	hdr->Status		= 0;
   2448 	hdr->TransactionID	= h2b64(gid_info->gl_transactionID);
   2449 	hdr->AttributeID	= h2b16(IB_DM_ATTR_IO_UNITINFO);
   2450 	hdr->AttributeModifier	= 0;
   2451 
   2452 	gid_info->gl_iou_cb_args.cb_req_type = IBDM_REQ_TYPE_IOUINFO;
   2453 	gid_info->gl_iou_cb_args.cb_gid_info = gid_info;
   2454 	gid_info->gl_iou_cb_args.cb_retry_count = ibdm_dft_retry_cnt;
   2455 
   2456 	mutex_enter(&gid_info->gl_mutex);
   2457 	gid_info->gl_timeout_id = timeout(ibdm_pkt_timeout_hdlr,
   2458 	    &gid_info->gl_iou_cb_args, IBDM_TIMEOUT_VALUE(ibdm_dft_timeout));
   2459 	mutex_exit(&gid_info->gl_mutex);
   2460 
   2461 	IBTF_DPRINTF_L5("ibdm", "handle_classportinfo:"
   2462 	    "timeout %x", gid_info->gl_timeout_id);
   2463 
   2464 	if (ibmf_msg_transport(ibmf_hdl, gid_info->gl_qp_hdl, msg, NULL,
   2465 	    ibdm_ibmf_send_cb, &gid_info->gl_iou_cb_args, 0) != IBMF_SUCCESS) {
   2466 		IBTF_DPRINTF_L2("ibdm",
   2467 		    "\thandle_classportinfo: msg transport failed");
   2468 		ibdm_ibmf_send_cb(ibmf_hdl, msg, &gid_info->gl_iou_cb_args);
   2469 	}
   2470 	(*flag) |= IBDM_IBMF_PKT_REUSED;
   2471 }
   2472 
   2473 
   2474 /*
   2475  * ibdm_send_iounitinfo:
   2476  *	Sends a DM request to get IOU unitinfo.
   2477  */
   2478 static int
   2479 ibdm_send_iounitinfo(ibdm_dp_gidinfo_t *gid_info)
   2480 {
   2481 	ibmf_msg_t	*msg;
   2482 	ib_mad_hdr_t	*hdr;
   2483 
   2484 	IBTF_DPRINTF_L4("ibdm", "\tsend_iounitinfo: gid info 0x%p", gid_info);
   2485 
   2486 	/*
   2487 	 * Send command to get iounitinfo attribute. Allocate a IBMF
   2488 	 * packet and initialize the packet.
   2489 	 */
   2490 	if (ibmf_alloc_msg(gid_info->gl_ibmf_hdl, IBMF_ALLOC_SLEEP, &msg) !=
   2491 	    IBMF_SUCCESS) {
   2492 		IBTF_DPRINTF_L4("ibdm", "\tsend_iounitinfo: pkt alloc fail");
   2493 		return (IBDM_FAILURE);
   2494 	}
   2495 
   2496 	mutex_enter(&gid_info->gl_mutex);
   2497 	ibdm_bump_transactionID(gid_info);
   2498 	mutex_exit(&gid_info->gl_mutex);
   2499 
   2500 
   2501 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*msg))
   2502 	ibdm_alloc_send_buffers(msg);
   2503 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*msg))
   2504 	msg->im_local_addr.ia_local_lid		= gid_info->gl_slid;
   2505 	msg->im_local_addr.ia_remote_lid	= gid_info->gl_dlid;
   2506 	msg->im_local_addr.ia_remote_qno	= 1;
   2507 	msg->im_local_addr.ia_p_key		= gid_info->gl_p_key;
   2508 	msg->im_local_addr.ia_q_key		= IB_GSI_QKEY;
   2509 	msg->im_local_addr.ia_service_level	= gid_info->gl_SL;
   2510 
   2511 	hdr			= IBDM_OUT_IBMFMSG_MADHDR(msg);
   2512 	hdr->BaseVersion	= MAD_CLASS_BASE_VERS_1;
   2513 	hdr->MgmtClass		= MAD_MGMT_CLASS_DEV_MGT;
   2514 	hdr->ClassVersion	= IB_DM_CLASS_VERSION_1;
   2515 	hdr->R_Method		= IB_DM_DEVMGT_METHOD_GET;
   2516 	hdr->Status		= 0;
   2517 	hdr->TransactionID	= h2b64(gid_info->gl_transactionID);
   2518 	hdr->AttributeID	= h2b16(IB_DM_ATTR_IO_UNITINFO);
   2519 	hdr->AttributeModifier	= 0;
   2520 
   2521 	gid_info->gl_iou_cb_args.cb_gid_info = gid_info;
   2522 	gid_info->gl_iou_cb_args.cb_retry_count = ibdm_dft_retry_cnt;
   2523 	gid_info->gl_iou_cb_args.cb_req_type = IBDM_REQ_TYPE_IOUINFO;
   2524 
   2525 	mutex_enter(&gid_info->gl_mutex);
   2526 	gid_info->gl_timeout_id = timeout(ibdm_pkt_timeout_hdlr,
   2527 	    &gid_info->gl_iou_cb_args, IBDM_TIMEOUT_VALUE(ibdm_dft_timeout));
   2528 	mutex_exit(&gid_info->gl_mutex);
   2529 
   2530 	IBTF_DPRINTF_L5("ibdm", "send_iouunitinfo:"
   2531 	    "timeout %x", gid_info->gl_timeout_id);
   2532 
   2533 	if (ibmf_msg_transport(gid_info->gl_ibmf_hdl, gid_info->gl_qp_hdl, msg,
   2534 	    NULL, ibdm_ibmf_send_cb, &gid_info->gl_iou_cb_args, 0) !=
   2535 	    IBMF_SUCCESS) {
   2536 		IBTF_DPRINTF_L2("ibdm", "\tsend_iounitinfo: ibmf send failed");
   2537 		ibdm_ibmf_send_cb(gid_info->gl_ibmf_hdl,
   2538 		    msg, &gid_info->gl_iou_cb_args);
   2539 	}
   2540 	return (IBDM_SUCCESS);
   2541 }
   2542 
   2543 /*
   2544  * ibdm_handle_iounitinfo()
   2545  *	Invoked by the IBMF when IO Unitinfo request is completed.
   2546  */
   2547 static void
   2548 ibdm_handle_iounitinfo(ibmf_handle_t ibmf_hdl,
   2549     ibmf_msg_t *msg, ibdm_dp_gidinfo_t *gid_info, int *flag)
   2550 {
   2551 	int			ii, first = B_TRUE;
   2552 	int			num_iocs;
   2553 	size_t			size;
   2554 	uchar_t			slot_info;
   2555 	timeout_id_t		timeout_id;
   2556 	ib_mad_hdr_t		*hdr;
   2557 	ibdm_ioc_info_t		*ioc_info;
   2558 	ib_dm_io_unitinfo_t	*iou_info;
   2559 	ib_dm_io_unitinfo_t	*giou_info;
   2560 	ibdm_timeout_cb_args_t	*cb_args;
   2561 
   2562 	IBTF_DPRINTF_L4("ibdm", "\thandle_iouintinfo:"
   2563 	    " ibmf hdl %p pkt %p gid info %p", ibmf_hdl, msg, gid_info);
   2564 
   2565 	if (IBDM_IN_IBMFMSG_ATTR(msg) != IB_DM_ATTR_IO_UNITINFO) {
   2566 		IBTF_DPRINTF_L4("ibdm", "\thandle_iounitinfo: "
   2567 		    "Unexpected response");
   2568 		(*flag) |= IBDM_IBMF_PKT_UNEXP_RESP;
   2569 		return;
   2570 	}
   2571 
   2572 	mutex_enter(&gid_info->gl_mutex);
   2573 	if (gid_info->gl_state != IBDM_GET_IOUNITINFO) {
   2574 		IBTF_DPRINTF_L4("ibdm",
   2575 		    "\thandle_iounitinfo: DUP resp");
   2576 		mutex_exit(&gid_info->gl_mutex);
   2577 		(*flag) = IBDM_IBMF_PKT_DUP_RESP;
   2578 		return;
   2579 	}
   2580 	gid_info->gl_iou_cb_args.cb_req_type = 0;
   2581 	if (gid_info->gl_timeout_id) {
   2582 		timeout_id = gid_info->gl_timeout_id;
   2583 		mutex_exit(&gid_info->gl_mutex);
   2584 		IBTF_DPRINTF_L5("ibdm", "handle_iounitinfo: "
   2585 		    "gl_timeout_id = 0x%x", timeout_id);
   2586 		if (untimeout(timeout_id) == -1) {
   2587 			IBTF_DPRINTF_L2("ibdm", "handle_iounitinfo: "
   2588 			    "untimeout gl_timeout_id failed");
   2589 		}
   2590 		mutex_enter(&gid_info->gl_mutex);
   2591 		gid_info->gl_timeout_id = 0;
   2592 	}
   2593 	gid_info->gl_state = IBDM_GET_IOC_DETAILS;
   2594 
   2595 	iou_info = IBDM_IN_IBMFMSG2IOU(msg);
   2596 	ibdm_dump_iounitinfo(iou_info);
   2597 	num_iocs = iou_info->iou_num_ctrl_slots;
   2598 	/*
   2599 	 * check if number of IOCs reported is zero? if yes, return.
   2600 	 * when num_iocs are reported zero internal IOC database needs
   2601 	 * to be updated. To ensure that save the number of IOCs in
   2602 	 * the new field "gl_num_iocs". Use a new field instead of
   2603 	 * "giou_info->iou_num_ctrl_slots" as that would prevent
   2604 	 * an unnecessary kmem_alloc/kmem_free when num_iocs is 0.
   2605 	 */
   2606 	if (num_iocs == 0 && gid_info->gl_num_iocs == 0) {
   2607 		IBTF_DPRINTF_L4("ibdm", "\thandle_iounitinfo: no IOC's");
   2608 		mutex_exit(&gid_info->gl_mutex);
   2609 		return;
   2610 	}
   2611 	IBTF_DPRINTF_L4("ibdm", "\thandle_iounitinfo: num_iocs = %d", num_iocs);
   2612 
   2613 	/*
   2614 	 * if there is an existing gl_iou (IOU has been probed before)
   2615 	 * check if the "iou_changeid" is same as saved entry in
   2616 	 * "giou_info->iou_changeid".
   2617 	 * (note: this logic can prevent IOC enumeration if a given
   2618 	 * vendor doesn't support setting iou_changeid field for its IOU)
   2619 	 *
   2620 	 * if there is an existing gl_iou and iou_changeid has changed :
   2621 	 * free up existing gl_iou info and its related structures.
   2622 	 * reallocate gl_iou info all over again.
   2623 	 * if we donot free this up; then this leads to memory leaks
   2624 	 */
   2625 	if (gid_info->gl_iou) {
   2626 		giou_info = &gid_info->gl_iou->iou_info;
   2627 		if (b2h16(iou_info->iou_changeid) ==
   2628 		    giou_info->iou_changeid) {
   2629 			IBTF_DPRINTF_L3("ibdm",
   2630 			    "\thandle_iounitinfo: no IOCs changed");
   2631 			gid_info->gl_state = IBDM_GID_PROBING_COMPLETE;
   2632 			mutex_exit(&gid_info->gl_mutex);
   2633 			return;
   2634 		}
   2635 
   2636 		/*
   2637 		 * Store the iou info as prev_iou to be used after
   2638 		 * sweep is done.
   2639 		 */
   2640 		ASSERT(gid_info->gl_prev_iou == NULL);
   2641 		IBTF_DPRINTF_L4(ibdm_string,
   2642 		    "\thandle_iounitinfo: setting gl_prev_iou %p",
   2643 		    gid_info->gl_prev_iou);
   2644 		gid_info->gl_prev_iou = gid_info->gl_iou;
   2645 		ibdm.ibdm_prev_iou = 1;
   2646 		gid_info->gl_iou = NULL;
   2647 	}
   2648 
   2649 	size = sizeof (ibdm_iou_info_t) + num_iocs * sizeof (ibdm_ioc_info_t);
   2650 	gid_info->gl_iou = (ibdm_iou_info_t *)kmem_zalloc(size, KM_SLEEP);
   2651 	giou_info = &gid_info->gl_iou->iou_info;
   2652 	gid_info->gl_iou->iou_ioc_info = (ibdm_ioc_info_t *)
   2653 	    ((char *)gid_info->gl_iou + sizeof (ibdm_iou_info_t));
   2654 
   2655 	giou_info->iou_num_ctrl_slots	= gid_info->gl_num_iocs	= num_iocs;
   2656 	giou_info->iou_flag		= iou_info->iou_flag;
   2657 	bcopy(iou_info->iou_ctrl_list, giou_info->iou_ctrl_list, 128);
   2658 	giou_info->iou_changeid	= b2h16(iou_info->iou_changeid);
   2659 	gid_info->gl_pending_cmds++; /* for diag code */
   2660 	mutex_exit(&gid_info->gl_mutex);
   2661 
   2662 	if (ibdm_get_diagcode(gid_info, 0) != IBDM_SUCCESS) {
   2663 		mutex_enter(&gid_info->gl_mutex);
   2664 		gid_info->gl_pending_cmds--;
   2665 		mutex_exit(&gid_info->gl_mutex);
   2666 	}
   2667 	/*
   2668 	 * Parallelize getting IOC controller profiles from here.
   2669 	 * Allocate IBMF packets and send commands to get IOC profile for
   2670 	 * each IOC present on the IOU.
   2671 	 */
   2672 	for (ii = 0; ii < num_iocs; ii++) {
   2673 		/*
   2674 		 * Check whether IOC is present in the slot
   2675 		 * Series of nibbles (in the field iou_ctrl_list) represents
   2676 		 * a slot in the IOU.
   2677 		 * Byte format: 76543210
   2678 		 * Bits 0-3 of first byte represent Slot 2
   2679 		 * bits 4-7 of first byte represent slot 1,
   2680 		 * bits 0-3 of second byte represent slot 4 and so on
   2681 		 * Each 4-bit nibble has the following meaning
   2682 		 * 0x0 : IOC not installed
   2683 		 * 0x1 : IOC is present
   2684 		 * 0xf : Slot does not exist
   2685 		 * and all other values are reserved.
   2686 		 */
   2687 		ioc_info = IBDM_GIDINFO2IOCINFO(gid_info, ii);
   2688 		slot_info = giou_info->iou_ctrl_list[(ii/2)];
   2689 		if ((ii % 2) == 0)
   2690 			slot_info = (slot_info >> 4);
   2691 
   2692 		if ((slot_info & 0xf) != 1) {
   2693 			IBTF_DPRINTF_L4("ibdm", "\thandle_iouintinfo: "
   2694 			    "No IOC is present in the slot = %d", ii);
   2695 			ioc_info->ioc_state = IBDM_IOC_STATE_PROBE_FAILED;
   2696 			continue;
   2697 		}
   2698 
   2699 		mutex_enter(&gid_info->gl_mutex);
   2700 		ibdm_bump_transactionID(gid_info);
   2701 		mutex_exit(&gid_info->gl_mutex);
   2702 
   2703 		/*
   2704 		 * Re use the already allocated packet (for IOUnitinfo) to
   2705 		 * send the first IOC controller attribute. Allocate new
   2706 		 * IBMF packets for the rest of the IOC's
   2707 		 */
   2708 		if (first != B_TRUE) {
   2709 			msg = NULL;
   2710 			if (ibmf_alloc_msg(ibmf_hdl, IBMF_ALLOC_SLEEP,
   2711 			    &msg) != IBMF_SUCCESS) {
   2712 				IBTF_DPRINTF_L4("ibdm", "\thandle_iouintinfo: "
   2713 				    "IBMF packet allocation failed");
   2714 				continue;
   2715 			}
   2716 
   2717 		}
   2718 
   2719 		/* allocate send buffers for all messages */
   2720 		_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*msg))
   2721 		ibdm_alloc_send_buffers(msg);
   2722 		_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*msg))
   2723 
   2724 		msg->im_local_addr.ia_local_lid	= gid_info->gl_slid;
   2725 		msg->im_local_addr.ia_remote_lid	= gid_info->gl_dlid;
   2726 		if (gid_info->gl_redirected == B_TRUE) {
   2727 			if (gid_info->gl_redirect_dlid != 0) {
   2728 				msg->im_local_addr.ia_remote_lid =
   2729 				    gid_info->gl_redirect_dlid;
   2730 			}
   2731 			msg->im_local_addr.ia_remote_qno =
   2732 			    gid_info->gl_redirect_QP;
   2733 			msg->im_local_addr.ia_p_key =
   2734 			    gid_info->gl_redirect_pkey;
   2735 			msg->im_local_addr.ia_q_key =
   2736 			    gid_info->gl_redirect_qkey;
   2737 			msg->im_local_addr.ia_service_level =
   2738 			    gid_info->gl_redirectSL;
   2739 		} else {
   2740 			msg->im_local_addr.ia_remote_qno = 1;
   2741 			msg->im_local_addr.ia_p_key = gid_info->gl_p_key;
   2742 			msg->im_local_addr.ia_q_key = IB_GSI_QKEY;
   2743 			msg->im_local_addr.ia_service_level = gid_info->gl_SL;
   2744 		}
   2745 
   2746 		hdr			= IBDM_OUT_IBMFMSG_MADHDR(msg);
   2747 		hdr->BaseVersion	= MAD_CLASS_BASE_VERS_1;
   2748 		hdr->MgmtClass		= MAD_MGMT_CLASS_DEV_MGT;
   2749 		hdr->ClassVersion	= IB_DM_CLASS_VERSION_1;
   2750 		hdr->R_Method		= IB_DM_DEVMGT_METHOD_GET;
   2751 		hdr->Status		= 0;
   2752 		hdr->TransactionID	= h2b64(gid_info->gl_transactionID);
   2753 		hdr->AttributeID	= h2b16(IB_DM_ATTR_IOC_CTRL_PROFILE);
   2754 		hdr->AttributeModifier 	= h2b32(ii + 1);
   2755 
   2756 		ioc_info->ioc_state	= IBDM_IOC_STATE_PROBE_INVALID;
   2757 		cb_args			= &ioc_info->ioc_cb_args;
   2758 		cb_args->cb_gid_info	= gid_info;
   2759 		cb_args->cb_retry_count	= ibdm_dft_retry_cnt;
   2760 		cb_args->cb_req_type	= IBDM_REQ_TYPE_IOCINFO;
   2761 		cb_args->cb_ioc_num	= ii;
   2762 
   2763 		mutex_enter(&gid_info->gl_mutex);
   2764 		gid_info->gl_pending_cmds++; /* for diag code */
   2765 
   2766 		ioc_info->ioc_timeout_id = timeout(ibdm_pkt_timeout_hdlr,
   2767 		    cb_args, IBDM_TIMEOUT_VALUE(ibdm_dft_timeout));
   2768 		mutex_exit(&gid_info->gl_mutex);
   2769 
   2770 		IBTF_DPRINTF_L5("ibdm", "\thandle_iounitinfo:"
   2771 		    "timeout 0x%x, ioc_num %d", ioc_info->ioc_timeout_id, ii);
   2772 
   2773 		if (ibmf_msg_transport(ibmf_hdl, gid_info->gl_qp_hdl, msg,
   2774 		    NULL, ibdm_ibmf_send_cb, cb_args, 0) != IBMF_SUCCESS) {
   2775 			IBTF_DPRINTF_L2("ibdm",
   2776 			    "\thandle_iounitinfo: msg transport failed");
   2777 			ibdm_ibmf_send_cb(ibmf_hdl, msg, cb_args);
   2778 		}
   2779 		(*flag) |= IBDM_IBMF_PKT_REUSED;
   2780 		first = B_FALSE;
   2781 		gid_info->gl_iou->iou_niocs_probe_in_progress++;
   2782 	}
   2783 }
   2784 
   2785 
   2786 /*
   2787  * ibdm_handle_ioc_profile()
   2788  *	Invoked by the IBMF when the IOCControllerProfile request
   2789  *	gets completed
   2790  */
   2791 static void
   2792 ibdm_handle_ioc_profile(ibmf_handle_t ibmf_hdl,
   2793     ibmf_msg_t *msg, ibdm_dp_gidinfo_t *gid_info, int *flag)
   2794 {
   2795 	int				first = B_TRUE, reprobe = 0;
   2796 	uint_t				ii, ioc_no, srv_start;
   2797 	uint_t				nserv_entries;
   2798 	timeout_id_t			timeout_id;
   2799 	ib_mad_hdr_t			*hdr;
   2800 	ibdm_ioc_info_t			*ioc_info;
   2801 	ibdm_timeout_cb_args_t		*cb_args;
   2802 	ib_dm_ioc_ctrl_profile_t	*ioc, *gioc;
   2803 
   2804 	IBTF_DPRINTF_L4("ibdm", "\thandle_ioc_profile:"
   2805 	    " ibmf hdl %p msg %p gid info %p", ibmf_hdl, msg, gid_info);
   2806 
   2807 	ioc = IBDM_IN_IBMFMSG2IOC(msg);
   2808 	/*
   2809 	 * Check whether we know this IOC already
   2810 	 * This will return NULL if reprobe is in progress
   2811 	 * IBDM_IOC_STATE_REPROBE_PROGRESS will be set.
   2812 	 * Do not hold mutexes here.
   2813 	 */
   2814 	if (ibdm_is_ioc_present(ioc->ioc_guid, gid_info, flag) != NULL) {
   2815 		IBTF_DPRINTF_L4("ibdm", "\thandle_ioc_profile:"
   2816 		    "IOC guid %llx is present", ioc->ioc_guid);
   2817 		return;
   2818 	}
   2819 	ioc_no = IBDM_IN_IBMFMSG_ATTRMOD(msg);
   2820 	IBTF_DPRINTF_L4("ibdm", "\thandle_ioc_profile: ioc_no = %d", ioc_no-1);
   2821 
   2822 	/* Make sure that IOC index is with the valid range */
   2823 	if (IBDM_IS_IOC_NUM_INVALID(ioc_no, gid_info)) {
   2824 		IBTF_DPRINTF_L2("ibdm", "\thandle_ioc_profile: "
   2825 		    "IOC index Out of range, index %d", ioc);
   2826 		(*flag) |= IBDM_IBMF_PKT_UNEXP_RESP;
   2827 		return;
   2828 	}
   2829 	ioc_info = &gid_info->gl_iou->iou_ioc_info[ioc_no - 1];
   2830 	ioc_info->ioc_iou_info = gid_info->gl_iou;
   2831 
   2832 	mutex_enter(&gid_info->gl_mutex);
   2833 	if (ioc_info->ioc_state == IBDM_IOC_STATE_REPROBE_PROGRESS) {
   2834 		reprobe = 1;
   2835 		ioc_info->ioc_prev_serv = ioc_info->ioc_serv;
   2836 		ioc_info->ioc_serv = NULL;
   2837 		ioc_info->ioc_prev_serv_cnt =
   2838 		    ioc_info->ioc_profile.ioc_service_entries;
   2839 	} else if (ioc_info->ioc_state != IBDM_IOC_STATE_PROBE_INVALID) {
   2840 		IBTF_DPRINTF_L2("ibdm", "\thandle_ioc_profile: DUP response"
   2841 		    "ioc %d, ioc_state %x", ioc_no - 1, ioc_info->ioc_state);
   2842 		mutex_exit(&gid_info->gl_mutex);
   2843 		(*flag) |= IBDM_IBMF_PKT_DUP_RESP;
   2844 		return;
   2845 	}
   2846 	ioc_info->ioc_cb_args.cb_req_type = 0;
   2847 	if (ioc_info->ioc_timeout_id) {
   2848 		timeout_id = ioc_info->ioc_timeout_id;
   2849 		ioc_info->ioc_timeout_id = 0;
   2850 		mutex_exit(&gid_info->gl_mutex);
   2851 		IBTF_DPRINTF_L5("ibdm", "handle_ioc_profile: "
   2852 		    "ioc_timeout_id = 0x%x", timeout_id);
   2853 		if (untimeout(timeout_id) == -1) {
   2854 			IBTF_DPRINTF_L2("ibdm", "handle_ioc_profile: "
   2855 			    "untimeout ioc_timeout_id failed");
   2856 		}
   2857 		mutex_enter(&gid_info->gl_mutex);
   2858 	}
   2859 
   2860 	ioc_info->ioc_state = IBDM_IOC_STATE_PROBE_SUCCESS;
   2861 	if (reprobe == 0) {
   2862 		ioc_info->ioc_iou_guid = gid_info->gl_nodeguid;
   2863 		ioc_info->ioc_nodeguid = gid_info->gl_nodeguid;
   2864 	}
   2865 
   2866 	/*
   2867 	 * Save all the IOC information in the global structures.
   2868 	 * Note the wire format is Big Endian and the Sparc process also
   2869 	 * big endian. So, there is no need to convert the data fields
   2870 	 * The conversion routines used below are ineffective on Sparc
   2871 	 * machines where as they will be effective on little endian
   2872 	 * machines such as Intel processors.
   2873 	 */
   2874 	gioc = (ib_dm_ioc_ctrl_profile_t *)&ioc_info->ioc_profile;
   2875 
   2876 	/*
   2877 	 * Restrict updates to onlyport GIDs and service entries during reprobe
   2878 	 */
   2879 	if (reprobe == 0) {
   2880 		gioc->ioc_guid			= b2h64(ioc->ioc_guid);
   2881 		gioc->ioc_vendorid		=
   2882 		    ((b2h32(ioc->ioc_vendorid) & IB_DM_VENDORID_MASK)
   2883 		    >> IB_DM_VENDORID_SHIFT);
   2884 		gioc->ioc_deviceid		= b2h32(ioc->ioc_deviceid);
   2885 		gioc->ioc_device_ver		= b2h16(ioc->ioc_device_ver);
   2886 		gioc->ioc_subsys_vendorid	=
   2887 		    ((b2h32(ioc->ioc_subsys_vendorid) & IB_DM_VENDORID_MASK)
   2888 		    >> IB_DM_VENDORID_SHIFT);
   2889 		gioc->ioc_subsys_id		= b2h32(ioc->ioc_subsys_id);
   2890 		gioc->ioc_io_class		= b2h16(ioc->ioc_io_class);
   2891 		gioc->ioc_io_subclass		= b2h16(ioc->ioc_io_subclass);
   2892 		gioc->ioc_protocol		= b2h16(ioc->ioc_protocol);
   2893 		gioc->ioc_protocol_ver		= b2h16(ioc->ioc_protocol_ver);
   2894 		gioc->ioc_send_msg_qdepth	=
   2895 		    b2h16(ioc->ioc_send_msg_qdepth);
   2896 		gioc->ioc_rdma_read_qdepth	=
   2897 		    b2h16(ioc->ioc_rdma_read_qdepth);
   2898 		gioc->ioc_send_msg_sz		= b2h32(ioc->ioc_send_msg_sz);
   2899 		gioc->ioc_rdma_xfer_sz		= b2h32(ioc->ioc_rdma_xfer_sz);
   2900 		gioc->ioc_ctrl_opcap_mask	= ioc->ioc_ctrl_opcap_mask;
   2901 		bcopy(ioc->ioc_id_string, gioc->ioc_id_string,
   2902 		    IB_DM_IOC_ID_STRING_LEN);
   2903 
   2904 		ioc_info->ioc_iou_diagcode = gid_info->gl_iou->iou_diagcode;
   2905 		ioc_info->ioc_iou_dc_valid = gid_info->gl_iou->iou_dc_valid;
   2906 		ioc_info->ioc_diagdeviceid = (IB_DM_IOU_DEVICEID_MASK &
   2907 		    gid_info->gl_iou->iou_info.iou_flag) ? B_TRUE : B_FALSE;
   2908 
   2909 		if (ioc_info->ioc_diagdeviceid == B_TRUE) {
   2910 			gid_info->gl_pending_cmds++;
   2911 			IBTF_DPRINTF_L3(ibdm_string,
   2912 			    "\tibdm_handle_ioc_profile: "
   2913 			    "%d: gid_info %p gl_state %d pending_cmds %d",
   2914 			    __LINE__, gid_info, gid_info->gl_state,
   2915 			    gid_info->gl_pending_cmds);
   2916 		}
   2917 	}
   2918 	gioc->ioc_service_entries	= ioc->ioc_service_entries;
   2919 	mutex_exit(&gid_info->gl_mutex);
   2920 
   2921 	ibdm_dump_ioc_profile(gioc);
   2922 
   2923 	if ((ioc_info->ioc_diagdeviceid == B_TRUE) && (reprobe == 0)) {
   2924 		if (ibdm_get_diagcode(gid_info, ioc_no) != IBDM_SUCCESS) {
   2925 			mutex_enter(&gid_info->gl_mutex);
   2926 			gid_info->gl_pending_cmds--;
   2927 			mutex_exit(&gid_info->gl_mutex);
   2928 		}
   2929 	}
   2930 	ioc_info->ioc_serv = (ibdm_srvents_info_t *)kmem_zalloc(
   2931 	    (gioc->ioc_service_entries * sizeof (ibdm_srvents_info_t)),
   2932 	    KM_SLEEP);
   2933 
   2934 	/*
   2935 	 * In one single request, maximum number of requests that can be
   2936 	 * obtained is 4. If number of service entries are more than four,
   2937 	 * calculate number requests needed and send them parallelly.
   2938 	 */
   2939 	nserv_entries = ioc->ioc_service_entries;
   2940 	ii = 0;
   2941 	while (nserv_entries) {
   2942 		mutex_enter(&gid_info->gl_mutex);
   2943 		gid_info->gl_pending_cmds++;
   2944 		ibdm_bump_transactionID(gid_info);
   2945 		mutex_exit(&gid_info->gl_mutex);
   2946 
   2947 		if (first != B_TRUE) {
   2948 			if (ibmf_alloc_msg(ibmf_hdl, IBMF_ALLOC_SLEEP,
   2949 			    &msg) != IBMF_SUCCESS) {
   2950 				continue;
   2951 			}
   2952 
   2953 		}
   2954 		_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*msg))
   2955 		ibdm_alloc_send_buffers(msg);
   2956 		_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*msg))
   2957 		msg->im_local_addr.ia_local_lid	= gid_info->gl_slid;
   2958 		msg->im_local_addr.ia_remote_lid	= gid_info->gl_dlid;
   2959 		if (gid_info->gl_redirected == B_TRUE) {
   2960 			if (gid_info->gl_redirect_dlid != 0) {
   2961 				msg->im_local_addr.ia_remote_lid =
   2962 				    gid_info->gl_redirect_dlid;
   2963 			}
   2964 			msg->im_local_addr.ia_remote_qno =
   2965 			    gid_info->gl_redirect_QP;
   2966 			msg->im_local_addr.ia_p_key =
   2967 			    gid_info->gl_redirect_pkey;
   2968 			msg->im_local_addr.ia_q_key =
   2969 			    gid_info->gl_redirect_qkey;
   2970 			msg->im_local_addr.ia_service_level =
   2971 			    gid_info->gl_redirectSL;
   2972 		} else {
   2973 			msg->im_local_addr.ia_remote_qno = 1;
   2974 			msg->im_local_addr.ia_p_key = gid_info->gl_p_key;
   2975 			msg->im_local_addr.ia_q_key = IB_GSI_QKEY;
   2976 			msg->im_local_addr.ia_service_level = gid_info->gl_SL;
   2977 		}
   2978 
   2979 		hdr			= IBDM_OUT_IBMFMSG_MADHDR(msg);
   2980 		hdr->BaseVersion	= MAD_CLASS_BASE_VERS_1;
   2981 		hdr->MgmtClass		= MAD_MGMT_CLASS_DEV_MGT;
   2982 		hdr->ClassVersion	= IB_DM_CLASS_VERSION_1;
   2983 		hdr->R_Method		= IB_DM_DEVMGT_METHOD_GET;
   2984 		hdr->Status		= 0;
   2985 		hdr->TransactionID	= h2b64(gid_info->gl_transactionID);
   2986 		hdr->AttributeID	= h2b16(IB_DM_ATTR_SERVICE_ENTRIES);
   2987 
   2988 		srv_start = ii * 4;
   2989 		cb_args = &ioc_info->ioc_serv[srv_start].se_cb_args;
   2990 		cb_args->cb_gid_info	= gid_info;
   2991 		cb_args->cb_retry_count	= ibdm_dft_retry_cnt;
   2992 		cb_args->cb_req_type	= IBDM_REQ_TYPE_SRVENTS;
   2993 		cb_args->cb_srvents_start = srv_start;
   2994 		cb_args->cb_ioc_num	= ioc_no - 1;
   2995 
   2996 		if (nserv_entries >= IBDM_MAX_SERV_ENTRIES_PER_REQ) {
   2997 			nserv_entries -= IBDM_MAX_SERV_ENTRIES_PER_REQ;
   2998 			cb_args->cb_srvents_end = (cb_args->cb_srvents_start +
   2999 			    IBDM_MAX_SERV_ENTRIES_PER_REQ - 1);
   3000 		} else {
   3001 			cb_args->cb_srvents_end =
   3002 			    (cb_args->cb_srvents_start + nserv_entries - 1);
   3003 			nserv_entries = 0;
   3004 		}
   3005 		_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*hdr))
   3006 		ibdm_fill_srv_attr_mod(hdr, cb_args);
   3007 		_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*hdr))
   3008 
   3009 		mutex_enter(&gid_info->gl_mutex);
   3010 		ioc_info->ioc_serv[srv_start].se_timeout_id = timeout(
   3011 		    ibdm_pkt_timeout_hdlr, cb_args,
   3012 		    IBDM_TIMEOUT_VALUE(ibdm_dft_timeout));
   3013 		mutex_exit(&gid_info->gl_mutex);
   3014 
   3015 		IBTF_DPRINTF_L5("ibdm", "\thandle_ioc_profile:"
   3016 		    "timeout %x, ioc %d srv %d",
   3017 		    ioc_info->ioc_serv[srv_start].se_timeout_id,
   3018 		    ioc_no - 1, srv_start);
   3019 
   3020 		if (ibmf_msg_transport(ibmf_hdl, gid_info->gl_qp_hdl, msg,
   3021 		    NULL, ibdm_ibmf_send_cb, cb_args, 0) != IBMF_SUCCESS) {
   3022 			IBTF_DPRINTF_L2("ibdm",
   3023 			    "\thandle_ioc_profile: msg send failed");
   3024 			ibdm_ibmf_send_cb(ibmf_hdl, msg, cb_args);
   3025 		}
   3026 		(*flag) |= IBDM_IBMF_PKT_REUSED;
   3027 		first = B_FALSE;
   3028 		ii++;
   3029 	}
   3030 }
   3031 
   3032 
   3033 /*
   3034  * ibdm_handle_srventry_mad()
   3035  */
   3036 static void
   3037 ibdm_handle_srventry_mad(ibmf_msg_t *msg,
   3038     ibdm_dp_gidinfo_t *gid_info, int *flag)
   3039 {
   3040 	uint_t			ii, ioc_no, attrmod;
   3041 	uint_t			nentries, start, end;
   3042 	timeout_id_t		timeout_id;
   3043 	ib_dm_srv_t		*srv_ents;
   3044 	ibdm_ioc_info_t		*ioc_info;
   3045 	ibdm_srvents_info_t	*gsrv_ents;
   3046 
   3047 	IBTF_DPRINTF_L4("ibdm", "\thandle_srventry_mad:"
   3048 	    " IBMF msg %p gid info %p", msg, gid_info);
   3049 
   3050 	srv_ents = IBDM_IN_IBMFMSG2SRVENT(msg);
   3051 	/*
   3052 	 * Get the start and end index of the service entries
   3053 	 * Upper 16 bits identify the IOC
   3054 	 * Lower 16 bits specify the range of service entries
   3055 	 * 	LSB specifies (Big endian) end of the range
   3056 	 * 	MSB specifies (Big endian) start of the range
   3057 	 */
   3058 	attrmod = IBDM_IN_IBMFMSG_ATTRMOD(msg);
   3059 	ioc_no	= ((attrmod >> 16) & IBDM_16_BIT_MASK);
   3060 	end	= ((attrmod >> 8) & IBDM_8_BIT_MASK);
   3061 	start	= (attrmod & IBDM_8_BIT_MASK);
   3062 
   3063 	/* Make sure that IOC index is with the valid range */
   3064 	if ((ioc_no < 1) |
   3065 	    (ioc_no > gid_info->gl_iou->iou_info.iou_num_ctrl_slots)) {
   3066 		IBTF_DPRINTF_L2("ibdm", "\thandle_srventry_mad: "
   3067 		    "IOC index Out of range, index %d", ioc_no);
   3068 		(*flag) |= IBDM_IBMF_PKT_UNEXP_RESP;
   3069 		return;
   3070 	}
   3071 	ioc_info = IBDM_GIDINFO2IOCINFO(gid_info, (ioc_no -1));
   3072 
   3073 	/*
   3074 	 * Make sure that the "start" and "end" service indexes are
   3075 	 * with in the valid range
   3076 	 */
   3077 	nentries = ioc_info->ioc_profile.ioc_service_entries;
   3078 	if ((start > end) | (start >= nentries) | (end >= nentries)) {
   3079 		IBTF_DPRINTF_L2("ibdm", "\thandle_srventry_mad: "
   3080 		    "Attr modifier 0x%x, #Serv entries %d", attrmod, nentries);
   3081 		(*flag) |= IBDM_IBMF_PKT_UNEXP_RESP;
   3082 		return;
   3083 	}
   3084 	gsrv_ents = &ioc_info->ioc_serv[start];
   3085 	mutex_enter(&gid_info->gl_mutex);
   3086 	if (gsrv_ents->se_state != IBDM_SE_INVALID) {
   3087 		IBTF_DPRINTF_L2("ibdm", "\thandle_srventry_mad: "
   3088 		    "already known, ioc %d, srv %d, se_state %x",
   3089 		    ioc_no - 1, start, gsrv_ents->se_state);
   3090 		mutex_exit(&gid_info->gl_mutex);
   3091 		(*flag) |= IBDM_IBMF_PKT_DUP_RESP;
   3092 		return;
   3093 	}
   3094 	ioc_info->ioc_serv[start].se_cb_args.cb_req_type = 0;
   3095 	if (ioc_info->ioc_serv[start].se_timeout_id) {
   3096 		IBTF_DPRINTF_L2("ibdm",
   3097 		    "\thandle_srventry_mad: ioc %d start %d", ioc_no, start);
   3098 		timeout_id = ioc_info->ioc_serv[start].se_timeout_id;
   3099 		ioc_info->ioc_serv[start].se_timeout_id = 0;
   3100 		mutex_exit(&gid_info->gl_mutex);
   3101 		IBTF_DPRINTF_L5("ibdm", "handle_srverntry_mad: "
   3102 		    "se_timeout_id = 0x%x", timeout_id);
   3103 		if (untimeout(timeout_id) == -1) {
   3104 			IBTF_DPRINTF_L2("ibdm", "handle_srventry_mad: "
   3105 			    "untimeout se_timeout_id failed");
   3106 		}
   3107 		mutex_enter(&gid_info->gl_mutex);
   3108 	}
   3109 
   3110 	gsrv_ents->se_state = IBDM_SE_VALID;
   3111 	mutex_exit(&gid_info->gl_mutex);
   3112 	for (ii = start; ii <= end; ii++, srv_ents++, gsrv_ents++) {
   3113 		gsrv_ents->se_attr.srv_id = b2h64(srv_ents->srv_id);
   3114 		bcopy(srv_ents->srv_name,
   3115 		    gsrv_ents->se_attr.srv_name, IB_DM_MAX_SVC_NAME_LEN);
   3116 		ibdm_dump_service_entries(&gsrv_ents->se_attr);
   3117 	}
   3118 }
   3119 
   3120 
   3121 /*
   3122  * ibdm_get_diagcode:
   3123  *	Send request to get IOU/IOC diag code
   3124  *	Returns IBDM_SUCCESS/IBDM_FAILURE
   3125  */
   3126 static int
   3127 ibdm_get_diagcode(ibdm_dp_gidinfo_t *gid_info, int attr)
   3128 {
   3129 	ibmf_msg_t		*msg;
   3130 	ib_mad_hdr_t		*hdr;
   3131 	ibdm_ioc_info_t		*ioc;
   3132 	ibdm_timeout_cb_args_t	*cb_args;
   3133 	timeout_id_t		*timeout_id;
   3134 
   3135 	IBTF_DPRINTF_L4("ibdm", "\tget_diagcode: gid info %p, attr = %d",
   3136 	    gid_info, attr);
   3137 
   3138 	if (ibmf_alloc_msg(gid_info->gl_ibmf_hdl, IBMF_ALLOC_SLEEP,
   3139 	    &msg) != IBMF_SUCCESS) {
   3140 		IBTF_DPRINTF_L4("ibdm", "\tget_diagcode: pkt alloc fail");
   3141 		return (IBDM_FAILURE);
   3142 	}
   3143 
   3144 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*msg))
   3145 	ibdm_alloc_send_buffers(msg);
   3146 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*msg))
   3147 
   3148 	mutex_enter(&gid_info->gl_mutex);
   3149 	ibdm_bump_transactionID(gid_info);
   3150 	mutex_exit(&gid_info->gl_mutex);
   3151 
   3152 	msg->im_local_addr.ia_local_lid	= gid_info->gl_slid;
   3153 	msg->im_local_addr.ia_remote_lid	= gid_info->gl_dlid;
   3154 	if (gid_info->gl_redirected == B_TRUE) {
   3155 		if (gid_info->gl_redirect_dlid != 0) {
   3156 			msg->im_local_addr.ia_remote_lid =
   3157 			    gid_info->gl_redirect_dlid;
   3158 		}
   3159 
   3160 		msg->im_local_addr.ia_remote_qno = gid_info->gl_redirect_QP;
   3161 		msg->im_local_addr.ia_p_key = gid_info->gl_redirect_pkey;
   3162 		msg->im_local_addr.ia_q_key = gid_info->gl_redirect_qkey;
   3163 		msg->im_local_addr.ia_service_level = gid_info->gl_redirectSL;
   3164 	} else {
   3165 		msg->im_local_addr.ia_remote_qno = 1;
   3166 		msg->im_local_addr.ia_p_key = gid_info->gl_p_key;
   3167 		msg->im_local_addr.ia_q_key = IB_GSI_QKEY;
   3168 		msg->im_local_addr.ia_service_level = gid_info->gl_SL;
   3169 	}
   3170 
   3171 	hdr			= IBDM_OUT_IBMFMSG_MADHDR(msg);
   3172 	hdr->BaseVersion	= MAD_CLASS_BASE_VERS_1;
   3173 	hdr->MgmtClass		= MAD_MGMT_CLASS_DEV_MGT;
   3174 	hdr->ClassVersion	= IB_DM_CLASS_VERSION_1;
   3175 	hdr->R_Method		= IB_DM_DEVMGT_METHOD_GET;
   3176 	hdr->Status		= 0;
   3177 	hdr->TransactionID	= h2b64(gid_info->gl_transactionID);
   3178 
   3179 	hdr->AttributeID	= h2b16(IB_DM_ATTR_DIAG_CODE);
   3180 	hdr->AttributeModifier	= h2b32(attr);
   3181 
   3182 	if (attr == 0) {
   3183 		cb_args = &gid_info->gl_iou_cb_args;
   3184 		gid_info->gl_iou->iou_dc_valid = B_FALSE;
   3185 		cb_args->cb_ioc_num	= 0;
   3186 		cb_args->cb_req_type	= IBDM_REQ_TYPE_IOU_DIAGCODE;
   3187 		timeout_id = &gid_info->gl_timeout_id;
   3188 	} else {
   3189 		ioc = IBDM_GIDINFO2IOCINFO(gid_info, (attr - 1));
   3190 		ioc->ioc_dc_valid = B_FALSE;
   3191 		cb_args = &ioc->ioc_dc_cb_args;
   3192 		cb_args->cb_ioc_num	= attr - 1;
   3193 		cb_args->cb_req_type	= IBDM_REQ_TYPE_IOC_DIAGCODE;
   3194 		timeout_id = &ioc->ioc_dc_timeout_id;
   3195 	}
   3196 	cb_args->cb_gid_info	= gid_info;
   3197 	cb_args->cb_retry_count	= ibdm_dft_retry_cnt;
   3198 	cb_args->cb_srvents_start = 0;
   3199 
   3200 	mutex_enter(&gid_info->gl_mutex);
   3201 	*timeout_id = timeout(ibdm_pkt_timeout_hdlr,
   3202 	    cb_args, IBDM_TIMEOUT_VALUE(ibdm_dft_timeout));
   3203 	mutex_exit(&gid_info->gl_mutex);
   3204 
   3205 	IBTF_DPRINTF_L5("ibdm", "\tget_diagcode:"
   3206 	    "timeout %x, ioc %d", *timeout_id, cb_args->cb_ioc_num);
   3207 
   3208 	if (ibmf_msg_transport(gid_info->gl_ibmf_hdl, gid_info->gl_qp_hdl,
   3209 	    msg, NULL, ibdm_ibmf_send_cb, cb_args, 0) != IBMF_SUCCESS) {
   3210 		IBTF_DPRINTF_L2("ibdm", "\tget_diagcode: ibmf send failed");
   3211 		ibdm_ibmf_send_cb(gid_info->gl_ibmf_hdl, msg, cb_args);
   3212 	}
   3213 	return (IBDM_SUCCESS);
   3214 }
   3215 
   3216 /*
   3217  * ibdm_handle_diagcode:
   3218  *	Process the DiagCode MAD response and update local DM
   3219  *	data structure.
   3220  */
   3221 static void
   3222 ibdm_handle_diagcode(ibmf_msg_t *ibmf_msg,
   3223     ibdm_dp_gidinfo_t *gid_info, int *flag)
   3224 {
   3225 	uint16_t	attrmod, *diagcode;
   3226 	ibdm_iou_info_t	*iou;
   3227 	ibdm_ioc_info_t	*ioc;
   3228 	timeout_id_t	timeout_id;
   3229 	ibdm_timeout_cb_args_t	*cb_args;
   3230 
   3231 	diagcode = (uint16_t *)ibmf_msg->im_msgbufs_recv.im_bufs_cl_data;
   3232 
   3233 	mutex_enter(&gid_info->gl_mutex);
   3234 	attrmod = IBDM_IN_IBMFMSG_ATTRMOD(ibmf_msg);
   3235 	iou = gid_info->gl_iou;
   3236 	if (attrmod == 0) {
   3237 		if (iou->iou_dc_valid != B_FALSE) {
   3238 			(*flag) |= IBDM_IBMF_PKT_DUP_RESP;
   3239 			IBTF_DPRINTF_L4("ibdm",
   3240 			    "\thandle_diagcode: Duplicate IOU DiagCode");
   3241 			mutex_exit(&gid_info->gl_mutex);
   3242 			return;
   3243 		}
   3244 		cb_args = &gid_info->gl_iou_cb_args;
   3245 		cb_args->cb_req_type = 0;
   3246 		iou->iou_diagcode = b2h16(*diagcode);
   3247 		iou->iou_dc_valid = B_TRUE;
   3248 		if (gid_info->gl_timeout_id) {
   3249 			timeout_id = gid_info->gl_timeout_id;
   3250 			mutex_exit(&gid_info->gl_mutex);
   3251 			IBTF_DPRINTF_L5("ibdm", "\thandle_diagcode: "
   3252 			    "gl_timeout_id = 0x%x", timeout_id);
   3253 			if (untimeout(timeout_id) == -1) {
   3254 				IBTF_DPRINTF_L2("ibdm", "handle_diagcode: "
   3255 				    "untimeout gl_timeout_id failed");
   3256 			}
   3257 			mutex_enter(&gid_info->gl_mutex);
   3258 			gid_info->gl_timeout_id = 0;
   3259 		}
   3260 	} else {
   3261 		ioc = IBDM_GIDINFO2IOCINFO(gid_info, (attrmod - 1));
   3262 		if (ioc->ioc_dc_valid != B_FALSE) {
   3263 			(*flag) |= IBDM_IBMF_PKT_DUP_RESP;
   3264 			IBTF_DPRINTF_L4("ibdm",
   3265 			    "\thandle_diagcode: Duplicate IOC DiagCode");
   3266 			mutex_exit(&gid_info->gl_mutex);
   3267 			return;
   3268 		}
   3269 		cb_args = &ioc->ioc_dc_cb_args;
   3270 		cb_args->cb_req_type = 0;
   3271 		ioc->ioc_diagcode = b2h16(*diagcode);
   3272 		ioc->ioc_dc_valid = B_TRUE;
   3273 		timeout_id = iou->iou_ioc_info[attrmod - 1].ioc_dc_timeout_id;
   3274 		if (timeout_id) {
   3275 			iou->iou_ioc_info[attrmod - 1].ioc_dc_timeout_id = 0;
   3276 			mutex_exit(&gid_info->gl_mutex);
   3277 			IBTF_DPRINTF_L5("ibdm", "handle_diagcode: "
   3278 			    "timeout_id = 0x%x", timeout_id);
   3279 			if (untimeout(timeout_id) == -1) {
   3280 				IBTF_DPRINTF_L2("ibdm", "\thandle_diagcode: "
   3281 				    "untimeout ioc_dc_timeout_id failed");
   3282 			}
   3283 			mutex_enter(&gid_info->gl_mutex);
   3284 		}
   3285 	}
   3286 	mutex_exit(&gid_info->gl_mutex);
   3287 
   3288 	IBTF_DPRINTF_L4("ibdm", "\thandle_diagcode: DiagCode : 0x%x"
   3289 	    "attrmod : 0x%x", b2h16(*diagcode), attrmod);
   3290 }
   3291 
   3292 
   3293 /*
   3294  * ibdm_is_ioc_present()
   3295  *	Return ibdm_ioc_info_t if IOC guid is found in the global gid list
   3296  */
   3297 static ibdm_ioc_info_t *
   3298 ibdm_is_ioc_present(ib_guid_t ioc_guid,
   3299     ibdm_dp_gidinfo_t *gid_info, int *flag)
   3300 {
   3301 	int				ii;
   3302 	ibdm_ioc_info_t			*ioc;
   3303 	ibdm_dp_gidinfo_t		*head;
   3304 	ib_dm_io_unitinfo_t		*iou;
   3305 
   3306 	mutex_enter(&ibdm.ibdm_mutex);
   3307 	head = ibdm.ibdm_dp_gidlist_head;
   3308 	while (head) {
   3309 		mutex_enter(&head->gl_mutex);
   3310 		if (head->gl_iou == NULL) {
   3311 			mutex_exit(&head->gl_mutex);
   3312 			head = head->gl_next;
   3313 			continue;
   3314 		}
   3315 		iou = &head->gl_iou->iou_info;
   3316 		for (ii = 0; ii < iou->iou_num_ctrl_slots; ii++) {
   3317 			ioc = IBDM_GIDINFO2IOCINFO(head, ii);
   3318 			if ((ioc->ioc_state == IBDM_IOC_STATE_PROBE_SUCCESS) &&
   3319 			    (ioc->ioc_profile.ioc_guid == ioc_guid)) {
   3320 				if (gid_info == head) {
   3321 					*flag |= IBDM_IBMF_PKT_DUP_RESP;
   3322 				} else if (ibdm_check_dgid(head->gl_dgid_lo,
   3323 				    head->gl_dgid_hi) != NULL) {
   3324 					IBTF_DPRINTF_L4("ibdm", "\tis_ioc_"
   3325 					    "present: gid not present");
   3326 					ibdm_add_to_gl_gid(gid_info, head);
   3327 				}
   3328 				mutex_exit(&head->gl_mutex);
   3329 				mutex_exit(&ibdm.ibdm_mutex);
   3330 				return (ioc);
   3331 			}
   3332 		}
   3333 		mutex_exit(&head->gl_mutex);
   3334 		head = head->gl_next;
   3335 	}
   3336 	mutex_exit(&ibdm.ibdm_mutex);
   3337 	return (NULL);
   3338 }
   3339 
   3340 
   3341 /*
   3342  * ibdm_ibmf_send_cb()
   3343  *	IBMF invokes this callback routine after posting the DM MAD to
   3344  *	the HCA.
   3345  */
   3346 /*ARGSUSED*/
   3347 static void
   3348 ibdm_ibmf_send_cb(ibmf_handle_t ibmf_hdl, ibmf_msg_t *ibmf_msg, void *arg)
   3349 {
   3350 	ibdm_dump_ibmf_msg(ibmf_msg, 1);
   3351 	ibdm_free_send_buffers(ibmf_msg);
   3352 	if (ibmf_free_msg(ibmf_hdl, &ibmf_msg) != IBMF_SUCCESS) {
   3353 		IBTF_DPRINTF_L4("ibdm",
   3354 		    "\tibmf_send_cb: IBMF free msg failed");
   3355 	}
   3356 }
   3357 
   3358 
   3359 /*
   3360  * ibdm_ibmf_recv_cb()
   3361  *	Invoked by the IBMF when a response to the one of the DM requests
   3362  *	is received.
   3363  */
   3364 /*ARGSUSED*/
   3365 static void
   3366 ibdm_ibmf_recv_cb(ibmf_handle_t ibmf_hdl, ibmf_msg_t *msg, void *arg)
   3367 {
   3368 	ibdm_taskq_args_t	*taskq_args;
   3369 
   3370 	/*
   3371 	 * If the taskq enable is set then dispatch a taskq to process
   3372 	 * the MAD, otherwise just process it on this thread
   3373 	 */
   3374 	if (ibdm_taskq_enable != IBDM_ENABLE_TASKQ_HANDLING) {
   3375 		ibdm_process_incoming_mad(ibmf_hdl, msg, arg);
   3376 		return;
   3377 	}
   3378 
   3379 	/*
   3380 	 * create a taskq and dispatch it to process the incoming MAD
   3381 	 */
   3382 	taskq_args = kmem_alloc(sizeof (ibdm_taskq_args_t), KM_NOSLEEP);
   3383 	if (taskq_args == NULL) {
   3384 		IBTF_DPRINTF_L2("ibdm", "ibmf_recv_cb: kmem_alloc failed for"
   3385 		    "taskq_args");
   3386 		if (ibmf_free_msg(ibmf_hdl, &msg) != IBMF_SUCCESS) {
   3387 			IBTF_DPRINTF_L4("ibmf_recv_cb",
   3388 			    "\tibmf_recv_cb: IBMF free msg failed");
   3389 		}
   3390 		return;
   3391 	}
   3392 	taskq_args->tq_ibmf_handle = ibmf_hdl;
   3393 	taskq_args->tq_ibmf_msg = msg;
   3394 	taskq_args->tq_args = arg;
   3395 
   3396 	if (taskq_dispatch(system_taskq, ibdm_recv_incoming_mad, taskq_args,
   3397 	    TQ_NOSLEEP) == 0) {
   3398 		IBTF_DPRINTF_L2("ibdm", "ibmf_recv_cb: taskq_dispatch failed");
   3399 		if (ibmf_free_msg(ibmf_hdl, &msg) != IBMF_SUCCESS) {
   3400 			IBTF_DPRINTF_L4("ibmf_recv_cb",
   3401 			    "\tibmf_recv_cb: IBMF free msg failed");
   3402 		}
   3403 		kmem_free(taskq_args, sizeof (ibdm_taskq_args_t));
   3404 		return;
   3405 	}
   3406 
   3407 	/* taskq_args are deleted in ibdm_recv_incoming_mad() */
   3408 }
   3409 
   3410 
   3411 void
   3412 ibdm_recv_incoming_mad(void *args)
   3413 {
   3414 	ibdm_taskq_args_t	*taskq_args;
   3415 
   3416 	taskq_args = (ibdm_taskq_args_t *)args;
   3417 
   3418 	IBTF_DPRINTF_L4("ibdm", "\tibdm_recv_incoming_mad: "
   3419 	    "Processing incoming MAD via taskq");
   3420 
   3421 	ibdm_process_incoming_mad(taskq_args->tq_ibmf_handle,
   3422 	    taskq_args->tq_ibmf_msg, taskq_args->tq_args);
   3423 
   3424 	kmem_free(taskq_args, sizeof (ibdm_taskq_args_t));
   3425 }
   3426 
   3427 
   3428 /*
   3429  * Calls ibdm_process_incoming_mad with all function arguments  extracted
   3430  * from args
   3431  */
   3432 /*ARGSUSED*/
   3433 static void
   3434 ibdm_process_incoming_mad(ibmf_handle_t ibmf_hdl, ibmf_msg_t *msg, void *arg)
   3435 {
   3436 	int			flag = 0;
   3437 	int			ret;
   3438 	uint64_t		transaction_id;
   3439 	ib_mad_hdr_t		*hdr;
   3440 	ibdm_dp_gidinfo_t	*gid_info = NULL;
   3441 
   3442 	IBTF_DPRINTF_L4("ibdm",
   3443 	    "\tprocess_incoming_mad: ibmf hdl %p pkt %p", ibmf_hdl, msg);
   3444 	ibdm_dump_ibmf_msg(msg, 0);
   3445 
   3446 	/*
   3447 	 * IBMF calls this routine for every DM MAD that arrives at this port.
   3448 	 * But we handle only the responses for requests we sent. We drop all
   3449 	 * the DM packets that does not have response bit set in the MAD
   3450 	 * header(this eliminates all the requests sent to this port).
   3451 	 * We handle only DM class version 1 MAD's
   3452 	 */
   3453 	hdr = IBDM_IN_IBMFMSG_MADHDR(msg);
   3454 	if (ibdm_verify_mad_status(hdr) != IBDM_SUCCESS) {
   3455 		if (ibmf_free_msg(ibmf_hdl, &msg) != IBMF_SUCCESS) {
   3456 			IBTF_DPRINTF_L2("ibdm", "\tprocess_incoming_mad: "
   3457 			    "IBMF free msg failed DM request drop it");
   3458 		}
   3459 		return;
   3460 	}
   3461 
   3462 	transaction_id = b2h64(hdr->TransactionID);
   3463 
   3464 	mutex_enter(&ibdm.ibdm_mutex);
   3465 	gid_info = ibdm.ibdm_dp_gidlist_head;
   3466 	while (gid_info) {
   3467 		if ((gid_info->gl_transactionID  &
   3468 		    IBDM_GID_TRANSACTIONID_MASK) ==
   3469 		    (transaction_id & IBDM_GID_TRANSACTIONID_MASK))
   3470 			break;
   3471 		gid_info = gid_info->gl_next;
   3472 	}
   3473 	mutex_exit(&ibdm.ibdm_mutex);
   3474 
   3475 	if (gid_info == NULL) {
   3476 		/* Drop the packet */
   3477 		IBTF_DPRINTF_L2("ibdm", "process_incoming_mad: transaction ID"
   3478 		    " does not match: 0x%llx", transaction_id);
   3479 		if (ibmf_free_msg(ibmf_hdl, &msg) != IBMF_SUCCESS) {
   3480 			IBTF_DPRINTF_L2("ibdm", "process_incoming_mad: "
   3481 			    "IBMF free msg failed DM request drop it");
   3482 		}
   3483 		return;
   3484 	}
   3485 
   3486 	/* Handle redirection for all the MAD's, except ClassPortInfo */
   3487 	if (((IBDM_IN_IBMFMSG_STATUS(msg) & MAD_STATUS_REDIRECT_REQUIRED)) &&
   3488 	    (IBDM_IN_IBMFMSG_ATTR(msg) != IB_DM_ATTR_CLASSPORTINFO)) {
   3489 		ret = ibdm_handle_redirection(msg, gid_info, &flag);
   3490 		if (ret == IBDM_SUCCESS) {
   3491 			return;
   3492 		}
   3493 	} else {
   3494 		uint_t gl_state;
   3495 
   3496 		mutex_enter(&gid_info->gl_mutex);
   3497 		gl_state = gid_info->gl_state;
   3498 		mutex_exit(&gid_info->gl_mutex);
   3499 
   3500 		switch (gl_state) {
   3501 
   3502 		case IBDM_SET_CLASSPORTINFO:
   3503 			ibdm_handle_setclassportinfo(
   3504 			    ibmf_hdl, msg, gid_info, &flag);
   3505 			break;
   3506 
   3507 		case IBDM_GET_CLASSPORTINFO:
   3508 			ibdm_handle_classportinfo(
   3509 			    ibmf_hdl, msg, gid_info, &flag);
   3510 			break;
   3511 
   3512 		case IBDM_GET_IOUNITINFO:
   3513 			ibdm_handle_iounitinfo(ibmf_hdl, msg, gid_info, &flag);
   3514 			break;
   3515 
   3516 		case IBDM_GET_IOC_DETAILS:
   3517 			switch (IBDM_IN_IBMFMSG_ATTR(msg)) {
   3518 
   3519 			case IB_DM_ATTR_SERVICE_ENTRIES:
   3520 				ibdm_handle_srventry_mad(msg, gid_info, &flag);
   3521 				break;
   3522 
   3523 			case IB_DM_ATTR_IOC_CTRL_PROFILE:
   3524 				ibdm_handle_ioc_profile(
   3525 				    ibmf_hdl, msg, gid_info, &flag);
   3526 				break;
   3527 
   3528 			case IB_DM_ATTR_DIAG_CODE:
   3529 				ibdm_handle_diagcode(msg, gid_info, &flag);
   3530 				break;
   3531 
   3532 			default:
   3533 				IBTF_DPRINTF_L2("ibdm", "process_incoming_mad: "
   3534 				    "Error state, wrong attribute :-(");
   3535 				(void) ibmf_free_msg(ibmf_hdl, &msg);
   3536 				return;
   3537 			}
   3538 			break;
   3539 		default:
   3540 			IBTF_DPRINTF_L2("ibdm",
   3541 			    "process_incoming_mad: Dropping the packet"
   3542 			    " gl_state %x", gl_state);
   3543 			if (ibmf_free_msg(ibmf_hdl, &msg) != IBMF_SUCCESS) {
   3544 				IBTF_DPRINTF_L2("ibdm", "process_incoming_mad: "
   3545 				    "IBMF free msg failed DM request drop it");
   3546 			}
   3547 			return;
   3548 		}
   3549 	}
   3550 
   3551 	if ((flag & IBDM_IBMF_PKT_DUP_RESP) ||
   3552 	    (flag & IBDM_IBMF_PKT_UNEXP_RESP)) {
   3553 		IBTF_DPRINTF_L2("ibdm",
   3554 		    "\tprocess_incoming_mad:Dup/unexp resp : 0x%x", flag);
   3555 		if (ibmf_free_msg(ibmf_hdl, &msg) != IBMF_SUCCESS) {
   3556 			IBTF_DPRINTF_L2("ibdm", "process_incoming_mad: "
   3557 			    "IBMF free msg failed DM request drop it");
   3558 		}
   3559 		return;
   3560 	}
   3561 
   3562 	mutex_enter(&gid_info->gl_mutex);
   3563 	if (gid_info->gl_pending_cmds < 1) {
   3564 		IBTF_DPRINTF_L2("ibdm",
   3565 		    "\tprocess_incoming_mad: pending commands negative");
   3566 	}
   3567 	if (--gid_info->gl_pending_cmds) {
   3568 		IBTF_DPRINTF_L4("ibdm", "\tprocess_incoming_mad: "
   3569 		    "gid_info %p pending cmds %d",
   3570 		    gid_info, gid_info->gl_pending_cmds);
   3571 		mutex_exit(&gid_info->gl_mutex);
   3572 	} else {
   3573 		uint_t prev_state;
   3574 		IBTF_DPRINTF_L4("ibdm", "\tprocess_incoming_mad: Probing DONE");
   3575 		prev_state = gid_info->gl_state;
   3576 		gid_info->gl_state = IBDM_GID_PROBING_COMPLETE;
   3577 		if (prev_state == IBDM_SET_CLASSPORTINFO) {
   3578 			IBTF_DPRINTF_L4("ibdm",
   3579 			    "\tprocess_incoming_mad: "
   3580 			    "Setclassportinfo for Cisco FC GW is done.");
   3581 			gid_info->gl_flag &= ~IBDM_CISCO_PROBE;
   3582 			gid_info->gl_flag |= IBDM_CISCO_PROBE_DONE;
   3583 			mutex_exit(&gid_info->gl_mutex);
   3584 			cv_broadcast(&gid_info->gl_probe_cv);
   3585 		} else {
   3586 			mutex_exit(&gid_info->gl_mutex);
   3587 			ibdm_notify_newgid_iocs(gid_info);
   3588 			mutex_enter(&ibdm.ibdm_mutex);
   3589 			if (--ibdm.ibdm_ngid_probes_in_progress == 0) {
   3590 				IBTF_DPRINTF_L4("ibdm",
   3591 				    "\tprocess_incoming_mad: Wakeup");
   3592 				ibdm.ibdm_busy &= ~IBDM_PROBE_IN_PROGRESS;
   3593 				cv_broadcast(&ibdm.ibdm_probe_cv);
   3594 			}
   3595 			mutex_exit(&ibdm.ibdm_mutex);
   3596 		}
   3597 	}
   3598 
   3599 	/*
   3600 	 * Do not deallocate the IBMF packet if atleast one request
   3601 	 * is posted. IBMF packet is reused.
   3602 	 */
   3603 	if (!(flag & IBDM_IBMF_PKT_REUSED)) {
   3604 		if (ibmf_free_msg(ibmf_hdl, &msg) != IBMF_SUCCESS) {
   3605 			IBTF_DPRINTF_L2("ibdm", "\tprocess_incoming_mad: "
   3606 			    "IBMF free msg failed DM request drop it");
   3607 		}
   3608 	}
   3609 }
   3610 
   3611 
   3612 /*
   3613  * ibdm_verify_mad_status()
   3614  *	Verifies the MAD status
   3615  *	Returns IBDM_SUCCESS if status is correct
   3616  *	Returns IBDM_FAILURE for bogus MAD status
   3617  */
   3618 static int
   3619 ibdm_verify_mad_status(ib_mad_hdr_t *hdr)
   3620 {
   3621 	int	ret = 0;
   3622 
   3623 	if ((hdr->R_Method != IB_DM_DEVMGT_METHOD_GET_RESP) ||
   3624 	    (hdr->ClassVersion != IB_DM_CLASS_VERSION_1)) {
   3625 		return (IBDM_FAILURE);
   3626 	}
   3627 
   3628 	if (b2h16(hdr->Status) == 0)
   3629 		ret = IBDM_SUCCESS;
   3630 	else if ((b2h16(hdr->Status) & 0x1f) == MAD_STATUS_REDIRECT_REQUIRED)
   3631 		ret = IBDM_SUCCESS;
   3632 	else {
   3633 		IBTF_DPRINTF_L2("ibdm",
   3634 		    "\tverify_mad_status: Status : 0x%x", b2h16(hdr->Status));
   3635 		ret = IBDM_FAILURE;
   3636 	}
   3637 	return (ret);
   3638 }
   3639 
   3640 
   3641 
   3642 /*
   3643  * ibdm_handle_redirection()
   3644  *	Returns IBDM_SUCCESS/IBDM_FAILURE
   3645  */
   3646 static int
   3647 ibdm_handle_redirection(ibmf_msg_t *msg,
   3648     ibdm_dp_gidinfo_t *gid_info, int *flag)
   3649 {
   3650 	int			attrmod, ioc_no, start;
   3651 	void			*data;
   3652 	timeout_id_t		*timeout_id;
   3653 	ib_mad_hdr_t		*hdr;
   3654 	ibdm_ioc_info_t		*ioc = NULL;
   3655 	ibdm_timeout_cb_args_t	*cb_args;
   3656 	ib_mad_classportinfo_t	*cpi;
   3657 
   3658 	IBTF_DPRINTF_L4("ibdm", "\thandle_redirection: Enter");
   3659 	mutex_enter(&gid_info->gl_mutex);
   3660 	switch (gid_info->gl_state) {
   3661 	case IBDM_GET_IOUNITINFO:
   3662 		cb_args		= &gid_info->gl_iou_cb_args;
   3663 		timeout_id	= &gid_info->gl_timeout_id;
   3664 		break;
   3665 
   3666 	case IBDM_GET_IOC_DETAILS:
   3667 		attrmod	= IBDM_IN_IBMFMSG_ATTRMOD(msg);
   3668 		switch (IBDM_IN_IBMFMSG_ATTR(msg)) {
   3669 
   3670 		case IB_DM_ATTR_DIAG_CODE:
   3671 			if (attrmod == 0) {
   3672 				cb_args = &gid_info->gl_iou_cb_args;
   3673 				timeout_id = &gid_info->gl_timeout_id;
   3674 				break;
   3675 			}
   3676 			if (IBDM_IS_IOC_NUM_INVALID(attrmod, gid_info)) {
   3677 				IBTF_DPRINTF_L2("ibdm", "\thandle_redirction:"
   3678 				    "IOC# Out of range %d", attrmod);
   3679 				(*flag) |= IBDM_IBMF_PKT_UNEXP_RESP;
   3680 				mutex_exit(&gid_info->gl_mutex);
   3681 				return (IBDM_FAILURE);
   3682 			}
   3683 			ioc	= IBDM_GIDINFO2IOCINFO(gid_info, (attrmod -1));
   3684 			cb_args = &ioc->ioc_dc_cb_args;
   3685 			timeout_id = &ioc->ioc_dc_timeout_id;
   3686 			break;
   3687 
   3688 		case IB_DM_ATTR_IOC_CTRL_PROFILE:
   3689 			if (IBDM_IS_IOC_NUM_INVALID(attrmod, gid_info)) {
   3690 				IBTF_DPRINTF_L2("ibdm", "\thandle_redirction:"
   3691 				    "IOC# Out of range %d", attrmod);
   3692 				(*flag) |= IBDM_IBMF_PKT_UNEXP_RESP;
   3693 				mutex_exit(&gid_info->gl_mutex);
   3694 				return (IBDM_FAILURE);
   3695 			}
   3696 			ioc	= IBDM_GIDINFO2IOCINFO(gid_info, (attrmod -1));
   3697 			cb_args = &ioc->ioc_cb_args;
   3698 			timeout_id = &ioc->ioc_timeout_id;
   3699 			break;
   3700 
   3701 		case IB_DM_ATTR_SERVICE_ENTRIES:
   3702 			ioc_no	= ((attrmod >> 16) & IBDM_16_BIT_MASK);
   3703 			if (IBDM_IS_IOC_NUM_INVALID(ioc_no, gid_info)) {
   3704 				IBTF_DPRINTF_L2("ibdm", "\thandle_redirction:"
   3705 				    "IOC# Out of range %d", ioc_no);
   3706 				(*flag) |= IBDM_IBMF_PKT_UNEXP_RESP;
   3707 				mutex_exit(&gid_info->gl_mutex);
   3708 				return (IBDM_FAILURE);
   3709 			}
   3710 			start 	= (attrmod & IBDM_8_BIT_MASK);
   3711 			ioc	= IBDM_GIDINFO2IOCINFO(gid_info, (ioc_no -1));
   3712 			if (start > ioc->ioc_profile.ioc_service_entries) {
   3713 				IBTF_DPRINTF_L2("ibdm", "\thandle_redirction:"
   3714 				    " SE index Out of range %d", start);
   3715 				(*flag) |= IBDM_IBMF_PKT_UNEXP_RESP;
   3716 				mutex_exit(&gid_info->gl_mutex);
   3717 				return (IBDM_FAILURE);
   3718 			}
   3719 			cb_args = &ioc->ioc_serv[start].se_cb_args;
   3720 			timeout_id = &ioc->ioc_serv[start].se_timeout_id;
   3721 			break;
   3722 
   3723 		default:
   3724 			/* ERROR State */
   3725 			IBTF_DPRINTF_L2("ibdm",
   3726 			    "\thandle_redirection: wrong attribute :-(");
   3727 			(*flag) |= IBDM_IBMF_PKT_UNEXP_RESP;
   3728 			mutex_exit(&gid_info->gl_mutex);
   3729 			return (IBDM_FAILURE);
   3730 		}
   3731 		break;
   3732 	default:
   3733 		/* ERROR State */
   3734 		IBTF_DPRINTF_L2("ibdm",
   3735 		    "\thandle_redirection: Error state :-(");
   3736 		(*flag) |= IBDM_IBMF_PKT_UNEXP_RESP;
   3737 		mutex_exit(&gid_info->gl_mutex);
   3738 		return (IBDM_FAILURE);
   3739 	}
   3740 	if ((*timeout_id) != 0) {
   3741 		mutex_exit(&gid_info->gl_mutex);
   3742 		if (untimeout(*timeout_id) == -1) {
   3743 			IBTF_DPRINTF_L2("ibdm", "\thandle_redirection: "
   3744 			    "untimeout failed %x", *timeout_id);
   3745 		} else {
   3746 			IBTF_DPRINTF_L5("ibdm",
   3747 			    "\thandle_redirection: timeout %x", *timeout_id);
   3748 		}
   3749 		mutex_enter(&gid_info->gl_mutex);
   3750 		*timeout_id = 0;
   3751 	}
   3752 
   3753 	data = msg->im_msgbufs_recv.im_bufs_cl_data;
   3754 	cpi = (ib_mad_classportinfo_t *)data;
   3755 
   3756 	gid_info->gl_resp_timeout	=
   3757 	    (b2h32(cpi->RespTimeValue) & 0x1F);
   3758 
   3759 	gid_info->gl_redirected		= B_TRUE;
   3760 	gid_info->gl_redirect_dlid	= b2h16(cpi->RedirectLID);
   3761 	gid_info->gl_redirect_QP	= (b2h32(cpi->RedirectQP) & 0xffffff);
   3762 	gid_info->gl_redirect_pkey	= b2h16(cpi->RedirectP_Key);
   3763 	gid_info->gl_redirect_qkey	= b2h32(cpi->RedirectQ_Key);
   3764 	gid_info->gl_redirectGID_hi	= b2h64(cpi->RedirectGID_hi);
   3765 	gid_info->gl_redirectGID_lo	= b2h64(cpi->RedirectGID_lo);
   3766 	gid_info->gl_redirectSL		= cpi->RedirectSL;
   3767 
   3768 	if (gid_info->gl_redirect_dlid != 0) {
   3769 		msg->im_local_addr.ia_remote_lid =
   3770 		    gid_info->gl_redirect_dlid;
   3771 	}
   3772 	ibdm_bump_transactionID(gid_info);
   3773 	mutex_exit(&gid_info->gl_mutex);
   3774 
   3775 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*msg, *hdr))
   3776 	ibdm_alloc_send_buffers(msg);
   3777 
   3778 	hdr			= IBDM_OUT_IBMFMSG_MADHDR(msg);
   3779 	hdr->BaseVersion	= MAD_CLASS_BASE_VERS_1;
   3780 	hdr->MgmtClass		= MAD_MGMT_CLASS_DEV_MGT;
   3781 	hdr->ClassVersion	= IB_DM_CLASS_VERSION_1;
   3782 	hdr->R_Method		= IB_DM_DEVMGT_METHOD_GET;
   3783 	hdr->Status		= 0;
   3784 	hdr->TransactionID	= h2b64(gid_info->gl_transactionID);
   3785 	hdr->AttributeID	=
   3786 	    msg->im_msgbufs_recv.im_bufs_mad_hdr->AttributeID;
   3787 	hdr->AttributeModifier	=
   3788 	    msg->im_msgbufs_recv.im_bufs_mad_hdr->AttributeModifier;
   3789 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*msg, *hdr))
   3790 
   3791 	msg->im_local_addr.ia_remote_qno = gid_info->gl_redirect_QP;
   3792 	msg->im_local_addr.ia_p_key = gid_info->gl_redirect_pkey;
   3793 	msg->im_local_addr.ia_q_key = gid_info->gl_redirect_qkey;
   3794 	msg->im_local_addr.ia_service_level = gid_info->gl_redirectSL;
   3795 
   3796 	mutex_enter(&gid_info->gl_mutex);
   3797 	*timeout_id = timeout(ibdm_pkt_timeout_hdlr,
   3798 	    cb_args, IBDM_TIMEOUT_VALUE(ibdm_dft_timeout));
   3799 	mutex_exit(&gid_info->gl_mutex);
   3800 
   3801 	IBTF_DPRINTF_L5("ibdm", "\thandle_redirect:"
   3802 	    "timeout %x", *timeout_id);
   3803 
   3804 	if (ibmf_msg_transport(gid_info->gl_ibmf_hdl, gid_info->gl_qp_hdl,
   3805 	    msg, NULL, ibdm_ibmf_send_cb, cb_args, 0) != IBMF_SUCCESS) {
   3806 		IBTF_DPRINTF_L4("ibdm", "\thandle_redirection:"
   3807 		    "message transport failed");
   3808 		ibdm_ibmf_send_cb(gid_info->gl_ibmf_hdl, msg, cb_args);
   3809 	}
   3810 	(*flag) |= IBDM_IBMF_PKT_REUSED;
   3811 	IBTF_DPRINTF_L4("ibdm", "\thandle_redirection: Exit");
   3812 	return (IBDM_SUCCESS);
   3813 }
   3814 
   3815 
   3816 /*
   3817  * ibdm_pkt_timeout_hdlr
   3818  *	This  timeout  handler is  registed for every  IBMF  packet that is
   3819  *	sent through the IBMF.  It gets called when no response is received
   3820  *	within the specified time for the packet. No retries for the failed
   3821  *	commands  currently.  Drops the failed  IBMF packet and  update the
   3822  *	pending list commands.
   3823  */
   3824 static void
   3825 ibdm_pkt_timeout_hdlr(void *arg)
   3826 {
   3827 	ibdm_iou_info_t		*iou;
   3828 	ibdm_ioc_info_t		*ioc;
   3829 	ibdm_timeout_cb_args_t	*cb_args = arg;
   3830 	ibdm_dp_gidinfo_t	*gid_info;
   3831 	int			srv_ent;
   3832 	uint_t			new_gl_state;
   3833 
   3834 	IBTF_DPRINTF_L2("ibdm", "\tpkt_timeout_hdlr: gid_info: %p "
   3835 	    "rtype 0x%x iocidx 0x%x srvidx %d", cb_args->cb_gid_info,
   3836 	    cb_args->cb_req_type, cb_args->cb_ioc_num,
   3837 	    cb_args->cb_srvents_start);
   3838 
   3839 	gid_info = cb_args->cb_gid_info;
   3840 	mutex_enter(&gid_info->gl_mutex);
   3841 
   3842 	if ((gid_info->gl_state == IBDM_GID_PROBING_COMPLETE) ||
   3843 	    (cb_args->cb_req_type == 0)) {
   3844 
   3845 		IBTF_DPRINTF_L2("ibdm", "\tpkt_timeout_hdlr: req completed"
   3846 		    "rtype 0x%x iocidx 0x%x srvidx %d", cb_args->cb_req_type,
   3847 		    cb_args->cb_ioc_num, cb_args->cb_srvents_start);
   3848 
   3849 		if (gid_info->gl_timeout_id)
   3850 			gid_info->gl_timeout_id = 0;
   3851 		mutex_exit(&gid_info->gl_mutex);
   3852 		return;
   3853 	}
   3854 	if (cb_args->cb_retry_count) {
   3855 		cb_args->cb_retry_count--;
   3856 		/*
   3857 		 * A new timeout_id is set inside ibdm_retry_command().
   3858 		 * When the function returns an error, the timeout_id
   3859 		 * is reset (to zero) in the switch statement below.
   3860 		 */
   3861 		if (ibdm_retry_command(cb_args) == IBDM_SUCCESS) {
   3862 			mutex_exit(&gid_info->gl_mutex);
   3863 			return;
   3864 		}
   3865 		cb_args->cb_retry_count = 0;
   3866 	}
   3867 
   3868 	IBTF_DPRINTF_L2("ibdm", "\tpkt_timeout_hdlr: command failed: gid %p"
   3869 	    " rtype 0x%x iocidx 0x%x srvidx %d", cb_args->cb_gid_info,
   3870 	    cb_args->cb_req_type, cb_args->cb_ioc_num,
   3871 	    cb_args->cb_srvents_start);
   3872 
   3873 	switch (cb_args->cb_req_type) {
   3874 
   3875 	case IBDM_REQ_TYPE_CLASSPORTINFO:
   3876 	case IBDM_REQ_TYPE_IOUINFO:
   3877 		new_gl_state = IBDM_GID_PROBING_FAILED;
   3878 		if (gid_info->gl_timeout_id)
   3879 			gid_info->gl_timeout_id = 0;
   3880 		break;
   3881 
   3882 	case IBDM_REQ_TYPE_IOCINFO:
   3883 		new_gl_state = IBDM_GID_PROBING_COMPLETE;
   3884 		iou = gid_info->gl_iou;
   3885 		ioc = &iou->iou_ioc_info[cb_args->cb_ioc_num];
   3886 		ioc->ioc_state = IBDM_IOC_STATE_PROBE_FAILED;
   3887 		if (ioc->ioc_timeout_id)
   3888 			ioc->ioc_timeout_id = 0;
   3889 		break;
   3890 
   3891 	case IBDM_REQ_TYPE_SRVENTS:
   3892 		new_gl_state = IBDM_GID_PROBING_COMPLETE;
   3893 		iou = gid_info->gl_iou;
   3894 		ioc = &iou->iou_ioc_info[cb_args->cb_ioc_num];
   3895 		ioc->ioc_state = IBDM_IOC_STATE_PROBE_FAILED;
   3896 		srv_ent = cb_args->cb_srvents_start;
   3897 		if (ioc->ioc_serv[srv_ent].se_timeout_id)
   3898 			ioc->ioc_serv[srv_ent].se_timeout_id = 0;
   3899 		break;
   3900 
   3901 	case IBDM_REQ_TYPE_IOU_DIAGCODE:
   3902 		new_gl_state = IBDM_GID_PROBING_COMPLETE;
   3903 		iou = gid_info->gl_iou;
   3904 		iou->iou_dc_valid = B_FALSE;
   3905 		if (gid_info->gl_timeout_id)
   3906 			gid_info->gl_timeout_id = 0;
   3907 		break;
   3908 
   3909 	case IBDM_REQ_TYPE_IOC_DIAGCODE:
   3910 		new_gl_state = IBDM_GID_PROBING_COMPLETE;
   3911 		iou = gid_info->gl_iou;
   3912 		ioc = &iou->iou_ioc_info[cb_args->cb_ioc_num];
   3913 		ioc->ioc_dc_valid = B_FALSE;
   3914 		if (ioc->ioc_dc_timeout_id)
   3915 			ioc->ioc_dc_timeout_id = 0;
   3916 		break;
   3917 
   3918 	default: /* ERROR State */
   3919 		new_gl_state = IBDM_GID_PROBING_FAILED;
   3920 		if (gid_info->gl_timeout_id)
   3921 			gid_info->gl_timeout_id = 0;
   3922 		IBTF_DPRINTF_L2("ibdm",
   3923 		    "\tpkt_timeout_hdlr: wrong request type.");
   3924 		break;
   3925 	}
   3926 
   3927 	--gid_info->gl_pending_cmds; /* decrease the counter */
   3928 
   3929 	if (gid_info->gl_pending_cmds == 0) {
   3930 		gid_info->gl_state = new_gl_state;
   3931 		mutex_exit(&gid_info->gl_mutex);
   3932 		/*
   3933 		 * Delete this gid_info if the gid probe fails.
   3934 		 */
   3935 		if (new_gl_state == IBDM_GID_PROBING_FAILED) {
   3936 			ibdm_delete_glhca_list(gid_info);
   3937 		}
   3938 		ibdm_notify_newgid_iocs(gid_info);
   3939 		mutex_enter(&ibdm.ibdm_mutex);
   3940 		if (--ibdm.ibdm_ngid_probes_in_progress == 0) {
   3941 			IBTF_DPRINTF_L4("ibdm", "\tpkt_timeout_hdlr: Wakeup");
   3942 			ibdm.ibdm_busy &= ~IBDM_PROBE_IN_PROGRESS;
   3943 			cv_broadcast(&ibdm.ibdm_probe_cv);
   3944 		}
   3945 		mutex_exit(&ibdm.ibdm_mutex);
   3946 	} else {
   3947 		/*
   3948 		 * Reset gl_pending_cmd if the extra timeout happens since
   3949 		 * gl_pending_cmd becomes negative as a result.
   3950 		 */
   3951 		if (gid_info->gl_pending_cmds < 0) {
   3952 			gid_info->gl_pending_cmds = 0;
   3953 			IBTF_DPRINTF_L2("ibdm",
   3954 			    "\tpkt_timeout_hdlr: extra timeout request."
   3955 			    " reset gl_pending_cmds");
   3956 		}
   3957 		mutex_exit(&gid_info->gl_mutex);
   3958 		/*
   3959 		 * Delete this gid_info if the gid probe fails.
   3960 		 */
   3961 		if (new_gl_state == IBDM_GID_PROBING_FAILED) {
   3962 			ibdm_delete_glhca_list(gid_info);
   3963 		}
   3964 	}
   3965 }
   3966 
   3967 
   3968 /*
   3969  * ibdm_retry_command()
   3970  *	Retries the failed command.
   3971  *	Returns IBDM_FAILURE/IBDM_SUCCESS
   3972  */
   3973 static int
   3974 ibdm_retry_command(ibdm_timeout_cb_args_t *cb_args)
   3975 {
   3976 	int			ret;
   3977 	ibmf_msg_t		*msg;
   3978 	ib_mad_hdr_t		*hdr;
   3979 	ibdm_dp_gidinfo_t	*gid_info = cb_args->cb_gid_info;
   3980 	timeout_id_t		*timeout_id;
   3981 	ibdm_ioc_info_t		*ioc;
   3982 	int			ioc_no;
   3983 	ASSERT(MUTEX_HELD(&gid_info->gl_mutex));
   3984 
   3985 	IBTF_DPRINTF_L2("ibdm", "\tretry_command: gid_info: %p "
   3986 	    "rtype 0x%x iocidx 0x%x srvidx %d", cb_args->cb_gid_info,
   3987 	    cb_args->cb_req_type, cb_args->cb_ioc_num,
   3988 	    cb_args->cb_srvents_start);
   3989 
   3990 	ret = ibmf_alloc_msg(gid_info->gl_ibmf_hdl, IBMF_ALLOC_NOSLEEP, &msg);
   3991 
   3992 
   3993 	/*
   3994 	 * Reset the gid if alloc_msg failed with BAD_HANDLE
   3995 	 * ibdm_reset_gidinfo reinits the gid_info
   3996 	 */
   3997 	if (ret == IBMF_BAD_HANDLE) {
   3998 		IBTF_DPRINTF_L3(ibdm_string, "\tretry_command: gid %p hdl bad",
   3999 		    gid_info);
   4000 
   4001 		mutex_exit(&gid_info->gl_mutex);
   4002 		ibdm_reset_gidinfo(gid_info);
   4003 		mutex_enter(&gid_info->gl_mutex);
   4004 
   4005 		/* Retry alloc */
   4006 		ret = ibmf_alloc_msg(gid_info->gl_ibmf_hdl, IBMF_ALLOC_NOSLEEP,
   4007 		    &msg);
   4008 	}
   4009 
   4010 	if (ret != IBDM_SUCCESS) {
   4011 		IBTF_DPRINTF_L2("ibdm", "\tretry_command: alloc failed: %p "
   4012 		    "rtype 0x%x iocidx 0x%x srvidx %d", cb_args->cb_gid_info,
   4013 		    cb_args->cb_req_type, cb_args->cb_ioc_num,
   4014 		    cb_args->cb_srvents_start);
   4015 		return (IBDM_FAILURE);
   4016 	}
   4017 
   4018 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*msg))
   4019 	ibdm_alloc_send_buffers(msg);
   4020 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*msg))
   4021 
   4022 	ibdm_bump_transactionID(gid_info);
   4023 
   4024 	msg->im_local_addr.ia_local_lid	= gid_info->gl_slid;
   4025 	msg->im_local_addr.ia_remote_lid	= gid_info->gl_dlid;
   4026 	if (gid_info->gl_redirected == B_TRUE) {
   4027 		if (gid_info->gl_redirect_dlid != 0) {
   4028 			msg->im_local_addr.ia_remote_lid =
   4029 			    gid_info->gl_redirect_dlid;
   4030 		}
   4031 		msg->im_local_addr.ia_remote_qno = gid_info->gl_redirect_QP;
   4032 		msg->im_local_addr.ia_p_key = gid_info->gl_redirect_pkey;
   4033 		msg->im_local_addr.ia_q_key = gid_info->gl_redirect_qkey;
   4034 		msg->im_local_addr.ia_service_level = gid_info->gl_redirectSL;
   4035 	} else {
   4036 		msg->im_local_addr.ia_remote_qno = 1;
   4037 		msg->im_local_addr.ia_p_key = gid_info->gl_p_key;
   4038 		msg->im_local_addr.ia_q_key = IB_GSI_QKEY;
   4039 		msg->im_local_addr.ia_service_level = gid_info->gl_SL;
   4040 	}
   4041 	hdr = IBDM_OUT_IBMFMSG_MADHDR(msg);
   4042 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*hdr))
   4043 	hdr->BaseVersion	= MAD_CLASS_BASE_VERS_1;
   4044 	hdr->MgmtClass		= MAD_MGMT_CLASS_DEV_MGT;
   4045 	hdr->ClassVersion	= IB_DM_CLASS_VERSION_1;
   4046 	hdr->R_Method		= IB_DM_DEVMGT_METHOD_GET;
   4047 	hdr->Status		= 0;
   4048 	hdr->TransactionID	= h2b64(gid_info->gl_transactionID);
   4049 
   4050 	switch (cb_args->cb_req_type) {
   4051 	case IBDM_REQ_TYPE_CLASSPORTINFO:
   4052 		hdr->AttributeID = h2b16(IB_DM_ATTR_CLASSPORTINFO);
   4053 		hdr->AttributeModifier = 0;
   4054 		timeout_id = &gid_info->gl_timeout_id;
   4055 		break;
   4056 	case IBDM_REQ_TYPE_IOUINFO:
   4057 		hdr->AttributeID = h2b16(IB_DM_ATTR_IO_UNITINFO);
   4058 		hdr->AttributeModifier = 0;
   4059 		timeout_id = &gid_info->gl_timeout_id;
   4060 		break;
   4061 	case IBDM_REQ_TYPE_IOCINFO:
   4062 		hdr->AttributeID = h2b16(IB_DM_ATTR_IOC_CTRL_PROFILE);
   4063 		hdr->AttributeModifier = h2b32(cb_args->cb_ioc_num + 1);
   4064 		ioc = IBDM_GIDINFO2IOCINFO(gid_info, cb_args->cb_ioc_num);
   4065 		timeout_id = &ioc->ioc_timeout_id;
   4066 		break;
   4067 	case IBDM_REQ_TYPE_SRVENTS:
   4068 		hdr->AttributeID = h2b16(IB_DM_ATTR_SERVICE_ENTRIES);
   4069 		ibdm_fill_srv_attr_mod(hdr, cb_args);
   4070 		ioc = IBDM_GIDINFO2IOCINFO(gid_info, cb_args->cb_ioc_num);
   4071 		timeout_id =
   4072 		    &ioc->ioc_serv[cb_args->cb_srvents_start].se_timeout_id;
   4073 		break;
   4074 	case IBDM_REQ_TYPE_IOU_DIAGCODE:
   4075 		hdr->AttributeID = h2b16(IB_DM_ATTR_DIAG_CODE);
   4076 		hdr->AttributeModifier = 0;
   4077 		timeout_id = &gid_info->gl_timeout_id;
   4078 		break;
   4079 	case IBDM_REQ_TYPE_IOC_DIAGCODE:
   4080 		hdr->AttributeID = h2b16(IB_DM_ATTR_DIAG_CODE);
   4081 		hdr->AttributeModifier = h2b32(cb_args->cb_ioc_num + 1);
   4082 		ioc_no = cb_args->cb_ioc_num;
   4083 		ioc = &gid_info->gl_iou->iou_ioc_info[ioc_no];
   4084 		timeout_id = &ioc->ioc_dc_timeout_id;
   4085 		break;
   4086 	}
   4087 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*hdr))
   4088 
   4089 	*timeout_id = timeout(ibdm_pkt_timeout_hdlr,
   4090 	    cb_args, IBDM_TIMEOUT_VALUE(ibdm_dft_timeout));
   4091 
   4092 	mutex_exit(&gid_info->gl_mutex);
   4093 
   4094 	IBTF_DPRINTF_L5("ibdm", "\tretry_command: %p,%x,%d,%d:"
   4095 	    "timeout %x", cb_args->cb_req_type, cb_args->cb_ioc_num,
   4096 	    cb_args->cb_srvents_start, *timeout_id);
   4097 
   4098 	if (ibmf_msg_transport(gid_info->gl_ibmf_hdl,
   4099 	    gid_info->gl_qp_hdl, msg, NULL, ibdm_ibmf_send_cb,
   4100 	    cb_args, 0) != IBMF_SUCCESS) {
   4101 		IBTF_DPRINTF_L2("ibdm", "\tretry_command: send failed: %p "
   4102 		    "rtype 0x%x iocidx 0x%x srvidx %d", cb_args->cb_gid_info,
   4103 		    cb_args->cb_req_type, cb_args->cb_ioc_num,
   4104 		    cb_args->cb_srvents_start);
   4105 		ibdm_ibmf_send_cb(gid_info->gl_ibmf_hdl, msg, cb_args);
   4106 	}
   4107 	mutex_enter(&gid_info->gl_mutex);
   4108 	return (IBDM_SUCCESS);
   4109 }
   4110 
   4111 
   4112 /*
   4113  * ibdm_update_ioc_port_gidlist()
   4114  */
   4115 static void
   4116 ibdm_update_ioc_port_gidlist(ibdm_ioc_info_t *dest,
   4117     ibdm_dp_gidinfo_t *gid_info)
   4118 {
   4119 	int		ii, ngid_ents;
   4120 	ibdm_gid_t	*tmp;
   4121 	ibdm_hca_list_t	*gid_hca_head, *temp;
   4122 	ibdm_hca_list_t	*ioc_head = NULL;
   4123 	ASSERT(MUTEX_HELD(&gid_info->gl_mutex));
   4124 
   4125 	IBTF_DPRINTF_L5("ibdm", "\tupdate_ioc_port_gidlist: Enter");
   4126 
   4127 	ngid_ents = gid_info->gl_ngids;
   4128 	dest->ioc_nportgids = ngid_ents;
   4129 	dest->ioc_gid_list = kmem_zalloc(sizeof (ibdm_gid_t) *
   4130 	    ngid_ents, KM_SLEEP);
   4131 	tmp = gid_info->gl_gid;
   4132 	for (ii = 0; (ii < ngid_ents) && (tmp); ii++) {
   4133 		dest->ioc_gid_list[ii].gid_dgid_hi = tmp->gid_dgid_hi;
   4134 		dest->ioc_gid_list[ii].gid_dgid_lo = tmp->gid_dgid_lo;
   4135 		tmp = tmp->gid_next;
   4136 	}
   4137 
   4138 	gid_hca_head = gid_info->gl_hca_list;
   4139 	while (gid_hca_head) {
   4140 		temp = ibdm_dup_hca_attr(gid_hca_head);
   4141 		temp->hl_next = ioc_head;
   4142 		ioc_head = temp;
   4143 		gid_hca_head = gid_hca_head->hl_next;
   4144 	}
   4145 	dest->ioc_hca_list = ioc_head;
   4146 }
   4147 
   4148 
   4149 /*
   4150  * ibdm_alloc_send_buffers()
   4151  *	Allocates memory for the IBMF send buffer to send and/or receive
   4152  *	the Device Management MAD packet.
   4153  */
   4154 static void
   4155 ibdm_alloc_send_buffers(ibmf_msg_t *msgp)
   4156 {
   4157 	msgp->im_msgbufs_send.im_bufs_mad_hdr =
   4158 	    kmem_zalloc(IBDM_MAD_SIZE, KM_SLEEP);
   4159 
   4160 	msgp->im_msgbufs_send.im_bufs_cl_hdr = (uchar_t *)
   4161 	    msgp->im_msgbufs_send.im_bufs_mad_hdr + sizeof (ib_mad_hdr_t);
   4162 	msgp->im_msgbufs_send.im_bufs_cl_hdr_len = IBDM_DM_MAD_HDR_SZ;
   4163 
   4164 	msgp->im_msgbufs_send.im_bufs_cl_data =
   4165 	    ((char *)msgp->im_msgbufs_send.im_bufs_cl_hdr + IBDM_DM_MAD_HDR_SZ);
   4166 	msgp->im_msgbufs_send.im_bufs_cl_data_len =
   4167 	    IBDM_MAD_SIZE - sizeof (ib_mad_hdr_t) - IBDM_DM_MAD_HDR_SZ;
   4168 }
   4169 
   4170 
   4171 /*
   4172  * ibdm_alloc_send_buffers()
   4173  *	De-allocates memory for the IBMF send buffer
   4174  */
   4175 static void
   4176 ibdm_free_send_buffers(ibmf_msg_t *msgp)
   4177 {
   4178 	if (msgp->im_msgbufs_send.im_bufs_mad_hdr != NULL)
   4179 		kmem_free(msgp->im_msgbufs_send.im_bufs_mad_hdr, IBDM_MAD_SIZE);
   4180 }
   4181 
   4182 /*
   4183  * ibdm_probe_ioc()
   4184  *  	1. Gets the node records for the port GUID. This detects all the port
   4185  *  		to the IOU.
   4186  *	2. Selectively probes all the IOC, given it's node GUID
   4187  *	3. In case of reprobe, only the IOC to be reprobed is send the IOC
   4188  *		Controller Profile asynchronously
   4189  */
   4190 /*ARGSUSED*/
   4191 static void
   4192 ibdm_probe_ioc(ib_guid_t nodeguid, ib_guid_t ioc_guid, int reprobe_flag)
   4193 {
   4194 	int			ii, nrecords;
   4195 	size_t			nr_len = 0, pi_len = 0;
   4196 	ib_gid_t		sgid, dgid;
   4197 	ibdm_hca_list_t		*hca_list = NULL;
   4198 	sa_node_record_t	*nr, *tmp;
   4199 	ibdm_port_attr_t	*port = NULL;
   4200 	ibdm_dp_gidinfo_t	*reprobe_gid, *new_gid, *node_gid;
   4201 	ibdm_dp_gidinfo_t	*temp_gidinfo;
   4202 	ibdm_gid_t		*temp_gid;
   4203 	sa_portinfo_record_t	*pi;
   4204 
   4205 	IBTF_DPRINTF_L4("ibdm", "\tprobe_ioc(%llx, %llx, %x): Begin",
   4206 	    nodeguid, ioc_guid, reprobe_flag);
   4207 
   4208 	/* Rescan the GID list for any removed GIDs for reprobe */
   4209 	if (reprobe_flag)
   4210 		ibdm_rescan_gidlist(&ioc_guid);
   4211 
   4212 	mutex_enter(&ibdm.ibdm_hl_mutex);
   4213 	for (ibdm_get_next_port(&hca_list, &port, 1); port;
   4214 	    ibdm_get_next_port(&hca_list, &port, 1)) {
   4215 		reprobe_gid = new_gid = node_gid = NULL;
   4216 
   4217 		nr = ibdm_get_node_records(port->pa_sa_hdl, &nr_len, nodeguid);
   4218 		if (nr == NULL) {
   4219 			IBTF_DPRINTF_L4("ibdm", "\tprobe_ioc: no records");
   4220 			continue;
   4221 		}
   4222 		nrecords = (nr_len / sizeof (sa_node_record_t));
   4223 		for (tmp = nr, ii = 0;  (ii < nrecords); ii++, tmp++) {
   4224 			if ((pi = ibdm_get_portinfo(
   4225 			    port->pa_sa_hdl, &pi_len, tmp->LID)) ==  NULL) {
   4226 				IBTF_DPRINTF_L4("ibdm",
   4227 				    "\tibdm_get_portinfo: no portinfo recs");
   4228 				continue;
   4229 			}
   4230 
   4231 			/*
   4232 			 * If Device Management is not supported on
   4233 			 * this port, skip the rest.
   4234 			 */
   4235 			if (!(pi->PortInfo.CapabilityMask &
   4236 			    SM_CAP_MASK_IS_DM_SUPPD)) {
   4237 				kmem_free(pi, pi_len);
   4238 				continue;
   4239 			}
   4240 
   4241 			/*
   4242 			 * For reprobes: Check if GID, already in
   4243 			 * the list. If so, set the state to SKIPPED
   4244 			 */
   4245 			if (((temp_gidinfo = ibdm_find_gid(nodeguid,
   4246 			    tmp->NodeInfo.PortGUID)) != NULL) &&
   4247 			    temp_gidinfo->gl_state ==
   4248 			    IBDM_GID_PROBING_COMPLETE) {
   4249 				ASSERT(reprobe_gid == NULL);
   4250 				ibdm_addto_glhcalist(temp_gidinfo,
   4251 				    hca_list);
   4252 				reprobe_gid = temp_gidinfo;
   4253 				kmem_free(pi, pi_len);
   4254 				continue;
   4255 			} else if (temp_gidinfo != NULL) {
   4256 				kmem_free(pi, pi_len);
   4257 				ibdm_addto_glhcalist(temp_gidinfo,
   4258 				    hca_list);
   4259 				continue;
   4260 			}
   4261 
   4262 			IBTF_DPRINTF_L4("ibdm", "\tprobe_ioc : "
   4263 			    "create_gid : prefix %llx, guid %llx\n",
   4264 			    pi->PortInfo.GidPrefix,
   4265 			    tmp->NodeInfo.PortGUID);
   4266 
   4267 			sgid.gid_prefix = port->pa_sn_prefix;
   4268 			sgid.gid_guid = port->pa_port_guid;
   4269 			dgid.gid_prefix = pi->PortInfo.GidPrefix;
   4270 			dgid.gid_guid = tmp->NodeInfo.PortGUID;
   4271 			new_gid = ibdm_create_gid_info(port, sgid,
   4272 			    dgid);
   4273 			if (new_gid == NULL) {
   4274 				IBTF_DPRINTF_L2("ibdm", "\tprobe_ioc: "
   4275 				    "create_gid_info failed\n");
   4276 				kmem_free(pi, pi_len);
   4277 				continue;
   4278 			}
   4279 			if (node_gid == NULL) {
   4280 				node_gid = new_gid;
   4281 				ibdm_add_to_gl_gid(node_gid, node_gid);
   4282 			} else {
   4283 				IBTF_DPRINTF_L4("ibdm",
   4284 				    "\tprobe_ioc: new gid");
   4285 				temp_gid = kmem_zalloc(
   4286 				    sizeof (ibdm_gid_t), KM_SLEEP);
   4287 				temp_gid->gid_dgid_hi =
   4288 				    new_gid->gl_dgid_hi;
   4289 				temp_gid->gid_dgid_lo =
   4290 				    new_gid->gl_dgid_lo;
   4291 				temp_gid->gid_next = node_gid->gl_gid;
   4292 				node_gid->gl_gid = temp_gid;
   4293 				node_gid->gl_ngids++;
   4294 			}
   4295 			new_gid->gl_is_dm_capable = B_TRUE;
   4296 			new_gid->gl_nodeguid = nodeguid;
   4297 			new_gid->gl_portguid = dgid.gid_guid;
   4298 			ibdm_addto_glhcalist(new_gid, hca_list);
   4299 
   4300 			/*
   4301 			 * Set the state to skipped as all these
   4302 			 * gids point to the same node.
   4303 			 * We (re)probe only one GID below and reset
   4304 			 * state appropriately
   4305 			 */
   4306 			new_gid->gl_state = IBDM_GID_PROBING_SKIPPED;
   4307 			new_gid->gl_devid = (*tmp).NodeInfo.DeviceID;
   4308 			kmem_free(pi, pi_len);
   4309 		}
   4310 		kmem_free(nr, nr_len);
   4311 
   4312 		IBTF_DPRINTF_L4("ibdm", "\tprobe_ioc : reprobe_flag %d "
   4313 		    "reprobe_gid %p new_gid %p node_gid %p",
   4314 		    reprobe_flag, reprobe_gid, new_gid, node_gid);
   4315 
   4316 		if (reprobe_flag != 0 && reprobe_gid != NULL) {
   4317 			int	niocs, jj;
   4318 			ibdm_ioc_info_t *tmp_ioc;
   4319 			int ioc_matched = 0;
   4320 
   4321 			mutex_exit(&ibdm.ibdm_hl_mutex);
   4322 			mutex_enter(&reprobe_gid->gl_mutex);
   4323 			reprobe_gid->gl_state = IBDM_GET_IOC_DETAILS;
   4324 			niocs =
   4325 			    reprobe_gid->gl_iou->iou_info.iou_num_ctrl_slots;
   4326 			reprobe_gid->gl_pending_cmds++;
   4327 			mutex_exit(&reprobe_gid->gl_mutex);
   4328 
   4329 			for (jj = 0; jj < niocs; jj++) {
   4330 				tmp_ioc =
   4331 				    IBDM_GIDINFO2IOCINFO(reprobe_gid, jj);
   4332 				if (tmp_ioc->ioc_profile.ioc_guid != ioc_guid)
   4333 					continue;
   4334 
   4335 				ioc_matched = 1;
   4336 
   4337 				/*
   4338 				 * Explicitly set gl_reprobe_flag to 0 so that
   4339 				 * IBnex is not notified on completion
   4340 				 */
   4341 				mutex_enter(&reprobe_gid->gl_mutex);
   4342 				reprobe_gid->gl_reprobe_flag = 0;
   4343 				mutex_exit(&reprobe_gid->gl_mutex);
   4344 
   4345 				mutex_enter(&ibdm.ibdm_mutex);
   4346 				ibdm.ibdm_ngid_probes_in_progress++;
   4347 				mutex_exit(&ibdm.ibdm_mutex);
   4348 				if (ibdm_send_ioc_profile(reprobe_gid, jj) !=
   4349 				    IBDM_SUCCESS) {
   4350 					IBTF_DPRINTF_L4("ibdm",
   4351 					    "\tprobe_ioc: "
   4352 					    "send_ioc_profile failed "
   4353 					    "for ioc %d", jj);
   4354 					ibdm_gid_decr_pending(reprobe_gid);
   4355 					break;
   4356 				}
   4357 				mutex_enter(&ibdm.ibdm_mutex);
   4358 				ibdm_wait_probe_completion();
   4359 				mutex_exit(&ibdm.ibdm_mutex);
   4360 				break;
   4361 			}
   4362 			if (ioc_matched == 0)
   4363 				ibdm_gid_decr_pending(reprobe_gid);
   4364 			else {
   4365 				mutex_enter(&ibdm.ibdm_hl_mutex);
   4366 				break;
   4367 			}
   4368 		} else if (new_gid != NULL) {
   4369 			mutex_exit(&ibdm.ibdm_hl_mutex);
   4370 			node_gid = node_gid ? node_gid : new_gid;
   4371 
   4372 			/*
   4373 			 * New or reinserted GID : Enable notification
   4374 			 * to IBnex
   4375 			 */
   4376 			mutex_enter(&node_gid->gl_mutex);
   4377 			node_gid->gl_reprobe_flag = 1;
   4378 			mutex_exit(&node_gid->gl_mutex);
   4379 
   4380 			ibdm_probe_gid(node_gid);
   4381 
   4382 			mutex_enter(&ibdm.ibdm_hl_mutex);
   4383 		}
   4384 	}
   4385 	mutex_exit(&ibdm.ibdm_hl_mutex);
   4386 	IBTF_DPRINTF_L4("ibdm", "\tprobe_ioc : End\n");
   4387 }
   4388 
   4389 
   4390 /*
   4391  * ibdm_probe_gid()
   4392  *	Selectively probes the GID
   4393  */
   4394 static void
   4395 ibdm_probe_gid(ibdm_dp_gidinfo_t *gid_info)
   4396 {
   4397 	IBTF_DPRINTF_L4("ibdm", "\tprobe_gid:");
   4398 
   4399 	/*
   4400 	 * A Cisco FC GW needs the special handling to get IOUnitInfo.
   4401 	 */
   4402 	mutex_enter(&gid_info->gl_mutex);
   4403 	if (ibdm_is_cisco_switch(gid_info)) {
   4404 		gid_info->gl_pending_cmds++;
   4405 		gid_info->gl_state = IBDM_SET_CLASSPORTINFO;
   4406 		mutex_exit(&gid_info->gl_mutex);
   4407 
   4408 		if (ibdm_set_classportinfo(gid_info) != IBDM_SUCCESS) {
   4409 
   4410 			mutex_enter(&gid_info->gl_mutex);
   4411 			gid_info->gl_state = IBDM_GID_PROBING_FAILED;
   4412 			--gid_info->gl_pending_cmds;
   4413 			mutex_exit(&gid_info->gl_mutex);
   4414 
   4415 			/* free the hca_list on this gid_info */
   4416 			ibdm_delete_glhca_list(gid_info);
   4417 			gid_info = gid_info->gl_next;
   4418 			return;
   4419 		}
   4420 
   4421 		mutex_enter(&gid_info->gl_mutex);
   4422 		ibdm_wait_cisco_probe_completion(gid_info);
   4423 
   4424 		IBTF_DPRINTF_L4("ibdm",
   4425 		    "\tprobe_gid: CISCO Wakeup signal received");
   4426 	}
   4427 
   4428 	/* move on to the 'GET_CLASSPORTINFO' stage */
   4429 	gid_info->gl_pending_cmds++;
   4430 	gid_info->gl_state = IBDM_GET_CLASSPORTINFO;
   4431 	mutex_exit(&gid_info->gl_mutex);
   4432 
   4433 	if (ibdm_send_classportinfo(gid_info) != IBDM_SUCCESS) {
   4434 
   4435 		mutex_enter(&gid_info->gl_mutex);
   4436 		gid_info->gl_state = IBDM_GID_PROBING_FAILED;
   4437 		--gid_info->gl_pending_cmds;
   4438 		mutex_exit(&gid_info->gl_mutex);
   4439 
   4440 		/* free the hca_list on this gid_info */
   4441 		ibdm_delete_glhca_list(gid_info);
   4442 		gid_info = gid_info->gl_next;
   4443 		return;
   4444 	}
   4445 
   4446 	mutex_enter(&ibdm.ibdm_mutex);
   4447 	ibdm.ibdm_ngid_probes_in_progress++;
   4448 	gid_info = gid_info->gl_next;
   4449 	ibdm_wait_probe_completion();
   4450 	mutex_exit(&ibdm.ibdm_mutex);
   4451 
   4452 	IBTF_DPRINTF_L4("ibdm", "\tprobe_gid: Wakeup signal received");
   4453 }
   4454 
   4455 
   4456 /*
   4457  * ibdm_create_gid_info()
   4458  *	Allocates a gid_info structure and initializes
   4459  *	Returns pointer to the structure on success
   4460  *	and NULL on failure
   4461  */
   4462 static ibdm_dp_gidinfo_t *
   4463 ibdm_create_gid_info(ibdm_port_attr_t *port, ib_gid_t sgid, ib_gid_t dgid)
   4464 {
   4465 	uint8_t			ii, npaths;
   4466 	sa_path_record_t	*path;
   4467 	size_t			len;
   4468 	ibdm_pkey_tbl_t		*pkey_tbl;
   4469 	ibdm_dp_gidinfo_t	*gid_info = NULL;
   4470 	int			ret;
   4471 
   4472 	IBTF_DPRINTF_L4("ibdm", "\tcreate_gid_info: Begin");
   4473 	npaths = 1;
   4474 
   4475 	/* query for reversible paths */
   4476 	if (port->pa_sa_hdl)
   4477 		ret = ibmf_saa_gid_to_pathrecords(port->pa_sa_hdl,
   4478 		    sgid, dgid, IBMF_SAA_PKEY_WC, 0, B_TRUE, &npaths, 0,
   4479 		    &len, &path);
   4480 	else
   4481 		return (NULL);
   4482 
   4483 	if (ret == IBMF_SUCCESS && path) {
   4484 		ibdm_dump_path_info(path);
   4485 
   4486 		gid_info = kmem_zalloc(
   4487 		    sizeof (ibdm_dp_gidinfo_t), KM_SLEEP);
   4488 		mutex_init(&gid_info->gl_mutex, NULL, MUTEX_DEFAULT, NULL);
   4489 		cv_init(&gid_info->gl_probe_cv, NULL, CV_DRIVER, NULL);
   4490 		gid_info->gl_dgid_hi		= path->DGID.gid_prefix;
   4491 		gid_info->gl_dgid_lo		= path->DGID.gid_guid;
   4492 		gid_info->gl_sgid_hi		= path->SGID.gid_prefix;
   4493 		gid_info->gl_sgid_lo		= path->SGID.gid_guid;
   4494 		gid_info->gl_p_key		= path->P_Key;
   4495 		gid_info->gl_sa_hdl		= port->pa_sa_hdl;
   4496 		gid_info->gl_ibmf_hdl		= port->pa_ibmf_hdl;
   4497 		gid_info->gl_slid		= path->SLID;
   4498 		gid_info->gl_dlid		= path->DLID;
   4499 		gid_info->gl_transactionID	= (++ibdm.ibdm_transactionID)
   4500 		    << IBDM_GID_TRANSACTIONID_SHIFT;
   4501 		gid_info->gl_min_transactionID  = gid_info->gl_transactionID;
   4502 		gid_info->gl_max_transactionID  = (ibdm.ibdm_transactionID +1)
   4503 		    << IBDM_GID_TRANSACTIONID_SHIFT;
   4504 		gid_info->gl_SL			= path->SL;
   4505 
   4506 		gid_info->gl_qp_hdl = IBMF_QP_HANDLE_DEFAULT;
   4507 		for (ii = 0; ii < port->pa_npkeys; ii++) {
   4508 			if (port->pa_pkey_tbl == NULL)
   4509 				break;
   4510 
   4511 			pkey_tbl = &port->pa_pkey_tbl[ii];
   4512 			if ((gid_info->gl_p_key == pkey_tbl->pt_pkey) &&
   4513 			    (pkey_tbl->pt_qp_hdl != NULL)) {
   4514 				gid_info->gl_qp_hdl = pkey_tbl->pt_qp_hdl;
   4515 				break;
   4516 			}
   4517 		}
   4518 		kmem_free(path, len);
   4519 
   4520 		/*
   4521 		 * QP handle for GID not initialized. No matching Pkey
   4522 		 * was found!! ibdm should *not* hit this case. Flag an
   4523 		 * error and drop the GID if ibdm does encounter this.
   4524 		 */
   4525 		if (gid_info->gl_qp_hdl == NULL) {
   4526 			IBTF_DPRINTF_L2(ibdm_string,
   4527 			    "\tcreate_gid_info: No matching Pkey");
   4528 			ibdm_delete_gidinfo(gid_info);
   4529 			return (NULL);
   4530 		}
   4531 
   4532 		ibdm.ibdm_ngids++;
   4533 		if (ibdm.ibdm_dp_gidlist_head == NULL) {
   4534 			ibdm.ibdm_dp_gidlist_head = gid_info;
   4535 			ibdm.ibdm_dp_gidlist_tail = gid_info;
   4536 		} else {
   4537 			ibdm.ibdm_dp_gidlist_tail->gl_next = gid_info;
   4538 			gid_info->gl_prev = ibdm.ibdm_dp_gidlist_tail;
   4539 			ibdm.ibdm_dp_gidlist_tail = gid_info;
   4540 		}
   4541 	}
   4542 
   4543 	return (gid_info);
   4544 }
   4545 
   4546 
   4547 /*
   4548  * ibdm_get_node_records
   4549  *	Sends a SA query to get the NODE record
   4550  *	Returns pointer to the sa_node_record_t on success
   4551  *	and NULL on failure
   4552  */
   4553 static sa_node_record_t *
   4554 ibdm_get_node_records(ibmf_saa_handle_t sa_hdl, size_t *length, ib_guid_t guid)
   4555 {
   4556 	sa_node_record_t	req, *resp = NULL;
   4557 	ibmf_saa_access_args_t	args;
   4558 	int			ret;
   4559 
   4560 	IBTF_DPRINTF_L4("ibdm", "\tget_node_records: Begin");
   4561 
   4562 	bzero(&req, sizeof (sa_node_record_t));
   4563 	req.NodeInfo.NodeGUID = guid;
   4564 
   4565 	args.sq_attr_id		= SA_NODERECORD_ATTRID;
   4566 	args.sq_access_type 	= IBMF_SAA_RETRIEVE;
   4567 	args.sq_component_mask 	= SA_NODEINFO_COMPMASK_NODEGUID;
   4568 	args.sq_template	= &req;
   4569 	args.sq_callback	= NULL;
   4570 	args.sq_callback_arg 	= NULL;
   4571 
   4572 	ret = ibmf_sa_access(sa_hdl, &args, 0, length, (void **) &resp);
   4573 	if (ret != IBMF_SUCCESS) {
   4574 		IBTF_DPRINTF_L2("ibdm", "\tget_node_records:"
   4575 		    " SA Retrieve Failed: %d", ret);
   4576 		return (NULL);
   4577 	}
   4578 	if ((resp == NULL) || (*length == 0)) {
   4579 		IBTF_DPRINTF_L2("ibdm", "\tget_node_records: No records");
   4580 		return (NULL);
   4581 	}
   4582 
   4583 	IBTF_DPRINTF_L4("ibdm", "\tget_node_records: NodeGuid %llx "
   4584 	    "PortGUID %llx", resp->NodeInfo.NodeGUID, resp->NodeInfo.PortGUID);
   4585 
   4586 	return (resp);
   4587 }
   4588 
   4589 
   4590 /*
   4591  * ibdm_get_portinfo()
   4592  *	Sends a SA query to get the PortInfo record
   4593  *	Returns pointer to the sa_portinfo_record_t on success
   4594  *	and NULL on failure
   4595  */
   4596 static sa_portinfo_record_t *
   4597 ibdm_get_portinfo(ibmf_saa_handle_t sa_hdl, size_t *length, ib_lid_t lid)
   4598 {
   4599 	sa_portinfo_record_t	req, *resp = NULL;
   4600 	ibmf_saa_access_args_t	args;
   4601 	int			ret;
   4602 
   4603 	IBTF_DPRINTF_L4("ibdm", "\tget_portinfo: Begin");
   4604 
   4605 	bzero(&req, sizeof (sa_portinfo_record_t));
   4606 	req.EndportLID	= lid;
   4607 
   4608 	args.sq_attr_id		= SA_PORTINFORECORD_ATTRID;
   4609 	args.sq_access_type	= IBMF_SAA_RETRIEVE;
   4610 	args.sq_component_mask	= SA_PORTINFO_COMPMASK_PORTLID;
   4611 	args.sq_template	= &req;
   4612 	args.sq_callback	= NULL;
   4613 	args.sq_callback_arg	= NULL;
   4614 
   4615 	ret = ibmf_sa_access(sa_hdl, &args, 0, length, (void **) &resp);
   4616 	if (ret != IBMF_SUCCESS) {
   4617 		IBTF_DPRINTF_L2("ibdm", "\tget_portinfo:"
   4618 		    " SA Retrieve Failed: 0x%X", ret);
   4619 		return (NULL);
   4620 	}
   4621 	if ((*length == 0) || (resp == NULL))
   4622 		return (NULL);
   4623 
   4624 	IBTF_DPRINTF_L4("ibdm", "\tget_portinfo: GidPrefix %llx Cap 0x%x",
   4625 	    resp->PortInfo.GidPrefix, resp->PortInfo.CapabilityMask);
   4626 	return (resp);
   4627 }
   4628 
   4629 
   4630 /*
   4631  * ibdm_ibnex_register_callback
   4632  *	IB nexus callback routine for HCA attach and detach notification
   4633  */
   4634 void
   4635 ibdm_ibnex_register_callback(ibdm_callback_t ibnex_dm_callback)
   4636 {
   4637 	IBTF_DPRINTF_L4("ibdm", "\tibnex_register_callbacks");
   4638 	mutex_enter(&ibdm.ibdm_ibnex_mutex);
   4639 	ibdm.ibdm_ibnex_callback = ibnex_dm_callback;
   4640 	mutex_exit(&ibdm.ibdm_ibnex_mutex);
   4641 }
   4642 
   4643 
   4644 /*
   4645  * ibdm_ibnex_unregister_callbacks
   4646  */
   4647 void
   4648 ibdm_ibnex_unregister_callback()
   4649 {
   4650 	IBTF_DPRINTF_L4("ibdm", "\tibnex_unregister_callbacks");
   4651 	mutex_enter(&ibdm.ibdm_ibnex_mutex);
   4652 	ibdm.ibdm_ibnex_callback = NULL;
   4653 	mutex_exit(&ibdm.ibdm_ibnex_mutex);
   4654 }
   4655 
   4656 /*
   4657  * ibdm_get_waittime()
   4658  *	Calculates the wait time based on the last HCA attach time
   4659  */
   4660 static time_t
   4661 ibdm_get_waittime(ib_guid_t hca_guid, int dft_wait)
   4662 {
   4663 	int		ii;
   4664 	time_t		temp, wait_time = 0;
   4665 	ibdm_hca_list_t	*hca;
   4666 
   4667 	IBTF_DPRINTF_L4("ibdm", "\tget_waittime hcaguid:%llx"
   4668 	    "\tport settling time %d", hca_guid, dft_wait);
   4669 
   4670 	ASSERT(mutex_owned(&ibdm.ibdm_hl_mutex));
   4671 
   4672 	hca = ibdm.ibdm_hca_list_head;
   4673 
   4674 	if (hca_guid) {
   4675 		for (ii = 0; ii < ibdm.ibdm_hca_count; ii++) {
   4676 			if ((hca_guid == hca->hl_hca_guid) &&
   4677 			    (hca->hl_nports != hca->hl_nports_active)) {
   4678 				wait_time =
   4679 				    ddi_get_time() - hca->hl_attach_time;
   4680 				wait_time = ((wait_time >= dft_wait) ?
   4681 				    0 : (dft_wait - wait_time));
   4682 				break;
   4683 			}
   4684 			hca = hca->hl_next;
   4685 		}
   4686 		IBTF_DPRINTF_L4("ibdm", "\tget_waittime %llx", wait_time);
   4687 		return (wait_time);
   4688 	}
   4689 
   4690 	for (ii = 0; ii < ibdm.ibdm_hca_count; ii++) {
   4691 		if (hca->hl_nports != hca->hl_nports_active) {
   4692 			temp = ddi_get_time() - hca->hl_attach_time;
   4693 			temp = ((temp >= dft_wait) ? 0 : (dft_wait - temp));
   4694 			wait_time = (temp > wait_time) ? temp : wait_time;
   4695 		}
   4696 	}
   4697 	IBTF_DPRINTF_L4("ibdm", "\tget_waittime %llx", wait_time);
   4698 	return (wait_time);
   4699 }
   4700 
   4701 void
   4702 ibdm_ibnex_port_settle_wait(ib_guid_t hca_guid, int dft_wait)
   4703 {
   4704 	time_t wait_time;
   4705 	clock_t delta;
   4706 
   4707 	mutex_enter(&ibdm.ibdm_hl_mutex);
   4708 
   4709 	while ((wait_time = ibdm_get_waittime(hca_guid, dft_wait)) > 0) {
   4710 		delta = drv_usectohz(wait_time * 1000000);
   4711 		(void) cv_reltimedwait(&ibdm.ibdm_port_settle_cv,
   4712 		    &ibdm.ibdm_hl_mutex, delta, TR_CLOCK_TICK);
   4713 	}
   4714 
   4715 	mutex_exit(&ibdm.ibdm_hl_mutex);
   4716 }
   4717 
   4718 
   4719 /*
   4720  * ibdm_ibnex_probe_hcaport
   4721  *	Probes the presence of HCA port (with HCA dip and port number)
   4722  *	Returns port attributes structure on SUCCESS
   4723  */
   4724 ibdm_port_attr_t *
   4725 ibdm_ibnex_probe_hcaport(ib_guid_t hca_guid, uint8_t port_num)
   4726 {
   4727 	int			ii, jj;
   4728 	ibdm_hca_list_t		*hca_list;
   4729 	ibdm_port_attr_t	*port_attr;
   4730 
   4731 	IBTF_DPRINTF_L4("ibdm", "\tibnex_probe_hcaport:");
   4732 
   4733 	mutex_enter(&ibdm.ibdm_hl_mutex);
   4734 	hca_list = ibdm.ibdm_hca_list_head;
   4735 	for (ii = 0; ii < ibdm.ibdm_hca_count; ii++) {
   4736 		if (hca_list->hl_hca_guid == hca_guid) {
   4737 			for (jj = 0; jj < hca_list->hl_nports; jj++) {
   4738 				if (hca_list->hl_port_attr[jj].pa_port_num ==
   4739 				    port_num) {
   4740 					break;
   4741 				}
   4742 			}
   4743 			if (jj != hca_list->hl_nports)
   4744 				break;
   4745 		}
   4746 		hca_list = hca_list->hl_next;
   4747 	}
   4748 	if (ii == ibdm.ibdm_hca_count) {
   4749 		IBTF_DPRINTF_L2("ibdm", "\tibnex_probe_hcaport: not found");
   4750 		mutex_exit(&ibdm.ibdm_hl_mutex);
   4751 		return (NULL);
   4752 	}
   4753 	port_attr = (ibdm_port_attr_t *)kmem_zalloc(
   4754 	    sizeof (ibdm_port_attr_t), KM_SLEEP);
   4755 	bcopy((char *)&hca_list->hl_port_attr[jj],
   4756 	    port_attr, sizeof (ibdm_port_attr_t));
   4757 	ibdm_update_port_attr(port_attr);
   4758 
   4759 	mutex_exit(&ibdm.ibdm_hl_mutex);
   4760 	return (port_attr);
   4761 }
   4762 
   4763 
   4764 /*
   4765  * ibdm_ibnex_get_port_attrs
   4766  *	Scan all HCAs for a matching port_guid.
   4767  *	Returns "port attributes" structure on success.
   4768  */
   4769 ibdm_port_attr_t *
   4770 ibdm_ibnex_get_port_attrs(ib_guid_t port_guid)
   4771 {
   4772 	int			ii, jj;
   4773 	ibdm_hca_list_t		*hca_list;
   4774 	ibdm_port_attr_t	*port_attr;
   4775 
   4776 	IBTF_DPRINTF_L4("ibdm", "\tibnex_get_port_attrs:");
   4777 
   4778 	mutex_enter(&ibdm.ibdm_hl_mutex);
   4779 	hca_list = ibdm.ibdm_hca_list_head;
   4780 
   4781 	for (ii = 0; ii < ibdm.ibdm_hca_count; ii++) {
   4782 		for (jj = 0; jj < hca_list->hl_nports; jj++) {
   4783 			if (hca_list->hl_port_attr[jj].pa_port_guid ==
   4784 			    port_guid) {
   4785 				break;
   4786 			}
   4787 		}
   4788 		if (jj != hca_list->hl_nports)
   4789 			break;
   4790 		hca_list = hca_list->hl_next;
   4791 	}
   4792 
   4793 	if (ii == ibdm.ibdm_hca_count) {
   4794 		IBTF_DPRINTF_L2("ibdm", "\tibnex_get_port_attrs: not found");
   4795 		mutex_exit(&ibdm.ibdm_hl_mutex);
   4796 		return (NULL);
   4797 	}
   4798 
   4799 	port_attr = (ibdm_port_attr_t *)kmem_alloc(sizeof (ibdm_port_attr_t),
   4800 	    KM_SLEEP);
   4801 	bcopy((char *)&hca_list->hl_port_attr[jj], port_attr,
   4802 	    sizeof (ibdm_port_attr_t));
   4803 	ibdm_update_port_attr(port_attr);
   4804 
   4805 	mutex_exit(&ibdm.ibdm_hl_mutex);
   4806 	return (port_attr);
   4807 }
   4808 
   4809 
   4810 /*
   4811  * ibdm_ibnex_free_port_attr()
   4812  */
   4813 void
   4814 ibdm_ibnex_free_port_attr(ibdm_port_attr_t *port_attr)
   4815 {
   4816 	IBTF_DPRINTF_L4("ibdm", "\tibnex_free_port_attr:");
   4817 	if (port_attr) {
   4818 		if (port_attr->pa_pkey_tbl != NULL) {
   4819 			kmem_free(port_attr->pa_pkey_tbl,
   4820 			    (port_attr->pa_npkeys * sizeof (ibdm_pkey_tbl_t)));
   4821 		}
   4822 		kmem_free(port_attr, sizeof (ibdm_port_attr_t));
   4823 	}
   4824 }
   4825 
   4826 
   4827 /*
   4828  * ibdm_ibnex_get_hca_list()
   4829  *	Returns portinfo for all the port for all the HCA's
   4830  */
   4831 void
   4832 ibdm_ibnex_get_hca_list(ibdm_hca_list_t **hca, int *count)
   4833 {
   4834 	ibdm_hca_list_t		*head = NULL, *temp, *temp1;
   4835 	int			ii;
   4836 
   4837 	IBTF_DPRINTF_L4("ibdm", "\tibnex_get_hca_list:");
   4838 
   4839 	mutex_enter(&ibdm.ibdm_hl_mutex);
   4840 	temp = ibdm.ibdm_hca_list_head;
   4841 	for (ii = 0; ii < ibdm.ibdm_hca_count; ii++) {
   4842 		temp1 = ibdm_dup_hca_attr(temp);
   4843 		temp1->hl_next = head;
   4844 		head = temp1;
   4845 		temp = temp->hl_next;
   4846 	}
   4847 	*count = ibdm.ibdm_hca_count;
   4848 	*hca = head;
   4849 	mutex_exit(&ibdm.ibdm_hl_mutex);
   4850 }
   4851 
   4852 
   4853 /*
   4854  * ibdm_ibnex_get_hca_info_by_guid()
   4855  */
   4856 ibdm_hca_list_t	*
   4857 ibdm_ibnex_get_hca_info_by_guid(ib_guid_t hca_guid)
   4858 {
   4859 	ibdm_hca_list_t		*head = NULL, *hca = NULL;
   4860 
   4861 	IBTF_DPRINTF_L4("ibdm", "\tibnex_get_hca_info_by_dip");
   4862 
   4863 	mutex_enter(&ibdm.ibdm_hl_mutex);
   4864 	head = ibdm.ibdm_hca_list_head;
   4865 	while (head) {
   4866 		if (head->hl_hca_guid == hca_guid) {
   4867 			hca = ibdm_dup_hca_attr(head);
   4868 			hca->hl_next = NULL;
   4869 			break;
   4870 		}
   4871 		head = head->hl_next;
   4872 	}
   4873 	mutex_exit(&ibdm.ibdm_hl_mutex);
   4874 	IBTF_DPRINTF_L4("ibdm", "\tibnex_get_hca_info_by_dip %p", hca);
   4875 	return (hca);
   4876 }
   4877 
   4878 
   4879 /*
   4880  * ibdm_dup_hca_attr()
   4881  *	Allocate a new HCA attribute strucuture and initialize
   4882  *	hca attribute structure with the incoming HCA attributes
   4883  *	returned the allocated hca attributes.
   4884  */
   4885 static ibdm_hca_list_t *
   4886 ibdm_dup_hca_attr(ibdm_hca_list_t *in_hca)
   4887 {
   4888 	int			len;
   4889 	ibdm_hca_list_t		*out_hca;
   4890 
   4891 	len = sizeof (ibdm_hca_list_t) +
   4892 	    (in_hca->hl_nports * sizeof (ibdm_port_attr_t));
   4893 	IBTF_DPRINTF_L4("ibdm", "\tdup_hca_attr len %d", len);
   4894 	out_hca = (ibdm_hca_list_t *)kmem_alloc(len, KM_SLEEP);
   4895 	bcopy((char *)in_hca,
   4896 	    (char *)out_hca, sizeof (ibdm_hca_list_t));
   4897 	if (in_hca->hl_nports) {
   4898 		out_hca->hl_port_attr = (ibdm_port_attr_t *)
   4899 		    ((char *)out_hca + sizeof (ibdm_hca_list_t));
   4900 		bcopy((char *)in_hca->hl_port_attr,
   4901 		    (char *)out_hca->hl_port_attr,
   4902 		    (in_hca->hl_nports * sizeof (ibdm_port_attr_t)));
   4903 		for (len = 0; len < out_hca->hl_nports; len++)
   4904 			ibdm_update_port_attr(&out_hca->hl_port_attr[len]);
   4905 	}
   4906 	return (out_hca);
   4907 }
   4908 
   4909 
   4910 /*
   4911  * ibdm_ibnex_free_hca_list()
   4912  *	Free one/more HCA lists
   4913  */
   4914 void
   4915 ibdm_ibnex_free_hca_list(ibdm_hca_list_t *hca_list)
   4916 {
   4917 	int			ii;
   4918 	size_t			len;
   4919 	ibdm_hca_list_t 	*temp;
   4920 	ibdm_port_attr_t	*port;
   4921 
   4922 	IBTF_DPRINTF_L4("ibdm", "\tibnex_free_hca_list:");
   4923 	ASSERT(hca_list);
   4924 	while (hca_list) {
   4925 		temp = hca_list;
   4926 		hca_list = hca_list->hl_next;
   4927 		for (ii = 0; ii < temp->hl_nports; ii++) {
   4928 			port = &temp->hl_port_attr[ii];
   4929 			len = (port->pa_npkeys * sizeof (ibdm_pkey_tbl_t));
   4930 			if (len != 0)
   4931 				kmem_free(port->pa_pkey_tbl, len);
   4932 		}
   4933 		len = sizeof (ibdm_hca_list_t) + (temp->hl_nports *
   4934 		    sizeof (ibdm_port_attr_t));
   4935 		kmem_free(temp, len);
   4936 	}
   4937 }
   4938 
   4939 
   4940 /*
   4941  * ibdm_ibnex_probe_iocguid()
   4942  *	Probes the IOC on the fabric and returns the IOC information
   4943  *	if present. Otherwise, NULL is returned
   4944  */
   4945 /* ARGSUSED */
   4946 ibdm_ioc_info_t *
   4947 ibdm_ibnex_probe_ioc(ib_guid_t iou, ib_guid_t ioc_guid, int reprobe_flag)
   4948 {
   4949 	int			k;
   4950 	ibdm_ioc_info_t		*ioc_info;
   4951 	ibdm_dp_gidinfo_t	*gid_info; /* used as index and arg */
   4952 	timeout_id_t		*timeout_id;
   4953 
   4954 	IBTF_DPRINTF_L4("ibdm", "\tibnex_probe_ioc: (%llX, %llX, %d) Begin",
   4955 	    iou, ioc_guid, reprobe_flag);
   4956 	/* Check whether we know this already */
   4957 	ioc_info = ibdm_get_ioc_info_with_gid(ioc_guid, &gid_info);
   4958 	if (ioc_info == NULL) {
   4959 		mutex_enter(&ibdm.ibdm_mutex);
   4960 		while (ibdm.ibdm_busy & IBDM_BUSY)
   4961 			cv_wait(&ibdm.ibdm_busy_cv, &ibdm.ibdm_mutex);
   4962 		ibdm.ibdm_busy |= IBDM_BUSY;
   4963 		mutex_exit(&ibdm.ibdm_mutex);
   4964 		ibdm_probe_ioc(iou, ioc_guid, 0);
   4965 		mutex_enter(&ibdm.ibdm_mutex);
   4966 		ibdm.ibdm_busy &= ~IBDM_BUSY;
   4967 		cv_broadcast(&ibdm.ibdm_busy_cv);
   4968 		mutex_exit(&ibdm.ibdm_mutex);
   4969 		ioc_info = ibdm_get_ioc_info_with_gid(ioc_guid, &gid_info);
   4970 	} else if (reprobe_flag) {	/* Handle Reprobe for the IOC */
   4971 		ASSERT(gid_info != NULL);
   4972 		/* Free the ioc_list before reprobe; and cancel any timers */
   4973 		mutex_enter(&ibdm.ibdm_mutex);
   4974 		mutex_enter(&gid_info->gl_mutex);
   4975 		if (ioc_info->ioc_timeout_id) {
   4976 			timeout_id = ioc_info->ioc_timeout_id;
   4977 			ioc_info->ioc_timeout_id = 0;
   4978 			mutex_exit(&gid_info->gl_mutex);
   4979 			IBTF_DPRINTF_L5("ibdm", "\tprobe_ioc: "
   4980 			    "ioc_timeout_id = 0x%x", timeout_id);
   4981 			if (untimeout(timeout_id) == -1) {
   4982 				IBTF_DPRINTF_L2("ibdm", "\tprobe_ioc: "
   4983 				    "untimeout ioc_timeout_id failed");
   4984 			}
   4985 			mutex_enter(&gid_info->gl_mutex);
   4986 		}
   4987 		if (ioc_info->ioc_dc_timeout_id) {
   4988 			timeout_id = ioc_info->ioc_dc_timeout_id;
   4989 			ioc_info->ioc_dc_timeout_id = 0;
   4990 			mutex_exit(&gid_info->gl_mutex);
   4991 			IBTF_DPRINTF_L5("ibdm", "\tprobe_ioc: "
   4992 			    "ioc_dc_timeout_id = 0x%x", timeout_id);
   4993 			if (untimeout(timeout_id) == -1) {
   4994 				IBTF_DPRINTF_L2("ibdm", "\tprobe_ioc: "
   4995 				    "untimeout ioc_dc_timeout_id failed");
   4996 			}
   4997 			mutex_enter(&gid_info->gl_mutex);
   4998 		}
   4999 		for (k = 0; k < ioc_info->ioc_profile.ioc_service_entries; k++)
   5000 			if (ioc_info->ioc_serv[k].se_timeout_id) {
   5001 				timeout_id = ioc_info->ioc_serv[k].
   5002 				    se_timeout_id;
   5003 				ioc_info->ioc_serv[k].se_timeout_id = 0;
   5004 				mutex_exit(&gid_info->gl_mutex);
   5005 				IBTF_DPRINTF_L5("ibdm", "\tprobe_ioc: "
   5006 				    "ioc_info->ioc_serv[k].se_timeout_id = %x",
   5007 				    k, timeout_id);
   5008 				if (untimeout(timeout_id) == -1) {
   5009 					IBTF_DPRINTF_L2("ibdm", "\tprobe_ioc: "
   5010 					    "untimeout se_timeout_id %d "
   5011 					    "failed", k);
   5012 				}
   5013 				mutex_enter(&gid_info->gl_mutex);
   5014 			}
   5015 		mutex_exit(&gid_info->gl_mutex);
   5016 		mutex_exit(&ibdm.ibdm_mutex);
   5017 		ibdm_ibnex_free_ioc_list(ioc_info);
   5018 
   5019 		mutex_enter(&ibdm.ibdm_mutex);
   5020 		while (ibdm.ibdm_busy & IBDM_BUSY)
   5021 			cv_wait(&ibdm.ibdm_busy_cv, &ibdm.ibdm_mutex);
   5022 		ibdm.ibdm_busy |= IBDM_BUSY;
   5023 		mutex_exit(&ibdm.ibdm_mutex);
   5024 
   5025 		ibdm_probe_ioc(iou, ioc_guid, 1);
   5026 
   5027 		/*
   5028 		 * Skip if gl_reprobe_flag is set, this will be
   5029 		 * a re-inserted / new GID, for which notifications
   5030 		 * have already been send.
   5031 		 */
   5032 		for (gid_info = ibdm.ibdm_dp_gidlist_head; gid_info;
   5033 		    gid_info = gid_info->gl_next) {
   5034 			uint8_t			ii, niocs;
   5035 			ibdm_ioc_info_t		*ioc;
   5036 
   5037 			if (gid_info->gl_iou == NULL)
   5038 				continue;
   5039 
   5040 			if (gid_info->gl_reprobe_flag) {
   5041 				gid_info->gl_reprobe_flag = 0;
   5042 				continue;
   5043 			}
   5044 
   5045 			niocs = gid_info->gl_iou->iou_info.iou_num_ctrl_slots;
   5046 			for (ii = 0; ii < niocs; ii++) {
   5047 				ioc = IBDM_GIDINFO2IOCINFO(gid_info, ii);
   5048 				if (ioc->ioc_profile.ioc_guid == ioc_guid) {
   5049 					mutex_enter(&ibdm.ibdm_mutex);
   5050 					ibdm_reprobe_update_port_srv(ioc,
   5051 					    gid_info);
   5052 					mutex_exit(&ibdm.ibdm_mutex);
   5053 				}
   5054 			}
   5055 		}
   5056 		mutex_enter(&ibdm.ibdm_mutex);
   5057 		ibdm.ibdm_busy &= ~IBDM_BUSY;
   5058 		cv_broadcast(&ibdm.ibdm_busy_cv);
   5059 		mutex_exit(&ibdm.ibdm_mutex);
   5060 
   5061 		ioc_info = ibdm_get_ioc_info_with_gid(ioc_guid, &gid_info);
   5062 	}
   5063 	return (ioc_info);
   5064 }
   5065 
   5066 
   5067 /*
   5068  * ibdm_get_ioc_info_with_gid()
   5069  *	Returns pointer to ibdm_ioc_info_t if it finds
   5070  *	matching record for the ioc_guid. Otherwise NULL is returned.
   5071  *	The pointer to gid_info is set to the second argument in case that
   5072  *	the non-NULL value returns (and the second argument is not NULL).
   5073  *
   5074  * Note. use the same strings as "ibnex_get_ioc_info" in
   5075  *       IBTF_DPRINTF() to keep compatibility.
   5076  */
   5077 static ibdm_ioc_info_t *
   5078 ibdm_get_ioc_info_with_gid(ib_guid_t ioc_guid,
   5079     ibdm_dp_gidinfo_t **gid_info)
   5080 {
   5081 	int			ii;
   5082 	ibdm_ioc_info_t		*ioc = NULL, *tmp = NULL;
   5083 	ibdm_dp_gidinfo_t	*gid_list;
   5084 	ib_dm_io_unitinfo_t	*iou;
   5085 
   5086 	IBTF_DPRINTF_L4("ibdm", "\tibnex_get_ioc_info: GUID %llx", ioc_guid);
   5087 
   5088 	mutex_enter(&ibdm.ibdm_mutex);
   5089 	while (ibdm.ibdm_busy & IBDM_BUSY)
   5090 		cv_wait(&ibdm.ibdm_busy_cv, &ibdm.ibdm_mutex);
   5091 	ibdm.ibdm_busy |= IBDM_BUSY;
   5092 
   5093 	if (gid_info)
   5094 		*gid_info = NULL; /* clear the value of gid_info */
   5095 
   5096 	gid_list = ibdm.ibdm_dp_gidlist_head;
   5097 	while (gid_list) {
   5098 		mutex_enter(&gid_list->gl_mutex);
   5099 		if (gid_list->gl_state != IBDM_GID_PROBING_COMPLETE) {
   5100 			mutex_exit(&gid_list->gl_mutex);
   5101 			gid_list = gid_list->gl_next;
   5102 			continue;
   5103 		}
   5104 		if (gid_list->gl_iou == NULL) {
   5105 			IBTF_DPRINTF_L2("ibdm",
   5106 			    "\tget_ioc_info: No IOU info");
   5107 			mutex_exit(&gid_list->gl_mutex);
   5108 			gid_list = gid_list->gl_next;
   5109 			continue;
   5110 		}
   5111 		iou = &gid_list->gl_iou->iou_info;
   5112 		for (ii = 0; ii < iou->iou_num_ctrl_slots; ii++) {
   5113 			tmp = IBDM_GIDINFO2IOCINFO(gid_list, ii);
   5114 			if ((tmp->ioc_profile.ioc_guid == ioc_guid) &&
   5115 			    (tmp->ioc_state == IBDM_IOC_STATE_PROBE_SUCCESS)) {
   5116 				ioc = ibdm_dup_ioc_info(tmp, gid_list);
   5117 				if (gid_info)
   5118 					*gid_info = gid_list; /* set this ptr */
   5119 				mutex_exit(&gid_list->gl_mutex);
   5120 				ibdm.ibdm_busy &= ~IBDM_BUSY;
   5121 				cv_broadcast(&ibdm.ibdm_busy_cv);
   5122 				mutex_exit(&ibdm.ibdm_mutex);
   5123 				IBTF_DPRINTF_L4("ibdm", "\tget_ioc_info: End");
   5124 				return (ioc);
   5125 			}
   5126 		}
   5127 		if (ii == iou->iou_num_ctrl_slots)
   5128 			ioc = NULL;
   5129 
   5130 		mutex_exit(&gid_list->gl_mutex);
   5131 		gid_list = gid_list->gl_next;
   5132 	}
   5133 
   5134 	ibdm.ibdm_busy &= ~IBDM_BUSY;
   5135 	cv_broadcast(&ibdm.ibdm_busy_cv);
   5136 	mutex_exit(&ibdm.ibdm_mutex);
   5137 	IBTF_DPRINTF_L4("ibdm", "\tget_ioc_info: failure End");
   5138 	return (ioc);
   5139 }
   5140 
   5141 /*
   5142  * ibdm_ibnex_get_ioc_info()
   5143  *	Returns pointer to ibdm_ioc_info_t if it finds
   5144  *	matching record for the ioc_guid, otherwise NULL
   5145  *	is returned
   5146  *
   5147  * Note. this is a wrapper function to ibdm_get_ioc_info_with_gid() now.
   5148  */
   5149 ibdm_ioc_info_t *
   5150 ibdm_ibnex_get_ioc_info(ib_guid_t ioc_guid)
   5151 {
   5152 	/* will not use the gid_info pointer, so the second arg is NULL */
   5153 	return (ibdm_get_ioc_info_with_gid(ioc_guid, NULL));
   5154 }
   5155 
   5156 /*
   5157  * ibdm_ibnex_get_ioc_count()
   5158  *	Returns number of ibdm_ioc_info_t it finds
   5159  */
   5160 int
   5161 ibdm_ibnex_get_ioc_count(void)
   5162 {
   5163 	int			count = 0, k;
   5164 	ibdm_ioc_info_t		*ioc;
   5165 	ibdm_dp_gidinfo_t	*gid_list;
   5166 
   5167 	mutex_enter(&ibdm.ibdm_mutex);
   5168 	ibdm_sweep_fabric(0);
   5169 
   5170 	while (ibdm.ibdm_busy & IBDM_BUSY)
   5171 		cv_wait(&ibdm.ibdm_busy_cv, &ibdm.ibdm_mutex);
   5172 	ibdm.ibdm_busy |= IBDM_BUSY;
   5173 
   5174 	for (gid_list = ibdm.ibdm_dp_gidlist_head; gid_list;
   5175 	    gid_list = gid_list->gl_next) {
   5176 		mutex_enter(&gid_list->gl_mutex);
   5177 		if ((gid_list->gl_state != IBDM_GID_PROBING_COMPLETE) ||
   5178 		    (gid_list->gl_iou == NULL)) {
   5179 			mutex_exit(&gid_list->gl_mutex);
   5180 			continue;
   5181 		}
   5182 		for (k = 0; k < gid_list->gl_iou->iou_info.iou_num_ctrl_slots;
   5183 		    k++) {
   5184 			ioc = IBDM_GIDINFO2IOCINFO(gid_list, k);
   5185 			if (ioc->ioc_state == IBDM_IOC_STATE_PROBE_SUCCESS)
   5186 				++count;
   5187 		}
   5188 		mutex_exit(&gid_list->gl_mutex);
   5189 	}
   5190 	ibdm.ibdm_busy &= ~IBDM_BUSY;
   5191 	cv_broadcast(&ibdm.ibdm_busy_cv);
   5192 	mutex_exit(&ibdm.ibdm_mutex);
   5193 
   5194 	IBTF_DPRINTF_L4("ibdm", "\tget_ioc_count: count = %d", count);
   5195 	return (count);
   5196 }
   5197 
   5198 
   5199 /*
   5200  * ibdm_ibnex_get_ioc_list()
   5201  *	Returns information about all the IOCs present on the fabric.
   5202  *	Reprobes the IOCs and the GID list if list_flag is set to REPROBE_ALL.
   5203  *	Does not sweep fabric if DONOT_PROBE is set
   5204  */
   5205 ibdm_ioc_info_t *
   5206 ibdm_ibnex_get_ioc_list(ibdm_ibnex_get_ioclist_mtd_t list_flag)
   5207 {
   5208 	int			ii;
   5209 	ibdm_ioc_info_t		*ioc_list = NULL, *tmp, *ioc;
   5210 	ibdm_dp_gidinfo_t	*gid_list;
   5211 	ib_dm_io_unitinfo_t	*iou;
   5212 
   5213 	IBTF_DPRINTF_L4("ibdm", "\tget_ioc_list: Enter");
   5214 
   5215 	mutex_enter(&ibdm.ibdm_mutex);
   5216 	if (list_flag != IBDM_IBNEX_DONOT_PROBE)
   5217 		ibdm_sweep_fabric(list_flag == IBDM_IBNEX_REPROBE_ALL);
   5218 
   5219 	while (ibdm.ibdm_busy & IBDM_BUSY)
   5220 		cv_wait(&ibdm.ibdm_busy_cv, &ibdm.ibdm_mutex);
   5221 	ibdm.ibdm_busy |= IBDM_BUSY;
   5222 
   5223 	gid_list = ibdm.ibdm_dp_gidlist_head;
   5224 	while (gid_list) {
   5225 		mutex_enter(&gid_list->gl_mutex);
   5226 		if (gid_list->gl_state != IBDM_GID_PROBING_COMPLETE) {
   5227 			mutex_exit(&gid_list->gl_mutex);
   5228 			gid_list = gid_list->gl_next;
   5229 			continue;
   5230 		}
   5231 		if (gid_list->gl_iou == NULL) {
   5232 			IBTF_DPRINTF_L2("ibdm",
   5233 			    "\tget_ioc_list: No IOU info");
   5234 			mutex_exit(&gid_list->gl_mutex);
   5235 			gid_list = gid_list->gl_next;
   5236 			continue;
   5237 		}
   5238 		iou = &gid_list->gl_iou->iou_info;
   5239 		for (ii = 0; ii < iou->iou_num_ctrl_slots; ii++) {
   5240 			ioc = IBDM_GIDINFO2IOCINFO(gid_list, ii);
   5241 			if (ioc->ioc_state == IBDM_IOC_STATE_PROBE_SUCCESS) {
   5242 				tmp = ibdm_dup_ioc_info(ioc, gid_list);
   5243 				tmp->ioc_next = ioc_list;
   5244 				ioc_list = tmp;
   5245 			}
   5246 		}
   5247 		mutex_exit(&gid_list->gl_mutex);
   5248 		gid_list = gid_list->gl_next;
   5249 	}
   5250 	ibdm.ibdm_busy &= ~IBDM_BUSY;
   5251 	cv_broadcast(&ibdm.ibdm_busy_cv);
   5252 	mutex_exit(&ibdm.ibdm_mutex);
   5253 
   5254 	IBTF_DPRINTF_L4("ibdm", "\tget_ioc_list: End");
   5255 	return (ioc_list);
   5256 }
   5257 
   5258 /*
   5259  * ibdm_dup_ioc_info()
   5260  *	Duplicate the IOC information and return the IOC
   5261  *	information.
   5262  */
   5263 static ibdm_ioc_info_t *
   5264 ibdm_dup_ioc_info(ibdm_ioc_info_t *in_ioc, ibdm_dp_gidinfo_t *gid_list)
   5265 {
   5266 	ibdm_ioc_info_t	*out_ioc;
   5267 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*out_ioc));
   5268 	ASSERT(MUTEX_HELD(&gid_list->gl_mutex));
   5269 
   5270 	out_ioc = kmem_alloc(sizeof (ibdm_ioc_info_t), KM_SLEEP);
   5271 	bcopy(in_ioc, out_ioc, sizeof (ibdm_ioc_info_t));
   5272 	ibdm_update_ioc_port_gidlist(out_ioc, gid_list);
   5273 	out_ioc->ioc_iou_dc_valid = gid_list->gl_iou->iou_dc_valid;
   5274 	out_ioc->ioc_iou_diagcode = gid_list->gl_iou->iou_diagcode;
   5275 
   5276 	return (out_ioc);
   5277 }
   5278 
   5279 
   5280 /*
   5281  * ibdm_free_ioc_list()
   5282  *	Deallocate memory for IOC list structure
   5283  */
   5284 void
   5285 ibdm_ibnex_free_ioc_list(ibdm_ioc_info_t *ioc)
   5286 {
   5287 	ibdm_ioc_info_t *temp;
   5288 
   5289 	IBTF_DPRINTF_L4("ibdm", "\tibnex_free_ioc_list:");
   5290 	while (ioc) {
   5291 		temp = ioc;
   5292 		ioc = ioc->ioc_next;
   5293 		kmem_free(temp->ioc_gid_list,
   5294 		    (sizeof (ibdm_gid_t) * temp->ioc_nportgids));
   5295 		if (temp->ioc_hca_list)
   5296 			ibdm_ibnex_free_hca_list(temp->ioc_hca_list);
   5297 		kmem_free(temp, sizeof (ibdm_ioc_info_t));
   5298 	}
   5299 }
   5300 
   5301 
   5302 /*
   5303  * ibdm_ibnex_update_pkey_tbls
   5304  *	Updates the DM P_Key database.
   5305  *	NOTE: Two cases are handled here: P_Key being added or removed.
   5306  *
   5307  * Arguments		: NONE
   5308  * Return Values	: NONE
   5309  */
   5310 void
   5311 ibdm_ibnex_update_pkey_tbls(void)
   5312 {
   5313 	int			h, pp, pidx;
   5314 	uint_t			nports;
   5315 	uint_t			size;
   5316 	ib_pkey_t		new_pkey;
   5317 	ib_pkey_t		*orig_pkey;
   5318 	ibdm_hca_list_t		*hca_list;
   5319 	ibdm_port_attr_t	*port;
   5320 	ibt_hca_portinfo_t	*pinfop;
   5321 
   5322 	IBTF_DPRINTF_L4("ibdm", "\tibnex_update_pkey_tbls:");
   5323 
   5324 	mutex_enter(&ibdm.ibdm_hl_mutex);
   5325 	hca_list = ibdm.ibdm_hca_list_head;
   5326 
   5327 	for (h = 0; h < ibdm.ibdm_hca_count; h++) {
   5328 
   5329 		/* This updates P_Key Tables for all ports of this HCA */
   5330 		(void) ibt_query_hca_ports(hca_list->hl_hca_hdl, 0, &pinfop,
   5331 		    &nports, &size);
   5332 
   5333 		/* number of ports shouldn't have changed */
   5334 		ASSERT(nports == hca_list->hl_nports);
   5335 
   5336 		for (pp = 0; pp < hca_list->hl_nports; pp++) {
   5337 			port = &hca_list->hl_port_attr[pp];
   5338 
   5339 			/*
   5340 			 * First figure out the P_Keys from IBTL.
   5341 			 * Three things could have happened:
   5342 			 *	New P_Keys added
   5343 			 *	Existing P_Keys removed
   5344 			 *	Both of the above two
   5345 			 *
   5346 			 * Loop through the P_Key Indices and check if a
   5347 			 * give P_Key_Ix matches that of the one seen by
   5348 			 * IBDM. If they match no action is needed.
   5349 			 *
   5350 			 * If they don't match:
   5351 			 *	1. if orig_pkey is invalid and new_pkey is valid
   5352 			 *		---> add new_pkey to DM database
   5353 			 *	2. if orig_pkey is valid and new_pkey is invalid
   5354 			 *		---> remove orig_pkey from DM database
   5355 			 *	3. if orig_pkey and new_pkey are both valid:
   5356 			 *		---> remov orig_pkey from DM database
   5357 			 *		---> add new_pkey to DM database
   5358 			 *	4. if orig_pkey and new_pkey are both invalid:
   5359 			 *		---> do nothing. Updated DM database.
   5360 			 */
   5361 
   5362 			for (pidx = 0; pidx < port->pa_npkeys; pidx++) {
   5363 				new_pkey = pinfop[pp].p_pkey_tbl[pidx];
   5364 				orig_pkey = &port->pa_pkey_tbl[pidx].pt_pkey;
   5365 
   5366 				/* keys match - do nothing */
   5367 				if (*orig_pkey == new_pkey)
   5368 					continue;
   5369 
   5370 				if (IBDM_INVALID_PKEY(*orig_pkey) &&
   5371 				    !IBDM_INVALID_PKEY(new_pkey)) {
   5372 					/* P_Key was added */
   5373 					IBTF_DPRINTF_L5("ibdm",
   5374 					    "\tibnex_update_pkey_tbls: new "
   5375 					    "P_Key added = 0x%x", new_pkey);
   5376 					*orig_pkey = new_pkey;
   5377 					ibdm_port_attr_ibmf_init(port,
   5378 					    new_pkey, pp);
   5379 				} else if (!IBDM_INVALID_PKEY(*orig_pkey) &&
   5380 				    IBDM_INVALID_PKEY(new_pkey)) {
   5381 					/* P_Key was removed */
   5382 					IBTF_DPRINTF_L5("ibdm",
   5383 					    "\tibnex_update_pkey_tbls: P_Key "
   5384 					    "removed = 0x%x", *orig_pkey);
   5385 					*orig_pkey = new_pkey;
   5386 					(void) ibdm_port_attr_ibmf_fini(port,
   5387 					    pidx);
   5388 				} else if (!IBDM_INVALID_PKEY(*orig_pkey) &&
   5389 				    !IBDM_INVALID_PKEY(new_pkey)) {
   5390 					/* P_Key were replaced */
   5391 					IBTF_DPRINTF_L5("ibdm",
   5392 					    "\tibnex_update_pkey_tbls: P_Key "
   5393 					    "replaced 0x%x with 0x%x",
   5394 					    *orig_pkey, new_pkey);
   5395 					(void) ibdm_port_attr_ibmf_fini(port,
   5396 					    pidx);
   5397 					*orig_pkey = new_pkey;
   5398 					ibdm_port_attr_ibmf_init(port,
   5399 					    new_pkey, pp);
   5400 				} else {
   5401 					/*
   5402 					 * P_Keys are invalid
   5403 					 * set anyway to reflect if
   5404 					 * INVALID_FULL was changed to
   5405 					 * INVALID_LIMITED or vice-versa.
   5406 					 */
   5407 					*orig_pkey = new_pkey;
   5408 				} /* end of else */
   5409 
   5410 			} /* loop of p_key index */
   5411 
   5412 		} /* loop of #ports of HCA */
   5413 
   5414 		ibt_free_portinfo(pinfop, size);
   5415 		hca_list = hca_list->hl_next;
   5416 
   5417 	} /* loop for all HCAs in the system */
   5418 
   5419 	mutex_exit(&ibdm.ibdm_hl_mutex);
   5420 }
   5421 
   5422 
   5423 /*
   5424  * ibdm_send_ioc_profile()
   5425  *	Send IOC Controller Profile request. When the request is completed
   5426  *	IBMF calls ibdm_process_incoming_mad routine to inform about
   5427  *	the completion.
   5428  */
   5429 static int
   5430 ibdm_send_ioc_profile(ibdm_dp_gidinfo_t *gid_info, uint8_t ioc_no)
   5431 {
   5432 	ibmf_msg_t		*msg;
   5433 	ib_mad_hdr_t	*hdr;
   5434 	ibdm_ioc_info_t	*ioc_info = &(gid_info->gl_iou->iou_ioc_info[ioc_no]);
   5435 	ibdm_timeout_cb_args_t	*cb_args;
   5436 
   5437 	IBTF_DPRINTF_L4("ibdm", "\tsend_ioc_profile: "
   5438 	    "gid info 0x%p, ioc_no = %d", gid_info, ioc_no);
   5439 
   5440 	/*
   5441 	 * Send command to get IOC profile.
   5442 	 * Allocate a IBMF packet and initialize the packet.
   5443 	 */
   5444 	if (ibmf_alloc_msg(gid_info->gl_ibmf_hdl, IBMF_ALLOC_SLEEP,
   5445 	    &msg) != IBMF_SUCCESS) {
   5446 		IBTF_DPRINTF_L2("ibdm", "\tsend_ioc_profile: pkt alloc fail");
   5447 		return (IBDM_FAILURE);
   5448 	}
   5449 
   5450 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*msg))
   5451 	ibdm_alloc_send_buffers(msg);
   5452 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*msg))
   5453 
   5454 	mutex_enter(&gid_info->gl_mutex);
   5455 	ibdm_bump_transactionID(gid_info);
   5456 	mutex_exit(&gid_info->gl_mutex);
   5457 
   5458 	msg->im_local_addr.ia_local_lid	= gid_info->gl_slid;
   5459 	msg->im_local_addr.ia_remote_lid	= gid_info->gl_dlid;
   5460 	if (gid_info->gl_redirected == B_TRUE) {
   5461 		if (gid_info->gl_redirect_dlid != 0) {
   5462 			msg->im_local_addr.ia_remote_lid =
   5463 			    gid_info->gl_redirect_dlid;
   5464 		}
   5465 		msg->im_local_addr.ia_remote_qno = gid_info->gl_redirect_QP;
   5466 		msg->im_local_addr.ia_p_key = gid_info->gl_redirect_pkey;
   5467 		msg->im_local_addr.ia_q_key = gid_info->gl_redirect_qkey;
   5468 		msg->im_local_addr.ia_service_level = gid_info->gl_redirectSL;
   5469 	} else {
   5470 		msg->im_local_addr.ia_remote_qno = 1;
   5471 		msg->im_local_addr.ia_p_key = gid_info->gl_p_key;
   5472 		msg->im_local_addr.ia_q_key = IB_GSI_QKEY;
   5473 		msg->im_local_addr.ia_service_level = gid_info->gl_SL;
   5474 	}
   5475 
   5476 	hdr			= IBDM_OUT_IBMFMSG_MADHDR(msg);
   5477 	hdr->BaseVersion	= MAD_CLASS_BASE_VERS_1;
   5478 	hdr->MgmtClass		= MAD_MGMT_CLASS_DEV_MGT;
   5479 	hdr->ClassVersion	= IB_DM_CLASS_VERSION_1;
   5480 	hdr->R_Method		= IB_DM_DEVMGT_METHOD_GET;
   5481 	hdr->Status		= 0;
   5482 	hdr->TransactionID	= h2b64(gid_info->gl_transactionID);
   5483 	hdr->AttributeID	= h2b16(IB_DM_ATTR_IOC_CTRL_PROFILE);
   5484 	hdr->AttributeModifier 	= h2b32(ioc_no + 1);
   5485 
   5486 	ioc_info->ioc_state	= IBDM_IOC_STATE_REPROBE_PROGRESS;
   5487 	cb_args			= &ioc_info->ioc_cb_args;
   5488 	cb_args->cb_gid_info	= gid_info;
   5489 	cb_args->cb_retry_count	= ibdm_dft_retry_cnt;
   5490 	cb_args->cb_req_type	= IBDM_REQ_TYPE_IOCINFO;
   5491 	cb_args->cb_ioc_num	= ioc_no;
   5492 
   5493 	mutex_enter(&gid_info->gl_mutex);
   5494 	ioc_info->ioc_timeout_id = timeout(ibdm_pkt_timeout_hdlr,
   5495 	    cb_args, IBDM_TIMEOUT_VALUE(ibdm_dft_timeout));
   5496 	mutex_exit(&gid_info->gl_mutex);
   5497 
   5498 	IBTF_DPRINTF_L5("ibdm", "\tsend_ioc_profile:"
   5499 	    "timeout %x", ioc_info->ioc_timeout_id);
   5500 
   5501 	if (ibmf_msg_transport(gid_info->gl_ibmf_hdl, gid_info->gl_qp_hdl, msg,
   5502 	    NULL, ibdm_ibmf_send_cb, cb_args, 0) != IBMF_SUCCESS) {
   5503 		IBTF_DPRINTF_L2("ibdm",
   5504 		    "\tsend_ioc_profile: msg transport failed");
   5505 		ibdm_ibmf_send_cb(gid_info->gl_ibmf_hdl, msg, cb_args);
   5506 	}
   5507 	ioc_info->ioc_state = IBDM_IOC_STATE_REPROBE_PROGRESS;
   5508 	return (IBDM_SUCCESS);
   5509 }
   5510 
   5511 
   5512 /*
   5513  * ibdm_port_reachable
   5514  *	Returns B_TRUE if the port GID is reachable by sending
   5515  *	a SA query to get the NODE record for this port GUID.
   5516  */
   5517 static boolean_t
   5518 ibdm_port_reachable(ibmf_saa_handle_t sa_hdl, ib_guid_t guid)
   5519 {
   5520 	sa_node_record_t *resp;
   5521 	size_t length;
   5522 
   5523 	/*
   5524 	 * Verify if it's reachable by getting the node record.
   5525 	 */
   5526 	if (ibdm_get_node_record_by_port(sa_hdl, guid, &resp, &length) ==
   5527 	    IBDM_SUCCESS) {
   5528 		kmem_free(resp, length);
   5529 		return (B_TRUE);
   5530 	}
   5531 	return (B_FALSE);
   5532 }
   5533 
   5534 /*
   5535  * ibdm_get_node_record_by_port
   5536  *	Sends a SA query to get the NODE record for port GUID
   5537  *	Returns IBDM_SUCCESS if the port GID is reachable.
   5538  *
   5539  *      Note: the caller must be responsible for freeing the resource
   5540  *      by calling kmem_free(resp, length) later.
   5541  */
   5542 static int
   5543 ibdm_get_node_record_by_port(ibmf_saa_handle_t sa_hdl, ib_guid_t guid,
   5544     sa_node_record_t **resp, size_t *length)
   5545 {
   5546 	sa_node_record_t	req;
   5547 	ibmf_saa_access_args_t	args;
   5548 	int			ret;
   5549 	ASSERT(resp != NULL && length != NULL);
   5550 
   5551 	IBTF_DPRINTF_L4("ibdm", "\tport_reachable: port_guid %llx",
   5552 	    guid);
   5553 
   5554 	bzero(&req, sizeof (sa_node_record_t));
   5555 	req.NodeInfo.PortGUID = guid;
   5556 
   5557 	args.sq_attr_id		= SA_NODERECORD_ATTRID;
   5558 	args.sq_access_type 	= IBMF_SAA_RETRIEVE;
   5559 	args.sq_component_mask 	= SA_NODEINFO_COMPMASK_PORTGUID;
   5560 	args.sq_template	= &req;
   5561 	args.sq_callback	= NULL;
   5562 	args.sq_callback_arg 	= NULL;
   5563 
   5564 	ret = ibmf_sa_access(sa_hdl, &args, 0, length, (void **) resp);
   5565 	if (ret != IBMF_SUCCESS) {
   5566 		IBTF_DPRINTF_L2("ibdm", "\tport_reachable:"
   5567 		    " SA Retrieve Failed: %d", ret);
   5568 		return (IBDM_FAILURE);
   5569 	}
   5570 	if (*resp == NULL || *length == 0) {
   5571 		IBTF_DPRINTF_L2("ibdm", "\tport_reachable: No records");
   5572 		return (IBDM_FAILURE);
   5573 	}
   5574 	/*
   5575 	 * There is one NodeRecord on each endport on a subnet.
   5576 	 */
   5577 	ASSERT(*length == sizeof (sa_node_record_t));
   5578 
   5579 	return (IBDM_SUCCESS);
   5580 }
   5581 
   5582 
   5583 /*
   5584  * Update the gidlist for all affected IOCs when GID becomes
   5585  * available/unavailable.
   5586  *
   5587  * Parameters :
   5588  *	gidinfo - Incoming / Outgoing GID.
   5589  *	add_flag - 1 for GID added, 0 for GID removed.
   5590  *		- (-1) : IOC gid list updated, ioc_list required.
   5591  *
   5592  * This function gets the GID for the node GUID corresponding to the
   5593  * port GID. Gets the IOU info
   5594  */
   5595 static ibdm_ioc_info_t *
   5596 ibdm_update_ioc_gidlist(ibdm_dp_gidinfo_t *gid_info, int avail_flag)
   5597 {
   5598 	ibdm_dp_gidinfo_t	*node_gid = NULL;
   5599 	uint8_t	niocs, ii;
   5600 	ibdm_ioc_info_t	*ioc, *ioc_list = NULL, *tmp;
   5601 
   5602 	IBTF_DPRINTF_L4("ibdm", "\tupdate_ioc_gidlist");
   5603 
   5604 	switch (avail_flag) {
   5605 		case 1 :
   5606 			node_gid = ibdm_check_dest_nodeguid(gid_info);
   5607 			break;
   5608 		case 0 :
   5609 			node_gid = ibdm_handle_gid_rm(gid_info);
   5610 			break;
   5611 		case -1 :
   5612 			node_gid = gid_info;
   5613 			break;
   5614 		default :
   5615 			break;
   5616 	}
   5617 
   5618 	if (node_gid == NULL) {
   5619 		IBTF_DPRINTF_L4("ibdm", "\tupdate_ioc_gidlist: "
   5620 		    "No node GID found, port gid 0x%p, avail_flag %d",
   5621 		    gid_info, avail_flag);
   5622 		return (NULL);
   5623 	}
   5624 
   5625 	mutex_enter(&node_gid->gl_mutex);
   5626 	if ((node_gid->gl_state != IBDM_GID_PROBING_COMPLETE &&
   5627 	    node_gid->gl_state != IBDM_GID_PROBING_SKIPPED) ||
   5628 	    node_gid->gl_iou == NULL) {
   5629 		IBTF_DPRINTF_L4("ibdm", "\tupdate_ioc_gidlist "
   5630 		    "gl_state %x, gl_iou %p", node_gid->gl_state,
   5631 		    node_gid->gl_iou);
   5632 		mutex_exit(&node_gid->gl_mutex);
   5633 		return (NULL);
   5634 	}
   5635 
   5636 	niocs = node_gid->gl_iou->iou_info.iou_num_ctrl_slots;
   5637 	IBTF_DPRINTF_L4("ibdm", "\tupdate_ioc_gidlist : niocs %x",
   5638 	    niocs);
   5639 	for (ii = 0; ii < niocs; ii++) {
   5640 		ioc = IBDM_GIDINFO2IOCINFO(node_gid, ii);
   5641 		/*
   5642 		 * Skip IOCs for which probe is not complete or
   5643 		 * reprobe is progress
   5644 		 */
   5645 		if (ioc->ioc_state == IBDM_IOC_STATE_PROBE_SUCCESS) {
   5646 			tmp = ibdm_dup_ioc_info(ioc, node_gid);
   5647 			tmp->ioc_info_updated.ib_gid_prop_updated = 1;
   5648 			tmp->ioc_next = ioc_list;
   5649 			ioc_list = tmp;
   5650 		}
   5651 	}
   5652 	mutex_exit(&node_gid->gl_mutex);
   5653 
   5654 	IBTF_DPRINTF_L4("ibdm", "\tupdate_ioc_gidlist : return %p",
   5655 	    ioc_list);
   5656 	return (ioc_list);
   5657 }
   5658 
   5659 /*
   5660  * ibdm_saa_event_cb :
   5661  *	Event handling which does *not* require ibdm_hl_mutex to be
   5662  *	held are executed in the same thread. This is to prevent
   5663  *	deadlocks with HCA port down notifications which hold the
   5664  *	ibdm_hl_mutex.
   5665  *
   5666  *	GID_AVAILABLE event is handled here. A taskq is spawned to
   5667  *	handle GID_UNAVAILABLE.
   5668  *
   5669  *	A new mutex ibdm_ibnex_mutex has been introduced to protect
   5670  *	ibnex_callback. This has been done to prevent any possible
   5671  *	deadlock (described above) while handling GID_AVAILABLE.
   5672  *
   5673  *	IBMF calls the event callback for a HCA port. The SA handle
   5674  *	for this port would be valid, till the callback returns.
   5675  *	IBDM calling IBDM using the above SA handle should be valid.
   5676  *
   5677  *	IBDM will additionally  check (SA handle != NULL), before
   5678  *	calling IBMF.
   5679  */
   5680 /*ARGSUSED*/
   5681 static void
   5682 ibdm_saa_event_cb(ibmf_saa_handle_t ibmf_saa_handle,
   5683     ibmf_saa_subnet_event_t ibmf_saa_event,
   5684     ibmf_saa_event_details_t *event_details, void *callback_arg)
   5685 {
   5686 	ibdm_saa_event_arg_t *event_arg;
   5687 	ib_gid_t		sgid, dgid;
   5688 	ibdm_port_attr_t	*hca_port;
   5689 	ibdm_dp_gidinfo_t	*gid_info, *node_gid_info = NULL;
   5690 	sa_node_record_t *nrec;
   5691 	size_t length;
   5692 
   5693 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*event_arg));
   5694 
   5695 	hca_port = (ibdm_port_attr_t *)callback_arg;
   5696 
   5697 	IBTF_DPRINTF_L4("ibdm", "\tsaa_event_cb(%x, %x, %x, %x)\n",
   5698 	    ibmf_saa_handle, ibmf_saa_event, event_details,
   5699 	    callback_arg);
   5700 #ifdef DEBUG
   5701 	if (ibdm_ignore_saa_event)
   5702 		return;
   5703 #endif
   5704 
   5705 	if (ibmf_saa_event == IBMF_SAA_EVENT_GID_AVAILABLE) {
   5706 		/*
   5707 		 * Ensure no other probe / sweep fabric is in
   5708 		 * progress.
   5709 		 */
   5710 		mutex_enter(&ibdm.ibdm_mutex);
   5711 		while (ibdm.ibdm_busy & IBDM_BUSY)
   5712 			cv_wait(&ibdm.ibdm_busy_cv, &ibdm.ibdm_mutex);
   5713 		ibdm.ibdm_busy |= IBDM_BUSY;
   5714 		mutex_exit(&ibdm.ibdm_mutex);
   5715 
   5716 		/*
   5717 		 * If we already know about this GID, return.
   5718 		 * GID_AVAILABLE may be reported for multiple HCA
   5719 		 * ports.
   5720 		 */
   5721 		if ((ibdm_check_dgid(event_details->ie_gid.gid_guid,
   5722 		    event_details->ie_gid.gid_prefix))  != NULL) {
   5723 			mutex_enter(&ibdm.ibdm_mutex);
   5724 			ibdm.ibdm_busy &= ~IBDM_BUSY;
   5725 			cv_broadcast(&ibdm.ibdm_busy_cv);
   5726 			mutex_exit(&ibdm.ibdm_mutex);
   5727 			return;
   5728 		}
   5729 
   5730 		IBTF_DPRINTF_L4("ibdm", "\tGID (prefix %x, guid %llx) "
   5731 		    "Insertion notified",
   5732 		    event_details->ie_gid.gid_prefix,
   5733 		    event_details->ie_gid.gid_guid);
   5734 
   5735 		/* This is a new gid, insert it to GID list */
   5736 		sgid.gid_prefix = hca_port->pa_sn_prefix;
   5737 		sgid.gid_guid = hca_port->pa_port_guid;
   5738 		dgid.gid_prefix = event_details->ie_gid.gid_prefix;
   5739 		dgid.gid_guid = event_details->ie_gid.gid_guid;
   5740 		gid_info = ibdm_create_gid_info(hca_port, sgid, dgid);
   5741 		if (gid_info == NULL) {
   5742 			IBTF_DPRINTF_L4("ibdm", "\tGID_AVAILABLE: "
   5743 			    "create_gid_info returned NULL");
   5744 			mutex_enter(&ibdm.ibdm_mutex);
   5745 			ibdm.ibdm_busy &= ~IBDM_BUSY;
   5746 			cv_broadcast(&ibdm.ibdm_busy_cv);
   5747 			mutex_exit(&ibdm.ibdm_mutex);
   5748 			return;
   5749 		}
   5750 		mutex_enter(&gid_info->gl_mutex);
   5751 		gid_info->gl_state = IBDM_GID_PROBING_SKIPPED;
   5752 		mutex_exit(&gid_info->gl_mutex);
   5753 
   5754 		/* Get the node GUID */
   5755 		if (ibdm_get_node_record_by_port(ibmf_saa_handle, dgid.gid_guid,
   5756 		    &nrec, &length) != IBDM_SUCCESS) {
   5757 			/*
   5758 			 * Set the state to PROBE_NOT_DONE for the
   5759 			 * next sweep to probe it
   5760 			 */
   5761 			IBTF_DPRINTF_L2("ibdm", "\tsaa_event_taskq: "
   5762 			    "Skipping GID : port GUID not found");
   5763 			mutex_enter(&gid_info->gl_mutex);
   5764 			gid_info->gl_state = IBDM_GID_PROBE_NOT_DONE;
   5765 			mutex_exit(&gid_info->gl_mutex);
   5766 			mutex_enter(&ibdm.ibdm_mutex);
   5767 			ibdm.ibdm_busy &= ~IBDM_BUSY;
   5768 			cv_broadcast(&ibdm.ibdm_busy_cv);
   5769 			mutex_exit(&ibdm.ibdm_mutex);
   5770 			return;
   5771 		}
   5772 		gid_info->gl_nodeguid = nrec->NodeInfo.NodeGUID;
   5773 		gid_info->gl_devid = nrec->NodeInfo.DeviceID;
   5774 		kmem_free(nrec, length);
   5775 		gid_info->gl_portguid = dgid.gid_guid;
   5776 
   5777 		/*
   5778 		 * Get the gid info with the same node GUID.
   5779 		 */
   5780 		mutex_enter(&ibdm.ibdm_mutex);
   5781 		node_gid_info = ibdm.ibdm_dp_gidlist_head;
   5782 		while (node_gid_info) {
   5783 			if (node_gid_info->gl_nodeguid ==
   5784 			    gid_info->gl_nodeguid &&
   5785 			    node_gid_info->gl_iou != NULL) {
   5786 				break;
   5787 			}
   5788 			node_gid_info = node_gid_info->gl_next;
   5789 		}
   5790 		mutex_exit(&ibdm.ibdm_mutex);
   5791 
   5792 		/*
   5793 		 * Handling a new GID requires filling of gl_hca_list.
   5794 		 * This require ibdm hca_list to be parsed and hence
   5795 		 * holding the ibdm_hl_mutex. Spawning a new thread to
   5796 		 * handle this.
   5797 		 */
   5798 		if (node_gid_info == NULL) {
   5799 			if (taskq_dispatch(system_taskq,
   5800 			    ibdm_saa_handle_new_gid, (void *)gid_info,
   5801 			    TQ_NOSLEEP) == NULL) {
   5802 				IBTF_DPRINTF_L2("ibdm", "\tsaa_event_cb: "
   5803 				    "new_gid taskq_dispatch failed");
   5804 				return;
   5805 			}
   5806 		}
   5807 
   5808 		mutex_enter(&ibdm.ibdm_mutex);
   5809 		ibdm.ibdm_busy &= ~IBDM_BUSY;
   5810 		cv_broadcast(&ibdm.ibdm_busy_cv);
   5811 		mutex_exit(&ibdm.ibdm_mutex);
   5812 		return;
   5813 	}
   5814 
   5815 	if (ibmf_saa_event != IBMF_SAA_EVENT_GID_UNAVAILABLE)
   5816 		return;
   5817 
   5818 	/*
   5819 	 * GID UNAVAIL EVENT: Try to locate the GID in the GID list.
   5820 	 * If we don't find it we just return.
   5821 	 */
   5822 	mutex_enter(&ibdm.ibdm_mutex);
   5823 	gid_info = ibdm.ibdm_dp_gidlist_head;
   5824 	while (gid_info) {
   5825 		if (gid_info->gl_portguid ==
   5826 		    event_details->ie_gid.gid_guid) {
   5827 			break;
   5828 		}
   5829 		gid_info = gid_info->gl_next;
   5830 	}
   5831 	mutex_exit(&ibdm.ibdm_mutex);
   5832 	if (gid_info == NULL) {
   5833 		IBTF_DPRINTF_L2("ibdm", "\tsaa_event_cb: "
   5834 		    "GID for GUID %llX not found during GID UNAVAIL event",
   5835 		    event_details->ie_gid.gid_guid);
   5836 		return;
   5837 	}
   5838 
   5839 	/*
   5840 	 * If this GID is DM capable, we'll have to check whether this DGID
   5841 	 * is reachable via another port.
   5842 	 */
   5843 	if (gid_info->gl_is_dm_capable == B_TRUE) {
   5844 		event_arg = (ibdm_saa_event_arg_t *)kmem_alloc(
   5845 		    sizeof (ibdm_saa_event_arg_t), KM_SLEEP);
   5846 		event_arg->ibmf_saa_handle = ibmf_saa_handle;
   5847 		event_arg->ibmf_saa_event = ibmf_saa_event;
   5848 		bcopy(event_details, &event_arg->event_details,
   5849 		    sizeof (ibmf_saa_event_details_t));
   5850 		event_arg->callback_arg = callback_arg;
   5851 
   5852 		if (taskq_dispatch(system_taskq, ibdm_saa_event_taskq,
   5853 		    (void *)event_arg, TQ_NOSLEEP) == NULL) {
   5854 			IBTF_DPRINTF_L2("ibdm", "\tsaa_event_cb: "
   5855 			    "taskq_dispatch failed");
   5856 			ibdm_free_saa_event_arg(event_arg);
   5857 			return;
   5858 		}
   5859 	}
   5860 }
   5861 
   5862 /*
   5863  * Handle a new GID discovered by GID_AVAILABLE saa event.
   5864  */
   5865 void
   5866 ibdm_saa_handle_new_gid(void *arg)
   5867 {
   5868 	ibdm_dp_gidinfo_t	*gid_info;
   5869 	ibdm_hca_list_t		*hca_list = NULL;
   5870 	ibdm_port_attr_t	*port = NULL;
   5871 	ibdm_ioc_info_t		*ioc_list = NULL;
   5872 
   5873 	IBTF_DPRINTF_L4(ibdm_string, "\tsaa_handle_new_gid(%p)", arg);
   5874 
   5875 	gid_info = (ibdm_dp_gidinfo_t *)arg;
   5876 
   5877 	/*
   5878 	 * Ensure that no other sweep / probe has completed
   5879 	 * probing this gid.
   5880 	 */
   5881 	mutex_enter(&gid_info->gl_mutex);
   5882 	if (gid_info->gl_state != IBDM_GID_PROBE_NOT_DONE) {
   5883 		mutex_exit(&gid_info->gl_mutex);
   5884 		return;
   5885 	}
   5886 	mutex_exit(&gid_info->gl_mutex);
   5887 
   5888 	/*
   5889 	 * Parse HCAs to fill gl_hca_list
   5890 	 */
   5891 	mutex_enter(&ibdm.ibdm_hl_mutex);
   5892 	for (ibdm_get_next_port(&hca_list, &port, 1); port;
   5893 	    ibdm_get_next_port(&hca_list, &port, 1)) {
   5894 		if (ibdm_port_reachable(port->pa_sa_hdl,
   5895 		    gid_info->gl_portguid) == B_TRUE) {
   5896 			ibdm_addto_glhcalist(gid_info, hca_list);
   5897 		}
   5898 	}
   5899 	mutex_exit(&ibdm.ibdm_hl_mutex);
   5900 
   5901 	/*
   5902 	 * Ensure no other probe / sweep fabric is in
   5903 	 * progress.
   5904 	 */
   5905 	mutex_enter(&ibdm.ibdm_mutex);
   5906 	while (ibdm.ibdm_busy & IBDM_BUSY)
   5907 		cv_wait(&ibdm.ibdm_busy_cv, &ibdm.ibdm_mutex);
   5908 	ibdm.ibdm_busy |= IBDM_BUSY;
   5909 	mutex_exit(&ibdm.ibdm_mutex);
   5910 
   5911 	/*
   5912 	 * New IOU probe it, to check if new IOCs
   5913 	 */
   5914 	IBTF_DPRINTF_L4(ibdm_string, "\tsaa_handle_new_gid: "
   5915 	    "new GID : probing");
   5916 	mutex_enter(&ibdm.ibdm_mutex);
   5917 	ibdm.ibdm_ngid_probes_in_progress++;
   5918 	mutex_exit(&ibdm.ibdm_mutex);
   5919 	mutex_enter(&gid_info->gl_mutex);
   5920 	gid_info->gl_reprobe_flag = 0;
   5921 	gid_info->gl_state = IBDM_GID_PROBE_NOT_DONE;
   5922 	mutex_exit(&gid_info->gl_mutex);
   5923 	ibdm_probe_gid_thread((void *)gid_info);
   5924 
   5925 	mutex_enter(&ibdm.ibdm_mutex);
   5926 	ibdm_wait_probe_completion();
   5927 	mutex_exit(&ibdm.ibdm_mutex);
   5928 
   5929 	if (gid_info->gl_iou == NULL) {
   5930 		mutex_enter(&ibdm.ibdm_mutex);
   5931 		ibdm.ibdm_busy &= ~IBDM_BUSY;
   5932 		cv_broadcast(&ibdm.ibdm_busy_cv);
   5933 		mutex_exit(&ibdm.ibdm_mutex);
   5934 		return;
   5935 	}
   5936 
   5937 	/*
   5938 	 * Update GID list in all IOCs affected by this
   5939 	 */
   5940 	ioc_list = ibdm_update_ioc_gidlist(gid_info, 1);
   5941 
   5942 	/*
   5943 	 * Pass on the IOCs with updated GIDs to IBnexus
   5944 	 */
   5945 	if (ioc_list) {
   5946 		mutex_enter(&ibdm.ibdm_ibnex_mutex);
   5947 		if (ibdm.ibdm_ibnex_callback != NULL) {
   5948 			(*ibdm.ibdm_ibnex_callback)((void *)ioc_list,
   5949 			    IBDM_EVENT_IOC_PROP_UPDATE);
   5950 		}
   5951 		mutex_exit(&ibdm.ibdm_ibnex_mutex);
   5952 	}
   5953 
   5954 	mutex_enter(&ibdm.ibdm_mutex);
   5955 	ibdm.ibdm_busy &= ~IBDM_BUSY;
   5956 	cv_broadcast(&ibdm.ibdm_busy_cv);
   5957 	mutex_exit(&ibdm.ibdm_mutex);
   5958 }
   5959 
   5960 /*
   5961  * ibdm_saa_event_taskq :
   5962  *	GID_UNAVAILABLE Event handling requires ibdm_hl_mutex to be
   5963  *	held. The GID_UNAVAILABLE handling is done in a taskq to
   5964  *	prevent deadlocks with HCA port down notifications which hold
   5965  *	ibdm_hl_mutex.
   5966  */
   5967 void
   5968 ibdm_saa_event_taskq(void *arg)
   5969 {
   5970 	ibdm_saa_event_arg_t *event_arg;
   5971 	ibmf_saa_handle_t ibmf_saa_handle;
   5972 	ibmf_saa_subnet_event_t ibmf_saa_event;
   5973 	ibmf_saa_event_details_t *event_details;
   5974 	void *callback_arg;
   5975 
   5976 	ibdm_dp_gidinfo_t	*gid_info;
   5977 	ibdm_port_attr_t	*hca_port, *port = NULL;
   5978 	ibdm_hca_list_t		*hca_list = NULL;
   5979 	int	sa_handle_valid = 0;
   5980 	ibdm_ioc_info_t		*ioc_list = NULL;
   5981 
   5982 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*event_arg));
   5983 
   5984 	event_arg = (ibdm_saa_event_arg_t *)arg;
   5985 	ibmf_saa_handle = event_arg->ibmf_saa_handle;
   5986 	ibmf_saa_event = event_arg->ibmf_saa_event;
   5987 	event_details = &event_arg->event_details;
   5988 	callback_arg = event_arg->callback_arg;
   5989 
   5990 	ASSERT(callback_arg != NULL);
   5991 	ASSERT(ibmf_saa_event == IBMF_SAA_EVENT_GID_UNAVAILABLE);
   5992 	IBTF_DPRINTF_L4("ibdm", "\tsaa_event_taskq(%x, %x, %x, %x)",
   5993 	    ibmf_saa_handle, ibmf_saa_event, event_details,
   5994 	    callback_arg);
   5995 
   5996 	hca_port = (ibdm_port_attr_t *)callback_arg;
   5997 
   5998 	/* Check if the port_attr is still valid */
   5999 	mutex_enter(&ibdm.ibdm_hl_mutex);
   6000 	for (ibdm_get_next_port(&hca_list, &port, 0); port;
   6001 	    ibdm_get_next_port(&hca_list, &port, 0)) {
   6002 		if (port == hca_port && port->pa_port_guid ==
   6003 		    hca_port->pa_port_guid) {
   6004 			if (ibmf_saa_handle == hca_port->pa_sa_hdl)
   6005 				sa_handle_valid = 1;
   6006 			break;
   6007 		}
   6008 	}
   6009 	mutex_exit(&ibdm.ibdm_hl_mutex);
   6010 	if (sa_handle_valid == 0) {
   6011 		ibdm_free_saa_event_arg(event_arg);
   6012 		return;
   6013 	}
   6014 
   6015 	if (hca_port && (hca_port->pa_sa_hdl == NULL ||
   6016 	    ibmf_saa_handle != hca_port->pa_sa_hdl)) {
   6017 		ibdm_free_saa_event_arg(event_arg);
   6018 		return;
   6019 	}
   6020 	hca_list = NULL;
   6021 	port = NULL;
   6022 
   6023 	/*
   6024 	 * Check if the GID is visible to other HCA ports.
   6025 	 * Return if so.
   6026 	 */
   6027 	mutex_enter(&ibdm.ibdm_hl_mutex);
   6028 	for (ibdm_get_next_port(&hca_list, &port, 1); port;
   6029 	    ibdm_get_next_port(&hca_list, &port, 1)) {
   6030 		if (ibdm_port_reachable(port->pa_sa_hdl,
   6031 		    event_details->ie_gid.gid_guid) == B_TRUE) {
   6032 			mutex_exit(&ibdm.ibdm_hl_mutex);
   6033 			ibdm_free_saa_event_arg(event_arg);
   6034 			return;
   6035 		}
   6036 	}
   6037 	mutex_exit(&ibdm.ibdm_hl_mutex);
   6038 
   6039 	/*
   6040 	 * Ensure no other probe / sweep fabric is in
   6041 	 * progress.
   6042 	 */
   6043 	mutex_enter(&ibdm.ibdm_mutex);
   6044 	while (ibdm.ibdm_busy & IBDM_BUSY)
   6045 		cv_wait(&ibdm.ibdm_busy_cv, &ibdm.ibdm_mutex);
   6046 	ibdm.ibdm_busy |= IBDM_BUSY;
   6047 	mutex_exit(&ibdm.ibdm_mutex);
   6048 
   6049 	/*
   6050 	 * If this GID is no longer in GID list, return
   6051 	 * GID_UNAVAILABLE may be reported for multiple HCA
   6052 	 * ports.
   6053 	 */
   6054 	mutex_enter(&ibdm.ibdm_mutex);
   6055 	gid_info = ibdm.ibdm_dp_gidlist_head;
   6056 	while (gid_info) {
   6057 		if (gid_info->gl_portguid ==
   6058 		    event_details->ie_gid.gid_guid) {
   6059 			break;
   6060 		}
   6061 		gid_info = gid_info->gl_next;
   6062 	}
   6063 	mutex_exit(&ibdm.ibdm_mutex);
   6064 	if (gid_info == NULL) {
   6065 		mutex_enter(&ibdm.ibdm_mutex);
   6066 		ibdm.ibdm_busy &= ~IBDM_BUSY;
   6067 		cv_broadcast(&ibdm.ibdm_busy_cv);
   6068 		mutex_exit(&ibdm.ibdm_mutex);
   6069 		ibdm_free_saa_event_arg(event_arg);
   6070 		return;
   6071 	}
   6072 
   6073 	IBTF_DPRINTF_L4("ibdm", "\tGID (prefix %x, guid %llx) "
   6074 	    "Unavailable notification",
   6075 	    event_details->ie_gid.gid_prefix,
   6076 	    event_details->ie_gid.gid_guid);
   6077 
   6078 	/*
   6079 	 * Update GID list in all IOCs affected by this
   6080 	 */
   6081 	if (gid_info->gl_state == IBDM_GID_PROBING_SKIPPED ||
   6082 	    gid_info->gl_state == IBDM_GID_PROBING_COMPLETE)
   6083 		ioc_list = ibdm_update_ioc_gidlist(gid_info, 0);
   6084 
   6085 	/*
   6086 	 * Remove GID from the global GID list
   6087 	 * Handle the case where all port GIDs for an
   6088 	 * IOU have been hot-removed. Check both gid_info
   6089 	 * & ioc_info for checking ngids.
   6090 	 */
   6091 	mutex_enter(&ibdm.ibdm_mutex);
   6092 	if (gid_info->gl_iou != NULL && gid_info->gl_ngids == 0) {
   6093 		mutex_enter(&gid_info->gl_mutex);
   6094 		(void) ibdm_free_iou_info(gid_info, &gid_info->gl_iou);
   6095 		mutex_exit(&gid_info->gl_mutex);
   6096 	}
   6097 	if (gid_info->gl_prev != NULL)
   6098 		gid_info->gl_prev->gl_next = gid_info->gl_next;
   6099 	if (gid_info->gl_next != NULL)
   6100 		gid_info->gl_next->gl_prev = gid_info->gl_prev;
   6101 
   6102 	if (gid_info == ibdm.ibdm_dp_gidlist_head)
   6103 		ibdm.ibdm_dp_gidlist_head = gid_info->gl_next;
   6104 	if (gid_info == ibdm.ibdm_dp_gidlist_tail)
   6105 		ibdm.ibdm_dp_gidlist_tail = gid_info->gl_prev;
   6106 	ibdm.ibdm_ngids--;
   6107 
   6108 	ibdm.ibdm_busy &= ~IBDM_BUSY;
   6109 	cv_broadcast(&ibdm.ibdm_busy_cv);
   6110 	mutex_exit(&ibdm.ibdm_mutex);
   6111 
   6112 	/* free the hca_list on this gid_info */
   6113 	ibdm_delete_glhca_list(gid_info);
   6114 
   6115 	mutex_destroy(&gid_info->gl_mutex);
   6116 	kmem_free(gid_info, sizeof (ibdm_dp_gidinfo_t));
   6117 
   6118 	/*
   6119 	 * Pass on the IOCs with updated GIDs to IBnexus
   6120 	 */
   6121 	if (ioc_list) {
   6122 		IBTF_DPRINTF_L4("ibdm", "\tGID_UNAVAILABLE "
   6123 		    "IOC_PROP_UPDATE for %p\n", ioc_list);
   6124 		mutex_enter(&ibdm.ibdm_ibnex_mutex);
   6125 		if (ibdm.ibdm_ibnex_callback != NULL) {
   6126 			(*ibdm.ibdm_ibnex_callback)((void *)
   6127 			    ioc_list, IBDM_EVENT_IOC_PROP_UPDATE);
   6128 		}
   6129 		mutex_exit(&ibdm.ibdm_ibnex_mutex);
   6130 	}
   6131 
   6132 	ibdm_free_saa_event_arg(event_arg);
   6133 }
   6134 
   6135 
   6136 static int
   6137 ibdm_cmp_gid_list(ibdm_gid_t *new, ibdm_gid_t *prev)
   6138 {
   6139 	ibdm_gid_t		*scan_new, *scan_prev;
   6140 	int	cmp_failed = 0;
   6141 
   6142 	ASSERT(new != NULL);
   6143 	ASSERT(prev != NULL);
   6144 
   6145 	/*
   6146 	 * Search for each new gid anywhere in the prev GID list.
   6147 	 * Note that the gid list could have been re-ordered.
   6148 	 */
   6149 	for (scan_new = new; scan_new; scan_new = scan_new->gid_next) {
   6150 		for (scan_prev = prev, cmp_failed = 1; scan_prev;
   6151 		    scan_prev = scan_prev->gid_next) {
   6152 			if (scan_prev->gid_dgid_hi == scan_new->gid_dgid_hi &&
   6153 			    scan_prev->gid_dgid_lo == scan_new->gid_dgid_lo) {
   6154 				cmp_failed = 0;
   6155 				break;
   6156 			}
   6157 		}
   6158 
   6159 		if (cmp_failed)
   6160 			return (1);
   6161 	}
   6162 	return (0);
   6163 }
   6164 
   6165 /*
   6166  * This is always called in a single thread
   6167  * This function updates the gid_list and serv_list of IOC
   6168  * The current gid_list is in ioc_info_t(contains only port
   6169  * guids for which probe is done) & gidinfo_t(other port gids)
   6170  * The gids in both locations are used for comparision.
   6171  */
   6172 static void
   6173 ibdm_reprobe_update_port_srv(ibdm_ioc_info_t *ioc, ibdm_dp_gidinfo_t *gidinfo)
   6174 {
   6175 	ibdm_gid_t		*cur_gid_list;
   6176 	uint_t			cur_nportgids;
   6177 
   6178 	ASSERT(MUTEX_HELD(&ibdm.ibdm_mutex));
   6179 
   6180 	ioc->ioc_info_updated.ib_prop_updated = 0;
   6181 
   6182 
   6183 	/* Current GID list in gid_info only */
   6184 	cur_gid_list = gidinfo->gl_gid;
   6185 	cur_nportgids = gidinfo->gl_ngids;
   6186 
   6187 	if (ioc->ioc_prev_serv_cnt !=
   6188 	    ioc->ioc_profile.ioc_service_entries ||
   6189 	    ibdm_serv_cmp(&ioc->ioc_serv[0], &ioc->ioc_prev_serv[0],
   6190 	    ioc->ioc_prev_serv_cnt))
   6191 		ioc->ioc_info_updated.ib_srv_prop_updated = 1;
   6192 
   6193 	if (ioc->ioc_prev_nportgids != cur_nportgids ||
   6194 	    ioc->ioc_prev_gid_list == NULL || cur_gid_list == NULL) {
   6195 		ioc->ioc_info_updated.ib_gid_prop_updated = 1;
   6196 	} else if (ibdm_cmp_gid_list(ioc->ioc_prev_gid_list, cur_gid_list)) {
   6197 		ioc->ioc_info_updated.ib_gid_prop_updated = 1;
   6198 	}
   6199 
   6200 	/* Zero out previous entries */
   6201 	ibdm_free_gid_list(ioc->ioc_prev_gid_list);
   6202 	if (ioc->ioc_prev_serv)
   6203 		kmem_free(ioc->ioc_prev_serv, ioc->ioc_prev_serv_cnt *
   6204 		    sizeof (ibdm_srvents_info_t));
   6205 	ioc->ioc_prev_serv_cnt = 0;
   6206 	ioc->ioc_prev_nportgids = 0;
   6207 	ioc->ioc_prev_serv = NULL;
   6208 	ioc->ioc_prev_gid_list = NULL;
   6209 }
   6210 
   6211 /*
   6212  * Handle GID removal. This returns gid_info of an GID for the same
   6213  * node GUID, if found.  For an GID with IOU information, the same
   6214  * gid_info is returned if no gid_info with same node_guid is found.
   6215  */
   6216 static ibdm_dp_gidinfo_t *
   6217 ibdm_handle_gid_rm(ibdm_dp_gidinfo_t *rm_gid)
   6218 {
   6219 	ibdm_dp_gidinfo_t	*gid_list;
   6220 
   6221 	IBTF_DPRINTF_L4("ibdm", "\thandle_gid_rm(0x%p)", rm_gid);
   6222 
   6223 	if (rm_gid->gl_iou == NULL) {
   6224 		IBTF_DPRINTF_L4("ibdm", "\thandle_gid_rm NO iou");
   6225 		/*
   6226 		 * Search for a GID with same node_guid and
   6227 		 * gl_iou != NULL
   6228 		 */
   6229 		for (gid_list = ibdm.ibdm_dp_gidlist_head; gid_list;
   6230 		    gid_list = gid_list->gl_next) {
   6231 			if (gid_list->gl_iou != NULL && (gid_list->gl_nodeguid
   6232 			    == rm_gid->gl_nodeguid))
   6233 				break;
   6234 		}
   6235 
   6236 		if (gid_list)
   6237 			ibdm_rmfrom_glgid_list(gid_list, rm_gid);
   6238 
   6239 		IBTF_DPRINTF_L4("ibdm", "\thandle_gid_rm ret %p", gid_list);
   6240 		return (gid_list);
   6241 	} else {
   6242 		/*
   6243 		 * Search for a GID with same node_guid and
   6244 		 * gl_iou == NULL
   6245 		 */
   6246 		IBTF_DPRINTF_L4("ibdm", "\thandle_gid_rm with iou");
   6247 		for (gid_list = ibdm.ibdm_dp_gidlist_head; gid_list;
   6248 		    gid_list = gid_list->gl_next) {
   6249 			if (gid_list->gl_iou == NULL && (gid_list->gl_nodeguid
   6250 			    == rm_gid->gl_nodeguid))
   6251 				break;
   6252 		}
   6253 
   6254 		if (gid_list) {
   6255 			/*
   6256 			 * Copy the following fields from rm_gid :
   6257 			 *	1. gl_state
   6258 			 *	2. gl_iou
   6259 			 *	3. gl_gid & gl_ngids
   6260 			 *
   6261 			 * Note :	Function is synchronized by
   6262 			 *			ibdm_busy flag.
   6263 			 *
   6264 			 * Note :	Redirect info is initialized if
   6265 			 *			any MADs for the GID fail
   6266 			 */
   6267 			IBTF_DPRINTF_L4("ibdm", "\thandle_gid_rm "
   6268 			    "copying info to GID with gl_iou != NULl");
   6269 			gid_list->gl_state = rm_gid->gl_state;
   6270 			gid_list->gl_iou = rm_gid->gl_iou;
   6271 			gid_list->gl_gid = rm_gid->gl_gid;
   6272 			gid_list->gl_ngids = rm_gid->gl_ngids;
   6273 
   6274 			/* Remove the GID from gl_gid list */
   6275 			ibdm_rmfrom_glgid_list(gid_list, rm_gid);
   6276 		} else {
   6277 			/*
   6278 			 * Handle a case where all GIDs to the IOU have
   6279 			 * been removed.
   6280 			 */
   6281 			IBTF_DPRINTF_L4("ibdm", "\thandle_gid_rm 0 GID "
   6282 			    "to IOU");
   6283 
   6284 			ibdm_rmfrom_glgid_list(rm_gid, rm_gid);
   6285 			return (rm_gid);
   6286 		}
   6287 		IBTF_DPRINTF_L4("ibdm", "\thandle_gid_rm ret %p", gid_list);
   6288 		return (gid_list);
   6289 	}
   6290 }
   6291 
   6292 static void
   6293 ibdm_rmfrom_glgid_list(ibdm_dp_gidinfo_t *gid_info,
   6294     ibdm_dp_gidinfo_t *rm_gid)
   6295 {
   6296 	ibdm_gid_t 		*tmp, *prev;
   6297 
   6298 	IBTF_DPRINTF_L4("ibdm", "\trmfrom_glgid (%p, %p)",
   6299 	    gid_info, rm_gid);
   6300 
   6301 	for (tmp = gid_info->gl_gid, prev = NULL; tmp; ) {
   6302 		if (tmp->gid_dgid_hi == rm_gid->gl_dgid_hi &&
   6303 		    tmp->gid_dgid_lo == rm_gid->gl_dgid_lo) {
   6304 			if (prev == NULL)
   6305 				gid_info->gl_gid = tmp->gid_next;
   6306 			else
   6307 				prev->gid_next = tmp->gid_next;
   6308 
   6309 			kmem_free(tmp, sizeof (ibdm_gid_t));
   6310 			gid_info->gl_ngids--;
   6311 			break;
   6312 		} else {
   6313 			prev = tmp;
   6314 			tmp = tmp->gid_next;
   6315 		}
   6316 	}
   6317 }
   6318 
   6319 static void
   6320 ibdm_addto_gidlist(ibdm_gid_t **src_ptr, ibdm_gid_t *dest)
   6321 {
   6322 	ibdm_gid_t *head = NULL, *new, *tail;
   6323 
   6324 	/* First copy the destination */
   6325 	for (; dest; dest = dest->gid_next) {
   6326 		new = kmem_zalloc(sizeof (ibdm_gid_t), KM_SLEEP);
   6327 		new->gid_dgid_hi = dest->gid_dgid_hi;
   6328 		new->gid_dgid_lo = dest->gid_dgid_lo;
   6329 		new->gid_next = head;
   6330 		head = new;
   6331 	}
   6332 
   6333 	/* Insert this to the source */
   6334 	if (*src_ptr == NULL)
   6335 		*src_ptr = head;
   6336 	else {
   6337 		for (tail = *src_ptr; tail->gid_next != NULL;
   6338 		    tail = tail->gid_next)
   6339 			;
   6340 
   6341 		tail->gid_next = head;
   6342 	}
   6343 }
   6344 
   6345 static void
   6346 ibdm_free_gid_list(ibdm_gid_t	*head)
   6347 {
   6348 	ibdm_gid_t	*delete;
   6349 
   6350 	for (delete = head; delete; ) {
   6351 		head = delete->gid_next;
   6352 		kmem_free(delete, sizeof (ibdm_gid_t));
   6353 		delete = head;
   6354 	}
   6355 }
   6356 
   6357 /*
   6358  * This function rescans the DM capable GIDs (gl_state is
   6359  * GID_PROBE_COMPLETE or IBDM_GID_PROBING_SKIPPED.This
   6360  * basically checks if the DM capable GID is reachable. If
   6361  * not this is handled the same way as GID_UNAVAILABLE,
   6362  * except that notifications are not send to IBnexus.
   6363  *
   6364  * This function also initializes the ioc_prev_list for
   6365  * a particular IOC (when called from probe_ioc, with
   6366  * ioc_guidp != NULL) or all IOCs for the gid (called from
   6367  * sweep_fabric, ioc_guidp == NULL).
   6368  */
   6369 static void
   6370 ibdm_rescan_gidlist(ib_guid_t *ioc_guidp)
   6371 {
   6372 	ibdm_dp_gidinfo_t	*gid_info, *tmp;
   6373 	int ii, niocs, found;
   6374 	ibdm_hca_list_t *hca_list = NULL;
   6375 	ibdm_port_attr_t *port = NULL;
   6376 	ibdm_ioc_info_t *ioc_list;
   6377 
   6378 	for (gid_info = ibdm.ibdm_dp_gidlist_head; gid_info; ) {
   6379 		found = 0;
   6380 		if (gid_info->gl_state != IBDM_GID_PROBING_SKIPPED &&
   6381 		    gid_info->gl_state != IBDM_GID_PROBING_COMPLETE) {
   6382 			gid_info = gid_info->gl_next;
   6383 			continue;
   6384 		}
   6385 
   6386 		/*
   6387 		 * Check if the GID is visible to any HCA ports.
   6388 		 * Return if so.
   6389 		 */
   6390 		mutex_enter(&ibdm.ibdm_hl_mutex);
   6391 		for (ibdm_get_next_port(&hca_list, &port, 1); port;
   6392 		    ibdm_get_next_port(&hca_list, &port, 1)) {
   6393 			if (ibdm_port_reachable(port->pa_sa_hdl,
   6394 			    gid_info->gl_dgid_lo) == B_TRUE) {
   6395 				found = 1;
   6396 				break;
   6397 			}
   6398 		}
   6399 		mutex_exit(&ibdm.ibdm_hl_mutex);
   6400 
   6401 		if (found) {
   6402 			if (gid_info->gl_iou == NULL) {
   6403 				gid_info = gid_info->gl_next;
   6404 				continue;
   6405 			}
   6406 
   6407 			/* Intialize the ioc_prev_gid_list */
   6408 			niocs =
   6409 			    gid_info->gl_iou->iou_info.iou_num_ctrl_slots;
   6410 			for (ii = 0; ii < niocs; ii++) {
   6411 				ioc_list = IBDM_GIDINFO2IOCINFO(gid_info, ii);
   6412 
   6413 				if (ioc_guidp == NULL || (*ioc_guidp ==
   6414 				    ioc_list->ioc_profile.ioc_guid)) {
   6415 					/* Add info of GIDs in gid_info also */
   6416 					ibdm_addto_gidlist(
   6417 					    &ioc_list->ioc_prev_gid_list,
   6418 					    gid_info->gl_gid);
   6419 					ioc_list->ioc_prev_nportgids =
   6420 					    gid_info->gl_ngids;
   6421 				}
   6422 			}
   6423 			gid_info = gid_info->gl_next;
   6424 			continue;
   6425 		}
   6426 
   6427 		IBTF_DPRINTF_L4("ibdm", "\trescan_gidlist "
   6428 		    "deleted port GUID %llx",
   6429 		    gid_info->gl_dgid_lo);
   6430 
   6431 		/*
   6432 		 * Update GID list in all IOCs affected by this
   6433 		 */
   6434 		ioc_list = ibdm_update_ioc_gidlist(gid_info, 0);
   6435 
   6436 		/*
   6437 		 * Remove GID from the global GID list
   6438 		 * Handle the case where all port GIDs for an
   6439 		 * IOU have been hot-removed.
   6440 		 */
   6441 		mutex_enter(&ibdm.ibdm_mutex);
   6442 		if (gid_info->gl_iou != NULL && gid_info->gl_ngids == 0) {
   6443 			mutex_enter(&gid_info->gl_mutex);
   6444 			(void) ibdm_free_iou_info(gid_info, &gid_info->gl_iou);
   6445 			mutex_exit(&gid_info->gl_mutex);
   6446 		}
   6447 
   6448 		tmp = gid_info->gl_next;
   6449 		if (gid_info->gl_prev != NULL)
   6450 			gid_info->gl_prev->gl_next = gid_info->gl_next;
   6451 		if (gid_info->gl_next != NULL)
   6452 			gid_info->gl_next->gl_prev = gid_info->gl_prev;
   6453 
   6454 		if (gid_info == ibdm.ibdm_dp_gidlist_head)
   6455 			ibdm.ibdm_dp_gidlist_head = gid_info->gl_next;
   6456 		if (gid_info == ibdm.ibdm_dp_gidlist_tail)
   6457 			ibdm.ibdm_dp_gidlist_tail = gid_info->gl_prev;
   6458 		ibdm.ibdm_ngids--;
   6459 		mutex_exit(&ibdm.ibdm_mutex);
   6460 
   6461 		/* free the hca_list on this gid_info */
   6462 		ibdm_delete_glhca_list(gid_info);
   6463 
   6464 		mutex_destroy(&gid_info->gl_mutex);
   6465 		kmem_free(gid_info, sizeof (ibdm_dp_gidinfo_t));
   6466 
   6467 		gid_info = tmp;
   6468 
   6469 		/*
   6470 		 * Pass on the IOCs with updated GIDs to IBnexus
   6471 		 */
   6472 		if (ioc_list) {
   6473 			IBTF_DPRINTF_L4("ibdm", "\trescan_gidlist "
   6474 			    "IOC_PROP_UPDATE for %p\n", ioc_list);
   6475 			mutex_enter(&ibdm.ibdm_ibnex_mutex);
   6476 			if (ibdm.ibdm_ibnex_callback != NULL) {
   6477 				(*ibdm.ibdm_ibnex_callback)((void *)
   6478 				    ioc_list, IBDM_EVENT_IOC_PROP_UPDATE);
   6479 			}
   6480 			mutex_exit(&ibdm.ibdm_ibnex_mutex);
   6481 		}
   6482 	}
   6483 }
   6484 
   6485 /*
   6486  * This function notifies IBnex of IOCs on this GID.
   6487  * Notification is for GIDs with gl_reprobe_flag set.
   6488  * The flag is set when IOC probe / fabric sweep
   6489  * probes a GID starting from CLASS port info.
   6490  *
   6491  * IBnexus will have information of a reconnected IOC
   6492  * if it had probed it before. If this is a new IOC,
   6493  * IBnexus ignores the notification.
   6494  *
   6495  * This function should be called with no locks held.
   6496  */
   6497 static void
   6498 ibdm_notify_newgid_iocs(ibdm_dp_gidinfo_t *gid_info)
   6499 {
   6500 	ibdm_ioc_info_t	*ioc_list;
   6501 
   6502 	if (gid_info->gl_reprobe_flag == 0 ||
   6503 	    gid_info->gl_iou == NULL)
   6504 		return;
   6505 
   6506 	ioc_list = ibdm_update_ioc_gidlist(gid_info, -1);
   6507 
   6508 	/*
   6509 	 * Pass on the IOCs with updated GIDs to IBnexus
   6510 	 */
   6511 	if (ioc_list) {
   6512 		mutex_enter(&ibdm.ibdm_ibnex_mutex);
   6513 		if (ibdm.ibdm_ibnex_callback != NULL) {
   6514 			(*ibdm.ibdm_ibnex_callback)((void *)ioc_list,
   6515 			    IBDM_EVENT_IOC_PROP_UPDATE);
   6516 		}
   6517 		mutex_exit(&ibdm.ibdm_ibnex_mutex);
   6518 	}
   6519 }
   6520 
   6521 
   6522 static void
   6523 ibdm_free_saa_event_arg(ibdm_saa_event_arg_t *arg)
   6524 {
   6525 	if (arg != NULL)
   6526 		kmem_free(arg, sizeof (ibdm_saa_event_arg_t));
   6527 }
   6528 
   6529 /*
   6530  * This function parses the list of HCAs and HCA ports
   6531  * to return the port_attr of the next HCA port. A port
   6532  * connected to IB fabric (port_state active) is returned,
   6533  * if connected_flag is set.
   6534  */
   6535 static void
   6536 ibdm_get_next_port(ibdm_hca_list_t **inp_hcap,
   6537     ibdm_port_attr_t **inp_portp, int connect_flag)
   6538 {
   6539 	int ii;
   6540 	ibdm_port_attr_t *port, *next_port = NULL;
   6541 	ibdm_port_attr_t *inp_port;
   6542 	ibdm_hca_list_t	 *hca_list;
   6543 	int found = 0;
   6544 
   6545 	ASSERT(MUTEX_HELD(&ibdm.ibdm_hl_mutex));
   6546 	IBTF_DPRINTF_L4(ibdm_string, "\tget_next_port(%p, %p, %x)",
   6547 	    inp_hcap, inp_portp, connect_flag);
   6548 
   6549 	hca_list = *inp_hcap;
   6550 	inp_port = *inp_portp;
   6551 
   6552 	if (hca_list == NULL)
   6553 		hca_list = ibdm.ibdm_hca_list_head;
   6554 
   6555 	for (; hca_list; hca_list = hca_list->hl_next) {
   6556 		for (ii = 0; ii < hca_list->hl_nports; ii++) {
   6557 			port = &hca_list->hl_port_attr[ii];
   6558 
   6559 			/*
   6560 			 * inp_port != NULL;
   6561 			 * 	Skip till we find the matching port
   6562 			 */
   6563 			if (inp_port && !found) {
   6564 				if (inp_port == port)
   6565 					found = 1;
   6566 				continue;
   6567 			}
   6568 
   6569 			if (!connect_flag) {
   6570 				next_port = port;
   6571 				break;
   6572 			}
   6573 
   6574 			if (port->pa_sa_hdl == NULL)
   6575 				ibdm_initialize_port(port);
   6576 			if (port->pa_sa_hdl == NULL)
   6577 				(void) ibdm_fini_port(port);
   6578 			else if (next_port == NULL &&
   6579 			    port->pa_sa_hdl != NULL &&
   6580 			    port->pa_state == IBT_PORT_ACTIVE) {
   6581 				next_port = port;
   6582 				break;
   6583 			}
   6584 		}
   6585 
   6586 		if (next_port)
   6587 			break;
   6588 	}
   6589 
   6590 	IBTF_DPRINTF_L4(ibdm_string, "\tget_next_port : "
   6591 	    "returns hca_list %p port %p", hca_list, next_port);
   6592 	*inp_hcap = hca_list;
   6593 	*inp_portp = next_port;
   6594 }
   6595 
   6596 static void
   6597 ibdm_add_to_gl_gid(ibdm_dp_gidinfo_t *nodegid, ibdm_dp_gidinfo_t *addgid)
   6598 {
   6599 	ibdm_gid_t	*tmp;
   6600 
   6601 	tmp = kmem_zalloc(sizeof (ibdm_gid_t), KM_SLEEP);
   6602 	tmp->gid_dgid_hi = addgid->gl_dgid_hi;
   6603 	tmp->gid_dgid_lo = addgid->gl_dgid_lo;
   6604 
   6605 	mutex_enter(&nodegid->gl_mutex);
   6606 	tmp->gid_next = nodegid->gl_gid;
   6607 	nodegid->gl_gid = tmp;
   6608 	nodegid->gl_ngids++;
   6609 	mutex_exit(&nodegid->gl_mutex);
   6610 }
   6611 
   6612 static void
   6613 ibdm_addto_glhcalist(ibdm_dp_gidinfo_t *gid_info,
   6614     ibdm_hca_list_t *hca)
   6615 {
   6616 	ibdm_hca_list_t		*head, *prev = NULL, *temp;
   6617 
   6618 	IBTF_DPRINTF_L4(ibdm_string, "\taddto_glhcalist(%p, %p) "
   6619 	    ": gl_hca_list %p", gid_info, hca, gid_info->gl_hca_list);
   6620 	ASSERT(!MUTEX_HELD(&gid_info->gl_mutex));
   6621 
   6622 	mutex_enter(&gid_info->gl_mutex);
   6623 	head = gid_info->gl_hca_list;
   6624 	if (head == NULL) {
   6625 		head = ibdm_dup_hca_attr(hca);
   6626 		head->hl_next = NULL;
   6627 		gid_info->gl_hca_list = head;
   6628 		mutex_exit(&gid_info->gl_mutex);
   6629 		IBTF_DPRINTF_L4(ibdm_string, "\tadd_to_glhcalist: "
   6630 		    "gid %p, gl_hca_list %p", gid_info,
   6631 		    gid_info->gl_hca_list);
   6632 		return;
   6633 	}
   6634 
   6635 	/* Check if already in the list */
   6636 	while (head) {
   6637 		if (head->hl_hca_guid == hca->hl_hca_guid) {
   6638 			mutex_exit(&gid_info->gl_mutex);
   6639 			IBTF_DPRINTF_L4(ibdm_string,
   6640 			    "\taddto_glhcalist : gid %p hca %p dup",
   6641 			    gid_info, hca);
   6642 			return;
   6643 		}
   6644 		prev = head;
   6645 		head = head->hl_next;
   6646 	}
   6647 
   6648 	/* Add this HCA to gl_hca_list */
   6649 	temp =  ibdm_dup_hca_attr(hca);
   6650 	temp->hl_next = NULL;
   6651 	prev->hl_next = temp;
   6652 	mutex_exit(&gid_info->gl_mutex);
   6653 
   6654 	IBTF_DPRINTF_L4(ibdm_string, "\tadd_to_glhcalist: "
   6655 	    "gid %p, gl_hca_list %p", gid_info, gid_info->gl_hca_list);
   6656 }
   6657 
   6658 static void
   6659 ibdm_delete_glhca_list(ibdm_dp_gidinfo_t *gid_info)
   6660 {
   6661 	ASSERT(!MUTEX_HELD(&gid_info->gl_mutex));
   6662 	ASSERT(!MUTEX_HELD(&ibdm.ibdm_mutex));
   6663 
   6664 	mutex_enter(&gid_info->gl_mutex);
   6665 	if (gid_info->gl_hca_list)
   6666 		ibdm_ibnex_free_hca_list(gid_info->gl_hca_list);
   6667 	gid_info->gl_hca_list = NULL;
   6668 	mutex_exit(&gid_info->gl_mutex);
   6669 }
   6670 
   6671 
   6672 static void
   6673 ibdm_reset_all_dgids(ibmf_saa_handle_t port_sa_hdl)
   6674 {
   6675 	IBTF_DPRINTF_L4(ibdm_string, "\treset_all_dgids(%X)",
   6676 	    port_sa_hdl);
   6677 
   6678 	ASSERT(!MUTEX_HELD(&ibdm.ibdm_mutex));
   6679 	ASSERT(!MUTEX_HELD(&ibdm.ibdm_hl_mutex));
   6680 
   6681 	/* Check : Not busy in another probe / sweep */
   6682 	mutex_enter(&ibdm.ibdm_mutex);
   6683 	if ((ibdm.ibdm_busy & IBDM_BUSY) == 0) {
   6684 		ibdm_dp_gidinfo_t	*gid_info;
   6685 
   6686 		ibdm.ibdm_busy |= IBDM_BUSY;
   6687 		mutex_exit(&ibdm.ibdm_mutex);
   6688 
   6689 		/*
   6690 		 * Check if any GID is using the SA & IBMF handle
   6691 		 * of HCA port going down. Reset ibdm_dp_gidinfo_t
   6692 		 * using another HCA port which can reach the GID.
   6693 		 * This is for DM capable GIDs only, no need to do
   6694 		 * this for others
   6695 		 *
   6696 		 * Delete the GID if no alternate HCA port to reach
   6697 		 * it is found.
   6698 		 */
   6699 		for (gid_info = ibdm.ibdm_dp_gidlist_head; gid_info; ) {
   6700 			ibdm_dp_gidinfo_t *tmp;
   6701 
   6702 			IBTF_DPRINTF_L4(ibdm_string, "\tevent_hdlr "
   6703 			    "checking gidinfo %p", gid_info);
   6704 
   6705 			if (gid_info->gl_sa_hdl == port_sa_hdl) {
   6706 				IBTF_DPRINTF_L3(ibdm_string,
   6707 				    "\tevent_hdlr: down HCA port hdl "
   6708 				    "matches gid %p", gid_info);
   6709 
   6710 				/*
   6711 				 * The non-DM GIDs can come back
   6712 				 * with a new subnet prefix, when
   6713 				 * the HCA port commes up again. To
   6714 				 * avoid issues, delete non-DM
   6715 				 * capable GIDs, if the gid was
   6716 				 * discovered using the HCA port
   6717 				 * going down. This is ensured by
   6718 				 * setting gl_disconnected to 1.
   6719 				 */
   6720 				if (gid_info->gl_is_dm_capable == B_FALSE)
   6721 					gid_info->gl_disconnected = 1;
   6722 				else
   6723 					ibdm_reset_gidinfo(gid_info);
   6724 
   6725 				if (gid_info->gl_disconnected) {
   6726 					IBTF_DPRINTF_L3(ibdm_string,
   6727 					    "\tevent_hdlr: deleting"
   6728 					    " gid %p", gid_info);
   6729 					tmp = gid_info;
   6730 					gid_info = gid_info->gl_next;
   6731 					ibdm_delete_gidinfo(tmp);
   6732 				} else
   6733 					gid_info = gid_info->gl_next;
   6734 			} else
   6735 				gid_info = gid_info->gl_next;
   6736 		}
   6737 
   6738 		mutex_enter(&ibdm.ibdm_mutex);
   6739 		ibdm.ibdm_busy &= ~IBDM_BUSY;
   6740 		cv_signal(&ibdm.ibdm_busy_cv);
   6741 	}
   6742 	mutex_exit(&ibdm.ibdm_mutex);
   6743 }
   6744 
   6745 static void
   6746 ibdm_reset_gidinfo(ibdm_dp_gidinfo_t *gidinfo)
   6747 {
   6748 	ibdm_hca_list_t	*hca_list = NULL;
   6749 	ibdm_port_attr_t	*port = NULL;
   6750 	int	gid_reinited = 0;
   6751 	sa_node_record_t	*nr, *tmp;
   6752 	sa_portinfo_record_t	*pi;
   6753 	size_t	nr_len = 0, pi_len = 0;
   6754 	size_t	path_len;
   6755 	ib_gid_t	sgid, dgid;
   6756 	int	ret, ii, nrecords;
   6757 	sa_path_record_t	*path;
   6758 	uint8_t	npaths = 1;
   6759 	ibdm_pkey_tbl_t		*pkey_tbl;
   6760 
   6761 	IBTF_DPRINTF_L4(ibdm_string, "\treset_gidinfo(%p)", gidinfo);
   6762 
   6763 	/*
   6764 	 * Get list of all the ports reachable from the local known HCA
   6765 	 * ports which are active
   6766 	 */
   6767 	mutex_enter(&ibdm.ibdm_hl_mutex);
   6768 	for (ibdm_get_next_port(&hca_list, &port, 1); port;
   6769 	    ibdm_get_next_port(&hca_list, &port, 1)) {
   6770 
   6771 
   6772 		/*
   6773 		 * Get the path and re-populate the gidinfo.
   6774 		 * Getting the path is the same probe_ioc
   6775 		 * Init the gid info as in ibdm_create_gidinfo()
   6776 		 */
   6777 		nr = ibdm_get_node_records(port->pa_sa_hdl, &nr_len,
   6778 		    gidinfo->gl_nodeguid);
   6779 		if (nr == NULL) {
   6780 			IBTF_DPRINTF_L4(ibdm_string,
   6781 			    "\treset_gidinfo : no records");
   6782 			continue;
   6783 		}
   6784 
   6785 		nrecords = (nr_len / sizeof (sa_node_record_t));
   6786 		for (tmp = nr, ii = 0;  (ii < nrecords); ii++, tmp++) {
   6787 			if (tmp->NodeInfo.PortGUID == gidinfo->gl_portguid)
   6788 				break;
   6789 		}
   6790 
   6791 		if (ii == nrecords) {
   6792 			IBTF_DPRINTF_L4(ibdm_string,
   6793 			    "\treset_gidinfo : no record for portguid");
   6794 			kmem_free(nr, nr_len);
   6795 			continue;
   6796 		}
   6797 
   6798 		pi = ibdm_get_portinfo(port->pa_sa_hdl, &pi_len, tmp->LID);
   6799 		if (pi == NULL) {
   6800 			IBTF_DPRINTF_L4(ibdm_string,
   6801 			    "\treset_gidinfo : no portinfo");
   6802 			kmem_free(nr, nr_len);
   6803 			continue;
   6804 		}
   6805 
   6806 		sgid.gid_prefix = port->pa_sn_prefix;
   6807 		sgid.gid_guid = port->pa_port_guid;
   6808 		dgid.gid_prefix = pi->PortInfo.GidPrefix;
   6809 		dgid.gid_guid = tmp->NodeInfo.PortGUID;
   6810 
   6811 		ret = ibmf_saa_gid_to_pathrecords(port->pa_sa_hdl, sgid, dgid,
   6812 		    IBMF_SAA_PKEY_WC, 0, B_TRUE, &npaths, 0, &path_len, &path);
   6813 
   6814 		if ((ret != IBMF_SUCCESS) || path == NULL) {
   6815 			IBTF_DPRINTF_L4(ibdm_string,
   6816 			    "\treset_gidinfo : no paths");
   6817 			kmem_free(pi, pi_len);
   6818 			kmem_free(nr, nr_len);
   6819 			continue;
   6820 		}
   6821 
   6822 		gidinfo->gl_dgid_hi	= path->DGID.gid_prefix;
   6823 		gidinfo->gl_dgid_lo	= path->DGID.gid_guid;
   6824 		gidinfo->gl_sgid_hi	= path->SGID.gid_prefix;
   6825 		gidinfo->gl_sgid_lo	= path->SGID.gid_guid;
   6826 		gidinfo->gl_p_key	= path->P_Key;
   6827 		gidinfo->gl_sa_hdl	= port->pa_sa_hdl;
   6828 		gidinfo->gl_ibmf_hdl	= port->pa_ibmf_hdl;
   6829 		gidinfo->gl_slid	= path->SLID;
   6830 		gidinfo->gl_dlid	= path->DLID;
   6831 		/* Reset redirect info, next MAD will set if redirected */
   6832 		gidinfo->gl_redirected	= 0;
   6833 		gidinfo->gl_devid	= (*tmp).NodeInfo.DeviceID;
   6834 		gidinfo->gl_SL		= path->SL;
   6835 
   6836 		gidinfo->gl_qp_hdl = IBMF_QP_HANDLE_DEFAULT;
   6837 		for (ii = 0; ii < port->pa_npkeys; ii++) {
   6838 			if (port->pa_pkey_tbl == NULL)
   6839 				break;
   6840 
   6841 			pkey_tbl = &port->pa_pkey_tbl[ii];
   6842 			if ((gidinfo->gl_p_key == pkey_tbl->pt_pkey) &&
   6843 			    (pkey_tbl->pt_qp_hdl != NULL)) {
   6844 				gidinfo->gl_qp_hdl = pkey_tbl->pt_qp_hdl;
   6845 				break;
   6846 			}
   6847 		}
   6848 
   6849 		if (gidinfo->gl_qp_hdl == NULL)
   6850 			IBTF_DPRINTF_L2(ibdm_string,
   6851 			    "\treset_gid_info: No matching Pkey");
   6852 		else
   6853 			gid_reinited = 1;
   6854 
   6855 		kmem_free(path, path_len);
   6856 		kmem_free(pi, pi_len);
   6857 		kmem_free(nr, nr_len);
   6858 		break;
   6859 	}
   6860 	mutex_exit(&ibdm.ibdm_hl_mutex);
   6861 
   6862 	if (!gid_reinited)
   6863 		gidinfo->gl_disconnected = 1;
   6864 }
   6865 
   6866 static void
   6867 ibdm_delete_gidinfo(ibdm_dp_gidinfo_t *gidinfo)
   6868 {
   6869 	ibdm_ioc_info_t *ioc_list;
   6870 	int	in_gidlist = 0;
   6871 
   6872 	/*
   6873 	 * Check if gidinfo has been inserted into the
   6874 	 * ibdm_dp_gidlist_head list. gl_next or gl_prev
   6875 	 * != NULL, if gidinfo is the list.
   6876 	 */
   6877 	if (gidinfo->gl_prev != NULL ||
   6878 	    gidinfo->gl_next != NULL ||
   6879 	    ibdm.ibdm_dp_gidlist_head == gidinfo)
   6880 		in_gidlist = 1;
   6881 
   6882 	ioc_list = ibdm_update_ioc_gidlist(gidinfo, 0);
   6883 
   6884 	/*
   6885 	 * Remove GID from the global GID list
   6886 	 * Handle the case where all port GIDs for an
   6887 	 * IOU have been hot-removed.
   6888 	 */
   6889 	mutex_enter(&ibdm.ibdm_mutex);
   6890 	if (gidinfo->gl_iou != NULL && gidinfo->gl_ngids == 0) {
   6891 		mutex_enter(&gidinfo->gl_mutex);
   6892 		(void) ibdm_free_iou_info(gidinfo, &gidinfo->gl_iou);
   6893 		mutex_exit(&gidinfo->gl_mutex);
   6894 	}
   6895 
   6896 	/* Delete gl_hca_list */
   6897 	mutex_exit(&ibdm.ibdm_mutex);
   6898 	ibdm_delete_glhca_list(gidinfo);
   6899 	mutex_enter(&ibdm.ibdm_mutex);
   6900 
   6901 	if (in_gidlist) {
   6902 		if (gidinfo->gl_prev != NULL)
   6903 			gidinfo->gl_prev->gl_next = gidinfo->gl_next;
   6904 		if (gidinfo->gl_next != NULL)
   6905 			gidinfo->gl_next->gl_prev = gidinfo->gl_prev;
   6906 
   6907 		if (gidinfo == ibdm.ibdm_dp_gidlist_head)
   6908 			ibdm.ibdm_dp_gidlist_head = gidinfo->gl_next;
   6909 		if (gidinfo == ibdm.ibdm_dp_gidlist_tail)
   6910 			ibdm.ibdm_dp_gidlist_tail = gidinfo->gl_prev;
   6911 		ibdm.ibdm_ngids--;
   6912 	}
   6913 	mutex_exit(&ibdm.ibdm_mutex);
   6914 
   6915 	mutex_destroy(&gidinfo->gl_mutex);
   6916 	cv_destroy(&gidinfo->gl_probe_cv);
   6917 	kmem_free(gidinfo, sizeof (ibdm_dp_gidinfo_t));
   6918 
   6919 	/*
   6920 	 * Pass on the IOCs with updated GIDs to IBnexus
   6921 	 */
   6922 	if (ioc_list) {
   6923 		IBTF_DPRINTF_L4("ibdm", "\tdelete_gidinfo "
   6924 		    "IOC_PROP_UPDATE for %p\n", ioc_list);
   6925 		mutex_enter(&ibdm.ibdm_ibnex_mutex);
   6926 		if (ibdm.ibdm_ibnex_callback != NULL) {
   6927 			(*ibdm.ibdm_ibnex_callback)((void *)
   6928 			    ioc_list, IBDM_EVENT_IOC_PROP_UPDATE);
   6929 		}
   6930 		mutex_exit(&ibdm.ibdm_ibnex_mutex);
   6931 	}
   6932 }
   6933 
   6934 
   6935 static void
   6936 ibdm_fill_srv_attr_mod(ib_mad_hdr_t *hdr, ibdm_timeout_cb_args_t *cb_args)
   6937 {
   6938 	uint32_t	attr_mod;
   6939 
   6940 	attr_mod = (cb_args->cb_ioc_num + 1) << 16;
   6941 	attr_mod |= cb_args->cb_srvents_start;
   6942 	attr_mod |= (cb_args->cb_srvents_end) << 8;
   6943 	hdr->AttributeModifier = h2b32(attr_mod);
   6944 }
   6945 
   6946 static void
   6947 ibdm_bump_transactionID(ibdm_dp_gidinfo_t *gid_info)
   6948 {
   6949 	ASSERT(MUTEX_HELD(&gid_info->gl_mutex));
   6950 	gid_info->gl_transactionID++;
   6951 	if (gid_info->gl_transactionID == gid_info->gl_max_transactionID) {
   6952 		IBTF_DPRINTF_L4(ibdm_string,
   6953 		    "\tbump_transactionID(%p), wrapup", gid_info);
   6954 		gid_info->gl_transactionID = gid_info->gl_min_transactionID;
   6955 	}
   6956 }
   6957 
   6958 /*
   6959  * gl_prev_iou is set for *non-reprobe* sweeep requests, which
   6960  * detected that ChangeID in IOU info has changed. The service
   6961  * entry also may have changed. Check if service entry in IOC
   6962  * has changed wrt the prev iou, if so notify to IB Nexus.
   6963  */
   6964 static ibdm_ioc_info_t *
   6965 ibdm_handle_prev_iou()
   6966 {
   6967 	ibdm_dp_gidinfo_t *gid_info;
   6968 	ibdm_ioc_info_t	*ioc_list_head = NULL, *ioc_list;
   6969 	ibdm_ioc_info_t	*prev_ioc, *ioc;
   6970 	int		ii, jj, niocs, prev_niocs;
   6971 
   6972 	ASSERT(MUTEX_HELD(&ibdm.ibdm_mutex));
   6973 
   6974 	IBTF_DPRINTF_L4(ibdm_string, "\thandle_prev_iou enter");
   6975 	for (gid_info = ibdm.ibdm_dp_gidlist_head; gid_info;
   6976 	    gid_info = gid_info->gl_next) {
   6977 		if (gid_info->gl_prev_iou == NULL)
   6978 			continue;
   6979 
   6980 		IBTF_DPRINTF_L4(ibdm_string, "\thandle_prev_iou gid %p",
   6981 		    gid_info);
   6982 		niocs = gid_info->gl_iou->iou_info.iou_num_ctrl_slots;
   6983 		prev_niocs =
   6984 		    gid_info->gl_prev_iou->iou_info.iou_num_ctrl_slots;
   6985 		for (ii = 0; ii < niocs; ii++) {
   6986 			ioc = IBDM_GIDINFO2IOCINFO(gid_info, ii);
   6987 
   6988 			/* Find matching IOC */
   6989 			for (jj = 0; jj < prev_niocs; jj++) {
   6990 				prev_ioc = (ibdm_ioc_info_t *)
   6991 				    &gid_info->gl_prev_iou->iou_ioc_info[jj];
   6992 				if (prev_ioc->ioc_profile.ioc_guid ==
   6993 				    ioc->ioc_profile.ioc_guid)
   6994 					break;
   6995 			}
   6996 			if (jj == prev_niocs)
   6997 				prev_ioc = NULL;
   6998 			if (ioc == NULL || prev_ioc == NULL)
   6999 				continue;
   7000 			if ((ioc->ioc_profile.ioc_service_entries !=
   7001 			    prev_ioc->ioc_profile.ioc_service_entries) ||
   7002 			    ibdm_serv_cmp(&ioc->ioc_serv[0],
   7003 			    &prev_ioc->ioc_serv[0],
   7004 			    ioc->ioc_profile.ioc_service_entries) != 0) {
   7005 				IBTF_DPRINTF_L4(ibdm_string,
   7006 				    "/thandle_prev_iou modified IOC: "
   7007 				    "current ioc %p, old ioc %p",
   7008 				    ioc, prev_ioc);
   7009 				mutex_enter(&gid_info->gl_mutex);
   7010 				ioc_list = ibdm_dup_ioc_info(ioc, gid_info);
   7011 				mutex_exit(&gid_info->gl_mutex);
   7012 				ioc_list->ioc_info_updated.ib_prop_updated
   7013 				    = 0;
   7014 				ioc_list->ioc_info_updated.ib_srv_prop_updated
   7015 				    = 1;
   7016 
   7017 				if (ioc_list_head == NULL)
   7018 					ioc_list_head = ioc_list;
   7019 				else {
   7020 					ioc_list_head->ioc_next = ioc_list;
   7021 					ioc_list_head = ioc_list;
   7022 				}
   7023 			}
   7024 		}
   7025 
   7026 		mutex_enter(&gid_info->gl_mutex);
   7027 		(void) ibdm_free_iou_info(gid_info, &gid_info->gl_prev_iou);
   7028 		mutex_exit(&gid_info->gl_mutex);
   7029 	}
   7030 	IBTF_DPRINTF_L4(ibdm_string, "\thandle_prev_iouret %p",
   7031 	    ioc_list_head);
   7032 	return (ioc_list_head);
   7033 }
   7034 
   7035 /*
   7036  * Compares two service entries lists, returns 0 if same, returns 1
   7037  * if no match.
   7038  */
   7039 static int
   7040 ibdm_serv_cmp(ibdm_srvents_info_t *serv1, ibdm_srvents_info_t *serv2,
   7041     int nserv)
   7042 {
   7043 	int	ii;
   7044 
   7045 	IBTF_DPRINTF_L4(ibdm_string, "\tserv_cmp: enter");
   7046 	for (ii = 0; ii < nserv; ii++, serv1++, serv2++) {
   7047 		if (serv1->se_attr.srv_id != serv2->se_attr.srv_id ||
   7048 		    bcmp(serv1->se_attr.srv_name,
   7049 		    serv2->se_attr.srv_name,
   7050 		    IB_DM_MAX_SVC_NAME_LEN) != 0) {
   7051 			IBTF_DPRINTF_L4(ibdm_string, "\tserv_cmp: ret 1");
   7052 			return (1);
   7053 		}
   7054 	}
   7055 	IBTF_DPRINTF_L4(ibdm_string, "\tserv_cmp: ret 0");
   7056 	return (0);
   7057 }
   7058 
   7059 /* For debugging purpose only */
   7060 #ifdef	DEBUG
   7061 void
   7062 ibdm_dump_mad_hdr(ib_mad_hdr_t	*mad_hdr)
   7063 {
   7064 	IBTF_DPRINTF_L4("ibdm", "\t\t MAD Header info");
   7065 	IBTF_DPRINTF_L4("ibdm", "\t\t ---------------");
   7066 
   7067 	IBTF_DPRINTF_L4("ibdm", "\tBase version  : 0x%x"
   7068 	    "\tMgmt Class : 0x%x", mad_hdr->BaseVersion, mad_hdr->MgmtClass);
   7069 	IBTF_DPRINTF_L4("ibdm", "\tClass version : 0x%x"
   7070 	    "\tR Method           : 0x%x",
   7071 	    mad_hdr->ClassVersion, mad_hdr->R_Method);
   7072 	IBTF_DPRINTF_L4("ibdm", "\tMAD  Status   : 0x%x"
   7073 	    "\tTransaction ID     : 0x%llx",
   7074 	    b2h16(mad_hdr->Status), b2h64(mad_hdr->TransactionID));
   7075 	IBTF_DPRINTF_L4("ibdm", "\t Attribute ID  : 0x%x"
   7076 	    "\tAttribute Modified : 0x%lx",
   7077 	    b2h16(mad_hdr->AttributeID), b2h32(mad_hdr->AttributeModifier));
   7078 }
   7079 
   7080 
   7081 void
   7082 ibdm_dump_ibmf_msg(ibmf_msg_t *ibmf_msg, int flag)
   7083 {
   7084 	ib_mad_hdr_t	*mad_hdr;
   7085 
   7086 	IBTF_DPRINTF_L4("ibdm", "\t\t(IBMF_PKT): Local address info");
   7087 	IBTF_DPRINTF_L4("ibdm", "\t\t            ------------------");
   7088 
   7089 	IBTF_DPRINTF_L4("ibdm", "\tLocal Lid  : 0x%x\tRemote Lid : 0x%x"
   7090 	    " Remote Qp  : 0x%x", ibmf_msg->im_local_addr.ia_local_lid,
   7091 	    ibmf_msg->im_local_addr.ia_remote_lid,
   7092 	    ibmf_msg->im_local_addr.ia_remote_qno);
   7093 	IBTF_DPRINTF_L4("ibdm", "\tP_key      : 0x%x\tQ_key      : 0x%x"
   7094 	    " SL  : 0x%x", ibmf_msg->im_local_addr.ia_p_key,
   7095 	    ibmf_msg->im_local_addr.ia_q_key,
   7096 	    ibmf_msg->im_local_addr.ia_service_level);
   7097 
   7098 	if (flag)
   7099 		mad_hdr = (ib_mad_hdr_t *)IBDM_OUT_IBMFMSG_MADHDR(ibmf_msg);
   7100 	else
   7101 		mad_hdr = IBDM_IN_IBMFMSG_MADHDR(ibmf_msg);
   7102 
   7103 	ibdm_dump_mad_hdr(mad_hdr);
   7104 }
   7105 
   7106 
   7107 void
   7108 ibdm_dump_path_info(sa_path_record_t *path)
   7109 {
   7110 	IBTF_DPRINTF_L4("ibdm", "\t\t Path information");
   7111 	IBTF_DPRINTF_L4("ibdm", "\t\t ----------------");
   7112 
   7113 	IBTF_DPRINTF_L4("ibdm", "\t DGID hi  : %llx\tDGID lo  : %llx",
   7114 	    path->DGID.gid_prefix, path->DGID.gid_guid);
   7115 	IBTF_DPRINTF_L4("ibdm", "\t SGID hi  : %llx\tSGID lo  : %llx",
   7116 	    path->SGID.gid_prefix, path->SGID.gid_guid);
   7117 	IBTF_DPRINTF_L4("ibdm", "\t SLID     : %x\t\tDlID     : %x",
   7118 	    path->SLID, path->DLID);
   7119 	IBTF_DPRINTF_L4("ibdm", "\t P Key    : %x\t\tSL       : %x",
   7120 	    path->P_Key, path->SL);
   7121 }
   7122 
   7123 
   7124 void
   7125 ibdm_dump_classportinfo(ib_mad_classportinfo_t *classportinfo)
   7126 {
   7127 	IBTF_DPRINTF_L4("ibdm", "\t\t CLASSPORT INFO");
   7128 	IBTF_DPRINTF_L4("ibdm", "\t\t --------------");
   7129 
   7130 	IBTF_DPRINTF_L4("ibdm", "\t Response Time Value : 0x%x",
   7131 	    ((b2h32(classportinfo->RespTimeValue)) & 0x1F));
   7132 
   7133 	IBTF_DPRINTF_L4("ibdm", "\t Redirected GID hi   : 0x%llx",
   7134 	    b2h64(classportinfo->RedirectGID_hi));
   7135 	IBTF_DPRINTF_L4("ibdm", "\t Redirected GID lo   : 0x%llx",
   7136 	    b2h64(classportinfo->RedirectGID_lo));
   7137 	IBTF_DPRINTF_L4("ibdm", "\t Redirected TC       : 0x%x",
   7138 	    classportinfo->RedirectTC);
   7139 	IBTF_DPRINTF_L4("ibdm", "\t Redirected SL       : 0x%x",
   7140 	    classportinfo->RedirectSL);
   7141 	IBTF_DPRINTF_L4("ibdm", "\t Redirected FL       : 0x%x",
   7142 	    classportinfo->RedirectFL);
   7143 	IBTF_DPRINTF_L4("ibdm", "\t Redirected LID      : 0x%x",
   7144 	    b2h16(classportinfo->RedirectLID));
   7145 	IBTF_DPRINTF_L4("ibdm", "\t Redirected P KEY    : 0x%x",
   7146 	    b2h16(classportinfo->RedirectP_Key));
   7147 	IBTF_DPRINTF_L4("ibdm", "\t Redirected QP       : 0x%x",
   7148 	    classportinfo->RedirectQP);
   7149 	IBTF_DPRINTF_L4("ibdm", "\t Redirected Q KEY    : 0x%x",
   7150 	    b2h32(classportinfo->RedirectQ_Key));
   7151 	IBTF_DPRINTF_L4("ibdm", "\t Trap GID hi         : 0x%llx",
   7152 	    b2h64(classportinfo->TrapGID_hi));
   7153 	IBTF_DPRINTF_L4("ibdm", "\t Trap GID lo         : 0x%llx",
   7154 	    b2h64(classportinfo->TrapGID_lo));
   7155 	IBTF_DPRINTF_L4("ibdm", "\t Trap TC             : 0x%x",
   7156 	    classportinfo->TrapTC);
   7157 	IBTF_DPRINTF_L4("ibdm", "\t Trap SL             : 0x%x",
   7158 	    classportinfo->TrapSL);
   7159 	IBTF_DPRINTF_L4("ibdm", "\t Trap FL             : 0x%x",
   7160 	    classportinfo->TrapFL);
   7161 	IBTF_DPRINTF_L4("ibdm", "\t Trap LID            : 0x%x",
   7162 	    b2h16(classportinfo->TrapLID));
   7163 	IBTF_DPRINTF_L4("ibdm", "\t Trap P_Key          : 0x%x",
   7164 	    b2h16(classportinfo->TrapP_Key));
   7165 	IBTF_DPRINTF_L4("ibdm", "\t Trap HL             : 0x%x",
   7166 	    classportinfo->TrapHL);
   7167 	IBTF_DPRINTF_L4("ibdm", "\t Trap QP             : 0x%x",
   7168 	    classportinfo->TrapQP);
   7169 	IBTF_DPRINTF_L4("ibdm", "\t Trap Q_Key          : 0x%x",
   7170 	    b2h32(classportinfo->TrapQ_Key));
   7171 }
   7172 
   7173 
   7174 void
   7175 ibdm_dump_iounitinfo(ib_dm_io_unitinfo_t *iou_info)
   7176 {
   7177 	IBTF_DPRINTF_L4("ibdm", "\t\t I/O UnitInfo");
   7178 	IBTF_DPRINTF_L4("ibdm", "\t\t ------------");
   7179 
   7180 	IBTF_DPRINTF_L4("ibdm", "\tChange ID            : 0x%x",
   7181 	    b2h16(iou_info->iou_changeid));
   7182 	IBTF_DPRINTF_L4("ibdm", "\t#of ctrl slots       : %d",
   7183 	    iou_info->iou_num_ctrl_slots);
   7184 	IBTF_DPRINTF_L4("ibdm", "\tIOU flag             : 0x%x",
   7185 	    iou_info->iou_flag);
   7186 	IBTF_DPRINTF_L4("ibdm", "\tContrl list byte 0   : 0x%x",
   7187 	    iou_info->iou_ctrl_list[0]);
   7188 	IBTF_DPRINTF_L4("ibdm", "\tContrl list byte 1   : 0x%x",
   7189 	    iou_info->iou_ctrl_list[1]);
   7190 	IBTF_DPRINTF_L4("ibdm", "\tContrl list byte 2   : 0x%x",
   7191 	    iou_info->iou_ctrl_list[2]);
   7192 }
   7193 
   7194 
   7195 void
   7196 ibdm_dump_ioc_profile(ib_dm_ioc_ctrl_profile_t *ioc)
   7197 {
   7198 	IBTF_DPRINTF_L4("ibdm", "\t\t IOC Controller Profile");
   7199 	IBTF_DPRINTF_L4("ibdm", "\t\t ----------------------");
   7200 
   7201 	IBTF_DPRINTF_L4("ibdm", "\tIOC Guid    : %llx", ioc->ioc_guid);
   7202 	IBTF_DPRINTF_L4("ibdm", "\tVendorID    : 0x%x", ioc->ioc_vendorid);
   7203 	IBTF_DPRINTF_L4("ibdm", "\tDevice Id   : 0x%x", ioc->ioc_deviceid);
   7204 	IBTF_DPRINTF_L4("ibdm", "\tDevice Ver  : 0x%x", ioc->ioc_device_ver);
   7205 	IBTF_DPRINTF_L4("ibdm", "\tSubsys ID   : 0x%x", ioc->ioc_subsys_id);
   7206 	IBTF_DPRINTF_L4("ibdm", "\tIO class    : 0x%x", ioc->ioc_io_class);
   7207 	IBTF_DPRINTF_L4("ibdm", "\tIO subclass : 0x%x", ioc->ioc_io_subclass);
   7208 	IBTF_DPRINTF_L4("ibdm", "\tProtocol    : 0x%x", ioc->ioc_protocol);
   7209 	IBTF_DPRINTF_L4("ibdm", "\tProtocolV   : 0x%x", ioc->ioc_protocol_ver);
   7210 	IBTF_DPRINTF_L4("ibdm", "\tmsg qdepth  : %d", ioc->ioc_send_msg_qdepth);
   7211 	IBTF_DPRINTF_L4("ibdm", "\trdma qdepth : %d",
   7212 	    ioc->ioc_rdma_read_qdepth);
   7213 	IBTF_DPRINTF_L4("ibdm", "\tsndmsg sz   : %d", ioc->ioc_send_msg_sz);
   7214 	IBTF_DPRINTF_L4("ibdm", "\trdma xfersz : %d", ioc->ioc_rdma_xfer_sz);
   7215 	IBTF_DPRINTF_L4("ibdm", "\topcal mask  : 0x%x",
   7216 	    ioc->ioc_ctrl_opcap_mask);
   7217 	IBTF_DPRINTF_L4("ibdm", "\tsrventries  : %x", ioc->ioc_service_entries);
   7218 }
   7219 
   7220 
   7221 void
   7222 ibdm_dump_service_entries(ib_dm_srv_t *srv_ents)
   7223 {
   7224 	IBTF_DPRINTF_L4("ibdm",
   7225 	    "\thandle_srventry_mad: service id : %llx", srv_ents->srv_id);
   7226 
   7227 	IBTF_DPRINTF_L4("ibdm", "\thandle_srventry_mad: "
   7228 	    "Service Name : %s", srv_ents->srv_name);
   7229 }
   7230 
   7231 int ibdm_allow_sweep_fabric_timestamp = 1;
   7232 
   7233 void
   7234 ibdm_dump_sweep_fabric_timestamp(int flag)
   7235 {
   7236 	static hrtime_t x;
   7237 	if (flag) {
   7238 		if (ibdm_allow_sweep_fabric_timestamp) {
   7239 			IBTF_DPRINTF_L4("ibdm", "\tTime taken to complete "
   7240 			    "sweep %lld ms", ((gethrtime() - x)/ 1000000));
   7241 		}
   7242 		x = 0;
   7243 	} else
   7244 		x = gethrtime();
   7245 }
   7246 #endif
   7247