/* * 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mema_prom.h" #include /* * 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); }