Home | History | Annotate | Download | only in common
      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 #include "cfga_ib.h"
     27 
     28 /*
     29  * cfga_ib.c:
     30  *	All cfgadm entry points that are defined in the config_admin(3X)
     31  *	needed for InfiniBand support are described here. These cfgadm
     32  *	interfaces issue ioctl(s) to the IB nexus driver. Attachment points
     33  *	supported are - IOC, VPPA, Port, HCA_SVC and Pseudo dynamic ap_ids,
     34  *	the HCA static ap_id, and the IB static ap_id.
     35  *
     36  *	Given InfiniBand bus is fabric based, #of dynamic ap_ids present are
     37  *	unknown at any given point of time. Hence this plugin uses a
     38  *	packed nvlist data structure to hold ap_id related information.
     39  *	The IB nexus driver allocates the nvlist data in the kernel
     40  *	and this plugin processes the data (it is freed by IB nexus driver).
     41  */
     42 
     43 
     44 /* function prototypes */
     45 static int		ib_get_link(di_devlink_t, void *);
     46 static icfga_ret_t	ib_physpath_to_devlink(char *, char **, int *);
     47 static const char	*ib_get_msg(uint_t, msgcvt_t *, uint_t);
     48 static void		ib_set_msg(char **, ...);
     49 static cfga_err_t	ib_err_msg(char **, cfga_ib_ret_t, const char *, int);
     50 static int		ib_verify_valid_apid(const char *);
     51 static cfga_ib_ret_t	ib_verify_params(const char *, const char *, char **);
     52 static void		ib_cleanup_after_devctl_cmd(devctl_hdl_t, nvlist_t *);
     53 static cfga_ib_ret_t	ib_setup_for_devctl_cmd(char *, boolean_t,
     54 			    devctl_hdl_t *, nvlist_t **);
     55 static cfga_ib_ret_t	ib_device_configured(devctl_hdl_t, nvlist_t *,
     56 			    ap_rstate_t *);
     57 static cfga_ib_ret_t	ib_device_connected(devctl_hdl_t, nvlist_t *,
     58 			    ap_ostate_t *);
     59 static cfga_ib_ret_t	ib_do_control_ioctl(char *, uint_t, uint_t, uint_t,
     60 			    void **, size_t *);
     61 cfga_err_t		cfga_change_state(cfga_cmd_t, const char *,
     62 			    const char *, struct cfga_confirm *,
     63 			    struct cfga_msg *, char **, cfga_flags_t);
     64 cfga_err_t		cfga_private_func(const char *, const char *,
     65 			    const char *, struct cfga_confirm *,
     66 			    struct cfga_msg *, char **, cfga_flags_t);
     67 cfga_err_t		cfga_test(const char *, const char *, struct cfga_msg *,
     68 			    char **, cfga_flags_t);
     69 static cfga_ib_ret_t	ib_fill_static_apids(char *, cfga_list_data_t *);
     70 cfga_err_t		cfga_list_ext(const char *, cfga_list_data_t **, int *,
     71 			    const char *, const char *, char **, cfga_flags_t);
     72 void			cfga_msg(struct cfga_msg *, const char *);
     73 cfga_err_t		cfga_help(struct cfga_msg *, const char *,
     74 			    cfga_flags_t);
     75 static int		ib_confirm(struct cfga_confirm *, char *);
     76 static char 		*ib_get_devicepath(const char *);
     77 
     78 
     79 /* External function prototypes */
     80 extern cfga_ib_ret_t	ib_rcm_offline(const char *, char **, char *,
     81 			    cfga_flags_t);
     82 extern cfga_ib_ret_t	ib_rcm_online(const char *, char **, char *,
     83 			    cfga_flags_t);
     84 extern cfga_ib_ret_t	ib_rcm_remove(const char *, char **, char *,
     85 			    cfga_flags_t);
     86 extern int		ib_add_service(char **);
     87 extern int		ib_delete_service(char **);
     88 extern int		ib_list_services(struct cfga_msg *, char **);
     89 
     90 
     91 /* Globals */
     92 int		cfga_version = CFGA_HSL_V2;	/* Set the version number for */
     93 						/* the cfgadm library's use. */
     94 
     95 static char	*ib_help[] = {	/* Help messages */
     96 	NULL,
     97 	/* CFGA_IB_HELP_HEADER */	"IB specific commands:\n",
     98 	/* CFGA_IB_HELP_CONFIG */	"cfgadm -c [configure|unconfigure] "
     99 	    "ap_id [ap_id...]\n",
    100 	/* CFGA_IB_HELP_LIST */		"cfgadm -x list_clients hca_ap_id "
    101 	    "[hca_ap_id...]\n",
    102 	/* CFGA_IB_HELP_UPD_PKEY */	"cfgadm -x update_pkey_tbls ib\n",
    103 	/* CFGA_IB_HELP_CONF_FILE1 */	"cfgadm -o comm=[port|vppa|hca-svc],"
    104 	    "service=<name> -x [add_service|delete_service] ib\n",
    105 	/* CFGA_IB_HELP_CONF_FILE2 */	"cfgadm -x list_services ib\n",
    106 	/* CFGA_IB_HELP_UPD_IOC_CONF */ "cfgadm -x update_ioc_config "
    107 	    "[ib | ioc_apid]\n",
    108 	/* CFGA_IB_HELP_UNCFG_CLNTS */	"cfgadm -x unconfig_clients hca_ap_id "
    109 	    "[hca_ap_id...]\n",
    110 	/* CFGA_IB_HELP_UNKNOWN */	"\tunknown command or option: ",
    111 	NULL
    112 };
    113 
    114 static msgcvt_t	ib_error_msgs[] = {	/* Error messages */
    115 	/* CFGA_IB_OK */		{ CVT, CFGA_OK, "ok" },
    116 	/* CFGA_IB_UNKNOWN */		{ CVT, CFGA_LIB_ERROR,
    117 	    "Unknown message; internal error " },
    118 	/* CFGA_IB_INTERNAL_ERR */	{ CVT, CFGA_LIB_ERROR,
    119 	    "Internal error " },
    120 	/* CFGA_IB_INVAL_ARG_ERR */	{ CVT, CFGA_LIB_ERROR,
    121 	    "Invalid input args " },
    122 	/* CFGA_IB_OPTIONS_ERR */	{ CVT, CFGA_ERROR,
    123 	    "Hardware specific options not supported " },
    124 	/* CFGA_IB_AP_ERR */		{ CVT, CFGA_APID_NOEXIST, "" },
    125 	/* CFGA_IB_DEVCTL_ERR */	{ CVT, CFGA_LIB_ERROR,
    126 	    "Cannot issue devctl to " },
    127 	/* CFGA_IB_NOT_CONNECTED */	{ CVT, CFGA_INSUFFICENT_CONDITION,
    128 	    "No device connected to " },
    129 	/* CFGA_IB_NOT_CONFIGURED */	{ CVT, CFGA_INSUFFICENT_CONDITION,
    130 	    "No device configured to " },
    131 	/* CFGA_IB_ALREADY_CONNECTED */	{ CVT, CFGA_INSUFFICENT_CONDITION,
    132 	    "already connected; cannot connect again " },
    133 	/* CFGA_IB_ALREADY_CONFIGURED */ { CVT, CFGA_INSUFFICENT_CONDITION,
    134 	    "already configured " },
    135 	/* CFGA_IB_CONFIG_OP_ERR */	{ CVT, CFGA_ERROR,
    136 	    "configure operation failed " },
    137 	/* CFGA_IB_UNCONFIG_OP_ERR */	{ CVT, CFGA_ERROR,
    138 	    "unconfigure operation failed " },
    139 	/* CFGA_IB_OPEN_ERR */		{ CVT, CFGA_LIB_ERROR, "Cannot open " },
    140 	/* CFGA_IB_IOCTL_ERR */		{ CVT, CFGA_LIB_ERROR,
    141 	    "Driver ioctl failed " },
    142 	/* CFGA_IB_BUSY_ERR */		{ CVT, CFGA_SYSTEM_BUSY, " " },
    143 	/* CFGA_IB_ALLOC_FAIL */	{ CVT, CFGA_LIB_ERROR,
    144 	    "Memory allocation failure " },
    145 	/* CFGA_IB_OPNOTSUPP */		{ CVT, CFGA_OPNOTSUPP,
    146 	    "Operation not supported " },
    147 	/* CFGA_IB_INVAL_APID_ERR */	{ CVT, CFGA_LIB_ERROR,
    148 	    "Invalid ap_id supplied " },
    149 	/* CFGA_IB_DEVLINK_ERR */	{ CVT, CFGA_LIB_ERROR,
    150 	    "Could not find /dev/cfg link for " },
    151 	/* CFGA_IB_PRIV_ERR */		{ CVT, CFGA_PRIV, " " },
    152 	/* CFGA_IB_NVLIST_ERR */	{ CVT, CFGA_ERROR,
    153 	    "Internal error (nvlist) " },
    154 	/* CFGA_IB_HCA_LIST_ERR */	{ CVT, CFGA_ERROR,
    155 	    "Listing HCA's clients failed " },
    156 	/* CFGA_IB_HCA_UNCONFIG_ERR */	{ CVT, CFGA_ERROR,
    157 	    "Unconfiguring HCA's clients failed " },
    158 	/* CFGA_IB_UPD_PKEY_TBLS_ERR */	{ CVT, CFGA_ERROR,
    159 	    "Updating P_Key tables failed " },
    160 	/* CFGA_IB_RCM_HANDLE_ERR */	{ CVT, CFGA_ERROR,
    161 	    "Opening ib.conf file failed " },
    162 	/* CFGA_IB_LOCK_FILE_ERR */	{ CVT, CFGA_LIB_ERROR,
    163 	    "Locking ib.conf file failed " },
    164 	/* CFGA_IB_UNLOCK_FILE_ERR */	{ CVT, CFGA_LIB_ERROR,
    165 	    "Unlocking ib.conf file failed " },
    166 	/* CFGA_IB_COMM_INVAL_ERR */	{ CVT, CFGA_INVAL,
    167 	    "Communication type incorrectly specified " },
    168 	/* CFGA_IB_SVC_INVAL_ERR */	{ CVT, CFGA_INVAL,
    169 	    "Service name incorrectly specified " },
    170 	/* CFGA_IB_SVC_LEN_ERR_ERR */	{ CVT, CFGA_INVAL,
    171 	    "Service name len should be <= to 4, " },
    172 	/* CFGA_IB_SVC_EXISTS_ERR */	{ CVT, CFGA_INVAL, " "},
    173 	/* CFGA_IB_SVC_NO_EXIST_ERR */	{ CVT, CFGA_INVAL, " " },
    174 	/* CFGA_IB_UCFG_CLNTS_ERR */	{ CVT, CFGA_INVAL,
    175 	    "unconfig_clients failed for HCA " },
    176 	/* CFGA_IB_INVALID_OP_ERR */	{ CVT, CFGA_OPNOTSUPP, "on " },
    177 	/* CFGA_IB_RCM_HANDLE */	{ CVT, CFGA_ERROR,
    178 	    "cannot get RCM handle "},
    179 	/* CFGA_IB_RCM_ONLINE_ERR */	{ CVT, CFGA_SYSTEM_BUSY,
    180 	    "failed to online: "},
    181 	/* CFGA_IB_RCM_OFFLINE_ERR */	{ CVT, CFGA_SYSTEM_BUSY,
    182 	    "failed to offline: "}
    183 };
    184 
    185 /*
    186  * these are the only valid sub-options for services.
    187  */
    188 static char		*ib_service_subopts[] = {
    189 				"comm",
    190 				"service",
    191 				NULL
    192 			};
    193 
    194 /* Communication Service name : "port" or "vppa" or "hca-svc" */
    195 static char		*comm_name = NULL;
    196 
    197 char 			*service_name = NULL;	/* service name */
    198 ib_service_type_t	service_type = IB_NONE;	/* service type */
    199 
    200 
    201 /* ========================================================================= */
    202 /*
    203  * The next two funcs are imported from cfgadm_scsi.
    204  * ib_physpath_to_devlink is the only func directly used by cfgadm_ib.
    205  * ib_get_link supports it.
    206  */
    207 
    208 /*
    209  * Function:
    210  *	ib_get_link
    211  * Input:
    212  *	devlink		- devlink for the device path
    213  *	arg		- argument passed to this "walker" function
    214  * Output:
    215  *	NONE
    216  * Returns:
    217  *	Continue "walking" or not
    218  * Description:
    219  *	Routine to search the /dev directory or a subtree of /dev.
    220  */
    221 static int
    222 ib_get_link(di_devlink_t devlink, void *arg)
    223 {
    224 	walk_link_t	*larg = (walk_link_t *)arg;
    225 
    226 	/*
    227 	 * When path is specified, it's the node path without minor
    228 	 * name. Therefore, the ../.. prefixes needs to be stripped.
    229 	 */
    230 	if (larg->path) {
    231 		char *content = (char *)di_devlink_content(devlink);
    232 		char *start = strstr(content, "/devices/");
    233 
    234 		/* line content must have minor node */
    235 		if (start == NULL ||
    236 		    strncmp(start, larg->path, larg->len) != 0 ||
    237 		    start[larg->len] != ':') {
    238 			return (DI_WALK_CONTINUE);
    239 		}
    240 	}
    241 
    242 	*(larg->linkpp) = strdup(di_devlink_path(devlink));
    243 	return (DI_WALK_TERMINATE);
    244 }
    245 
    246 
    247 /*
    248  * Function:
    249  *	ib_physpath_to_devlink
    250  * Input:
    251  *	node_path	- Physical path of the ap_id node
    252  * Output:
    253  *	logpp		- Logical path to the ap_id node
    254  *	l_errnop	- "errno"
    255  * Returns:
    256  *	ICFGA_OK if everything was fine; otherwise an error with
    257  *	l_errnop set.
    258  * Description:
    259  *	Given a physical path to an ap_id ensure that it exists
    260  */
    261 /* ARGSUSED */
    262 static icfga_ret_t
    263 ib_physpath_to_devlink(char *node_path, char **logpp, int *l_errnop)
    264 {
    265 	char			*minor_path;
    266 	walk_link_t		larg;
    267 	di_devlink_handle_t	hdl;
    268 
    269 	if ((hdl = di_devlink_init(NULL, 0)) == NULL) {
    270 		*l_errnop = errno;
    271 		return (ICFGA_LIB_ERR);
    272 	}
    273 
    274 	*logpp = NULL;
    275 	larg.linkpp = logpp;
    276 	minor_path = (char *)node_path + strlen("/devices");
    277 	larg.path = NULL;
    278 	larg.len = 0;
    279 
    280 	(void) di_devlink_walk(hdl, "^cfg/", minor_path, DI_PRIMARY_LINK,
    281 	    (void *)&larg, ib_get_link);
    282 
    283 	di_devlink_fini(&hdl);
    284 
    285 	if (*logpp == NULL) {
    286 		*l_errnop = errno;
    287 		return (ICFGA_LIB_ERR);
    288 	}
    289 
    290 	return (ICFGA_OK);
    291 }
    292 
    293 
    294 /* ========================================================================= */
    295 /* Utilities */
    296 
    297 /*
    298  * Function:
    299  *	ib_get_msg
    300  * Input:
    301  *	msg_index	- Index into the message table
    302  *	msg_tbl		- the message table
    303  *	tbl_size	- size of the message table
    304  * Output:
    305  *	NONE
    306  * Returns:
    307  *	Message string if valid, otherwise an error
    308  * Description:
    309  *	Given the index into a table (msgcvt_t) of messages,
    310  *	get the message string, converting it to the proper
    311  *	locale if necessary.
    312  *
    313  *	NOTE: See cfga_ib.h
    314  */
    315 static const char *
    316 ib_get_msg(uint_t msg_index, msgcvt_t *msg_tbl, uint_t tbl_size)
    317 {
    318 	if (msg_index >= tbl_size) {
    319 		DPRINTF("get_error_msg: bad error msg index: %d\n", msg_index);
    320 		msg_index = CFGA_IB_UNKNOWN;
    321 	}
    322 
    323 	return ((msg_tbl[msg_index].intl) ?
    324 	    dgettext(TEXT_DOMAIN, msg_tbl[msg_index].msgstr) :
    325 	    msg_tbl[msg_index].msgstr);
    326 }
    327 
    328 
    329 /*
    330  * Function:
    331  *	ib_set_msg
    332  * Input:
    333  *	NONE
    334  * Output:
    335  *	ret_str	- Returned "message" string.
    336  * Returns:
    337  *	NONE
    338  * Description:
    339  *	Allocates and creates a message string (in *ret_str),
    340  *	by concatenating all the (char *) args together, in order.
    341  *	Last arg MUST be NULL.
    342  */
    343 static void
    344 ib_set_msg(char **ret_str, ...)
    345 {
    346 	char	*str;
    347 	size_t	total_len, ret_str_len;
    348 	va_list	valist;
    349 
    350 	va_start(valist, ret_str);
    351 
    352 	total_len = (*ret_str == NULL) ? 0 : strlen(*ret_str);
    353 
    354 	while ((str = va_arg(valist, char *)) != NULL) {
    355 		size_t	len = strlen(str);
    356 		char	*old_str = *ret_str;
    357 
    358 		ret_str_len = total_len + len + 1;
    359 		*ret_str = (char *)realloc(*ret_str, ret_str_len);
    360 		if (*ret_str == NULL) {
    361 			free(old_str);
    362 			DPRINTF("ib_set_msg: realloc failed.\n");
    363 			va_end(valist);
    364 			return;
    365 		}
    366 
    367 		(void) strlcpy(*ret_str + total_len, str, ret_str_len);
    368 		total_len += len;
    369 	}
    370 
    371 	va_end(valist);
    372 }
    373 
    374 
    375 /*
    376  * Function:
    377  *	ib_err_msg
    378  * Input:
    379  *	ap_id		- The attachment point of an IB fabric
    380  * Output:
    381  *	errstring	- Fill in the error msg string
    382  *	l_errno		- The "errno" to be filled in.
    383  * Returns:
    384  *	CFGA_IB_OK if we are able to fill in error msg;
    385  *	otherwise emit an error.
    386  * Description:
    387  *	Error message handling.
    388  *
    389  *	For the rv passed in, looks up the corresponding error message
    390  *	string(s), internationalized it if necessary, and concatenates
    391  *	it into a new memory buffer, and points *errstring to it.
    392  *	Note not all "rv"s will result in an error message return, as
    393  *	not all error conditions warrant a IB-specific error message.
    394  *
    395  *	Some messages may display ap_id or errno, which is why they are
    396  *	passed in.
    397  */
    398 static cfga_err_t
    399 ib_err_msg(char **errstring, cfga_ib_ret_t rv, const char *ap_id, int l_errno)
    400 {
    401 	char *errno_str;
    402 
    403 	if (errstring == NULL) {
    404 		return (ib_error_msgs[rv].cfga_err);
    405 	}
    406 
    407 	/* Generate the appropriate IB-specific error message(s) (if any). */
    408 	switch (rv) {
    409 	case CFGA_IB_OK:	/* Special case - do nothing.  */
    410 		break;
    411 	case CFGA_IB_AP_ERR:
    412 	case CFGA_IB_UNKNOWN:
    413 	case CFGA_IB_INTERNAL_ERR:
    414 	case CFGA_IB_OPTIONS_ERR:
    415 	case CFGA_IB_ALLOC_FAIL:
    416 		/* These messages require no additional strings passed. */
    417 		ib_set_msg(errstring, ERR_STR(rv), NULL);
    418 		break;
    419 	case CFGA_IB_NOT_CONNECTED:
    420 	case CFGA_IB_NOT_CONFIGURED:
    421 	case CFGA_IB_ALREADY_CONNECTED:
    422 	case CFGA_IB_ALREADY_CONFIGURED:
    423 	case CFGA_IB_CONFIG_OP_ERR:
    424 	case CFGA_IB_UNCONFIG_OP_ERR:
    425 	case CFGA_IB_BUSY_ERR:
    426 	case CFGA_IB_DEVLINK_ERR:
    427 	case CFGA_IB_RCM_HANDLE_ERR:
    428 	case CFGA_IB_RCM_ONLINE_ERR:
    429 	case CFGA_IB_RCM_OFFLINE_ERR:
    430 	case CFGA_IB_DEVCTL_ERR:
    431 	case CFGA_IB_COMM_INVAL_ERR:
    432 	case CFGA_IB_SVC_INVAL_ERR:
    433 	case CFGA_IB_SVC_LEN_ERR:
    434 	case CFGA_IB_SVC_EXISTS_ERR:
    435 	case CFGA_IB_SVC_NO_EXIST_ERR:
    436 	case CFGA_IB_LOCK_FILE_ERR:
    437 	case CFGA_IB_CONFIG_FILE_ERR:
    438 	case CFGA_IB_UNLOCK_FILE_ERR:
    439 	case CFGA_IB_UCFG_CLNTS_ERR:
    440 	case CFGA_IB_INVALID_OP_ERR:
    441 		/* These messages also print ap_id.  */
    442 		ib_set_msg(errstring, ERR_STR(rv), "ap_id: ", ap_id, "", NULL);
    443 		break;
    444 	case CFGA_IB_IOCTL_ERR:	/* These messages also print errno.  */
    445 	case CFGA_IB_NVLIST_ERR:
    446 		errno_str = l_errno ? strerror(l_errno) : "";
    447 		ib_set_msg(errstring, ERR_STR(rv), errno_str,
    448 		    l_errno ? "\n" : "", NULL);
    449 		break;
    450 	case CFGA_IB_OPEN_ERR: /* This messages also prints apid and errno.  */
    451 	case CFGA_IB_PRIV_ERR:
    452 	case CFGA_IB_HCA_LIST_ERR:
    453 	case CFGA_IB_OPNOTSUPP:
    454 	case CFGA_IB_INVAL_ARG_ERR:
    455 	case CFGA_IB_INVAL_APID_ERR:
    456 	case CFGA_IB_HCA_UNCONFIG_ERR:
    457 	case CFGA_IB_UPD_PKEY_TBLS_ERR:
    458 		errno_str = l_errno ? strerror(l_errno) : "";
    459 		ib_set_msg(errstring, ERR_STR(rv), "ap_id: ", ap_id, "\n",
    460 		    errno_str, l_errno ? "\n" : "", NULL);
    461 		break;
    462 	default:
    463 		DPRINTF("ib_err_msg: Unrecognized message index: %d\n", rv);
    464 		ib_set_msg(errstring, ERR_STR(CFGA_IB_INTERNAL_ERR), NULL);
    465 	}
    466 
    467 	/*
    468 	 * Determine the proper error code to send back to the cfgadm library.
    469 	 */
    470 	return (ib_error_msgs[rv].cfga_err);
    471 }
    472 
    473 
    474 /*
    475  * Function:
    476  *	ib_verify_valid_apid
    477  * Input:
    478  *	ap_id		- The attachment point of an IB fabric
    479  * Output:
    480  *	NONE
    481  * Returns:
    482  *	0 if ap_id is valid; otherwise -1
    483  * Description:
    484  *	Check if ap_id is valid or not.
    485  *	Ensure the ap_id passed is in the correct (physical ap_id) form:
    486  *	path/device:xx[.xx]+
    487  *	where xx is a one or two-digit number.
    488  *
    489  *	Note the library always calls the plugin with a physical ap_id.
    490  *	Called by ib_verify_params().
    491  */
    492 static int
    493 ib_verify_valid_apid(const char *ap_id)
    494 {
    495 	char	*l_ap_id;
    496 
    497 	if (ap_id == NULL) {
    498 		return (-1);
    499 	}
    500 
    501 	l_ap_id = strchr(ap_id, *MINOR_SEP);
    502 	l_ap_id++;
    503 
    504 	/* fabric apids */
    505 	if (strstr((char *)ap_id, IBNEX_FABRIC) != NULL) {
    506 		DPRINTF("ib_valid_apid: l_apid = %s\n", l_ap_id);
    507 		/* if the ap_id is "ib::" then report an error */
    508 		if ((strlen(l_ap_id) == strlen(IBNEX_FABRIC) + 1) ||
    509 		    (strlen(l_ap_id) == strlen(IBNEX_FABRIC) + 2)) {
    510 			return (-1);
    511 		}
    512 
    513 		if (strstr(l_ap_id, "...") != NULL) {
    514 			return (-1);
    515 		}
    516 
    517 	} else {	/* HCA ap_ids */
    518 		/* ap_id has 1..2 or more than 2 dots */
    519 		if (strstr(l_ap_id, "..") != NULL) {
    520 			return (-1);
    521 		}
    522 	}
    523 
    524 	return (0);
    525 }
    526 
    527 
    528 /*
    529  * Function:
    530  *	ib_verify_params
    531  * Input:
    532  *	ap_id		- The attachment point of an IB fabric
    533  *	options		- command options passed by the cfgadm(1M)
    534  *	errstring	- This contains error msg if command fails
    535  * Output:
    536  *	NONE
    537  * Returns:
    538  *	CFGA_IB_OK if parameters are valid; otherwise emit an error.
    539  * Description:
    540  *	Check if "options" and "errstring" are valid and if ap_id is
    541  *	valid or not.
    542  */
    543 static cfga_ib_ret_t
    544 ib_verify_params(const char *ap_id, const char *options, char **errstring)
    545 {
    546 	if (errstring != NULL) {
    547 		*errstring = NULL;
    548 	}
    549 
    550 	if (options != NULL) {
    551 		DPRINTF("ib_verify_params: h/w-specific options not "
    552 		    "supported.\n");
    553 		return (CFGA_IB_OPTIONS_ERR);
    554 	}
    555 
    556 	if (ib_verify_valid_apid(ap_id) != 0) {
    557 		DPRINTF("ib_verify_params: not an IB ap_id.\n");
    558 		return (CFGA_IB_AP_ERR);
    559 	}
    560 	return (CFGA_IB_OK);
    561 }
    562 
    563 
    564 /*
    565  * Function:
    566  *	ib_cleanup_after_devctl_cmd
    567  * Input:
    568  *	devctl_hdl	- Handler to devctl
    569  *	user_nvlistp	- Name-value-pair list pointer
    570  * Output:
    571  *	NONE
    572  * Returns:
    573  *	NONE
    574  * Description:
    575  *	Cleanup an initialization/setup done in the next function i.e.
    576  *	ib_setup_for_devctl_cmd().
    577  */
    578 static void
    579 ib_cleanup_after_devctl_cmd(devctl_hdl_t devctl_hdl, nvlist_t *user_nvlist)
    580 {
    581 	if (user_nvlist != NULL) {
    582 		nvlist_free(user_nvlist);
    583 	}
    584 
    585 	if (devctl_hdl != NULL) {
    586 		devctl_release(devctl_hdl);
    587 	}
    588 }
    589 
    590 
    591 /*
    592  * Function:
    593  *	ib_setup_for_devctl_cmd
    594  * Input:
    595  *	ap_id		- Attachment point for the IB device in question
    596  *	use_static_ap_id - Whether to use static ap_id or not flag
    597  * Output:
    598  *	devctl_hdl	- Handler to devctl
    599  *	user_nvlistp	- Name-value-pair list pointer
    600  * Returns:
    601  *	CFGA_IB_OK if it succeeds or an appropriate error.
    602  * Description:
    603  *	For any IB device  that is doing a cfgadm operation this function
    604  *	sets up a devctl_hdl and allocates a nvlist_t. The devctl_hdl
    605  *	is acquired using libdevice APIs. The nvlist_t is filled up with
    606  *	the ap_id (as a string). This nvlist_t is looked up in the kernel
    607  *	to figure out which ap_id we are currently dealing with.
    608  *
    609  *	"use_static_ap_id" flag tells if one should do a devctl_ap_acquire
    610  *	with IB_STATIC_APID or not. NOTE: We need an actual file-system
    611  *	vnode to do a devctl_ap_acquire.
    612  *
    613  *	NOTE: always call ib_cleanup_after_devctl_cmd() after this function.
    614  */
    615 static cfga_ib_ret_t
    616 ib_setup_for_devctl_cmd(char *ap_id, boolean_t use_static_ap_id,
    617     devctl_hdl_t *devctl_hdl, nvlist_t **user_nvlistp)
    618 {
    619 	char	*apid = (use_static_ap_id == B_TRUE) ? IB_STATIC_APID : ap_id;
    620 
    621 	/* Get a handle to the ap */
    622 	if ((*devctl_hdl = devctl_ap_acquire(apid, NULL)) == NULL) {
    623 		DPRINTF("ib_setup_for_devctl_cmd: devctl_ap_acquire "
    624 		    "errno: %d\n", errno);
    625 		ib_cleanup_after_devctl_cmd(*devctl_hdl, *user_nvlistp);
    626 		return (CFGA_IB_DEVCTL_ERR);
    627 	}
    628 
    629 	/* Set up to pass dynamic ap_id down to driver */
    630 	if (nvlist_alloc(user_nvlistp, NV_UNIQUE_NAME_TYPE, NULL) != 0) {
    631 		DPRINTF("ib_setup_for_devctl: nvlist_alloc errno: %d\n", errno);
    632 		*user_nvlistp = NULL;	/* Prevent possible incorrect free in */
    633 					/* ib_cleanup_after_devctl_cmd */
    634 		ib_cleanup_after_devctl_cmd(*devctl_hdl, *user_nvlistp);
    635 		return (CFGA_IB_NVLIST_ERR);
    636 	}
    637 
    638 	/* create a "string" entry */
    639 	if (nvlist_add_string(*user_nvlistp, IB_APID, ap_id) == -1) {
    640 		DPRINTF("ib_setup_for_devctl_cmd: nvlist_add_string failed. "
    641 		    "errno: %d\n", errno);
    642 		ib_cleanup_after_devctl_cmd(*devctl_hdl, *user_nvlistp);
    643 		return (CFGA_IB_NVLIST_ERR);
    644 	}
    645 
    646 	return (CFGA_IB_OK);
    647 }
    648 
    649 
    650 /*
    651  * Function:
    652  *	ib_device_configured
    653  * Input:
    654  *	hdl		- Handler to devctl
    655  *	nvl		- Name-value-pair list pointer
    656  * Output:
    657  *	rstate		- Receptacle state for the apid
    658  * Returns:
    659  *	CFGA_IB_OK if it succeeds or an appropriate error.
    660  * Description:
    661  *	Checks if there is a device actually configured to the ap? If so,
    662  *	issues a "devctl" to get the Receptacle state for that ap_id.
    663  *	If the ap_id is already configured it returns CFGA_IB_OK.
    664  *	Otherwise it returns a failure.
    665  */
    666 static cfga_ib_ret_t
    667 ib_device_configured(devctl_hdl_t hdl, nvlist_t *nvl, ap_rstate_t *rstate)
    668 {
    669 	cfga_ib_ret_t		rv;
    670 	devctl_ap_state_t	devctl_ap_state;
    671 
    672 	/* get ap_id's "devctl_ap_state" first */
    673 	if (devctl_ap_getstate(hdl, nvl, &devctl_ap_state) == -1) {
    674 		DPRINTF("ib_device_configured failed, errno: %d\n", errno);
    675 		return (CFGA_IB_DEVCTL_ERR);
    676 	}
    677 
    678 	rv = CFGA_IB_ALREADY_CONFIGURED;
    679 	*rstate = devctl_ap_state.ap_rstate;
    680 	if (devctl_ap_state.ap_ostate != AP_OSTATE_CONFIGURED) {
    681 		return (CFGA_IB_NOT_CONFIGURED);
    682 	}
    683 
    684 	return (rv);
    685 }
    686 
    687 
    688 /*
    689  * Function:
    690  *	ib_device_connected
    691  * Input:
    692  *	hdl		- Handler to devctl
    693  *	nvl		- Name-value-pair list pointer
    694  * Output:
    695  *	ostate		- Occupant state for the apid
    696  * Returns:
    697  *	CFGA_IB_OK if it succeeds or an appropriate error.
    698  * Description:
    699  *	Checks if there is a device actually connected to the ap? If so,
    700  *	issues a "devctl" to get the Occupant state for that ap_id.
    701  *	If the ap_id is already connected it returns CFGA_IB_OK.
    702  *	Otherwise it returns a failure.
    703  */
    704 static cfga_ib_ret_t
    705 ib_device_connected(devctl_hdl_t hdl, nvlist_t *list, ap_ostate_t *ostate)
    706 {
    707 	cfga_ib_ret_t		rv = CFGA_IB_ALREADY_CONNECTED;
    708 	devctl_ap_state_t	devctl_ap_state;
    709 
    710 	if (devctl_ap_getstate(hdl, list, &devctl_ap_state) == -1) {
    711 		DPRINTF("ib_device_connected failed, errno: %d\n", errno);
    712 		return (CFGA_IB_DEVCTL_ERR);
    713 	}
    714 
    715 	*ostate =  devctl_ap_state.ap_ostate;
    716 	if (devctl_ap_state.ap_rstate != AP_RSTATE_CONNECTED) {
    717 		return (CFGA_IB_NOT_CONNECTED);
    718 	}
    719 
    720 	return (rv);
    721 }
    722 
    723 
    724 /*
    725  * Function:
    726  *	ib_do_control_ioctl
    727  * Input:
    728  *	ap_id		- The dynamic attachment point of an IB device
    729  *	sub_cmd1	- Sub Command 1 to DEVCTL_AP_CONTROL devctl
    730  *	sub_cmd2	- Sub Command 2 to DEVCTL_AP_CONTROL devctl
    731  *				(Mandatory except for IBNEX_NUM_HCA_NODES,
    732  *				IBNEX_NUM_DEVICE_NODES,
    733  *				IBNEX_UPDATE_PKEY_TBLS &
    734  *				IBNEX_UPDATE_IOC_CONF)
    735  *	misc_arg	- optional arguments to DEVCTL_AP_CONTROL devctl
    736  * Output:
    737  *	descrp		- Buffer containing data back from kernel
    738  *	sizep		- Length of the buffer back from kernel
    739  * Returns:
    740  *	CFGA_IB_OK if it succeeds or an appropriate error.
    741  * Description:
    742  *	Issues DEVCTL_AP_CONTROL devctl with sub_cmd1 first which actually
    743  *	queries the IBNEX module in the kernel on the size of the data to
    744  *	be returned.
    745  *
    746  *	Next issues DEVCTL_AP_CONTROL devctl with a buffer of that much
    747  *	size and gets the actual data back.
    748  *	Passes the data and the size back to caller.
    749  */
    750 static cfga_ib_ret_t
    751 ib_do_control_ioctl(char *ap_id, uint_t sub_cmd1, uint_t sub_cmd2,
    752     uint_t misc_arg, void **descrp, size_t *sizep)
    753 {
    754 	int			fd = -1;
    755 	uint32_t		local_size = 0;
    756 	cfga_ib_ret_t		rv = CFGA_IB_OK;
    757 	struct ibnex_ioctl_data	ioctl_data;
    758 
    759 	/* try to open the ONLY static ap_id */
    760 	if ((fd = open(IB_STATIC_APID, O_RDONLY)) == -1) {
    761 		DPRINTF("ib_do_control_ioctl: open failed: "
    762 		    "errno = %d\n", errno);
    763 		/* Provides a more useful error msg */
    764 		rv = (errno == EBUSY) ? CFGA_IB_BUSY_ERR : CFGA_IB_OPEN_ERR;
    765 		return (rv);
    766 	}
    767 
    768 	/*
    769 	 * Find out first how large a buffer is needed?
    770 	 * NOTE: Ioctls only accept/return a 32-bit int for a get_size
    771 	 * to avoid 32/64 and BE/LE issues.
    772 	 */
    773 	ioctl_data.cmd = sub_cmd1;
    774 	ioctl_data.misc_arg = (uint_t)misc_arg;
    775 	ioctl_data.buf = (caddr_t)&local_size;
    776 	ioctl_data.bufsiz = sizeof (local_size);
    777 
    778 	/* Pass "ap_id" up for all other commands */
    779 	if (sub_cmd1 != IBNEX_NUM_DEVICE_NODES &&
    780 	    sub_cmd1 != IBNEX_NUM_HCA_NODES &&
    781 	    sub_cmd1 != IBNEX_UPDATE_PKEY_TBLS) {
    782 		ioctl_data.ap_id = (caddr_t)ap_id;
    783 		ioctl_data.ap_id_len = strlen(ap_id);
    784 
    785 	} else {
    786 		ioctl_data.ap_id = NULL;
    787 		ioctl_data.ap_id_len = 0;
    788 	}
    789 
    790 	if (ioctl(fd, DEVCTL_AP_CONTROL, &ioctl_data) != 0) {
    791 		DPRINTF("ib_do_control_ioctl: size ioctl ERR, errno: %d\n",
    792 		    errno);
    793 		(void) close(fd);
    794 		rv = (errno == EBUSY) ? CFGA_IB_BUSY_ERR : CFGA_IB_IOCTL_ERR;
    795 		return (rv);
    796 	}
    797 	*sizep = local_size;
    798 
    799 	/*
    800 	 * Don't do the second ioctl only in these cases
    801 	 * (NOTE: the data is returned in the first ioctl itself; if any)
    802 	 */
    803 	if (sub_cmd1 == IBNEX_NUM_DEVICE_NODES ||
    804 	    sub_cmd1 == IBNEX_NUM_HCA_NODES ||
    805 	    sub_cmd1 == IBNEX_UPDATE_PKEY_TBLS ||
    806 	    sub_cmd1 == IBNEX_UPDATE_IOC_CONF) {
    807 		(void) close(fd);
    808 		return (rv);
    809 	}
    810 
    811 	if (local_size == 0 || (*descrp = malloc(*sizep)) == NULL) {
    812 		DPRINTF("ib_do_control_ioctl: malloc failed\n");
    813 		(void) close(fd);
    814 		return (CFGA_IB_ALLOC_FAIL);
    815 	}
    816 
    817 	/* Get the data */
    818 	ioctl_data.cmd = sub_cmd2;
    819 	ioctl_data.buf = (caddr_t)*descrp;
    820 	ioctl_data.bufsiz = *sizep;
    821 
    822 	if (ioctl(fd, DEVCTL_AP_CONTROL, &ioctl_data) != 0) {
    823 		DPRINTF("ib_do_control_ioctl: ioctl failed: errno:%d\n", errno);
    824 		if (*descrp != NULL) {
    825 			free(*descrp);
    826 			*descrp = NULL;
    827 		}
    828 		rv = (errno == EBUSY) ? CFGA_IB_BUSY_ERR : CFGA_IB_IOCTL_ERR;
    829 	}
    830 
    831 	(void) close(fd);
    832 	return (rv);
    833 }
    834 
    835 
    836 /* ========================================================================== */
    837 /* Entry points */
    838 
    839 /*
    840  * Function:
    841  *	cfga_change_state
    842  * Input:
    843  *	state_change_cmd - Argument to the cfgadm -c command
    844  *	ap_id		- The attachment point of an IB fabric
    845  *	options		- State Change command options passed by the cfgadm(1M)
    846  *	confp		- Whether this command requires confirmation?
    847  *	msgp		- cfgadm error message for this plugin
    848  *	errstring	- This contains error msg if command fails
    849  *	flags		- Cfgadm(1m) flags
    850  * Output:
    851  *	NONE
    852  * Returns:
    853  *	If the command succeeded perform the cfgadm -c <cmd>;
    854  *	otherwise emit an error
    855  * Description:
    856  *	Do cfgadm -c <cmd>
    857  */
    858 /*ARGSUSED*/
    859 cfga_err_t
    860 cfga_change_state(cfga_cmd_t state_change_cmd, const char *ap_id,
    861     const char *options, struct cfga_confirm *confp, struct cfga_msg *msgp,
    862     char **errstring, cfga_flags_t flags)
    863 {
    864 	int		ret;
    865 	char		*devpath;
    866 	nvlist_t	*nvl = NULL;
    867 	boolean_t	static_ap_id = B_TRUE;
    868 	ap_rstate_t	rstate;
    869 	ap_ostate_t	ostate;
    870 	devctl_hdl_t	hdl = NULL;
    871 	cfga_ib_ret_t	rv = CFGA_IB_OK;
    872 
    873 	if ((rv = ib_verify_params(ap_id, options, errstring)) != CFGA_IB_OK) {
    874 		(void) cfga_help(msgp, options, flags);
    875 		return (ib_err_msg(errstring, CFGA_IB_INVAL_APID_ERR,
    876 		    ap_id, errno));
    877 	}
    878 
    879 	/*
    880 	 * All subcommands which can change state of device require
    881 	 * root privileges.
    882 	 */
    883 	if (geteuid() != 0) {
    884 		return (ib_err_msg(errstring, CFGA_IB_PRIV_ERR, ap_id, errno));
    885 	}
    886 
    887 	if (strstr((char *)ap_id, IB_FABRIC_APID_STR) == NULL)
    888 		static_ap_id = B_FALSE;
    889 
    890 	if ((rv = ib_setup_for_devctl_cmd((char *)ap_id, static_ap_id,
    891 	    &hdl, &nvl)) != CFGA_IB_OK) {
    892 		ib_cleanup_after_devctl_cmd(hdl, nvl);
    893 		return (ib_err_msg(errstring, rv, ap_id, errno));
    894 	}
    895 
    896 	switch (state_change_cmd) {
    897 	case CFGA_CMD_CONFIGURE:
    898 		rv = ib_device_connected(hdl, nvl, &ostate);
    899 		if (rv != CFGA_IB_ALREADY_CONNECTED) {
    900 			ret = (rv != CFGA_IB_NOT_CONNECTED) ?
    901 			    CFGA_IB_CONFIG_OP_ERR : rv;
    902 			ib_cleanup_after_devctl_cmd(hdl, nvl);
    903 			return (ib_err_msg(errstring, ret, ap_id, errno));
    904 		}
    905 
    906 		if (rv == CFGA_IB_ALREADY_CONNECTED) {
    907 			/*
    908 			 * special case handling for
    909 			 * SLM based cfgadm disconnects
    910 			 */
    911 			if (ostate == AP_OSTATE_CONFIGURED) {
    912 				ib_cleanup_after_devctl_cmd(hdl, nvl);
    913 				return (ib_err_msg(errstring,
    914 				    CFGA_IB_ALREADY_CONFIGURED, ap_id,
    915 				    errno));
    916 			}
    917 		}
    918 
    919 
    920 		rv = CFGA_IB_OK;	/* Other status don't matter */
    921 
    922 		if (devctl_ap_configure(hdl, nvl) != 0) {
    923 			DPRINTF("cfga_change_state: devctl_ap_configure "
    924 			    "failed. errno: %d\n", errno);
    925 			rv = CFGA_IB_CONFIG_OP_ERR;
    926 			break;
    927 		}
    928 
    929 		devpath = ib_get_devicepath(ap_id);
    930 		if (devpath == NULL) {
    931 			int i;
    932 
    933 			/*
    934 			 * try for some time as IB hotplug thread
    935 			 * takes a while to create the path
    936 			 * and then eventually give up
    937 			 */
    938 			for (i = 0;
    939 			    i < IB_RETRY_DEVPATH && (devpath == NULL); i++) {
    940 				sleep(IB_MAX_DEVPATH_DELAY);
    941 				devpath = ib_get_devicepath(ap_id);
    942 			}
    943 
    944 			if (devpath == NULL) {
    945 				DPRINTF("cfga_change_state: get device "
    946 				    "path failed i = %d\n", i);
    947 				rv = CFGA_IB_CONFIG_OP_ERR;
    948 				break;
    949 			}
    950 		}
    951 		S_FREE(devpath);
    952 		break;
    953 
    954 	case CFGA_CMD_UNCONFIGURE:
    955 		if ((rv = ib_device_connected(hdl, nvl, &ostate)) !=
    956 		    CFGA_IB_ALREADY_CONNECTED) {
    957 			ib_cleanup_after_devctl_cmd(hdl, nvl);
    958 			if (rv == CFGA_IB_DEVCTL_ERR)
    959 				rv = CFGA_IB_INVALID_OP_ERR;
    960 			return (ib_err_msg(errstring, rv, ap_id, errno));
    961 		}
    962 
    963 		/* check if it is already unconfigured */
    964 		if ((rv = ib_device_configured(hdl, nvl, &rstate)) ==
    965 		    CFGA_IB_NOT_CONFIGURED) {
    966 			ib_cleanup_after_devctl_cmd(hdl, nvl);
    967 			return (ib_err_msg(errstring, rv, ap_id, errno));
    968 		}
    969 
    970 		rv = CFGA_IB_OK;	/* Other statuses don't matter */
    971 
    972 		if (!ib_confirm(confp, IB_CONFIRM1)) {
    973 			ib_cleanup_after_devctl_cmd(hdl, nvl);
    974 			return (CFGA_NACK);
    975 		}
    976 
    977 		devpath = ib_get_devicepath(ap_id);
    978 		if (devpath == NULL) {
    979 			DPRINTF("cfga_change_state: get device path failed\n");
    980 			rv = CFGA_IB_UNCONFIG_OP_ERR;
    981 			break;
    982 		}
    983 
    984 		if ((rv = ib_rcm_offline(ap_id, errstring, devpath, flags)) !=
    985 		    CFGA_IB_OK) {
    986 			S_FREE(devpath);
    987 			break;
    988 		}
    989 
    990 		ret = devctl_ap_unconfigure(hdl, nvl);
    991 		if (ret != 0) {
    992 			DPRINTF("cfga_change_state: devctl_ap_unconfigure "
    993 			    "failed with errno: %d\n", errno);
    994 			rv = CFGA_IB_UNCONFIG_OP_ERR;
    995 			if (errno == EBUSY) {
    996 				rv = CFGA_IB_BUSY_ERR;
    997 			}
    998 			(void) ib_rcm_online(ap_id, errstring, devpath, flags);
    999 
   1000 		} else {
   1001 			(void) ib_rcm_remove(ap_id, errstring, devpath, flags);
   1002 		}
   1003 
   1004 		S_FREE(devpath);
   1005 		break;
   1006 
   1007 	case CFGA_CMD_LOAD:
   1008 	case CFGA_CMD_UNLOAD:
   1009 	case CFGA_CMD_CONNECT:
   1010 	case CFGA_CMD_DISCONNECT:
   1011 		(void) cfga_help(msgp, options, flags);
   1012 		rv = CFGA_IB_OPNOTSUPP;
   1013 		break;
   1014 
   1015 	case CFGA_CMD_NONE:
   1016 	default:
   1017 		(void) cfga_help(msgp, options, flags);
   1018 		rv = CFGA_IB_INTERNAL_ERR;
   1019 	}
   1020 
   1021 	ib_cleanup_after_devctl_cmd(hdl, nvl);
   1022 	return (ib_err_msg(errstring, rv, ap_id, errno));
   1023 }
   1024 
   1025 
   1026 /*
   1027  * Function:
   1028  *	cfga_private_func
   1029  * Input:
   1030  *	func		- The private function (passed w/ -x option)
   1031  *	ap_id		- The attachment point of an IB fabric
   1032  *	options		- Private function command options passed
   1033  *				by the cfgadm(1M)
   1034  *	confp		- Whether this command requires confirmation?
   1035  *	msgp		- cfgadm error message for this plugin
   1036  *	errstring	- This contains error msg if command fails
   1037  *	flags		- Cfgadm(1m) flags
   1038  * Output:
   1039  *	NONE
   1040  * Returns:
   1041  *	If the command succeeded perform the 'cfgadm -x <func>'; otherwise
   1042  *	return failure.
   1043  * Description:
   1044  *	Do cfgadm -x <func>
   1045  */
   1046 /*ARGSUSED*/
   1047 cfga_err_t
   1048 cfga_private_func(const char *func, const char *ap_id, const char *options,
   1049     struct cfga_confirm *confp, struct cfga_msg *msgp, char **errstring,
   1050     cfga_flags_t flags)
   1051 {
   1052 	int		len, ret, count = 0;
   1053 	char		*clnt_name = NULL, *alt_hca = NULL;
   1054 	char		*clnt_apid = NULL, *clnt_devpath = NULL;
   1055 	char		*name, *msg = NULL;
   1056 	char		*fab_apid = strstr((char *)ap_id, IBNEX_FABRIC);
   1057 	size_t		info_len = 0;
   1058 	uchar_t		*info = NULL;
   1059 	nvlist_t	*nvl;
   1060 	nvpair_t	*nvp = NULL;
   1061 	ap_rstate_t	rstate;
   1062 	devctl_hdl_t	hdl = NULL;
   1063 	cfga_ib_ret_t	rv;
   1064 
   1065 	if ((rv = ib_verify_params(ap_id, NULL, errstring)) != CFGA_IB_OK) {
   1066 		DPRINTF("cfga_private_func: ib_verify_params "
   1067 		    "failed with rv: %d\n", rv);
   1068 		return (ib_err_msg(errstring, rv, ap_id, errno));
   1069 	}
   1070 
   1071 	if (func == NULL) {
   1072 		DPRINTF("cfga_private_func: func is NULL\n");
   1073 		return (ib_err_msg(errstring, CFGA_IB_INVAL_ARG_ERR, ap_id,
   1074 		    errno));
   1075 	}
   1076 
   1077 	/*
   1078 	 * check first if IB static ap_id is "configured" for use
   1079 	 */
   1080 	if (fab_apid != NULL) {
   1081 		if ((rv = ib_setup_for_devctl_cmd(fab_apid, B_TRUE, &hdl,
   1082 		    &nvl)) != CFGA_IB_OK) {
   1083 			ib_cleanup_after_devctl_cmd(hdl, nvl);
   1084 			return (ib_err_msg(errstring, rv, ap_id, errno));
   1085 		}
   1086 		if ((rv = ib_device_configured(hdl, nvl, &rstate)) ==
   1087 		    CFGA_IB_NOT_CONFIGURED) {
   1088 			return (ib_err_msg(errstring, rv, ap_id, errno));
   1089 		}
   1090 		ib_cleanup_after_devctl_cmd(hdl, nvl);
   1091 	}
   1092 
   1093 	rv = CFGA_IB_OK;
   1094 	DPRINTF("cfga_private_func: func is %s\n", func);
   1095 	if (strcmp(func, IB_LIST_HCA_CLIENTS) == 0) {	/* -x list_clients */
   1096 
   1097 		/* only supported on HCA ap_ids */
   1098 		if (fab_apid != NULL) {
   1099 			DPRINTF("cfga_private_func: fabric apid supplied\n");
   1100 			return (ib_err_msg(errstring, CFGA_IB_INVALID_OP_ERR,
   1101 			    ap_id, errno));
   1102 		}
   1103 
   1104 		if ((msg = (char *)calloc(256, 1)) == NULL) {
   1105 			DPRINTF("cfga_private_func: malloc for msg failed. "
   1106 			    "errno: %d\n", errno);
   1107 			return (ib_err_msg(errstring, CFGA_IB_ALLOC_FAIL,
   1108 			    ap_id, errno));
   1109 		}
   1110 
   1111 		if ((rv = ib_do_control_ioctl((char *)ap_id, IBNEX_HCA_LIST_SZ,
   1112 		    IBNEX_HCA_LIST_INFO, 0, (void **)&info, &info_len)) != 0) {
   1113 			DPRINTF("cfga_private_func: "
   1114 			    "ib_do_control_ioctl list failed :%d\n", rv);
   1115 			S_FREE(msg);
   1116 			return (ib_err_msg(errstring, CFGA_IB_HCA_LIST_ERR,
   1117 			    ap_id, errno));
   1118 		}
   1119 
   1120 		if (nvlist_unpack((char *)info, info_len, &nvl, 0)) {
   1121 			DPRINTF("cfga_private_func: "
   1122 			    "nvlist_unpack 2 failed %p\n", info);
   1123 			S_FREE(info);
   1124 			S_FREE(msg);
   1125 			return (ib_err_msg(errstring, CFGA_IB_NVLIST_ERR, ap_id,
   1126 			    errno));
   1127 		}
   1128 
   1129 		(void) snprintf(msg, 256, "Ap_Id\t\t\t       IB Client\t\t "
   1130 		    "Alternate HCA\n");
   1131 		cfga_msg(msgp, msg);
   1132 
   1133 		/* Walk the NVPAIR data */
   1134 		while (nvp = nvlist_next_nvpair(nvl, nvp)) {
   1135 			name = nvpair_name(nvp);
   1136 			if (strcmp(name, "Client") == 0) {
   1137 				(void) nvpair_value_string(nvp, &clnt_name);
   1138 				++count;
   1139 			} else if (strcmp(name, "Alt_HCA") == 0) {
   1140 				(void) nvpair_value_string(nvp, &alt_hca);
   1141 				++count;
   1142 			} else if (strcmp(name, "ApID") == 0) {
   1143 				(void) nvpair_value_string(nvp, &clnt_apid);
   1144 				++count;
   1145 			}
   1146 
   1147 			/* check at the end; print message per client found */
   1148 			if (count == 3) {
   1149 				count = 0;
   1150 				(void) snprintf(msg, 256, "%-30s %-25s %s\n",
   1151 				    clnt_apid, clnt_name, alt_hca);
   1152 				cfga_msg(msgp, msg);
   1153 			}
   1154 		} /* end of while */
   1155 
   1156 		S_FREE(info);
   1157 		S_FREE(msg);
   1158 		nvlist_free(nvl);
   1159 
   1160 	/* -x unconfig_clients */
   1161 	} else if (strcmp(func, IB_UNCONFIG_HCA_CLIENTS) == 0) {
   1162 		/*
   1163 		 * -x unconfig_clients changes state by calling into RCM.
   1164 		 * It needs root privileges.
   1165 		 */
   1166 		if (geteuid() != 0) {
   1167 			return (ib_err_msg(errstring, CFGA_IB_PRIV_ERR, ap_id,
   1168 			    errno));
   1169 		}
   1170 
   1171 		/* only supported on HCA ap_ids */
   1172 		if (fab_apid != NULL) {
   1173 			DPRINTF("cfga_private_func: fabric apid supplied\n");
   1174 			return (ib_err_msg(errstring, CFGA_IB_INVALID_OP_ERR,
   1175 			    ap_id, errno));
   1176 		}
   1177 
   1178 		/*
   1179 		 * Check w/ user if it is ok to do this operation
   1180 		 * If the user fails to confirm, bailout
   1181 		 */
   1182 		if (!ib_confirm(confp, IB_CONFIRM3))
   1183 			return (CFGA_NACK);
   1184 
   1185 		/* Get device-paths of all the IOC/Port/Pseudo devices */
   1186 		rv = ib_do_control_ioctl((char *)ap_id, IBNEX_UNCFG_CLNTS_SZ,
   1187 		    IBNEX_UNCFG_CLNTS_INFO, 0, (void **)&info, &info_len);
   1188 		if (rv != 0) {
   1189 			DPRINTF("cfga_private_func: ib_do_control_ioctl "
   1190 			    "failed :%d\n", rv);
   1191 			return (ib_err_msg(errstring, CFGA_IB_HCA_UNCONFIG_ERR,
   1192 			    ap_id, errno));
   1193 		}
   1194 
   1195 		if (nvlist_unpack((char *)info, info_len, &nvl, 0)) {
   1196 			DPRINTF("cfga_private_func: nvlist_unpack failed %p\n",
   1197 			    info);
   1198 			S_FREE(info);
   1199 			return (ib_err_msg(errstring, CFGA_IB_NVLIST_ERR, ap_id,
   1200 			    errno));
   1201 		}
   1202 
   1203 		ret = 0;
   1204 
   1205 		/* Call RCM Offline on all device paths */
   1206 		while (nvp = nvlist_next_nvpair(nvl, nvp)) {
   1207 			name = nvpair_name(nvp);
   1208 			if (strcmp(name, "devpath") == 0) {
   1209 				(void) nvpair_value_string(nvp, &clnt_devpath);
   1210 				++count;
   1211 			} else if (strcmp(name, "ApID") == 0) {
   1212 				(void) nvpair_value_string(nvp, &clnt_apid);
   1213 				++count;
   1214 			}
   1215 
   1216 			/* handle the client unconfigure now */
   1217 			if (count == 2) {
   1218 				count = 0;	/* reset count */
   1219 
   1220 				DPRINTF("cfga_private_func: client apid = %s, "
   1221 				    "DevPath = %s\n", clnt_apid, clnt_devpath);
   1222 				if ((rv = ib_setup_for_devctl_cmd(clnt_apid,
   1223 				    B_TRUE, &hdl, &nvl)) != CFGA_IB_OK) {
   1224 					ib_cleanup_after_devctl_cmd(hdl, nvl);
   1225 					return (ib_err_msg(errstring, rv,
   1226 					    clnt_apid, errno));
   1227 				}
   1228 
   1229 				if ((rv = ib_device_configured(hdl, nvl,
   1230 				    &rstate)) == CFGA_IB_NOT_CONFIGURED)
   1231 					continue;
   1232 
   1233 				if ((rv = ib_rcm_offline(clnt_apid, errstring,
   1234 				    clnt_devpath, flags)) != CFGA_IB_OK) {
   1235 					DPRINTF("cfga_private_func: client rcm "
   1236 					    "offline failed for %s, with %d\n",
   1237 					    clnt_devpath, rv);
   1238 					ret = rv;
   1239 					continue;
   1240 				}
   1241 
   1242 				if (devctl_ap_unconfigure(hdl, nvl) != 0) {
   1243 					DPRINTF("cfga_private_func: client "
   1244 					    "unconfigure failed: errno %d\n",
   1245 					    errno);
   1246 					ret = CFGA_IB_UNCONFIG_OP_ERR;
   1247 					if (errno == EBUSY)
   1248 						ret = CFGA_IB_BUSY_ERR;
   1249 					(void) ib_rcm_online(clnt_apid,
   1250 					    errstring, clnt_devpath, flags);
   1251 					continue;
   1252 				} else {
   1253 					(void) ib_rcm_remove(clnt_apid,
   1254 					    errstring, clnt_devpath, flags);
   1255 				}
   1256 				ib_cleanup_after_devctl_cmd(hdl, nvl);
   1257 
   1258 			} /* end of if count == 2 */
   1259 
   1260 		} /* end of while */
   1261 
   1262 		S_FREE(info);
   1263 		nvlist_free(nvl);
   1264 		if (ret) {
   1265 			DPRINTF("cfga_private_func: unconfig_clients of %s "
   1266 			    "failed with %d\n", ap_id, ret);
   1267 			return (ib_err_msg(errstring, CFGA_IB_UCFG_CLNTS_ERR,
   1268 			    ap_id, errno));
   1269 		}
   1270 
   1271 	/* -x update_pkey_tbls */
   1272 	} else if (strcmp(func, IB_UPDATE_PKEY_TBLS) == 0) {
   1273 		/*
   1274 		 * Check for root privileges.
   1275 		 */
   1276 		if (geteuid() != 0) {
   1277 			return (ib_err_msg(errstring, CFGA_IB_PRIV_ERR, ap_id,
   1278 			    errno));
   1279 		}
   1280 
   1281 		/* CHECK: Only supported on fabric ap_ids */
   1282 		if (fab_apid == NULL || strcmp(fab_apid, IBNEX_FABRIC) != 0) {
   1283 			DPRINTF("cfga_private_func: fabric apid needed\n");
   1284 			return (ib_err_msg(errstring, CFGA_IB_INVALID_OP_ERR,
   1285 			    ap_id, errno));
   1286 		}
   1287 
   1288 		/* Check w/ user if it is ok to do this operation */
   1289 		len = strlen(IB_CONFIRM4) + 10;
   1290 		if ((msg = (char *)calloc(len, 1)) != NULL) {
   1291 			(void) snprintf(msg, len, "%s\nContinue", IB_CONFIRM4);
   1292 		}
   1293 
   1294 		/* If the user fails to confirm, return */
   1295 		if (!ib_confirm(confp, msg)) {
   1296 			free(msg);
   1297 			return (CFGA_NACK);
   1298 		}
   1299 		free(msg);
   1300 
   1301 		/* Update P_Key tables for all ports of all HCAs */
   1302 		rv = ib_do_control_ioctl((char *)ap_id, IBNEX_UPDATE_PKEY_TBLS,
   1303 		    0, 0, 0, &info_len);
   1304 
   1305 		if (rv != 0) {
   1306 			DPRINTF("cfga_private_func: ib_do_control_ioctl "
   1307 			    "failed :%d\n", rv);
   1308 			return (ib_err_msg(errstring, CFGA_IB_UPD_PKEY_TBLS_ERR,
   1309 			    ap_id, errno));
   1310 		}
   1311 
   1312 	/* -x [add_service|delete_service] */
   1313 	} else if ((strncmp(func, IB_ADD_SERVICE, 12) == 0) ||
   1314 	    (strncmp(func, IB_DELETE_SERVICE, 15) == 0)) {
   1315 		char			*subopts, *val;
   1316 		uint8_t			cmd;
   1317 
   1318 		/* check: Only supported on fabric ap_ids */
   1319 		if (fab_apid == NULL || strcmp(fab_apid, IBNEX_FABRIC) != 0) {
   1320 			DPRINTF("cfga_private_func: fabric apid needed\n");
   1321 			return (ib_err_msg(errstring, CFGA_IB_INVALID_OP_ERR,
   1322 			    ap_id, errno));
   1323 		}
   1324 
   1325 		/* Check for root privileges. */
   1326 		if (geteuid() != 0) {
   1327 			return (ib_err_msg(errstring, CFGA_IB_PRIV_ERR, ap_id,
   1328 			    errno));
   1329 		}
   1330 
   1331 		/* return error if no options are specified */
   1332 		subopts = (char *)options;
   1333 		if (subopts == (char *)NULL) {
   1334 			DPRINTF("cfga_private_func: no sub-options\n");
   1335 			(void) cfga_help(msgp, options, flags);
   1336 			return (ib_err_msg(errstring, CFGA_IB_INVAL_ARG_ERR,
   1337 			    ap_id, errno));
   1338 		}
   1339 
   1340 		/* parse options specified */
   1341 		while (*subopts != '\0') {
   1342 			switch (getsubopt(&subopts, ib_service_subopts, &val)) {
   1343 			case 0: /* comm */
   1344 				if (val == NULL) {
   1345 					(void) cfga_help(msgp, options, flags);
   1346 					S_FREE(service_name);
   1347 					return (ib_err_msg(errstring,
   1348 					    CFGA_IB_INVAL_ARG_ERR,
   1349 					    ap_id, errno));
   1350 				} else {
   1351 					comm_name = strdup(val);
   1352 					if (comm_name == NULL) {
   1353 						DPRINTF("comm sub-opt invalid "
   1354 						    "arg\n");
   1355 						S_FREE(service_name);
   1356 						return (ib_err_msg(errstring,
   1357 						    CFGA_IB_COMM_INVAL_ERR,
   1358 						    ap_id, errno));
   1359 					}
   1360 				}
   1361 				break;
   1362 
   1363 			case 1: /* service */
   1364 				if (val == NULL) {
   1365 					(void) cfga_help(msgp, options, flags);
   1366 					S_FREE(comm_name);
   1367 					return (ib_err_msg(errstring,
   1368 					    CFGA_IB_INVAL_ARG_ERR,
   1369 					    ap_id, errno));
   1370 				} else {
   1371 					/* service can be upto 4 long */
   1372 					if (strlen(val) == 0 ||
   1373 					    strlen(val) > 4) {
   1374 						DPRINTF("comm sub-opt invalid "
   1375 						    "service passed\n");
   1376 						S_FREE(comm_name);
   1377 						return (ib_err_msg(errstring,
   1378 						    CFGA_IB_SVC_LEN_ERR,
   1379 						    ap_id, errno));
   1380 					}
   1381 					service_name = strdup(val);
   1382 					if (service_name == NULL) {
   1383 						DPRINTF("comm sub-opt "
   1384 						    "internal error\n");
   1385 						S_FREE(comm_name);
   1386 						return (ib_err_msg(errstring,
   1387 						    CFGA_IB_SVC_INVAL_ERR,
   1388 						    ap_id, errno));
   1389 					}
   1390 				}
   1391 				break;
   1392 
   1393 			default:
   1394 				(void) cfga_help(msgp, options, flags);
   1395 				S_FREE(comm_name);
   1396 				S_FREE(service_name);
   1397 				return (ib_err_msg(errstring,
   1398 				    CFGA_IB_INVAL_ARG_ERR, ap_id, errno));
   1399 			}
   1400 		}
   1401 
   1402 		/* figure out the "operation" */
   1403 		if (strncasecmp(func, IB_ADD_SERVICE, 11) == 0)
   1404 			cmd = IBCONF_ADD_ENTRY;
   1405 		else if (strncasecmp(func, IB_DELETE_SERVICE, 14) == 0)
   1406 			cmd = IBCONF_DELETE_ENTRY;
   1407 		DPRINTF("Service = %s, Comm = %s, Operation = %s\n",
   1408 		    service_name, comm_name, func);
   1409 
   1410 		if (strncasecmp(comm_name, IBNEX_PORT_STR, 4) == 0)
   1411 			service_type = IB_PORT_SERVICE;
   1412 		else if (strncasecmp(comm_name, IBNEX_VPPA_STR, 4) == 0)
   1413 			service_type = IB_VPPA_SERVICE;
   1414 		else if (strncasecmp(comm_name, IBNEX_HCASVC_STR, 4) == 0)
   1415 			service_type = IB_HCASVC_SERVICE;
   1416 		else {
   1417 			(void) cfga_help(msgp, options, flags);
   1418 			S_FREE(comm_name);
   1419 			S_FREE(service_name);
   1420 			return (ib_err_msg(errstring, CFGA_IB_INVAL_ARG_ERR,
   1421 			    ap_id, errno));
   1422 		}
   1423 
   1424 		/* do the add/delete entry to the service */
   1425 		if (cmd == IBCONF_ADD_ENTRY) {
   1426 			if ((rv = ib_add_service(errstring)) != CFGA_IB_OK)
   1427 				DPRINTF("cfga_private_func: add failed\n");
   1428 		} else if (cmd == IBCONF_DELETE_ENTRY) {
   1429 			if ((rv = ib_delete_service(errstring)) != CFGA_IB_OK)
   1430 				DPRINTF("cfga_private_func: delete failed\n");
   1431 		}
   1432 
   1433 		S_FREE(comm_name);
   1434 		S_FREE(service_name);
   1435 		return (ib_err_msg(errstring, rv, ap_id, errno));
   1436 
   1437 	} else if (strncmp(func, IB_LIST_SERVICES, 13) == 0) {
   1438 
   1439 		/* check: Only supported on fabric ap_ids */
   1440 		if (fab_apid == NULL || strcmp(fab_apid, IBNEX_FABRIC) != 0) {
   1441 			DPRINTF("cfga_private_func: fabric apid needed\n");
   1442 			return (ib_err_msg(errstring, CFGA_IB_INVALID_OP_ERR,
   1443 			    ap_id, errno));
   1444 		}
   1445 
   1446 		/* do the list services */
   1447 		rv = ib_list_services(msgp, errstring);
   1448 		if (rv != CFGA_IB_OK) {
   1449 			DPRINTF("cfga_private_func: ib_list_services failed\n");
   1450 			return (ib_err_msg(errstring, rv, ap_id, errno));
   1451 		}
   1452 
   1453 	/* -x update_ioc_conf */
   1454 	} else if (strncmp(func, IB_UPDATE_IOC_CONF, 17) == 0) {
   1455 		uint_t misc_arg;
   1456 
   1457 		/* Supported only with root privilege */
   1458 		if (geteuid() != 0) {
   1459 			return (ib_err_msg(errstring, CFGA_IB_PRIV_ERR, ap_id,
   1460 			    errno));
   1461 		}
   1462 
   1463 		/*
   1464 		 * check: Only supported on fabric ap_id or IOC APID
   1465 		 * IOC APID does not have any commas in it.
   1466 		 */
   1467 		if (fab_apid == NULL ||
   1468 		    (fab_apid != NULL && strstr(fab_apid, ",") != NULL)) {
   1469 			DPRINTF("cfga_private_func: fabric/IOC apid needed\n");
   1470 			return (ib_err_msg(errstring, CFGA_IB_INVALID_OP_ERR,
   1471 			    ap_id, errno));
   1472 		}
   1473 
   1474 		/* Check w/ user if it is ok to do this operation */
   1475 		len = strlen(IB_CONFIRM5) + 10;
   1476 		if ((msg = (char *)calloc(len, 1)) != NULL) {
   1477 			(void) snprintf(msg, len, "%s\nContinue", IB_CONFIRM5);
   1478 		}
   1479 
   1480 		/* If the user fails to confirm, return */
   1481 		if (!ib_confirm(confp, msg)) {
   1482 			free(msg);
   1483 			return (CFGA_NACK);
   1484 		}
   1485 		free(msg);
   1486 
   1487 		misc_arg = (strcmp(fab_apid, IBNEX_FABRIC) == 0) ?
   1488 		    IBNEX_BASE_APID : IBNEX_DYN_APID;
   1489 
   1490 		/* Reprobe and update IOC(s) configuration */
   1491 		rv = ib_do_control_ioctl((char *)ap_id, IBNEX_UPDATE_IOC_CONF,
   1492 		    0, misc_arg, 0, &info_len);
   1493 
   1494 		if (rv != 0) {
   1495 			DPRINTF("cfga_private_func: ib_do_control_ioctl "
   1496 			    "failed :%d\n", rv);
   1497 			return (ib_err_msg(errstring, CFGA_IB_DEVCTL_ERR,
   1498 			    ap_id, errno));
   1499 		}
   1500 	} else {
   1501 		DPRINTF("cfga_private_func: unrecognized command.\n");
   1502 		(void) cfga_help(msgp, options, flags);
   1503 		errno = EINVAL;
   1504 		return (CFGA_INVAL);
   1505 	}
   1506 
   1507 	return (ib_err_msg(errstring, rv, ap_id, errno));
   1508 }
   1509 
   1510 
   1511 /*
   1512  * Function:
   1513  *	cfga_test
   1514  * Input:
   1515  *	ap_id		- The attachment point of an IB fabric
   1516  *	options		- Test command options passed by the cfgadm(1M)
   1517  *	msgp		- cfgadm error message for this plugin
   1518  *	errstring	- This contains error msg if command fails
   1519  *	flags		- Cfgadm(1m) flags
   1520  * Output:
   1521  *	NONE
   1522  * Returns:
   1523  *	CFGA_OPNOTSUPP
   1524  * Description:
   1525  *	Do "cfgadm -t"
   1526  */
   1527 /*ARGSUSED*/
   1528 cfga_err_t
   1529 cfga_test(const char *ap_id, const char *options, struct cfga_msg *msgp,
   1530     char **errstring, cfga_flags_t flags)
   1531 {
   1532 	(void) cfga_help(msgp, options, flags);
   1533 	return (CFGA_OPNOTSUPP);
   1534 }
   1535 
   1536 
   1537 /*
   1538  * Function:
   1539  *	ib_fill_static_apids
   1540  * Input:
   1541  *	ap_id		- The static attachment point of an IB device
   1542  *	clp		- The returned "list" information array
   1543  * Output:
   1544  *	NONE
   1545  * Returns:
   1546  *	Fills up the "list" information array for the static attachment point
   1547  * Description:
   1548  *	IB fabric supports two types of static attachment points.
   1549  *	One is fabric and other is for the HCAs. This fills up
   1550  *	"cfga_list_data_t" for static attachment points.
   1551  */
   1552 static cfga_ib_ret_t
   1553 ib_fill_static_apids(char *ap_id, cfga_list_data_t *clp)
   1554 {
   1555 	int	rv, l_err;
   1556 	char	*ap_id_log = NULL;
   1557 
   1558 	/* Get /dev/cfg path to corresponding to the physical ap_id */
   1559 	/* Remember ap_id_log must be freed */
   1560 	if ((cfga_ib_ret_t)ib_physpath_to_devlink(ap_id, &ap_id_log,
   1561 	    &l_err) != ICFGA_OK) {
   1562 		DPRINTF("ib_fill_static_apids: "
   1563 		    "ib_physpath_to_devlink failed\n");
   1564 		return (CFGA_IB_DEVLINK_ERR);
   1565 	}
   1566 	assert(ap_id_log != NULL);
   1567 
   1568 	/* Get logical ap-id corresponding to the physical */
   1569 	if (strstr(ap_id_log, CFGA_DEV_DIR) == NULL) {
   1570 		DPRINTF("ib_fill_static_apids: devlink doesn't contain "
   1571 		    "/dev/cfg\n");
   1572 		free(ap_id_log);
   1573 		return (CFGA_IB_DEVLINK_ERR);
   1574 	}
   1575 
   1576 	clp->ap_cond = CFGA_COND_OK;
   1577 	clp->ap_r_state = CFGA_STAT_CONNECTED;
   1578 	clp->ap_o_state = CFGA_STAT_CONFIGURED;
   1579 	clp->ap_class[0] = '\0';	/* Filled by libcfgadm */
   1580 	clp->ap_busy = 0;
   1581 	clp->ap_status_time = (time_t)-1;
   1582 	(void) snprintf(clp->ap_log_id, sizeof (clp->ap_log_id), "%s",
   1583 	    /* Strip off /dev/cfg/ */ ap_id_log + strlen(CFGA_DEV_DIR) + 1);
   1584 	(void) strlcpy(clp->ap_phys_id, ap_id, sizeof (clp->ap_phys_id));
   1585 
   1586 	/* Static IB apid */
   1587 	if (strstr((char *)ap_id, IB_FABRIC_APID_STR) != NULL)  {
   1588 		(void) strlcpy(clp->ap_type, IB_FABRIC_TYPE,
   1589 		    sizeof (clp->ap_type));	/* Fill in type */
   1590 		(void) strlcpy(clp->ap_info, IB_FABRIC_INFO,
   1591 		    sizeof (clp->ap_info));
   1592 
   1593 	} else {	/* Static HCA apid */
   1594 		size_t	size = 0;
   1595 		uchar_t	*data = NULL;
   1596 
   1597 		(void) strlcpy(clp->ap_type, IB_HCA_TYPE,
   1598 		    sizeof (clp->ap_type));	/* Fill in type */
   1599 
   1600 		rv = ib_do_control_ioctl(ap_id, IBNEX_HCA_VERBOSE_SZ,
   1601 		    IBNEX_HCA_VERBOSE_INFO, 0, (void **)&data, &size);
   1602 		if (rv != 0) {
   1603 			DPRINTF("ib_fill_static_apids: ib_do_control_ioctl "
   1604 			    "failed :%d\n", rv);
   1605 			free(ap_id_log);
   1606 			S_FREE(data);
   1607 			return (CFGA_IB_IOCTL_ERR);
   1608 		}
   1609 
   1610 		(void) strlcpy(clp->ap_info, (char *)data,
   1611 		    sizeof (clp->ap_info));
   1612 		S_FREE(data);
   1613 	}
   1614 	free(ap_id_log);
   1615 	return (CFGA_IB_OK);
   1616 }
   1617 
   1618 
   1619 /*
   1620  * Function:
   1621  *	cfga_list_ext
   1622  * Input:
   1623  *	ap_id		- The attachment point of an IB fabric
   1624  *	ap_id_list	- The returned "list" information array
   1625  *	nlistp		- Number of elements in the "list" information array
   1626  *	options		- List command options passed by the cfgadm(1M)
   1627  *	listopts	- "-s" specific options
   1628  *	errstring	- This contains error msg if command fails
   1629  *	flags		- Cfgadm(1m) flags
   1630  * Output:
   1631  *	NONE
   1632  * Returns:
   1633  *	If the command succeeded, cfgadm -l output otherwise an error
   1634  * Description:
   1635  *	Do cfgadm -l
   1636  */
   1637 /*ARGSUSED*/
   1638 cfga_err_t
   1639 cfga_list_ext(const char *ap_id, cfga_list_data_t **ap_id_list, int *nlistp,
   1640     const char *options, const char *listopts, char **errstring,
   1641     cfga_flags_t flags)
   1642 {
   1643 	int			expand = 0;
   1644 	int			i, index, count;
   1645 	int			show_dynamic = 0;
   1646 	size_t			num_devices = 0;
   1647 	size_t			num_hcas = 0;
   1648 	size_t			snap_size = 0;
   1649 	uchar_t			*snap_data = NULL;
   1650 	nvpair_t		*nvp = NULL;	/* for lint purposes */
   1651 	nvlist_t		*nvl = NULL;
   1652 	boolean_t		apid_matched = B_FALSE;	/* for valid ap_id */
   1653 	cfga_ib_ret_t		rv = CFGA_IB_OK;
   1654 	cfga_list_data_t	*clp = NULL;
   1655 
   1656 	if ((rv = ib_verify_params(ap_id, options, errstring)) != CFGA_IB_OK) {
   1657 		(void) cfga_help(NULL, options, flags);
   1658 		return (ib_err_msg(errstring, rv, ap_id, errno));
   1659 	}
   1660 
   1661 	/* make sure we have a valid ap_id_list */
   1662 	if (ap_id_list == NULL || nlistp == NULL) {
   1663 		DPRINTF("cfga_list_ext: list = NULL or nlistp = NULL\n");
   1664 		(void) cfga_help(NULL, options, flags);
   1665 		return (ib_err_msg(errstring, CFGA_IB_INVAL_ARG_ERR,
   1666 		    ap_id, errno));
   1667 	}
   1668 
   1669 	DPRINTF("cfga_list_ext: ap_id = %s\n", ap_id);
   1670 
   1671 	if ((flags & CFGA_FLAG_LIST_ALL) == CFGA_FLAG_LIST_ALL) {
   1672 		expand = 1;		/* -a flag passed */
   1673 	}
   1674 
   1675 	if (GET_DYN(ap_id) != NULL) {
   1676 		show_dynamic = 1;
   1677 	}
   1678 
   1679 	if ((expand == 1) &&	/* -a option passed */
   1680 	    (strstr((char *)ap_id, IB_FABRIC_APID_STR) != NULL)) {
   1681 		/*
   1682 		 * Figure out how many IOC/Port/Pseudo
   1683 		 * devices exist in the system?
   1684 		 */
   1685 		if ((rv = ib_do_control_ioctl((char *)ap_id,
   1686 		    IBNEX_NUM_DEVICE_NODES, 0, 0, 0, &num_devices)) !=
   1687 		    CFGA_IB_OK) {
   1688 			DPRINTF("cfga_list_ext: ib_do_control_ioctl "
   1689 			    "IBNEX_NUM_DEVICE_NODES failed :%d\n", rv);
   1690 			if (errno == ENOENT)
   1691 				return (CFGA_APID_NOEXIST);
   1692 			return (ib_err_msg(errstring, rv, ap_id, errno));
   1693 		}
   1694 
   1695 		DPRINTF("cfga_list_ext: num_devices = %d\n", num_devices);
   1696 	}
   1697 
   1698 	/* Figure out how many HCA nodes exist in the system. */
   1699 	if ((rv = ib_do_control_ioctl((char *)ap_id, IBNEX_NUM_HCA_NODES, 0, 0,
   1700 	    0, &num_hcas)) != CFGA_IB_OK) {
   1701 		DPRINTF("cfga_list_ext: ib_do_control_ioctl "
   1702 		    "IBNEX_NUM_HCA_NODES failed :%d\n", rv);
   1703 		if (errno == ENOENT)
   1704 			return (CFGA_APID_NOEXIST);
   1705 		return (ib_err_msg(errstring, rv, ap_id, errno));
   1706 	}
   1707 	DPRINTF("cfga_list_ext: num_hcas = %d\n", num_hcas);
   1708 
   1709 	/*
   1710 	 * No HCAs or IOC/VPPA/Port/HCA_SVC/Pseudo devices seen (non-IB system)
   1711 	 */
   1712 	if (!(num_hcas || num_devices)) {
   1713 		DPRINTF("cfga_list_ext: no IB devices found\n");
   1714 		return (CFGA_APID_NOEXIST);
   1715 	}
   1716 
   1717 	/*
   1718 	 * *nlistp contains to how many APIDs to show w/ cfgadm -l.
   1719 	 * If ap_id is "fabric" then
   1720 	 * 	*nlistp is all Dynamic Apids + One more for "fabric"
   1721 	 * If ap_id is "HCA" ap_id then
   1722 	 *	*nlistp is 1
   1723 	 * Note that each HCA is a static APID, so nlistp will be 1 always
   1724 	 * and this function will be called N times for each of the N HCAs
   1725 	 * in the host.
   1726 	 */
   1727 	if (strstr((char *)ap_id, IB_FABRIC_APID_STR) != NULL) {
   1728 		*nlistp = num_devices + 1;
   1729 
   1730 	} else {
   1731 		/* Assume it as a HCA ap_id */
   1732 		*nlistp = 1;
   1733 	}
   1734 
   1735 	/* Allocate storage for passing "list" info back */
   1736 	if ((*ap_id_list = (cfga_list_data_t *)calloc(*nlistp,
   1737 	    sizeof (cfga_list_data_t))) == NULL) {
   1738 		DPRINTF("cfga_list_ext: malloc for cfga_list_data_t failed. "
   1739 		    "errno: %d\n", errno);
   1740 		return (ib_err_msg(errstring, CFGA_IB_ALLOC_FAIL,
   1741 		    ap_id, errno));
   1742 	}
   1743 
   1744 	/*
   1745 	 * Only static ap_id is ib_fabric:
   1746 	 * If -a options isn't specified then only show the static ap_id.
   1747 	 */
   1748 	if (!show_dynamic) {
   1749 		clp = &(*ap_id_list[0]);
   1750 
   1751 		if ((rv = ib_fill_static_apids((char *)ap_id, clp)) !=
   1752 		    CFGA_IB_OK) {
   1753 			S_FREE(*ap_id_list);
   1754 			return (ib_err_msg(errstring, rv, ap_id, errno));
   1755 		}
   1756 		apid_matched = B_TRUE;
   1757 	}
   1758 
   1759 	/*
   1760 	 * No -a specified
   1761 	 * No HCAs or IOC/VPPA/HCA_SVC/Port/Pseudo devices seen (non-IB system)
   1762 	 */
   1763 	if (!expand || (!num_hcas && !num_devices)) {
   1764 		if (!show_dynamic)
   1765 			return (CFGA_OK);
   1766 	}
   1767 
   1768 	if (strstr((char *)ap_id, IB_FABRIC_APID_STR) != NULL) {
   1769 		rv = ib_do_control_ioctl((char *)ap_id, IBNEX_SNAPSHOT_SIZE,
   1770 		    IBNEX_GET_SNAPSHOT, IBNEX_DONOT_PROBE_FLAG,
   1771 		    (void **)&snap_data, &snap_size);
   1772 		if (rv != 0) {
   1773 			DPRINTF("cfga_list_ext: ib_do_control_ioctl "
   1774 			    "failed :%d\n", rv);
   1775 			S_FREE(*ap_id_list);
   1776 			S_FREE(snap_data);
   1777 			return (ib_err_msg(errstring, rv, ap_id, errno));
   1778 		}
   1779 
   1780 		if (nvlist_unpack((char *)snap_data, snap_size, &nvl, 0)) {
   1781 			DPRINTF("cfga_list_ext: nvlist_unpack 1 failed %p\n",
   1782 			    snap_data);
   1783 			S_FREE(*ap_id_list);
   1784 			S_FREE(snap_data);
   1785 			return (ib_err_msg(errstring, CFGA_IB_NVLIST_ERR,
   1786 			    ap_id, errno));
   1787 		}
   1788 
   1789 		/*
   1790 		 * In kernel a nvlist is build per ap_id which contains
   1791 		 * information that is displayed using cfgadm -l.
   1792 		 * For IB devices only these 6 items are shown:
   1793 		 *	ap_id, type, occupant, receptacle, condition and info
   1794 		 *
   1795 		 * In addition, one could specify a dynamic ap_id from
   1796 		 * command-line. Then cfgadm -l should show only that
   1797 		 * ap_id and skip rest.
   1798 		 */
   1799 		index = 1; count = 0;
   1800 		while (nvp = nvlist_next_nvpair(nvl, nvp)) {
   1801 			int32_t intval = 0;
   1802 			int32_t node_type;
   1803 			char	*info;
   1804 			char	*nv_apid;
   1805 			char	*name = nvpair_name(nvp);
   1806 
   1807 			/* start of with next device */
   1808 			if (count == IB_NUM_NVPAIRS) {
   1809 				count = 0;
   1810 				++index;
   1811 			}
   1812 
   1813 			/*
   1814 			 * Check if the index doesn't go beyond the
   1815 			 * device number. If it goes, stop the loop
   1816 			 * here not to cause the heap corruption.
   1817 			 */
   1818 			if (show_dynamic == 0 && index > num_devices)
   1819 				break;
   1820 
   1821 			/* fill up data into "clp" */
   1822 			clp =  (show_dynamic != 0) ? &(*ap_id_list[0]) :
   1823 			    &(ap_id_list[0][index]);
   1824 
   1825 			/* First nvlist entry is "ap_id" always */
   1826 			if (strcmp(name, IBNEX_NODE_APID_NVL) == 0) {
   1827 				(void) nvpair_value_string(nvp, &nv_apid);
   1828 				DPRINTF("cfga_list_ext: Name = %s, apid = %s\n",
   1829 				    name, nv_apid);
   1830 
   1831 				/*
   1832 				 * If a dynamic ap_id is specified in the
   1833 				 * command-line, skip all entries until
   1834 				 * the one needed matches.
   1835 				 */
   1836 				if (show_dynamic &&
   1837 				    strstr(ap_id, nv_apid) == NULL) {
   1838 					DPRINTF("cfga_list_ext: NO MATCH\n");
   1839 
   1840 					/*
   1841 					 * skip rest of the entries of this
   1842 					 * device.
   1843 					 */
   1844 					for (i = 0; i < IB_NUM_NVPAIRS - 1; i++)
   1845 						nvp = nvlist_next_nvpair(nvl,
   1846 						    nvp);
   1847 					count = 0;	/* reset it */
   1848 					continue;
   1849 				}
   1850 
   1851 				apid_matched = B_TRUE;
   1852 
   1853 				/* build the physical ap_id */
   1854 				if (strstr(ap_id, DYN_SEP) == NULL) {
   1855 					(void) snprintf(clp->ap_phys_id,
   1856 					    sizeof (clp->ap_phys_id), "%s%s%s",
   1857 					    ap_id, DYN_SEP, nv_apid);
   1858 				} else {
   1859 					(void) snprintf(clp->ap_phys_id,
   1860 					    sizeof (clp->ap_phys_id), "%s",
   1861 					    ap_id);
   1862 				}
   1863 
   1864 				/* ensure that this is a valid apid */
   1865 				if (ib_verify_valid_apid(clp->ap_phys_id) !=
   1866 				    0) {
   1867 					DPRINTF("cfga_list_ext: "
   1868 					    "not a valid IB ap_id\n");
   1869 					S_FREE(*ap_id_list);
   1870 					S_FREE(snap_data);
   1871 					nvlist_free(nvl);
   1872 					return (ib_err_msg(errstring,
   1873 					    CFGA_IB_AP_ERR, ap_id, errno));
   1874 				}
   1875 
   1876 				/* build the logical ap_id */
   1877 				(void) snprintf(clp->ap_log_id,
   1878 				    sizeof (clp->ap_log_id), "ib%s%s",
   1879 				    DYN_SEP, nv_apid);
   1880 				DPRINTF("cfga_list_ext: ap_pi = %s, ap_li = %s,"
   1881 				    "\nap_info = %s\n", clp->ap_phys_id,
   1882 				    clp->ap_log_id, clp->ap_info);
   1883 				++count;
   1884 
   1885 			} else if (strcmp(name, IBNEX_NODE_INFO_NVL) == 0) {
   1886 				(void) nvpair_value_string(nvp, &info);
   1887 				DPRINTF("cfga_list_ext: Name = %s, info = %s\n",
   1888 				    name, info);
   1889 				(void) snprintf(clp->ap_info,
   1890 				    sizeof (clp->ap_info), "%s", info);
   1891 				++count;
   1892 
   1893 			} else if (strcmp(name, IBNEX_NODE_TYPE_NVL) == 0) {
   1894 				(void) nvpair_value_int32(nvp, &node_type);
   1895 				if (node_type == IBNEX_PORT_NODE_TYPE) {
   1896 					(void) snprintf(clp->ap_type,
   1897 					    sizeof (clp->ap_type), "%s",
   1898 					    IB_PORT_TYPE);
   1899 				} else if (node_type == IBNEX_VPPA_NODE_TYPE) {
   1900 					(void) snprintf(clp->ap_type,
   1901 					    sizeof (clp->ap_type), "%s",
   1902 					    IB_VPPA_TYPE);
   1903 				} else if (node_type ==
   1904 				    IBNEX_HCASVC_NODE_TYPE) {
   1905 					(void) snprintf(clp->ap_type,
   1906 					    sizeof (clp->ap_type), "%s",
   1907 					    IB_HCASVC_TYPE);
   1908 				} else if (node_type == IBNEX_IOC_NODE_TYPE) {
   1909 					(void) snprintf(clp->ap_type,
   1910 					    sizeof (clp->ap_type), "%s",
   1911 					    IB_IOC_TYPE);
   1912 				} else if (node_type ==
   1913 				    IBNEX_PSEUDO_NODE_TYPE) {
   1914 					(void) snprintf(clp->ap_type,
   1915 					    sizeof (clp->ap_type), "%s",
   1916 					    IB_PSEUDO_TYPE);
   1917 				}
   1918 				DPRINTF("cfga_list_ext: Name = %s, type = %x\n",
   1919 				    name, intval);
   1920 				++count;
   1921 
   1922 			} else if (strcmp(name, IBNEX_NODE_RSTATE_NVL) == 0) {
   1923 				(void) nvpair_value_int32(nvp, &intval);
   1924 
   1925 				if (intval == AP_RSTATE_EMPTY)
   1926 					clp->ap_r_state = CFGA_STAT_EMPTY;
   1927 				else if (intval == AP_RSTATE_DISCONNECTED)
   1928 					clp->ap_r_state =
   1929 					    CFGA_STAT_DISCONNECTED;
   1930 				else if (intval == AP_RSTATE_CONNECTED)
   1931 					clp->ap_r_state = CFGA_STAT_CONNECTED;
   1932 				DPRINTF("cfga_list_ext: Name = %s, "
   1933 				    "rstate = %x\n", name, intval);
   1934 				++count;
   1935 
   1936 			} else if (strcmp(name, IBNEX_NODE_OSTATE_NVL) == 0) {
   1937 				(void) nvpair_value_int32(nvp, &intval);
   1938 
   1939 				if (intval == AP_OSTATE_CONFIGURED)
   1940 					clp->ap_o_state = CFGA_STAT_CONFIGURED;
   1941 				else if (intval == AP_OSTATE_UNCONFIGURED)
   1942 					clp->ap_o_state =
   1943 					    CFGA_STAT_UNCONFIGURED;
   1944 				DPRINTF("cfga_list_ext: Name = %s, "
   1945 				    "ostate = %x\n", name, intval);
   1946 				++count;
   1947 
   1948 			} else if (strcmp(name, IBNEX_NODE_COND_NVL) == 0) {
   1949 				(void) nvpair_value_int32(nvp, &intval);
   1950 
   1951 				if (intval == AP_COND_OK)
   1952 					clp->ap_cond = CFGA_COND_OK;
   1953 				else if (intval == AP_COND_FAILING)
   1954 					clp->ap_cond = CFGA_COND_FAILING;
   1955 				else if (intval == AP_COND_FAILED)
   1956 					clp->ap_cond = CFGA_COND_FAILED;
   1957 				else if (intval == AP_COND_UNUSABLE)
   1958 					clp->ap_cond = CFGA_COND_UNUSABLE;
   1959 				else if (intval == AP_COND_UNKNOWN)
   1960 					clp->ap_cond = CFGA_COND_UNKNOWN;
   1961 				DPRINTF("cfga_list_ext: Name = %s, "
   1962 				    "condition = %x\n", name, intval);
   1963 				++count;
   1964 			}
   1965 
   1966 			clp->ap_class[0] = '\0'; /* Filled by libcfgadm */
   1967 			clp->ap_busy = 0;
   1968 			clp->ap_status_time = (time_t)-1;
   1969 		} /* end of while */
   1970 	}
   1971 
   1972 	S_FREE(snap_data);
   1973 	if (nvl)
   1974 		nvlist_free(nvl);
   1975 
   1976 	/*
   1977 	 * if a cmdline specified ap_id doesn't match the known list of ap_ids
   1978 	 * then report an error right away
   1979 	 */
   1980 	rv = (apid_matched ==  B_TRUE) ? CFGA_IB_OK : CFGA_IB_AP_ERR;
   1981 	return (ib_err_msg(errstring, rv, ap_id, errno));
   1982 }
   1983 
   1984 
   1985 /*
   1986  * Function:
   1987  *	cfga_msg
   1988  * Input:
   1989  *	msgp		- cfgadm error message for this plugin
   1990  *	str		- string to be passed on to the message
   1991  * Output:
   1992  *	NONE
   1993  * Returns:
   1994  *	NONE
   1995  * Description:
   1996  *	This routine accepts a variable number of message IDs and
   1997  *	constructs a corresponding error string which is printed
   1998  *	via the message print routine argument.
   1999  */
   2000 void
   2001 cfga_msg(struct cfga_msg *msgp, const char *str)
   2002 {
   2003 	int len;
   2004 	char *q;
   2005 
   2006 	if (msgp == NULL || msgp->message_routine == NULL) {
   2007 		DPRINTF("cfga_msg: msg\n");
   2008 		return;
   2009 	}
   2010 
   2011 	if ((len = strlen(str)) == 0) {
   2012 		DPRINTF("cfga_msg: null str\n");
   2013 		return;
   2014 	}
   2015 
   2016 	if ((q = (char *)calloc(len + 1, 1)) == NULL) {
   2017 		DPRINTF("cfga_msg: null q\n");
   2018 		return;
   2019 	}
   2020 
   2021 	(void) strlcpy(q, str, len + 1);
   2022 	(*msgp->message_routine)(msgp->appdata_ptr, q);
   2023 
   2024 	free(q);
   2025 }
   2026 
   2027 
   2028 /*
   2029  * Function:
   2030  *	cfga_help
   2031  * Input:
   2032  *	msgp		- Help message passed on to cfgadm(1M)
   2033  *	options		- Help message options passed on to cfgadm(1M)
   2034  *	flags		- Cfgadm(1m) flags
   2035  * Output:
   2036  *	NONE
   2037  * Returns:
   2038  *	Were we able to print cfgadm help or not for this plugin
   2039  * Description:
   2040  *	Print cfgadm help for this plugin
   2041  */
   2042 /* ARGSUSED */
   2043 cfga_err_t
   2044 cfga_help(struct cfga_msg *msgp, const char *options, cfga_flags_t flags)
   2045 {
   2046 	DPRINTF("cfga_help:\n");
   2047 
   2048 	if (options) {
   2049 		cfga_msg(msgp, dgettext(TEXT_DOMAIN, ib_help[
   2050 		    CFGA_IB_HELP_UNKNOWN]));
   2051 		cfga_msg(msgp, options);
   2052 	}
   2053 
   2054 	/* Print messages array */
   2055 	cfga_msg(msgp, dgettext(TEXT_DOMAIN, ib_help[CFGA_IB_HELP_HEADER]));
   2056 	cfga_msg(msgp, ib_help[CFGA_IB_HELP_CONFIG]);
   2057 	cfga_msg(msgp, ib_help[CFGA_IB_HELP_LIST]);
   2058 	cfga_msg(msgp, ib_help[CFGA_IB_HELP_UPD_PKEY]);
   2059 	cfga_msg(msgp, ib_help[CFGA_IB_HELP_CONF_FILE1]);
   2060 	cfga_msg(msgp, ib_help[CFGA_IB_HELP_CONF_FILE2]);
   2061 	cfga_msg(msgp, ib_help[CFGA_IB_HELP_UPD_IOC_CONF]);
   2062 	cfga_msg(msgp, ib_help[CFGA_IB_HELP_UNCFG_CLNTS]);
   2063 
   2064 	return (CFGA_OK);
   2065 }
   2066 
   2067 
   2068 /*
   2069  * Function:
   2070  *	ib_confirm
   2071  * Input:
   2072  *	confp		- The "cfga" structure that confirms a cfgadm query
   2073  *	msg		- The message that needs confirmation
   2074  * Output:
   2075  *	None
   2076  * Returns:
   2077  *	If a user entered YES or NO
   2078  * Description:
   2079  *	Queries a user if it is ok to proceed with an operation or not.
   2080  *	Returns user's response.
   2081  */
   2082 static int
   2083 ib_confirm(struct cfga_confirm *confp, char *msg)
   2084 {
   2085 	int rval;
   2086 
   2087 	/* check that "confirm" function exists */
   2088 	if (confp == NULL || confp->confirm == NULL) {
   2089 		return (0);
   2090 	}
   2091 
   2092 	/* Call cfgadm provided "confirm" function */
   2093 	rval = (*confp->confirm)(confp->appdata_ptr, msg);
   2094 	DPRINTF("ib_confirm: %d\n", rval);
   2095 
   2096 	return (rval);
   2097 }
   2098 
   2099 
   2100 /*
   2101  * Function:
   2102  *	ib_get_devicepath
   2103  * Input:
   2104  *	ap_id		- The dynamic attachment point of an IB device
   2105  * Output:
   2106  *	None
   2107  * Returns:
   2108  *	devpath if it exists; otherwise NULL
   2109  * Description:
   2110  *	Returns the devicepath for a dynamic attachment point of an IB device
   2111  */
   2112 static char *
   2113 ib_get_devicepath(const char *ap_id)
   2114 {
   2115 	char		*devpath = NULL;
   2116 	size_t		size;
   2117 
   2118 	/* Get device path sizes */
   2119 	if (ib_do_control_ioctl((char *)ap_id, IBNEX_DEVICE_PATH_SZ,
   2120 	    IBNEX_GET_DEVICE_PATH, 0, (void **)&devpath, &size) == CFGA_IB_OK) {
   2121 		DPRINTF("ib_get_devicepath: get device path ioctl ok\n");
   2122 		return (devpath);
   2123 
   2124 	} else {
   2125 		DPRINTF("ib_get_devicepath: get device path ioctl failed\n");
   2126 		return ((char *)NULL);
   2127 	}
   2128 }
   2129