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