xref: /illumos-gate/usr/src/lib/cfgadm_plugins/ac/common/mema_prom.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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))
62 typedef union {
63 	char buf[BUFSIZE];
64 	struct openpromio opp;
65 } Oppbuf;
66 #define	PROP_MEMORY_LIST	"disabled-memory-list"
67 
68 static int prom_read_one(mema_disabled_t *, int, int, char *, u_int);
69 static int prom_write_one(mema_disabled_t *, int, int, char *, u_int);
70 
71 int
72 prom_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 
88 int
89 prom_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 
104 static int
105 prom_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 
173 static int
174 prom_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*/
254 int
255 prom_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