dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / cfgadm_plugins / sbd / common / ap_sbd.c
blob7c3b34b1f02a49179601ec5c54d5f7534837ef9c
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <ctype.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <fcntl.h>
31 #include <unistd.h>
32 #include <libdevinfo.h>
33 #include <errno.h>
34 #include <libintl.h>
35 #define CFGA_PLUGIN_LIB
36 #include <config_admin.h>
37 #include "ap.h"
38 #include <sys/obpdefs.h>
39 #include <sys/processor.h>
40 #include <sys/stat.h>
41 #include <sys/sbd_ioctl.h>
42 #include <sys/int_fmtio.h>
44 static cfga_err_t
45 ap_getncm(apd_t *a, sbd_comp_type_t type, int *ncm)
47 sbd_ioctl_arg_t *ctl;
48 sbd_getncm_cmd_t *cp;
50 if (a->fd == -1 || a->ctl == NULL)
51 return (CFGA_LIB_ERROR);
53 ctl = (sbd_ioctl_arg_t *)a->ctl;
54 ctl->ic_type = type;
55 ctl->ic_name[0] = '\0';
56 ctl->ic_unit = 0;
57 ctl->i_len = 0;
58 ctl->i_opts = NULL;
60 DBG("ioctl(%d SBD_CMD_GETNCM, 0x%p)\n", a->fd, (void *)ctl);
62 if (ioctl(a->fd, SBD_CMD_GETNCM, ctl) == -1) {
63 ap_err(a, ERR_CMD_FAIL, CMD_GETNCM);
64 return (CFGA_ERROR);
67 cp = &ctl->i_cmd.cmd_getncm;
69 DBG("ncm(%d)=%d\n", type, cp->g_ncm);
71 if (ncm)
72 *ncm = cp->g_ncm;
74 return (CFGA_OK);
77 cfga_err_t
78 ap_stat(apd_t *a, int all)
80 int fd;
81 int ncm;
82 int select;
83 int stsize;
84 int oflag;
85 sbd_stat_cmd_t *sc;
86 sbd_ioctl_arg_t *ctl;
87 cfga_err_t rc;
88 sbd_stat_t *new_stat;
90 rc = CFGA_LIB_ERROR;
92 DBG("ap_stat(%s)\n", a->path);
94 /* Open the file descriptor if not already open */
95 if (a->fd == -1) {
96 DBG("open(%s)\n", a->path);
97 if (a->statonly != 0)
98 oflag = O_RDONLY;
99 else
100 oflag = O_RDWR;
101 if ((fd = open(a->path, oflag, 0)) == -1) {
102 ap_err(a, ERR_AP_INVAL);
103 return (rc);
105 a->fd = fd;
106 } else {
107 fd = a->fd;
110 if (a->ctl == NULL && (a->ctl = calloc(1, sizeof (*ctl))) == NULL) {
111 ap_err(a, ERR_CMD_FAIL, CMD_STATUS);
112 return (rc);
115 if (a->tgt == AP_BOARD) {
117 * The status target is the board. If we need to
118 * return component data (to support the -a option),
119 * get the number of components on the board.
121 select = 0;
122 if (all) {
123 cfga_err_t r;
124 r = ap_getncm(a, SBD_COMP_NONE, &ncm);
125 if (r != CFGA_OK) {
126 return (r);
128 } else {
129 ncm = 0;
131 } else {
132 select = 1;
133 ncm = 1;
136 DBG("ncm=%d\n", ncm);
138 a->ncm = ncm;
141 * The status structure contains space for one component;
142 * add the space for the other components if necessary.
144 stsize = sizeof (sbd_stat_t);
145 if (ncm > 1)
146 stsize += ((ncm - 1) * sizeof (sbd_dev_stat_t));
148 if ((new_stat = realloc(a->stat, stsize)) == NULL) {
149 ap_err(a, ERR_CMD_FAIL, CMD_STATUS);
150 return (rc);
153 a->stat = new_stat;
156 ctl = (sbd_ioctl_arg_t *)a->ctl;
157 ctl->i_len = 0;
158 ctl->i_opts = NULL;
159 ctl->ic_type = SBD_COMP_NONE;
160 if (all)
161 ctl->i_flags |= SBD_FLAG_ALLCMP;
162 sc = &ctl->i_cmd.cmd_stat;
163 sc->s_statp = (caddr_t)a->stat;
164 sc->s_nbytes = stsize;
166 if (select) {
168 * The target is a specific component. Pass its
169 * name and unit number to the driver. Set its
170 * type to UNKNOWN since the plugin does not know
171 * the type of the component specified by the user.
173 ctl->ic_type = SBD_COMP_UNKNOWN;
174 ctl->ic_unit = a->cnum;
175 (void) strcpy(ctl->ic_name, a->cname);
178 DBG("ioctl(%d SBD_CMD_STATUS, sc=0x%p sz=%d flags=%d",
179 fd, (void *)sc->s_statp, sc->s_nbytes, ctl->i_flags);
180 if (select)
181 DBG(" cname=<%s> cnum=%d", a->cname, a->cnum);
182 DBG(")\n");
184 if (ioctl(fd, SBD_CMD_STATUS, ctl) == -1) {
185 ap_err(a, ERR_CMD_FAIL, CMD_STATUS);
186 rc = CFGA_ERROR;
187 } else
188 rc = CFGA_OK;
190 DBG("ap_stat()=%d\n", rc);
192 return (rc);
196 * Convert a component to a target type.
198 static ap_target_t
199 ap_cm_tgt(sbd_comp_type_t type)
201 ap_target_t c;
203 switch (type) {
204 case SBD_COMP_CPU:
205 c = AP_CPU;
206 break;
207 case SBD_COMP_MEM:
208 c = AP_MEM;
209 break;
210 case SBD_COMP_IO:
211 c = AP_IO;
212 break;
213 case SBD_COMP_CMP:
214 c = AP_CMP;
215 break;
216 default:
217 c = AP_NONE;
218 break;
221 return (c);
224 cfga_err_t
225 apd_init(apd_t *a, int all)
227 int i;
228 char *cn, *dn;
229 sbd_stat_t *st;
230 sbd_dev_stat_t *dst;
231 cfga_err_t rc;
234 * Ideally, for board operations (other than status) it is not
235 * necessary to issue the STATUS ioctl. The call however allows a
236 * final sanity check to ensure that the board number returned
237 * by the driver matches the plugin's notion of the board number
238 * as extracted from the ap_id. If this check is not desirable,
239 * we can change the code to issue the status call only when
240 * necessary. Note that for component operations, we need to do
241 * the STATUS in order to figure out the component type and
242 * validate the command/options accordingly. XXX
244 if ((rc = ap_stat(a, all)) != CFGA_OK) {
245 ap_err(a, ERR_AP_INVAL);
246 return (rc);
249 st = (sbd_stat_t *)a->stat;
252 * Set the component count to the returned stat count.
254 if (a->ncm > st->s_nstat) {
256 DBG("ncm=%d nstat=%d (truncated)\n", a->ncm, st->s_nstat);
258 a->ncm = st->s_nstat;
261 if (a->tgt == AP_BOARD) {
263 DBG("tgt=%d\n", a->tgt);
266 * Initialize the RCM module here so that it can record
267 * the initial state of the capacity information.
269 rc = ap_rcm_init(a);
271 return (rc);
274 a->tgt = AP_NONE;
275 cn = a->cname;
277 DBG("cname=<%s> cunit=<%d>\n", a->cname, a->cnum);
279 for (dst = st->s_stat, i = 0; i < st->s_nstat; i++, dst++) {
281 DBG("ds_name,ds_unit,ds_type=<%s,%d,%d> ",
282 dst->ds_name, dst->ds_unit, dst->ds_type);
284 if (dst->ds_unit != a->cnum)
285 continue;
288 * Consider the names matched if they are either
289 * both absent or the same. It is conceivable that
290 * a NULL component name be considered valid
291 * by the driver.
293 dn = dst->ds_name;
295 if ((dn == NULL && cn == NULL) ||
296 (dn != NULL && cn != NULL && strcmp(dn, cn) == 0)) {
297 a->tgt = ap_cm_tgt(dst->ds_type);
298 a->cmstat = (void *)dst;
300 DBG("found ");
302 break;
306 DBG("tgt=%d\n", a->tgt);
308 if (a->tgt == AP_NONE) {
309 ap_err(a, ERR_CM_INVAL, a->cid);
310 return (CFGA_INVAL);
314 * Initialize the RCM module here so that it can record
315 * the initial state of the capacity information.
317 rc = ap_rcm_init(a);
319 return (rc);
322 void
323 apd_free(apd_t *a)
325 if (a == NULL)
326 return;
328 ap_rcm_fini(a);
330 if (a->fd != -1)
331 (void) close(a->fd);
333 s_free(a->options);
334 s_free(a->path);
335 s_free(a->drv);
336 s_free(a->target);
337 s_free(a->cname);
338 s_free(a->ctl);
339 s_free(a->stat);
341 free(a);
344 apd_t *
345 apd_alloc(const char *ap_id, cfga_flags_t flags, char **errstring,
346 struct cfga_msg *msgp, struct cfga_confirm *confp)
348 apd_t *a;
350 if ((a = calloc(1, sizeof (*a))) == NULL)
351 return (NULL);
353 if (errstring != NULL)
354 *errstring = NULL;
356 a->fd = -1;
357 a->errstring = errstring;
358 a->msgp = msgp;
359 a->confp = confp;
360 a->class = "sbd";
362 if (flags & CFGA_FLAG_LIST_ALL)
363 ap_setopt(a, OPT_LIST_ALL);
364 if (flags & CFGA_FLAG_FORCE)
365 ap_setopt(a, OPT_FORCE);
366 if (flags & CFGA_FLAG_VERBOSE)
367 ap_setopt(a, OPT_VERBOSE);
369 if (ap_id == NULL || ap_parse(a, ap_id) == 0)
370 return (a);
372 apd_free(a);
373 return (NULL);
377 * The type field is defined to be parsable by cfgadm(1M): It
378 * must not contain white space characters. This function
379 * converts white space to underscore.
382 static void
383 parsable_strncpy(char *op, const char *ip, size_t n)
385 char c;
387 while (n-- > 0) {
388 c = *ip++;
389 if (isspace(c))
390 c = '_';
391 *op++ = c;
392 if (c == '\0')
393 break;
397 void
398 ap_init(apd_t *a, cfga_list_data_t *ap)
400 sbd_stat_t *st;
402 st = (sbd_stat_t *)a->stat;
404 DBG("ap_init bd=%d rs=%d os=%d type=<%s>\n",
405 a->bnum, st->s_rstate, st->s_ostate, st->s_type);
407 parsable_strncpy(ap->ap_type, st->s_type, sizeof (ap->ap_type));
408 ap->ap_r_state = (cfga_stat_t)st->s_rstate;
409 ap->ap_o_state = (cfga_stat_t)st->s_ostate;
410 ap->ap_cond = (cfga_cond_t)st->s_cond;
411 ap->ap_busy = (cfga_busy_t)st->s_busy;
412 ap->ap_status_time = st->s_time;
413 ap_info(a, ap->ap_info, AP_BOARD);
416 typedef struct {
417 int cmd;
418 int ioc;
419 } ap_ioc_t;
421 static ap_ioc_t
422 ap_iocs[] = {
423 {CMD_ASSIGN, SBD_CMD_ASSIGN },
424 {CMD_POWERON, SBD_CMD_POWERON },
425 {CMD_TEST, SBD_CMD_TEST },
426 {CMD_CONNECT, SBD_CMD_CONNECT },
427 {CMD_CONFIGURE, SBD_CMD_CONFIGURE },
428 {CMD_UNCONFIGURE, SBD_CMD_UNCONFIGURE },
429 {CMD_DISCONNECT, SBD_CMD_DISCONNECT },
430 {CMD_POWEROFF, SBD_CMD_POWEROFF },
431 {CMD_STATUS, SBD_CMD_STATUS },
432 {CMD_GETNCM, SBD_CMD_GETNCM },
433 {CMD_UNASSIGN, SBD_CMD_UNASSIGN },
434 {CMD_PASSTHRU, SBD_CMD_PASSTHRU },
435 {CMD_NONE, 0 }
438 static int
439 ap_ioc(int cmd)
441 ap_ioc_t *acp;
443 DBG("ap_ioc(%d)\n", cmd);
445 for (acp = ap_iocs; acp->cmd != CMD_NONE; acp++)
446 if (acp->cmd == cmd)
447 break;
449 DBG("ap_ioc(%d)=0x%x\n", cmd, acp->ioc);
451 return (acp->ioc);
454 cfga_err_t
455 ap_suspend_query(apd_t *a, int cmd, int *check)
457 int ioc;
458 sbd_dev_stat_t *dst;
461 * See if the a quiesce operation is required for
462 * this command for any of the components. If the
463 * command does not map to an ioctl, then there is
464 * nothing to do.
466 if ((ioc = ap_ioc(cmd)) == 0)
467 return (CFGA_OK);
468 else if (a->tgt == AP_BOARD) {
469 int i;
471 dst = ((sbd_stat_t *)a->stat)->s_stat;
474 * See if any component requires a
475 * OS suspension for this command.
477 for (i = 0; i < a->ncm; i++, dst++)
478 if (SBD_CHECK_SUSPEND(ioc, dst->ds_suspend))
479 (*check)++;
480 } else {
481 dst = (sbd_dev_stat_t *)a->cmstat;
482 if (SBD_CHECK_SUSPEND(ioc, dst->ds_suspend))
483 (*check)++;
486 return (CFGA_OK);
489 cfga_err_t
490 ap_platopts_check(apd_t *a, int first, int last)
492 int c;
493 uint_t platopts;
494 sbd_stat_t *stat;
495 ap_opts_t *opts;
497 opts = &a->opts;
498 stat = (sbd_stat_t *)a->stat;
499 platopts = stat->s_platopts;
503 * If there are no platform options set then there
504 * is no need to check this operation
506 if (opts->platform == NULL)
507 return (CFGA_OK);
510 * Check if any of the steps in the sequence
511 * allows for a platform option
513 for (c = first; c <= last; c++)
515 * If the platopt is set it means that the platform does not
516 * support options for this cmd
518 if (SBD_CHECK_PLATOPTS(ap_ioc(c), platopts) == 0) {
519 return (CFGA_OK);
522 ap_err(a, ERR_OPT_INVAL, opts->platform);
524 return (CFGA_INVAL);
527 cfga_err_t
528 ap_ioctl(apd_t *a, int cmd)
530 int ioc;
531 sbd_ioctl_arg_t *ctl;
533 if (a->ctl == NULL && (a->ctl = calloc(1, sizeof (*ctl))) == NULL) {
534 ap_err(a, ERR_CMD_FAIL, cmd);
535 return (CFGA_LIB_ERROR);
538 ap_msg(a, MSG_ISSUE, cmd, a->target);
540 ctl = (sbd_ioctl_arg_t *)a->ctl;
541 ctl->i_flags = 0;
542 ctl->i_len = 0;
543 ctl->i_opts = NULL;
545 if (ap_getopt(a, OPT_FORCE))
546 ctl->i_flags |= SBD_FLAG_FORCE;
547 if (ap_getopt(a, OPT_SUSPEND_OK))
548 ctl->i_flags |= SBD_FLAG_QUIESCE_OKAY;
550 if (a->tgt == AP_BOARD)
551 ctl->ic_type = SBD_COMP_NONE;
552 else {
553 ctl->ic_type = SBD_COMP_UNKNOWN;
554 ctl->ic_unit = a->cnum;
555 (void) strcpy(ctl->ic_name, a->cname);
558 if (!(ioc = ap_ioc(cmd))) {
559 ap_err(a, ERR_CMD_FAIL, cmd);
560 return (CFGA_LIB_ERROR);
564 * If this is a passthru command, pass all of its
565 * options; otherwise, pass all options after the
566 * platform keyword.
568 if (cmd == CMD_PASSTHRU)
569 ctl->i_opts = a->options;
570 else {
572 * Only pass the platform option to the cmds that the platform
573 * has specified as ok
575 sbd_stat_t *stat;
577 stat = (sbd_stat_t *)a->stat;
578 if (SBD_CHECK_PLATOPTS(ioc, stat->s_platopts) == 0)
579 ctl->i_opts = a->opts.platform;
582 if (ctl->i_opts != NULL)
583 ctl->i_len = strlen(ctl->i_opts) + 1;
585 DBG("i_opts=%s\n", ctl->i_opts ? ctl->i_opts : "NULL");
586 DBG("i_flags=0x%x\n", ctl->i_flags);
588 if (ap_getopt(a, OPT_SIM)) {
589 ap_msg(a, MSG_DONE, cmd, a->target);
590 return (CFGA_OK);
593 if (ioctl(a->fd, ioc, ctl) == -1) {
594 ap_err(a, ERR_CMD_FAIL, cmd);
595 return (CFGA_ERROR);
597 ap_msg(a, MSG_DONE, cmd, a->target);
599 return (CFGA_OK);
603 * Return the error string corresponding to a given error code.
604 * String table and error code sets are provided by sbd_etab. This data
605 * structure is automatically generated at compile time from the error
606 * code and message text information in sbd_ioctl.h.
608 static char *
609 mod_estr(int code)
611 int i;
612 char *s;
613 extern sbd_etab_t sbd_etab[];
614 extern int sbd_etab_len;
616 s = NULL;
618 for (i = 0; i < sbd_etab_len; i++) {
619 sbd_etab_t *eptr = &sbd_etab[i];
621 if ((code >= eptr->t_base) && (code <= eptr->t_bnd)) {
622 int index;
623 char **t_text;
626 * Found it. Just extract the string
628 index = code - eptr->t_base;
629 t_text = eptr->t_text;
630 s = strdup(t_text[index]);
631 break;
635 if (i == sbd_etab_len) {
636 char buf[32];
638 (void) snprintf(buf, sizeof (buf), "error %d", code);
639 s = strdup(buf);
642 return (s);
645 char *
646 ap_sys_err(apd_t *a, char **rp)
648 int code;
649 char *p;
650 char *rsc;
652 sbd_ioctl_arg_t *ctl = (sbd_ioctl_arg_t *)a->ctl;
655 * The driver sets the errno to EIO if it returns
656 * more detailed error info via e_code. In all
657 * other cases, use standard error text.
659 if (ctl == NULL || errno != EIO) {
660 if ((p = strerror(errno)) != NULL)
661 p = strdup(p);
662 return (p);
665 code = ctl->ie_code;
666 rsc = ctl->ie_rsc;
668 if (code)
669 p = mod_estr(code);
670 else if ((p = strerror(errno)) != NULL)
671 p = strdup(p);
673 if (*rsc != '\0' && rp != NULL)
674 *rp = strdup(rsc);
676 return (p);
680 * cfgadm -o err=plugin-err,cmd=name,code=ecode -x errtest ap_id.
682 cfga_err_t
683 ap_test_err(apd_t *a, const char *options)
685 int err;
686 int cmd;
687 ap_opts_t *opts;
688 sbd_ioctl_arg_t ctl;
690 opts = &a->opts;
691 err = opts->err;
692 cmd = CMD_DISCONNECT;
694 DBG("ap_test_err(%d %d)\n", opts->code, opts->err);
696 switch (err) {
697 case ERR_CMD_INVAL:
698 ap_err(a, err, ap_cmd_name(cmd));
699 break;
700 case ERR_CMD_NOTSUPP:
701 ap_err(a, err, cmd);
702 break;
703 case ERR_CMD_FAIL:
704 errno = EIO;
705 ctl.i_err.e_code = opts->code;
706 *ctl.i_err.e_rsc = '\0';
707 a->ctl = &ctl;
708 ap_err(a, err, cmd);
709 a->ctl = NULL;
710 break;
711 case ERR_OPT_INVAL:
712 ap_err(a, err, options);
713 break;
714 case ERR_OPT_NOVAL:
715 ap_err(a, err, options);
716 break;
717 case ERR_AP_INVAL:
718 ap_err(a, err);
719 break;
720 case ERR_CM_INVAL:
721 ap_err(a, err, a->cid);
722 break;
723 case ERR_TRANS_INVAL:
724 ap_err(a, ERR_TRANS_INVAL, cmd);
725 break;
728 return (CFGA_LIB_ERROR);
731 static char *
732 ap_help_topics[] = {
733 "\nSbd specific commands/options:\n\n",
734 "\tcfgadm [-o parsable] -l ap_id\n",
735 "\tcfgadm [-o unassign|nopoweroff] -c disconnect ap_id\n",
736 "\tcfgadm -t ap_id\n",
737 "\tcfgadm -x assign ap_id\n",
738 "\tcfgadm -x unassign ap_id\n",
739 "\tcfgadm -x poweron ap_id\n",
740 "\tcfgadm -x poweroff ap_id\n",
741 NULL
744 /*ARGSUSED*/
745 cfga_err_t
746 ap_help(struct cfga_msg *msgp, const char *options, cfga_flags_t flags)
748 int len;
749 char **p;
750 char *q;
752 if (msgp == NULL || msgp->message_routine == NULL)
753 return (CFGA_OK);
755 for (p = ap_help_topics; *p != NULL; p++) {
756 if ((len = strlen(*p)) == 0)
757 continue;
758 if ((q = (char *)calloc(len + 1, 1)) == NULL)
759 continue;
760 (void) strcpy(q, *p);
761 (*msgp->message_routine)(msgp->appdata_ptr, q);
762 free(q);
765 return (CFGA_OK);
768 static char *
769 ap_dev_type(sbd_dev_stat_t *dst)
771 char *type;
773 switch (dst->ds_type) {
774 case SBD_COMP_CPU:
775 type = "cpu";
776 break;
777 case SBD_COMP_MEM:
778 type = "memory";
779 break;
780 case SBD_COMP_IO:
781 type = "io";
782 break;
783 case SBD_COMP_CMP:
784 type = "cpu";
785 break;
786 default:
787 type = "other";
788 break;
791 DBG("ap_dev_type(%d)=%s\n", dst->ds_type, type);
793 return (type);
796 static sbd_dev_stat_t *
797 ap_cm_stat(apd_t *a, int seq)
799 sbd_stat_t *st;
801 if (seq == CM_DFLT)
802 return (a->cmstat);
804 st = (sbd_stat_t *)a->stat;
805 return (st->s_stat + seq);
808 char *
809 ap_cm_devpath(apd_t *a, int seq)
811 int len;
812 char *path;
813 char *devpath;
814 sbd_io_stat_t *dst;
818 * If no component sequence number is provided
819 * default to the current target component.
820 * Assume an io component so that we can get
821 * the path if the component is indeed of type io.
823 if (seq == CM_DFLT)
824 dst = (sbd_io_stat_t *)a->cmstat;
825 else {
826 sbd_stat_t *st;
827 st = (sbd_stat_t *)a->stat;
828 dst = (sbd_io_stat_t *)st->s_stat + seq;
831 if (dst->is_type != SBD_COMP_IO)
832 path = NULL;
833 else
834 path = dst->is_pathname;
836 if (str_valid(path)) {
837 len = strlen(DEVDIR) + strlen(path) + 1;
839 if ((devpath = calloc(1, len)) == NULL)
840 return (NULL);
842 (void) snprintf(devpath, len, "%s%s", DEVDIR, path);
843 } else
844 devpath = NULL;
846 DBG("ap_cm_path(%d)=%s\n", seq, devpath ? devpath : "");
848 return (devpath);
851 void
852 ap_cm_id(apd_t *a, int seq, char *id, size_t bufsize)
854 int unit;
855 char *name;
856 sbd_dev_stat_t *dst;
858 dst = ap_cm_stat(a, seq);
860 unit = dst->ds_unit;
861 name = dst->ds_name;
864 * If the component has a unit number,
865 * add it to the id, otherwise just use
866 * the component's name.
868 if (unit == -1)
869 (void) snprintf(id, bufsize, "%s", name);
870 else
871 (void) snprintf(id, bufsize, "%s%d", name, unit);
873 DBG("ap_cm_id(%d)=%s\n", seq, id);
877 * Convert a component to a target type.
879 ap_target_t
880 ap_cm_type(apd_t *a, int seq)
882 ap_target_t c;
883 sbd_dev_stat_t *dst;
885 dst = ap_cm_stat(a, seq);
887 switch (dst->ds_type) {
888 case SBD_COMP_CPU:
889 c = AP_CPU;
890 break;
891 case SBD_COMP_MEM:
892 c = AP_MEM;
893 break;
894 case SBD_COMP_IO:
895 c = AP_IO;
896 break;
897 case SBD_COMP_CMP:
898 c = AP_CMP;
899 break;
900 default:
901 c = AP_NONE;
902 break;
905 return (c);
909 ap_cm_ncap(apd_t *a, int seq)
911 sbd_dev_stat_t *dst;
912 int ncap;
914 dst = ap_cm_stat(a, seq);
916 switch (dst->ds_type) {
917 case SBD_COMP_CPU:
918 case SBD_COMP_MEM:
919 case SBD_COMP_IO:
920 ncap = 1;
921 break;
922 case SBD_COMP_CMP:
923 ncap = ((sbd_cmp_stat_t *)dst)->ps_ncores;
924 break;
925 default:
926 ncap = 0;
927 break;
930 return (ncap);
934 ap_cm_capacity(apd_t *a, int seq, void *cap, int *ncap, cfga_stat_t *ostate)
936 int i;
937 sbd_dev_stat_t *dst;
938 cfga_stat_t os;
940 if (cap == NULL)
941 return (0);
943 dst = ap_cm_stat(a, seq);
944 os = (cfga_stat_t)dst->ds_ostate;
945 if (os != CFGA_STAT_CONFIGURED && os != CFGA_STAT_UNCONFIGURED)
946 return (0);
947 if (ostate)
948 *ostate = os;
950 *ncap = 1;
952 switch (dst->ds_type) {
953 case SBD_COMP_CPU: {
954 sbd_cpu_stat_t *cpu = (sbd_cpu_stat_t *)dst;
955 *((processorid_t *)cap) = cpu->cs_cpuid;
956 break;
958 case SBD_COMP_MEM: {
959 sbd_mem_stat_t *mem = (sbd_mem_stat_t *)dst;
960 *((long *)cap) = mem->ms_totpages;
961 break;
963 case SBD_COMP_CMP: {
964 sbd_cmp_stat_t *cmp = (sbd_cmp_stat_t *)dst;
965 processorid_t *cpuid;
967 cpuid = (processorid_t *)cap;
968 for (i = 0; i < cmp->ps_ncores; i++) {
969 cpuid[i] = cmp->ps_cpuid[i];
972 *ncap = cmp->ps_ncores;
973 break;
975 default:
976 return (0);
979 DBG("ap_cm_capacity(%d)=(", seq);
980 for (i = 0; i < *ncap; i++) {
981 DBG("%d ", ((int *)cap)[i]);
983 DBG("%d)\n", *ostate);
985 return (1);
988 void
989 ap_cm_init(apd_t *a, cfga_list_data_t *ap, int seq)
991 char *type;
992 sbd_stat_t *st;
993 sbd_dev_stat_t *dst;
995 st = (sbd_stat_t *)a->stat;
996 dst = st->s_stat + seq;
997 type = ap_dev_type(dst);
999 a->cmstat = (void *)dst;
1001 DBG("ap_cm_init bd=%d rs=%d os=%d type=<%s> seq=%d\n",
1002 a->bnum, st->s_rstate, dst->ds_ostate, type, seq);
1004 (void) strncpy(ap->ap_type, type, sizeof (ap->ap_type));
1005 ap->ap_r_state = (cfga_stat_t)st->s_rstate;
1006 ap->ap_o_state = (cfga_stat_t)dst->ds_ostate;
1007 ap->ap_cond = (cfga_cond_t)dst->ds_cond;
1008 ap->ap_busy = (cfga_busy_t)dst->ds_busy;
1009 ap->ap_status_time = dst->ds_time;
1010 ap_info(a, ap->ap_info, ap_cm_tgt(dst->ds_type));
1013 void
1014 ap_state(apd_t *a, cfga_stat_t *rs, cfga_stat_t *os)
1016 sbd_stat_t *st;
1017 sbd_dev_stat_t *dst;
1019 st = (sbd_stat_t *)a->stat;
1020 dst = (sbd_dev_stat_t *)a->cmstat;
1022 if (rs != NULL) {
1023 if (a->tgt == AP_NONE)
1024 *rs = CFGA_STAT_NONE;
1025 else
1026 *rs = (cfga_stat_t)st->s_rstate;
1029 if (os != NULL) {
1030 if (a->tgt == AP_NONE)
1031 *os = CFGA_STAT_NONE;
1032 else if (a->tgt == AP_BOARD)
1033 *os = (cfga_stat_t)st->s_ostate;
1034 else
1035 *os = (cfga_stat_t)dst->ds_ostate;
1039 #define BI_POWERED 0
1040 #define BI_ASSIGNED 1
1042 static const char *
1043 binfo[] = {
1044 "powered-on",
1045 ", assigned"
1048 static const char *
1049 binfo_parsable[] = {
1050 "powered-on",
1051 " assigned"
1054 static void
1055 bd_info(apd_t *a, cfga_info_t info, int parsable)
1057 int i;
1058 int nsep;
1059 const char **p;
1060 sbd_stat_t *st;
1061 char *end = &info[sizeof (cfga_info_t)];
1063 DBG("bd_info(%p)\n", (void *)info);
1065 st = (sbd_stat_t *)a->stat;
1067 if (parsable) {
1068 p = binfo_parsable;
1069 nsep = 1;
1070 } else {
1071 p = binfo;
1072 nsep = 2;
1075 i = nsep;
1077 if (st->s_power) {
1078 info += snprintf(info, end - info, p[BI_POWERED]);
1079 i = 0;
1081 if (st->s_assigned)
1082 info += snprintf(info, end - info, p[BI_ASSIGNED] + i);
1085 #define CI_CPUID 0
1086 #define CI_SPEED 1
1087 #define CI_ECACHE 2
1089 static const char *
1090 cpuinfo[] = {
1091 "cpuid %d",
1092 ", speed %d MHz",
1093 ", ecache %d MBytes"
1096 static const char *
1097 cpuinfo_parsable[] = {
1098 "cpuid=%d",
1099 " speed=%d",
1100 " ecache=%d"
1103 static void
1104 cpu_info(apd_t *a, cfga_info_t info, int parsable)
1106 const char **p;
1107 sbd_cpu_stat_t *dst;
1108 char *end = &info[sizeof (cfga_info_t)];
1110 DBG("cpu_info(%p)\n", (void *)info);
1112 dst = (sbd_cpu_stat_t *)a->cmstat;
1114 if (parsable)
1115 p = cpuinfo_parsable;
1116 else
1117 p = cpuinfo;
1119 info += snprintf(info, end - info, p[CI_CPUID], dst->cs_cpuid);
1120 info += snprintf(info, end - info, p[CI_SPEED], dst->cs_speed);
1121 info += snprintf(info, end - info, p[CI_ECACHE], dst->cs_ecache);
1124 #define MI_ADDRESS 0
1125 #define MI_SIZE 1
1126 #define MI_PERMANENT 2
1127 #define MI_UNCONFIGURABLE 3
1128 #define MI_SOURCE 4
1129 #define MI_TARGET 5
1130 #define MI_DELETED 6
1131 #define MI_REMAINING 7
1132 #define MI_INTERLEAVE 8
1134 static const char *
1135 meminfo_nonparsable[] = {
1136 "base address 0x%" PRIx64,
1137 ", %lu KBytes total",
1138 ", %lu KBytes permanent",
1139 ", unconfigurable",
1140 ", memory delete requested on %s",
1141 ", memory delete in progress on %s",
1142 ", %lu KBytes deleted",
1143 ", %lu KBytes remaining",
1144 ", inter board interleave"
1147 static const char *
1148 meminfo_parsable[] = {
1149 "address=0x%" PRIx64,
1150 " size=%lu",
1151 " permanent=%lu",
1152 " unconfigurable",
1153 " source=%s",
1154 " target=%s",
1155 " deleted=%lu",
1156 " remaining=%lu",
1157 " inter-board-interleave"
1161 #define _K1 1024
1164 * This function assumes pagesize > 1024 and that
1165 * pagesize is a multiple of 1024.
1167 static ulong_t
1168 pages_to_kbytes(uint_t pgs)
1170 long pagesize;
1172 pagesize = sysconf(_SC_PAGESIZE);
1173 return (pgs * (pagesize / _K1));
1176 static uint64_t
1177 pages_to_bytes(uint_t pgs)
1179 long pagesize;
1181 pagesize = sysconf(_SC_PAGESIZE);
1182 return ((uint64_t)pgs * pagesize);
1185 static void
1186 mem_info(apd_t *a, cfga_info_t info, int parsable)
1188 const char **p;
1189 sbd_mem_stat_t *dst;
1190 int want_progress;
1191 char *end = &info[sizeof (cfga_info_t)];
1193 DBG("mem_info(%p)\n", (void *)info);
1195 dst = (sbd_mem_stat_t *)a->cmstat;
1197 if (parsable)
1198 p = meminfo_parsable;
1199 else
1200 p = meminfo_nonparsable;
1202 info += snprintf(info, end - info, p[MI_ADDRESS],
1203 pages_to_bytes(dst->ms_basepfn));
1204 info += snprintf(info, end - info, p[MI_SIZE],
1205 pages_to_kbytes(dst->ms_totpages));
1207 if (dst->ms_noreloc_pages)
1208 info += snprintf(info, end - info, p[MI_PERMANENT],
1209 pages_to_kbytes(dst->ms_noreloc_pages));
1210 if (!dst->ms_cage_enabled)
1211 info += snprintf(info, end - info, p[MI_UNCONFIGURABLE]);
1212 if (dst->ms_interleave)
1213 info += snprintf(info, end - info, p[MI_INTERLEAVE]);
1216 * If there is a valid peer physical ap_id specified,
1217 * convert it to a logical id.
1219 want_progress = 0;
1220 if (str_valid(dst->ms_peer_ap_id)) {
1221 char *cm;
1222 char *peer;
1223 char physid[MAXPATHLEN];
1224 char logid[MAXPATHLEN];
1226 (void) snprintf(physid, sizeof (physid), "%s%s",
1227 DEVDIR, dst->ms_peer_ap_id);
1230 * Save the component portion of the physid and
1231 * add it back after converting to logical format.
1233 if ((cm = strstr(physid, "::")) != NULL) {
1234 *cm = '\0';
1235 cm += 2;
1238 /* attempt to resolve to symlink */
1239 if (ap_symid(a, physid, logid, sizeof (logid)) == 0)
1240 peer = logid;
1241 else
1242 peer = physid;
1244 if (dst->ms_peer_is_target) {
1245 info += snprintf(info, end - info, p[MI_TARGET], peer);
1246 if (cm)
1247 info += snprintf(info, end - info, "::%s", cm);
1248 want_progress = 1;
1249 } else {
1250 info += snprintf(info, end - info, p[MI_SOURCE], peer);
1251 if (cm)
1252 info += snprintf(info, end - info, "::%s", cm);
1255 if (want_progress ||
1256 (dst->ms_detpages != 0 && dst->ms_detpages != dst->ms_totpages)) {
1257 info += snprintf(info, end - info, p[MI_DELETED],
1258 pages_to_kbytes(dst->ms_detpages));
1259 info += snprintf(info, end - info, p[MI_REMAINING],
1260 pages_to_kbytes(dst->ms_totpages -
1261 dst->ms_detpages));
1265 #define II_DEVICE 0
1266 #define II_REFERENCED 1
1268 static const char *
1269 ioinfo[] = {
1270 "device %s",
1271 ", referenced"
1274 static const char *
1275 ioinfo_parsable[] = {
1276 "device=%s",
1277 " referenced"
1280 static void
1281 io_info(apd_t *a, cfga_info_t info, int parsable)
1283 const char **p;
1284 sbd_io_stat_t *dst;
1285 char *end = &info[sizeof (cfga_info_t)];
1287 dst = (sbd_io_stat_t *)a->cmstat;
1289 if (parsable)
1290 p = ioinfo_parsable;
1291 else
1292 p = ioinfo;
1294 info += snprintf(info, end - info, p[II_DEVICE], dst->is_pathname);
1295 if (dst->is_referenced)
1296 info += snprintf(info, end - info, p[II_REFERENCED]);
1299 #define PI_CPUID 0
1300 #define PI_CPUID_PAIR 1
1301 #define PI_CPUID_CONT 2
1302 #define PI_CPUID_LAST 3
1303 #define PI_SPEED 4
1304 #define PI_ECACHE 5
1306 static const char *
1307 cmpinfo[] = {
1308 "cpuid %d",
1309 " and %d",
1310 ", %d",
1311 ", and %d",
1312 ", speed %d MHz",
1313 ", ecache %d MBytes"
1316 static const char *
1317 cmpinfo_parsable[] = {
1318 "cpuid=%d",
1319 ",%d",
1320 ",%d",
1321 ",%d",
1322 " speed=%d",
1323 " ecache=%d"
1326 static void
1327 cmp_info(apd_t *a, cfga_info_t info, int parsable)
1329 int i;
1330 int last;
1331 const char **p;
1332 sbd_cmp_stat_t *dst;
1333 char *end = &info[sizeof (cfga_info_t)];
1335 DBG("cmp_info(%p)\n", (void *)info);
1337 dst = (sbd_cmp_stat_t *)a->cmstat;
1339 if (parsable)
1340 p = cmpinfo_parsable;
1341 else
1342 p = cmpinfo;
1344 /* Print the first cpuid */
1345 info += snprintf(info, end - info, p[PI_CPUID], dst->ps_cpuid[0]);
1348 * Print the middle cpuids, if necessary. Stop before
1349 * the last one, since printing the last cpuid is a
1350 * special case for the non parsable form.
1352 for (i = 1; i < (dst->ps_ncores - 1); i++) {
1353 info += snprintf(info, end - info, p[PI_CPUID_CONT],
1354 dst->ps_cpuid[i]);
1357 /* Print the last cpuid, if necessary */
1358 if (dst->ps_ncores > 1) {
1359 last = (dst->ps_ncores == 2) ? PI_CPUID_PAIR : PI_CPUID_LAST;
1360 info += snprintf(info, end - info,
1361 dgettext(TEXT_DOMAIN, p[last]), dst->ps_cpuid[i]);
1364 info += snprintf(info, end - info, p[PI_SPEED], dst->ps_speed);
1365 info += snprintf(info, end - info, p[PI_ECACHE], dst->ps_ecache);
1368 void
1369 ap_info(apd_t *a, cfga_info_t info, ap_target_t tgt)
1371 int parsable = ap_getopt(a, OPT_PARSABLE);
1373 DBG("ap_info(%p, %d)\n", (void *)info, parsable);
1375 switch (tgt) {
1376 case AP_BOARD:
1377 bd_info(a, info, parsable);
1378 break;
1379 case AP_CPU:
1380 cpu_info(a, info, parsable);
1381 break;
1382 case AP_MEM:
1383 mem_info(a, info, parsable);
1384 break;
1385 case AP_IO:
1386 io_info(a, info, parsable);
1387 break;
1388 case AP_CMP:
1389 cmp_info(a, info, parsable);
1390 break;
1391 default:
1392 break;