dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / picl / plugins / common / devtree / picldevtree.c
blobc0ad4dfb2349f551d85f858acc32e1f661dcf0f9
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * PICL plug-in that creates device tree nodes for all platforms
30 #include <stdio.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <limits.h>
34 #include <stdlib.h>
35 #include <assert.h>
36 #include <alloca.h>
37 #include <unistd.h>
38 #include <stropts.h>
39 #include <syslog.h>
40 #include <libdevinfo.h>
41 #include <sys/dkio.h>
42 #include <sys/vtoc.h>
43 #include <sys/time.h>
44 #include <fcntl.h>
45 #include <picl.h>
46 #include <picltree.h>
47 #include <sys/types.h>
48 #include <sys/processor.h>
49 #include <kstat.h>
50 #include <sys/sysinfo.h>
51 #include <dirent.h>
52 #include <libintl.h>
53 #include <pthread.h>
54 #include <libnvpair.h>
55 #include <sys/utsname.h>
56 #include <sys/systeminfo.h>
57 #include <sys/obpdefs.h>
58 #include <sys/openpromio.h>
59 #include "picldevtree.h"
62 * Plugin registration entry points
64 static void picldevtree_register(void);
65 static void picldevtree_init(void);
66 static void picldevtree_fini(void);
68 static void picldevtree_evhandler(const char *ename, const void *earg,
69 size_t size, void *cookie);
71 #pragma init(picldevtree_register)
74 * Log message texts
76 #define DEVINFO_PLUGIN_INIT_FAILED gettext("SUNW_picldevtree failed!\n")
77 #define PICL_EVENT_DROPPED \
78 gettext("SUNW_picldevtree '%s' event dropped.\n")
81 * Macro to get PCI device id (from IEEE 1275 spec)
83 #define PCI_DEVICE_ID(x) (((x) >> 11) & 0x1f)
85 * Local variables
87 static picld_plugin_reg_t my_reg_info = {
88 PICLD_PLUGIN_VERSION_1,
89 PICLD_PLUGIN_CRITICAL,
90 "SUNW_picldevtree",
91 picldevtree_init,
92 picldevtree_fini
96 * Debug enabling environment variable
98 #define SUNW_PICLDEVTREE_PLUGIN_DEBUG "SUNW_PICLDEVTREE_PLUGIN_DEBUG"
99 static int picldevtree_debug = 0;
101 static conf_entries_t *conf_name_class_map = NULL;
102 static builtin_map_t sun4u_map[] = {
103 /* MAX_NAMEVAL_SIZE */
104 { "SUNW,bpp", PICL_CLASS_PARALLEL},
105 { "parallel", PICL_CLASS_PARALLEL},
106 { "floppy", PICL_CLASS_FLOPPY},
107 { "memory", PICL_CLASS_MEMORY},
108 { "ebus", PICL_CLASS_EBUS},
109 { "i2c", PICL_CLASS_I2C},
110 { "usb", PICL_CLASS_USB},
111 { "isa", PICL_CLASS_ISA},
112 { "dma", PICL_CLASS_DMA},
113 { "keyboard", PICL_CLASS_KEYBOARD},
114 { "mouse", PICL_CLASS_MOUSE},
115 { "fan-control", PICL_CLASS_FAN_CONTROL},
116 { "sc", PICL_CLASS_SYSTEM_CONTROLLER},
117 { "dimm", PICL_CLASS_SEEPROM},
118 { "dimm-fru", PICL_CLASS_SEEPROM},
119 { "cpu", PICL_CLASS_SEEPROM},
120 { "cpu-fru", PICL_CLASS_SEEPROM},
121 { "flashprom", PICL_CLASS_FLASHPROM},
122 { "temperature", PICL_CLASS_TEMPERATURE_DEVICE},
123 { "motherboard", PICL_CLASS_SEEPROM},
124 { "motherboard-fru", PICL_CLASS_SEEPROM},
125 { "motherboard-fru-prom", PICL_CLASS_SEEPROM},
126 { "pmu", PICL_CLASS_PMU},
127 { "sound", PICL_CLASS_SOUND},
128 { "firewire", PICL_CLASS_FIREWIRE},
129 { "i2c-at34c02", PICL_CLASS_SEEPROM},
130 { "hardware-monitor", PICL_CLASS_HARDWARE_MONITOR},
131 { "", ""}
133 static builtin_map_t i86pc_map[] = {
134 /* MAX_NAMEVAL_SIZE */
135 { "cpus", PICL_CLASS_I86CPUS},
136 { "cpu", PICL_CLASS_CPU},
137 { "memory", PICL_CLASS_MEMORY},
138 { "asy", PICL_CLASS_SERIAL},
139 { "", ""}
141 static pname_type_map_t pname_type_map[] = {
142 { "reg", PICL_PTYPE_BYTEARRAY},
143 { "device_type", PICL_PTYPE_CHARSTRING},
144 { "ranges", PICL_PTYPE_BYTEARRAY},
145 { "status", PICL_PTYPE_CHARSTRING},
146 { "compatible", PICL_PTYPE_CHARSTRING},
147 { "interrupts", PICL_PTYPE_BYTEARRAY},
148 { "model", PICL_PTYPE_CHARSTRING},
149 { "address", PICL_PTYPE_BYTEARRAY},
150 { "vendor-id", PICL_PTYPE_UNSIGNED_INT},
151 { "device-id", PICL_PTYPE_UNSIGNED_INT},
152 { "revision-id", PICL_PTYPE_UNSIGNED_INT},
153 { "class-code", PICL_PTYPE_UNSIGNED_INT},
154 { "min-grant", PICL_PTYPE_UNSIGNED_INT},
155 { "max-latency", PICL_PTYPE_UNSIGNED_INT},
156 { "devsel-speed", PICL_PTYPE_UNSIGNED_INT},
157 { "subsystem-id", PICL_PTYPE_UNSIGNED_INT},
158 { "subsystem-vendor-id", PICL_PTYPE_UNSIGNED_INT},
159 { "assigned-addresses", PICL_PTYPE_BYTEARRAY},
160 { "configuration#", PICL_PTYPE_UNSIGNED_INT},
161 { "assigned-address", PICL_PTYPE_UNSIGNED_INT},
162 { "#address-cells", PICL_PTYPE_UNSIGNED_INT},
163 { "#size-cells", PICL_PTYPE_UNSIGNED_INT},
164 { "clock-frequency", PICL_PTYPE_UNSIGNED_INT},
165 { "scsi-initiator-id", PICL_PTYPE_UNSIGNED_INT},
166 { "differential", PICL_PTYPE_UNSIGNED_INT},
167 { "idprom", PICL_PTYPE_BYTEARRAY},
168 { "bus-range", PICL_PTYPE_BYTEARRAY},
169 { "alternate-reg", PICL_PTYPE_BYTEARRAY},
170 { "power-consumption", PICL_PTYPE_BYTEARRAY},
171 { "slot-names", PICL_PTYPE_BYTEARRAY},
172 { "burst-sizes", PICL_PTYPE_UNSIGNED_INT},
173 { "up-burst-sizes", PICL_PTYPE_UNSIGNED_INT},
174 { "slot-address-bits", PICL_PTYPE_UNSIGNED_INT},
175 { "eisa-slots", PICL_PTYPE_BYTEARRAY},
176 { "dma", PICL_PTYPE_BYTEARRAY},
177 { "slot-names-index", PICL_PTYPE_UNSIGNED_INT},
178 { "pnp-csn", PICL_PTYPE_UNSIGNED_INT},
179 { "pnp-data", PICL_PTYPE_BYTEARRAY},
180 { "description", PICL_PTYPE_CHARSTRING},
181 { "pnp-id", PICL_PTYPE_CHARSTRING},
182 { "max-frame-size", PICL_PTYPE_UNSIGNED_INT},
183 { "address-bits", PICL_PTYPE_UNSIGNED_INT},
184 { "local-mac-address", PICL_PTYPE_BYTEARRAY},
185 { "mac-address", PICL_PTYPE_BYTEARRAY},
186 { "character-set", PICL_PTYPE_CHARSTRING},
187 { "available", PICL_PTYPE_BYTEARRAY},
188 { "port-wwn", PICL_PTYPE_BYTEARRAY},
189 { "node-wwn", PICL_PTYPE_BYTEARRAY},
190 { "width", PICL_PTYPE_UNSIGNED_INT},
191 { "linebytes", PICL_PTYPE_UNSIGNED_INT},
192 { "height", PICL_PTYPE_UNSIGNED_INT},
193 { "banner-name", PICL_PTYPE_CHARSTRING},
194 { "reset-reason", PICL_PTYPE_CHARSTRING},
195 { "implementation#", PICL_PTYPE_UNSIGNED_INT},
196 { "version#", PICL_PTYPE_UNSIGNED_INT},
197 { "icache-size", PICL_PTYPE_UNSIGNED_INT},
198 { "icache-line-size", PICL_PTYPE_UNSIGNED_INT},
199 { "icache-associativity", PICL_PTYPE_UNSIGNED_INT},
200 { "l1-icache-size", PICL_PTYPE_UNSIGNED_INT},
201 { "l1-icache-line-size", PICL_PTYPE_UNSIGNED_INT},
202 { "l1-icache-associativity", PICL_PTYPE_UNSIGNED_INT},
203 { "#itlb-entries", PICL_PTYPE_UNSIGNED_INT},
204 { "dcache-size", PICL_PTYPE_UNSIGNED_INT},
205 { "dcache-line-size", PICL_PTYPE_UNSIGNED_INT},
206 { "dcache-associativity", PICL_PTYPE_UNSIGNED_INT},
207 { "l1-dcache-size", PICL_PTYPE_UNSIGNED_INT},
208 { "l1-dcache-line-size", PICL_PTYPE_UNSIGNED_INT},
209 { "l1-dcache-associativity", PICL_PTYPE_UNSIGNED_INT},
210 { "#dtlb-entries", PICL_PTYPE_UNSIGNED_INT},
211 { "ecache-size", PICL_PTYPE_UNSIGNED_INT},
212 { "ecache-line-size", PICL_PTYPE_UNSIGNED_INT},
213 { "ecache-associativity", PICL_PTYPE_UNSIGNED_INT},
214 { "l2-cache-size", PICL_PTYPE_UNSIGNED_INT},
215 { "l2-cache-line-size", PICL_PTYPE_UNSIGNED_INT},
216 { "l2-cache-associativity", PICL_PTYPE_UNSIGNED_INT},
217 { "l2-cache-sharing", PICL_PTYPE_BYTEARRAY},
218 { "mask#", PICL_PTYPE_UNSIGNED_INT},
219 { "manufacturer#", PICL_PTYPE_UNSIGNED_INT},
220 { "sparc-version", PICL_PTYPE_UNSIGNED_INT},
221 { "version", PICL_PTYPE_CHARSTRING},
222 { "cpu-model", PICL_PTYPE_UNSIGNED_INT},
223 { "memory-layout", PICL_PTYPE_BYTEARRAY},
224 { "#interrupt-cells", PICL_PTYPE_UNSIGNED_INT},
225 { "interrupt-map", PICL_PTYPE_BYTEARRAY},
226 { "interrupt-map-mask", PICL_PTYPE_BYTEARRAY}
229 #define PNAME_MAP_SIZE sizeof (pname_type_map) / sizeof (pname_type_map_t)
231 static builtin_map_t *builtin_map_ptr = NULL;
232 static int builtin_map_size = 0;
233 static char mach_name[SYS_NMLN];
234 static di_prom_handle_t ph = DI_PROM_HANDLE_NIL;
235 static int snapshot_stale;
238 * UnitAddress mapping table
240 static unitaddr_func_t encode_default_unitaddr;
241 static unitaddr_func_t encode_optional_unitaddr;
242 static unitaddr_func_t encode_scsi_unitaddr;
243 static unitaddr_func_t encode_upa_unitaddr;
244 static unitaddr_func_t encode_gptwo_jbus_unitaddr;
245 static unitaddr_func_t encode_pci_unitaddr;
247 static unitaddr_map_t unitaddr_map_table[] = {
248 {PICL_CLASS_JBUS, encode_gptwo_jbus_unitaddr, 0},
249 {PICL_CLASS_GPTWO, encode_gptwo_jbus_unitaddr, 0},
250 {PICL_CLASS_PCI, encode_pci_unitaddr, 0},
251 {PICL_CLASS_PCIEX, encode_pci_unitaddr, 0},
252 {PICL_CLASS_UPA, encode_upa_unitaddr, 0},
253 {PICL_CLASS_SCSI, encode_scsi_unitaddr, 0},
254 {PICL_CLASS_SCSI2, encode_scsi_unitaddr, 0},
255 {PICL_CLASS_EBUS, encode_default_unitaddr, 2},
256 {PICL_CLASS_SBUS, encode_default_unitaddr, 2},
257 {PICL_CLASS_I2C, encode_default_unitaddr, 2},
258 {PICL_CLASS_USB, encode_default_unitaddr, 1},
259 {PICL_CLASS_PMU, encode_optional_unitaddr, 2},
260 {NULL, encode_default_unitaddr, 0}
263 static int add_unitaddr_prop_to_subtree(picl_nodehdl_t nodeh);
264 static int get_unitaddr(picl_nodehdl_t parh, picl_nodehdl_t nodeh,
265 char *unitaddr, size_t ualen);
266 static void set_pci_pciex_deviceid(picl_nodehdl_t plafh);
269 * The mc event completion handler.
270 * The arguments are event name buffer and a packed nvlist buffer
271 * with the size specifying the size of unpacked nvlist. These
272 * buffers are deallcoated here.
274 * Also, if a memory controller node is being removed then destroy the
275 * PICL subtree associated with that memory controller.
277 static void
278 mc_completion_handler(char *ename, void *earg, size_t size)
280 picl_nodehdl_t mch;
281 nvlist_t *unpack_nvl;
283 if (strcmp(ename, PICLEVENT_MC_REMOVED) == 0 &&
284 nvlist_unpack(earg, size, &unpack_nvl, 0) == 0) {
285 mch = (uintptr_t)NULL;
286 (void) nvlist_lookup_uint64(unpack_nvl,
287 PICLEVENTARG_NODEHANDLE, &mch);
288 if (mch != (uintptr_t)NULL) {
289 if (picldevtree_debug)
290 syslog(LOG_INFO,
291 "picldevtree: destroying_node:%llx\n",
292 mch);
293 (void) ptree_destroy_node(mch);
295 nvlist_free(unpack_nvl);
298 free(ename);
299 free(earg);
303 * Functions to post memory controller change event
305 static int
306 post_mc_event(char *ename, picl_nodehdl_t mch)
308 nvlist_t *nvl;
309 size_t nvl_size;
310 char *pack_buf;
311 char *ev_name;
313 ev_name = strdup(ename);
314 if (ev_name == NULL)
315 return (-1);
317 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, 0)) {
318 free(ev_name);
319 return (-1);
322 pack_buf = NULL;
323 if (nvlist_add_uint64(nvl, PICLEVENTARG_NODEHANDLE, mch) ||
324 nvlist_pack(nvl, &pack_buf, &nvl_size, NV_ENCODE_NATIVE, 0)) {
325 free(ev_name);
326 nvlist_free(nvl);
327 return (-1);
330 if (picldevtree_debug)
331 syslog(LOG_INFO,
332 "picldevtree: posting MC event ename:%s nodeh:%llx\n",
333 ev_name, mch);
334 if (ptree_post_event(ev_name, pack_buf, nvl_size,
335 mc_completion_handler) != PICL_SUCCESS) {
336 free(ev_name);
337 nvlist_free(nvl);
338 return (-1);
340 nvlist_free(nvl);
341 return (0);
345 * Lookup a name in the name to class map tables
347 static int
348 lookup_name_class_map(char *classbuf, const char *nm)
350 conf_entries_t *ptr;
351 int i;
354 * check name to class mapping in conf file
356 ptr = conf_name_class_map;
358 while (ptr != NULL) {
359 if (strcmp(ptr->name, nm) == 0) {
360 (void) strlcpy(classbuf, ptr->piclclass,
361 PICL_CLASSNAMELEN_MAX);
362 return (0);
364 ptr = ptr->next;
368 * check name to class mapping in builtin table
370 if (builtin_map_ptr == NULL)
371 return (-1);
373 for (i = 0; i < builtin_map_size; ++i)
374 if (strcmp(builtin_map_ptr[i].name, nm) == 0) {
375 (void) strlcpy(classbuf, builtin_map_ptr[i].piclclass,
376 PICL_CLASSNAMELEN_MAX);
377 return (0);
379 return (-1);
383 * Lookup a prop name in the pname to class map table
385 static int
386 lookup_pname_type_map(const char *pname, picl_prop_type_t *type)
388 int i;
390 for (i = 0; i < PNAME_MAP_SIZE; ++i)
391 if (strcmp(pname_type_map[i].pname, pname) == 0) {
392 *type = pname_type_map[i].type;
393 return (0);
396 return (-1);
400 * Return the number of strings in the buffer
402 static int
403 get_string_count(char *strdat, int length)
405 int count;
406 char *lastnull;
407 char *nullptr;
409 count = 1;
410 for (lastnull = &strdat[length - 1], nullptr = strchr(strdat, '\0');
411 nullptr != lastnull; nullptr = strchr(nullptr+1, '\0'))
412 count++;
414 return (count);
418 * Return 1 if the node has a "reg" property
420 static int
421 has_reg_prop(di_node_t dn)
423 int *pdata;
424 int dret;
426 dret = di_prop_lookup_ints(DDI_DEV_T_ANY, dn, OBP_REG, &pdata);
427 if (dret > 0)
428 return (1);
430 if (!ph)
431 return (0);
432 dret = di_prom_prop_lookup_ints(ph, dn, OBP_REG, &pdata);
433 return (dret < 0 ? 0 : 1);
437 * This function copies a PROM node's device_type property value into the
438 * buffer given by outbuf. The buffer size is PICL_CLASSNAMELEN_MAX.
440 * We reclassify device_type 'fru-prom' to PICL class 'seeprom'
441 * for FRUID support.
443 static int
444 get_device_type(char *outbuf, di_node_t dn)
446 char *pdata;
447 char *pdatap;
448 int dret;
449 int i;
451 dret = di_prop_lookup_strings(DDI_DEV_T_ANY, dn, OBP_DEVICETYPE,
452 &pdata);
453 if (dret <= 0) {
454 if (!ph)
455 return (-1);
457 dret = di_prom_prop_lookup_strings(ph, dn, OBP_DEVICETYPE,
458 &pdata);
459 if (dret <= 0) {
460 return (-1);
464 if (dret != 1) {
466 * multiple strings
468 pdatap = pdata;
469 for (i = 0; i < (dret - 1); ++i) {
470 pdatap += strlen(pdatap);
471 *pdatap = '-'; /* replace '\0' with '-' */
472 pdatap++;
475 if (strcasecmp(pdata, "fru-prom") == 0) {
477 * Use PICL 'seeprom' class for fru-prom device types
479 (void) strlcpy(outbuf, PICL_CLASS_SEEPROM,
480 PICL_CLASSNAMELEN_MAX);
481 } else {
482 (void) strlcpy(outbuf, pdata, PICL_CLASSNAMELEN_MAX);
484 return (0);
488 * Get the minor node name in the class buffer passed
490 static int
491 get_minor_class(char *classbuf, di_node_t dn)
493 di_minor_t mi_node;
494 char *mi_nodetype;
495 char *mi_name;
497 /* get minor node type */
498 mi_node = di_minor_next(dn, DI_MINOR_NIL);
499 if (mi_node == DI_MINOR_NIL)
500 return (-1);
502 mi_nodetype = di_minor_nodetype(mi_node);
503 if (mi_nodetype == NULL) { /* no type info, return name */
504 mi_name = di_minor_name(mi_node);
505 if (mi_name == NULL)
506 return (-1);
507 (void) strlcpy(classbuf, mi_name, PICL_CLASSNAMELEN_MAX);
508 return (0);
511 #define DDI_NODETYPE(x, y) (strncmp(x, y, (sizeof (y) - 1)) == 0)
514 * convert the string to the picl class for non-peudo nodes
516 if (DDI_NODETYPE(mi_nodetype, DDI_PSEUDO))
517 return (-1);
518 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_BLOCK_WWN))
519 (void) strcpy(classbuf, PICL_CLASS_BLOCK);
520 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_BLOCK_CHAN))
521 (void) strcpy(classbuf, PICL_CLASS_BLOCK);
522 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_CD))
523 (void) strcpy(classbuf, PICL_CLASS_CDROM);
524 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_CD_CHAN))
525 (void) strcpy(classbuf, PICL_CLASS_CDROM);
526 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_FD))
527 (void) strcpy(classbuf, PICL_CLASS_FLOPPY);
528 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_BLOCK_FABRIC))
529 (void) strcpy(classbuf, PICL_CLASS_FABRIC);
530 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_BLOCK_SAS))
531 (void) strcpy(classbuf, PICL_CLASS_SAS);
532 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_BLOCK))
533 (void) strcpy(classbuf, PICL_CLASS_BLOCK);
534 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_MOUSE))
535 (void) strcpy(classbuf, PICL_CLASS_MOUSE);
536 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_KEYBOARD))
537 (void) strcpy(classbuf, PICL_CLASS_KEYBOARD);
538 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_ATTACHMENT_POINT))
539 (void) strcpy(classbuf, PICL_CLASS_ATTACHMENT_POINT);
540 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_TAPE))
541 (void) strcpy(classbuf, PICL_CLASS_TAPE);
542 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_SCSI_ENCLOSURE))
543 (void) strcpy(classbuf, PICL_CLASS_SCSI);
544 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_ENCLOSURE)) {
545 char *colon;
547 if ((colon = strchr(mi_nodetype, ':')) == NULL)
548 return (-1);
549 ++colon;
550 (void) strcpy(classbuf, colon);
551 } else { /* unrecognized type, return name */
552 mi_name = di_minor_name(mi_node);
553 if (mi_name == NULL)
554 return (-1);
555 (void) strlcpy(classbuf, mi_name, PICL_CLASSNAMELEN_MAX);
557 return (0);
561 * Derive PICL class using the compatible property of the node
562 * We use the map table to map compatible property value to
563 * class.
565 static int
566 get_compatible_class(char *outbuf, di_node_t dn)
568 char *pdata;
569 char *pdatap;
570 int dret;
571 int i;
573 dret = di_prop_lookup_strings(DDI_DEV_T_ANY, dn, OBP_COMPATIBLE,
574 &pdata);
575 if (dret <= 0) {
576 if (!ph)
577 return (-1);
579 dret = di_prom_prop_lookup_strings(ph, dn, OBP_COMPATIBLE,
580 &pdata);
581 if (dret <= 0) {
582 return (-1);
586 pdatap = pdata;
587 for (i = 0; i < dret; ++i) {
588 if (lookup_name_class_map(outbuf, pdatap) == 0)
589 return (0);
590 pdatap += strlen(pdatap);
591 pdatap++;
593 return (-1);
597 * For a given device node find the PICL class to use. Returns NULL
598 * for non device node
600 static int
601 get_node_class(char *classbuf, di_node_t dn, const char *nodename)
603 if (get_device_type(classbuf, dn) == 0) {
604 if (di_nodeid(dn) == DI_PROM_NODEID) {
606 * discard place holder nodes
608 if ((strcmp(classbuf, DEVICE_TYPE_BLOCK) == 0) ||
609 (strcmp(classbuf, DEVICE_TYPE_BYTE) == 0) ||
610 (strcmp(classbuf, DEVICE_TYPE_SES) == 0) ||
611 (strcmp(classbuf, DEVICE_TYPE_FP) == 0) ||
612 (strcmp(classbuf, DEVICE_TYPE_DISK) == 0))
613 return (-1);
615 return (0);
617 return (0); /* return device_type value */
620 if (get_compatible_class(classbuf, dn) == 0) {
621 return (0); /* derive class using compatible prop */
624 if (lookup_name_class_map(classbuf, nodename) == 0)
625 return (0); /* derive class using name prop */
627 if (has_reg_prop(dn)) { /* use default obp-device */
628 (void) strcpy(classbuf, PICL_CLASS_OBP_DEVICE);
629 return (0);
632 return (get_minor_class(classbuf, dn));
636 * Add a table property containing nrows with one column
638 static int
639 add_string_list_prop(picl_nodehdl_t nodeh, char *name, char *strlist,
640 unsigned int nrows)
642 ptree_propinfo_t propinfo;
643 picl_prophdl_t proph;
644 picl_prophdl_t tblh;
645 int err;
646 unsigned int i;
647 unsigned int j;
648 picl_prophdl_t *proprow;
649 int len;
651 #define NCOLS_IN_STRING_TABLE 1
653 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
654 PICL_PTYPE_TABLE, PICL_READ, sizeof (picl_prophdl_t), name,
655 NULL, NULL);
656 if (err != PICL_SUCCESS)
657 return (err);
659 err = ptree_create_table(&tblh);
660 if (err != PICL_SUCCESS)
661 return (err);
663 err = ptree_create_and_add_prop(nodeh, &propinfo, &tblh, &proph);
664 if (err != PICL_SUCCESS)
665 return (err);
667 proprow = alloca(sizeof (picl_prophdl_t) * nrows);
668 if (proprow == NULL) {
669 (void) ptree_destroy_prop(proph);
670 return (PICL_FAILURE);
673 for (j = 0; j < nrows; ++j) {
674 len = strlen(strlist) + 1;
675 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
676 PICL_PTYPE_CHARSTRING, PICL_READ, len, name,
677 NULL, NULL);
678 if (err != PICL_SUCCESS)
679 break;
680 err = ptree_create_prop(&propinfo, strlist, &proprow[j]);
681 if (err != PICL_SUCCESS)
682 break;
683 strlist += len;
684 err = ptree_add_row_to_table(tblh, NCOLS_IN_STRING_TABLE,
685 &proprow[j]);
686 if (err != PICL_SUCCESS)
687 break;
690 if (err != PICL_SUCCESS) {
691 for (i = 0; i < j; ++i)
692 (void) ptree_destroy_prop(proprow[i]);
693 (void) ptree_delete_prop(proph);
694 (void) ptree_destroy_prop(proph);
695 return (err);
698 return (PICL_SUCCESS);
702 * return 1 if this node has this property with the given value
704 static int
705 compare_string_propval(picl_nodehdl_t nodeh, const char *pname,
706 const char *pval)
708 char *pvalbuf;
709 int err;
710 int len;
711 ptree_propinfo_t pinfo;
712 picl_prophdl_t proph;
714 err = ptree_get_prop_by_name(nodeh, pname, &proph);
715 if (err != PICL_SUCCESS) /* prop doesn't exist */
716 return (0);
718 err = ptree_get_propinfo(proph, &pinfo);
719 if (pinfo.piclinfo.type != PICL_PTYPE_CHARSTRING)
720 return (0); /* not string prop */
722 len = strlen(pval) + 1;
724 pvalbuf = alloca(len);
725 if (pvalbuf == NULL)
726 return (0);
728 err = ptree_get_propval(proph, pvalbuf, len);
729 if ((err == PICL_SUCCESS) && (strcmp(pvalbuf, pval) == 0))
730 return (1); /* prop match */
732 return (0);
736 * This function recursively searches the tree for a node that has
737 * the specified string property name and value
739 static int
740 find_node_by_string_prop(picl_nodehdl_t rooth, const char *pname,
741 const char *pval, picl_nodehdl_t *nodeh)
743 picl_nodehdl_t childh;
744 int err;
746 for (err = ptree_get_propval_by_name(rooth, PICL_PROP_CHILD, &childh,
747 sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND;
748 err = ptree_get_propval_by_name(childh, PICL_PROP_PEER, &childh,
749 sizeof (picl_nodehdl_t))) {
750 if (err != PICL_SUCCESS)
751 return (err);
753 if (compare_string_propval(childh, pname, pval)) {
754 *nodeh = childh;
755 return (PICL_SUCCESS);
758 if (find_node_by_string_prop(childh, pname, pval, nodeh) ==
759 PICL_SUCCESS)
760 return (PICL_SUCCESS);
763 return (PICL_FAILURE);
767 * check if this is a string prop
768 * If the length is less than or equal to 4, assume it's not a string list.
769 * If there is any non-ascii or non-print char, it's not a string prop
770 * If \0 is in the first char or any two consecutive \0's exist,
771 * it's a bytearray prop.
772 * Return value: 0 means it's not a string prop, 1 means it's a string prop
774 static int
775 is_string_propval(unsigned char *pdata, int len)
777 int i;
778 int lastindex;
779 int prevnull = -1;
781 switch (len) {
782 case 1:
783 if (!isascii(pdata[0]) || !isprint(pdata[0]))
784 return (0);
785 return (1);
786 case 2:
787 case 3:
788 case 4:
789 lastindex = len;
790 if (pdata[len-1] == '\0')
791 lastindex = len - 1;
793 for (i = 0; i < lastindex; i++)
794 if (!isascii(pdata[i]) || !isprint(pdata[i]))
795 return (0);
797 return (1);
799 default:
800 if (len <= 0)
801 return (0);
802 for (i = 0; i < len; i++) {
803 if (!isascii(pdata[i]) || !isprint(pdata[i])) {
804 if (pdata[i] != '\0')
805 return (0);
807 * if the null char is in the first char
808 * or two consecutive nulls' exist,
809 * it's a bytearray prop
811 if ((i == 0) || ((i - prevnull) == 1))
812 return (0);
814 prevnull = i;
817 break;
820 return (1);
824 * This function counts the number of strings in the value buffer pdata
825 * and creates a property.
826 * If there is only one string in the buffer, pdata, a charstring property
827 * type is created and added.
828 * If there are more than one string in the buffer, pdata, then a table
829 * of charstrings is added.
831 static int
832 process_charstring_data(picl_nodehdl_t nodeh, char *pname, unsigned char *pdata,
833 int retval)
835 int err;
836 int strcount;
837 char *strdat;
838 ptree_propinfo_t propinfo;
841 * append the null char at the end of string when there is
842 * no null terminator
844 if (pdata[retval - 1] != '\0') {
845 strdat = alloca(retval + 1);
846 (void) memcpy(strdat, pdata, retval);
847 strdat[retval] = '\0';
848 retval++;
849 } else {
850 strdat = alloca(retval);
851 (void) memcpy(strdat, pdata, retval);
855 * If it's a string list, create a table prop
857 strcount = get_string_count(strdat, retval);
858 if (strcount > 1) {
859 err = add_string_list_prop(nodeh, pname,
860 strdat, strcount);
861 if (err != PICL_SUCCESS)
862 return (err);
863 } else {
864 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
865 PICL_PTYPE_CHARSTRING, PICL_READ,
866 strlen(strdat) + 1, pname, NULL,
867 NULL);
868 if (err != PICL_SUCCESS)
869 return (err);
870 (void) ptree_create_and_add_prop(nodeh, &propinfo,
871 strdat, NULL);
873 return (PICL_SUCCESS);
877 * Add the OBP properties as properties of the PICL node
879 static int
880 add_openprom_props(picl_nodehdl_t nodeh, di_node_t di_node)
882 di_prom_prop_t promp;
883 char *pname;
884 unsigned char *pdata;
885 int retval;
886 ptree_propinfo_t propinfo;
887 int err;
888 picl_prop_type_t type;
890 if (!ph)
891 return (PICL_FAILURE);
893 for (promp = di_prom_prop_next(ph, di_node, DI_PROM_PROP_NIL);
894 promp != DI_PROM_PROP_NIL;
895 promp = di_prom_prop_next(ph, di_node, promp)) {
897 pname = di_prom_prop_name(promp);
899 retval = di_prom_prop_data(promp, &pdata);
900 if (retval < 0) {
901 return (PICL_SUCCESS);
903 if (retval == 0) {
904 err = ptree_init_propinfo(&propinfo,
905 PTREE_PROPINFO_VERSION, PICL_PTYPE_VOID,
906 PICL_READ, (size_t)0, pname, NULL, NULL);
907 if (err != PICL_SUCCESS) {
908 return (err);
910 (void) ptree_create_and_add_prop(nodeh, &propinfo, NULL,
911 NULL);
912 continue;
916 * Get the prop type from pname map table
918 if (lookup_pname_type_map(pname, &type) == 0) {
919 if (type == PICL_PTYPE_CHARSTRING) {
920 err = process_charstring_data(nodeh, pname,
921 pdata, retval);
922 if (err != PICL_SUCCESS) {
923 return (err);
925 continue;
928 err = ptree_init_propinfo(&propinfo,
929 PTREE_PROPINFO_VERSION, type, PICL_READ,
930 retval, pname, NULL, NULL);
931 if (err != PICL_SUCCESS) {
932 return (err);
934 (void) ptree_create_and_add_prop(nodeh, &propinfo,
935 pdata, NULL);
936 } else if (!is_string_propval(pdata, retval)) {
937 switch (retval) {
938 case sizeof (uint8_t):
939 /*FALLTHROUGH*/
940 case sizeof (uint16_t):
941 /*FALLTHROUGH*/
942 case sizeof (uint32_t):
943 type = PICL_PTYPE_UNSIGNED_INT;
944 break;
945 default:
946 type = PICL_PTYPE_BYTEARRAY;
947 break;
949 err = ptree_init_propinfo(&propinfo,
950 PTREE_PROPINFO_VERSION, type, PICL_READ,
951 retval, pname, NULL, NULL);
952 if (err != PICL_SUCCESS) {
953 return (err);
955 (void) ptree_create_and_add_prop(nodeh, &propinfo,
956 pdata, NULL);
957 } else {
958 err = process_charstring_data(nodeh, pname, pdata,
959 retval);
960 if (err != PICL_SUCCESS) {
961 return (err);
966 return (PICL_SUCCESS);
969 static void
970 add_boolean_prop(picl_nodehdl_t nodeh, ptree_propinfo_t propinfo, char *di_val)
972 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
973 PICL_PTYPE_VOID, PICL_READ, (size_t)0, di_val, NULL, NULL);
974 (void) ptree_create_and_add_prop(nodeh, &propinfo, NULL, NULL);
977 static void
978 add_uints_prop(picl_nodehdl_t nodeh, ptree_propinfo_t propinfo, char *di_val,
979 int *idata, int len)
981 if (len == 1)
982 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
983 PICL_PTYPE_UNSIGNED_INT, PICL_READ, sizeof (int), di_val,
984 NULL, NULL);
985 else
986 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
987 PICL_PTYPE_BYTEARRAY, PICL_READ, len * sizeof (int), di_val,
988 NULL, NULL);
990 (void) ptree_create_and_add_prop(nodeh, &propinfo, idata, NULL);
993 static void
994 add_strings_prop(picl_nodehdl_t nodeh, ptree_propinfo_t propinfo, char *di_val,
995 char *sdata, int len)
997 if (len == 1) {
998 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
999 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(sdata) + 1, di_val,
1000 NULL, NULL);
1001 (void) ptree_create_and_add_prop(nodeh, &propinfo, sdata, NULL);
1002 } else {
1003 (void) add_string_list_prop(nodeh, di_val, sdata, len);
1007 static void
1008 add_bytes_prop(picl_nodehdl_t nodeh, ptree_propinfo_t propinfo, char *di_val,
1009 unsigned char *bdata, int len)
1011 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
1012 PICL_PTYPE_BYTEARRAY, PICL_READ, len, di_val, NULL, NULL);
1013 (void) ptree_create_and_add_prop(nodeh, &propinfo, bdata, NULL);
1016 static const char *
1017 path_state_name(di_path_state_t st)
1019 switch (st) {
1020 case DI_PATH_STATE_ONLINE:
1021 return ("online");
1022 case DI_PATH_STATE_STANDBY:
1023 return ("standby");
1024 case DI_PATH_STATE_OFFLINE:
1025 return ("offline");
1026 case DI_PATH_STATE_FAULT:
1027 return ("faulted");
1029 return ("unknown");
1033 * This function is the volatile property handler for the multipath node
1034 * "State" property. It must locate the associated devinfo node in order to
1035 * determine the current state. Since the devinfo node can have multiple
1036 * paths the devfs_path is used to locate the correct path.
1038 static int
1039 get_path_state_name(ptree_rarg_t *rarg, void *vbuf)
1041 int err;
1042 picl_nodehdl_t parh;
1043 char devfs_path[PATH_MAX];
1044 di_node_t di_node;
1045 di_node_t di_root;
1046 di_path_t pi = DI_PATH_NIL;
1047 picl_nodehdl_t mpnode;
1049 (void) strlcpy(vbuf, "unknown", MAX_STATE_SIZE);
1051 mpnode = rarg->nodeh;
1054 * The parent node represents the vHCI.
1056 err = ptree_get_propval_by_name(mpnode, PICL_PROP_PARENT, &parh,
1057 sizeof (picl_nodehdl_t));
1058 if (err != PICL_SUCCESS) {
1059 return (PICL_SUCCESS);
1063 * The PICL_PROP_DEVFS_PATH property will be used to locate the
1064 * devinfo node for the vHCI driver.
1066 err = ptree_get_propval_by_name(parh, PICL_PROP_DEVFS_PATH, devfs_path,
1067 sizeof (devfs_path));
1068 if (err != PICL_SUCCESS) {
1069 return (PICL_SUCCESS);
1072 * Find the di_node for the vHCI driver. It will be used to scan
1073 * the path information nodes.
1075 di_root = di_init("/", DINFOCACHE);
1076 if (di_root == DI_NODE_NIL) {
1077 return (PICL_SUCCESS);
1079 di_node = di_lookup_node(di_root, devfs_path);
1080 if (di_node == DI_NODE_NIL) {
1081 di_fini(di_root);
1082 return (PICL_SUCCESS);
1086 * The devfs_path will be used below to match the
1087 * proper path information node.
1089 err = ptree_get_propval_by_name(mpnode, PICL_PROP_DEVFS_PATH,
1090 devfs_path, sizeof (devfs_path));
1091 if (err != PICL_SUCCESS) {
1092 di_fini(di_root);
1093 return (PICL_SUCCESS);
1097 * Scan the path information nodes looking for the matching devfs
1098 * path. When found obtain the state information.
1100 while ((pi = di_path_next_phci(di_node, pi)) != DI_PATH_NIL) {
1101 char *di_path;
1102 di_node_t phci_node = di_path_phci_node(pi);
1104 if (phci_node == DI_PATH_NIL)
1105 continue;
1107 di_path = di_devfs_path(phci_node);
1108 if (di_path) {
1109 if (strcmp(di_path, devfs_path) != 0) {
1110 di_devfs_path_free(di_path);
1111 continue;
1113 (void) strlcpy(vbuf, path_state_name(di_path_state(pi)),
1114 MAX_STATE_SIZE);
1115 di_devfs_path_free(di_path);
1116 break;
1120 di_fini(di_root);
1121 return (PICL_SUCCESS);
1124 static void
1125 add_di_path_prop(picl_nodehdl_t nodeh, di_path_prop_t di_path_prop)
1127 int di_ptype;
1128 char *di_val;
1129 ptree_propinfo_t propinfo;
1130 int *idata;
1131 char *sdata;
1132 unsigned char *bdata;
1133 int len;
1135 di_ptype = di_path_prop_type(di_path_prop);
1136 di_val = di_path_prop_name(di_path_prop);
1138 switch (di_ptype) {
1139 case DI_PROP_TYPE_BOOLEAN:
1140 add_boolean_prop(nodeh, propinfo, di_val);
1141 break;
1142 case DI_PROP_TYPE_INT:
1143 case DI_PROP_TYPE_INT64:
1144 len = di_path_prop_ints(di_path_prop, &idata);
1145 if (len < 0)
1146 /* Received error, so ignore prop */
1147 break;
1148 add_uints_prop(nodeh, propinfo, di_val, idata, len);
1149 break;
1150 case DI_PROP_TYPE_STRING:
1151 len = di_path_prop_strings(di_path_prop, &sdata);
1152 if (len <= 0)
1153 break;
1154 add_strings_prop(nodeh, propinfo, di_val, sdata, len);
1155 break;
1156 case DI_PROP_TYPE_BYTE:
1157 len = di_path_prop_bytes(di_path_prop, &bdata);
1158 if (len < 0)
1159 break;
1160 add_bytes_prop(nodeh, propinfo, di_val, bdata, len);
1161 break;
1162 case DI_PROP_TYPE_UNKNOWN:
1164 * Unknown type, we'll try and guess what it should be.
1166 len = di_path_prop_strings(di_path_prop, &sdata);
1167 if ((len > 0) && (sdata[0] != 0)) {
1168 add_strings_prop(nodeh, propinfo, di_val, sdata,
1169 len);
1170 break;
1172 len = di_path_prop_ints(di_path_prop, &idata);
1173 if (len > 0) {
1174 add_uints_prop(nodeh, propinfo, di_val,
1175 idata, len);
1176 break;
1178 len = di_path_prop_bytes(di_path_prop, &bdata);
1179 if (len > 0)
1180 add_bytes_prop(nodeh, propinfo,
1181 di_val, bdata, len);
1182 else if (len == 0)
1183 add_boolean_prop(nodeh, propinfo,
1184 di_val);
1185 break;
1186 case DI_PROP_TYPE_UNDEF_IT:
1187 break;
1188 default:
1189 break;
1194 * Add nodes for path information (PSARC/1999/647, PSARC/2008/437)
1196 static void
1197 construct_mpath_node(picl_nodehdl_t parh, di_node_t di_node)
1199 di_path_t pi = DI_PATH_NIL;
1201 while ((pi = di_path_next_phci(di_node, pi)) != DI_PATH_NIL) {
1202 di_node_t phci_node = di_path_phci_node(pi);
1203 di_path_prop_t di_path_prop;
1204 picl_nodehdl_t nodeh;
1205 ptree_propinfo_t propinfo;
1206 int err;
1207 int instance;
1208 char *di_val;
1210 if (phci_node == DI_PATH_NIL)
1211 continue;
1213 err = ptree_create_and_add_node(parh, PICL_CLASS_MULTIPATH,
1214 PICL_CLASS_MULTIPATH, &nodeh);
1215 if (err != PICL_SUCCESS)
1216 continue;
1218 instance = di_instance(phci_node);
1219 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
1220 PICL_PTYPE_INT, PICL_READ, sizeof (instance),
1221 PICL_PROP_INSTANCE, NULL, NULL);
1222 (void) ptree_create_and_add_prop(nodeh, &propinfo, &instance,
1223 NULL);
1225 di_val = di_devfs_path(phci_node);
1226 if (di_val) {
1227 (void) ptree_init_propinfo(&propinfo,
1228 PTREE_PROPINFO_VERSION,
1229 PICL_PTYPE_CHARSTRING, PICL_READ,
1230 strlen(di_val) + 1, PICL_PROP_DEVFS_PATH,
1231 NULL, NULL);
1232 (void) ptree_create_and_add_prop(nodeh,
1233 &propinfo, di_val, NULL);
1234 di_devfs_path_free(di_val);
1237 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
1238 PICL_PTYPE_CHARSTRING, (PICL_READ|PICL_VOLATILE),
1239 MAX_STATE_SIZE, PICL_PROP_STATE, get_path_state_name, NULL);
1240 (void) ptree_create_and_add_prop(nodeh, &propinfo, NULL, NULL);
1242 for (di_path_prop = di_path_prop_next(pi, DI_PROP_NIL);
1243 di_path_prop != DI_PROP_NIL;
1244 di_path_prop = di_path_prop_next(pi, di_path_prop)) {
1245 add_di_path_prop(nodeh, di_path_prop);
1251 * Add properties provided by libdevinfo
1253 static void
1254 add_devinfo_props(picl_nodehdl_t nodeh, di_node_t di_node)
1256 int instance;
1257 char *di_val;
1258 di_prop_t di_prop;
1259 int di_ptype;
1260 ptree_propinfo_t propinfo;
1261 char *sdata;
1262 unsigned char *bdata;
1263 int *idata;
1264 int len;
1266 instance = di_instance(di_node);
1267 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
1268 PICL_PTYPE_INT, PICL_READ, sizeof (instance), PICL_PROP_INSTANCE,
1269 NULL, NULL);
1270 (void) ptree_create_and_add_prop(nodeh, &propinfo, &instance, NULL);
1272 di_val = di_bus_addr(di_node);
1273 if (di_val) {
1274 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
1275 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(di_val) + 1,
1276 PICL_PROP_BUS_ADDR, NULL, NULL);
1277 (void) ptree_create_and_add_prop(nodeh, &propinfo, di_val,
1278 NULL);
1281 di_val = di_binding_name(di_node);
1282 if (di_val) {
1283 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
1284 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(di_val) + 1,
1285 PICL_PROP_BINDING_NAME, NULL, NULL);
1286 (void) ptree_create_and_add_prop(nodeh, &propinfo, di_val,
1287 NULL);
1290 di_val = di_driver_name(di_node);
1291 if (di_val) {
1292 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
1293 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(di_val) + 1,
1294 PICL_PROP_DRIVER_NAME, NULL, NULL);
1295 (void) ptree_create_and_add_prop(nodeh, &propinfo, di_val,
1296 NULL);
1299 di_val = di_devfs_path(di_node);
1300 if (di_val) {
1301 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
1302 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(di_val) + 1,
1303 PICL_PROP_DEVFS_PATH, NULL, NULL);
1304 (void) ptree_create_and_add_prop(nodeh, &propinfo, di_val,
1305 NULL);
1306 di_devfs_path_free(di_val);
1309 for (di_prop = di_prop_next(di_node, DI_PROP_NIL);
1310 di_prop != DI_PROP_NIL;
1311 di_prop = di_prop_next(di_node, di_prop)) {
1313 di_val = di_prop_name(di_prop);
1314 di_ptype = di_prop_type(di_prop);
1316 switch (di_ptype) {
1317 case DI_PROP_TYPE_BOOLEAN:
1318 add_boolean_prop(nodeh, propinfo, di_val);
1319 break;
1320 case DI_PROP_TYPE_INT:
1321 len = di_prop_ints(di_prop, &idata);
1322 if (len < 0)
1323 /* Received error, so ignore prop */
1324 break;
1325 add_uints_prop(nodeh, propinfo, di_val, idata, len);
1326 break;
1327 case DI_PROP_TYPE_STRING:
1328 len = di_prop_strings(di_prop, &sdata);
1329 if (len < 0)
1330 break;
1331 add_strings_prop(nodeh, propinfo, di_val, sdata, len);
1332 break;
1333 case DI_PROP_TYPE_BYTE:
1334 len = di_prop_bytes(di_prop, &bdata);
1335 if (len < 0)
1336 break;
1337 add_bytes_prop(nodeh, propinfo, di_val, bdata, len);
1338 break;
1339 case DI_PROP_TYPE_UNKNOWN:
1341 * Unknown type, we'll try and guess what it should be.
1343 len = di_prop_strings(di_prop, &sdata);
1344 if ((len > 0) && (sdata[0] != 0)) {
1345 add_strings_prop(nodeh, propinfo, di_val, sdata,
1346 len);
1347 break;
1349 len = di_prop_ints(di_prop, &idata);
1350 if (len > 0) {
1351 add_uints_prop(nodeh, propinfo, di_val,
1352 idata, len);
1353 break;
1355 len = di_prop_rawdata(di_prop, &bdata);
1356 if (len > 0)
1357 add_bytes_prop(nodeh, propinfo,
1358 di_val, bdata, len);
1359 else if (len == 0)
1360 add_boolean_prop(nodeh, propinfo,
1361 di_val);
1362 break;
1363 case DI_PROP_TYPE_UNDEF_IT:
1364 break;
1365 default:
1366 break;
1372 * This function creates the /obp node in the PICL tree for OBP nodes
1373 * without a device type class.
1375 static int
1376 construct_picl_openprom(picl_nodehdl_t rooth, picl_nodehdl_t *obph)
1378 picl_nodehdl_t tmph;
1379 int err;
1381 err = ptree_create_and_add_node(rooth, PICL_NODE_OBP,
1382 PICL_CLASS_PICL, &tmph);
1384 if (err != PICL_SUCCESS)
1385 return (err);
1386 *obph = tmph;
1387 return (PICL_SUCCESS);
1391 * This function creates the /platform node in the PICL tree and
1392 * its properties. It sets the "platform-name" property to the
1393 * platform name
1395 static int
1396 construct_picl_platform(picl_nodehdl_t rooth, di_node_t di_root,
1397 picl_nodehdl_t *piclh)
1399 int err;
1400 picl_nodehdl_t plafh;
1401 char *nodename;
1402 char nodeclass[PICL_CLASSNAMELEN_MAX];
1403 ptree_propinfo_t propinfo;
1404 picl_prophdl_t proph;
1406 nodename = di_node_name(di_root);
1407 if (nodename == NULL)
1408 return (PICL_FAILURE);
1410 err = 0;
1411 if (di_nodeid(di_root) == DI_PROM_NODEID ||
1412 di_nodeid(di_root) == DI_SID_NODEID)
1413 err = get_device_type(nodeclass, di_root);
1415 if (err < 0)
1416 (void) strcpy(nodeclass, PICL_CLASS_UPA); /* default */
1418 err = ptree_create_and_add_node(rooth, PICL_NODE_PLATFORM,
1419 nodeclass, &plafh);
1420 if (err != PICL_SUCCESS)
1421 return (err);
1423 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
1424 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(nodename) + 1,
1425 PICL_PROP_PLATFORM_NAME, NULL, NULL);
1426 err = ptree_create_and_add_prop(plafh, &propinfo, nodename, &proph);
1427 if (err != PICL_SUCCESS)
1428 return (err);
1430 (void) add_devinfo_props(plafh, di_root);
1432 (void) add_openprom_props(plafh, di_root);
1434 *piclh = plafh;
1436 return (PICL_SUCCESS);
1440 * This function creates a node in /obp tree for the libdevinfo handle.
1442 static int
1443 construct_obp_node(picl_nodehdl_t parh, di_node_t dn, picl_nodehdl_t *chdh)
1445 int err;
1446 char *nodename;
1447 char nodeclass[PICL_CLASSNAMELEN_MAX];
1448 picl_nodehdl_t anodeh;
1450 nodename = di_node_name(dn); /* PICL_PROP_NAME */
1451 if (nodename == NULL)
1452 return (PICL_FAILURE);
1454 if (strcmp(nodename, "pseudo") == 0)
1455 return (PICL_FAILURE);
1457 if ((di_nodeid(dn) == DI_PROM_NODEID) &&
1458 (get_device_type(nodeclass, dn) == 0))
1459 return (PICL_FAILURE);
1461 err = ptree_create_and_add_node(parh, nodename, nodename, &anodeh);
1462 if (err != PICL_SUCCESS)
1463 return (err);
1465 add_devinfo_props(anodeh, dn);
1467 (void) add_openprom_props(anodeh, dn);
1469 *chdh = anodeh;
1471 return (PICL_SUCCESS);
1475 * This function creates a PICL node in /platform tree for a device
1477 static int
1478 construct_devtype_node(picl_nodehdl_t parh, char *nodename,
1479 char *nodeclass, di_node_t dn, picl_nodehdl_t *chdh)
1481 int err;
1482 picl_nodehdl_t anodeh;
1484 err = ptree_create_and_add_node(parh, nodename, nodeclass, &anodeh);
1485 if (err != PICL_SUCCESS)
1486 return (err);
1488 (void) add_devinfo_props(anodeh, dn);
1489 (void) add_openprom_props(anodeh, dn);
1490 construct_mpath_node(anodeh, dn);
1492 *chdh = anodeh;
1493 return (err);
1497 * Create a subtree of "picl" class nodes in /obp for these nodes
1499 static int
1500 construct_openprom_tree(picl_nodehdl_t nodeh, di_node_t dinode)
1502 di_node_t cnode;
1503 picl_nodehdl_t chdh;
1504 int err;
1506 err = construct_obp_node(nodeh, dinode, &chdh);
1507 if (err != PICL_SUCCESS)
1508 return (err);
1510 for (cnode = di_child_node(dinode); cnode != DI_NODE_NIL;
1511 cnode = di_sibling_node(cnode))
1512 (void) construct_openprom_tree(chdh, cnode);
1514 return (PICL_SUCCESS);
1519 * Process the libdevinfo device tree and create nodes in /platform or /obp
1520 * PICL tree.
1522 * This routine traverses the immediate children of "dinode" device and
1523 * determines the node class for that child. If it finds a valid class
1524 * name, then it builds a PICL node under /platform subtree and calls itself
1525 * recursively to construct the subtree for that child node. Otherwise, if
1526 * the parent_class is NULL, then it constructs a node and subtree under /obp
1527 * subtree.
1529 * Note that we skip the children nodes that don't have a valid class name
1530 * and the parent_class is non NULL to prevent creation of any placeholder
1531 * nodes (such as sd,...).
1533 static int
1534 construct_devinfo_tree(picl_nodehdl_t plafh, picl_nodehdl_t obph,
1535 di_node_t dinode, char *parent_class)
1537 di_node_t cnode;
1538 picl_nodehdl_t chdh;
1539 char nodeclass[PICL_CLASSNAMELEN_MAX];
1540 char *nodename;
1541 int err;
1543 err = PICL_SUCCESS;
1544 for (cnode = di_child_node(dinode); cnode != DI_NODE_NIL;
1545 cnode = di_sibling_node(cnode)) {
1546 nodename = di_node_name(cnode); /* PICL_PROP_NAME */
1547 if (nodename == NULL)
1548 continue;
1550 err = get_node_class(nodeclass, cnode, nodename);
1552 if (err == 0) {
1553 err = construct_devtype_node(plafh, nodename,
1554 nodeclass, cnode, &chdh);
1555 if (err != PICL_SUCCESS)
1556 return (err);
1557 err = construct_devinfo_tree(chdh, obph, cnode,
1558 nodeclass);
1559 } else if (parent_class == NULL)
1560 err = construct_openprom_tree(obph, cnode);
1561 else
1562 continue;
1564 * if parent_class is non NULL, skip the children nodes
1565 * that don't have a valid device class - eliminates
1566 * placeholder nodes (sd,...) from being created.
1570 return (err);
1575 * This function is called from the event handler called from the daemon
1576 * on PICL events.
1578 * This routine traverses the children of the "dinode" device and
1579 * creates a PICL node for each child not found in the PICL tree and
1580 * invokes itself recursively to create a subtree for the newly created
1581 * child node. It also checks if the node being created is a meory
1582 * controller. If so, it posts PICLEVENT_MC_ADDED PICL event to the PICL
1583 * framework.
1585 static int
1586 update_subtree(picl_nodehdl_t nodeh, di_node_t dinode)
1588 di_node_t cnode;
1589 picl_nodehdl_t chdh;
1590 picl_nodehdl_t nh;
1591 char *nodename;
1592 char nodeclass[PICL_CLASSNAMELEN_MAX];
1593 char *path_buf;
1594 char buf[MAX_UNIT_ADDRESS_LEN];
1595 char unitaddr[MAX_UNIT_ADDRESS_LEN];
1596 char path_w_ua[MAXPATHLEN];
1597 char path_wo_ua[MAXPATHLEN];
1598 char *strp;
1599 int gotit;
1600 int err;
1602 for (cnode = di_child_node(dinode); cnode != DI_NODE_NIL;
1603 cnode = di_sibling_node(cnode)) {
1604 path_buf = di_devfs_path(cnode);
1605 if (path_buf == NULL)
1606 continue;
1608 nodename = di_node_name(cnode);
1609 if (nodename == NULL) {
1610 di_devfs_path_free(path_buf);
1611 continue;
1614 err = get_node_class(nodeclass, cnode, nodename);
1616 if (err < 0) {
1617 di_devfs_path_free(path_buf);
1618 continue;
1622 * this is quite complicated - both path_buf and any nodes
1623 * already in the picl tree may, or may not, have the
1624 * @<unit_addr> at the end of their names. So we must
1625 * take path_buf and work out what the device path would
1626 * be both with and without the unit_address, then search
1627 * the picl tree for both forms.
1629 if (((strp = strrchr(path_buf, '/')) != NULL) &&
1630 strchr(strp, '@') == NULL) {
1632 * This is an unattached node - so the path is not
1633 * unique. Need to find out which node it is.
1634 * Find the unit_address from the OBP or devinfo
1635 * properties.
1637 err = ptree_create_node(nodename, nodeclass, &chdh);
1638 if (err != PICL_SUCCESS)
1639 return (err);
1641 (void) add_devinfo_props(chdh, cnode);
1642 (void) add_openprom_props(chdh, cnode);
1644 err = get_unitaddr(nodeh, chdh, unitaddr,
1645 sizeof (unitaddr));
1646 if (err != PICL_SUCCESS)
1647 return (err);
1648 (void) ptree_destroy_node(chdh);
1649 (void) snprintf(path_w_ua, sizeof (path_w_ua), "%s@%s",
1650 path_buf, unitaddr);
1651 (void) snprintf(path_wo_ua, sizeof (path_wo_ua), "%s",
1652 path_buf);
1653 } else {
1655 * this is an attached node - so the path is unique
1657 (void) snprintf(path_w_ua, sizeof (path_w_ua), "%s",
1658 path_buf);
1659 (void) snprintf(path_wo_ua, sizeof (path_wo_ua), "%s",
1660 path_buf);
1661 strp = strrchr(path_wo_ua, '@');
1662 *strp++ = '\0';
1663 (void) snprintf(unitaddr, sizeof (unitaddr), "%s",
1664 strp);
1667 * first look for node with unit address in devfs_path
1669 if (ptree_find_node(nodeh, PICL_PROP_DEVFS_PATH,
1670 PICL_PTYPE_CHARSTRING, path_w_ua, strlen(path_w_ua) + 1,
1671 &nh) == PICL_SUCCESS) {
1673 * node already there - there's nothing we need to do
1675 if (picldevtree_debug > 1)
1676 syslog(LOG_INFO,
1677 "update_subtree: path:%s node exists\n",
1678 path_buf);
1679 di_devfs_path_free(path_buf);
1680 continue;
1683 * now look for node without unit address in devfs_path.
1684 * This might be just one out of several
1685 * nodes - need to check all siblings
1687 err = ptree_get_propval_by_name(nodeh, PICL_PROP_CHILD,
1688 &chdh, sizeof (chdh));
1689 if ((err != PICL_SUCCESS) && (err != PICL_PROPNOTFOUND))
1690 return (err);
1691 gotit = 0;
1692 while (err == PICL_SUCCESS) {
1693 err = ptree_get_propval_by_name(chdh,
1694 PICL_PROP_DEVFS_PATH, buf, sizeof (buf));
1695 if (err != PICL_SUCCESS)
1696 return (err);
1697 if (strcmp(buf, path_wo_ua) == 0) {
1698 err = ptree_get_propval_by_name(chdh,
1699 PICL_PROP_UNIT_ADDRESS, buf, sizeof (buf));
1700 if (err != PICL_SUCCESS)
1701 return (err);
1702 if (strcmp(buf, unitaddr) == 0) {
1703 gotit = 1;
1704 break;
1707 err = ptree_get_propval_by_name(chdh,
1708 PICL_PROP_PEER, &chdh, sizeof (chdh));
1709 if (err != PICL_SUCCESS)
1710 break;
1712 if (gotit) {
1714 * node already there - there's nothing we need to do
1716 if (picldevtree_debug > 1)
1717 syslog(LOG_INFO,
1718 "update_subtree: path:%s node exists\n",
1719 path_buf);
1720 di_devfs_path_free(path_buf);
1721 continue;
1724 #define IS_MC(x) (strcmp(x, PICL_CLASS_MEMORY_CONTROLLER) == 0 ? 1 : 0)
1726 if (construct_devtype_node(nodeh, nodename, nodeclass, cnode,
1727 &chdh) == PICL_SUCCESS) {
1728 if (picldevtree_debug)
1729 syslog(LOG_INFO,
1730 "picldevtree: added node:%s path:%s\n",
1731 nodename, path_buf);
1732 if (IS_MC(nodeclass)) {
1733 if (post_mc_event(PICLEVENT_MC_ADDED, chdh) !=
1734 PICL_SUCCESS)
1735 syslog(LOG_WARNING, PICL_EVENT_DROPPED,
1736 PICLEVENT_MC_ADDED);
1739 di_devfs_path_free(path_buf);
1740 (void) update_subtree(chdh, cnode);
1744 return (PICL_SUCCESS);
1749 * Check for a stale OBP node. EINVAL is returned from the openprom(7D) driver
1750 * if the nodeid stored in the snapshot is not valid.
1752 static int
1753 check_stale_node(di_node_t node, void *arg)
1755 di_prom_prop_t promp;
1757 errno = 0;
1758 promp = di_prom_prop_next(ph, node, DI_PROM_PROP_NIL);
1759 if (promp == DI_PROM_PROP_NIL && errno == EINVAL) {
1760 snapshot_stale = 1;
1761 return (DI_WALK_TERMINATE);
1763 return (DI_WALK_CONTINUE);
1767 * Walk the snapshot and check the OBP properties of each node.
1769 static int
1770 is_snapshot_stale(di_node_t root)
1772 snapshot_stale = 0;
1773 di_walk_node(root, DI_WALK_CLDFIRST, NULL, check_stale_node);
1774 return (snapshot_stale);
1778 * This function processes the data from libdevinfo and creates nodes
1779 * in the PICL tree.
1781 static int
1782 libdevinfo_init(picl_nodehdl_t rooth)
1784 di_node_t di_root;
1785 picl_nodehdl_t plafh;
1786 picl_nodehdl_t obph;
1787 int err;
1790 * Use DINFOCACHE so that we obtain all attributes for all
1791 * device instances (without necessarily doing a load/attach
1792 * of all drivers). Once the (on-disk) cache file is built, it
1793 * exists over a reboot and can be read into memory at a very
1794 * low cost.
1796 if ((di_root = di_init("/", DINFOCACHE)) == DI_NODE_NIL)
1797 return (PICL_FAILURE);
1799 if ((ph = di_prom_init()) == NULL)
1800 return (PICL_FAILURE);
1803 * Check if the snapshot cache contains stale OBP nodeid references.
1804 * If it does release the snapshot and obtain a live snapshot from the
1805 * kernel.
1807 if (is_snapshot_stale(di_root)) {
1808 syslog(LOG_INFO, "picld detected stale snapshot cache");
1809 di_fini(di_root);
1810 if ((di_root = di_init("/", DINFOCPYALL | DINFOFORCE)) ==
1811 DI_NODE_NIL) {
1812 return (PICL_FAILURE);
1817 * create platform PICL node using di_root node
1819 err = construct_picl_platform(rooth, di_root, &plafh);
1820 if (err != PICL_SUCCESS) {
1821 di_fini(di_root);
1822 return (PICL_FAILURE);
1825 err = construct_picl_openprom(rooth, &obph);
1826 if (err != PICL_SUCCESS) {
1827 di_fini(di_root);
1828 return (PICL_FAILURE);
1831 (void) construct_devinfo_tree(plafh, obph, di_root, NULL);
1832 if (ph) {
1833 di_prom_fini(ph);
1834 ph = NULL;
1836 di_fini(di_root);
1837 return (err);
1841 * This function returns the integer property value
1843 static int
1844 get_int_propval_by_name(picl_nodehdl_t nodeh, char *pname, int *ival)
1846 int err;
1848 err = ptree_get_propval_by_name(nodeh, pname, ival,
1849 sizeof (int));
1851 return (err);
1855 * This function returns the port ID (or CPU ID in the case of CMP cores)
1856 * of the specific CPU node handle. If upa_portid exists, return its value.
1857 * Otherwise, return portid/cpuid.
1859 static int
1860 get_cpu_portid(picl_nodehdl_t modh, int *id)
1862 int err;
1864 if (strcmp(mach_name, "sun4u") == 0 ||
1865 strcmp(mach_name, "sun4v") == 0) {
1866 err = get_int_propval_by_name(modh, OBP_PROP_UPA_PORTID, id);
1867 if (err == PICL_SUCCESS)
1868 return (err);
1869 err = get_int_propval_by_name(modh, OBP_PROP_PORTID, id);
1870 if (err == PICL_SUCCESS)
1871 return (err);
1872 return (get_int_propval_by_name(modh, OBP_PROP_CPUID, id));
1874 if (strcmp(mach_name, "i86pc") == 0)
1875 return (get_int_propval_by_name(modh, OBP_REG, id));
1877 return (PICL_FAILURE);
1881 * This function is the volatile read access function of CPU state
1882 * property
1884 static int
1885 get_pi_state(ptree_rarg_t *rarg, void *vbuf)
1887 int id;
1888 int err;
1890 err = get_int_propval_by_name(rarg->nodeh, PICL_PROP_ID, &id);
1891 if (err != PICL_SUCCESS)
1892 return (err);
1894 switch (p_online(id, P_STATUS)) {
1895 case P_ONLINE:
1896 (void) strlcpy(vbuf, PS_ONLINE, MAX_STATE_SIZE);
1897 break;
1898 case P_OFFLINE:
1899 (void) strlcpy(vbuf, PS_OFFLINE, MAX_STATE_SIZE);
1900 break;
1901 case P_NOINTR:
1902 (void) strlcpy(vbuf, PS_NOINTR, MAX_STATE_SIZE);
1903 break;
1904 case P_SPARE:
1905 (void) strlcpy(vbuf, PS_SPARE, MAX_STATE_SIZE);
1906 break;
1907 case P_FAULTED:
1908 (void) strlcpy(vbuf, PS_FAULTED, MAX_STATE_SIZE);
1909 break;
1910 case P_POWEROFF:
1911 (void) strlcpy(vbuf, PS_POWEROFF, MAX_STATE_SIZE);
1912 break;
1913 default:
1914 (void) strlcpy(vbuf, "unknown", MAX_STATE_SIZE);
1915 break;
1917 return (PICL_SUCCESS);
1921 * This function is the volatile read access function of CPU processor_type
1922 * property
1924 static int
1925 get_processor_type(ptree_rarg_t *rarg, void *vbuf)
1927 processor_info_t cpu_info;
1928 int id;
1929 int err;
1931 err = get_int_propval_by_name(rarg->nodeh, PICL_PROP_ID, &id);
1932 if (err != PICL_SUCCESS)
1933 return (err);
1935 if (processor_info(id, &cpu_info) >= 0) {
1936 (void) strlcpy(vbuf, cpu_info.pi_processor_type, PI_TYPELEN);
1938 return (PICL_SUCCESS);
1942 * This function is the volatile read access function of CPU fputypes
1943 * property
1945 static int
1946 get_fputypes(ptree_rarg_t *rarg, void *vbuf)
1948 processor_info_t cpu_info;
1949 int id;
1950 int err;
1952 err = get_int_propval_by_name(rarg->nodeh, PICL_PROP_ID, &id);
1953 if (err != PICL_SUCCESS)
1954 return (err);
1956 if (processor_info(id, &cpu_info) >= 0) {
1957 (void) strlcpy(vbuf, cpu_info.pi_fputypes, PI_FPUTYPE);
1959 return (PICL_SUCCESS);
1963 * This function is the volatile read access function of CPU StateBegin
1964 * property. To minimize overhead, use kstat_chain_update() to refresh
1965 * the kstat header info as opposed to invoking kstat_open() every time.
1967 static int
1968 get_pi_state_begin(ptree_rarg_t *rarg, void *vbuf)
1970 int err;
1971 int cpu_id;
1972 static kstat_ctl_t *kc = NULL;
1973 static pthread_mutex_t kc_mutex = PTHREAD_MUTEX_INITIALIZER;
1974 kstat_t *kp;
1975 kstat_named_t *kn;
1977 err = get_int_propval_by_name(rarg->nodeh, PICL_PROP_ID, &cpu_id);
1978 if (err != PICL_SUCCESS)
1979 return (err);
1981 (void) pthread_mutex_lock(&kc_mutex);
1982 if (kc == NULL)
1983 kc = kstat_open();
1984 else if (kstat_chain_update(kc) == -1) {
1985 (void) kstat_close(kc);
1986 kc = kstat_open();
1989 if (kc == NULL) {
1990 (void) pthread_mutex_unlock(&kc_mutex);
1991 return (PICL_FAILURE);
1994 /* Get the state_begin from kstat */
1995 if ((kp = kstat_lookup(kc, KSTAT_CPU_INFO, cpu_id, NULL)) == NULL ||
1996 kp->ks_type != KSTAT_TYPE_NAMED || kstat_read(kc, kp, 0) < 0) {
1997 (void) pthread_mutex_unlock(&kc_mutex);
1998 return (PICL_FAILURE);
2001 kn = kstat_data_lookup(kp, KSTAT_STATE_BEGIN);
2002 if (kn) {
2003 *(uint64_t *)vbuf = (uint64_t)kn->value.l;
2004 err = PICL_SUCCESS;
2005 } else
2006 err = PICL_FAILURE;
2008 (void) pthread_mutex_unlock(&kc_mutex);
2009 return (err);
2013 * This function adds CPU information to the CPU nodes
2015 /* ARGSUSED */
2016 static int
2017 add_processor_info(picl_nodehdl_t cpuh, void *args)
2019 int err;
2020 int cpu_id;
2021 ptree_propinfo_t propinfo;
2022 ptree_propinfo_t pinfo;
2024 err = get_cpu_portid(cpuh, &cpu_id);
2025 if (err != PICL_SUCCESS)
2026 return (PICL_WALK_CONTINUE);
2029 * Check to make sure that the CPU is still present, i.e. that it
2030 * has not been DR'ed out of the system.
2032 if (p_online(cpu_id, P_STATUS) == -1) {
2033 if (picldevtree_debug)
2034 syslog(LOG_INFO,
2035 "picldevtree: cpu %d (%llx) does not exist - "
2036 "deleting node\n", cpu_id, cpuh);
2038 if (ptree_delete_node(cpuh) == PICL_SUCCESS)
2039 (void) ptree_destroy_node(cpuh);
2041 return (PICL_WALK_CONTINUE);
2044 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
2045 PICL_PTYPE_INT, PICL_READ, sizeof (int), PICL_PROP_ID, NULL, NULL);
2046 err = ptree_create_and_add_prop(cpuh, &propinfo, &cpu_id, NULL);
2047 if (err != PICL_SUCCESS)
2048 return (PICL_WALK_CONTINUE);
2050 (void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION,
2051 PICL_PTYPE_CHARSTRING, (PICL_READ|PICL_VOLATILE), MAX_STATE_SIZE,
2052 PICL_PROP_STATE, get_pi_state, NULL);
2053 (void) ptree_create_and_add_prop(cpuh, &pinfo, NULL, NULL);
2055 (void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION,
2056 PICL_PTYPE_CHARSTRING, (PICL_READ|PICL_VOLATILE), PI_TYPELEN,
2057 PICL_PROP_PROCESSOR_TYPE, get_processor_type, NULL);
2058 (void) ptree_create_and_add_prop(cpuh, &pinfo, NULL, NULL);
2060 (void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION,
2061 PICL_PTYPE_CHARSTRING, (PICL_READ|PICL_VOLATILE), PI_FPUTYPE,
2062 PICL_PROP_FPUTYPE, get_fputypes, NULL);
2063 (void) ptree_create_and_add_prop(cpuh, &pinfo, NULL, NULL);
2065 (void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION,
2066 PICL_PTYPE_TIMESTAMP, PICL_READ|PICL_VOLATILE, sizeof (uint64_t),
2067 PICL_PROP_STATE_BEGIN, get_pi_state_begin, NULL);
2068 (void) ptree_create_and_add_prop(cpuh, &pinfo, NULL, NULL);
2070 return (PICL_WALK_CONTINUE);
2074 * This function sets up the "ID" property in every CPU nodes
2075 * and adds processor info
2077 static int
2078 setup_cpus(picl_nodehdl_t plafh)
2080 int err;
2082 err = ptree_walk_tree_by_class(plafh, PICL_CLASS_CPU, NULL,
2083 add_processor_info);
2085 return (err);
2089 * This function format's the manufacture's information for FFB display
2090 * devices
2092 static void
2093 fmt_manf_id(manuf_t manufid, int bufsz, char *outbuf)
2096 * Format the manufacturer's info. Note a small inconsistency we
2097 * have to work around - Brooktree has it's part number in decimal,
2098 * while Mitsubishi has it's part number in hex.
2100 switch (manufid.fld.manf) {
2101 case MANF_BROOKTREE:
2102 (void) snprintf(outbuf, bufsz, "%s %d, version %d",
2103 "Brooktree", manufid.fld.partno, manufid.fld.version);
2104 break;
2106 case MANF_MITSUBISHI:
2107 (void) snprintf(outbuf, bufsz, "%s %x, version %d",
2108 "Mitsubishi", manufid.fld.partno, manufid.fld.version);
2109 break;
2111 default:
2112 (void) snprintf(outbuf, bufsz,
2113 "JED code %d, Part num 0x%x, version %d",
2114 manufid.fld.manf, manufid.fld.partno, manufid.fld.version);
2119 * If it's an ffb device, open ffb devices and return PICL_SUCCESS
2121 static int
2122 open_ffb_device(picl_nodehdl_t ffbh, int *fd)
2124 DIR *dirp;
2125 char devfs_path[PATH_MAX];
2126 char dev_path[PATH_MAX];
2127 char *devp;
2128 struct dirent *direntp;
2129 int err;
2130 int tmpfd;
2132 /* Get the devfs_path of the ffb devices */
2133 err = ptree_get_propval_by_name(ffbh, PICL_PROP_DEVFS_PATH, devfs_path,
2134 sizeof (devfs_path));
2135 if (err != PICL_SUCCESS)
2136 return (err);
2138 /* Get the device node name */
2139 devp = strrchr(devfs_path, '/');
2140 if (devp == NULL)
2141 return (PICL_FAILURE);
2142 *devp = '\0';
2143 ++devp;
2146 * Check if device node name has the ffb string
2147 * If not, assume it's not a ffb device.
2149 if (strstr(devp, FFB_NAME) == NULL)
2150 return (PICL_FAILURE);
2153 * Get the parent path of the ffb device node.
2155 (void) snprintf(dev_path, sizeof (dev_path), "%s/%s", "/devices",
2156 devfs_path);
2159 * Since we don't know ffb's minor nodename,
2160 * we need to search all the devices under its
2161 * parent dir by comparing the node name
2163 if ((dirp = opendir(dev_path)) == NULL)
2164 return (PICL_FAILURE);
2166 while ((direntp = readdir(dirp)) != NULL) {
2167 if (strstr(direntp->d_name, devp) != NULL) {
2168 (void) strcat(dev_path, "/");
2169 (void) strcat(dev_path, direntp->d_name);
2170 tmpfd = open(dev_path, O_RDWR);
2171 if (tmpfd < 0)
2172 continue;
2173 *fd = tmpfd;
2174 (void) closedir(dirp);
2175 return (PICL_SUCCESS);
2179 (void) closedir(dirp);
2180 return (PICL_FAILURE);
2184 * This function recursively searches the tree for ffb display devices
2185 * and add ffb config information
2187 static int
2188 add_ffb_config_info(picl_nodehdl_t rooth)
2190 picl_nodehdl_t nodeh;
2191 int err;
2192 char piclclass[PICL_CLASSNAMELEN_MAX];
2193 char manfidbuf[FFB_MANUF_BUFSIZE];
2194 int fd;
2195 int board_rev;
2196 ffb_sys_info_t fsi;
2197 ptree_propinfo_t pinfo;
2199 for (err = ptree_get_propval_by_name(rooth, PICL_PROP_CHILD, &nodeh,
2200 sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND;
2201 err = ptree_get_propval_by_name(nodeh, PICL_PROP_PEER,
2202 &nodeh, sizeof (picl_nodehdl_t))) {
2204 if (err != PICL_SUCCESS)
2205 return (err);
2207 err = ptree_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
2208 piclclass, PICL_CLASSNAMELEN_MAX);
2210 if ((err == PICL_SUCCESS) &&
2211 (strcmp(piclclass, PICL_CLASS_DISPLAY) == 0)) {
2213 err = open_ffb_device(nodeh, &fd);
2214 if ((err == PICL_SUCCESS) &&
2215 (ioctl(fd, FFB_SYS_INFO, &fsi) >= 0)) {
2216 (void) ptree_init_propinfo(&pinfo,
2217 PTREE_PROPINFO_VERSION,
2218 PICL_PTYPE_UNSIGNED_INT, PICL_READ,
2219 sizeof (int), PICL_PROP_FFB_BOARD_REV,
2220 NULL, NULL);
2221 board_rev = fsi.ffb_strap_bits.fld.board_rev;
2222 (void) ptree_create_and_add_prop(nodeh, &pinfo,
2223 &board_rev, NULL);
2225 fmt_manf_id(fsi.dac_version,
2226 sizeof (manfidbuf), manfidbuf);
2227 (void) ptree_init_propinfo(&pinfo,
2228 PTREE_PROPINFO_VERSION,
2229 PICL_PTYPE_CHARSTRING, PICL_READ,
2230 strlen(manfidbuf) + 1,
2231 PICL_PROP_FFB_DAC_VER, NULL, NULL);
2232 (void) ptree_create_and_add_prop(nodeh, &pinfo,
2233 manfidbuf, NULL);
2235 fmt_manf_id(fsi.fbram_version,
2236 sizeof (manfidbuf), manfidbuf);
2237 (void) ptree_init_propinfo(&pinfo,
2238 PTREE_PROPINFO_VERSION,
2239 PICL_PTYPE_CHARSTRING, PICL_READ,
2240 strlen(manfidbuf) + 1,
2241 PICL_PROP_FFB_FBRAM_VER, NULL,
2242 NULL);
2243 (void) ptree_create_and_add_prop(nodeh, &pinfo,
2244 manfidbuf, NULL);
2245 (void) close(fd);
2247 } else if (add_ffb_config_info(nodeh) != PICL_SUCCESS)
2248 return (PICL_FAILURE);
2250 return (PICL_SUCCESS);
2253 static conf_entries_t *
2254 free_conf_entries(conf_entries_t *list)
2256 conf_entries_t *el;
2257 conf_entries_t *del;
2259 if (list == NULL)
2260 return (NULL);
2261 el = list;
2262 while (el != NULL) {
2263 del = el;
2264 el = el->next;
2265 free(del->name);
2266 free(del->piclclass);
2267 free(del);
2269 return (el);
2273 * Reading config order: platform, common
2275 static conf_entries_t *
2276 read_conf_file(char *fname, conf_entries_t *list)
2278 FILE *fp;
2279 char lbuf[CONFFILE_LINELEN_MAX];
2280 char *nametok;
2281 char *classtok;
2282 conf_entries_t *el;
2283 conf_entries_t *ptr;
2285 if (fname == NULL)
2286 return (list);
2288 fp = fopen(fname, "r");
2290 if (fp == NULL)
2291 return (list);
2293 while (fgets(lbuf, CONFFILE_LINELEN_MAX, fp) != NULL) {
2294 if ((lbuf[0] == CONFFILE_COMMENT_CHAR) || (lbuf[0] == '\n'))
2295 continue;
2297 nametok = strtok(lbuf, " \t\n");
2298 if (nametok == NULL)
2299 continue;
2301 classtok = strtok(NULL, " \t\n");
2302 if (classtok == NULL)
2303 continue;
2305 el = malloc(sizeof (conf_entries_t));
2306 if (el == NULL)
2307 break;
2308 el->name = strdup(nametok);
2309 el->piclclass = strdup(classtok);
2310 if ((el->name == NULL) || (el->piclclass == NULL)) {
2311 free(el);
2312 return (list);
2314 el->next = NULL;
2317 * Add it to the end of list
2319 if (list == NULL)
2320 list = el;
2321 else {
2322 ptr = list;
2323 while (ptr->next != NULL)
2324 ptr = ptr->next;
2325 ptr->next = el;
2329 (void) fclose(fp);
2330 return (list);
2334 * Process the devtree conf file and set up the conf_name_class_map list
2336 static void
2337 process_devtree_conf_file(void)
2339 char nmbuf[SYS_NMLN];
2340 char pname[PATH_MAX];
2342 conf_name_class_map = NULL;
2344 if (sysinfo(SI_PLATFORM, nmbuf, sizeof (nmbuf)) != -1) {
2345 (void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf);
2346 (void) strlcat(pname, DEVTREE_CONFFILE_NAME, PATH_MAX);
2347 conf_name_class_map = read_conf_file(pname,
2348 conf_name_class_map);
2351 if (sysinfo(SI_MACHINE, nmbuf, sizeof (nmbuf)) != -1) {
2352 (void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf);
2353 (void) strlcat(pname, DEVTREE_CONFFILE_NAME, PATH_MAX);
2354 conf_name_class_map = read_conf_file(pname,
2355 conf_name_class_map);
2358 (void) snprintf(pname, PATH_MAX, "%s/%s", PICLD_COMMON_PLUGIN_DIR,
2359 DEVTREE_CONFFILE_NAME);
2360 conf_name_class_map = read_conf_file(pname, conf_name_class_map);
2363 static asr_conf_entries_t *conf_name_asr_map = NULL;
2365 static void
2366 free_asr_conf_entries(asr_conf_entries_t *list) {
2367 asr_conf_entries_t *el;
2368 asr_conf_entries_t *del;
2370 el = list;
2371 while (el != NULL) {
2372 del = el;
2373 el = el->next;
2374 free(del->name);
2375 free(del->address);
2376 free(del->status);
2377 free(del->piclclass);
2378 free(del->props);
2379 free(del);
2384 * Reading config order: platform, common
2386 static asr_conf_entries_t *
2387 read_asr_conf_file(char *fname, asr_conf_entries_t *list)
2389 FILE *fp;
2390 char lbuf[CONFFILE_LINELEN_MAX];
2391 char *nametok;
2392 char *classtok;
2393 char *statustok;
2394 char *addresstok;
2395 char *propstok;
2396 asr_conf_entries_t *el;
2397 asr_conf_entries_t *ptr;
2399 if (fname == NULL)
2400 return (list);
2402 fp = fopen(fname, "r");
2403 if (fp == NULL)
2404 return (list);
2406 while (fgets(lbuf, CONFFILE_LINELEN_MAX, fp) != NULL) {
2407 if ((lbuf[0] == CONFFILE_COMMENT_CHAR) || (lbuf[0] == '\n'))
2408 continue;
2410 nametok = strtok(lbuf, " \t\n");
2411 if (nametok == NULL)
2412 continue;
2414 classtok = strtok(NULL, " \t\n");
2415 if (classtok == NULL)
2416 continue;
2418 statustok = strtok(NULL, " \t\n");
2419 if (statustok == NULL)
2420 continue;
2422 addresstok = strtok(NULL, " \t\n");
2423 if (addresstok == NULL)
2424 continue;
2427 * props are optional
2429 propstok = strtok(NULL, " \t\n");
2431 el = malloc(sizeof (asr_conf_entries_t));
2432 if (el == NULL)
2433 break;
2434 el->name = strdup(nametok);
2435 el->piclclass = strdup(classtok);
2436 el->status = strdup(statustok);
2437 el->address = strdup(addresstok);
2438 if (propstok != NULL)
2439 el->props = strdup(propstok);
2440 else
2441 el->props = NULL;
2442 if ((el->name == NULL) || (el->piclclass == NULL) ||
2443 (el->address == NULL) || (el->status == NULL)) {
2444 free(el->name);
2445 free(el->address);
2446 free(el->status);
2447 free(el->piclclass);
2448 free(el->props);
2449 free(el);
2450 break;
2452 el->next = NULL;
2455 * Add it to the end of list
2457 if (list == NULL)
2458 list = el;
2459 else {
2460 ptr = list;
2461 while (ptr->next != NULL)
2462 ptr = ptr->next;
2463 ptr->next = el;
2467 (void) fclose(fp);
2468 return (list);
2472 * Process the asr conf file
2474 static void
2475 process_asrtree_conf_file(void)
2477 char nmbuf[SYS_NMLN];
2478 char pname[PATH_MAX];
2480 if (sysinfo(SI_PLATFORM, nmbuf, sizeof (nmbuf)) != -1) {
2481 (void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf);
2482 (void) strlcat(pname, ASRTREE_CONFFILE_NAME, PATH_MAX);
2483 conf_name_asr_map = read_asr_conf_file(pname,
2484 conf_name_asr_map);
2487 if (sysinfo(SI_MACHINE, nmbuf, sizeof (nmbuf)) != -1) {
2488 (void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf);
2489 (void) strlcat(pname, ASRTREE_CONFFILE_NAME, PATH_MAX);
2490 conf_name_asr_map = read_asr_conf_file(pname,
2491 conf_name_asr_map);
2494 (void) snprintf(pname, PATH_MAX, "%s/%s", PICLD_COMMON_PLUGIN_DIR,
2495 ASRTREE_CONFFILE_NAME);
2496 conf_name_asr_map = read_asr_conf_file(pname, conf_name_asr_map);
2500 * This function reads the export file list from ASR
2502 static int
2503 get_asr_export_list(char **exportlist, int *exportlistlen)
2505 struct openpromio oppbuf;
2506 struct openpromio *opp = &oppbuf;
2507 int d;
2508 int listsize;
2510 d = open("/dev/openprom", O_RDWR);
2511 if (d < 0)
2512 return (0);
2514 if (ioctl(d, OPROMEXPORTLEN, opp) == -1) {
2515 (void) close(d);
2516 return (0);
2518 listsize = opp->oprom_size;
2519 opp = (struct openpromio *)malloc(sizeof (struct openpromio) +
2520 listsize);
2521 if (opp == NULL) {
2522 (void) close(d);
2523 return (0);
2525 (void) memset(opp, '\0', sizeof (struct openpromio) + listsize);
2526 opp->oprom_size = listsize;
2527 if (ioctl(d, OPROMEXPORT, opp) == -1) {
2528 free(opp);
2529 (void) close(d);
2530 return (0);
2532 *exportlist = malloc(listsize);
2533 if (*exportlist == NULL) {
2534 free(opp);
2535 (void) close(d);
2536 return (0);
2538 (void) memcpy(*exportlist, opp->oprom_array, opp->oprom_size);
2539 free(opp);
2540 *exportlistlen = opp->oprom_size;
2541 (void) close(d);
2542 return (1);
2546 * Parses properties string, fills in triplet structure with first
2547 * type, name, val triplet and returns pointer to next property.
2548 * Returns NULL if no valid triplet found
2549 * CAUTION: drops \0 characters over separator characters: if you
2550 * want to parse the string twice, you'll have to take a copy.
2552 static char *
2553 parse_props_string(char *props, asr_prop_triplet_t *triplet)
2555 char *prop_name;
2556 char *prop_val;
2557 char *prop_next;
2559 prop_name = strchr(props, '?');
2560 if (prop_name == NULL)
2561 return (NULL);
2562 *prop_name++ = '\0';
2563 prop_val = strchr(prop_name, '=');
2564 if (prop_val == NULL)
2565 return (NULL);
2566 *prop_val++ = '\0';
2567 triplet->proptype = props;
2568 triplet->propname = prop_name;
2569 triplet->propval = prop_val;
2570 prop_next = strchr(prop_val, ':');
2571 if (prop_next == NULL)
2572 return (prop_val - 1);
2573 *prop_next++ = '\0';
2574 return (prop_next);
2577 static int
2578 add_status_prop(picl_nodehdl_t chdh, char *status)
2580 ptree_propinfo_t propinfo;
2581 picl_prophdl_t proph;
2582 int err;
2584 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
2585 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(status) + 1,
2586 PICL_PROP_STATUS, NULL, NULL);
2587 if (err != PICL_SUCCESS)
2588 return (err);
2589 err = ptree_create_and_add_prop(chdh, &propinfo, status, &proph);
2590 return (err);
2593 static void
2594 create_asr_node(char *parent, char *child, char *unitaddr, char *class,
2595 char *status, char *props)
2597 char ptreepath[PATH_MAX];
2598 char nodename[PICL_PROPNAMELEN_MAX];
2599 char ua[MAX_UNIT_ADDRESS_LEN];
2600 char *props_copy = NULL;
2601 char *next;
2602 char *prop_string;
2603 boolean_t found = B_FALSE;
2604 picl_nodehdl_t nodeh;
2605 picl_nodehdl_t chdh;
2606 asr_prop_triplet_t triple;
2607 ptree_propinfo_t propinfo;
2608 picl_prophdl_t proph;
2609 int val;
2610 int err;
2612 (void) strlcpy(ptreepath, PLATFORM_PATH, PATH_MAX);
2613 (void) strlcat(ptreepath, parent, PATH_MAX);
2615 if (ptree_get_node_by_path(ptreepath, &nodeh) != PICL_SUCCESS)
2616 return;
2618 * see if the required child node already exists
2620 for (err = ptree_get_propval_by_name(nodeh, PICL_PROP_CHILD, &chdh,
2621 sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND;
2622 err = ptree_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh,
2623 sizeof (picl_nodehdl_t))) {
2624 if (err != PICL_SUCCESS)
2625 break;
2626 err = ptree_get_propval_by_name(chdh, PICL_PROP_NAME,
2627 (void *)nodename, PICL_PROPNAMELEN_MAX);
2628 if (err != PICL_SUCCESS)
2629 break;
2630 if (strcmp(nodename, child) != 0)
2631 continue;
2633 * found a candidate child node
2635 if (unitaddr) {
2637 * does it match the required unit address?
2639 err = ptree_get_propval_by_name(chdh,
2640 PICL_PROP_UNIT_ADDRESS, ua, sizeof (ua));
2641 if (err == PICL_PROPNOTFOUND)
2642 continue;
2643 if (err != PICL_SUCCESS)
2644 break;
2645 if (strcmp(unitaddr, ua) != 0)
2646 continue;
2648 if (props == NULL) {
2649 next = "";
2650 } else if (props_copy == NULL) {
2651 props_copy = strdup(props);
2652 if (props_copy == NULL)
2653 return;
2654 next = props_copy;
2656 while ((next = parse_props_string(next, &triple)) != NULL) {
2657 err = ptree_get_prop_by_name(chdh, triple.propname,
2658 &proph);
2659 if (err != PICL_SUCCESS)
2660 break;
2661 err = ptree_get_propinfo(proph, &propinfo);
2662 if (err != PICL_SUCCESS)
2663 break;
2664 err = PICL_FAILURE;
2665 switch (propinfo.piclinfo.type) {
2666 case PICL_PTYPE_INT:
2667 case PICL_PTYPE_UNSIGNED_INT:
2668 if (strcmp(triple.proptype, "I") != 0)
2669 break;
2670 err = ptree_get_propval(proph, (void *)&val,
2671 sizeof (val));
2672 if (err != PICL_SUCCESS)
2673 break;
2674 if (val != atoi(triple.propval))
2675 err = PICL_FAILURE;
2676 break;
2677 case PICL_PTYPE_CHARSTRING:
2678 if (strcmp(triple.proptype, "S") != 0)
2679 break;
2680 prop_string = malloc(propinfo.piclinfo.size);
2681 if (prop_string == NULL)
2682 break;
2683 err = ptree_get_propval(proph,
2684 (void *)prop_string,
2685 propinfo.piclinfo.size);
2686 if (err != PICL_SUCCESS) {
2687 free(prop_string);
2688 break;
2690 if (strcmp(prop_string, triple.propval) != 0)
2691 err = PICL_FAILURE;
2692 free(prop_string);
2693 break;
2694 default:
2695 break;
2697 if (err != PICL_SUCCESS) {
2698 break;
2701 if (next == NULL) {
2702 found = B_TRUE;
2703 break;
2706 free(props_copy);
2707 if (found) {
2709 * does the pre-existing node have a status property?
2711 err = ptree_get_propval_by_name(chdh, PICL_PROP_STATUS,
2712 ua, sizeof (ua));
2713 if (err == PICL_PROPNOTFOUND)
2714 (void) add_status_prop(chdh, status);
2715 if (err != PICL_SUCCESS)
2716 return;
2717 if ((strcmp(ua, ASR_DISABLED) == 0) ||
2718 (strcmp(ua, ASR_FAILED) == 0) ||
2719 ((strcmp(status, ASR_DISABLED) != 0) &&
2720 (strcmp(status, ASR_FAILED) != 0))) {
2721 return;
2724 * more urgent status now, so replace existing value
2726 err = ptree_get_prop_by_name(chdh, PICL_PROP_STATUS, &proph);
2727 if (err != PICL_SUCCESS)
2728 return;
2729 (void) ptree_delete_prop(proph);
2730 (void) ptree_destroy_prop(proph);
2731 err = add_status_prop(chdh, status);
2732 if (err != PICL_SUCCESS)
2733 return;
2734 return;
2738 * typical case, node needs adding together with a set of properties
2740 if (ptree_create_and_add_node(nodeh, child, class, &chdh) ==
2741 PICL_SUCCESS) {
2742 (void) add_status_prop(chdh, status);
2743 if (unitaddr) {
2744 (void) ptree_init_propinfo(&propinfo,
2745 PTREE_PROPINFO_VERSION, PICL_PTYPE_CHARSTRING,
2746 PICL_READ, strlen(unitaddr) + 1,
2747 PICL_PROP_UNIT_ADDRESS, NULL, NULL);
2748 (void) ptree_create_and_add_prop(chdh, &propinfo,
2749 unitaddr, &proph);
2750 (void) strlcpy(ptreepath, parent, PATH_MAX);
2751 (void) strlcat(ptreepath, "/", PATH_MAX);
2752 (void) strlcat(ptreepath, child, PATH_MAX);
2753 (void) strlcat(ptreepath, "@", PATH_MAX);
2754 (void) strlcat(ptreepath, unitaddr, PATH_MAX);
2755 (void) ptree_init_propinfo(&propinfo,
2756 PTREE_PROPINFO_VERSION, PICL_PTYPE_CHARSTRING,
2757 PICL_READ, strlen(ptreepath) + 1,
2758 PICL_PROP_DEVFS_PATH, NULL, NULL);
2759 (void) ptree_create_and_add_prop(chdh, &propinfo,
2760 ptreepath, &proph);
2762 next = props;
2763 while ((next = parse_props_string(next, &triple)) != NULL) {
2765 * only handle int and string properties for
2766 * simplicity
2768 if (strcmp(triple.proptype, "I") == 0) {
2769 (void) ptree_init_propinfo(&propinfo,
2770 PTREE_PROPINFO_VERSION,
2771 PICL_PTYPE_INT, PICL_READ,
2772 sizeof (int), triple.propname, NULL, NULL);
2773 val = atoi(triple.propval);
2774 (void) ptree_create_and_add_prop(chdh,
2775 &propinfo, &val, &proph);
2776 } else {
2777 (void) ptree_init_propinfo(&propinfo,
2778 PTREE_PROPINFO_VERSION,
2779 PICL_PTYPE_CHARSTRING, PICL_READ,
2780 strlen(triple.propval) + 1,
2781 triple.propname, NULL, NULL);
2782 (void) ptree_create_and_add_prop(chdh,
2783 &propinfo, triple.propval, &proph);
2789 static void
2790 add_asr_nodes()
2792 char *asrexport;
2793 int asrexportlen;
2794 asr_conf_entries_t *c = NULL;
2795 int i;
2796 char *key;
2797 char *child;
2798 char *unitaddr;
2799 uint16_t count;
2800 int disabled;
2802 if (get_asr_export_list(&asrexport, &asrexportlen) == 0)
2803 return;
2804 process_asrtree_conf_file();
2805 if (conf_name_asr_map == NULL)
2806 return;
2807 i = 0;
2808 while (i < asrexportlen) {
2809 key = &asrexport[i];
2810 i += strlen(key) + 1;
2811 if (i >= asrexportlen)
2812 break;
2815 * next byte tells us whether failed by diags or manually
2816 * disabled
2818 disabled = asrexport[i];
2819 i++;
2820 if (i >= asrexportlen)
2821 break;
2824 * only type 1 supported
2826 if (asrexport[i] != 1)
2827 break;
2828 i++;
2829 if (i >= asrexportlen)
2830 break;
2833 * next two bytes give size of reason string
2835 count = (asrexport[i] << 8) | asrexport[i + 1];
2836 i += count + 2;
2837 if (i > asrexportlen)
2838 break;
2841 * now look for key in conf file info
2843 c = conf_name_asr_map;
2844 while (c != NULL) {
2845 if (strcmp(key, c->name) == 0) {
2846 child = strrchr(c->address, '/');
2847 *child++ = '\0';
2848 unitaddr = strchr(child, '@');
2849 if (unitaddr)
2850 *unitaddr++ = '\0';
2851 if (strcmp(c->status, ASR_DISABLED) == 0) {
2852 create_asr_node(c->address, child,
2853 unitaddr, c->piclclass, disabled ?
2854 ASR_DISABLED : ASR_FAILED,
2855 c->props);
2856 } else {
2857 create_asr_node(c->address, child,
2858 unitaddr, c->piclclass, c->status,
2859 c->props);
2862 c = c->next;
2866 free_asr_conf_entries(conf_name_asr_map);
2867 free(asrexport);
2871 * This function adds information to the /platform node
2873 static int
2874 add_platform_info(picl_nodehdl_t plafh)
2876 struct utsname uts_info;
2877 int err;
2878 ptree_propinfo_t propinfo;
2879 picl_prophdl_t proph;
2881 if (uname(&uts_info) < 0)
2882 return (PICL_FAILURE);
2884 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
2885 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(uts_info.sysname) + 1,
2886 PICL_PROP_SYSNAME, NULL, NULL);
2887 err = ptree_create_and_add_prop(plafh, &propinfo, uts_info.sysname,
2888 &proph);
2889 if (err != PICL_SUCCESS)
2890 return (err);
2892 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
2893 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(uts_info.nodename) + 1,
2894 PICL_PROP_NODENAME, NULL, NULL);
2895 err = ptree_create_and_add_prop(plafh, &propinfo, uts_info.nodename,
2896 &proph);
2897 if (err != PICL_SUCCESS)
2898 return (err);
2900 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
2901 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(uts_info.release) + 1,
2902 PICL_PROP_RELEASE, NULL, NULL);
2903 err = ptree_create_and_add_prop(plafh, &propinfo, uts_info.release,
2904 &proph);
2905 if (err != PICL_SUCCESS)
2906 return (err);
2908 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
2909 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(uts_info.version) + 1,
2910 PICL_PROP_VERSION, NULL, NULL);
2911 err = ptree_create_and_add_prop(plafh, &propinfo, uts_info.version,
2912 &proph);
2913 if (err != PICL_SUCCESS)
2914 return (err);
2916 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
2917 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(uts_info.machine) + 1,
2918 PICL_PROP_MACHINE, NULL, NULL);
2919 err = ptree_create_and_add_prop(plafh, &propinfo, uts_info.machine,
2920 &proph);
2921 return (err);
2925 * Get first 32-bit value from the reg property
2927 static int
2928 get_first_reg_word(picl_nodehdl_t nodeh, uint32_t *regval)
2930 int err;
2931 uint32_t *regbuf;
2932 picl_prophdl_t regh;
2933 ptree_propinfo_t pinfo;
2935 err = ptree_get_prop_by_name(nodeh, OBP_REG, &regh);
2936 if (err != PICL_SUCCESS) /* no reg property */
2937 return (err);
2938 err = ptree_get_propinfo(regh, &pinfo);
2939 if (err != PICL_SUCCESS)
2940 return (err);
2941 if (pinfo.piclinfo.size < sizeof (uint32_t)) /* too small */
2942 return (PICL_FAILURE);
2943 regbuf = alloca(pinfo.piclinfo.size);
2944 if (regbuf == NULL)
2945 return (PICL_FAILURE);
2946 err = ptree_get_propval(regh, regbuf, pinfo.piclinfo.size);
2947 if (err != PICL_SUCCESS)
2948 return (err);
2949 *regval = *regbuf; /* get first 32-bit value */
2950 return (PICL_SUCCESS);
2954 * Get device ID from the reg property
2956 static int
2957 get_device_id(picl_nodehdl_t nodeh, uint32_t *dev_id)
2959 int err;
2960 uint32_t regval;
2962 err = get_first_reg_word(nodeh, &regval);
2963 if (err != PICL_SUCCESS)
2964 return (err);
2966 *dev_id = PCI_DEVICE_ID(regval);
2967 return (PICL_SUCCESS);
2971 * add Slot property for children of SBUS node
2973 /* ARGSUSED */
2974 static int
2975 add_sbus_slots(picl_nodehdl_t pcih, void *args)
2977 picl_nodehdl_t nodeh;
2978 uint32_t slot;
2979 int err;
2980 ptree_propinfo_t pinfo;
2982 for (err = ptree_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh,
2983 sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND;
2984 err = ptree_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh,
2985 sizeof (picl_nodehdl_t))) {
2986 if (err != PICL_SUCCESS)
2987 return (err);
2989 if (get_first_reg_word(nodeh, &slot) != 0)
2990 continue;
2991 (void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION,
2992 PICL_PTYPE_UNSIGNED_INT, PICL_READ, sizeof (uint32_t),
2993 PICL_PROP_SLOT, NULL, NULL);
2994 (void) ptree_create_and_add_prop(nodeh, &pinfo, &slot, NULL);
2997 return (PICL_WALK_CONTINUE);
3001 * This function creates a Slot property for SBUS child nodes
3002 * which can be correlated with the slot they are plugged into
3003 * on the motherboard.
3005 static int
3006 set_sbus_slot(picl_nodehdl_t plafh)
3008 int err;
3010 err = ptree_walk_tree_by_class(plafh, PICL_CLASS_SBUS, NULL,
3011 add_sbus_slots);
3013 return (err);
3017 * add DeviceID property for children of PCI/PCIEX node
3019 /* ARGSUSED */
3020 static int
3021 add_pci_deviceids(picl_nodehdl_t pcih, void *args)
3023 picl_nodehdl_t nodeh;
3024 uint32_t dev_id;
3025 int err;
3026 ptree_propinfo_t pinfo;
3028 for (err = ptree_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh,
3029 sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND;
3030 err = ptree_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh,
3031 sizeof (picl_nodehdl_t))) {
3032 if (err != PICL_SUCCESS)
3033 return (err);
3035 if (get_device_id(nodeh, &dev_id) != 0)
3036 continue;
3037 (void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION,
3038 PICL_PTYPE_UNSIGNED_INT, PICL_READ, sizeof (uint32_t),
3039 PICL_PROP_DEVICE_ID, NULL, NULL);
3040 (void) ptree_create_and_add_prop(nodeh, &pinfo, &dev_id, NULL);
3043 return (PICL_WALK_CONTINUE);
3047 * This function creates a DeviceID property for PCI/PCIEX child nodes
3048 * which can be correlated with the slot they are plugged into
3049 * on the motherboard.
3051 static void
3052 set_pci_pciex_deviceid(picl_nodehdl_t plafh)
3054 (void) ptree_walk_tree_by_class(plafh, PICL_CLASS_PCI, NULL,
3055 add_pci_deviceids);
3057 (void) ptree_walk_tree_by_class(plafh, PICL_CLASS_PCIEX, NULL,
3058 add_pci_deviceids);
3062 * Default UnitAddress encode function
3064 static int
3065 encode_default_unitaddr(char *buf, int sz, uint32_t *regprop, uint_t addrcells)
3067 int i, len;
3070 * Encode UnitAddress as %a,%b,%c,...,%n
3072 if (addrcells < 1)
3073 return (-1);
3075 len = snprintf(buf, sz, "%x", *regprop);
3076 for (i = 1; i < addrcells && len < sz; i++)
3077 len += snprintf(&buf[len], sz-len, ",%x", regprop[i]);
3079 return ((len >= sz) ? -1 : 0);
3083 * UnitAddress encode function where the last component is not printed
3084 * unless non-zero.
3086 static int
3087 encode_optional_unitaddr(char *buf, int sz, uint32_t *regprop, uint_t addrcells)
3089 int retval;
3092 * Encode UnitAddress as %a,%b,%c,...,%n where the last component
3093 * is printed only if non-zero.
3095 if (addrcells > 1 && regprop[addrcells-1] == 0)
3096 retval = encode_default_unitaddr(buf, sz, regprop, addrcells-1);
3097 else
3098 retval = encode_default_unitaddr(buf, sz, regprop, addrcells);
3100 return (retval);
3105 * UnitAddress encode function for SCSI class of devices
3107 static int
3108 encode_scsi_unitaddr(char *buf, int sz, uint32_t *regprop, uint_t addrcells)
3110 int len, retval;
3113 * #address-cells Format
3114 * 2 second component printed only if non-zero
3116 * 4 regprop: phys_hi phys_lo lun_hi lun_lo
3117 * UnitAddr: w<phys_hi><phys_lo>,<lun_lo>
3120 if (addrcells == 2) {
3121 retval = encode_optional_unitaddr(buf, sz, regprop, addrcells);
3122 } else if (addrcells == 4) {
3123 len = snprintf(buf, sz, "w%08x%08x,%x", regprop[0], regprop[1],
3124 regprop[3]);
3125 retval = (len >= sz) ? -1 : 0;
3126 } else
3127 retval = -1;
3129 return (retval);
3133 * UnitAddress encode function for UPA devices
3135 static int
3136 encode_upa_unitaddr(char *buf, int sz, uint32_t *regprop, uint_t addrcells)
3138 int len;
3140 if (addrcells != 2)
3141 return (-1);
3143 len = snprintf(buf, sz, "%x,%x", (regprop[0]/2)&0x1f, regprop[1]);
3144 return ((len >= sz) ? -1 : 0);
3148 * UnitAddress encode function for GPTWO, JBUS devices
3150 static int
3151 encode_gptwo_jbus_unitaddr(char *buf, int sz, uint32_t *regprop,
3152 uint_t addrcells)
3154 uint32_t hi, lo;
3155 int len, id, off;
3157 if (addrcells != 2)
3158 return (-1);
3160 hi = regprop[0];
3161 lo = regprop[1];
3163 if (hi & 0x400) {
3164 id = ((hi & 0x1) << 9) | (lo >> 23); /* agent id */
3165 off = lo & 0x7fffff; /* config offset */
3166 len = snprintf(buf, sz, "%x,%x", id, off);
3167 } else {
3168 len = snprintf(buf, sz, "m%x,%x", hi, lo);
3170 return ((len >= sz) ? -1 : 0);
3174 * UnitAddress encode function for PCI devices
3176 static int
3177 encode_pci_unitaddr(char *buf, int sz, uint32_t *regprop, uint_t addrcells)
3179 typedef struct {
3180 uint32_t n:1, /* relocatable */
3181 p:1, /* prefetchable */
3182 t:1, /* address region aliases */
3183 zero:3, /* must be zero */
3184 ss:2, /* address space type */
3185 bus:8, /* bus number */
3186 dev:5, /* device number */
3187 fn:3, /* function number */
3188 reg:8; /* register number */
3189 uint32_t phys_hi; /* high physical address */
3190 uint32_t phys_lo; /* low physical address */
3191 } pci_addrcell_t;
3193 pci_addrcell_t *p;
3194 int len;
3196 if (addrcells != 3)
3197 return (-1);
3199 p = (pci_addrcell_t *)regprop;
3200 switch (p->ss) {
3201 case 0: /* Config */
3202 if (p->fn)
3203 len = snprintf(buf, sz, "%x,%x", p->dev, p->fn);
3204 else
3205 len = snprintf(buf, sz, "%x", p->dev);
3206 break;
3207 case 1: /* IO */
3208 len = snprintf(buf, sz, "i%x,%x,%x,%x", p->dev, p->fn, p->reg,
3209 p->phys_lo);
3210 break;
3211 case 2: /* Mem32 */
3212 len = snprintf(buf, sz, "m%x,%x,%x,%x", p->dev, p->fn, p->reg,
3213 p->phys_lo);
3214 break;
3215 case 3: /* Mem64 */
3216 len = snprintf(buf, sz, "x%x,%x,%x,%x%08x", p->dev, p->fn,
3217 p->reg, p->phys_hi, p->phys_lo);
3218 break;
3220 return ((len >= sz) ? -1 : 0);
3224 * Get #address-cells property value
3226 static uint_t
3227 get_addrcells_prop(picl_nodehdl_t nodeh)
3229 int len, err;
3230 uint32_t addrcells;
3231 ptree_propinfo_t pinfo;
3232 picl_prophdl_t proph;
3235 * Get #address-cells property. If not present, use default value.
3237 err = ptree_get_prop_by_name(nodeh, OBP_PROP_ADDRESS_CELLS, &proph);
3238 if (err == PICL_SUCCESS)
3239 err = ptree_get_propinfo(proph, &pinfo);
3241 len = pinfo.piclinfo.size;
3242 if (err == PICL_SUCCESS && len >= sizeof (uint8_t) &&
3243 len <= sizeof (addrcells)) {
3244 err = ptree_get_propval(proph, &addrcells, len);
3245 if (err == PICL_SUCCESS) {
3246 if (len == sizeof (uint8_t))
3247 addrcells = *(uint8_t *)&addrcells;
3248 else if (len == sizeof (uint16_t))
3249 addrcells = *(uint16_t *)&addrcells;
3250 } else
3251 addrcells = DEFAULT_ADDRESS_CELLS;
3252 } else
3253 addrcells = DEFAULT_ADDRESS_CELLS;
3255 return (addrcells);
3259 * Get UnitAddress mapping entry for a node
3261 static unitaddr_map_t *
3262 get_unitaddr_mapping(picl_nodehdl_t nodeh)
3264 int err;
3265 unitaddr_map_t *uamap;
3266 char clname[PICL_CLASSNAMELEN_MAX];
3269 * Get my classname and locate a function to translate "reg" prop
3270 * into "UnitAddress" prop for my children.
3272 err = ptree_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME, clname,
3273 sizeof (clname));
3274 if (err != PICL_SUCCESS)
3275 (void) strcpy(clname, ""); /* NULL class name */
3277 for (uamap = &unitaddr_map_table[0]; uamap->class != NULL; uamap++)
3278 if (strcmp(clname, uamap->class) == 0)
3279 break;
3281 return (uamap);
3285 * Add UnitAddress property to the specified node
3287 static int
3288 add_unitaddr_prop(picl_nodehdl_t nodeh, unitaddr_map_t *uamap, uint_t addrcells)
3290 int regproplen, err;
3291 uint32_t *regbuf;
3292 picl_prophdl_t regh;
3293 ptree_propinfo_t pinfo;
3294 char unitaddr[MAX_UNIT_ADDRESS_LEN];
3296 err = ptree_get_prop_by_name(nodeh, OBP_REG, &regh);
3297 if (err != PICL_SUCCESS)
3298 return (err);
3300 err = ptree_get_propinfo(regh, &pinfo);
3301 if (err != PICL_SUCCESS)
3302 return (PICL_FAILURE);
3304 if (pinfo.piclinfo.size < (addrcells * sizeof (uint32_t)))
3305 return (PICL_FAILURE);
3307 regproplen = pinfo.piclinfo.size;
3308 regbuf = alloca(regproplen);
3309 if (regbuf == NULL)
3310 return (PICL_FAILURE);
3312 err = ptree_get_propval(regh, regbuf, regproplen);
3313 if (err != PICL_SUCCESS || uamap->func == NULL ||
3314 (uamap->addrcellcnt && uamap->addrcellcnt != addrcells) ||
3315 (uamap->func)(unitaddr, sizeof (unitaddr), regbuf,
3316 addrcells) != 0) {
3317 return (PICL_FAILURE);
3320 err = ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION,
3321 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(unitaddr)+1,
3322 PICL_PROP_UNIT_ADDRESS, NULL, NULL);
3323 if (err == PICL_SUCCESS)
3324 err = ptree_create_and_add_prop(nodeh, &pinfo, unitaddr, NULL);
3326 return (err);
3330 * work out UnitAddress property of the specified node
3332 static int
3333 get_unitaddr(picl_nodehdl_t parh, picl_nodehdl_t nodeh, char *unitaddr,
3334 size_t ualen)
3336 int regproplen, err;
3337 uint32_t *regbuf;
3338 picl_prophdl_t regh;
3339 ptree_propinfo_t pinfo;
3340 unitaddr_map_t *uamap;
3341 uint32_t addrcells;
3343 addrcells = get_addrcells_prop(parh);
3344 uamap = get_unitaddr_mapping(parh);
3346 err = ptree_get_prop_by_name(nodeh, OBP_REG, &regh);
3347 if (err != PICL_SUCCESS)
3348 return (err);
3350 err = ptree_get_propinfo(regh, &pinfo);
3351 if (err != PICL_SUCCESS)
3352 return (err);
3354 if (pinfo.piclinfo.size < (addrcells * sizeof (uint32_t)))
3355 return (PICL_FAILURE);
3357 regproplen = pinfo.piclinfo.size;
3358 regbuf = alloca(regproplen);
3359 if (regbuf == NULL)
3360 return (PICL_FAILURE);
3362 err = ptree_get_propval(regh, regbuf, regproplen);
3363 if (err != PICL_SUCCESS || uamap->func == NULL ||
3364 (uamap->addrcellcnt && uamap->addrcellcnt != addrcells) ||
3365 (uamap->func)(unitaddr, ualen, regbuf, addrcells) != 0) {
3366 return (PICL_FAILURE);
3368 return (PICL_SUCCESS);
3372 * Add UnitAddress property to all children of the specified node
3374 static int
3375 add_unitaddr_prop_to_subtree(picl_nodehdl_t nodeh)
3377 int err;
3378 picl_nodehdl_t chdh;
3379 unitaddr_map_t *uamap;
3380 uint32_t addrcells;
3383 * Get #address-cells and unit address mapping entry for my
3384 * node's class
3386 addrcells = get_addrcells_prop(nodeh);
3387 uamap = get_unitaddr_mapping(nodeh);
3390 * Add UnitAddress property to my children and their subtree
3392 err = ptree_get_propval_by_name(nodeh, PICL_PROP_CHILD, &chdh,
3393 sizeof (picl_nodehdl_t));
3395 while (err == PICL_SUCCESS) {
3396 (void) add_unitaddr_prop(chdh, uamap, addrcells);
3397 (void) add_unitaddr_prop_to_subtree(chdh);
3399 err = ptree_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh,
3400 sizeof (picl_nodehdl_t));
3403 return (PICL_SUCCESS);
3406 static int
3407 update_memory_size_prop(picl_nodehdl_t plafh)
3409 picl_nodehdl_t memh;
3410 picl_prophdl_t proph;
3411 ptree_propinfo_t pinfo;
3412 int err, nspecs, snum, pval;
3413 char *regbuf;
3414 memspecs_t *mspecs;
3415 uint64_t memsize;
3418 * check if the #size-cells of the platform node is 2
3420 err = ptree_get_propval_by_name(plafh, OBP_PROP_SIZE_CELLS, &pval,
3421 sizeof (pval));
3423 if (err == PICL_PROPNOTFOUND)
3424 pval = SUPPORTED_NUM_CELL_SIZE;
3425 else if (err != PICL_SUCCESS)
3426 return (err);
3429 * don't know how to handle other vals
3431 if (pval != SUPPORTED_NUM_CELL_SIZE)
3432 return (PICL_FAILURE);
3434 err = ptree_get_node_by_path(MEMORY_PATH, &memh);
3435 if (err != PICL_SUCCESS)
3436 return (err);
3439 * Get the REG property to calculate the size of memory
3441 err = ptree_get_prop_by_name(memh, OBP_REG, &proph);
3442 if (err != PICL_SUCCESS)
3443 return (err);
3445 err = ptree_get_propinfo(proph, &pinfo);
3446 if (err != PICL_SUCCESS)
3447 return (err);
3449 regbuf = alloca(pinfo.piclinfo.size);
3450 if (regbuf == NULL)
3451 return (PICL_FAILURE);
3453 err = ptree_get_propval(proph, regbuf, pinfo.piclinfo.size);
3454 if (err != PICL_SUCCESS)
3455 return (err);
3457 mspecs = (memspecs_t *)regbuf;
3458 nspecs = pinfo.piclinfo.size / sizeof (memspecs_t);
3460 memsize = 0;
3461 for (snum = 0; snum < nspecs; ++snum)
3462 memsize += mspecs[snum].size;
3464 err = ptree_get_prop_by_name(memh, PICL_PROP_SIZE, &proph);
3465 if (err == PICL_SUCCESS) {
3466 err = ptree_update_propval(proph, &memsize, sizeof (memsize));
3467 return (err);
3471 * Add the size property
3473 (void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION,
3474 PICL_PTYPE_UNSIGNED_INT, PICL_READ, sizeof (memsize),
3475 PICL_PROP_SIZE, NULL, NULL);
3476 err = ptree_create_and_add_prop(memh, &pinfo, &memsize, NULL);
3477 return (err);
3481 * This function is executed as part of .init when the plugin is
3482 * dlopen()ed
3484 static void
3485 picldevtree_register(void)
3487 if (getenv(SUNW_PICLDEVTREE_PLUGIN_DEBUG))
3488 picldevtree_debug = 1;
3489 (void) picld_plugin_register(&my_reg_info);
3493 * This function is the init entry point of the plugin.
3494 * It initializes the /platform tree based on libdevinfo
3496 static void
3497 picldevtree_init(void)
3499 picl_nodehdl_t rhdl;
3500 int err;
3501 struct utsname utsname;
3502 picl_nodehdl_t plafh;
3504 if (uname(&utsname) < 0)
3505 return;
3507 (void) strcpy(mach_name, utsname.machine);
3509 if (strcmp(mach_name, "sun4u") == 0) {
3510 builtin_map_ptr = sun4u_map;
3511 builtin_map_size = sizeof (sun4u_map) / sizeof (builtin_map_t);
3512 } else if (strcmp(mach_name, "sun4v") == 0) {
3513 builtin_map_ptr = sun4u_map;
3514 builtin_map_size = sizeof (sun4u_map) / sizeof (builtin_map_t);
3515 } else if (strcmp(mach_name, "i86pc") == 0) {
3516 builtin_map_ptr = i86pc_map;
3517 builtin_map_size = sizeof (i86pc_map) / sizeof (builtin_map_t);
3518 } else {
3519 builtin_map_ptr = NULL;
3520 builtin_map_size = 0;
3523 err = ptree_get_root(&rhdl);
3524 if (err != PICL_SUCCESS) {
3525 syslog(LOG_ERR, DEVINFO_PLUGIN_INIT_FAILED);
3526 return;
3529 process_devtree_conf_file();
3531 if (libdevinfo_init(rhdl) != PICL_SUCCESS) {
3532 syslog(LOG_ERR, DEVINFO_PLUGIN_INIT_FAILED);
3533 return;
3536 err = ptree_get_node_by_path(PLATFORM_PATH, &plafh);
3537 if (err != PICL_SUCCESS)
3538 return;
3540 (void) add_unitaddr_prop_to_subtree(plafh);
3542 add_asr_nodes();
3544 (void) update_memory_size_prop(plafh);
3546 (void) setup_cpus(plafh);
3548 (void) add_ffb_config_info(plafh);
3550 (void) add_platform_info(plafh);
3552 set_pci_pciex_deviceid(plafh);
3554 (void) set_sbus_slot(plafh);
3556 (void) ptree_register_handler(PICLEVENT_SYSEVENT_DEVICE_ADDED,
3557 picldevtree_evhandler, NULL);
3558 (void) ptree_register_handler(PICLEVENT_SYSEVENT_DEVICE_REMOVED,
3559 picldevtree_evhandler, NULL);
3560 (void) ptree_register_handler(PICLEVENT_CPU_STATE_CHANGE,
3561 picldevtree_evhandler, NULL);
3562 (void) ptree_register_handler(PICLEVENT_DR_AP_STATE_CHANGE,
3563 picldevtree_evhandler, NULL);
3567 * This function is the fini entry point of the plugin
3569 static void
3570 picldevtree_fini(void)
3572 /* First unregister the event handlers */
3573 (void) ptree_unregister_handler(PICLEVENT_SYSEVENT_DEVICE_ADDED,
3574 picldevtree_evhandler, NULL);
3575 (void) ptree_unregister_handler(PICLEVENT_SYSEVENT_DEVICE_REMOVED,
3576 picldevtree_evhandler, NULL);
3577 (void) ptree_unregister_handler(PICLEVENT_CPU_STATE_CHANGE,
3578 picldevtree_evhandler, NULL);
3579 (void) ptree_unregister_handler(PICLEVENT_DR_AP_STATE_CHANGE,
3580 picldevtree_evhandler, NULL);
3582 conf_name_class_map = free_conf_entries(conf_name_class_map);
3586 * This function is the event handler of this plug-in.
3588 * It processes the following events:
3590 * PICLEVENT_SYSEVENT_DEVICE_ADDED
3591 * PICLEVENT_SYSEVENT_DEVICE_REMOVED
3592 * PICLEVENT_CPU_STATE_CHANGE
3593 * PICLEVENT_DR_AP_STATE_CHANGE
3595 /* ARGSUSED */
3596 static void
3597 picldevtree_evhandler(const char *ename, const void *earg, size_t size,
3598 void *cookie)
3600 char *devfs_path;
3601 char ptreepath[PATH_MAX];
3602 char dipath[PATH_MAX];
3603 picl_nodehdl_t plafh;
3604 picl_nodehdl_t nodeh;
3605 nvlist_t *nvlp;
3607 if ((earg == NULL) ||
3608 (ptree_get_node_by_path(PLATFORM_PATH, &plafh) != PICL_SUCCESS))
3609 return;
3611 if (strcmp(ename, PICLEVENT_DR_AP_STATE_CHANGE) == 0) {
3612 (void) setup_cpus(plafh);
3613 if (picldevtree_debug > 1)
3614 syslog(LOG_INFO, "picldevtree: event handler done\n");
3615 return;
3618 nvlp = NULL;
3619 if (nvlist_unpack((char *)earg, size, &nvlp, 0) ||
3620 nvlist_lookup_string(nvlp, PICLEVENTARG_DEVFS_PATH, &devfs_path) ||
3621 strlen(devfs_path) > (PATH_MAX - sizeof (PLATFORM_PATH))) {
3622 syslog(LOG_INFO, PICL_EVENT_DROPPED, ename);
3623 nvlist_free(nvlp);
3624 return;
3627 (void) strlcpy(ptreepath, PLATFORM_PATH, PATH_MAX);
3628 (void) strlcat(ptreepath, devfs_path, PATH_MAX);
3629 (void) strlcpy(dipath, devfs_path, PATH_MAX);
3630 nvlist_free(nvlp);
3632 if (picldevtree_debug)
3633 syslog(LOG_INFO, "picldevtree: event handler invoked ename:%s "
3634 "ptreepath:%s\n", ename, ptreepath);
3636 if (strcmp(ename, PICLEVENT_CPU_STATE_CHANGE) == 0) {
3637 goto done;
3639 if (strcmp(ename, PICLEVENT_SYSEVENT_DEVICE_ADDED) == 0) {
3640 di_node_t devnode;
3641 char *strp;
3642 picl_nodehdl_t parh;
3643 char nodeclass[PICL_CLASSNAMELEN_MAX];
3644 char *nodename;
3645 int err;
3647 /* If the node already exist, then nothing else to do here */
3648 if (ptree_get_node_by_path(ptreepath, &nodeh) == PICL_SUCCESS)
3649 return;
3651 /* Skip if unable to find parent PICL node handle */
3652 parh = plafh;
3653 if (((strp = strrchr(ptreepath, '/')) != NULL) &&
3654 (strp != strchr(ptreepath, '/'))) {
3655 *strp = '\0';
3656 if (ptree_get_node_by_path(ptreepath, &parh) !=
3657 PICL_SUCCESS)
3658 return;
3662 * If parent is the root node
3664 if (parh == plafh) {
3665 ph = di_prom_init();
3666 devnode = di_init(dipath, DINFOCPYALL);
3667 if (devnode == DI_NODE_NIL) {
3668 if (ph != NULL) {
3669 di_prom_fini(ph);
3670 ph = NULL;
3672 return;
3674 nodename = di_node_name(devnode);
3675 if (nodename == NULL) {
3676 di_fini(devnode);
3677 if (ph != NULL) {
3678 di_prom_fini(ph);
3679 ph = NULL;
3681 return;
3684 err = get_node_class(nodeclass, devnode, nodename);
3685 if (err < 0) {
3686 di_fini(devnode);
3687 if (ph != NULL) {
3688 di_prom_fini(ph);
3689 ph = NULL;
3691 return;
3693 err = construct_devtype_node(plafh, nodename,
3694 nodeclass, devnode, &nodeh);
3695 if (err != PICL_SUCCESS) {
3696 di_fini(devnode);
3697 if (ph != NULL) {
3698 di_prom_fini(ph);
3699 ph = NULL;
3701 return;
3703 (void) update_subtree(nodeh, devnode);
3704 (void) add_unitaddr_prop_to_subtree(nodeh);
3705 if (ph != NULL) {
3706 di_prom_fini(ph);
3707 ph = NULL;
3709 di_fini(devnode);
3710 goto done;
3713 /* kludge ... try without bus-addr first */
3714 if ((strp = strrchr(dipath, '@')) != NULL) {
3715 char *p;
3717 p = strrchr(dipath, '/');
3718 if (p != NULL && strp > p) {
3719 *strp = '\0';
3720 devnode = di_init(dipath, DINFOCPYALL);
3721 if (devnode != DI_NODE_NIL)
3722 di_fini(devnode);
3723 *strp = '@';
3726 /* Get parent devnode */
3727 if ((strp = strrchr(dipath, '/')) != NULL)
3728 *++strp = '\0';
3729 devnode = di_init(dipath, DINFOCPYALL);
3730 if (devnode == DI_NODE_NIL)
3731 return;
3732 ph = di_prom_init();
3733 (void) update_subtree(parh, devnode);
3734 (void) add_unitaddr_prop_to_subtree(parh);
3735 if (ph) {
3736 di_prom_fini(ph);
3737 ph = NULL;
3739 di_fini(devnode);
3740 } else if (strcmp(ename, PICLEVENT_SYSEVENT_DEVICE_REMOVED) == 0) {
3741 char delclass[PICL_CLASSNAMELEN_MAX];
3742 char *strp;
3745 * if final element of path doesn't have a unit address
3746 * then it is not uniquely identifiable - cannot remove
3748 if (((strp = strrchr(ptreepath, '/')) != NULL) &&
3749 strchr(strp, '@') == NULL)
3750 return;
3752 /* skip if can't find the node */
3753 if (ptree_get_node_by_path(ptreepath, &nodeh) != PICL_SUCCESS)
3754 return;
3756 if (ptree_delete_node(nodeh) != PICL_SUCCESS)
3757 return;
3759 if (picldevtree_debug)
3760 syslog(LOG_INFO,
3761 "picldevtree: deleted node nodeh:%llx\n", nodeh);
3762 if ((ptree_get_propval_by_name(nodeh,
3763 PICL_PROP_CLASSNAME, delclass, PICL_CLASSNAMELEN_MAX) ==
3764 PICL_SUCCESS) && IS_MC(delclass)) {
3765 if (post_mc_event(PICLEVENT_MC_REMOVED, nodeh) !=
3766 PICL_SUCCESS)
3767 syslog(LOG_WARNING, PICL_EVENT_DROPPED,
3768 PICLEVENT_MC_REMOVED);
3769 } else
3770 (void) ptree_destroy_node(nodeh);
3772 done:
3773 (void) setup_cpus(plafh);
3774 (void) add_ffb_config_info(plafh);
3775 set_pci_pciex_deviceid(plafh);
3776 (void) set_sbus_slot(plafh);
3777 if (picldevtree_debug > 1)
3778 syslog(LOG_INFO, "picldevtree: event handler done\n");