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