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