Print this page
6659 nvlist_free(NULL) is a no-op
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/cfgadm_plugins/sbd/common/ap_rcm.c
+++ new/usr/src/lib/cfgadm_plugins/sbd/common/ap_rcm.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 2008 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 26 #include <ctype.h>
27 27 #include <stdio.h>
28 28 #include <stdlib.h>
29 29 #include <stdarg.h>
30 30 #include <string.h>
31 31 #include <unistd.h>
32 32 #include <macros.h>
33 33 #include <errno.h>
34 34 #include <kstat.h>
35 35 #include <sys/kmem.h>
36 36 #include <dlfcn.h>
37 37 #include <libdevinfo.h>
38 38 #include <librcm.h>
39 39 #include <libintl.h>
40 40 #define CFGA_PLUGIN_LIB
41 41 #include <config_admin.h>
42 42 #include <sys/sbd_ioctl.h>
43 43 #include "ap.h"
44 44
45 45 typedef int32_t cpuid_t;
46 46
47 47 typedef struct {
48 48 int valid;
49 49 cfga_stat_t ostate;
50 50 int ncap;
51 51 union {
52 52 long npages;
53 53 cpuid_t cpuid[SBD_MAX_CORES_PER_CMP];
54 54 } type;
55 55 } cap_info_t;
56 56
57 57 typedef struct {
58 58 int firstcm; /* first component to operate on */
59 59 int lastcm; /* last component to operate on */
60 60 void *lib;
61 61 char **rlist;
62 62 cap_info_t *capinfo;
63 63 int ncpus; /* # of CPUs in cpuids list */
64 64 cpuid_t *cpuids; /* List of cpuids */
65 65 int capcpus; /* # of CPUs - tracking capacity */
66 66 int cappages; /* # of memory pages - tracking capacity */
67 67 rcm_handle_t *hd;
68 68 rcm_info_t *rinfo;
69 69 rcm_info_tuple_t *infot;
70 70 int (*alloc_handle)(char *, uint_t, void *, rcm_handle_t **);
71 71 void (*free_handle)(rcm_handle_t *);
72 72 int (*get_info)(rcm_handle_t *, char *, uint_t, rcm_info_t **);
73 73 void (*free_info)(rcm_info_t *);
74 74 rcm_info_tuple_t *(*info_next)(rcm_info_t *, rcm_info_tuple_t *);
75 75 int (*info_state)(rcm_info_tuple_t *);
76 76 pid_t (*info_pid)(rcm_info_tuple_t *);
77 77 const char *(*info_error)(rcm_info_tuple_t *);
78 78 const char *(*info_info)(rcm_info_tuple_t *);
79 79 const char *(*info_rsrc)(rcm_info_tuple_t *);
80 80 int (*request_offline_list)(rcm_handle_t *, char **, uint_t,
81 81 rcm_info_t **);
82 82 int (*notify_online_list)(rcm_handle_t *, char **, uint_t,
83 83 rcm_info_t **);
84 84 int (*request_suspend)(rcm_handle_t *, char *, uint_t, timespec_t *,
85 85 rcm_info_t **);
86 86 int (*notify_resume)(rcm_handle_t *, char *, uint_t, rcm_info_t **);
87 87 int (*notify_remove_list)(rcm_handle_t *, char **, uint_t,
88 88 rcm_info_t **);
89 89 int (*request_capacity_change)(rcm_handle_t *, char *, uint_t,
90 90 nvlist_t *, rcm_info_t **);
91 91 int (*notify_capacity_change)(rcm_handle_t *, char *, uint_t,
92 92 nvlist_t *, rcm_info_t **);
93 93 } rcmd_t;
94 94
95 95 static char *
96 96 ap_rcm_ops[] = {
97 97 "rcm_alloc_handle",
98 98 "rcm_free_handle",
99 99 "rcm_get_info",
100 100 "rcm_free_info",
101 101 "rcm_info_next",
102 102 "rcm_info_state",
103 103 "rcm_info_pid",
104 104 "rcm_info_error",
105 105 "rcm_info_info",
106 106 "rcm_info_rsrc",
107 107 "rcm_request_offline_list",
108 108 "rcm_notify_online_list",
109 109 "rcm_request_suspend",
110 110 "rcm_notify_resume",
111 111 "rcm_notify_remove_list",
112 112 "rcm_request_capacity_change",
113 113 "rcm_notify_capacity_change",
114 114 NULL
115 115 };
116 116
117 117 #define ALLOC_HANDLE 0
118 118 #define FREE_HANDLE 1
119 119 #define GET_INFO 2
120 120 #define FREE_INFO 3
121 121 #define INFO_TUPLE_NEXT 4
122 122 #define INFO_TUPLE_STATE 5
123 123 #define INFO_TUPLE_ID 6
124 124 #define INFO_TUPLE_ERROR 7
125 125 #define INFO_TUPLE_INFO 8
126 126 #define INFO_TUPLE_RSRC 9
127 127 #define REQUEST_OFFLINE 10
128 128 #define NOTIFY_ONLINE 11
129 129 #define REQUEST_SUSPEND 12
130 130 #define NOTIFY_RESUME 13
131 131 #define NOTIFY_REMOVE 14
132 132 #define REQUEST_CAP_CHANGE 15
133 133 #define NOTIFY_CAP_CHANGE 16
134 134
135 135 /*
136 136 * There is no consumer for SUNW_OS. This is defined here
137 137 * for generic OS quiescence.
138 138 */
139 139 #define OS "SUNW_OS" /* XXX */
140 140
141 141 /* Max width of an RCM formatted message line */
142 142 #define RCM_MAX_FORMAT 80
143 143
144 144 #ifdef __sparcv9
145 145 #define RCMLIB "/lib/sparcv9/librcm.so";
146 146 #elif defined(__amd64)
147 147 #define RCMLIB "/lib/amd64/librcm.so";
148 148 #else
149 149 #define RCMLIB "/lib/librcm.so";
150 150 #endif
151 151
152 152 static cfga_err_t
153 153 ap_capinfo(apd_t *a, int firstcm, int lastcm, cap_info_t **capinfo)
154 154 {
155 155 int cm;
156 156 int ncm;
157 157 void *cap;
158 158 int *ncap;
159 159 cfga_stat_t *os;
160 160 cap_info_t *cinfo, *cp;
161 161
162 162 DBG("ap_capinfo(%p)\n", (void *)a);
163 163
164 164 if (capinfo == NULL) {
165 165 ap_err(a, ERR_PLUGIN, "null capinfo");
166 166 return (CFGA_LIB_ERROR);
167 167 }
168 168
169 169 /*
170 170 * Assume there are components with valid capacity
171 171 * information and allocate space for them. If there
172 172 * are none at the end, free the allocated space.
173 173 */
174 174 ncm = lastcm - firstcm + 1;
175 175
176 176 cinfo = (cap_info_t *)calloc(ncm, sizeof (cap_info_t));
177 177 if (cinfo == NULL) {
178 178 ap_err(a, ERR_NOMEM);
179 179 return (CFGA_LIB_ERROR);
180 180 }
181 181
182 182 *capinfo = NULL;
183 183 ncm = 0;
184 184 for (cp = cinfo, cm = firstcm; cm <= lastcm; cm++, cp++) {
185 185 os = &cp->ostate;
186 186 ncap = &cp->ncap;
187 187
188 188 switch (ap_cm_type(a, cm)) {
189 189 case AP_CPU:
190 190 case AP_CMP:
191 191 cap = (void *)(cp->type.cpuid);
192 192 break;
193 193 case AP_MEM:
194 194 cap = (void *)&(cp->type.npages);
195 195 break;
196 196 default:
197 197 continue;
198 198 }
199 199 /*
200 200 * Remember which components have valid
201 201 * capacity information.
202 202 */
203 203 if (ap_cm_capacity(a, cm, cap, ncap, os)) {
204 204 cp->valid = 1;
205 205 ncm++;
206 206 }
207 207 }
208 208
209 209 if (ncm == 0)
210 210 free(cinfo);
211 211 else
212 212 *capinfo = cinfo;
213 213
214 214 return (CFGA_OK);
215 215 }
216 216
217 217 static int
218 218 getsyscpuids(int *ncpuids, cpuid_t **cpuids)
219 219 {
220 220 int ncpu;
221 221 int maxncpu;
222 222 kstat_t *ksp;
223 223 kstat_ctl_t *kc = NULL;
224 224 cpuid_t *cp;
225 225
226 226 DBG("getsyscpuids\n");
227 227
228 228 if ((maxncpu = sysconf(_SC_NPROCESSORS_MAX)) == -1 ||
229 229 (kc = kstat_open()) == NULL ||
230 230 (cp = (cpuid_t *)calloc(maxncpu, sizeof (cpuid_t))) == NULL) {
231 231 /* if calloc failed, clean up kstats */
232 232 if (kc != NULL) {
233 233 (void) kstat_close(kc);
234 234 }
235 235 return (-1);
236 236 }
237 237
238 238 DBG("syscpuids: ");
239 239 for (ncpu = 0, ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
240 240 if (strcmp(ksp->ks_module, "cpu_info") == 0) {
241 241 cp[ncpu++] = ksp->ks_instance;
242 242 DBG("%d ", ksp->ks_instance);
243 243 }
244 244 }
245 245 DBG("\n");
246 246
247 247 (void) kstat_close(kc);
248 248 *cpuids = cp;
249 249 *ncpuids = ncpu;
250 250 return (0);
251 251 }
252 252
253 253 cfga_err_t
254 254 ap_rcm_init(apd_t *a)
255 255 {
256 256 int i;
257 257 char *err;
258 258 char *rcmlib;
259 259 void *sym;
260 260 void *lib;
261 261 char **op;
262 262 rcmd_t *rcm;
263 263 cfga_err_t rc;
264 264 struct stat buf;
265 265
266 266 DBG("ap_rcm_init(%p)\n", (void *)a);
267 267
268 268 /*
269 269 * If the initial command is status, or the RCM feature is not
270 270 * available, or the RCM interface has already been initialized,
271 271 * just return.
272 272 */
273 273
274 274 if ((a->statonly != 0) || (a->norcm != 0) ||
275 275 ((rcm = (rcmd_t *)a->rcm) != NULL)) {
276 276 return (CFGA_OK);
277 277 }
278 278
279 279 rcmlib = RCMLIB;
280 280 rc = CFGA_LIB_ERROR;
281 281
282 282 DBG("Looking for %s\n", rcmlib);
283 283 /*
284 284 * If the library is not present, there is nothing more
285 285 * to do. The RCM offline/suspend steps become no-ops
286 286 * in that case.
287 287 */
288 288 if (stat(rcmlib, &buf) == -1) {
289 289 if (errno == ENOENT) {
290 290 a->norcm++;
291 291 ap_msg(a, MSG_NORCM);
292 292 return (CFGA_OK);
293 293 } else {
294 294 ap_err(a, ERR_STAT, rcmlib);
295 295 return (rc);
296 296 }
297 297 }
298 298 DBG("%s found\n", rcmlib);
299 299
300 300 if ((a->rcm = calloc(1, sizeof (rcmd_t))) == NULL) {
301 301 ap_err(a, ERR_NOMEM);
302 302 return (rc);
303 303 }
304 304
305 305 rcm = (rcmd_t *)a->rcm;
306 306
307 307 if ((lib = dlopen(rcmlib, RTLD_NOW)) == NULL) {
308 308 if ((err = dlerror()) != NULL)
309 309 err = strdup(err);
310 310 ap_err(a, ERR_LIB_OPEN, rcmlib, err);
311 311 if (err != NULL)
312 312 free(err);
313 313 return (rc);
314 314 }
315 315
316 316 rcm->lib = lib;
317 317
318 318 for (i = 0, op = ap_rcm_ops; *op != NULL; op++, i++) {
319 319 if ((sym = dlsym(lib, *op)) == NULL) {
320 320 ap_err(a, ERR_LIB_SYM, rcmlib, *op);
321 321 return (rc);
322 322 }
323 323 switch (i) {
324 324 case ALLOC_HANDLE:
325 325 rcm->alloc_handle = (int(*)
326 326 (char *, uint_t, void *, rcm_handle_t **))sym;
327 327 break;
328 328 case FREE_HANDLE:
329 329 rcm->free_handle = (void (*)(rcm_handle_t *))sym;
330 330 break;
331 331 case GET_INFO:
332 332 rcm->get_info = (int (*)
333 333 (rcm_handle_t *, char *, uint_t, rcm_info_t **))sym;
334 334 break;
335 335 case FREE_INFO:
336 336 rcm->free_info = (void (*)(rcm_info_t *))sym;
337 337 break;
338 338 case INFO_TUPLE_NEXT:
339 339 rcm->info_next = (rcm_info_tuple_t *(*)
340 340 (rcm_info_t *, rcm_info_tuple_t *))sym;
341 341 break;
342 342 case INFO_TUPLE_STATE:
343 343 rcm->info_state = (int (*)(rcm_info_tuple_t *))sym;
344 344 break;
345 345 case INFO_TUPLE_ID:
346 346 rcm->info_pid = (pid_t (*)(rcm_info_tuple_t *))sym;
347 347 break;
348 348 case INFO_TUPLE_ERROR:
349 349 rcm->info_error = (const char *(*)
350 350 (rcm_info_tuple_t *))sym;
351 351 break;
352 352 case INFO_TUPLE_INFO:
353 353 rcm->info_info = (const char *(*)
354 354 (rcm_info_tuple_t *))sym;
355 355 break;
356 356 case INFO_TUPLE_RSRC:
357 357 rcm->info_rsrc = (const char *(*)
358 358 (rcm_info_tuple_t *))sym;
359 359 break;
360 360 case REQUEST_OFFLINE:
361 361 rcm->request_offline_list = (int (*)
362 362 (rcm_handle_t *, char **, uint_t,
363 363 rcm_info_t **))sym;
364 364 break;
365 365 case NOTIFY_ONLINE:
366 366 rcm->notify_online_list = (int (*)
367 367 (rcm_handle_t *, char **, uint_t,
368 368 rcm_info_t **))sym;
369 369 break;
370 370 case REQUEST_SUSPEND:
371 371 rcm->request_suspend = (int (*)
372 372 (rcm_handle_t *, char *, uint_t,
373 373 timespec_t *, rcm_info_t **))sym;
374 374 break;
375 375 case NOTIFY_RESUME:
376 376 rcm->notify_resume = (int (*)
377 377 (rcm_handle_t *, char *, uint_t,
378 378 rcm_info_t **))sym;
379 379 break;
380 380 case NOTIFY_REMOVE:
381 381 rcm->notify_remove_list = (int (*)
382 382 (rcm_handle_t *, char **, uint_t,
383 383 rcm_info_t **))sym;
384 384 break;
385 385 case REQUEST_CAP_CHANGE:
386 386 rcm->request_capacity_change = (int (*)
387 387 (rcm_handle_t *, char *, uint_t,
388 388 nvlist_t *, rcm_info_t **))sym;
389 389 break;
390 390 case NOTIFY_CAP_CHANGE:
391 391 rcm->notify_capacity_change = (int (*)
392 392 (rcm_handle_t *, char *, uint_t,
393 393 nvlist_t *, rcm_info_t **))sym;
394 394 break;
395 395 default:
396 396 break;
397 397 }
398 398 }
399 399
400 400 if (rcm->alloc_handle == NULL ||
401 401 (*rcm->alloc_handle)(NULL, RCM_NOPID, NULL, &rcm->hd)
402 402 != RCM_SUCCESS) {
403 403 ap_err(a, ERR_RCM_HANDLE);
404 404 return (CFGA_LIB_ERROR);
405 405 }
406 406
407 407 /*
408 408 * Offlining/onlining a board means offlining/onlining
409 409 * all components on the board. When operating on a
410 410 * single component no component sequence number is
411 411 * needed since the default is the current (target)
412 412 * component.
413 413 */
414 414 if (a->tgt == AP_BOARD) {
415 415 rcm->firstcm = 0;
416 416 rcm->lastcm = a->ncm - 1;
417 417 } else {
418 418 rcm->firstcm = CM_DFLT;
419 419 rcm->lastcm = CM_DFLT;
420 420 }
421 421
422 422 if (rcm->cpuids == NULL) {
423 423 int cm;
424 424 int ncpu;
425 425
426 426 /*
427 427 * Allocate space for the cpu capacity change info.
428 428 * Not every cpu may be relevant to the capacity
429 429 * request, but allocating for the maximum makes
430 430 * it easier, and the space is insignifcant.
431 431 */
432 432 for (ncpu = 0, cm = rcm->firstcm; cm <= rcm->lastcm; cm++) {
433 433
434 434 ap_target_t type = ap_cm_type(a, cm);
435 435
436 436 if ((type == AP_CPU) || (type == AP_CMP)) {
437 437 ncpu += ap_cm_ncap(a, cm);
438 438 }
439 439 }
440 440
441 441 rcm->ncpus = ncpu;
442 442 if ((rcm->cpuids = (cpuid_t *)calloc(ncpu, sizeof (cpuid_t)))
443 443 == NULL) {
444 444 ap_err(a, ERR_NOMEM);
445 445 return (CFGA_LIB_ERROR);
446 446 }
447 447 }
448 448
449 449 /*
450 450 * Remember initial capacity information.
451 451 * This information is based on the initial
452 452 * state of the ap_id, i.e. before any
453 453 * state change change operations were
454 454 * executed. We will later get the
455 455 * current capacity information in order
456 456 * to figure out exactly what has changed
457 457 * as the result of the executed command
458 458 * sequence.
459 459 */
460 460 rc = ap_capinfo(a, rcm->firstcm, rcm->lastcm, &rcm->capinfo);
461 461
462 462 rcm->capcpus = sysconf(_SC_NPROCESSORS_CONF);
463 463 rcm->cappages = sysconf(_SC_PHYS_PAGES);
464 464
465 465 return (rc);
466 466 }
467 467
468 468 void
469 469 ap_rcm_fini(apd_t *a)
470 470 {
471 471 rcmd_t *rcm;
472 472 char **rp;
473 473
474 474 DBG("ap_rcm_fini(%p)\n", (void *)a);
475 475
476 476 if ((rcm = (rcmd_t *)a->rcm) == NULL)
477 477 return;
478 478
479 479 if (rcm->hd)
480 480 (*rcm->free_handle)(rcm->hd);
481 481
482 482 (void) dlclose(rcm->lib);
483 483
484 484 /*
485 485 * Free all the names in the resource list, followed
486 486 * by the resource list itself.
487 487 */
488 488 if (rcm->rlist)
489 489 for (rp = rcm->rlist; *rp; rp++)
490 490 s_free(*rp);
491 491 s_free(rcm->rlist);
492 492 s_free(rcm->cpuids);
493 493 s_free(rcm->capinfo);
494 494 s_free(a->rcm);
495 495 }
496 496
497 497 static cfga_err_t
498 498 ap_rcm_rlist(apd_t *a, int firstcm, int lastcm, char ***rlist, int cmd)
499 499 {
500 500 int n;
501 501 int cm;
502 502 int ncap;
503 503 char *path;
504 504 char *cpuname;
505 505 char **rp;
506 506
507 507 DBG("ap_rcm_rlist(%p)\n", (void *)a);
508 508
509 509 /*
510 510 * Allocate space for the maximum number of components
511 511 * that can be affected by this operation.
512 512 */
513 513 for (ncap = 0, cm = firstcm; cm <= lastcm; cm++) {
514 514 ncap += ap_cm_ncap(a, cm);
515 515 }
516 516
517 517 DBG("ncap=%d\n", ncap);
518 518
519 519 if ((rp = (char **)calloc(ncap + 1, sizeof (char *))) == NULL) {
520 520 ap_err(a, ERR_NOMEM);
521 521 return (CFGA_LIB_ERROR);
522 522 }
523 523
524 524 n = 12; /* SUNW_cpu/cpuCCC */
525 525 /* <--- 12 ---> */
526 526 cpuname = "SUNW_cpu/cpuCCC";
527 527 /*
528 528 * Set the RCM resource name for each component:
529 529 *
530 530 * io: <device-path>
531 531 * cpu: SUNW_cpu/cpu<cpuid>
532 532 *
533 533 */
534 534 for (ncap = 0, cm = firstcm; cm <= lastcm; cm++) {
535 535 switch (ap_cm_type(a, cm)) {
536 536 case AP_CPU:
537 537 case AP_CMP: {
538 538 int i;
539 539 int len;
540 540 cap_info_t cap;
541 541 cfga_stat_t os;
542 542 cpuid_t *cpuid;
543 543 int *nc;
544 544 cap_info_t *prevcap;
545 545 rcmd_t *rcm;
546 546 int allow_op;
547 547 int capindex;
548 548
549 549 cpuid = cap.type.cpuid;
550 550 nc = &cap.ncap;
551 551
552 552 /*
553 553 * See if the request target is a single
554 554 * (default) component
555 555 */
556 556 capindex = (cm == CM_DFLT) ? 0 : cm;
557 557
558 558 /* Get the previous capacity info */
559 559 rcm = (rcmd_t *)a->rcm;
560 560 prevcap = rcm->capinfo;
561 561
562 562 if (!ap_cm_capacity(a, cm, cpuid, nc, &os)) {
563 563 break;
564 564 }
565 565
566 566 len = (strlen(cpuname) - n) + 1;
567 567
568 568 /*
569 569 * For CMD_RCM_OFFLINE and REMOVE, add the CPU to the
570 570 * list if it is currently configured. For
571 571 * CMD_RCM_ONLINE, do so only if the state has changed
572 572 * to CFGA_STAT_CONFIGURED.
573 573 */
574 574 allow_op = 0;
575 575 if ((cmd == CMD_RCM_OFFLINE) ||
576 576 (cmd == CMD_RCM_REMOVE)) {
577 577 if (os == CFGA_STAT_CONFIGURED)
578 578 allow_op = 1;
579 579 } else {
580 580 if ((os == CFGA_STAT_CONFIGURED) &&
581 581 ((prevcap == NULL) ||
582 582 (prevcap[capindex].ostate != os)))
583 583 allow_op = 1;
584 584 }
585 585
586 586 if (allow_op) {
587 587 for (i = 0; i < *nc; i++) {
588 588 if ((path = strdup(cpuname)) == NULL) {
589 589 ap_err(a, ERR_NOMEM);
590 590 return (CFGA_LIB_ERROR);
591 591 }
592 592 (void) snprintf(&path[n], len, "%d",
593 593 cpuid[i]);
594 594
595 595 DBG("rp[%d]=%s\n", ncap, path);
596 596 rp[ncap++] = path;
597 597 }
598 598 }
599 599 break;
600 600 }
601 601 case AP_IO:
602 602 if ((path = ap_cm_devpath(a, cm)) != NULL) {
603 603 DBG("rp[%d]=%s\n", ncap, path);
604 604 rp[ncap++] = path;
605 605 }
606 606 break;
607 607 case AP_MEM:
608 608 /*
609 609 * Nothing to do for AP_MEM since only capacity
610 610 * change notifications apply to SUNW_memory
611 611 */
612 612 default:
613 613 break;
614 614 }
615 615 }
616 616
617 617 rp[ncap] = NULL;
618 618 if (rlist)
619 619 *rlist = rp;
620 620 return (CFGA_OK);
621 621 }
622 622
623 623 /*
624 624 * Returns 1 if the cpu ID 'cpuid' is in the list of CPU IDs
625 625 * 'list' of length 'length'. Returns 0 otherwise.
626 626 */
627 627 static int
628 628 is_cpu_in_list(cpuid_t cpuid, cpuid_t *list, int length)
629 629 {
630 630 int i;
631 631
632 632 DBG("is_cpu_in_list\n");
633 633
634 634 if (list == NULL)
635 635 return (0);
636 636
637 637 for (i = 0; i < length; i++) {
638 638 if (list[i] == cpuid)
639 639 return (1);
640 640 }
641 641 return (0);
642 642 }
643 643
644 644 static int
645 645 ap_rcm_cap_cpu(apd_t *a, rcmd_t *rcm, rcm_handle_t *hd, uint_t flags,
646 646 rcm_info_t **rinfo, int cmd, int change)
647 647 {
648 648 int i;
649 649 int rv = RCM_FAILURE;
650 650 int ncpuids;
651 651 int oldncpuids;
652 652 int newncpuids;
653 653 char buf[32];
654 654 const char *fmt;
655 655 size_t size;
656 656 nvlist_t *nvl = NULL;
657 657 cpuid_t *cpuids = NULL;
658 658 cpuid_t *oldcpuids = NULL;
659 659 cpuid_t *newcpuids = NULL;
660 660
661 661 DBG("ap_rcm_cap_cpu(%p)\n", (void *)a);
662 662
663 663 /*
664 664 * Get the current number of configured cpus.
665 665 */
666 666 if (getsyscpuids(&ncpuids, &cpuids) == -1)
667 667 return (rv);
668 668 else if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
669 669 free(cpuids);
670 670 goto done;
671 671 }
672 672
673 673 if (change == 1)
674 674 fmt = "(%d cpu)";
675 675 else
676 676 fmt = "(%d cpus)";
677 677
678 678 size = sizeof (cpuid_t);
679 679
680 680 if (cmd == CMD_RCM_CAP_DEL) {
681 681 /*
682 682 * A delete request. rcm->cpuids represents the
683 683 * cpus that will be unconfigured. The current
684 684 * set of cpus, before the unconfigure operation,
685 685 * are the old CPUs. The new CPUs are those
686 686 * that would remain.
687 687 */
688 688 oldncpuids = ncpuids;
689 689 oldcpuids = cpuids;
690 690
691 691 /*
692 692 * Fill newcpuids with the CPU IDs in the cpuids array,
693 693 * but not in rcm->cpuids.
694 694 */
695 695 newcpuids = (cpuid_t *)calloc(ncpuids, size);
696 696 if (newcpuids == NULL)
697 697 goto done;
698 698
699 699 newncpuids = 0;
700 700 for (i = 0; i < ncpuids; i++) {
701 701 if (!is_cpu_in_list(cpuids[i], rcm->cpuids, change))
702 702 newcpuids[newncpuids++] = cpuids[i];
703 703 }
704 704 } else if (cmd == CMD_RCM_CAP_NOTIFY) {
705 705 /*
706 706 * An unconfigure capacity change notification. This
707 707 * notification is sent after a DR unconfigure, whether
708 708 * or not the DR was successful. rcm->cpuids represents
709 709 * the CPUs that have been unconfigured.
710 710 */
711 711
712 712 /* New CPU IDs are the CPUs configured right now. */
713 713 newncpuids = ncpuids;
714 714 newcpuids = cpuids;
715 715
716 716 /*
717 717 * Old CPU IDs are the CPUs configured right now
718 718 * in addition to those that have been unconfigured.
719 719 * We build the old CPU ID list by concatenating
720 720 * cpuids and rcm->cpuids.
721 721 */
722 722 oldcpuids = (cpuid_t *)calloc(ncpuids + change, size);
723 723 if (oldcpuids == NULL)
724 724 goto done;
725 725
726 726 oldncpuids = 0;
727 727 for (i = 0; i < ncpuids; i++) {
728 728 if (!is_cpu_in_list(cpuids[i], rcm->cpuids, change))
729 729 oldcpuids[oldncpuids++] = cpuids[i];
730 730 }
731 731 for (i = 0; i < change; i++)
732 732 oldcpuids[oldncpuids++] = rcm->cpuids[i];
733 733 } else {
734 734 DBG("ap_rcm_cap_cpu: CPU capacity, old = %d, new = %d \n",
735 735 rcm->capcpus, ncpuids);
736 736 if (rcm->capcpus == ncpuids) {
737 737 /* No real change in CPU capacity */
738 738 rv = RCM_SUCCESS;
739 739 goto done;
740 740 }
741 741
742 742 /*
743 743 * An add notification. rcm->cpuids represents the
744 744 * cpus that have been configured. The current
745 745 * set of cpus, after the configure operation,
746 746 * are the new CPU IDs.
747 747 */
748 748 newncpuids = ncpuids;
749 749 newcpuids = cpuids;
750 750
751 751 /*
752 752 * Fill oldcpuids with the CPU IDs in the cpuids array,
753 753 * but not in rcm->cpuids.
754 754 */
755 755 oldcpuids = (cpuid_t *)calloc(ncpuids, size);
756 756 if (oldcpuids == NULL)
757 757 goto done;
758 758
759 759 oldncpuids = 0;
760 760 for (i = 0; i < ncpuids; i++) {
761 761 if (!is_cpu_in_list(cpuids[i], rcm->cpuids, change))
762 762 oldcpuids[oldncpuids++] = cpuids[i];
763 763 }
764 764 }
765 765
766 766 DBG("oldcpuids: ");
767 767 for (i = 0; i < oldncpuids; i++)
768 768 DBG("%d ", oldcpuids[i]);
769 769 DBG("\n");
770 770 DBG("change : ");
771 771 for (i = 0; i < change; i++)
772 772 DBG("%d ", rcm->cpuids[i]);
773 773 DBG("\n");
774 774 DBG("newcpuids: ");
775 775 for (i = 0; i < newncpuids; i++)
776 776 DBG("%d ", newcpuids[i]);
777 777 DBG("\n");
778 778
779 779 if (nvlist_add_string(nvl, "state", "capacity") != 0 ||
780 780 nvlist_add_int32(nvl, "old_total", oldncpuids) != 0 ||
781 781 nvlist_add_int32(nvl, "new_total", newncpuids) != 0 ||
782 782 nvlist_add_int32_array(nvl, "old_cpu_list", oldcpuids,
783 783 oldncpuids) != 0 ||
784 784 nvlist_add_int32_array(nvl, "new_cpu_list", newcpuids,
785 785 newncpuids) != 0)
786 786 goto done;
787 787
788 788 (void) snprintf(buf, sizeof (buf), fmt, change);
789 789 ap_msg(a, MSG_ISSUE, cmd, buf);
↓ open down ↓ |
789 lines elided |
↑ open up ↑ |
790 790
791 791 if (cmd == CMD_RCM_CAP_DEL) {
792 792 rv = (*rcm->request_capacity_change)(hd, "SUNW_cpu",
793 793 flags, nvl, rinfo);
794 794 } else {
795 795 rv = (*rcm->notify_capacity_change)(hd, "SUNW_cpu",
796 796 flags & ~RCM_FORCE, nvl, rinfo);
797 797 }
798 798
799 799 done:
800 - if (nvl)
801 - nvlist_free(nvl);
800 + nvlist_free(nvl);
802 801 s_free(oldcpuids);
803 802 s_free(newcpuids);
804 803 return (rv);
805 804 }
806 805
807 806 static int
808 807 ap_rcm_cap_mem(apd_t *a, rcmd_t *rcm, rcm_handle_t *hd, uint_t flags,
809 808 rcm_info_t **rinfo, int cmd, long change)
810 809 {
811 810 int rv;
812 811 int pgsize;
813 812 long oldpages;
814 813 long newpages;
815 814 long currpages;
816 815 char buf[32];
817 816 nvlist_t *nvl;
818 817
819 818 DBG("ap_rcm_cap_mem(%p)\n", (void *)a);
820 819
821 820 /*
822 821 * Get the current amount of configured memory.
823 822 */
824 823 if ((pgsize = sysconf(_SC_PAGE_SIZE)) == -1 ||
825 824 (currpages = sysconf(_SC_PHYS_PAGES)) == -1 ||
826 825 nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) > 0)
827 826 return (RCM_FAILURE);
828 827
829 828 /*
830 829 * If this is a (delete) request, change represents
831 830 * the amount of capacity that will be deleted from the
832 831 * system. If this is an (add) notification, change
833 832 * represents the amount of capacity that has already
834 833 * been added to the system.
835 834 */
836 835 if (cmd == CMD_RCM_CAP_DEL) {
837 836 oldpages = currpages;
838 837 newpages = currpages - change;
839 838 } else if (cmd == CMD_RCM_CAP_NOTIFY) {
840 839 newpages = currpages;
841 840 oldpages = rcm->cappages;
842 841 } else {
843 842 if (rcm->cappages == currpages) {
844 843 /* No real change in memory capacity */
845 844 DBG("ap_rcm_cap_mem: no change in capacity.\n");
846 845 nvlist_free(nvl);
847 846 return (RCM_SUCCESS);
848 847 }
849 848
850 849 oldpages = currpages - change;
851 850 newpages = currpages;
852 851 }
853 852
854 853 DBG("ap_rcm_cap_mem: Memory capacity, old = %ld, new = %ld\n",
855 854 oldpages, newpages);
856 855
857 856 if (nvlist_add_string(nvl, "state", "capacity") != 0 ||
858 857 nvlist_add_int32(nvl, "page_size", pgsize) != 0 ||
859 858 nvlist_add_int32(nvl, "old_pages", oldpages) != 0 ||
860 859 nvlist_add_int32(nvl, "new_pages", newpages) != 0) {
861 860 nvlist_free(nvl);
862 861 return (RCM_FAILURE);
863 862 }
864 863
865 864 (void) snprintf(buf, sizeof (buf), "(%ld pages)", change);
866 865 ap_msg(a, MSG_ISSUE, cmd, buf);
867 866
868 867 if (cmd == CMD_RCM_CAP_DEL) {
869 868 rv = (*rcm->request_capacity_change)(hd, "SUNW_memory",
870 869 flags, nvl, rinfo);
871 870 } else {
872 871 rv = (*rcm->notify_capacity_change)(hd, "SUNW_memory",
873 872 flags & ~RCM_FORCE, nvl, rinfo);
874 873 }
875 874
876 875 nvlist_free(nvl);
877 876
878 877 return (rv);
879 878 }
880 879
881 880 static cfga_err_t
882 881 ap_rcm_request_cap(apd_t *a, rcmd_t *rcm, rcm_handle_t *hd,
883 882 int *rv, uint_t flags, rcm_info_t **rinfo)
884 883 {
885 884 int cm;
886 885 int ncpus;
887 886 long npages;
888 887 cap_info_t *capinfo;
889 888 ap_target_t type;
890 889
891 890 DBG("ap_rcm_request_cap(%p)\n", (void *)a);
892 891
893 892 if ((capinfo = rcm->capinfo) == NULL) {
894 893 ap_err(a, ERR_PLUGIN, "null capinfo");
895 894 return (CFGA_LIB_ERROR);
896 895 }
897 896
898 897 ncpus = npages = 0;
899 898
900 899 for (cm = rcm->firstcm; cm <= rcm->lastcm; cm++) {
901 900 int i, j;
902 901
903 902 /*
904 903 * See if the request target is a single
905 904 * (default) component
906 905 */
907 906 i = (cm == CM_DFLT) ? 0 : cm;
908 907
909 908 /*
910 909 * We are interested only in those components
911 910 * in the configured state since they represent
912 911 * available capacity.
913 912 */
914 913 type = ap_cm_type(a, cm);
915 914 if (capinfo[i].valid == 0 ||
916 915 capinfo[i].ostate != CFGA_STAT_CONFIGURED)
917 916 continue;
918 917 else if ((type == AP_CPU) || (type == AP_CMP)) {
919 918 for (j = 0; j < capinfo[i].ncap; j++) {
920 919 rcm->cpuids[ncpus++] = capinfo[i].type.cpuid[j];
921 920 }
922 921 } else if (type == AP_MEM)
923 922 npages += capinfo[i].type.npages;
924 923 }
925 924
926 925 if (ncpus && ((*rv = ap_rcm_cap_cpu(a, rcm, hd, flags, rinfo,
927 926 CMD_RCM_CAP_DEL, ncpus)) != RCM_SUCCESS)) {
928 927 return (CFGA_LIB_ERROR);
929 928 }
930 929 if (npages && ((*rv = ap_rcm_cap_mem(a, rcm, hd, flags, rinfo,
931 930 CMD_RCM_CAP_DEL, npages)) != RCM_SUCCESS)) {
932 931 return (CFGA_LIB_ERROR);
933 932 }
934 933
935 934 return (CFGA_OK);
936 935 }
937 936
938 937 static cfga_err_t
939 938 ap_rcm_add_cap(apd_t *a, rcmd_t *rcm, rcm_handle_t *hd,
940 939 int *rv, uint_t flags, rcm_info_t **rinfo)
941 940 {
942 941 int cm;
943 942 int ncpus;
944 943 long npages;
945 944 cap_info_t *capinfo, *prevcapinfo;
946 945 cfga_err_t rc;
947 946
948 947 DBG("ap_rcm_add_cap(%p)\n", (void *)a);
949 948
950 949 /* Get the new capacity info to figure out what has changed */
951 950 if ((rc = ap_capinfo(a, rcm->firstcm, rcm->lastcm, &capinfo)) !=
952 951 CFGA_OK)
953 952 return (rc);
954 953
955 954 if (capinfo == NULL) {
956 955 DBG("no pertinent capacity info\n");
957 956 return (CFGA_OK);
958 957 }
959 958
960 959 ncpus = npages = 0;
961 960 prevcapinfo = rcm->capinfo;
962 961
963 962 for (cm = rcm->firstcm; cm <= rcm->lastcm; cm++) {
964 963 int i, j;
965 964 cfga_stat_t os, prevos;
966 965 int prevvalidity;
967 966 ap_target_t type;
968 967
969 968 /*
970 969 * See if the request target is a single
971 970 * (default) component
972 971 */
973 972 i = cm == CM_DFLT ? 0 : cm;
974 973
975 974 os = capinfo[i].ostate;
976 975 if (prevcapinfo == NULL) {
977 976 prevos = CFGA_STAT_EMPTY;
978 977 prevvalidity = 1;
979 978 } else {
980 979 prevos = prevcapinfo[i].ostate;
981 980 prevvalidity = prevcapinfo[i].valid;
982 981 }
983 982
984 983 type = ap_cm_type(a, cm);
985 984
986 985 DBG("cm=%d valid=%d type=%d, prevos=%d os=%d\n",
987 986 cm, prevvalidity, type, prevos, os);
988 987
989 988 /*
990 989 * We are interested only in those components
991 990 * whose states have changed to configured as
992 991 * the result of the current cfgadm request.
993 992 */
994 993 if (prevvalidity == 0 || os != CFGA_STAT_CONFIGURED) {
995 994 capinfo[i].valid = 0;
996 995 continue;
997 996 } else if (prevos != CFGA_STAT_CONFIGURED) {
998 997 /*
999 998 * The occupant state is configured, and
1000 999 * the previous occupant state was not.
1001 1000 */
1002 1001 if ((type == AP_CPU) || (type == AP_CMP)) {
1003 1002 for (j = 0; j < capinfo[i].ncap; j++) {
1004 1003 rcm->cpuids[ncpus++] =
1005 1004 capinfo[i].type.cpuid[j];
1006 1005 }
1007 1006 } else if (type == AP_MEM)
1008 1007 npages += capinfo[i].type.npages;
1009 1008 }
1010 1009 }
1011 1010 free(capinfo);
1012 1011
1013 1012 if (ncpus && ((*rv = ap_rcm_cap_cpu(a, rcm, hd, flags, rinfo,
1014 1013 CMD_RCM_CAP_ADD, ncpus)) != RCM_SUCCESS)) {
1015 1014 return (CFGA_LIB_ERROR);
1016 1015 }
1017 1016 if (npages && ((*rv = ap_rcm_cap_mem(a, rcm, hd, flags, rinfo,
1018 1017 CMD_RCM_CAP_ADD, npages)) != RCM_SUCCESS)) {
1019 1018 return (CFGA_LIB_ERROR);
1020 1019 }
1021 1020
1022 1021 return (CFGA_OK);
1023 1022 }
1024 1023
1025 1024 /*
1026 1025 * ap_rcm_notify_cap:
1027 1026 *
1028 1027 * This routine handles the CMD_RCM_CAP_NOTIFY command. It
1029 1028 * is called after a successful/failed DR unconfigure
1030 1029 * operation. It filters out components that have changed
1031 1030 * and passes this information on to ap_rcm_cap_{cpu,mem}.
1032 1031 *
1033 1032 * ap_rcm_cap_{cpu,mem} will still be called if all the
1034 1033 * components have not changed and at least one {cpu,mem}
1035 1034 * component was originally configured.
1036 1035 */
1037 1036 static cfga_err_t
1038 1037 ap_rcm_notify_cap(apd_t *a, rcmd_t *rcm, rcm_handle_t *hd,
1039 1038 int *rv, uint_t flags, rcm_info_t **rinfo)
1040 1039 {
1041 1040 cfga_err_t rc;
1042 1041 cap_info_t *capinfo;
1043 1042 cap_info_t *prevcapinfo;
1044 1043 int cm;
1045 1044 long npages = 0;
1046 1045 int ncpus = 0;
1047 1046 int prev_mem = 0; /* # of prev. configured mem components */
1048 1047 int prev_cpus = 0; /* # of prev. configured CPUs */
1049 1048
1050 1049 DBG("ap_rcm_notify_cap(%p)\n", (void *)a);
1051 1050
1052 1051 /* Get the new capacity info to figure out what has changed */
1053 1052 if ((rc = ap_capinfo(a, rcm->firstcm, rcm->lastcm, &capinfo)) !=
1054 1053 CFGA_OK)
1055 1054 return (rc);
1056 1055
1057 1056 if (capinfo == NULL) {
1058 1057 DBG("no pertinent capacity info\n");
1059 1058 return (CFGA_OK);
1060 1059 }
1061 1060
1062 1061 /* The original capacity info */
1063 1062 prevcapinfo = rcm->capinfo;
1064 1063
1065 1064 /*
1066 1065 * Cycle through all components that we are operating
1067 1066 * on. Record which components' occupant states have
1068 1067 * changed.
1069 1068 */
1070 1069 for (cm = rcm->firstcm; cm <= rcm->lastcm; cm++) {
1071 1070 int i;
1072 1071 cfga_stat_t prevos, os;
1073 1072 ap_target_t type;
1074 1073 int prev_conf = 0;
1075 1074 int now_conf = 0;
1076 1075
1077 1076 /*
1078 1077 * See if the request target is a single
1079 1078 * (default) component
1080 1079 */
1081 1080 i = cm == CM_DFLT ? 0 : cm;
1082 1081
1083 1082 os = capinfo[i].ostate;
1084 1083
1085 1084 if (prevcapinfo == NULL) {
1086 1085 prevos = CFGA_STAT_EMPTY;
1087 1086 } else {
1088 1087 prevos = prevcapinfo[i].ostate;
1089 1088 if (prevcapinfo[i].valid == 0) {
1090 1089 DBG("ap_rcm_notify_cap: skipping component "
1091 1090 "due to prevvalidity == 0\n");
1092 1091 continue;
1093 1092 }
1094 1093 }
1095 1094
1096 1095 type = ap_cm_type(a, cm);
1097 1096
1098 1097 prev_conf = (prevos == CFGA_STAT_CONFIGURED);
1099 1098 now_conf = (os == CFGA_STAT_CONFIGURED);
1100 1099
1101 1100 /*
1102 1101 * Build up rcm->cpuids with the IDs of CPUs that
1103 1102 * have been removed. Record the number of removed
1104 1103 * CPUs and pages.
1105 1104 */
1106 1105 if (type == AP_CPU || type == AP_CMP) {
1107 1106 if (prev_conf)
1108 1107 prev_cpus++;
1109 1108 if (prev_conf && !now_conf) {
1110 1109 int j;
1111 1110 for (j = 0; j < capinfo[i].ncap; j++) {
1112 1111 rcm->cpuids[ncpus++] =
1113 1112 capinfo[i].type.cpuid[j];
1114 1113 }
1115 1114 }
1116 1115 } else if (type == AP_MEM) {
1117 1116 if (prev_conf)
1118 1117 prev_mem++;
1119 1118 if (prev_conf && !now_conf)
1120 1119 npages += capinfo[i].type.npages;
1121 1120 }
1122 1121 }
1123 1122 free(capinfo);
1124 1123
1125 1124 /*
1126 1125 * If any CPU or memory components were operated on,
1127 1126 * successfully or not, the rcm_notify_capacity_change()
1128 1127 * routine must be called.
1129 1128 */
1130 1129
1131 1130 if (prev_cpus) {
1132 1131 *rv = ap_rcm_cap_cpu(a, rcm, hd, flags, rinfo,
1133 1132 CMD_RCM_CAP_NOTIFY, ncpus);
1134 1133
1135 1134 if (*rv != RCM_SUCCESS)
1136 1135 return (CFGA_LIB_ERROR);
1137 1136 }
1138 1137
1139 1138 if (prev_mem) {
1140 1139 *rv = ap_rcm_cap_mem(a, rcm, hd, flags, rinfo,
1141 1140 CMD_RCM_CAP_NOTIFY, npages);
1142 1141
1143 1142 if (*rv != RCM_SUCCESS)
1144 1143 return (CFGA_LIB_ERROR);
1145 1144 }
1146 1145
1147 1146 return (CFGA_OK);
1148 1147 }
1149 1148
1150 1149 cfga_err_t
1151 1150 ap_rcm_ctl(apd_t *a, int cmd)
1152 1151 {
1153 1152 int i;
1154 1153 int rv;
1155 1154 int noop;
1156 1155 int ncpus;
1157 1156 int cm;
1158 1157 uint_t flags;
1159 1158 char *rsrc;
1160 1159 char **rlist;
1161 1160 rcmd_t *rcm;
1162 1161 rcm_info_t *rinfo;
1163 1162 rcm_handle_t *hd;
1164 1163 cfga_err_t rc;
1165 1164 cpuid_t *growcpuids;
1166 1165
1167 1166 DBG("ap_rcm_ctl(%p)\n", (void *)a);
1168 1167
1169 1168 if ((rcm = (rcmd_t *)a->rcm) == NULL) {
1170 1169 ap_msg(a, MSG_SKIP, cmd, a->target);
1171 1170 return (CFGA_OK);
1172 1171 }
1173 1172
1174 1173 hd = rcm->hd;
1175 1174 rv = RCM_SUCCESS;
1176 1175 rc = CFGA_OK;
1177 1176 if (ap_getopt(a, OPT_FORCE))
1178 1177 flags = RCM_FORCE;
1179 1178 else
1180 1179 flags = 0;
1181 1180 rinfo = NULL;
1182 1181 rlist = NULL;
1183 1182 rsrc = NULL;
1184 1183 noop = 0;
1185 1184
1186 1185 switch (cmd) {
1187 1186 case CMD_RCM_CAP_DEL:
1188 1187 if (rcm->capinfo == NULL)
1189 1188 noop++;
1190 1189 else
1191 1190 rc = ap_rcm_request_cap(a, rcm, hd, &rv, flags, &rinfo);
1192 1191 break;
1193 1192 case CMD_RCM_CAP_ADD:
1194 1193 rc = ap_rcm_add_cap(a, rcm, hd, &rv, flags, &rinfo);
1195 1194 break;
1196 1195 case CMD_RCM_CAP_NOTIFY:
1197 1196 rc = ap_rcm_notify_cap(a, rcm, hd, &rv, flags, &rinfo);
1198 1197 break;
1199 1198 case CMD_RCM_ONLINE:
1200 1199 /* Refresh changed component states */
1201 1200 if ((rc = ap_stat(a, 1)) != CFGA_OK) {
1202 1201 noop++;
1203 1202 break;
1204 1203 }
1205 1204
1206 1205 if (a->tgt == AP_BOARD) {
1207 1206 rcm->firstcm = 0;
1208 1207 rcm->lastcm = a->ncm - 1;
1209 1208
1210 1209 /* Check if we need to grow our cpuids list */
1211 1210 for (ncpus = 0, cm = rcm->firstcm; cm <= rcm->lastcm;
1212 1211 cm++) {
1213 1212 ap_target_t type = ap_cm_type(a, cm);
1214 1213 if ((type == AP_CPU) || (type == AP_CMP))
1215 1214 ncpus += ap_cm_ncap(a, cm);
1216 1215 }
1217 1216
1218 1217 if (rcm->ncpus < ncpus) {
1219 1218 if ((growcpuids =
1220 1219 (cpuid_t *)realloc(rcm->cpuids,
1221 1220 (ncpus * sizeof (cpuid_t)))) == NULL) {
1222 1221 ap_err(a, ERR_NOMEM);
1223 1222 return (CFGA_LIB_ERROR);
1224 1223 }
1225 1224 rcm->ncpus = ncpus;
1226 1225 rcm->cpuids = growcpuids;
1227 1226 }
1228 1227
1229 1228 } else {
1230 1229 rcm->firstcm = CM_DFLT;
1231 1230 rcm->lastcm = CM_DFLT;
1232 1231 }
1233 1232
1234 1233 /*FALLTHROUGH*/
1235 1234
1236 1235 case CMD_RCM_OFFLINE:
1237 1236 case CMD_RCM_REMOVE: {
1238 1237 uint_t nrsrc;
1239 1238
1240 1239 if (cmd == CMD_RCM_REMOVE) {
1241 1240 /*
1242 1241 * An unconfigure has just taken place, so
1243 1242 * refresh the changed component states.
1244 1243 */
1245 1244 if ((rc = ap_stat(a, 1)) != CFGA_OK) {
1246 1245 noop++;
1247 1246 break;
1248 1247 }
1249 1248 }
1250 1249
1251 1250 /* Check if this is an empty board, i.e. no components */
1252 1251 if (a->ncm == 0) {
1253 1252 noop++;
1254 1253 break;
1255 1254 }
1256 1255
1257 1256 if ((rlist = rcm->rlist) == NULL) {
1258 1257 rc = ap_rcm_rlist(a, rcm->firstcm, rcm->lastcm, &rlist,
1259 1258 cmd);
1260 1259 if ((rc == CFGA_OK) && (rlist != NULL) &&
1261 1260 (rlist[0] != NULL)) {
1262 1261 rcm->rlist = rlist;
1263 1262 } else {
1264 1263 /* Do not pass up empty resource list to RCM */
1265 1264 noop++;
1266 1265 break;
1267 1266 }
1268 1267 }
1269 1268 for (nrsrc = 0; rlist[nrsrc] != NULL; nrsrc++)
1270 1269 ap_msg(a, MSG_ISSUE, cmd, rlist[nrsrc]);
1271 1270 if (cmd == CMD_RCM_OFFLINE)
1272 1271 rv = (*rcm->request_offline_list)(hd, rlist, flags,
1273 1272 &rinfo);
1274 1273 else if (cmd == CMD_RCM_ONLINE)
1275 1274 rv = (*rcm->notify_online_list)(hd, rlist,
1276 1275 flags & ~RCM_FORCE, &rinfo);
1277 1276 else
1278 1277 rv = (*rcm->notify_remove_list)(hd, rlist,
1279 1278 flags & ~RCM_FORCE, &rinfo);
1280 1279 break;
1281 1280 }
1282 1281 case CMD_RCM_SUSPEND: {
1283 1282 timespec_t t;
1284 1283 t.tv_sec = (time_t)0;
1285 1284 t.tv_nsec = (long)0;
1286 1285 rsrc = OS;
1287 1286 ap_msg(a, MSG_ISSUE, cmd, rsrc);
1288 1287 rv = (*rcm->request_suspend)(hd, rsrc, flags, &t, &rinfo);
1289 1288 break;
1290 1289 }
1291 1290 case CMD_RCM_RESUME:
1292 1291 rsrc = OS;
1293 1292 ap_msg(a, MSG_ISSUE, cmd, rsrc);
1294 1293 rv = (*rcm->notify_resume)(hd, rsrc, 0, &rinfo);
1295 1294 break;
1296 1295 default:
1297 1296 ap_err(a, ERR_CMD_INVAL, cmd);
1298 1297 return (CFGA_INVAL);
1299 1298 }
1300 1299
1301 1300 if (rv != RCM_SUCCESS) {
1302 1301 rcm->rinfo = rinfo;
1303 1302 rcm->infot = NULL;
1304 1303 ap_err(a, ERR_RCM_CMD, cmd);
1305 1304 (*rcm->free_info)(rinfo);
1306 1305 if (rc == CFGA_OK)
1307 1306 rc = CFGA_LIB_ERROR; /* make sure error is set */
1308 1307 }
1309 1308 if ((rc == CFGA_OK) && (noop == 0)) {
1310 1309 if (rlist)
1311 1310 for (i = 0; rlist[i]; i++)
1312 1311 ap_msg(a, MSG_DONE, cmd, rlist[i]);
1313 1312 else if (rsrc)
1314 1313 ap_msg(a, MSG_DONE, cmd, rsrc);
1315 1314 else
1316 1315 ap_msg(a, MSG_DONE, cmd, a->target);
1317 1316 }
1318 1317
1319 1318 return (rc);
1320 1319 }
1321 1320
1322 1321 /*
1323 1322 * ap_rcm_info
1324 1323 *
1325 1324 * Takes an ap_id and a character pointer, and formats
1326 1325 * the rcm_info_t data in the form of a table to the given character pointer.
1327 1326 * Code duplicated from the scsi plugin.
1328 1327 * Note: This function will go away when a generic librcm callback is
1329 1328 * implemented to format RCM messages for plugins.
1330 1329 */
1331 1330 int
1332 1331 ap_rcm_info(apd_t *a, char **msg)
1333 1332 {
1334 1333 rcmd_t *rcm;
1335 1334 rcm_info_t *rinfo;
1336 1335 int i;
1337 1336 size_t w;
1338 1337 size_t width = 0;
1339 1338 size_t w_rsrc = 0;
1340 1339 size_t w_info = 0;
1341 1340 size_t msg_size = 0;
1342 1341 uint_t tuples = 0;
1343 1342 rcm_info_tuple_t *tuple = NULL;
1344 1343 char *rsrc;
1345 1344 char *info;
1346 1345 char *newmsg;
1347 1346 static char format[RCM_MAX_FORMAT];
1348 1347 const char *infostr;
1349 1348
1350 1349
1351 1350 DBG("ap_rcm_info(%p)\n", (void *)a);
1352 1351
1353 1352 /* Protect against invalid arguments */
1354 1353 if ((a == NULL) || ((rcm = (rcmd_t *)a->rcm) == NULL) ||
1355 1354 ((rinfo = rcm->rinfo) == NULL) || (msg == NULL)) {
1356 1355 return (-1);
1357 1356 }
1358 1357
1359 1358 /* Set localized table header strings */
1360 1359 rsrc = dgettext(TEXT_DOMAIN, "Resource");
1361 1360 info = dgettext(TEXT_DOMAIN, "Information");
1362 1361
1363 1362 /* A first pass, to size up the RCM information */
1364 1363 while (tuple = (*rcm->info_next)(rinfo, tuple)) {
1365 1364 if ((infostr = (*rcm->info_info)(tuple)) != NULL) {
1366 1365 tuples++;
1367 1366 if ((w = strlen((*rcm->info_rsrc)(tuple))) > w_rsrc)
1368 1367 w_rsrc = w;
1369 1368 if ((w = strlen(infostr)) > w_info)
1370 1369 w_info = w;
1371 1370 }
1372 1371 }
1373 1372
1374 1373 /* If nothing was sized up above, stop early */
1375 1374 if (tuples == 0)
1376 1375 return (0);
1377 1376
1378 1377 /* Adjust column widths for column headings */
1379 1378 if ((w = strlen(rsrc)) > w_rsrc)
1380 1379 w_rsrc = w;
1381 1380 else if ((w_rsrc - w) % 2)
1382 1381 w_rsrc++;
1383 1382 if ((w = strlen(info)) > w_info)
1384 1383 w_info = w;
1385 1384 else if ((w_info - w) % 2)
1386 1385 w_info++;
1387 1386
1388 1387 /*
1389 1388 * Compute the total line width of each line,
1390 1389 * accounting for intercolumn spacing.
1391 1390 */
1392 1391 width = w_info + w_rsrc + 4;
1393 1392
1394 1393 /* Allocate space for the table */
1395 1394 msg_size = (2 + tuples) * (width + 1) + 2;
1396 1395 if (*msg == NULL) {
1397 1396 /* zero fill for the strcat() call below */
1398 1397 *msg = calloc(msg_size, sizeof (char));
1399 1398 if (*msg == NULL)
1400 1399 return (-1);
1401 1400 } else {
1402 1401 newmsg = realloc(*msg, strlen(*msg) + msg_size);
1403 1402 if (newmsg == NULL)
1404 1403 return (-1);
1405 1404 else
1406 1405 *msg = newmsg;
1407 1406 }
1408 1407
1409 1408 /* Place a table header into the string */
1410 1409
1411 1410 /* The resource header */
1412 1411 (void) strcat(*msg, "\n");
1413 1412 w = strlen(rsrc);
1414 1413 for (i = 0; i < ((w_rsrc - w) / 2); i++)
1415 1414 (void) strcat(*msg, " ");
1416 1415 (void) strcat(*msg, rsrc);
1417 1416 for (i = 0; i < ((w_rsrc - w) / 2); i++)
1418 1417 (void) strcat(*msg, " ");
1419 1418
1420 1419 /* The information header */
1421 1420 (void) strcat(*msg, " ");
1422 1421 w = strlen(info);
1423 1422 for (i = 0; i < ((w_info - w) / 2); i++)
1424 1423 (void) strcat(*msg, " ");
1425 1424 (void) strcat(*msg, info);
1426 1425 for (i = 0; i < ((w_info - w) / 2); i++)
1427 1426 (void) strcat(*msg, " ");
1428 1427
1429 1428 /* Underline the headers */
1430 1429 (void) strcat(*msg, "\n");
1431 1430 for (i = 0; i < w_rsrc; i++)
1432 1431 (void) strcat(*msg, "-");
1433 1432 (void) strcat(*msg, " ");
1434 1433 for (i = 0; i < w_info; i++)
1435 1434 (void) strcat(*msg, "-");
1436 1435
1437 1436 /* Construct the format string */
1438 1437 (void) snprintf(format, RCM_MAX_FORMAT, "%%-%ds %%-%ds",
1439 1438 (int)w_rsrc, (int)w_info);
1440 1439
1441 1440 /* Add the tuples to the table string */
1442 1441 tuple = NULL;
1443 1442 while ((tuple = (*rcm->info_next)(rinfo, tuple)) != NULL) {
1444 1443 if ((infostr = (*rcm->info_info)(tuple)) != NULL) {
1445 1444 (void) strcat(*msg, "\n");
1446 1445 (void) sprintf(&((*msg)[strlen(*msg)]), format,
1447 1446 (*rcm->info_rsrc)(tuple), infostr);
1448 1447 }
1449 1448 }
1450 1449
1451 1450 DBG("ap_rcm_info(%p) success\n", (void *)a);
1452 1451 return (0);
1453 1452 }
↓ open down ↓ |
642 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX