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