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