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