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