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