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