1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright (c) 1996-1998 by Sun Microsystems, Inc.
24 * All rights reserved.
25 */
26
27#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29#include <stddef.h>
30#include <stdlib.h>
31#include <fcntl.h>
32#include <unistd.h>
33#include <string.h>
34#include <errno.h>
35#include <assert.h>
36#include <sys/param.h>
37#include <sys/obpdefs.h>
38#include <sys/fhc.h>
39#include <sys/ac.h>
40#include <sys/sysctrl.h>
41#include <sys/openpromio.h>
42#include "mema_prom.h"
43#include <config_admin.h>
44
45
46/*
47 * PROM access routines to get and set disabled lists
48 * Based on code in the usr/src/cmd/eeprom directory.
49 */
50#define	PROMDEV		"/dev/openprom"
51/*
52 * 128 is the size of the largest (currently) property name
53 * 8192 - MAXPROPSIZE - sizeof (int) is the size of the largest
54 * (currently) property value, viz. nvramrc.
55 * the sizeof(u_int) is from struct openpromio
56 */
57
58#define	MAXPROPSIZE	128
59#define	MAXNAMESIZE	MAXPROPSIZE
60#define	MAXVALSIZE	(8192 - MAXPROPSIZE - sizeof (u_int))
61#define	BUFSIZE		(MAXPROPSIZE + MAXVALSIZE + sizeof (u_int))
62typedef union {
63	char buf[BUFSIZE];
64	struct openpromio opp;
65} Oppbuf;
66#define	PROP_MEMORY_LIST	"disabled-memory-list"
67
68static int prom_read_one(mema_disabled_t *, int, int, char *, u_int);
69static int prom_write_one(mema_disabled_t *, int, int, char *, u_int);
70
71int
72prom_read_disabled_list(mema_disabled_t *dp, int bd)
73{
74	int prom_fd;
75	int ret;
76
77	(void) memset((void *)dp, 0, sizeof (*dp));
78	prom_fd = open(PROMDEV, O_RDONLY);
79	if (prom_fd == -1) {
80		return (0);
81	}
82	ret = prom_read_one(dp, bd, prom_fd,
83	    PROP_MEMORY_LIST, PROM_MEMORY_DISABLED);
84	(void) close(prom_fd);
85	return (ret);
86}
87
88int
89prom_write_disabled_list(mema_disabled_t *dp, int bd)
90{
91	int prom_fd;
92	int ret;
93
94	prom_fd = open(PROMDEV, O_RDWR);
95	if (prom_fd == -1) {
96		return (0);
97	}
98	ret = prom_write_one(dp, bd, prom_fd,
99	    PROP_MEMORY_LIST, PROM_MEMORY_DISABLED);
100	(void) close(prom_fd);
101	return (ret);
102}
103
104static int
105prom_read_one(
106	mema_disabled_t *dp,
107	int bd,
108	int prom_fd,
109	char *var,
110	u_int bit)
111{
112	Oppbuf oppbuf;
113	struct openpromio *opp = &oppbuf.opp;
114	int ret;
115
116	(void) memset((void *)&oppbuf, 0, sizeof (oppbuf));
117	(void) strncpy(opp->oprom_array, var, MAXNAMESIZE);
118	opp->oprom_size = MAXVALSIZE;
119	if (ioctl(prom_fd, OPROMGETOPT, opp) == -1) {
120		ret = 0;
121	} else
122	if (opp->oprom_size == 0) {
123		/* Not a failure - just not set to anything */
124		ret = 1;
125	} else {
126		char *cp;
127		int board;
128
129		ret = 1;
130		for (cp = opp->oprom_array; *cp != '\0'; cp++) {
131			switch (*cp) {
132			case '0':
133			case '1':
134			case '2':
135			case '3':
136			case '4':
137			case '5':
138			case '6':
139			case '7':
140			case '8':
141			case '9':
142				board = *cp - '0';
143				break;
144			case 'a':
145			case 'b':
146			case 'c':
147			case 'd':
148			case 'e':
149			case 'f':
150				board = *cp - 'a' + 10;
151				break;
152			case 'A':
153			case 'B':
154			case 'C':
155			case 'D':
156			case 'E':
157			case 'F':
158				board = *cp - 'A' + 10;
159				break;
160			default:
161				/* Ignore bad characters. */
162				/* TODO: maybe should set ret to 0? */
163				board = -1;
164				break;
165			}
166			if (board == bd)
167				*dp |= bit;
168		}
169	}
170	return (ret);
171}
172
173static int
174prom_write_one(
175	mema_disabled_t *dp,
176	int bd,
177	int prom_fd,
178	char *var,
179	u_int bit)
180{
181	Oppbuf in_oppbuf;
182	struct openpromio *in_opp = &in_oppbuf.opp;
183	Oppbuf oppbuf;
184	struct openpromio *opp = &oppbuf.opp;
185	int ret;
186	char *cp;
187
188	/* Setup output buffer. */
189	(void) memset((void *)&oppbuf, 0, sizeof (oppbuf));
190	(void) strncpy(opp->oprom_array, var, MAXNAMESIZE);
191	opp->oprom_size = strlen(var) + 1;
192	cp = opp->oprom_array + opp->oprom_size;
193
194	/*
195	 * First read the existing list, filtering out 'bd' if 'bit'
196	 * not set.
197	 */
198	(void) memset((void *)&in_oppbuf, 0, sizeof (in_oppbuf));
199	(void) strncpy(in_opp->oprom_array, var, MAXNAMESIZE);
200	in_opp->oprom_size = MAXVALSIZE;
201	if (ioctl(prom_fd, OPROMGETOPT, in_opp) != -1 &&
202	    in_opp->oprom_size != 0) {
203		char *icp;
204		int board;
205
206		for (icp = in_opp->oprom_array; *icp != '\0'; icp++) {
207			switch (*icp) {
208			case '0': case '1': case '2': case '3':
209			case '4': case '5': case '6': case '7':
210			case '8': case '9':
211				board = *icp - '0';
212				break;
213			case 'a': case 'b': case 'c':
214			case 'd': case 'e': case 'f':
215				board = *icp - 'a' + 10;
216				break;
217			case 'A': case 'B': case 'C':
218			case 'D': case 'E': case 'F':
219				board = *icp - 'A' + 10;
220				break;
221			default:
222				/* Ignore bad characters. */
223				continue;
224			}
225			/* If enabling this board ... */
226			if (board == bd && (*dp & bit) == 0)
227				continue;
228			*cp++ = "0123456789abcdef"[board];
229			opp->oprom_size++;
230		}
231	}
232
233	if ((*dp & bit) != 0) {
234		*cp++ = "0123456789abcdef"[bd];
235		opp->oprom_size++;
236	}
237	if (ioctl(prom_fd, OPROMSETOPT, opp) == -1) {
238		ret = 0;
239	} else {
240		ret = 1;
241	}
242
243	return (ret);
244}
245
246/*
247 * The PROM only has board-level disable of memory.  If two banks are present
248 * on the board, both are either enabled or disabled at boot.
249 * The caller of this routine must set the PROM_MEMORY_PRESENT bits
250 * before calling this function.
251 */
252
253/*ARGSUSED*/
254int
255prom_viable_disabled_list(mema_disabled_t *dp)
256{
257#ifdef	XXX
258	int board;
259
260	for (board = 0; board < MAX_BOARDS; board++) {
261		if ((dp->bank_A[board] & PROM_MEMORY_PRESENT) != 0 &&
262		    (dp->bank_B[board] & PROM_MEMORY_PRESENT) != 0 &&
263		    (dp->bank_A[board] & PROM_MEMORY_DISABLED) !=
264		    (dp->bank_B[board] & PROM_MEMORY_DISABLED)) {
265			return (0);
266		}
267	}
268#endif
269	return (1);
270}
271