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
56static 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
62typedef struct {
63	char	name[32];
64	picl_nodehdl_t  node;
65} picl_psvc_t;
66
67extern struct handle {
68	uint32_t	obj_count;
69	picl_psvc_t *objects;
70	FILE *fp;
71} psvc_hdl;
72
73void psvc_psr_plugin_init(void);
74void psvc_psr_plugin_fini(void);
75
76picld_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
89extern int ptree_get_node_by_path(const char *, picl_nodehdl_t *);
90
91/* ======================================== */
92struct 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
193static 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
201void
202psvc_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
280void
281psvc_psr_plugin_fini(void)
282{
283	psvc_fini(hdlp);
284	hdlp = NULL;
285}
286
287void
288psvc_psr_plugin_register(void)
289{
290	picld_plugin_register(&psvc_psr_reg);
291}
292