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 /* 23*12555SScott.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 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 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 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 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 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 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 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; 62110923SEvan.Yan@Sun.COM hp_node_t node; 62210923SEvan.Yan@Sun.COM hp_node_t results = NULL; 62310923SEvan.Yan@Sun.COM 62410923SEvan.Yan@Sun.COM if ((rv = check_options(options)) != CFGA_OK) { 62510923SEvan.Yan@Sun.COM return (rv); 62610923SEvan.Yan@Sun.COM } 62710923SEvan.Yan@Sun.COM 62810923SEvan.Yan@Sun.COM if (errstring != NULL) 62910923SEvan.Yan@Sun.COM *errstring = NULL; 63010923SEvan.Yan@Sun.COM 63110923SEvan.Yan@Sun.COM rv = CFGA_OK; 63210923SEvan.Yan@Sun.COM DBG(1, ("cfga_change_state:(%s)\n", ap_id)); 63310923SEvan.Yan@Sun.COM 63410923SEvan.Yan@Sun.COM rv = physpath2node(ap_id, errstring, &node); 63510923SEvan.Yan@Sun.COM if (rv != CFGA_OK) 63610923SEvan.Yan@Sun.COM return (rv); 63710923SEvan.Yan@Sun.COM 63810923SEvan.Yan@Sun.COM state = hp_state(node); 63910923SEvan.Yan@Sun.COM 64010923SEvan.Yan@Sun.COM /* 64110923SEvan.Yan@Sun.COM * Which state should we drive to ? 64210923SEvan.Yan@Sun.COM */ 64310923SEvan.Yan@Sun.COM if ((state_change_cmd != CFGA_CMD_LOAD) && 64410923SEvan.Yan@Sun.COM (state_change_cmd != CFGA_CMD_UNLOAD)) { 64510923SEvan.Yan@Sun.COM if (cfga_target_state(state_change_cmd, 64610923SEvan.Yan@Sun.COM &new_state) != CFGA_OK) { 64710923SEvan.Yan@Sun.COM hp_fini(node); 64810923SEvan.Yan@Sun.COM return (CFGA_ERROR); 64910923SEvan.Yan@Sun.COM } 65010923SEvan.Yan@Sun.COM } 65110923SEvan.Yan@Sun.COM 65210923SEvan.Yan@Sun.COM DBG(1, ("cfga_change_state: state is %d\n", state)); 65310923SEvan.Yan@Sun.COM switch (state_change_cmd) { 65410923SEvan.Yan@Sun.COM case CFGA_CMD_CONNECT: 655*12555SScott.Carter@Oracle.COM DBG(1, ("connect\n")); 656*12555SScott.Carter@Oracle.COM if (state == DDI_HP_CN_STATE_EMPTY) { 65710923SEvan.Yan@Sun.COM cfga_err(errstring, ERR_AP_ERR, 0); 65810923SEvan.Yan@Sun.COM rv = CFGA_INVAL; 659*12555SScott.Carter@Oracle.COM } else if (state == DDI_HP_CN_STATE_PRESENT) { 660*12555SScott.Carter@Oracle.COM /* Connect the slot */ 66110923SEvan.Yan@Sun.COM if (hp_set_state(node, 0, new_state, &results) != 0) { 66210923SEvan.Yan@Sun.COM rv = CFGA_ERROR; 66310923SEvan.Yan@Sun.COM cfga_err(errstring, CMD_SLOT_CONNECT, 0); 66410923SEvan.Yan@Sun.COM } 66510923SEvan.Yan@Sun.COM } 66610923SEvan.Yan@Sun.COM break; 66710923SEvan.Yan@Sun.COM 66810923SEvan.Yan@Sun.COM case CFGA_CMD_DISCONNECT: 66910923SEvan.Yan@Sun.COM DBG(1, ("disconnect\n")); 670*12555SScott.Carter@Oracle.COM if (state == DDI_HP_CN_STATE_EMPTY) { 67110923SEvan.Yan@Sun.COM cfga_err(errstring, ERR_AP_ERR, 0); 67210923SEvan.Yan@Sun.COM rv = CFGA_INVAL; 673*12555SScott.Carter@Oracle.COM } else if (state > DDI_HP_CN_STATE_PRESENT) { 674*12555SScott.Carter@Oracle.COM /* Disconnect the slot */ 67510923SEvan.Yan@Sun.COM if ((rv = hp_set_state(node, 0, new_state, &results)) 67610923SEvan.Yan@Sun.COM != 0) { 67710923SEvan.Yan@Sun.COM if (rv == EBUSY) 67810923SEvan.Yan@Sun.COM rv = CFGA_BUSY; 67910923SEvan.Yan@Sun.COM else 68010923SEvan.Yan@Sun.COM rv = CFGA_ERROR; 68110923SEvan.Yan@Sun.COM 68210923SEvan.Yan@Sun.COM if (results) { 68310923SEvan.Yan@Sun.COM pci_rcm_info_table(results, errstring); 68410923SEvan.Yan@Sun.COM hp_fini(results); 68510923SEvan.Yan@Sun.COM } else { 68610923SEvan.Yan@Sun.COM cfga_err(errstring, 68710923SEvan.Yan@Sun.COM CMD_SLOT_DISCONNECT, 0); 68810923SEvan.Yan@Sun.COM } 68910923SEvan.Yan@Sun.COM } 69010923SEvan.Yan@Sun.COM } 69110923SEvan.Yan@Sun.COM break; 69210923SEvan.Yan@Sun.COM 69310923SEvan.Yan@Sun.COM case CFGA_CMD_CONFIGURE: 69410923SEvan.Yan@Sun.COM /* 69510923SEvan.Yan@Sun.COM * for multi-func device we allow multiple 69610923SEvan.Yan@Sun.COM * configure on the same slot because one 69710923SEvan.Yan@Sun.COM * func can be configured and other one won't 69810923SEvan.Yan@Sun.COM */ 699*12555SScott.Carter@Oracle.COM DBG(1, ("configure\n")); 700*12555SScott.Carter@Oracle.COM if (state == DDI_HP_CN_STATE_EMPTY) { 701*12555SScott.Carter@Oracle.COM cfga_err(errstring, ERR_AP_ERR, 0); 702*12555SScott.Carter@Oracle.COM rv = CFGA_INVAL; 703*12555SScott.Carter@Oracle.COM } else if (hp_set_state(node, 0, new_state, &results) != 0) { 70410923SEvan.Yan@Sun.COM rv = CFGA_ERROR; 70510923SEvan.Yan@Sun.COM cfga_err(errstring, CMD_SLOT_CONFIGURE, 0); 70610923SEvan.Yan@Sun.COM } 70710923SEvan.Yan@Sun.COM break; 70810923SEvan.Yan@Sun.COM 70910923SEvan.Yan@Sun.COM case CFGA_CMD_UNCONFIGURE: 71010923SEvan.Yan@Sun.COM DBG(1, ("unconfigure\n")); 711*12555SScott.Carter@Oracle.COM if (state == DDI_HP_CN_STATE_EMPTY) { 712*12555SScott.Carter@Oracle.COM cfga_err(errstring, ERR_AP_ERR, 0); 713*12555SScott.Carter@Oracle.COM rv = CFGA_INVAL; 714*12555SScott.Carter@Oracle.COM } else if (state >= DDI_HP_CN_STATE_ENABLED) { 71510923SEvan.Yan@Sun.COM if ((rv = hp_set_state(node, 0, new_state, &results)) 71610923SEvan.Yan@Sun.COM != 0) { 71710923SEvan.Yan@Sun.COM if (rv == EBUSY) 71810923SEvan.Yan@Sun.COM rv = CFGA_BUSY; 71910923SEvan.Yan@Sun.COM else 72010923SEvan.Yan@Sun.COM rv = CFGA_ERROR; 72110923SEvan.Yan@Sun.COM 72210923SEvan.Yan@Sun.COM if (results) { 72310923SEvan.Yan@Sun.COM pci_rcm_info_table(results, errstring); 72410923SEvan.Yan@Sun.COM hp_fini(results); 72510923SEvan.Yan@Sun.COM } else { 72610923SEvan.Yan@Sun.COM cfga_err(errstring, 72710923SEvan.Yan@Sun.COM CMD_SLOT_UNCONFIGURE, 0); 72810923SEvan.Yan@Sun.COM } 72910923SEvan.Yan@Sun.COM } 73010923SEvan.Yan@Sun.COM } 73110923SEvan.Yan@Sun.COM DBG(1, ("unconfigure rv:(%i)\n", rv)); 73210923SEvan.Yan@Sun.COM break; 73310923SEvan.Yan@Sun.COM 73410923SEvan.Yan@Sun.COM case CFGA_CMD_LOAD: 73510923SEvan.Yan@Sun.COM /* do nothing, just produce error msg as is */ 73610923SEvan.Yan@Sun.COM if (state < DDI_HP_CN_STATE_POWERED) { 73710923SEvan.Yan@Sun.COM rv = CFGA_ERROR; 73810923SEvan.Yan@Sun.COM cfga_err(errstring, CMD_SLOT_INSERT, 0); 73910923SEvan.Yan@Sun.COM } else { 74010923SEvan.Yan@Sun.COM cfga_err(errstring, ERR_AP_ERR, 0); 74110923SEvan.Yan@Sun.COM rv = CFGA_INVAL; 74210923SEvan.Yan@Sun.COM } 74310923SEvan.Yan@Sun.COM break; 74410923SEvan.Yan@Sun.COM 74510923SEvan.Yan@Sun.COM case CFGA_CMD_UNLOAD: 74610923SEvan.Yan@Sun.COM /* do nothing, just produce error msg as is */ 74710923SEvan.Yan@Sun.COM if (state < DDI_HP_CN_STATE_POWERED) { 74810923SEvan.Yan@Sun.COM rv = CFGA_ERROR; 74910923SEvan.Yan@Sun.COM cfga_err(errstring, CMD_SLOT_REMOVE, 0); 75010923SEvan.Yan@Sun.COM } else { 75110923SEvan.Yan@Sun.COM cfga_err(errstring, ERR_AP_ERR, 0); 75210923SEvan.Yan@Sun.COM rv = CFGA_INVAL; 75310923SEvan.Yan@Sun.COM } 75410923SEvan.Yan@Sun.COM break; 75510923SEvan.Yan@Sun.COM 75610923SEvan.Yan@Sun.COM default: 75710923SEvan.Yan@Sun.COM rv = CFGA_OPNOTSUPP; 75810923SEvan.Yan@Sun.COM break; 75910923SEvan.Yan@Sun.COM } 76010923SEvan.Yan@Sun.COM 76110923SEvan.Yan@Sun.COM hp_fini(node); 76210923SEvan.Yan@Sun.COM return (rv); 76310923SEvan.Yan@Sun.COM } 76410923SEvan.Yan@Sun.COM 76510923SEvan.Yan@Sun.COM char * 76610923SEvan.Yan@Sun.COM get_val_from_result(char *result) 76710923SEvan.Yan@Sun.COM { 76810923SEvan.Yan@Sun.COM char *tmp; 76910923SEvan.Yan@Sun.COM 77010923SEvan.Yan@Sun.COM tmp = strchr(result, '='); 77110923SEvan.Yan@Sun.COM if (tmp == NULL) 77210923SEvan.Yan@Sun.COM return (NULL); 77310923SEvan.Yan@Sun.COM 77410923SEvan.Yan@Sun.COM tmp++; 77510923SEvan.Yan@Sun.COM return (tmp); 77610923SEvan.Yan@Sun.COM } 77710923SEvan.Yan@Sun.COM 77810923SEvan.Yan@Sun.COM static cfga_err_t 77910923SEvan.Yan@Sun.COM prt_led_mode(const char *ap_id, int repeat, char **errstring, 78010923SEvan.Yan@Sun.COM struct cfga_msg *msgp) 78110923SEvan.Yan@Sun.COM { 78210923SEvan.Yan@Sun.COM pciehpc_led_t led; 78310923SEvan.Yan@Sun.COM hp_node_t node; 78410923SEvan.Yan@Sun.COM char *buff; 78510923SEvan.Yan@Sun.COM char *buf; 78610923SEvan.Yan@Sun.COM char *cp, line[MAXLINE]; 78710923SEvan.Yan@Sun.COM char *tmp; 78810923SEvan.Yan@Sun.COM char *format; 78910923SEvan.Yan@Sun.COM char *result; 79010923SEvan.Yan@Sun.COM int i, n, rv; 79110923SEvan.Yan@Sun.COM int len = MAXLINE; 79210923SEvan.Yan@Sun.COM 79310923SEvan.Yan@Sun.COM pciehpc_led_t states[] = { 79410923SEvan.Yan@Sun.COM PCIEHPC_POWER_LED, 79510923SEvan.Yan@Sun.COM PCIEHPC_FAULT_LED, 79610923SEvan.Yan@Sun.COM PCIEHPC_ATTN_LED, 79710923SEvan.Yan@Sun.COM PCIEHPC_ACTIVE_LED 79810923SEvan.Yan@Sun.COM }; 79910923SEvan.Yan@Sun.COM 80010923SEvan.Yan@Sun.COM DBG(1, ("prt_led_mod function\n")); 80110923SEvan.Yan@Sun.COM if (!repeat) 80210923SEvan.Yan@Sun.COM cfga_msg(msgp, "Ap_Id\t\t\tLed"); 80310923SEvan.Yan@Sun.COM 80410923SEvan.Yan@Sun.COM rv = physpath2node(ap_id, errstring, &node); 80510923SEvan.Yan@Sun.COM if (rv != CFGA_OK) 80610923SEvan.Yan@Sun.COM return (rv); 80710923SEvan.Yan@Sun.COM 80810923SEvan.Yan@Sun.COM if ((buff = malloc(MAXPATHLEN)) == NULL) { 80910923SEvan.Yan@Sun.COM hp_fini(node); 81010923SEvan.Yan@Sun.COM cfga_err(errstring, "malloc ", 0); 81110923SEvan.Yan@Sun.COM return (CFGA_ERROR); 81210923SEvan.Yan@Sun.COM } 81310923SEvan.Yan@Sun.COM 81410923SEvan.Yan@Sun.COM (void) memset(buff, 0, MAXPATHLEN); 81510923SEvan.Yan@Sun.COM 81610923SEvan.Yan@Sun.COM if (fix_ap_name(buff, ap_id, hp_name(node), 81710923SEvan.Yan@Sun.COM errstring) != CFGA_OK) { 81810923SEvan.Yan@Sun.COM hp_fini(node); 81910923SEvan.Yan@Sun.COM free(buff); 82010923SEvan.Yan@Sun.COM return (CFGA_ERROR); 82110923SEvan.Yan@Sun.COM } 82210923SEvan.Yan@Sun.COM 82310923SEvan.Yan@Sun.COM cp = line; 82410923SEvan.Yan@Sun.COM (void) snprintf(cp, len, "%s\t\t", buff); 82510923SEvan.Yan@Sun.COM len -= strlen(cp); 82610923SEvan.Yan@Sun.COM cp += strlen(cp); 82710923SEvan.Yan@Sun.COM 82810923SEvan.Yan@Sun.COM free(buff); 82910923SEvan.Yan@Sun.COM 83010923SEvan.Yan@Sun.COM n = sizeof (states)/sizeof (pciehpc_led_t); 83110923SEvan.Yan@Sun.COM for (i = 0; i < n; i++) { 83210923SEvan.Yan@Sun.COM led = states[i]; 83310923SEvan.Yan@Sun.COM 83410923SEvan.Yan@Sun.COM format = (i == n - 1) ? "%s=%s" : "%s=%s,"; 83510923SEvan.Yan@Sun.COM if (hp_get_private(node, led_strs2[led], &result) != 0) { 83610923SEvan.Yan@Sun.COM (void) snprintf(cp, len, format, 83710923SEvan.Yan@Sun.COM led_strs[led], cfga_strs[UNKNOWN]); 83810923SEvan.Yan@Sun.COM len -= strlen(cp); 83910923SEvan.Yan@Sun.COM cp += strlen(cp); 84010923SEvan.Yan@Sun.COM DBG(1, ("%s:%s\n", led_strs[led], cfga_strs[UNKNOWN])); 84110923SEvan.Yan@Sun.COM } else { 84210923SEvan.Yan@Sun.COM /* 84310923SEvan.Yan@Sun.COM * hp_get_private() will return back things like 84410923SEvan.Yan@Sun.COM * "led_fault=off", transform it to cfgadm desired 84510923SEvan.Yan@Sun.COM * format. 84610923SEvan.Yan@Sun.COM */ 84710923SEvan.Yan@Sun.COM tmp = get_val_from_result(result); 84810923SEvan.Yan@Sun.COM if (tmp == NULL) { 84910923SEvan.Yan@Sun.COM free(result); 85010923SEvan.Yan@Sun.COM hp_fini(node); 85110923SEvan.Yan@Sun.COM return (CFGA_ERROR); 85210923SEvan.Yan@Sun.COM } 85310923SEvan.Yan@Sun.COM 85410923SEvan.Yan@Sun.COM (void) snprintf(cp, len, format, 85510923SEvan.Yan@Sun.COM led_strs[led], tmp); 85610923SEvan.Yan@Sun.COM len -= strlen(cp); 85710923SEvan.Yan@Sun.COM cp += strlen(cp); 85810923SEvan.Yan@Sun.COM DBG(1, ("%s:%s\n", led_strs[led], tmp)); 85910923SEvan.Yan@Sun.COM free(result); 86010923SEvan.Yan@Sun.COM } 86110923SEvan.Yan@Sun.COM } 86210923SEvan.Yan@Sun.COM 86310923SEvan.Yan@Sun.COM cfga_msg(msgp, line); /* print the message */ 86410923SEvan.Yan@Sun.COM 86510923SEvan.Yan@Sun.COM hp_fini(node); 86610923SEvan.Yan@Sun.COM 86710923SEvan.Yan@Sun.COM return (CFGA_OK); 86810923SEvan.Yan@Sun.COM } 86910923SEvan.Yan@Sun.COM 87010923SEvan.Yan@Sun.COM /*ARGSUSED*/ 87110923SEvan.Yan@Sun.COM cfga_err_t 87210923SEvan.Yan@Sun.COM cfga_private_func(const char *function, const char *ap_id, 87310923SEvan.Yan@Sun.COM const char *options, struct cfga_confirm *confp, 87410923SEvan.Yan@Sun.COM struct cfga_msg *msgp, char **errstring, cfga_flags_t flags) 87510923SEvan.Yan@Sun.COM { 87610923SEvan.Yan@Sun.COM char *str; 87710923SEvan.Yan@Sun.COM int len, fd, i = 0, repeat = 0; 87810923SEvan.Yan@Sun.COM char buf[MAXNAMELEN]; 87910923SEvan.Yan@Sun.COM char ptr; 88010923SEvan.Yan@Sun.COM cfga_err_t rv; 88110923SEvan.Yan@Sun.COM char *led, *mode; 88210923SEvan.Yan@Sun.COM hp_node_t node; 88310923SEvan.Yan@Sun.COM char *result; 88410923SEvan.Yan@Sun.COM 88510923SEvan.Yan@Sun.COM DBG(1, ("cfgadm_private_func: ap_id:%s\n", ap_id)); 88610923SEvan.Yan@Sun.COM DBG(2, (" options: %s\n", (options == NULL)?"null":options)); 88710923SEvan.Yan@Sun.COM DBG(2, (" confp: %x\n", confp)); 88810923SEvan.Yan@Sun.COM DBG(2, (" cfga_msg: %x\n", cfga_msg)); 88910923SEvan.Yan@Sun.COM DBG(2, (" flag: %d\n", flags)); 89010923SEvan.Yan@Sun.COM 89110923SEvan.Yan@Sun.COM if ((rv = check_options(options)) != CFGA_OK) { 89210923SEvan.Yan@Sun.COM return (rv); 89310923SEvan.Yan@Sun.COM } 89410923SEvan.Yan@Sun.COM 89510923SEvan.Yan@Sun.COM if (private_check == confp) 89610923SEvan.Yan@Sun.COM repeat = 1; 89710923SEvan.Yan@Sun.COM else 89810923SEvan.Yan@Sun.COM private_check = (void*)confp; 89910923SEvan.Yan@Sun.COM 90010923SEvan.Yan@Sun.COM for (i = 0, str = func_strs[i], len = strlen(str); 90110923SEvan.Yan@Sun.COM func_strs[i] != NULL; i++) { 90210923SEvan.Yan@Sun.COM str = func_strs[i]; 90310923SEvan.Yan@Sun.COM len = strlen(str); 90410923SEvan.Yan@Sun.COM if (strncmp(function, str, len) == 0) 90510923SEvan.Yan@Sun.COM break; 90610923SEvan.Yan@Sun.COM } 90710923SEvan.Yan@Sun.COM 90810923SEvan.Yan@Sun.COM switch (i) { 90910923SEvan.Yan@Sun.COM case ENABLE_SLOT: 91010923SEvan.Yan@Sun.COM case DISABLE_SLOT: 91110923SEvan.Yan@Sun.COM /* pass through */ 91210923SEvan.Yan@Sun.COM case ENABLE_AUTOCNF: 91310923SEvan.Yan@Sun.COM case DISABLE_AUTOCNF: 91410923SEvan.Yan@Sun.COM /* no action needed */ 91510923SEvan.Yan@Sun.COM return (CFGA_OK); 91610923SEvan.Yan@Sun.COM break; 91710923SEvan.Yan@Sun.COM case LED: 91810923SEvan.Yan@Sun.COM /* set mode */ 91910923SEvan.Yan@Sun.COM ptr = function[len++]; 92010923SEvan.Yan@Sun.COM if (ptr == '=') { 92110923SEvan.Yan@Sun.COM str = (char *)function; 92210923SEvan.Yan@Sun.COM for (str = (str+len++), i = 0; *str != ','; 92310923SEvan.Yan@Sun.COM i++, str++) { 92410923SEvan.Yan@Sun.COM if (i == (MAXNAMELEN - 1)) 92510923SEvan.Yan@Sun.COM break; 92610923SEvan.Yan@Sun.COM 92710923SEvan.Yan@Sun.COM buf[i] = *str; 92810923SEvan.Yan@Sun.COM DBG_F(2, (stdout, "%c\n", buf[i])); 92910923SEvan.Yan@Sun.COM } 93010923SEvan.Yan@Sun.COM buf[i] = '\0'; str++; 93110923SEvan.Yan@Sun.COM DBG(2, ("buf = %s\n", buf)); 93210923SEvan.Yan@Sun.COM 93310923SEvan.Yan@Sun.COM /* ACTIVE=3,ATTN=2,POWER=1,FAULT=0 */ 93410923SEvan.Yan@Sun.COM if (strcmp(buf, led_strs[POWER]) == 0) 93510923SEvan.Yan@Sun.COM led = PCIEHPC_PROP_LED_POWER; 93610923SEvan.Yan@Sun.COM else if (strcmp(buf, led_strs[FAULT]) == 0) 93710923SEvan.Yan@Sun.COM led = PCIEHPC_PROP_LED_FAULT; 93810923SEvan.Yan@Sun.COM else if (strcmp(buf, led_strs[ATTN]) == 0) 93910923SEvan.Yan@Sun.COM led = PCIEHPC_PROP_LED_ATTN; 94010923SEvan.Yan@Sun.COM else if (strcmp(buf, led_strs[ACTIVE]) == 0) 94110923SEvan.Yan@Sun.COM led = PCIEHPC_PROP_LED_ACTIVE; 94210923SEvan.Yan@Sun.COM else return (CFGA_INVAL); 94310923SEvan.Yan@Sun.COM 94410923SEvan.Yan@Sun.COM len = strlen(func_strs[MODE]); 94510923SEvan.Yan@Sun.COM if ((strncmp(str, func_strs[MODE], len) == 0) && 94610923SEvan.Yan@Sun.COM (*(str+(len)) == '=')) { 94710923SEvan.Yan@Sun.COM for (str = (str+(++len)), i = 0; 94810923SEvan.Yan@Sun.COM *str != NULL; i++, str++) { 94910923SEvan.Yan@Sun.COM buf[i] = *str; 95010923SEvan.Yan@Sun.COM } 95110923SEvan.Yan@Sun.COM } 95210923SEvan.Yan@Sun.COM buf[i] = '\0'; 95310923SEvan.Yan@Sun.COM DBG(2, ("buf_mode= %s\n", buf)); 95410923SEvan.Yan@Sun.COM 95510923SEvan.Yan@Sun.COM /* ON = 1, OFF = 0 */ 95610923SEvan.Yan@Sun.COM if (strcmp(buf, mode_strs[ON]) == 0) 95710923SEvan.Yan@Sun.COM mode = PCIEHPC_PROP_VALUE_ON; 95810923SEvan.Yan@Sun.COM else if (strcmp(buf, mode_strs[OFF]) == 0) 95910923SEvan.Yan@Sun.COM mode = PCIEHPC_PROP_VALUE_OFF; 96010923SEvan.Yan@Sun.COM else if (strcmp(buf, mode_strs[BLINK]) == 0) 96110923SEvan.Yan@Sun.COM mode = PCIEHPC_PROP_VALUE_BLINK; 96210923SEvan.Yan@Sun.COM else return (CFGA_INVAL); 96310923SEvan.Yan@Sun.COM 96410923SEvan.Yan@Sun.COM /* sendin */ 96510923SEvan.Yan@Sun.COM memset(buf, 0, sizeof (buf)); 96610923SEvan.Yan@Sun.COM snprintf(buf, sizeof (buf), "%s=%s", 96710923SEvan.Yan@Sun.COM led, mode); 96810923SEvan.Yan@Sun.COM buf[MAXNAMELEN - 1] = '\0'; 96910923SEvan.Yan@Sun.COM 97010923SEvan.Yan@Sun.COM break; 97110923SEvan.Yan@Sun.COM } else if (ptr == '\0') { 97210923SEvan.Yan@Sun.COM /* print mode */ 97310923SEvan.Yan@Sun.COM DBG(1, ("Print mode\n")); 97410923SEvan.Yan@Sun.COM return (prt_led_mode(ap_id, repeat, errstring, 97510923SEvan.Yan@Sun.COM msgp)); 97610923SEvan.Yan@Sun.COM } 97710923SEvan.Yan@Sun.COM default: 97810923SEvan.Yan@Sun.COM DBG(1, ("default\n")); 97910923SEvan.Yan@Sun.COM errno = EINVAL; 98010923SEvan.Yan@Sun.COM return (CFGA_INVAL); 98110923SEvan.Yan@Sun.COM } 98210923SEvan.Yan@Sun.COM 98310923SEvan.Yan@Sun.COM rv = physpath2node(ap_id, errstring, &node); 98410923SEvan.Yan@Sun.COM if (rv != CFGA_OK) 98510923SEvan.Yan@Sun.COM return (rv); 98610923SEvan.Yan@Sun.COM 98710923SEvan.Yan@Sun.COM if (hp_set_private(node, buf, &result) != 0) { 98810923SEvan.Yan@Sun.COM hp_fini(node); 98910923SEvan.Yan@Sun.COM return (CFGA_ERROR); 99010923SEvan.Yan@Sun.COM } 99110923SEvan.Yan@Sun.COM 99210923SEvan.Yan@Sun.COM hp_fini(node); 99310923SEvan.Yan@Sun.COM return (CFGA_OK); 99410923SEvan.Yan@Sun.COM } 99510923SEvan.Yan@Sun.COM 99610923SEvan.Yan@Sun.COM /*ARGSUSED*/ 99710923SEvan.Yan@Sun.COM cfga_err_t cfga_test(const char *ap_id, const char *options, 99810923SEvan.Yan@Sun.COM struct cfga_msg *msgp, char **errstring, cfga_flags_t flags) 99910923SEvan.Yan@Sun.COM { 100010923SEvan.Yan@Sun.COM cfga_err_t rv; 100110923SEvan.Yan@Sun.COM if (errstring != NULL) 100210923SEvan.Yan@Sun.COM *errstring = NULL; 100310923SEvan.Yan@Sun.COM 100410923SEvan.Yan@Sun.COM if ((rv = check_options(options)) != CFGA_OK) { 100510923SEvan.Yan@Sun.COM return (rv); 100610923SEvan.Yan@Sun.COM } 100710923SEvan.Yan@Sun.COM 100810923SEvan.Yan@Sun.COM DBG(1, ("cfga_test:(%s)\n", ap_id)); 100910923SEvan.Yan@Sun.COM /* will need to implement pci CTRL command */ 101010923SEvan.Yan@Sun.COM return (CFGA_NOTSUPP); 101110923SEvan.Yan@Sun.COM } 101210923SEvan.Yan@Sun.COM 101310923SEvan.Yan@Sun.COM /* 101410923SEvan.Yan@Sun.COM * The slot-names property describes the external labeling of add-in slots. 101510923SEvan.Yan@Sun.COM * This property is an encoded array, an integer followed by a list of 101610923SEvan.Yan@Sun.COM * strings. The return value from di_prop_lookup_ints for slot-names is -1. 101710923SEvan.Yan@Sun.COM * The expected return value should be the number of elements. 101810923SEvan.Yan@Sun.COM * Di_prop_decode_common does not decode encoded data from software, 101910923SEvan.Yan@Sun.COM * such as the solaris device tree, unlike from the prom. 102010923SEvan.Yan@Sun.COM * Di_prop_decode_common takes the size of the encoded data and mods 102110923SEvan.Yan@Sun.COM * it with the size of int. The size of the encoded data for slot-names is 9 102210923SEvan.Yan@Sun.COM * and the size of int is 4, yielding a non zero result. A value of -1 is used 102310923SEvan.Yan@Sun.COM * to indicate that the number of elements can not be determined. 102410923SEvan.Yan@Sun.COM * Di_prop_decode_common can be modified to decode encoded data from the solaris 102510923SEvan.Yan@Sun.COM * device tree. 102610923SEvan.Yan@Sun.COM */ 102710923SEvan.Yan@Sun.COM static int 102810923SEvan.Yan@Sun.COM fixup_slotname(int rval, int *intp, struct searcharg *slotarg) 102910923SEvan.Yan@Sun.COM { 103010923SEvan.Yan@Sun.COM if ((slotarg->slt_name_src == PROM_SLT_NAME) && (rval == -1)) { 103110923SEvan.Yan@Sun.COM return (DI_WALK_TERMINATE); 103210923SEvan.Yan@Sun.COM } else { 103310923SEvan.Yan@Sun.COM int i; 103410923SEvan.Yan@Sun.COM char *tmptr = (char *)(intp+1); 103510923SEvan.Yan@Sun.COM DBG(1, ("slot-bitmask: %x \n", *intp)); 103610923SEvan.Yan@Sun.COM 103710923SEvan.Yan@Sun.COM rval = (rval -1) * 4; 103810923SEvan.Yan@Sun.COM 103910923SEvan.Yan@Sun.COM for (i = 0; i <= slotarg->minor; i++) { 104010923SEvan.Yan@Sun.COM DBG(2, ("curr slot-name: %s \n", tmptr)); 104110923SEvan.Yan@Sun.COM 104210923SEvan.Yan@Sun.COM if (i >= MAXDEVS) 104310923SEvan.Yan@Sun.COM return (DI_WALK_TERMINATE); 104410923SEvan.Yan@Sun.COM 104510923SEvan.Yan@Sun.COM if ((*intp >> i) & 1) { 104610923SEvan.Yan@Sun.COM /* assign tmptr */ 104710923SEvan.Yan@Sun.COM DBG(2, ("slot-name: %s \n", tmptr)); 104810923SEvan.Yan@Sun.COM if (i == slotarg->minor) 104910923SEvan.Yan@Sun.COM (void) strcpy(slotarg->slotnames[i], 105010923SEvan.Yan@Sun.COM tmptr); 105110923SEvan.Yan@Sun.COM /* wind tmptr to next \0 */ 105210923SEvan.Yan@Sun.COM while (*tmptr != '\0') { 105310923SEvan.Yan@Sun.COM tmptr++; 105410923SEvan.Yan@Sun.COM } 105510923SEvan.Yan@Sun.COM tmptr++; 105610923SEvan.Yan@Sun.COM } else { 105710923SEvan.Yan@Sun.COM /* point at unknown string */ 105810923SEvan.Yan@Sun.COM if (i == slotarg->minor) 105910923SEvan.Yan@Sun.COM (void) strcpy(slotarg->slotnames[i], 106010923SEvan.Yan@Sun.COM "unknown"); 106110923SEvan.Yan@Sun.COM } 106210923SEvan.Yan@Sun.COM } 106310923SEvan.Yan@Sun.COM } 106410923SEvan.Yan@Sun.COM return (DI_WALK_TERMINATE); 106510923SEvan.Yan@Sun.COM } 106610923SEvan.Yan@Sun.COM 106710923SEvan.Yan@Sun.COM static int 106810923SEvan.Yan@Sun.COM find_slotname(di_node_t din, di_minor_t dim, void *arg) 106910923SEvan.Yan@Sun.COM { 107010923SEvan.Yan@Sun.COM struct searcharg *slotarg = (struct searcharg *)arg; 107110923SEvan.Yan@Sun.COM di_prom_handle_t ph = (di_prom_handle_t)slotarg->promp; 107210923SEvan.Yan@Sun.COM di_prom_prop_t prom_prop; 107310923SEvan.Yan@Sun.COM di_prop_t solaris_prop; 107410923SEvan.Yan@Sun.COM int *intp, rval; 107510923SEvan.Yan@Sun.COM char *devname; 107610923SEvan.Yan@Sun.COM char fulldevname[MAXNAMELEN]; 107710923SEvan.Yan@Sun.COM 107810923SEvan.Yan@Sun.COM slotarg->minor = dim->dev_minor % 256; 107910923SEvan.Yan@Sun.COM 108010923SEvan.Yan@Sun.COM DBG(2, ("minor number:(%i)\n", slotarg->minor)); 108110923SEvan.Yan@Sun.COM DBG(2, ("hot plug slots found so far:(%i)\n", 0)); 108210923SEvan.Yan@Sun.COM 108310923SEvan.Yan@Sun.COM if ((devname = di_devfs_path(din)) != NULL) { 108410923SEvan.Yan@Sun.COM (void) snprintf(fulldevname, MAXNAMELEN, 108510923SEvan.Yan@Sun.COM "/devices%s:%s", devname, di_minor_name(dim)); 108610923SEvan.Yan@Sun.COM di_devfs_path_free(devname); 108710923SEvan.Yan@Sun.COM } 108810923SEvan.Yan@Sun.COM 108910923SEvan.Yan@Sun.COM if (strcmp(fulldevname, slotarg->devpath) == 0) { 109010923SEvan.Yan@Sun.COM 109110923SEvan.Yan@Sun.COM /* 109210923SEvan.Yan@Sun.COM * Check the Solaris device tree first 109310923SEvan.Yan@Sun.COM * in the case of a DR operation 109410923SEvan.Yan@Sun.COM */ 109510923SEvan.Yan@Sun.COM solaris_prop = di_prop_hw_next(din, DI_PROP_NIL); 109610923SEvan.Yan@Sun.COM while (solaris_prop != DI_PROP_NIL) { 109710923SEvan.Yan@Sun.COM if (strcmp("slot-names", di_prop_name(solaris_prop)) 109810923SEvan.Yan@Sun.COM == 0) { 109910923SEvan.Yan@Sun.COM rval = di_prop_lookup_ints(DDI_DEV_T_ANY, 110010923SEvan.Yan@Sun.COM din, di_prop_name(solaris_prop), &intp); 110110923SEvan.Yan@Sun.COM slotarg->slt_name_src = SOLARIS_SLT_NAME; 110210923SEvan.Yan@Sun.COM 110310923SEvan.Yan@Sun.COM return (fixup_slotname(rval, intp, slotarg)); 110410923SEvan.Yan@Sun.COM } 110510923SEvan.Yan@Sun.COM solaris_prop = di_prop_hw_next(din, solaris_prop); 110610923SEvan.Yan@Sun.COM } 110710923SEvan.Yan@Sun.COM 110810923SEvan.Yan@Sun.COM /* 110910923SEvan.Yan@Sun.COM * Check the prom device tree which is populated at boot. 111010923SEvan.Yan@Sun.COM * If this fails, give up and set the slot name to null. 111110923SEvan.Yan@Sun.COM */ 111210923SEvan.Yan@Sun.COM prom_prop = di_prom_prop_next(ph, din, DI_PROM_PROP_NIL); 111310923SEvan.Yan@Sun.COM while (prom_prop != DI_PROM_PROP_NIL) { 111410923SEvan.Yan@Sun.COM if (strcmp("slot-names", di_prom_prop_name(prom_prop)) 111510923SEvan.Yan@Sun.COM == 0) { 111610923SEvan.Yan@Sun.COM rval = di_prom_prop_lookup_ints(ph, 111710923SEvan.Yan@Sun.COM din, di_prom_prop_name(prom_prop), &intp); 111810923SEvan.Yan@Sun.COM slotarg->slt_name_src = PROM_SLT_NAME; 111910923SEvan.Yan@Sun.COM 112010923SEvan.Yan@Sun.COM return (fixup_slotname(rval, intp, slotarg)); 112110923SEvan.Yan@Sun.COM } 112210923SEvan.Yan@Sun.COM prom_prop = di_prom_prop_next(ph, din, prom_prop); 112310923SEvan.Yan@Sun.COM } 112410923SEvan.Yan@Sun.COM *slotarg->slotnames[slotarg->minor] = '\0'; 112510923SEvan.Yan@Sun.COM return (DI_WALK_TERMINATE); 112610923SEvan.Yan@Sun.COM } else 112710923SEvan.Yan@Sun.COM return (DI_WALK_CONTINUE); 112810923SEvan.Yan@Sun.COM } 112910923SEvan.Yan@Sun.COM 113010923SEvan.Yan@Sun.COM static int 113110923SEvan.Yan@Sun.COM find_physical_slot_names(const char *devcomp, struct searcharg *slotarg) 113210923SEvan.Yan@Sun.COM { 113310923SEvan.Yan@Sun.COM di_node_t root_node; 113410923SEvan.Yan@Sun.COM 113510923SEvan.Yan@Sun.COM DBG(1, ("find_physical_slot_names\n")); 113610923SEvan.Yan@Sun.COM 113710923SEvan.Yan@Sun.COM if ((root_node = di_init("/", DINFOCPYALL|DINFOPATH)) 113810923SEvan.Yan@Sun.COM == DI_NODE_NIL) { 113910923SEvan.Yan@Sun.COM DBG(1, ("di_init() failed\n")); 114010923SEvan.Yan@Sun.COM return (-1); 114110923SEvan.Yan@Sun.COM } 114210923SEvan.Yan@Sun.COM 114310923SEvan.Yan@Sun.COM slotarg->devpath = (char *)devcomp; 114410923SEvan.Yan@Sun.COM 114510923SEvan.Yan@Sun.COM if ((slotarg->promp = di_prom_init()) == DI_PROM_HANDLE_NIL) { 114610923SEvan.Yan@Sun.COM DBG(1, ("di_prom_init() failed\n")); 114710923SEvan.Yan@Sun.COM di_fini(root_node); 114810923SEvan.Yan@Sun.COM return (-1); 114910923SEvan.Yan@Sun.COM } 115010923SEvan.Yan@Sun.COM 115110923SEvan.Yan@Sun.COM (void) di_walk_minor(root_node, "ddi_ctl:attachment_point:pci", 115210923SEvan.Yan@Sun.COM 0, (void *)slotarg, find_slotname); 115310923SEvan.Yan@Sun.COM 115410923SEvan.Yan@Sun.COM di_prom_fini(slotarg->promp); 115510923SEvan.Yan@Sun.COM di_fini(root_node); 115610923SEvan.Yan@Sun.COM if (slotarg->slotnames[0] != NULL) 115710923SEvan.Yan@Sun.COM return (0); 115810923SEvan.Yan@Sun.COM else 115910923SEvan.Yan@Sun.COM return (-1); 116010923SEvan.Yan@Sun.COM } 116110923SEvan.Yan@Sun.COM 116210923SEvan.Yan@Sun.COM static void 116310923SEvan.Yan@Sun.COM get_type(const char *boardtype, const char *cardtype, char *buf) 116410923SEvan.Yan@Sun.COM { 116510923SEvan.Yan@Sun.COM /* for type string assembly in get_type() */ 116610923SEvan.Yan@Sun.COM #define TPCT(s) (void) strlcat(buf, (s), CFGA_TYPE_LEN) 116710923SEvan.Yan@Sun.COM 116810923SEvan.Yan@Sun.COM int i; 116910923SEvan.Yan@Sun.COM 117010923SEvan.Yan@Sun.COM if (strcmp(cardtype, "unknown") == 0) { 117110923SEvan.Yan@Sun.COM TPCT("unknown"); 117210923SEvan.Yan@Sun.COM return; 117310923SEvan.Yan@Sun.COM } 117410923SEvan.Yan@Sun.COM 117510923SEvan.Yan@Sun.COM TPCT(cardtype); 117610923SEvan.Yan@Sun.COM TPCT("/"); 117710923SEvan.Yan@Sun.COM 117810923SEvan.Yan@Sun.COM if (strcmp(boardtype, PCIEHPC_PROP_VALUE_PCIHOTPLUG) == 0) 117910923SEvan.Yan@Sun.COM TPCT(board_strs[PCIEHPC_BOARD_PCI_HOTPLUG]); 118010923SEvan.Yan@Sun.COM else 118110923SEvan.Yan@Sun.COM TPCT(board_strs[PCIEHPC_BOARD_UNKNOWN]); 118210923SEvan.Yan@Sun.COM } 118310923SEvan.Yan@Sun.COM 118410923SEvan.Yan@Sun.COM /* 118510923SEvan.Yan@Sun.COM * call-back function for di_devlink_walk 118610923SEvan.Yan@Sun.COM * if the link lives in /dev/cfg copy its name 118710923SEvan.Yan@Sun.COM */ 118810923SEvan.Yan@Sun.COM static int 118910923SEvan.Yan@Sun.COM found_devlink(di_devlink_t link, void *ap_log_id) 119010923SEvan.Yan@Sun.COM { 119110923SEvan.Yan@Sun.COM if (strncmp("/dev/cfg/", di_devlink_path(link), 9) == 0) { 119210923SEvan.Yan@Sun.COM /* copy everything but /dev/cfg/ */ 119310923SEvan.Yan@Sun.COM (void) strcpy((char *)ap_log_id, di_devlink_path(link) + 9); 119410923SEvan.Yan@Sun.COM DBG(1, ("found_devlink: %s\n", (char *)ap_log_id)); 119510923SEvan.Yan@Sun.COM return (DI_WALK_TERMINATE); 119610923SEvan.Yan@Sun.COM } 119710923SEvan.Yan@Sun.COM return (DI_WALK_CONTINUE); 119810923SEvan.Yan@Sun.COM } 119910923SEvan.Yan@Sun.COM 120010923SEvan.Yan@Sun.COM /* 120110923SEvan.Yan@Sun.COM * Walk throught the cached /dev link tree looking for links to the ap 120210923SEvan.Yan@Sun.COM * if none are found return an error 120310923SEvan.Yan@Sun.COM */ 120410923SEvan.Yan@Sun.COM static cfga_err_t 120510923SEvan.Yan@Sun.COM check_devlinks(char *ap_log_id, const char *ap_id) 120610923SEvan.Yan@Sun.COM { 120710923SEvan.Yan@Sun.COM di_devlink_handle_t hdl; 120810923SEvan.Yan@Sun.COM 120910923SEvan.Yan@Sun.COM DBG(1, ("check_devlinks: %s\n", ap_id)); 121010923SEvan.Yan@Sun.COM 121110923SEvan.Yan@Sun.COM hdl = di_devlink_init(NULL, 0); 121210923SEvan.Yan@Sun.COM 121310923SEvan.Yan@Sun.COM if (strncmp("/devices/", ap_id, 9) == 0) { 121410923SEvan.Yan@Sun.COM /* ap_id is a valid minor_path with /devices prepended */ 121510923SEvan.Yan@Sun.COM (void) di_devlink_walk(hdl, NULL, ap_id + 8, DI_PRIMARY_LINK, 121610923SEvan.Yan@Sun.COM (void *)ap_log_id, found_devlink); 121710923SEvan.Yan@Sun.COM } else { 121810923SEvan.Yan@Sun.COM DBG(1, ("check_devlinks: invalid ap_id: %s\n", ap_id)); 121910923SEvan.Yan@Sun.COM return (CFGA_ERROR); 122010923SEvan.Yan@Sun.COM } 122110923SEvan.Yan@Sun.COM 122210923SEvan.Yan@Sun.COM (void) di_devlink_fini(&hdl); 122310923SEvan.Yan@Sun.COM 122410923SEvan.Yan@Sun.COM if (ap_log_id[0] != '\0') 122510923SEvan.Yan@Sun.COM return (CFGA_OK); 122610923SEvan.Yan@Sun.COM else 122710923SEvan.Yan@Sun.COM return (CFGA_ERROR); 122810923SEvan.Yan@Sun.COM } 122910923SEvan.Yan@Sun.COM 123010923SEvan.Yan@Sun.COM /* 123110923SEvan.Yan@Sun.COM * most of this is needed to compensate for 123210923SEvan.Yan@Sun.COM * differences between various platforms 123310923SEvan.Yan@Sun.COM */ 123410923SEvan.Yan@Sun.COM static cfga_err_t 123510923SEvan.Yan@Sun.COM fix_ap_name(char *ap_log_id, const char *ap_id, char *slot_name, 123610923SEvan.Yan@Sun.COM char **errstring) 123710923SEvan.Yan@Sun.COM { 123810923SEvan.Yan@Sun.COM char *buf; 123910923SEvan.Yan@Sun.COM char *tmp; 124010923SEvan.Yan@Sun.COM char *ptr; 124110923SEvan.Yan@Sun.COM 124210923SEvan.Yan@Sun.COM di_node_t ap_node; 124310923SEvan.Yan@Sun.COM 124410923SEvan.Yan@Sun.COM ap_log_id[0] = '\0'; 124510923SEvan.Yan@Sun.COM 124610923SEvan.Yan@Sun.COM if (check_devlinks(ap_log_id, ap_id) == CFGA_OK) 124710923SEvan.Yan@Sun.COM return (CFGA_OK); 124810923SEvan.Yan@Sun.COM 124910923SEvan.Yan@Sun.COM DBG(1, ("fix_ap_name: %s\n", ap_id)); 125010923SEvan.Yan@Sun.COM 125110923SEvan.Yan@Sun.COM if ((buf = malloc(strlen(ap_id) + 1)) == NULL) { 125210923SEvan.Yan@Sun.COM DBG(1, ("malloc failed\n")); 125310923SEvan.Yan@Sun.COM return (CFGA_ERROR); 125410923SEvan.Yan@Sun.COM } 125510923SEvan.Yan@Sun.COM (void) strcpy(buf, ap_id); 125610923SEvan.Yan@Sun.COM tmp = buf + sizeof ("/devices") - 1; 125710923SEvan.Yan@Sun.COM 125810923SEvan.Yan@Sun.COM ptr = strchr(tmp, ':'); 125910923SEvan.Yan@Sun.COM ptr[0] = '\0'; 126010923SEvan.Yan@Sun.COM 126110923SEvan.Yan@Sun.COM DBG(1, ("fix_ap_name: %s\n", tmp)); 126210923SEvan.Yan@Sun.COM 126310923SEvan.Yan@Sun.COM ap_node = di_init(tmp, DINFOMINOR); 126410923SEvan.Yan@Sun.COM if (ap_node == DI_NODE_NIL) { 126510923SEvan.Yan@Sun.COM cfga_err(errstring, "di_init ", 0); 126610923SEvan.Yan@Sun.COM DBG(1, ("fix_ap_name: failed to snapshot node\n")); 126710923SEvan.Yan@Sun.COM return (CFGA_ERROR); 126810923SEvan.Yan@Sun.COM } 126910923SEvan.Yan@Sun.COM 127010923SEvan.Yan@Sun.COM (void) snprintf(ap_log_id, strlen(ap_id) + 1, "%s%i:%s", 127110923SEvan.Yan@Sun.COM di_driver_name(ap_node), di_instance(ap_node), slot_name); 127210923SEvan.Yan@Sun.COM 127310923SEvan.Yan@Sun.COM DBG(1, ("fix_ap_name: %s\n", ap_log_id)); 127410923SEvan.Yan@Sun.COM 127510923SEvan.Yan@Sun.COM di_fini(ap_node); 127610923SEvan.Yan@Sun.COM 127710923SEvan.Yan@Sun.COM free(buf); 127810923SEvan.Yan@Sun.COM return (CFGA_OK); 127910923SEvan.Yan@Sun.COM } 128010923SEvan.Yan@Sun.COM 128110923SEvan.Yan@Sun.COM 128210923SEvan.Yan@Sun.COM static int 128310923SEvan.Yan@Sun.COM findlink_cb(di_devlink_t devlink, void *arg) 128410923SEvan.Yan@Sun.COM { 128510923SEvan.Yan@Sun.COM (*(char **)arg) = strdup(di_devlink_path(devlink)); 128610923SEvan.Yan@Sun.COM 128710923SEvan.Yan@Sun.COM return (DI_WALK_TERMINATE); 128810923SEvan.Yan@Sun.COM } 128910923SEvan.Yan@Sun.COM 129010923SEvan.Yan@Sun.COM /* 129110923SEvan.Yan@Sun.COM * returns an allocated string containing the full path to the devlink for 129210923SEvan.Yan@Sun.COM * <ap_phys_id> in the devlink database; we expect only one devlink per 129310923SEvan.Yan@Sun.COM * <ap_phys_id> so we return the first encountered 129410923SEvan.Yan@Sun.COM */ 129510923SEvan.Yan@Sun.COM static char * 129610923SEvan.Yan@Sun.COM findlink(char *ap_phys_id) 129710923SEvan.Yan@Sun.COM { 129810923SEvan.Yan@Sun.COM di_devlink_handle_t hdl; 129910923SEvan.Yan@Sun.COM char *path = NULL; 130010923SEvan.Yan@Sun.COM 130110923SEvan.Yan@Sun.COM hdl = di_devlink_init(NULL, 0); 130210923SEvan.Yan@Sun.COM 130310923SEvan.Yan@Sun.COM if (strncmp("/devices/", ap_phys_id, 9) == 0) 130410923SEvan.Yan@Sun.COM ap_phys_id += 8; 130510923SEvan.Yan@Sun.COM 130610923SEvan.Yan@Sun.COM (void) di_devlink_walk(hdl, "^cfg/.+$", ap_phys_id, DI_PRIMARY_LINK, 130710923SEvan.Yan@Sun.COM (void *)&path, findlink_cb); 130810923SEvan.Yan@Sun.COM 130910923SEvan.Yan@Sun.COM (void) di_devlink_fini(&hdl); 131010923SEvan.Yan@Sun.COM return (path); 131110923SEvan.Yan@Sun.COM } 131210923SEvan.Yan@Sun.COM 131310923SEvan.Yan@Sun.COM 131410923SEvan.Yan@Sun.COM /* 131510923SEvan.Yan@Sun.COM * returns CFGA_OK if it can succesfully retrieve the devlink info associated 131610923SEvan.Yan@Sun.COM * with devlink for <ap_phys_id> which will be returned through <ap_info> 131710923SEvan.Yan@Sun.COM */ 131810923SEvan.Yan@Sun.COM cfga_err_t 131910923SEvan.Yan@Sun.COM get_dli(char *dlpath, char *ap_info, int ap_info_sz) 132010923SEvan.Yan@Sun.COM { 132110923SEvan.Yan@Sun.COM int fd; 132210923SEvan.Yan@Sun.COM 132310923SEvan.Yan@Sun.COM fd = di_dli_openr(dlpath); 132410923SEvan.Yan@Sun.COM if (fd < 0) 132510923SEvan.Yan@Sun.COM return (CFGA_ERROR); 132610923SEvan.Yan@Sun.COM 132710923SEvan.Yan@Sun.COM (void) read(fd, ap_info, ap_info_sz); 132810923SEvan.Yan@Sun.COM ap_info[ap_info_sz - 1] = '\0'; 132910923SEvan.Yan@Sun.COM 133010923SEvan.Yan@Sun.COM di_dli_close(fd); 133110923SEvan.Yan@Sun.COM return (CFGA_OK); 133210923SEvan.Yan@Sun.COM } 133310923SEvan.Yan@Sun.COM 133410923SEvan.Yan@Sun.COM static cfga_err_t 133510923SEvan.Yan@Sun.COM cfga_get_condition(hp_node_t node, ap_condition_t *cond) 133610923SEvan.Yan@Sun.COM { 133710923SEvan.Yan@Sun.COM char *condition; 133810923SEvan.Yan@Sun.COM 133910923SEvan.Yan@Sun.COM /* "condition" bus specific commands */ 134010923SEvan.Yan@Sun.COM if (hp_get_private(node, PCIEHPC_PROP_SLOT_CONDITION, 134110923SEvan.Yan@Sun.COM &condition) != 0) { 134210923SEvan.Yan@Sun.COM *cond = AP_COND_UNKNOWN; 134310923SEvan.Yan@Sun.COM return (CFGA_ERROR); 134410923SEvan.Yan@Sun.COM } 134510923SEvan.Yan@Sun.COM 134610923SEvan.Yan@Sun.COM condition = get_val_from_result(condition); 134710923SEvan.Yan@Sun.COM 134810923SEvan.Yan@Sun.COM if (strcmp(condition, PCIEHPC_PROP_COND_OK) == 0) 134910923SEvan.Yan@Sun.COM *cond = AP_COND_OK; 135010923SEvan.Yan@Sun.COM else if (strcmp(condition, PCIEHPC_PROP_COND_FAILING) == 0) 135110923SEvan.Yan@Sun.COM *cond = AP_COND_FAILING; 135210923SEvan.Yan@Sun.COM else if (strcmp(condition, PCIEHPC_PROP_COND_FAILED) == 0) 135310923SEvan.Yan@Sun.COM *cond = AP_COND_FAILED; 135410923SEvan.Yan@Sun.COM else if (strcmp(condition, PCIEHPC_PROP_COND_UNUSABLE) == 0) 135510923SEvan.Yan@Sun.COM *cond = AP_COND_UNUSABLE; 135610923SEvan.Yan@Sun.COM else if (strcmp(condition, PCIEHPC_PROP_COND_UNKNOWN) == 0) 135710923SEvan.Yan@Sun.COM *cond = AP_COND_UNKNOWN; 135810923SEvan.Yan@Sun.COM else 135910923SEvan.Yan@Sun.COM return (CFGA_ERROR); 136010923SEvan.Yan@Sun.COM 136110923SEvan.Yan@Sun.COM return (CFGA_OK); 136210923SEvan.Yan@Sun.COM } 136310923SEvan.Yan@Sun.COM 136410923SEvan.Yan@Sun.COM /*ARGSUSED*/ 136510923SEvan.Yan@Sun.COM cfga_err_t 136610923SEvan.Yan@Sun.COM cfga_list_ext(const char *ap_id, cfga_list_data_t **cs, 136710923SEvan.Yan@Sun.COM int *nlist, const char *options, const char *listopts, char **errstring, 136810923SEvan.Yan@Sun.COM cfga_flags_t flags) 136910923SEvan.Yan@Sun.COM { 137010923SEvan.Yan@Sun.COM char *boardtype; 137110923SEvan.Yan@Sun.COM char *cardtype; 137210923SEvan.Yan@Sun.COM struct searcharg slotname_arg; 137310923SEvan.Yan@Sun.COM int fd; 137410923SEvan.Yan@Sun.COM int rv = CFGA_OK; 137510923SEvan.Yan@Sun.COM char *dlpath = NULL; 137610923SEvan.Yan@Sun.COM hp_node_t node; 137710923SEvan.Yan@Sun.COM ap_rstate_t rs; 137810923SEvan.Yan@Sun.COM ap_ostate_t os; 137910923SEvan.Yan@Sun.COM ap_condition_t cond; 138010923SEvan.Yan@Sun.COM 138110923SEvan.Yan@Sun.COM if ((rv = check_options(options)) != CFGA_OK) { 138210923SEvan.Yan@Sun.COM return (rv); 138310923SEvan.Yan@Sun.COM } 138410923SEvan.Yan@Sun.COM 138510923SEvan.Yan@Sun.COM if (errstring != NULL) 138610923SEvan.Yan@Sun.COM *errstring = NULL; 138710923SEvan.Yan@Sun.COM 138810923SEvan.Yan@Sun.COM DBG(1, ("cfga_list_ext:(%s)\n", ap_id)); 138910923SEvan.Yan@Sun.COM 139010923SEvan.Yan@Sun.COM if (cs == NULL || nlist == NULL) { 139110923SEvan.Yan@Sun.COM rv = CFGA_ERROR; 139210923SEvan.Yan@Sun.COM return (rv); 139310923SEvan.Yan@Sun.COM } 139410923SEvan.Yan@Sun.COM 139510923SEvan.Yan@Sun.COM *nlist = 1; 139610923SEvan.Yan@Sun.COM 139710923SEvan.Yan@Sun.COM if ((*cs = malloc(sizeof (cfga_list_data_t))) == NULL) { 139810923SEvan.Yan@Sun.COM cfga_err(errstring, "malloc ", 0); 139910923SEvan.Yan@Sun.COM DBG(1, ("malloc failed\n")); 140010923SEvan.Yan@Sun.COM rv = CFGA_ERROR; 140110923SEvan.Yan@Sun.COM return (rv); 140210923SEvan.Yan@Sun.COM } 140310923SEvan.Yan@Sun.COM (void) memset(*cs, 0, sizeof (cfga_list_data_t)); 140410923SEvan.Yan@Sun.COM 140510923SEvan.Yan@Sun.COM rv = physpath2node(ap_id, errstring, &node); 140610923SEvan.Yan@Sun.COM if (rv != CFGA_OK) { 140710923SEvan.Yan@Sun.COM DBG(1, ("physpath2node failed\n")); 140810923SEvan.Yan@Sun.COM return (rv); 140910923SEvan.Yan@Sun.COM } 141010923SEvan.Yan@Sun.COM 141110923SEvan.Yan@Sun.COM if (cfga_get_state(node, &rs, &os) != CFGA_OK) { 141210923SEvan.Yan@Sun.COM DBG(1, ("cfga_get_state failed\n")); 141310923SEvan.Yan@Sun.COM hp_fini(node); 141410923SEvan.Yan@Sun.COM return (CFGA_ERROR); 141510923SEvan.Yan@Sun.COM } 141610923SEvan.Yan@Sun.COM 141710923SEvan.Yan@Sun.COM switch (rs) { 141810923SEvan.Yan@Sun.COM case AP_RSTATE_EMPTY: 141910923SEvan.Yan@Sun.COM (*cs)->ap_r_state = CFGA_STAT_EMPTY; 142010923SEvan.Yan@Sun.COM DBG(2, ("ap_rstate = CFGA_STAT_EMPTY\n")); 142110923SEvan.Yan@Sun.COM break; 142210923SEvan.Yan@Sun.COM case AP_RSTATE_DISCONNECTED: 142310923SEvan.Yan@Sun.COM (*cs)->ap_r_state = CFGA_STAT_DISCONNECTED; 142410923SEvan.Yan@Sun.COM DBG(2, ("ap_rstate = CFGA_STAT_DISCONNECTED\n")); 142510923SEvan.Yan@Sun.COM break; 142610923SEvan.Yan@Sun.COM case AP_RSTATE_CONNECTED: 142710923SEvan.Yan@Sun.COM (*cs)->ap_r_state = CFGA_STAT_CONNECTED; 142810923SEvan.Yan@Sun.COM DBG(2, ("ap_rstate = CFGA_STAT_CONNECTED\n")); 142910923SEvan.Yan@Sun.COM break; 143010923SEvan.Yan@Sun.COM default: 143110923SEvan.Yan@Sun.COM cfga_err(errstring, CMD_GETSTAT, ap_id, 0); 143210923SEvan.Yan@Sun.COM rv = CFGA_ERROR; 143310923SEvan.Yan@Sun.COM hp_fini(node); 143410923SEvan.Yan@Sun.COM return (rv); 143510923SEvan.Yan@Sun.COM } 143610923SEvan.Yan@Sun.COM 143710923SEvan.Yan@Sun.COM switch (os) { 143810923SEvan.Yan@Sun.COM case AP_OSTATE_CONFIGURED: 143910923SEvan.Yan@Sun.COM (*cs)->ap_o_state = CFGA_STAT_CONFIGURED; 144010923SEvan.Yan@Sun.COM DBG(2, ("ap_ostate = CFGA_STAT_CONFIGURED\n")); 144110923SEvan.Yan@Sun.COM break; 144210923SEvan.Yan@Sun.COM case AP_OSTATE_UNCONFIGURED: 144310923SEvan.Yan@Sun.COM (*cs)->ap_o_state = CFGA_STAT_UNCONFIGURED; 144410923SEvan.Yan@Sun.COM DBG(2, ("ap_ostate = CFGA_STAT_UNCONFIGURED\n")); 144510923SEvan.Yan@Sun.COM break; 144610923SEvan.Yan@Sun.COM default: 144710923SEvan.Yan@Sun.COM cfga_err(errstring, CMD_GETSTAT, ap_id, 0); 144810923SEvan.Yan@Sun.COM rv = CFGA_ERROR; 144910923SEvan.Yan@Sun.COM hp_fini(node); 145010923SEvan.Yan@Sun.COM return (rv); 145110923SEvan.Yan@Sun.COM } 145210923SEvan.Yan@Sun.COM 145310923SEvan.Yan@Sun.COM (void) cfga_get_condition(node, &cond); 145410923SEvan.Yan@Sun.COM 145510923SEvan.Yan@Sun.COM switch (cond) { 145610923SEvan.Yan@Sun.COM case AP_COND_OK: 145710923SEvan.Yan@Sun.COM (*cs)->ap_cond = CFGA_COND_OK; 145810923SEvan.Yan@Sun.COM DBG(2, ("ap_cond = CFGA_COND_OK\n")); 145910923SEvan.Yan@Sun.COM break; 146010923SEvan.Yan@Sun.COM case AP_COND_FAILING: 146110923SEvan.Yan@Sun.COM (*cs)->ap_cond = CFGA_COND_FAILING; 146210923SEvan.Yan@Sun.COM DBG(2, ("ap_cond = CFGA_COND_FAILING\n")); 146310923SEvan.Yan@Sun.COM break; 146410923SEvan.Yan@Sun.COM case AP_COND_FAILED: 146510923SEvan.Yan@Sun.COM (*cs)->ap_cond = CFGA_COND_FAILED; 146610923SEvan.Yan@Sun.COM DBG(2, ("ap_cond = CFGA_COND_FAILED\n")); 146710923SEvan.Yan@Sun.COM break; 146810923SEvan.Yan@Sun.COM case AP_COND_UNUSABLE: 146910923SEvan.Yan@Sun.COM (*cs)->ap_cond = CFGA_COND_UNUSABLE; 147010923SEvan.Yan@Sun.COM DBG(2, ("ap_cond = CFGA_COND_UNUSABLE\n")); 147110923SEvan.Yan@Sun.COM break; 147210923SEvan.Yan@Sun.COM case AP_COND_UNKNOWN: 147310923SEvan.Yan@Sun.COM (*cs)->ap_cond = CFGA_COND_UNKNOWN; 147410923SEvan.Yan@Sun.COM DBG(2, ("ap_cond = CFGA_COND_UNKNOW\n")); 147510923SEvan.Yan@Sun.COM break; 147610923SEvan.Yan@Sun.COM default: 147710923SEvan.Yan@Sun.COM cfga_err(errstring, CMD_GETSTAT, ap_id, 0); 147810923SEvan.Yan@Sun.COM rv = CFGA_ERROR; 147910923SEvan.Yan@Sun.COM hp_fini(node); 148010923SEvan.Yan@Sun.COM return (rv); 148110923SEvan.Yan@Sun.COM } 148210923SEvan.Yan@Sun.COM /* 148310923SEvan.Yan@Sun.COM * We're not busy since the entrance into the kernel has been 148410923SEvan.Yan@Sun.COM * sync'ed via libhotplug. 148510923SEvan.Yan@Sun.COM */ 148610923SEvan.Yan@Sun.COM (*cs)->ap_busy = 0; 148710923SEvan.Yan@Sun.COM 148810923SEvan.Yan@Sun.COM /* last change */ 148910923SEvan.Yan@Sun.COM (*cs)->ap_status_time = hp_last_change(node); 149010923SEvan.Yan@Sun.COM 149110923SEvan.Yan@Sun.COM /* board type */ 149210923SEvan.Yan@Sun.COM if (hp_get_private(node, PCIEHPC_PROP_BOARD_TYPE, &boardtype) != 0) 149310923SEvan.Yan@Sun.COM boardtype = PCIEHPC_PROP_VALUE_UNKNOWN; 149410923SEvan.Yan@Sun.COM else 149510923SEvan.Yan@Sun.COM boardtype = get_val_from_result(boardtype); 149610923SEvan.Yan@Sun.COM 149710923SEvan.Yan@Sun.COM /* card type */ 149810923SEvan.Yan@Sun.COM if (hp_get_private(node, PCIEHPC_PROP_CARD_TYPE, &cardtype) != 0) 149910923SEvan.Yan@Sun.COM cardtype = PCIEHPC_PROP_VALUE_UNKNOWN; 150010923SEvan.Yan@Sun.COM else 150110923SEvan.Yan@Sun.COM cardtype = get_val_from_result(cardtype); 150210923SEvan.Yan@Sun.COM 150310923SEvan.Yan@Sun.COM /* logical ap_id */ 150410923SEvan.Yan@Sun.COM rv = fix_ap_name((*cs)->ap_log_id, ap_id, 150510923SEvan.Yan@Sun.COM hp_name(node), errstring); 150610923SEvan.Yan@Sun.COM DBG(1, ("logical id: %s\n", (*cs)->ap_log_id)); 150710923SEvan.Yan@Sun.COM /* physical ap_id */ 150810923SEvan.Yan@Sun.COM (void) strcpy((*cs)->ap_phys_id, ap_id); /* physical path of AP */ 150910923SEvan.Yan@Sun.COM 151010923SEvan.Yan@Sun.COM /* information */ 151110923SEvan.Yan@Sun.COM dlpath = findlink((*cs)->ap_phys_id); 151210923SEvan.Yan@Sun.COM if (dlpath != NULL) { 151310923SEvan.Yan@Sun.COM if (get_dli(dlpath, (*cs)->ap_info, 151410923SEvan.Yan@Sun.COM sizeof ((*cs)->ap_info)) != CFGA_OK) 151510923SEvan.Yan@Sun.COM (*cs)->ap_info[0] = '\0'; 151610923SEvan.Yan@Sun.COM free(dlpath); 151710923SEvan.Yan@Sun.COM } 151810923SEvan.Yan@Sun.COM 151910923SEvan.Yan@Sun.COM if ((*cs)->ap_log_id[0] == '\0') 152010923SEvan.Yan@Sun.COM (void) strcpy((*cs)->ap_log_id, hp_name(node)); 152110923SEvan.Yan@Sun.COM 152210923SEvan.Yan@Sun.COM if ((*cs)->ap_info[0] == '\0') { 152310923SEvan.Yan@Sun.COM /* slot_names of bus node */ 152410923SEvan.Yan@Sun.COM if (find_physical_slot_names(ap_id, &slotname_arg) != -1) 152510923SEvan.Yan@Sun.COM (void) strcpy((*cs)->ap_info, 152610923SEvan.Yan@Sun.COM slotname_arg.slotnames[slotname_arg.minor]); 152710923SEvan.Yan@Sun.COM } 152810923SEvan.Yan@Sun.COM 152910923SEvan.Yan@Sun.COM /* class_code/subclass/boardtype */ 153010923SEvan.Yan@Sun.COM get_type(boardtype, cardtype, (*cs)->ap_type); 153110923SEvan.Yan@Sun.COM 153210923SEvan.Yan@Sun.COM DBG(1, ("cfga_list_ext return success\n")); 153310923SEvan.Yan@Sun.COM rv = CFGA_OK; 153410923SEvan.Yan@Sun.COM 153510923SEvan.Yan@Sun.COM hp_fini(node); 153610923SEvan.Yan@Sun.COM return (rv); 153710923SEvan.Yan@Sun.COM } 153810923SEvan.Yan@Sun.COM 153910923SEvan.Yan@Sun.COM /* 154010923SEvan.Yan@Sun.COM * This routine prints a single line of help message 154110923SEvan.Yan@Sun.COM */ 154210923SEvan.Yan@Sun.COM static void 154310923SEvan.Yan@Sun.COM cfga_msg(struct cfga_msg *msgp, const char *str) 154410923SEvan.Yan@Sun.COM { 154510923SEvan.Yan@Sun.COM DBG(2, ("<%s>", str)); 154610923SEvan.Yan@Sun.COM 154710923SEvan.Yan@Sun.COM if (msgp == NULL || msgp->message_routine == NULL) 154810923SEvan.Yan@Sun.COM return; 154910923SEvan.Yan@Sun.COM 155010923SEvan.Yan@Sun.COM (*msgp->message_routine)(msgp->appdata_ptr, str); 155110923SEvan.Yan@Sun.COM (*msgp->message_routine)(msgp->appdata_ptr, "\n"); 155210923SEvan.Yan@Sun.COM } 155310923SEvan.Yan@Sun.COM 155410923SEvan.Yan@Sun.COM static cfga_err_t 155510923SEvan.Yan@Sun.COM check_options(const char *options) 155610923SEvan.Yan@Sun.COM { 155710923SEvan.Yan@Sun.COM struct cfga_msg *msgp = NULL; 155810923SEvan.Yan@Sun.COM 155910923SEvan.Yan@Sun.COM if (options) { 156010923SEvan.Yan@Sun.COM cfga_msg(msgp, dgettext(TEXT_DOMAIN, cfga_strs[HELP_UNKNOWN])); 156110923SEvan.Yan@Sun.COM cfga_msg(msgp, options); 156210923SEvan.Yan@Sun.COM return (CFGA_INVAL); 156310923SEvan.Yan@Sun.COM } 156410923SEvan.Yan@Sun.COM return (CFGA_OK); 156510923SEvan.Yan@Sun.COM } 156610923SEvan.Yan@Sun.COM 156710923SEvan.Yan@Sun.COM /*ARGSUSED*/ 156810923SEvan.Yan@Sun.COM cfga_err_t 156910923SEvan.Yan@Sun.COM cfga_help(struct cfga_msg *msgp, const char *options, cfga_flags_t flags) 157010923SEvan.Yan@Sun.COM { 157110923SEvan.Yan@Sun.COM if (options) { 157210923SEvan.Yan@Sun.COM cfga_msg(msgp, dgettext(TEXT_DOMAIN, cfga_strs[HELP_UNKNOWN])); 157310923SEvan.Yan@Sun.COM cfga_msg(msgp, options); 157410923SEvan.Yan@Sun.COM } 157510923SEvan.Yan@Sun.COM DBG(1, ("cfga_help\n")); 157610923SEvan.Yan@Sun.COM 157710923SEvan.Yan@Sun.COM cfga_msg(msgp, dgettext(TEXT_DOMAIN, cfga_strs[HELP_HEADER])); 157810923SEvan.Yan@Sun.COM cfga_msg(msgp, cfga_strs[HELP_CONFIG]); 157910923SEvan.Yan@Sun.COM cfga_msg(msgp, cfga_strs[HELP_ENABLE_SLOT]); 158010923SEvan.Yan@Sun.COM cfga_msg(msgp, cfga_strs[HELP_DISABLE_SLOT]); 158110923SEvan.Yan@Sun.COM cfga_msg(msgp, cfga_strs[HELP_ENABLE_AUTOCONF]); 158210923SEvan.Yan@Sun.COM cfga_msg(msgp, cfga_strs[HELP_DISABLE_AUTOCONF]); 158310923SEvan.Yan@Sun.COM cfga_msg(msgp, cfga_strs[HELP_LED_CNTRL]); 158410923SEvan.Yan@Sun.COM return (CFGA_OK); 158510923SEvan.Yan@Sun.COM } 158610923SEvan.Yan@Sun.COM 158710923SEvan.Yan@Sun.COM /* 158810923SEvan.Yan@Sun.COM * cfga_err() accepts a variable number of message IDs and constructs 158910923SEvan.Yan@Sun.COM * a corresponding error string which is returned via the errstring argument. 159010923SEvan.Yan@Sun.COM * cfga_err() calls gettext() to internationalize proper messages. 159110923SEvan.Yan@Sun.COM */ 159210923SEvan.Yan@Sun.COM static void 159310923SEvan.Yan@Sun.COM cfga_err(char **errstring, ...) 159410923SEvan.Yan@Sun.COM { 159510923SEvan.Yan@Sun.COM int a; 159610923SEvan.Yan@Sun.COM int i; 159710923SEvan.Yan@Sun.COM int n; 159810923SEvan.Yan@Sun.COM int len; 159910923SEvan.Yan@Sun.COM int flen; 160010923SEvan.Yan@Sun.COM char *p; 160110923SEvan.Yan@Sun.COM char *q; 160210923SEvan.Yan@Sun.COM char *s[32]; 160310923SEvan.Yan@Sun.COM char *failed; 160410923SEvan.Yan@Sun.COM va_list ap; 160510923SEvan.Yan@Sun.COM 160610923SEvan.Yan@Sun.COM /* 160710923SEvan.Yan@Sun.COM * If errstring is null it means user is not interested in getting 160810923SEvan.Yan@Sun.COM * error status. So we don't do all the work 160910923SEvan.Yan@Sun.COM */ 161010923SEvan.Yan@Sun.COM if (errstring == NULL) { 161110923SEvan.Yan@Sun.COM return; 161210923SEvan.Yan@Sun.COM } 161310923SEvan.Yan@Sun.COM va_start(ap, errstring); 161410923SEvan.Yan@Sun.COM 161510923SEvan.Yan@Sun.COM failed = dgettext(TEXT_DOMAIN, cfga_strs[FAILED]); 161610923SEvan.Yan@Sun.COM flen = strlen(failed); 161710923SEvan.Yan@Sun.COM 161810923SEvan.Yan@Sun.COM for (n = len = 0; (a = va_arg(ap, int)) != 0; n++) { 161910923SEvan.Yan@Sun.COM switch (a) { 162010923SEvan.Yan@Sun.COM case CMD_GETSTAT: 162110923SEvan.Yan@Sun.COM case CMD_LIST: 162210923SEvan.Yan@Sun.COM case CMD_SLOT_CONNECT: 162310923SEvan.Yan@Sun.COM case CMD_SLOT_DISCONNECT: 162410923SEvan.Yan@Sun.COM case CMD_SLOT_CONFIGURE: 162510923SEvan.Yan@Sun.COM case CMD_SLOT_UNCONFIGURE: 162610923SEvan.Yan@Sun.COM p = cfga_errstrs(a); 162710923SEvan.Yan@Sun.COM len += (strlen(p) + flen); 162810923SEvan.Yan@Sun.COM s[n] = p; 162910923SEvan.Yan@Sun.COM s[++n] = cfga_strs[FAILED]; 163010923SEvan.Yan@Sun.COM 163110923SEvan.Yan@Sun.COM DBG(2, ("<%s>", p)); 163210923SEvan.Yan@Sun.COM DBG(2, (cfga_strs[FAILED])); 163310923SEvan.Yan@Sun.COM break; 163410923SEvan.Yan@Sun.COM 163510923SEvan.Yan@Sun.COM case ERR_CMD_INVAL: 163610923SEvan.Yan@Sun.COM case ERR_AP_INVAL: 163710923SEvan.Yan@Sun.COM case ERR_OPT_INVAL: 163810923SEvan.Yan@Sun.COM case ERR_AP_ERR: 163910923SEvan.Yan@Sun.COM switch (a) { 164010923SEvan.Yan@Sun.COM case ERR_CMD_INVAL: 164110923SEvan.Yan@Sun.COM p = dgettext(TEXT_DOMAIN, 164210923SEvan.Yan@Sun.COM cfga_errstrs[ERR_CMD_INVAL]); 164310923SEvan.Yan@Sun.COM break; 164410923SEvan.Yan@Sun.COM case ERR_AP_INVAL: 164510923SEvan.Yan@Sun.COM p = dgettext(TEXT_DOMAIN, 164610923SEvan.Yan@Sun.COM cfga_errstrs[ERR_AP_INVAL]); 164710923SEvan.Yan@Sun.COM break; 164810923SEvan.Yan@Sun.COM case ERR_OPT_INVAL: 164910923SEvan.Yan@Sun.COM p = dgettext(TEXT_DOMAIN, 165010923SEvan.Yan@Sun.COM cfga_errstrs[ERR_OPT_INVAL]); 165110923SEvan.Yan@Sun.COM break; 165210923SEvan.Yan@Sun.COM case ERR_AP_ERR: 165310923SEvan.Yan@Sun.COM p = dgettext(TEXT_DOMAIN, 165410923SEvan.Yan@Sun.COM cfga_errstrs[ERR_AP_ERR]); 165510923SEvan.Yan@Sun.COM break; 165610923SEvan.Yan@Sun.COM } 165710923SEvan.Yan@Sun.COM 165810923SEvan.Yan@Sun.COM if ((q = va_arg(ap, char *)) != NULL) { 165910923SEvan.Yan@Sun.COM len += (strlen(p) + strlen(q)); 166010923SEvan.Yan@Sun.COM s[n] = p; 166110923SEvan.Yan@Sun.COM s[++n] = q; 166210923SEvan.Yan@Sun.COM DBG(2, ("<%s>", p)); 166310923SEvan.Yan@Sun.COM DBG(2, ("<%s>", q)); 166410923SEvan.Yan@Sun.COM break; 166510923SEvan.Yan@Sun.COM } else { 166610923SEvan.Yan@Sun.COM len += strlen(p); 166710923SEvan.Yan@Sun.COM s[n] = p; 166810923SEvan.Yan@Sun.COM 166910923SEvan.Yan@Sun.COM } 167010923SEvan.Yan@Sun.COM DBG(2, ("<%s>", p)); 167110923SEvan.Yan@Sun.COM break; 167210923SEvan.Yan@Sun.COM 167310923SEvan.Yan@Sun.COM default: 167410923SEvan.Yan@Sun.COM n--; 167510923SEvan.Yan@Sun.COM break; 167610923SEvan.Yan@Sun.COM } 167710923SEvan.Yan@Sun.COM } 167810923SEvan.Yan@Sun.COM 167910923SEvan.Yan@Sun.COM DBG(2, ("\n")); 168010923SEvan.Yan@Sun.COM va_end(ap); 168110923SEvan.Yan@Sun.COM 168210923SEvan.Yan@Sun.COM if ((p = calloc(len + 1, 1)) == NULL) 168310923SEvan.Yan@Sun.COM return; 168410923SEvan.Yan@Sun.COM 168510923SEvan.Yan@Sun.COM for (i = 0; i < n; i++) { 168610923SEvan.Yan@Sun.COM (void) strlcat(p, s[i], len + 1); 168710923SEvan.Yan@Sun.COM DBG(2, ("i:%d, %s\n", i, s[i])); 168810923SEvan.Yan@Sun.COM } 168910923SEvan.Yan@Sun.COM 169010923SEvan.Yan@Sun.COM *errstring = p; 169110923SEvan.Yan@Sun.COM DBG(2, ("%s\n", *errstring)); 169210923SEvan.Yan@Sun.COM } 169310923SEvan.Yan@Sun.COM 169410923SEvan.Yan@Sun.COM /* 169510923SEvan.Yan@Sun.COM * cfga_ap_id_cmp -- use default_ap_id_cmp() in libcfgadm 169610923SEvan.Yan@Sun.COM */ 1697