1*10923SEvan.Yan@Sun.COM /* 2*10923SEvan.Yan@Sun.COM * CDDL HEADER START 3*10923SEvan.Yan@Sun.COM * 4*10923SEvan.Yan@Sun.COM * The contents of this file are subject to the terms of the 5*10923SEvan.Yan@Sun.COM * Common Development and Distribution License (the "License"). 6*10923SEvan.Yan@Sun.COM * You may not use this file except in compliance with the License. 7*10923SEvan.Yan@Sun.COM * 8*10923SEvan.Yan@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*10923SEvan.Yan@Sun.COM * or http://www.opensolaris.org/os/licensing. 10*10923SEvan.Yan@Sun.COM * See the License for the specific language governing permissions 11*10923SEvan.Yan@Sun.COM * and limitations under the License. 12*10923SEvan.Yan@Sun.COM * 13*10923SEvan.Yan@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 14*10923SEvan.Yan@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*10923SEvan.Yan@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 16*10923SEvan.Yan@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 17*10923SEvan.Yan@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 18*10923SEvan.Yan@Sun.COM * 19*10923SEvan.Yan@Sun.COM * CDDL HEADER END 20*10923SEvan.Yan@Sun.COM */ 21*10923SEvan.Yan@Sun.COM 22*10923SEvan.Yan@Sun.COM /* 23*10923SEvan.Yan@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24*10923SEvan.Yan@Sun.COM * Use is subject to license terms. 25*10923SEvan.Yan@Sun.COM */ 26*10923SEvan.Yan@Sun.COM 27*10923SEvan.Yan@Sun.COM /* 28*10923SEvan.Yan@Sun.COM * Plugin library for PCI Express and PCI (SHPC) hotplug controller 29*10923SEvan.Yan@Sun.COM */ 30*10923SEvan.Yan@Sun.COM 31*10923SEvan.Yan@Sun.COM #include <stddef.h> 32*10923SEvan.Yan@Sun.COM #include <locale.h> 33*10923SEvan.Yan@Sun.COM #include <ctype.h> 34*10923SEvan.Yan@Sun.COM #include <stdio.h> 35*10923SEvan.Yan@Sun.COM #include <stdlib.h> 36*10923SEvan.Yan@Sun.COM #include <string.h> 37*10923SEvan.Yan@Sun.COM #include <fcntl.h> 38*10923SEvan.Yan@Sun.COM #include <unistd.h> 39*10923SEvan.Yan@Sun.COM #include <errno.h> 40*10923SEvan.Yan@Sun.COM #include <locale.h> 41*10923SEvan.Yan@Sun.COM #include <langinfo.h> 42*10923SEvan.Yan@Sun.COM #include <time.h> 43*10923SEvan.Yan@Sun.COM #include <sys/param.h> 44*10923SEvan.Yan@Sun.COM #include <stdarg.h> 45*10923SEvan.Yan@Sun.COM #include <libdevinfo.h> 46*10923SEvan.Yan@Sun.COM #include <libdevice.h> 47*10923SEvan.Yan@Sun.COM 48*10923SEvan.Yan@Sun.COM #define CFGA_PLUGIN_LIB 49*10923SEvan.Yan@Sun.COM 50*10923SEvan.Yan@Sun.COM #include <config_admin.h> 51*10923SEvan.Yan@Sun.COM 52*10923SEvan.Yan@Sun.COM #include <assert.h> 53*10923SEvan.Yan@Sun.COM #include <sys/types.h> 54*10923SEvan.Yan@Sun.COM #include <sys/stat.h> 55*10923SEvan.Yan@Sun.COM #include <sys/dditypes.h> 56*10923SEvan.Yan@Sun.COM #include <sys/pci.h> 57*10923SEvan.Yan@Sun.COM #include <libintl.h> 58*10923SEvan.Yan@Sun.COM 59*10923SEvan.Yan@Sun.COM #include <dirent.h> 60*10923SEvan.Yan@Sun.COM #include <limits.h> 61*10923SEvan.Yan@Sun.COM #include <sys/mkdev.h> 62*10923SEvan.Yan@Sun.COM #include "../../../../uts/common/sys/hotplug/pci/pcie_hp.h" 63*10923SEvan.Yan@Sun.COM #include "../../../../common/pci/pci_strings.h" 64*10923SEvan.Yan@Sun.COM #include <libhotplug.h> 65*10923SEvan.Yan@Sun.COM 66*10923SEvan.Yan@Sun.COM extern const struct pci_class_strings_s class_pci[]; 67*10923SEvan.Yan@Sun.COM extern int class_pci_items; 68*10923SEvan.Yan@Sun.COM 69*10923SEvan.Yan@Sun.COM #define MSG_HOTPLUG_DISABLED \ 70*10923SEvan.Yan@Sun.COM "Error: hotplug service is probably not running, " \ 71*10923SEvan.Yan@Sun.COM "please use 'svcadm enable hotplug' to enable the service. " \ 72*10923SEvan.Yan@Sun.COM "See cfgadm_shp(1M) for more details." 73*10923SEvan.Yan@Sun.COM 74*10923SEvan.Yan@Sun.COM #define DEVICES_DIR "/devices" 75*10923SEvan.Yan@Sun.COM #define SLASH "/" 76*10923SEvan.Yan@Sun.COM #define GET_DYN(a) (strstr((a), CFGA_DYN_SEP)) 77*10923SEvan.Yan@Sun.COM 78*10923SEvan.Yan@Sun.COM /* 79*10923SEvan.Yan@Sun.COM * Set the version number 80*10923SEvan.Yan@Sun.COM */ 81*10923SEvan.Yan@Sun.COM int cfga_version = CFGA_HSL_V2; 82*10923SEvan.Yan@Sun.COM 83*10923SEvan.Yan@Sun.COM #ifdef DEBUG 84*10923SEvan.Yan@Sun.COM #define SHP_DBG 1 85*10923SEvan.Yan@Sun.COM #endif 86*10923SEvan.Yan@Sun.COM 87*10923SEvan.Yan@Sun.COM #if !defined(TEXT_DOMAIN) 88*10923SEvan.Yan@Sun.COM #define TEXT_DOMAIN "SYS_TEST" 89*10923SEvan.Yan@Sun.COM #endif 90*10923SEvan.Yan@Sun.COM 91*10923SEvan.Yan@Sun.COM /* 92*10923SEvan.Yan@Sun.COM * DEBUGING LEVEL 93*10923SEvan.Yan@Sun.COM * 94*10923SEvan.Yan@Sun.COM * External routines: 1 - 2 95*10923SEvan.Yan@Sun.COM * Internal routines: 3 - 4 96*10923SEvan.Yan@Sun.COM */ 97*10923SEvan.Yan@Sun.COM #ifdef SHP_DBG 98*10923SEvan.Yan@Sun.COM int shp_debug = 1; 99*10923SEvan.Yan@Sun.COM #define DBG(level, args) \ 100*10923SEvan.Yan@Sun.COM { if (shp_debug >= (level)) printf args; } 101*10923SEvan.Yan@Sun.COM #define DBG_F(level, args) \ 102*10923SEvan.Yan@Sun.COM { if (shp_debug >= (level)) fprintf args; } 103*10923SEvan.Yan@Sun.COM #else 104*10923SEvan.Yan@Sun.COM #define DBG(level, args) /* nothing */ 105*10923SEvan.Yan@Sun.COM #define DBG_F(level, args) /* nothing */ 106*10923SEvan.Yan@Sun.COM #endif 107*10923SEvan.Yan@Sun.COM 108*10923SEvan.Yan@Sun.COM #define CMD_ACQUIRE 0 109*10923SEvan.Yan@Sun.COM #define CMD_GETSTAT 1 110*10923SEvan.Yan@Sun.COM #define CMD_LIST 2 111*10923SEvan.Yan@Sun.COM #define CMD_SLOT_CONNECT 3 112*10923SEvan.Yan@Sun.COM #define CMD_SLOT_DISCONNECT 4 113*10923SEvan.Yan@Sun.COM #define CMD_SLOT_CONFIGURE 5 114*10923SEvan.Yan@Sun.COM #define CMD_SLOT_UNCONFIGURE 6 115*10923SEvan.Yan@Sun.COM #define CMD_SLOT_INSERT 7 116*10923SEvan.Yan@Sun.COM #define CMD_SLOT_REMOVE 8 117*10923SEvan.Yan@Sun.COM #define CMD_OPEN 9 118*10923SEvan.Yan@Sun.COM #define CMD_FSTAT 10 119*10923SEvan.Yan@Sun.COM #define ERR_CMD_INVAL 11 120*10923SEvan.Yan@Sun.COM #define ERR_AP_INVAL 12 121*10923SEvan.Yan@Sun.COM #define ERR_AP_ERR 13 122*10923SEvan.Yan@Sun.COM #define ERR_OPT_INVAL 14 123*10923SEvan.Yan@Sun.COM 124*10923SEvan.Yan@Sun.COM static char * 125*10923SEvan.Yan@Sun.COM cfga_errstrs[] = { 126*10923SEvan.Yan@Sun.COM /* n */ "acquire ", 127*10923SEvan.Yan@Sun.COM /* n */ "get-status ", 128*10923SEvan.Yan@Sun.COM /* n */ "list ", 129*10923SEvan.Yan@Sun.COM /* n */ "connect ", 130*10923SEvan.Yan@Sun.COM /* n */ "disconnect ", 131*10923SEvan.Yan@Sun.COM /* n */ "configure ", 132*10923SEvan.Yan@Sun.COM /* n */ "unconfigure ", 133*10923SEvan.Yan@Sun.COM /* n */ "insert ", 134*10923SEvan.Yan@Sun.COM /* n */ "remove ", 135*10923SEvan.Yan@Sun.COM /* n */ "open ", 136*10923SEvan.Yan@Sun.COM /* n */ "fstat ", 137*10923SEvan.Yan@Sun.COM /* y */ "invalid command ", 138*10923SEvan.Yan@Sun.COM /* y */ "invalid attachment point ", 139*10923SEvan.Yan@Sun.COM /* y */ "invalid transition ", 140*10923SEvan.Yan@Sun.COM /* y */ "invalid option ", 141*10923SEvan.Yan@Sun.COM NULL 142*10923SEvan.Yan@Sun.COM }; 143*10923SEvan.Yan@Sun.COM 144*10923SEvan.Yan@Sun.COM #define HELP_HEADER 1 145*10923SEvan.Yan@Sun.COM #define HELP_CONFIG 2 146*10923SEvan.Yan@Sun.COM #define HELP_ENABLE_SLOT 3 147*10923SEvan.Yan@Sun.COM #define HELP_DISABLE_SLOT 4 148*10923SEvan.Yan@Sun.COM #define HELP_ENABLE_AUTOCONF 5 149*10923SEvan.Yan@Sun.COM #define HELP_DISABLE_AUTOCONF 6 150*10923SEvan.Yan@Sun.COM #define HELP_LED_CNTRL 7 151*10923SEvan.Yan@Sun.COM #define HELP_UNKNOWN 8 152*10923SEvan.Yan@Sun.COM #define SUCCESS 9 153*10923SEvan.Yan@Sun.COM #define FAILED 10 154*10923SEvan.Yan@Sun.COM #define UNKNOWN 11 155*10923SEvan.Yan@Sun.COM 156*10923SEvan.Yan@Sun.COM #define MAXLINE 256 157*10923SEvan.Yan@Sun.COM 158*10923SEvan.Yan@Sun.COM extern int errno; 159*10923SEvan.Yan@Sun.COM 160*10923SEvan.Yan@Sun.COM static void cfga_err(char **errstring, ...); 161*10923SEvan.Yan@Sun.COM static cfga_err_t fix_ap_name(char *ap_log_id, const char *ap_id, 162*10923SEvan.Yan@Sun.COM char *slot_name, char **errstring); 163*10923SEvan.Yan@Sun.COM static cfga_err_t check_options(const char *options); 164*10923SEvan.Yan@Sun.COM static void cfga_msg(struct cfga_msg *msgp, const char *str); 165*10923SEvan.Yan@Sun.COM static char *findlink(char *ap_phys_id); 166*10923SEvan.Yan@Sun.COM 167*10923SEvan.Yan@Sun.COM static char * 168*10923SEvan.Yan@Sun.COM cfga_strs[] = { 169*10923SEvan.Yan@Sun.COM NULL, 170*10923SEvan.Yan@Sun.COM "\nPCI hotplug specific commands:", 171*10923SEvan.Yan@Sun.COM "\t-c [connect|disconnect|configure|unconfigure|insert|remove] " 172*10923SEvan.Yan@Sun.COM "ap_id [ap_id...]", 173*10923SEvan.Yan@Sun.COM "\t-x enable_slot ap_id [ap_id...]", 174*10923SEvan.Yan@Sun.COM "\t-x disable_slot ap_id [ap_id...]", 175*10923SEvan.Yan@Sun.COM "\t-x enable_autoconfig ap_id [ap_id...]", 176*10923SEvan.Yan@Sun.COM "\t-x disable_autoconfig ap_id [ap_id...]", 177*10923SEvan.Yan@Sun.COM "\t-x led[=[fault|power|active|attn],mode=[on|off|blink]] ap_id [ap_id...]", 178*10923SEvan.Yan@Sun.COM "\tunknown command or option: ", 179*10923SEvan.Yan@Sun.COM "success ", 180*10923SEvan.Yan@Sun.COM "failed ", 181*10923SEvan.Yan@Sun.COM "unknown", 182*10923SEvan.Yan@Sun.COM NULL 183*10923SEvan.Yan@Sun.COM }; 184*10923SEvan.Yan@Sun.COM 185*10923SEvan.Yan@Sun.COM #define MAX_FORMAT 80 186*10923SEvan.Yan@Sun.COM 187*10923SEvan.Yan@Sun.COM #define ENABLE_SLOT 0 188*10923SEvan.Yan@Sun.COM #define DISABLE_SLOT 1 189*10923SEvan.Yan@Sun.COM #define ENABLE_AUTOCNF 2 190*10923SEvan.Yan@Sun.COM #define DISABLE_AUTOCNF 3 191*10923SEvan.Yan@Sun.COM #define LED 4 192*10923SEvan.Yan@Sun.COM #define MODE 5 193*10923SEvan.Yan@Sun.COM 194*10923SEvan.Yan@Sun.COM typedef enum { PCIEHPC_FAULT_LED, PCIEHPC_POWER_LED, PCIEHPC_ATTN_LED, 195*10923SEvan.Yan@Sun.COM PCIEHPC_ACTIVE_LED} pciehpc_led_t; 196*10923SEvan.Yan@Sun.COM 197*10923SEvan.Yan@Sun.COM typedef enum { PCIEHPC_BOARD_UNKNOWN, PCIEHPC_BOARD_PCI_HOTPLUG } 198*10923SEvan.Yan@Sun.COM pciehpc_board_type_t; 199*10923SEvan.Yan@Sun.COM 200*10923SEvan.Yan@Sun.COM /* 201*10923SEvan.Yan@Sun.COM * Board Type 202*10923SEvan.Yan@Sun.COM */ 203*10923SEvan.Yan@Sun.COM static char * 204*10923SEvan.Yan@Sun.COM board_strs[] = { 205*10923SEvan.Yan@Sun.COM /* n */ "???", /* PCIEHPC_BOARD_UNKNOWN */ 206*10923SEvan.Yan@Sun.COM /* n */ "hp", /* PCIEHPC_BOARD_PCI_HOTPLUG */ 207*10923SEvan.Yan@Sun.COM /* n */ NULL 208*10923SEvan.Yan@Sun.COM }; 209*10923SEvan.Yan@Sun.COM 210*10923SEvan.Yan@Sun.COM /* 211*10923SEvan.Yan@Sun.COM * HW functions 212*10923SEvan.Yan@Sun.COM */ 213*10923SEvan.Yan@Sun.COM static char * 214*10923SEvan.Yan@Sun.COM func_strs[] = { 215*10923SEvan.Yan@Sun.COM /* n */ "enable_slot", 216*10923SEvan.Yan@Sun.COM /* n */ "disable_slot", 217*10923SEvan.Yan@Sun.COM /* n */ "enable_autoconfig", 218*10923SEvan.Yan@Sun.COM /* n */ "disable_autoconfig", 219*10923SEvan.Yan@Sun.COM /* n */ "led", 220*10923SEvan.Yan@Sun.COM /* n */ "mode", 221*10923SEvan.Yan@Sun.COM /* n */ NULL 222*10923SEvan.Yan@Sun.COM }; 223*10923SEvan.Yan@Sun.COM 224*10923SEvan.Yan@Sun.COM /* 225*10923SEvan.Yan@Sun.COM * LED strings 226*10923SEvan.Yan@Sun.COM */ 227*10923SEvan.Yan@Sun.COM static char * 228*10923SEvan.Yan@Sun.COM led_strs[] = { 229*10923SEvan.Yan@Sun.COM /* n */ "fault", /* PCIEHPC_FAULT_LED */ 230*10923SEvan.Yan@Sun.COM /* n */ "power", /* PCIEHPC_POWER_LED */ 231*10923SEvan.Yan@Sun.COM /* n */ "attn", /* PCIEHPC_ATTN_LED */ 232*10923SEvan.Yan@Sun.COM /* n */ "active", /* PCIEHPC_ACTIVE_LED */ 233*10923SEvan.Yan@Sun.COM /* n */ NULL 234*10923SEvan.Yan@Sun.COM }; 235*10923SEvan.Yan@Sun.COM 236*10923SEvan.Yan@Sun.COM static char * 237*10923SEvan.Yan@Sun.COM led_strs2[] = { 238*10923SEvan.Yan@Sun.COM /* n */ PCIEHPC_PROP_LED_FAULT, /* PCIEHPC_FAULT_LED */ 239*10923SEvan.Yan@Sun.COM /* n */ PCIEHPC_PROP_LED_POWER, /* PCIEHPC_POWER_LED */ 240*10923SEvan.Yan@Sun.COM /* n */ PCIEHPC_PROP_LED_ATTN, /* PCIEHPC_ATTN_LED */ 241*10923SEvan.Yan@Sun.COM /* n */ PCIEHPC_PROP_LED_ACTIVE, /* PCIEHPC_ACTIVE_LED */ 242*10923SEvan.Yan@Sun.COM /* n */ NULL 243*10923SEvan.Yan@Sun.COM }; 244*10923SEvan.Yan@Sun.COM 245*10923SEvan.Yan@Sun.COM #define FAULT 0 246*10923SEvan.Yan@Sun.COM #define POWER 1 247*10923SEvan.Yan@Sun.COM #define ATTN 2 248*10923SEvan.Yan@Sun.COM #define ACTIVE 3 249*10923SEvan.Yan@Sun.COM 250*10923SEvan.Yan@Sun.COM static char * 251*10923SEvan.Yan@Sun.COM mode_strs[] = { 252*10923SEvan.Yan@Sun.COM /* n */ "off", /* OFF */ 253*10923SEvan.Yan@Sun.COM /* n */ "on", /* ON */ 254*10923SEvan.Yan@Sun.COM /* n */ "blink", /* BLINK */ 255*10923SEvan.Yan@Sun.COM /* n */ NULL 256*10923SEvan.Yan@Sun.COM }; 257*10923SEvan.Yan@Sun.COM 258*10923SEvan.Yan@Sun.COM #define OFF 0 259*10923SEvan.Yan@Sun.COM #define ON 1 260*10923SEvan.Yan@Sun.COM #define BLINK 2 261*10923SEvan.Yan@Sun.COM 262*10923SEvan.Yan@Sun.COM #define cfga_errstrs(i) cfga_errstrs[(i)] 263*10923SEvan.Yan@Sun.COM 264*10923SEvan.Yan@Sun.COM #define cfga_eid(a, b) (((a) << 8) + (b)) 265*10923SEvan.Yan@Sun.COM #define MAXDEVS 32 266*10923SEvan.Yan@Sun.COM 267*10923SEvan.Yan@Sun.COM typedef enum { 268*10923SEvan.Yan@Sun.COM SOLARIS_SLT_NAME, 269*10923SEvan.Yan@Sun.COM PROM_SLT_NAME 270*10923SEvan.Yan@Sun.COM } slt_name_src_t; 271*10923SEvan.Yan@Sun.COM 272*10923SEvan.Yan@Sun.COM struct searcharg { 273*10923SEvan.Yan@Sun.COM char *devpath; 274*10923SEvan.Yan@Sun.COM char slotnames[MAXDEVS][MAXNAMELEN]; 275*10923SEvan.Yan@Sun.COM int minor; 276*10923SEvan.Yan@Sun.COM di_prom_handle_t promp; 277*10923SEvan.Yan@Sun.COM slt_name_src_t slt_name_src; 278*10923SEvan.Yan@Sun.COM }; 279*10923SEvan.Yan@Sun.COM 280*10923SEvan.Yan@Sun.COM static void *private_check; 281*10923SEvan.Yan@Sun.COM 282*10923SEvan.Yan@Sun.COM /* 283*10923SEvan.Yan@Sun.COM * Return the corresponding hp node for a given ap_id, it is the caller's 284*10923SEvan.Yan@Sun.COM * responsibility to call hp_fini() to free the snapshot. 285*10923SEvan.Yan@Sun.COM */ 286*10923SEvan.Yan@Sun.COM static cfga_err_t 287*10923SEvan.Yan@Sun.COM physpath2node(const char *physpath, char **errstring, hp_node_t *nodep) 288*10923SEvan.Yan@Sun.COM { 289*10923SEvan.Yan@Sun.COM char *rpath; 290*10923SEvan.Yan@Sun.COM char *cp; 291*10923SEvan.Yan@Sun.COM hp_node_t node; 292*10923SEvan.Yan@Sun.COM size_t len; 293*10923SEvan.Yan@Sun.COM char *errmsg; 294*10923SEvan.Yan@Sun.COM 295*10923SEvan.Yan@Sun.COM if (getuid() != 0 && geteuid() != 0) 296*10923SEvan.Yan@Sun.COM return (CFGA_ERROR); 297*10923SEvan.Yan@Sun.COM 298*10923SEvan.Yan@Sun.COM if ((rpath = malloc(strlen(physpath) + 1)) == NULL) 299*10923SEvan.Yan@Sun.COM return (CFGA_ERROR); 300*10923SEvan.Yan@Sun.COM 301*10923SEvan.Yan@Sun.COM (void) strcpy(rpath, physpath); 302*10923SEvan.Yan@Sun.COM 303*10923SEvan.Yan@Sun.COM /* Remove devices prefix (if any) */ 304*10923SEvan.Yan@Sun.COM len = strlen(DEVICES_DIR); 305*10923SEvan.Yan@Sun.COM if (strncmp(rpath, DEVICES_DIR SLASH, len + strlen(SLASH)) == 0) { 306*10923SEvan.Yan@Sun.COM (void) memmove(rpath, rpath + len, 307*10923SEvan.Yan@Sun.COM strlen(rpath + len) + 1); 308*10923SEvan.Yan@Sun.COM } 309*10923SEvan.Yan@Sun.COM 310*10923SEvan.Yan@Sun.COM /* Remove dynamic component if any */ 311*10923SEvan.Yan@Sun.COM if ((cp = GET_DYN(rpath)) != NULL) { 312*10923SEvan.Yan@Sun.COM *cp = '\0'; 313*10923SEvan.Yan@Sun.COM } 314*10923SEvan.Yan@Sun.COM 315*10923SEvan.Yan@Sun.COM /* Remove minor name (if any) */ 316*10923SEvan.Yan@Sun.COM if ((cp = strrchr(rpath, ':')) == NULL) { 317*10923SEvan.Yan@Sun.COM free(rpath); 318*10923SEvan.Yan@Sun.COM return (CFGA_INVAL); 319*10923SEvan.Yan@Sun.COM } 320*10923SEvan.Yan@Sun.COM 321*10923SEvan.Yan@Sun.COM *cp = '\0'; 322*10923SEvan.Yan@Sun.COM cp++; 323*10923SEvan.Yan@Sun.COM 324*10923SEvan.Yan@Sun.COM DBG(1, ("rpath=%s,cp=%s\n", rpath, cp)); 325*10923SEvan.Yan@Sun.COM if ((node = hp_init(rpath, cp, 0)) == NULL) { 326*10923SEvan.Yan@Sun.COM if (errno == EBADF) { 327*10923SEvan.Yan@Sun.COM /* No reponse to operations on the door file. */ 328*10923SEvan.Yan@Sun.COM assert(errstring != NULL); 329*10923SEvan.Yan@Sun.COM *errstring = strdup(MSG_HOTPLUG_DISABLED); 330*10923SEvan.Yan@Sun.COM free(rpath); 331*10923SEvan.Yan@Sun.COM return (CFGA_NOTSUPP); 332*10923SEvan.Yan@Sun.COM } 333*10923SEvan.Yan@Sun.COM free(rpath); 334*10923SEvan.Yan@Sun.COM return (CFGA_ERROR); 335*10923SEvan.Yan@Sun.COM } 336*10923SEvan.Yan@Sun.COM 337*10923SEvan.Yan@Sun.COM free(rpath); 338*10923SEvan.Yan@Sun.COM 339*10923SEvan.Yan@Sun.COM *nodep = node; 340*10923SEvan.Yan@Sun.COM return (CFGA_OK); 341*10923SEvan.Yan@Sun.COM } 342*10923SEvan.Yan@Sun.COM 343*10923SEvan.Yan@Sun.COM typedef struct error_size_cb_arg { 344*10923SEvan.Yan@Sun.COM size_t rsrc_width; 345*10923SEvan.Yan@Sun.COM size_t info_width; 346*10923SEvan.Yan@Sun.COM int cnt; 347*10923SEvan.Yan@Sun.COM } error_size_cb_arg_t; 348*10923SEvan.Yan@Sun.COM 349*10923SEvan.Yan@Sun.COM /* 350*10923SEvan.Yan@Sun.COM * Callback function for hp_traverse(), to sum up the 351*10923SEvan.Yan@Sun.COM * maximum length for error message display. 352*10923SEvan.Yan@Sun.COM */ 353*10923SEvan.Yan@Sun.COM static int 354*10923SEvan.Yan@Sun.COM error_sizeup_cb(hp_node_t node, void *arg) 355*10923SEvan.Yan@Sun.COM { 356*10923SEvan.Yan@Sun.COM error_size_cb_arg_t *sizearg = (error_size_cb_arg_t *)arg; 357*10923SEvan.Yan@Sun.COM size_t len; 358*10923SEvan.Yan@Sun.COM 359*10923SEvan.Yan@Sun.COM /* Only process USAGE nodes */ 360*10923SEvan.Yan@Sun.COM if (hp_type(node) != HP_NODE_USAGE) 361*10923SEvan.Yan@Sun.COM return (HP_WALK_CONTINUE); 362*10923SEvan.Yan@Sun.COM 363*10923SEvan.Yan@Sun.COM sizearg->cnt++; 364*10923SEvan.Yan@Sun.COM 365*10923SEvan.Yan@Sun.COM /* size up resource name */ 366*10923SEvan.Yan@Sun.COM len = strlen(hp_name(node)); 367*10923SEvan.Yan@Sun.COM if (sizearg->rsrc_width < len) 368*10923SEvan.Yan@Sun.COM sizearg->rsrc_width = len; 369*10923SEvan.Yan@Sun.COM 370*10923SEvan.Yan@Sun.COM /* size up usage description */ 371*10923SEvan.Yan@Sun.COM len = strlen(hp_usage(node)); 372*10923SEvan.Yan@Sun.COM if (sizearg->info_width < len) 373*10923SEvan.Yan@Sun.COM sizearg->info_width = len; 374*10923SEvan.Yan@Sun.COM 375*10923SEvan.Yan@Sun.COM return (HP_WALK_CONTINUE); 376*10923SEvan.Yan@Sun.COM } 377*10923SEvan.Yan@Sun.COM 378*10923SEvan.Yan@Sun.COM typedef struct error_sum_cb_arg { 379*10923SEvan.Yan@Sun.COM char **table; 380*10923SEvan.Yan@Sun.COM char *format; 381*10923SEvan.Yan@Sun.COM } error_sum_cb_arg_t; 382*10923SEvan.Yan@Sun.COM 383*10923SEvan.Yan@Sun.COM /* 384*10923SEvan.Yan@Sun.COM * Callback function for hp_traverse(), to add the error 385*10923SEvan.Yan@Sun.COM * message to he table. 386*10923SEvan.Yan@Sun.COM */ 387*10923SEvan.Yan@Sun.COM static int 388*10923SEvan.Yan@Sun.COM error_sumup_cb(hp_node_t node, void *arg) 389*10923SEvan.Yan@Sun.COM { 390*10923SEvan.Yan@Sun.COM error_sum_cb_arg_t *sumarg = (error_sum_cb_arg_t *)arg; 391*10923SEvan.Yan@Sun.COM char **table = sumarg->table; 392*10923SEvan.Yan@Sun.COM char *format = sumarg->format; 393*10923SEvan.Yan@Sun.COM 394*10923SEvan.Yan@Sun.COM /* Only process USAGE nodes */ 395*10923SEvan.Yan@Sun.COM if (hp_type(node) != HP_NODE_USAGE) 396*10923SEvan.Yan@Sun.COM return (HP_WALK_CONTINUE); 397*10923SEvan.Yan@Sun.COM 398*10923SEvan.Yan@Sun.COM (void) strcat(*table, "\n"); 399*10923SEvan.Yan@Sun.COM (void) sprintf(&((*table)[strlen(*table)]), 400*10923SEvan.Yan@Sun.COM format, hp_name(node), hp_usage(node)); 401*10923SEvan.Yan@Sun.COM 402*10923SEvan.Yan@Sun.COM return (HP_WALK_CONTINUE); 403*10923SEvan.Yan@Sun.COM } 404*10923SEvan.Yan@Sun.COM 405*10923SEvan.Yan@Sun.COM /* 406*10923SEvan.Yan@Sun.COM * Takes an opaque rcm_info_t pointer and a character pointer, and appends 407*10923SEvan.Yan@Sun.COM * the rcm_info_t data in the form of a table to the given character pointer. 408*10923SEvan.Yan@Sun.COM */ 409*10923SEvan.Yan@Sun.COM static void 410*10923SEvan.Yan@Sun.COM pci_rcm_info_table(hp_node_t node, char **table) 411*10923SEvan.Yan@Sun.COM { 412*10923SEvan.Yan@Sun.COM int i; 413*10923SEvan.Yan@Sun.COM size_t w; 414*10923SEvan.Yan@Sun.COM size_t width = 0; 415*10923SEvan.Yan@Sun.COM size_t w_rsrc = 0; 416*10923SEvan.Yan@Sun.COM size_t w_info = 0; 417*10923SEvan.Yan@Sun.COM size_t table_size = 0; 418*10923SEvan.Yan@Sun.COM uint_t tuples = 0; 419*10923SEvan.Yan@Sun.COM char *rsrc; 420*10923SEvan.Yan@Sun.COM char *info; 421*10923SEvan.Yan@Sun.COM char *newtable; 422*10923SEvan.Yan@Sun.COM static char format[MAX_FORMAT]; 423*10923SEvan.Yan@Sun.COM const char *infostr; 424*10923SEvan.Yan@Sun.COM error_size_cb_arg_t sizearg; 425*10923SEvan.Yan@Sun.COM error_sum_cb_arg_t sumarg; 426*10923SEvan.Yan@Sun.COM 427*10923SEvan.Yan@Sun.COM /* Protect against invalid arguments */ 428*10923SEvan.Yan@Sun.COM if (table == NULL) 429*10923SEvan.Yan@Sun.COM return; 430*10923SEvan.Yan@Sun.COM 431*10923SEvan.Yan@Sun.COM /* Set localized table header strings */ 432*10923SEvan.Yan@Sun.COM rsrc = dgettext(TEXT_DOMAIN, "Resource"); 433*10923SEvan.Yan@Sun.COM info = dgettext(TEXT_DOMAIN, "Information"); 434*10923SEvan.Yan@Sun.COM 435*10923SEvan.Yan@Sun.COM /* A first pass, to size up the RCM information */ 436*10923SEvan.Yan@Sun.COM sizearg.rsrc_width = strlen(rsrc); 437*10923SEvan.Yan@Sun.COM sizearg.info_width = strlen(info); 438*10923SEvan.Yan@Sun.COM sizearg.cnt = 0; 439*10923SEvan.Yan@Sun.COM (void) hp_traverse(node, &sizearg, error_sizeup_cb); 440*10923SEvan.Yan@Sun.COM 441*10923SEvan.Yan@Sun.COM /* If nothing was sized up above, stop early */ 442*10923SEvan.Yan@Sun.COM if (sizearg.cnt == 0) 443*10923SEvan.Yan@Sun.COM return; 444*10923SEvan.Yan@Sun.COM 445*10923SEvan.Yan@Sun.COM w_rsrc = sizearg.rsrc_width; 446*10923SEvan.Yan@Sun.COM w_info = sizearg.info_width; 447*10923SEvan.Yan@Sun.COM tuples = sizearg.cnt; 448*10923SEvan.Yan@Sun.COM 449*10923SEvan.Yan@Sun.COM /* Adjust column widths for column headings */ 450*10923SEvan.Yan@Sun.COM if ((w = strlen(rsrc)) > w_rsrc) 451*10923SEvan.Yan@Sun.COM w_rsrc = w; 452*10923SEvan.Yan@Sun.COM else if ((w_rsrc - w) % 2) 453*10923SEvan.Yan@Sun.COM w_rsrc++; 454*10923SEvan.Yan@Sun.COM if ((w = strlen(info)) > w_info) 455*10923SEvan.Yan@Sun.COM w_info = w; 456*10923SEvan.Yan@Sun.COM else if ((w_info - w) % 2) 457*10923SEvan.Yan@Sun.COM w_info++; 458*10923SEvan.Yan@Sun.COM 459*10923SEvan.Yan@Sun.COM /* 460*10923SEvan.Yan@Sun.COM * Compute the total line width of each line, 461*10923SEvan.Yan@Sun.COM * accounting for intercolumn spacing. 462*10923SEvan.Yan@Sun.COM */ 463*10923SEvan.Yan@Sun.COM width = w_info + w_rsrc + 4; 464*10923SEvan.Yan@Sun.COM 465*10923SEvan.Yan@Sun.COM /* Allocate space for the table */ 466*10923SEvan.Yan@Sun.COM table_size = (2 + tuples) * (width + 1) + 2; 467*10923SEvan.Yan@Sun.COM if (*table == NULL) { 468*10923SEvan.Yan@Sun.COM /* zero fill for the strcat() call below */ 469*10923SEvan.Yan@Sun.COM *table = calloc(table_size, sizeof (char)); 470*10923SEvan.Yan@Sun.COM if (*table == NULL) 471*10923SEvan.Yan@Sun.COM return; 472*10923SEvan.Yan@Sun.COM } else { 473*10923SEvan.Yan@Sun.COM newtable = realloc(*table, strlen(*table) + table_size); 474*10923SEvan.Yan@Sun.COM if (newtable == NULL) 475*10923SEvan.Yan@Sun.COM return; 476*10923SEvan.Yan@Sun.COM else 477*10923SEvan.Yan@Sun.COM *table = newtable; 478*10923SEvan.Yan@Sun.COM } 479*10923SEvan.Yan@Sun.COM 480*10923SEvan.Yan@Sun.COM /* Place a table header into the string */ 481*10923SEvan.Yan@Sun.COM 482*10923SEvan.Yan@Sun.COM /* The resource header */ 483*10923SEvan.Yan@Sun.COM (void) strcat(*table, "\n"); 484*10923SEvan.Yan@Sun.COM w = strlen(rsrc); 485*10923SEvan.Yan@Sun.COM for (i = 0; i < ((w_rsrc - w) / 2); i++) 486*10923SEvan.Yan@Sun.COM (void) strcat(*table, " "); 487*10923SEvan.Yan@Sun.COM (void) strcat(*table, rsrc); 488*10923SEvan.Yan@Sun.COM for (i = 0; i < ((w_rsrc - w) / 2); i++) 489*10923SEvan.Yan@Sun.COM (void) strcat(*table, " "); 490*10923SEvan.Yan@Sun.COM 491*10923SEvan.Yan@Sun.COM /* The information header */ 492*10923SEvan.Yan@Sun.COM (void) strcat(*table, " "); 493*10923SEvan.Yan@Sun.COM w = strlen(info); 494*10923SEvan.Yan@Sun.COM for (i = 0; i < ((w_info - w) / 2); i++) 495*10923SEvan.Yan@Sun.COM (void) strcat(*table, " "); 496*10923SEvan.Yan@Sun.COM (void) strcat(*table, info); 497*10923SEvan.Yan@Sun.COM for (i = 0; i < ((w_info - w) / 2); i++) 498*10923SEvan.Yan@Sun.COM (void) strcat(*table, " "); 499*10923SEvan.Yan@Sun.COM /* Underline the headers */ 500*10923SEvan.Yan@Sun.COM (void) strcat(*table, "\n"); 501*10923SEvan.Yan@Sun.COM for (i = 0; i < w_rsrc; i++) 502*10923SEvan.Yan@Sun.COM (void) strcat(*table, "-"); 503*10923SEvan.Yan@Sun.COM (void) strcat(*table, " "); 504*10923SEvan.Yan@Sun.COM for (i = 0; i < w_info; i++) 505*10923SEvan.Yan@Sun.COM (void) strcat(*table, "-"); 506*10923SEvan.Yan@Sun.COM 507*10923SEvan.Yan@Sun.COM /* Construct the format string */ 508*10923SEvan.Yan@Sun.COM (void) snprintf(format, MAX_FORMAT, "%%-%ds %%-%ds", 509*10923SEvan.Yan@Sun.COM (int)w_rsrc, (int)w_info); 510*10923SEvan.Yan@Sun.COM 511*10923SEvan.Yan@Sun.COM /* Add the tuples to the table string */ 512*10923SEvan.Yan@Sun.COM sumarg.table = table; 513*10923SEvan.Yan@Sun.COM sumarg.format = format; 514*10923SEvan.Yan@Sun.COM (void) hp_traverse(node, &sumarg, error_sumup_cb); 515*10923SEvan.Yan@Sun.COM } 516*10923SEvan.Yan@Sun.COM 517*10923SEvan.Yan@Sun.COM /* 518*10923SEvan.Yan@Sun.COM * Figure out the target kernel state for a given cfgadm 519*10923SEvan.Yan@Sun.COM * change-state operation. 520*10923SEvan.Yan@Sun.COM */ 521*10923SEvan.Yan@Sun.COM static cfga_err_t 522*10923SEvan.Yan@Sun.COM cfga_target_state(cfga_cmd_t state_change_cmd, int *state) 523*10923SEvan.Yan@Sun.COM { 524*10923SEvan.Yan@Sun.COM switch (state_change_cmd) { 525*10923SEvan.Yan@Sun.COM case CFGA_CMD_CONNECT: 526*10923SEvan.Yan@Sun.COM *state = DDI_HP_CN_STATE_POWERED; 527*10923SEvan.Yan@Sun.COM break; 528*10923SEvan.Yan@Sun.COM case CFGA_CMD_DISCONNECT: 529*10923SEvan.Yan@Sun.COM *state = DDI_HP_CN_STATE_PRESENT; 530*10923SEvan.Yan@Sun.COM break; 531*10923SEvan.Yan@Sun.COM case CFGA_CMD_CONFIGURE: 532*10923SEvan.Yan@Sun.COM *state = DDI_HP_CN_STATE_ENABLED; 533*10923SEvan.Yan@Sun.COM break; 534*10923SEvan.Yan@Sun.COM case CFGA_CMD_UNCONFIGURE: 535*10923SEvan.Yan@Sun.COM *state = DDI_HP_CN_STATE_POWERED; 536*10923SEvan.Yan@Sun.COM break; 537*10923SEvan.Yan@Sun.COM default: 538*10923SEvan.Yan@Sun.COM return (CFGA_ERROR); 539*10923SEvan.Yan@Sun.COM } 540*10923SEvan.Yan@Sun.COM 541*10923SEvan.Yan@Sun.COM return (CFGA_OK); 542*10923SEvan.Yan@Sun.COM } 543*10923SEvan.Yan@Sun.COM 544*10923SEvan.Yan@Sun.COM /* 545*10923SEvan.Yan@Sun.COM * Translate kernel state to cfgadm receptacle state and occupant state. 546*10923SEvan.Yan@Sun.COM */ 547*10923SEvan.Yan@Sun.COM static cfga_err_t 548*10923SEvan.Yan@Sun.COM cfga_get_state(hp_node_t connector, ap_rstate_t *rs, ap_ostate_t *os) 549*10923SEvan.Yan@Sun.COM { 550*10923SEvan.Yan@Sun.COM int state; 551*10923SEvan.Yan@Sun.COM hp_node_t port; 552*10923SEvan.Yan@Sun.COM 553*10923SEvan.Yan@Sun.COM state = hp_state(connector); 554*10923SEvan.Yan@Sun.COM 555*10923SEvan.Yan@Sun.COM /* Receptacle state */ 556*10923SEvan.Yan@Sun.COM switch (state) { 557*10923SEvan.Yan@Sun.COM case DDI_HP_CN_STATE_EMPTY: 558*10923SEvan.Yan@Sun.COM *rs = AP_RSTATE_EMPTY; 559*10923SEvan.Yan@Sun.COM break; 560*10923SEvan.Yan@Sun.COM case DDI_HP_CN_STATE_PRESENT: 561*10923SEvan.Yan@Sun.COM *rs = AP_RSTATE_DISCONNECTED; 562*10923SEvan.Yan@Sun.COM break; 563*10923SEvan.Yan@Sun.COM case DDI_HP_CN_STATE_POWERED: 564*10923SEvan.Yan@Sun.COM case DDI_HP_CN_STATE_ENABLED: 565*10923SEvan.Yan@Sun.COM *rs = AP_RSTATE_CONNECTED; 566*10923SEvan.Yan@Sun.COM break; 567*10923SEvan.Yan@Sun.COM /* 568*10923SEvan.Yan@Sun.COM * Connector state can only be one of 569*10923SEvan.Yan@Sun.COM * Empty, Present, Powered, Enabled. 570*10923SEvan.Yan@Sun.COM */ 571*10923SEvan.Yan@Sun.COM default: 572*10923SEvan.Yan@Sun.COM return (CFGA_ERROR); 573*10923SEvan.Yan@Sun.COM } 574*10923SEvan.Yan@Sun.COM 575*10923SEvan.Yan@Sun.COM /* 576*10923SEvan.Yan@Sun.COM * Occupant state 577*10923SEvan.Yan@Sun.COM */ 578*10923SEvan.Yan@Sun.COM port = hp_child(connector); 579*10923SEvan.Yan@Sun.COM while (port != NULL) { 580*10923SEvan.Yan@Sun.COM DBG(1, ("cfga_get_state:(%x)\n", hp_state(port))); 581*10923SEvan.Yan@Sun.COM 582*10923SEvan.Yan@Sun.COM /* 583*10923SEvan.Yan@Sun.COM * Mark occupant state as "configured" if at least one of the 584*10923SEvan.Yan@Sun.COM * associated ports is at state "offline" or above. Driver 585*10923SEvan.Yan@Sun.COM * attach ("online" state) is not necessary here. 586*10923SEvan.Yan@Sun.COM */ 587*10923SEvan.Yan@Sun.COM if (hp_state(port) >= DDI_HP_CN_STATE_OFFLINE) 588*10923SEvan.Yan@Sun.COM break; 589*10923SEvan.Yan@Sun.COM 590*10923SEvan.Yan@Sun.COM port = hp_sibling(port); 591*10923SEvan.Yan@Sun.COM } 592*10923SEvan.Yan@Sun.COM 593*10923SEvan.Yan@Sun.COM if (port != NULL) 594*10923SEvan.Yan@Sun.COM *os = AP_OSTATE_CONFIGURED; 595*10923SEvan.Yan@Sun.COM else 596*10923SEvan.Yan@Sun.COM *os = AP_OSTATE_UNCONFIGURED; 597*10923SEvan.Yan@Sun.COM 598*10923SEvan.Yan@Sun.COM return (CFGA_OK); 599*10923SEvan.Yan@Sun.COM } 600*10923SEvan.Yan@Sun.COM 601*10923SEvan.Yan@Sun.COM /* 602*10923SEvan.Yan@Sun.COM * Transitional Diagram: 603*10923SEvan.Yan@Sun.COM * 604*10923SEvan.Yan@Sun.COM * empty unconfigure 605*10923SEvan.Yan@Sun.COM * (remove) ^| (physically insert card) 606*10923SEvan.Yan@Sun.COM * |V 607*10923SEvan.Yan@Sun.COM * disconnect configure 608*10923SEvan.Yan@Sun.COM * "-c DISCONNECT" ^| "-c CONNECT" 609*10923SEvan.Yan@Sun.COM * |V "-c CONFIGURE" 610*10923SEvan.Yan@Sun.COM * connect unconfigure -> connect configure 611*10923SEvan.Yan@Sun.COM * <- 612*10923SEvan.Yan@Sun.COM * "-c UNCONFIGURE" 613*10923SEvan.Yan@Sun.COM * 614*10923SEvan.Yan@Sun.COM */ 615*10923SEvan.Yan@Sun.COM /*ARGSUSED*/ 616*10923SEvan.Yan@Sun.COM cfga_err_t 617*10923SEvan.Yan@Sun.COM cfga_change_state(cfga_cmd_t state_change_cmd, const char *ap_id, 618*10923SEvan.Yan@Sun.COM const char *options, struct cfga_confirm *confp, 619*10923SEvan.Yan@Sun.COM struct cfga_msg *msgp, char **errstring, cfga_flags_t flags) 620*10923SEvan.Yan@Sun.COM { 621*10923SEvan.Yan@Sun.COM int rv, state, new_state; 622*10923SEvan.Yan@Sun.COM hp_node_t node; 623*10923SEvan.Yan@Sun.COM hp_node_t results = NULL; 624*10923SEvan.Yan@Sun.COM 625*10923SEvan.Yan@Sun.COM if ((rv = check_options(options)) != CFGA_OK) { 626*10923SEvan.Yan@Sun.COM return (rv); 627*10923SEvan.Yan@Sun.COM } 628*10923SEvan.Yan@Sun.COM 629*10923SEvan.Yan@Sun.COM if (errstring != NULL) 630*10923SEvan.Yan@Sun.COM *errstring = NULL; 631*10923SEvan.Yan@Sun.COM 632*10923SEvan.Yan@Sun.COM rv = CFGA_OK; 633*10923SEvan.Yan@Sun.COM DBG(1, ("cfga_change_state:(%s)\n", ap_id)); 634*10923SEvan.Yan@Sun.COM 635*10923SEvan.Yan@Sun.COM rv = physpath2node(ap_id, errstring, &node); 636*10923SEvan.Yan@Sun.COM if (rv != CFGA_OK) 637*10923SEvan.Yan@Sun.COM return (rv); 638*10923SEvan.Yan@Sun.COM 639*10923SEvan.Yan@Sun.COM state = hp_state(node); 640*10923SEvan.Yan@Sun.COM 641*10923SEvan.Yan@Sun.COM /* 642*10923SEvan.Yan@Sun.COM * Which state should we drive to ? 643*10923SEvan.Yan@Sun.COM */ 644*10923SEvan.Yan@Sun.COM if ((state_change_cmd != CFGA_CMD_LOAD) && 645*10923SEvan.Yan@Sun.COM (state_change_cmd != CFGA_CMD_UNLOAD)) { 646*10923SEvan.Yan@Sun.COM if (cfga_target_state(state_change_cmd, 647*10923SEvan.Yan@Sun.COM &new_state) != CFGA_OK) { 648*10923SEvan.Yan@Sun.COM hp_fini(node); 649*10923SEvan.Yan@Sun.COM return (CFGA_ERROR); 650*10923SEvan.Yan@Sun.COM } 651*10923SEvan.Yan@Sun.COM } 652*10923SEvan.Yan@Sun.COM 653*10923SEvan.Yan@Sun.COM DBG(1, ("cfga_change_state: state is %d\n", state)); 654*10923SEvan.Yan@Sun.COM switch (state_change_cmd) { 655*10923SEvan.Yan@Sun.COM case CFGA_CMD_CONNECT: 656*10923SEvan.Yan@Sun.COM if ((state == DDI_HP_CN_STATE_EMPTY) || 657*10923SEvan.Yan@Sun.COM (state >= DDI_HP_CN_STATE_POWERED)) { 658*10923SEvan.Yan@Sun.COM cfga_err(errstring, ERR_AP_ERR, 0); 659*10923SEvan.Yan@Sun.COM rv = CFGA_INVAL; 660*10923SEvan.Yan@Sun.COM } else { 661*10923SEvan.Yan@Sun.COM /* Lets connect the slot */ 662*10923SEvan.Yan@Sun.COM if (hp_set_state(node, 0, new_state, &results) != 0) { 663*10923SEvan.Yan@Sun.COM rv = CFGA_ERROR; 664*10923SEvan.Yan@Sun.COM cfga_err(errstring, CMD_SLOT_CONNECT, 0); 665*10923SEvan.Yan@Sun.COM } 666*10923SEvan.Yan@Sun.COM } 667*10923SEvan.Yan@Sun.COM 668*10923SEvan.Yan@Sun.COM break; 669*10923SEvan.Yan@Sun.COM 670*10923SEvan.Yan@Sun.COM case CFGA_CMD_DISCONNECT: 671*10923SEvan.Yan@Sun.COM DBG(1, ("disconnect\n")); 672*10923SEvan.Yan@Sun.COM 673*10923SEvan.Yan@Sun.COM if (state < DDI_HP_CN_STATE_POWERED) { 674*10923SEvan.Yan@Sun.COM cfga_err(errstring, ERR_AP_ERR, 0); 675*10923SEvan.Yan@Sun.COM rv = CFGA_INVAL; 676*10923SEvan.Yan@Sun.COM } else { 677*10923SEvan.Yan@Sun.COM if ((rv = hp_set_state(node, 0, new_state, &results)) 678*10923SEvan.Yan@Sun.COM != 0) { 679*10923SEvan.Yan@Sun.COM if (rv == EBUSY) 680*10923SEvan.Yan@Sun.COM rv = CFGA_BUSY; 681*10923SEvan.Yan@Sun.COM else 682*10923SEvan.Yan@Sun.COM rv = CFGA_ERROR; 683*10923SEvan.Yan@Sun.COM 684*10923SEvan.Yan@Sun.COM if (results) { 685*10923SEvan.Yan@Sun.COM pci_rcm_info_table(results, errstring); 686*10923SEvan.Yan@Sun.COM hp_fini(results); 687*10923SEvan.Yan@Sun.COM } else { 688*10923SEvan.Yan@Sun.COM cfga_err(errstring, 689*10923SEvan.Yan@Sun.COM CMD_SLOT_DISCONNECT, 0); 690*10923SEvan.Yan@Sun.COM } 691*10923SEvan.Yan@Sun.COM } 692*10923SEvan.Yan@Sun.COM } 693*10923SEvan.Yan@Sun.COM 694*10923SEvan.Yan@Sun.COM break; 695*10923SEvan.Yan@Sun.COM 696*10923SEvan.Yan@Sun.COM case CFGA_CMD_CONFIGURE: 697*10923SEvan.Yan@Sun.COM /* 698*10923SEvan.Yan@Sun.COM * for multi-func device we allow multiple 699*10923SEvan.Yan@Sun.COM * configure on the same slot because one 700*10923SEvan.Yan@Sun.COM * func can be configured and other one won't 701*10923SEvan.Yan@Sun.COM */ 702*10923SEvan.Yan@Sun.COM if (hp_set_state(node, 0, new_state, &results) != 0) { 703*10923SEvan.Yan@Sun.COM rv = CFGA_ERROR; 704*10923SEvan.Yan@Sun.COM cfga_err(errstring, CMD_SLOT_CONFIGURE, 0); 705*10923SEvan.Yan@Sun.COM } 706*10923SEvan.Yan@Sun.COM 707*10923SEvan.Yan@Sun.COM break; 708*10923SEvan.Yan@Sun.COM 709*10923SEvan.Yan@Sun.COM case CFGA_CMD_UNCONFIGURE: 710*10923SEvan.Yan@Sun.COM DBG(1, ("unconfigure\n")); 711*10923SEvan.Yan@Sun.COM 712*10923SEvan.Yan@Sun.COM if (state >= DDI_HP_CN_STATE_ENABLED) { 713*10923SEvan.Yan@Sun.COM if ((rv = hp_set_state(node, 0, new_state, &results)) 714*10923SEvan.Yan@Sun.COM != 0) { 715*10923SEvan.Yan@Sun.COM if (rv == EBUSY) 716*10923SEvan.Yan@Sun.COM rv = CFGA_BUSY; 717*10923SEvan.Yan@Sun.COM else 718*10923SEvan.Yan@Sun.COM rv = CFGA_ERROR; 719*10923SEvan.Yan@Sun.COM 720*10923SEvan.Yan@Sun.COM if (results) { 721*10923SEvan.Yan@Sun.COM pci_rcm_info_table(results, errstring); 722*10923SEvan.Yan@Sun.COM hp_fini(results); 723*10923SEvan.Yan@Sun.COM } else { 724*10923SEvan.Yan@Sun.COM cfga_err(errstring, 725*10923SEvan.Yan@Sun.COM CMD_SLOT_UNCONFIGURE, 0); 726*10923SEvan.Yan@Sun.COM } 727*10923SEvan.Yan@Sun.COM } 728*10923SEvan.Yan@Sun.COM } else { 729*10923SEvan.Yan@Sun.COM cfga_err(errstring, ERR_AP_ERR, 0); 730*10923SEvan.Yan@Sun.COM rv = CFGA_INVAL; 731*10923SEvan.Yan@Sun.COM } 732*10923SEvan.Yan@Sun.COM 733*10923SEvan.Yan@Sun.COM DBG(1, ("unconfigure rv:(%i)\n", rv)); 734*10923SEvan.Yan@Sun.COM break; 735*10923SEvan.Yan@Sun.COM 736*10923SEvan.Yan@Sun.COM case CFGA_CMD_LOAD: 737*10923SEvan.Yan@Sun.COM /* do nothing, just produce error msg as is */ 738*10923SEvan.Yan@Sun.COM if (state < DDI_HP_CN_STATE_POWERED) { 739*10923SEvan.Yan@Sun.COM rv = CFGA_ERROR; 740*10923SEvan.Yan@Sun.COM cfga_err(errstring, CMD_SLOT_INSERT, 0); 741*10923SEvan.Yan@Sun.COM } else { 742*10923SEvan.Yan@Sun.COM cfga_err(errstring, ERR_AP_ERR, 0); 743*10923SEvan.Yan@Sun.COM rv = CFGA_INVAL; 744*10923SEvan.Yan@Sun.COM } 745*10923SEvan.Yan@Sun.COM break; 746*10923SEvan.Yan@Sun.COM 747*10923SEvan.Yan@Sun.COM case CFGA_CMD_UNLOAD: 748*10923SEvan.Yan@Sun.COM /* do nothing, just produce error msg as is */ 749*10923SEvan.Yan@Sun.COM if (state < DDI_HP_CN_STATE_POWERED) { 750*10923SEvan.Yan@Sun.COM rv = CFGA_ERROR; 751*10923SEvan.Yan@Sun.COM cfga_err(errstring, CMD_SLOT_REMOVE, 0); 752*10923SEvan.Yan@Sun.COM } else { 753*10923SEvan.Yan@Sun.COM cfga_err(errstring, ERR_AP_ERR, 0); 754*10923SEvan.Yan@Sun.COM rv = CFGA_INVAL; 755*10923SEvan.Yan@Sun.COM } 756*10923SEvan.Yan@Sun.COM break; 757*10923SEvan.Yan@Sun.COM 758*10923SEvan.Yan@Sun.COM default: 759*10923SEvan.Yan@Sun.COM rv = CFGA_OPNOTSUPP; 760*10923SEvan.Yan@Sun.COM break; 761*10923SEvan.Yan@Sun.COM } 762*10923SEvan.Yan@Sun.COM 763*10923SEvan.Yan@Sun.COM hp_fini(node); 764*10923SEvan.Yan@Sun.COM return (rv); 765*10923SEvan.Yan@Sun.COM } 766*10923SEvan.Yan@Sun.COM 767*10923SEvan.Yan@Sun.COM char * 768*10923SEvan.Yan@Sun.COM get_val_from_result(char *result) 769*10923SEvan.Yan@Sun.COM { 770*10923SEvan.Yan@Sun.COM char *tmp; 771*10923SEvan.Yan@Sun.COM 772*10923SEvan.Yan@Sun.COM tmp = strchr(result, '='); 773*10923SEvan.Yan@Sun.COM if (tmp == NULL) 774*10923SEvan.Yan@Sun.COM return (NULL); 775*10923SEvan.Yan@Sun.COM 776*10923SEvan.Yan@Sun.COM tmp++; 777*10923SEvan.Yan@Sun.COM return (tmp); 778*10923SEvan.Yan@Sun.COM } 779*10923SEvan.Yan@Sun.COM 780*10923SEvan.Yan@Sun.COM static cfga_err_t 781*10923SEvan.Yan@Sun.COM prt_led_mode(const char *ap_id, int repeat, char **errstring, 782*10923SEvan.Yan@Sun.COM struct cfga_msg *msgp) 783*10923SEvan.Yan@Sun.COM { 784*10923SEvan.Yan@Sun.COM pciehpc_led_t led; 785*10923SEvan.Yan@Sun.COM hp_node_t node; 786*10923SEvan.Yan@Sun.COM char *buff; 787*10923SEvan.Yan@Sun.COM char *buf; 788*10923SEvan.Yan@Sun.COM char *cp, line[MAXLINE]; 789*10923SEvan.Yan@Sun.COM char *tmp; 790*10923SEvan.Yan@Sun.COM char *format; 791*10923SEvan.Yan@Sun.COM char *result; 792*10923SEvan.Yan@Sun.COM int i, n, rv; 793*10923SEvan.Yan@Sun.COM int len = MAXLINE; 794*10923SEvan.Yan@Sun.COM 795*10923SEvan.Yan@Sun.COM pciehpc_led_t states[] = { 796*10923SEvan.Yan@Sun.COM PCIEHPC_POWER_LED, 797*10923SEvan.Yan@Sun.COM PCIEHPC_FAULT_LED, 798*10923SEvan.Yan@Sun.COM PCIEHPC_ATTN_LED, 799*10923SEvan.Yan@Sun.COM PCIEHPC_ACTIVE_LED 800*10923SEvan.Yan@Sun.COM }; 801*10923SEvan.Yan@Sun.COM 802*10923SEvan.Yan@Sun.COM DBG(1, ("prt_led_mod function\n")); 803*10923SEvan.Yan@Sun.COM if (!repeat) 804*10923SEvan.Yan@Sun.COM cfga_msg(msgp, "Ap_Id\t\t\tLed"); 805*10923SEvan.Yan@Sun.COM 806*10923SEvan.Yan@Sun.COM rv = physpath2node(ap_id, errstring, &node); 807*10923SEvan.Yan@Sun.COM if (rv != CFGA_OK) 808*10923SEvan.Yan@Sun.COM return (rv); 809*10923SEvan.Yan@Sun.COM 810*10923SEvan.Yan@Sun.COM if ((buff = malloc(MAXPATHLEN)) == NULL) { 811*10923SEvan.Yan@Sun.COM hp_fini(node); 812*10923SEvan.Yan@Sun.COM cfga_err(errstring, "malloc ", 0); 813*10923SEvan.Yan@Sun.COM return (CFGA_ERROR); 814*10923SEvan.Yan@Sun.COM } 815*10923SEvan.Yan@Sun.COM 816*10923SEvan.Yan@Sun.COM (void) memset(buff, 0, MAXPATHLEN); 817*10923SEvan.Yan@Sun.COM 818*10923SEvan.Yan@Sun.COM if (fix_ap_name(buff, ap_id, hp_name(node), 819*10923SEvan.Yan@Sun.COM errstring) != CFGA_OK) { 820*10923SEvan.Yan@Sun.COM hp_fini(node); 821*10923SEvan.Yan@Sun.COM free(buff); 822*10923SEvan.Yan@Sun.COM return (CFGA_ERROR); 823*10923SEvan.Yan@Sun.COM } 824*10923SEvan.Yan@Sun.COM 825*10923SEvan.Yan@Sun.COM cp = line; 826*10923SEvan.Yan@Sun.COM (void) snprintf(cp, len, "%s\t\t", buff); 827*10923SEvan.Yan@Sun.COM len -= strlen(cp); 828*10923SEvan.Yan@Sun.COM cp += strlen(cp); 829*10923SEvan.Yan@Sun.COM 830*10923SEvan.Yan@Sun.COM free(buff); 831*10923SEvan.Yan@Sun.COM 832*10923SEvan.Yan@Sun.COM n = sizeof (states)/sizeof (pciehpc_led_t); 833*10923SEvan.Yan@Sun.COM for (i = 0; i < n; i++) { 834*10923SEvan.Yan@Sun.COM led = states[i]; 835*10923SEvan.Yan@Sun.COM 836*10923SEvan.Yan@Sun.COM format = (i == n - 1) ? "%s=%s" : "%s=%s,"; 837*10923SEvan.Yan@Sun.COM if (hp_get_private(node, led_strs2[led], &result) != 0) { 838*10923SEvan.Yan@Sun.COM (void) snprintf(cp, len, format, 839*10923SEvan.Yan@Sun.COM led_strs[led], cfga_strs[UNKNOWN]); 840*10923SEvan.Yan@Sun.COM len -= strlen(cp); 841*10923SEvan.Yan@Sun.COM cp += strlen(cp); 842*10923SEvan.Yan@Sun.COM DBG(1, ("%s:%s\n", led_strs[led], cfga_strs[UNKNOWN])); 843*10923SEvan.Yan@Sun.COM } else { 844*10923SEvan.Yan@Sun.COM /* 845*10923SEvan.Yan@Sun.COM * hp_get_private() will return back things like 846*10923SEvan.Yan@Sun.COM * "led_fault=off", transform it to cfgadm desired 847*10923SEvan.Yan@Sun.COM * format. 848*10923SEvan.Yan@Sun.COM */ 849*10923SEvan.Yan@Sun.COM tmp = get_val_from_result(result); 850*10923SEvan.Yan@Sun.COM if (tmp == NULL) { 851*10923SEvan.Yan@Sun.COM free(result); 852*10923SEvan.Yan@Sun.COM hp_fini(node); 853*10923SEvan.Yan@Sun.COM return (CFGA_ERROR); 854*10923SEvan.Yan@Sun.COM } 855*10923SEvan.Yan@Sun.COM 856*10923SEvan.Yan@Sun.COM (void) snprintf(cp, len, format, 857*10923SEvan.Yan@Sun.COM led_strs[led], tmp); 858*10923SEvan.Yan@Sun.COM len -= strlen(cp); 859*10923SEvan.Yan@Sun.COM cp += strlen(cp); 860*10923SEvan.Yan@Sun.COM DBG(1, ("%s:%s\n", led_strs[led], tmp)); 861*10923SEvan.Yan@Sun.COM free(result); 862*10923SEvan.Yan@Sun.COM } 863*10923SEvan.Yan@Sun.COM } 864*10923SEvan.Yan@Sun.COM 865*10923SEvan.Yan@Sun.COM cfga_msg(msgp, line); /* print the message */ 866*10923SEvan.Yan@Sun.COM 867*10923SEvan.Yan@Sun.COM hp_fini(node); 868*10923SEvan.Yan@Sun.COM 869*10923SEvan.Yan@Sun.COM return (CFGA_OK); 870*10923SEvan.Yan@Sun.COM } 871*10923SEvan.Yan@Sun.COM 872*10923SEvan.Yan@Sun.COM /*ARGSUSED*/ 873*10923SEvan.Yan@Sun.COM cfga_err_t 874*10923SEvan.Yan@Sun.COM cfga_private_func(const char *function, const char *ap_id, 875*10923SEvan.Yan@Sun.COM const char *options, struct cfga_confirm *confp, 876*10923SEvan.Yan@Sun.COM struct cfga_msg *msgp, char **errstring, cfga_flags_t flags) 877*10923SEvan.Yan@Sun.COM { 878*10923SEvan.Yan@Sun.COM char *str; 879*10923SEvan.Yan@Sun.COM int len, fd, i = 0, repeat = 0; 880*10923SEvan.Yan@Sun.COM char buf[MAXNAMELEN]; 881*10923SEvan.Yan@Sun.COM char ptr; 882*10923SEvan.Yan@Sun.COM cfga_err_t rv; 883*10923SEvan.Yan@Sun.COM char *led, *mode; 884*10923SEvan.Yan@Sun.COM hp_node_t node; 885*10923SEvan.Yan@Sun.COM char *result; 886*10923SEvan.Yan@Sun.COM 887*10923SEvan.Yan@Sun.COM DBG(1, ("cfgadm_private_func: ap_id:%s\n", ap_id)); 888*10923SEvan.Yan@Sun.COM DBG(2, (" options: %s\n", (options == NULL)?"null":options)); 889*10923SEvan.Yan@Sun.COM DBG(2, (" confp: %x\n", confp)); 890*10923SEvan.Yan@Sun.COM DBG(2, (" cfga_msg: %x\n", cfga_msg)); 891*10923SEvan.Yan@Sun.COM DBG(2, (" flag: %d\n", flags)); 892*10923SEvan.Yan@Sun.COM 893*10923SEvan.Yan@Sun.COM if ((rv = check_options(options)) != CFGA_OK) { 894*10923SEvan.Yan@Sun.COM return (rv); 895*10923SEvan.Yan@Sun.COM } 896*10923SEvan.Yan@Sun.COM 897*10923SEvan.Yan@Sun.COM if (private_check == confp) 898*10923SEvan.Yan@Sun.COM repeat = 1; 899*10923SEvan.Yan@Sun.COM else 900*10923SEvan.Yan@Sun.COM private_check = (void*)confp; 901*10923SEvan.Yan@Sun.COM 902*10923SEvan.Yan@Sun.COM for (i = 0, str = func_strs[i], len = strlen(str); 903*10923SEvan.Yan@Sun.COM func_strs[i] != NULL; i++) { 904*10923SEvan.Yan@Sun.COM str = func_strs[i]; 905*10923SEvan.Yan@Sun.COM len = strlen(str); 906*10923SEvan.Yan@Sun.COM if (strncmp(function, str, len) == 0) 907*10923SEvan.Yan@Sun.COM break; 908*10923SEvan.Yan@Sun.COM } 909*10923SEvan.Yan@Sun.COM 910*10923SEvan.Yan@Sun.COM switch (i) { 911*10923SEvan.Yan@Sun.COM case ENABLE_SLOT: 912*10923SEvan.Yan@Sun.COM case DISABLE_SLOT: 913*10923SEvan.Yan@Sun.COM /* pass through */ 914*10923SEvan.Yan@Sun.COM case ENABLE_AUTOCNF: 915*10923SEvan.Yan@Sun.COM case DISABLE_AUTOCNF: 916*10923SEvan.Yan@Sun.COM /* no action needed */ 917*10923SEvan.Yan@Sun.COM return (CFGA_OK); 918*10923SEvan.Yan@Sun.COM break; 919*10923SEvan.Yan@Sun.COM case LED: 920*10923SEvan.Yan@Sun.COM /* set mode */ 921*10923SEvan.Yan@Sun.COM ptr = function[len++]; 922*10923SEvan.Yan@Sun.COM if (ptr == '=') { 923*10923SEvan.Yan@Sun.COM str = (char *)function; 924*10923SEvan.Yan@Sun.COM for (str = (str+len++), i = 0; *str != ','; 925*10923SEvan.Yan@Sun.COM i++, str++) { 926*10923SEvan.Yan@Sun.COM if (i == (MAXNAMELEN - 1)) 927*10923SEvan.Yan@Sun.COM break; 928*10923SEvan.Yan@Sun.COM 929*10923SEvan.Yan@Sun.COM buf[i] = *str; 930*10923SEvan.Yan@Sun.COM DBG_F(2, (stdout, "%c\n", buf[i])); 931*10923SEvan.Yan@Sun.COM } 932*10923SEvan.Yan@Sun.COM buf[i] = '\0'; str++; 933*10923SEvan.Yan@Sun.COM DBG(2, ("buf = %s\n", buf)); 934*10923SEvan.Yan@Sun.COM 935*10923SEvan.Yan@Sun.COM /* ACTIVE=3,ATTN=2,POWER=1,FAULT=0 */ 936*10923SEvan.Yan@Sun.COM if (strcmp(buf, led_strs[POWER]) == 0) 937*10923SEvan.Yan@Sun.COM led = PCIEHPC_PROP_LED_POWER; 938*10923SEvan.Yan@Sun.COM else if (strcmp(buf, led_strs[FAULT]) == 0) 939*10923SEvan.Yan@Sun.COM led = PCIEHPC_PROP_LED_FAULT; 940*10923SEvan.Yan@Sun.COM else if (strcmp(buf, led_strs[ATTN]) == 0) 941*10923SEvan.Yan@Sun.COM led = PCIEHPC_PROP_LED_ATTN; 942*10923SEvan.Yan@Sun.COM else if (strcmp(buf, led_strs[ACTIVE]) == 0) 943*10923SEvan.Yan@Sun.COM led = PCIEHPC_PROP_LED_ACTIVE; 944*10923SEvan.Yan@Sun.COM else return (CFGA_INVAL); 945*10923SEvan.Yan@Sun.COM 946*10923SEvan.Yan@Sun.COM len = strlen(func_strs[MODE]); 947*10923SEvan.Yan@Sun.COM if ((strncmp(str, func_strs[MODE], len) == 0) && 948*10923SEvan.Yan@Sun.COM (*(str+(len)) == '=')) { 949*10923SEvan.Yan@Sun.COM for (str = (str+(++len)), i = 0; 950*10923SEvan.Yan@Sun.COM *str != NULL; i++, str++) { 951*10923SEvan.Yan@Sun.COM buf[i] = *str; 952*10923SEvan.Yan@Sun.COM } 953*10923SEvan.Yan@Sun.COM } 954*10923SEvan.Yan@Sun.COM buf[i] = '\0'; 955*10923SEvan.Yan@Sun.COM DBG(2, ("buf_mode= %s\n", buf)); 956*10923SEvan.Yan@Sun.COM 957*10923SEvan.Yan@Sun.COM /* ON = 1, OFF = 0 */ 958*10923SEvan.Yan@Sun.COM if (strcmp(buf, mode_strs[ON]) == 0) 959*10923SEvan.Yan@Sun.COM mode = PCIEHPC_PROP_VALUE_ON; 960*10923SEvan.Yan@Sun.COM else if (strcmp(buf, mode_strs[OFF]) == 0) 961*10923SEvan.Yan@Sun.COM mode = PCIEHPC_PROP_VALUE_OFF; 962*10923SEvan.Yan@Sun.COM else if (strcmp(buf, mode_strs[BLINK]) == 0) 963*10923SEvan.Yan@Sun.COM mode = PCIEHPC_PROP_VALUE_BLINK; 964*10923SEvan.Yan@Sun.COM else return (CFGA_INVAL); 965*10923SEvan.Yan@Sun.COM 966*10923SEvan.Yan@Sun.COM /* sendin */ 967*10923SEvan.Yan@Sun.COM memset(buf, 0, sizeof (buf)); 968*10923SEvan.Yan@Sun.COM snprintf(buf, sizeof (buf), "%s=%s", 969*10923SEvan.Yan@Sun.COM led, mode); 970*10923SEvan.Yan@Sun.COM buf[MAXNAMELEN - 1] = '\0'; 971*10923SEvan.Yan@Sun.COM 972*10923SEvan.Yan@Sun.COM break; 973*10923SEvan.Yan@Sun.COM } else if (ptr == '\0') { 974*10923SEvan.Yan@Sun.COM /* print mode */ 975*10923SEvan.Yan@Sun.COM DBG(1, ("Print mode\n")); 976*10923SEvan.Yan@Sun.COM return (prt_led_mode(ap_id, repeat, errstring, 977*10923SEvan.Yan@Sun.COM msgp)); 978*10923SEvan.Yan@Sun.COM } 979*10923SEvan.Yan@Sun.COM default: 980*10923SEvan.Yan@Sun.COM DBG(1, ("default\n")); 981*10923SEvan.Yan@Sun.COM errno = EINVAL; 982*10923SEvan.Yan@Sun.COM return (CFGA_INVAL); 983*10923SEvan.Yan@Sun.COM } 984*10923SEvan.Yan@Sun.COM 985*10923SEvan.Yan@Sun.COM rv = physpath2node(ap_id, errstring, &node); 986*10923SEvan.Yan@Sun.COM if (rv != CFGA_OK) 987*10923SEvan.Yan@Sun.COM return (rv); 988*10923SEvan.Yan@Sun.COM 989*10923SEvan.Yan@Sun.COM if (hp_set_private(node, buf, &result) != 0) { 990*10923SEvan.Yan@Sun.COM hp_fini(node); 991*10923SEvan.Yan@Sun.COM return (CFGA_ERROR); 992*10923SEvan.Yan@Sun.COM } 993*10923SEvan.Yan@Sun.COM 994*10923SEvan.Yan@Sun.COM hp_fini(node); 995*10923SEvan.Yan@Sun.COM return (CFGA_OK); 996*10923SEvan.Yan@Sun.COM } 997*10923SEvan.Yan@Sun.COM 998*10923SEvan.Yan@Sun.COM /*ARGSUSED*/ 999*10923SEvan.Yan@Sun.COM cfga_err_t cfga_test(const char *ap_id, const char *options, 1000*10923SEvan.Yan@Sun.COM struct cfga_msg *msgp, char **errstring, cfga_flags_t flags) 1001*10923SEvan.Yan@Sun.COM { 1002*10923SEvan.Yan@Sun.COM cfga_err_t rv; 1003*10923SEvan.Yan@Sun.COM if (errstring != NULL) 1004*10923SEvan.Yan@Sun.COM *errstring = NULL; 1005*10923SEvan.Yan@Sun.COM 1006*10923SEvan.Yan@Sun.COM if ((rv = check_options(options)) != CFGA_OK) { 1007*10923SEvan.Yan@Sun.COM return (rv); 1008*10923SEvan.Yan@Sun.COM } 1009*10923SEvan.Yan@Sun.COM 1010*10923SEvan.Yan@Sun.COM DBG(1, ("cfga_test:(%s)\n", ap_id)); 1011*10923SEvan.Yan@Sun.COM /* will need to implement pci CTRL command */ 1012*10923SEvan.Yan@Sun.COM return (CFGA_NOTSUPP); 1013*10923SEvan.Yan@Sun.COM } 1014*10923SEvan.Yan@Sun.COM 1015*10923SEvan.Yan@Sun.COM /* 1016*10923SEvan.Yan@Sun.COM * The slot-names property describes the external labeling of add-in slots. 1017*10923SEvan.Yan@Sun.COM * This property is an encoded array, an integer followed by a list of 1018*10923SEvan.Yan@Sun.COM * strings. The return value from di_prop_lookup_ints for slot-names is -1. 1019*10923SEvan.Yan@Sun.COM * The expected return value should be the number of elements. 1020*10923SEvan.Yan@Sun.COM * Di_prop_decode_common does not decode encoded data from software, 1021*10923SEvan.Yan@Sun.COM * such as the solaris device tree, unlike from the prom. 1022*10923SEvan.Yan@Sun.COM * Di_prop_decode_common takes the size of the encoded data and mods 1023*10923SEvan.Yan@Sun.COM * it with the size of int. The size of the encoded data for slot-names is 9 1024*10923SEvan.Yan@Sun.COM * and the size of int is 4, yielding a non zero result. A value of -1 is used 1025*10923SEvan.Yan@Sun.COM * to indicate that the number of elements can not be determined. 1026*10923SEvan.Yan@Sun.COM * Di_prop_decode_common can be modified to decode encoded data from the solaris 1027*10923SEvan.Yan@Sun.COM * device tree. 1028*10923SEvan.Yan@Sun.COM */ 1029*10923SEvan.Yan@Sun.COM static int 1030*10923SEvan.Yan@Sun.COM fixup_slotname(int rval, int *intp, struct searcharg *slotarg) 1031*10923SEvan.Yan@Sun.COM { 1032*10923SEvan.Yan@Sun.COM if ((slotarg->slt_name_src == PROM_SLT_NAME) && (rval == -1)) { 1033*10923SEvan.Yan@Sun.COM return (DI_WALK_TERMINATE); 1034*10923SEvan.Yan@Sun.COM } else { 1035*10923SEvan.Yan@Sun.COM int i; 1036*10923SEvan.Yan@Sun.COM char *tmptr = (char *)(intp+1); 1037*10923SEvan.Yan@Sun.COM DBG(1, ("slot-bitmask: %x \n", *intp)); 1038*10923SEvan.Yan@Sun.COM 1039*10923SEvan.Yan@Sun.COM rval = (rval -1) * 4; 1040*10923SEvan.Yan@Sun.COM 1041*10923SEvan.Yan@Sun.COM for (i = 0; i <= slotarg->minor; i++) { 1042*10923SEvan.Yan@Sun.COM DBG(2, ("curr slot-name: %s \n", tmptr)); 1043*10923SEvan.Yan@Sun.COM 1044*10923SEvan.Yan@Sun.COM if (i >= MAXDEVS) 1045*10923SEvan.Yan@Sun.COM return (DI_WALK_TERMINATE); 1046*10923SEvan.Yan@Sun.COM 1047*10923SEvan.Yan@Sun.COM if ((*intp >> i) & 1) { 1048*10923SEvan.Yan@Sun.COM /* assign tmptr */ 1049*10923SEvan.Yan@Sun.COM DBG(2, ("slot-name: %s \n", tmptr)); 1050*10923SEvan.Yan@Sun.COM if (i == slotarg->minor) 1051*10923SEvan.Yan@Sun.COM (void) strcpy(slotarg->slotnames[i], 1052*10923SEvan.Yan@Sun.COM tmptr); 1053*10923SEvan.Yan@Sun.COM /* wind tmptr to next \0 */ 1054*10923SEvan.Yan@Sun.COM while (*tmptr != '\0') { 1055*10923SEvan.Yan@Sun.COM tmptr++; 1056*10923SEvan.Yan@Sun.COM } 1057*10923SEvan.Yan@Sun.COM tmptr++; 1058*10923SEvan.Yan@Sun.COM } else { 1059*10923SEvan.Yan@Sun.COM /* point at unknown string */ 1060*10923SEvan.Yan@Sun.COM if (i == slotarg->minor) 1061*10923SEvan.Yan@Sun.COM (void) strcpy(slotarg->slotnames[i], 1062*10923SEvan.Yan@Sun.COM "unknown"); 1063*10923SEvan.Yan@Sun.COM } 1064*10923SEvan.Yan@Sun.COM } 1065*10923SEvan.Yan@Sun.COM } 1066*10923SEvan.Yan@Sun.COM return (DI_WALK_TERMINATE); 1067*10923SEvan.Yan@Sun.COM } 1068*10923SEvan.Yan@Sun.COM 1069*10923SEvan.Yan@Sun.COM static int 1070*10923SEvan.Yan@Sun.COM find_slotname(di_node_t din, di_minor_t dim, void *arg) 1071*10923SEvan.Yan@Sun.COM { 1072*10923SEvan.Yan@Sun.COM struct searcharg *slotarg = (struct searcharg *)arg; 1073*10923SEvan.Yan@Sun.COM di_prom_handle_t ph = (di_prom_handle_t)slotarg->promp; 1074*10923SEvan.Yan@Sun.COM di_prom_prop_t prom_prop; 1075*10923SEvan.Yan@Sun.COM di_prop_t solaris_prop; 1076*10923SEvan.Yan@Sun.COM int *intp, rval; 1077*10923SEvan.Yan@Sun.COM char *devname; 1078*10923SEvan.Yan@Sun.COM char fulldevname[MAXNAMELEN]; 1079*10923SEvan.Yan@Sun.COM 1080*10923SEvan.Yan@Sun.COM slotarg->minor = dim->dev_minor % 256; 1081*10923SEvan.Yan@Sun.COM 1082*10923SEvan.Yan@Sun.COM DBG(2, ("minor number:(%i)\n", slotarg->minor)); 1083*10923SEvan.Yan@Sun.COM DBG(2, ("hot plug slots found so far:(%i)\n", 0)); 1084*10923SEvan.Yan@Sun.COM 1085*10923SEvan.Yan@Sun.COM if ((devname = di_devfs_path(din)) != NULL) { 1086*10923SEvan.Yan@Sun.COM (void) snprintf(fulldevname, MAXNAMELEN, 1087*10923SEvan.Yan@Sun.COM "/devices%s:%s", devname, di_minor_name(dim)); 1088*10923SEvan.Yan@Sun.COM di_devfs_path_free(devname); 1089*10923SEvan.Yan@Sun.COM } 1090*10923SEvan.Yan@Sun.COM 1091*10923SEvan.Yan@Sun.COM if (strcmp(fulldevname, slotarg->devpath) == 0) { 1092*10923SEvan.Yan@Sun.COM 1093*10923SEvan.Yan@Sun.COM /* 1094*10923SEvan.Yan@Sun.COM * Check the Solaris device tree first 1095*10923SEvan.Yan@Sun.COM * in the case of a DR operation 1096*10923SEvan.Yan@Sun.COM */ 1097*10923SEvan.Yan@Sun.COM solaris_prop = di_prop_hw_next(din, DI_PROP_NIL); 1098*10923SEvan.Yan@Sun.COM while (solaris_prop != DI_PROP_NIL) { 1099*10923SEvan.Yan@Sun.COM if (strcmp("slot-names", di_prop_name(solaris_prop)) 1100*10923SEvan.Yan@Sun.COM == 0) { 1101*10923SEvan.Yan@Sun.COM rval = di_prop_lookup_ints(DDI_DEV_T_ANY, 1102*10923SEvan.Yan@Sun.COM din, di_prop_name(solaris_prop), &intp); 1103*10923SEvan.Yan@Sun.COM slotarg->slt_name_src = SOLARIS_SLT_NAME; 1104*10923SEvan.Yan@Sun.COM 1105*10923SEvan.Yan@Sun.COM return (fixup_slotname(rval, intp, slotarg)); 1106*10923SEvan.Yan@Sun.COM } 1107*10923SEvan.Yan@Sun.COM solaris_prop = di_prop_hw_next(din, solaris_prop); 1108*10923SEvan.Yan@Sun.COM } 1109*10923SEvan.Yan@Sun.COM 1110*10923SEvan.Yan@Sun.COM /* 1111*10923SEvan.Yan@Sun.COM * Check the prom device tree which is populated at boot. 1112*10923SEvan.Yan@Sun.COM * If this fails, give up and set the slot name to null. 1113*10923SEvan.Yan@Sun.COM */ 1114*10923SEvan.Yan@Sun.COM prom_prop = di_prom_prop_next(ph, din, DI_PROM_PROP_NIL); 1115*10923SEvan.Yan@Sun.COM while (prom_prop != DI_PROM_PROP_NIL) { 1116*10923SEvan.Yan@Sun.COM if (strcmp("slot-names", di_prom_prop_name(prom_prop)) 1117*10923SEvan.Yan@Sun.COM == 0) { 1118*10923SEvan.Yan@Sun.COM rval = di_prom_prop_lookup_ints(ph, 1119*10923SEvan.Yan@Sun.COM din, di_prom_prop_name(prom_prop), &intp); 1120*10923SEvan.Yan@Sun.COM slotarg->slt_name_src = PROM_SLT_NAME; 1121*10923SEvan.Yan@Sun.COM 1122*10923SEvan.Yan@Sun.COM return (fixup_slotname(rval, intp, slotarg)); 1123*10923SEvan.Yan@Sun.COM } 1124*10923SEvan.Yan@Sun.COM prom_prop = di_prom_prop_next(ph, din, prom_prop); 1125*10923SEvan.Yan@Sun.COM } 1126*10923SEvan.Yan@Sun.COM *slotarg->slotnames[slotarg->minor] = '\0'; 1127*10923SEvan.Yan@Sun.COM return (DI_WALK_TERMINATE); 1128*10923SEvan.Yan@Sun.COM } else 1129*10923SEvan.Yan@Sun.COM return (DI_WALK_CONTINUE); 1130*10923SEvan.Yan@Sun.COM } 1131*10923SEvan.Yan@Sun.COM 1132*10923SEvan.Yan@Sun.COM static int 1133*10923SEvan.Yan@Sun.COM find_physical_slot_names(const char *devcomp, struct searcharg *slotarg) 1134*10923SEvan.Yan@Sun.COM { 1135*10923SEvan.Yan@Sun.COM di_node_t root_node; 1136*10923SEvan.Yan@Sun.COM 1137*10923SEvan.Yan@Sun.COM DBG(1, ("find_physical_slot_names\n")); 1138*10923SEvan.Yan@Sun.COM 1139*10923SEvan.Yan@Sun.COM if ((root_node = di_init("/", DINFOCPYALL|DINFOPATH)) 1140*10923SEvan.Yan@Sun.COM == DI_NODE_NIL) { 1141*10923SEvan.Yan@Sun.COM DBG(1, ("di_init() failed\n")); 1142*10923SEvan.Yan@Sun.COM return (-1); 1143*10923SEvan.Yan@Sun.COM } 1144*10923SEvan.Yan@Sun.COM 1145*10923SEvan.Yan@Sun.COM slotarg->devpath = (char *)devcomp; 1146*10923SEvan.Yan@Sun.COM 1147*10923SEvan.Yan@Sun.COM if ((slotarg->promp = di_prom_init()) == DI_PROM_HANDLE_NIL) { 1148*10923SEvan.Yan@Sun.COM DBG(1, ("di_prom_init() failed\n")); 1149*10923SEvan.Yan@Sun.COM di_fini(root_node); 1150*10923SEvan.Yan@Sun.COM return (-1); 1151*10923SEvan.Yan@Sun.COM } 1152*10923SEvan.Yan@Sun.COM 1153*10923SEvan.Yan@Sun.COM (void) di_walk_minor(root_node, "ddi_ctl:attachment_point:pci", 1154*10923SEvan.Yan@Sun.COM 0, (void *)slotarg, find_slotname); 1155*10923SEvan.Yan@Sun.COM 1156*10923SEvan.Yan@Sun.COM di_prom_fini(slotarg->promp); 1157*10923SEvan.Yan@Sun.COM di_fini(root_node); 1158*10923SEvan.Yan@Sun.COM if (slotarg->slotnames[0] != NULL) 1159*10923SEvan.Yan@Sun.COM return (0); 1160*10923SEvan.Yan@Sun.COM else 1161*10923SEvan.Yan@Sun.COM return (-1); 1162*10923SEvan.Yan@Sun.COM } 1163*10923SEvan.Yan@Sun.COM 1164*10923SEvan.Yan@Sun.COM static void 1165*10923SEvan.Yan@Sun.COM get_type(const char *boardtype, const char *cardtype, char *buf) 1166*10923SEvan.Yan@Sun.COM { 1167*10923SEvan.Yan@Sun.COM /* for type string assembly in get_type() */ 1168*10923SEvan.Yan@Sun.COM #define TPCT(s) (void) strlcat(buf, (s), CFGA_TYPE_LEN) 1169*10923SEvan.Yan@Sun.COM 1170*10923SEvan.Yan@Sun.COM int i; 1171*10923SEvan.Yan@Sun.COM 1172*10923SEvan.Yan@Sun.COM if (strcmp(cardtype, "unknown") == 0) { 1173*10923SEvan.Yan@Sun.COM TPCT("unknown"); 1174*10923SEvan.Yan@Sun.COM return; 1175*10923SEvan.Yan@Sun.COM } 1176*10923SEvan.Yan@Sun.COM 1177*10923SEvan.Yan@Sun.COM TPCT(cardtype); 1178*10923SEvan.Yan@Sun.COM TPCT("/"); 1179*10923SEvan.Yan@Sun.COM 1180*10923SEvan.Yan@Sun.COM if (strcmp(boardtype, PCIEHPC_PROP_VALUE_PCIHOTPLUG) == 0) 1181*10923SEvan.Yan@Sun.COM TPCT(board_strs[PCIEHPC_BOARD_PCI_HOTPLUG]); 1182*10923SEvan.Yan@Sun.COM else 1183*10923SEvan.Yan@Sun.COM TPCT(board_strs[PCIEHPC_BOARD_UNKNOWN]); 1184*10923SEvan.Yan@Sun.COM } 1185*10923SEvan.Yan@Sun.COM 1186*10923SEvan.Yan@Sun.COM /* 1187*10923SEvan.Yan@Sun.COM * call-back function for di_devlink_walk 1188*10923SEvan.Yan@Sun.COM * if the link lives in /dev/cfg copy its name 1189*10923SEvan.Yan@Sun.COM */ 1190*10923SEvan.Yan@Sun.COM static int 1191*10923SEvan.Yan@Sun.COM found_devlink(di_devlink_t link, void *ap_log_id) 1192*10923SEvan.Yan@Sun.COM { 1193*10923SEvan.Yan@Sun.COM if (strncmp("/dev/cfg/", di_devlink_path(link), 9) == 0) { 1194*10923SEvan.Yan@Sun.COM /* copy everything but /dev/cfg/ */ 1195*10923SEvan.Yan@Sun.COM (void) strcpy((char *)ap_log_id, di_devlink_path(link) + 9); 1196*10923SEvan.Yan@Sun.COM DBG(1, ("found_devlink: %s\n", (char *)ap_log_id)); 1197*10923SEvan.Yan@Sun.COM return (DI_WALK_TERMINATE); 1198*10923SEvan.Yan@Sun.COM } 1199*10923SEvan.Yan@Sun.COM return (DI_WALK_CONTINUE); 1200*10923SEvan.Yan@Sun.COM } 1201*10923SEvan.Yan@Sun.COM 1202*10923SEvan.Yan@Sun.COM /* 1203*10923SEvan.Yan@Sun.COM * Walk throught the cached /dev link tree looking for links to the ap 1204*10923SEvan.Yan@Sun.COM * if none are found return an error 1205*10923SEvan.Yan@Sun.COM */ 1206*10923SEvan.Yan@Sun.COM static cfga_err_t 1207*10923SEvan.Yan@Sun.COM check_devlinks(char *ap_log_id, const char *ap_id) 1208*10923SEvan.Yan@Sun.COM { 1209*10923SEvan.Yan@Sun.COM di_devlink_handle_t hdl; 1210*10923SEvan.Yan@Sun.COM 1211*10923SEvan.Yan@Sun.COM DBG(1, ("check_devlinks: %s\n", ap_id)); 1212*10923SEvan.Yan@Sun.COM 1213*10923SEvan.Yan@Sun.COM hdl = di_devlink_init(NULL, 0); 1214*10923SEvan.Yan@Sun.COM 1215*10923SEvan.Yan@Sun.COM if (strncmp("/devices/", ap_id, 9) == 0) { 1216*10923SEvan.Yan@Sun.COM /* ap_id is a valid minor_path with /devices prepended */ 1217*10923SEvan.Yan@Sun.COM (void) di_devlink_walk(hdl, NULL, ap_id + 8, DI_PRIMARY_LINK, 1218*10923SEvan.Yan@Sun.COM (void *)ap_log_id, found_devlink); 1219*10923SEvan.Yan@Sun.COM } else { 1220*10923SEvan.Yan@Sun.COM DBG(1, ("check_devlinks: invalid ap_id: %s\n", ap_id)); 1221*10923SEvan.Yan@Sun.COM return (CFGA_ERROR); 1222*10923SEvan.Yan@Sun.COM } 1223*10923SEvan.Yan@Sun.COM 1224*10923SEvan.Yan@Sun.COM (void) di_devlink_fini(&hdl); 1225*10923SEvan.Yan@Sun.COM 1226*10923SEvan.Yan@Sun.COM if (ap_log_id[0] != '\0') 1227*10923SEvan.Yan@Sun.COM return (CFGA_OK); 1228*10923SEvan.Yan@Sun.COM else 1229*10923SEvan.Yan@Sun.COM return (CFGA_ERROR); 1230*10923SEvan.Yan@Sun.COM } 1231*10923SEvan.Yan@Sun.COM 1232*10923SEvan.Yan@Sun.COM /* 1233*10923SEvan.Yan@Sun.COM * most of this is needed to compensate for 1234*10923SEvan.Yan@Sun.COM * differences between various platforms 1235*10923SEvan.Yan@Sun.COM */ 1236*10923SEvan.Yan@Sun.COM static cfga_err_t 1237*10923SEvan.Yan@Sun.COM fix_ap_name(char *ap_log_id, const char *ap_id, char *slot_name, 1238*10923SEvan.Yan@Sun.COM char **errstring) 1239*10923SEvan.Yan@Sun.COM { 1240*10923SEvan.Yan@Sun.COM char *buf; 1241*10923SEvan.Yan@Sun.COM char *tmp; 1242*10923SEvan.Yan@Sun.COM char *ptr; 1243*10923SEvan.Yan@Sun.COM 1244*10923SEvan.Yan@Sun.COM di_node_t ap_node; 1245*10923SEvan.Yan@Sun.COM 1246*10923SEvan.Yan@Sun.COM ap_log_id[0] = '\0'; 1247*10923SEvan.Yan@Sun.COM 1248*10923SEvan.Yan@Sun.COM if (check_devlinks(ap_log_id, ap_id) == CFGA_OK) 1249*10923SEvan.Yan@Sun.COM return (CFGA_OK); 1250*10923SEvan.Yan@Sun.COM 1251*10923SEvan.Yan@Sun.COM DBG(1, ("fix_ap_name: %s\n", ap_id)); 1252*10923SEvan.Yan@Sun.COM 1253*10923SEvan.Yan@Sun.COM if ((buf = malloc(strlen(ap_id) + 1)) == NULL) { 1254*10923SEvan.Yan@Sun.COM DBG(1, ("malloc failed\n")); 1255*10923SEvan.Yan@Sun.COM return (CFGA_ERROR); 1256*10923SEvan.Yan@Sun.COM } 1257*10923SEvan.Yan@Sun.COM (void) strcpy(buf, ap_id); 1258*10923SEvan.Yan@Sun.COM tmp = buf + sizeof ("/devices") - 1; 1259*10923SEvan.Yan@Sun.COM 1260*10923SEvan.Yan@Sun.COM ptr = strchr(tmp, ':'); 1261*10923SEvan.Yan@Sun.COM ptr[0] = '\0'; 1262*10923SEvan.Yan@Sun.COM 1263*10923SEvan.Yan@Sun.COM DBG(1, ("fix_ap_name: %s\n", tmp)); 1264*10923SEvan.Yan@Sun.COM 1265*10923SEvan.Yan@Sun.COM ap_node = di_init(tmp, DINFOMINOR); 1266*10923SEvan.Yan@Sun.COM if (ap_node == DI_NODE_NIL) { 1267*10923SEvan.Yan@Sun.COM cfga_err(errstring, "di_init ", 0); 1268*10923SEvan.Yan@Sun.COM DBG(1, ("fix_ap_name: failed to snapshot node\n")); 1269*10923SEvan.Yan@Sun.COM return (CFGA_ERROR); 1270*10923SEvan.Yan@Sun.COM } 1271*10923SEvan.Yan@Sun.COM 1272*10923SEvan.Yan@Sun.COM (void) snprintf(ap_log_id, strlen(ap_id) + 1, "%s%i:%s", 1273*10923SEvan.Yan@Sun.COM di_driver_name(ap_node), di_instance(ap_node), slot_name); 1274*10923SEvan.Yan@Sun.COM 1275*10923SEvan.Yan@Sun.COM DBG(1, ("fix_ap_name: %s\n", ap_log_id)); 1276*10923SEvan.Yan@Sun.COM 1277*10923SEvan.Yan@Sun.COM di_fini(ap_node); 1278*10923SEvan.Yan@Sun.COM 1279*10923SEvan.Yan@Sun.COM free(buf); 1280*10923SEvan.Yan@Sun.COM return (CFGA_OK); 1281*10923SEvan.Yan@Sun.COM } 1282*10923SEvan.Yan@Sun.COM 1283*10923SEvan.Yan@Sun.COM 1284*10923SEvan.Yan@Sun.COM static int 1285*10923SEvan.Yan@Sun.COM findlink_cb(di_devlink_t devlink, void *arg) 1286*10923SEvan.Yan@Sun.COM { 1287*10923SEvan.Yan@Sun.COM (*(char **)arg) = strdup(di_devlink_path(devlink)); 1288*10923SEvan.Yan@Sun.COM 1289*10923SEvan.Yan@Sun.COM return (DI_WALK_TERMINATE); 1290*10923SEvan.Yan@Sun.COM } 1291*10923SEvan.Yan@Sun.COM 1292*10923SEvan.Yan@Sun.COM /* 1293*10923SEvan.Yan@Sun.COM * returns an allocated string containing the full path to the devlink for 1294*10923SEvan.Yan@Sun.COM * <ap_phys_id> in the devlink database; we expect only one devlink per 1295*10923SEvan.Yan@Sun.COM * <ap_phys_id> so we return the first encountered 1296*10923SEvan.Yan@Sun.COM */ 1297*10923SEvan.Yan@Sun.COM static char * 1298*10923SEvan.Yan@Sun.COM findlink(char *ap_phys_id) 1299*10923SEvan.Yan@Sun.COM { 1300*10923SEvan.Yan@Sun.COM di_devlink_handle_t hdl; 1301*10923SEvan.Yan@Sun.COM char *path = NULL; 1302*10923SEvan.Yan@Sun.COM 1303*10923SEvan.Yan@Sun.COM hdl = di_devlink_init(NULL, 0); 1304*10923SEvan.Yan@Sun.COM 1305*10923SEvan.Yan@Sun.COM if (strncmp("/devices/", ap_phys_id, 9) == 0) 1306*10923SEvan.Yan@Sun.COM ap_phys_id += 8; 1307*10923SEvan.Yan@Sun.COM 1308*10923SEvan.Yan@Sun.COM (void) di_devlink_walk(hdl, "^cfg/.+$", ap_phys_id, DI_PRIMARY_LINK, 1309*10923SEvan.Yan@Sun.COM (void *)&path, findlink_cb); 1310*10923SEvan.Yan@Sun.COM 1311*10923SEvan.Yan@Sun.COM (void) di_devlink_fini(&hdl); 1312*10923SEvan.Yan@Sun.COM return (path); 1313*10923SEvan.Yan@Sun.COM } 1314*10923SEvan.Yan@Sun.COM 1315*10923SEvan.Yan@Sun.COM 1316*10923SEvan.Yan@Sun.COM /* 1317*10923SEvan.Yan@Sun.COM * returns CFGA_OK if it can succesfully retrieve the devlink info associated 1318*10923SEvan.Yan@Sun.COM * with devlink for <ap_phys_id> which will be returned through <ap_info> 1319*10923SEvan.Yan@Sun.COM */ 1320*10923SEvan.Yan@Sun.COM cfga_err_t 1321*10923SEvan.Yan@Sun.COM get_dli(char *dlpath, char *ap_info, int ap_info_sz) 1322*10923SEvan.Yan@Sun.COM { 1323*10923SEvan.Yan@Sun.COM int fd; 1324*10923SEvan.Yan@Sun.COM 1325*10923SEvan.Yan@Sun.COM fd = di_dli_openr(dlpath); 1326*10923SEvan.Yan@Sun.COM if (fd < 0) 1327*10923SEvan.Yan@Sun.COM return (CFGA_ERROR); 1328*10923SEvan.Yan@Sun.COM 1329*10923SEvan.Yan@Sun.COM (void) read(fd, ap_info, ap_info_sz); 1330*10923SEvan.Yan@Sun.COM ap_info[ap_info_sz - 1] = '\0'; 1331*10923SEvan.Yan@Sun.COM 1332*10923SEvan.Yan@Sun.COM di_dli_close(fd); 1333*10923SEvan.Yan@Sun.COM return (CFGA_OK); 1334*10923SEvan.Yan@Sun.COM } 1335*10923SEvan.Yan@Sun.COM 1336*10923SEvan.Yan@Sun.COM static cfga_err_t 1337*10923SEvan.Yan@Sun.COM cfga_get_condition(hp_node_t node, ap_condition_t *cond) 1338*10923SEvan.Yan@Sun.COM { 1339*10923SEvan.Yan@Sun.COM char *condition; 1340*10923SEvan.Yan@Sun.COM 1341*10923SEvan.Yan@Sun.COM /* "condition" bus specific commands */ 1342*10923SEvan.Yan@Sun.COM if (hp_get_private(node, PCIEHPC_PROP_SLOT_CONDITION, 1343*10923SEvan.Yan@Sun.COM &condition) != 0) { 1344*10923SEvan.Yan@Sun.COM *cond = AP_COND_UNKNOWN; 1345*10923SEvan.Yan@Sun.COM return (CFGA_ERROR); 1346*10923SEvan.Yan@Sun.COM } 1347*10923SEvan.Yan@Sun.COM 1348*10923SEvan.Yan@Sun.COM condition = get_val_from_result(condition); 1349*10923SEvan.Yan@Sun.COM 1350*10923SEvan.Yan@Sun.COM if (strcmp(condition, PCIEHPC_PROP_COND_OK) == 0) 1351*10923SEvan.Yan@Sun.COM *cond = AP_COND_OK; 1352*10923SEvan.Yan@Sun.COM else if (strcmp(condition, PCIEHPC_PROP_COND_FAILING) == 0) 1353*10923SEvan.Yan@Sun.COM *cond = AP_COND_FAILING; 1354*10923SEvan.Yan@Sun.COM else if (strcmp(condition, PCIEHPC_PROP_COND_FAILED) == 0) 1355*10923SEvan.Yan@Sun.COM *cond = AP_COND_FAILED; 1356*10923SEvan.Yan@Sun.COM else if (strcmp(condition, PCIEHPC_PROP_COND_UNUSABLE) == 0) 1357*10923SEvan.Yan@Sun.COM *cond = AP_COND_UNUSABLE; 1358*10923SEvan.Yan@Sun.COM else if (strcmp(condition, PCIEHPC_PROP_COND_UNKNOWN) == 0) 1359*10923SEvan.Yan@Sun.COM *cond = AP_COND_UNKNOWN; 1360*10923SEvan.Yan@Sun.COM else 1361*10923SEvan.Yan@Sun.COM return (CFGA_ERROR); 1362*10923SEvan.Yan@Sun.COM 1363*10923SEvan.Yan@Sun.COM return (CFGA_OK); 1364*10923SEvan.Yan@Sun.COM } 1365*10923SEvan.Yan@Sun.COM 1366*10923SEvan.Yan@Sun.COM /*ARGSUSED*/ 1367*10923SEvan.Yan@Sun.COM cfga_err_t 1368*10923SEvan.Yan@Sun.COM cfga_list_ext(const char *ap_id, cfga_list_data_t **cs, 1369*10923SEvan.Yan@Sun.COM int *nlist, const char *options, const char *listopts, char **errstring, 1370*10923SEvan.Yan@Sun.COM cfga_flags_t flags) 1371*10923SEvan.Yan@Sun.COM { 1372*10923SEvan.Yan@Sun.COM char *boardtype; 1373*10923SEvan.Yan@Sun.COM char *cardtype; 1374*10923SEvan.Yan@Sun.COM struct searcharg slotname_arg; 1375*10923SEvan.Yan@Sun.COM int fd; 1376*10923SEvan.Yan@Sun.COM int rv = CFGA_OK; 1377*10923SEvan.Yan@Sun.COM char *dlpath = NULL; 1378*10923SEvan.Yan@Sun.COM hp_node_t node; 1379*10923SEvan.Yan@Sun.COM ap_rstate_t rs; 1380*10923SEvan.Yan@Sun.COM ap_ostate_t os; 1381*10923SEvan.Yan@Sun.COM ap_condition_t cond; 1382*10923SEvan.Yan@Sun.COM 1383*10923SEvan.Yan@Sun.COM if ((rv = check_options(options)) != CFGA_OK) { 1384*10923SEvan.Yan@Sun.COM return (rv); 1385*10923SEvan.Yan@Sun.COM } 1386*10923SEvan.Yan@Sun.COM 1387*10923SEvan.Yan@Sun.COM if (errstring != NULL) 1388*10923SEvan.Yan@Sun.COM *errstring = NULL; 1389*10923SEvan.Yan@Sun.COM 1390*10923SEvan.Yan@Sun.COM DBG(1, ("cfga_list_ext:(%s)\n", ap_id)); 1391*10923SEvan.Yan@Sun.COM 1392*10923SEvan.Yan@Sun.COM if (cs == NULL || nlist == NULL) { 1393*10923SEvan.Yan@Sun.COM rv = CFGA_ERROR; 1394*10923SEvan.Yan@Sun.COM return (rv); 1395*10923SEvan.Yan@Sun.COM } 1396*10923SEvan.Yan@Sun.COM 1397*10923SEvan.Yan@Sun.COM *nlist = 1; 1398*10923SEvan.Yan@Sun.COM 1399*10923SEvan.Yan@Sun.COM if ((*cs = malloc(sizeof (cfga_list_data_t))) == NULL) { 1400*10923SEvan.Yan@Sun.COM cfga_err(errstring, "malloc ", 0); 1401*10923SEvan.Yan@Sun.COM DBG(1, ("malloc failed\n")); 1402*10923SEvan.Yan@Sun.COM rv = CFGA_ERROR; 1403*10923SEvan.Yan@Sun.COM return (rv); 1404*10923SEvan.Yan@Sun.COM } 1405*10923SEvan.Yan@Sun.COM (void) memset(*cs, 0, sizeof (cfga_list_data_t)); 1406*10923SEvan.Yan@Sun.COM 1407*10923SEvan.Yan@Sun.COM rv = physpath2node(ap_id, errstring, &node); 1408*10923SEvan.Yan@Sun.COM if (rv != CFGA_OK) { 1409*10923SEvan.Yan@Sun.COM DBG(1, ("physpath2node failed\n")); 1410*10923SEvan.Yan@Sun.COM return (rv); 1411*10923SEvan.Yan@Sun.COM } 1412*10923SEvan.Yan@Sun.COM 1413*10923SEvan.Yan@Sun.COM if (cfga_get_state(node, &rs, &os) != CFGA_OK) { 1414*10923SEvan.Yan@Sun.COM DBG(1, ("cfga_get_state failed\n")); 1415*10923SEvan.Yan@Sun.COM hp_fini(node); 1416*10923SEvan.Yan@Sun.COM return (CFGA_ERROR); 1417*10923SEvan.Yan@Sun.COM } 1418*10923SEvan.Yan@Sun.COM 1419*10923SEvan.Yan@Sun.COM switch (rs) { 1420*10923SEvan.Yan@Sun.COM case AP_RSTATE_EMPTY: 1421*10923SEvan.Yan@Sun.COM (*cs)->ap_r_state = CFGA_STAT_EMPTY; 1422*10923SEvan.Yan@Sun.COM DBG(2, ("ap_rstate = CFGA_STAT_EMPTY\n")); 1423*10923SEvan.Yan@Sun.COM break; 1424*10923SEvan.Yan@Sun.COM case AP_RSTATE_DISCONNECTED: 1425*10923SEvan.Yan@Sun.COM (*cs)->ap_r_state = CFGA_STAT_DISCONNECTED; 1426*10923SEvan.Yan@Sun.COM DBG(2, ("ap_rstate = CFGA_STAT_DISCONNECTED\n")); 1427*10923SEvan.Yan@Sun.COM break; 1428*10923SEvan.Yan@Sun.COM case AP_RSTATE_CONNECTED: 1429*10923SEvan.Yan@Sun.COM (*cs)->ap_r_state = CFGA_STAT_CONNECTED; 1430*10923SEvan.Yan@Sun.COM DBG(2, ("ap_rstate = CFGA_STAT_CONNECTED\n")); 1431*10923SEvan.Yan@Sun.COM break; 1432*10923SEvan.Yan@Sun.COM default: 1433*10923SEvan.Yan@Sun.COM cfga_err(errstring, CMD_GETSTAT, ap_id, 0); 1434*10923SEvan.Yan@Sun.COM rv = CFGA_ERROR; 1435*10923SEvan.Yan@Sun.COM hp_fini(node); 1436*10923SEvan.Yan@Sun.COM return (rv); 1437*10923SEvan.Yan@Sun.COM } 1438*10923SEvan.Yan@Sun.COM 1439*10923SEvan.Yan@Sun.COM switch (os) { 1440*10923SEvan.Yan@Sun.COM case AP_OSTATE_CONFIGURED: 1441*10923SEvan.Yan@Sun.COM (*cs)->ap_o_state = CFGA_STAT_CONFIGURED; 1442*10923SEvan.Yan@Sun.COM DBG(2, ("ap_ostate = CFGA_STAT_CONFIGURED\n")); 1443*10923SEvan.Yan@Sun.COM break; 1444*10923SEvan.Yan@Sun.COM case AP_OSTATE_UNCONFIGURED: 1445*10923SEvan.Yan@Sun.COM (*cs)->ap_o_state = CFGA_STAT_UNCONFIGURED; 1446*10923SEvan.Yan@Sun.COM DBG(2, ("ap_ostate = CFGA_STAT_UNCONFIGURED\n")); 1447*10923SEvan.Yan@Sun.COM break; 1448*10923SEvan.Yan@Sun.COM default: 1449*10923SEvan.Yan@Sun.COM cfga_err(errstring, CMD_GETSTAT, ap_id, 0); 1450*10923SEvan.Yan@Sun.COM rv = CFGA_ERROR; 1451*10923SEvan.Yan@Sun.COM hp_fini(node); 1452*10923SEvan.Yan@Sun.COM return (rv); 1453*10923SEvan.Yan@Sun.COM } 1454*10923SEvan.Yan@Sun.COM 1455*10923SEvan.Yan@Sun.COM (void) cfga_get_condition(node, &cond); 1456*10923SEvan.Yan@Sun.COM 1457*10923SEvan.Yan@Sun.COM switch (cond) { 1458*10923SEvan.Yan@Sun.COM case AP_COND_OK: 1459*10923SEvan.Yan@Sun.COM (*cs)->ap_cond = CFGA_COND_OK; 1460*10923SEvan.Yan@Sun.COM DBG(2, ("ap_cond = CFGA_COND_OK\n")); 1461*10923SEvan.Yan@Sun.COM break; 1462*10923SEvan.Yan@Sun.COM case AP_COND_FAILING: 1463*10923SEvan.Yan@Sun.COM (*cs)->ap_cond = CFGA_COND_FAILING; 1464*10923SEvan.Yan@Sun.COM DBG(2, ("ap_cond = CFGA_COND_FAILING\n")); 1465*10923SEvan.Yan@Sun.COM break; 1466*10923SEvan.Yan@Sun.COM case AP_COND_FAILED: 1467*10923SEvan.Yan@Sun.COM (*cs)->ap_cond = CFGA_COND_FAILED; 1468*10923SEvan.Yan@Sun.COM DBG(2, ("ap_cond = CFGA_COND_FAILED\n")); 1469*10923SEvan.Yan@Sun.COM break; 1470*10923SEvan.Yan@Sun.COM case AP_COND_UNUSABLE: 1471*10923SEvan.Yan@Sun.COM (*cs)->ap_cond = CFGA_COND_UNUSABLE; 1472*10923SEvan.Yan@Sun.COM DBG(2, ("ap_cond = CFGA_COND_UNUSABLE\n")); 1473*10923SEvan.Yan@Sun.COM break; 1474*10923SEvan.Yan@Sun.COM case AP_COND_UNKNOWN: 1475*10923SEvan.Yan@Sun.COM (*cs)->ap_cond = CFGA_COND_UNKNOWN; 1476*10923SEvan.Yan@Sun.COM DBG(2, ("ap_cond = CFGA_COND_UNKNOW\n")); 1477*10923SEvan.Yan@Sun.COM break; 1478*10923SEvan.Yan@Sun.COM default: 1479*10923SEvan.Yan@Sun.COM cfga_err(errstring, CMD_GETSTAT, ap_id, 0); 1480*10923SEvan.Yan@Sun.COM rv = CFGA_ERROR; 1481*10923SEvan.Yan@Sun.COM hp_fini(node); 1482*10923SEvan.Yan@Sun.COM return (rv); 1483*10923SEvan.Yan@Sun.COM } 1484*10923SEvan.Yan@Sun.COM /* 1485*10923SEvan.Yan@Sun.COM * We're not busy since the entrance into the kernel has been 1486*10923SEvan.Yan@Sun.COM * sync'ed via libhotplug. 1487*10923SEvan.Yan@Sun.COM */ 1488*10923SEvan.Yan@Sun.COM (*cs)->ap_busy = 0; 1489*10923SEvan.Yan@Sun.COM 1490*10923SEvan.Yan@Sun.COM /* last change */ 1491*10923SEvan.Yan@Sun.COM (*cs)->ap_status_time = hp_last_change(node); 1492*10923SEvan.Yan@Sun.COM 1493*10923SEvan.Yan@Sun.COM /* board type */ 1494*10923SEvan.Yan@Sun.COM if (hp_get_private(node, PCIEHPC_PROP_BOARD_TYPE, &boardtype) != 0) 1495*10923SEvan.Yan@Sun.COM boardtype = PCIEHPC_PROP_VALUE_UNKNOWN; 1496*10923SEvan.Yan@Sun.COM else 1497*10923SEvan.Yan@Sun.COM boardtype = get_val_from_result(boardtype); 1498*10923SEvan.Yan@Sun.COM 1499*10923SEvan.Yan@Sun.COM /* card type */ 1500*10923SEvan.Yan@Sun.COM if (hp_get_private(node, PCIEHPC_PROP_CARD_TYPE, &cardtype) != 0) 1501*10923SEvan.Yan@Sun.COM cardtype = PCIEHPC_PROP_VALUE_UNKNOWN; 1502*10923SEvan.Yan@Sun.COM else 1503*10923SEvan.Yan@Sun.COM cardtype = get_val_from_result(cardtype); 1504*10923SEvan.Yan@Sun.COM 1505*10923SEvan.Yan@Sun.COM /* logical ap_id */ 1506*10923SEvan.Yan@Sun.COM rv = fix_ap_name((*cs)->ap_log_id, ap_id, 1507*10923SEvan.Yan@Sun.COM hp_name(node), errstring); 1508*10923SEvan.Yan@Sun.COM DBG(1, ("logical id: %s\n", (*cs)->ap_log_id)); 1509*10923SEvan.Yan@Sun.COM /* physical ap_id */ 1510*10923SEvan.Yan@Sun.COM (void) strcpy((*cs)->ap_phys_id, ap_id); /* physical path of AP */ 1511*10923SEvan.Yan@Sun.COM 1512*10923SEvan.Yan@Sun.COM /* information */ 1513*10923SEvan.Yan@Sun.COM dlpath = findlink((*cs)->ap_phys_id); 1514*10923SEvan.Yan@Sun.COM if (dlpath != NULL) { 1515*10923SEvan.Yan@Sun.COM if (get_dli(dlpath, (*cs)->ap_info, 1516*10923SEvan.Yan@Sun.COM sizeof ((*cs)->ap_info)) != CFGA_OK) 1517*10923SEvan.Yan@Sun.COM (*cs)->ap_info[0] = '\0'; 1518*10923SEvan.Yan@Sun.COM free(dlpath); 1519*10923SEvan.Yan@Sun.COM } 1520*10923SEvan.Yan@Sun.COM 1521*10923SEvan.Yan@Sun.COM if ((*cs)->ap_log_id[0] == '\0') 1522*10923SEvan.Yan@Sun.COM (void) strcpy((*cs)->ap_log_id, hp_name(node)); 1523*10923SEvan.Yan@Sun.COM 1524*10923SEvan.Yan@Sun.COM if ((*cs)->ap_info[0] == '\0') { 1525*10923SEvan.Yan@Sun.COM /* slot_names of bus node */ 1526*10923SEvan.Yan@Sun.COM if (find_physical_slot_names(ap_id, &slotname_arg) != -1) 1527*10923SEvan.Yan@Sun.COM (void) strcpy((*cs)->ap_info, 1528*10923SEvan.Yan@Sun.COM slotname_arg.slotnames[slotname_arg.minor]); 1529*10923SEvan.Yan@Sun.COM } 1530*10923SEvan.Yan@Sun.COM 1531*10923SEvan.Yan@Sun.COM /* class_code/subclass/boardtype */ 1532*10923SEvan.Yan@Sun.COM get_type(boardtype, cardtype, (*cs)->ap_type); 1533*10923SEvan.Yan@Sun.COM 1534*10923SEvan.Yan@Sun.COM DBG(1, ("cfga_list_ext return success\n")); 1535*10923SEvan.Yan@Sun.COM rv = CFGA_OK; 1536*10923SEvan.Yan@Sun.COM 1537*10923SEvan.Yan@Sun.COM hp_fini(node); 1538*10923SEvan.Yan@Sun.COM return (rv); 1539*10923SEvan.Yan@Sun.COM } 1540*10923SEvan.Yan@Sun.COM 1541*10923SEvan.Yan@Sun.COM /* 1542*10923SEvan.Yan@Sun.COM * This routine prints a single line of help message 1543*10923SEvan.Yan@Sun.COM */ 1544*10923SEvan.Yan@Sun.COM static void 1545*10923SEvan.Yan@Sun.COM cfga_msg(struct cfga_msg *msgp, const char *str) 1546*10923SEvan.Yan@Sun.COM { 1547*10923SEvan.Yan@Sun.COM DBG(2, ("<%s>", str)); 1548*10923SEvan.Yan@Sun.COM 1549*10923SEvan.Yan@Sun.COM if (msgp == NULL || msgp->message_routine == NULL) 1550*10923SEvan.Yan@Sun.COM return; 1551*10923SEvan.Yan@Sun.COM 1552*10923SEvan.Yan@Sun.COM (*msgp->message_routine)(msgp->appdata_ptr, str); 1553*10923SEvan.Yan@Sun.COM (*msgp->message_routine)(msgp->appdata_ptr, "\n"); 1554*10923SEvan.Yan@Sun.COM } 1555*10923SEvan.Yan@Sun.COM 1556*10923SEvan.Yan@Sun.COM static cfga_err_t 1557*10923SEvan.Yan@Sun.COM check_options(const char *options) 1558*10923SEvan.Yan@Sun.COM { 1559*10923SEvan.Yan@Sun.COM struct cfga_msg *msgp = NULL; 1560*10923SEvan.Yan@Sun.COM 1561*10923SEvan.Yan@Sun.COM if (options) { 1562*10923SEvan.Yan@Sun.COM cfga_msg(msgp, dgettext(TEXT_DOMAIN, cfga_strs[HELP_UNKNOWN])); 1563*10923SEvan.Yan@Sun.COM cfga_msg(msgp, options); 1564*10923SEvan.Yan@Sun.COM return (CFGA_INVAL); 1565*10923SEvan.Yan@Sun.COM } 1566*10923SEvan.Yan@Sun.COM return (CFGA_OK); 1567*10923SEvan.Yan@Sun.COM } 1568*10923SEvan.Yan@Sun.COM 1569*10923SEvan.Yan@Sun.COM /*ARGSUSED*/ 1570*10923SEvan.Yan@Sun.COM cfga_err_t 1571*10923SEvan.Yan@Sun.COM cfga_help(struct cfga_msg *msgp, const char *options, cfga_flags_t flags) 1572*10923SEvan.Yan@Sun.COM { 1573*10923SEvan.Yan@Sun.COM if (options) { 1574*10923SEvan.Yan@Sun.COM cfga_msg(msgp, dgettext(TEXT_DOMAIN, cfga_strs[HELP_UNKNOWN])); 1575*10923SEvan.Yan@Sun.COM cfga_msg(msgp, options); 1576*10923SEvan.Yan@Sun.COM } 1577*10923SEvan.Yan@Sun.COM DBG(1, ("cfga_help\n")); 1578*10923SEvan.Yan@Sun.COM 1579*10923SEvan.Yan@Sun.COM cfga_msg(msgp, dgettext(TEXT_DOMAIN, cfga_strs[HELP_HEADER])); 1580*10923SEvan.Yan@Sun.COM cfga_msg(msgp, cfga_strs[HELP_CONFIG]); 1581*10923SEvan.Yan@Sun.COM cfga_msg(msgp, cfga_strs[HELP_ENABLE_SLOT]); 1582*10923SEvan.Yan@Sun.COM cfga_msg(msgp, cfga_strs[HELP_DISABLE_SLOT]); 1583*10923SEvan.Yan@Sun.COM cfga_msg(msgp, cfga_strs[HELP_ENABLE_AUTOCONF]); 1584*10923SEvan.Yan@Sun.COM cfga_msg(msgp, cfga_strs[HELP_DISABLE_AUTOCONF]); 1585*10923SEvan.Yan@Sun.COM cfga_msg(msgp, cfga_strs[HELP_LED_CNTRL]); 1586*10923SEvan.Yan@Sun.COM return (CFGA_OK); 1587*10923SEvan.Yan@Sun.COM } 1588*10923SEvan.Yan@Sun.COM 1589*10923SEvan.Yan@Sun.COM /* 1590*10923SEvan.Yan@Sun.COM * cfga_err() accepts a variable number of message IDs and constructs 1591*10923SEvan.Yan@Sun.COM * a corresponding error string which is returned via the errstring argument. 1592*10923SEvan.Yan@Sun.COM * cfga_err() calls gettext() to internationalize proper messages. 1593*10923SEvan.Yan@Sun.COM */ 1594*10923SEvan.Yan@Sun.COM static void 1595*10923SEvan.Yan@Sun.COM cfga_err(char **errstring, ...) 1596*10923SEvan.Yan@Sun.COM { 1597*10923SEvan.Yan@Sun.COM int a; 1598*10923SEvan.Yan@Sun.COM int i; 1599*10923SEvan.Yan@Sun.COM int n; 1600*10923SEvan.Yan@Sun.COM int len; 1601*10923SEvan.Yan@Sun.COM int flen; 1602*10923SEvan.Yan@Sun.COM char *p; 1603*10923SEvan.Yan@Sun.COM char *q; 1604*10923SEvan.Yan@Sun.COM char *s[32]; 1605*10923SEvan.Yan@Sun.COM char *failed; 1606*10923SEvan.Yan@Sun.COM va_list ap; 1607*10923SEvan.Yan@Sun.COM 1608*10923SEvan.Yan@Sun.COM /* 1609*10923SEvan.Yan@Sun.COM * If errstring is null it means user is not interested in getting 1610*10923SEvan.Yan@Sun.COM * error status. So we don't do all the work 1611*10923SEvan.Yan@Sun.COM */ 1612*10923SEvan.Yan@Sun.COM if (errstring == NULL) { 1613*10923SEvan.Yan@Sun.COM return; 1614*10923SEvan.Yan@Sun.COM } 1615*10923SEvan.Yan@Sun.COM va_start(ap, errstring); 1616*10923SEvan.Yan@Sun.COM 1617*10923SEvan.Yan@Sun.COM failed = dgettext(TEXT_DOMAIN, cfga_strs[FAILED]); 1618*10923SEvan.Yan@Sun.COM flen = strlen(failed); 1619*10923SEvan.Yan@Sun.COM 1620*10923SEvan.Yan@Sun.COM for (n = len = 0; (a = va_arg(ap, int)) != 0; n++) { 1621*10923SEvan.Yan@Sun.COM switch (a) { 1622*10923SEvan.Yan@Sun.COM case CMD_GETSTAT: 1623*10923SEvan.Yan@Sun.COM case CMD_LIST: 1624*10923SEvan.Yan@Sun.COM case CMD_SLOT_CONNECT: 1625*10923SEvan.Yan@Sun.COM case CMD_SLOT_DISCONNECT: 1626*10923SEvan.Yan@Sun.COM case CMD_SLOT_CONFIGURE: 1627*10923SEvan.Yan@Sun.COM case CMD_SLOT_UNCONFIGURE: 1628*10923SEvan.Yan@Sun.COM p = cfga_errstrs(a); 1629*10923SEvan.Yan@Sun.COM len += (strlen(p) + flen); 1630*10923SEvan.Yan@Sun.COM s[n] = p; 1631*10923SEvan.Yan@Sun.COM s[++n] = cfga_strs[FAILED]; 1632*10923SEvan.Yan@Sun.COM 1633*10923SEvan.Yan@Sun.COM DBG(2, ("<%s>", p)); 1634*10923SEvan.Yan@Sun.COM DBG(2, (cfga_strs[FAILED])); 1635*10923SEvan.Yan@Sun.COM break; 1636*10923SEvan.Yan@Sun.COM 1637*10923SEvan.Yan@Sun.COM case ERR_CMD_INVAL: 1638*10923SEvan.Yan@Sun.COM case ERR_AP_INVAL: 1639*10923SEvan.Yan@Sun.COM case ERR_OPT_INVAL: 1640*10923SEvan.Yan@Sun.COM case ERR_AP_ERR: 1641*10923SEvan.Yan@Sun.COM switch (a) { 1642*10923SEvan.Yan@Sun.COM case ERR_CMD_INVAL: 1643*10923SEvan.Yan@Sun.COM p = dgettext(TEXT_DOMAIN, 1644*10923SEvan.Yan@Sun.COM cfga_errstrs[ERR_CMD_INVAL]); 1645*10923SEvan.Yan@Sun.COM break; 1646*10923SEvan.Yan@Sun.COM case ERR_AP_INVAL: 1647*10923SEvan.Yan@Sun.COM p = dgettext(TEXT_DOMAIN, 1648*10923SEvan.Yan@Sun.COM cfga_errstrs[ERR_AP_INVAL]); 1649*10923SEvan.Yan@Sun.COM break; 1650*10923SEvan.Yan@Sun.COM case ERR_OPT_INVAL: 1651*10923SEvan.Yan@Sun.COM p = dgettext(TEXT_DOMAIN, 1652*10923SEvan.Yan@Sun.COM cfga_errstrs[ERR_OPT_INVAL]); 1653*10923SEvan.Yan@Sun.COM break; 1654*10923SEvan.Yan@Sun.COM case ERR_AP_ERR: 1655*10923SEvan.Yan@Sun.COM p = dgettext(TEXT_DOMAIN, 1656*10923SEvan.Yan@Sun.COM cfga_errstrs[ERR_AP_ERR]); 1657*10923SEvan.Yan@Sun.COM break; 1658*10923SEvan.Yan@Sun.COM } 1659*10923SEvan.Yan@Sun.COM 1660*10923SEvan.Yan@Sun.COM if ((q = va_arg(ap, char *)) != NULL) { 1661*10923SEvan.Yan@Sun.COM len += (strlen(p) + strlen(q)); 1662*10923SEvan.Yan@Sun.COM s[n] = p; 1663*10923SEvan.Yan@Sun.COM s[++n] = q; 1664*10923SEvan.Yan@Sun.COM DBG(2, ("<%s>", p)); 1665*10923SEvan.Yan@Sun.COM DBG(2, ("<%s>", q)); 1666*10923SEvan.Yan@Sun.COM break; 1667*10923SEvan.Yan@Sun.COM } else { 1668*10923SEvan.Yan@Sun.COM len += strlen(p); 1669*10923SEvan.Yan@Sun.COM s[n] = p; 1670*10923SEvan.Yan@Sun.COM 1671*10923SEvan.Yan@Sun.COM } 1672*10923SEvan.Yan@Sun.COM DBG(2, ("<%s>", p)); 1673*10923SEvan.Yan@Sun.COM break; 1674*10923SEvan.Yan@Sun.COM 1675*10923SEvan.Yan@Sun.COM default: 1676*10923SEvan.Yan@Sun.COM n--; 1677*10923SEvan.Yan@Sun.COM break; 1678*10923SEvan.Yan@Sun.COM } 1679*10923SEvan.Yan@Sun.COM } 1680*10923SEvan.Yan@Sun.COM 1681*10923SEvan.Yan@Sun.COM DBG(2, ("\n")); 1682*10923SEvan.Yan@Sun.COM va_end(ap); 1683*10923SEvan.Yan@Sun.COM 1684*10923SEvan.Yan@Sun.COM if ((p = calloc(len + 1, 1)) == NULL) 1685*10923SEvan.Yan@Sun.COM return; 1686*10923SEvan.Yan@Sun.COM 1687*10923SEvan.Yan@Sun.COM for (i = 0; i < n; i++) { 1688*10923SEvan.Yan@Sun.COM (void) strlcat(p, s[i], len + 1); 1689*10923SEvan.Yan@Sun.COM DBG(2, ("i:%d, %s\n", i, s[i])); 1690*10923SEvan.Yan@Sun.COM } 1691*10923SEvan.Yan@Sun.COM 1692*10923SEvan.Yan@Sun.COM *errstring = p; 1693*10923SEvan.Yan@Sun.COM DBG(2, ("%s\n", *errstring)); 1694*10923SEvan.Yan@Sun.COM } 1695*10923SEvan.Yan@Sun.COM 1696*10923SEvan.Yan@Sun.COM /* 1697*10923SEvan.Yan@Sun.COM * cfga_ap_id_cmp -- use default_ap_id_cmp() in libcfgadm 1698*10923SEvan.Yan@Sun.COM */ 1699