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