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