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