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