126947304SEvan Yan /* 226947304SEvan Yan * CDDL HEADER START 326947304SEvan Yan * 426947304SEvan Yan * The contents of this file are subject to the terms of the 526947304SEvan Yan * Common Development and Distribution License (the "License"). 626947304SEvan Yan * You may not use this file except in compliance with the License. 726947304SEvan Yan * 826947304SEvan Yan * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 926947304SEvan Yan * or http://www.opensolaris.org/os/licensing. 1026947304SEvan Yan * See the License for the specific language governing permissions 1126947304SEvan Yan * and limitations under the License. 1226947304SEvan Yan * 1326947304SEvan Yan * When distributing Covered Code, include this CDDL HEADER in each 1426947304SEvan Yan * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1526947304SEvan Yan * If applicable, add the following below this CDDL HEADER, with the 1626947304SEvan Yan * fields enclosed by brackets "[]" replaced with your own identifying 1726947304SEvan Yan * information: Portions Copyright [yyyy] [name of copyright owner] 1826947304SEvan Yan * 1926947304SEvan Yan * CDDL HEADER END 2026947304SEvan Yan */ 2126947304SEvan Yan 2226947304SEvan Yan /* 23bc6a100fSScott M. Carter * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 2426947304SEvan Yan */ 2526947304SEvan Yan 2626947304SEvan Yan /* 2726947304SEvan Yan * Plugin library for PCI Express and PCI (SHPC) hotplug controller 2826947304SEvan Yan */ 2926947304SEvan Yan 3026947304SEvan Yan #include <stddef.h> 3126947304SEvan Yan #include <locale.h> 3226947304SEvan Yan #include <ctype.h> 3326947304SEvan Yan #include <stdio.h> 3426947304SEvan Yan #include <stdlib.h> 3526947304SEvan Yan #include <string.h> 3626947304SEvan Yan #include <fcntl.h> 3726947304SEvan Yan #include <unistd.h> 3826947304SEvan Yan #include <errno.h> 3926947304SEvan Yan #include <locale.h> 4026947304SEvan Yan #include <langinfo.h> 4126947304SEvan Yan #include <time.h> 4226947304SEvan Yan #include <sys/param.h> 4326947304SEvan Yan #include <stdarg.h> 4426947304SEvan Yan #include <libdevinfo.h> 4526947304SEvan Yan #include <libdevice.h> 4626947304SEvan Yan 4726947304SEvan Yan #define CFGA_PLUGIN_LIB 4826947304SEvan Yan 4926947304SEvan Yan #include <config_admin.h> 5026947304SEvan Yan 5126947304SEvan Yan #include <assert.h> 5226947304SEvan Yan #include <sys/types.h> 5326947304SEvan Yan #include <sys/stat.h> 5426947304SEvan Yan #include <sys/dditypes.h> 5526947304SEvan Yan #include <sys/pci.h> 5626947304SEvan Yan #include <libintl.h> 5726947304SEvan Yan 5826947304SEvan Yan #include <dirent.h> 5926947304SEvan Yan #include <limits.h> 6026947304SEvan Yan #include <sys/mkdev.h> 6126947304SEvan Yan #include "../../../../uts/common/sys/hotplug/pci/pcie_hp.h" 6226947304SEvan Yan #include "../../../../common/pci/pci_strings.h" 6326947304SEvan Yan #include <libhotplug.h> 6426947304SEvan Yan 6526947304SEvan Yan extern const struct pci_class_strings_s class_pci[]; 6626947304SEvan Yan extern int class_pci_items; 6726947304SEvan Yan 6826947304SEvan Yan #define MSG_HOTPLUG_DISABLED \ 6926947304SEvan Yan "Error: hotplug service is probably not running, " \ 7026947304SEvan Yan "please use 'svcadm enable hotplug' to enable the service. " \ 7126947304SEvan Yan "See cfgadm_shp(1M) for more details." 7226947304SEvan Yan 7326947304SEvan Yan #define DEVICES_DIR "/devices" 7426947304SEvan Yan #define SLASH "/" 7526947304SEvan Yan #define GET_DYN(a) (strstr((a), CFGA_DYN_SEP)) 7626947304SEvan Yan 7726947304SEvan Yan /* 7826947304SEvan Yan * Set the version number 7926947304SEvan Yan */ 8026947304SEvan Yan int cfga_version = CFGA_HSL_V2; 8126947304SEvan Yan 8226947304SEvan Yan #ifdef DEBUG 8326947304SEvan Yan #define SHP_DBG 1 8426947304SEvan Yan #endif 8526947304SEvan Yan 8626947304SEvan Yan #if !defined(TEXT_DOMAIN) 8726947304SEvan Yan #define TEXT_DOMAIN "SYS_TEST" 8826947304SEvan Yan #endif 8926947304SEvan Yan 9026947304SEvan Yan /* 9126947304SEvan Yan * DEBUGING LEVEL 9226947304SEvan Yan * 9326947304SEvan Yan * External routines: 1 - 2 9426947304SEvan Yan * Internal routines: 3 - 4 9526947304SEvan Yan */ 9626947304SEvan Yan #ifdef SHP_DBG 9726947304SEvan Yan int shp_debug = 1; 9826947304SEvan Yan #define DBG(level, args) \ 9926947304SEvan Yan { if (shp_debug >= (level)) printf args; } 10026947304SEvan Yan #define DBG_F(level, args) \ 10126947304SEvan Yan { if (shp_debug >= (level)) fprintf args; } 10226947304SEvan Yan #else 10326947304SEvan Yan #define DBG(level, args) /* nothing */ 10426947304SEvan Yan #define DBG_F(level, args) /* nothing */ 10526947304SEvan Yan #endif 10626947304SEvan Yan 10726947304SEvan Yan #define CMD_ACQUIRE 0 10826947304SEvan Yan #define CMD_GETSTAT 1 10926947304SEvan Yan #define CMD_LIST 2 11026947304SEvan Yan #define CMD_SLOT_CONNECT 3 11126947304SEvan Yan #define CMD_SLOT_DISCONNECT 4 11226947304SEvan Yan #define CMD_SLOT_CONFIGURE 5 11326947304SEvan Yan #define CMD_SLOT_UNCONFIGURE 6 11426947304SEvan Yan #define CMD_SLOT_INSERT 7 11526947304SEvan Yan #define CMD_SLOT_REMOVE 8 11626947304SEvan Yan #define CMD_OPEN 9 11726947304SEvan Yan #define CMD_FSTAT 10 11826947304SEvan Yan #define ERR_CMD_INVAL 11 11926947304SEvan Yan #define ERR_AP_INVAL 12 12026947304SEvan Yan #define ERR_AP_ERR 13 12126947304SEvan Yan #define ERR_OPT_INVAL 14 12226947304SEvan Yan 12326947304SEvan Yan static char * 12426947304SEvan Yan cfga_errstrs[] = { 12526947304SEvan Yan /* n */ "acquire ", 12626947304SEvan Yan /* n */ "get-status ", 12726947304SEvan Yan /* n */ "list ", 12826947304SEvan Yan /* n */ "connect ", 12926947304SEvan Yan /* n */ "disconnect ", 13026947304SEvan Yan /* n */ "configure ", 13126947304SEvan Yan /* n */ "unconfigure ", 13226947304SEvan Yan /* n */ "insert ", 13326947304SEvan Yan /* n */ "remove ", 13426947304SEvan Yan /* n */ "open ", 13526947304SEvan Yan /* n */ "fstat ", 13626947304SEvan Yan /* y */ "invalid command ", 13726947304SEvan Yan /* y */ "invalid attachment point ", 13826947304SEvan Yan /* y */ "invalid transition ", 13926947304SEvan Yan /* y */ "invalid option ", 14026947304SEvan Yan NULL 14126947304SEvan Yan }; 14226947304SEvan Yan 14326947304SEvan Yan #define HELP_HEADER 1 14426947304SEvan Yan #define HELP_CONFIG 2 14526947304SEvan Yan #define HELP_ENABLE_SLOT 3 14626947304SEvan Yan #define HELP_DISABLE_SLOT 4 14726947304SEvan Yan #define HELP_ENABLE_AUTOCONF 5 14826947304SEvan Yan #define HELP_DISABLE_AUTOCONF 6 14926947304SEvan Yan #define HELP_LED_CNTRL 7 15026947304SEvan Yan #define HELP_UNKNOWN 8 15126947304SEvan Yan #define SUCCESS 9 15226947304SEvan Yan #define FAILED 10 15326947304SEvan Yan #define UNKNOWN 11 15426947304SEvan Yan 15526947304SEvan Yan #define MAXLINE 256 15626947304SEvan Yan 15726947304SEvan Yan extern int errno; 15826947304SEvan Yan 15926947304SEvan Yan static void cfga_err(char **errstring, ...); 16026947304SEvan Yan static cfga_err_t fix_ap_name(char *ap_log_id, const char *ap_id, 16126947304SEvan Yan char *slot_name, char **errstring); 16226947304SEvan Yan static cfga_err_t check_options(const char *options); 16326947304SEvan Yan static void cfga_msg(struct cfga_msg *msgp, const char *str); 16426947304SEvan Yan static char *findlink(char *ap_phys_id); 16526947304SEvan Yan 16626947304SEvan Yan static char * 16726947304SEvan Yan cfga_strs[] = { 16826947304SEvan Yan NULL, 16926947304SEvan Yan "\nPCI hotplug specific commands:", 17026947304SEvan Yan "\t-c [connect|disconnect|configure|unconfigure|insert|remove] " 17126947304SEvan Yan "ap_id [ap_id...]", 17226947304SEvan Yan "\t-x enable_slot ap_id [ap_id...]", 17326947304SEvan Yan "\t-x disable_slot ap_id [ap_id...]", 17426947304SEvan Yan "\t-x enable_autoconfig ap_id [ap_id...]", 17526947304SEvan Yan "\t-x disable_autoconfig ap_id [ap_id...]", 17626947304SEvan Yan "\t-x led[=[fault|power|active|attn],mode=[on|off|blink]] ap_id [ap_id...]", 17726947304SEvan Yan "\tunknown command or option: ", 17826947304SEvan Yan "success ", 17926947304SEvan Yan "failed ", 18026947304SEvan Yan "unknown", 18126947304SEvan Yan NULL 18226947304SEvan Yan }; 18326947304SEvan Yan 18426947304SEvan Yan #define MAX_FORMAT 80 18526947304SEvan Yan 18626947304SEvan Yan #define ENABLE_SLOT 0 18726947304SEvan Yan #define DISABLE_SLOT 1 18826947304SEvan Yan #define ENABLE_AUTOCNF 2 18926947304SEvan Yan #define DISABLE_AUTOCNF 3 19026947304SEvan Yan #define LED 4 19126947304SEvan Yan #define MODE 5 19226947304SEvan Yan 19326947304SEvan Yan typedef enum { PCIEHPC_FAULT_LED, PCIEHPC_POWER_LED, PCIEHPC_ATTN_LED, 19426947304SEvan Yan PCIEHPC_ACTIVE_LED} pciehpc_led_t; 19526947304SEvan Yan 19626947304SEvan Yan typedef enum { PCIEHPC_BOARD_UNKNOWN, PCIEHPC_BOARD_PCI_HOTPLUG } 19726947304SEvan Yan pciehpc_board_type_t; 19826947304SEvan Yan 19926947304SEvan Yan /* 20026947304SEvan Yan * Board Type 20126947304SEvan Yan */ 20226947304SEvan Yan static char * 20326947304SEvan Yan board_strs[] = { 20426947304SEvan Yan /* n */ "???", /* PCIEHPC_BOARD_UNKNOWN */ 20526947304SEvan Yan /* n */ "hp", /* PCIEHPC_BOARD_PCI_HOTPLUG */ 20626947304SEvan Yan /* n */ NULL 20726947304SEvan Yan }; 20826947304SEvan Yan 20926947304SEvan Yan /* 21026947304SEvan Yan * HW functions 21126947304SEvan Yan */ 21226947304SEvan Yan static char * 21326947304SEvan Yan func_strs[] = { 21426947304SEvan Yan /* n */ "enable_slot", 21526947304SEvan Yan /* n */ "disable_slot", 21626947304SEvan Yan /* n */ "enable_autoconfig", 21726947304SEvan Yan /* n */ "disable_autoconfig", 21826947304SEvan Yan /* n */ "led", 21926947304SEvan Yan /* n */ "mode", 22026947304SEvan Yan /* n */ NULL 22126947304SEvan Yan }; 22226947304SEvan Yan 22326947304SEvan Yan /* 22426947304SEvan Yan * LED strings 22526947304SEvan Yan */ 22626947304SEvan Yan static char * 22726947304SEvan Yan led_strs[] = { 22826947304SEvan Yan /* n */ "fault", /* PCIEHPC_FAULT_LED */ 22926947304SEvan Yan /* n */ "power", /* PCIEHPC_POWER_LED */ 23026947304SEvan Yan /* n */ "attn", /* PCIEHPC_ATTN_LED */ 23126947304SEvan Yan /* n */ "active", /* PCIEHPC_ACTIVE_LED */ 23226947304SEvan Yan /* n */ NULL 23326947304SEvan Yan }; 23426947304SEvan Yan 23526947304SEvan Yan static char * 23626947304SEvan Yan led_strs2[] = { 23726947304SEvan Yan /* n */ PCIEHPC_PROP_LED_FAULT, /* PCIEHPC_FAULT_LED */ 23826947304SEvan Yan /* n */ PCIEHPC_PROP_LED_POWER, /* PCIEHPC_POWER_LED */ 23926947304SEvan Yan /* n */ PCIEHPC_PROP_LED_ATTN, /* PCIEHPC_ATTN_LED */ 24026947304SEvan Yan /* n */ PCIEHPC_PROP_LED_ACTIVE, /* PCIEHPC_ACTIVE_LED */ 24126947304SEvan Yan /* n */ NULL 24226947304SEvan Yan }; 24326947304SEvan Yan 24426947304SEvan Yan #define FAULT 0 24526947304SEvan Yan #define POWER 1 24626947304SEvan Yan #define ATTN 2 24726947304SEvan Yan #define ACTIVE 3 24826947304SEvan Yan 24926947304SEvan Yan static char * 25026947304SEvan Yan mode_strs[] = { 25126947304SEvan Yan /* n */ "off", /* OFF */ 25226947304SEvan Yan /* n */ "on", /* ON */ 25326947304SEvan Yan /* n */ "blink", /* BLINK */ 25426947304SEvan Yan /* n */ NULL 25526947304SEvan Yan }; 25626947304SEvan Yan 25726947304SEvan Yan #define OFF 0 25826947304SEvan Yan #define ON 1 25926947304SEvan Yan #define BLINK 2 26026947304SEvan Yan 26126947304SEvan Yan #define cfga_errstrs(i) cfga_errstrs[(i)] 26226947304SEvan Yan 26326947304SEvan Yan #define cfga_eid(a, b) (((a) << 8) + (b)) 26426947304SEvan Yan #define MAXDEVS 32 26526947304SEvan Yan 26626947304SEvan Yan typedef enum { 26726947304SEvan Yan SOLARIS_SLT_NAME, 26826947304SEvan Yan PROM_SLT_NAME 26926947304SEvan Yan } slt_name_src_t; 27026947304SEvan Yan 27126947304SEvan Yan struct searcharg { 27226947304SEvan Yan char *devpath; 27326947304SEvan Yan char slotnames[MAXDEVS][MAXNAMELEN]; 27426947304SEvan Yan int minor; 27526947304SEvan Yan di_prom_handle_t promp; 27626947304SEvan Yan slt_name_src_t slt_name_src; 27726947304SEvan Yan }; 27826947304SEvan Yan 27926947304SEvan Yan static void *private_check; 28026947304SEvan Yan 28126947304SEvan Yan /* 28226947304SEvan Yan * Return the corresponding hp node for a given ap_id, it is the caller's 28326947304SEvan Yan * responsibility to call hp_fini() to free the snapshot. 28426947304SEvan Yan */ 28526947304SEvan Yan static cfga_err_t 28626947304SEvan Yan physpath2node(const char *physpath, char **errstring, hp_node_t *nodep) 28726947304SEvan Yan { 28826947304SEvan Yan char *rpath; 28926947304SEvan Yan char *cp; 29026947304SEvan Yan hp_node_t node; 29126947304SEvan Yan size_t len; 29226947304SEvan Yan char *errmsg; 29326947304SEvan Yan 29426947304SEvan Yan if (getuid() != 0 && geteuid() != 0) 29526947304SEvan Yan return (CFGA_ERROR); 29626947304SEvan Yan 29726947304SEvan Yan if ((rpath = malloc(strlen(physpath) + 1)) == NULL) 29826947304SEvan Yan return (CFGA_ERROR); 29926947304SEvan Yan 30026947304SEvan Yan (void) strcpy(rpath, physpath); 30126947304SEvan Yan 30226947304SEvan Yan /* Remove devices prefix (if any) */ 30326947304SEvan Yan len = strlen(DEVICES_DIR); 30426947304SEvan Yan if (strncmp(rpath, DEVICES_DIR SLASH, len + strlen(SLASH)) == 0) { 30526947304SEvan Yan (void) memmove(rpath, rpath + len, 30626947304SEvan Yan strlen(rpath + len) + 1); 30726947304SEvan Yan } 30826947304SEvan Yan 30926947304SEvan Yan /* Remove dynamic component if any */ 31026947304SEvan Yan if ((cp = GET_DYN(rpath)) != NULL) { 31126947304SEvan Yan *cp = '\0'; 31226947304SEvan Yan } 31326947304SEvan Yan 31426947304SEvan Yan /* Remove minor name (if any) */ 31526947304SEvan Yan if ((cp = strrchr(rpath, ':')) == NULL) { 31626947304SEvan Yan free(rpath); 31726947304SEvan Yan return (CFGA_INVAL); 31826947304SEvan Yan } 31926947304SEvan Yan 32026947304SEvan Yan *cp = '\0'; 32126947304SEvan Yan cp++; 32226947304SEvan Yan 32326947304SEvan Yan DBG(1, ("rpath=%s,cp=%s\n", rpath, cp)); 32426947304SEvan Yan if ((node = hp_init(rpath, cp, 0)) == NULL) { 32526947304SEvan Yan if (errno == EBADF) { 32626947304SEvan Yan /* No reponse to operations on the door file. */ 32726947304SEvan Yan assert(errstring != NULL); 32826947304SEvan Yan *errstring = strdup(MSG_HOTPLUG_DISABLED); 32926947304SEvan Yan free(rpath); 33026947304SEvan Yan return (CFGA_NOTSUPP); 33126947304SEvan Yan } 33226947304SEvan Yan free(rpath); 33326947304SEvan Yan return (CFGA_ERROR); 33426947304SEvan Yan } 33526947304SEvan Yan 33626947304SEvan Yan free(rpath); 33726947304SEvan Yan 33826947304SEvan Yan *nodep = node; 33926947304SEvan Yan return (CFGA_OK); 34026947304SEvan Yan } 34126947304SEvan Yan 34226947304SEvan Yan typedef struct error_size_cb_arg { 34326947304SEvan Yan size_t rsrc_width; 34426947304SEvan Yan size_t info_width; 34526947304SEvan Yan int cnt; 34626947304SEvan Yan } error_size_cb_arg_t; 34726947304SEvan Yan 34826947304SEvan Yan /* 34926947304SEvan Yan * Callback function for hp_traverse(), to sum up the 35026947304SEvan Yan * maximum length for error message display. 35126947304SEvan Yan */ 35226947304SEvan Yan static int 35326947304SEvan Yan error_sizeup_cb(hp_node_t node, void *arg) 35426947304SEvan Yan { 35526947304SEvan Yan error_size_cb_arg_t *sizearg = (error_size_cb_arg_t *)arg; 35626947304SEvan Yan size_t len; 35726947304SEvan Yan 35826947304SEvan Yan /* Only process USAGE nodes */ 35926947304SEvan Yan if (hp_type(node) != HP_NODE_USAGE) 36026947304SEvan Yan return (HP_WALK_CONTINUE); 36126947304SEvan Yan 36226947304SEvan Yan sizearg->cnt++; 36326947304SEvan Yan 36426947304SEvan Yan /* size up resource name */ 36526947304SEvan Yan len = strlen(hp_name(node)); 36626947304SEvan Yan if (sizearg->rsrc_width < len) 36726947304SEvan Yan sizearg->rsrc_width = len; 36826947304SEvan Yan 36926947304SEvan Yan /* size up usage description */ 37026947304SEvan Yan len = strlen(hp_usage(node)); 37126947304SEvan Yan if (sizearg->info_width < len) 37226947304SEvan Yan sizearg->info_width = len; 37326947304SEvan Yan 37426947304SEvan Yan return (HP_WALK_CONTINUE); 37526947304SEvan Yan } 37626947304SEvan Yan 37726947304SEvan Yan typedef struct error_sum_cb_arg { 37826947304SEvan Yan char **table; 37926947304SEvan Yan char *format; 38026947304SEvan Yan } error_sum_cb_arg_t; 38126947304SEvan Yan 38226947304SEvan Yan /* 38326947304SEvan Yan * Callback function for hp_traverse(), to add the error 38426947304SEvan Yan * message to he table. 38526947304SEvan Yan */ 38626947304SEvan Yan static int 38726947304SEvan Yan error_sumup_cb(hp_node_t node, void *arg) 38826947304SEvan Yan { 38926947304SEvan Yan error_sum_cb_arg_t *sumarg = (error_sum_cb_arg_t *)arg; 39026947304SEvan Yan char **table = sumarg->table; 39126947304SEvan Yan char *format = sumarg->format; 39226947304SEvan Yan 39326947304SEvan Yan /* Only process USAGE nodes */ 39426947304SEvan Yan if (hp_type(node) != HP_NODE_USAGE) 39526947304SEvan Yan return (HP_WALK_CONTINUE); 39626947304SEvan Yan 39726947304SEvan Yan (void) strcat(*table, "\n"); 39826947304SEvan Yan (void) sprintf(&((*table)[strlen(*table)]), 39926947304SEvan Yan format, hp_name(node), hp_usage(node)); 40026947304SEvan Yan 40126947304SEvan Yan return (HP_WALK_CONTINUE); 40226947304SEvan Yan } 40326947304SEvan Yan 40426947304SEvan Yan /* 40526947304SEvan Yan * Takes an opaque rcm_info_t pointer and a character pointer, and appends 40626947304SEvan Yan * the rcm_info_t data in the form of a table to the given character pointer. 40726947304SEvan Yan */ 40826947304SEvan Yan static void 40926947304SEvan Yan pci_rcm_info_table(hp_node_t node, char **table) 41026947304SEvan Yan { 41126947304SEvan Yan int i; 41226947304SEvan Yan size_t w; 41326947304SEvan Yan size_t width = 0; 41426947304SEvan Yan size_t w_rsrc = 0; 41526947304SEvan Yan size_t w_info = 0; 41626947304SEvan Yan size_t table_size = 0; 41726947304SEvan Yan uint_t tuples = 0; 41826947304SEvan Yan char *rsrc; 41926947304SEvan Yan char *info; 42026947304SEvan Yan char *newtable; 42126947304SEvan Yan static char format[MAX_FORMAT]; 42226947304SEvan Yan const char *infostr; 42326947304SEvan Yan error_size_cb_arg_t sizearg; 42426947304SEvan Yan error_sum_cb_arg_t sumarg; 42526947304SEvan Yan 42626947304SEvan Yan /* Protect against invalid arguments */ 42726947304SEvan Yan if (table == NULL) 42826947304SEvan Yan return; 42926947304SEvan Yan 43026947304SEvan Yan /* Set localized table header strings */ 43126947304SEvan Yan rsrc = dgettext(TEXT_DOMAIN, "Resource"); 43226947304SEvan Yan info = dgettext(TEXT_DOMAIN, "Information"); 43326947304SEvan Yan 43426947304SEvan Yan /* A first pass, to size up the RCM information */ 43526947304SEvan Yan sizearg.rsrc_width = strlen(rsrc); 43626947304SEvan Yan sizearg.info_width = strlen(info); 43726947304SEvan Yan sizearg.cnt = 0; 43826947304SEvan Yan (void) hp_traverse(node, &sizearg, error_sizeup_cb); 43926947304SEvan Yan 44026947304SEvan Yan /* If nothing was sized up above, stop early */ 44126947304SEvan Yan if (sizearg.cnt == 0) 44226947304SEvan Yan return; 44326947304SEvan Yan 44426947304SEvan Yan w_rsrc = sizearg.rsrc_width; 44526947304SEvan Yan w_info = sizearg.info_width; 44626947304SEvan Yan tuples = sizearg.cnt; 44726947304SEvan Yan 44826947304SEvan Yan /* Adjust column widths for column headings */ 44926947304SEvan Yan if ((w = strlen(rsrc)) > w_rsrc) 45026947304SEvan Yan w_rsrc = w; 45126947304SEvan Yan else if ((w_rsrc - w) % 2) 45226947304SEvan Yan w_rsrc++; 45326947304SEvan Yan if ((w = strlen(info)) > w_info) 45426947304SEvan Yan w_info = w; 45526947304SEvan Yan else if ((w_info - w) % 2) 45626947304SEvan Yan w_info++; 45726947304SEvan Yan 45826947304SEvan Yan /* 45926947304SEvan Yan * Compute the total line width of each line, 46026947304SEvan Yan * accounting for intercolumn spacing. 46126947304SEvan Yan */ 46226947304SEvan Yan width = w_info + w_rsrc + 4; 46326947304SEvan Yan 46426947304SEvan Yan /* Allocate space for the table */ 46526947304SEvan Yan table_size = (2 + tuples) * (width + 1) + 2; 46626947304SEvan Yan if (*table == NULL) { 46726947304SEvan Yan /* zero fill for the strcat() call below */ 46826947304SEvan Yan *table = calloc(table_size, sizeof (char)); 46926947304SEvan Yan if (*table == NULL) 47026947304SEvan Yan return; 47126947304SEvan Yan } else { 47226947304SEvan Yan newtable = realloc(*table, strlen(*table) + table_size); 47326947304SEvan Yan if (newtable == NULL) 47426947304SEvan Yan return; 47526947304SEvan Yan else 47626947304SEvan Yan *table = newtable; 47726947304SEvan Yan } 47826947304SEvan Yan 47926947304SEvan Yan /* Place a table header into the string */ 48026947304SEvan Yan 48126947304SEvan Yan /* The resource header */ 48226947304SEvan Yan (void) strcat(*table, "\n"); 48326947304SEvan Yan w = strlen(rsrc); 48426947304SEvan Yan for (i = 0; i < ((w_rsrc - w) / 2); i++) 48526947304SEvan Yan (void) strcat(*table, " "); 48626947304SEvan Yan (void) strcat(*table, rsrc); 48726947304SEvan Yan for (i = 0; i < ((w_rsrc - w) / 2); i++) 48826947304SEvan Yan (void) strcat(*table, " "); 48926947304SEvan Yan 49026947304SEvan Yan /* The information header */ 49126947304SEvan Yan (void) strcat(*table, " "); 49226947304SEvan Yan w = strlen(info); 49326947304SEvan Yan for (i = 0; i < ((w_info - w) / 2); i++) 49426947304SEvan Yan (void) strcat(*table, " "); 49526947304SEvan Yan (void) strcat(*table, info); 49626947304SEvan Yan for (i = 0; i < ((w_info - w) / 2); i++) 49726947304SEvan Yan (void) strcat(*table, " "); 49826947304SEvan Yan /* Underline the headers */ 49926947304SEvan Yan (void) strcat(*table, "\n"); 50026947304SEvan Yan for (i = 0; i < w_rsrc; i++) 50126947304SEvan Yan (void) strcat(*table, "-"); 50226947304SEvan Yan (void) strcat(*table, " "); 50326947304SEvan Yan for (i = 0; i < w_info; i++) 50426947304SEvan Yan (void) strcat(*table, "-"); 50526947304SEvan Yan 50626947304SEvan Yan /* Construct the format string */ 50726947304SEvan Yan (void) snprintf(format, MAX_FORMAT, "%%-%ds %%-%ds", 50826947304SEvan Yan (int)w_rsrc, (int)w_info); 50926947304SEvan Yan 51026947304SEvan Yan /* Add the tuples to the table string */ 51126947304SEvan Yan sumarg.table = table; 51226947304SEvan Yan sumarg.format = format; 51326947304SEvan Yan (void) hp_traverse(node, &sumarg, error_sumup_cb); 51426947304SEvan Yan } 51526947304SEvan Yan 51626947304SEvan Yan /* 51726947304SEvan Yan * Figure out the target kernel state for a given cfgadm 51826947304SEvan Yan * change-state operation. 51926947304SEvan Yan */ 52026947304SEvan Yan static cfga_err_t 52126947304SEvan Yan cfga_target_state(cfga_cmd_t state_change_cmd, int *state) 52226947304SEvan Yan { 52326947304SEvan Yan switch (state_change_cmd) { 52426947304SEvan Yan case CFGA_CMD_CONNECT: 52526947304SEvan Yan *state = DDI_HP_CN_STATE_POWERED; 52626947304SEvan Yan break; 52726947304SEvan Yan case CFGA_CMD_DISCONNECT: 52826947304SEvan Yan *state = DDI_HP_CN_STATE_PRESENT; 52926947304SEvan Yan break; 53026947304SEvan Yan case CFGA_CMD_CONFIGURE: 53126947304SEvan Yan *state = DDI_HP_CN_STATE_ENABLED; 53226947304SEvan Yan break; 53326947304SEvan Yan case CFGA_CMD_UNCONFIGURE: 53426947304SEvan Yan *state = DDI_HP_CN_STATE_POWERED; 53526947304SEvan Yan break; 53626947304SEvan Yan default: 53726947304SEvan Yan return (CFGA_ERROR); 53826947304SEvan Yan } 53926947304SEvan Yan 54026947304SEvan Yan return (CFGA_OK); 54126947304SEvan Yan } 54226947304SEvan Yan 54326947304SEvan Yan /* 54426947304SEvan Yan * Translate kernel state to cfgadm receptacle state and occupant state. 54526947304SEvan Yan */ 54626947304SEvan Yan static cfga_err_t 54726947304SEvan Yan cfga_get_state(hp_node_t connector, ap_rstate_t *rs, ap_ostate_t *os) 54826947304SEvan Yan { 54926947304SEvan Yan int state; 55026947304SEvan Yan hp_node_t port; 55126947304SEvan Yan 55226947304SEvan Yan state = hp_state(connector); 55326947304SEvan Yan 55426947304SEvan Yan /* Receptacle state */ 55526947304SEvan Yan switch (state) { 55626947304SEvan Yan case DDI_HP_CN_STATE_EMPTY: 55726947304SEvan Yan *rs = AP_RSTATE_EMPTY; 55826947304SEvan Yan break; 55926947304SEvan Yan case DDI_HP_CN_STATE_PRESENT: 56026947304SEvan Yan *rs = AP_RSTATE_DISCONNECTED; 56126947304SEvan Yan break; 56226947304SEvan Yan case DDI_HP_CN_STATE_POWERED: 56326947304SEvan Yan case DDI_HP_CN_STATE_ENABLED: 56426947304SEvan Yan *rs = AP_RSTATE_CONNECTED; 56526947304SEvan Yan break; 56626947304SEvan Yan /* 56726947304SEvan Yan * Connector state can only be one of 56826947304SEvan Yan * Empty, Present, Powered, Enabled. 56926947304SEvan Yan */ 57026947304SEvan Yan default: 57126947304SEvan Yan return (CFGA_ERROR); 57226947304SEvan Yan } 57326947304SEvan Yan 57426947304SEvan Yan /* 57526947304SEvan Yan * Occupant state 57626947304SEvan Yan */ 57726947304SEvan Yan port = hp_child(connector); 57826947304SEvan Yan while (port != NULL) { 57926947304SEvan Yan DBG(1, ("cfga_get_state:(%x)\n", hp_state(port))); 58026947304SEvan Yan 58126947304SEvan Yan /* 58226947304SEvan Yan * Mark occupant state as "configured" if at least one of the 58326947304SEvan Yan * associated ports is at state "offline" or above. Driver 58426947304SEvan Yan * attach ("online" state) is not necessary here. 58526947304SEvan Yan */ 58626947304SEvan Yan if (hp_state(port) >= DDI_HP_CN_STATE_OFFLINE) 58726947304SEvan Yan break; 58826947304SEvan Yan 58926947304SEvan Yan port = hp_sibling(port); 59026947304SEvan Yan } 59126947304SEvan Yan 59226947304SEvan Yan if (port != NULL) 59326947304SEvan Yan *os = AP_OSTATE_CONFIGURED; 59426947304SEvan Yan else 59526947304SEvan Yan *os = AP_OSTATE_UNCONFIGURED; 59626947304SEvan Yan 59726947304SEvan Yan return (CFGA_OK); 59826947304SEvan Yan } 59926947304SEvan Yan 60026947304SEvan Yan /* 60126947304SEvan Yan * Transitional Diagram: 60226947304SEvan Yan * 60326947304SEvan Yan * empty unconfigure 60426947304SEvan Yan * (remove) ^| (physically insert card) 60526947304SEvan Yan * |V 60626947304SEvan Yan * disconnect configure 60726947304SEvan Yan * "-c DISCONNECT" ^| "-c CONNECT" 60826947304SEvan Yan * |V "-c CONFIGURE" 60926947304SEvan Yan * connect unconfigure -> connect configure 61026947304SEvan Yan * <- 61126947304SEvan Yan * "-c UNCONFIGURE" 61226947304SEvan Yan * 61326947304SEvan Yan */ 61426947304SEvan Yan /*ARGSUSED*/ 61526947304SEvan Yan cfga_err_t 61626947304SEvan Yan cfga_change_state(cfga_cmd_t state_change_cmd, const char *ap_id, 61726947304SEvan Yan const char *options, struct cfga_confirm *confp, 61826947304SEvan Yan struct cfga_msg *msgp, char **errstring, cfga_flags_t flags) 61926947304SEvan Yan { 62026947304SEvan Yan int rv, state, new_state; 621*29d8c27bSScott M. Carter uint_t hpflags = 0; 62226947304SEvan Yan hp_node_t node; 62326947304SEvan Yan hp_node_t results = NULL; 62426947304SEvan Yan 62526947304SEvan Yan if ((rv = check_options(options)) != CFGA_OK) { 62626947304SEvan Yan return (rv); 62726947304SEvan Yan } 62826947304SEvan Yan 62926947304SEvan Yan if (errstring != NULL) 63026947304SEvan Yan *errstring = NULL; 63126947304SEvan Yan 63226947304SEvan Yan rv = CFGA_OK; 63326947304SEvan Yan DBG(1, ("cfga_change_state:(%s)\n", ap_id)); 63426947304SEvan Yan 63526947304SEvan Yan rv = physpath2node(ap_id, errstring, &node); 63626947304SEvan Yan if (rv != CFGA_OK) 63726947304SEvan Yan return (rv); 63826947304SEvan Yan 639*29d8c27bSScott M. Carter /* 640*29d8c27bSScott M. Carter * Check for the FORCE flag. It is only used 641*29d8c27bSScott M. Carter * for DISCONNECT or UNCONFIGURE state changes. 642*29d8c27bSScott M. Carter */ 643*29d8c27bSScott M. Carter if (flags & CFGA_FLAG_FORCE) 644*29d8c27bSScott M. Carter hpflags |= HPFORCE; 645*29d8c27bSScott M. Carter 64626947304SEvan Yan state = hp_state(node); 64726947304SEvan Yan 64826947304SEvan Yan /* 64926947304SEvan Yan * Which state should we drive to ? 65026947304SEvan Yan */ 65126947304SEvan Yan if ((state_change_cmd != CFGA_CMD_LOAD) && 65226947304SEvan Yan (state_change_cmd != CFGA_CMD_UNLOAD)) { 65326947304SEvan Yan if (cfga_target_state(state_change_cmd, 65426947304SEvan Yan &new_state) != CFGA_OK) { 65526947304SEvan Yan hp_fini(node); 65626947304SEvan Yan return (CFGA_ERROR); 65726947304SEvan Yan } 65826947304SEvan Yan } 65926947304SEvan Yan 66026947304SEvan Yan DBG(1, ("cfga_change_state: state is %d\n", state)); 66126947304SEvan Yan switch (state_change_cmd) { 66226947304SEvan Yan case CFGA_CMD_CONNECT: 663bc6a100fSScott M. Carter DBG(1, ("connect\n")); 664bc6a100fSScott M. Carter if (state == DDI_HP_CN_STATE_EMPTY) { 66526947304SEvan Yan cfga_err(errstring, ERR_AP_ERR, 0); 66626947304SEvan Yan rv = CFGA_INVAL; 667bc6a100fSScott M. Carter } else if (state == DDI_HP_CN_STATE_PRESENT) { 668bc6a100fSScott M. Carter /* Connect the slot */ 66926947304SEvan Yan if (hp_set_state(node, 0, new_state, &results) != 0) { 67026947304SEvan Yan rv = CFGA_ERROR; 67126947304SEvan Yan cfga_err(errstring, CMD_SLOT_CONNECT, 0); 67226947304SEvan Yan } 67326947304SEvan Yan } 67426947304SEvan Yan break; 67526947304SEvan Yan 67626947304SEvan Yan case CFGA_CMD_DISCONNECT: 67726947304SEvan Yan DBG(1, ("disconnect\n")); 678bc6a100fSScott M. Carter if (state == DDI_HP_CN_STATE_EMPTY) { 67926947304SEvan Yan cfga_err(errstring, ERR_AP_ERR, 0); 68026947304SEvan Yan rv = CFGA_INVAL; 681bc6a100fSScott M. Carter } else if (state > DDI_HP_CN_STATE_PRESENT) { 682bc6a100fSScott M. Carter /* Disconnect the slot */ 683*29d8c27bSScott M. Carter rv = hp_set_state(node, hpflags, new_state, &results); 684*29d8c27bSScott M. Carter if (rv != 0) { 68526947304SEvan Yan if (rv == EBUSY) 68626947304SEvan Yan rv = CFGA_BUSY; 68726947304SEvan Yan else 68826947304SEvan Yan rv = CFGA_ERROR; 68926947304SEvan Yan 69026947304SEvan Yan if (results) { 69126947304SEvan Yan pci_rcm_info_table(results, errstring); 69226947304SEvan Yan hp_fini(results); 69326947304SEvan Yan } else { 69426947304SEvan Yan cfga_err(errstring, 69526947304SEvan Yan CMD_SLOT_DISCONNECT, 0); 69626947304SEvan Yan } 69726947304SEvan Yan } 69826947304SEvan Yan } 69926947304SEvan Yan break; 70026947304SEvan Yan 70126947304SEvan Yan case CFGA_CMD_CONFIGURE: 70226947304SEvan Yan /* 70326947304SEvan Yan * for multi-func device we allow multiple 70426947304SEvan Yan * configure on the same slot because one 70526947304SEvan Yan * func can be configured and other one won't 70626947304SEvan Yan */ 707bc6a100fSScott M. Carter DBG(1, ("configure\n")); 708bc6a100fSScott M. Carter if (state == DDI_HP_CN_STATE_EMPTY) { 709bc6a100fSScott M. Carter cfga_err(errstring, ERR_AP_ERR, 0); 710bc6a100fSScott M. Carter rv = CFGA_INVAL; 711bc6a100fSScott M. Carter } else if (hp_set_state(node, 0, new_state, &results) != 0) { 71226947304SEvan Yan rv = CFGA_ERROR; 71326947304SEvan Yan cfga_err(errstring, CMD_SLOT_CONFIGURE, 0); 71426947304SEvan Yan } 71526947304SEvan Yan break; 71626947304SEvan Yan 71726947304SEvan Yan case CFGA_CMD_UNCONFIGURE: 71826947304SEvan Yan DBG(1, ("unconfigure\n")); 719bc6a100fSScott M. Carter if (state == DDI_HP_CN_STATE_EMPTY) { 720bc6a100fSScott M. Carter cfga_err(errstring, ERR_AP_ERR, 0); 721bc6a100fSScott M. Carter rv = CFGA_INVAL; 722bc6a100fSScott M. Carter } else if (state >= DDI_HP_CN_STATE_ENABLED) { 723*29d8c27bSScott M. Carter rv = hp_set_state(node, hpflags, new_state, &results); 724*29d8c27bSScott M. Carter if (rv != 0) { 72526947304SEvan Yan if (rv == EBUSY) 72626947304SEvan Yan rv = CFGA_BUSY; 72726947304SEvan Yan else 72826947304SEvan Yan rv = CFGA_ERROR; 72926947304SEvan Yan 73026947304SEvan Yan if (results) { 73126947304SEvan Yan pci_rcm_info_table(results, errstring); 73226947304SEvan Yan hp_fini(results); 73326947304SEvan Yan } else { 73426947304SEvan Yan cfga_err(errstring, 73526947304SEvan Yan CMD_SLOT_UNCONFIGURE, 0); 73626947304SEvan Yan } 73726947304SEvan Yan } 73826947304SEvan Yan } 73926947304SEvan Yan DBG(1, ("unconfigure rv:(%i)\n", rv)); 74026947304SEvan Yan break; 74126947304SEvan Yan 74226947304SEvan Yan case CFGA_CMD_LOAD: 74326947304SEvan Yan /* do nothing, just produce error msg as is */ 74426947304SEvan Yan if (state < DDI_HP_CN_STATE_POWERED) { 74526947304SEvan Yan rv = CFGA_ERROR; 74626947304SEvan Yan cfga_err(errstring, CMD_SLOT_INSERT, 0); 74726947304SEvan Yan } else { 74826947304SEvan Yan cfga_err(errstring, ERR_AP_ERR, 0); 74926947304SEvan Yan rv = CFGA_INVAL; 75026947304SEvan Yan } 75126947304SEvan Yan break; 75226947304SEvan Yan 75326947304SEvan Yan case CFGA_CMD_UNLOAD: 75426947304SEvan Yan /* do nothing, just produce error msg as is */ 75526947304SEvan Yan if (state < DDI_HP_CN_STATE_POWERED) { 75626947304SEvan Yan rv = CFGA_ERROR; 75726947304SEvan Yan cfga_err(errstring, CMD_SLOT_REMOVE, 0); 75826947304SEvan Yan } else { 75926947304SEvan Yan cfga_err(errstring, ERR_AP_ERR, 0); 76026947304SEvan Yan rv = CFGA_INVAL; 76126947304SEvan Yan } 76226947304SEvan Yan break; 76326947304SEvan Yan 76426947304SEvan Yan default: 76526947304SEvan Yan rv = CFGA_OPNOTSUPP; 76626947304SEvan Yan break; 76726947304SEvan Yan } 76826947304SEvan Yan 76926947304SEvan Yan hp_fini(node); 77026947304SEvan Yan return (rv); 77126947304SEvan Yan } 77226947304SEvan Yan 77326947304SEvan Yan char * 77426947304SEvan Yan get_val_from_result(char *result) 77526947304SEvan Yan { 77626947304SEvan Yan char *tmp; 77726947304SEvan Yan 77826947304SEvan Yan tmp = strchr(result, '='); 77926947304SEvan Yan if (tmp == NULL) 78026947304SEvan Yan return (NULL); 78126947304SEvan Yan 78226947304SEvan Yan tmp++; 78326947304SEvan Yan return (tmp); 78426947304SEvan Yan } 78526947304SEvan Yan 78626947304SEvan Yan static cfga_err_t 78726947304SEvan Yan prt_led_mode(const char *ap_id, int repeat, char **errstring, 78826947304SEvan Yan struct cfga_msg *msgp) 78926947304SEvan Yan { 79026947304SEvan Yan pciehpc_led_t led; 79126947304SEvan Yan hp_node_t node; 79226947304SEvan Yan char *buff; 79326947304SEvan Yan char *buf; 79426947304SEvan Yan char *cp, line[MAXLINE]; 79526947304SEvan Yan char *tmp; 79626947304SEvan Yan char *format; 79726947304SEvan Yan char *result; 79826947304SEvan Yan int i, n, rv; 79926947304SEvan Yan int len = MAXLINE; 80026947304SEvan Yan 80126947304SEvan Yan pciehpc_led_t states[] = { 80226947304SEvan Yan PCIEHPC_POWER_LED, 80326947304SEvan Yan PCIEHPC_FAULT_LED, 80426947304SEvan Yan PCIEHPC_ATTN_LED, 80526947304SEvan Yan PCIEHPC_ACTIVE_LED 80626947304SEvan Yan }; 80726947304SEvan Yan 80826947304SEvan Yan DBG(1, ("prt_led_mod function\n")); 80926947304SEvan Yan if (!repeat) 81026947304SEvan Yan cfga_msg(msgp, "Ap_Id\t\t\tLed"); 81126947304SEvan Yan 81226947304SEvan Yan rv = physpath2node(ap_id, errstring, &node); 81326947304SEvan Yan if (rv != CFGA_OK) 81426947304SEvan Yan return (rv); 81526947304SEvan Yan 81626947304SEvan Yan if ((buff = malloc(MAXPATHLEN)) == NULL) { 81726947304SEvan Yan hp_fini(node); 81826947304SEvan Yan cfga_err(errstring, "malloc ", 0); 81926947304SEvan Yan return (CFGA_ERROR); 82026947304SEvan Yan } 82126947304SEvan Yan 82226947304SEvan Yan (void) memset(buff, 0, MAXPATHLEN); 82326947304SEvan Yan 82426947304SEvan Yan if (fix_ap_name(buff, ap_id, hp_name(node), 82526947304SEvan Yan errstring) != CFGA_OK) { 82626947304SEvan Yan hp_fini(node); 82726947304SEvan Yan free(buff); 82826947304SEvan Yan return (CFGA_ERROR); 82926947304SEvan Yan } 83026947304SEvan Yan 83126947304SEvan Yan cp = line; 83226947304SEvan Yan (void) snprintf(cp, len, "%s\t\t", buff); 83326947304SEvan Yan len -= strlen(cp); 83426947304SEvan Yan cp += strlen(cp); 83526947304SEvan Yan 83626947304SEvan Yan free(buff); 83726947304SEvan Yan 83826947304SEvan Yan n = sizeof (states)/sizeof (pciehpc_led_t); 83926947304SEvan Yan for (i = 0; i < n; i++) { 84026947304SEvan Yan led = states[i]; 84126947304SEvan Yan 84226947304SEvan Yan format = (i == n - 1) ? "%s=%s" : "%s=%s,"; 84326947304SEvan Yan if (hp_get_private(node, led_strs2[led], &result) != 0) { 84426947304SEvan Yan (void) snprintf(cp, len, format, 84526947304SEvan Yan led_strs[led], cfga_strs[UNKNOWN]); 84626947304SEvan Yan len -= strlen(cp); 84726947304SEvan Yan cp += strlen(cp); 84826947304SEvan Yan DBG(1, ("%s:%s\n", led_strs[led], cfga_strs[UNKNOWN])); 84926947304SEvan Yan } else { 85026947304SEvan Yan /* 85126947304SEvan Yan * hp_get_private() will return back things like 85226947304SEvan Yan * "led_fault=off", transform it to cfgadm desired 85326947304SEvan Yan * format. 85426947304SEvan Yan */ 85526947304SEvan Yan tmp = get_val_from_result(result); 85626947304SEvan Yan if (tmp == NULL) { 85726947304SEvan Yan free(result); 85826947304SEvan Yan hp_fini(node); 85926947304SEvan Yan return (CFGA_ERROR); 86026947304SEvan Yan } 86126947304SEvan Yan 86226947304SEvan Yan (void) snprintf(cp, len, format, 86326947304SEvan Yan led_strs[led], tmp); 86426947304SEvan Yan len -= strlen(cp); 86526947304SEvan Yan cp += strlen(cp); 86626947304SEvan Yan DBG(1, ("%s:%s\n", led_strs[led], tmp)); 86726947304SEvan Yan free(result); 86826947304SEvan Yan } 86926947304SEvan Yan } 87026947304SEvan Yan 87126947304SEvan Yan cfga_msg(msgp, line); /* print the message */ 87226947304SEvan Yan 87326947304SEvan Yan hp_fini(node); 87426947304SEvan Yan 87526947304SEvan Yan return (CFGA_OK); 87626947304SEvan Yan } 87726947304SEvan Yan 87826947304SEvan Yan /*ARGSUSED*/ 87926947304SEvan Yan cfga_err_t 88026947304SEvan Yan cfga_private_func(const char *function, const char *ap_id, 88126947304SEvan Yan const char *options, struct cfga_confirm *confp, 88226947304SEvan Yan struct cfga_msg *msgp, char **errstring, cfga_flags_t flags) 88326947304SEvan Yan { 88426947304SEvan Yan char *str; 88526947304SEvan Yan int len, fd, i = 0, repeat = 0; 88626947304SEvan Yan char buf[MAXNAMELEN]; 88726947304SEvan Yan char ptr; 88826947304SEvan Yan cfga_err_t rv; 88926947304SEvan Yan char *led, *mode; 89026947304SEvan Yan hp_node_t node; 89126947304SEvan Yan char *result; 89226947304SEvan Yan 89326947304SEvan Yan DBG(1, ("cfgadm_private_func: ap_id:%s\n", ap_id)); 89426947304SEvan Yan DBG(2, (" options: %s\n", (options == NULL)?"null":options)); 89526947304SEvan Yan DBG(2, (" confp: %x\n", confp)); 89626947304SEvan Yan DBG(2, (" cfga_msg: %x\n", cfga_msg)); 89726947304SEvan Yan DBG(2, (" flag: %d\n", flags)); 89826947304SEvan Yan 89926947304SEvan Yan if ((rv = check_options(options)) != CFGA_OK) { 90026947304SEvan Yan return (rv); 90126947304SEvan Yan } 90226947304SEvan Yan 90326947304SEvan Yan if (private_check == confp) 90426947304SEvan Yan repeat = 1; 90526947304SEvan Yan else 90626947304SEvan Yan private_check = (void*)confp; 90726947304SEvan Yan 90826947304SEvan Yan for (i = 0, str = func_strs[i], len = strlen(str); 90926947304SEvan Yan func_strs[i] != NULL; i++) { 91026947304SEvan Yan str = func_strs[i]; 91126947304SEvan Yan len = strlen(str); 91226947304SEvan Yan if (strncmp(function, str, len) == 0) 91326947304SEvan Yan break; 91426947304SEvan Yan } 91526947304SEvan Yan 91626947304SEvan Yan switch (i) { 91726947304SEvan Yan case ENABLE_SLOT: 91826947304SEvan Yan case DISABLE_SLOT: 91926947304SEvan Yan /* pass through */ 92026947304SEvan Yan case ENABLE_AUTOCNF: 92126947304SEvan Yan case DISABLE_AUTOCNF: 92226947304SEvan Yan /* no action needed */ 92326947304SEvan Yan return (CFGA_OK); 92426947304SEvan Yan break; 92526947304SEvan Yan case LED: 92626947304SEvan Yan /* set mode */ 92726947304SEvan Yan ptr = function[len++]; 92826947304SEvan Yan if (ptr == '=') { 92926947304SEvan Yan str = (char *)function; 93026947304SEvan Yan for (str = (str+len++), i = 0; *str != ','; 93126947304SEvan Yan i++, str++) { 93226947304SEvan Yan if (i == (MAXNAMELEN - 1)) 93326947304SEvan Yan break; 93426947304SEvan Yan 93526947304SEvan Yan buf[i] = *str; 93626947304SEvan Yan DBG_F(2, (stdout, "%c\n", buf[i])); 93726947304SEvan Yan } 93826947304SEvan Yan buf[i] = '\0'; str++; 93926947304SEvan Yan DBG(2, ("buf = %s\n", buf)); 94026947304SEvan Yan 94126947304SEvan Yan /* ACTIVE=3,ATTN=2,POWER=1,FAULT=0 */ 94226947304SEvan Yan if (strcmp(buf, led_strs[POWER]) == 0) 94326947304SEvan Yan led = PCIEHPC_PROP_LED_POWER; 94426947304SEvan Yan else if (strcmp(buf, led_strs[FAULT]) == 0) 94526947304SEvan Yan led = PCIEHPC_PROP_LED_FAULT; 94626947304SEvan Yan else if (strcmp(buf, led_strs[ATTN]) == 0) 94726947304SEvan Yan led = PCIEHPC_PROP_LED_ATTN; 94826947304SEvan Yan else if (strcmp(buf, led_strs[ACTIVE]) == 0) 94926947304SEvan Yan led = PCIEHPC_PROP_LED_ACTIVE; 95026947304SEvan Yan else return (CFGA_INVAL); 95126947304SEvan Yan 95226947304SEvan Yan len = strlen(func_strs[MODE]); 95326947304SEvan Yan if ((strncmp(str, func_strs[MODE], len) == 0) && 95426947304SEvan Yan (*(str+(len)) == '=')) { 95526947304SEvan Yan for (str = (str+(++len)), i = 0; 95626947304SEvan Yan *str != NULL; i++, str++) { 95726947304SEvan Yan buf[i] = *str; 95826947304SEvan Yan } 95926947304SEvan Yan } 96026947304SEvan Yan buf[i] = '\0'; 96126947304SEvan Yan DBG(2, ("buf_mode= %s\n", buf)); 96226947304SEvan Yan 96326947304SEvan Yan /* ON = 1, OFF = 0 */ 96426947304SEvan Yan if (strcmp(buf, mode_strs[ON]) == 0) 96526947304SEvan Yan mode = PCIEHPC_PROP_VALUE_ON; 96626947304SEvan Yan else if (strcmp(buf, mode_strs[OFF]) == 0) 96726947304SEvan Yan mode = PCIEHPC_PROP_VALUE_OFF; 96826947304SEvan Yan else if (strcmp(buf, mode_strs[BLINK]) == 0) 96926947304SEvan Yan mode = PCIEHPC_PROP_VALUE_BLINK; 97026947304SEvan Yan else return (CFGA_INVAL); 97126947304SEvan Yan 97226947304SEvan Yan /* sendin */ 97326947304SEvan Yan memset(buf, 0, sizeof (buf)); 97426947304SEvan Yan snprintf(buf, sizeof (buf), "%s=%s", 97526947304SEvan Yan led, mode); 97626947304SEvan Yan buf[MAXNAMELEN - 1] = '\0'; 97726947304SEvan Yan 97826947304SEvan Yan break; 97926947304SEvan Yan } else if (ptr == '\0') { 98026947304SEvan Yan /* print mode */ 98126947304SEvan Yan DBG(1, ("Print mode\n")); 98226947304SEvan Yan return (prt_led_mode(ap_id, repeat, errstring, 98326947304SEvan Yan msgp)); 98426947304SEvan Yan } 98526947304SEvan Yan default: 98626947304SEvan Yan DBG(1, ("default\n")); 98726947304SEvan Yan errno = EINVAL; 98826947304SEvan Yan return (CFGA_INVAL); 98926947304SEvan Yan } 99026947304SEvan Yan 99126947304SEvan Yan rv = physpath2node(ap_id, errstring, &node); 99226947304SEvan Yan if (rv != CFGA_OK) 99326947304SEvan Yan return (rv); 99426947304SEvan Yan 99526947304SEvan Yan if (hp_set_private(node, buf, &result) != 0) { 99626947304SEvan Yan hp_fini(node); 99726947304SEvan Yan return (CFGA_ERROR); 99826947304SEvan Yan } 99926947304SEvan Yan 100026947304SEvan Yan hp_fini(node); 100126947304SEvan Yan return (CFGA_OK); 100226947304SEvan Yan } 100326947304SEvan Yan 100426947304SEvan Yan /*ARGSUSED*/ 100526947304SEvan Yan cfga_err_t cfga_test(const char *ap_id, const char *options, 100626947304SEvan Yan struct cfga_msg *msgp, char **errstring, cfga_flags_t flags) 100726947304SEvan Yan { 100826947304SEvan Yan cfga_err_t rv; 100926947304SEvan Yan if (errstring != NULL) 101026947304SEvan Yan *errstring = NULL; 101126947304SEvan Yan 101226947304SEvan Yan if ((rv = check_options(options)) != CFGA_OK) { 101326947304SEvan Yan return (rv); 101426947304SEvan Yan } 101526947304SEvan Yan 101626947304SEvan Yan DBG(1, ("cfga_test:(%s)\n", ap_id)); 101726947304SEvan Yan /* will need to implement pci CTRL command */ 101826947304SEvan Yan return (CFGA_NOTSUPP); 101926947304SEvan Yan } 102026947304SEvan Yan 102126947304SEvan Yan /* 102226947304SEvan Yan * The slot-names property describes the external labeling of add-in slots. 102326947304SEvan Yan * This property is an encoded array, an integer followed by a list of 102426947304SEvan Yan * strings. The return value from di_prop_lookup_ints for slot-names is -1. 102526947304SEvan Yan * The expected return value should be the number of elements. 102626947304SEvan Yan * Di_prop_decode_common does not decode encoded data from software, 102726947304SEvan Yan * such as the solaris device tree, unlike from the prom. 102826947304SEvan Yan * Di_prop_decode_common takes the size of the encoded data and mods 102926947304SEvan Yan * it with the size of int. The size of the encoded data for slot-names is 9 103026947304SEvan Yan * and the size of int is 4, yielding a non zero result. A value of -1 is used 103126947304SEvan Yan * to indicate that the number of elements can not be determined. 103226947304SEvan Yan * Di_prop_decode_common can be modified to decode encoded data from the solaris 103326947304SEvan Yan * device tree. 103426947304SEvan Yan */ 103526947304SEvan Yan static int 103626947304SEvan Yan fixup_slotname(int rval, int *intp, struct searcharg *slotarg) 103726947304SEvan Yan { 103826947304SEvan Yan if ((slotarg->slt_name_src == PROM_SLT_NAME) && (rval == -1)) { 103926947304SEvan Yan return (DI_WALK_TERMINATE); 104026947304SEvan Yan } else { 104126947304SEvan Yan int i; 104226947304SEvan Yan char *tmptr = (char *)(intp+1); 104326947304SEvan Yan DBG(1, ("slot-bitmask: %x \n", *intp)); 104426947304SEvan Yan 104526947304SEvan Yan rval = (rval -1) * 4; 104626947304SEvan Yan 104726947304SEvan Yan for (i = 0; i <= slotarg->minor; i++) { 104826947304SEvan Yan DBG(2, ("curr slot-name: %s \n", tmptr)); 104926947304SEvan Yan 105026947304SEvan Yan if (i >= MAXDEVS) 105126947304SEvan Yan return (DI_WALK_TERMINATE); 105226947304SEvan Yan 105326947304SEvan Yan if ((*intp >> i) & 1) { 105426947304SEvan Yan /* assign tmptr */ 105526947304SEvan Yan DBG(2, ("slot-name: %s \n", tmptr)); 105626947304SEvan Yan if (i == slotarg->minor) 105726947304SEvan Yan (void) strcpy(slotarg->slotnames[i], 105826947304SEvan Yan tmptr); 105926947304SEvan Yan /* wind tmptr to next \0 */ 106026947304SEvan Yan while (*tmptr != '\0') { 106126947304SEvan Yan tmptr++; 106226947304SEvan Yan } 106326947304SEvan Yan tmptr++; 106426947304SEvan Yan } else { 106526947304SEvan Yan /* point at unknown string */ 106626947304SEvan Yan if (i == slotarg->minor) 106726947304SEvan Yan (void) strcpy(slotarg->slotnames[i], 106826947304SEvan Yan "unknown"); 106926947304SEvan Yan } 107026947304SEvan Yan } 107126947304SEvan Yan } 107226947304SEvan Yan return (DI_WALK_TERMINATE); 107326947304SEvan Yan } 107426947304SEvan Yan 107526947304SEvan Yan static int 107626947304SEvan Yan find_slotname(di_node_t din, di_minor_t dim, void *arg) 107726947304SEvan Yan { 107826947304SEvan Yan struct searcharg *slotarg = (struct searcharg *)arg; 107926947304SEvan Yan di_prom_handle_t ph = (di_prom_handle_t)slotarg->promp; 108026947304SEvan Yan di_prom_prop_t prom_prop; 108126947304SEvan Yan di_prop_t solaris_prop; 108226947304SEvan Yan int *intp, rval; 108326947304SEvan Yan char *devname; 108426947304SEvan Yan char fulldevname[MAXNAMELEN]; 108526947304SEvan Yan 108626947304SEvan Yan slotarg->minor = dim->dev_minor % 256; 108726947304SEvan Yan 108826947304SEvan Yan DBG(2, ("minor number:(%i)\n", slotarg->minor)); 108926947304SEvan Yan DBG(2, ("hot plug slots found so far:(%i)\n", 0)); 109026947304SEvan Yan 109126947304SEvan Yan if ((devname = di_devfs_path(din)) != NULL) { 109226947304SEvan Yan (void) snprintf(fulldevname, MAXNAMELEN, 109326947304SEvan Yan "/devices%s:%s", devname, di_minor_name(dim)); 109426947304SEvan Yan di_devfs_path_free(devname); 109526947304SEvan Yan } 109626947304SEvan Yan 109726947304SEvan Yan if (strcmp(fulldevname, slotarg->devpath) == 0) { 109826947304SEvan Yan 109926947304SEvan Yan /* 110026947304SEvan Yan * Check the Solaris device tree first 110126947304SEvan Yan * in the case of a DR operation 110226947304SEvan Yan */ 110326947304SEvan Yan solaris_prop = di_prop_hw_next(din, DI_PROP_NIL); 110426947304SEvan Yan while (solaris_prop != DI_PROP_NIL) { 110526947304SEvan Yan if (strcmp("slot-names", di_prop_name(solaris_prop)) 110626947304SEvan Yan == 0) { 110726947304SEvan Yan rval = di_prop_lookup_ints(DDI_DEV_T_ANY, 110826947304SEvan Yan din, di_prop_name(solaris_prop), &intp); 110926947304SEvan Yan slotarg->slt_name_src = SOLARIS_SLT_NAME; 111026947304SEvan Yan 111126947304SEvan Yan return (fixup_slotname(rval, intp, slotarg)); 111226947304SEvan Yan } 111326947304SEvan Yan solaris_prop = di_prop_hw_next(din, solaris_prop); 111426947304SEvan Yan } 111526947304SEvan Yan 111626947304SEvan Yan /* 111726947304SEvan Yan * Check the prom device tree which is populated at boot. 111826947304SEvan Yan * If this fails, give up and set the slot name to null. 111926947304SEvan Yan */ 112026947304SEvan Yan prom_prop = di_prom_prop_next(ph, din, DI_PROM_PROP_NIL); 112126947304SEvan Yan while (prom_prop != DI_PROM_PROP_NIL) { 112226947304SEvan Yan if (strcmp("slot-names", di_prom_prop_name(prom_prop)) 112326947304SEvan Yan == 0) { 112426947304SEvan Yan rval = di_prom_prop_lookup_ints(ph, 112526947304SEvan Yan din, di_prom_prop_name(prom_prop), &intp); 112626947304SEvan Yan slotarg->slt_name_src = PROM_SLT_NAME; 112726947304SEvan Yan 112826947304SEvan Yan return (fixup_slotname(rval, intp, slotarg)); 112926947304SEvan Yan } 113026947304SEvan Yan prom_prop = di_prom_prop_next(ph, din, prom_prop); 113126947304SEvan Yan } 113226947304SEvan Yan *slotarg->slotnames[slotarg->minor] = '\0'; 113326947304SEvan Yan return (DI_WALK_TERMINATE); 113426947304SEvan Yan } else 113526947304SEvan Yan return (DI_WALK_CONTINUE); 113626947304SEvan Yan } 113726947304SEvan Yan 113826947304SEvan Yan static int 113926947304SEvan Yan find_physical_slot_names(const char *devcomp, struct searcharg *slotarg) 114026947304SEvan Yan { 114126947304SEvan Yan di_node_t root_node; 114226947304SEvan Yan 114326947304SEvan Yan DBG(1, ("find_physical_slot_names\n")); 114426947304SEvan Yan 114526947304SEvan Yan if ((root_node = di_init("/", DINFOCPYALL|DINFOPATH)) 114626947304SEvan Yan == DI_NODE_NIL) { 114726947304SEvan Yan DBG(1, ("di_init() failed\n")); 114826947304SEvan Yan return (-1); 114926947304SEvan Yan } 115026947304SEvan Yan 115126947304SEvan Yan slotarg->devpath = (char *)devcomp; 115226947304SEvan Yan 115326947304SEvan Yan if ((slotarg->promp = di_prom_init()) == DI_PROM_HANDLE_NIL) { 115426947304SEvan Yan DBG(1, ("di_prom_init() failed\n")); 115526947304SEvan Yan di_fini(root_node); 115626947304SEvan Yan return (-1); 115726947304SEvan Yan } 115826947304SEvan Yan 115926947304SEvan Yan (void) di_walk_minor(root_node, "ddi_ctl:attachment_point:pci", 116026947304SEvan Yan 0, (void *)slotarg, find_slotname); 116126947304SEvan Yan 116226947304SEvan Yan di_prom_fini(slotarg->promp); 116326947304SEvan Yan di_fini(root_node); 116426947304SEvan Yan if (slotarg->slotnames[0] != NULL) 116526947304SEvan Yan return (0); 116626947304SEvan Yan else 116726947304SEvan Yan return (-1); 116826947304SEvan Yan } 116926947304SEvan Yan 117026947304SEvan Yan static void 117126947304SEvan Yan get_type(const char *boardtype, const char *cardtype, char *buf) 117226947304SEvan Yan { 117326947304SEvan Yan /* for type string assembly in get_type() */ 117426947304SEvan Yan #define TPCT(s) (void) strlcat(buf, (s), CFGA_TYPE_LEN) 117526947304SEvan Yan 117626947304SEvan Yan int i; 117726947304SEvan Yan 117826947304SEvan Yan if (strcmp(cardtype, "unknown") == 0) { 117926947304SEvan Yan TPCT("unknown"); 118026947304SEvan Yan return; 118126947304SEvan Yan } 118226947304SEvan Yan 118326947304SEvan Yan TPCT(cardtype); 118426947304SEvan Yan TPCT("/"); 118526947304SEvan Yan 118626947304SEvan Yan if (strcmp(boardtype, PCIEHPC_PROP_VALUE_PCIHOTPLUG) == 0) 118726947304SEvan Yan TPCT(board_strs[PCIEHPC_BOARD_PCI_HOTPLUG]); 118826947304SEvan Yan else 118926947304SEvan Yan TPCT(board_strs[PCIEHPC_BOARD_UNKNOWN]); 119026947304SEvan Yan } 119126947304SEvan Yan 119226947304SEvan Yan /* 119326947304SEvan Yan * call-back function for di_devlink_walk 119426947304SEvan Yan * if the link lives in /dev/cfg copy its name 119526947304SEvan Yan */ 119626947304SEvan Yan static int 119726947304SEvan Yan found_devlink(di_devlink_t link, void *ap_log_id) 119826947304SEvan Yan { 119926947304SEvan Yan if (strncmp("/dev/cfg/", di_devlink_path(link), 9) == 0) { 120026947304SEvan Yan /* copy everything but /dev/cfg/ */ 120126947304SEvan Yan (void) strcpy((char *)ap_log_id, di_devlink_path(link) + 9); 120226947304SEvan Yan DBG(1, ("found_devlink: %s\n", (char *)ap_log_id)); 120326947304SEvan Yan return (DI_WALK_TERMINATE); 120426947304SEvan Yan } 120526947304SEvan Yan return (DI_WALK_CONTINUE); 120626947304SEvan Yan } 120726947304SEvan Yan 120826947304SEvan Yan /* 120926947304SEvan Yan * Walk throught the cached /dev link tree looking for links to the ap 121026947304SEvan Yan * if none are found return an error 121126947304SEvan Yan */ 121226947304SEvan Yan static cfga_err_t 121326947304SEvan Yan check_devlinks(char *ap_log_id, const char *ap_id) 121426947304SEvan Yan { 121526947304SEvan Yan di_devlink_handle_t hdl; 121626947304SEvan Yan 121726947304SEvan Yan DBG(1, ("check_devlinks: %s\n", ap_id)); 121826947304SEvan Yan 121926947304SEvan Yan hdl = di_devlink_init(NULL, 0); 122026947304SEvan Yan 122126947304SEvan Yan if (strncmp("/devices/", ap_id, 9) == 0) { 122226947304SEvan Yan /* ap_id is a valid minor_path with /devices prepended */ 122326947304SEvan Yan (void) di_devlink_walk(hdl, NULL, ap_id + 8, DI_PRIMARY_LINK, 122426947304SEvan Yan (void *)ap_log_id, found_devlink); 122526947304SEvan Yan } else { 122626947304SEvan Yan DBG(1, ("check_devlinks: invalid ap_id: %s\n", ap_id)); 122726947304SEvan Yan return (CFGA_ERROR); 122826947304SEvan Yan } 122926947304SEvan Yan 123026947304SEvan Yan (void) di_devlink_fini(&hdl); 123126947304SEvan Yan 123226947304SEvan Yan if (ap_log_id[0] != '\0') 123326947304SEvan Yan return (CFGA_OK); 123426947304SEvan Yan else 123526947304SEvan Yan return (CFGA_ERROR); 123626947304SEvan Yan } 123726947304SEvan Yan 123826947304SEvan Yan /* 123926947304SEvan Yan * most of this is needed to compensate for 124026947304SEvan Yan * differences between various platforms 124126947304SEvan Yan */ 124226947304SEvan Yan static cfga_err_t 124326947304SEvan Yan fix_ap_name(char *ap_log_id, const char *ap_id, char *slot_name, 124426947304SEvan Yan char **errstring) 124526947304SEvan Yan { 124626947304SEvan Yan char *buf; 124726947304SEvan Yan char *tmp; 124826947304SEvan Yan char *ptr; 124926947304SEvan Yan 125026947304SEvan Yan di_node_t ap_node; 125126947304SEvan Yan 125226947304SEvan Yan ap_log_id[0] = '\0'; 125326947304SEvan Yan 125426947304SEvan Yan if (check_devlinks(ap_log_id, ap_id) == CFGA_OK) 125526947304SEvan Yan return (CFGA_OK); 125626947304SEvan Yan 125726947304SEvan Yan DBG(1, ("fix_ap_name: %s\n", ap_id)); 125826947304SEvan Yan 125926947304SEvan Yan if ((buf = malloc(strlen(ap_id) + 1)) == NULL) { 126026947304SEvan Yan DBG(1, ("malloc failed\n")); 126126947304SEvan Yan return (CFGA_ERROR); 126226947304SEvan Yan } 126326947304SEvan Yan (void) strcpy(buf, ap_id); 126426947304SEvan Yan tmp = buf + sizeof ("/devices") - 1; 126526947304SEvan Yan 126626947304SEvan Yan ptr = strchr(tmp, ':'); 126726947304SEvan Yan ptr[0] = '\0'; 126826947304SEvan Yan 126926947304SEvan Yan DBG(1, ("fix_ap_name: %s\n", tmp)); 127026947304SEvan Yan 127126947304SEvan Yan ap_node = di_init(tmp, DINFOMINOR); 127226947304SEvan Yan if (ap_node == DI_NODE_NIL) { 127326947304SEvan Yan cfga_err(errstring, "di_init ", 0); 127426947304SEvan Yan DBG(1, ("fix_ap_name: failed to snapshot node\n")); 127526947304SEvan Yan return (CFGA_ERROR); 127626947304SEvan Yan } 127726947304SEvan Yan 127826947304SEvan Yan (void) snprintf(ap_log_id, strlen(ap_id) + 1, "%s%i:%s", 127926947304SEvan Yan di_driver_name(ap_node), di_instance(ap_node), slot_name); 128026947304SEvan Yan 128126947304SEvan Yan DBG(1, ("fix_ap_name: %s\n", ap_log_id)); 128226947304SEvan Yan 128326947304SEvan Yan di_fini(ap_node); 128426947304SEvan Yan 128526947304SEvan Yan free(buf); 128626947304SEvan Yan return (CFGA_OK); 128726947304SEvan Yan } 128826947304SEvan Yan 128926947304SEvan Yan 129026947304SEvan Yan static int 129126947304SEvan Yan findlink_cb(di_devlink_t devlink, void *arg) 129226947304SEvan Yan { 129326947304SEvan Yan (*(char **)arg) = strdup(di_devlink_path(devlink)); 129426947304SEvan Yan 129526947304SEvan Yan return (DI_WALK_TERMINATE); 129626947304SEvan Yan } 129726947304SEvan Yan 129826947304SEvan Yan /* 129926947304SEvan Yan * returns an allocated string containing the full path to the devlink for 130026947304SEvan Yan * <ap_phys_id> in the devlink database; we expect only one devlink per 130126947304SEvan Yan * <ap_phys_id> so we return the first encountered 130226947304SEvan Yan */ 130326947304SEvan Yan static char * 130426947304SEvan Yan findlink(char *ap_phys_id) 130526947304SEvan Yan { 130626947304SEvan Yan di_devlink_handle_t hdl; 130726947304SEvan Yan char *path = NULL; 130826947304SEvan Yan 130926947304SEvan Yan hdl = di_devlink_init(NULL, 0); 131026947304SEvan Yan 131126947304SEvan Yan if (strncmp("/devices/", ap_phys_id, 9) == 0) 131226947304SEvan Yan ap_phys_id += 8; 131326947304SEvan Yan 131426947304SEvan Yan (void) di_devlink_walk(hdl, "^cfg/.+$", ap_phys_id, DI_PRIMARY_LINK, 131526947304SEvan Yan (void *)&path, findlink_cb); 131626947304SEvan Yan 131726947304SEvan Yan (void) di_devlink_fini(&hdl); 131826947304SEvan Yan return (path); 131926947304SEvan Yan } 132026947304SEvan Yan 132126947304SEvan Yan 132226947304SEvan Yan /* 132326947304SEvan Yan * returns CFGA_OK if it can succesfully retrieve the devlink info associated 132426947304SEvan Yan * with devlink for <ap_phys_id> which will be returned through <ap_info> 132526947304SEvan Yan */ 132626947304SEvan Yan cfga_err_t 132726947304SEvan Yan get_dli(char *dlpath, char *ap_info, int ap_info_sz) 132826947304SEvan Yan { 132926947304SEvan Yan int fd; 133026947304SEvan Yan 133126947304SEvan Yan fd = di_dli_openr(dlpath); 133226947304SEvan Yan if (fd < 0) 133326947304SEvan Yan return (CFGA_ERROR); 133426947304SEvan Yan 133526947304SEvan Yan (void) read(fd, ap_info, ap_info_sz); 133626947304SEvan Yan ap_info[ap_info_sz - 1] = '\0'; 133726947304SEvan Yan 133826947304SEvan Yan di_dli_close(fd); 133926947304SEvan Yan return (CFGA_OK); 134026947304SEvan Yan } 134126947304SEvan Yan 134226947304SEvan Yan static cfga_err_t 134326947304SEvan Yan cfga_get_condition(hp_node_t node, ap_condition_t *cond) 134426947304SEvan Yan { 134526947304SEvan Yan char *condition; 134626947304SEvan Yan 134726947304SEvan Yan /* "condition" bus specific commands */ 134826947304SEvan Yan if (hp_get_private(node, PCIEHPC_PROP_SLOT_CONDITION, 134926947304SEvan Yan &condition) != 0) { 135026947304SEvan Yan *cond = AP_COND_UNKNOWN; 135126947304SEvan Yan return (CFGA_ERROR); 135226947304SEvan Yan } 135326947304SEvan Yan 135426947304SEvan Yan condition = get_val_from_result(condition); 135526947304SEvan Yan 135626947304SEvan Yan if (strcmp(condition, PCIEHPC_PROP_COND_OK) == 0) 135726947304SEvan Yan *cond = AP_COND_OK; 135826947304SEvan Yan else if (strcmp(condition, PCIEHPC_PROP_COND_FAILING) == 0) 135926947304SEvan Yan *cond = AP_COND_FAILING; 136026947304SEvan Yan else if (strcmp(condition, PCIEHPC_PROP_COND_FAILED) == 0) 136126947304SEvan Yan *cond = AP_COND_FAILED; 136226947304SEvan Yan else if (strcmp(condition, PCIEHPC_PROP_COND_UNUSABLE) == 0) 136326947304SEvan Yan *cond = AP_COND_UNUSABLE; 136426947304SEvan Yan else if (strcmp(condition, PCIEHPC_PROP_COND_UNKNOWN) == 0) 136526947304SEvan Yan *cond = AP_COND_UNKNOWN; 136626947304SEvan Yan else 136726947304SEvan Yan return (CFGA_ERROR); 136826947304SEvan Yan 136926947304SEvan Yan return (CFGA_OK); 137026947304SEvan Yan } 137126947304SEvan Yan 137226947304SEvan Yan /*ARGSUSED*/ 137326947304SEvan Yan cfga_err_t 137426947304SEvan Yan cfga_list_ext(const char *ap_id, cfga_list_data_t **cs, 137526947304SEvan Yan int *nlist, const char *options, const char *listopts, char **errstring, 137626947304SEvan Yan cfga_flags_t flags) 137726947304SEvan Yan { 137826947304SEvan Yan char *boardtype; 137926947304SEvan Yan char *cardtype; 138026947304SEvan Yan struct searcharg slotname_arg; 138126947304SEvan Yan int fd; 138226947304SEvan Yan int rv = CFGA_OK; 138326947304SEvan Yan char *dlpath = NULL; 138426947304SEvan Yan hp_node_t node; 138526947304SEvan Yan ap_rstate_t rs; 138626947304SEvan Yan ap_ostate_t os; 138726947304SEvan Yan ap_condition_t cond; 138826947304SEvan Yan 138926947304SEvan Yan if ((rv = check_options(options)) != CFGA_OK) { 139026947304SEvan Yan return (rv); 139126947304SEvan Yan } 139226947304SEvan Yan 139326947304SEvan Yan if (errstring != NULL) 139426947304SEvan Yan *errstring = NULL; 139526947304SEvan Yan 139626947304SEvan Yan DBG(1, ("cfga_list_ext:(%s)\n", ap_id)); 139726947304SEvan Yan 139826947304SEvan Yan if (cs == NULL || nlist == NULL) { 139926947304SEvan Yan rv = CFGA_ERROR; 140026947304SEvan Yan return (rv); 140126947304SEvan Yan } 140226947304SEvan Yan 140326947304SEvan Yan *nlist = 1; 140426947304SEvan Yan 140526947304SEvan Yan if ((*cs = malloc(sizeof (cfga_list_data_t))) == NULL) { 140626947304SEvan Yan cfga_err(errstring, "malloc ", 0); 140726947304SEvan Yan DBG(1, ("malloc failed\n")); 140826947304SEvan Yan rv = CFGA_ERROR; 140926947304SEvan Yan return (rv); 141026947304SEvan Yan } 141126947304SEvan Yan (void) memset(*cs, 0, sizeof (cfga_list_data_t)); 141226947304SEvan Yan 141326947304SEvan Yan rv = physpath2node(ap_id, errstring, &node); 141426947304SEvan Yan if (rv != CFGA_OK) { 141526947304SEvan Yan DBG(1, ("physpath2node failed\n")); 141626947304SEvan Yan return (rv); 141726947304SEvan Yan } 141826947304SEvan Yan 141926947304SEvan Yan if (cfga_get_state(node, &rs, &os) != CFGA_OK) { 142026947304SEvan Yan DBG(1, ("cfga_get_state failed\n")); 142126947304SEvan Yan hp_fini(node); 142226947304SEvan Yan return (CFGA_ERROR); 142326947304SEvan Yan } 142426947304SEvan Yan 142526947304SEvan Yan switch (rs) { 142626947304SEvan Yan case AP_RSTATE_EMPTY: 142726947304SEvan Yan (*cs)->ap_r_state = CFGA_STAT_EMPTY; 142826947304SEvan Yan DBG(2, ("ap_rstate = CFGA_STAT_EMPTY\n")); 142926947304SEvan Yan break; 143026947304SEvan Yan case AP_RSTATE_DISCONNECTED: 143126947304SEvan Yan (*cs)->ap_r_state = CFGA_STAT_DISCONNECTED; 143226947304SEvan Yan DBG(2, ("ap_rstate = CFGA_STAT_DISCONNECTED\n")); 143326947304SEvan Yan break; 143426947304SEvan Yan case AP_RSTATE_CONNECTED: 143526947304SEvan Yan (*cs)->ap_r_state = CFGA_STAT_CONNECTED; 143626947304SEvan Yan DBG(2, ("ap_rstate = CFGA_STAT_CONNECTED\n")); 143726947304SEvan Yan break; 143826947304SEvan Yan default: 143926947304SEvan Yan cfga_err(errstring, CMD_GETSTAT, ap_id, 0); 144026947304SEvan Yan rv = CFGA_ERROR; 144126947304SEvan Yan hp_fini(node); 144226947304SEvan Yan return (rv); 144326947304SEvan Yan } 144426947304SEvan Yan 144526947304SEvan Yan switch (os) { 144626947304SEvan Yan case AP_OSTATE_CONFIGURED: 144726947304SEvan Yan (*cs)->ap_o_state = CFGA_STAT_CONFIGURED; 144826947304SEvan Yan DBG(2, ("ap_ostate = CFGA_STAT_CONFIGURED\n")); 144926947304SEvan Yan break; 145026947304SEvan Yan case AP_OSTATE_UNCONFIGURED: 145126947304SEvan Yan (*cs)->ap_o_state = CFGA_STAT_UNCONFIGURED; 145226947304SEvan Yan DBG(2, ("ap_ostate = CFGA_STAT_UNCONFIGURED\n")); 145326947304SEvan Yan break; 145426947304SEvan Yan default: 145526947304SEvan Yan cfga_err(errstring, CMD_GETSTAT, ap_id, 0); 145626947304SEvan Yan rv = CFGA_ERROR; 145726947304SEvan Yan hp_fini(node); 145826947304SEvan Yan return (rv); 145926947304SEvan Yan } 146026947304SEvan Yan 146126947304SEvan Yan (void) cfga_get_condition(node, &cond); 146226947304SEvan Yan 146326947304SEvan Yan switch (cond) { 146426947304SEvan Yan case AP_COND_OK: 146526947304SEvan Yan (*cs)->ap_cond = CFGA_COND_OK; 146626947304SEvan Yan DBG(2, ("ap_cond = CFGA_COND_OK\n")); 146726947304SEvan Yan break; 146826947304SEvan Yan case AP_COND_FAILING: 146926947304SEvan Yan (*cs)->ap_cond = CFGA_COND_FAILING; 147026947304SEvan Yan DBG(2, ("ap_cond = CFGA_COND_FAILING\n")); 147126947304SEvan Yan break; 147226947304SEvan Yan case AP_COND_FAILED: 147326947304SEvan Yan (*cs)->ap_cond = CFGA_COND_FAILED; 147426947304SEvan Yan DBG(2, ("ap_cond = CFGA_COND_FAILED\n")); 147526947304SEvan Yan break; 147626947304SEvan Yan case AP_COND_UNUSABLE: 147726947304SEvan Yan (*cs)->ap_cond = CFGA_COND_UNUSABLE; 147826947304SEvan Yan DBG(2, ("ap_cond = CFGA_COND_UNUSABLE\n")); 147926947304SEvan Yan break; 148026947304SEvan Yan case AP_COND_UNKNOWN: 148126947304SEvan Yan (*cs)->ap_cond = CFGA_COND_UNKNOWN; 148226947304SEvan Yan DBG(2, ("ap_cond = CFGA_COND_UNKNOW\n")); 148326947304SEvan Yan break; 148426947304SEvan Yan default: 148526947304SEvan Yan cfga_err(errstring, CMD_GETSTAT, ap_id, 0); 148626947304SEvan Yan rv = CFGA_ERROR; 148726947304SEvan Yan hp_fini(node); 148826947304SEvan Yan return (rv); 148926947304SEvan Yan } 149026947304SEvan Yan /* 149126947304SEvan Yan * We're not busy since the entrance into the kernel has been 149226947304SEvan Yan * sync'ed via libhotplug. 149326947304SEvan Yan */ 149426947304SEvan Yan (*cs)->ap_busy = 0; 149526947304SEvan Yan 149626947304SEvan Yan /* last change */ 149726947304SEvan Yan (*cs)->ap_status_time = hp_last_change(node); 149826947304SEvan Yan 149926947304SEvan Yan /* board type */ 150026947304SEvan Yan if (hp_get_private(node, PCIEHPC_PROP_BOARD_TYPE, &boardtype) != 0) 150126947304SEvan Yan boardtype = PCIEHPC_PROP_VALUE_UNKNOWN; 150226947304SEvan Yan else 150326947304SEvan Yan boardtype = get_val_from_result(boardtype); 150426947304SEvan Yan 150526947304SEvan Yan /* card type */ 150626947304SEvan Yan if (hp_get_private(node, PCIEHPC_PROP_CARD_TYPE, &cardtype) != 0) 150726947304SEvan Yan cardtype = PCIEHPC_PROP_VALUE_UNKNOWN; 150826947304SEvan Yan else 150926947304SEvan Yan cardtype = get_val_from_result(cardtype); 151026947304SEvan Yan 151126947304SEvan Yan /* logical ap_id */ 151226947304SEvan Yan rv = fix_ap_name((*cs)->ap_log_id, ap_id, 151326947304SEvan Yan hp_name(node), errstring); 151426947304SEvan Yan DBG(1, ("logical id: %s\n", (*cs)->ap_log_id)); 151526947304SEvan Yan /* physical ap_id */ 151626947304SEvan Yan (void) strcpy((*cs)->ap_phys_id, ap_id); /* physical path of AP */ 151726947304SEvan Yan 151826947304SEvan Yan /* information */ 151926947304SEvan Yan dlpath = findlink((*cs)->ap_phys_id); 152026947304SEvan Yan if (dlpath != NULL) { 152126947304SEvan Yan if (get_dli(dlpath, (*cs)->ap_info, 152226947304SEvan Yan sizeof ((*cs)->ap_info)) != CFGA_OK) 152326947304SEvan Yan (*cs)->ap_info[0] = '\0'; 152426947304SEvan Yan free(dlpath); 152526947304SEvan Yan } 152626947304SEvan Yan 152726947304SEvan Yan if ((*cs)->ap_log_id[0] == '\0') 152826947304SEvan Yan (void) strcpy((*cs)->ap_log_id, hp_name(node)); 152926947304SEvan Yan 153026947304SEvan Yan if ((*cs)->ap_info[0] == '\0') { 153126947304SEvan Yan /* slot_names of bus node */ 153226947304SEvan Yan if (find_physical_slot_names(ap_id, &slotname_arg) != -1) 153326947304SEvan Yan (void) strcpy((*cs)->ap_info, 153426947304SEvan Yan slotname_arg.slotnames[slotname_arg.minor]); 153526947304SEvan Yan } 153626947304SEvan Yan 153726947304SEvan Yan /* class_code/subclass/boardtype */ 153826947304SEvan Yan get_type(boardtype, cardtype, (*cs)->ap_type); 153926947304SEvan Yan 154026947304SEvan Yan DBG(1, ("cfga_list_ext return success\n")); 154126947304SEvan Yan rv = CFGA_OK; 154226947304SEvan Yan 154326947304SEvan Yan hp_fini(node); 154426947304SEvan Yan return (rv); 154526947304SEvan Yan } 154626947304SEvan Yan 154726947304SEvan Yan /* 154826947304SEvan Yan * This routine prints a single line of help message 154926947304SEvan Yan */ 155026947304SEvan Yan static void 155126947304SEvan Yan cfga_msg(struct cfga_msg *msgp, const char *str) 155226947304SEvan Yan { 155326947304SEvan Yan DBG(2, ("<%s>", str)); 155426947304SEvan Yan 155526947304SEvan Yan if (msgp == NULL || msgp->message_routine == NULL) 155626947304SEvan Yan return; 155726947304SEvan Yan 155826947304SEvan Yan (*msgp->message_routine)(msgp->appdata_ptr, str); 155926947304SEvan Yan (*msgp->message_routine)(msgp->appdata_ptr, "\n"); 156026947304SEvan Yan } 156126947304SEvan Yan 156226947304SEvan Yan static cfga_err_t 156326947304SEvan Yan check_options(const char *options) 156426947304SEvan Yan { 156526947304SEvan Yan struct cfga_msg *msgp = NULL; 156626947304SEvan Yan 156726947304SEvan Yan if (options) { 156826947304SEvan Yan cfga_msg(msgp, dgettext(TEXT_DOMAIN, cfga_strs[HELP_UNKNOWN])); 156926947304SEvan Yan cfga_msg(msgp, options); 157026947304SEvan Yan return (CFGA_INVAL); 157126947304SEvan Yan } 157226947304SEvan Yan return (CFGA_OK); 157326947304SEvan Yan } 157426947304SEvan Yan 157526947304SEvan Yan /*ARGSUSED*/ 157626947304SEvan Yan cfga_err_t 157726947304SEvan Yan cfga_help(struct cfga_msg *msgp, const char *options, cfga_flags_t flags) 157826947304SEvan Yan { 157926947304SEvan Yan if (options) { 158026947304SEvan Yan cfga_msg(msgp, dgettext(TEXT_DOMAIN, cfga_strs[HELP_UNKNOWN])); 158126947304SEvan Yan cfga_msg(msgp, options); 158226947304SEvan Yan } 158326947304SEvan Yan DBG(1, ("cfga_help\n")); 158426947304SEvan Yan 158526947304SEvan Yan cfga_msg(msgp, dgettext(TEXT_DOMAIN, cfga_strs[HELP_HEADER])); 158626947304SEvan Yan cfga_msg(msgp, cfga_strs[HELP_CONFIG]); 158726947304SEvan Yan cfga_msg(msgp, cfga_strs[HELP_ENABLE_SLOT]); 158826947304SEvan Yan cfga_msg(msgp, cfga_strs[HELP_DISABLE_SLOT]); 158926947304SEvan Yan cfga_msg(msgp, cfga_strs[HELP_ENABLE_AUTOCONF]); 159026947304SEvan Yan cfga_msg(msgp, cfga_strs[HELP_DISABLE_AUTOCONF]); 159126947304SEvan Yan cfga_msg(msgp, cfga_strs[HELP_LED_CNTRL]); 159226947304SEvan Yan return (CFGA_OK); 159326947304SEvan Yan } 159426947304SEvan Yan 159526947304SEvan Yan /* 159626947304SEvan Yan * cfga_err() accepts a variable number of message IDs and constructs 159726947304SEvan Yan * a corresponding error string which is returned via the errstring argument. 159826947304SEvan Yan * cfga_err() calls gettext() to internationalize proper messages. 159926947304SEvan Yan */ 160026947304SEvan Yan static void 160126947304SEvan Yan cfga_err(char **errstring, ...) 160226947304SEvan Yan { 160326947304SEvan Yan int a; 160426947304SEvan Yan int i; 160526947304SEvan Yan int n; 160626947304SEvan Yan int len; 160726947304SEvan Yan int flen; 160826947304SEvan Yan char *p; 160926947304SEvan Yan char *q; 161026947304SEvan Yan char *s[32]; 161126947304SEvan Yan char *failed; 161226947304SEvan Yan va_list ap; 161326947304SEvan Yan 161426947304SEvan Yan /* 161526947304SEvan Yan * If errstring is null it means user is not interested in getting 161626947304SEvan Yan * error status. So we don't do all the work 161726947304SEvan Yan */ 161826947304SEvan Yan if (errstring == NULL) { 161926947304SEvan Yan return; 162026947304SEvan Yan } 162126947304SEvan Yan va_start(ap, errstring); 162226947304SEvan Yan 162326947304SEvan Yan failed = dgettext(TEXT_DOMAIN, cfga_strs[FAILED]); 162426947304SEvan Yan flen = strlen(failed); 162526947304SEvan Yan 162626947304SEvan Yan for (n = len = 0; (a = va_arg(ap, int)) != 0; n++) { 162726947304SEvan Yan switch (a) { 162826947304SEvan Yan case CMD_GETSTAT: 162926947304SEvan Yan case CMD_LIST: 163026947304SEvan Yan case CMD_SLOT_CONNECT: 163126947304SEvan Yan case CMD_SLOT_DISCONNECT: 163226947304SEvan Yan case CMD_SLOT_CONFIGURE: 163326947304SEvan Yan case CMD_SLOT_UNCONFIGURE: 163426947304SEvan Yan p = cfga_errstrs(a); 163526947304SEvan Yan len += (strlen(p) + flen); 163626947304SEvan Yan s[n] = p; 163726947304SEvan Yan s[++n] = cfga_strs[FAILED]; 163826947304SEvan Yan 163926947304SEvan Yan DBG(2, ("<%s>", p)); 164026947304SEvan Yan DBG(2, (cfga_strs[FAILED])); 164126947304SEvan Yan break; 164226947304SEvan Yan 164326947304SEvan Yan case ERR_CMD_INVAL: 164426947304SEvan Yan case ERR_AP_INVAL: 164526947304SEvan Yan case ERR_OPT_INVAL: 164626947304SEvan Yan case ERR_AP_ERR: 164726947304SEvan Yan switch (a) { 164826947304SEvan Yan case ERR_CMD_INVAL: 164926947304SEvan Yan p = dgettext(TEXT_DOMAIN, 165026947304SEvan Yan cfga_errstrs[ERR_CMD_INVAL]); 165126947304SEvan Yan break; 165226947304SEvan Yan case ERR_AP_INVAL: 165326947304SEvan Yan p = dgettext(TEXT_DOMAIN, 165426947304SEvan Yan cfga_errstrs[ERR_AP_INVAL]); 165526947304SEvan Yan break; 165626947304SEvan Yan case ERR_OPT_INVAL: 165726947304SEvan Yan p = dgettext(TEXT_DOMAIN, 165826947304SEvan Yan cfga_errstrs[ERR_OPT_INVAL]); 165926947304SEvan Yan break; 166026947304SEvan Yan case ERR_AP_ERR: 166126947304SEvan Yan p = dgettext(TEXT_DOMAIN, 166226947304SEvan Yan cfga_errstrs[ERR_AP_ERR]); 166326947304SEvan Yan break; 166426947304SEvan Yan } 166526947304SEvan Yan 166626947304SEvan Yan if ((q = va_arg(ap, char *)) != NULL) { 166726947304SEvan Yan len += (strlen(p) + strlen(q)); 166826947304SEvan Yan s[n] = p; 166926947304SEvan Yan s[++n] = q; 167026947304SEvan Yan DBG(2, ("<%s>", p)); 167126947304SEvan Yan DBG(2, ("<%s>", q)); 167226947304SEvan Yan break; 167326947304SEvan Yan } else { 167426947304SEvan Yan len += strlen(p); 167526947304SEvan Yan s[n] = p; 167626947304SEvan Yan 167726947304SEvan Yan } 167826947304SEvan Yan DBG(2, ("<%s>", p)); 167926947304SEvan Yan break; 168026947304SEvan Yan 168126947304SEvan Yan default: 168226947304SEvan Yan n--; 168326947304SEvan Yan break; 168426947304SEvan Yan } 168526947304SEvan Yan } 168626947304SEvan Yan 168726947304SEvan Yan DBG(2, ("\n")); 168826947304SEvan Yan va_end(ap); 168926947304SEvan Yan 169026947304SEvan Yan if ((p = calloc(len + 1, 1)) == NULL) 169126947304SEvan Yan return; 169226947304SEvan Yan 169326947304SEvan Yan for (i = 0; i < n; i++) { 169426947304SEvan Yan (void) strlcat(p, s[i], len + 1); 169526947304SEvan Yan DBG(2, ("i:%d, %s\n", i, s[i])); 169626947304SEvan Yan } 169726947304SEvan Yan 169826947304SEvan Yan *errstring = p; 169926947304SEvan Yan DBG(2, ("%s\n", *errstring)); 170026947304SEvan Yan } 170126947304SEvan Yan 170226947304SEvan Yan /* 170326947304SEvan Yan * cfga_ap_id_cmp -- use default_ap_id_cmp() in libcfgadm 170426947304SEvan Yan */ 1705