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