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