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 == NULL)
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) == 0) {
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) == NULL) {
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) == NULL) {
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