1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * Implementation of ri_init routine for obtaining mapping 31*0Sstevel@tonic-gate * of system board attachment points to physical devices and to 32*0Sstevel@tonic-gate * the Reconfiguration Coordination Manager (RCM) client usage 33*0Sstevel@tonic-gate * of these devices. 34*0Sstevel@tonic-gate */ 35*0Sstevel@tonic-gate #include <string.h> 36*0Sstevel@tonic-gate #include <stdlib.h> 37*0Sstevel@tonic-gate #include <unistd.h> 38*0Sstevel@tonic-gate #include <kstat.h> 39*0Sstevel@tonic-gate #include <sys/param.h> 40*0Sstevel@tonic-gate #include <sys/sbd_ioctl.h> 41*0Sstevel@tonic-gate #include "rsrc_info_impl.h" 42*0Sstevel@tonic-gate 43*0Sstevel@tonic-gate /* 44*0Sstevel@tonic-gate * Occupant types exported by cfgadm sbd plugin via 45*0Sstevel@tonic-gate * config_admin(3CFGADM). 46*0Sstevel@tonic-gate */ 47*0Sstevel@tonic-gate #define SBD_CM_CPU "cpu" 48*0Sstevel@tonic-gate #define SBD_CM_MEM "memory" 49*0Sstevel@tonic-gate #define SBD_CM_IO "io" 50*0Sstevel@tonic-gate 51*0Sstevel@tonic-gate /* 52*0Sstevel@tonic-gate * RCM abstract resource names. 53*0Sstevel@tonic-gate */ 54*0Sstevel@tonic-gate #define RCM_MEM_ALL "SUNW_memory" 55*0Sstevel@tonic-gate #define RCM_CPU_ALL "SUNW_cpu" 56*0Sstevel@tonic-gate #define RCM_CPU RCM_CPU_ALL"/cpu" 57*0Sstevel@tonic-gate 58*0Sstevel@tonic-gate #define KBYTE 1024 59*0Sstevel@tonic-gate #define MBYTE 1048576 60*0Sstevel@tonic-gate #define USAGE_ALLOC_SIZE 128 61*0Sstevel@tonic-gate 62*0Sstevel@tonic-gate /* 63*0Sstevel@tonic-gate * define to allow io_cm_info to return NODE is NULL to ri_init, 64*0Sstevel@tonic-gate * in order to skip over nodes w/unattached drivers 65*0Sstevel@tonic-gate */ 66*0Sstevel@tonic-gate #define RI_NODE_NIL 1 67*0Sstevel@tonic-gate 68*0Sstevel@tonic-gate /* 69*0Sstevel@tonic-gate * This code is CMP aware as it parses the 70*0Sstevel@tonic-gate * cfgadm info field for individual cpuids. 71*0Sstevel@tonic-gate */ 72*0Sstevel@tonic-gate #define CPUID_SEP "," 73*0Sstevel@tonic-gate #define CPU_INFO_FMT "cpuid=%s speed=%d ecache=%d" 74*0Sstevel@tonic-gate 75*0Sstevel@tonic-gate typedef struct { 76*0Sstevel@tonic-gate cfga_list_data_t *cfga_list_data; 77*0Sstevel@tonic-gate int nlist; 78*0Sstevel@tonic-gate } apd_t; 79*0Sstevel@tonic-gate 80*0Sstevel@tonic-gate typedef struct { 81*0Sstevel@tonic-gate long pagesize; 82*0Sstevel@tonic-gate long syspages; 83*0Sstevel@tonic-gate long sysmb; 84*0Sstevel@tonic-gate } mem_stat_t; 85*0Sstevel@tonic-gate 86*0Sstevel@tonic-gate #define ms_syspages m_stat.syspages 87*0Sstevel@tonic-gate #define ms_pagesize m_stat.pagesize 88*0Sstevel@tonic-gate #define ms_sysmb m_stat.sysmb 89*0Sstevel@tonic-gate 90*0Sstevel@tonic-gate typedef int32_t cpuid_t; 91*0Sstevel@tonic-gate 92*0Sstevel@tonic-gate typedef struct { 93*0Sstevel@tonic-gate int cpuid_max; /* maximum cpuid value */ 94*0Sstevel@tonic-gate int *ecache_sizes; /* indexed by cpuid */ 95*0Sstevel@tonic-gate } ecache_info_t; 96*0Sstevel@tonic-gate 97*0Sstevel@tonic-gate typedef struct { 98*0Sstevel@tonic-gate rcm_handle_t *hdl; 99*0Sstevel@tonic-gate rcm_info_t *offline_query_info; 100*0Sstevel@tonic-gate char **rlist; 101*0Sstevel@tonic-gate int nrlist; 102*0Sstevel@tonic-gate cpuid_t *cpus; 103*0Sstevel@tonic-gate int ncpus; 104*0Sstevel@tonic-gate int ndevs; 105*0Sstevel@tonic-gate uint_t query_pages; 106*0Sstevel@tonic-gate mem_stat_t m_stat; 107*0Sstevel@tonic-gate ecache_info_t ecache_info; 108*0Sstevel@tonic-gate } rcmd_t; 109*0Sstevel@tonic-gate 110*0Sstevel@tonic-gate typedef struct { 111*0Sstevel@tonic-gate const char *rsrc; 112*0Sstevel@tonic-gate const char *info; 113*0Sstevel@tonic-gate } usage_t; 114*0Sstevel@tonic-gate 115*0Sstevel@tonic-gate /* Lookup table entry for matching IO devices to RCM resource usage */ 116*0Sstevel@tonic-gate typedef struct { 117*0Sstevel@tonic-gate int index; /* index into the table array */ 118*0Sstevel@tonic-gate di_node_t node; /* associated devinfo node */ 119*0Sstevel@tonic-gate char *name; /* device full path name */ 120*0Sstevel@tonic-gate int n_usage; 121*0Sstevel@tonic-gate usage_t *usage; 122*0Sstevel@tonic-gate } lookup_entry_t; 123*0Sstevel@tonic-gate 124*0Sstevel@tonic-gate typedef struct { 125*0Sstevel@tonic-gate int n_entries; 126*0Sstevel@tonic-gate int n_slots; 127*0Sstevel@tonic-gate lookup_entry_t *table; 128*0Sstevel@tonic-gate } lookup_table_t; 129*0Sstevel@tonic-gate 130*0Sstevel@tonic-gate typedef struct { 131*0Sstevel@tonic-gate int err; 132*0Sstevel@tonic-gate di_node_t node; 133*0Sstevel@tonic-gate char *pathbuf; 134*0Sstevel@tonic-gate lookup_table_t *table; 135*0Sstevel@tonic-gate di_devlink_handle_t linkhd; 136*0Sstevel@tonic-gate } devinfo_arg_t; 137*0Sstevel@tonic-gate 138*0Sstevel@tonic-gate static int dyn_ap_ids(char *, cfga_list_data_t **, int *); 139*0Sstevel@tonic-gate static int rcm_init(rcmd_t *, apd_t [], int, int); 140*0Sstevel@tonic-gate static void rcm_fini(rcmd_t *); 141*0Sstevel@tonic-gate static int rcm_query_init(rcmd_t *, apd_t [], int); 142*0Sstevel@tonic-gate static int cap_request(ri_hdl_t *, rcmd_t *); 143*0Sstevel@tonic-gate static int syscpus(cpuid_t **, int *); 144*0Sstevel@tonic-gate static int cpu_cap_request(ri_hdl_t *, rcmd_t *); 145*0Sstevel@tonic-gate static int mem_cap_request(ri_hdl_t *, rcmd_t *); 146*0Sstevel@tonic-gate static int (*cm_rcm_qpass_func(cfga_type_t))(cfga_list_data_t *, rcmd_t *); 147*0Sstevel@tonic-gate static int cpu_rcm_qpass(cfga_list_data_t *, rcmd_t *); 148*0Sstevel@tonic-gate static int mem_rcm_qpass(cfga_list_data_t *, rcmd_t *); 149*0Sstevel@tonic-gate static int io_rcm_qpass(cfga_list_data_t *, rcmd_t *); 150*0Sstevel@tonic-gate static int (*cm_info_func(cfga_type_t))(ri_ap_t *, cfga_list_data_t *, int, 151*0Sstevel@tonic-gate rcmd_t *); 152*0Sstevel@tonic-gate static int cpu_cm_info(ri_ap_t *, cfga_list_data_t *, int, rcmd_t *); 153*0Sstevel@tonic-gate static int i_cpu_cm_info(processorid_t, int, ri_ap_t *, rcmd_t *); 154*0Sstevel@tonic-gate static int mem_cm_info(ri_ap_t *, cfga_list_data_t *, int, rcmd_t *); 155*0Sstevel@tonic-gate static int io_cm_info(ri_ap_t *, cfga_list_data_t *, int, rcmd_t *); 156*0Sstevel@tonic-gate static int ident_leaf(di_node_t); 157*0Sstevel@tonic-gate static int mk_drv_inst(di_node_t, char [], char *); 158*0Sstevel@tonic-gate static int devinfo_node_walk(di_node_t, void *); 159*0Sstevel@tonic-gate static int devinfo_minor_walk(di_node_t, di_minor_t, void *); 160*0Sstevel@tonic-gate static int devinfo_devlink_walk(di_devlink_t, void *); 161*0Sstevel@tonic-gate static int add_rcm_clients(ri_client_t **, rcmd_t *, rcm_info_t *, int, int *); 162*0Sstevel@tonic-gate static int rcm_ignore(char *, char *); 163*0Sstevel@tonic-gate static int add_query_state(rcmd_t *, ri_client_t *, const char *, const char *); 164*0Sstevel@tonic-gate static int state2query(int); 165*0Sstevel@tonic-gate static void dev_list_append(ri_dev_t **, ri_dev_t *); 166*0Sstevel@tonic-gate static void dev_list_cpu_insert(ri_dev_t **, ri_dev_t *, processorid_t); 167*0Sstevel@tonic-gate static rcm_info_tuple_t *tuple_lookup(rcmd_t *, const char *, const char *); 168*0Sstevel@tonic-gate static ri_ap_t *ri_ap_alloc(char *, ri_hdl_t *); 169*0Sstevel@tonic-gate static ri_dev_t *ri_dev_alloc(void); 170*0Sstevel@tonic-gate static ri_dev_t *io_dev_alloc(char *); 171*0Sstevel@tonic-gate static ri_client_t *ri_client_alloc(char *, char *); 172*0Sstevel@tonic-gate static void apd_tbl_free(apd_t [], int); 173*0Sstevel@tonic-gate static char *pstate2str(int); 174*0Sstevel@tonic-gate static int ecache_info_init(ecache_info_t *); 175*0Sstevel@tonic-gate static int find_cpu_nodes(di_node_t, void *); 176*0Sstevel@tonic-gate static int prop_lookup_int(di_node_t, di_prom_handle_t, char *, int **); 177*0Sstevel@tonic-gate static int add_lookup_entry(lookup_table_t *, const char *, di_node_t); 178*0Sstevel@tonic-gate static int table_compare_names(const void *, const void *); 179*0Sstevel@tonic-gate static int table_compare_indices(const void *, const void *); 180*0Sstevel@tonic-gate static lookup_entry_t *lookup(lookup_table_t *table, const char *); 181*0Sstevel@tonic-gate static int add_usage(lookup_entry_t *, const char *, rcm_info_tuple_t *); 182*0Sstevel@tonic-gate static void empty_table(lookup_table_t *); 183*0Sstevel@tonic-gate 184*0Sstevel@tonic-gate #ifdef DEBUG 185*0Sstevel@tonic-gate static void dump_apd_tbl(FILE *, apd_t *, int); 186*0Sstevel@tonic-gate #endif /* DEBUG */ 187*0Sstevel@tonic-gate 188*0Sstevel@tonic-gate static struct { 189*0Sstevel@tonic-gate char *type; 190*0Sstevel@tonic-gate int (*cm_info)(ri_ap_t *, cfga_list_data_t *, int, rcmd_t *); 191*0Sstevel@tonic-gate int (*cm_rcm_qpass)(cfga_list_data_t *, rcmd_t *); 192*0Sstevel@tonic-gate } cm_ctl[] = { 193*0Sstevel@tonic-gate {SBD_CM_CPU, cpu_cm_info, cpu_rcm_qpass}, 194*0Sstevel@tonic-gate {SBD_CM_MEM, mem_cm_info, mem_rcm_qpass}, 195*0Sstevel@tonic-gate {SBD_CM_IO, io_cm_info, io_rcm_qpass} 196*0Sstevel@tonic-gate }; 197*0Sstevel@tonic-gate 198*0Sstevel@tonic-gate /* 199*0Sstevel@tonic-gate * Table of known info string prefixes for RCM modules that do not 200*0Sstevel@tonic-gate * represent actual resource usage, but instead provide name translations 201*0Sstevel@tonic-gate * or sequencing within the RCM namespace. Since RCM provides no way to 202*0Sstevel@tonic-gate * filter these out, we must maintain this hack. 203*0Sstevel@tonic-gate */ 204*0Sstevel@tonic-gate static char *rcm_info_filter[] = { 205*0Sstevel@tonic-gate "Network interface", /* Network naming module */ 206*0Sstevel@tonic-gate NULL 207*0Sstevel@tonic-gate }; 208*0Sstevel@tonic-gate 209*0Sstevel@tonic-gate 210*0Sstevel@tonic-gate /* 211*0Sstevel@tonic-gate * Allocate snapshot handle. 212*0Sstevel@tonic-gate */ 213*0Sstevel@tonic-gate int 214*0Sstevel@tonic-gate ri_init(int n_apids, char **ap_ids, int flags, ri_hdl_t **hdlp) 215*0Sstevel@tonic-gate { 216*0Sstevel@tonic-gate int i, j; 217*0Sstevel@tonic-gate ri_hdl_t *ri_hdl; 218*0Sstevel@tonic-gate ri_ap_t *ap_hdl; 219*0Sstevel@tonic-gate rcmd_t *rcm = NULL; 220*0Sstevel@tonic-gate cfga_list_data_t *cfga_ldata; 221*0Sstevel@tonic-gate apd_t *apd, *apd_tbl = NULL; 222*0Sstevel@tonic-gate int (*cm_info)(ri_ap_t *, cfga_list_data_t *, 223*0Sstevel@tonic-gate int, rcmd_t *); 224*0Sstevel@tonic-gate int rv = RI_SUCCESS; 225*0Sstevel@tonic-gate int cm_info_rv; 226*0Sstevel@tonic-gate 227*0Sstevel@tonic-gate if (n_apids <= 0 || ap_ids == NULL || hdlp == NULL) 228*0Sstevel@tonic-gate return (RI_INVAL); 229*0Sstevel@tonic-gate 230*0Sstevel@tonic-gate if (flags & ~RI_REQ_MASK) 231*0Sstevel@tonic-gate return (RI_NOTSUP); 232*0Sstevel@tonic-gate 233*0Sstevel@tonic-gate *hdlp = NULL; 234*0Sstevel@tonic-gate if ((ri_hdl = calloc(1, sizeof (*ri_hdl))) == NULL || 235*0Sstevel@tonic-gate (rcm = calloc(1, sizeof (*rcm))) == NULL || 236*0Sstevel@tonic-gate (apd_tbl = calloc(n_apids, sizeof (*apd_tbl))) == NULL) { 237*0Sstevel@tonic-gate dprintf((stderr, "calloc: %s\n", strerror(errno))); 238*0Sstevel@tonic-gate rv = RI_FAILURE; 239*0Sstevel@tonic-gate goto out; 240*0Sstevel@tonic-gate } 241*0Sstevel@tonic-gate 242*0Sstevel@tonic-gate /* 243*0Sstevel@tonic-gate * Create mapping of boards to components. 244*0Sstevel@tonic-gate */ 245*0Sstevel@tonic-gate for (i = 0, apd = apd_tbl; i < n_apids; i++, apd++) { 246*0Sstevel@tonic-gate if (dyn_ap_ids(ap_ids[i], &apd->cfga_list_data, 247*0Sstevel@tonic-gate &apd->nlist) == -1) { 248*0Sstevel@tonic-gate rv = RI_INVAL; 249*0Sstevel@tonic-gate goto out; 250*0Sstevel@tonic-gate } 251*0Sstevel@tonic-gate } 252*0Sstevel@tonic-gate #ifdef DEBUG 253*0Sstevel@tonic-gate dump_apd_tbl(stderr, apd_tbl, n_apids); 254*0Sstevel@tonic-gate #endif /* DEBUG */ 255*0Sstevel@tonic-gate 256*0Sstevel@tonic-gate if (rcm_init(rcm, apd_tbl, n_apids, flags) != 0) { 257*0Sstevel@tonic-gate rv = RI_FAILURE; 258*0Sstevel@tonic-gate goto out; 259*0Sstevel@tonic-gate } 260*0Sstevel@tonic-gate 261*0Sstevel@tonic-gate /* 262*0Sstevel@tonic-gate * Best effort attempt to read cpu ecache sizes from 263*0Sstevel@tonic-gate * OBP/Solaris device trees. These are later looked up 264*0Sstevel@tonic-gate * in i_cpu_cm_info(). 265*0Sstevel@tonic-gate */ 266*0Sstevel@tonic-gate (void) ecache_info_init(&rcm->ecache_info); 267*0Sstevel@tonic-gate 268*0Sstevel@tonic-gate for (i = 0, apd = apd_tbl; i < n_apids; i++, apd++) { 269*0Sstevel@tonic-gate if ((ap_hdl = ri_ap_alloc(ap_ids[i], ri_hdl)) == NULL) { 270*0Sstevel@tonic-gate rv = RI_FAILURE; 271*0Sstevel@tonic-gate goto out; 272*0Sstevel@tonic-gate } 273*0Sstevel@tonic-gate 274*0Sstevel@tonic-gate /* 275*0Sstevel@tonic-gate * Add component info based on occupant type. Note all 276*0Sstevel@tonic-gate * passes through the apd table skip over the first 277*0Sstevel@tonic-gate * cfgadm_list_data entry, which is the static system board 278*0Sstevel@tonic-gate * attachment point. 279*0Sstevel@tonic-gate */ 280*0Sstevel@tonic-gate for (j = 1, cfga_ldata = &apd->cfga_list_data[1]; 281*0Sstevel@tonic-gate j < apd->nlist; j++, cfga_ldata++) { 282*0Sstevel@tonic-gate if (cfga_ldata->ap_o_state != CFGA_STAT_CONFIGURED) { 283*0Sstevel@tonic-gate continue; 284*0Sstevel@tonic-gate } 285*0Sstevel@tonic-gate 286*0Sstevel@tonic-gate if ((cm_info = 287*0Sstevel@tonic-gate cm_info_func(cfga_ldata->ap_type)) != NULL) { 288*0Sstevel@tonic-gate cm_info_rv = 289*0Sstevel@tonic-gate (*cm_info)(ap_hdl, cfga_ldata, flags, rcm); 290*0Sstevel@tonic-gate if (cm_info_rv != 0) { 291*0Sstevel@tonic-gate /* 292*0Sstevel@tonic-gate * If we cannot obtain info for the ap, 293*0Sstevel@tonic-gate * skip it and do not fail the entire 294*0Sstevel@tonic-gate * operation. This case occurs when the 295*0Sstevel@tonic-gate * driver for a device is not attached: 296*0Sstevel@tonic-gate * di_init() returns failed back to 297*0Sstevel@tonic-gate * io_cm_info(). 298*0Sstevel@tonic-gate */ 299*0Sstevel@tonic-gate if (cm_info_rv == RI_NODE_NIL) 300*0Sstevel@tonic-gate continue; 301*0Sstevel@tonic-gate else { 302*0Sstevel@tonic-gate rv = RI_FAILURE; 303*0Sstevel@tonic-gate goto out; 304*0Sstevel@tonic-gate } 305*0Sstevel@tonic-gate } 306*0Sstevel@tonic-gate } 307*0Sstevel@tonic-gate } 308*0Sstevel@tonic-gate } 309*0Sstevel@tonic-gate 310*0Sstevel@tonic-gate if ((flags & RI_INCLUDE_QUERY) && cap_request(ri_hdl, rcm) != 0) 311*0Sstevel@tonic-gate rv = RI_FAILURE; 312*0Sstevel@tonic-gate 313*0Sstevel@tonic-gate out: 314*0Sstevel@tonic-gate if (apd_tbl != NULL) 315*0Sstevel@tonic-gate apd_tbl_free(apd_tbl, n_apids); 316*0Sstevel@tonic-gate if (rcm != NULL) 317*0Sstevel@tonic-gate rcm_fini(rcm); 318*0Sstevel@tonic-gate 319*0Sstevel@tonic-gate if (rv == RI_SUCCESS) 320*0Sstevel@tonic-gate *hdlp = ri_hdl; 321*0Sstevel@tonic-gate else 322*0Sstevel@tonic-gate ri_fini(ri_hdl); 323*0Sstevel@tonic-gate 324*0Sstevel@tonic-gate return (rv); 325*0Sstevel@tonic-gate } 326*0Sstevel@tonic-gate 327*0Sstevel@tonic-gate /* 328*0Sstevel@tonic-gate * Map static board attachment point to dynamic attachment points (components). 329*0Sstevel@tonic-gate */ 330*0Sstevel@tonic-gate static int 331*0Sstevel@tonic-gate dyn_ap_ids(char *ap_id, cfga_list_data_t **ap_id_list, int *nlist) 332*0Sstevel@tonic-gate { 333*0Sstevel@tonic-gate cfga_err_t cfga_err; 334*0Sstevel@tonic-gate char *errstr; 335*0Sstevel@tonic-gate char *opts = "parsable"; 336*0Sstevel@tonic-gate char *listops = "class=sbd"; 337*0Sstevel@tonic-gate 338*0Sstevel@tonic-gate cfga_err = config_list_ext(1, &ap_id, ap_id_list, nlist, 339*0Sstevel@tonic-gate opts, listops, &errstr, CFGA_FLAG_LIST_ALL); 340*0Sstevel@tonic-gate if (cfga_err != CFGA_OK) { 341*0Sstevel@tonic-gate dprintf((stderr, "config_list_ext: %s\n", 342*0Sstevel@tonic-gate config_strerror(cfga_err))); 343*0Sstevel@tonic-gate return (-1); 344*0Sstevel@tonic-gate } 345*0Sstevel@tonic-gate 346*0Sstevel@tonic-gate return (0); 347*0Sstevel@tonic-gate } 348*0Sstevel@tonic-gate 349*0Sstevel@tonic-gate /* 350*0Sstevel@tonic-gate * Initialize rcm handle, memory stats. Cache query result if necessary. 351*0Sstevel@tonic-gate */ 352*0Sstevel@tonic-gate static int 353*0Sstevel@tonic-gate rcm_init(rcmd_t *rcm, apd_t apd_tbl[], int napds, int flags) 354*0Sstevel@tonic-gate { 355*0Sstevel@tonic-gate longlong_t ii; 356*0Sstevel@tonic-gate int rv = 0; 357*0Sstevel@tonic-gate 358*0Sstevel@tonic-gate rcm->offline_query_info = NULL; 359*0Sstevel@tonic-gate rcm->rlist = NULL; 360*0Sstevel@tonic-gate rcm->cpus = NULL; 361*0Sstevel@tonic-gate 362*0Sstevel@tonic-gate if (rcm_alloc_handle(NULL, RCM_NOPID, NULL, &rcm->hdl) != RCM_SUCCESS) { 363*0Sstevel@tonic-gate dprintf((stderr, "rcm_alloc_handle (errno=%d)\n", errno)); 364*0Sstevel@tonic-gate return (-1); 365*0Sstevel@tonic-gate } 366*0Sstevel@tonic-gate 367*0Sstevel@tonic-gate if ((rcm->ms_pagesize = sysconf(_SC_PAGE_SIZE)) == -1 || 368*0Sstevel@tonic-gate (rcm->ms_syspages = sysconf(_SC_PHYS_PAGES)) == -1) { 369*0Sstevel@tonic-gate dprintf((stderr, "sysconf: %s\n", strerror(errno))); 370*0Sstevel@tonic-gate return (-1); 371*0Sstevel@tonic-gate } 372*0Sstevel@tonic-gate ii = (longlong_t)rcm->ms_pagesize * rcm->ms_syspages; 373*0Sstevel@tonic-gate rcm->ms_sysmb = (int)((ii+MBYTE-1) / MBYTE); 374*0Sstevel@tonic-gate 375*0Sstevel@tonic-gate if (flags & RI_INCLUDE_QUERY) 376*0Sstevel@tonic-gate rv = rcm_query_init(rcm, apd_tbl, napds); 377*0Sstevel@tonic-gate 378*0Sstevel@tonic-gate return (rv); 379*0Sstevel@tonic-gate } 380*0Sstevel@tonic-gate 381*0Sstevel@tonic-gate static void 382*0Sstevel@tonic-gate rcm_fini(rcmd_t *rcm) 383*0Sstevel@tonic-gate { 384*0Sstevel@tonic-gate char **cpp; 385*0Sstevel@tonic-gate 386*0Sstevel@tonic-gate assert(rcm != NULL); 387*0Sstevel@tonic-gate 388*0Sstevel@tonic-gate if (rcm->offline_query_info != NULL) 389*0Sstevel@tonic-gate rcm_free_info(rcm->offline_query_info); 390*0Sstevel@tonic-gate if (rcm->hdl != NULL) 391*0Sstevel@tonic-gate rcm_free_handle(rcm->hdl); 392*0Sstevel@tonic-gate 393*0Sstevel@tonic-gate if (rcm->rlist != NULL) { 394*0Sstevel@tonic-gate for (cpp = rcm->rlist; *cpp != NULL; cpp++) 395*0Sstevel@tonic-gate s_free(*cpp); 396*0Sstevel@tonic-gate free(rcm->rlist); 397*0Sstevel@tonic-gate } 398*0Sstevel@tonic-gate 399*0Sstevel@tonic-gate s_free(rcm->cpus); 400*0Sstevel@tonic-gate free(rcm); 401*0Sstevel@tonic-gate } 402*0Sstevel@tonic-gate 403*0Sstevel@tonic-gate #define NODENAME_CMP "cmp" 404*0Sstevel@tonic-gate #define NODENAME_SSM "ssm" 405*0Sstevel@tonic-gate #define PROP_CPUID "cpuid" 406*0Sstevel@tonic-gate #define PROP_DEVICE_TYPE "device-type" 407*0Sstevel@tonic-gate #define PROP_ECACHE_SIZE "ecache-size" 408*0Sstevel@tonic-gate #define PROP_L2_CACHE_SIZE "l2-cache-size" 409*0Sstevel@tonic-gate #define PROP_L3_CACHE_SIZE "l3-cache-size" 410*0Sstevel@tonic-gate 411*0Sstevel@tonic-gate typedef struct { 412*0Sstevel@tonic-gate di_node_t root; 413*0Sstevel@tonic-gate di_prom_handle_t ph; 414*0Sstevel@tonic-gate ecache_info_t *ecache_info; 415*0Sstevel@tonic-gate } di_arg_t; 416*0Sstevel@tonic-gate 417*0Sstevel@tonic-gate /* 418*0Sstevel@tonic-gate * The ecache sizes for individual cpus are read from the 419*0Sstevel@tonic-gate * OBP/Solaris device trees. This info cannot be derived 420*0Sstevel@tonic-gate * from the cfgadm_sbd cpu attachment point ecache info, 421*0Sstevel@tonic-gate * which may be a sum of multiple cores for CMP. 422*0Sstevel@tonic-gate */ 423*0Sstevel@tonic-gate static int 424*0Sstevel@tonic-gate ecache_info_init(ecache_info_t *ec) 425*0Sstevel@tonic-gate { 426*0Sstevel@tonic-gate di_arg_t di_arg; 427*0Sstevel@tonic-gate di_prom_handle_t ph = DI_PROM_HANDLE_NIL; 428*0Sstevel@tonic-gate di_node_t root = DI_NODE_NIL; 429*0Sstevel@tonic-gate int cpuid_max, rv = 0; 430*0Sstevel@tonic-gate 431*0Sstevel@tonic-gate assert(ec != NULL && ec->cpuid_max == 0 && ec->ecache_sizes == NULL); 432*0Sstevel@tonic-gate 433*0Sstevel@tonic-gate if ((cpuid_max = sysconf(_SC_CPUID_MAX)) == -1) { 434*0Sstevel@tonic-gate dprintf((stderr, "sysconf fail: %s\n", strerror(errno))); 435*0Sstevel@tonic-gate rv = -1; 436*0Sstevel@tonic-gate goto done; 437*0Sstevel@tonic-gate } 438*0Sstevel@tonic-gate 439*0Sstevel@tonic-gate if ((root = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) { 440*0Sstevel@tonic-gate dprintf((stderr, "di_init fail: %s\n", strerror(errno))); 441*0Sstevel@tonic-gate rv = -1; 442*0Sstevel@tonic-gate goto done; 443*0Sstevel@tonic-gate } 444*0Sstevel@tonic-gate 445*0Sstevel@tonic-gate if ((ph = di_prom_init()) == DI_PROM_HANDLE_NIL) { 446*0Sstevel@tonic-gate dprintf((stderr, "di_prom_init fail: %s\n", strerror(errno))); 447*0Sstevel@tonic-gate rv = -1; 448*0Sstevel@tonic-gate goto done; 449*0Sstevel@tonic-gate } 450*0Sstevel@tonic-gate 451*0Sstevel@tonic-gate if ((ec->ecache_sizes = calloc(cpuid_max + 1, sizeof (int))) == NULL) { 452*0Sstevel@tonic-gate dprintf((stderr, "calloc fail: %s\n", strerror(errno))); 453*0Sstevel@tonic-gate rv = -1; 454*0Sstevel@tonic-gate goto done; 455*0Sstevel@tonic-gate } 456*0Sstevel@tonic-gate ec->cpuid_max = cpuid_max; 457*0Sstevel@tonic-gate 458*0Sstevel@tonic-gate dprintf((stderr, "cpuid_max is set to %d\n", ec->cpuid_max)); 459*0Sstevel@tonic-gate 460*0Sstevel@tonic-gate di_arg.ph = ph; 461*0Sstevel@tonic-gate di_arg.root = root; 462*0Sstevel@tonic-gate di_arg.ecache_info = ec; 463*0Sstevel@tonic-gate 464*0Sstevel@tonic-gate if (di_walk_node(root, DI_WALK_CLDFIRST, (void *)&di_arg, 465*0Sstevel@tonic-gate find_cpu_nodes) != 0) { 466*0Sstevel@tonic-gate dprintf((stderr, "di_walk_node fail: %s\n", strerror(errno))); 467*0Sstevel@tonic-gate rv = -1; 468*0Sstevel@tonic-gate } 469*0Sstevel@tonic-gate 470*0Sstevel@tonic-gate done: 471*0Sstevel@tonic-gate if (root != DI_NODE_NIL) 472*0Sstevel@tonic-gate di_fini(root); 473*0Sstevel@tonic-gate if (ph != DI_PROM_HANDLE_NIL) 474*0Sstevel@tonic-gate di_prom_fini(ph); 475*0Sstevel@tonic-gate 476*0Sstevel@tonic-gate return (rv); 477*0Sstevel@tonic-gate } 478*0Sstevel@tonic-gate 479*0Sstevel@tonic-gate /* 480*0Sstevel@tonic-gate * Libdevinfo node walk callback for reading ecache size 481*0Sstevel@tonic-gate * properties for cpu device nodes. Subtrees not containing 482*0Sstevel@tonic-gate * cpu nodes are filtered out. 483*0Sstevel@tonic-gate */ 484*0Sstevel@tonic-gate static int 485*0Sstevel@tonic-gate find_cpu_nodes(di_node_t node, void *arg) 486*0Sstevel@tonic-gate { 487*0Sstevel@tonic-gate char *name; 488*0Sstevel@tonic-gate int *cpuid, *ecache; 489*0Sstevel@tonic-gate di_arg_t *di_arg = (di_arg_t *)arg; 490*0Sstevel@tonic-gate ecache_info_t *ec = di_arg->ecache_info; 491*0Sstevel@tonic-gate di_prom_handle_t ph = di_arg->ph; 492*0Sstevel@tonic-gate 493*0Sstevel@tonic-gate if (node == DI_NODE_NIL) { 494*0Sstevel@tonic-gate return (DI_WALK_TERMINATE); 495*0Sstevel@tonic-gate } 496*0Sstevel@tonic-gate 497*0Sstevel@tonic-gate if (node == di_arg->root) { 498*0Sstevel@tonic-gate return (DI_WALK_CONTINUE); 499*0Sstevel@tonic-gate } 500*0Sstevel@tonic-gate 501*0Sstevel@tonic-gate if (di_nodeid(node) == DI_PSEUDO_NODEID) { 502*0Sstevel@tonic-gate return (DI_WALK_PRUNECHILD); 503*0Sstevel@tonic-gate } 504*0Sstevel@tonic-gate 505*0Sstevel@tonic-gate name = di_node_name(node); 506*0Sstevel@tonic-gate if (name != NULL) { 507*0Sstevel@tonic-gate /* 508*0Sstevel@tonic-gate * CMP nodes will be the parent of cpu nodes. On some platforms, 509*0Sstevel@tonic-gate * cpu nodes will be under the ssm node. In either case, 510*0Sstevel@tonic-gate * continue searching this subtree. 511*0Sstevel@tonic-gate */ 512*0Sstevel@tonic-gate if (strncmp(name, NODENAME_SSM, strlen(NODENAME_SSM)) == 0 || 513*0Sstevel@tonic-gate strncmp(name, NODENAME_CMP, strlen(NODENAME_CMP)) == 0) { 514*0Sstevel@tonic-gate return (DI_WALK_CONTINUE); 515*0Sstevel@tonic-gate } 516*0Sstevel@tonic-gate } 517*0Sstevel@tonic-gate 518*0Sstevel@tonic-gate dprintf((stderr, "find_cpu_nodes: node=%p, name=%s, binding_name=%s\n", 519*0Sstevel@tonic-gate node, di_node_name(node), di_binding_name(node))); 520*0Sstevel@tonic-gate 521*0Sstevel@tonic-gate /* 522*0Sstevel@tonic-gate * Ecache size property name differs with processor implementation. 523*0Sstevel@tonic-gate * Panther has both L2 and L3, so check for L3 first to differentiate 524*0Sstevel@tonic-gate * from Jaguar, which has only L2. 525*0Sstevel@tonic-gate */ 526*0Sstevel@tonic-gate if (prop_lookup_int(node, ph, PROP_CPUID, &cpuid) == 0 && 527*0Sstevel@tonic-gate (prop_lookup_int(node, ph, PROP_ECACHE_SIZE, &ecache) == 0 || 528*0Sstevel@tonic-gate prop_lookup_int(node, ph, PROP_L3_CACHE_SIZE, &ecache) == 0 || 529*0Sstevel@tonic-gate prop_lookup_int(node, ph, PROP_L2_CACHE_SIZE, &ecache) == 0)) { 530*0Sstevel@tonic-gate assert(ec != NULL && ec->ecache_sizes != NULL && 531*0Sstevel@tonic-gate *cpuid <= ec->cpuid_max); 532*0Sstevel@tonic-gate ec->ecache_sizes[*cpuid] = *ecache; 533*0Sstevel@tonic-gate } 534*0Sstevel@tonic-gate 535*0Sstevel@tonic-gate return (DI_WALK_PRUNECHILD); 536*0Sstevel@tonic-gate } 537*0Sstevel@tonic-gate 538*0Sstevel@tonic-gate /* 539*0Sstevel@tonic-gate * Given a di_node_t, call the appropriate int property lookup routine. 540*0Sstevel@tonic-gate * Note: This lookup fails if the int property has multiple value entries. 541*0Sstevel@tonic-gate */ 542*0Sstevel@tonic-gate static int 543*0Sstevel@tonic-gate prop_lookup_int(di_node_t node, di_prom_handle_t ph, char *propname, int **ival) 544*0Sstevel@tonic-gate { 545*0Sstevel@tonic-gate int rv; 546*0Sstevel@tonic-gate 547*0Sstevel@tonic-gate rv = (di_nodeid(node) == DI_PROM_NODEID) ? 548*0Sstevel@tonic-gate di_prom_prop_lookup_ints(ph, node, propname, ival) : 549*0Sstevel@tonic-gate di_prop_lookup_ints(DDI_DEV_T_ANY, node, propname, ival); 550*0Sstevel@tonic-gate 551*0Sstevel@tonic-gate return (rv == 1 ? 0 : -1); 552*0Sstevel@tonic-gate } 553*0Sstevel@tonic-gate 554*0Sstevel@tonic-gate /* 555*0Sstevel@tonic-gate * For offline queries, RCM must be given a list of all resources 556*0Sstevel@tonic-gate * so modules can have access to the full scope of the operation. 557*0Sstevel@tonic-gate * The rcm_get_info calls are made individually in order to map the 558*0Sstevel@tonic-gate * returned rcm_info_t's to physical devices. The rcm_request_offline 559*0Sstevel@tonic-gate * result is cached so the query state can be looked up as we process 560*0Sstevel@tonic-gate * the rcm_get_info calls. This routine also tallies up the amount of 561*0Sstevel@tonic-gate * memory going away and creates a list of cpu ids to be used 562*0Sstevel@tonic-gate * later for rcm_request_capacity_change. 563*0Sstevel@tonic-gate */ 564*0Sstevel@tonic-gate static int 565*0Sstevel@tonic-gate rcm_query_init(rcmd_t *rcm, apd_t apd_tbl[], int napds) 566*0Sstevel@tonic-gate { 567*0Sstevel@tonic-gate apd_t *apd; 568*0Sstevel@tonic-gate int i, j; 569*0Sstevel@tonic-gate cfga_list_data_t *cfga_ldata; 570*0Sstevel@tonic-gate int (*cm_rcm_qpass)(cfga_list_data_t *, rcmd_t *); 571*0Sstevel@tonic-gate #ifdef DEBUG 572*0Sstevel@tonic-gate char **cpp; 573*0Sstevel@tonic-gate #endif /* DEBUG */ 574*0Sstevel@tonic-gate 575*0Sstevel@tonic-gate /* 576*0Sstevel@tonic-gate * Initial pass to size cpu and resource name arrays needed to 577*0Sstevel@tonic-gate * interface with RCM. Attachment point ids for CMP can represent 578*0Sstevel@tonic-gate * multiple cpus (and resource names). Instead of parsing the 579*0Sstevel@tonic-gate * cfgadm info field here, use the worse case that all component 580*0Sstevel@tonic-gate * attachment points are CMP. 581*0Sstevel@tonic-gate */ 582*0Sstevel@tonic-gate rcm->ndevs = 0; 583*0Sstevel@tonic-gate for (i = 0, apd = apd_tbl; i < napds; i++, apd++) { 584*0Sstevel@tonic-gate for (j = 1, cfga_ldata = &apd->cfga_list_data[1]; 585*0Sstevel@tonic-gate j < apd->nlist; j++, cfga_ldata++) { 586*0Sstevel@tonic-gate if (cfga_ldata->ap_o_state != CFGA_STAT_CONFIGURED) { 587*0Sstevel@tonic-gate continue; 588*0Sstevel@tonic-gate } 589*0Sstevel@tonic-gate rcm->ndevs += SBD_MAX_CORES_PER_CMP; 590*0Sstevel@tonic-gate } 591*0Sstevel@tonic-gate } 592*0Sstevel@tonic-gate 593*0Sstevel@tonic-gate /* account for trailing NULL in rlist */ 594*0Sstevel@tonic-gate if (rcm->ndevs > 0 && 595*0Sstevel@tonic-gate ((rcm->cpus = calloc(rcm->ndevs, sizeof (cpuid_t))) == NULL || 596*0Sstevel@tonic-gate (rcm->rlist = calloc(rcm->ndevs + 1, sizeof (char *))) == NULL)) { 597*0Sstevel@tonic-gate dprintf((stderr, "calloc: %s\n", strerror(errno))); 598*0Sstevel@tonic-gate return (-1); 599*0Sstevel@tonic-gate } 600*0Sstevel@tonic-gate 601*0Sstevel@tonic-gate /* 602*0Sstevel@tonic-gate * Second pass to fill in the RCM resource and cpu lists. 603*0Sstevel@tonic-gate */ 604*0Sstevel@tonic-gate for (i = 0, apd = apd_tbl; i < napds; i++, apd++) { 605*0Sstevel@tonic-gate for (j = 1, cfga_ldata = &apd->cfga_list_data[1]; 606*0Sstevel@tonic-gate j < apd->nlist; j++, cfga_ldata++) { 607*0Sstevel@tonic-gate if (cfga_ldata->ap_o_state != CFGA_STAT_CONFIGURED) { 608*0Sstevel@tonic-gate continue; 609*0Sstevel@tonic-gate } 610*0Sstevel@tonic-gate if ((cm_rcm_qpass = 611*0Sstevel@tonic-gate cm_rcm_qpass_func(cfga_ldata->ap_type)) != NULL && 612*0Sstevel@tonic-gate (*cm_rcm_qpass)(cfga_ldata, rcm) != 0) { 613*0Sstevel@tonic-gate return (-1); 614*0Sstevel@tonic-gate } 615*0Sstevel@tonic-gate } 616*0Sstevel@tonic-gate } 617*0Sstevel@tonic-gate 618*0Sstevel@tonic-gate if (rcm->nrlist == 0) 619*0Sstevel@tonic-gate return (0); 620*0Sstevel@tonic-gate 621*0Sstevel@tonic-gate /* 622*0Sstevel@tonic-gate * Cache query result. Since we are only interested in the 623*0Sstevel@tonic-gate * set of RCM clients processed and not their request status, 624*0Sstevel@tonic-gate * the return value is irrelevant. 625*0Sstevel@tonic-gate */ 626*0Sstevel@tonic-gate (void) rcm_request_offline_list(rcm->hdl, rcm->rlist, 627*0Sstevel@tonic-gate RCM_QUERY|RCM_SCOPE, &rcm->offline_query_info); 628*0Sstevel@tonic-gate 629*0Sstevel@tonic-gate #ifdef DEBUG 630*0Sstevel@tonic-gate dprintf((stderr, "RCM rlist: nrlist=%d\n", rcm->nrlist)); 631*0Sstevel@tonic-gate for (cpp = rcm->rlist, i = 0; *cpp != NULL; cpp++, i++) { 632*0Sstevel@tonic-gate dprintf((stderr, "rlist[%d]=%s\n", i, *cpp)); 633*0Sstevel@tonic-gate } 634*0Sstevel@tonic-gate #endif /* DEBUG */ 635*0Sstevel@tonic-gate 636*0Sstevel@tonic-gate return (0); 637*0Sstevel@tonic-gate } 638*0Sstevel@tonic-gate 639*0Sstevel@tonic-gate static int 640*0Sstevel@tonic-gate cap_request(ri_hdl_t *ri_hdl, rcmd_t *rcm) 641*0Sstevel@tonic-gate { 642*0Sstevel@tonic-gate return (((rcm->ncpus > 0 && cpu_cap_request(ri_hdl, rcm) != 0) || 643*0Sstevel@tonic-gate (rcm->query_pages > 0 && mem_cap_request(ri_hdl, rcm) != 0)) ? 644*0Sstevel@tonic-gate -1 : 0); 645*0Sstevel@tonic-gate } 646*0Sstevel@tonic-gate 647*0Sstevel@tonic-gate /* 648*0Sstevel@tonic-gate * RCM capacity change request for cpus. 649*0Sstevel@tonic-gate */ 650*0Sstevel@tonic-gate static int 651*0Sstevel@tonic-gate cpu_cap_request(ri_hdl_t *ri_hdl, rcmd_t *rcm) 652*0Sstevel@tonic-gate { 653*0Sstevel@tonic-gate cpuid_t *syscpuids, *newcpuids; 654*0Sstevel@tonic-gate int sysncpus, newncpus; 655*0Sstevel@tonic-gate rcm_info_t *rcm_info = NULL; 656*0Sstevel@tonic-gate int i, j, k; 657*0Sstevel@tonic-gate nvlist_t *nvl; 658*0Sstevel@tonic-gate int rv = 0; 659*0Sstevel@tonic-gate 660*0Sstevel@tonic-gate /* get all cpus in the system */ 661*0Sstevel@tonic-gate if (syscpus(&syscpuids, &sysncpus) == -1) 662*0Sstevel@tonic-gate return (-1); 663*0Sstevel@tonic-gate 664*0Sstevel@tonic-gate newncpus = sysncpus - rcm->ncpus; 665*0Sstevel@tonic-gate if ((newcpuids = calloc(newncpus, sizeof (cpuid_t))) == NULL) { 666*0Sstevel@tonic-gate dprintf((stderr, "calloc: %s", strerror(errno))); 667*0Sstevel@tonic-gate rv = -1; 668*0Sstevel@tonic-gate goto out; 669*0Sstevel@tonic-gate } 670*0Sstevel@tonic-gate 671*0Sstevel@tonic-gate if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) { 672*0Sstevel@tonic-gate dprintf((stderr, "nvlist_alloc fail\n")); 673*0Sstevel@tonic-gate rv = -1; 674*0Sstevel@tonic-gate goto out; 675*0Sstevel@tonic-gate } 676*0Sstevel@tonic-gate 677*0Sstevel@tonic-gate /* 678*0Sstevel@tonic-gate * Construct the new cpu list. 679*0Sstevel@tonic-gate */ 680*0Sstevel@tonic-gate for (i = 0, j = 0; i < sysncpus; i++) { 681*0Sstevel@tonic-gate for (k = 0; k < rcm->ncpus; k++) { 682*0Sstevel@tonic-gate if (rcm->cpus[k] == syscpuids[i]) { 683*0Sstevel@tonic-gate break; 684*0Sstevel@tonic-gate } 685*0Sstevel@tonic-gate } 686*0Sstevel@tonic-gate if (k == rcm->ncpus) { 687*0Sstevel@tonic-gate newcpuids[j++] = syscpuids[i]; 688*0Sstevel@tonic-gate } 689*0Sstevel@tonic-gate } 690*0Sstevel@tonic-gate 691*0Sstevel@tonic-gate if (nvlist_add_int32(nvl, "old_total", sysncpus) != 0 || 692*0Sstevel@tonic-gate nvlist_add_int32(nvl, "new_total", newncpus) != 0 || 693*0Sstevel@tonic-gate nvlist_add_int32_array(nvl, "old_cpu_list", syscpuids, 694*0Sstevel@tonic-gate sysncpus) != 0 || 695*0Sstevel@tonic-gate nvlist_add_int32_array(nvl, "new_cpu_list", newcpuids, 696*0Sstevel@tonic-gate newncpus) != 0) { 697*0Sstevel@tonic-gate dprintf((stderr, "nvlist_add fail\n")); 698*0Sstevel@tonic-gate rv = -1; 699*0Sstevel@tonic-gate goto out; 700*0Sstevel@tonic-gate } 701*0Sstevel@tonic-gate 702*0Sstevel@tonic-gate #ifdef DEBUG 703*0Sstevel@tonic-gate dprintf((stderr, "old_total=%d\n", sysncpus)); 704*0Sstevel@tonic-gate for (i = 0; i < sysncpus; i++) { 705*0Sstevel@tonic-gate dprintf((stderr, "old_cpu_list[%d]=%d\n", i, syscpuids[i])); 706*0Sstevel@tonic-gate } 707*0Sstevel@tonic-gate dprintf((stderr, "new_total=%d\n", newncpus)); 708*0Sstevel@tonic-gate for (i = 0; i < newncpus; i++) { 709*0Sstevel@tonic-gate dprintf((stderr, "new_cpu_list[%d]=%d\n", i, newcpuids[i])); 710*0Sstevel@tonic-gate } 711*0Sstevel@tonic-gate #endif /* DEBUG */ 712*0Sstevel@tonic-gate 713*0Sstevel@tonic-gate (void) rcm_request_capacity_change(rcm->hdl, RCM_CPU_ALL, 714*0Sstevel@tonic-gate RCM_QUERY|RCM_SCOPE, nvl, &rcm_info); 715*0Sstevel@tonic-gate 716*0Sstevel@tonic-gate rv = add_rcm_clients(&ri_hdl->cpu_cap_clients, rcm, rcm_info, 0, NULL); 717*0Sstevel@tonic-gate 718*0Sstevel@tonic-gate out: 719*0Sstevel@tonic-gate s_free(syscpuids); 720*0Sstevel@tonic-gate s_free(newcpuids); 721*0Sstevel@tonic-gate if (nvl != NULL) 722*0Sstevel@tonic-gate nvlist_free(nvl); 723*0Sstevel@tonic-gate if (rcm_info != NULL) 724*0Sstevel@tonic-gate rcm_free_info(rcm_info); 725*0Sstevel@tonic-gate 726*0Sstevel@tonic-gate return (rv); 727*0Sstevel@tonic-gate } 728*0Sstevel@tonic-gate 729*0Sstevel@tonic-gate static int 730*0Sstevel@tonic-gate syscpus(cpuid_t **cpuids, int *ncpus) 731*0Sstevel@tonic-gate { 732*0Sstevel@tonic-gate kstat_t *ksp; 733*0Sstevel@tonic-gate kstat_ctl_t *kc; 734*0Sstevel@tonic-gate cpuid_t *cp; 735*0Sstevel@tonic-gate int i; 736*0Sstevel@tonic-gate 737*0Sstevel@tonic-gate if ((*ncpus = sysconf(_SC_NPROCESSORS_CONF)) == -1) { 738*0Sstevel@tonic-gate dprintf((stderr, "sysconf: %s\n", errno)); 739*0Sstevel@tonic-gate return (-1); 740*0Sstevel@tonic-gate } 741*0Sstevel@tonic-gate 742*0Sstevel@tonic-gate if ((kc = kstat_open()) == NULL) { 743*0Sstevel@tonic-gate dprintf((stderr, "kstat_open fail\n")); 744*0Sstevel@tonic-gate return (-1); 745*0Sstevel@tonic-gate } 746*0Sstevel@tonic-gate 747*0Sstevel@tonic-gate if ((cp = calloc(*ncpus, sizeof (cpuid_t))) == NULL) { 748*0Sstevel@tonic-gate dprintf((stderr, "calloc: %s\n", errno)); 749*0Sstevel@tonic-gate (void) kstat_close(kc); 750*0Sstevel@tonic-gate return (-1); 751*0Sstevel@tonic-gate } 752*0Sstevel@tonic-gate 753*0Sstevel@tonic-gate for (i = 0, ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) { 754*0Sstevel@tonic-gate if (strcmp(ksp->ks_module, "cpu_info") == 0) { 755*0Sstevel@tonic-gate cp[i++] = ksp->ks_instance; 756*0Sstevel@tonic-gate } 757*0Sstevel@tonic-gate } 758*0Sstevel@tonic-gate 759*0Sstevel@tonic-gate (void) kstat_close(kc); 760*0Sstevel@tonic-gate *cpuids = cp; 761*0Sstevel@tonic-gate 762*0Sstevel@tonic-gate return (0); 763*0Sstevel@tonic-gate } 764*0Sstevel@tonic-gate 765*0Sstevel@tonic-gate /* 766*0Sstevel@tonic-gate * RCM capacity change request for memory. 767*0Sstevel@tonic-gate */ 768*0Sstevel@tonic-gate static int 769*0Sstevel@tonic-gate mem_cap_request(ri_hdl_t *ri_hdl, rcmd_t *rcm) 770*0Sstevel@tonic-gate { 771*0Sstevel@tonic-gate nvlist_t *nvl; 772*0Sstevel@tonic-gate rcm_info_t *rcm_info = NULL; 773*0Sstevel@tonic-gate long newpages; 774*0Sstevel@tonic-gate int rv = 0; 775*0Sstevel@tonic-gate 776*0Sstevel@tonic-gate if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) { 777*0Sstevel@tonic-gate dprintf((stderr, "nvlist_alloc fail\n")); 778*0Sstevel@tonic-gate return (-1); 779*0Sstevel@tonic-gate } 780*0Sstevel@tonic-gate 781*0Sstevel@tonic-gate newpages = rcm->ms_syspages - rcm->query_pages; 782*0Sstevel@tonic-gate if (nvlist_add_int32(nvl, "page_size", rcm->ms_pagesize) != 0 || 783*0Sstevel@tonic-gate nvlist_add_int32(nvl, "old_pages", rcm->ms_syspages) != 0 || 784*0Sstevel@tonic-gate nvlist_add_int32(nvl, "new_pages", newpages) != 0) { 785*0Sstevel@tonic-gate dprintf((stderr, "nvlist_add fail\n")); 786*0Sstevel@tonic-gate nvlist_free(nvl); 787*0Sstevel@tonic-gate return (-1); 788*0Sstevel@tonic-gate } 789*0Sstevel@tonic-gate 790*0Sstevel@tonic-gate dprintf((stderr, "memory capacity change req: " 791*0Sstevel@tonic-gate "page_size=%d, old_pages=%d, new_pages=%d\n", 792*0Sstevel@tonic-gate rcm->ms_pagesize, rcm->ms_syspages, newpages)); 793*0Sstevel@tonic-gate 794*0Sstevel@tonic-gate (void) rcm_request_capacity_change(rcm->hdl, RCM_MEM_ALL, 795*0Sstevel@tonic-gate RCM_QUERY|RCM_SCOPE, nvl, &rcm_info); 796*0Sstevel@tonic-gate 797*0Sstevel@tonic-gate rv = add_rcm_clients(&ri_hdl->mem_cap_clients, rcm, rcm_info, 0, NULL); 798*0Sstevel@tonic-gate 799*0Sstevel@tonic-gate nvlist_free(nvl); 800*0Sstevel@tonic-gate if (rcm_info != NULL) 801*0Sstevel@tonic-gate rcm_free_info(rcm_info); 802*0Sstevel@tonic-gate 803*0Sstevel@tonic-gate return (rv); 804*0Sstevel@tonic-gate } 805*0Sstevel@tonic-gate 806*0Sstevel@tonic-gate static int 807*0Sstevel@tonic-gate (*cm_rcm_qpass_func(cfga_type_t ap_type))(cfga_list_data_t *, rcmd_t *) 808*0Sstevel@tonic-gate { 809*0Sstevel@tonic-gate int i; 810*0Sstevel@tonic-gate 811*0Sstevel@tonic-gate for (i = 0; i < sizeof (cm_ctl) / sizeof (cm_ctl[0]); i++) { 812*0Sstevel@tonic-gate if (strcmp(cm_ctl[i].type, ap_type) == 0) { 813*0Sstevel@tonic-gate return (cm_ctl[i].cm_rcm_qpass); 814*0Sstevel@tonic-gate } 815*0Sstevel@tonic-gate } 816*0Sstevel@tonic-gate return (NULL); 817*0Sstevel@tonic-gate } 818*0Sstevel@tonic-gate 819*0Sstevel@tonic-gate /* 820*0Sstevel@tonic-gate * Save cpu ids and RCM abstract resource names. 821*0Sstevel@tonic-gate * Cpu ids will be used for the capacity change request. 822*0Sstevel@tonic-gate * Resource names will be used for the offline query. 823*0Sstevel@tonic-gate */ 824*0Sstevel@tonic-gate static int 825*0Sstevel@tonic-gate cpu_rcm_qpass(cfga_list_data_t *cfga_ldata, rcmd_t *rcm) 826*0Sstevel@tonic-gate { 827*0Sstevel@tonic-gate processorid_t cpuid; 828*0Sstevel@tonic-gate char *cpustr, *lasts, *rsrcname, rbuf[32]; 829*0Sstevel@tonic-gate char cbuf[CFGA_INFO_LEN]; 830*0Sstevel@tonic-gate int speed, ecache; 831*0Sstevel@tonic-gate 832*0Sstevel@tonic-gate assert(sscanf(cfga_ldata->ap_info, CPU_INFO_FMT, &cbuf, &speed, 833*0Sstevel@tonic-gate &ecache) == 3); 834*0Sstevel@tonic-gate 835*0Sstevel@tonic-gate for (cpustr = (char *)strtok_r(cbuf, CPUID_SEP, &lasts); 836*0Sstevel@tonic-gate cpustr != NULL; 837*0Sstevel@tonic-gate cpustr = (char *)strtok_r(NULL, CPUID_SEP, &lasts)) { 838*0Sstevel@tonic-gate cpuid = atoi(cpustr); 839*0Sstevel@tonic-gate 840*0Sstevel@tonic-gate (void) snprintf(rbuf, sizeof (rbuf), "%s%d", RCM_CPU, cpuid); 841*0Sstevel@tonic-gate if ((rsrcname = strdup(rbuf)) == NULL) { 842*0Sstevel@tonic-gate dprintf((stderr, "strdup fail\n")); 843*0Sstevel@tonic-gate return (-1); 844*0Sstevel@tonic-gate } 845*0Sstevel@tonic-gate assert(rcm->nrlist < rcm->ndevs && rcm->ncpus < rcm->ndevs); 846*0Sstevel@tonic-gate rcm->rlist[rcm->nrlist++] = rsrcname; 847*0Sstevel@tonic-gate rcm->cpus[rcm->ncpus++] = (cpuid_t)cpuid; 848*0Sstevel@tonic-gate 849*0Sstevel@tonic-gate dprintf((stderr, "cpu_cm_info: cpuid=%d, rsrcname=%s", 850*0Sstevel@tonic-gate cpuid, rsrcname)); 851*0Sstevel@tonic-gate } 852*0Sstevel@tonic-gate 853*0Sstevel@tonic-gate return (0); 854*0Sstevel@tonic-gate } 855*0Sstevel@tonic-gate 856*0Sstevel@tonic-gate /* 857*0Sstevel@tonic-gate * No RCM resource names for individual memory units, so 858*0Sstevel@tonic-gate * just add to offline query page count. 859*0Sstevel@tonic-gate */ 860*0Sstevel@tonic-gate static int 861*0Sstevel@tonic-gate mem_rcm_qpass(cfga_list_data_t *cfga, rcmd_t *rcm) 862*0Sstevel@tonic-gate { 863*0Sstevel@tonic-gate char *cp; 864*0Sstevel@tonic-gate uint_t kbytes; 865*0Sstevel@tonic-gate longlong_t ii; 866*0Sstevel@tonic-gate 867*0Sstevel@tonic-gate if ((cp = strstr(cfga->ap_info, "size")) == NULL || 868*0Sstevel@tonic-gate sscanf(cp, "size=%u", &kbytes) != 1) { 869*0Sstevel@tonic-gate dprintf((stderr, "unknown sbd info format: %s\n", cp)); 870*0Sstevel@tonic-gate return (-1); 871*0Sstevel@tonic-gate } 872*0Sstevel@tonic-gate 873*0Sstevel@tonic-gate ii = (longlong_t)kbytes * KBYTE; 874*0Sstevel@tonic-gate rcm->query_pages += (uint_t)(ii / rcm->ms_pagesize); 875*0Sstevel@tonic-gate 876*0Sstevel@tonic-gate dprintf((stderr, "%s: npages=%u\n", cfga->ap_log_id, 877*0Sstevel@tonic-gate (uint_t)(ii / rcm->ms_pagesize))); 878*0Sstevel@tonic-gate 879*0Sstevel@tonic-gate return (0); 880*0Sstevel@tonic-gate } 881*0Sstevel@tonic-gate 882*0Sstevel@tonic-gate /* 883*0Sstevel@tonic-gate * Add physical I/O bus name to RCM resource list. 884*0Sstevel@tonic-gate */ 885*0Sstevel@tonic-gate static int 886*0Sstevel@tonic-gate io_rcm_qpass(cfga_list_data_t *cfga, rcmd_t *rcm) 887*0Sstevel@tonic-gate { 888*0Sstevel@tonic-gate char path[MAXPATHLEN]; 889*0Sstevel@tonic-gate char buf[MAXPATHLEN]; 890*0Sstevel@tonic-gate char *rsrcname; 891*0Sstevel@tonic-gate 892*0Sstevel@tonic-gate if (sscanf(cfga->ap_info, "device=%s", path) != 1) { 893*0Sstevel@tonic-gate dprintf((stderr, "unknown sbd info format: %s\n", 894*0Sstevel@tonic-gate cfga->ap_info)); 895*0Sstevel@tonic-gate return (-1); 896*0Sstevel@tonic-gate } 897*0Sstevel@tonic-gate 898*0Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "/devices%s", path); 899*0Sstevel@tonic-gate if ((rsrcname = strdup(buf)) == NULL) { 900*0Sstevel@tonic-gate dprintf((stderr, "strdup fail\n")); 901*0Sstevel@tonic-gate return (-1); 902*0Sstevel@tonic-gate } 903*0Sstevel@tonic-gate 904*0Sstevel@tonic-gate assert(rcm->nrlist < rcm->ndevs); 905*0Sstevel@tonic-gate rcm->rlist[rcm->nrlist++] = rsrcname; 906*0Sstevel@tonic-gate 907*0Sstevel@tonic-gate return (0); 908*0Sstevel@tonic-gate } 909*0Sstevel@tonic-gate 910*0Sstevel@tonic-gate static int 911*0Sstevel@tonic-gate (*cm_info_func(cfga_type_t ap_type))(ri_ap_t *, cfga_list_data_t *, 912*0Sstevel@tonic-gate int, rcmd_t *) 913*0Sstevel@tonic-gate { 914*0Sstevel@tonic-gate int i; 915*0Sstevel@tonic-gate 916*0Sstevel@tonic-gate for (i = 0; i < sizeof (cm_ctl) / sizeof (cm_ctl[0]); i++) { 917*0Sstevel@tonic-gate if (strcmp(cm_ctl[i].type, ap_type) == 0) { 918*0Sstevel@tonic-gate return (cm_ctl[i].cm_info); 919*0Sstevel@tonic-gate } 920*0Sstevel@tonic-gate } 921*0Sstevel@tonic-gate return (NULL); 922*0Sstevel@tonic-gate } 923*0Sstevel@tonic-gate 924*0Sstevel@tonic-gate /* 925*0Sstevel@tonic-gate * Create cpu handle, adding properties exported by sbd plugin and 926*0Sstevel@tonic-gate * RCM client usage. 927*0Sstevel@tonic-gate */ 928*0Sstevel@tonic-gate /* ARGSUSED */ 929*0Sstevel@tonic-gate static int 930*0Sstevel@tonic-gate cpu_cm_info(ri_ap_t *ap, cfga_list_data_t *cfga, int flags, rcmd_t *rcm) 931*0Sstevel@tonic-gate { 932*0Sstevel@tonic-gate processorid_t cpuid; 933*0Sstevel@tonic-gate int speed, ecache, rv = 0; 934*0Sstevel@tonic-gate char buf[CFGA_INFO_LEN], *cpustr, *lasts; 935*0Sstevel@tonic-gate 936*0Sstevel@tonic-gate if (sscanf(cfga->ap_info, CPU_INFO_FMT, &buf, &speed, &ecache) != 3) { 937*0Sstevel@tonic-gate dprintf((stderr, "unknown sbd info format: %s\n", 938*0Sstevel@tonic-gate cfga->ap_info)); 939*0Sstevel@tonic-gate return (-1); 940*0Sstevel@tonic-gate } 941*0Sstevel@tonic-gate 942*0Sstevel@tonic-gate /* parse cpuids */ 943*0Sstevel@tonic-gate for (cpustr = (char *)strtok_r(buf, CPUID_SEP, &lasts); 944*0Sstevel@tonic-gate cpustr != NULL; 945*0Sstevel@tonic-gate cpustr = (char *)strtok_r(NULL, CPUID_SEP, &lasts)) { 946*0Sstevel@tonic-gate cpuid = atoi(cpustr); 947*0Sstevel@tonic-gate if ((rv = i_cpu_cm_info(cpuid, speed, ap, rcm)) != 0) { 948*0Sstevel@tonic-gate break; 949*0Sstevel@tonic-gate } 950*0Sstevel@tonic-gate } 951*0Sstevel@tonic-gate 952*0Sstevel@tonic-gate return (rv); 953*0Sstevel@tonic-gate } 954*0Sstevel@tonic-gate 955*0Sstevel@tonic-gate static int 956*0Sstevel@tonic-gate i_cpu_cm_info(processorid_t cpuid, int speed, ri_ap_t *ap, rcmd_t *rcm) 957*0Sstevel@tonic-gate { 958*0Sstevel@tonic-gate int ecache = 0; 959*0Sstevel@tonic-gate char *state, buf[32]; 960*0Sstevel@tonic-gate processor_info_t cpu_info; 961*0Sstevel@tonic-gate ri_dev_t *cpu = NULL; 962*0Sstevel@tonic-gate rcm_info_t *rcm_info = NULL; 963*0Sstevel@tonic-gate 964*0Sstevel@tonic-gate /* 965*0Sstevel@tonic-gate * Could have been unconfigured in the interim, so cannot 966*0Sstevel@tonic-gate * count on processor_info recognizing it. 967*0Sstevel@tonic-gate */ 968*0Sstevel@tonic-gate state = (processor_info(cpuid, &cpu_info) == 0) ? 969*0Sstevel@tonic-gate pstate2str(cpu_info.pi_state) : "unknown"; 970*0Sstevel@tonic-gate 971*0Sstevel@tonic-gate if ((cpu = ri_dev_alloc()) == NULL) { 972*0Sstevel@tonic-gate dprintf((stderr, "ri_dev_alloc failed\n")); 973*0Sstevel@tonic-gate return (-1); 974*0Sstevel@tonic-gate } 975*0Sstevel@tonic-gate 976*0Sstevel@tonic-gate if (rcm->ecache_info.ecache_sizes != NULL) { 977*0Sstevel@tonic-gate assert(rcm->ecache_info.cpuid_max != 0 && 978*0Sstevel@tonic-gate cpuid <= rcm->ecache_info.cpuid_max); 979*0Sstevel@tonic-gate ecache = rcm->ecache_info.ecache_sizes[cpuid] / MBYTE; 980*0Sstevel@tonic-gate } 981*0Sstevel@tonic-gate 982*0Sstevel@tonic-gate dprintf((stderr, "i_cpu_cm_info: cpu(%d) ecache=%d MB\n", 983*0Sstevel@tonic-gate cpuid, ecache)); 984*0Sstevel@tonic-gate 985*0Sstevel@tonic-gate if (nvlist_add_int32(cpu->conf_props, RI_CPU_ID, cpuid) != 0 || 986*0Sstevel@tonic-gate nvlist_add_int32(cpu->conf_props, RI_CPU_SPEED, speed) != 0 || 987*0Sstevel@tonic-gate nvlist_add_int32(cpu->conf_props, RI_CPU_ECACHE, ecache) != 0 || 988*0Sstevel@tonic-gate nvlist_add_string(cpu->conf_props, RI_CPU_STATE, state) != 0) { 989*0Sstevel@tonic-gate dprintf((stderr, "nvlist_add fail\n")); 990*0Sstevel@tonic-gate ri_dev_free(cpu); 991*0Sstevel@tonic-gate return (-1); 992*0Sstevel@tonic-gate } 993*0Sstevel@tonic-gate 994*0Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "%s%d", RCM_CPU, cpuid); 995*0Sstevel@tonic-gate dprintf((stderr, "rcm_get_info(%s)\n", buf)); 996*0Sstevel@tonic-gate if (rcm_get_info(rcm->hdl, buf, RCM_INCLUDE_DEPENDENT, 997*0Sstevel@tonic-gate &rcm_info) != RCM_SUCCESS) { 998*0Sstevel@tonic-gate dprintf((stderr, "rcm_get_info (errno=%d)\n", errno)); 999*0Sstevel@tonic-gate ri_dev_free(cpu); 1000*0Sstevel@tonic-gate if (rcm_info != NULL) 1001*0Sstevel@tonic-gate rcm_free_info(rcm_info); 1002*0Sstevel@tonic-gate return (-1); 1003*0Sstevel@tonic-gate } 1004*0Sstevel@tonic-gate 1005*0Sstevel@tonic-gate dev_list_cpu_insert(&ap->cpus, cpu, cpuid); 1006*0Sstevel@tonic-gate 1007*0Sstevel@tonic-gate return (0); 1008*0Sstevel@tonic-gate } 1009*0Sstevel@tonic-gate 1010*0Sstevel@tonic-gate /* 1011*0Sstevel@tonic-gate * Create memory handle, adding properties exported by sbd plugin. 1012*0Sstevel@tonic-gate * No RCM tuples to be saved unless RCM is modified to export names 1013*0Sstevel@tonic-gate * for individual memory units. 1014*0Sstevel@tonic-gate */ 1015*0Sstevel@tonic-gate /* ARGSUSED */ 1016*0Sstevel@tonic-gate static int 1017*0Sstevel@tonic-gate mem_cm_info(ri_ap_t *ap, cfga_list_data_t *cfga, int flags, rcmd_t *rcm) 1018*0Sstevel@tonic-gate { 1019*0Sstevel@tonic-gate ri_dev_t *mem; 1020*0Sstevel@tonic-gate char *cp; 1021*0Sstevel@tonic-gate uint64_t base_addr; /* required */ 1022*0Sstevel@tonic-gate int32_t size_kb; /* required */ 1023*0Sstevel@tonic-gate int32_t perm_kb = 0; /* optional */ 1024*0Sstevel@tonic-gate char *target = NULL; /* optional */ 1025*0Sstevel@tonic-gate int32_t del_kb = 0; /* optional */ 1026*0Sstevel@tonic-gate int32_t rem_kb = 0; /* optional */ 1027*0Sstevel@tonic-gate char *source = NULL; /* optional */ 1028*0Sstevel@tonic-gate 1029*0Sstevel@tonic-gate if (sscanf(cfga->ap_info, "address=0x%llx size=%u", &base_addr, 1030*0Sstevel@tonic-gate &size_kb) != 2) { 1031*0Sstevel@tonic-gate goto err_fmt; 1032*0Sstevel@tonic-gate } 1033*0Sstevel@tonic-gate 1034*0Sstevel@tonic-gate if ((cp = strstr(cfga->ap_info, "permanent")) != NULL && 1035*0Sstevel@tonic-gate sscanf(cp, "permanent=%u", &perm_kb) != 1) { 1036*0Sstevel@tonic-gate goto err_fmt; 1037*0Sstevel@tonic-gate } 1038*0Sstevel@tonic-gate 1039*0Sstevel@tonic-gate if ((cp = strstr(cfga->ap_info, "target")) != NULL && 1040*0Sstevel@tonic-gate sscanf(cp, "target=%s deleted=%u remaining=%u", &target, &del_kb, 1041*0Sstevel@tonic-gate &rem_kb) != 3) { 1042*0Sstevel@tonic-gate goto err_fmt; 1043*0Sstevel@tonic-gate } 1044*0Sstevel@tonic-gate 1045*0Sstevel@tonic-gate if ((cp = strstr(cfga->ap_info, "source")) != NULL && 1046*0Sstevel@tonic-gate sscanf(cp, "source=%s", &source) != 1) { 1047*0Sstevel@tonic-gate goto err_fmt; 1048*0Sstevel@tonic-gate } 1049*0Sstevel@tonic-gate 1050*0Sstevel@tonic-gate dprintf((stderr, "%s: base=0x%llx, size=%u, permanent=%u\n", 1051*0Sstevel@tonic-gate cfga->ap_log_id, base_addr, size_kb, perm_kb)); 1052*0Sstevel@tonic-gate 1053*0Sstevel@tonic-gate if ((mem = ri_dev_alloc()) == NULL) 1054*0Sstevel@tonic-gate return (-1); 1055*0Sstevel@tonic-gate 1056*0Sstevel@tonic-gate /* 1057*0Sstevel@tonic-gate * Convert memory sizes to MB (truncate). 1058*0Sstevel@tonic-gate */ 1059*0Sstevel@tonic-gate if (nvlist_add_uint64(mem->conf_props, RI_MEM_ADDR, base_addr) != 0 || 1060*0Sstevel@tonic-gate nvlist_add_int32(mem->conf_props, RI_MEM_BRD, size_kb/KBYTE) != 0 || 1061*0Sstevel@tonic-gate nvlist_add_int32(mem->conf_props, RI_MEM_PERM, 1062*0Sstevel@tonic-gate perm_kb/KBYTE) != 0) { 1063*0Sstevel@tonic-gate dprintf((stderr, "nvlist_add failure\n")); 1064*0Sstevel@tonic-gate ri_dev_free(mem); 1065*0Sstevel@tonic-gate return (-1); 1066*0Sstevel@tonic-gate } 1067*0Sstevel@tonic-gate 1068*0Sstevel@tonic-gate if (target != NULL && 1069*0Sstevel@tonic-gate (nvlist_add_string(mem->conf_props, RI_MEM_TARG, target) != 0 || 1070*0Sstevel@tonic-gate nvlist_add_int32(mem->conf_props, RI_MEM_DEL, del_kb/KBYTE) != 0 || 1071*0Sstevel@tonic-gate nvlist_add_int32(mem->conf_props, RI_MEM_REMAIN, 1072*0Sstevel@tonic-gate rem_kb/KBYTE) != 0)) { 1073*0Sstevel@tonic-gate dprintf((stderr, "nvlist_add failure\n")); 1074*0Sstevel@tonic-gate ri_dev_free(mem); 1075*0Sstevel@tonic-gate return (-1); 1076*0Sstevel@tonic-gate } 1077*0Sstevel@tonic-gate 1078*0Sstevel@tonic-gate if (source != NULL && nvlist_add_string(mem->conf_props, RI_MEM_SRC, 1079*0Sstevel@tonic-gate source) != 0) { 1080*0Sstevel@tonic-gate dprintf((stderr, "nvlist_add failure\n")); 1081*0Sstevel@tonic-gate ri_dev_free(mem); 1082*0Sstevel@tonic-gate return (-1); 1083*0Sstevel@tonic-gate } 1084*0Sstevel@tonic-gate 1085*0Sstevel@tonic-gate /* 1086*0Sstevel@tonic-gate * XXX - move this property to attachment point hdl? 1087*0Sstevel@tonic-gate */ 1088*0Sstevel@tonic-gate if (nvlist_add_int32(mem->conf_props, RI_MEM_DOMAIN, 1089*0Sstevel@tonic-gate rcm->ms_sysmb) != 0) { 1090*0Sstevel@tonic-gate dprintf((stderr, "nvlist_add failure\n")); 1091*0Sstevel@tonic-gate ri_dev_free(mem); 1092*0Sstevel@tonic-gate return (-1); 1093*0Sstevel@tonic-gate } 1094*0Sstevel@tonic-gate 1095*0Sstevel@tonic-gate dev_list_append(&ap->mems, mem); 1096*0Sstevel@tonic-gate return (0); 1097*0Sstevel@tonic-gate 1098*0Sstevel@tonic-gate err_fmt: 1099*0Sstevel@tonic-gate dprintf((stderr, "unknown sbd info format: %s\n", cfga->ap_info)); 1100*0Sstevel@tonic-gate return (-1); 1101*0Sstevel@tonic-gate } 1102*0Sstevel@tonic-gate 1103*0Sstevel@tonic-gate /* 1104*0Sstevel@tonic-gate * Initiate a libdevinfo walk on the IO bus path. 1105*0Sstevel@tonic-gate * XXX - investigate performance using two threads here: one thread to do the 1106*0Sstevel@tonic-gate * libdevinfo snapshot and treewalk; and one thread to get RCM usage info 1107*0Sstevel@tonic-gate */ 1108*0Sstevel@tonic-gate static int 1109*0Sstevel@tonic-gate io_cm_info(ri_ap_t *ap, cfga_list_data_t *cfga, int flags, rcmd_t *rcm) 1110*0Sstevel@tonic-gate { 1111*0Sstevel@tonic-gate int i; 1112*0Sstevel@tonic-gate int j; 1113*0Sstevel@tonic-gate int k; 1114*0Sstevel@tonic-gate int set_size; 1115*0Sstevel@tonic-gate int retval = 0; 1116*0Sstevel@tonic-gate int n_usage; 1117*0Sstevel@tonic-gate devinfo_arg_t di_arg; 1118*0Sstevel@tonic-gate lookup_table_t devicetable; 1119*0Sstevel@tonic-gate lookup_entry_t *deventry; 1120*0Sstevel@tonic-gate lookup_entry_t *lastdeventry; 1121*0Sstevel@tonic-gate ri_dev_t *io = NULL; 1122*0Sstevel@tonic-gate ri_client_t *client; 1123*0Sstevel@tonic-gate ri_client_t *tmp; 1124*0Sstevel@tonic-gate di_devlink_handle_t linkhd = NULL; 1125*0Sstevel@tonic-gate di_node_t root = DI_NODE_NIL; 1126*0Sstevel@tonic-gate di_node_t node = DI_NODE_NIL; 1127*0Sstevel@tonic-gate rcm_info_tuple_t *rcm_tuple; 1128*0Sstevel@tonic-gate rcm_info_t *rcm_info = NULL; 1129*0Sstevel@tonic-gate const char *rcm_rsrc = NULL; 1130*0Sstevel@tonic-gate char drv_inst[MAXPATHLEN]; 1131*0Sstevel@tonic-gate char path[MAXPATHLEN]; 1132*0Sstevel@tonic-gate char pathbuf[MAXPATHLEN]; 1133*0Sstevel@tonic-gate 1134*0Sstevel@tonic-gate dprintf((stderr, "io_cm_info(%s)\n", cfga->ap_log_id)); 1135*0Sstevel@tonic-gate 1136*0Sstevel@tonic-gate /* Extract devfs path from cfgadm information */ 1137*0Sstevel@tonic-gate if (sscanf(cfga->ap_info, "device=%s\n", path) != 1) { 1138*0Sstevel@tonic-gate dprintf((stderr, "unknown sbd info format: %s\n", 1139*0Sstevel@tonic-gate cfga->ap_info)); 1140*0Sstevel@tonic-gate return (-1); 1141*0Sstevel@tonic-gate } 1142*0Sstevel@tonic-gate 1143*0Sstevel@tonic-gate /* Initialize empty device lookup table */ 1144*0Sstevel@tonic-gate devicetable.n_entries = 0; 1145*0Sstevel@tonic-gate devicetable.n_slots = 0; 1146*0Sstevel@tonic-gate devicetable.table = NULL; 1147*0Sstevel@tonic-gate 1148*0Sstevel@tonic-gate /* Get libdevinfo snapshot */ 1149*0Sstevel@tonic-gate dprintf((stderr, "di_init(%s)\n", path)); 1150*0Sstevel@tonic-gate if ((root = di_init(path, DINFOCPYALL)) == DI_NODE_NIL) { 1151*0Sstevel@tonic-gate dprintf((stderr, "di_init: %s\n", strerror(errno))); 1152*0Sstevel@tonic-gate retval = RI_NODE_NIL; /* tell ri_init to skip this node */ 1153*0Sstevel@tonic-gate goto end; 1154*0Sstevel@tonic-gate } 1155*0Sstevel@tonic-gate 1156*0Sstevel@tonic-gate /* 1157*0Sstevel@tonic-gate * Map in devlinks database. 1158*0Sstevel@tonic-gate * XXX - This could be moved to ri_init() for better performance. 1159*0Sstevel@tonic-gate */ 1160*0Sstevel@tonic-gate dprintf((stderr, "di_devlink_init()\n")); 1161*0Sstevel@tonic-gate if ((linkhd = di_devlink_init(NULL, 0)) == NULL) { 1162*0Sstevel@tonic-gate dprintf((stderr, "di_devlink_init: %s\n", strerror(errno))); 1163*0Sstevel@tonic-gate retval = -1; 1164*0Sstevel@tonic-gate goto end; 1165*0Sstevel@tonic-gate } 1166*0Sstevel@tonic-gate 1167*0Sstevel@tonic-gate /* Initialize argument for devinfo treewalk */ 1168*0Sstevel@tonic-gate di_arg.err = 0; 1169*0Sstevel@tonic-gate di_arg.node = DI_NODE_NIL; 1170*0Sstevel@tonic-gate di_arg.pathbuf = pathbuf; 1171*0Sstevel@tonic-gate di_arg.table = &devicetable; 1172*0Sstevel@tonic-gate di_arg.linkhd = linkhd; 1173*0Sstevel@tonic-gate 1174*0Sstevel@tonic-gate /* Use libdevinfo treewalk to build device lookup table */ 1175*0Sstevel@tonic-gate if (di_walk_node(root, DI_WALK_CLDFIRST, (void *)&di_arg, 1176*0Sstevel@tonic-gate devinfo_node_walk) != 0) { 1177*0Sstevel@tonic-gate dprintf((stderr, "di_walk_node: %s\n", strerror(errno))); 1178*0Sstevel@tonic-gate retval = -1; 1179*0Sstevel@tonic-gate goto end; 1180*0Sstevel@tonic-gate } 1181*0Sstevel@tonic-gate if (di_arg.err != 0) { 1182*0Sstevel@tonic-gate dprintf((stderr, "di_walk_node: device tree walk failed\n")); 1183*0Sstevel@tonic-gate retval = -1; 1184*0Sstevel@tonic-gate goto end; 1185*0Sstevel@tonic-gate } 1186*0Sstevel@tonic-gate 1187*0Sstevel@tonic-gate /* Call RCM to gather usage information */ 1188*0Sstevel@tonic-gate (void) snprintf(pathbuf, MAXPATHLEN, "/devices%s", path); 1189*0Sstevel@tonic-gate dprintf((stderr, "rcm_get_info(%s)\n", pathbuf)); 1190*0Sstevel@tonic-gate if (rcm_get_info(rcm->hdl, pathbuf, 1191*0Sstevel@tonic-gate RCM_INCLUDE_SUBTREE|RCM_INCLUDE_DEPENDENT, &rcm_info) != 1192*0Sstevel@tonic-gate RCM_SUCCESS) { 1193*0Sstevel@tonic-gate dprintf((stderr, "rcm_get_info (errno=%d)\n", errno)); 1194*0Sstevel@tonic-gate retval = -1; 1195*0Sstevel@tonic-gate goto end; 1196*0Sstevel@tonic-gate } 1197*0Sstevel@tonic-gate 1198*0Sstevel@tonic-gate /* Sort the device table by name (proper order for lookups) */ 1199*0Sstevel@tonic-gate qsort(devicetable.table, devicetable.n_entries, sizeof (lookup_entry_t), 1200*0Sstevel@tonic-gate table_compare_names); 1201*0Sstevel@tonic-gate 1202*0Sstevel@tonic-gate /* Perform mappings of RCM usage segments to device table entries */ 1203*0Sstevel@tonic-gate lastdeventry = NULL; 1204*0Sstevel@tonic-gate rcm_tuple = NULL; 1205*0Sstevel@tonic-gate while ((rcm_tuple = rcm_info_next(rcm_info, rcm_tuple)) != NULL) { 1206*0Sstevel@tonic-gate if ((rcm_rsrc = rcm_info_rsrc(rcm_tuple)) == NULL) 1207*0Sstevel@tonic-gate continue; 1208*0Sstevel@tonic-gate if (deventry = lookup(&devicetable, rcm_rsrc)) { 1209*0Sstevel@tonic-gate if (add_usage(deventry, rcm_rsrc, rcm_tuple)) { 1210*0Sstevel@tonic-gate retval = -1; 1211*0Sstevel@tonic-gate goto end; 1212*0Sstevel@tonic-gate } 1213*0Sstevel@tonic-gate lastdeventry = deventry; 1214*0Sstevel@tonic-gate } else { 1215*0Sstevel@tonic-gate if (add_usage(lastdeventry, rcm_rsrc, rcm_tuple)) { 1216*0Sstevel@tonic-gate retval = -1; 1217*0Sstevel@tonic-gate goto end; 1218*0Sstevel@tonic-gate } 1219*0Sstevel@tonic-gate } 1220*0Sstevel@tonic-gate } 1221*0Sstevel@tonic-gate 1222*0Sstevel@tonic-gate /* Re-sort the device table by index number (original treewalk order) */ 1223*0Sstevel@tonic-gate qsort(devicetable.table, devicetable.n_entries, sizeof (lookup_entry_t), 1224*0Sstevel@tonic-gate table_compare_indices); 1225*0Sstevel@tonic-gate 1226*0Sstevel@tonic-gate /* 1227*0Sstevel@tonic-gate * Use the mapped usage and the device table to construct ri_dev_t's. 1228*0Sstevel@tonic-gate * Construct one for each set of entries in the device table with 1229*0Sstevel@tonic-gate * matching di_node_t's, if: 1) it has mapped RCM usage, or 2) it is 1230*0Sstevel@tonic-gate * a leaf node and the caller has requested that unmanaged nodes be 1231*0Sstevel@tonic-gate * included in the output. 1232*0Sstevel@tonic-gate */ 1233*0Sstevel@tonic-gate i = 0; 1234*0Sstevel@tonic-gate while (i < devicetable.n_entries) { 1235*0Sstevel@tonic-gate 1236*0Sstevel@tonic-gate node = devicetable.table[i].node; 1237*0Sstevel@tonic-gate 1238*0Sstevel@tonic-gate /* Count how many usage records are mapped to this node's set */ 1239*0Sstevel@tonic-gate n_usage = 0; 1240*0Sstevel@tonic-gate set_size = 0; 1241*0Sstevel@tonic-gate while (((i + set_size) < devicetable.n_entries) && 1242*0Sstevel@tonic-gate (devicetable.table[i + set_size].node == node)) { 1243*0Sstevel@tonic-gate n_usage += devicetable.table[i + set_size].n_usage; 1244*0Sstevel@tonic-gate set_size += 1; 1245*0Sstevel@tonic-gate } 1246*0Sstevel@tonic-gate 1247*0Sstevel@tonic-gate /* 1248*0Sstevel@tonic-gate * If there's no usage, then the node is unmanaged. Skip this 1249*0Sstevel@tonic-gate * set of devicetable entries unless the node is a leaf node 1250*0Sstevel@tonic-gate * and the caller has requested information on unmanaged leaves. 1251*0Sstevel@tonic-gate */ 1252*0Sstevel@tonic-gate if ((n_usage == 0) && 1253*0Sstevel@tonic-gate !((flags & RI_INCLUDE_UNMANAGED) && (ident_leaf(node)))) { 1254*0Sstevel@tonic-gate i += set_size; 1255*0Sstevel@tonic-gate continue; 1256*0Sstevel@tonic-gate } 1257*0Sstevel@tonic-gate 1258*0Sstevel@tonic-gate /* 1259*0Sstevel@tonic-gate * The checks above determined that this node is going in. 1260*0Sstevel@tonic-gate * So determine its driver/instance name and allocate an 1261*0Sstevel@tonic-gate * ri_dev_t for this node. 1262*0Sstevel@tonic-gate */ 1263*0Sstevel@tonic-gate if (mk_drv_inst(node, drv_inst, devicetable.table[i].name)) { 1264*0Sstevel@tonic-gate dprintf((stderr, "mk_drv_inst failed\n")); 1265*0Sstevel@tonic-gate retval = -1; 1266*0Sstevel@tonic-gate break; 1267*0Sstevel@tonic-gate } 1268*0Sstevel@tonic-gate if ((io = io_dev_alloc(drv_inst)) == NULL) { 1269*0Sstevel@tonic-gate dprintf((stderr, "io_dev_alloc failed\n")); 1270*0Sstevel@tonic-gate retval = -1; 1271*0Sstevel@tonic-gate break; 1272*0Sstevel@tonic-gate } 1273*0Sstevel@tonic-gate 1274*0Sstevel@tonic-gate /* Now add all the RCM usage records (if any) to the ri_dev_t */ 1275*0Sstevel@tonic-gate for (j = i; j < (i + set_size); j++) { 1276*0Sstevel@tonic-gate for (k = 0; k < devicetable.table[j].n_usage; k++) { 1277*0Sstevel@tonic-gate /* Create new ri_client_t for basic usage */ 1278*0Sstevel@tonic-gate client = ri_client_alloc( 1279*0Sstevel@tonic-gate (char *)devicetable.table[j].usage[k].rsrc, 1280*0Sstevel@tonic-gate (char *)devicetable.table[j].usage[k].info); 1281*0Sstevel@tonic-gate if (client == NULL) { 1282*0Sstevel@tonic-gate dprintf((stderr, 1283*0Sstevel@tonic-gate "ri_client_alloc failed\n")); 1284*0Sstevel@tonic-gate ri_dev_free(io); 1285*0Sstevel@tonic-gate retval = -1; 1286*0Sstevel@tonic-gate goto end; 1287*0Sstevel@tonic-gate } 1288*0Sstevel@tonic-gate 1289*0Sstevel@tonic-gate /* Add extra query usage to the ri_client_t */ 1290*0Sstevel@tonic-gate if ((flags & RI_INCLUDE_QUERY) && 1291*0Sstevel@tonic-gate (add_query_state(rcm, client, 1292*0Sstevel@tonic-gate devicetable.table[j].usage[k].rsrc, 1293*0Sstevel@tonic-gate devicetable.table[j].usage[k].info) != 0)) { 1294*0Sstevel@tonic-gate dprintf((stderr, 1295*0Sstevel@tonic-gate "add_query_state failed\n")); 1296*0Sstevel@tonic-gate ri_dev_free(io); 1297*0Sstevel@tonic-gate ri_client_free(client); 1298*0Sstevel@tonic-gate retval = -1; 1299*0Sstevel@tonic-gate goto end; 1300*0Sstevel@tonic-gate } 1301*0Sstevel@tonic-gate 1302*0Sstevel@tonic-gate /* Link new ri_client_t to ri_dev_t */ 1303*0Sstevel@tonic-gate if (io->rcm_clients) { 1304*0Sstevel@tonic-gate tmp = io->rcm_clients; 1305*0Sstevel@tonic-gate while (tmp->next) 1306*0Sstevel@tonic-gate tmp = tmp->next; 1307*0Sstevel@tonic-gate tmp->next = client; 1308*0Sstevel@tonic-gate } else { 1309*0Sstevel@tonic-gate io->rcm_clients = client; 1310*0Sstevel@tonic-gate } 1311*0Sstevel@tonic-gate } 1312*0Sstevel@tonic-gate } 1313*0Sstevel@tonic-gate 1314*0Sstevel@tonic-gate /* Link the ri_dev_t into the return value */ 1315*0Sstevel@tonic-gate dev_list_append(&ap->ios, io); 1316*0Sstevel@tonic-gate 1317*0Sstevel@tonic-gate /* Advance to the next node set */ 1318*0Sstevel@tonic-gate i += set_size; 1319*0Sstevel@tonic-gate } 1320*0Sstevel@tonic-gate 1321*0Sstevel@tonic-gate end: 1322*0Sstevel@tonic-gate if (rcm_info != NULL) 1323*0Sstevel@tonic-gate rcm_free_info(rcm_info); 1324*0Sstevel@tonic-gate if (linkhd != NULL) 1325*0Sstevel@tonic-gate di_devlink_fini(&linkhd); 1326*0Sstevel@tonic-gate if (root != DI_NODE_NIL) 1327*0Sstevel@tonic-gate di_fini(root); 1328*0Sstevel@tonic-gate empty_table(&devicetable); 1329*0Sstevel@tonic-gate 1330*0Sstevel@tonic-gate dprintf((stderr, "io_cm_info: returning %d\n", retval)); 1331*0Sstevel@tonic-gate return (retval); 1332*0Sstevel@tonic-gate } 1333*0Sstevel@tonic-gate 1334*0Sstevel@tonic-gate static int 1335*0Sstevel@tonic-gate ident_leaf(di_node_t node) 1336*0Sstevel@tonic-gate { 1337*0Sstevel@tonic-gate di_minor_t minor = DI_MINOR_NIL; 1338*0Sstevel@tonic-gate 1339*0Sstevel@tonic-gate return ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL && 1340*0Sstevel@tonic-gate di_child_node(node) == DI_NODE_NIL); 1341*0Sstevel@tonic-gate } 1342*0Sstevel@tonic-gate 1343*0Sstevel@tonic-gate /* ARGSUSED */ 1344*0Sstevel@tonic-gate static int 1345*0Sstevel@tonic-gate mk_drv_inst(di_node_t node, char drv_inst[], char *devfs_path) 1346*0Sstevel@tonic-gate { 1347*0Sstevel@tonic-gate char *drv; 1348*0Sstevel@tonic-gate int inst; 1349*0Sstevel@tonic-gate 1350*0Sstevel@tonic-gate if ((drv = di_driver_name(node)) == NULL) { 1351*0Sstevel@tonic-gate dprintf((stderr, "no driver bound to %s\n", 1352*0Sstevel@tonic-gate devfs_path)); 1353*0Sstevel@tonic-gate return (-1); 1354*0Sstevel@tonic-gate } 1355*0Sstevel@tonic-gate 1356*0Sstevel@tonic-gate if ((inst = di_instance(node)) == -1) { 1357*0Sstevel@tonic-gate dprintf((stderr, "no instance assigned to %s\n", 1358*0Sstevel@tonic-gate devfs_path)); 1359*0Sstevel@tonic-gate return (-1); 1360*0Sstevel@tonic-gate } 1361*0Sstevel@tonic-gate (void) snprintf(drv_inst, MAXPATHLEN, "%s%d", drv, inst); 1362*0Sstevel@tonic-gate 1363*0Sstevel@tonic-gate return (0); 1364*0Sstevel@tonic-gate } 1365*0Sstevel@tonic-gate 1366*0Sstevel@tonic-gate /* 1367*0Sstevel@tonic-gate * Libdevinfo walker. 1368*0Sstevel@tonic-gate * 1369*0Sstevel@tonic-gate * During the tree walk of the attached IO devices, for each node 1370*0Sstevel@tonic-gate * and all of its associated minors, the following actions are performed: 1371*0Sstevel@tonic-gate * - The /devices path of the physical device node or minor 1372*0Sstevel@tonic-gate * is stored in a lookup table along with a reference to the 1373*0Sstevel@tonic-gate * libdevinfo node it represents via add_lookup_entry(). 1374*0Sstevel@tonic-gate * - The device links associated with each device are also 1375*0Sstevel@tonic-gate * stored in the same lookup table along with a reference to 1376*0Sstevel@tonic-gate * the libdevinfo node it represents via the minor walk callback. 1377*0Sstevel@tonic-gate * 1378*0Sstevel@tonic-gate */ 1379*0Sstevel@tonic-gate static int 1380*0Sstevel@tonic-gate devinfo_node_walk(di_node_t node, void *arg) 1381*0Sstevel@tonic-gate { 1382*0Sstevel@tonic-gate char *devfs_path; 1383*0Sstevel@tonic-gate #ifdef DEBUG 1384*0Sstevel@tonic-gate char *drv; 1385*0Sstevel@tonic-gate #endif /* DEBUG */ 1386*0Sstevel@tonic-gate devinfo_arg_t *di_arg = (devinfo_arg_t *)arg; 1387*0Sstevel@tonic-gate 1388*0Sstevel@tonic-gate if (node == DI_NODE_NIL) { 1389*0Sstevel@tonic-gate return (DI_WALK_TERMINATE); 1390*0Sstevel@tonic-gate } 1391*0Sstevel@tonic-gate 1392*0Sstevel@tonic-gate if (((di_state(node) & DI_DRIVER_DETACHED) == 0) && 1393*0Sstevel@tonic-gate ((devfs_path = di_devfs_path(node)) != NULL)) { 1394*0Sstevel@tonic-gate 1395*0Sstevel@tonic-gate /* Use the provided path buffer to create full /devices path */ 1396*0Sstevel@tonic-gate (void) snprintf(di_arg->pathbuf, MAXPATHLEN, "/devices%s", 1397*0Sstevel@tonic-gate devfs_path); 1398*0Sstevel@tonic-gate 1399*0Sstevel@tonic-gate #ifdef DEBUG 1400*0Sstevel@tonic-gate dprintf((stderr, "devinfo_node_walk(%s)\n", di_arg->pathbuf)); 1401*0Sstevel@tonic-gate if ((drv = di_driver_name(node)) != NULL) 1402*0Sstevel@tonic-gate dprintf((stderr, " driver name %s instance %d\n", drv, 1403*0Sstevel@tonic-gate di_instance(node))); 1404*0Sstevel@tonic-gate #endif 1405*0Sstevel@tonic-gate 1406*0Sstevel@tonic-gate /* Free the devfs_path */ 1407*0Sstevel@tonic-gate di_devfs_path_free(devfs_path); 1408*0Sstevel@tonic-gate 1409*0Sstevel@tonic-gate /* Add an entry to the lookup table for this physical device */ 1410*0Sstevel@tonic-gate if (add_lookup_entry(di_arg->table, di_arg->pathbuf, node)) { 1411*0Sstevel@tonic-gate dprintf((stderr, "add_lookup_entry: %s\n", 1412*0Sstevel@tonic-gate strerror(errno))); 1413*0Sstevel@tonic-gate di_arg->err = 1; 1414*0Sstevel@tonic-gate return (DI_WALK_TERMINATE); 1415*0Sstevel@tonic-gate } 1416*0Sstevel@tonic-gate 1417*0Sstevel@tonic-gate /* Check if this node has minors */ 1418*0Sstevel@tonic-gate if ((di_minor_next(node, DI_MINOR_NIL)) != DI_MINOR_NIL) { 1419*0Sstevel@tonic-gate /* Walk this node's minors */ 1420*0Sstevel@tonic-gate di_arg->node = node; 1421*0Sstevel@tonic-gate if (di_walk_minor(node, NULL, DI_CHECK_ALIAS, arg, 1422*0Sstevel@tonic-gate devinfo_minor_walk) != 0) { 1423*0Sstevel@tonic-gate dprintf((stderr, "di_walk_minor: %s\n", 1424*0Sstevel@tonic-gate strerror(errno))); 1425*0Sstevel@tonic-gate di_arg->err = 1; 1426*0Sstevel@tonic-gate return (DI_WALK_TERMINATE); 1427*0Sstevel@tonic-gate } 1428*0Sstevel@tonic-gate } 1429*0Sstevel@tonic-gate } 1430*0Sstevel@tonic-gate 1431*0Sstevel@tonic-gate return (DI_WALK_CONTINUE); 1432*0Sstevel@tonic-gate } 1433*0Sstevel@tonic-gate 1434*0Sstevel@tonic-gate /* 1435*0Sstevel@tonic-gate * Use di_devlink_walk to find the /dev link from /devices path for this minor 1436*0Sstevel@tonic-gate */ 1437*0Sstevel@tonic-gate static int 1438*0Sstevel@tonic-gate devinfo_minor_walk(di_node_t node, di_minor_t minor, void *arg) 1439*0Sstevel@tonic-gate { 1440*0Sstevel@tonic-gate char *name; 1441*0Sstevel@tonic-gate char *devfs_path; 1442*0Sstevel@tonic-gate devinfo_arg_t *di_arg = (devinfo_arg_t *)arg; 1443*0Sstevel@tonic-gate char pathbuf[MAXPATHLEN]; 1444*0Sstevel@tonic-gate 1445*0Sstevel@tonic-gate #ifdef DEBUG 1446*0Sstevel@tonic-gate dprintf((stderr, "devinfo_minor_walk(%d) %s\n", minor, 1447*0Sstevel@tonic-gate di_arg->pathbuf)); 1448*0Sstevel@tonic-gate 1449*0Sstevel@tonic-gate if ((name = di_minor_name(minor)) != NULL) { 1450*0Sstevel@tonic-gate dprintf((stderr, " minor name %s\n", name)); 1451*0Sstevel@tonic-gate } 1452*0Sstevel@tonic-gate #endif /* DEBUG */ 1453*0Sstevel@tonic-gate 1454*0Sstevel@tonic-gate /* Terminate the walk when the device node changes */ 1455*0Sstevel@tonic-gate if (node != di_arg->node) { 1456*0Sstevel@tonic-gate return (DI_WALK_TERMINATE); 1457*0Sstevel@tonic-gate } 1458*0Sstevel@tonic-gate 1459*0Sstevel@tonic-gate /* Construct full /devices path for this minor */ 1460*0Sstevel@tonic-gate if ((name = di_minor_name(minor)) == NULL) { 1461*0Sstevel@tonic-gate return (DI_WALK_CONTINUE); 1462*0Sstevel@tonic-gate } 1463*0Sstevel@tonic-gate (void) snprintf(pathbuf, MAXPATHLEN, "%s:%s", di_arg->pathbuf, name); 1464*0Sstevel@tonic-gate 1465*0Sstevel@tonic-gate /* Add lookup entry for this minor node */ 1466*0Sstevel@tonic-gate if (add_lookup_entry(di_arg->table, pathbuf, node)) { 1467*0Sstevel@tonic-gate dprintf((stderr, "add_lookup_entry: %s\n", strerror(errno))); 1468*0Sstevel@tonic-gate di_arg->err = 1; 1469*0Sstevel@tonic-gate return (DI_WALK_TERMINATE); 1470*0Sstevel@tonic-gate } 1471*0Sstevel@tonic-gate 1472*0Sstevel@tonic-gate /* 1473*0Sstevel@tonic-gate * Walk the associated device links. 1474*0Sstevel@tonic-gate * Note that di_devlink_walk() doesn't want "/devices" in its paths. 1475*0Sstevel@tonic-gate * Also note that di_devlink_walk() will fail if there are no device 1476*0Sstevel@tonic-gate * links, which is fine; so ignore if it fails. Only check for 1477*0Sstevel@tonic-gate * internal failures during such a walk. 1478*0Sstevel@tonic-gate */ 1479*0Sstevel@tonic-gate devfs_path = &pathbuf[strlen("/devices")]; 1480*0Sstevel@tonic-gate (void) di_devlink_walk(di_arg->linkhd, NULL, devfs_path, 0, arg, 1481*0Sstevel@tonic-gate devinfo_devlink_walk); 1482*0Sstevel@tonic-gate if (di_arg->err != 0) { 1483*0Sstevel@tonic-gate return (DI_WALK_TERMINATE); 1484*0Sstevel@tonic-gate } 1485*0Sstevel@tonic-gate 1486*0Sstevel@tonic-gate return (DI_WALK_CONTINUE); 1487*0Sstevel@tonic-gate } 1488*0Sstevel@tonic-gate 1489*0Sstevel@tonic-gate static int 1490*0Sstevel@tonic-gate devinfo_devlink_walk(di_devlink_t devlink, void *arg) 1491*0Sstevel@tonic-gate { 1492*0Sstevel@tonic-gate const char *linkpath; 1493*0Sstevel@tonic-gate devinfo_arg_t *di_arg = (devinfo_arg_t *)arg; 1494*0Sstevel@tonic-gate 1495*0Sstevel@tonic-gate /* Get the devlink's path */ 1496*0Sstevel@tonic-gate if ((linkpath = di_devlink_path(devlink)) == NULL) { 1497*0Sstevel@tonic-gate dprintf((stderr, "di_devlink_path: %s\n", strerror(errno))); 1498*0Sstevel@tonic-gate di_arg->err = 1; 1499*0Sstevel@tonic-gate return (DI_WALK_TERMINATE); 1500*0Sstevel@tonic-gate } 1501*0Sstevel@tonic-gate dprintf((stderr, "devinfo_devlink_walk: %s\n", linkpath)); 1502*0Sstevel@tonic-gate 1503*0Sstevel@tonic-gate /* Add lookup entry for this devlink */ 1504*0Sstevel@tonic-gate if (add_lookup_entry(di_arg->table, linkpath, di_arg->node)) { 1505*0Sstevel@tonic-gate dprintf((stderr, "add_lookup_entry: %s\n", strerror(errno))); 1506*0Sstevel@tonic-gate di_arg->err = 1; 1507*0Sstevel@tonic-gate return (DI_WALK_TERMINATE); 1508*0Sstevel@tonic-gate } 1509*0Sstevel@tonic-gate 1510*0Sstevel@tonic-gate return (DI_WALK_CONTINUE); 1511*0Sstevel@tonic-gate } 1512*0Sstevel@tonic-gate 1513*0Sstevel@tonic-gate /* 1514*0Sstevel@tonic-gate * Map rcm_info_t's to ri_client_t's, filtering out "uninteresting" (hack) 1515*0Sstevel@tonic-gate * RCM clients. The number of "interesting" ri_client_t's is returned 1516*0Sstevel@tonic-gate * in cnt if passed non-NULL. 1517*0Sstevel@tonic-gate */ 1518*0Sstevel@tonic-gate static int 1519*0Sstevel@tonic-gate add_rcm_clients(ri_client_t **client_list, rcmd_t *rcm, rcm_info_t *info, 1520*0Sstevel@tonic-gate int flags, int *cnt) 1521*0Sstevel@tonic-gate { 1522*0Sstevel@tonic-gate rcm_info_tuple_t *tuple; 1523*0Sstevel@tonic-gate char *rsrc, *usage; 1524*0Sstevel@tonic-gate ri_client_t *client, *tmp; 1525*0Sstevel@tonic-gate 1526*0Sstevel@tonic-gate assert(client_list != NULL && rcm != NULL); 1527*0Sstevel@tonic-gate 1528*0Sstevel@tonic-gate if (info == NULL) 1529*0Sstevel@tonic-gate return (0); 1530*0Sstevel@tonic-gate 1531*0Sstevel@tonic-gate if (cnt != NULL) 1532*0Sstevel@tonic-gate *cnt = 0; 1533*0Sstevel@tonic-gate 1534*0Sstevel@tonic-gate tuple = NULL; 1535*0Sstevel@tonic-gate while ((tuple = rcm_info_next(info, tuple)) != NULL) { 1536*0Sstevel@tonic-gate if ((rsrc = (char *)rcm_info_rsrc(tuple)) == NULL || 1537*0Sstevel@tonic-gate (usage = (char *)rcm_info_info(tuple)) == NULL) { 1538*0Sstevel@tonic-gate continue; 1539*0Sstevel@tonic-gate } 1540*0Sstevel@tonic-gate 1541*0Sstevel@tonic-gate if (rcm_ignore(rsrc, usage) == 0) 1542*0Sstevel@tonic-gate continue; 1543*0Sstevel@tonic-gate 1544*0Sstevel@tonic-gate if ((client = ri_client_alloc(rsrc, usage)) == NULL) 1545*0Sstevel@tonic-gate return (-1); 1546*0Sstevel@tonic-gate 1547*0Sstevel@tonic-gate if ((flags & RI_INCLUDE_QUERY) && add_query_state(rcm, client, 1548*0Sstevel@tonic-gate rsrc, usage) != 0) { 1549*0Sstevel@tonic-gate ri_client_free(client); 1550*0Sstevel@tonic-gate return (-1); 1551*0Sstevel@tonic-gate } 1552*0Sstevel@tonic-gate 1553*0Sstevel@tonic-gate if (cnt != NULL) 1554*0Sstevel@tonic-gate ++*cnt; 1555*0Sstevel@tonic-gate 1556*0Sstevel@tonic-gate /* 1557*0Sstevel@tonic-gate * Link in 1558*0Sstevel@tonic-gate */ 1559*0Sstevel@tonic-gate if ((tmp = *client_list) == NULL) { 1560*0Sstevel@tonic-gate *client_list = client; 1561*0Sstevel@tonic-gate continue; 1562*0Sstevel@tonic-gate } 1563*0Sstevel@tonic-gate while (tmp->next != NULL) { 1564*0Sstevel@tonic-gate tmp = tmp->next; 1565*0Sstevel@tonic-gate } 1566*0Sstevel@tonic-gate tmp->next = client; 1567*0Sstevel@tonic-gate } 1568*0Sstevel@tonic-gate 1569*0Sstevel@tonic-gate return (0); 1570*0Sstevel@tonic-gate } 1571*0Sstevel@tonic-gate 1572*0Sstevel@tonic-gate /* 1573*0Sstevel@tonic-gate * Currently only filtering out based on known info string prefixes. 1574*0Sstevel@tonic-gate */ 1575*0Sstevel@tonic-gate /* ARGSUSED */ 1576*0Sstevel@tonic-gate static int 1577*0Sstevel@tonic-gate rcm_ignore(char *rsrc, char *infostr) 1578*0Sstevel@tonic-gate { 1579*0Sstevel@tonic-gate char **cpp; 1580*0Sstevel@tonic-gate 1581*0Sstevel@tonic-gate for (cpp = rcm_info_filter; *cpp != NULL; cpp++) { 1582*0Sstevel@tonic-gate if (strncmp(infostr, *cpp, strlen(*cpp)) == 0) { 1583*0Sstevel@tonic-gate return (0); 1584*0Sstevel@tonic-gate } 1585*0Sstevel@tonic-gate } 1586*0Sstevel@tonic-gate return (-1); 1587*0Sstevel@tonic-gate } 1588*0Sstevel@tonic-gate 1589*0Sstevel@tonic-gate /* 1590*0Sstevel@tonic-gate * If this tuple was cached in the offline query pass, add the 1591*0Sstevel@tonic-gate * query state and error string to the ri_client_t. 1592*0Sstevel@tonic-gate */ 1593*0Sstevel@tonic-gate static int 1594*0Sstevel@tonic-gate add_query_state(rcmd_t *rcm, ri_client_t *client, const char *rsrc, 1595*0Sstevel@tonic-gate const char *info) 1596*0Sstevel@tonic-gate { 1597*0Sstevel@tonic-gate int qstate = RI_QUERY_UNKNOWN; 1598*0Sstevel@tonic-gate char *errstr = NULL; 1599*0Sstevel@tonic-gate rcm_info_tuple_t *cached_tuple; 1600*0Sstevel@tonic-gate 1601*0Sstevel@tonic-gate if ((cached_tuple = tuple_lookup(rcm, rsrc, info)) != NULL) { 1602*0Sstevel@tonic-gate qstate = state2query(rcm_info_state(cached_tuple)); 1603*0Sstevel@tonic-gate errstr = (char *)rcm_info_error(cached_tuple); 1604*0Sstevel@tonic-gate } 1605*0Sstevel@tonic-gate 1606*0Sstevel@tonic-gate if (nvlist_add_int32(client->usg_props, RI_QUERY_STATE, qstate) != 0 || 1607*0Sstevel@tonic-gate (errstr != NULL && nvlist_add_string(client->usg_props, 1608*0Sstevel@tonic-gate RI_QUERY_ERR, errstr) != 0)) { 1609*0Sstevel@tonic-gate dprintf((stderr, "nvlist_add fail\n")); 1610*0Sstevel@tonic-gate return (-1); 1611*0Sstevel@tonic-gate } 1612*0Sstevel@tonic-gate 1613*0Sstevel@tonic-gate return (0); 1614*0Sstevel@tonic-gate } 1615*0Sstevel@tonic-gate 1616*0Sstevel@tonic-gate static int 1617*0Sstevel@tonic-gate state2query(int rcm_state) 1618*0Sstevel@tonic-gate { 1619*0Sstevel@tonic-gate int query; 1620*0Sstevel@tonic-gate 1621*0Sstevel@tonic-gate switch (rcm_state) { 1622*0Sstevel@tonic-gate case RCM_STATE_OFFLINE_QUERY: 1623*0Sstevel@tonic-gate case RCM_STATE_SUSPEND_QUERY: 1624*0Sstevel@tonic-gate query = RI_QUERY_OK; 1625*0Sstevel@tonic-gate break; 1626*0Sstevel@tonic-gate case RCM_STATE_OFFLINE_QUERY_FAIL: 1627*0Sstevel@tonic-gate case RCM_STATE_SUSPEND_QUERY_FAIL: 1628*0Sstevel@tonic-gate query = RI_QUERY_FAIL; 1629*0Sstevel@tonic-gate break; 1630*0Sstevel@tonic-gate default: 1631*0Sstevel@tonic-gate query = RI_QUERY_UNKNOWN; 1632*0Sstevel@tonic-gate break; 1633*0Sstevel@tonic-gate } 1634*0Sstevel@tonic-gate 1635*0Sstevel@tonic-gate return (query); 1636*0Sstevel@tonic-gate } 1637*0Sstevel@tonic-gate 1638*0Sstevel@tonic-gate static void 1639*0Sstevel@tonic-gate dev_list_append(ri_dev_t **head, ri_dev_t *dev) 1640*0Sstevel@tonic-gate { 1641*0Sstevel@tonic-gate ri_dev_t *tmp; 1642*0Sstevel@tonic-gate 1643*0Sstevel@tonic-gate if ((tmp = *head) == NULL) { 1644*0Sstevel@tonic-gate *head = dev; 1645*0Sstevel@tonic-gate return; 1646*0Sstevel@tonic-gate } 1647*0Sstevel@tonic-gate while (tmp->next != NULL) { 1648*0Sstevel@tonic-gate tmp = tmp->next; 1649*0Sstevel@tonic-gate } 1650*0Sstevel@tonic-gate tmp->next = dev; 1651*0Sstevel@tonic-gate } 1652*0Sstevel@tonic-gate 1653*0Sstevel@tonic-gate /* 1654*0Sstevel@tonic-gate * The cpu list is ordered on cpuid since CMP cpuids will not necessarily 1655*0Sstevel@tonic-gate * be discovered in sequence. 1656*0Sstevel@tonic-gate */ 1657*0Sstevel@tonic-gate static void 1658*0Sstevel@tonic-gate dev_list_cpu_insert(ri_dev_t **listp, ri_dev_t *dev, processorid_t newid) 1659*0Sstevel@tonic-gate { 1660*0Sstevel@tonic-gate ri_dev_t *tmp; 1661*0Sstevel@tonic-gate int32_t cpuid; 1662*0Sstevel@tonic-gate 1663*0Sstevel@tonic-gate while ((tmp = *listp) != NULL && 1664*0Sstevel@tonic-gate nvlist_lookup_int32(tmp->conf_props, RI_CPU_ID, &cpuid) == 0 && 1665*0Sstevel@tonic-gate cpuid < newid) { 1666*0Sstevel@tonic-gate listp = &tmp->next; 1667*0Sstevel@tonic-gate } 1668*0Sstevel@tonic-gate 1669*0Sstevel@tonic-gate dev->next = tmp; 1670*0Sstevel@tonic-gate *listp = dev; 1671*0Sstevel@tonic-gate } 1672*0Sstevel@tonic-gate 1673*0Sstevel@tonic-gate /* 1674*0Sstevel@tonic-gate * Linear lookup. Should convert to hash tab. 1675*0Sstevel@tonic-gate */ 1676*0Sstevel@tonic-gate static rcm_info_tuple_t * 1677*0Sstevel@tonic-gate tuple_lookup(rcmd_t *rcm, const char *krsrc, const char *kinfo) 1678*0Sstevel@tonic-gate { 1679*0Sstevel@tonic-gate rcm_info_tuple_t *tuple = NULL; 1680*0Sstevel@tonic-gate const char *rsrc, *info; 1681*0Sstevel@tonic-gate 1682*0Sstevel@tonic-gate if ((rcm == NULL) || (krsrc == NULL) || (kinfo == NULL)) { 1683*0Sstevel@tonic-gate return (NULL); 1684*0Sstevel@tonic-gate } 1685*0Sstevel@tonic-gate 1686*0Sstevel@tonic-gate while ((tuple = rcm_info_next(rcm->offline_query_info, 1687*0Sstevel@tonic-gate tuple)) != NULL) { 1688*0Sstevel@tonic-gate if ((rsrc = rcm_info_rsrc(tuple)) == NULL || 1689*0Sstevel@tonic-gate (info = rcm_info_info(tuple)) == NULL) { 1690*0Sstevel@tonic-gate continue; 1691*0Sstevel@tonic-gate } 1692*0Sstevel@tonic-gate 1693*0Sstevel@tonic-gate if (strcmp(rsrc, krsrc) == 0 && strcmp(info, kinfo) == 0) { 1694*0Sstevel@tonic-gate return (tuple); 1695*0Sstevel@tonic-gate } 1696*0Sstevel@tonic-gate } 1697*0Sstevel@tonic-gate return (NULL); 1698*0Sstevel@tonic-gate } 1699*0Sstevel@tonic-gate 1700*0Sstevel@tonic-gate /* 1701*0Sstevel@tonic-gate * Create and link attachment point handle. 1702*0Sstevel@tonic-gate */ 1703*0Sstevel@tonic-gate static ri_ap_t * 1704*0Sstevel@tonic-gate ri_ap_alloc(char *ap_id, ri_hdl_t *hdl) 1705*0Sstevel@tonic-gate { 1706*0Sstevel@tonic-gate ri_ap_t *ap, *tmp; 1707*0Sstevel@tonic-gate 1708*0Sstevel@tonic-gate if ((ap = calloc(1, sizeof (*ap))) == NULL) { 1709*0Sstevel@tonic-gate dprintf((stderr, "calloc: %s\n", strerror(errno))); 1710*0Sstevel@tonic-gate return (NULL); 1711*0Sstevel@tonic-gate } 1712*0Sstevel@tonic-gate 1713*0Sstevel@tonic-gate if (nvlist_alloc(&ap->conf_props, NV_UNIQUE_NAME, 0) != 0 || 1714*0Sstevel@tonic-gate nvlist_add_string(ap->conf_props, RI_AP_REQ_ID, ap_id) != 0) { 1715*0Sstevel@tonic-gate if (ap->conf_props != NULL) 1716*0Sstevel@tonic-gate nvlist_free(ap->conf_props); 1717*0Sstevel@tonic-gate free(ap); 1718*0Sstevel@tonic-gate return (NULL); 1719*0Sstevel@tonic-gate } 1720*0Sstevel@tonic-gate 1721*0Sstevel@tonic-gate if ((tmp = hdl->aps) == NULL) { 1722*0Sstevel@tonic-gate hdl->aps = ap; 1723*0Sstevel@tonic-gate } else { 1724*0Sstevel@tonic-gate while (tmp->next != NULL) { 1725*0Sstevel@tonic-gate tmp = tmp->next; 1726*0Sstevel@tonic-gate } 1727*0Sstevel@tonic-gate tmp->next = ap; 1728*0Sstevel@tonic-gate } 1729*0Sstevel@tonic-gate 1730*0Sstevel@tonic-gate return (ap); 1731*0Sstevel@tonic-gate } 1732*0Sstevel@tonic-gate 1733*0Sstevel@tonic-gate static ri_dev_t * 1734*0Sstevel@tonic-gate ri_dev_alloc(void) 1735*0Sstevel@tonic-gate { 1736*0Sstevel@tonic-gate ri_dev_t *dev; 1737*0Sstevel@tonic-gate 1738*0Sstevel@tonic-gate if ((dev = calloc(1, sizeof (*dev))) == NULL || 1739*0Sstevel@tonic-gate nvlist_alloc(&dev->conf_props, NV_UNIQUE_NAME, 0) != 0) { 1740*0Sstevel@tonic-gate s_free(dev); 1741*0Sstevel@tonic-gate } 1742*0Sstevel@tonic-gate return (dev); 1743*0Sstevel@tonic-gate } 1744*0Sstevel@tonic-gate 1745*0Sstevel@tonic-gate static ri_dev_t * 1746*0Sstevel@tonic-gate io_dev_alloc(char *drv_inst) 1747*0Sstevel@tonic-gate { 1748*0Sstevel@tonic-gate ri_dev_t *io; 1749*0Sstevel@tonic-gate 1750*0Sstevel@tonic-gate assert(drv_inst != NULL); 1751*0Sstevel@tonic-gate 1752*0Sstevel@tonic-gate if ((io = ri_dev_alloc()) == NULL) 1753*0Sstevel@tonic-gate return (NULL); 1754*0Sstevel@tonic-gate 1755*0Sstevel@tonic-gate if (nvlist_add_string(io->conf_props, RI_IO_DRV_INST, 1756*0Sstevel@tonic-gate drv_inst) != 0) { 1757*0Sstevel@tonic-gate dprintf((stderr, "nvlist_add_string fail\n")); 1758*0Sstevel@tonic-gate ri_dev_free(io); 1759*0Sstevel@tonic-gate return (NULL); 1760*0Sstevel@tonic-gate } 1761*0Sstevel@tonic-gate 1762*0Sstevel@tonic-gate return (io); 1763*0Sstevel@tonic-gate } 1764*0Sstevel@tonic-gate 1765*0Sstevel@tonic-gate static ri_client_t * 1766*0Sstevel@tonic-gate ri_client_alloc(char *rsrc, char *usage) 1767*0Sstevel@tonic-gate { 1768*0Sstevel@tonic-gate ri_client_t *client; 1769*0Sstevel@tonic-gate 1770*0Sstevel@tonic-gate assert(rsrc != NULL && usage != NULL); 1771*0Sstevel@tonic-gate 1772*0Sstevel@tonic-gate if ((client = calloc(1, sizeof (*client))) == NULL) { 1773*0Sstevel@tonic-gate dprintf((stderr, "calloc: %s\n", strerror(errno))); 1774*0Sstevel@tonic-gate return (NULL); 1775*0Sstevel@tonic-gate } 1776*0Sstevel@tonic-gate 1777*0Sstevel@tonic-gate if (nvlist_alloc(&client->usg_props, NV_UNIQUE_NAME, 0) != 0) { 1778*0Sstevel@tonic-gate dprintf((stderr, "nvlist_alloc fail\n")); 1779*0Sstevel@tonic-gate free(client); 1780*0Sstevel@tonic-gate return (NULL); 1781*0Sstevel@tonic-gate } 1782*0Sstevel@tonic-gate 1783*0Sstevel@tonic-gate if (nvlist_add_string(client->usg_props, RI_CLIENT_RSRC, rsrc) != 0 || 1784*0Sstevel@tonic-gate nvlist_add_string(client->usg_props, RI_CLIENT_USAGE, usage) != 0) { 1785*0Sstevel@tonic-gate dprintf((stderr, "nvlist_add_string fail\n")); 1786*0Sstevel@tonic-gate ri_client_free(client); 1787*0Sstevel@tonic-gate return (NULL); 1788*0Sstevel@tonic-gate } 1789*0Sstevel@tonic-gate 1790*0Sstevel@tonic-gate return (client); 1791*0Sstevel@tonic-gate } 1792*0Sstevel@tonic-gate 1793*0Sstevel@tonic-gate static void 1794*0Sstevel@tonic-gate apd_tbl_free(apd_t apd_tbl[], int napds) 1795*0Sstevel@tonic-gate { 1796*0Sstevel@tonic-gate int i; 1797*0Sstevel@tonic-gate apd_t *apd; 1798*0Sstevel@tonic-gate 1799*0Sstevel@tonic-gate for (i = 0, apd = apd_tbl; i < napds; i++, apd++) 1800*0Sstevel@tonic-gate s_free(apd->cfga_list_data); 1801*0Sstevel@tonic-gate 1802*0Sstevel@tonic-gate free(apd_tbl); 1803*0Sstevel@tonic-gate } 1804*0Sstevel@tonic-gate 1805*0Sstevel@tonic-gate static char * 1806*0Sstevel@tonic-gate pstate2str(int pi_state) 1807*0Sstevel@tonic-gate { 1808*0Sstevel@tonic-gate char *state; 1809*0Sstevel@tonic-gate 1810*0Sstevel@tonic-gate switch (pi_state) { 1811*0Sstevel@tonic-gate case P_OFFLINE: 1812*0Sstevel@tonic-gate state = PS_OFFLINE; 1813*0Sstevel@tonic-gate break; 1814*0Sstevel@tonic-gate case P_ONLINE: 1815*0Sstevel@tonic-gate state = PS_ONLINE; 1816*0Sstevel@tonic-gate break; 1817*0Sstevel@tonic-gate case P_FAULTED: 1818*0Sstevel@tonic-gate state = PS_FAULTED; 1819*0Sstevel@tonic-gate break; 1820*0Sstevel@tonic-gate case P_POWEROFF: 1821*0Sstevel@tonic-gate state = PS_POWEROFF; 1822*0Sstevel@tonic-gate break; 1823*0Sstevel@tonic-gate case P_NOINTR: 1824*0Sstevel@tonic-gate state = PS_NOINTR; 1825*0Sstevel@tonic-gate break; 1826*0Sstevel@tonic-gate case P_SPARE: 1827*0Sstevel@tonic-gate state = PS_SPARE; 1828*0Sstevel@tonic-gate break; 1829*0Sstevel@tonic-gate default: 1830*0Sstevel@tonic-gate state = "unknown"; 1831*0Sstevel@tonic-gate break; 1832*0Sstevel@tonic-gate } 1833*0Sstevel@tonic-gate 1834*0Sstevel@tonic-gate return (state); 1835*0Sstevel@tonic-gate } 1836*0Sstevel@tonic-gate 1837*0Sstevel@tonic-gate #ifdef DEBUG 1838*0Sstevel@tonic-gate static void 1839*0Sstevel@tonic-gate dump_apd_tbl(FILE *fp, apd_t *apds, int n_apds) 1840*0Sstevel@tonic-gate { 1841*0Sstevel@tonic-gate int i, j; 1842*0Sstevel@tonic-gate cfga_list_data_t *cfga_ldata; 1843*0Sstevel@tonic-gate 1844*0Sstevel@tonic-gate for (i = 0; i < n_apds; i++, apds++) { 1845*0Sstevel@tonic-gate dprintf((stderr, "apd_tbl[%d].nlist=%d\n", i, apds->nlist)); 1846*0Sstevel@tonic-gate for (j = 0, cfga_ldata = apds->cfga_list_data; j < apds->nlist; 1847*0Sstevel@tonic-gate j++, cfga_ldata++) { 1848*0Sstevel@tonic-gate dprintf((fp, 1849*0Sstevel@tonic-gate "apd_tbl[%d].cfga_list_data[%d].ap_log_id=%s\n", 1850*0Sstevel@tonic-gate i, j, cfga_ldata->ap_log_id)); 1851*0Sstevel@tonic-gate } 1852*0Sstevel@tonic-gate } 1853*0Sstevel@tonic-gate } 1854*0Sstevel@tonic-gate #endif /* DEBUG */ 1855*0Sstevel@tonic-gate 1856*0Sstevel@tonic-gate /* 1857*0Sstevel@tonic-gate * The lookup table is a simple array that is grown in chunks 1858*0Sstevel@tonic-gate * to optimize memory allocation. 1859*0Sstevel@tonic-gate * Indices are assigned to each array entry in-order so that 1860*0Sstevel@tonic-gate * the original device tree ordering can be discerned at a later time. 1861*0Sstevel@tonic-gate * 1862*0Sstevel@tonic-gate * add_lookup_entry is called from the libdevinfo tree traversal callbacks: 1863*0Sstevel@tonic-gate * 1) devinfo_node_walk - physical device path for each node in 1864*0Sstevel@tonic-gate * the devinfo tree via di_walk_node(), lookup entry name is 1865*0Sstevel@tonic-gate * /devices/[di_devfs_path] 1866*0Sstevel@tonic-gate * 2) devinfo_minor_walk - physical device path plus minor name for 1867*0Sstevel@tonic-gate * each minor associated with a node via di_walk_minor(), lookup entry 1868*0Sstevel@tonic-gate * name is /devices/[di_devfs_path:di_minor_name] 1869*0Sstevel@tonic-gate * 3) devinfo_devlink_walk - for each minor's /dev link from its /devices 1870*0Sstevel@tonic-gate * path via di_devlink_walk(), lookup entry name is di_devlink_path() 1871*0Sstevel@tonic-gate */ 1872*0Sstevel@tonic-gate static int 1873*0Sstevel@tonic-gate add_lookup_entry(lookup_table_t *table, const char *name, di_node_t node) 1874*0Sstevel@tonic-gate { 1875*0Sstevel@tonic-gate size_t size; 1876*0Sstevel@tonic-gate lookup_entry_t *new_table; 1877*0Sstevel@tonic-gate 1878*0Sstevel@tonic-gate 1879*0Sstevel@tonic-gate /* Grow the lookup table by USAGE_ALLOC_SIZE slots if necessary */ 1880*0Sstevel@tonic-gate if (table->n_entries == table->n_slots) { 1881*0Sstevel@tonic-gate size = (table->n_slots + USAGE_ALLOC_SIZE) * 1882*0Sstevel@tonic-gate sizeof (lookup_entry_t); 1883*0Sstevel@tonic-gate new_table = (lookup_entry_t *)realloc(table->table, size); 1884*0Sstevel@tonic-gate if (new_table == NULL) { 1885*0Sstevel@tonic-gate dprintf((stderr, "add_lookup_entry: alloc failed: %s\n", 1886*0Sstevel@tonic-gate strerror(errno))); 1887*0Sstevel@tonic-gate errno = ENOMEM; 1888*0Sstevel@tonic-gate return (-1); 1889*0Sstevel@tonic-gate } 1890*0Sstevel@tonic-gate table->table = new_table; 1891*0Sstevel@tonic-gate table->n_slots += USAGE_ALLOC_SIZE; 1892*0Sstevel@tonic-gate } 1893*0Sstevel@tonic-gate 1894*0Sstevel@tonic-gate dprintf((stderr, "add_lookup_entry[%d]:%s\n", table->n_entries, name)); 1895*0Sstevel@tonic-gate 1896*0Sstevel@tonic-gate /* Add this name to the next slot */ 1897*0Sstevel@tonic-gate if ((table->table[table->n_entries].name = strdup(name)) == NULL) { 1898*0Sstevel@tonic-gate dprintf((stderr, "add_lookup_entry: strdup failed: %s\n", 1899*0Sstevel@tonic-gate strerror(errno))); 1900*0Sstevel@tonic-gate errno = ENOMEM; 1901*0Sstevel@tonic-gate return (-1); 1902*0Sstevel@tonic-gate } 1903*0Sstevel@tonic-gate table->table[table->n_entries].index = table->n_entries; 1904*0Sstevel@tonic-gate table->table[table->n_entries].node = node; 1905*0Sstevel@tonic-gate table->table[table->n_entries].n_usage = 0; 1906*0Sstevel@tonic-gate table->table[table->n_entries].usage = NULL; 1907*0Sstevel@tonic-gate table->n_entries += 1; 1908*0Sstevel@tonic-gate 1909*0Sstevel@tonic-gate return (0); 1910*0Sstevel@tonic-gate } 1911*0Sstevel@tonic-gate 1912*0Sstevel@tonic-gate /* 1913*0Sstevel@tonic-gate * lookup table entry names are full pathname strings, all start with / 1914*0Sstevel@tonic-gate */ 1915*0Sstevel@tonic-gate static int 1916*0Sstevel@tonic-gate table_compare_names(const void *a, const void *b) 1917*0Sstevel@tonic-gate { 1918*0Sstevel@tonic-gate lookup_entry_t *entry1 = (lookup_entry_t *)a; 1919*0Sstevel@tonic-gate lookup_entry_t *entry2 = (lookup_entry_t *)b; 1920*0Sstevel@tonic-gate 1921*0Sstevel@tonic-gate return (strcmp(entry1->name, entry2->name)); 1922*0Sstevel@tonic-gate } 1923*0Sstevel@tonic-gate 1924*0Sstevel@tonic-gate 1925*0Sstevel@tonic-gate /* 1926*0Sstevel@tonic-gate * Compare two indices and return -1 for less, 1 for greater, 0 for equal 1927*0Sstevel@tonic-gate */ 1928*0Sstevel@tonic-gate static int 1929*0Sstevel@tonic-gate table_compare_indices(const void *a, const void *b) 1930*0Sstevel@tonic-gate { 1931*0Sstevel@tonic-gate lookup_entry_t *entry1 = (lookup_entry_t *)a; 1932*0Sstevel@tonic-gate lookup_entry_t *entry2 = (lookup_entry_t *)b; 1933*0Sstevel@tonic-gate 1934*0Sstevel@tonic-gate if (entry1->index < entry2->index) 1935*0Sstevel@tonic-gate return (-1); 1936*0Sstevel@tonic-gate if (entry1->index > entry2->index) 1937*0Sstevel@tonic-gate return (1); 1938*0Sstevel@tonic-gate return (0); 1939*0Sstevel@tonic-gate } 1940*0Sstevel@tonic-gate 1941*0Sstevel@tonic-gate /* 1942*0Sstevel@tonic-gate * Given a RCM resource name, find the matching entry in the IO device table 1943*0Sstevel@tonic-gate */ 1944*0Sstevel@tonic-gate static lookup_entry_t * 1945*0Sstevel@tonic-gate lookup(lookup_table_t *table, const char *rcm_rsrc) 1946*0Sstevel@tonic-gate { 1947*0Sstevel@tonic-gate lookup_entry_t *entry; 1948*0Sstevel@tonic-gate lookup_entry_t lookup_arg; 1949*0Sstevel@tonic-gate 1950*0Sstevel@tonic-gate dprintf((stderr, "lookup:%s\n", rcm_rsrc)); 1951*0Sstevel@tonic-gate lookup_arg.name = (char *)rcm_rsrc; 1952*0Sstevel@tonic-gate entry = bsearch(&lookup_arg, table->table, table->n_entries, 1953*0Sstevel@tonic-gate sizeof (lookup_entry_t), table_compare_names); 1954*0Sstevel@tonic-gate 1955*0Sstevel@tonic-gate #ifdef DEBUG 1956*0Sstevel@tonic-gate if (entry != NULL) { 1957*0Sstevel@tonic-gate dprintf((stderr, " found entry:%d\n", entry->index)); 1958*0Sstevel@tonic-gate } 1959*0Sstevel@tonic-gate #endif /* DEBUG */ 1960*0Sstevel@tonic-gate return (entry); 1961*0Sstevel@tonic-gate } 1962*0Sstevel@tonic-gate 1963*0Sstevel@tonic-gate /* 1964*0Sstevel@tonic-gate * Add RCM usage to the given device table entry. 1965*0Sstevel@tonic-gate * Returns -1 on realloc failure. 1966*0Sstevel@tonic-gate */ 1967*0Sstevel@tonic-gate static int 1968*0Sstevel@tonic-gate add_usage(lookup_entry_t *entry, const char *rcm_rsrc, rcm_info_tuple_t *tuple) 1969*0Sstevel@tonic-gate { 1970*0Sstevel@tonic-gate size_t size; 1971*0Sstevel@tonic-gate const char *info; 1972*0Sstevel@tonic-gate usage_t *new_usage; 1973*0Sstevel@tonic-gate 1974*0Sstevel@tonic-gate if ((entry == NULL) || 1975*0Sstevel@tonic-gate ((info = rcm_info_info(tuple)) == NULL)) 1976*0Sstevel@tonic-gate return (0); 1977*0Sstevel@tonic-gate 1978*0Sstevel@tonic-gate if (rcm_ignore((char *)rcm_rsrc, (char *)info) == 0) 1979*0Sstevel@tonic-gate return (0); 1980*0Sstevel@tonic-gate 1981*0Sstevel@tonic-gate size = (entry->n_usage + 1) * sizeof (usage_t); 1982*0Sstevel@tonic-gate new_usage = (usage_t *)realloc(entry->usage, size); 1983*0Sstevel@tonic-gate if (new_usage == NULL) { 1984*0Sstevel@tonic-gate dprintf((stderr, "add_usage: alloc failed: %s\n", 1985*0Sstevel@tonic-gate strerror(errno))); 1986*0Sstevel@tonic-gate return (-1); 1987*0Sstevel@tonic-gate } 1988*0Sstevel@tonic-gate dprintf((stderr, "add_usage: entry %d rsrc: %s info: %s\n", 1989*0Sstevel@tonic-gate entry->index, rcm_rsrc, info)); 1990*0Sstevel@tonic-gate 1991*0Sstevel@tonic-gate entry->usage = new_usage; 1992*0Sstevel@tonic-gate entry->usage[entry->n_usage].rsrc = rcm_rsrc; 1993*0Sstevel@tonic-gate entry->usage[entry->n_usage].info = info; 1994*0Sstevel@tonic-gate entry->n_usage += 1; 1995*0Sstevel@tonic-gate return (0); 1996*0Sstevel@tonic-gate } 1997*0Sstevel@tonic-gate 1998*0Sstevel@tonic-gate static void 1999*0Sstevel@tonic-gate empty_table(lookup_table_t *table) 2000*0Sstevel@tonic-gate { 2001*0Sstevel@tonic-gate int i; 2002*0Sstevel@tonic-gate 2003*0Sstevel@tonic-gate if (table) { 2004*0Sstevel@tonic-gate for (i = 0; i < table->n_entries; i++) { 2005*0Sstevel@tonic-gate if (table->table[i].name) 2006*0Sstevel@tonic-gate free(table->table[i].name); 2007*0Sstevel@tonic-gate /* 2008*0Sstevel@tonic-gate * Note: the strings pointed to from within 2009*0Sstevel@tonic-gate * usage were freed already by rcm_free_info 2010*0Sstevel@tonic-gate */ 2011*0Sstevel@tonic-gate if (table->table[i].usage) 2012*0Sstevel@tonic-gate free(table->table[i].usage); 2013*0Sstevel@tonic-gate } 2014*0Sstevel@tonic-gate if (table->table) 2015*0Sstevel@tonic-gate free(table->table); 2016*0Sstevel@tonic-gate table->table = NULL; 2017*0Sstevel@tonic-gate table->n_entries = 0; 2018*0Sstevel@tonic-gate table->n_slots = 0; 2019*0Sstevel@tonic-gate } 2020*0Sstevel@tonic-gate } 2021