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
);
318 for (i
= 0, op
= ap_rcm_ops
; *op
!= NULL
; op
++, i
++) {
319 if ((sym
= dlsym(lib
, *op
)) == NULL
) {
320 ap_err(a
, ERR_LIB_SYM
, rcmlib
, *op
);
325 rcm
->alloc_handle
= (int(*)
326 (char *, uint_t
, void *, rcm_handle_t
**))sym
;
329 rcm
->free_handle
= (void (*)(rcm_handle_t
*))sym
;
332 rcm
->get_info
= (int (*)
333 (rcm_handle_t
*, char *, uint_t
, rcm_info_t
**))sym
;
336 rcm
->free_info
= (void (*)(rcm_info_t
*))sym
;
338 case INFO_TUPLE_NEXT
:
339 rcm
->info_next
= (rcm_info_tuple_t
*(*)
340 (rcm_info_t
*, rcm_info_tuple_t
*))sym
;
342 case INFO_TUPLE_STATE
:
343 rcm
->info_state
= (int (*)(rcm_info_tuple_t
*))sym
;
346 rcm
->info_pid
= (pid_t (*)(rcm_info_tuple_t
*))sym
;
348 case INFO_TUPLE_ERROR
:
349 rcm
->info_error
= (const char *(*)
350 (rcm_info_tuple_t
*))sym
;
352 case INFO_TUPLE_INFO
:
353 rcm
->info_info
= (const char *(*)
354 (rcm_info_tuple_t
*))sym
;
356 case INFO_TUPLE_RSRC
:
357 rcm
->info_rsrc
= (const char *(*)
358 (rcm_info_tuple_t
*))sym
;
360 case REQUEST_OFFLINE
:
361 rcm
->request_offline_list
= (int (*)
362 (rcm_handle_t
*, char **, uint_t
,
366 rcm
->notify_online_list
= (int (*)
367 (rcm_handle_t
*, char **, uint_t
,
370 case REQUEST_SUSPEND
:
371 rcm
->request_suspend
= (int (*)
372 (rcm_handle_t
*, char *, uint_t
,
373 timespec_t
*, rcm_info_t
**))sym
;
376 rcm
->notify_resume
= (int (*)
377 (rcm_handle_t
*, char *, uint_t
,
381 rcm
->notify_remove_list
= (int (*)
382 (rcm_handle_t
*, char **, uint_t
,
385 case REQUEST_CAP_CHANGE
:
386 rcm
->request_capacity_change
= (int (*)
387 (rcm_handle_t
*, char *, uint_t
,
388 nvlist_t
*, rcm_info_t
**))sym
;
390 case NOTIFY_CAP_CHANGE
:
391 rcm
->notify_capacity_change
= (int (*)
392 (rcm_handle_t
*, char *, uint_t
,
393 nvlist_t
*, rcm_info_t
**))sym
;
400 if (rcm
->alloc_handle
== NULL
||
401 (*rcm
->alloc_handle
)(NULL
, RCM_NOPID
, NULL
, &rcm
->hd
)
403 ap_err(a
, ERR_RCM_HANDLE
);
404 return (CFGA_LIB_ERROR
);
408 * Offlining/onlining a board means offlining/onlining
409 * all components on the board. When operating on a
410 * single component no component sequence number is
411 * needed since the default is the current (target)
414 if (a
->tgt
== AP_BOARD
) {
416 rcm
->lastcm
= a
->ncm
- 1;
418 rcm
->firstcm
= CM_DFLT
;
419 rcm
->lastcm
= CM_DFLT
;
422 if (rcm
->cpuids
== NULL
) {
427 * Allocate space for the cpu capacity change info.
428 * Not every cpu may be relevant to the capacity
429 * request, but allocating for the maximum makes
430 * it easier, and the space is insignifcant.
432 for (ncpu
= 0, cm
= rcm
->firstcm
; cm
<= rcm
->lastcm
; cm
++) {
434 ap_target_t type
= ap_cm_type(a
, cm
);
436 if ((type
== AP_CPU
) || (type
== AP_CMP
)) {
437 ncpu
+= ap_cm_ncap(a
, cm
);
442 if ((rcm
->cpuids
= (cpuid_t
*)calloc(ncpu
, sizeof (cpuid_t
)))
444 ap_err(a
, ERR_NOMEM
);
445 return (CFGA_LIB_ERROR
);
450 * Remember initial capacity information.
451 * This information is based on the initial
452 * state of the ap_id, i.e. before any
453 * state change change operations were
454 * executed. We will later get the
455 * current capacity information in order
456 * to figure out exactly what has changed
457 * as the result of the executed command
460 rc
= ap_capinfo(a
, rcm
->firstcm
, rcm
->lastcm
, &rcm
->capinfo
);
462 rcm
->capcpus
= sysconf(_SC_NPROCESSORS_CONF
);
463 rcm
->cappages
= sysconf(_SC_PHYS_PAGES
);
469 ap_rcm_fini(apd_t
*a
)
474 DBG("ap_rcm_fini(%p)\n", (void *)a
);
476 if ((rcm
= (rcmd_t
*)a
->rcm
) == NULL
)
480 (*rcm
->free_handle
)(rcm
->hd
);
482 (void) dlclose(rcm
->lib
);
485 * Free all the names in the resource list, followed
486 * by the resource list itself.
489 for (rp
= rcm
->rlist
; *rp
; rp
++)
493 s_free(rcm
->capinfo
);
498 ap_rcm_rlist(apd_t
*a
, int firstcm
, int lastcm
, char ***rlist
, int cmd
)
507 DBG("ap_rcm_rlist(%p)\n", (void *)a
);
510 * Allocate space for the maximum number of components
511 * that can be affected by this operation.
513 for (ncap
= 0, cm
= firstcm
; cm
<= lastcm
; cm
++) {
514 ncap
+= ap_cm_ncap(a
, cm
);
517 DBG("ncap=%d\n", ncap
);
519 if ((rp
= (char **)calloc(ncap
+ 1, sizeof (char *))) == NULL
) {
520 ap_err(a
, ERR_NOMEM
);
521 return (CFGA_LIB_ERROR
);
524 n
= 12; /* SUNW_cpu/cpuCCC */
526 cpuname
= "SUNW_cpu/cpuCCC";
528 * Set the RCM resource name for each component:
531 * cpu: SUNW_cpu/cpu<cpuid>
534 for (ncap
= 0, cm
= firstcm
; cm
<= lastcm
; cm
++) {
535 switch (ap_cm_type(a
, cm
)) {
549 cpuid
= cap
.type
.cpuid
;
553 * See if the request target is a single
554 * (default) component
556 capindex
= (cm
== CM_DFLT
) ? 0 : cm
;
558 /* Get the previous capacity info */
559 rcm
= (rcmd_t
*)a
->rcm
;
560 prevcap
= rcm
->capinfo
;
562 if (!ap_cm_capacity(a
, cm
, cpuid
, nc
, &os
)) {
566 len
= (strlen(cpuname
) - n
) + 1;
569 * For CMD_RCM_OFFLINE and REMOVE, add the CPU to the
570 * list if it is currently configured. For
571 * CMD_RCM_ONLINE, do so only if the state has changed
572 * to CFGA_STAT_CONFIGURED.
575 if ((cmd
== CMD_RCM_OFFLINE
) ||
576 (cmd
== CMD_RCM_REMOVE
)) {
577 if (os
== CFGA_STAT_CONFIGURED
)
580 if ((os
== CFGA_STAT_CONFIGURED
) &&
581 ((prevcap
== NULL
) ||
582 (prevcap
[capindex
].ostate
!= os
)))
587 for (i
= 0; i
< *nc
; i
++) {
588 if ((path
= strdup(cpuname
)) == NULL
) {
589 ap_err(a
, ERR_NOMEM
);
590 return (CFGA_LIB_ERROR
);
592 (void) snprintf(&path
[n
], len
, "%d",
595 DBG("rp[%d]=%s\n", ncap
, path
);
602 if ((path
= ap_cm_devpath(a
, cm
)) != NULL
) {
603 DBG("rp[%d]=%s\n", ncap
, path
);
609 * Nothing to do for AP_MEM since only capacity
610 * change notifications apply to SUNW_memory
624 * Returns 1 if the cpu ID 'cpuid' is in the list of CPU IDs
625 * 'list' of length 'length'. Returns 0 otherwise.
628 is_cpu_in_list(cpuid_t cpuid
, cpuid_t
*list
, int length
)
632 DBG("is_cpu_in_list\n");
637 for (i
= 0; i
< length
; i
++) {
638 if (list
[i
] == cpuid
)
645 ap_rcm_cap_cpu(apd_t
*a
, rcmd_t
*rcm
, rcm_handle_t
*hd
, uint_t flags
,
646 rcm_info_t
**rinfo
, int cmd
, int change
)
649 int rv
= RCM_FAILURE
;
656 nvlist_t
*nvl
= NULL
;
657 cpuid_t
*cpuids
= NULL
;
658 cpuid_t
*oldcpuids
= NULL
;
659 cpuid_t
*newcpuids
= NULL
;
661 DBG("ap_rcm_cap_cpu(%p)\n", (void *)a
);
664 * Get the current number of configured cpus.
666 if (getsyscpuids(&ncpuids
, &cpuids
) == -1)
668 else if (nvlist_alloc(&nvl
, NV_UNIQUE_NAME
, 0) != 0) {
678 size
= sizeof (cpuid_t
);
680 if (cmd
== CMD_RCM_CAP_DEL
) {
682 * A delete request. rcm->cpuids represents the
683 * cpus that will be unconfigured. The current
684 * set of cpus, before the unconfigure operation,
685 * are the old CPUs. The new CPUs are those
688 oldncpuids
= ncpuids
;
692 * Fill newcpuids with the CPU IDs in the cpuids array,
693 * but not in rcm->cpuids.
695 newcpuids
= (cpuid_t
*)calloc(ncpuids
, size
);
696 if (newcpuids
== NULL
)
700 for (i
= 0; i
< ncpuids
; i
++) {
701 if (!is_cpu_in_list(cpuids
[i
], rcm
->cpuids
, change
))
702 newcpuids
[newncpuids
++] = cpuids
[i
];
704 } else if (cmd
== CMD_RCM_CAP_NOTIFY
) {
706 * An unconfigure capacity change notification. This
707 * notification is sent after a DR unconfigure, whether
708 * or not the DR was successful. rcm->cpuids represents
709 * the CPUs that have been unconfigured.
712 /* New CPU IDs are the CPUs configured right now. */
713 newncpuids
= ncpuids
;
717 * Old CPU IDs are the CPUs configured right now
718 * in addition to those that have been unconfigured.
719 * We build the old CPU ID list by concatenating
720 * cpuids and rcm->cpuids.
722 oldcpuids
= (cpuid_t
*)calloc(ncpuids
+ change
, size
);
723 if (oldcpuids
== NULL
)
727 for (i
= 0; i
< ncpuids
; i
++) {
728 if (!is_cpu_in_list(cpuids
[i
], rcm
->cpuids
, change
))
729 oldcpuids
[oldncpuids
++] = cpuids
[i
];
731 for (i
= 0; i
< change
; i
++)
732 oldcpuids
[oldncpuids
++] = rcm
->cpuids
[i
];
734 DBG("ap_rcm_cap_cpu: CPU capacity, old = %d, new = %d \n",
735 rcm
->capcpus
, ncpuids
);
736 if (rcm
->capcpus
== ncpuids
) {
737 /* No real change in CPU capacity */
743 * An add notification. rcm->cpuids represents the
744 * cpus that have been configured. The current
745 * set of cpus, after the configure operation,
746 * are the new CPU IDs.
748 newncpuids
= ncpuids
;
752 * Fill oldcpuids with the CPU IDs in the cpuids array,
753 * but not in rcm->cpuids.
755 oldcpuids
= (cpuid_t
*)calloc(ncpuids
, size
);
756 if (oldcpuids
== NULL
)
760 for (i
= 0; i
< ncpuids
; i
++) {
761 if (!is_cpu_in_list(cpuids
[i
], rcm
->cpuids
, change
))
762 oldcpuids
[oldncpuids
++] = cpuids
[i
];
767 for (i
= 0; i
< oldncpuids
; i
++)
768 DBG("%d ", oldcpuids
[i
]);
771 for (i
= 0; i
< change
; i
++)
772 DBG("%d ", rcm
->cpuids
[i
]);
775 for (i
= 0; i
< newncpuids
; i
++)
776 DBG("%d ", newcpuids
[i
]);
779 if (nvlist_add_string(nvl
, "state", "capacity") != 0 ||
780 nvlist_add_int32(nvl
, "old_total", oldncpuids
) != 0 ||
781 nvlist_add_int32(nvl
, "new_total", newncpuids
) != 0 ||
782 nvlist_add_int32_array(nvl
, "old_cpu_list", oldcpuids
,
784 nvlist_add_int32_array(nvl
, "new_cpu_list", newcpuids
,
788 (void) snprintf(buf
, sizeof (buf
), fmt
, change
);
789 ap_msg(a
, MSG_ISSUE
, cmd
, buf
);
791 if (cmd
== CMD_RCM_CAP_DEL
) {
792 rv
= (*rcm
->request_capacity_change
)(hd
, "SUNW_cpu",
795 rv
= (*rcm
->notify_capacity_change
)(hd
, "SUNW_cpu",
796 flags
& ~RCM_FORCE
, nvl
, rinfo
);
807 ap_rcm_cap_mem(apd_t
*a
, rcmd_t
*rcm
, rcm_handle_t
*hd
, uint_t flags
,
808 rcm_info_t
**rinfo
, int cmd
, long change
)
818 DBG("ap_rcm_cap_mem(%p)\n", (void *)a
);
821 * Get the current amount of configured memory.
823 if ((pgsize
= sysconf(_SC_PAGE_SIZE
)) == -1 ||
824 (currpages
= sysconf(_SC_PHYS_PAGES
)) == -1 ||
825 nvlist_alloc(&nvl
, NV_UNIQUE_NAME
, 0) > 0)
826 return (RCM_FAILURE
);
829 * If this is a (delete) request, change represents
830 * the amount of capacity that will be deleted from the
831 * system. If this is an (add) notification, change
832 * represents the amount of capacity that has already
833 * been added to the system.
835 if (cmd
== CMD_RCM_CAP_DEL
) {
836 oldpages
= currpages
;
837 newpages
= currpages
- change
;
838 } else if (cmd
== CMD_RCM_CAP_NOTIFY
) {
839 newpages
= currpages
;
840 oldpages
= rcm
->cappages
;
842 if (rcm
->cappages
== currpages
) {
843 /* No real change in memory capacity */
844 DBG("ap_rcm_cap_mem: no change in capacity.\n");
846 return (RCM_SUCCESS
);
849 oldpages
= currpages
- change
;
850 newpages
= currpages
;
853 DBG("ap_rcm_cap_mem: Memory capacity, old = %ld, new = %ld\n",
856 if (nvlist_add_string(nvl
, "state", "capacity") != 0 ||
857 nvlist_add_int32(nvl
, "page_size", pgsize
) != 0 ||
858 nvlist_add_int32(nvl
, "old_pages", oldpages
) != 0 ||
859 nvlist_add_int32(nvl
, "new_pages", newpages
) != 0) {
861 return (RCM_FAILURE
);
864 (void) snprintf(buf
, sizeof (buf
), "(%ld pages)", change
);
865 ap_msg(a
, MSG_ISSUE
, cmd
, buf
);
867 if (cmd
== CMD_RCM_CAP_DEL
) {
868 rv
= (*rcm
->request_capacity_change
)(hd
, "SUNW_memory",
871 rv
= (*rcm
->notify_capacity_change
)(hd
, "SUNW_memory",
872 flags
& ~RCM_FORCE
, nvl
, rinfo
);
881 ap_rcm_request_cap(apd_t
*a
, rcmd_t
*rcm
, rcm_handle_t
*hd
,
882 int *rv
, uint_t flags
, rcm_info_t
**rinfo
)
890 DBG("ap_rcm_request_cap(%p)\n", (void *)a
);
892 if ((capinfo
= rcm
->capinfo
) == NULL
) {
893 ap_err(a
, ERR_PLUGIN
, "null capinfo");
894 return (CFGA_LIB_ERROR
);
899 for (cm
= rcm
->firstcm
; cm
<= rcm
->lastcm
; cm
++) {
903 * See if the request target is a single
904 * (default) component
906 i
= (cm
== CM_DFLT
) ? 0 : cm
;
909 * We are interested only in those components
910 * in the configured state since they represent
911 * available capacity.
913 type
= ap_cm_type(a
, cm
);
914 if (capinfo
[i
].valid
== 0 ||
915 capinfo
[i
].ostate
!= CFGA_STAT_CONFIGURED
)
917 else if ((type
== AP_CPU
) || (type
== AP_CMP
)) {
918 for (j
= 0; j
< capinfo
[i
].ncap
; j
++) {
919 rcm
->cpuids
[ncpus
++] = capinfo
[i
].type
.cpuid
[j
];
921 } else if (type
== AP_MEM
)
922 npages
+= capinfo
[i
].type
.npages
;
925 if (ncpus
&& ((*rv
= ap_rcm_cap_cpu(a
, rcm
, hd
, flags
, rinfo
,
926 CMD_RCM_CAP_DEL
, ncpus
)) != RCM_SUCCESS
)) {
927 return (CFGA_LIB_ERROR
);
929 if (npages
&& ((*rv
= ap_rcm_cap_mem(a
, rcm
, hd
, flags
, rinfo
,
930 CMD_RCM_CAP_DEL
, npages
)) != RCM_SUCCESS
)) {
931 return (CFGA_LIB_ERROR
);
938 ap_rcm_add_cap(apd_t
*a
, rcmd_t
*rcm
, rcm_handle_t
*hd
,
939 int *rv
, uint_t flags
, rcm_info_t
**rinfo
)
944 cap_info_t
*capinfo
, *prevcapinfo
;
947 DBG("ap_rcm_add_cap(%p)\n", (void *)a
);
949 /* Get the new capacity info to figure out what has changed */
950 if ((rc
= ap_capinfo(a
, rcm
->firstcm
, rcm
->lastcm
, &capinfo
)) !=
954 if (capinfo
== NULL
) {
955 DBG("no pertinent capacity info\n");
960 prevcapinfo
= rcm
->capinfo
;
962 for (cm
= rcm
->firstcm
; cm
<= rcm
->lastcm
; cm
++) {
964 cfga_stat_t os
, prevos
;
969 * See if the request target is a single
970 * (default) component
972 i
= cm
== CM_DFLT
? 0 : cm
;
974 os
= capinfo
[i
].ostate
;
975 if (prevcapinfo
== NULL
) {
976 prevos
= CFGA_STAT_EMPTY
;
979 prevos
= prevcapinfo
[i
].ostate
;
980 prevvalidity
= prevcapinfo
[i
].valid
;
983 type
= ap_cm_type(a
, cm
);
985 DBG("cm=%d valid=%d type=%d, prevos=%d os=%d\n",
986 cm
, prevvalidity
, type
, prevos
, os
);
989 * We are interested only in those components
990 * whose states have changed to configured as
991 * the result of the current cfgadm request.
993 if (prevvalidity
== 0 || os
!= CFGA_STAT_CONFIGURED
) {
994 capinfo
[i
].valid
= 0;
996 } else if (prevos
!= CFGA_STAT_CONFIGURED
) {
998 * The occupant state is configured, and
999 * the previous occupant state was not.
1001 if ((type
== AP_CPU
) || (type
== AP_CMP
)) {
1002 for (j
= 0; j
< capinfo
[i
].ncap
; j
++) {
1003 rcm
->cpuids
[ncpus
++] =
1004 capinfo
[i
].type
.cpuid
[j
];
1006 } else if (type
== AP_MEM
)
1007 npages
+= capinfo
[i
].type
.npages
;
1012 if (ncpus
&& ((*rv
= ap_rcm_cap_cpu(a
, rcm
, hd
, flags
, rinfo
,
1013 CMD_RCM_CAP_ADD
, ncpus
)) != RCM_SUCCESS
)) {
1014 return (CFGA_LIB_ERROR
);
1016 if (npages
&& ((*rv
= ap_rcm_cap_mem(a
, rcm
, hd
, flags
, rinfo
,
1017 CMD_RCM_CAP_ADD
, npages
)) != RCM_SUCCESS
)) {
1018 return (CFGA_LIB_ERROR
);
1025 * ap_rcm_notify_cap:
1027 * This routine handles the CMD_RCM_CAP_NOTIFY command. It
1028 * is called after a successful/failed DR unconfigure
1029 * operation. It filters out components that have changed
1030 * and passes this information on to ap_rcm_cap_{cpu,mem}.
1032 * ap_rcm_cap_{cpu,mem} will still be called if all the
1033 * components have not changed and at least one {cpu,mem}
1034 * component was originally configured.
1037 ap_rcm_notify_cap(apd_t
*a
, rcmd_t
*rcm
, rcm_handle_t
*hd
,
1038 int *rv
, uint_t flags
, rcm_info_t
**rinfo
)
1041 cap_info_t
*capinfo
;
1042 cap_info_t
*prevcapinfo
;
1046 int prev_mem
= 0; /* # of prev. configured mem components */
1047 int prev_cpus
= 0; /* # of prev. configured CPUs */
1049 DBG("ap_rcm_notify_cap(%p)\n", (void *)a
);
1051 /* Get the new capacity info to figure out what has changed */
1052 if ((rc
= ap_capinfo(a
, rcm
->firstcm
, rcm
->lastcm
, &capinfo
)) !=
1056 if (capinfo
== NULL
) {
1057 DBG("no pertinent capacity info\n");
1061 /* The original capacity info */
1062 prevcapinfo
= rcm
->capinfo
;
1065 * Cycle through all components that we are operating
1066 * on. Record which components' occupant states have
1069 for (cm
= rcm
->firstcm
; cm
<= rcm
->lastcm
; cm
++) {
1071 cfga_stat_t prevos
, os
;
1077 * See if the request target is a single
1078 * (default) component
1080 i
= cm
== CM_DFLT
? 0 : cm
;
1082 os
= capinfo
[i
].ostate
;
1084 if (prevcapinfo
== NULL
) {
1085 prevos
= CFGA_STAT_EMPTY
;
1087 prevos
= prevcapinfo
[i
].ostate
;
1088 if (prevcapinfo
[i
].valid
== 0) {
1089 DBG("ap_rcm_notify_cap: skipping component "
1090 "due to prevvalidity == 0\n");
1095 type
= ap_cm_type(a
, cm
);
1097 prev_conf
= (prevos
== CFGA_STAT_CONFIGURED
);
1098 now_conf
= (os
== CFGA_STAT_CONFIGURED
);
1101 * Build up rcm->cpuids with the IDs of CPUs that
1102 * have been removed. Record the number of removed
1105 if (type
== AP_CPU
|| type
== AP_CMP
) {
1108 if (prev_conf
&& !now_conf
) {
1110 for (j
= 0; j
< capinfo
[i
].ncap
; j
++) {
1111 rcm
->cpuids
[ncpus
++] =
1112 capinfo
[i
].type
.cpuid
[j
];
1115 } else if (type
== AP_MEM
) {
1118 if (prev_conf
&& !now_conf
)
1119 npages
+= capinfo
[i
].type
.npages
;
1125 * If any CPU or memory components were operated on,
1126 * successfully or not, the rcm_notify_capacity_change()
1127 * routine must be called.
1131 *rv
= ap_rcm_cap_cpu(a
, rcm
, hd
, flags
, rinfo
,
1132 CMD_RCM_CAP_NOTIFY
, ncpus
);
1134 if (*rv
!= RCM_SUCCESS
)
1135 return (CFGA_LIB_ERROR
);
1139 *rv
= ap_rcm_cap_mem(a
, rcm
, hd
, flags
, rinfo
,
1140 CMD_RCM_CAP_NOTIFY
, npages
);
1142 if (*rv
!= RCM_SUCCESS
)
1143 return (CFGA_LIB_ERROR
);
1150 ap_rcm_ctl(apd_t
*a
, int cmd
)
1164 cpuid_t
*growcpuids
;
1166 DBG("ap_rcm_ctl(%p)\n", (void *)a
);
1168 if ((rcm
= (rcmd_t
*)a
->rcm
) == NULL
) {
1169 ap_msg(a
, MSG_SKIP
, cmd
, a
->target
);
1176 if (ap_getopt(a
, OPT_FORCE
))
1186 case CMD_RCM_CAP_DEL
:
1187 if (rcm
->capinfo
== NULL
)
1190 rc
= ap_rcm_request_cap(a
, rcm
, hd
, &rv
, flags
, &rinfo
);
1192 case CMD_RCM_CAP_ADD
:
1193 rc
= ap_rcm_add_cap(a
, rcm
, hd
, &rv
, flags
, &rinfo
);
1195 case CMD_RCM_CAP_NOTIFY
:
1196 rc
= ap_rcm_notify_cap(a
, rcm
, hd
, &rv
, flags
, &rinfo
);
1198 case CMD_RCM_ONLINE
:
1199 /* Refresh changed component states */
1200 if ((rc
= ap_stat(a
, 1)) != CFGA_OK
) {
1205 if (a
->tgt
== AP_BOARD
) {
1207 rcm
->lastcm
= a
->ncm
- 1;
1209 /* Check if we need to grow our cpuids list */
1210 for (ncpus
= 0, cm
= rcm
->firstcm
; cm
<= rcm
->lastcm
;
1212 ap_target_t type
= ap_cm_type(a
, cm
);
1213 if ((type
== AP_CPU
) || (type
== AP_CMP
))
1214 ncpus
+= ap_cm_ncap(a
, cm
);
1217 if (rcm
->ncpus
< ncpus
) {
1219 (cpuid_t
*)realloc(rcm
->cpuids
,
1220 (ncpus
* sizeof (cpuid_t
)))) == NULL
) {
1221 ap_err(a
, ERR_NOMEM
);
1222 return (CFGA_LIB_ERROR
);
1225 rcm
->cpuids
= growcpuids
;
1229 rcm
->firstcm
= CM_DFLT
;
1230 rcm
->lastcm
= CM_DFLT
;
1235 case CMD_RCM_OFFLINE
:
1236 case CMD_RCM_REMOVE
: {
1239 if (cmd
== CMD_RCM_REMOVE
) {
1241 * An unconfigure has just taken place, so
1242 * refresh the changed component states.
1244 if ((rc
= ap_stat(a
, 1)) != CFGA_OK
) {
1250 /* Check if this is an empty board, i.e. no components */
1256 if ((rlist
= rcm
->rlist
) == NULL
) {
1257 rc
= ap_rcm_rlist(a
, rcm
->firstcm
, rcm
->lastcm
, &rlist
,
1259 if ((rc
== CFGA_OK
) && (rlist
!= NULL
) &&
1260 (rlist
[0] != NULL
)) {
1263 /* Do not pass up empty resource list to RCM */
1268 for (nrsrc
= 0; rlist
[nrsrc
] != NULL
; nrsrc
++)
1269 ap_msg(a
, MSG_ISSUE
, cmd
, rlist
[nrsrc
]);
1270 if (cmd
== CMD_RCM_OFFLINE
)
1271 rv
= (*rcm
->request_offline_list
)(hd
, rlist
, flags
,
1273 else if (cmd
== CMD_RCM_ONLINE
)
1274 rv
= (*rcm
->notify_online_list
)(hd
, rlist
,
1275 flags
& ~RCM_FORCE
, &rinfo
);
1277 rv
= (*rcm
->notify_remove_list
)(hd
, rlist
,
1278 flags
& ~RCM_FORCE
, &rinfo
);
1281 case CMD_RCM_SUSPEND
: {
1283 t
.tv_sec
= (time_t)0;
1284 t
.tv_nsec
= (long)0;
1286 ap_msg(a
, MSG_ISSUE
, cmd
, rsrc
);
1287 rv
= (*rcm
->request_suspend
)(hd
, rsrc
, flags
, &t
, &rinfo
);
1290 case CMD_RCM_RESUME
:
1292 ap_msg(a
, MSG_ISSUE
, cmd
, rsrc
);
1293 rv
= (*rcm
->notify_resume
)(hd
, rsrc
, 0, &rinfo
);
1296 ap_err(a
, ERR_CMD_INVAL
, cmd
);
1297 return (CFGA_INVAL
);
1300 if (rv
!= RCM_SUCCESS
) {
1303 ap_err(a
, ERR_RCM_CMD
, cmd
);
1304 (*rcm
->free_info
)(rinfo
);
1306 rc
= CFGA_LIB_ERROR
; /* make sure error is set */
1308 if ((rc
== CFGA_OK
) && (noop
== 0)) {
1310 for (i
= 0; rlist
[i
]; i
++)
1311 ap_msg(a
, MSG_DONE
, cmd
, rlist
[i
]);
1313 ap_msg(a
, MSG_DONE
, cmd
, rsrc
);
1315 ap_msg(a
, MSG_DONE
, cmd
, a
->target
);
1324 * Takes an ap_id and a character pointer, and formats
1325 * the rcm_info_t data in the form of a table to the given character pointer.
1326 * Code duplicated from the scsi plugin.
1327 * Note: This function will go away when a generic librcm callback is
1328 * implemented to format RCM messages for plugins.
1331 ap_rcm_info(apd_t
*a
, char **msg
)
1340 size_t msg_size
= 0;
1342 rcm_info_tuple_t
*tuple
= NULL
;
1346 static char format
[RCM_MAX_FORMAT
];
1347 const char *infostr
;
1350 DBG("ap_rcm_info(%p)\n", (void *)a
);
1352 /* Protect against invalid arguments */
1353 if ((a
== NULL
) || ((rcm
= (rcmd_t
*)a
->rcm
) == NULL
) ||
1354 ((rinfo
= rcm
->rinfo
) == NULL
) || (msg
== NULL
)) {
1358 /* Set localized table header strings */
1359 rsrc
= dgettext(TEXT_DOMAIN
, "Resource");
1360 info
= dgettext(TEXT_DOMAIN
, "Information");
1362 /* A first pass, to size up the RCM information */
1363 while (tuple
= (*rcm
->info_next
)(rinfo
, tuple
)) {
1364 if ((infostr
= (*rcm
->info_info
)(tuple
)) != NULL
) {
1366 if ((w
= strlen((*rcm
->info_rsrc
)(tuple
))) > w_rsrc
)
1368 if ((w
= strlen(infostr
)) > w_info
)
1373 /* If nothing was sized up above, stop early */
1377 /* Adjust column widths for column headings */
1378 if ((w
= strlen(rsrc
)) > w_rsrc
)
1380 else if ((w_rsrc
- w
) % 2)
1382 if ((w
= strlen(info
)) > w_info
)
1384 else if ((w_info
- w
) % 2)
1388 * Compute the total line width of each line,
1389 * accounting for intercolumn spacing.
1391 width
= w_info
+ w_rsrc
+ 4;
1393 /* Allocate space for the table */
1394 msg_size
= (2 + tuples
) * (width
+ 1) + 2;
1396 /* zero fill for the strcat() call below */
1397 *msg
= calloc(msg_size
, sizeof (char));
1401 newmsg
= realloc(*msg
, strlen(*msg
) + msg_size
);
1408 /* Place a table header into the string */
1410 /* The resource header */
1411 (void) strcat(*msg
, "\n");
1413 for (i
= 0; i
< ((w_rsrc
- w
) / 2); i
++)
1414 (void) strcat(*msg
, " ");
1415 (void) strcat(*msg
, rsrc
);
1416 for (i
= 0; i
< ((w_rsrc
- w
) / 2); i
++)
1417 (void) strcat(*msg
, " ");
1419 /* The information header */
1420 (void) strcat(*msg
, " ");
1422 for (i
= 0; i
< ((w_info
- w
) / 2); i
++)
1423 (void) strcat(*msg
, " ");
1424 (void) strcat(*msg
, info
);
1425 for (i
= 0; i
< ((w_info
- w
) / 2); i
++)
1426 (void) strcat(*msg
, " ");
1428 /* Underline the headers */
1429 (void) strcat(*msg
, "\n");
1430 for (i
= 0; i
< w_rsrc
; i
++)
1431 (void) strcat(*msg
, "-");
1432 (void) strcat(*msg
, " ");
1433 for (i
= 0; i
< w_info
; i
++)
1434 (void) strcat(*msg
, "-");
1436 /* Construct the format string */
1437 (void) snprintf(format
, RCM_MAX_FORMAT
, "%%-%ds %%-%ds",
1438 (int)w_rsrc
, (int)w_info
);
1440 /* Add the tuples to the table string */
1442 while ((tuple
= (*rcm
->info_next
)(rinfo
, tuple
)) != NULL
) {
1443 if ((infostr
= (*rcm
->info_info
)(tuple
)) != NULL
) {
1444 (void) strcat(*msg
, "\n");
1445 (void) sprintf(&((*msg
)[strlen(*msg
)]), format
,
1446 (*rcm
->info_rsrc
)(tuple
), infostr
);
1450 DBG("ap_rcm_info(%p) success\n", (void *)a
);