2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License, Version 1.0 only
2N/A * (the "License"). You may not use this file except in compliance
2N/A * with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright (c) 1996-1998 by Sun Microsystems, Inc.
2N/A * All rights reserved.
2N/A */
2N/A
2N/A#pragma ident "%Z%%M% %I% %E% SMI"
2N/A
2N/A#include <stddef.h>
2N/A#include <stdlib.h>
2N/A#include <fcntl.h>
2N/A#include <unistd.h>
2N/A#include <string.h>
2N/A#include <errno.h>
2N/A#include <assert.h>
2N/A#include <sys/param.h>
2N/A#include <sys/obpdefs.h>
2N/A#include <sys/fhc.h>
2N/A#include <sys/ac.h>
2N/A#include <sys/sysctrl.h>
2N/A#include <sys/openpromio.h>
2N/A#include "mema_prom.h"
2N/A#include <config_admin.h>
2N/A
2N/A
2N/A/*
2N/A * PROM access routines to get and set disabled lists
2N/A * Based on code in the usr/src/cmd/eeprom directory.
2N/A */
2N/A#define PROMDEV "/dev/openprom"
2N/A/*
2N/A * 128 is the size of the largest (currently) property name
2N/A * 8192 - MAXPROPSIZE - sizeof (int) is the size of the largest
2N/A * (currently) property value, viz. nvramrc.
2N/A * the sizeof(u_int) is from struct openpromio
2N/A */
2N/A
2N/A#define MAXPROPSIZE 128
2N/A#define MAXNAMESIZE MAXPROPSIZE
2N/A#define MAXVALSIZE (8192 - MAXPROPSIZE - sizeof (u_int))
2N/A#define BUFSIZE (MAXPROPSIZE + MAXVALSIZE + sizeof (u_int))
2N/Atypedef union {
2N/A char buf[BUFSIZE];
2N/A struct openpromio opp;
2N/A} Oppbuf;
2N/A#define PROP_MEMORY_LIST "disabled-memory-list"
2N/A
2N/Astatic int prom_read_one(mema_disabled_t *, int, int, char *, u_int);
2N/Astatic int prom_write_one(mema_disabled_t *, int, int, char *, u_int);
2N/A
2N/Aint
2N/Aprom_read_disabled_list(mema_disabled_t *dp, int bd)
2N/A{
2N/A int prom_fd;
2N/A int ret;
2N/A
2N/A (void) memset((void *)dp, 0, sizeof (*dp));
2N/A prom_fd = open(PROMDEV, O_RDONLY);
2N/A if (prom_fd == -1) {
2N/A return (0);
2N/A }
2N/A ret = prom_read_one(dp, bd, prom_fd,
2N/A PROP_MEMORY_LIST, PROM_MEMORY_DISABLED);
2N/A (void) close(prom_fd);
2N/A return (ret);
2N/A}
2N/A
2N/Aint
2N/Aprom_write_disabled_list(mema_disabled_t *dp, int bd)
2N/A{
2N/A int prom_fd;
2N/A int ret;
2N/A
2N/A prom_fd = open(PROMDEV, O_RDWR);
2N/A if (prom_fd == -1) {
2N/A return (0);
2N/A }
2N/A ret = prom_write_one(dp, bd, prom_fd,
2N/A PROP_MEMORY_LIST, PROM_MEMORY_DISABLED);
2N/A (void) close(prom_fd);
2N/A return (ret);
2N/A}
2N/A
2N/Astatic int
2N/Aprom_read_one(
2N/A mema_disabled_t *dp,
2N/A int bd,
2N/A int prom_fd,
2N/A char *var,
2N/A u_int bit)
2N/A{
2N/A Oppbuf oppbuf;
2N/A struct openpromio *opp = &oppbuf.opp;
2N/A int ret;
2N/A
2N/A (void) memset((void *)&oppbuf, 0, sizeof (oppbuf));
2N/A (void) strncpy(opp->oprom_array, var, MAXNAMESIZE);
2N/A opp->oprom_size = MAXVALSIZE;
2N/A if (ioctl(prom_fd, OPROMGETOPT, opp) == -1) {
2N/A ret = 0;
2N/A } else
2N/A if (opp->oprom_size == 0) {
2N/A /* Not a failure - just not set to anything */
2N/A ret = 1;
2N/A } else {
2N/A char *cp;
2N/A int board;
2N/A
2N/A ret = 1;
2N/A for (cp = opp->oprom_array; *cp != '\0'; cp++) {
2N/A switch (*cp) {
2N/A case '0':
2N/A case '1':
2N/A case '2':
2N/A case '3':
2N/A case '4':
2N/A case '5':
2N/A case '6':
2N/A case '7':
2N/A case '8':
2N/A case '9':
2N/A board = *cp - '0';
2N/A break;
2N/A case 'a':
2N/A case 'b':
2N/A case 'c':
2N/A case 'd':
2N/A case 'e':
2N/A case 'f':
2N/A board = *cp - 'a' + 10;
2N/A break;
2N/A case 'A':
2N/A case 'B':
2N/A case 'C':
2N/A case 'D':
2N/A case 'E':
2N/A case 'F':
2N/A board = *cp - 'A' + 10;
2N/A break;
2N/A default:
2N/A /* Ignore bad characters. */
2N/A /* TODO: maybe should set ret to 0? */
2N/A board = -1;
2N/A break;
2N/A }
2N/A if (board == bd)
2N/A *dp |= bit;
2N/A }
2N/A }
2N/A return (ret);
2N/A}
2N/A
2N/Astatic int
2N/Aprom_write_one(
2N/A mema_disabled_t *dp,
2N/A int bd,
2N/A int prom_fd,
2N/A char *var,
2N/A u_int bit)
2N/A{
2N/A Oppbuf in_oppbuf;
2N/A struct openpromio *in_opp = &in_oppbuf.opp;
2N/A Oppbuf oppbuf;
2N/A struct openpromio *opp = &oppbuf.opp;
2N/A int ret;
2N/A char *cp;
2N/A
2N/A /* Setup output buffer. */
2N/A (void) memset((void *)&oppbuf, 0, sizeof (oppbuf));
2N/A (void) strncpy(opp->oprom_array, var, MAXNAMESIZE);
2N/A opp->oprom_size = strlen(var) + 1;
2N/A cp = opp->oprom_array + opp->oprom_size;
2N/A
2N/A /*
2N/A * First read the existing list, filtering out 'bd' if 'bit'
2N/A * not set.
2N/A */
2N/A (void) memset((void *)&in_oppbuf, 0, sizeof (in_oppbuf));
2N/A (void) strncpy(in_opp->oprom_array, var, MAXNAMESIZE);
2N/A in_opp->oprom_size = MAXVALSIZE;
2N/A if (ioctl(prom_fd, OPROMGETOPT, in_opp) != -1 &&
2N/A in_opp->oprom_size != 0) {
2N/A char *icp;
2N/A int board;
2N/A
2N/A for (icp = in_opp->oprom_array; *icp != '\0'; icp++) {
2N/A switch (*icp) {
2N/A case '0': case '1': case '2': case '3':
2N/A case '4': case '5': case '6': case '7':
2N/A case '8': case '9':
2N/A board = *icp - '0';
2N/A break;
2N/A case 'a': case 'b': case 'c':
2N/A case 'd': case 'e': case 'f':
2N/A board = *icp - 'a' + 10;
2N/A break;
2N/A case 'A': case 'B': case 'C':
2N/A case 'D': case 'E': case 'F':
2N/A board = *icp - 'A' + 10;
2N/A break;
2N/A default:
2N/A /* Ignore bad characters. */
2N/A continue;
2N/A }
2N/A /* If enabling this board ... */
2N/A if (board == bd && (*dp & bit) == 0)
2N/A continue;
2N/A *cp++ = "0123456789abcdef"[board];
2N/A opp->oprom_size++;
2N/A }
2N/A }
2N/A
2N/A if ((*dp & bit) != 0) {
2N/A *cp++ = "0123456789abcdef"[bd];
2N/A opp->oprom_size++;
2N/A }
2N/A if (ioctl(prom_fd, OPROMSETOPT, opp) == -1) {
2N/A ret = 0;
2N/A } else {
2N/A ret = 1;
2N/A }
2N/A
2N/A return (ret);
2N/A}
2N/A
2N/A/*
2N/A * The PROM only has board-level disable of memory. If two banks are present
2N/A * on the board, both are either enabled or disabled at boot.
2N/A * The caller of this routine must set the PROM_MEMORY_PRESENT bits
2N/A * before calling this function.
2N/A */
2N/A
2N/A/*ARGSUSED*/
2N/Aint
2N/Aprom_viable_disabled_list(mema_disabled_t *dp)
2N/A{
2N/A#ifdef XXX
2N/A int board;
2N/A
2N/A for (board = 0; board < MAX_BOARDS; board++) {
2N/A if ((dp->bank_A[board] & PROM_MEMORY_PRESENT) != 0 &&
2N/A (dp->bank_B[board] & PROM_MEMORY_PRESENT) != 0 &&
2N/A (dp->bank_A[board] & PROM_MEMORY_DISABLED) !=
2N/A (dp->bank_B[board] & PROM_MEMORY_DISABLED)) {
2N/A return (0);
2N/A }
2N/A }
2N/A#endif
2N/A return (1);
2N/A}