xref: /illumos-gate/usr/src/lib/cfgadm_plugins/ib/common/cfga_ib.c (revision 257873cfc1dd3337766407f80397db60a56f2f5a)
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 2008 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 (!ib_confirm(confp, IB_CONFIRM1)) {
923 			ib_cleanup_after_devctl_cmd(hdl, nvl);
924 			return (CFGA_NACK);
925 		}
926 
927 		if (devctl_ap_configure(hdl, nvl) != 0) {
928 			DPRINTF("cfga_change_state: devctl_ap_configure "
929 			    "failed. errno: %d\n", errno);
930 			rv = CFGA_IB_CONFIG_OP_ERR;
931 			break;
932 		}
933 
934 		devpath = ib_get_devicepath(ap_id);
935 		if (devpath == NULL) {
936 			int i;
937 
938 			/*
939 			 * try for some time as IB hotplug thread
940 			 * takes a while to create the path
941 			 * and then eventually give up
942 			 */
943 			for (i = 0;
944 			    i < IB_RETRY_DEVPATH && (devpath == NULL); i++) {
945 				sleep(IB_MAX_DEVPATH_DELAY);
946 				devpath = ib_get_devicepath(ap_id);
947 			}
948 
949 			if (devpath == NULL) {
950 				DPRINTF("cfga_change_state: get device "
951 				    "path failed i = %d\n", i);
952 				rv = CFGA_IB_CONFIG_OP_ERR;
953 				break;
954 			}
955 		}
956 		S_FREE(devpath);
957 		break;
958 
959 	case CFGA_CMD_UNCONFIGURE:
960 		if ((rv = ib_device_connected(hdl, nvl, &ostate)) !=
961 		    CFGA_IB_ALREADY_CONNECTED) {
962 			ib_cleanup_after_devctl_cmd(hdl, nvl);
963 			if (rv == CFGA_IB_DEVCTL_ERR)
964 				rv = CFGA_IB_INVALID_OP_ERR;
965 			return (ib_err_msg(errstring, rv, ap_id, errno));
966 		}
967 
968 		/* check if it is already unconfigured */
969 		if ((rv = ib_device_configured(hdl, nvl, &rstate)) ==
970 		    CFGA_IB_NOT_CONFIGURED) {
971 			ib_cleanup_after_devctl_cmd(hdl, nvl);
972 			return (ib_err_msg(errstring, rv, ap_id, errno));
973 		}
974 
975 		rv = CFGA_IB_OK;	/* Other statuses don't matter */
976 
977 		if (!ib_confirm(confp, IB_CONFIRM1)) {
978 			ib_cleanup_after_devctl_cmd(hdl, nvl);
979 			return (CFGA_NACK);
980 		}
981 
982 		devpath = ib_get_devicepath(ap_id);
983 		if (devpath == NULL) {
984 			DPRINTF("cfga_change_state: get device path failed\n");
985 			rv = CFGA_IB_UNCONFIG_OP_ERR;
986 			break;
987 		}
988 
989 		if ((rv = ib_rcm_offline(ap_id, errstring, devpath, flags)) !=
990 		    CFGA_IB_OK) {
991 			S_FREE(devpath);
992 			break;
993 		}
994 
995 		ret = devctl_ap_unconfigure(hdl, nvl);
996 		if (ret != 0) {
997 			DPRINTF("cfga_change_state: devctl_ap_unconfigure "
998 			    "failed with errno: %d\n", errno);
999 			rv = CFGA_IB_UNCONFIG_OP_ERR;
1000 			if (errno == EBUSY) {
1001 				rv = CFGA_IB_BUSY_ERR;
1002 			}
1003 			(void) ib_rcm_online(ap_id, errstring, devpath, flags);
1004 
1005 		} else {
1006 			(void) ib_rcm_remove(ap_id, errstring, devpath, flags);
1007 		}
1008 
1009 		S_FREE(devpath);
1010 		break;
1011 
1012 	case CFGA_CMD_LOAD:
1013 	case CFGA_CMD_UNLOAD:
1014 	case CFGA_CMD_CONNECT:
1015 	case CFGA_CMD_DISCONNECT:
1016 		(void) cfga_help(msgp, options, flags);
1017 		rv = CFGA_IB_OPNOTSUPP;
1018 		break;
1019 
1020 	case CFGA_CMD_NONE:
1021 	default:
1022 		(void) cfga_help(msgp, options, flags);
1023 		rv = CFGA_IB_INTERNAL_ERR;
1024 	}
1025 
1026 	ib_cleanup_after_devctl_cmd(hdl, nvl);
1027 	return (ib_err_msg(errstring, rv, ap_id, errno));
1028 }
1029 
1030 
1031 /*
1032  * Function:
1033  *	cfga_private_func
1034  * Input:
1035  *	func		- The private function (passed w/ -x option)
1036  *	ap_id		- The attachment point of an IB fabric
1037  *	options		- Private function command options passed
1038  *				by the cfgadm(1M)
1039  *	confp		- Whether this command requires confirmation?
1040  *	msgp		- cfgadm error message for this plugin
1041  *	errstring	- This contains error msg if command fails
1042  *	flags		- Cfgadm(1m) flags
1043  * Output:
1044  *	NONE
1045  * Returns:
1046  *	If the command succeeded perform the 'cfgadm -x <func>'; otherwise
1047  *	return failure.
1048  * Description:
1049  *	Do cfgadm -x <func>
1050  */
1051 /*ARGSUSED*/
1052 cfga_err_t
1053 cfga_private_func(const char *func, const char *ap_id, const char *options,
1054     struct cfga_confirm *confp, struct cfga_msg *msgp, char **errstring,
1055     cfga_flags_t flags)
1056 {
1057 	int		len, ret, count = 0;
1058 	char		*clnt_name = NULL, *alt_hca = NULL;
1059 	char		*clnt_apid = NULL, *clnt_devpath = NULL;
1060 	char		*name, *msg = NULL;
1061 	char		*fab_apid = strstr((char *)ap_id, IBNEX_FABRIC);
1062 	size_t		info_len = 0;
1063 	uchar_t		*info = NULL;
1064 	nvlist_t	*nvl;
1065 	nvpair_t	*nvp = NULL;
1066 	ap_rstate_t	rstate;
1067 	devctl_hdl_t	hdl = NULL;
1068 	cfga_ib_ret_t	rv;
1069 
1070 	if ((rv = ib_verify_params(ap_id, NULL, errstring)) != CFGA_IB_OK) {
1071 		DPRINTF("cfga_private_func: ib_verify_params "
1072 		    "failed with rv: %d\n", rv);
1073 		return (ib_err_msg(errstring, rv, ap_id, errno));
1074 	}
1075 
1076 	if (func == NULL) {
1077 		DPRINTF("cfga_private_func: func is NULL\n");
1078 		return (ib_err_msg(errstring, CFGA_IB_INVAL_ARG_ERR, ap_id,
1079 		    errno));
1080 	}
1081 
1082 	/*
1083 	 * check first if IB static ap_id is "configured" for use
1084 	 */
1085 	if (fab_apid != NULL) {
1086 		if ((rv = ib_setup_for_devctl_cmd(fab_apid, B_TRUE, &hdl,
1087 		    &nvl)) != CFGA_IB_OK) {
1088 			ib_cleanup_after_devctl_cmd(hdl, nvl);
1089 			return (ib_err_msg(errstring, rv, ap_id, errno));
1090 		}
1091 		if ((rv = ib_device_configured(hdl, nvl, &rstate)) ==
1092 		    CFGA_IB_NOT_CONFIGURED) {
1093 			return (ib_err_msg(errstring, rv, ap_id, errno));
1094 		}
1095 		ib_cleanup_after_devctl_cmd(hdl, nvl);
1096 	}
1097 
1098 	rv = CFGA_IB_OK;
1099 	DPRINTF("cfga_private_func: func is %s\n", func);
1100 	if (strcmp(func, IB_LIST_HCA_CLIENTS) == 0) {	/* -x list_clients */
1101 
1102 		/* only supported on HCA ap_ids */
1103 		if (fab_apid != NULL) {
1104 			DPRINTF("cfga_private_func: fabric apid supplied\n");
1105 			return (ib_err_msg(errstring, CFGA_IB_INVALID_OP_ERR,
1106 			    ap_id, errno));
1107 		}
1108 
1109 		if ((msg = (char *)calloc(256, 1)) == NULL) {
1110 			DPRINTF("cfga_private_func: malloc for msg failed. "
1111 			    "errno: %d\n", errno);
1112 			return (ib_err_msg(errstring, CFGA_IB_ALLOC_FAIL,
1113 			    ap_id, errno));
1114 		}
1115 
1116 		if ((rv = ib_do_control_ioctl((char *)ap_id, IBNEX_HCA_LIST_SZ,
1117 		    IBNEX_HCA_LIST_INFO, 0, (void **)&info, &info_len)) != 0) {
1118 			DPRINTF("cfga_private_func: "
1119 			    "ib_do_control_ioctl list failed :%d\n", rv);
1120 			S_FREE(msg);
1121 			return (ib_err_msg(errstring, CFGA_IB_HCA_LIST_ERR,
1122 			    ap_id, errno));
1123 		}
1124 
1125 		if (nvlist_unpack((char *)info, info_len, &nvl, 0)) {
1126 			DPRINTF("cfga_private_func: "
1127 			    "nvlist_unpack 2 failed %p\n", info);
1128 			S_FREE(info);
1129 			S_FREE(msg);
1130 			return (ib_err_msg(errstring, CFGA_IB_NVLIST_ERR, ap_id,
1131 			    errno));
1132 		}
1133 
1134 		(void) snprintf(msg, 256, "Ap_Id\t\t\t       IB Client\t\t "
1135 		    "Alternate HCA\n");
1136 		cfga_msg(msgp, msg);
1137 
1138 		/* Walk the NVPAIR data */
1139 		while (nvp = nvlist_next_nvpair(nvl, nvp)) {
1140 			name = nvpair_name(nvp);
1141 			if (strcmp(name, "Client") == 0) {
1142 				(void) nvpair_value_string(nvp, &clnt_name);
1143 				++count;
1144 			} else if (strcmp(name, "Alt_HCA") == 0) {
1145 				(void) nvpair_value_string(nvp, &alt_hca);
1146 				++count;
1147 			} else if (strcmp(name, "ApID") == 0) {
1148 				(void) nvpair_value_string(nvp, &clnt_apid);
1149 				++count;
1150 			}
1151 
1152 			/* check at the end; print message per client found */
1153 			if (count == 3) {
1154 				count = 0;
1155 				(void) snprintf(msg, 256, "%-30s %-25s %s\n",
1156 				    clnt_apid, clnt_name, alt_hca);
1157 				cfga_msg(msgp, msg);
1158 			}
1159 		} /* end of while */
1160 
1161 		S_FREE(info);
1162 		S_FREE(msg);
1163 		nvlist_free(nvl);
1164 
1165 	/* -x unconfig_clients */
1166 	} else if (strcmp(func, IB_UNCONFIG_HCA_CLIENTS) == 0) {
1167 		/*
1168 		 * -x unconfig_clients changes state by calling into RCM.
1169 		 * It needs root privileges.
1170 		 */
1171 		if (geteuid() != 0) {
1172 			return (ib_err_msg(errstring, CFGA_IB_PRIV_ERR, ap_id,
1173 			    errno));
1174 		}
1175 
1176 		/* only supported on HCA ap_ids */
1177 		if (fab_apid != NULL) {
1178 			DPRINTF("cfga_private_func: fabric apid supplied\n");
1179 			return (ib_err_msg(errstring, CFGA_IB_INVALID_OP_ERR,
1180 			    ap_id, errno));
1181 		}
1182 
1183 		/*
1184 		 * Check w/ user if it is ok to do this operation
1185 		 * If the user fails to confirm, bailout
1186 		 */
1187 		if (!ib_confirm(confp, IB_CONFIRM3))
1188 			return (CFGA_NACK);
1189 
1190 		/* Get device-paths of all the IOC/Port/Pseudo devices */
1191 		rv = ib_do_control_ioctl((char *)ap_id, IBNEX_UNCFG_CLNTS_SZ,
1192 		    IBNEX_UNCFG_CLNTS_INFO, 0, (void **)&info, &info_len);
1193 		if (rv != 0) {
1194 			DPRINTF("cfga_private_func: ib_do_control_ioctl "
1195 			    "failed :%d\n", rv);
1196 			return (ib_err_msg(errstring, CFGA_IB_HCA_UNCONFIG_ERR,
1197 			    ap_id, errno));
1198 		}
1199 
1200 		if (nvlist_unpack((char *)info, info_len, &nvl, 0)) {
1201 			DPRINTF("cfga_private_func: nvlist_unpack failed %p\n",
1202 			    info);
1203 			S_FREE(info);
1204 			return (ib_err_msg(errstring, CFGA_IB_NVLIST_ERR, ap_id,
1205 			    errno));
1206 		}
1207 
1208 		ret = 0;
1209 
1210 		/* Call RCM Offline on all device paths */
1211 		while (nvp = nvlist_next_nvpair(nvl, nvp)) {
1212 			name = nvpair_name(nvp);
1213 			if (strcmp(name, "devpath") == 0) {
1214 				(void) nvpair_value_string(nvp, &clnt_devpath);
1215 				++count;
1216 			} else if (strcmp(name, "ApID") == 0) {
1217 				(void) nvpair_value_string(nvp, &clnt_apid);
1218 				++count;
1219 			}
1220 
1221 			/* handle the client unconfigure now */
1222 			if (count == 2) {
1223 				count = 0;	/* reset count */
1224 
1225 				DPRINTF("cfga_private_func: client apid = %s, "
1226 				    "DevPath = %s\n", clnt_apid, clnt_devpath);
1227 				if ((rv = ib_setup_for_devctl_cmd(clnt_apid,
1228 				    B_TRUE, &hdl, &nvl)) != CFGA_IB_OK) {
1229 					ib_cleanup_after_devctl_cmd(hdl, nvl);
1230 					return (ib_err_msg(errstring, rv,
1231 					    clnt_apid, errno));
1232 				}
1233 
1234 				if ((rv = ib_device_configured(hdl, nvl,
1235 				    &rstate)) == CFGA_IB_NOT_CONFIGURED)
1236 					continue;
1237 
1238 				if ((rv = ib_rcm_offline(clnt_apid, errstring,
1239 				    clnt_devpath, flags)) != CFGA_IB_OK) {
1240 					DPRINTF("cfga_private_func: client rcm "
1241 					    "offline failed for %s, with %d\n",
1242 					    clnt_devpath, rv);
1243 					ret = rv;
1244 					continue;
1245 				}
1246 
1247 				if (devctl_ap_unconfigure(hdl, nvl) != 0) {
1248 					DPRINTF("cfga_private_func: client "
1249 					    "unconfigure failed: errno %d\n",
1250 					    errno);
1251 					ret = CFGA_IB_UNCONFIG_OP_ERR;
1252 					if (errno == EBUSY)
1253 						ret = CFGA_IB_BUSY_ERR;
1254 					(void) ib_rcm_online(clnt_apid,
1255 					    errstring, clnt_devpath, flags);
1256 					continue;
1257 				} else {
1258 					(void) ib_rcm_remove(clnt_apid,
1259 					    errstring, clnt_devpath, flags);
1260 				}
1261 				ib_cleanup_after_devctl_cmd(hdl, nvl);
1262 
1263 			} /* end of if count == 2 */
1264 
1265 		} /* end of while */
1266 
1267 		S_FREE(info);
1268 		nvlist_free(nvl);
1269 		if (ret) {
1270 			DPRINTF("cfga_private_func: unconfig_clients of %s "
1271 			    "failed with %d\n", ap_id, ret);
1272 			return (ib_err_msg(errstring, CFGA_IB_UCFG_CLNTS_ERR,
1273 			    ap_id, errno));
1274 		}
1275 
1276 	/* -x update_pkey_tbls */
1277 	} else if (strcmp(func, IB_UPDATE_PKEY_TBLS) == 0) {
1278 		/*
1279 		 * Check for root privileges.
1280 		 */
1281 		if (geteuid() != 0) {
1282 			return (ib_err_msg(errstring, CFGA_IB_PRIV_ERR, ap_id,
1283 			    errno));
1284 		}
1285 
1286 		/* CHECK: Only supported on fabric ap_ids */
1287 		if (fab_apid == NULL) {
1288 			DPRINTF("cfga_private_func: fabric apid needed\n");
1289 			return (ib_err_msg(errstring, CFGA_IB_INVALID_OP_ERR,
1290 			    ap_id, errno));
1291 		}
1292 
1293 		/* Check w/ user if it is ok to do this operation */
1294 		len = strlen(IB_CONFIRM4) + 10;
1295 		if ((msg = (char *)calloc(len, 1)) != NULL) {
1296 			(void) snprintf(msg, len, "%s\nContinue", IB_CONFIRM4);
1297 		}
1298 
1299 		/* If the user fails to confirm, return */
1300 		if (!ib_confirm(confp, msg)) {
1301 			free(msg);
1302 			return (CFGA_NACK);
1303 		}
1304 		free(msg);
1305 
1306 		/* Update P_Key tables for all ports of all HCAs */
1307 		rv = ib_do_control_ioctl((char *)ap_id, IBNEX_UPDATE_PKEY_TBLS,
1308 		    0, 0, 0, &info_len);
1309 
1310 		if (rv != 0) {
1311 			DPRINTF("cfga_private_func: ib_do_control_ioctl "
1312 			    "failed :%d\n", rv);
1313 			return (ib_err_msg(errstring, CFGA_IB_UPD_PKEY_TBLS_ERR,
1314 			    ap_id, errno));
1315 		}
1316 
1317 	/* -x [add_service|delete_service] */
1318 	} else if ((strncmp(func, IB_ADD_SERVICE, 12) == 0) ||
1319 	    (strncmp(func, IB_DELETE_SERVICE, 15) == 0)) {
1320 		char			*subopts, *val;
1321 		uint8_t			cmd;
1322 
1323 		/* check: Only supported on fabric ap_ids */
1324 		if (fab_apid == NULL || strcmp(fab_apid, IBNEX_FABRIC) != 0) {
1325 			DPRINTF("cfga_private_func: fabric apid needed\n");
1326 			return (ib_err_msg(errstring, CFGA_IB_INVALID_OP_ERR,
1327 			    ap_id, errno));
1328 		}
1329 
1330 		/* Check for root privileges. */
1331 		if (geteuid() != 0) {
1332 			return (ib_err_msg(errstring, CFGA_IB_PRIV_ERR, ap_id,
1333 			    errno));
1334 		}
1335 
1336 		/* return error if no options are specified */
1337 		subopts = (char *)options;
1338 		if (subopts == (char *)NULL) {
1339 			DPRINTF("cfga_private_func: no sub-options\n");
1340 			(void) cfga_help(msgp, options, flags);
1341 			return (ib_err_msg(errstring, CFGA_IB_INVAL_ARG_ERR,
1342 			    ap_id, errno));
1343 		}
1344 
1345 		/* parse options specified */
1346 		while (*subopts != '\0') {
1347 			switch (getsubopt(&subopts, ib_service_subopts, &val)) {
1348 			case 0: /* comm */
1349 				if (val == NULL) {
1350 					(void) cfga_help(msgp, options, flags);
1351 					S_FREE(service_name);
1352 					return (ib_err_msg(errstring,
1353 					    CFGA_IB_INVAL_ARG_ERR,
1354 					    ap_id, errno));
1355 				} else {
1356 					comm_name = strdup(val);
1357 					if (comm_name == NULL) {
1358 						DPRINTF("comm sub-opt invalid "
1359 						    "arg\n");
1360 						S_FREE(service_name);
1361 						return (ib_err_msg(errstring,
1362 						    CFGA_IB_COMM_INVAL_ERR,
1363 						    ap_id, errno));
1364 					}
1365 				}
1366 				break;
1367 
1368 			case 1: /* service */
1369 				if (val == NULL) {
1370 					(void) cfga_help(msgp, options, flags);
1371 					S_FREE(comm_name);
1372 					return (ib_err_msg(errstring,
1373 					    CFGA_IB_INVAL_ARG_ERR,
1374 					    ap_id, errno));
1375 				} else {
1376 					/* service can be upto 4 long */
1377 					if (strlen(val) == 0 ||
1378 					    strlen(val) > 4) {
1379 						DPRINTF("comm sub-opt invalid "
1380 						    "service passed\n");
1381 						S_FREE(comm_name);
1382 						return (ib_err_msg(errstring,
1383 						    CFGA_IB_SVC_LEN_ERR,
1384 						    ap_id, errno));
1385 					}
1386 					service_name = strdup(val);
1387 					if (service_name == NULL) {
1388 						DPRINTF("comm sub-opt "
1389 						    "internal error\n");
1390 						S_FREE(comm_name);
1391 						return (ib_err_msg(errstring,
1392 						    CFGA_IB_SVC_INVAL_ERR,
1393 						    ap_id, errno));
1394 					}
1395 				}
1396 				break;
1397 
1398 			default:
1399 				(void) cfga_help(msgp, options, flags);
1400 				S_FREE(comm_name);
1401 				S_FREE(service_name);
1402 				return (ib_err_msg(errstring,
1403 				    CFGA_IB_INVAL_ARG_ERR, ap_id, errno));
1404 			}
1405 		}
1406 
1407 		/* figure out the "operation" */
1408 		if (strncasecmp(func, IB_ADD_SERVICE, 11) == 0)
1409 			cmd = IBCONF_ADD_ENTRY;
1410 		else if (strncasecmp(func, IB_DELETE_SERVICE, 14) == 0)
1411 			cmd = IBCONF_DELETE_ENTRY;
1412 		DPRINTF("Service = %s, Comm = %s, Operation = %s\n",
1413 		    service_name, comm_name, func);
1414 
1415 		if (strncasecmp(comm_name, IBNEX_PORT_STR, 4) == 0)
1416 			service_type = IB_PORT_SERVICE;
1417 		else if (strncasecmp(comm_name, IBNEX_VPPA_STR, 4) == 0)
1418 			service_type = IB_VPPA_SERVICE;
1419 		else if (strncasecmp(comm_name, IBNEX_HCASVC_STR, 4) == 0)
1420 			service_type = IB_HCASVC_SERVICE;
1421 		else {
1422 			(void) cfga_help(msgp, options, flags);
1423 			S_FREE(comm_name);
1424 			S_FREE(service_name);
1425 			return (ib_err_msg(errstring, CFGA_IB_INVAL_ARG_ERR,
1426 			    ap_id, errno));
1427 		}
1428 
1429 		/* do the add/delete entry to the service */
1430 		if (cmd == IBCONF_ADD_ENTRY) {
1431 			if ((rv = ib_add_service(errstring)) != CFGA_IB_OK)
1432 				DPRINTF("cfga_private_func: add failed\n");
1433 		} else if (cmd == IBCONF_DELETE_ENTRY) {
1434 			if ((rv = ib_delete_service(errstring)) != CFGA_IB_OK)
1435 				DPRINTF("cfga_private_func: delete failed\n");
1436 		}
1437 
1438 		S_FREE(comm_name);
1439 		S_FREE(service_name);
1440 		return (ib_err_msg(errstring, rv, ap_id, errno));
1441 
1442 	} else if (strncmp(func, IB_LIST_SERVICES, 13) == 0) {
1443 
1444 		/* check: Only supported on fabric ap_ids */
1445 		if (fab_apid == NULL || strcmp(fab_apid, IBNEX_FABRIC) != 0) {
1446 			DPRINTF("cfga_private_func: fabric apid needed\n");
1447 			return (ib_err_msg(errstring, CFGA_IB_INVALID_OP_ERR,
1448 			    ap_id, errno));
1449 		}
1450 
1451 		/* do the list services */
1452 		rv = ib_list_services(msgp, errstring);
1453 		if (rv != CFGA_IB_OK) {
1454 			DPRINTF("cfga_private_func: ib_list_services failed\n");
1455 			return (ib_err_msg(errstring, rv, ap_id, errno));
1456 		}
1457 
1458 	/* -x update_ioc_conf */
1459 	} else if (strncmp(func, IB_UPDATE_IOC_CONF, 17) == 0) {
1460 		uint_t misc_arg;
1461 
1462 		/* Supported only with root privilege */
1463 		if (geteuid() != 0) {
1464 			return (ib_err_msg(errstring, CFGA_IB_PRIV_ERR, ap_id,
1465 			    errno));
1466 		}
1467 
1468 		/*
1469 		 * check: Only supported on fabric ap_id or IOC APID
1470 		 * IOC APID does not have any commas in it.
1471 		 */
1472 		if (fab_apid == NULL ||
1473 		    (fab_apid != NULL && strstr(fab_apid, ",") != NULL)) {
1474 			DPRINTF("cfga_private_func: fabric/IOC apid needed\n");
1475 			return (ib_err_msg(errstring, CFGA_IB_INVALID_OP_ERR,
1476 			    ap_id, errno));
1477 		}
1478 
1479 		/* Check w/ user if it is ok to do this operation */
1480 		len = strlen(IB_CONFIRM5) + 10;
1481 		if ((msg = (char *)calloc(len, 1)) != NULL) {
1482 			(void) snprintf(msg, len, "%s\nContinue", IB_CONFIRM5);
1483 		}
1484 
1485 		/* If the user fails to confirm, return */
1486 		if (!ib_confirm(confp, msg)) {
1487 			free(msg);
1488 			return (CFGA_NACK);
1489 		}
1490 		free(msg);
1491 
1492 		misc_arg = (strcmp(fab_apid, IBNEX_FABRIC) == 0) ?
1493 		    IBNEX_BASE_APID : IBNEX_DYN_APID;
1494 
1495 		/* Reprobe and update IOC(s) configuration */
1496 		rv = ib_do_control_ioctl((char *)ap_id, IBNEX_UPDATE_IOC_CONF,
1497 		    0, misc_arg, 0, &info_len);
1498 
1499 		if (rv != 0) {
1500 			DPRINTF("cfga_private_func: ib_do_control_ioctl "
1501 			    "failed :%d\n", rv);
1502 			return (ib_err_msg(errstring, CFGA_IB_DEVCTL_ERR,
1503 			    ap_id, errno));
1504 		}
1505 	} else {
1506 		DPRINTF("cfga_private_func: unrecognized command.\n");
1507 		(void) cfga_help(msgp, options, flags);
1508 		errno = EINVAL;
1509 		return (CFGA_INVAL);
1510 	}
1511 
1512 	return (ib_err_msg(errstring, rv, ap_id, errno));
1513 }
1514 
1515 
1516 /*
1517  * Function:
1518  *	cfga_test
1519  * Input:
1520  *	ap_id		- The attachment point of an IB fabric
1521  *	options		- Test command options passed by the cfgadm(1M)
1522  *	msgp		- cfgadm error message for this plugin
1523  *	errstring	- This contains error msg if command fails
1524  *	flags		- Cfgadm(1m) flags
1525  * Output:
1526  *	NONE
1527  * Returns:
1528  *	CFGA_OPNOTSUPP
1529  * Description:
1530  *	Do "cfgadm -t"
1531  */
1532 /*ARGSUSED*/
1533 cfga_err_t
1534 cfga_test(const char *ap_id, const char *options, struct cfga_msg *msgp,
1535     char **errstring, cfga_flags_t flags)
1536 {
1537 	(void) cfga_help(msgp, options, flags);
1538 	return (CFGA_OPNOTSUPP);
1539 }
1540 
1541 
1542 /*
1543  * Function:
1544  *	ib_fill_static_apids
1545  * Input:
1546  *	ap_id		- The static attachment point of an IB device
1547  *	clp		- The returned "list" information array
1548  * Output:
1549  *	NONE
1550  * Returns:
1551  *	Fills up the "list" information array for the static attachment point
1552  * Description:
1553  *	IB fabric supports two types of static attachment points.
1554  *	One is fabric and other is for the HCAs. This fills up
1555  *	"cfga_list_data_t" for static attachment points.
1556  */
1557 static cfga_ib_ret_t
1558 ib_fill_static_apids(char *ap_id, cfga_list_data_t *clp)
1559 {
1560 	int	rv, l_err;
1561 	char	*ap_id_log = NULL;
1562 
1563 	/* Get /dev/cfg path to corresponding to the physical ap_id */
1564 	/* Remember ap_id_log must be freed */
1565 	if ((cfga_ib_ret_t)ib_physpath_to_devlink(ap_id, &ap_id_log,
1566 	    &l_err) != ICFGA_OK) {
1567 		DPRINTF("ib_fill_static_apids: "
1568 		    "ib_physpath_to_devlink failed\n");
1569 		return (CFGA_IB_DEVLINK_ERR);
1570 	}
1571 	assert(ap_id_log != NULL);
1572 
1573 	/* Get logical ap-id corresponding to the physical */
1574 	if (strstr(ap_id_log, CFGA_DEV_DIR) == NULL) {
1575 		DPRINTF("ib_fill_static_apids: devlink doesn't contain "
1576 		    "/dev/cfg\n");
1577 		free(ap_id_log);
1578 		return (CFGA_IB_DEVLINK_ERR);
1579 	}
1580 
1581 	clp->ap_cond = CFGA_COND_OK;
1582 	clp->ap_r_state = CFGA_STAT_CONNECTED;
1583 	clp->ap_o_state = CFGA_STAT_CONFIGURED;
1584 	clp->ap_class[0] = '\0';	/* Filled by libcfgadm */
1585 	clp->ap_busy = 0;
1586 	clp->ap_status_time = (time_t)-1;
1587 	(void) snprintf(clp->ap_log_id, sizeof (clp->ap_log_id), "%s",
1588 	    /* Strip off /dev/cfg/ */ ap_id_log + strlen(CFGA_DEV_DIR) + 1);
1589 	(void) strlcpy(clp->ap_phys_id, ap_id, sizeof (clp->ap_phys_id));
1590 
1591 	/* Static IB apid */
1592 	if (strstr((char *)ap_id, IB_FABRIC_APID_STR) != NULL)  {
1593 		(void) strlcpy(clp->ap_type, IB_FABRIC_TYPE,
1594 		    sizeof (clp->ap_type));	/* Fill in type */
1595 		(void) strlcpy(clp->ap_info, IB_FABRIC_INFO,
1596 		    sizeof (clp->ap_info));
1597 
1598 	} else {	/* Static HCA apid */
1599 		size_t	size = 0;
1600 		uchar_t	*data = NULL;
1601 
1602 		(void) strlcpy(clp->ap_type, IB_HCA_TYPE,
1603 		    sizeof (clp->ap_type));	/* Fill in type */
1604 
1605 		rv = ib_do_control_ioctl(ap_id, IBNEX_HCA_VERBOSE_SZ,
1606 		    IBNEX_HCA_VERBOSE_INFO, 0, (void **)&data, &size);
1607 		if (rv != 0) {
1608 			DPRINTF("ib_fill_static_apids: ib_do_control_ioctl "
1609 			    "failed :%d\n", rv);
1610 			free(ap_id_log);
1611 			S_FREE(data);
1612 			return (CFGA_IB_IOCTL_ERR);
1613 		}
1614 
1615 		(void) strlcpy(clp->ap_info, (char *)data,
1616 		    sizeof (clp->ap_info));
1617 		S_FREE(data);
1618 	}
1619 	free(ap_id_log);
1620 	return (CFGA_IB_OK);
1621 }
1622 
1623 
1624 /*
1625  * Function:
1626  *	cfga_list_ext
1627  * Input:
1628  *	ap_id		- The attachment point of an IB fabric
1629  *	ap_id_list	- The returned "list" information array
1630  *	nlistp		- Number of elements in the "list" information array
1631  *	options		- List command options passed by the cfgadm(1M)
1632  *	listopts	- "-s" specific options
1633  *	errstring	- This contains error msg if command fails
1634  *	flags		- Cfgadm(1m) flags
1635  * Output:
1636  *	NONE
1637  * Returns:
1638  *	If the command succeeded, cfgadm -l output otherwise an error
1639  * Description:
1640  *	Do cfgadm -l
1641  */
1642 /*ARGSUSED*/
1643 cfga_err_t
1644 cfga_list_ext(const char *ap_id, cfga_list_data_t **ap_id_list, int *nlistp,
1645     const char *options, const char *listopts, char **errstring,
1646     cfga_flags_t flags)
1647 {
1648 	int			expand = 0;
1649 	int			i, index, count;
1650 	int			show_dynamic = 0;
1651 	size_t			num_devices = 0;
1652 	size_t			num_hcas = 0;
1653 	size_t			snap_size = 0;
1654 	uchar_t			*snap_data = NULL;
1655 	nvpair_t		*nvp = NULL;	/* for lint purposes */
1656 	nvlist_t		*nvl = NULL;
1657 	boolean_t		apid_matched = B_FALSE;	/* for valid ap_id */
1658 	cfga_ib_ret_t		rv = CFGA_IB_OK;
1659 	cfga_list_data_t	*clp = NULL;
1660 
1661 	if ((rv = ib_verify_params(ap_id, options, errstring)) != CFGA_IB_OK) {
1662 		(void) cfga_help(NULL, options, flags);
1663 		return (ib_err_msg(errstring, rv, ap_id, errno));
1664 	}
1665 
1666 	/* make sure we have a valid ap_id_list */
1667 	if (ap_id_list == NULL || nlistp == NULL) {
1668 		DPRINTF("cfga_list_ext: list = NULL or nlistp = NULL\n");
1669 		(void) cfga_help(NULL, options, flags);
1670 		return (ib_err_msg(errstring, CFGA_IB_INVAL_ARG_ERR,
1671 		    ap_id, errno));
1672 	}
1673 
1674 	DPRINTF("cfga_list_ext: ap_id = %s\n", ap_id);
1675 
1676 	if ((flags & CFGA_FLAG_LIST_ALL) == CFGA_FLAG_LIST_ALL) {
1677 		expand = 1;		/* -a flag passed */
1678 	}
1679 
1680 	if (GET_DYN(ap_id) != NULL) {
1681 		show_dynamic = 1;
1682 	}
1683 
1684 	if ((expand == 1) &&	/* -a option passed */
1685 	    (strstr((char *)ap_id, IB_FABRIC_APID_STR) != NULL)) {
1686 		/*
1687 		 * Figure out how many IOC/Port/Pseudo
1688 		 * devices exist in the system?
1689 		 */
1690 		if ((rv = ib_do_control_ioctl((char *)ap_id,
1691 		    IBNEX_NUM_DEVICE_NODES, 0, 0, 0, &num_devices)) !=
1692 		    CFGA_IB_OK) {
1693 			DPRINTF("cfga_list_ext: ib_do_control_ioctl "
1694 			    "IBNEX_NUM_DEVICE_NODES failed :%d\n", rv);
1695 			if (errno == ENOENT)
1696 				return (CFGA_APID_NOEXIST);
1697 			return (ib_err_msg(errstring, rv, ap_id, errno));
1698 		}
1699 
1700 		DPRINTF("cfga_list_ext: num_devices = %d\n", num_devices);
1701 	}
1702 
1703 	/* Figure out how many HCA nodes exist in the system. */
1704 	if ((rv = ib_do_control_ioctl((char *)ap_id, IBNEX_NUM_HCA_NODES, 0, 0,
1705 	    0, &num_hcas)) != CFGA_IB_OK) {
1706 		DPRINTF("cfga_list_ext: ib_do_control_ioctl "
1707 		    "IBNEX_NUM_HCA_NODES failed :%d\n", rv);
1708 		if (errno == ENOENT)
1709 			return (CFGA_APID_NOEXIST);
1710 		return (ib_err_msg(errstring, rv, ap_id, errno));
1711 	}
1712 	DPRINTF("cfga_list_ext: num_hcas = %d\n", num_hcas);
1713 
1714 	/*
1715 	 * No HCAs or IOC/VPPA/Port/HCA_SVC/Pseudo devices seen (non-IB system)
1716 	 */
1717 	if (!(num_hcas || num_devices)) {
1718 		DPRINTF("cfga_list_ext: no IB devices found\n");
1719 		return (CFGA_APID_NOEXIST);
1720 	}
1721 
1722 	/*
1723 	 * *nlistp contains to how many APIDs to show w/ cfgadm -l.
1724 	 * If ap_id is "fabric" then
1725 	 * 	*nlistp is all Dynamic Apids + One more for "fabric"
1726 	 * If ap_id is "HCA" ap_id then
1727 	 *	*nlistp is 1
1728 	 * Note that each HCA is a static APID, so nlistp will be 1 always
1729 	 * and this function will be called N times for each of the N HCAs
1730 	 * in the host.
1731 	 */
1732 	if (strstr((char *)ap_id, IB_FABRIC_APID_STR) != NULL) {
1733 		*nlistp = num_devices + 1;
1734 
1735 	} else {
1736 		/* Assume it as a HCA ap_id */
1737 		*nlistp = 1;
1738 	}
1739 
1740 	/* Allocate storage for passing "list" info back */
1741 	if ((*ap_id_list = (cfga_list_data_t *)calloc(*nlistp,
1742 	    sizeof (cfga_list_data_t))) == NULL) {
1743 		DPRINTF("cfga_list_ext: malloc for cfga_list_data_t failed. "
1744 		    "errno: %d\n", errno);
1745 		return (ib_err_msg(errstring, CFGA_IB_ALLOC_FAIL,
1746 		    ap_id, errno));
1747 	}
1748 
1749 	/*
1750 	 * Only static ap_id is ib_fabric:
1751 	 * If -a options isn't specified then only show the static ap_id.
1752 	 */
1753 	if (!show_dynamic) {
1754 		clp = &(*ap_id_list[0]);
1755 
1756 		if ((rv = ib_fill_static_apids((char *)ap_id, clp)) !=
1757 		    CFGA_IB_OK) {
1758 			S_FREE(*ap_id_list);
1759 			return (ib_err_msg(errstring, rv, ap_id, errno));
1760 		}
1761 		apid_matched = B_TRUE;
1762 	}
1763 
1764 	/*
1765 	 * No -a specified
1766 	 * No HCAs or IOC/VPPA/HCA_SVC/Port/Pseudo devices seen (non-IB system)
1767 	 */
1768 	if (!expand || (!num_hcas && !num_devices)) {
1769 		if (!show_dynamic)
1770 			return (CFGA_OK);
1771 	}
1772 
1773 	if (strstr((char *)ap_id, IB_FABRIC_APID_STR) != NULL) {
1774 		rv = ib_do_control_ioctl((char *)ap_id, IBNEX_SNAPSHOT_SIZE,
1775 		    IBNEX_GET_SNAPSHOT, IBNEX_DONOT_PROBE_FLAG,
1776 		    (void **)&snap_data, &snap_size);
1777 		if (rv != 0) {
1778 			DPRINTF("cfga_list_ext: ib_do_control_ioctl "
1779 			    "failed :%d\n", rv);
1780 			S_FREE(*ap_id_list);
1781 			S_FREE(snap_data);
1782 			return (ib_err_msg(errstring, rv, ap_id, errno));
1783 		}
1784 
1785 		if (nvlist_unpack((char *)snap_data, snap_size, &nvl, 0)) {
1786 			DPRINTF("cfga_list_ext: nvlist_unpack 1 failed %p\n",
1787 			    snap_data);
1788 			S_FREE(*ap_id_list);
1789 			S_FREE(snap_data);
1790 			return (ib_err_msg(errstring, CFGA_IB_NVLIST_ERR,
1791 			    ap_id, errno));
1792 		}
1793 
1794 		/*
1795 		 * In kernel a nvlist is build per ap_id which contains
1796 		 * information that is displayed using cfgadm -l.
1797 		 * For IB devices only these 6 items are shown:
1798 		 *	ap_id, type, occupant, receptacle, condition and info
1799 		 *
1800 		 * In addition, one could specify a dynamic ap_id from
1801 		 * command-line. Then cfgadm -l should show only that
1802 		 * ap_id and skip rest.
1803 		 */
1804 		index = 1; count = 0;
1805 		while (nvp = nvlist_next_nvpair(nvl, nvp)) {
1806 			int32_t intval = 0;
1807 			int32_t node_type;
1808 			char	*info;
1809 			char	*nv_apid;
1810 			char	*name = nvpair_name(nvp);
1811 
1812 			/* start of with next device */
1813 			if (count == IB_NUM_NVPAIRS) {
1814 				count = 0;
1815 				++index;
1816 			}
1817 
1818 			/*
1819 			 * Check if the index doesn't go beyond the
1820 			 * device number. If it goes, stop the loop
1821 			 * here not to cause the heap corruption.
1822 			 */
1823 			if (show_dynamic == 0 && index > num_devices)
1824 				break;
1825 
1826 			/* fill up data into "clp" */
1827 			clp =  (show_dynamic != 0) ? &(*ap_id_list[0]) :
1828 			    &(ap_id_list[0][index]);
1829 
1830 			/* First nvlist entry is "ap_id" always */
1831 			if (strcmp(name, IBNEX_NODE_APID_NVL) == 0) {
1832 				(void) nvpair_value_string(nvp, &nv_apid);
1833 				DPRINTF("cfga_list_ext: Name = %s, apid = %s\n",
1834 				    name, nv_apid);
1835 
1836 				/*
1837 				 * If a dynamic ap_id is specified in the
1838 				 * command-line, skip all entries until
1839 				 * the one needed matches.
1840 				 */
1841 				if (show_dynamic &&
1842 				    strstr(ap_id, nv_apid) == NULL) {
1843 					DPRINTF("cfga_list_ext: NO MATCH\n");
1844 
1845 					/*
1846 					 * skip rest of the entries of this
1847 					 * device.
1848 					 */
1849 					for (i = 0; i < IB_NUM_NVPAIRS - 1; i++)
1850 						nvp = nvlist_next_nvpair(nvl,
1851 						    nvp);
1852 					count = 0;	/* reset it */
1853 					continue;
1854 				}
1855 
1856 				apid_matched = B_TRUE;
1857 
1858 				/* build the physical ap_id */
1859 				if (strstr(ap_id, DYN_SEP) == NULL) {
1860 					(void) snprintf(clp->ap_phys_id,
1861 					    sizeof (clp->ap_phys_id), "%s%s%s",
1862 					    ap_id, DYN_SEP, nv_apid);
1863 				} else {
1864 					(void) snprintf(clp->ap_phys_id,
1865 					    sizeof (clp->ap_phys_id), "%s",
1866 					    ap_id);
1867 				}
1868 
1869 				/* ensure that this is a valid apid */
1870 				if (ib_verify_valid_apid(clp->ap_phys_id) !=
1871 				    0) {
1872 					DPRINTF("cfga_list_ext: "
1873 					    "not a valid IB ap_id\n");
1874 					S_FREE(*ap_id_list);
1875 					S_FREE(snap_data);
1876 					nvlist_free(nvl);
1877 					return (ib_err_msg(errstring,
1878 					    CFGA_IB_AP_ERR, ap_id, errno));
1879 				}
1880 
1881 				/* build the logical ap_id */
1882 				(void) snprintf(clp->ap_log_id,
1883 				    sizeof (clp->ap_log_id), "ib%s%s",
1884 				    DYN_SEP, nv_apid);
1885 				DPRINTF("cfga_list_ext: ap_pi = %s, ap_li = %s,"
1886 				    "\nap_info = %s\n", clp->ap_phys_id,
1887 				    clp->ap_log_id, clp->ap_info);
1888 				++count;
1889 
1890 			} else if (strcmp(name, IBNEX_NODE_INFO_NVL) == 0) {
1891 				(void) nvpair_value_string(nvp, &info);
1892 				DPRINTF("cfga_list_ext: Name = %s, info = %s\n",
1893 				    name, info);
1894 				(void) snprintf(clp->ap_info,
1895 				    sizeof (clp->ap_info), "%s", info);
1896 				++count;
1897 
1898 			} else if (strcmp(name, IBNEX_NODE_TYPE_NVL) == 0) {
1899 				(void) nvpair_value_int32(nvp, &node_type);
1900 				if (node_type == IBNEX_PORT_NODE_TYPE) {
1901 					(void) snprintf(clp->ap_type,
1902 					    sizeof (clp->ap_type), "%s",
1903 					    IB_PORT_TYPE);
1904 				} else if (node_type == IBNEX_VPPA_NODE_TYPE) {
1905 					(void) snprintf(clp->ap_type,
1906 					    sizeof (clp->ap_type), "%s",
1907 					    IB_VPPA_TYPE);
1908 				} else if (node_type ==
1909 				    IBNEX_HCASVC_NODE_TYPE) {
1910 					(void) snprintf(clp->ap_type,
1911 					    sizeof (clp->ap_type), "%s",
1912 					    IB_HCASVC_TYPE);
1913 				} else if (node_type == IBNEX_IOC_NODE_TYPE) {
1914 					(void) snprintf(clp->ap_type,
1915 					    sizeof (clp->ap_type), "%s",
1916 					    IB_IOC_TYPE);
1917 				} else if (node_type ==
1918 				    IBNEX_PSEUDO_NODE_TYPE) {
1919 					(void) snprintf(clp->ap_type,
1920 					    sizeof (clp->ap_type), "%s",
1921 					    IB_PSEUDO_TYPE);
1922 				}
1923 				DPRINTF("cfga_list_ext: Name = %s, type = %x\n",
1924 				    name, intval);
1925 				++count;
1926 
1927 			} else if (strcmp(name, IBNEX_NODE_RSTATE_NVL) == 0) {
1928 				(void) nvpair_value_int32(nvp, &intval);
1929 
1930 				if (intval == AP_RSTATE_EMPTY)
1931 					clp->ap_r_state = CFGA_STAT_EMPTY;
1932 				else if (intval == AP_RSTATE_DISCONNECTED)
1933 					clp->ap_r_state =
1934 					    CFGA_STAT_DISCONNECTED;
1935 				else if (intval == AP_RSTATE_CONNECTED)
1936 					clp->ap_r_state = CFGA_STAT_CONNECTED;
1937 				DPRINTF("cfga_list_ext: Name = %s, "
1938 				    "rstate = %x\n", name, intval);
1939 				++count;
1940 
1941 			} else if (strcmp(name, IBNEX_NODE_OSTATE_NVL) == 0) {
1942 				(void) nvpair_value_int32(nvp, &intval);
1943 
1944 				if (intval == AP_OSTATE_CONFIGURED)
1945 					clp->ap_o_state = CFGA_STAT_CONFIGURED;
1946 				else if (intval == AP_OSTATE_UNCONFIGURED)
1947 					clp->ap_o_state =
1948 					    CFGA_STAT_UNCONFIGURED;
1949 				DPRINTF("cfga_list_ext: Name = %s, "
1950 				    "ostate = %x\n", name, intval);
1951 				++count;
1952 
1953 			} else if (strcmp(name, IBNEX_NODE_COND_NVL) == 0) {
1954 				(void) nvpair_value_int32(nvp, &intval);
1955 
1956 				if (intval == AP_COND_OK)
1957 					clp->ap_cond = CFGA_COND_OK;
1958 				else if (intval == AP_COND_FAILING)
1959 					clp->ap_cond = CFGA_COND_FAILING;
1960 				else if (intval == AP_COND_FAILED)
1961 					clp->ap_cond = CFGA_COND_FAILED;
1962 				else if (intval == AP_COND_UNUSABLE)
1963 					clp->ap_cond = CFGA_COND_UNUSABLE;
1964 				else if (intval == AP_COND_UNKNOWN)
1965 					clp->ap_cond = CFGA_COND_UNKNOWN;
1966 				DPRINTF("cfga_list_ext: Name = %s, "
1967 				    "condition = %x\n", name, intval);
1968 				++count;
1969 			}
1970 
1971 			clp->ap_class[0] = '\0'; /* Filled by libcfgadm */
1972 			clp->ap_busy = 0;
1973 			clp->ap_status_time = (time_t)-1;
1974 		} /* end of while */
1975 	}
1976 
1977 	S_FREE(snap_data);
1978 	if (nvl)
1979 		nvlist_free(nvl);
1980 
1981 	/*
1982 	 * if a cmdline specified ap_id doesn't match the known list of ap_ids
1983 	 * then report an error right away
1984 	 */
1985 	rv = (apid_matched ==  B_TRUE) ? CFGA_IB_OK : CFGA_IB_AP_ERR;
1986 	return (ib_err_msg(errstring, rv, ap_id, errno));
1987 }
1988 
1989 
1990 /*
1991  * Function:
1992  *	cfga_msg
1993  * Input:
1994  *	msgp		- cfgadm error message for this plugin
1995  *	str		- string to be passed on to the message
1996  * Output:
1997  *	NONE
1998  * Returns:
1999  *	NONE
2000  * Description:
2001  *	This routine accepts a variable number of message IDs and
2002  *	constructs a corresponding error string which is printed
2003  *	via the message print routine argument.
2004  */
2005 void
2006 cfga_msg(struct cfga_msg *msgp, const char *str)
2007 {
2008 	int len;
2009 	char *q;
2010 
2011 	if (msgp == NULL || msgp->message_routine == NULL) {
2012 		DPRINTF("cfga_msg: msg\n");
2013 		return;
2014 	}
2015 
2016 	if ((len = strlen(str)) == 0) {
2017 		DPRINTF("cfga_msg: null str\n");
2018 		return;
2019 	}
2020 
2021 	if ((q = (char *)calloc(len + 1, 1)) == NULL) {
2022 		DPRINTF("cfga_msg: null q\n");
2023 		return;
2024 	}
2025 
2026 	(void) strlcpy(q, str, len + 1);
2027 	(*msgp->message_routine)(msgp->appdata_ptr, q);
2028 
2029 	free(q);
2030 }
2031 
2032 
2033 /*
2034  * Function:
2035  *	cfga_help
2036  * Input:
2037  *	msgp		- Help message passed on to cfgadm(1M)
2038  *	options		- Help message options passed on to cfgadm(1M)
2039  *	flags		- Cfgadm(1m) flags
2040  * Output:
2041  *	NONE
2042  * Returns:
2043  *	Were we able to print cfgadm help or not for this plugin
2044  * Description:
2045  *	Print cfgadm help for this plugin
2046  */
2047 /* ARGSUSED */
2048 cfga_err_t
2049 cfga_help(struct cfga_msg *msgp, const char *options, cfga_flags_t flags)
2050 {
2051 	DPRINTF("cfga_help:\n");
2052 
2053 	if (options) {
2054 		cfga_msg(msgp, dgettext(TEXT_DOMAIN, ib_help[
2055 		    CFGA_IB_HELP_UNKNOWN]));
2056 		cfga_msg(msgp, options);
2057 	}
2058 
2059 	/* Print messages array */
2060 	cfga_msg(msgp, dgettext(TEXT_DOMAIN, ib_help[CFGA_IB_HELP_HEADER]));
2061 	cfga_msg(msgp, ib_help[CFGA_IB_HELP_CONFIG]);
2062 	cfga_msg(msgp, ib_help[CFGA_IB_HELP_LIST]);
2063 	cfga_msg(msgp, ib_help[CFGA_IB_HELP_UPD_PKEY]);
2064 	cfga_msg(msgp, ib_help[CFGA_IB_HELP_CONF_FILE1]);
2065 	cfga_msg(msgp, ib_help[CFGA_IB_HELP_CONF_FILE2]);
2066 	cfga_msg(msgp, ib_help[CFGA_IB_HELP_UPD_IOC_CONF]);
2067 	cfga_msg(msgp, ib_help[CFGA_IB_HELP_UNCFG_CLNTS]);
2068 
2069 	return (CFGA_OK);
2070 }
2071 
2072 
2073 /*
2074  * Function:
2075  *	ib_confirm
2076  * Input:
2077  *	confp		- The "cfga" structure that confirms a cfgadm query
2078  *	msg		- The message that needs confirmation
2079  * Output:
2080  *	None
2081  * Returns:
2082  *	If a user entered YES or NO
2083  * Description:
2084  *	Queries a user if it is ok to proceed with an operation or not.
2085  *	Returns user's response.
2086  */
2087 static int
2088 ib_confirm(struct cfga_confirm *confp, char *msg)
2089 {
2090 	int rval;
2091 
2092 	/* check that "confirm" function exists */
2093 	if (confp == NULL || confp->confirm == NULL) {
2094 		return (0);
2095 	}
2096 
2097 	/* Call cfgadm provided "confirm" function */
2098 	rval = (*confp->confirm)(confp->appdata_ptr, msg);
2099 	DPRINTF("ib_confirm: %d\n", rval);
2100 
2101 	return (rval);
2102 }
2103 
2104 
2105 /*
2106  * Function:
2107  *	ib_get_devicepath
2108  * Input:
2109  *	ap_id		- The dynamic attachment point of an IB device
2110  * Output:
2111  *	None
2112  * Returns:
2113  *	devpath if it exists; otherwise NULL
2114  * Description:
2115  *	Returns the devicepath for a dynamic attachment point of an IB device
2116  */
2117 static char *
2118 ib_get_devicepath(const char *ap_id)
2119 {
2120 	char		*devpath = NULL;
2121 	size_t		size;
2122 
2123 	/* Get device path sizes */
2124 	if (ib_do_control_ioctl((char *)ap_id, IBNEX_DEVICE_PATH_SZ,
2125 	    IBNEX_GET_DEVICE_PATH, 0, (void **)&devpath, &size) == CFGA_IB_OK) {
2126 		DPRINTF("ib_get_devicepath: get device path ioctl ok\n");
2127 		return (devpath);
2128 
2129 	} else {
2130 		DPRINTF("ib_get_devicepath: get device path ioctl failed\n");
2131 		return ((char *)NULL);
2132 	}
2133 }
2134