diff options
author | stevel <none@none> | 2006-06-29 14:43:12 -0700 |
---|---|---|
committer | stevel <none@none> | 2006-06-29 14:43:12 -0700 |
commit | 3db86aab554edbb4244c8d1a1c90f152eee768af (patch) | |
tree | 705cf08ad6c4913d9bf209e3b319816d99d03779 /usr/src/lib | |
parent | e34b029407ed5ec566196ede3f54256d7868dd10 (diff) | |
download | illumos-joyent-3db86aab554edbb4244c8d1a1c90f152eee768af.tar.gz |
6392835 move driver central to usr/src
6392843 move driver socal to usr/src
6393456 move driver pcic to usr/src
6393457 move driver pem to usr/src
6393459 move driver envctrltwo to usr/src
6393461 move driver lombus to usr/src
6393465 move driver rmclomv to usr/src
6393468 move driver wrsmd to usr/src
6438236 cfgadm plugins for ac & sysctrl want to be reunited with their drivers in usr/src
6443714 CardBus driver should be moved from usr/closed to usr/src
Diffstat (limited to 'usr/src/lib')
23 files changed, 5532 insertions, 7 deletions
diff --git a/usr/src/lib/cfgadm_plugins/Makefile b/usr/src/lib/cfgadm_plugins/Makefile index a2afd72d10..399a8e3a8d 100644 --- a/usr/src/lib/cfgadm_plugins/Makefile +++ b/usr/src/lib/cfgadm_plugins/Makefile @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -29,16 +29,11 @@ include $(SRC)/Makefile.master -CLOSED_PLUGIN = $(CLOSED)/lib/cfgadm_plugins/ - COMMON_SUBDIRS= scsi pci usb ib -sparc_SUBDIRS= sbd +sparc_SUBDIRS= sbd ac sysctrl i386_SUBDIRS= sata -$(CLOSED_BUILD)sparc_SUBDIRS += $(CLOSED_PLUGIN)/ac -$(CLOSED_BUILD)sparc_SUBDIRS += $(CLOSED_PLUGIN)/sysctrl - SUBDIRS= $(COMMON_SUBDIRS) $($(MACH)_SUBDIRS) ALL_SUBDIRS= $(COMMON_SUBDIRS) $(sparc_SUBDIRS) $(i386_SUBDIRS) diff --git a/usr/src/lib/cfgadm_plugins/ac/Makefile b/usr/src/lib/cfgadm_plugins/ac/Makefile new file mode 100644 index 0000000000..09d804f547 --- /dev/null +++ b/usr/src/lib/cfgadm_plugins/ac/Makefile @@ -0,0 +1,74 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" +# +# lib/cfgadm_plugins/ac/Makefile + +include $(SRC)/Makefile.master + +SUBDIRS= $(MACH) $(BUILD64) $(MACH64) + +all := TARGET= all +clean := TARGET= clean +clobber := TARGET= clobber +delete := TARGET= delete +install := TARGET= install +lint := TARGET= lint +_msg := TARGET= _msg +catalog := TARGET= catalog +package := TARGET= package + +TEXT_DOMAIN= SUNW_OST_OSLIB +XGETFLAGS= -a -x ac.xcl +POFILE= ac.po +POFILES= generic.po + +SED= sed +GREP= grep +CP= cp + +.KEEP_STATE: + +all clean clobber delete install lint catalog package: $(SUBDIRS) + +$(MACH) $(MACH64): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +_msg: $(MSGDOMAIN) $(POFILE) + $(RM) $(MSGDOMAIN)/$(POFILE) + $(CP) $(POFILE) $(MSGDOMAIN) + +$(POFILE): $(POFILES) + $(RM) $@ + $(CAT) $(POFILES) > $@ + +$(POFILES): + $(RM) messages.po + $(XGETTEXT) $(XGETFLAGS) `$(GREP) -l gettext */*.[ch]` + $(SED) -e '/^# msg/d' -e '/^domain/d' messages.po > $@ + $(RM) messages.po + +FRC: diff --git a/usr/src/lib/cfgadm_plugins/ac/Makefile.com b/usr/src/lib/cfgadm_plugins/ac/Makefile.com new file mode 100644 index 0000000000..c7aa48aadc --- /dev/null +++ b/usr/src/lib/cfgadm_plugins/ac/Makefile.com @@ -0,0 +1,99 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# lib/ac/Makefile.com + +include $(SRC)/lib/cfgadm_plugins/Makefile.com + +PLATFORM= sun4u +LIBRARY= ac.a +VERS= .1 + +OBJECTS= mema.o mema_prom.o mema_test.o mema_test_config.o mema_test_subr.o \ + mema_util.o + +# include library definitions +include $(SRC)/lib/Makefile.lib + +INS.dir.root.sys= $(INS) -s -d -m $(DIRMODE) $@ +$(CH)INS.dir.root.sys= $(INS) -s -d -m $(DIRMODE) -u root -g sys $@ +INS.dir.root.bin= $(INS) -s -d -m $(DIRMODE) $@ +$(CH)INS.dir.root.bin= $(INS) -s -d -m $(DIRMODE) -u root -g bin $@ + +USR_PLAT_DIR = $(ROOT)/usr/platform +USR_PSM_DIR = $(USR_PLAT_DIR)/sun4u +USR_PSM_LIB_DIR = $(USR_PSM_DIR)/lib +USR_PSM_LIB_CFG_DIR = $(USR_PSM_LIB_DIR)/cfgadm +USR_PSM_LIB_CFG_DIR_64 = $(USR_PSM_LIB_CFG_DIR)/$(MACH64) + +ROOTLIBDIR= $(USR_PSM_LIB_CFG_DIR) +ROOTLIBDIR64= $(USR_PSM_LIB_CFG_DIR_64) + +MAPFILE= ../common/mapfile-vers +SRCS= $(OBJECTS:%.o=../common/%.c) + +LIBS = $(DYNLIB) + +CFLAGS += $(CCVERBOSE) +DYNFLAGS += -M $(MAPFILE) +LDLIBS += -lc + +CPPFLAGS += -I$(ROOT)/usr/platform/$(PLATFORM)/include + +.KEEP_STATE: + +all: $(LIBS) + +lint: lintcheck + +$(DYNLIB): $(MAPFILE) + +# Create target directories +$(USR_PSM_DIR): $(LINKED_DIRS) + -$(INS.dir.root.sys) + +$(USR_PSM_LIB_DIR): $(USR_PSM_DIR) $(LINKED_LIB_DIRS) + -$(INS.dir.root.bin) + +$(USR_PSM_LIB_CFG_DIR): $(USR_PSM_LIB_DIR) $(LINKED_CFG_DIRS) + -$(INS.dir.root.bin) + +$(USR_PSM_LIB_CFG_DIR_64): $(USR_PSM_LIB_CFG_DIR) + -$(INS.dir.root.bin) + +$(USR_PSM_LIB_CFG_DIR)/%: % $(USR_PSM_LIB_CFG_DIR) + -$(INS.file) + +$(USR_PSM_LIB_CFG_DIR_64)/%: % $(USR_PSM_LIB_CFG_DIR_64) + -$(INS.file) + +# include library targets +include $(SRC)/lib/Makefile.targ + +pics/%.o: ../common/%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) diff --git a/usr/src/lib/cfgadm_plugins/ac/ac.xcl b/usr/src/lib/cfgadm_plugins/ac/ac.xcl new file mode 100644 index 0000000000..a42c3d6301 --- /dev/null +++ b/usr/src/lib/cfgadm_plugins/ac/ac.xcl @@ -0,0 +1,114 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +msgid "disable-at-boot" +msgid "enable-at-boot" +msgid "timeout" +msgid "errno=%d" +msgid "bank" +msgid "ap_bk_idx(%s)\n" +msgid "ap_bk_idx: s=%s, n=%d\n" +msgid "ap_bk_idx(%s)=%d\n" +msgid "relocate-test" +msgid "board %d bank%d" +msgid ", " +msgid "???" +msgid "" +msgid "slot%d" +msgid " empty" +msgid "Gb" +msgid "Mb" +msgid " %d%s" +msgid " (%d%s used)" +msgid " base 0x%llx" +msgid " interleaved %u-way" +msgid " %s" +msgid "disabled at boot" +msgid " permanent" +msgid "memory" +msgid "ap_drv_idx(%s)\n" +msgid "ac" +msgid "ap_drv_idx(%s)=%d\n" +msgid "MEMADM_DEBUG" +msgid "a" +msgid "\nDebug started, pid=%d\n" +msgid "IOCTL: AC_MEM_CONFIGURE\n" +msgid "IOCTL: AC_MEM_UNCONFIGURE\n" +msgid "IOCTL: AC_MEM_TEST_START\n" +msgid "IOCTL: AC_MEM_TEST_STOP handle=%#x " + "condition=%d\n" +msgid "IOCTL: AC_MEM_TEST_READ handle=%#x " + "buf=%#x page=%#llx off=%#x count=%#x\n" +msgid "IOCTL: AC_MEM_TEST_WRITE handle=%#x " + "buf=%#x page=%#llx off=%#x count=%#x\n" +msgid "IOCTL: AC_MEM_ADMIN_VER:\n" +msgid "IOCTL: AC_MEM_STAT\n" +msgid "IOCTL: AC_MEM_EXERCISE arg=%d\n" +msgid "IOCTL: unknown (%#x)\n" +msgid "IOCTL failed, \"%s\" (errno=%d)\n" +msgid "IOCTL succeeded, ret=%d\n" +msgid " handle=%#x tester_pid=%d " + "prev_condition=%d bank_size=%#llx " + "page_size=%#x line_size=%#x afar_base=%#llx\n" +msgid "module_id=%#llx afsr=%#llx " + "afar=%#llx udbh_error_reg=%#llx " + "udbl_error_reg=%#llx\n" +msgid "\n" +msgid " version %d\n" +msgid " rstate=%u ostate=%u " + "condition=%u status_time=%#lx board=%u\n" +msgid " real_size=%u use_size=%u " + "busy=%u\n" +msgid " page_size=%#x " + "phys_pages=%#llx managed=%#llx nonrelocatable=%#llx\n" +msgid " memctl=%#llx " + "decode0=%#llx decode1=%#llx\n" +msgid " base=%u npgs=%u" + " nopaget=%u nolock=%u isfree=%u reloc=%u" + " noreloc=%u\n" +msgid "total error %u\n" +msgid "quick" +msgid "normal" +msgid "extended" +msgid "max_errors" +msgid "Normal test started\n" +msgid "Normal test finished\n" +msgid "Quick test started\n" +msgid "Quick test finished\n" +msgid "Extended test started\n" +msgid "Extended test finished\n" +msgid " March 1, " +msgid " March 2, " +msgid " March 3, " +msgid " March 4, " +msgid "read. " +msgid "write. " +msgid "compare. " +msgid "read/compare. " +msgid "repeated read/compare. " +msgid "mixed line read/compare. " +msgid "line read/compare. " +msgid "%s%s%d%% complete.\n" +msgid " Errors at page address: 0x%x.\n" +msgid " Error reading page at address: 0x%x.\n" +msgid " Error writing page at address: 0x%x.\n" +msgid " Offset: 0x%x, data written/read: 0x%2x/0x%2x.\n" +msgid "\t-o {quick, normal, extended},[max_errors=#] -t ap_id [ap_id...]\n" diff --git a/usr/src/lib/cfgadm_plugins/ac/common/mapfile-vers b/usr/src/lib/cfgadm_plugins/ac/common/mapfile-vers new file mode 100644 index 0000000000..b535a50cf7 --- /dev/null +++ b/usr/src/lib/cfgadm_plugins/ac/common/mapfile-vers @@ -0,0 +1,38 @@ +# +#pragma ident "%Z%%M% %I% %E% SMI" +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +SUNWprivate_1.1 { + global: + cfga_change_state; + cfga_private_func; + cfga_test; + cfga_stat; + cfga_list; + cfga_help; + local: + *; +}; diff --git a/usr/src/lib/cfgadm_plugins/ac/common/mema.c b/usr/src/lib/cfgadm_plugins/ac/common/mema.c new file mode 100644 index 0000000000..1b08d13f92 --- /dev/null +++ b/usr/src/lib/cfgadm_plugins/ac/common/mema.c @@ -0,0 +1,1814 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stddef.h> +#include <stdlib.h> +#include <unistd.h> +#include <ctype.h> +#include <fcntl.h> +#include <signal.h> +#include <string.h> +#include <locale.h> +#include <errno.h> +#include <assert.h> +#include <sys/dditypes.h> +#include <sys/param.h> +#include <sys/obpdefs.h> +#include <sys/fhc.h> +#include <sys/sysctrl.h> +#include <sys/ac.h> +#include <sys/spitregs.h> +#include <config_admin.h> +#include "mema_util.h" +#include "mema_test.h" +#include "mema_prom.h" + +#ifdef DEBUG +#define DBG (void) printf +#define DBG1 (void) printf +#define DBG3 (void) printf +#define DBG4 (void) printf +#else +#define DBG(a, b) +#define DBG1(a) +#define DBG3(a, b, c) +#define DBG4(a, b, c, d) +#endif + +#ifndef P_DER_UE +/* + * <sys/spitregs.h> has these defines inside 'ifdef _KERNEL' at the + * time of writing. Re-define here if that is still the case. + */ + +#define P_DER_UE 0x00000000000000200ULL /* UE has occurred */ +#define P_DER_CE 0x00000000000000100ULL /* CE has occurred */ +#define P_DER_E_SYND 0x000000000000000FFULL /* SYND<7:0>: ECC syndrome */ +#endif /* ! P_DER_UE */ + +#define DEV_DEBUG +#ifdef DEV_DEBUG +#include <stdio.h> +#include <stdlib.h> + +static FILE *debug_fp; +static int debugging(void); +static void dump_ioctl(int, void *); +static void dump_ioctl_res(int, void *, int, int); +#else /* DEV_DEBUG */ +#define dump_ioctl(CMD, ARG) +#define dump_ioctl_res(CMD, ARG, RET, ERRNO) +#endif /* DEV_DEBUG */ + +typedef struct { + uint_t board; + uint_t bank; +} mema_bank_t; + +static char *mema_opts[] = { +#define OPT_BOOT_DISABLE 0 + "disable-at-boot", +#define OPT_BOOT_ENABLE 1 + "enable-at-boot", +#define OPT_TIMEOUT 2 + "timeout", + NULL +}; + +#define OPT_NEEDS_VALUE(O) ((O) == OPT_TIMEOUT) + +#define MAX_OPT_LENGTH (sizeof ("disable-at-boot")) + +/* + * For each function there is an array of opt_control structures giving + * the valid options. The array is terminated by an element with the + * subopt field set to -1. The group field is used to identify + * mutually exclusive options, with zero meaning no grouping. + */ +struct opt_control { + int subopt; + int group; +}; + +/* + * Returned set of options. + * If the option takes a value, it will be set in 'val' + * if the corresponding bit is set in 'bits' is set, + * otherwise the pointer in 'val' is undefined. + */ +#define OPT_VAL_ARRAY_SIZE 32 /* # bits in 'bits' */ +typedef struct { + unsigned int bits; + char *val[OPT_VAL_ARRAY_SIZE]; +} option_set_t; + +#define OPTSET_INIT(S) ((S).bits = 0) +#define _OPT_TO_BIT(O) (1 << (O)) +#define OPTSET_SET_VAL(S, O, V) ((S).bits |= _OPT_TO_BIT(O), \ + (S).val[(O)] = (V)) +#define OPTSET_TEST(S, O) (((S).bits & _OPT_TO_BIT(O)) != 0) +#define OPTSET_VAL(S, O) ((S).val[(O)]) +#define OPTSET_IS_EMPTY(S) ((S).bits == 0) + +static option_set_t process_options(const char *, struct opt_control *, + int *, char **); + +static struct opt_control add_opts[] = { + {OPT_BOOT_ENABLE, 1}, + {OPT_BOOT_DISABLE, 1}, + {-1, 0} +}; + +static struct opt_control del_opts[] = { + {OPT_BOOT_ENABLE, 1}, + {OPT_BOOT_DISABLE, 1}, + {OPT_TIMEOUT, 2}, + {-1, 0} +}; + +static struct opt_control stat_opts[] = { + {OPT_BOOT_ENABLE, 1}, + {OPT_BOOT_DISABLE, 1}, + {-1, 0} +}; + +#if !defined(TEXT_DOMAIN) +#define TEXT_DOMAIN "SYS_TEST" +#endif + +static const char still_testing[] = "bank %s being tested by process %d"; +static const char no_value[] = "sub-option \"%s\" does not take a value"; +static const char missing_value[] = "sub-option \"%s\" needs a value"; +static const char conflict_opt[] = "sub-option \"%s\" conflicts with \"%s\""; +static const char unk_subopt[] = "sub-option \"%s\" unknown\n" + "choose from: %s"; +static const char not_valid[] = + "sub-option \"%s\" not valid for this operation\n" + "choose from: %s"; +static const char timeout_notnum[] = + "timeout value not a positive integer \"%s\""; +static const char calloc_fail[] = "memory allocation failed (%d*%d bytes)"; +static const char unk_test[] = "test \"%s\" unknown\n" + "choose from: %s"; +static const char dup_test[] = "more than one test type specified (\"%s\")"; +static const char dup_num[] = "option specified more than once (\"%s\")"; +static const char no_num[] = "invalid number specified for max_errors(\"%s\")"; +static const char mtest_rw_error[] = "memory test read/write error"; +static const char mtest_lib_error[] = "memory test library error"; +static const char dlist_invalid[] = "invalid disabled-memory-list"; +static const char dlist_write_failed[] = "disabled-memory-list write failed"; +static const char mtest_unknown_error[] = "unknown memory test error"; +static const char ap_invalid[] = "invalid attachment point: %s"; +static const char trans_illegal[] = "illegal transition"; +static const char open_failed[] = "open failed: %s: %s"; +static const char mema_help[] = "\nAc specific options:\n"; +static const char disable_opts[] = "\t-o disable-at-boot\n"; +static const char enable_opts[] = "\t-o enable-at-boot\n"; +static const char timeout_opts[] = "\t-o timeout=# (seconds)\n"; +static const char test_opts[] = + "\t-o {quick, normal, extended},[max_errors=#] -t ap_id [ap_id...]\n"; +static const char private_funcs[] = "\t-x relocate-test ap_id [ap_id...]\n"; +static const char add_is_disabled[] = "memory is disabled at boot"; +static const char add_willbe_disabled[] = + "memory will be disabled at boot"; +static const char add_disab_err[] = "cannot get memory disabled status"; +static const char pfunc_unknown[] = "private function \"%s\" unknown"; + + +#define mema_eid(a, b) (((a) << 8) + (b)) +#define mema_str(i) mema_strs[(i)] + +#define AC_BK_BUSY 0 +#define AC_BK_ID 1 +#define AC_BD_ID 2 +#define AC_BD_TYPE 3 +#define AC_BD_STATE 4 +#define AC_MEM_TEST_ID 5 +#define AC_MEM_TEST_PAR 6 +#define AC_MEM_PERM 7 +#define AC_KPM_CANCELLED 8 +#define AC_KPM_REFUSED 9 +#define AC_KPM_SPAN 10 +#define AC_KPM_DUP 11 +#define AC_KPM_FAULT 12 +#define AC_KPM_RESOURCE 13 +#define AC_KPM_NOTSUP 14 +#define AC_KPM_NOHANDLES 15 +#define AC_KPM_NONRELOC 16 +#define AC_KPM_HANDLE 17 +#define AC_KPM_BUSY 18 +#define AC_KPM_NOTVIABLE 19 +#define AC_KPM_SEQUENCE 20 +#define AC_KPM_NOWORK 21 +#define AC_KPM_NOTFINISHED 22 +#define AC_KPM_NOTRUNNING 23 +#define AC_VMEM 24 +#define CMD_MEM_STAT 25 +#define CMD_MEM_ADD 26 +#define CMD_MEM_DEL 27 +#define CMD_MEM_TEST_START 28 +#define CMD_MEM_TEST_STOP 29 +#define AC_UNKNOWN 30 +#define AC_INTR 31 +#define AC_TIMEOUT 32 +#define CMD_MEM_RELOCTEST 33 +#define AC_DEINTLV 34 + +static char * +mema_strs[] = { + "memory bank busy", + "invalid memory bank", + "invalid board id", + "invalid board type", + "invalid board state", + "invalid memory test id", + "invalid memory test parameter(s)", + "no write permission", + "memory operation cancelled", + "memory operation refused", + "memory already in use (add)", + "memory span duplicate (delete)", + "memory access test failed (add)", + "some resource was not available", + "operation not supported", + "cannot allocate any more handles", + "non-relocatable pages in span", + "bad handle supplied", + "memory in span is being deleted", + "VM viability test failed", + "function called out of sequence", + "no memory to delete", + "delete processing not finished", + "delete processing not running", + "insufficient virtual memory", + "memory stat failed: %s", + "memory add failed: %s", + "memory delete failed: %s", + "memory test start failed: %s", + "memory test stop failed: %s", + "unknown error", + "memory delete killed", + "memory delete timeout", + "memory relocate-test failed: %s", + "memory cannot be de-interleaved" +}; + +/* + * AC_MEM_PERM, EBADF, AC_ERR_MEM_PERM + * AC_BK_BUSY, EBUSY, AC_ERR_MEM_BK + * AC_KPM_CANCELLED, EINTR, AC_ERR_KPM_CANCELLED + * AC_KPM_REFUSED, EINTR, AC_ERR_KPM_REFUSED + * AC_BK_ID, EINVAL, AC_ERR_MEM_BK + * AC_BD_ID, EINVAL, AC_ERR_BD + * AC_BD_TYPE, EINVAL, AC_ERR_BD_TYPE + * AC_BD_STATE, EINVAL, AC_ERR_BD_STATE + * AC_MEM_TEST_ID, EINVAL, AC_ERR_MEM_TEST + * AC_MEM_TEST_PAR, EINVAL, AC_ERR_MEM_TEST_PAR + * AC_KPM_SPAN, EINVAL, AC_ERR_KPM_SPAN + * AC_KPM_DUP, EINVAL, AC_ERR_KPM_DUP? + * AC_KPM_FAULT, EINVAL, AC_ERR_KPM_FAULT + * AC_KPM_RESOURCE, EINVAL, AC_ERR_KPM_RESOURCE + * AC_KPM_NOTSUP, EINVAL, AC_ERR_KPM_NOTSUP + * AC_KPM_NOHANDLES, EINVAL, AC_ERR_KPM_NOHANDLES + * AC_KPM_NONRELOC, EINVAL, AC_ERR_KPM_NONRELOC + * AC_KPM_HANDLE, EINVAL, AC_ERR_KPM_HANDLE + * AC_KPM_BUSY, EINVAL, AC_ERR_KPM_BUSY + * AC_KPM_NOTVIABLE, EINVAL, AC_ERR_KPM_NOTVIABLE + * AC_KPM_SEQUENCE, EINVAL, AC_ERR_KPM_SEQUENCE + * AC_KPM_NOWORK, EINVAL, AC_ERR_KPM_NOWORK + * AC_KPM_NOTFINISHED, EINVAL, AC_ERR_KPM_NOTFINISHED + * AC_KPM_NOTRUNNING, EINVAL, AC_ERR_KPM_NOTRUNNING + * AC_VMEM, ENOMEM, AC_ERR_VMEM + * AC_INTR, EINTR, AC_ERR_INTR + * AC_TIMEOUT, EINTR, AC_ERR_TIMEOUT + * AC_DEINTLV, EINVAL, AC_ERR_MEM_DEINTLV + */ +static int +mema_sid(int err, int acerr) +{ + if (acerr == AC_ERR_DEFAULT) + return (AC_UNKNOWN); + + switch (mema_eid(err, acerr)) { + case mema_eid(EBADF, AC_ERR_MEM_PERM): + return (AC_MEM_PERM); + case mema_eid(EBUSY, AC_ERR_MEM_BK): + return (AC_BK_BUSY); + case mema_eid(EINTR, AC_ERR_KPM_CANCELLED): + return (AC_KPM_CANCELLED); + case mema_eid(EINTR, AC_ERR_KPM_REFUSED): + return (AC_KPM_REFUSED); + case mema_eid(EINVAL, AC_ERR_MEM_BK): + return (AC_BK_ID); + case mema_eid(EINVAL, AC_ERR_BD): + return (AC_BD_ID); + case mema_eid(EINVAL, AC_ERR_BD_TYPE): + return (AC_BD_TYPE); + case mema_eid(EINVAL, AC_ERR_BD_STATE): + return (AC_BD_STATE); + case mema_eid(EINVAL, AC_ERR_MEM_TEST): + return (AC_MEM_TEST_ID); + case mema_eid(EINVAL, AC_ERR_MEM_TEST_PAR): + return (AC_MEM_TEST_PAR); + case mema_eid(EINVAL, AC_ERR_KPM_SPAN): + return (AC_KPM_SPAN); + case mema_eid(EINVAL, AC_ERR_KPM_DUP): + return (AC_KPM_DUP); + case mema_eid(EINVAL, AC_ERR_KPM_FAULT): + return (AC_KPM_FAULT); + case mema_eid(EINVAL, AC_ERR_KPM_RESOURCE): + return (AC_KPM_RESOURCE); + case mema_eid(EINVAL, AC_ERR_KPM_NOTSUP): + return (AC_KPM_NOTSUP); + case mema_eid(EINVAL, AC_ERR_KPM_NOHANDLES): + return (AC_KPM_NOHANDLES); + case mema_eid(EINVAL, AC_ERR_KPM_NONRELOC): + return (AC_KPM_NONRELOC); + case mema_eid(EINVAL, AC_ERR_KPM_HANDLE): + return (AC_KPM_HANDLE); + case mema_eid(EINVAL, AC_ERR_KPM_BUSY): + return (AC_KPM_BUSY); + case mema_eid(EINVAL, AC_ERR_KPM_NOTVIABLE): + return (AC_KPM_NOTVIABLE); + case mema_eid(EINVAL, AC_ERR_KPM_SEQUENCE): + return (AC_KPM_SEQUENCE); + case mema_eid(EINVAL, AC_ERR_KPM_NOWORK): + return (AC_KPM_NOWORK); + case mema_eid(EINVAL, AC_ERR_KPM_NOTFINISHED): + return (AC_KPM_NOTFINISHED); + case mema_eid(EINVAL, AC_ERR_KPM_NOTRUNNING): + return (AC_KPM_NOTRUNNING); + case mema_eid(ENOMEM, AC_ERR_VMEM): + return (AC_VMEM); + case mema_eid(EINTR, AC_ERR_INTR): + return (AC_INTR); + case mema_eid(EINTR, AC_ERR_TIMEOUT): + return (AC_TIMEOUT); + case mema_eid(EINVAL, AC_ERR_MEM_DEINTLV): + return (AC_DEINTLV); + default: + break; + } + + return (AC_UNKNOWN); +} + +static void +mema_err(ac_cfga_cmd_t *ac, int ret_errno, char **errstring, int cmd) +{ + char *cname = mema_str(cmd); + char *syserr; + char syserr_num[20]; + + if (ac) { + syserr = mema_str(mema_sid(ret_errno, ac->errtype)); + syserr = dgettext(TEXT_DOMAIN, syserr); + } else { + syserr = strerror(ret_errno); + /* strerror() does its own gettext(). */ + if (syserr == NULL) { + (void) sprintf(syserr_num, "errno=%d", errno); + syserr = syserr_num; + } + } + + __fmt_errstring(errstring, strlen(syserr), + dgettext(TEXT_DOMAIN, cname), syserr); +} + +static void +mema_cmd_init(ac_cfga_cmd_t *ac, void *cmd, char *outputstr, int force) +{ + (void) memset((void *)ac, 0, sizeof (*ac)); + + ac->errtype = AC_ERR_DEFAULT; + ac->private = cmd; + ac->force = force; + ac->outputstr = outputstr; + + (void) memset((void *)outputstr, 0, AC_OUTPUT_LEN); +} + +static int +ap_bk_idx(const char *ap_id) +{ + int id; + char *s; + static char *bank = "bank"; + + DBG("ap_bk_idx(%s)\n", ap_id); + + if ((s = strstr(ap_id, bank)) == NULL) + return (-1); + else { + int n; + + s += strlen(bank); + n = strlen(s); + + DBG3("ap_bk_idx: s=%s, n=%d\n", s, n); + + if ((n != 1) || !isdigit(s[0])) + return (-1); + } + + id = atoi(s); + + if (id < 0 || id > 1) + return (-1); + + DBG3("ap_bk_idx(%s)=%d\n", s, id); + + return (id); +} + +static cfga_err_t +ap_stat( + const char *bank_spec, + int *fdp, + mema_bank_t *bkp, + ac_stat_t *stp, + char **errstring) +{ + int fd; + int ret, ret_errno; + int bank; + mema_bank_t bk; + ac_stat_t stat; + ac_cfga_cmd_t cmd; + char outputstr[AC_OUTPUT_LEN]; + + if ((bank = ap_bk_idx(bank_spec)) == -1) { + __fmt_errstring(errstring, strlen(bank_spec), + dgettext(TEXT_DOMAIN, ap_invalid), bank_spec); + return (CFGA_ERROR); + } + + bk.bank = bank; + + if ((fd = open(bank_spec, ((fdp != NULL) ? O_RDWR : O_RDONLY), 0)) == + -1) { + char *syserr; + char syserr_num[20]; + + syserr = strerror(errno); + if (syserr == NULL) { + (void) sprintf(syserr_num, "errno=%d", errno); + syserr = syserr_num; + } + __fmt_errstring(errstring, strlen(syserr) + + strlen(bank_spec), + dgettext(TEXT_DOMAIN, open_failed), bank_spec, syserr); + return (CFGA_ERROR); + } + + mema_cmd_init(&cmd, &stat, outputstr, 0); + dump_ioctl(AC_MEM_STAT, NULL); + ret = ioctl(fd, AC_MEM_STAT, &cmd); + ret_errno = errno; + dump_ioctl_res(AC_MEM_STAT, &stat, ret, ret_errno); + + if (ret == -1) { + mema_err(&cmd, ret_errno, errstring, CMD_MEM_STAT); + (void) close(fd); + return (CFGA_ERROR); + } + + if (fdp) + *fdp = fd; + else + (void) close(fd); + + if (stp) + *stp = stat; + + if (bkp) { + bkp->bank = bk.bank; + bkp->board = stat.board; + } + + return (CFGA_OK); +} + +static void +set_disabled_bits(mema_disabled_t *dp, int value) +{ + if (value == 0) + *dp &= ~PROM_MEMORY_DISABLED; + else + *dp |= PROM_MEMORY_DISABLED; +} + +static void +set_present_bits(mema_disabled_t *dp, ac_stat_t *asp) +{ + if (asp->ostate == SYSC_CFGA_OSTATE_CONFIGURED) + *dp |= PROM_MEMORY_PRESENT; + else + *dp &= ~PROM_MEMORY_DISABLED; +} + +static cfga_err_t +prom_do_options( + option_set_t do_option, + int board, + ac_stat_t *asp, + char **errstring) +{ + cfga_err_t ret; + mema_disabled_t disab; + + if (!prom_read_disabled_list(&disab, board)) + return (CFGA_ERROR); + + set_present_bits(&disab, asp); + + ret = CFGA_OK; + + if (OPTSET_TEST(do_option, OPT_BOOT_ENABLE)) { + set_disabled_bits(&disab, 0); + if (!prom_viable_disabled_list(&disab)) { + __fmt_errstring(errstring, 0, + dgettext(TEXT_DOMAIN, dlist_invalid)); + ret = CFGA_ERROR; + } else if (!prom_write_disabled_list(&disab, board)) { + __fmt_errstring(errstring, 0, + dgettext(TEXT_DOMAIN, dlist_write_failed)); + ret = CFGA_ERROR; + } + } else if (OPTSET_TEST(do_option, OPT_BOOT_DISABLE)) { + set_disabled_bits(&disab, 1); + if (!prom_viable_disabled_list(&disab)) { + __fmt_errstring(errstring, 0, + dgettext(TEXT_DOMAIN, dlist_invalid)); + ret = CFGA_ERROR; + } else if (!prom_write_disabled_list(&disab, board)) { + __fmt_errstring(errstring, 0, + dgettext(TEXT_DOMAIN, dlist_write_failed)); + ret = CFGA_ERROR; + } + } + + return (ret); +} + +static cfga_err_t +mema_add( + const char *bank_spec, + const char *options, + char **errstring, + int force) +{ + mema_bank_t bk; + int fd, ret, ret_errno; + option_set_t do_option; + ac_cfga_cmd_t cmd; + ac_stat_t stat; + char outputstr[AC_OUTPUT_LEN]; + + ret = 0; + do_option = process_options(options, add_opts, &ret, errstring); + if (ret != 0) { + return (ret); + } + + ret = ap_stat(bank_spec, &fd, &bk, &stat, errstring); + if (ret != CFGA_OK) + return (ret); + + + if (stat.rstate != SYSC_CFGA_RSTATE_CONNECTED || + stat.ostate != SYSC_CFGA_OSTATE_UNCONFIGURED) { + __fmt_errstring(errstring, 0, + dgettext(TEXT_DOMAIN, trans_illegal)); + (void) close(fd); + return (CFGA_ERROR); + } + + if (!force) { + mema_disabled_t disab; + + if (prom_read_disabled_list(&disab, bk.board)) { + if (disab != 0 && + !OPTSET_TEST(do_option, OPT_BOOT_ENABLE)) { + __fmt_errstring(errstring, 0, + dgettext(TEXT_DOMAIN, add_is_disabled)); + (void) close(fd); + return (CFGA_ERROR); + } + if (disab == 0 && + OPTSET_TEST(do_option, OPT_BOOT_DISABLE)) { + __fmt_errstring(errstring, 0, + dgettext(TEXT_DOMAIN, add_willbe_disabled)); + (void) close(fd); + return (CFGA_ERROR); + } + } else { + __fmt_errstring(errstring, 0, + dgettext(TEXT_DOMAIN, add_disab_err)); + (void) close(fd); + return (CFGA_ERROR); + } + } + + mema_cmd_init(&cmd, NULL, outputstr, force); + dump_ioctl(AC_MEM_CONFIGURE, NULL); + ret = ioctl(fd, AC_MEM_CONFIGURE, &cmd); + ret_errno = errno; + dump_ioctl_res(AC_MEM_CONFIGURE, NULL, ret, ret_errno); + (void) close(fd); + + if (ret == -1) { + mema_err(&cmd, ret_errno, errstring, CMD_MEM_ADD); + return (CFGA_ERROR); + } + + ret = prom_do_options(do_option, bk.board, &stat, errstring); + + return (ret); +} + +static cfga_err_t +mema_delete( + const char *bank_spec, + const char *options, + char **errstring, + int force) +{ + mema_bank_t bk; + int fd, ret, ret_errno; + option_set_t do_option; + ac_cfga_cmd_t cmd; + ac_stat_t stat; + char outputstr[AC_OUTPUT_LEN]; + int timeout_secs = -1; /* Init to 'use default'. */ + + ret = 0; + do_option = process_options(options, del_opts, &ret, errstring); + if (ret != 0) { + return (ret); + } + + if (OPTSET_TEST(do_option, OPT_TIMEOUT)) { + char *to_val; + char *ep; + + to_val = OPTSET_VAL(do_option, OPT_TIMEOUT); + timeout_secs = (int)strtol(to_val, &ep, 10); + if (*ep != '\0' || ep == to_val || timeout_secs < 0) { + __fmt_errstring(errstring, strlen(to_val), + dgettext(TEXT_DOMAIN, timeout_notnum), to_val); + return (CFGA_ERROR); + } + } + + ret = ap_stat(bank_spec, &fd, &bk, &stat, errstring); + if (ret != CFGA_OK) + return (ret); + + if (stat.rstate != SYSC_CFGA_RSTATE_CONNECTED || + stat.ostate != SYSC_CFGA_OSTATE_CONFIGURED) { + __fmt_errstring(errstring, 0, + dgettext(TEXT_DOMAIN, trans_illegal)); + (void) close(fd); + return (CFGA_ERROR); + } + + mema_cmd_init(&cmd, NULL, outputstr, force); + cmd.arg = timeout_secs; + dump_ioctl(AC_MEM_UNCONFIGURE, NULL); + ret = ioctl(fd, AC_MEM_UNCONFIGURE, &cmd); + ret_errno = errno; + dump_ioctl_res(AC_MEM_UNCONFIGURE, NULL, ret, ret_errno); + (void) close(fd); + + if (ret == -1) { + mema_err(&cmd, ret_errno, errstring, CMD_MEM_DEL); + return (CFGA_ERROR); + } + + ret = prom_do_options(do_option, bk.board, &stat, errstring); + + return (ret); +} + +/*ARGSUSED*/ +cfga_err_t +cfga_change_state( + cfga_cmd_t state_change_cmd, + const char *ap_id, + const char *options, + struct cfga_confirm *confp, + struct cfga_msg *msgp, + char **errstring, + cfga_flags_t flags) +{ + int force; + cfga_err_t rc; + + if (errstring != NULL) + *errstring = NULL; + + force = flags & CFGA_FLAG_FORCE; + + switch (state_change_cmd) { + case CFGA_CMD_CONFIGURE: + rc = mema_add(ap_id, options, errstring, force); + break; + + case CFGA_CMD_UNCONFIGURE: + rc = mema_delete(ap_id, options, errstring, force); + break; + + default: + rc = CFGA_OPNOTSUPP; + break; + } + + return (rc); +} + +/*ARGSUSED*/ +cfga_err_t +cfga_private_func( + const char *function, + const char *ap_id, + const char *options, + struct cfga_confirm *confp, + struct cfga_msg *msgp, + char **errstring, + cfga_flags_t flags) +{ + mema_bank_t bk; + ac_stat_t stat; + int fd, ret, ret_errno; + ac_cfga_cmd_t cmd; + char outputstr[AC_OUTPUT_LEN]; + + if (errstring != NULL) + *errstring = NULL; + + ret = ap_stat(ap_id, &fd, &bk, &stat, errstring); + if (ret != CFGA_OK) + return (ret); + + if (strcmp(function, "relocate-test") == 0) { + struct ac_memx_relocate_stats rstat; + + mema_cmd_init(&cmd, NULL, outputstr, + (flags & CFGA_FLAG_FORCE)); + cmd.arg = AC_MEMX_RELOCATE_ALL; + cmd.private = &rstat; + (void) memset((void *)&rstat, 0, sizeof (rstat)); + dump_ioctl(AC_MEM_EXERCISE, &cmd); + ret = ioctl(fd, AC_MEM_EXERCISE, &cmd); + ret_errno = errno; + dump_ioctl_res(AC_MEM_EXERCISE, &cmd, ret, ret_errno); + (void) close(fd); + + if (ret == -1) { + mema_err(&cmd, ret_errno, errstring, CMD_MEM_RELOCTEST); + return (CFGA_ERROR); + } + return (CFGA_OK); + } + + __fmt_errstring(errstring, strlen(function), + dgettext(TEXT_DOMAIN, pfunc_unknown), function); + + return (CFGA_ERROR); +} + +static int +mtest_run( + int fd, + int test_fun, + mema_bank_t *abkp, + struct cfga_msg *msgp, + char **errstring, + ulong_t max_errors) +{ + ac_mem_test_start_t test_start; + ac_mem_test_stop_t test_stop; + struct mtest_handle handle; + int ret, ret_errno; + int res; + ac_cfga_cmd_t cmd; + char outputstr[AC_OUTPUT_LEN]; + + (void) memset((void *)&test_start, 0, sizeof (test_start)); + mema_cmd_init(&cmd, &test_start, outputstr, 0); + dump_ioctl(AC_MEM_TEST_START, &test_start); + ret = ioctl(fd, AC_MEM_TEST_START, &cmd); + ret_errno = errno; + dump_ioctl_res(AC_MEM_TEST_START, &test_start, ret, ret_errno); + + if (ret == -1) { + if (ret_errno == ENOTSUP) { + mema_err(&cmd, ret_errno, errstring, + CMD_MEM_TEST_START); + return (CFGA_OPNOTSUPP); + } + if (ret_errno == EBUSY && test_start.tester_pid > 0) { + /* + * Bank appears to be being tested. Check that + * process 'tester_pid' is still running. + */ + if (kill(test_start.tester_pid, 0) != -1 || + errno != ESRCH) { + cfga_ap_log_id_t bname; + + /* Process still exists. */ + (void) sprintf(bname, "board %d bank%d", + abkp->board, abkp->bank); + __fmt_errstring(errstring, strlen(bname), + dgettext(TEXT_DOMAIN, still_testing), + bname, test_start.tester_pid); + return (CFGA_ERROR); + } + /* + * Do a test stop and re-try the start. + */ + (void) memset((void *)&test_stop, 0, + sizeof (test_stop)); + test_stop.handle = test_start.handle; + test_stop.condition = SYSC_CFGA_COND_UNKNOWN; + mema_cmd_init(&cmd, &test_stop, outputstr, 0); + dump_ioctl(AC_MEM_TEST_STOP, &test_stop); + ret = ioctl(fd, AC_MEM_TEST_STOP, &cmd); + ret_errno = errno; + dump_ioctl_res(AC_MEM_TEST_STOP, &test_stop, + ret, ret_errno); + /* + * Ignore test stop error processing and re-try the + * start. The error return will be derived from the + * result of start. + */ + (void) memset((void *)&test_start, 0, + sizeof (test_start)); + mema_cmd_init(&cmd, &test_start, outputstr, 0); + dump_ioctl(AC_MEM_TEST_START, &test_start); + ret = ioctl(fd, AC_MEM_TEST_START, &cmd); + ret_errno = errno; + dump_ioctl_res(AC_MEM_TEST_START, &test_start, + ret, ret_errno); + } + /* Test return code again to cover the case of a re-try. */ + if (ret == -1) { + mema_err(&cmd, ret_errno, errstring, + CMD_MEM_TEST_START); + return (CFGA_ERROR); + } + } + (void) memset((void *)&handle, 0, sizeof (handle)); + handle.fd = fd; + handle.drvhandle = (void *)&test_start; + handle.msgp = msgp; + handle.bank_size = test_start.bank_size; + handle.page_size = test_start.page_size; + handle.line_size = test_start.line_size; + handle.lines_per_page = test_start.page_size / test_start.line_size; + handle.condition = CFGA_COND_UNKNOWN; + handle.max_errors = max_errors; + + res = (*mtest_table[test_fun].test_func)(&handle); + + mtest_deallocate_buf_all(&handle); + + /* + * Convert memory test code to MEMA_ code. + */ + switch (res) { + case MTEST_DONE: + res = CFGA_OK; + break; + case MTEST_LIB_ERROR: + __fmt_errstring(errstring, 0, dgettext(TEXT_DOMAIN, + mtest_lib_error)); + res = CFGA_ERROR; + break; + case MTEST_DEV_ERROR: + __fmt_errstring(errstring, 0, dgettext(TEXT_DOMAIN, + mtest_rw_error)); + res = CFGA_ERROR; + break; + default: + __fmt_errstring(errstring, 0, dgettext(TEXT_DOMAIN, + mtest_unknown_error)); + res = CFGA_ERROR; + assert(0); + break; + } + + (void) memset((void *)&test_stop, 0, sizeof (test_stop)); + test_stop.handle = test_start.handle; + switch (handle.condition) { + case CFGA_COND_OK: + test_stop.condition = SYSC_CFGA_COND_OK; + break; + case CFGA_COND_FAILING: + test_stop.condition = SYSC_CFGA_COND_FAILING; + break; + case CFGA_COND_FAILED: + test_stop.condition = SYSC_CFGA_COND_FAILED; + break; + case CFGA_COND_UNKNOWN: + test_stop.condition = SYSC_CFGA_COND_UNKNOWN; + break; + default: + test_stop.condition = SYSC_CFGA_COND_UNKNOWN; + assert(0); + break; + } + + mema_cmd_init(&cmd, &test_stop, outputstr, 0); + dump_ioctl(AC_MEM_TEST_STOP, &test_stop); + ret = ioctl(fd, AC_MEM_TEST_STOP, &cmd); + ret_errno = errno; + dump_ioctl_res(AC_MEM_TEST_STOP, &test_stop, ret, ret_errno); + if (ret == -1) { + mema_err(&cmd, ret_errno, errstring, + CMD_MEM_TEST_STOP); + return (CFGA_ERROR); + } + return (res); +} + +#define DRVHANDLE(H) (((ac_mem_test_start_t *)(H)->drvhandle)->handle) + +int +mtest_write( + mtest_handle_t handle, + void *page_buf, + u_longlong_t page_no, + uint_t line_offset, + uint_t line_count) +{ + ac_mem_test_write_t test_write; + int fd, ret, ret_errno; + ac_cfga_cmd_t cmd; + char outputstr[AC_OUTPUT_LEN]; + + (void) memset((void *)&test_write, 0, sizeof (test_write)); + fd = handle->fd; + test_write.handle = DRVHANDLE(handle); + test_write.page_buf = page_buf; + test_write.address.page_num = page_no; + test_write.address.line_offset = line_offset; + if (line_count == 0) + test_write.address.line_count = handle->lines_per_page; + else + test_write.address.line_count = line_count; + + mema_cmd_init(&cmd, &test_write, outputstr, 0); + dump_ioctl(AC_MEM_TEST_WRITE, &test_write); + ret = ioctl(fd, AC_MEM_TEST_WRITE, &cmd); + ret_errno = errno; + dump_ioctl_res(AC_MEM_TEST_WRITE, &test_write, ret, ret_errno); + + if (ret == -1) + return (-1); + return (0); +} + +int +mtest_read( + mtest_handle_t handle, + void *page_buf, + u_longlong_t page_no, + uint_t line_offset, + uint_t line_count, + struct mtest_error *errp) +{ + ac_mem_test_read_t test_read; + sunfire_processor_error_regs_t errbuf; + int fd, ret, ret_errno; + ac_cfga_cmd_t cmd; + char outputstr[AC_OUTPUT_LEN]; + + (void) memset((void *)&test_read, 0, sizeof (test_read)); + (void) memset((void *)&errbuf, 0, sizeof (errbuf)); + fd = handle->fd; + test_read.handle = DRVHANDLE(handle); + test_read.page_buf = page_buf; + test_read.address.page_num = page_no; + test_read.address.line_offset = line_offset; + test_read.error_buf = &errbuf; + if (line_count == 0) + test_read.address.line_count = handle->lines_per_page; + else + test_read.address.line_count = line_count; + + mema_cmd_init(&cmd, &test_read, outputstr, 0); + dump_ioctl(AC_MEM_TEST_READ, &test_read); + ret = ioctl(fd, AC_MEM_TEST_READ, &cmd); + ret_errno = errno; + dump_ioctl_res(AC_MEM_TEST_READ, &test_read, ret, ret_errno); + + if (ret == -1) { + if (ret_errno == EIO) { + /* + * Special case indicating CE or UE. + */ + if (((errbuf.udbh_error_reg | errbuf.udbl_error_reg) & + P_DER_UE) != 0) + errp->error_type = MTEST_ERR_UE; + else + errp->error_type = MTEST_ERR_CE; + } else { + return (-1); + } + } else { + errp->error_type = MTEST_ERR_NONE; + } + return (0); +} + +static char * +subopt_help_str(char *opts[]) +{ + char *str; + const char *sep; + int len; + int i, n; + static const char help_sep[] = ", "; + static const char help_nil[] = "???"; + + len = 0; + n = 0; + for (i = 0; opts[i] != NULL; i++) { + n++; + len += strlen(opts[i]); + } + if (n == 0) + return (strdup(help_nil)); + len += (n - 1) * strlen(help_sep); + len++; + str = (char *)malloc(len); + if (str == NULL) + return (NULL); + *str = '\0'; + sep = ""; + for (i = 0; opts[i] != NULL; i++) { + (void) strcat(str, sep); + (void) strcat(str, opts[i]); + sep = help_sep; + } + return (str); +} + +/*ARGSUSED*/ +cfga_err_t +cfga_test( + const char *ap_id, + const char *options, + struct cfga_msg *msgp, + char **errstring, + cfga_flags_t flags) +{ + mema_bank_t bk; + ac_stat_t stat; + int test_fun = -1; + int fd, ret; + int maxerr_idx; + long max_errors = -1; + char *ret_p; + + if (errstring != NULL) + *errstring = NULL; + + /* + * Decode test level and max error number. + */ + if (options != NULL && *options != '\0') { + char **opts; + char *value; + char *cp, *free_cp; + int subopt; + + /* getsubopt() modifies the input string, so copy it. */ + cp = strdup(options); + if (cp == NULL) { + return (CFGA_LIB_ERROR); + } + free_cp = cp; + opts = mtest_build_opts(&maxerr_idx); + if (opts == NULL) { + free((void *)free_cp); + return (CFGA_LIB_ERROR); + } + + while (*cp != '\0') { + subopt = getsubopt(&cp, opts, &value); + if (subopt == -1) { + char *hlp; + + hlp = subopt_help_str(opts); + if (hlp != NULL) { + __fmt_errstring(errstring, + strlen(value) + strlen(hlp), + dgettext(TEXT_DOMAIN, unk_test), + value, hlp); + free((void *)hlp); + } else { + __fmt_errstring(errstring, 20, + dgettext(TEXT_DOMAIN, calloc_fail), + strlen(options) + 1, 1); + } + /* Free after printing value. */ + free((void *)free_cp); + return (CFGA_ERROR); + } + + if (test_fun != -1 && subopt != test_fun && + subopt != maxerr_idx) { + __fmt_errstring(errstring, + strlen(opts[subopt]), + dgettext(TEXT_DOMAIN, dup_test), + opts[subopt]); + free((void *)free_cp); + return (CFGA_ERROR); + } + + if (subopt < maxerr_idx) + test_fun = subopt; + else { + + if (max_errors != -1 && subopt == maxerr_idx) { + __fmt_errstring(errstring, + strlen(opts[subopt]), + dgettext(TEXT_DOMAIN, dup_num), + opts[subopt]); + free((void *)free_cp); + return (CFGA_ERROR); + } + + if (value == NULL) { + __fmt_errstring(errstring, + 0, + dgettext(TEXT_DOMAIN, no_num), + ""); + free((void *)free_cp); + return (CFGA_ERROR); + } + + max_errors = strtol(value, &ret_p, 10); + if ((ret_p == value) || (*ret_p != '\0') || + (max_errors < 0)) { + __fmt_errstring(errstring, + strlen(value), + dgettext(TEXT_DOMAIN, no_num), + value); + free((void *)free_cp); + return (CFGA_ERROR); + } + } + } + free((void *)free_cp); + } + + if (test_fun == -1) + test_fun = MTEST_DEFAULT_TEST; + if (max_errors == -1) + max_errors = MAX_ERRORS; + + ret = ap_stat(ap_id, &fd, &bk, &stat, errstring); + if (ret != CFGA_OK) + return (ret); + + if (stat.rstate != SYSC_CFGA_RSTATE_CONNECTED || + stat.ostate != SYSC_CFGA_OSTATE_UNCONFIGURED) { + __fmt_errstring(errstring, 0, + dgettext(TEXT_DOMAIN, trans_illegal)); + (void) close(fd); + return (CFGA_ERROR); + } + + ret = mtest_run(fd, test_fun, &bk, + ((flags & CFGA_FLAG_VERBOSE) != 0) ? msgp : NULL, errstring, + (ulong_t)max_errors); + + (void) close(fd); + + return (ret); +} + +static cfga_stat_t +rstate_cvt(sysc_cfga_rstate_t rs) +{ + cfga_stat_t cs; + + switch (rs) { + case SYSC_CFGA_RSTATE_EMPTY: + cs = CFGA_STAT_EMPTY; + break; + case SYSC_CFGA_RSTATE_DISCONNECTED: + cs = CFGA_STAT_DISCONNECTED; + break; + case SYSC_CFGA_RSTATE_CONNECTED: + cs = CFGA_STAT_CONNECTED; + break; + default: + cs = CFGA_STAT_NONE; + break; + } + + return (cs); +} + +static cfga_stat_t +ostate_cvt(sysc_cfga_ostate_t os) +{ + cfga_stat_t cs; + + switch (os) { + case SYSC_CFGA_OSTATE_UNCONFIGURED: + cs = CFGA_STAT_UNCONFIGURED; + break; + case SYSC_CFGA_OSTATE_CONFIGURED: + cs = CFGA_STAT_CONFIGURED; + break; + default: + cs = CFGA_STAT_NONE; + break; + } + + return (cs); +} + +static cfga_cond_t +cond_cvt(sysc_cfga_cond_t sc) +{ + cfga_cond_t cc; + + switch (sc) { + case SYSC_CFGA_COND_OK: + cc = CFGA_COND_OK; + break; + case SYSC_CFGA_COND_FAILING: + cc = CFGA_COND_FAILING; + break; + case SYSC_CFGA_COND_FAILED: + cc = CFGA_COND_FAILED; + break; + case SYSC_CFGA_COND_UNUSABLE: + cc = CFGA_COND_UNUSABLE; + break; + case SYSC_CFGA_COND_UNKNOWN: + default: + cc = CFGA_COND_UNKNOWN; + break; + } + + return (cc); +} + +static void +info_set(ac_stat_t *asp, mema_bank_t *bkp, cfga_info_t info) +{ + mema_disabled_t disab; + uint_t board; + uint_t n; + u_longlong_t decode; + uint_t intlv; + char *f; + char *end; + + end = &info[sizeof (cfga_info_t)]; + *info = NULL; + + board = bkp->board; + + /* Print the board number in a way that matches the sysctrl AP. */ + info += snprintf(info, end - info, "slot%d", board); + + if (asp->real_size == 0) { + info += snprintf(info, end - info, " empty"); + return; + } + + if ((n = asp->real_size) >= 1024) { + n /= 1024; + f = "Gb"; + } else + f = "Mb"; + info += snprintf(info, end - info, " %d%s", n, f); + + if (asp->rstate == SYSC_CFGA_RSTATE_CONNECTED && + asp->ostate == SYSC_CFGA_OSTATE_CONFIGURED && + asp->use_size != asp->real_size) { + if ((n = asp->use_size) >= 1024) { + n /= 1024; + f = "Gb"; + } else + f = "Mb"; + info += snprintf(info, end - info, " (%d%s used)", n, f); + } + + if (bkp->bank == 0) + decode = asp->ac_decode0; + else + decode = asp->ac_decode1; + + info += snprintf(info, end - info, " base 0x%llx", + GRP_REALBASE(decode)); + + if (bkp->bank == 0) + intlv = INTLV0(asp->ac_memctl); + else + intlv = INTLV1(asp->ac_memctl); + + if (intlv != 1) + info += snprintf(info, end - info, " interleaved %u-way", + intlv); + + if (prom_read_disabled_list(&disab, board)) { + if (disab != 0) { + info += snprintf(info, end - info, " disabled at boot"); + } + + } + + if (asp->rstate == SYSC_CFGA_RSTATE_CONNECTED && + asp->ostate == SYSC_CFGA_OSTATE_CONFIGURED && + asp->nonrelocatable) + info += snprintf(info, end - info, " permanent"); +} + +static void +mema_cvt(ac_stat_t *ac, mema_bank_t *bkp, cfga_stat_data_t *cs) +{ + (void) strcpy(cs->ap_type, "memory"); + cs->ap_r_state = rstate_cvt(ac->rstate); + cs->ap_o_state = ostate_cvt(ac->ostate); + cs->ap_cond = cond_cvt(ac->condition); + cs->ap_busy = (cfga_busy_t)ac->busy; + cs->ap_status_time = ac->status_time; + info_set(ac, bkp, cs->ap_info); + cs->ap_log_id[0] = NULL; + cs->ap_phys_id[0] = NULL; +} + +/*ARGSUSED*/ +cfga_err_t +cfga_stat( + const char *ap_id, + struct cfga_stat_data *cs, + const char *options, + char **errstring) +{ + int ret; + mema_bank_t bk; + ac_stat_t stat; + option_set_t do_option; + + if (errstring != NULL) + *errstring = NULL; + + ret = 0; + do_option = process_options(options, stat_opts, &ret, errstring); + if (ret != 0) + return (ret); + + ret = ap_stat(ap_id, NULL, &bk, &stat, errstring); + if (ret != CFGA_OK) + return (ret); + + mema_cvt(&stat, &bk, cs); + + ret = prom_do_options(do_option, bk.board, &stat, errstring); + + return (ret); +} + +/*ARGSUSED*/ +cfga_err_t +cfga_list( + const char *ap_id, + cfga_stat_data_t **ap_list, + int *nlist, + const char *options, + char **errstring) +{ + if (errstring != NULL) + *errstring = NULL; + + return (CFGA_NOTSUPP); +} + +/* + * cfga_ap_id_cmp -- use default_ap_id_cmp() in libcfgadm + */ + +/*ARGSUSED*/ +cfga_err_t +cfga_help(struct cfga_msg *msgp, const char *options, cfga_flags_t flags) +{ + + + (*msgp->message_routine)(msgp->appdata_ptr, mema_help); + (*msgp->message_routine)(msgp->appdata_ptr, disable_opts); + (*msgp->message_routine)(msgp->appdata_ptr, enable_opts); + (*msgp->message_routine)(msgp->appdata_ptr, timeout_opts); + (*msgp->message_routine)(msgp->appdata_ptr, test_opts); + (*msgp->message_routine)(msgp->appdata_ptr, private_funcs); + + return (CFGA_OK); +} + +#if 0 +static ac_mem_version_t +get_version(int fd) +{ + ac_mem_version_t ver; + int ret, ret_errno; + + ver = 0; + dump_ioctl(AC_MEM_ADMIN_VER, &ver); + ret = ioctl(fd, AC_MEM_ADMIN_VER, &ver); + ret_errno = errno; + dump_ioctl_res(AC_MEM_ADMIN_VER, &ver, ret, ret_errno); + return (ver); +} +#endif + +static char * +opt_help_str(struct opt_control *opts) +{ + char *str; + const char *sep; + int len; + int i, n; + static const char help_sep[] = ", "; + static const char help_nil[] = "???"; + + len = 0; + n = 0; + for (i = 0; opts[i].subopt != -1; i++) { + n++; + len += strlen(mema_opts[opts[i].subopt]); + } + if (n == 0) + return (strdup(help_nil)); + len += (n - 1) * strlen(help_sep); + len++; + str = (char *)malloc(len); + if (str == NULL) + return (NULL); + *str = '\0'; + sep = ""; + for (i = 0; opts[i].subopt != -1; i++) { + (void) strcat(str, sep); + (void) strcat(str, mema_opts[opts[i].subopt]); + sep = help_sep; + } + return (str); +} + +static option_set_t +process_options( + const char *options, + struct opt_control *opts, + int *retp, + char **errstring) +{ + option_set_t opt_set; + char *optcopy, *optcopy_alloc; + char *value; + int subopt; + int subopt_err; + int i; + int group; + int need_value; + + OPTSET_INIT(opt_set); + + if (options == NULL || *options == '\0') { + return (opt_set); + } + + optcopy = optcopy_alloc = strdup(options); + if (optcopy_alloc == NULL) { + __fmt_errstring(errstring, 20, + dgettext(TEXT_DOMAIN, calloc_fail), strlen(options) + 1, 1); + *retp = CFGA_LIB_ERROR; + return (opt_set); + } + + subopt_err = 0; + while (*optcopy != '\0' && subopt_err == 0) { + subopt = getsubopt(&optcopy, mema_opts, &value); + if (subopt == -1) { + char *hlp; + + hlp = opt_help_str(opts); + __fmt_errstring(errstring, strlen(value) + strlen(hlp), + dgettext(TEXT_DOMAIN, unk_subopt), value, hlp); + free((void *)hlp); + subopt_err = 1; + break; + } + for (i = 0; opts[i].subopt != -1; i++) { + if (opts[i].subopt == subopt) { + group = opts[i].group; + break; + } + } + if (opts[i].subopt == -1) { + char *hlp; + + hlp = opt_help_str(opts); + __fmt_errstring(errstring, + MAX_OPT_LENGTH + strlen(hlp), + dgettext(TEXT_DOMAIN, not_valid), + mema_opts[subopt], hlp); + free((void *)hlp); + subopt_err = 1; + break; + } + need_value = OPT_NEEDS_VALUE(subopt); + if (!need_value && value != NULL) { + __fmt_errstring(errstring, MAX_OPT_LENGTH, + dgettext(TEXT_DOMAIN, no_value), + mema_opts[subopt]); + subopt_err = 1; + break; + } + if (need_value && value == NULL) { + __fmt_errstring(errstring, MAX_OPT_LENGTH, + dgettext(TEXT_DOMAIN, missing_value), + mema_opts[subopt]); + subopt_err = 1; + break; + } + if (OPTSET_TEST(opt_set, subopt)) { + /* Ignore repeated options. */ + continue; + } + if (group != 0 && !OPTSET_IS_EMPTY(opt_set)) { + for (i = 0; opts[i].subopt != -1; i++) { + if (i == subopt) + continue; + if (opts[i].group == group && + OPTSET_TEST(opt_set, opts[i].subopt)) + break; + } + if (opts[i].subopt != -1) { + __fmt_errstring(errstring, MAX_OPT_LENGTH * 2, + dgettext(TEXT_DOMAIN, conflict_opt), + mema_opts[subopt], + mema_opts[opts[i].subopt]); + subopt_err = 1; + break; + } + } + OPTSET_SET_VAL(opt_set, subopt, value); + } + free((void *)optcopy_alloc); + if (subopt_err) { + *retp = CFGA_ERROR; + } + + return (opt_set); +} + +#ifdef DEV_DEBUG + +static int +debugging(void) +{ + char *ep; + static int inited; + + if (inited) + return (debug_fp != NULL); + inited = 1; + + if ((ep = getenv("MEMADM_DEBUG")) == NULL) { + return (0); + } + if (*ep == '\0') + debug_fp = stderr; + else { + if ((debug_fp = fopen(ep, "a")) == NULL) + return (0); + } + (void) fprintf(debug_fp, "\nDebug started, pid=%d\n", (int)getpid()); + return (1); +} + +static void +dump_ioctl( + int cmd, + void *arg) +{ + if (!debugging()) + return; + + switch (cmd) { + case AC_MEM_CONFIGURE: + (void) fprintf(debug_fp, "IOCTL: AC_MEM_CONFIGURE\n"); + break; + + case AC_MEM_UNCONFIGURE: + (void) fprintf(debug_fp, "IOCTL: AC_MEM_UNCONFIGURE\n"); + break; + + case AC_MEM_TEST_START: + (void) fprintf(debug_fp, "IOCTL: AC_MEM_TEST_START\n"); + break; + + case AC_MEM_TEST_STOP: { + ac_mem_test_stop_t *tstop; + + tstop = (ac_mem_test_stop_t *)arg; + (void) fprintf(debug_fp, "IOCTL: AC_MEM_TEST_STOP handle=%#x " + "condition=%d\n", tstop->handle, tstop->condition); + } + break; + case AC_MEM_TEST_READ: { + ac_mem_test_read_t *tread; + + tread = (ac_mem_test_read_t *)arg; + (void) fprintf(debug_fp, "IOCTL: AC_MEM_TEST_READ handle=%#x " + "buf=%#p page=%#llx off=%#x count=%#x\n", + tread->handle, tread->page_buf, + tread->address.page_num, + tread->address.line_offset, tread->address.line_count); + } + break; + case AC_MEM_TEST_WRITE: { + ac_mem_test_write_t *twrite; + + twrite = (ac_mem_test_write_t *)arg; + (void) fprintf(debug_fp, "IOCTL: AC_MEM_TEST_WRITE handle=%#x " + "buf=%#p page=%#llx off=%#x count=%#x\n", + twrite->handle, twrite->page_buf, + twrite->address.page_num, + twrite->address.line_offset, twrite->address.line_count); + } + break; + case AC_MEM_ADMIN_VER: + (void) fprintf(debug_fp, "IOCTL: AC_MEM_ADMIN_VER:\n"); + break; + case AC_MEM_STAT: + (void) fprintf(debug_fp, "IOCTL: AC_MEM_STAT\n"); + break; + case AC_MEM_EXERCISE: { + ac_cfga_cmd_t *cmdp; + + cmdp = arg; + (void) fprintf(debug_fp, "IOCTL: AC_MEM_EXERCISE arg=%d\n", + cmdp->arg); + break; + } + default: + (void) fprintf(debug_fp, "IOCTL: unknown (%#x)\n", cmd); + break; + } + (void) fflush(debug_fp); +} + +static void +dump_ioctl_res( + int cmd, + void *arg, + int ret, + int ret_errno) +{ + if (!debugging()) + return; + + if (ret == -1) { + (void) fprintf(debug_fp, "IOCTL failed, \"%s\" (errno=%d)\n", + strerror(ret_errno), ret_errno); + (void) fflush(debug_fp); + return; + } else { + (void) fprintf(debug_fp, "IOCTL succeeded, ret=%d\n", ret); + } + + switch (cmd) { + case AC_MEM_CONFIGURE: + case AC_MEM_UNCONFIGURE: + break; + case AC_MEM_TEST_START: { + ac_mem_test_start_t *tstart; + + tstart = (ac_mem_test_start_t *)arg; + (void) fprintf(debug_fp, " handle=%#x tester_pid=%d " + "prev_condition=%d bank_size=%#llx " + "page_size=%#x line_size=%#x afar_base=%#llx\n", + tstart->handle, (int)tstart->tester_pid, + tstart->prev_condition, + tstart->bank_size, tstart->page_size, + tstart->line_size, tstart->afar_base); + } + break; + case AC_MEM_TEST_STOP: + break; + case AC_MEM_TEST_READ: { + ac_mem_test_read_t *tread; + sunfire_processor_error_regs_t *err; + + tread = (ac_mem_test_read_t *)arg; + err = tread->error_buf; + if (ret_errno == EIO) { + (void) fprintf(debug_fp, "module_id=%#llx afsr=%#llx " + "afar=%#llx udbh_error_reg=%#llx " + "udbl_error_reg=%#llx\n", + (longlong_t)err->module_id, (longlong_t)err->afsr, + (longlong_t)err->afar, + (longlong_t)err->udbh_error_reg, + (longlong_t)err->udbl_error_reg); + } else { + (void) fprintf(debug_fp, "\n"); + } + } + break; + case AC_MEM_TEST_WRITE: + break; + case AC_MEM_ADMIN_VER: { + ac_mem_version_t *ver; + + ver = (ac_mem_version_t *)arg; + (void) fprintf(debug_fp, " version %d\n", *ver); + } + break; + case AC_MEM_STAT: { + ac_stat_t *tstat; + + tstat = (ac_stat_t *)arg; + (void) fprintf(debug_fp, " rstate=%u ostate=%u " + "condition=%u status_time=%#lx board=%u\n", + (uint_t)tstat->rstate, (uint_t)tstat->ostate, + (uint_t)tstat->condition, (ulong_t)tstat->status_time, + tstat->board); + (void) fprintf(debug_fp, " real_size=%u use_size=%u " + "busy=%u\n", + tstat->real_size, tstat->use_size, tstat->busy); + (void) fprintf(debug_fp, " page_size=%#x " + "phys_pages=%#llx managed=%#llx nonrelocatable=%#llx\n", + tstat->page_size, (longlong_t)tstat->phys_pages, + (longlong_t)tstat->managed, + (longlong_t)tstat->nonrelocatable); + (void) fprintf(debug_fp, " memctl=%#llx " + "decode0=%#llx decode1=%#llx\n", + (longlong_t)tstat->ac_memctl, (longlong_t)tstat->ac_decode0, + (longlong_t)tstat->ac_decode1); + } + break; + case AC_MEM_EXERCISE: { + ac_cfga_cmd_t *cmdp; + + cmdp = arg; + switch (cmdp->arg) { + case AC_MEMX_RELOCATE_ALL: { + struct ac_memx_relocate_stats *stp; + + if ((stp = cmdp->private) != NULL) { + (void) fprintf(debug_fp, " base=%u npgs=%u" + " nopaget=%u nolock=%u isfree=%u reloc=%u" + " noreloc=%u\n", + stp->base, stp->npgs, stp->nopaget, + stp->nolock, stp->isfree, stp->reloc, + stp->noreloc); + } + break; + } + default: + break; + } + break; + } + default: + break; + } + (void) fflush(debug_fp); +} +#endif /* DEV_DEBUG */ diff --git a/usr/src/lib/cfgadm_plugins/ac/common/mema_prom.c b/usr/src/lib/cfgadm_plugins/ac/common/mema_prom.c new file mode 100644 index 0000000000..6f44fbd37b --- /dev/null +++ b/usr/src/lib/cfgadm_plugins/ac/common/mema_prom.c @@ -0,0 +1,270 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1996-1998 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stddef.h> +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <assert.h> +#include <sys/param.h> +#include <sys/obpdefs.h> +#include <sys/fhc.h> +#include <sys/ac.h> +#include <sys/sysctrl.h> +#include <sys/openpromio.h> +#include "mema_prom.h" +#include <config_admin.h> + + +/* + * PROM access routines to get and set disabled lists + * Based on code in the usr/src/cmd/eeprom directory. + */ +#define PROMDEV "/dev/openprom" +/* + * 128 is the size of the largest (currently) property name + * 8192 - MAXPROPSIZE - sizeof (int) is the size of the largest + * (currently) property value, viz. nvramrc. + * the sizeof(u_int) is from struct openpromio + */ + +#define MAXPROPSIZE 128 +#define MAXNAMESIZE MAXPROPSIZE +#define MAXVALSIZE (8192 - MAXPROPSIZE - sizeof (u_int)) +#define BUFSIZE (MAXPROPSIZE + MAXVALSIZE + sizeof (u_int)) +typedef union { + char buf[BUFSIZE]; + struct openpromio opp; +} Oppbuf; +#define PROP_MEMORY_LIST "disabled-memory-list" + +static int prom_read_one(mema_disabled_t *, int, int, char *, u_int); +static int prom_write_one(mema_disabled_t *, int, int, char *, u_int); + +int +prom_read_disabled_list(mema_disabled_t *dp, int bd) +{ + int prom_fd; + int ret; + + (void) memset((void *)dp, 0, sizeof (*dp)); + prom_fd = open(PROMDEV, O_RDONLY); + if (prom_fd == -1) { + return (0); + } + ret = prom_read_one(dp, bd, prom_fd, + PROP_MEMORY_LIST, PROM_MEMORY_DISABLED); + (void) close(prom_fd); + return (ret); +} + +int +prom_write_disabled_list(mema_disabled_t *dp, int bd) +{ + int prom_fd; + int ret; + + prom_fd = open(PROMDEV, O_RDWR); + if (prom_fd == -1) { + return (0); + } + ret = prom_write_one(dp, bd, prom_fd, + PROP_MEMORY_LIST, PROM_MEMORY_DISABLED); + (void) close(prom_fd); + return (ret); +} + +static int +prom_read_one( + mema_disabled_t *dp, + int bd, + int prom_fd, + char *var, + u_int bit) +{ + Oppbuf oppbuf; + struct openpromio *opp = &oppbuf.opp; + int ret; + + (void) memset((void *)&oppbuf, 0, sizeof (oppbuf)); + (void) strncpy(opp->oprom_array, var, MAXNAMESIZE); + opp->oprom_size = MAXVALSIZE; + if (ioctl(prom_fd, OPROMGETOPT, opp) == -1) { + ret = 0; + } else + if (opp->oprom_size == 0) { + /* Not a failure - just not set to anything */ + ret = 1; + } else { + char *cp; + int board; + + ret = 1; + for (cp = opp->oprom_array; *cp != '\0'; cp++) { + switch (*cp) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + board = *cp - '0'; + break; + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + board = *cp - 'a' + 10; + break; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + board = *cp - 'A' + 10; + break; + default: + /* Ignore bad characters. */ + /* TODO: maybe should set ret to 0? */ + board = -1; + break; + } + if (board == bd) + *dp |= bit; + } + } + return (ret); +} + +static int +prom_write_one( + mema_disabled_t *dp, + int bd, + int prom_fd, + char *var, + u_int bit) +{ + Oppbuf in_oppbuf; + struct openpromio *in_opp = &in_oppbuf.opp; + Oppbuf oppbuf; + struct openpromio *opp = &oppbuf.opp; + int ret; + char *cp; + + /* Setup output buffer. */ + (void) memset((void *)&oppbuf, 0, sizeof (oppbuf)); + (void) strncpy(opp->oprom_array, var, MAXNAMESIZE); + opp->oprom_size = strlen(var) + 1; + cp = opp->oprom_array + opp->oprom_size; + + /* + * First read the existing list, filtering out 'bd' if 'bit' + * not set. + */ + (void) memset((void *)&in_oppbuf, 0, sizeof (in_oppbuf)); + (void) strncpy(in_opp->oprom_array, var, MAXNAMESIZE); + in_opp->oprom_size = MAXVALSIZE; + if (ioctl(prom_fd, OPROMGETOPT, in_opp) != -1 && + in_opp->oprom_size != 0) { + char *icp; + int board; + + for (icp = in_opp->oprom_array; *icp != '\0'; icp++) { + switch (*icp) { + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + case '8': case '9': + board = *icp - '0'; + break; + case 'a': case 'b': case 'c': + case 'd': case 'e': case 'f': + board = *icp - 'a' + 10; + break; + case 'A': case 'B': case 'C': + case 'D': case 'E': case 'F': + board = *icp - 'A' + 10; + break; + default: + /* Ignore bad characters. */ + continue; + } + /* If enabling this board ... */ + if (board == bd && (*dp & bit) == 0) + continue; + *cp++ = "0123456789abcdef"[board]; + opp->oprom_size++; + } + } + + if ((*dp & bit) != 0) { + *cp++ = "0123456789abcdef"[bd]; + opp->oprom_size++; + } + if (ioctl(prom_fd, OPROMSETOPT, opp) == -1) { + ret = 0; + } else { + ret = 1; + } + + return (ret); +} + +/* + * The PROM only has board-level disable of memory. If two banks are present + * on the board, both are either enabled or disabled at boot. + * The caller of this routine must set the PROM_MEMORY_PRESENT bits + * before calling this function. + */ + +/*ARGSUSED*/ +int +prom_viable_disabled_list(mema_disabled_t *dp) +{ +#ifdef XXX + int board; + + for (board = 0; board < MAX_BOARDS; board++) { + if ((dp->bank_A[board] & PROM_MEMORY_PRESENT) != 0 && + (dp->bank_B[board] & PROM_MEMORY_PRESENT) != 0 && + (dp->bank_A[board] & PROM_MEMORY_DISABLED) != + (dp->bank_B[board] & PROM_MEMORY_DISABLED)) { + return (0); + } + } +#endif + return (1); +} diff --git a/usr/src/lib/cfgadm_plugins/ac/common/mema_prom.h b/usr/src/lib/cfgadm_plugins/ac/common/mema_prom.h new file mode 100644 index 0000000000..445620be3e --- /dev/null +++ b/usr/src/lib/cfgadm_plugins/ac/common/mema_prom.h @@ -0,0 +1,49 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1996-1998 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#ifndef _MEMA_SF_PROM_H +#define _MEMA_SF_PROM_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned char mema_disabled_t; + +extern int prom_read_disabled_list(mema_disabled_t *, int); +extern int prom_write_disabled_list(mema_disabled_t *, int); +extern int prom_viable_disabled_list(mema_disabled_t *); + +#define PROM_MEMORY_DISABLED 0x02 +#define PROM_MEMORY_PRESENT 0x04 /* for viable check */ + +#ifdef __cplusplus +} +#endif + +#endif /* _MEMA_SF_PROM_H */ diff --git a/usr/src/lib/cfgadm_plugins/ac/common/mema_test.c b/usr/src/lib/cfgadm_plugins/ac/common/mema_test.c new file mode 100644 index 0000000000..ff2c78f287 --- /dev/null +++ b/usr/src/lib/cfgadm_plugins/ac/common/mema_test.c @@ -0,0 +1,723 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1996-1998, 2001 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stddef.h> +#include <stdio.h> +#include <sys/param.h> +#include <config_admin.h> +#include <memory.h> +#include <sys/types.h> +#include <time.h> +#include "mema_test.h" + +typedef u_longlong_t pbuf_t; + +/* + * Test for stuck-at fault and transitional faults + * Algorithm: + * for i = 0 to npages + * write(0x55) + * for npages to 0 + * read_compare(0x55) + * write(0xaa) + * for 0 to number of pages + * read_compare(0xaa) + * write(0x55) + * read_compare(0x55) + * + * stuck-at fault is detected because each cell have a 1 and a 0 is read + * transitional fault is detected because after each 0 to 1 and 1 to 0 + * transition the value is check to be sure that the cell is not frozen. + */ + +/* + * The following strings are subject of stderr output and + * gettext() is not used for them. + */ +static const char err_sum[] = "total error %u\n"; +static const char nts_msg[] = "Normal test started\n"; +static const char ntf_msg[] = "Normal test finished\n"; +static const char qts_msg[] = "Quick test started\n"; +static const char qtf_msg[] = "Quick test finished\n"; +static const char ets_msg[] = "Extended test started\n"; +static const char etf_msg[] = "Extended test finished\n"; +static const char m1_msg[] = " March 1, "; +static const char m2_msg[] = " March 2, "; +static const char m3_msg[] = " March 3, "; +static const char m4_msg[] = " March 4, "; +static const char wr_msg[] = "write. "; +static const char rd_cmp_msg[] = "read/compare. "; +static const char rpt_rd_cmp_msg[] = "repeated read/compare. "; +static const char ml_rd_cmp_msg[] = "mixed line read/compare. "; +static const char ln_rd_cmp_msg[] = "line read/compare. "; +static const char report_msg[] = "%s%s%d%% complete.\n"; +static const char pg_header_msg[] = " Errors at page address: 0x%x.\n"; +static const char rd_err_msg[] = " Error reading page at address: 0x%x.\n"; +static const char wr_err_msg[] = " Error writing page at address: 0x%x.\n"; +static const +char mem_err_msg[] = " Offset: 0x%x, data written/read: 0x%2x/0x%2x.\n"; + +/* + * Macros do deal with test conditions. + */ +#define TEST_END(END_MSG) \ + if ((handle->max_errors != 0) &&\ + (handle->max_errors == total_errors)) {\ + mtest_message(handle, (END_MSG));\ + error_summary(handle, total_errors);\ + SET_CONDITION(handle, cond);\ + return (MTEST_DONE);\ + } + +static void +error_summary(mtest_handle_t handle, uint_t total_errors) +{ + char msgbuf[100]; + + (void) sprintf(msgbuf, err_sum, total_errors); + mtest_message(handle, msgbuf); +} + + +static void +error_print(char *writebuf, char *readbuf, mtest_handle_t handle, long pageno, + uint_t *total_errorsp) +{ + char msgbuf[100]; + size_t offset; + + (void) sprintf(msgbuf, pg_header_msg, PAGE_SIZE(handle) * pageno); + mtest_message(handle, msgbuf); + + for (offset = 0; offset < PAGE_SIZE(handle); offset++) { + if ((handle->max_errors != 0) && + (readbuf[offset] != writebuf[offset]) && + (handle->max_errors == *total_errorsp)) + return; + else { + (*total_errorsp)++; + (void) sprintf(msgbuf, mem_err_msg, offset, + writebuf[offset], readbuf[offset]); + mtest_message(handle, msgbuf); + } + } +} + +int +memory_test_normal( + mtest_handle_t handle) +{ + pbuf_t *patternbuf1; + pbuf_t *patternbuf2; + pbuf_t *readbuf; + long npages, pageno; + struct mtest_error errbuf; + uint_t total_errors; + cfga_cond_t cond; + time_t time_rep; + char msgbuf[100]; + + patternbuf1 = (pbuf_t *)mtest_allocate_page_buf(handle); + patternbuf2 = (pbuf_t *)mtest_allocate_page_buf(handle); + readbuf = (pbuf_t *)mtest_allocate_page_buf(handle); + if (patternbuf1 == NULL || patternbuf2 == NULL || readbuf == NULL) { + return (MTEST_LIB_ERROR); + } + + mtest_message(handle, nts_msg); + npages = BANK_SIZE(handle) / PAGE_SIZE(handle); + + total_errors = 0; + cond = CFGA_COND_OK; + + (void) memset((void *)patternbuf1, 0x55, PAGE_SIZE(handle)); + (void) memset((void *)patternbuf2, 0xaa, PAGE_SIZE(handle)); + + time_rep = time(NULL) + REPORT_SEC; + + for (pageno = 0; pageno < npages; pageno++) { + if (mtest_write(handle, (void *)patternbuf1, pageno, 0, 0) + == -1) { + (void) sprintf(msgbuf, wr_err_msg, pageno); + mtest_message(handle, msgbuf); + return (MTEST_DEV_ERROR); + } + if ((time(NULL) >= time_rep) || (pageno == npages - 1) || + (pageno == 0)) { + (void) sprintf(msgbuf, report_msg, m1_msg, wr_msg, + ((pageno + 1) * 100) / npages); + mtest_message(handle, msgbuf); + time_rep = time(NULL) + REPORT_SEC; + } + } + for (pageno = npages-1; pageno >= 0; pageno--) { + if (mtest_read(handle, (void *)readbuf, pageno, 0, 0, &errbuf) + == -1) { + (void) sprintf(msgbuf, rd_err_msg, pageno); + mtest_message(handle, msgbuf); + return (MTEST_DEV_ERROR); + } + if (errbuf.error_type != MTEST_ERR_NONE) { + if (errbuf.error_type == MTEST_ERR_CE && + cond != CFGA_COND_FAILED) + cond = CFGA_COND_FAILING; + else + cond = CFGA_COND_FAILED; + total_errors++; + /* + * Keep going if max errors is 0 or limit not + * reached. + */ + TEST_END(ntf_msg); + } + if (memcmp((void *)patternbuf1, (void *)readbuf, + PAGE_SIZE(handle)) != 0) { + cond = CFGA_COND_FAILED; + error_print((void *)patternbuf1, (void *)readbuf, + handle, pageno, &total_errors); + TEST_END(ntf_msg); + } + if (mtest_write(handle, (void *)patternbuf2, pageno, 0, 0) + == -1) { + (void) sprintf(msgbuf, wr_err_msg, pageno); + mtest_message(handle, msgbuf); + return (MTEST_DEV_ERROR); + } + if ((time(NULL) >= time_rep) || (pageno == npages - 1) || + (pageno == 0)) { + (void) sprintf(msgbuf, report_msg, m1_msg, rd_cmp_msg, + ((npages - pageno) * 100) / npages); + mtest_message(handle, msgbuf); + time_rep = time(NULL) + REPORT_SEC; + } + } + /* March 2 (repeated) */ + for (pageno = 0; pageno < npages; pageno++) { + if (mtest_read(handle, (void *)readbuf, pageno, 0, 0, &errbuf) + == -1) { + (void) sprintf(msgbuf, rd_err_msg, pageno); + mtest_message(handle, msgbuf); + return (MTEST_DEV_ERROR); + } + if (errbuf.error_type != MTEST_ERR_NONE) { + if (errbuf.error_type == MTEST_ERR_CE && + cond != CFGA_COND_FAILED) + cond = CFGA_COND_FAILING; + else + cond = CFGA_COND_FAILED; + total_errors++; + TEST_END(ntf_msg); + } + if (memcmp((void *)patternbuf2, (void *)readbuf, + PAGE_SIZE(handle)) != 0) { + cond = CFGA_COND_FAILED; + error_print((void *)patternbuf2, (void *)readbuf, + handle, pageno, &total_errors); + TEST_END(ntf_msg); + } + if (mtest_write(handle, (void *)patternbuf1, pageno, 0, 0) + == -1) { + (void) sprintf(msgbuf, wr_err_msg, pageno); + mtest_message(handle, msgbuf); + return (MTEST_DEV_ERROR); + } + if (mtest_read(handle, (void *)readbuf, pageno, 0, 0, &errbuf) + == -1) { + (void) sprintf(msgbuf, rd_err_msg, pageno); + mtest_message(handle, msgbuf); + return (MTEST_DEV_ERROR); + } + if (errbuf.error_type != MTEST_ERR_NONE) { + if (errbuf.error_type == MTEST_ERR_CE && + cond != CFGA_COND_FAILED) + cond = CFGA_COND_FAILING; + else + cond = CFGA_COND_FAILED; + total_errors++; + TEST_END(ntf_msg); + } + if (memcmp((void *)patternbuf1, (void *)readbuf, + PAGE_SIZE(handle)) != 0) { + cond = CFGA_COND_FAILED; + error_print((void *)patternbuf1, (void *)readbuf, + handle, pageno, &total_errors); + TEST_END(ntf_msg); + } + if ((time(NULL) >= time_rep) || (pageno == npages - 1) || + (pageno == 0)) { + (void) sprintf(msgbuf, report_msg, m2_msg, + rpt_rd_cmp_msg, ((pageno + 1) * 100) / npages); + mtest_message(handle, msgbuf); + time_rep = time(NULL) + REPORT_SEC; + } + } + mtest_message(handle, ntf_msg); + error_summary(handle, total_errors); + SET_CONDITION(handle, cond); + return (MTEST_DONE); +} + +/* this test look only for stuck-at fault */ +int +memory_test_quick( + mtest_handle_t handle) +{ + pbuf_t *patternbuf1; + pbuf_t *patternbuf2; + pbuf_t *readbuf; + long npages, pageno; + struct mtest_error errbuf; + uint_t total_errors; + cfga_cond_t cond; + time_t time_rep; + char msgbuf[100]; + + patternbuf1 = (pbuf_t *)mtest_allocate_page_buf(handle); + patternbuf2 = (pbuf_t *)mtest_allocate_page_buf(handle); + readbuf = (pbuf_t *)mtest_allocate_page_buf(handle); + if (patternbuf1 == NULL || patternbuf2 == NULL || readbuf == NULL) { + return (MTEST_LIB_ERROR); + } + + mtest_message(handle, qts_msg); + npages = BANK_SIZE(handle) / PAGE_SIZE(handle); + + total_errors = 0; + cond = CFGA_COND_OK; + + (void) memset((void *)patternbuf1, 0x55, PAGE_SIZE(handle)); + (void) memset((void *)patternbuf2, 0xaa, PAGE_SIZE(handle)); + + time_rep = time(NULL) + REPORT_SEC; + + for (pageno = 0; pageno < npages; pageno++) { + if (mtest_write(handle, (void *)patternbuf1, pageno, 0, 0) + == -1) { + (void) sprintf(msgbuf, wr_err_msg, pageno); + mtest_message(handle, msgbuf); + return (MTEST_DEV_ERROR); + } + if ((time(NULL) >= time_rep) || (pageno == npages - 1) || + (pageno == 0)) { + (void) sprintf(msgbuf, report_msg, m1_msg, wr_msg, + ((pageno + 1) * 100) / npages); + mtest_message(handle, msgbuf); + time_rep = time(NULL) + REPORT_SEC; + } + } + + for (pageno = npages-1; pageno >= 0; pageno--) { + if (mtest_read(handle, (void *)readbuf, pageno, 0, 0, &errbuf) + == -1) { + (void) sprintf(msgbuf, rd_err_msg, pageno); + mtest_message(handle, msgbuf); + return (MTEST_DEV_ERROR); + } + if (errbuf.error_type != MTEST_ERR_NONE) { + if (errbuf.error_type == MTEST_ERR_CE && + cond != CFGA_COND_FAILED) + cond = CFGA_COND_FAILING; + else + cond = CFGA_COND_FAILED; + total_errors++; + /* + * Keep going if max errors is 0 or limit not + * reached. + */ + TEST_END(qtf_msg); + } + if (memcmp((void *)patternbuf1, (void *)readbuf, + PAGE_SIZE(handle)) != 0) { + cond = CFGA_COND_FAILED; + error_print((void *)patternbuf1, (void *)readbuf, + handle, pageno, &total_errors); + TEST_END(qtf_msg); + } + if (mtest_write(handle, (void *)patternbuf2, pageno, 0, 0) + == -1) { + (void) sprintf(msgbuf, wr_err_msg, pageno); + mtest_message(handle, msgbuf); + return (MTEST_DEV_ERROR); + } + if ((time(NULL) >= time_rep) || (pageno == npages - 1) || + (pageno == 0)) { + (void) sprintf(msgbuf, report_msg, m1_msg, rd_cmp_msg, + ((npages - pageno) * 100) / npages); + mtest_message(handle, msgbuf); + time_rep = time(NULL) + REPORT_SEC; + } + } + /* March 2 */ + for (pageno = 0; pageno < npages; pageno++) { + if (mtest_read(handle, (void *)readbuf, pageno, 0, 0, &errbuf) + == -1) { + (void) sprintf(msgbuf, rd_err_msg, pageno); + mtest_message(handle, msgbuf); + return (MTEST_DEV_ERROR); + } + if (errbuf.error_type != MTEST_ERR_NONE) { + if (errbuf.error_type == MTEST_ERR_CE && + cond != CFGA_COND_FAILED) + cond = CFGA_COND_FAILING; + else + cond = CFGA_COND_FAILED; + total_errors++; + TEST_END(qtf_msg); + } + if (memcmp((void *)patternbuf2, (void *)readbuf, + PAGE_SIZE(handle)) != 0) { + cond = CFGA_COND_FAILED; + error_print((void *)patternbuf2, (void *)readbuf, + handle, pageno, &total_errors); + TEST_END(qtf_msg); + } + if ((time(NULL) >= time_rep) || (pageno == npages - 1) || + (pageno == 0)) { + (void) sprintf(msgbuf, report_msg, m2_msg, rd_cmp_msg, + ((pageno + 1) * 100) / npages); + mtest_message(handle, msgbuf); + time_rep = time(NULL) + REPORT_SEC; + } + } + mtest_message(handle, qtf_msg); + error_summary(handle, total_errors); + SET_CONDITION(handle, cond); + return (MTEST_DONE); +} + + +/* look for stuck-at, transition, coupling fault: inversion, idempotent */ +int +memory_test_extended( + mtest_handle_t handle) +{ + pbuf_t *patternbuf0, *patternbuf1; + pbuf_t *readbuf0, *readbuf1, *readbuf2; + long npages, pageno; + long line; + struct mtest_error errbuf; + uint_t total_errors; + cfga_cond_t cond; + time_t time_rep; + char msgbuf[100]; + + patternbuf0 = (pbuf_t *)mtest_allocate_page_buf(handle); + patternbuf1 = (pbuf_t *)mtest_allocate_page_buf(handle); + readbuf0 = (pbuf_t *)mtest_allocate_page_buf(handle); + readbuf1 = (pbuf_t *)mtest_allocate_page_buf(handle); + readbuf2 = (pbuf_t *)mtest_allocate_page_buf(handle); + if (patternbuf0 == NULL || patternbuf1 == NULL || + readbuf0 == NULL || readbuf1 == NULL || readbuf2 == NULL) { + return (MTEST_LIB_ERROR); + } + + mtest_message(handle, ets_msg); + npages = BANK_SIZE(handle) / PAGE_SIZE(handle); + + total_errors = 0; + cond = CFGA_COND_OK; + + (void) memset((void *)patternbuf0, 0x55, PAGE_SIZE(handle)); + (void) memset((void *)patternbuf1, 0xaa, PAGE_SIZE(handle)); + + time_rep = time(NULL) + REPORT_SEC; + + for (pageno = 0; pageno < npages; pageno++) { + if (mtest_write(handle, (void *)patternbuf0, pageno, 0, 0) + == -1) { + (void) sprintf(msgbuf, wr_err_msg, pageno); + mtest_message(handle, msgbuf); + return (MTEST_DEV_ERROR); + } + if ((time(NULL) >= time_rep) || (pageno == npages - 1) || + (pageno == 0)) { + (void) sprintf(msgbuf, report_msg, m1_msg, wr_msg, + ((pageno + 1) * 100) / npages); + mtest_message(handle, msgbuf); + time_rep = time(NULL) + REPORT_SEC; + } + } + + /* + * Line tests take 5-9 time longer and the reprting interval + * should be extended 3-5 times. + */ + + /* March 1 */ + for (pageno = npages-1; pageno >= 0; pageno--) { + for (line = (LINES_PER_PAGE(handle) - 1); line >= 0; line--) { + if (mtest_read(handle, (void *)readbuf0, pageno, + line, 1, &errbuf) == -1) { + (void) sprintf(msgbuf, rd_err_msg, pageno); + mtest_message(handle, msgbuf); + return (MTEST_DEV_ERROR); + } + if (errbuf.error_type != MTEST_ERR_NONE) { + if (errbuf.error_type == MTEST_ERR_CE && + cond != CFGA_COND_FAILED) + cond = CFGA_COND_FAILING; + else + cond = CFGA_COND_FAILED; + total_errors++; + /* + * Keep going if max errors is 0 or limit not + * reached. + */ + TEST_END(ntf_msg); + } + if (mtest_write(handle, (void*)patternbuf1, pageno, + line, 1) == -1) { + (void) sprintf(msgbuf, wr_err_msg, pageno); + mtest_message(handle, msgbuf); + return (MTEST_DEV_ERROR); + } + if (mtest_read(handle, (void *)readbuf1, pageno, + line, 1, &errbuf) == -1) { + (void) sprintf(msgbuf, rd_err_msg, pageno); + mtest_message(handle, msgbuf); + return (MTEST_DEV_ERROR); + } + if (errbuf.error_type != MTEST_ERR_NONE) { + if (errbuf.error_type == MTEST_ERR_CE && + cond != CFGA_COND_FAILED) + cond = CFGA_COND_FAILING; + else + cond = CFGA_COND_FAILED; + total_errors++; + TEST_END(ntf_msg); + } + if (mtest_write(handle, (void*)patternbuf0, pageno, + line, 1) == -1) { + (void) sprintf(msgbuf, wr_err_msg, pageno); + mtest_message(handle, msgbuf); + return (MTEST_DEV_ERROR); + } + if (mtest_read(handle, (void *)readbuf2, pageno, + line, 1, &errbuf) == -1) { + (void) sprintf(msgbuf, rd_err_msg, pageno); + mtest_message(handle, msgbuf); + return (MTEST_DEV_ERROR); + } + if (errbuf.error_type != MTEST_ERR_NONE) { + if (errbuf.error_type == MTEST_ERR_CE && + cond != CFGA_COND_FAILED) + cond = CFGA_COND_FAILING; + else + cond = CFGA_COND_FAILED; + total_errors++; + TEST_END(ntf_msg); + } + if (mtest_write(handle, (void*)patternbuf1, pageno, + line, 1) == -1) { + (void) sprintf(msgbuf, wr_err_msg, pageno); + return (MTEST_DEV_ERROR); + } + } /* line */ + if (memcmp((void *)patternbuf0, (void *)readbuf0, + PAGE_SIZE(handle)) != 0) { + cond = CFGA_COND_FAILED; + error_print((void *)patternbuf0, (void *)readbuf0, + handle, pageno, &total_errors); + TEST_END(ntf_msg); + } + if (memcmp((void *)patternbuf1, (void *)readbuf1, + PAGE_SIZE(handle)) != 0) { + cond = CFGA_COND_FAILED; + error_print((void *)patternbuf1, (void *)readbuf1, + handle, pageno, &total_errors); + TEST_END(ntf_msg); + } + if (memcmp((void *)patternbuf0, (void *)readbuf2, + PAGE_SIZE(handle)) != 0) { + cond = CFGA_COND_FAILED; + error_print((void *)patternbuf0, (void *)readbuf2, + handle, pageno, &total_errors); + TEST_END(ntf_msg); + } + if ((time(NULL) >= time_rep) || (pageno == npages - 1) || + (pageno == 0)) { + (void) sprintf(msgbuf, report_msg, m1_msg, + ml_rd_cmp_msg, ((npages - pageno) * 100) / npages); + mtest_message(handle, msgbuf); + time_rep = time(NULL) + REPORT_SEC * 3; + } + } /* page */ + + /* March 2 */ + for (pageno = npages-1; pageno >= 0; pageno--) { + for (line = (LINES_PER_PAGE(handle) - 1); line >= 0; line--) { + if (mtest_read(handle, (void *)readbuf0, pageno, + line, 1, &errbuf) == -1) { + (void) sprintf(msgbuf, rd_err_msg, pageno); + mtest_message(handle, msgbuf); + return (MTEST_DEV_ERROR); + } + if (errbuf.error_type != MTEST_ERR_NONE) { + if (errbuf.error_type == MTEST_ERR_CE && + cond != CFGA_COND_FAILED) + cond = CFGA_COND_FAILING; + else + cond = CFGA_COND_FAILED; + total_errors++; + /* + * Keep going if max errors is 0 or limit not + * reached. + */ + TEST_END(ntf_msg); + } + if (mtest_write(handle, (void*)patternbuf0, pageno, + line, 1) == -1) { + (void) sprintf(msgbuf, wr_err_msg, pageno); + mtest_message(handle, msgbuf); + return (MTEST_DEV_ERROR); + } + if (mtest_write(handle, (void*)patternbuf1, pageno, + line, 1) == -1) { + (void) sprintf(msgbuf, wr_err_msg, pageno); + mtest_message(handle, msgbuf); + return (MTEST_DEV_ERROR); + } + } + if (memcmp((void *)patternbuf1, (void *)readbuf0, + PAGE_SIZE(handle)) != 0) { + cond = CFGA_COND_FAILED; + total_errors++; + } + if ((time(NULL) >= time_rep) || (pageno == npages - 1) || + (pageno == 0)) { + (void) sprintf(msgbuf, report_msg, m2_msg, + ln_rd_cmp_msg, ((npages - pageno) * 100) / npages); + mtest_message(handle, msgbuf); + time_rep = time(NULL) + REPORT_SEC * 3; + } + } /* page */ + + /* March 3 */ + for (pageno = 0; pageno < npages; pageno++) { + for (line = 0; line < LINES_PER_PAGE(handle); line++) { + if (mtest_read(handle, (void *)readbuf0, pageno, + line, 1, &errbuf) == -1) { + (void) sprintf(msgbuf, rd_err_msg, pageno); + mtest_message(handle, msgbuf); + return (MTEST_DEV_ERROR); + } + if (errbuf.error_type != MTEST_ERR_NONE) { + if (errbuf.error_type == MTEST_ERR_CE && + cond != CFGA_COND_FAILED) + cond = CFGA_COND_FAILING; + else + cond = CFGA_COND_FAILED; + total_errors++; + TEST_END(ntf_msg); + } + if (mtest_write(handle, (void*)patternbuf0, pageno, + line, 1) == -1) { + (void) sprintf(msgbuf, wr_err_msg, pageno); + mtest_message(handle, msgbuf); + return (MTEST_DEV_ERROR); + } + if (mtest_write(handle, (void*)patternbuf1, pageno, + line, 1) == -1) { + (void) sprintf(msgbuf, wr_err_msg, pageno); + mtest_message(handle, msgbuf); + return (MTEST_DEV_ERROR); + } + if (mtest_write(handle, (void*)patternbuf0, pageno, + line, 1) == -1) { + (void) sprintf(msgbuf, wr_err_msg, pageno); + mtest_message(handle, msgbuf); + return (MTEST_DEV_ERROR); + } + } + if (memcmp((void *)patternbuf1, (void *)readbuf0, + PAGE_SIZE(handle)) != 0) { + cond = CFGA_COND_FAILED; + error_print((void *)patternbuf1, (void *)readbuf0, + handle, pageno, &total_errors); + TEST_END(ntf_msg); + } + if ((time(NULL) >= time_rep) || (pageno == npages - 1) || + (pageno == 0)) { + (void) sprintf(msgbuf, report_msg, m3_msg, + ml_rd_cmp_msg, ((pageno + 1) * 100) / npages); + mtest_message(handle, msgbuf); + time_rep = time(NULL) + REPORT_SEC * 3; + } + } /* page */ + + /* March 4 */ + for (pageno = 0; pageno < npages; pageno++) { + for (line = 0; line < LINES_PER_PAGE(handle); line++) { + if (mtest_read(handle, (void *)readbuf0, pageno, + line, 1, &errbuf) == -1) { + (void) sprintf(msgbuf, rd_err_msg, pageno); + mtest_message(handle, msgbuf); + return (MTEST_DEV_ERROR); + } + if (errbuf.error_type != MTEST_ERR_NONE) { + if (errbuf.error_type == MTEST_ERR_CE && + cond != CFGA_COND_FAILED) + cond = CFGA_COND_FAILING; + else + cond = CFGA_COND_FAILED; + total_errors++; + TEST_END(ntf_msg); + } + if (mtest_write(handle, (void*)patternbuf1, pageno, + line, 1) == -1) { + (void) sprintf(msgbuf, wr_err_msg, pageno); + mtest_message(handle, msgbuf); + return (MTEST_DEV_ERROR); + } + if (mtest_write(handle, (void*)patternbuf0, pageno, + line, 1) == -1) { + (void) sprintf(msgbuf, wr_err_msg, pageno); + mtest_message(handle, msgbuf); + return (MTEST_DEV_ERROR); + } + } + if (memcmp((void *)patternbuf0, (void *)readbuf0, + PAGE_SIZE(handle)) != 0) { + cond = CFGA_COND_FAILED; + error_print((void *)patternbuf0, (void *)readbuf0, + handle, pageno, &total_errors); + TEST_END(ntf_msg); + } + if ((time(NULL) >= time_rep) || (pageno == npages - 1) || + (pageno == 0)) { + (void) sprintf(msgbuf, report_msg, m4_msg, + ln_rd_cmp_msg, ((pageno + 1) * 100) / npages); + mtest_message(handle, msgbuf); + time_rep = time(NULL) + REPORT_SEC * 3; + } + } /* page */ + mtest_message(handle, etf_msg); + error_summary(handle, total_errors); + SET_CONDITION(handle, cond); + return (MTEST_DONE); +} diff --git a/usr/src/lib/cfgadm_plugins/ac/common/mema_test.h b/usr/src/lib/cfgadm_plugins/ac/common/mema_test.h new file mode 100644 index 0000000000..929eebabca --- /dev/null +++ b/usr/src/lib/cfgadm_plugins/ac/common/mema_test.h @@ -0,0 +1,127 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1996-1998 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#ifndef _MEMA_TEST_H +#define _MEMA_TEST_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +struct mtest_alloc_ent { + struct mtest_alloc_ent *next; + void *buf; +}; + +struct mtest_handle { + u_longlong_t bank_size; + ulong_t page_size; + ulong_t line_size; + ulong_t lines_per_page; + cfga_cond_t condition; + int fd; + ulong_t max_errors; + struct mtest_alloc_ent *alloc_list; + void *drvhandle; + struct cfga_msg *msgp; +}; + +typedef struct mtest_handle *mtest_handle_t; + +typedef int mtest_func_t(mtest_handle_t); + +struct mtest_table_ent { + const char *test_name; + mtest_func_t *test_func; +}; +extern struct mtest_table_ent mtest_table[]; +#define MTEST_DEFAULT_TEST (0) +extern char **mtest_build_opts(int *maxerr_idx); + +#define BANK_SIZE(H) ((H)->bank_size) +#define PAGE_SIZE(H) ((H)->page_size) +#define LINE_SIZE(H) ((H)->line_size) +#define LINES_PER_PAGE(H) ((H)->lines_per_page) +#define SET_CONDITION(H, C) ((H)->condition = (C)) + +struct mtest_error { + int error_type; +}; + +/* + * Error types. + */ +#define MTEST_ERR_NONE 0 +#define MTEST_ERR_UE 1 +#define MTEST_ERR_CE 2 + +/* + * Test routine return codes. + */ +#define MTEST_DONE 0 +#define MTEST_LIB_ERROR 1 +#define MTEST_DEV_ERROR 2 + +/* + * Each test is allowed maximum number of errors and the index has + * to be coordinated with the token table size in mema_test_config.c + */ +#define MAX_ERRORS 32 +#define REPORT_SEC 5 + +/* + * Test functions should use this buffer allocation interface. + * The test framework will deallocate them on return. + */ +extern void *mtest_allocate_buf(mtest_handle_t, size_t); +#define mtest_allocate_page_buf(H) mtest_allocate_buf((H), \ + (size_t)PAGE_SIZE(H)) +extern void mtest_deallocate_buf(mtest_handle_t, void *); +extern void mtest_deallocate_buf_all(mtest_handle_t); + +/* + * Test write: mtest_write(handle, buffer, page_num, line_offset, line_count) + * A line count of 0 indicates the whole page. + * A return of 0 indicates success. A return of -1 indicates a failure of + * the device interface. + */ +extern int mtest_write(mtest_handle_t, void *, u_longlong_t, uint_t, uint_t); +extern int mtest_read(mtest_handle_t, void *, u_longlong_t, uint_t, uint_t, + struct mtest_error *); + +/* + * Message interface. If the upper layer has verbose on, the + * message will be seen by the user. + */ +extern void mtest_message(mtest_handle_t, const char *); + +#ifdef __cplusplus +} +#endif + +#endif /* _MEMA_TEST_H */ diff --git a/usr/src/lib/cfgadm_plugins/ac/common/mema_test_config.c b/usr/src/lib/cfgadm_plugins/ac/common/mema_test_config.c new file mode 100644 index 0000000000..8391b631d8 --- /dev/null +++ b/usr/src/lib/cfgadm_plugins/ac/common/mema_test_config.c @@ -0,0 +1,79 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1996-1998 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stddef.h> +#include <stdlib.h> +#include <sys/param.h> +#include <config_admin.h> +#include <memory.h> +#include "mema_test.h" + +extern mtest_func_t memory_test_normal; +extern mtest_func_t memory_test_quick; +extern mtest_func_t memory_test_extended; + +/* + * Default test is first entry in the table (MTEST_DEFAULT_TEST). + */ +struct mtest_table_ent mtest_table[] = { + {"normal", memory_test_normal}, + {"quick", memory_test_quick}, + {"extended", memory_test_extended}, +}; + +static char **opt_array; + +char ** +mtest_build_opts(int *maxerr_idx) +{ + if (opt_array == NULL) { + int nopts; + /* + * Test "type" options here, max_errors should be the + * last one. + */ + nopts = sizeof (mtest_table) / sizeof (mtest_table[0]); + *maxerr_idx = nopts; + + /* + * One extra option for "max_errors" + */ + opt_array = (char **)malloc((nopts + 2) * sizeof (*opt_array)); + if (opt_array != NULL) { + int i; + + for (i = 0; i < nopts; i++) + opt_array[i] = (char *)mtest_table[i].test_name; + + opt_array[nopts] = "max_errors"; + opt_array[nopts + 1] = NULL; + } + } + *maxerr_idx = sizeof (mtest_table) / sizeof (mtest_table[0]); + return (opt_array); +} diff --git a/usr/src/lib/cfgadm_plugins/ac/common/mema_test_subr.c b/usr/src/lib/cfgadm_plugins/ac/common/mema_test_subr.c new file mode 100644 index 0000000000..90a2656358 --- /dev/null +++ b/usr/src/lib/cfgadm_plugins/ac/common/mema_test_subr.c @@ -0,0 +1,98 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1996-1998 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stddef.h> +#include <stdlib.h> +#include <assert.h> +#include <sys/param.h> +#include <memory.h> +#include <config_admin.h> +#include "mema_test.h" + +void * +mtest_allocate_buf( + mtest_handle_t handle, + size_t size) +{ + struct mtest_alloc_ent *new_ent; + + new_ent = + (struct mtest_alloc_ent *)malloc(sizeof (struct mtest_alloc_ent)); + if (new_ent == NULL) + return (NULL); + + new_ent->buf = malloc(size); + if (new_ent->buf == NULL) { + free((void *)new_ent); + return (NULL); + } + /* TODO: probably not thread safe? */ + new_ent->next = handle->alloc_list; + handle->alloc_list = new_ent; + + return (new_ent->buf); +} + +/* This routine dedicated to George Cameron */ +void +mtest_deallocate_buf( + mtest_handle_t handle, + void *buf) +{ + struct mtest_alloc_ent **p, *p1; + + p = &handle->alloc_list; + while ((*p) != NULL && (*p)->buf != buf) + p = &(*p)->next; + assert((*p) != NULL); + p1 = *p; + *p = (*p)->next; + free(p1->buf); + free((void *)p1); +} + +void +mtest_deallocate_buf_all(mtest_handle_t handle) +{ + struct mtest_alloc_ent *p1; + + while ((p1 = handle->alloc_list) != NULL) { + handle->alloc_list = p1->next; + free(p1->buf); + free((void *)p1); + } +} + +void +mtest_message(mtest_handle_t handle, const char *msg) +{ + if (handle->msgp != NULL && handle->msgp->message_routine != NULL) { + (*handle->msgp->message_routine)(handle->msgp->appdata_ptr, + msg); + } +} diff --git a/usr/src/lib/cfgadm_plugins/ac/common/mema_util.c b/usr/src/lib/cfgadm_plugins/ac/common/mema_util.c new file mode 100644 index 0000000000..944d1c569b --- /dev/null +++ b/usr/src/lib/cfgadm_plugins/ac/common/mema_util.c @@ -0,0 +1,81 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stddef.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <locale.h> +#include <sys/param.h> +#include <config_admin.h> +#include "mema_util.h" + +/* + * The libmemadm routines can return arbitrary error strings. As the + * calling program does not know how long these errors might be, + * the library routines must allocate the required space and the + * calling program must deallocate it. + * + * This routine povides a printf-like interface for creating the + * error strings. + */ + +#define FMT_STR_SLOP (16) + +void +__fmt_errstring( + char **errstring, + size_t extra_length_hint, + const char *fmt, + ...) +{ + char *ebuf; + size_t elen; + va_list ap; + + /* + * If no errors required or error already set, return. + */ + if ((errstring == NULL) || (*errstring != NULL)) + return; + + elen = strlen(fmt) + extra_length_hint + FMT_STR_SLOP; + + if ((ebuf = (char *)malloc(elen + 1)) == NULL) + return; + + va_start(ap, fmt); + (void) vsprintf(ebuf, fmt, ap); + va_end(ap); + + if (strlen(ebuf) > elen) + abort(); + + *errstring = ebuf; +} diff --git a/usr/src/lib/cfgadm_plugins/ac/common/mema_util.h b/usr/src/lib/cfgadm_plugins/ac/common/mema_util.h new file mode 100644 index 0000000000..f4a3710682 --- /dev/null +++ b/usr/src/lib/cfgadm_plugins/ac/common/mema_util.h @@ -0,0 +1,42 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 1996-1998 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#ifndef _MEMA_UTIL_H +#define _MEMA_UTIL_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +extern void __fmt_errstring(char **, size_t, const char *, ...); + +#ifdef __cplusplus +} +#endif + +#endif /* _MEMA_UTIL_H */ diff --git a/usr/src/lib/cfgadm_plugins/ac/sparc/Makefile b/usr/src/lib/cfgadm_plugins/ac/sparc/Makefile new file mode 100644 index 0000000000..b5723eab97 --- /dev/null +++ b/usr/src/lib/cfgadm_plugins/ac/sparc/Makefile @@ -0,0 +1,34 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright (c) 1997-1998, by Sun Microsystems, Inc. +# All rights reserved. +# +#ident "%Z%%M% %I% %E% SMI" +# +# lib/ac/sparc/Makefile + +include ../Makefile.com + +.KEEP_STATE: + +install: all $(ROOTLIBS) $(ROOTLINKS) diff --git a/usr/src/lib/cfgadm_plugins/ac/sparcv9/Makefile b/usr/src/lib/cfgadm_plugins/ac/sparcv9/Makefile new file mode 100644 index 0000000000..7fff4f77de --- /dev/null +++ b/usr/src/lib/cfgadm_plugins/ac/sparcv9/Makefile @@ -0,0 +1,35 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" +# +# lib/ac/sparcv9/Makefile + +include ../Makefile.com +include $(SRC)/lib/Makefile.lib.64 + +.KEEP_STATE: + +install: all $(ROOTLIBS64) $(ROOTLINKS64) diff --git a/usr/src/lib/cfgadm_plugins/sysctrl/Makefile b/usr/src/lib/cfgadm_plugins/sysctrl/Makefile new file mode 100644 index 0000000000..9d582057e8 --- /dev/null +++ b/usr/src/lib/cfgadm_plugins/sysctrl/Makefile @@ -0,0 +1,73 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" +# +# lib/cfgadm_plugins/sysctrl/Makefile + +include $(SRC)/Makefile.master + +SUBDIRS= $(MACH) $(BUILD64) $(MACH64) + +all := TARGET= all +clean := TARGET= clean +clobber := TARGET= clobber +delete := TARGET= delete +install := TARGET= install +lint := TARGET= lint +_msg := TARGET= _msg +package := TARGET= package + +TEXT_DOMAIN= SUNW_OST_OSLIB +XGETFLAGS= -a -x sysctrl.xcl +POFILE= sysctrl.po +POFILES= generic.po + +SED= sed +GREP= grep +CP= cp + +.KEEP_STATE: + +all clean clobber delete install lint package: $(SUBDIRS) + +$(MACH) $(MACH64): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +_msg: $(MSGDOMAIN) $(POFILE) + $(RM) $(MSGDOMAIN)/$(POFILE) + $(CP) $(POFILE) $(MSGDOMAIN) + +$(POFILE): $(POFILES) + $(RM) $@ + $(CAT) $(POFILES) > $@ + +$(POFILES): + $(RM) messages.po + $(XGETTEXT) $(XGETFLAGS) `$(GREP) -l gettext */*.[ch]` + $(SED) -e '/^# msg/d' -e '/^domain/d' messages.po > $@ + $(RM) messages.po + +FRC: diff --git a/usr/src/lib/cfgadm_plugins/sysctrl/Makefile.com b/usr/src/lib/cfgadm_plugins/sysctrl/Makefile.com new file mode 100644 index 0000000000..f37a852473 --- /dev/null +++ b/usr/src/lib/cfgadm_plugins/sysctrl/Makefile.com @@ -0,0 +1,99 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# +# lib/sysctrl/Makefile.com +# + +include $(SRC)/lib/cfgadm_plugins/Makefile.com + +PLATFORM= sun4u +LIBRARY= sysctrl.a +VERS= .1 + +OBJECTS= cfga.o + +# include library definitions +include $(SRC)/lib/Makefile.lib + +INS.dir.root.sys= $(INS) -s -d -m $(DIRMODE) $@ +$(CH)INS.dir.root.sys= $(INS) -s -d -m $(DIRMODE) -u root -g sys $@ +INS.dir.root.bin= $(INS) -s -d -m $(DIRMODE) $@ +$(CH)INS.dir.root.bin= $(INS) -s -d -m $(DIRMODE) -u root -g bin $@ + +USR_PLAT_DIR = $(ROOT)/usr/platform +USR_PSM_DIR = $(USR_PLAT_DIR)/sun4u +USR_PSM_LIB_DIR = $(USR_PSM_DIR)/lib +USR_PSM_LIB_CFG_DIR = $(USR_PSM_LIB_DIR)/cfgadm +USR_PSM_LIB_CFG_DIR_64 = $(USR_PSM_LIB_CFG_DIR)/$(MACH64) + +ROOTLIBDIR= $(USR_PSM_LIB_CFG_DIR) +ROOTLIBDIR64= $(USR_PSM_LIB_CFG_DIR_64) + +MAPFILE= ../common/mapfile-vers +SRCS= $(OBJECTS:%.o=../common/%.c) + +LIBS = $(DYNLIB) + +CFLAGS += $(CCVERBOSE) +DYNFLAGS += -M $(MAPFILE) +LDLIBS += -lc + +CPPFLAGS += -I$(ROOT)/usr/platform/$(PLATFORM)/include + +.KEEP_STATE: + +all: $(LIBS) + +lint: lintcheck + +$(DYNLIB): $(MAPFILE) + +# Create target directories +$(USR_PSM_DIR): $(LINKED_DIRS) + -$(INS.dir.root.sys) + +$(USR_PSM_LIB_DIR): $(USR_PSM_DIR) $(LINKED_LIB_DIRS) + -$(INS.dir.root.bin) + +$(USR_PSM_LIB_CFG_DIR): $(USR_PSM_LIB_DIR) $(LINKED_CFG_DIRS) + -$(INS.dir.root.bin) + +$(USR_PSM_LIB_CFG_DIR_64): $(USR_PSM_LIB_CFG_DIR) + -$(INS.dir.root.bin) + +$(USR_PSM_LIB_CFG_DIR)/%: % $(USR_PSM_LIB_CFG_DIR) + -$(INS.file) + +$(USR_PSM_LIB_CFG_DIR_64)/%: % $(USR_PSM_LIB_CFG_DIR_64) + -$(INS.file) + +# include library targets +include $(SRC)/lib/Makefile.targ + +pics/%.o: ../common/%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) diff --git a/usr/src/lib/cfgadm_plugins/sysctrl/common/cfga.c b/usr/src/lib/cfgadm_plugins/sysctrl/common/cfga.c new file mode 100644 index 0000000000..1dca716564 --- /dev/null +++ b/usr/src/lib/cfgadm_plugins/sysctrl/common/cfga.c @@ -0,0 +1,1480 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stddef.h> +#include <locale.h> +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <locale.h> +#include <langinfo.h> +#include <time.h> +#include <stdarg.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/dditypes.h> +#include <sys/modctl.h> +#include <sys/obpdefs.h> +#include <sys/fhc.h> +#include <sys/sysctrl.h> +#include <sys/openpromio.h> +#ifdef SIM +#include <sys/stat.h> +#endif +#define CFGA_PLUGIN_LIB +#include <config_admin.h> + +#ifdef DEBUG +#define DBG printf +#define DBG1 printf +#define DBG3 printf +#define DBG4 printf +#else +#define DBG(a, b) +#define DBG1(a) +#define DBG3(a, b, c) +#define DBG4(a, b, c, d) +#endif + +#define BD_CPU 1 +#define BD_MEM 2 +#define BD_IO_2SBUS 3 +#define BD_IO_SBUS_FFB 4 +#define BD_IO_PCI 5 +#define BD_DISK 6 +#define BD_IO_2SBUS_SOCPLUS 7 +#define BD_IO_SBUS_FFB_SOCPLUS 8 +#define BD_UNKNOWN 9 +#define CMD_GETSTAT 10 +#define CMD_LIST 11 +#define CMD_CONNECT 12 +#define CMD_DISCONNECT 13 +#define CMD_CONFIGURE 14 +#define CMD_UNCONFIGURE 15 +#define CMD_QUIESCE 16 +#define CMD_INSERT 17 +#define CMD_REMOVE 18 +#define CMD_SET_COND 19 +#define OPT_ENABLE 20 +#define OPT_DISABLE 21 +#define ERR_PROM_OPEN 22 +#define ERR_PROM_GETPROP 23 +#define ERR_PROM_SETPROP 24 +#define ERR_TRANS 25 +#define ERR_CMD_INVAL 26 +#define ERR_OPT_INVAL 27 +#define ERR_AP_INVAL 28 +#define ERR_DISABLED 29 +#define DIAG_FORCE 30 +#define DIAG_TRANS_OK 31 +#define DIAG_FAILED 32 +#define DIAG_WAS_ENABLED 33 +#define DIAG_WAS_DISABLED 34 +#define DIAG_WILL_ENABLE 35 +#define DIAG_WILL_DISABLE 36 +#define HELP_HEADER 37 +#define HELP_QUIESCE 38 +#define HELP_INSERT 39 +#define HELP_REMOVE 40 +#define HELP_SET_COND 41 +#define HELP_ENABLE 42 +#define HELP_DISABLE 43 +#define HELP_UNKNOWN 44 +#define ASK_CONNECT 45 +#define STR_BD 46 +#define STR_COL 47 +#define COND_UNKNOWN 48 +#define COND_OK 49 +#define COND_FAILING 50 +#define COND_FAILED 51 +#define COND_UNUSABLE 52 +#define SYSC_COOLING 53 +#define SYSC_POWER 54 +#define SYSC_PRECHARGE 55 +#define SYSC_INTRANS 56 +#define SYSC_UTHREAD 57 +#define SYSC_KTHREAD 58 +#define SYSC_DEV_ATTACH 59 +#define SYSC_DEV_DETACH 60 +#define SYSC_NDI_ATTACH 61 +#define SYSC_NDI_DETACH 62 +#define SYSC_CORE_RESOURCE 63 +#define SYSC_OSTATE 64 +#define SYSC_RSTATE 65 +#define SYSC_COND 66 +#define SYSC_PROM 67 +#define SYSC_NOMEM 68 +#define SYSC_HOTPLUG 69 +#define SYSC_HW_COMPAT 70 +#define SYSC_NON_DR_PROM 71 +#define SYSC_SUSPEND 72 +#define SYSC_RESUME 73 +#define SYSC_UNKNOWN 74 +#define SYSC_DEVSTR 75 + +/* + * The string table contains all the strings used by the platform + * library. The comment next to each string specifies whether the + * string should be internationalized (y) or not (n). + * Note that there are calls to dgettext() with strings other than + * the ones below, they are marked by the li18 symbol. + */ +static char * +cfga_strs[] = { + /* */ NULL, + /* n */ "cpu/mem ", + /* n */ "mem ", + /* n */ "dual-sbus ", + /* n */ "sbus-upa ", + /* n */ "dual-pci ", + /* n */ "disk ", + /* n */ "soc+sbus ", + /* n */ "soc+upa ", + /* n */ "unknown ", + /* n */ "get-status", + /* n */ "list", + /* n */ "connect", + /* n */ "disconnect", + /* n */ "configure", + /* n */ "unconfigure", + /* n */ "quiesce-test", + /* n */ "insert-test", + /* n */ "remove-test", + /* n */ "set-condition-test", + /* n */ "enable-at-boot", + /* n */ "disable-at-boot", + /* n */ "prom open", + /* n */ "prom getprop", + /* n */ "prom setprop", + /* y */ "invalid transition", + /* y */ "invalid command: ", + /* y */ "invalid option: ", + /* y */ "invalid attachment point: ", + /* y */ "board is disabled: must override with ", + /* n */ "[-f][-o enable-at-boot]", + /* y */ "transition succeeded but ", + /* y */ " failed: ", + /* y */ "was already enabled at boot time", + /* y */ "was already disabled at boot time", + /* y */ "will be enabled at boot time", + /* y */ "will be disabled at boot time", + /* y */ "\nSysctrl specific commands/options:", + /* n */ "\t-x quiesce-test ap_id [ap_id...]", + /* n */ "\t-x insert-test ap_id [ap_id...]", + /* n */ "\t-x remove-test ap_id [ap_id...]", + /* n */ "\t-x set-condition-test=<condition>", + /* n */ "\t-o enable-at-boot", + /* n */ "\t-o disable-at-boot", + /* y */ "\tunknown command or option: ", + /* y */ + "system will be temporarily suspended to connect a board: proceed", + /* y */ "board ", + /* y */ ": ", + /* n */ "unknown", + /* n */ "ok", + /* n */ "failing", + /* n */ "failed", + /* n */ "unusable", + /* y */ "not enough cooling for a new board", + /* y */ "not enough power for a new board", + /* y */ "not enough precharge power for a new board", + /* y */ "configuration operation already in progress on this board", + /* y */ "could not suspend user process: ", + /* y */ "could not suspend system processes", + /* y */ "device did not attach", + /* y */ "device did not detach", + /* y */ "nexus error during attach", + /* y */ "nexus error during detach", + /* y */ "attempt to remove core system resource", + /* y */ "invalid occupant state", + /* y */ "invalid receptacle state", + /* y */ "insufficient condition", + /* y */ "firmware operation error", + /* y */ "not enough memory", + /* y */ "hotplug feature unavailable on this machine", + /* y */ "board does not support dynamic reconfiguration", + /* y */ "firmware does not support dynamic reconfiguration", + /* y */ "system suspend error", + /* y */ "system resume error", + /* y */ "unknown system error", + /* */ NULL +}; + +#define cfga_str(i) cfga_strs[(i)] + +#define cfga_eid(a, b) (((a) << 8) + (b)) + +/* + * + * Translation table for mapping from an <errno,sysc_err> + * pair to an error string. + * + * + * SYSC_COOLING, EAGAIN, SYSC_ERR_COOLING + * SYSC_POWER, EAGAIN, SYSC_ERR_POWER + * SYSC_PRECHARGE, EAGAIN, SYSC_ERR_PRECHARGE + * SYSC_INTRANS, EBUSY, SYSC_ERR_INTRANS + * SYSC_KTHREAD, EBUSY, SYSC_ERR_KTHREAD + * SYSC_DEV_ATTACH, EBUSY, SYSC_ERR_NDI_ATTACH + * SYSC_DEV_DETACH, EBUSY, SYSC_ERR_NDI_DETACH + * SYSC_NDI_ATTACH, EFAULT, SYSC_ERR_NDI_ATTACH + * SYSC_NDI_DETACH, EFAULT, SYSC_ERR_NDI_DETACH + * SYSC_CORE_RESOURCE, EINVAL, SYSC_ERR_CORE_RESOURCE + * SYSC_OSTATE, EINVAL, SYSC_ERR_OSTATE + * SYSC_RSTATE, EINVAL, SYSC_ERR_RSTATE + * SYSC_COND, EINVAL, SYSC_ERR_COND + * SYSC_PROM, EIO, SYSC_ERR_PROM + * SYSC_NOMEM, ENOMEM, SYSC_ERR_DR_INIT + * SYSC_NOMEM, ENOMEM, SYSC_ERR_NDI_ATTACH + * SYSC_NOMEM, ENOMEM, SYSC_ERR_NDI_DETACH + * SYSC_HOTPLUG, ENOTSUP, SYSC_ERR_HOTPLUG + * SYSC_HW_COMPAT, ENOTSUP, SYSC_ERR_HW_COMPAT + * SYSC_NON_DR_PROM, ENOTSUP, SYSC_ERR_NON_DR_PROM + * SYSC_SUSPEND, ENXIO, SYSC_ERR_SUSPEND + * SYSC_RESUME, ENXIO, SYSC_ERR_RESUME + * SYSC_UTHREAD, ESRCH, SYSC_ERR_UTHREAD + */ +static int +cfga_sid(int err, int scerr) +{ + if (scerr == SYSC_ERR_DEFAULT) + return (SYSC_UNKNOWN); + + switch (cfga_eid(err, scerr)) { + case cfga_eid(EAGAIN, SYSC_ERR_COOLING): + return (SYSC_COOLING); + case cfga_eid(EAGAIN, SYSC_ERR_POWER): + return (SYSC_POWER); + case cfga_eid(EAGAIN, SYSC_ERR_PRECHARGE): + return (SYSC_PRECHARGE); + case cfga_eid(EBUSY, SYSC_ERR_INTRANS): + return (SYSC_INTRANS); + case cfga_eid(EBUSY, SYSC_ERR_KTHREAD): + return (SYSC_KTHREAD); + case cfga_eid(EBUSY, SYSC_ERR_NDI_ATTACH): + return (SYSC_DEV_ATTACH); + case cfga_eid(EBUSY, SYSC_ERR_NDI_DETACH): + return (SYSC_DEV_DETACH); + case cfga_eid(EFAULT, SYSC_ERR_NDI_ATTACH): + return (SYSC_NDI_ATTACH); + case cfga_eid(EFAULT, SYSC_ERR_NDI_DETACH): + return (SYSC_NDI_DETACH); + case cfga_eid(EINVAL, SYSC_ERR_CORE_RESOURCE): + return (SYSC_CORE_RESOURCE); + case cfga_eid(EINVAL, SYSC_ERR_OSTATE): + return (SYSC_OSTATE); + case cfga_eid(EINVAL, SYSC_ERR_RSTATE): + return (SYSC_RSTATE); + case cfga_eid(EINVAL, SYSC_ERR_COND): + return (SYSC_COND); + case cfga_eid(EIO, SYSC_ERR_PROM): + return (SYSC_PROM); + case cfga_eid(ENOMEM, SYSC_ERR_DR_INIT): + return (SYSC_NOMEM); + case cfga_eid(ENOMEM, SYSC_ERR_NDI_ATTACH): + return (SYSC_NOMEM); + case cfga_eid(ENOMEM, SYSC_ERR_NDI_DETACH): + return (SYSC_NOMEM); + case cfga_eid(ENOTSUP, SYSC_ERR_HOTPLUG): + return (SYSC_HOTPLUG); + case cfga_eid(ENOTSUP, SYSC_ERR_HW_COMPAT): + return (SYSC_HW_COMPAT); + case cfga_eid(ENOTSUP, SYSC_ERR_NON_DR_PROM): + return (SYSC_NON_DR_PROM); + case cfga_eid(ENXIO, SYSC_ERR_SUSPEND): + return (SYSC_SUSPEND); + case cfga_eid(ENXIO, SYSC_ERR_RESUME): + return (SYSC_RESUME); + case cfga_eid(ESRCH, SYSC_ERR_UTHREAD): + return (SYSC_UTHREAD); + default: + break; + } + + return (SYSC_UNKNOWN); +} + +static void +sysc_cmd_init(sysc_cfga_cmd_t *sc, char *outputstr, int force) +{ + sc->force = force; + sc->outputstr = outputstr; + sc->errtype = SYSC_ERR_DEFAULT; + + (void) memset((void *)outputstr, 0, sizeof (outputstr)); + + cfga_str(SYSC_DEVSTR) = outputstr; +} + +/* + * cfga_err() accepts a variable number of message IDs and constructs + * a corresponding error string which is returned via the errstring argument. + * cfga_err() calls dgettext() to internationalize proper messages. + */ +static void +cfga_err(sysc_cfga_cmd_t *sc, char **errstring, ...) +{ + int a; + int i; + int n; + int len; + int flen; + char *p; + char *q; + char *s[32]; + char *failed; + va_list ap; + char syserr_num[20]; + + /* + * If errstring is null it means user in not interested in getting + * error status. So we don't do all the work + */ + if (errstring == NULL) { + return; + } + va_start(ap, errstring); + + failed = dgettext(TEXT_DOMAIN, cfga_str(DIAG_FAILED)); + flen = strlen(failed); + + for (n = len = 0; (a = va_arg(ap, int)) != 0; n++) { + + switch (a) { + case ERR_PROM_OPEN: + case ERR_PROM_GETPROP: + case ERR_PROM_SETPROP: + case CMD_GETSTAT: + case CMD_LIST: + case CMD_CONNECT: + case CMD_DISCONNECT: + case CMD_CONFIGURE: + case CMD_UNCONFIGURE: + case CMD_QUIESCE: + case CMD_INSERT: + case CMD_REMOVE: + case CMD_SET_COND: + p = cfga_str(a); + len += (strlen(p) + flen); + s[n] = p; + s[++n] = failed; + + DBG("<%s>", p); + DBG("<%s>", failed); + break; + + case OPT_ENABLE: + case OPT_DISABLE: + p = dgettext(TEXT_DOMAIN, cfga_str(DIAG_TRANS_OK)); + q = cfga_str(a); + len += (strlen(p) + strlen(q) + flen); + s[n] = p; + s[++n] = q; + s[++n] = failed; + + DBG("<%s>", p); + DBG("<%s>", q); + DBG("<%s>", failed); + break; + + case ERR_CMD_INVAL: + case ERR_AP_INVAL: + case ERR_OPT_INVAL: + p = dgettext(TEXT_DOMAIN, cfga_str(a)); + q = va_arg(ap, char *); + len += (strlen(p) + strlen(q)); + s[n] = p; + s[++n] = q; + + DBG("<%s>", p); + DBG("<%s>", q); + break; + + case ERR_TRANS: + case ERR_DISABLED: + p = dgettext(TEXT_DOMAIN, cfga_str(a)); + len += strlen(p); + s[n] = p; + + DBG("<%s>", p); + break; + + case DIAG_FORCE: + default: + p = cfga_str(a); + len += strlen(p); + s[n] = p; + + DBG("<%s>", p); + break; + } + } + + DBG1("\n"); + va_end(ap); + + if (errno) { + if (sc) + i = cfga_sid(errno, (int)sc->errtype); + else + i = SYSC_UNKNOWN; + + DBG4("cfga_sid(%d,%d)=%d\n", errno, sc->errtype, i); + + if (i == SYSC_UNKNOWN) { + p = strerror(errno); + if (p == NULL) { + (void) sprintf(syserr_num, "errno=%d", errno); + p = syserr_num; + } + } else + p = dgettext(TEXT_DOMAIN, cfga_str(i)); + + len += strlen(p); + s[n++] = p; + p = cfga_str(SYSC_DEVSTR); + if (p && p[0]) { + q = cfga_str(STR_COL); + + len += strlen(q); + s[n++] = q; + len += strlen(p); + s[n++] = p; + } + } + + if ((p = (char *)calloc(len, 1)) == NULL) + return; + + for (i = 0; i < n; i++) + (void) strcat(p, s[i]); + + *errstring = p; +#ifdef SIM_MSG + printf("%s\n", *errstring); +#endif +} + +/* + * This routine accepts a variable number of message IDs and constructs + * a corresponding error string which is printed via the message print routine + * argument. The HELP_UNKNOWN message ID has an argument string (the unknown + * help topic) that follows. + */ +static void +cfga_msg(struct cfga_msg *msgp, ...) +{ + int a; + int i; + int n; + int len; + char *p; + char *s[32]; + va_list ap; + + va_start(ap, msgp); + + for (n = len = 0; (a = va_arg(ap, int)) != 0; n++) { + DBG("<%d>", a); + p = dgettext(TEXT_DOMAIN, cfga_str(a)); + len += strlen(p); + s[n] = p; + if (a == HELP_UNKNOWN) { + p = va_arg(ap, char *); + len += strlen(p); + s[++n] = p; + } + } + + va_end(ap); + + if ((p = (char *)calloc(len + 1, 1)) == NULL) + return; + + for (i = 0; i < n; i++) + (void) strcat(p, s[i]); + (void) strcat(p, "\n"); + +#ifdef SIM_MSG + printf("%s", p); +#else + (*msgp->message_routine)(msgp->appdata_ptr, p); +#endif + free(p); +} + +static sysc_cfga_stat_t * +sysc_stat(const char *ap_id, int *fdp) +{ + int fd; + static sysc_cfga_stat_t sc_list[MAX_BOARDS]; + + + if ((fd = open(ap_id, O_RDWR, 0)) == -1) + return (NULL); + else if (ioctl(fd, SYSC_CFGA_CMD_GETSTATUS, sc_list) == -1) { + (void) close(fd); + return (NULL); + } else if (fdp) + *fdp = fd; + else + (void) close(fd); + + return (sc_list); +} + +/* + * This code implementes the simulation of the ioctls that transition state. + * The GETSTAT ioctl is not simulated. In this way a snapshot of the system + * state is read and manipulated by the simulation routines. It is basically + * a useful debugging tool. + */ +#ifdef SIM +static int sim_idx; +static int sim_fd = -1; +static int sim_size = MAX_BOARDS * sizeof (sysc_cfga_stat_t); +static sysc_cfga_stat_t sim_sc_list[MAX_BOARDS]; + +static sysc_cfga_stat_t * +sim_sysc_stat(const char *ap_id, int *fdp) +{ + int fd; + struct stat buf; + + if (sim_fd != -1) + return (sim_sc_list); + + if ((sim_fd = open("/tmp/cfga_simdata", O_RDWR|O_CREAT)) == -1) { + perror("sim_open"); + exit(1); + } else if (fstat(sim_fd, &buf) == -1) { + perror("sim_stat"); + exit(1); + } + + if (buf.st_size) { + if (buf.st_size != sim_size) { + perror("sim_size"); + exit(1); + } else if (read(sim_fd, sim_sc_list, sim_size) == -1) { + perror("sim_read"); + exit(1); + } + } else if ((fd = open(ap_id, O_RDWR, 0)) == -1) + return (NULL); + else if (ioctl(fd, SYSC_CFGA_CMD_GETSTATUS, sim_sc_list) == -1) { + (void) close(fd); + return (NULL); + } else if (fdp) + *fdp = fd; + + return (sim_sc_list); +} + +static int +sim_open(char *a, int b, int c) +{ + printf("sim_open(%s)\n", a); + + if (strcmp(a, "/dev/openprom") == 0) + return (open(a, b, c)); + return (0); +} + +static int +sim_close(int a) { return (0); } + +static int +sim_ioctl(int fd, int cmd, void *a) +{ + printf("sim_ioctl(%d)\n", sim_idx); + + switch (cmd) { + case SYSC_CFGA_CMD_CONNECT: + sim_sc_list[sim_idx].rstate = SYSC_CFGA_RSTATE_CONNECTED; + break; + case SYSC_CFGA_CMD_CONFIGURE: + sim_sc_list[sim_idx].ostate = SYSC_CFGA_OSTATE_CONFIGURED; + break; + case SYSC_CFGA_CMD_UNCONFIGURE: + sim_sc_list[sim_idx].ostate = SYSC_CFGA_OSTATE_UNCONFIGURED; + break; + case SYSC_CFGA_CMD_DISCONNECT: + sim_sc_list[sim_idx].rstate = SYSC_CFGA_RSTATE_DISCONNECTED; + break; + case SYSC_CFGA_CMD_QUIESCE_TEST: + case SYSC_CFGA_CMD_TEST: + return (0); + case OPROMGETOPT: + return (ioctl(fd, OPROMGETOPT, a)); + case OPROMSETOPT: + return (ioctl(fd, OPROMSETOPT, a)); + } + + if (lseek(sim_fd, SEEK_SET, 0) == -1) { + perror("sim_seek"); + exit(1); + } + if (write(sim_fd, sim_sc_list, sim_size) == -1) { + perror("sim_write"); + exit(1); + } + + return (0); +} + +#define open(a, b, c) sim_open((char *)(a), (int)(b), (int)(c)) +#define close(a) sim_close(a) +#define ioctl(a, b, c) sim_ioctl((int)(a), (int)(b), (void *)(c)) +#define sysc_stat(a, b) sim_sysc_stat(a, b) +#endif /* SIM */ + +static char *promdev = "/dev/openprom"; +static char *dlprop = "disabled-board-list"; + +#define BUFSIZE 128 + +typedef union { + char buf[BUFSIZE]; + struct openpromio opp; +} oppbuf_t; + +static int +prom_get_prop(int prom_fd, char *var, char **val) +{ + static oppbuf_t oppbuf; + struct openpromio *opp = &(oppbuf.opp); + + (void) strncpy(opp->oprom_array, var, OBP_MAXPROPNAME); + opp->oprom_array[OBP_MAXPROPNAME + 1] = '\0'; + opp->oprom_size = BUFSIZE; + + DBG3("getprop(%s, %d)\n", opp->oprom_array, opp->oprom_size); + + if (ioctl(prom_fd, OPROMGETOPT, opp) < 0) + return (ERR_PROM_GETPROP); + else if (opp->oprom_size > 0) + *val = opp->oprom_array; + else + *val = NULL; + + return (0); +} + +static cfga_err_t +prom_set_prop(int prom_fd, char *var, char *val) +{ + oppbuf_t oppbuf; + struct openpromio *opp = &(oppbuf.opp); + int varlen = strlen(var) + 1; + int vallen = strlen(val); + + DBG("prom_set_prop(%s)\n", val); + + (void) strcpy(opp->oprom_array, var); + (void) strcpy(opp->oprom_array + varlen, val); + opp->oprom_size = varlen + vallen; + + if (ioctl(prom_fd, OPROMSETOPT, opp) < 0) + return (ERR_PROM_SETPROP); + + return (0); +} + +static int +dlist_find(int board, char **dlist, int *disabled) +{ + int i; + int err; + int prom_fd; + char *p; + char *dl; + char b[2]; + + if ((prom_fd = open(promdev, O_RDWR, 0)) < 0) + return (ERR_PROM_OPEN); + else if (err = prom_get_prop(prom_fd, dlprop, dlist)) { + (void) close(prom_fd); + return (err); + } else + (void) close(prom_fd); + + b[1] = 0; + *disabled = 0; + + if ((dl = *dlist) != NULL) { + int len = strlen(dl); + + for (i = 0; i < len; i++) { + int bd; + + b[0] = dl[i]; + bd = strtol(b, &p, 16); + + if (p != b && bd == board) + (*disabled)++; + } + } + + return (0); +} + +static int +dlist_update(int board, int disable, char *dlist, struct cfga_msg *msgp, + int verbose) +{ + int i, j, n; + int err; + int found; + int update; + int prom_fd; + char *p; + char b[2]; + char ndlist[64]; + + b[1] = 0; + ndlist[0] = 0; + j = 0; + found = 0; + update = 0; + + if ((prom_fd = open(promdev, O_RDWR, 0)) < 0) + return (ERR_PROM_OPEN); + + if (dlist) { + int len = strlen(dlist); + + for (i = 0; i < len; i++) { + int bd; + + b[0] = dlist[i]; + bd = strtol(b, &p, 16); + + if (p != b && bd == board) { + + found++; + if (disable) { + if (verbose) + cfga_msg(msgp, STR_BD, + DIAG_WAS_DISABLED, 0); + } else { + if (verbose) + cfga_msg(msgp, STR_BD, + DIAG_WILL_ENABLE, 0); + update++; + continue; + } + } + ndlist[j++] = dlist[i]; + } + ndlist[j] = 0; + } + + if (!found) + if (disable) { + if (verbose) + cfga_msg(msgp, STR_BD, DIAG_WILL_DISABLE, 0); + p = &ndlist[j]; + n = sprintf(p, "%x", board); + p[n] = 0; + update++; + } else { + if (verbose) + cfga_msg(msgp, STR_BD, DIAG_WAS_ENABLED, 0); + } + + if (update) + err = prom_set_prop(prom_fd, dlprop, ndlist); + else + err = 0; + + (void) close(prom_fd); + + return (err); +} + +static int +ap_idx(const char *ap_id) +{ + int id; + char *s; + static char *slot = "slot"; + + DBG("ap_idx(%s)\n", ap_id); + + if ((s = strstr(ap_id, slot)) == NULL) + return (-1); + else { + int n; + + s += strlen(slot); + n = strlen(s); + + DBG3("ap_idx: s=%s, n=%d\n", s, n); + + switch (n) { + case 2: + if (!isdigit(s[1])) + return (-1); + /* FALLTHROUGH */ + case 1: + if (!isdigit(s[0])) + return (-1); + break; + default: + return (-1); + } + } + + if ((id = atoi(s)) > MAX_BOARDS) + return (-1); + + DBG3("ap_idx(%s)=%d\n", s, id); + + return (id); +} + +/*ARGSUSED*/ +cfga_err_t +cfga_change_state( + cfga_cmd_t state_change_cmd, + const char *ap_id, + const char *options, + struct cfga_confirm *confp, + struct cfga_msg *msgp, + char **errstring, + cfga_flags_t flags) +{ + int fd; + int idx; + int err; + int force; + int verbose; + int opterr; + int disable; + int disabled; + cfga_err_t rc; + sysc_cfga_stat_t *ss; + sysc_cfga_cmd_t *sc, sysc_cmd; + sysc_cfga_rstate_t rs; + sysc_cfga_ostate_t os; + char *dlist; + char outputstr[SYSC_OUTPUT_LEN]; + + if (errstring != NULL) + *errstring = NULL; + + rc = CFGA_ERROR; + + if (options) { + disable = 0; + if (strcmp(options, cfga_str(OPT_DISABLE)) == 0) + disable++; + else if (strcmp(options, cfga_str(OPT_ENABLE))) { + cfga_err(NULL, errstring, ERR_OPT_INVAL, options, 0); + return (rc); + } + } + + if ((idx = ap_idx(ap_id)) == -1) { + cfga_err(NULL, errstring, ERR_AP_INVAL, ap_id, 0); + return (rc); + } else if ((ss = sysc_stat(ap_id, &fd)) == NULL) { + cfga_err(NULL, errstring, CMD_GETSTAT, 0); + return (rc); + } +#ifdef SIM + sim_idx = idx; +#endif + /* + * We disallow connecting on the disabled list unless + * either the FORCE flag or the enable-at-boot option + * is set. The check is made further below + */ + if (opterr = dlist_find(idx, &dlist, &disabled)) { + err = disable ? OPT_DISABLE : OPT_ENABLE; + cfga_err(NULL, errstring, err, opterr, 0); + (void) close(fd); + return (rc); + } else + force = flags & CFGA_FLAG_FORCE; + + rs = ss[idx].rstate; + os = ss[idx].ostate; + + sc = &sysc_cmd; + sysc_cmd_init(sc, outputstr, force); + verbose = flags & CFGA_FLAG_VERBOSE; + + switch (state_change_cmd) { + case CFGA_CMD_CONNECT: + if (rs != SYSC_CFGA_RSTATE_DISCONNECTED) + cfga_err(NULL, errstring, ERR_TRANS, 0); + else if (disabled && !(force || (options && !disable))) + cfga_err(NULL, errstring, CMD_CONNECT, + ERR_DISABLED, DIAG_FORCE, 0); + else if (!(*confp->confirm)(confp->appdata_ptr, + cfga_str(ASK_CONNECT))) { + (void) close(fd); + return (CFGA_NACK); + } else if (ioctl(fd, SYSC_CFGA_CMD_CONNECT, sc) == -1) + cfga_err(sc, errstring, CMD_CONNECT, 0); + else if (options && (opterr = dlist_update(idx, disable, + dlist, msgp, verbose))) { + err = disable ? OPT_DISABLE : OPT_ENABLE; + cfga_err(NULL, errstring, err, opterr, 0); + } else + rc = CFGA_OK; + break; + + case CFGA_CMD_DISCONNECT: + if ((os == SYSC_CFGA_OSTATE_CONFIGURED) && + (ioctl(fd, SYSC_CFGA_CMD_UNCONFIGURE, sc) == -1)) { + cfga_err(sc, errstring, CMD_UNCONFIGURE, 0); + (void) close(fd); + return (CFGA_ERROR); + } else + sysc_cmd_init(sc, outputstr, force); + + if (rs == SYSC_CFGA_RSTATE_CONNECTED) { + if (ioctl(fd, SYSC_CFGA_CMD_DISCONNECT, sc) == -1) + cfga_err(sc, errstring, CMD_DISCONNECT, 0); + else if (options && (opterr = dlist_update(idx, disable, + dlist, msgp, verbose))) { + err = disable ? OPT_DISABLE : OPT_ENABLE; + cfga_err(NULL, errstring, err, opterr, 0); + } else + rc = CFGA_OK; + } else + cfga_err(NULL, errstring, ERR_TRANS, 0); + break; + + case CFGA_CMD_CONFIGURE: + if (rs == SYSC_CFGA_RSTATE_DISCONNECTED) + if (disabled && !(force || (options && !disable))) { + cfga_err(NULL, errstring, CMD_CONFIGURE, + ERR_DISABLED, DIAG_FORCE, 0); + (void) close(fd); + return (CFGA_ERROR); + } else if (!(*confp->confirm)(confp->appdata_ptr, + cfga_str(ASK_CONNECT))) { + (void) close(fd); + return (CFGA_NACK); + } else if (ioctl(fd, SYSC_CFGA_CMD_CONNECT, sc) == -1) { + cfga_err(sc, errstring, CMD_CONNECT, 0); + (void) close(fd); + return (CFGA_ERROR); + } else + sysc_cmd_init(sc, outputstr, force); + + if (os == SYSC_CFGA_OSTATE_UNCONFIGURED) { + if (ioctl(fd, SYSC_CFGA_CMD_CONFIGURE, sc) == -1) + cfga_err(sc, errstring, CMD_CONFIGURE, 0); + else if (options && (opterr = dlist_update(idx, + disable, dlist, msgp, verbose))) { + err = disable ? OPT_DISABLE : OPT_ENABLE; + cfga_err(NULL, errstring, err, opterr, 0); + } else + rc = CFGA_OK; + } else + cfga_err(NULL, errstring, ERR_TRANS, 0); + break; + + case CFGA_CMD_UNCONFIGURE: + if (os != SYSC_CFGA_OSTATE_CONFIGURED) + cfga_err(NULL, errstring, ERR_TRANS, 0); + else if (ioctl(fd, SYSC_CFGA_CMD_UNCONFIGURE, sc) == -1) + cfga_err(sc, errstring, CMD_UNCONFIGURE, 0); + else if (options && (opterr = dlist_update(idx, disable, + dlist, msgp, verbose))) { + err = disable ? OPT_DISABLE : OPT_ENABLE; + cfga_err(NULL, errstring, err, opterr, 0); + } else + rc = CFGA_OK; + break; + + default: + rc = CFGA_OPNOTSUPP; + break; + } + + (void) close(fd); + return (rc); +} + +static int +str2cond(const char *cond) +{ + int c; + + if (strcmp(cond, cfga_str(COND_UNKNOWN)) == 0) + c = SYSC_CFGA_COND_UNKNOWN; + else if (strcmp(cond, cfga_str(COND_OK)) == 0) + c = SYSC_CFGA_COND_OK; + else if (strcmp(cond, cfga_str(COND_FAILING)) == 0) + c = SYSC_CFGA_COND_FAILING; + else if (strcmp(cond, cfga_str(COND_FAILED)) == 0) + c = SYSC_CFGA_COND_FAILED; + else if (strcmp(cond, cfga_str(COND_UNUSABLE)) == 0) + c = SYSC_CFGA_COND_UNUSABLE; + else + c = -1; + + return (c); +} + +/*ARGSUSED*/ +cfga_err_t +cfga_private_func( + const char *function, + const char *ap_id, + const char *options, + struct cfga_confirm *confp, + struct cfga_msg *msgp, + char **errstring, + cfga_flags_t flags) +{ + int fd; + int idx; + int len; + int cmd; + int cond; + int err; + int opterr; + int verbose; + int disable; + int disabled; + cfga_err_t rc; + char *str; + char *dlist; + char outputstr[SYSC_OUTPUT_LEN]; + sysc_cfga_cmd_t *sc, sysc_cmd; + + if (errstring != NULL) + *errstring = NULL; + + verbose = flags & CFGA_FLAG_VERBOSE; + + rc = CFGA_ERROR; + + if (options) { + disable = 0; + if (strcmp(options, cfga_str(OPT_DISABLE)) == 0) + disable++; + else if (strcmp(options, cfga_str(OPT_ENABLE))) { + cfga_err(NULL, errstring, ERR_OPT_INVAL, options, 0); + return (rc); + } + } + + sc = &sysc_cmd; + str = cfga_str(CMD_SET_COND); + len = strlen(str); + + if ((strncmp(function, str, len) == 0) && (function[len++] == '=') && + ((cond = (str2cond(&function[len]))) != -1)) { + cmd = SYSC_CFGA_CMD_TEST_SET_COND; + err = CMD_SET_COND; + sc->arg = cond; + } else if (strcmp(function, cfga_str(CMD_QUIESCE)) == 0) { + cmd = SYSC_CFGA_CMD_QUIESCE_TEST; + err = CMD_QUIESCE; + } else if (strcmp(function, cfga_str(CMD_INSERT)) == 0) { + cmd = SYSC_CFGA_CMD_TEST; + err = CMD_INSERT; + } else if (strcmp(function, cfga_str(CMD_REMOVE)) == 0) { + cmd = SYSC_CFGA_CMD_TEST; + err = CMD_REMOVE; + } else { + cfga_err(NULL, errstring, ERR_CMD_INVAL, (char *)function, 0); + return (rc); + } + + sysc_cmd_init(sc, outputstr, 0); + + if ((idx = ap_idx(ap_id)) == -1) + cfga_err(NULL, errstring, ERR_AP_INVAL, ap_id, 0); + else if (((fd = open(ap_id, O_RDWR, 0)) == -1) || + (ioctl(fd, cmd, sc) == -1)) + cfga_err(NULL, errstring, err, 0); + else + rc = CFGA_OK; + + if (options) { + opterr = (dlist_find(idx, &dlist, &disabled) || + dlist_update(idx, disable, dlist, msgp, verbose)); + if (opterr) { + err = disable ? OPT_DISABLE : OPT_ENABLE; + if (verbose) + cfga_msg(msgp, err, opterr, 0); + } + } + + (void) close(fd); + return (rc); +} + + +/*ARGSUSED*/ +cfga_err_t +cfga_test( + const char *ap_id, + const char *options, + struct cfga_msg *msgp, + char **errstring, + cfga_flags_t flags) +{ + if (errstring != NULL) + *errstring = NULL; + + return (CFGA_OPNOTSUPP); +} + +static cfga_stat_t +rstate_cvt(sysc_cfga_rstate_t rs) +{ + cfga_stat_t cs; + + switch (rs) { + case SYSC_CFGA_RSTATE_EMPTY: + cs = CFGA_STAT_EMPTY; + break; + case SYSC_CFGA_RSTATE_DISCONNECTED: + cs = CFGA_STAT_DISCONNECTED; + break; + case SYSC_CFGA_RSTATE_CONNECTED: + cs = CFGA_STAT_CONNECTED; + break; + default: + cs = CFGA_STAT_NONE; + break; + } + + return (cs); +} + +static cfga_stat_t +ostate_cvt(sysc_cfga_ostate_t os) +{ + cfga_stat_t cs; + + switch (os) { + case SYSC_CFGA_OSTATE_UNCONFIGURED: + cs = CFGA_STAT_UNCONFIGURED; + break; + case SYSC_CFGA_OSTATE_CONFIGURED: + cs = CFGA_STAT_CONFIGURED; + break; + default: + cs = CFGA_STAT_NONE; + break; + } + + return (cs); +} + +static cfga_cond_t +cond_cvt(sysc_cfga_cond_t sc) +{ + cfga_cond_t cc; + + switch (sc) { + case SYSC_CFGA_COND_OK: + cc = CFGA_COND_OK; + break; + case SYSC_CFGA_COND_FAILING: + cc = CFGA_COND_FAILING; + break; + case SYSC_CFGA_COND_FAILED: + cc = CFGA_COND_FAILED; + break; + case SYSC_CFGA_COND_UNUSABLE: + cc = CFGA_COND_UNUSABLE; + break; + case SYSC_CFGA_COND_UNKNOWN: + default: + cc = CFGA_COND_UNKNOWN; + break; + } + + return (cc); +} + +static char * +type_str(enum board_type type) +{ + char *type_str; + + switch (type) { + case MEM_BOARD: + type_str = cfga_str(BD_MEM); + break; + case CPU_BOARD: + type_str = cfga_str(BD_CPU); + break; + case IO_2SBUS_BOARD: + type_str = cfga_str(BD_IO_2SBUS); + break; + case IO_SBUS_FFB_BOARD: + type_str = cfga_str(BD_IO_SBUS_FFB); + break; + case IO_PCI_BOARD: + type_str = cfga_str(BD_IO_PCI); + break; + case DISK_BOARD: + type_str = cfga_str(BD_DISK); + break; + case IO_2SBUS_SOCPLUS_BOARD: + type_str = cfga_str(BD_IO_2SBUS_SOCPLUS); + break; + case IO_SBUS_FFB_SOCPLUS_BOARD: + type_str = cfga_str(BD_IO_SBUS_FFB_SOCPLUS); + break; + case UNKNOWN_BOARD: + default: + type_str = cfga_str(BD_UNKNOWN); + break; + } + return (type_str); +} + +static void +info_set(sysc_cfga_stat_t *sc, cfga_info_t info, int disabled) +{ + int i; + struct cpu_info *cpu; + union bd_un *bd = &sc->bd; + + *info = NULL; + + switch (sc->type) { + case CPU_BOARD: + for (i = 0, cpu = bd->cpu; i < 2; i++, cpu++) { + if (cpu->cpu_speed > 1) { + info += sprintf(info, "cpu %d: ", i); + info += sprintf(info, "%3d MHz ", + cpu->cpu_speed); + if (cpu->cache_size) + info += sprintf(info, "%0.1fM ", + (float)cpu->cache_size / + (float)(1024 * 1024)); + } + } + break; + case IO_SBUS_FFB_BOARD: + switch (bd->io2.ffb_size) { + case FFB_SINGLE: + info += sprintf(info, "single buffered ffb "); + break; + case FFB_DOUBLE: + info += sprintf(info, "double buffered ffb "); + break; + case FFB_NOT_FOUND: +#ifdef FFB_DR_SUPPORT + info += sprintf(info, "no ffb installed "); +#endif + break; + default: + info += sprintf(info, "illegal ffb size "); + break; + } + break; + case DISK_BOARD: + for (i = 0; i < 2; i++) + if (bd->dsk.disk_pres[i]) + info += sprintf(info, "target: %2d ", + bd->dsk.disk_id[i]); + else + info += sprintf(info, "no disk "); + break; + } + + if (disabled) + info += sprintf(info, "disabled at boot "); + + if (sc->no_detach) + info += sprintf(info, "non-detachable "); + + if (sc->plus_board) + info += sprintf(info, "100 MHz capable "); +} + +static void +sysc_cvt(sysc_cfga_stat_t *sc, cfga_stat_data_t *cs, int disabled) +{ + (void) strcpy(cs->ap_type, type_str(sc->type)); + cs->ap_r_state = rstate_cvt(sc->rstate); + cs->ap_o_state = ostate_cvt(sc->ostate); + cs->ap_cond = cond_cvt(sc->condition); + cs->ap_busy = (cfga_busy_t)sc->in_transition; + cs->ap_status_time = sc->last_change; + info_set(sc, cs->ap_info, disabled); + cs->ap_log_id[0] = NULL; + cs->ap_phys_id[0] = NULL; +} + +/*ARGSUSED*/ +cfga_err_t +cfga_list( + const char *ap_id, + cfga_stat_data_t **ap_list, + int *nlist, + const char *options, + char **errstring) +{ + int i; + cfga_err_t rc; + sysc_cfga_stat_t *sc; + cfga_stat_data_t *cs; + + if (errstring != NULL) + *errstring = NULL; + + rc = CFGA_ERROR; + + if (ap_idx(ap_id) == -1) + cfga_err(NULL, errstring, ERR_AP_INVAL, ap_id, 0); + else if ((sc = sysc_stat(ap_id, NULL)) == NULL) + cfga_err(NULL, errstring, CMD_LIST, 0); + else if (!(cs = (cfga_stat_data_t *)malloc(MAX_BOARDS * sizeof (*cs)))) + cfga_err(NULL, errstring, CMD_LIST, 0); + else { + *ap_list = cs; + + for (*nlist = 0, i = 0; i < MAX_BOARDS; i++, sc++) { + if (sc->board == -1) + continue; + sysc_cvt(sc, cs++, 0); /* XXX - disable */ + (*nlist)++; + } + + rc = CFGA_OK; + } + + return (rc); +} + +/*ARGSUSED*/ +cfga_err_t +cfga_stat( + const char *ap_id, + struct cfga_stat_data *cs, + const char *options, + char **errstring) +{ + cfga_err_t rc; + int idx; + int err; + int opterr; + int disable; + int disabled; + char *dlist; + sysc_cfga_stat_t *sc; + + if (errstring != NULL) + *errstring = NULL; + + rc = CFGA_ERROR; + + if (options && options[0]) { + disable = 0; + if (strcmp(options, cfga_str(OPT_DISABLE)) == 0) + disable++; + else if (strcmp(options, cfga_str(OPT_ENABLE))) { + cfga_err(NULL, errstring, ERR_OPT_INVAL, options, 0); + return (rc); + } + } + + if ((idx = ap_idx(ap_id)) == -1) + cfga_err(NULL, errstring, ERR_AP_INVAL, ap_id, 0); + else if ((sc = sysc_stat(ap_id, NULL)) == NULL) + cfga_err(NULL, errstring, CMD_GETSTAT, 0); + else { + opterr = dlist_find(idx, &dlist, &disabled); + sysc_cvt(sc + idx, cs, disabled); + + rc = CFGA_OK; + + if (options && options[0] && ((opterr != 0) || + ((opterr = dlist_update(idx, disable, dlist, NULL, 0)) + != 0))) { + err = disable ? OPT_DISABLE : OPT_ENABLE; + cfga_err(NULL, errstring, err, opterr, 0); + } + } + + return (rc); +} + +/*ARGSUSED*/ +cfga_err_t +cfga_help(struct cfga_msg *msgp, const char *options, cfga_flags_t flags) +{ + int help = 0; + + if (options) { + if (strcmp(options, cfga_str(OPT_DISABLE)) == 0) + help = HELP_DISABLE; + else if (strcmp(options, cfga_str(OPT_ENABLE)) == 0) + help = HELP_ENABLE; + else if (strcmp(options, cfga_str(CMD_INSERT)) == 0) + help = HELP_INSERT; + else if (strcmp(options, cfga_str(CMD_REMOVE)) == 0) + help = HELP_REMOVE; + else if (strcmp(options, cfga_str(CMD_QUIESCE)) == 0) + help = HELP_QUIESCE; + else + help = HELP_UNKNOWN; + } + + if (help) { + if (help == HELP_UNKNOWN) + cfga_msg(msgp, help, options, 0); + else + cfga_msg(msgp, help, 0); + } else { + cfga_msg(msgp, HELP_HEADER, 0); + cfga_msg(msgp, HELP_DISABLE, 0); + cfga_msg(msgp, HELP_ENABLE, 0); + cfga_msg(msgp, HELP_INSERT, 0); + cfga_msg(msgp, HELP_REMOVE, 0); + cfga_msg(msgp, HELP_QUIESCE, 0); + cfga_msg(msgp, HELP_SET_COND, 0); + } + + return (CFGA_OK); +} + +/* + * cfga_ap_id_cmp -- use default_ap_id_cmp() in libcfgadm + */ diff --git a/usr/src/lib/cfgadm_plugins/sysctrl/common/mapfile-vers b/usr/src/lib/cfgadm_plugins/sysctrl/common/mapfile-vers new file mode 100644 index 0000000000..6d56c4331a --- /dev/null +++ b/usr/src/lib/cfgadm_plugins/sysctrl/common/mapfile-vers @@ -0,0 +1,38 @@ +# +#ident "%Z%%M% %I% %E% SMI" +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +SUNWprivate_1.1 { + global: + cfga_change_state; + cfga_private_func; + cfga_test; + cfga_stat; + cfga_list; + cfga_help; + local: + *; +}; diff --git a/usr/src/lib/cfgadm_plugins/sysctrl/sparc/Makefile b/usr/src/lib/cfgadm_plugins/sysctrl/sparc/Makefile new file mode 100644 index 0000000000..2be38997cb --- /dev/null +++ b/usr/src/lib/cfgadm_plugins/sysctrl/sparc/Makefile @@ -0,0 +1,34 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright (c) 1997-1998, by Sun Microsystems, Inc. +# All rights reserved. +# +#ident "%Z%%M% %I% %E% SMI" +# +# lib/sysctrl/sparc/Makefile + +include ../Makefile.com + +.KEEP_STATE: + +install: all $(ROOTLIBS) $(ROOTLINKS) diff --git a/usr/src/lib/cfgadm_plugins/sysctrl/sparcv9/Makefile b/usr/src/lib/cfgadm_plugins/sysctrl/sparcv9/Makefile new file mode 100644 index 0000000000..53a2dc875c --- /dev/null +++ b/usr/src/lib/cfgadm_plugins/sysctrl/sparcv9/Makefile @@ -0,0 +1,35 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" +# +# lib/sysctrl/sparcv9/Makefile + +include ../Makefile.com +include $(SRC)/lib/Makefile.lib.64 + +.KEEP_STATE: + +install: all $(ROOTLIBS64) $(ROOTLINKS64) diff --git a/usr/src/lib/cfgadm_plugins/sysctrl/sysctrl.xcl b/usr/src/lib/cfgadm_plugins/sysctrl/sysctrl.xcl new file mode 100644 index 0000000000..852c813749 --- /dev/null +++ b/usr/src/lib/cfgadm_plugins/sysctrl/sysctrl.xcl @@ -0,0 +1,94 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License, Version 1.0 only +# (the "License"). You may not use this file except in compliance +# with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +msgid "cpu/mem " +msgid "mem " +msgid "dual-sbus " +msgid "sbus-upa " +msgid "dual-pci " +msgid "disk " +msgid "soc+sbus " +msgid "soc+upa " +msgid "unknown " +msgid "get-status" +msgid "list" +msgid "connect" +msgid "disconnect" +msgid "configure" +msgid "unconfigure" +msgid "quiesce-test" +msgid "insert-test" +msgid "remove-test" +msgid "set-condition-test" +msgid "enable-at-boot" +msgid "disable-at-boot" +msgid "prom open" +msgid "prom getprop" +msgid "prom setprop" +msgid "[-f][-o enable-at-boot]" +msgid "\t-x quiesce-test ap_id [ap_id...]" +msgid "\t-x insert-test ap_id [ap_id...]" +msgid "\t-x remove-test ap_id [ap_id...]" +msgid "\t-x set-condition-test=<condition>" +msgid "\t-o enable-at-boot" +msgid "\t-o disable-at-boot" +msgid "unknown" +msgid "ok" +msgid "failing" +msgid "failed" +msgid "unusable" +msgid "<%s>" +msgid "\n" +msgid "cfga_sid(%d,%d)=%d\n" +msgid "errno=%d" +msgid "%s\n" +msgid "<%d>" +msgid "%s" +msgid "/tmp/cfga_simdata" +msgid "sim_open" +msgid "sim_stat" +msgid "sim_size" +msgid "sim_read" +msgid "sim_open(%s)\n" +msgid "/dev/openprom" +msgid "sim_ioctl(%d)\n" +msgid "sim_seek" +msgid "sim_write" +msgid "disabled-board-list" +msgid "getprop(%s, %d)\n" +msgid "prom_set_prop(%s)\n" +msgid "%x" +msgid "slot" +msgid "ap_idx(%s)\n" +msgid "ap_idx: s=%s, n=%d\n" +msgid "ap_idx(%s)=%d\n" +msgid "cpu %d: " +msgid "%3d MHz " +msgid "%0.1fM " +msgid "single buffered ffb " +msgid "double buffered ffb " +msgid "no ffb installed " +msgid "illegal ffb size " +msgid "target: %2d " +msgid "no disk " +msgid "disabled at boot " +msgid "non-detachable " +msgid "100 MHz capable " |