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]
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
40 #include <libdevinfo.h>
47 #include <sys/types.h>
48 #include <sys/processor.h>
50 #include <sys/sysinfo.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)
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)
87 static picld_plugin_reg_t my_reg_info
= {
88 PICLD_PLUGIN_VERSION_1
,
89 PICLD_PLUGIN_CRITICAL
,
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
},
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
},
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.
278 mc_completion_handler(char *ename
, void *earg
, size_t size
)
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
)
291 "picldevtree: destroying_node:%llx\n",
293 (void) ptree_destroy_node(mch
);
295 nvlist_free(unpack_nvl
);
303 * Functions to post memory controller change event
306 post_mc_event(char *ename
, picl_nodehdl_t mch
)
313 ev_name
= strdup(ename
);
317 if (nvlist_alloc(&nvl
, NV_UNIQUE_NAME_TYPE
, 0)) {
323 if (nvlist_add_uint64(nvl
, PICLEVENTARG_NODEHANDLE
, mch
) ||
324 nvlist_pack(nvl
, &pack_buf
, &nvl_size
, NV_ENCODE_NATIVE
, 0)) {
330 if (picldevtree_debug
)
332 "picldevtree: posting MC event ename:%s nodeh:%llx\n",
334 if (ptree_post_event(ev_name
, pack_buf
, nvl_size
,
335 mc_completion_handler
) != PICL_SUCCESS
) {
345 * Lookup a name in the name to class map tables
348 lookup_name_class_map(char *classbuf
, const char *nm
)
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
);
368 * check name to class mapping in builtin table
370 if (builtin_map_ptr
== NULL
)
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
);
383 * Lookup a prop name in the pname to class map table
386 lookup_pname_type_map(const char *pname
, picl_prop_type_t
*type
)
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
;
400 * Return the number of strings in the buffer
403 get_string_count(char *strdat
, int length
)
410 for (lastnull
= &strdat
[length
- 1], nullptr = strchr(strdat
, '\0');
411 nullptr != lastnull
; nullptr = strchr(nullptr+1, '\0'))
418 * Return 1 if the node has a "reg" property
421 has_reg_prop(di_node_t dn
)
426 dret
= di_prop_lookup_ints(DDI_DEV_T_ANY
, dn
, OBP_REG
, &pdata
);
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'
444 get_device_type(char *outbuf
, di_node_t dn
)
451 dret
= di_prop_lookup_strings(DDI_DEV_T_ANY
, dn
, OBP_DEVICETYPE
,
457 dret
= di_prom_prop_lookup_strings(ph
, dn
, OBP_DEVICETYPE
,
469 for (i
= 0; i
< (dret
- 1); ++i
) {
470 pdatap
+= strlen(pdatap
);
471 *pdatap
= '-'; /* replace '\0' with '-' */
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
);
482 (void) strlcpy(outbuf
, pdata
, PICL_CLASSNAMELEN_MAX
);
488 * Get the minor node name in the class buffer passed
491 get_minor_class(char *classbuf
, di_node_t dn
)
497 /* get minor node type */
498 mi_node
= di_minor_next(dn
, DI_MINOR_NIL
);
499 if (mi_node
== DI_MINOR_NIL
)
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
);
507 (void) strlcpy(classbuf
, mi_name
, PICL_CLASSNAMELEN_MAX
);
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
))
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
)) {
547 if ((colon
= strchr(mi_nodetype
, ':')) == NULL
)
550 (void) strcpy(classbuf
, colon
);
551 } else { /* unrecognized type, return name */
552 mi_name
= di_minor_name(mi_node
);
555 (void) strlcpy(classbuf
, mi_name
, PICL_CLASSNAMELEN_MAX
);
561 * Derive PICL class using the compatible property of the node
562 * We use the map table to map compatible property value to
566 get_compatible_class(char *outbuf
, di_node_t dn
)
573 dret
= di_prop_lookup_strings(DDI_DEV_T_ANY
, dn
, OBP_COMPATIBLE
,
579 dret
= di_prom_prop_lookup_strings(ph
, dn
, OBP_COMPATIBLE
,
587 for (i
= 0; i
< dret
; ++i
) {
588 if (lookup_name_class_map(outbuf
, pdatap
) == 0)
590 pdatap
+= strlen(pdatap
);
597 * For a given device node find the PICL class to use. Returns NULL
598 * for non device node
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))
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
);
632 return (get_minor_class(classbuf
, dn
));
636 * Add a table property containing nrows with one column
639 add_string_list_prop(picl_nodehdl_t nodeh
, char *name
, char *strlist
,
642 ptree_propinfo_t propinfo
;
643 picl_prophdl_t proph
;
648 picl_prophdl_t
*proprow
;
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
,
656 if (err
!= PICL_SUCCESS
)
659 err
= ptree_create_table(&tblh
);
660 if (err
!= PICL_SUCCESS
)
663 err
= ptree_create_and_add_prop(nodeh
, &propinfo
, &tblh
, &proph
);
664 if (err
!= PICL_SUCCESS
)
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
,
678 if (err
!= PICL_SUCCESS
)
680 err
= ptree_create_prop(&propinfo
, strlist
, &proprow
[j
]);
681 if (err
!= PICL_SUCCESS
)
684 err
= ptree_add_row_to_table(tblh
, NCOLS_IN_STRING_TABLE
,
686 if (err
!= PICL_SUCCESS
)
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
);
698 return (PICL_SUCCESS
);
702 * return 1 if this node has this property with the given value
705 compare_string_propval(picl_nodehdl_t nodeh
, const char *pname
,
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 */
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
);
728 err
= ptree_get_propval(proph
, pvalbuf
, len
);
729 if ((err
== PICL_SUCCESS
) && (strcmp(pvalbuf
, pval
) == 0))
730 return (1); /* prop match */
736 * This function recursively searches the tree for a node that has
737 * the specified string property name and value
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
;
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
)
753 if (compare_string_propval(childh
, pname
, pval
)) {
755 return (PICL_SUCCESS
);
758 if (find_node_by_string_prop(childh
, pname
, pval
, nodeh
) ==
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
775 is_string_propval(unsigned char *pdata
, int len
)
783 if (!isascii(pdata
[0]) || !isprint(pdata
[0]))
790 if (pdata
[len
-1] == '\0')
793 for (i
= 0; i
< lastindex
; i
++)
794 if (!isascii(pdata
[i
]) || !isprint(pdata
[i
]))
802 for (i
= 0; i
< len
; i
++) {
803 if (!isascii(pdata
[i
]) || !isprint(pdata
[i
])) {
804 if (pdata
[i
] != '\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))
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.
832 process_charstring_data(picl_nodehdl_t nodeh
, char *pname
, unsigned char *pdata
,
838 ptree_propinfo_t propinfo
;
841 * append the null char at the end of string when there is
844 if (pdata
[retval
- 1] != '\0') {
845 strdat
= alloca(retval
+ 1);
846 (void) memcpy(strdat
, pdata
, retval
);
847 strdat
[retval
] = '\0';
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
);
859 err
= add_string_list_prop(nodeh
, pname
,
861 if (err
!= PICL_SUCCESS
)
864 err
= ptree_init_propinfo(&propinfo
, PTREE_PROPINFO_VERSION
,
865 PICL_PTYPE_CHARSTRING
, PICL_READ
,
866 strlen(strdat
) + 1, pname
, NULL
,
868 if (err
!= PICL_SUCCESS
)
870 (void) ptree_create_and_add_prop(nodeh
, &propinfo
,
873 return (PICL_SUCCESS
);
877 * Add the OBP properties as properties of the PICL node
880 add_openprom_props(picl_nodehdl_t nodeh
, di_node_t di_node
)
882 di_prom_prop_t promp
;
884 unsigned char *pdata
;
886 ptree_propinfo_t propinfo
;
888 picl_prop_type_t type
;
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
);
901 return (PICL_SUCCESS
);
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
) {
910 (void) ptree_create_and_add_prop(nodeh
, &propinfo
, NULL
,
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
,
922 if (err
!= PICL_SUCCESS
) {
928 err
= ptree_init_propinfo(&propinfo
,
929 PTREE_PROPINFO_VERSION
, type
, PICL_READ
,
930 retval
, pname
, NULL
, NULL
);
931 if (err
!= PICL_SUCCESS
) {
934 (void) ptree_create_and_add_prop(nodeh
, &propinfo
,
936 } else if (!is_string_propval(pdata
, retval
)) {
938 case sizeof (uint8_t):
940 case sizeof (uint16_t):
942 case sizeof (uint32_t):
943 type
= PICL_PTYPE_UNSIGNED_INT
;
946 type
= PICL_PTYPE_BYTEARRAY
;
949 err
= ptree_init_propinfo(&propinfo
,
950 PTREE_PROPINFO_VERSION
, type
, PICL_READ
,
951 retval
, pname
, NULL
, NULL
);
952 if (err
!= PICL_SUCCESS
) {
955 (void) ptree_create_and_add_prop(nodeh
, &propinfo
,
958 err
= process_charstring_data(nodeh
, pname
, pdata
,
960 if (err
!= PICL_SUCCESS
) {
966 return (PICL_SUCCESS
);
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
);
978 add_uints_prop(picl_nodehdl_t nodeh
, ptree_propinfo_t propinfo
, char *di_val
,
982 (void) ptree_init_propinfo(&propinfo
, PTREE_PROPINFO_VERSION
,
983 PICL_PTYPE_UNSIGNED_INT
, PICL_READ
, sizeof (int), di_val
,
986 (void) ptree_init_propinfo(&propinfo
, PTREE_PROPINFO_VERSION
,
987 PICL_PTYPE_BYTEARRAY
, PICL_READ
, len
* sizeof (int), di_val
,
990 (void) ptree_create_and_add_prop(nodeh
, &propinfo
, idata
, NULL
);
994 add_strings_prop(picl_nodehdl_t nodeh
, ptree_propinfo_t propinfo
, char *di_val
,
995 char *sdata
, int len
)
998 (void) ptree_init_propinfo(&propinfo
, PTREE_PROPINFO_VERSION
,
999 PICL_PTYPE_CHARSTRING
, PICL_READ
, strlen(sdata
) + 1, di_val
,
1001 (void) ptree_create_and_add_prop(nodeh
, &propinfo
, sdata
, NULL
);
1003 (void) add_string_list_prop(nodeh
, di_val
, sdata
, len
);
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
);
1017 path_state_name(di_path_state_t st
)
1020 case DI_PATH_STATE_ONLINE
:
1022 case DI_PATH_STATE_STANDBY
:
1024 case DI_PATH_STATE_OFFLINE
:
1026 case DI_PATH_STATE_FAULT
:
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.
1039 get_path_state_name(ptree_rarg_t
*rarg
, void *vbuf
)
1042 picl_nodehdl_t parh
;
1043 char devfs_path
[PATH_MAX
];
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
) {
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
) {
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
) {
1102 di_node_t phci_node
= di_path_phci_node(pi
);
1104 if (phci_node
== DI_PATH_NIL
)
1107 di_path
= di_devfs_path(phci_node
);
1109 if (strcmp(di_path
, devfs_path
) != 0) {
1110 di_devfs_path_free(di_path
);
1113 (void) strlcpy(vbuf
, path_state_name(di_path_state(pi
)),
1115 di_devfs_path_free(di_path
);
1121 return (PICL_SUCCESS
);
1125 add_di_path_prop(picl_nodehdl_t nodeh
, di_path_prop_t di_path_prop
)
1129 ptree_propinfo_t propinfo
;
1132 unsigned char *bdata
;
1135 di_ptype
= di_path_prop_type(di_path_prop
);
1136 di_val
= di_path_prop_name(di_path_prop
);
1139 case DI_PROP_TYPE_BOOLEAN
:
1140 add_boolean_prop(nodeh
, propinfo
, di_val
);
1142 case DI_PROP_TYPE_INT
:
1143 case DI_PROP_TYPE_INT64
:
1144 len
= di_path_prop_ints(di_path_prop
, &idata
);
1146 /* Received error, so ignore prop */
1148 add_uints_prop(nodeh
, propinfo
, di_val
, idata
, len
);
1150 case DI_PROP_TYPE_STRING
:
1151 len
= di_path_prop_strings(di_path_prop
, &sdata
);
1154 add_strings_prop(nodeh
, propinfo
, di_val
, sdata
, len
);
1156 case DI_PROP_TYPE_BYTE
:
1157 len
= di_path_prop_bytes(di_path_prop
, &bdata
);
1160 add_bytes_prop(nodeh
, propinfo
, di_val
, bdata
, len
);
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
,
1172 len
= di_path_prop_ints(di_path_prop
, &idata
);
1174 add_uints_prop(nodeh
, propinfo
, di_val
,
1178 len
= di_path_prop_bytes(di_path_prop
, &bdata
);
1180 add_bytes_prop(nodeh
, propinfo
,
1181 di_val
, bdata
, len
);
1183 add_boolean_prop(nodeh
, propinfo
,
1186 case DI_PROP_TYPE_UNDEF_IT
:
1194 * Add nodes for path information (PSARC/1999/647, PSARC/2008/437)
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
;
1210 if (phci_node
== DI_PATH_NIL
)
1213 err
= ptree_create_and_add_node(parh
, PICL_CLASS_MULTIPATH
,
1214 PICL_CLASS_MULTIPATH
, &nodeh
);
1215 if (err
!= PICL_SUCCESS
)
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
,
1225 di_val
= di_devfs_path(phci_node
);
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
,
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
1254 add_devinfo_props(picl_nodehdl_t nodeh
, di_node_t di_node
)
1260 ptree_propinfo_t propinfo
;
1262 unsigned char *bdata
;
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
,
1270 (void) ptree_create_and_add_prop(nodeh
, &propinfo
, &instance
, NULL
);
1272 di_val
= di_bus_addr(di_node
);
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
,
1281 di_val
= di_binding_name(di_node
);
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
,
1290 di_val
= di_driver_name(di_node
);
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
,
1299 di_val
= di_devfs_path(di_node
);
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
,
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
);
1317 case DI_PROP_TYPE_BOOLEAN
:
1318 add_boolean_prop(nodeh
, propinfo
, di_val
);
1320 case DI_PROP_TYPE_INT
:
1321 len
= di_prop_ints(di_prop
, &idata
);
1323 /* Received error, so ignore prop */
1325 add_uints_prop(nodeh
, propinfo
, di_val
, idata
, len
);
1327 case DI_PROP_TYPE_STRING
:
1328 len
= di_prop_strings(di_prop
, &sdata
);
1331 add_strings_prop(nodeh
, propinfo
, di_val
, sdata
, len
);
1333 case DI_PROP_TYPE_BYTE
:
1334 len
= di_prop_bytes(di_prop
, &bdata
);
1337 add_bytes_prop(nodeh
, propinfo
, di_val
, bdata
, len
);
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
,
1349 len
= di_prop_ints(di_prop
, &idata
);
1351 add_uints_prop(nodeh
, propinfo
, di_val
,
1355 len
= di_prop_rawdata(di_prop
, &bdata
);
1357 add_bytes_prop(nodeh
, propinfo
,
1358 di_val
, bdata
, len
);
1360 add_boolean_prop(nodeh
, propinfo
,
1363 case DI_PROP_TYPE_UNDEF_IT
:
1372 * This function creates the /obp node in the PICL tree for OBP nodes
1373 * without a device type class.
1376 construct_picl_openprom(picl_nodehdl_t rooth
, picl_nodehdl_t
*obph
)
1378 picl_nodehdl_t tmph
;
1381 err
= ptree_create_and_add_node(rooth
, PICL_NODE_OBP
,
1382 PICL_CLASS_PICL
, &tmph
);
1384 if (err
!= PICL_SUCCESS
)
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
1396 construct_picl_platform(picl_nodehdl_t rooth
, di_node_t di_root
,
1397 picl_nodehdl_t
*piclh
)
1400 picl_nodehdl_t plafh
;
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
);
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
);
1416 (void) strcpy(nodeclass
, PICL_CLASS_UPA
); /* default */
1418 err
= ptree_create_and_add_node(rooth
, PICL_NODE_PLATFORM
,
1420 if (err
!= PICL_SUCCESS
)
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
)
1430 (void) add_devinfo_props(plafh
, di_root
);
1432 (void) add_openprom_props(plafh
, di_root
);
1436 return (PICL_SUCCESS
);
1440 * This function creates a node in /obp tree for the libdevinfo handle.
1443 construct_obp_node(picl_nodehdl_t parh
, di_node_t dn
, picl_nodehdl_t
*chdh
)
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
)
1465 add_devinfo_props(anodeh
, dn
);
1467 (void) add_openprom_props(anodeh
, dn
);
1471 return (PICL_SUCCESS
);
1475 * This function creates a PICL node in /platform tree for a device
1478 construct_devtype_node(picl_nodehdl_t parh
, char *nodename
,
1479 char *nodeclass
, di_node_t dn
, picl_nodehdl_t
*chdh
)
1482 picl_nodehdl_t anodeh
;
1484 err
= ptree_create_and_add_node(parh
, nodename
, nodeclass
, &anodeh
);
1485 if (err
!= PICL_SUCCESS
)
1488 (void) add_devinfo_props(anodeh
, dn
);
1489 (void) add_openprom_props(anodeh
, dn
);
1490 construct_mpath_node(anodeh
, dn
);
1497 * Create a subtree of "picl" class nodes in /obp for these nodes
1500 construct_openprom_tree(picl_nodehdl_t nodeh
, di_node_t dinode
)
1503 picl_nodehdl_t chdh
;
1506 err
= construct_obp_node(nodeh
, dinode
, &chdh
);
1507 if (err
!= PICL_SUCCESS
)
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
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
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,...).
1534 construct_devinfo_tree(picl_nodehdl_t plafh
, picl_nodehdl_t obph
,
1535 di_node_t dinode
, char *parent_class
)
1538 picl_nodehdl_t chdh
;
1539 char nodeclass
[PICL_CLASSNAMELEN_MAX
];
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
)
1550 err
= get_node_class(nodeclass
, cnode
, nodename
);
1553 err
= construct_devtype_node(plafh
, nodename
,
1554 nodeclass
, cnode
, &chdh
);
1555 if (err
!= PICL_SUCCESS
)
1557 err
= construct_devinfo_tree(chdh
, obph
, cnode
,
1559 } else if (parent_class
== NULL
)
1560 err
= construct_openprom_tree(obph
, cnode
);
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.
1575 * This function is called from the event handler called from the daemon
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
1586 update_subtree(picl_nodehdl_t nodeh
, di_node_t dinode
)
1589 picl_nodehdl_t chdh
;
1592 char nodeclass
[PICL_CLASSNAMELEN_MAX
];
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
];
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
)
1608 nodename
= di_node_name(cnode
);
1609 if (nodename
== NULL
) {
1610 di_devfs_path_free(path_buf
);
1614 err
= get_node_class(nodeclass
, cnode
, nodename
);
1617 di_devfs_path_free(path_buf
);
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
1637 err
= ptree_create_node(nodename
, nodeclass
, &chdh
);
1638 if (err
!= PICL_SUCCESS
)
1641 (void) add_devinfo_props(chdh
, cnode
);
1642 (void) add_openprom_props(chdh
, cnode
);
1644 err
= get_unitaddr(nodeh
, chdh
, unitaddr
,
1646 if (err
!= PICL_SUCCESS
)
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",
1655 * this is an attached node - so the path is unique
1657 (void) snprintf(path_w_ua
, sizeof (path_w_ua
), "%s",
1659 (void) snprintf(path_wo_ua
, sizeof (path_wo_ua
), "%s",
1661 strp
= strrchr(path_wo_ua
, '@');
1663 (void) snprintf(unitaddr
, sizeof (unitaddr
), "%s",
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)
1677 "update_subtree: path:%s node exists\n",
1679 di_devfs_path_free(path_buf
);
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
))
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
)
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
)
1702 if (strcmp(buf
, unitaddr
) == 0) {
1707 err
= ptree_get_propval_by_name(chdh
,
1708 PICL_PROP_PEER
, &chdh
, sizeof (chdh
));
1709 if (err
!= PICL_SUCCESS
)
1714 * node already there - there's nothing we need to do
1716 if (picldevtree_debug
> 1)
1718 "update_subtree: path:%s node exists\n",
1720 di_devfs_path_free(path_buf
);
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
)
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
) !=
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.
1753 check_stale_node(di_node_t node
, void *arg
)
1755 di_prom_prop_t promp
;
1758 promp
= di_prom_prop_next(ph
, node
, DI_PROM_PROP_NIL
);
1759 if (promp
== DI_PROM_PROP_NIL
&& errno
== EINVAL
) {
1761 return (DI_WALK_TERMINATE
);
1763 return (DI_WALK_CONTINUE
);
1767 * Walk the snapshot and check the OBP properties of each node.
1770 is_snapshot_stale(di_node_t root
)
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
1782 libdevinfo_init(picl_nodehdl_t rooth
)
1785 picl_nodehdl_t plafh
;
1786 picl_nodehdl_t obph
;
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
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
1807 if (is_snapshot_stale(di_root
)) {
1808 syslog(LOG_INFO
, "picld detected stale snapshot cache");
1810 if ((di_root
= di_init("/", DINFOCPYALL
| DINFOFORCE
)) ==
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
) {
1822 return (PICL_FAILURE
);
1825 err
= construct_picl_openprom(rooth
, &obph
);
1826 if (err
!= PICL_SUCCESS
) {
1828 return (PICL_FAILURE
);
1831 (void) construct_devinfo_tree(plafh
, obph
, di_root
, NULL
);
1841 * This function returns the integer property value
1844 get_int_propval_by_name(picl_nodehdl_t nodeh
, char *pname
, int *ival
)
1848 err
= ptree_get_propval_by_name(nodeh
, pname
, ival
,
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.
1860 get_cpu_portid(picl_nodehdl_t modh
, int *id
)
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
)
1869 err
= get_int_propval_by_name(modh
, OBP_PROP_PORTID
, id
);
1870 if (err
== PICL_SUCCESS
)
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
1885 get_pi_state(ptree_rarg_t
*rarg
, void *vbuf
)
1890 err
= get_int_propval_by_name(rarg
->nodeh
, PICL_PROP_ID
, &id
);
1891 if (err
!= PICL_SUCCESS
)
1894 switch (p_online(id
, P_STATUS
)) {
1896 (void) strlcpy(vbuf
, PS_ONLINE
, MAX_STATE_SIZE
);
1899 (void) strlcpy(vbuf
, PS_OFFLINE
, MAX_STATE_SIZE
);
1902 (void) strlcpy(vbuf
, PS_NOINTR
, MAX_STATE_SIZE
);
1905 (void) strlcpy(vbuf
, PS_SPARE
, MAX_STATE_SIZE
);
1908 (void) strlcpy(vbuf
, PS_FAULTED
, MAX_STATE_SIZE
);
1911 (void) strlcpy(vbuf
, PS_POWEROFF
, MAX_STATE_SIZE
);
1914 (void) strlcpy(vbuf
, "unknown", MAX_STATE_SIZE
);
1917 return (PICL_SUCCESS
);
1921 * This function is the volatile read access function of CPU processor_type
1925 get_processor_type(ptree_rarg_t
*rarg
, void *vbuf
)
1927 processor_info_t cpu_info
;
1931 err
= get_int_propval_by_name(rarg
->nodeh
, PICL_PROP_ID
, &id
);
1932 if (err
!= PICL_SUCCESS
)
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
1946 get_fputypes(ptree_rarg_t
*rarg
, void *vbuf
)
1948 processor_info_t cpu_info
;
1952 err
= get_int_propval_by_name(rarg
->nodeh
, PICL_PROP_ID
, &id
);
1953 if (err
!= PICL_SUCCESS
)
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.
1968 get_pi_state_begin(ptree_rarg_t
*rarg
, void *vbuf
)
1972 static kstat_ctl_t
*kc
= NULL
;
1973 static pthread_mutex_t kc_mutex
= PTHREAD_MUTEX_INITIALIZER
;
1977 err
= get_int_propval_by_name(rarg
->nodeh
, PICL_PROP_ID
, &cpu_id
);
1978 if (err
!= PICL_SUCCESS
)
1981 (void) pthread_mutex_lock(&kc_mutex
);
1984 else if (kstat_chain_update(kc
) == -1) {
1985 (void) kstat_close(kc
);
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
);
2003 *(uint64_t *)vbuf
= (uint64_t)kn
->value
.l
;
2008 (void) pthread_mutex_unlock(&kc_mutex
);
2013 * This function adds CPU information to the CPU nodes
2017 add_processor_info(picl_nodehdl_t cpuh
, void *args
)
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
)
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
2078 setup_cpus(picl_nodehdl_t plafh
)
2082 err
= ptree_walk_tree_by_class(plafh
, PICL_CLASS_CPU
, NULL
,
2083 add_processor_info
);
2089 * This function format's the manufacture's information for FFB display
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
);
2106 case MANF_MITSUBISHI
:
2107 (void) snprintf(outbuf
, bufsz
, "%s %x, version %d",
2108 "Mitsubishi", manufid
.fld
.partno
, manufid
.fld
.version
);
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
2122 open_ffb_device(picl_nodehdl_t ffbh
, int *fd
)
2125 char devfs_path
[PATH_MAX
];
2126 char dev_path
[PATH_MAX
];
2128 struct dirent
*direntp
;
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
)
2138 /* Get the device node name */
2139 devp
= strrchr(devfs_path
, '/');
2141 return (PICL_FAILURE
);
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",
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
);
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
2188 add_ffb_config_info(picl_nodehdl_t rooth
)
2190 picl_nodehdl_t nodeh
;
2192 char piclclass
[PICL_CLASSNAMELEN_MAX
];
2193 char manfidbuf
[FFB_MANUF_BUFSIZE
];
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
)
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
,
2221 board_rev
= fsi
.ffb_strap_bits
.fld
.board_rev
;
2222 (void) ptree_create_and_add_prop(nodeh
, &pinfo
,
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
,
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
,
2243 (void) ptree_create_and_add_prop(nodeh
, &pinfo
,
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
)
2257 conf_entries_t
*del
;
2262 while (el
!= NULL
) {
2266 free(del
->piclclass
);
2273 * Reading config order: platform, common
2275 static conf_entries_t
*
2276 read_conf_file(char *fname
, conf_entries_t
*list
)
2279 char lbuf
[CONFFILE_LINELEN_MAX
];
2283 conf_entries_t
*ptr
;
2288 fp
= fopen(fname
, "r");
2293 while (fgets(lbuf
, CONFFILE_LINELEN_MAX
, fp
) != NULL
) {
2294 if ((lbuf
[0] == CONFFILE_COMMENT_CHAR
) || (lbuf
[0] == '\n'))
2297 nametok
= strtok(lbuf
, " \t\n");
2298 if (nametok
== NULL
)
2301 classtok
= strtok(NULL
, " \t\n");
2302 if (classtok
== NULL
)
2305 el
= malloc(sizeof (conf_entries_t
));
2308 el
->name
= strdup(nametok
);
2309 el
->piclclass
= strdup(classtok
);
2310 if ((el
->name
== NULL
) || (el
->piclclass
== NULL
)) {
2317 * Add it to the end of list
2323 while (ptr
->next
!= NULL
)
2334 * Process the devtree conf file and set up the conf_name_class_map list
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
;
2366 free_asr_conf_entries(asr_conf_entries_t
*list
) {
2367 asr_conf_entries_t
*el
;
2368 asr_conf_entries_t
*del
;
2371 while (el
!= NULL
) {
2377 free(del
->piclclass
);
2384 * Reading config order: platform, common
2386 static asr_conf_entries_t
*
2387 read_asr_conf_file(char *fname
, asr_conf_entries_t
*list
)
2390 char lbuf
[CONFFILE_LINELEN_MAX
];
2396 asr_conf_entries_t
*el
;
2397 asr_conf_entries_t
*ptr
;
2402 fp
= fopen(fname
, "r");
2406 while (fgets(lbuf
, CONFFILE_LINELEN_MAX
, fp
) != NULL
) {
2407 if ((lbuf
[0] == CONFFILE_COMMENT_CHAR
) || (lbuf
[0] == '\n'))
2410 nametok
= strtok(lbuf
, " \t\n");
2411 if (nametok
== NULL
)
2414 classtok
= strtok(NULL
, " \t\n");
2415 if (classtok
== NULL
)
2418 statustok
= strtok(NULL
, " \t\n");
2419 if (statustok
== NULL
)
2422 addresstok
= strtok(NULL
, " \t\n");
2423 if (addresstok
== NULL
)
2427 * props are optional
2429 propstok
= strtok(NULL
, " \t\n");
2431 el
= malloc(sizeof (asr_conf_entries_t
));
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
);
2442 if ((el
->name
== NULL
) || (el
->piclclass
== NULL
) ||
2443 (el
->address
== NULL
) || (el
->status
== NULL
)) {
2447 free(el
->piclclass
);
2455 * Add it to the end of list
2461 while (ptr
->next
!= NULL
)
2472 * Process the asr conf file
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
,
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
,
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
2503 get_asr_export_list(char **exportlist
, int *exportlistlen
)
2505 struct openpromio oppbuf
;
2506 struct openpromio
*opp
= &oppbuf
;
2510 d
= open("/dev/openprom", O_RDWR
);
2514 if (ioctl(d
, OPROMEXPORTLEN
, opp
) == -1) {
2518 listsize
= opp
->oprom_size
;
2519 opp
= (struct openpromio
*)malloc(sizeof (struct openpromio
) +
2525 (void) memset(opp
, '\0', sizeof (struct openpromio
) + listsize
);
2526 opp
->oprom_size
= listsize
;
2527 if (ioctl(d
, OPROMEXPORT
, opp
) == -1) {
2532 *exportlist
= malloc(listsize
);
2533 if (*exportlist
== NULL
) {
2538 (void) memcpy(*exportlist
, opp
->oprom_array
, opp
->oprom_size
);
2540 *exportlistlen
= opp
->oprom_size
;
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.
2553 parse_props_string(char *props
, asr_prop_triplet_t
*triplet
)
2559 prop_name
= strchr(props
, '?');
2560 if (prop_name
== NULL
)
2562 *prop_name
++ = '\0';
2563 prop_val
= strchr(prop_name
, '=');
2564 if (prop_val
== NULL
)
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';
2578 add_status_prop(picl_nodehdl_t chdh
, char *status
)
2580 ptree_propinfo_t propinfo
;
2581 picl_prophdl_t proph
;
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
)
2589 err
= ptree_create_and_add_prop(chdh
, &propinfo
, status
, &proph
);
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
;
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
;
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
)
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
)
2626 err
= ptree_get_propval_by_name(chdh
, PICL_PROP_NAME
,
2627 (void *)nodename
, PICL_PROPNAMELEN_MAX
);
2628 if (err
!= PICL_SUCCESS
)
2630 if (strcmp(nodename
, child
) != 0)
2633 * found a candidate child node
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
)
2643 if (err
!= PICL_SUCCESS
)
2645 if (strcmp(unitaddr
, ua
) != 0)
2648 if (props
== NULL
) {
2650 } else if (props_copy
== NULL
) {
2651 props_copy
= strdup(props
);
2652 if (props_copy
== NULL
)
2656 while ((next
= parse_props_string(next
, &triple
)) != NULL
) {
2657 err
= ptree_get_prop_by_name(chdh
, triple
.propname
,
2659 if (err
!= PICL_SUCCESS
)
2661 err
= ptree_get_propinfo(proph
, &propinfo
);
2662 if (err
!= PICL_SUCCESS
)
2665 switch (propinfo
.piclinfo
.type
) {
2666 case PICL_PTYPE_INT
:
2667 case PICL_PTYPE_UNSIGNED_INT
:
2668 if (strcmp(triple
.proptype
, "I") != 0)
2670 err
= ptree_get_propval(proph
, (void *)&val
,
2672 if (err
!= PICL_SUCCESS
)
2674 if (val
!= atoi(triple
.propval
))
2677 case PICL_PTYPE_CHARSTRING
:
2678 if (strcmp(triple
.proptype
, "S") != 0)
2680 prop_string
= malloc(propinfo
.piclinfo
.size
);
2681 if (prop_string
== NULL
)
2683 err
= ptree_get_propval(proph
,
2684 (void *)prop_string
,
2685 propinfo
.piclinfo
.size
);
2686 if (err
!= PICL_SUCCESS
) {
2690 if (strcmp(prop_string
, triple
.propval
) != 0)
2697 if (err
!= PICL_SUCCESS
) {
2709 * does the pre-existing node have a status property?
2711 err
= ptree_get_propval_by_name(chdh
, PICL_PROP_STATUS
,
2713 if (err
== PICL_PROPNOTFOUND
)
2714 (void) add_status_prop(chdh
, status
);
2715 if (err
!= PICL_SUCCESS
)
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))) {
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
)
2729 (void) ptree_delete_prop(proph
);
2730 (void) ptree_destroy_prop(proph
);
2731 err
= add_status_prop(chdh
, status
);
2732 if (err
!= PICL_SUCCESS
)
2738 * typical case, node needs adding together with a set of properties
2740 if (ptree_create_and_add_node(nodeh
, child
, class, &chdh
) ==
2742 (void) add_status_prop(chdh
, status
);
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
,
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
,
2763 while ((next
= parse_props_string(next
, &triple
)) != NULL
) {
2765 * only handle int and string properties for
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
);
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
);
2794 asr_conf_entries_t
*c
= NULL
;
2802 if (get_asr_export_list(&asrexport
, &asrexportlen
) == 0)
2804 process_asrtree_conf_file();
2805 if (conf_name_asr_map
== NULL
)
2808 while (i
< asrexportlen
) {
2809 key
= &asrexport
[i
];
2810 i
+= strlen(key
) + 1;
2811 if (i
>= asrexportlen
)
2815 * next byte tells us whether failed by diags or manually
2818 disabled
= asrexport
[i
];
2820 if (i
>= asrexportlen
)
2824 * only type 1 supported
2826 if (asrexport
[i
] != 1)
2829 if (i
>= asrexportlen
)
2833 * next two bytes give size of reason string
2835 count
= (asrexport
[i
] << 8) | asrexport
[i
+ 1];
2837 if (i
> asrexportlen
)
2841 * now look for key in conf file info
2843 c
= conf_name_asr_map
;
2845 if (strcmp(key
, c
->name
) == 0) {
2846 child
= strrchr(c
->address
, '/');
2848 unitaddr
= strchr(child
, '@');
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
,
2857 create_asr_node(c
->address
, child
,
2858 unitaddr
, c
->piclclass
, c
->status
,
2866 free_asr_conf_entries(conf_name_asr_map
);
2871 * This function adds information to the /platform node
2874 add_platform_info(picl_nodehdl_t plafh
)
2876 struct utsname uts_info
;
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
,
2889 if (err
!= PICL_SUCCESS
)
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
,
2897 if (err
!= PICL_SUCCESS
)
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
,
2905 if (err
!= PICL_SUCCESS
)
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
,
2913 if (err
!= PICL_SUCCESS
)
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
,
2925 * Get first 32-bit value from the reg property
2928 get_first_reg_word(picl_nodehdl_t nodeh
, uint32_t *regval
)
2932 picl_prophdl_t regh
;
2933 ptree_propinfo_t pinfo
;
2935 err
= ptree_get_prop_by_name(nodeh
, OBP_REG
, ®h
);
2936 if (err
!= PICL_SUCCESS
) /* no reg property */
2938 err
= ptree_get_propinfo(regh
, &pinfo
);
2939 if (err
!= PICL_SUCCESS
)
2941 if (pinfo
.piclinfo
.size
< sizeof (uint32_t)) /* too small */
2942 return (PICL_FAILURE
);
2943 regbuf
= alloca(pinfo
.piclinfo
.size
);
2945 return (PICL_FAILURE
);
2946 err
= ptree_get_propval(regh
, regbuf
, pinfo
.piclinfo
.size
);
2947 if (err
!= PICL_SUCCESS
)
2949 *regval
= *regbuf
; /* get first 32-bit value */
2950 return (PICL_SUCCESS
);
2954 * Get device ID from the reg property
2957 get_device_id(picl_nodehdl_t nodeh
, uint32_t *dev_id
)
2962 err
= get_first_reg_word(nodeh
, ®val
);
2963 if (err
!= PICL_SUCCESS
)
2966 *dev_id
= PCI_DEVICE_ID(regval
);
2967 return (PICL_SUCCESS
);
2971 * add Slot property for children of SBUS node
2975 add_sbus_slots(picl_nodehdl_t pcih
, void *args
)
2977 picl_nodehdl_t nodeh
;
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
)
2989 if (get_first_reg_word(nodeh
, &slot
) != 0)
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.
3006 set_sbus_slot(picl_nodehdl_t plafh
)
3010 err
= ptree_walk_tree_by_class(plafh
, PICL_CLASS_SBUS
, NULL
,
3017 * add DeviceID property for children of PCI/PCIEX node
3021 add_pci_deviceids(picl_nodehdl_t pcih
, void *args
)
3023 picl_nodehdl_t nodeh
;
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
)
3035 if (get_device_id(nodeh
, &dev_id
) != 0)
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.
3052 set_pci_pciex_deviceid(picl_nodehdl_t plafh
)
3054 (void) ptree_walk_tree_by_class(plafh
, PICL_CLASS_PCI
, NULL
,
3057 (void) ptree_walk_tree_by_class(plafh
, PICL_CLASS_PCIEX
, NULL
,
3062 * Default UnitAddress encode function
3065 encode_default_unitaddr(char *buf
, int sz
, uint32_t *regprop
, uint_t addrcells
)
3070 * Encode UnitAddress as %a,%b,%c,...,%n
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
3087 encode_optional_unitaddr(char *buf
, int sz
, uint32_t *regprop
, uint_t addrcells
)
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);
3098 retval
= encode_default_unitaddr(buf
, sz
, regprop
, addrcells
);
3105 * UnitAddress encode function for SCSI class of devices
3108 encode_scsi_unitaddr(char *buf
, int sz
, uint32_t *regprop
, uint_t addrcells
)
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],
3125 retval
= (len
>= sz
) ? -1 : 0;
3133 * UnitAddress encode function for UPA devices
3136 encode_upa_unitaddr(char *buf
, int sz
, uint32_t *regprop
, uint_t addrcells
)
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
3151 encode_gptwo_jbus_unitaddr(char *buf
, int sz
, uint32_t *regprop
,
3164 id
= ((hi
& 0x1) << 9) | (lo
>> 23); /* agent id */
3165 off
= lo
& 0x7fffff; /* config offset */
3166 len
= snprintf(buf
, sz
, "%x,%x", id
, off
);
3168 len
= snprintf(buf
, sz
, "m%x,%x", hi
, lo
);
3170 return ((len
>= sz
) ? -1 : 0);
3174 * UnitAddress encode function for PCI devices
3177 encode_pci_unitaddr(char *buf
, int sz
, uint32_t *regprop
, uint_t addrcells
)
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 */
3199 p
= (pci_addrcell_t
*)regprop
;
3201 case 0: /* Config */
3203 len
= snprintf(buf
, sz
, "%x,%x", p
->dev
, p
->fn
);
3205 len
= snprintf(buf
, sz
, "%x", p
->dev
);
3208 len
= snprintf(buf
, sz
, "i%x,%x,%x,%x", p
->dev
, p
->fn
, p
->reg
,
3212 len
= snprintf(buf
, sz
, "m%x,%x,%x,%x", p
->dev
, p
->fn
, p
->reg
,
3216 len
= snprintf(buf
, sz
, "x%x,%x,%x,%x%08x", p
->dev
, p
->fn
,
3217 p
->reg
, p
->phys_hi
, p
->phys_lo
);
3220 return ((len
>= sz
) ? -1 : 0);
3224 * Get #address-cells property value
3227 get_addrcells_prop(picl_nodehdl_t nodeh
)
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
;
3251 addrcells
= DEFAULT_ADDRESS_CELLS
;
3253 addrcells
= DEFAULT_ADDRESS_CELLS
;
3259 * Get UnitAddress mapping entry for a node
3261 static unitaddr_map_t
*
3262 get_unitaddr_mapping(picl_nodehdl_t nodeh
)
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
,
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)
3285 * Add UnitAddress property to the specified node
3288 add_unitaddr_prop(picl_nodehdl_t nodeh
, unitaddr_map_t
*uamap
, uint_t addrcells
)
3290 int regproplen
, err
;
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
, ®h
);
3297 if (err
!= PICL_SUCCESS
)
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
);
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
,
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
);
3330 * work out UnitAddress property of the specified node
3333 get_unitaddr(picl_nodehdl_t parh
, picl_nodehdl_t nodeh
, char *unitaddr
,
3336 int regproplen
, err
;
3338 picl_prophdl_t regh
;
3339 ptree_propinfo_t pinfo
;
3340 unitaddr_map_t
*uamap
;
3343 addrcells
= get_addrcells_prop(parh
);
3344 uamap
= get_unitaddr_mapping(parh
);
3346 err
= ptree_get_prop_by_name(nodeh
, OBP_REG
, ®h
);
3347 if (err
!= PICL_SUCCESS
)
3350 err
= ptree_get_propinfo(regh
, &pinfo
);
3351 if (err
!= PICL_SUCCESS
)
3354 if (pinfo
.piclinfo
.size
< (addrcells
* sizeof (uint32_t)))
3355 return (PICL_FAILURE
);
3357 regproplen
= pinfo
.piclinfo
.size
;
3358 regbuf
= alloca(regproplen
);
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
3375 add_unitaddr_prop_to_subtree(picl_nodehdl_t nodeh
)
3378 picl_nodehdl_t chdh
;
3379 unitaddr_map_t
*uamap
;
3383 * Get #address-cells and unit address mapping entry for my
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
);
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
;
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
,
3423 if (err
== PICL_PROPNOTFOUND
)
3424 pval
= SUPPORTED_NUM_CELL_SIZE
;
3425 else if (err
!= PICL_SUCCESS
)
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
)
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
)
3445 err
= ptree_get_propinfo(proph
, &pinfo
);
3446 if (err
!= PICL_SUCCESS
)
3449 regbuf
= alloca(pinfo
.piclinfo
.size
);
3451 return (PICL_FAILURE
);
3453 err
= ptree_get_propval(proph
, regbuf
, pinfo
.piclinfo
.size
);
3454 if (err
!= PICL_SUCCESS
)
3457 mspecs
= (memspecs_t
*)regbuf
;
3458 nspecs
= pinfo
.piclinfo
.size
/ sizeof (memspecs_t
);
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
));
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
);
3481 * This function is executed as part of .init when the plugin is
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
3497 picldevtree_init(void)
3499 picl_nodehdl_t rhdl
;
3501 struct utsname utsname
;
3502 picl_nodehdl_t plafh
;
3504 if (uname(&utsname
) < 0)
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
);
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
);
3529 process_devtree_conf_file();
3531 if (libdevinfo_init(rhdl
) != PICL_SUCCESS
) {
3532 syslog(LOG_ERR
, DEVINFO_PLUGIN_INIT_FAILED
);
3536 err
= ptree_get_node_by_path(PLATFORM_PATH
, &plafh
);
3537 if (err
!= PICL_SUCCESS
)
3540 (void) add_unitaddr_prop_to_subtree(plafh
);
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
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
3597 picldevtree_evhandler(const char *ename
, const void *earg
, size_t size
,
3601 char ptreepath
[PATH_MAX
];
3602 char dipath
[PATH_MAX
];
3603 picl_nodehdl_t plafh
;
3604 picl_nodehdl_t nodeh
;
3607 if ((earg
== NULL
) ||
3608 (ptree_get_node_by_path(PLATFORM_PATH
, &plafh
) != PICL_SUCCESS
))
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");
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
);
3627 (void) strlcpy(ptreepath
, PLATFORM_PATH
, PATH_MAX
);
3628 (void) strlcat(ptreepath
, devfs_path
, PATH_MAX
);
3629 (void) strlcpy(dipath
, devfs_path
, PATH_MAX
);
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) {
3639 if (strcmp(ename
, PICLEVENT_SYSEVENT_DEVICE_ADDED
) == 0) {
3642 picl_nodehdl_t parh
;
3643 char nodeclass
[PICL_CLASSNAMELEN_MAX
];
3647 /* If the node already exist, then nothing else to do here */
3648 if (ptree_get_node_by_path(ptreepath
, &nodeh
) == PICL_SUCCESS
)
3651 /* Skip if unable to find parent PICL node handle */
3653 if (((strp
= strrchr(ptreepath
, '/')) != NULL
) &&
3654 (strp
!= strchr(ptreepath
, '/'))) {
3656 if (ptree_get_node_by_path(ptreepath
, &parh
) !=
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
) {
3674 nodename
= di_node_name(devnode
);
3675 if (nodename
== NULL
) {
3684 err
= get_node_class(nodeclass
, devnode
, nodename
);
3693 err
= construct_devtype_node(plafh
, nodename
,
3694 nodeclass
, devnode
, &nodeh
);
3695 if (err
!= PICL_SUCCESS
) {
3703 (void) update_subtree(nodeh
, devnode
);
3704 (void) add_unitaddr_prop_to_subtree(nodeh
);
3713 /* kludge ... try without bus-addr first */
3714 if ((strp
= strrchr(dipath
, '@')) != NULL
) {
3717 p
= strrchr(dipath
, '/');
3718 if (p
!= NULL
&& strp
> p
) {
3720 devnode
= di_init(dipath
, DINFOCPYALL
);
3721 if (devnode
!= DI_NODE_NIL
)
3726 /* Get parent devnode */
3727 if ((strp
= strrchr(dipath
, '/')) != NULL
)
3729 devnode
= di_init(dipath
, DINFOCPYALL
);
3730 if (devnode
== DI_NODE_NIL
)
3732 ph
= di_prom_init();
3733 (void) update_subtree(parh
, devnode
);
3734 (void) add_unitaddr_prop_to_subtree(parh
);
3740 } else if (strcmp(ename
, PICLEVENT_SYSEVENT_DEVICE_REMOVED
) == 0) {
3741 char delclass
[PICL_CLASSNAMELEN_MAX
];
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
)
3752 /* skip if can't find the node */
3753 if (ptree_get_node_by_path(ptreepath
, &nodeh
) != PICL_SUCCESS
)
3756 if (ptree_delete_node(nodeh
) != PICL_SUCCESS
)
3759 if (picldevtree_debug
)
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
) !=
3767 syslog(LOG_WARNING
, PICL_EVENT_DROPPED
,
3768 PICLEVENT_MC_REMOVED
);
3770 (void) ptree_destroy_node(nodeh
);
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");