1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 /* 26 * Copyright 2023 Oxide Computer Company 27 */ 28 29 /* 30 * This file contains support required for IB cfgadm plugin. 31 */ 32 33 #include <sys/conf.h> 34 #include <sys/stat.h> 35 #include <sys/modctl.h> 36 #include <sys/ib/mgt/ibdm/ibdm_impl.h> 37 #include <sys/ib/ibnex/ibnex.h> 38 #include <sys/ib/ibnex/ibnex_devctl.h> 39 #include <sys/ib/ibtl/impl/ibtl_ibnex.h> 40 #include <sys/ib/ibtl/impl/ibtl.h> 41 #include <sys/file.h> 42 #include <sys/sunndi.h> 43 #include <sys/fs/dv_node.h> 44 #include <sys/mdi_impldefs.h> 45 #include <sys/sunmdi.h> 46 47 /* return the minimum value of (x) and (y) */ 48 #define MIN(x, y) ((x) < (y) ? (x) : (y)) 49 50 /* 51 * function prototypes 52 */ 53 int ibnex_open(dev_t *, int, int, cred_t *); 54 int ibnex_close(dev_t, int, int, cred_t *); 55 int ibnex_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 56 int ibnex_offline_childdip(dev_info_t *); 57 static int ibnex_get_num_devices(void); 58 static int ibnex_get_snapshot(char **, size_t *, int); 59 static int ibnex_get_commsvcnode_snapshot(nvlist_t **, ib_guid_t, 60 ib_guid_t, int, ib_pkey_t, ibnex_node_type_t); 61 static int ibnex_fill_ioc_tmp(nvlist_t **, ibdm_ioc_info_t *); 62 static int ibnex_fill_nodeinfo(nvlist_t **, ibnex_node_data_t *, 63 void *); 64 static void ibnex_figure_ap_devstate(ibnex_node_data_t *, 65 devctl_ap_state_t *); 66 static void ibnex_figure_ib_apid_devstate(devctl_ap_state_t *); 67 static char *ibnex_get_apid(struct devctl_iocdata *); 68 static int ibnex_get_dip_from_apid(char *, dev_info_t **, 69 ibnex_node_data_t **); 70 extern int ibnex_get_node_and_dip_from_guid(ib_guid_t, int, 71 ib_pkey_t, ibnex_node_data_t **, dev_info_t **); 72 static ibnex_rval_t ibnex_handle_pseudo_configure(char *); 73 static ibnex_rval_t ibnex_handle_ioc_configure(char *); 74 static ibnex_rval_t ibnex_handle_commsvcnode_configure(char *); 75 static void ibnex_return_apid(dev_info_t *, char **); 76 static void ibnex_port_conf_entry_add(char *); 77 static void ibnex_vppa_conf_entry_add(char *); 78 static void ibnex_hcasvc_conf_entry_add(char *); 79 static int ibnex_port_conf_entry_delete(char *, char *); 80 static int ibnex_vppa_conf_entry_delete(char *, char *); 81 static int ibnex_hcasvc_conf_entry_delete(char *, char *); 82 83 static ibnex_rval_t ibnex_ioc_fininode(dev_info_t *, ibnex_ioc_node_t *); 84 static ibnex_rval_t ibnex_commsvc_fininode(dev_info_t *); 85 static ibnex_rval_t ibnex_pseudo_fininode(dev_info_t *); 86 87 static int ibnex_devctl(dev_t, int, intptr_t, int, 88 cred_t *, int *); 89 static int ibnex_ctl_get_api_ver(dev_t, int, intptr_t, int, 90 cred_t *, int *); 91 static int ibnex_ctl_get_hca_list(dev_t, int, intptr_t, int, 92 cred_t *, int *); 93 static int ibnex_ctl_query_hca(dev_t, int, intptr_t, int, 94 cred_t *, int *); 95 static int ibnex_ctl_query_hca_port(dev_t, int, intptr_t, int, 96 cred_t *, int *); 97 98 extern uint64_t ibnex_str2hex(char *, int, int *); 99 extern int ibnex_ioc_initnode_all_pi(ibdm_ioc_info_t *); 100 extern dev_info_t *ibnex_commsvc_initnode(dev_info_t *, 101 ibdm_port_attr_t *, int, int, ib_pkey_t, int *, 102 int); 103 extern int ibnex_get_dip_from_guid(ib_guid_t, int, 104 ib_pkey_t, dev_info_t **); 105 extern void ibnex_reprobe_ioc_dev(void *arg); 106 extern void ibnex_reprobe_ioc_all(); 107 extern int ibnex_pseudo_create_all_pi(ibnex_node_data_t *); 108 extern void ibnex_pseudo_initnodes(void); 109 110 extern ibnex_t ibnex; 111 112 /* 113 * ibnex_open() 114 */ 115 /* ARGSUSED */ 116 int 117 ibnex_open(dev_t *dev, int flag, int otyp, cred_t *credp) 118 { 119 IBTF_DPRINTF_L4("ibnex", "\topen"); 120 return (0); 121 } 122 123 124 /* 125 * ibnex_close() 126 */ 127 /* ARGSUSED */ 128 int 129 ibnex_close(dev_t dev, int flag, int otyp, cred_t *credp) 130 { 131 IBTF_DPRINTF_L4("ibnex", "\tclose"); 132 return (0); 133 } 134 135 int 136 ibnex_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 137 int *rvalp) 138 { 139 /* 140 * For all generic devctl ioctls (such as DEVCTL_AP_CONFIGURE), 141 * call ibnex_devctl(). 142 */ 143 if (IS_DEVCTL(cmd)) 144 return (ibnex_devctl(dev, cmd, arg, mode, credp, rvalp)); 145 146 /* 147 * The rest are ibnex specific ioctls. 148 */ 149 150 switch (cmd) { 151 case IBNEX_CTL_GET_API_VER: 152 return (ibnex_ctl_get_api_ver(dev, cmd, arg, mode, 153 credp, rvalp)); 154 155 case IBNEX_CTL_GET_HCA_LIST: 156 return (ibnex_ctl_get_hca_list(dev, cmd, arg, mode, 157 credp, rvalp)); 158 159 case IBNEX_CTL_QUERY_HCA: 160 return (ibnex_ctl_query_hca(dev, cmd, arg, mode, 161 credp, rvalp)); 162 163 case IBNEX_CTL_QUERY_HCA_PORT: 164 return (ibnex_ctl_query_hca_port(dev, cmd, arg, mode, 165 credp, rvalp)); 166 167 default: 168 return (EINVAL); 169 } 170 } 171 172 /* 173 * ibnex_ioctl() 174 * Ioctl routine for cfgadm controls 175 * DEVCTL_AP_GETSTATE: returns attachment point state 176 * DEVCTL_AP_CONTROL: Does "ibnex" specific ioctls listed below 177 * IBNEX_NUM_DEVICE_NODES Gives how many device nodes exist? 178 * IBNEX_NUM_HCA_NODES Gives how many HCAs exist in the fabric 179 * IBNEX_UPDATE_PKEY_TBLS "-x update_pkey_tbls" 180 * IBNEX_GET_SNAPSHOT Gets the "snapshot" back to user-land 181 * IBNEX_SNAPSHOT_SIZE What is "snapshot" size 182 * IBNEX_DEVICE_PATH_SZ What is device-path size 183 * IBNEX_GET_DEVICE_PATH Gets the device path for Dynamic ap 184 * IBNEX_HCA_LIST_SZ "-x list" option size for the HCA ap_id 185 * IBNEX_HCA_LIST_INFO "-x list" option info for the HCA ap_id 186 * IBNEX_UNCFG_CLNTS_SZ "-x unconfig_client option size" 187 * IBNEX_UNCFG_CLNTS_INFO "-x unconfig_client data" 188 * IBNEX_CONF_ENTRY_ADD: "-x add_service" 189 * IBNEX_CONF_ENTRY_DEL: "-x delete_service" 190 * IBNEX_HCA_VERBOSE_SZ: "-alv hca_apid data size" 191 * IBNEX_HCA_VERBOSE_INFO: "-alv hca_apid actual data" 192 * IBNEX_UPDATE_IOC_CONF "-x update_ioc_conf" 193 * DEVCTL_AP_CONFIGURE: "configure" the attachment point 194 * DEVCTL_AP_UNCONFIGURE: "unconfigure" the attachment point 195 */ 196 /* ARGSUSED */ 197 static int 198 ibnex_devctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 199 int *rvalp) 200 { 201 int ret, rv = 0, ioc_reprobe_pending = 0; 202 char *snapshot = NULL; 203 char *apid_n = NULL; 204 char *service = NULL; 205 char *devnm = NULL; 206 char *msg; 207 char *guid_str; 208 uint_t num_hcas = 0; 209 size_t snapshot_sz = 0; 210 uint32_t ssiz; 211 uint32_t apid_len; 212 ib_guid_t hca_guid; 213 boolean_t apid_alloced = B_FALSE; 214 dev_info_t *apid_dip = NULL; 215 dev_info_t *pdip; 216 ibnex_rval_t ret_val; 217 ib_service_type_t svc_type = IB_NONE; 218 devctl_ap_state_t ap_state; 219 ibnex_node_data_t *nodep = NULL; 220 ibnex_node_data_t *scanp; 221 struct devctl_iocdata *dcp = NULL; 222 223 IBTF_DPRINTF_L4("ibnex", "\tdevctl: cmd=%x, arg=%p, mode=%x, cred=%p, " 224 "\t\trval=%p dev=0x%x", cmd, arg, mode, credp, rvalp, dev); 225 226 /* read devctl ioctl data */ 227 if ((cmd != DEVCTL_AP_CONTROL) && 228 (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)) { 229 IBTF_DPRINTF_L4("ibnex", 230 "\tdevctl: ndi_dc_allochdl failed\n"); 231 return (EFAULT); 232 } 233 234 mutex_enter(&ibnex.ibnex_mutex); 235 switch (cmd) { 236 case DEVCTL_AP_GETSTATE: 237 msg = "\tdevctl: DEVCTL_AP_GETSTATE"; 238 IBTF_DPRINTF_L4("ibnex", "%s:", msg); 239 240 apid_n = ibnex_get_apid(dcp); 241 if (*apid_n == '\0') { 242 IBTF_DPRINTF_L2("ibnex", 243 "%s: ibnex_get_apid failed", msg); 244 rv = EIO; 245 break; 246 } 247 248 if (strncmp(apid_n, IBNEX_FABRIC, strlen(IBNEX_FABRIC)) == 0) { 249 ibnex_figure_ib_apid_devstate(&ap_state); 250 apid_dip = ibnex.ibnex_dip; 251 } else { 252 /* if this apid is already seen by IBNEX, get the dip */ 253 rv = ibnex_get_dip_from_apid(apid_n, &apid_dip, &nodep); 254 if (rv != IBNEX_DYN_APID) { 255 IBTF_DPRINTF_L2("ibnex", 256 "%s: ibnex_get_dip_from_apid failed", msg); 257 rv = EIO; 258 break; 259 } 260 if (apid_dip) 261 ndi_rele_devi(apid_dip); 262 /* rv could be something undesirable, so reset it */ 263 rv = 0; 264 265 ibnex_figure_ap_devstate(nodep, &ap_state); 266 } 267 268 /* copy the return-AP-state information to the user space */ 269 if (ndi_dc_return_ap_state(&ap_state, dcp) != NDI_SUCCESS) { 270 IBTF_DPRINTF_L2("ibnex", 271 "%s: ndi_dc_return_ap_state failed", msg); 272 rv = EFAULT; 273 } 274 break; 275 276 case DEVCTL_AP_CONTROL: 277 { 278 int num_nodes = 0; 279 ibnex_ioctl_data_t ioc; /* for 64-bit copies only */ 280 281 msg = "\tdevctl: DEVCTL_AP_CONTROL"; 282 #ifdef _MULTI_DATAMODEL 283 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 284 ibnex_ioctl_data_32_t ioc32; 285 286 if (ddi_copyin((void *)arg, &ioc32, 287 sizeof (ioc32), mode) != 0) { 288 IBTF_DPRINTF_L2("ibnex", 289 "%s: ddi_copyin err 1", msg); 290 rv = EFAULT; 291 break; 292 } 293 ioc.cmd = (uint_t)ioc32.cmd; 294 ioc.buf = (caddr_t)(uintptr_t)ioc32.buf; 295 ioc.bufsiz = (uint_t)ioc32.bufsiz; 296 ioc.ap_id = (caddr_t)(uintptr_t)ioc32.ap_id; 297 ioc.ap_id_len = (uint_t)ioc32.ap_id_len; 298 ioc.misc_arg = (uint_t)ioc32.misc_arg; 299 } 300 #else 301 if (ddi_copyin((void *)arg, &ioc, sizeof (ioc), 302 mode) != 0) { 303 IBTF_DPRINTF_L2("ibnex", 304 "%s: ddi_copyin 2 failed", msg); 305 rv = EFAULT; 306 break; 307 } 308 #endif /* _MULTI_DATAMODEL */ 309 310 IBTF_DPRINTF_L4("ibnex", "%s: \n\tioc: cmd=%x buf=%p, " 311 "bufsiz=%d", msg, ioc.cmd, ioc.buf, ioc.bufsiz); 312 313 /* 314 * figure out ap_id name as passed from user-land 315 * NOTE: We don't need to figure out ap_id for these 316 * two sub-commands:- 317 * IBNEX_NUM_DEVICE_NODES, IBNEX_NUM_HCA_NODES 318 * 319 * Hence, In user-land, these two ioctls force "ap_id_len" to 0. 320 */ 321 if (ioc.ap_id_len > 0) { 322 apid_alloced = B_TRUE; 323 apid_len = ioc.ap_id_len + 1; 324 apid_n = kmem_zalloc(apid_len, KM_SLEEP); 325 if (ddi_copyin((void *)ioc.ap_id, apid_n, 326 ioc.ap_id_len, mode) != 0) { 327 IBTF_DPRINTF_L2("ibnex", 328 "%s: ddi_copyin err 3", msg); 329 rv = EFAULT; 330 break; 331 } 332 333 IBTF_DPRINTF_L3("ibnex", "%s: apid_n= %s", msg, apid_n); 334 } 335 336 337 /* process sub-commands */ 338 switch (ioc.cmd) { 339 case IBNEX_NUM_DEVICE_NODES: 340 msg = "\tdevctl: DEVCTL_AP_CONTROL: NUM_DEVICE_NODES"; 341 342 /* 343 * figure out how many IOC, VPPA, 344 * Pseudo and Port nodes are present 345 */ 346 num_nodes = ibnex_get_num_devices(); 347 IBTF_DPRINTF_L4("ibnex", "%s: num_nodes = %d", 348 msg, num_nodes); 349 350 if (ddi_copyout(&num_nodes, ioc.buf, 351 ioc.bufsiz, mode) != 0) { 352 IBTF_DPRINTF_L2("ibnex", "%s: copyout", msg); 353 rv = EIO; 354 } 355 mutex_exit(&ibnex.ibnex_mutex); 356 return (rv); 357 358 case IBNEX_NUM_HCA_NODES: 359 msg = "\tdevctl: DEVCTL_AP_CONTROL: NUM_HCA_NODES"; 360 361 /* figure out how many HCAs are present in the host */ 362 mutex_exit(&ibnex.ibnex_mutex); 363 num_hcas = ibt_get_hca_list(NULL); 364 IBTF_DPRINTF_L4("ibnex", "%s: num %d", msg, num_hcas); 365 366 if (ddi_copyout(&num_hcas, ioc.buf, 367 ioc.bufsiz, mode) != 0) { 368 IBTF_DPRINTF_L2("ibnex", "%s: copyout", msg); 369 rv = EIO; 370 } 371 return (rv); 372 373 case IBNEX_UPDATE_PKEY_TBLS: 374 msg = "\tdevctl: DEVCTL_AP_CONTROL: UPDATE_PKEY_TBLS"; 375 IBTF_DPRINTF_L4("ibnex", "%s", msg); 376 377 /* 378 * update P_Key tables: 379 * ibdm_ibnex_update_pkey_tbls() calls 380 * ibt_query_hca_ports_byguids() for all the 381 * HCAs that the IBDM has "seen" in the system. 382 * This ends up updating the IBTL P_Key database. 383 * NOTE: Changes in this area will break this 384 * assumption. Initially the plan was to call 385 * ibt_query_hca_ports_byguids() in IBTL but 386 * IBDM needs to call it as well. So, eliminating 387 * the first invocation. 388 * 389 * It next updates the DM P_Key database. 390 * Note that the DM P_Key database updating 391 * will always be driven through cfgadm. 392 */ 393 mutex_exit(&ibnex.ibnex_mutex); 394 ibdm_ibnex_update_pkey_tbls(); 395 mutex_enter(&ibnex.ibnex_mutex); 396 break; 397 398 case IBNEX_GET_SNAPSHOT: 399 case IBNEX_SNAPSHOT_SIZE: 400 msg = (ioc.cmd == IBNEX_SNAPSHOT_SIZE) ? 401 "\tdevctl: DEVCTL_AP_CONTROL: IBNEX_SNAPSHOT_SIZE" : 402 "\tdevctl: DEVCTL_AP_CONTROL: IBNEX_GET_SNAPSHOT"; 403 404 IBTF_DPRINTF_L4("ibnex", "%s:", msg); 405 406 if (ibnex_get_snapshot(&snapshot, &snapshot_sz, 407 ioc.misc_arg) != 0) { 408 IBTF_DPRINTF_L2("ibnex", 409 "%s:\n\tibnex_get_snapshot failed", msg); 410 rv = EIO; 411 break; 412 } 413 414 /* ssiz needs to be reinitialized again */ 415 ssiz = snapshot_sz; 416 IBTF_DPRINTF_L4("ibnex", 417 "%s:\n\tsize =%x", msg, snapshot_sz); 418 419 if (ioc.cmd == IBNEX_SNAPSHOT_SIZE) { 420 if (ddi_copyout(&ssiz, ioc.buf, 421 ioc.bufsiz, mode) != 0) { 422 IBTF_DPRINTF_L2("ibnex", 423 "%s:\n\tddi_copyout 2 failed", msg); 424 rv = EFAULT; 425 } 426 427 } else { 428 if (ioc.bufsiz != snapshot_sz) { 429 IBTF_DPRINTF_L2("ibnex", 430 "%s:\n\tinvalid buffer size (%x %x)" 431 " ", msg, ioc.bufsiz, snapshot_sz); 432 rv = EINVAL; 433 434 } else if (ddi_copyout(snapshot, ioc.buf, 435 ioc.bufsiz, mode) != 0) { 436 IBTF_DPRINTF_L2("ibnex", 437 "%s:\n\tddi_copyout 3 failed", msg); 438 rv = EFAULT; 439 } 440 } 441 442 kmem_free(snapshot, snapshot_sz); 443 break; 444 445 case IBNEX_DEVICE_PATH_SZ: 446 case IBNEX_GET_DEVICE_PATH: 447 { 448 char path[MAXPATHLEN]; 449 450 msg = (ioc.cmd == IBNEX_DEVICE_PATH_SZ) ? 451 "\tdevctl:DEVCTL_AP_CONTROL: IBNEX_DEVICE_PATH_SZ" : 452 "\tdevctl:DEVCTL_AP_CONTROL: IBNEX_GET_DEVICE_PATH"; 453 454 IBTF_DPRINTF_L4("ibnex", "%s: apid = %s", msg, apid_n); 455 456 /* if this apid is already seen by IBNEX, get the dip */ 457 rv = ibnex_get_dip_from_apid(apid_n, &apid_dip, &nodep); 458 if (rv != IBNEX_DYN_APID || apid_dip == NULL) { 459 IBTF_DPRINTF_L2("ibnex", 460 "%s:\n\tget_dip_from_apid failed", msg); 461 rv = EIO; 462 break; 463 } 464 ndi_rele_devi(apid_dip); 465 466 /* ddi_pathname doesn't supply /devices, so we do. */ 467 (void) strcpy(path, "/devices"); 468 (void) ddi_pathname(apid_dip, path + strlen(path)); 469 ssiz = (uint32_t)strlen(path) + 1; 470 IBTF_DPRINTF_L4("ibnex", 471 "%s: len = %x\n\tpath = %s", msg, ssiz, path); 472 473 /* rv could be something undesirable, so reset it */ 474 rv = 0; 475 476 if (ioc.cmd == IBNEX_DEVICE_PATH_SZ) { 477 if (ddi_copyout(&ssiz, ioc.buf, 478 ioc.bufsiz, mode) != 0) { 479 IBTF_DPRINTF_L2("ibnex", 480 "%s: ddi_copyout 4 failed", msg); 481 rv = EFAULT; 482 } 483 484 } else { 485 if (ioc.bufsiz != ssiz) { 486 IBTF_DPRINTF_L2("ibnex", 487 "%s: invalid size (%x, %x)", 488 msg, ioc.bufsiz, ssiz); 489 rv = EINVAL; 490 } else if (ddi_copyout(&path, ioc.buf, 491 ioc.bufsiz, mode) != 0) { 492 IBTF_DPRINTF_L2("ibnex", "%s " 493 "ddi_copyout 5 failed", msg); 494 rv = EFAULT; 495 } 496 } 497 break; 498 } 499 500 case IBNEX_HCA_LIST_SZ: 501 case IBNEX_HCA_LIST_INFO: 502 msg = (ioc.cmd == IBNEX_HCA_LIST_SZ) ? 503 "DEVCTL_AP_CONTROL: IBNEX_HCA_LIST_SZ" : 504 "DEVCTL_AP_CONTROL: IBNEX_HCA_LIST_INFO"; 505 506 guid_str = strrchr(apid_n, ':') + 1; 507 IBTF_DPRINTF_L4("ibnex", "%s, input apid = %s, " 508 "guid = %s", msg, apid_n, guid_str); 509 510 if (guid_str == NULL) { 511 IBTF_DPRINTF_L2("ibnex", "%s: invalid input " 512 "GUID passed %s", msg, guid_str); 513 rv = EFAULT; 514 break; 515 } 516 517 /* Get the GUID(hex value) from apid_n */ 518 hca_guid = ibnex_str2hex(guid_str, strlen(guid_str), 519 &ret); 520 if (ret != IBNEX_SUCCESS) { 521 IBTF_DPRINTF_L2("ibnex", "%s: Invalid HCA " 522 "GUID string", msg); 523 rv = EIO; 524 break; 525 } 526 IBTF_DPRINTF_L4("ibnex", "%s HCA GUID = %llX", 527 msg, hca_guid); 528 if (ibtl_ibnex_get_hca_info(hca_guid, 529 IBTL_IBNEX_LIST_CLNTS_FLAG, &snapshot, &snapshot_sz, 530 ibnex_return_apid) != IBT_SUCCESS) { 531 IBTF_DPRINTF_L2("ibnex", 532 "%s: get HCA consumers failed", msg); 533 rv = EIO; 534 break; 535 } 536 537 ssiz = snapshot_sz; 538 IBTF_DPRINTF_L4("ibnex", "%s: size =%x", msg, ssiz); 539 540 if (ioc.cmd == IBNEX_HCA_LIST_SZ) { 541 if (ddi_copyout(&ssiz, ioc.buf, 542 ioc.bufsiz, mode) != 0) { 543 IBTF_DPRINTF_L2("ibnex", 544 "%s: ddi_copyout 6 failed", msg); 545 rv = EFAULT; 546 } 547 } else { 548 if (ioc.bufsiz != ssiz) { 549 IBTF_DPRINTF_L2("ibnex", "%s: invalid " 550 "size (%x, %x)", msg, ioc.bufsiz, 551 ssiz); 552 rv = EINVAL; 553 } else if (ddi_copyout(snapshot, ioc.buf, 554 ioc.bufsiz, mode) != 0) { 555 IBTF_DPRINTF_L2("ibnex", "%s " 556 "ddi_copyout 7 failed", msg); 557 rv = EFAULT; 558 } 559 } 560 561 kmem_free(snapshot, snapshot_sz); 562 break; 563 564 case IBNEX_UNCFG_CLNTS_SZ: 565 case IBNEX_UNCFG_CLNTS_INFO: 566 msg = (ioc.cmd == IBNEX_UNCFG_CLNTS_SZ) ? 567 "\tdevctl:DEVCTL_AP_CONTROL: IBNEX_UNCFG_CLNTS_SZ" : 568 "\tdevctl:DEVCTL_AP_CONTROL: " 569 "IBNEX_UNCFG_CLNTS_INFO"; 570 571 guid_str = strrchr(apid_n, ':') + 1; 572 IBTF_DPRINTF_L4("ibnex", "%s, apid = %s, guid = %s", 573 msg, apid_n, guid_str); 574 575 if (guid_str == NULL) { 576 IBTF_DPRINTF_L2("ibnex", "%s: invalid input " 577 "GUID %s", msg, guid_str); 578 rv = EFAULT; 579 break; 580 } 581 582 /* Get the GUID(hex value) from apid_n */ 583 hca_guid = ibnex_str2hex(guid_str, strlen(guid_str), 584 &ret); 585 if (ret != IBNEX_SUCCESS) { 586 IBTF_DPRINTF_L2("ibnex", "%s: Invalid HCA " 587 "GUID string passed", msg); 588 rv = EIO; 589 break; 590 } 591 IBTF_DPRINTF_L4("ibnex", "%s G = %llX", msg, hca_guid); 592 if (ibtl_ibnex_get_hca_info(hca_guid, 593 IBTL_IBNEX_UNCFG_CLNTS_FLAG, &snapshot, 594 &snapshot_sz, ibnex_return_apid) != IBT_SUCCESS) { 595 IBTF_DPRINTF_L2("ibnex", 596 "%s: get HCA consumers failed", msg); 597 rv = EIO; 598 break; 599 } 600 /* ssiz needs to be reinitialized again */ 601 ssiz = snapshot_sz; 602 603 IBTF_DPRINTF_L4("ibnex", "%s: size =%x", msg, ssiz); 604 605 if (ioc.cmd == IBNEX_UNCFG_CLNTS_SZ) { 606 if (ddi_copyout(&ssiz, ioc.buf, 607 ioc.bufsiz, mode) != 0) { 608 IBTF_DPRINTF_L2("ibnex", 609 "%s: ddi_copyout 9 failed", msg); 610 rv = EFAULT; 611 } 612 613 } else { 614 if (ioc.bufsiz != ssiz) { 615 IBTF_DPRINTF_L2("ibnex", 616 "%s: invalid size (%x, %x)", 617 msg, ioc.bufsiz, ssiz); 618 rv = EINVAL; 619 } else if (ddi_copyout(snapshot, ioc.buf, 620 ioc.bufsiz, mode) != 0) { 621 IBTF_DPRINTF_L2("ibnex", "%s " 622 "ddi_copyout 10 failed", msg); 623 rv = EFAULT; 624 } 625 } 626 627 kmem_free(snapshot, snapshot_sz); 628 break; 629 630 case IBNEX_CONF_ENTRY_ADD: 631 msg = "\tdevctl: IBNEX_CONF_ENTRY_ADD: "; 632 service = kmem_zalloc(ioc.bufsiz + 1, KM_SLEEP); 633 /* read in the "service" name */ 634 if (ddi_copyin(ioc.buf, service, 635 ioc.bufsiz, mode) != 0) { 636 IBTF_DPRINTF_L2("ibnex", "%s: ddi_copyin err 6", 637 msg); 638 rv = EFAULT; 639 break; 640 } 641 642 /* read in the "service type" */ 643 svc_type = ioc.misc_arg; 644 IBTF_DPRINTF_L4("ibnex", "%s: service = %s, type = %d", 645 msg, service, svc_type); 646 647 if (svc_type == IB_PORT_SERVICE) { 648 ibnex_port_conf_entry_add(service); 649 } else if (svc_type == IB_VPPA_SERVICE) { 650 ibnex_vppa_conf_entry_add(service); 651 } else if (svc_type == IB_HCASVC_SERVICE) { 652 ibnex_hcasvc_conf_entry_add(service); 653 } 654 kmem_free(service, ioc.bufsiz + 1); 655 break; 656 657 case IBNEX_CONF_ENTRY_DEL: 658 msg = "\tdevctl:IBNEX_CONF_ENTRY_DEL: "; 659 service = kmem_zalloc(ioc.bufsiz + 1, KM_SLEEP); 660 /* read in the "service" name */ 661 if (ddi_copyin(ioc.buf, service, 662 ioc.bufsiz, mode) != 0) { 663 IBTF_DPRINTF_L2("ibnex", "%s: ddi_copyin err 7", 664 msg); 665 rv = EFAULT; 666 break; 667 } 668 669 /* read in the "service type" */ 670 svc_type = ioc.misc_arg; 671 IBTF_DPRINTF_L4("ibnex", "%s: service = %s, type = %d", 672 msg, service, svc_type); 673 674 if (svc_type == IB_PORT_SERVICE) { 675 rv = ibnex_port_conf_entry_delete(msg, service); 676 } else if (svc_type == IB_VPPA_SERVICE) { 677 rv = ibnex_vppa_conf_entry_delete(msg, service); 678 } else if (svc_type == IB_HCASVC_SERVICE) { 679 rv = ibnex_hcasvc_conf_entry_delete(msg, 680 service); 681 } 682 kmem_free(service, ioc.bufsiz + 1); 683 break; 684 685 case IBNEX_HCA_VERBOSE_SZ: 686 case IBNEX_HCA_VERBOSE_INFO: 687 msg = (ioc.cmd == IBNEX_HCA_VERBOSE_SZ) ? 688 "DEVCTL_AP_CONTROL: IBNEX_HCA_VERBOSE_SZ" : 689 "DEVCTL_AP_CONTROL: IBNEX_HCA_VERBOSE_INFO"; 690 691 guid_str = strrchr(apid_n, ':') + 1; 692 IBTF_DPRINTF_L4("ibnex", "%s, apid = %s, guid = %s", 693 msg, apid_n, guid_str); 694 695 if (guid_str == NULL) { 696 IBTF_DPRINTF_L2("ibnex", "%s: invalid GUID %s", 697 msg, guid_str); 698 rv = EFAULT; 699 break; 700 } 701 702 /* Get the GUID(hex value) from apid_n */ 703 hca_guid = ibnex_str2hex(guid_str, strlen(guid_str), 704 &ret); 705 if (ret != IBNEX_SUCCESS) { 706 IBTF_DPRINTF_L2("ibnex", "%s: Invalid HCA GUID " 707 "string", msg); 708 rv = EIO; 709 break; 710 } 711 IBTF_DPRINTF_L4("ibnex", "%s HCA GUID = 0x%llX", 712 msg, hca_guid); 713 714 if (ibtl_ibnex_get_hca_verbose_data(hca_guid, &snapshot, 715 &snapshot_sz) != IBT_SUCCESS) { 716 IBTF_DPRINTF_L2("ibnex", "%s: get HCA verbose " 717 "data failed", msg); 718 rv = EIO; 719 break; 720 } 721 722 ssiz = snapshot_sz; 723 IBTF_DPRINTF_L4("ibnex", "%s: size =%x", msg, ssiz); 724 725 if (ioc.cmd == IBNEX_HCA_VERBOSE_SZ) { 726 if (ddi_copyout(&ssiz, ioc.buf, 727 ioc.bufsiz, mode) != 0) { 728 IBTF_DPRINTF_L2("ibnex", 729 "%s: ddi_copyout 11 failed", msg); 730 rv = EFAULT; 731 } 732 } else { 733 if (ioc.bufsiz != ssiz) { 734 IBTF_DPRINTF_L2("ibnex", 735 "%s: invalid size (%x, %x)", 736 msg, ioc.bufsiz, ssiz); 737 rv = EINVAL; 738 } else if (ddi_copyout(snapshot, 739 ioc.buf, ioc.bufsiz, mode) != 0) { 740 IBTF_DPRINTF_L2("ibnex", "%s " 741 "ddi_copyout 12 failed", msg); 742 rv = EFAULT; 743 } 744 } 745 746 kmem_free(snapshot, snapshot_sz); 747 break; 748 749 case IBNEX_UPDATE_IOC_CONF : 750 msg = "\tdevctl:IBNEX_UPDATE_IOC_CONF: "; 751 752 /* 753 * If IB fabric APID, call ibnex_update_all 754 * If IOC APID, get the apid dip and call 755 * ibnex_update_ioc 756 */ 757 if (ioc.misc_arg == IBNEX_BASE_APID) { 758 /* 759 * If reprobe is in progress or another reprobe 760 * is already waiting, wait. 761 */ 762 if (ibnex.ibnex_reprobe_state != 0) { 763 if (ibnex.ibnex_reprobe_state == 764 IBNEX_REPROBE_ALL_PROGRESS) 765 ibnex.ibnex_reprobe_state = 766 IBNEX_REPROBE_ALL_WAIT; 767 while (ibnex.ibnex_reprobe_state) { 768 cv_wait(&ibnex.ibnex_reprobe_cv, 769 &ibnex.ibnex_mutex); 770 } 771 772 /* 773 * Pending reprobe all completed, return 774 */ 775 break; 776 } 777 778 /* Check if reprobe for any IOC is pending */ 779 /* CONSTCOND */ 780 while (1) { 781 ioc_reprobe_pending = 0; 782 for (scanp = ibnex.ibnex_ioc_node_head; 783 scanp; 784 scanp = scanp->node_next) { 785 if (scanp->node_reprobe_state 786 != 0) { 787 ioc_reprobe_pending = 788 1; 789 break; 790 } 791 } 792 if (ioc_reprobe_pending == 0) { 793 ibnex.ibnex_reprobe_state &= 794 ~IBNEX_REPROBE_IOC_WAIT; 795 break; 796 } 797 798 ibnex.ibnex_reprobe_state = 799 IBNEX_REPROBE_IOC_WAIT; 800 cv_wait(&ibnex.ibnex_reprobe_cv, 801 &ibnex.ibnex_mutex); 802 } 803 804 /* 805 * Set the REPROBE_ALL_PROGRESS state & 806 * start reprobe 807 */ 808 ibnex.ibnex_reprobe_state = 809 IBNEX_REPROBE_ALL_PROGRESS; 810 mutex_exit(&ibnex.ibnex_mutex); 811 ibnex_reprobe_ioc_all(); 812 mutex_enter(&ibnex.ibnex_mutex); 813 } else if (ioc.misc_arg == IBNEX_DYN_APID) { 814 rv = ibnex_get_dip_from_apid(apid_n, &apid_dip, 815 &nodep); 816 ASSERT(rv == IBNEX_DYN_APID); 817 818 /* Device unconfigured: return */ 819 if (apid_dip == NULL) 820 break; 821 822 ndi_rele_devi(apid_dip); 823 /* Reset return value back to 0 */ 824 rv = 0; 825 if (ibnex.ibnex_reprobe_state != 0 || 826 nodep->node_reprobe_state != 0) { 827 while (ibnex.ibnex_reprobe_state != 0 && 828 nodep->node_reprobe_state != 0) { 829 cv_wait(&ibnex.ibnex_reprobe_cv, 830 &ibnex.ibnex_mutex); 831 } 832 /* Pending reprobe completed, return */ 833 break; 834 } 835 836 /* Set node_reprobe_state and start reprobe */ 837 nodep->node_reprobe_state = 838 IBNEX_NODE_REPROBE_NOTIFY_ON_UPDATE; 839 mutex_exit(&ibnex.ibnex_mutex); 840 ibnex_reprobe_ioc_dev((void *)apid_dip); 841 mutex_enter(&ibnex.ibnex_mutex); 842 } else { 843 rv = EINVAL; 844 } 845 846 break; 847 848 default: 849 IBTF_DPRINTF_L2("ibnex", 850 "DEVCTL_AP_CONTROL: ioc:unknown cmd = %x", ioc.cmd); 851 break; 852 } 853 } 854 break; 855 856 case DEVCTL_AP_UNCONFIGURE: 857 msg = "DEVCTL_AP_UNCONFIGURE"; 858 IBTF_DPRINTF_L4("ibnex", "%s", msg); 859 860 /* Check for write permissions */ 861 if (!(mode & FWRITE)) { 862 IBTF_DPRINTF_L2("ibnex", "%s: invalid mode %x", 863 msg, mode); 864 rv = EPERM; 865 break; 866 } 867 868 if ((apid_n = ibnex_get_apid(dcp)) == NULL) { 869 IBTF_DPRINTF_L2("ibnex", 870 "%s: ibnex_get_apid failed", msg); 871 rv = EIO; 872 break; 873 } 874 875 /* 876 * If this apid is already seen by IBNEX, get the dip 877 * NOTE: ibnex_get_dip_from_apid() finds a valid dip 878 * and also does a ndi_devi_hold() on the child. 879 */ 880 rv = ibnex_get_dip_from_apid(apid_n, &apid_dip, &nodep); 881 if ((rv != IBNEX_DYN_APID) || (apid_dip == NULL)) { 882 IBTF_DPRINTF_L2("ibnex", "%s: get_dip_from_apid " 883 "failed with 0x%x", msg, rv); 884 rv = EIO; 885 break; 886 } 887 IBTF_DPRINTF_L4("ibnex", "%s: DIP = %p", msg, apid_dip); 888 889 /* Check if it is a valid node type? */ 890 if (!IBNEX_VALID_NODE_TYPE(nodep)) { 891 IBTF_DPRINTF_L2("ibnex", "%s: invalid IB node", msg); 892 rv = ENODEV; 893 ndi_rele_devi(apid_dip); 894 break; 895 } 896 897 /* 898 * continue unconfigure operation, only if device node 899 * is already configured. Return EBUSY if another 900 * configure/unconfigure operation is in progress. 901 */ 902 if (nodep->node_state == IBNEX_CFGADM_CONFIGURING || 903 nodep->node_state == IBNEX_CFGADM_UNCONFIGURING) { 904 rv = EBUSY; 905 ndi_rele_devi(apid_dip); 906 break; 907 } 908 909 /* do this before to avoid races */ 910 nodep->node_dip = NULL; 911 nodep->node_state = IBNEX_CFGADM_UNCONFIGURING; 912 913 /* 914 * Call devfs_clean first 915 * NOTE: The code so far is protected by holding ibnex_mutex 916 * and by doing a ndi_devi_hold() on the child. 917 */ 918 pdip = ddi_get_parent(apid_dip); 919 if (i_ddi_node_state(apid_dip) >= DS_INITIALIZED) { 920 devnm = kmem_alloc(MAXNAMELEN + 1, KM_SLEEP); 921 (void) ddi_deviname(apid_dip, devnm); 922 mutex_exit(&ibnex.ibnex_mutex); 923 (void) devfs_clean(pdip, devnm + 1, DV_CLEAN_FORCE); 924 mutex_enter(&ibnex.ibnex_mutex); 925 kmem_free(devnm, MAXNAMELEN + 1); 926 } 927 928 mutex_exit(&ibnex.ibnex_mutex); 929 ndi_devi_enter(pdip); 930 ndi_rele_devi(apid_dip); 931 mutex_enter(&ibnex.ibnex_mutex); 932 933 /* unconfigure the Port/VPPA/HCA_SVC node */ 934 if (IBNEX_COMMSVC_NODE_TYPE(nodep)) { 935 ret_val = ibnex_commsvc_fininode(apid_dip); 936 } else if (nodep->node_type == IBNEX_IOC_NODE) { 937 /* unconfigure the IOC node */ 938 ret_val = ibnex_ioc_fininode(apid_dip, 939 &nodep->node_data.ioc_node); 940 } else if (nodep->node_type == IBNEX_PSEUDO_NODE) { 941 /* unconfigure the pseudo node */ 942 ret_val = ibnex_pseudo_fininode(apid_dip); 943 } 944 945 /* reset upon failure */ 946 if (ret_val != IBNEX_SUCCESS) { 947 nodep->node_dip = apid_dip; 948 nodep->node_state = IBNEX_CFGADM_CONFIGURED; 949 } else { 950 nodep->node_state = IBNEX_CFGADM_UNCONFIGURED; 951 nodep->node_ap_state = IBNEX_NODE_AP_UNCONFIGURED; 952 } 953 954 rv = (ret_val != IBNEX_SUCCESS) ? EIO : 0; 955 ndi_devi_exit(pdip); 956 IBTF_DPRINTF_L2("ibnex", "%s: DONE !! It %s", msg, 957 rv ? "failed" : "succeeded"); 958 break; 959 960 case DEVCTL_AP_CONFIGURE: 961 msg = "DEVCTL_AP_CONFIGURE"; 962 IBTF_DPRINTF_L4("ibnex", "%s", msg); 963 mutex_exit(&ibnex.ibnex_mutex); 964 ndi_devi_enter(ibnex.ibnex_dip); 965 mutex_enter(&ibnex.ibnex_mutex); 966 967 /* Check for write permissions */ 968 if (!(mode & FWRITE)) { 969 IBTF_DPRINTF_L2("ibnex", "%s: invalid mode %x", 970 msg, mode); 971 rv = EPERM; 972 ndi_devi_exit(ibnex.ibnex_dip); 973 break; 974 } 975 976 if ((apid_n = ibnex_get_apid(dcp)) == NULL) { 977 IBTF_DPRINTF_L2("ibnex", 978 "%s: ibnex_get_apid failed", msg); 979 rv = EIO; 980 ndi_devi_exit(ibnex.ibnex_dip); 981 break; 982 } 983 984 /* 985 * Let's get the node if it already exists. 986 * NOTE: ibnex_get_dip_from_apid() finds a valid dip 987 * and also does a ndi_devi_hold() on the child. 988 */ 989 nodep = NULL; 990 ret_val = ibnex_get_dip_from_apid(apid_n, &apid_dip, &nodep); 991 /* 992 * We need the node_data but not the dip. If we get a dip for 993 * this apid, it means it's already configured. We need to 994 * return. 995 */ 996 if (apid_dip != NULL) { 997 ndi_rele_devi(apid_dip); 998 ndi_devi_exit(ibnex.ibnex_dip); 999 rv = 0; 1000 break; 1001 } 1002 1003 /* 1004 * A node exits for this apid but not a dip. So we must have 1005 * unconfigured it earlier. Set the node_ap_state to configuring 1006 * to allow configure operation. 1007 */ 1008 if (nodep != NULL) { 1009 nodep->node_ap_state = IBNEX_NODE_AP_CONFIGURING; 1010 } 1011 1012 1013 /* 1014 * Five types of APIDs are supported: 1015 * o HCA_GUID,0,service-name (HCA-SVC device) 1016 * o IOC_GUID (IOC device) 1017 * o PORT_GUID,0,service-name (Port device) 1018 * o pseudo_name,unit-address, (Pseudo device) 1019 * o PORT_GUID,P_Key,service-name (VPPA device) 1020 * If the apid doesn't have "," then treat it as an IOC 1021 * If the apid has one "," then it is Pseudo device 1022 * If the apid has 2 ","s then it is one of the 1023 * Port,VPPA,HCA_SVC devices 1024 */ 1025 if (strrchr(apid_n, ',') == NULL) { 1026 ret_val = ibnex_handle_ioc_configure(apid_n); 1027 } else { 1028 char *first = strchr(apid_n, ','); 1029 char *second; 1030 1031 second = first ? strchr(first + 1, ',') : NULL; 1032 if (first != NULL && second == NULL) { 1033 ret_val = ibnex_handle_pseudo_configure(apid_n); 1034 } else if (first != NULL && second != NULL) { 1035 ret_val = ibnex_handle_commsvcnode_configure( 1036 apid_n); 1037 } 1038 } /* end of else */ 1039 1040 if (ret_val != IBNEX_SUCCESS) { 1041 rv = (ret_val == IBNEX_BUSY) ? EBUSY : EIO; 1042 } else { 1043 /* 1044 * Get the newly created node and set the state to 1045 * IBNEX_NODE_AP_CONFIGURED. 1046 * NOTE: ibnex_get_dip_from_apid() finds a valid dip 1047 * and also does a ndi_devi_hold() on the child. 1048 */ 1049 if (!nodep) 1050 ret_val = ibnex_get_dip_from_apid(apid_n, 1051 &apid_dip, &nodep); 1052 if (nodep != NULL) { 1053 nodep->node_ap_state = IBNEX_NODE_AP_CONFIGURED; 1054 } 1055 if (apid_dip != NULL) { 1056 ndi_rele_devi(apid_dip); 1057 } 1058 } 1059 IBTF_DPRINTF_L2("ibnex", "%s: DONE !! It %s", msg, 1060 rv ? "failed" : "succeeded"); 1061 ndi_devi_exit(ibnex.ibnex_dip); 1062 break; 1063 1064 default: 1065 rv = EIO; 1066 break; 1067 } 1068 mutex_exit(&ibnex.ibnex_mutex); 1069 1070 if ((apid_alloced == B_TRUE) && (apid_n != NULL)) { 1071 kmem_free(apid_n, apid_len); 1072 } 1073 1074 if (dcp) { 1075 ndi_dc_freehdl(dcp); 1076 } 1077 return (rv); 1078 } 1079 1080 1081 /* 1082 * ibnex_get_num_devices() 1083 * Figure out how many IOC, VPPA, Pseudo, HCA_SVC and Port devices exist 1084 */ 1085 static int 1086 ibnex_get_num_devices(void) 1087 { 1088 int j, k, l, hca_count; 1089 int num_nodes = 0; 1090 ibdm_hca_list_t *hca_list, *hcap; 1091 ibdm_port_attr_t *pattr; 1092 ibnex_node_data_t *nodep; 1093 1094 ASSERT(mutex_owned(&ibnex.ibnex_mutex)); 1095 1096 /* Get a count of HCAs, first. */ 1097 mutex_exit(&ibnex.ibnex_mutex); 1098 ibdm_ibnex_get_hca_list(&hca_list, &hca_count); 1099 mutex_enter(&ibnex.ibnex_mutex); 1100 for (hcap = hca_list; hca_list != NULL; hca_list = hca_list->hl_next) { 1101 for (j = 0; j < ibnex.ibnex_nhcasvc_comm_svcs; j++) 1102 num_nodes++; 1103 for (j = 0; j < hca_list->hl_nports; j++) { 1104 for (k = 0; k < ibnex.ibnex_num_comm_svcs; k++) 1105 num_nodes++; 1106 1107 pattr = &hca_list->hl_port_attr[j]; 1108 for (k = 0; k < pattr->pa_npkeys; k++) { 1109 if (IBNEX_INVALID_PKEY(pattr->pa_pkey_tbl[k]. 1110 pt_pkey)) 1111 continue; 1112 1113 for (l = 0; l < ibnex.ibnex_nvppa_comm_svcs; 1114 l++, ++num_nodes) 1115 ; 1116 } /* end of pa_npkeys */ 1117 } /* end of hl_nports */ 1118 } /* end of hca_list != NULL */ 1119 if (hcap) 1120 ibdm_ibnex_free_hca_list(hcap); 1121 1122 /* 1123 * Now figure out how many IOC nodes are present. 1124 * Add count of configured "diconnected" IOCs 1125 */ 1126 mutex_exit(&ibnex.ibnex_mutex); 1127 num_nodes += ibdm_ibnex_get_ioc_count(); 1128 mutex_enter(&ibnex.ibnex_mutex); 1129 num_nodes += ibnex.ibnex_num_disconnect_iocs; 1130 1131 /* Last: figure out how many Pseudo nodes are present. */ 1132 for (nodep = ibnex.ibnex_pseudo_node_head; nodep; 1133 nodep = nodep->node_next) { 1134 if (nodep->node_data.pseudo_node.pseudo_merge_node == 1) 1135 continue; 1136 1137 num_nodes++; 1138 } 1139 return (num_nodes); 1140 } 1141 1142 1143 /* 1144 * ibnex_get_snapshot() 1145 * Get a snapshot of all Port/IOC/VPPA/HCA_SVC/Pseudo nodes 1146 * Snapshot includes IBNEX_NODE_INFO_NVL, IBNEX_NODE_TYPE_NVL, 1147 * IBNEX_NODE_RSTATE_NVL, IBNEX_NODE_OSTATE_NVL and 1148 * IBNEX_NODE_COND_NVL 1149 */ 1150 static int 1151 ibnex_get_snapshot(char **buf, size_t *sz, int allow_probe) 1152 { 1153 int i, j, k, l, hca_count; 1154 nvlist_t *nvl; 1155 ib_pkey_t pkey; 1156 boolean_t found; 1157 ibdm_ioc_info_t *ioc_listp; 1158 ibdm_ioc_info_t *iocp; 1159 ibdm_hca_list_t *hca_list, *hcap; 1160 ibdm_port_attr_t *port_attr; 1161 ibnex_node_data_t *nodep; 1162 1163 ASSERT(mutex_owned(&ibnex.ibnex_mutex)); 1164 1165 *buf = NULL; 1166 *sz = 0; 1167 1168 if (!ibnex.ibnex_pseudo_inited) { 1169 mutex_exit(&ibnex.ibnex_mutex); 1170 ibnex_pseudo_initnodes(); 1171 mutex_enter(&ibnex.ibnex_mutex); 1172 ibnex.ibnex_pseudo_inited = 1; 1173 } 1174 1175 /* First, Port/VPPA/HCA_SVC nodes */ 1176 mutex_exit(&ibnex.ibnex_mutex); 1177 ibdm_ibnex_get_hca_list(&hca_list, &hca_count); 1178 mutex_enter(&ibnex.ibnex_mutex); 1179 1180 (void) nvlist_alloc(&nvl, 0, KM_SLEEP); 1181 1182 /* Go thru all the ports of all the HCAs and all the port-svc indices */ 1183 for (hcap = hca_list, i = 0; i < hca_count; 1184 hca_list = hca_list->hl_next, i++) { 1185 1186 IBTF_DPRINTF_L4("ibnex", "ibnex_get_snapshot: " 1187 "fill in COMM service HCA_SVC nodes"); 1188 port_attr = hca_list->hl_hca_port_attr; 1189 for (j = 0; j < ibnex.ibnex_nhcasvc_comm_svcs; j++) { 1190 if (ibnex_get_commsvcnode_snapshot(&nvl, 1191 port_attr->pa_hca_guid, 1192 port_attr->pa_hca_guid, j, (ib_pkey_t)0, 1193 IBNEX_HCASVC_COMMSVC_NODE) != 0) { 1194 IBTF_DPRINTF_L2("ibnex", 1195 "ibnex_get_snapshot: failed to fill" 1196 " HCA_SVC device (%x %x)", i, j); 1197 ibdm_ibnex_free_hca_list(hcap); 1198 nvlist_free(nvl); 1199 return (-1); 1200 } 1201 1202 } 1203 1204 for (j = 0; j < hca_list->hl_nports; j++) { 1205 port_attr = &hca_list->hl_port_attr[j]; 1206 1207 IBTF_DPRINTF_L4("ibnex", "ibnex_get_snapshot: " 1208 "fill in COMM service Port nodes"); 1209 for (k = 0; k < ibnex.ibnex_num_comm_svcs; k++) { 1210 1211 if (ibnex_get_commsvcnode_snapshot(&nvl, 1212 port_attr->pa_hca_guid, 1213 port_attr->pa_port_guid, k, (ib_pkey_t)0, 1214 IBNEX_PORT_COMMSVC_NODE) != 0) { 1215 IBTF_DPRINTF_L2("ibnex", 1216 "ibnex_get_snapshot: failed to fill" 1217 " Port device (%x %x %x)", i, j, k); 1218 ibdm_ibnex_free_hca_list(hcap); 1219 nvlist_free(nvl); 1220 return (-1); 1221 } 1222 1223 } /* end of num_comm_svcs for loop */ 1224 1225 IBTF_DPRINTF_L4("ibnex", "ibnex_get_snapshot: " 1226 "fill in VPPA service port nodes"); 1227 for (l = 0; l < port_attr->pa_npkeys; l++) { 1228 pkey = port_attr->pa_pkey_tbl[l].pt_pkey; 1229 if (IBNEX_INVALID_PKEY(pkey)) 1230 continue; 1231 1232 for (k = 0; k < ibnex.ibnex_nvppa_comm_svcs; 1233 k++) { 1234 1235 if (ibnex_get_commsvcnode_snapshot(&nvl, 1236 port_attr->pa_hca_guid, 1237 port_attr->pa_port_guid, k, pkey, 1238 IBNEX_VPPA_COMMSVC_NODE) != 0) { 1239 IBTF_DPRINTF_L2("ibnex", 1240 "ibnex_get_snapshot: " 1241 "failed to fill VPPA " 1242 "device (%x %x %x % x)", 1243 i, j, k, l); 1244 ibdm_ibnex_free_hca_list(hcap); 1245 nvlist_free(nvl); 1246 return (-1); 1247 } 1248 } /* end of ibnex_nvppa_comm_svcs loop */ 1249 1250 } /* end of pa_npkeys for loop */ 1251 1252 } /* end of hl_nports for loop */ 1253 1254 } /* end of hca_count for loop */ 1255 1256 if (hcap) 1257 ibdm_ibnex_free_hca_list(hcap); 1258 1259 /* save it to free up the entire list */ 1260 mutex_exit(&ibnex.ibnex_mutex); 1261 iocp = ioc_listp = ibdm_ibnex_get_ioc_list(allow_probe); 1262 mutex_enter(&ibnex.ibnex_mutex); 1263 for (; ioc_listp != NULL; ioc_listp = ioc_listp->ioc_next) { 1264 1265 /* 1266 * Say we have N IOCs and all were deleted from ibnex 1267 * but not from IBDM 1268 */ 1269 if (ibnex.ibnex_ioc_node_head == NULL) { 1270 if (ibnex_fill_ioc_tmp(&nvl, ioc_listp) != 0) { 1271 IBTF_DPRINTF_L2("ibnex", "ibnex_get_snapshot: " 1272 "filling NVL data failed"); 1273 ibdm_ibnex_free_ioc_list(iocp); 1274 nvlist_free(nvl); 1275 return (-1); 1276 } 1277 continue; 1278 1279 } else { 1280 found = B_FALSE; 1281 1282 /* Check first, if we have already seen this IOC? */ 1283 for (nodep = ibnex.ibnex_ioc_node_head; nodep != NULL; 1284 nodep = nodep->node_next) { 1285 if (ioc_listp->ioc_profile.ioc_guid == 1286 nodep->node_data.ioc_node.ioc_guid) { 1287 found = B_TRUE; 1288 break; 1289 } 1290 } 1291 1292 1293 /* have we seen this IOC before? */ 1294 if (found == B_TRUE) { 1295 if (ibnex_fill_nodeinfo(&nvl, nodep, 1296 &ioc_listp->ioc_profile) != 0) { 1297 IBTF_DPRINTF_L2("ibnex", 1298 "ibnex_get_snapshot: filling NVL " 1299 "for IOC node %p failed", nodep); 1300 ibdm_ibnex_free_ioc_list(iocp); 1301 nvlist_free(nvl); 1302 return (-1); 1303 } 1304 1305 } else { 1306 1307 if (ibnex_fill_ioc_tmp(&nvl, ioc_listp) != 0) { 1308 IBTF_DPRINTF_L2("ibnex", 1309 "ibnex_get_snapshot: filling NVL " 1310 "tmp for IOC node %p failed", 1311 ioc_listp); 1312 ibdm_ibnex_free_ioc_list(iocp); 1313 nvlist_free(nvl); 1314 return (-1); 1315 } 1316 } 1317 1318 } /* end of else ibnex_ioc_node_head == NULL */ 1319 } /* end of external for */ 1320 1321 ibdm_ibnex_free_ioc_list(iocp); 1322 1323 /* 1324 * Add list of "disconnected" IOCs, not unconfigured. 1325 */ 1326 for (nodep = ibnex.ibnex_ioc_node_head; nodep != NULL; 1327 nodep = nodep->node_next) { 1328 if (nodep->node_data.ioc_node.ioc_ngids == 0 && 1329 nodep->node_data.ioc_node.ioc_profile != NULL && 1330 nodep->node_state != IBNEX_CFGADM_UNCONFIGURED) { 1331 if (ibnex_fill_nodeinfo(&nvl, nodep, 1332 nodep->node_data.ioc_node.ioc_profile) != 0) { 1333 IBTF_DPRINTF_L2("ibnex", 1334 "ibnex_get_snapshot: filling NVL " 1335 "for disconnected IOC node %p " 1336 "failed", nodep); 1337 nvlist_free(nvl); 1338 return (-1); 1339 } 1340 } 1341 } 1342 1343 /* lastly; pseudo nodes */ 1344 for (nodep = ibnex.ibnex_pseudo_node_head; nodep; 1345 nodep = nodep->node_next) { 1346 if (nodep->node_data.pseudo_node.pseudo_merge_node == 1) 1347 continue; 1348 if (ibnex_fill_nodeinfo(&nvl, nodep, NULL) != 0) { 1349 IBTF_DPRINTF_L2("ibnex", "ibnex_get_snapshot: " 1350 "filling NVL data for Pseudo %p failed", nodep); 1351 nvlist_free(nvl); 1352 return (-1); 1353 } 1354 } 1355 1356 /* pack the data into the buffer */ 1357 if (nvlist_pack(nvl, buf, sz, NV_ENCODE_NATIVE, KM_SLEEP)) { 1358 IBTF_DPRINTF_L2("ibnex", 1359 "ibnex_get_snapshot: nvlist_pack failed"); 1360 nvlist_free(nvl); 1361 return (-1); 1362 } 1363 1364 IBTF_DPRINTF_L4("ibnex", "ibnex_get_snapshot: size = 0x%x", *sz); 1365 nvlist_free(nvl); 1366 return (0); 1367 } 1368 1369 1370 /* 1371 * ibnex_get_commsvcnode_snapshot() 1372 * A utility function to fill in a "dummy" Port/VPPA/HCA_SVC 1373 * information. Cfgadm plugin will display all Port/VPPA/ 1374 * HCA_SVCs seen even if they are not all configured by IBNEX. 1375 * 1376 * This function uses information from IBDM to fill up Port/VPPA/ 1377 * HCA_SVC snapshot. If none exists then it makes up a "temporary" 1378 * node which will be displayed as "connected/unconfigured/unknown". 1379 * 1380 * For HCA_SVC node port_guid will be same as hca_guid. 1381 */ 1382 static int 1383 ibnex_get_commsvcnode_snapshot(nvlist_t **nvlpp, ib_guid_t hca_guid, 1384 ib_guid_t port_guid, int svc_index, ib_pkey_t p_key, 1385 ibnex_node_type_t node_type) 1386 { 1387 int rval; 1388 dev_info_t *dip = NULL; 1389 ibnex_node_data_t *nodep; 1390 ibnex_node_data_t dummy; 1391 ibnex_node_data_t *tmp = &dummy; 1392 1393 IBTF_DPRINTF_L4("ibnex", "ibnex_get_commsvcnode_snapshot: " 1394 "HCA GUID: %llX Port GUID: %llX svc_index = %x pkey = %x " 1395 "node_type = %x", hca_guid, port_guid, svc_index, p_key, node_type); 1396 1397 /* check if this node was seen before? */ 1398 rval = ibnex_get_node_and_dip_from_guid(port_guid, svc_index, p_key, 1399 &nodep, &dip); 1400 if (rval == IBNEX_SUCCESS && nodep != NULL) { 1401 1402 if (ibnex_fill_nodeinfo(nvlpp, nodep, NULL) != 0) { 1403 IBTF_DPRINTF_L2("ibnex", 1404 "ibnex_get_commsvcnode_snapshot: failed to fill " 1405 "Port/VPPA device node %p NVL data", nodep); 1406 return (-1); 1407 } 1408 1409 } else { 1410 /* Fake up a Port/VPPA/HCA_SVC node */ 1411 IBTF_DPRINTF_L4("ibnex", "ibnex_get_commsvcnode_snapshot: " 1412 "VPPA/Port/HCA_SVC not seen by ibnex"); 1413 bzero(tmp, sizeof (ibnex_node_data_t)); 1414 tmp->node_type = node_type; 1415 tmp->node_data.port_node.port_guid = port_guid; 1416 tmp->node_data.port_node.port_hcaguid = hca_guid; 1417 tmp->node_data.port_node.port_commsvc_idx = svc_index; 1418 /* Fill P_Key only for VPPA nodes */ 1419 if (node_type == IBNEX_VPPA_COMMSVC_NODE) { 1420 tmp->node_data.port_node.port_pkey = p_key; 1421 } 1422 1423 if (ibnex_fill_nodeinfo(nvlpp, tmp, NULL) != 0) { 1424 IBTF_DPRINTF_L2("ibnex", 1425 "ibnex_get_commsvcnode_snapshot: failed to fill " 1426 "tmp Port/VPPA device node %p NVL data", tmp); 1427 return (-1); 1428 } 1429 } 1430 1431 return (0); 1432 } 1433 1434 1435 /* 1436 * ibnex_fill_ioc_tmp() 1437 * A utility function to fill in a "dummy" IOC information. 1438 * Cfgadm plugin will display all IOCs seen by IBDM even if they 1439 * are configured or not by IBNEX. 1440 * 1441 * This function uses information from IBDM to fill up a 1442 * dummy IOC information. It will be displayed as 1443 * "connected/unconfigured/unknown". 1444 */ 1445 static int 1446 ibnex_fill_ioc_tmp(nvlist_t **nvlpp, ibdm_ioc_info_t *ioc_listp) 1447 { 1448 ibnex_node_data_t dummy; 1449 ibnex_node_data_t *nodep = &dummy; 1450 1451 IBTF_DPRINTF_L4("ibnex", "\tibnex_fill_ioc_tmp:"); 1452 1453 bzero(nodep, sizeof (ibnex_node_data_t)); 1454 nodep->node_type = IBNEX_IOC_NODE; 1455 nodep->node_data.ioc_node.ioc_guid = ioc_listp->ioc_profile.ioc_guid; 1456 nodep->node_data.ioc_node.iou_guid = ioc_listp->ioc_iou_guid; 1457 (void) strncpy(nodep->node_data.ioc_node.ioc_id_string, 1458 (char *)ioc_listp->ioc_profile.ioc_id_string, 1459 IB_DM_IOC_ID_STRING_LEN); 1460 IBTF_DPRINTF_L4("ibnex", "\tibnex_fill_ioc_tmp: %s", 1461 nodep->node_data.ioc_node.ioc_id_string); 1462 1463 if (ibnex_fill_nodeinfo(nvlpp, nodep, &ioc_listp->ioc_profile) != 0) { 1464 IBTF_DPRINTF_L2("ibnex", "\tibnex_fill_ioc_tmp: filling NVL " 1465 "data for IOC node %p failed", nodep); 1466 return (-1); 1467 } 1468 1469 return (0); 1470 } 1471 1472 1473 /* 1474 * ibnex_fill_nodeinfo() 1475 * A utility function to fill in to the NVLIST information about 1476 * a Port/IOC/VPPA/HCA_SVC/Pseudo driver that is then passed over 1477 * to cfgadm utility for display. This information is used only 1478 * for cfgadm -ll displays. 1479 * 1480 * Information that is filled in here is:- 1481 * AP_ID_NAME 1482 * AP_ID_INFO 1483 * AP_ID_TYPE 1484 * AP_ID_OCCUPANT_STATE 1485 * AP_ID_RECEPTACLE_STATE 1486 * AP_ID_CONDITION 1487 */ 1488 static int 1489 ibnex_fill_nodeinfo(nvlist_t **nvlpp, ibnex_node_data_t *node_datap, void *tmp) 1490 { 1491 char *svcname; 1492 char *node_name; 1493 char apid[IBTL_IBNEX_APID_LEN]; 1494 char info_data[MAXNAMELEN]; 1495 ib_dm_ioc_ctrl_profile_t *profilep; 1496 devctl_ap_state_t state; 1497 1498 IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: 0x%x addr is %p", 1499 node_datap->node_type, node_datap); 1500 1501 if (node_datap->node_type == IBNEX_PORT_COMMSVC_NODE) { 1502 svcname = ibnex.ibnex_comm_svc_names[node_datap->node_data. 1503 port_node.port_commsvc_idx]; 1504 (void) snprintf(apid, IBTL_IBNEX_APID_LEN, "%llX,0,%s", 1505 (longlong_t)node_datap->node_data.port_node.port_guid, 1506 svcname); 1507 1508 /* Node APID */ 1509 if (nvlist_add_string(*nvlpp, IBNEX_NODE_APID_NVL, apid)) { 1510 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: " 1511 "failed to fill %s", IBNEX_NODE_APID_NVL); 1512 return (-1); 1513 } 1514 1515 /* Node Info */ 1516 if (nvlist_add_string(*nvlpp, IBNEX_NODE_INFO_NVL, svcname)) { 1517 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: " 1518 "failed to fill Port %s", IBNEX_NODE_INFO_NVL); 1519 return (-1); 1520 } 1521 1522 IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: " 1523 "Port %s = %s, %s = %s", 1524 IBNEX_NODE_INFO_NVL, apid, IBNEX_NODE_APID_NVL, svcname); 1525 1526 } else if (node_datap->node_type == IBNEX_VPPA_COMMSVC_NODE) { 1527 svcname = ibnex.ibnex_vppa_comm_svc_names[node_datap->node_data. 1528 port_node.port_commsvc_idx]; 1529 (void) snprintf(apid, IBTL_IBNEX_APID_LEN, "%llX,%x,%s", 1530 (longlong_t)node_datap->node_data.port_node.port_guid, 1531 node_datap->node_data.port_node.port_pkey, svcname); 1532 1533 /* Node APID */ 1534 if (nvlist_add_string(*nvlpp, IBNEX_NODE_APID_NVL, apid)) { 1535 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: " 1536 "failed to fill %s", IBNEX_NODE_APID_NVL); 1537 return (-1); 1538 } 1539 1540 /* Node Info */ 1541 if (nvlist_add_string(*nvlpp, IBNEX_NODE_INFO_NVL, svcname)) { 1542 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: " 1543 "failed to fill VPPA %s", IBNEX_NODE_INFO_NVL); 1544 return (-1); 1545 } 1546 1547 IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: " 1548 "VPPA %s = %s, %s = %s", 1549 IBNEX_NODE_APID_NVL, apid, IBNEX_NODE_INFO_NVL, svcname); 1550 1551 } else if (node_datap->node_type == IBNEX_HCASVC_COMMSVC_NODE) { 1552 svcname = ibnex.ibnex_hcasvc_comm_svc_names[node_datap-> 1553 node_data.port_node.port_commsvc_idx]; 1554 (void) snprintf(apid, IBTL_IBNEX_APID_LEN, "%llX,0,%s", 1555 (longlong_t)node_datap->node_data.port_node.port_guid, 1556 svcname); 1557 1558 /* Node APID */ 1559 if (nvlist_add_string(*nvlpp, IBNEX_NODE_APID_NVL, apid)) { 1560 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: " 1561 "failed to fill %s", IBNEX_NODE_APID_NVL); 1562 return (-1); 1563 } 1564 1565 /* Node Info */ 1566 if (nvlist_add_string(*nvlpp, IBNEX_NODE_INFO_NVL, svcname)) { 1567 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: " 1568 "failed to fill Port %s", IBNEX_NODE_INFO_NVL); 1569 return (-1); 1570 } 1571 1572 IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: " 1573 "Port %s = %s, %s = %s", 1574 IBNEX_NODE_INFO_NVL, apid, IBNEX_NODE_APID_NVL, svcname); 1575 1576 } else if (node_datap->node_type == IBNEX_IOC_NODE) { 1577 1578 /* 1579 * get the IOC profile pointer from the args 1580 */ 1581 profilep = (ib_dm_ioc_ctrl_profile_t *)tmp; 1582 IBNEX_FORM_GUID(apid, IBTL_IBNEX_APID_LEN, profilep->ioc_guid); 1583 1584 /* Node APID */ 1585 if (nvlist_add_string(*nvlpp, IBNEX_NODE_APID_NVL, apid)) { 1586 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: " 1587 "failed to fill in %s", IBNEX_NODE_APID_NVL); 1588 return (-1); 1589 } 1590 IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: %s %s", 1591 IBNEX_NODE_APID_NVL, apid); 1592 1593 /* 1594 * IOC "info" filed will display the following fields 1595 * VendorID, IOCDeviceID, DeviceVersion, SubsystemVendorID, 1596 * SubsystemID, Class, Subclass, Protocol, ProtocolVersion 1597 */ 1598 (void) snprintf(info_data, MAXNAMELEN, 1599 "VID: 0x%x DEVID: 0x%x VER: 0x%x SUBSYS_VID: 0x%x " 1600 "SUBSYS_ID: 0x%x CLASS: 0x%x SUBCLASS: 0x%x PROTO: 0x%x " 1601 "PROTOVER: 0x%x ID_STRING: %s", profilep->ioc_vendorid, 1602 profilep->ioc_deviceid, profilep->ioc_device_ver, 1603 profilep->ioc_subsys_vendorid, profilep->ioc_subsys_id, 1604 profilep->ioc_io_class, profilep->ioc_io_subclass, 1605 profilep->ioc_protocol, profilep->ioc_protocol_ver, 1606 (char *)profilep->ioc_id_string); 1607 IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: %s", info_data); 1608 1609 /* Node Info */ 1610 if (nvlist_add_string(*nvlpp, IBNEX_NODE_INFO_NVL, info_data)) { 1611 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: " 1612 "failed to fill IOC %s", IBNEX_NODE_INFO_NVL); 1613 return (-1); 1614 } 1615 1616 } else if (node_datap->node_type == IBNEX_PSEUDO_NODE) { 1617 (void) snprintf(apid, IBTL_IBNEX_APID_LEN, "%s", 1618 node_datap->node_data.pseudo_node.pseudo_node_addr); 1619 1620 /* Node APID */ 1621 if (nvlist_add_string(*nvlpp, IBNEX_NODE_APID_NVL, apid)) { 1622 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: " 1623 "failed to fill in %s", IBNEX_NODE_APID_NVL); 1624 return (-1); 1625 } 1626 1627 /* Node Info */ 1628 node_name = node_datap->node_data.pseudo_node.pseudo_devi_name; 1629 (void) snprintf(info_data, MAXNAMELEN, 1630 "Pseudo Driver = \"%s\", Unit-address = \"%s\"", 1631 node_name, apid + strlen(node_name) + 1); 1632 if (nvlist_add_string(*nvlpp, IBNEX_NODE_INFO_NVL, info_data)) { 1633 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: " 1634 "failed to fill Pseudo %s", IBNEX_NODE_INFO_NVL); 1635 return (-1); 1636 } 1637 1638 IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: Pseudo %s = %s," 1639 "%s = %s", IBNEX_NODE_APID_NVL, apid, IBNEX_NODE_INFO_NVL, 1640 info_data); 1641 } 1642 1643 /* Node type */ 1644 if (nvlist_add_int32(*nvlpp, IBNEX_NODE_TYPE_NVL, 1645 node_datap->node_type)) { 1646 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: " 1647 "failed to fill in %s", IBNEX_NODE_TYPE_NVL); 1648 return (-1); 1649 } 1650 IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: %s %d", 1651 IBNEX_NODE_TYPE_NVL, node_datap->node_type); 1652 1653 /* figure out "ostate", "rstate" and "condition" */ 1654 ibnex_figure_ap_devstate(node_datap, &state); 1655 1656 if (nvlist_add_int32(*nvlpp, IBNEX_NODE_RSTATE_NVL, state.ap_rstate)) { 1657 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: " 1658 "failed to fill in %s", IBNEX_NODE_RSTATE_NVL); 1659 return (-1); 1660 } 1661 IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: %s %d", 1662 IBNEX_NODE_RSTATE_NVL, state.ap_rstate); 1663 1664 if (nvlist_add_int32(*nvlpp, IBNEX_NODE_OSTATE_NVL, state.ap_ostate)) { 1665 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: " 1666 "failed to fill in %s", IBNEX_NODE_OSTATE_NVL); 1667 return (-1); 1668 } 1669 IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: %s %d", 1670 IBNEX_NODE_OSTATE_NVL, state.ap_ostate); 1671 1672 if (nvlist_add_int32(*nvlpp, IBNEX_NODE_COND_NVL, state.ap_condition)) { 1673 IBTF_DPRINTF_L2("ibnex", "ibnex_fill_nodeinfo: " 1674 "failed to fill in %s", IBNEX_NODE_COND_NVL); 1675 return (-1); 1676 } 1677 IBTF_DPRINTF_L5("ibnex", "ibnex_fill_nodeinfo: %s %d", 1678 IBNEX_NODE_COND_NVL, state.ap_condition); 1679 1680 return (0); 1681 } 1682 1683 1684 /* 1685 * ibnex_figure_ap_devstate() 1686 * Fills the "devctl_ap_state_t" for a given ap_id 1687 * 1688 * currently it assumes that we don't support "error_code" and 1689 * "last_change" value. 1690 */ 1691 static void 1692 ibnex_figure_ap_devstate(ibnex_node_data_t *nodep, devctl_ap_state_t *ap_state) 1693 { 1694 IBTF_DPRINTF_L5("ibnex", "ibnex_figure_ap_devstate: nodep = %p", nodep); 1695 1696 ap_state->ap_rstate = AP_RSTATE_CONNECTED; 1697 if (nodep == NULL) { /* for nodes not seen by IBNEX yet */ 1698 ap_state->ap_ostate = AP_OSTATE_UNCONFIGURED; 1699 ap_state->ap_condition = AP_COND_UNKNOWN; 1700 } else { 1701 /* 1702 * IBNEX_NODE_AP_UNCONFIGURED & IBNEX_NODE_AP_CONFIGURING. 1703 */ 1704 if (nodep->node_ap_state >= IBNEX_NODE_AP_UNCONFIGURED) { 1705 ap_state->ap_ostate = AP_OSTATE_UNCONFIGURED; 1706 ap_state->ap_condition = AP_COND_UNKNOWN; 1707 } else { 1708 ap_state->ap_ostate = AP_OSTATE_CONFIGURED; 1709 ap_state->ap_condition = AP_COND_OK; 1710 } 1711 } 1712 ap_state->ap_last_change = (time_t)-1; 1713 ap_state->ap_error_code = 0; 1714 ap_state->ap_in_transition = 0; 1715 } 1716 1717 1718 /* 1719 * ibnex_figure_ib_apid_devstate() 1720 * Fills the "devctl_ap_state_t" for a IB static ap_id 1721 */ 1722 static void 1723 ibnex_figure_ib_apid_devstate(devctl_ap_state_t *ap_state) 1724 { 1725 ap_state->ap_rstate = AP_RSTATE_CONNECTED; 1726 ap_state->ap_condition = AP_COND_OK; 1727 ap_state->ap_ostate = (ibt_get_hca_list(NULL) == 0) ? 1728 AP_OSTATE_UNCONFIGURED : AP_OSTATE_CONFIGURED; 1729 ap_state->ap_last_change = (time_t)-1; 1730 ap_state->ap_error_code = 0; 1731 ap_state->ap_in_transition = 0; 1732 } 1733 1734 1735 /* 1736 * ibnex_get_apid() 1737 * Reads in the ap_id passed as an nvlist_string from user-land 1738 */ 1739 static char * 1740 ibnex_get_apid(struct devctl_iocdata *dcp) 1741 { 1742 char *ap_id; 1743 1744 ASSERT(mutex_owned(&ibnex.ibnex_mutex)); 1745 1746 /* Get which ap_id to operate on. */ 1747 if (nvlist_lookup_string(ndi_dc_get_ap_data(dcp), "apid", 1748 &ap_id) != 0) { 1749 IBTF_DPRINTF_L4("ibnex", "ibnex_get_apid: ap_id lookup failed"); 1750 ap_id = NULL; 1751 } 1752 1753 IBTF_DPRINTF_L4("ibnex", "ibnex_get_apid: ap_id=%s", ap_id); 1754 return (ap_id); 1755 } 1756 1757 1758 /* 1759 * ibnex_get_dip_from_apid() 1760 * Figures out the dip/node_data from an ap_id given that this ap_id 1761 * exists as a "name" in the "ibnex" list 1762 * 1763 * NOTE: ap_id was on stack earlier and gets manipulated here. Since this 1764 * function may be called twice; it is better to make a local copy of 1765 * ap_id; if the ap_id were to be reused. 1766 */ 1767 static int 1768 ibnex_get_dip_from_apid(char *apid, dev_info_t **ret_dip, 1769 ibnex_node_data_t **ret_node_datap) 1770 { 1771 int rv, ret; 1772 int index; 1773 int len = strlen((char *)apid) + 1; 1774 char *dyn; 1775 char *ap_id; 1776 char *first; 1777 char *second = NULL; 1778 char *node_addr; 1779 char name[100]; 1780 ibnex_node_data_t *nodep = NULL; 1781 1782 ap_id = i_ddi_strdup(apid, KM_SLEEP); 1783 IBTF_DPRINTF_L4("ibnex", "\tibnex_get_dip_from_apid: %s", ap_id); 1784 ASSERT(mutex_owned(&ibnex.ibnex_mutex)); 1785 1786 if ((dyn = GET_DYN(ap_id)) != NULL) { 1787 rv = IBNEX_DYN_APID; 1788 } else { /* either static, hca or unknown */ 1789 *ret_dip = NULL; 1790 if (strstr(ap_id, "hca") != 0) { 1791 rv = IBNEX_HCA_APID; 1792 } else if (strstr(ap_id, IBNEX_FABRIC) != 0) { 1793 rv = IBNEX_BASE_APID; 1794 } else { 1795 rv = IBNEX_UNKNOWN_APID; 1796 } 1797 kmem_free(ap_id, len); 1798 return (rv); 1799 } 1800 1801 dyn += strlen(DYN_SEP); 1802 if (*dyn == '\0') { 1803 *ret_dip = NULL; 1804 kmem_free(ap_id, len); 1805 return (IBNEX_UNKNOWN_APID); 1806 } 1807 1808 /* APID */ 1809 first = strchr(dyn, ','); 1810 if (first != NULL) 1811 second = strchr(first+1, ','); 1812 1813 /* Implies Port or VPPA or HCA_SVC Driver ap_id */ 1814 if (first != NULL && second != NULL) { 1815 int str_len; 1816 int pkey_val = 0; 1817 char *pkey_str = strchr(ap_id, ','); 1818 char *svc_str = strrchr(pkey_str, ','); 1819 1820 /* dyn contains ,GUID,p_key,svc_name. Change it to GUID */ 1821 str_len = strlen(dyn) - strlen(pkey_str); 1822 dyn[str_len] = '\0'; 1823 IBTF_DPRINTF_L4("ibnex", "\tibnex_get_dip_from_apid: " 1824 "Port / Node Guid %s", dyn); 1825 1826 /* figure out comm or vppa. figure out pkey */ 1827 ++pkey_str; /* pkey_str used to point to ",p_key,svc_name" */ 1828 1829 /* pkey_str contains p_key,svc_name. Change it to p_key */ 1830 str_len = strlen(pkey_str) - strlen(svc_str); 1831 pkey_str[str_len] = '\0'; 1832 1833 /* convert the string P_KEY to hex value */ 1834 pkey_val = ibnex_str2hex(pkey_str, strlen(pkey_str), &ret); 1835 if (ret != IBNEX_SUCCESS) { 1836 *ret_dip = NULL; 1837 kmem_free(ap_id, len); 1838 return (IBNEX_UNKNOWN_APID); 1839 } 1840 1841 ++svc_str; /* svc_str used to point to ",svc_name" */ 1842 IBTF_DPRINTF_L5("ibnex", "\tibnex_get_dip_from_apid: pkey %s" 1843 ":%x service name = %s", pkey_str, pkey_val, svc_str); 1844 1845 for (nodep = ibnex.ibnex_port_node_head; 1846 nodep != NULL; nodep = nodep->node_next) { 1847 index = nodep->node_data.port_node.port_commsvc_idx; 1848 IBNEX_FORM_GUID(name, IBTL_IBNEX_APID_LEN, 1849 nodep->node_data.port_node.port_guid); 1850 1851 /* 1852 * Match P_Key, name string & service string: 1853 * For COMM / HCA_SVC services these should be true: 1854 * P_Key matches to 0, svc_str in comm_svc_names[] 1855 * and name matches the dynamic part of the ap_id 1856 * For VPPA services this should be true: 1857 * P_Key != 0 & matches, svc_str in 1858 * vppa_comm_svc_names[] and the name matches the 1859 * dynamic part of the ap_id. 1860 */ 1861 if ((pkey_val == nodep->node_data.port_node. 1862 port_pkey) && (strstr(dyn, name) != NULL)) { 1863 1864 /* pkey != 0, COMM / HCA_SVC service */ 1865 if (((pkey_val == 0) && ( 1866 /* Port Service */ 1867 ((ibnex.ibnex_comm_svc_names != NULL) && 1868 (index < ibnex.ibnex_num_comm_svcs) && 1869 (strstr(svc_str, ibnex. 1870 ibnex_comm_svc_names[index]) != NULL)) || 1871 /* HCA_SVC service */ 1872 ((ibnex.ibnex_hcasvc_comm_svc_names != 1873 NULL) && (index < 1874 ibnex.ibnex_nhcasvc_comm_svcs) && 1875 (strstr(svc_str, ibnex. 1876 ibnex_hcasvc_comm_svc_names[index]) 1877 != NULL)))) || 1878 /* next the VPPA strings */ 1879 ((pkey_val != 0) && (strstr(svc_str, ibnex. 1880 ibnex_vppa_comm_svc_names[index]) != 1881 NULL))) { 1882 if (nodep->node_dip) 1883 ndi_hold_devi(nodep->node_dip); 1884 *ret_node_datap = nodep; 1885 *ret_dip = nodep->node_dip; 1886 kmem_free(ap_id, len); 1887 return (rv); 1888 } 1889 } 1890 1891 } /* end of for */ 1892 1893 } else if (first != NULL && second == NULL) { 1894 /* pseudo ap_id */ 1895 for (nodep = ibnex.ibnex_pseudo_node_head; nodep; 1896 nodep = nodep->node_next) { 1897 if (nodep->node_data.pseudo_node.pseudo_merge_node 1898 == 1) 1899 continue; 1900 node_addr = nodep->node_data.pseudo_node. 1901 pseudo_node_addr; 1902 if (strncmp(dyn, node_addr, strlen(node_addr)) == 0) { 1903 if (nodep->node_dip) 1904 ndi_hold_devi(nodep->node_dip); 1905 *ret_node_datap = nodep; 1906 *ret_dip = nodep->node_dip; 1907 kmem_free(ap_id, len); 1908 return (rv); 1909 } 1910 } 1911 1912 } else if (first == NULL && second == NULL) { 1913 /* This is an IOC ap_id */ 1914 for (nodep = ibnex.ibnex_ioc_node_head; nodep != NULL; 1915 nodep = nodep->node_next) { 1916 IBNEX_FORM_GUID(name, IBTL_IBNEX_APID_LEN, 1917 nodep->node_data.ioc_node.ioc_guid); 1918 if (strstr(dyn, name) != NULL) { 1919 if (nodep->node_dip) 1920 ndi_hold_devi(nodep->node_dip); 1921 *ret_node_datap = nodep; 1922 *ret_dip = nodep->node_dip; 1923 kmem_free(ap_id, len); 1924 return (rv); 1925 } 1926 } 1927 } 1928 1929 /* Could not find a matching IB device */ 1930 *ret_dip = (nodep) ? nodep->node_dip : NULL; 1931 kmem_free(ap_id, len); 1932 return (rv); 1933 } 1934 1935 1936 /* 1937 * ibnex_handle_pseudo_configure() 1938 * Do DEVCTL_AP_CONNECT processing for Pseudo devices only. 1939 * The code also checks if the given ap_id is valid or not. 1940 */ 1941 static ibnex_rval_t 1942 ibnex_handle_pseudo_configure(char *apid) 1943 { 1944 char *node_addr; 1945 char *last = strrchr(apid, ':') + 1; 1946 ibnex_rval_t retval = IBNEX_FAILURE; 1947 ibnex_node_data_t *nodep; 1948 1949 IBTF_DPRINTF_L4("ibnex", "\tibnex_handle_pseudo_configure: " 1950 "last = %s\n\t\tapid = %s", last, apid); 1951 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex)); 1952 1953 /* Check if the APID is valid first */ 1954 if (apid == NULL || last == NULL) { 1955 IBTF_DPRINTF_L4("ibnex", "\tibnex_handle_pseudo_configure: " 1956 "invalid apid %s", apid); 1957 return (retval); 1958 } 1959 1960 /* find the matching entry and configure it */ 1961 for (nodep = ibnex.ibnex_pseudo_node_head; nodep != NULL; 1962 nodep = nodep->node_next) { 1963 if (nodep->node_data.pseudo_node.pseudo_merge_node == 1) 1964 continue; 1965 node_addr = nodep->node_data.pseudo_node.pseudo_node_addr; 1966 if (strncmp(node_addr, last, strlen(last))) 1967 continue; 1968 1969 if (nodep->node_dip != NULL) { 1970 /* 1971 * Return BUSY if another configure 1972 * operation is in progress 1973 */ 1974 if (nodep->node_state == 1975 IBNEX_CFGADM_CONFIGURING) 1976 return (IBNEX_BUSY); 1977 else 1978 return (IBNEX_SUCCESS); 1979 } 1980 1981 /* 1982 * Return BUSY if another unconfigure operation is 1983 * in progress 1984 */ 1985 if (nodep->node_state == IBNEX_CFGADM_UNCONFIGURING) 1986 return (IBNEX_BUSY); 1987 1988 ASSERT(nodep->node_state != IBNEX_CFGADM_CONFIGURED); 1989 nodep->node_state = IBNEX_CFGADM_CONFIGURING; 1990 1991 mutex_exit(&ibnex.ibnex_mutex); 1992 retval = ibnex_pseudo_create_all_pi(nodep); 1993 mutex_enter(&ibnex.ibnex_mutex); 1994 if (retval == NDI_SUCCESS) { 1995 nodep->node_state = IBNEX_CFGADM_CONFIGURED; 1996 return (IBNEX_SUCCESS); 1997 } else { 1998 nodep->node_state = IBNEX_CFGADM_UNCONFIGURED; 1999 return (IBNEX_FAILURE); 2000 } 2001 } 2002 2003 IBTF_DPRINTF_L4("ibnex", "\thandle_pseudo_configure: retval=%d", 2004 retval); 2005 return (retval); 2006 } 2007 2008 2009 /* 2010 * ibnex_handle_ioc_configure() 2011 * Do DEVCTL_AP_CONNECT processing for IOCs only. 2012 * The code also checks if the given ap_id is valid or not. 2013 */ 2014 static ibnex_rval_t 2015 ibnex_handle_ioc_configure(char *apid) 2016 { 2017 int ret; 2018 char *guid_str = strrchr(apid, ':') + 1; 2019 ib_guid_t ioc_guid; 2020 ibnex_rval_t retval = IBNEX_FAILURE; 2021 ibdm_ioc_info_t *ioc_info; 2022 2023 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex)); 2024 IBTF_DPRINTF_L4("ibnex", "\tibnex_handle_ioc_configure: %s", apid); 2025 2026 /* Check if the APID is valid first */ 2027 if (guid_str == NULL) { 2028 IBTF_DPRINTF_L4("ibnex", 2029 "\tibnex_handle_ioc_configure: invalid apid %s", apid); 2030 return (retval); 2031 } 2032 2033 /* 2034 * Call into IBDM to get IOC information 2035 */ 2036 ioc_guid = ibnex_str2hex(guid_str, strlen(guid_str), &ret); 2037 if (ret != IBNEX_SUCCESS) 2038 return (ret); 2039 2040 IBTF_DPRINTF_L4("ibnex", 2041 "\tibnex_handle_ioc_configure: IOC GUID = %llX", ioc_guid); 2042 mutex_exit(&ibnex.ibnex_mutex); 2043 ioc_info = ibdm_ibnex_get_ioc_info(ioc_guid); 2044 mutex_enter(&ibnex.ibnex_mutex); 2045 if (ioc_info == NULL) { 2046 IBTF_DPRINTF_L2("ibnex", 2047 "\tibnex_handle_ioc_configure: probe_iocguid failed"); 2048 return (retval); 2049 } 2050 2051 retval = ibnex_ioc_initnode_all_pi(ioc_info); 2052 ibdm_ibnex_free_ioc_list(ioc_info); 2053 2054 IBTF_DPRINTF_L4("ibnex", "\tibnex_handle_ioc_configure: " 2055 "done retval = %d", retval); 2056 return (retval); 2057 } 2058 2059 2060 /* 2061 * ibnex_handle_commsvcnode_configure() 2062 * Do DEVCTL_AP_CONNECT processing 2063 * This is done for Port/VPPA/HCA_SVC drivers Only. 2064 * The code also checks if the given ap_id is valid or not. 2065 */ 2066 static ibnex_rval_t 2067 ibnex_handle_commsvcnode_configure(char *apid) 2068 { 2069 int ret, str_len; 2070 int sndx; 2071 int port_pkey = 0; 2072 char *pkey_str = strchr(apid, ','); 2073 char *guid_str = strrchr(apid, ':') + 1; 2074 char *svc_str = strrchr(pkey_str, ','); 2075 boolean_t found = B_FALSE; 2076 boolean_t is_hcasvc_node = B_FALSE; 2077 ib_guid_t guid; /* Port / Node GUID */ 2078 dev_info_t *parent; 2079 ibnex_rval_t retval = IBNEX_FAILURE; 2080 ibdm_port_attr_t *port_attr; 2081 int node_type; 2082 ibdm_hca_list_t *hca_list; 2083 2084 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex)); 2085 IBTF_DPRINTF_L4("ibnex", "\tibnex_handle_commsvcnode_configure: %s", 2086 apid); 2087 2088 /* Check if the APID is valid first */ 2089 if (guid_str == NULL || ((guid_str != NULL) && 2090 (pkey_str == NULL || svc_str == NULL))) { 2091 IBTF_DPRINTF_L4("ibnex", 2092 "\tibnex_handle_commsvcnode_configure: " 2093 "invalid apid %s", apid); 2094 return (retval); 2095 } 2096 2097 /* guid_str contains GUID,p_key,svc_name. Change it to GUID */ 2098 str_len = strlen(guid_str) - strlen(pkey_str); 2099 guid_str[str_len] = '\0'; 2100 2101 /* convert the string GUID to hex value */ 2102 guid = ibnex_str2hex(guid_str, strlen(guid_str), &ret); 2103 if (ret == IBNEX_FAILURE) 2104 return (ret); 2105 IBTF_DPRINTF_L4("ibnex", "\tibnex_handle_commsvcnode_configure: " 2106 "Port / Node Guid %llX", guid); 2107 2108 /* figure out Port/HCA_SVC or VPPA. Also figure out the P_Key. */ 2109 ++pkey_str; /* pkey_str used to point to ",p_key,svc_name" */ 2110 2111 /* pkey_str contains p_key,svc_name. Change it to P_Key */ 2112 str_len = strlen(pkey_str) - strlen(svc_str); 2113 pkey_str[str_len] = '\0'; 2114 IBTF_DPRINTF_L5("ibnex", "\tibnex_handle_commsvcnode_configure: " 2115 "p_key %s", pkey_str); 2116 2117 /* convert the string P_Key to a hexadecimal value */ 2118 port_pkey = ibnex_str2hex(pkey_str, strlen(pkey_str), &ret); 2119 IBTF_DPRINTF_L5("ibnex", "\tibnex_handle_commsvcnode_configure: " 2120 "PKEY num %x", port_pkey); 2121 if (ret == IBNEX_FAILURE) 2122 return (ret); 2123 2124 ++svc_str; /* svc_str used to point to ",svc_name" */ 2125 2126 /* find the service index */ 2127 if (port_pkey == 0) { 2128 /* PORT Devices */ 2129 for (sndx = 0; sndx < ibnex.ibnex_num_comm_svcs; sndx++) { 2130 if (strncmp(ibnex.ibnex_comm_svc_names[sndx], 2131 svc_str, strlen(svc_str)) == 0) { 2132 found = B_TRUE; 2133 break; 2134 } 2135 } 2136 2137 /* HCA_SVC Devices */ 2138 if (found == B_FALSE) { 2139 for (sndx = 0; sndx < ibnex.ibnex_nhcasvc_comm_svcs; 2140 sndx++) { 2141 if (strncmp(ibnex.ibnex_hcasvc_comm_svc_names 2142 [sndx], svc_str, strlen(svc_str)) == 0) { 2143 found = B_TRUE; 2144 is_hcasvc_node = B_TRUE; 2145 break; 2146 } 2147 } 2148 } 2149 2150 } else { 2151 for (sndx = 0; sndx < ibnex.ibnex_nvppa_comm_svcs; sndx++) { 2152 if (strncmp(ibnex.ibnex_vppa_comm_svc_names[sndx], 2153 svc_str, strlen(svc_str)) == 0) { 2154 found = B_TRUE; 2155 break; 2156 } 2157 } 2158 } 2159 2160 if (found == B_FALSE) { 2161 IBTF_DPRINTF_L2("ibnex", 2162 "\tibnex_handle_commsvcnode_configure: " 2163 "invalid service %s", svc_str); 2164 return (retval); 2165 } 2166 2167 /* get Port attributes structure */ 2168 mutex_exit(&ibnex.ibnex_mutex); 2169 if (is_hcasvc_node == B_FALSE) { 2170 port_attr = ibdm_ibnex_get_port_attrs(guid); 2171 if (port_attr == NULL) { 2172 IBTF_DPRINTF_L2("ibnex", 2173 "\tibnex_handle_commsvcnode_configure: " 2174 "ibdm_ibnex_get_port_attrs failed"); 2175 mutex_enter(&ibnex.ibnex_mutex); 2176 return (retval); 2177 } 2178 } else { 2179 hca_list = ibdm_ibnex_get_hca_info_by_guid(guid); 2180 if (hca_list == NULL) { 2181 IBTF_DPRINTF_L2("ibnex", 2182 "\tibnex_handle_commsvcnode_configure: " 2183 "ibdm_ibnex_get_hca_info_by_guid failed"); 2184 mutex_enter(&ibnex.ibnex_mutex); 2185 return (retval); 2186 } 2187 port_attr = hca_list->hl_hca_port_attr; 2188 } 2189 2190 /* get HCA's dip */ 2191 parent = ibtl_ibnex_hcaguid2dip(port_attr->pa_hca_guid); 2192 2193 if (parent == NULL) { 2194 IBTF_DPRINTF_L2("ibnex", 2195 "\tibnex_handle_commsvcnode_configure: " 2196 "no HCA present"); 2197 mutex_enter(&ibnex.ibnex_mutex); 2198 if (is_hcasvc_node == B_FALSE) 2199 ibdm_ibnex_free_port_attr(port_attr); 2200 else 2201 ibdm_ibnex_free_hca_list(hca_list); 2202 return (retval); 2203 } 2204 2205 if (port_pkey == 0) 2206 node_type = (is_hcasvc_node == B_FALSE) ? 2207 IBNEX_PORT_COMMSVC_NODE : IBNEX_HCASVC_COMMSVC_NODE; 2208 else 2209 node_type = IBNEX_VPPA_COMMSVC_NODE; 2210 2211 mutex_enter(&ibnex.ibnex_mutex); 2212 ndi_devi_enter(parent); 2213 if (ibnex_commsvc_initnode(parent, port_attr, sndx, node_type, 2214 port_pkey, &ret, IBNEX_CFGADM_ENUMERATE) != NULL) { 2215 retval = IBNEX_SUCCESS; 2216 } else { 2217 retval = (ret == IBNEX_BUSY) ? IBNEX_BUSY : IBNEX_FAILURE; 2218 } 2219 ndi_devi_exit(parent); 2220 2221 if (is_hcasvc_node == B_FALSE) 2222 ibdm_ibnex_free_port_attr(port_attr); 2223 else 2224 ibdm_ibnex_free_hca_list(hca_list); 2225 2226 IBTF_DPRINTF_L4("ibnex", "\tibnex_handle_commsvcnode_configure: " 2227 "done retval = %d", retval); 2228 2229 return (retval); 2230 } 2231 2232 2233 /* 2234 * ibnex_return_apid() 2235 * Construct the ap_id of a given IBTF client in kernel 2236 */ 2237 static void 2238 ibnex_return_apid(dev_info_t *childp, char **ret_apid) 2239 { 2240 ibnex_node_data_t *nodep; 2241 2242 IBTF_DPRINTF_L4("ibnex", "ibnex_return_apid:"); 2243 2244 ASSERT(childp != NULL); 2245 nodep = ddi_get_parent_data(childp); 2246 2247 if (nodep->node_type == IBNEX_PORT_COMMSVC_NODE) { 2248 (void) snprintf(*ret_apid, IBTL_IBNEX_APID_LEN, 2249 "ib%s%llX,0,%s", DYN_SEP, 2250 (longlong_t)nodep->node_data.port_node.port_guid, 2251 ibnex.ibnex_comm_svc_names[nodep->node_data.port_node. 2252 port_commsvc_idx]); 2253 2254 } else if (nodep->node_type == IBNEX_HCASVC_COMMSVC_NODE) { 2255 (void) snprintf(*ret_apid, IBTL_IBNEX_APID_LEN, 2256 "ib%s%llX,0,%s", DYN_SEP, 2257 (longlong_t)nodep->node_data.port_node.port_guid, ibnex. 2258 ibnex_hcasvc_comm_svc_names[nodep->node_data.port_node. 2259 port_commsvc_idx]); 2260 2261 } else if (nodep->node_type == IBNEX_VPPA_COMMSVC_NODE) { 2262 (void) snprintf(*ret_apid, IBTL_IBNEX_APID_LEN, 2263 "ib%s%llX,%x,%s", DYN_SEP, 2264 (longlong_t)nodep->node_data.port_node.port_guid, 2265 nodep->node_data.port_node.port_pkey, 2266 ibnex.ibnex_vppa_comm_svc_names[nodep->node_data.port_node. 2267 port_commsvc_idx]); 2268 2269 } else if (nodep->node_type == IBNEX_IOC_NODE) { 2270 (void) snprintf(*ret_apid, IBTL_IBNEX_APID_LEN, 2271 "ib%s%llX", DYN_SEP, 2272 (longlong_t)nodep->node_data.ioc_node.ioc_guid); 2273 2274 } else if (nodep->node_type == IBNEX_PSEUDO_NODE) { 2275 (void) snprintf(*ret_apid, IBTL_IBNEX_APID_LEN, "ib%s%s", 2276 DYN_SEP, nodep->node_data.pseudo_node.pseudo_node_addr); 2277 2278 } else { 2279 (void) snprintf(*ret_apid, IBTL_IBNEX_APID_LEN, "%s", "-"); 2280 } 2281 2282 IBTF_DPRINTF_L4("ibnex", "ibnex_return_apid: %x %s", 2283 nodep->node_type, ret_apid); 2284 } 2285 2286 2287 /* 2288 * ibnex_vppa_conf_entry_add() 2289 * Add a new service to the ibnex data base of VPPA communication 2290 * services. 2291 */ 2292 static void 2293 ibnex_vppa_conf_entry_add(char *service) 2294 { 2295 int i, nsvcs; 2296 char **service_name; 2297 2298 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex)); 2299 nsvcs = ibnex.ibnex_nvppa_comm_svcs; 2300 2301 /* Allocate space for new "ibnex.ibnex_nvppa_comm_svcs + 1" */ 2302 service_name = kmem_alloc((nsvcs + 1) * sizeof (char *), KM_SLEEP); 2303 /* 2304 * Copy over the existing "ibnex.ibnex_vppa_comm_svc_names" 2305 * array. Add the new service at the end. 2306 */ 2307 for (i = 0; i < nsvcs; i++) 2308 service_name[i] = ibnex.ibnex_vppa_comm_svc_names[i]; 2309 service_name[i] = kmem_alloc(strlen(service) + 1, KM_SLEEP); 2310 (void) snprintf(service_name[i], 5, "%s", service); 2311 2312 /* Replace existing pointer to VPPA services w/ newly allocated one */ 2313 if (ibnex.ibnex_vppa_comm_svc_names) { 2314 kmem_free(ibnex.ibnex_vppa_comm_svc_names, nsvcs * 2315 sizeof (char *)); 2316 } 2317 ibnex.ibnex_nvppa_comm_svcs++; 2318 ibnex.ibnex_vppa_comm_svc_names = service_name; 2319 } 2320 2321 /* 2322 * ibnex_port_conf_entry_add() 2323 * Add a new service to the ibnex data base of Port communication 2324 * services. 2325 */ 2326 static void 2327 ibnex_port_conf_entry_add(char *service) 2328 { 2329 int i, nsvcs; 2330 char **service_name; 2331 2332 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex)); 2333 nsvcs = ibnex.ibnex_num_comm_svcs; 2334 2335 /* Allocate space for new "ibnex.ibnex_num_comm_svcs + 1" */ 2336 service_name = kmem_alloc((nsvcs + 1) * sizeof (char *), KM_SLEEP); 2337 /* 2338 * Copy over the existing "ibnex.ibnex_comm_svc_names" array. 2339 * Add the new service to the end. 2340 */ 2341 for (i = 0; i < nsvcs; i++) 2342 service_name[i] = ibnex.ibnex_comm_svc_names[i]; 2343 service_name[i] = kmem_alloc(strlen(service) + 1, KM_SLEEP); 2344 (void) snprintf(service_name[i], 5, "%s", service); 2345 2346 /* Replace existing pointer to Port services w/ newly allocated one */ 2347 if (ibnex.ibnex_comm_svc_names) { 2348 kmem_free(ibnex.ibnex_comm_svc_names, nsvcs * sizeof (char *)); 2349 } 2350 ibnex.ibnex_num_comm_svcs++; 2351 ibnex.ibnex_comm_svc_names = service_name; 2352 } 2353 2354 /* 2355 * ibnex_hcasvc_conf_entry_add() 2356 * Add a new service to the ibnex data base of HCA_SVC communication 2357 * services. 2358 */ 2359 static void 2360 ibnex_hcasvc_conf_entry_add(char *service) 2361 { 2362 int i, nsvcs; 2363 char **service_name; 2364 2365 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex)); 2366 nsvcs = ibnex.ibnex_nhcasvc_comm_svcs; 2367 2368 /* Allocate space for new "ibnex.ibnex_nvppa_comm_svcs + 1" */ 2369 service_name = kmem_alloc((nsvcs + 1) * sizeof (char *), KM_SLEEP); 2370 /* 2371 * Copy over the existing "ibnex.ibnex_hcasvc_comm_svc_names" 2372 * array. Add the new service at the end. 2373 */ 2374 for (i = 0; i < nsvcs; i++) 2375 service_name[i] = ibnex.ibnex_hcasvc_comm_svc_names[i]; 2376 service_name[i] = kmem_alloc(strlen(service) + 1, KM_SLEEP); 2377 (void) snprintf(service_name[i], 5, "%s", service); 2378 2379 /* 2380 * Replace existing pointer to HCA_SVC services w/ newly 2381 * allocated one 2382 */ 2383 if (ibnex.ibnex_hcasvc_comm_svc_names) { 2384 kmem_free(ibnex.ibnex_hcasvc_comm_svc_names, nsvcs * 2385 sizeof (char *)); 2386 } 2387 ibnex.ibnex_nhcasvc_comm_svcs++; 2388 ibnex.ibnex_hcasvc_comm_svc_names = service_name; 2389 } 2390 2391 2392 /* 2393 * ibnex_vppa_conf_entry_delete() 2394 * Delete an existing service entry from ibnex data base of 2395 * VPPA communication services. 2396 */ 2397 static int 2398 ibnex_vppa_conf_entry_delete(char *msg, char *service) 2399 { 2400 int i, j, nsvcs; 2401 int len; 2402 int match_ndx; 2403 char **service_name; 2404 boolean_t found = B_FALSE; 2405 ibnex_node_data_t *node_datap = ibnex.ibnex_port_node_head; 2406 2407 IBTF_DPRINTF_L4("ibnex", "\tvppa_conf_entry_delete: %s", service); 2408 2409 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex)); 2410 nsvcs = ibnex.ibnex_nvppa_comm_svcs; 2411 2412 /* find matching index */ 2413 for (i = 0; i < nsvcs; i++) { 2414 if (strcmp(ibnex.ibnex_vppa_comm_svc_names[i], service)) 2415 continue; 2416 found = B_TRUE; 2417 match_ndx = i; 2418 break; 2419 } 2420 2421 /* check for valid "nsvcs" */ 2422 if (found == B_FALSE || nsvcs == 0) { 2423 IBTF_DPRINTF_L2("ibnex", "%s: invalid vppa services %x", 2424 msg, nsvcs); 2425 return (EIO); 2426 } 2427 2428 /* Check if service is in use; return failure if so */ 2429 for (; node_datap; node_datap = node_datap->node_next) { 2430 if ((node_datap->node_data.port_node.port_commsvc_idx == i) && 2431 node_datap->node_type == IBNEX_VPPA_COMMSVC_NODE && 2432 node_datap->node_dip) { 2433 IBTF_DPRINTF_L2("ibnex", "%s: service %s is in use", 2434 msg, service); 2435 return (EIO); 2436 } 2437 } 2438 2439 /* if nsvcs == 1, bailout early */ 2440 if (nsvcs == 1) { 2441 /* free up that single entry */ 2442 len = strlen(ibnex.ibnex_vppa_comm_svc_names[0]) + 1; 2443 kmem_free(ibnex.ibnex_vppa_comm_svc_names[0], len); 2444 kmem_free(ibnex.ibnex_vppa_comm_svc_names, sizeof (char *)); 2445 ibnex.ibnex_vppa_comm_svc_names = NULL; 2446 ibnex.ibnex_nvppa_comm_svcs = 0; 2447 return (0); 2448 } 2449 2450 /* Allocate space for new "ibnex.ibnex_nvppa_comm_svcs - 1" */ 2451 service_name = kmem_alloc((nsvcs - 1) * sizeof (char *), KM_SLEEP); 2452 /* 2453 * Copy over the existing "ibnex.ibnex_vppa_comm_svc_names" 2454 * array. Do not copy over the matching service. 2455 */ 2456 for (i = 0, j = 0; i < nsvcs; i++) { 2457 if (i == match_ndx) { 2458 /* free up that entry */ 2459 len = strlen(ibnex.ibnex_vppa_comm_svc_names[i]) + 1; 2460 kmem_free(ibnex.ibnex_vppa_comm_svc_names[i], len); 2461 continue; 2462 } 2463 service_name[j++] = ibnex.ibnex_vppa_comm_svc_names[i]; 2464 } 2465 2466 /* Replace existing pointer to VPPA services w/ newly adjusted one */ 2467 if (ibnex.ibnex_vppa_comm_svc_names) { 2468 kmem_free(ibnex.ibnex_vppa_comm_svc_names, nsvcs * 2469 sizeof (char *)); 2470 ibnex.ibnex_nvppa_comm_svcs--; 2471 ibnex.ibnex_vppa_comm_svc_names = service_name; 2472 } 2473 return (0); 2474 } 2475 2476 2477 /* 2478 * ibnex_port_conf_entry_delete() 2479 * Delete an existing service entry from ibnex data base of 2480 * Port communication services. 2481 */ 2482 static int 2483 ibnex_port_conf_entry_delete(char *msg, char *service) 2484 { 2485 int i, j, nsvcs; 2486 int match_ndx; 2487 int len; 2488 char **service_name; 2489 boolean_t found = B_FALSE; 2490 ibnex_node_data_t *node_datap = ibnex.ibnex_port_node_head; 2491 2492 IBTF_DPRINTF_L4("ibnex", "\tport_conf_entry_delete: %s", service); 2493 2494 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex)); 2495 nsvcs = ibnex.ibnex_num_comm_svcs; 2496 2497 /* find matching index */ 2498 for (i = 0; i < nsvcs; i++) { 2499 if (strcmp(ibnex.ibnex_comm_svc_names[i], service)) 2500 continue; 2501 found = B_TRUE; 2502 match_ndx = i; 2503 break; 2504 } 2505 2506 /* check for valid "nsvcs" */ 2507 if (found == B_FALSE || nsvcs == 0) { 2508 IBTF_DPRINTF_L2("ibnex", "%s: invalid services %x", msg, nsvcs); 2509 return (EIO); 2510 } 2511 2512 /* Check if service is in use; return failure if so */ 2513 for (; node_datap; node_datap = node_datap->node_next) { 2514 if ((node_datap->node_data.port_node.port_commsvc_idx == i) && 2515 node_datap->node_type == IBNEX_PORT_COMMSVC_NODE && 2516 node_datap->node_dip) 2517 return (EIO); 2518 } 2519 2520 /* if nsvcs == 1, bailout early */ 2521 if (nsvcs == 1) { 2522 /* free up that single entry */ 2523 len = strlen(ibnex.ibnex_comm_svc_names[0]) + 1; 2524 kmem_free(ibnex.ibnex_comm_svc_names[0], len); 2525 kmem_free(ibnex.ibnex_comm_svc_names, sizeof (char *)); 2526 ibnex.ibnex_comm_svc_names = NULL; 2527 ibnex.ibnex_num_comm_svcs = 0; 2528 return (0); 2529 } 2530 2531 /* Allocate space for new "ibnex.ibnex_num_comm_svcs - 1" */ 2532 service_name = kmem_alloc((nsvcs - 1) * sizeof (char *), KM_SLEEP); 2533 /* 2534 * Copy over the existing "ibnex.ibnex_comm_svc_names" array. 2535 * Skip the matching service. 2536 */ 2537 for (i = 0, j = 0; i < nsvcs; i++) { 2538 if (i == match_ndx) { 2539 /* free up that entry */ 2540 len = strlen(ibnex.ibnex_comm_svc_names[i]) + 1; 2541 kmem_free(ibnex.ibnex_comm_svc_names[i], len); 2542 continue; 2543 } 2544 service_name[j++] = ibnex.ibnex_comm_svc_names[i]; 2545 } 2546 2547 /* Replace existing pointer to Port services w/ newly adjusted one */ 2548 if (ibnex.ibnex_comm_svc_names) { 2549 kmem_free(ibnex.ibnex_comm_svc_names, nsvcs * sizeof (char *)); 2550 ibnex.ibnex_num_comm_svcs--; 2551 ibnex.ibnex_comm_svc_names = service_name; 2552 } 2553 return (0); 2554 } 2555 2556 /* 2557 * ibnex_hcasvc_conf_entry_delete() 2558 * Delete an existing service entry from ibnex data base of 2559 * HCA_SVC communication services. 2560 */ 2561 static int 2562 ibnex_hcasvc_conf_entry_delete(char *msg, char *service) 2563 { 2564 int i, j, nsvcs; 2565 int len; 2566 int match_ndx; 2567 char **service_name; 2568 boolean_t found = B_FALSE; 2569 ibnex_node_data_t *node_datap = ibnex.ibnex_port_node_head; 2570 2571 IBTF_DPRINTF_L4("ibnex", "\thcasvc_conf_entry_delete: %s", service); 2572 2573 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex)); 2574 nsvcs = ibnex.ibnex_nhcasvc_comm_svcs; 2575 2576 /* find matching index */ 2577 for (i = 0; i < nsvcs; i++) { 2578 if (strcmp(ibnex.ibnex_hcasvc_comm_svc_names[i], service)) 2579 continue; 2580 found = B_TRUE; 2581 match_ndx = i; 2582 break; 2583 } 2584 2585 /* check for valid "nsvcs" */ 2586 if (found == B_FALSE || nsvcs == 0) { 2587 IBTF_DPRINTF_L2("ibnex", "%s: invalid hca_svc services %x", 2588 msg, nsvcs); 2589 return (EIO); 2590 } 2591 2592 /* Check if service is in use; return failure if so */ 2593 for (; node_datap; node_datap = node_datap->node_next) { 2594 if ((node_datap->node_data.port_node.port_commsvc_idx == i) && 2595 node_datap->node_type == IBNEX_HCASVC_COMMSVC_NODE && 2596 node_datap->node_dip) { 2597 IBTF_DPRINTF_L2("ibnex", "%s: service %s is in use", 2598 msg, service); 2599 return (EIO); 2600 } 2601 } 2602 2603 /* if nsvcs == 1, bailout early */ 2604 if (nsvcs == 1) { 2605 /* free up that single entry */ 2606 len = strlen(ibnex.ibnex_hcasvc_comm_svc_names[0]) + 1; 2607 kmem_free(ibnex.ibnex_hcasvc_comm_svc_names[0], len); 2608 kmem_free(ibnex.ibnex_hcasvc_comm_svc_names, sizeof (char *)); 2609 ibnex.ibnex_hcasvc_comm_svc_names = NULL; 2610 ibnex.ibnex_nhcasvc_comm_svcs = 0; 2611 return (0); 2612 } 2613 2614 /* Allocate space for new "ibnex.ibnex_nhcasvc_comm_svcs - 1" */ 2615 service_name = kmem_alloc((nsvcs - 1) * sizeof (char *), KM_SLEEP); 2616 /* 2617 * Copy over the existing "ibnex.ibnex_hcasvc_comm_svc_names" 2618 * array. Do not copy over the matching service. 2619 */ 2620 for (i = 0, j = 0; i < nsvcs; i++) { 2621 if (i == match_ndx) { 2622 /* free up that entry */ 2623 len = strlen(ibnex.ibnex_hcasvc_comm_svc_names[i]) + 1; 2624 kmem_free(ibnex.ibnex_hcasvc_comm_svc_names[i], len); 2625 continue; 2626 } 2627 service_name[j++] = ibnex.ibnex_hcasvc_comm_svc_names[i]; 2628 } 2629 2630 /* Replace existing pointer to VPPA services w/ newly adjusted one */ 2631 if (ibnex.ibnex_hcasvc_comm_svc_names) { 2632 kmem_free(ibnex.ibnex_hcasvc_comm_svc_names, nsvcs * 2633 sizeof (char *)); 2634 ibnex.ibnex_nhcasvc_comm_svcs--; 2635 ibnex.ibnex_hcasvc_comm_svc_names = service_name; 2636 } 2637 return (0); 2638 } 2639 2640 2641 /* 2642 * ibnex_ioc_fininode() 2643 * Un-initialize a child device node for IOC device node 2644 * Returns IBNEX_SUCCESS/IBNEX_FAILURE 2645 */ 2646 static ibnex_rval_t 2647 ibnex_ioc_fininode(dev_info_t *dip, ibnex_ioc_node_t *ioc_nodep) 2648 { 2649 int rval = MDI_SUCCESS; 2650 2651 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex)); 2652 IBTF_DPRINTF_L4("ibnex", "\tioc_fininode"); 2653 2654 /* 2655 * For a dis-connected IOC, 2656 * Free the ioc_profile && 2657 * decrement ibnex_num_disconnect_iocs 2658 */ 2659 if (ioc_nodep->ioc_ngids == 0 && ioc_nodep->ioc_profile) { 2660 IBTF_DPRINTF_L4("ibnex", "\tioc_fininode: unconfigure " 2661 "disconnected IOC: GUID %lX", ioc_nodep->ioc_guid); 2662 ibnex.ibnex_num_disconnect_iocs--; 2663 kmem_free(ioc_nodep->ioc_profile, 2664 sizeof (ib_dm_ioc_ctrl_profile_t)); 2665 ioc_nodep->ioc_profile = NULL; 2666 } 2667 2668 mutex_exit(&ibnex.ibnex_mutex); 2669 ASSERT(i_ddi_node_state(dip) >= DS_BOUND); 2670 2671 IBTF_DPRINTF_L4("ibnex", "\tioc_fininode: offlining the IOC"); 2672 rval = ibnex_offline_childdip(dip); 2673 2674 if (rval != MDI_SUCCESS) { 2675 rval = NDI_FAILURE; 2676 IBTF_DPRINTF_L2("ibnex", "\toffline failed for IOC " 2677 "dip %p with 0x%x", dip, rval); 2678 } 2679 2680 mutex_enter(&ibnex.ibnex_mutex); 2681 return (rval == MDI_SUCCESS ? IBNEX_SUCCESS : IBNEX_OFFLINE_FAILED); 2682 } 2683 2684 2685 int 2686 ibnex_offline_childdip(dev_info_t *dip) 2687 { 2688 int rval = MDI_SUCCESS, rval2; 2689 mdi_pathinfo_t *path = NULL, *temp; 2690 2691 IBTF_DPRINTF_L4("ibnex", "\toffline_childdip; begin"); 2692 if (dip == NULL) { 2693 IBTF_DPRINTF_L2("ibnex", "\toffline_childdip; NULL dip"); 2694 return (MDI_FAILURE); 2695 } 2696 2697 for (path = mdi_get_next_phci_path(dip, path); path; ) { 2698 IBTF_DPRINTF_L4("ibnex", "\toffline_childdip: " 2699 "offling path %p", path); 2700 rval2 = MDI_SUCCESS; 2701 if (MDI_PI_IS_ONLINE(path)) { 2702 rval2 = mdi_pi_offline(path, NDI_UNCONFIG); 2703 /* If it cannot be offlined, log this path and error */ 2704 if (rval2 != MDI_SUCCESS) { 2705 rval = rval2; 2706 cmn_err(CE_WARN, 2707 "!ibnex\toffline_childdip (0x%p): " 2708 "mdi_pi_offline path (0x%p) failed with %d", 2709 (void *)dip, (void *)path, rval2); 2710 } 2711 } 2712 /* prepare the next path */ 2713 temp = path; 2714 path = mdi_get_next_phci_path(dip, path); 2715 /* free the offline path */ 2716 if (rval2 == MDI_SUCCESS) { 2717 (void) mdi_pi_free(temp, 0); 2718 } 2719 } 2720 return (rval); 2721 } 2722 2723 2724 /* 2725 * ibnex_commsvc_fininode() 2726 * 2727 * Un-initialize a child device node for HCA port / node GUID 2728 * for a communication service. 2729 * Returns IBNEX_SUCCESS/IBNEX_FAILURE 2730 */ 2731 static ibnex_rval_t 2732 ibnex_commsvc_fininode(dev_info_t *dip) 2733 { 2734 int rval = NDI_SUCCESS; 2735 2736 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex)); 2737 IBTF_DPRINTF_L4("ibnex", "\tcommsvc_fininode"); 2738 2739 mutex_exit(&ibnex.ibnex_mutex); 2740 if (i_ddi_node_state(dip) < DS_BOUND) { 2741 /* 2742 * if the child hasn't been bound yet, we can 2743 * just free the dip. This path is currently 2744 * untested. 2745 */ 2746 (void) ddi_remove_child(dip, 0); 2747 IBTF_DPRINTF_L4("ibnex", 2748 "\tcommsvc_fininode: ddi_remove_child"); 2749 } else { 2750 IBTF_DPRINTF_L4("ibnex", "\tcommsvc_fininode: offlining the " 2751 "Commsvc node"); 2752 2753 rval = ndi_devi_offline(dip, NDI_DEVI_REMOVE | NDI_UNCONFIG); 2754 if (rval != NDI_SUCCESS) 2755 IBTF_DPRINTF_L2("ibnex", "\toffline failed for Commsvc " 2756 "dip %p with 0x%x", dip, rval); 2757 } 2758 mutex_enter(&ibnex.ibnex_mutex); 2759 return (rval == NDI_SUCCESS ? IBNEX_SUCCESS : IBNEX_OFFLINE_FAILED); 2760 } 2761 2762 2763 /* 2764 * ibnex_pseudo_fininode() 2765 * Un-initialize a child pseudo device node 2766 * Returns IBNEX_SUCCESS/IBNEX_FAILURE 2767 */ 2768 static ibnex_rval_t 2769 ibnex_pseudo_fininode(dev_info_t *dip) 2770 { 2771 int rval = MDI_SUCCESS; 2772 2773 ASSERT(MUTEX_HELD(&ibnex.ibnex_mutex)); 2774 IBTF_DPRINTF_L4("ibnex", "\tpseudo_fininode: dip = %p", dip); 2775 2776 mutex_exit(&ibnex.ibnex_mutex); 2777 ASSERT(i_ddi_node_state(dip) >= DS_BOUND); 2778 2779 IBTF_DPRINTF_L4("ibnex", "\tpseudo_fininode: offlining the " 2780 "pseudo device"); 2781 rval = ibnex_offline_childdip(dip); 2782 if (rval != MDI_SUCCESS) { 2783 rval = NDI_FAILURE; 2784 IBTF_DPRINTF_L2("ibnex", "\tpseudo offline failed for " 2785 "dip %p with 0x%x", dip, rval); 2786 } 2787 2788 mutex_enter(&ibnex.ibnex_mutex); 2789 return (rval == MDI_SUCCESS ? IBNEX_SUCCESS : IBNEX_OFFLINE_FAILED); 2790 } 2791 2792 /* 2793 * IOCTL implementation to get api version number. 2794 */ 2795 static int 2796 ibnex_ctl_get_api_ver(dev_t dev, int cmd, intptr_t arg, int mode, 2797 cred_t *credp, int *rvalp) 2798 { 2799 ibnex_ctl_api_ver_t api_ver; 2800 2801 IBTF_DPRINTF_L4("ibnex", "\tctl_get_api_ver: cmd=%x, arg=%p, " 2802 "mode=%x, cred=%p, rval=%p, dev=0x%x", cmd, arg, mode, credp, 2803 rvalp, dev); 2804 2805 api_ver.api_ver_num = IBNEX_CTL_API_VERSION; 2806 2807 if (ddi_copyout(&api_ver, (void *)arg, sizeof (ibnex_ctl_api_ver_t), 2808 mode) != 0) { 2809 IBTF_DPRINTF_L2("ibnex", 2810 "\tctl_get_api_ver: ddi_copyout err"); 2811 return (EFAULT); 2812 } 2813 2814 return (0); 2815 } 2816 2817 /* 2818 * IOCTL implementation to get the list of HCAs 2819 */ 2820 static int 2821 ibnex_ctl_get_hca_list(dev_t dev, int cmd, intptr_t arg, int mode, 2822 cred_t *credp, int *rvalp) 2823 { 2824 ibnex_ctl_get_hca_list_t hca_list; 2825 int rv = 0; 2826 uint_t *in_nhcasp; 2827 uint_t nhcas, n; 2828 ib_guid_t *hca_guids; 2829 2830 IBTF_DPRINTF_L4("ibnex", "\tctl_get_hca_list: cmd=%x, arg=%p, " 2831 "mode=%x, cred=%p, rval=%p, dev=0x%x", cmd, arg, mode, credp, 2832 rvalp, dev); 2833 2834 #ifdef _MULTI_DATAMODEL 2835 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 2836 ibnex_ctl_get_hca_list_32_t hca_list_32; 2837 2838 if (ddi_copyin((void *)arg, &hca_list_32, 2839 sizeof (ibnex_ctl_get_hca_list_32_t), mode) != 0) { 2840 IBTF_DPRINTF_L2("ibnex", 2841 "\tctl_get_hca_list: ddi_copyin err 1"); 2842 return (EFAULT); 2843 } 2844 2845 hca_list.hca_guids_alloc_sz = hca_list_32.hca_guids_alloc_sz; 2846 hca_list.hca_guids = 2847 (ib_guid_t *)(uintptr_t)hca_list_32.hca_guids; 2848 in_nhcasp = &((ibnex_ctl_get_hca_list_32_t *)arg)->nhcas; 2849 } else 2850 #endif 2851 { 2852 if (ddi_copyin((void *)arg, &hca_list, 2853 sizeof (ibnex_ctl_get_hca_list_t), mode) != 0) { 2854 IBTF_DPRINTF_L2("ibnex", 2855 "\tctl_get_hca_list: ddi_copyin err 2"); 2856 return (EFAULT); 2857 } 2858 2859 in_nhcasp = &((ibnex_ctl_get_hca_list_t *)arg)->nhcas; 2860 } 2861 2862 nhcas = ibt_get_hca_list(&hca_guids); 2863 2864 /* copy number of hcas to user space */ 2865 if (ddi_copyout(&nhcas, in_nhcasp, sizeof (uint_t), mode) != 0) { 2866 IBTF_DPRINTF_L2("ibnex", 2867 "\tctl_get_hca_list: ddi_copyout err 1"); 2868 rv = EFAULT; 2869 goto out; 2870 } 2871 2872 n = MIN(nhcas, hca_list.hca_guids_alloc_sz); 2873 if (n == 0) 2874 goto out; 2875 2876 /* copy HCA guids to user space */ 2877 if (ddi_copyout(hca_guids, hca_list.hca_guids, 2878 n * sizeof (ib_guid_t), mode) != 0) { 2879 IBTF_DPRINTF_L2("ibnex", 2880 "\tctl_get_hca_list: ddi_copyout err 2"); 2881 rv = EFAULT; 2882 } 2883 2884 out: 2885 if (nhcas > 0) 2886 ibt_free_hca_list(hca_guids, nhcas); 2887 2888 return (rv); 2889 } 2890 2891 #define IBNEX_CTL_CP_HCA_INFO(x, y, driver_name, instance, device_path, \ 2892 device_path_alloc_sz, device_path_len) \ 2893 { \ 2894 (x)->hca_node_guid = (y)->hca_node_guid; \ 2895 (x)->hca_si_guid = (y)->hca_si_guid; \ 2896 (x)->hca_nports = (y)->hca_nports; \ 2897 (x)->hca_flags = (y)->hca_flags; \ 2898 (x)->hca_flags2 = (y)->hca_flags2; \ 2899 (x)->hca_vendor_id = (y)->hca_vendor_id; \ 2900 (x)->hca_device_id = (y)->hca_device_id; \ 2901 (x)->hca_version_id = (y)->hca_version_id; \ 2902 (x)->hca_max_chans = (y)->hca_max_chans; \ 2903 (x)->hca_max_chan_sz = (y)->hca_max_chan_sz; \ 2904 (x)->hca_max_sgl = (y)->hca_max_sgl; \ 2905 (x)->hca_max_cq = (y)->hca_max_cq; \ 2906 (x)->hca_max_cq_sz = (y)->hca_max_cq_sz; \ 2907 (x)->hca_page_sz = (y)->hca_page_sz; \ 2908 (x)->hca_max_memr = (y)->hca_max_memr; \ 2909 (x)->hca_max_memr_len = (y)->hca_max_memr_len; \ 2910 (x)->hca_max_mem_win = (y)->hca_max_mem_win; \ 2911 (x)->hca_max_rsc = (y)->hca_max_rsc; \ 2912 (x)->hca_max_rdma_in_chan = (y)->hca_max_rdma_in_chan; \ 2913 (x)->hca_max_rdma_out_chan = (y)->hca_max_rdma_out_chan; \ 2914 (x)->hca_max_ipv6_chan = (y)->hca_max_ipv6_chan; \ 2915 (x)->hca_max_ether_chan = (y)->hca_max_ether_chan; \ 2916 (x)->hca_max_mcg_chans = (y)->hca_max_mcg_chans; \ 2917 (x)->hca_max_mcg = (y)->hca_max_mcg; \ 2918 (x)->hca_max_chan_per_mcg = (y)->hca_max_chan_per_mcg; \ 2919 (x)->hca_max_partitions = (y)->hca_max_partitions; \ 2920 (x)->hca_local_ack_delay = (y)->hca_local_ack_delay; \ 2921 (x)->hca_max_port_sgid_tbl_sz = (y)->hca_max_port_sgid_tbl_sz; \ 2922 (x)->hca_max_port_pkey_tbl_sz = (y)->hca_max_port_pkey_tbl_sz; \ 2923 (x)->hca_max_pd = (y)->hca_max_pd; \ 2924 (x)->hca_max_ud_dest = (y)->hca_max_ud_dest; \ 2925 (x)->hca_max_srqs = (y)->hca_max_srqs; \ 2926 (x)->hca_max_srqs_sz = (y)->hca_max_srqs_sz; \ 2927 (x)->hca_max_srq_sgl = (y)->hca_max_srq_sgl; \ 2928 (x)->hca_max_cq_handlers = (y)->hca_max_cq_handlers; \ 2929 (x)->hca_reserved_lkey = (y)->hca_reserved_lkey; \ 2930 (x)->hca_max_fmrs = (y)->hca_max_fmrs; \ 2931 (x)->hca_max_lso_size = (y)->hca_max_lso_size; \ 2932 (x)->hca_max_lso_hdr_size = (y)->hca_max_lso_hdr_size; \ 2933 (x)->hca_max_inline_size = (y)->hca_max_inline_size; \ 2934 (x)->hca_max_cq_mod_count = (y)->hca_max_cq_mod_count; \ 2935 (x)->hca_max_cq_mod_usec = (y)->hca_max_cq_mod_usec; \ 2936 (x)->hca_fw_major_version = (y)->hca_fw_major_version; \ 2937 (x)->hca_fw_minor_version = (y)->hca_fw_minor_version; \ 2938 (x)->hca_fw_micro_version = (y)->hca_fw_micro_version; \ 2939 (x)->hca_ud_send_inline_sz = (y)->hca_ud_send_inline_sz; \ 2940 (x)->hca_conn_send_inline_sz = (y)->hca_conn_send_inline_sz; \ 2941 (x)->hca_conn_rdmaw_inline_overhead = \ 2942 (y)->hca_conn_rdmaw_inline_overhead; \ 2943 (x)->hca_recv_sgl_sz = (y)->hca_recv_sgl_sz; \ 2944 (x)->hca_ud_send_sgl_sz = (y)->hca_ud_send_sgl_sz; \ 2945 (x)->hca_conn_send_sgl_sz = (y)->hca_conn_send_sgl_sz; \ 2946 (x)->hca_conn_rdma_sgl_overhead = (y)->hca_conn_rdma_sgl_overhead; \ 2947 \ 2948 (void) strlcpy((x)->hca_driver_name, (driver_name), \ 2949 MAX_HCA_DRVNAME_LEN); \ 2950 (x)->hca_driver_instance = (instance); \ 2951 \ 2952 (x)->hca_device_path = (device_path); \ 2953 (x)->hca_device_path_len = (device_path_len); \ 2954 } 2955 2956 /* 2957 * IOCTL implementation to query HCA attributes 2958 */ 2959 static int 2960 ibnex_ctl_query_hca(dev_t dev, int cmd, intptr_t arg, int mode, 2961 cred_t *credp, int *rvalp) 2962 { 2963 int rv = 0; 2964 ibnex_ctl_query_hca_t *query_hca = NULL; 2965 #ifdef _MULTI_DATAMODEL 2966 ibnex_ctl_query_hca_32_t *query_hca_32 = NULL; 2967 #endif 2968 ibt_hca_attr_t *hca_attr = NULL; 2969 char driver_name[MAX_HCA_DRVNAME_LEN]; 2970 int instance; 2971 ib_guid_t hca_guid; 2972 char *device_path; 2973 uint_t device_path_alloc_sz, hca_device_path_len; 2974 char *hca_device_path = NULL; 2975 uint_t model; 2976 2977 IBTF_DPRINTF_L4("ibnex", "\tctl_query_hca: cmd=%x, arg=%p, " 2978 "mode=%x, cred=%p, rval=%p, dev=0x%x", cmd, arg, mode, credp, 2979 rvalp, dev); 2980 2981 switch (model = ddi_model_convert_from(mode & FMODELS)) { 2982 #ifdef _MULTI_DATAMODEL 2983 case DDI_MODEL_ILP32: 2984 query_hca_32 = kmem_zalloc( 2985 sizeof (ibnex_ctl_query_hca_32_t), KM_SLEEP); 2986 2987 if (ddi_copyin((void *)arg, query_hca_32, 2988 sizeof (ibnex_ctl_query_hca_32_t), mode) != 0) { 2989 IBTF_DPRINTF_L2("ibnex", 2990 "\tctl_query_hca: ddi_copyin err 1"); 2991 rv = EFAULT; 2992 goto out; 2993 } 2994 2995 hca_guid = query_hca_32->hca_guid; 2996 device_path = (char *)(uintptr_t)query_hca_32->hca_device_path; 2997 device_path_alloc_sz = query_hca_32->hca_device_path_alloc_sz; 2998 break; 2999 #endif 3000 default: 3001 query_hca = kmem_zalloc(sizeof (ibnex_ctl_query_hca_t), 3002 KM_SLEEP); 3003 3004 if (ddi_copyin((void *)arg, query_hca, 3005 sizeof (ibnex_ctl_query_hca_t), mode) != 0) { 3006 IBTF_DPRINTF_L2("ibnex", 3007 "\tctl_query_hca: ddi_copyin err 2"); 3008 rv = EFAULT; 3009 goto out; 3010 } 3011 3012 hca_guid = query_hca->hca_guid; 3013 device_path = query_hca->hca_device_path; 3014 device_path_alloc_sz = query_hca->hca_device_path_alloc_sz; 3015 break; 3016 } 3017 3018 hca_attr = kmem_zalloc(sizeof (ibt_hca_attr_t), KM_SLEEP); 3019 hca_device_path = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 3020 3021 if (ibtl_ibnex_query_hca_byguid(hca_guid, hca_attr, 3022 driver_name, sizeof (driver_name), &instance, hca_device_path) 3023 != IBT_SUCCESS) { 3024 rv = ENXIO; 3025 goto out; 3026 } 3027 3028 hca_device_path_len = strlen(hca_device_path) + 1; 3029 3030 switch (model) { 3031 char *device_path64; 3032 #ifdef _MULTI_DATAMODEL 3033 caddr32_t device_path32; 3034 case DDI_MODEL_ILP32: 3035 3036 if (device_path_alloc_sz >= hca_device_path_len) 3037 device_path32 = (uintptr_t)device_path; 3038 else 3039 device_path32 = (uintptr_t)NULL; 3040 3041 IBNEX_CTL_CP_HCA_INFO(&query_hca_32->hca_info, hca_attr, 3042 driver_name, instance, device_path32, 3043 device_path_alloc_sz, hca_device_path_len); 3044 3045 /* copy hca information to the user space */ 3046 if (ddi_copyout(&query_hca_32->hca_info, 3047 &((ibnex_ctl_query_hca_32_t *)arg)->hca_info, 3048 sizeof (ibnex_ctl_hca_info_32_t), mode) != 0) { 3049 IBTF_DPRINTF_L2("ibnex", 3050 "\tctl_query_hca: ddi_copyout err 1"); 3051 rv = EFAULT; 3052 goto out; 3053 } 3054 break; 3055 #endif 3056 default: 3057 if (device_path_alloc_sz >= hca_device_path_len) 3058 device_path64 = device_path; 3059 else 3060 device_path64 = NULL; 3061 3062 IBNEX_CTL_CP_HCA_INFO(&query_hca->hca_info, hca_attr, 3063 driver_name, instance, device_path64, 3064 device_path_alloc_sz, hca_device_path_len); 3065 3066 /* copy hca information to the user space */ 3067 if (ddi_copyout(&query_hca->hca_info, 3068 &((ibnex_ctl_query_hca_t *)arg)->hca_info, 3069 sizeof (ibnex_ctl_hca_info_t), mode) != 0) { 3070 IBTF_DPRINTF_L2("ibnex", 3071 "\tctl_query_hca: ddi_copyout err 2"); 3072 rv = EFAULT; 3073 goto out; 3074 } 3075 break; 3076 } 3077 3078 if (device_path_alloc_sz >= hca_device_path_len) { 3079 if (ddi_copyout(hca_device_path, 3080 device_path, 3081 hca_device_path_len, mode) != 0) { 3082 IBTF_DPRINTF_L2("ibnex", "\tctl_query_hca: " 3083 "ddi_copyout err copying device path"); 3084 rv = EFAULT; 3085 } 3086 } 3087 3088 out: 3089 if (query_hca) 3090 kmem_free(query_hca, sizeof (ibnex_ctl_query_hca_t)); 3091 #ifdef _MULTI_DATAMODEL 3092 if (query_hca_32) 3093 kmem_free(query_hca_32, sizeof (ibnex_ctl_query_hca_32_t)); 3094 #endif 3095 if (hca_attr) 3096 kmem_free(hca_attr, sizeof (ibt_hca_attr_t)); 3097 if (hca_device_path) 3098 kmem_free(hca_device_path, MAXPATHLEN); 3099 3100 return (rv); 3101 } 3102 3103 #define IBNEX_CTL_CP_PORT_INFO(x, y, sgid_tbl, pkey_tbl) \ 3104 { \ 3105 (x)->p_lid = (y)->p_opaque1; \ 3106 (x)->p_qkey_violations = (y)->p_qkey_violations; \ 3107 (x)->p_pkey_violations = (y)->p_pkey_violations; \ 3108 (x)->p_sm_sl = (y)->p_sm_sl; \ 3109 (x)->p_phys_state = (y)->p_phys_state; \ 3110 (x)->p_sm_lid = (y)->p_sm_lid; \ 3111 (x)->p_linkstate = (y)->p_linkstate; \ 3112 (x)->p_port_num = (y)->p_port_num; \ 3113 (x)->p_width_supported = (y)->p_width_supported; \ 3114 (x)->p_width_enabled = (y)->p_width_enabled; \ 3115 (x)->p_width_active = (y)->p_width_active; \ 3116 (x)->p_mtu = (y)->p_mtu; \ 3117 (x)->p_lmc = (y)->p_lmc; \ 3118 (x)->p_speed_supported = (y)->p_speed_supported; \ 3119 (x)->p_speed_enabled = (y)->p_speed_enabled; \ 3120 (x)->p_speed_active = (y)->p_speed_active; \ 3121 (x)->p_sgid_tbl = (sgid_tbl); \ 3122 (x)->p_sgid_tbl_sz = (y)->p_sgid_tbl_sz; \ 3123 (x)->p_pkey_tbl = (pkey_tbl); \ 3124 (x)->p_pkey_tbl_sz = (y)->p_pkey_tbl_sz; \ 3125 (x)->p_def_pkey_ix = (y)->p_def_pkey_ix; \ 3126 (x)->p_max_vl = (y)->p_max_vl; \ 3127 (x)->p_init_type_reply = (y)->p_init_type_reply; \ 3128 (x)->p_subnet_timeout = (y)->p_subnet_timeout; \ 3129 (x)->p_capabilities = (y)->p_capabilities; \ 3130 (x)->p_msg_sz = (y)->p_msg_sz; \ 3131 } 3132 3133 /* 3134 * IOCTL implementation to query HCA port attributes 3135 */ 3136 static int 3137 ibnex_ctl_query_hca_port(dev_t dev, int cmd, intptr_t arg, int mode, 3138 cred_t *credp, int *rvalp) 3139 { 3140 ibt_hca_portinfo_t *ibt_pi; 3141 uint_t nports; 3142 uint_t size = 0; 3143 int rv = 0; 3144 ibnex_ctl_query_hca_port_t *query_hca_port = NULL; 3145 ibnex_ctl_query_hca_port_32_t *query_hca_port_32 = NULL; 3146 uint_t sgid_tbl_sz; 3147 uint16_t pkey_tbl_sz; 3148 ibt_hca_attr_t hca_attr; 3149 3150 IBTF_DPRINTF_L4("ibnex", "\tctl_query_hca_port: cmd=%x, arg=%p, " 3151 "mode=%x, cred=%p, rval=%p, dev=0x%x", cmd, arg, mode, credp, 3152 rvalp, dev); 3153 3154 query_hca_port = kmem_zalloc(sizeof (ibnex_ctl_query_hca_port_t), 3155 KM_SLEEP); 3156 3157 #ifdef _MULTI_DATAMODEL 3158 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 3159 query_hca_port_32 = kmem_zalloc( 3160 sizeof (ibnex_ctl_query_hca_port_32_t), KM_SLEEP); 3161 3162 if (ddi_copyin((void *)arg, query_hca_port_32, 3163 sizeof (ibnex_ctl_query_hca_port_32_t), mode) != 0) { 3164 IBTF_DPRINTF_L2("ibnex", 3165 "\tctl_query_hca_port: ddi_copyin err 1"); 3166 rv = EFAULT; 3167 goto out; 3168 } 3169 3170 query_hca_port->hca_guid = query_hca_port_32->hca_guid; 3171 query_hca_port->port_num = query_hca_port_32->port_num; 3172 3173 query_hca_port->sgid_tbl = 3174 (ib_gid_t *)(uintptr_t)query_hca_port_32->sgid_tbl; 3175 query_hca_port->sgid_tbl_alloc_sz = 3176 query_hca_port_32->sgid_tbl_alloc_sz; 3177 3178 query_hca_port->pkey_tbl = 3179 (ib_pkey_t *)(uintptr_t)query_hca_port_32->pkey_tbl; 3180 query_hca_port->pkey_tbl_alloc_sz = 3181 query_hca_port_32->pkey_tbl_alloc_sz; 3182 3183 } else 3184 #endif 3185 { 3186 if (ddi_copyin((void *)arg, query_hca_port, 3187 sizeof (ibnex_ctl_query_hca_port_t), mode) != 0) { 3188 IBTF_DPRINTF_L2("ibnex", 3189 "\tctl_query_hca_port: ddi_copyin err 2"); 3190 rv = EFAULT; 3191 goto out; 3192 } 3193 } 3194 3195 if (ibt_query_hca_byguid(query_hca_port->hca_guid, &hca_attr) != 3196 IBT_SUCCESS) { 3197 rv = ENXIO; 3198 goto out; 3199 } 3200 3201 if (query_hca_port->port_num == 0 || 3202 query_hca_port->port_num > hca_attr.hca_nports) { 3203 rv = ENOENT; 3204 goto out; 3205 } 3206 3207 /* 3208 * Query hca port attributes and copy them to the user space. 3209 */ 3210 3211 if (ibt_query_hca_ports_byguid(query_hca_port->hca_guid, 3212 query_hca_port->port_num, &ibt_pi, &nports, &size) != IBT_SUCCESS) { 3213 rv = ENXIO; 3214 goto out; 3215 } 3216 3217 sgid_tbl_sz = MIN(query_hca_port->sgid_tbl_alloc_sz, 3218 ibt_pi->p_sgid_tbl_sz); 3219 3220 pkey_tbl_sz = MIN(query_hca_port->pkey_tbl_alloc_sz, 3221 ibt_pi->p_pkey_tbl_sz); 3222 3223 #ifdef _MULTI_DATAMODEL 3224 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 3225 IBNEX_CTL_CP_PORT_INFO( 3226 &query_hca_port_32->port_info, ibt_pi, 3227 query_hca_port_32->sgid_tbl, query_hca_port_32->pkey_tbl); 3228 3229 if (ddi_copyout(&query_hca_port_32->port_info, 3230 &((ibnex_ctl_query_hca_port_32_t *)arg)->port_info, 3231 sizeof (ibnex_ctl_hca_port_info_32_t), mode) != 0 || 3232 3233 ddi_copyout(ibt_pi->p_sgid_tbl, 3234 query_hca_port->sgid_tbl, 3235 sgid_tbl_sz * sizeof (ib_gid_t), mode) != 0 || 3236 3237 ddi_copyout(ibt_pi->p_pkey_tbl, 3238 query_hca_port->pkey_tbl, 3239 pkey_tbl_sz * sizeof (ib_pkey_t), mode) != 0) { 3240 3241 IBTF_DPRINTF_L2("ibnex", 3242 "\tctl_query_hca_port: ddi_copyout err 2"); 3243 rv = EFAULT; 3244 goto out; 3245 } 3246 } else 3247 #endif 3248 { 3249 IBNEX_CTL_CP_PORT_INFO( 3250 &query_hca_port->port_info, ibt_pi, 3251 query_hca_port->sgid_tbl, query_hca_port->pkey_tbl); 3252 3253 if (ddi_copyout(&query_hca_port->port_info, 3254 &((ibnex_ctl_query_hca_port_t *)arg)->port_info, 3255 sizeof (ibnex_ctl_hca_port_info_t), mode) != 0 || 3256 3257 ddi_copyout(ibt_pi->p_sgid_tbl, 3258 query_hca_port->sgid_tbl, 3259 sgid_tbl_sz * sizeof (ib_gid_t), mode) != 0 || 3260 3261 ddi_copyout(ibt_pi->p_pkey_tbl, 3262 query_hca_port->pkey_tbl, 3263 pkey_tbl_sz * sizeof (ib_pkey_t), mode) != 0) { 3264 3265 IBTF_DPRINTF_L2("ibnex", 3266 "\tctl_query_hca_port: ddi_copyout err 2"); 3267 rv = EFAULT; 3268 goto out; 3269 } 3270 } 3271 3272 out: 3273 if (size > 0) 3274 ibt_free_portinfo(ibt_pi, size); 3275 3276 if (query_hca_port) 3277 kmem_free(query_hca_port, sizeof (ibnex_ctl_query_hca_port_t)); 3278 3279 if (query_hca_port_32) 3280 kmem_free(query_hca_port_32, 3281 sizeof (ibnex_ctl_query_hca_port_32_t)); 3282 return (rv); 3283 } 3284