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 Littleneck platform plug-in to create environment tree nodes.
31 */
32 #define _POSIX_PRIORITY_SCHEDULING 1
33
34 #include <picl.h>
35 #include <picltree.h>
36 #include <stdio.h>
37 #include <time.h>
38 #include <fcntl.h>
39 #include <unistd.h>
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <libintl.h>
43 #include <limits.h>
44 #include <ctype.h>
45 #include <errno.h>
46 #include <semaphore.h>
47 #include <syslog.h>
48 #include <string.h>
49 #include <sys/types.h>
50 #include <sys/systeminfo.h>
51 #include <psvc_objects.h>
52
53 static psvc_opaque_t hdlp;
54
55 #define PSVC_PLUGIN_VERSION PICLD_PLUGIN_VERSION_1
56
57 #pragma init(psvc_psr_plugin_register) /* place in .init section */
58
59 typedef struct {
60 char name[32];
61 picl_nodehdl_t node;
62 } picl_psvc_t;
63
64 extern struct handle {
65 uint32_t obj_count;
66 picl_psvc_t *objects;
67 FILE *fp;
68 } psvc_hdl;
69
70 void psvc_psr_plugin_init(void);
71 void psvc_psr_plugin_fini(void);
72
73 picld_plugin_reg_t psvc_psr_reg = {
74 PSVC_PLUGIN_VERSION,
75 PICLD_PLUGIN_CRITICAL,
76 "PSVC_PSR",
77 psvc_psr_plugin_init,
78 psvc_psr_plugin_fini
79 };
80
81 #define PSVC_INIT_ERR gettext("%s: Error in psvc_init(): %s\n")
82 #define PTREE_DELETE_NODE_ERR gettext("%s: ptree_delete_node() failed: %s\n")
83 #define PTREE_GET_NODE_ERR \
84 gettext("%s: ptree_get_node_by_path() failed: %s\n")
85
86 extern int ptree_get_node_by_path(const char *, picl_nodehdl_t *);
87
88 struct node_file {
89 char path[256];
90 char file[256];
91 } dev_pr_info[] = {
92 {"/SYSTEM/CPU0_MOD_CARD",
93 "/devices/pci@8,700000/ebus@5/i2c@1,30/temperature@0,30:die_temp"},
94 {"/SYSTEM/CPU1_MOD_CARD",
95 "/devices/pci@8,700000/ebus@5/i2c@1,30/temperature@0,98:die_temp"},
96 {"/SYSTEM/AT24C64_A0_1",
97 "/devices/pci@8,700000/ebus@5/i2c@1,2e/dimm@1,a0:dimm"},
98 {"/SYSTEM/AT24C64_A2_1",
99 "/devices/pci@8,700000/ebus@5/i2c@1,2e/dimm@1,a2:dimm"},
100 {"/SYSTEM/AT24C64_A4_1",
101 "/devices/pci@8,700000/ebus@5/i2c@1,2e/dimm@1,a4:dimm"},
102 {"/SYSTEM/AT24C64_A6_1",
103 "/devices/pci@8,700000/ebus@5/i2c@1,2e/dimm@1,a6:dimm"},
104 {"/SYSTEM/AT24C64_A8_1",
105 "/devices/pci@8,700000/ebus@5/i2c@1,2e/dimm@1,a8:dimm"},
106 {"/SYSTEM/AT24C64_AA_1",
107 "/devices/pci@8,700000/ebus@5/i2c@1,2e/dimm@1,aa:dimm"},
108 {"/SYSTEM/AT24C64_AC_1",
109 "/devices/pci@8,700000/ebus@5/i2c@1,2e/dimm@1,ac:dimm"},
110 {"/SYSTEM/AT24C64_AE_1",
111 "/devices/pci@8,700000/ebus@5/i2c@1,2e/dimm@1,ae:dimm"}
112 };
113 #define DEV_PR_COUNT (sizeof (dev_pr_info) / sizeof (struct node_file))
114
init_err(char * fmt,char * arg1,char * arg2)115 static void init_err(char *fmt, char *arg1, char *arg2)
116 {
117 char msg[256];
118
119 sprintf(msg, fmt, arg1, arg2);
120 syslog(LOG_ERR, msg);
121 }
122
123 void
psvc_psr_plugin_init(void)124 psvc_psr_plugin_init(void)
125 {
126 char *funcname = "psvc_plugin_init";
127 int32_t i;
128 int err;
129 boolean_t present;
130 /*
131 * So the volatile read/write routines can retrieve data from
132 * psvc or picl
133 */
134 err = psvc_init(&hdlp);
135 if (err != 0) {
136 init_err(PSVC_INIT_ERR, funcname, strerror(errno));
137
138 }
139
140 /*
141 * Remove nodes whose devices aren't present from the picl tree.
142 */
143 for (i = 0; i < psvc_hdl.obj_count; ++i) {
144 picl_psvc_t *objp;
145 uint64_t features;
146 objp = &psvc_hdl.objects[i];
147
148 err = psvc_get_attr(hdlp, objp->name, PSVC_PRESENCE_ATTR,
149 &present);
150 if (err != PSVC_SUCCESS)
151 continue;
152 err = psvc_get_attr(hdlp, objp->name, PSVC_FEATURES_ATTR,
153 &features);
154 if (err != PSVC_SUCCESS)
155 continue;
156 if ((features & (PSVC_DEV_HOTPLUG | PSVC_DEV_OPTION)) &&
157 (present == PSVC_ABSENT)) {
158 err = ptree_delete_node(objp->node);
159 if (err != 0) {
160 init_err(PTREE_DELETE_NODE_ERR, funcname,
161 picl_strerror(err));
162 return;
163 }
164 }
165 }
166
167 /*
168 * Remove PICL device nodes if their /devices file isn't present or
169 * if the device file is present but the open returns ENXIO
170 * which indicates that the node file doesn't represent a device
171 * tree node and is probably a relic from some previous boot config
172 */
173 for (i = 0; i < DEV_PR_COUNT; ++i) {
174 picl_nodehdl_t dev_pr_node;
175 int fd;
176 fd = open(dev_pr_info[i].file, O_RDONLY);
177 if (fd != -1) {
178 close(fd);
179 continue;
180 }
181 if ((errno != ENOENT) && (errno != ENXIO))
182 continue;
183
184 err = ptree_get_node_by_path(dev_pr_info[i].path, &dev_pr_node);
185 if (err != 0) {
186 init_err(PTREE_GET_NODE_ERR, funcname,
187 picl_strerror(err));
188 return;
189 }
190
191 err = ptree_delete_node(dev_pr_node);
192 if (err != 0) {
193 init_err(PTREE_DELETE_NODE_ERR, funcname,
194 picl_strerror(err));
195 return;
196 }
197 }
198 free(psvc_hdl.objects);
199 }
200
201 void
psvc_psr_plugin_fini(void)202 psvc_psr_plugin_fini(void)
203 {
204 psvc_fini(hdlp);
205 }
206
207 void
psvc_psr_plugin_register(void)208 psvc_psr_plugin_register(void)
209 {
210 picld_plugin_register(&psvc_psr_reg);
211 }
212