2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A#include <ctype.h>
2N/A#include <stdio.h>
2N/A#include <stdlib.h>
2N/A#include <string.h>
2N/A#include <fcntl.h>
2N/A#include <unistd.h>
2N/A#include <libdevinfo.h>
2N/A#include <errno.h>
2N/A#include <libintl.h>
2N/A#define CFGA_PLUGIN_LIB
2N/A#include <config_admin.h>
2N/A#include "ap.h"
2N/A#include <sys/obpdefs.h>
2N/A#include <sys/processor.h>
2N/A#include <sys/stat.h>
2N/A#include <sys/sbd_ioctl.h>
2N/A#include <sys/int_fmtio.h>
2N/A
2N/Astatic cfga_err_t
2N/Aap_getncm(apd_t *a, sbd_comp_type_t type, int *ncm)
2N/A{
2N/A sbd_ioctl_arg_t *ctl;
2N/A sbd_getncm_cmd_t *cp;
2N/A
2N/A if (a->fd == -1 || a->ctl == NULL)
2N/A return (CFGA_LIB_ERROR);
2N/A
2N/A ctl = (sbd_ioctl_arg_t *)a->ctl;
2N/A ctl->ic_type = type;
2N/A ctl->ic_name[0] = '\0';
2N/A ctl->ic_unit = 0;
2N/A ctl->i_len = 0;
2N/A ctl->i_opts = NULL;
2N/A
2N/A DBG("ioctl(%d SBD_CMD_GETNCM, 0x%p)\n", a->fd, (void *)ctl);
2N/A
2N/A if (ioctl(a->fd, SBD_CMD_GETNCM, ctl) == -1) {
2N/A ap_err(a, ERR_CMD_FAIL, CMD_GETNCM);
2N/A return (CFGA_ERROR);
2N/A }
2N/A
2N/A cp = &ctl->i_cmd.cmd_getncm;
2N/A
2N/A DBG("ncm(%d)=%d\n", type, cp->g_ncm);
2N/A
2N/A if (ncm)
2N/A *ncm = cp->g_ncm;
2N/A
2N/A return (CFGA_OK);
2N/A}
2N/A
2N/Acfga_err_t
2N/Aap_stat(apd_t *a, int all)
2N/A{
2N/A int fd;
2N/A int ncm;
2N/A int select;
2N/A int stsize;
2N/A int oflag;
2N/A sbd_stat_cmd_t *sc;
2N/A sbd_ioctl_arg_t *ctl;
2N/A cfga_err_t rc;
2N/A sbd_stat_t *new_stat;
2N/A
2N/A rc = CFGA_LIB_ERROR;
2N/A
2N/A DBG("ap_stat(%s)\n", a->path);
2N/A
2N/A /* Open the file descriptor if not already open */
2N/A if (a->fd == -1) {
2N/A DBG("open(%s)\n", a->path);
2N/A if (a->statonly != 0)
2N/A oflag = O_RDONLY;
2N/A else
2N/A oflag = O_RDWR;
2N/A if ((fd = open(a->path, oflag, 0)) == -1) {
2N/A ap_err(a, ERR_AP_INVAL);
2N/A return (rc);
2N/A }
2N/A a->fd = fd;
2N/A } else {
2N/A fd = a->fd;
2N/A }
2N/A
2N/A if (a->ctl == NULL && (a->ctl = calloc(1, sizeof (*ctl))) == NULL) {
2N/A ap_err(a, ERR_CMD_FAIL, CMD_STATUS);
2N/A return (rc);
2N/A }
2N/A
2N/A if (a->tgt == AP_BOARD) {
2N/A /*
2N/A * The status target is the board. If we need to
2N/A * return component data (to support the -a option),
2N/A * get the number of components on the board.
2N/A */
2N/A select = 0;
2N/A if (all) {
2N/A cfga_err_t r;
2N/A r = ap_getncm(a, SBD_COMP_NONE, &ncm);
2N/A if (r != CFGA_OK) {
2N/A return (r);
2N/A }
2N/A } else {
2N/A ncm = 0;
2N/A }
2N/A } else {
2N/A select = 1;
2N/A ncm = 1;
2N/A }
2N/A
2N/A DBG("ncm=%d\n", ncm);
2N/A
2N/A a->ncm = ncm;
2N/A
2N/A /*
2N/A * The status structure contains space for one component;
2N/A * add the space for the other components if necessary.
2N/A */
2N/A stsize = sizeof (sbd_stat_t);
2N/A if (ncm > 1)
2N/A stsize += ((ncm - 1) * sizeof (sbd_dev_stat_t));
2N/A
2N/A if ((new_stat = realloc(a->stat, stsize)) == NULL) {
2N/A ap_err(a, ERR_CMD_FAIL, CMD_STATUS);
2N/A return (rc);
2N/A }
2N/A
2N/A a->stat = new_stat;
2N/A
2N/A
2N/A ctl = (sbd_ioctl_arg_t *)a->ctl;
2N/A ctl->i_len = 0;
2N/A ctl->i_opts = NULL;
2N/A ctl->ic_type = SBD_COMP_NONE;
2N/A if (all)
2N/A ctl->i_flags |= SBD_FLAG_ALLCMP;
2N/A sc = &ctl->i_cmd.cmd_stat;
2N/A sc->s_statp = (caddr_t)a->stat;
2N/A sc->s_nbytes = stsize;
2N/A
2N/A if (select) {
2N/A /*
2N/A * The target is a specific component. Pass its
2N/A * name and unit number to the driver. Set its
2N/A * type to UNKNOWN since the plugin does not know
2N/A * the type of the component specified by the user.
2N/A */
2N/A ctl->ic_type = SBD_COMP_UNKNOWN;
2N/A ctl->ic_unit = a->cnum;
2N/A (void) strcpy(ctl->ic_name, a->cname);
2N/A }
2N/A
2N/A DBG("ioctl(%d SBD_CMD_STATUS, sc=0x%p sz=%d flags=%d",
2N/A fd, (void *)sc->s_statp, sc->s_nbytes, ctl->i_flags);
2N/A if (select)
2N/A DBG(" cname=<%s> cnum=%d", a->cname, a->cnum);
2N/A DBG(")\n");
2N/A
2N/A if (ioctl(fd, SBD_CMD_STATUS, ctl) == -1) {
2N/A ap_err(a, ERR_CMD_FAIL, CMD_STATUS);
2N/A rc = CFGA_ERROR;
2N/A } else
2N/A rc = CFGA_OK;
2N/A
2N/A DBG("ap_stat()=%d\n", rc);
2N/A
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * Convert a component to a target type.
2N/A */
2N/Astatic ap_target_t
2N/Aap_cm_tgt(sbd_comp_type_t type)
2N/A{
2N/A ap_target_t c;
2N/A
2N/A switch (type) {
2N/A case SBD_COMP_CPU:
2N/A c = AP_CPU;
2N/A break;
2N/A case SBD_COMP_MEM:
2N/A c = AP_MEM;
2N/A break;
2N/A case SBD_COMP_IO:
2N/A c = AP_IO;
2N/A break;
2N/A case SBD_COMP_CMP:
2N/A c = AP_CMP;
2N/A break;
2N/A default:
2N/A c = AP_NONE;
2N/A break;
2N/A }
2N/A
2N/A return (c);
2N/A}
2N/A
2N/Acfga_err_t
2N/Aapd_init(apd_t *a, int all)
2N/A{
2N/A int i;
2N/A char *cn, *dn;
2N/A sbd_stat_t *st;
2N/A sbd_dev_stat_t *dst;
2N/A cfga_err_t rc;
2N/A
2N/A /*
2N/A * Ideally, for board operations (other than status) it is not
2N/A * necessary to issue the STATUS ioctl. The call however allows a
2N/A * final sanity check to ensure that the board number returned
2N/A * by the driver matches the plugin's notion of the board number
2N/A * as extracted from the ap_id. If this check is not desirable,
2N/A * we can change the code to issue the status call only when
2N/A * necessary. Note that for component operations, we need to do
2N/A * the STATUS in order to figure out the component type and
2N/A * validate the command/options accordingly. XXX
2N/A */
2N/A if ((rc = ap_stat(a, all)) != CFGA_OK) {
2N/A ap_err(a, ERR_AP_INVAL);
2N/A return (rc);
2N/A }
2N/A
2N/A st = (sbd_stat_t *)a->stat;
2N/A
2N/A /*
2N/A * Set the component count to the returned stat count.
2N/A */
2N/A if (a->ncm > st->s_nstat) {
2N/A
2N/A DBG("ncm=%d nstat=%d (truncated)\n", a->ncm, st->s_nstat);
2N/A
2N/A a->ncm = st->s_nstat;
2N/A }
2N/A
2N/A if (a->tgt == AP_BOARD) {
2N/A
2N/A DBG("tgt=%d\n", a->tgt);
2N/A
2N/A /*
2N/A * Initialize the RCM module here so that it can record
2N/A * the initial state of the capacity information.
2N/A */
2N/A rc = ap_rcm_init(a);
2N/A
2N/A return (rc);
2N/A }
2N/A
2N/A a->tgt = AP_NONE;
2N/A cn = a->cname;
2N/A
2N/A DBG("cname=<%s> cunit=<%d>\n", a->cname, a->cnum);
2N/A
2N/A for (dst = st->s_stat, i = 0; i < st->s_nstat; i++, dst++) {
2N/A
2N/A DBG("ds_name,ds_unit,ds_type=<%s,%d,%d> ",
2N/A dst->ds_name, dst->ds_unit, dst->ds_type);
2N/A
2N/A if (dst->ds_unit != a->cnum)
2N/A continue;
2N/A
2N/A /*
2N/A * Consider the names matched if they are either
2N/A * both absent or the same. It is conceivable that
2N/A * a NULL component name be considered valid
2N/A * by the driver.
2N/A */
2N/A dn = dst->ds_name;
2N/A
2N/A if ((dn == NULL && cn == NULL) ||
2N/A (dn != NULL && cn != NULL && strcmp(dn, cn) == 0)) {
2N/A a->tgt = ap_cm_tgt(dst->ds_type);
2N/A a->cmstat = (void *)dst;
2N/A
2N/A DBG("found ");
2N/A
2N/A break;
2N/A }
2N/A }
2N/A
2N/A DBG("tgt=%d\n", a->tgt);
2N/A
2N/A if (a->tgt == AP_NONE) {
2N/A ap_err(a, ERR_CM_INVAL, a->cid);
2N/A return (CFGA_INVAL);
2N/A }
2N/A
2N/A /*
2N/A * Initialize the RCM module here so that it can record
2N/A * the initial state of the capacity information.
2N/A */
2N/A rc = ap_rcm_init(a);
2N/A
2N/A return (rc);
2N/A}
2N/A
2N/Avoid
2N/Aapd_free(apd_t *a)
2N/A{
2N/A if (a == NULL)
2N/A return;
2N/A
2N/A ap_rcm_fini(a);
2N/A
2N/A if (a->fd != -1)
2N/A (void) close(a->fd);
2N/A
2N/A s_free(a->options);
2N/A s_free(a->path);
2N/A s_free(a->drv);
2N/A s_free(a->target);
2N/A s_free(a->cname);
2N/A s_free(a->ctl);
2N/A s_free(a->stat);
2N/A
2N/A free(a);
2N/A}
2N/A
2N/Aapd_t *
2N/Aapd_alloc(const char *ap_id, cfga_flags_t flags, char **errstring,
2N/A struct cfga_msg *msgp, struct cfga_confirm *confp)
2N/A{
2N/A apd_t *a;
2N/A
2N/A if ((a = calloc(1, sizeof (*a))) == NULL)
2N/A return (NULL);
2N/A
2N/A if (errstring != NULL)
2N/A *errstring = NULL;
2N/A
2N/A a->fd = -1;
2N/A a->errstring = errstring;
2N/A a->msgp = msgp;
2N/A a->confp = confp;
2N/A a->class = "sbd";
2N/A
2N/A if (flags & CFGA_FLAG_LIST_ALL)
2N/A ap_setopt(a, OPT_LIST_ALL);
2N/A if (flags & CFGA_FLAG_FORCE)
2N/A ap_setopt(a, OPT_FORCE);
2N/A if (flags & CFGA_FLAG_VERBOSE)
2N/A ap_setopt(a, OPT_VERBOSE);
2N/A
2N/A if (ap_id == NULL || ap_parse(a, ap_id) == 0)
2N/A return (a);
2N/A
2N/A apd_free(a);
2N/A return (NULL);
2N/A}
2N/A
2N/A/*
2N/A * The type field is defined to be parsable by cfgadm(1M): It
2N/A * must not contain white space characters. This function
2N/A * converts white space to underscore.
2N/A */
2N/A
2N/Astatic void
2N/Aparsable_strncpy(char *op, const char *ip, size_t n)
2N/A{
2N/A char c;
2N/A
2N/A while (n-- > 0) {
2N/A c = *ip++;
2N/A if (isspace(c))
2N/A c = '_';
2N/A *op++ = c;
2N/A if (c == '\0')
2N/A break;
2N/A }
2N/A}
2N/A
2N/Avoid
2N/Aap_init(apd_t *a, cfga_list_data_t *ap)
2N/A{
2N/A sbd_stat_t *st;
2N/A
2N/A st = (sbd_stat_t *)a->stat;
2N/A
2N/A DBG("ap_init bd=%d rs=%d os=%d type=<%s>\n",
2N/A a->bnum, st->s_rstate, st->s_ostate, st->s_type);
2N/A
2N/A parsable_strncpy(ap->ap_type, st->s_type, sizeof (ap->ap_type));
2N/A ap->ap_r_state = (cfga_stat_t)st->s_rstate;
2N/A ap->ap_o_state = (cfga_stat_t)st->s_ostate;
2N/A ap->ap_cond = (cfga_cond_t)st->s_cond;
2N/A ap->ap_busy = (cfga_busy_t)st->s_busy;
2N/A ap->ap_status_time = st->s_time;
2N/A ap_info(a, ap->ap_info, AP_BOARD);
2N/A}
2N/A
2N/Atypedef struct {
2N/A int cmd;
2N/A int ioc;
2N/A} ap_ioc_t;
2N/A
2N/Astatic ap_ioc_t
2N/Aap_iocs[] = {
2N/A {CMD_ASSIGN, SBD_CMD_ASSIGN },
2N/A {CMD_POWERON, SBD_CMD_POWERON },
2N/A {CMD_TEST, SBD_CMD_TEST },
2N/A {CMD_CONNECT, SBD_CMD_CONNECT },
2N/A {CMD_CONFIGURE, SBD_CMD_CONFIGURE },
2N/A {CMD_UNCONFIGURE, SBD_CMD_UNCONFIGURE },
2N/A {CMD_DISCONNECT, SBD_CMD_DISCONNECT },
2N/A {CMD_POWEROFF, SBD_CMD_POWEROFF },
2N/A {CMD_STATUS, SBD_CMD_STATUS },
2N/A {CMD_GETNCM, SBD_CMD_GETNCM },
2N/A {CMD_UNASSIGN, SBD_CMD_UNASSIGN },
2N/A {CMD_PASSTHRU, SBD_CMD_PASSTHRU },
2N/A {CMD_NONE, 0 }
2N/A};
2N/A
2N/Astatic int
2N/Aap_ioc(int cmd)
2N/A{
2N/A ap_ioc_t *acp;
2N/A
2N/A DBG("ap_ioc(%d)\n", cmd);
2N/A
2N/A for (acp = ap_iocs; acp->cmd != CMD_NONE; acp++)
2N/A if (acp->cmd == cmd)
2N/A break;
2N/A
2N/A DBG("ap_ioc(%d)=0x%x\n", cmd, acp->ioc);
2N/A
2N/A return (acp->ioc);
2N/A}
2N/A
2N/Acfga_err_t
2N/Aap_suspend_query(apd_t *a, int cmd, int *check)
2N/A{
2N/A int ioc;
2N/A sbd_dev_stat_t *dst;
2N/A
2N/A /*
2N/A * See if the a quiesce operation is required for
2N/A * this command for any of the components. If the
2N/A * command does not map to an ioctl, then there is
2N/A * nothing to do.
2N/A */
2N/A if ((ioc = ap_ioc(cmd)) == 0)
2N/A return (CFGA_OK);
2N/A else if (a->tgt == AP_BOARD) {
2N/A int i;
2N/A
2N/A dst = ((sbd_stat_t *)a->stat)->s_stat;
2N/A
2N/A /*
2N/A * See if any component requires a
2N/A * OS suspension for this command.
2N/A */
2N/A for (i = 0; i < a->ncm; i++, dst++)
2N/A if (SBD_CHECK_SUSPEND(ioc, dst->ds_suspend))
2N/A (*check)++;
2N/A } else {
2N/A dst = (sbd_dev_stat_t *)a->cmstat;
2N/A if (SBD_CHECK_SUSPEND(ioc, dst->ds_suspend))
2N/A (*check)++;
2N/A }
2N/A
2N/A return (CFGA_OK);
2N/A}
2N/A
2N/Acfga_err_t
2N/Aap_platopts_check(apd_t *a, int first, int last)
2N/A{
2N/A int c;
2N/A uint_t platopts;
2N/A sbd_stat_t *stat;
2N/A ap_opts_t *opts;
2N/A
2N/A opts = &a->opts;
2N/A stat = (sbd_stat_t *)a->stat;
2N/A platopts = stat->s_platopts;
2N/A
2N/A
2N/A /*
2N/A * If there are no platform options set then there
2N/A * is no need to check this operation
2N/A */
2N/A if (opts->platform == NULL)
2N/A return (CFGA_OK);
2N/A
2N/A /*
2N/A * Check if any of the steps in the sequence
2N/A * allows for a platform option
2N/A */
2N/A for (c = first; c <= last; c++)
2N/A /*
2N/A * If the platopt is set it means that the platform does not
2N/A * support options for this cmd
2N/A */
2N/A if (SBD_CHECK_PLATOPTS(ap_ioc(c), platopts) == 0) {
2N/A return (CFGA_OK);
2N/A }
2N/A
2N/A ap_err(a, ERR_OPT_INVAL, opts->platform);
2N/A
2N/A return (CFGA_INVAL);
2N/A}
2N/A
2N/Acfga_err_t
2N/Aap_ioctl(apd_t *a, int cmd)
2N/A{
2N/A int ioc;
2N/A sbd_ioctl_arg_t *ctl;
2N/A
2N/A if (a->ctl == NULL && (a->ctl = calloc(1, sizeof (*ctl))) == NULL) {
2N/A ap_err(a, ERR_CMD_FAIL, cmd);
2N/A return (CFGA_LIB_ERROR);
2N/A }
2N/A
2N/A ap_msg(a, MSG_ISSUE, cmd, a->target);
2N/A
2N/A ctl = (sbd_ioctl_arg_t *)a->ctl;
2N/A ctl->i_flags = 0;
2N/A ctl->i_len = 0;
2N/A ctl->i_opts = NULL;
2N/A
2N/A if (ap_getopt(a, OPT_FORCE))
2N/A ctl->i_flags |= SBD_FLAG_FORCE;
2N/A if (ap_getopt(a, OPT_SUSPEND_OK))
2N/A ctl->i_flags |= SBD_FLAG_QUIESCE_OKAY;
2N/A
2N/A if (a->tgt == AP_BOARD)
2N/A ctl->ic_type = SBD_COMP_NONE;
2N/A else {
2N/A ctl->ic_type = SBD_COMP_UNKNOWN;
2N/A ctl->ic_unit = a->cnum;
2N/A (void) strcpy(ctl->ic_name, a->cname);
2N/A }
2N/A
2N/A if (!(ioc = ap_ioc(cmd))) {
2N/A ap_err(a, ERR_CMD_FAIL, cmd);
2N/A return (CFGA_LIB_ERROR);
2N/A }
2N/A
2N/A /*
2N/A * If this is a passthru command, pass all of its
2N/A * options; otherwise, pass all options after the
2N/A * platform keyword.
2N/A */
2N/A if (cmd == CMD_PASSTHRU)
2N/A ctl->i_opts = a->options;
2N/A else {
2N/A /*
2N/A * Only pass the platform option to the cmds that the platform
2N/A * has specified as ok
2N/A */
2N/A sbd_stat_t *stat;
2N/A
2N/A stat = (sbd_stat_t *)a->stat;
2N/A if (SBD_CHECK_PLATOPTS(ioc, stat->s_platopts) == 0)
2N/A ctl->i_opts = a->opts.platform;
2N/A }
2N/A
2N/A if (ctl->i_opts != NULL)
2N/A ctl->i_len = strlen(ctl->i_opts) + 1;
2N/A
2N/A DBG("i_opts=%s\n", ctl->i_opts ? ctl->i_opts : "NULL");
2N/A DBG("i_flags=0x%x\n", ctl->i_flags);
2N/A
2N/A if (ap_getopt(a, OPT_SIM)) {
2N/A ap_msg(a, MSG_DONE, cmd, a->target);
2N/A return (CFGA_OK);
2N/A }
2N/A
2N/A if (ioctl(a->fd, ioc, ctl) == -1) {
2N/A ap_err(a, ERR_CMD_FAIL, cmd);
2N/A return (CFGA_ERROR);
2N/A }
2N/A ap_msg(a, MSG_DONE, cmd, a->target);
2N/A
2N/A return (CFGA_OK);
2N/A}
2N/A
2N/A/*
2N/A * Return the error string corresponding to a given error code.
2N/A * String table and error code sets are provided by sbd_etab. This data
2N/A * structure is automatically generated at compile time from the error
2N/A * code and message text information in sbd_ioctl.h.
2N/A */
2N/Astatic char *
2N/Amod_estr(int code)
2N/A{
2N/A int i;
2N/A char *s;
2N/A extern sbd_etab_t sbd_etab[];
2N/A extern int sbd_etab_len;
2N/A
2N/A s = NULL;
2N/A
2N/A for (i = 0; i < sbd_etab_len; i++) {
2N/A sbd_etab_t *eptr = &sbd_etab[i];
2N/A
2N/A if ((code >= eptr->t_base) && (code <= eptr->t_bnd)) {
2N/A int index;
2N/A char **t_text;
2N/A
2N/A /*
2N/A * Found it. Just extract the string
2N/A */
2N/A index = code - eptr->t_base;
2N/A t_text = eptr->t_text;
2N/A s = strdup(t_text[index]);
2N/A break;
2N/A }
2N/A }
2N/A
2N/A if (i == sbd_etab_len) {
2N/A char buf[32];
2N/A
2N/A (void) snprintf(buf, sizeof (buf), "error %d", code);
2N/A s = strdup(buf);
2N/A }
2N/A
2N/A return (s);
2N/A}
2N/A
2N/Achar *
2N/Aap_sys_err(apd_t *a, char **rp)
2N/A{
2N/A int code;
2N/A char *p;
2N/A char *rsc;
2N/A
2N/A sbd_ioctl_arg_t *ctl = (sbd_ioctl_arg_t *)a->ctl;
2N/A
2N/A /*
2N/A * The driver sets the errno to EIO if it returns
2N/A * more detailed error info via e_code. In all
2N/A * other cases, use standard error text.
2N/A */
2N/A if (ctl == NULL || errno != EIO) {
2N/A if ((p = strerror(errno)) != NULL)
2N/A p = strdup(p);
2N/A return (p);
2N/A }
2N/A
2N/A code = ctl->ie_code;
2N/A rsc = ctl->ie_rsc;
2N/A
2N/A if (code)
2N/A p = mod_estr(code);
2N/A else if ((p = strerror(errno)) != NULL)
2N/A p = strdup(p);
2N/A
2N/A if (*rsc != '\0' && rp != NULL)
2N/A *rp = strdup(rsc);
2N/A
2N/A return (p);
2N/A}
2N/A
2N/A/*
2N/A * cfgadm -o err=plugin-err,cmd=name,code=ecode -x errtest ap_id.
2N/A */
2N/Acfga_err_t
2N/Aap_test_err(apd_t *a, const char *options)
2N/A{
2N/A int err;
2N/A int cmd;
2N/A ap_opts_t *opts;
2N/A sbd_ioctl_arg_t ctl;
2N/A
2N/A opts = &a->opts;
2N/A err = opts->err;
2N/A cmd = CMD_DISCONNECT;
2N/A
2N/A DBG("ap_test_err(%d %d)\n", opts->code, opts->err);
2N/A
2N/A switch (err) {
2N/A case ERR_CMD_INVAL:
2N/A ap_err(a, err, ap_cmd_name(cmd));
2N/A break;
2N/A case ERR_CMD_NOTSUPP:
2N/A ap_err(a, err, cmd);
2N/A break;
2N/A case ERR_CMD_FAIL:
2N/A errno = EIO;
2N/A ctl.i_err.e_code = opts->code;
2N/A *ctl.i_err.e_rsc = '\0';
2N/A a->ctl = &ctl;
2N/A ap_err(a, err, cmd);
2N/A a->ctl = NULL;
2N/A break;
2N/A case ERR_OPT_INVAL:
2N/A ap_err(a, err, options);
2N/A break;
2N/A case ERR_OPT_NOVAL:
2N/A ap_err(a, err, options);
2N/A break;
2N/A case ERR_AP_INVAL:
2N/A ap_err(a, err);
2N/A break;
2N/A case ERR_CM_INVAL:
2N/A ap_err(a, err, a->cid);
2N/A break;
2N/A case ERR_TRANS_INVAL:
2N/A ap_err(a, ERR_TRANS_INVAL, cmd);
2N/A break;
2N/A }
2N/A
2N/A return (CFGA_LIB_ERROR);
2N/A}
2N/A
2N/Astatic char *
2N/Aap_help_topics[] = {
2N/A "\nSbd specific commands/options:\n\n",
2N/A "\tcfgadm [-o parsable] -l ap_id\n",
2N/A "\tcfgadm [-o unassign|nopoweroff] -c disconnect ap_id\n",
2N/A "\tcfgadm -t ap_id\n",
2N/A "\tcfgadm -x assign ap_id\n",
2N/A "\tcfgadm -x unassign ap_id\n",
2N/A "\tcfgadm -x poweron ap_id\n",
2N/A "\tcfgadm -x poweroff ap_id\n",
2N/A NULL
2N/A};
2N/A
2N/A/*ARGSUSED*/
2N/Acfga_err_t
2N/Aap_help(struct cfga_msg *msgp, const char *options, cfga_flags_t flags)
2N/A{
2N/A int len;
2N/A char **p;
2N/A char *q;
2N/A
2N/A if (msgp == NULL || msgp->message_routine == NULL)
2N/A return (CFGA_OK);
2N/A
2N/A for (p = ap_help_topics; *p != NULL; p++) {
2N/A if ((len = strlen(*p)) == 0)
2N/A continue;
2N/A if ((q = (char *)calloc(len + 1, 1)) == NULL)
2N/A continue;
2N/A (void) strcpy(q, *p);
2N/A (*msgp->message_routine)(msgp->appdata_ptr, q);
2N/A free(q);
2N/A }
2N/A
2N/A return (CFGA_OK);
2N/A}
2N/A
2N/Astatic char *
2N/Aap_dev_type(sbd_dev_stat_t *dst)
2N/A{
2N/A char *type;
2N/A
2N/A switch (dst->ds_type) {
2N/A case SBD_COMP_CPU:
2N/A type = "cpu";
2N/A break;
2N/A case SBD_COMP_MEM:
2N/A type = "memory";
2N/A break;
2N/A case SBD_COMP_IO:
2N/A type = "io";
2N/A break;
2N/A case SBD_COMP_CMP:
2N/A type = "cpu";
2N/A break;
2N/A default:
2N/A type = "other";
2N/A break;
2N/A }
2N/A
2N/A DBG("ap_dev_type(%d)=%s\n", dst->ds_type, type);
2N/A
2N/A return (type);
2N/A}
2N/A
2N/Astatic sbd_dev_stat_t *
2N/Aap_cm_stat(apd_t *a, int seq)
2N/A{
2N/A sbd_stat_t *st;
2N/A
2N/A if (seq == CM_DFLT)
2N/A return (a->cmstat);
2N/A
2N/A st = (sbd_stat_t *)a->stat;
2N/A return (st->s_stat + seq);
2N/A}
2N/A
2N/Achar *
2N/Aap_cm_devpath(apd_t *a, int seq)
2N/A{
2N/A int len;
2N/A char *path;
2N/A char *devpath;
2N/A sbd_io_stat_t *dst;
2N/A
2N/A
2N/A /*
2N/A * If no component sequence number is provided
2N/A * default to the current target component.
2N/A * Assume an io component so that we can get
2N/A * the path if the component is indeed of type io.
2N/A */
2N/A if (seq == CM_DFLT)
2N/A dst = (sbd_io_stat_t *)a->cmstat;
2N/A else {
2N/A sbd_stat_t *st;
2N/A st = (sbd_stat_t *)a->stat;
2N/A dst = (sbd_io_stat_t *)st->s_stat + seq;
2N/A }
2N/A
2N/A if (dst->is_type != SBD_COMP_IO)
2N/A path = NULL;
2N/A else
2N/A path = dst->is_pathname;
2N/A
2N/A if (str_valid(path)) {
2N/A len = strlen(DEVDIR) + strlen(path) + 1;
2N/A
2N/A if ((devpath = calloc(1, len)) == NULL)
2N/A return (NULL);
2N/A
2N/A (void) snprintf(devpath, len, "%s%s", DEVDIR, path);
2N/A } else
2N/A devpath = NULL;
2N/A
2N/A DBG("ap_cm_path(%d)=%s\n", seq, devpath ? devpath : "");
2N/A
2N/A return (devpath);
2N/A}
2N/A
2N/Avoid
2N/Aap_cm_id(apd_t *a, int seq, char *id, size_t bufsize)
2N/A{
2N/A int unit;
2N/A char *name;
2N/A sbd_dev_stat_t *dst;
2N/A
2N/A dst = ap_cm_stat(a, seq);
2N/A
2N/A unit = dst->ds_unit;
2N/A name = dst->ds_name;
2N/A
2N/A /*
2N/A * If the component has a unit number,
2N/A * add it to the id, otherwise just use
2N/A * the component's name.
2N/A */
2N/A if (unit == -1)
2N/A (void) snprintf(id, bufsize, "%s", name);
2N/A else
2N/A (void) snprintf(id, bufsize, "%s%d", name, unit);
2N/A
2N/A DBG("ap_cm_id(%d)=%s\n", seq, id);
2N/A}
2N/A
2N/A/*
2N/A * Convert a component to a target type.
2N/A */
2N/Aap_target_t
2N/Aap_cm_type(apd_t *a, int seq)
2N/A{
2N/A ap_target_t c;
2N/A sbd_dev_stat_t *dst;
2N/A
2N/A dst = ap_cm_stat(a, seq);
2N/A
2N/A switch (dst->ds_type) {
2N/A case SBD_COMP_CPU:
2N/A c = AP_CPU;
2N/A break;
2N/A case SBD_COMP_MEM:
2N/A c = AP_MEM;
2N/A break;
2N/A case SBD_COMP_IO:
2N/A c = AP_IO;
2N/A break;
2N/A case SBD_COMP_CMP:
2N/A c = AP_CMP;
2N/A break;
2N/A default:
2N/A c = AP_NONE;
2N/A break;
2N/A }
2N/A
2N/A return (c);
2N/A}
2N/A
2N/Aint
2N/Aap_cm_ncap(apd_t *a, int seq)
2N/A{
2N/A sbd_dev_stat_t *dst;
2N/A int ncap;
2N/A
2N/A dst = ap_cm_stat(a, seq);
2N/A
2N/A switch (dst->ds_type) {
2N/A case SBD_COMP_CPU:
2N/A case SBD_COMP_MEM:
2N/A case SBD_COMP_IO:
2N/A ncap = 1;
2N/A break;
2N/A case SBD_COMP_CMP:
2N/A ncap = ((sbd_cmp_stat_t *)dst)->ps_ncores;
2N/A break;
2N/A default:
2N/A ncap = 0;
2N/A break;
2N/A }
2N/A
2N/A return (ncap);
2N/A}
2N/A
2N/Aint
2N/Aap_cm_capacity(apd_t *a, int seq, void *cap, int *ncap, cfga_stat_t *ostate)
2N/A{
2N/A int i;
2N/A sbd_dev_stat_t *dst;
2N/A cfga_stat_t os;
2N/A
2N/A if (cap == NULL)
2N/A return (0);
2N/A
2N/A dst = ap_cm_stat(a, seq);
2N/A os = (cfga_stat_t)dst->ds_ostate;
2N/A if (os != CFGA_STAT_CONFIGURED && os != CFGA_STAT_UNCONFIGURED)
2N/A return (0);
2N/A if (ostate)
2N/A *ostate = os;
2N/A
2N/A *ncap = 1;
2N/A
2N/A switch (dst->ds_type) {
2N/A case SBD_COMP_CPU: {
2N/A sbd_cpu_stat_t *cpu = (sbd_cpu_stat_t *)dst;
2N/A *((processorid_t *)cap) = cpu->cs_cpuid;
2N/A break;
2N/A }
2N/A case SBD_COMP_MEM: {
2N/A sbd_mem_stat_t *mem = (sbd_mem_stat_t *)dst;
2N/A *((long *)cap) = mem->ms_totpages;
2N/A break;
2N/A }
2N/A case SBD_COMP_CMP: {
2N/A sbd_cmp_stat_t *cmp = (sbd_cmp_stat_t *)dst;
2N/A processorid_t *cpuid;
2N/A
2N/A cpuid = (processorid_t *)cap;
2N/A for (i = 0; i < cmp->ps_ncores; i++) {
2N/A cpuid[i] = cmp->ps_cpuid[i];
2N/A }
2N/A
2N/A *ncap = cmp->ps_ncores;
2N/A break;
2N/A }
2N/A default:
2N/A return (0);
2N/A }
2N/A
2N/A DBG("ap_cm_capacity(%d)=(", seq);
2N/A for (i = 0; i < *ncap; i++) {
2N/A DBG("%d ", ((int *)cap)[i]);
2N/A }
2N/A DBG("%d)\n", *ostate);
2N/A
2N/A return (1);
2N/A}
2N/A
2N/Avoid
2N/Aap_cm_init(apd_t *a, cfga_list_data_t *ap, int seq)
2N/A{
2N/A char *type;
2N/A sbd_stat_t *st;
2N/A sbd_dev_stat_t *dst;
2N/A
2N/A st = (sbd_stat_t *)a->stat;
2N/A dst = st->s_stat + seq;
2N/A type = ap_dev_type(dst);
2N/A
2N/A a->cmstat = (void *)dst;
2N/A
2N/A DBG("ap_cm_init bd=%d rs=%d os=%d type=<%s> seq=%d\n",
2N/A a->bnum, st->s_rstate, dst->ds_ostate, type, seq);
2N/A
2N/A (void) strncpy(ap->ap_type, type, sizeof (ap->ap_type));
2N/A ap->ap_r_state = (cfga_stat_t)st->s_rstate;
2N/A ap->ap_o_state = (cfga_stat_t)dst->ds_ostate;
2N/A ap->ap_cond = (cfga_cond_t)dst->ds_cond;
2N/A ap->ap_busy = (cfga_busy_t)dst->ds_busy;
2N/A ap->ap_status_time = dst->ds_time;
2N/A ap_info(a, ap->ap_info, ap_cm_tgt(dst->ds_type));
2N/A}
2N/A
2N/Avoid
2N/Aap_state(apd_t *a, cfga_stat_t *rs, cfga_stat_t *os)
2N/A{
2N/A sbd_stat_t *st;
2N/A sbd_dev_stat_t *dst;
2N/A
2N/A st = (sbd_stat_t *)a->stat;
2N/A dst = (sbd_dev_stat_t *)a->cmstat;
2N/A
2N/A if (rs != NULL) {
2N/A if (a->tgt == AP_NONE)
2N/A *rs = CFGA_STAT_NONE;
2N/A else
2N/A *rs = (cfga_stat_t)st->s_rstate;
2N/A }
2N/A
2N/A if (os != NULL) {
2N/A if (a->tgt == AP_NONE)
2N/A *os = CFGA_STAT_NONE;
2N/A else if (a->tgt == AP_BOARD)
2N/A *os = (cfga_stat_t)st->s_ostate;
2N/A else
2N/A *os = (cfga_stat_t)dst->ds_ostate;
2N/A }
2N/A}
2N/A
2N/A#define BI_POWERED 0
2N/A#define BI_ASSIGNED 1
2N/A
2N/Astatic const char *
2N/Abinfo[] = {
2N/A "powered-on",
2N/A ", assigned"
2N/A};
2N/A
2N/Astatic const char *
2N/Abinfo_parsable[] = {
2N/A "powered-on",
2N/A " assigned"
2N/A};
2N/A
2N/Astatic void
2N/Abd_info(apd_t *a, cfga_info_t info, int parsable)
2N/A{
2N/A int i;
2N/A int nsep;
2N/A const char **p;
2N/A sbd_stat_t *st;
2N/A char *end = &info[sizeof (cfga_info_t)];
2N/A
2N/A DBG("bd_info(%p)\n", (void *)info);
2N/A
2N/A st = (sbd_stat_t *)a->stat;
2N/A
2N/A if (parsable) {
2N/A p = binfo_parsable;
2N/A nsep = 1;
2N/A } else {
2N/A p = binfo;
2N/A nsep = 2;
2N/A }
2N/A
2N/A i = nsep;
2N/A
2N/A if (st->s_power) {
2N/A info += snprintf(info, end - info, p[BI_POWERED]);
2N/A i = 0;
2N/A }
2N/A if (st->s_assigned)
2N/A info += snprintf(info, end - info, p[BI_ASSIGNED] + i);
2N/A}
2N/A
2N/A#define CI_CPUID 0
2N/A#define CI_SPEED 1
2N/A#define CI_ECACHE 2
2N/A
2N/Astatic const char *
2N/Acpuinfo[] = {
2N/A "cpuid %d",
2N/A ", speed %d MHz",
2N/A ", ecache %d MBytes"
2N/A};
2N/A
2N/Astatic const char *
2N/Acpuinfo_parsable[] = {
2N/A "cpuid=%d",
2N/A " speed=%d",
2N/A " ecache=%d"
2N/A};
2N/A
2N/Astatic void
2N/Acpu_info(apd_t *a, cfga_info_t info, int parsable)
2N/A{
2N/A const char **p;
2N/A sbd_cpu_stat_t *dst;
2N/A char *end = &info[sizeof (cfga_info_t)];
2N/A
2N/A DBG("cpu_info(%p)\n", (void *)info);
2N/A
2N/A dst = (sbd_cpu_stat_t *)a->cmstat;
2N/A
2N/A if (parsable)
2N/A p = cpuinfo_parsable;
2N/A else
2N/A p = cpuinfo;
2N/A
2N/A info += snprintf(info, end - info, p[CI_CPUID], dst->cs_cpuid);
2N/A info += snprintf(info, end - info, p[CI_SPEED], dst->cs_speed);
2N/A info += snprintf(info, end - info, p[CI_ECACHE], dst->cs_ecache);
2N/A}
2N/A
2N/A#define MI_ADDRESS 0
2N/A#define MI_SIZE 1
2N/A#define MI_PERMANENT 2
2N/A#define MI_UNCONFIGURABLE 3
2N/A#define MI_SOURCE 4
2N/A#define MI_TARGET 5
2N/A#define MI_DELETED 6
2N/A#define MI_REMAINING 7
2N/A#define MI_INTERLEAVE 8
2N/A
2N/Astatic const char *
2N/Ameminfo_nonparsable[] = {
2N/A "base address 0x%" PRIx64,
2N/A ", %lu KBytes total",
2N/A ", %lu KBytes permanent",
2N/A ", unconfigurable",
2N/A ", memory delete requested on %s",
2N/A ", memory delete in progress on %s",
2N/A ", %lu KBytes deleted",
2N/A ", %lu KBytes remaining",
2N/A ", inter board interleave"
2N/A};
2N/A
2N/Astatic const char *
2N/Ameminfo_parsable[] = {
2N/A "address=0x%" PRIx64,
2N/A " size=%lu",
2N/A " permanent=%lu",
2N/A " unconfigurable",
2N/A " source=%s",
2N/A " target=%s",
2N/A " deleted=%lu",
2N/A " remaining=%lu",
2N/A " inter-board-interleave"
2N/A};
2N/A
2N/A
2N/A#define _K1 1024
2N/A
2N/A/*
2N/A * This function assumes pagesize > 1024 and that
2N/A * pagesize is a multiple of 1024.
2N/A */
2N/Astatic ulong_t
2N/Apages_to_kbytes(uint_t pgs)
2N/A{
2N/A long pagesize;
2N/A
2N/A pagesize = sysconf(_SC_PAGESIZE);
2N/A return (pgs * (pagesize / _K1));
2N/A}
2N/A
2N/Astatic uint64_t
2N/Apages_to_bytes(uint_t pgs)
2N/A{
2N/A long pagesize;
2N/A
2N/A pagesize = sysconf(_SC_PAGESIZE);
2N/A return ((uint64_t)pgs * pagesize);
2N/A}
2N/A
2N/Astatic void
2N/Amem_info(apd_t *a, cfga_info_t info, int parsable)
2N/A{
2N/A const char **p;
2N/A sbd_mem_stat_t *dst;
2N/A int want_progress;
2N/A char *end = &info[sizeof (cfga_info_t)];
2N/A
2N/A DBG("mem_info(%p)\n", (void *)info);
2N/A
2N/A dst = (sbd_mem_stat_t *)a->cmstat;
2N/A
2N/A if (parsable)
2N/A p = meminfo_parsable;
2N/A else
2N/A p = meminfo_nonparsable;
2N/A
2N/A info += snprintf(info, end - info, p[MI_ADDRESS],
2N/A pages_to_bytes(dst->ms_basepfn));
2N/A info += snprintf(info, end - info, p[MI_SIZE],
2N/A pages_to_kbytes(dst->ms_totpages));
2N/A
2N/A if (dst->ms_noreloc_pages)
2N/A info += snprintf(info, end - info, p[MI_PERMANENT],
2N/A pages_to_kbytes(dst->ms_noreloc_pages));
2N/A if (!dst->ms_cage_enabled)
2N/A info += snprintf(info, end - info, p[MI_UNCONFIGURABLE]);
2N/A if (dst->ms_interleave)
2N/A info += snprintf(info, end - info, p[MI_INTERLEAVE]);
2N/A
2N/A /*
2N/A * If there is a valid peer physical ap_id specified,
2N/A * convert it to a logical id.
2N/A */
2N/A want_progress = 0;
2N/A if (str_valid(dst->ms_peer_ap_id)) {
2N/A char *cm;
2N/A char *peer;
2N/A char physid[MAXPATHLEN];
2N/A char logid[MAXPATHLEN];
2N/A
2N/A (void) snprintf(physid, sizeof (physid), "%s%s",
2N/A DEVDIR, dst->ms_peer_ap_id);
2N/A
2N/A /*
2N/A * Save the component portion of the physid and
2N/A * add it back after converting to logical format.
2N/A */
2N/A if ((cm = strstr(physid, "::")) != NULL) {
2N/A *cm = '\0';
2N/A cm += 2;
2N/A }
2N/A
2N/A /* attempt to resolve to symlink */
2N/A if (ap_symid(a, physid, logid, sizeof (logid)) == 0)
2N/A peer = logid;
2N/A else
2N/A peer = physid;
2N/A
2N/A if (dst->ms_peer_is_target) {
2N/A info += snprintf(info, end - info, p[MI_TARGET], peer);
2N/A if (cm)
2N/A info += snprintf(info, end - info, "::%s", cm);
2N/A want_progress = 1;
2N/A } else {
2N/A info += snprintf(info, end - info, p[MI_SOURCE], peer);
2N/A if (cm)
2N/A info += snprintf(info, end - info, "::%s", cm);
2N/A }
2N/A }
2N/A if (want_progress ||
2N/A (dst->ms_detpages != 0 && dst->ms_detpages != dst->ms_totpages)) {
2N/A info += snprintf(info, end - info, p[MI_DELETED],
2N/A pages_to_kbytes(dst->ms_detpages));
2N/A info += snprintf(info, end - info, p[MI_REMAINING],
2N/A pages_to_kbytes(dst->ms_totpages -
2N/A dst->ms_detpages));
2N/A }
2N/A}
2N/A
2N/A#define II_DEVICE 0
2N/A#define II_REFERENCED 1
2N/A
2N/Astatic const char *
2N/Aioinfo[] = {
2N/A "device %s",
2N/A ", referenced"
2N/A};
2N/A
2N/Astatic const char *
2N/Aioinfo_parsable[] = {
2N/A "device=%s",
2N/A " referenced"
2N/A};
2N/A
2N/Astatic void
2N/Aio_info(apd_t *a, cfga_info_t info, int parsable)
2N/A{
2N/A const char **p;
2N/A sbd_io_stat_t *dst;
2N/A char *end = &info[sizeof (cfga_info_t)];
2N/A
2N/A dst = (sbd_io_stat_t *)a->cmstat;
2N/A
2N/A if (parsable)
2N/A p = ioinfo_parsable;
2N/A else
2N/A p = ioinfo;
2N/A
2N/A info += snprintf(info, end - info, p[II_DEVICE], dst->is_pathname);
2N/A if (dst->is_referenced)
2N/A info += snprintf(info, end - info, p[II_REFERENCED]);
2N/A}
2N/A
2N/A#define PI_CPUID 0
2N/A#define PI_CPUID_PAIR 1
2N/A#define PI_CPUID_CONT 2
2N/A#define PI_CPUID_LAST 3
2N/A#define PI_SPEED 4
2N/A#define PI_ECACHE 5
2N/A
2N/Astatic const char *
2N/Acmpinfo[] = {
2N/A "cpuid %d",
2N/A " and %d",
2N/A ", %d",
2N/A ", and %d",
2N/A ", speed %d MHz",
2N/A ", ecache %d MBytes"
2N/A};
2N/A
2N/Astatic const char *
2N/Acmpinfo_parsable[] = {
2N/A "cpuid=%d",
2N/A ",%d",
2N/A ",%d",
2N/A ",%d",
2N/A " speed=%d",
2N/A " ecache=%d"
2N/A};
2N/A
2N/Astatic void
2N/Acmp_info(apd_t *a, cfga_info_t info, int parsable)
2N/A{
2N/A int i;
2N/A int last;
2N/A const char **p;
2N/A sbd_cmp_stat_t *dst;
2N/A char *end = &info[sizeof (cfga_info_t)];
2N/A
2N/A DBG("cmp_info(%p)\n", (void *)info);
2N/A
2N/A dst = (sbd_cmp_stat_t *)a->cmstat;
2N/A
2N/A if (parsable)
2N/A p = cmpinfo_parsable;
2N/A else
2N/A p = cmpinfo;
2N/A
2N/A /* Print the first cpuid */
2N/A info += snprintf(info, end - info, p[PI_CPUID], dst->ps_cpuid[0]);
2N/A
2N/A /*
2N/A * Print the middle cpuids, if necessary. Stop before
2N/A * the last one, since printing the last cpuid is a
2N/A * special case for the non parsable form.
2N/A */
2N/A for (i = 1; i < (dst->ps_ncores - 1); i++) {
2N/A info += snprintf(info, end - info, p[PI_CPUID_CONT],
2N/A dst->ps_cpuid[i]);
2N/A }
2N/A
2N/A /* Print the last cpuid, if necessary */
2N/A if (dst->ps_ncores > 1) {
2N/A last = (dst->ps_ncores == 2) ? PI_CPUID_PAIR : PI_CPUID_LAST;
2N/A info += snprintf(info, end - info,
2N/A dgettext(TEXT_DOMAIN, p[last]), dst->ps_cpuid[i]);
2N/A }
2N/A
2N/A info += snprintf(info, end - info, p[PI_SPEED], dst->ps_speed);
2N/A info += snprintf(info, end - info, p[PI_ECACHE], dst->ps_ecache);
2N/A}
2N/A
2N/Avoid
2N/Aap_info(apd_t *a, cfga_info_t info, ap_target_t tgt)
2N/A{
2N/A int parsable = ap_getopt(a, OPT_PARSABLE);
2N/A
2N/A DBG("ap_info(%p, %d)\n", (void *)info, parsable);
2N/A
2N/A switch (tgt) {
2N/A case AP_BOARD:
2N/A bd_info(a, info, parsable);
2N/A break;
2N/A case AP_CPU:
2N/A cpu_info(a, info, parsable);
2N/A break;
2N/A case AP_MEM:
2N/A mem_info(a, info, parsable);
2N/A break;
2N/A case AP_IO:
2N/A io_info(a, info, parsable);
2N/A break;
2N/A case AP_CMP:
2N/A cmp_info(a, info, parsable);
2N/A break;
2N/A default:
2N/A break;
2N/A }
2N/A}