/*
* 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
* 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/spitregs.h>
#include <config_admin.h>
#include "mema_util.h"
#include "mema_test.h"
#include "mema_prom.h"
#ifdef DEBUG
#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.
*/
#endif /* ! P_DER_UE */
#define DEV_DEBUG
#ifdef DEV_DEBUG
#include <stdio.h>
#include <stdlib.h>
static int debugging(void);
static void dump_ioctl(int, void *);
static void dump_ioctl_res(int, void *, int, int);
#else /* DEV_DEBUG */
#endif /* DEV_DEBUG */
typedef struct {
} mema_bank_t;
static char *mema_opts[] = {
#define OPT_BOOT_DISABLE 0
"disable-at-boot",
"enable-at-boot",
"timeout",
};
/*
* 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.
*/
typedef struct {
unsigned int bits;
} option_set_t;
(S).val[(O)] = (V))
int *, char **);
{OPT_BOOT_ENABLE, 1},
{OPT_BOOT_DISABLE, 1},
{-1, 0}
};
{OPT_BOOT_ENABLE, 1},
{OPT_BOOT_DISABLE, 1},
{OPT_TIMEOUT, 2},
{-1, 0}
};
{OPT_BOOT_ENABLE, 1},
{OPT_BOOT_DISABLE, 1},
{-1, 0}
};
#if !defined(TEXT_DOMAIN)
#endif
"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\"";
"choose from: %s";
static const char test_opts[] =
"\t-o {quick, normal, extended},[max_errors=#] -t ap_id [ap_id...]\n";
static const char add_willbe_disabled[] =
"memory will be disabled at boot";
#define AC_BK_BUSY 0
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
{
if (acerr == AC_ERR_DEFAULT)
return (AC_UNKNOWN);
return (AC_MEM_PERM);
return (AC_BK_BUSY);
return (AC_KPM_CANCELLED);
return (AC_KPM_REFUSED);
return (AC_BK_ID);
return (AC_BD_ID);
return (AC_BD_TYPE);
return (AC_BD_STATE);
return (AC_MEM_TEST_ID);
return (AC_MEM_TEST_PAR);
return (AC_KPM_SPAN);
return (AC_KPM_DUP);
return (AC_KPM_FAULT);
return (AC_KPM_RESOURCE);
return (AC_KPM_NOTSUP);
return (AC_KPM_NOHANDLES);
return (AC_KPM_NONRELOC);
return (AC_KPM_HANDLE);
return (AC_KPM_BUSY);
return (AC_KPM_NOTVIABLE);
return (AC_KPM_SEQUENCE);
return (AC_KPM_NOWORK);
return (AC_KPM_NOTFINISHED);
return (AC_KPM_NOTRUNNING);
return (AC_VMEM);
return (AC_INTR);
return (AC_TIMEOUT);
return (AC_DEINTLV);
default:
break;
}
return (AC_UNKNOWN);
}
static void
{
char *syserr;
if (ac) {
} else {
/* strerror() does its own gettext(). */
syserr = syserr_num;
}
}
}
static void
{
}
static int
{
int id;
char *s;
return (-1);
else {
int n;
n = strlen(s);
DBG3("ap_bk_idx: s=%s, n=%d\n", s, n);
if ((n != 1) || !isdigit(s[0]))
return (-1);
}
return (-1);
return (id);
}
static cfga_err_t
const char *bank_spec,
int *fdp,
char **errstring)
{
int fd;
int bank;
return (CFGA_ERROR);
}
-1) {
char *syserr;
syserr = syserr_num;
}
return (CFGA_ERROR);
}
if (ret == -1) {
return (CFGA_ERROR);
}
if (fdp)
else
if (stp)
if (bkp) {
}
return (CFGA_OK);
}
static void
{
if (value == 0)
*dp &= ~PROM_MEMORY_DISABLED;
else
*dp |= PROM_MEMORY_DISABLED;
}
static void
{
*dp |= PROM_MEMORY_PRESENT;
else
*dp &= ~PROM_MEMORY_DISABLED;
}
static cfga_err_t
int board,
char **errstring)
{
return (CFGA_ERROR);
set_disabled_bits(&disab, 0);
if (!prom_viable_disabled_list(&disab)) {
ret = CFGA_ERROR;
ret = CFGA_ERROR;
}
if (!prom_viable_disabled_list(&disab)) {
ret = CFGA_ERROR;
ret = CFGA_ERROR;
}
}
return (ret);
}
static cfga_err_t
const char *bank_spec,
const char *options,
char **errstring,
int force)
{
ret = 0;
if (ret != 0) {
return (ret);
}
return (ret);
return (CFGA_ERROR);
}
if (!force) {
if (disab != 0 &&
return (CFGA_ERROR);
}
if (disab == 0 &&
return (CFGA_ERROR);
}
} else {
return (CFGA_ERROR);
}
}
if (ret == -1) {
return (CFGA_ERROR);
}
return (ret);
}
static cfga_err_t
const char *bank_spec,
const char *options,
char **errstring,
int force)
{
ret = 0;
if (ret != 0) {
return (ret);
}
char *to_val;
char *ep;
return (CFGA_ERROR);
}
}
return (ret);
return (CFGA_ERROR);
}
if (ret == -1) {
return (CFGA_ERROR);
}
return (ret);
}
/*ARGSUSED*/
const char *ap_id,
const char *options,
struct cfga_confirm *confp,
char **errstring,
{
int force;
switch (state_change_cmd) {
case CFGA_CMD_CONFIGURE:
break;
case CFGA_CMD_UNCONFIGURE:
break;
default:
rc = CFGA_OPNOTSUPP;
break;
}
return (rc);
}
/*ARGSUSED*/
const char *function,
const char *ap_id,
const char *options,
struct cfga_confirm *confp,
char **errstring,
{
return (ret);
(flags & CFGA_FLAG_FORCE));
if (ret == -1) {
return (CFGA_ERROR);
}
return (CFGA_OK);
}
return (CFGA_ERROR);
}
static int
int fd,
int test_fun,
char **errstring,
{
int res;
if (ret == -1) {
return (CFGA_OPNOTSUPP);
}
/*
* Bank appears to be being tested. Check that
* process 'tester_pid' is still running.
*/
/* Process still exists. */
return (CFGA_ERROR);
}
/*
* Do a test stop and re-try the start.
*/
sizeof (test_stop));
/*
* 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));
}
/* Test return code again to cover the case of a re-try. */
if (ret == -1) {
return (CFGA_ERROR);
}
}
/*
* Convert memory test code to MEMA_ code.
*/
switch (res) {
case MTEST_DONE:
break;
case MTEST_LIB_ERROR:
res = CFGA_ERROR;
break;
case MTEST_DEV_ERROR:
res = CFGA_ERROR;
break;
default:
res = CFGA_ERROR;
assert(0);
break;
}
case CFGA_COND_OK:
break;
case CFGA_COND_FAILING:
break;
case CFGA_COND_FAILED:
break;
case CFGA_COND_UNKNOWN:
break;
default:
assert(0);
break;
}
if (ret == -1) {
return (CFGA_ERROR);
}
return (res);
}
int
void *page_buf,
{
if (line_count == 0)
else
if (ret == -1)
return (-1);
return (0);
}
int
void *page_buf,
struct mtest_error *errp)
{
if (line_count == 0)
else
if (ret == -1) {
/*
* Special case indicating CE or UE.
*/
P_DER_UE) != 0)
else
} else {
return (-1);
}
} else {
}
return (0);
}
static char *
{
char *str;
const char *sep;
int len;
int i, n;
len = 0;
n = 0;
n++;
}
if (n == 0)
len++;
return (NULL);
*str = '\0';
sep = "";
}
return (str);
}
/*ARGSUSED*/
const char *ap_id,
const char *options,
char **errstring,
{
int maxerr_idx;
char *ret_p;
/*
* Decode test level and max error number.
*/
char **opts;
char *value;
int subopt;
/* getsubopt() modifies the input string, so copy it. */
return (CFGA_LIB_ERROR);
}
return (CFGA_LIB_ERROR);
}
while (*cp != '\0') {
if (subopt == -1) {
char *hlp;
} else {
}
/* Free after printing value. */
return (CFGA_ERROR);
}
subopt != maxerr_idx) {
return (CFGA_ERROR);
}
if (subopt < maxerr_idx)
else {
return (CFGA_ERROR);
}
0,
"");
return (CFGA_ERROR);
}
(max_errors < 0)) {
value);
return (CFGA_ERROR);
}
}
}
}
if (test_fun == -1)
if (max_errors == -1)
return (ret);
return (CFGA_ERROR);
}
return (ret);
}
static cfga_stat_t
{
switch (rs) {
case SYSC_CFGA_RSTATE_EMPTY:
break;
break;
break;
default:
cs = CFGA_STAT_NONE;
break;
}
return (cs);
}
static cfga_stat_t
{
switch (os) {
break;
break;
default:
cs = CFGA_STAT_NONE;
break;
}
return (cs);
}
static cfga_cond_t
{
switch (sc) {
case SYSC_CFGA_COND_OK:
cc = CFGA_COND_OK;
break;
case SYSC_CFGA_COND_FAILING:
break;
case SYSC_CFGA_COND_FAILED:
break;
case SYSC_CFGA_COND_UNUSABLE:
break;
case SYSC_CFGA_COND_UNKNOWN:
default:
break;
}
return (cc);
}
static void
{
uint_t n;
char *f;
char *end;
/* Print the board number in a way that matches the sysctrl AP. */
return;
}
n /= 1024;
f = "Gb";
} else
f = "Mb";
n /= 1024;
f = "Gb";
} else
f = "Mb";
}
else
else
if (intlv != 1)
intlv);
if (disab != 0) {
}
}
}
static void
{
}
/*ARGSUSED*/
const char *ap_id,
struct cfga_stat_data *cs,
const char *options,
char **errstring)
{
int ret;
ret = 0;
if (ret != 0)
return (ret);
return (ret);
return (ret);
}
/*ARGSUSED*/
const char *ap_id,
int *nlist,
const char *options,
char **errstring)
{
return (CFGA_NOTSUPP);
}
/*
* cfga_ap_id_cmp -- use default_ap_id_cmp() in libcfgadm
*/
/*ARGSUSED*/
{
return (CFGA_OK);
}
#if 0
static ac_mem_version_t
get_version(int fd)
{
ver = 0;
return (ver);
}
#endif
static char *
{
char *str;
const char *sep;
int len;
int i, n;
len = 0;
n = 0;
n++;
}
if (n == 0)
len++;
return (NULL);
*str = '\0';
sep = "";
}
return (str);
}
static option_set_t
const char *options,
struct opt_control *opts,
int *retp,
char **errstring)
{
char *value;
int subopt;
int subopt_err;
int i;
int group;
int need_value;
return (opt_set);
}
if (optcopy_alloc == NULL) {
*retp = CFGA_LIB_ERROR;
return (opt_set);
}
subopt_err = 0;
if (subopt == -1) {
char *hlp;
subopt_err = 1;
break;
}
break;
}
}
char *hlp;
subopt_err = 1;
break;
}
subopt_err = 1;
break;
}
subopt_err = 1;
break;
}
/* Ignore repeated options. */
continue;
}
if (i == subopt)
continue;
break;
}
subopt_err = 1;
break;
}
}
}
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)
inited = 1;
return (0);
}
if (*ep == '\0')
else {
return (0);
}
return (1);
}
static void
int cmd,
void *arg)
{
if (!debugging())
return;
switch (cmd) {
case AC_MEM_CONFIGURE:
break;
case AC_MEM_UNCONFIGURE:
break;
case AC_MEM_TEST_START:
break;
case AC_MEM_TEST_STOP: {
}
break;
case AC_MEM_TEST_READ: {
"buf=%#p page=%#llx off=%#x count=%#x\n",
}
break;
case AC_MEM_TEST_WRITE: {
"buf=%#p page=%#llx off=%#x count=%#x\n",
}
break;
case AC_MEM_ADMIN_VER:
break;
case AC_MEM_STAT:
break;
case AC_MEM_EXERCISE: {
break;
}
default:
break;
}
}
static void
int cmd,
void *arg,
int ret,
int ret_errno)
{
if (!debugging())
return;
if (ret == -1) {
return;
} else {
}
switch (cmd) {
case AC_MEM_CONFIGURE:
case AC_MEM_UNCONFIGURE:
break;
case AC_MEM_TEST_START: {
"prev_condition=%d bank_size=%#llx "
"page_size=%#x line_size=%#x afar_base=%#llx\n",
}
break;
case AC_MEM_TEST_STOP:
break;
case AC_MEM_TEST_READ: {
"afar=%#llx udbh_error_reg=%#llx "
"udbl_error_reg=%#llx\n",
} else {
}
}
break;
case AC_MEM_TEST_WRITE:
break;
case AC_MEM_ADMIN_VER: {
}
break;
case AC_MEM_STAT: {
"condition=%u status_time=%#lx board=%u\n",
"busy=%u\n",
"phys_pages=%#llx managed=%#llx nonrelocatable=%#llx\n",
"decode0=%#llx decode1=%#llx\n",
}
break;
case AC_MEM_EXERCISE: {
case AC_MEMX_RELOCATE_ALL: {
" nopaget=%u nolock=%u isfree=%u reloc=%u"
" noreloc=%u\n",
}
break;
}
default:
break;
}
break;
}
default:
break;
}
}
#endif /* DEV_DEBUG */