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