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