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