xref: /illumos-gate/usr/src/cmd/picl/plugins/sun4u/cherrystone/psvcplugin/psvcplugin.c (revision 45ede40b2394db7967e59f19288fae9b62efd4aa)
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 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * PICL Cherrystone platform plug-in to remove environment tree nodes
31  * if corresponding physical device is not present.  For creating
32  * the picltree nodes, see:
33  * usr/src/cmd/picl/plugins/sun4u/psvc/psvcplugin/psvcplugin.c
34  */
35 #define	_POSIX_PRIORITY_SCHEDULING 1
36 
37 #include <picl.h>
38 #include <picltree.h>
39 #include <stdio.h>
40 #include <time.h>
41 #include <fcntl.h>
42 #include <unistd.h>
43 #include <stdlib.h>
44 #include  <stdio.h>
45 #include  <libintl.h>
46 #include <limits.h>
47 #include  <ctype.h>
48 #include <errno.h>
49 #include <semaphore.h>
50 #include <syslog.h>
51 #include <string.h>
52 #include <sys/types.h>
53 #include <sys/systeminfo.h>
54 #include <psvc_objects.h>
55 
56 static psvc_opaque_t hdlp;
57 
58 #define	PSVC_PLUGIN_VERSION	PICLD_PLUGIN_VERSION_1
59 
60 #pragma init(psvc_psr_plugin_register)	/* place in .init section */
61 
62 typedef struct {
63 	char	name[32];
64 	picl_nodehdl_t  node;
65 } picl_psvc_t;
66 
67 extern struct handle {
68 	uint32_t	obj_count;
69 	picl_psvc_t *objects;
70 	FILE *fp;
71 } psvc_hdl;
72 
73 void psvc_psr_plugin_init(void);
74 void psvc_psr_plugin_fini(void);
75 
76 picld_plugin_reg_t psvc_psr_reg = {
77 	PSVC_PLUGIN_VERSION,
78 	PICLD_PLUGIN_CRITICAL,
79 	"PSVC_PSR",
80 	psvc_psr_plugin_init,
81 	psvc_psr_plugin_fini
82 };
83 
84 #define	PSVC_INIT_ERR		gettext("%s: Error in psvc_init(): %s\n")
85 #define	PTREE_DELETE_NODE_ERR	gettext("%s: ptree_delete_node() failed: %s\n")
86 #define	PTREE_GET_NODE_ERR			\
87 	gettext("%s: ptree_get_node_by_path() failed: %s\n")
88 
89 extern int ptree_get_node_by_path(const char *, picl_nodehdl_t *);
90 
91 /* ======================================== */
92 struct node_file {
93 	char	path[256];
94 	char	file[256];
95 } dev_pr_info[] = {
96 /* Search for memory */
97 {"/SYSTEM/MOTHERBOARD/CPU_0_2_MOD_SLOT/CPU_0_2_MOD_CARD/24C02_A0_0",
98 	"/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@0,a0:fru"},
99 {"/SYSTEM/MOTHERBOARD/CPU_0_2_MOD_SLOT/CPU_0_2_MOD_CARD/24C02_A2_0",
100 	"/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@0,a2:fru"},
101 {"/SYSTEM/MOTHERBOARD/CPU_0_2_MOD_SLOT/CPU_0_2_MOD_CARD/24C02_A4_0",
102 	"/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@0,a4:fru"},
103 {"/SYSTEM/MOTHERBOARD/CPU_0_2_MOD_SLOT/CPU_0_2_MOD_CARD/24C02_A6_0",
104 	"/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@0,a6:fru"},
105 {"/SYSTEM/MOTHERBOARD/CPU_0_2_MOD_SLOT/CPU_0_2_MOD_CARD/24C02_A8_0",
106 	"/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@0,a8:fru"},
107 {"/SYSTEM/MOTHERBOARD/CPU_0_2_MOD_SLOT/CPU_0_2_MOD_CARD/24C02_AA_0",
108 	"/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@0,aa:fru"},
109 {"/SYSTEM/MOTHERBOARD/CPU_0_2_MOD_SLOT/CPU_0_2_MOD_CARD/24C02_AC_0",
110 	"/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@0,ac:fru"},
111 {"/SYSTEM/MOTHERBOARD/CPU_0_2_MOD_SLOT/CPU_0_2_MOD_CARD/24C02_AE_0",
112 	"/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@0,ae:fru"},
113 {"/SYSTEM/MOTHERBOARD/CPU_1_3_MOD_SLOT/CPU_1_3_MOD_CARD/24C02_A0_1",
114 	"/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@1,a0:fru"},
115 {"/SYSTEM/MOTHERBOARD/CPU_1_3_MOD_SLOT/CPU_1_3_MOD_CARD/24C02_A2_1",
116 	"/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@1,a2:fru"},
117 {"/SYSTEM/MOTHERBOARD/CPU_1_3_MOD_SLOT/CPU_1_3_MOD_CARD/24C02_A4_1",
118 	"/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@1,a4:fru"},
119 {"/SYSTEM/MOTHERBOARD/CPU_1_3_MOD_SLOT/CPU_1_3_MOD_CARD/24C02_A6_1",
120 	"/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@1,a6:fru"},
121 {"/SYSTEM/MOTHERBOARD/CPU_1_3_MOD_SLOT/CPU_1_3_MOD_CARD/24C02_A8_1",
122 	"/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@1,a8:fru"},
123 {"/SYSTEM/MOTHERBOARD/CPU_1_3_MOD_SLOT/CPU_1_3_MOD_CARD/24C02_AA_1",
124 	"/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@1,aa:fru"},
125 {"/SYSTEM/MOTHERBOARD/CPU_1_3_MOD_SLOT/CPU_1_3_MOD_CARD/24C02_AC_1",
126 	"/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@1,ac:fru"},
127 {"/SYSTEM/MOTHERBOARD/CPU_1_3_MOD_SLOT/CPU_1_3_MOD_CARD/24C02_AE_1",
128 	"/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@1,ae:fru"},
129 {"/SYSTEM/MOTHERBOARD/CPU_0_2_MOD_SLOT/CPU_0_2_MOD_CARD/24C02_A0_2",
130 	"/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@2,a0:fru"},
131 {"/SYSTEM/MOTHERBOARD/CPU_0_2_MOD_SLOT/CPU_0_2_MOD_CARD/24C02_A2_2",
132 	"/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@2,a2:fru"},
133 {"/SYSTEM/MOTHERBOARD/CPU_0_2_MOD_SLOT/CPU_0_2_MOD_CARD/24C02_A4_2",
134 	"/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@2,a4:fru"},
135 {"/SYSTEM/MOTHERBOARD/CPU_0_2_MOD_SLOT/CPU_0_2_MOD_CARD/24C02_A6_2",
136 	"/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@2,a6:fru"},
137 {"/SYSTEM/MOTHERBOARD/CPU_0_2_MOD_SLOT/CPU_0_2_MOD_CARD/24C02_A8_2",
138 	"/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@2,a8:fru"},
139 {"/SYSTEM/MOTHERBOARD/CPU_0_2_MOD_SLOT/CPU_0_2_MOD_CARD/24C02_AA_2",
140 	"/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@2,aa:fru"},
141 {"/SYSTEM/MOTHERBOARD/CPU_0_2_MOD_SLOT/CPU_0_2_MOD_CARD/24C02_AC_2",
142 	"/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@2,ac:fru"},
143 {"/SYSTEM/MOTHERBOARD/CPU_0_2_MOD_SLOT/CPU_0_2_MOD_CARD/24C02_AE_2",
144 	"/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@2,ae:fru"},
145 {"/SYSTEM/MOTHERBOARD/CPU_1_3_MOD_SLOT/CPU_1_3_MOD_CARD/24C02_A0_3",
146 	"/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@3,a0:fru"},
147 {"/SYSTEM/MOTHERBOARD/CPU_1_3_MOD_SLOT/CPU_1_3_MOD_CARD/24C02_A2_3",
148 	"/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@3,a2:fru"},
149 {"/SYSTEM/MOTHERBOARD/CPU_1_3_MOD_SLOT/CPU_1_3_MOD_CARD/24C02_A4_3",
150 	"/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@3,a4:fru"},
151 {"/SYSTEM/MOTHERBOARD/CPU_1_3_MOD_SLOT/CPU_1_3_MOD_CARD/24C02_A6_3",
152 	"/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@3,a6:fru"},
153 {"/SYSTEM/MOTHERBOARD/CPU_1_3_MOD_SLOT/CPU_1_3_MOD_CARD/24C02_A8_3",
154 	"/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@3,a8:fru"},
155 {"/SYSTEM/MOTHERBOARD/CPU_1_3_MOD_SLOT/CPU_1_3_MOD_CARD/24C02_AA_3",
156 	"/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@3,aa:fru"},
157 {"/SYSTEM/MOTHERBOARD/CPU_1_3_MOD_SLOT/CPU_1_3_MOD_CARD/24C02_AC_3",
158 	"/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@3,ac:fru"},
159 {"/SYSTEM/MOTHERBOARD/CPU_1_3_MOD_SLOT/CPU_1_3_MOD_CARD/24C02_AE_3",
160 	"/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@3,ae:fru"},
161 /* Search for 64Kbit SPD */
162 {"/SYSTEM/MOTHERBOARD/CPU_0_2_MOD_SLOT/CPU_0_2_MOD_CARD/24C64_A0_4",
163 	"/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@4,a0:fru"},
164 {"/SYSTEM/MOTHERBOARD/CPU_1_3_MOD_SLOT/CPU_1_3_MOD_CARD/24C64_A2_4",
165 	"/devices/pci@9,700000/ebus@1/i2c@1,2e/fru@4,a2:fru"},
166 
167 /*
168  * Search for CPU Module cards.  We check one cpu's die temperature
169  * sensor If not present, then we remove the entire node since module
170  * cards come with two cpus in them, each cpu having a die temperature
171  * sensor
172  */
173 
174 {"/SYSTEM/MOTHERBOARD/CPU_0_2_MOD_SLOT/CPU_0_2_MOD_CARD",
175 	"/devices/pci@9,700000/ebus@1/i2c@1,30/temperature@0,30:die_temp"},
176 {"/SYSTEM/MOTHERBOARD/CPU_1_3_MOD_SLOT/CPU_1_3_MOD_CARD",
177 	"/devices/pci@9,700000/ebus@1/i2c@1,30/temperature@0,52:die_temp"},
178 {"/SYSTEM/SIB_BOARD",
179 	"/devices/pci@9,700000/ebus@1/i2c@1,30/temperature@0,98:die_temp"},
180 /*
181  * Check to see if RSC Card FRU is present.  If it is not present,
182  * then RSC Card is not present, and so we remove those nodes from
183  * picl tree as well.
184  */
185 {"/SYSTEM/RSC_SLOT/RSC_CARD/24C64_A6_5",
186 	"/devices/pci@9,700000/ebus@1/i2c@1,30/fru@0,a6:fru"},
187 {"/SYSTEM/RSC_SLOT/RSC_CARD",
188 	"/devices/pci@9,700000/ebus@1/i2c@1,30/fru@0,a6:fru"}
189 };
190 
191 #define	DEV_PR_COUNT (sizeof (dev_pr_info) / sizeof (struct node_file))
192 
193 static void init_err(char *fmt, char *arg1, char *arg2)
194 {
195 	char msg[256];
196 
197 	sprintf(msg, fmt, arg1, arg2);
198 	syslog(LOG_ERR, msg);
199 }
200 
201 void
202 psvc_psr_plugin_init(void)
203 {
204 	char *funcname = "psvc_plugin_psr_init";
205 	int32_t i;
206 	int err;
207 	boolean_t present;
208 	/*
209 	 * So the volatile read/write routines can retrieve data from
210 	 * psvc or picl
211 	 */
212 	err = psvc_init(&hdlp);
213 	if (err != 0) {
214 		init_err(PSVC_INIT_ERR, funcname, strerror(errno));
215 
216 	}
217 
218 	/*
219 	 * Remove nodes whose devices aren't present from the picl tree.
220 	 */
221 	for (i = 0; i < psvc_hdl.obj_count; ++i) {
222 		picl_psvc_t *objp;
223 		uint64_t features;
224 		objp = &psvc_hdl.objects[i];
225 
226 		err = psvc_get_attr(hdlp, objp->name, PSVC_PRESENCE_ATTR,
227 			&present);
228 		if (err != PSVC_SUCCESS)
229 			continue;
230 		err = psvc_get_attr(hdlp, objp->name, PSVC_FEATURES_ATTR,
231 			&features);
232 		if (err != PSVC_SUCCESS)
233 			continue;
234 		if ((features & (PSVC_DEV_HOTPLUG | PSVC_DEV_OPTION)) &&
235 			(present == PSVC_ABSENT)) {
236 			err = ptree_delete_node(objp->node);
237 			if (err != 0) {
238 				init_err(PTREE_DELETE_NODE_ERR, funcname,
239 					picl_strerror(err));
240 				return;
241 			}
242 		}
243 	}
244 
245 	/*
246 	 * Remove PICL device nodes if their /devices file isn't present or
247 	 * if the device file is present but the open returns ENXIO
248 	 * which indicates that the node file doesn't represent a device
249 	 * tree node and is probably a relic from some previous boot config
250 	 */
251 	for (i = 0; i < DEV_PR_COUNT; ++i) {
252 		picl_nodehdl_t	dev_pr_node;
253 		int fd;
254 		fd = open(dev_pr_info[i].file, O_RDONLY);
255 		if (fd != -1) {
256 			close(fd);
257 			continue;
258 		}
259 		if ((errno != ENOENT) && (errno != ENXIO))
260 			continue;
261 
262 		err = ptree_get_node_by_path(dev_pr_info[i].path, &dev_pr_node);
263 		if (err != 0) {
264 			syslog(LOG_ERR, "Bad path: %s", dev_pr_info[i].path);
265 			init_err(PTREE_GET_NODE_ERR, funcname,
266 				picl_strerror(err));
267 			return;
268 		}
269 
270 		err = ptree_delete_node(dev_pr_node);
271 		if (err != 0) {
272 			init_err(PTREE_DELETE_NODE_ERR, funcname,
273 				picl_strerror(err));
274 			return;
275 		}
276 	}
277 	free(psvc_hdl.objects);
278 }
279 
280 void
281 psvc_psr_plugin_fini(void)
282 {
283 	psvc_fini(hdlp);
284 	hdlp = NULL;
285 }
286 
287 void
288 psvc_psr_plugin_register(void)
289 {
290 	picld_plugin_register(&psvc_psr_reg);
291 }
292