Home | History | Annotate | Download | only in common
      1  0  stevel /*
      2  0  stevel  * CDDL HEADER START
      3  0  stevel  *
      4  0  stevel  * The contents of this file are subject to the terms of the
      5  0  stevel  * Common Development and Distribution License, Version 1.0 only
      6  0  stevel  * (the "License").  You may not use this file except in compliance
      7  0  stevel  * with the License.
      8  0  stevel  *
      9  0  stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     10  0  stevel  * or http://www.opensolaris.org/os/licensing.
     11  0  stevel  * See the License for the specific language governing permissions
     12  0  stevel  * and limitations under the License.
     13  0  stevel  *
     14  0  stevel  * When distributing Covered Code, include this CDDL HEADER in each
     15  0  stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     16  0  stevel  * If applicable, add the following below this CDDL HEADER, with the
     17  0  stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     18  0  stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     19  0  stevel  *
     20  0  stevel  * CDDL HEADER END
     21  0  stevel  */
     22  0  stevel /*
     23  0  stevel  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
     24  0  stevel  * Use is subject to license terms.
     25  0  stevel  */
     26  0  stevel 
     27  0  stevel #pragma ident	"%Z%%M%	%I%	%E% SMI"
     28  0  stevel 
     29  0  stevel #include <ctype.h>
     30  0  stevel #include <stdio.h>
     31  0  stevel #include <stdlib.h>
     32  0  stevel #include <string.h>
     33  0  stevel #include <fcntl.h>
     34  0  stevel #include <unistd.h>
     35  0  stevel #include <libdevinfo.h>
     36  0  stevel #include <errno.h>
     37  0  stevel #include <libintl.h>
     38  0  stevel #define	CFGA_PLUGIN_LIB
     39  0  stevel #include <config_admin.h>
     40  0  stevel #include "ap.h"
     41  0  stevel #include <sys/obpdefs.h>
     42  0  stevel #include <sys/processor.h>
     43  0  stevel #include <sys/stat.h>
     44  0  stevel #include <sys/sbd_ioctl.h>
     45  0  stevel #include <sys/int_fmtio.h>
     46  0  stevel 
     47  0  stevel static cfga_err_t
     48  0  stevel ap_getncm(apd_t *a, sbd_comp_type_t type, int *ncm)
     49  0  stevel {
     50  0  stevel 	sbd_ioctl_arg_t *ctl;
     51  0  stevel 	sbd_getncm_cmd_t *cp;
     52  0  stevel 
     53  0  stevel 	if (a->fd == -1 || a->ctl == NULL)
     54  0  stevel 		return (CFGA_LIB_ERROR);
     55  0  stevel 
     56  0  stevel 	ctl = (sbd_ioctl_arg_t *)a->ctl;
     57  0  stevel 	ctl->ic_type = type;
     58  0  stevel 	ctl->ic_name[0] = '\0';
     59  0  stevel 	ctl->ic_unit = 0;
     60  0  stevel 	ctl->i_len = 0;
     61  0  stevel 	ctl->i_opts = NULL;
     62  0  stevel 
     63  0  stevel 	DBG("ioctl(%d SBD_CMD_GETNCM, 0x%p)\n", a->fd, (void *)ctl);
     64  0  stevel 
     65  0  stevel 	if (ioctl(a->fd, SBD_CMD_GETNCM, ctl) == -1) {
     66  0  stevel 		ap_err(a, ERR_CMD_FAIL, CMD_GETNCM);
     67  0  stevel 		return (CFGA_ERROR);
     68  0  stevel 	}
     69  0  stevel 
     70  0  stevel 	cp = &ctl->i_cmd.cmd_getncm;
     71  0  stevel 
     72  0  stevel 	DBG("ncm(%d)=%d\n", type, cp->g_ncm);
     73  0  stevel 
     74  0  stevel 	if (ncm)
     75  0  stevel 		*ncm = cp->g_ncm;
     76  0  stevel 
     77  0  stevel 	return (CFGA_OK);
     78  0  stevel }
     79  0  stevel 
     80  0  stevel cfga_err_t
     81  0  stevel ap_stat(apd_t *a, int all)
     82  0  stevel {
     83  0  stevel 	int fd;
     84  0  stevel 	int ncm;
     85  0  stevel 	int select;
     86  0  stevel 	int stsize;
     87  0  stevel 	int oflag;
     88  0  stevel 	sbd_stat_cmd_t *sc;
     89  0  stevel 	sbd_ioctl_arg_t *ctl;
     90  0  stevel 	cfga_err_t rc;
     91  0  stevel 	sbd_stat_t *new_stat;
     92  0  stevel 
     93  0  stevel 	rc = CFGA_LIB_ERROR;
     94  0  stevel 
     95  0  stevel 	DBG("ap_stat(%s)\n", a->path);
     96  0  stevel 
     97  0  stevel 	/* Open the file descriptor if not already open */
     98  0  stevel 	if (a->fd == -1) {
     99  0  stevel 		DBG("open(%s)\n", a->path);
    100  0  stevel 		if (a->statonly != 0)
    101  0  stevel 			oflag = O_RDONLY;
    102  0  stevel 		else
    103  0  stevel 			oflag = O_RDWR;
    104  0  stevel 		if ((fd = open(a->path, oflag, 0)) == -1) {
    105  0  stevel 			ap_err(a, ERR_AP_INVAL);
    106  0  stevel 			return (rc);
    107  0  stevel 		}
    108  0  stevel 		a->fd = fd;
    109  0  stevel 	} else {
    110  0  stevel 		fd = a->fd;
    111  0  stevel 	}
    112  0  stevel 
    113  0  stevel 	if (a->ctl == NULL && (a->ctl = calloc(1, sizeof (*ctl))) == NULL) {
    114  0  stevel 		ap_err(a, ERR_CMD_FAIL, CMD_STATUS);
    115  0  stevel 		return (rc);
    116  0  stevel 	}
    117  0  stevel 
    118  0  stevel 	if (a->tgt == AP_BOARD) {
    119  0  stevel 		/*
    120  0  stevel 		 * The status target is the board. If we need to
    121  0  stevel 		 * return component data (to support the -a option),
    122  0  stevel 		 * get the number of components on the board.
    123  0  stevel 		 */
    124  0  stevel 		select = 0;
    125  0  stevel 		if (all) {
    126  0  stevel 			cfga_err_t r;
    127  0  stevel 			r = ap_getncm(a, SBD_COMP_NONE, &ncm);
    128  0  stevel 			if (r != CFGA_OK) {
    129  0  stevel 				return (r);
    130  0  stevel 			}
    131  0  stevel 		} else {
    132  0  stevel 			ncm = 0;
    133  0  stevel 		}
    134  0  stevel 	} else {
    135  0  stevel 		select = 1;
    136  0  stevel 		ncm = 1;
    137  0  stevel 	}
    138  0  stevel 
    139  0  stevel 	DBG("ncm=%d\n", ncm);
    140  0  stevel 
    141  0  stevel 	a->ncm = ncm;
    142  0  stevel 
    143  0  stevel 	/*
    144  0  stevel 	 * The status structure contains space for one component;
    145  0  stevel 	 * add the space for the other components if necessary.
    146  0  stevel 	 */
    147  0  stevel 	stsize = sizeof (sbd_stat_t);
    148  0  stevel 	if (ncm > 1)
    149  0  stevel 		stsize += ((ncm - 1) * sizeof (sbd_dev_stat_t));
    150  0  stevel 
    151  0  stevel 	if ((new_stat = realloc(a->stat, stsize)) == NULL) {
    152  0  stevel 		ap_err(a, ERR_CMD_FAIL, CMD_STATUS);
    153  0  stevel 		return (rc);
    154  0  stevel 	}
    155  0  stevel 
    156  0  stevel 	a->stat = new_stat;
    157  0  stevel 
    158  0  stevel 
    159  0  stevel 	ctl = (sbd_ioctl_arg_t *)a->ctl;
    160  0  stevel 	ctl->i_len = 0;
    161  0  stevel 	ctl->i_opts = NULL;
    162  0  stevel 	ctl->ic_type = SBD_COMP_NONE;
    163  0  stevel 	if (all)
    164  0  stevel 		ctl->i_flags |= SBD_FLAG_ALLCMP;
    165  0  stevel 	sc = &ctl->i_cmd.cmd_stat;
    166  0  stevel 	sc->s_statp = (caddr_t)a->stat;
    167  0  stevel 	sc->s_nbytes = stsize;
    168  0  stevel 
    169  0  stevel 	if (select) {
    170  0  stevel 		/*
    171  0  stevel 		 * The target is a specific component.  Pass its
    172  0  stevel 		 * name and unit number to the driver.  Set its
    173  0  stevel 		 * type to UNKNOWN since the plugin does not know
    174  0  stevel 		 * the type of the component specified by the user.
    175  0  stevel 		 */
    176  0  stevel 		ctl->ic_type = SBD_COMP_UNKNOWN;
    177  0  stevel 		ctl->ic_unit = a->cnum;
    178  0  stevel 		strcpy(ctl->ic_name, a->cname);
    179  0  stevel 	}
    180  0  stevel 
    181  0  stevel 	DBG("ioctl(%d SBD_CMD_STATUS, sc=0x%p sz=%d flags=%d",
    182  0  stevel 		fd, (void *)sc->s_statp, sc->s_nbytes, ctl->i_flags);
    183  0  stevel 	if (select)
    184  0  stevel 		DBG(" cname=<%s> cnum=%d", a->cname, a->cnum);
    185  0  stevel 	DBG(")\n");
    186  0  stevel 
    187  0  stevel 	if (ioctl(fd, SBD_CMD_STATUS, ctl) == -1) {
    188  0  stevel 		ap_err(a, ERR_CMD_FAIL, CMD_STATUS);
    189  0  stevel 		rc = CFGA_ERROR;
    190  0  stevel 	} else
    191  0  stevel 		rc = CFGA_OK;
    192  0  stevel 
    193  0  stevel 	DBG("ap_stat()=%d\n", rc);
    194  0  stevel 
    195  0  stevel 	return (rc);
    196  0  stevel }
    197  0  stevel 
    198  0  stevel /*
    199  0  stevel  * Convert a component to a target type.
    200  0  stevel  */
    201  0  stevel static ap_target_t
    202  0  stevel ap_cm_tgt(sbd_comp_type_t type)
    203  0  stevel {
    204  0  stevel 	ap_target_t c;
    205  0  stevel 
    206  0  stevel 	switch (type) {
    207  0  stevel 	case SBD_COMP_CPU:
    208  0  stevel 		c = AP_CPU;
    209  0  stevel 		break;
    210  0  stevel 	case SBD_COMP_MEM:
    211  0  stevel 		c = AP_MEM;
    212  0  stevel 		break;
    213  0  stevel 	case SBD_COMP_IO:
    214  0  stevel 		c = AP_IO;
    215  0  stevel 		break;
    216  0  stevel 	case SBD_COMP_CMP:
    217  0  stevel 		c = AP_CMP;
    218  0  stevel 		break;
    219  0  stevel 	default:
    220  0  stevel 		c = AP_NONE;
    221  0  stevel 		break;
    222  0  stevel 	}
    223  0  stevel 
    224  0  stevel 	return (c);
    225  0  stevel }
    226  0  stevel 
    227  0  stevel cfga_err_t
    228  0  stevel apd_init(apd_t *a, int all)
    229  0  stevel {
    230  0  stevel 	int i;
    231  0  stevel 	char *cn, *dn;
    232  0  stevel 	sbd_stat_t *st;
    233  0  stevel 	sbd_dev_stat_t *dst;
    234  0  stevel 	cfga_err_t rc;
    235  0  stevel 
    236  0  stevel 	/*
    237  0  stevel 	 * Ideally, for board operations (other than status) it is not
    238  0  stevel 	 * necessary to issue the STATUS ioctl.  The call however allows a
    239  0  stevel 	 * final sanity check to ensure that the board number returned
    240  0  stevel 	 * by the driver matches the plugin's notion of the board number
    241  0  stevel 	 * as extracted from the ap_id.  If this check is not desirable,
    242  0  stevel 	 * we can change the code to issue the status call only when
    243  0  stevel 	 * necessary.  Note that for component operations, we need to do
    244  0  stevel 	 * the STATUS in order to figure out the component type and
    245  0  stevel 	 * validate the command/options accordingly. XXX
    246  0  stevel 	 */
    247  0  stevel 	if ((rc = ap_stat(a, all)) != CFGA_OK) {
    248  0  stevel 		ap_err(a, ERR_AP_INVAL);
    249  0  stevel 		return (rc);
    250  0  stevel 	}
    251  0  stevel 
    252  0  stevel 	st = (sbd_stat_t *)a->stat;
    253  0  stevel 
    254  0  stevel 	/*
    255  0  stevel 	 * Set the component count to the returned stat count.
    256  0  stevel 	 */
    257  0  stevel 	if (a->ncm > st->s_nstat) {
    258  0  stevel 
    259  0  stevel 		DBG("ncm=%d nstat=%d (truncated)\n", a->ncm, st->s_nstat);
    260  0  stevel 
    261  0  stevel 		a->ncm = st->s_nstat;
    262  0  stevel 	}
    263  0  stevel 
    264  0  stevel 	if (a->tgt == AP_BOARD) {
    265  0  stevel 
    266  0  stevel 		DBG("tgt=%d\n", a->tgt);
    267  0  stevel 
    268  0  stevel 		/*
    269  0  stevel 		 * Initialize the RCM module here so that it can record
    270  0  stevel 		 * the initial state of the capacity information.
    271  0  stevel 		 */
    272  0  stevel 		rc = ap_rcm_init(a);
    273  0  stevel 
    274  0  stevel 		return (rc);
    275  0  stevel 	}
    276  0  stevel 
    277  0  stevel 	a->tgt = AP_NONE;
    278  0  stevel 	cn = a->cname;
    279  0  stevel 
    280  0  stevel 	DBG("cname=<%s> cunit=<%d>\n", a->cname, a->cnum);
    281  0  stevel 
    282  0  stevel 	for (dst = st->s_stat, i = 0; i < st->s_nstat; i++, dst++) {
    283  0  stevel 
    284  0  stevel 		DBG("ds_name,ds_unit,ds_type=<%s,%d,%d> ",
    285  0  stevel 			dst->ds_name, dst->ds_unit, dst->ds_type);
    286  0  stevel 
    287  0  stevel 		if (dst->ds_unit != a->cnum)
    288  0  stevel 			continue;
    289  0  stevel 
    290  0  stevel 		/*
    291  0  stevel 		 * Consider the names matched if they are either
    292  0  stevel 		 * both absent or the same. It is conceivable that
    293  0  stevel 		 * a NULL component name be considered valid
    294  0  stevel 		 * by the driver.
    295  0  stevel 		 */
    296  0  stevel 		dn = dst->ds_name;
    297  0  stevel 
    298  0  stevel 		if ((dn == NULL && cn == NULL) ||
    299  0  stevel 		    (dn != NULL && cn != NULL && strcmp(dn, cn) == 0)) {
    300  0  stevel 			a->tgt = ap_cm_tgt(dst->ds_type);
    301  0  stevel 			a->cmstat = (void *)dst;
    302  0  stevel 
    303  0  stevel 			DBG("found ");
    304  0  stevel 
    305  0  stevel 			break;
    306  0  stevel 		}
    307  0  stevel 	}
    308  0  stevel 
    309  0  stevel 	DBG("tgt=%d\n", a->tgt);
    310  0  stevel 
    311  0  stevel 	if (a->tgt == AP_NONE) {
    312  0  stevel 		ap_err(a, ERR_CM_INVAL, a->cid);
    313  0  stevel 		return (CFGA_INVAL);
    314  0  stevel 	}
    315  0  stevel 
    316  0  stevel 	/*
    317  0  stevel 	 * Initialize the RCM module here so that it can record
    318  0  stevel 	 * the initial state of the capacity information.
    319  0  stevel 	 */
    320  0  stevel 	rc = ap_rcm_init(a);
    321  0  stevel 
    322  0  stevel 	return (rc);
    323  0  stevel }
    324  0  stevel 
    325  0  stevel void
    326  0  stevel apd_free(apd_t *a)
    327  0  stevel {
    328  0  stevel 	if (a == NULL)
    329  0  stevel 		return;
    330  0  stevel 
    331  0  stevel 	ap_rcm_fini(a);
    332  0  stevel 
    333  0  stevel 	if (a->fd != -1)
    334  0  stevel 		close(a->fd);
    335  0  stevel 
    336  0  stevel 	s_free(a->options);
    337  0  stevel 	s_free(a->path);
    338  0  stevel 	s_free(a->drv);
    339  0  stevel 	s_free(a->target);
    340  0  stevel 	s_free(a->cname);
    341  0  stevel 	s_free(a->ctl);
    342  0  stevel 	s_free(a->stat);
    343  0  stevel 
    344  0  stevel 	free(a);
    345  0  stevel }
    346  0  stevel 
    347  0  stevel apd_t *
    348  0  stevel apd_alloc(const char *ap_id, cfga_flags_t flags, char **errstring,
    349  0  stevel 	struct cfga_msg *msgp, struct cfga_confirm *confp)
    350  0  stevel {
    351  0  stevel 	apd_t *a;
    352  0  stevel 
    353  0  stevel 	if ((a = calloc(1, sizeof (*a))) == NULL)
    354  0  stevel 		return (NULL);
    355  0  stevel 
    356  0  stevel 	if (errstring != NULL)
    357  0  stevel 		*errstring = NULL;
    358  0  stevel 
    359  0  stevel 	a->fd = -1;
    360  0  stevel 	a->errstring = errstring;
    361  0  stevel 	a->msgp = msgp;
    362  0  stevel 	a->confp = confp;
    363  0  stevel 	a->class = "sbd";
    364  0  stevel 
    365  0  stevel 	if (flags & CFGA_FLAG_LIST_ALL)
    366  0  stevel 		ap_setopt(a, OPT_LIST_ALL);
    367  0  stevel 	if (flags & CFGA_FLAG_FORCE)
    368  0  stevel 		ap_setopt(a, OPT_FORCE);
    369  0  stevel 	if (flags & CFGA_FLAG_VERBOSE)
    370  0  stevel 		ap_setopt(a, OPT_VERBOSE);
    371  0  stevel 
    372  0  stevel 	if (ap_id == NULL || ap_parse(a, ap_id) == 0)
    373  0  stevel 		return (a);
    374  0  stevel 
    375  0  stevel 	apd_free(a);
    376  0  stevel 	return (NULL);
    377  0  stevel }
    378  0  stevel 
    379  0  stevel /*
    380  0  stevel  * The type field is defined to be parsable by cfgadm(1M): It
    381  0  stevel  * must not contain white space characters. This function
    382  0  stevel  * converts white space to underscore.
    383  0  stevel  */
    384  0  stevel 
    385  0  stevel static void
    386  0  stevel parsable_strncpy(char *op, const char *ip, size_t n)
    387  0  stevel {
    388  0  stevel 	char c;
    389  0  stevel 
    390  0  stevel 	while (n-- > 0) {
    391  0  stevel 		c = *ip++;
    392  0  stevel 		if (isspace(c))
    393  0  stevel 			c = '_';
    394  0  stevel 		*op++ = c;
    395  0  stevel 		if (c == '\0')
    396  0  stevel 			break;
    397  0  stevel 	}
    398  0  stevel }
    399  0  stevel 
    400  0  stevel void
    401  0  stevel ap_init(apd_t *a, cfga_list_data_t *ap)
    402  0  stevel {
    403  0  stevel 	sbd_stat_t *st;
    404  0  stevel 
    405  0  stevel 	st = (sbd_stat_t *)a->stat;
    406  0  stevel 
    407  0  stevel 	DBG("ap_init bd=%d rs=%d os=%d type=<%s>\n",
    408  0  stevel 		a->bnum, st->s_rstate, st->s_ostate, st->s_type);
    409  0  stevel 
    410  0  stevel 	parsable_strncpy(ap->ap_type, st->s_type, sizeof (ap->ap_type));
    411  0  stevel 	ap->ap_r_state = (cfga_stat_t)st->s_rstate;
    412  0  stevel 	ap->ap_o_state = (cfga_stat_t)st->s_ostate;
    413  0  stevel 	ap->ap_cond = (cfga_cond_t)st->s_cond;
    414  0  stevel 	ap->ap_busy = (cfga_busy_t)st->s_busy;
    415  0  stevel 	ap->ap_status_time = st->s_time;
    416  0  stevel 	ap_info(a, ap->ap_info, AP_BOARD);
    417  0  stevel }
    418  0  stevel 
    419  0  stevel typedef struct {
    420  0  stevel 	int cmd;
    421  0  stevel 	int ioc;
    422  0  stevel } ap_ioc_t;
    423  0  stevel 
    424  0  stevel static ap_ioc_t
    425  0  stevel ap_iocs[] =  {
    426  0  stevel 	{CMD_ASSIGN,	  SBD_CMD_ASSIGN	},
    427  0  stevel 	{CMD_POWERON,	  SBD_CMD_POWERON	},
    428  0  stevel 	{CMD_TEST,	  SBD_CMD_TEST		},
    429  0  stevel 	{CMD_CONNECT,	  SBD_CMD_CONNECT	},
    430  0  stevel 	{CMD_CONFIGURE,	  SBD_CMD_CONFIGURE	},
    431  0  stevel 	{CMD_UNCONFIGURE, SBD_CMD_UNCONFIGURE	},
    432  0  stevel 	{CMD_DISCONNECT,  SBD_CMD_DISCONNECT	},
    433  0  stevel 	{CMD_POWEROFF,	  SBD_CMD_POWEROFF	},
    434  0  stevel 	{CMD_STATUS,	  SBD_CMD_STATUS	},
    435  0  stevel 	{CMD_GETNCM,	  SBD_CMD_GETNCM	},
    436  0  stevel 	{CMD_UNASSIGN,	  SBD_CMD_UNASSIGN	},
    437  0  stevel 	{CMD_PASSTHRU,	  SBD_CMD_PASSTHRU	},
    438  0  stevel 	{CMD_NONE,	  0			}
    439  0  stevel };
    440  0  stevel 
    441  0  stevel static int
    442  0  stevel ap_ioc(int cmd)
    443  0  stevel {
    444  0  stevel 	ap_ioc_t *acp;
    445  0  stevel 
    446  0  stevel 	DBG("ap_ioc(%d)\n", cmd);
    447  0  stevel 
    448  0  stevel 	for (acp = ap_iocs; acp->cmd != CMD_NONE; acp++)
    449  0  stevel 		if (acp->cmd == cmd)
    450  0  stevel 			break;
    451  0  stevel 
    452  0  stevel 	DBG("ap_ioc(%d)=0x%x\n", cmd, acp->ioc);
    453  0  stevel 
    454  0  stevel 	return (acp->ioc);
    455  0  stevel }
    456  0  stevel 
    457  0  stevel cfga_err_t
    458  0  stevel ap_suspend_query(apd_t *a, int cmd, int *check)
    459  0  stevel {
    460  0  stevel 	int ioc;
    461  0  stevel 	sbd_dev_stat_t *dst;
    462  0  stevel 
    463  0  stevel 	/*
    464  0  stevel 	 * See if the a quiesce operation is required for
    465  0  stevel 	 * this command for any of the components.  If the
    466  0  stevel 	 * command does not map to an ioctl, then there is
    467  0  stevel 	 * nothing to do.
    468  0  stevel 	 */
    469  0  stevel 	if ((ioc = ap_ioc(cmd)) == 0)
    470  0  stevel 		return (CFGA_OK);
    471  0  stevel 	else if (a->tgt == AP_BOARD) {
    472  0  stevel 		int i;
    473  0  stevel 
    474  0  stevel 		dst = ((sbd_stat_t *)a->stat)->s_stat;
    475  0  stevel 
    476  0  stevel 		/*
    477  0  stevel 		 * See if any component requires a
    478  0  stevel 		 * OS suspension for this command.
    479  0  stevel 		 */
    480  0  stevel 		for (i = 0; i < a->ncm; i++, dst++)
    481  0  stevel 			if (SBD_CHECK_SUSPEND(ioc, dst->ds_suspend))
    482  0  stevel 				(*check)++;
    483  0  stevel 	} else {
    484  0  stevel 		dst = (sbd_dev_stat_t *)a->cmstat;
    485  0  stevel 		if (SBD_CHECK_SUSPEND(ioc, dst->ds_suspend))
    486  0  stevel 				(*check)++;
    487  0  stevel 	}
    488  0  stevel 
    489  0  stevel 	return (CFGA_OK);
    490  0  stevel }
    491  0  stevel 
    492  0  stevel cfga_err_t
    493  0  stevel ap_platopts_check(apd_t *a, int first, int last)
    494  0  stevel {
    495  0  stevel 	int c;
    496  0  stevel 	uint_t platopts;
    497  0  stevel 	sbd_stat_t *stat;
    498  0  stevel 	ap_opts_t *opts;
    499  0  stevel 
    500  0  stevel 	opts = &a->opts;
    501  0  stevel 	stat = (sbd_stat_t *)a->stat;
    502  0  stevel 	platopts = stat->s_platopts;
    503  0  stevel 
    504  0  stevel 
    505  0  stevel 	/*
    506  0  stevel 	 * If there are no platform options set then there
    507  0  stevel 	 * is no need to check this operation
    508  0  stevel 	 */
    509  0  stevel 	if (opts->platform == NULL)
    510  0  stevel 		return (CFGA_OK);
    511  0  stevel 
    512  0  stevel 	/*
    513  0  stevel 	 * Check if any of the steps in the sequence
    514  0  stevel 	 * allows for a platform option
    515  0  stevel 	 */
    516  0  stevel 	for (c = first; c <= last; c++)
    517  0  stevel 		/*
    518  0  stevel 		 * If the platopt is set it means that the platform does not
    519  0  stevel 		 * support options for this cmd
    520  0  stevel 		 */
    521  0  stevel 		if (SBD_CHECK_PLATOPTS(ap_ioc(c), platopts) == 0) {
    522  0  stevel 			return (CFGA_OK);
    523  0  stevel 		}
    524  0  stevel 
    525  0  stevel 	ap_err(a, ERR_OPT_INVAL, opts->platform);
    526  0  stevel 
    527  0  stevel 	return (CFGA_INVAL);
    528  0  stevel }
    529  0  stevel 
    530  0  stevel cfga_err_t
    531  0  stevel ap_ioctl(apd_t *a, int cmd)
    532  0  stevel {
    533  0  stevel 	int ioc;
    534  0  stevel 	sbd_ioctl_arg_t *ctl;
    535  0  stevel 
    536  0  stevel 	if (a->ctl == NULL && (a->ctl = calloc(1, sizeof (*ctl))) == NULL) {
    537  0  stevel 		ap_err(a, ERR_CMD_FAIL, cmd);
    538  0  stevel 		return (CFGA_LIB_ERROR);
    539  0  stevel 	}
    540  0  stevel 
    541  0  stevel 	ap_msg(a, MSG_ISSUE, cmd, a->target);
    542  0  stevel 
    543  0  stevel 	ctl = (sbd_ioctl_arg_t *)a->ctl;
    544  0  stevel 	ctl->i_flags = 0;
    545  0  stevel 	ctl->i_len = 0;
    546  0  stevel 	ctl->i_opts = NULL;
    547  0  stevel 
    548  0  stevel 	if (ap_getopt(a, OPT_FORCE))
    549  0  stevel 		ctl->i_flags |= SBD_FLAG_FORCE;
    550  0  stevel 	if (ap_getopt(a, OPT_SUSPEND_OK))
    551  0  stevel 		ctl->i_flags |= SBD_FLAG_QUIESCE_OKAY;
    552  0  stevel 
    553  0  stevel 	if (a->tgt == AP_BOARD)
    554  0  stevel 		ctl->ic_type = SBD_COMP_NONE;
    555  0  stevel 	else {
    556  0  stevel 		ctl->ic_type = SBD_COMP_UNKNOWN;
    557  0  stevel 		ctl->ic_unit = a->cnum;
    558  0  stevel 		strcpy(ctl->ic_name, a->cname);
    559  0  stevel 	}
    560  0  stevel 
    561  0  stevel 	if (!(ioc = ap_ioc(cmd))) {
    562  0  stevel 		ap_err(a, ERR_CMD_FAIL, cmd);
    563  0  stevel 		return (CFGA_LIB_ERROR);
    564  0  stevel 	}
    565  0  stevel 
    566  0  stevel 	/*
    567  0  stevel 	 * If this is a passthru command, pass all of its
    568  0  stevel 	 * options; otherwise, pass all options after the
    569  0  stevel 	 * platform keyword.
    570  0  stevel 	 */
    571  0  stevel 	if (cmd == CMD_PASSTHRU)
    572  0  stevel 		ctl->i_opts = a->options;
    573  0  stevel 	else {
    574  0  stevel 		/*
    575  0  stevel 		 * Only pass the platform option to the cmds that the platform
    576  0  stevel 		 * has specified as ok
    577  0  stevel 		 */
    578  0  stevel 		sbd_stat_t *stat;
    579  0  stevel 
    580  0  stevel 		stat = (sbd_stat_t *)a->stat;
    581  0  stevel 		if (SBD_CHECK_PLATOPTS(ioc, stat->s_platopts) == 0)
    582  0  stevel 			ctl->i_opts = a->opts.platform;
    583  0  stevel 	}
    584  0  stevel 
    585  0  stevel 	if (ctl->i_opts != NULL)
    586  0  stevel 		ctl->i_len = strlen(ctl->i_opts) + 1;
    587  0  stevel 
    588  0  stevel 	DBG("i_opts=%s\n", ctl->i_opts ? ctl->i_opts : "NULL");
    589  0  stevel 	DBG("i_flags=0x%x\n", ctl->i_flags);
    590  0  stevel 
    591  0  stevel 	if (ap_getopt(a, OPT_SIM)) {
    592  0  stevel 		ap_msg(a, MSG_DONE, cmd, a->target);
    593  0  stevel 		return (CFGA_OK);
    594  0  stevel 	}
    595  0  stevel 
    596  0  stevel 	if (ioctl(a->fd, ioc, ctl) == -1) {
    597  0  stevel 		ap_err(a, ERR_CMD_FAIL, cmd);
    598  0  stevel 		return (CFGA_ERROR);
    599  0  stevel 	}
    600  0  stevel 	ap_msg(a, MSG_DONE, cmd, a->target);
    601  0  stevel 
    602  0  stevel 	return (CFGA_OK);
    603  0  stevel }
    604  0  stevel 
    605  0  stevel /*
    606  0  stevel  * Return the error string corresponding to a given error code.
    607  0  stevel  * String table and error code sets are provided by sbd_etab.  This data
    608  0  stevel  * structure is automatically generated at compile time from the error
    609  0  stevel  * code and message text information in sbd_ioctl.h.
    610  0  stevel  */
    611  0  stevel static char *
    612  0  stevel mod_estr(int code)
    613  0  stevel {
    614  0  stevel 	int i;
    615  0  stevel 	char *s;
    616  0  stevel 	extern sbd_etab_t sbd_etab[];
    617  0  stevel 	extern int sbd_etab_len;
    618  0  stevel 
    619  0  stevel 	s = NULL;
    620  0  stevel 
    621  0  stevel 	for (i = 0; i < sbd_etab_len; i++) {
    622  0  stevel 		sbd_etab_t *eptr = &sbd_etab[i];
    623  0  stevel 
    624  0  stevel 		if ((code >= eptr->t_base) && (code <= eptr->t_bnd)) {
    625  0  stevel 			int index;
    626  0  stevel 			char **t_text;
    627  0  stevel 
    628  0  stevel 			/*
    629  0  stevel 			 * Found it. Just extract the string
    630  0  stevel 			 */
    631  0  stevel 			index = code - eptr->t_base;
    632  0  stevel 			t_text = eptr->t_text;
    633  0  stevel 			s = strdup(t_text[index]);
    634  0  stevel 			break;
    635  0  stevel 		}
    636  0  stevel 	}
    637  0  stevel 
    638  0  stevel 	if (i == sbd_etab_len) {
    639  0  stevel 		char buf[32];
    640  0  stevel 
    641  0  stevel 		snprintf(buf, sizeof (buf), "error %d", code);
    642  0  stevel 		s = strdup(buf);
    643  0  stevel 	}
    644  0  stevel 
    645  0  stevel 	return (s);
    646  0  stevel }
    647  0  stevel 
    648  0  stevel char *
    649  0  stevel ap_sys_err(apd_t *a, char **rp)
    650  0  stevel {
    651  0  stevel 	int code;
    652  0  stevel 	char *p;
    653  0  stevel 	char *rsc;
    654  0  stevel 
    655  0  stevel 	sbd_ioctl_arg_t *ctl = (sbd_ioctl_arg_t *)a->ctl;
    656  0  stevel 
    657  0  stevel 	/*
    658  0  stevel 	 * The driver sets the errno to EIO if it returns
    659  0  stevel 	 * more detailed error info via e_code.  In all
    660  0  stevel 	 * other cases, use standard error text.
    661  0  stevel 	 */
    662  0  stevel 	if (ctl == NULL || errno != EIO) {
    663  0  stevel 		if ((p = strerror(errno)) != NULL)
    664  0  stevel 			p = strdup(p);
    665  0  stevel 		return (p);
    666  0  stevel 	}
    667  0  stevel 
    668  0  stevel 	code = ctl->ie_code;
    669  0  stevel 	rsc = ctl->ie_rsc;
    670  0  stevel 
    671  0  stevel 	if (code)
    672  0  stevel 		p = mod_estr(code);
    673  0  stevel 	else if ((p = strerror(errno)) != NULL)
    674  0  stevel 		p = strdup(p);
    675  0  stevel 
    676  0  stevel 	if (*rsc != '\0' && rp != NULL)
    677  0  stevel 		*rp = strdup(rsc);
    678  0  stevel 
    679  0  stevel 	return (p);
    680  0  stevel }
    681  0  stevel 
    682  0  stevel /*
    683  0  stevel  * cfgadm -o err=plugin-err,cmd=name,code=ecode -x errtest ap_id.
    684  0  stevel  */
    685  0  stevel cfga_err_t
    686  0  stevel ap_test_err(apd_t *a, const char *options)
    687  0  stevel {
    688  0  stevel 	int err;
    689  0  stevel 	int cmd;
    690  0  stevel 	ap_opts_t *opts;
    691  0  stevel 	sbd_ioctl_arg_t ctl;
    692  0  stevel 
    693  0  stevel 	opts = &a->opts;
    694  0  stevel 	err = opts->err;
    695  0  stevel 	cmd = CMD_DISCONNECT;
    696  0  stevel 
    697  0  stevel 	DBG("ap_test_err(%d %d)\n", opts->code, opts->err);
    698  0  stevel 
    699  0  stevel 	switch (err) {
    700  0  stevel 	case ERR_CMD_INVAL:
    701  0  stevel 		ap_err(a, err, ap_cmd_name(cmd));
    702  0  stevel 		break;
    703  0  stevel 	case ERR_CMD_NOTSUPP:
    704  0  stevel 		ap_err(a, err, cmd);
    705  0  stevel 		break;
    706  0  stevel 	case ERR_CMD_FAIL:
    707  0  stevel 		errno = EIO;
    708  0  stevel 		ctl.i_err.e_code = opts->code;
    709  0  stevel 		*ctl.i_err.e_rsc = '\0';
    710  0  stevel 		a->ctl = &ctl;
    711  0  stevel 		ap_err(a, err, cmd);
    712  0  stevel 		a->ctl = NULL;
    713  0  stevel 		break;
    714  0  stevel 	case ERR_OPT_INVAL:
    715  0  stevel 		ap_err(a, err, options);
    716  0  stevel 		break;
    717  0  stevel 	case ERR_OPT_NOVAL:
    718  0  stevel 		ap_err(a, err, options);
    719  0  stevel 		break;
    720  0  stevel 	case ERR_AP_INVAL:
    721  0  stevel 		ap_err(a, err);
    722  0  stevel 		break;
    723  0  stevel 	case ERR_CM_INVAL:
    724  0  stevel 		ap_err(a, err, a->cid);
    725  0  stevel 		break;
    726  0  stevel 	case ERR_TRANS_INVAL:
    727  0  stevel 		ap_err(a, ERR_TRANS_INVAL, cmd);
    728  0  stevel 		break;
    729  0  stevel 	}
    730  0  stevel 
    731  0  stevel 	return (CFGA_LIB_ERROR);
    732  0  stevel }
    733  0  stevel 
    734  0  stevel static char *
    735  0  stevel ap_help_topics[] = {
    736  0  stevel 	"\nSbd specific commands/options:\n\n",
    737  0  stevel 	"\tcfgadm [-o parsable] -l ap_id\n",
    738  0  stevel 	"\tcfgadm [-o unassign|nopoweroff] -c disconnect ap_id\n",
    739  0  stevel 	"\tcfgadm -t ap_id\n",
    740  0  stevel 	"\tcfgadm -x assign ap_id\n",
    741  0  stevel 	"\tcfgadm -x unassign ap_id\n",
    742  0  stevel 	"\tcfgadm -x poweron ap_id\n",
    743  0  stevel 	"\tcfgadm -x poweroff ap_id\n",
    744  0  stevel 	NULL
    745  0  stevel };
    746  0  stevel 
    747  0  stevel /*ARGSUSED*/
    748  0  stevel cfga_err_t
    749  0  stevel ap_help(struct cfga_msg *msgp, const char *options, cfga_flags_t flags)
    750  0  stevel {
    751  0  stevel 	int len;
    752  0  stevel 	char **p;
    753  0  stevel 	char *q;
    754  0  stevel 
    755  0  stevel 	if (msgp == NULL || msgp->message_routine == NULL)
    756  0  stevel 		return (CFGA_OK);
    757  0  stevel 
    758  0  stevel 	for (p = ap_help_topics; *p != NULL; p++) {
    759  0  stevel 		if ((len = strlen(*p)) == 0)
    760  0  stevel 			continue;
    761  0  stevel 		if ((q = (char *)calloc(len + 1, 1)) == NULL)
    762  0  stevel 			continue;
    763  0  stevel 		strcpy(q, *p);
    764  0  stevel 		(*msgp->message_routine)(msgp->appdata_ptr, q);
    765  0  stevel 		free(q);
    766  0  stevel 	}
    767  0  stevel 
    768  0  stevel 	return (CFGA_OK);
    769  0  stevel }
    770  0  stevel 
    771  0  stevel static char *
    772  0  stevel ap_dev_type(sbd_dev_stat_t *dst)
    773  0  stevel {
    774  0  stevel 	char *type;
    775  0  stevel 
    776  0  stevel 	switch (dst->ds_type) {
    777  0  stevel 	case SBD_COMP_CPU:
    778  0  stevel 		type = "cpu";
    779  0  stevel 		break;
    780  0  stevel 	case SBD_COMP_MEM:
    781  0  stevel 		type = "memory";
    782  0  stevel 		break;
    783  0  stevel 	case SBD_COMP_IO:
    784  0  stevel 		type = "io";
    785  0  stevel 		break;
    786  0  stevel 	case SBD_COMP_CMP:
    787  0  stevel 		type = "cpu";
    788  0  stevel 		break;
    789  0  stevel 	default:
    790  0  stevel 		type = "other";
    791  0  stevel 		break;
    792  0  stevel 	}
    793  0  stevel 
    794  0  stevel 	DBG("ap_dev_type(%d)=%s\n", dst->ds_type, type);
    795  0  stevel 
    796  0  stevel 	return (type);
    797  0  stevel }
    798  0  stevel 
    799  0  stevel static sbd_dev_stat_t *
    800  0  stevel ap_cm_stat(apd_t *a, int seq)
    801  0  stevel {
    802  0  stevel 	sbd_stat_t *st;
    803  0  stevel 
    804  0  stevel 	if (seq == CM_DFLT)
    805  0  stevel 		return (a->cmstat);
    806  0  stevel 
    807  0  stevel 	st = (sbd_stat_t *)a->stat;
    808  0  stevel 	return (st->s_stat + seq);
    809  0  stevel }
    810  0  stevel 
    811  0  stevel char *
    812  0  stevel ap_cm_devpath(apd_t *a, int seq)
    813  0  stevel {
    814  0  stevel 	int len;
    815  0  stevel 	char *path;
    816  0  stevel 	char *devpath;
    817  0  stevel 	sbd_io_stat_t *dst;
    818  0  stevel 
    819  0  stevel 
    820  0  stevel 	/*
    821  0  stevel 	 * If no component sequence number is provided
    822  0  stevel 	 * default to the current target component.
    823  0  stevel 	 * Assume an io component so that we can get
    824  0  stevel 	 * the path if the component is indeed of type io.
    825  0  stevel 	 */
    826  0  stevel 	if (seq == -1)
    827  0  stevel 		dst = (sbd_io_stat_t *)a->cmstat;
    828  0  stevel 	else {
    829  0  stevel 		sbd_stat_t *st;
    830  0  stevel 		st = (sbd_stat_t *)a->stat;
    831  0  stevel 		dst = (sbd_io_stat_t *)st->s_stat + seq;
    832  0  stevel 	}
    833  0  stevel 
    834  0  stevel 	if (dst->is_type != SBD_COMP_IO)
    835  0  stevel 		path = NULL;
    836  0  stevel 	else
    837  0  stevel 		path = dst->is_pathname;
    838  0  stevel 
    839  0  stevel 	if (str_valid(path)) {
    840  0  stevel 		len = strlen(DEVDIR) + strlen(path) + 1;
    841  0  stevel 
    842  0  stevel 		if ((devpath = calloc(1, len)) == NULL)
    843  0  stevel 			return (NULL);
    844  0  stevel 
    845  0  stevel 		(void) snprintf(devpath, len, "%s%s", DEVDIR, path);
    846  0  stevel 	} else
    847  0  stevel 		devpath = NULL;
    848  0  stevel 
    849  0  stevel 	DBG("ap_cm_path(%d)=%s\n", seq, devpath ? devpath : "");
    850  0  stevel 
    851  0  stevel 	return (devpath);
    852  0  stevel }
    853  0  stevel 
    854  0  stevel void
    855  0  stevel ap_cm_id(apd_t *a, int seq, char *id, size_t bufsize)
    856  0  stevel {
    857  0  stevel 	int unit;
    858  0  stevel 	char *name;
    859  0  stevel 	sbd_dev_stat_t *dst;
    860  0  stevel 
    861  0  stevel 	dst = ap_cm_stat(a, seq);
    862  0  stevel 
    863  0  stevel 	unit = dst->ds_unit;
    864  0  stevel 	name = dst->ds_name;
    865  0  stevel 
    866  0  stevel 	/*
    867  0  stevel 	 * If the component has a unit number,
    868  0  stevel 	 * add it to the id, otherwise just use
    869  0  stevel 	 * the component's name.
    870  0  stevel 	 */
    871  0  stevel 	if (unit == -1)
    872  0  stevel 		(void) snprintf(id, bufsize, "%s", name);
    873  0  stevel 	else
    874  0  stevel 		(void) snprintf(id, bufsize, "%s%d", name, unit);
    875  0  stevel 
    876  0  stevel 	DBG("ap_cm_id(%d)=%s\n", seq, id);
    877  0  stevel }
    878  0  stevel 
    879  0  stevel /*
    880  0  stevel  * Convert a component to a target type.
    881  0  stevel  */
    882  0  stevel ap_target_t
    883  0  stevel ap_cm_type(apd_t *a, int seq)
    884  0  stevel {
    885  0  stevel 	ap_target_t c;
    886  0  stevel 	sbd_dev_stat_t *dst;
    887  0  stevel 
    888  0  stevel 	dst = ap_cm_stat(a, seq);
    889  0  stevel 
    890  0  stevel 	switch (dst->ds_type) {
    891  0  stevel 	case SBD_COMP_CPU:
    892  0  stevel 		c = AP_CPU;
    893  0  stevel 		break;
    894  0  stevel 	case SBD_COMP_MEM:
    895  0  stevel 		c = AP_MEM;
    896  0  stevel 		break;
    897  0  stevel 	case SBD_COMP_IO:
    898  0  stevel 		c = AP_IO;
    899  0  stevel 		break;
    900  0  stevel 	case SBD_COMP_CMP:
    901  0  stevel 		c = AP_CMP;
    902  0  stevel 		break;
    903  0  stevel 	default:
    904  0  stevel 		c = AP_NONE;
    905  0  stevel 		break;
    906  0  stevel 	}
    907  0  stevel 
    908  0  stevel 	return (c);
    909  0  stevel }
    910  0  stevel 
    911  0  stevel int
    912  0  stevel ap_cm_ncap(apd_t *a, int seq)
    913  0  stevel {
    914  0  stevel 	sbd_dev_stat_t	*dst;
    915  0  stevel 	int		ncap;
    916  0  stevel 
    917  0  stevel 	dst = ap_cm_stat(a, seq);
    918  0  stevel 
    919  0  stevel 	switch (dst->ds_type) {
    920  0  stevel 	case SBD_COMP_CPU:
    921  0  stevel 	case SBD_COMP_MEM:
    922  0  stevel 	case SBD_COMP_IO:
    923  0  stevel 		ncap = 1;
    924  0  stevel 		break;
    925  0  stevel 	case SBD_COMP_CMP:
    926  0  stevel 		ncap = ((sbd_cmp_stat_t *)dst)->ps_ncores;
    927  0  stevel 		break;
    928  0  stevel 	default:
    929  0  stevel 		ncap = 0;
    930  0  stevel 		break;
    931  0  stevel 	}
    932  0  stevel 
    933  0  stevel 	return (ncap);
    934  0  stevel }
    935  0  stevel 
    936  0  stevel int
    937  0  stevel ap_cm_capacity(apd_t *a, int seq, void *cap, int *ncap, cfga_stat_t *ostate)
    938  0  stevel {
    939  0  stevel 	int i;
    940  0  stevel 	sbd_dev_stat_t *dst;
    941  0  stevel 	cfga_stat_t os;
    942  0  stevel 
    943  0  stevel 	if (cap == NULL)
    944  0  stevel 		return (0);
    945  0  stevel 
    946  0  stevel 	dst = ap_cm_stat(a, seq);
    947  0  stevel 	os = (cfga_stat_t)dst->ds_ostate;
    948  0  stevel 	if (os != CFGA_STAT_CONFIGURED && os != CFGA_STAT_UNCONFIGURED)
    949  0  stevel 		return (0);
    950  0  stevel 	if (ostate)
    951  0  stevel 		*ostate = os;
    952  0  stevel 
    953  0  stevel 	*ncap = 1;
    954  0  stevel 
    955  0  stevel 	switch (dst->ds_type) {
    956  0  stevel 	case SBD_COMP_CPU: {
    957  0  stevel 		sbd_cpu_stat_t *cpu = (sbd_cpu_stat_t *)dst;
    958  0  stevel 		*((processorid_t *)cap) = cpu->cs_cpuid;
    959  0  stevel 		break;
    960  0  stevel 	}
    961  0  stevel 	case SBD_COMP_MEM: {
    962  0  stevel 		sbd_mem_stat_t *mem = (sbd_mem_stat_t *)dst;
    963  0  stevel 		*((long *)cap) = mem->ms_totpages;
    964  0  stevel 		break;
    965  0  stevel 	}
    966  0  stevel 	case SBD_COMP_CMP: {
    967  0  stevel 		sbd_cmp_stat_t	*cmp = (sbd_cmp_stat_t *)dst;
    968  0  stevel 		processorid_t	*cpuid;
    969  0  stevel 
    970  0  stevel 		cpuid = (processorid_t *)cap;
    971  0  stevel 		for (i = 0; i < cmp->ps_ncores; i++) {
    972  0  stevel 			cpuid[i] = cmp->ps_cpuid[i];
    973  0  stevel 		}
    974  0  stevel 
    975  0  stevel 		*ncap = cmp->ps_ncores;
    976  0  stevel 		break;
    977  0  stevel 	}
    978  0  stevel 	default:
    979  0  stevel 		return (0);
    980  0  stevel 	}
    981  0  stevel 
    982  0  stevel 	DBG("ap_cm_capacity(%d)=(", seq);
    983  0  stevel 	for (i = 0; i < *ncap; i++) {
    984  0  stevel 		DBG("%d ", ((int *)cap)[i]);
    985  0  stevel 	}
    986  0  stevel 	DBG("%d)\n", *ostate);
    987  0  stevel 
    988  0  stevel 	return (1);
    989  0  stevel }
    990  0  stevel 
    991  0  stevel void
    992  0  stevel ap_cm_init(apd_t *a, cfga_list_data_t *ap, int seq)
    993  0  stevel {
    994  0  stevel 	char *type;
    995  0  stevel 	sbd_stat_t *st;
    996  0  stevel 	sbd_dev_stat_t *dst;
    997  0  stevel 
    998  0  stevel 	st = (sbd_stat_t *)a->stat;
    999  0  stevel 	dst = st->s_stat + seq;
   1000  0  stevel 	type = ap_dev_type(dst);
   1001  0  stevel 
   1002  0  stevel 	a->cmstat = (void *)dst;
   1003  0  stevel 
   1004  0  stevel 	DBG("ap_cm_init bd=%d rs=%d os=%d type=<%s> seq=%d\n",
   1005  0  stevel 		a->bnum, st->s_rstate, dst->ds_ostate, type, seq);
   1006  0  stevel 
   1007  0  stevel 	(void) strncpy(ap->ap_type, type, sizeof (ap->ap_type));
   1008  0  stevel 	ap->ap_r_state = (cfga_stat_t)st->s_rstate;
   1009  0  stevel 	ap->ap_o_state = (cfga_stat_t)dst->ds_ostate;
   1010  0  stevel 	ap->ap_cond = (cfga_cond_t)dst->ds_cond;
   1011  0  stevel 	ap->ap_busy = (cfga_busy_t)dst->ds_busy;
   1012  0  stevel 	ap->ap_status_time = dst->ds_time;
   1013  0  stevel 	ap_info(a, ap->ap_info, ap_cm_tgt(dst->ds_type));
   1014  0  stevel }
   1015  0  stevel 
   1016  0  stevel void
   1017  0  stevel ap_state(apd_t *a, cfga_stat_t *rs, cfga_stat_t *os)
   1018  0  stevel {
   1019  0  stevel 	sbd_stat_t *st;
   1020  0  stevel 	sbd_dev_stat_t *dst;
   1021  0  stevel 
   1022  0  stevel 	st = (sbd_stat_t *)a->stat;
   1023  0  stevel 	dst = (sbd_dev_stat_t *)a->cmstat;
   1024  0  stevel 
   1025  0  stevel 	if (rs != NULL) {
   1026  0  stevel 		if (a->tgt == AP_NONE)
   1027  0  stevel 			*rs = CFGA_STAT_NONE;
   1028  0  stevel 		else
   1029  0  stevel 			*rs = (cfga_stat_t)st->s_rstate;
   1030  0  stevel 	}
   1031  0  stevel 
   1032  0  stevel 	if (os != NULL) {
   1033  0  stevel 		if (a->tgt == AP_NONE)
   1034  0  stevel 			*os = CFGA_STAT_NONE;
   1035  0  stevel 		else if (a->tgt == AP_BOARD)
   1036  0  stevel 			*os = (cfga_stat_t)st->s_ostate;
   1037  0  stevel 		else
   1038  0  stevel 			*os = (cfga_stat_t)dst->ds_ostate;
   1039  0  stevel 	}
   1040  0  stevel }
   1041  0  stevel 
   1042  0  stevel #define	BI_POWERED		0
   1043  0  stevel #define	BI_ASSIGNED		1
   1044  0  stevel 
   1045  0  stevel static const char *
   1046  0  stevel binfo[] = {
   1047  0  stevel 	"powered-on",
   1048  0  stevel 	", assigned"
   1049  0  stevel };
   1050  0  stevel 
   1051  0  stevel static const char *
   1052  0  stevel binfo_parsable[] = {
   1053  0  stevel 	"powered-on",
   1054  0  stevel 	" assigned"
   1055  0  stevel };
   1056  0  stevel 
   1057  0  stevel static void
   1058  0  stevel bd_info(apd_t *a, cfga_info_t info, int parsable)
   1059  0  stevel {
   1060  0  stevel 	int i;
   1061  0  stevel 	int nsep;
   1062  0  stevel 	const char **p;
   1063  0  stevel 	sbd_stat_t *st;
   1064  0  stevel 	char *end = &info[sizeof (cfga_info_t)];
   1065  0  stevel 
   1066  0  stevel 	DBG("bd_info(%p)\n", (void *)info);
   1067  0  stevel 
   1068  0  stevel 	st = (sbd_stat_t *)a->stat;
   1069  0  stevel 
   1070  0  stevel 	if (parsable) {
   1071  0  stevel 		p = binfo_parsable;
   1072  0  stevel 		nsep = 1;
   1073  0  stevel 	} else {
   1074  0  stevel 		p = binfo;
   1075  0  stevel 		nsep = 2;
   1076  0  stevel 	}
   1077  0  stevel 
   1078  0  stevel 	i = nsep;
   1079  0  stevel 
   1080  0  stevel 	if (st->s_power) {
   1081  0  stevel 		info += snprintf(info, end - info, p[BI_POWERED]);
   1082  0  stevel 		i = 0;
   1083  0  stevel 	}
   1084  0  stevel 	if (st->s_assigned)
   1085  0  stevel 		info += snprintf(info, end - info, p[BI_ASSIGNED] + i);
   1086  0  stevel }
   1087  0  stevel 
   1088  0  stevel #define	CI_CPUID		0
   1089  0  stevel #define	CI_SPEED		1
   1090  0  stevel #define	CI_ECACHE		2
   1091  0  stevel 
   1092  0  stevel static const char *
   1093  0  stevel cpuinfo[] = {
   1094  0  stevel 	"cpuid %d",
   1095  0  stevel 	", speed %d MHz",
   1096  0  stevel 	", ecache %d MBytes"
   1097  0  stevel };
   1098  0  stevel 
   1099  0  stevel static const char *
   1100  0  stevel cpuinfo_parsable[] = {
   1101  0  stevel 	"cpuid=%d",
   1102  0  stevel 	" speed=%d",
   1103  0  stevel 	" ecache=%d"
   1104  0  stevel };
   1105  0  stevel 
   1106  0  stevel static void
   1107  0  stevel cpu_info(apd_t *a, cfga_info_t info, int parsable)
   1108  0  stevel {
   1109  0  stevel 	const char **p;
   1110  0  stevel 	sbd_cpu_stat_t *dst;
   1111  0  stevel 	char *end = &info[sizeof (cfga_info_t)];
   1112  0  stevel 
   1113  0  stevel 	DBG("cpu_info(%p)\n", (void *)info);
   1114  0  stevel 
   1115  0  stevel 	dst = (sbd_cpu_stat_t *)a->cmstat;
   1116  0  stevel 
   1117  0  stevel 	if (parsable)
   1118  0  stevel 		p = cpuinfo_parsable;
   1119  0  stevel 	else
   1120  0  stevel 		p = cpuinfo;
   1121  0  stevel 
   1122  0  stevel 	info += snprintf(info, end - info, p[CI_CPUID], dst->cs_cpuid);
   1123  0  stevel 	info += snprintf(info, end - info, p[CI_SPEED], dst->cs_speed);
   1124  0  stevel 	info += snprintf(info, end - info, p[CI_ECACHE], dst->cs_ecache);
   1125  0  stevel }
   1126  0  stevel 
   1127  0  stevel #define	MI_ADDRESS		0
   1128  0  stevel #define	MI_SIZE			1
   1129  0  stevel #define	MI_PERMANENT		2
   1130  0  stevel #define	MI_UNCONFIGURABLE	3
   1131  0  stevel #define	MI_SOURCE		4
   1132  0  stevel #define	MI_TARGET		5
   1133  0  stevel #define	MI_DELETED		6
   1134  0  stevel #define	MI_REMAINING		7
   1135  0  stevel #define	MI_INTERLEAVE		8
   1136  0  stevel 
   1137  0  stevel static const char *
   1138  0  stevel meminfo_nonparsable[] = {
   1139  0  stevel 	"base address 0x%" PRIx64,
   1140  0  stevel 	", %lu KBytes total",
   1141  0  stevel 	", %lu KBytes permanent",
   1142  0  stevel 	", unconfigurable",
   1143  0  stevel 	", memory delete requested on %s",
   1144  0  stevel 	", memory delete in progress on %s",
   1145  0  stevel 	", %lu KBytes deleted",
   1146  0  stevel 	", %lu KBytes remaining",
   1147  0  stevel 	", inter board interleave"
   1148  0  stevel };
   1149  0  stevel 
   1150  0  stevel static const char *
   1151  0  stevel meminfo_parsable[] = {
   1152  0  stevel 	"address=0x%" PRIx64,
   1153  0  stevel 	" size=%lu",
   1154  0  stevel 	" permanent=%lu",
   1155  0  stevel 	" unconfigurable",
   1156  0  stevel 	" source=%s",
   1157  0  stevel 	" target=%s",
   1158  0  stevel 	" deleted=%lu",
   1159  0  stevel 	" remaining=%lu",
   1160  0  stevel 	" inter-board-interleave"
   1161  0  stevel };
   1162  0  stevel 
   1163  0  stevel 
   1164  0  stevel #define	_K1	1024
   1165  0  stevel 
   1166  0  stevel /*
   1167  0  stevel  * This function assumes pagesize > 1024 and that
   1168  0  stevel  * pagesize is a multiple of 1024.
   1169  0  stevel  */
   1170  0  stevel static ulong_t
   1171  0  stevel pages_to_kbytes(uint_t pgs)
   1172  0  stevel {
   1173  0  stevel 	long pagesize;
   1174  0  stevel 
   1175  0  stevel 	pagesize = sysconf(_SC_PAGESIZE);
   1176  0  stevel 	return (pgs * (pagesize / _K1));
   1177  0  stevel }
   1178  0  stevel 
   1179  0  stevel static uint64_t
   1180  0  stevel pages_to_bytes(uint_t pgs)
   1181  0  stevel {
   1182  0  stevel 	long pagesize;
   1183  0  stevel 
   1184  0  stevel 	pagesize = sysconf(_SC_PAGESIZE);
   1185  0  stevel 	return ((uint64_t)pgs * pagesize);
   1186  0  stevel }
   1187  0  stevel 
   1188  0  stevel static void
   1189  0  stevel mem_info(apd_t *a, cfga_info_t info, int parsable)
   1190  0  stevel {
   1191  0  stevel 	const char **p;
   1192  0  stevel 	sbd_mem_stat_t *dst;
   1193  0  stevel 	int want_progress;
   1194  0  stevel 	char *end = &info[sizeof (cfga_info_t)];
   1195  0  stevel 
   1196  0  stevel 	DBG("mem_info(%p)\n", (void *)info);
   1197  0  stevel 
   1198  0  stevel 	dst = (sbd_mem_stat_t *)a->cmstat;
   1199  0  stevel 
   1200  0  stevel 	if (parsable)
   1201  0  stevel 		p = meminfo_parsable;
   1202  0  stevel 	else
   1203  0  stevel 		p = meminfo_nonparsable;
   1204  0  stevel 
   1205  0  stevel 	info += snprintf(info, end - info, p[MI_ADDRESS],
   1206  0  stevel 	    pages_to_bytes(dst->ms_basepfn));
   1207  0  stevel 	info += snprintf(info, end - info, p[MI_SIZE],
   1208  0  stevel 	    pages_to_kbytes(dst->ms_totpages));
   1209  0  stevel 
   1210  0  stevel 	if (dst->ms_noreloc_pages)
   1211  0  stevel 		info += snprintf(info, end - info, p[MI_PERMANENT],
   1212  0  stevel 		    pages_to_kbytes(dst->ms_noreloc_pages));
   1213  0  stevel 	if (!dst->ms_cage_enabled)
   1214  0  stevel 		info += snprintf(info, end - info, p[MI_UNCONFIGURABLE]);
   1215  0  stevel 	if (dst->ms_interleave)
   1216  0  stevel 		info += snprintf(info, end - info, p[MI_INTERLEAVE]);
   1217  0  stevel 
   1218  0  stevel 	/*
   1219  0  stevel 	 * If there is a valid peer physical ap_id specified,
   1220  0  stevel 	 * convert it to a logical id.
   1221  0  stevel 	 */
   1222  0  stevel 	want_progress = 0;
   1223  0  stevel 	if (str_valid(dst->ms_peer_ap_id)) {
   1224  0  stevel 		char *cm;
   1225  0  stevel 		char *peer;
   1226  0  stevel 		char physid[MAXPATHLEN];
   1227  0  stevel 		char logid[MAXPATHLEN];
   1228  0  stevel 
   1229  0  stevel 		(void) snprintf(physid, sizeof (physid), "%s%s",
   1230  0  stevel 		    DEVDIR, dst->ms_peer_ap_id);
   1231  0  stevel 
   1232  0  stevel 		/*
   1233  0  stevel 		 * Save the component portion of the physid and
   1234  0  stevel 		 * add it back after converting to logical format.
   1235  0  stevel 		 */
   1236  0  stevel 		if ((cm = strstr(physid, "::")) != NULL) {
   1237  0  stevel 			*cm = '\0';
   1238  0  stevel 			cm += 2;
   1239  0  stevel 		}
   1240  0  stevel 
   1241  0  stevel 		/* attempt to resolve to symlink */
   1242  0  stevel 		if (ap_symid(a, physid, logid, sizeof (logid)) == 0)
   1243  0  stevel 			peer = logid;
   1244  0  stevel 		else
   1245  0  stevel 			peer = physid;
   1246  0  stevel 
   1247  0  stevel 		if (dst->ms_peer_is_target) {
   1248  0  stevel 			info += snprintf(info, end - info, p[MI_TARGET], peer);
   1249  0  stevel 			if (cm)
   1250  0  stevel 				info += snprintf(info, end - info, "::%s", cm);
   1251  0  stevel 			want_progress = 1;
   1252  0  stevel 		} else {
   1253  0  stevel 			info += snprintf(info, end - info, p[MI_SOURCE], peer);
   1254  0  stevel 			if (cm)
   1255  0  stevel 				info += snprintf(info, end - info, "::%s", cm);
   1256  0  stevel 		}
   1257  0  stevel 	}
   1258  0  stevel 	if (want_progress ||
   1259  0  stevel 	    (dst->ms_detpages != 0 && dst->ms_detpages != dst->ms_totpages)) {
   1260  0  stevel 		info += snprintf(info, end - info, p[MI_DELETED],
   1261  0  stevel 		    pages_to_kbytes(dst->ms_detpages));
   1262  0  stevel 		info += snprintf(info, end - info, p[MI_REMAINING],
   1263  0  stevel 		    pages_to_kbytes(dst->ms_totpages -
   1264  0  stevel 		    dst->ms_detpages));
   1265  0  stevel 	}
   1266  0  stevel }
   1267  0  stevel 
   1268  0  stevel #define	II_DEVICE		0
   1269  0  stevel #define	II_REFERENCED		1
   1270  0  stevel 
   1271  0  stevel static const char *
   1272  0  stevel ioinfo[] = {
   1273  0  stevel 	"device %s",
   1274  0  stevel 	", referenced"
   1275  0  stevel };
   1276  0  stevel 
   1277  0  stevel static const char *
   1278  0  stevel ioinfo_parsable[] = {
   1279  0  stevel 	"device=%s",
   1280  0  stevel 	" referenced"
   1281  0  stevel };
   1282  0  stevel 
   1283  0  stevel static void
   1284  0  stevel io_info(apd_t *a, cfga_info_t info, int parsable)
   1285  0  stevel {
   1286  0  stevel 	const char **p;
   1287  0  stevel 	sbd_io_stat_t *dst;
   1288  0  stevel 	char *end = &info[sizeof (cfga_info_t)];
   1289  0  stevel 
   1290  0  stevel 	dst = (sbd_io_stat_t *)a->cmstat;
   1291  0  stevel 
   1292  0  stevel 	if (parsable)
   1293  0  stevel 		p = ioinfo_parsable;
   1294  0  stevel 	else
   1295  0  stevel 		p = ioinfo;
   1296  0  stevel 
   1297  0  stevel 	info += snprintf(info, end - info, p[II_DEVICE], dst->is_pathname);
   1298  0  stevel 	if (dst->is_referenced)
   1299  0  stevel 		info += snprintf(info, end - info, p[II_REFERENCED]);
   1300  0  stevel }
   1301  0  stevel 
   1302  0  stevel #define	PI_CPUID		0
   1303  0  stevel #define	PI_CPUID_PAIR		1
   1304  0  stevel #define	PI_CPUID_CONT		2
   1305  0  stevel #define	PI_CPUID_LAST		3
   1306  0  stevel #define	PI_SPEED		4
   1307  0  stevel #define	PI_ECACHE		5
   1308  0  stevel 
   1309  0  stevel static const char *
   1310  0  stevel cmpinfo[] = {
   1311  0  stevel 	"cpuid %d",
   1312  0  stevel 	" and %d",
   1313  0  stevel 	", %d",
   1314  0  stevel 	", and %d",
   1315  0  stevel 	", speed %d MHz",
   1316  0  stevel 	", ecache %d MBytes"
   1317  0  stevel };
   1318  0  stevel 
   1319  0  stevel static const char *
   1320  0  stevel cmpinfo_parsable[] = {
   1321  0  stevel 	"cpuid=%d",
   1322  0  stevel 	",%d",
   1323  0  stevel 	",%d",
   1324  0  stevel 	",%d",
   1325  0  stevel 	" speed=%d",
   1326  0  stevel 	" ecache=%d"
   1327  0  stevel };
   1328  0  stevel 
   1329  0  stevel static void
   1330  0  stevel cmp_info(apd_t *a, cfga_info_t info, int parsable)
   1331  0  stevel {
   1332  0  stevel 	int		i;
   1333  0  stevel 	int		last;
   1334  0  stevel 	const char	**p;
   1335  0  stevel 	sbd_cmp_stat_t	*dst;
   1336  0  stevel 	char *end = &info[sizeof (cfga_info_t)];
   1337  0  stevel 
   1338  0  stevel 	DBG("cmp_info(%p)\n", (void *)info);
   1339  0  stevel 
   1340  0  stevel 	dst = (sbd_cmp_stat_t *)a->cmstat;
   1341  0  stevel 
   1342  0  stevel 	if (parsable)
   1343  0  stevel 		p = cmpinfo_parsable;
   1344  0  stevel 	else
   1345  0  stevel 		p = cmpinfo;
   1346  0  stevel 
   1347  0  stevel 	/* Print the first cpuid */
   1348  0  stevel 	info += snprintf(info, end - info, p[PI_CPUID], dst->ps_cpuid[0]);
   1349  0  stevel 
   1350  0  stevel 	/*
   1351  0  stevel 	 * Print the middle cpuids, if necessary. Stop before
   1352  0  stevel 	 * the last one, since printing the last cpuid is a
   1353  0  stevel 	 * special case for the non parsable form.
   1354  0  stevel 	 */
   1355  0  stevel 	for (i = 1; i < (dst->ps_ncores - 1); i++) {
   1356  0  stevel 		info += snprintf(info, end - info, p[PI_CPUID_CONT],
   1357  0  stevel 		    dst->ps_cpuid[i]);
   1358  0  stevel 	}
   1359  0  stevel 
   1360  0  stevel 	/* Print the last cpuid, if necessary */
   1361  0  stevel 	if (dst->ps_ncores > 1) {
   1362  0  stevel 		last = (dst->ps_ncores == 2) ? PI_CPUID_PAIR : PI_CPUID_LAST;
   1363  0  stevel 		info += snprintf(info, end - info,
   1364  0  stevel 		    dgettext(TEXT_DOMAIN, p[last]), dst->ps_cpuid[i]);
   1365  0  stevel 	}
   1366  0  stevel 
   1367  0  stevel 	info += snprintf(info, end - info, p[PI_SPEED], dst->ps_speed);
   1368  0  stevel 	info += snprintf(info, end - info, p[PI_ECACHE], dst->ps_ecache);
   1369  0  stevel }
   1370  0  stevel 
   1371  0  stevel void
   1372  0  stevel ap_info(apd_t *a, cfga_info_t info, ap_target_t tgt)
   1373  0  stevel {
   1374  0  stevel 	int parsable = ap_getopt(a, OPT_PARSABLE);
   1375  0  stevel 
   1376  0  stevel 	DBG("ap_info(%p, %d)\n", (void *)info, parsable);
   1377  0  stevel 
   1378  0  stevel 	switch (tgt) {
   1379  0  stevel 	case AP_BOARD:
   1380  0  stevel 		bd_info(a, info, parsable);
   1381  0  stevel 		break;
   1382  0  stevel 	case AP_CPU:
   1383  0  stevel 		cpu_info(a, info, parsable);
   1384  0  stevel 		break;
   1385  0  stevel 	case AP_MEM:
   1386  0  stevel 		mem_info(a, info, parsable);
   1387  0  stevel 		break;
   1388  0  stevel 	case AP_IO:
   1389  0  stevel 		io_info(a, info, parsable);
   1390  0  stevel 		break;
   1391  0  stevel 	case AP_CMP:
   1392  0  stevel 		cmp_info(a, info, parsable);
   1393  0  stevel 		break;
   1394  0  stevel 	default:
   1395  0  stevel 		break;
   1396  0  stevel 	}
   1397  0  stevel }
   1398