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