4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
37 #include <libdevinfo.h>
40 #define CFGA_PLUGIN_LIB
41 #include <config_admin.h>
42 #include <sys/sbd_ioctl.h>
45 typedef int32_t cpuid_t
;
53 cpuid_t cpuid
[SBD_MAX_CORES_PER_CMP
];
58 int firstcm
; /* first component to operate on */
59 int lastcm
; /* last component to operate on */
63 int ncpus
; /* # of CPUs in cpuids list */
64 cpuid_t
*cpuids
; /* List of cpuids */
65 int capcpus
; /* # of CPUs - tracking capacity */
66 int cappages
; /* # of memory pages - tracking capacity */
69 rcm_info_tuple_t
*infot
;
70 int (*alloc_handle
)(char *, uint_t
, void *, rcm_handle_t
**);
71 void (*free_handle
)(rcm_handle_t
*);
72 int (*get_info
)(rcm_handle_t
*, char *, uint_t
, rcm_info_t
**);
73 void (*free_info
)(rcm_info_t
*);
74 rcm_info_tuple_t
*(*info_next
)(rcm_info_t
*, rcm_info_tuple_t
*);
75 int (*info_state
)(rcm_info_tuple_t
*);
76 pid_t (*info_pid
)(rcm_info_tuple_t
*);
77 const char *(*info_error
)(rcm_info_tuple_t
*);
78 const char *(*info_info
)(rcm_info_tuple_t
*);
79 const char *(*info_rsrc
)(rcm_info_tuple_t
*);
80 int (*request_offline_list
)(rcm_handle_t
*, char **, uint_t
,
82 int (*notify_online_list
)(rcm_handle_t
*, char **, uint_t
,
84 int (*request_suspend
)(rcm_handle_t
*, char *, uint_t
, timespec_t
*,
86 int (*notify_resume
)(rcm_handle_t
*, char *, uint_t
, rcm_info_t
**);
87 int (*notify_remove_list
)(rcm_handle_t
*, char **, uint_t
,
89 int (*request_capacity_change
)(rcm_handle_t
*, char *, uint_t
,
90 nvlist_t
*, rcm_info_t
**);
91 int (*notify_capacity_change
)(rcm_handle_t
*, char *, uint_t
,
92 nvlist_t
*, rcm_info_t
**);
107 "rcm_request_offline_list",
108 "rcm_notify_online_list",
109 "rcm_request_suspend",
111 "rcm_notify_remove_list",
112 "rcm_request_capacity_change",
113 "rcm_notify_capacity_change",
117 #define ALLOC_HANDLE 0
118 #define FREE_HANDLE 1
121 #define INFO_TUPLE_NEXT 4
122 #define INFO_TUPLE_STATE 5
123 #define INFO_TUPLE_ID 6
124 #define INFO_TUPLE_ERROR 7
125 #define INFO_TUPLE_INFO 8
126 #define INFO_TUPLE_RSRC 9
127 #define REQUEST_OFFLINE 10
128 #define NOTIFY_ONLINE 11
129 #define REQUEST_SUSPEND 12
130 #define NOTIFY_RESUME 13
131 #define NOTIFY_REMOVE 14
132 #define REQUEST_CAP_CHANGE 15
133 #define NOTIFY_CAP_CHANGE 16
136 * There is no consumer for SUNW_OS. This is defined here
137 * for generic OS quiescence.
139 #define OS "SUNW_OS" /* XXX */
141 /* Max width of an RCM formatted message line */
142 #define RCM_MAX_FORMAT 80
145 #define RCMLIB "/lib/sparcv9/librcm.so";
146 #elif defined(__amd64)
147 #define RCMLIB "/lib/amd64/librcm.so";
149 #define RCMLIB "/lib/librcm.so";
153 ap_capinfo(apd_t
*a
, int firstcm
, int lastcm
, cap_info_t
**capinfo
)
160 cap_info_t
*cinfo
, *cp
;
162 DBG("ap_capinfo(%p)\n", (void *)a
);
164 if (capinfo
== NULL
) {
165 ap_err(a
, ERR_PLUGIN
, "null capinfo");
166 return (CFGA_LIB_ERROR
);
170 * Assume there are components with valid capacity
171 * information and allocate space for them. If there
172 * are none at the end, free the allocated space.
174 ncm
= lastcm
- firstcm
+ 1;
176 cinfo
= (cap_info_t
*)calloc(ncm
, sizeof (cap_info_t
));
178 ap_err(a
, ERR_NOMEM
);
179 return (CFGA_LIB_ERROR
);
184 for (cp
= cinfo
, cm
= firstcm
; cm
<= lastcm
; cm
++, cp
++) {
188 switch (ap_cm_type(a
, cm
)) {
191 cap
= (void *)(cp
->type
.cpuid
);
194 cap
= (void *)&(cp
->type
.npages
);
200 * Remember which components have valid
201 * capacity information.
203 if (ap_cm_capacity(a
, cm
, cap
, ncap
, os
)) {
218 getsyscpuids(int *ncpuids
, cpuid_t
**cpuids
)
223 kstat_ctl_t
*kc
= NULL
;
226 DBG("getsyscpuids\n");
228 if ((maxncpu
= sysconf(_SC_NPROCESSORS_MAX
)) == -1 ||
229 (kc
= kstat_open()) == NULL
||
230 (cp
= (cpuid_t
*)calloc(maxncpu
, sizeof (cpuid_t
))) == NULL
) {
231 /* if calloc failed, clean up kstats */
233 (void) kstat_close(kc
);
239 for (ncpu
= 0, ksp
= kc
->kc_chain
; ksp
!= NULL
; ksp
= ksp
->ks_next
) {
240 if (strcmp(ksp
->ks_module
, "cpu_info") == 0) {
241 cp
[ncpu
++] = ksp
->ks_instance
;
242 DBG("%d ", ksp
->ks_instance
);
247 (void) kstat_close(kc
);
254 ap_rcm_init(apd_t
*a
)
266 DBG("ap_rcm_init(%p)\n", (void *)a
);
269 * If the initial command is status, or the RCM feature is not
270 * available, or the RCM interface has already been initialized,
274 if ((a
->statonly
!= 0) || (a
->norcm
!= 0) ||
275 ((rcm
= (rcmd_t
*)a
->rcm
) != NULL
)) {
282 DBG("Looking for %s\n", rcmlib
);
284 * If the library is not present, there is nothing more
285 * to do. The RCM offline/suspend steps become no-ops
288 if (stat(rcmlib
, &buf
) == -1) {
289 if (errno
== ENOENT
) {
291 ap_msg(a
, MSG_NORCM
);
294 ap_err(a
, ERR_STAT
, rcmlib
);
298 DBG("%s found\n", rcmlib
);
300 if ((a
->rcm
= calloc(1, sizeof (rcmd_t
))) == NULL
) {
301 ap_err(a
, ERR_NOMEM
);
305 rcm
= (rcmd_t
*)a
->rcm
;
307 if ((lib
= dlopen(rcmlib
, RTLD_NOW
)) == NULL
) {
308 if ((err
= dlerror()) != NULL
)
310 ap_err(a
, ERR_LIB_OPEN
, rcmlib
, err
);
317 for (i
= 0, op
= ap_rcm_ops
; *op
!= NULL
; op
++, i
++) {
318 if ((sym
= dlsym(lib
, *op
)) == NULL
) {
319 ap_err(a
, ERR_LIB_SYM
, rcmlib
, *op
);
324 rcm
->alloc_handle
= (int(*)
325 (char *, uint_t
, void *, rcm_handle_t
**))sym
;
328 rcm
->free_handle
= (void (*)(rcm_handle_t
*))sym
;
331 rcm
->get_info
= (int (*)
332 (rcm_handle_t
*, char *, uint_t
, rcm_info_t
**))sym
;
335 rcm
->free_info
= (void (*)(rcm_info_t
*))sym
;
337 case INFO_TUPLE_NEXT
:
338 rcm
->info_next
= (rcm_info_tuple_t
*(*)
339 (rcm_info_t
*, rcm_info_tuple_t
*))sym
;
341 case INFO_TUPLE_STATE
:
342 rcm
->info_state
= (int (*)(rcm_info_tuple_t
*))sym
;
345 rcm
->info_pid
= (pid_t (*)(rcm_info_tuple_t
*))sym
;
347 case INFO_TUPLE_ERROR
:
348 rcm
->info_error
= (const char *(*)
349 (rcm_info_tuple_t
*))sym
;
351 case INFO_TUPLE_INFO
:
352 rcm
->info_info
= (const char *(*)
353 (rcm_info_tuple_t
*))sym
;
355 case INFO_TUPLE_RSRC
:
356 rcm
->info_rsrc
= (const char *(*)
357 (rcm_info_tuple_t
*))sym
;
359 case REQUEST_OFFLINE
:
360 rcm
->request_offline_list
= (int (*)
361 (rcm_handle_t
*, char **, uint_t
,
365 rcm
->notify_online_list
= (int (*)
366 (rcm_handle_t
*, char **, uint_t
,
369 case REQUEST_SUSPEND
:
370 rcm
->request_suspend
= (int (*)
371 (rcm_handle_t
*, char *, uint_t
,
372 timespec_t
*, rcm_info_t
**))sym
;
375 rcm
->notify_resume
= (int (*)
376 (rcm_handle_t
*, char *, uint_t
,
380 rcm
->notify_remove_list
= (int (*)
381 (rcm_handle_t
*, char **, uint_t
,
384 case REQUEST_CAP_CHANGE
:
385 rcm
->request_capacity_change
= (int (*)
386 (rcm_handle_t
*, char *, uint_t
,
387 nvlist_t
*, rcm_info_t
**))sym
;
389 case NOTIFY_CAP_CHANGE
:
390 rcm
->notify_capacity_change
= (int (*)
391 (rcm_handle_t
*, char *, uint_t
,
392 nvlist_t
*, rcm_info_t
**))sym
;
399 if (rcm
->alloc_handle
== NULL
||
400 (*rcm
->alloc_handle
)(NULL
, RCM_NOPID
, NULL
, &rcm
->hd
)
402 ap_err(a
, ERR_RCM_HANDLE
);
403 return (CFGA_LIB_ERROR
);
407 * Offlining/onlining a board means offlining/onlining
408 * all components on the board. When operating on a
409 * single component no component sequence number is
410 * needed since the default is the current (target)
413 if (a
->tgt
== AP_BOARD
) {
415 rcm
->lastcm
= a
->ncm
- 1;
417 rcm
->firstcm
= CM_DFLT
;
418 rcm
->lastcm
= CM_DFLT
;
421 if (rcm
->cpuids
== NULL
) {
426 * Allocate space for the cpu capacity change info.
427 * Not every cpu may be relevant to the capacity
428 * request, but allocating for the maximum makes
429 * it easier, and the space is insignifcant.
431 for (ncpu
= 0, cm
= rcm
->firstcm
; cm
<= rcm
->lastcm
; cm
++) {
433 ap_target_t type
= ap_cm_type(a
, cm
);
435 if ((type
== AP_CPU
) || (type
== AP_CMP
)) {
436 ncpu
+= ap_cm_ncap(a
, cm
);
441 if ((rcm
->cpuids
= (cpuid_t
*)calloc(ncpu
, sizeof (cpuid_t
)))
443 ap_err(a
, ERR_NOMEM
);
444 return (CFGA_LIB_ERROR
);
449 * Remember initial capacity information.
450 * This information is based on the initial
451 * state of the ap_id, i.e. before any
452 * state change change operations were
453 * executed. We will later get the
454 * current capacity information in order
455 * to figure out exactly what has changed
456 * as the result of the executed command
459 rc
= ap_capinfo(a
, rcm
->firstcm
, rcm
->lastcm
, &rcm
->capinfo
);
461 rcm
->capcpus
= sysconf(_SC_NPROCESSORS_CONF
);
462 rcm
->cappages
= sysconf(_SC_PHYS_PAGES
);
468 ap_rcm_fini(apd_t
*a
)
473 DBG("ap_rcm_fini(%p)\n", (void *)a
);
475 if ((rcm
= (rcmd_t
*)a
->rcm
) == NULL
)
479 (*rcm
->free_handle
)(rcm
->hd
);
481 (void) dlclose(rcm
->lib
);
484 * Free all the names in the resource list, followed
485 * by the resource list itself.
488 for (rp
= rcm
->rlist
; *rp
; rp
++)
492 s_free(rcm
->capinfo
);
497 ap_rcm_rlist(apd_t
*a
, int firstcm
, int lastcm
, char ***rlist
, int cmd
)
506 DBG("ap_rcm_rlist(%p)\n", (void *)a
);
509 * Allocate space for the maximum number of components
510 * that can be affected by this operation.
512 for (ncap
= 0, cm
= firstcm
; cm
<= lastcm
; cm
++) {
513 ncap
+= ap_cm_ncap(a
, cm
);
516 DBG("ncap=%d\n", ncap
);
518 if ((rp
= (char **)calloc(ncap
+ 1, sizeof (char *))) == NULL
) {
519 ap_err(a
, ERR_NOMEM
);
520 return (CFGA_LIB_ERROR
);
523 n
= 12; /* SUNW_cpu/cpuCCC */
525 cpuname
= "SUNW_cpu/cpuCCC";
527 * Set the RCM resource name for each component:
530 * cpu: SUNW_cpu/cpu<cpuid>
533 for (ncap
= 0, cm
= firstcm
; cm
<= lastcm
; cm
++) {
534 switch (ap_cm_type(a
, cm
)) {
548 cpuid
= cap
.type
.cpuid
;
552 * See if the request target is a single
553 * (default) component
555 capindex
= (cm
== CM_DFLT
) ? 0 : cm
;
557 /* Get the previous capacity info */
558 rcm
= (rcmd_t
*)a
->rcm
;
559 prevcap
= rcm
->capinfo
;
561 if (!ap_cm_capacity(a
, cm
, cpuid
, nc
, &os
)) {
565 len
= (strlen(cpuname
) - n
) + 1;
568 * For CMD_RCM_OFFLINE and REMOVE, add the CPU to the
569 * list if it is currently configured. For
570 * CMD_RCM_ONLINE, do so only if the state has changed
571 * to CFGA_STAT_CONFIGURED.
574 if ((cmd
== CMD_RCM_OFFLINE
) ||
575 (cmd
== CMD_RCM_REMOVE
)) {
576 if (os
== CFGA_STAT_CONFIGURED
)
579 if ((os
== CFGA_STAT_CONFIGURED
) &&
580 ((prevcap
== NULL
) ||
581 (prevcap
[capindex
].ostate
!= os
)))
586 for (i
= 0; i
< *nc
; i
++) {
587 if ((path
= strdup(cpuname
)) == NULL
) {
588 ap_err(a
, ERR_NOMEM
);
589 return (CFGA_LIB_ERROR
);
591 (void) snprintf(&path
[n
], len
, "%d",
594 DBG("rp[%d]=%s\n", ncap
, path
);
601 if ((path
= ap_cm_devpath(a
, cm
)) != NULL
) {
602 DBG("rp[%d]=%s\n", ncap
, path
);
608 * Nothing to do for AP_MEM since only capacity
609 * change notifications apply to SUNW_memory
623 * Returns 1 if the cpu ID 'cpuid' is in the list of CPU IDs
624 * 'list' of length 'length'. Returns 0 otherwise.
627 is_cpu_in_list(cpuid_t cpuid
, cpuid_t
*list
, int length
)
631 DBG("is_cpu_in_list\n");
636 for (i
= 0; i
< length
; i
++) {
637 if (list
[i
] == cpuid
)
644 ap_rcm_cap_cpu(apd_t
*a
, rcmd_t
*rcm
, rcm_handle_t
*hd
, uint_t flags
,
645 rcm_info_t
**rinfo
, int cmd
, int change
)
648 int rv
= RCM_FAILURE
;
655 nvlist_t
*nvl
= NULL
;
656 cpuid_t
*cpuids
= NULL
;
657 cpuid_t
*oldcpuids
= NULL
;
658 cpuid_t
*newcpuids
= NULL
;
660 DBG("ap_rcm_cap_cpu(%p)\n", (void *)a
);
663 * Get the current number of configured cpus.
665 if (getsyscpuids(&ncpuids
, &cpuids
) == -1)
667 else if (nvlist_alloc(&nvl
, NV_UNIQUE_NAME
, 0) != 0) {
677 size
= sizeof (cpuid_t
);
679 if (cmd
== CMD_RCM_CAP_DEL
) {
681 * A delete request. rcm->cpuids represents the
682 * cpus that will be unconfigured. The current
683 * set of cpus, before the unconfigure operation,
684 * are the old CPUs. The new CPUs are those
687 oldncpuids
= ncpuids
;
691 * Fill newcpuids with the CPU IDs in the cpuids array,
692 * but not in rcm->cpuids.
694 newcpuids
= (cpuid_t
*)calloc(ncpuids
, size
);
695 if (newcpuids
== NULL
)
699 for (i
= 0; i
< ncpuids
; i
++) {
700 if (!is_cpu_in_list(cpuids
[i
], rcm
->cpuids
, change
))
701 newcpuids
[newncpuids
++] = cpuids
[i
];
703 } else if (cmd
== CMD_RCM_CAP_NOTIFY
) {
705 * An unconfigure capacity change notification. This
706 * notification is sent after a DR unconfigure, whether
707 * or not the DR was successful. rcm->cpuids represents
708 * the CPUs that have been unconfigured.
711 /* New CPU IDs are the CPUs configured right now. */
712 newncpuids
= ncpuids
;
716 * Old CPU IDs are the CPUs configured right now
717 * in addition to those that have been unconfigured.
718 * We build the old CPU ID list by concatenating
719 * cpuids and rcm->cpuids.
721 oldcpuids
= (cpuid_t
*)calloc(ncpuids
+ change
, size
);
722 if (oldcpuids
== NULL
)
726 for (i
= 0; i
< ncpuids
; i
++) {
727 if (!is_cpu_in_list(cpuids
[i
], rcm
->cpuids
, change
))
728 oldcpuids
[oldncpuids
++] = cpuids
[i
];
730 for (i
= 0; i
< change
; i
++)
731 oldcpuids
[oldncpuids
++] = rcm
->cpuids
[i
];
733 DBG("ap_rcm_cap_cpu: CPU capacity, old = %d, new = %d \n",
734 rcm
->capcpus
, ncpuids
);
735 if (rcm
->capcpus
== ncpuids
) {
736 /* No real change in CPU capacity */
742 * An add notification. rcm->cpuids represents the
743 * cpus that have been configured. The current
744 * set of cpus, after the configure operation,
745 * are the new CPU IDs.
747 newncpuids
= ncpuids
;
751 * Fill oldcpuids with the CPU IDs in the cpuids array,
752 * but not in rcm->cpuids.
754 oldcpuids
= (cpuid_t
*)calloc(ncpuids
, size
);
755 if (oldcpuids
== NULL
)
759 for (i
= 0; i
< ncpuids
; i
++) {
760 if (!is_cpu_in_list(cpuids
[i
], rcm
->cpuids
, change
))
761 oldcpuids
[oldncpuids
++] = cpuids
[i
];
766 for (i
= 0; i
< oldncpuids
; i
++)
767 DBG("%d ", oldcpuids
[i
]);
770 for (i
= 0; i
< change
; i
++)
771 DBG("%d ", rcm
->cpuids
[i
]);
774 for (i
= 0; i
< newncpuids
; i
++)
775 DBG("%d ", newcpuids
[i
]);
778 if (nvlist_add_string(nvl
, "state", "capacity") != 0 ||
779 nvlist_add_int32(nvl
, "old_total", oldncpuids
) != 0 ||
780 nvlist_add_int32(nvl
, "new_total", newncpuids
) != 0 ||
781 nvlist_add_int32_array(nvl
, "old_cpu_list", oldcpuids
,
783 nvlist_add_int32_array(nvl
, "new_cpu_list", newcpuids
,
787 (void) snprintf(buf
, sizeof (buf
), fmt
, change
);
788 ap_msg(a
, MSG_ISSUE
, cmd
, buf
);
790 if (cmd
== CMD_RCM_CAP_DEL
) {
791 rv
= (*rcm
->request_capacity_change
)(hd
, "SUNW_cpu",
794 rv
= (*rcm
->notify_capacity_change
)(hd
, "SUNW_cpu",
795 flags
& ~RCM_FORCE
, nvl
, rinfo
);
806 ap_rcm_cap_mem(apd_t
*a
, rcmd_t
*rcm
, rcm_handle_t
*hd
, uint_t flags
,
807 rcm_info_t
**rinfo
, int cmd
, long change
)
817 DBG("ap_rcm_cap_mem(%p)\n", (void *)a
);
820 * Get the current amount of configured memory.
822 if ((pgsize
= sysconf(_SC_PAGE_SIZE
)) == -1 ||
823 (currpages
= sysconf(_SC_PHYS_PAGES
)) == -1 ||
824 nvlist_alloc(&nvl
, NV_UNIQUE_NAME
, 0) > 0)
825 return (RCM_FAILURE
);
828 * If this is a (delete) request, change represents
829 * the amount of capacity that will be deleted from the
830 * system. If this is an (add) notification, change
831 * represents the amount of capacity that has already
832 * been added to the system.
834 if (cmd
== CMD_RCM_CAP_DEL
) {
835 oldpages
= currpages
;
836 newpages
= currpages
- change
;
837 } else if (cmd
== CMD_RCM_CAP_NOTIFY
) {
838 newpages
= currpages
;
839 oldpages
= rcm
->cappages
;
841 if (rcm
->cappages
== currpages
) {
842 /* No real change in memory capacity */
843 DBG("ap_rcm_cap_mem: no change in capacity.\n");
845 return (RCM_SUCCESS
);
848 oldpages
= currpages
- change
;
849 newpages
= currpages
;
852 DBG("ap_rcm_cap_mem: Memory capacity, old = %ld, new = %ld\n",
855 if (nvlist_add_string(nvl
, "state", "capacity") != 0 ||
856 nvlist_add_int32(nvl
, "page_size", pgsize
) != 0 ||
857 nvlist_add_int32(nvl
, "old_pages", oldpages
) != 0 ||
858 nvlist_add_int32(nvl
, "new_pages", newpages
) != 0) {
860 return (RCM_FAILURE
);
863 (void) snprintf(buf
, sizeof (buf
), "(%ld pages)", change
);
864 ap_msg(a
, MSG_ISSUE
, cmd
, buf
);
866 if (cmd
== CMD_RCM_CAP_DEL
) {
867 rv
= (*rcm
->request_capacity_change
)(hd
, "SUNW_memory",
870 rv
= (*rcm
->notify_capacity_change
)(hd
, "SUNW_memory",
871 flags
& ~RCM_FORCE
, nvl
, rinfo
);
880 ap_rcm_request_cap(apd_t
*a
, rcmd_t
*rcm
, rcm_handle_t
*hd
,
881 int *rv
, uint_t flags
, rcm_info_t
**rinfo
)
889 DBG("ap_rcm_request_cap(%p)\n", (void *)a
);
891 if ((capinfo
= rcm
->capinfo
) == NULL
) {
892 ap_err(a
, ERR_PLUGIN
, "null capinfo");
893 return (CFGA_LIB_ERROR
);
898 for (cm
= rcm
->firstcm
; cm
<= rcm
->lastcm
; cm
++) {
902 * See if the request target is a single
903 * (default) component
905 i
= (cm
== CM_DFLT
) ? 0 : cm
;
908 * We are interested only in those components
909 * in the configured state since they represent
910 * available capacity.
912 type
= ap_cm_type(a
, cm
);
913 if (capinfo
[i
].valid
== 0 ||
914 capinfo
[i
].ostate
!= CFGA_STAT_CONFIGURED
)
916 else if ((type
== AP_CPU
) || (type
== AP_CMP
)) {
917 for (j
= 0; j
< capinfo
[i
].ncap
; j
++) {
918 rcm
->cpuids
[ncpus
++] = capinfo
[i
].type
.cpuid
[j
];
920 } else if (type
== AP_MEM
)
921 npages
+= capinfo
[i
].type
.npages
;
924 if (ncpus
&& ((*rv
= ap_rcm_cap_cpu(a
, rcm
, hd
, flags
, rinfo
,
925 CMD_RCM_CAP_DEL
, ncpus
)) != RCM_SUCCESS
)) {
926 return (CFGA_LIB_ERROR
);
928 if (npages
&& ((*rv
= ap_rcm_cap_mem(a
, rcm
, hd
, flags
, rinfo
,
929 CMD_RCM_CAP_DEL
, npages
)) != RCM_SUCCESS
)) {
930 return (CFGA_LIB_ERROR
);
937 ap_rcm_add_cap(apd_t
*a
, rcmd_t
*rcm
, rcm_handle_t
*hd
,
938 int *rv
, uint_t flags
, rcm_info_t
**rinfo
)
943 cap_info_t
*capinfo
, *prevcapinfo
;
946 DBG("ap_rcm_add_cap(%p)\n", (void *)a
);
948 /* Get the new capacity info to figure out what has changed */
949 if ((rc
= ap_capinfo(a
, rcm
->firstcm
, rcm
->lastcm
, &capinfo
)) !=
953 if (capinfo
== NULL
) {
954 DBG("no pertinent capacity info\n");
959 prevcapinfo
= rcm
->capinfo
;
961 for (cm
= rcm
->firstcm
; cm
<= rcm
->lastcm
; cm
++) {
963 cfga_stat_t os
, prevos
;
968 * See if the request target is a single
969 * (default) component
971 i
= cm
== CM_DFLT
? 0 : cm
;
973 os
= capinfo
[i
].ostate
;
974 if (prevcapinfo
== NULL
) {
975 prevos
= CFGA_STAT_EMPTY
;
978 prevos
= prevcapinfo
[i
].ostate
;
979 prevvalidity
= prevcapinfo
[i
].valid
;
982 type
= ap_cm_type(a
, cm
);
984 DBG("cm=%d valid=%d type=%d, prevos=%d os=%d\n",
985 cm
, prevvalidity
, type
, prevos
, os
);
988 * We are interested only in those components
989 * whose states have changed to configured as
990 * the result of the current cfgadm request.
992 if (prevvalidity
== 0 || os
!= CFGA_STAT_CONFIGURED
) {
993 capinfo
[i
].valid
= 0;
995 } else if (prevos
!= CFGA_STAT_CONFIGURED
) {
997 * The occupant state is configured, and
998 * the previous occupant state was not.
1000 if ((type
== AP_CPU
) || (type
== AP_CMP
)) {
1001 for (j
= 0; j
< capinfo
[i
].ncap
; j
++) {
1002 rcm
->cpuids
[ncpus
++] =
1003 capinfo
[i
].type
.cpuid
[j
];
1005 } else if (type
== AP_MEM
)
1006 npages
+= capinfo
[i
].type
.npages
;
1011 if (ncpus
&& ((*rv
= ap_rcm_cap_cpu(a
, rcm
, hd
, flags
, rinfo
,
1012 CMD_RCM_CAP_ADD
, ncpus
)) != RCM_SUCCESS
)) {
1013 return (CFGA_LIB_ERROR
);
1015 if (npages
&& ((*rv
= ap_rcm_cap_mem(a
, rcm
, hd
, flags
, rinfo
,
1016 CMD_RCM_CAP_ADD
, npages
)) != RCM_SUCCESS
)) {
1017 return (CFGA_LIB_ERROR
);
1024 * ap_rcm_notify_cap:
1026 * This routine handles the CMD_RCM_CAP_NOTIFY command. It
1027 * is called after a successful/failed DR unconfigure
1028 * operation. It filters out components that have changed
1029 * and passes this information on to ap_rcm_cap_{cpu,mem}.
1031 * ap_rcm_cap_{cpu,mem} will still be called if all the
1032 * components have not changed and at least one {cpu,mem}
1033 * component was originally configured.
1036 ap_rcm_notify_cap(apd_t
*a
, rcmd_t
*rcm
, rcm_handle_t
*hd
,
1037 int *rv
, uint_t flags
, rcm_info_t
**rinfo
)
1040 cap_info_t
*capinfo
;
1041 cap_info_t
*prevcapinfo
;
1045 int prev_mem
= 0; /* # of prev. configured mem components */
1046 int prev_cpus
= 0; /* # of prev. configured CPUs */
1048 DBG("ap_rcm_notify_cap(%p)\n", (void *)a
);
1050 /* Get the new capacity info to figure out what has changed */
1051 if ((rc
= ap_capinfo(a
, rcm
->firstcm
, rcm
->lastcm
, &capinfo
)) !=
1055 if (capinfo
== NULL
) {
1056 DBG("no pertinent capacity info\n");
1060 /* The original capacity info */
1061 prevcapinfo
= rcm
->capinfo
;
1064 * Cycle through all components that we are operating
1065 * on. Record which components' occupant states have
1068 for (cm
= rcm
->firstcm
; cm
<= rcm
->lastcm
; cm
++) {
1070 cfga_stat_t prevos
, os
;
1076 * See if the request target is a single
1077 * (default) component
1079 i
= cm
== CM_DFLT
? 0 : cm
;
1081 os
= capinfo
[i
].ostate
;
1083 if (prevcapinfo
== NULL
) {
1084 prevos
= CFGA_STAT_EMPTY
;
1086 prevos
= prevcapinfo
[i
].ostate
;
1087 if (prevcapinfo
[i
].valid
== 0) {
1088 DBG("ap_rcm_notify_cap: skipping component "
1089 "due to prevvalidity == 0\n");
1094 type
= ap_cm_type(a
, cm
);
1096 prev_conf
= (prevos
== CFGA_STAT_CONFIGURED
);
1097 now_conf
= (os
== CFGA_STAT_CONFIGURED
);
1100 * Build up rcm->cpuids with the IDs of CPUs that
1101 * have been removed. Record the number of removed
1104 if (type
== AP_CPU
|| type
== AP_CMP
) {
1107 if (prev_conf
&& !now_conf
) {
1109 for (j
= 0; j
< capinfo
[i
].ncap
; j
++) {
1110 rcm
->cpuids
[ncpus
++] =
1111 capinfo
[i
].type
.cpuid
[j
];
1114 } else if (type
== AP_MEM
) {
1117 if (prev_conf
&& !now_conf
)
1118 npages
+= capinfo
[i
].type
.npages
;
1124 * If any CPU or memory components were operated on,
1125 * successfully or not, the rcm_notify_capacity_change()
1126 * routine must be called.
1130 *rv
= ap_rcm_cap_cpu(a
, rcm
, hd
, flags
, rinfo
,
1131 CMD_RCM_CAP_NOTIFY
, ncpus
);
1133 if (*rv
!= RCM_SUCCESS
)
1134 return (CFGA_LIB_ERROR
);
1138 *rv
= ap_rcm_cap_mem(a
, rcm
, hd
, flags
, rinfo
,
1139 CMD_RCM_CAP_NOTIFY
, npages
);
1141 if (*rv
!= RCM_SUCCESS
)
1142 return (CFGA_LIB_ERROR
);
1149 ap_rcm_ctl(apd_t
*a
, int cmd
)
1163 cpuid_t
*growcpuids
;
1165 DBG("ap_rcm_ctl(%p)\n", (void *)a
);
1167 if ((rcm
= (rcmd_t
*)a
->rcm
) == NULL
) {
1168 ap_msg(a
, MSG_SKIP
, cmd
, a
->target
);
1175 if (ap_getopt(a
, OPT_FORCE
))
1185 case CMD_RCM_CAP_DEL
:
1186 if (rcm
->capinfo
== NULL
)
1189 rc
= ap_rcm_request_cap(a
, rcm
, hd
, &rv
, flags
, &rinfo
);
1191 case CMD_RCM_CAP_ADD
:
1192 rc
= ap_rcm_add_cap(a
, rcm
, hd
, &rv
, flags
, &rinfo
);
1194 case CMD_RCM_CAP_NOTIFY
:
1195 rc
= ap_rcm_notify_cap(a
, rcm
, hd
, &rv
, flags
, &rinfo
);
1197 case CMD_RCM_ONLINE
:
1198 /* Refresh changed component states */
1199 if ((rc
= ap_stat(a
, 1)) != CFGA_OK
) {
1204 if (a
->tgt
== AP_BOARD
) {
1206 rcm
->lastcm
= a
->ncm
- 1;
1208 /* Check if we need to grow our cpuids list */
1209 for (ncpus
= 0, cm
= rcm
->firstcm
; cm
<= rcm
->lastcm
;
1211 ap_target_t type
= ap_cm_type(a
, cm
);
1212 if ((type
== AP_CPU
) || (type
== AP_CMP
))
1213 ncpus
+= ap_cm_ncap(a
, cm
);
1216 if (rcm
->ncpus
< ncpus
) {
1218 (cpuid_t
*)realloc(rcm
->cpuids
,
1219 (ncpus
* sizeof (cpuid_t
)))) == NULL
) {
1220 ap_err(a
, ERR_NOMEM
);
1221 return (CFGA_LIB_ERROR
);
1224 rcm
->cpuids
= growcpuids
;
1228 rcm
->firstcm
= CM_DFLT
;
1229 rcm
->lastcm
= CM_DFLT
;
1234 case CMD_RCM_OFFLINE
:
1235 case CMD_RCM_REMOVE
: {
1238 if (cmd
== CMD_RCM_REMOVE
) {
1240 * An unconfigure has just taken place, so
1241 * refresh the changed component states.
1243 if ((rc
= ap_stat(a
, 1)) != CFGA_OK
) {
1249 /* Check if this is an empty board, i.e. no components */
1255 if ((rlist
= rcm
->rlist
) == NULL
) {
1256 rc
= ap_rcm_rlist(a
, rcm
->firstcm
, rcm
->lastcm
, &rlist
,
1258 if ((rc
== CFGA_OK
) && (rlist
!= NULL
) &&
1259 (rlist
[0] != NULL
)) {
1262 /* Do not pass up empty resource list to RCM */
1267 for (nrsrc
= 0; rlist
[nrsrc
] != NULL
; nrsrc
++)
1268 ap_msg(a
, MSG_ISSUE
, cmd
, rlist
[nrsrc
]);
1269 if (cmd
== CMD_RCM_OFFLINE
)
1270 rv
= (*rcm
->request_offline_list
)(hd
, rlist
, flags
,
1272 else if (cmd
== CMD_RCM_ONLINE
)
1273 rv
= (*rcm
->notify_online_list
)(hd
, rlist
,
1274 flags
& ~RCM_FORCE
, &rinfo
);
1276 rv
= (*rcm
->notify_remove_list
)(hd
, rlist
,
1277 flags
& ~RCM_FORCE
, &rinfo
);
1280 case CMD_RCM_SUSPEND
: {
1282 t
.tv_sec
= (time_t)0;
1283 t
.tv_nsec
= (long)0;
1285 ap_msg(a
, MSG_ISSUE
, cmd
, rsrc
);
1286 rv
= (*rcm
->request_suspend
)(hd
, rsrc
, flags
, &t
, &rinfo
);
1289 case CMD_RCM_RESUME
:
1291 ap_msg(a
, MSG_ISSUE
, cmd
, rsrc
);
1292 rv
= (*rcm
->notify_resume
)(hd
, rsrc
, 0, &rinfo
);
1295 ap_err(a
, ERR_CMD_INVAL
, cmd
);
1296 return (CFGA_INVAL
);
1299 if (rv
!= RCM_SUCCESS
) {
1302 ap_err(a
, ERR_RCM_CMD
, cmd
);
1303 (*rcm
->free_info
)(rinfo
);
1305 rc
= CFGA_LIB_ERROR
; /* make sure error is set */
1307 if ((rc
== CFGA_OK
) && (noop
== 0)) {
1309 for (i
= 0; rlist
[i
]; i
++)
1310 ap_msg(a
, MSG_DONE
, cmd
, rlist
[i
]);
1312 ap_msg(a
, MSG_DONE
, cmd
, rsrc
);
1314 ap_msg(a
, MSG_DONE
, cmd
, a
->target
);
1323 * Takes an ap_id and a character pointer, and formats
1324 * the rcm_info_t data in the form of a table to the given character pointer.
1325 * Code duplicated from the scsi plugin.
1326 * Note: This function will go away when a generic librcm callback is
1327 * implemented to format RCM messages for plugins.
1330 ap_rcm_info(apd_t
*a
, char **msg
)
1339 size_t msg_size
= 0;
1341 rcm_info_tuple_t
*tuple
= NULL
;
1345 static char format
[RCM_MAX_FORMAT
];
1346 const char *infostr
;
1349 DBG("ap_rcm_info(%p)\n", (void *)a
);
1351 /* Protect against invalid arguments */
1352 if ((a
== NULL
) || ((rcm
= (rcmd_t
*)a
->rcm
) == NULL
) ||
1353 ((rinfo
= rcm
->rinfo
) == NULL
) || (msg
== NULL
)) {
1357 /* Set localized table header strings */
1358 rsrc
= dgettext(TEXT_DOMAIN
, "Resource");
1359 info
= dgettext(TEXT_DOMAIN
, "Information");
1361 /* A first pass, to size up the RCM information */
1362 while (tuple
= (*rcm
->info_next
)(rinfo
, tuple
)) {
1363 if ((infostr
= (*rcm
->info_info
)(tuple
)) != NULL
) {
1365 if ((w
= strlen((*rcm
->info_rsrc
)(tuple
))) > w_rsrc
)
1367 if ((w
= strlen(infostr
)) > w_info
)
1372 /* If nothing was sized up above, stop early */
1376 /* Adjust column widths for column headings */
1377 if ((w
= strlen(rsrc
)) > w_rsrc
)
1379 else if ((w_rsrc
- w
) % 2)
1381 if ((w
= strlen(info
)) > w_info
)
1383 else if ((w_info
- w
) % 2)
1387 * Compute the total line width of each line,
1388 * accounting for intercolumn spacing.
1390 width
= w_info
+ w_rsrc
+ 4;
1392 /* Allocate space for the table */
1393 msg_size
= (2 + tuples
) * (width
+ 1) + 2;
1395 /* zero fill for the strcat() call below */
1396 *msg
= calloc(msg_size
, sizeof (char));
1400 newmsg
= realloc(*msg
, strlen(*msg
) + msg_size
);
1407 /* Place a table header into the string */
1409 /* The resource header */
1410 (void) strcat(*msg
, "\n");
1412 for (i
= 0; i
< ((w_rsrc
- w
) / 2); i
++)
1413 (void) strcat(*msg
, " ");
1414 (void) strcat(*msg
, rsrc
);
1415 for (i
= 0; i
< ((w_rsrc
- w
) / 2); i
++)
1416 (void) strcat(*msg
, " ");
1418 /* The information header */
1419 (void) strcat(*msg
, " ");
1421 for (i
= 0; i
< ((w_info
- w
) / 2); i
++)
1422 (void) strcat(*msg
, " ");
1423 (void) strcat(*msg
, info
);
1424 for (i
= 0; i
< ((w_info
- w
) / 2); i
++)
1425 (void) strcat(*msg
, " ");
1427 /* Underline the headers */
1428 (void) strcat(*msg
, "\n");
1429 for (i
= 0; i
< w_rsrc
; i
++)
1430 (void) strcat(*msg
, "-");
1431 (void) strcat(*msg
, " ");
1432 for (i
= 0; i
< w_info
; i
++)
1433 (void) strcat(*msg
, "-");
1435 /* Construct the format string */
1436 (void) snprintf(format
, RCM_MAX_FORMAT
, "%%-%ds %%-%ds",
1437 (int)w_rsrc
, (int)w_info
);
1439 /* Add the tuples to the table string */
1441 while ((tuple
= (*rcm
->info_next
)(rinfo
, tuple
)) != NULL
) {
1442 if ((infostr
= (*rcm
->info_info
)(tuple
)) != NULL
) {
1443 (void) strcat(*msg
, "\n");
1444 (void) sprintf(&((*msg
)[strlen(*msg
)]), format
,
1445 (*rcm
->info_rsrc
)(tuple
), infostr
);
1449 DBG("ap_rcm_info(%p) success\n", (void *)a
);