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