xref: /onnv-gate/usr/src/lib/cfgadm_plugins/shp/common/shp.c (revision 12821:c2b074364dff)
110923SEvan.Yan@Sun.COM /*
210923SEvan.Yan@Sun.COM  * CDDL HEADER START
310923SEvan.Yan@Sun.COM  *
410923SEvan.Yan@Sun.COM  * The contents of this file are subject to the terms of the
510923SEvan.Yan@Sun.COM  * Common Development and Distribution License (the "License").
610923SEvan.Yan@Sun.COM  * You may not use this file except in compliance with the License.
710923SEvan.Yan@Sun.COM  *
810923SEvan.Yan@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
910923SEvan.Yan@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1010923SEvan.Yan@Sun.COM  * See the License for the specific language governing permissions
1110923SEvan.Yan@Sun.COM  * and limitations under the License.
1210923SEvan.Yan@Sun.COM  *
1310923SEvan.Yan@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1410923SEvan.Yan@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1510923SEvan.Yan@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1610923SEvan.Yan@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1710923SEvan.Yan@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1810923SEvan.Yan@Sun.COM  *
1910923SEvan.Yan@Sun.COM  * CDDL HEADER END
2010923SEvan.Yan@Sun.COM  */
2110923SEvan.Yan@Sun.COM 
2210923SEvan.Yan@Sun.COM /*
2312555SScott.Carter@Oracle.COM  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2410923SEvan.Yan@Sun.COM  */
2510923SEvan.Yan@Sun.COM 
2610923SEvan.Yan@Sun.COM /*
2710923SEvan.Yan@Sun.COM  *	Plugin library for PCI Express and PCI (SHPC) hotplug controller
2810923SEvan.Yan@Sun.COM  */
2910923SEvan.Yan@Sun.COM 
3010923SEvan.Yan@Sun.COM #include <stddef.h>
3110923SEvan.Yan@Sun.COM #include <locale.h>
3210923SEvan.Yan@Sun.COM #include <ctype.h>
3310923SEvan.Yan@Sun.COM #include <stdio.h>
3410923SEvan.Yan@Sun.COM #include <stdlib.h>
3510923SEvan.Yan@Sun.COM #include <string.h>
3610923SEvan.Yan@Sun.COM #include <fcntl.h>
3710923SEvan.Yan@Sun.COM #include <unistd.h>
3810923SEvan.Yan@Sun.COM #include <errno.h>
3910923SEvan.Yan@Sun.COM #include <locale.h>
4010923SEvan.Yan@Sun.COM #include <langinfo.h>
4110923SEvan.Yan@Sun.COM #include <time.h>
4210923SEvan.Yan@Sun.COM #include <sys/param.h>
4310923SEvan.Yan@Sun.COM #include <stdarg.h>
4410923SEvan.Yan@Sun.COM #include <libdevinfo.h>
4510923SEvan.Yan@Sun.COM #include <libdevice.h>
4610923SEvan.Yan@Sun.COM 
4710923SEvan.Yan@Sun.COM #define	CFGA_PLUGIN_LIB
4810923SEvan.Yan@Sun.COM 
4910923SEvan.Yan@Sun.COM #include <config_admin.h>
5010923SEvan.Yan@Sun.COM 
5110923SEvan.Yan@Sun.COM #include <assert.h>
5210923SEvan.Yan@Sun.COM #include <sys/types.h>
5310923SEvan.Yan@Sun.COM #include <sys/stat.h>
5410923SEvan.Yan@Sun.COM #include <sys/dditypes.h>
5510923SEvan.Yan@Sun.COM #include <sys/pci.h>
5610923SEvan.Yan@Sun.COM #include <libintl.h>
5710923SEvan.Yan@Sun.COM 
5810923SEvan.Yan@Sun.COM #include <dirent.h>
5910923SEvan.Yan@Sun.COM #include <limits.h>
6010923SEvan.Yan@Sun.COM #include <sys/mkdev.h>
6110923SEvan.Yan@Sun.COM #include "../../../../uts/common/sys/hotplug/pci/pcie_hp.h"
6210923SEvan.Yan@Sun.COM #include "../../../../common/pci/pci_strings.h"
6310923SEvan.Yan@Sun.COM #include <libhotplug.h>
6410923SEvan.Yan@Sun.COM 
6510923SEvan.Yan@Sun.COM extern const struct pci_class_strings_s class_pci[];
6610923SEvan.Yan@Sun.COM extern int class_pci_items;
6710923SEvan.Yan@Sun.COM 
6810923SEvan.Yan@Sun.COM #define	MSG_HOTPLUG_DISABLED \
6910923SEvan.Yan@Sun.COM 	"Error: hotplug service is probably not running, " \
7010923SEvan.Yan@Sun.COM 	"please use 'svcadm enable hotplug' to enable the service. " \
7110923SEvan.Yan@Sun.COM 	"See cfgadm_shp(1M) for more details."
7210923SEvan.Yan@Sun.COM 
7310923SEvan.Yan@Sun.COM #define	DEVICES_DIR		"/devices"
7410923SEvan.Yan@Sun.COM #define	SLASH			"/"
7510923SEvan.Yan@Sun.COM #define	GET_DYN(a)	(strstr((a), CFGA_DYN_SEP))
7610923SEvan.Yan@Sun.COM 
7710923SEvan.Yan@Sun.COM /*
7810923SEvan.Yan@Sun.COM  * Set the version number
7910923SEvan.Yan@Sun.COM  */
8010923SEvan.Yan@Sun.COM int cfga_version = CFGA_HSL_V2;
8110923SEvan.Yan@Sun.COM 
8210923SEvan.Yan@Sun.COM #ifdef	DEBUG
8310923SEvan.Yan@Sun.COM #define	SHP_DBG	1
8410923SEvan.Yan@Sun.COM #endif
8510923SEvan.Yan@Sun.COM 
8610923SEvan.Yan@Sun.COM #if !defined(TEXT_DOMAIN)
8710923SEvan.Yan@Sun.COM #define	TEXT_DOMAIN	"SYS_TEST"
8810923SEvan.Yan@Sun.COM #endif
8910923SEvan.Yan@Sun.COM 
9010923SEvan.Yan@Sun.COM /*
9110923SEvan.Yan@Sun.COM  *	DEBUGING LEVEL
9210923SEvan.Yan@Sun.COM  *
9310923SEvan.Yan@Sun.COM  * 	External routines:  1 - 2
9410923SEvan.Yan@Sun.COM  *	Internal routines:  3 - 4
9510923SEvan.Yan@Sun.COM  */
9610923SEvan.Yan@Sun.COM #ifdef	SHP_DBG
9710923SEvan.Yan@Sun.COM int	shp_debug = 1;
9810923SEvan.Yan@Sun.COM #define	DBG(level, args) \
9910923SEvan.Yan@Sun.COM 	{ if (shp_debug >= (level)) printf args; }
10010923SEvan.Yan@Sun.COM #define	DBG_F(level, args) \
10110923SEvan.Yan@Sun.COM 	{ if (shp_debug >= (level)) fprintf args; }
10210923SEvan.Yan@Sun.COM #else
10310923SEvan.Yan@Sun.COM #define	DBG(level, args)	/* nothing */
10410923SEvan.Yan@Sun.COM #define	DBG_F(level, args)	/* nothing */
10510923SEvan.Yan@Sun.COM #endif
10610923SEvan.Yan@Sun.COM 
10710923SEvan.Yan@Sun.COM #define	CMD_ACQUIRE		0
10810923SEvan.Yan@Sun.COM #define	CMD_GETSTAT		1
10910923SEvan.Yan@Sun.COM #define	CMD_LIST		2
11010923SEvan.Yan@Sun.COM #define	CMD_SLOT_CONNECT	3
11110923SEvan.Yan@Sun.COM #define	CMD_SLOT_DISCONNECT	4
11210923SEvan.Yan@Sun.COM #define	CMD_SLOT_CONFIGURE	5
11310923SEvan.Yan@Sun.COM #define	CMD_SLOT_UNCONFIGURE	6
11410923SEvan.Yan@Sun.COM #define	CMD_SLOT_INSERT		7
11510923SEvan.Yan@Sun.COM #define	CMD_SLOT_REMOVE		8
11610923SEvan.Yan@Sun.COM #define	CMD_OPEN		9
11710923SEvan.Yan@Sun.COM #define	CMD_FSTAT		10
11810923SEvan.Yan@Sun.COM #define	ERR_CMD_INVAL		11
11910923SEvan.Yan@Sun.COM #define	ERR_AP_INVAL		12
12010923SEvan.Yan@Sun.COM #define	ERR_AP_ERR		13
12110923SEvan.Yan@Sun.COM #define	ERR_OPT_INVAL		14
12210923SEvan.Yan@Sun.COM 
12310923SEvan.Yan@Sun.COM static char *
12410923SEvan.Yan@Sun.COM cfga_errstrs[] = {
12510923SEvan.Yan@Sun.COM 	/* n */ "acquire ",
12610923SEvan.Yan@Sun.COM 	/* n */ "get-status ",
12710923SEvan.Yan@Sun.COM 	/* n */ "list ",
12810923SEvan.Yan@Sun.COM 	/* n */ "connect ",
12910923SEvan.Yan@Sun.COM 	/* n */ "disconnect ",
13010923SEvan.Yan@Sun.COM 	/* n */ "configure ",
13110923SEvan.Yan@Sun.COM 	/* n */ "unconfigure ",
13210923SEvan.Yan@Sun.COM 	/* n */ "insert ",
13310923SEvan.Yan@Sun.COM 	/* n */ "remove ",
13410923SEvan.Yan@Sun.COM 	/* n */ "open ",
13510923SEvan.Yan@Sun.COM 	/* n */ "fstat ",
13610923SEvan.Yan@Sun.COM 	/* y */ "invalid command ",
13710923SEvan.Yan@Sun.COM 	/* y */ "invalid attachment point ",
13810923SEvan.Yan@Sun.COM 	/* y */ "invalid transition ",
13910923SEvan.Yan@Sun.COM 	/* y */ "invalid option ",
14010923SEvan.Yan@Sun.COM 		NULL
14110923SEvan.Yan@Sun.COM };
14210923SEvan.Yan@Sun.COM 
14310923SEvan.Yan@Sun.COM #define	HELP_HEADER		1
14410923SEvan.Yan@Sun.COM #define	HELP_CONFIG		2
14510923SEvan.Yan@Sun.COM #define	HELP_ENABLE_SLOT	3
14610923SEvan.Yan@Sun.COM #define	HELP_DISABLE_SLOT	4
14710923SEvan.Yan@Sun.COM #define	HELP_ENABLE_AUTOCONF	5
14810923SEvan.Yan@Sun.COM #define	HELP_DISABLE_AUTOCONF	6
14910923SEvan.Yan@Sun.COM #define	HELP_LED_CNTRL		7
15010923SEvan.Yan@Sun.COM #define	HELP_UNKNOWN		8
15110923SEvan.Yan@Sun.COM #define	SUCCESS			9
15210923SEvan.Yan@Sun.COM #define	FAILED			10
15310923SEvan.Yan@Sun.COM #define	UNKNOWN			11
15410923SEvan.Yan@Sun.COM 
15510923SEvan.Yan@Sun.COM #define	MAXLINE			256
15610923SEvan.Yan@Sun.COM 
15710923SEvan.Yan@Sun.COM extern int errno;
15810923SEvan.Yan@Sun.COM 
15910923SEvan.Yan@Sun.COM static void cfga_err(char **errstring, ...);
16010923SEvan.Yan@Sun.COM static cfga_err_t fix_ap_name(char *ap_log_id, const char *ap_id,
16110923SEvan.Yan@Sun.COM     char *slot_name, char **errstring);
16210923SEvan.Yan@Sun.COM static cfga_err_t check_options(const char *options);
16310923SEvan.Yan@Sun.COM static void cfga_msg(struct cfga_msg *msgp, const char *str);
16410923SEvan.Yan@Sun.COM static char *findlink(char *ap_phys_id);
16510923SEvan.Yan@Sun.COM 
16610923SEvan.Yan@Sun.COM static char *
16710923SEvan.Yan@Sun.COM cfga_strs[] = {
16810923SEvan.Yan@Sun.COM NULL,
16910923SEvan.Yan@Sun.COM "\nPCI hotplug specific commands:",
17010923SEvan.Yan@Sun.COM "\t-c [connect|disconnect|configure|unconfigure|insert|remove] "
17110923SEvan.Yan@Sun.COM "ap_id [ap_id...]",
17210923SEvan.Yan@Sun.COM "\t-x enable_slot  ap_id [ap_id...]",
17310923SEvan.Yan@Sun.COM "\t-x disable_slot ap_id [ap_id...]",
17410923SEvan.Yan@Sun.COM "\t-x enable_autoconfig  ap_id [ap_id...]",
17510923SEvan.Yan@Sun.COM "\t-x disable_autoconfig ap_id [ap_id...]",
17610923SEvan.Yan@Sun.COM "\t-x led[=[fault|power|active|attn],mode=[on|off|blink]] ap_id [ap_id...]",
17710923SEvan.Yan@Sun.COM "\tunknown command or option: ",
17810923SEvan.Yan@Sun.COM "success   ",
17910923SEvan.Yan@Sun.COM "failed   ",
18010923SEvan.Yan@Sun.COM "unknown",
18110923SEvan.Yan@Sun.COM NULL
18210923SEvan.Yan@Sun.COM };
18310923SEvan.Yan@Sun.COM 
18410923SEvan.Yan@Sun.COM #define	MAX_FORMAT 80
18510923SEvan.Yan@Sun.COM 
18610923SEvan.Yan@Sun.COM #define	ENABLE_SLOT	0
18710923SEvan.Yan@Sun.COM #define	DISABLE_SLOT	1
18810923SEvan.Yan@Sun.COM #define	ENABLE_AUTOCNF	2
18910923SEvan.Yan@Sun.COM #define	DISABLE_AUTOCNF	3
19010923SEvan.Yan@Sun.COM #define	LED		4
19110923SEvan.Yan@Sun.COM #define	MODE		5
19210923SEvan.Yan@Sun.COM 
19310923SEvan.Yan@Sun.COM typedef	enum { PCIEHPC_FAULT_LED, PCIEHPC_POWER_LED, PCIEHPC_ATTN_LED,
19410923SEvan.Yan@Sun.COM 	PCIEHPC_ACTIVE_LED} pciehpc_led_t;
19510923SEvan.Yan@Sun.COM 
19610923SEvan.Yan@Sun.COM typedef	enum { PCIEHPC_BOARD_UNKNOWN, PCIEHPC_BOARD_PCI_HOTPLUG }
19710923SEvan.Yan@Sun.COM 	pciehpc_board_type_t;
19810923SEvan.Yan@Sun.COM 
19910923SEvan.Yan@Sun.COM /*
20010923SEvan.Yan@Sun.COM  * Board Type
20110923SEvan.Yan@Sun.COM  */
20210923SEvan.Yan@Sun.COM static char *
20310923SEvan.Yan@Sun.COM board_strs[] = {
20410923SEvan.Yan@Sun.COM 	/* n */ "???",	/* PCIEHPC_BOARD_UNKNOWN */
20510923SEvan.Yan@Sun.COM 	/* n */ "hp",	/* PCIEHPC_BOARD_PCI_HOTPLUG */
20610923SEvan.Yan@Sun.COM 	/* n */ NULL
20710923SEvan.Yan@Sun.COM };
20810923SEvan.Yan@Sun.COM 
20910923SEvan.Yan@Sun.COM /*
21010923SEvan.Yan@Sun.COM  * HW functions
21110923SEvan.Yan@Sun.COM  */
21210923SEvan.Yan@Sun.COM static char *
21310923SEvan.Yan@Sun.COM func_strs[] = {
21410923SEvan.Yan@Sun.COM 	/* n */ "enable_slot",
21510923SEvan.Yan@Sun.COM 	/* n */ "disable_slot",
21610923SEvan.Yan@Sun.COM 	/* n */ "enable_autoconfig",
21710923SEvan.Yan@Sun.COM 	/* n */ "disable_autoconfig",
21810923SEvan.Yan@Sun.COM 	/* n */ "led",
21910923SEvan.Yan@Sun.COM 	/* n */ "mode",
22010923SEvan.Yan@Sun.COM 	/* n */ NULL
22110923SEvan.Yan@Sun.COM };
22210923SEvan.Yan@Sun.COM 
22310923SEvan.Yan@Sun.COM /*
22410923SEvan.Yan@Sun.COM  * LED strings
22510923SEvan.Yan@Sun.COM  */
22610923SEvan.Yan@Sun.COM static char *
22710923SEvan.Yan@Sun.COM led_strs[] = {
22810923SEvan.Yan@Sun.COM 	/* n */ "fault",	/* PCIEHPC_FAULT_LED */
22910923SEvan.Yan@Sun.COM 	/* n */ "power",	/* PCIEHPC_POWER_LED */
23010923SEvan.Yan@Sun.COM 	/* n */ "attn",		/* PCIEHPC_ATTN_LED */
23110923SEvan.Yan@Sun.COM 	/* n */ "active",	/* PCIEHPC_ACTIVE_LED */
23210923SEvan.Yan@Sun.COM 	/* n */ NULL
23310923SEvan.Yan@Sun.COM };
23410923SEvan.Yan@Sun.COM 
23510923SEvan.Yan@Sun.COM static char *
23610923SEvan.Yan@Sun.COM led_strs2[] = {
23710923SEvan.Yan@Sun.COM 	/* n */ PCIEHPC_PROP_LED_FAULT,		/* PCIEHPC_FAULT_LED */
23810923SEvan.Yan@Sun.COM 	/* n */ PCIEHPC_PROP_LED_POWER,		/* PCIEHPC_POWER_LED */
23910923SEvan.Yan@Sun.COM 	/* n */ PCIEHPC_PROP_LED_ATTN,		/* PCIEHPC_ATTN_LED */
24010923SEvan.Yan@Sun.COM 	/* n */ PCIEHPC_PROP_LED_ACTIVE,	/* PCIEHPC_ACTIVE_LED */
24110923SEvan.Yan@Sun.COM 	/* n */ NULL
24210923SEvan.Yan@Sun.COM };
24310923SEvan.Yan@Sun.COM 
24410923SEvan.Yan@Sun.COM #define	FAULT	0
24510923SEvan.Yan@Sun.COM #define	POWER	1
24610923SEvan.Yan@Sun.COM #define	ATTN	2
24710923SEvan.Yan@Sun.COM #define	ACTIVE	3
24810923SEvan.Yan@Sun.COM 
24910923SEvan.Yan@Sun.COM static char *
25010923SEvan.Yan@Sun.COM mode_strs[] = {
25110923SEvan.Yan@Sun.COM 	/* n */ "off",		/* OFF */
25210923SEvan.Yan@Sun.COM 	/* n */ "on",		/* ON */
25310923SEvan.Yan@Sun.COM 	/* n */ "blink",	/* BLINK */
25410923SEvan.Yan@Sun.COM 	/* n */	NULL
25510923SEvan.Yan@Sun.COM };
25610923SEvan.Yan@Sun.COM 
25710923SEvan.Yan@Sun.COM #define	OFF	0
25810923SEvan.Yan@Sun.COM #define	ON	1
25910923SEvan.Yan@Sun.COM #define	BLINK	2
26010923SEvan.Yan@Sun.COM 
26110923SEvan.Yan@Sun.COM #define	cfga_errstrs(i)		cfga_errstrs[(i)]
26210923SEvan.Yan@Sun.COM 
26310923SEvan.Yan@Sun.COM #define	cfga_eid(a, b)		(((a) << 8) + (b))
26410923SEvan.Yan@Sun.COM #define	MAXDEVS			32
26510923SEvan.Yan@Sun.COM 
26610923SEvan.Yan@Sun.COM typedef enum {
26710923SEvan.Yan@Sun.COM 	SOLARIS_SLT_NAME,
26810923SEvan.Yan@Sun.COM 	PROM_SLT_NAME
26910923SEvan.Yan@Sun.COM } slt_name_src_t;
27010923SEvan.Yan@Sun.COM 
27110923SEvan.Yan@Sun.COM struct searcharg {
27210923SEvan.Yan@Sun.COM 	char	*devpath;
27310923SEvan.Yan@Sun.COM 	char	slotnames[MAXDEVS][MAXNAMELEN];
27410923SEvan.Yan@Sun.COM 	int	minor;
27510923SEvan.Yan@Sun.COM 	di_prom_handle_t	promp;
27610923SEvan.Yan@Sun.COM 	slt_name_src_t	slt_name_src;
27710923SEvan.Yan@Sun.COM };
27810923SEvan.Yan@Sun.COM 
27910923SEvan.Yan@Sun.COM static void *private_check;
28010923SEvan.Yan@Sun.COM 
28110923SEvan.Yan@Sun.COM /*
28210923SEvan.Yan@Sun.COM  * Return the corresponding hp node for a given ap_id, it is the caller's
28310923SEvan.Yan@Sun.COM  * responsibility to call hp_fini() to free the snapshot.
28410923SEvan.Yan@Sun.COM  */
28510923SEvan.Yan@Sun.COM static cfga_err_t
physpath2node(const char * physpath,char ** errstring,hp_node_t * nodep)28610923SEvan.Yan@Sun.COM physpath2node(const char *physpath, char **errstring, hp_node_t *nodep)
28710923SEvan.Yan@Sun.COM {
28810923SEvan.Yan@Sun.COM 	char *rpath;
28910923SEvan.Yan@Sun.COM 	char *cp;
29010923SEvan.Yan@Sun.COM 	hp_node_t node;
29110923SEvan.Yan@Sun.COM 	size_t len;
29210923SEvan.Yan@Sun.COM 	char *errmsg;
29310923SEvan.Yan@Sun.COM 
29410923SEvan.Yan@Sun.COM 	if (getuid() != 0 && geteuid() != 0)
29510923SEvan.Yan@Sun.COM 		return (CFGA_ERROR);
29610923SEvan.Yan@Sun.COM 
29710923SEvan.Yan@Sun.COM 	if ((rpath = malloc(strlen(physpath) + 1)) == NULL)
29810923SEvan.Yan@Sun.COM 		return (CFGA_ERROR);
29910923SEvan.Yan@Sun.COM 
30010923SEvan.Yan@Sun.COM 	(void) strcpy(rpath, physpath);
30110923SEvan.Yan@Sun.COM 
30210923SEvan.Yan@Sun.COM 	/* Remove devices prefix (if any) */
30310923SEvan.Yan@Sun.COM 	len = strlen(DEVICES_DIR);
30410923SEvan.Yan@Sun.COM 	if (strncmp(rpath, DEVICES_DIR SLASH, len + strlen(SLASH)) == 0) {
30510923SEvan.Yan@Sun.COM 		(void) memmove(rpath, rpath + len,
30610923SEvan.Yan@Sun.COM 		    strlen(rpath + len) + 1);
30710923SEvan.Yan@Sun.COM 	}
30810923SEvan.Yan@Sun.COM 
30910923SEvan.Yan@Sun.COM 	/* Remove dynamic component if any */
31010923SEvan.Yan@Sun.COM 	if ((cp = GET_DYN(rpath)) != NULL) {
31110923SEvan.Yan@Sun.COM 		*cp = '\0';
31210923SEvan.Yan@Sun.COM 	}
31310923SEvan.Yan@Sun.COM 
31410923SEvan.Yan@Sun.COM 	/* Remove minor name (if any) */
31510923SEvan.Yan@Sun.COM 	if ((cp = strrchr(rpath, ':')) == NULL) {
31610923SEvan.Yan@Sun.COM 		free(rpath);
31710923SEvan.Yan@Sun.COM 		return (CFGA_INVAL);
31810923SEvan.Yan@Sun.COM 	}
31910923SEvan.Yan@Sun.COM 
32010923SEvan.Yan@Sun.COM 	*cp = '\0';
32110923SEvan.Yan@Sun.COM 	cp++;
32210923SEvan.Yan@Sun.COM 
32310923SEvan.Yan@Sun.COM 	DBG(1, ("rpath=%s,cp=%s\n", rpath, cp));
32410923SEvan.Yan@Sun.COM 	if ((node = hp_init(rpath, cp, 0)) == NULL) {
32510923SEvan.Yan@Sun.COM 		if (errno == EBADF) {
32610923SEvan.Yan@Sun.COM 			/* No reponse to operations on the door file. */
32710923SEvan.Yan@Sun.COM 			assert(errstring != NULL);
32810923SEvan.Yan@Sun.COM 			*errstring = strdup(MSG_HOTPLUG_DISABLED);
32910923SEvan.Yan@Sun.COM 			free(rpath);
33010923SEvan.Yan@Sun.COM 			return (CFGA_NOTSUPP);
33110923SEvan.Yan@Sun.COM 		}
33210923SEvan.Yan@Sun.COM 		free(rpath);
33310923SEvan.Yan@Sun.COM 		return (CFGA_ERROR);
33410923SEvan.Yan@Sun.COM 	}
33510923SEvan.Yan@Sun.COM 
33610923SEvan.Yan@Sun.COM 	free(rpath);
33710923SEvan.Yan@Sun.COM 
33810923SEvan.Yan@Sun.COM 	*nodep = node;
33910923SEvan.Yan@Sun.COM 	return (CFGA_OK);
34010923SEvan.Yan@Sun.COM }
34110923SEvan.Yan@Sun.COM 
34210923SEvan.Yan@Sun.COM typedef struct error_size_cb_arg {
34310923SEvan.Yan@Sun.COM 	size_t	rsrc_width;
34410923SEvan.Yan@Sun.COM 	size_t	info_width;
34510923SEvan.Yan@Sun.COM 	int	cnt;
34610923SEvan.Yan@Sun.COM } error_size_cb_arg_t;
34710923SEvan.Yan@Sun.COM 
34810923SEvan.Yan@Sun.COM /*
34910923SEvan.Yan@Sun.COM  * Callback function for hp_traverse(), to sum up the
35010923SEvan.Yan@Sun.COM  * maximum length for error message display.
35110923SEvan.Yan@Sun.COM  */
35210923SEvan.Yan@Sun.COM static int
error_sizeup_cb(hp_node_t node,void * arg)35310923SEvan.Yan@Sun.COM error_sizeup_cb(hp_node_t node, void *arg)
35410923SEvan.Yan@Sun.COM {
35510923SEvan.Yan@Sun.COM 	error_size_cb_arg_t	*sizearg = (error_size_cb_arg_t *)arg;
35610923SEvan.Yan@Sun.COM 	size_t 			len;
35710923SEvan.Yan@Sun.COM 
35810923SEvan.Yan@Sun.COM 	/* Only process USAGE nodes */
35910923SEvan.Yan@Sun.COM 	if (hp_type(node) != HP_NODE_USAGE)
36010923SEvan.Yan@Sun.COM 		return (HP_WALK_CONTINUE);
36110923SEvan.Yan@Sun.COM 
36210923SEvan.Yan@Sun.COM 	sizearg->cnt++;
36310923SEvan.Yan@Sun.COM 
36410923SEvan.Yan@Sun.COM 	/* size up resource name */
36510923SEvan.Yan@Sun.COM 	len = strlen(hp_name(node));
36610923SEvan.Yan@Sun.COM 	if (sizearg->rsrc_width < len)
36710923SEvan.Yan@Sun.COM 		sizearg->rsrc_width = len;
36810923SEvan.Yan@Sun.COM 
36910923SEvan.Yan@Sun.COM 	/* size up usage description */
37010923SEvan.Yan@Sun.COM 	len = strlen(hp_usage(node));
37110923SEvan.Yan@Sun.COM 	if (sizearg->info_width < len)
37210923SEvan.Yan@Sun.COM 		sizearg->info_width = len;
37310923SEvan.Yan@Sun.COM 
37410923SEvan.Yan@Sun.COM 	return (HP_WALK_CONTINUE);
37510923SEvan.Yan@Sun.COM }
37610923SEvan.Yan@Sun.COM 
37710923SEvan.Yan@Sun.COM typedef struct error_sum_cb_arg {
37810923SEvan.Yan@Sun.COM 	char **table;
37910923SEvan.Yan@Sun.COM 	char *format;
38010923SEvan.Yan@Sun.COM } error_sum_cb_arg_t;
38110923SEvan.Yan@Sun.COM 
38210923SEvan.Yan@Sun.COM /*
38310923SEvan.Yan@Sun.COM  * Callback function for hp_traverse(), to add the error
38410923SEvan.Yan@Sun.COM  * message to he table.
38510923SEvan.Yan@Sun.COM  */
38610923SEvan.Yan@Sun.COM static int
error_sumup_cb(hp_node_t node,void * arg)38710923SEvan.Yan@Sun.COM error_sumup_cb(hp_node_t node, void *arg)
38810923SEvan.Yan@Sun.COM {
38910923SEvan.Yan@Sun.COM 	error_sum_cb_arg_t *sumarg = (error_sum_cb_arg_t *)arg;
39010923SEvan.Yan@Sun.COM 	char **table = sumarg->table;
39110923SEvan.Yan@Sun.COM 	char *format = sumarg->format;
39210923SEvan.Yan@Sun.COM 
39310923SEvan.Yan@Sun.COM 	/* Only process USAGE nodes */
39410923SEvan.Yan@Sun.COM 	if (hp_type(node) != HP_NODE_USAGE)
39510923SEvan.Yan@Sun.COM 		return (HP_WALK_CONTINUE);
39610923SEvan.Yan@Sun.COM 
39710923SEvan.Yan@Sun.COM 	(void) strcat(*table, "\n");
39810923SEvan.Yan@Sun.COM 	(void) sprintf(&((*table)[strlen(*table)]),
39910923SEvan.Yan@Sun.COM 	    format, hp_name(node), hp_usage(node));
40010923SEvan.Yan@Sun.COM 
40110923SEvan.Yan@Sun.COM 	return (HP_WALK_CONTINUE);
40210923SEvan.Yan@Sun.COM }
40310923SEvan.Yan@Sun.COM 
40410923SEvan.Yan@Sun.COM /*
40510923SEvan.Yan@Sun.COM  * Takes an opaque rcm_info_t pointer and a character pointer, and appends
40610923SEvan.Yan@Sun.COM  * the rcm_info_t data in the form of a table to the given character pointer.
40710923SEvan.Yan@Sun.COM  */
40810923SEvan.Yan@Sun.COM static void
pci_rcm_info_table(hp_node_t node,char ** table)40910923SEvan.Yan@Sun.COM pci_rcm_info_table(hp_node_t node, char **table)
41010923SEvan.Yan@Sun.COM {
41110923SEvan.Yan@Sun.COM 	int i;
41210923SEvan.Yan@Sun.COM 	size_t w;
41310923SEvan.Yan@Sun.COM 	size_t width = 0;
41410923SEvan.Yan@Sun.COM 	size_t w_rsrc = 0;
41510923SEvan.Yan@Sun.COM 	size_t w_info = 0;
41610923SEvan.Yan@Sun.COM 	size_t table_size = 0;
41710923SEvan.Yan@Sun.COM 	uint_t tuples = 0;
41810923SEvan.Yan@Sun.COM 	char *rsrc;
41910923SEvan.Yan@Sun.COM 	char *info;
42010923SEvan.Yan@Sun.COM 	char *newtable;
42110923SEvan.Yan@Sun.COM 	static char format[MAX_FORMAT];
42210923SEvan.Yan@Sun.COM 	const char *infostr;
42310923SEvan.Yan@Sun.COM 	error_size_cb_arg_t sizearg;
42410923SEvan.Yan@Sun.COM 	error_sum_cb_arg_t sumarg;
42510923SEvan.Yan@Sun.COM 
42610923SEvan.Yan@Sun.COM 	/* Protect against invalid arguments */
42710923SEvan.Yan@Sun.COM 	if (table == NULL)
42810923SEvan.Yan@Sun.COM 		return;
42910923SEvan.Yan@Sun.COM 
43010923SEvan.Yan@Sun.COM 	/* Set localized table header strings */
43110923SEvan.Yan@Sun.COM 	rsrc = dgettext(TEXT_DOMAIN, "Resource");
43210923SEvan.Yan@Sun.COM 	info = dgettext(TEXT_DOMAIN, "Information");
43310923SEvan.Yan@Sun.COM 
43410923SEvan.Yan@Sun.COM 	/* A first pass, to size up the RCM information */
43510923SEvan.Yan@Sun.COM 	sizearg.rsrc_width = strlen(rsrc);
43610923SEvan.Yan@Sun.COM 	sizearg.info_width = strlen(info);
43710923SEvan.Yan@Sun.COM 	sizearg.cnt = 0;
43810923SEvan.Yan@Sun.COM 	(void) hp_traverse(node, &sizearg, error_sizeup_cb);
43910923SEvan.Yan@Sun.COM 
44010923SEvan.Yan@Sun.COM 	/* If nothing was sized up above, stop early */
44110923SEvan.Yan@Sun.COM 	if (sizearg.cnt == 0)
44210923SEvan.Yan@Sun.COM 		return;
44310923SEvan.Yan@Sun.COM 
44410923SEvan.Yan@Sun.COM 	w_rsrc = sizearg.rsrc_width;
44510923SEvan.Yan@Sun.COM 	w_info = sizearg.info_width;
44610923SEvan.Yan@Sun.COM 	tuples = sizearg.cnt;
44710923SEvan.Yan@Sun.COM 
44810923SEvan.Yan@Sun.COM 	/* Adjust column widths for column headings */
44910923SEvan.Yan@Sun.COM 	if ((w = strlen(rsrc)) > w_rsrc)
45010923SEvan.Yan@Sun.COM 		w_rsrc = w;
45110923SEvan.Yan@Sun.COM 	else if ((w_rsrc - w) % 2)
45210923SEvan.Yan@Sun.COM 		w_rsrc++;
45310923SEvan.Yan@Sun.COM 	if ((w = strlen(info)) > w_info)
45410923SEvan.Yan@Sun.COM 		w_info = w;
45510923SEvan.Yan@Sun.COM 	else if ((w_info - w) % 2)
45610923SEvan.Yan@Sun.COM 		w_info++;
45710923SEvan.Yan@Sun.COM 
45810923SEvan.Yan@Sun.COM 	/*
45910923SEvan.Yan@Sun.COM 	 * Compute the total line width of each line,
46010923SEvan.Yan@Sun.COM 	 * accounting for intercolumn spacing.
46110923SEvan.Yan@Sun.COM 	 */
46210923SEvan.Yan@Sun.COM 	width = w_info + w_rsrc + 4;
46310923SEvan.Yan@Sun.COM 
46410923SEvan.Yan@Sun.COM 	/* Allocate space for the table */
46510923SEvan.Yan@Sun.COM 	table_size = (2 + tuples) * (width + 1) + 2;
46610923SEvan.Yan@Sun.COM 	if (*table == NULL) {
46710923SEvan.Yan@Sun.COM 		/* zero fill for the strcat() call below */
46810923SEvan.Yan@Sun.COM 		*table = calloc(table_size, sizeof (char));
46910923SEvan.Yan@Sun.COM 		if (*table == NULL)
47010923SEvan.Yan@Sun.COM 			return;
47110923SEvan.Yan@Sun.COM 	} else {
47210923SEvan.Yan@Sun.COM 		newtable = realloc(*table, strlen(*table) + table_size);
47310923SEvan.Yan@Sun.COM 		if (newtable == NULL)
47410923SEvan.Yan@Sun.COM 			return;
47510923SEvan.Yan@Sun.COM 		else
47610923SEvan.Yan@Sun.COM 			*table = newtable;
47710923SEvan.Yan@Sun.COM 	}
47810923SEvan.Yan@Sun.COM 
47910923SEvan.Yan@Sun.COM 	/* Place a table header into the string */
48010923SEvan.Yan@Sun.COM 
48110923SEvan.Yan@Sun.COM 	/* The resource header */
48210923SEvan.Yan@Sun.COM 	(void) strcat(*table, "\n");
48310923SEvan.Yan@Sun.COM 	w = strlen(rsrc);
48410923SEvan.Yan@Sun.COM 	for (i = 0; i < ((w_rsrc - w) / 2); i++)
48510923SEvan.Yan@Sun.COM 		(void) strcat(*table, " ");
48610923SEvan.Yan@Sun.COM 	(void) strcat(*table, rsrc);
48710923SEvan.Yan@Sun.COM 	for (i = 0; i < ((w_rsrc - w) / 2); i++)
48810923SEvan.Yan@Sun.COM 		(void) strcat(*table, " ");
48910923SEvan.Yan@Sun.COM 
49010923SEvan.Yan@Sun.COM 	/* The information header */
49110923SEvan.Yan@Sun.COM 	(void) strcat(*table, "  ");
49210923SEvan.Yan@Sun.COM 	w = strlen(info);
49310923SEvan.Yan@Sun.COM 	for (i = 0; i < ((w_info - w) / 2); i++)
49410923SEvan.Yan@Sun.COM 		(void) strcat(*table, " ");
49510923SEvan.Yan@Sun.COM 	(void) strcat(*table, info);
49610923SEvan.Yan@Sun.COM 	for (i = 0; i < ((w_info - w) / 2); i++)
49710923SEvan.Yan@Sun.COM 		(void) strcat(*table, " ");
49810923SEvan.Yan@Sun.COM 	/* Underline the headers */
49910923SEvan.Yan@Sun.COM 	(void) strcat(*table, "\n");
50010923SEvan.Yan@Sun.COM 	for (i = 0; i < w_rsrc; i++)
50110923SEvan.Yan@Sun.COM 		(void) strcat(*table, "-");
50210923SEvan.Yan@Sun.COM 	(void) strcat(*table, "  ");
50310923SEvan.Yan@Sun.COM 	for (i = 0; i < w_info; i++)
50410923SEvan.Yan@Sun.COM 		(void) strcat(*table, "-");
50510923SEvan.Yan@Sun.COM 
50610923SEvan.Yan@Sun.COM 	/* Construct the format string */
50710923SEvan.Yan@Sun.COM 	(void) snprintf(format, MAX_FORMAT, "%%-%ds  %%-%ds",
50810923SEvan.Yan@Sun.COM 	    (int)w_rsrc, (int)w_info);
50910923SEvan.Yan@Sun.COM 
51010923SEvan.Yan@Sun.COM 	/* Add the tuples to the table string */
51110923SEvan.Yan@Sun.COM 	sumarg.table = table;
51210923SEvan.Yan@Sun.COM 	sumarg.format = format;
51310923SEvan.Yan@Sun.COM 	(void) hp_traverse(node, &sumarg, error_sumup_cb);
51410923SEvan.Yan@Sun.COM }
51510923SEvan.Yan@Sun.COM 
51610923SEvan.Yan@Sun.COM /*
51710923SEvan.Yan@Sun.COM  * Figure out the target kernel state for a given cfgadm
51810923SEvan.Yan@Sun.COM  * change-state operation.
51910923SEvan.Yan@Sun.COM  */
52010923SEvan.Yan@Sun.COM static cfga_err_t
cfga_target_state(cfga_cmd_t state_change_cmd,int * state)52110923SEvan.Yan@Sun.COM cfga_target_state(cfga_cmd_t state_change_cmd, int *state)
52210923SEvan.Yan@Sun.COM {
52310923SEvan.Yan@Sun.COM 	switch (state_change_cmd) {
52410923SEvan.Yan@Sun.COM 	case CFGA_CMD_CONNECT:
52510923SEvan.Yan@Sun.COM 		*state = DDI_HP_CN_STATE_POWERED;
52610923SEvan.Yan@Sun.COM 		break;
52710923SEvan.Yan@Sun.COM 	case CFGA_CMD_DISCONNECT:
52810923SEvan.Yan@Sun.COM 		*state = DDI_HP_CN_STATE_PRESENT;
52910923SEvan.Yan@Sun.COM 		break;
53010923SEvan.Yan@Sun.COM 	case CFGA_CMD_CONFIGURE:
53110923SEvan.Yan@Sun.COM 		*state = DDI_HP_CN_STATE_ENABLED;
53210923SEvan.Yan@Sun.COM 		break;
53310923SEvan.Yan@Sun.COM 	case CFGA_CMD_UNCONFIGURE:
53410923SEvan.Yan@Sun.COM 		*state = DDI_HP_CN_STATE_POWERED;
53510923SEvan.Yan@Sun.COM 		break;
53610923SEvan.Yan@Sun.COM 	default:
53710923SEvan.Yan@Sun.COM 		return (CFGA_ERROR);
53810923SEvan.Yan@Sun.COM 	}
53910923SEvan.Yan@Sun.COM 
54010923SEvan.Yan@Sun.COM 	return (CFGA_OK);
54110923SEvan.Yan@Sun.COM }
54210923SEvan.Yan@Sun.COM 
54310923SEvan.Yan@Sun.COM /*
54410923SEvan.Yan@Sun.COM  * Translate kernel state to cfgadm receptacle state and occupant state.
54510923SEvan.Yan@Sun.COM  */
54610923SEvan.Yan@Sun.COM static cfga_err_t
cfga_get_state(hp_node_t connector,ap_rstate_t * rs,ap_ostate_t * os)54710923SEvan.Yan@Sun.COM cfga_get_state(hp_node_t connector, ap_rstate_t *rs, ap_ostate_t *os)
54810923SEvan.Yan@Sun.COM {
54910923SEvan.Yan@Sun.COM 	int state;
55010923SEvan.Yan@Sun.COM 	hp_node_t port;
55110923SEvan.Yan@Sun.COM 
55210923SEvan.Yan@Sun.COM 	state = hp_state(connector);
55310923SEvan.Yan@Sun.COM 
55410923SEvan.Yan@Sun.COM 	/* Receptacle state */
55510923SEvan.Yan@Sun.COM 	switch (state) {
55610923SEvan.Yan@Sun.COM 	case DDI_HP_CN_STATE_EMPTY:
55710923SEvan.Yan@Sun.COM 		*rs = AP_RSTATE_EMPTY;
55810923SEvan.Yan@Sun.COM 		break;
55910923SEvan.Yan@Sun.COM 	case DDI_HP_CN_STATE_PRESENT:
56010923SEvan.Yan@Sun.COM 		*rs = AP_RSTATE_DISCONNECTED;
56110923SEvan.Yan@Sun.COM 		break;
56210923SEvan.Yan@Sun.COM 	case DDI_HP_CN_STATE_POWERED:
56310923SEvan.Yan@Sun.COM 	case DDI_HP_CN_STATE_ENABLED:
56410923SEvan.Yan@Sun.COM 		*rs = AP_RSTATE_CONNECTED;
56510923SEvan.Yan@Sun.COM 		break;
56610923SEvan.Yan@Sun.COM 		/*
56710923SEvan.Yan@Sun.COM 		 * Connector state can only be one of
56810923SEvan.Yan@Sun.COM 		 * Empty, Present, Powered, Enabled.
56910923SEvan.Yan@Sun.COM 		 */
57010923SEvan.Yan@Sun.COM 	default:
57110923SEvan.Yan@Sun.COM 		return (CFGA_ERROR);
57210923SEvan.Yan@Sun.COM 	}
57310923SEvan.Yan@Sun.COM 
57410923SEvan.Yan@Sun.COM 	/*
57510923SEvan.Yan@Sun.COM 	 * Occupant state
57610923SEvan.Yan@Sun.COM 	 */
57710923SEvan.Yan@Sun.COM 	port = hp_child(connector);
57810923SEvan.Yan@Sun.COM 	while (port != NULL) {
57910923SEvan.Yan@Sun.COM 		DBG(1, ("cfga_get_state:(%x)\n", hp_state(port)));
58010923SEvan.Yan@Sun.COM 
58110923SEvan.Yan@Sun.COM 		/*
58210923SEvan.Yan@Sun.COM 		 * Mark occupant state as "configured" if at least one of the
58310923SEvan.Yan@Sun.COM 		 * associated ports is at state "offline" or above. Driver
58410923SEvan.Yan@Sun.COM 		 * attach ("online" state) is not necessary here.
58510923SEvan.Yan@Sun.COM 		 */
58610923SEvan.Yan@Sun.COM 		if (hp_state(port) >= DDI_HP_CN_STATE_OFFLINE)
58710923SEvan.Yan@Sun.COM 			break;
58810923SEvan.Yan@Sun.COM 
58910923SEvan.Yan@Sun.COM 		port = hp_sibling(port);
59010923SEvan.Yan@Sun.COM 	}
59110923SEvan.Yan@Sun.COM 
59210923SEvan.Yan@Sun.COM 	if (port != NULL)
59310923SEvan.Yan@Sun.COM 		*os = AP_OSTATE_CONFIGURED;
59410923SEvan.Yan@Sun.COM 	else
59510923SEvan.Yan@Sun.COM 		*os = AP_OSTATE_UNCONFIGURED;
59610923SEvan.Yan@Sun.COM 
59710923SEvan.Yan@Sun.COM 	return (CFGA_OK);
59810923SEvan.Yan@Sun.COM }
59910923SEvan.Yan@Sun.COM 
60010923SEvan.Yan@Sun.COM /*
60110923SEvan.Yan@Sun.COM  * Transitional Diagram:
60210923SEvan.Yan@Sun.COM  *
60310923SEvan.Yan@Sun.COM  *  empty		unconfigure
60410923SEvan.Yan@Sun.COM  * (remove)	^|  (physically insert card)
60510923SEvan.Yan@Sun.COM  *			|V
60610923SEvan.Yan@Sun.COM  * disconnect	configure
60710923SEvan.Yan@Sun.COM  * "-c DISCONNECT"	^|	"-c CONNECT"
60810923SEvan.Yan@Sun.COM  *				|V	"-c CONFIGURE"
60910923SEvan.Yan@Sun.COM  * connect	unconfigure	->	connect    configure
61010923SEvan.Yan@Sun.COM  *						<-
61110923SEvan.Yan@Sun.COM  *					"-c UNCONFIGURE"
61210923SEvan.Yan@Sun.COM  *
61310923SEvan.Yan@Sun.COM  */
61410923SEvan.Yan@Sun.COM /*ARGSUSED*/
61510923SEvan.Yan@Sun.COM cfga_err_t
cfga_change_state(cfga_cmd_t state_change_cmd,const char * ap_id,const char * options,struct cfga_confirm * confp,struct cfga_msg * msgp,char ** errstring,cfga_flags_t flags)61610923SEvan.Yan@Sun.COM cfga_change_state(cfga_cmd_t state_change_cmd, const char *ap_id,
61710923SEvan.Yan@Sun.COM     const char *options, struct cfga_confirm *confp,
61810923SEvan.Yan@Sun.COM     struct cfga_msg *msgp, char **errstring, cfga_flags_t flags)
61910923SEvan.Yan@Sun.COM {
62010923SEvan.Yan@Sun.COM 	int		rv, state, new_state;
621*12821SScott.Carter@Oracle.COM 	uint_t		hpflags = 0;
62210923SEvan.Yan@Sun.COM 	hp_node_t	node;
62310923SEvan.Yan@Sun.COM 	hp_node_t	results = NULL;
62410923SEvan.Yan@Sun.COM 
62510923SEvan.Yan@Sun.COM 	if ((rv = check_options(options)) != CFGA_OK) {
62610923SEvan.Yan@Sun.COM 		return (rv);
62710923SEvan.Yan@Sun.COM 	}
62810923SEvan.Yan@Sun.COM 
62910923SEvan.Yan@Sun.COM 	if (errstring != NULL)
63010923SEvan.Yan@Sun.COM 		*errstring = NULL;
63110923SEvan.Yan@Sun.COM 
63210923SEvan.Yan@Sun.COM 	rv = CFGA_OK;
63310923SEvan.Yan@Sun.COM 	DBG(1, ("cfga_change_state:(%s)\n", ap_id));
63410923SEvan.Yan@Sun.COM 
63510923SEvan.Yan@Sun.COM 	rv = physpath2node(ap_id, errstring, &node);
63610923SEvan.Yan@Sun.COM 	if (rv != CFGA_OK)
63710923SEvan.Yan@Sun.COM 		return (rv);
63810923SEvan.Yan@Sun.COM 
639*12821SScott.Carter@Oracle.COM 	/*
640*12821SScott.Carter@Oracle.COM 	 * Check for the FORCE flag.  It is only used
641*12821SScott.Carter@Oracle.COM 	 * for DISCONNECT or UNCONFIGURE state changes.
642*12821SScott.Carter@Oracle.COM 	 */
643*12821SScott.Carter@Oracle.COM 	if (flags & CFGA_FLAG_FORCE)
644*12821SScott.Carter@Oracle.COM 		hpflags |= HPFORCE;
645*12821SScott.Carter@Oracle.COM 
64610923SEvan.Yan@Sun.COM 	state = hp_state(node);
64710923SEvan.Yan@Sun.COM 
64810923SEvan.Yan@Sun.COM 	/*
64910923SEvan.Yan@Sun.COM 	 * Which state should we drive to ?
65010923SEvan.Yan@Sun.COM 	 */
65110923SEvan.Yan@Sun.COM 	if ((state_change_cmd != CFGA_CMD_LOAD) &&
65210923SEvan.Yan@Sun.COM 	    (state_change_cmd != CFGA_CMD_UNLOAD)) {
65310923SEvan.Yan@Sun.COM 		if (cfga_target_state(state_change_cmd,
65410923SEvan.Yan@Sun.COM 		    &new_state) != CFGA_OK) {
65510923SEvan.Yan@Sun.COM 			hp_fini(node);
65610923SEvan.Yan@Sun.COM 			return (CFGA_ERROR);
65710923SEvan.Yan@Sun.COM 		}
65810923SEvan.Yan@Sun.COM 	}
65910923SEvan.Yan@Sun.COM 
66010923SEvan.Yan@Sun.COM 	DBG(1, ("cfga_change_state: state is %d\n", state));
66110923SEvan.Yan@Sun.COM 	switch (state_change_cmd) {
66210923SEvan.Yan@Sun.COM 	case CFGA_CMD_CONNECT:
66312555SScott.Carter@Oracle.COM 		DBG(1, ("connect\n"));
66412555SScott.Carter@Oracle.COM 		if (state == DDI_HP_CN_STATE_EMPTY) {
66510923SEvan.Yan@Sun.COM 			cfga_err(errstring, ERR_AP_ERR, 0);
66610923SEvan.Yan@Sun.COM 			rv = CFGA_INVAL;
66712555SScott.Carter@Oracle.COM 		} else if (state == DDI_HP_CN_STATE_PRESENT) {
66812555SScott.Carter@Oracle.COM 			/* Connect the slot */
66910923SEvan.Yan@Sun.COM 			if (hp_set_state(node, 0, new_state, &results) != 0) {
67010923SEvan.Yan@Sun.COM 				rv = CFGA_ERROR;
67110923SEvan.Yan@Sun.COM 				cfga_err(errstring, CMD_SLOT_CONNECT, 0);
67210923SEvan.Yan@Sun.COM 			}
67310923SEvan.Yan@Sun.COM 		}
67410923SEvan.Yan@Sun.COM 		break;
67510923SEvan.Yan@Sun.COM 
67610923SEvan.Yan@Sun.COM 	case CFGA_CMD_DISCONNECT:
67710923SEvan.Yan@Sun.COM 		DBG(1, ("disconnect\n"));
67812555SScott.Carter@Oracle.COM 		if (state == DDI_HP_CN_STATE_EMPTY) {
67910923SEvan.Yan@Sun.COM 			cfga_err(errstring, ERR_AP_ERR, 0);
68010923SEvan.Yan@Sun.COM 			rv = CFGA_INVAL;
68112555SScott.Carter@Oracle.COM 		} else if (state > DDI_HP_CN_STATE_PRESENT) {
68212555SScott.Carter@Oracle.COM 			/* Disconnect the slot */
683*12821SScott.Carter@Oracle.COM 			rv = hp_set_state(node, hpflags, new_state, &results);
684*12821SScott.Carter@Oracle.COM 			if (rv != 0) {
68510923SEvan.Yan@Sun.COM 				if (rv == EBUSY)
68610923SEvan.Yan@Sun.COM 					rv = CFGA_BUSY;
68710923SEvan.Yan@Sun.COM 				else
68810923SEvan.Yan@Sun.COM 					rv = CFGA_ERROR;
68910923SEvan.Yan@Sun.COM 
69010923SEvan.Yan@Sun.COM 				if (results) {
69110923SEvan.Yan@Sun.COM 					pci_rcm_info_table(results, errstring);
69210923SEvan.Yan@Sun.COM 					hp_fini(results);
69310923SEvan.Yan@Sun.COM 				} else {
69410923SEvan.Yan@Sun.COM 					cfga_err(errstring,
69510923SEvan.Yan@Sun.COM 					    CMD_SLOT_DISCONNECT, 0);
69610923SEvan.Yan@Sun.COM 				}
69710923SEvan.Yan@Sun.COM 			}
69810923SEvan.Yan@Sun.COM 		}
69910923SEvan.Yan@Sun.COM 		break;
70010923SEvan.Yan@Sun.COM 
70110923SEvan.Yan@Sun.COM 	case CFGA_CMD_CONFIGURE:
70210923SEvan.Yan@Sun.COM 		/*
70310923SEvan.Yan@Sun.COM 		 * for multi-func device we allow multiple
70410923SEvan.Yan@Sun.COM 		 * configure on the same slot because one
70510923SEvan.Yan@Sun.COM 		 * func can be configured and other one won't
70610923SEvan.Yan@Sun.COM 		 */
70712555SScott.Carter@Oracle.COM 		DBG(1, ("configure\n"));
70812555SScott.Carter@Oracle.COM 		if (state == DDI_HP_CN_STATE_EMPTY) {
70912555SScott.Carter@Oracle.COM 			cfga_err(errstring, ERR_AP_ERR, 0);
71012555SScott.Carter@Oracle.COM 			rv = CFGA_INVAL;
71112555SScott.Carter@Oracle.COM 		} else if (hp_set_state(node, 0, new_state, &results) != 0) {
71210923SEvan.Yan@Sun.COM 			rv = CFGA_ERROR;
71310923SEvan.Yan@Sun.COM 			cfga_err(errstring, CMD_SLOT_CONFIGURE, 0);
71410923SEvan.Yan@Sun.COM 		}
71510923SEvan.Yan@Sun.COM 		break;
71610923SEvan.Yan@Sun.COM 
71710923SEvan.Yan@Sun.COM 	case CFGA_CMD_UNCONFIGURE:
71810923SEvan.Yan@Sun.COM 		DBG(1, ("unconfigure\n"));
71912555SScott.Carter@Oracle.COM 		if (state == DDI_HP_CN_STATE_EMPTY) {
72012555SScott.Carter@Oracle.COM 			cfga_err(errstring, ERR_AP_ERR, 0);
72112555SScott.Carter@Oracle.COM 			rv = CFGA_INVAL;
72212555SScott.Carter@Oracle.COM 		} else if (state >= DDI_HP_CN_STATE_ENABLED) {
723*12821SScott.Carter@Oracle.COM 			rv = hp_set_state(node, hpflags, new_state, &results);
724*12821SScott.Carter@Oracle.COM 			if (rv != 0) {
72510923SEvan.Yan@Sun.COM 				if (rv == EBUSY)
72610923SEvan.Yan@Sun.COM 					rv = CFGA_BUSY;
72710923SEvan.Yan@Sun.COM 				else
72810923SEvan.Yan@Sun.COM 					rv = CFGA_ERROR;
72910923SEvan.Yan@Sun.COM 
73010923SEvan.Yan@Sun.COM 				if (results) {
73110923SEvan.Yan@Sun.COM 					pci_rcm_info_table(results, errstring);
73210923SEvan.Yan@Sun.COM 					hp_fini(results);
73310923SEvan.Yan@Sun.COM 				} else {
73410923SEvan.Yan@Sun.COM 					cfga_err(errstring,
73510923SEvan.Yan@Sun.COM 					    CMD_SLOT_UNCONFIGURE, 0);
73610923SEvan.Yan@Sun.COM 				}
73710923SEvan.Yan@Sun.COM 			}
73810923SEvan.Yan@Sun.COM 		}
73910923SEvan.Yan@Sun.COM 		DBG(1, ("unconfigure rv:(%i)\n", rv));
74010923SEvan.Yan@Sun.COM 		break;
74110923SEvan.Yan@Sun.COM 
74210923SEvan.Yan@Sun.COM 	case CFGA_CMD_LOAD:
74310923SEvan.Yan@Sun.COM 		/* do nothing, just produce error msg as is */
74410923SEvan.Yan@Sun.COM 		if (state < DDI_HP_CN_STATE_POWERED) {
74510923SEvan.Yan@Sun.COM 			rv = CFGA_ERROR;
74610923SEvan.Yan@Sun.COM 			cfga_err(errstring, CMD_SLOT_INSERT, 0);
74710923SEvan.Yan@Sun.COM 		} else {
74810923SEvan.Yan@Sun.COM 			cfga_err(errstring, ERR_AP_ERR, 0);
74910923SEvan.Yan@Sun.COM 			rv = CFGA_INVAL;
75010923SEvan.Yan@Sun.COM 		}
75110923SEvan.Yan@Sun.COM 		break;
75210923SEvan.Yan@Sun.COM 
75310923SEvan.Yan@Sun.COM 	case CFGA_CMD_UNLOAD:
75410923SEvan.Yan@Sun.COM 		/* do nothing, just produce error msg as is */
75510923SEvan.Yan@Sun.COM 		if (state < DDI_HP_CN_STATE_POWERED) {
75610923SEvan.Yan@Sun.COM 			rv = CFGA_ERROR;
75710923SEvan.Yan@Sun.COM 			cfga_err(errstring, CMD_SLOT_REMOVE, 0);
75810923SEvan.Yan@Sun.COM 		} else {
75910923SEvan.Yan@Sun.COM 			cfga_err(errstring, ERR_AP_ERR, 0);
76010923SEvan.Yan@Sun.COM 			rv = CFGA_INVAL;
76110923SEvan.Yan@Sun.COM 		}
76210923SEvan.Yan@Sun.COM 		break;
76310923SEvan.Yan@Sun.COM 
76410923SEvan.Yan@Sun.COM 	default:
76510923SEvan.Yan@Sun.COM 		rv = CFGA_OPNOTSUPP;
76610923SEvan.Yan@Sun.COM 		break;
76710923SEvan.Yan@Sun.COM 	}
76810923SEvan.Yan@Sun.COM 
76910923SEvan.Yan@Sun.COM 	hp_fini(node);
77010923SEvan.Yan@Sun.COM 	return (rv);
77110923SEvan.Yan@Sun.COM }
77210923SEvan.Yan@Sun.COM 
77310923SEvan.Yan@Sun.COM char *
get_val_from_result(char * result)77410923SEvan.Yan@Sun.COM get_val_from_result(char *result)
77510923SEvan.Yan@Sun.COM {
77610923SEvan.Yan@Sun.COM 	char *tmp;
77710923SEvan.Yan@Sun.COM 
77810923SEvan.Yan@Sun.COM 	tmp = strchr(result, '=');
77910923SEvan.Yan@Sun.COM 	if (tmp == NULL)
78010923SEvan.Yan@Sun.COM 		return (NULL);
78110923SEvan.Yan@Sun.COM 
78210923SEvan.Yan@Sun.COM 	tmp++;
78310923SEvan.Yan@Sun.COM 	return (tmp);
78410923SEvan.Yan@Sun.COM }
78510923SEvan.Yan@Sun.COM 
78610923SEvan.Yan@Sun.COM static cfga_err_t
prt_led_mode(const char * ap_id,int repeat,char ** errstring,struct cfga_msg * msgp)78710923SEvan.Yan@Sun.COM prt_led_mode(const char *ap_id, int repeat, char **errstring,
78810923SEvan.Yan@Sun.COM     struct cfga_msg *msgp)
78910923SEvan.Yan@Sun.COM {
79010923SEvan.Yan@Sun.COM 	pciehpc_led_t led;
79110923SEvan.Yan@Sun.COM 	hp_node_t node;
79210923SEvan.Yan@Sun.COM 	char *buff;
79310923SEvan.Yan@Sun.COM 	char *buf;
79410923SEvan.Yan@Sun.COM 	char *cp, line[MAXLINE];
79510923SEvan.Yan@Sun.COM 	char *tmp;
79610923SEvan.Yan@Sun.COM 	char *format;
79710923SEvan.Yan@Sun.COM 	char *result;
79810923SEvan.Yan@Sun.COM 	int i, n, rv;
79910923SEvan.Yan@Sun.COM 	int len = MAXLINE;
80010923SEvan.Yan@Sun.COM 
80110923SEvan.Yan@Sun.COM 	pciehpc_led_t states[] = {
80210923SEvan.Yan@Sun.COM 		PCIEHPC_POWER_LED,
80310923SEvan.Yan@Sun.COM 		PCIEHPC_FAULT_LED,
80410923SEvan.Yan@Sun.COM 		PCIEHPC_ATTN_LED,
80510923SEvan.Yan@Sun.COM 		PCIEHPC_ACTIVE_LED
80610923SEvan.Yan@Sun.COM 	};
80710923SEvan.Yan@Sun.COM 
80810923SEvan.Yan@Sun.COM 	DBG(1, ("prt_led_mod function\n"));
80910923SEvan.Yan@Sun.COM 	if (!repeat)
81010923SEvan.Yan@Sun.COM 		cfga_msg(msgp, "Ap_Id\t\t\tLed");
81110923SEvan.Yan@Sun.COM 
81210923SEvan.Yan@Sun.COM 	rv = physpath2node(ap_id, errstring, &node);
81310923SEvan.Yan@Sun.COM 	if (rv != CFGA_OK)
81410923SEvan.Yan@Sun.COM 		return (rv);
81510923SEvan.Yan@Sun.COM 
81610923SEvan.Yan@Sun.COM 	if ((buff = malloc(MAXPATHLEN)) == NULL) {
81710923SEvan.Yan@Sun.COM 		hp_fini(node);
81810923SEvan.Yan@Sun.COM 		cfga_err(errstring, "malloc ", 0);
81910923SEvan.Yan@Sun.COM 		return (CFGA_ERROR);
82010923SEvan.Yan@Sun.COM 	}
82110923SEvan.Yan@Sun.COM 
82210923SEvan.Yan@Sun.COM 	(void) memset(buff, 0, MAXPATHLEN);
82310923SEvan.Yan@Sun.COM 
82410923SEvan.Yan@Sun.COM 	if (fix_ap_name(buff, ap_id, hp_name(node),
82510923SEvan.Yan@Sun.COM 	    errstring) != CFGA_OK) {
82610923SEvan.Yan@Sun.COM 		hp_fini(node);
82710923SEvan.Yan@Sun.COM 		free(buff);
82810923SEvan.Yan@Sun.COM 		return (CFGA_ERROR);
82910923SEvan.Yan@Sun.COM 	}
83010923SEvan.Yan@Sun.COM 
83110923SEvan.Yan@Sun.COM 	cp = line;
83210923SEvan.Yan@Sun.COM 	(void) snprintf(cp, len, "%s\t\t", buff);
83310923SEvan.Yan@Sun.COM 	len -= strlen(cp);
83410923SEvan.Yan@Sun.COM 	cp += strlen(cp);
83510923SEvan.Yan@Sun.COM 
83610923SEvan.Yan@Sun.COM 	free(buff);
83710923SEvan.Yan@Sun.COM 
83810923SEvan.Yan@Sun.COM 	n = sizeof (states)/sizeof (pciehpc_led_t);
83910923SEvan.Yan@Sun.COM 	for (i = 0; i < n; i++) {
84010923SEvan.Yan@Sun.COM 		led = states[i];
84110923SEvan.Yan@Sun.COM 
84210923SEvan.Yan@Sun.COM 		format = (i == n - 1) ? "%s=%s" : "%s=%s,";
84310923SEvan.Yan@Sun.COM 		if (hp_get_private(node, led_strs2[led], &result) != 0) {
84410923SEvan.Yan@Sun.COM 			(void) snprintf(cp, len, format,
84510923SEvan.Yan@Sun.COM 			    led_strs[led], cfga_strs[UNKNOWN]);
84610923SEvan.Yan@Sun.COM 			len -= strlen(cp);
84710923SEvan.Yan@Sun.COM 			cp += strlen(cp);
84810923SEvan.Yan@Sun.COM 			DBG(1, ("%s:%s\n", led_strs[led], cfga_strs[UNKNOWN]));
84910923SEvan.Yan@Sun.COM 		} else {
85010923SEvan.Yan@Sun.COM 			/*
85110923SEvan.Yan@Sun.COM 			 * hp_get_private() will return back things like
85210923SEvan.Yan@Sun.COM 			 * "led_fault=off", transform it to cfgadm desired
85310923SEvan.Yan@Sun.COM 			 * format.
85410923SEvan.Yan@Sun.COM 			 */
85510923SEvan.Yan@Sun.COM 			tmp = get_val_from_result(result);
85610923SEvan.Yan@Sun.COM 			if (tmp == NULL) {
85710923SEvan.Yan@Sun.COM 				free(result);
85810923SEvan.Yan@Sun.COM 				hp_fini(node);
85910923SEvan.Yan@Sun.COM 				return (CFGA_ERROR);
86010923SEvan.Yan@Sun.COM 			}
86110923SEvan.Yan@Sun.COM 
86210923SEvan.Yan@Sun.COM 			(void) snprintf(cp, len, format,
86310923SEvan.Yan@Sun.COM 			    led_strs[led], tmp);
86410923SEvan.Yan@Sun.COM 			len -= strlen(cp);
86510923SEvan.Yan@Sun.COM 			cp += strlen(cp);
86610923SEvan.Yan@Sun.COM 			DBG(1, ("%s:%s\n", led_strs[led], tmp));
86710923SEvan.Yan@Sun.COM 			free(result);
86810923SEvan.Yan@Sun.COM 		}
86910923SEvan.Yan@Sun.COM 	}
87010923SEvan.Yan@Sun.COM 
87110923SEvan.Yan@Sun.COM 	cfga_msg(msgp, line);	/* print the message */
87210923SEvan.Yan@Sun.COM 
87310923SEvan.Yan@Sun.COM 	hp_fini(node);
87410923SEvan.Yan@Sun.COM 
87510923SEvan.Yan@Sun.COM 	return (CFGA_OK);
87610923SEvan.Yan@Sun.COM }
87710923SEvan.Yan@Sun.COM 
87810923SEvan.Yan@Sun.COM /*ARGSUSED*/
87910923SEvan.Yan@Sun.COM cfga_err_t
cfga_private_func(const char * function,const char * ap_id,const char * options,struct cfga_confirm * confp,struct cfga_msg * msgp,char ** errstring,cfga_flags_t flags)88010923SEvan.Yan@Sun.COM cfga_private_func(const char *function, const char *ap_id,
88110923SEvan.Yan@Sun.COM     const char *options, struct cfga_confirm *confp,
88210923SEvan.Yan@Sun.COM     struct cfga_msg *msgp, char **errstring, cfga_flags_t flags)
88310923SEvan.Yan@Sun.COM {
88410923SEvan.Yan@Sun.COM 	char *str;
88510923SEvan.Yan@Sun.COM 	int   len, fd, i = 0, repeat = 0;
88610923SEvan.Yan@Sun.COM 	char buf[MAXNAMELEN];
88710923SEvan.Yan@Sun.COM 	char ptr;
88810923SEvan.Yan@Sun.COM 	cfga_err_t rv;
88910923SEvan.Yan@Sun.COM 	char *led, *mode;
89010923SEvan.Yan@Sun.COM 	hp_node_t node;
89110923SEvan.Yan@Sun.COM 	char *result;
89210923SEvan.Yan@Sun.COM 
89310923SEvan.Yan@Sun.COM 	DBG(1, ("cfgadm_private_func: ap_id:%s\n", ap_id));
89410923SEvan.Yan@Sun.COM 	DBG(2, ("  options: %s\n", (options == NULL)?"null":options));
89510923SEvan.Yan@Sun.COM 	DBG(2, ("  confp: %x\n", confp));
89610923SEvan.Yan@Sun.COM 	DBG(2, ("  cfga_msg: %x\n", cfga_msg));
89710923SEvan.Yan@Sun.COM 	DBG(2, ("  flag: %d\n", flags));
89810923SEvan.Yan@Sun.COM 
89910923SEvan.Yan@Sun.COM 	if ((rv = check_options(options)) != CFGA_OK) {
90010923SEvan.Yan@Sun.COM 		return (rv);
90110923SEvan.Yan@Sun.COM 	}
90210923SEvan.Yan@Sun.COM 
90310923SEvan.Yan@Sun.COM 	if (private_check == confp)
90410923SEvan.Yan@Sun.COM 		repeat = 1;
90510923SEvan.Yan@Sun.COM 	else
90610923SEvan.Yan@Sun.COM 		private_check = (void*)confp;
90710923SEvan.Yan@Sun.COM 
90810923SEvan.Yan@Sun.COM 	for (i = 0, str = func_strs[i], len = strlen(str);
90910923SEvan.Yan@Sun.COM 	    func_strs[i] != NULL; i++) {
91010923SEvan.Yan@Sun.COM 		str = func_strs[i];
91110923SEvan.Yan@Sun.COM 		len = strlen(str);
91210923SEvan.Yan@Sun.COM 		if (strncmp(function, str, len) == 0)
91310923SEvan.Yan@Sun.COM 			break;
91410923SEvan.Yan@Sun.COM 	}
91510923SEvan.Yan@Sun.COM 
91610923SEvan.Yan@Sun.COM 	switch (i) {
91710923SEvan.Yan@Sun.COM 		case ENABLE_SLOT:
91810923SEvan.Yan@Sun.COM 		case DISABLE_SLOT:
91910923SEvan.Yan@Sun.COM 			/* pass through */
92010923SEvan.Yan@Sun.COM 		case ENABLE_AUTOCNF:
92110923SEvan.Yan@Sun.COM 		case DISABLE_AUTOCNF:
92210923SEvan.Yan@Sun.COM 			/* no action needed */
92310923SEvan.Yan@Sun.COM 			return (CFGA_OK);
92410923SEvan.Yan@Sun.COM 			break;
92510923SEvan.Yan@Sun.COM 		case LED:
92610923SEvan.Yan@Sun.COM 			/* set mode */
92710923SEvan.Yan@Sun.COM 			ptr = function[len++];
92810923SEvan.Yan@Sun.COM 			if (ptr == '=') {
92910923SEvan.Yan@Sun.COM 				str = (char *)function;
93010923SEvan.Yan@Sun.COM 				for (str = (str+len++), i = 0; *str != ',';
93110923SEvan.Yan@Sun.COM 				    i++, str++) {
93210923SEvan.Yan@Sun.COM 					if (i == (MAXNAMELEN - 1))
93310923SEvan.Yan@Sun.COM 						break;
93410923SEvan.Yan@Sun.COM 
93510923SEvan.Yan@Sun.COM 					buf[i] = *str;
93610923SEvan.Yan@Sun.COM 					DBG_F(2, (stdout, "%c\n", buf[i]));
93710923SEvan.Yan@Sun.COM 				}
93810923SEvan.Yan@Sun.COM 				buf[i] = '\0'; str++;
93910923SEvan.Yan@Sun.COM 				DBG(2, ("buf = %s\n", buf));
94010923SEvan.Yan@Sun.COM 
94110923SEvan.Yan@Sun.COM 				/* ACTIVE=3,ATTN=2,POWER=1,FAULT=0 */
94210923SEvan.Yan@Sun.COM 				if (strcmp(buf, led_strs[POWER]) == 0)
94310923SEvan.Yan@Sun.COM 					led = PCIEHPC_PROP_LED_POWER;
94410923SEvan.Yan@Sun.COM 				else if (strcmp(buf, led_strs[FAULT]) == 0)
94510923SEvan.Yan@Sun.COM 					led = PCIEHPC_PROP_LED_FAULT;
94610923SEvan.Yan@Sun.COM 				else if (strcmp(buf, led_strs[ATTN]) == 0)
94710923SEvan.Yan@Sun.COM 					led = PCIEHPC_PROP_LED_ATTN;
94810923SEvan.Yan@Sun.COM 				else if (strcmp(buf, led_strs[ACTIVE]) == 0)
94910923SEvan.Yan@Sun.COM 					led = PCIEHPC_PROP_LED_ACTIVE;
95010923SEvan.Yan@Sun.COM 				else return (CFGA_INVAL);
95110923SEvan.Yan@Sun.COM 
95210923SEvan.Yan@Sun.COM 				len = strlen(func_strs[MODE]);
95310923SEvan.Yan@Sun.COM 				if ((strncmp(str, func_strs[MODE], len) == 0) &&
95410923SEvan.Yan@Sun.COM 				    (*(str+(len)) == '=')) {
95510923SEvan.Yan@Sun.COM 					for (str = (str+(++len)), i = 0;
95610923SEvan.Yan@Sun.COM 					    *str != NULL; i++, str++) {
95710923SEvan.Yan@Sun.COM 						buf[i] = *str;
95810923SEvan.Yan@Sun.COM 					}
95910923SEvan.Yan@Sun.COM 				}
96010923SEvan.Yan@Sun.COM 				buf[i] = '\0';
96110923SEvan.Yan@Sun.COM 				DBG(2, ("buf_mode= %s\n", buf));
96210923SEvan.Yan@Sun.COM 
96310923SEvan.Yan@Sun.COM 				/* ON = 1, OFF = 0 */
96410923SEvan.Yan@Sun.COM 				if (strcmp(buf, mode_strs[ON]) == 0)
96510923SEvan.Yan@Sun.COM 					mode = PCIEHPC_PROP_VALUE_ON;
96610923SEvan.Yan@Sun.COM 				else if (strcmp(buf, mode_strs[OFF]) == 0)
96710923SEvan.Yan@Sun.COM 					mode = PCIEHPC_PROP_VALUE_OFF;
96810923SEvan.Yan@Sun.COM 				else if (strcmp(buf, mode_strs[BLINK]) == 0)
96910923SEvan.Yan@Sun.COM 					mode = PCIEHPC_PROP_VALUE_BLINK;
97010923SEvan.Yan@Sun.COM 				else return (CFGA_INVAL);
97110923SEvan.Yan@Sun.COM 
97210923SEvan.Yan@Sun.COM 				/* sendin  */
97310923SEvan.Yan@Sun.COM 				memset(buf, 0, sizeof (buf));
97410923SEvan.Yan@Sun.COM 				snprintf(buf, sizeof (buf), "%s=%s",
97510923SEvan.Yan@Sun.COM 				    led, mode);
97610923SEvan.Yan@Sun.COM 				buf[MAXNAMELEN - 1] = '\0';
97710923SEvan.Yan@Sun.COM 
97810923SEvan.Yan@Sun.COM 				break;
97910923SEvan.Yan@Sun.COM 			} else if (ptr == '\0') {
98010923SEvan.Yan@Sun.COM 				/* print mode */
98110923SEvan.Yan@Sun.COM 				DBG(1, ("Print mode\n"));
98210923SEvan.Yan@Sun.COM 				return (prt_led_mode(ap_id, repeat, errstring,
98310923SEvan.Yan@Sun.COM 				    msgp));
98410923SEvan.Yan@Sun.COM 			}
98510923SEvan.Yan@Sun.COM 		default:
98610923SEvan.Yan@Sun.COM 			DBG(1, ("default\n"));
98710923SEvan.Yan@Sun.COM 			errno = EINVAL;
98810923SEvan.Yan@Sun.COM 			return (CFGA_INVAL);
98910923SEvan.Yan@Sun.COM 	}
99010923SEvan.Yan@Sun.COM 
99110923SEvan.Yan@Sun.COM 	rv = physpath2node(ap_id, errstring, &node);
99210923SEvan.Yan@Sun.COM 	if (rv != CFGA_OK)
99310923SEvan.Yan@Sun.COM 		return (rv);
99410923SEvan.Yan@Sun.COM 
99510923SEvan.Yan@Sun.COM 	if (hp_set_private(node, buf, &result) != 0) {
99610923SEvan.Yan@Sun.COM 		hp_fini(node);
99710923SEvan.Yan@Sun.COM 		return (CFGA_ERROR);
99810923SEvan.Yan@Sun.COM 	}
99910923SEvan.Yan@Sun.COM 
100010923SEvan.Yan@Sun.COM 	hp_fini(node);
100110923SEvan.Yan@Sun.COM 	return (CFGA_OK);
100210923SEvan.Yan@Sun.COM }
100310923SEvan.Yan@Sun.COM 
100410923SEvan.Yan@Sun.COM /*ARGSUSED*/
cfga_test(const char * ap_id,const char * options,struct cfga_msg * msgp,char ** errstring,cfga_flags_t flags)100510923SEvan.Yan@Sun.COM cfga_err_t cfga_test(const char *ap_id, const char *options,
100610923SEvan.Yan@Sun.COM     struct cfga_msg *msgp, char **errstring, cfga_flags_t flags)
100710923SEvan.Yan@Sun.COM {
100810923SEvan.Yan@Sun.COM 	cfga_err_t rv;
100910923SEvan.Yan@Sun.COM 	if (errstring != NULL)
101010923SEvan.Yan@Sun.COM 		*errstring = NULL;
101110923SEvan.Yan@Sun.COM 
101210923SEvan.Yan@Sun.COM 	if ((rv = check_options(options)) != CFGA_OK) {
101310923SEvan.Yan@Sun.COM 		return (rv);
101410923SEvan.Yan@Sun.COM 	}
101510923SEvan.Yan@Sun.COM 
101610923SEvan.Yan@Sun.COM 	DBG(1, ("cfga_test:(%s)\n", ap_id));
101710923SEvan.Yan@Sun.COM 	/* will need to implement pci CTRL command */
101810923SEvan.Yan@Sun.COM 	return (CFGA_NOTSUPP);
101910923SEvan.Yan@Sun.COM }
102010923SEvan.Yan@Sun.COM 
102110923SEvan.Yan@Sun.COM /*
102210923SEvan.Yan@Sun.COM  * The slot-names property describes the external labeling of add-in slots.
102310923SEvan.Yan@Sun.COM  * This property is an encoded array, an integer followed by a list of
102410923SEvan.Yan@Sun.COM  * strings. The return value from di_prop_lookup_ints for slot-names is -1.
102510923SEvan.Yan@Sun.COM  * The expected return value should be the number of elements.
102610923SEvan.Yan@Sun.COM  * Di_prop_decode_common does not decode encoded data from software,
102710923SEvan.Yan@Sun.COM  * such as the solaris device tree, unlike from the prom.
102810923SEvan.Yan@Sun.COM  * Di_prop_decode_common takes the size of the encoded data and mods
102910923SEvan.Yan@Sun.COM  * it with the size of int. The size of the encoded data for slot-names is 9
103010923SEvan.Yan@Sun.COM  * and the size of int is 4, yielding a non zero result. A value of -1 is used
103110923SEvan.Yan@Sun.COM  * to indicate that the number of elements can not be determined.
103210923SEvan.Yan@Sun.COM  * Di_prop_decode_common can be modified to decode encoded data from the solaris
103310923SEvan.Yan@Sun.COM  * device tree.
103410923SEvan.Yan@Sun.COM  */
103510923SEvan.Yan@Sun.COM static int
fixup_slotname(int rval,int * intp,struct searcharg * slotarg)103610923SEvan.Yan@Sun.COM fixup_slotname(int rval, int *intp, struct searcharg *slotarg)
103710923SEvan.Yan@Sun.COM {
103810923SEvan.Yan@Sun.COM 	if ((slotarg->slt_name_src == PROM_SLT_NAME) && (rval == -1)) {
103910923SEvan.Yan@Sun.COM 		return (DI_WALK_TERMINATE);
104010923SEvan.Yan@Sun.COM 	} else {
104110923SEvan.Yan@Sun.COM 		int i;
104210923SEvan.Yan@Sun.COM 		char *tmptr = (char *)(intp+1);
104310923SEvan.Yan@Sun.COM 		DBG(1, ("slot-bitmask: %x \n", *intp));
104410923SEvan.Yan@Sun.COM 
104510923SEvan.Yan@Sun.COM 		rval = (rval -1) * 4;
104610923SEvan.Yan@Sun.COM 
104710923SEvan.Yan@Sun.COM 		for (i = 0; i <= slotarg->minor; i++) {
104810923SEvan.Yan@Sun.COM 			DBG(2, ("curr slot-name: %s \n", tmptr));
104910923SEvan.Yan@Sun.COM 
105010923SEvan.Yan@Sun.COM 			if (i >= MAXDEVS)
105110923SEvan.Yan@Sun.COM 				return (DI_WALK_TERMINATE);
105210923SEvan.Yan@Sun.COM 
105310923SEvan.Yan@Sun.COM 			if ((*intp >> i) & 1) {
105410923SEvan.Yan@Sun.COM 				/* assign tmptr */
105510923SEvan.Yan@Sun.COM 				DBG(2, ("slot-name: %s \n", tmptr));
105610923SEvan.Yan@Sun.COM 				if (i == slotarg->minor)
105710923SEvan.Yan@Sun.COM 					(void) strcpy(slotarg->slotnames[i],
105810923SEvan.Yan@Sun.COM 					    tmptr);
105910923SEvan.Yan@Sun.COM 				/* wind tmptr to next \0 */
106010923SEvan.Yan@Sun.COM 				while (*tmptr != '\0') {
106110923SEvan.Yan@Sun.COM 					tmptr++;
106210923SEvan.Yan@Sun.COM 				}
106310923SEvan.Yan@Sun.COM 				tmptr++;
106410923SEvan.Yan@Sun.COM 			} else {
106510923SEvan.Yan@Sun.COM 				/* point at unknown string */
106610923SEvan.Yan@Sun.COM 				if (i == slotarg->minor)
106710923SEvan.Yan@Sun.COM 					(void) strcpy(slotarg->slotnames[i],
106810923SEvan.Yan@Sun.COM 					    "unknown");
106910923SEvan.Yan@Sun.COM 			}
107010923SEvan.Yan@Sun.COM 		}
107110923SEvan.Yan@Sun.COM 	}
107210923SEvan.Yan@Sun.COM 	return (DI_WALK_TERMINATE);
107310923SEvan.Yan@Sun.COM }
107410923SEvan.Yan@Sun.COM 
107510923SEvan.Yan@Sun.COM static int
find_slotname(di_node_t din,di_minor_t dim,void * arg)107610923SEvan.Yan@Sun.COM find_slotname(di_node_t din, di_minor_t dim, void *arg)
107710923SEvan.Yan@Sun.COM {
107810923SEvan.Yan@Sun.COM 	struct searcharg *slotarg = (struct searcharg *)arg;
107910923SEvan.Yan@Sun.COM 	di_prom_handle_t ph = (di_prom_handle_t)slotarg->promp;
108010923SEvan.Yan@Sun.COM 	di_prom_prop_t	prom_prop;
108110923SEvan.Yan@Sun.COM 	di_prop_t	solaris_prop;
108210923SEvan.Yan@Sun.COM 	int *intp, rval;
108310923SEvan.Yan@Sun.COM 	char *devname;
108410923SEvan.Yan@Sun.COM 	char fulldevname[MAXNAMELEN];
108510923SEvan.Yan@Sun.COM 
108610923SEvan.Yan@Sun.COM 	slotarg->minor = dim->dev_minor % 256;
108710923SEvan.Yan@Sun.COM 
108810923SEvan.Yan@Sun.COM 	DBG(2, ("minor number:(%i)\n", slotarg->minor));
108910923SEvan.Yan@Sun.COM 	DBG(2, ("hot plug slots found so far:(%i)\n", 0));
109010923SEvan.Yan@Sun.COM 
109110923SEvan.Yan@Sun.COM 	if ((devname = di_devfs_path(din)) != NULL) {
109210923SEvan.Yan@Sun.COM 		(void) snprintf(fulldevname, MAXNAMELEN,
109310923SEvan.Yan@Sun.COM 		    "/devices%s:%s", devname, di_minor_name(dim));
109410923SEvan.Yan@Sun.COM 		di_devfs_path_free(devname);
109510923SEvan.Yan@Sun.COM 	}
109610923SEvan.Yan@Sun.COM 
109710923SEvan.Yan@Sun.COM 	if (strcmp(fulldevname, slotarg->devpath) == 0) {
109810923SEvan.Yan@Sun.COM 
109910923SEvan.Yan@Sun.COM 		/*
110010923SEvan.Yan@Sun.COM 		 * Check the Solaris device tree first
110110923SEvan.Yan@Sun.COM 		 * in the case of a DR operation
110210923SEvan.Yan@Sun.COM 		 */
110310923SEvan.Yan@Sun.COM 		solaris_prop = di_prop_hw_next(din, DI_PROP_NIL);
110410923SEvan.Yan@Sun.COM 		while (solaris_prop != DI_PROP_NIL) {
110510923SEvan.Yan@Sun.COM 			if (strcmp("slot-names", di_prop_name(solaris_prop))
110610923SEvan.Yan@Sun.COM 			    == 0) {
110710923SEvan.Yan@Sun.COM 				rval = di_prop_lookup_ints(DDI_DEV_T_ANY,
110810923SEvan.Yan@Sun.COM 				    din, di_prop_name(solaris_prop), &intp);
110910923SEvan.Yan@Sun.COM 				slotarg->slt_name_src = SOLARIS_SLT_NAME;
111010923SEvan.Yan@Sun.COM 
111110923SEvan.Yan@Sun.COM 				return (fixup_slotname(rval, intp, slotarg));
111210923SEvan.Yan@Sun.COM 			}
111310923SEvan.Yan@Sun.COM 			solaris_prop = di_prop_hw_next(din, solaris_prop);
111410923SEvan.Yan@Sun.COM 		}
111510923SEvan.Yan@Sun.COM 
111610923SEvan.Yan@Sun.COM 		/*
111710923SEvan.Yan@Sun.COM 		 * Check the prom device tree which is populated at boot.
111810923SEvan.Yan@Sun.COM 		 * If this fails, give up and set the slot name to null.
111910923SEvan.Yan@Sun.COM 		 */
112010923SEvan.Yan@Sun.COM 		prom_prop = di_prom_prop_next(ph, din, DI_PROM_PROP_NIL);
112110923SEvan.Yan@Sun.COM 		while (prom_prop != DI_PROM_PROP_NIL) {
112210923SEvan.Yan@Sun.COM 			if (strcmp("slot-names", di_prom_prop_name(prom_prop))
112310923SEvan.Yan@Sun.COM 			    == 0) {
112410923SEvan.Yan@Sun.COM 				rval = di_prom_prop_lookup_ints(ph,
112510923SEvan.Yan@Sun.COM 				    din, di_prom_prop_name(prom_prop), &intp);
112610923SEvan.Yan@Sun.COM 				slotarg->slt_name_src = PROM_SLT_NAME;
112710923SEvan.Yan@Sun.COM 
112810923SEvan.Yan@Sun.COM 				return (fixup_slotname(rval, intp, slotarg));
112910923SEvan.Yan@Sun.COM 			}
113010923SEvan.Yan@Sun.COM 			prom_prop = di_prom_prop_next(ph, din, prom_prop);
113110923SEvan.Yan@Sun.COM 		}
113210923SEvan.Yan@Sun.COM 		*slotarg->slotnames[slotarg->minor] = '\0';
113310923SEvan.Yan@Sun.COM 		return (DI_WALK_TERMINATE);
113410923SEvan.Yan@Sun.COM 	} else
113510923SEvan.Yan@Sun.COM 		return (DI_WALK_CONTINUE);
113610923SEvan.Yan@Sun.COM }
113710923SEvan.Yan@Sun.COM 
113810923SEvan.Yan@Sun.COM static int
find_physical_slot_names(const char * devcomp,struct searcharg * slotarg)113910923SEvan.Yan@Sun.COM find_physical_slot_names(const char *devcomp, struct searcharg *slotarg)
114010923SEvan.Yan@Sun.COM {
114110923SEvan.Yan@Sun.COM 	di_node_t root_node;
114210923SEvan.Yan@Sun.COM 
114310923SEvan.Yan@Sun.COM 	DBG(1, ("find_physical_slot_names\n"));
114410923SEvan.Yan@Sun.COM 
114510923SEvan.Yan@Sun.COM 	if ((root_node = di_init("/", DINFOCPYALL|DINFOPATH))
114610923SEvan.Yan@Sun.COM 	    == DI_NODE_NIL) {
114710923SEvan.Yan@Sun.COM 		DBG(1, ("di_init() failed\n"));
114810923SEvan.Yan@Sun.COM 		return (-1);
114910923SEvan.Yan@Sun.COM 	}
115010923SEvan.Yan@Sun.COM 
115110923SEvan.Yan@Sun.COM 	slotarg->devpath = (char *)devcomp;
115210923SEvan.Yan@Sun.COM 
115310923SEvan.Yan@Sun.COM 	if ((slotarg->promp = di_prom_init()) == DI_PROM_HANDLE_NIL) {
115410923SEvan.Yan@Sun.COM 		DBG(1, ("di_prom_init() failed\n"));
115510923SEvan.Yan@Sun.COM 		di_fini(root_node);
115610923SEvan.Yan@Sun.COM 		return (-1);
115710923SEvan.Yan@Sun.COM 	}
115810923SEvan.Yan@Sun.COM 
115910923SEvan.Yan@Sun.COM 	(void) di_walk_minor(root_node, "ddi_ctl:attachment_point:pci",
116010923SEvan.Yan@Sun.COM 	    0, (void *)slotarg, find_slotname);
116110923SEvan.Yan@Sun.COM 
116210923SEvan.Yan@Sun.COM 	di_prom_fini(slotarg->promp);
116310923SEvan.Yan@Sun.COM 	di_fini(root_node);
116410923SEvan.Yan@Sun.COM 	if (slotarg->slotnames[0] != NULL)
116510923SEvan.Yan@Sun.COM 		return (0);
116610923SEvan.Yan@Sun.COM 	else
116710923SEvan.Yan@Sun.COM 		return (-1);
116810923SEvan.Yan@Sun.COM }
116910923SEvan.Yan@Sun.COM 
117010923SEvan.Yan@Sun.COM static void
get_type(const char * boardtype,const char * cardtype,char * buf)117110923SEvan.Yan@Sun.COM get_type(const char *boardtype, const char *cardtype, char *buf)
117210923SEvan.Yan@Sun.COM {
117310923SEvan.Yan@Sun.COM /* for type string assembly in get_type() */
117410923SEvan.Yan@Sun.COM #define	TPCT(s)	(void) strlcat(buf, (s), CFGA_TYPE_LEN)
117510923SEvan.Yan@Sun.COM 
117610923SEvan.Yan@Sun.COM 	int i;
117710923SEvan.Yan@Sun.COM 
117810923SEvan.Yan@Sun.COM 	if (strcmp(cardtype, "unknown") == 0) {
117910923SEvan.Yan@Sun.COM 		TPCT("unknown");
118010923SEvan.Yan@Sun.COM 		return;
118110923SEvan.Yan@Sun.COM 	}
118210923SEvan.Yan@Sun.COM 
118310923SEvan.Yan@Sun.COM 	TPCT(cardtype);
118410923SEvan.Yan@Sun.COM 	TPCT("/");
118510923SEvan.Yan@Sun.COM 
118610923SEvan.Yan@Sun.COM 	if (strcmp(boardtype, PCIEHPC_PROP_VALUE_PCIHOTPLUG) == 0)
118710923SEvan.Yan@Sun.COM 		TPCT(board_strs[PCIEHPC_BOARD_PCI_HOTPLUG]);
118810923SEvan.Yan@Sun.COM 	else
118910923SEvan.Yan@Sun.COM 		TPCT(board_strs[PCIEHPC_BOARD_UNKNOWN]);
119010923SEvan.Yan@Sun.COM }
119110923SEvan.Yan@Sun.COM 
119210923SEvan.Yan@Sun.COM /*
119310923SEvan.Yan@Sun.COM  * call-back function for di_devlink_walk
119410923SEvan.Yan@Sun.COM  * if the link lives in /dev/cfg copy its name
119510923SEvan.Yan@Sun.COM  */
119610923SEvan.Yan@Sun.COM static int
found_devlink(di_devlink_t link,void * ap_log_id)119710923SEvan.Yan@Sun.COM found_devlink(di_devlink_t link, void *ap_log_id)
119810923SEvan.Yan@Sun.COM {
119910923SEvan.Yan@Sun.COM 	if (strncmp("/dev/cfg/", di_devlink_path(link), 9) == 0) {
120010923SEvan.Yan@Sun.COM 		/* copy everything but /dev/cfg/ */
120110923SEvan.Yan@Sun.COM 		(void) strcpy((char *)ap_log_id, di_devlink_path(link) + 9);
120210923SEvan.Yan@Sun.COM 		DBG(1, ("found_devlink: %s\n", (char *)ap_log_id));
120310923SEvan.Yan@Sun.COM 		return (DI_WALK_TERMINATE);
120410923SEvan.Yan@Sun.COM 	}
120510923SEvan.Yan@Sun.COM 	return (DI_WALK_CONTINUE);
120610923SEvan.Yan@Sun.COM }
120710923SEvan.Yan@Sun.COM 
120810923SEvan.Yan@Sun.COM /*
120910923SEvan.Yan@Sun.COM  * Walk throught the cached /dev link tree looking for links to the ap
121010923SEvan.Yan@Sun.COM  * if none are found return an error
121110923SEvan.Yan@Sun.COM  */
121210923SEvan.Yan@Sun.COM static cfga_err_t
check_devlinks(char * ap_log_id,const char * ap_id)121310923SEvan.Yan@Sun.COM check_devlinks(char *ap_log_id, const char *ap_id)
121410923SEvan.Yan@Sun.COM {
121510923SEvan.Yan@Sun.COM 	di_devlink_handle_t hdl;
121610923SEvan.Yan@Sun.COM 
121710923SEvan.Yan@Sun.COM 	DBG(1, ("check_devlinks: %s\n", ap_id));
121810923SEvan.Yan@Sun.COM 
121910923SEvan.Yan@Sun.COM 	hdl = di_devlink_init(NULL, 0);
122010923SEvan.Yan@Sun.COM 
122110923SEvan.Yan@Sun.COM 	if (strncmp("/devices/", ap_id, 9) == 0) {
122210923SEvan.Yan@Sun.COM 		/* ap_id is a valid minor_path with /devices prepended */
122310923SEvan.Yan@Sun.COM 		(void) di_devlink_walk(hdl, NULL, ap_id + 8, DI_PRIMARY_LINK,
122410923SEvan.Yan@Sun.COM 		    (void *)ap_log_id, found_devlink);
122510923SEvan.Yan@Sun.COM 	} else {
122610923SEvan.Yan@Sun.COM 		DBG(1, ("check_devlinks: invalid ap_id: %s\n", ap_id));
122710923SEvan.Yan@Sun.COM 		return (CFGA_ERROR);
122810923SEvan.Yan@Sun.COM 	}
122910923SEvan.Yan@Sun.COM 
123010923SEvan.Yan@Sun.COM 	(void) di_devlink_fini(&hdl);
123110923SEvan.Yan@Sun.COM 
123210923SEvan.Yan@Sun.COM 	if (ap_log_id[0] != '\0')
123310923SEvan.Yan@Sun.COM 		return (CFGA_OK);
123410923SEvan.Yan@Sun.COM 	else
123510923SEvan.Yan@Sun.COM 		return (CFGA_ERROR);
123610923SEvan.Yan@Sun.COM }
123710923SEvan.Yan@Sun.COM 
123810923SEvan.Yan@Sun.COM /*
123910923SEvan.Yan@Sun.COM  * most of this is needed to compensate for
124010923SEvan.Yan@Sun.COM  * differences between various platforms
124110923SEvan.Yan@Sun.COM  */
124210923SEvan.Yan@Sun.COM static cfga_err_t
fix_ap_name(char * ap_log_id,const char * ap_id,char * slot_name,char ** errstring)124310923SEvan.Yan@Sun.COM fix_ap_name(char *ap_log_id, const char *ap_id, char *slot_name,
124410923SEvan.Yan@Sun.COM     char **errstring)
124510923SEvan.Yan@Sun.COM {
124610923SEvan.Yan@Sun.COM 	char *buf;
124710923SEvan.Yan@Sun.COM 	char *tmp;
124810923SEvan.Yan@Sun.COM 	char *ptr;
124910923SEvan.Yan@Sun.COM 
125010923SEvan.Yan@Sun.COM 	di_node_t ap_node;
125110923SEvan.Yan@Sun.COM 
125210923SEvan.Yan@Sun.COM 	ap_log_id[0] = '\0';
125310923SEvan.Yan@Sun.COM 
125410923SEvan.Yan@Sun.COM 	if (check_devlinks(ap_log_id, ap_id) == CFGA_OK)
125510923SEvan.Yan@Sun.COM 		return (CFGA_OK);
125610923SEvan.Yan@Sun.COM 
125710923SEvan.Yan@Sun.COM 	DBG(1, ("fix_ap_name: %s\n", ap_id));
125810923SEvan.Yan@Sun.COM 
125910923SEvan.Yan@Sun.COM 	if ((buf = malloc(strlen(ap_id) + 1)) == NULL) {
126010923SEvan.Yan@Sun.COM 		DBG(1, ("malloc failed\n"));
126110923SEvan.Yan@Sun.COM 		return (CFGA_ERROR);
126210923SEvan.Yan@Sun.COM 	}
126310923SEvan.Yan@Sun.COM 	(void) strcpy(buf, ap_id);
126410923SEvan.Yan@Sun.COM 	tmp = buf + sizeof ("/devices") - 1;
126510923SEvan.Yan@Sun.COM 
126610923SEvan.Yan@Sun.COM 	ptr = strchr(tmp, ':');
126710923SEvan.Yan@Sun.COM 	ptr[0] = '\0';
126810923SEvan.Yan@Sun.COM 
126910923SEvan.Yan@Sun.COM 	DBG(1, ("fix_ap_name: %s\n", tmp));
127010923SEvan.Yan@Sun.COM 
127110923SEvan.Yan@Sun.COM 	ap_node = di_init(tmp, DINFOMINOR);
127210923SEvan.Yan@Sun.COM 	if (ap_node == DI_NODE_NIL) {
127310923SEvan.Yan@Sun.COM 		cfga_err(errstring, "di_init ", 0);
127410923SEvan.Yan@Sun.COM 		DBG(1, ("fix_ap_name: failed to snapshot node\n"));
127510923SEvan.Yan@Sun.COM 		return (CFGA_ERROR);
127610923SEvan.Yan@Sun.COM 	}
127710923SEvan.Yan@Sun.COM 
127810923SEvan.Yan@Sun.COM 	(void) snprintf(ap_log_id, strlen(ap_id) + 1, "%s%i:%s",
127910923SEvan.Yan@Sun.COM 	    di_driver_name(ap_node), di_instance(ap_node), slot_name);
128010923SEvan.Yan@Sun.COM 
128110923SEvan.Yan@Sun.COM 	DBG(1, ("fix_ap_name: %s\n", ap_log_id));
128210923SEvan.Yan@Sun.COM 
128310923SEvan.Yan@Sun.COM 	di_fini(ap_node);
128410923SEvan.Yan@Sun.COM 
128510923SEvan.Yan@Sun.COM 	free(buf);
128610923SEvan.Yan@Sun.COM 	return (CFGA_OK);
128710923SEvan.Yan@Sun.COM }
128810923SEvan.Yan@Sun.COM 
128910923SEvan.Yan@Sun.COM 
129010923SEvan.Yan@Sun.COM static int
findlink_cb(di_devlink_t devlink,void * arg)129110923SEvan.Yan@Sun.COM findlink_cb(di_devlink_t devlink, void *arg)
129210923SEvan.Yan@Sun.COM {
129310923SEvan.Yan@Sun.COM 	(*(char **)arg) = strdup(di_devlink_path(devlink));
129410923SEvan.Yan@Sun.COM 
129510923SEvan.Yan@Sun.COM 	return (DI_WALK_TERMINATE);
129610923SEvan.Yan@Sun.COM }
129710923SEvan.Yan@Sun.COM 
129810923SEvan.Yan@Sun.COM /*
129910923SEvan.Yan@Sun.COM  * returns an allocated string containing the full path to the devlink for
130010923SEvan.Yan@Sun.COM  * <ap_phys_id> in the devlink database; we expect only one devlink per
130110923SEvan.Yan@Sun.COM  * <ap_phys_id> so we return the first encountered
130210923SEvan.Yan@Sun.COM  */
130310923SEvan.Yan@Sun.COM static char *
findlink(char * ap_phys_id)130410923SEvan.Yan@Sun.COM findlink(char *ap_phys_id)
130510923SEvan.Yan@Sun.COM {
130610923SEvan.Yan@Sun.COM 	di_devlink_handle_t hdl;
130710923SEvan.Yan@Sun.COM 	char *path = NULL;
130810923SEvan.Yan@Sun.COM 
130910923SEvan.Yan@Sun.COM 	hdl = di_devlink_init(NULL, 0);
131010923SEvan.Yan@Sun.COM 
131110923SEvan.Yan@Sun.COM 	if (strncmp("/devices/", ap_phys_id, 9) == 0)
131210923SEvan.Yan@Sun.COM 		ap_phys_id += 8;
131310923SEvan.Yan@Sun.COM 
131410923SEvan.Yan@Sun.COM 	(void) di_devlink_walk(hdl, "^cfg/.+$", ap_phys_id, DI_PRIMARY_LINK,
131510923SEvan.Yan@Sun.COM 	    (void *)&path, findlink_cb);
131610923SEvan.Yan@Sun.COM 
131710923SEvan.Yan@Sun.COM 	(void) di_devlink_fini(&hdl);
131810923SEvan.Yan@Sun.COM 	return (path);
131910923SEvan.Yan@Sun.COM }
132010923SEvan.Yan@Sun.COM 
132110923SEvan.Yan@Sun.COM 
132210923SEvan.Yan@Sun.COM /*
132310923SEvan.Yan@Sun.COM  * returns CFGA_OK if it can succesfully retrieve the devlink info associated
132410923SEvan.Yan@Sun.COM  * with devlink for <ap_phys_id> which will be returned through <ap_info>
132510923SEvan.Yan@Sun.COM  */
132610923SEvan.Yan@Sun.COM cfga_err_t
get_dli(char * dlpath,char * ap_info,int ap_info_sz)132710923SEvan.Yan@Sun.COM get_dli(char *dlpath, char *ap_info, int ap_info_sz)
132810923SEvan.Yan@Sun.COM {
132910923SEvan.Yan@Sun.COM 	int fd;
133010923SEvan.Yan@Sun.COM 
133110923SEvan.Yan@Sun.COM 	fd = di_dli_openr(dlpath);
133210923SEvan.Yan@Sun.COM 	if (fd < 0)
133310923SEvan.Yan@Sun.COM 		return (CFGA_ERROR);
133410923SEvan.Yan@Sun.COM 
133510923SEvan.Yan@Sun.COM 	(void) read(fd, ap_info, ap_info_sz);
133610923SEvan.Yan@Sun.COM 	ap_info[ap_info_sz - 1] = '\0';
133710923SEvan.Yan@Sun.COM 
133810923SEvan.Yan@Sun.COM 	di_dli_close(fd);
133910923SEvan.Yan@Sun.COM 	return (CFGA_OK);
134010923SEvan.Yan@Sun.COM }
134110923SEvan.Yan@Sun.COM 
134210923SEvan.Yan@Sun.COM static cfga_err_t
cfga_get_condition(hp_node_t node,ap_condition_t * cond)134310923SEvan.Yan@Sun.COM cfga_get_condition(hp_node_t node, ap_condition_t *cond)
134410923SEvan.Yan@Sun.COM {
134510923SEvan.Yan@Sun.COM 	char *condition;
134610923SEvan.Yan@Sun.COM 
134710923SEvan.Yan@Sun.COM 	/* "condition" bus specific commands */
134810923SEvan.Yan@Sun.COM 	if (hp_get_private(node, PCIEHPC_PROP_SLOT_CONDITION,
134910923SEvan.Yan@Sun.COM 	    &condition) != 0) {
135010923SEvan.Yan@Sun.COM 		*cond = AP_COND_UNKNOWN;
135110923SEvan.Yan@Sun.COM 		return (CFGA_ERROR);
135210923SEvan.Yan@Sun.COM 	}
135310923SEvan.Yan@Sun.COM 
135410923SEvan.Yan@Sun.COM 	condition = get_val_from_result(condition);
135510923SEvan.Yan@Sun.COM 
135610923SEvan.Yan@Sun.COM 	if (strcmp(condition, PCIEHPC_PROP_COND_OK) == 0)
135710923SEvan.Yan@Sun.COM 		*cond = AP_COND_OK;
135810923SEvan.Yan@Sun.COM 	else if (strcmp(condition, PCIEHPC_PROP_COND_FAILING) == 0)
135910923SEvan.Yan@Sun.COM 		*cond = AP_COND_FAILING;
136010923SEvan.Yan@Sun.COM 	else if (strcmp(condition, PCIEHPC_PROP_COND_FAILED) == 0)
136110923SEvan.Yan@Sun.COM 		*cond = AP_COND_FAILED;
136210923SEvan.Yan@Sun.COM 	else if (strcmp(condition, PCIEHPC_PROP_COND_UNUSABLE) == 0)
136310923SEvan.Yan@Sun.COM 		*cond = AP_COND_UNUSABLE;
136410923SEvan.Yan@Sun.COM 	else if (strcmp(condition, PCIEHPC_PROP_COND_UNKNOWN) == 0)
136510923SEvan.Yan@Sun.COM 		*cond = AP_COND_UNKNOWN;
136610923SEvan.Yan@Sun.COM 	else
136710923SEvan.Yan@Sun.COM 		return (CFGA_ERROR);
136810923SEvan.Yan@Sun.COM 
136910923SEvan.Yan@Sun.COM 	return (CFGA_OK);
137010923SEvan.Yan@Sun.COM }
137110923SEvan.Yan@Sun.COM 
137210923SEvan.Yan@Sun.COM /*ARGSUSED*/
137310923SEvan.Yan@Sun.COM cfga_err_t
cfga_list_ext(const char * ap_id,cfga_list_data_t ** cs,int * nlist,const char * options,const char * listopts,char ** errstring,cfga_flags_t flags)137410923SEvan.Yan@Sun.COM cfga_list_ext(const char *ap_id, cfga_list_data_t **cs,
137510923SEvan.Yan@Sun.COM     int *nlist, const char *options, const char *listopts, char **errstring,
137610923SEvan.Yan@Sun.COM     cfga_flags_t flags)
137710923SEvan.Yan@Sun.COM {
137810923SEvan.Yan@Sun.COM 	char			*boardtype;
137910923SEvan.Yan@Sun.COM 	char			*cardtype;
138010923SEvan.Yan@Sun.COM 	struct	searcharg	slotname_arg;
138110923SEvan.Yan@Sun.COM 	int			fd;
138210923SEvan.Yan@Sun.COM 	int			rv = CFGA_OK;
138310923SEvan.Yan@Sun.COM 	char			*dlpath = NULL;
138410923SEvan.Yan@Sun.COM 	hp_node_t		node;
138510923SEvan.Yan@Sun.COM 	ap_rstate_t		rs;
138610923SEvan.Yan@Sun.COM 	ap_ostate_t		os;
138710923SEvan.Yan@Sun.COM 	ap_condition_t		cond;
138810923SEvan.Yan@Sun.COM 
138910923SEvan.Yan@Sun.COM 	if ((rv = check_options(options)) != CFGA_OK) {
139010923SEvan.Yan@Sun.COM 		return (rv);
139110923SEvan.Yan@Sun.COM 	}
139210923SEvan.Yan@Sun.COM 
139310923SEvan.Yan@Sun.COM 	if (errstring != NULL)
139410923SEvan.Yan@Sun.COM 		*errstring = NULL;
139510923SEvan.Yan@Sun.COM 
139610923SEvan.Yan@Sun.COM 	DBG(1, ("cfga_list_ext:(%s)\n", ap_id));
139710923SEvan.Yan@Sun.COM 
139810923SEvan.Yan@Sun.COM 	if (cs == NULL || nlist == NULL) {
139910923SEvan.Yan@Sun.COM 		rv = CFGA_ERROR;
140010923SEvan.Yan@Sun.COM 		return (rv);
140110923SEvan.Yan@Sun.COM 	}
140210923SEvan.Yan@Sun.COM 
140310923SEvan.Yan@Sun.COM 	*nlist = 1;
140410923SEvan.Yan@Sun.COM 
140510923SEvan.Yan@Sun.COM 	if ((*cs = malloc(sizeof (cfga_list_data_t))) == NULL) {
140610923SEvan.Yan@Sun.COM 		cfga_err(errstring, "malloc ", 0);
140710923SEvan.Yan@Sun.COM 		DBG(1, ("malloc failed\n"));
140810923SEvan.Yan@Sun.COM 		rv = CFGA_ERROR;
140910923SEvan.Yan@Sun.COM 		return (rv);
141010923SEvan.Yan@Sun.COM 	}
141110923SEvan.Yan@Sun.COM 	(void) memset(*cs, 0, sizeof (cfga_list_data_t));
141210923SEvan.Yan@Sun.COM 
141310923SEvan.Yan@Sun.COM 	rv = physpath2node(ap_id, errstring, &node);
141410923SEvan.Yan@Sun.COM 	if (rv != CFGA_OK) {
141510923SEvan.Yan@Sun.COM 		DBG(1, ("physpath2node failed\n"));
141610923SEvan.Yan@Sun.COM 		return (rv);
141710923SEvan.Yan@Sun.COM 	}
141810923SEvan.Yan@Sun.COM 
141910923SEvan.Yan@Sun.COM 	if (cfga_get_state(node, &rs, &os) != CFGA_OK) {
142010923SEvan.Yan@Sun.COM 		DBG(1, ("cfga_get_state failed\n"));
142110923SEvan.Yan@Sun.COM 		hp_fini(node);
142210923SEvan.Yan@Sun.COM 		return (CFGA_ERROR);
142310923SEvan.Yan@Sun.COM 	}
142410923SEvan.Yan@Sun.COM 
142510923SEvan.Yan@Sun.COM 	switch (rs) {
142610923SEvan.Yan@Sun.COM 		case AP_RSTATE_EMPTY:
142710923SEvan.Yan@Sun.COM 			(*cs)->ap_r_state = CFGA_STAT_EMPTY;
142810923SEvan.Yan@Sun.COM 			DBG(2, ("ap_rstate = CFGA_STAT_EMPTY\n"));
142910923SEvan.Yan@Sun.COM 			break;
143010923SEvan.Yan@Sun.COM 		case AP_RSTATE_DISCONNECTED:
143110923SEvan.Yan@Sun.COM 			(*cs)->ap_r_state = CFGA_STAT_DISCONNECTED;
143210923SEvan.Yan@Sun.COM 			DBG(2, ("ap_rstate = CFGA_STAT_DISCONNECTED\n"));
143310923SEvan.Yan@Sun.COM 			break;
143410923SEvan.Yan@Sun.COM 		case AP_RSTATE_CONNECTED:
143510923SEvan.Yan@Sun.COM 			(*cs)->ap_r_state = CFGA_STAT_CONNECTED;
143610923SEvan.Yan@Sun.COM 			DBG(2, ("ap_rstate = CFGA_STAT_CONNECTED\n"));
143710923SEvan.Yan@Sun.COM 			break;
143810923SEvan.Yan@Sun.COM 	default:
143910923SEvan.Yan@Sun.COM 		cfga_err(errstring, CMD_GETSTAT, ap_id, 0);
144010923SEvan.Yan@Sun.COM 		rv = CFGA_ERROR;
144110923SEvan.Yan@Sun.COM 		hp_fini(node);
144210923SEvan.Yan@Sun.COM 		return (rv);
144310923SEvan.Yan@Sun.COM 	}
144410923SEvan.Yan@Sun.COM 
144510923SEvan.Yan@Sun.COM 	switch (os) {
144610923SEvan.Yan@Sun.COM 		case AP_OSTATE_CONFIGURED:
144710923SEvan.Yan@Sun.COM 			(*cs)->ap_o_state = CFGA_STAT_CONFIGURED;
144810923SEvan.Yan@Sun.COM 			DBG(2, ("ap_ostate = CFGA_STAT_CONFIGURED\n"));
144910923SEvan.Yan@Sun.COM 			break;
145010923SEvan.Yan@Sun.COM 		case AP_OSTATE_UNCONFIGURED:
145110923SEvan.Yan@Sun.COM 			(*cs)->ap_o_state = CFGA_STAT_UNCONFIGURED;
145210923SEvan.Yan@Sun.COM 			DBG(2, ("ap_ostate = CFGA_STAT_UNCONFIGURED\n"));
145310923SEvan.Yan@Sun.COM 			break;
145410923SEvan.Yan@Sun.COM 	default:
145510923SEvan.Yan@Sun.COM 		cfga_err(errstring, CMD_GETSTAT, ap_id, 0);
145610923SEvan.Yan@Sun.COM 		rv = CFGA_ERROR;
145710923SEvan.Yan@Sun.COM 		hp_fini(node);
145810923SEvan.Yan@Sun.COM 		return (rv);
145910923SEvan.Yan@Sun.COM 	}
146010923SEvan.Yan@Sun.COM 
146110923SEvan.Yan@Sun.COM 	(void) cfga_get_condition(node, &cond);
146210923SEvan.Yan@Sun.COM 
146310923SEvan.Yan@Sun.COM 	switch (cond) {
146410923SEvan.Yan@Sun.COM 		case AP_COND_OK:
146510923SEvan.Yan@Sun.COM 			(*cs)->ap_cond = CFGA_COND_OK;
146610923SEvan.Yan@Sun.COM 			DBG(2, ("ap_cond = CFGA_COND_OK\n"));
146710923SEvan.Yan@Sun.COM 			break;
146810923SEvan.Yan@Sun.COM 		case AP_COND_FAILING:
146910923SEvan.Yan@Sun.COM 			(*cs)->ap_cond = CFGA_COND_FAILING;
147010923SEvan.Yan@Sun.COM 			DBG(2, ("ap_cond = CFGA_COND_FAILING\n"));
147110923SEvan.Yan@Sun.COM 			break;
147210923SEvan.Yan@Sun.COM 		case AP_COND_FAILED:
147310923SEvan.Yan@Sun.COM 			(*cs)->ap_cond = CFGA_COND_FAILED;
147410923SEvan.Yan@Sun.COM 			DBG(2, ("ap_cond = CFGA_COND_FAILED\n"));
147510923SEvan.Yan@Sun.COM 			break;
147610923SEvan.Yan@Sun.COM 		case AP_COND_UNUSABLE:
147710923SEvan.Yan@Sun.COM 			(*cs)->ap_cond = CFGA_COND_UNUSABLE;
147810923SEvan.Yan@Sun.COM 			DBG(2, ("ap_cond = CFGA_COND_UNUSABLE\n"));
147910923SEvan.Yan@Sun.COM 			break;
148010923SEvan.Yan@Sun.COM 		case AP_COND_UNKNOWN:
148110923SEvan.Yan@Sun.COM 			(*cs)->ap_cond = CFGA_COND_UNKNOWN;
148210923SEvan.Yan@Sun.COM 			DBG(2, ("ap_cond = CFGA_COND_UNKNOW\n"));
148310923SEvan.Yan@Sun.COM 			break;
148410923SEvan.Yan@Sun.COM 	default:
148510923SEvan.Yan@Sun.COM 		cfga_err(errstring, CMD_GETSTAT, ap_id, 0);
148610923SEvan.Yan@Sun.COM 		rv = CFGA_ERROR;
148710923SEvan.Yan@Sun.COM 		hp_fini(node);
148810923SEvan.Yan@Sun.COM 		return (rv);
148910923SEvan.Yan@Sun.COM 	}
149010923SEvan.Yan@Sun.COM 	/*
149110923SEvan.Yan@Sun.COM 	 * We're not busy since the entrance into the kernel has been
149210923SEvan.Yan@Sun.COM 	 * sync'ed via libhotplug.
149310923SEvan.Yan@Sun.COM 	 */
149410923SEvan.Yan@Sun.COM 	(*cs)->ap_busy = 0;
149510923SEvan.Yan@Sun.COM 
149610923SEvan.Yan@Sun.COM 	/* last change */
149710923SEvan.Yan@Sun.COM 	(*cs)->ap_status_time = hp_last_change(node);
149810923SEvan.Yan@Sun.COM 
149910923SEvan.Yan@Sun.COM 	/* board type */
150010923SEvan.Yan@Sun.COM 	if (hp_get_private(node, PCIEHPC_PROP_BOARD_TYPE, &boardtype) != 0)
150110923SEvan.Yan@Sun.COM 		boardtype = PCIEHPC_PROP_VALUE_UNKNOWN;
150210923SEvan.Yan@Sun.COM 	else
150310923SEvan.Yan@Sun.COM 		boardtype = get_val_from_result(boardtype);
150410923SEvan.Yan@Sun.COM 
150510923SEvan.Yan@Sun.COM 	/* card type */
150610923SEvan.Yan@Sun.COM 	if (hp_get_private(node, PCIEHPC_PROP_CARD_TYPE, &cardtype) != 0)
150710923SEvan.Yan@Sun.COM 		cardtype = PCIEHPC_PROP_VALUE_UNKNOWN;
150810923SEvan.Yan@Sun.COM 	else
150910923SEvan.Yan@Sun.COM 		cardtype = get_val_from_result(cardtype);
151010923SEvan.Yan@Sun.COM 
151110923SEvan.Yan@Sun.COM 	/* logical ap_id */
151210923SEvan.Yan@Sun.COM 	rv = fix_ap_name((*cs)->ap_log_id, ap_id,
151310923SEvan.Yan@Sun.COM 	    hp_name(node), errstring);
151410923SEvan.Yan@Sun.COM 	DBG(1, ("logical id: %s\n", (*cs)->ap_log_id));
151510923SEvan.Yan@Sun.COM 	/* physical ap_id */
151610923SEvan.Yan@Sun.COM 	(void) strcpy((*cs)->ap_phys_id, ap_id);    /* physical path of AP */
151710923SEvan.Yan@Sun.COM 
151810923SEvan.Yan@Sun.COM 	/* information */
151910923SEvan.Yan@Sun.COM 	dlpath = findlink((*cs)->ap_phys_id);
152010923SEvan.Yan@Sun.COM 	if (dlpath != NULL) {
152110923SEvan.Yan@Sun.COM 		if (get_dli(dlpath, (*cs)->ap_info,
152210923SEvan.Yan@Sun.COM 		    sizeof ((*cs)->ap_info)) != CFGA_OK)
152310923SEvan.Yan@Sun.COM 			(*cs)->ap_info[0] = '\0';
152410923SEvan.Yan@Sun.COM 		free(dlpath);
152510923SEvan.Yan@Sun.COM 	}
152610923SEvan.Yan@Sun.COM 
152710923SEvan.Yan@Sun.COM 	if ((*cs)->ap_log_id[0] == '\0')
152810923SEvan.Yan@Sun.COM 		(void) strcpy((*cs)->ap_log_id, hp_name(node));
152910923SEvan.Yan@Sun.COM 
153010923SEvan.Yan@Sun.COM 	if ((*cs)->ap_info[0] == '\0') {
153110923SEvan.Yan@Sun.COM 		/* slot_names of bus node  */
153210923SEvan.Yan@Sun.COM 		if (find_physical_slot_names(ap_id, &slotname_arg) != -1)
153310923SEvan.Yan@Sun.COM 			(void) strcpy((*cs)->ap_info,
153410923SEvan.Yan@Sun.COM 			    slotname_arg.slotnames[slotname_arg.minor]);
153510923SEvan.Yan@Sun.COM 	}
153610923SEvan.Yan@Sun.COM 
153710923SEvan.Yan@Sun.COM 	/* class_code/subclass/boardtype */
153810923SEvan.Yan@Sun.COM 	get_type(boardtype, cardtype, (*cs)->ap_type);
153910923SEvan.Yan@Sun.COM 
154010923SEvan.Yan@Sun.COM 	DBG(1, ("cfga_list_ext return success\n"));
154110923SEvan.Yan@Sun.COM 	rv = CFGA_OK;
154210923SEvan.Yan@Sun.COM 
154310923SEvan.Yan@Sun.COM 	hp_fini(node);
154410923SEvan.Yan@Sun.COM 	return (rv);
154510923SEvan.Yan@Sun.COM }
154610923SEvan.Yan@Sun.COM 
154710923SEvan.Yan@Sun.COM /*
154810923SEvan.Yan@Sun.COM  * This routine prints a single line of help message
154910923SEvan.Yan@Sun.COM  */
155010923SEvan.Yan@Sun.COM static void
cfga_msg(struct cfga_msg * msgp,const char * str)155110923SEvan.Yan@Sun.COM cfga_msg(struct cfga_msg *msgp, const char *str)
155210923SEvan.Yan@Sun.COM {
155310923SEvan.Yan@Sun.COM 	DBG(2, ("<%s>", str));
155410923SEvan.Yan@Sun.COM 
155510923SEvan.Yan@Sun.COM 	if (msgp == NULL || msgp->message_routine == NULL)
155610923SEvan.Yan@Sun.COM 		return;
155710923SEvan.Yan@Sun.COM 
155810923SEvan.Yan@Sun.COM 	(*msgp->message_routine)(msgp->appdata_ptr, str);
155910923SEvan.Yan@Sun.COM 	(*msgp->message_routine)(msgp->appdata_ptr, "\n");
156010923SEvan.Yan@Sun.COM }
156110923SEvan.Yan@Sun.COM 
156210923SEvan.Yan@Sun.COM static cfga_err_t
check_options(const char * options)156310923SEvan.Yan@Sun.COM check_options(const char *options)
156410923SEvan.Yan@Sun.COM {
156510923SEvan.Yan@Sun.COM 	struct cfga_msg *msgp = NULL;
156610923SEvan.Yan@Sun.COM 
156710923SEvan.Yan@Sun.COM 	if (options) {
156810923SEvan.Yan@Sun.COM 		cfga_msg(msgp, dgettext(TEXT_DOMAIN, cfga_strs[HELP_UNKNOWN]));
156910923SEvan.Yan@Sun.COM 		cfga_msg(msgp, options);
157010923SEvan.Yan@Sun.COM 		return (CFGA_INVAL);
157110923SEvan.Yan@Sun.COM 	}
157210923SEvan.Yan@Sun.COM 	return (CFGA_OK);
157310923SEvan.Yan@Sun.COM }
157410923SEvan.Yan@Sun.COM 
157510923SEvan.Yan@Sun.COM /*ARGSUSED*/
157610923SEvan.Yan@Sun.COM cfga_err_t
cfga_help(struct cfga_msg * msgp,const char * options,cfga_flags_t flags)157710923SEvan.Yan@Sun.COM cfga_help(struct cfga_msg *msgp, const char *options, cfga_flags_t flags)
157810923SEvan.Yan@Sun.COM {
157910923SEvan.Yan@Sun.COM 	if (options) {
158010923SEvan.Yan@Sun.COM 		cfga_msg(msgp, dgettext(TEXT_DOMAIN, cfga_strs[HELP_UNKNOWN]));
158110923SEvan.Yan@Sun.COM 		cfga_msg(msgp, options);
158210923SEvan.Yan@Sun.COM 	}
158310923SEvan.Yan@Sun.COM 	DBG(1, ("cfga_help\n"));
158410923SEvan.Yan@Sun.COM 
158510923SEvan.Yan@Sun.COM 	cfga_msg(msgp, dgettext(TEXT_DOMAIN, cfga_strs[HELP_HEADER]));
158610923SEvan.Yan@Sun.COM 	cfga_msg(msgp, cfga_strs[HELP_CONFIG]);
158710923SEvan.Yan@Sun.COM 	cfga_msg(msgp, cfga_strs[HELP_ENABLE_SLOT]);
158810923SEvan.Yan@Sun.COM 	cfga_msg(msgp, cfga_strs[HELP_DISABLE_SLOT]);
158910923SEvan.Yan@Sun.COM 	cfga_msg(msgp, cfga_strs[HELP_ENABLE_AUTOCONF]);
159010923SEvan.Yan@Sun.COM 	cfga_msg(msgp, cfga_strs[HELP_DISABLE_AUTOCONF]);
159110923SEvan.Yan@Sun.COM 	cfga_msg(msgp, cfga_strs[HELP_LED_CNTRL]);
159210923SEvan.Yan@Sun.COM 	return (CFGA_OK);
159310923SEvan.Yan@Sun.COM }
159410923SEvan.Yan@Sun.COM 
159510923SEvan.Yan@Sun.COM /*
159610923SEvan.Yan@Sun.COM  * cfga_err() accepts a variable number of message IDs and constructs
159710923SEvan.Yan@Sun.COM  * a corresponding error string which is returned via the errstring argument.
159810923SEvan.Yan@Sun.COM  * cfga_err() calls gettext() to internationalize proper messages.
159910923SEvan.Yan@Sun.COM  */
160010923SEvan.Yan@Sun.COM static void
cfga_err(char ** errstring,...)160110923SEvan.Yan@Sun.COM cfga_err(char **errstring, ...)
160210923SEvan.Yan@Sun.COM {
160310923SEvan.Yan@Sun.COM 	int a;
160410923SEvan.Yan@Sun.COM 	int i;
160510923SEvan.Yan@Sun.COM 	int n;
160610923SEvan.Yan@Sun.COM 	int len;
160710923SEvan.Yan@Sun.COM 	int flen;
160810923SEvan.Yan@Sun.COM 	char *p;
160910923SEvan.Yan@Sun.COM 	char *q;
161010923SEvan.Yan@Sun.COM 	char *s[32];
161110923SEvan.Yan@Sun.COM 	char *failed;
161210923SEvan.Yan@Sun.COM 	va_list ap;
161310923SEvan.Yan@Sun.COM 
161410923SEvan.Yan@Sun.COM 	/*
161510923SEvan.Yan@Sun.COM 	 * If errstring is null it means user is not interested in getting
161610923SEvan.Yan@Sun.COM 	 * error status. So we don't do all the work
161710923SEvan.Yan@Sun.COM 	 */
161810923SEvan.Yan@Sun.COM 	if (errstring == NULL) {
161910923SEvan.Yan@Sun.COM 		return;
162010923SEvan.Yan@Sun.COM 	}
162110923SEvan.Yan@Sun.COM 	va_start(ap, errstring);
162210923SEvan.Yan@Sun.COM 
162310923SEvan.Yan@Sun.COM 	failed = dgettext(TEXT_DOMAIN, cfga_strs[FAILED]);
162410923SEvan.Yan@Sun.COM 	flen = strlen(failed);
162510923SEvan.Yan@Sun.COM 
162610923SEvan.Yan@Sun.COM 	for (n = len = 0; (a = va_arg(ap, int)) != 0; n++) {
162710923SEvan.Yan@Sun.COM 		switch (a) {
162810923SEvan.Yan@Sun.COM 		case CMD_GETSTAT:
162910923SEvan.Yan@Sun.COM 		case CMD_LIST:
163010923SEvan.Yan@Sun.COM 		case CMD_SLOT_CONNECT:
163110923SEvan.Yan@Sun.COM 		case CMD_SLOT_DISCONNECT:
163210923SEvan.Yan@Sun.COM 		case CMD_SLOT_CONFIGURE:
163310923SEvan.Yan@Sun.COM 		case CMD_SLOT_UNCONFIGURE:
163410923SEvan.Yan@Sun.COM 			p =  cfga_errstrs(a);
163510923SEvan.Yan@Sun.COM 			len += (strlen(p) + flen);
163610923SEvan.Yan@Sun.COM 			s[n] = p;
163710923SEvan.Yan@Sun.COM 			s[++n] = cfga_strs[FAILED];
163810923SEvan.Yan@Sun.COM 
163910923SEvan.Yan@Sun.COM 			DBG(2, ("<%s>", p));
164010923SEvan.Yan@Sun.COM 			DBG(2, (cfga_strs[FAILED]));
164110923SEvan.Yan@Sun.COM 			break;
164210923SEvan.Yan@Sun.COM 
164310923SEvan.Yan@Sun.COM 		case ERR_CMD_INVAL:
164410923SEvan.Yan@Sun.COM 		case ERR_AP_INVAL:
164510923SEvan.Yan@Sun.COM 		case ERR_OPT_INVAL:
164610923SEvan.Yan@Sun.COM 		case ERR_AP_ERR:
164710923SEvan.Yan@Sun.COM 			switch (a) {
164810923SEvan.Yan@Sun.COM 			case ERR_CMD_INVAL:
164910923SEvan.Yan@Sun.COM 				p = dgettext(TEXT_DOMAIN,
165010923SEvan.Yan@Sun.COM 				    cfga_errstrs[ERR_CMD_INVAL]);
165110923SEvan.Yan@Sun.COM 				break;
165210923SEvan.Yan@Sun.COM 			case ERR_AP_INVAL:
165310923SEvan.Yan@Sun.COM 				p = dgettext(TEXT_DOMAIN,
165410923SEvan.Yan@Sun.COM 				    cfga_errstrs[ERR_AP_INVAL]);
165510923SEvan.Yan@Sun.COM 				break;
165610923SEvan.Yan@Sun.COM 			case ERR_OPT_INVAL:
165710923SEvan.Yan@Sun.COM 				p = dgettext(TEXT_DOMAIN,
165810923SEvan.Yan@Sun.COM 				    cfga_errstrs[ERR_OPT_INVAL]);
165910923SEvan.Yan@Sun.COM 				break;
166010923SEvan.Yan@Sun.COM 			case ERR_AP_ERR:
166110923SEvan.Yan@Sun.COM 				p = dgettext(TEXT_DOMAIN,
166210923SEvan.Yan@Sun.COM 				    cfga_errstrs[ERR_AP_ERR]);
166310923SEvan.Yan@Sun.COM 				break;
166410923SEvan.Yan@Sun.COM 			}
166510923SEvan.Yan@Sun.COM 
166610923SEvan.Yan@Sun.COM 			if ((q = va_arg(ap, char *)) != NULL) {
166710923SEvan.Yan@Sun.COM 				len += (strlen(p) + strlen(q));
166810923SEvan.Yan@Sun.COM 				s[n] = p;
166910923SEvan.Yan@Sun.COM 				s[++n] = q;
167010923SEvan.Yan@Sun.COM 				DBG(2, ("<%s>", p));
167110923SEvan.Yan@Sun.COM 				DBG(2, ("<%s>", q));
167210923SEvan.Yan@Sun.COM 				break;
167310923SEvan.Yan@Sun.COM 			} else {
167410923SEvan.Yan@Sun.COM 				len += strlen(p);
167510923SEvan.Yan@Sun.COM 				s[n] = p;
167610923SEvan.Yan@Sun.COM 
167710923SEvan.Yan@Sun.COM 			}
167810923SEvan.Yan@Sun.COM 			DBG(2, ("<%s>", p));
167910923SEvan.Yan@Sun.COM 			break;
168010923SEvan.Yan@Sun.COM 
168110923SEvan.Yan@Sun.COM 		default:
168210923SEvan.Yan@Sun.COM 			n--;
168310923SEvan.Yan@Sun.COM 			break;
168410923SEvan.Yan@Sun.COM 		}
168510923SEvan.Yan@Sun.COM 	}
168610923SEvan.Yan@Sun.COM 
168710923SEvan.Yan@Sun.COM 	DBG(2, ("\n"));
168810923SEvan.Yan@Sun.COM 	va_end(ap);
168910923SEvan.Yan@Sun.COM 
169010923SEvan.Yan@Sun.COM 	if ((p = calloc(len + 1, 1)) == NULL)
169110923SEvan.Yan@Sun.COM 		return;
169210923SEvan.Yan@Sun.COM 
169310923SEvan.Yan@Sun.COM 	for (i = 0; i < n; i++) {
169410923SEvan.Yan@Sun.COM 		(void) strlcat(p, s[i], len + 1);
169510923SEvan.Yan@Sun.COM 		DBG(2, ("i:%d, %s\n", i, s[i]));
169610923SEvan.Yan@Sun.COM 	}
169710923SEvan.Yan@Sun.COM 
169810923SEvan.Yan@Sun.COM 	*errstring = p;
169910923SEvan.Yan@Sun.COM 	DBG(2, ("%s\n", *errstring));
170010923SEvan.Yan@Sun.COM }
170110923SEvan.Yan@Sun.COM 
170210923SEvan.Yan@Sun.COM /*
170310923SEvan.Yan@Sun.COM  * cfga_ap_id_cmp -- use default_ap_id_cmp() in libcfgadm
170410923SEvan.Yan@Sun.COM  */
1705